Added libdli to dali-toolkit as dali-scene-loader. 97/247197/52
authorGyörgy Straub <g.straub@partner.samsung.com>
Thu, 12 Nov 2020 10:21:32 +0000 (10:21 +0000)
committerGyörgy Straub <g.straub@partner.samsung.com>
Mon, 21 Dec 2020 08:05:14 +0000 (08:05 +0000)
Change-Id: I002e58331035101d9d92d719a864be9baeacc44d

225 files changed:
automated-tests/resources/2CylinderEngine.gltf [new file with mode: 0644]
automated-tests/resources/2CylinderEngine0.bin [new file with mode: 0644]
automated-tests/resources/AnimatedMorphCube.bin [new file with mode: 0644]
automated-tests/resources/AnimatedMorphCube.gltf [new file with mode: 0644]
automated-tests/resources/AnimatedMorphSphere.bin [new file with mode: 0644]
automated-tests/resources/AnimatedMorphSphere.gltf [new file with mode: 0644]
automated-tests/resources/AnimatedTriangle.gltf [new file with mode: 0644]
automated-tests/resources/BoxAnimated.gltf [new file with mode: 0644]
automated-tests/resources/BoxAnimated0.bin [new file with mode: 0644]
automated-tests/resources/CesiumMan.gltf [new file with mode: 0644]
automated-tests/resources/CesiumMan_data.bin [new file with mode: 0644]
automated-tests/resources/CesiumMilkTruck.gltf [new file with mode: 0644]
automated-tests/resources/CesiumMilkTruck_data.bin [new file with mode: 0644]
automated-tests/resources/EnvironmentTest.gltf [new file with mode: 0644]
automated-tests/resources/EnvironmentTest_binary.bin [new file with mode: 0644]
automated-tests/resources/MetalRoughSpheres.gltf [new file with mode: 0644]
automated-tests/resources/MetalRoughSpheres0.bin [new file with mode: 0644]
automated-tests/resources/MorphPrimitivesTest.bin [new file with mode: 0644]
automated-tests/resources/MorphPrimitivesTest.gltf [new file with mode: 0644]
automated-tests/resources/RGB16F.ktx [new file with mode: 0644]
automated-tests/resources/RGB32F.ktx [new file with mode: 0644]
automated-tests/resources/RGBA8888.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_10x10.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_10x5.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_10x6.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_12x10.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_12x12.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_4x4.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_5x4.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_5x5.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_6x5.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_6x6.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_8x5.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_8x6.ktx [new file with mode: 0644]
automated-tests/resources/RGBA_ASTC_8x8.ktx [new file with mode: 0644]
automated-tests/resources/SimpleSparseAccessor.bin [new file with mode: 0644]
automated-tests/resources/SimpleSparseAccessor.gltf [new file with mode: 0644]
automated-tests/resources/Studio/Irradiance.ktx [new file with mode: 0644]
automated-tests/resources/Studio/Radiance.ktx [new file with mode: 0644]
automated-tests/resources/animation.bin [new file with mode: 0644]
automated-tests/resources/arc.dli [new file with mode: 0644]
automated-tests/resources/dli/animation-failed-to-open.dli [new file with mode: 0644]
automated-tests/resources/dli/constraints.dli [new file with mode: 0644]
automated-tests/resources/dli/extras.dli [new file with mode: 0644]
automated-tests/resources/dli/material-environment-out-of-bounds.dli [new file with mode: 0644]
automated-tests/resources/dli/mesh-indices-read-fail.dli [new file with mode: 0644]
automated-tests/resources/dli/mesh-positions-read-fail.dli [new file with mode: 0644]
automated-tests/resources/dli/mesh-uri-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/node-animated-image-mesh-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/node-arc-mesh-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/node-child-invalid-type.dli [new file with mode: 0644]
automated-tests/resources/dli/node-model-mesh-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/node-name-already-used.dli [new file with mode: 0644]
automated-tests/resources/dli/node-processor.dli [new file with mode: 0644]
automated-tests/resources/dli/node-renderable-mesh-invalid-type.dli [new file with mode: 0644]
automated-tests/resources/dli/node-renderable-mesh-out-of-bounds.dli [new file with mode: 0644]
automated-tests/resources/dli/nodes-array-empty.dli [new file with mode: 0644]
automated-tests/resources/dli/nodes-invalid-type.dli [new file with mode: 0644]
automated-tests/resources/dli/nodes-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/root-id-invalid.dli [new file with mode: 0644]
automated-tests/resources/dli/root-id-out-of-bounds.dli [new file with mode: 0644]
automated-tests/resources/dli/root-node-invalid-type.dli [new file with mode: 0644]
automated-tests/resources/dli/scene-out-of-bounds.dli [new file with mode: 0644]
automated-tests/resources/dli/scenes-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/scenes-nodes-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/shader-fragment-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/shader-uniforms.dli [new file with mode: 0644]
automated-tests/resources/dli/shader-vertex-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/skeleton-node-missing.dli [new file with mode: 0644]
automated-tests/resources/dli/skeleton-root-not-found.dli [new file with mode: 0644]
automated-tests/resources/dli_arc.fsh [new file with mode: 0644]
automated-tests/resources/dli_arc.vsh [new file with mode: 0644]
automated-tests/resources/dli_images.fsh [new file with mode: 0644]
automated-tests/resources/dli_images.vsh [new file with mode: 0644]
automated-tests/resources/dli_pbr.fsh [new file with mode: 0644]
automated-tests/resources/dli_pbr.vsh [new file with mode: 0644]
automated-tests/resources/exercise.dli [new file with mode: 0644]
automated-tests/resources/exercise/Icons/Icon_Idle.png [new file with mode: 0644]
automated-tests/resources/exercise/Icons/Icon_JJ.png [new file with mode: 0644]
automated-tests/resources/exercise/Icons/Icon_Lunge.png [new file with mode: 0644]
automated-tests/resources/exercise/Icons/Icon_Squat.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/BG_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/BG_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Body_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Body_Female_Asian_Adult_SubsurfaceColor.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Body_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Eye_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Eye_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/FitBot_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/FitBot_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/FitTop_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/FitTop_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Hair_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Hair_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Head_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Head_Female_SubsurfaceColor.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Head_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Shoe_AlbedoMetallic.png [new file with mode: 0644]
automated-tests/resources/exercise/Textures/Shoe_NormalRoughness.png [new file with mode: 0644]
automated-tests/resources/exercise/idle-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/idle-to-jumping-jack-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/idle-to-lunge-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/idle-to-squat-animation-0.ani [new file with mode: 0644]
automated-tests/resources/exercise/idle-to-squat-animation-1.ani [new file with mode: 0644]
automated-tests/resources/exercise/jumping-jack-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/jumping-jack-to-idle-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/jumping-jack-to-lunge-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/jumping-jack-to-squat-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/lunge-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/lunge-to-idle-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/lunge-to-jumping-jack-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/lunge-to-squat-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/model.dae.bin [new file with mode: 0644]
automated-tests/resources/exercise/squat-animation-0.ani [new file with mode: 0644]
automated-tests/resources/exercise/squat-animation-1.ani [new file with mode: 0644]
automated-tests/resources/exercise/squat-to-idle-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/squat-to-jumping-jack-animation.ani [new file with mode: 0644]
automated-tests/resources/exercise/squat-to-lunge-animation.ani [new file with mode: 0644]
automated-tests/resources/forest_irradiance.ktx [new file with mode: 0644]
automated-tests/resources/forest_radiance.ktx [new file with mode: 0644]
automated-tests/resources/invalid.gltf [new file with mode: 0644]
automated-tests/resources/morph.dli [new file with mode: 0644]
automated-tests/resources/morph/HeadTest_002.dae.bin [new file with mode: 0644]
automated-tests/resources/morph/cube.gltf.bin [new file with mode: 0644]
automated-tests/resources/simpleTriangle.bin [new file with mode: 0644]
automated-tests/resources/truncated.ktx [new file with mode: 0644]
automated-tests/src/dali-scene-loader-internal/CMakeLists.txt [new file with mode: 0755]
automated-tests/src/dali-scene-loader-internal/tct-dali-scene-loader-internal-core.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader-internal/utc-Dali-Gltf2Asset.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader-internal/utc-Dali-Hash.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader-internal/utc-Dali-JsonReader.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader-internal/utc-Dali-JsonUtil.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/CMakeLists.txt [new file with mode: 0755]
automated-tests/src/dali-scene-loader/tct-dali-scene-loader-core.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-AlphaFunctionHelper.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-AnimatedProperty.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-AnimationDefinition.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-CameraParameters.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-EnvironmentDefinition.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-KtxLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-MatrixStack.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-NodeDefinition.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-RendererState.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-ResourceBundle.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-SceneDefinition.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinition.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-StringCallback.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-Utils.cpp [new file with mode: 0644]
automated-tests/src/dali-scene-loader/utc-Dali-ViewProjection.cpp [new file with mode: 0644]
build/tizen/CMakeLists.txt
build/tizen/dali-scene-loader/CMakeLists.txt [new file with mode: 0644]
build/tizen/dali-scene-loader/build.sh [new file with mode: 0755]
build/tizen/dali-scene-loader/dali2-scene-loader.pc.in [new file with mode: 0644]
dali-scene-loader.manifest [new file with mode: 0644]
dali-scene-loader.manifest-smack [new file with mode: 0644]
dali-scene-loader/README.md [new file with mode: 0644]
dali-scene-loader/internal/file.list [new file with mode: 0644]
dali-scene-loader/internal/gltf2-asset.cpp [new file with mode: 0644]
dali-scene-loader/internal/gltf2-asset.h [new file with mode: 0644]
dali-scene-loader/internal/hash.cpp [new file with mode: 0644]
dali-scene-loader/internal/hash.h [new file with mode: 0644]
dali-scene-loader/internal/json-reader.cpp [new file with mode: 0644]
dali-scene-loader/internal/json-reader.h [new file with mode: 0644]
dali-scene-loader/internal/json-util.cpp [new file with mode: 0644]
dali-scene-loader/internal/json-util.h [new file with mode: 0644]
dali-scene-loader/public-api/alpha-function-helper.cpp [new file with mode: 0644]
dali-scene-loader/public-api/alpha-function-helper.h [new file with mode: 0644]
dali-scene-loader/public-api/animated-property.cpp [new file with mode: 0644]
dali-scene-loader/public-api/animated-property.h [new file with mode: 0644]
dali-scene-loader/public-api/animation-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/animation-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/api.h [new file with mode: 0644]
dali-scene-loader/public-api/blend-shape-details.cpp [new file with mode: 0644]
dali-scene-loader/public-api/blend-shape-details.h [new file with mode: 0644]
dali-scene-loader/public-api/camera-parameters.cpp [new file with mode: 0644]
dali-scene-loader/public-api/camera-parameters.h [new file with mode: 0644]
dali-scene-loader/public-api/customization.cpp [new file with mode: 0644]
dali-scene-loader/public-api/customization.h [new file with mode: 0644]
dali-scene-loader/public-api/dli-loader.cpp [new file with mode: 0644]
dali-scene-loader/public-api/dli-loader.h [new file with mode: 0644]
dali-scene-loader/public-api/environment-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/environment-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/file.list [new file with mode: 0644]
dali-scene-loader/public-api/gltf2-loader.cpp [new file with mode: 0644]
dali-scene-loader/public-api/gltf2-loader.h [new file with mode: 0644]
dali-scene-loader/public-api/index.h [new file with mode: 0644]
dali-scene-loader/public-api/ktx-loader.cpp [new file with mode: 0644]
dali-scene-loader/public-api/ktx-loader.h [new file with mode: 0644]
dali-scene-loader/public-api/light-parameters.h [new file with mode: 0644]
dali-scene-loader/public-api/load-result.h [new file with mode: 0644]
dali-scene-loader/public-api/material-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/material-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/matrix-stack.cpp [new file with mode: 0644]
dali-scene-loader/public-api/matrix-stack.h [new file with mode: 0644]
dali-scene-loader/public-api/mesh-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/mesh-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/mesh-geometry.h [new file with mode: 0644]
dali-scene-loader/public-api/node-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/node-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/parse-renderer-state.cpp [new file with mode: 0644]
dali-scene-loader/public-api/parse-renderer-state.h [new file with mode: 0644]
dali-scene-loader/public-api/renderer-state.cpp [new file with mode: 0644]
dali-scene-loader/public-api/renderer-state.h [new file with mode: 0644]
dali-scene-loader/public-api/resource-bundle.cpp [new file with mode: 0644]
dali-scene-loader/public-api/resource-bundle.h [new file with mode: 0644]
dali-scene-loader/public-api/scene-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/scene-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/shader-definition-factory.cpp [new file with mode: 0644]
dali-scene-loader/public-api/shader-definition-factory.h [new file with mode: 0644]
dali-scene-loader/public-api/shader-definition.cpp [new file with mode: 0644]
dali-scene-loader/public-api/shader-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/skeleton-definition.h [new file with mode: 0644]
dali-scene-loader/public-api/skinning-details.cpp [new file with mode: 0644]
dali-scene-loader/public-api/skinning-details.h [new file with mode: 0644]
dali-scene-loader/public-api/string-callback.cpp [new file with mode: 0644]
dali-scene-loader/public-api/string-callback.h [new file with mode: 0644]
dali-scene-loader/public-api/utils.cpp [new file with mode: 0644]
dali-scene-loader/public-api/utils.h [new file with mode: 0644]
dali-scene-loader/public-api/view-projection.cpp [new file with mode: 0644]
dali-scene-loader/public-api/view-projection.h [new file with mode: 0644]
dali-scene-loader/third-party/json.h [new file with mode: 0644]
packaging/dali-toolkit.spec

diff --git a/automated-tests/resources/2CylinderEngine.gltf b/automated-tests/resources/2CylinderEngine.gltf
new file mode 100644 (file)
index 0000000..c4caf78
--- /dev/null
@@ -0,0 +1,4390 @@
+{\r
+    "asset": {\r
+        "generator": "COLLADA2GLTF",\r
+        "version": "2.0"\r
+    },\r
+    "scene": 0,\r
+    "scenes": [\r
+        {\r
+            "nodes": [\r
+                81,\r
+                0\r
+            ]\r
+        }\r
+    ],\r
+    "nodes": [\r
+        {\r
+            "children": [\r
+                80,\r
+                79,\r
+                78,\r
+                77,\r
+                76,\r
+                75,\r
+                74,\r
+                73,\r
+                13,\r
+                10,\r
+                7,\r
+                4,\r
+                1\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                3,\r
+                2\r
+            ],\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                136.860107421875,\r
+                -64.45372009277344,\r
+                -36.179630279541019,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 0,\r
+            "matrix": [\r
+                -1.0,\r
+                8.979318677493353e-11,\r
+                0.0,\r
+                0.0,\r
+                -8.979318677493353e-11,\r
+                -1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -294.67718505859377,\r
+                73.97987365722656,\r
+                16.17963218688965,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 1,\r
+            "matrix": [\r
+                0.9995650053024292,\r
+                0.029493184760212896,\r
+                0.0,\r
+                0.0,\r
+                -0.029493184760212896,\r
+                0.9995650053024292,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -45.315460205078128,\r
+                -24.617263793945317,\r
+                -26.320369720458986,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                6,\r
+                5\r
+            ],\r
+            "matrix": [\r
+                -1.0,\r
+                8.979318677493353e-11,\r
+                0.0,\r
+                0.0,\r
+                -8.979318677493353e-11,\r
+                -1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -136.860107421875,\r
+                64.45372009277344,\r
+                3.8203670978546144,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 0,\r
+            "matrix": [\r
+                -1.0,\r
+                8.979318677493353e-11,\r
+                0.0,\r
+                0.0,\r
+                -8.979318677493353e-11,\r
+                -1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -294.67718505859377,\r
+                73.97987365722656,\r
+                16.17963218688965,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 1,\r
+            "matrix": [\r
+                0.9995650053024292,\r
+                0.029493184760212896,\r
+                0.0,\r
+                0.0,\r
+                -0.029493184760212896,\r
+                0.9995650053024292,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -45.315460205078128,\r
+                -24.617263793945317,\r
+                -26.32036781311035,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                9,\r
+                8\r
+            ],\r
+            "matrix": [\r
+                -0.5,\r
+                -0.8660253882408142,\r
+                0.0,\r
+                0.0,\r
+                0.8660253882408142,\r
+                -0.5,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                18.09818458557129,\r
+                -69.69783782958985,\r
+                -105.559814453125,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 2,\r
+            "matrix": [\r
+                -0.9390941858291626,\r
+                0.3436597883701325,\r
+                0.0,\r
+                0.0,\r
+                -0.3436597883701325,\r
+                -0.9390941858291626,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -51.311012268066409,\r
+                -50.52240753173828,\r
+                -18.440185546875,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 3,\r
+            "matrix": [\r
+                -0.9390941858291626,\r
+                0.3436597883701325,\r
+                0.0,\r
+                0.0,\r
+                -0.3436597883701325,\r
+                -0.9390941858291626,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -51.311012268066409,\r
+                -50.52240753173828,\r
+                107.559814453125,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                12,\r
+                11\r
+            ],\r
+            "matrix": [\r
+                0.7071067690849304,\r
+                -0.7071067690849304,\r
+                0.0,\r
+                0.0,\r
+                0.7071067690849304,\r
+                0.7071067690849304,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                47.17867660522461,\r
+                -52.821327209472659,\r
+                -88.94477081298828,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 4,\r
+            "matrix": [\r
+                -0.4234085381031037,\r
+                -0.9059388637542724,\r
+                -7.575183536001616e-11,\r
+                0.0,\r
+                -0.9059388637542724,\r
+                0.4234085381031037,\r
+                -4.821281221478735e-11,\r
+                0.0,\r
+                7.575183536001616e-11,\r
+                4.821281221478735e-11,\r
+                -1.0,\r
+                0.0,\r
+                -90.59386444091796,\r
+                -24.379817962646489,\r
+                -40.05522918701172,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 5,\r
+            "matrix": [\r
+                -1.877404400829619e-7,\r
+                -1.194886607436274e-7,\r
+                1.0,\r
+                0.0,\r
+                -0.905938446521759,\r
+                0.42340943217277529,\r
+                -1.194886607436274e-7,\r
+                0.0,\r
+                -0.42340943217277529,\r
+                -0.905938446521759,\r
+                -1.877404400829619e-7,\r
+                0.0,\r
+                -30.2958984375,\r
+                -52.56131362915039,\r
+                25.05522727966309,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                72,\r
+                71,\r
+                70,\r
+                69,\r
+                68,\r
+                67,\r
+                66,\r
+                65,\r
+                14\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                64,\r
+                63,\r
+                62,\r
+                61,\r
+                60,\r
+                59,\r
+                58,\r
+                57,\r
+                56,\r
+                43,\r
+                29,\r
+                15\r
+            ],\r
+            "matrix": [\r
+                -2.430540746445331e-7,\r
+                0.0000014087579529586949,\r
+                -1.0,\r
+                0.0,\r
+                -1.0,\r
+                -2.430540746445331e-7,\r
+                2.4305373358402006e-7,\r
+                0.0,\r
+                -2.4305373358402006e-7,\r
+                1.0,\r
+                0.0000014087580666455324,\r
+                0.0,\r
+                -48.26182556152344,\r
+                -59.11042404174805,\r
+                34.595985412597659,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                28,\r
+                27,\r
+                16\r
+            ],\r
+            "matrix": [\r
+                -0.4546820223331452,\r
+                0.6541662216186523,\r
+                -0.6044260263442993,\r
+                0.0,\r
+                0.8696397542953491,\r
+                0.4726206660270691,\r
+                -0.1426759660243988,\r
+                0.0,\r
+                0.19233042001724244,\r
+                -0.590505063533783,\r
+                -0.7837810516357422,\r
+                0.0,\r
+                14.898193359375,\r
+                85.82951354980469,\r
+                -48.034645080566409,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                26,\r
+                25,\r
+                24,\r
+                23,\r
+                22,\r
+                21,\r
+                20,\r
+                19,\r
+                18,\r
+                17\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8450329899787903,\r
+                0.005398945417255163,\r
+                -0.5346869230270386,\r
+                0.0,\r
+                -0.4710906744003296,\r
+                0.4805830717086792,\r
+                -0.7396712303161621,\r
+                0.0,\r
+                0.25296804308891299,\r
+                0.8769326210021973,\r
+                0.4086519181728363,\r
+                0.0,\r
+                -74.0894775390625,\r
+                71.41646575927735,\r
+                -157.91323852539066,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.7145451903343201,\r
+                -0.1154177337884903,\r
+                0.6900028586387634,\r
+                0.0,\r
+                -0.6522517800331116,\r
+                0.4665486216545105,\r
+                -0.5974110960960388,\r
+                0.0,\r
+                -0.25296807289123537,\r
+                -0.8769327998161316,\r
+                -0.4086515009403229,\r
+                0.0,\r
+                122.53109741210938,\r
+                86.64814758300781,\r
+                -312.3133850097656,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8450329899787903,\r
+                0.005398945417255163,\r
+                -0.5346869230270386,\r
+                0.0,\r
+                -0.4710906744003296,\r
+                0.4805830717086792,\r
+                -0.7396712303161621,\r
+                0.0,\r
+                0.25296804308891299,\r
+                0.8769326210021973,\r
+                0.4086519181728363,\r
+                0.0,\r
+                -69.3792953491211,\r
+                71.78133392333985,\r
+                -161.61203002929688,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.7145451903343201,\r
+                -0.1154177337884903,\r
+                0.6900028586387634,\r
+                0.0,\r
+                -0.6522517800331116,\r
+                0.4665486216545105,\r
+                -0.5974110960960388,\r
+                0.0,\r
+                -0.25296807289123537,\r
+                -0.8769327998161316,\r
+                -0.4086515009403229,\r
+                0.0,\r
+                127.24127197265624,\r
+                87.01302337646485,\r
+                -316.0121765136719,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8450329899787903,\r
+                0.005398945417255163,\r
+                -0.5346869230270386,\r
+                0.0,\r
+                -0.4710906744003296,\r
+                0.4805830717086792,\r
+                -0.7396712303161621,\r
+                0.0,\r
+                0.25296804308891299,\r
+                0.8769326210021973,\r
+                0.4086519181728363,\r
+                0.0,\r
+                -64.66907501220703,\r
+                72.14624786376953,\r
+                -165.310791015625,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.7145451903343201,\r
+                -0.1154177337884903,\r
+                0.6900028586387634,\r
+                0.0,\r
+                -0.6522517800331116,\r
+                0.4665486216545105,\r
+                -0.5974110960960388,\r
+                0.0,\r
+                -0.25296807289123537,\r
+                -0.8769327998161316,\r
+                -0.4086515009403229,\r
+                0.0,\r
+                131.9515380859375,\r
+                87.37792205810547,\r
+                -319.7109680175781,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8450329899787903,\r
+                0.005398945417255163,\r
+                -0.5346869230270386,\r
+                0.0,\r
+                -0.4710906744003296,\r
+                0.4805830717086792,\r
+                -0.7396712303161621,\r
+                0.0,\r
+                0.25296804308891299,\r
+                0.8769326210021973,\r
+                0.4086519181728363,\r
+                0.0,\r
+                -59.958885192871097,\r
+                72.5111312866211,\r
+                -169.00955200195313,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.7145451903343201,\r
+                -0.1154177337884903,\r
+                0.6900028586387634,\r
+                0.0,\r
+                -0.6522517800331116,\r
+                0.4665486216545105,\r
+                -0.5974110960960388,\r
+                0.0,\r
+                -0.25296807289123537,\r
+                -0.8769327998161316,\r
+                -0.4086515009403229,\r
+                0.0,\r
+                136.66165161132813,\r
+                87.74280548095703,\r
+                -323.4097595214844,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8450329899787903,\r
+                0.005398945417255163,\r
+                -0.5346869230270386,\r
+                0.0,\r
+                -0.4710906744003296,\r
+                0.4805830717086792,\r
+                -0.7396712303161621,\r
+                0.0,\r
+                0.25296804308891299,\r
+                0.8769326210021973,\r
+                0.4086519181728363,\r
+                0.0,\r
+                -55.24869537353516,\r
+                72.87601470947266,\r
+                -172.70831298828126,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.7145451903343201,\r
+                -0.1154177337884903,\r
+                0.6900028586387634,\r
+                0.0,\r
+                -0.6522517800331116,\r
+                0.4665486216545105,\r
+                -0.5974110960960388,\r
+                0.0,\r
+                -0.25296807289123537,\r
+                -0.8769327998161316,\r
+                -0.4086515009403229,\r
+                0.0,\r
+                141.37188720703126,\r
+                88.10767364501953,\r
+                -327.1084899902344,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 7,\r
+            "matrix": [\r
+                0.7850325703620911,\r
+                0.06081420928239823,\r
+                -0.6164620518684387,\r
+                0.0,\r
+                -0.13561886548995973,\r
+                0.9878994822502136,\r
+                -0.07524696737527847,\r
+                0.0,\r
+                0.6044265031814575,\r
+                0.14267520606517793,\r
+                0.7837808728218079,\r
+                0.0,\r
+                -5.746735095977783,\r
+                -250.409912109375,\r
+                -86.68790435791016,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 8,\r
+            "matrix": [\r
+                0.785033106803894,\r
+                0.06081344559788704,\r
+                -0.616461455821991,\r
+                0.0,\r
+                -0.3681585192680359,\r
+                -0.7545340061187744,\r
+                -0.5432658195495606,\r
+                0.0,\r
+                -0.4981790184974671,\r
+                0.6534371972084045,\r
+                -0.569945216178894,\r
+                0.0,\r
+                34.187137603759769,\r
+                252.666015625,\r
+                65.06369018554688,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                42,\r
+                41,\r
+                30\r
+            ],\r
+            "matrix": [\r
+                0.4546822011470794,\r
+                0.6541662216186523,\r
+                0.604425847530365,\r
+                0.0,\r
+                -0.8696396350860596,\r
+                0.4726209044456482,\r
+                0.14267593622207642,\r
+                0.0,\r
+                -0.1923305094242096,\r
+                -0.5905048847198486,\r
+                0.7837811708450317,\r
+                0.0,\r
+                91.87051391601564,\r
+                80.63255310058594,\r
+                166.26089477539066,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                40,\r
+                39,\r
+                38,\r
+                37,\r
+                36,\r
+                35,\r
+                34,\r
+                33,\r
+                32,\r
+                31\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8620702028274536,\r
+                -0.015319700352847577,\r
+                -0.506557285785675,\r
+                0.0,\r
+                -0.4340354502201081,\r
+                0.4936883449554444,\r
+                -0.7535814642906189,\r
+                0.0,\r
+                0.26162606477737429,\r
+                0.8695039749145508,\r
+                0.41894471645355227,\r
+                0.0,\r
+                -77.39921569824219,\r
+                74.49835205078125,\r
+                -159.90199279785157,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.6893031001091003,\r
+                -0.13550062477588654,\r
+                0.7116886973381043,\r
+                0.0,\r
+                -0.6755834221839905,\r
+                0.47497618198394778,\r
+                -0.5639013051986694,\r
+                0.0,\r
+                -0.2616262137889862,\r
+                -0.8695039749145508,\r
+                -0.4189445376396179,\r
+                0.0,\r
+                115.9541015625,\r
+                89.47693634033203,\r
+                -311.7364501953125,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8620702028274536,\r
+                -0.015319700352847577,\r
+                -0.506557285785675,\r
+                0.0,\r
+                -0.4340354502201081,\r
+                0.4936883449554444,\r
+                -0.7535814642906189,\r
+                0.0,\r
+                0.26162606477737429,\r
+                0.8695039749145508,\r
+                0.41894471645355227,\r
+                0.0,\r
+                -71.11894989013672,\r
+                74.98487091064453,\r
+                -164.83367919921876,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.6893031001091003,\r
+                -0.13550062477588654,\r
+                0.7116886973381043,\r
+                0.0,\r
+                -0.6755834221839905,\r
+                0.47497618198394778,\r
+                -0.5639013051986694,\r
+                0.0,\r
+                -0.2616262137889862,\r
+                -0.8695039749145508,\r
+                -0.4189445376396179,\r
+                0.0,\r
+                122.234375,\r
+                89.96346282958985,\r
+                -316.668212890625,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8620702028274536,\r
+                -0.015319700352847577,\r
+                -0.506557285785675,\r
+                0.0,\r
+                -0.4340354502201081,\r
+                0.4936883449554444,\r
+                -0.7535814642906189,\r
+                0.0,\r
+                0.26162606477737429,\r
+                0.8695039749145508,\r
+                0.41894471645355227,\r
+                0.0,\r
+                -64.83870697021485,\r
+                75.47139739990235,\r
+                -169.76536560058598,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.6893031001091003,\r
+                -0.13550062477588654,\r
+                0.7116886973381043,\r
+                0.0,\r
+                -0.6755834221839905,\r
+                0.47497618198394778,\r
+                -0.5639013051986694,\r
+                0.0,\r
+                -0.2616262137889862,\r
+                -0.8695039749145508,\r
+                -0.4189445376396179,\r
+                0.0,\r
+                128.51461791992188,\r
+                90.44998931884766,\r
+                -321.5999145507813,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8620702028274536,\r
+                -0.015319700352847577,\r
+                -0.506557285785675,\r
+                0.0,\r
+                -0.4340354502201081,\r
+                0.4936883449554444,\r
+                -0.7535814642906189,\r
+                0.0,\r
+                0.26162606477737429,\r
+                0.8695039749145508,\r
+                0.41894471645355227,\r
+                0.0,\r
+                -58.558441162109378,\r
+                75.9579086303711,\r
+                -174.6970672607422,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.6893031001091003,\r
+                -0.13550062477588654,\r
+                0.7116886973381043,\r
+                0.0,\r
+                -0.6755834221839905,\r
+                0.47497618198394778,\r
+                -0.5639013051986694,\r
+                0.0,\r
+                -0.2616262137889862,\r
+                -0.8695039749145508,\r
+                -0.4189445376396179,\r
+                0.0,\r
+                134.79489135742188,\r
+                90.9365005493164,\r
+                -326.5315856933594,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                0.8620702028274536,\r
+                -0.015319700352847577,\r
+                -0.506557285785675,\r
+                0.0,\r
+                -0.4340354502201081,\r
+                0.4936883449554444,\r
+                -0.7535814642906189,\r
+                0.0,\r
+                0.26162606477737429,\r
+                0.8695039749145508,\r
+                0.41894471645355227,\r
+                0.0,\r
+                -52.27817535400391,\r
+                76.44441223144531,\r
+                -179.62875366210938,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 6,\r
+            "matrix": [\r
+                -0.6893031001091003,\r
+                -0.13550062477588654,\r
+                0.7116886973381043,\r
+                0.0,\r
+                -0.6755834221839905,\r
+                0.47497618198394778,\r
+                -0.5639013051986694,\r
+                0.0,\r
+                -0.2616262137889862,\r
+                -0.8695039749145508,\r
+                -0.4189445376396179,\r
+                0.0,\r
+                141.07516479492188,\r
+                91.42301940917968,\r
+                -331.4632263183594,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 7,\r
+            "matrix": [\r
+                0.7850325703620911,\r
+                0.06081420928239823,\r
+                -0.6164620518684387,\r
+                0.0,\r
+                -0.13561886548995973,\r
+                0.9878994822502136,\r
+                -0.07524696737527847,\r
+                0.0,\r
+                0.6044265031814575,\r
+                0.14267520606517793,\r
+                0.7837808728218079,\r
+                0.0,\r
+                -1.248520016670227,\r
+                -250.06192016601566,\r
+                -90.22713470458985,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 8,\r
+            "matrix": [\r
+                0.7850322723388672,\r
+                0.06081392988562584,\r
+                -0.6164625287055969,\r
+                0.0,\r
+                -0.3924780488014221,\r
+                -0.7211048007011414,\r
+                -0.5709367990493774,\r
+                0.0,\r
+                -0.4792549908161164,\r
+                0.6901518106460571,\r
+                -0.5422223806381226,\r
+                0.0,\r
+                45.59693908691406,\r
+                243.51312255859376,\r
+                69.38878631591797,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                55,\r
+                54,\r
+                49,\r
+                44\r
+            ],\r
+            "matrix": [\r
+                0.9999974370002748,\r
+                0.0,\r
+                -0.0022710729390382768,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0022710729390382768,\r
+                0.0,\r
+                0.9999974370002748,\r
+                0.0,\r
+                -0.13409000635147096,\r
+                -12.999988555908204,\r
+                0.12365700304508208,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                48,\r
+                47,\r
+                46,\r
+                45\r
+            ],\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -0.000007999999979801942,\r
+                -0.000011000000085914508,\r
+                -99.9995346069336,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 9,\r
+            "matrix": [\r
+                0.9999974370002748,\r
+                0.0,\r
+                0.002270043129101396,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -0.002270043129101396,\r
+                0.0,\r
+                0.9999974370002748,\r
+                0.0,\r
+                49.7321662902832,\r
+                344.3533630371094,\r
+                79.59915161132813,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 10,\r
+            "matrix": [\r
+                0.9999974370002748,\r
+                1.0191530236923485e-13,\r
+                0.0022699993569403888,\r
+                0.0,\r
+                -1.0191530236923485e-13,\r
+                -1.0,\r
+                8.97931243248884e-11,\r
+                0.0,\r
+                0.0022699993569403888,\r
+                -8.97931243248884e-11,\r
+                -0.9999974370002748,\r
+                0.0,\r
+                49.69811248779297,\r
+                257.12298583984377,\r
+                94.59911346435549,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 11,\r
+            "matrix": [\r
+                0.9986716508865356,\r
+                -4.959933574966158e-10,\r
+                -0.051525991410017017,\r
+                0.0,\r
+                -0.051525991410017017,\r
+                -1.9239376314317274e-8,\r
+                -0.9986716508865356,\r
+                0.0,\r
+                -4.959933574966158e-10,\r
+                1.0,\r
+                -1.9239376314317274e-8,\r
+                0.0,\r
+                67.53964233398438,\r
+                326.7381286621094,\r
+                297.74066162109377,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 11,\r
+            "matrix": [\r
+                0.9986629486083984,\r
+                -1.884843170429917e-9,\r
+                -0.05169397220015526,\r
+                0.0,\r
+                -0.05169397220015526,\r
+                -7.287438563707839e-8,\r
+                -0.9986629486083984,\r
+                0.0,\r
+                -1.884843170429917e-9,\r
+                1.0,\r
+                -7.287438563707839e-8,\r
+                0.0,\r
+                17.574960708618165,\r
+                326.7381286621094,\r
+                297.6291809082031,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                53,\r
+                52,\r
+                51,\r
+                50\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 9,\r
+            "matrix": [\r
+                0.9999974370002748,\r
+                0.0,\r
+                0.002270043129101396,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -0.002270043129101396,\r
+                0.0,\r
+                0.9999974370002748,\r
+                0.0,\r
+                49.50515365600586,\r
+                344.3533630371094,\r
+                79.59934997558594,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 10,\r
+            "matrix": [\r
+                0.9999974370002748,\r
+                1.0191530236923485e-13,\r
+                0.0022699993569403888,\r
+                0.0,\r
+                -1.0191530236923485e-13,\r
+                -1.0,\r
+                8.97931243248884e-11,\r
+                0.0,\r
+                0.0022699993569403888,\r
+                -8.97931243248884e-11,\r
+                -0.9999974370002748,\r
+                0.0,\r
+                49.47110366821289,\r
+                257.1229553222656,\r
+                94.59931182861328,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 11,\r
+            "matrix": [\r
+                0.9984543323516846,\r
+                -6.428584886641885e-10,\r
+                -0.05557801201939583,\r
+                0.0,\r
+                -0.05557801201939583,\r
+                -2.311567648405344e-8,\r
+                -0.9984543323516846,\r
+                0.0,\r
+                -6.428584886641885e-10,\r
+                1.0,\r
+                -2.311567648405344e-8,\r
+                0.0,\r
+                68.16710662841797,\r
+                326.7381286621094,\r
+                297.7886657714844,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 11,\r
+            "matrix": [\r
+                0.998445212841034,\r
+                5.507552747197052e-10,\r
+                -0.05574197694659233,\r
+                0.0,\r
+                -0.05574197694659233,\r
+                1.97455189976381e-8,\r
+                -0.998445212841034,\r
+                0.0,\r
+                5.507552747197052e-10,\r
+                1.0,\r
+                1.97455189976381e-8,\r
+                0.0,\r
+                18.201759338378908,\r
+                326.7381286621094,\r
+                297.6770324707031,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 12,\r
+            "matrix": [\r
+                -0.9999873638153076,\r
+                -0.004487415309995413,\r
+                -0.0022699744440615179,\r
+                0.0,\r
+                0.004487401805818081,\r
+                -0.999989926815033,\r
+                0.000011093182365584652,\r
+                0.0,\r
+                -0.0022700014524161817,\r
+                9.06754564766743e-7,\r
+                0.9999974370002748,\r
+                0.0,\r
+                -29.98022842407227,\r
+                768.69921875,\r
+                -20.581327438354493,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 12,\r
+            "matrix": [\r
+                -0.9999850392341614,\r
+                -0.004973169881850481,\r
+                -0.002269970485940576,\r
+                0.0,\r
+                0.004973156377673149,\r
+                -0.9999876618385316,\r
+                0.00001164450713986298,\r
+                0.0,\r
+                -0.0022700002882629639,\r
+                3.554153522600245e-7,\r
+                0.9999974370002748,\r
+                0.0,\r
+                48.794708251953128,\r
+                768.6771850585938,\r
+                -20.40250396728516,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 13,\r
+            "matrix": [\r
+                -0.8213930726051331,\r
+                0.3830228745937348,\r
+                0.4226191341876984,\r
+                0.0,\r
+                -0.3830228745937348,\r
+                0.17860689759254456,\r
+                -0.9063073992729188,\r
+                0.0,\r
+                -0.4226191341876984,\r
+                -0.9063073992729188,\r
+                4.807415265872805e-8,\r
+                0.0,\r
+                -141.64085388183598,\r
+                388.6727600097656,\r
+                122.00779724121094,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 13,\r
+            "matrix": [\r
+                -0.8213450312614441,\r
+                -0.38299909234046938,\r
+                0.42273396253585818,\r
+                0.0,\r
+                -0.38312679529190077,\r
+                -0.1786557286977768,\r
+                -0.9062538146972656,\r
+                0.0,\r
+                0.4226182401180268,\r
+                -0.906307816505432,\r
+                7.823305168130901e-7,\r
+                0.0,\r
+                -270.7940673828125,\r
+                145.4340057373047,\r
+                122.04411315917968,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 14,\r
+            "matrix": [\r
+                1.0,\r
+                -0.000060999998822808269,\r
+                -0.000001000000338535756,\r
+                0.0,\r
+                0.000001000000338535756,\r
+                9.44896494381453e-10,\r
+                1.0,\r
+                0.0,\r
+                -0.000060999998822808269,\r
+                -1.0,\r
+                1.0058964772241553e-9,\r
+                0.0,\r
+                51.087928771972659,\r
+                325.7384033203125,\r
+                91.09835815429688,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 15,\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                -1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                24.52630043029785,\r
+                213.73817443847657,\r
+                283.0735778808594,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 16,\r
+            "matrix": [\r
+                0.9026297926902772,\r
+                -0.4304177761077881,\r
+                0.0,\r
+                0.0,\r
+                0.4304177761077881,\r
+                0.9026297926902772,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                353.9793395996094,\r
+                330.9040222167969,\r
+                -5.389931201934815,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 17,\r
+            "matrix": [\r
+                0.9026297330856324,\r
+                0.4304178953170777,\r
+                0.0,\r
+                0.0,\r
+                -0.4304178953170777,\r
+                0.9026297330856324,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                277.7611083984375,\r
+                580.0806274414063,\r
+                -5.3898539543151859,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 18,\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -1.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                49.58733749389649,\r
+                175.73818969726566,\r
+                89.59835815429688,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 19,\r
+            "matrix": [\r
+                0.9999933242797852,\r
+                -1.649976856532565e-11,\r
+                0.003653998486697674,\r
+                0.0,\r
+                0.003653998486697674,\r
+                9.031045244967118e-9,\r
+                -0.9999933242797852,\r
+                0.0,\r
+                -1.649976856532565e-11,\r
+                1.0,\r
+                9.031045244967118e-9,\r
+                0.0,\r
+                81.19497680664063,\r
+                247.73817443847657,\r
+                220.1460723876953,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 19,\r
+            "matrix": [\r
+                0.9999898672103882,\r
+                -4.353116391658807e-12,\r
+                -0.004497999791055918,\r
+                0.0,\r
+                -0.004497999791055918,\r
+                -1.9355692604250409e-9,\r
+                -0.9999898672103882,\r
+                0.0,\r
+                -4.353116391658807e-12,\r
+                1.0,\r
+                -1.9355692604250409e-9,\r
+                0.0,\r
+                -23.12494468688965,\r
+                247.73817443847657,\r
+                220.35459899902345,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 20,\r
+            "matrix": [\r
+                -2.907086411596538e-7,\r
+                0.7071071863174439,\r
+                -0.7071064114570618,\r
+                0.0,\r
+                7.018321639407077e-7,\r
+                -0.7071064114570618,\r
+                -0.7071071863174439,\r
+                0.0,\r
+                -1.0,\r
+                -7.018321639407077e-7,\r
+                -2.907086411596538e-7,\r
+                0.0,\r
+                65.0,\r
+                128.71702575683598,\r
+                -3.270524024963379,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 21,\r
+            "matrix": [\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                -1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                223.9999847412109,\r
+                31.98792839050293,\r
+                23.50873374938965,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 22,\r
+            "matrix": [\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                -1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                223.9999847412109,\r
+                30.487924575805665,\r
+                25.008731842041017,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 23,\r
+            "matrix": [\r
+                1.1084333451094608e-10,\r
+                -0.0009251347510144116,\r
+                -0.9999995827674866,\r
+                0.0,\r
+                2.396268712345773e-7,\r
+                -0.9999995827674866,\r
+                0.0009251347510144116,\r
+                0.0,\r
+                -1.0,\r
+                -2.396268712345773e-7,\r
+                1.1084333451094608e-10,\r
+                0.0,\r
+                -295.0,\r
+                21.498876571655278,\r
+                0.49255698919296267,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 23,\r
+            "matrix": [\r
+                5.062397168131838e-10,\r
+                0.002356505487114191,\r
+                -0.9999971985816956,\r
+                0.0,\r
+                -4.2965237412317949e-7,\r
+                -0.9999971985816956,\r
+                -0.002356505487114191,\r
+                0.0,\r
+                -1.0,\r
+                4.2965237412317949e-7,\r
+                5.062397168131838e-10,\r
+                0.0,\r
+                -295.0,\r
+                21.60527801513672,\r
+                -105.32867431640624,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 24,\r
+            "matrix": [\r
+                -1.0,\r
+                6.349337028366264e-11,\r
+                6.349337028366264e-11,\r
+                0.0,\r
+                -6.349337028366264e-11,\r
+                -2.220446049250313e-16,\r
+                -1.0,\r
+                0.0,\r
+                -6.349337028366264e-11,\r
+                -1.0,\r
+                -2.220446049250313e-16,\r
+                0.0,\r
+                -126.93566131591796,\r
+                0.000003000000106112566,\r
+                36.558841705322269,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 25,\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -1.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                126.93566131591796,\r
+                -0.00005299999975250103,\r
+                -36.5588493347168,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 26\r
+        },\r
+        {\r
+            "mesh": 27,\r
+            "matrix": [\r
+                -0.9861037135124208,\r
+                0.16613073647022248,\r
+                0.0,\r
+                0.0,\r
+                -0.16613073647022248,\r
+                -0.9861037135124208,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -71.01806640625,\r
+                -22.193012237548829,\r
+                -20.0,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 27,\r
+            "matrix": [\r
+                0.9861037135124208,\r
+                -0.16613082587718965,\r
+                0.0,\r
+                0.0,\r
+                0.16613082587718965,\r
+                0.9861037135124208,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                71.01806640625,\r
+                22.19301414489746,\r
+                22.0,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 28,\r
+            "matrix": [\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -1.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                -100.0,\r
+                -66.15117645263672,\r
+                -5.627896785736084,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 28,\r
+            "matrix": [\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -1.0,\r
+                0.0,\r
+                4.4896641959724089e-11,\r
+                0.0,\r
+                -100.0,\r
+                -66.15116882324219,\r
+                14.372098922729493,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 28,\r
+            "matrix": [\r
+                -2.220446049250313e-16,\r
+                6.349337028366264e-11,\r
+                1.0,\r
+                0.0,\r
+                -6.349337028366264e-11,\r
+                -1.0,\r
+                6.349337028366264e-11,\r
+                0.0,\r
+                1.0,\r
+                -6.349337028366264e-11,\r
+                -2.220446049250313e-16,\r
+                0.0,\r
+                100.0,\r
+                -133.8488311767578,\r
+                34.37212753295899,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 28,\r
+            "matrix": [\r
+                -2.220446049250313e-16,\r
+                6.349337028366264e-11,\r
+                1.0,\r
+                0.0,\r
+                -6.349337028366264e-11,\r
+                -1.0,\r
+                6.349337028366264e-11,\r
+                0.0,\r
+                1.0,\r
+                -6.349337028366264e-11,\r
+                -2.220446049250313e-16,\r
+                0.0,\r
+                100.0,\r
+                -133.8488311767578,\r
+                54.37212371826172,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 23,\r
+            "matrix": [\r
+                5.062397168131838e-10,\r
+                0.002356505487114191,\r
+                -0.9999971985816956,\r
+                0.0,\r
+                -4.2965237412317949e-7,\r
+                -0.9999971985816956,\r
+                -0.002356505487114191,\r
+                0.0,\r
+                -1.0,\r
+                4.2965237412317949e-7,\r
+                5.062397168131838e-10,\r
+                0.0,\r
+                -295.0,\r
+                123.80779266357422,\r
+                -100.10150146484377,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 23,\r
+            "matrix": [\r
+                5.062397168131838e-10,\r
+                0.002356505487114191,\r
+                -0.9999971985816956,\r
+                0.0,\r
+                -4.2965237412317949e-7,\r
+                -0.9999971985816956,\r
+                -0.002356505487114191,\r
+                0.0,\r
+                -1.0,\r
+                4.2965237412317949e-7,\r
+                5.062397168131838e-10,\r
+                0.0,\r
+                -295.0,\r
+                132.1395263671875,\r
+                -3.9833459854125978,\r
+                1.0\r
+            ]\r
+        },\r
+        {\r
+            "matrix": [\r
+                0.7071067690849304,\r
+                -2.1563657526257888e-7,\r
+                -0.7071068286895752,\r
+                0.0,\r
+                -0.3312943577766419,\r
+                0.883452296257019,\r
+                -0.33129459619522097,\r
+                0.0,\r
+                0.6246951818466187,\r
+                0.4685211479663849,\r
+                0.6246950030326843,\r
+                0.0,\r
+                1005.9874267578124,\r
+                766.3170776367188,\r
+                953.3455810546876,\r
+                1.0\r
+            ],\r
+            "camera": 0\r
+        }\r
+    ],\r
+    "cameras": [\r
+        {\r
+            "perspective": {\r
+                "aspectRatio": 1.0,\r
+                "yfov": 0.3143463730812073,\r
+                "zfar": 1000000.0,\r
+                "znear": 0.04999999701976776\r
+            },\r
+            "type": "perspective"\r
+        }\r
+    ],\r
+    "meshes": [\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 1,\r
+                        "POSITION": 2\r
+                    },\r
+                    "indices": 0,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                },\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 4,\r
+                        "POSITION": 5\r
+                    },\r
+                    "indices": 3,\r
+                    "mode": 4,\r
+                    "material": 1\r
+                }\r
+            ],\r
+            "name": "Piston_123-844_0_Parts_1"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 7,\r
+                        "POSITION": 8\r
+                    },\r
+                    "indices": 6,\r
+                    "mode": 4,\r
+                    "material": 2\r
+                }\r
+            ],\r
+            "name": "body_24"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 10,\r
+                        "POSITION": 11\r
+                    },\r
+                    "indices": 9,\r
+                    "mode": 4,\r
+                    "material": 3\r
+                }\r
+            ],\r
+            "name": "body_23"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 13,\r
+                        "POSITION": 14\r
+                    },\r
+                    "indices": 12,\r
+                    "mode": 4,\r
+                    "material": 4\r
+                }\r
+            ],\r
+            "name": "body_22"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 16,\r
+                        "POSITION": 17\r
+                    },\r
+                    "indices": 15,\r
+                    "mode": 4,\r
+                    "material": 5\r
+                }\r
+            ],\r
+            "name": "body_21"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 19,\r
+                        "POSITION": 20\r
+                    },\r
+                    "indices": 18,\r
+                    "mode": 4,\r
+                    "material": 6\r
+                }\r
+            ],\r
+            "name": "body_20"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 22,\r
+                        "POSITION": 23\r
+                    },\r
+                    "indices": 21,\r
+                    "mode": 4,\r
+                    "material": 7\r
+                },\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 25,\r
+                        "POSITION": 26\r
+                    },\r
+                    "indices": 24,\r
+                    "mode": 4,\r
+                    "material": 8\r
+                },\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 28,\r
+                        "POSITION": 29\r
+                    },\r
+                    "indices": 27,\r
+                    "mode": 4,\r
+                    "material": 9\r
+                }\r
+            ],\r
+            "name": "Spring_Link__0_Parts_1"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 31,\r
+                        "POSITION": 32\r
+                    },\r
+                    "indices": 30,\r
+                    "mode": 4,\r
+                    "material": 10\r
+                }\r
+            ],\r
+            "name": "body_19"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 34,\r
+                        "POSITION": 35\r
+                    },\r
+                    "indices": 33,\r
+                    "mode": 4,\r
+                    "material": 11\r
+                }\r
+            ],\r
+            "name": "body_18"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 37,\r
+                        "POSITION": 38\r
+                    },\r
+                    "indices": 36,\r
+                    "mode": 4,\r
+                    "material": 12\r
+                }\r
+            ],\r
+            "name": "body_17"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 40,\r
+                        "POSITION": 41\r
+                    },\r
+                    "indices": 39,\r
+                    "mode": 4,\r
+                    "material": 13\r
+                }\r
+            ],\r
+            "name": "body_16"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 43,\r
+                        "POSITION": 44\r
+                    },\r
+                    "indices": 42,\r
+                    "mode": 4,\r
+                    "material": 14\r
+                }\r
+            ],\r
+            "name": "body_15"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 46,\r
+                        "POSITION": 47\r
+                    },\r
+                    "indices": 45,\r
+                    "mode": 4,\r
+                    "material": 15\r
+                }\r
+            ],\r
+            "name": "body_14"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 49,\r
+                        "POSITION": 50\r
+                    },\r
+                    "indices": 48,\r
+                    "mode": 4,\r
+                    "material": 16\r
+                }\r
+            ],\r
+            "name": "body_13"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 52,\r
+                        "POSITION": 53\r
+                    },\r
+                    "indices": 51,\r
+                    "mode": 4,\r
+                    "material": 17\r
+                }\r
+            ],\r
+            "name": "body_12"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 55,\r
+                        "POSITION": 56\r
+                    },\r
+                    "indices": 54,\r
+                    "mode": 4,\r
+                    "material": 18\r
+                }\r
+            ],\r
+            "name": "body_11"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 58,\r
+                        "POSITION": 59\r
+                    },\r
+                    "indices": 57,\r
+                    "mode": 4,\r
+                    "material": 19\r
+                }\r
+            ],\r
+            "name": "body_10"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 61,\r
+                        "POSITION": 62\r
+                    },\r
+                    "indices": 60,\r
+                    "mode": 4,\r
+                    "material": 20\r
+                }\r
+            ],\r
+            "name": "body_9"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 64,\r
+                        "POSITION": 65\r
+                    },\r
+                    "indices": 63,\r
+                    "mode": 4,\r
+                    "material": 21\r
+                }\r
+            ],\r
+            "name": "body_8"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 67,\r
+                        "POSITION": 68\r
+                    },\r
+                    "indices": 66,\r
+                    "mode": 4,\r
+                    "material": 22\r
+                }\r
+            ],\r
+            "name": "body_7"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 70,\r
+                        "POSITION": 71\r
+                    },\r
+                    "indices": 69,\r
+                    "mode": 4,\r
+                    "material": 23\r
+                }\r
+            ],\r
+            "name": "body_6"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 73,\r
+                        "POSITION": 74\r
+                    },\r
+                    "indices": 72,\r
+                    "mode": 4,\r
+                    "material": 24\r
+                }\r
+            ],\r
+            "name": "body_5"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 76,\r
+                        "POSITION": 77\r
+                    },\r
+                    "indices": 75,\r
+                    "mode": 4,\r
+                    "material": 25\r
+                }\r
+            ],\r
+            "name": "body_4"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 79,\r
+                        "POSITION": 80\r
+                    },\r
+                    "indices": 78,\r
+                    "mode": 4,\r
+                    "material": 26\r
+                }\r
+            ],\r
+            "name": "body"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 82,\r
+                        "POSITION": 83\r
+                    },\r
+                    "indices": 81,\r
+                    "mode": 4,\r
+                    "material": 27\r
+                }\r
+            ],\r
+            "name": "body_3"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 85,\r
+                        "POSITION": 86\r
+                    },\r
+                    "indices": 84,\r
+                    "mode": 4,\r
+                    "material": 28\r
+                }\r
+            ],\r
+            "name": "body_2"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 88,\r
+                        "POSITION": 89\r
+                    },\r
+                    "indices": 87,\r
+                    "mode": 4,\r
+                    "material": 29\r
+                }\r
+            ],\r
+            "name": "body_1"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 91,\r
+                        "POSITION": 92\r
+                    },\r
+                    "indices": 90,\r
+                    "mode": 4,\r
+                    "material": 30\r
+                },\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 94,\r
+                        "POSITION": 95\r
+                    },\r
+                    "indices": 93,\r
+                    "mode": 4,\r
+                    "material": 31\r
+                }\r
+            ],\r
+            "name": "rod_123-699_0_Parts_1"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 97,\r
+                        "POSITION": 98\r
+                    },\r
+                    "indices": 96,\r
+                    "mode": 4,\r
+                    "material": 32\r
+                },\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 100,\r
+                        "POSITION": 101\r
+                    },\r
+                    "indices": 99,\r
+                    "mode": 4,\r
+                    "material": 33\r
+                }\r
+            ],\r
+            "name": "Lifter_123-923_0_Parts_1"\r
+        }\r
+    ],\r
+    "accessors": [\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 0,\r
+            "componentType": 5123,\r
+            "count": 8250,\r
+            "max": [\r
+                2011\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 2012,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 24144,\r
+            "componentType": 5126,\r
+            "count": 2012,\r
+            "max": [\r
+                63.35246658325195,\r
+                56.026153564453128,\r
+                46.5\r
+            ],\r
+            "min": [\r
+                -43.13071060180664,\r
+                -36.97384643554688,\r
+                -46.5\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 16500,\r
+            "componentType": 5123,\r
+            "count": 5034,\r
+            "max": [\r
+                1295\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 48288,\r
+            "componentType": 5126,\r
+            "count": 1296,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                0.9992589950561525\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -0.9992589950561525\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 63840,\r
+            "componentType": 5126,\r
+            "count": 1296,\r
+            "max": [\r
+                53.35246658325195,\r
+                56.026153564453128,\r
+                46.46559143066406\r
+            ],\r
+            "min": [\r
+                31.869285583496095,\r
+                -36.97384643554688,\r
+                -46.46559143066406\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 26568,\r
+            "componentType": 5123,\r
+            "count": 936,\r
+            "max": [\r
+                263\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 79392,\r
+            "componentType": 5126,\r
+            "count": 264,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 82560,\r
+            "componentType": 5126,\r
+            "count": 264,\r
+            "max": [\r
+                -242.49256896972657,\r
+                107.58116149902344,\r
+                85.0\r
+            ],\r
+            "min": [\r
+                -264.4925537109375,\r
+                85.59744262695313,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 28440,\r
+            "componentType": 5123,\r
+            "count": 1845,\r
+            "max": [\r
+                669\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 85728,\r
+            "componentType": 5126,\r
+            "count": 670,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 93768,\r
+            "componentType": 5126,\r
+            "count": 670,\r
+            "max": [\r
+                35.97993087768555,\r
+                35.75779342651367,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                -35.97993087768555,\r
+                -35.97336959838867,\r
+                -15.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 32130,\r
+            "componentType": 5123,\r
+            "count": 6489,\r
+            "max": [\r
+                1552\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 101808,\r
+            "componentType": 5126,\r
+            "count": 1553,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 120444,\r
+            "componentType": 5126,\r
+            "count": 1553,\r
+            "max": [\r
+                63.0,\r
+                35.0,\r
+                113.5\r
+            ],\r
+            "min": [\r
+                -62.99030303955078,\r
+                -35.0,\r
+                -140.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 45108,\r
+            "componentType": 5123,\r
+            "count": 9267,\r
+            "max": [\r
+                2469\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 139080,\r
+            "componentType": 5126,\r
+            "count": 2470,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 168720,\r
+            "componentType": 5126,\r
+            "count": 2470,\r
+            "max": [\r
+                68.9806137084961,\r
+                -31.11992645263672,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                -68.9806137084961,\r
+                -168.8800811767578,\r
+                -15.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 63642,\r
+            "componentType": 5123,\r
+            "count": 4839,\r
+            "max": [\r
+                1381\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 198360,\r
+            "componentType": 5126,\r
+            "count": 1382,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 214944,\r
+            "componentType": 5126,\r
+            "count": 1382,\r
+            "max": [\r
+                177.38954162597657,\r
+                -14.305740356445313,\r
+                18.985939025878908\r
+            ],\r
+            "min": [\r
+                -76.1104507446289,\r
+                -55.56795501708985,\r
+                -19.073078155517576\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 73320,\r
+            "componentType": 5123,\r
+            "count": 123,\r
+            "max": [\r
+                42\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 231528,\r
+            "componentType": 5126,\r
+            "count": 43,\r
+            "max": [\r
+                0.9818310141563416,\r
+                0.9992589950561525,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 232044,\r
+            "componentType": 5126,\r
+            "count": 43,\r
+            "max": [\r
+                131.15240478515626,\r
+                -35.549163818359378,\r
+                5.0\r
+            ],\r
+            "min": [\r
+                129.44984436035157,\r
+                -37.250465393066409,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 73566,\r
+            "componentType": 5123,\r
+            "count": 123,\r
+            "max": [\r
+                42\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 232560,\r
+            "componentType": 5126,\r
+            "count": 43,\r
+            "max": [\r
+                0.9992589950561525,\r
+                1.0,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                -0.9992589950561525,\r
+                -0.9818310141563416,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 233076,\r
+            "componentType": 5126,\r
+            "count": 43,\r
+            "max": [\r
+                131.19471740722657,\r
+                -61.50555038452149,\r
+                5.0\r
+            ],\r
+            "min": [\r
+                129.4075164794922,\r
+                -63.2940788269043,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 73812,\r
+            "componentType": 5123,\r
+            "count": 4842,\r
+            "max": [\r
+                869\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 233592,\r
+            "componentType": 5126,\r
+            "count": 870,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                0.9992589950561525\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 244032,\r
+            "componentType": 5126,\r
+            "count": 870,\r
+            "max": [\r
+                132.30111694335938,\r
+                -34.40129470825195,\r
+                14.998519897460938\r
+            ],\r
+            "min": [\r
+                128.30111694335938,\r
+                -64.39833068847656,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 83496,\r
+            "componentType": 5123,\r
+            "count": 987,\r
+            "max": [\r
+                293\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 254472,\r
+            "componentType": 5126,\r
+            "count": 294,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                0.9992589950561525\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -0.9992589950561525\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 258000,\r
+            "componentType": 5126,\r
+            "count": 294,\r
+            "max": [\r
+                181.5590057373047,\r
+                312.1140747070313,\r
+                17.986684799194337\r
+            ],\r
+            "min": [\r
+                71.55899810791016,\r
+                276.1140747070313,\r
+                -17.986684799194337\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 85470,\r
+            "componentType": 5123,\r
+            "count": 2145,\r
+            "max": [\r
+                623\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 261528,\r
+            "componentType": 5126,\r
+            "count": 624,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                0.9992589950561525\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -0.9992589950561525\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 269016,\r
+            "componentType": 5126,\r
+            "count": 624,\r
+            "max": [\r
+                211.16444396972657,\r
+                300.2055358886719,\r
+                15.988161087036133\r
+            ],\r
+            "min": [\r
+                202.16444396972657,\r
+                268.2055358886719,\r
+                -15.988161087036133\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 89760,\r
+            "componentType": 5123,\r
+            "count": 1566,\r
+            "max": [\r
+                407\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 276504,\r
+            "componentType": 5126,\r
+            "count": 408,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 281400,\r
+            "componentType": 5126,\r
+            "count": 408,\r
+            "max": [\r
+                54.54435348510742,\r
+                -38.61518478393555,\r
+                15.0\r
+            ],\r
+            "min": [\r
+                -44.45564651489258,\r
+                -80.61518859863281,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 92892,\r
+            "componentType": 5123,\r
+            "count": 1359,\r
+            "max": [\r
+                339\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 286296,\r
+            "componentType": 5126,\r
+            "count": 340,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 290376,\r
+            "componentType": 5126,\r
+            "count": 340,\r
+            "max": [\r
+                54.54435348510742,\r
+                -48.61518478393555,\r
+                15.0\r
+            ],\r
+            "min": [\r
+                -44.45564651489258,\r
+                -61.61518478393555,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 95610,\r
+            "componentType": 5123,\r
+            "count": 1032,\r
+            "max": [\r
+                323\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 294456,\r
+            "componentType": 5126,\r
+            "count": 324,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 298344,\r
+            "componentType": 5126,\r
+            "count": 324,\r
+            "max": [\r
+                30.5535831451416,\r
+                217.1583709716797,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                15.553584098815918,\r
+                202.16946411132813,\r
+                -81.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 97674,\r
+            "componentType": 5123,\r
+            "count": 288,\r
+            "max": [\r
+                95\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 302232,\r
+            "componentType": 5126,\r
+            "count": 96,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 303384,\r
+            "componentType": 5126,\r
+            "count": 96,\r
+            "max": [\r
+                -36.67900466918945,\r
+                469.6546325683594,\r
+                115.00000762939452\r
+            ],\r
+            "min": [\r
+                -49.67900466918945,\r
+                456.6642761230469,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 98250,\r
+            "componentType": 5123,\r
+            "count": 1266,\r
+            "max": [\r
+                347\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 304536,\r
+            "componentType": 5126,\r
+            "count": 348,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 308712,\r
+            "componentType": 5126,\r
+            "count": 348,\r
+            "max": [\r
+                -278.3986206054688,\r
+                -55.62376022338867,\r
+                65.0\r
+            ],\r
+            "min": [\r
+                -296.3985900878906,\r
+                -73.61044311523438,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 100782,\r
+            "componentType": 5123,\r
+            "count": 5787,\r
+            "max": [\r
+                1408\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 312888,\r
+            "componentType": 5126,\r
+            "count": 1409,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 329796,\r
+            "componentType": 5126,\r
+            "count": 1409,\r
+            "max": [\r
+                105.0087432861328,\r
+                60.05363082885742,\r
+                75.0\r
+            ],\r
+            "min": [\r
+                -97.99126434326172,\r
+                -124.0295867919922,\r
+                2.307800054550171\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 112356,\r
+            "componentType": 5123,\r
+            "count": 8964,\r
+            "max": [\r
+                1939\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 346704,\r
+            "componentType": 5126,\r
+            "count": 1940,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 369984,\r
+            "componentType": 5126,\r
+            "count": 1940,\r
+            "max": [\r
+                40.85147476196289,\r
+                233.1286773681641,\r
+                70.0\r
+            ],\r
+            "min": [\r
+                19.2884521484375,\r
+                214.79766845703129,\r
+                -28.7859001159668\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 130284,\r
+            "componentType": 5123,\r
+            "count": 10167,\r
+            "max": [\r
+                1753\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 393264,\r
+            "componentType": 5126,\r
+            "count": 1754,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9999880194664002,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 414312,\r
+            "componentType": 5126,\r
+            "count": 1754,\r
+            "max": [\r
+                -252.55343627929688,\r
+                -164.07803344726566,\r
+                85.0\r
+            ],\r
+            "min": [\r
+                -330.4447326660156,\r
+                -199.1783599853516,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 150618,\r
+            "componentType": 5123,\r
+            "count": 10125,\r
+            "max": [\r
+                1748\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 435360,\r
+            "componentType": 5126,\r
+            "count": 1749,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9999880194664002,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 456348,\r
+            "componentType": 5126,\r
+            "count": 1749,\r
+            "max": [\r
+                -248.47320556640626,\r
+                -164.07803344726566,\r
+                85.0\r
+            ],\r
+            "min": [\r
+                -326.3644409179688,\r
+                -199.1783599853516,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 170868,\r
+            "componentType": 5123,\r
+            "count": 21150,\r
+            "max": [\r
+                5473\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 477336,\r
+            "componentType": 5126,\r
+            "count": 5474,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 543024,\r
+            "componentType": 5126,\r
+            "count": 5474,\r
+            "max": [\r
+                113.00873565673828,\r
+                59.71368026733399,\r
+                0.0026710000820457937\r
+            ],\r
+            "min": [\r
+                -102.99126434326172,\r
+                -120.6896514892578,\r
+                -82.39035034179688\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 213168,\r
+            "componentType": 5123,\r
+            "count": 1359,\r
+            "max": [\r
+                371\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 608712,\r
+            "componentType": 5126,\r
+            "count": 372,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 613176,\r
+            "componentType": 5126,\r
+            "count": 372,\r
+            "max": [\r
+                37.65166091918945,\r
+                226.15505981445316,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                13.65165901184082,\r
+                202.1728057861328,\r
+                -17.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 215886,\r
+            "componentType": 5123,\r
+            "count": 684,\r
+            "max": [\r
+                239\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 617640,\r
+            "componentType": 5126,\r
+            "count": 240,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 620520,\r
+            "componentType": 5126,\r
+            "count": 240,\r
+            "max": [\r
+                -25.97146224975586,\r
+                156.0619659423828,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                -188.97146606445316,\r
+                -6.938029766082764,\r
+                -230.0000152587891\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 217254,\r
+            "componentType": 5123,\r
+            "count": 5889,\r
+            "max": [\r
+                1413\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 623400,\r
+            "componentType": 5126,\r
+            "count": 1414,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 640368,\r
+            "componentType": 5126,\r
+            "count": 1414,\r
+            "max": [\r
+                105.0087432861328,\r
+                60.05352783203125,\r
+                147.6921844482422\r
+            ],\r
+            "min": [\r
+                -97.99126434326172,\r
+                -124.0295867919922,\r
+                75.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 229032,\r
+            "componentType": 5123,\r
+            "count": 20607,\r
+            "max": [\r
+                5363\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 657336,\r
+            "componentType": 5126,\r
+            "count": 5364,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 721704,\r
+            "componentType": 5126,\r
+            "count": 5364,\r
+            "max": [\r
+                113.00873565673828,\r
+                59.71368026733399,\r
+                82.39035034179688\r
+            ],\r
+            "min": [\r
+                -102.99126434326172,\r
+                -120.6896514892578,\r
+                -0.002749999985098839\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 270246,\r
+            "componentType": 5123,\r
+            "count": 573,\r
+            "max": [\r
+                191\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 786072,\r
+            "componentType": 5126,\r
+            "count": 192,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 788376,\r
+            "componentType": 5126,\r
+            "count": 192,\r
+            "max": [\r
+                -25.97146224975586,\r
+                81.05715942382813,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                -38.97146224975586,\r
+                68.06676483154297,\r
+                -230.0000152587891\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 271392,\r
+            "componentType": 5123,\r
+            "count": 32934,\r
+            "max": [\r
+                8617\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 790680,\r
+            "componentType": 5126,\r
+            "count": 8618,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 894096,\r
+            "componentType": 5126,\r
+            "count": 8618,\r
+            "max": [\r
+                99.06433868408205,\r
+                151.558837890625,\r
+                80.00056457519531\r
+            ],\r
+            "min": [\r
+                -61.93566513061524,\r
+                -38.4411506652832,\r
+                -80.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 337260,\r
+            "componentType": 5123,\r
+            "count": 33420,\r
+            "max": [\r
+                8617\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 997512,\r
+            "componentType": 5126,\r
+            "count": 8618,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1100928,\r
+            "componentType": 5126,\r
+            "count": 8618,\r
+            "max": [\r
+                99.06433868408205,\r
+                151.558837890625,\r
+                80.00056457519531\r
+            ],\r
+            "min": [\r
+                -61.93566513061524,\r
+                -38.4411506652832,\r
+                -80.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 404100,\r
+            "componentType": 5123,\r
+            "count": 17691,\r
+            "max": [\r
+                3671\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1204344,\r
+            "componentType": 5126,\r
+            "count": 3672,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1248408,\r
+            "componentType": 5126,\r
+            "count": 3672,\r
+            "max": [\r
+                95.0,\r
+                90.0,\r
+                112.99999237060549\r
+            ],\r
+            "min": [\r
+                -95.0,\r
+                -180.9715576171875,\r
+                -120.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 439482,\r
+            "componentType": 5123,\r
+            "count": 3903,\r
+            "max": [\r
+                1280\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1292472,\r
+            "componentType": 5126,\r
+            "count": 1281,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1307844,\r
+            "componentType": 5126,\r
+            "count": 1281,\r
+            "max": [\r
+                111.05359649658205,\r
+                30.67658042907715,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                -70.94640350341797,\r
+                -43.32342147827149,\r
+                -10.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 447288,\r
+            "componentType": 5123,\r
+            "count": 960,\r
+            "max": [\r
+                179\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1323216,\r
+            "componentType": 5126,\r
+            "count": 180,\r
+            "max": [\r
+                1.0,\r
+                0.9992589950561525,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1325376,\r
+            "componentType": 5126,\r
+            "count": 180,\r
+            "max": [\r
+                76.06450653076172,\r
+                2.5340518951416017,\r
+                7.0\r
+            ],\r
+            "min": [\r
+                -11.810647010803225,\r
+                -15.180893898010254,\r
+                -7.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 449208,\r
+            "componentType": 5123,\r
+            "count": 423,\r
+            "max": [\r
+                142\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1327536,\r
+            "componentType": 5126,\r
+            "count": 143,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -0.9992589950561525,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1329252,\r
+            "componentType": 5126,\r
+            "count": 143,\r
+            "max": [\r
+                -16.62210273742676,\r
+                -26.09882354736328,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                -32.12210464477539,\r
+                -41.59605407714844,\r
+                -81.32071685791016\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 450054,\r
+            "componentType": 5123,\r
+            "count": 2163,\r
+            "max": [\r
+                385\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1330968,\r
+            "componentType": 5126,\r
+            "count": 386,\r
+            "max": [\r
+                0.7761409878730774,\r
+                0.7761409878730774,\r
+                -0.6286939978599548\r
+            ],\r
+            "min": [\r
+                -0.7758179903030396,\r
+                -0.7761409878730774,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1335600,\r
+            "componentType": 5126,\r
+            "count": 386,\r
+            "max": [\r
+                -16.62210273742676,\r
+                -26.09882354736328,\r
+                -81.31858825683594\r
+            ],\r
+            "min": [\r
+                -32.11616134643555,\r
+                -41.59875106811524,\r
+                -85.0\r
+            ],\r
+            "type": "VEC3"\r
+        }\r
+    ],\r
+    "materials": [\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_21"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.42500001192092898,\r
+                    0.42500001192092898,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_22"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.42500001192092898,\r
+                    0.42500001192092898,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_22"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.0,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_18"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.5609999895095825,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_23"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_16"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_16"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_16"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_16"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.5609999895095825,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_23"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_16"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.42500001192092898,\r
+                    0.42500001192092898,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_22"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.5609999895095825,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_23"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_16"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_19"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    0.8500000238418579,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_20"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.5609999895095825,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_17"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.8500000238418579,\r
+                    0.0,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "name": "Material_18"\r
+        }\r
+    ],\r
+    "bufferViews": [\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 1340232,\r
+            "byteLength": 454380,\r
+            "target": 34963\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 0,\r
+            "byteLength": 1340232,\r
+            "byteStride": 12,\r
+            "target": 34962\r
+        }\r
+    ],\r
+    "buffers": [\r
+        {\r
+            "byteLength": 1794612,\r
+            "uri": "2CylinderEngine0.bin"\r
+        }\r
+    ]\r
+}\r
diff --git a/automated-tests/resources/2CylinderEngine0.bin b/automated-tests/resources/2CylinderEngine0.bin
new file mode 100644 (file)
index 0000000..e8cb49d
Binary files /dev/null and b/automated-tests/resources/2CylinderEngine0.bin differ
diff --git a/automated-tests/resources/AnimatedMorphCube.bin b/automated-tests/resources/AnimatedMorphCube.bin
new file mode 100644 (file)
index 0000000..7b14a17
Binary files /dev/null and b/automated-tests/resources/AnimatedMorphCube.bin differ
diff --git a/automated-tests/resources/AnimatedMorphCube.gltf b/automated-tests/resources/AnimatedMorphCube.gltf
new file mode 100644 (file)
index 0000000..fa99bc5
--- /dev/null
@@ -0,0 +1,282 @@
+{\r
+  "accessors": [\r
+    {\r
+      "bufferView": 0,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0100000035,\r
+        0.0100000035,\r
+        0.01\r
+      ],\r
+      "min": [\r
+        -0.0100000044,\r
+        -0.0100000054,\r
+        -0.01\r
+      ]\r
+    },\r
+    {\r
+      "bufferView": 3,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "thin"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0,\r
+        0.01893253,\r
+        0.0\r
+      ],\r
+      "min": [\r
+        0.0,\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "thin"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "thin"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "angle"\r
+    },\r
+    {\r
+      "bufferView": 7,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0,\r
+        0.0198908355,\r
+        0.0\r
+      ],\r
+      "min": [\r
+        0.0,\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "angle"\r
+    },\r
+    {\r
+      "bufferView": 8,\r
+      "componentType": 5126,\r
+      "count": 24,\r
+      "type": "VEC3",\r
+      "name": "angle"\r
+    },\r
+    {\r
+      "bufferView": 9,\r
+      "componentType": 5123,\r
+      "count": 36,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 10,\r
+      "componentType": 5126,\r
+      "count": 127,\r
+      "type": "SCALAR",\r
+      "max": [\r
+        4.19999743\r
+      ],\r
+      "min": [\r
+        0.0\r
+      ]\r
+    },\r
+    {\r
+      "bufferView": 11,\r
+      "componentType": 5126,\r
+      "count": 254,\r
+      "type": "SCALAR"\r
+    }\r
+  ],\r
+  "animations": [\r
+    {\r
+      "channels": [\r
+        {\r
+          "sampler": 0,\r
+          "target": {\r
+            "node": 0,\r
+            "path": "weights"\r
+          }\r
+        }\r
+      ],\r
+      "samplers": [\r
+        {\r
+          "input": 10,\r
+          "interpolation": "LINEAR",\r
+          "output": 11\r
+        }\r
+      ],\r
+      "name": "Square"\r
+    }\r
+  ],\r
+  "asset": {\r
+    "generator": "glTF Tools for Unity",\r
+    "version": "2.0"\r
+  },\r
+  "bufferViews": [\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 288,\r
+      "byteLength": 384\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 672,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 960,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1248,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1536,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1824,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2112,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2400,\r
+      "byteLength": 288\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2688,\r
+      "byteLength": 72\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 2760,\r
+      "byteLength": 508\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 3268,\r
+      "byteLength": 1016\r
+    }\r
+  ],\r
+  "buffers": [\r
+    {\r
+      "uri": "AnimatedMorphCube.bin",\r
+      "byteLength": 4284\r
+    }\r
+  ],\r
+  "meshes": [\r
+    {\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "NORMAL": 0,\r
+            "TANGENT": 1,\r
+            "POSITION": 2\r
+          },\r
+          "indices": 9,\r
+          "material": 0,\r
+          "targets": [\r
+            {\r
+              "NORMAL": 3,\r
+              "POSITION": 4,\r
+              "TANGENT": 5\r
+            },\r
+            {\r
+              "NORMAL": 6,\r
+              "POSITION": 7,\r
+              "TANGENT": 8\r
+            }\r
+          ]\r
+        }\r
+      ],\r
+      "weights": [\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "Cube"\r
+    }\r
+  ],\r
+  "materials": [\r
+    {\r
+      "pbrMetallicRoughness": {\r
+        "baseColorFactor": [\r
+          0.6038274,\r
+          0.6038274,\r
+          0.6038274,\r
+          1.0\r
+        ],\r
+        "metallicFactor": 0.0,\r
+        "roughnessFactor": 0.5\r
+      },\r
+      "name": "Material"\r
+    }\r
+  ],\r
+  "nodes": [\r
+    {\r
+      "mesh": 0,\r
+      "rotation": [\r
+        0.0,\r
+        0.7071067,\r
+        -0.7071068,\r
+        0.0\r
+      ],\r
+      "scale": [\r
+        100.0,\r
+        100.0,\r
+        100.0\r
+      ],\r
+      "name": "AnimatedMorphCube"\r
+    }\r
+  ],\r
+  "scene": 0,\r
+  "scenes": [\r
+    {\r
+      "nodes": [\r
+        0\r
+      ]\r
+    }\r
+  ]\r
+}
\ No newline at end of file
diff --git a/automated-tests/resources/AnimatedMorphSphere.bin b/automated-tests/resources/AnimatedMorphSphere.bin
new file mode 100644 (file)
index 0000000..5bc8fc6
--- /dev/null
@@ -0,0 +1,185 @@
+\86ô=½u\18ñ>f\87a¿\86ô=½u\18ñ>f\87a¿\86ô=½u\18ñ>f\87a¿\86ô=½u\18ñ>f\87a¿å7±½Çì`?9sð>å7±½Çì`?9sð>å7±½Çì`?9sð>å7±½Çì`?9sð>nk\7f½±\16"?k\81E¿nk\7f½±\16"?k\81E¿nk\7f½±\16"?k\81E¿nk\7f½±\16"?k\81E¿Õw\9b½ßQE?\95ï!?Õw\9b½ßQE?\95ï!?Õw\9b½ßQE?\95ï!?Õw\9b½ßQE?\95ï!?Õw\9b½ßQE?\95ï!¿Õw\9b½ßQE?\95ï!¿Õw\9b½ßQE?\95ï!¿Õw\9b½ßQE?\95ï!¿¹k\7f½°\16"?j\81E?¹k\7f½°\16"?j\81E?¹k\7f½°\16"?j\81E?¹k\7f½°\16"?j\81E?ð7±½Çì`?6sð¾ð7±½Çì`?6sð¾ð7±½Çì`?6sð¾ð7±½Çì`?6sð¾\88ô=½\7f\18ñ>d\87a?\88ô=½\7f\18ñ>d\87a?\88ô=½\7f\18ñ>d\87a?\88ô=½\7f\18ñ>d\87a?\8b*À½_ås?4ø\93¾\8b*À½_ås?4ø\93¾\8b*À½_ås?4ø\93¾\8b*À½_ås?4ø\93¾\v\eê¼¢\90\94>màt?\v\eê¼¢\90\94>màt?\v\eê¼¢\90\94>màt?\v\eê¼¢\90\94>màt?ãÅǽe\8d}?IÈǽãÅǽe\8d}?IÈǽãÅǽe\8d}?IÈǽãÅǽe\8d}?IÈǽ\8f\1a\1e¼ËºÈ=dÁ~¿\8f\1a\1e¼ËºÈ=dÁ~¿\8f\1a\1e¼ËºÈ=dÁ~¿Î5ê¼÷\ 3Á=bÁ~¿A+>½Pâ±=bÁ~¿ù5ê<\v\ 4Á=bÁ~¿f+>=fâ±=bÁ~¿Rç\7f½ªê\9b=fÁ~¿Rç\7f½ªê\9b=fÁ~¿[ë\9b½Cê\7f=bÁ~¿íà±½u)>=hÁ~¿\8f\ 4Á½Ò3ê<bÁ~¿\8f\ 4Á½Ò3ê<bÁ~¿ZºÈ½\a)\1e<dÁ~¿Q»È½+)\1e¼bÁ~¿\r\ 3Á½\ 64ê¼fÁ~¿\r\ 3Á½\ 64ê¼fÁ~¿\16ã±½\99)>½bÁ~¿\é\9b½vê\7f½fÁ~¿·ë\7f½Êê\9b½bÁ~¿·ë\7f½Êê\9b½bÁ~¿E'>½xâ±½dÁ~¿ª-ê¼#\ 4Á½dÁ~¿!<\1e¼çºÈ½bÁ~¿!<\1e¼çºÈ½bÁ~¿#<\1e<éºÈ½bÁ~¿¾-ê<'\ 4Á½dÁ~¿T'>=\82â±½dÁ~¿T'>=\82â±½dÁ~¿×ë\7f=Õê\9b½bÁ~¿~ê\9b=\82ê\7f½dÁ~¿1â±=°)>½dÁ~¿1â±=°)>½dÁ~¿Â\ 4Á=þ3ê¼aÁ~¿_»È=+)\1e¼bÁ~¿qºÈ=M)\1e<dÁ~¿qºÈ=M)\1e<dÁ~¿C\ 5Á=\b4ê<aÁ~¿\16á±=¡)>=fÁ~¿wë\9b=rê\7f=bÁ~¿wë\9b=rê\7f=bÁ~¿\8aç\7f=Äê\9b=fÁ~¿\94#\1e¼ÂºÈ=dÁ~?\94#\1e¼ÂºÈ=dÁ~?\94#\1e¼ÂºÈ=dÁ~?Y1ê¼ñ\ 3Á=dÁ~?{+>½Râ±=bÁ~?s1ê<þ\ 3Á=dÁ~?\8a+>=Yâ±=bÁ~?«è\7f½ªê\9b=dÁ~?«è\7f½ªê\9b=dÁ~?øê\9b½;ê\7f=bÁ~?¯â±½l)>=bÁ~?¾\ 4Á½É3ê<aÁ~?¾\ 4Á½É3ê<aÁ~?qºÈ½+)\1e<dÁ~?{»È½))\1e¼aÁ~?¶\ 3Á½Ü3ê¼dÁ~?¶\ 3Á½Ü3ê¼dÁ~?¬â±½{)>½bÁ~?¾ê\9b½Kê\7f½dÁ~?µè\7f½¬ê\9b½dÁ~?µè\7f½¬ê\9b½dÁ~?\84+>½Vâ±½bÁ~?f1ê¼ü\ 3Á½dÁ~?´&\1e¼½ºÈ½dÁ~?´&\1e¼½ºÈ½dÁ~?='\1e<ÀºÈ½dÁ~?ò1ê<ú\ 3Á½dÁ~?\8a+>=Vâ±½bÁ~?\8a+>=Vâ±½bÁ~?½è\7f=®ê\9b½dÁ~?Ãê\9b=Kê\7f½bÁ~?½â±=t)>½bÁ~?½â±=t)>½bÁ~?Ç\ 3Á=á3ê¼dÁ~?\8c»È=7)\1e¼aÁ~?\82ºÈ=8)\1e<dÁ~?\82ºÈ=8)\1e<dÁ~?Ó\ 4Á=á3ê<aÁ~?>â±=\83)>=dÁ~?Äê\9b=Mê\7f=bÁ~?Äê\9b=Mê\7f=bÁ~?Áè\7f=³ê\9b=dÁ~?ÎÅǽe\8d}?FÈÇ=ÎÅǽe\8d}?FÈÇ=ÎÅǽe\8d}?FÈÇ=ÎÅǽe\8d}?FÈÇ=\ f\eê¼³\90\94>kàt¿\ f\eê¼³\90\94>kàt¿\ f\eê¼³\90\94>kàt¿\ f\eê¼³\90\94>kàt¿e*À½cås?'ø\93>e*À½cås?'ø\93>e*À½cås?'ø\93>e*À½cås?'ø\93>Æê\93¾îÎs?FÈÇ=Æê\93¾îÎs?FÈÇ=Æê\93¾îÎs?FÈÇ=Æê\93¾îÎs?FÈÇ=òV­½\13Û\8e>màt¿òV­½\13Û\8e>màt¿òV­½\13Û\8e>màt¿òV­½\13Û\8e>màt¿£H\8e¾è\85j?Dø\93>£H\8e¾è\85j?Dø\93>£H\8e¾è\85j?Dø\93>£H\8e¾è\85j?Dø\93>\¦\f¾\8eÔç>f\87a¿\¦\f¾\8eÔç>f\87a¿\¦\f¾\8eÔç>f\87a¿\¦\f¾\8eÔç>f\87a¿m7\83¾ûGX?\1csð>m7\83¾ûGX?\1csð>m7\83¾ûGX?\1csð>m7\83¾ûGX?\1csð>E\1e\12Ü\e?g\81E¿E\1e\12Ü\e?g\81E¿E\1e\12Ü\e?g\81E¿E\1e\12Ü\e?g\81E¿o9f¾\99¼=? ï!?o9f¾\99¼=? ï!?o9f¾\99¼=? ï!?o9f¾\99¼=? ï!?s9f¾\9a¼=?\9eï!¿s9f¾\9a¼=?\9eï!¿s9f¾\9a¼=?\9eï!¿s9f¾\9a¼=?\9eï!¿=\1e\10Ü\e?j\81E?=\1e\10Ü\e?j\81E?=\1e\10Ü\e?j\81E?=\1e\10Ü\e?j\81E?j7\83¾øGX?(sð¾j7\83¾øGX?(sð¾j7\83¾øGX?(sð¾j7\83¾øGX?(sð¾[¦\f¾\90Ôç>d\87a?[¦\f¾\90Ôç>d\87a?[¦\f¾\90Ôç>d\87a?[¦\f¾\90Ôç>d\87a?\9fH\8e¾è\85j?Iø\93¾\9fH\8e¾è\85j?Iø\93¾\9fH\8e¾è\85j?Iø\93¾\9fH\8e¾è\85j?Iø\93¾«W­½\ 6Û\8e>kàt?«W­½\ 6Û\8e>kàt?«W­½\ 6Û\8e>kàt?«W­½\ 6Û\8e>kàt?Àê\93¾îÎs?FÈǽÀê\93¾îÎs?FÈǽÀê\93¾îÎs?FÈǽÀê\93¾îÎs?FÈǽ.\8e\99¾\1f¤\ f?i\81E?.\8e\99¾\1f¤\ f?i\81E?.\8e\99¾\1f¤\ f?i\81E?.\8e\99¾\1f¤\ f?i\81E?t\15Õ¾nSG?\1fsð¾t\15Õ¾nSG?\1fsð¾t\15Õ¾nSG?\1fsð¾t\15Õ¾nSG?\1fsð¾xgd¾í§Õ>b\87a?xgd¾í§Õ>b\87a?xgd¾í§Õ>b\87a?xgd¾í§Õ>b\87a?Z\ eç¾<#X?\ø\93¾Z\ eç¾<#X?\ø\93¾Z\ eç¾<#X?\ø\93¾Z\ eç¾<#X?\ø\93¾r¾\f¾\ e¨\83>màt?r¾\f¾\ e¨\83>màt?r¾\f¾\ e¨\83>màt?r¾\f¾\ e¨\83>màt?@4ð¾ï±`?öÇǽ@4ð¾ï±`?öÇǽ@4ð¾ï±`?öÇǽ@4ð¾ï±`?öÇǽ@4ð¾ï±`?öÇÇ=@4ð¾ï±`?öÇÇ=@4ð¾ï±`?öÇÇ=@4ð¾ï±`?öÇÇ=l¾\f¾\17¨\83>màt¿l¾\f¾\17¨\83>màt¿l¾\f¾\17¨\83>màt¿l¾\f¾\17¨\83>màt¿\\ eç¾=#X?Pø\93>\\ eç¾=#X?Pø\93>\\ eç¾=#X?Pø\93>\\ eç¾=#X?Pø\93>Igd¾ë§Õ>d\87a¿Igd¾ë§Õ>d\87a¿Igd¾ë§Õ>d\87a¿Igd¾ë§Õ>d\87a¿~\15Õ¾qSG?\10sð>~\15Õ¾qSG?\10sð>~\15Õ¾qSG?\10sð>~\15Õ¾qSG?\10sð>1\8e\99¾\1e¤\ f?g\81E¿1\8e\99¾\1e¤\ f?g\81E¿1\8e\99¾\1e¤\ f?g\81E¿1\8e\99¾\1e¤\ f?g\81E¿\83ÇÜ.?\9fï!?\83ÇÜ.?\9fï!?\83ÇÜ.?\9fï!?\83ÇÜ.?\9fï!?\81ÆÜ.?¢ï!¿\81ÆÜ.?¢ï!¿\81ÆÜ.?¢ï!¿\81ÆÜ.?¢ï!¿{y\e¿Cr=?Eø\93>{y\e¿Cr=?Eø\93>{y\e¿Cr=?Eø\93>{y\e¿Cr=?Eø\93>z°\99¾gE»>f\87a¿z°\99¾gE»>f\87a¿z°\99¾gE»>f\87a¿z°\99¾gE»>f\87a¿\9ea\ f¿éµ.?!sð>\9ea\ f¿éµ.?!sð>\9ea\ f¿éµ.?!sð>\9ea\ f¿éµ.?!sð>¦¦Î¾\ fÎû>f\81E¿¦¦Î¾\ fÎû>f\81E¿¦¦Î¾\ fÎû>f\81E¿¦¦Î¾\ fÎû>f\81E¿b\91û¾©D\19?\9aï!?b\91û¾©D\19?\9aï!?b\91û¾©D\19?\9aï!?b\91û¾©D\19?\9aï!?b\91û¾¨D\19?\9dï!¿b\91û¾¨D\19?\9dï!¿b\91û¾¨D\19?\9dï!¿b\91û¾¨D\19?\9dï!¿§¦Î¾\aÎû>j\81E?§¦Î¾\aÎû>j\81E?§¦Î¾\aÎû>j\81E?§¦Î¾\aÎû>j\81E?\9da\ f¿éµ.?\1dsð¾\9da\ f¿éµ.?\1dsð¾\9da\ f¿éµ.?\1dsð¾\9da\ f¿éµ.?\1dsð¾g°\99¾iE»>i\87a?g°\99¾iE»>i\87a?g°\99¾iE»>i\87a?g°\99¾iE»>i\87a?zy\e¿?r=?Oø\93¾zy\e¿?r=?Oø\93¾zy\e¿?r=?Oø\93¾zy\e¿?r=?Oø\93¾\14i=¾¨Ëf>kàt?\14i=¾¨Ëf>kàt?\14i=¾¨Ëf>kàt?\14i=¾¨Ëf>kàt?O¡!¿eòD?dÈǽO¡!¿eòD?dÈǽO¡!¿eòD?dÈǽO¡!¿eòD?dÈǽN¡!¿fòD?eÈÇ=N¡!¿fòD?eÈÇ=N¡!¿fòD?eÈÇ=N¡!¿fòD?eÈÇ=\ fi=¾ÅËf>jàt¿\ fi=¾ÅËf>jàt¿\ fi=¾ÅËf>jàt¿\ fi=¾ÅËf>jàt¿]E»¾}°\99>f\87a?]E»¾}°\99>f\87a?]E»¾}°\99>f\87a?]E»¾}°\99>f\87a?Cr=¿{y\e?Bø\93¾Cr=¿{y\e?Bø\93¾Cr=¿{y\e?Bø\93¾Cr=¿{y\e?Bø\93¾vËf¾Ãh=>sàt?vËf¾Ãh=>sàt?vËf¾Ãh=>sàt?vËf¾Ãh=>sàt?hòD¿K¡!?uÈǽhòD¿K¡!?uÈǽhòD¿K¡!?uÈǽhòD¿K¡!?uÈǽhòD¿J¡!?sÈÇ=hòD¿J¡!?sÈÇ=hòD¿J¡!?sÈÇ=hòD¿J¡!?sÈÇ=\9cËf¾Ïh=>oàt¿\9cËf¾Ïh=>oàt¿\9cËf¾Ïh=>oàt¿\9cËf¾Ïh=>oàt¿Br=¿{y\e?Bø\93>Br=¿{y\e?Bø\93>Br=¿{y\e?Bø\93>Br=¿{y\e?Bø\93>kE»¾}°\99>b\87a¿kE»¾}°\99>b\87a¿kE»¾}°\99>b\87a¿kE»¾}°\99>b\87a¿êµ.¿\9da\ f?\esð>êµ.¿\9da\ f?\esð>êµ.¿\9da\ f?\esð>êµ.¿\9da\ f?\esð>\14Îû¾\9d¦Î>g\81E¿\14Îû¾\9d¦Î>g\81E¿\14Îû¾\9d¦Î>g\81E¿\14Îû¾\9d¦Î>g\81E¿¦D\19¿]\91û>\9eï!?¦D\19¿]\91û>\9eï!?¦D\19¿]\91û>\9eï!?¦D\19¿]\91û>\9eï!?¦D\19¿]\91û>\9eï!¿¦D\19¿]\91û>\9eï!¿¦D\19¿]\91û>\9eï!¿¦D\19¿]\91û>\9eï!¿\17Îû¾\98¦Î>i\81E?\17Îû¾\98¦Î>i\81E?\17Îû¾\98¦Î>i\81E?\17Îû¾\98¦Î>i\81E?êµ.¿\97a\ f?*sð¾êµ.¿\97a\ f?*sð¾êµ.¿\97a\ f?*sð¾êµ.¿\97a\ f?*sð¾ô§Õ¾0gd>d\87a¿ô§Õ¾0gd>d\87a¿ô§Õ¾0gd>d\87a¿ô§Õ¾0gd>d\87a¿qSG¿m\15Õ>\1asð>qSG¿m\15Õ>\1asð>qSG¿m\15Õ>\1asð>qSG¿m\15Õ>\1asð>\e¤\ f¿1\8e\99>k\81E¿\e¤\ f¿1\8e\99>k\81E¿\e¤\ f¿1\8e\99>k\81E¿\e¤\ f¿1\8e\99>k\81E¿ÊÜ.¿\81îº>\9bï!?ÊÜ.¿\81îº>\9bï!?ÊÜ.¿\81îº>\9bï!?ÊÜ.¿\81îº>\9bï!?ÊÜ.¿\84îº>\9dï!¿ÊÜ.¿\84îº>\9dï!¿ÊÜ.¿\84îº>\9dï!¿ÊÜ.¿\84îº>\9dï!¿\1a¤\ f¿8\8e\99>k\81E?\1a¤\ f¿8\8e\99>k\81E?\1a¤\ f¿8\8e\99>k\81E?\1a¤\ f¿8\8e\99>k\81E?nSG¿t\15Õ>\1fsð¾nSG¿t\15Õ>\1fsð¾nSG¿t\15Õ>\1fsð¾nSG¿t\15Õ>\1fsð¾÷§Õ¾+gd>b\87a?÷§Õ¾+gd>b\87a?÷§Õ¾+gd>b\87a?÷§Õ¾+gd>b\87a?F#X¿F\ eç>Cø\93¾F#X¿F\ eç>Cø\93¾F#X¿F\ eç>Cø\93¾F#X¿F\ eç>Cø\93¾\15¨\83¾a¾\f>màt?\15¨\83¾a¾\f>màt?\15¨\83¾a¾\f>màt?\15¨\83¾a¾\f>màt?ò±`¿04ð>~Èǽò±`¿04ð>~Èǽò±`¿04ð>~Èǽò±`¿04ð>~Èǽò±`¿.4ð>~ÈÇ=ò±`¿.4ð>~ÈÇ=ò±`¿.4ð>~ÈÇ=ò±`¿.4ð>~ÈÇ=\12¨\83¾i¾\f>màt¿\12¨\83¾i¾\f>màt¿\12¨\83¾i¾\f>màt¿\12¨\83¾i¾\f>màt¿G#X¿G\ eç>=ø\93>G#X¿G\ eç>=ø\93>G#X¿G\ eç>=ø\93>G#X¿G\ eç>=ø\93\85j¿\9fH\8e>Aø\93¾é\85j¿\9fH\8e>Aø\93¾é\85j¿\9fH\8e>Aø\93¾é\85j¿\9fH\8e>Aø\93¾ÿÚ\8e¾ÉV­=qàt?ÿÚ\8e¾ÉV­=qàt?ÿÚ\8e¾ÉV­=qàt?ÿÚ\8e¾ÉV­=qàt?îÎs¿¼ê\93>\90ÈǽîÎs¿¼ê\93>\90ÈǽîÎs¿¼ê\93>\90ÈǽîÎs¿¼ê\93>\90ÈǽîÎs¿¼ê\93>\90ÈÇ=îÎs¿¼ê\93>\90ÈÇ=îÎs¿¼ê\93>\90ÈÇ=îÎs¿¼ê\93>\90ÈÇ=\1eÛ\8e¾ÅV­=kàt¿\1eÛ\8e¾ÅV­=kàt¿\1eÛ\8e¾ÅV­=kàt¿\1eÛ\8e¾ÅV­=kàt¿é\85j¿\9fH\8e>@ø\93\85j¿\9fH\8e>@ø\93\85j¿\9fH\8e>@ø\93\85j¿\9fH\8e>@ø\93>\92Ôç¾N¦\f>f\87a¿\92Ôç¾N¦\f>f\87a¿\92Ôç¾N¦\f>f\87a¿\92Ôç¾N¦\f>f\87a¿ÿGX¿b7\83>\13sð>ÿGX¿b7\83>\13sð>ÿGX¿b7\83>\13sð>ÿGX¿b7\83>\13sð>\10Ü\e¿1\1e=>i\81E¿\10Ü\e¿1\1e=>i\81E¿\10Ü\e¿1\1e=>i\81E¿\10Ü\e¿1\1e=>i\81E¿\9d¼=¿H9f>\9fï!?\9d¼=¿H9f>\9fï!?\9d¼=¿H9f>\9fï!?\9d¼=¿H9f>\9fï!?\9d¼=¿H9f>\9fï!¿\9d¼=¿H9f>\9fï!¿\9d¼=¿H9f>\9fï!¿\9d¼=¿H9f>\9fï!¿\11Ü\e¿>\1e=>g\81E?\11Ü\e¿>\1e=>g\81E?\11Ü\e¿>\1e=>g\81E?\11Ü\e¿>\1e=>g\81E?ÿGX¿[7\83>\19sð¾ÿGX¿[7\83>\19sð¾ÿGX¿[7\83>\19sð¾ÿGX¿[7\83>\19sð¾\8bÔç¾Z¦\f>f\87a?\8bÔç¾Z¦\f>f\87a?\8bÔç¾Z¦\f>f\87a?\8bÔç¾Z¦\f>f\87a?Ìì`¿\9b9±=\18sð>Ìì`¿\9b9±=\18sð>Ìì`¿\9b9±=\18sð>Ìì`¿\9b9±=\18sð>²\16"¿ðm\7f=f\81E¿²\16"¿ðm\7f=f\81E¿²\16"¿ðm\7f=f\81E¿²\16"¿ðm\7f=f\81E¿ÒQE¿yy\9b=\9fï!?ÒQE¿yy\9b=\9fï!?ÒQE¿yy\9b=\9fï!?ÒQE¿yy\9b=\9fï!?ÒQE¿yy\9b=\9fï!¿ÒQE¿yy\9b=\9fï!¿ÒQE¿yy\9b=\9fï!¿ÒQE¿yy\9b=\9fï!¿²\16"¿\95m\7f=f\81E?²\16"¿\95m\7f=f\81E?²\16"¿\95m\7f=f\81E?²\16"¿\95m\7f=f\81E?Çì`¿¢9±=#sð¾Çì`¿¢9±=#sð¾Çì`¿¢9±=#sð¾Çì`¿¢9±=#sð¾\7f\18ñ¾\r÷==a\87a?\7f\18ñ¾\r÷==a\87a?\7f\18ñ¾\r÷==a\87a?\7f\18ñ¾\r÷==a\87a?Zås¿:,À==ø\93¾Zås¿:,À==ø\93¾Zås¿:,À==ø\93¾Zås¿:,À==ø\93¾\9b\90\94¾Æ\1dê<oàt?\9b\90\94¾Æ\1dê<oàt?\9b\90\94¾Æ\1dê<oàt?\9b\90\94¾Æ\1dê<oàt?]\8d}¿óÇÇ=´Èǽ]\8d}¿óÇÇ=´Èǽ]\8d}¿óÇÇ=´Èǽ]\8d}¿óÇÇ=´Èǽ]\8d}¿óÇÇ=´ÈÇ=]\8d}¿óÇÇ=´ÈÇ=]\8d}¿óÇÇ=´ÈÇ=]\8d}¿óÇÇ=´ÈÇ=®\90\94¾\19\1eê<kàt¿®\90\94¾\19\1eê<kàt¿®\90\94¾\19\1eê<kàt¿®\90\94¾\19\1eê<kàt¿Zås¿:,À=<ø\93>Zås¿:,À=<ø\93>Zås¿:,À=<ø\93>Zås¿:,À=<ø\93>q\18ñ¾\7f÷==d\87a¿q\18ñ¾\7f÷==d\87a¿q\18ñ¾\7f÷==d\87a¿q\18ñ¾\7f÷==d\87a¿\9b\90\94¾#\1eê¼oàt?\9b\90\94¾#\1eê¼oàt?\9b\90\94¾#\1eê¼oàt?\9b\90\94¾#\1eê¼oàt?[\8d}¿(ÈǽÛÈǽ[\8d}¿(ÈǽÛÈǽ[\8d}¿(ÈǽÛÈǽ[\8d}¿(ÈǽÛÈǽ[\8d}¿(ÈǽÛÈÇ=[\8d}¿(ÈǽÛÈÇ=[\8d}¿(ÈǽÛÈÇ=[\8d}¿(ÈǽÛÈÇ=®\90\94¾\1d\1eê¼kàt¿®\90\94¾\1d\1eê¼kàt¿®\90\94¾\1d\1eê¼kàt¿®\90\94¾\1d\1eê¼kàt¿Zås¿q,À½7ø\93>Zås¿q,À½7ø\93>Zås¿q,À½7ø\93>Zås¿q,À½7ø\93>n\18ñ¾¸÷=½f\87a¿n\18ñ¾¸÷=½f\87a¿n\18ñ¾¸÷=½f\87a¿n\18ñ¾¸÷=½f\87a¿Êì`¿Õ9±½\14sð>Êì`¿Õ9±½\14sð>Êì`¿Õ9±½\14sð>Êì`¿Õ9±½\14sð>­\16"¿ým\7f½k\81E¿­\16"¿ým\7f½k\81E¿­\16"¿ým\7f½k\81E¿­\16"¿ým\7f½k\81E¿ÕQE¿wy\9b½\9dï!?ÕQE¿wy\9b½\9dï!?ÕQE¿wy\9b½\9dï!?ÕQE¿wy\9b½\9dï!?ÕQE¿wy\9b½\9dï!¿ÕQE¿wy\9b½\9dï!¿ÕQE¿wy\9b½\9dï!¿ÕQE¿wy\9b½\9dï!¿¬\16"¿Bn\7f½k\81E?¬\16"¿Bn\7f½k\81E?¬\16"¿Bn\7f½k\81E?¬\16"¿Bn\7f½k\81E?Çì`¿¢9±½#sð¾Çì`¿¢9±½#sð¾Çì`¿¢9±½#sð¾Çì`¿¢9±½#sð¾s\18ñ¾H÷=½d\87a?s\18ñ¾H÷=½d\87a?s\18ñ¾H÷=½d\87a?s\18ñ¾H÷=½d\87a?Zås¿p,À½6ø\93¾Zås¿p,À½6ø\93¾Zås¿p,À½6ø\93¾Zås¿p,À½6ø\93¾\13Ü\e¿4\1e=¾i\81E¿\13Ü\e¿4\1e=¾i\81E¿\13Ü\e¿4\1e=¾i\81E¿\13Ü\e¿4\1e=¾i\81E¿\9e¼=¿h9f¾\9aï!?\9e¼=¿h9f¾\9aï!?\9e¼=¿h9f¾\9aï!?\9e¼=¿h9f¾\9aï!?\9e¼=¿h9f¾\9aï!¿\9e¼=¿h9f¾\9aï!¿\9e¼=¿h9f¾\9aï!¿\9e¼=¿h9f¾\9aï!¿\ eÜ\e¿B\1e=¾j\81E?\ eÜ\e¿B\1e=¾j\81E?\ eÜ\e¿B\1e=¾j\81E?\ eÜ\e¿B\1e=¾j\81E?øGX¿i7\83¾(sð¾øGX¿i7\83¾(sð¾øGX¿i7\83¾(sð¾øGX¿i7\83¾(sð¾\91Ôç¾g¦\f¾b\87a?\91Ôç¾g¦\f¾b\87a?\91Ôç¾g¦\f¾b\87a?\91Ôç¾g¦\f¾b\87a?ë\85j¿\9fH\8e¾3ø\93¾ë\85j¿\9fH\8e¾3ø\93¾ë\85j¿\9fH\8e¾3ø\93¾ë\85j¿\9fH\8e¾3ø\93¾\17Û\8e¾àV­½kàt?\17Û\8e¾àV­½kàt?\17Û\8e¾àV­½kàt?\17Û\8e¾àV­½kàt?ìÎs¿»ê\93¾àÈǽìÎs¿»ê\93¾àÈǽìÎs¿»ê\93¾àÈǽìÎs¿»ê\93¾àÈǽìÎs¿»ê\93¾àÈÇ=ìÎs¿»ê\93¾àÈÇ=ìÎs¿»ê\93¾àÈÇ=ìÎs¿»ê\93¾àÈÇ=\ 1Û\8e¾ùV­½oàt¿\ 1Û\8e¾ùV­½oàt¿\ 1Û\8e¾ùV­½oàt¿\ 1Û\8e¾ùV­½oàt¿é\85j¿¡H\8e¾6ø\93\85j¿¡H\8e¾6ø\93\85j¿¡H\8e¾6ø\93\85j¿¡H\8e¾6ø\93>\8eÔç¾\¦\f¾f\87a¿\8eÔç¾\¦\f¾f\87a¿\8eÔç¾\¦\f¾f\87a¿\8eÔç¾\¦\f¾f\87a¿þGX¿c7\83¾\1csð>þGX¿c7\83¾\1csð>þGX¿c7\83¾\1csð>þGX¿c7\83¾\1csð>ì±`¿?4ð¾ÛÈǽì±`¿?4ð¾ÛÈǽì±`¿?4ð¾ÛÈǽì±`¿?4ð¾ÛÈǽì±`¿=4ð¾ÙÈÇ=ì±`¿=4ð¾ÙÈÇ=ì±`¿=4ð¾ÙÈÇ=ì±`¿=4ð¾ÙÈÇ=,¨\83¾n¾\f¾jàt¿,¨\83¾n¾\f¾jàt¿,¨\83¾n¾\f¾jàt¿,¨\83¾n¾\f¾jàt¿B#X¿c\ eç¾4ø\93>B#X¿c\ eç¾4ø\93>B#X¿c\ eç¾4ø\93>B#X¿c\ eç¾4ø\93>ó§Õ¾5gd¾d\87a¿ó§Õ¾5gd¾d\87a¿ó§Õ¾5gd¾d\87a¿ó§Õ¾5gd¾d\87a¿mSG¿x\15Õ¾\1dsð>mSG¿x\15Õ¾\1dsð>mSG¿x\15Õ¾\1dsð>mSG¿x\15Õ¾\1dsð> ¤\ f¿?\8e\99¾e\81E¿ ¤\ f¿?\8e\99¾e\81E¿ ¤\ f¿?\8e\99¾e\81E¿ ¤\ f¿?\8e\99¾e\81E¿ÈÜ.¿\93\98ï!?ÈÜ.¿\93\98ï!?ÈÜ.¿\93\98ï!?ÈÜ.¿\93\98ï!?ÈÜ.¿\93\9aï!¿ÈÜ.¿\93\9aï!¿ÈÜ.¿\93\9aï!¿ÈÜ.¿\93\9aï!¿\1a¤\ f¿1\8e\99¾k\81E?\1a¤\ f¿1\8e\99¾k\81E?\1a¤\ f¿1\8e\99¾k\81E?\1a¤\ f¿1\8e\99¾k\81E?kSG¿t\15Õ¾+sð¾kSG¿t\15Õ¾+sð¾kSG¿t\15Õ¾+sð¾kSG¿t\15Õ¾+sð¾ð§Õ¾0gd¾d\87a?ð§Õ¾0gd¾d\87a?ð§Õ¾0gd¾d\87a?ð§Õ¾0gd¾d\87a?B#X¿c\ eç¾2ø\93¾B#X¿c\ eç¾2ø\93¾B#X¿c\ eç¾2ø\93¾B#X¿c\ eç¾2ø\93¾\ 2¨\83¾e¾\f¾qàt?\ 2¨\83¾e¾\f¾qàt?\ 2¨\83¾e¾\f¾qàt?\ 2¨\83¾e¾\f¾qàt?§D\19¿k\91û¾\9aï!?§D\19¿k\91û¾\9aï!?§D\19¿k\91û¾\9aï!?§D\19¿k\91û¾\9aï!?¤D\19¿l\91û¾\9cï!¿¤D\19¿l\91û¾\9cï!¿¤D\19¿l\91û¾\9cï!¿¤D\19¿l\91û¾\9cï!¿\ 6Îû¾¨¦Î¾k\81E?\ 6Îû¾¨¦Î¾k\81E?\ 6Îû¾¨¦Î¾k\81E?\ 6Îû¾¨¦Î¾k\81E?çµ.¿\9ba\ f¿-sð¾çµ.¿\9ba\ f¿-sð¾çµ.¿\9ba\ f¿-sð¾çµ.¿\9ba\ f¿-sð¾kE»¾\84°\99¾b\87a?kE»¾\84°\99¾b\87a?kE»¾\84°\99¾b\87a?kE»¾\84°\99¾b\87a?Hr=¿vy\e¿8ø\93¾Hr=¿vy\e¿8ø\93¾Hr=¿vy\e¿8ø\93¾Hr=¿vy\e¿8ø\93¾\0Ìf¾¾h=¾jàt?\0Ìf¾¾h=¾jàt?\0Ìf¾¾h=¾jàt?\0Ìf¾¾h=¾jàt?bòD¿P¡!¿ËÈǽbòD¿P¡!¿ËÈǽbòD¿P¡!¿ËÈǽbòD¿P¡!¿ËÈǽbòD¿P¡!¿ËÈÇ=bòD¿P¡!¿ËÈÇ=bòD¿P¡!¿ËÈÇ=bòD¿P¡!¿ËÈÇ=ËËf¾Ðh=¾kàt¿ËËf¾Ðh=¾kàt¿ËËf¾Ðh=¾kàt¿ËËf¾Ðh=¾kàt¿Hr=¿wy\e¿5ø\93>Hr=¿wy\e¿5ø\93>Hr=¿wy\e¿5ø\93>Hr=¿wy\e¿5ø\93>^E»¾{°\99¾g\87a¿^E»¾{°\99¾g\87a¿^E»¾{°\99¾g\87a¿^E»¾{°\99¾g\87a¿ëµ.¿\9ba\ f¿"sð>ëµ.¿\9ba\ f¿"sð>ëµ.¿\9ba\ f¿"sð>ëµ.¿\9ba\ f¿"sð>\13Îû¾¦¦Î¾f\81E¿\13Îû¾¦¦Î¾f\81E¿\13Îû¾¦¦Î¾f\81E¿\13Îû¾¦¦Î¾f\81E¿O¡!¿dòD¿¶ÈÇ=O¡!¿dòD¿¶ÈÇ=O¡!¿dòD¿¶ÈÇ=O¡!¿dòD¿¶ÈÇ=¿h=¾ÒËf¾màt¿¿h=¾ÒËf¾màt¿¿h=¾ÒËf¾màt¿¿h=¾ÒËf¾màt¿zy\e¿Fr=¿8ø\93>zy\e¿Fr=¿8ø\93>zy\e¿Fr=¿8ø\93>zy\e¿Fr=¿8ø\93>z°\99¾lE»¾d\87a¿z°\99¾lE»¾d\87a¿z°\99¾lE»¾d\87a¿z°\99¾lE»¾d\87a¿\9ba\ f¿çµ.¿,sð>\9ba\ f¿çµ.¿,sð>\9ba\ f¿çµ.¿,sð>\9ba\ f¿çµ.¿,sð>¯¦Î¾\fÎû¾e\81E¿¯¦Î¾\fÎû¾e\81E¿¯¦Î¾\fÎû¾e\81E¿¯¦Î¾\fÎû¾e\81E¿\\91û¾ªD\19¿\9cï!?\\91û¾ªD\19¿\9cï!?\\91û¾ªD\19¿\9cï!?\\91û¾ªD\19¿\9cï!?]\91û¾ªD\19¿\9aï!¿]\91û¾ªD\19¿\9aï!¿]\91û¾ªD\19¿\9aï!¿]\91û¾ªD\19¿\9aï!¿\9f¦Î¾\fÎû¾j\81E?\9f¦Î¾\fÎû¾j\81E?\9f¦Î¾\fÎû¾j\81E?\9f¦Î¾\fÎû¾j\81E?\98a\ f¿çµ.¿3sð¾\98a\ f¿çµ.¿3sð¾\98a\ f¿çµ.¿3sð¾\98a\ f¿çµ.¿3sð¾b°\99¾rE»¾g\87a?b°\99¾rE»¾g\87a?b°\99¾rE»¾g\87a?b°\99¾rE»¾g\87a?zy\e¿Fr=¿8ø\93¾zy\e¿Fr=¿8ø\93¾zy\e¿Fr=¿8ø\93¾zy\e¿Fr=¿8ø\93¾Äh=¾»Ëf¾màt?Äh=¾»Ëf¾màt?Äh=¾»Ëf¾màt?Äh=¾»Ëf¾màt?O¡!¿dòD¿¶ÈǽO¡!¿dòD¿¶ÈǽO¡!¿dòD¿¶ÈǽO¡!¿dòD¿¶Èǽ/\8e\99¾\1f¤\ f¿g\81E?/\8e\99¾\1f¤\ f¿g\81E?/\8e\99¾\1f¤\ f¿g\81E?/\8e\99¾\1f¤\ f¿g\81E?b\15Õ¾mSG¿3sð¾b\15Õ¾mSG¿3sð¾b\15Õ¾mSG¿3sð¾b\15Õ¾mSG¿3sð¾\19gd¾ù§Õ¾d\87a?\19gd¾ù§Õ¾d\87a?\19gd¾ù§Õ¾d\87a?\19gd¾ù§Õ¾d\87a?S\ eç¾D#X¿7ø\93¾S\ eç¾D#X¿7ø\93¾S\ eç¾D#X¿7ø\93¾S\ eç¾D#X¿7ø\93¾y¾\f¾\ f¨\83¾màt?y¾\f¾\ f¨\83¾màt?y¾\f¾\ f¨\83¾màt?y¾\f¾\ f¨\83¾màt?/4ð¾ñ±`¿ËÈǽ/4ð¾ñ±`¿ËÈǽ/4ð¾ñ±`¿ËÈǽ/4ð¾ñ±`¿ËÈǽ14ð¾ñ±`¿ËÈÇ=14ð¾ñ±`¿ËÈÇ=14ð¾ñ±`¿ËÈÇ=14ð¾ñ±`¿ËÈÇ=y¾\f¾\1e¨\83¾kàt¿y¾\f¾\1e¨\83¾kàt¿y¾\f¾\1e¨\83¾kàt¿y¾\f¾\1e¨\83¾kàt¿Q\ eç¾D#X¿>ø\93>Q\ eç¾D#X¿>ø\93>Q\ eç¾D#X¿>ø\93>Q\ eç¾D#X¿>ø\93>Ngd¾î§Õ¾b\87a¿Ngd¾î§Õ¾b\87a¿Ngd¾î§Õ¾b\87a¿Ngd¾î§Õ¾b\87a¿f\15Õ¾nSG¿+sð>f\15Õ¾nSG¿+sð>f\15Õ¾nSG¿+sð>f\15Õ¾nSG¿+sð>5\8e\99¾\1f¤\ f¿g\81E¿5\8e\99¾\1f¤\ f¿g\81E¿5\8e\99¾\1f¤\ f¿g\81E¿5\8e\99¾\1f¤\ f¿g\81E¿\82ÌÜ.¿\99ï!?\82ÌÜ.¿\99ï!?\82ÌÜ.¿\99ï!?\82ÌÜ.¿\99ï!?{ËÜ.¿\9aï!¿{ËÜ.¿\9aï!¿{ËÜ.¿\9aï!¿{ËÜ.¿\9aï!¿­W­½\13Û\8e¾jàt¿­W­½\13Û\8e¾jàt¿­W­½\13Û\8e¾jàt¿­W­½\13Û\8e¾jàt¿\98H\8e¾í\85j¿2ø\93>\98H\8e¾í\85j¿2ø\93>\98H\8e¾í\85j¿2ø\93>\98H\8e¾í\85j¿2ø\93>^¦\f¾\8bÔç¾f\87a¿^¦\f¾\8bÔç¾f\87a¿^¦\f¾\8bÔç¾f\87a¿^¦\f¾\8bÔç¾f\87a¿V7\83¾ùGX¿0sð>V7\83¾ùGX¿0sð>V7\83¾ùGX¿0sð>V7\83¾ùGX¿0sð>:\1e\18Ü\e¿c\81E¿:\1e\18Ü\e¿c\81E¿:\1e\18Ü\e¿c\81E¿:\1e\18Ü\e¿c\81E¿_9f¾ ¼=¿\97ï!?_9f¾ ¼=¿\97ï!?_9f¾ ¼=¿\97ï!?_9f¾ ¼=¿\97ï!?_9f¾ ¼=¿\97ï!¿_9f¾ ¼=¿\97ï!¿_9f¾ ¼=¿\97ï!¿_9f¾ ¼=¿\97ï!¿0\1e\11Ü\e¿i\81E?0\1e\11Ü\e¿i\81E?0\1e\11Ü\e¿i\81E?0\1e\11Ü\e¿i\81E?U7\83¾øGX¿3sð¾U7\83¾øGX¿3sð¾U7\83¾øGX¿3sð¾U7\83¾øGX¿3sð¾_¦\f¾\93Ôç¾d\87a?_¦\f¾\93Ôç¾d\87a?_¦\f¾\93Ôç¾d\87a?_¦\f¾\93Ôç¾d\87a?\99H\8e¾í\85j¿2ø\93¾\99H\8e¾í\85j¿2ø\93¾\99H\8e¾í\85j¿2ø\93¾\99H\8e¾í\85j¿2ø\93¾\ 2W­½\rÛ\8e¾màt?\ 2W­½\rÛ\8e¾màt?\ 2W­½\rÛ\8e¾màt?\ 2W­½\rÛ\8e¾màt?·ê\93¾ìÎs¿&Éǽ·ê\93¾ìÎs¿&Éǽ·ê\93¾ìÎs¿&Éǽ·ê\93¾ìÎs¿&Éǽ·ê\93¾ìÎs¿&ÉÇ=·ê\93¾ìÎs¿&ÉÇ=·ê\93¾ìÎs¿&ÉÇ=·ê\93¾ìÎs¿&ÉÇ=£9±½Äì`¿-sð¾£9±½Äì`¿-sð¾£9±½Äì`¿-sð¾£9±½Äì`¿-sð¾ó÷=½r\18ñ¾b\87a?ó÷=½r\18ñ¾b\87a?ó÷=½r\18ñ¾b\87a?ó÷=½r\18ñ¾b\87a??,À½Xås¿Bø\93¾?,À½Xås¿Bø\93¾?,À½Xås¿Bø\93¾?,À½Xås¿Bø\93¾þ\1aê¼\9f\90\94¾oàt?þ\1aê¼\9f\90\94¾oàt?þ\1aê¼\9f\90\94¾oàt?þ\1aê¼\9f\90\94¾oàt?ãÇǽ]\8d}¿ÇÈǽãÇǽ]\8d}¿ÇÈǽãÇǽ]\8d}¿ÇÈǽãÇǽ]\8d}¿ÇÈǽãÇǽ]\8d}¿ÇÈÇ=ãÇǽ]\8d}¿ÇÈÇ=ãÇǽ]\8d}¿ÇÈÇ=ãÇǽ]\8d}¿ÇÈÇ=ý\1aê¼®\90\94¾kàt¿ý\1aê¼®\90\94¾kàt¿ý\1aê¼®\90\94¾kàt¿ý\1aê¼®\90\94¾kàt¿G,À½Xås¿Bø\93>G,À½Xås¿Bø\93>G,À½Xås¿Bø\93>G,À½Xås¿Bø\93>\14÷=½k\18ñ¾g\87a¿\14÷=½k\18ñ¾g\87a¿\14÷=½k\18ñ¾g\87a¿\14÷=½k\18ñ¾g\87a¿«9±½Çì`¿#sð>«9±½Çì`¿#sð>«9±½Çì`¿#sð>«9±½Çì`¿#sð>úm\7f½±\16"¿i\81E¿úm\7f½±\16"¿i\81E¿úm\7f½±\16"¿i\81E¿úm\7f½±\16"¿i\81E¿<y\9b½ÛQE¿\95ï!?<y\9b½ÛQE¿\95ï!?<y\9b½ÛQE¿\95ï!?<y\9b½ÛQE¿\95ï!?<y\9b½ÛQE¿\95ï!¿<y\9b½ÛQE¿\95ï!¿<y\9b½ÛQE¿\95ï!¿<y\9b½ÛQE¿\95ï!¿\9am\7f½¬\16"¿l\81E?\9am\7f½¬\16"¿l\81E?\9am\7f½¬\16"¿l\81E?\9am\7f½¬\16"¿l\81E?l,À=Xås¿<ø\93>l,À=Xås¿<ø\93>l,À=Xås¿<ø\93>l,À=Xås¿<ø\93>\11÷==f\18ñ¾i\87a¿\11÷==f\18ñ¾i\87a¿\11÷==f\18ñ¾i\87a¿\11÷==f\18ñ¾i\87a¿Â9±=Âì`¿4sð>Â9±=Âì`¿4sð>Â9±=Âì`¿4sð>Â9±=Âì`¿4sð>\ 1n\7f\16"¿a\81E¿\ 1n\7f\16"¿a\81E¿\ 1n\7f\16"¿a\81E¿\ 1n\7f\16"¿a\81E¿\83y\9b=ÞQE¿\8fï!?\83y\9b=ÞQE¿\8fï!?\83y\9b=ÞQE¿\8fï!?\83y\9b=ÞQE¿\8fï!?\83y\9b=ÞQE¿\8fï!¿\83y\9b=ÞQE¿\8fï!¿\83y\9b=ÞQE¿\8fï!¿\83y\9b=ÞQE¿\8fï!¿An\7f\16"¿i\81E?An\7f\16"¿i\81E?An\7f\16"¿i\81E?An\7f\16"¿i\81E?¾9±=¿ì`¿Asð¾¾9±=¿ì`¿Asð¾¾9±=¿ì`¿Asð¾¾9±=¿ì`¿Asð¾\18÷==w\18ñ¾b\87a?\18÷==w\18ñ¾b\87a?\18÷==w\18ñ¾b\87a?\18÷==w\18ñ¾b\87a?l,À=Xås¿<ø\93¾l,À=Xås¿<ø\93¾l,À=Xås¿<ø\93¾l,À=Xås¿<ø\93¾Ó\1dê<\9d\90\94¾oàt?Ó\1dê<\9d\90\94¾oàt?Ó\1dê<\9d\90\94¾oàt?Ó\1dê<\9d\90\94¾oàt?6ÈÇ=[\8d}¿ÕÈǽ6ÈÇ=[\8d}¿ÕÈǽ6ÈÇ=[\8d}¿ÕÈǽ6ÈÇ=[\8d}¿ÕÈǽ4ÈÇ=[\8d}¿ÕÈÇ=4ÈÇ=[\8d}¿ÕÈÇ=4ÈÇ=[\8d}¿ÕÈÇ=4ÈÇ=[\8d}¿ÕÈÇ=Î\1dê<«\90\94¾kàt¿Î\1dê<«\90\94¾kàt¿Î\1dê<«\90\94¾kàt¿Î\1dê<«\90\94¾kàt¿^¦\f>\8eÔç¾d\87a?^¦\f>\8eÔç¾d\87a?^¦\f>\8eÔç¾d\87a?^¦\f>\8eÔç¾d\87a?\9fH\8e\85j¿#ø\93¾\9fH\8e\85j¿#ø\93¾\9fH\8e\85j¿#ø\93¾\9fH\8e\85j¿#ø\93¾\ 2W­=\vÛ\8e¾màt?\ 2W­=\vÛ\8e¾màt?\ 2W­=\vÛ\8e¾màt?\ 2W­=\vÛ\8e¾màt?Âê\93>ìÎs¿\fÉǽÂê\93>ìÎs¿\fÉǽÂê\93>ìÎs¿\fÉǽÂê\93>ìÎs¿\fÉǽÂê\93>ìÎs¿\fÉÇ=Âê\93>ìÎs¿\fÉÇ=Âê\93>ìÎs¿\fÉÇ=Âê\93>ìÎs¿\fÉÇ=\ 2W­=\18Û\8e¾kàt¿\ 2W­=\18Û\8e¾kàt¿\ 2W­=\18Û\8e¾kàt¿\ 2W­=\18Û\8e¾kàt¿\9fH\8e\85j¿#ø\93>\9fH\8e\85j¿#ø\93>\9fH\8e\85j¿#ø\93>\9fH\8e\85j¿#ø\93>\¦\f>\8aÔç¾g\87a¿\¦\f>\8aÔç¾g\87a¿\¦\f>\8aÔç¾g\87a¿\¦\f>\8aÔç¾g\87a¿h7\83>ôGX¿;sð>h7\83>ôGX¿;sð>h7\83>ôGX¿;sð>h7\83>ôGX¿;sð>:\1e=>\15Ü\e¿e\81E¿:\1e=>\15Ü\e¿e\81E¿:\1e=>\15Ü\e¿e\81E¿:\1e=>\15Ü\e¿e\81E¿u9f> ¼=¿\96ï!?u9f> ¼=¿\96ï!?u9f> ¼=¿\96ï!?u9f> ¼=¿\96ï!?u9f> ¼=¿\96ï!¿u9f> ¼=¿\96ï!¿u9f> ¼=¿\96ï!¿u9f> ¼=¿\96ï!¿G\1e=>\12Ü\e¿g\81E?G\1e=>\12Ü\e¿g\81E?G\1e=>\12Ü\e¿g\81E?G\1e=>\12Ü\e¿g\81E?e7\83>ïGX¿Msð¾e7\83>ïGX¿Msð¾e7\83>ïGX¿Msð¾e7\83>ïGX¿Msð¾Hgd>å§Õ¾g\87a¿Hgd>å§Õ¾g\87a¿Hgd>å§Õ¾g\87a¿Hgd>å§Õ¾g\87a¿r\15Õ>cSG¿Csð>r\15Õ>cSG¿Csð>r\15Õ>cSG¿Csð>r\15Õ>cSG¿Csð>E\8e\99>"¤\ f¿c\81E¿E\8e\99>"¤\ f¿c\81E¿E\8e\99>"¤\ f¿c\81E¿E\8e\99>"¤\ f¿c\81E¿\9eîº>ÒÜ.¿\8bï!?\9eîº>ÒÜ.¿\8bï!?\9eîº>ÒÜ.¿\8bï!?\9eîº>ÒÜ.¿\8bï!?\9eîº>ÒÜ.¿\8bï!¿\9eîº>ÒÜ.¿\8bï!¿\9eîº>ÒÜ.¿\8bï!¿\9eîº>ÒÜ.¿\8bï!¿3\8e\99>\1e¤\ f¿i\81E?3\8e\99>\1e¤\ f¿i\81E?3\8e\99>\1e¤\ f¿i\81E?3\8e\99>\1e¤\ f¿i\81E?l\15Õ>`SG¿Tsð¾l\15Õ>`SG¿Tsð¾l\15Õ>`SG¿Tsð¾l\15Õ>`SG¿Tsð¾\85gd>ï§Õ¾a\87a?\85gd>ï§Õ¾a\87a?\85gd>ï§Õ¾a\87a?\85gd>ï§Õ¾a\87a?b\ eç>D#X¿&ø\93¾b\ eç>D#X¿&ø\93¾b\ eç>D#X¿&ø\93¾b\ eç>D#X¿&ø\93¾×¾\f>\r¨\83¾kàt?×¾\f>\r¨\83¾kàt?×¾\f>\r¨\83¾kàt?×¾\f>\r¨\83¾kàt??4ð>ì±`¿\vÉǽ?4ð>ì±`¿\vÉǽ?4ð>ì±`¿\vÉǽ?4ð>ì±`¿\vÉǽ?4ð>ì±`¿\vÉÇ=?4ð>ì±`¿\vÉÇ=?4ð>ì±`¿\vÉÇ=?4ð>ì±`¿\vÉÇ=Ö¾\f>\1c¨\83¾hàt¿Ö¾\f>\1c¨\83¾hàt¿Ö¾\f>\1c¨\83¾hàt¿Ö¾\f>\1c¨\83¾hàt¿]\ eç>D#X¿$ø\93>]\ eç>D#X¿$ø\93>]\ eç>D#X¿$ø\93>]\ eç>D#X¿$ø\93>\84y\e?>r=¿.ø\93¾\84y\e?>r=¿.ø\93¾\84y\e?>r=¿.ø\93¾\84y\e?>r=¿.ø\93¾Ëh=>½Ëf¾màt?Ëh=>½Ëf¾màt?Ëh=>½Ëf¾màt?Ëh=>½Ëf¾màt?S¡!?`òD¿ãÈǽS¡!?`òD¿ãÈǽS¡!?`òD¿ãÈǽS¡!?`òD¿ãÈǽS¡!?`òD¿ãÈÇ=S¡!?`òD¿ãÈÇ=S¡!?`òD¿ãÈÇ=S¡!?`òD¿ãÈÇ=Èh=>ØËf¾kàt¿Èh=>ØËf¾kàt¿Èh=>ØËf¾kàt¿Èh=>ØËf¾kàt¿\83y\e?=r=¿3ø\93>\83y\e?=r=¿3ø\93>\83y\e?=r=¿3ø\93>\83y\e?=r=¿3ø\93>u°\99>^E»¾i\87a¿u°\99>^E»¾i\87a¿u°\99>^E»¾i\87a¿u°\99>^E»¾i\87a¿\99a\ f?âµ.¿=sð>\99a\ f?âµ.¿=sð>\99a\ f?âµ.¿=sð>\99a\ f?âµ.¿=sð>§¦Î>\1aÎû¾c\81E¿§¦Î>\1aÎû¾c\81E¿§¦Î>\1aÎû¾c\81E¿§¦Î>\1aÎû¾c\81E¿t\91û>®D\19¿\8fï!?t\91û>®D\19¿\8fï!?t\91û>®D\19¿\8fï!?t\91û>®D\19¿\8fï!?t\91û>®D\19¿\8fï!¿t\91û>®D\19¿\8fï!¿t\91û>®D\19¿\8fï!¿t\91û>®D\19¿\8fï!¿ ¦Î>\aÎû¾k\81E? ¦Î>\aÎû¾k\81E? ¦Î>\aÎû¾k\81E? ¦Î>\aÎû¾k\81E?\98a\ f?àµ.¿Fsð¾\98a\ f?àµ.¿Fsð¾\98a\ f?àµ.¿Fsð¾\98a\ f?àµ.¿Fsð¾o°\99>gE»¾g\87a?o°\99>gE»¾g\87a?o°\99>gE»¾g\87a?o°\99>gE»¾g\87a?âµ.?\98a\ f¿Asð>âµ.?\98a\ f¿Asð>âµ.?\98a\ f¿Asð>âµ.?\98a\ f¿Asð>\15Îû>\9e¦Î¾i\81E¿\15Îû>\9e¦Î¾i\81E¿\15Îû>\9e¦Î¾i\81E¿\15Îû>\9e¦Î¾i\81E¿¯D\19?n\91û¾\92ï!?¯D\19?n\91û¾\92ï!?¯D\19?n\91û¾\92ï!?¯D\19?n\91û¾\92ï!?­D\19?j\91û¾\94ï!¿­D\19?j\91û¾\94ï!¿­D\19?j\91û¾\94ï!¿­D\19?j\91û¾\94ï!¿\14Îû>\97¦Î¾j\81E?\14Îû>\97¦Î¾j\81E?\14Îû>\97¦Î¾j\81E?\14Îû>\97¦Î¾j\81E?áµ.?\91a\ f¿Ssð¾áµ.?\91a\ f¿Ssð¾áµ.?\91a\ f¿Ssð¾áµ.?\91a\ f¿Ssð¾rE»>\80°\99¾b\87a?rE»>\80°\99¾b\87a?rE»>\80°\99¾b\87a?rE»>\80°\99¾b\87a?Cr=?\81y\e¿$ø\93¾Cr=?\81y\e¿$ø\93¾Cr=?\81y\e¿$ø\93¾Cr=?\81y\e¿$ø\93¾´Ëf>Æh=¾oàt?´Ëf>Æh=¾oàt?´Ëf>Æh=¾oàt?´Ëf>Æh=¾oàt?fòD?K¡!¿úÈǽfòD?K¡!¿úÈǽfòD?K¡!¿úÈǽfòD?K¡!¿úÈǽfòD?K¡!¿úÈÇ=fòD?K¡!¿úÈÇ=fòD?K¡!¿úÈÇ=fòD?K¡!¿úÈÇ=µËf>Óh=¾màt¿µËf>Óh=¾màt¿µËf>Óh=¾màt¿µËf>Óh=¾màt¿Er=?\80y\e¿!ø\93>Er=?\80y\e¿!ø\93>Er=?\80y\e¿!ø\93>Er=?\80y\e¿!ø\93>kE»>s°\99¾f\87a¿kE»>s°\99¾f\87a¿kE»>s°\99¾f\87a¿kE»>s°\99¾f\87a¿ø§\83>a¾\f¾qàt?ø§\83>a¾\f¾qàt?ø§\83>a¾\f¾qàt?ø§\83>a¾\f¾qàt?ò±`?'4ð¾ñÈǽò±`?'4ð¾ñÈǽò±`?'4ð¾ñÈǽò±`?'4ð¾ñÈǽò±`?'4ð¾ñÈÇ=ò±`?'4ð¾ñÈÇ=ò±`?'4ð¾ñÈÇ=ò±`?'4ð¾ñÈÇ="¨\83>n¾\f¾kàt¿"¨\83>n¾\f¾kàt¿"¨\83>n¾\f¾kàt¿"¨\83>n¾\f¾kàt¿I#X?\\ eç¾\1cø\93>I#X?\\ eç¾\1cø\93>I#X?\\ eç¾\1cø\93>I#X?\\ eç¾\1cø\93>ñ§Õ>\10gd¾g\87a¿ñ§Õ>\10gd¾g\87a¿ñ§Õ>\10gd¾g\87a¿ñ§Õ>\10gd¾g\87a¿fSG?e\15Õ¾Esð>fSG?e\15Õ¾Esð>fSG?e\15Õ¾Esð>fSG?e\15Õ¾Esð>\1d¤\ f?5\8e\99¾g\81E¿\1d¤\ f?5\8e\99¾g\81E¿\1d¤\ f?5\8e\99¾g\81E¿\1d¤\ f?5\8e\99¾g\81E¿ÏÜ.?\95\90ï!?ÏÜ.?\95\90ï!?ÏÜ.?\95\90ï!?ÏÜ.?\95\90ï!?ÑÜ.?\95\8fï!¿ÑÜ.?\95\8fï!¿ÑÜ.?\95\8fï!¿ÑÜ.?\95\8fï!¿\e¤\ f?C\8e\99¾f\81E?\e¤\ f?C\8e\99¾f\81E?\e¤\ f?C\8e\99¾f\81E?\e¤\ f?C\8e\99¾f\81E?bSG?k\15Õ¾Msð¾bSG?k\15Õ¾Msð¾bSG?k\15Õ¾Msð¾bSG?k\15Õ¾Msð¾ú§Õ>\19gd¾d\87a?ú§Õ>\19gd¾d\87a?ú§Õ>\19gd¾d\87a?ú§Õ>\19gd¾d\87a?I#X?\\ eç¾\1cø\93¾I#X?\\ eç¾\1cø\93¾I#X?\\ eç¾\1cø\93¾I#X?\\ eç¾\1cø\93¾ª¼=?Z9f¾\8eï!?ª¼=?Z9f¾\8eï!?ª¼=?Z9f¾\8eï!?ª¼=?Z9f¾\8eï!?ª¼=?Z9f¾\8eï!¿ª¼=?Z9f¾\8eï!¿ª¼=?Z9f¾\8eï!¿ª¼=?Z9f¾\8eï!¿\rÜ\e?\1d\1e=¾o\81E?\rÜ\e?\1d\1e=¾o\81E?\rÜ\e?\1d\1e=¾o\81E?\rÜ\e?\1d\1e=¾o\81E?ïGX?U7\83¾Tsð¾ïGX?U7\83¾Tsð¾ïGX?U7\83¾Tsð¾ïGX?U7\83¾Tsð¾\9cÔç>k¦\f¾b\87a?\9cÔç>k¦\f¾b\87a?\9cÔç>k¦\f¾b\87a?\9cÔç>k¦\f¾b\87a?ð\85j?\95H\8e¾\18ø\93¾ð\85j?\95H\8e¾\18ø\93¾ð\85j?\95H\8e¾\18ø\93¾ð\85j?\95H\8e¾\18ø\93¾\11Û\8e>½V­½màt?\11Û\8e>½V­½màt?\11Û\8e>½V­½màt?\11Û\8e>½V­½màt?îÎs?²ê\93¾ñÈǽîÎs?²ê\93¾ñÈǽîÎs?²ê\93¾ñÈǽîÎs?²ê\93¾ñÈǽîÎs?²ê\93¾îÈÇ=îÎs?²ê\93¾îÈÇ=îÎs?²ê\93¾îÈÇ=îÎs?²ê\93¾îÈÇ=&Û\8e>çV­½jàt¿&Û\8e>çV­½jàt¿&Û\8e>çV­½jàt¿&Û\8e>çV­½jàt¿ð\85j?\98H\8e¾\1aø\93\85j?\98H\8e¾\1aø\93\85j?\98H\8e¾\1aø\93\85j?\98H\8e¾\1aø\93>\8bÔç>[¦\f¾f\87a¿\8bÔç>[¦\f¾f\87a¿\8bÔç>[¦\f¾f\87a¿\8bÔç>[¦\f¾f\87a¿òGX?^7\83¾Fsð>òGX?^7\83¾Fsð>òGX?^7\83¾Fsð>òGX?^7\83¾Fsð>\11Ü\e?6\1e=¾i\81E¿\11Ü\e?6\1e=¾i\81E¿\11Ü\e?6\1e=¾i\81E¿\11Ü\e?6\1e=¾i\81E¿]\8d}?öÇǽÝÈÇ=]\8d}?öÇǽÝÈÇ=]\8d}?öÇǽÝÈÇ=]\8d}?öÇǽÝÈÇ=°\90\94\1dê¼kàt¿°\90\94\1dê¼kàt¿°\90\94\1dê¼kàt¿°\90\94\1dê¼kàt¿]ås?D,À½\1cø\93>]ås?D,À½\1cø\93>]ås?D,À½\1cø\93>]ås?D,À½\1cø\93>h\18ñ>\15÷=½g\87a¿h\18ñ>\15÷=½g\87a¿h\18ñ>\15÷=½g\87a¿h\18ñ>\15÷=½g\87a¿¿ì`?\949±½Asð>¿ì`?\949±½Asð>¿ì`?\949±½Asð>¿ì`?\949±½Asð>®\16"?úm\7f½i\81E¿®\16"?úm\7f½i\81E¿®\16"?úm\7f½i\81E¿®\16"?úm\7f½i\81E¿âQE?Cy\9b½\8fï!?âQE?Cy\9b½\8fï!?âQE?Cy\9b½\8fï!?âQE?Cy\9b½\8fï!?âQE?Cy\9b½\8fï!¿âQE?Cy\9b½\8fï!¿âQE?Cy\9b½\8fï!¿âQE?Cy\9b½\8fï!¿¬\16"?\9em\7f½l\81E?¬\16"?\9em\7f½l\81E?¬\16"?\9em\7f½l\81E?¬\16"?\9em\7f½l\81E?¼ì`?\9e9±½Msð¾¼ì`?\9e9±½Msð¾¼ì`?\9e9±½Msð¾¼ì`?\9e9±½Msð¾n\18ñ>\18÷=½f\87a?n\18ñ>\18÷=½f\87a?n\18ñ>\18÷=½f\87a?n\18ñ>\18÷=½f\87a?_ås?C,À½\eø\93¾_ås?C,À½\eø\93¾_ås?C,À½\eø\93¾_ås?C,À½\eø\93¾ \90\94>\93\1eê¼màt? \90\94>\93\1eê¼màt? \90\94>\93\1eê¼màt? \90\94>\93\1eê¼màt?]\8d}?ùÇǽáÈǽ]\8d}?ùÇǽáÈǽ]\8d}?ùÇǽáÈǽ]\8d}?ùÇǽáÈǽáQE?\8ay\9b=\8eï!¿áQE?\8ay\9b=\8eï!¿áQE?\8ay\9b=\8eï!¿áQE?\8ay\9b=\8eï!¿®\16"?ëm\7f=i\81E?®\16"?ëm\7f=i\81E?®\16"?ëm\7f=i\81E?®\16"?ëm\7f=i\81E?¼ì`?\9e9±=Msð¾¼ì`?\9e9±=Msð¾¼ì`?\9e9±=Msð¾¼ì`?\9e9±=Msð¾n\18ñ>Q÷==f\87a?n\18ñ>Q÷==f\87a?n\18ñ>Q÷==f\87a?n\18ñ>Q÷==f\87a?]ås?°,À=\18ø\93¾]ås?°,À=\18ø\93¾]ås?°,À=\18ø\93¾]ås?°,À=\18ø\93¾©\90\94>\92\1eê<kàt?©\90\94>\92\1eê<kàt?©\90\94>\92\1eê<kàt?©\90\94>\92\1eê<kàt?[\8d}?bÈÇ=ÛÈǽ[\8d}?bÈÇ=ÛÈǽ[\8d}?bÈÇ=ÛÈǽ[\8d}?bÈÇ=ÛÈǽ[\8d}?bÈÇ=ÛÈÇ=[\8d}?bÈÇ=ÛÈÇ=[\8d}?bÈÇ=ÛÈÇ=[\8d}?bÈÇ=ÛÈÇ=ª\90\94\1dê<màt¿ª\90\94\1dê<màt¿ª\90\94\1dê<màt¿ª\90\94\1dê<màt¿]ås?°,À=\18ø\93>]ås?°,À=\18ø\93>]ås?°,À=\18ø\93>]ås?°,À=\18ø\93>f\18ñ>P÷==g\87a¿f\18ñ>P÷==g\87a¿f\18ñ>P÷==g\87a¿f\18ñ>P÷==g\87a¿¾ì`?Ò9±=Csð>¾ì`?Ò9±=Csð>¾ì`?Ò9±=Csð>¾ì`?Ò9±=Csð>²\16"?En\7f=e\81E¿²\16"?En\7f=e\81E¿²\16"?En\7f=e\81E¿²\16"?En\7f=e\81E¿áQE?\8ay\9b=\8eï!?áQE?\8ay\9b=\8eï!?áQE?\8ay\9b=\8eï!?áQE?\8ay\9b=\8eï!?ìÎs?Áê\93>ÞÈÇ=ìÎs?Áê\93>ÞÈÇ=ìÎs?Áê\93>ÞÈÇ=ìÎs?Áê\93>ÞÈÇ=\ fÛ\8e>þV­=màt¿\ fÛ\8e>þV­=màt¿\ fÛ\8e>þV­=màt¿\ fÛ\8e>þV­=màt¿ð\85j?\99H\8e>\10ø\93\85j?\99H\8e>\10ø\93\85j?\99H\8e>\10ø\93\85j?\99H\8e>\10ø\93>\83Ôç>b¦\f>i\87a¿\83Ôç>b¦\f>i\87a¿\83Ôç>b¦\f>i\87a¿\83Ôç>b¦\f>i\87a¿ñGX?a7\83>Hsð>ñGX?a7\83>Hsð>ñGX?a7\83>Hsð>ñGX?a7\83>Hsð>\ fÜ\e?E\1e=>i\81E¿\ fÜ\e?E\1e=>i\81E¿\ fÜ\e?E\1e=>i\81E¿\ fÜ\e?E\1e=>i\81E¿¨¼=?\809f>\8dï!?¨¼=?\809f>\8dï!?¨¼=?\809f>\8dï!?¨¼=?\809f>\8dï!?¨¼=?\809f>\8dï!¿¨¼=?\809f>\8dï!¿¨¼=?\809f>\8dï!¿¨¼=?\809f>\8dï!¿\vÜ\e?-\1e=>m\81E?\vÜ\e?-\1e=>m\81E?\vÜ\e?-\1e=>m\81E?\vÜ\e?-\1e=>m\81E?ïGX?e7\83>Osð¾ïGX?e7\83>Osð¾ïGX?e7\83>Osð¾ïGX?e7\83>Osð¾\96Ôç>n¦\f>b\87a?\96Ôç>n¦\f>b\87a?\96Ôç>n¦\f>b\87a?\96Ôç>n¦\f>b\87a?ð\85j?\9aH\8e>\10ø\93¾ð\85j?\9aH\8e>\10ø\93¾ð\85j?\9aH\8e>\10ø\93¾ð\85j?\9aH\8e>\10ø\93¾\11Û\8e>ÔV­=màt?\11Û\8e>ÔV­=màt?\11Û\8e>ÔV­=màt?\11Û\8e>ÔV­=màt?ìÎs?Áê\93>âÈǽìÎs?Áê\93>âÈǽìÎs?Áê\93>âÈǽìÎs?Áê\93>âÈǽ\18¤\ f?A\8e\99>j\81E?\18¤\ f?A\8e\99>j\81E?\18¤\ f?A\8e\99>j\81E?\18¤\ f?A\8e\99>j\81E?`SG?o\15Õ>Rsð¾`SG?o\15Õ>Rsð¾`SG?o\15Õ>Rsð¾`SG?o\15Õ>Rsð¾ô§Õ>Egd>b\87a?ô§Õ>Egd>b\87a?ô§Õ>Egd>b\87a?ô§Õ>Egd>b\87a?D#X?i\ eç>\11ø\93¾D#X?i\ eç>\11ø\93¾D#X?i\ eç>\11ø\93¾D#X?i\ eç>\11ø\93¾\10¨\83>s¾\f>màt?\10¨\83>s¾\f>màt?\10¨\83>s¾\f>màt?\10¨\83>s¾\f>màt?é±`?M4ð>ÑÈǽé±`?M4ð>ÑÈǽé±`?M4ð>ÑÈǽé±`?M4ð>ÑÈǽé±`?K4ð>ÎÈÇ=é±`?K4ð>ÎÈÇ=é±`?K4ð>ÎÈÇ=é±`?K4ð>ÎÈÇ=#¨\83>|¾\f>kàt¿#¨\83>|¾\f>kàt¿#¨\83>|¾\f>kàt¿#¨\83>|¾\f>kàt¿D#X?k\ eç>\12ø\93>D#X?k\ eç>\12ø\93>D#X?k\ eç>\12ø\93>D#X?k\ eç>\12ø\93>Ó§Õ>?gd>l\87a¿Ó§Õ>?gd>l\87a¿Ó§Õ>?gd>l\87a¿Ó§Õ>?gd>l\87a¿bSG?r\15Õ>Gsð>bSG?r\15Õ>Gsð>bSG?r\15Õ>Gsð>bSG?r\15Õ>Gsð>\1e¤\ f?3\8e\99>g\81E¿\1e¤\ f?3\8e\99>g\81E¿\1e¤\ f?3\8e\99>g\81E¿\1e¤\ f?3\8e\99>g\81E¿ÒÜ.?\9dîº>\8aï!?ÒÜ.?\9dîº>\8aï!?ÒÜ.?\9dîº>\8aï!?ÒÜ.?\9dîº>\8aï!?ÒÜ.?\9dîº>\8bï!¿ÒÜ.?\9dîº>\8bï!¿ÒÜ.?\9dîº>\8bï!¿ÒÜ.?\9dîº>\8bï!¿ºËf>âh=>màt¿ºËf>âh=>màt¿ºËf>âh=>màt¿ºËf>âh=>màt¿Fr=?\82y\e?\12ø\93>Fr=?\82y\e?\12ø\93>Fr=?\82y\e?\12ø\93>Fr=?\82y\e?\12ø\93>aE»>\81°\99>d\87a¿aE»>\81°\99>d\87a¿aE»>\81°\99>d\87a¿aE»>\81°\99>d\87a¿ßµ.?\99a\ f?Csð>ßµ.?\99a\ f?Csð>ßµ.?\99a\ f?Csð>ßµ.?\99a\ f?Csð>ñÍû>¢¦Î>q\81E¿ñÍû>¢¦Î>q\81E¿ñÍû>¢¦Î>q\81E¿ñÍû>¢¦Î>q\81E¿³D\19?{\91û>\8aï!?³D\19?{\91û>\8aï!?³D\19?{\91û>\8aï!?³D\19?{\91û>\8aï!?³D\19?{\91û>\8aï!¿³D\19?{\91û>\8aï!¿³D\19?{\91û>\8aï!¿³D\19?{\91û>\8aï!¿\ 1Îû>\9b¦Î>o\81E?\ 1Îû>\9b¦Î>o\81E?\ 1Îû>\9b¦Î>o\81E?\ 1Îû>\9b¦Î>o\81E?ݵ.?\96a\ f?Osð¾Ýµ.?\96a\ f?Osð¾Ýµ.?\96a\ f?Osð¾Ýµ.?\96a\ f?Osð¾jE»>\82°\99>b\87a?jE»>\82°\99>b\87a?jE»>\82°\99>b\87a?jE»>\82°\99>b\87a?Fr=?\82y\e?\12ø\93¾Fr=?\82y\e?\12ø\93¾Fr=?\82y\e?\12ø\93¾Fr=?\82y\e?\12ø\93¾ëËf>Âh=>kàt?ëËf>Âh=>kàt?ëËf>Âh=>kàt?ëËf>Âh=>kàt?aòD?R¡!?ÇÈǽaòD?R¡!?ÇÈǽaòD?R¡!?ÇÈǽaòD?R¡!?ÇÈǽaòD?R¡!?ÇÈÇ=aòD?R¡!?ÇÈÇ=aòD?R¡!?ÇÈÇ=aòD?R¡!?ÇÈÇ=\90a\ f?ãµ.?Osð¾\90a\ f?ãµ.?Osð¾\90a\ f?ãµ.?Osð¾\90a\ f?ãµ.?Osð¾}°\99>jE»>b\87a?}°\99>jE»>b\87a?}°\99>jE»>b\87a?}°\99>jE»>b\87a?|y\e?Nr=?\ 5ø\93¾|y\e?Nr=?\ 5ø\93¾|y\e?Nr=?\ 5ø\93¾|y\e?Nr=?\ 5ø\93¾Îh=>ÃËf>màt?Îh=>ÃËf>màt?Îh=>ÃËf>màt?Îh=>ÃËf>màt?G¡!?jòD?ÈÈǽG¡!?jòD?ÈÈǽG¡!?jòD?ÈÈǽG¡!?jòD?ÈÈǽG¡!?jòD?ÈÈÇ=G¡!?jòD?ÈÈÇ=G¡!?jòD?ÈÈÇ=G¡!?jòD?ÈÈÇ=Óh=>ÙËf>kàt¿Óh=>ÙËf>kàt¿Óh=>ÙËf>kàt¿Óh=>ÙËf>kàt¿{y\e?Mr=?\vø\93>{y\e?Mr=?\vø\93>{y\e?Mr=?\vø\93>{y\e?Mr=?\vø\93>}°\99>dE»>f\87a¿}°\99>dE»>f\87a¿}°\99>dE»>f\87a¿}°\99>dE»>f\87a¿\92a\ f?æµ.?Bsð>\92a\ f?æµ.?Bsð>\92a\ f?æµ.?Bsð>\92a\ f?æµ.?Bsð>¥¦Î>\rÎû>g\81E¿¥¦Î>\rÎû>g\81E¿¥¦Î>\rÎû>g\81E¿¥¦Î>\rÎû>g\81E¿m\91û>µD\19?\8aï!?m\91û>µD\19?\8aï!?m\91û>µD\19?\8aï!?m\91û>µD\19?\8aï!?i\91û>¶D\19?\8bï!¿i\91û>¶D\19?\8bï!¿i\91û>¶D\19?\8bï!¿i\91û>¶D\19?\8bï!¿\99¦Î>\vÎû>l\81E?\99¦Î>\vÎû>l\81E?\99¦Î>\vÎû>l\81E?\99¦Î>\vÎû>l\81E?Z\ eç>L#X?\ 6ø\93>Z\ eç>L#X?\ 6ø\93>Z\ eç>L#X?\ 6ø\93>Z\ eç>L#X?\ 6ø\93>"gd>í§Õ>g\87a¿"gd>í§Õ>g\87a¿"gd>í§Õ>g\87a¿"gd>í§Õ>g\87a¿`\15Õ>bSG?Ssð>`\15Õ>bSG?Ssð>`\15Õ>bSG?Ssð>`\15Õ>bSG?Ssð>7\8e\99>\e¤\ f?j\81E¿7\8e\99>\e¤\ f?j\81E¿7\8e\99>\e¤\ f?j\81E¿7\8e\99>\e¤\ f?j\81E¿\97îº>ØÜ.?\8aï!?\97îº>ØÜ.?\8aï!?\97îº>ØÜ.?\8aï!?\97îº>ØÜ.?\8aï!?\95îº>ÖÜ.?\8bï!¿\95îº>ÖÜ.?\8bï!¿\95îº>ÖÜ.?\8bï!¿\95îº>ÖÜ.?\8bï!¿/\8e\99>\e¤\ f?k\81E?/\8e\99>\e¤\ f?k\81E?/\8e\99>\e¤\ f?k\81E?/\8e\99>\e¤\ f?k\81E?Y\15Õ>cSG?Wsð¾Y\15Õ>cSG?Wsð¾Y\15Õ>cSG?Wsð¾Y\15Õ>cSG?Wsð¾ gd>ú§Õ>d\87a? gd>ú§Õ>d\87a? gd>ú§Õ>d\87a? gd>ú§Õ>d\87a?]\ eç>L#X?\ 5ø\93¾]\ eç>L#X?\ 5ø\93¾]\ eç>L#X?\ 5ø\93¾]\ eç>L#X?\ 5ø\93¾\82¾\f>\16¨\83>màt?\82¾\f>\16¨\83>màt?\82¾\f>\16¨\83>màt?\82¾\f>\16¨\83>màt?/4ð>ñ±`?»Èǽ/4ð>ñ±`?»Èǽ/4ð>ñ±`?»Èǽ/4ð>ñ±`?»Èǽ/4ð>ñ±`?»ÈÇ=/4ð>ñ±`?»ÈÇ=/4ð>ñ±`?»ÈÇ=/4ð>ñ±`?»ÈÇ=ܾ\f>#¨\83>hàt¿Ü¾\f>#¨\83>hàt¿Ü¾\f>#¨\83>hàt¿Ü¾\f>#¨\83>hàt¿f¦\f>\9cÔç>b\87a?f¦\f>\9cÔç>b\87a?f¦\f>\9cÔç>b\87a?f¦\f>\9cÔç>b\87a?\9cH\8e\85j?\ 1ø\93¾\9cH\8e\85j?\ 1ø\93¾\9cH\8e\85j?\ 1ø\93¾\9cH\8e\85j?\ 1ø\93¾\bW­=\ fÛ\8e>màt?\bW­=\ fÛ\8e>màt?\bW­=\ fÛ\8e>màt?\bW­=\ fÛ\8e>màt?­ê\93>ðÎs?¶Èǽ­ê\93>ðÎs?¶Èǽ­ê\93>ðÎs?¶Èǽ­ê\93>ðÎs?¶Èǽ®ê\93>ðÎs?µÈÇ=®ê\93>ðÎs?µÈÇ=®ê\93>ðÎs?µÈÇ=®ê\93>ðÎs?µÈÇ=       W­=\1fÛ\8e>jàt¿     W­=\1fÛ\8e>jàt¿     W­=\1fÛ\8e>jàt¿     W­=\1fÛ\8e>jàt¿\9cH\8e\85j?\ 1ø\93>\9cH\8e\85j?\ 1ø\93>\9cH\8e\85j?\ 1ø\93>\9cH\8e\85j?\ 1ø\93>,¦\f>\93Ôç>f\87a¿,¦\f>\93Ôç>f\87a¿,¦\f>\93Ôç>f\87a¿,¦\f>\93Ôç>f\87a¿X7\83>ñGX?Jsð>X7\83>ñGX?Jsð>X7\83>ñGX?Jsð>X7\83>ñGX?Jsð>1\1e=>\rÜ\e?l\81E¿1\1e=>\rÜ\e?l\81E¿1\1e=>\rÜ\e?l\81E¿1\1e=>\rÜ\e?l\81E¿e9f>°¼=?\86ï!?e9f>°¼=?\86ï!?e9f>°¼=?\86ï!?e9f>°¼=?\86ï!?e9f>°¼=?\86ï!¿e9f>°¼=?\86ï!¿e9f>°¼=?\86ï!¿e9f>°¼=?\86ï!¿)\1e=>\vÜ\e?o\81E?)\1e=>\vÜ\e?o\81E?)\1e=>\vÜ\e?o\81E?)\1e=>\vÜ\e?o\81E?W7\83>íGX?]sð¾W7\83>íGX?]sð¾W7\83>íGX?]sð¾W7\83>íGX?]sð¾\899±=¿ì`?Dsð>\899±=¿ì`?Dsð>\899±=¿ì`?Dsð>\899±=¿ì`?Dsð>Nm\7f\16"?m\81E¿Nm\7f\16"?m\81E¿Nm\7f\16"?m\81E¿Nm\7f\16"?m\81E¿Hy\9b=çQE?\88ï!?Hy\9b=çQE?\88ï!?Hy\9b=çQE?\88ï!?Hy\9b=çQE?\88ï!?Hy\9b=çQE?\88ï!¿Hy\9b=çQE?\88ï!¿Hy\9b=çQE?\88ï!¿Hy\9b=çQE?\88ï!¿\9am\7f\16"?o\81E?\9am\7f\16"?o\81E?\9am\7f\16"?o\81E?\9am\7f\16"?o\81E?\819±=¼ì`?Msð¾\819±=¼ì`?Msð¾\819±=¼ì`?Msð¾\819±=¼ì`?Msð¾"÷==}\18ñ>b\87a?"÷==}\18ñ>b\87a?"÷==}\18ñ>b\87a?"÷==}\18ñ>b\87a?2,À=aås?\aø\93¾2,À=aås?\aø\93¾2,À=aås?\aø\93¾2,À=aås?\aø\93¾ß\1dê<¢\90\94>màt?ß\1dê<¢\90\94>màt?ß\1dê<¢\90\94>màt?ß\1dê<¢\90\94>màt?ëÇÇ=]\8d}?fÈǽëÇÇ=]\8d}?fÈǽëÇÇ=]\8d}?fÈǽëÇÇ=]\8d}?fÈǽêÇÇ=]\8d}?fÈÇ=êÇÇ=]\8d}?fÈÇ=êÇÇ=]\8d}?fÈÇ=êÇÇ=]\8d}?fÈÇ=
+\eê<±\90\94>kàt¿
+\eê<±\90\94>kàt¿
+\eê<±\90\94>kàt¿
+\eê<±\90\94>kàt¿=,À=aås?\aø\93>=,À=aås?\aø\93>=,À=aås?\aø\93>=,À=aås?\aø\93>ý÷==o\18ñ>f\87a¿ý÷==o\18ñ>f\87a¿ý÷==o\18ñ>f\87a¿ý÷==o\18ñ>f\87a¿\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?\0\0\80?\0\0\0\0\0\0\0\80\0\0\80?ÑÎ\94°\90\f¶;]:\b¼u\10\8eº\1d\8d²;]:\b¼\13¶Cºùùu;P^\17¼\1d²W°\8cËz;P^\17¼@\v;±T:\b<\9b\f¶;;\9dÔºC\9c\ 5<\9b\f¶;\83>캽u\14<\99Ëz;[¼.°K^\17<\99Ëz;u?Ò°a´ç;j´ç»Aдºª@ã;j´ç»u\10\8eº\1d\8d²;]:\b¼ÑÎ\94°\90\f¶;]:\b¼u?Ò°a´ç;j´ç;Aдºª@ã;j´ç;;\9dÔºC\9c\ 5<\9b\f¶;@\v;±T:\b<\9b\f¶;@\v;±T:\b<\9b\f¶»;\9dÔºC\9c\ 5<\9b\f¶»Aдºª@ã;j´ç»u?Ò°a´ç;j´ç»³I©°\8e\f¶;]:\b<t\10\8eº\1c\8d²;]:\b<Aдºª@ã;j´ç;u?Ò°a´ç;j´ç;[¼.°K^\17< Ëz»\82>캽u\14< Ëz»;\9dÔºC\9c\ 5<\9b\f¶»@\v;±T:\b<\9b\f¶»\1d²W°\8aËz;R^\17<\r¶Cºòùu;R^\17<t\10\8eº\1c\8d²;]:\b<³I©°\8e\f¶;]:\b<ÏÍ0±\13± <uµÿº¥Ëúº­\9a\1d<uµÿº\82>캽u\14< Ëz»[¼.°K^\17< Ëz»\8av&¯Pµÿ:\1e± <\9b\8bǹ\8bËú:\1e± <\r¶Cºòùu;R^\17<\1d²W°\8aËz;R^\17<@\v\ 1×#<ì\86O°xµÿº\1d± <ì\86O°¥Ëúº­\9a\1d<uµÿºÏÍ0±\13± <uµÿº\8c\1cίaµÿ:\1d± ¼ª\8bǹ Ëú:\1d± ¼uÍø0N\fͱ
+×#¼\1c¶Cº}>ì:\1d± ¼\7f\10\8eº0\9dÔ:\1d± ¼\92\8bÇ9\8fËú:\1d± ¼
+¶C:n>ì:\1d± ¼Pдº4д:\1d± ¼uÍø0N\fͱ
+×#¼K\9dÔºb\10\8e:\1d± ¼\97>ìºâµC:\1d± ¼¹Ëúº8\8bÇ9\1d± ¼uÍø0N\fͱ
+×#¼\8bµÿºfv`±\1d± ¼¸Ëúº\18\8cǹ\1d± ¼\93>ìºP¶Cº\1d± ¼uÍø0N\fͱ
+×#¼F\9dÔº\97\10\8eº\1d± ¼Jдºgдº\1d± ¼y\10\8eºa\9dÔº\1d± ¼uÍø0N\fͱ
+×#¼\14¶Cº«>ìº\1d± ¼¡\8bǹÎËúº\1d± ¼
+\98\9e. µÿº\1d± ¼uÍø0N\fͱ
+×#¼¥\8bÇ9ËËúº\1d± ¼\13¶C:§>ìº\1d± ¼w\10\8e:\\9dÔº\1d± ¼uÍø0N\fͱ
+×#¼Fд:aдº\1d± ¼@\9dÔ:\91\10\8eº\1d± ¼\8a>ì:F¶Cº\1d± ¼uÍø0N\fͱ
+×#¼¬Ëú:
+\8cǹ\1d± ¼~µÿ:õ8V±\1d± ¼«Ëú:2\8bÇ9\1d± ¼uÍø0N\fͱ
+×#¼\89>ì:صC:\1d± ¼=\9dÔ:Y\10\8e:\1d± ¼Bд:)д:\1d± ¼uÍø0N\fͱ
+×#¼s\10\8e:"\9dÔ:\1d± ¼\0\0\0\0\9eê_±
+×#<\9b\8bǹ\8bËú:\1e± <\8av&¯Pµÿ:\1e± <\v¶Cºi>ì:\1e± <r\10\8eº \9dÔ:\1e± <\8a\8bÇ9~Ëú:\1e± <þµC:]>ì:\1e± <\0\0\0\0\9eê_±
+×#<@дº&д:\1e± <9\9dÔºW\10\8e:\1e± <\82>ìºÕµC:\1e± <\0\0\0\0\9eê_±
+×#<£Ëúº.\8bÇ9\1e± <wµÿº\99©S±\1e± <£Ëúº\ 2\8cǹ\1e± <\0\0\0\0\9eê_±
+×#<\81>ìº>¶Cº\1e± <7\9dÔº\8c\10\8eº\1e± <=дºYдº\1e± <\0\0\0\0\9eê_±
+×#<p\10\8eºR\9dÔº\1e± <        ¶Cº\9b>ìº\1e± <\97\8bǹ¼Ëúº\1e± <\0\0\0\0\9eê_±
+×#<
+U.®\8eµÿº\1e± <\93\8bÇ9»Ëúº\1e± <\ 4¶C:\97>ìº\1e± <\0\0\0\0\9eê_±
+×#<l\10\8e:L\9dÔº\1e± <8д:Tдº\1e± <0\9dÔ:\87\10\8eº\1e± <\0\0\0\0\9eê_±
+×#<x>ì:7¶Cº\1e± <\99Ëú:ü\8bǹ\1e± <lµÿ:RÈX±\1e± <\0\0\0\0\9eê_±
+×#<\99Ëú:"\8bÇ9\1e± <x>ì:ʵC:\1e± </\9dÔ:O\10\8e:\1e± <\0\0\0\0\9eê_±
+×#<7д:\1cд:\1e± <j\10\8e:\14\9dÔ:\1e± <ÏÍ0±\13± <iµÿ:¦Ëúº­\9a\1d<iµÿ:xµÿº\1d± <ì\86O°@\v\ 1×#<ì\86\1d²W°\8cËz;P^\17¼\13¶Cºùùu;P^\17¼ª\8bǹ Ëú:\1d± ¼\8c\1cίaµÿ:\1d± ¼[¼.°K^\17<\99Ëz;\83>캽u\14<\99Ëz;¦Ëúº­\9a\1d<iµÿ:ÏÍ0±\13± <iµÿ:¦Ëúº­\9a\1d<iµÿ:ýùu»¼u\14<iµÿ:¥Ëz»P^\17\86O°xµÿº\1d± <ì\86\13¶Cºùùu;P^\17¼^ó¿ºk´g;P^\17¼\1c¶Cº}>ì:\1d± ¼ª\8bǹ Ëú:\1d± ¼\83>캽u\14<\99Ëz;o´g»\9fØ\v<\99Ëz;ýùu»¼u\14<iµÿ:¦Ëúº­\9a\1d<iµÿ:u\10\8eº\1d\8d²;]:\b¼¥U\v»
+1¨;]:\b¼^ó¿ºk´g;P^\17¼\13¶Cºùùu;P^\17¼;\9dÔºC\9c\ 5<\9b\f¶;b\87P»j·û;\9b\f¶;o´g»\9fØ\v<\99Ëz;\83>캽u\14<\99Ëz;Aдºª@ã;j´ç»×V1»7\11Ö;j´ç»¥U\v»
+1¨;]:\b¼u\10\8eº\1d\8d²;]:\b¼Aдºª@ã;j´ç;×V1»7\11Ö;j´ç;b\87P»j·û;\9b\f¶;;\9dÔºC\9c\ 5<\9b\f¶;;\9dÔºC\9c\ 5<\9b\f¶»b\87P»j·û;\9b\f¶»×V1»7\11Ö;j´ç»Aдºª@ã;j´ç»t\10\8eº\1c\8d²;]:\b<¤U\v»    1¨;]:\b<×V1»7\11Ö;j´ç;Aдºª@ã;j´ç;\82>캽u\14< Ëz»n´g»\9fØ\v< Ëz»b\87P»j·û;\9b\f¶»;\9dÔºC\9c\ 5<\9b\f¶»\r¶Cºòùu;R^\17<Yó¿ºd´g;R^\17<¤U\v»     1¨;]:\b<t\10\8eº\1c\8d²;]:\b<¥Ëúº­\9a\1d<uµÿºýùu»¼u\14<uµÿºn´g»\9fØ\v< Ëz»\82>캽u\14< Ëz»\9b\8bǹ\8bËú:\1e± <\v¶Cºi>ì:\1e± <Yó¿ºd´g;R^\17<\r¶Cºòùu;R^\17<xµÿº\1d± <ì\86O°¥Ëz»P^\17\86O°ýùu»¼u\14<uµÿº¥Ëúº­\9a\1d<uµÿº¤U\v» 1¨;]:\b<JHJ»N^\97;]:\b<sº\80»Ê§À;j´ç;×V1»7\11Ö;j´ç;n´g»\9fØ\v< Ëz»\ e1¨»i·û; Ëz»T^\97»ð\89â;\9b\f¶»b\87P»j·û;\9b\f¶»Yó¿ºd´g;R^\17<¤U\v»U\87P;R^\17<JHJ»N^\97;]:\b<¤U\v»     1¨;]:\b<ýùu»¼u\14<uµÿº \8d²»A\9c\ 5<uµÿº\ e1¨»i·û; Ëz»n´g»\9fØ\v< Ëz»\v¶Cºi>ì:\1e± <r\10\8eº \9dÔ:\1e± <¤U\v»U\87P;R^\17<Yó¿ºd´g;R^\17<¥Ëz»P^\17\86O° \f¶»[:\b\86O° \8d²»A\9c\ 5<uµÿºýùu»¼u\14<uµÿºýùu»¼u\14<iµÿ: \8d²»A\9c\ 5<iµÿ: \f¶»[:\b\86O°¥Ëz»P^\17\86O°^ó¿ºk´g;P^\17¼§U\v»\\87P;P^\17¼\7f\10\8eº0\9dÔ:\1d± ¼\1c¶Cº}>ì:\1d± ¼o´g»\9fØ\v<\99Ëz;\ e1¨»j·û;\99Ëz; \8d²»A\9c\ 5<iµÿ:ýùu»¼u\14<iµÿ:¥U\v»
+1¨;]:\b¼KHJ»O^\97;]:\b¼§U\v»\\87P;P^\17¼^ó¿ºk´g;P^\17¼b\87P»j·û;\9b\f¶;T^\97»ð\89â;\9b\f¶;\ e1¨»j·û;\99Ëz;o´g»\9fØ\v<\99Ëz;×V1»7\11Ö;j´ç»sº\80»Ê§À;j´ç»KHJ»O^\97;]:\b¼¥U\v»
+1¨;]:\b¼×V1»7\11Ö;j´ç;sº\80»Ê§À;j´ç;T^\97»ð\89â;\9b\f¶;b\87P»j·û;\9b\f¶;b\87P»j·û;\9b\f¶»T^\97»ð\89â;\9b\f¶»sº\80»Ê§À;j´ç»×V1»7\11Ö;j´ç»\ e1¨»j·û;\99Ëz;<\11Ö»7\11Ö;\99Ëz;®@㻦@ã;iµÿ: \8d²»A\9c\ 5<iµÿ:KHJ»O^\97;]:\b¼tº\80»mº\80;]:\b¼ÜV1»ÎV1;P^\17¼§U\v»\\87P;P^\17¼T^\97»ð\89â;\9b\f¶;ЧÀ»É§À;\9b\f¶;<\11Ö»7\11Ö;\99Ëz;\ e1¨»j·û;\99Ëz;sº\80»Ê§À;j´ç»\ e×£»\a×£;j´ç»tº\80»mº\80;]:\b¼KHJ»O^\97;]:\b¼sº\80»Ê§À;j´ç;\ e×£»\a×£;j´ç;ЧÀ»É§À;\9b\f¶;T^\97»ð\89â;\9b\f¶;T^\97»ð\89â;\9b\f¶»Ð§À»É§À;\9b\f¶»\ e×£»\a×£;j´ç»sº\80»Ê§À;j´ç»JHJ»N^\97;]:\b<sº\80»kº\80;]:\b<\ e×£»\a×£;j´ç;sº\80»Ê§À;j´ç;\ e1¨»i·û; Ëz»<\11Ö»5\11Ö; Ëz»Ð§À»É§À;\9b\f¶»T^\97»ð\89â;\9b\f¶»¤U\v»U\87P;R^\17<×V1»ÊV1;R^\17<sº\80»kº\80;]:\b<JHJ»N^\97;]:\b\8d²»A\9c\ 5<uµÿº®@㻦@ã;uµÿº<\11Ö»5\11Ö; Ëz»\ e1¨»i·û; Ëz»r\10\8eº \9dÔ:\1e± <@дº&д:\1e± <×V1»ÊV1;R^\17<¤U\v»U\87P;R^\17\f¶»[:\b\86O°o´ç»f´ç;ì\86O°®@㻦@ã;uµÿº \8d²»A\9c\ 5<uµÿº \8d²»A\9c\ 5<iµÿ:®@㻦@ã;iµÿ:o´ç»f´ç;ì\86O° \f¶»[:\b\86O°§U\v»\\87P;P^\17¼ÜV1»ÎV1;P^\17¼Pдº4д:\1d± ¼\7f\10\8eº0\9dÔ:\1d± ¼×V1»ÊV1;R^\17<d\87\97U\v;R^\17<T^\97»;HJ;]:\b<sº\80»kº\80;]:\b<®@㻦@ã;uµÿºD\9c\ 5¼\17\8d²;uµÿºo·û»\a1¨; Ëz»<\11Ö»5\11Ö; Ëz»@дº&д:\1e± <9\9dÔºW\10\8e:\1e± <d\87\97U\v;R^\17<×V1»ÊV1;R^\17<o´ç»f´ç;ì\86O°_:\b¼\97\f¶;ì\86O°D\9c\ 5¼\17\8d²;uµÿº®@㻦@ã;uµÿº®@㻦@ã;iµÿ:D\9c\ 5¼\17\8d²;iµÿ:_:\b¼\97\f¶;ì\86O°o´ç»f´ç;ì\86O°ÜV1»ÎV1;P^\17¼i\87\9aU\v;P^\17¼K\9dÔºb\10\8e:\1d± ¼Pдº4д:\1d± ¼<\11Ö»7\11Ö;\99Ëz;o·û»        1¨;\99Ëz;D\9c\ 5¼\17\8d²;iµÿ:®@㻦@ã;iµÿ:tº\80»mº\80;]:\b¼V^\97»=HJ;]:\b¼i\87\9aU\v;P^\17¼ÜV1»ÎV1;P^\17¼Ð§À»É§À;\9b\f¶;÷\89â»M^\97;\9b\f¶;o·û»     1¨;\99Ëz;<\11Ö»7\11Ö;\99Ëz;\ e×£»\a×£;j´ç»Ð§À»kº\80;j´ç»V^\97»=HJ;]:\b¼tº\80»mº\80;]:\b¼\ e×£»\a×£;j´ç;ЧÀ»kº\80;j´ç;÷\89â»M^\97;\9b\f¶;ЧÀ»É§À;\9b\f¶;ЧÀ»É§À;\9b\f¶»÷\89â»M^\97;\9b\f¶»Ð§À»kº\80;j´ç»\ e×£»\a×£;j´ç»sº\80»kº\80;]:\b<T^\97»;HJ;]:\b<ЧÀ»kº\80;j´ç;\ e×£»\a×£;j´ç;<\11Ö»5\11Ö; Ëz»o·û»\a1¨; Ëz»÷\89â»M^\97;\9b\f¶»Ð§À»É§À;\9b\f¶»V^\97»=HJ;]:\b¼\101¨»\97U\v;]:\b¼w´g»Dó¿:P^\17¼i\87\9aU\v;P^\17¼÷\89â»M^\97;\9b\f¶;p·û»R\87P;\9b\f¶;¡Ø\v¼d´g;\99Ëz;o·û»     1¨;\99Ëz;ЧÀ»kº\80;j´ç»=\11Ö»ÇV1;j´ç»\101¨»\97U\v;]:\b¼V^\97»=HJ;]:\b¼Ð§À»kº\80;j´ç;=\11Ö»ÇV1;j´ç;p·û»R\87P;\9b\f¶;÷\89â»M^\97;\9b\f¶;÷\89â»M^\97;\9b\f¶»p·û»R\87P;\9b\f¶»=\11Ö»ÇV1;j´ç»Ð§À»kº\80;j´ç»T^\97»;HJ;]:\b<\ f1¨»\94U\v;]:\b<=\11Ö»ÇV1;j´ç;ЧÀ»kº\80;j´ç;o·û»\a1¨; Ëz»¡Ø\v¼a´g; Ëz»p·û»R\87P;\9b\f¶»÷\89â»M^\97;\9b\f¶»d\87\97U\v;R^\17<p´g»@ó¿:R^\17<\ f1¨»\94U\v;]:\b<T^\97»;HJ;]:\b<D\9c\ 5¼\17\8d²;uµÿº¾u\14¼éùu;uµÿº¡Ø\v¼a´g; Ëz»o·û»\a1¨; Ëz»9\9dÔºW\10\8e:\1e± <\82>ìºÕµC:\1e± <p´g»@ó¿:R^\17<d\87\97U\v;R^\17<_:\b¼\97\f¶;ì\86O°S^\17¼\94Ëz;ì\86O°¾u\14¼éùu;uµÿºD\9c\ 5¼\17\8d²;uµÿºD\9c\ 5¼\17\8d²;iµÿ:¾u\14¼éùu;iµÿ:S^\17¼\94Ëz;ì\86O°_:\b¼\97\f¶;ì\86O°i\87\9aU\v;P^\17¼w´g»Dó¿:P^\17¼\97>ìºâµC:\1d± ¼K\9dÔºb\10\8e:\1d± ¼o·û»     1¨;\99Ëz;¡Ø\v¼d´g;\99Ëz;¾u\14¼éùu;iµÿ:D\9c\ 5¼\17\8d²;iµÿ:¾u\14¼éùu;uµÿº®\9a\1d¼\80Ëú:uµÿº¿u\14¼i>ì: Ëz»¡Ø\v¼a´g; Ëz»\82>ìºÕµC:\1e± <£Ëúº.\8bÇ9\1e± <þùu»×µC:R^\17<p´g»@ó¿:R^\17<S^\17¼\94Ëz;ì\86O° ± ¼Wµÿ:ì\86O°®\9a\1d¼\80Ëú:uµÿº¾u\14¼éùu;uµÿº¾u\14¼éùu;iµÿ:®\9a\1d¼\80Ëú:iµÿ: ± ¼Wµÿ:ì\86O°S^\17¼\94Ëz;ì\86O°w´g»Dó¿:P^\17¼\ 5úu»ÙµC:P^\17¼¹Ëúº8\8bÇ9\1d± ¼\97>ìºâµC:\1d± ¼¡Ø\v¼d´g;\99Ëz;¿u\14¼n>ì:\99Ëz;®\9a\1d¼\80Ëú:iµÿ:¾u\14¼éùu;iµÿ:\101¨»\97U\v;]:\b¼"\8d²»X\10\8e:]:\b¼\ 5úu»ÙµC:P^\17¼w´g»Dó¿:P^\17¼p·û»R\87P;\9b\f¶;E\9c\ 5¼\e\9dÔ:\9b\f¶;¿u\14¼n>ì:\99Ëz;¡Ø\v¼d´g;\99Ëz;=\11Ö»ÇV1;j´ç»¯@ã»%д:j´ç»"\8d²»X\10\8e:]:\b¼\101¨»\97U\v;]:\b¼=\11Ö»ÇV1;j´ç;¯@ã»%д:j´ç;E\9c\ 5¼\e\9dÔ:\9b\f¶;p·û»R\87P;\9b\f¶;p·û»R\87P;\9b\f¶»E\9c\ 5¼\e\9dÔ:\9b\f¶»¯@ã»%д:j´ç»=\11Ö»ÇV1;j´ç»\ f1¨»\94U\v;]:\b<!\8d²»T\10\8e:]:\b<¯@ã»%д:j´ç;=\11Ö»ÇV1;j´ç;¡Ø\v¼a´g; Ëz»¿u\14¼i>ì: Ëz»E\9c\ 5¼\e\9dÔ:\9b\f¶»p·û»R\87P;\9b\f¶»p´g»@ó¿:R^\17<þùu»×µC:R^\17<!\8d²»T\10\8e:]:\b<\ f1¨»\94U\v;]:\b<E\9c\ 5¼\e\9dÔ:\9b\f¶;_:\b¼\1e\95\9b\f¶;R^\17¼
\1d±\99Ëz;¿u\14¼n>ì:\99Ëz;¯@ã»%д:j´ç»n´ç»®W[±j´ç»¡\f¶»õ8V±]:\b¼"\8d²»X\10\8e:]:\b¼¯@ã»%д:j´ç;n´ç»®W[±j´ç;_:\b¼\1e\95\9b\f¶;E\9c\ 5¼\e\9dÔ:\9b\f¶;E\9c\ 5¼\e\9dÔ:\9b\f¶»_:\b¼\1e\95\9b\f¶»n´ç»®W[±j´ç»¯@ã»%д:j´ç»!\8d²»T\10\8e:]:\b<\9e\f¶»×³j±]:\b<n´ç»®W[±j´ç;¯@ã»%д:j´ç;¿u\14¼i>ì: Ëz»R^\17¼\\9f<± Ëz»_:\b¼\1e\95\9b\f¶»E\9c\ 5¼\e\9dÔ:\9b\f¶»þùu»×µC:R^\17<¥Ëz»=\1aQ±R^\17<\9e\f¶»×³j±]:\b<!\8d²»T\10\8e:]:\b\9a\1d¼\80Ëú:uµÿº\1d± ¼pE\87±uµÿºR^\17¼\\9f<± Ëz»¿u\14¼i>ì: Ëz»£Ëúº.\8bÇ9\1e± <wµÿº\99©S±\1e± <¥Ëz»=\1aQ±R^\17<þùu»×µC:R^\17< ± ¼Wµÿ:ì\86\r×#¼¸&\82±ì\86\1d± ¼pE\87±uµÿº®\9a\1d¼\80Ëú:uµÿº®\9a\1d¼\80Ëú:iµÿ:\1d± ¼pE\87±iµÿ:\r×#¼¸&\82±ì\86O° ± ¼Wµÿ:ì\86\ 5úu»ÙµC:P^\17¼«Ëz»®W[±P^\17¼\8bµÿºfv`±\1d± ¼¹Ëúº8\8bÇ9\1d± ¼¿u\14¼n>ì:\99Ëz;R^\17¼
\1d±\99Ëz;\1d± ¼pE\87±iµÿ:®\9a\1d¼\80Ëú:iµÿ:"\8d²»X\10\8e:]:\b¼¡\f¶»õ8V±]:\b¼«Ëz»®W[±P^\17¼\ 5úu»ÙµC:P^\17¼wµÿº\99©S±\1e± <£Ëúº\ 2\8cǹ\1e± <ýùu»>¶CºR^\17<¥Ëz»=\1aQ±R^\17<\r×#¼¸&\82±ì\86O° ± ¼\97µÿºì\86O°­\9a\1d¼ÁËúºuµÿº\1d± ¼pE\87±uµÿº\1d± ¼pE\87±iµÿ:­\9a\1d¼ÁËúºiµÿ: ± ¼\97µÿºì\86\r×#¼¸&\82±ì\86O°«Ëz»®W[±P^\17¼\ 3úu»F¶CºP^\17¼¸Ëúº\18\8cǹ\1d± ¼\8bµÿºfv`±\1d± ¼R^\17¼
\1d±\99Ëz;¿u\14¼\94>ìº\99Ëz;­\9a\1d¼ÁËúºiµÿ:\1d± ¼pE\87±iµÿ:¡\f¶»õ8V±]:\b¼"\8d²»\8e\10\8eº]:\b¼\ 3úu»F¶CºP^\17¼«Ëz»®W[±P^\17¼_:\b¼\1e\95\9b\f¶;D\9c\ 5¼S\9dÔº\9b\f¶;¿u\14¼\94>ìº\99Ëz;R^\17¼
\1d±\99Ëz;n´ç»®W[±j´ç»®@ã»Yдºj´ç»"\8d²»\8e\10\8eº]:\b¼¡\f¶»õ8V±]:\b¼n´ç»®W[±j´ç;®@ã»Yдºj´ç;D\9c\ 5¼S\9dÔº\9b\f¶;_:\b¼\1e\95\9b\f¶;_:\b¼\1e\95\9b\f¶»D\9c\ 5¼S\9dÔº\9b\f¶»®@ã»Yдºj´ç»n´ç»®W[±j´ç»\9e\f¶»×³j±]:\b\8d²»\8f\10\8eº]:\b<®@ã»Yдºj´ç;n´ç»®W[±j´ç;R^\17¼\\9f<± Ëz»¿u\14¼\98>캠Ëz»D\9c\ 5¼S\9dÔº\9b\f¶»_:\b¼\1e\95\9b\f¶»¥Ëz»=\1aQ±R^\17<ýùu»>¶CºR^\17\8d²»\8f\10\8eº]:\b<\9e\f¶»×³j±]:\b<\1d± ¼pE\87±uµÿº­\9a\1d¼ÁËúºuµÿº¿u\14¼\98>캠Ëz»R^\17¼\\9f<± Ëz»®@ã»Yдºj´ç»<\11Ö»áV1»j´ç»\ f1¨»°U\v»]:\b¼"\8d²»\8e\10\8eº]:\b¼®@ã»Yдºj´ç;<\11Ö»áV1»j´ç;l·û»n\87\9b\f¶;D\9c\ 5¼S\9dÔº\9b\f¶;D\9c\ 5¼S\9dÔº\9b\f¶»l·û»n\87\9b\f¶»<\11Ö»áV1»j´ç»®@ã»Yдºj´ç» \8d²»\8f\10\8eº]:\b<\r1¨»°U\v»]:\b<<\11Ö»áV1»j´ç;®@ã»Yдºj´ç;¿u\14¼\98>캠Ëz»¡Ø\v¼x´g» Ëz»l·û»n\87\9b\f¶»D\9c\ 5¼S\9dÔº\9b\f¶»ýùu»>¶CºR^\17<n´g»ró¿ºR^\17<\r1¨»°U\v»]:\b\8d²»\8f\10\8eº]:\b\9a\1d¼ÁËúºuµÿº¼u\14¼\aúu»uµÿº¡Ø\v¼x´g» Ëz»¿u\14¼\98>캠Ëz»£Ëúº\ 2\8cǹ\1e± <\81>ìº>¶Cº\1e± <n´g»ró¿ºR^\17<ýùu»>¶CºR^\17< ± ¼\97µÿºì\86O°R^\17¼³Ëz»ì\86O°¼u\14¼\aúu»uµÿº­\9a\1d¼ÁËúºuµÿº­\9a\1d¼ÁËúºiµÿ:¼u\14¼\aúu»iµÿ:R^\17¼³Ëz»ì\86O° ± ¼\97µÿºì\86\ 3úu»F¶CºP^\17¼t´g»wó¿ºP^\17¼\93>ìºP¶Cº\1d± ¼¸Ëúº\18\8cǹ\1d± ¼¿u\14¼\94>ìº\99Ëz;¡Ø\v¼u´g»\99Ëz;¼u\14¼\aúu»iµÿ:­\9a\1d¼ÁËúºiµÿ:"\8d²»\8e\10\8eº]:\b¼\ f1¨»°U\v»]:\b¼t´g»wó¿ºP^\17¼\ 3úu»F¶CºP^\17¼D\9c\ 5¼S\9dÔº\9b\f¶;l·û»n\87\9b\f¶;¡Ø\v¼u´g»\99Ëz;¿u\14¼\94>ìº\99Ëz;R^\17¼³Ëz»ì\86O°^:\b¼¥\f¶»ì\86O°B\9c\ 5¼$\8d²»uµÿº¼u\14¼\aúu»uµÿº¼u\14¼\aúu»iµÿ:B\9c\ 5¼$\8d²»iµÿ:^:\b¼¥\f¶»ì\86O°R^\17¼³Ëz»ì\86O°t´g»wó¿ºP^\17¼f\87P»²U\v»P^\17¼F\9dÔº\97\10\8eº\1d± ¼\93>ìºP¶Cº\1d± ¼¡Ø\v¼u´g»\99Ëz;n·û»\121¨»\99Ëz;B\9c\ 5¼$\8d²»iµÿ:¼u\14¼\aúu»iµÿ:\ f1¨»°U\v»]:\b¼T^\97»UHJ»]:\b¼f\87P»²U\v»P^\17¼t´g»wó¿ºP^\17¼l·û»n\87\9b\f¶;ó\89â»Y^\97»\9b\f¶;n·û»\121¨»\99Ëz;¡Ø\v¼u´g»\99Ëz;<\11Ö»áV1»j´ç»Ï§À»wº\80»j´ç»T^\97»UHJ»]:\b¼\ f1¨»°U\v»]:\b¼<\11Ö»áV1»j´ç;ϧÀ»wº\80»j´ç;ó\89â»Y^\97»\9b\f¶;l·û»n\87\9b\f¶;l·û»n\87\9b\f¶»ó\89â»Y^\97»\9b\f¶»Ï§À»wº\80»j´ç»<\11Ö»áV1»j´ç»\r1¨»°U\v»]:\b<R^\97»THJ»]:\b<ϧÀ»wº\80»j´ç;<\11Ö»áV1»j´ç;¡Ø\v¼x´g» Ëz»n·û»\121¨» Ëz»ó\89â»Y^\97»\9b\f¶»l·û»n\87\9b\f¶»n´g»ró¿ºR^\17<`\87P»¯U\v»R^\17<R^\97»THJ»]:\b<\r1¨»°U\v»]:\b<¼u\14¼\aúu»uµÿºB\9c\ 5¼$\8d²»uµÿºn·û»\121¨» Ëz»¡Ø\v¼x´g» Ëz»\81>ìº>¶Cº\1e± <7\9dÔº\8c\10\8eº\1e± <`\87P»¯U\v»R^\17<n´g»ró¿ºR^\17<ϧÀ»wº\80»j´ç;\v×£»\12×£»j´ç;˧À»Ô§À»\9b\f¶;ó\89â»Y^\97»\9b\f¶;ó\89â»Y^\97»\9b\f¶»Ë§À»Ô§À»\9b\f¶»\v×£»\12×£»j´ç»Ï§À»wº\80»j´ç»R^\97»THJ»]:\b<pº\80»wº\80»]:\b<\v×£»\12×£»j´ç;ϧÀ»wº\80»j´ç;n·û»\121¨» Ëz»<\11Ö»@\11Ö» Ëz»Ë§À»Ô§À»\9b\f¶»ó\89â»Y^\97»\9b\f¶»`\87P»¯U\v»R^\17<ÓV1»áV1»R^\17<pº\80»wº\80»]:\b<R^\97»THJ»]:\b<B\9c\ 5¼$\8d²»uµÿº©@ã»°@ã»uµÿº<\11Ö»@\11Ö» Ëz»n·û»\121¨» Ëz»7\9dÔº\8c\10\8eº\1e± <=дºYдº\1e± <ÓV1»áV1»R^\17<`\87P»¯U\v»R^\17<^:\b¼¥\f¶»ì\86O°k´ç»t´ç»ì\86O°©@ã»°@ã»uµÿºB\9c\ 5¼$\8d²»uµÿºB\9c\ 5¼$\8d²»iµÿ:©@ã»°@ã»iµÿ:k´ç»t´ç»ì\86O°^:\b¼¥\f¶»ì\86O°f\87P»²U\v»P^\17¼ÙV1»åV1»P^\17¼Jдºgдº\1d± ¼F\9dÔº\97\10\8eº\1d± ¼n·û»\121¨»\99Ëz;<\11Ö»@\11Ö»\99Ëz;©@ã»°@ã»iµÿ:B\9c\ 5¼$\8d²»iµÿ:T^\97»UHJ»]:\b¼rº\80»xº\80»]:\b¼ÙV1»åV1»P^\17¼f\87P»²U\v»P^\17¼ó\89â»Y^\97»\9b\f¶;˧À»Ô§À»\9b\f¶;<\11Ö»@\11Ö»\99Ëz;n·û»\121¨»\99Ëz;ϧÀ»wº\80»j´ç»\v×£»\12×£»j´ç»rº\80»xº\80»]:\b¼T^\97»UHJ»]:\b¼©@ã»°@ã»iµÿ:\e\8d²»F\9c\ 5¼iµÿ:\9c\f¶»b:\b¼ì\86O°k´ç»t´ç»ì\86O°ÙV1»åV1»P^\17¼¥U\v»p\87P»P^\17¼y\10\8eºa\9dÔº\1d± ¼Jдºgдº\1d± ¼<\11Ö»@\11Ö»\99Ëz;\ e1¨»s·û»\99Ëz;\e\8d²»F\9c\ 5¼iµÿ:©@ã»°@ã»iµÿ:rº\80»xº\80»]:\b¼GHJ»Y^\97»]:\b¼¥U\v»p\87P»P^\17¼ÙV1»åV1»P^\17¼Ë§À»Ô§À»\9b\f¶;P^\97»ù\89â»\9b\f¶;\ e1¨»s·û»\99Ëz;<\11Ö»@\11Ö»\99Ëz;\v×£»\12×£»j´ç»pº\80»Ô§À»j´ç»GHJ»Y^\97»]:\b¼rº\80»xº\80»]:\b¼\v×£»\12×£»j´ç;pº\80»Ô§À»j´ç;P^\97»ù\89â»\9b\f¶;˧À»Ô§À»\9b\f¶;˧À»Ô§À»\9b\f¶»P^\97»ù\89â»\9b\f¶»pº\80»Ô§À»j´ç»\v×£»\12×£»j´ç»pº\80»wº\80»]:\b<DHJ»X^\97»]:\b<pº\80»Ô§À»j´ç;\v×£»\12×£»j´ç;<\11Ö»@\11Ö» Ëz»\ e1¨»s·û» Ëz»P^\97»ù\89â»\9b\f¶»Ë§À»Ô§À»\9b\f¶»ÓV1»áV1»R^\17< U\v»k\87P»R^\17<DHJ»X^\97»]:\b<pº\80»wº\80»]:\b<©@ã»°@ã»uµÿº\e\8d²»F\9c\ 5¼uµÿº\ e1¨»s·û» Ëz»<\11Ö»@\11Ö» Ëz»=дºYдº\1e± <p\10\8eºR\9dÔº\1e± < U\v»k\87P»R^\17<ÓV1»áV1»R^\17<k´ç»t´ç»ì\86\9c\f¶»b:\b¼ì\86\e\8d²»F\9c\ 5¼uµÿº©@ã»°@ã»uµÿºDHJ»X^\97»]:\b<\9fU\v»\121¨»]:\b<ÐV1»@\11Ö»j´ç;pº\80»Ô§À»j´ç;\ e1¨»s·û» Ëz»n´g»£Ø\v¼ Ëz»Y\87P»r·û»\9b\f¶»P^\97»ù\89â»\9b\f¶» U\v»k\87P»R^\17<Tó¿ºx´g»R^\17<\9fU\v»\121¨»]:\b<DHJ»X^\97»]:\b<\e\8d²»F\9c\ 5¼uµÿºóùu»¿u\14¼uµÿºn´g»£Ø\v¼ Ëz»\ e1¨»s·û» Ëz»p\10\8eºR\9dÔº\1e± <    ¶Cº\9b>ìº\1e± <Tó¿ºx´g»R^\17< U\v»k\87P»R^\17<\9c\f¶»b:\b¼ì\86\9eËz»V^\17¼ì\86O°óùu»¿u\14¼uµÿº\e\8d²»F\9c\ 5¼uµÿº\e\8d²»F\9c\ 5¼iµÿ:óùu»¿u\14¼iµÿ:\9eËz»V^\17¼ì\86\9c\f¶»b:\b¼ì\86O°¥U\v»p\87P»P^\17¼\ó¿º}´g»P^\17¼\14¶Cº«>ìº\1d± ¼y\10\8eºa\9dÔº\1d± ¼\ e1¨»s·û»\99Ëz;n´g»£Ø\v¼\99Ëz;óùu»¿u\14¼iµÿ:\e\8d²»F\9c\ 5¼iµÿ:GHJ»Y^\97»]:\b¼¢U\v»\141¨»]:\b¼\ó¿º}´g»P^\17¼¥U\v»p\87P»P^\17¼P^\97»ù\89â»\9b\f¶;Y\87P»r·û»\9b\f¶;n´g»£Ø\v¼\99Ëz;\ e1¨»s·û»\99Ëz;pº\80»Ô§À»j´ç»ÐV1»@\11Ö»j´ç»¢U\v»\141¨»]:\b¼GHJ»Y^\97»]:\b¼pº\80»Ô§À»j´ç;ÐV1»@\11Ö»j´ç;Y\87P»r·û»\9b\f¶;P^\97»ù\89â»\9b\f¶;P^\97»ù\89â»\9b\f¶»Y\87P»r·û»\9b\f¶»ÐV1»@\11Ö»j´ç»pº\80»Ô§À»j´ç»\ó¿º}´g»P^\17¼\12¶Cº\vúu»P^\17¼¡\8bǹÎËúº\1d± ¼\14¶Cº«>ìº\1d± ¼n´g»£Ø\v¼\99Ëz;\83>ìºÀu\14¼\99Ëz;\97Ëúº¯\9a\1d¼iµÿ:óùu»¿u\14¼iµÿ:¢U\v»\141¨»]:\b¼s\10\8eº&\8d²»]:\b¼\12¶Cº\vúu»P^\17¼\ó¿º}´g»P^\17¼Y\87P»r·û»\9b\f¶;+\9dÔºE\9c\ 5¼\9b\f¶;\83>ìºÀu\14¼\99Ëz;n´g»£Ø\v¼\99Ëz;ÐV1»@\11Ö»j´ç»9дº²@ã»j´ç»s\10\8eº&\8d²»]:\b¼¢U\v»\141¨»]:\b¼ÐV1»@\11Ö»j´ç;9дº²@ã»j´ç;+\9dÔºE\9c\ 5¼\9b\f¶;Y\87P»r·û»\9b\f¶;Y\87P»r·û»\9b\f¶»+\9dÔºE\9c\ 5¼\9b\f¶»9дº²@ã»j´ç»ÐV1»@\11Ö»j´ç»\9fU\v»\121¨»]:\b<m\10\8eº$\8d²»]:\b<9дº²@ã»j´ç;ÐV1»@\11Ö»j´ç;n´g»£Ø\v¼ Ëz»\83>ìºÀu\14¼ Ëz»+\9dÔºE\9c\ 5¼\9b\f¶»Y\87P»r·û»\9b\f¶»Tó¿ºx´g»R^\17<\a¶Cº\ 6úu»R^\17<m\10\8eº$\8d²»]:\b<\9fU\v»\121¨»]:\b<óùu»¿u\14¼uµÿº\97Ëúº¯\9a\1d¼uµÿº\83>ìºÀu\14¼ Ëz»n´g»£Ø\v¼ Ëz»     ¶Cº\9b>ìº\1e± <\97\8bǹ¼Ëúº\1e± <\a¶Cº\ 6úu»R^\17<Tó¿ºx´g»R^\17<\9eËz»V^\17¼ì\86O°lµÿº"± ¼ì\86\97Ëúº¯\9a\1d¼uµÿºóùu»¿u\14¼uµÿºóùu»¿u\14¼iµÿ:\97Ëúº¯\9a\1d¼iµÿ:lµÿº"± ¼ì\86\9eËz»V^\17¼ì\86\83>ìºÀu\14¼ Ëz»[¼.°T^\17¼ Ëz»>Ýj0^:\b¼\9b\f¶»+\9dÔºE\9c\ 5¼\9b\f¶»\a¶Cº\ 6úu»R^\17<
+U.®¬Ëz»R^\17<\8f\83ð.¡\f¶»]:\b<m\10\8eº$\8d²»]:\b<\97Ëúº¯\9a\1d¼uµÿº>Ýj0\1e± ¼uµÿº[¼.°T^\17¼ Ëz»\83>ìºÀu\14¼ Ëz»\97\8bǹ¼Ëúº\1e± <
+U.®\8eµÿº\1e± <
+U.®¬Ëz»R^\17<\a¶Cº\ 6úu»R^\17<lµÿº"± ¼ì\86\80é\890\ e×#¼ì\86O°>Ýj0\1e± ¼uµÿº\97Ëúº¯\9a\1d¼uµÿº\97Ëúº¯\9a\1d¼iµÿ:>Ýj0\1e± ¼iµÿ:\80é\890\ e×#¼ì\86O°lµÿº"± ¼ì\86\12¶Cº\vúu»P^\17¼n\97⯲Ëz»P^\17¼
+\98\9e. µÿº\1d± ¼¡\8bǹÎËúº\1d± ¼\83>ìºÀu\14¼\99Ëz;[¼.°T^\17¼\99Ëz;>Ýj0\1e± ¼iµÿ:\97Ëúº¯\9a\1d¼iµÿ:s\10\8eº&\8d²»]:\b¼é«\90¯¥\f¶»]:\b¼n\97⯲Ëz»P^\17¼\12¶Cº\vúu»P^\17¼+\9dÔºE\9c\ 5¼\9b\f¶;>Ýj0^:\b¼\9b\f¶;[¼.°T^\17¼\99Ëz;\83>ìºÀu\14¼\99Ëz;9дº²@ã»j´ç»i\f\8e/p´ç»j´ç»é«\90¯¥\f¶»]:\b¼s\10\8eº&\8d²»]:\b¼9дº²@ã»j´ç;i\f\8e/p´ç»j´ç;>Ýj0^:\b¼\9b\f¶;+\9dÔºE\9c\ 5¼\9b\f¶;+\9dÔºE\9c\ 5¼\9b\f¶»>Ýj0^:\b¼\9b\f¶»i\f\8e/p´ç»j´ç»9дº²@ã»j´ç»m\10\8eº$\8d²»]:\b<\8f\83ð.¡\f¶»]:\b<i\f\8e/p´ç»j´ç;9дº²@ã»j´ç;[¼.°T^\17¼\99Ëz;y>ì:Àu\14¼\99Ëz;£Ëú:®\9a\1d¼iµÿ:>Ýj0\1e± ¼iµÿ:é«\90¯¥\f¶»]:\b¼n\10\8e:&\8d²»]:\b¼\ 2¶C:    úu»P^\17¼n\97⯲Ëz»P^\17¼>Ýj0^:\b¼\9b\f¶;9\9dÔ:D\9c\ 5¼\9b\f¶;y>ì:Àu\14¼\99Ëz;[¼.°T^\17¼\99Ëz;i\f\8e/p´ç»j´ç»>д:°@ã»j´ç»n\10\8e:&\8d²»]:\b¼é«\90¯¥\f¶»]:\b¼i\f\8e/p´ç»j´ç;>д:°@ã»j´ç;9\9dÔ:D\9c\ 5¼\9b\f¶;>Ýj0^:\b¼\9b\f¶;>Ýj0^:\b¼\9b\f¶»9\9dÔ:D\9c\ 5¼\9b\f¶»>д:°@ã»j´ç»i\f\8e/p´ç»j´ç»\8f\83ð.¡\f¶»]:\b<n\10\8e:"\8d²»]:\b<>д:°@ã»j´ç;i\f\8e/p´ç»j´ç;[¼.°T^\17¼ Ëz»y>ì:Àu\14¼ Ëz»9\9dÔ:D\9c\ 5¼\9b\f¶»>Ýj0^:\b¼\9b\f¶»
+U.®¬Ëz»R^\17<\ 4¶C:\ 3úu»R^\17<n\10\8e:"\8d²»]:\b<\8f\83ð.¡\f¶»]:\b<>Ýj0\1e± ¼uµÿº£Ëú:®\9a\1d¼uµÿºy>ì:Àu\14¼ Ëz»[¼.°T^\17¼ Ëz»
+U.®\8eµÿº\1e± <\93\8bÇ9»Ëúº\1e± <\ 4¶C:\ 3úu»R^\17<
+U.®¬Ëz»R^\17<\80é\890\ e×#¼ì\86O°}µÿ:!± ¼ì\86O°£Ëú:®\9a\1d¼uµÿº>Ýj0\1e± ¼uµÿº>Ýj0\1e± ¼iµÿ:£Ëú:®\9a\1d¼iµÿ:}µÿ:!± ¼ì\86\80é\890\ e×#¼ì\86O°n\97⯲Ëz»P^\17¼\ 2¶C:    úu»P^\17¼¥\8bÇ9ËËúº\1d± ¼
+\98\9e. µÿº\1d± ¼\ 4¶C:\ 3úu»R^\17<Ró¿:t´g»R^\17<\9fU\v;\101¨»]:\b<n\10\8e:"\8d²»]:\b<£Ëú:®\9a\1d¼uµÿºøùu;½u\14¼uµÿºg´g;£Ø\v¼ Ëz»y>ì:Àu\14¼ Ëz»\93\8bÇ9»Ëúº\1e± <\ 4¶C:\97>ìº\1e± <Ró¿:t´g»R^\17<\ 4¶C:\ 3úu»R^\17<}µÿ:!± ¼ì\86O°¦Ëz;T^\17¼ì\86O°øùu;½u\14¼uµÿº£Ëú:®\9a\1d¼uµÿº£Ëú:®\9a\1d¼iµÿ:øùu;½u\14¼iµÿ:¦Ëz;T^\17¼ì\86O°}µÿ:!± ¼ì\86\ 2¶C:        úu»P^\17¼Só¿:y´g»P^\17¼\13¶C:§>ìº\1d± ¼¥\8bÇ9ËËúº\1d± ¼y>ì:Àu\14¼\99Ëz;g´g;£Ø\v¼\99Ëz;øùu;½u\14¼iµÿ:£Ëú:®\9a\1d¼iµÿ:n\10\8e:&\8d²»]:\b¼ U\v;\141¨»]:\b¼Só¿:y´g»P^\17¼\ 2¶C:     úu»P^\17¼9\9dÔ:D\9c\ 5¼\9b\f¶;]\87P;k·û»\9b\f¶;g´g;£Ø\v¼\99Ëz;y>ì:Àu\14¼\99Ëz;>д:°@ã»j´ç»ÒV1;>\11Ö»j´ç» U\v;\141¨»]:\b¼n\10\8e:&\8d²»]:\b¼>д:°@ã»j´ç;ÒV1;>\11Ö»j´ç;]\87P;k·û»\9b\f¶;9\9dÔ:D\9c\ 5¼\9b\f¶;9\9dÔ:D\9c\ 5¼\9b\f¶»]\87P;k·û»\9b\f¶»ÒV1;>\11Ö»j´ç»>д:°@ã»j´ç»n\10\8e:"\8d²»]:\b<\9fU\v;\101¨»]:\b<ÒV1;>\11Ö»j´ç;>д:°@ã»j´ç;y>ì:Àu\14¼ Ëz»g´g;£Ø\v¼ Ëz»]\87P;k·û»\9b\f¶»9\9dÔ:D\9c\ 5¼\9b\f¶» U\v;\141¨»]:\b¼EHJ;Y^\97»]:\b¼\9fU\v;k\87P»P^\17¼Só¿:y´g»P^\17¼]\87P;k·û»\9b\f¶;O^\97\89â»\9b\f¶;
+1¨;r·û»\99Ëz;g´g;£Ø\v¼\99Ëz;ÒV1;>\11Ö»j´ç»oº\80;Ò§À»j´ç»EHJ;Y^\97»]:\b¼ U\v;\141¨»]:\b¼ÒV1;>\11Ö»j´ç;oº\80;Ò§À»j´ç;O^\97\89â»\9b\f¶;]\87P;k·û»\9b\f¶;]\87P;k·û»\9b\f¶»O^\97\89â»\9b\f¶»oº\80;Ò§À»j´ç»ÒV1;>\11Ö»j´ç»\9fU\v;\101¨»]:\b<BHJ;V^\97»]:\b<oº\80;Ò§À»j´ç;ÒV1;>\11Ö»j´ç;g´g;£Ø\v¼ Ëz»
+1¨;r·û» Ëz»O^\97\89â»\9b\f¶»]\87P;k·û»\9b\f¶»Ró¿:t´g»R^\17<\9dU\v;f\87P»R^\17<BHJ;V^\97»]:\b<\9fU\v;\101¨»]:\b<øùu;½u\14¼uµÿº\1c\8d²;C\9c\ 5¼uµÿº
+1¨;r·û» Ëz»g´g;£Ø\v¼ Ëz»\ 4¶C:\97>ìº\1e± <l\10\8e:L\9dÔº\1e± <\9dU\v;f\87P»R^\17<Ró¿:t´g»R^\17<¦Ëz;T^\17¼ì\86\9e\f¶;_:\b¼ì\86\1c\8d²;C\9c\ 5¼uµÿºøùu;½u\14¼uµÿºøùu;½u\14¼iµÿ:\1c\8d²;C\9c\ 5¼iµÿ:\9e\f¶;_:\b¼ì\86O°¦Ëz;T^\17¼ì\86O°Só¿:y´g»P^\17¼\9fU\v;k\87P»P^\17¼w\10\8e:\\9dÔº\1d± ¼\13¶C:§>ìº\1d± ¼g´g;£Ø\v¼\99Ëz;
+1¨;r·û»\99Ëz;\1c\8d²;C\9c\ 5¼iµÿ:øùu;½u\14¼iµÿ:\1c\8d²;C\9c\ 5¼uµÿº§@ã;ª@ã»uµÿº7\11Ö;>\11Ö» Ëz»
+1¨;r·û» Ëz»l\10\8e:L\9dÔº\1e± <8д:Tдº\1e± <ÏV1;ÛV1»R^\17<\9dU\v;f\87P»R^\17<\9e\f¶;_:\b¼ì\86O°l´ç;n´ç»ì\86O°§@ã;ª@ã»uµÿº\1c\8d²;C\9c\ 5¼uµÿº\1c\8d²;C\9c\ 5¼iµÿ:§@ã;ª@ã»iµÿ:l´ç;n´ç»ì\86\9e\f¶;_:\b¼ì\86\9fU\v;k\87P»P^\17¼ÒV1;ÞV1»P^\17¼Fд:aдº\1d± ¼w\10\8e:\\9dÔº\1d± ¼
+1¨;r·û»\99Ëz;7\11Ö;>\11Ö»\99Ëz;§@ã;ª@ã»iµÿ:\1c\8d²;C\9c\ 5¼iµÿ:EHJ;Y^\97»]:\b¼pº\80;wº\80»]:\b¼ÒV1;ÞV1»P^\17¼\9fU\v;k\87P»P^\17¼O^\97\89â»\9b\f¶;ɧÀ;˧À»\9b\f¶;7\11Ö;>\11Ö»\99Ëz;
+1¨;r·û»\99Ëz;oº\80;Ò§À»j´ç»
+×£;\ f×£»j´ç»pº\80;wº\80»]:\b¼EHJ;Y^\97»]:\b¼oº\80;Ò§À»j´ç;
+×£;\ f×£»j´ç;ɧÀ;˧À»\9b\f¶;O^\97\89â»\9b\f¶;O^\97\89â»\9b\f¶»É§À;˧À»\9b\f¶»
+×£;\ f×£»j´ç»oº\80;Ò§À»j´ç»BHJ;V^\97»]:\b<nº\80;tº\80»]:\b<
+×£;\ f×£»j´ç;oº\80;Ò§À»j´ç;
+1¨;r·û» Ëz»7\11Ö;>\11Ö» Ëz»É§À;˧À»\9b\f¶»O^\97\89â»\9b\f¶»\9dU\v;f\87P»R^\17<ÏV1;ÛV1»R^\17<nº\80;tº\80»]:\b<BHJ;V^\97»]:\b<ɧÀ;˧À»\9b\f¶;î\89â;Q^\97»\9b\f¶;j·û;\121¨»\99Ëz;7\11Ö;>\11Ö»\99Ëz;
+×£;\ f×£»j´ç»Ë§À;tº\80»j´ç»Q^\97;SHJ»]:\b¼pº\80;wº\80»]:\b¼
+×£;\ f×£»j´ç;˧À;tº\80»j´ç;î\89â;Q^\97»\9b\f¶;ɧÀ;˧À»\9b\f¶;ɧÀ;˧À»\9b\f¶»î\89â;Q^\97»\9b\f¶»Ë§À;tº\80»j´ç»
+×£;\ f×£»j´ç»nº\80;tº\80»]:\b<O^\97;MHJ»]:\b<˧À;tº\80»j´ç;
+×£;\ f×£»j´ç;7\11Ö;>\11Ö» Ëz»j·û;\121¨» Ëz»î\89â;Q^\97»\9b\f¶»É§À;˧À»\9b\f¶»ÏV1;ÛV1»R^\17<Y\87P;§U\v»R^\17<O^\97;MHJ»]:\b<nº\80;tº\80»]:\b<§@ã;ª@ã»uµÿº@\9c\ 5<\1c\8d²»uµÿºj·û;\121¨» Ëz»7\11Ö;>\11Ö» Ëz»8д:Tдº\1e± <0\9dÔ:\87\10\8eº\1e± <Y\87P;§U\v»R^\17<ÏV1;ÛV1»R^\17<l´ç;n´ç»ì\86O°]:\b<\9e\f¶»ì\86O°@\9c\ 5<\1c\8d²»uµÿº§@ã;ª@ã»uµÿº§@ã;ª@ã»iµÿ:@\9c\ 5<\1c\8d²»iµÿ:]:\b<\9e\f¶»ì\86O°l´ç;n´ç»ì\86O°ÒV1;ÞV1»P^\17¼]\87P;«U\v»P^\17¼@\9dÔ:\91\10\8eº\1d± ¼Fд:aдº\1d± ¼7\11Ö;>\11Ö»\99Ëz;j·û;\121¨»\99Ëz;@\9c\ 5<\1c\8d²»iµÿ:§@ã;ª@ã»iµÿ:pº\80;wº\80»]:\b¼Q^\97;SHJ»]:\b¼]\87P;«U\v»P^\17¼ÒV1;ÞV1»P^\17¼0\9dÔ:\87\10\8eº\1e± <x>ì:7¶Cº\1e± <e´g;eó¿ºR^\17<Y\87P;§U\v»R^\17<]:\b<\9e\f¶»ì\86O°P^\17<¥Ëz»ì\86O°ºu\14<÷ùu»uµÿº@\9c\ 5<\1c\8d²»uµÿº@\9c\ 5<\1c\8d²»iµÿ:ºu\14<÷ùu»iµÿ:P^\17<¥Ëz»ì\86O°]:\b<\9e\f¶»ì\86O°]\87P;«U\v»P^\17¼i´g;jó¿ºP^\17¼\8a>ì:F¶Cº\1d± ¼@\9dÔ:\91\10\8eº\1d± ¼j·û;\121¨»\99Ëz;\9fØ\v<x´g»\99Ëz;ºu\14<÷ùu»iµÿ:@\9c\ 5<\1c\8d²»iµÿ:Q^\97;SHJ»]:\b¼\v1¨;­U\v»]:\b¼i´g;jó¿ºP^\17¼]\87P;«U\v»P^\17¼î\89â;Q^\97»\9b\f¶;e·û;^\87\9b\f¶;\9fØ\v<x´g»\99Ëz;j·û;\121¨»\99Ëz;˧À;tº\80»j´ç»8\11Ö;ÛV1»j´ç»\v1¨;­U\v»]:\b¼Q^\97;SHJ»]:\b¼Ë§À;tº\80»j´ç;8\11Ö;ÛV1»j´ç;e·û;^\87\9b\f¶;î\89â;Q^\97»\9b\f¶;î\89â;Q^\97»\9b\f¶»e·û;^\87\9b\f¶»8\11Ö;ÛV1»j´ç»Ë§À;tº\80»j´ç»O^\97;MHJ»]:\b<        1¨;©U\v»]:\b<8\11Ö;ÛV1»j´ç;˧À;tº\80»j´ç;j·û;\121¨» Ëz»\9fØ\v<x´g» Ëz»e·û;^\87\9b\f¶»î\89â;Q^\97»\9b\f¶»Y\87P;§U\v»R^\17<e´g;eó¿ºR^\17<     1¨;©U\v»]:\b<O^\97;MHJ»]:\b<@\9c\ 5<\1c\8d²»uµÿººu\14<÷ùu»uµÿº\9fØ\v<x´g» Ëz»j·û;\121¨» Ëz»8\11Ö;ÛV1»j´ç;ª@ã;Mдºj´ç;?\9c\ 5<;\9dÔº\9b\f¶;e·û;^\87\9b\f¶;e·û;^\87\9b\f¶»?\9c\ 5<;\9dÔº\9b\f¶»ª@ã;Mдºj´ç»8\11Ö;ÛV1»j´ç» 1¨;©U\v»]:\b<\e\8d²;\84\10\8eº]:\b<ª@ã;Mдºj´ç;8\11Ö;ÛV1»j´ç;\9fØ\v<x´g» Ëz»½u\14<\99>캠Ëz»?\9c\ 5<;\9dÔº\9b\f¶»e·û;^\87\9b\f¶»e´g;eó¿ºR^\17<òùu;-¶CºR^\17<\e\8d²;\84\10\8eº]:\b<     1¨;©U\v»]:\b<ºu\14<÷ùu»uµÿº©\9a\1d<¢Ëúºuµÿº½u\14<\99>캠Ëz»\9fØ\v<x´g» Ëz»x>ì:7¶Cº\1e± <\99Ëú:ü\8bǹ\1e± <òùu;-¶CºR^\17<e´g;eó¿ºR^\17<P^\17<¥Ëz»ì\86\1d± <}µÿºì\86O°©\9a\1d<¢Ëúºuµÿººu\14<÷ùu»uµÿººu\14<÷ùu»iµÿ:©\9a\1d<¢Ëúºiµÿ:\1d± <}µÿºì\86O°P^\17<¥Ëz»ì\86O°i´g;jó¿ºP^\17¼õùu;4¶CºP^\17¼¬Ëú:
+\8cǹ\1d± ¼\8a>ì:F¶Cº\1d± ¼\9fØ\v<x´g»\99Ëz;½u\14<\99>ìº\99Ëz;©\9a\1d<¢Ëúºiµÿ:ºu\14<÷ùu»iµÿ:\v1¨;­U\v»]:\b¼\1d\8d²;\87\10\8eº]:\b¼õùu;4¶CºP^\17¼i´g;jó¿ºP^\17¼e·û;^\87\9b\f¶;?\9c\ 5<;\9dÔº\9b\f¶;½u\14<\99>ìº\99Ëz;\9fØ\v<x´g»\99Ëz;8\11Ö;ÛV1»j´ç»ª@ã;Mдºj´ç»\1d\8d²;\87\10\8eº]:\b¼\v1¨;­U\v»]:\b¼©\9a\1d<¢Ëúºiµÿ:\19± <)|\83°iµÿ:\b×#<ÍìÀ°ì\86\1d± <}µÿºì\86O°õùu;4¶CºP^\17¼\9dËz;\14¾A±P^\17¼~µÿ:õ8V±\1d± ¼¬Ëú:
+\8cǹ\1d± ¼½u\14<\99>ìº\99Ëz;P^\17<®W[±\99Ëz;\19± <)|\83°iµÿ:©\9a\1d<¢Ëúºiµÿ:\1d\8d²;\87\10\8eº]:\b¼\9b\f¶;\14¾A±]:\b¼\9dËz;\14¾A±P^\17¼õùu;4¶CºP^\17¼?\9c\ 5<;\9dÔº\9b\f¶;Y:\b<ÍìÀ°\9b\f¶;P^\17<®W[±\99Ëz;½u\14<\99>ìº\99Ëz;ª@ã;Mдºj´ç»i´ç;p]þ°j´ç»\9b\f¶;\14¾A±]:\b¼\1d\8d²;\87\10\8eº]:\b¼ª@ã;Mдºj´ç;i´ç;p]þ°j´ç;Y:\b<ÍìÀ°\9b\f¶;?\9c\ 5<;\9dÔº\9b\f¶;?\9c\ 5<;\9dÔº\9b\f¶»Y:\b<ÍìÀ°\9b\f¶»i´ç;p]þ°j´ç»ª@ã;Mдºj´ç»\e\8d²;\84\10\8eº]:\b<\98\f¶;ëa2±]:\b<i´ç;p]þ°j´ç;ª@ã;Mдºj´ç;½u\14<\99>캠Ëz»P^\17<®W[± Ëz»Y:\b<ÍìÀ°\9b\f¶»?\9c\ 5<;\9dÔº\9b\f¶»òùu;-¶CºR^\17<\98Ëz;3C-±R^\17<\98\f¶;ëa2±]:\b<\e\8d²;\84\10\8eº]:\b\9a\1d<¢Ëúºuµÿº\19± <)|\83°uµÿºP^\17<®W[± Ëz»½u\14<\99>캠Ëz»\99Ëú:ü\8bǹ\1e± <lµÿ:RÈX±\1e± <\98Ëz;3C-±R^\17<òùu;-¶CºR^\17<\1d± <}µÿºì\86\b×#<ÍìÀ°ì\86\19± <)|\83°uµÿº©\9a\1d<¢ËúºuµÿºY:\b<ÍìÀ°\9b\f¶»>\9c\ 5<"\9dÔ:\9b\f¶»©@ã;+д:j´ç»i´ç;p]þ°j´ç»\98\f¶;ëa2±]:\b<\19\8d²;V\10\8e:]:\b<©@ã;+д:j´ç;i´ç;p]þ°j´ç;P^\17<®W[± Ëz»¼u\14<b>ì: Ëz»>\9c\ 5<"\9dÔ:\9b\f¶»Y:\b<ÍìÀ°\9b\f¶»\98Ëz;3C-±R^\17<ðùu;ÔµC:R^\17<\19\8d²;V\10\8e:]:\b<\98\f¶;ëa2±]:\b<\19± <)|\83°uµÿº§\9a\1d<\90Ëú:uµÿº¼u\14<b>ì: Ëz»P^\17<®W[± Ëz»lµÿ:RÈX±\1e± <\99Ëú:"\8bÇ9\1e± <ðùu;ÔµC:R^\17<\98Ëz;3C-±R^\17<\b×#<ÍìÀ°ì\86\e± <eµÿ:ì\86O°§\9a\1d<\90Ëú:uµÿº\19± <)|\83°uµÿº\19± <)|\83°iµÿ:§\9a\1d<\90Ëú:iµÿ:\e± <eµÿ:ì\86\b×#<ÍìÀ°ì\86\9dËz;\14¾A±P^\17¼õùu;ÓµC:P^\17¼«Ëú:2\8bÇ9\1d± ¼~µÿ:õ8V±\1d± ¼P^\17<®W[±\99Ëz;¼u\14<b>ì:\99Ëz;§\9a\1d<\90Ëú:iµÿ:\19± <)|\83°iµÿ:\9b\f¶;\14¾A±]:\b¼\1c\8d²;V\10\8e:]:\b¼õùu;ÓµC:P^\17¼\9dËz;\14¾A±P^\17¼Y:\b<ÍìÀ°\9b\f¶;>\9c\ 5<"\9dÔ:\9b\f¶;¼u\14<b>ì:\99Ëz;P^\17<®W[±\99Ëz;i´ç;p]þ°j´ç»©@ã;+д:j´ç»\1c\8d²;V\10\8e:]:\b¼\9b\f¶;\14¾A±]:\b¼i´ç;p]þ°j´ç;©@ã;+д:j´ç;>\9c\ 5<"\9dÔ:\9b\f¶;Y:\b<ÍìÀ°\9b\f¶;§\9a\1d<\90Ëú:iµÿ:·u\14<ëùu;iµÿ:M^\17<\97Ëz;ì\86\e± <eµÿ:ì\86O°õùu;ÓµC:P^\17¼g´g;9ó¿:P^\17¼\89>ì:صC:\1d± ¼«Ëú:2\8bÇ9\1d± ¼¼u\14<b>ì:\99Ëz;\9fØ\v<\´g;\99Ëz;·u\14<ëùu;iµÿ:§\9a\1d<\90Ëú:iµÿ:\1c\8d²;V\10\8e:]:\b¼    1¨;\93U\v;]:\b¼g´g;9ó¿:P^\17¼õùu;ÓµC:P^\17¼>\9c\ 5<"\9dÔ:\9b\f¶;a·û;P\87P;\9b\f¶;\9fØ\v<\´g;\99Ëz;¼u\14<b>ì:\99Ëz;©@ã;+д:j´ç»5\11Ö;ÉV1;j´ç»     1¨;\93U\v;]:\b¼\1c\8d²;V\10\8e:]:\b¼©@ã;+д:j´ç;5\11Ö;ÉV1;j´ç;a·û;P\87P;\9b\f¶;>\9c\ 5<"\9dÔ:\9b\f¶;>\9c\ 5<"\9dÔ:\9b\f¶»a·û;P\87P;\9b\f¶»5\11Ö;ÉV1;j´ç»©@ã;+д:j´ç»\19\8d²;V\10\8e:]:\b<\ 61¨;\92U\v;]:\b<5\11Ö;ÉV1;j´ç;©@ã;+д:j´ç;¼u\14<b>ì: Ëz»\9fØ\v<\´g; Ëz»a·û;P\87P;\9b\f¶»>\9c\ 5<"\9dÔ:\9b\f¶»ðùu;ÔµC:R^\17<b´g;8ó¿:R^\17<\ 61¨;\92U\v;]:\b<\19\8d²;V\10\8e:]:\b\9a\1d<\90Ëú:uµÿº·u\14<ëùu;uµÿº\9fØ\v<\´g; Ëz»¼u\14<b>ì: Ëz»\99Ëú:"\8bÇ9\1e± <x>ì:ʵC:\1e± <b´g;8ó¿:R^\17<ðùu;ÔµC:R^\17<\e± <eµÿ:ì\86O°M^\17<\97Ëz;ì\86O°·u\14<ëùu;uµÿº§\9a\1d<\90Ëú:uµÿº\ 61¨;\92U\v;]:\b<K^\97;4HJ;]:\b<ɧÀ;jº\80;j´ç;5\11Ö;ÉV1;j´ç;\9fØ\v<\´g; Ëz»i·û;\ 41¨; Ëz»ç\89â;I^\97;\9b\f¶»a·û;P\87P;\9b\f¶»b´g;8ó¿:R^\17<T\87P;\90U\v;R^\17<K^\97;4HJ;]:\b<\ 61¨;\92U\v;]:\b<·u\14<ëùu;uµÿº=\9c\ 5<\14\8d²;uµÿºi·û;\ 41¨; Ëz»\9fØ\v<\´g; Ëz»x>ì:ʵC:\1e± </\9dÔ:O\10\8e:\1e± <T\87P;\90U\v;R^\17<b´g;8ó¿:R^\17<M^\17<\97Ëz;ì\86O°Y:\b<\95\f¶;ì\86O°=\9c\ 5<\14\8d²;uµÿº·u\14<ëùu;uµÿº·u\14<ëùu;iµÿ:=\9c\ 5<\14\8d²;iµÿ:Y:\b<\95\f¶;ì\86O°M^\17<\97Ëz;ì\86O°g´g;9ó¿:P^\17¼Y\87P;\92U\v;P^\17¼=\9dÔ:Y\10\8e:\1d± ¼\89>ì:صC:\1d± ¼\9fØ\v<\´g;\99Ëz;i·û;\ 41¨;\99Ëz;=\9c\ 5<\14\8d²;iµÿ:·u\14<ëùu;iµÿ: 1¨;\93U\v;]:\b¼N^\97;7HJ;]:\b¼Y\87P;\92U\v;P^\17¼g´g;9ó¿:P^\17¼a·û;P\87P;\9b\f¶;ç\89â;I^\97;\9b\f¶;i·û;\ 41¨;\99Ëz;\9fØ\v<\´g;\99Ëz;5\11Ö;ÉV1;j´ç»É§À;jº\80;j´ç»N^\97;7HJ;]:\b¼     1¨;\93U\v;]:\b¼5\11Ö;ÉV1;j´ç;ɧÀ;jº\80;j´ç;ç\89â;I^\97;\9b\f¶;a·û;P\87P;\9b\f¶;a·û;P\87P;\9b\f¶»ç\89â;I^\97;\9b\f¶»É§À;jº\80;j´ç»5\11Ö;ÉV1;j´ç»Y\87P;\92U\v;P^\17¼ÍV1;ÂV1;P^\17¼Bд:)д:\1d± ¼=\9dÔ:Y\10\8e:\1d± ¼i·û;\ 41¨;\99Ëz;7\11Ö;0\11Ö;\99Ëz;\9e@ã;\9e@ã;iµÿ:=\9c\ 5<\14\8d²;iµÿ:N^\97;7HJ;]:\b¼lº\80;hº\80;]:\b¼ÍV1;ÂV1;P^\17¼Y\87P;\92U\v;P^\17¼ç\89â;I^\97;\9b\f¶;Á§À;§À;\9b\f¶;7\11Ö;0\11Ö;\99Ëz;i·û;\ 41¨;\99Ëz;ɧÀ;jº\80;j´ç»\a×£;\ 4×£;j´ç»lº\80;hº\80;]:\b¼N^\97;7HJ;]:\b¼É§À;jº\80;j´ç;\a×£;\ 4×£;j´ç;Á§À;§À;\9b\f¶;ç\89â;I^\97;\9b\f¶;ç\89â;I^\97;\9b\f¶»Á§À;§À;\9b\f¶»\a×£;\ 4×£;j´ç»É§À;jº\80;j´ç»K^\97;4HJ;]:\b<jº\80;fº\80;]:\b<\a×£;\ 4×£;j´ç;ɧÀ;jº\80;j´ç;i·û;\ 41¨; Ëz»7\11Ö;0\11Ö; Ëz»Á§À;§À;\9b\f¶»ç\89â;I^\97;\9b\f¶»T\87P;\90U\v;R^\17<ÊV1;ÀV1;R^\17<jº\80;fº\80;]:\b<K^\97;4HJ;]:\b<=\9c\ 5<\14\8d²;uµÿº\9e@ã;\9e@ã;uµÿº7\11Ö;0\11Ö; Ëz»i·û;\ 41¨; Ëz»/\9dÔ:O\10\8e:\1e± <7д:\1cд:\1e± <ÊV1;ÀV1;R^\17<T\87P;\90U\v;R^\17<Y:\b<\95\f¶;ì\86O°a´ç;b´ç;ì\86\9e@ã;\9e@ã;uµÿº=\9c\ 5<\14\8d²;uµÿº=\9c\ 5<\14\8d²;iµÿ:\9e@ã;\9e@ã;iµÿ:a´ç;b´ç;ì\86O°Y:\b<\95\f¶;ì\86O°7\11Ö;0\11Ö; Ëz» 1¨;b·û; Ëz»G^\97\89â;\9b\f¶»Á§À;§À;\9b\f¶»ÊV1;ÀV1;R^\17<\99U\v;J\87P;R^\17<;HJ;G^\97;]:\b<jº\80;fº\80;]:\b<\9e@ã;\9e@ã;uµÿº\12\8d²;;\9c\ 5<uµÿº     1¨;b·û; Ëz»7\11Ö;0\11Ö; Ëz»7д:\1cд:\1e± <j\10\8e:\14\9dÔ:\1e± <\99U\v;J\87P;R^\17<ÊV1;ÀV1;R^\17<a´ç;b´ç;ì\86\93\f¶;W:\b\86\12\8d²;;\9c\ 5<uµÿº\9e@ã;\9e@ã;uµÿº\9e@ã;\9e@ã;iµÿ:\12\8d²;;\9c\ 5<iµÿ:\93\f¶;W:\b\86O°a´ç;b´ç;ì\86O°ÍV1;ÂV1;P^\17¼\9bU\v;L\87P;P^\17¼s\10\8e:"\9dÔ:\1d± ¼Bд:)д:\1d± ¼7\11Ö;0\11Ö;\99Ëz;     1¨;b·û;\99Ëz;\12\8d²;;\9c\ 5<iµÿ:\9e@ã;\9e@ã;iµÿ:lº\80;hº\80;]:\b¼=HJ;I^\97;]:\b¼\9bU\v;L\87P;P^\17¼ÍV1;ÂV1;P^\17¼Á§À;§À;\9b\f¶;G^\97\89â;\9b\f¶;     1¨;b·û;\99Ëz;7\11Ö;0\11Ö;\99Ëz;\a×£;\ 4×£;j´ç»kº\80;ŧÀ;j´ç»=HJ;I^\97;]:\b¼lº\80;hº\80;]:\b¼\a×£;\ 4×£;j´ç;kº\80;ŧÀ;j´ç;G^\97\89â;\9b\f¶;Á§À;§À;\9b\f¶;Á§À;§À;\9b\f¶»G^\97\89â;\9b\f¶»kº\80;ŧÀ;j´ç»\a×£;\ 4×£;j´ç»jº\80;fº\80;]:\b<;HJ;G^\97;]:\b<kº\80;ŧÀ;j´ç;\a×£;\ 4×£;j´ç; 1¨;b·û;\99Ëz;f´g;\9bØ\v<\99Ëz;ãùu;´u\14<iµÿ:\12\8d²;;\9c\ 5<iµÿ:=HJ;I^\97;]:\b¼\99U\v;\ 21¨;]:\b¼Kó¿:Y´g;P^\17¼\9bU\v;L\87P;P^\17¼G^\97\89â;\9b\f¶;J\87P;]·û;\9b\f¶;f´g;\9bØ\v<\99Ëz;     1¨;b·û;\99Ëz;kº\80;ŧÀ;j´ç»ÊV1;2\11Ö;j´ç»\99U\v;\ 21¨;]:\b¼=HJ;I^\97;]:\b¼kº\80;ŧÀ;j´ç;ÊV1;2\11Ö;j´ç;J\87P;]·û;\9b\f¶;G^\97\89â;\9b\f¶;G^\97\89â;\9b\f¶»J\87P;]·û;\9b\f¶»ÊV1;2\11Ö;j´ç»kº\80;ŧÀ;j´ç»;HJ;G^\97;]:\b<\97U\v;\01¨;]:\b<ÊV1;2\11Ö;j´ç;kº\80;ŧÀ;j´ç;     1¨;b·û; Ëz»f´g;\9bØ\v< Ëz»J\87P;]·û;\9b\f¶»G^\97\89â;\9b\f¶»\99U\v;J\87P;R^\17<Ió¿:W´g;R^\17<\97U\v;\01¨;]:\b<;HJ;G^\97;]:\b<\12\8d²;;\9c\ 5<uµÿºãùu;´u\14<uµÿºf´g;\9bØ\v< Ëz»     1¨;b·û; Ëz»j\10\8e:\14\9dÔ:\1e± <þµC:]>ì:\1e± <Ió¿:W´g;R^\17<\99U\v;J\87P;R^\17<\93\f¶;W:\b\86\8fËz;J^\17\86O°ãùu;´u\14<uµÿº\12\8d²;;\9c\ 5<uµÿº\12\8d²;;\9c\ 5<iµÿ:ãùu;´u\14<iµÿ:\8fËz;J^\17\86\93\f¶;W:\b\86\9bU\v;L\87P;P^\17¼Kó¿:Y´g;P^\17¼
+¶C:n>ì:\1d± ¼s\10\8e:"\9dÔ:\1d± ¼Ió¿:W´g;R^\17<óµC:ãùu;R^\17<`\10\8e:\10\8d²;]:\b<\97U\v;\01¨;]:\b<ãùu;´u\14<uµÿº\80Ëú:¤\9a\1d<uµÿºw>ì:¸u\14< Ëz»f´g;\9bØ\v< Ëz»þµC:]>ì:\1e± <\8a\8bÇ9~Ëú:\1e± <óµC:ãùu;R^\17<Ió¿:W´g;R^\17<\8fËz;J^\17\86O°Uµÿ:\16± <ì\86\80Ëú:¤\9a\1d<uµÿºãùu;´u\14<uµÿºãùu;´u\14<iµÿ:\80Ëú:¤\9a\1d<iµÿ:Uµÿ:\16± <ì\86\8fËz;J^\17\86O°Kó¿:Y´g;P^\17¼õµC:æùu;P^\17¼\92\8bÇ9\8fËú:\1d± ¼
+¶C:n>ì:\1d± ¼f´g;\9bØ\v<\99Ëz;w>ì:¸u\14<\99Ëz;\80Ëú:¤\9a\1d<iµÿ:ãùu;´u\14<iµÿ:\99U\v;\ 21¨;]:\b¼c\10\8e:\13\8d²;]:\b¼õµC:æùu;P^\17¼Kó¿:Y´g;P^\17¼J\87P;]·û;\9b\f¶;\15\9dÔ:;\9c\ 5<\9b\f¶;w>ì:¸u\14<\99Ëz;f´g;\9bØ\v<\99Ëz;ÊV1;2\11Ö;j´ç».д:¢@ã;j´ç»c\10\8e:\13\8d²;]:\b¼\99U\v;\ 21¨;]:\b¼ÊV1;2\11Ö;j´ç;.д:¢@ã;j´ç;\15\9dÔ:;\9c\ 5<\9b\f¶;J\87P;]·û;\9b\f¶;J\87P;]·û;\9b\f¶»\15\9dÔ:;\9c\ 5<\9b\f¶».д:¢@ã;j´ç»ÊV1;2\11Ö;j´ç»\97U\v;\01¨;]:\b<`\10\8e:\10\8d²;]:\b<.д:¢@ã;j´ç;ÊV1;2\11Ö;j´ç;f´g;\9bØ\v< Ëz»w>ì:¸u\14< Ëz»\15\9dÔ:;\9c\ 5<\9b\f¶»J\87P;]·û;\9b\f¶»\15\9dÔ:;\9c\ 5<\9b\f¶;@\v;±T:\b<\9b\f¶;[¼.°K^\17<\99Ëz;w>ì:¸u\14<\99Ëz;.д:¢@ã;j´ç»u?Ò°a´ç;j´ç»ÑÎ\94°\90\f¶;]:\b¼c\10\8e:\13\8d²;]:\b¼.д:¢@ã;j´ç;u?Ò°a´ç;j´ç;@\v;±T:\b<\9b\f¶;\15\9dÔ:;\9c\ 5<\9b\f¶;\15\9dÔ:;\9c\ 5<\9b\f¶»@\v;±T:\b<\9b\f¶»u?Ò°a´ç;j´ç».д:¢@ã;j´ç»`\10\8e:\10\8d²;]:\b<³I©°\8e\f¶;]:\b<u?Ò°a´ç;j´ç;.д:¢@ã;j´ç;w>ì:¸u\14< Ëz»[¼.°K^\17< Ëz»@\v;±T:\b<\9b\f¶»\15\9dÔ:;\9c\ 5<\9b\f¶»óµC:ãùu;R^\17<\1d²W°\8aËz;R^\17<³I©°\8e\f¶;]:\b<`\10\8e:\10\8d²;]:\b<\80Ëú:¤\9a\1d<uµÿºÏÍ0±\13± <uµÿº[¼.°K^\17< Ëz»w>ì:¸u\14< Ëz»\8a\8bÇ9~Ëú:\1e± <\8av&¯Pµÿ:\1e± <\1d²W°\8aËz;R^\17<óµC:ãùu;R^\17<Uµÿ:\16± <ì\86O°@\v\ 1×#<ì\86O°ÏÍ0±\13± <uµÿº\80Ëú:¤\9a\1d<uµÿº\80Ëú:¤\9a\1d<iµÿ:ÏÍ0±\13± <iµÿ:@\v\ 1×#<ì\86O°Uµÿ:\16± <ì\86O°õµC:æùu;P^\17¼\1d²W°\8cËz;P^\17¼\8c\1cίaµÿ:\1d± ¼\92\8bÇ9\8fËú:\1d± ¼w>ì:¸u\14<\99Ëz;[¼.°K^\17<\99Ëz;ÏÍ0±\13± <iµÿ:\80Ëú:¤\9a\1d<iµÿ:c\10\8e:\13\8d²;]:\b¼ÑÎ\94°\90\f¶;]:\b¼\1d²W°\8cËz;P^\17¼õµC:æùu;P^\17¼\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0(¤Cº\0\0\0\80`µÄ<\1eÖ\1d»\0\0\0\80ÍfÖ<PþGº\0\0\0\80\0\0\0\0`´6¹\0\0\0\80\0\0\0\0Ðÿ\92;\0\0\0\80\0\0\0\0\83;\0\0\0\80\0\0\0\0ë\11\19<\0\0\0\80\0\0\0\0\19d<<\0\0\0\80\0\0\0\0\9d¹\0\0\0\80"í¨<\92\18\85»\0\0\0\80`µÄ<\1eÖ\1d»\0\0\0\80\0\0\0\0(¤Cº\0\0\0\80\0\0\0\0,õ×:\0\0\0\80\0\0\0\0\b\80»:\0\0\0\80\0\0\0\0\83;\0\0\0\80\0\0\0\0Ðÿ\92;\0\0\0\80\0\0\0\0\f³\r;\0\0\0\80°\80^<=Ú¢»\0\0\0\80"í¨<\92\18\85»\0\0\0\80\0\0\0\0\9d¹\0\0\0\80\0\0\0\0\80õí8\0\0\0\80\0\0\0\0\0\87\9b8\0\0\0\80\0\0\0\0\b\80»:\0\0\0\80\0\0\0\0,õ×:\0\0\0\80\0\0\0\0\ 3<\0\0\0\80\966\91;ú­-»\0\0\0\80°\80^<=Ú¢»\0\0\0\80\0\0\0\0\f³\r;\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\87\9b8\0\0\0\80\0\0\0\0\80õí8\0\0\0\80\0\0\0\0Rd\9b<\0\0\0\80\0\0\0\0@ E;\0\0\0\80\966\91;ú­-»\0\0\0\80\0\0\0\0\ 3<\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0nW¹<\0\0\0\80\0\0\0\0    ^i<\0\0\0\80\0\0\0\0@ E;\0\0\0\80\0\0\0\0Rd\9b<\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80¾Ný<\0X\ eµ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\9a[þ<À 8¸\0\0\0\80{äÿ<0\80ÿ¸\0\0\0\80½Ný¼\0Ð\rµ\0\0\0\80\99[þ¼à\1e\0\0\0\80<P\0=\98ÂF¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80B\16\0=¤Vb¹\0\0\0\80kúþ<|ÂF¹\0\0\0\80ÇÒý<\10\80ÿ¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ãGý<¢ 8¸\0\0\0\80\8aJý<\0L\ eµ\0\0\0\80<Ký<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80=Ký<\0\0\0\0\0\0\0\80BKý<\0\0\0\0\0\0\0\80CKý<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80=Ký<\0\0\0\0\0\0\0\80CKý<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80CKý¼\0\0\0\0\0\0\0\80=Ký¼\0\0\0\0\0\0\0\80BKý¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80AKý¼\0\0\0\0\0\0\0\80=Ký¼\0\0\0\0\0\0\0\80<Ký¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\8aJý¼\0h\ eµ\0\0\0\80âGý¼Ë 8¸\0\0\0\80ÆÒý¼ø\7fÿ¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80kúþ¼TÂF¹\0\0\0\80A\16\0½\Vb¹\0\0\0\80;P\0½@ÂF¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80zäÿ¼P\7fÿ¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0Ø\15£<\0\0\0\80\0\0\0\0\84<\0\0\0\80\0\0\0\0     ^i<\0\0\0\80\0\0\0\0nW¹<\0\0\0\80\0\0\0\0`´6¹\0\0\0\80ÍfÖ<PþGº\0\0\0\80¾Ný<\0X\ eµ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\19d<<\0\0\0\80\0\0\0\0ë\11\19<\0\0\0\80\0\0\0\0\84<\0\0\0\80\0\0\0\0Ø\15£<\0\0\0\80\0\0\0\0\84<\0\0\0\80\0\0\0\0Èy@;\0\0\0\80\0\0\0\0\92þ_»\0\0\0\80\0\0\0\0     ^i<\0\0\0\80ÍfÖ<PþGº\0\0\0\808\86ë<>zκ\0\0\0\80\9a[þ<À 8¸\0\0\0\80¾Ný<\0X\ eµ\0\0\0\80\0\0\0\0ë\11\19<\0\0\0\80\0\0\0\0Ê\8f\9b;\0\0\0\80\0\0\0\0Èy@;\0\0\0\80\0\0\0\0\84<\0\0\0\80`µÄ<\1eÖ\1d»\0\0\0\80çdä<×\93\94»\0\0\0\808\86ë<>zκ\0\0\0\80ÍfÖ<PþGº\0\0\0\80\0\0\0\0\83;\0\0\0\80\0\0\0\0`\1e:;\0\0\0\80\0\0\0\0Ê\8f\9b;\0\0\0\80\0\0\0\0ë\11\19<\0\0\0\80"í¨<\92\18\85»\0\0\0\80\ eþ¯<&\9dü»\0\0\0\80çdä<×\93\94»\0\0\0\80`µÄ<\1eÖ\1d»\0\0\0\80\0\0\0\0\b\80»:\0\0\0\80\0\0\0\0À­g:\0\0\0\80\0\0\0\0`\1e:;\0\0\0\80\0\0\0\0\83;\0\0\0\80°\80^<=Ú¢»\0\0\0\80>\aO<Lß!¼\0\0\0\80\ eþ¯<&\9dü»\0\0\0\80"í¨<\92\18\85»\0\0\0\80\0\0\0\0\0\87\9b8\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0À­g:\0\0\0\80\0\0\0\0\b\80»:\0\0\0\80\966\91;ú­-»\0\0\0\806­¶;\ 501¼\90V¸9>\aO<Lß!¼\0\0\0\80°\80^<=Ú¢»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\87\9b8\0\0\0\80\0\0\0\0@ E;\0\0\0\80\b¾\97:Ø2\v¼\0\0\0\806­¶;\ 501¼\90V¸9\966\91;ú­-»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0     ^i<\0\0\0\80\0\0\0\0\92þ_»\0\0\0\80\b¾\97:Ø2\v¼\0\0\0\80\0\0\0\0@ E;\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\10\8b\959\0\0\0\80\0\0\0\0À­g:\0\0\0\806­¶;\ 501¼\90V¸9a]¸;\1c\19¶¼\1eH`;\e\94\99;fΤ¼xÔ:;>\aO<Lß!¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\b¾\97:Ø2\v¼\0\0\0\80\1fan;\15n\94¼Ûþ\10;a]¸;\1c\19¶¼\1eH`;6­¶;\ 501¼\90V¸9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\92þ_»\0\0\0\80\0\0\0\0\10)$¼\0\0\0\80\1fan;\15n\94¼Ûþ\10;\b¾\97:Ø2\v¼\0\0\0\80\0\0\0\0Èy@;\0\0\0\80\0\0\0\0D"¤»\0\0\0\80\0\0\0\0\10)$¼\0\0\0\80\0\0\0\0\92þ_»\0\0\0\808\86ë<>zκ\0\0\0\80dÈð<\1f$\1c»\0\0\0\80{äÿ<0\80ÿ¸\0\0\0\80\9a[þ<À 8¸\0\0\0\80\0\0\0\0Ê\8f\9b;\0\0\0\80\0\0\0\0à2û9\0\0\0\80\0\0\0\0D"¤»\0\0\0\80\0\0\0\0Èy@;\0\0\0\80çdä<×\93\94»\0\0\0\80\ 4\9e´<ÇÐØ»\0\0\0\80dÈð<\1f$\1c»\0\0\0\808\86ë<>zκ\0\0\0\80\0\0\0\0`\1e:;\0\0\0\80\0\0\0\0H$·:\0\0\0\80\0\0\0\0à2û9\0\0\0\80\0\0\0\0Ê\8f\9b;\0\0\0\80\ eþ¯<&\9dü»\0\0\0\80þ\90=;\80tp¼\90wñ:\ 4\9e´<ÇÐØ»\0\0\0\80çdä<×\93\94»\0\0\0\80\0\0\0\0À­g:\0\0\0\80\0\0\0\0\10\8b\959\0\0\0\80\0\0\0\0H$·:\0\0\0\80\0\0\0\0`\1e:;\0\0\0\80>\aO<Lß!¼\0\0\0\80\e\94\99;fΤ¼xÔ:;þ\90=;\80tp¼\90wñ:\ eþ¯<&\9dü»\0\0\0\80\0\0\0\0à2û9\0\0\0\80\0\0\0\0ó4.»\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80\0\0\0\0D"¤»\0\0\0\80\ 4\9e´<ÇÐØ»\0\0\0\80\17oF<ôE\ 5¼\0\0\0\80pÛâ<}¦B»\0\0\0\80dÈð<\1f$\1c»\0\0\0\80\0\0\0\0H$·:\0\0\0\80\0\0\0\0Àm\119\0\0\0\80\0\0\0\0ó4.»\0\0\0\80\0\0\0\0à2û9\0\0\0\80þ\90=;\80tp¼\90wñ:¨\88/;³\8a\8b¼ì\89Õ:\17oF<ôE\ 5¼\0\0\0\80\ 4\9e´<ÇÐØ»\0\0\0\80\0\0\0\0\10\8b\959\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0Àm\119\0\0\0\80\0\0\0\0H$·:\0\0\0\80\e\94\99;fΤ¼xÔ:;¼\ 5þ:\16
+­¼°\82\9a\88/;³\8a\8b¼ì\89Õ:þ\90=;\80tp¼\90wñ:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\10\8b\959\0\0\0\80a]¸;\1c\19¶¼\1eH`;à` :èüµ¼$\1aC:¼\ 5þ:\16
+­¼°\82\9a:\e\94\99;fΤ¼xÔ:;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\1fan;\15n\94¼Ûþ\10\93,;\9e\11±¼0ñÑ:à` :èüµ¼$\1aC:a]¸;\1c\19¶¼\1eH`;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\10)$¼\0\0\0\80X×¾:\98\88\v)h:Ê\93,;\9e\11±¼0ñÑ:\1fan;\15n\94¼Ûþ\10;\0\0\0\0D"¤»\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80X×¾:\98\88\v)h:\0\0\0\0\10)$¼\0\0\0\80dÈð<\1f$\1c»\0\0\0\80pÛâ<}¦B»\0\0\0\80<P\0=\98ÂF¹\0\0\0\80{äÿ<0\80ÿ¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Ê\93,;\9e\11±¼0ñÑ:\0:ø7\80¿¨¼Àü\967\0\0\0\0ù?»¼\0\0\0\80à` :èüµ¼$\1aC:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80X×¾:\98\88\v)h:H\9cQ:\8f\1f\83¼Jþþ9\0:ø7\80¿¨¼Àü\96\93,;\9e\11±¼0ñÑ:\0\0\0\0h\19ý»\0\0\0\80\0\0\0\0Åa\ e¼\0\0\0\80H\9cQ:\8f\1f\83¼Jþþ9X×¾:\98\88\v)h:pÛâ<}¦B»\0\0\0\80\1f\8aÌ<ý´P»\0\0\0\80B\16\0=¤Vb¹\0\0\0\80<P\0=\98ÂF¹\0\0\0\80\0\0\0\0ó4.»\0\0\0\80\0\0\0\0     µP»\0\0\0\80\0\0\0\0Åa\ e¼\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80\17oF<ôE\ 5¼\0\0\0\80Ð\12o;üE0¼\\1c\97:\1f\8aÌ<ý´P»\0\0\0\80pÛâ<}¦B»\0\0\0\80\0\0\0\0Àm\119\0\0\0\80\0\0\0\0\80Vb¹\0\0\0\80\0\0\0\0     µP»\0\0\0\80\0\0\0\0ó4.»\0\0\0\80¨\88/;³\8a\8b¼ì\89Õ:ÜÒË:\9dà\89¼ ôw:Ð\12o;üE0¼\\1c\97:\17oF<ôE\ 5¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\80Vb¹\0\0\0\80\0\0\0\0Àm\119\0\0\0\80¼\ 5þ:\16
+­¼°\82\9a:\0X!6G\81¨¼\0@Ä5ÜÒË:\9dà\89¼ ôw:¨\88/;³\8a\8b¼ì\89Õ:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80à` :èüµ¼$\1aC:\0\0\0\0ù?»¼\0\0\0\80\0X!6G\81¨¼\0@Ä5¼\ 5þ:\16
+­¼°\82\9a\12o;üE0¼\\1c\97:\b8­;D\89(¼¼9\9d:3À¹<~¦B»\0\0\0\80\1f\8aÌ<ý´P»\0\0\0\80\0\0\0\0\80Vb¹\0\0\0\80\0\0\0\0\0Þò¸\0\0\0\80\0\0\0\0M¯/»\0\0\0\80\0\0\0\0 µP»\0\0\0\80ÜÒË:\9dà\89¼ ôw:\80\13k:¢9w¼\88ü\ e:\b8­;D\89(¼¼9\9d\12o;üE0¼\\1c\97:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0Þò¸\0\0\0\80\0\0\0\0\80Vb¹\0\0\0\80\0X!6G\81¨¼\0@Ä5\0\0\0\0\9b¼\0\0\0\80\80\13k:¢9w¼\88ü\ e:ÜÒË:\9dà\89¼ ôw:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0ù?»¼\0\0\0\80\0\0\0\0e\f«¼\0\0\0\80\0\0\0\0\9b¼\0\0\0\80\0X!6G\81¨¼\0@Ä5\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0:ø7\80¿¨¼Àü\967\0\0\0\0\8b\86\99¼\0\0\0\80\0\0\0\0e\f«¼\0\0\0\80\0\0\0\0ù?»¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80H\9cQ:\8f\1f\83¼Jþþ9Àâ\ 29\10»b¼F9\9f8\0\0\0\0\8b\86\99¼\0\0\0\80\0:ø7\80¿¨¼Àü\967\0\0\0\0Åa\ e¼\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80Àâ\ 29\10»b¼F9\9f8H\9cQ:\8f\1f\83¼Jþþ9\1f\8aÌ<ý´P»\0\0\0\803À¹<~¦B»\0\0\0\80kúþ<|ÂF¹\0\0\0\80B\16\0=¤Vb¹\0\0\0\80\0\0\0\0     µP»\0\0\0\80\0\0\0\0M¯/»\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80\0\0\0\0Åa\ e¼\0\0\0\80\0\0\0\0\8b\86\99¼\0\0\0\80\0°-6½Ýg¼\0@Ó5\0\0\0\0¨Ë\83¼\0\0\0\80\0\0\0\0e\f«¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Àâ\ 29\10»b¼F9\9f8\0\0\0\0\v)$¼\0\0\0\80\0°-6½Ýg¼\0@Ó5\0\0\0\0\8b\86\99¼\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80\0\0\0\0Ô\11¬»\0\0\0\80\0\0\0\0\v)$¼\0\0\0\80Àâ\ 29\10»b¼F9\9f83À¹<~¦B»\0\0\0\80\7f´¯<\1e$\1c»\0\0\0\80ÇÒý<\10\80ÿ¸\0\0\0\80kúþ<|ÂF¹\0\0\0\80\0\0\0\0M¯/»\0\0\0\80\0\0\0\0»@¿º\0\0\0\80\0\0\0\0Ô\11¬»\0\0\0\80\0\0\0\0h\19ý»\0\0\0\80\b8­;D\89(¼¼9\9d\10±;õì   ¼0\9c\83:\7f´¯<\1e$\1c»\0\0\0\803À¹<~¦B»\0\0\0\80\0\0\0\0\0Þò¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0»@¿º\0\0\0\80\0\0\0\0M¯/»\0\0\0\80\80\13k:¢9w¼\88ü\ e:X\9e<:÷)G¼àtå9¯\10±;õì     ¼0\9c\83:\b8­;D\89(¼¼9\9d:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0Þò¸\0\0\0\80\0\0\0\0\9b¼\0\0\0\80\0Æ\848^ðv¼\80\85!8X\9e<:÷)G¼àtå9\80\13k:¢9w¼\88ü\ e:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0e\f«¼\0\0\0\80\0\0\0\0¨Ë\83¼\0\0\0\80\0Æ\848^ðv¼\80\85!8\0\0\0\0\9b¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0J\f\93¹\0\0\0\80\0\0\0\0»@¿º\0\0\0\80X\9e<:÷)G¼àtå90²Ô9\9d\8f\ 5¼ _\819²ÿ\9c\a¼»\18é/:¯\10±;õì     ¼0\9c\83:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0Æ\848^ðv¼\80\85!8\0C´9%\ 5(¼@J[90²Ô9\9d\8f\ 5¼ _\819X\9e<:÷)G¼àtå9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0¨Ë\83¼\0\0\0\80\0\93\ 69~%)¼ ¶£8\0C´9%\ 5(¼@J[9\0Æ\848^ðv¼\80\85!8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0°-6½Ýg¼\0@Ó5\0ø\986UI\v¼\0\12:6\0\93\ 69~%)¼ ¶£8\0\0\0\0¨Ë\83¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\v)$¼\0\0\0\80\0\0\0\0Ô\1c´»\0\0\0\80\0ø\986UI\v¼\0\12:6\0°-6½Ýg¼\0@Ó5\0\0\0\0Ô\11¬»\0\0\0\80\0\0\0\0\1f\92\19»\0\0\0\80\0\0\0\0Ô\1c´»\0\0\0\80\0\0\0\0\v)$¼\0\0\0\80\7f´¯<\1e$\1c»\0\0\0\80²ì­<4zκ\0\0\0\80ãGý<¢ 8¸\0\0\0\80ÇÒý<\10\80ÿ¸\0\0\0\80\0\0\0\0»@¿º\0\0\0\80\0\0\0\0J\f\93¹\0\0\0\80\0\0\0\0\1f\92\19»\0\0\0\80\0\0\0\0Ô\11¬»\0\0\0\80¯\10±;õì     ¼0\9c\83:²ÿ\9c\a¼»\18é/:²ì­<4zκ\0\0\0\80\7f´¯<\1e$\1c»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0Ô\1c´»\0\0\0\80\0\0\0\0éoߺ\0\0\0\80\0\0\0\0\90\92\0\0\0\80\0ø\986UI\v¼\0\12:6\0\0\0\0\1f\92\19»\0\0\0\80\0\0\0\0\84\95 ¹\0\0\0\80\0\0\0\0éoߺ\0\0\0\80\0\0\0\0Ô\1c´»\0\0\0\80²ì­<4zκ\0\0\0\80]¬±<6þGº\0\0\0\80\8aJý<\0L\ eµ\0\0\0\80ãGý<¢ 8¸\0\0\0\80\0\0\0\0J\f\93¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\84\95 ¹\0\0\0\80\0\0\0\0\1f\92\19»\0\0\0\80²ÿ\9c\a¼»\18é/:\ e/\ f\ e\0<:8]¬±<6þGº\0\0\0\80²ì­<4zκ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0J\f\93¹\0\0\0\800²Ô9\9d\8f\ 5¼ _\819hn3:KÐ\8b»\80\9dï8\ e/\ f\ e\0<:8²ÿ\9c\a¼»\18é/:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0C´9%\ 5(¼@J[9\0øå8)Ʀ»\80á\8b8hn3:KÐ\8b»\80\9dï80²Ô9\9d\8f\ 5¼ _\819\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\93\ 69~%)¼ ¶£8\0\88m7\ e¡\9b»\0{\107\0øå8)Ʀ»\80á\8b8\0C´9%\ 5(¼@J[9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0ø\986UI\v¼\0\12:6\0\0\0\0\90\92\0\0\0\80\0\88m7\ e¡\9b»\0{\107\0\93\ 69~%)¼ ¶£8hn3:KÐ\8b»\80\9dï8\86?v;9Á\r»\0z\0:}\e<<\104Gº\0\0\0\80\ e/\ f\ e\0<:8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0øå8)Ʀ»\80á\8b8\0À/5\8cË·º\0À©4\86?v;9Á\r»\0z\0:hn3:KÐ\8b»\80\9dï8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\88m7\ e¡\9b»\0{\107\0\0\0\0\88º\0\0\0\80\0À/5\8cË·º\0À©4\0øå8)Ʀ»\80á\8b8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\90\92\0\0\0\80\0\0\0\088á¹\0\0\0\80\0\0\0\0\88º\0\0\0\80\0\88m7\ e¡\9b»\0{\107\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0éoߺ\0\0\0\80\0\0\0\0\0ËK·\0\0\0\80\0\0\0\088á¹\0\0\0\80\0\0\0\0\90\92\0\0\0\80\0\0\0\0\84\95 ¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0ËK·\0\0\0\80\0\0\0\0éoߺ\0\0\0\80]¬±<6þGº\0\0\0\80v\9c·<h´6¹\0\0\0\80<Ký<\0\0\0\0\0\0\0\80\8aJý<\0L\ eµ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\84\95 ¹\0\0\0\80\ e/\ f\ e\0<:8}\e<<\104Gº\0\0\0\80v\9c·<h´6¹\0\0\0\80]¬±<6þGº\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0ËK·\0\0\0\80\07³8\0\97ø`\ 4Z8@èk9\10»\80¹Ð}\ f9\0\0\0\088á¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\07³8\0\97ø`\ 4Z8\0\0\0\0\0ËK·\0\0\0\80v\9c·<h´6¹\0\0\0\80Oaº<\0\0\0\0\0\0\0\80=Ký<\0\0\0\0\0\0\0\80<Ký<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80}\e<<\104Gº\0\0\0\80ªhU<\0ãv·\0\0\0\80Oaº<\0\0\0\0\0\0\0\80v\9c·<h´6¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\86?v;9Á\r»\0z\0:O×Ð;\18¢îº\94Û\82:ªhU<\0ãv·\0\0\0\80}\e<<\104Gº\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0À/5\8cË·º\0À©4\b\v#:0¯¬¹`¿>9O×Ð;\18¢îº\94Û\82:\86?v;9Á\r»\0z\0:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\88º\0\0\0\80\90 \899\10¨\95¹ Ñ&9\b\v#:0¯¬¹`¿>9\0À/5\8cË·º\0À©4\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\088á¹\0\0\0\80@èk9\10»\80¹Ð}\ f9\90 \899\10¨\95¹ Ñ&9\0\0\0\0\88º\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\b\v#:0¯¬¹`¿>9\ fÛ\ f;(Ê\ 5»h!\95:ãØý;\1c¦S»Ðêë:O×Ð;\18¢îº\94Û\82:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90 \899\10¨\95¹ Ñ&9^ó ;$\8e\16»\86ѧ:\ fÛ\ f;(Ê\ 5»h!\95:\b\v#:0¯¬¹`¿>9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80@èk9\10»\80¹Ð}\ f9pÕ\r;\fË\1a»Ò\8a¬:^ó     ;$\8e\16»\86ѧ:\90 \899\10¨\95¹ Ñ&9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\07³8\0\97ø`\ 4Z8\80\90Ü:°·ðºÖ(\86:pÕ\r;\fË\1a»Ò\8a¬:@èk9\10»\80¹Ð}\ f9\0\0\0\0\0\0\0\0\0\0\0\80Häh:Ð+~ºZ¨\r:\80\90Ü:°·ðºÖ(\86:\07³8\0\97ø`\ 4Z8Oaº<\0\0\0\0\0\0\0\80Oaº<\0\0\0\0\0\0\0\80BKý<\0\0\0\0\0\0\0\80=Ký<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80à\8bC9ÀiU¹`âí8Häh:Ð+~ºZ¨\r:\0\0\0\0\0\0\0\0\0\0\0\80ªhU<\0ãv·\0\0\0\80©\rV<\0\0\0\0\0\0\0\80Oaº<\0\0\0\0\0\0\0\80Oaº<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80à\8bC9ÀiU¹`âí8\0\0\0\0\0\0\0\0\0\0\0\80O×Ð;\18¢îº\94Û\82:ãØý;\1c¦S»Ðêë:©\rV<\0\0\0\0\0\0\0\80ªhU<\0ãv·\0\0\0\80Häh:Ð+~ºZ¨\r:]JP;pRc»;cý:?£\9b;¼Û©»»U=;\80\90Ü:°·ðºÖ(\86:Oaº<\0\0\0\0\0\0\0\80Raº<\0\0\0\0\0\0\0\80CKý<\0\0\0\0\0\0\0\80BKý<\0\0\0\0\0\0\0\80à\8bC9ÀiU¹`âí8\80\ 1»:´\17̺\9c~c:]JP;pRc»;cý:Häh:Ð+~ºZ¨\r\rV<\0\0\0\0\0\0\0\80­\rV<\0\0\0\0\0\0\0\80Raº<\0\0\0\0\0\0\0\80Oaº<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 ¹Y9À\9dm¹`n\ 49\80\ 1»:´\17̺\9c~c:à\8bC9ÀiU¹`âí8ãØý;\1c¦S»Ðêë:\fhh:\b\83\8b»:\82\e\rV<\0\0\0\0\0\0\0\80©\rV<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 ¹Y9À\9dm¹`n\ 49\0\0\0\0\0\0\0\0\0\0\0\80\ fÛ\ f;(Ê\ 5»h!\95:4\14\97;'G\99»uÚ*;\fhh:\b\83\8b»:\82\e;ãØý;\1c¦S»Ðêë:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80^ó ;$\8e\16»\86ѧ: \83©;%\0¹»£6N;4\14\97;'G\99»uÚ*;\ fÛ\ f;(Ê\ 5»h!\95:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\r;\fË\1a»Ò\8a¬:÷Ö´;ô\Å»Rþ[; \83©;%\0¹»£6N;^ó     ;$\8e\16»\86ѧ:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\80\90Ü:°·ðºÖ(\86:?£\9b;¼Û©»»U=;÷Ö´;ô\Å»Rþ[;pÕ\r;\fË\1a»Ò\8a¬:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 \83©;%\0¹»£6N;>%\r
+\1a¼z´«;â\bê;<Ðó»\8câ\87;4\14\97;'G\99»uÚ*;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80÷Ö´;ô\Å»Rþ[;Ìe\19<çi'¼!\9cº;>%\r
+\1a¼z´«; \83©;%\0¹»£6N;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\9b;¼Û©»»U=;\1a°\b<X-\15¼FH¦;Ìe\19<çi'¼!\9cº;÷Ö´;ô\Å»Rþ[;]JP;pRc»;cý:óHÄ;:8Ö»bÈn;\1a°\b<X-\15¼FH¦;?£\9b;¼Û©»»U=;Raº<\0\0\0\0\0\0\0\80Raº<\0\0\0\0\0\0\0\80=Ký<\0\0\0\0\0\0\0\80CKý<\0\0\0\0\0\0\0\80\80\ 1»:´\17̺\9c~c:3\88Q;T­d»âåþ:óHÄ;:8Ö»bÈn;]JP;pRc»;cý:­\rV<\0\0\0\0\0\0\0\80²\rV<\0\0\0\0\0\0\0\80Raº<\0\0\0\0\0\0\0\80Raº<\0\0\0\0\0\0\0\80 ¹Y9À\9dm¹`n\ 49 Är:Py\84ºè©\13:3\88Q;T­d»âåþ:\80\ 1»:´\17̺\9c~c:\fhh:\b\83\8b»:\82\e;\84l=:&`\91»~\v";²\rV<\0\0\0\0\0\0\0\80­\rV<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 Är:Py\84ºè©\13: ¹Y9À\9dm¹`n\ 494\14\97;'G\99»uÚ*;â\bê;<Ðó»\8câ\87;\84l=:&`\91»~\v";\fhh:\b\83\8b»:\82\e;Raº<\0\0\0\0\0\0\0\80Waº<\0\0\0\0\0\0\0\80CKý<\0\0\0\0\0\0\0\80=Ký<\0\0\0\0\0\0\0\803\88Q;T­d»âåþ:þ\19\9a;\8e.¨»Ww;;-\1f\b<-\8f\14¼ø\97¥;óHÄ;:8Ö»bÈn;²\rV<\0\0\0\0\0\0\0\80²\rV<\0\0\0\0\0\0\0\80Waº<\0\0\0\0\0\0\0\80Raº<\0\0\0\0\0\0\0\80 Är:Py\84ºè©\13:\88¥×:°Yëº\f+\83\19\9a;\8e.¨»Ww;;3\88Q;T­d»âåþ:\84l=:&`\91»~\v";¬ö·:D\fr»¦æ\ 6\rV<\0\0\0\0\0\0\0\80²\rV<\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80°\87\9e\ 3­¸\0Ú@8\88¥×:°Yëº\f+\83: Är:Py\84ºè©\13\bê;<Ðó»\8câ\87;à]\13<q\a\e¼$ά;¬ö·:D\fr»¦æ\ 6;\84l=:&`\91»~\v";\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80°\87\9e\ 3­¸\0Ú@8\0\0\0\0\0\0\0\0\0\0\0\80>%\r
+\1a¼z´«;Zó:<J\bL¼lmã;à]\13<q\a\e¼$ά;â\bê;<Ðó»\8câ\87;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Ìe\19<çi'¼!\9cº;©øM<\81Ê`¼û\90ú;Zó:<J\bL¼lmã;>%\r
+\1a¼z´«;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\1a°\b<X-\15¼FH¦;>\869<ÔyJ¼C±á;©øM<\81Ê`¼û\90ú;Ìe\19<çi'¼!\9cº;óHÄ;:8Ö»bÈn;-\1f\b<-\8f\14¼ø\97¥;>\869<ÔyJ¼C±á;\1a°\b<X-\15¼FH¦;Zó:<J\bL¼lmã;\0\0\0\0@é_¼æ\95ù;\0\0\0\0nÂ$¼Á¦·;à]\13<q\a\e¼$ά;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80©øM<\81Ê`¼û\90ú;\0\0\0\0îÙx¼V±
+<\0\0\0\0@é_¼æ\95ù;Zó:<J\bL¼lmã;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80>\869<ÔyJ¼C±á;\0\0\0\0<é_¼â\95ù;\0\0\0\0îÙx¼V±
+<©øM<\81Ê`¼û\90ú;-\1f\b<-\8f\14¼ø\97¥;\0\0\0\0pÂ$¼Â¦·;\0\0\0\0<é_¼â\95ù;>\869<ÔyJ¼C±á;Waº<\0\0\0\0\0\0\0\80\0\0\0\0\80f\16¹\0¥§8\0\0\0\0\0\0\0\0\0\0\0\80CKý<\0\0\0\0\0\0\0\80þ\19\9a;\8e.¨»Ww;;\0\0\0\0\09½»iëR;\0\0\0\0pÂ$¼Â¦·;-\1f\b<-\8f\14¼ø\97¥;²\rV<\0\0\0\0\0\0\0\80\0\0\0\0\f¯
+»ô\95\9a:\0\0\0\0\80f\16¹\0¥§8Waº<\0\0\0\0\0\0\0\80\88¥×:°Yëº\f+\83:\0\0\0\0ü®
+»ä\95\9a:\0\0\0\0\09½»iëR;þ\19\9a;\8e.¨»Ww;;¬ö·:D\fr»¦æ\ 6;\0\0\0\0\09½»iëR;\0\0\0\0\f¯
+»ô\95\9a\rV<\0\0\0\0\0\0\0\80°\87\9e\ 3­¸\0Ú@8\0\0\0\0@f\16¹\0¥§8\0\0\0\0ü®
+»ä\95\9a:\88¥×:°Yëº\f+\83:à]\13<q\a\e¼$ά;\0\0\0\0nÂ$¼Á¦·;\0\0\0\0\09½»iëR;¬ö·:D\fr»¦æ\ 6;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0@f\16¹\0¥§8°\87\9e\ 3­¸\0Ú@8\0\0\0\0\09½»iëR;ü\19\9a»\8e.¨»Ww;;/\1f\b¼.\8f\14¼ø\97¥;\0\0\0\0pÂ$¼Â¦·;\0\0\0\0\f¯
+»ô\95\9a\r\0\0\0\0\0\0\0\80Vaº¼\0\0\0\0\0\0\0\80\0\0\0\0\80f\16¹\0¥§8\0\0\0\0ü®
+»ä\95\9a:\96¥×º¸Yëº\f+\83\19\9a»\8e.¨»Ww;;\0\0\0\0\09½»iëR;\0\0\0\0\09½»iëR;±ö·ºH\fr»¦æ\ 6\r\0\0\0\0\0\0\0\80\0\0\0\0\f¯
+»ô\95\9a:\0\0\0\0@f\16¹\0¥§8\0\88\9e¸@\ 4­¸\0Ú@8\96¥×º¸Yëº\f+\83:\0\0\0\0ü®
+»ä\95\9a:\0\0\0\0nÂ$¼Á¦·;â]\13¼r\a\e¼$ά;±ö·ºH\fr»¦æ\ 6;\0\0\0\0\09½»iëR;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\88\9e¸@\ 4­¸\0Ú@8\0\0\0\0@f\16¹\0¥§8\0\0\0\0@é_¼æ\95ù;Yó:¼J\bL¼lmã;â]\13¼r\a\e¼$ά;\0\0\0\0nÂ$¼Á¦·;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0îÙx¼V±
+<ªøM¼\82Ê`¼û\90ú;Yó:¼J\bL¼lmã;\0\0\0\0@é_¼æ\95ù;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0<é_¼â\95ù;B\869¼ÕyJ¼C±á;ªøM¼\82Ê`¼û\90ú;\0\0\0\0îÙx¼V±
+<\0\0\0\0pÂ$¼Â¦·;/\1f\b¼.\8f\14¼ø\97¥;B\869¼ÕyJ¼C±á;\0\0\0\0<é_¼â\95ù;\0\0\0\0\80f\16¹\0¥§8Vaº¼\0\0\0\0\0\0\0\80CKý¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ªøM¼\82Ê`¼û\90ú;Íe\19¼éi'¼!\9cº;<%\r¼Á
+\1a¼z´«;Yó:¼J\bL¼lmã;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80B\869¼ÕyJ¼C±á;\1c°\b¼Z-\15¼FH¦;Íe\19¼éi'¼!\9cº;ªøM¼\82Ê`¼û\90ú;/\1f\b¼.\8f\14¼ø\97¥;öHÄ»>8Ö»bÈn;\1c°\b¼Z-\15¼FH¦;B\869¼ÕyJ¼C±á;Vaº¼\0\0\0\0\0\0\0\80Qaº¼\0\0\0\0\0\0\0\80=Ký¼\0\0\0\0\0\0\0\80CKý¼\0\0\0\0\0\0\0\80ü\19\9a»\8e.¨»Ww;;,\88Q»T­d»âåþ:öHÄ»>8Ö»bÈn;/\1f\b¼.\8f\14¼ø\97¥;²\r\0\0\0\0\0\0\0\80±\r\0\0\0\0\0\0\0\80Qaº¼\0\0\0\0\0\0\0\80Vaº¼\0\0\0\0\0\0\0\80\96¥×º¸Yëº\f+\83:0Ärºly\84ºè©\13:,\88Q»T­d»âåþ:ü\19\9a»\8e.¨»Ww;;±ö·ºH\fr»¦æ\ 6;\8cl=º(`\91»~\v";±\r\0\0\0\0\0\0\0\80²\r\0\0\0\0\0\0\0\80\0\88\9e¸@\ 4­¸\0Ú@8\0\0\0\0\0\0\0\0\0\0\0\800Ärºly\84ºè©\13:\96¥×º¸Yëº\f+\83:â]\13¼r\a\e¼$ά;ä\bê»CÐó»\8câ\87;\8cl=º(`\91»~\v";±ö·ºH\fr»¦æ\ 6;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\88\9e¸@\ 4­¸\0Ú@8Yó:¼J\bL¼lmã;<%\r¼Á
+\1a¼z´«;ä\bê»CÐó»\8câ\87;â]\13¼r\a\e¼$ά;±\r\0\0\0\0\0\0\0\80«\r\0\0\0\0\0\0\0\80Qaº¼\0\0\0\0\0\0\0\80Qaº¼\0\0\0\0\0\0\0\800Ärºly\84ºè©\13:\0¹Y¹ \9em¹`n\ 49p\ 1»º¸\17̺\9c~c:,\88Q»T­d»âåþ:\8cl=º(`\91»~\v";\ 4hhº
+\83\8b»:\82\e\r\0\0\0\0\0\0\0\80±\r\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0¹Y¹ \9em¹`n\ 490Ärºly\84ºè©\13\bê»CÐó»\8câ\87;3\14\97».G\99»uÚ*;\ 4hhº
+\83\8b»:\82\e;\8cl=º(`\91»~\v";\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80<%\r¼Á
+\1a¼z´«;\1c\83©»&\0¹»£6N;3\14\97».G\99»uÚ*;ä\bê»CÐó»\8câ\87;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Íe\19¼éi'¼!\9cº;øÖ´»ú\Å»Rþ[;\1c\83©»&\0¹»£6N;<%\r¼Á
+\1a¼z´«;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\1c°\b¼Z-\15¼FH¦;A£\9b»ÂÛ©»»U=;øÖ´»ú\Å»Rþ[;Íe\19¼éi'¼!\9cº;öHÄ»>8Ö»bÈn;_JP»|Rc»;cý:A£\9b»ÂÛ©»»U=;\1c°\b¼Z-\15¼FH¦;Qaº¼\0\0\0\0\0\0\0\80Qaº¼\0\0\0\0\0\0\0\80BKý¼\0\0\0\0\0\0\0\80=Ký¼\0\0\0\0\0\0\0\80,\88Q»T­d»âåþ:p\ 1»º¸\17̺\9c~c:_JP»|Rc»;cý:öHÄ»>8Ö»bÈn;øÖ´»ú\Å»Rþ[;lÕ\r»\18Ë\1a»Ò\8a¬:Tó       »(\8e\16»\86ѧ:\1c\83©»&\0¹»£6N;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\9b»ÂÛ©»»U=;\84\90ܺȷðºÖ(\86:lÕ\r»\18Ë\1a»Ò\8a¬:øÖ´»ú\Å»Rþ[;_JP»|Rc»;cý:8ähº\0,~ºZ¨\r:\84\90ܺȷðºÖ(\86:A£\9b»ÂÛ©»»U=;Qaº¼\0\0\0\0\0\0\0\80Paº¼\0\0\0\0\0\0\0\80AKý¼\0\0\0\0\0\0\0\80BKý¼\0\0\0\0\0\0\0\80p\ 1»º¸\17̺\9c~c:@\8b\0jU¹`âí88ähº\0,~ºZ¨\r:_JP»|Rc»;cý:«\r\0\0\0\0\0\0\0\80§\r\0\0\0\0\0\0\0\80Paº¼\0\0\0\0\0\0\0\80Qaº¼\0\0\0\0\0\0\0\80\0¹Y¹ \9em¹`n\ 49\0\0\0\0\0\0\0\0\0\0\0\80@\8b\0jU¹`âí8p\ 1»º¸\17̺\9c~c:\ 4hhº
+\83\8b»:\82\e;äØý»"¦S»Ðêë:§\r\0\0\0\0\0\0\0\80«\r\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0¹Y¹ \9em¹`n\ 493\14\97».G\99»uÚ*;\vÛ\ f»:Ê\ 5»h!\95:äØý»"¦S»Ðêë:\ 4hhº
+\83\8b»:\82\e;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\1c\83©»&\0¹»£6N;Tó  »(\8e\16»\86ѧ:\vÛ\ f»:Ê\ 5»h!\95:3\14\97».G\99»uÚ*;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80@\8b\0jU¹`âí8äØý»"¦S»Ðêë:K×л$¢îº\94Û\82:¨hU¼\0åv·\0\0\0\80§\r\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\vÛ\ f»:Ê\ 5»h!\95
+#º°¯¬¹`¿>9K×л$¢îº\94Û\82:äØý»"¦S»Ðêë:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Tó   »(\8e\16»\86ѧ:P \89¹\10¨\95¹ Ñ&9à
+#º°¯¬¹`¿>9\vÛ\ f»:Ê\ 5»h!\95:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\r»\18Ë\1a»Ò\8a¬:Àçk¹\90»\80¹Ð}\ f9P \89¹\10¨\95¹ Ñ&9Tó   »(\8e\16»\86ѧ:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\84\90ܺȷðºÖ(\86:\806³¸À\98ø`\ 4Z8Àçk¹\90»\80¹Ð}\ f9lÕ\r»\18Ë\1a»Ò\8a¬:8ähº\0,~ºZ¨\r:\0\0\0\0\0\0\0\0\0\0\0\80\806³¸À\98ø`\ 4Z8\84\90ܺȷðºÖ(\86:Paº¼\0\0\0\0\0\0\0\80Naº¼\0\0\0\0\0\0\0\80=Ký¼\0\0\0\0\0\0\0\80AKý¼\0\0\0\0\0\0\0\80@\8b\0jU¹`âí8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\808ähº\0,~ºZ¨\r\r\0\0\0\0\0\0\0\80¨hU¼\0åv·\0\0\0\80Naº¼\0\0\0\0\0\0\0\80Paº¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\806³¸À\98ø`\ 4Z8\0\0\0\0\0ÙK·\0\0\0\80\0\0\0\0¸8á¹\0\0\0\80Àçk¹\90»\80¹Ð}\ f9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0ÙK·\0\0\0\80\806³¸À\98ø`\ 4Z8Naº¼\0\0\0\0\0\0\0\80t\9c·¼Ð´6¹\0\0\0\80<Ký¼\0\0\0\0\0\0\0\80=Ký¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80¨hU¼\0åv·\0\0\0\80z\e\1c4Gº\0\0\0\80t\9c·¼Ð´6¹\0\0\0\80Naº¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80K×л$¢îº\94Û\82:~?v»?Á\r»\0z\0:z\e\1c4Gº\0\0\0\80¨hU¼\0åv·\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80à
+#º°¯¬¹`¿>9\0à.µ¬Ë·º\0À©4~?v»?Á\r»\0z\0:K×л$¢îº\94Û\82:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\89¹\10¨\95¹ Ñ&9\0\0\0\0\88º\0\0\0\80\0à.µ¬Ë·º\0À©4à
+#º°¯¬¹`¿>9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Àçk¹\90»\80¹Ð}\ f9\0\0\0\0¸8á¹\0\0\0\80\0\0\0\0\88º\0\0\0\80\89¹\10¨\95¹ Ñ&9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0à.µ¬Ë·º\0À©4\80õå¸1Ʀ»\80á\8b8Hn3ºNÐ\8b»\80\9dï8~?v»?Á\r»\0z\0:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\88º\0\0\0\80\0\80\ e¡\9b»\0{\107\80õå¸1Ʀ»\80á\8b8\0à.µ¬Ë·º\0À©4\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0¸8á¹\0\0\0\80\0\0\0\0\9f\92\0\0\0\80\0\80\ e¡\9b»\0{\107\0\0\0\0\88º\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0ÙK·\0\0\0\80\0\0\0\0\ 3pߺ\0\0\0\80\0\0\0\0\9f\92\0\0\0\80\0\0\0\0¸8á¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\96 ¹\0\0\0\80\0\0\0\0\ 3pߺ\0\0\0\80\0\0\0\0\0ÙK·\0\0\0\80t\9c·¼Ð´6¹\0\0\0\80\¬±¼HþGº\0\0\0\80\8aJý¼\0h\ eµ\0\0\0\80<Ký¼\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\96 ¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80z\e\1c4Gº\0\0\0\80\v/\ f¼º\ e\0<:8\¬±¼HþGº\0\0\0\80t\9c·¼Ð´6¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80~?v»?Á\r»\0z\0:Hn3ºNÐ\8b»\80\9dï8\v/\ f¼º\ e\0<:8z\e\1c4Gº\0\0\0\80\0\0\0\0\0\96 ¹\0\0\0\80\0\0\0\0,\92\19»\0\0\0\80\0\0\0\0Ù\1c´»\0\0\0\80\0\0\0\0\ 3pߺ\0\0\0\80\¬±¼HþGº\0\0\0\80±ì­¼7zκ\0\0\0\80âGý¼Ë 8¸\0\0\0\80\8aJý¼\0h\ eµ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0+\f\93¹\0\0\0\80\0\0\0\0,\92\19»\0\0\0\80\0\0\0\0\0\96 ¹\0\0\0\80\v/\ f¼º\ e\0<:8¬ÿ\9c»þ\a¼»\18é/:±ì­¼7zκ\0\0\0\80\¬±¼HþGº\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0+\f\93¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Hn3ºNÐ\8b»\80\9dï8à±Ô¹\9e\8f\ 5¼ _\819¬ÿ\9c»þ\a¼»\18é/:\v/\ f¼º\ e\0<:8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\80õå¸1Ʀ»\80á\8b8@B´¹'\ 5(¼@J[9à±Ô¹\9e\8f\ 5¼ _\819Hn3ºNÐ\8b»\80\9dï8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\80\ e¡\9b»\0{\107\80\92\ 6¹~%)¼ ¶£8@B´¹'\ 5(¼@J[9\80õå¸1Ʀ»\80á\8b8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\9f\92\0\0\0\80\0Ø\98¶XI\v¼\0\12:6\80\92\ 6¹~%)¼ ¶£8\0\80\ e¡\9b»\0{\107\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\ 3pߺ\0\0\0\80\0\0\0\0Ù\1c´»\0\0\0\80\0Ø\98¶XI\v¼\0\12:6\0\0\0\0\9f\92\0\0\0\80@B´¹'\ 5(¼@J[9\80Â\84¸_ðv¼\80\85!8(\9e<º÷)G¼àtå9à±Ô¹\9e\8f\ 5¼ _\819\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\80\92\ 6¹~%)¼ ¶£8\0\0\0\0¨Ë\83¼\0\0\0\80\80Â\84¸_ðv¼\80\85!8@B´¹'\ 5(¼@J[9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0Ø\98¶XI\v¼\0\12:6\0@-¶ÀÝg¼\0@Ó5\0\0\0\0¨Ë\83¼\0\0\0\80\80\92\ 6¹~%)¼ ¶£8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0Ù\1c´»\0\0\0\80\0\0\0\0\r)$¼\0\0\0\80\0@-¶ÀÝg¼\0@Ó5\0Ø\98¶XI\v¼\0\12:6\0\0\0\0,\92\19»\0\0\0\80\0\0\0\0Ø\11¬»\0\0\0\80\0\0\0\0\r)$¼\0\0\0\80\0\0\0\0Ù\1c´»\0\0\0\80±ì­¼7zκ\0\0\0\80~´¯¼\1e$\1c»\0\0\0\80ÆÒý¼ø\7fÿ¸\0\0\0\80âGý¼Ë 8¸\0\0\0\80\0\0\0\0+\f\93¹\0\0\0\80\0\0\0\0¯@¿º\0\0\0\80\0\0\0\0Ø\11¬»\0\0\0\80\0\0\0\0,\92\19»\0\0\0\80¬ÿ\9c»þ\a¼»\18é/:©\10±»õì   ¼0\9c\83:~´¯¼\1e$\1c»\0\0\0\80±ì­¼7zκ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0¯@¿º\0\0\0\80\0\0\0\0+\f\93¹\0\0\0\80à±Ô¹\9e\8f\ 5¼ _\819(\9e<º÷)G¼àtå9©\10±»õì     ¼0\9c\83:¬ÿ\9c»þ\a¼»\18é/:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0Ø\11¬»\0\0\0\80\0\0\0\0j\19ý»\0\0\0\80\ 2¹\11»b¼F9\9f8\0\0\0\0\r)$¼\0\0\0\80~´¯¼\1e$\1c»\0\0\0\802À¹¼x¦B»\0\0\0\80kúþ¼TÂF¹\0\0\0\80ÆÒý¼ø\7fÿ¸\0\0\0\80\0\0\0\0¯@¿º\0\0\0\80\0\0\0\0E¯/»\0\0\0\80\0\0\0\0j\19ý»\0\0\0\80\0\0\0\0Ø\11¬»\0\0\0\80©\10±»õì ¼0\9c\83:\ 18­»B\89(¼¼9\9d:2À¹¼x¦B»\0\0\0\80~´¯¼\1e$\1c»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0ÀÝò¸\0\0\0\80\0\0\0\0E¯/»\0\0\0\80\0\0\0\0¯@¿º\0\0\0\80(\9e<º÷)G¼àtå9@\13kº¢9w¼\88ü\ e:\ 18­»B\89(¼¼9\9d\10±»õì     ¼0\9c\83:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0ÀÝò¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\80Â\84¸_ðv¼\80\85!8\0\0\0\0\9b¼\0\0\0\80@\13kº¢9w¼\88ü\ e:(\9e<º÷)G¼àtå9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0¨Ë\83¼\0\0\0\80\0\0\0\0d\f«¼\0\0\0\80\0\0\0\0\9b¼\0\0\0\80\80Â\84¸_ðv¼\80\85!8\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0@-¶ÀÝg¼\0@Ó5\0\0\0\0\8b\86\99¼\0\0\0\80\0\0\0\0d\f«¼\0\0\0\80\0\0\0\0¨Ë\83¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\r)$¼\0\0\0\80\ 2¹\11»b¼F9\9f8\0\0\0\0\8b\86\99¼\0\0\0\80\0@-¶ÀÝg¼\0@Ó5\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0d\f«¼\0\0\0\80\0\0\0\0ø?»¼\0\0\0\80\0Ø ¶F\81¨¼\0@Ä5\0\0\0\0\9b¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\8b\86\99¼\0\0\0\80\0,ø·\80¿¨¼Àü\967\0\0\0\0ø?»¼\0\0\0\80\0\0\0\0d\f«¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\ 2¹\11»b¼F9\9f\9b\8e\1f\83¼Jþþ9\0,ø·\80¿¨¼Àü\967\0\0\0\0\8b\86\99¼\0\0\0\80\0\0\0\0j\19ý»\0\0\0\80\0\0\0\0Äa\ e¼\0\0\0\80è\9b\8e\1f\83¼Jþþ9@á\ 2¹\11»b¼F9\9f82À¹¼x¦B»\0\0\0\80\1d\8a̼ö´P»\0\0\0\80A\16\0½\Vb¹\0\0\0\80kúþ¼TÂF¹\0\0\0\80\0\0\0\0E¯/»\0\0\0\80\0\0\0\0ÿ´P»\0\0\0\80\0\0\0\0Äa\ e¼\0\0\0\80\0\0\0\0j\19ý»\0\0\0\80\ 18­»B\89(¼¼9\9d\12o»úE0¼\\1c\97:\1d\8a̼ö´P»\0\0\0\802À¹¼x¦B»\0\0\0\80\0\0\0\0ÀÝò¸\0\0\0\80\0\0\0\0\0Vb¹\0\0\0\80\0\0\0\0ÿ´P»\0\0\0\80\0\0\0\0E¯/»\0\0\0\80@\13kº¢9w¼\88ü\ e:ÀÒ˺\9cà\89¼ ôw:À\12o»úE0¼\\1c\97:\ 18­»B\89(¼¼9\9d:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0Vb¹\0\0\0\80\0\0\0\0ÀÝò¸\0\0\0\80\0\0\0\0\9b¼\0\0\0\80\0Ø ¶F\81¨¼\0@Ä5ÀÒ˺\9cà\89¼ ôw:@\13kº¢9w¼\88ü\ e:\1d\8a̼ö´P»\0\0\0\80nÛâ¼q¦B»\0\0\0\80;P\0½@ÂF¹\0\0\0\80A\16\0½\Vb¹\0\0\0\80\0\0\0\0ÿ´P»\0\0\0\80\0\0\0\0å4.»\0\0\0\80\0\0\0\0`\19ý»\0\0\0\80\0\0\0\0Äa\ e¼\0\0\0\80À\12o»úE0¼\\1c\97:\13oF¼òE\ 5¼\0\0\0\80nÛâ¼q¦B»\0\0\0\80\1d\8a̼ö´P»\0\0\0\80\0\0\0\0\0Vb¹\0\0\0\80\0\0\0\0 n\119\0\0\0\80\0\0\0\0å4.»\0\0\0\80\0\0\0\0ÿ´P»\0\0\0\80ÀÒ˺\9cà\89¼ ôw:\9a\88/»²\8a\8b¼ì\89Õ:\13oF¼òE\ 5¼\0\0\0\80À\12o»úE0¼\\1c\97:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0 n\119\0\0\0\80\0\0\0\0\0Vb¹\0\0\0\80\0Ø ¶F\81¨¼\0@Ä5\80\ 5þº\14
+­¼°\82\9a:\9a\88/»²\8a\8b¼ì\89Õ:ÀÒ˺\9cà\89¼ ôw:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0ø?»¼\0\0\0\80Ì` ºéüµ¼$\1aC:\80\ 5þº\14
+­¼°\82\9a:\0Ø ¶F\81¨¼\0@Ä5\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0,ø·\80¿¨¼Àü\96\93\9c\11±¼0ñÑ:Ì` ºéüµ¼$\1aC:\0\0\0\0ø?»¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80è\9b\8e\1f\83¼Jþþ9 ×¾º\97\88\v)h:ª\93\9c\11±¼0ñÑ:\0,ø·\80¿¨¼Àü\967\0\0\0\0Äa\ e¼\0\0\0\80\0\0\0\0`\19ý»\0\0\0\80 ×¾º\97\88\v)h:è\9b\8e\1f\83¼Jþþ9Ì` ºéüµ¼$\1aC:\]¸»\e\19¶¼\1eH`;\ e\94\99»dΤ¼xÔ:;\80\ 5þº\14
+­¼°\82\9a:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ª\93\9c\11±¼0ñÑ:\ 3an»\12n\94¼Ûþ\10;\]¸»\e\19¶¼\1eH`;Ì` ºéüµ¼$\1aC:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 ×¾º\97\88\v)h:\0\0\0\0\f)$¼\0\0\0\80\ 3an»\12n\94¼Ûþ\10\93\9c\11±¼0ñÑ:\0\0\0\0`\19ý»\0\0\0\80\0\0\0\08"¤»\0\0\0\80\0\0\0\0\f)$¼\0\0\0\80 ×¾º\97\88\v)h:nÛâ¼q¦B»\0\0\0\80bÈð¼\ f$\1c»\0\0\0\80zäÿ¼P\7fÿ¸\0\0\0\80;P\0½@ÂF¹\0\0\0\80\0\0\0\0å4.»\0\0\0\80\0\0\0\0`3û9\0\0\0\80\0\0\0\08"¤»\0\0\0\80\0\0\0\0`\19ý»\0\0\0\80\13oF¼òE\ 5¼\0\0\0\80\ 3\9e´¼ÁÐØ»\0\0\0\80bÈð¼\ f$\1c»\0\0\0\80nÛâ¼q¦B»\0\0\0\80\0\0\0\0 n\119\0\0\0\80\0\0\0\0p$·:\0\0\0\80\0\0\0\0`3û9\0\0\0\80\0\0\0\0å4.»\0\0\0\80\9a\88/»²\8a\8b¼ì\89Õ:î\90=»~tp¼\90wñ:\ 3\9e´¼ÁÐØ»\0\0\0\80\13oF¼òE\ 5¼\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0`\8b\959\0\0\0\80\0\0\0\0p$·:\0\0\0\80\0\0\0\0 n\119\0\0\0\80\80\ 5þº\14
+­¼°\82\9a:\ e\94\99»dΤ¼xÔ:;î\90=»~tp¼\90wñ:\9a\88/»²\8a\8b¼ì\89Õ:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0`\8b\959\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0`3û9\0\0\0\80\0\0\0\0Ò\8f\9b;\0\0\0\80\0\0\0\0èy@;\0\0\0\80\0\0\0\08"¤»\0\0\0\80\ 3\9e´¼ÁÐØ»\0\0\0\80ådä¼Ï\93\94»\0\0\0\807\86ë¼\1azκ\0\0\0\80bÈð¼\ f$\1c»\0\0\0\80\0\0\0\0p$·:\0\0\0\80\0\0\0\0z\1e:;\0\0\0\80\0\0\0\0Ò\8f\9b;\0\0\0\80\0\0\0\0`3û9\0\0\0\80î\90=»~tp¼\90wñ:\fþ¯¼!\9dü»\0\0\0\80ådä¼Ï\93\94»\0\0\0\80\ 3\9e´¼ÁÐØ»\0\0\0\80\0\0\0\0`\8b\959\0\0\0\80\0\0\0\0è­g:\0\0\0\80\0\0\0\0z\1e:;\0\0\0\80\0\0\0\0p$·:\0\0\0\80\ e\94\99»dΤ¼xÔ:;8\aO¼Fß!¼\0\0\0\80\fþ¯¼!\9dü»\0\0\0\80î\90=»~tp¼\90wñ:\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0è­g:\0\0\0\80\0\0\0\0`\8b\959\0\0\0\80\]¸»\e\19¶¼\1eH`;0­¶»\ 101¼\90V¸98\aO¼Fß!¼\0\0\0\80\ e\94\99»dΤ¼xÔ:;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\ 3an»\12n\94¼Ûþ\10;Ô½\97ºÐ2\v¼\0\0\0\800­¶»\ 101¼\90V¸9\]¸»\e\19¶¼\1eH`;\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\f)$¼\0\0\0\80\0\0\0\0zþ_»\0\0\0\80Ô½\97ºÐ2\v¼\0\0\0\80\ 3an»\12n\94¼Ûþ\10;\0\0\0\08"¤»\0\0\0\80\0\0\0\0èy@;\0\0\0\80\0\0\0\0zþ_»\0\0\0\80\0\0\0\0\f)$¼\0\0\0\80bÈð¼\ f$\1c»\0\0\0\807\86ë¼\1azκ\0\0\0\80\99[þ¼à\1e\0\0\0\80zäÿ¼P\7fÿ¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\8a\9b8\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Ô½\97ºÐ2\v¼\0\0\0\80\0\0\0\0d E;\0\0\0\80\936\91»æ­-»\0\0\0\800­¶»\ 101¼\90V¸9\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0zþ_»\0\0\0\80\0\0\0\0\10^i<\0\0\0\80\0\0\0\0d E;\0\0\0\80Ô½\97ºÐ2\v¼\0\0\0\80\0\0\0\0èy@;\0\0\0\80\0\0\0\0\84<\0\0\0\80\0\0\0\0\10^i<\0\0\0\80\0\0\0\0zþ_»\0\0\0\807\86ë¼\1azκ\0\0\0\80ÌfÖ¼\ 4þGº\0\0\0\80½Ný¼\0Ð\rµ\0\0\0\80\99[þ¼à\1e\0\0\0\80\0\0\0\0Ò\8f\9b;\0\0\0\80\0\0\0\0ð\11\19<\0\0\0\80\0\0\0\0\84<\0\0\0\80\0\0\0\0èy@;\0\0\0\80ådä¼Ï\93\94»\0\0\0\80_µÄ¼
\1d»\0\0\0\80ÌfÖ¼\ 4þGº\0\0\0\807\86ë¼\1azκ\0\0\0\80\0\0\0\0z\1e:;\0\0\0\80\0\0\0\0\83;\0\0\0\80\0\0\0\0ð\11\19<\0\0\0\80\0\0\0\0Ò\8f\9b;\0\0\0\80\fþ¯¼!\9dü»\0\0\0\80!í¨¼\8a\18\85»\0\0\0\80_µÄ¼
\1d»\0\0\0\80ådä¼Ï\93\94»\0\0\0\80\0\0\0\0è­g:\0\0\0\80\0\0\0\0(\80»:\0\0\0\80\0\0\0\0\83;\0\0\0\80\0\0\0\0z\1e:;\0\0\0\808\aO¼Fß!¼\0\0\0\80¬\80^¼-Ú¢»\0\0\0\80!í¨¼\8a\18\85»\0\0\0\80\fþ¯¼!\9dü»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\8a\9b8\0\0\0\80\0\0\0\0(\80»:\0\0\0\80\0\0\0\0è­g:\0\0\0\800­¶»\ 101¼\90V¸9\936\91»æ­-»\0\0\0\80¬\80^¼-Ú¢»\0\0\0\808\aO¼Fß!¼\0\0\0\80\0\0\0\0\83;\0\0\0\80\0\0\0\0Ðÿ\92;\0\0\0\80\0\0\0\0\19d<<\0\0\0\80\0\0\0\0ð\11\19<\0\0\0\80!í¨¼\8a\18\85»\0\0\0\80\0\0\0\0\9d¹\0\0\0\80\0\0\0\0(¤Cº\0\0\0\80_µÄ¼
\1d»\0\0\0\80\0\0\0\0(\80»:\0\0\0\80\0\0\0\0,õ×:\0\0\0\80\0\0\0\0Ðÿ\92;\0\0\0\80\0\0\0\0\83;\0\0\0\80¬\80^¼-Ú¢»\0\0\0\80\0\0\0\0\f³\r;\0\0\0\80\0\0\0\0\9d¹\0\0\0\80!í¨¼\8a\18\85»\0\0\0\80\0\0\0\0\0\8a\9b8\0\0\0\80\0\0\0\0\80õí8\0\0\0\80\0\0\0\0,õ×:\0\0\0\80\0\0\0\0(\80»:\0\0\0\80\936\91»æ­-»\0\0\0\80\0\0\0\0\ 3<\0\0\0\80\0\0\0\0\f³\r;\0\0\0\80¬\80^¼-Ú¢»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\80õí8\0\0\0\80\0\0\0\0\0\8a\9b8\0\0\0\80\0\0\0\0d E;\0\0\0\80\0\0\0\0Rd\9b<\0\0\0\80\0\0\0\0\ 3<\0\0\0\80\936\91»æ­-»\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\10^i<\0\0\0\80\0\0\0\0nW¹<\0\0\0\80\0\0\0\0Rd\9b<\0\0\0\80\0\0\0\0d E;\0\0\0\80\0\0\0\0\84<\0\0\0\80\0\0\0\0Ø\15£<\0\0\0\80\0\0\0\0nW¹<\0\0\0\80\0\0\0\0\10^i<\0\0\0\80ÌfÖ¼\ 4þGº\0\0\0\80\0\0\0\0`´6¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80½Ný¼\0Ð\rµ\0\0\0\80\0\0\0\0ð\11\19<\0\0\0\80\0\0\0\0\19d<<\0\0\0\80\0\0\0\0Ø\15£<\0\0\0\80\0\0\0\0\84<\0\0\0\80_µÄ¼
\1d»\0\0\0\80\0\0\0\0(¤Cº\0\0\0\80\0\0\0\0`´6¹\0\0\0\80ÌfÖ¼\ 4þGº\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80Ôä\ 6» ób¹\0\0\0\80Øô\13»XéÕ¹\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0À°ß¸\0\0\0\80'¸õº\80\1c\89¸\0\0\0\80Ôä\ 6» ób¹\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\805íµº\0\80ªµ\0\0\0\80'¸õº\80\1c\89¸\0\0\0\80\0\0\0\0À°ß¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\10
+Eº\0\0\0\0\0\0\0\805íµº\0\80ªµ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80(\ 6\0\0\0\0\0\0\0\80\10
+Eº\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80(\ 6\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0Z\94\0\0\0\80¦ïA»F\86\rº\0\0\0\80\0\0\0\0~±Hº\0\0\0\80yRj»4®ø¹\0\0\0\80à\9e\8a»dJÕ¹\0\0\0\80©ïA;$\86\rº\0\0\0\80~Rj;ø­ø¹\0\0\0\80\88®\9f»Pá³¹\0\0\0\80\0\0\0\0~±Hº\0\0\0\80}²»Fý\96¹\0\0\0\80\9c\9e»Ò1\80¹\0\0\0\80n\84λT\13\0\0\0\80\0\0\0\0~±Hº\0\0\0\80Ï-Ö»)®L¹\0\0\0\80LóÙ»ô«D¹\0\0\0\80w'Ú»\f%G¹\0\0\0\80\0\0\0\0~±Hº\0\0\0\80\1a\80Ö»8+U¹\0\0\0\80âÇλð+p¹\0\0\0\80¤\ 6ûL®\8c¹\0\0\0\80\0\0\0\0~±Hº\0\0\0\80,ʳ»|E¨¹\0\0\0\80Om¢»\10]ɹ\0\0\0\80\0\0\0\0d\94\0\0\0\80\0\0\0\0~±Hº\0\0\0\80Om¢;\1c]ɹ\0\0\0\80-ʳ;\8cE¨¹\0\0\0\80¤\ 6Ã;`®\8c¹\0\0\0\80\0\0\0\0~±Hº\0\0\0\80æÇÎ; ,p¹\0\0\0\80\1c\80Ö;h+U¹\0\0\0\80z'Ú;4%G¹\0\0\0\80\0\0\0\0~±Hº\0\0\0\80OóÙ;\10¬D¹\0\0\0\80Ò-Ö;3®L¹\0\0\0\80q\84Î;H\13\0\0\0\80\0\0\0\0~±Hº\0\0\0\80 \9eÂ;¾1\80¹\0\0\0\80\81²;"ý\96¹\0\0\0\80\8c®\9f;$á³¹\0\0\0\80\0\0\0\0~±Hº\0\0\0\80ã\9e\8a;,JÕ¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\93\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80H\96\0\0\0\0\0\0\0\80|\96¡¹\0\0\0\0\0\0\0\80\ 2º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80¦¤7º\0\0\0\0\0\0\0\80\82üjº\0\0\0\0\0\0\0\80\8aº\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\7fä\98º\0\0\0\0\0\0\0\80íÑ\9dº\0\0\0\0\0\0\0\80\7fä\98º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\8aº\0\0\0\0\0\0\0\80\81üjº\0\0\0\0\0\0\0\80¬¤7º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80®¤7:\0\0\0\0\0\0\0\80\86üj:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\8a:\0\0\0\0\0\0\0\80\84ä\98:\0\0\0\0\0\0\0\80ôÑ\9d:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\88ä\98:\0\0\0\0\0\0\0\80\8a:\0\0\0\0\0\0\0\80\98üj:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80º¤7:\0\0\0\0\0\0\0\80\ 2:\0\0\0\0\0\0\0\80¤\96¡9\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90\96#9\0\0\0\0\0\0\0\80À\94^8\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80Øô\13»XéÕ¹\0\0\0\80¦ïA»F\86\rº\0\0\0\80\0\0\0\0Z\94\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 IѸ\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Øô\13»XéÕ¹\0\0\0\80+\V»pú¦¹\0\0\0\80yRj»4®ø¹\0\0\0\80¦ïA»F\86\rº\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Ôä\ 6» ób¹\0\0\0\80¹YK»àÛ\13¹\0\0\0\80+\V»pú¦¹\0\0\0\80Øô\13»XéÕ¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80'¸õº\80\1c\89¸\0\0\0\80I8?»\0#µ·\0\0\0\80¹YK»àÛ\13¹\0\0\0\80Ôä\ 6» ób¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\805íµº\0\80ªµ\0\0\0\80j[\14»\0\0\0\0\0\0\0\80I8?»\0#µ·\0\0\0\80'¸õº\80\1c\89¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\10
+Eº\0\0\0\0\0\0\0\80TÙ¿º\0\0\0\0\0\0\0\80j[\14»\0\0\0\0\0\0\0\805íµº\0\80ªµ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80(\ 6\0\0\0\0\0\0\0\80\fÂ)º\0\0\0\0\0\0\0\80TÙ¿º\0\0\0\0\0\0\0\80\10
+Eº\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 IѸ\0\0\0\0\0\0\0\80\fÂ)º\0\0\0\0\0\0\0\80(\ 6\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80TÙ¿º\0\0\0\0\0\0\0\80ħ\10»\0\0\0\0\0\0\0\80h\1f\0\0\0\0\0\0\0\80j[\14»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\fÂ)º\0\0\0\0\0\0\0\80\96º\0\0\0\0\0\0\0\80ħ\10»\0\0\0\0\0\0\0\80TÙ¿º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\93\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80 IѸ\0\0\0\0\0\0\0\80À\15¬¹\0\0\0\0\0\0\0\80\96º\0\0\0\0\0\0\0\80\fÂ)º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\15¬¹\0\0\0\0\0\0\0\80 IѸ\0\0\0\0\0\0\0\80+\V»pú¦¹\0\0\0\80Ð\86\91»Àqh¹\0\0\0\80à\9e\8a»dJÕ¹\0\0\0\80yRj»4®ø¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80¹YK»àÛ\13¹\0\0\0\80\90»À\ 6\8b¸\0\0\0\80Ð\86\91»Àqh¹\0\0\0\80+\V»pú¦¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80I8?»\0#µ·\0\0\0\80S\9b\8b»\0\0\0\0\0\80\90»À\ 6\8b¸\0\0\0\80¹YK»àÛ\13¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80j[\14»\0\0\0\0\0\0\0\80h\1f\0\0\0\0\0\0\0\80S\9b\8b»\0\0\0\0\0\80I8?»\0#µ·\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\93Õ·\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90»À\ 6\8b¸\0\0\0\80ôa½»\0©\83·\0\0\0\80ª\8f·»\80ø\ e¹\0\0\0\80Ð\86\91»Àqh¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80S\9b\8b»\0\0\0\0\0\80\90X´»\0\0\0\0\0\0\0\80ôa½»\0©\83·\0\0\0\80\90»À\ 6\8b¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80h\1f\0\0\0\0\0\0\0\80è|\95»\0\0\0\0\0\0\0\80\90X´»\0\0\0\0\0\0\0\80S\9b\8b»\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\ 5\96¸\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ħ\10»\0\0\0\0\0\0\0\80ü(G»\0\0\0\0\0\0\0\80è|\95»\0\0\0\0\0\0\0\80h\1f\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90}\1e¹\0\0\0\0\0\0\0\80À\ 5\96¸\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\96º\0\0\0\0\0\0\0\80X~̺\0\0\0\0\0\0\0\80ü(G»\0\0\0\0\0\0\0\80ħ\10»\0\0\0\0\0\0\0\80À\93\0\0\0\0\0\0\0\80H\96\0\0\0\0\0\0\0\80\90}\1e¹\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\15¬¹\0\0\0\0\0\0\0\80èu\ eº\0\0\0\0\0\0\0\80X~̺\0\0\0\0\0\0\0\80\96º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\93Õ·\0\0\0\0\0\0\0\80èu\ eº\0\0\0\0\0\0\0\80À\15¬¹\0\0\0\0\0\0\0\80Ð\86\91»Àqh¹\0\0\0\80ª\8f·»\80ø\ e¹\0\0\0\80\88®\9f»Pá³¹\0\0\0\80à\9e\8a»dJÕ¹\0\0\0\80\90}\1e¹\0\0\0\0\0\0\0\80Ì/\ 2º\0\0\0\0\0\0\0\80¸\8f   º\0\0\0\0\0\0\0\80À\ 5\96¸\0\0\0\0\0\0\0\80X~̺\0\0\0\0\0\0\0\80xäúº\0\0\0\0\0\0\0\80\92ëq»\0\0\0\0\0\0\0\80ü(G»\0\0\0\0\0\0\0\80H\96\0\0\0\0\0\0\0\80|\96¡¹\0\0\0\0\0\0\0\80Ì/\ 2º\0\0\0\0\0\0\0\80\90}\1e¹\0\0\0\0\0\0\0\80èu\ eº\0\0\0\0\0\0\0\80\90~&º\0\0\0\0\0\0\0\80xäúº\0\0\0\0\0\0\0\80X~̺\0\0\0\0\0\0\0\80\0\93Õ·\0\0\0\0\0\0\0\80\0÷@¸\0\0\0\0\0\0\0\80\90~&º\0\0\0\0\0\0\0\80èu\ eº\0\0\0\0\0\0\0\80ª\8f·»\80ø\ e¹\0\0\0\80\8a\1aØ» B\9e¸\0\0\0\80}²»Fý\96¹\0\0\0\80\88®\9f»Pá³¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0÷@¸\0\0\0\0\0\0\0\80\0\93Õ·\0\0\0\0\0\0\0\80ôa½»\0©\83·\0\0\0\80ØÚá»\0\0\0\0\0\80\8a\1aØ» B\9e¸\0\0\0\80ª\8f·»\80ø\ e¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\87\15¹\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90X´»\0\0\0\0\0\0\0\80p{Ó»\0\0\0\0\0\0\0\80ØÚá»\0\0\0\0\0\80ôa½»\0©\83·\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80àëĹ\0\0\0\0\0\0\0\80À\87\15¹\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80è|\95»\0\0\0\0\0\0\0\80ïj¯»\0\0\0\0\0\0\0\80p{Ó»\0\0\0\0\0\0\0\80\90X´»\0\0\0\0\0\0\0\80À\ 5\96¸\0\0\0\0\0\0\0\80¸\8f     º\0\0\0\0\0\0\0\80àëĹ\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ü(G»\0\0\0\0\0\0\0\80\92ëq»\0\0\0\0\0\0\0\80ïj¯»\0\0\0\0\0\0\0\80è|\95»\0\0\0\0\0\0\0\80ØÚá»\0\0\0\0\0\80Þ\91ø»\0\0\0\0\0\0\0\80\9eëï» .)¸\0\0\0\80\8a\1aØ» B\9e¸\0\0\0\80À\87\15¹\0\0\0\0\0\0\0\80\87º\0\0\0\0\0\0\0\80\10í
\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80p{Ó»\0\0\0\0\0\0\0\80Û_ä»\0\0\0\0\0\0\0\80Þ\91ø»\0\0\0\0\0\0\0\80ØÚá»\0\0\0\0\0\80àëĹ\0\0\0\0\0\0\0\80\ 4@²º\0\0\0\0\0\0\0\80\87º\0\0\0\0\0\0\0\80À\87\15¹\0\0\0\0\0\0\0\80ïj¯»\0\0\0\0\0\0\0\80\18ôº»\0\0\0\0\0\0\0\80Û_ä»\0\0\0\0\0\0\0\80p{Ó»\0\0\0\0\0\0\0\80¸\8f        º\0\0\0\0\0\0\0\80<´°º\0\0\0\0\0\0\0\80\ 4@²º\0\0\0\0\0\0\0\80àëĹ\0\0\0\0\0\0\0\80\92ëq»\0\0\0\0\0\0\0\80\1eu\84»\0\0\0\0\0\0\0\80\18ôº»\0\0\0\0\0\0\0\80ïj¯»\0\0\0\0\0\0\0\80Ì/\ 2º\0\0\0\0\0\0\0\80 è\83º\0\0\0\0\0\0\0\80<´°º\0\0\0\0\0\0\0\80¸\8f     º\0\0\0\0\0\0\0\80xäúº\0\0\0\0\0\0\0\80ØA\ f»\0\0\0\0\0\0\0\80\1eu\84»\0\0\0\0\0\0\0\80\92ëq»\0\0\0\0\0\0\0\80|\96¡¹\0\0\0\0\0\0\0\80\ 2º\0\0\0\0\0\0\0\80 è\83º\0\0\0\0\0\0\0\80Ì/\ 2º\0\0\0\0\0\0\0\80\90~&º\0\0\0\0\0\0\0\80ÐÆ,º\0\0\0\0\0\0\0\80ØA\ f»\0\0\0\0\0\0\0\80xäúº\0\0\0\0\0\0\0\80\0÷@¸\0\0\0\0\0\0\0\80\0º\ 4¹\0\0\0\0\0\0\0\80ÐÆ,º\0\0\0\0\0\0\0\80\90~&º\0\0\0\0\0\0\0\80\8a\1aØ» B\9e¸\0\0\0\80\9eëï» .)¸\0\0\0\80\9c\9e»Ò1\80¹\0\0\0\80}²»Fý\96¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\10í
\0\0\0\0\0\0\0\80\0º\ 4¹\0\0\0\0\0\0\0\80\0÷@¸\0\0\0\0\0\0\0\80ØA\ f»\0\0\0\0\0\0\0\80Hò>»\0\0\0\0\0\0\0\80Ì\ 3\96»\0\0\0\0\0\0\0\80\1eu\84»\0\0\0\0\0\0\0\80\ 2º\0\0\0\0\0\0\0\80¦¤7º\0\0\0\0\0\0\0\808êÓº\0\0\0\0\0\0\0\80 è\83º\0\0\0\0\0\0\0\80ÐÆ,º\0\0\0\0\0\0\0\80 Vº\0\0\0\0\0\0\0\80Hò>»\0\0\0\0\0\0\0\80ØA\ f»\0\0\0\0\0\0\0\80\0º\ 4¹\0\0\0\0\0\0\0\80È˲º\0\0\0\0\0\0\0\80 Vº\0\0\0\0\0\0\0\80ÐÆ,º\0\0\0\0\0\0\0\80\9eëï» .)¸\0\0\0\80\88\8cÿ»àM½·\0\0\0\80n\84λT\13\0\0\0\80\9c\9e»Ò1\80¹\0\0\0\80\10í
\0\0\0\0\0\0\0\80x\88ÿº\0\0\0\0\0\0\0\80È˲º\0\0\0\0\0\0\0\80\0º\ 4¹\0\0\0\0\0\0\0\80Þ\91ø»\0\0\0\0\0\0\0\80_1\ 3¼\0\0\0\0\0\0\0\80\88\8cÿ»àM½·\0\0\0\80\9eëï» .)¸\0\0\0\80\87º\0\0\0\0\0\0\0\80ü2*»\0\0\0\0\0\0\0\80x\88ÿº\0\0\0\0\0\0\0\80\10í
\0\0\0\0\0\0\0\80Û_ä»\0\0\0\0\0\0\0\80\81
+ð»\0\0\0\0\0\0\0\80_1\ 3¼\0\0\0\0\0\0\0\80Þ\91ø»\0\0\0\0\0\0\0\80\ 4@²º\0\0\0\0\0\0\0\80Þ58»\0\0\0\0\0\0\0\80ü2*»\0\0\0\0\0\0\0\80\87º\0\0\0\0\0\0\0\80\18ôº»\0\0\0\0\0\0\0\80Z\16È»\0\0\0\0\0\0\0\80\81
+ð»\0\0\0\0\0\0\0\80Û_ä»\0\0\0\0\0\0\0\80<´°º\0\0\0\0\0\0\0\80.`\1f»\0\0\0\0\0\0\0\80Þ58»\0\0\0\0\0\0\0\80\ 4@²º\0\0\0\0\0\0\0\80\1eu\84»\0\0\0\0\0\0\0\80Ì\ 3\96»\0\0\0\0\0\0\0\80Z\16È»\0\0\0\0\0\0\0\80\18ôº»\0\0\0\0\0\0\0\80 è\83º\0\0\0\0\0\0\0\808êÓº\0\0\0\0\0\0\0\80.`\1f»\0\0\0\0\0\0\0\80<´°º\0\0\0\0\0\0\0\80ü2*»\0\0\0\0\0\0\0\80\16-\95»\0\0\0\0\0\0\0\80ÞÛ\84»\0\0\0\0\0\0\0\80x\88ÿº\0\0\0\0\0\0\0\80\81
+ð»\0\0\0\0\0\0\0\80°Çú»\0\0\0\0\0\0\0\80êý\a¼\0\0\0\0\0\0\0\80_1\ 3¼\0\0\0\0\0\0\0\80Þ58»\0\0\0\0\0\0\0\80\1a]\93»\0\0\0\0\0\0\0\80\16-\95»\0\0\0\0\0\0\0\80ü2*»\0\0\0\0\0\0\0\80Z\16È»\0\0\0\0\0\0\0\80\ 6<Ø»\0\0\0\0\0\0\0\80°Çú»\0\0\0\0\0\0\0\80\81
+ð»\0\0\0\0\0\0\0\80.`\1f»\0\0\0\0\0\0\0\80¼¶l»\0\0\0\0\0\0\0\80\1a]\93»\0\0\0\0\0\0\0\80Þ58»\0\0\0\0\0\0\0\80Ì\ 3\96»\0\0\0\0\0\0\0\804+®»\0\0\0\0\0\0\0\80\ 6<Ø»\0\0\0\0\0\0\0\80Z\16È»\0\0\0\0\0\0\0\808êÓº\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\80¼¶l»\0\0\0\0\0\0\0\80.`\1f»\0\0\0\0\0\0\0\80Hò>»\0\0\0\0\0\0\0\80bx\82»\0\0\0\0\0\0\0\804+®»\0\0\0\0\0\0\0\80Ì\ 3\96»\0\0\0\0\0\0\0\80¦¤7º\0\0\0\0\0\0\0\80\82üjº\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\808êÓº\0\0\0\0\0\0\0\80 Vº\0\0\0\0\0\0\0\808N[»\0\0\0\0\0\0\0\80bx\82»\0\0\0\0\0\0\0\80Hò>»\0\0\0\0\0\0\0\80È˲º\0\0\0\0\0\0\0\80¼\8a\0\0\0\0\0\0\0\808N[»\0\0\0\0\0\0\0\80 Vº\0\0\0\0\0\0\0\80\88\8cÿ»àM½·\0\0\0\80ì\10\ 5¼¬©Z·\0\0\0\80Ï-Ö»)®L¹\0\0\0\80n\84λT\13\0\0\0\80x\88ÿº\0\0\0\0\0\0\0\80ÞÛ\84»\0\0\0\0\0\0\0\80¼\8a\0\0\0\0\0\0\0\80È˲º\0\0\0\0\0\0\0\80_1\ 3¼\0\0\0\0\0\0\0\80êý\a¼\0\0\0\0\0\0\0\80ì\10\ 5¼¬©Z·\0\0\0\80\88\8cÿ»àM½·\0\0\0\80\82üjº\0\0\0\0\0\0\0\80\8aº\0\0\0\0\0\0\0\80Ù|6»\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\808N[»\0\0\0\0\0\0\0\80²ù°»\0\0\0\0\0\0\0\80ªÞ®»\0\0\0\0\0\0\0\80bx\82»\0\0\0\0\0\0\0\80¼\8a\0\0\0\0\0\0\0\80¸n·»\0\0\0\0\0\0\0\80²ù°»\0\0\0\0\0\0\0\808N[»\0\0\0\0\0\0\0\80ì\10\ 5¼¬©Z·\0\0\0\80ã>\b¼@}
\0\0\0\80LóÙ»ô«D¹\0\0\0\80Ï-Ö»)®L¹\0\0\0\80ÞÛ\84»\0\0\0\0\0\0\0\80HçÅ»\0\0\0\0\0\0\0\80¸n·»\0\0\0\0\0\0\0\80¼\8a\0\0\0\0\0\0\0\80êý\a¼\0\0\0\0\0\0\0\80ïS\v¼\0\0\0\0\0\0\0\80ã>\b¼@}
\0\0\0\80ì\10\ 5¼¬©Z·\0\0\0\80\16-\95»\0\0\0\0\0\0\0\80úlÕ»\0\0\0\0\0\0\0\80HçÅ»\0\0\0\0\0\0\0\80ÞÛ\84»\0\0\0\0\0\0\0\80°Çú»\0\0\0\0\0\0\0\80Ø*\ 2¼\0\0\0\0\0\0\0\80ïS\v¼\0\0\0\0\0\0\0\80êý\a¼\0\0\0\0\0\0\0\80\1a]\93»\0\0\0\0\0\0\0\80rjÈ»\0\0\0\0\0\0\0\80úlÕ»\0\0\0\0\0\0\0\80\16-\95»\0\0\0\0\0\0\0\80\ 6<Ø»\0\0\0\0\0\0\0\80\ 6éç»\0\0\0\0\0\0\0\80Ø*\ 2¼\0\0\0\0\0\0\0\80°Çú»\0\0\0\0\0\0\0\80¼¶l»\0\0\0\0\0\0\0\80Ö\92\99»\0\0\0\0\0\0\0\80rjÈ»\0\0\0\0\0\0\0\80\1a]\93»\0\0\0\0\0\0\0\804+®»\0\0\0\0\0\0\0\80\90\9aÆ»\0\0\0\0\0\0\0\80\ 6éç»\0\0\0\0\0\0\0\80\ 6<Ø»\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\80Ù|6»\0\0\0\0\0\0\0\80Ö\92\99»\0\0\0\0\0\0\0\80¼¶l»\0\0\0\0\0\0\0\80bx\82»\0\0\0\0\0\0\0\80ªÞ®»\0\0\0\0\0\0\0\80\90\9aÆ»\0\0\0\0\0\0\0\804+®»\0\0\0\0\0\0\0\80Ø*\ 2¼\0\0\0\0\0\0\0\80\ 3\95\ 6¼\0\0\0\0\0\0\0\80ä÷\r¼\0\0\0\0\0\0\0\80ïS\v¼\0\0\0\0\0\0\0\80rjÈ»\0\0\0\0\0\0\0\80:âï»\0\0\0\0\0\0\0\80h\96\ 3¼\0\0\0\0\0\0\0\80úlÕ»\0\0\0\0\0\0\0\80\ 6éç»\0\0\0\0\0\0\0\80úÍõ»\0\0\0\0\0\0\0\80\ 3\95\ 6¼\0\0\0\0\0\0\0\80Ø*\ 2¼\0\0\0\0\0\0\0\80Ö\92\99»\0\0\0\0\0\0\0\80!w²»\0\0\0\0\0\0\0\80:âï»\0\0\0\0\0\0\0\80rjÈ»\0\0\0\0\0\0\0\80\90\9aÆ»\0\0\0\0\0\0\0\80\90\9aÛ»\0\0\0\0\0\0\0\80úÍõ»\0\0\0\0\0\0\0\80\ 6éç»\0\0\0\0\0\0\0\80Ù|6»\0\0\0\0\0\0\0\80\16ºN»\0\0\0\0\0\0\0\80!w²»\0\0\0\0\0\0\0\80Ö\92\99»\0\0\0\0\0\0\0\80ªÞ®»\0\0\0\0\0\0\0\80D\ 3Ú»\0\0\0\0\0\0\0\80\90\9aÛ»\0\0\0\0\0\0\0\80\90\9aÆ»\0\0\0\0\0\0\0\80\8aº\0\0\0\0\0\0\0\80\7fä\98º\0\0\0\0\0\0\0\80\16ºN»\0\0\0\0\0\0\0\80Ù|6»\0\0\0\0\0\0\0\80²ù°»\0\0\0\0\0\0\0\80Hùè»\0\0\0\0\0\0\0\80D\ 3Ú»\0\0\0\0\0\0\0\80ªÞ®»\0\0\0\0\0\0\0\80¸n·»\0\0\0\0\0\0\0\80\84?è»\0\0\0\0\0\0\0\80Hùè»\0\0\0\0\0\0\0\80²ù°»\0\0\0\0\0\0\0\80ã>\b¼@}
\0\0\0\806\9b        ¼\0&ܶ\0\0\0\80w'Ú»\f%G¹\0\0\0\80LóÙ»ô«D¹\0\0\0\80HçÅ»\0\0\0\0\0\0\0\80juö»\0\0\0\0\0\0\0\80\84?è»\0\0\0\0\0\0\0\80¸n·»\0\0\0\0\0\0\0\80ïS\v¼\0\0\0\0\0\0\0\80ä÷\r¼\0\0\0\0\0\0\0\806\9b     ¼\0&ܶ\0\0\0\80ã>\b¼@}
\0\0\0\80úlÕ»\0\0\0\0\0\0\0\80h\96\ 3¼\0\0\0\0\0\0\0\80juö»\0\0\0\0\0\0\0\80HçÅ»\0\0\0\0\0\0\0\80Hùè»\0\0\0\0\0\0\0\80\ 2.\ 4¼\0\0\0\0\0\0\0\80Pûò»\0\0\0\0\0\0\0\80D\ 3Ú»\0\0\0\0\0\0\0\80\84?è»\0\0\0\0\0\0\0\80î\97\ 3¼\0\0\0\0\0\0\0\80\ 2.\ 4¼\0\0\0\0\0\0\0\80Hùè»\0\0\0\0\0\0\0\806\9b        ¼\0&ܶ\0\0\0\80\98ÿ\b¼\0\92\ 6·\0\0\0\80\1a\80Ö»8+U¹\0\0\0\80w'Ú»\f%G¹\0\0\0\80juö»\0\0\0\0\0\0\0\80O\v\b¼\0\0\0\0\0\0\0\80î\97\ 3¼\0\0\0\0\0\0\0\80\84?è»\0\0\0\0\0\0\0\80ä÷\r¼\0\0\0\0\0\0\0\80\91Þ\ f¼\0\0\0\0\0\0\0\80\98ÿ\b¼\0\92\ 6·\0\0\0\806\9b     ¼\0&ܶ\0\0\0\80h\96\ 3¼\0\0\0\0\0\0\0\80ø-\ e¼\0\0\0\0\0\0\0\80O\v\b¼\0\0\0\0\0\0\0\80juö»\0\0\0\0\0\0\0\80\ 3\95\ 6¼\0\0\0\0\0\0\0\80\10{
\0\0\0\0\0\0\0\80\91Þ\ f¼\0\0\0\0\0\0\0\80ä÷\r¼\0\0\0\0\0\0\0\80:âï»\0\0\0\0\0\0\0\80iÑþ»\0\0\0\0\0\0\0\80ø-\ e¼\0\0\0\0\0\0\0\80h\96\ 3¼\0\0\0\0\0\0\0\80úÍõ»\0\0\0\0\0\0\0\80°`\0¼\0\0\0\0\0\0\0\80\10{
\0\0\0\0\0\0\0\80\ 3\95\ 6¼\0\0\0\0\0\0\0\80!w²»\0\0\0\0\0\0\0\80z~»»\0\0\0\0\0\0\0\80iÑþ»\0\0\0\0\0\0\0\80:âï»\0\0\0\0\0\0\0\80\90\9aÛ»\0\0\0\0\0\0\0\80¶ìé»\0\0\0\0\0\0\0\80°`\0¼\0\0\0\0\0\0\0\80úÍõ»\0\0\0\0\0\0\0\80\16ºN»\0\0\0\0\0\0\0\80*UW»\0\0\0\0\0\0\0\80z~»»\0\0\0\0\0\0\0\80!w²»\0\0\0\0\0\0\0\80D\ 3Ú»\0\0\0\0\0\0\0\80Pûò»\0\0\0\0\0\0\0\80¶ìé»\0\0\0\0\0\0\0\80\90\9aÛ»\0\0\0\0\0\0\0\80\7fä\98º\0\0\0\0\0\0\0\80íÑ\9dº\0\0\0\0\0\0\0\80*UW»\0\0\0\0\0\0\0\80\16ºN»\0\0\0\0\0\0\0\80iÑþ»\0\0\0\0\0\0\0\80§ßñ»\0\0\0\0\0\0\0\80\18\9a\b¼\0\0\0\0\0\0\0\80ø-\ e¼\0\0\0\0\0\0\0\80°`\0¼\0\0\0\0\0\0\0\80æè\ 1¼\0\0\0\0\0\0\0\80Z-\f¼\0\0\0\0\0\0\0\80\10{
\0\0\0\0\0\0\0\80z~»»\0\0\0\0\0\0\0\80"w²»\0\0\0\0\0\0\0\80§ßñ»\0\0\0\0\0\0\0\80iÑþ»\0\0\0\0\0\0\0\80¶ìé»\0\0\0\0\0\0\0\80¨¡ã»\0\0\0\0\0\0\0\80æè\ 1¼\0\0\0\0\0\0\0\80°`\0¼\0\0\0\0\0\0\0\80*UW»\0\0\0\0\0\0\0\80\17ºN»\0\0\0\0\0\0\0\80"w²»\0\0\0\0\0\0\0\80z~»»\0\0\0\0\0\0\0\80Pûò»\0\0\0\0\0\0\0\80\aÐâ»\0\0\0\0\0\0\0\80¨¡ã»\0\0\0\0\0\0\0\80¶ìé»\0\0\0\0\0\0\0\80íÑ\9dº\0\0\0\0\0\0\0\80\7fä\98º\0\0\0\0\0\0\0\80\17ºN»\0\0\0\0\0\0\0\80*UW»\0\0\0\0\0\0\0\80\ 2.\ 4¼\0\0\0\0\0\0\0\80\86Ñ\0¼\0\0\0\0\0\0\0\80\aÐâ»\0\0\0\0\0\0\0\80Pûò»\0\0\0\0\0\0\0\80î\97\ 3¼\0\0\0\0\0\0\0\80Êí\a¼\0\0\0\0\0\0\0\80\86Ñ\0¼\0\0\0\0\0\0\0\80\ 2.\ 4¼\0\0\0\0\0\0\0\80\98ÿ\b¼\0\92\ 6·\0\0\0\80\7f\96\ 5¼\0¼\82·\0\0\0\80âÇλð+p¹\0\0\0\80\1a\80Ö»8+U¹\0\0\0\80O\v\b¼\0\0\0\0\0\0\0\80ö\e        ¼\0\0\0\0\0\0\0\80Êí\a¼\0\0\0\0\0\0\0\80î\97\ 3¼\0\0\0\0\0\0\0\80\91Þ\ f¼\0\0\0\0\0\0\0\80\ f¼\0\0\0\0\0\0\0\80\7f\96\ 5¼\0¼\82·\0\0\0\80\98ÿ\b¼\0\92\ 6·\0\0\0\80ø-\ e¼\0\0\0\0\0\0\0\80\18\9a\b¼\0\0\0\0\0\0\0\80ö\e     ¼\0\0\0\0\0\0\0\80O\v\b¼\0\0\0\0\0\0\0\80\10{
\0\0\0\0\0\0\0\80Z-\f¼\0\0\0\0\0\0\0\80\ f¼\0\0\0\0\0\0\0\80\91Þ\ f¼\0\0\0\0\0\0\0\80Êí\a¼\0\0\0\0\0\0\0\80}2é»\0\0\0\0\0\0\0\80\ 4YÁ»\0\0\0\0\0\0\0\80\86Ñ\0¼\0\0\0\0\0\0\0\80\7f\96\ 5¼\0¼\82·\0\0\0\80\80Ðû»\80ý\1e¸\0\0\0\80¤\ 6ûL®\8c¹\0\0\0\80âÇλð+p¹\0\0\0\80ö\e        ¼\0\0\0\0\0\0\0\80<Võ»\0\0\0\0\0\0\0\80}2é»\0\0\0\0\0\0\0\80Êí\a¼\0\0\0\0\0\0\0\80\ f¼\0\0\0\0\0\0\0\80©^
\0\0\0\0\0\0\0\80\80Ðû»\80ý\1e¸\0\0\0\80\7f\96\ 5¼\0¼\82·\0\0\0\80\18\9a\b¼\0\0\0\0\0\0\0\80øIí»\0\0\0\0\0\0\0\80<Võ»\0\0\0\0\0\0\0\80ö\e        ¼\0\0\0\0\0\0\0\80Z-\f¼\0\0\0\0\0\0\0\80\7fº\a¼\0\0\0\0\0\0\0\80©^
\0\0\0\0\0\0\0\80\ f¼\0\0\0\0\0\0\0\80§ßñ»\0\0\0\0\0\0\0\80\ 2bÍ»\0\0\0\0\0\0\0\80øIí»\0\0\0\0\0\0\0\80\18\9a\b¼\0\0\0\0\0\0\0\80æè\ 1¼\0\0\0\0\0\0\0\80`\1cò»\0\0\0\0\0\0\0\80\7fº\a¼\0\0\0\0\0\0\0\80Z-\f¼\0\0\0\0\0\0\0\80"w²»\0\0\0\0\0\0\0\80Ñ\92\99»\0\0\0\0\0\0\0\80\ 2bÍ»\0\0\0\0\0\0\0\80§ßñ»\0\0\0\0\0\0\0\80¨¡ã»\0\0\0\0\0\0\0\80ºß¿»\0\0\0\0\0\0\0\80`\1cò»\0\0\0\0\0\0\0\80æè\ 1¼\0\0\0\0\0\0\0\80\17ºN»\0\0\0\0\0\0\0\80Ú|6»\0\0\0\0\0\0\0\80Ñ\92\99»\0\0\0\0\0\0\0\80"w²»\0\0\0\0\0\0\0\80\aÐâ»\0\0\0\0\0\0\0\80/Q¨»\0\0\0\0\0\0\0\80ºß¿»\0\0\0\0\0\0\0\80¨¡ã»\0\0\0\0\0\0\0\80\7fä\98º\0\0\0\0\0\0\0\80\8aº\0\0\0\0\0\0\0\80Ú|6»\0\0\0\0\0\0\0\80\17ºN»\0\0\0\0\0\0\0\80\86Ñ\0¼\0\0\0\0\0\0\0\80\ 4YÁ»\0\0\0\0\0\0\0\80/Q¨»\0\0\0\0\0\0\0\80\aÐâ»\0\0\0\0\0\0\0\80Ñ\92\99»\0\0\0\0\0\0\0\80½¶l»\0\0\0\0\0\0\0\80}'\95»\0\0\0\0\0\0\0\80\ 2bÍ»\0\0\0\0\0\0\0\80ºß¿»\0\0\0\0\0\0\0\80e1\87»\0\0\0\0\0\0\0\80*\9aû\0\0\0\0\0\0\0\80`\1cò»\0\0\0\0\0\0\0\80Ú|6»\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\80½¶l»\0\0\0\0\0\0\0\80Ñ\92\99»\0\0\0\0\0\0\0\80/Q¨»\0\0\0\0\0\0\0\80\89\7f\0\0\0\0\0\0\0\80e1\87»\0\0\0\0\0\0\0\80ºß¿»\0\0\0\0\0\0\0\80\8aº\0\0\0\0\0\0\0\80\81üjº\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\80Ú|6»\0\0\0\0\0\0\0\80\ 4YÁ»\0\0\0\0\0\0\0\80\86$4»\0\0\0\0\0\0\0\80\89\7f\0\0\0\0\0\0\0\80/Q¨»\0\0\0\0\0\0\0\80}2é»\0\0\0\0\0\0\0\80®¨\86»\0\0\0\0\0\0\0\80\86$4»\0\0\0\0\0\0\0\80\ 4YÁ»\0\0\0\0\0\0\0\80\80Ðû»\80ý\1e¸\0\0\0\805"á»\80}¼¸\0\0\0\80,ʳ»|E¨¹\0\0\0\80¤\ 6ûL®\8c¹\0\0\0\80<Võ»\0\0\0\0\0\0\0\80µÎ£»\0\0\0\0\0\0\0\80®¨\86»\0\0\0\0\0\0\0\80}2é»\0\0\0\0\0\0\0\80©^
\0\0\0\0\0\0\0\80\ 3\ e÷»\0\0\0\0\0\0\0\805"á»\80}¼¸\0\0\0\80\80Ðû»\80ý\1e¸\0\0\0\80øIí»\0\0\0\0\0\0\0\80\1aQ§»\0\0\0\0\0\0\0\80µÎ£»\0\0\0\0\0\0\0\80<Võ»\0\0\0\0\0\0\0\80\7fº\a¼\0\0\0\0\0\0\0\80þ\1dî»\0\0\0\0\0\0\0\80\ 3\ e÷»\0\0\0\0\0\0\0\80©^
\0\0\0\0\0\0\0\80\ 2bÍ»\0\0\0\0\0\0\0\80}'\95»\0\0\0\0\0\0\0\80\1aQ§»\0\0\0\0\0\0\0\80øIí»\0\0\0\0\0\0\0\80`\1cò»\0\0\0\0\0\0\0\80*\9aû\0\0\0\0\0\0\0\80þ\1dî»\0\0\0\0\0\0\0\80\7fº\a¼\0\0\0\0\0\0\0\805"á»\80}¼¸\0\0\0\80`×»»ð6?¹\0\0\0\80Om¢»\10]ɹ\0\0\0\80,ʳ»|E¨¹\0\0\0\80µÎ£»\0\0\0\0\0\0\0\80Òº\ 3»\0\0\0\0\0\0\0\80ûO\95º\0\0\0\0\0\0\0\80®¨\86»\0\0\0\0\0\0\0\80\ 3\ e÷»\0\0\0\0\0\0\0\80¼òû\80\9f\0\0\0\80`×»»ð6?¹\0\0\0\805"á»\80}¼¸\0\0\0\80\1aQ§»\0\0\0\0\0\0\0\80T?+»\0\0\0\0\0\0\0\80Òº\ 3»\0\0\0\0\0\0\0\80µÎ£»\0\0\0\0\0\0\0\80þ\1dî»\0\0\0\0\0\0\0\80Dð±»\0\0\0\0\0\0\0\80¼òû\80\9f\0\0\0\80\ 3\ e÷»\0\0\0\0\0\0\0\80}'\95»\0\0\0\0\0\0\0\80â58»\0\0\0\0\0\0\0\80T?+»\0\0\0\0\0\0\0\80\1aQ§»\0\0\0\0\0\0\0\80*\9aû\0\0\0\0\0\0\0\805L\83»\0\0\0\0\0\0\0\80Dð±»\0\0\0\0\0\0\0\80þ\1dî»\0\0\0\0\0\0\0\80½¶l»\0\0\0\0\0\0\0\80,`\1f»\0\0\0\0\0\0\0\80â58»\0\0\0\0\0\0\0\80}'\95»\0\0\0\0\0\0\0\80e1\87»\0\0\0\0\0\0\0\80®>\16»\0\0\0\0\0\0\0\805L\83»\0\0\0\0\0\0\0\80*\9aû\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\80:êÓº\0\0\0\0\0\0\0\80,`\1f»\0\0\0\0\0\0\0\80½¶l»\0\0\0\0\0\0\0\80\89\7f\0\0\0\0\0\0\0\802\11\0\0\0\0\0\0\0\80®>\16»\0\0\0\0\0\0\0\80e1\87»\0\0\0\0\0\0\0\80\81üjº\0\0\0\0\0\0\0\80¬¤7º\0\0\0\0\0\0\0\80:êÓº\0\0\0\0\0\0\0\80\12»\0\0\0\0\0\0\0\80\86$4»\0\0\0\0\0\0\0\80\b\r͹\0\0\0\0\0\0\0\802\11\0\0\0\0\0\0\0\80\89\7f\0\0\0\0\0\0\0\80®¨\86»\0\0\0\0\0\0\0\80ûO\95º\0\0\0\0\0\0\0\80\b\r͹\0\0\0\0\0\0\0\80\86$4»\0\0\0\0\0\0\0\80®>\16»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\805L\83»\0\0\0\0\0\0\0\80:êÓº\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80,`\1f»\0\0\0\0\0\0\0\802\11\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80®>\16»\0\0\0\0\0\0\0\80¬¤7º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80:êÓº\0\0\0\0\0\0\0\80\b\r͹\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\802\11\0\0\0\0\0\0\0\80ûO\95º\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\b\r͹\0\0\0\0\0\0\0\80`×»»ð6?¹\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80\0\0\0\0d\94\0\0\0\80Om¢»\10]ɹ\0\0\0\80Òº\ 3»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ûO\95º\0\0\0\0\0\0\0\80¼òû\80\9f\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80`×»»ð6?¹\0\0\0\80T?+»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Òº\ 3»\0\0\0\0\0\0\0\80Dð±»\0\0\0\0\0\0\0\80\0\0\0\0\0±ß¸\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80¼òû\80\9f\0\0\0\80â58»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80T?+»\0\0\0\0\0\0\0\805L\83»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0±ß¸\0\0\0\80Dð±»\0\0\0\0\0\0\0\80,`\1f»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80â58»\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Öº\ 3;\0\0\0\0\0\0\0\80ïO\95:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80¾òÃ;\80\9f\0\0\0\80b×»;\107?¹\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80L?+;\0\0\0\0\0\0\0\80Öº\ 3;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0±ß¸\0\0\0\80Bð±;\0\0\0\0\0\0\0\80¾òÃ;\80\9f\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ß58;\0\0\0\0\0\0\0\80L?+;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\802L\83;\0\0\0\0\0\0\0\80Bð±;\0\0\0\0\0\0\0\80\0\0\0\0\0±ß¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80+`\1f;\0\0\0\0\0\0\0\80ß58;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80´>\16;\0\0\0\0\0\0\0\802L\83;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80>êÓ:\0\0\0\0\0\0\0\80+`\1f;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\1a\11U:\0\0\0\0\0\0\0\80´>\16;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80®¤7:\0\0\0\0\0\0\0\80>êÓ:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Ä\fÍ9\0\0\0\0\0\0\0\80\1a\11U:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ïO\95:\0\0\0\0\0\0\0\80Ä\fÍ9\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80b×»;\107?¹\0\0\0\80Om¢;\1c]ɹ\0\0\0\80\0\0\0\0d\94\0\0\0\80>êÓ:\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80½¶l;\0\0\0\0\0\0\0\80+`\1f;\0\0\0\0\0\0\0\80\1a\11U:\0\0\0\0\0\0\0\80\84\7f.;\0\0\0\0\0\0\0\80h1\87;\0\0\0\0\0\0\0\80´>\16;\0\0\0\0\0\0\0\80®¤7:\0\0\0\0\0\0\0\80\86üj:\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80>êÓ:\0\0\0\0\0\0\0\80Ä\fÍ9\0\0\0\0\0\0\0\80~$4;\0\0\0\0\0\0\0\80\84\7f.;\0\0\0\0\0\0\0\80\1a\11U:\0\0\0\0\0\0\0\80ïO\95:\0\0\0\0\0\0\0\80¬¨\86;\0\0\0\0\0\0\0\80~$4;\0\0\0\0\0\0\0\80Ä\fÍ9\0\0\0\0\0\0\0\80b×»;\107?¹\0\0\0\807"á;\0~¼¸\0\0\0\80-ʳ;\8cE¨¹\0\0\0\80Om¢;\1c]ɹ\0\0\0\80Öº\ 3;\0\0\0\0\0\0\0\80¸Î£;\0\0\0\0\0\0\0\80¬¨\86;\0\0\0\0\0\0\0\80ïO\95:\0\0\0\0\0\0\0\80¾òÃ;\80\9f\0\0\0\80\ 2\ e÷;\0\0\0\0\0\0\0\807"á;\0~¼¸\0\0\0\80b×»;\107?¹\0\0\0\80L?+;\0\0\0\0\0\0\0\80\16Q§;\0\0\0\0\0\0\0\80¸Î£;\0\0\0\0\0\0\0\80Öº\ 3;\0\0\0\0\0\0\0\80Bð±;\0\0\0\0\0\0\0\80ý\1dî;\0\0\0\0\0\0\0\80\ 2\ e÷;\0\0\0\0\0\0\0\80¾òÃ;\80\9f\0\0\0\80ß58;\0\0\0\0\0\0\0\80|'\95;\0\0\0\0\0\0\0\80\16Q§;\0\0\0\0\0\0\0\80L?+;\0\0\0\0\0\0\0\802L\83;\0\0\0\0\0\0\0\80(\9aÃ;\0\0\0\0\0\0\0\80ý\1dî;\0\0\0\0\0\0\0\80Bð±;\0\0\0\0\0\0\0\80+`\1f;\0\0\0\0\0\0\0\80½¶l;\0\0\0\0\0\0\0\80|'\95;\0\0\0\0\0\0\0\80ß58;\0\0\0\0\0\0\0\80´>\16;\0\0\0\0\0\0\0\80h1\87;\0\0\0\0\0\0\0\80(\9aÃ;\0\0\0\0\0\0\0\802L\83;\0\0\0\0\0\0\0\80\ 2\ e÷;\0\0\0\0\0\0\0\80ª^
+<\0\0\0\0\0\0\0\80\82Ðû;Àþ\1e¸\0\0\0\807"á;\0~¼¸\0\0\0\80\16Q§;\0\0\0\0\0\0\0\80ùIí;\0\0\0\0\0\0\0\80@Võ;\0\0\0\0\0\0\0\80¸Î£;\0\0\0\0\0\0\0\80ý\1dî;\0\0\0\0\0\0\0\80\80º\a<\0\0\0\0\0\0\0\80ª^
+<\0\0\0\0\0\0\0\80\ 2\ e÷;\0\0\0\0\0\0\0\80|'\95;\0\0\0\0\0\0\0\80\ 3bÍ;\0\0\0\0\0\0\0\80ùIí;\0\0\0\0\0\0\0\80\16Q§;\0\0\0\0\0\0\0\80(\9aÃ;\0\0\0\0\0\0\0\80a\1cò;\0\0\0\0\0\0\0\80\80º\a<\0\0\0\0\0\0\0\80ý\1dî;\0\0\0\0\0\0\0\80½¶l;\0\0\0\0\0\0\0\80Ò\92\99;\0\0\0\0\0\0\0\80\ 3bÍ;\0\0\0\0\0\0\0\80|'\95;\0\0\0\0\0\0\0\80h1\87;\0\0\0\0\0\0\0\80¾ß¿;\0\0\0\0\0\0\0\80a\1cò;\0\0\0\0\0\0\0\80(\9aÃ;\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80Ý|6;\0\0\0\0\0\0\0\80Ò\92\99;\0\0\0\0\0\0\0\80½¶l;\0\0\0\0\0\0\0\80\84\7f.;\0\0\0\0\0\0\0\80.Q¨;\0\0\0\0\0\0\0\80¾ß¿;\0\0\0\0\0\0\0\80h1\87;\0\0\0\0\0\0\0\80\86üj:\0\0\0\0\0\0\0\80\8a:\0\0\0\0\0\0\0\80Ý|6;\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80~$4;\0\0\0\0\0\0\0\80\ 2YÁ;\0\0\0\0\0\0\0\80.Q¨;\0\0\0\0\0\0\0\80\84\7f.;\0\0\0\0\0\0\0\80¬¨\86;\0\0\0\0\0\0\0\80|2é;\0\0\0\0\0\0\0\80\ 2YÁ;\0\0\0\0\0\0\0\80~$4;\0\0\0\0\0\0\0\807"á;\0~¼¸\0\0\0\80\82Ðû;Àþ\1e¸\0\0\0\80¤\ 6Ã;`®\8c¹\0\0\0\80-ʳ;\8cE¨¹\0\0\0\80¸Î£;\0\0\0\0\0\0\0\80@Võ;\0\0\0\0\0\0\0\80|2é;\0\0\0\0\0\0\0\80¬¨\86;\0\0\0\0\0\0\0\80.Q¨;\0\0\0\0\0\0\0\80      Ðâ;\0\0\0\0\0\0\0\80­¡ã;\0\0\0\0\0\0\0\80¾ß¿;\0\0\0\0\0\0\0\80\8a:\0\0\0\0\0\0\0\80\84ä\98:\0\0\0\0\0\0\0\80\eºN;\0\0\0\0\0\0\0\80Ý|6;\0\0\0\0\0\0\0\80\ 2YÁ;\0\0\0\0\0\0\0\80\85Ñ\0<\0\0\0\0\0\0\0\80     Ðâ;\0\0\0\0\0\0\0\80.Q¨;\0\0\0\0\0\0\0\80|2é;\0\0\0\0\0\0\0\80Êí\a<\0\0\0\0\0\0\0\80\85Ñ\0<\0\0\0\0\0\0\0\80\ 2YÁ;\0\0\0\0\0\0\0\80\82Ðû;Àþ\1e¸\0\0\0\80\80\96\ 5<\80¿\82·\0\0\0\80æÇÎ; ,p¹\0\0\0\80¤\ 6Ã;`®\8c¹\0\0\0\80@Võ;\0\0\0\0\0\0\0\80ø\e   <\0\0\0\0\0\0\0\80Êí\a<\0\0\0\0\0\0\0\80|2é;\0\0\0\0\0\0\0\80ª^
+<\0\0\0\0\0\0\0\80\ f<\0\0\0\0\0\0\0\80\80\96\ 5<\80¿\82·\0\0\0\80\82Ðû;Àþ\1e¸\0\0\0\80ùIí;\0\0\0\0\0\0\0\80\18\9a\b<\0\0\0\0\0\0\0\80ø\e        <\0\0\0\0\0\0\0\80@Võ;\0\0\0\0\0\0\0\80\80º\a<\0\0\0\0\0\0\0\80[-\f<\0\0\0\0\0\0\0\80\ f<\0\0\0\0\0\0\0\80ª^
+<\0\0\0\0\0\0\0\80\ 3bÍ;\0\0\0\0\0\0\0\80¨ßñ;\0\0\0\0\0\0\0\80\18\9a\b<\0\0\0\0\0\0\0\80ùIí;\0\0\0\0\0\0\0\80a\1cò;\0\0\0\0\0\0\0\80æè\ 1<\0\0\0\0\0\0\0\80[-\f<\0\0\0\0\0\0\0\80\80º\a<\0\0\0\0\0\0\0\80Ò\92\99;\0\0\0\0\0\0\0\80$w²;\0\0\0\0\0\0\0\80¨ßñ;\0\0\0\0\0\0\0\80\ 3bÍ;\0\0\0\0\0\0\0\80¾ß¿;\0\0\0\0\0\0\0\80­¡ã;\0\0\0\0\0\0\0\80æè\ 1<\0\0\0\0\0\0\0\80a\1cò;\0\0\0\0\0\0\0\80Ý|6;\0\0\0\0\0\0\0\80\eºN;\0\0\0\0\0\0\0\80$w²;\0\0\0\0\0\0\0\80Ò\92\99;\0\0\0\0\0\0\0\80\18\9a\b<\0\0\0\0\0\0\0\80û-\ e<\0\0\0\0\0\0\0\80Q\v\b<\0\0\0\0\0\0\0\80ø\e        <\0\0\0\0\0\0\0\80[-\f<\0\0\0\0\0\0\0\80\12{
+<\0\0\0\0\0\0\0\80\92Þ\ f<\0\0\0\0\0\0\0\80\ f<\0\0\0\0\0\0\0\80¨ßñ;\0\0\0\0\0\0\0\80mÑþ;\0\0\0\0\0\0\0\80û-\ e<\0\0\0\0\0\0\0\80\18\9a\b<\0\0\0\0\0\0\0\80æè\ 1<\0\0\0\0\0\0\0\80²`\0<\0\0\0\0\0\0\0\80\12{
+<\0\0\0\0\0\0\0\80[-\f<\0\0\0\0\0\0\0\80$w²;\0\0\0\0\0\0\0\80}~»;\0\0\0\0\0\0\0\80mÑþ;\0\0\0\0\0\0\0\80¨ßñ;\0\0\0\0\0\0\0\80­¡ã;\0\0\0\0\0\0\0\80ºìé;\0\0\0\0\0\0\0\80²`\0<\0\0\0\0\0\0\0\80æè\ 1<\0\0\0\0\0\0\0\80\eºN;\0\0\0\0\0\0\0\801UW;\0\0\0\0\0\0\0\80}~»;\0\0\0\0\0\0\0\80$w²;\0\0\0\0\0\0\0\80  Ðâ;\0\0\0\0\0\0\0\80Tûò;\0\0\0\0\0\0\0\80ºìé;\0\0\0\0\0\0\0\80­¡ã;\0\0\0\0\0\0\0\80\84ä\98:\0\0\0\0\0\0\0\80ôÑ\9d:\0\0\0\0\0\0\0\801UW;\0\0\0\0\0\0\0\80\eºN;\0\0\0\0\0\0\0\80\85Ñ\0<\0\0\0\0\0\0\0\80\ 3.\ 4<\0\0\0\0\0\0\0\80Tûò;\0\0\0\0\0\0\0\80     Ðâ;\0\0\0\0\0\0\0\80Êí\a<\0\0\0\0\0\0\0\80ð\97\ 3<\0\0\0\0\0\0\0\80\ 3.\ 4<\0\0\0\0\0\0\0\80\85Ñ\0<\0\0\0\0\0\0\0\80\80\96\ 5<\80¿\82·\0\0\0\80\9bÿ\b<\0\99\ 6·\0\0\0\80\1c\80Ö;h+U¹\0\0\0\80æÇÎ; ,p¹\0\0\0\80ø\e   <\0\0\0\0\0\0\0\80Q\v\b<\0\0\0\0\0\0\0\80ð\97\ 3<\0\0\0\0\0\0\0\80Êí\a<\0\0\0\0\0\0\0\80\ f<\0\0\0\0\0\0\0\80\92Þ\ f<\0\0\0\0\0\0\0\80\9bÿ\b<\0\99\ 6·\0\0\0\80\80\96\ 5<\80¿\82·\0\0\0\80ôÑ\9d:\0\0\0\0\0\0\0\80\88ä\98:\0\0\0\0\0\0\0\80\1fºN;\0\0\0\0\0\0\0\801UW;\0\0\0\0\0\0\0\80\ 3.\ 4<\0\0\0\0\0\0\0\80Lùè;\0\0\0\0\0\0\0\80H\ 3Ú;\0\0\0\0\0\0\0\80Tûò;\0\0\0\0\0\0\0\80ð\97\ 3<\0\0\0\0\0\0\0\80\88?è;\0\0\0\0\0\0\0\80Lùè;\0\0\0\0\0\0\0\80\ 3.\ 4<\0\0\0\0\0\0\0\80\9bÿ\b<\0\99\ 6·\0\0\0\809\9b     <\03ܶ\0\0\0\80z'Ú;4%G¹\0\0\0\80\1c\80Ö;h+U¹\0\0\0\80Q\v\b<\0\0\0\0\0\0\0\80nuö;\0\0\0\0\0\0\0\80\88?è;\0\0\0\0\0\0\0\80ð\97\ 3<\0\0\0\0\0\0\0\80\92Þ\ f<\0\0\0\0\0\0\0\80æ÷\r<\0\0\0\0\0\0\0\809\9b     <\03ܶ\0\0\0\80\9bÿ\b<\0\99\ 6·\0\0\0\80û-\ e<\0\0\0\0\0\0\0\80l\96\ 3<\0\0\0\0\0\0\0\80nuö;\0\0\0\0\0\0\0\80Q\v\b<\0\0\0\0\0\0\0\80\12{
+<\0\0\0\0\0\0\0\80\ 5\95\ 6<\0\0\0\0\0\0\0\80æ÷\r<\0\0\0\0\0\0\0\80\92Þ\ f<\0\0\0\0\0\0\0\80mÑþ;\0\0\0\0\0\0\0\80>âï;\0\0\0\0\0\0\0\80l\96\ 3<\0\0\0\0\0\0\0\80û-\ e<\0\0\0\0\0\0\0\80²`\0<\0\0\0\0\0\0\0\80\ 1Îõ;\0\0\0\0\0\0\0\80\ 5\95\ 6<\0\0\0\0\0\0\0\80\12{
+<\0\0\0\0\0\0\0\80}~»;\0\0\0\0\0\0\0\80%w²;\0\0\0\0\0\0\0\80>âï;\0\0\0\0\0\0\0\80mÑþ;\0\0\0\0\0\0\0\80ºìé;\0\0\0\0\0\0\0\80\94\9aÛ;\0\0\0\0\0\0\0\80\ 1Îõ;\0\0\0\0\0\0\0\80²`\0<\0\0\0\0\0\0\0\801UW;\0\0\0\0\0\0\0\80\1fºN;\0\0\0\0\0\0\0\80%w²;\0\0\0\0\0\0\0\80}~»;\0\0\0\0\0\0\0\80Tûò;\0\0\0\0\0\0\0\80H\ 3Ú;\0\0\0\0\0\0\0\80\94\9aÛ;\0\0\0\0\0\0\0\80ºìé;\0\0\0\0\0\0\0\80>âï;\0\0\0\0\0\0\0\80vjÈ;\0\0\0\0\0\0\0\80\ 4mÕ;\0\0\0\0\0\0\0\80l\96\ 3<\0\0\0\0\0\0\0\80\ 1Îõ;\0\0\0\0\0\0\0\80\10éç;\0\0\0\0\0\0\0\80Ú*\ 2<\0\0\0\0\0\0\0\80\ 5\95\ 6<\0\0\0\0\0\0\0\80%w²;\0\0\0\0\0\0\0\80Û\92\99;\0\0\0\0\0\0\0\80vjÈ;\0\0\0\0\0\0\0\80>âï;\0\0\0\0\0\0\0\80\94\9aÛ;\0\0\0\0\0\0\0\80\94\9aÆ;\0\0\0\0\0\0\0\80\10éç;\0\0\0\0\0\0\0\80\ 1Îõ;\0\0\0\0\0\0\0\80\1fºN;\0\0\0\0\0\0\0\80ä|6;\0\0\0\0\0\0\0\80Û\92\99;\0\0\0\0\0\0\0\80%w²;\0\0\0\0\0\0\0\80H\ 3Ú;\0\0\0\0\0\0\0\80²Þ®;\0\0\0\0\0\0\0\80\94\9aÆ;\0\0\0\0\0\0\0\80\94\9aÛ;\0\0\0\0\0\0\0\80\88ä\98:\0\0\0\0\0\0\0\80\8a:\0\0\0\0\0\0\0\80ä|6;\0\0\0\0\0\0\0\80\1fºN;\0\0\0\0\0\0\0\80Lùè;\0\0\0\0\0\0\0\80¸ù°;\0\0\0\0\0\0\0\80²Þ®;\0\0\0\0\0\0\0\80H\ 3Ú;\0\0\0\0\0\0\0\80\88?è;\0\0\0\0\0\0\0\80Àn·;\0\0\0\0\0\0\0\80¸ù°;\0\0\0\0\0\0\0\80Lùè;\0\0\0\0\0\0\0\809\9b    <\03ܶ\0\0\0\80ç>\b\81
\0\0\0\80OóÙ;\10¬D¹\0\0\0\80z'Ú;4%G¹\0\0\0\80nuö;\0\0\0\0\0\0\0\80LçÅ;\0\0\0\0\0\0\0\80Àn·;\0\0\0\0\0\0\0\80\88?è;\0\0\0\0\0\0\0\80æ÷\r<\0\0\0\0\0\0\0\80òS\v<\0\0\0\0\0\0\0\80ç>\b\81
\0\0\0\809\9b        <\03ܶ\0\0\0\80l\96\ 3<\0\0\0\0\0\0\0\80\ 4mÕ;\0\0\0\0\0\0\0\80LçÅ;\0\0\0\0\0\0\0\80nuö;\0\0\0\0\0\0\0\80\ 5\95\ 6<\0\0\0\0\0\0\0\80Ú*\ 2<\0\0\0\0\0\0\0\80òS\v<\0\0\0\0\0\0\0\80æ÷\r<\0\0\0\0\0\0\0\80Àn·;\0\0\0\0\0\0\0\80Ì\8ah;\0\0\0\0\0\0\0\80LN[;\0\0\0\0\0\0\0\80¸ù°;\0\0\0\0\0\0\0\80ç>\b\81
\0\0\0\80ð\10\ 5<E«Z·\0\0\0\80Ò-Ö;3®L¹\0\0\0\80OóÙ;\10¬D¹\0\0\0\80LçÅ;\0\0\0\0\0\0\0\80âÛ\84;\0\0\0\0\0\0\0\80Ì\8ah;\0\0\0\0\0\0\0\80Àn·;\0\0\0\0\0\0\0\80òS\v<\0\0\0\0\0\0\0\80îý\a<\0\0\0\0\0\0\0\80ð\10\ 5<E«Z·\0\0\0\80ç>\b\81
\0\0\0\80\ 4mÕ;\0\0\0\0\0\0\0\80"-\95;\0\0\0\0\0\0\0\80âÛ\84;\0\0\0\0\0\0\0\80LçÅ;\0\0\0\0\0\0\0\80Ú*\ 2<\0\0\0\0\0\0\0\80µÇú;\0\0\0\0\0\0\0\80îý\a<\0\0\0\0\0\0\0\80òS\v<\0\0\0\0\0\0\0\80vjÈ;\0\0\0\0\0\0\0\80\1f]\93;\0\0\0\0\0\0\0\80"-\95;\0\0\0\0\0\0\0\80\ 4mÕ;\0\0\0\0\0\0\0\80\10éç;\0\0\0\0\0\0\0\80\12<Ø;\0\0\0\0\0\0\0\80µÇú;\0\0\0\0\0\0\0\80Ú*\ 2<\0\0\0\0\0\0\0\80Û\92\99;\0\0\0\0\0\0\0\80ȶl;\0\0\0\0\0\0\0\80\1f]\93;\0\0\0\0\0\0\0\80vjÈ;\0\0\0\0\0\0\0\80\94\9aÆ;\0\0\0\0\0\0\0\808+®;\0\0\0\0\0\0\0\80\12<Ø;\0\0\0\0\0\0\0\80\10éç;\0\0\0\0\0\0\0\80ä|6;\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80ȶl;\0\0\0\0\0\0\0\80Û\92\99;\0\0\0\0\0\0\0\80²Þ®;\0\0\0\0\0\0\0\80jx\82;\0\0\0\0\0\0\0\808+®;\0\0\0\0\0\0\0\80\94\9aÆ;\0\0\0\0\0\0\0\80\8a:\0\0\0\0\0\0\0\80\98üj:\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80ä|6;\0\0\0\0\0\0\0\80¸ù°;\0\0\0\0\0\0\0\80LN[;\0\0\0\0\0\0\0\80jx\82;\0\0\0\0\0\0\0\80²Þ®;\0\0\0\0\0\0\0\80\12<Ø;\0\0\0\0\0\0\0\80h\16È;\0\0\0\0\0\0\0\80\87
+ð;\0\0\0\0\0\0\0\80µÇú;\0\0\0\0\0\0\0\80ȶl;\0\0\0\0\0\0\0\80>`\1f;\0\0\0\0\0\0\0\80ê58;\0\0\0\0\0\0\0\80\1f]\93;\0\0\0\0\0\0\0\808+®;\0\0\0\0\0\0\0\80Ò\ 3\96;\0\0\0\0\0\0\0\80h\16È;\0\0\0\0\0\0\0\80\12<Ø;\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80TêÓ:\0\0\0\0\0\0\0\80>`\1f;\0\0\0\0\0\0\0\80ȶl;\0\0\0\0\0\0\0\80jx\82;\0\0\0\0\0\0\0\80dò>;\0\0\0\0\0\0\0\80Ò\ 3\96;\0\0\0\0\0\0\0\808+®;\0\0\0\0\0\0\0\80\98üj:\0\0\0\0\0\0\0\80º¤7:\0\0\0\0\0\0\0\80TêÓ:\0\0\0\0\0\0\0\80\12;\0\0\0\0\0\0\0\80LN[;\0\0\0\0\0\0\0\80HVÂ:\0\0\0\0\0\0\0\80dò>;\0\0\0\0\0\0\0\80jx\82;\0\0\0\0\0\0\0\80Ì\8ah;\0\0\0\0\0\0\0\80\0̲:\0\0\0\0\0\0\0\80HVÂ:\0\0\0\0\0\0\0\80LN[;\0\0\0\0\0\0\0\80ð\10\ 5<E«Z·\0\0\0\80\90\8cÿ; M½·\0\0\0\80q\84Î;H\13\0\0\0\80Ò-Ö;3®L¹\0\0\0\80âÛ\84;\0\0\0\0\0\0\0\80\90\88ÿ:\0\0\0\0\0\0\0\80\0̲:\0\0\0\0\0\0\0\80Ì\8ah;\0\0\0\0\0\0\0\80îý\a<\0\0\0\0\0\0\0\80b1\ 3<\0\0\0\0\0\0\0\80\90\8cÿ; M½·\0\0\0\80ð\10\ 5<E«Z·\0\0\0\80"-\95;\0\0\0\0\0\0\0\80\183*;\0\0\0\0\0\0\0\80\90\88ÿ:\0\0\0\0\0\0\0\80âÛ\84;\0\0\0\0\0\0\0\80µÇú;\0\0\0\0\0\0\0\80\87
+ð;\0\0\0\0\0\0\0\80b1\ 3<\0\0\0\0\0\0\0\80îý\a<\0\0\0\0\0\0\0\80\1f]\93;\0\0\0\0\0\0\0\80ê58;\0\0\0\0\0\0\0\80\183*;\0\0\0\0\0\0\0\80"-\95;\0\0\0\0\0\0\0\80\0̲:\0\0\0\0\0\0\0\80À»\ 49\0\0\0\0\0\0\0\800Ç,:\0\0\0\0\0\0\0\80HVÂ:\0\0\0\0\0\0\0\80\90\8cÿ; M½·\0\0\0\80¦ëï;@-)¸\0\0\0\80 \9eÂ;¾1\80¹\0\0\0\80q\84Î;H\13\0\0\0\80\90\88ÿ:\0\0\0\0\0\0\0\80
+:\0\0\0\0\0\0\0\80À»\ 49\0\0\0\0\0\0\0\80\0̲:\0\0\0\0\0\0\0\80b1\ 3<\0\0\0\0\0\0\0\80å\91ø;\0\0\0\0\0\0\0\80¦ëï;@-)¸\0\0\0\80\90\8cÿ; M½·\0\0\0\80\183*;\0\0\0\0\0\0\0\80\87:\0\0\0\0\0\0\0\80
+:\0\0\0\0\0\0\0\80\90\88ÿ:\0\0\0\0\0\0\0\80\87
+ð;\0\0\0\0\0\0\0\80ã_ä;\0\0\0\0\0\0\0\80å\91ø;\0\0\0\0\0\0\0\80b1\ 3<\0\0\0\0\0\0\0\80ê58;\0\0\0\0\0\0\0\80$@²:\0\0\0\0\0\0\0\80\87:\0\0\0\0\0\0\0\80\183*;\0\0\0\0\0\0\0\80h\16È;\0\0\0\0\0\0\0\80'ôº;\0\0\0\0\0\0\0\80ã_ä;\0\0\0\0\0\0\0\80\87
+ð;\0\0\0\0\0\0\0\80>`\1f;\0\0\0\0\0\0\0\80`´°:\0\0\0\0\0\0\0\80$@²:\0\0\0\0\0\0\0\80ê58;\0\0\0\0\0\0\0\80Ò\ 3\96;\0\0\0\0\0\0\0\80"u\84;\0\0\0\0\0\0\0\80'ôº;\0\0\0\0\0\0\0\80h\16È;\0\0\0\0\0\0\0\80TêÓ:\0\0\0\0\0\0\0\80¼è\83:\0\0\0\0\0\0\0\80`´°:\0\0\0\0\0\0\0\80>`\1f;\0\0\0\0\0\0\0\80dò>;\0\0\0\0\0\0\0\80ôA\ f;\0\0\0\0\0\0\0\80"u\84;\0\0\0\0\0\0\0\80Ò\ 3\96;\0\0\0\0\0\0\0\80º¤7:\0\0\0\0\0\0\0\80\ 2:\0\0\0\0\0\0\0\80¼è\83:\0\0\0\0\0\0\0\80TêÓ:\0\0\0\0\0\0\0\80HVÂ:\0\0\0\0\0\0\0\800Ç,:\0\0\0\0\0\0\0\80ôA\ f;\0\0\0\0\0\0\0\80dò>;\0\0\0\0\0\0\0\80`´°:\0\0\0\0\0\0\0\80\0\90       :\0\0\0\0\0\0\0\80PìÄ9\0\0\0\0\0\0\0\80$@²:\0\0\0\0\0\0\0\80"u\84;\0\0\0\0\0\0\0\80\9eëq;\0\0\0\0\0\0\0\80ÿj¯;\0\0\0\0\0\0\0\80'ôº;\0\0\0\0\0\0\0\80¼è\83:\0\0\0\0\0\0\0\80\f0\ 2:\0\0\0\0\0\0\0\80\0\90     :\0\0\0\0\0\0\0\80`´°:\0\0\0\0\0\0\0\80ôA\ f;\0\0\0\0\0\0\0\80°äú:\0\0\0\0\0\0\0\80\9eëq;\0\0\0\0\0\0\0\80"u\84;\0\0\0\0\0\0\0\80\ 2:\0\0\0\0\0\0\0\80¤\96¡9\0\0\0\0\0\0\0\80\f0\ 2:\0\0\0\0\0\0\0\80¼è\83:\0\0\0\0\0\0\0\800Ç,:\0\0\0\0\0\0\0\80ð~&:\0\0\0\0\0\0\0\80°äú:\0\0\0\0\0\0\0\80ôA\ f;\0\0\0\0\0\0\0\80À»\ 49\0\0\0\0\0\0\0\80\0þ@8\0\0\0\0\0\0\0\80ð~&:\0\0\0\0\0\0\0\800Ç,:\0\0\0\0\0\0\0\80¦ëï;@-)¸\0\0\0\80\92\1aØ; A\9e¸\0\0\0\80\81²;"ý\96¹\0\0\0\80 \9eÂ;¾1\80¹\0\0\0\80
+:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0þ@8\0\0\0\0\0\0\0\80À»\ 49\0\0\0\0\0\0\0\80å\91ø;\0\0\0\0\0\0\0\80àÚá;\0\0\0\0\0\80\92\1aØ; A\9e¸\0\0\0\80¦ëï;@-)¸\0\0\0\80\87:\0\0\0\0\0\0\0\80À\89\159\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80
+:\0\0\0\0\0\0\0\80ã_ä;\0\0\0\0\0\0\0\80w{Ó;\0\0\0\0\0\0\0\80àÚá;\0\0\0\0\0\80å\91ø;\0\0\0\0\0\0\0\80$@²:\0\0\0\0\0\0\0\80PìÄ9\0\0\0\0\0\0\0\80À\89\159\0\0\0\0\0\0\0\80\87:\0\0\0\0\0\0\0\80'ôº;\0\0\0\0\0\0\0\80ÿj¯;\0\0\0\0\0\0\0\80w{Ó;\0\0\0\0\0\0\0\80ã_ä;\0\0\0\0\0\0\0\80\92\1aØ; A\9e¸\0\0\0\80²\8f·;À÷\ e¹\0\0\0\80\8c®\9f;$á³¹\0\0\0\80\81²;"ý\96¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0£Õ7\0\0\0\0\0\0\0\80\0þ@8\0\0\0\0\0\0\0\80àÚá;\0\0\0\0\0\80üa½;\0¤\83·\0\0\0\80²\8f·;À÷\ e¹\0\0\0\80\92\1aØ; A\9e¸\0\0\0\80À\89\159\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80w{Ó;\0\0\0\0\0\0\0\80\97X´;\0\0\0\0\0\0\0\80üa½;\0¤\83·\0\0\0\80àÚá;\0\0\0\0\0\80PìÄ9\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80À\89\159\0\0\0\0\0\0\0\80ÿj¯;\0\0\0\0\0\0\0\80÷|\95;\0\0\0\0\0\0\0\80\97X´;\0\0\0\0\0\0\0\80w{Ó;\0\0\0\0\0\0\0\80\0\90    :\0\0\0\0\0\0\0\80\0\b\968\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80PìÄ9\0\0\0\0\0\0\0\80\9eëq;\0\0\0\0\0\0\0\80\ 6)G;\0\0\0\0\0\0\0\80÷|\95;\0\0\0\0\0\0\0\80ÿj¯;\0\0\0\0\0\0\0\80\f0\ 2:\0\0\0\0\0\0\0\80`~\1e9\0\0\0\0\0\0\0\80\0\b\968\0\0\0\0\0\0\0\80\0\90     :\0\0\0\0\0\0\0\80°äú:\0\0\0\0\0\0\0\80\98~Ì:\0\0\0\0\0\0\0\80\ 6)G;\0\0\0\0\0\0\0\80\9eëq;\0\0\0\0\0\0\0\80¤\96¡9\0\0\0\0\0\0\0\80\90\96#9\0\0\0\0\0\0\0\80`~\1e9\0\0\0\0\0\0\0\80\f0\ 2:\0\0\0\0\0\0\0\80ð~&:\0\0\0\0\0\0\0\80Xv\ e:\0\0\0\0\0\0\0\80\98~Ì:\0\0\0\0\0\0\0\80°äú:\0\0\0\0\0\0\0\80\0þ@8\0\0\0\0\0\0\0\80\0£Õ7\0\0\0\0\0\0\0\80Xv\ e:\0\0\0\0\0\0\0\80ð~&:\0\0\0\0\0\0\0\80\ 6)G;\0\0\0\0\0\0\0\80Χ\10;\0\0\0\0\0\0\0\80\82\1f_;\0\0\0\0\0\0\0\80÷|\95;\0\0\0\0\0\0\0\80`~\1e9\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\b\968\0\0\0\0\0\0\0\80\98~Ì:\0\0\0\0\0\0\0\80\96:\0\0\0\0\0\0\0\80Χ\10;\0\0\0\0\0\0\0\80\ 6)G;\0\0\0\0\0\0\0\80\90\96#9\0\0\0\0\0\0\0\80À\94^8\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80`~\1e9\0\0\0\0\0\0\0\80Xv\ e:\0\0\0\0\0\0\0\80\90\16¬9\0\0\0\0\0\0\0\80\96:\0\0\0\0\0\0\0\80\98~Ì:\0\0\0\0\0\0\0\80\0£Õ7\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90\16¬9\0\0\0\0\0\0\0\80Xv\ e:\0\0\0\0\0\0\0\80²\8f·;À÷\ e¹\0\0\0\80Ö\86\91;Àph¹\0\0\0\80ã\9e\8a;,JÕ¹\0\0\0\80\8c®\9f;$á³¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0£Õ7\0\0\0\0\0\0\0\80üa½;\0¤\83·\0\0\0\80\90;@\ 5\8b¸\0\0\0\80Ö\86\91;Àph¹\0\0\0\80²\8f·;À÷\ e¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\97X´;\0\0\0\0\0\0\0\80[\9b\8b;\0\0 ³\0\0\0\80\90;@\ 5\8b¸\0\0\0\80üa½;\0¤\83·\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80÷|\95;\0\0\0\0\0\0\0\80\82\1f_;\0\0\0\0\0\0\0\80[\9b\8b;\0\0 ³\0\0\0\80\97X´;\0\0\0\0\0\0\0\80\0\b\968\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90;@\ 5\8b¸\0\0\0\80ÅYK;àÚ\13¹\0\0\0\806\V;àù¦¹\0\0\0\80Ö\86\91;Àph¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80[\9b\8b;\0\0 ³\0\0\0\80V8?;\0\1eµ·\0\0\0\80ÅYK;àÚ\13¹\0\0\0\80\90;@\ 5\8b¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\82\1f_;\0\0\0\0\0\0\0\80\82[\14;\0\0\0\0\0\0\0\80V8?;\0\1eµ·\0\0\0\80[\9b\8b;\0\0 ³\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Χ\10;\0\0\0\0\0\0\0\80dÙ¿:\0\0\0\0\0\0\0\80\82[\14;\0\0\0\0\0\0\0\80\82\1f_;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\96:\0\0\0\0\0\0\0\80tÂ):\0\0\0\0\0\0\0\80dÙ¿:\0\0\0\0\0\0\0\80Χ\10;\0\0\0\0\0\0\0\80À\94^8\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\90\16¬9\0\0\0\0\0\0\0\80àKÑ8\0\0\0\0\0\0\0\80tÂ):\0\0\0\0\0\0\0\80\96:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80àKÑ8\0\0\0\0\0\0\0\80\90\16¬9\0\0\0\0\0\0\0\80Ö\86\91;Àph¹\0\0\0\806\V;àù¦¹\0\0\0\80~Rj;ø­ø¹\0\0\0\80ã\9e\8a;,JÕ¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80tÂ):\0\0\0\0\0\0\0\80P\a^9\0\0\0\0\0\0\0\80&
+E:\0\0\0\0\0\0\0\80dÙ¿:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80àKÑ8\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80P\a^9\0\0\0\0\0\0\0\80tÂ):\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80àKÑ8\0\0\0\0\0\0\0\806\V;àù¦¹\0\0\0\80àô\13;ÀèÕ¹\0\0\0\80©ïA;$\86\rº\0\0\0\80~Rj;ø­ø¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80ÅYK;àÚ\13¹\0\0\0\80Þä\ 6;`òb¹\0\0\0\80àô\13;ÀèÕ¹\0\0\0\806\V;àù¦¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80V8?;\0\1eµ·\0\0\0\80:¸õ:\80\1a\89¸\0\0\0\80Þä\ 6;`òb¹\0\0\0\80ÅYK;àÚ\13¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\82[\14;\0\0\0\0\0\0\0\80[íµ:\0\80©µ\0\0\0\80:¸õ:\80\1a\89¸\0\0\0\80V8?;\0\1eµ·\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80dÙ¿:\0\0\0\0\0\0\0\80&
+E:\0\0\0\0\0\0\0\80[íµ:\0\80©µ\0\0\0\80\82[\14;\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80:¸õ:\80\1a\89¸\0\0\0\80\0\0\0\0À°ß¸\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80Þä\ 6;`òb¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80[íµ:\0\80©µ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0À°ß¸\0\0\0\80:¸õ:\80\1a\89¸\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80&
+E:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80[íµ:\0\80©µ\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80P\a^9\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80&
+E:\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80P\a^9\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80àô\13;ÀèÕ¹\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80\0\0\0\0Z\94\0\0\0\80©ïA;$\86\rº\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80Þä\ 6;`òb¹\0\0\0\80\0\0\0\0 \9a\98¹\0\0\0\80\0\0\0\0\0à\ 4º\0\0\0\80àô\13;ÀèÕ¹\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\0\0\0\0\0\0\0\0\0\0\0\80\ 2\0\ 1\0\0\0\ 3\0\ 2\0\0\0\ 6\0\ 5\0\ 4\0\a\0\ 6\0\ 4\0
+\0      \0\b\0\v\0
+\0\b\0\ e\0\r\0\f\0\ f\0\ e\0\f\0\12\0\11\0\10\0\13\0\12\0\10\0\16\0\15\0\14\0\17\0\16\0\14\0\1a\0\19\0\18\0\e\0\1a\0\18\0\1e\0\1d\0\1c\0\1f\0\1e\0\1c\0"\0!\0 \0#\0"\0 \0&\0%\0$\0'\0&\0$\0*\0)\0(\0+\0*\0(\0.\0-\0,\0.\0/\0-\0.\00\0/\0.\0,\01\0.\01\02\04\03\00\04\05\03\04\06\05\08\07\06\08\09\07\08\0:\09\0<\0;\0:\0<\0=\0;\0<\0>\0=\0@\0?\0>\0@\0A\0?\0@\0B\0A\0D\0C\0B\0D\0E\0C\0D\0F\0E\0H\0G\0F\0H\0I\0G\0H\0J\0I\0L\0K\0J\0L\0M\0K\0L\0N\0M\0P\0O\0N\0P\0Q\0O\0P\0R\0Q\0T\0S\0R\0T\0U\0S\0T\02\0U\0X\0W\0V\0W\0Y\0V\0Y\0Z\0V\0[\0X\0V\0\\0[\0V\0Z\0^\0]\0^\0_\0]\0_\0`\0]\0`\0b\0a\0b\0c\0a\0c\0d\0a\0d\0f\0e\0f\0g\0e\0g\0h\0e\0h\0j\0i\0j\0k\0i\0k\0l\0i\0l\0n\0m\0n\0o\0m\0o\0p\0m\0p\0r\0q\0r\0s\0q\0s\0t\0q\0t\0v\0u\0v\0w\0u\0w\0x\0u\0x\0z\0y\0z\0{\0y\0{\0|\0y\0|\0~\0}\0~\0\7f\0}\0\7f\0\\0}\0\82\0\81\0\80\0\83\0\82\0\80\0\86\0\85\0\84\0\87\0\86\0\84\0\8a\0\89\0\88\0\8b\0\8a\0\88\0\8e\0\8d\0\8c\0\8f\0\8e\0\8c\0\92\0\91\0\90\0\93\0\92\0\90\0\96\0\95\0\94\0\97\0\96\0\94\0\9a\0\99\0\98\0\9b\0\9a\0\98\0\9e\0\9d\0\9c\0\9f\0\9e\0\9c\0¢\0¡\0 \0£\0¢\0 \0¦\0¥\0¤\0§\0¦\0¤\0ª\0©\0¨\0«\0ª\0¨\0®\0­\0¬\0¯\0®\0¬\0²\0±\0°\0³\0²\0°\0\0µ\0´\0·\0\0´\0º\0¹\0¸\0»\0º\0¸\0¾\0½\0¼\0¿\0¾\0¼\0Â\0Á\0À\0Ã\0Â\0À\0Æ\0Å\0Ä\0Ç\0Æ\0Ä\0Ê\0É\0È\0Ë\0Ê\0È\0Î\0Í\0Ì\0Ï\0Î\0Ì\0Ò\0Ñ\0Ð\0Ó\0Ò\0Ð\0Ö\0Õ\0Ô\0×\0Ö\0Ô\0Ú\0Ù\0Ø\0Û\0Ú\0Ø\0Þ\0Ý\0Ü\0ß\0Þ\0Ü\0â\0á\0à\0ã\0â\0à\0æ\0å\0ä\0ç\0æ\0ä\0ê\0é\0è\0ë\0ê\0è\0î\0í\0ì\0ï\0î\0ì\0ò\0ñ\0ð\0ó\0ò\0ð\0ö\0õ\0ô\0÷\0ö\0ô\0ú\0ù\0ø\0û\0ú\0ø\0þ\0ý\0ü\0ÿ\0þ\0ü\0\ 2\ 1\ 1\ 1\0\ 1\ 3\ 1\ 2\ 1\0\ 1\ 6\ 1\ 5\ 1\ 4\ 1\a\ 1\ 6\ 1\ 4\ 1
+\ 1      \ 1\b\ 1\v\ 1
+\ 1\b\ 1\ e\ 1\r\ 1\f\ 1\ f\ 1\ e\ 1\f\ 1\12\ 1\11\ 1\10\ 1\13\ 1\12\ 1\10\ 1\16\ 1\15\ 1\14\ 1\17\ 1\16\ 1\14\ 1\1a\ 1\19\ 1\18\ 1\e\ 1\1a\ 1\18\ 1\1e\ 1\1d\ 1\1c\ 1\1f\ 1\1e\ 1\1c\ 1"\ 1!\ 1 \ 1#\ 1"\ 1 \ 1&\ 1%\ 1$\ 1'\ 1&\ 1$\ 1*\ 1)\ 1(\ 1+\ 1*\ 1(\ 1.\ 1-\ 1,\ 1/\ 1.\ 1,\ 12\ 11\ 10\ 13\ 12\ 10\ 16\ 15\ 14\ 17\ 16\ 14\ 1:\ 19\ 18\ 1;\ 1:\ 18\ 1>\ 1=\ 1<\ 1?\ 1>\ 1<\ 1B\ 1A\ 1@\ 1C\ 1B\ 1@\ 1F\ 1E\ 1D\ 1G\ 1F\ 1D\ 1J\ 1I\ 1H\ 1K\ 1J\ 1H\ 1N\ 1M\ 1L\ 1O\ 1N\ 1L\ 1R\ 1Q\ 1P\ 1S\ 1R\ 1P\ 1V\ 1U\ 1T\ 1W\ 1V\ 1T\ 1Z\ 1Y\ 1X\ 1[\ 1Z\ 1X\ 1^\ 1]\ 1\\ 1_\ 1^\ 1\\ 1b\ 1a\ 1`\ 1c\ 1b\ 1`\ 1f\ 1e\ 1d\ 1g\ 1f\ 1d\ 1j\ 1i\ 1h\ 1k\ 1j\ 1h\ 1n\ 1m\ 1l\ 1o\ 1n\ 1l\ 1r\ 1q\ 1p\ 1s\ 1r\ 1p\ 1v\ 1u\ 1t\ 1w\ 1v\ 1t\ 1z\ 1y\ 1x\ 1{\ 1z\ 1x\ 1~\ 1}\ 1|\ 1\7f\ 1~\ 1|\ 1\82\ 1\81\ 1\80\ 1\83\ 1\82\ 1\80\ 1\86\ 1\85\ 1\84\ 1\87\ 1\86\ 1\84\ 1\8a\ 1\89\ 1\88\ 1\8b\ 1\8a\ 1\88\ 1\8e\ 1\8d\ 1\8c\ 1\8f\ 1\8e\ 1\8c\ 1\92\ 1\91\ 1\90\ 1\93\ 1\92\ 1\90\ 1\96\ 1\95\ 1\94\ 1\97\ 1\96\ 1\94\ 1\9a\ 1\99\ 1\98\ 1\9b\ 1\9a\ 1\98\ 1\9e\ 1\9d\ 1\9c\ 1\9f\ 1\9e\ 1\9c\ 1¢\ 1¡\ 1 \ 1£\ 1¢\ 1 \ 1¦\ 1¥\ 1¤\ 1§\ 1¦\ 1¤\ 1ª\ 1©\ 1¨\ 1«\ 1ª\ 1¨\ 1®\ 1­\ 1¬\ 1¯\ 1®\ 1¬\ 1²\ 1±\ 1°\ 1³\ 1²\ 1°\ 1\ 1µ\ 1´\ 1·\ 1\ 1´\ 1º\ 1¹\ 1¸\ 1»\ 1º\ 1¸\ 1¾\ 1½\ 1¼\ 1¿\ 1¾\ 1¼\ 1Â\ 1Á\ 1À\ 1Ã\ 1Â\ 1À\ 1Æ\ 1Å\ 1Ä\ 1Ç\ 1Æ\ 1Ä\ 1Ê\ 1É\ 1È\ 1Ë\ 1Ê\ 1È\ 1Î\ 1Í\ 1Ì\ 1Ï\ 1Î\ 1Ì\ 1Ò\ 1Ñ\ 1Ð\ 1Ó\ 1Ò\ 1Ð\ 1Ö\ 1Õ\ 1Ô\ 1×\ 1Ö\ 1Ô\ 1Ú\ 1Ù\ 1Ø\ 1Û\ 1Ú\ 1Ø\ 1Þ\ 1Ý\ 1Ü\ 1ß\ 1Þ\ 1Ü\ 1â\ 1á\ 1à\ 1ã\ 1â\ 1à\ 1æ\ 1å\ 1ä\ 1ç\ 1æ\ 1ä\ 1ê\ 1é\ 1è\ 1ë\ 1ê\ 1è\ 1î\ 1í\ 1ì\ 1ï\ 1î\ 1ì\ 1ò\ 1ñ\ 1ð\ 1ó\ 1ò\ 1ð\ 1ö\ 1õ\ 1ô\ 1÷\ 1ö\ 1ô\ 1ú\ 1ù\ 1ø\ 1û\ 1ú\ 1ø\ 1þ\ 1ý\ 1ü\ 1ÿ\ 1þ\ 1ü\ 1\ 2\ 2\ 1\ 2\0\ 2\ 3\ 2\ 2\ 2\0\ 2\ 6\ 2\ 5\ 2\ 4\ 2\a\ 2\ 6\ 2\ 4\ 2
+\ 2      \ 2\b\ 2\v\ 2
+\ 2\b\ 2\ e\ 2\r\ 2\f\ 2\ f\ 2\ e\ 2\f\ 2\12\ 2\11\ 2\10\ 2\13\ 2\12\ 2\10\ 2\16\ 2\15\ 2\14\ 2\17\ 2\16\ 2\14\ 2\1a\ 2\19\ 2\18\ 2\e\ 2\1a\ 2\18\ 2\1e\ 2\1d\ 2\1c\ 2\1f\ 2\1e\ 2\1c\ 2"\ 2!\ 2 \ 2#\ 2"\ 2 \ 2&\ 2%\ 2$\ 2'\ 2&\ 2$\ 2*\ 2)\ 2(\ 2+\ 2*\ 2(\ 2.\ 2-\ 2,\ 2/\ 2.\ 2,\ 22\ 21\ 20\ 23\ 22\ 20\ 26\ 25\ 24\ 27\ 26\ 24\ 2:\ 29\ 28\ 2;\ 2:\ 28\ 2>\ 2=\ 2<\ 2?\ 2>\ 2<\ 2B\ 2A\ 2@\ 2C\ 2B\ 2@\ 2F\ 2E\ 2D\ 2G\ 2F\ 2D\ 2J\ 2I\ 2H\ 2K\ 2J\ 2H\ 2N\ 2M\ 2L\ 2O\ 2N\ 2L\ 2R\ 2Q\ 2P\ 2S\ 2R\ 2P\ 2V\ 2U\ 2T\ 2W\ 2V\ 2T\ 2Z\ 2Y\ 2X\ 2[\ 2Z\ 2X\ 2^\ 2]\ 2\\ 2_\ 2^\ 2\\ 2b\ 2a\ 2`\ 2c\ 2b\ 2`\ 2f\ 2e\ 2d\ 2g\ 2f\ 2d\ 2j\ 2i\ 2h\ 2k\ 2j\ 2h\ 2n\ 2m\ 2l\ 2o\ 2n\ 2l\ 2r\ 2q\ 2p\ 2s\ 2r\ 2p\ 2v\ 2u\ 2t\ 2w\ 2v\ 2t\ 2z\ 2y\ 2x\ 2{\ 2z\ 2x\ 2~\ 2}\ 2|\ 2\7f\ 2~\ 2|\ 2\82\ 2\81\ 2\80\ 2\83\ 2\82\ 2\80\ 2\86\ 2\85\ 2\84\ 2\87\ 2\86\ 2\84\ 2\8a\ 2\89\ 2\88\ 2\8b\ 2\8a\ 2\88\ 2\8e\ 2\8d\ 2\8c\ 2\8f\ 2\8e\ 2\8c\ 2\92\ 2\91\ 2\90\ 2\93\ 2\92\ 2\90\ 2\96\ 2\95\ 2\94\ 2\97\ 2\96\ 2\94\ 2\9a\ 2\99\ 2\98\ 2\9b\ 2\9a\ 2\98\ 2\9e\ 2\9d\ 2\9c\ 2\9f\ 2\9e\ 2\9c\ 2¢\ 2¡\ 2 \ 2£\ 2¢\ 2 \ 2¦\ 2¥\ 2¤\ 2§\ 2¦\ 2¤\ 2ª\ 2©\ 2¨\ 2«\ 2ª\ 2¨\ 2®\ 2­\ 2¬\ 2¯\ 2®\ 2¬\ 2²\ 2±\ 2°\ 2³\ 2²\ 2°\ 2\ 2µ\ 2´\ 2·\ 2\ 2´\ 2º\ 2¹\ 2¸\ 2»\ 2º\ 2¸\ 2¾\ 2½\ 2¼\ 2¿\ 2¾\ 2¼\ 2Â\ 2Á\ 2À\ 2Ã\ 2Â\ 2À\ 2Æ\ 2Å\ 2Ä\ 2Ç\ 2Æ\ 2Ä\ 2Ê\ 2É\ 2È\ 2Ë\ 2Ê\ 2È\ 2Î\ 2Í\ 2Ì\ 2Ï\ 2Î\ 2Ì\ 2Ò\ 2Ñ\ 2Ð\ 2Ó\ 2Ò\ 2Ð\ 2Ö\ 2Õ\ 2Ô\ 2×\ 2Ö\ 2Ô\ 2Ú\ 2Ù\ 2Ø\ 2Û\ 2Ú\ 2Ø\ 2Þ\ 2Ý\ 2Ü\ 2ß\ 2Þ\ 2Ü\ 2â\ 2á\ 2à\ 2ã\ 2â\ 2à\ 2æ\ 2å\ 2ä\ 2ç\ 2æ\ 2ä\ 2ê\ 2é\ 2è\ 2ë\ 2ê\ 2è\ 2î\ 2í\ 2ì\ 2ï\ 2î\ 2ì\ 2ò\ 2ñ\ 2ð\ 2ó\ 2ò\ 2ð\ 2ö\ 2õ\ 2ô\ 2÷\ 2ö\ 2ô\ 2ú\ 2ù\ 2ø\ 2û\ 2ú\ 2ø\ 2þ\ 2ý\ 2ü\ 2ÿ\ 2þ\ 2ü\ 2\ 2\ 3\ 1\ 3\0\ 3\ 3\ 3\ 2\ 3\0\ 3\ 6\ 3\ 5\ 3\ 4\ 3\a\ 3\ 6\ 3\ 4\ 3
+\ 3      \ 3\b\ 3\v\ 3
+\ 3\b\ 3\ e\ 3\r\ 3\f\ 3\ f\ 3\ e\ 3\f\ 3\12\ 3\11\ 3\10\ 3\13\ 3\12\ 3\10\ 3\16\ 3\15\ 3\14\ 3\17\ 3\16\ 3\14\ 3\1a\ 3\19\ 3\18\ 3\e\ 3\1a\ 3\18\ 3\1e\ 3\1d\ 3\1c\ 3\1f\ 3\1e\ 3\1c\ 3"\ 3!\ 3 \ 3#\ 3"\ 3 \ 3&\ 3%\ 3$\ 3'\ 3&\ 3$\ 3*\ 3)\ 3(\ 3+\ 3*\ 3(\ 3.\ 3-\ 3,\ 3/\ 3.\ 3,\ 32\ 31\ 30\ 33\ 32\ 30\ 36\ 35\ 34\ 37\ 36\ 34\ 3:\ 39\ 38\ 3;\ 3:\ 38\ 3>\ 3=\ 3<\ 3?\ 3>\ 3<\ 3B\ 3A\ 3@\ 3C\ 3B\ 3@\ 3F\ 3E\ 3D\ 3G\ 3F\ 3D\ 3J\ 3I\ 3H\ 3K\ 3J\ 3H\ 3N\ 3M\ 3L\ 3O\ 3N\ 3L\ 3R\ 3Q\ 3P\ 3S\ 3R\ 3P\ 3V\ 3U\ 3T\ 3W\ 3V\ 3T\ 3Z\ 3Y\ 3X\ 3[\ 3Z\ 3X\ 3^\ 3]\ 3\\ 3_\ 3^\ 3\\ 3b\ 3a\ 3`\ 3c\ 3b\ 3`\ 3f\ 3e\ 3d\ 3g\ 3f\ 3d\ 3j\ 3i\ 3h\ 3k\ 3j\ 3h\ 3n\ 3m\ 3l\ 3o\ 3n\ 3l\ 3r\ 3q\ 3p\ 3s\ 3r\ 3p\ 3v\ 3u\ 3t\ 3w\ 3v\ 3t\ 3z\ 3y\ 3x\ 3{\ 3z\ 3x\ 3~\ 3}\ 3|\ 3\7f\ 3~\ 3|\ 3\82\ 3\81\ 3\80\ 3\83\ 3\82\ 3\80\ 3\86\ 3\85\ 3\84\ 3\87\ 3\86\ 3\84\ 3\8a\ 3\89\ 3\88\ 3\8b\ 3\8a\ 3\88\ 3\8e\ 3\8d\ 3\8c\ 3\8f\ 3\8e\ 3\8c\ 3\92\ 3\91\ 3\90\ 3\93\ 3\92\ 3\90\ 3\96\ 3\95\ 3\94\ 3\97\ 3\96\ 3\94\ 3\9a\ 3\99\ 3\98\ 3\9b\ 3\9a\ 3\98\ 3\9e\ 3\9d\ 3\9c\ 3\9f\ 3\9e\ 3\9c\ 3¢\ 3¡\ 3 \ 3£\ 3¢\ 3 \ 3¦\ 3¥\ 3¤\ 3§\ 3¦\ 3¤\ 3ª\ 3©\ 3¨\ 3«\ 3ª\ 3¨\ 3®\ 3­\ 3¬\ 3¯\ 3®\ 3¬\ 3²\ 3±\ 3°\ 3³\ 3²\ 3°\ 3\ 3µ\ 3´\ 3·\ 3\ 3´\ 3º\ 3¹\ 3¸\ 3»\ 3º\ 3¸\ 3¾\ 3½\ 3¼\ 3¿\ 3¾\ 3¼\ 3Â\ 3Á\ 3À\ 3Ã\ 3Â\ 3À\ 3Æ\ 3Å\ 3Ä\ 3Ç\ 3Æ\ 3Ä\ 3Ê\ 3É\ 3È\ 3Ë\ 3Ê\ 3È\ 3Î\ 3Í\ 3Ì\ 3Ï\ 3Î\ 3Ì\ 3Ò\ 3Ñ\ 3Ð\ 3Ó\ 3Ò\ 3Ð\ 3Ö\ 3Õ\ 3Ô\ 3×\ 3Ö\ 3Ô\ 3Ú\ 3Ù\ 3Ø\ 3Û\ 3Ú\ 3Ø\ 3Þ\ 3Ý\ 3Ü\ 3ß\ 3Þ\ 3Ü\ 3â\ 3á\ 3à\ 3ã\ 3â\ 3à\ 3æ\ 3å\ 3ä\ 3ç\ 3æ\ 3ä\ 3ê\ 3é\ 3è\ 3ë\ 3ê\ 3è\ 3î\ 3í\ 3ì\ 3ï\ 3î\ 3ì\ 3ò\ 3ñ\ 3ð\ 3ó\ 3ò\ 3ð\ 3ö\ 3õ\ 3ô\ 3÷\ 3ö\ 3ô\ 3ú\ 3ù\ 3ø\ 3û\ 3ú\ 3ø\ 3þ\ 3ý\ 3ü\ 3ÿ\ 3þ\ 3ü\ 3\ 2\ 4\ 1\ 4\0\ 4\ 3\ 4\ 2\ 4\0\ 4\ 6\ 4\ 5\ 4\ 4\ 4\a\ 4\ 6\ 4\ 4\ 4
+\ 4      \ 4\b\ 4\v\ 4
+\ 4\b\ 4\ e\ 4\r\ 4\f\ 4\ f\ 4\ e\ 4\f\ 4\12\ 4\11\ 4\10\ 4\13\ 4\12\ 4\10\ 4\16\ 4\15\ 4\14\ 4\17\ 4\16\ 4\14\ 4\1a\ 4\19\ 4\18\ 4\e\ 4\1a\ 4\18\ 4\1e\ 4\1d\ 4\1c\ 4\1f\ 4\1e\ 4\1c\ 4"\ 4!\ 4 \ 4#\ 4"\ 4 \ 4&\ 4%\ 4$\ 4'\ 4&\ 4$\ 4*\ 4)\ 4(\ 4+\ 4*\ 4(\ 4.\ 4-\ 4,\ 4/\ 4.\ 4,\ 42\ 41\ 40\ 43\ 42\ 40\ 46\ 45\ 44\ 47\ 46\ 44\ 4:\ 49\ 48\ 4;\ 4:\ 48\ 4>\ 4=\ 4<\ 4?\ 4>\ 4<\ 4B\ 4A\ 4@\ 4C\ 4B\ 4@\ 4F\ 4E\ 4D\ 4G\ 4F\ 4D\ 4J\ 4I\ 4H\ 4K\ 4J\ 4H\ 4N\ 4M\ 4L\ 4O\ 4N\ 4L\ 4R\ 4Q\ 4P\ 4S\ 4R\ 4P\ 4V\ 4U\ 4T\ 4W\ 4V\ 4T\ 4Z\ 4Y\ 4X\ 4[\ 4Z\ 4X\ 4^\ 4]\ 4\\ 4_\ 4^\ 4\\ 4b\ 4a\ 4`\ 4c\ 4b\ 4`\ 4f\ 4e\ 4d\ 4g\ 4f\ 4d\ 4j\ 4i\ 4h\ 4k\ 4j\ 4h\ 4n\ 4m\ 4l\ 4o\ 4n\ 4l\ 4r\ 4q\ 4p\ 4s\ 4r\ 4p\ 4v\ 4u\ 4t\ 4w\ 4v\ 4t\ 4z\ 4y\ 4x\ 4{\ 4z\ 4x\ 4~\ 4}\ 4|\ 4\7f\ 4~\ 4|\ 4\82\ 4\81\ 4\80\ 4\83\ 4\82\ 4\80\ 4\86\ 4\85\ 4\84\ 4\87\ 4\86\ 4\84\ 4\8a\ 4\89\ 4\88\ 4\8b\ 4\8a\ 4\88\ 4\8e\ 4\8d\ 4\8c\ 4\8f\ 4\8e\ 4\8c\ 4\92\ 4\91\ 4\90\ 4\93\ 4\92\ 4\90\ 4\96\ 4\95\ 4\94\ 4\97\ 4\96\ 4\94\ 4\9a\ 4\99\ 4\98\ 4\9b\ 4\9a\ 4\98\ 4\9e\ 4\9d\ 4\9c\ 4\9f\ 4\9e\ 4\9c\ 4¢\ 4¡\ 4 \ 4£\ 4¢\ 4 \ 4¦\ 4¥\ 4¤\ 4§\ 4¦\ 4¤\ 4ª\ 4©\ 4¨\ 4«\ 4ª\ 4¨\ 4®\ 4­\ 4¬\ 4¯\ 4®\ 4¬\ 4²\ 4±\ 4°\ 4³\ 4²\ 4°\ 4\ 4µ\ 4´\ 4·\ 4\ 4´\ 4º\ 4¹\ 4¸\ 4»\ 4º\ 4¸\ 4¾\ 4½\ 4¼\ 4¿\ 4¾\ 4¼\ 4Â\ 4Á\ 4À\ 4Ã\ 4Â\ 4À\ 4Æ\ 4Å\ 4Ä\ 4Ç\ 4Æ\ 4Ä\ 4Ê\ 4É\ 4È\ 4Ë\ 4Ê\ 4È\ 4Î\ 4Í\ 4Ì\ 4Ï\ 4Î\ 4Ì\ 4Ò\ 4Ñ\ 4Ð\ 4Ó\ 4Ò\ 4Ð\ 4Ö\ 4Õ\ 4Ô\ 4×\ 4Ö\ 4Ô\ 4Ú\ 4Ù\ 4Ø\ 4Û\ 4Ú\ 4Ø\ 4Þ\ 4Ý\ 4Ü\ 4ß\ 4Þ\ 4Ü\ 4â\ 4á\ 4à\ 4ã\ 4â\ 4à\ 4æ\ 4å\ 4ä\ 4ç\ 4æ\ 4ä\ 4ê\ 4é\ 4è\ 4ë\ 4ê\ 4è\ 4î\ 4í\ 4ì\ 4ï\ 4î\ 4ì\ 4ò\ 4ñ\ 4ð\ 4ó\ 4ò\ 4ð\ 4ö\ 4õ\ 4ô\ 4÷\ 4ö\ 4ô\ 4ú\ 4ù\ 4ø\ 4û\ 4ú\ 4ø\ 4þ\ 4ý\ 4ü\ 4ÿ\ 4þ\ 4ü\ 4\ 2\ 5\ 1\ 5\0\ 5\ 3\ 5\ 2\ 5\0\ 5\ 6\ 5\ 5\ 5\ 4\ 5\a\ 5\ 6\ 5\ 4\ 5
+\ 5      \ 5\b\ 5\v\ 5
+\ 5\b\ 5\ e\ 5\r\ 5\f\ 5\ f\ 5\ e\ 5\f\ 5\12\ 5\11\ 5\10\ 5\13\ 5\12\ 5\10\ 5\16\ 5\15\ 5\14\ 5\17\ 5\16\ 5\14\ 5\1a\ 5\19\ 5\18\ 5\e\ 5\1a\ 5\18\ 5\1e\ 5\1d\ 5\1c\ 5\1f\ 5\1e\ 5\1c\ 5"\ 5!\ 5 \ 5#\ 5"\ 5 \ 5&\ 5%\ 5$\ 5'\ 5&\ 5$\ 5*\ 5)\ 5(\ 5+\ 5*\ 5(\ 5.\ 5-\ 5,\ 5/\ 5.\ 5,\ 52\ 51\ 50\ 53\ 52\ 50\ 56\ 55\ 54\ 57\ 56\ 54\ 5:\ 59\ 58\ 5;\ 5:\ 58\ 5>\ 5=\ 5<\ 5?\ 5>\ 5<\ 5B\ 5A\ 5@\ 5C\ 5B\ 5@\ 5F\ 5E\ 5D\ 5G\ 5F\ 5D\ 5J\ 5I\ 5H\ 5K\ 5J\ 5H\ 5N\ 5M\ 5L\ 5O\ 5N\ 5L\ 5R\ 5Q\ 5P\ 5S\ 5R\ 5P\ 5V\ 5U\ 5T\ 5W\ 5V\ 5T\ 5Z\ 5Y\ 5X\ 5[\ 5Z\ 5X\ 5^\ 5]\ 5\\ 5_\ 5^\ 5\\ 5b\ 5a\ 5`\ 5c\ 5b\ 5`\ 5f\ 5e\ 5d\ 5g\ 5f\ 5d\ 5j\ 5i\ 5h\ 5k\ 5j\ 5h\ 5n\ 5m\ 5l\ 5o\ 5n\ 5l\ 5r\ 5q\ 5p\ 5s\ 5r\ 5p\ 5v\ 5u\ 5t\ 5w\ 5v\ 5t\ 5z\ 5y\ 5x\ 5{\ 5z\ 5x\ 5~\ 5}\ 5|\ 5\7f\ 5~\ 5|\ 5\82\ 5\81\ 5\80\ 5\83\ 5\82\ 5\80\ 5\86\ 5\85\ 5\84\ 5\87\ 5\86\ 5\84\ 5\8a\ 5\89\ 5\88\ 5\8b\ 5\8a\ 5\88\ 5\8e\ 5\8d\ 5\8c\ 5\8f\ 5\8e\ 5\8c\ 5\92\ 5\91\ 5\90\ 5\93\ 5\92\ 5\90\ 5\96\ 5\95\ 5\94\ 5\97\ 5\96\ 5\94\ 5\9a\ 5\99\ 5\98\ 5\9b\ 5\9a\ 5\98\ 5\9e\ 5\9d\ 5\9c\ 5\9f\ 5\9e\ 5\9c\ 5¢\ 5¡\ 5 \ 5£\ 5¢\ 5 \ 5¦\ 5¥\ 5¤\ 5§\ 5¦\ 5¤\ 5ª\ 5©\ 5¨\ 5«\ 5ª\ 5¨\ 5®\ 5­\ 5¬\ 5¯\ 5®\ 5¬\ 5²\ 5±\ 5°\ 5³\ 5²\ 5°\ 5\ 5µ\ 5´\ 5·\ 5\ 5´\ 5º\ 5¹\ 5¸\ 5»\ 5º\ 5¸\ 5¾\ 5½\ 5¼\ 5¿\ 5¾\ 5¼\ 5Â\ 5Á\ 5À\ 5Ã\ 5Â\ 5À\ 5Æ\ 5Å\ 5Ä\ 5Ç\ 5Æ\ 5Ä\ 5Ê\ 5É\ 5È\ 5Ë\ 5Ê\ 5È\ 5Î\ 5Í\ 5Ì\ 5Ï\ 5Î\ 5Ì\ 5Ò\ 5Ñ\ 5Ð\ 5Ó\ 5Ò\ 5Ð\ 5Ö\ 5Õ\ 5Ô\ 5×\ 5Ö\ 5Ô\ 5Ú\ 5Ù\ 5Ø\ 5Û\ 5Ú\ 5Ø\ 5Þ\ 5Ý\ 5Ü\ 5ß\ 5Þ\ 5Ü\ 5â\ 5á\ 5à\ 5ã\ 5â\ 5à\ 5æ\ 5å\ 5ä\ 5ç\ 5æ\ 5ä\ 5ê\ 5é\ 5è\ 5ë\ 5ê\ 5è\ 5î\ 5í\ 5ì\ 5ï\ 5î\ 5ì\ 5ò\ 5ñ\ 5ð\ 5ó\ 5ò\ 5ð\ 5ö\ 5õ\ 5ô\ 5÷\ 5ö\ 5ô\ 5ú\ 5ù\ 5ø\ 5û\ 5ú\ 5ø\ 5þ\ 5ý\ 5ü\ 5ÿ\ 5þ\ 5ü\ 5\ 2\ 6\ 1\ 6\0\ 6\ 3\ 6\ 2\ 6\0\ 6\ 6\ 6\ 5\ 6\ 4\ 6\a\ 6\ 6\ 6\ 4\ 6
+\ 6      \ 6\b\ 6\v\ 6
+\ 6\b\ 6\ e\ 6\r\ 6\f\ 6\ f\ 6\ e\ 6\f\ 6\12\ 6\11\ 6\10\ 6\13\ 6\12\ 6\10\ 6\16\ 6\15\ 6\14\ 6\17\ 6\16\ 6\14\ 6\1a\ 6\19\ 6\18\ 6\e\ 6\1a\ 6\18\ 6\1e\ 6\1d\ 6\1c\ 6\1f\ 6\1e\ 6\1c\ 6"\ 6!\ 6 \ 6#\ 6"\ 6 \ 6&\ 6%\ 6$\ 6'\ 6&\ 6$\ 6*\ 6)\ 6(\ 6+\ 6*\ 6(\ 6.\ 6-\ 6,\ 6/\ 6.\ 6,\ 62\ 61\ 60\ 63\ 62\ 60\ 66\ 65\ 64\ 67\ 66\ 64\ 6:\ 69\ 68\ 6;\ 6:\ 68\ 6>\ 6=\ 6<\ 6?\ 6>\ 6<\ 6B\ 6A\ 6@\ 6C\ 6B\ 6@\ 6F\ 6E\ 6D\ 6G\ 6F\ 6D\ 6J\ 6I\ 6H\ 6K\ 6J\ 6H\ 6N\ 6M\ 6L\ 6O\ 6N\ 6L\ 6R\ 6Q\ 6P\ 6S\ 6R\ 6P\ 6V\ 6U\ 6T\ 6W\ 6V\ 6T\ 6Z\ 6Y\ 6X\ 6[\ 6Z\ 6X\ 6^\ 6]\ 6\\ 6_\ 6^\ 6\\ 6b\ 6a\ 6`\ 6c\ 6b\ 6`\ 6f\ 6e\ 6d\ 6g\ 6f\ 6d\ 6j\ 6i\ 6h\ 6k\ 6j\ 6h\ 6n\ 6m\ 6l\ 6o\ 6n\ 6l\ 6r\ 6q\ 6p\ 6s\ 6r\ 6p\ 6v\ 6u\ 6t\ 6w\ 6v\ 6t\ 6z\ 6y\ 6x\ 6{\ 6z\ 6x\ 6~\ 6}\ 6|\ 6\7f\ 6~\ 6|\ 6\82\ 6\81\ 6\80\ 6\83\ 6\82\ 6\80\ 6\86\ 6\85\ 6\84\ 6\87\ 6\86\ 6\84\ 6\8a\ 6\89\ 6\88\ 6\8b\ 6\8a\ 6\88\ 6\8e\ 6\8d\ 6\8c\ 6\8f\ 6\8e\ 6\8c\ 6\92\ 6\91\ 6\90\ 6\93\ 6\92\ 6\90\ 6\96\ 6\95\ 6\94\ 6\97\ 6\96\ 6\94\ 6\9a\ 6\99\ 6\98\ 6\9b\ 6\9a\ 6\98\ 6\9e\ 6\9d\ 6\9c\ 6\9f\ 6\9e\ 6\9c\ 6¢\ 6¡\ 6 \ 6£\ 6¢\ 6 \ 6¦\ 6¥\ 6¤\ 6§\ 6¦\ 6¤\ 6ª\ 6©\ 6¨\ 6«\ 6ª\ 6¨\ 6®\ 6­\ 6¬\ 6¯\ 6®\ 6¬\ 6²\ 6±\ 6°\ 6³\ 6²\ 6°\ 6\ 6µ\ 6´\ 6·\ 6\ 6´\ 6º\ 6¹\ 6¸\ 6»\ 6º\ 6¸\ 6¾\ 6½\ 6¼\ 6¿\ 6¾\ 6¼\ 6Â\ 6Á\ 6À\ 6Ã\ 6Â\ 6À\ 6Æ\ 6Å\ 6Ä\ 6Ç\ 6Æ\ 6Ä\ 6Ê\ 6É\ 6È\ 6Ë\ 6Ê\ 6È\ 6Î\ 6Í\ 6Ì\ 6Ï\ 6Î\ 6Ì\ 6Ò\ 6Ñ\ 6Ð\ 6Ó\ 6Ò\ 6Ð\ 6Ö\ 6Õ\ 6Ô\ 6×\ 6Ö\ 6Ô\ 6Ú\ 6Ù\ 6Ø\ 6Û\ 6Ú\ 6Ø\ 6Þ\ 6Ý\ 6Ü\ 6ß\ 6Þ\ 6Ü\ 6â\ 6á\ 6à\ 6ã\ 6â\ 6à\ 6æ\ 6å\ 6ä\ 6ç\ 6æ\ 6ä\ 6ê\ 6é\ 6è\ 6ë\ 6ê\ 6è\ 6î\ 6í\ 6ì\ 6ï\ 6î\ 6ì\ 6ò\ 6ñ\ 6ð\ 6ó\ 6ò\ 6ð\ 6ö\ 6õ\ 6ô\ 6÷\ 6ö\ 6ô\ 6ú\ 6ù\ 6ø\ 6û\ 6ú\ 6ø\ 6þ\ 6ý\ 6ü\ 6ÿ\ 6þ\ 6ü\ 6\ 2\a\ 1\a\0\a\ 3\a\ 2\a\0\a\ 6\a\ 5\a\ 4\a\a\a\ 6\a\ 4\a
+\a      \a\b\a\v\a
+\a\b\a\ e\a\r\a\f\a\ f\a\ e\a\f\a\12\a\11\a\10\a\13\a\12\a\10\a\16\a\15\a\14\a\17\a\16\a\14\a\1a\a\19\a\18\a\e\a\1a\a\18\a\1e\a\1d\a\1c\a\1f\a\1e\a\1c\a"\a!\a \a#\a"\a \a&\a%\a$\a'\a&\a$\a*\a)\a(\a+\a*\a(\a.\a-\a,\a/\a.\a,\a2\a1\a0\a3\a2\a0\a6\a5\a4\a7\a6\a4\a:\a9\a8\a;\a:\a8\a>\a=\a<\a?\a>\a<\aB\aA\a@\aC\aB\a@\aF\aE\aD\aG\aF\aD\aJ\aI\aH\aK\aJ\aH\aN\aM\aL\aO\aN\aL\aR\aQ\aP\aS\aR\aP\a\0\0\0\0\89\88\b=\89\88\88=ÎÌÌ=\89\88\b>«ª*>ÍÌL>ïîn>\89\88\88>\9a\99\99>«ªª>¼»»>ÍÌÌ>ÞÝÝ>ïîî>\0\0\0?\89\88\b?\12\11\11?\9b\99\19?$""?­ª*?633?¿»;?HDD?ÑÌL?ZUU?ãÝ]?lff?õîn?~ww?\ 3\0\80?GD\84?\8b\88\88?ÏÌ\8c?\13\11\91?WU\95?\9b\99\99?ßÝ\9d?#"¢?gf¦?«ªª?ïî®?33³?ww·?»»»?ÿÿ¿?CDÄ?\87\88È?ËÌÌ?\ f\11Ñ?SUÕ?\97\99Ù?ÛÝÝ?\1f"â?cfæ?§ªê?ëîî?/3ó?sw÷?·»û?ûÿÿ? "\ 2@BD\ 4@df\ 6@\86\88\b@¨ª
+@ÊÌ\f@ìî\ e@\ e\11\11@03\13@RU\15@tw\17@\96\99\19@¸»\e@ÚÝ\1d@üÿ\1f@\1e""@@D$@bf&@\84\88(@¦ª*@ÈÌ,@êî.@\f\111@.33@PU5@rw7@\94\999@¶»;@ØÝ=@úÿ?@\1c"B@>DD@`fF@\82\88H@¤ªJ@ÆÌL@èîN@
+\11Q@,3S@NUU@pwW@\92\99Y@´»[@ÖÝ]@øÿ_@\1a"b@<Dd@^ff@\80\88h@¢ªj@ÄÌl@æîn@\b\11q@*3s@LUu@nww@\90\99y@²»{@ÔÝ}@öÿ\7f@\f\11\81@\1d"\82@.3\83@?D\84@PU\85@af\86@rw\87@\83\88\88@\94\99\89@¥ª\8a@¶»\8b@ÇÌ\8c@ØÝ\8d@éî\8e@úÿ\8f@\v\11\91@\1c"\92@-3\93@>D\94@OU\95@`f\96@qw\97@\82\88\98@\93\99\99@¤ª\9a@µ»\9b@ÆÌ\9c@×Ý\9d@èî\9e@ùÿ\9f@
+\11¡@\e"¢@,3£@=D¤@NU¥@_f¦@pw§@\81\88¨@\92\99©@£ªª@´»«@Å̬@ÖÝ­@çî®@øÿ¯@    \11±@\1a"²@+3³@<D´@MUµ@^f¶@ow·@\80\88¸@\91\99¹@¢ªº@³»»@Ä̼@Õݽ@æî¾@÷ÿ¿@\b\11Á@\19"Â@*3Ã@;DÄ@LUÅ@]fÆ@nwÇ@\7f\88È@\90\99É@¡ªÊ@²»Ë@ÃÌÌ@ÔÝÍ@åîÎ@öÿÏ@\a\11Ñ@\18"Ò@)3Ó@:DÔ@KUÕ@\fÖ@mw×@~\88Ø@\8f\99Ù@ ªÚ@±»Û@ÂÌÜ@ÓÝÝ@äîÞ@õÿß@\ 6\11á@\17"â@(3ã@9Dä@JUå@[fæ@\0\0\0\0\0\0\0\0\0\0\0\0½\1ak:\0\0\0\0¼Xh;\0\0\0\0Ê$\ 1<\0\0\0\0»Ôb<\0\0\0\0¡\ e¯<\0\0\0\0Ñúø<\0\0\0\0EU'=\0\0\0\0ºÌW=\0\0\0\0ÈÐ\86=\0\0\0\0ÏH¤=\0\0\0\0W-Ä=\0\0\0\0L]æ=\0\0\0\0È[\ 5>\0\0\0\0\88\8d\18>\0\0\0\0Z³,>\0\0\0\0²¼A>\0\0\0\0\ 3\99W>\0\0\0\0Á7n>\0\0\0\0\82>\0\0\0\0\8e>\0\0\0\0\8bþ\9a>\0\0\0\0\b\80§>\0\0\0\0_9´>\0\0\0\0F"Á>\0\0\0\0}2Î>\0\0\0\0ºaÛ>\0\0\0\0¶§è>\0\0\0\0-üõ>\0\0\0\0\ 1?\0\0\0\0¸W\b?\0\0\0\0Ùþ\ e?\0\0\0\0ª\9c\15?\0\0\0\0
+-\1c?\0\0\0\0Õ«"?\0\0\0\0è\14)?\0\0\0\0 d/?\0\0\0\0\\955?\0\0\0\0v¤;?\0\0\0\0M\8dA?\0\0\0\0»KG?\0\0\0\0¡ÛL?\0\0\0\0Ú8R?\0\0\0\0D_W?\0\0\0\0ºJ\?\0\0\0\0\e÷`?\0\0\0\0C`e?\0\0\0\0\ e\82i?\0\0\0\0[Xm?\0\0\0\0\bßp?\0\0\0\0î\11t?\0\0\0\0íìv?\0\0\0\0áky?\0\0\0\0¦\8a{?\0\0\0\0\1cE}?\0\0\0\0\1f\97~?\0\0\0\0\8a|\7f?\0\0\0\0\7f?\12þ\169\91ö\7f?óJ¨:Û«\7f?
+\8cg;t\18\7f?3Äà;w>~?±ÿ7<\ 1 }?}\1a\88<,¿{?\8f=¼<\13\1ez?£%ø<Ó>x?¤Ç\1d=\85#v?\8a\eC=HÎs?Ïìk=3Aq?Ý\f\8c=d~n?LÀ£=÷\87k?Øÿ¼=\ 5`h?¥º×=¬\be?Úßó=\ 5\84a?O¯\b>-Ô]?\a\13\18>?ûY?ª\12(>VûU?Í¥8>\8dÖQ?ýÃI>\0\8fM?Ñd[>Ì&I?Ú\7fm>
+ D?T\ 6\80>Öü??h\81\89>L?;?ó,\93>\86i6?¼\ 4\9d>¡}1?\8f\ 4§>¸},?3(±>æk'?rk»>GJ"?\13ÊÅ>ö\1a\1d?ä?Ð>\ eà\17?¬ÈÚ>ª\9b\12?2`å>çO\r?A\ 2ð>ßþ\a?£ªú>¯ª\ 2?\8fª\ 2?áªú>Àþ\a?\80\ 2ð>ÈO\r?q`å>\8c\9b\12?èÈÚ>ïß\17?!@Ð>Ø\1a\1d?QÊÅ>*J"?­k»>Ék'?n(±>\9b},?Ê\ 4§>\84}1?ø\ 4\9d>ji6?,-\93>/?;?¡\81\89>ºü??\8d\ 6\80\9fD?C\80m>²&I?8e[>è\8eM?aÄI>tÖQ?.¦8>=ûU?
+\13(>(ûY?a\13\18>\17Ô]?¤¯\b\83a?{àó=\97\be?H»×=ó_h?f\0½=æ\87k?ÍÀ£=T~n?\\r\8c=$Aq?Ãík=:Îs?f\1cC={#v?RÈ\1d=Ê>x?¸&ø<
+\1ez?¸>¼<%¿{?\\e\88\1f}?\9a\ 18<s>~?fÆà;q\18\7f?\\8fg;Û«\7f?=J¨:\91ö\7f?Ãõ\169vù\7f?\0\0\0\0\91Å\7f?\0\0\0\0ò^\7f?\0\0\0\0ÏÆ~?\0\0\0\0_þ}?\0\0\0\0Ú\ 6}?\0\0\0\0tá{?\0\0\0\0i\8fz?\0\0\0\0ì\11y?\0\0\0\06jw?\0\0\0\0}\99u?\0\0\0\0ø s?\0\0\0\0à\81q?\0\0\0\0j=o?\0\0\0\0ÎÔl?\0\0\0\0CIj?\0\0\0\0ÿ\9bg?\0\0\0\0;Îd?\0\0\0\0,áa?\0\0\0\0
+Ö^?\0\0\0\0\ e®[?\0\0\0\0ljX?\0\0\0\0\\fU?\0\0\0\0\16\95Q?\0\0\0\0Ï\ 5N?\0\0\0\0Á_J?\0\0\0\0!¤F?\0\0\0\0(ÔB?\0\0\0\0
+ñ>?\0\0\0\0\0ü:?\0\0\0\0Aö6?\0\0\0\0\ 4á2?\0\0\0\0\80½.?\0\0\0\0ì\8c*?\0\0\0\0\7fP&?\0\0\0\0o       "?\0\0\0\0ö¸\1d?\0\0\0\0H`\19?\0\0\0\0\9d\0\15?\0\0\0\0.\9b\10?\0\0\0\001\f?\0\0\0\0ÚÃ\a?\0\0\0\0dT\ 3?\0\0\0\0
+Èý>\0\0\0\0èçô>\0\0\0\0Ì
+ì>\0\0\0\0,3ã>\0\0\0\0ncÚ>\0\0\0\0\ 5\9eÑ>\0\0\0\0]åÈ>\0\0\0\0é;À>\0\0\0\0\12¤·>\0\0\0\0H ¯>\0\0\0\0ö²¦>\0\0\0\0\92^\9e>\0\0\0\0}%\96>\0\0\0\03
+\8e>\0\0\0\0\1a\ f\86>\0\0\0\0Hm|>\0\0\0\0v\ 6m>\0\0\0\0\9fî]>\0\0\0\0\9f*O>\0\0\0\0\¿@>\0\0\0\0\9f±2>\0\0\0\0R\ 6%>\0\0\0\0\17>\0\0\0\0
+>\0\0\0\0\14\aý=\0\0\0\0\14%å=\0\0\0\0\858Î=\0\0\0\0\1fK¸=\0\0\0\0\9af£=\0\0\0\0¸\94\8f=\0\0\0\0)¾y=\0\0\0\0H\9fV=\0\0\0\0×ß5=\0\0\0\0H\93\17=\0\0\0\0f\9a÷<\0\0\0\0ìAÅ<\0\0\0\0\0D\98<\0\0\0\0®\8fa<\0\0\0\0\1d<\0\0\0\0¸¾Ë;\0\0\0\0=
+g;\0\0\0\0áúÎ:\0\0\0\0\9a\99Ð9\0\0\0\0
+×#´\0\0\0\0
\ No newline at end of file
diff --git a/automated-tests/resources/AnimatedMorphSphere.gltf b/automated-tests/resources/AnimatedMorphSphere.gltf
new file mode 100644 (file)
index 0000000..95c2751
--- /dev/null
@@ -0,0 +1,276 @@
+{\r
+  "accessors": [\r
+    {\r
+      "bufferView": 0,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.009999998,\r
+        0.009999991,\r
+        0.01\r
+      ],\r
+      "min": [\r
+        -0.0100000026,\r
+        -0.0100000035,\r
+        -0.01\r
+      ]\r
+    },\r
+    {\r
+      "bufferView": 3,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "name": "Ship"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.0313265175,\r
+        0.0226246975,\r
+        0.008465132\r
+      ],\r
+      "min": [\r
+        -0.0313265137,\r
+        -0.022857653,\r
+        0.0\r
+      ],\r
+      "name": "Ship"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "name": "Ship"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "name": "Blob"\r
+    },\r
+    {\r
+      "bufferView": 7,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.008781092,\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "min": [\r
+        -0.008781091,\r
+        -0.0007655843,\r
+        0.0\r
+      ],\r
+      "name": "Blob"\r
+    },\r
+    {\r
+      "bufferView": 8,\r
+      "componentType": 5126,\r
+      "count": 1876,\r
+      "type": "VEC3",\r
+      "name": "Blob"\r
+    },\r
+    {\r
+      "bufferView": 9,\r
+      "componentType": 5123,\r
+      "count": 2880,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 10,\r
+      "componentType": 5126,\r
+      "count": 217,\r
+      "type": "SCALAR",\r
+      "max": [\r
+        7.19999456\r
+      ],\r
+      "min": [\r
+        0.0\r
+      ]\r
+    },\r
+    {\r
+      "bufferView": 11,\r
+      "componentType": 5126,\r
+      "count": 434,\r
+      "type": "SCALAR"\r
+    }\r
+  ],\r
+  "animations": [\r
+    {\r
+      "channels": [\r
+        {\r
+          "sampler": 0,\r
+          "target": {\r
+            "node": 0,\r
+            "path": "weights"\r
+          }\r
+        }\r
+      ],\r
+      "samplers": [\r
+        {\r
+          "input": 10,\r
+          "interpolation": "LINEAR",\r
+          "output": 11\r
+        }\r
+      ],\r
+      "name": "Globe"\r
+    }\r
+  ],\r
+  "asset": {\r
+    "generator": "glTF Tools for Unity",\r
+    "version": "2.0"\r
+  },\r
+  "bufferViews": [\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 22512,\r
+      "byteLength": 30016\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 52528,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 75040,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 97552,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 120064,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 142576,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 165088,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 187600,\r
+      "byteLength": 22512\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 210112,\r
+      "byteLength": 5760\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 215872,\r
+      "byteLength": 868\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 216740,\r
+      "byteLength": 1736\r
+    }\r
+  ],\r
+  "buffers": [\r
+    {\r
+      "uri": "AnimatedMorphSphere.bin",\r
+      "byteLength": 218476\r
+    }\r
+  ],\r
+  "meshes": [\r
+    {\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "NORMAL": 0,\r
+            "TANGENT": 1,\r
+            "POSITION": 2\r
+          },\r
+          "indices": 9,\r
+          "material": 0,\r
+          "targets": [\r
+            {\r
+              "NORMAL": 3,\r
+              "POSITION": 4,\r
+              "TANGENT": 5\r
+            },\r
+            {\r
+              "NORMAL": 6,\r
+              "POSITION": 7,\r
+              "TANGENT": 8\r
+            }\r
+          ]\r
+        }\r
+      ],\r
+      "weights": [\r
+        0.0,\r
+        0.0\r
+      ],\r
+      "name": "Sphere"\r
+    }\r
+  ],\r
+  "materials": [\r
+    {\r
+      "pbrMetallicRoughness": {\r
+        "metallicFactor": 0.0,\r
+        "roughnessFactor": 0.5\r
+      },\r
+      "name": "No Name"\r
+    }\r
+  ],\r
+  "nodes": [\r
+    {\r
+      "mesh": 0,\r
+      "rotation": [\r
+        0.0,\r
+        0.7071067,\r
+        -0.7071068,\r
+        0.0\r
+      ],\r
+      "scale": [\r
+        100.0,\r
+        100.0,\r
+        100.0\r
+      ],\r
+      "name": "AnimatedMorphSphere"\r
+    }\r
+  ],\r
+  "scene": 0,\r
+  "scenes": [\r
+    {\r
+      "nodes": [\r
+        0\r
+      ]\r
+    }\r
+  ]\r
+}
\ No newline at end of file
diff --git a/automated-tests/resources/AnimatedTriangle.gltf b/automated-tests/resources/AnimatedTriangle.gltf
new file mode 100644 (file)
index 0000000..4e4a9cb
--- /dev/null
@@ -0,0 +1,118 @@
+{\r
+  "scene" : 0,\r
+  "scenes" : [\r
+    {\r
+      "nodes" : [ 0 ]\r
+    }\r
+  ],\r
+  \r
+  "nodes" : [\r
+    {\r
+      "mesh" : 0,\r
+      "rotation" : [ 0.0, 0.0, 0.0, 1.0 ]\r
+    }\r
+  ],\r
+  \r
+  "meshes" : [\r
+    {\r
+      "primitives" : [ {\r
+        "attributes" : {\r
+          "POSITION" : 1\r
+        },\r
+        "indices" : 0\r
+      } ]\r
+    }\r
+  ],\r
+  \r
+  "animations": [\r
+    {\r
+      "samplers" : [\r
+        {\r
+          "input" : 2,\r
+          "interpolation" : "LINEAR",\r
+          "output" : 3\r
+        }\r
+      ],\r
+      "channels" : [ {\r
+        "sampler" : 0,\r
+        "target" : {\r
+          "node" : 0,\r
+          "path" : "rotation"\r
+        }\r
+      } ]\r
+    }\r
+  ],\r
+\r
+  "buffers" : [\r
+    {\r
+      "uri" : "simpleTriangle.bin",\r
+      "byteLength" : 44\r
+    },\r
+    {\r
+      "uri" : "animation.bin",\r
+      "byteLength" : 100\r
+    }\r
+  ],\r
+  "bufferViews" : [\r
+    {\r
+      "buffer" : 0,\r
+      "byteOffset" : 0,\r
+      "byteLength" : 6,\r
+      "target" : 34963\r
+    },\r
+    {\r
+      "buffer" : 0,\r
+      "byteOffset" : 8,\r
+      "byteLength" : 36,\r
+      "target" : 34962\r
+    },\r
+    {\r
+      "buffer" : 1,\r
+      "byteOffset" : 0,\r
+      "byteLength" : 100\r
+    }\r
+  ],\r
+  "accessors" : [\r
+    {\r
+      "bufferView" : 0,\r
+      "byteOffset" : 0,\r
+      "componentType" : 5123,\r
+      "count" : 3,\r
+      "type" : "SCALAR",\r
+      "max" : [ 2 ],\r
+      "min" : [ 0 ]\r
+    },\r
+    {\r
+      "bufferView" : 1,\r
+      "byteOffset" : 0,\r
+      "componentType" : 5126,\r
+      "count" : 3,\r
+      "type" : "VEC3",\r
+      "max" : [ 1.0, 1.0, 0.0 ],\r
+      "min" : [ 0.0, 0.0, 0.0 ]\r
+    },\r
+    {\r
+      "bufferView" : 2,\r
+      "byteOffset" : 0,\r
+      "componentType" : 5126,\r
+      "count" : 5,\r
+      "type" : "SCALAR",\r
+      "max" : [ 1.0 ],\r
+      "min" : [ 0.0 ]\r
+    },\r
+    {\r
+      "bufferView" : 2,\r
+      "byteOffset" : 20,\r
+      "componentType" : 5126,\r
+      "count" : 5,\r
+      "type" : "VEC4",\r
+      "max" : [ 0.0, 0.0, 1.0, 1.0 ],\r
+      "min" : [ 0.0, 0.0, 0.0, -0.707 ]\r
+    }\r
+  ],\r
+  \r
+  "asset" : {\r
+    "version" : "2.0"\r
+  }\r
+  \r
+}\r
diff --git a/automated-tests/resources/BoxAnimated.gltf b/automated-tests/resources/BoxAnimated.gltf
new file mode 100644 (file)
index 0000000..afa7afb
--- /dev/null
@@ -0,0 +1,327 @@
+{\r
+    "asset": {\r
+        "generator": "COLLADA2GLTF",\r
+        "version": "2.0"\r
+    },\r
+    "scene": 0,\r
+    "scenes": [\r
+        {\r
+            "nodes": [\r
+                3,\r
+                0\r
+            ]\r
+        }\r
+    ],\r
+    "nodes": [\r
+        {\r
+            "children": [\r
+                1\r
+            ],\r
+            "rotation": [\r
+                -0.0,\r
+                -0.0,\r
+                -0.0,\r
+                -1.0\r
+            ]\r
+        },\r
+        {\r
+            "children": [\r
+                2\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 0,\r
+            "rotation": [\r
+                -0.0,\r
+                -0.0,\r
+                -0.0,\r
+                -1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 1\r
+        }\r
+    ],\r
+    "meshes": [\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 1,\r
+                        "POSITION": 2\r
+                    },\r
+                    "indices": 0,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                }\r
+            ],\r
+            "name": "inner_box"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 4,\r
+                        "POSITION": 5\r
+                    },\r
+                    "indices": 3,\r
+                    "mode": 4,\r
+                    "material": 1\r
+                }\r
+            ],\r
+            "name": "outer_box"\r
+        }\r
+    ],\r
+    "animations": [\r
+        {\r
+            "channels": [\r
+                {\r
+                    "sampler": 0,\r
+                    "target": {\r
+                        "node": 2,\r
+                        "path": "rotation"\r
+                    }\r
+                },\r
+                {\r
+                    "sampler": 1,\r
+                    "target": {\r
+                        "node": 0,\r
+                        "path": "translation"\r
+                    }\r
+                }\r
+            ],\r
+            "samplers": [\r
+                {\r
+                    "input": 6,\r
+                    "interpolation": "LINEAR",\r
+                    "output": 7\r
+                },\r
+                {\r
+                    "input": 8,\r
+                    "interpolation": "LINEAR",\r
+                    "output": 9\r
+                }\r
+            ]\r
+        }\r
+    ],\r
+    "accessors": [\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 0,\r
+            "componentType": 5123,\r
+            "count": 186,\r
+            "max": [\r
+                95\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 96,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1152,\r
+            "componentType": 5126,\r
+            "count": 96,\r
+            "max": [\r
+                0.33504000306129458,\r
+                0.5,\r
+                0.33504000306129458\r
+            ],\r
+            "min": [\r
+                -0.33504000306129458,\r
+                -0.5,\r
+                -0.33504000306129458\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 372,\r
+            "componentType": 5123,\r
+            "count": 576,\r
+            "max": [\r
+                223\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 2304,\r
+            "componentType": 5126,\r
+            "count": 224,\r
+            "max": [\r
+                1.0,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 4992,\r
+            "componentType": 5126,\r
+            "count": 224,\r
+            "max": [\r
+                0.5,\r
+                0.5,\r
+                0.5\r
+            ],\r
+            "min": [\r
+                -0.5,\r
+                -0.5,\r
+                -0.5\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 2,\r
+            "max": [\r
+                2.5\r
+            ],\r
+            "min": [\r
+                1.25\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 3,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 2,\r
+            "max": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                4.4896593387466768e-11\r
+            ],\r
+            "min": [\r
+                -0.0,\r
+                0.0,\r
+                0.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC4"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 8,\r
+            "componentType": 5126,\r
+            "count": 4,\r
+            "max": [\r
+                3.708329916000366\r
+            ],\r
+            "min": [\r
+                0.0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 4,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 4,\r
+            "max": [\r
+                0.0,\r
+                2.5199999809265138,\r
+                0.0\r
+            ],\r
+            "min": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ],\r
+            "type": "VEC3"\r
+        }\r
+    ],\r
+    "materials": [\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.800000011920929,\r
+                    0.4159420132637024,\r
+                    0.7952920198440552,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "name": "inner"\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.3016040027141571,\r
+                    0.5335419774055481,\r
+                    0.800000011920929,\r
+                    1.0\r
+                ],\r
+                "metallicFactor": 0.0\r
+            },\r
+            "name": "outer"\r
+        }\r
+    ],\r
+    "bufferViews": [\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 7784,\r
+            "byteLength": 1524,\r
+            "target": 34963\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 80,\r
+            "byteLength": 7680,\r
+            "byteStride": 12,\r
+            "target": 34962\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 7760,\r
+            "byteLength": 24\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 0,\r
+            "byteLength": 32\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 32,\r
+            "byteLength": 48\r
+        }\r
+    ],\r
+    "buffers": [\r
+        {\r
+            "byteLength": 9308,\r
+            "uri": "BoxAnimated0.bin"\r
+        }\r
+    ]\r
+}\r
diff --git a/automated-tests/resources/BoxAnimated0.bin b/automated-tests/resources/BoxAnimated0.bin
new file mode 100644 (file)
index 0000000..2e4ef6e
Binary files /dev/null and b/automated-tests/resources/BoxAnimated0.bin differ
diff --git a/automated-tests/resources/CesiumMan.gltf b/automated-tests/resources/CesiumMan.gltf
new file mode 100644 (file)
index 0000000..e9356ff
--- /dev/null
@@ -0,0 +1,2715 @@
+{\r
+  "asset": {\r
+    "generator": "COLLADA2GLTF",\r
+    "version": "2.0"\r
+  },\r
+  "scenes": [\r
+    {\r
+      "nodes": [\r
+        0\r
+      ]\r
+    }\r
+  ],\r
+  "scene": 0,\r
+  "nodes": [\r
+    {\r
+      "children": [\r
+        1\r
+      ],\r
+      "matrix": [\r
+        1,\r
+        0,\r
+        0,\r
+        0,\r
+        0,\r
+        0,\r
+        -1,\r
+        0,\r
+        0,\r
+        1,\r
+        0,\r
+        0,\r
+        0,\r
+        0,\r
+        0,\r
+        1\r
+      ],\r
+      "name": "Z_UP"\r
+    },\r
+    {\r
+      "children": [\r
+        3,\r
+        2\r
+      ],\r
+      "matrix": [\r
+        -4.371139894487897e-8,\r
+        -1,\r
+        0,\r
+        0,\r
+        1,\r
+        -4.371139894487897e-8,\r
+        0,\r
+        0,\r
+        0,\r
+        0,\r
+        1,\r
+        0,\r
+        0,\r
+        0,\r
+        0,\r
+        1\r
+      ],\r
+      "name": "Armature"\r
+    },\r
+    {\r
+      "mesh": 0,\r
+      "skin": 0,\r
+      "name": "Cesium_Man"\r
+    },\r
+    {\r
+      "children": [\r
+        12,\r
+        8,\r
+        4\r
+      ],\r
+      "translation": [\r
+        1.57554005397742e-8,\r
+        0.004999836906790733,\r
+        0.6789999008178711\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.0378035344183445,\r
+        0,\r
+        -0.9992852210998536\r
+      ],\r
+      "name": "Skeleton_torso_joint_1",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        5\r
+      ],\r
+      "translation": [\r
+        0.02855719067156315,\r
+        -0.06803914159536362,\r
+        -0.06295864284038544\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.6898291707038879,\r
+        0,\r
+        -0.7239722013473511\r
+      ],\r
+      "name": "leg_joint_R_1",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        6\r
+      ],\r
+      "translation": [\r
+        0.26089081168174744,\r
+        -0.009026050567626951,\r
+        0.05167089030146599\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.0941137745976448,\r
+        0,\r
+        -0.9955614805221558\r
+      ],\r
+      "scale": [\r
+        1.0000001192092896,\r
+        1,\r
+        1.0000001192092896\r
+      ],\r
+      "name": "leg_joint_R_2"\r
+    },\r
+    {\r
+      "children": [\r
+        7\r
+      ],\r
+      "translation": [\r
+        0.27546030282974243,\r
+        -0.0014317259192466736,\r
+        -0.014104830101132391\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.8666408061981201,\r
+        0,\r
+        0.4989325702190399\r
+      ],\r
+      "name": "leg_joint_R_3",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "translation": [\r
+        -0.06681963056325912,\r
+        -0.001072264974936843,\r
+        0.026351310312747955\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.3269147574901581,\r
+        0,\r
+        -0.9450538158416748\r
+      ],\r
+      "name": "leg_joint_R_5",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        9\r
+      ],\r
+      "translation": [\r
+        0.028519999235868457,\r
+        0.06803944706916809,\r
+        -0.06295935809612274\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.32463353872299194,\r
+        0,\r
+        -0.9458398818969728\r
+      ],\r
+      "name": "leg_joint_L_1",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        10\r
+      ],\r
+      "translation": [\r
+        0.20916390419006348,\r
+        0.009055502712726591,\r
+        -0.16426950693130493\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.5294369459152222,\r
+        0,\r
+        -0.8483493328094482\r
+      ],\r
+      "scale": [\r
+        1.0000001192092896,\r
+        1,\r
+        1.0000001192092896\r
+      ],\r
+      "name": "leg_joint_L_2"\r
+    },\r
+    {\r
+      "children": [\r
+        11\r
+      ],\r
+      "translation": [\r
+        0.27579009532928467,\r
+        0.0013972519664093852,\r
+        0.004122479818761349\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.8377647399902344,\r
+        0,\r
+        -0.5460314750671387\r
+      ],\r
+      "scale": [\r
+        1,\r
+        0.9999999403953552,\r
+        1\r
+      ],\r
+      "name": "leg_joint_L_3"\r
+    },\r
+    {\r
+      "translation": [\r
+        -0.06558381021022797,\r
+        0.001090653007850051,\r
+        0.02929146029055119\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.3130458891391754,\r
+        0,\r
+        -0.9497380256652832\r
+      ],\r
+      "name": "leg_joint_L_5",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        13\r
+      ],\r
+      "translation": [\r
+        0.0000133617004394182,\r
+        -0.000013373800356930587,\r
+        0.14541690051555634\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.6573964357376099,\r
+        0,\r
+        -0.7535448670387268\r
+      ],\r
+      "name": "Skeleton_torso_joint_2",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        20,\r
+        17,\r
+        14\r
+      ],\r
+      "translation": [\r
+        -0.2505168914794922,\r
+        6.072219775887788e-7,\r
+        -0.00007290810026461259\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.6227028965950012,\r
+        0,\r
+        -0.7824583649635315\r
+      ],\r
+      "name": "torso_joint_3",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        15\r
+      ],\r
+      "translation": [\r
+        -0.00003830249988823198,\r
+        -0.09098774939775468,\r
+        -0.000062032304413151\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.9909319281578064,\r
+        0,\r
+        -0.13436488807201385\r
+      ],\r
+      "name": "Skeleton_arm_joint_R",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        16\r
+      ],\r
+      "translation": [\r
+        -0.03554634004831314,\r
+        -0.2154989987611771,\r
+        0.10423289984464645\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.8961479663848877,\r
+        0,\r
+        0.4437553286552429\r
+      ],\r
+      "scale": [\r
+        0.9999999403953552,\r
+        1,\r
+        0.9999999403953552\r
+      ],\r
+      "name": "Skeleton_arm_joint_R__2_"\r
+    },\r
+    {\r
+      "translation": [\r
+        0.03137021884322167,\r
+        -0.1430010050535202,\r
+        -0.11761169880628586\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.3792171180248261,\r
+        0,\r
+        -0.9253078103065492\r
+      ],\r
+      "scale": [\r
+        1.0000001192092896,\r
+        1,\r
+        1.0000001192092896\r
+      ],\r
+      "name": "Skeleton_arm_joint_R__3_"\r
+    },\r
+    {\r
+      "children": [\r
+        18\r
+      ],\r
+      "translation": [\r
+        -0.00003837469921563752,\r
+        0.091013602912426,\r
+        -0.00006143339851405472\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.9959768652915956,\r
+        0,\r
+        0.08961082249879837\r
+      ],\r
+      "name": "Skeleton_arm_joint_L__4_",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        19\r
+      ],\r
+      "translation": [\r
+        0.01322161965072155,\r
+        0.21549950540065768,\r
+        0.10933209955692293\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.0711694285273552,\r
+        0,\r
+        -0.9974642395973206\r
+      ],\r
+      "name": "Skeleton_arm_joint_L__3_",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "translation": [\r
+        -0.09332461655139924,\r
+        0.1430000960826874,\r
+        0.07814791053533554\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.02254222705960274,\r
+        0,\r
+        -0.9997459053993224\r
+      ],\r
+      "name": "Skeleton_arm_joint_L__2_",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        21\r
+      ],\r
+      "translation": [\r
+        -0.000002366030003031483,\r
+        0.000002413989932392724,\r
+        0.06483621150255203\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        -0.660634458065033,\r
+        0,\r
+        -0.750707745552063\r
+      ],\r
+      "name": "Skeleton_neck_joint_1",\r
+      "scale": [\r
+        1,\r
+        1,\r
+        1\r
+      ]\r
+    },\r
+    {\r
+      "translation": [\r
+        -0.05204017087817192,\r
+        -3.3993298842460724e-8,\r
+        -0.0000026607899599184748\r
+      ],\r
+      "rotation": [\r
+        0,\r
+        0.9996904730796814,\r
+        0,\r
+        0.024879230186343193\r
+      ],\r
+      "scale": [\r
+        1.0000001192092896,\r
+        1,\r
+        1.0000001192092896\r
+      ],\r
+      "name": "Skeleton_neck_joint_2"\r
+    }\r
+  ],\r
+  "meshes": [\r
+    {\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "JOINTS_0": 1,\r
+            "NORMAL": 2,\r
+            "POSITION": 3,\r
+            "TEXCOORD_0": 4,\r
+            "WEIGHTS_0": 5\r
+          },\r
+          "indices": 0,\r
+          "mode": 4,\r
+          "material": 0\r
+        }\r
+      ],\r
+      "name": "Cesium_Man"\r
+    }\r
+  ],\r
+  "animations": [\r
+    {\r
+      "channels": [\r
+        {\r
+          "sampler": 0,\r
+          "target": {\r
+            "node": 3,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 1,\r
+          "target": {\r
+            "node": 3,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 2,\r
+          "target": {\r
+            "node": 3,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 3,\r
+          "target": {\r
+            "node": 12,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 4,\r
+          "target": {\r
+            "node": 12,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 5,\r
+          "target": {\r
+            "node": 12,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 6,\r
+          "target": {\r
+            "node": 13,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 7,\r
+          "target": {\r
+            "node": 13,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 8,\r
+          "target": {\r
+            "node": 13,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 9,\r
+          "target": {\r
+            "node": 20,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 10,\r
+          "target": {\r
+            "node": 20,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 11,\r
+          "target": {\r
+            "node": 20,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 12,\r
+          "target": {\r
+            "node": 21,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 13,\r
+          "target": {\r
+            "node": 21,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 14,\r
+          "target": {\r
+            "node": 21,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 15,\r
+          "target": {\r
+            "node": 17,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 16,\r
+          "target": {\r
+            "node": 17,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 17,\r
+          "target": {\r
+            "node": 17,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 18,\r
+          "target": {\r
+            "node": 18,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 19,\r
+          "target": {\r
+            "node": 18,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 20,\r
+          "target": {\r
+            "node": 18,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 21,\r
+          "target": {\r
+            "node": 19,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 22,\r
+          "target": {\r
+            "node": 19,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 23,\r
+          "target": {\r
+            "node": 19,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 24,\r
+          "target": {\r
+            "node": 14,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 25,\r
+          "target": {\r
+            "node": 14,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 26,\r
+          "target": {\r
+            "node": 14,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 27,\r
+          "target": {\r
+            "node": 15,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 28,\r
+          "target": {\r
+            "node": 15,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 29,\r
+          "target": {\r
+            "node": 15,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 30,\r
+          "target": {\r
+            "node": 16,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 31,\r
+          "target": {\r
+            "node": 16,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 32,\r
+          "target": {\r
+            "node": 16,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 33,\r
+          "target": {\r
+            "node": 8,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 34,\r
+          "target": {\r
+            "node": 8,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 35,\r
+          "target": {\r
+            "node": 8,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 36,\r
+          "target": {\r
+            "node": 9,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 37,\r
+          "target": {\r
+            "node": 9,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 38,\r
+          "target": {\r
+            "node": 9,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 39,\r
+          "target": {\r
+            "node": 10,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 40,\r
+          "target": {\r
+            "node": 10,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 41,\r
+          "target": {\r
+            "node": 10,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 42,\r
+          "target": {\r
+            "node": 11,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 43,\r
+          "target": {\r
+            "node": 11,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 44,\r
+          "target": {\r
+            "node": 11,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 45,\r
+          "target": {\r
+            "node": 4,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 46,\r
+          "target": {\r
+            "node": 4,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 47,\r
+          "target": {\r
+            "node": 4,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 48,\r
+          "target": {\r
+            "node": 5,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 49,\r
+          "target": {\r
+            "node": 5,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 50,\r
+          "target": {\r
+            "node": 5,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 51,\r
+          "target": {\r
+            "node": 6,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 52,\r
+          "target": {\r
+            "node": 6,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 53,\r
+          "target": {\r
+            "node": 6,\r
+            "path": "scale"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 54,\r
+          "target": {\r
+            "node": 7,\r
+            "path": "translation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 55,\r
+          "target": {\r
+            "node": 7,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 56,\r
+          "target": {\r
+            "node": 7,\r
+            "path": "scale"\r
+          }\r
+        }\r
+      ],\r
+      "samplers": [\r
+        {\r
+          "input": 6,\r
+          "interpolation": "LINEAR",\r
+          "output": 7\r
+        },\r
+        {\r
+          "input": 6,\r
+          "interpolation": "LINEAR",\r
+          "output": 8\r
+        },\r
+        {\r
+          "input": 6,\r
+          "interpolation": "LINEAR",\r
+          "output": 9\r
+        },\r
+        {\r
+          "input": 10,\r
+          "interpolation": "LINEAR",\r
+          "output": 11\r
+        },\r
+        {\r
+          "input": 10,\r
+          "interpolation": "LINEAR",\r
+          "output": 12\r
+        },\r
+        {\r
+          "input": 10,\r
+          "interpolation": "LINEAR",\r
+          "output": 13\r
+        },\r
+        {\r
+          "input": 14,\r
+          "interpolation": "LINEAR",\r
+          "output": 15\r
+        },\r
+        {\r
+          "input": 14,\r
+          "interpolation": "LINEAR",\r
+          "output": 16\r
+        },\r
+        {\r
+          "input": 14,\r
+          "interpolation": "LINEAR",\r
+          "output": 17\r
+        },\r
+        {\r
+          "input": 18,\r
+          "interpolation": "LINEAR",\r
+          "output": 19\r
+        },\r
+        {\r
+          "input": 18,\r
+          "interpolation": "LINEAR",\r
+          "output": 20\r
+        },\r
+        {\r
+          "input": 18,\r
+          "interpolation": "LINEAR",\r
+          "output": 21\r
+        },\r
+        {\r
+          "input": 22,\r
+          "interpolation": "LINEAR",\r
+          "output": 23\r
+        },\r
+        {\r
+          "input": 22,\r
+          "interpolation": "LINEAR",\r
+          "output": 24\r
+        },\r
+        {\r
+          "input": 22,\r
+          "interpolation": "LINEAR",\r
+          "output": 25\r
+        },\r
+        {\r
+          "input": 26,\r
+          "interpolation": "LINEAR",\r
+          "output": 27\r
+        },\r
+        {\r
+          "input": 26,\r
+          "interpolation": "LINEAR",\r
+          "output": 28\r
+        },\r
+        {\r
+          "input": 26,\r
+          "interpolation": "LINEAR",\r
+          "output": 29\r
+        },\r
+        {\r
+          "input": 30,\r
+          "interpolation": "LINEAR",\r
+          "output": 31\r
+        },\r
+        {\r
+          "input": 30,\r
+          "interpolation": "LINEAR",\r
+          "output": 32\r
+        },\r
+        {\r
+          "input": 30,\r
+          "interpolation": "LINEAR",\r
+          "output": 33\r
+        },\r
+        {\r
+          "input": 34,\r
+          "interpolation": "LINEAR",\r
+          "output": 35\r
+        },\r
+        {\r
+          "input": 34,\r
+          "interpolation": "LINEAR",\r
+          "output": 36\r
+        },\r
+        {\r
+          "input": 34,\r
+          "interpolation": "LINEAR",\r
+          "output": 37\r
+        },\r
+        {\r
+          "input": 38,\r
+          "interpolation": "LINEAR",\r
+          "output": 39\r
+        },\r
+        {\r
+          "input": 38,\r
+          "interpolation": "LINEAR",\r
+          "output": 40\r
+        },\r
+        {\r
+          "input": 38,\r
+          "interpolation": "LINEAR",\r
+          "output": 41\r
+        },\r
+        {\r
+          "input": 42,\r
+          "interpolation": "LINEAR",\r
+          "output": 43\r
+        },\r
+        {\r
+          "input": 42,\r
+          "interpolation": "LINEAR",\r
+          "output": 44\r
+        },\r
+        {\r
+          "input": 42,\r
+          "interpolation": "LINEAR",\r
+          "output": 45\r
+        },\r
+        {\r
+          "input": 46,\r
+          "interpolation": "LINEAR",\r
+          "output": 47\r
+        },\r
+        {\r
+          "input": 46,\r
+          "interpolation": "LINEAR",\r
+          "output": 48\r
+        },\r
+        {\r
+          "input": 46,\r
+          "interpolation": "LINEAR",\r
+          "output": 49\r
+        },\r
+        {\r
+          "input": 50,\r
+          "interpolation": "LINEAR",\r
+          "output": 51\r
+        },\r
+        {\r
+          "input": 50,\r
+          "interpolation": "LINEAR",\r
+          "output": 52\r
+        },\r
+        {\r
+          "input": 50,\r
+          "interpolation": "LINEAR",\r
+          "output": 53\r
+        },\r
+        {\r
+          "input": 54,\r
+          "interpolation": "LINEAR",\r
+          "output": 55\r
+        },\r
+        {\r
+          "input": 54,\r
+          "interpolation": "LINEAR",\r
+          "output": 56\r
+        },\r
+        {\r
+          "input": 54,\r
+          "interpolation": "LINEAR",\r
+          "output": 57\r
+        },\r
+        {\r
+          "input": 58,\r
+          "interpolation": "LINEAR",\r
+          "output": 59\r
+        },\r
+        {\r
+          "input": 58,\r
+          "interpolation": "LINEAR",\r
+          "output": 60\r
+        },\r
+        {\r
+          "input": 58,\r
+          "interpolation": "LINEAR",\r
+          "output": 61\r
+        },\r
+        {\r
+          "input": 62,\r
+          "interpolation": "LINEAR",\r
+          "output": 63\r
+        },\r
+        {\r
+          "input": 62,\r
+          "interpolation": "LINEAR",\r
+          "output": 64\r
+        },\r
+        {\r
+          "input": 62,\r
+          "interpolation": "LINEAR",\r
+          "output": 65\r
+        },\r
+        {\r
+          "input": 66,\r
+          "interpolation": "LINEAR",\r
+          "output": 67\r
+        },\r
+        {\r
+          "input": 66,\r
+          "interpolation": "LINEAR",\r
+          "output": 68\r
+        },\r
+        {\r
+          "input": 66,\r
+          "interpolation": "LINEAR",\r
+          "output": 69\r
+        },\r
+        {\r
+          "input": 70,\r
+          "interpolation": "LINEAR",\r
+          "output": 71\r
+        },\r
+        {\r
+          "input": 70,\r
+          "interpolation": "LINEAR",\r
+          "output": 72\r
+        },\r
+        {\r
+          "input": 70,\r
+          "interpolation": "LINEAR",\r
+          "output": 73\r
+        },\r
+        {\r
+          "input": 74,\r
+          "interpolation": "LINEAR",\r
+          "output": 75\r
+        },\r
+        {\r
+          "input": 74,\r
+          "interpolation": "LINEAR",\r
+          "output": 76\r
+        },\r
+        {\r
+          "input": 74,\r
+          "interpolation": "LINEAR",\r
+          "output": 77\r
+        },\r
+        {\r
+          "input": 78,\r
+          "interpolation": "LINEAR",\r
+          "output": 79\r
+        },\r
+        {\r
+          "input": 78,\r
+          "interpolation": "LINEAR",\r
+          "output": 80\r
+        },\r
+        {\r
+          "input": 78,\r
+          "interpolation": "LINEAR",\r
+          "output": 81\r
+        }\r
+      ]\r
+    }\r
+  ],\r
+  "skins": [\r
+    {\r
+      "inverseBindMatrices": 82,\r
+      "skeleton": 3,\r
+      "joints": [\r
+        3,\r
+        12,\r
+        13,\r
+        20,\r
+        21,\r
+        17,\r
+        14,\r
+        18,\r
+        15,\r
+        19,\r
+        16,\r
+        8,\r
+        4,\r
+        9,\r
+        5,\r
+        10,\r
+        6,\r
+        11,\r
+        7\r
+      ],\r
+      "name": "Armature"\r
+    }\r
+  ],\r
+  "accessors": [\r
+    {\r
+      "bufferView": 0,\r
+      "byteOffset": 0,\r
+      "componentType": 5123,\r
+      "count": 14016,\r
+      "max": [\r
+        3272\r
+      ],\r
+      "min": [\r
+        0\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "byteOffset": 0,\r
+      "componentType": 5123,\r
+      "count": 3273,\r
+      "max": [\r
+        18,\r
+        18,\r
+        18,\r
+        18\r
+      ],\r
+      "min": [\r
+        0,\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "byteOffset": 0,\r
+      "componentType": 5126,\r
+      "count": 3273,\r
+      "max": [\r
+        1,\r
+        0.9999808073043824,\r
+        0.9944415092468262\r
+      ],\r
+      "min": [\r
+        -1,\r
+        -0.9999808073043824,\r
+        -1\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "byteOffset": 39276,\r
+      "componentType": 5126,\r
+      "count": 3273,\r
+      "max": [\r
+        0.1809539943933487,\r
+        0.569136917591095,\r
+        1.5065499544143677\r
+      ],\r
+      "min": [\r
+        -0.13100001215934753,\r
+        -0.5691370964050293,\r
+        0\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "byteOffset": 26184,\r
+      "componentType": 5126,\r
+      "count": 3273,\r
+      "max": [\r
+        0.990805983543396,\r
+        0.9880298972129822\r
+      ],\r
+      "min": [\r
+        0.014079390093684196,\r
+        0.008445978164672852\r
+      ],\r
+      "type": "VEC2"\r
+    },\r
+    {\r
+      "bufferView": 3,\r
+      "byteOffset": 0,\r
+      "componentType": 5126,\r
+      "count": 3273,\r
+      "max": [\r
+        1,\r
+        0.989919900894165,\r
+        0.9510763883590698,\r
+        0.9196179509162904\r
+      ],\r
+      "min": [\r
+        0.010080089792609217,\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 0,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 0,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        3.880559873437051e-8,\r
+        -0.02000010944902897,\r
+        0.7110069990158081\r
+      ],\r
+      "min": [\r
+        2.716890046272624e-9,\r
+        -0.030000129714608192,\r
+        0.6399999856948853\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 0,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.0001435002632206306,\r
+        -0.02146764844655991,\r
+        -0.000009948204024112783,\r
+        -0.9980905055999756\r
+      ],\r
+      "min": [\r
+        -0.012384946458041668,\r
+        -0.06042621284723282,\r
+        -0.0041049933061003685,\r
+        -0.9997026920318604\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 576,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000004768371584,\r
+        1.0000001192092896,\r
+        1.000000238418579\r
+      ],\r
+      "min": [\r
+        0.9999999403953552,\r
+        0.9999998211860656,\r
+        0.9999997615814208\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 192,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 1152,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.000013520900211005937,\r
+        0.0009866129839792848,\r
+        0.1454171985387802\r
+      ],\r
+      "min": [\r
+        0.000013436199878924528,\r
+        0.0009865909814834597,\r
+        0.145416796207428\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 768,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.011148878373205662,\r
+        -0.7106494903564453,\r
+        0.0006393495132215321,\r
+        -0.6787928938865662\r
+      ],\r
+      "min": [\r
+        -0.008564536459743977,\r
+        -0.7339289784431458,\r
+        -0.025856714695692062,\r
+        -0.7034341096878052\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 1728,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000004768371584,\r
+        1.000000238418579,\r
+        0.9999998211860656\r
+      ],\r
+      "min": [\r
+        0.9999999403953552,\r
+        0.9999998807907104,\r
+        0.9999989867210388\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 384,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 2304,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.25051650404930115,\r
+        5.923209869251878e-7,\r
+        -0.00007277730037458241\r
+      ],\r
+      "min": [\r
+        -0.25051701068878174,\r
+        5.58793999516638e-7,\r
+        -0.00007287789776455611\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 1536,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.13804565370082855,\r
+        0.6359269618988037,\r
+        -0.003375347936525941,\r
+        -0.7641801238059998\r
+      ],\r
+      "min": [\r
+        -0.06163197010755539,\r
+        0.6225405335426331,\r
+        -0.0653248131275177,\r
+        -0.7825579643249512\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 2880,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.000001072883606,\r
+        1.0000003576278689,\r
+        1\r
+      ],\r
+      "min": [\r
+        1.0000004768371584,\r
+        0.9999999403953552,\r
+        0.999999463558197\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 576,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 3456,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.000002384189883741783,\r
+        0.000002458690005369135,\r
+        0.06483876705169678\r
+      ],\r
+      "min": [\r
+        -0.000002536919964768458,\r
+        0.000002384189883741783,\r
+        0.06483828276395798\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 2304,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.0364987850189209,\r
+        -0.6325404644012451,\r
+        0.04193282127380371,\r
+        -0.749859094619751\r
+      ],\r
+      "min": [\r
+        -0.02474863827228546,\r
+        -0.6592763066291809,\r
+        -0.03008362464606762,\r
+        -0.7735469341278076\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 4032,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1,\r
+        1.000000238418579,\r
+        1.000000238418579\r
+      ],\r
+      "min": [\r
+        0.9999996423721313,\r
+        0.9999995231628418,\r
+        0.9999995827674866\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 768,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 4608,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.0520395003259182,\r
+        7.450579708745408e-9,\r
+        -0.000002585350102890516\r
+      ],\r
+      "min": [\r
+        -0.05204005911946297,\r
+        -5.96045985901128e-8,\r
+        -0.0000026747600259113824\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 3072,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.04680187255144119,\r
+        0.999507486820221,\r
+        0.002036086050793529,\r
+        0.09058715403079988\r
+      ],\r
+      "min": [\r
+        -0.093629889190197,\r
+        0.9950671792030336,\r
+        -0.00258980062790215,\r
+        0.0184526015073061\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 5184,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000003576278689,\r
+        1.000000238418579,\r
+        1.0000009536743164\r
+      ],\r
+      "min": [\r
+        0.9999998807907104,\r
+        0.9999996423721313,\r
+        1.000000238418579\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 960,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 5760,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.00003742050103028305,\r
+        0.08800023794174194,\r
+        -0.00005880460230400786\r
+      ],\r
+      "min": [\r
+        -0.000037621699448209256,\r
+        0.08799994736909866,\r
+        -0.000059304802562110126\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 3840,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.2951536476612091,\r
+        0.9301012754440308,\r
+        -0.2815393805503845,\r
+        0.3835828900337219\r
+      ],\r
+      "min": [\r
+        -0.13552021980285645,\r
+        0.8065234422683716,\r
+        -0.4443180561065674,\r
+        -0.17752912640571597\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 6336,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000005960464478,\r
+        1.0000001192092896,\r
+        1.0000003576278689\r
+      ],\r
+      "min": [\r
+        0.9999999403953552,\r
+        0.9999996423721313,\r
+        0.9999998211860656\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 1152,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 6912,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.013221889734268188,\r
+        0.215499609708786,\r
+        0.10933230072259904\r
+      ],\r
+      "min": [\r
+        0.01322161965072155,\r
+        0.2154994010925293,\r
+        0.10933209955692293\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 4608,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.023567700758576393,\r
+        0.02101488783955574,\r
+        0.176296666264534,\r
+        -0.971515953540802\r
+      ],\r
+      "min": [\r
+        -0.0574759915471077,\r
+        -0.18002526462078097,\r
+        -0.15063291788101196,\r
+        -0.998132348060608\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 7488,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.9999998211860656,\r
+        0.9999998211860656,\r
+        0.9999999403953552\r
+      ],\r
+      "min": [\r
+        0.9999991059303284,\r
+        0.9999993443489076,\r
+        0.9999994039535524\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 1344,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 8064,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.09332455694675446,\r
+        0.1430000960826874,\r
+        0.07814794778823853\r
+      ],\r
+      "min": [\r
+        -0.09332473576068878,\r
+        0.14299990236759189,\r
+        0.07814773917198181\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 5376,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.03372078761458397,\r
+        0.0026474546175450087,\r
+        0.207317128777504,\r
+        -0.9705979824066162\r
+      ],\r
+      "min": [\r
+        0.006105833686888218,\r
+        -0.12215615808963776,\r
+        0.003784916130825877,\r
+        -0.9994208216667176\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 8640,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000007152557373,\r
+        1.0000003576278689,\r
+        1.0000008344650269\r
+      ],\r
+      "min": [\r
+        1.0000001192092896,\r
+        0.9999998211860656,\r
+        1.000000238418579\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 1536,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 9216,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.00003894419933203608,\r
+        -0.0879998430609703,\r
+        -0.00005919210161664523\r
+      ],\r
+      "min": [\r
+        -0.0000392795009247493,\r
+        -0.08800008893013,\r
+        -0.00005960090129519813\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 6144,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.2377220243215561,\r
+        0.942186713218689,\r
+        0.37760788202285767,\r
+        0.2007839232683182\r
+      ],\r
+      "min": [\r
+        -0.2700891792774201,\r
+        0.8732703924179077,\r
+        0.2710656225681305,\r
+        -0.2673804461956024\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 9792,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.000000238418579,\r
+        1.0000003576278689,\r
+        1.0000001192092896\r
+      ],\r
+      "min": [\r
+        0.999999701976776,\r
+        0.9999997615814208,\r
+        0.9999997615814208\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 1728,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 10368,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.035546209663152695,\r
+        -0.21549880504608157,\r
+        0.10423330217599867\r
+      ],\r
+      "min": [\r
+        -0.03554638102650643,\r
+        -0.21549910306930545,\r
+        0.10423299670219421\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 6912,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.00792065542191267,\r
+        0.9315358996391296,\r
+        0.0024673622101545334,\r
+        0.41479358077049255\r
+      ],\r
+      "min": [\r
+        -0.15234939754009247,\r
+        0.9063802361488342,\r
+        -0.08167753368616104,\r
+        0.3280625641345978\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 10944,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000005960464478,\r
+        1.0000001192092896,\r
+        1.000000238418579\r
+      ],\r
+      "min": [\r
+        1,\r
+        0.9999996423721313,\r
+        0.9999996423721313\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 1920,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 11520,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.03137049078941345,\r
+        -0.1430007964372635,\r
+        -0.11761150509119034\r
+      ],\r
+      "min": [\r
+        0.03137030825018883,\r
+        -0.1430010050535202,\r
+        -0.11761169880628586\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 7680,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.22148266434669495,\r
+        0.3926030695438385,\r
+        0.08952529728412628,\r
+        -0.9178923964500428\r
+      ],\r
+      "min": [\r
+        0.055695075541734695,\r
+        0.277910977602005,\r
+        -0.015314305201172829,\r
+        -0.9438881278038024\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 12096,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000004768371584,\r
+        1.0000004768371584,\r
+        1.0000004768371584\r
+      ],\r
+      "min": [\r
+        0.9999997615814208,\r
+        0.9999997615814208,\r
+        0.9999998807907104\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 2112,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 12672,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.028520189225673676,\r
+        0.06762184202671051,\r
+        -0.06295985728502274\r
+      ],\r
+      "min": [\r
+        0.028520019724965096,\r
+        0.06762173771858215,\r
+        -0.06296010315418243\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 8448,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.013129070401191711,\r
+        0.10440785437822342,\r
+        0.004284336231648922,\r
+        -0.7728573679924011\r
+      ],\r
+      "min": [\r
+        -0.013805897906422617,\r
+        -0.6344362497329712,\r
+        -0.03212129324674606,\r
+        -0.9994977116584778\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 13248,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000001192092896,\r
+        1.0000004768371584,\r
+        1.000000238418579\r
+      ],\r
+      "min": [\r
+        0.9999995231628418,\r
+        1,\r
+        0.9999995827674866\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 2304,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 13824,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.209164097905159,\r
+        0.009055494330823421,\r
+        -0.16426970064640045\r
+      ],\r
+      "min": [\r
+        0.20916390419006348,\r
+        0.009055464528501034,\r
+        -0.1642698049545288\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 9216,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.009955321438610554,\r
+        -0.2965533435344696,\r
+        0.003957682754844427,\r
+        -0.1911347657442093\r
+      ],\r
+      "min": [\r
+        -0.00983923487365246,\r
+        -0.9813112020492554,\r
+        -0.02193812094628811,\r
+        -0.9549583792686462\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 14400,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.000000238418579,\r
+        0.999999463558197,\r
+        1.0000001192092896\r
+      ],\r
+      "min": [\r
+        0.999999463558197,\r
+        0.999998927116394,\r
+        0.9999993443489076\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 2496,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 14976,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.2757900059223175,\r
+        0.0013972820015624166,\r
+        0.004122554790228605\r
+      ],\r
+      "min": [\r
+        0.27578991651535034,\r
+        0.0013972449814900756,\r
+        0.004122436046600342\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 9984,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.01264618057757616,\r
+        -0.8448027968406677,\r
+        0.03285584971308708,\r
+        -0.15347692370414737\r
+      ],\r
+      "min": [\r
+        -0.045710742473602295,\r
+        -0.9879721403121948,\r
+        0.007757793180644512,\r
+        -0.5345877408981323\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 15552,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000008344650269,\r
+        1.0000009536743164,\r
+        1.0000004768371584\r
+      ],\r
+      "min": [\r
+        1.000000238418579,\r
+        1.0000003576278689,\r
+        0.9999997615814208\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 2688,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 16128,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.06558377295732498,\r
+        0.00109061598777771,\r
+        0.029291389510035515\r
+      ],\r
+      "min": [\r
+        -0.06558384746313095,\r
+        0.001090570935048163,\r
+        0.029291240498423576\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 10752,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.022798636928200725,\r
+        0.5332140922546387,\r
+        -0.003377946326509118,\r
+        -0.844382643699646\r
+      ],\r
+      "min": [\r
+        0.007516560610383749,\r
+        0.22626954317092896,\r
+        -0.04913739487528801,\r
+        -0.972984254360199\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 16704,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000008344650269,\r
+        1.0000003576278689,\r
+        1.0000003576278689\r
+      ],\r
+      "min": [\r
+        0.9999998211860656,\r
+        0.999999701976776,\r
+        0.9999995231628418\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 2880,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 17280,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.028557300567626953,\r
+        -0.0684543326497078,\r
+        -0.06295845657587051\r
+      ],\r
+      "min": [\r
+        0.028557060286402702,\r
+        -0.06845436990261078,\r
+        -0.0629587471485138\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 11520,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.04037770628929138,\r
+        -0.2803998589515686,\r
+        0.02151232957839966,\r
+        -0.32386553287506104\r
+      ],\r
+      "min": [\r
+        -0.009615562856197357,\r
+        -0.9458208084106444,\r
+        -0.006491139996796846,\r
+        -0.9590301513671876\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 17856,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.000000238418579,\r
+        1.0000005960464478,\r
+        1.0000005960464478\r
+      ],\r
+      "min": [\r
+        0.9999994039535524,\r
+        0.9999999403953552,\r
+        0.9999998211860656\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 3072,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 18432,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.2608909010887146,\r
+        -0.00902603566646576,\r
+        0.05167100951075554\r
+      ],\r
+      "min": [\r
+        0.2608906924724579,\r
+        -0.009026064537465572,\r
+        0.05167080089449883\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 12288,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.02468797937035561,\r
+        0.19154119491577148,\r
+        0.017835097387433052,\r
+        -0.6250466108322144\r
+      ],\r
+      "min": [\r
+        -0.013421673327684404,\r
+        -0.7804162502288818,\r
+        -0.031287722289562225,\r
+        -0.9999792575836182\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 19008,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000003576278689,\r
+        1.0000007152557373,\r
+        1.000001072883606\r
+      ],\r
+      "min": [\r
+        0.999999463558197,\r
+        1,\r
+        0.999999701976776\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 3264,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 19584,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.2754603922367096,\r
+        -0.0014316890155896544,\r
+        -0.014104750007390976\r
+      ],\r
+      "min": [\r
+        0.27546021342277527,\r
+        -0.0014317409368231893,\r
+        -0.014104840345680714\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 13056,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.022092316299676895,\r
+        0.9990847110748292,\r
+        0.04779285565018654,\r
+        0.4428757429122925\r
+      ],\r
+      "min": [\r
+        -0.001671039150096476,\r
+        0.8965795040130615,\r
+        0.002310338197275996,\r
+        0.0384783074259758\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 20160,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.9999999403953552,\r
+        0.9999996423721313,\r
+        1.000000238418579\r
+      ],\r
+      "min": [\r
+        0.9999994039535524,\r
+        0.9999991655349731,\r
+        0.9999996423721313\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "byteOffset": 3456,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        2\r
+      ],\r
+      "min": [\r
+        0.04166661947965622\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 20736,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        -0.06681966781616211,\r
+        -0.0010721459984779358,\r
+        0.026351390406489372\r
+      ],\r
+      "min": [\r
+        -0.06681978702545166,\r
+        -0.001072190934792161,\r
+        0.02635126002132893\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "byteOffset": 13824,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        0.003402489935979247,\r
+        0.4966025054454804,\r
+        0.1101396307349205,\r
+        -0.8675833940505981\r
+      ],\r
+      "min": [\r
+        -0.027623889967799187,\r
+        0.26874634623527527,\r
+        -0.02591408602893353,\r
+        -0.9565747380256652\r
+      ],\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "byteOffset": 21312,\r
+      "componentType": 5126,\r
+      "count": 48,\r
+      "max": [\r
+        1.0000004768371584,\r
+        0.9999998211860656,\r
+        0.9999994039535524\r
+      ],\r
+      "min": [\r
+        0.9999995231628418,\r
+        0.999999225139618,\r
+        0.9999986886978148\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 7,\r
+      "byteOffset": 0,\r
+      "componentType": 5126,\r
+      "count": 19,\r
+      "max": [\r
+        0.9971418380737304,\r
+        -4.371139894487897e-8,\r
+        0.9996265172958374,\r
+        0,\r
+        4.3586464215650273e-8,\r
+        1,\r
+        4.3695074225524884e-8,\r
+        0,\r
+        0.9999366402626038,\r
+        0,\r
+        0.9971418380737304,\r
+        0,\r
+        1.1374080181121828,\r
+        0.44450080394744873,\r
+        1.0739599466323853,\r
+        1\r
+      ],\r
+      "min": [\r
+        -0.9999089241027832,\r
+        -4.371139894487897e-8,\r
+        -0.9999366402626038,\r
+        0,\r
+        -4.3707416352845037e-8,\r
+        1,\r
+        -4.37086278282095e-8,\r
+        0,\r
+        -0.9996265172958374,\r
+        0,\r
+        -0.9999089241027832,\r
+        0,\r
+        -1.189831018447876,\r
+        -0.45450031757354736,\r
+        -1.058603048324585,\r
+        1\r
+      ],\r
+      "type": "MAT4"\r
+    }\r
+  ],\r
+  "materials": [\r
+    {\r
+      "pbrMetallicRoughness": {\r
+        "baseColorTexture": {\r
+          "index": 0,\r
+          "texCoord": 0\r
+        },\r
+        "metallicFactor": 0,\r
+        "baseColorFactor": [\r
+          1,\r
+          1,\r
+          1,\r
+          1\r
+        ],\r
+        "roughnessFactor": 1\r
+      },\r
+      "emissiveFactor": [\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "name": "Cesium_Man-effect",\r
+      "alphaMode": "OPAQUE",\r
+      "doubleSided": false\r
+    }\r
+  ],\r
+  "textures": [\r
+    {\r
+      "sampler": 0,\r
+      "source": 0\r
+    }\r
+  ],\r
+  "images": [\r
+    {\r
+      "uri": "CesiumMan_img0.jpg"\r
+    }\r
+  ],\r
+  "samplers": [\r
+    {\r
+      "magFilter": 9729,\r
+      "minFilter": 9986,\r
+      "wrapS": 10497,\r
+      "wrapT": 10497\r
+    }\r
+  ],\r
+  "bufferViews": [\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 0,\r
+      "byteLength": 28032,\r
+      "target": 34963\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 28032,\r
+      "byteLength": 52368,\r
+      "byteStride": 8,\r
+      "target": 34962\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 80400,\r
+      "byteLength": 78552,\r
+      "byteStride": 12,\r
+      "target": 34962\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 158952,\r
+      "byteLength": 52368,\r
+      "byteStride": 16,\r
+      "target": 34962\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 211320,\r
+      "byteLength": 3648\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 214968,\r
+      "byteLength": 21888\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 236856,\r
+      "byteLength": 14592\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 251448,\r
+      "byteLength": 1216\r
+    }\r
+  ],\r
+  "buffers": [\r
+    {\r
+      "uri": "CesiumMan_data.bin",\r
+      "byteLength": 252664\r
+    }\r
+  ]\r
+}
\ No newline at end of file
diff --git a/automated-tests/resources/CesiumMan_data.bin b/automated-tests/resources/CesiumMan_data.bin
new file mode 100644 (file)
index 0000000..d78b75c
Binary files /dev/null and b/automated-tests/resources/CesiumMan_data.bin differ
diff --git a/automated-tests/resources/CesiumMilkTruck.gltf b/automated-tests/resources/CesiumMilkTruck.gltf
new file mode 100644 (file)
index 0000000..c9a24e3
--- /dev/null
@@ -0,0 +1,489 @@
+{\r
+  "asset": {\r
+    "generator": "Khronos glTF Blender I/O v1.0.5",\r
+    "version": "2.0"\r
+  },\r
+  "scene": 0,\r
+  "scenes": [\r
+    {\r
+      "name": "Scene",\r
+      "nodes": [\r
+        5\r
+      ]\r
+    }\r
+  ],\r
+  "nodes": [\r
+    {\r
+      "mesh": 0,\r
+      "name": "Wheels",\r
+      "rotation": [\r
+        0,\r
+        0.08848588913679123,\r
+        0,\r
+        -0.9960774183273315\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        0\r
+      ],\r
+      "name": "Node",\r
+      "translation": [\r
+        1.432669997215271,\r
+        0,\r
+        -0.4277220070362091\r
+      ]\r
+    },\r
+    {\r
+      "mesh": 0,\r
+      "name": "Wheels.001",\r
+      "rotation": [\r
+        0,\r
+        0.08848588913679123,\r
+        0,\r
+        -0.9960774183273315\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        2\r
+      ],\r
+      "name": "Node.001",\r
+      "translation": [\r
+        -1.352329969406128,\r
+        0,\r
+        -0.4277220070362091\r
+      ]\r
+    },\r
+    {\r
+      "children": [\r
+        1,\r
+        3\r
+      ],\r
+      "mesh": 1,\r
+      "name": "Cesium_Milk_Truck"\r
+    },\r
+    {\r
+      "children": [\r
+        4\r
+      ],\r
+      "name": "Yup2Zup",\r
+      "rotation": [\r
+        0.4999999701976776,\r
+        -0.5,\r
+        0.5,\r
+        0.4999999701976776\r
+      ]\r
+    }\r
+  ],\r
+  "animations": [\r
+    {\r
+      "channels": [\r
+        {\r
+          "sampler": 0,\r
+          "target": {\r
+            "node": 0,\r
+            "path": "rotation"\r
+          }\r
+        },\r
+        {\r
+          "sampler": 1,\r
+          "target": {\r
+            "node": 2,\r
+            "path": "rotation"\r
+          }\r
+        }\r
+      ],\r
+      "name": "Wheels",\r
+      "samplers": [\r
+        {\r
+          "input": 16,\r
+          "interpolation": "LINEAR",\r
+          "output": 17\r
+        },\r
+        {\r
+          "input": 16,\r
+          "interpolation": "LINEAR",\r
+          "output": 18\r
+        }\r
+      ]\r
+    }\r
+  ],\r
+  "materials": [\r
+    {\r
+      "name": "wheels",\r
+      "pbrMetallicRoughness": {\r
+        "baseColorTexture": {\r
+          "index": 0,\r
+          "texCoord": 0\r
+        },\r
+        "metallicFactor": 0,\r
+        "roughnessFactor": 1\r
+      }\r
+    },\r
+    {\r
+      "name": "truck",\r
+      "pbrMetallicRoughness": {\r
+        "baseColorTexture": {\r
+          "index": 1,\r
+          "texCoord": 0\r
+        },\r
+        "metallicFactor": 0,\r
+        "roughnessFactor": 1\r
+      }\r
+    },\r
+    {\r
+      "name": "glass",\r
+      "pbrMetallicRoughness": {\r
+        "baseColorFactor": [\r
+          0,\r
+          0.04050629958510399,\r
+          0.021240700036287308,\r
+          1\r
+        ],\r
+        "metallicFactor": 0,\r
+        "roughnessFactor": 1\r
+      }\r
+    },\r
+    {\r
+      "name": "window_trim",\r
+      "pbrMetallicRoughness": {\r
+        "baseColorFactor": [\r
+          0.06400000303983688,\r
+          0.06400000303983688,\r
+          0.06400000303983688,\r
+          1\r
+        ],\r
+        "metallicFactor": 0,\r
+        "roughnessFactor": 1\r
+      }\r
+    }\r
+  ],\r
+  "meshes": [\r
+    {\r
+      "name": "Wheels",\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "POSITION": 0,\r
+            "NORMAL": 1,\r
+            "TEXCOORD_0": 2\r
+          },\r
+          "indices": 3,\r
+          "material": 0\r
+        }\r
+      ]\r
+    },\r
+    {\r
+      "name": "Cesium_Milk_Truck",\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "POSITION": 4,\r
+            "NORMAL": 5,\r
+            "TEXCOORD_0": 6\r
+          },\r
+          "indices": 7,\r
+          "material": 1\r
+        },\r
+        {\r
+          "attributes": {\r
+            "POSITION": 8,\r
+            "NORMAL": 9,\r
+            "TEXCOORD_0": 10\r
+          },\r
+          "indices": 11,\r
+          "material": 2\r
+        },\r
+        {\r
+          "attributes": {\r
+            "POSITION": 12,\r
+            "NORMAL": 13,\r
+            "TEXCOORD_0": 14\r
+          },\r
+          "indices": 15,\r
+          "material": 3\r
+        }\r
+      ]\r
+    }\r
+  ],\r
+  "textures": [\r
+    {\r
+      "source": 0\r
+    },\r
+    {\r
+      "source": 0\r
+    }\r
+  ],\r
+  "images": [\r
+    {\r
+      "name": "CesiumMilkTruck.jpg",\r
+      "uri": "CesiumMilkTruck.jpg"\r
+    }\r
+  ],\r
+  "accessors": [\r
+    {\r
+      "bufferView": 0,\r
+      "componentType": 5126,\r
+      "count": 828,\r
+      "max": [\r
+        0.4277999997138977,\r
+        1.0579999685287476,\r
+        0.4277999997138977\r
+      ],\r
+      "min": [\r
+        -0.4277999997138977,\r
+        -1.0579999685287476,\r
+        -0.4277999997138977\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "componentType": 5126,\r
+      "count": 828,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "componentType": 5126,\r
+      "count": 828,\r
+      "type": "VEC2"\r
+    },\r
+    {\r
+      "bufferView": 3,\r
+      "componentType": 5123,\r
+      "count": 2304,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "componentType": 5126,\r
+      "count": 2366,\r
+      "max": [\r
+        2.437999963760376,\r
+        1.3960000276565552,\r
+        -0.2667999863624573\r
+      ],\r
+      "min": [\r
+        -2.430910110473633,\r
+        -1.3960000276565552,\r
+        -2.5843698978424072\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "componentType": 5126,\r
+      "count": 2366,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "componentType": 5126,\r
+      "count": 2366,\r
+      "type": "VEC2"\r
+    },\r
+    {\r
+      "bufferView": 7,\r
+      "componentType": 5123,\r
+      "count": 5232,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 8,\r
+      "componentType": 5126,\r
+      "count": 151,\r
+      "max": [\r
+        1.6011799573898315,\r
+        1.3960000276565552,\r
+        -1.631850004196167\r
+      ],\r
+      "min": [\r
+        0.22885000705718994,\r
+        -1.3960000276565552,\r
+        -2.3545401096343994\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 9,\r
+      "componentType": 5126,\r
+      "count": 151,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 10,\r
+      "componentType": 5126,\r
+      "count": 151,\r
+      "type": "VEC2"\r
+    },\r
+    {\r
+      "bufferView": 11,\r
+      "componentType": 5123,\r
+      "count": 168,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 12,\r
+      "componentType": 5126,\r
+      "count": 650,\r
+      "max": [\r
+        1.62267005443573,\r
+        1.100000023841858,\r
+        -1.5961999893188477\r
+      ],\r
+      "min": [\r
+        0.1932000070810318,\r
+        -1.1100000143051147,\r
+        -2.3919999599456787\r
+      ],\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 13,\r
+      "componentType": 5126,\r
+      "count": 650,\r
+      "type": "VEC3"\r
+    },\r
+    {\r
+      "bufferView": 14,\r
+      "componentType": 5126,\r
+      "count": 650,\r
+      "type": "VEC2"\r
+    },\r
+    {\r
+      "bufferView": 15,\r
+      "componentType": 5123,\r
+      "count": 864,\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 16,\r
+      "componentType": 5126,\r
+      "count": 31,\r
+      "max": [\r
+        1.25\r
+      ],\r
+      "min": [\r
+        0\r
+      ],\r
+      "type": "SCALAR"\r
+    },\r
+    {\r
+      "bufferView": 17,\r
+      "componentType": 5126,\r
+      "count": 31,\r
+      "type": "VEC4"\r
+    },\r
+    {\r
+      "bufferView": 18,\r
+      "componentType": 5126,\r
+      "count": 31,\r
+      "type": "VEC4"\r
+    }\r
+  ],\r
+  "bufferViews": [\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 9936,\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 9936,\r
+      "byteOffset": 9936\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 6624,\r
+      "byteOffset": 19872\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 4608,\r
+      "byteOffset": 26496\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 28392,\r
+      "byteOffset": 31104\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 28392,\r
+      "byteOffset": 59496\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 18928,\r
+      "byteOffset": 87888\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 10464,\r
+      "byteOffset": 106816\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 1812,\r
+      "byteOffset": 117280\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 1812,\r
+      "byteOffset": 119092\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 1208,\r
+      "byteOffset": 120904\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 336,\r
+      "byteOffset": 122112\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 7800,\r
+      "byteOffset": 122448\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 7800,\r
+      "byteOffset": 130248\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 5200,\r
+      "byteOffset": 138048\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 1728,\r
+      "byteOffset": 143248\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 124,\r
+      "byteOffset": 144976\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 496,\r
+      "byteOffset": 145100\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteLength": 496,\r
+      "byteOffset": 145596\r
+    }\r
+  ],\r
+  "buffers": [\r
+    {\r
+      "uri": "CesiumMilkTruck_data.bin",\r
+      "byteLength": 146092\r
+    }\r
+  ]\r
+}\r
diff --git a/automated-tests/resources/CesiumMilkTruck_data.bin b/automated-tests/resources/CesiumMilkTruck_data.bin
new file mode 100644 (file)
index 0000000..51e3646
Binary files /dev/null and b/automated-tests/resources/CesiumMilkTruck_data.bin differ
diff --git a/automated-tests/resources/EnvironmentTest.gltf b/automated-tests/resources/EnvironmentTest.gltf
new file mode 100644 (file)
index 0000000..962e475
--- /dev/null
@@ -0,0 +1,328 @@
+{\r
+    "asset": {\r
+        "copyright": "2018 (c) Adobe Systems Inc.",\r
+        "generator": "Adobe Dimension - b417c10282aa66313155856d4a54e84f3f388647",\r
+        "version": "2.0"\r
+    },\r
+    "accessors": [\r
+        {\r
+            "bufferView": 0,\r
+            "componentType": 5126,\r
+            "count": 4598,\r
+            "type": "VEC3",\r
+            "max": [\r
+                10.647041320800782,\r
+                1.6470409631729127,\r
+                0.6470409631729126\r
+            ],\r
+            "min": [\r
+                -10.647041320800782,\r
+                0.3529590368270874,\r
+                -0.6470409631729126\r
+            ]\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "componentType": 5126,\r
+            "count": 4598,\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "componentType": 5126,\r
+            "count": 4598,\r
+            "type": "VEC2"\r
+        },\r
+        {\r
+            "bufferView": 3,\r
+            "componentType": 5125,\r
+            "count": 25344,\r
+            "type": "SCALAR",\r
+            "max": [\r
+                4597.0\r
+            ],\r
+            "min": [\r
+                0.0\r
+            ]\r
+        },\r
+        {\r
+            "bufferView": 4,\r
+            "componentType": 5126,\r
+            "count": 4598,\r
+            "type": "VEC3",\r
+            "max": [\r
+                10.647041320800782,\r
+                -0.3529590368270874,\r
+                0.6470409631729126\r
+            ],\r
+            "min": [\r
+                -10.647041320800782,\r
+                -1.6470409631729127,\r
+                -0.6470409631729126\r
+            ]\r
+        },\r
+        {\r
+            "bufferView": 5,\r
+            "componentType": 5126,\r
+            "count": 4598,\r
+            "type": "VEC2"\r
+        }\r
+    ],\r
+    "bufferViews": [\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 0,\r
+            "byteLength": 55176,\r
+            "target": 34962\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 55176,\r
+            "byteLength": 55176,\r
+            "target": 34962\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 110352,\r
+            "byteLength": 36784,\r
+            "target": 34962\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 147136,\r
+            "byteLength": 101376,\r
+            "target": 34963\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 248512,\r
+            "byteLength": 55176,\r
+            "target": 34962\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 303688,\r
+            "byteLength": 36784,\r
+            "target": 34962\r
+        }\r
+    ],\r
+    "buffers": [\r
+        {\r
+            "byteLength": 340472,\r
+            "uri": "EnvironmentTest_binary.bin"\r
+        }\r
+    ],\r
+    "cameras": [\r
+        {\r
+            "perspective": {\r
+                "znear": 0.0010000000474974514,\r
+                "yfov": 0.6024156808853149,\r
+                "zfar": 200.0,\r
+                "aspectRatio": 1.3333333730697632\r
+            },\r
+            "type": "perspective",\r
+            "name": "render_camera"\r
+        }\r
+    ],\r
+    "images": [\r
+        {\r
+            "name": "tmp_image_pie_dc1e_1a22_fbf9roughness_map_roughness_tmp_image_pie_dc1e_1a22_fbf9metal_map_metallic_0",\r
+            "uri": "EnvironmentTest_images/roughness_metallic_0.jpg",\r
+            "mimeType": "image/jpeg"\r
+        },\r
+        {\r
+            "name": "tmp_image_pie_b20b_ebb4_317droughness_map2_roughness_tmp_image_pie_b20b_ebb4_317dmetal_map2_metallic_1",\r
+            "uri": "EnvironmentTest_images/roughness_metallic_1.jpg",\r
+            "mimeType": "image/jpeg"\r
+        }\r
+    ],\r
+    "materials": [\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "metallicRoughnessTexture": {\r
+                    "index": 0\r
+                }\r
+            },\r
+            "name": "MetallicSpheresMat",\r
+            "doubleSided": true\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "metallicRoughnessTexture": {\r
+                    "index": 1\r
+                }\r
+            },\r
+            "name": "DielectricSpheresMat",\r
+            "doubleSided": true\r
+        },\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorFactor": [\r
+                    0.0,\r
+                    0.0,\r
+                    0.0,\r
+                    1.0\r
+                ],\r
+                "metallicRoughnessTexture": {\r
+                    "index": 1\r
+                }\r
+            },\r
+            "name": "DielectricSpheresMat",\r
+            "doubleSided": true\r
+        }\r
+    ],\r
+    "meshes": [\r
+        {\r
+            "name": "Metallic0_N3D",\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "POSITION": 0,\r
+                        "NORMAL": 1,\r
+                        "TEXCOORD_0": 2\r
+                    },\r
+                    "indices": 3,\r
+                    "material": 0\r
+                }\r
+            ]\r
+        },\r
+        {\r
+            "name": "Dielectric0_N3D2",\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "TEXCOORD_0": 5,\r
+                        "NORMAL": 1,\r
+                        "POSITION": 4\r
+                    },\r
+                    "indices": 3,\r
+                    "material": 1\r
+                }\r
+            ]\r
+        },\r
+        {\r
+            "name": "Dielectric0_N3D",\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "POSITION": 4,\r
+                        "NORMAL": 1,\r
+                        "TEXCOORD_0": 5\r
+                    },\r
+                    "indices": 3,\r
+                    "material": 2\r
+                }\r
+            ]\r
+        }\r
+    ],\r
+    "nodes": [\r
+        {\r
+            "matrix": [\r
+                0.9999533295631409,\r
+                3.16067598760128e-8,\r
+                0.009662099182605744,\r
+                0.0,\r
+                0.0014864075928926468,\r
+                0.9880954027175903,\r
+                -0.15383504331111909,\r
+                0.0,\r
+                -0.009547080844640732,\r
+                0.15384222567081452,\r
+                0.988049328327179,\r
+                0.0,\r
+                -0.7599077224731445,\r
+                7.708760738372803,\r
+                27.743375778198243,\r
+                1.0\r
+            ],\r
+            "camera": 0,\r
+            "name": "render_camera_n3d"\r
+        },\r
+        {\r
+            "name": "ground_plane_n3d"\r
+        },\r
+        {\r
+            "children": [\r
+                3,\r
+                4,\r
+                5\r
+            ],\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                -0.5564079284667969,\r
+                4.774584770202637,\r
+                -1.0962677001953126,\r
+                1.0\r
+            ],\r
+            "name": "ENV_Spheres"\r
+        },\r
+        {\r
+            "mesh": 0,\r
+            "name": "Metallic0"\r
+        },\r
+        {\r
+            "mesh": 1,\r
+            "name": "Dielectric0"\r
+        },\r
+        {\r
+            "matrix": [\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                0.0,\r
+                1.0,\r
+                0.0,\r
+                0.0,\r
+                -1.985867977142334,\r
+                0.0,\r
+                1.0\r
+            ],\r
+            "mesh": 2,\r
+            "name": "Dielectric0-Black"\r
+        }\r
+    ],\r
+    "samplers": [\r
+        {},\r
+        {}\r
+    ],\r
+    "scenes": [\r
+        {\r
+            "nodes": [\r
+                0,\r
+                1,\r
+                2\r
+            ],\r
+            "name": "scene"\r
+        }\r
+    ],\r
+    "textures": [\r
+        {\r
+            "name": "tmp_image_pie_dc1e_1a22_fbf9roughness_map_roughness_tmp_image_pie_dc1e_1a22_fbf9metal_map_metallic_0_texture",\r
+            "sampler": 0,\r
+            "source": 0\r
+        },\r
+        {\r
+            "name": "tmp_image_pie_b20b_ebb4_317droughness_map2_roughness_tmp_image_pie_b20b_ebb4_317dmetal_map2_metallic_1_texture",\r
+            "sampler": 1,\r
+            "source": 1\r
+        }\r
+    ],\r
+    "scene": 0\r
+}
\ No newline at end of file
diff --git a/automated-tests/resources/EnvironmentTest_binary.bin b/automated-tests/resources/EnvironmentTest_binary.bin
new file mode 100644 (file)
index 0000000..4473a85
Binary files /dev/null and b/automated-tests/resources/EnvironmentTest_binary.bin differ
diff --git a/automated-tests/resources/MetalRoughSpheres.gltf b/automated-tests/resources/MetalRoughSpheres.gltf
new file mode 100644 (file)
index 0000000..7ea5ba0
--- /dev/null
@@ -0,0 +1,507 @@
+{\r
+    "asset": {\r
+        "copyright": "Copyright 2017 Analytical Graphics, Inc, CC-BY 4.0 https://creativecommons.org/licenses/by/4.0/ - Model and textures by Ed Mackey.",\r
+        "generator": "COLLADA2GLTF with hand-edits",\r
+        "version": "2.0"\r
+    },\r
+    "scene": 0,\r
+    "scenes": [\r
+        {\r
+            "nodes": [\r
+                0\r
+            ]\r
+        }\r
+    ],\r
+    "nodes": [\r
+        {\r
+            "children": [\r
+                5,\r
+                4,\r
+                3,\r
+                2,\r
+                1\r
+            ],\r
+            "matrix": [\r
+                0.4,  0.0,  0.0,  0.0,\r
+                0.0,  0.0, -0.4,  0.0,\r
+                0.0,  0.4,  0.0,  0.0,\r
+                0.0,  0.0,  0.0,  1.0\r
+            ]\r
+        },\r
+        {\r
+            "mesh": 0\r
+        },\r
+        {\r
+            "mesh": 1\r
+        },\r
+        {\r
+            "mesh": 2\r
+        },\r
+        {\r
+            "mesh": 3\r
+        },\r
+        {\r
+            "mesh": 4\r
+        }\r
+    ],\r
+    "meshes": [\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 1,\r
+                        "POSITION": 2,\r
+                        "TEXCOORD_0": 3\r
+                    },\r
+                    "indices": 0,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                }\r
+            ],\r
+            "name": "Spheres.004"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 5,\r
+                        "POSITION": 6,\r
+                        "TEXCOORD_0": 7\r
+                    },\r
+                    "indices": 4,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                }\r
+            ],\r
+            "name": "Spheres.003"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 9,\r
+                        "POSITION": 10,\r
+                        "TEXCOORD_0": 11\r
+                    },\r
+                    "indices": 8,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                }\r
+            ],\r
+            "name": "Spheres.002"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 13,\r
+                        "POSITION": 14,\r
+                        "TEXCOORD_0": 15\r
+                    },\r
+                    "indices": 12,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                }\r
+            ],\r
+            "name": "Spheres.001"\r
+        },\r
+        {\r
+            "primitives": [\r
+                {\r
+                    "attributes": {\r
+                        "NORMAL": 17,\r
+                        "POSITION": 18,\r
+                        "TEXCOORD_0": 19\r
+                    },\r
+                    "indices": 16,\r
+                    "mode": 4,\r
+                    "material": 0\r
+                }\r
+            ],\r
+            "name": "Spheres"\r
+        }\r
+    ],\r
+    "accessors": [\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 2642016,\r
+            "componentType": 5123,\r
+            "count": 184320,\r
+            "max": [\r
+                31331\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 5389968,\r
+            "componentType": 5126,\r
+            "count": 31332,\r
+            "max": [\r
+                0.9999999403953552,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -0.9999999403953552,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 5765952,\r
+            "componentType": 5126,\r
+            "count": 31332,\r
+            "max": [\r
+                -8.0,\r
+                9.0,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                -10.0,\r
+                -1.0,\r
+                -7.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 1796656,\r
+            "componentType": 5126,\r
+            "count": 31332,\r
+            "max": [\r
+                0.1278132051229477,\r
+                0.7597609758377075\r
+            ],\r
+            "min": [\r
+                0.03436123952269554,\r
+                0.013921022415161133\r
+            ],\r
+            "type": "VEC2"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 0,\r
+            "componentType": 5123,\r
+            "count": 368640,\r
+            "max": [\r
+                62663\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                0.9999999403953552,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -0.9999999403953552,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 751968,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                -2.0,\r
+                9.0,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                -7.0,\r
+                -1.0,\r
+                -7.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 0,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                0.4161497056484223,\r
+                0.7597609758377075\r
+            ],\r
+            "min": [\r
+                0.15740810334682465,\r
+                0.012456059455871582\r
+            ],\r
+            "type": "VEC2"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 1904736,\r
+            "componentType": 5123,\r
+            "count": 368640,\r
+            "max": [\r
+                62663\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 3886032,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                0.9999999403953552,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -0.9999999403953552,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 4638000,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                4.0,\r
+                9.0,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                -1.0,\r
+                -1.0,\r
+                -7.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 1295344,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                0.7028239369392395,\r
+                0.7636672854423523\r
+            ],\r
+            "min": [\r
+                0.4482637047767639,\r
+                0.015471160411834717\r
+            ],\r
+            "type": "VEC2"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 1167456,\r
+            "componentType": 5123,\r
+            "count": 368640,\r
+            "max": [\r
+                62663\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 2382096,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                0.9999999403953552,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -0.9999999403953552,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 3134064,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                10.0,\r
+                9.0,\r
+                10.0\r
+            ],\r
+            "min": [\r
+                5.0,\r
+                -1.0,\r
+                -7.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 794032,\r
+            "componentType": 5126,\r
+            "count": 62664,\r
+            "max": [\r
+                0.9852716326713562,\r
+                0.7671433687210083\r
+            ],\r
+            "min": [\r
+                0.7233805060386658,\r
+                0.016381680965423585\r
+            ],\r
+            "type": "VEC2"\r
+        },\r
+        {\r
+            "bufferView": 0,\r
+            "byteOffset": 737280,\r
+            "componentType": 5123,\r
+            "count": 215088,\r
+            "max": [\r
+                36589\r
+            ],\r
+            "min": [\r
+                0\r
+            ],\r
+            "type": "SCALAR"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1503936,\r
+            "componentType": 5126,\r
+            "count": 36590,\r
+            "max": [\r
+                0.9999999403953552,\r
+                1.0,\r
+                1.0\r
+            ],\r
+            "min": [\r
+                -0.9999999403953552,\r
+                -1.0,\r
+                -1.0\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 1,\r
+            "byteOffset": 1943016,\r
+            "componentType": 5126,\r
+            "count": 36590,\r
+            "max": [\r
+                11.874730110168456,\r
+                9.0,\r
+                10.969940185546877\r
+            ],\r
+            "min": [\r
+                -12.186589241027832,\r
+                -1.0,\r
+                -12.35944938659668\r
+            ],\r
+            "type": "VEC3"\r
+        },\r
+        {\r
+            "bufferView": 2,\r
+            "byteOffset": 501312,\r
+            "componentType": 5126,\r
+            "count": 36590,\r
+            "max": [\r
+                0.9869875311851502,\r
+                0.9988328814506532\r
+            ],\r
+            "min": [\r
+                0.0013856289442628625,\r
+                0.016568005084991456\r
+            ],\r
+            "type": "VEC2"\r
+        }\r
+    ],\r
+    "materials": [\r
+        {\r
+            "pbrMetallicRoughness": {\r
+                "baseColorTexture": {\r
+                    "index": 0\r
+                },\r
+                "metallicRoughnessTexture": {\r
+                    "index": 1\r
+                }\r
+            },\r
+            "emissiveFactor": [\r
+                0.0,\r
+                0.0,\r
+                0.0\r
+            ]\r
+        }\r
+    ],\r
+    "textures": [\r
+        {\r
+            "sampler": 0,\r
+            "source": 0\r
+        },\r
+        {\r
+            "sampler": 0,\r
+            "source": 1\r
+        }\r
+    ],\r
+    "images": [\r
+        {\r
+            "uri": "Spheres_BaseColor.png"\r
+        },\r
+        {\r
+            "uri": "Spheres_MetalRough.png"\r
+        }\r
+    ],\r
+    "samplers": [\r
+        {\r
+            "magFilter": 9729,\r
+            "minFilter": 9986,\r
+            "wrapS": 33071,\r
+            "wrapT": 33071\r
+        }\r
+    ],\r
+    "bufferViews": [\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 8189248,\r
+            "byteLength": 3010656,\r
+            "target": 34963\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 0,\r
+            "byteLength": 6141936,\r
+            "byteStride": 12,\r
+            "target": 34962\r
+        },\r
+        {\r
+            "buffer": 0,\r
+            "byteOffset": 6141936,\r
+            "byteLength": 2047312,\r
+            "byteStride": 8,\r
+            "target": 34962\r
+        }\r
+    ],\r
+    "buffers": [\r
+        {\r
+            "byteLength": 11199904,\r
+            "uri": "MetalRoughSpheres0.bin"\r
+        }\r
+    ]\r
+}\r
diff --git a/automated-tests/resources/MetalRoughSpheres0.bin b/automated-tests/resources/MetalRoughSpheres0.bin
new file mode 100644 (file)
index 0000000..2823ba4
Binary files /dev/null and b/automated-tests/resources/MetalRoughSpheres0.bin differ
diff --git a/automated-tests/resources/MorphPrimitivesTest.bin b/automated-tests/resources/MorphPrimitivesTest.bin
new file mode 100644 (file)
index 0000000..7f269e1
Binary files /dev/null and b/automated-tests/resources/MorphPrimitivesTest.bin differ
diff --git a/automated-tests/resources/MorphPrimitivesTest.gltf b/automated-tests/resources/MorphPrimitivesTest.gltf
new file mode 100644 (file)
index 0000000..a987f2d
--- /dev/null
@@ -0,0 +1,331 @@
+{\r
+  "asset": {\r
+    "generator": "glTF Converter for Shade3D",\r
+    "version": "2.0",\r
+    "extras": {\r
+      "title": "multiple_primitives",\r
+      "author": "ft-lab",\r
+      "license": "CC BY-4.0 (https://creativecommons.org/licenses/by/4.0/)"\r
+    }\r
+  },\r
+  "accessors": [\r
+    {\r
+      "bufferView": 0,\r
+      "componentType": 5123,\r
+      "count": 72,\r
+      "type": "SCALAR",\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 1,\r
+      "componentType": 5126,\r
+      "count": 21,\r
+      "type": "VEC3",\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 2,\r
+      "componentType": 5126,\r
+      "count": 21,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.5,\r
+        0,\r
+        0.5\r
+      ],\r
+      "min": [\r
+        -0.5,\r
+        0,\r
+        -0.5\r
+      ],\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 3,\r
+      "componentType": 5126,\r
+      "count": 21,\r
+      "type": "VEC2",\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 4,\r
+      "componentType": 5126,\r
+      "count": 21,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0,\r
+        0.20000000298023224,\r
+        0\r
+      ],\r
+      "min": [\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 5,\r
+      "componentType": 5123,\r
+      "count": 24,\r
+      "type": "SCALAR",\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 6,\r
+      "componentType": 5126,\r
+      "count": 9,\r
+      "type": "VEC3",\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 7,\r
+      "componentType": 5126,\r
+      "count": 9,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0.5,\r
+        0,\r
+        0\r
+      ],\r
+      "min": [\r
+        0,\r
+        0,\r
+        -0.5\r
+      ],\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 8,\r
+      "componentType": 5126,\r
+      "count": 9,\r
+      "type": "VEC2",\r
+      "byteOffset": 0\r
+    },\r
+    {\r
+      "bufferView": 9,\r
+      "componentType": 5126,\r
+      "count": 9,\r
+      "type": "VEC3",\r
+      "max": [\r
+        0,\r
+        0.20000000298023224,\r
+        0\r
+      ],\r
+      "min": [\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "byteOffset": 0\r
+    }\r
+  ],\r
+  "bufferViews": [\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 0,\r
+      "byteLength": 144,\r
+      "target": 34963\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 144,\r
+      "byteLength": 252,\r
+      "target": 34962,\r
+      "byteStride": 12\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 396,\r
+      "byteLength": 252,\r
+      "target": 34962,\r
+      "byteStride": 12\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 648,\r
+      "byteLength": 168,\r
+      "target": 34962,\r
+      "byteStride": 8\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 816,\r
+      "byteLength": 252,\r
+      "target": 34962,\r
+      "byteStride": 12\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1068,\r
+      "byteLength": 48,\r
+      "target": 34963\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1116,\r
+      "byteLength": 108,\r
+      "target": 34962,\r
+      "byteStride": 12\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1224,\r
+      "byteLength": 108,\r
+      "target": 34962,\r
+      "byteStride": 12\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1332,\r
+      "byteLength": 72,\r
+      "target": 34962,\r
+      "byteStride": 8\r
+    },\r
+    {\r
+      "buffer": 0,\r
+      "byteOffset": 1404,\r
+      "byteLength": 108,\r
+      "target": 34962,\r
+      "byteStride": 12\r
+    }\r
+  ],\r
+  "buffers": [\r
+    {\r
+      "name": "MorphPrimitivesTest",\r
+      "byteLength": 1512,\r
+      "uri": "MorphPrimitivesTest.bin"\r
+    }\r
+  ],\r
+  "images": [\r
+    {\r
+      "name": "uv_texture.jpg",\r
+      "mimeType": "image/jpeg",\r
+      "uri": "uv_texture.jpg"\r
+    }\r
+  ],\r
+  "materials": [\r
+    {\r
+      "pbrMetallicRoughness": {\r
+        "baseColorFactor": [\r
+          1,\r
+          0,\r
+          0,\r
+          1\r
+        ],\r
+        "baseColorTexture": {\r
+          "index": 0,\r
+          "texCoord": 0\r
+        },\r
+        "metallicFactor": 0,\r
+        "roughnessFactor": 1\r
+      },\r
+      "name": "red",\r
+      "emissiveFactor": [\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "alphaMode": "OPAQUE",\r
+      "doubleSided": false\r
+    },\r
+    {\r
+      "pbrMetallicRoughness": {\r
+        "baseColorFactor": [\r
+          0,\r
+          1,\r
+          0,\r
+          1\r
+        ],\r
+        "baseColorTexture": {\r
+          "index": 0,\r
+          "texCoord": 0\r
+        },\r
+        "metallicFactor": 0,\r
+        "roughnessFactor": 1\r
+      },\r
+      "name": "green",\r
+      "emissiveFactor": [\r
+        0,\r
+        0,\r
+        0\r
+      ],\r
+      "alphaMode": "OPAQUE",\r
+      "doubleSided": false\r
+    }\r
+  ],\r
+  "meshes": [\r
+    {\r
+      "weights": [\r
+        0.5\r
+      ],\r
+      "name": "mesh",\r
+      "primitives": [\r
+        {\r
+          "attributes": {\r
+            "NORMAL": 1,\r
+            "POSITION": 2,\r
+            "TEXCOORD_0": 3\r
+          },\r
+          "indices": 0,\r
+          "material": 0,\r
+          "targets": [\r
+            {\r
+              "POSITION": 4\r
+            }\r
+          ],\r
+          "mode": 4\r
+        },\r
+        {\r
+          "attributes": {\r
+            "POSITION": 7,\r
+            "NORMAL": 6,\r
+            "TEXCOORD_0": 8\r
+          },\r
+          "indices": 5,\r
+          "material": 1,\r
+          "targets": [\r
+            {\r
+              "POSITION": 9\r
+            }\r
+          ],\r
+          "mode": 4\r
+        }\r
+      ]\r
+    }\r
+  ],\r
+  "nodes": [\r
+    {\r
+      "children": [\r
+        1\r
+      ],\r
+      "name": "ルートパート"\r
+    },\r
+    {\r
+      "mesh": 0,\r
+      "name": "mesh"\r
+    }\r
+  ],\r
+  "samplers": [\r
+    {\r
+      "minFilter": 9729,\r
+      "wrapS": 10497,\r
+      "wrapT": 10497\r
+    }\r
+  ],\r
+  "scenes": [\r
+    {\r
+      "nodes": [\r
+        0\r
+      ],\r
+      "name": "Scene"\r
+    }\r
+  ],\r
+  "textures": [\r
+    {\r
+      "sampler": 0,\r
+      "source": 0\r
+    }\r
+  ],\r
+  "scene": 0\r
+}\r
diff --git a/automated-tests/resources/RGB16F.ktx b/automated-tests/resources/RGB16F.ktx
new file mode 100644 (file)
index 0000000..9e9714b
Binary files /dev/null and b/automated-tests/resources/RGB16F.ktx differ
diff --git a/automated-tests/resources/RGB32F.ktx b/automated-tests/resources/RGB32F.ktx
new file mode 100644 (file)
index 0000000..99f5e7f
Binary files /dev/null and b/automated-tests/resources/RGB32F.ktx differ
diff --git a/automated-tests/resources/RGBA8888.ktx b/automated-tests/resources/RGBA8888.ktx
new file mode 100644 (file)
index 0000000..48afa5d
Binary files /dev/null and b/automated-tests/resources/RGBA8888.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_10x10.ktx b/automated-tests/resources/RGBA_ASTC_10x10.ktx
new file mode 100644 (file)
index 0000000..94dde71
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_10x10.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_10x5.ktx b/automated-tests/resources/RGBA_ASTC_10x5.ktx
new file mode 100644 (file)
index 0000000..315674e
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_10x5.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_10x6.ktx b/automated-tests/resources/RGBA_ASTC_10x6.ktx
new file mode 100644 (file)
index 0000000..b5f1cbb
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_10x6.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_12x10.ktx b/automated-tests/resources/RGBA_ASTC_12x10.ktx
new file mode 100644 (file)
index 0000000..c3c04fa
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_12x10.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_12x12.ktx b/automated-tests/resources/RGBA_ASTC_12x12.ktx
new file mode 100644 (file)
index 0000000..c1e5e0d
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_12x12.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_4x4.ktx b/automated-tests/resources/RGBA_ASTC_4x4.ktx
new file mode 100644 (file)
index 0000000..fa7fe6b
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_4x4.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_5x4.ktx b/automated-tests/resources/RGBA_ASTC_5x4.ktx
new file mode 100644 (file)
index 0000000..9a4372c
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_5x4.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_5x5.ktx b/automated-tests/resources/RGBA_ASTC_5x5.ktx
new file mode 100644 (file)
index 0000000..776175b
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_5x5.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_6x5.ktx b/automated-tests/resources/RGBA_ASTC_6x5.ktx
new file mode 100644 (file)
index 0000000..2b10f9d
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_6x5.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_6x6.ktx b/automated-tests/resources/RGBA_ASTC_6x6.ktx
new file mode 100644 (file)
index 0000000..27f511a
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_6x6.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_8x5.ktx b/automated-tests/resources/RGBA_ASTC_8x5.ktx
new file mode 100644 (file)
index 0000000..7bbb4e0
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_8x5.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_8x6.ktx b/automated-tests/resources/RGBA_ASTC_8x6.ktx
new file mode 100644 (file)
index 0000000..2836beb
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_8x6.ktx differ
diff --git a/automated-tests/resources/RGBA_ASTC_8x8.ktx b/automated-tests/resources/RGBA_ASTC_8x8.ktx
new file mode 100644 (file)
index 0000000..c1bc85a
Binary files /dev/null and b/automated-tests/resources/RGBA_ASTC_8x8.ktx differ
diff --git a/automated-tests/resources/SimpleSparseAccessor.bin b/automated-tests/resources/SimpleSparseAccessor.bin
new file mode 100644 (file)
index 0000000..99eaf33
Binary files /dev/null and b/automated-tests/resources/SimpleSparseAccessor.bin differ
diff --git a/automated-tests/resources/SimpleSparseAccessor.gltf b/automated-tests/resources/SimpleSparseAccessor.gltf
new file mode 100644 (file)
index 0000000..918cd48
--- /dev/null
@@ -0,0 +1,106 @@
+{\r
+   "scene" : 0,\r
+   "scenes":[\r
+      {\r
+         "nodes":[\r
+            0\r
+         ]\r
+      }\r
+   ],\r
+   "nodes":[\r
+      {\r
+         "mesh":0\r
+      }\r
+   ],\r
+   "meshes":[\r
+      {\r
+         "primitives":[\r
+            {\r
+               "attributes":{\r
+                  "POSITION":1\r
+               },\r
+               "indices":0\r
+            }\r
+         ]\r
+      }\r
+   ],\r
+   "buffers":[\r
+      {\r
+         "uri":"SimpleSparseAccessor.bin",\r
+         "byteLength":284\r
+      }\r
+   ],\r
+   "bufferViews":[\r
+      {\r
+         "buffer":0,\r
+         "byteOffset":0,\r
+         "byteLength":72,\r
+         "target":34963\r
+      },\r
+      {\r
+         "buffer":0,\r
+         "byteOffset":72,\r
+         "byteLength":168\r
+      },\r
+      {\r
+         "buffer":0,\r
+         "byteOffset":240,\r
+         "byteLength":6\r
+      },\r
+      {\r
+         "buffer":0,\r
+         "byteOffset":248,\r
+         "byteLength":36\r
+      }\r
+   ],\r
+   "accessors":[\r
+      {\r
+         "bufferView":0,\r
+         "byteOffset":0,\r
+         "componentType":5123,\r
+         "count":36,\r
+         "type":"SCALAR",\r
+         "max":[\r
+            13\r
+         ],\r
+         "min":[\r
+            0\r
+         ]\r
+      },\r
+      {\r
+         "bufferView":1,\r
+         "byteOffset":0,\r
+         "componentType":5126,\r
+         "count":14,\r
+         "type":"VEC3",\r
+         "sparse":{\r
+            "count":3,\r
+            "indices":{\r
+               "bufferView":2,\r
+               "byteOffset":0,\r
+               "componentType":5123\r
+            },\r
+            "values":{\r
+               "bufferView":3,\r
+               "byteOffset":0\r
+            }\r
+         },\r
+         "max":[\r
+            6.0,\r
+            4.0,\r
+            0.0\r
+         ],\r
+         "min":[\r
+            0.0,\r
+            0.0,\r
+            0.0\r
+         ]\r
+      }\r
+   ],\r
+   "asset":{\r
+      "version":"2.0"\r
+   }\r
+}\r
+\r
+\r
+\r
diff --git a/automated-tests/resources/Studio/Irradiance.ktx b/automated-tests/resources/Studio/Irradiance.ktx
new file mode 100644 (file)
index 0000000..df24c05
Binary files /dev/null and b/automated-tests/resources/Studio/Irradiance.ktx differ
diff --git a/automated-tests/resources/Studio/Radiance.ktx b/automated-tests/resources/Studio/Radiance.ktx
new file mode 100644 (file)
index 0000000..51aa681
Binary files /dev/null and b/automated-tests/resources/Studio/Radiance.ktx differ
diff --git a/automated-tests/resources/animation.bin b/automated-tests/resources/animation.bin
new file mode 100644 (file)
index 0000000..fa20e9f
Binary files /dev/null and b/automated-tests/resources/animation.bin differ
diff --git a/automated-tests/resources/arc.dli b/automated-tests/resources/arc.dli
new file mode 100644 (file)
index 0000000..4d0c6b5
--- /dev/null
@@ -0,0 +1,35 @@
+{\r
+  "scene": 0,\r
+  "scenes": [ { "nodes": [ 0 ] } ],\r
+  "nodes": [ {\r
+    "name": "root",\r
+    "children": [ 1 ]\r
+  }, {\r
+    "name": "arc",\r
+    "size": [ 2.0, 2.0 ],\r
+       "color": [ 0.5, 1.0, 0.5, 0.5 ],\r
+    "arc": {\r
+      "shader": 0,\r
+      "mesh": 0,\r
+      "startAngle" : -45.0,\r
+      "endAngle" : 135.0,\r
+      "radius" : -0.75,\r
+         "arcCaps": 3\r
+    }\r
+  } ],\r
+  "environment": [ {\r
+  } ],\r
+  "meshes": [ {\r
+    "uri": "quad",\r
+    "attributes": 0\r
+  } ],\r
+  "materials": [ {\r
+  } ],\r
+  "shaders": [ {\r
+    "vertex": "dli_arc.vsh",\r
+    "fragment": "dli_arc.fsh",\r
+    "rendererState" : "ALPHA_BLEND",\r
+       "startAngle": [ -1.0, 0.0 ],\r
+       "endAngle": [ 1.0, 0.0 ]\r
+  } ]\r
+}\r
diff --git a/automated-tests/resources/dli/animation-failed-to-open.dli b/automated-tests/resources/dli/animation-failed-to-open.dli
new file mode 100644 (file)
index 0000000..9cd0602
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root"
+  } ],
+  "animations": [ {
+    "properties": [ {
+      "node": "root",
+      "property": "position",
+      "keyFramesBin": { "url": "doesntexist.bin" }
+    } ]
+  } ]
+}
diff --git a/automated-tests/resources/dli/constraints.dli b/automated-tests/resources/dli/constraints.dli
new file mode 100644 (file)
index 0000000..200bd88
--- /dev/null
@@ -0,0 +1,32 @@
+{
+  "scene": 0,
+  "scenes": [ { "nodes": [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "children": [ 1, 2, 3 ]
+  }, {
+    "name": "Alice",
+    "angle": [ 0.0, -45.0, 10.0 ],
+    "position": [ 500.0, -50.0, 0.0 ]
+  }, {
+    "name": "Bob",
+    "position": [ 1000.0, 1.0, -400.0 ],
+    "angle": [ 10.0, 0.0, -90.0 ],
+    "extras": {
+      "angularVelocity": [ -0.5, 0.0004 ]
+    }
+  }, {
+    "name": "Charlie",
+    "position": [ -400.0, 0.0, 100.0 ],
+    "constraints": {
+      "orientation": 1,
+      "position": 2,
+      "angularVelocity": 2,
+      "invalid": "zero"
+    },
+    "extras": {
+      "angularVelocity": [ 0.0, 0.0 ]
+    }
+  } ]
+}
+
diff --git a/automated-tests/resources/dli/extras.dli b/automated-tests/resources/dli/extras.dli
new file mode 100644 (file)
index 0000000..4f5edab
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "scene": 0,
+  "scenes": [ { "nodes": [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "extras": {
+      "fudgeFactor": 9000.1,
+      "fudgeVector": [ 8, 7.0 ],
+      "fudgeVector": [ -0.25, 17.0 ],
+      "isThisTheRealLife": true,
+      "isThisJustFantasy": false,
+      "": 16384,
+      "velocity": [ 0.1, 58.0, -0.2 ],
+      "not a great extra": "this one",
+      "frameOfReference": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
+    }
+  } ]
+}
+
diff --git a/automated-tests/resources/dli/material-environment-out-of-bounds.dli b/automated-tests/resources/dli/material-environment-out-of-bounds.dli
new file mode 100644 (file)
index 0000000..effdcf2
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ { "name": "root" } ],
+  "materials": [ {
+    "environment": 0
+  } ]
+}
diff --git a/automated-tests/resources/dli/mesh-indices-read-fail.dli b/automated-tests/resources/dli/mesh-indices-read-fail.dli
new file mode 100644 (file)
index 0000000..b911f0f
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {} ],
+  "meshes": [ {
+    "uri": "mesh.bin",
+       "attributes": 1
+  } ]
+}
+
diff --git a/automated-tests/resources/dli/mesh-positions-read-fail.dli b/automated-tests/resources/dli/mesh-positions-read-fail.dli
new file mode 100644 (file)
index 0000000..1e98fda
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {} ],
+  "meshes": [ {
+    "uri": "mesh.bin",
+       "attributes": 2
+  } ]
+}
diff --git a/automated-tests/resources/dli/mesh-uri-missing.dli b/automated-tests/resources/dli/mesh-uri-missing.dli
new file mode 100644 (file)
index 0000000..26af1e4
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {} ],
+  "meshes": [ {
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-animated-image-mesh-missing.dli b/automated-tests/resources/dli/node-animated-image-mesh-missing.dli
new file mode 100644 (file)
index 0000000..85c3edf
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "model": { }
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-arc-mesh-missing.dli b/automated-tests/resources/dli/node-arc-mesh-missing.dli
new file mode 100644 (file)
index 0000000..69b8ed4
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "arc": { }
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-child-invalid-type.dli b/automated-tests/resources/dli/node-child-invalid-type.dli
new file mode 100644 (file)
index 0000000..49a719f
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "children": [
+      "what?"
+    ]
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-model-mesh-missing.dli b/automated-tests/resources/dli/node-model-mesh-missing.dli
new file mode 100644 (file)
index 0000000..85c3edf
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "model": { }
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-name-already-used.dli b/automated-tests/resources/dli/node-name-already-used.dli
new file mode 100644 (file)
index 0000000..f176e3a
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "children" : [ 1 ]
+  }, {
+    "name": "root"
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-processor.dli b/automated-tests/resources/dli/node-processor.dli
new file mode 100644 (file)
index 0000000..2b069ad
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "scene": 0,
+  "scenes": [ { "nodes": [ 0 ] }, { "nodes": [ 1 ] } ],
+  "nodes": [ {
+    "name": "rootA",
+    "array": [ 1, 2, 4, 8, -500 ],
+    "object": {
+      "physics": true,
+      "elasticity": 0.27,
+      "drag": 0.91,
+      "inner array": [ "why", "not", false ],
+      "inner object": {
+        "supported": true
+      }
+    },
+    "nickname": "same as name",
+    "favourite number": 63478
+  }, {
+    "name": "rootB"
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-renderable-mesh-invalid-type.dli b/automated-tests/resources/dli/node-renderable-mesh-invalid-type.dli
new file mode 100644 (file)
index 0000000..96cb99c
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "model": { 
+      "mesh": 0.5
+    }
+  } ]
+}
diff --git a/automated-tests/resources/dli/node-renderable-mesh-out-of-bounds.dli b/automated-tests/resources/dli/node-renderable-mesh-out-of-bounds.dli
new file mode 100644 (file)
index 0000000..0b48607
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {
+    "name": "root",
+    "model": {
+      "mesh": 0
+    }
+  } ]
+}
diff --git a/automated-tests/resources/dli/nodes-array-empty.dli b/automated-tests/resources/dli/nodes-array-empty.dli
new file mode 100644 (file)
index 0000000..9a8674d
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "scenes": [ { "nodes" : [] } ],
+  "nodes": []
+}
diff --git a/automated-tests/resources/dli/nodes-invalid-type.dli b/automated-tests/resources/dli/nodes-invalid-type.dli
new file mode 100644 (file)
index 0000000..97fe920
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "scenes": [ { "nodes" : 0 } ],
+  "nodes": []
+}
diff --git a/automated-tests/resources/dli/nodes-missing.dli b/automated-tests/resources/dli/nodes-missing.dli
new file mode 100644 (file)
index 0000000..27504c8
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "scenes": []
+}
diff --git a/automated-tests/resources/dli/root-id-invalid.dli b/automated-tests/resources/dli/root-id-invalid.dli
new file mode 100644 (file)
index 0000000..e6a8608
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "scenes": [ { "nodes" : [ "0" ] } ],
+  "nodes": []
+}
diff --git a/automated-tests/resources/dli/root-id-out-of-bounds.dli b/automated-tests/resources/dli/root-id-out-of-bounds.dli
new file mode 100644 (file)
index 0000000..0549b0b
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": []
+}
diff --git a/automated-tests/resources/dli/root-node-invalid-type.dli b/automated-tests/resources/dli/root-node-invalid-type.dli
new file mode 100644 (file)
index 0000000..e43c9ea
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ "helloo" ]
+}
diff --git a/automated-tests/resources/dli/scene-out-of-bounds.dli b/automated-tests/resources/dli/scene-out-of-bounds.dli
new file mode 100644 (file)
index 0000000..40189a0
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "scenes": [],
+  "nodes": []
+}
diff --git a/automated-tests/resources/dli/scenes-missing.dli b/automated-tests/resources/dli/scenes-missing.dli
new file mode 100644 (file)
index 0000000..1b74fa4
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "": {}
+}
diff --git a/automated-tests/resources/dli/scenes-nodes-missing.dli b/automated-tests/resources/dli/scenes-nodes-missing.dli
new file mode 100644 (file)
index 0000000..e7738fb
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "scenes": [ { } ]
+}
diff --git a/automated-tests/resources/dli/shader-fragment-missing.dli b/automated-tests/resources/dli/shader-fragment-missing.dli
new file mode 100644 (file)
index 0000000..9e7a9e4
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {} ],
+  "shaders": [ {
+    "vertex": "some.vsh"
+  } ]
+}
diff --git a/automated-tests/resources/dli/shader-uniforms.dli b/automated-tests/resources/dli/shader-uniforms.dli
new file mode 100644 (file)
index 0000000..1573fe2
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "scene": 0,
+  "scenes": [ { "nodes": [ 0 ] } ],
+  "nodes": [ {
+    "name": "root"
+  } ],
+  "shaders": [ {
+    "vertex": "dli_pbr.vsh",
+    "fragment": "dli_pbr.fsh",
+    "uBool": true,
+    "uInt": 255,
+    "uFloat": -0.5,
+    "uVec2": [ 100.0, -100.0 ],
+    "uVec3": [ 50.0, 0.0, -200.0 ],
+    "uVec4": [ 0.1774, 1.0, 0.5333, 0.7997 ],
+    "uMat3": [ 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 ],
+    "uMat4": [ 8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 8.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+    "invalid": "Hello, I'm a string"
+  } ]
+}
diff --git a/automated-tests/resources/dli/shader-vertex-missing.dli b/automated-tests/resources/dli/shader-vertex-missing.dli
new file mode 100644 (file)
index 0000000..4f28012
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ { "name": "root" } ],
+  "shaders": [ {} ]
+}
diff --git a/automated-tests/resources/dli/skeleton-node-missing.dli b/automated-tests/resources/dli/skeleton-node-missing.dli
new file mode 100644 (file)
index 0000000..8940f5f
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ {} ],
+  "skeletons": [ {} ]
+}
diff --git a/automated-tests/resources/dli/skeleton-root-not-found.dli b/automated-tests/resources/dli/skeleton-root-not-found.dli
new file mode 100644 (file)
index 0000000..2b6ec8a
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "scenes": [ { "nodes" : [ 0 ] } ],
+  "nodes": [ { "name": "1" } ],
+  "skeletons": [ { "node": "some-other" } ]
+}
diff --git a/automated-tests/resources/dli_arc.fsh b/automated-tests/resources/dli_arc.fsh
new file mode 100644 (file)
index 0000000..7eb83af
--- /dev/null
@@ -0,0 +1,112 @@
+#version 300 es\r
+\r
+#ifdef HIGHP\r
+  precision highp float;\r
+#else\r
+  precision mediump float;\r
+#endif\r
+\r
+#define ROUND_STARTCAP   0x1\r
+#define ROUND_ENDCAP     0x2\r
+#define SQUARE_STARTCAP  0x4\r
+#define SQUARE_ENDCAP    0x8\r
+precision mediump float;\r
+\r
+in vec2 vUV;\r
+\r
+uniform vec4 uColor;\r
+uniform int antiAliasing;\r
+uniform float radius;\r
+uniform vec2 startAngle;\r
+uniform vec2 endAngle;\r
+uniform int arcCaps;\r
+\r
+out vec4 FragColor;\r
+\r
+\r
+void main()\r
+{\r
+////////////////////\r
+//Inputs\r
+  float radius1 = 1.0;\r
+  float uvPixel = length( dFdx( vUV ) ) * 2.0;\r
+  float dx = mix( 0.0001, uvPixel, antiAliasing > 0 );\r
+  float radius2 = mix( 1.0 - radius * uvPixel - dx , -radius , step( 0.0, -radius ) );\r
+////////////////////\r
+  float alpha = 0.0;\r
+  float circle = 0.0;\r
+\r
+  vec2 uv = fract(vUV) * 2.0 - 1.0;\r
+\r
+  float ang_img = endAngle.y * startAngle.x - endAngle.x * startAngle.y;\r
+  float half1 = uv.x * startAngle.x - uv.y * startAngle.y;\r
+  float half2 = uv.y * endAngle.y - uv.x * endAngle.x;\r
+  float len = length(uv);\r
+  float equalAngles = step(0.99999, dot(endAngle, startAngle));\r
+  float right_side = step(0.0, ang_img);\r
+  vec2 uv_norm = normalize(uv);\r
+  float cap_radius = -0.5 + radius2 / 2.0;\r
+  float square_cap;\r
+  float sq_plane;\r
+\r
+    /******************************************\r
+   * Equivalent to:\r
+   * if( len > radius1 || len < radius2 )\r
+   */\r
+  circle = alpha =  smoothstep( len, len + dx, radius1 ) * smoothstep( -len, -len + dx, -radius2 );\r
+  float half1_step = smoothstep( -dx, 0.0, half1 );\r
+  float half2_step = smoothstep( -dx, 0.0, half2 );\r
+\r
+  float neg_angimg = max( half1_step, half2_step );\r
+  float pos_angimg = min( half1_step, half2_step );\r
+  /******************************************\r
+   * Equivalent to:\r
+  if(ang_img < 0.0)\r
+  {\r
+    alpha *= max(smoothstep( 0.0, dx, half1 ), smoothstep( 0.0, dx, half2));\r
+  }\r
+  else\r
+  {\r
+    alpha *= min(smoothstep( 0.0, dx, half1 ) , smoothstep( 0.0, dx, half2 ));\r
+  }\r
+  */\r
+  alpha *= mix( neg_angimg, pos_angimg, step(0.0, ang_img) );\r
+\r
+  alpha = mix( alpha, mix( circle, 0.0, right_side ), equalAngles );\r
+\r
+  if((arcCaps & ROUND_STARTCAP) > 0)\r
+  {\r
+    len = length(uv - normalize( vec2( startAngle.y, startAngle.x )) * (1.0 + cap_radius));\r
+    alpha = max(alpha, smoothstep(cap_radius, cap_radius + dx, -len) );\r
+  }\r
+  if((arcCaps & ROUND_ENDCAP) > 0)\r
+  {\r
+    len = length(uv - normalize( vec2( endAngle.y, endAngle.x )) * (1.0 + cap_radius));\r
+    alpha = max(alpha, smoothstep(cap_radius, cap_radius + dx, -len) );\r
+  }\r
+\r
+  if((arcCaps & SQUARE_STARTCAP) > 0)\r
+  {\r
+    sq_plane = -uv.x * startAngle.y - uv.y * startAngle.x;\r
+    square_cap = min(step( 0.0, -half1 ), smoothstep( cap_radius, cap_radius + dx, half1 ));\r
+    square_cap = min(square_cap, smoothstep( radius2, radius2 + dx, -sq_plane ));\r
+    square_cap = min(square_cap, smoothstep( -1.0, -1.0 + dx, sq_plane ));\r
+    alpha = max(square_cap, alpha);\r
+  }\r
+\r
+  if((arcCaps & SQUARE_ENDCAP) > 0)\r
+  {\r
+    sq_plane = -uv.x * endAngle.y - uv.y * endAngle.x;\r
+    square_cap = min(step( 0.0, -half2 ), smoothstep( cap_radius, cap_radius + dx, half2 ));\r
+    square_cap = min(square_cap, smoothstep( radius2, radius2 + dx, -sq_plane ));\r
+    square_cap = min(square_cap, smoothstep( -1.0, -1.0 + dx, sq_plane ));\r
+    alpha = max(square_cap, alpha);\r
+  }\r
+\r
+  if( alpha == 0.0 )\r
+  {\r
+    discard;\r
+  }\r
+\r
+  FragColor = vec4(vec3(uColor), uColor.a * alpha);\r
+}\r
diff --git a/automated-tests/resources/dli_arc.vsh b/automated-tests/resources/dli_arc.vsh
new file mode 100644 (file)
index 0000000..7b38dea
--- /dev/null
@@ -0,0 +1,36 @@
+#version 300 es\r
+\r
+#ifdef HIGHP\r
+  precision highp float;\r
+#else\r
+  precision mediump float;\r
+#endif\r
+\r
+in vec3 aPosition;\r
+in vec2 aTexCoord;\r
+\r
+out vec2 vUV;\r
+\r
+uniform vec3 uSize;\r
+\r
+uniform mat4 uProjection;\r
+uniform mat4 uModelMatrix;\r
+uniform mat4 uViewMatrix;\r
+\r
+uniform vec2 uTilt;\r
+\r
+void main()\r
+{\r
+  vec4 vPosition = vec4( aPosition * uSize, 1.0);\r
+  vec4 mPosition = uModelMatrix * vPosition;\r
+\r
+  mPosition.xy += 0.3 * uTilt * mPosition.z;\r
+  gl_Position = uProjection * uViewMatrix * mPosition;\r
+\r
+#ifdef FLIP_V\r
+  vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\r
+#else\r
+  vUV = aTexCoord;\r
+#endif\r
+\r
+}\r
diff --git a/automated-tests/resources/dli_images.fsh b/automated-tests/resources/dli_images.fsh
new file mode 100644 (file)
index 0000000..72a88b3
--- /dev/null
@@ -0,0 +1,31 @@
+#version 300 es\r
+\r
+#ifdef HIGHP\r
+  precision highp float;\r
+#else\r
+  precision mediump float;\r
+#endif\r
+\r
+uniform sampler2D sAlbedo;\r
+\r
+uniform vec4 uColor;\r
+\r
+#ifdef ALPHA_TEST\r
+  uniform float uAlphaThreshold;\r
+#endif //ALPHA_TEST\r
+\r
+in vec2 vUV;\r
+\r
+out vec4 FragColor;\r
+\r
+void main()\r
+{\r
+  vec4 color = texture(sAlbedo, vUV.st);\r
+#ifdef ALPHA_TEST\r
+  if (color.a <= uAlphaThreshold)\r
+  {\r
+    discard;\r
+  }\r
+#endif\r
+  FragColor = color * uColor;\r
+}\r
diff --git a/automated-tests/resources/dli_images.vsh b/automated-tests/resources/dli_images.vsh
new file mode 100644 (file)
index 0000000..9698937
--- /dev/null
@@ -0,0 +1,37 @@
+#version 300 es\r
+\r
+#ifdef HIGHP\r
+  precision highp float;\r
+#else\r
+  precision mediump float;\r
+#endif\r
+\r
+in vec3 aPosition;\r
+in vec2 aTexCoord;\r
+\r
+out vec2 vUV;\r
+\r
+uniform vec3 uSize;\r
+\r
+uniform mat4 uCubeMatrix;\r
+\r
+uniform mat4 uProjection;\r
+uniform mat4 uModelMatrix;\r
+uniform mat4 uViewMatrix;\r
+\r
+uniform vec2 uTilt;\r
+\r
+void main()\r
+{\r
+  vec4 vPosition = vec4( aPosition * uSize, 1.0);\r
+  vec4 mPosition = uModelMatrix * vPosition;\r
+\r
+  mPosition.xy += 0.3 * uTilt * mPosition.z;\r
+  gl_Position = uProjection * uViewMatrix * mPosition;\r
+\r
+#ifdef FLIP_V\r
+  vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\r
+#else\r
+  vUV = aTexCoord;\r
+#endif\r
+}\r
diff --git a/automated-tests/resources/dli_pbr.fsh b/automated-tests/resources/dli_pbr.fsh
new file mode 100644 (file)
index 0000000..72a0d31
--- /dev/null
@@ -0,0 +1,160 @@
+#version 300 es\r
+\r
+#ifdef HIGHP\r
+  precision highp float;\r
+#else\r
+  precision mediump float;\r
+#endif\r
+\r
+#ifdef THREE_TEX\r
+#ifdef GLTF_CHANNELS\r
+// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture\r
+#define METALLIC b\r
+#define ROUGHNESS g\r
+#else //GLTF_CHANNELS\r
+#define METALLIC r\r
+#define ROUGHNESS a\r
+#endif //GLTF_CHANNELS\r
+#endif //THREE_TEX\r
+\r
+#ifdef THREE_TEX\r
+  uniform sampler2D sAlbedoAlpha;\r
+  uniform sampler2D sMetalRoughness;\r
+  uniform sampler2D sNormal;\r
+\r
+#ifdef ALPHA_TEST\r
+  uniform float uAlphaThreshold;\r
+#endif //ALPHA_TEST\r
+\r
+#else\r
+  uniform sampler2D sAlbedoMetal;\r
+  uniform sampler2D sNormalRoughness;\r
+#endif\r
+\r
+uniform samplerCube sDiffuse;\r
+uniform samplerCube sSpecular;\r
+\r
+// Number of mip map levels in the texture\r
+uniform float uMaxLOD;\r
+\r
+// Transformation matrix of the cubemap texture\r
+uniform mat4 uCubeMatrix;\r
+\r
+uniform vec4 uColor;\r
+uniform float uMetallicFactor;\r
+uniform float uRoughnessFactor;\r
+\r
+//IBL Light intensity\r
+uniform float uIblIntensity;\r
+\r
+in vec2 vUV;\r
+in vec3 vNormal;\r
+in vec3 vTangent;\r
+in vec3 vViewVec;\r
+\r
+out vec4 FragColor;\r
+\r
+// Functions for BRDF calculation come from\r
+// https://www.unrealengine.com/blog/physically-based-shading-on-mobile\r
+// Based on the paper by Dimitar Lazarov\r
+// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf\r
+vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )\r
+{\r
+  const vec4 c0 = vec4( -1.0, -0.0275, -0.572, 0.022 );\r
+  const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04 );\r
+  vec4 r = Roughness * c0 + c1;\r
+  float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\r
+  vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\r
+\r
+  return SpecularColor * AB.x + AB.y;\r
+}\r
+\r
+void main()\r
+{\r
+  // We get information from the maps (albedo, normal map, roughness, metalness\r
+  // I access the maps in the order they will be used\r
+#ifdef THREE_TEX\r
+  vec4 albedoAlpha = texture(sAlbedoAlpha, vUV.st);\r
+  float alpha = albedoAlpha.a;\r
+#ifdef ALPHA_TEST\r
+  if (alpha <= uAlphaThreshold)\r
+  {\r
+    discard;\r
+  }\r
+#endif //ALPHA_TEST\r
+  vec3 albedoColor = albedoAlpha.rgb * uColor.rgb;\r
+\r
+  vec4 metalRoughness = texture(sMetalRoughness, vUV.st);\r
+  float metallic = metalRoughness.METALLIC * uMetallicFactor;\r
+  float roughness = metalRoughness.ROUGHNESS * uRoughnessFactor;\r
+\r
+  vec3 normalMap = texture(sNormal, vUV.st).rgb;\r
+#else  //THREE_TEX\r
+  vec4 albedoMetal = texture(sAlbedoMetal, vUV.st);\r
+  vec3 albedoColor = albedoMetal.rgb * uColor.rgb;\r
+  float metallic = albedoMetal.a * uMetallicFactor;\r
+\r
+  vec4 normalRoughness = texture(sNormalRoughness, vUV.st);\r
+  vec3 normalMap = normalRoughness.rgb;\r
+  float roughness = normalRoughness.a * uRoughnessFactor;\r
+#endif\r
+  //Normalize vectors\r
+  vec3 normal = normalize(vNormal);\r
+  vec3 tangent = normalize(vTangent);\r
+\r
+  // NOTE: normal and tangent have to be orthogonal for the result of the cross()\r
+  // product to be a unit vector. We might find that we need to normalize().\r
+  vec3 bitangent = cross(normal, tangent);\r
+\r
+  vec3 viewVec = normalize(vViewVec);\r
+\r
+  // Create Inverse Local to world matrix\r
+  mat3 vInvTBN = mat3(tangent, bitangent, normal);\r
+\r
+  // Get normal map info in world space\r
+  normalMap = normalize(normalMap - 0.5);\r
+  vec3 newNormal = vInvTBN * normalMap.rgb;\r
+\r
+  // Calculate normal dot view vector\r
+  float NoV = max(dot(newNormal, -viewVec), 0.0);\r
+\r
+  // Reflect vector\r
+  vec3 reflectionVec = reflect(viewVec, newNormal);\r
+\r
+  //transform it now to environment coordinates (used when the environment rotates)\r
+  vec3 reflecCube = (uCubeMatrix * vec4( reflectionVec, 0.0 ) ).xyz;\r
+  reflecCube = normalize( reflecCube );\r
+\r
+  //transform it now to environment coordinates\r
+  vec3 normalCube = ( uCubeMatrix * vec4( newNormal, 0.0 ) ).xyz;\r
+  normalCube = normalize( normalCube );\r
+\r
+  // Get irradiance from diffuse cubemap\r
+  vec3 irradiance = texture( sDiffuse, normalCube ).rgb;\r
+\r
+  // Access reflection color using roughness value\r
+  float finalLod = mix( 0.0, uMaxLOD - 2.0, roughness);\r
+  vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb;\r
+\r
+  // We are supposed to be using DielectricColor (0.04) of a plastic (almost everything)\r
+  // http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf\r
+  // however that seems to prevent achieving very dark tones (i.e. get dark gray blacks).\r
+  vec3 DiffuseColor = albedoColor - albedoColor * metallic;  // 1 mad\r
+  vec3 SpecularColor = mix( vec3(0.04), albedoColor, metallic); // 2 mad\r
+\r
+  // Calculate specular color using Magic Function (takes original roughness and normal dot view).\r
+  vec3 specColor =  reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV );\r
+\r
+  // Multiply the result by albedo texture and do energy conservation\r
+  vec3 diffuseColor = irradiance * DiffuseColor;\r
+\r
+  // Final color is the sum of the diffuse and specular term\r
+  vec3 finalColor = diffuseColor + specColor;\r
+\r
+  finalColor = sqrt( finalColor ) * uIblIntensity;\r
+#ifdef THREE_TEX\r
+  FragColor = vec4( finalColor, alpha );\r
+#else //THREE_TEX\r
+  FragColor = vec4( finalColor, 1.0 );\r
+#endif //THREE_TEX\r
+}\r
diff --git a/automated-tests/resources/dli_pbr.vsh b/automated-tests/resources/dli_pbr.vsh
new file mode 100644 (file)
index 0000000..d1be304
--- /dev/null
@@ -0,0 +1,150 @@
+#version 300 es\r
+\r
+#ifdef HIGHP\r
+  precision highp float;\r
+#else\r
+  precision mediump float;\r
+#endif\r
+\r
+in vec3 aPosition;\r
+in vec2 aTexCoord;\r
+in vec3 aNormal;\r
+in vec3 aTangent;\r
+\r
+#ifdef MORPH\r
+  uniform sampler2D sBlendShapeGeometry;\r
+#endif\r
+\r
+out vec2 vUV;\r
+out vec3 vNormal;\r
+out vec3 vTangent;\r
+out vec3 vViewVec;\r
+\r
+\r
+uniform highp mat4 uMvpMatrix;\r
+uniform highp mat4 uViewMatrix;\r
+uniform mat3 uNormalMatrix;\r
+uniform mat4 uModelMatrix;\r
+uniform mat4 uModelView;\r
+uniform mat4 uProjection;\r
+\r
+#ifdef SKINNING\r
+  in vec4 aJoints;\r
+  in vec4 aWeights;\r
+  #define MAX_BONES 64\r
+  uniform mat4 uBone[MAX_BONES];\r
+#endif\r
+\r
+#ifdef MORPH\r
+#define MAX_BLEND_SHAPE_NUMBER 128\r
+uniform int uNumberOfBlendShapes;                                   ///< Total number of blend shapes loaded.\r
+uniform float uBlendShapeWeight[MAX_BLEND_SHAPE_NUMBER];            ///< The weight of each blend shape.\r
+#ifdef MORPH_VERSION_2_0\r
+uniform float uBlendShapeUnnormalizeFactor;                         ///< Factor used to unnormalize the geometry of the blend shape.\r
+#else\r
+uniform float uBlendShapeUnnormalizeFactor[MAX_BLEND_SHAPE_NUMBER]; ///< Factor used to unnormalize the geometry of the blend shape.\r
+#endif\r
+uniform int uBlendShapeComponentSize;                               ///< The size in the texture of either the vertices, normals or tangents. Used to calculate the offset to address them.\r
+#endif\r
+\r
+void main()\r
+{\r
+  vec4 position = vec4(aPosition, 1.0);\r
+  vec3 normal = aNormal;\r
+  vec3 tangent = aTangent;\r
+\r
+#ifdef MORPH\r
+  int width = textureSize( sBlendShapeGeometry, 0 ).x;\r
+\r
+  int blendShapeBufferOffset = 0;\r
+  for( int index = 0; index < uNumberOfBlendShapes; ++index )\r
+  {\r
+#ifdef MORPH_POSITION\r
+    // Calculate the index to retrieve the geometry from the texture.\r
+    int vertexId = gl_VertexID + blendShapeBufferOffset;\r
+    int x = vertexId % width;\r
+    int y = vertexId / width;\r
+\r
+    vec3 diff = vec3(0.0);\r
+    // Retrieves the blend shape geometry from the texture, unnormalizes it and multiply by the weight.\r
+    if( 0.0 != uBlendShapeWeight[index] )\r
+    {\r
+#ifdef MORPH_VERSION_2_0\r
+       float unnormalizeFactor = uBlendShapeUnnormalizeFactor;\r
+#else\r
+       float unnormalizeFactor = uBlendShapeUnnormalizeFactor[index];\r
+#endif\r
+\r
+      diff = uBlendShapeWeight[index] * unnormalizeFactor * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );\r
+    }\r
+\r
+    position.xyz += diff;\r
+\r
+    blendShapeBufferOffset += uBlendShapeComponentSize;\r
+#endif\r
+\r
+#ifdef MORPH_NORMAL\r
+    // Calculate the index to retrieve the normal from the texture.\r
+    vertexId = gl_VertexID + blendShapeBufferOffset;\r
+    x = vertexId % width;\r
+    y = vertexId / width;\r
+\r
+    // Retrieves the blend shape normal from the texture, unnormalizes it and multiply by the weight.\r
+    if( 0.0 != uBlendShapeWeight[index] )\r
+    {\r
+      diff = uBlendShapeWeight[index] * 2.0 * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );\r
+    }\r
+\r
+    normal += diff.xyz;\r
+\r
+    blendShapeBufferOffset += uBlendShapeComponentSize;\r
+#endif\r
+\r
+#ifdef MORPH_TANGENT\r
+    // Calculate the index to retrieve the tangent from the texture.\r
+    vertexId = gl_VertexID + blendShapeBufferOffset;\r
+    x = vertexId % width;\r
+    y = vertexId / width;\r
+\r
+    // Retrieves the blend shape tangent from the texture, unnormalizes it and multiply by the weight.\r
+    if( 0.0 != uBlendShapeWeight[index] )\r
+    {\r
+      diff = uBlendShapeWeight[index] * 2.0 * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );\r
+    }\r
+\r
+    tangent += diff.xyz;\r
+\r
+    blendShapeBufferOffset += uBlendShapeComponentSize;\r
+#endif\r
+  }\r
+\r
+#endif\r
+\r
+#ifdef SKINNING\r
+  mat4 bone = uBone[int(aJoints.x)] * aWeights.x +\r
+    uBone[int(aJoints.y)] * aWeights.y +\r
+    uBone[int(aJoints.z)] * aWeights.z +\r
+    uBone[int(aJoints.w)] * aWeights.w;\r
+  position = bone * position;\r
+  normal = (bone * vec4(normal, 0.0)).xyz;\r
+  tangent = (bone * vec4(tangent, 0.0)).xyz;\r
+#endif\r
+\r
+  vec4 vPosition = uModelMatrix * position;\r
+\r
+  vNormal = normalize(uNormalMatrix * normal);\r
+\r
+  vTangent = normalize(uNormalMatrix * tangent);\r
+\r
+\r
+  vec4 viewPosition = uViewMatrix * vPosition;\r
+  gl_Position = uProjection * viewPosition;\r
+\r
+#ifdef FLIP_V\r
+  vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\r
+#else\r
+  vUV = aTexCoord;\r
+#endif\r
+\r
+  vViewVec = viewPosition.xyz;\r
+}\r
diff --git a/automated-tests/resources/exercise.dli b/automated-tests/resources/exercise.dli
new file mode 100644 (file)
index 0000000..7d9c6b4
--- /dev/null
@@ -0,0 +1,11634 @@
+{\r
+    "asset" : {\r
+        "version" : "1.0"\r
+    },\r
+    "scene" : 1,\r
+    "scenes" : [ {\r
+        "nodes" : [ 0 ]\r
+    }, {\r
+        "nodes" : [ 95 ]\r
+    } ],\r
+    "nodes" : [ {\r
+        "name" : "ExerciseDemo",\r
+        "matrix" : [ 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 1, 79, 88, 91, 92, 93, 94 ],\r
+        "behavior" : [ 4 ],\r
+        "visible" : true,\r
+        "lightingMode" : "lit"\r
+    }, {\r
+        "name" : "ReferenceShape_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 2 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hips_JNT",\r
+        "matrix" : [ 0.984536, 0.175182, 0.0, 0.0, -0.175122, 0.984198, 0.026198, 0.0, 0.004589, -0.025793, 0.999657, 0.0, 5.27538, 78.6471, -1.41421, 1.0 ],\r
+        "children" : [ 3, 69, 74 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.013219, -80.0521, 1.41421, 1.0 ]\r
+    }, {\r
+        "name" : "spine_JNT",\r
+        "matrix" : [ 0.984536, -0.175122, 0.004589, 0.0, 0.174502, 0.982682, 0.062338, 0.0, -0.015426, -0.060573, 0.998044, 0.0, 0.015846, 4.13037, 0.166239, 1.0 ],\r
+        "children" : [ 4 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.002627, -84.1824, 1.24797, 1.0 ]\r
+    }, {\r
+        "name" : "spine1_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.998172, -0.06044, 0.0, 0.0, 0.06044, 0.998172, 0.0, 0.005973, 10.694, 0.968772, 1.0 ],\r
+        "children" : [ 5 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.0086, -94.8764, 0.279197, 1.0 ]\r
+    }, {\r
+        "name" : "spine2_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.998172, -0.06044, 0.0, 0.0, 0.06044, 0.998172, 0.0, 0.0, 10.1532, -0.580362, 1.0 ],\r
+        "children" : [ 6, 30, 54 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.008557, -105.03, 0.859559, 1.0 ]\r
+    }, {\r
+        "name" : "l_shoulder_JNT",\r
+        "matrix" : [ 0.949195, 0.273744, -0.155217, 0.0, -0.201691, 0.907824, 0.367663, 0.0, 0.241555, -0.317678, 0.916914, 0.0, 2.88666, 12.5391, -0.534974, 1.0 ],\r
+        "children" : [ 7 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.89521, -117.569, 1.39453, 1.0 ]\r
+    }, {\r
+        "name" : "l_arm_JNT",\r
+        "matrix" : [ 0.421571, -0.904401, -0.065849, 0.0, 0.517137, 0.180132, 0.836733, 0.0, -0.744881, -0.386795, 0.543638, 0.0, 10.2653, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 8 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -13.1738, -116.164, 1.39451, 1.0 ]\r
+    }, {\r
+        "name" : "l_forearm_JNT",\r
+        "matrix" : [ -0.073871, 0.0, 0.997268, 0.0, -3.91E-4, 1.0, 0.0, 0.0, -0.997268, -3.93E-4, -0.073871, 0.0, 25.5729, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 9 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -38.7466, -116.164, 1.39451, 1.0 ]\r
+    }, {\r
+        "name" : "l_hand_JNT",\r
+        "matrix" : [ 0.738915, 0.444766, -0.506149, 0.0, -0.59918, 0.777334, -0.191665, 0.0, 0.308201, 0.444898, 0.840879, 0.0, 19.8068, -0.345714, 1.00359, 1.0 ],\r
+        "children" : [ 10, 14, 18, 22, 26 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -58.5534, -115.818, 0.390923, 1.0 ]\r
+    }, {\r
+        "name" : "l_handThumb1_JNT",\r
+        "matrix" : [ 0.782913, -0.117863, 0.610865, 0.0, 0.011962, 0.984561, 0.174635, 0.0, -0.622017, -0.129417, 0.772235, 0.0, 2.27648, -1.65194, 3.31969, 1.0 ],\r
+        "children" : [ 11 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.707107, 0.0, -0.707107, 0.0, 0.0, 1.0, 0.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, -45.0842, -114.166, 40.9423, 1.0 ]\r
+    }, {\r
+        "name" : "l_handThumb2_JNT",\r
+        "matrix" : [ 0.830425, -0.487404, -0.269872, 0.0, 0.464771, 0.873169, -0.146844, 0.0, 0.307216, -0.003486, 0.951633, 0.0, 3.0735, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 12 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.707107, 0.0, -0.707108, 0.0, 0.0, 1.0, 0.0, 0.0, 0.707108, 0.0, 0.707107, 0.0, -48.1577, -114.166, 40.9423, 1.0 ]\r
+    }, {\r
+        "name" : "l_handThumb3_JNT",\r
+        "matrix" : [ 0.98882, -0.149117, 0.0, 0.0, 0.149117, 0.98882, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 3.37693, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 13 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.707107, 0.0, -0.707108, 0.0, 0.0, 1.0, 0.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, -51.5344, -114.166, 40.9423, 1.0 ]\r
+    }, {\r
+        "name" : "l_handThumb4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 3.92326, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_handIndex1_JNT",\r
+        "matrix" : [ 0.904938, -0.425377, 0.011949, 0.0, 0.425382, 0.905011, 0.002209, 0.0, -0.011754, 0.003084, 1.0, 0.0, 9.34022, -0.291901, 4.04881, 1.0 ],\r
+        "children" : [ 15 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -67.8936, -115.526, -3.65789, 1.0 ]\r
+    }, {\r
+        "name" : "l_handIndex2_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.09938, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 16 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -71.993, -115.526, -3.65788, 1.0 ]\r
+    }, {\r
+        "name" : "l_handIndex3_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.57415, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 17 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -74.5672, -115.526, -3.65788, 1.0 ]\r
+    }, {\r
+        "name" : "l_handIndex4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.56603, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_handPinky1_JNT",\r
+        "matrix" : [ 0.996226, -0.081261, -0.030513, 0.0, 0.081431, 0.996669, 0.004384, 0.0, 0.030055, -0.006852, 0.999525, 0.0, 8.45263, -1.52385, -3.88068, 1.0 ],\r
+        "children" : [ 19 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -67.0061, -114.294, 4.2716, 1.0 ]\r
+    }, {\r
+        "name" : "l_handPinky2_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 3.07304, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 20 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -70.0791, -114.294, 4.2716, 1.0 ]\r
+    }, {\r
+        "name" : "l_handPinky3_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.96712, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 21 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -72.0462, -114.294, 4.27159, 1.0 ]\r
+    }, {\r
+        "name" : "l_handPinky4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.8257, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_handRing1_JNT",\r
+        "matrix" : [ 0.980994, -0.191551, 0.030976, 0.0, 0.19168, 0.981457, -0.001225, 0.0, -0.030167, 0.007139, 0.999519, 0.0, 9.86254, -0.583908, -1.401, 1.0 ],\r
+        "children" : [ 23 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -68.416, -115.234, 1.79193, 1.0 ]\r
+    }, {\r
+        "name" : "l_handRing2_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 3.90873, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 24 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -72.3247, -115.234, 1.79192, 1.0 ]\r
+    }, {\r
+        "name" : "l_handRing3_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.36478, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 25 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -74.6895, -115.234, 1.79192, 1.0 ]\r
+    }, {\r
+        "name" : "l_handRing4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.88243, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_handMiddle1_JNT",\r
+        "matrix" : [ 0.953413, -0.301668, 0.0, 0.0, 0.301668, 0.953413, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0737, -0.408325, 1.31404, 1.0 ],\r
+        "children" : [ 27 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -68.6272, -115.41, -0.923121, 1.0 ]\r
+    }, {\r
+        "name" : "l_handMiddle2_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973047, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.2249, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 28 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -72.8521, -115.41, -0.923118, 1.0 ]\r
+    }, {\r
+        "name" : "l_handMiddle3_JNT",\r
+        "matrix" : [ 0.973047, -0.230606, 0.0, 0.0, 0.230606, 0.973048, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.46916, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 29 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -75.3213, -115.41, -0.923117, 1.0 ]\r
+    }, {\r
+        "name" : "l_handMiddle4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 3.28131, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "r_shoulder_JNT",\r
+        "matrix" : [ 0.999696, 0.01745, -0.017452, 0.0, -0.017145, 0.999701, 0.01745, 0.0, 0.017751, -0.017145, 0.999696, 0.0, -2.88677, 12.5391, -0.53497, 1.0 ],\r
+        "children" : [ 31 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 2.87821, -117.569, 1.39453, 1.0 ]\r
+    }, {\r
+        "name" : "r_arm_JNT",\r
+        "matrix" : [ 0.148671, 0.988778, -0.014664, 0.0, -0.988733, 0.14837, -0.019851, 0.0, -0.017453, 0.01745, 0.999695, 0.0, -10.2653, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 32 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 13.1303, -116.164, 1.39455, 1.0 ]\r
+    }, {\r
+        "name" : "r_forearm_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 4.01E-4, 0.0, 0.0, -4.01E-4, 1.0, 0.0, -25.5729, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 33 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 38.7032, -116.164, 1.39456, 1.0 ]\r
+    }, {\r
+        "name" : "r_hand_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -4.01E-4, 0.0, 0.0, 4.01E-4, 1.0, 0.0, -19.807, -0.346, 1.00358, 1.0 ],\r
+        "children" : [ 34, 38, 42, 46, 50 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 58.5102, -115.818, 0.390979, 1.0 ]\r
+    }, {\r
+        "name" : "r_handThumb1_JNT",\r
+        "matrix" : [ 0.653433, 0.24549, -0.716073, 0.0, -0.244838, 0.963648, 0.106945, 0.0, 0.716296, 0.105441, 0.689785, 0.0, -2.27647, -1.65195, 3.31969, 1.0 ],\r
+        "children" : [ 35 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.707106, 0.0, 0.707106, 0.0, 0.0, 1.0, 0.0, 0.0, -0.707106, 0.0, 0.707106, 0.0, 45.0536, -114.166, 40.9117, 1.0 ]\r
+    }, {\r
+        "name" : "r_handThumb2_JNT",\r
+        "matrix" : [ 0.867302, 0.0, 0.497783, 0.0, 0.0, 1.0, 0.0, 0.0, -0.497783, 0.0, 0.867301, 0.0, -3.0735, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 36 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.707106, 0.0, 0.707106, 0.0, 0.0, 1.0, 0.0, 0.0, -0.707106, 0.0, 0.707106, 0.0, 48.127, -114.166, 40.9117, 1.0 ]\r
+    }, {\r
+        "name" : "r_handThumb3_JNT",\r
+        "matrix" : [ 0.996311, 0.0, 0.085813, 0.0, 0.0, 1.0, 0.0, 0.0, -0.085813, 0.0, 0.996311, 0.0, -3.37693, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 37 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.707106, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.0, 0.0, -0.707106, 0.0, 0.707107, 0.0, 51.504, -114.166, 40.9117, 1.0 ]\r
+    }, {\r
+        "name" : "r_handThumb4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -3.923, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "r_handRing1_JNT",\r
+        "matrix" : [ 0.915131, 0.400047, -0.049976, 0.0, -0.400717, 0.916194, -0.003754, 0.0, 0.044286, 0.023462, 0.998743, 0.0, -9.86253, -0.583984, -1.40101, 1.0 ],\r
+        "children" : [ 39 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 68.3727, -115.234, 1.79199, 1.0 ]\r
+    }, {\r
+        "name" : "r_handRing2_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -3.90872, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 40 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 72.2814, -115.234, 1.79199, 1.0 ]\r
+    }, {\r
+        "name" : "r_handRing3_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.36478, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 41 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 74.6462, -115.234, 1.792, 1.0 ]\r
+    }, {\r
+        "name" : "r_handRing4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.882, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "r_handPinky1_JNT",\r
+        "matrix" : [ 0.863063, 0.499949, -0.071924, 0.0, -0.501878, 0.864874, -0.010555, 0.0, 0.056928, 0.045207, 0.997354, 0.0, -8.45262, -1.52391, -3.88068, 1.0 ],\r
+        "children" : [ 43 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 66.9628, -114.294, 4.27166, 1.0 ]\r
+    }, {\r
+        "name" : "r_handPinky2_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -3.07304, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 44 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 70.0358, -114.294, 4.27167, 1.0 ]\r
+    }, {\r
+        "name" : "r_handPinky3_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -1.96712, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 45 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 72.0029, -114.294, 4.27168, 1.0 ]\r
+    }, {\r
+        "name" : "r_handPinky4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.826, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "r_handMiddle1_JNT",\r
+        "matrix" : [ 0.944916, 0.327312, 0.0, 0.0, -0.327312, 0.944916, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -10.0737, -0.408401, 1.31403, 1.0 ],\r
+        "children" : [ 47 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 68.5839, -115.409, -0.923056, 1.0 ]\r
+    }, {\r
+        "name" : "r_handMiddle2_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -4.2249, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 48 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 72.8088, -115.409, -0.923044, 1.0 ]\r
+    }, {\r
+        "name" : "r_handMiddle3_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.46917, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 49 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 75.278, -115.409, -0.92304, 1.0 ]\r
+    }, {\r
+        "name" : "r_handMiddle4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -3.281, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "r_handIndex1_JNT",\r
+        "matrix" : [ 0.980248, 0.186022, 0.067154, 0.0, -0.186597, 0.982434, 0.002344, 0.0, -0.065538, -0.014828, 0.99774, 0.0, -9.34022, -0.291962, 4.0488, 1.0 ],\r
+        "children" : [ 51 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 67.8504, -115.526, -3.65782, 1.0 ]\r
+    }, {\r
+        "name" : "r_handIndex2_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -4.09938, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 52 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 71.9498, -115.526, -3.65782, 1.0 ]\r
+    }, {\r
+        "name" : "r_handIndex3_JNT",\r
+        "matrix" : [ 0.94204, 0.335501, 0.0, 0.0, -0.335501, 0.94204, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.57415, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 53 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 74.5239, -115.526, -3.65782, 1.0 ]\r
+    }, {\r
+        "name" : "r_handIndex4_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -2.566, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "neck_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.998172, -0.06044, 0.0, 0.0, 0.06044, 0.998172, 0.0, 0.0, 17.0656, -0.695395, 1.0 ],\r
+        "children" : [ 55 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.008488, -122.095, 1.55495, 1.0 ]\r
+    }, {\r
+        "name" : "head_JNT",\r
+        "matrix" : [ 0.995828, 0.087837, -0.024703, 0.0, -0.081637, 0.978626, 0.188753, 0.0, 0.040755, -0.185949, 0.981714, 0.0, 0.0, 8.13757, 2.14518, 1.0 ],\r
+        "children" : [ 56, 59, 62, 65, 66, 67, 68 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.021705, -128.828, -2.00444, 1.0 ]\r
+    }, {\r
+        "name" : "hair_01_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 11.442, 24.1427, -1.69867, 1.0 ],\r
+        "children" : [ 57 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_01_01_JNT",\r
+        "matrix" : [ 0.0, 0.0, -1.0, 0.0, -0.093641, 0.995606, 0.0, 0.0, 0.995606, 0.093641, 0.0, 0.0, 0.0, -9.01569, 0.0, 1.0 ],\r
+        "children" : [ 58 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_01_02_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -11.0805, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_02_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -13.1304, 24.2143, -1.69866, 1.0 ],\r
+        "children" : [ 60 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_02_01_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -9.01563, 0.0, 1.0 ],\r
+        "children" : [ 61 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_02_02_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -11.0805, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_03_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 24.2142, -13.2264, 1.0 ],\r
+        "children" : [ 63 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_03_01_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -9.01563, 0.0, 1.0 ],\r
+        "children" : [ 64 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "hair_03_02_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -11.0805, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_earring_accessory_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.936, 6.972, 0.888, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "r_earring_accessory_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -11.0026, 6.74516, 0.187242, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_eye_JNT",\r
+        "matrix" : [ 0.997963, -0.003027, 0.063724, 0.0, -0.003026, 0.995503, 0.094684, 0.0, -0.063724, -0.094684, 0.993466, 0.0, 4.68487, 12.7498, 9.96268, 1.0 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -4.74966, -141.45, -10.6596, 1.0 ]\r
+    }, {\r
+        "name" : "r_eye_JNT",\r
+        "matrix" : [ 0.997966, -0.002933, 0.063684, 0.0, -0.002932, 0.995772, 0.091809, 0.0, -0.063684, -0.091809, 0.993738, 0.0, -4.77108, 12.7498, 9.96268, 1.0 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 4.70629, -141.45, -10.6596, 1.0 ]\r
+    }, {\r
+        "name" : "r_upleg_JNT",\r
+        "matrix" : [ 0.927337, -0.198173, 0.317448, 0.0, 0.278028, 0.93264, -0.229963, 0.0, -0.250492, 0.301512, 0.919969, 0.0, -7.5159, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 70 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, -0.002495, -1.16E-4, 0.0, 0.002493, 0.999837, -0.017917, 0.0, 1.61E-4, 0.017917, 0.99984, 0.0, 7.32992, -80.0324, 2.84741, 1.0 ]\r
+    }, {\r
+        "name" : "r_leg_JNT",\r
+        "matrix" : [ 0.997732, 0.060039, 0.030441, 0.0, -0.067243, 0.9099, 0.409341, 0.0, -0.003122, -0.41046, 0.911874, 0.0, -0.724057, -37.7363, 2.80023, 1.0 ],\r
+        "children" : [ 71 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.002998, 0.0, 0.0, -0.002998, 0.999857, 0.016638, 0.0, 0.0, -0.016638, 0.999862, 0.0, 8.28614, -42.2277, -1.41208, 1.0 ]\r
+    }, {\r
+        "name" : "r_foot_JNT",\r
+        "matrix" : [ 0.964557, 0.026598, 0.262529, 0.0, 0.024923, 0.981276, -0.190988, 0.0, -0.262693, 0.190762, 0.945834, 0.0, 1.26E-4, -34.5752, -1.6048, 1.0 ],\r
+        "children" : [ 72 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 9.09E-4, 0.0, 0.0, -9.09E-4, 1.0, 0.0, 8.26299, -7.67328, 0.312986, 1.0 ]\r
+    }, {\r
+        "name" : "r_toebase_JNT",\r
+        "matrix" : [ 0.0, -0.103501, 0.994629, 0.0, 0.0, 0.994629, 0.103501, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -6.10491, 11.1619, 1.0 ],\r
+        "children" : [ 73 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.0, 0.0, -1.0, 0.0, -0.102591, 0.994724, 0.0, 0.0, 0.994724, 0.102591, 0.0, 0.0, -10.6284, -2.68276, -8.26298, 1.0 ]\r
+    }, {\r
+        "name" : "joint1",\r
+        "matrix" : [ 0.0, 0.0, -1.0, 0.0, -0.108623, 0.994083, 0.0, 0.0, 0.994083, 0.108623, 0.0, 0.0, 5.7477, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "l_upleg_JNT",\r
+        "matrix" : [ 0.969105, -0.243372, 0.040065, 0.0, 0.242338, 0.969759, 0.028984, 0.0, -0.045907, -0.018379, 0.998777, 0.0, 7.51591, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 75 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.999881, -0.015441, 0.0, 0.0, 0.015441, 0.999881, 0.0, -7.50515, -80.0204, 2.6501, 1.0 ]\r
+    }, {\r
+        "name" : "l_leg_JNT",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.993288, -0.115665, 0.0, 0.0, 0.115665, 0.993288, 0.0, 2.16E-4, -37.7436, 2.62906, 1.0 ],\r
+        "children" : [ 76 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.999822, 0.018881, 0.0, 0.0, -0.018881, 0.999822, 0.0, -7.50542, -42.2526, -1.42976, 1.0 ]\r
+    }, {\r
+        "name" : "l_foot_JNT",\r
+        "matrix" : [ 0.996936, 0.072648, -0.029003, 0.0, -0.070636, 0.995367, 0.065233, 0.0, 0.033608, -0.062984, 0.997448, 0.0, 0.0, -34.5752, -1.6048, 1.0 ],\r
+        "children" : [ 77 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 9.11E-4, 0.0, 0.0, -9.11E-4, 1.0, 0.0, -7.50523, -7.67329, 0.31298, 1.0 ]\r
+    }, {\r
+        "name" : "l_toebase_JNT",\r
+        "matrix" : [ 1.9E-4, -0.10218, 0.994766, 0.0, 0.0, 0.994766, 0.10218, 0.0, -1.0, 0.0, 1.81E-4, 0.0, 0.0, -6.10494, 11.1619, 1.0 ],\r
+        "children" : [ 78 ],\r
+        "visible" : true,\r
+        "inverseBindPoseMatrix" : [ 0.0, 0.0, -1.0, 0.0, -0.102591, 0.994724, 0.0, 0.0, 0.994724, 0.102591, 0.0, 0.0, -10.6284, -2.68276, 7.50523, 1.0 ]\r
+    }, {\r
+        "name" : "joint2",\r
+        "matrix" : [ 0.0, 0.0, -1.0, 0.0, -0.104271, 0.994549, 0.0, 0.0, 0.994549, 0.104271, 0.0, 0.0, 5.91715, 0.0, 0.0, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "Model",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 80, 81, 82, 83, 84, 85, 86, 87 ],\r
+        "visible" : true,\r
+        "lightingMode" : "lit-solid"\r
+    }, {\r
+        "name" : "R_New_Eye",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 8,\r
+            "mesh" : 0,\r
+            "shader" : 1\r
+        }\r
+    }, {\r
+        "name" : "L_New_Eye",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 8,\r
+            "mesh" : 1,\r
+            "shader" : 1\r
+        }\r
+    }, {\r
+        "name" : "newhair",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 9,\r
+            "mesh" : 2,\r
+            "shader" : 1\r
+        }\r
+    }, {\r
+        "name" : "OutFit_Bottom",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 10,\r
+            "mesh" : 3,\r
+            "shader" : 1\r
+        }\r
+    }, {\r
+        "name" : "OutFit_Top",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 11,\r
+            "mesh" : 4,\r
+            "shader" : 1\r
+        }\r
+    }, {\r
+        "name" : "Shoes_Shoes01_Female_Adult_Thumbnail_GEO",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 12,\r
+            "mesh" : 5,\r
+            "shader" : 1\r
+        }\r
+    }, {\r
+        "name" : "Head_GEO",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 7,\r
+            "mesh" : 6,\r
+            "shader" : 2\r
+        }\r
+    }, {\r
+        "name" : "Body_GEO",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 6,\r
+            "mesh" : 9,\r
+            "shader" : 2\r
+        }\r
+    }, {\r
+        "name" : "directionalLight1",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 91.3751, 284.323, 1.0 ],\r
+        "visible" : true\r
+    }, {\r
+        "name" : "BackGround",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 5,\r
+            "mesh" : 7,\r
+            "shader" : 4\r
+        }\r
+    }, {\r
+        "name" : "Ground",\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 5,\r
+            "mesh" : 8,\r
+            "shader" : 4\r
+        }\r
+    }, {\r
+        "name" : "Idle",\r
+        "size" : [ 30.0, 30.0 ],\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -82.0, 64.0, -1.0, 1.0 ],\r
+        "behavior" : [ 0 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 1,\r
+            "mesh" : 10,\r
+            "shader" : 3\r
+        }\r
+    }, {\r
+        "name" : "Squat",\r
+        "size" : [ 30.0, 30.0 ],\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -85.0, 94.0, 1.0, 1.0 ],\r
+        "behavior" : [ 1 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 2,\r
+            "mesh" : 10,\r
+            "shader" : 3\r
+        }\r
+    }, {\r
+        "name" : "JumpingJack",\r
+        "size" : [ 30.0, 30.0 ],\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -75.0, 124.0, 0.0, 1.0 ],\r
+        "behavior" : [ 2 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 3,\r
+            "mesh" : 10,\r
+            "shader" : 3\r
+        }\r
+    }, {\r
+        "name" : "Lunge",\r
+        "size" : [ 30.0, 30.0 ],\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -55.0, 154.0, 0.0, 1.0 ],\r
+        "behavior" : [ 3 ],\r
+        "visible" : true,\r
+        "model" : {\r
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+            "material" : 4,\r
+            "mesh" : 10,\r
+            "shader" : 3\r
+        }\r
+    }, {\r
+        "name" : "Backdrop",\r
+        "matrix" : [ 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "children" : [ 89, 90 ],\r
+        "visible" : true,\r
+        "lightingMode" : "lit"\r
+    } ],\r
+    "meshes" : [ {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 0,\r
+            "byteLength" : 2520\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 2520,\r
+            "byteLength" : 3168\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 5688,\r
+            "byteLength" : 3168\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 8856,\r
+            "byteLength" : 2112\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 10968,\r
+            "byteLength" : 3168\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 14136,\r
+            "byteLength" : 4224\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 18360,\r
+            "byteLength" : 4224\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 22584,\r
+            "byteLength" : 2520\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 25104,\r
+            "byteLength" : 3180\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 28284,\r
+            "byteLength" : 3180\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 31464,\r
+            "byteLength" : 2120\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 33584,\r
+            "byteLength" : 3180\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 36764,\r
+            "byteLength" : 4240\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 41004,\r
+            "byteLength" : 4240\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 45244,\r
+            "byteLength" : 25938\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 71182,\r
+            "byteLength" : 34092\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 105274,\r
+            "byteLength" : 34092\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 139366,\r
+            "byteLength" : 22728\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 162094,\r
+            "byteLength" : 34092\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 196186,\r
+            "byteLength" : 45456\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 241642,\r
+            "byteLength" : 45456\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 287098,\r
+            "byteLength" : 5988\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 293086,\r
+            "byteLength" : 8412\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 301498,\r
+            "byteLength" : 8412\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 309910,\r
+            "byteLength" : 5608\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 315518,\r
+            "byteLength" : 8412\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 323930,\r
+            "byteLength" : 11216\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 335146,\r
+            "byteLength" : 11216\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 346362,\r
+            "byteLength" : 3720\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 350082,\r
+            "byteLength" : 5004\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 355086,\r
+            "byteLength" : 5004\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 360090,\r
+            "byteLength" : 3336\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 363426,\r
+            "byteLength" : 5004\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 368430,\r
+            "byteLength" : 6672\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 375102,\r
+            "byteLength" : 6672\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 381774,\r
+            "byteLength" : 5520\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 387294,\r
+            "byteLength" : 7284\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 394578,\r
+            "byteLength" : 7284\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 401862,\r
+            "byteLength" : 4856\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 406718,\r
+            "byteLength" : 7284\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 414002,\r
+            "byteLength" : 9712\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 423714,\r
+            "byteLength" : 9712\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 433426,\r
+            "byteLength" : 34524\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 467950,\r
+            "byteLength" : 37824\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 505774,\r
+            "byteLength" : 37824\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 543598,\r
+            "byteLength" : 25216\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 568814,\r
+            "byteLength" : 37824\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 606638,\r
+            "byteLength" : 50432\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 657070,\r
+            "byteLength" : 50432\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 31,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 707502,\r
+            "byteLength" : 360\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 707862,\r
+            "byteLength" : 732\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 708594,\r
+            "byteLength" : 732\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 709326,\r
+            "byteLength" : 488\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 709814,\r
+            "byteLength" : 732\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 31,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 710546,\r
+            "byteLength" : 12\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 710558,\r
+            "byteLength" : 48\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 710606,\r
+            "byteLength" : 48\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 710654,\r
+            "byteLength" : 32\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 710686,\r
+            "byteLength" : 48\r
+        }\r
+    }, {\r
+        "uri" : "exercise/model.dae.bin",\r
+        "attributes" : 223,\r
+        "primitive" : "TRIANGLES",\r
+        "indices" : {\r
+            "byteOffset" : 710734,\r
+            "byteLength" : 24312\r
+        },\r
+        "positions" : {\r
+            "byteOffset" : 735046,\r
+            "byteLength" : 33000\r
+        },\r
+        "normals" : {\r
+            "byteOffset" : 768046,\r
+            "byteLength" : 33000\r
+        },\r
+        "textures" : {\r
+            "byteOffset" : 801046,\r
+            "byteLength" : 22000\r
+        },\r
+        "tangents" : {\r
+            "byteOffset" : 823046,\r
+            "byteLength" : 33000\r
+        },\r
+        "skeleton" : 0,\r
+        "joints0" : {\r
+            "byteOffset" : 856046,\r
+            "byteLength" : 44000\r
+        },\r
+        "weights0" : {\r
+            "byteOffset" : 900046,\r
+            "byteLength" : 44000\r
+        }\r
+    }, {\r
+        "uri" : "quad",\r
+        "attributes" : 0,\r
+        "primitive" : "TRIANGLES"\r
+    } ],\r
+    "cameras" : [ {\r
+        "near" : 2.5,\r
+        "far" : 1000.0,\r
+        "matrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.9138, 5.0, 1.0 ],\r
+        "fov" : 37.8492\r
+    } ],\r
+    "lights" : [ {\r
+        "matrix" : [ 0.8950600624084473, 0.0914330929517746, 0.4364715814590454, 0.0, 0.3676385283470154, 0.4026888310909271, -0.8382623195648193, 0.0, -0.25240713357925415, 0.9107588529586792, 0.3268163800239563, 0.0, 0.0, 0.0, -1.0, 1.0 ],\r
+        "color" : [ 1.0, 1.0, 1.0 ],\r
+        "intensity" : 1.0,\r
+        "shadowMapSize" : 256,\r
+        "orthographicSize" : 4.2760005,\r
+        "shadowIntensity" : 1.0\r
+    } ],\r
+    "materials" : [ {\r
+        "name" : "No name",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Icons\\Icon_Idle.png",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : false,\r
+        "albedoMap" : "exercise/Icons/Icon_Idle.png"\r
+    }, {\r
+        "name" : "Icons\\Icon_Squat.png",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : false,\r
+        "albedoMap" : "exercise/Icons/Icon_Squat.png"\r
+    }, {\r
+        "name" : "Icons\\Icon_JJ.png",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : false,\r
+        "albedoMap" : "exercise/Icons/Icon_JJ.png"\r
+    }, {\r
+        "name" : "Icons\\Icon_Lunge.png",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : false,\r
+        "albedoMap" : "exercise/Icons/Icon_Lunge.png"\r
+    }, {\r
+        "name" : "Background",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/BG_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/BG_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Body",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/Body_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/Body_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "subsurfaceMap" : "exercise/Textures/Body_Female_Asian_Adult_SubsurfaceColor.png",\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Head",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/Head_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/Head_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "subsurfaceMap" : "exercise/Textures/Head_Female_SubsurfaceColor.png",\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Eye",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/Eye_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/Eye_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Hair",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/Hair_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/Hair_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Bottom outfit",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/FitBot_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/FitBot_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Top outfit",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/FitTop_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/FitTop_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    }, {\r
+        "name" : "Shoe",\r
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],\r
+        "normalRoughnessMap" : "exercise/Textures/Shoe_NormalRoughness.png",\r
+        "albedoMetallicMap" : "exercise/Textures/Shoe_AlbedoMetallic.png",\r
+        "roughness" : 1.0,\r
+        "metallic" : 1.0,\r
+        "mipmap" : true,\r
+        "environment" : 1\r
+    } ],\r
+    "environment" : [ {\r
+        "cubeInitialOrientation" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "iblIntensity" : 1.0\r
+    }, {\r
+        "cubeSpecular" : "Studio/Radiance.ktx",\r
+        "cubeDiffuse" : "Studio/Irradiance.ktx",\r
+        "cubeInitialOrientation" : [ 0.6716271638870239, 0.07979151606559753, -0.7365801334381104, 0.0, 0.07979151606559753, 0.9806114435195923, 0.17898204922676086, 0.0, 0.7365801334381104, -0.17898204922676086, 0.6522386074066162, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "iblIntensity" : 0.75\r
+    } ],\r
+    "shaders" : [ {\r
+        "vertex" : "dli_pbr.vsh",\r
+        "fragment" : "dli_pbr.fsh",\r
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",\r
+        "uCubeMatrix" : [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],\r
+        "uMaxLOD" : 8\r
+    }, {\r
+        "vertex" : "dli_pbr.vsh",\r
+        "fragment" : "dli_pbr.fsh",\r
+        "hints": [ "MODIFIES_GEOMETRY" ],\r
+        "defines" : [ "LIT", "SKINNING" ],\r
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",\r
+        "uCubeMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "uMaxLOD" : 6\r
+    }, {\r
+        "vertex" : "dli_pbr.vsh",\r
+        "fragment" : "dli_pbr.fsh",\r
+        "hints": [ "MODIFIES_GEOMETRY" ],\r
+        "defines" : [ "LIT", "SKINNING", "SSS" ],\r
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",\r
+        "uCubeMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "uMaxLOD" : 6\r
+    }, {\r
+        "vertex" : "dli_pbr.vsh",\r
+        "fragment" : "dli_pbr.fsh",\r
+        "rendererState" : "DEPTH_TEST|ALPHA_BLEND",\r
+        "uCubeMatrix" : [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],\r
+        "uTilt" : [ 0.0, 0.0 ]\r
+    }, {\r
+        "vertex" : "dli_pbr.vsh",\r
+        "fragment" : "dli_pbr.fsh",\r
+        "defines" : [ "LIT", "SHADOW" ],\r
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",\r
+        "uCubeMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],\r
+        "uMaxLOD" : 6\r
+    } ],\r
+    "animations" : [ {\r
+        "name" : "idleClip",\r
+        "loopCount" : 0,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 3024,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 6048,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 9072,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 12096,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 15120,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 18144,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 20592,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 23616,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 26640,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 29664,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 32688,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 35712,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 38736,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 41760,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 44784,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 47808,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 50832,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-animation.ani",\r
+                "byteOffset" : 53856,\r
+                "numKeys" : 144\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 6.0\r
+            },\r
+            "relative" : false\r
+        } ]\r
+    }, {\r
+        "name" : "squatClip_0",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 1764,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 3192,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 4956,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 6720,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 8484,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 10248,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hair_02_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 12012,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hair_03_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-0.ani",\r
+                "byteOffset" : 13776,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 1 ]\r
+    }, {\r
+        "name" : "squatClip_1",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 1596,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 3192,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 4788,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 6384,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 7980,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 9576,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 11172,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 12768,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 14364,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 15656,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 17252,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 18848,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 20444,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 22040,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 23636,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 25232,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 26828,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 28424,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 30020,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 31616,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 33212,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 34808,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 36404,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 38000,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 39596,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 41192,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 42788,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-animation-1.ani",\r
+                "byteOffset" : 44384,\r
+                "numKeys" : 76\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.16667\r
+            },\r
+            "relative" : false\r
+        } ]\r
+    }, {\r
+        "name" : "jumpingJackClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 630,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 1140,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 1770,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 2400,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 3030,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 3660,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 4290,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 4920,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 5550,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 6180,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 6810,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 7440,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 8070,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 8700,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 9330,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 9960,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 10590,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 11220,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 11850,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 12480,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 13110,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 13740,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 14370,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 15000,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 15630,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 16260,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 16890,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 17520,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 18150,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 18780,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 19410,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 20040,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 20670,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 21300,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 21930,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 22560,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 23190,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 23820,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 24450,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 25080,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 25710,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 26340,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 26970,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 27600,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 28230,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 28860,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 29490,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 30120,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 30750,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 31380,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-animation.ani",\r
+                "byteOffset" : 32010,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 4 ]\r
+    }, {\r
+        "name" : "lungeClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 1649,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 3686,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 5723,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 7760,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 9797,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 11834,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 13871,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 15908,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 17945,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 19982,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 22019,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 24056,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 26093,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 28130,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 30167,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 32204,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 34241,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 36278,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 38315,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 40352,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 42389,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 44426,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 46075,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 48112,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 50149,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 52186,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 54223,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 56260,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 58297,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 60334,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 62371,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 64408,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 66445,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-animation.ani",\r
+                "byteOffset" : 68482,\r
+                "numKeys" : 97\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 4.04167\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 7 ]\r
+    }, {\r
+        "name" : "idleToSquatClip_0",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 1932,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 3496,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 5428,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 6992,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 8924,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 10856,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 12788,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 14720,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 16652,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 18584,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 20516,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 22448,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 24380,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 26312,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 28244,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 30176,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 32108,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 34040,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 35972,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 37904,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 39836,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 41768,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 43700,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 45632,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 47564,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 49496,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 51060,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 52992,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 54924,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 56856,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 58788,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 60720,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 62652,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 64584,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 66516,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 68448,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 70380,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 72312,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 74244,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 76176,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 78108,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 80040,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 81972,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 83904,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 85836,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 87768,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 89700,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 91632,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 93564,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 95496,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 97428,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 99360,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 101292,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 103224,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 105156,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-0.ani",\r
+                "byteOffset" : 107088,\r
+                "numKeys" : 92\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.83333\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 0 ]\r
+    }, {\r
+        "name" : "idleToSquatClip_1",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hair_02_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-1.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hair_03_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-squat-animation-1.ani",\r
+                "byteOffset" : 1764,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        } ]\r
+    }, {\r
+        "name" : "squatToIdleClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 1806,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 3268,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 5074,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 6880,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 8686,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 10492,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 12298,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 14104,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 15910,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 17716,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 19522,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 21328,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 23134,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 24940,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 26746,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 28552,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 30358,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 32164,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 33970,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 35776,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 37582,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 39388,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 41194,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 43000,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 44462,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 46268,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 48074,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 49880,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 51686,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 53492,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 55298,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 57104,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 58910,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 60716,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 62522,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 64328,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 66134,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 67940,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 69746,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 71552,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 73358,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 75164,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 76970,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 78776,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hair_02_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 80582,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hair_03_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 82388,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 84194,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 86000,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 87806,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 89612,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 91418,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 93224,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 95030,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 96836,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 98642,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-idle-animation.ani",\r
+                "byteOffset" : 100448,\r
+                "numKeys" : 86\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.58333\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 2 ]\r
+    }, {\r
+        "name" : "idleToJumpingJackClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 1365,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 2470,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 3835,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 5200,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 6565,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 7930,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 9295,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 10660,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 12025,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 13390,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 14755,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 16120,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 17485,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 18850,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 20215,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 21580,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 22945,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 24310,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 25675,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 27040,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 28405,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 29770,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 31135,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 32500,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 33865,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 34970,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 36335,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 37700,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 39065,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 40430,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 41795,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 43160,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 44525,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 45890,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 47255,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 48620,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 49985,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 51350,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 52715,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 54080,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 55445,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 56810,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 58175,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 59540,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 60905,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 62270,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 63635,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 65000,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 66365,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 67730,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 69095,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 70460,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 71825,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 73190,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 74555,\r
+                "numKeys" : 65\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.70833\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 3 ]\r
+    }, {\r
+        "name" : "jumpingJackToIdleClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 1491,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 2698,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 4189,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 5680,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 7171,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 8662,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 10153,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 11644,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 13135,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 14626,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 16117,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 17608,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 19099,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 20590,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 22081,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 23572,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 25063,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 26554,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 28045,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 29536,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 31027,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 32518,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 34009,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 35500,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 36707,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 38198,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 39689,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 41180,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 42671,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 44162,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 45653,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 47144,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 48635,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 50126,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 51617,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 53108,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 54599,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 56090,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 57581,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 59072,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 60563,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 62054,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 63545,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 65036,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 66527,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 68018,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 69509,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 71000,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 72491,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 73982,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 75473,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 76964,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 78455,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-idle-animation.ani",\r
+                "byteOffset" : 79946,\r
+                "numKeys" : 71\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 2.95833\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 5 ]\r
+    }, {\r
+        "name" : "idleToLungeClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 1764,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 3192,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 4956,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 6384,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 8148,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 9912,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 11676,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 13440,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 15204,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 16968,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 18732,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 20496,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 22260,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 24024,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 25788,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 27552,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 29316,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 31080,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 32844,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 34608,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 36372,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 38136,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 39900,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 41664,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 43428,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 45192,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 46620,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 48384,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 50148,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 51912,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 53676,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 55440,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 57204,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 58968,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 60732,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 62496,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 64260,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 66024,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 67788,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 69552,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 71316,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 73080,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 74844,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 76608,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 78372,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 80136,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 81900,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 83664,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 85428,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 87192,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 88956,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 90720,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 92484,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 94248,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/idle-to-lunge-animation.ani",\r
+                "byteOffset" : 96012,\r
+                "numKeys" : 84\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.5\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 6 ]\r
+    }, {\r
+        "name" : "lungeToIdleClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 1701,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 3078,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 4779,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 6480,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_shoulder_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 8181,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 9882,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 11583,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 13284,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 14985,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 16686,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 18387,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 20088,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 21789,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 23490,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 25191,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 26892,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 28593,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 30294,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 31995,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 33696,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 35397,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 37098,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 38799,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 40500,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 41877,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 43578,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 45279,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 46980,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 48681,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 50382,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 52083,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 53784,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 55485,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 57186,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 58887,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 60588,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 62289,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 63990,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 65691,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 67392,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 69093,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 70794,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 72495,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 74196,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_eye_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 75897,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 77598,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 79299,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 81000,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 82701,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 84402,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 86103,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 87804,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-idle-animation.ani",\r
+                "byteOffset" : 89505,\r
+                "numKeys" : 81\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 3.375\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 8 ]\r
+    }, {\r
+        "name" : "jumpingJackToLungeClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 756,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 1368,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 2124,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 2736,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 3492,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 4248,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 5004,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 5760,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 6516,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 7272,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 8028,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 8784,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 9540,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 10296,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 11052,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 11808,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 12564,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 13320,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 14076,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 14832,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 15588,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 16344,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 17100,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 17856,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 18468,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 19224,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 19980,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 20736,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 21492,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 22248,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 23004,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 23760,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 24516,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 25272,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 26028,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 26784,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 27540,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 28296,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 29052,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 29808,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 30564,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 31320,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 32076,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 32832,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 33588,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 34344,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 35100,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 35856,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 36612,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 37368,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-lunge-animation.ani",\r
+                "byteOffset" : 38124,\r
+                "numKeys" : 36\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.5\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 9 ]\r
+    }, {\r
+        "name" : "jumpingJackToSquatClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 525,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 950,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 1475,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 2000,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 2525,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 3050,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 3575,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 4100,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 4625,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 5150,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 5675,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 6200,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 6725,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 7250,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 7775,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 8300,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 8825,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 9350,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 9875,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 10400,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 10925,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 11450,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 11975,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/jumping-jack-to-squat-animation.ani",\r
+                "byteOffset" : 12500,\r
+                "numKeys" : 25\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.04167\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 10 ]\r
+    }, {\r
+        "name" : "lungeToJumpingJackClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 861,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 1558,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 2419,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 3116,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 3977,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 4838,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 5699,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 6560,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 7421,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 8282,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 9143,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 10004,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 10865,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 11726,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 12587,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 13448,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 14309,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 15170,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 16031,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 16892,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 17753,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 18614,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 19475,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 20336,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 21033,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 21894,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 22755,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 23616,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 24477,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 25338,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 26199,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 27060,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 27921,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 28782,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 29643,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 30504,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 31365,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 32226,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 33087,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 33948,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 34809,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 35670,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 36531,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 37392,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 38253,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 39114,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 39975,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 40836,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 41697,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 42558,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 43419,\r
+                "numKeys" : 41\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.70833\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 11 ]\r
+    }, {\r
+        "name" : "lungeToSquatClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 546,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 988,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 1534,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 1976,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 2522,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 3068,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 3614,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 4160,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 4706,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 5252,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 5798,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 6344,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 6890,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 7436,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 7982,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 8528,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 9074,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 9620,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 10166,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 10712,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 11258,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 11804,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 12350,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 12896,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 13338,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 13884,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 14430,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 14976,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 15522,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 16068,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 16614,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 17160,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 17706,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 18252,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 18798,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 19344,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 19890,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 20436,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 20982,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 21528,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 22074,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 22620,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 23166,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 23712,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 24258,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 24804,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 25350,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 25896,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 26442,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 26988,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/lunge-to-squat-animation.ani",\r
+                "byteOffset" : 27534,\r
+                "numKeys" : 26\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.08333\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 12 ]\r
+    }, {\r
+        "name" : "squatToJumpingJackClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 630,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 1140,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 1770,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 2400,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 3030,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 3660,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 4290,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 4920,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 5550,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_shoulder_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 6180,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 6690,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 7320,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 7950,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 8580,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 9210,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 9840,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 10470,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 11100,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 11730,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 12360,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 12990,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 13620,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 14250,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 14880,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 15510,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-jumping-jack-animation.ani",\r
+                "byteOffset" : 16140,\r
+                "numKeys" : 30\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.25\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 13 ]\r
+    }, {\r
+        "name" : "squatToLungeClip",\r
+        "loopCount" : 1,\r
+        "duration" : 0.0,\r
+        "endAction" : "BAKE",\r
+        "disconnectAction" : "BAKE",\r
+        "properties" : [ {\r
+            "node" : "hips_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 0,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "hips_JNT",\r
+            "property" : "position",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 504,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 912,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 1416,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "spine2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 1920,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 2424,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 2928,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 3432,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 3936,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 4440,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 4944,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 5448,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 5952,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 6456,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 6960,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 7464,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 7968,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 8472,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 8976,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 9480,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 9984,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 10488,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 10992,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_arm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 11496,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_forearm_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 12000,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_hand_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 12504,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 13008,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 13512,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handThumb3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 14016,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 14520,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 15024,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handRing3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 15528,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 16032,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 16536,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handPinky3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 17040,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 17544,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 18048,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handMiddle3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 18552,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex1_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 19056,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex2_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 19560,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_handIndex3_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 20064,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "neck_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 20568,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "head_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 21072,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 21576,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 22080,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 22584,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "r_toebase_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 23088,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_upleg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 23592,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_leg_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 24096,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        }, {\r
+            "node" : "l_foot_JNT",\r
+            "property" : "orientation",\r
+            "keyFramesBin" : {\r
+                "url" : "exercise/squat-to-lunge-animation.ani",\r
+                "byteOffset" : 24600,\r
+                "numKeys" : 24\r
+            },\r
+            "alphaFunction" : "DEFAULT",\r
+            "timePeriod" : {\r
+                "delay" : 0.0,\r
+                "duration" : 1.0\r
+            },\r
+            "relative" : false\r
+        } ],\r
+        "finishedActions" : [ 14 ]\r
+    } ],\r
+    "animationGroups" : [ {\r
+        "name" : "Idle",\r
+        "animations" : [ "idleClip" ]\r
+    }, {\r
+        "name" : "Squat",\r
+        "animations" : [ "squatClip_0", "squatClip_1" ]\r
+    }, {\r
+        "name" : "JumpingJack",\r
+        "animations" : [ "jumpingJackClip" ]\r
+    }, {\r
+        "name" : "Lunge",\r
+        "animations" : [ "lungeClip" ]\r
+    }, {\r
+        "name" : "IdleToSquat",\r
+        "animations" : [ "idleToSquatClip_0", "idleToSquatClip_1" ]\r
+    }, {\r
+        "name" : "SquatToIdle",\r
+        "animations" : [ "squatToIdleClip" ]\r
+    }, {\r
+        "name" : "IdleToJumpingJack",\r
+        "animations" : [ "idleToJumpingJackClip" ]\r
+    }, {\r
+        "name" : "JumpingJackToIdle",\r
+        "animations" : [ "jumpingJackToIdleClip" ]\r
+    }, {\r
+        "name" : "IdleToLunge",\r
+        "animations" : [ "idleToLungeClip" ]\r
+    }, {\r
+        "name" : "LungeToIdle",\r
+        "animations" : [ "lungeToIdleClip" ]\r
+    }, {\r
+        "name" : "JumpingJackToLunge",\r
+        "animations" : [ "jumpingJackToLungeClip" ]\r
+    }, {\r
+        "name" : "JumpingJackToSquat",\r
+        "animations" : [ "jumpingJackToSquatClip" ]\r
+    }, {\r
+        "name" : "LungeToJumpingJack",\r
+        "animations" : [ "lungeToJumpingJackClip" ]\r
+    }, {\r
+        "name" : "LungeToSquat",\r
+        "animations" : [ "lungeToSquatClip" ]\r
+    }, {\r
+        "name" : "SquatToJumpingJack",\r
+        "animations" : [ "squatToJumpingJackClip" ]\r
+    }, {\r
+        "name" : "SquatToLunge",\r
+        "animations" : [ "squatToLungeClip" ]\r
+    } ],\r
+    "skeletons" : [ {\r
+        "node" : "hips_JNT"\r
+    } ]\r
+}\r
diff --git a/automated-tests/resources/exercise/Icons/Icon_Idle.png b/automated-tests/resources/exercise/Icons/Icon_Idle.png
new file mode 100644 (file)
index 0000000..ee10734
Binary files /dev/null and b/automated-tests/resources/exercise/Icons/Icon_Idle.png differ
diff --git a/automated-tests/resources/exercise/Icons/Icon_JJ.png b/automated-tests/resources/exercise/Icons/Icon_JJ.png
new file mode 100644 (file)
index 0000000..1c690f5
Binary files /dev/null and b/automated-tests/resources/exercise/Icons/Icon_JJ.png differ
diff --git a/automated-tests/resources/exercise/Icons/Icon_Lunge.png b/automated-tests/resources/exercise/Icons/Icon_Lunge.png
new file mode 100644 (file)
index 0000000..8853b14
Binary files /dev/null and b/automated-tests/resources/exercise/Icons/Icon_Lunge.png differ
diff --git a/automated-tests/resources/exercise/Icons/Icon_Squat.png b/automated-tests/resources/exercise/Icons/Icon_Squat.png
new file mode 100644 (file)
index 0000000..f4f8ce3
Binary files /dev/null and b/automated-tests/resources/exercise/Icons/Icon_Squat.png differ
diff --git a/automated-tests/resources/exercise/Textures/BG_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/BG_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..45489d2
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/BG_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/BG_NormalRoughness.png b/automated-tests/resources/exercise/Textures/BG_NormalRoughness.png
new file mode 100644 (file)
index 0000000..52cb66d
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/BG_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/Body_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/Body_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..d8211a6
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Body_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/Body_Female_Asian_Adult_SubsurfaceColor.png b/automated-tests/resources/exercise/Textures/Body_Female_Asian_Adult_SubsurfaceColor.png
new file mode 100644 (file)
index 0000000..8df1878
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Body_Female_Asian_Adult_SubsurfaceColor.png differ
diff --git a/automated-tests/resources/exercise/Textures/Body_NormalRoughness.png b/automated-tests/resources/exercise/Textures/Body_NormalRoughness.png
new file mode 100644 (file)
index 0000000..91d02cb
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Body_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/Eye_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/Eye_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..0137f24
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Eye_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/Eye_NormalRoughness.png b/automated-tests/resources/exercise/Textures/Eye_NormalRoughness.png
new file mode 100644 (file)
index 0000000..9d5971b
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Eye_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/FitBot_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/FitBot_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..d70a3de
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/FitBot_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/FitBot_NormalRoughness.png b/automated-tests/resources/exercise/Textures/FitBot_NormalRoughness.png
new file mode 100644 (file)
index 0000000..fd47924
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/FitBot_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/FitTop_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/FitTop_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..f19e93c
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/FitTop_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/FitTop_NormalRoughness.png b/automated-tests/resources/exercise/Textures/FitTop_NormalRoughness.png
new file mode 100644 (file)
index 0000000..6c3e743
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/FitTop_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/Hair_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/Hair_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..8b96834
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Hair_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/Hair_NormalRoughness.png b/automated-tests/resources/exercise/Textures/Hair_NormalRoughness.png
new file mode 100644 (file)
index 0000000..9d643ab
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Hair_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/Head_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/Head_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..568a115
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Head_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/Head_Female_SubsurfaceColor.png b/automated-tests/resources/exercise/Textures/Head_Female_SubsurfaceColor.png
new file mode 100644 (file)
index 0000000..609ce5b
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Head_Female_SubsurfaceColor.png differ
diff --git a/automated-tests/resources/exercise/Textures/Head_NormalRoughness.png b/automated-tests/resources/exercise/Textures/Head_NormalRoughness.png
new file mode 100644 (file)
index 0000000..b2eb952
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Head_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/Textures/Shoe_AlbedoMetallic.png b/automated-tests/resources/exercise/Textures/Shoe_AlbedoMetallic.png
new file mode 100644 (file)
index 0000000..6bf07f9
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Shoe_AlbedoMetallic.png differ
diff --git a/automated-tests/resources/exercise/Textures/Shoe_NormalRoughness.png b/automated-tests/resources/exercise/Textures/Shoe_NormalRoughness.png
new file mode 100644 (file)
index 0000000..f953ec0
Binary files /dev/null and b/automated-tests/resources/exercise/Textures/Shoe_NormalRoughness.png differ
diff --git a/automated-tests/resources/exercise/idle-animation.ani b/automated-tests/resources/exercise/idle-animation.ani
new file mode 100644 (file)
index 0000000..02f76fd
Binary files /dev/null and b/automated-tests/resources/exercise/idle-animation.ani differ
diff --git a/automated-tests/resources/exercise/idle-to-jumping-jack-animation.ani b/automated-tests/resources/exercise/idle-to-jumping-jack-animation.ani
new file mode 100644 (file)
index 0000000..74b8647
Binary files /dev/null and b/automated-tests/resources/exercise/idle-to-jumping-jack-animation.ani differ
diff --git a/automated-tests/resources/exercise/idle-to-lunge-animation.ani b/automated-tests/resources/exercise/idle-to-lunge-animation.ani
new file mode 100644 (file)
index 0000000..81743dd
Binary files /dev/null and b/automated-tests/resources/exercise/idle-to-lunge-animation.ani differ
diff --git a/automated-tests/resources/exercise/idle-to-squat-animation-0.ani b/automated-tests/resources/exercise/idle-to-squat-animation-0.ani
new file mode 100644 (file)
index 0000000..f7d792c
Binary files /dev/null and b/automated-tests/resources/exercise/idle-to-squat-animation-0.ani differ
diff --git a/automated-tests/resources/exercise/idle-to-squat-animation-1.ani b/automated-tests/resources/exercise/idle-to-squat-animation-1.ani
new file mode 100644 (file)
index 0000000..e0ec040
Binary files /dev/null and b/automated-tests/resources/exercise/idle-to-squat-animation-1.ani differ
diff --git a/automated-tests/resources/exercise/jumping-jack-animation.ani b/automated-tests/resources/exercise/jumping-jack-animation.ani
new file mode 100644 (file)
index 0000000..8bd679d
Binary files /dev/null and b/automated-tests/resources/exercise/jumping-jack-animation.ani differ
diff --git a/automated-tests/resources/exercise/jumping-jack-to-idle-animation.ani b/automated-tests/resources/exercise/jumping-jack-to-idle-animation.ani
new file mode 100644 (file)
index 0000000..6d143e1
Binary files /dev/null and b/automated-tests/resources/exercise/jumping-jack-to-idle-animation.ani differ
diff --git a/automated-tests/resources/exercise/jumping-jack-to-lunge-animation.ani b/automated-tests/resources/exercise/jumping-jack-to-lunge-animation.ani
new file mode 100644 (file)
index 0000000..08c588b
Binary files /dev/null and b/automated-tests/resources/exercise/jumping-jack-to-lunge-animation.ani differ
diff --git a/automated-tests/resources/exercise/jumping-jack-to-squat-animation.ani b/automated-tests/resources/exercise/jumping-jack-to-squat-animation.ani
new file mode 100644 (file)
index 0000000..ae66e77
Binary files /dev/null and b/automated-tests/resources/exercise/jumping-jack-to-squat-animation.ani differ
diff --git a/automated-tests/resources/exercise/lunge-animation.ani b/automated-tests/resources/exercise/lunge-animation.ani
new file mode 100644 (file)
index 0000000..3912665
Binary files /dev/null and b/automated-tests/resources/exercise/lunge-animation.ani differ
diff --git a/automated-tests/resources/exercise/lunge-to-idle-animation.ani b/automated-tests/resources/exercise/lunge-to-idle-animation.ani
new file mode 100644 (file)
index 0000000..d88c844
Binary files /dev/null and b/automated-tests/resources/exercise/lunge-to-idle-animation.ani differ
diff --git a/automated-tests/resources/exercise/lunge-to-jumping-jack-animation.ani b/automated-tests/resources/exercise/lunge-to-jumping-jack-animation.ani
new file mode 100644 (file)
index 0000000..118ffa1
Binary files /dev/null and b/automated-tests/resources/exercise/lunge-to-jumping-jack-animation.ani differ
diff --git a/automated-tests/resources/exercise/lunge-to-squat-animation.ani b/automated-tests/resources/exercise/lunge-to-squat-animation.ani
new file mode 100644 (file)
index 0000000..6d435de
Binary files /dev/null and b/automated-tests/resources/exercise/lunge-to-squat-animation.ani differ
diff --git a/automated-tests/resources/exercise/model.dae.bin b/automated-tests/resources/exercise/model.dae.bin
new file mode 100644 (file)
index 0000000..c894ae9
Binary files /dev/null and b/automated-tests/resources/exercise/model.dae.bin differ
diff --git a/automated-tests/resources/exercise/squat-animation-0.ani b/automated-tests/resources/exercise/squat-animation-0.ani
new file mode 100644 (file)
index 0000000..435aaeb
Binary files /dev/null and b/automated-tests/resources/exercise/squat-animation-0.ani differ
diff --git a/automated-tests/resources/exercise/squat-animation-1.ani b/automated-tests/resources/exercise/squat-animation-1.ani
new file mode 100644 (file)
index 0000000..6fd09cb
Binary files /dev/null and b/automated-tests/resources/exercise/squat-animation-1.ani differ
diff --git a/automated-tests/resources/exercise/squat-to-idle-animation.ani b/automated-tests/resources/exercise/squat-to-idle-animation.ani
new file mode 100644 (file)
index 0000000..1bfef9a
Binary files /dev/null and b/automated-tests/resources/exercise/squat-to-idle-animation.ani differ
diff --git a/automated-tests/resources/exercise/squat-to-jumping-jack-animation.ani b/automated-tests/resources/exercise/squat-to-jumping-jack-animation.ani
new file mode 100644 (file)
index 0000000..82316cb
Binary files /dev/null and b/automated-tests/resources/exercise/squat-to-jumping-jack-animation.ani differ
diff --git a/automated-tests/resources/exercise/squat-to-lunge-animation.ani b/automated-tests/resources/exercise/squat-to-lunge-animation.ani
new file mode 100644 (file)
index 0000000..c967b9a
Binary files /dev/null and b/automated-tests/resources/exercise/squat-to-lunge-animation.ani differ
diff --git a/automated-tests/resources/forest_irradiance.ktx b/automated-tests/resources/forest_irradiance.ktx
new file mode 100644 (file)
index 0000000..c6b2332
Binary files /dev/null and b/automated-tests/resources/forest_irradiance.ktx differ
diff --git a/automated-tests/resources/forest_radiance.ktx b/automated-tests/resources/forest_radiance.ktx
new file mode 100644 (file)
index 0000000..38f7f1a
Binary files /dev/null and b/automated-tests/resources/forest_radiance.ktx differ
diff --git a/automated-tests/resources/invalid.gltf b/automated-tests/resources/invalid.gltf
new file mode 100644 (file)
index 0000000..a9e1c8a
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "error": yes
+}
diff --git a/automated-tests/resources/morph.dli b/automated-tests/resources/morph.dli
new file mode 100644 (file)
index 0000000..9f9a5a2
--- /dev/null
@@ -0,0 +1,280 @@
+{
+    "metadata" : [ {
+        "key" : "clock-type",
+        "value" : "com.samsung.watchface-01"
+    }, {
+        "key" : "tickpersecond",
+        "value" : "1"
+    }, {
+        "key" : "preview_time",
+        "value" : "10:08:32"
+    }, {
+        "key" : "tilt-mode",
+        "value" : "light"
+    } ],
+    "asset" : {
+        "version" : "1.0"
+    },
+    "scene" : 0,
+    "scenes" : [ {
+        "nodes" : [ 0 ]
+    } ],
+    "nodes" : [ {
+        "name" : "HeadTest_002",
+        "matrix" : [ 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "children" : [ 1, 2 ],
+        "visible" : true,
+        "lightingMode" : "unlit"
+    }, {
+        "name" : "head",
+        "matrix" : [ 0.819152044288992, 0.0, 0.5735764363510462, 0.0, 0.0, 1.0, 0.0, 0.0, -0.5735764363510462, 0.0, 0.819152044288992, 0.0, 0.0, -143.995, -1.1208, 1.0 ],
+        "behavior" : [ 0 ],
+        "visible" : true,
+        "lightingMode" : "lit-solid",
+        "model" : {
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],
+            "material" : 0,
+            "mesh" : 0,
+            "shader" : 3
+        }
+    }, {
+        "name" : "Cube",
+        "matrix" : [ 25.98076211353316, 0.0, -15.0, 0.0, 0.0, 30.0, 0.0, 0.0, 15.0, 0.0, 25.98076211353316, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "visible" : true,
+        "lightingMode" : "lit",
+        "model" : {
+            "color" : [ 1.0, 1.0, 1.0, 1.0 ],
+            "material" : 0,
+            "mesh" : 1,
+            "shader" : 4
+        }
+    } ],
+    "meshes" : [ {
+        "uri" : "morph/HeadTest_002.dae.bin",
+        "attributes" : 31,
+        "primitive" : "TRIANGLES",
+        "indices" : {
+            "byteOffset" : 0,
+            "byteLength" : 34524
+        },
+        "positions" : {
+            "byteOffset" : 34524,
+            "byteLength" : 37812
+        },
+        "normals" : {
+            "byteOffset" : 72336,
+            "byteLength" : 37812
+        },
+        "textures" : {
+            "byteOffset" : 110148,
+            "byteLength" : 25208
+        },
+        "tangents" : {
+            "byteOffset" : 135356,
+            "byteLength" : 37812
+        },
+        "blendShapeHeader" : {
+            "version" : "1.0",
+            "byteOffset" : 173168,
+            "byteLength" : 4
+        },
+        "blendShapes" : [ {
+            "name" : "Shape_01MeshMesh",
+            "weight" : 0.0,
+            "positions" : {
+                "byteOffset" : 173172,
+                "byteLength" : 37812
+            },
+            "normals" : {
+                "byteOffset" : 210984,
+                "byteLength" : 37812
+            }
+        }, {
+            "name" : "Shape_02MeshMesh",
+            "weight" : 0.0,
+            "positions" : {
+                "byteOffset" : 248796,
+                "byteLength" : 37812
+            },
+            "normals" : {
+                "byteOffset" : 286608,
+                "byteLength" : 37812
+            }
+        }, {
+            "name" : "Shape_03MeshMesh",
+            "weight" : 0.0,
+            "positions" : {
+                "byteOffset" : 324420,
+                "byteLength" : 37812
+            },
+            "normals" : {
+                "byteOffset" : 362232,
+                "byteLength" : 37812
+            }
+        } ]
+    }, {
+        "uri" : "morph/cube.gltf.bin",
+        "attributes" : 31,
+        "primitive" : "TRIANGLES",
+        "indices" : {
+            "byteOffset" : 0,
+            "byteLength" : 72
+        },
+        "positions" : {
+            "byteOffset" : 72,
+            "byteLength" : 288
+        },
+        "normals" : {
+            "byteOffset" : 360,
+            "byteLength" : 288
+        },
+        "textures" : {
+            "byteOffset" : 648,
+            "byteLength" : 192
+        },
+        "tangents" : {
+            "byteOffset" : 840,
+            "byteLength" : 288
+        }
+    } ],
+    "cameras" : [ {
+        "near" : 0.1,
+        "far" : 10000.0,
+        "matrix" : [ 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.767773, 1.0 ],
+        "fov" : 54.4321
+    } ],
+    "lights" : [ {
+        "matrix" : [ 0.4999999403953552, 0.0, 0.8660255074501038, 0.0, 0.0, 1.0, 0.0, 0.0, -0.8660255074501038, 0.0, 0.4999999403953552, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "color" : [ 1.0, 1.0, 1.0 ],
+        "intensity" : 1.0,
+        "shadowMapSize" : 1024,
+        "orthographicSize" : 1.0,
+        "shadowIntensity" : 1.0
+    } ],
+    "materials" : [ {
+        "name" : "No name",
+        "color" : [ 1.0, 1.0, 1.0, 1.0 ],
+        "mipmap" : true,
+        "roughness" : 1.0,
+        "metallic" : 1.0,
+        "environment" : 1
+    } ],
+    "environment" : [ {
+        "cubeInitialOrientation" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "iblIntensity" : 1.0
+    }, {
+        "cubeSpecular" : "Studio/Radiance.ktx",
+        "cubeDiffuse" : "Studio/Irradiance.ktx",
+        "cubeInitialOrientation" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "iblIntensity" : 1.0
+    } ],
+    "shaders" : [ {
+        "vertex" : "dli_pbr.vsh",
+        "fragment" : "dli_pbr.fsh",
+        "defines" : [ "LIT" ],
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",
+        "uCubeMatrix" : [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
+        "uMaxLOD" : 6
+    }, {
+        "vertex" : "dli_pbr.vsh",
+        "fragment" : "dli_pbr.fsh",
+        "defines" : [ "THREE_TEX" ],
+        "rendererState" : "DEPTH_TEST|ALPHA_BLEND",
+        "uCubeMatrix" : [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
+        "uMaxLOD" : 6
+    }, {
+        "vertex" : "dli_pbr.vsh",
+        "fragment" : "dli_pbr.fsh",
+        "defines" : [ "MORPH", "MORPH_POSITION", "MORPH_NORMAL" ],
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",
+        "uCubeMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "uMaxLOD" : 6
+    }, {
+        "vertex" : "dli_pbr.vsh",
+        "fragment" : "dli_pbr.fsh",
+        "hints" : [ "MODIFIES_GEOMETRY" ],
+        "defines" : [ "MORPH", "MORPH_POSITION", "MORPH_NORMAL" ],
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_BACK|DEPTH_FUNC:LESS_EQUAL",
+        "uCubeMatrix" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ],
+        "uMaxLOD" : 6
+    }, {
+        "vertex" : "dli_pbr.vsh",
+        "fragment" : "dli_pbr.fsh",
+        "defines" : [ "LIT", "SHADOW" ],
+        "rendererState" : "DEPTH_TEST|DEPTH_WRITE|CULL_FRONT",
+        "uCubeMatrix" : [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
+        "uMaxLOD" : 6
+    } ],
+    "behaviors" : [ {
+        "url" : "head-behavior_1.lua",
+        "event" : "scene.loaded"
+    } ],
+    "animations" : [ {
+        "name" : "Morph",
+        "loopCount" : 0,
+        "duration" : 1.0,
+        "endAction" : "DISCARD",
+        "disconnectAction" : "BAKE",
+        "properties" : [ {
+            "node" : "head",
+            "property" : "uBlendShapeWeight[0]",
+            "value" : 1.0,
+            "alphaFunction" : "DEFAULT",
+            "timePeriod" : {
+                "delay" : 0.0,
+                "duration" : 0.5
+            },
+            "relative" : false
+        }, {
+            "node" : "head",
+            "property" : "uBlendShapeWeight[1]",
+            "value" : 1.0,
+            "alphaFunction" : "DEFAULT",
+            "timePeriod" : {
+                "delay" : 0.0,
+                "duration" : 0.5
+            },
+            "relative" : false
+        }, {
+            "node" : "head",
+            "property" : "uBlendShapeWeight[2]",
+            "value" : 1.0,
+            "alphaFunction" : "DEFAULT",
+            "timePeriod" : {
+                "delay" : 0.0,
+                "duration" : 0.5
+            },
+            "relative" : false
+        }, {
+            "node" : "head",
+            "property" : "uBlendShapeWeight[0]",
+            "value" : 0.0,
+            "alphaFunction" : "DEFAULT",
+            "timePeriod" : {
+                "delay" : 0.5,
+                "duration" : 0.5
+            },
+            "relative" : false
+        }, {
+            "node" : "head",
+            "property" : "uBlendShapeWeight[1]",
+            "value" : 0.0,
+            "alphaFunction" : "DEFAULT",
+            "timePeriod" : {
+                "delay" : 0.5,
+                "duration" : 0.5
+            },
+            "relative" : false
+        }, {
+            "node" : "head",
+            "property" : "uBlendShapeWeight[2]",
+            "value" : 0.0,
+            "alphaFunction" : "DEFAULT",
+            "timePeriod" : {
+                "delay" : 0.5,
+                "duration" : 0.5
+            },
+            "relative" : false
+        } ]
+    } ]
+}
diff --git a/automated-tests/resources/morph/HeadTest_002.dae.bin b/automated-tests/resources/morph/HeadTest_002.dae.bin
new file mode 100644 (file)
index 0000000..5fcc8c5
Binary files /dev/null and b/automated-tests/resources/morph/HeadTest_002.dae.bin differ
diff --git a/automated-tests/resources/morph/cube.gltf.bin b/automated-tests/resources/morph/cube.gltf.bin
new file mode 100644 (file)
index 0000000..8d715e4
Binary files /dev/null and b/automated-tests/resources/morph/cube.gltf.bin differ
diff --git a/automated-tests/resources/simpleTriangle.bin b/automated-tests/resources/simpleTriangle.bin
new file mode 100644 (file)
index 0000000..d642500
Binary files /dev/null and b/automated-tests/resources/simpleTriangle.bin differ
diff --git a/automated-tests/resources/truncated.ktx b/automated-tests/resources/truncated.ktx
new file mode 100644 (file)
index 0000000..a2dbcf1
Binary files /dev/null and b/automated-tests/resources/truncated.ktx differ
diff --git a/automated-tests/src/dali-scene-loader-internal/CMakeLists.txt b/automated-tests/src/dali-scene-loader-internal/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..14c7edd
--- /dev/null
@@ -0,0 +1,88 @@
+SET(PKG_NAME "dali-scene-loader-internal")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-scene-loader")
+
+# List of test case sources (Only these get parsed for test cases)
+SET(TC_SOURCES
+  utc-Dali-Gltf2Asset.cpp
+  utc-Dali-Hash.cpp
+  utc-Dali-JsonReader.cpp
+  utc-Dali-JsonUtil.cpp
+)
+
+# List of test harness files (Won't get parsed for test cases)
+SET(TEST_HARNESS_DIR "../dali-toolkit/dali-toolkit-test-utils")
+
+SET(TEST_HARNESS_SOURCES
+  ${TEST_HARNESS_DIR}/toolkit-adaptor.cpp
+  ${TEST_HARNESS_DIR}/toolkit-application.cpp
+  ${TEST_HARNESS_DIR}/toolkit-event-thread-callback.cpp
+  ${TEST_HARNESS_DIR}/toolkit-environment-variable.cpp
+  ${TEST_HARNESS_DIR}/toolkit-input-method-context.cpp
+  ${TEST_HARNESS_DIR}/toolkit-input-method-options.cpp
+  ${TEST_HARNESS_DIR}/toolkit-lifecycle-controller.cpp
+  ${TEST_HARNESS_DIR}/toolkit-orientation.cpp
+  ${TEST_HARNESS_DIR}/toolkit-style-monitor.cpp
+  ${TEST_HARNESS_DIR}/toolkit-test-application.cpp
+  ${TEST_HARNESS_DIR}/toolkit-timer.cpp
+  ${TEST_HARNESS_DIR}/toolkit-trigger-event-factory.cpp
+  ${TEST_HARNESS_DIR}/toolkit-window.cpp
+  ${TEST_HARNESS_DIR}/toolkit-scene-holder.cpp
+  ${TEST_HARNESS_DIR}/dali-test-suite-utils.cpp
+  ${TEST_HARNESS_DIR}/dali-toolkit-test-suite-utils.cpp
+  ${TEST_HARNESS_DIR}/dummy-control.cpp
+  ${TEST_HARNESS_DIR}/mesh-builder.cpp
+  ${TEST_HARNESS_DIR}/test-actor-utils.cpp
+  ${TEST_HARNESS_DIR}/test-animation-data.cpp
+  ${TEST_HARNESS_DIR}/test-application.cpp
+  ${TEST_HARNESS_DIR}/test-button.cpp
+  ${TEST_HARNESS_DIR}/test-harness.cpp
+  ${TEST_HARNESS_DIR}/test-gesture-generator.cpp
+  ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-gl-sync-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-platform-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-render-controller.cpp
+  ${TEST_HARNESS_DIR}/test-trace-call-stack.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+  dali2-core
+  dali2-adaptor
+  dali2-toolkit
+  dali2-scene-loader
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED)
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-toolkit/dali-toolkit-test-utils
+)
+
+ADD_CUSTOM_COMMAND(
+  COMMAND ${SCRIPT_DIR}/tcheadgen.sh ${EXEC_NAME}.h ${TC_SOURCES}
+  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+  OUTPUT ${EXEC_NAME}.h
+  COMMENT "Generating test tables"
+  )
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.h ${EXEC_NAME}.cpp ${TC_SOURCES} ${TEST_HARNESS_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+    -lpthread --coverage
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-scene-loader-internal/tct-dali-scene-loader-internal-core.cpp b/automated-tests/src/dali-scene-loader-internal/tct-dali-scene-loader-internal-core.cpp
new file mode 100644 (file)
index 0000000..9dea347
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-scene-loader-internal-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-scene-loader-internal/utc-Dali-Gltf2Asset.cpp b/automated-tests/src/dali-scene-loader-internal/utc-Dali-Gltf2Asset.cpp
new file mode 100644 (file)
index 0000000..8574137
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/internal/gltf2-asset.h"
+#include <dali-test-suite-utils.h>
+#include <string>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliGltf2AssetComponentIsUnsigned(void)
+{
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::BYTE), false);
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::UNSIGNED_BYTE), true);
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::SHORT), false);
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::UNSIGNED_SHORT), true);
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::UNSIGNED_INT), true);
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::FLOAT), false);
+  DALI_TEST_EQUAL(gltf2::Component::IsUnsigned(gltf2::Component::INVALID), false);
+
+  END_TEST;
+}
+
+int UtcDaliGltf2AssetComponentSize(void)
+{
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::BYTE), 1u);
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::UNSIGNED_BYTE), 1u);
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::SHORT), 2u);
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::UNSIGNED_SHORT), 2u);
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::UNSIGNED_INT), 4u);
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::FLOAT), 4u);
+  DALI_TEST_EQUAL(gltf2::Component::Size(gltf2::Component::INVALID), -1);
+
+  END_TEST;
+}
+
+#define FROM_STRING_HELPER(x) FromString(#x, strlen(#x))
+
+#define STRING_CHECK(type, x) DALI_TEST_EQUAL(gltf2::type:: FROM_STRING_HELPER(x), gltf2::type::x)
+
+int UtcDaliGltf2AssetAccessorType(void)
+{
+  STRING_CHECK(AccessorType, SCALAR);
+  STRING_CHECK(AccessorType, VEC2);
+  STRING_CHECK(AccessorType, VEC3);
+  STRING_CHECK(AccessorType, VEC4);
+  STRING_CHECK(AccessorType, MAT2);
+  STRING_CHECK(AccessorType, MAT3);
+  STRING_CHECK(AccessorType, MAT4);
+  DALI_TEST_EQUAL(gltf2::AccessorType::FROM_STRING_HELPER(VEC88), gltf2::AccessorType::INVALID);
+
+  END_TEST;
+}
+
+int UtcDaliGltf2AssetAlphaMode(void)
+{
+  STRING_CHECK(AlphaMode, OPAQUE);
+  STRING_CHECK(AlphaMode, MASK);
+  STRING_CHECK(AlphaMode, BLEND);
+  DALI_TEST_EQUAL(gltf2::AlphaMode::FROM_STRING_HELPER(ALPHA_SCHMALPHA), gltf2::AlphaMode::INVALID);
+
+  END_TEST;
+}
+
+int UtcDaliGltf2AssetAttribute(void)
+{
+  STRING_CHECK(Attribute, POSITION);
+  STRING_CHECK(Attribute, NORMAL);
+  STRING_CHECK(Attribute, TANGENT);
+  STRING_CHECK(Attribute, TEXCOORD_0);
+  STRING_CHECK(Attribute, TEXCOORD_1);
+  STRING_CHECK(Attribute, COLOR_0);
+  STRING_CHECK(Attribute, JOINTS_0);
+  STRING_CHECK(Attribute, WEIGHTS_0);
+  DALI_TEST_EQUAL(gltf2::Attribute::FROM_STRING_HELPER(VISCOSITY), gltf2::Attribute::INVALID);
+
+  END_TEST;
+}
+
+int UtcDaliGltf2AssetAnimationSamplerInterpolation(void)
+{
+  STRING_CHECK(Animation::Sampler::Interpolation, STEP);
+  STRING_CHECK(Animation::Sampler::Interpolation, LINEAR);
+  STRING_CHECK(Animation::Sampler::Interpolation, CUBICSPLINE);
+  DALI_TEST_EQUAL(gltf2::Animation::Sampler::Interpolation::FROM_STRING_HELPER(EASE_IN_OUT), gltf2::Animation::Sampler::Interpolation::INVALID);
+
+  END_TEST;
+}
+
+int UtcDaliGltf2AssetAnimationChannelTarget(void)
+{
+  STRING_CHECK(Animation::Channel::Target, TRANSLATION);
+  STRING_CHECK(Animation::Channel::Target, ROTATION);
+  STRING_CHECK(Animation::Channel::Target, SCALE);
+  STRING_CHECK(Animation::Channel::Target, WEIGHTS);
+  DALI_TEST_EQUAL(gltf2::Animation::Channel::Target::FROM_STRING_HELPER(FLUFFINESS), gltf2::Animation::Channel::Target::INVALID);
+
+  END_TEST;
+}
+
+int UtcDaliGltf2AssetAccessorSparse(void)
+{
+  gltf2::Accessor acc;
+  DALI_TEST_CHECK(!acc.mSparse);
+
+  std::vector<gltf2::BufferView> bufferViews;
+
+  gltf2::Accessor::Sparse sparse{ 256u };
+  sparse.mIndices.mBufferView = gltf2::Ref<gltf2::BufferView>(bufferViews, 5u);
+  sparse.mIndices.mComponentType = gltf2::Component::FLOAT;
+  sparse.mValues.mBufferView = gltf2::Ref<gltf2::BufferView>(bufferViews, 284u);
+  sparse.mValues.mByteOffset = 16532;
+  acc.SetSparse(sparse);
+
+  DALI_TEST_EQUAL(acc.mSparse->mCount, sparse.mCount);
+  DALI_TEST_EQUAL(acc.mSparse->mIndices.mBufferView, sparse.mIndices.mBufferView);
+  DALI_TEST_EQUAL(acc.mSparse->mIndices.mByteOffset, sparse.mIndices.mByteOffset);
+  DALI_TEST_EQUAL(acc.mSparse->mIndices.mComponentType, sparse.mIndices.mComponentType);
+  DALI_TEST_EQUAL(acc.mSparse->mValues.mBufferView, sparse.mValues.mBufferView);
+  DALI_TEST_EQUAL(acc.mSparse->mValues.mByteOffset, sparse.mValues.mByteOffset);
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-scene-loader-internal/utc-Dali-Hash.cpp b/automated-tests/src/dali-scene-loader-internal/utc-Dali-Hash.cpp
new file mode 100644 (file)
index 0000000..efd5053
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/internal/hash.h"
+#include <dali-test-suite-utils.h>
+#include <string>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliHash(void)
+{
+  DALI_TEST_EQUAL(Hash(0).Add(true), 0);
+  DALI_TEST_EQUAL(Hash(0).Add(false), 1);
+
+  int32_t myInt32 = std::numeric_limits<int32_t>::min();
+  DALI_TEST_EQUAL(Hash(0).Add(myInt32), myInt32);
+
+  uint32_t myUint32 = std::numeric_limits<uint32_t>::max();
+  DALI_TEST_EQUAL(Hash(0).Add(myUint32), myUint32);
+
+  uint64_t myUint64 = std::numeric_limits<uint64_t>::max();
+  DALI_TEST_EQUAL(uint64_t(Hash(0).Add(myUint64)), myUint64);
+
+  constexpr uint32_t multiplier = 31;
+  uint64_t expected = 0;
+  float f = 1928.46852;
+  for (auto i0 = reinterpret_cast<uint8_t const*>(&f), i1 = i0 + sizeof(f); i0 != i1; ++i0)
+  {
+    expected = expected * multiplier + *i0;
+  }
+
+  DALI_TEST_EQUAL(uint64_t(Hash(0).Add(f)), expected);
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-scene-loader-internal/utc-Dali-JsonReader.cpp b/automated-tests/src/dali-scene-loader-internal/utc-Dali-JsonReader.cpp
new file mode 100644 (file)
index 0000000..6b7e000
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/internal/json-reader.h"
+#include <dali-test-suite-utils.h>
+#include <string>
+
+using namespace Dali;
+
+#define JSON_STRING(x) #x, strlen(#x)
+
+int UtcDaliJsonReaderStrCmp(void)
+{
+  json_string_s jstr[] {
+    { JSON_STRING(hello) },
+    { JSON_STRING(hellew) },
+  };
+  DALI_TEST_EQUAL(json::StrCmp(jstr[0], "hello"), 0);
+  DALI_TEST_EQUAL(json::StrCmp(jstr[1], "hello"), 'e' - 'o');
+
+  END_TEST;
+}
+
+int UtcDaliJsonReaderValidateThrow(void)
+{
+  json_value_s jval { nullptr, json_type_array };
+  DALI_TEST_THROWS(json::Validate(jval, json_type_object), std::runtime_error);
+  json::Validate(jval, json_type_array);
+
+  END_TEST;
+}
+
+int UtcDaliJsonReaderFindObjectChild(void)
+{
+  json_string_s jkey{ JSON_STRING(fudgeFactor) };
+  json_number_s jActualValue{ JSON_STRING(5.2) };
+  json_value_s jvalue { &jActualValue, json_type_number };
+  json_object_element_s jobjelem { &jkey, &jvalue, nullptr };
+
+  json_object_s jobj{ &jobjelem, 1 };
+
+  DALI_TEST_EQUAL(json::FindObjectChild(jkey.string, jobj), &jvalue);
+  DALI_TEST_EQUAL(json::FindObjectChild("fudgeFactory", jobj), static_cast<json_value_s*>(nullptr));
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader-internal/utc-Dali-JsonUtil.cpp b/automated-tests/src/dali-scene-loader-internal/utc-Dali-JsonUtil.cpp
new file mode 100644 (file)
index 0000000..41ac039
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/internal/json-util.h"
+#include "dali-toolkit/devel-api/builder/json-parser.h"
+#include <dali-test-suite-utils.h>
+#include <string>
+
+#define STRINGIFY(x) #x
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+const std::string TEST_JSON =
+  "{ \"int\": 17834,"
+  "\"float\": 3.1415628,"
+  "\"bool\": true,"
+  "\"null\": null,"
+  "\"string\": \"hello\","
+  "\"floatArray\": [ 0.0, 0.25, 1.0, 0.75 ],"
+  "\"intArray\": [ 1, 2, 3, 5, 7, 11, 13, -1, -5 ],"
+  "\"mixedArray\": [ 1.99, \"the\", 6, \"brown\", \"fox\" ],"
+  "\"stringArray\": [ \"lorem\", \"ipsum\", \"dolor\", \"sic\", \"amet\" ],"
+  "\"object\": { \"duration\": 4.0, \"delay\": 1.0 },"
+  "\"rgb\": [ 0.5, 0.8, 0.25 ],"
+  "\"disambiguatedFloat\": { \"type\": \"float\", \"value\": 15.8 },"
+  "\"rotation1\": { \"type\": \"rotation\", \"value\": [ 15.0, 90.0, -45.0 ] },"
+  "\"rotation2\": { \"type\": \"rotation\", \"value\": [ 0.707, 0.0, 0.707, 0.0 ] },"
+  "\"matrix\": [ 1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 1.0, 2.0, 3.0, 4.0 ],"
+  "\"matrix3\": [ 2.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 1.0, 2.0 ],"
+  "\"vector2\": [ 2.0, 1.0 ]"
+  "}";
+
+template <typename T>
+struct Item
+{
+  std::string name;
+  bool readResult;
+  T result;
+};
+
+struct Document
+{
+  Document(const std::string& json)
+  : parser(JsonParser::New())
+  {
+    //DALI_TEST_CHECK(parser.Parse(json));
+    if (!parser.Parse(json))
+    {
+      auto error = parser.GetErrorDescription();
+      printf("Error: %s in {%d, %d}\n", error.c_str(), parser.GetErrorLineNumber(), parser.GetErrorColumn());
+    }
+    root = parser.GetRoot();
+  }
+
+  JsonParser parser;
+  const TreeNode* root;
+};
+
+template <typename T, size_t N>
+bool CompareArrays(const T (&array)[N], const T* p, T epsilon = T(0))
+{
+  for (auto& i: array)
+  {
+    if (std::abs(i - *p) > epsilon)
+    {
+      printf("Element %d mismatched.\n", int32_t(std::distance(array, &i)));
+      return false;
+    }
+    ++p;
+  }
+  return true;
+}
+
+}
+
+int UtcDaliJsonUtilReadBool(void)
+{
+  bool value = false;
+  DALI_TEST_CHECK(!ReadBool(nullptr, value));
+  DALI_TEST_EQUAL(value, false); // unchanged
+
+  Document doc{ TEST_JSON };
+
+  for (auto& i : {
+    Item<bool>{ "bool",       true, true },
+    Item<bool>{ "int",        false, true }, // value unchanged
+    Item<bool>{ "float",      false, true },
+    Item<bool>{ "null",       false, true },
+    Item<bool>{ "floatArray", false, true },
+    Item<bool>{ "intArray",   false, true },
+    Item<bool>{ "object",     false, true },
+  })
+  {
+    bool readResult = ReadBool(doc.root->GetChild(i.name), value);
+    DALI_TEST_EQUAL(readResult, i.readResult);
+    if (readResult)
+    {
+      DALI_TEST_EQUAL(value, i.result);
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadInt(void)
+{
+  int value = 0xbadbeef;
+  DALI_TEST_CHECK(!ReadInt(nullptr, value));
+  DALI_TEST_EQUAL(value, 0xbadbeef);
+
+  Document doc{ TEST_JSON };
+
+  for (auto& i : {
+    Item<int>{ "bool",       false, 0xbadbeef }, // unchanged from initial
+    Item<int>{ "int",        true, 17834 },
+    Item<int>{ "float",      true, 3 },
+    Item<int>{ "null",       false, 3 },
+    Item<int>{ "floatArray", false, 3 },
+    Item<int>{ "intArray",   false, 3 },
+    Item<int>{ "object",     false, 3 },
+  })
+  {
+    bool readResult = ReadInt(doc.root->GetChild(i.name), value);
+    DALI_TEST_EQUAL(readResult, i.readResult);
+    if (readResult)
+    {
+      DALI_TEST_EQUAL(value, i.result);
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadFloat(void)
+{
+  float value = 10.101f;
+  DALI_TEST_CHECK(!ReadFloat(nullptr, value));
+  DALI_TEST_EQUAL(value, 10.101f);
+
+  Document doc{ TEST_JSON };
+
+  for (auto& i : {
+    Item<float>{ "bool",       false, 10.101f }, // unchanged from initial
+    Item<float>{ "int",        true, 17834.f },
+    Item<float>{ "float",      true, 3.1415628f },
+    Item<float>{ "null",       false, 3.1415628f },
+    Item<float>{ "floatArray", false, 3.1415628f },
+    Item<float>{ "intArray",   false, 3.1415628f },
+    Item<float>{ "object",     false, 3.1415628f },
+  })
+  {
+    bool readResult = ReadFloat(doc.root->GetChild(i.name), value);
+    DALI_TEST_EQUAL(readResult, i.readResult);
+    if (readResult)
+    {
+      DALI_TEST_EQUAL(value, i.result);
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilNumericalArrays(void)
+{
+  Document doc{ TEST_JSON };
+
+  DALI_TEST_EQUAL(4u, GetNumericalArraySize(doc.root->GetChild("floatArray")));
+  DALI_TEST_EQUAL(9u, GetNumericalArraySize(doc.root->GetChild("intArray")));
+  DALI_TEST_EQUAL(1u, GetNumericalArraySize(doc.root->GetChild("mixedArray")));
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadVectorInt(void)
+{
+  DALI_TEST_CHECK(!ReadVector(nullptr, static_cast<int*>(nullptr), 0));
+
+  Document doc{ TEST_JSON };
+
+  int ints[9];
+  DALI_TEST_CHECK(ReadVector(doc.root->GetChild("floatArray"), ints, 4u));
+  DALI_TEST_CHECK(CompareArrays<int>({ 0, 0, 1, 0 }, ints));
+
+  DALI_TEST_CHECK(ReadVector(doc.root->GetChild("intArray"), ints, 9u));
+  DALI_TEST_CHECK(CompareArrays<int>({ 1, 2, 3, 5, 7, 11, 13, -1, -5 }, ints));
+
+  DALI_TEST_CHECK(ReadVector(doc.root->GetChild("mixedArray"), ints, 1u));
+  DALI_TEST_CHECK(CompareArrays<int>({ 1 }, ints));
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadVectorFloat(void)
+{
+  DALI_TEST_CHECK(!ReadVector(nullptr, static_cast<int*>(nullptr), 0));
+
+  Document doc{ TEST_JSON };
+
+  constexpr float e = 1e-6f;
+  float floats[9];
+  DALI_TEST_CHECK(ReadVector(doc.root->GetChild("floatArray"), floats, 4u));
+  DALI_TEST_CHECK(CompareArrays<float>({ 0.f, 0.25f, 1.f, 0.75f }, floats, e));
+
+  DALI_TEST_CHECK(ReadVector(doc.root->GetChild("intArray"), floats, 9u));
+  DALI_TEST_CHECK(CompareArrays<float>({ 1.f, 2.f, 3.f, 5.f, 7.f, 11.f, 13.f, -1.f, -5.f }, floats, e));
+
+  DALI_TEST_CHECK(ReadVector(doc.root->GetChild("mixedArray"), floats, 1u));
+  DALI_TEST_CHECK(CompareArrays<float>({ 1.99f }, floats, e));
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadColor(void)
+{
+  Vector4 color;
+  DALI_TEST_CHECK(!ReadColor(nullptr, color));
+
+  Document doc{ TEST_JSON };
+  DALI_TEST_CHECK(!ReadColor(doc.root->GetChild("bool"), color));
+  DALI_TEST_CHECK(!ReadColor(doc.root->GetChild("int"), color));
+  DALI_TEST_CHECK(!ReadColor(doc.root->GetChild("float"), color));
+  DALI_TEST_CHECK(!ReadColor(doc.root->GetChild("string"), color));
+  DALI_TEST_CHECK(!ReadColor(doc.root->GetChild("object"), color));
+
+  constexpr float e = 1e-6f;
+  DALI_TEST_CHECK(ReadColor(doc.root->GetChild("floatArray"), color));
+  DALI_TEST_CHECK(CompareArrays<float>({ 0.f, 0.25f, 1.0f, 0.75f }, color.AsFloat(), e));
+
+  DALI_TEST_CHECK(ReadColor(doc.root->GetChild("intArray"), color));
+  DALI_TEST_CHECK(CompareArrays<float>({ 1.f, 2.f, 3.f, 5.f }, color.AsFloat(), e));
+
+  DALI_TEST_CHECK(ReadColor(doc.root->GetChild("rgb"), color));
+  DALI_TEST_CHECK(CompareArrays<float>({ .5f, .8f, .25f, 1.f }, color.AsFloat(), e));
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadTimePeriod(void)
+{
+  TimePeriod value(60.f);
+  DALI_TEST_CHECK(!ReadTimePeriod(nullptr, value));
+  DALI_TEST_EQUAL(value.durationSeconds, 60.f);
+  DALI_TEST_EQUAL(value.delaySeconds, 0.f);
+
+  Document doc{ TEST_JSON };
+  DALI_TEST_CHECK(ReadTimePeriod(doc.root->GetChild("object"), value));
+  DALI_TEST_EQUAL(value.durationSeconds, 4.f);
+  DALI_TEST_EQUAL(value.delaySeconds, 1.f);
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadString(void)
+{
+  std::string value = "bye";
+  DALI_TEST_CHECK(!ReadString(nullptr, value));
+  DALI_TEST_EQUAL(value, "bye");
+
+  Document doc{ TEST_JSON };
+
+  for (auto& i : {
+    Item<std::string>{ "bool",       false, "bye"}, // unchanged from initial
+    Item<std::string>{ "int",        false, "bye"},
+    Item<std::string>{ "float",      false, "bye"},
+    Item<std::string>{ "null",       false, "bye"},
+    Item<std::string>{ "string",     true, "hello"},
+    Item<std::string>{ "floatArray", false, "hello"}, // unchanged
+    Item<std::string>{ "object",     false, "hello"},
+  })
+  {
+    bool readResult = ReadString(doc.root->GetChild(i.name), value);
+    DALI_TEST_EQUAL(readResult, i.readResult);
+    if (readResult)
+    {
+      DALI_TEST_EQUAL(value, i.result);
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadStringVector(void)
+{
+  std::vector<std::string> strings;
+  DALI_TEST_CHECK(!ReadStringVector(nullptr, strings));
+  DALI_TEST_CHECK(strings.empty());
+
+  Document doc{ TEST_JSON };
+
+  DALI_TEST_CHECK(!ReadStringVector(doc.root->GetChild("floatArray"), strings));
+  DALI_TEST_CHECK(strings.empty());
+
+  DALI_TEST_CHECK(!ReadStringVector(doc.root->GetChild("intArray"), strings));
+  DALI_TEST_CHECK(strings.empty());
+
+  DALI_TEST_CHECK(!ReadStringVector(doc.root->GetChild("mixedArray"), strings));
+  DALI_TEST_CHECK(strings.empty());
+
+  DALI_TEST_CHECK(ReadStringVector(doc.root->GetChild("stringArray"), strings));
+  DALI_TEST_EQUAL(strings.size(), 5u);
+
+  auto iStrings = strings.begin();
+  for (auto& i : { "lorem", "ipsum", "dolor", "sic", "amet" })
+  {
+    DALI_TEST_EQUAL(*iStrings, i);
+    ++iStrings;
+  }
+
+  END_TEST;
+}
+
+int UtcDaliJsonUtilReadAndReturnPropertyValue(void)
+{
+  Document doc{ TEST_JSON };
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("disambiguatedFloat")).Get<float>(), 15.8f);
+
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("rotation1")).Get<Quaternion>(),
+    Quaternion(Radian(Degree(15.0)), Radian(Degree(90.0)), Radian(Degree(-45.f))));
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("rotation2")).Get<Quaternion>(),
+    Quaternion(Vector4(0.707f, 0.f, 0.707f, 0.f)));
+
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("bool")).Get<bool>(), true);
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("int")).Get<int32_t>(), 17834);
+
+  const float floats[]{ 1.f, 0.f, 0.f, 0.f, 0.f, 2.f, 0.f, 0.f, 0.f, 0.f, 3.f, 0.f, 1.f, 2.f, 3.f, 4.f };
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("matrix")).Get<Matrix>(), Matrix(floats));
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("matrix3")).Get<Matrix3>(), Matrix3(floats[5],
+    floats[6], floats[7], floats[8], floats[9], floats[10], floats[11], floats[12], floats[13]));
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("floatArray")).Get<Vector4>(),
+    Vector4(0.f, .25f, 1.f, .75f));
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("rgb")).Get<Vector3>(),
+    Vector3(.5f, .8f, .25f));
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("vector2")).Get<Vector2>(),
+    Vector2(2.f, 1.f));
+  DALI_TEST_EQUAL(ReadPropertyValue(*doc.root->GetChild("object")->GetChild("duration")).Get<float>(), 4.f );
+
+  END_TEST;
+}
+
+namespace
+{
+template <typename T>
+void CheckEqualityAs(Property::Value lhs, Property::Value rhs)
+{
+  DALI_TEST_EQUAL(lhs.Get<T>(), rhs.Get<T>());
+}
+
+}
+
+int UtcDaliJsonUtilReadPropertyValue(void)
+{
+  struct TypeNameValue
+  {
+    Property::Type type;
+    std::string name;
+    Property::Value value;
+    void(*compareFn)(Property::Value, Property::Value);
+  };
+
+  Document doc{ TEST_JSON };
+
+  const float floats[]{ 1.f, 0.f, 0.f, 0.f, 0.f, 2.f, 0.f, 0.f, 0.f, 0.f, 3.f, 0.f, 1.f, 2.f, 3.f, 4.f };
+  const TypeNameValue typeNameValues[] {
+    { Property::BOOLEAN, "bool", true, CheckEqualityAs<bool> },
+    { Property::FLOAT, "float", 3.1415628f, CheckEqualityAs<float> },
+    { Property::INTEGER, "int", 17834, CheckEqualityAs<int32_t> },
+    { Property::VECTOR2, "vector2", Vector2(2.f, 1.f), CheckEqualityAs<Vector2> },
+    { Property::VECTOR3, "rgb", Vector3(.5f, .8f, .25f), CheckEqualityAs<Vector3> },
+    { Property::VECTOR4, "floatArray", Vector4(.0f, .25f, 1.f, .75f), CheckEqualityAs<Vector4> },
+    { Property::MATRIX3, "matrix3", Matrix3(2.f, 0.f, 0.f, 0.f, 0.f, 3.f, 0.f, 1.f, 2.f),
+      CheckEqualityAs<Matrix3> },
+    { Property::MATRIX, "matrix", Matrix(floats), CheckEqualityAs<Matrix> },
+    { Property::RECTANGLE, "intArray", Rect<int>(1, 2, 3, 5), CheckEqualityAs<Rect<int>> },
+    { Property::EXTENTS, "intArray", Extents(1, 2, 3, 5), CheckEqualityAs<Extents> },
+  };
+  for(auto& i: typeNameValues)
+  {
+    std::cout << i.value << std::endl;
+    i.compareFn(ReadPropertyValue(i.type, *doc.root->GetChild(i.name)), i.value);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/CMakeLists.txt b/automated-tests/src/dali-scene-loader/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..348f29c
--- /dev/null
@@ -0,0 +1,102 @@
+SET(PKG_NAME "dali-scene-loader")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-scene-loader")
+
+# List of test case sources (Only these get parsed for test cases)
+SET(TC_SOURCES
+  utc-Dali-AlphaFunctionHelper.cpp
+  utc-Dali-AnimationDefinition.cpp
+  utc-Dali-AnimatedProperty.cpp
+  utc-Dali-CameraParameters.cpp
+  utc-Dali-DliLoader.cpp
+  utc-Dali-EnvironmentDefinition.cpp
+  utc-Dali-Gltf2Loader.cpp
+  utc-Dali-KtxLoader.cpp
+  utc-Dali-MatrixStack.cpp
+  utc-Dali-NodeDefinition.cpp
+  utc-Dali-RendererState.cpp
+  utc-Dali-ResourceBundle.cpp
+  utc-Dali-SceneDefinition.cpp
+  utc-Dali-ShaderDefinition.cpp
+  utc-Dali-ShaderDefinitionFactory.cpp
+  utc-Dali-StringCallback.cpp
+  utc-Dali-Utils.cpp
+  utc-Dali-ViewProjection.cpp
+)
+
+# List of test harness files (Won't get parsed for test cases)
+SET(TEST_HARNESS_DIR "../dali-toolkit/dali-toolkit-test-utils")
+
+SET(TEST_HARNESS_SOURCES
+  ${TEST_HARNESS_DIR}/toolkit-adaptor.cpp
+  ${TEST_HARNESS_DIR}/toolkit-application.cpp
+  ${TEST_HARNESS_DIR}/toolkit-event-thread-callback.cpp
+  ${TEST_HARNESS_DIR}/toolkit-environment-variable.cpp
+  ${TEST_HARNESS_DIR}/toolkit-input-method-context.cpp
+  ${TEST_HARNESS_DIR}/toolkit-input-method-options.cpp
+  ${TEST_HARNESS_DIR}/toolkit-lifecycle-controller.cpp
+  ${TEST_HARNESS_DIR}/toolkit-orientation.cpp
+  ${TEST_HARNESS_DIR}/toolkit-style-monitor.cpp
+  ${TEST_HARNESS_DIR}/toolkit-test-application.cpp
+  ${TEST_HARNESS_DIR}/toolkit-timer.cpp
+  ${TEST_HARNESS_DIR}/toolkit-trigger-event-factory.cpp
+  ${TEST_HARNESS_DIR}/toolkit-window.cpp
+  ${TEST_HARNESS_DIR}/toolkit-scene-holder.cpp
+  ${TEST_HARNESS_DIR}/dali-test-suite-utils.cpp
+  ${TEST_HARNESS_DIR}/dali-toolkit-test-suite-utils.cpp
+  ${TEST_HARNESS_DIR}/dummy-control.cpp
+  ${TEST_HARNESS_DIR}/mesh-builder.cpp
+  ${TEST_HARNESS_DIR}/test-actor-utils.cpp
+  ${TEST_HARNESS_DIR}/test-animation-data.cpp
+  ${TEST_HARNESS_DIR}/test-application.cpp
+  ${TEST_HARNESS_DIR}/test-button.cpp
+  ${TEST_HARNESS_DIR}/test-harness.cpp
+  ${TEST_HARNESS_DIR}/test-gesture-generator.cpp
+  ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-gl-sync-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-platform-abstraction.cpp
+  ${TEST_HARNESS_DIR}/test-render-controller.cpp
+  ${TEST_HARNESS_DIR}/test-trace-call-stack.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+  dali2-core
+  dali2-adaptor
+  dali2-toolkit
+  dali2-scene-loader
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED)
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-toolkit/dali-toolkit-test-utils
+)
+
+ADD_CUSTOM_COMMAND(
+  COMMAND ${SCRIPT_DIR}/tcheadgen.sh ${EXEC_NAME}.h ${TC_SOURCES}
+  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+  OUTPUT ${EXEC_NAME}.h
+  COMMENT "Generating test tables"
+  )
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.h ${EXEC_NAME}.cpp ${TC_SOURCES} ${TEST_HARNESS_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+    -lpthread --coverage
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-scene-loader/tct-dali-scene-loader-core.cpp b/automated-tests/src/dali-scene-loader/tct-dali-scene-loader-core.cpp
new file mode 100644 (file)
index 0000000..90b7a2c
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-scene-loader-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-AlphaFunctionHelper.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-AlphaFunctionHelper.cpp
new file mode 100644 (file)
index 0000000..da40b27
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/alpha-function-helper.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+#define ALPHA_FN_PAIR(x) { #x, AlphaFunction::x }
+
+const std::pair<std::string, AlphaFunction::BuiltinFunction> BUILTIN_FUNCTIONS[] {
+  ALPHA_FN_PAIR(DEFAULT),
+  ALPHA_FN_PAIR(LINEAR),
+  ALPHA_FN_PAIR(REVERSE),
+  ALPHA_FN_PAIR(EASE_IN),
+  ALPHA_FN_PAIR(EASE_OUT),
+  ALPHA_FN_PAIR(EASE_IN_OUT),
+  ALPHA_FN_PAIR(EASE_IN_SQUARE),
+  ALPHA_FN_PAIR(EASE_OUT_SQUARE),
+  ALPHA_FN_PAIR(EASE_IN_SINE),
+  ALPHA_FN_PAIR(EASE_OUT_SINE),
+  ALPHA_FN_PAIR(EASE_IN_OUT_SINE),
+  ALPHA_FN_PAIR(BOUNCE),
+  ALPHA_FN_PAIR(SIN),
+  ALPHA_FN_PAIR(EASE_OUT_BACK),
+};
+
+int UtcDaliAlphaFunctionHelperGet(void)
+{
+  bool found;
+  for (auto& a: BUILTIN_FUNCTIONS)
+  {
+    auto result = GetAlphaFunction(a.first, &found);
+    DALI_TEST_EQUAL(result.GetBuiltinFunction(), a.second);
+    DALI_TEST_EQUAL(result.GetMode(), AlphaFunction::BUILTIN_FUNCTION);
+    DALI_TEST_CHECK(found);
+  }
+
+  auto result = GetAlphaFunction("made up function", &found);
+  DALI_TEST_EQUAL(result.GetBuiltinFunction(), AlphaFunction::DEFAULT);
+  DALI_TEST_EQUAL(result.GetMode(), AlphaFunction::BUILTIN_FUNCTION);
+  DALI_TEST_CHECK(!found);
+
+  END_TEST;
+}
+
+int UtcDaliAlphaFunctionHelperRegister(void)
+{
+  for (auto& a: BUILTIN_FUNCTIONS)
+  {
+    DALI_TEST_ASSERTION(RegisterAlphaFunction(a.first, AlphaFunction()), "given key already exists");
+  }
+
+  AlphaFunctionPrototype testFn = [](float f) {
+    return f > .5f ? 1.f : 0.f;
+  };
+  RegisterAlphaFunction("step", AlphaFunction(testFn));
+
+  bool found;
+  auto result = GetAlphaFunction("step", &found);
+  DALI_TEST_EQUAL(result.GetMode(), AlphaFunction::CUSTOM_FUNCTION);
+  DALI_TEST_EQUAL(result.GetCustomFunction(), testFn);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-AnimatedProperty.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-AnimatedProperty.cpp
new file mode 100644 (file)
index 0000000..c660a1d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/animated-property.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliAnimatedPropertyGetPropertyType(void)
+{
+  TestApplication app;
+  auto actor = Actor::New();
+  actor.SetProperty(Actor::Property::NAME, "ChristopherPlummer");
+
+  AnimatedProperty animProp {
+   "ChristopherPlummer",
+   "position",
+   KeyFrames(),
+   std::unique_ptr<AnimatedProperty::Value>{ new AnimatedProperty::Value{
+     Property::Value{ Vector3::XAXIS * 100.f },
+     true
+   } },
+  };
+
+  Property expected(actor, Actor::Property::POSITION);
+  Property result = animProp.GetProperty(actor);
+  DALI_TEST_EQUAL(result.object, expected.object);
+  DALI_TEST_EQUAL(result.propertyIndex, expected.propertyIndex);
+  DALI_TEST_EQUAL(result.componentIndex, expected.componentIndex);
+  DALI_TEST_EQUAL(animProp.GetPropertyType(actor), Property::VECTOR3);
+
+  END_TEST;
+}
+
+
+
+
+
+
+
+
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-AnimationDefinition.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-AnimationDefinition.cpp
new file mode 100644 (file)
index 0000000..e27fb36
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/animation-definition.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliAnimationDefinitionStopForModification(void)
+{
+  TestApplication app;
+  auto anim = Animation::New(15.f);
+  anim.Play();
+
+  auto oldEndAction = AnimationDefinition::StopForModification(anim);
+  DALI_TEST_EQUAL(anim.GetState(), Animation::STOPPED);
+  DALI_TEST_EQUAL(oldEndAction, Animation::BAKE);
+  DALI_TEST_EQUAL(anim.GetEndAction(), Animation::DISCARD);
+
+  END_TEST;
+}
+
+int UtcDaliAnimationDefinitionReAnimate(void)
+{
+  TestApplication app;
+  auto actor = Actor::New();
+  actor.SetProperty(Actor::Property::NAME, "ChristopherPlummer");
+
+  auto getActor = [&actor](const std::string& name) {
+    return actor.FindChildByName(name);
+  };
+
+  for (bool b: { false, true })
+  {
+    AnimationDefinition animDef;
+    animDef.mName = "WalkRight";
+    animDef.mDuration = 10.f;
+    animDef.mLoopCount = 2;
+    animDef.mEndAction = Animation::BAKE_FINAL;
+    animDef.mSpeedFactor = .7f;
+    animDef.mProperties.push_back(AnimatedProperty{
+     "ChristopherPlummer",
+     "position",
+     KeyFrames(),
+     std::unique_ptr<AnimatedProperty::Value>{ new AnimatedProperty::Value{
+       Property::Value{ Vector3::XAXIS * 100.f },
+       b
+     } },
+     AlphaFunction::EASE_OUT,
+     TimePeriod(animDef.mDuration)
+    });
+
+    auto anim = animDef.ReAnimate(getActor);
+    DALI_TEST_EQUAL(anim.GetDuration(), animDef.mDuration);
+    DALI_TEST_EQUAL(anim.GetEndAction(), animDef.mEndAction);
+    DALI_TEST_EQUAL(anim.GetSpeedFactor(), animDef.mSpeedFactor);
+    DALI_TEST_EQUAL(anim.GetLoopCount(), animDef.mLoopCount);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAnimationDefinitionReAnimateKeyFrames(void)
+{
+  TestApplication app;
+  auto actor = Actor::New();
+  actor.SetProperty(Actor::Property::NAME, "ChristopherPlummer");
+
+  auto getActor = [&actor](const std::string& name) {
+    return actor.FindChildByName(name);
+  };
+
+  KeyFrames kf = KeyFrames::New();
+  kf.Add(0.f, Vector3::ZERO);
+  kf.Add(1.f, Vector3::XAXIS * 100.f);
+
+  AnimationDefinition animDef;
+  animDef.mName = "WalkRight";
+  animDef.mDuration = 10.f;
+  animDef.mLoopCount = 2;
+  animDef.mEndAction = Animation::BAKE_FINAL;
+  animDef.mSpeedFactor = .7f;
+  animDef.mProperties.push_back(AnimatedProperty{
+   "ChristopherPlummer",
+   "position",
+   kf,
+   nullptr,
+   AlphaFunction::EASE_OUT,
+   TimePeriod(animDef.mDuration)
+  });
+
+  auto anim = animDef.ReAnimate(getActor);
+  DALI_TEST_EQUAL(anim.GetDuration(), animDef.mDuration);
+  DALI_TEST_EQUAL(anim.GetEndAction(), animDef.mEndAction);
+  DALI_TEST_EQUAL(anim.GetSpeedFactor(), animDef.mSpeedFactor);
+  DALI_TEST_EQUAL(anim.GetLoopCount(), animDef.mLoopCount);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-CameraParameters.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-CameraParameters.cpp
new file mode 100644 (file)
index 0000000..5ad4a40
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/camera-parameters.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliCameraParameters(void)
+{
+  Quaternion qView = Quaternion(Radian(Degree(180.f)), Vector3::YAXIS);
+  CameraParameters camParams;
+  camParams.matrix.SetTransformComponents(Vector3::ONE * 2.f,
+    qView,
+    Vector3::ZAXIS * -100.f);
+  camParams.orthographicSize = Vector4{ -1.f, 1.f, -1.f, 1.f };
+  camParams.yFov = Radian(M_PI * .5).radian;
+  camParams.zNear = 1.f;
+  camParams.zFar = 1000.f;
+
+  Vector3 scale;
+  Quaternion orientation;
+  Vector3 position;
+  camParams.CalculateTransformComponents(position, orientation, scale);
+  DALI_TEST_EQUAL(scale, Vector3::ONE * 2.f);
+  DALI_TEST_EQUAL(orientation, Quaternion::IDENTITY); // 2 180 degrees rotations along y
+  DALI_TEST_EQUAL(position, Vector3::ZAXIS * -100.f);
+
+  TestApplication app;
+  CameraActor camera = CameraActor::New();
+  for (auto i : { false, true })
+  {
+    camParams.isPerspective = i;
+
+    auto viewProjection = camParams.GetViewProjection();
+    Matrix view{ false };
+    Matrix::Multiply(view, Matrix(qView), camParams.matrix);
+    view.Invert();
+    DALI_TEST_EQUAL(viewProjection.GetView(), view);
+
+    camParams.ConfigureCamera(camera);
+    DALI_TEST_EQUAL(camParams.zNear, camera.GetNearClippingPlane());
+    DALI_TEST_EQUAL(camParams.zFar, camera.GetFarClippingPlane());
+
+    DALI_TEST_EQUAL(camera.GetInvertYAxis(), true);
+    DALI_TEST_EQUAL(camera.GetProperty(Actor::Property::POSITION).Get<Vector3>(), position);
+    DALI_TEST_EQUAL(camera.GetProperty(Actor::Property::ORIENTATION).Get<Quaternion>(), orientation);
+    DALI_TEST_EQUAL(camera.GetProperty(Actor::Property::SCALE).Get<Vector3>(), scale);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-DliLoader.cpp
new file mode 100644 (file)
index 0000000..d09d2da
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/dli-loader.h"
+#include "dali-scene-loader/public-api/resource-bundle.h"
+#include "dali-scene-loader/public-api/scene-definition.h"
+#include "dali-scene-loader/public-api/load-result.h"
+#include "dali-scene-loader/internal/json-util.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+
+void ConfigureBlendShapeShaders(ResourceBundle& resources, const SceneDefinition& scene, Actor root,
+  std::vector<BlendshapeShaderConfigurationRequest>&& requests)
+{
+  std::vector<std::string> errors;
+  auto onError = [&errors](const std::string& msg) {
+    errors.push_back(msg);
+  };
+
+  if (!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
+  {
+    ExceptionFlinger flinger(ASSERT_LOCATION);
+    for (auto& msg : errors)
+    {
+      flinger << msg << '\n';
+    }
+  }
+}
+
+struct Context
+{
+  ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
+    return TEST_RESOURCE_DIR "/";
+  };
+
+  ResourceBundle resources;
+  SceneDefinition scene;
+  std::vector<CameraParameters> cameraParameters;
+  std::vector<LightParameters> lights;
+  std::vector<AnimationDefinition> animations;
+  std::vector<AnimationGroupDefinition> animGroups;
+
+  LoadResult output {
+    resources,
+    scene,
+    animations,
+    animGroups,
+    cameraParameters,
+    lights
+  };
+
+  DliLoader::InputParams input {
+    pathProvider(ResourceType::Mesh),
+    nullptr,
+    {},
+    {},
+    nullptr,
+  };
+  DliLoader::LoadParams loadParams{ input, output };
+
+  std::vector<std::string> errors;
+  DliLoader loader;
+
+  StringCallback onError = [this](const std::string& error) {
+    errors.push_back(error);
+    printf("%s\n", error.c_str());
+  };
+
+  Context()
+  {
+    loader.SetErrorCallback(onError);
+  }
+};
+
+bool StringHasTokens(const char* string, const std::vector<const char*>& tokens)
+{
+  for (auto& token: tokens)
+  {
+    auto result = strstr(string, token);
+    if(nullptr == result)
+    {
+      return false;
+    }
+    string = result + strlen(token);
+  }
+  return true;
+}
+
+}
+
+int UtcDaliDliLoaderLoadSceneNotFound(void)
+{
+  Context ctx;
+
+  DALI_TEST_EQUAL(ctx.loader.LoadScene("does_not_exist.dli", ctx.loadParams), false);
+
+  auto error = ctx.loader.GetParseError();
+  DALI_TEST_CHECK(StringHasTokens(error.c_str(), { "Empty source buffer to parse." }));
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneFailParse(void)
+{
+  Context ctx;
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "invalid.gltf";
+  DALI_TEST_EQUAL(ctx.loader.LoadScene(path, ctx.loadParams), false);
+
+  auto error = ctx.loader.GetParseError();
+  DALI_TEST_CHECK(StringHasTokens(error.c_str(), { "Unexpected character." }));
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneAssertions(void)
+{
+  const std::pair<std::string, std::string> pathExceptionPairs[] {
+     // from RequireChild()
+    { "scenes-nodes-missing", "Failed to find child node" },
+    { "scenes-missing", "Failed to find child node" },
+    { "nodes-missing", "Failed to find child node" },
+    // from ParseSceneInternal()
+    { "scene-out-of-bounds", "out of bounds" },
+    { "nodes-invalid-type", "invalid type; array required" },
+    { "nodes-array-empty", "must define a node id" },
+    { "root-id-invalid", "invalid value for root node index" },
+    { "root-id-out-of-bounds", "out of bounds" },
+    { "root-node-invalid-type", "invalid JSON type; object required" },
+    // from ParseSkeletons()
+    { "skeleton-node-missing", "Missing required attribute" },
+    { "skeleton-root-not-found", "not defined" },
+    // from ParseShaders()
+    { "shader-vertex-missing", "Missing vertex / fragment shader" },
+    { "shader-fragment-missing", "Missing vertex / fragment shader" },
+    // from ParseMeshes()
+    { "mesh-uri-missing", "Missing required attribute" },
+    { "mesh-indices-read-fail", "Failed to read indices" },
+    { "mesh-positions-read-fail", "Failed to read positions" },
+    // from ParseMaterials()
+    { "material-environment-out-of-bounds", "out of bounds" },
+    // from ParseNodes()
+    { "node-model-mesh-missing", "Missing mesh" },
+    { "node-arc-mesh-missing", "Missing mesh" },
+    { "node-animated-image-mesh-missing", "Missing mesh" },
+    { "node-renderable-mesh-invalid-type", "Invalid Mesh index type" },
+    { "node-renderable-mesh-out-of-bounds", "out of bounds" },
+    { "node-child-invalid-type", "invalid index type" },
+    { "node-name-already-used", "name already used" },
+    // from ParseAnimations()
+    { "animation-failed-to-open", "Failed to open animation data" }
+  };
+  for (auto& i: pathExceptionPairs)
+  {
+    Context ctx;
+
+    auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/" + i.first + ".dli";
+    printf("\n\n%s: %s\n", path.c_str(), i.second.c_str());
+    DALI_TEST_ASSERTION(ctx.loader.LoadScene(path, ctx.loadParams), i.second.c_str());
+  }
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneExercise(void)
+{
+  Context ctx;
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "exercise.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+  DALI_TEST_CHECK(ctx.errors.empty());
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 2u);
+  DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "Backdrop"); // default scene is scene 1 - this one.
+  DALI_TEST_EQUAL(scene.GetNode(roots[1])->mName, "ExerciseDemo");
+
+  DALI_TEST_EQUAL(scene.GetNodeCount(), 96u);
+
+  auto& resources = ctx.resources;
+  DALI_TEST_EQUAL(resources.mMeshes.size(), 11u);
+  DALI_TEST_EQUAL(resources.mMaterials.size(), 13u);
+  DALI_TEST_EQUAL(resources.mShaders.size(), 5u);
+  DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 2u);
+  DALI_TEST_EQUAL(resources.mSkeletons.size(), 1u);
+
+  DALI_TEST_EQUAL(ctx.cameraParameters.size(), 1u);
+  DALI_TEST_EQUAL(ctx.lights.size(), 1u);
+  DALI_TEST_EQUAL(ctx.animations.size(), 18u);
+  DALI_TEST_EQUAL(ctx.animGroups.size(), 16u);
+
+  ViewProjection viewProjection;
+  Transforms xforms {
+    MatrixStack{},
+    viewProjection
+  };
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for (auto iRoot : scene.GetRoots())
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_EQUAL(root.GetChildCount(), 2u);
+  DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "Backdrop");
+  DALI_TEST_EQUAL(root.GetChildAt(1).GetProperty(Actor::Property::NAME).Get<std::string>(), "ExerciseDemo");
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneMorph(void)
+{
+  Context ctx;
+
+  std::vector<std::string> metadata;
+  uint32_t metadataCount = 0;
+  ctx.input.mPreNodeCategoryProcessors.push_back({ "metadata",
+    [&](const Property::Array& array, StringCallback) {
+      std::string key, value;
+      for (uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0)
+      {
+        auto& data = array.GetElementAt(i0);
+        DALI_TEST_EQUAL(data.GetType(), Property::MAP);
+
+        auto map = data.GetMap();
+        auto key = map->Find("key");
+        auto value = map->Find("value");
+        DALI_TEST_EQUAL(key->GetType(), Property::STRING);
+        DALI_TEST_EQUAL(value->GetType(), Property::STRING);
+        metadata.push_back(key->Get<std::string>() + ":" + value->Get<std::string>());
+
+        ++metadataCount;
+      }
+    }
+  });
+
+  std::vector<std::string> behaviors;
+  uint32_t behaviorCount = 0;
+  ctx.input.mPostNodeCategoryProcessors.push_back({ "behaviors",
+    [&](const Property::Array& array, StringCallback) {
+      for (uint32_t i0 = 0, i1 = array.Count(); i0 < i1; ++i0)
+      {
+        auto& data = array.GetElementAt(i0);
+        DALI_TEST_EQUAL(data.GetType(), Property::MAP);
+
+        auto map = data.GetMap();
+        auto event = map->Find("event");
+        auto url = map->Find("url");
+        DALI_TEST_EQUAL(event->GetType(), Property::STRING);
+        DALI_TEST_EQUAL(url->GetType(), Property::STRING);
+        behaviors.push_back(event->Get<std::string>() + ":" + url->Get<std::string>());
+
+        ++behaviorCount;
+      }
+    }
+  });
+
+  size_t numNodes = 0;
+  ctx.input.mNodePropertyProcessor = [&](const NodeDefinition&, const Property::Map&, StringCallback) {
+    ++numNodes;
+  };
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "morph.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+  DALI_TEST_CHECK(ctx.errors.empty());
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+  DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "HeadTest_002");
+
+  DALI_TEST_EQUAL(numNodes, 3u);
+  DALI_TEST_EQUAL(scene.GetNodeCount(), numNodes);
+
+  auto& resources = ctx.resources;
+  DALI_TEST_EQUAL(resources.mMeshes.size(), 2u);
+  DALI_TEST_EQUAL(resources.mMaterials.size(), 1u);
+  DALI_TEST_EQUAL(resources.mShaders.size(), 5u);
+  DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 2u);
+  DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u);
+
+  DALI_TEST_EQUAL(ctx.cameraParameters.size(), 1u);
+  DALI_TEST_EQUAL(ctx.lights.size(), 1u);
+  DALI_TEST_EQUAL(ctx.animations.size(), 1u);
+  DALI_TEST_EQUAL(ctx.animGroups.size(), 0u);
+
+  DALI_TEST_EQUAL(metadata.size(), 4u);
+  DALI_TEST_EQUAL(behaviors.size(), 1u);
+
+  ViewProjection viewProjection;
+  Transforms xforms {
+    MatrixStack{},
+    viewProjection
+  };
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for (auto iRoot : scene.GetRoots())
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_EQUAL(root.GetChildCount(), 1u);
+  DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "HeadTest_002");
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneArc(void)
+{
+  Context ctx;
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "arc.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+  DALI_TEST_CHECK(ctx.errors.empty());
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+  DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root");
+
+  DALI_TEST_EQUAL(scene.GetNodeCount(), 2u);
+
+  auto& resources = ctx.resources;
+  DALI_TEST_EQUAL(resources.mMeshes.size(), 1u);
+  DALI_TEST_EQUAL(resources.mMaterials.size(), 1u);
+  DALI_TEST_EQUAL(resources.mShaders.size(), 1u);
+  DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 1u);
+  DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u);
+
+  DALI_TEST_EQUAL(ctx.cameraParameters.size(), 0u);
+  DALI_TEST_EQUAL(ctx.lights.size(), 0u);
+  DALI_TEST_EQUAL(ctx.animations.size(), 0u);
+  DALI_TEST_EQUAL(ctx.animGroups.size(), 0u);
+
+  ViewProjection viewProjection;
+  Transforms xforms {
+    MatrixStack{},
+    viewProjection
+  };
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for (auto iRoot : scene.GetRoots())
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if (auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_EQUAL(root.GetChildCount(), 1u);
+  DALI_TEST_EQUAL(root.GetChildAt(0).GetProperty(Actor::Property::NAME).Get<std::string>(), "root");
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneShaderUniforms(void)
+{
+  Context ctx;
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/shader-uniforms.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+  DALI_TEST_EQUAL(ctx.errors.size(), 1u);
+  DALI_TEST_CHECK(ctx.errors[0].find("failed to infer type") != std::string::npos);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+  DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root");
+
+  DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
+
+  auto& resources = ctx.resources;
+  DALI_TEST_EQUAL(resources.mMeshes.size(), 0u);
+  DALI_TEST_EQUAL(resources.mMaterials.size(), 0u);
+  DALI_TEST_EQUAL(resources.mShaders.size(), 1u);
+  DALI_TEST_EQUAL(resources.mEnvironmentMaps.size(), 0u);
+  DALI_TEST_EQUAL(resources.mSkeletons.size(), 0u);
+
+  auto raw = resources.mShaders[0].first.LoadRaw(ctx.pathProvider(ResourceType::Shader));
+
+  TestApplication app;
+
+  auto shader = resources.mShaders[0].first.Load(std::move(raw));
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uBool")).Get<float>(), 1.0f);
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uInt")).Get<float>(), 255.0f);
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uFloat")).Get<float>(), -0.5f);
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uVec2")).Get<Vector2>(), Vector2(100.0f, -100.0f));
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uVec3")).Get<Vector3>(), Vector3(50.0f, 0.f, -200.0f));
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uVec4")).Get<Vector4>(), Vector4(0.1774f, 1.0f, 0.5333f, 0.7997f));
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uMat3")).Get<Matrix3>(), Matrix3(9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f));
+
+  Matrix expectedMatrix;
+  expectedMatrix.SetTransformComponents(Vector3::ONE * 8.0, Quaternion::IDENTITY, Vector3::ZERO);
+  DALI_TEST_EQUAL(shader.GetProperty(shader.GetPropertyIndex("uMat4")).Get<Matrix>(), expectedMatrix);
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneExtras(void)
+{
+  Context ctx;
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/extras.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+  DALI_TEST_EQUAL(ctx.errors.size(), 3u);
+  DALI_TEST_CHECK(ctx.errors[0].find("already defined; overriding") != std::string::npos);
+  DALI_TEST_CHECK(ctx.errors[1].find("empty string is invalid for name") != std::string::npos);
+  DALI_TEST_CHECK(ctx.errors[2].find("failed to interpret value") != std::string::npos);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+  DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "root");
+
+  DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
+
+  ViewProjection viewProjection;
+  Transforms xforms {
+    MatrixStack{},
+    viewProjection
+  };
+  auto& resources = ctx.resources;
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+  Actor actor = scene.CreateNodes(0, choices, nodeParams);
+
+  DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("fudgeFactor")).Get<float>(), 9000.1f);
+  DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("fudgeVector")).Get<Vector2>(), Vector2(-.25f, 17.f));
+  DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("isThisTheRealLife")).Get<bool>(), true);
+  DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("isThisJustFantasy")).Get<bool>(), false);
+  DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("velocity")).Get<Vector3>(), Vector3(.1f, 58.f, -.2f));
+  DALI_TEST_EQUAL(actor.GetProperty(actor.GetPropertyIndex("frameOfReference")).Get<Matrix>(), Matrix::IDENTITY);
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderLoadSceneConstraints(void)
+{
+  Context ctx;
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/constraints.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+  DALI_TEST_EQUAL(ctx.errors.size(), 1u);
+  DALI_TEST_CHECK(ctx.errors[0].find("invalid", ctx.errors[0].find("node ID")) != std::string::npos);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+  DALI_TEST_EQUAL(scene.GetNode(0)->mName, "root");
+  DALI_TEST_EQUAL(scene.GetNode(1)->mName, "Alice");
+  DALI_TEST_EQUAL(scene.GetNode(2)->mName, "Bob");
+  DALI_TEST_EQUAL(scene.GetNode(3)->mName, "Charlie");
+
+  DALI_TEST_EQUAL(scene.GetNodeCount(), 4u);
+
+  ViewProjection viewProjection;
+  Transforms xforms {
+    MatrixStack{},
+    viewProjection
+  };
+  auto& resources = ctx.resources;
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = scene.CreateNodes(0, choices, nodeParams);
+  Actor alice = root.FindChildByName("Alice");
+  Actor bob = root.FindChildByName("Bob");
+  Actor charlie = root.FindChildByName("Charlie");
+
+  DALI_TEST_EQUAL(nodeParams.mConstrainables.size(), 3u);
+  DALI_TEST_EQUAL(bob.GetProperty(bob.GetPropertyIndex("angularVelocity")).Get<Vector2>(), Vector2(-0.5, 0.0004));
+
+  ctx.errors.clear();
+  scene.ApplyConstraints(root, std::move(nodeParams.mConstrainables), ctx.onError);
+  DALI_TEST_CHECK(ctx.errors.empty());
+
+  app.GetScene().Add(root);
+  app.SendNotification();
+  app.Render();
+  app.SendNotification();
+  app.Render();
+
+  DALI_TEST_EQUAL(charlie.GetCurrentProperty(Actor::Property::ORIENTATION), alice.GetProperty(Actor::Property::ORIENTATION));
+  DALI_TEST_EQUAL(charlie.GetCurrentProperty(Actor::Property::POSITION), bob.GetProperty(Actor::Property::POSITION));
+  DALI_TEST_EQUAL(charlie.GetCurrentProperty(charlie.GetPropertyIndex("angularVelocity")), bob.GetProperty(bob.GetPropertyIndex("angularVelocity")));
+
+  END_TEST;
+}
+
+int UtcDaliDliLoaderNodeProcessor(void)
+{
+  Context ctx;
+
+  std::vector<Property::Map> nodeMaps;
+  ctx.input.mNodePropertyProcessor = [&](const NodeDefinition&, Property::Map&& map, StringCallback) {
+    nodeMaps.push_back(map);
+  };
+
+  auto path = ctx.pathProvider(ResourceType::Mesh) + "dli/node-processor.dli";
+  DALI_TEST_CHECK(ctx.loader.LoadScene(path, ctx.loadParams));
+
+  DALI_TEST_EQUAL(nodeMaps.size(), 2u);
+  DALI_TEST_EQUAL(nodeMaps[0].Count(), 5u);
+  DALI_TEST_EQUAL(nodeMaps[0].Find("name")->Get<std::string>(), "rootA");
+  DALI_TEST_EQUAL(nodeMaps[0].Find("nickname")->Get<std::string>(), "same as name");
+  DALI_TEST_EQUAL(nodeMaps[0].Find("favourite number")->Get<int32_t>(), 63478);
+
+  auto propArray = nodeMaps[0].Find("array");
+  DALI_TEST_EQUAL(propArray->GetType(), Property::ARRAY);
+
+  auto array = propArray->GetArray();
+  DALI_TEST_EQUAL(array->Count(), 5);
+  DALI_TEST_EQUAL(array->GetElementAt(0).Get<int32_t>(), 1);
+  DALI_TEST_EQUAL(array->GetElementAt(1).Get<int32_t>(), 2);
+  DALI_TEST_EQUAL(array->GetElementAt(2).Get<int32_t>(), 4);
+  DALI_TEST_EQUAL(array->GetElementAt(3).Get<int32_t>(), 8);
+  DALI_TEST_EQUAL(array->GetElementAt(4).Get<int32_t>(), -500);
+
+  auto propObject = nodeMaps[0].Find("object");
+  DALI_TEST_EQUAL(propObject->GetType(), Property::MAP);
+
+  auto object = propObject->GetMap();
+  DALI_TEST_EQUAL(object->Count(), 5);
+  DALI_TEST_EQUAL(object->Find("physics")->Get<bool>(), true);
+  DALI_TEST_EQUAL(object->Find("elasticity")->Get<float>(), .27f);
+  DALI_TEST_EQUAL(object->Find("drag")->Get<float>(), .91f);
+
+  auto propInnerArray = object->Find("inner array");
+  DALI_TEST_EQUAL(propInnerArray->GetType(), Property::ARRAY);
+
+  auto innerArray = propInnerArray->GetArray();
+  DALI_TEST_EQUAL(innerArray->Count(), 3);
+  DALI_TEST_EQUAL(innerArray->GetElementAt(0).Get<std::string>(), "why");
+  DALI_TEST_EQUAL(innerArray->GetElementAt(1).Get<std::string>(), "not");
+  DALI_TEST_EQUAL(innerArray->GetElementAt(2).Get<bool>(), false);
+
+  auto propInnerObject = object->Find("inner object");
+  DALI_TEST_EQUAL(propInnerObject->GetType(), Property::MAP);
+
+  auto innerObject = propInnerObject->GetMap();
+  DALI_TEST_EQUAL(innerObject->Count(), 1);
+  DALI_TEST_EQUAL(innerObject->Find("supported")->Get<bool>(), true);
+
+  DALI_TEST_EQUAL(nodeMaps[1].Count(), 1u);
+  DALI_TEST_EQUAL(nodeMaps[1].Find("name")->Get<std::string>(), "rootB");
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-EnvironmentDefinition.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-EnvironmentDefinition.cpp
new file mode 100644 (file)
index 0000000..e151c6a
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/environment-definition.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliEnvironmentDefinitionLoadRawDefault(void)
+{
+  EnvironmentDefinition envDef;
+  auto rawData = envDef.LoadRaw("");
+
+  DALI_TEST_EQUAL(rawData.mDiffuse.data.size(), 6u);
+  for (auto& face: rawData.mDiffuse.data)
+  {
+    DALI_TEST_EQUAL(face.size(), 1u);
+  }
+
+  DALI_TEST_EQUAL(rawData.mSpecular.data.size(), 6u);
+  for (auto& face: rawData.mSpecular.data)
+  {
+    DALI_TEST_EQUAL(face.size(), 1u);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEnvironmentDefinitionLoadRawFail(void)
+{
+  for (auto name: { "nonexistent.ktx", TEST_RESOURCE_DIR "Cobe.obj" , TEST_RESOURCE_DIR "truncated.ktx" })
+  {
+    EnvironmentDefinition envDef { name, name };
+    DALI_TEST_ASSERTION(envDef.LoadRaw(""), "Failed to load cubemap texture");
+
+    envDef.mDiffuseMapPath = "";
+    DALI_TEST_ASSERTION(envDef.LoadRaw(""), "Failed to load cubemap texture"); // specular map still invalid
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEnvironmentDefinitionLoadRawSuccess(void)
+{
+  EnvironmentDefinition envDef { "forest_irradiance.ktx", "forest_radiance.ktx" };
+  auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");
+
+  DALI_TEST_EQUAL(rawData.mDiffuse.data.size(), 6u);
+  for (auto& face: rawData.mDiffuse.data)
+  {
+    DALI_TEST_EQUAL(face.size(), 1u);
+    uint32_t size = 64u;
+    for (auto& mipLevel : face)
+    {
+      DALI_TEST_EQUAL(mipLevel.GetPixelFormat(), Pixel::Format::RGB888);
+      DALI_TEST_EQUAL(mipLevel.GetWidth(), size);
+      DALI_TEST_EQUAL(mipLevel.GetHeight(), size);
+      size /= 2;
+    }
+  }
+
+  DALI_TEST_EQUAL(rawData.mSpecular.data.size(), 6u);
+  for (auto& face: rawData.mSpecular.data)
+  {
+    DALI_TEST_EQUAL(face.size(), 5u);
+    uint32_t size = 64u;
+    for (auto& mipLevel : face)
+    {
+      DALI_TEST_EQUAL(mipLevel.GetPixelFormat(), Pixel::Format::RGB888);
+      DALI_TEST_EQUAL(mipLevel.GetWidth(), size);
+      DALI_TEST_EQUAL(mipLevel.GetHeight(), size);
+      size /= 2;
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEnvironmentDefinitionLoadEmptyRaw(void)
+{
+  EnvironmentDefinition::RawData rawData;
+  EnvironmentDefinition envDef;
+  auto textures = envDef.Load(std::move(rawData));
+  DALI_TEST_CHECK(!textures.mDiffuse);
+  DALI_TEST_CHECK(!textures.mSpecular);
+
+  END_TEST;
+}
+
+namespace
+{
+
+void CheckTextureDefault(Texture texture)
+{
+  DALI_TEST_CHECK(texture);
+  DALI_TEST_EQUAL(texture.GetWidth(), 1u);
+  DALI_TEST_EQUAL(texture.GetHeight(), 1u);
+}
+
+void CheckTextureNotDefault(Texture texture)
+{
+  DALI_TEST_CHECK(texture);
+  DALI_TEST_CHECK(texture.GetWidth() > 1u);
+  DALI_TEST_CHECK(texture.GetHeight() > 1u);
+}
+
+}
+
+int UtcDaliEnvironmentDefinitionLoadDefault(void)
+{
+  EnvironmentDefinition envDef{};
+  auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");;
+
+  TestApplication app;
+  auto textures = envDef.Load(std::move(rawData));
+
+  CheckTextureDefault(textures.mSpecular);
+  CheckTextureDefault(textures.mDiffuse);
+
+  END_TEST;
+}
+
+int UtcDaliEnvironmentDefinitionLoadDiffuse(void)
+{
+  EnvironmentDefinition envDef{ "forest_irradiance.ktx" };
+  auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");;
+
+  TestApplication app;
+  auto textures = envDef.Load(std::move(rawData));
+
+  CheckTextureNotDefault(textures.mDiffuse);
+  CheckTextureDefault(textures.mSpecular);
+
+  END_TEST;
+}
+
+int UtcDaliEnvironmentDefinitionLoadSpecular(void)
+{
+  EnvironmentDefinition envDef{ "", "forest_radiance.ktx" };
+  auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");;
+
+  TestApplication app;
+  auto textures = envDef.Load(std::move(rawData));
+
+  CheckTextureDefault(textures.mDiffuse);
+  CheckTextureNotDefault(textures.mSpecular);
+
+  END_TEST;
+}
+
+int UtcDaliEnvironmentDefinitionLoadBoth(void)
+{
+  EnvironmentDefinition envDef{ "forest_irradiance.ktx", "forest_radiance.ktx" };
+  auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");;
+
+  TestApplication app;
+  auto textures = envDef.Load(std::move(rawData));
+
+  CheckTextureNotDefault(textures.mDiffuse);
+  CheckTextureNotDefault(textures.mSpecular);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-Gltf2Loader.cpp
new file mode 100644 (file)
index 0000000..3f829dc
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/resource-bundle.h"
+#include "dali-scene-loader/public-api/scene-definition.h"
+#include "dali-scene-loader/public-api/load-result.h"
+#include "dali-scene-loader/public-api/gltf2-loader.h"
+#include "dali-scene-loader/public-api/shader-definition-factory.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+#define DALI_TEST_THROW(expression, exception, predicate) \
+  {\
+    bool daliTestThrowSuccess__ = false;\
+    try\
+    {\
+      do { expression; } while(0);\
+      printf("No exception was thrown.\n");\
+    }\
+    catch (std::decay<exception>::type& ex)\
+    {\
+      daliTestThrowSuccess__ = predicate(ex);\
+    }\
+    catch (...)\
+    {\
+      printf("Wrong type of exception thrown.\n");\
+    }\
+    DALI_TEST_CHECK(daliTestThrowSuccess__);\
+  }
+
+namespace
+{
+struct Context
+{
+  ResourceBundle resources;
+  SceneDefinition scene;
+
+  std::vector<AnimationDefinition> animations;
+  std::vector<AnimationGroupDefinition> animationGroups;
+  std::vector<CameraParameters> cameras;
+  std::vector<LightParameters> lights;
+
+  LoadResult loadResult {
+    resources,
+    scene,
+    animations,
+    animationGroups,
+    cameras,
+    lights
+  };
+};
+
+struct ExceptionMessageStartsWith
+{
+  const std::string_view expected;
+
+  bool operator()(const std::runtime_error& e)
+  {
+    const bool success = (0 == strncmp(e.what(), expected.data(), expected.size()));
+    if (!success)
+    {
+      printf("Expected: %s, got: %s.\n", expected.data(), e.what());
+    }
+    return success;
+  }
+};
+
+}
+
+int UtcDaliGltfLoaderFailedToLoad(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+
+  DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult),
+    std::runtime_error,
+    ExceptionMessageStartsWith{"Failed to load"});
+
+  DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
+  DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
+
+  DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
+
+  DALI_TEST_EQUAL(0, ctx.cameras.size());
+  DALI_TEST_EQUAL(0, ctx.lights.size());
+  DALI_TEST_EQUAL(0, ctx.animations.size());
+  DALI_TEST_EQUAL(0, ctx.animationGroups.size());
+
+  END_TEST;
+}
+
+int UtcDaliGltfLoaderFailedToParse(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+
+  DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult),
+    std::runtime_error,
+    ExceptionMessageStartsWith{"Failed to parse"});
+
+  DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
+  DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
+
+  DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
+  DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
+
+  DALI_TEST_EQUAL(0, ctx.cameras.size());
+  DALI_TEST_EQUAL(0, ctx.lights.size());
+  DALI_TEST_EQUAL(0, ctx.animations.size());
+  DALI_TEST_EQUAL(0, ctx.animationGroups.size());
+
+  END_TEST;
+}
+
+int UtcDaliGltfLoaderSuccess1(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+
+  LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult);
+
+  DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
+  DALI_TEST_EQUAL(6u, ctx.scene.GetNodeCount());
+
+  DALI_TEST_EQUAL(0u, ctx.resources.mEnvironmentMaps.size());
+
+  auto& materials = ctx.resources.mMaterials;
+  DALI_TEST_EQUAL(2u, materials.size());
+  const MaterialDefinition materialGroundTruth[] {
+    {
+      MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+        MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
+        (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
+      0,
+      Vector4(1.f, .766f, .336f, 1.f),
+      1.f,
+      0.f,
+      {
+        { MaterialDefinition::ALBEDO,
+          { "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
+        { MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+          { "AnimatedCube_MetallicRoughness.png",
+            SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT) } },
+        { MaterialDefinition::NORMAL,
+          { "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
+      }
+    },
+    {
+      MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+        MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
+      0,
+      Vector4(1.f, .766f, .336f, 1.f),
+      1.f,
+      0.f,
+      {
+        { MaterialDefinition::ALBEDO,
+          { "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
+        { MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+          { "AnimatedCube_MetallicRoughness.png",
+            SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT) } },
+        { MaterialDefinition::NORMAL,
+          { "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
+      }
+    },
+  };
+
+  auto iMaterial = materials.begin();
+  for (auto& m : materialGroundTruth)
+  {
+    printf("material %ld\n", iMaterial - materials.begin());
+    auto& md = iMaterial->first;
+    DALI_TEST_EQUAL(md.mFlags, m.mFlags);
+    DALI_TEST_EQUAL(md.mEnvironmentIdx, m.mEnvironmentIdx);
+    DALI_TEST_EQUAL(md.mColor, m.mColor);
+    DALI_TEST_EQUAL(md.mMetallic, m.mMetallic);
+    DALI_TEST_EQUAL(md.mRoughness, m.mRoughness);
+
+    DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
+    auto iTexture = md.mTextureStages.begin();
+    for (auto& ts: m.mTextureStages)
+    {
+      printf("texture %ld\n", iTexture - md.mTextureStages.begin());
+      DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
+      DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
+      DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
+      ++iTexture;
+    }
+    ++iMaterial;
+  }
+
+  auto& meshes = ctx.resources.mMeshes;
+  DALI_TEST_EQUAL(2u, meshes.size());
+
+  using Blob = MeshDefinition::Blob;
+  using Accessor = MeshDefinition::Accessor;
+  const MeshDefinition meshGroundTruth[] {
+    {
+      0,
+      Geometry::TRIANGLES,
+      "AnimatedCube.bin",
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+    },
+    {
+      0,
+      Geometry::TRIANGLES,
+      "AnimatedCube.bin",
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+      Accessor{ Blob{ 0, 0 }, {} },
+    },
+  };
+
+  auto iMesh = meshes.begin();
+  for (auto& m : meshGroundTruth)
+  {
+    printf("mesh %ld\n", iMesh - meshes.begin());
+
+    auto& md = iMesh->first;
+    DALI_TEST_EQUAL(md.mFlags, m.mFlags);
+    DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
+    for (auto mp: {
+      &MeshDefinition::mIndices,
+      &MeshDefinition::mPositions,
+      &MeshDefinition::mNormals,
+      &MeshDefinition::mTexCoords,
+      &MeshDefinition::mTangents,
+      &MeshDefinition::mJoints0,
+      &MeshDefinition::mWeights0
+    })
+    {
+      DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
+      DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
+    }
+
+    DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
+
+    ++iMesh;
+  }
+
+  DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
+  DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
+
+  DALI_TEST_EQUAL(3u, ctx.cameras.size());
+  DALI_TEST_EQUAL(0u, ctx.lights.size());
+  DALI_TEST_EQUAL(1u, ctx.animations.size());
+  DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
+
+  END_TEST;
+}
+
+int UtcDaliGltfLoaderSuccessShort(void)
+{
+  TestApplication app;
+
+  const std::string resourcePath = TEST_RESOURCE_DIR "/";
+  auto pathProvider = [resourcePath](ResourceType::Value) {
+    return resourcePath;
+  };
+
+  Customization::Choices choices;
+  for (auto modelName : {
+    "2CylinderEngine",
+    "AnimatedMorphCube",
+    "AnimatedMorphSphere",
+    "AnimatedTriangle",
+    "BoxAnimated",
+    "CesiumMan",
+    "CesiumMilkTruck",
+    "EnvironmentTest",
+    "MetalRoughSpheres",
+    "MorphPrimitivesTest",
+    "SimpleSparseAccessor",
+  })
+  {
+    Context ctx;
+
+    ShaderDefinitionFactory sdf;
+
+    auto& resources = ctx.resources;
+    resources.mEnvironmentMaps.push_back({});
+
+    sdf.SetResources(resources);
+
+    printf("%s\n", modelName);
+    LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult);
+    DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
+
+    auto& scene = ctx.scene;
+    for (auto iRoot : scene.GetRoots())
+    {
+      struct Visitor: NodeDefinition::IVisitor
+      {
+        struct ResourceReceiver: IResourceReceiver
+        {
+          std::vector<bool> mCounts;
+
+          void Register(ResourceType::Value type, Index id) override
+          {
+            if (type == ResourceType::Mesh)
+            {
+              mCounts[id] = true;
+            }
+          }
+        } receiver;
+
+        void Start(NodeDefinition& n) override
+        {
+          if (n.mRenderable)
+          {
+            n.mRenderable->RegisterResources(receiver);
+          }
+        }
+
+        void Finish(NodeDefinition& n) override
+        {}
+      } visitor;
+      visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
+
+      scene.Visit(iRoot, choices, visitor);
+      for (uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
+      {
+        if (visitor.receiver.mCounts[i0])
+        {
+          auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
+          DALI_TEST_CHECK(!raw.mAttribs.empty());
+
+          resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
+          DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
+        }
+      }
+    }
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-KtxLoader.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-KtxLoader.cpp
new file mode 100644 (file)
index 0000000..15d6b58
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/ktx-loader.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+#include <fstream>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliKtxLoaderFailNonexistent(void)
+{
+  CubeData data;
+  DALI_TEST_CHECK(!LoadCubeMapData("non-existent.ktx", data));
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderFailInvalid1(void)
+{
+  CubeData data;
+  DALI_TEST_CHECK(!LoadCubeMapData(TEST_RESOURCE_DIR "/invalid.svg", data)); // file smaller than KTX header
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderFailInvalid2(void)
+{
+  CubeData data;
+  DALI_TEST_CHECK(!LoadCubeMapData(TEST_RESOURCE_DIR "/anim.gif", data)); // not a KTX
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderFailTruncated(void)
+{
+  CubeData data;
+  DALI_TEST_CHECK(!LoadCubeMapData(TEST_RESOURCE_DIR "/truncated.ktx", data));
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderSuccess(void)
+{
+  CubeData cubeData;
+  auto path = TEST_RESOURCE_DIR "/forest_radiance.ktx";
+  DALI_TEST_CHECK(LoadCubeMapData(path, cubeData));
+
+  DALI_TEST_EQUAL(6u, cubeData.data.size());
+  for (auto& face: cubeData.data)
+  {
+    uint32_t size = 64;
+    for (auto& mipData: face)
+    {
+      DALI_TEST_EQUAL(size, mipData.GetWidth());
+      DALI_TEST_EQUAL(size, mipData.GetHeight());
+      DALI_TEST_EQUAL(Pixel::Format::RGB888, mipData.GetPixelFormat());
+      size /= 2;
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderFormats(void)
+{
+  auto resPath = TEST_RESOURCE_DIR "/";
+#define FORMAT_PATH(x) { #x, Pixel::x }
+#define FORMAT_COMPRESSED_PATH(x) { #x, Pixel::COMPRESSED_ ## x ## _KHR }
+  std::pair<std::string, Pixel::Format> pathFormats[] {
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_4x4),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_5x4),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_5x5),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_6x5),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_6x6),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_8x5),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_8x6),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_8x8),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_10x5),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_10x6),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_10x10),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_12x10),
+    FORMAT_COMPRESSED_PATH(RGBA_ASTC_12x12),
+    FORMAT_PATH(RGB16F),
+    FORMAT_PATH(RGB32F),
+    FORMAT_PATH(RGBA8888),
+  };
+  for (auto i : pathFormats)
+  {
+    CubeData cubeData;
+    DALI_TEST_CHECK(LoadCubeMapData(resPath + i.first + ".ktx", cubeData));
+    DALI_TEST_EQUAL(cubeData.data[0][0].GetPixelFormat(), i.second);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderCubeDataCreateTexture1(void)
+{
+  uint32_t pixelBufferSize = 3;
+  uint8_t* pixelBuffer = new uint8_t[pixelBufferSize];
+
+  CubeData cubeData;
+  cubeData.data.push_back({});
+
+  auto pixelData = PixelData::New(pixelBuffer, pixelBufferSize, 1, 1, Pixel::Format::RGB888, PixelData::DELETE_ARRAY);
+  cubeData.data[0].push_back(pixelData);
+
+  TestApplication app;
+  auto texture = cubeData.CreateTexture();
+
+  DALI_TEST_CHECK(texture);
+  DALI_TEST_EQUAL(1u, texture.GetWidth());
+  DALI_TEST_EQUAL(1u, texture.GetHeight());
+
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderCubeDataCreateTexture2(void)
+{
+  CubeData cubeData;
+  auto path = TEST_RESOURCE_DIR "/forest_radiance.ktx";
+  DALI_TEST_CHECK(LoadCubeMapData(path, cubeData));
+
+  TestApplication app;
+  auto texture = cubeData.CreateTexture();
+
+  DALI_TEST_CHECK(texture);
+  DALI_TEST_EQUAL(64u, texture.GetWidth());
+  DALI_TEST_EQUAL(64u, texture.GetHeight());
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-MatrixStack.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-MatrixStack.cpp
new file mode 100644 (file)
index 0000000..776ded7
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/matrix-stack.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliMatrixStack(void)
+{
+  MatrixStack stack;
+  DALI_TEST_CHECK(stack.IsEmpty());
+
+  Matrix testMatrix;
+  testMatrix.SetTransformComponents(Vector3::ONE * 5.f,
+    Quaternion(Radian(Degree(-45.f)), Vector3::XAXIS),
+    Vector3(100.f, 0.f, -200.f));
+
+  stack.Push(testMatrix);
+  DALI_TEST_CHECK(!stack.IsEmpty());
+  DALI_TEST_EQUAL(stack.Top(), testMatrix);
+
+  stack.Push(Matrix::IDENTITY);
+  DALI_TEST_CHECK(!stack.IsEmpty());
+  DALI_TEST_EQUAL(stack.Top(), testMatrix);
+
+  stack.Push(testMatrix);
+
+  Matrix testMatrix2;
+  Matrix::Multiply(testMatrix2, testMatrix, testMatrix);
+  DALI_TEST_CHECK(!stack.IsEmpty());
+  DALI_TEST_EQUAL(stack.Top(), testMatrix2);
+
+  stack.PopAll();
+  DALI_TEST_CHECK(stack.IsEmpty());
+
+  stack.Push(Matrix::IDENTITY);
+  DALI_TEST_EQUAL(stack.Top(), Matrix::IDENTITY);
+
+  stack.Push(testMatrix);
+  DALI_TEST_EQUAL(stack.Top(), testMatrix);
+
+  stack.Pop();
+  DALI_TEST_EQUAL(stack.Top(), Matrix::IDENTITY);
+  DALI_TEST_CHECK(!stack.IsEmpty());
+
+  stack.Pop();
+  DALI_TEST_CHECK(stack.IsEmpty());
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-NodeDefinition.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-NodeDefinition.cpp
new file mode 100644 (file)
index 0000000..7f1a7cf
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/node-definition.h"
+#include "dali-scene-loader/public-api/view-projection.h"
+#include <toolkit-test-application.h>
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+
+struct Context
+{
+  ResourceBundle resources;
+
+  ViewProjection viewProjection;
+  Transforms transforms { MatrixStack{}, viewProjection };
+
+  NodeDefinition::CreateParams createParams {
+    resources,
+    transforms
+  };
+};
+
+}
+
+int UtcDaliConstraintDefinitionsCompare(void)
+{
+  ConstraintDefinition cd1{ "orientation", 0 };
+  ConstraintDefinition cd2{ "position", 1 };
+
+  DALI_TEST_CHECK(cd1 < cd2);
+  DALI_TEST_CHECK(!(cd2 < cd1));
+  DALI_TEST_CHECK(!(cd1 < cd1));
+  DALI_TEST_CHECK(!(cd2 < cd2));
+
+  DALI_TEST_CHECK(cd1 == cd1);
+  DALI_TEST_CHECK(cd2 == cd2);
+
+  ConstraintDefinition cd3{ "position", 0 };
+  ConstraintDefinition cd4{ "scale", 1 };
+  ConstraintDefinition cd5{ "position", 1 };
+  DALI_TEST_CHECK(cd2 != cd3);
+  DALI_TEST_CHECK(cd2 != cd4);
+  DALI_TEST_CHECK(cd2 == cd5);
+  DALI_TEST_CHECK(cd5 == cd2);
+
+  END_TEST;
+}
+
+int UtcDaliBlendshapeShaderConfigurationRequestsCompare(void)
+{
+  TestApplication app;
+  BlendshapeShaderConfigurationRequest bsscr1{ "", 0, Shader(nullptr) };
+
+  BlendshapeShaderConfigurationRequest bsscr2{ "", 0, Shader::New(
+    "void main(){ gl_Position = vec4(0.); }",
+    "void main(){ gl_FragColor = vec4(1.); }"
+  ) };
+
+  DALI_TEST_CHECK(bsscr1 < bsscr2);
+  DALI_TEST_CHECK(!(bsscr2 < bsscr1));
+  DALI_TEST_CHECK(!(bsscr1 < bsscr1));
+  DALI_TEST_CHECK(!(bsscr2 < bsscr2));
+
+  END_TEST;
+}
+
+int UtcDaliNodeDefinitionExtrasCompare(void)
+{
+  NodeDefinition::Extra e1{ "alpha", Vector3::XAXIS * 2.f };
+  NodeDefinition::Extra e2{ "beta", 8 };
+
+  DALI_TEST_CHECK(e1 < e2);
+  DALI_TEST_CHECK(!(e1 < e1));
+  DALI_TEST_CHECK(!(e2 < e1));
+  DALI_TEST_CHECK(!(e2 < e2));
+
+  END_TEST;
+}
+
+int UtcDaliNodeDefinitionProperties(void)
+{
+  TestApplication testApp;
+  NodeDefinition nodeDef{
+    "testRootNode",
+    Vector3{ -100.f, 100.f, -500.f },
+    Quaternion{ Radian(Degree(45.f)), Vector3::ZAXIS },
+    Vector3{ 2.f, 4.f, 8.f },
+    Vector3{ 100.f, 50.f, 25.f },
+    false,
+  };
+
+  Quaternion frobnicateFactor(0.f, 1.f, 2.f, 3.f);
+  frobnicateFactor.Normalize(); // because it will be (by DALi) once it's set as a property.
+  nodeDef.mExtras.push_back(NodeDefinition::Extra{ "frobnicateFactor", frobnicateFactor });
+
+  Context ctx;
+  auto actor = nodeDef.CreateActor(ctx.createParams);
+  DALI_TEST_EQUAL(nodeDef.mName, actor.GetProperty(Actor::Property::NAME).Get<std::string>());
+  DALI_TEST_EQUAL(nodeDef.mPosition, actor.GetProperty(Actor::Property::POSITION).Get<Vector3>());
+  DALI_TEST_EQUAL(nodeDef.mOrientation, actor.GetProperty(Actor::Property::ORIENTATION).Get<Quaternion>());
+  DALI_TEST_EQUAL(nodeDef.mScale, actor.GetProperty(Actor::Property::SCALE).Get<Vector3>());
+  DALI_TEST_EQUAL(nodeDef.mSize, actor.GetProperty(Actor::Property::SIZE).Get<Vector3>());
+  DALI_TEST_EQUAL(nodeDef.mIsVisible, actor.GetProperty(Actor::Property::VISIBLE).Get<bool>());
+
+  Property::Index propFrobnicateFactor = actor.GetPropertyIndex("frobnicateFactor");
+  DALI_TEST_CHECK(propFrobnicateFactor != Property::INVALID_INDEX);
+
+  auto frobnicateFactorValue = actor.GetProperty(propFrobnicateFactor);
+  DALI_TEST_EQUAL(Property::ROTATION, frobnicateFactorValue.GetType());
+  DALI_TEST_EQUAL(frobnicateFactorValue.Get<Quaternion>(), frobnicateFactor);
+
+  DALI_TEST_EQUAL(0, actor.GetChildCount());
+  DALI_TEST_EQUAL(0, actor.GetRendererCount());
+
+  END_TEST;
+}
+
+int UtcDaliNodeDefinitionRenderableRegisterResources(void)
+{
+  NodeDefinition nodeDef;
+
+  auto renderable = new NodeDefinition::Renderable();
+  renderable->mShaderIdx = 0;
+  nodeDef.mRenderable.reset(renderable);
+
+  struct : IResourceReceiver
+  {
+    std::vector<Index> shaders;
+    uint32_t otherResources = 0;
+
+    void Register(ResourceType::Value type, Index id) override
+    {
+      switch(type)
+      {
+      case ResourceType::Shader:
+        shaders.push_back(id);
+        break;
+
+      default:
+        ++otherResources;
+      }
+    }
+  } resourceReceiver;
+
+  nodeDef.mRenderable->RegisterResources(resourceReceiver);
+  DALI_TEST_EQUAL(1u, resourceReceiver.shaders.size());
+  DALI_TEST_EQUAL(0, resourceReceiver.shaders[0]);
+  DALI_TEST_EQUAL(0, resourceReceiver.otherResources);
+
+  END_TEST;
+}
+
+int UtcDaliNodeDefinitionRenderableReflectResources(void)
+{
+  NodeDefinition nodeDef;
+
+  auto renderable = new NodeDefinition::Renderable();
+  renderable->mShaderIdx = 0;
+  nodeDef.mRenderable.reset(renderable);
+
+  struct : IResourceReflector
+  {
+    std::vector<Index*> shaders;
+    uint32_t otherResources = 0;
+
+    void Reflect(ResourceType::Value type, Index& id) override
+    {
+      switch(type)
+      {
+      case ResourceType::Shader:
+        shaders.push_back(&id);
+        break;
+
+      default:
+        ++otherResources;
+      }
+    }
+  } resourceReflector;
+
+  nodeDef.mRenderable->ReflectResources(resourceReflector);
+  DALI_TEST_EQUAL(1u, resourceReflector.shaders.size());
+  DALI_TEST_EQUAL(&renderable->mShaderIdx, resourceReflector.shaders[0]);
+  DALI_TEST_EQUAL(0, resourceReflector.otherResources);
+
+  END_TEST;
+}
+
+int UtcDaliNodeDefinitionRenderable(void)
+{
+  TestApplication testApp;
+  NodeDefinition nodeDef;
+
+  auto renderable = new NodeDefinition::Renderable();
+  renderable->mShaderIdx = 0;
+  nodeDef.mRenderable.reset(renderable);
+
+  Context ctx;
+  const auto VSH = "void main() { gl_Position = vec4(0.); }";
+  const auto FSH = "void main() { gl_FragColor = vec4(1.); }";
+  auto shader = Shader::New(VSH, FSH);
+  ctx.resources.mShaders.push_back({ ShaderDefinition{}, shader });
+
+  auto actor = nodeDef.CreateActor(ctx.createParams);
+  DALI_TEST_EQUAL(1, actor.GetRendererCount());
+
+  auto renderer = actor.GetRendererAt(0);
+  DALI_TEST_EQUAL(renderer.GetShader(), shader);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-RendererState.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-RendererState.cpp
new file mode 100644 (file)
index 0000000..a6f6251
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/renderer-state.h"
+#include "dali-scene-loader/public-api/parse-renderer-state.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace sl = SceneLoader;
+namespace rs = RendererState;
+
+int UtcDaliRendererStateFromBlendFactors(void)
+{
+  rs::Type state = rs::FromBlendFactors(sl::BlendFactor::ZERO, sl::BlendFactor::ONE,
+    sl::BlendFactor::SRC_COLOR, sl::BlendFactor::ONE_MINUS_SRC_COLOR);
+
+  DALI_TEST_EQUAL((state >> rs::BLEND_FACTOR_BASE_SHIFT) & rs::BLEND_FACTOR_ITEM_MASK, rs::Type(sl::BlendFactor::ZERO));
+  DALI_TEST_EQUAL((state >> (rs::BLEND_FACTOR_BASE_SHIFT + rs::BLEND_FACTOR_ITEM_BITS)) &
+    rs::BLEND_FACTOR_ITEM_MASK, rs::Type(sl::BlendFactor::ONE));
+  DALI_TEST_EQUAL((state >> (rs::BLEND_FACTOR_BASE_SHIFT + rs::BLEND_FACTOR_ITEM_BITS * 2)) &
+    rs::BLEND_FACTOR_ITEM_MASK, rs::Type(sl::BlendFactor::SRC_COLOR));
+  DALI_TEST_EQUAL((state >> (rs::BLEND_FACTOR_BASE_SHIFT + rs::BLEND_FACTOR_ITEM_BITS * 3)) &
+    rs::BLEND_FACTOR_ITEM_MASK, rs::Type(sl::BlendFactor::ONE_MINUS_SRC_COLOR));
+
+  END_TEST;
+}
+
+#define HELP_TEST_RENDERER_STATE(property, resetValue, state, checkValue, renderer)\
+  renderer.SetProperty(property, ~(resetValue));\
+  rs::Apply((state), (renderer));\
+  printf("%s %s vs %s\n", #property, #state, #checkValue);\
+  DALI_TEST_EQUAL(renderer.GetProperty(property).Get<decltype(checkValue)>(), (checkValue));
+
+int UtcDaliRendererStateApply(void)
+{
+  TestApplication app;
+  auto vsh = "void main() { gl_Position = vec4(0.); }";
+  auto fsh = "void main() { gl_FragColor = vec4(1.); }";
+  Geometry geom = Geometry::New();
+  Shader shader = Shader::New(vsh, fsh);
+  Renderer renderer = Renderer::New(geom, shader);
+
+  HELP_TEST_RENDERER_STATE(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF, rs::DEPTH_WRITE, DepthWriteMode::ON, renderer);
+  HELP_TEST_RENDERER_STATE(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::OFF, rs::DEPTH_TEST, DepthTestMode::ON, renderer);
+
+  HELP_TEST_RENDERER_STATE(Renderer::Property::BLEND_MODE, BlendMode::OFF, rs::ALPHA_BLEND, BlendMode::ON, renderer);
+
+  HELP_TEST_RENDERER_STATE(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::NONE, rs::CULL_FRONT, FaceCullingMode::FRONT, renderer);
+  HELP_TEST_RENDERER_STATE(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::NONE, rs::CULL_BACK, FaceCullingMode::BACK, renderer);
+  HELP_TEST_RENDERER_STATE(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::NONE, rs::CULL_FRONT | rs::CULL_BACK,
+    FaceCullingMode::FRONT_AND_BACK, renderer);
+
+#define DEPTH_FUNC_PAIR(x) { Comparison::x << rs::DEPTH_FUNCTION_SHIFT, DepthFunction::x }
+  const std::pair<rs::Type, DepthFunction::Type> depthFunctionPairs[] {
+    DEPTH_FUNC_PAIR(NEVER),
+    DEPTH_FUNC_PAIR(ALWAYS),
+    DEPTH_FUNC_PAIR(LESS),
+    DEPTH_FUNC_PAIR(GREATER),
+    DEPTH_FUNC_PAIR(EQUAL),
+    DEPTH_FUNC_PAIR(NOT_EQUAL),
+    DEPTH_FUNC_PAIR(LESS_EQUAL),
+    DEPTH_FUNC_PAIR(GREATER_EQUAL),
+  };
+#undef DEPTH_FUNC_PAIR
+  for (auto& p : depthFunctionPairs)
+  {
+    HELP_TEST_RENDERER_STATE(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS, p.first, p.second, renderer);
+  }
+
+#define BLEND_FACTOR_PAIR(x) { sl::BlendFactor::x, BlendFactor::x }
+  const std::pair<rs::Type, BlendFactor::Type> BLEND_FACTORS[] {
+    BLEND_FACTOR_PAIR(ZERO),
+    BLEND_FACTOR_PAIR(ONE),
+    BLEND_FACTOR_PAIR(SRC_COLOR),
+    BLEND_FACTOR_PAIR(ONE_MINUS_SRC_COLOR),
+    BLEND_FACTOR_PAIR(SRC_ALPHA),
+    BLEND_FACTOR_PAIR(ONE_MINUS_SRC_ALPHA),
+    BLEND_FACTOR_PAIR(DST_COLOR),
+    BLEND_FACTOR_PAIR(ONE_MINUS_DST_COLOR),
+    BLEND_FACTOR_PAIR(DST_ALPHA),
+    BLEND_FACTOR_PAIR(ONE_MINUS_DST_ALPHA),
+    BLEND_FACTOR_PAIR(SRC_ALPHA_SATURATE),
+    BLEND_FACTOR_PAIR(CONSTANT_COLOR),
+    BLEND_FACTOR_PAIR(ONE_MINUS_CONSTANT_COLOR),
+    BLEND_FACTOR_PAIR(CONSTANT_ALPHA),
+    BLEND_FACTOR_PAIR(ONE_MINUS_CONSTANT_ALPHA),
+  };
+#undef BLEND_FACTOR_PAIR
+  for (auto property: {
+    Renderer::Property::BLEND_FACTOR_SRC_RGB,
+    Renderer::Property::BLEND_FACTOR_DEST_RGB,
+    Renderer::Property::BLEND_FACTOR_SRC_ALPHA,
+    Renderer::Property::BLEND_FACTOR_DEST_ALPHA,
+  })
+  {
+    const auto itemShift = rs::BLEND_FACTOR_ITEM_BITS * (property - Renderer::Property::BLEND_FACTOR_SRC_RGB);
+    const auto shift = rs::BLEND_FACTOR_BASE_SHIFT + itemShift;
+    for (auto& value: BLEND_FACTORS)
+    {
+      HELP_TEST_RENDERER_STATE(property, BlendFactor::ZERO, value.first << shift, value.second, renderer);
+    }
+  }
+
+#define RENDER_MODE_PAIR(x) { BufferMode::x << rs::BUFFER_MODE_SHIFT, RenderMode::x }
+  std::pair<rs::Type, RenderMode::Type> renderModePairs[] {
+    // same as our reset value: RENDER_MODE_PAIR(NONE),
+    RENDER_MODE_PAIR(AUTO),
+    RENDER_MODE_PAIR(COLOR),
+    RENDER_MODE_PAIR(STENCIL),
+    RENDER_MODE_PAIR(COLOR_STENCIL),
+  };
+#undef RENDER_MODE_PAIR
+  for (auto& p: renderModePairs)
+  {
+    HELP_TEST_RENDERER_STATE(Renderer::Property::RENDER_MODE, RenderMode::NONE, p.first, p.second, renderer);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliRendererStateParseEmpty(void)
+{
+  std::string error;
+  auto onError = [&](const std::string& e) { error = e; };
+
+  DALI_TEST_EQUAL(rs::Parse("", 0, onError), uint32_t(rs::NONE));
+  DALI_TEST_CHECK(error.empty());
+  END_TEST;
+}
+
+int UtcDaliRendererStateParseInvalid(void)
+{
+  std::string error;
+  auto onError = [&](const std::string& e) { error = e; };
+
+  DALI_TEST_EQUAL(rs::Parse("definitelyNotAValidRendererState", 0, onError), uint32_t(rs::NONE));
+  DALI_TEST_CHECK(strstr(error.c_str(), "Not a valid RendererState") != nullptr);
+  END_TEST;
+}
+
+namespace
+{
+struct Option
+{
+  std::string_view name;
+  rs::Type expected;
+
+  void Apply(std::ostream& stream, uint8_t shift, uint32_t& result) const
+  {
+    stream << name;
+    result |= expected << shift;
+  }
+};
+
+struct StateGenerator
+{
+  std::string_view name;
+
+  uint8_t shift;
+  std::vector<Option> permutations;
+};
+
+#define STRING_STATE_PAIR(x, y) { #x, y::x }
+const decltype(StateGenerator::permutations) BLEND_FACTORS {
+  { "", sl::BlendFactor::OMIT },
+  STRING_STATE_PAIR(ZERO, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE, sl::BlendFactor),
+  STRING_STATE_PAIR(SRC_COLOR, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE_MINUS_SRC_COLOR, sl::BlendFactor),
+  STRING_STATE_PAIR(SRC_ALPHA, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE_MINUS_SRC_ALPHA, sl::BlendFactor),
+  STRING_STATE_PAIR(DST_COLOR, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE_MINUS_DST_COLOR, sl::BlendFactor),
+  STRING_STATE_PAIR(DST_ALPHA, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE_MINUS_DST_ALPHA, sl::BlendFactor),
+  STRING_STATE_PAIR(SRC_ALPHA_SATURATE, sl::BlendFactor),
+  STRING_STATE_PAIR(CONSTANT_COLOR, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE_MINUS_CONSTANT_COLOR, sl::BlendFactor),
+  STRING_STATE_PAIR(CONSTANT_ALPHA, sl::BlendFactor),
+  STRING_STATE_PAIR(ONE_MINUS_CONSTANT_ALPHA, sl::BlendFactor),
+};
+
+const StateGenerator PERMUTATORS[] {
+  { "DEPTH_FUNC:", rs::DEPTH_FUNCTION_SHIFT, {
+    { "", Comparison::OMIT },
+    STRING_STATE_PAIR(NEVER, Comparison),
+    STRING_STATE_PAIR(ALWAYS, Comparison),
+    STRING_STATE_PAIR(LESS, Comparison),
+    STRING_STATE_PAIR(GREATER, Comparison),
+    STRING_STATE_PAIR(EQUAL, Comparison),
+    STRING_STATE_PAIR(NOT_EQUAL, Comparison),
+    STRING_STATE_PAIR(LESS_EQUAL, Comparison),
+    STRING_STATE_PAIR(GREATER_EQUAL, Comparison),
+  } },
+  { "BLEND_SRC_RGB:", rs::BLEND_FACTOR_BASE_SHIFT, BLEND_FACTORS },
+  { "BLEND_DST_RGB:", rs::BLEND_FACTOR_BASE_SHIFT + rs::BLEND_FACTOR_ITEM_BITS, BLEND_FACTORS  },
+  { "BLEND_SRC_ALPHA:", rs::BLEND_FACTOR_BASE_SHIFT + rs::BLEND_FACTOR_ITEM_BITS * 2, BLEND_FACTORS },
+  { "BLEND_DST_ALPHA:", rs::BLEND_FACTOR_BASE_SHIFT + rs::BLEND_FACTOR_ITEM_BITS * 3, BLEND_FACTORS },
+  { "BUFFER_MODE:", rs::BUFFER_MODE_SHIFT, {
+    { "", BufferMode::OMIT },
+    STRING_STATE_PAIR(NONE, BufferMode),
+    STRING_STATE_PAIR(AUTO, BufferMode),
+    STRING_STATE_PAIR(COLOR, BufferMode),
+    STRING_STATE_PAIR(STENCIL, BufferMode),
+    STRING_STATE_PAIR(COLOR_STENCIL, BufferMode),
+  } },
+  // binary options
+  { "", 0, { STRING_STATE_PAIR(DEPTH_WRITE, rs) } },
+  { "", 0, { STRING_STATE_PAIR(DEPTH_TEST, rs) } },
+  { "", 0, { STRING_STATE_PAIR(CULL_FRONT, rs) } },
+  { "", 0, { STRING_STATE_PAIR(CULL_BACK, rs) } },
+  { "", 0, { STRING_STATE_PAIR(ALPHA_BLEND, rs) } },
+};
+
+#undef STRING_STATE_PAIR
+}
+
+int UtcDaliRendererStateParseIndividual(void)
+{
+  std::string error;
+  auto onError = [&](const std::string& e) { error = e; };
+
+  char buffer[512] {};
+  for (auto& p: PERMUTATORS)
+  {
+    for (auto& o: p.permutations)
+    {
+      StreamBuffer streamBuf(buffer, sizeof(buffer));
+      std::ostream stream(&streamBuf);
+
+      stream << p.name;
+
+      uint32_t expected = 0x0;
+      o.Apply(stream, p.shift, expected);
+      stream << '\0';
+
+      printf("%s -> %d\n", buffer, expected);
+      DALI_TEST_EQUAL(rs::Parse(buffer, 0, onError), expected);
+      DALI_TEST_CHECK(error.empty());
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliRendererStateParseCombined(void)
+{
+  constexpr uint32_t count = std::extent<decltype(PERMUTATORS)>::value;
+  constexpr uint32_t prime = 13;
+  static_assert(prime > count);
+  constexpr uint32_t skip = 3 * count * count + 7 * count + 1;
+  static_assert(skip % prime != 0);
+
+  std::string error;
+  auto onError = [&](const std::string& e) { error = e; };
+
+  std::vector<rs::Type> expectedValues;
+
+  char buffer[512] {};
+  for (uint32_t i = 0; i < count; ++i)
+  {
+    StreamBuffer streamBuf(buffer, sizeof(buffer));
+    std::ostream stream(&streamBuf);
+
+    uint32_t expected = 0x0;
+
+    uint32_t iTmp = i;
+    for (uint32_t j = 0; j < count; ++j)
+    {
+      iTmp = (iTmp + skip) % count;
+      DALI_TEST_CHECK(iTmp < count);
+
+      if (expected)
+      {
+        stream << "|";
+      }
+
+      auto& perm = PERMUTATORS[iTmp];
+      stream << perm.name;
+      perm.permutations.back().Apply(stream, perm.shift, expected);
+    }
+
+    stream << '\0';
+
+    DALI_TEST_EQUAL(rs::Parse(buffer, 0, onError), expected);
+    DALI_TEST_CHECK(error.empty());
+
+    auto iFind = std::lower_bound(expectedValues.begin(), expectedValues.end(), expected);
+    if (iFind == expectedValues.end() || *iFind != expected)
+    {
+      expectedValues.insert(iFind, expected);
+    }
+    DALI_TEST_EQUAL(expectedValues.size(), 1u);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-ResourceBundle.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-ResourceBundle.cpp
new file mode 100644 (file)
index 0000000..8f03828
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/resource-bundle.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliResourceRefCounts(void)
+{
+  ResourceBundle resourceBundle;
+  resourceBundle.mEnvironmentMaps.resize(4);
+  resourceBundle.mShaders.resize(13);
+  resourceBundle.mMeshes.resize(17);
+  resourceBundle.mMaterials.resize(19);
+
+  int i = 0;
+  std::vector<int> testEnvironmentReferences(resourceBundle.mEnvironmentMaps.size());
+  for (auto& m : resourceBundle.mMaterials)
+  {
+    Index iEnv = 0;
+    iEnv += (i % 3) == 0;
+    iEnv += ((i % 4) == 0) * 2;
+    m.first.mEnvironmentIdx = iEnv;
+
+    printf("%d : %d, ", i, iEnv);
+
+    ++testEnvironmentReferences[iEnv];
+    ++i;
+  }
+
+  auto counter = resourceBundle.CreateRefCounter();
+  DALI_TEST_EQUAL(counter[ResourceType::Environment].Size(), resourceBundle.mEnvironmentMaps.size());
+  DALI_TEST_EQUAL(counter[ResourceType::Shader].Size(), resourceBundle.mShaders.size());
+  DALI_TEST_EQUAL(counter[ResourceType::Mesh].Size(), resourceBundle.mMeshes.size());
+  DALI_TEST_EQUAL(counter[ResourceType::Material].Size(), resourceBundle.mMaterials.size());
+
+  std::fill(counter[ResourceType::Material].begin(), counter[ResourceType::Material].end(), 1u);
+  resourceBundle.CountEnvironmentReferences(counter);
+  i = 0;
+  for (auto& er: counter[ResourceType::Environment])
+  {
+    DALI_TEST_EQUAL(er, testEnvironmentReferences[i]);
+    ++i;
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-SceneDefinition.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-SceneDefinition.cpp
new file mode 100644 (file)
index 0000000..9b163bd
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/scene-definition.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliSceneDefinitionAddNode(void)
+{
+  SceneDefinition sceneDef;
+
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 0u);
+  auto node = new NodeDefinition();
+  node->mName = "First";
+
+  auto result = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ node });
+  DALI_TEST_EQUAL(result, node);
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 1u);
+  DALI_TEST_EQUAL(sceneDef.GetNode(0), node);
+  DALI_TEST_EQUAL(sceneDef.FindNode(node->mName), node);
+
+  auto node2 = new NodeDefinition();
+  node2->mName = node->mName;
+  result = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ node2 });
+  DALI_TEST_EQUAL(result, static_cast<NodeDefinition*>(nullptr)); // failed
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 1u); // still
+  DALI_TEST_EQUAL(sceneDef.GetNode(0), node); // still
+  DALI_TEST_EQUAL(sceneDef.FindNode(node->mName), node); // still
+
+  auto child = new NodeDefinition();
+  child->mName = "Second";
+  child->mParentIdx = 0;
+
+  DALI_TEST_CHECK(node->mChildren.empty()); // these are hooked up by AddNode, base on parent idx.
+
+  result = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ child });
+  DALI_TEST_EQUAL(result, child);
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 2u);
+  DALI_TEST_EQUAL(sceneDef.GetNode(1), child);
+  DALI_TEST_EQUAL(sceneDef.FindNode(child->mName), child);
+
+  DALI_TEST_EQUAL(node->mChildren[0], 1u); // these are hooked up by AddNode, base on parent idx.
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionAddRootsFail(void)
+{
+  SceneDefinition sceneDef;
+
+  DALI_TEST_ASSERTION(sceneDef.AddRootNode(0), "index out of bounds");
+  DALI_TEST_CHECK(sceneDef.GetRoots().empty());
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 0u);
+
+  END_TEST;
+}
+
+namespace
+{
+
+struct TestContext
+{
+  SceneDefinition sceneDef;
+  NodeDefinition* root;
+  NodeDefinition* childA;
+  NodeDefinition* childB;
+
+  TestContext()
+  : sceneDef{},
+    root{ new NodeDefinition{ "Root" }},
+    childA{ new NodeDefinition{ "A" }},
+    childB{ new NodeDefinition{ "B" }}
+  {
+    childA->mParentIdx = 0;
+    childB->mParentIdx = 0;
+
+    root = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ root });
+    childA = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ childA });
+    childB = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ childB });
+  }
+};
+
+enum Event
+{
+  DEFAULT = -1,
+  START,
+  FINISH
+};
+
+struct NodeVisitor : NodeDefinition::IVisitor
+{
+  struct Visit
+  {
+    Event event;
+    NodeDefinition* node;
+
+    bool operator==(const Visit& other) const
+    {
+      return event == other.event && node == other.node;
+    }
+  };
+
+  void Start(NodeDefinition& n) override
+  {
+    visits.push_back({ START, &n });
+  }
+
+  void Finish(NodeDefinition& n) override
+  {
+    visits.push_back({ FINISH, &n });
+  }
+
+  std::vector<Visit> visits;
+};
+
+struct ConstNodeVisitor : NodeDefinition::IConstVisitor
+{
+  struct Visit
+  {
+    Event  event;
+    const NodeDefinition* node;
+
+    bool operator==(const Visit& other) const
+    {
+      return event == other.event && node == other.node;
+    }
+  };
+
+  void Start(const NodeDefinition& n) override
+  {
+    visits.push_back({ START, &n });
+  }
+
+  void Finish(const NodeDefinition& n) override
+  {
+    visits.push_back({ FINISH, &n });
+  }
+
+  std::vector<Visit> visits;
+};
+
+}
+
+int UtcDaliSceneDefinitionAddRemoveRootNode(void)
+{
+  TestContext ctx;
+
+  DALI_TEST_EQUAL(ctx.sceneDef.AddRootNode(0), 0);
+  DALI_TEST_EQUAL(ctx.sceneDef.GetRoots().size(), 1u);
+  DALI_TEST_EQUAL(ctx.sceneDef.GetRoots()[0], 0);
+
+  ctx.sceneDef.RemoveRootNode(0);
+  DALI_TEST_EQUAL(ctx.sceneDef.GetRoots().size(), 0);
+
+  DALI_TEST_EQUAL(ctx.sceneDef.GetNodeCount(), 3u);
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionVisit(void)
+{
+  TestContext ctx;
+
+  NodeVisitor visitor;
+  ctx.sceneDef.Visit(0, Customization::Choices{}, visitor);
+
+  const NodeVisitor::Visit expected[] {
+    { START, ctx.root },
+    { START, ctx.childA },
+    { FINISH, ctx.childA },
+    { START, ctx.childB },
+    { FINISH, ctx.childB },
+    { FINISH, ctx.root },
+  };
+  DALI_TEST_CHECK(std::equal(visitor.visits.begin(), visitor.visits.end(), expected));
+
+  END_TEST;
+};
+
+int UtcDaliSceneDefinitionConstVisit(void)
+{
+  TestContext ctx;
+
+  ConstNodeVisitor visitor;
+  ctx.sceneDef.Visit(0, Customization::Choices{}, visitor);
+
+  const ConstNodeVisitor::Visit expected[] {
+    { START, ctx.root },
+    { START, ctx.childA },
+    { FINISH, ctx.childA },
+    { START, ctx.childB },
+    { FINISH, ctx.childB },
+    { FINISH, ctx.root },
+  };
+  DALI_TEST_CHECK(std::equal(visitor.visits.begin(), visitor.visits.end(), expected));
+
+  END_TEST;
+};
+
+int UtcDaliSceneDefinitionVisitCustomized(void)
+{
+  TestContext ctx;
+
+  ctx.root->mCustomization.reset(new NodeDefinition::CustomizationDefinition{ "A/B" });
+
+  const NodeVisitor::Visit expected[] {
+    { START, ctx.root },
+    { START, ctx.childB },
+    { FINISH, ctx.childB },
+    { FINISH, ctx.root },
+  };
+
+  Customization::Choices choices;
+  for (auto i : { 1, 2 })
+  {
+    choices.Set("A/B", i);
+
+    NodeVisitor visitor;
+    ctx.sceneDef.Visit(0, choices, visitor);
+
+    DALI_TEST_CHECK(std::equal(visitor.visits.begin(), visitor.visits.end(), std::begin(expected)));
+  }
+
+  END_TEST;
+};
+
+int UtcDaliSceneDefinitionConstVisitCustomized(void)
+{
+  TestContext ctx;
+
+  ctx.root->mCustomization.reset(new NodeDefinition::CustomizationDefinition{ "A/B" });
+
+  const ConstNodeVisitor::Visit expected[] {
+    { START, ctx.root },
+    { START, ctx.childB },
+    { FINISH, ctx.childB },
+    { FINISH, ctx.root },
+  };
+
+  Customization::Choices choices;
+  for (auto i : { 1, 2 })
+  {
+    choices.Set("A/B", i);
+
+    ConstNodeVisitor visitor;
+    ctx.sceneDef.Visit(0, choices, visitor);
+
+    DALI_TEST_CHECK(std::equal(visitor.visits.begin(), visitor.visits.end(), std::begin(expected)));
+  }
+
+  END_TEST;
+};
+
+int UtcDaliSceneDefinitionGetCustomizationOptions(void)
+{
+  TestContext ctx;
+
+  ctx.sceneDef.AddRootNode(0); // GetCustomizationOptions requires this.
+
+  ctx.root->mCustomization.reset(new NodeDefinition::CustomizationDefinition{ "A/B" });
+  ctx.childA->mCustomization.reset(new NodeDefinition::CustomizationDefinition{ "hello" });
+  ctx.childB->mCustomization.reset(new NodeDefinition::CustomizationDefinition{ "goodbye" });
+
+  Customization::Choices choices;
+  Customization::Map options;
+  ctx.sceneDef.GetCustomizationOptions(choices, options, &choices);
+
+  DALI_TEST_EQUAL(choices.Size(), 2u);
+  DALI_TEST_EQUAL(options.Size(), 2u);
+
+  struct TestOption
+  {
+    std::string name;
+    Customization customization;
+    Customization::OptionType choice;
+  };
+
+  std::vector<TestOption> testOptions {
+    { "A/B", { 2, { "Root" } }, 0 },
+    { "hello", { 0, { "A" } }, 0 },
+  };
+  for (auto& testOption: testOptions)
+  {
+    auto iFind = choices.Get(testOption.name);
+    DALI_TEST_EQUAL(iFind, testOption.choice);
+
+    auto iFindOption = options.Get(testOption.name);
+    DALI_TEST_CHECK(iFindOption != nullptr);
+    DALI_TEST_EQUAL(iFindOption->numOptions, testOption.customization.numOptions);
+    DALI_TEST_EQUAL(iFindOption->nodes.size(), testOption.customization.nodes.size());
+    DALI_TEST_CHECK(std::equal(iFindOption->nodes.begin(), iFindOption->nodes.end(),
+      testOption.customization.nodes.begin()));
+  }
+
+  choices.Clear();
+  choices.Set("A/B", 1);
+  *options.Get("A/B") = {};
+
+  testOptions[0].choice = 1;
+  testOptions[1].name = "goodbye";
+  testOptions[1].customization.nodes[0] = "B";
+
+  ctx.sceneDef.GetCustomizationOptions(choices, options, &choices);
+
+  DALI_TEST_EQUAL(choices.Size(), 2u);
+  DALI_TEST_EQUAL(options.Size(), 3u);
+
+  for (auto& testOption: testOptions)
+  {
+    auto iFind = choices.Get(testOption.name);
+    DALI_TEST_EQUAL(iFind, testOption.choice);
+
+    auto iFindOption = options.Get(testOption.name);
+    DALI_TEST_CHECK(iFindOption != nullptr);
+    DALI_TEST_EQUAL(iFindOption->numOptions, testOption.customization.numOptions);
+    DALI_TEST_EQUAL(iFindOption->nodes.size(), testOption.customization.nodes.size());
+    DALI_TEST_CHECK(std::equal(iFindOption->nodes.begin(), iFindOption->nodes.end(),
+      testOption.customization.nodes.begin()));
+  }
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionFindNode(void)
+{
+  TestContext ctx;
+
+  Index result = INVALID_INDEX;
+  for (auto n: { ctx.root, ctx.childA, ctx.childB })
+  {
+    ctx.sceneDef.FindNode(n->mName, &result);
+    DALI_TEST_CHECK(result != INVALID_INDEX);
+    DALI_TEST_EQUAL(ctx.sceneDef.GetNode(result), n);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionConstFindNode(void)
+{
+  TestContext ctx;
+
+  Index result = INVALID_INDEX;
+  for (auto n: { ctx.root, ctx.childA, ctx.childB })
+  {
+    const_cast<const TestContext&>(ctx).sceneDef.FindNode(n->mName, &result);
+    DALI_TEST_CHECK(result != INVALID_INDEX);
+    DALI_TEST_EQUAL(ctx.sceneDef.GetNode(result), n);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionFindNodeIndex(void)
+{
+  TestContext ctx;
+
+  Index result = INVALID_INDEX;
+  for (auto n: { ctx.root, ctx.childA, ctx.childB })
+  {
+    result = ctx.sceneDef.FindNodeIndex(*n);
+    DALI_TEST_CHECK(result != INVALID_INDEX);
+    DALI_TEST_EQUAL(ctx.sceneDef.GetNode(result), n);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionFindNodes(void)
+{
+  TestContext ctx;
+
+  std::vector<NodeDefinition*> nodes;
+  auto nodeConsumer = [&nodes](NodeDefinition& nd) {
+    nodes.push_back(&nd);
+  };
+
+  auto nodePredicate = [](const NodeDefinition& nd) {
+    return nd.mName.length() == 1;
+  };
+
+  ctx.sceneDef.FindNodes(nodePredicate, nodeConsumer, 1);
+  DALI_TEST_EQUAL(nodes.size(), 1);
+  DALI_TEST_EQUAL(nodes[0]->mName, "A");
+  DALI_TEST_EQUAL(nodes[0], ctx.childA);
+
+  nodes.clear();
+  ctx.sceneDef.FindNodes(nodePredicate, nodeConsumer);
+
+  DALI_TEST_EQUAL(nodes.size(), 2);
+  DALI_TEST_EQUAL(nodes[0]->mName, "A");
+  DALI_TEST_EQUAL(nodes[0], ctx.childA);
+  DALI_TEST_EQUAL(nodes[1]->mName, "B");
+  DALI_TEST_EQUAL(nodes[1], ctx.childB);
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionRemoveNode(void)
+{
+  TestContext ctx;
+  DALI_TEST_EQUAL(ctx.sceneDef.RemoveNode("doesn't exist"), false);
+
+  // pre-removing A
+  DALI_TEST_EQUAL(ctx.sceneDef.GetNodeCount(), 3u);
+  DALI_TEST_EQUAL(ctx.root->mChildren.size(), 2u);
+
+  Index result;
+  DALI_TEST_EQUAL(ctx.sceneDef.FindNode("B", &result), ctx.childB);
+  DALI_TEST_EQUAL(result, 2);
+
+  DALI_TEST_EQUAL(ctx.sceneDef.RemoveNode("A"), true);
+
+  // post-removing A
+  DALI_TEST_EQUAL(ctx.sceneDef.GetNodeCount(), 2u);
+
+  result = 12345;
+  DALI_TEST_EQUAL(ctx.sceneDef.FindNode("A", &result), static_cast<NodeDefinition*>(nullptr));
+  DALI_TEST_EQUAL(result, 12345); // doesn't change
+
+  DALI_TEST_EQUAL(ctx.sceneDef.FindNode("B", &result), ctx.childB);
+  DALI_TEST_EQUAL(result, 1); // dropped
+
+  DALI_TEST_EQUAL(ctx.root->mChildren.size(), 1u);
+  DALI_TEST_EQUAL(ctx.root->mChildren[0], 1u);
+
+  // removing root
+  DALI_TEST_EQUAL(ctx.sceneDef.RemoveNode("Root"), true);
+  DALI_TEST_EQUAL(ctx.sceneDef.GetNodeCount(), 0);
+
+  END_TEST;
+}
+
+int UtcDaliSceneDefinitionReparentNode(void)
+{
+  TestContext ctx;
+
+  ctx.sceneDef.ReparentNode("B", "A", 0);
+
+  DALI_TEST_EQUAL(ctx.childB->mParentIdx, ctx.sceneDef.FindNodeIndex(*ctx.childA));
+  DALI_TEST_EQUAL(ctx.childA->mChildren.size(), 1u);
+  DALI_TEST_EQUAL(ctx.childA->mChildren[0], ctx.sceneDef.FindNodeIndex(*ctx.childB));
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinition.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinition.cpp
new file mode 100644 (file)
index 0000000..e58e702
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/shader-definition.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+int UtcDaliShaderDefinitionFailedToLoad(void)
+{
+  ShaderDefinition shaderDef;
+  shaderDef.mVertexShaderPath = "nonexistent.vsh";
+  shaderDef.mFragmentShaderPath = "nonexistent.vsh";
+
+  DALI_TEST_ASSERTION(shaderDef.LoadRaw(""), "Failed to load shader source");
+
+  shaderDef.mVertexShaderPath = "dli_pbr.vsh";
+
+  auto shaderPath = TEST_RESOURCE_DIR "/";
+  DALI_TEST_ASSERTION(shaderDef.LoadRaw(shaderPath), "Failed to load shader source");
+
+  shaderDef.mFragmentShaderPath = "dli_pbr.fsh";
+
+  shaderDef.mHints.push_back("MODIFIES_GEOMETRY");
+  shaderDef.mHints.push_back("OUTPUT_IS_TRANSPARENT");
+  auto raw = shaderDef.LoadRaw(shaderPath);
+
+  TestApplication app;
+  auto shader = shaderDef.Load(std::move(raw));
+  DALI_TEST_CHECK(shader);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-ShaderDefinitionFactory.cpp
new file mode 100644 (file)
index 0000000..c1b5481
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/gltf2-loader.h"
+#include "dali-scene-loader/public-api/shader-definition-factory.h"
+#include "dali-scene-loader/public-api/node-definition.h"
+#include "dali-scene-loader/public-api/resource-bundle.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+#include <set>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+
+bool EndsWith(const std::string& str, const std::string& suffix) // ends_width() is C++20
+{
+  return str.size() >= suffix.size() && str.substr(str.size() - suffix.size()).compare(suffix) == 0;
+}
+
+MaterialDefinition& NewMaterialDefinition(ResourceBundle& resources)
+{
+  resources.mMaterials.push_back({});
+  return resources.mMaterials.back().first;
+}
+
+MeshDefinition& NewMeshDefinition(ResourceBundle& resources)
+{
+  resources.mMeshes.push_back({});
+  return resources.mMeshes.back().first;
+}
+
+void ClearMeshesAndMaterials(ResourceBundle& resources)
+{
+  resources.mMaterials.clear();
+  resources.mMeshes.clear();
+}
+
+struct Context
+{
+  ResourceBundle resources;
+  ShaderDefinitionFactory factory;
+
+  Context()
+  {
+    factory.SetResources(resources);
+  }
+};
+
+struct ShaderParameters
+{
+  MeshDefinition& meshDef;
+  MaterialDefinition& materialDef;
+  NodeDefinition& nodeDef;
+};
+
+struct Permutation
+{
+  using ConfigureFn = void(*)(ShaderParameters&);
+
+  ConfigureFn configureFn;
+
+  std::set<std::string> defines;
+  RendererState::Type rendererStateSet = 0;
+  RendererState::Type rendererStateClear = 0;
+};
+
+struct PermutationSet
+{
+  std::vector<const Permutation*> permutations;
+  Index shaderIdx;
+};
+
+}
+
+int UtcDaliShaderDefinitionFactoryProduceShaderInvalid(void)
+{
+  Context ctx;
+
+  NodeDefinition nodeDef;
+  nodeDef.mRenderable.reset(new NodeDefinition::Renderable());
+
+  DALI_TEST_EQUAL(INVALID_INDEX, ctx.factory.ProduceShader(nodeDef));
+  DALI_TEST_CHECK(ctx.resources.mShaders.empty());
+
+  END_TEST;
+}
+
+int UtcDaliShaderDefinitionFactoryProduceShader(void)
+{
+  Context ctx;
+  ctx.resources.mMaterials.push_back({});
+  ctx.resources.mMeshes.push_back({});
+
+  Permutation permutations[]{
+    {
+      [](ShaderParameters& p) {},
+      {},
+      RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK,
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.mFlags |= MaterialDefinition::TRANSPARENCY;
+      },
+      { "THREE_TEX" },
+      RendererState::ALPHA_BLEND,
+      RendererState::DEPTH_WRITE,
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.mTextureStages.push_back({ MaterialDefinition::ALBEDO, {} });
+      },
+      { "THREE_TEX" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.mTextureStages.push_back({ MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {} });
+      },
+      { "THREE_TEX" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.mTextureStages.push_back({ MaterialDefinition::NORMAL, {} });
+      },
+      { "THREE_TEX" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.mFlags |= MaterialDefinition::SUBSURFACE;
+      },
+      { "SSS" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.SetAlphaCutoff(.5f);
+      },
+      { "ALPHA_TEST" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.SetAlphaCutoff(1.f);
+      },
+      { "ALPHA_TEST" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.materialDef.mFlags |= MaterialDefinition::GLTF_CHANNELS;
+      },
+      { "GLTF_CHANNELS" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.meshDef.mJoints0.mBlob.mOffset = 0;
+        p.meshDef.mWeights0.mBlob.mOffset = 0;
+      },
+      { "SKINNING" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.meshDef.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL;
+      },
+      { "FLIP_V" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.meshDef.mBlendShapes.push_back({});
+      },
+    },
+    {
+      [](ShaderParameters& p) {
+        p.meshDef.mBlendShapes.back().deltas.mBlob.mOffset = 0;
+      },
+      { "MORPH_POSITION", "MORPH" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.meshDef.mBlendShapes.back().normals.mBlob.mOffset = 0;
+      },
+      { "MORPH_NORMAL", "MORPH" }
+    },
+    {
+      [](ShaderParameters& p) {
+        p.meshDef.mBlendShapes.back().tangents.mBlob.mOffset = 0;
+      },
+      { "MORPH_TANGENT", "MORPH" }
+    },
+    {
+      [](ShaderParameters& p) {
+        auto& blendShapes = p.meshDef.mBlendShapes;
+        DALI_ASSERT_ALWAYS(!blendShapes.empty() &&
+          (blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID ||
+          blendShapes.back().normals.mBlob.mOffset != MeshDefinition::INVALID ||
+          blendShapes.back().tangents.mBlob.mOffset != MeshDefinition::INVALID));
+        p.meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+      },
+      { "MORPH_VERSION_2_0" }
+    },
+  };
+
+  PermutationSet permSets[] {
+    // default
+    { { &permutations[0] }, 0 },
+
+    // alpha
+    { { &permutations[0], &permutations[1] }, 1 },
+
+    // three-texture setups
+    { { &permutations[0], &permutations[2] }, 2 },
+    { { &permutations[0], &permutations[3] }, 2 },
+    { { &permutations[0], &permutations[4] }, 2 },
+    { { &permutations[0], &permutations[2], &permutations[3] }, 2 },
+    { { &permutations[0], &permutations[3], &permutations[4] }, 2 },
+    { { &permutations[0], &permutations[4], &permutations[2] }, 2 },
+    { { &permutations[0], &permutations[2], &permutations[3], &permutations[4] }, 2 },
+
+    // subsurface scattering
+    { { &permutations[0], &permutations[5] }, 3 },
+
+    // alpha test
+    { { &permutations[0], &permutations[6] }, 4 },
+    { { &permutations[0], &permutations[7] }, 4 },
+
+    // glTF channels
+    { { &permutations[0], &permutations[8] }, 5 },
+
+    // skinning
+    { { &permutations[0], &permutations[9] }, 6 },
+
+    // flip uvs
+    { { &permutations[0], &permutations[10] }, 7 },
+
+    // morphing
+    { { &permutations[0], &permutations[11], &permutations[12] }, 8 },
+    { { &permutations[0], &permutations[11], &permutations[13] }, 9 },
+    { { &permutations[0], &permutations[11], &permutations[14] }, 10 },
+    { { &permutations[0], &permutations[11], &permutations[12], &permutations[13] }, 11 },
+    { { &permutations[0], &permutations[11], &permutations[13], &permutations[14] }, 12 },
+    { { &permutations[0], &permutations[11], &permutations[14], &permutations[12] }, 13 },
+    { { &permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14] }, 14 },
+
+    { { &permutations[0], &permutations[11], &permutations[12], &permutations[15] }, 15 },
+    { { &permutations[0], &permutations[11], &permutations[13], &permutations[15] }, 16 },
+    { { &permutations[0], &permutations[11], &permutations[14], &permutations[15] }, 17 },
+    { { &permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[15] }, 18 },
+    { { &permutations[0], &permutations[11], &permutations[13], &permutations[14], &permutations[15] }, 19 },
+    { { &permutations[0], &permutations[11], &permutations[14], &permutations[12], &permutations[15] }, 20 },
+    { { &permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14], &permutations[15] }, 21 },
+
+    // etc.
+    { { &permutations[0], &permutations[1], &permutations[2] }, 1 },
+    { { &permutations[0], &permutations[1], &permutations[3] }, 1 },
+    { { &permutations[0], &permutations[1], &permutations[2], &permutations[3] }, 1 },
+  };
+  for(auto& ps: permSets)
+  {
+    printf("%ld\n", &ps - permSets);
+
+    auto modelNode = new ModelNode();
+    modelNode->mMeshIdx = 0;
+    modelNode->mMaterialIdx = 0;
+
+    NodeDefinition nodeDef;
+    nodeDef.mRenderable.reset(modelNode);
+
+    auto& meshDef = NewMeshDefinition(ctx.resources);
+    auto& materialDef = NewMaterialDefinition(ctx.resources);
+    ShaderParameters sp{ meshDef, materialDef, nodeDef };
+
+    std::set<std::string> defines;
+    RendererState::Type rendererState = 0;
+    for (auto p : ps.permutations)
+    {
+      p->configureFn(sp);
+      defines.insert(p->defines.begin(), p->defines.end());
+      rendererState = (rendererState | p->rendererStateSet) & ~p->rendererStateClear;
+    }
+
+    auto shaderIdx = ctx.factory.ProduceShader(nodeDef);
+    DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
+
+    auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
+    DALI_TEST_CHECK(EndsWith(shaderDef.mVertexShaderPath, ".vsh"));
+    DALI_TEST_CHECK(EndsWith(shaderDef.mFragmentShaderPath, ".fsh"));
+    DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
+
+    uint32_t definesUnmatched = shaderDef.mDefines.size();
+    for (auto& d: shaderDef.mDefines)
+    {
+      auto iFind = defines.find(d);
+      if (iFind != defines.end())
+      {
+        defines.erase(iFind);
+        --definesUnmatched;
+      }
+      else
+      {
+        printf("mismatched: %s\n", d.c_str());
+        break;
+      }
+    }
+
+    DALI_TEST_CHECK(defines.empty());
+    DALI_TEST_EQUAL(0, definesUnmatched);
+
+    printf("defines OK\n");
+
+    auto uMaxLOD = shaderDef.mUniforms["uMaxLOD"];
+    DALI_TEST_EQUAL(uMaxLOD.GetType(), Property::FLOAT);
+
+    auto uCubeMatrix = shaderDef.mUniforms["uCubeMatrix"];
+    DALI_TEST_EQUAL(uCubeMatrix.GetType(), Property::MATRIX);
+
+    ClearMeshesAndMaterials(ctx.resources);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-StringCallback.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-StringCallback.cpp
new file mode 100644 (file)
index 0000000..acd5183
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/string-callback.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+
+char sBuffer[64];
+
+void TestLogFunction(Integration::Log::DebugPriority level, std::string& str)
+{
+  snprintf(sBuffer, sizeof(sBuffer), "%d: %s", level, str.c_str());
+}
+
+}
+
+int UtcDaliUtilsDefaultStringCallback(void)
+{
+  InstallLogFunction(TestLogFunction);
+  DefaultErrorCallback("Hello world!");
+  DALI_TEST_EQUAL(std::string(sBuffer), "2: DefaultErrorCallback Hello world!");
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-Utils.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-Utils.cpp
new file mode 100644 (file)
index 0000000..68e30a0
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/utils.h"
+#include <dali-test-suite-utils.h>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+constexpr std::string_view TEST_STRING = "The quick brown fox jumped over a lazy dog.1337true";
+}
+
+template <size_t N>
+void HelpTestStreamBuffer()
+{
+  char buffer[N];
+  StreamBuffer streamBuffer(buffer, N); // note we aren't leaving space for a terminating 0 as we're using strNcmp.
+  std::ostream stream(&streamBuffer);
+
+  stream << "The quick brown fox jumped over a lazy dog.";
+  stream << 1337;
+  stream << std::boolalpha << true;
+
+  const size_t checkLen = std::min(N, TEST_STRING.size());
+  DALI_TEST_EQUAL(0, strncmp(buffer, TEST_STRING.data(), checkLen));
+}
+
+int UtcDaliUtilsStreamBuffer(void)
+{
+  HelpTestStreamBuffer<16>();
+  HelpTestStreamBuffer<32>();
+  HelpTestStreamBuffer<64>();
+  END_TEST;
+}
+
+int UtcDaliUtilsFormatString(void)
+{
+  DALI_TEST_EQUAL(FormatString("%s", "hello"), "hello");
+  DALI_TEST_EQUAL(FormatString("%d", 1667), "1667");
+
+  DALI_TEST_EQUAL(FormatString("%s %d", "hello", 2778), "hello 2778");
+  DALI_TEST_EQUAL(FormatString("%d %s", 3889, "hello"), "3889 hello");
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene-loader/utc-Dali-ViewProjection.cpp b/automated-tests/src/dali-scene-loader/utc-Dali-ViewProjection.cpp
new file mode 100644 (file)
index 0000000..c4567ab
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include "dali-scene-loader/public-api/view-projection.h"
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::SceneLoader;
+
+namespace
+{
+void SetPerspectiveProjection(Matrix& m)
+{
+  auto data = m.AsFloat();
+  float near = 1.f;
+  float far = 10.f;
+  float right = 1.f;
+  float left = -right;
+  float top = .75f;
+  float bottom = -top;
+  data[0] = 2.f * near / (right - left);
+  data[5] = 2.f * near / (top - bottom);
+  data[8] = (right + left) / (right - left);
+  data[9] = (top + bottom) / (top - bottom);
+  data[10] = (far + near) / (far - near);
+  data[11] = -1.f;
+  data[14] = 2 * far * near / (far - near);
+}
+
+}
+
+int UtcDaliViewProjection(void)
+{
+  ViewProjection vp;
+  Matrix viewMatrix;
+  viewMatrix.SetTransformComponents( Vector3::ONE,
+    Quaternion(Radian(Degree(90.f)), Vector3::YAXIS),
+    Vector3::XAXIS * 200.f);
+  vp.GetView() = viewMatrix;
+
+  Matrix projectionMatrix;
+  SetPerspectiveProjection(projectionMatrix);
+  vp.GetProjection() = projectionMatrix;
+
+  vp.Update();
+
+  [&](const ViewProjection& vp) {
+    DALI_TEST_EQUAL(vp.GetView(), viewMatrix);
+    DALI_TEST_EQUAL(vp.GetProjection(), projectionMatrix);
+  }(vp);
+
+  Matrix expectedViewProjection{ false };
+  Matrix::Multiply(expectedViewProjection, viewMatrix, projectionMatrix);
+  auto viewProjectionResult = vp.GetViewProjection();
+  DALI_TEST_EQUAL(viewProjectionResult, expectedViewProjection);
+
+  Matrix expectedInverseProjection{ projectionMatrix };
+  expectedInverseProjection.Invert();
+  auto inverseProjectionResult = vp.GetInverseProjection();
+  DALI_TEST_EQUAL(inverseProjectionResult, expectedInverseProjection);
+
+  END_TEST;
+}
+
+int UtcDaliViewProjectionUpdateFail(void)
+{
+  ViewProjection vp;
+  DALI_TEST_ASSERTION(vp.Update(), "Failed to find inverse");
+
+  END_TEST;
+}
index 21b7c0f..657446c 100644 (file)
@@ -34,6 +34,7 @@ OPTION(ENABLE_LINK_TEST          "Enable the link test" ON)
 OPTION(INSTALL_DOXYGEN_DOC       "Install doxygen doc" ON)
 OPTION(CONFIGURE_AUTOMATED_TESTS "Configure automated tests" ON)
 OPTION(USE_DEFAULT_RESOURCE_DIR  "Whether to use the default resource folders. Otherwise set environment variables for DALI_IMAGE_DIR, DALI_SOUND_DIR, DALI_STYLE_DIR, DALI_STYLE_IMAGE_DIR and DALI_DATA_READ_ONLY_DIR" ON)
 OPTION(INSTALL_DOXYGEN_DOC       "Install doxygen doc" ON)
 OPTION(CONFIGURE_AUTOMATED_TESTS "Configure automated tests" ON)
 OPTION(USE_DEFAULT_RESOURCE_DIR  "Whether to use the default resource folders. Otherwise set environment variables for DALI_IMAGE_DIR, DALI_SOUND_DIR, DALI_STYLE_DIR, DALI_STYLE_IMAGE_DIR and DALI_DATA_READ_ONLY_DIR" ON)
+OPTION(BUILD_SCENE_LOADER        "Whether to build dali-scene-loader." ON)
 
 IF( ENABLE_PKG_CONFIGURE )
   FIND_PACKAGE( PkgConfig REQUIRED )
 
 IF( ENABLE_PKG_CONFIGURE )
   FIND_PACKAGE( PkgConfig REQUIRED )
@@ -443,7 +444,7 @@ IF( ENABLE_COVERAGE )
     ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}rename_cov_data ./rename-cov-data )
 
     ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}cov_data ${LCOV_BIN} ${LCOV_OPTS} --base-directory . --directory . -c -o dali.info
     ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}rename_cov_data ./rename-cov-data )
 
     ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}cov_data ${LCOV_BIN} ${LCOV_OPTS} --base-directory . --directory . -c -o dali.info
-      COMMAND ${LCOV_BIN} ${LCOV_OPTS} --remove dali.info \"*/dali-env/*\" \"/usr/include/*\" "*/dali-env/*" "*solid-color-actor*" "*/dali-toolkit/third-party/*" -o dali.info )
+      COMMAND ${LCOV_BIN} ${LCOV_OPTS} --remove dali.info \"*/dali-env/*\" \"/usr/include/*\" "*/dali-env/*" "*solid-color-actor*" "*/dali-toolkit/third-party/*" \"*/dali-scene-loader/third-party/*\" -o dali.info )
 
     ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}coverage genhtml ${LCOV_OPTS} -o ${COVERAGE_OUTPUT_DIR} dali.info
       DEPENDS cov_data )
 
     ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}coverage genhtml ${LCOV_OPTS} -o ${COVERAGE_OUTPUT_DIR} dali.info
       DEPENDS cov_data )
@@ -520,6 +521,10 @@ IF( CONFIGURE_AUTOMATED_TESTS )
                   ${ROOT_SRC_DIR}/automated-tests/CMakeLists.txt @ONLY )
 ENDIF()
 
                   ${ROOT_SRC_DIR}/automated-tests/CMakeLists.txt @ONLY )
 ENDIF()
 
+IF ( BUILD_SCENE_LOADER )
+  ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/dali-scene-loader )
+ENDIF()
+
 # Configuration Messages
 MESSAGE( STATUS "Configuration:\n" )
 MESSAGE( STATUS "Prefix:                        " ${PREFIX} )
 # Configuration Messages
 MESSAGE( STATUS "Configuration:\n" )
 MESSAGE( STATUS "Prefix:                        " ${PREFIX} )
@@ -541,6 +546,7 @@ MESSAGE( STATUS "Use pkg configure:             " ${ENABLE_PKG_CONFIGURE} )
 MESSAGE( STATUS "Vector Based Text Rendering:   " ${ENABLE_VECTOR_BASED_TEXT_RENDERING} )
 MESSAGE( STATUS "Enable link test:              " ${ENABLE_LINK_TEST} )
 MESSAGE( STATUS "Configure automated tests:     " ${CONFIGURE_AUTOMATED_TESTS} )
 MESSAGE( STATUS "Vector Based Text Rendering:   " ${ENABLE_VECTOR_BASED_TEXT_RENDERING} )
 MESSAGE( STATUS "Enable link test:              " ${ENABLE_LINK_TEST} )
 MESSAGE( STATUS "Configure automated tests:     " ${CONFIGURE_AUTOMATED_TESTS} )
+MESSAGE( STATUS "Build Dali Scene Loader:       " ${BUILD_SCENE_LOADER} )
 MESSAGE( STATUS "CXXFLAGS:                      " ${CMAKE_CXX_FLAGS} )
 MESSAGE( STATUS "LDFLAGS:                       " ${CMAKE_SHARED_LINKER_FLAGS_INIT}${CMAKE_SHARED_LINKER_FLAGS} )
 
 MESSAGE( STATUS "CXXFLAGS:                      " ${CMAKE_CXX_FLAGS} )
 MESSAGE( STATUS "LDFLAGS:                       " ${CMAKE_SHARED_LINKER_FLAGS_INIT}${CMAKE_SHARED_LINKER_FLAGS} )
 
diff --git a/build/tizen/dali-scene-loader/CMakeLists.txt b/build/tizen/dali-scene-loader/CMakeLists.txt
new file mode 100644 (file)
index 0000000..887b2a5
--- /dev/null
@@ -0,0 +1,159 @@
+cmake_minimum_required(VERSION 2.6)
+set(name "dali2-scene-loader")
+
+project(${name} CXX)
+
+set(${name}_VERSION_MAJOR 2)
+set(${name}_VERSION_MINOR 0)
+set(${name}_VERSION_PATCH 0)
+set(${name}_VERSION ${${name}_VERSION_MAJOR}.${${name}_VERSION_MINOR}.${${name}_VERSION_PATCH} )
+
+SET(DALI_SCENE_LOADER_VERSION ${${name}_VERSION} )
+
+if(CMAKE_BUILD_TYPE MATCHES Debug)
+       add_definitions("-DDEBUG_ENABLED")
+endif()
+
+foreach(flag ${PKGS_CFLAGS})
+       set(extra_flags "${extra_flags} ${flag}")
+endforeach(flag)
+
+set(prj_cxx_std c++17)
+if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+       set(extra_flags "${extra_flags} -fPIC -std=${prj_cxx_std}")
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+       set(extra_flags "${extra_flags} -fPIC -std=${prj_cxx_std}")
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+       set(extra_flags "${extra_flags} /std:${prj_cxx_std} /vmg /D_USE_MATH_DEFINES /D_CRT_SECURE_NO_WARNINGS /MP /GS /Oi /GL /EHsc")
+endif()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${extra_flags}")
+
+set(prefix ${CMAKE_INSTALL_PREFIX})
+
+set(repo_root_dir "${CMAKE_CURRENT_LIST_DIR}/../../../")
+set(scene_loader_dir "${repo_root_dir}/dali-scene-loader")
+
+option(ENABLE_PKG_CONFIGURE "Use pkgconfig" ON)
+option(ENABLE_COVERAGE "Coverage" OFF)
+
+IF( ENABLE_COVERAGE OR "$ENV{CXXFLAGS}" MATCHES --coverage )
+  ADD_COMPILE_OPTIONS( --coverage )
+  SET(ENABLE_COVERAGE ON)
+  SET(COVERAGE --coverage)
+ENDIF()
+
+if (ENABLE_PKG_CONFIGURE)
+       find_package(PkgConfig REQUIRED)
+
+       pkg_check_modules(DALICORE REQUIRED dali2-core)
+       pkg_check_modules(DALIADAPTOR REQUIRED dali2-adaptor)
+
+       # Configure the pkg-config file
+       # Requires the following variables to be setup:
+       # @PREFIX@ @EXEC_PREFIX@ @DALI_VERSION@ @LIB_DIR@ @DEV_INCLUDE_PATH@
+       set( LIB_DIR $ENV{libdir} )
+       if( NOT LIB_DIR )
+               set( LIB_DIR ${CMAKE_INSTALL_LIBDIR} )
+       endif()
+       if( NOT LIB_DIR )
+               set( LIB_DIR ${prefix}/lib )
+       endif()
+
+       set(PREFIX ${prefix})
+       set(EXEC_PREFIX ${CMAKE_INSTALL_PREFIX})
+       set(DEV_INCLUDE_PATH ${repo_root_dir})
+
+       set(core_pkg_cfg_file dali2-scene-loader.pc)
+       configure_file(${CMAKE_CURRENT_LIST_DIR}/${core_pkg_cfg_file}.in ${core_pkg_cfg_file} @ONLY)
+endif()
+
+if (ENABLE_COVERAGE)
+       find_program(lcov_bin "lcov")
+       if (${lcov_bin})
+               set(cov_dir ".cov")
+               set(cov_output_dir "doc/coverage")
+
+               execute_process(COMMAND bash -c "${lcov_bin} --version | cut -d' ' -f4" OUTPUT_VARIABLE lcov_version)
+               string(REPLACE "." ";" lcov_vlist ${lcov_version})
+               if (NOT $<VERSION_LESS:${lcov_version},"1.10"> )
+                       set(lcov_opts --rc lcov_branch_coverage=1)
+               endif()
+
+               add_custom_target(${prefix}rename_cov_data ./rename-cov-data)
+
+               add_custom_target(${prefix}cov_data
+                       ${lcov_bin} ${lcov_opts} --base-directory . --directory . -c -o dali.info
+                       COMMAND ${lcov_bin} ${lcov_opts} --remove dali.info \"*/dali-env/*\" \"/usr/include/*\" \"/usr/local/include/*\" \"*/dali-env/*\" \"*/dali-scene-loader/third-party/*\" -o dali.info
+               )
+
+               add_custom_target(${prefix}coverage genhtml ${lcov_opts} -o ${cov_output_dir} dali.info)
+
+               add_custom_target(${prefix}reset_coverage @${lcov_bin} -\ --direwctory `pwd`)
+
+               add_custom_target(${prefix}distclean @echo cleaning for source distribution)
+               add_custom_command(
+                       DEPENDS ${prefix}clean
+                       COMMENT "distribution clean"
+                       COMMAND find
+                       ARGS .
+                       -not -name config.cmake -and \(
+                       -name tester.c -or
+                       -name Testing -or
+                       -name CMakeFiles -or
+                       -name doc -or
+                       -name cmake.depends -or
+                       -name cmake.check_depends -or
+                       -name CMakeCache.txt -or
+                       -name cmake.check_cache -or
+                       -name *.cmake -or
+                       -name Makefile -or
+                       -name core -or
+                       -name core.* -or
+                       -name gmon.out -or
+                       -name install_manifest.txt -or
+                       -name *.pc -or
+                       -name *.gcov -or
+                       -name *.gcno -or
+                       -name *.gcda -or
+                       -name *~ -or
+                       -name libdali*.so* \)
+                       | grep -v TC | xargs rm -rf
+                       TARGET  ${DALI_TOOLKIT_PREFIX}distclean
+                       VERBATIM
+               )
+       endif()
+endif()
+
+set(scene_loader_src_files "")
+include("${scene_loader_dir}/internal/file.list")
+include("${scene_loader_dir}/public-api/file.list")
+
+set(prefix_include_dir "${prefix}/include")
+include_directories(${repo_root_dir}
+       ${prefix_include_dir}
+)
+
+add_library(${name} SHARED ${scene_loader_src_files})
+
+target_link_libraries(${name} ${DALICORE_LDFLAGS} ${DALIADAPTOR_LDFLAGS}
+       dali2-toolkit
+       ${COVERAGE})
+
+if( ANDROID )
+       target_link_libraries(${name} log)
+endif()
+
+install(TARGETS ${name} DESTINATION ${prefix}/lib)
+
+file(GLOB scene_loader_include_files ${scene_loader_public_api_dir})
+install(DIRECTORY ${scene_loader_include_files}
+       DESTINATION "${prefix_include_dir}/dali-scene-loader"
+       FILES_MATCHING PATTERN "*.h"
+)
+
+if (ENABLE_PKG_CONFIGURE)
+       install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${core_pkg_cfg_file}
+               DESTINATION ${LIB_DIR}/pkgconfig
+       )
+endif()
diff --git a/build/tizen/dali-scene-loader/build.sh b/build/tizen/dali-scene-loader/build.sh
new file mode 100755 (executable)
index 0000000..5397887
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+git clean -xdf .
+cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX .
+make install -j16
diff --git a/build/tizen/dali-scene-loader/dali2-scene-loader.pc.in b/build/tizen/dali-scene-loader/dali2-scene-loader.pc.in
new file mode 100644 (file)
index 0000000..8f7e885
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+apiversion=@DALI_SCENE_LOADER_VERSION@
+libdir=@LIB_DIR@
+includedir=@DEV_INCLUDE_PATH@
+
+Name: Dali 3D Engine Scene Loader
+Description: Dali Scene Loader library
+Version: ${apiversion}
+Requires: dali2-toolkit
+Libs: -L${libdir} -ldali2-scene-loader
+Cflags: -I${includedir}
diff --git a/dali-scene-loader.manifest b/dali-scene-loader.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/dali-scene-loader.manifest-smack b/dali-scene-loader.manifest-smack
new file mode 100644 (file)
index 0000000..08561d6
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+       <assign>
+               <filesystem path="/usr/lib/*" label="_" />
+       </assign>
+       <request>
+               <domain name="dali"/>
+       </request>
+</manifest>
diff --git a/dali-scene-loader/README.md b/dali-scene-loader/README.md
new file mode 100644 (file)
index 0000000..2f88dbe
--- /dev/null
@@ -0,0 +1,41 @@
+# dali-sceen-loader
+
+Provides functionality for loading scenes created in the JSON-based DLI format. DLI is most similar to glTF, but less verbose / granular, and it has a few extra features:
+
+- customizations: switch between alternative definitions of parts of the scene;
+- environment maps;
+- text, arc, and image elements;
+- etc. (TODO)
+
+Please refer to [dli-exporter](http://github.com/dalihub/dli-exporter) for converting 3D models to DLI.
+
+## Prequisites
+
+- Windows:
+
+  - Microsoft Visual Studio 2017 (or later, with 2017 build tools);
+  - [windows-dependencies](https://github.com/dalihub/windows-dependencies ) - please follow the steps in its README.md *as well as* its vcpkg-script/ReadMe.md, to install VCPKG and all dependencies;
+- Linux:
+
+  - GCC v9.3+;
+  - CMake v3.14+;
+  - [dali-core](https://github.com/dalihub/dali-core );
+  - [dali-adaptor](https://github.com/dalihub/dali-adaptor );
+  - [dali-toolkit](https://github.com/dalihub/dali-toolkit );
+  - configure DALi environment by following the instructions in README.md, in dali-core;
+
+## Build instructions
+
+1, build the DALi libraries;
+
+2,
+
+  - Windows: refer to the VS2017 solution in the windows-dependencies repository;
+  - Linux: run the ../build/tizen/dali-scene-loader/build.sh;
+  - Tizen:
+
+    $ gbs build -A ${target_arch}
+
+    - for debug, add: --define "%enable_debug 1"
+    - for SMACK-enabled targets, add: --define "%enable_dali_smack_rules 1"
diff --git a/dali-scene-loader/internal/file.list b/dali-scene-loader/internal/file.list
new file mode 100644 (file)
index 0000000..70d94f3
--- /dev/null
@@ -0,0 +1,8 @@
+set(scene_loader_internal_dir "${scene_loader_dir}/internal")
+
+set(scene_loader_src_files ${scene_loader_src_files}
+       ${scene_loader_internal_dir}/gltf2-asset.cpp
+       ${scene_loader_internal_dir}/hash.cpp
+       ${scene_loader_internal_dir}/json-reader.cpp
+       ${scene_loader_internal_dir}/json-util.cpp
+)
diff --git a/dali-scene-loader/internal/gltf2-asset.cpp b/dali-scene-loader/internal/gltf2-asset.cpp
new file mode 100644 (file)
index 0000000..e77a6f5
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+*
+* 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 "dali-scene-loader/internal/gltf2-asset.h"
+#include "dali/public-api/math/matrix.h"
+#include <algorithm>
+#include <map>
+
+#define ENUM_STRING_MAPPING(t, x) { #x, t::x }
+
+using namespace Dali;
+
+namespace gltf2
+{
+namespace
+{
+
+constexpr uint32_t ACCESSOR_TYPE_ELEMENT_COUNT[]{
+  1,
+  2,
+  3,
+  4,
+  4,
+  9,
+  16,
+  static_cast<uint32_t>(-1)
+};
+
+const std::map<std::string_view, AccessorType::Type> ACCESSOR_TYPES{
+  ENUM_STRING_MAPPING(AccessorType, SCALAR),
+  ENUM_STRING_MAPPING(AccessorType, VEC2),
+  ENUM_STRING_MAPPING(AccessorType, VEC3),
+  ENUM_STRING_MAPPING(AccessorType, VEC4),
+  ENUM_STRING_MAPPING(AccessorType, MAT2),
+  ENUM_STRING_MAPPING(AccessorType, MAT3),
+  ENUM_STRING_MAPPING(AccessorType, MAT4),
+};
+
+const std::map<std::string_view, AlphaMode::Type> ALPHA_MODE_TYPES{
+  ENUM_STRING_MAPPING(AlphaMode::Type, OPAQUE),
+  ENUM_STRING_MAPPING(AlphaMode::Type, MASK),
+  ENUM_STRING_MAPPING(AlphaMode::Type, BLEND),
+};
+
+const std::map<std::string_view, Attribute::Type> ATTRIBUTE_TYPES{
+  ENUM_STRING_MAPPING(Attribute::Type, POSITION),
+  ENUM_STRING_MAPPING(Attribute::Type, NORMAL),
+  ENUM_STRING_MAPPING(Attribute::Type, TANGENT),
+  ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_0),
+  ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_1),
+  ENUM_STRING_MAPPING(Attribute::Type, COLOR_0),
+  ENUM_STRING_MAPPING(Attribute::Type, JOINTS_0),
+  ENUM_STRING_MAPPING(Attribute::Type, WEIGHTS_0),
+};
+
+const std::map<std::string_view, Animation::Sampler::Interpolation::Type> ANIMATION_SAMPLER_INTERPOLATION{
+  ENUM_STRING_MAPPING(Animation::Sampler::Interpolation::Type, STEP),
+  ENUM_STRING_MAPPING(Animation::Sampler::Interpolation::Type, LINEAR),
+  ENUM_STRING_MAPPING(Animation::Sampler::Interpolation::Type, CUBICSPLINE),
+};
+
+const std::map<std::string_view, Animation::Channel::Target::Type> ANIMATION_CHANNEL_TARGET_PATH_TYPES{
+  ENUM_STRING_MAPPING(Animation::Channel::Target::Type, TRANSLATION),
+  ENUM_STRING_MAPPING(Animation::Channel::Target::Type, ROTATION),
+  ENUM_STRING_MAPPING(Animation::Channel::Target::Type, SCALE),
+  ENUM_STRING_MAPPING(Animation::Channel::Target::Type, WEIGHTS),
+};
+
+}
+
+bool Component::IsUnsigned(Type t)
+{
+  return t == UNSIGNED_BYTE || t == UNSIGNED_SHORT || t == UNSIGNED_INT;
+}
+
+uint32_t Component::Size(Type t)
+{
+  switch (t)
+  {
+  case BYTE:
+  case UNSIGNED_BYTE:
+    return 1;
+  case SHORT:
+  case UNSIGNED_SHORT:
+    return 2;
+  case UNSIGNED_INT:
+  case FLOAT:
+    return 4;
+  default:
+    return -1;
+  }
+}
+
+uint32_t AccessorType::ElementCount(Type t)
+{
+  return ACCESSOR_TYPE_ELEMENT_COUNT[t];
+}
+
+AccessorType::Type AccessorType::FromString(const char* s, size_t len)
+{
+  auto iFind = ACCESSOR_TYPES.find(std::string_view(s, len));
+  if (iFind != ACCESSOR_TYPES.end())
+  {
+    return iFind->second;
+  }
+  return AccessorType::INVALID;
+}
+
+AlphaMode::Type AlphaMode::FromString(const char* s, size_t len)
+{
+  auto iFind = ALPHA_MODE_TYPES.find(std::string_view(s, len));
+  if (iFind != ALPHA_MODE_TYPES.end())
+  {
+    return iFind->second;
+  }
+  return AlphaMode::INVALID;
+}
+
+Attribute::Type Attribute::FromString(const char* s, size_t len)
+{
+  auto iFind = ATTRIBUTE_TYPES.find(std::string_view(s, len));
+  if (iFind != ATTRIBUTE_TYPES.end())
+  {
+    return iFind->second;
+  }
+  return Attribute::INVALID;
+}
+
+Animation::Sampler::Interpolation::Type Animation::Sampler::Interpolation::FromString(const char* s, size_t len)
+{
+  auto iFind = ANIMATION_SAMPLER_INTERPOLATION.find(std::string_view(s, len));
+  if (iFind != ANIMATION_SAMPLER_INTERPOLATION.end())
+  {
+    return iFind->second;
+  }
+  return Animation::Sampler::Interpolation::Type::INVALID;
+}
+
+uint32_t ComponentTypedBufferViewClient::GetBytesPerComponent() const
+{
+  return Component::Size(mComponentType);
+}
+
+Animation::Channel::Target::Type Animation::Channel::Target::FromString(const char* s, size_t len)
+{
+  std::string target(s, len);
+  std::transform(target.begin(), target.end(), target.begin(), ::toupper);
+
+  auto iFind = ANIMATION_CHANNEL_TARGET_PATH_TYPES.find(std::string_view(target.c_str(), len));
+  if (iFind != ANIMATION_CHANNEL_TARGET_PATH_TYPES.end())
+  {
+    return iFind->second;
+  }
+  return Animation::Channel::Target::INVALID;
+};
+
+void Node::SetMatrix(const Matrix& m)
+{
+  m.GetTransformComponents(mTranslation, mRotation, mScale);
+}
+
+Quaternion ReadQuaternion(const json_value_s & j)
+{
+       return Quaternion(ReadDaliVector<Vector4>(j));
+}
+
+}
diff --git a/dali-scene-loader/internal/gltf2-asset.h b/dali-scene-loader/internal/gltf2-asset.h
new file mode 100644 (file)
index 0000000..79a72db
--- /dev/null
@@ -0,0 +1,585 @@
+#ifndef DALI_SCENE_LOADER_GLTF2_ASSET_H_
+#define DALI_SCENE_LOADER_GLTF2_ASSET_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/index.h"
+#include "dali-scene-loader/internal/json-reader.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/vector4.h"
+#include "dali/public-api/math/quaternion.h"
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/devel-api/common/map-wrapper.h"
+#include <cstdint>
+#include <memory>
+
+namespace gltf2
+{
+
+using Index = Dali::SceneLoader::Index;
+
+template <typename T>
+class Ref
+{
+public:
+  Ref() = default;
+  Ref(std::vector<T>& v, Index i)
+  : mVector(&v),
+    mIndex(i)
+  {}
+
+  /**
+   * @return The index of the object into the vector.
+   * @note It is client code responsibility to ensure that the vector is unambiguous. It should be in
+   *  a glTF document, since there's one vector for each type.
+   */
+  Index GetIndex() const { return mIndex; }
+
+  /**
+   * @brief There may be scenarios in which the object, whose vector we're populating, changes, e.g.
+   *  when we don't have a final one at the time of reading the references.
+   */
+  void UpdateVector(std::vector<T>& v)
+  {
+    mVector = &v;
+  }
+
+  operator bool() const { return mVector != nullptr; }
+  T* operator->() const { return &(*mVector)[mIndex]; }
+  T& operator*() const { return (*mVector)[mIndex]; }
+
+  bool operator==(const Ref<T>& other) const
+  {
+    return mVector == other.mVector && mIndex == other.mIndex;
+  }
+
+  bool operator!=(const Ref<T>& other) const
+  {
+    return !operator==(other);
+  }
+
+private:
+  std::vector<T>* mVector = nullptr;
+  Index mIndex = Dali::SceneLoader::INVALID_INDEX;
+};
+
+struct Asset
+{
+  std::string_view mVersion;
+};
+
+struct Component
+{
+  enum Type
+  {
+    BYTE = 5120,
+    UNSIGNED_BYTE = 5121,
+    SHORT = 5122,
+    UNSIGNED_SHORT = 5123,
+    UNSIGNED_INT = 5125,
+    FLOAT = 5126,
+    INVALID = -1
+  };
+
+  static bool IsUnsigned(Type t);
+  static uint32_t Size(Type t);
+
+  Component() = delete;
+};
+
+struct AccessorType
+{
+  enum Type
+  {
+    SCALAR,
+    VEC2,
+    VEC3,
+    VEC4,
+    MAT2,
+    MAT3,
+    MAT4,
+    INVALID
+  };
+
+  static uint32_t ElementCount(Type t);
+
+  static Type FromString(const char* s, size_t len);
+
+  AccessorType() = delete;
+};
+
+struct AlphaMode
+{
+  enum Type
+  {
+    OPAQUE,
+    MASK,
+    BLEND,
+    INVALID
+  };
+
+  static Type FromString(const char* s, size_t len);
+
+  AlphaMode() = delete;
+};
+
+struct Attribute
+{
+  enum Type
+  {
+    POSITION,
+    NORMAL,
+    TANGENT,
+    TEXCOORD_0,
+    TEXCOORD_1,
+    COLOR_0,
+    JOINTS_0,
+    WEIGHTS_0,
+    INVALID
+  };
+
+  static Type FromString(const char* s, size_t len);
+
+  Attribute() = delete;
+};
+
+struct Buffer
+{
+  uint32_t mByteLength;
+  std::string_view mUri;
+  //TODO: extensions
+  //TODO: extras
+};
+
+struct BufferView
+{
+  struct Target
+  {
+    enum Type
+    {
+      NONE,
+      ARRAY_BUFFER = 34962,
+      ELEMENT_ARRAY_BUFFER = 34963
+    };
+
+    Target() = delete;
+  };
+
+  Ref<Buffer> mBuffer;
+  uint32_t mByteOffset = 0;
+  uint32_t mByteLength;
+  uint32_t mByteStride = 0;  // if 0 after reading, it needs to be calculated
+  uint32_t mTarget;
+  //TODO: extensions
+  //TODO: extras
+};
+
+struct BufferViewClient
+{
+  Ref<BufferView> mBufferView;
+  uint32_t mByteOffset = 0;
+};
+
+struct ComponentTypedBufferViewClient : BufferViewClient
+{
+  Component::Type mComponentType = Component::INVALID;
+
+  uint32_t GetBytesPerComponent() const;
+};
+
+struct Named
+{
+  std::string_view mName;
+
+protected:
+  Named() = default;
+};
+
+struct Accessor : ComponentTypedBufferViewClient, Named
+{
+  struct Sparse
+  {
+    uint32_t mCount;
+    ComponentTypedBufferViewClient mIndices;
+    BufferViewClient mValues;
+    //TODO: extensions
+    //TODO: extras
+  };
+
+  uint32_t mCount;
+  bool mNormalized = false;
+  AccessorType::Type mType = AccessorType::INVALID;
+  std::vector<float> mMin;
+  std::vector<float> mMax;
+  std::unique_ptr<Sparse> mSparse;
+  //TODO: extensions
+  //TODO: extras
+
+  uint32_t GetElementSizeBytes() const
+  {
+    return GetBytesPerComponent() * AccessorType::ElementCount(mType);
+  }
+
+  uint32_t GetBytesLength() const
+  {
+    return GetElementSizeBytes() * mCount;
+  }
+
+  void SetSparse(const Sparse& s)
+  {
+    mSparse.reset(new Sparse(s));
+  }
+};
+
+struct Image: Named
+{
+  std::string_view mUri;
+  std::string_view mMimeType;
+  Ref<BufferView> mBufferView;
+  //TODO: extensions
+  //TODO: extras
+};
+
+struct Filter
+{
+  enum Type
+  {
+    NEAREST = 9728,
+    LINEAR = 9729,
+    NEAREST_MIPMAP_NEAREST = 9984,
+    NEAREST_MIPMAP_LINEAR = 9985,
+    LINEAR_MIPMAP_NEAREST = 9986,
+    LINEAR_MIPMAP_LINEAR = 9987,
+  };
+
+  Filter() = delete;
+};
+
+struct Wrap
+{
+  enum Type
+  {
+    REPEAT = 10497,
+    CLAMP_TO_EDGE = 33071,
+    MIRRORED_REPEAT = 33648,
+  };
+
+  Wrap() = delete;
+};
+
+struct Sampler
+{
+  Filter::Type mMinFilter = Filter::LINEAR;
+  Filter::Type mMagFilter = Filter::LINEAR;
+  Wrap::Type mWrapS = Wrap::CLAMP_TO_EDGE;
+  Wrap::Type mWrapT = Wrap::CLAMP_TO_EDGE;
+  //TODO: extensions
+  //TODO: extras
+};
+
+struct Texture
+{
+  Ref<Image> mSource;
+  Ref<Sampler> mSampler;
+};
+
+struct TextureInfo
+{
+  Ref<gltf2::Texture> mTexture;
+  uint32_t mTexCoord = 0;
+  float mScale = 1.f;
+
+  operator bool() const
+  {
+    return !!mTexture;
+  }
+};
+
+struct Material: Named
+{
+  struct Pbr//MetallicRoughness
+  {
+    Dali::Vector4 mBaseColorFactor = Dali::Vector4::ONE;
+    TextureInfo mBaseColorTexture;
+    float mMetallicFactor = 1.f;
+    float mRoughnessFactor = 1.f;
+    TextureInfo mMetallicRoughnessTexture;
+    //TODO: extensions
+    //TODO: extras
+  };
+
+  Pbr mPbrMetallicRoughness;
+  TextureInfo mNormalTexture;
+  TextureInfo mOcclusionTexture;
+  TextureInfo mEmissiveTexture;
+  Dali::Vector3 mEmissiveFactor;
+  AlphaMode::Type mAlphaMode = AlphaMode::OPAQUE;
+  float mAlphaCutoff = .5f;
+  bool mDoubleSided = false;
+  //TODO: extensions
+  //TODO: extras
+};
+
+struct Mesh: Named
+{
+  struct Primitive
+  {
+    enum Mode
+    {
+      POINTS,
+      LINES,
+      LINE_LOOP,
+      LINE_STRIP,
+      TRIANGLES,
+      TRIANGLE_STRIP,
+      TRIANGLE_FAN,
+      INVALID
+    };
+
+    std::map<Attribute::Type, Ref<Accessor>> mAttributes;
+    std::vector<std::map<Attribute::Type, Ref<Accessor>>> mTargets;
+    Ref<Accessor> mIndices;
+    Ref<Material> mMaterial;
+    Mode mMode = TRIANGLES;
+
+    //TODO: [morph] targets
+    //TODO: extras
+    //TODO: extensions
+  };
+
+  std::vector<Primitive> mPrimitives;
+  std::vector<float> mWeights;
+  //TODO: extras
+  //TODO: extensions
+};
+
+struct Node;
+
+struct Skin : Named
+{
+  Ref<Accessor> mInverseBindMatrices;
+  Ref<Node> mSkeleton;
+  std::vector<Ref<Node>> mJoints;
+  //TODO: extras
+  //TODO: extensions
+};
+
+struct Camera: Named
+{
+  struct Perspective
+  {
+    float mAspectRatio;
+    float mYFov;
+    float mZFar;
+    float mZNear;
+    //TODO: extras
+    //TODO: extensions
+  };
+
+  struct Orthographic
+  {
+    float mXMag;
+    float mYMag;
+    float mZFar;
+    float mZNear;
+    //TODO: extras
+    //TODO: extensions
+  };
+
+  std::string_view mType;
+  Perspective mPerspective;
+  Orthographic mOrthographic;
+  //TODO: extras
+  //TODO: extensions
+};
+
+struct Node: Named
+{
+  Dali::Vector3 mTranslation = Dali::Vector3::ZERO;
+  Dali::Quaternion mRotation = Dali::Quaternion::IDENTITY;
+  Dali::Vector3 mScale = Dali::Vector3::ONE;
+
+  Ref<Camera> mCamera;
+  std::vector<Ref<Node>> mChildren;
+  Ref<Mesh> mMesh;
+
+  Ref<Skin> mSkin;
+  //TODO: [morph] weights
+  //TODO: extras
+  //TODO: extensions
+
+  void SetMatrix(const Dali::Matrix& m);
+};
+
+struct Animation : Named
+{
+  struct Sampler
+  {
+    struct Interpolation
+    {
+      enum Type
+      {
+        STEP,
+        LINEAR,
+        CUBICSPLINE,
+        INVALID
+      };
+      static Type FromString(const char* s, size_t len);
+    };
+
+    Ref<Accessor> mInput;
+    Ref<Accessor> mOutput;
+    Interpolation::Type mInterpolation;
+
+    //TODO: extras
+    //TODO: extensions
+  };
+
+  struct Channel
+  {
+    struct Target
+    {
+      enum Type
+      {
+        TRANSLATION,
+        ROTATION,
+        SCALE,
+        WEIGHTS,
+        INVALID
+      };
+
+      static Type FromString(const char* s, size_t len);
+
+      Ref<Node> mNode;
+      Type mPath;
+    };
+
+    Ref<Sampler> mSampler;
+    Target mTarget;
+    //TODO: extras
+    //TODO: extensions
+  };
+
+  std::vector<Sampler> mSamplers;
+  std::vector<Channel> mChannels;
+};
+
+struct Scene: Named
+{
+  std::vector<Ref<Node>> mNodes;
+};
+
+struct Document
+{
+  Asset mAsset;
+
+  std::vector<Buffer> mBuffers;
+  std::vector<BufferView> mBufferViews;
+  std::vector<Accessor> mAccessors;
+
+  std::vector<Image> mImages;
+  std::vector<Sampler> mSamplers;
+  std::vector<Texture> mTextures;
+  std::vector<Material> mMaterials;
+
+  std::vector<Mesh> mMeshes;
+  std::vector<Skin> mSkins;
+
+  std::vector<Camera> mCameras;
+  std::vector<Node> mNodes;
+
+  std::vector<Animation> mAnimations;
+
+  std::vector<Scene> mScenes;
+  Ref<Scene> mScene;
+
+  Document() = default;
+  Document(const Document&) = delete;
+  Document(Document&&) = default;
+
+  Document& operator=(const Document&) = delete;
+  Document& operator=(Document&&) = default;
+};
+
+/**
+ * @brief Provides a json::Property<T>::ReadFn for interpreting unsigned integers
+ *  as a Ref<U> into a std::vector<U> data member of a type T.
+ */
+template <typename T>
+struct RefReader
+{
+  static T* sObject;
+
+  template <typename U, std::vector<U> T::* V>
+  static Ref<U> Read(const json_value_s& j)
+  {
+    uint32_t index = json::Read::Number<uint32_t>(j);
+    return Ref<U>(sObject->*V, index);
+  }
+};
+
+template <typename T>
+T* RefReader<T>::sObject = nullptr;
+
+/**
+ * @brief Convenience method to set the object for RefReader.
+ */
+template <typename T>
+void SetRefReaderObject(T& object)
+{
+  RefReader<T>::sObject = &object;
+}
+
+/**
+ * @brief Reads a string and attempts to convert it to an enum.
+ * @note The enum must: 1, be called Type, nested to T, 2, provide a FromString static method taking a const char*
+ *  (string data) and a size_t (string length) and returning T::Type.
+ */
+template <typename T> // T must have a nested enum called Type and a static Type FromString(const char*) method.
+typename T::Type ReadStringEnum(const json_value_s& j)
+{
+  auto str = json::Read::StringView(j);
+
+  return T::FromString(str.data(), str.size());
+}
+
+/**
+ * @brief Convenience method to attempt to create a Dali vector type T from an array of floats.
+ * @note T must provide an AsFloat() member method returning the non-const array of its
+ *  float components.
+ */
+template <typename T>
+inline
+T ReadDaliVector(const json_value_s& j)
+{
+  std::vector<float> floats = json::Read::Array<float, json::Read::Number<float>>(j);
+  T result;
+  std::copy(floats.begin(), std::min(floats.end(), floats.begin() + sizeof(T) / sizeof(float)), result.AsFloat());
+  return result;
+}
+
+/**
+ * @brief Convenience method to attemt to read a Quaternion, which implicitly converts
+ *  to Vector4 but fails to provide an AsFloat() method.
+ */
+Dali::Quaternion ReadQuaternion(const json_value_s& j);
+
+}
+
+#endif //DALI_SCENE_LOADER_GLTF2_ASSET_H_
diff --git a/dali-scene-loader/internal/hash.cpp b/dali-scene-loader/internal/hash.cpp
new file mode 100644 (file)
index 0000000..e863f0a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/internal/hash.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+Hash::Hash(uint64_t initial)
+: mValue(initial)
+{}
+
+Hash& Hash::Add(bool b)
+{
+  mValue = Concatenate(b ? 0 : 1);
+  return *this;
+}
+
+Hash& Hash::Add(int32_t i)
+{
+  mValue = Concatenate(i);
+  return *this;
+}
+
+Hash& Hash::Add(uint32_t i)
+{
+  mValue = Concatenate(i);
+  return *this;
+}
+
+Hash& Hash::Add(uint64_t i)
+{
+  mValue = Concatenate(i);
+  return *this;
+}
+
+Hash& Hash::Add(float f)
+{
+  return AddObjectBytes(f);
+}
+
+Hash& Hash::Add(const char * cStr)
+{
+  return Add(cStr, strlen(cStr));
+}
+
+Hash& Hash::Add(const char * cStr, size_t len)
+{
+  auto i0 = reinterpret_cast<const uint8_t*>(cStr);
+  return AddBytes(i0, i0 + len);
+}
+
+Hash& Hash::Add(const std::string & str)
+{
+  auto i0 = reinterpret_cast<const uint8_t*>(str.c_str());
+  return AddBytes(i0, i0 + str.size());
+}
+
+Hash& Hash::AddBytes(const uint8_t * i0, const uint8_t * i1)
+{
+  while (i0 != i1)
+  {
+    mValue = Concatenate(*i0);
+    ++i0;
+  }
+  return *this;
+}
+
+Hash::operator uint64_t() const
+{
+  return mValue;
+}
+
+uint64_t Hash::Concatenate(uint64_t value)
+{
+  return mValue * 31 + value;
+}
+
+}
+}
diff --git a/dali-scene-loader/internal/hash.h b/dali-scene-loader/internal/hash.h
new file mode 100644 (file)
index 0000000..32c69da
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef DALI_SCENE_LOADER_HASH_H_
+#define DALI_SCENE_LOADER_HASH_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 <string>
+#include <cstring>
+#include <cstdint>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Rudimentary hash generator that follows a builder pattern.
+ */
+class Hash
+{
+public:
+  static constexpr uint64_t DEFAULT_SEED = 61081;
+
+  explicit Hash(uint64_t initial = DEFAULT_SEED);
+
+  /**
+   * @brief Applies a boolean to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(bool b);
+
+  /**
+   * @brief Applies a signed 32-bit integer to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(int32_t i);
+
+  /**
+   * @brief Applies an unsigned 32-bit integer to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(uint32_t i);
+
+  /**
+   * @brief Applies an unsigned 64-bit integer to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(uint64_t i);
+
+  /**
+   * @brief Applies a float to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(float f);
+
+  /**
+   * @brief Applies a c-string to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(const char* cStr);
+
+  /**
+   * @brief Applies a c-string @a cStr of @a len characters, to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(const char* cStr, size_t len);
+
+  /**
+   * @brief Applies a string to the hash.
+   * @return Its updated self.
+   */
+  Hash& Add(const std::string& str);
+
+  /**
+   * @brief Applies a series of bytes between @a i0 and @a i1 to the hash.
+   * @return Its updated self.
+   */
+  Hash& AddBytes(const uint8_t* i0, const uint8_t* i1);
+
+  /**
+   * @brief Applies the bytes of an object @a value, to the hash.
+   * @return Its updated self.
+   */
+  template <typename T>
+  Hash& AddObjectBytes(const T& value);
+
+  operator uint64_t() const;
+
+private:
+  uint64_t mValue;
+
+  uint64_t Concatenate(uint64_t value);
+};
+
+
+template<typename T>
+Hash& Hash::AddObjectBytes(const T & value)
+{
+  auto i0 = reinterpret_cast<const uint8_t*>(&value);
+  auto i1 = i0 + sizeof(T);
+  while (i0 != i1)
+  {
+    mValue = Concatenate(*i0);
+    ++i0;
+  }
+  return *this;
+}
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_HASH_H_
diff --git a/dali-scene-loader/internal/json-reader.cpp b/dali-scene-loader/internal/json-reader.cpp
new file mode 100644 (file)
index 0000000..6b12d1d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+*
+* 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 "dali-scene-loader/internal/json-reader.h"
+#include <algorithm>
+#include <cstring>
+
+namespace json
+{
+
+int StrCmp(const json_string_s& js, const char* s)
+{
+  auto sSize = strlen(s);
+  auto shorter = std::min(js.string_size, sSize);
+  auto base = strncmp(js.string, s, shorter);
+  return ((base != 0) || (sSize == js.string_size)) ? base : ((js.string_size < sSize) ?
+    -s[shorter] : js.string[shorter]);
+}
+
+int StrCmp(const json_string_s& js, const std::string& s)
+{
+  auto sSize = s.size();
+  auto shorter = std::min(js.string_size, sSize);
+  auto base = strncmp(js.string, s.c_str(), shorter);
+  return ((base != 0) || (sSize == js.string_size)) ? base : ((js.string_size < sSize) ?
+    -s[shorter] : js.string[shorter]);
+}
+
+void Validate(const json_value_s & jv, json_type_e type)
+{
+  if (jv.type != type)
+  {
+    throw std::runtime_error("Invalid type; expected: " + std::to_string(type) + ", got: " + std::to_string(jv.type));
+  }
+}
+
+json_value_s* FindObjectChild(const std::string& key, json_object_s& obj)
+{
+  auto i = obj.start;
+  while (i)
+  {
+    if (0 == StrCmp(*i->name, key))
+    {
+      return i->value;
+    }
+    i = i->next;
+  }
+  return nullptr;
+}
+
+}
diff --git a/dali-scene-loader/internal/json-reader.h b/dali-scene-loader/internal/json-reader.h
new file mode 100644 (file)
index 0000000..2f769a7
--- /dev/null
@@ -0,0 +1,439 @@
+#ifndef DALI_SCENE_LOADER_JSON_READER_H_
+#define DALI_SCENE_LOADER_JSON_READER_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/third-party/json.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include <algorithm>
+#include <map>
+#include <string_view>
+#include <sstream>
+#include <cstring>
+#include <memory>
+
+namespace json
+{
+
+/**
+ * @brief Helper for freeing the memory allocated by json_parse()
+ */
+struct json_value_deleter
+{
+  void operator()(json_value_s* p) const
+  {
+    free(p);
+  }
+};
+typedef std::unique_ptr<json_value_s, json_value_deleter> unique_ptr;
+
+/**
+ * @brief Case sensitive comparison of json_string_s and c-string.
+ * @return difference in first different character, or 0 if the strings are identical.
+ */
+int StrCmp(const json_string_s& js, const char* s);
+
+/**
+ * @brief Case sensitive comparison of json_string_s and std::string.
+ * @return difference in first different character, or 0 if the strings are identical.
+ */
+int StrCmp(const json_string_s& js, const std::string& s);
+
+/**
+ * @brief Convenience function to compare json_string_s and other supported string type,
+ *  in swapped order.
+ */
+template <typename String>
+inline
+int StrCmp(String& s, const json_string_s& js)
+{
+  return -StrCmp(js, s);
+}
+
+/**
+ * @brief Checks @a jv to be the given @a type, otherwise a std::runtime_error is thrown.
+ */
+void Validate(const json_value_s& jv, json_type_e type);
+
+namespace detail
+{
+/**
+ * @brief Compile-time type-enum mapping.
+ */
+template <typename T>
+struct Type2Enum
+{};
+
+#define TYPE2ENUM(x) template<> struct Type2Enum<json_## x ##_s>\
+{\
+  enum { VALUE = json_type_## x };\
+};
+
+TYPE2ENUM(object)
+TYPE2ENUM(array)
+TYPE2ENUM(string)
+TYPE2ENUM(number)
+#undef TYPE2ENUM
+}
+
+/**
+ * @brief Casts the payload of a json_value_s to the given type.
+ */
+template <typename Out>
+inline
+const Out& Cast(const json_value_s& j)
+{
+  Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
+  return *static_cast<const Out*>(j.payload);
+}
+
+/**
+ * @brief Casts the payload of a json_value_s to the given type.
+ * @note std::runtime_error is thrown if the value is not the given type.
+ */
+template <typename Out>
+inline
+Out& Cast(json_value_s& j)
+{
+  Validate(j, static_cast<json_type_e>(detail::Type2Enum<typename std::decay<Out>::type>::VALUE));
+  return *static_cast<Out*>(j.payload);
+}
+
+/**
+ * @brief Helper function to find a child element of @a obj mapped to @a key.
+ * @return Pointer to the element, or nullptr if it could not be found.
+ */
+json_value_s* FindObjectChild(const std::string& key, json_object_s& obj);
+
+/**
+ * @brief Helper functions for reading various value types.
+ */
+struct Read
+{
+  static bool Boolean(const json_value_s& j)
+  {
+    if (j.type == json_type_true)
+    {
+      return true;
+    }
+    else if (j.type == json_type_false)
+    {
+      return false;
+    }
+    else // try to interpret a numeric value.
+    {
+      return Number<int>(j) != 0;
+    }
+  }
+
+  template <typename T>
+  static T Number(const json_value_s& j)
+  {
+    auto& jn = Cast<const json_number_s>(j);
+    std::stringstream ss;
+    for (auto i0 = jn.number, i1 = i0 + jn.number_size; i0 != i1; ++i0)
+    {
+      ss.put(*i0);
+    }
+
+    T result;
+    if (ss >> result)
+    {
+      return result;
+    }
+    throw std::runtime_error("Failed to convert value to number");
+  }
+
+  template <typename E>
+  static E Enum(const json_value_s& j)
+  {
+    size_t number = Number<size_t>(j);
+    return static_cast<E>(number);
+  }
+
+  static std::string_view StringView(const json_value_s& j)
+  {
+    auto& js = Cast<json_string_s>(j);
+    return std::string_view(js.string, js.string_size);
+  }
+
+  static std::string String(const json_value_s& j)
+  {
+    auto& js = Cast<const json_string_s>(j);
+    return std::string(js.string, js.string_size);
+  }
+
+  template <typename T, T(*readElement)(const json_value_s&)>
+  static std::vector<T> Array(const json_value_s& j)
+  {
+    auto& ja = Cast<const json_array_s>(j);
+    std::vector<T> result;
+    result.reserve(ja.length);
+    auto i = ja.start;
+    while (i)
+    {
+      result.push_back(std::move(readElement(*i->value)));
+      i = i->next;
+    }
+    return result;
+  }
+};
+
+/**
+ * @brief Core class for object properties.
+ */
+struct PropertyCore
+{
+protected:
+  explicit PropertyCore(const std::string& key)
+  : mKey(key)
+  {}
+
+  const std::string& GetKey() const { return mKey; }
+
+private:
+  std::string mKey;
+};
+
+/**
+ * @brief Base class for the properties of a type T.
+ */
+template <typename T>
+struct PropertyBase : PropertyCore
+{
+  using PropertyCore::GetKey;
+
+  explicit PropertyBase(const std::string& key)
+  : PropertyCore(key)
+  {}
+
+  virtual ~PropertyBase()
+  {}
+
+  virtual void Read(const json_value_s& j, T& obj) = 0;
+};
+
+/**
+ * @brief Concrete property of an object to read into from JSON with a given function.
+ */
+template <class T, typename U>
+struct Property : PropertyBase<T>
+{
+  using ReadFn = U(*)(const json_value_s&);
+  using MemberPtr = U T::*;
+  using SetterArgType = typename std::conditional<sizeof(U) <= sizeof(uintptr_t), U, const U&>::type;
+  using Setter = void (T::*)(SetterArgType);
+
+  Property(const std::string& key, ReadFn read, MemberPtr ptr)
+  : PropertyBase<T>(key),
+    mRead(read),
+    mAccessor(new DirectAccessor(ptr))
+  {}
+
+  Property(const std::string& key, ReadFn read, Setter setter)
+  : PropertyBase<T>(key),
+    mRead(read),
+    mAccessor(new SetterAccessor(setter))
+  {}
+
+  ~Property()
+  {}
+
+  void Read(const json_value_s& j, T& obj) override
+  {
+    mAccessor->Set(mRead(j), obj);
+  }
+
+private:
+  struct AccessorBase
+  {
+    virtual ~AccessorBase()
+    {}
+
+    virtual void Set(U value, T& obj) const = 0;
+  };
+
+  struct DirectAccessor : AccessorBase
+  {
+    DirectAccessor(MemberPtr ptr)
+    : mPointer(ptr)
+    {}
+
+    void Set(U value, T& obj) const override
+    {
+      obj.*mPointer = std::move(value);
+    }
+
+    MemberPtr mPointer;
+  };
+
+  struct SetterAccessor : AccessorBase
+  {
+    SetterAccessor(Setter setter)
+    : mSetter(setter)
+    {}
+
+    void Set(U value, T& obj) const override
+    {
+      (obj.*mSetter)(value);
+    }
+
+    Setter mSetter;
+  };
+
+  ReadFn mRead;
+  std::unique_ptr<AccessorBase> mAccessor;
+};
+
+/**
+ * @brief Helper function to make a Property for a member of type U, of object of type T.
+ */
+template <class T, typename U>
+Property<T, U>* MakeProperty(const std::string& key, typename Property<T, U>::ReadFn readFn,
+  U T::* ptr)
+{
+  return new Property<T, U>(key, readFn, ptr);
+}
+
+/**
+ * @brief Core class for an object Reader.
+ */
+struct ReaderCore
+{
+protected:
+  std::vector<void*> mProperties;
+
+  ReaderCore() = default;
+
+  ReaderCore(const ReaderCore& other) = delete;
+  ReaderCore& operator=(const ReaderCore& other) = delete;
+
+  ReaderCore(ReaderCore&& other) = default;
+  ReaderCore& operator=(ReaderCore&& other) = default;
+};
+
+/**
+ * @brief Object Reader template for reading into an object of a given type,
+ *  with properties registered for the various members.
+ */
+template <typename T>
+class Reader : protected ReaderCore
+{
+public:
+  Reader() = default;
+
+  Reader(const Reader<T>& other) = delete;
+  Reader<T>& operator=(const Reader<T>& other) = delete;
+
+  Reader(Reader<T>&& other) = default;
+  Reader<T>& operator=(Reader&& other) = default;
+
+  ~Reader()
+  {
+    for (auto& p : mProperties)
+    {
+      delete Cast(p);
+    }
+  }
+
+  Reader<T>& Register(PropertyBase<T>& prop)
+  {
+    auto iInsert = std::lower_bound(mProperties.begin(), mProperties.end(), &prop,
+      SortPredicate);
+    if (iInsert == mProperties.end() || Cast(*iInsert)->GetKey() != prop.GetKey())
+    {
+      mProperties.insert(iInsert, &prop);
+    }
+    else
+    {
+      delete Cast(*iInsert);
+      *iInsert = &prop;
+    }
+    return *this;
+  }
+
+  void Read(const json_object_s& jo, T& obj) const
+  {
+    auto i = jo.start;
+    while (i)
+    {
+      auto iFind = std::lower_bound(mProperties.begin(), mProperties.end(),
+        *i->name, FindPredicate);
+      if (iFind != mProperties.end())
+      {
+        auto prop = Cast(*iFind);
+        if (0 == StrCmp(*i->name, prop->GetKey()))
+        {
+          prop->Read(*i->value, obj);
+        }
+      }
+      i = i->next;
+    }
+  }
+
+private:
+  static inline PropertyBase<T>* Cast(void* p)
+  {
+    return static_cast<PropertyBase<T>*>(p);
+  }
+
+  static bool SortPredicate(void* p, PropertyBase<T>* prop)
+  {
+    const auto prop0 = Cast(p);
+    return prop0->GetKey().compare(prop->GetKey()) < 0;
+  }
+
+  static bool FindPredicate(void* p, const json_string_s& key)
+  {
+    const auto prop = Cast(p);
+    return StrCmp(prop->GetKey(), key) < 0;
+  }
+};
+
+/**
+ * @brief Wraps a Reader<T> in a function usable as a Property<T>::ReadFn, i.e. to facilitate
+ *  deserializing structures of nested objects.
+ */
+template <typename T>
+struct ObjectReader
+{
+  static const Reader<T>* sReader;
+
+  static T Read(const json_value_s& j)
+  {
+    T result;
+    auto& jo = Cast<json_object_s>(j);
+    sReader->Read(jo, result);
+    return result;
+  }
+};
+
+template <typename T>
+const Reader<T>* ObjectReader<T>::sReader = nullptr;
+
+template <typename T>
+void SetObjectReader(const Reader<T>& r)
+{
+  ObjectReader<T>::sReader = &r;
+}
+
+} // json
+
+#endif //DALI_SCENE_LOADER_JSON_READER_H_
diff --git a/dali-scene-loader/internal/json-util.cpp b/dali-scene-loader/internal/json-util.cpp
new file mode 100644 (file)
index 0000000..613a764
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/internal/json-util.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/extents.h"
+#include "dali/public-api/math/matrix3.h"
+#include "dali/public-api/math/matrix.h"
+#include "dali/public-api/math/quaternion.h"
+#include "dali/public-api/math/radian.h"
+#include "dali/public-api/math/vector2.h"
+#include "dali/public-api/math/vector3.h"
+#include "dali/public-api/object/property-value.h"
+#include "dali/devel-api/common/map-wrapper.h"
+#include <array>
+
+namespace Dali
+{
+using namespace Toolkit;
+
+namespace SceneLoader
+{
+namespace
+{
+
+template <typename T>
+Property::Value ReadPrimitiveHelper(const TreeNode* tn, bool(*reader)(const TreeNode*, T&))
+{
+  T value;
+  if (reader(tn, value))
+  {
+    return Property::Value(value);
+  }
+  return Property::Value();
+}
+
+template <typename T>
+Property::Value ReadVectorHelper(const TreeNode* tn)
+{
+  static_assert(sizeof(T) % sizeof(float) == 0, "");
+  T value;
+  if (ReadVector(tn, value.AsFloat(), sizeof(T) / sizeof(float)))
+  {
+    return Property::Value(value);
+  }
+  return Property::Value();
+}
+
+Property::Value ReadVectorSingleFloatHelper(const TreeNode* tn)
+{
+  float value;
+  if (ReadVector(tn, &value, 1u))
+  {
+    return Property::Value(value);
+  }
+  return Property::Value();
+}
+
+Property::Value ReadRotationHelper(const TreeNode* tn)
+{
+  switch (tn->Size())
+  {
+  case 3:
+  {
+    // degrees as per spec
+    Vector3 rotation;
+    ReadVector(tn, rotation.AsFloat(), 3u);
+    return Property::Value(Quaternion(Radian(Degree(rotation.x)),
+      Radian(Degree(rotation.y)),
+      Radian(Degree(rotation.z))));
+  }
+  case 4:
+  {
+    Vector4 v;
+    ReadVector(tn, v.AsFloat(), 4u);
+    //Quaternion
+    return Property::Value(Quaternion(v));
+  }
+  default:
+    return Property::Value();
+  }
+}
+
+template <typename T>
+bool ReadQuadHelper(const TreeNode* tn, const std::array<T*, 4>& quad)
+{
+  auto i = quad.begin();
+  auto iEnd = quad.end();
+  auto iJson = tn->CBegin();
+  while (iJson != tn->CEnd() && i != iEnd)
+  {
+    int value;
+    if (ReadInt(&(*iJson).second, value) && value <= std::numeric_limits<T>::max())
+    {
+      **i = value;
+      ++i;
+      ++iJson;
+    }
+    else
+    {
+      return false;
+    }
+  }
+  return true;
+}
+
+const std::map<std::string, Property::Value(*)(const TreeNode*)> kTypeIds {
+  // NONE
+  { "boolean", [](const TreeNode* tn) {
+    return ReadPrimitiveHelper<bool>(tn, ReadBool);
+  }},
+  { "float", [](const TreeNode* tn) {
+    return ReadPrimitiveHelper<float>(tn, ReadFloat);
+  }},
+  { "integer", [](const TreeNode* tn) {
+    return ReadPrimitiveHelper<int>(tn, ReadInt);
+  }},
+  { "vector2", ReadVectorHelper<Vector2> },
+  { "vector3", ReadVectorHelper<Vector3> },
+  { "vector4", ReadVectorHelper<Vector4> },
+  { "matrix3", ReadVectorHelper<Matrix3> },
+  { "matrix", ReadVectorHelper<Matrix> },
+  { "rectangle", [](const TreeNode* tn) {
+    Rect<int> value;
+    if (ReadQuadHelper<int>(tn, { &value.x, &value.y, &value.width, &value.height }))
+    {
+      return Property::Value(value);
+    }
+    return Property::Value();
+  }},
+  { "rotation", ReadRotationHelper },
+  // STRING - not particularly animatable
+  // ARRAY - not particularly animatable
+  // MAP - not particularly animatable
+  { "extents", [](const TreeNode* tn) {
+    Extents value;
+    if (ReadQuadHelper<uint16_t>(tn, { &value.start, &value.end, &value.top, &value.bottom }))
+    {
+      return Property::Value(value);
+    }
+    return Property::Value();
+  }},
+};
+
+Property::Value(* const kArrayPropertyProcessors[])(const TreeNode*) {
+  ReadVectorHelper<Matrix>,
+  ReadVectorHelper<Matrix3>,
+  ReadVectorHelper<Vector4>,
+  ReadVectorHelper<Vector3>,
+  ReadVectorHelper<Vector2>,
+  ReadVectorSingleFloatHelper
+};
+
+}  // nonamespace
+
+bool ReadBool(const TreeNode* node, bool& num)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if (node->GetType() == TreeNode::BOOLEAN)
+  {
+    num = node->GetBoolean();
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadInt(const TreeNode* node, int& num)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if (node->GetType() == TreeNode::INTEGER)
+  {
+    num = node->GetInteger();
+    returnValue = true;
+  }
+  else if (node->GetType() == TreeNode::FLOAT)
+  {
+    num = static_cast<int>(node->GetFloat());
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadFloat(const TreeNode* node, float& num)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if (node->GetType() == TreeNode::FLOAT)
+  {
+    num = node->GetFloat();
+    returnValue = true;
+  }
+  else if (node->GetType() == TreeNode::INTEGER)
+  {
+    num = static_cast<float>(node->GetInteger());
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadIndex(const Toolkit::TreeNode* node, Index& num)
+{
+  bool returnValue = node && node->GetType() == TreeNode::INTEGER;
+  if (returnValue)
+  {
+    num = static_cast<Index>(node->GetInteger());
+  }
+
+  return returnValue;
+}
+
+bool ReadBlob(const Toolkit::TreeNode* node, unsigned int& offset, unsigned int& length)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  int iOffset, iLength;
+  bool success = ReadInt(node->GetChild("byteOffset"), iOffset) &&
+    ReadInt(node->GetChild("byteLength"), iLength) &&
+    iOffset >= 0 && iLength >= 0;  // 0 length might not be sensible, but is not an error at this stage.
+  if (success)
+  {
+    offset = static_cast<unsigned int>( iOffset );
+    length = static_cast<unsigned int>( iLength );
+  }
+  return success;
+}
+
+size_t GetNumericalArraySize(const TreeNode* node)
+{
+  size_t size = 0;
+  if (node->GetType() == TreeNode::ARRAY)
+  {
+    for (auto i0 = node->CBegin(), i1 = node->CEnd(); i0 != i1 &&
+      ((*i0).second.GetType() == TreeNode::FLOAT || (*i0).second.GetType() == TreeNode::INTEGER);
+      ++i0)
+    {
+      ++size;
+    }
+  }
+  return size;
+}
+
+bool ReadVector(const TreeNode* node, float* num, unsigned int size)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if ((node->Size() >= size) && (node->GetType() == TreeNode::ARRAY))
+  {
+    unsigned int offset = 0u;
+    for (TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset)
+    {
+      const TreeNode& coord = (*it).second;
+      if (!ReadFloat(&coord, *(num + offset)))
+      {
+        return false;
+      }
+    }
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadVector(const Toolkit::TreeNode* node, int* num, unsigned int size)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if ((node->Size() >= size) && (node->GetType() == TreeNode::ARRAY))
+  {
+    unsigned int offset = 0u;
+    for (TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset)
+    {
+      const TreeNode& coord = (*it).second;
+      if (!ReadInt(&coord, *(num + offset)))
+      {
+        return false;
+      }
+    }
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadColor(const TreeNode* node, Vector4& color)
+{
+  if (nullptr == node)
+  {
+    return false;
+  }
+
+  if (!ReadVector(node, color.AsFloat(), 4))
+  {
+    if (!ReadVector(node, color.AsFloat(), 3))
+    {
+      return false;
+    }
+    color.a = 1.f;
+  }
+
+  return true;
+}
+
+bool ReadTimePeriod(const TreeNode* node, TimePeriod& timePeriod)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  if (!ReadFloat(node->GetChild("delay"), timePeriod.delaySeconds) || !ReadFloat(node->GetChild("duration"), timePeriod.durationSeconds))
+  {
+    return false;
+  }
+  return true;
+}
+
+bool ReadString(const TreeNode* node, std::string& strValue)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if (node->GetType() == TreeNode::STRING)
+  {
+    strValue = node->GetString();
+    returnValue = true;
+  }
+  return returnValue;
+}
+
+bool ReadStringVector(const TreeNode* node, std::vector<std::string>& strvector)
+{
+  if (!node)
+  {
+    return false;
+  }
+
+  bool returnValue = false;
+  if (node->GetType() == TreeNode::ARRAY)
+  {
+    for (TreeNode::ConstIterator it = node->CBegin(); it != node->CEnd(); ++it)
+    {
+      const TreeNode& strNode = (*it).second;
+      if (strNode.GetType() == TreeNode::STRING)
+      {
+        strvector.push_back(strNode.GetString());
+      }
+      else
+      {
+        return false;
+      }
+    }
+    returnValue = true;
+  }
+  return returnValue;
+}
+
+Property::Value ReadPropertyValue(const Property::Type& propType, const TreeNode& tn)
+{
+  switch (propType)
+  {
+  case Property::BOOLEAN:
+    return ReadPrimitiveHelper<bool>(&tn, ReadBool);
+
+  case Property::FLOAT:
+    return ReadPrimitiveHelper<float>(&tn, ReadFloat);
+
+  case Property::INTEGER:
+    return ReadPrimitiveHelper<int>(&tn, ReadInt);
+
+  case Property::VECTOR2:
+    return ReadVectorHelper<Vector2>(&tn);
+
+  case Property::VECTOR3:
+    return ReadVectorHelper<Vector3>(&tn);
+
+  case Property::VECTOR4:
+    return ReadVectorHelper<Vector4>(&tn);
+
+  case Property::MATRIX3:
+    return ReadVectorHelper<Matrix3>(&tn);
+
+  case Property::MATRIX:
+    return ReadVectorHelper<Matrix>(&tn);
+
+  case Property::RECTANGLE:
+  {
+    Rect<int> value;
+    if (ReadQuadHelper<int>(&tn, { &value.x, &value.y, &value.width, &value.height }))
+    {
+      return Property::Value(value);
+    }
+    break;
+  }
+
+  case Property::ROTATION:
+    return ReadRotationHelper(&tn);
+
+  case Property::EXTENTS:
+  {
+    Extents value;
+    if (ReadQuadHelper<uint16_t>(&tn, { &value.start, &value.end, &value.top, &value.bottom }))
+    {
+      return Property::Value(value);
+    }
+    break;
+  }
+
+  case Property::NONE: // fall
+  default:
+  {
+    DALI_ASSERT_ALWAYS(!"Property type incorrect");
+  }
+  }
+  return Property::Value();
+}
+
+Property::Value ReadPropertyValue(const Toolkit::TreeNode& tn)
+{
+  Property::Value propValue;
+  if (tn.GetType() == TreeNode::OBJECT)  // attempt to disambiguate type.
+  {
+    auto jsonType = tn.GetChild("type");
+    if (jsonType && jsonType->GetType() == TreeNode::STRING)
+    {
+      auto iFind = kTypeIds.find(jsonType->GetString());
+      if (iFind != kTypeIds.end())
+      {
+        propValue = iFind->second(tn.GetChild("value"));
+      }
+    }
+  }
+
+  if (propValue.GetType() == Property::NONE)
+  {
+    if (tn.Size() == 0)
+    {
+      switch (tn.GetType())
+      {
+      case TreeNode::BOOLEAN:
+        propValue = ReadPrimitiveHelper<bool>(&tn, ReadBool);
+        break;
+
+      case TreeNode::INTEGER:
+        propValue = ReadPrimitiveHelper<int>(&tn, ReadInt);
+        break;
+
+      case TreeNode::FLOAT:
+        propValue = ReadPrimitiveHelper<float>(&tn, ReadFloat);
+        break;
+
+      default:
+        break;
+      }
+    }
+    else
+    {
+      bool allNumbers = true;
+      for (auto i0 = tn.CBegin(), i1 = tn.CEnd(); i0 != i1; ++i0)
+      {
+        auto type = (*i0).second.GetType();
+        if(!(type == TreeNode::FLOAT || type == TreeNode::INTEGER))
+        {
+          allNumbers = false;
+          break;
+        }
+      }
+
+      if (allNumbers)
+      {
+        // NOTE: rotations / rectangles / extents must be disambiguated in all circumstances.
+        for (auto& r : kArrayPropertyProcessors)
+        {
+          propValue = r(&tn);
+          if (propValue.GetType() != Property::NONE)
+          {
+            break;
+          }
+        }
+      }
+    }
+  }
+  return propValue;
+}
+
+}
+}
diff --git a/dali-scene-loader/internal/json-util.h b/dali-scene-loader/internal/json-util.h
new file mode 100644 (file)
index 0000000..64a99cd
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef DALI_SCENE_LOADER_JSON_UTIL_H_
+#define DALI_SCENE_LOADER_JSON_UTIL_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/index.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/public-api/animation/time-period.h"
+#include "dali/public-api/object/property.h"
+#include "dali/public-api/math/vector4.h"
+#include "dali-toolkit/devel-api/builder/tree-node.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+bool ReadBool(const Toolkit::TreeNode* node, bool& num);
+
+bool ReadInt(const Toolkit::TreeNode* node, int& num);
+
+bool ReadFloat(const Toolkit::TreeNode* node, float& num);
+
+bool ReadIndex(const Toolkit::TreeNode* node, Index& num);
+
+bool ReadBlob(const Toolkit::TreeNode* node, unsigned int& offset, unsigned int& length);
+
+/**
+ * @brief Gets the number of numerical element of a JSON array;
+ * @return 0 if not an array, otherwise the number of float or integer elements
+ *  at the front of the array.
+ */
+size_t GetNumericalArraySize(const Toolkit::TreeNode* node);
+
+bool ReadVector(const Toolkit::TreeNode* node, float* num, unsigned int size);
+
+bool ReadVector(const Toolkit::TreeNode* node, int* num, unsigned int size);
+
+/**
+ * @brief Reads a color.
+ * 
+ * The node contents could be a vector of 4 floats [r,g,b,a].
+ * 
+ * @param[in] node The tree node with the color.
+ * @param[out] color The RGBA color.
+ * 
+ * @return true if succedded to read the color.
+ */
+bool ReadColor(const Toolkit::TreeNode* node, Vector4& color);
+
+bool ReadTimePeriod(const Toolkit::TreeNode* node, TimePeriod& timePeriod);
+
+bool ReadString(const Toolkit::TreeNode* node, std::string& strValue);
+
+bool ReadStringVector(const Toolkit::TreeNode* node, std::vector<std::string>& strvector);
+
+/**
+ * @brief Attempts to read a property of the given type from the given JSON node.
+ * @return The property value that it could interpret. If unsuccessful, its type will be NONE.
+ * @note Currently only numerical types are supported (including boolean).
+ */
+Property::Value ReadPropertyValue(const Property::Type& propType, const Toolkit::TreeNode& tn);
+
+/**
+ * @brief Attempts to read a property, whose type it will attempt to determine from the given
+ *  JSON node.
+ * @return The property value that it could interpret. If unsuccessful, its type will be NONE.
+ * @note Currently only numerical types are supported (including boolean).
+ * @note Supports a disambiguation syntax, whereby the type can be specified explicitly:
+ *  { "type": "rotation", "value": [...] } .
+ * @note: rotation / rectangle / extents type properties must be disambiguated in all circumstances.
+ */
+Property::Value ReadPropertyValue(const Toolkit::TreeNode& tn);
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_JSON_UTIL_H_
diff --git a/dali-scene-loader/public-api/alpha-function-helper.cpp b/dali-scene-loader/public-api/alpha-function-helper.cpp
new file mode 100644 (file)
index 0000000..33ad3db
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/alpha-function-helper.h"
+#include <unordered_map>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+
+#define DALI_ALPHA_FUNCTION_ENTRY(x) { #x, AlphaFunction::x }
+
+std::unordered_map<std::string, AlphaFunction> sFunctions {
+  DALI_ALPHA_FUNCTION_ENTRY(DEFAULT),
+  DALI_ALPHA_FUNCTION_ENTRY(LINEAR),
+  DALI_ALPHA_FUNCTION_ENTRY(REVERSE),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_IN_SQUARE),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_OUT_SQUARE),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_IN),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_OUT),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_IN_OUT),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_IN_SINE),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_OUT_SINE),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_IN_OUT_SINE),
+  DALI_ALPHA_FUNCTION_ENTRY(BOUNCE),
+  DALI_ALPHA_FUNCTION_ENTRY(SIN),
+  DALI_ALPHA_FUNCTION_ENTRY(EASE_OUT_BACK),
+};
+
+#undef DALI_ALPHA_FUNCTION_ENTRY
+
+} // nonamespace
+
+AlphaFunction GetAlphaFunction(const std::string& name, bool* found)
+{
+  auto iFind = sFunctions.find(name);
+  bool success = iFind != sFunctions.end();
+  if (found)
+  {
+    *found = success;
+  }
+  return success ? iFind->second : AlphaFunction(AlphaFunction::DEFAULT);
+}
+
+void RegisterAlphaFunction(const std::string & name, AlphaFunction alphaFn)
+{
+  DALI_ASSERT_ALWAYS(sFunctions.insert({ name, alphaFn }).second &&
+    "Function with given key already exists.");
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/alpha-function-helper.h b/dali-scene-loader/public-api/alpha-function-helper.h
new file mode 100644 (file)
index 0000000..1a6c9ad
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DALI_SCENE_LOADER_ALPHA_FUNCTION_HELPER_H_
+#define DALI_SCENE_LOADER_ALPHA_FUNCTION_HELPER_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/api.h"
+
+#include "dali/public-api/animation/alpha-function.h"
+#include <string>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @return Given a name, provide a AlphaFunction; if the name was not
+ *  recognised, get the default one.
+ */
+AlphaFunction DALI_SCENE_LOADER_API GetAlphaFunction(const std::string& name, bool* found = nullptr);
+
+/**
+ * @brief Registers an alpha function only if one with the same @a name has
+ *  not yet been registered. Throws Exception the name isn't unique.
+ */
+void DALI_SCENE_LOADER_API RegisterAlphaFunction(const std::string& name, AlphaFunction alphaFn) noexcept(false);
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_ALPHA_FUNCTION_HELPER_H_
diff --git a/dali-scene-loader/public-api/animated-property.cpp b/dali-scene-loader/public-api/animated-property.cpp
new file mode 100644 (file)
index 0000000..1e8a592
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/animated-property.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+void AnimatedProperty::Animate(Animation& anim, GetActor getActor)
+{
+  if (Actor actor = getActor(mNodeName))
+  {
+    Property prop = GetProperty(actor);
+    if (mKeyFrames)
+    {
+      anim.AnimateBetween(prop, mKeyFrames, mAlphaFunction, mTimePeriod);
+    }
+    else if (mValue)
+    {
+      if (mValue->mIsRelative)
+      {
+        anim.AnimateBy(prop, mValue->mValue, mAlphaFunction, mTimePeriod);
+      }
+      else
+      {
+        anim.AnimateTo(prop, mValue->mValue, mAlphaFunction, mTimePeriod);
+      }
+    }
+  }
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/animated-property.h b/dali-scene-loader/public-api/animated-property.h
new file mode 100644 (file)
index 0000000..026b68a
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef DALI_SCENE_LOADER_ANIMATED_PROPERTY_H
+#define DALI_SCENE_LOADER_ANIMATED_PROPERTY_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/actors/actor.h"
+#include "dali/public-api/animation/animation.h"
+#include "dali/public-api/object/property.h"
+#include <memory>
+#include <functional>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Intermediate representation for a property that's given to
+ *  a Animation to animate. Since there is no getting an
+ *  animated property back from the Animation (i.e. past AnimateBetween/By/To()),
+ *  changing properties (e.g. from the SDK) requires the whole Animation
+ *  object to be recreated with all of its properties (incl. modifications).
+ */
+struct DALI_SCENE_LOADER_API AnimatedProperty
+{
+public: // METHODS
+  /**
+   * @brief Function to obtain an Actor based on its name. Its processing will
+   *  ignore empty handles returned by it.
+   */
+  using GetActor = std::function<Actor(const std::string&)>;
+
+  /**
+   * @return The Property object (of the given @a actor) whose value is being animated.
+   */
+  Property GetProperty(Actor& actor)
+  {
+    auto idx = actor.GetPropertyIndex(mPropertyName);
+    return Property(actor, idx);
+  }
+
+  /**
+   * @brief The type of the Property (of the given @a actor) that is being animated.
+   */
+  Property::Type GetPropertyType(Actor& actor)
+  {
+    auto idx = actor.GetPropertyIndex(mPropertyName);
+    return actor.GetPropertyType(idx);
+  }
+
+  /**
+   * @brief Registers the animation of this property against the given @a anim.
+   *  @a getActor will be used to obtain the Actor named by this property.
+   *  Failing to find the actor purely means that this property will not be
+   *  animated.
+   */
+  void Animate(Animation& anim, GetActor getActor);
+
+public: // DATA
+  struct Value
+  {
+    Property::Value mValue;
+    bool mIsRelative;
+  };
+
+  std::string mNodeName;
+  std::string mPropertyName;
+
+  KeyFrames mKeyFrames;
+  std::unique_ptr<Value> mValue;
+
+  AlphaFunction mAlphaFunction = AlphaFunction::DEFAULT;
+  TimePeriod mTimePeriod = TimePeriod(0.f);
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_ANIMATED_PROPERTY_H
diff --git a/dali-scene-loader/public-api/animation-definition.cpp b/dali-scene-loader/public-api/animation-definition.cpp
new file mode 100644 (file)
index 0000000..b41b8d5
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/animation-definition.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+const float AnimationDefinition::DEFAULT_DURATION_SECONDS = 1.f;
+const float AnimationDefinition::MIN_DURATION_SECONDS = 1e-2f;
+
+Animation::EndAction AnimationDefinition::StopForModification(Animation& anim)
+{
+  const auto endAction = anim.GetEndAction();
+  anim.SetEndAction(Animation::DISCARD);
+  anim.Stop();
+  return endAction;
+}
+
+AnimationDefinition::AnimationDefinition()
+{}
+
+AnimationDefinition::AnimationDefinition(AnimationDefinition&& other)
+:  mName(std::move(other.mName)),
+  mDuration(other.mDuration),
+  mLoopCount(other.mLoopCount),
+  mDisconnectAction(other.mDisconnectAction),
+  mEndAction(other.mEndAction),
+  mSpeedFactor(other.mSpeedFactor),
+  mPlayRange(other.mPlayRange),
+  mProperties(std::move(other.mProperties))
+{}
+
+void AnimationDefinition::Animate(Animation& animation, AnimatedProperty::GetActor getActor)
+{
+  DALI_ASSERT_ALWAYS(animation);
+  for (auto& ap : mProperties)
+  {
+    ap.Animate(animation, getActor);
+  }
+}
+
+Animation AnimationDefinition::ReAnimate(AnimatedProperty::GetActor getActor)
+{
+  // Create and configure new animation.
+  Animation a = Animation::New(mDuration);
+  a.SetLoopCount(mLoopCount);
+  a.SetDisconnectAction(mDisconnectAction);
+  a.SetEndAction(mEndAction);
+
+  a.SetSpeedFactor(mSpeedFactor);
+  a.SetPlayRange(mPlayRange);
+
+  Animate(a, getActor);
+  return a;
+}
+
+AnimationDefinition& AnimationDefinition::operator=(AnimationDefinition&& other)
+{
+  AnimationDefinition tmp(std::move(other));
+  mName = std::move(tmp.mName);
+  mDuration = tmp.mDuration;
+  mLoopCount = tmp.mLoopCount;
+  mDisconnectAction = tmp.mDisconnectAction;
+  mEndAction = tmp.mEndAction;
+  mSpeedFactor = tmp.mSpeedFactor;
+  mPlayRange = tmp.mPlayRange;
+  mProperties.swap(tmp.mProperties);
+  return *this;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/animation-definition.h b/dali-scene-loader/public-api/animation-definition.h
new file mode 100644 (file)
index 0000000..41de471
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DALI_SCENE_LOADER_ANIMATION_DEFINITION_H
+#define DALI_SCENE_LOADER_ANIMATION_DEFINITION_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/animated-property.h"
+#include "dali/public-api/common/vector-wrapper.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Animation handle + name + definition of properties.
+ */
+class DALI_SCENE_LOADER_API AnimationDefinition
+{
+public: // STATIC
+  // For Animations created in the SDK.
+  static const float DEFAULT_DURATION_SECONDS;
+
+  // For parsing Animations from dli, when duration was not defined.
+  static const float MIN_DURATION_SECONDS;
+
+  /**
+   * @brief Saves the original end action of @a anim, sets the end action to
+   *  Discard, then stops the animation and returns the end action.
+   */
+  static Animation::EndAction StopForModification(Animation& anim);
+
+public: // METHODS
+  AnimationDefinition();
+
+  AnimationDefinition(AnimationDefinition&& other);
+
+  /**
+   * @brief Registers the properties against the given @a animation. @a getActor
+   *  will be used to obtain the Actors for each AnimatedProperty.
+   */
+  void Animate(Animation& animation, AnimatedProperty::GetActor getActor);
+
+  /**
+   * @brief Creates a new Animation and Animates() its properties. @a getActor
+   *  will be used to obtain the Actors for each AnimatedProperty.
+   */
+  Animation ReAnimate(AnimatedProperty::GetActor getActor);
+
+  AnimationDefinition& operator=(AnimationDefinition&& other);
+
+public: // DATA
+  std::string mName;
+
+  float mDuration = DEFAULT_DURATION_SECONDS;
+  int mLoopCount = 1;
+  Animation::EndAction mDisconnectAction = Animation::BAKE_FINAL;
+  Animation::EndAction mEndAction = Animation::BAKE;
+  float mSpeedFactor = 1.f;
+  Vector2 mPlayRange = Vector2{ 0.f, 1.f };
+
+  std::vector<AnimatedProperty> mProperties;
+};
+
+struct AnimationGroupDefinition
+{
+  std::string mName;
+  std::vector<std::string> mAnimations;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_ANIMATION_DEFINITION_H
diff --git a/dali-scene-loader/public-api/api.h b/dali-scene-loader/public-api/api.h
new file mode 100644 (file)
index 0000000..f5ffea0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef DALI_SCENE_LOADER_API_H
+#define DALI_SCENE_LOADER_API_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+#if __GNUC__ >= 4
+#define DALI_SCENE_LOADER_API __attribute__((visibility("default")))
+
+#elif defined(WIN32)
+#ifdef BUILDING_DALI_SCENE_LOADER
+#define DALI_SCENE_LOADER_API  __declspec(dllexport)
+#else
+#define DALI_SCENE_LOADER_API  __declspec(dllimport)
+#endif  // BUILDING_DALI_SCENE_LOADER
+
+#endif
+
+#endif //DALI_SCENE_LOADER_API_H
diff --git a/dali-scene-loader/public-api/blend-shape-details.cpp b/dali-scene-loader/public-api/blend-shape-details.cpp
new file mode 100644 (file)
index 0000000..3308d37
--- /dev/null
@@ -0,0 +1,85 @@
+
+/*
+* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+*
+* 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.
+*
+*/
+
+// FILE HEADER
+#include "dali-scene-loader/public-api/blend-shape-details.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/animation/constraints.h"
+#include "dali/public-api/object/property.h"
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/resource-bundle.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+const std::string BlendShapes::NUMBER_OF_BLEND_SHAPES("uNumberOfBlendShapes");
+const std::string BlendShapes::UNNORMALIZE_FACTOR("uBlendShapeUnnormalizeFactor");
+const std::string BlendShapes::COMPONENT_SIZE("uBlendShapeComponentSize");
+
+const std::string BlendShapes::COMPONENTS("blendShapeComponents");
+
+const std::string BlendShapes::WEIGHTS_UNIFORM("uBlendShapeWeight");
+
+void BlendShapes::ConfigureProperties(const std::pair<MeshDefinition, MeshGeometry>& mesh, Shader shader, Actor actor)
+{
+  unsigned int index = 0u;
+
+  char weightNameBuffer[32];
+  char unnormalizeFactorNameBuffer[64];
+  char* const pWeightName = weightNameBuffer + snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s", WEIGHTS_UNIFORM.c_str());
+  char* const pFactorName = unnormalizeFactorNameBuffer + snprintf(unnormalizeFactorNameBuffer, sizeof(unnormalizeFactorNameBuffer), "%s", UNNORMALIZE_FACTOR.c_str());
+  for (const auto& blendShape : mesh.first.mBlendShapes)
+  {
+    snprintf(pWeightName, sizeof(weightNameBuffer) - (pWeightName - weightNameBuffer), "[%d]", index);
+    std::string weightName{ weightNameBuffer };
+    actor.RegisterProperty(weightName, blendShape.weight);
+
+    if (mesh.first.mBlendShapeVersion == Version::VERSION_1_0)
+    {
+      snprintf(pFactorName, sizeof(unnormalizeFactorNameBuffer) - (pFactorName - unnormalizeFactorNameBuffer), "[%d]", index);
+      std::string factorName{ unnormalizeFactorNameBuffer };
+      shader.RegisterProperty(factorName, mesh.second.blendShapeUnnormalizeFactor[index]);
+    }
+
+    ++index;
+  }
+
+  if (Version::VERSION_2_0 == mesh.first.mBlendShapeVersion)
+  {
+    shader.RegisterProperty(UNNORMALIZE_FACTOR, mesh.second.blendShapeUnnormalizeFactor[0u]);
+  }
+
+  shader.RegisterProperty(NUMBER_OF_BLEND_SHAPES, Property::Value(static_cast<int>(index)));
+  shader.RegisterProperty(COMPONENT_SIZE, Property::Value(static_cast<int>(mesh.second.blendShapeBufferOffset)));
+
+  // Create a read only property to preserve the components of the blend shape.
+  int32_t components = 0x0;
+  for (auto& bs : mesh.first.mBlendShapes)
+  {
+    components |= (bs.deltas.IsDefined() * Component::POSITIONS) |
+      (bs.normals.IsDefined() * Component::NORMALS) | (bs.tangents.IsDefined() * Component::TANGENTS);
+  }
+  shader.RegisterProperty(COMPONENTS, components, Property::AccessMode::READ_ONLY);
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/blend-shape-details.h b/dali-scene-loader/public-api/blend-shape-details.h
new file mode 100644 (file)
index 0000000..7ea6d3f
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef DALI_SCENE_LOADER_BLEND_SHAPE_DETAILS_H
+#define DALI_SCENE_LOADER_BLEND_SHAPE_DETAILS_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/rendering/shader.h"
+#include "dali/public-api/actors/actor.h"
+#include <string>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+struct MeshDefinition;
+struct MeshGeometry;
+
+struct DALI_SCENE_LOADER_API BlendShapes
+{
+  enum class Version
+  {
+    VERSION_1_0,
+    VERSION_2_0,
+    INVALID
+  };
+
+  struct Component
+  {
+    enum
+    {
+      POSITIONS = 0x1,
+      NORMALS = 0x2,
+      TANGENTS = 0x4
+    };
+  };
+
+  // shader properties - animatable (uniforms)
+  static const std::string NUMBER_OF_BLEND_SHAPES;  ///< Integer number of blend shapes loaded.
+  static const std::string UNNORMALIZE_FACTOR;  ///< Scalar(s) for position components of blend shapes; Version 1.0: float array (1 per blend shape); Version 2.0: single float.
+  static const std::string COMPONENT_SIZE;  ///< Integer offset from one component (positions / normals / tangents) of a blend shape to the next.
+
+  // shader properties - read-only (not available as uniforms)
+  static const std::string COMPONENTS;  ///< Integer bitmask of the blend shape components that the shader uses; refer to the Components enum.
+
+  // actor property (instance) - animatable (uniforms)
+  static const std::string WEIGHTS_UNIFORM;  ///< The weight of each blend shape in a float array
+
+  /**
+   * @brief Registers properties based on the mesh definition (and geometry) and identified by the above string constants,
+   *  on the given @a shader and @a actor.
+   */
+  static void ConfigureProperties(const std::pair<MeshDefinition, MeshGeometry>& mesh, Shader shader, Actor actor);
+};
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_BLEND_SHAPE_DETAILS_H
diff --git a/dali-scene-loader/public-api/camera-parameters.cpp b/dali-scene-loader/public-api/camera-parameters.cpp
new file mode 100644 (file)
index 0000000..875c58b
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/camera-parameters.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include "dali/public-api/actors/camera-actor.h"
+#include "dali/public-api/math/quaternion.h"
+#include "dali/integration-api/debug.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+/**
+ * @brief Creates a perspective matrix.
+ *
+ * @param[out] result The perspective matrix.
+ * @param[in] left The coordinate for the left vertical clipping plane.
+ * @param[in] right The coordinate for the right vertical clipping plane.
+ * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
+ * @param[in] top The coordinate for the top horizontal clipping plane.
+ * @param[in] near The distance to the near depth clipping plane.
+ * @param[in] far The distance to the far depth clipping plane.
+ * @param[in] invertYAxis Whether to invert the 'Y' axis.
+ */
+void Frustum( Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis )
+{
+  float deltaZ = farPlane - nearPlane;
+  if ((nearPlane <= 0.0f) || (farPlane <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
+  {
+    DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
+    DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
+    return;
+  }
+
+  float deltaX = right - left;
+  float deltaY = invertYAxis ? bottom - top : top - bottom;
+
+  result.SetIdentity();
+
+  float* m = result.AsFloat();
+  m[0] = -2.0f * nearPlane / deltaX;
+  m[1] = m[2] = m[3] = 0.0f;
+
+  m[5] = -2.0f * nearPlane / deltaY;
+  m[4] = m[6] = m[7] = 0.0f;
+
+  m[8] = (right + left) / deltaX;
+  m[9] = (top + bottom) / deltaY;
+  m[10] = (nearPlane + farPlane) / deltaZ;
+  m[11] = 1.0f;
+
+  m[14] = -2.0f * nearPlane * farPlane / deltaZ;
+  m[12] = m[13] = m[15] = 0.0f;
+}
+
+/**
+ * @brief Creates a perspective projection matrix.
+ *
+ * It calls Frustum()
+ *
+ * @param[out] result The perspective projection matrix.
+ * @param[in] fovy The vertical field of view.
+ * @param[in] aspect The aspect ratio.
+ * @param[in] nearPlane The distance to the near depth clipping plane.
+ * @param[in] farPlane The distance to the far depth clipping plane.
+ * @param[in] invertYAxis Whether to invert the 'Y' axis.
+ */
+void Perspective( Matrix& result, float fovy, float aspect, float nearPlane, float farPlane, bool invertYAxis )
+{
+  float frustumH = tanf( fovy * 0.5f ) * nearPlane;
+  float frustumW = frustumH * aspect;
+
+  Frustum( result, -frustumW, frustumW, -frustumH, frustumH, nearPlane, farPlane, invertYAxis );
+}
+
+/**
+* @brief Creates an orthographic projection matrix.
+*
+* @param[out] result The orthographic projection matrix.
+* @param[in] left The coordinate for the left vertical clipping plane.
+* @param[in] right The coordinate for the right vertical clipping plane.
+* @param[in] bottom The coordinate for the bottom horizontal clipping plane.
+* @param[in] top The coordinate for the top horizontal clipping plane.
+* @param[in] nearPlane The distance to the near depth clipping plane.
+* @param[in] farPlane The distance to the far depth clipping plane.
+* @param[in] invertYAxis Whether to invert the 'Y' axis.
+*/
+void Orthographic(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
+{
+  if (Equals(right, left) || Equals(top, bottom) || Equals(farPlane, nearPlane))
+  {
+    DALI_LOG_ERROR("Cannot create orthographic projection matrix with a zero dimension.\n");
+    DALI_ASSERT_DEBUG("Cannot create orthographic projection matrix with a zero dimension.");
+    return;
+  }
+
+  float deltaX = right - left;
+  float deltaY = invertYAxis ? bottom - top : top - bottom;
+  float deltaZ = farPlane - nearPlane;
+
+  float *m = result.AsFloat();
+  m[0] = -2.0f / deltaX;
+  m[1] = 0.0f;
+  m[2] = 0.0f;
+  m[3] = 0.0f;
+
+  m[4] = 0.0f;
+  m[5] = -2.0f / deltaY;
+  m[6] = 0.0f;
+  m[7] = 0.0f;
+
+  m[8] = 0.0f;
+  m[9] = 0.0f;
+  m[10] = 2.0f / deltaZ;
+  m[11] = 0.0f;
+  m[12] = -(right + left) / deltaX;
+  m[13] = -(top + bottom) / deltaY;
+  m[14] = -(nearPlane + farPlane) / deltaZ;
+  m[15] = 1.0f;
+}
+
+} // nonamespace
+
+ViewProjection CameraParameters::GetViewProjection() const
+{
+  ViewProjection viewProjection;
+  // The projection matrix.
+  if (isPerspective)
+  {
+    Perspective(viewProjection.GetProjection(),
+      Radian(Degree(yFov)),
+      1.f,
+      zNear,
+      zFar,
+      true);
+  }
+  else
+  {
+    Orthographic(viewProjection.GetProjection(),
+      orthographicSize.x,
+      orthographicSize.y,
+      orthographicSize.z,
+      orthographicSize.w,
+      zNear,
+      zFar,
+      true);
+
+  }
+
+  // The view matrix.
+  const Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
+  Vector3 translation;
+  Quaternion cameraOrientation;
+  Vector3 scale;
+  matrix.GetTransformComponents(translation, cameraOrientation, scale);
+  cameraOrientation *= viewQuaternion;
+
+  viewProjection.GetView().SetInverseTransformComponents(scale,
+    cameraOrientation,
+    translation);
+
+  viewProjection.Update();
+  return viewProjection;
+}
+
+void CameraParameters::CalculateTransformComponents(Vector3 & position, Quaternion & orientation, Vector3 & scale) const
+{
+  matrix.GetTransformComponents(position, orientation, scale);
+
+  // The CameraActor is expected to look down the negative Z axis, towards the scene.
+  // Here we emulate the default direction of the camera in DALi.
+  Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
+  orientation *= viewQuaternion;
+}
+
+void CameraParameters::ConfigureCamera(CameraActor& camera) const
+{
+  SetActorCentered(camera);
+
+  if (isPerspective)
+  {
+    camera.SetProjectionMode(Camera::PERSPECTIVE_PROJECTION);
+    camera.SetNearClippingPlane(zNear);
+    camera.SetFarClippingPlane(zFar);
+    camera.SetFieldOfView(Radian(Degree(yFov)));
+  }
+  else
+  {
+    camera.SetProjectionMode(Camera::ORTHOGRAPHIC_PROJECTION);
+    camera.SetOrthographicProjection(orthographicSize.x,
+      orthographicSize.y,
+      orthographicSize.z,
+      orthographicSize.w,
+      zNear,
+      zFar);
+  }
+
+  // model
+  Vector3 camTranslation;
+  Vector3 camScale;
+  Quaternion camOrientation;
+  CalculateTransformComponents(camTranslation, camOrientation, camScale);
+
+  camera.SetInvertYAxis(true);
+  camera.SetProperty(Actor::Property::POSITION, camTranslation);
+  camera.SetProperty(Actor::Property::ORIENTATION, camOrientation);
+  camera.SetProperty(Actor::Property::SCALE, camScale);
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/camera-parameters.h b/dali-scene-loader/public-api/camera-parameters.h
new file mode 100644 (file)
index 0000000..20b3ee3
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef DALI_SCENE_LOADER_CAMERA_PARAMETERS_H
+#define DALI_SCENE_LOADER_CAMERA_PARAMETERS_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+ // INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/view-projection.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/matrix.h"
+#include "dali/public-api/math/vector3.h"
+
+namespace Dali
+{
+
+class CameraActor;
+
+namespace SceneLoader
+{
+
+struct DALI_SCENE_LOADER_API CameraParameters
+{
+  CameraParameters()
+  : matrix(Matrix::IDENTITY),
+    orthographicSize(-1.f, 1.f, 1.f, -1.f),
+    yFov(60.f),
+    zNear(0.1f),
+    zFar(1000.f),
+    isPerspective(true)
+  {}
+
+  ~CameraParameters() = default;
+
+  Matrix matrix;
+  Vector4 orthographicSize;
+  float yFov;
+  float zNear;
+  float zFar;
+  bool isPerspective;
+
+  /**
+   * @return The view-projection matrix of the camera.
+   */
+  ViewProjection GetViewProjection() const;
+
+  /**
+   * @brief Calculates the @a position, @a orientation and @a scale that's defined
+   *        for this camera, and writes it into the respective variable.
+   */
+  void CalculateTransformComponents(Vector3& position, Quaternion& orientation, Vector3& scale) const;
+
+  /**
+   * @brief Configures the camera in the way that it is supposed to be used with
+   *        scene-loader scenes. This means inverted Y and a rotation of 180 degrees
+   *        along the Y axis, plus whatever the parameters define.
+   */
+  void ConfigureCamera(CameraActor& camera) const;
+};
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_CAMERA_PARAMETERS_H
diff --git a/dali-scene-loader/public-api/customization.cpp b/dali-scene-loader/public-api/customization.cpp
new file mode 100644 (file)
index 0000000..546d938
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/customization.h"
+#include "dali/devel-api/common/map-wrapper.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+struct Customization::Map::Impl {
+  std::map<Tag, Customization> mCustomizations;
+};
+
+Customization::Map::Map()
+: mImpl{ new Impl }
+{}
+
+Customization::Map::~Map() = default;
+
+Customization* Customization::Map::Set(Tag tag, Customization&& customization)
+{
+  auto& result = (mImpl->mCustomizations[tag] = customization);
+  return &result;
+}
+
+const Customization* Customization::Map::Get(Tag tag) const
+{
+  auto& customizations = mImpl->mCustomizations;
+  auto iFind = customizations.find(tag);
+  if (iFind != customizations.end())
+  {
+    return &iFind->second;
+  }
+  return nullptr;
+}
+
+Customization* Customization::Map::Get(Tag tag)
+{
+  auto& customizations = mImpl->mCustomizations;
+  auto iFind = customizations.find(tag);
+  if (iFind != customizations.end())
+  {
+    return &iFind->second;
+  }
+  return nullptr;
+}
+
+uint32_t Customization::Map::Size() const
+{
+  return mImpl->mCustomizations.size();
+}
+
+void Customization::Map::Clear()
+{
+  mImpl->mCustomizations.clear();
+}
+
+struct Customization::Choices::Impl
+{
+  std::map<Tag, OptionType> mOptions;
+};
+
+Customization::Choices::Choices()
+: mImpl{ new Impl }
+{}
+
+Customization::Choices::~Choices() = default;
+
+void Customization::Choices::Set(Tag tag, OptionType option)
+{
+  mImpl->mOptions[tag] = option;
+}
+
+Customization::OptionType Customization::Choices::Get(Tag tag) const
+{
+  auto& options = mImpl->mOptions;
+  auto iFind = options.find(tag);
+  if (iFind != options.end())
+  {
+    return iFind->second;
+  }
+  return NONE;
+}
+
+uint32_t Customization::Choices::Size() const
+{
+  return mImpl->mOptions.size();
+}
+
+void Customization::Choices::Clear()
+{
+  mImpl->mOptions.clear();
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/customization.h b/dali-scene-loader/public-api/customization.h
new file mode 100644 (file)
index 0000000..ff29b95
--- /dev/null
@@ -0,0 +1,124 @@
+#ifndef DALI_SCENE_LOADER_CUSTOMIZATION_STATE_H_
+#define DALI_SCENE_LOADER_CUSTOMIZATION_STATE_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+ // INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include <string>
+#include <memory>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Offers a description of an aspect of the scene that can be customized:
+ *     the number of options, and the name of the nodes that are registered
+ *     for the tag, whose children will be shown / hidden based on selection.
+ */
+struct DALI_SCENE_LOADER_API Customization
+{
+  using Tag = std::string;
+  using OptionType = uint32_t;
+
+  /**
+   * @brief A mapping of customizations to tags.
+   */
+  struct DALI_SCENE_LOADER_API Map
+  {
+    Map();
+    ~Map();
+
+    /**
+     * @brief Maps the given @a customization to the given @a tag, overwriting any previous mapping to the same tag.
+     * @return Pointer to the inserted (or pre-existing) Customization instance.
+     */
+    Customization* Set(Tag tag, Customization&& customization);
+
+    /**
+     * @brief Attempts to retrieve a const Customization based on the given @a tag.
+     */
+    const Customization* Get(Tag tag) const;
+
+    /**
+     * @brief Attempts to retrieve a Customization based on the given @a tag.
+     */
+    Customization* Get(Tag tag);
+
+    /**
+     * @brief Returns the number of elements.
+     */
+    uint32_t Size() const;
+
+    /*
+     * @brief Removes every element from the Map.
+     */
+    void Clear();
+
+  private:
+    struct Impl;
+    const std::unique_ptr<Impl> mImpl;
+  };
+
+  /**
+   * @brief A mapping of choices - indices of children of customization nodes to use - to tags.
+   */
+  struct DALI_SCENE_LOADER_API Choices
+  {
+    Choices();
+    ~Choices();
+
+    /**
+     * @brief Maps the given @a option to the given @a tag, overwriting any previous mapping to the same tag.
+     */
+    void Set(Tag tag, OptionType option);
+
+    /**
+     * @brief Attempts to retrieve a Customization based on the given @a tag. Returns NONE if @a tag is not known.
+     */
+    OptionType Get(Tag tag) const;
+
+    /**
+     * @brief Returns the number of elements.
+     */
+    uint32_t Size() const;
+
+    /*
+     * @brief Removes every element from the underlying map.
+     */
+    void Clear();
+
+  private:
+    struct Impl;
+    const std::unique_ptr<Impl> mImpl;
+  };
+
+  static const OptionType NONE = OptionType(-1);
+
+  OptionType numOptions = 0;
+  std::vector<std::string> nodes;  // to apply option to.
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_CUSTOMIZATION_STATE_H_
diff --git a/dali-scene-loader/public-api/dli-loader.cpp b/dali-scene-loader/public-api/dli-loader.cpp
new file mode 100644 (file)
index 0000000..06268eb
--- /dev/null
@@ -0,0 +1,1778 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "dali-scene-loader/public-api/dli-loader.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/object/property-array.h"
+#include "dali/devel-api/common/map-wrapper.h"
+#include "dali-toolkit/devel-api/builder/json-parser.h"
+#include "dali/integration-api/debug.h"
+#include <fstream>
+#include <limits>
+#include <algorithm>
+#include <memory>
+#include <cmath>
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/parse-renderer-state.h"
+#include "dali-scene-loader/public-api/skinning-details.h"
+#include "dali-scene-loader/public-api/load-result.h"
+#include "dali-scene-loader/public-api/scene-definition.h"
+#include "dali-scene-loader/public-api/animation-definition.h"
+#include "dali-scene-loader/public-api/alpha-function-helper.h"
+#include "dali-scene-loader/public-api/camera-parameters.h"
+#include "dali-scene-loader/public-api/light-parameters.h"
+#include "dali-scene-loader/public-api/blend-shape-details.h"
+#include "dali-scene-loader/public-api/ktx-loader.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include "dali-scene-loader/internal/json-util.h"
+
+#define DLI_0_1_COMPATIBILITY
+
+namespace Dali
+{
+using namespace Toolkit;
+
+namespace SceneLoader
+{
+
+namespace rs = RendererState;
+
+namespace
+{
+const std::string NODES = "nodes";
+const std::string SCENES = "scenes";
+const std::string NODE = "node";
+const std::string URI = "uri";
+const std::string URL = "url";
+const std::string CUSTOMIZATION = "customization";
+const std::string HINTS = "hints";
+const std::string NAME("name");
+const std::string BLEND_SHAPE_HEADER("blendShapeHeader");
+const std::string BLEND_SHAPES("blendShapes");
+const std::string BLEND_SHAPE_VERSION_1_0("1.0");
+const std::string BLEND_SHAPE_VERSION_2_0("2.0");
+const std::string VERSION("version");
+
+const char* const SHADOW_MAP_SIZE = "shadowMapSize";
+const char* const ORTHOGRAPHIC_SIZE = "orthographicSize";
+const char* const PIXEL_UNITS = "px";
+
+const char SLASH = '/';
+
+void ReadModelTransform(const TreeNode* node, Quaternion& orientation, Vector3& translation, Vector3& scale)
+{
+  float num[16u] = { .0f };
+
+  if (ReadVector(node->GetChild("matrix"), num, 16u))
+  {
+    Matrix mat(num);
+    mat.GetTransformComponents(translation, orientation, scale);
+  }
+  else
+  {
+    if (ReadVector(node->GetChild("angle"), num, 3u))
+    {
+      orientation = Quaternion(Radian(Degree(num[0u])), Radian(Degree(num[1u])), Radian(Degree(num[2u])));
+    }
+
+    if (ReadVector(node->GetChild("position"), num, 3u))
+    {
+      translation = Vector3(num);
+    }
+  }
+}
+
+bool ReadAttribBlob(const TreeNode* node, MeshDefinition::Blob& buffer)
+{
+  return ReadBlob(node, buffer.mOffset, buffer.mLength);
+}
+
+bool ReadAttribAccessor(const TreeNode* node, MeshDefinition::Accessor& accessor)
+{
+  return ReadBlob(node, accessor.mBlob.mOffset, accessor.mBlob.mLength);
+}
+
+bool ReadColorCode(const TreeNode* node, Vector4& color,
+  DliLoader::ConvertColorCode convertColorCode)
+{
+  if (!node || !convertColorCode)
+  {
+    return false;
+  }
+
+  color = convertColorCode(node->GetString());
+
+  return true;
+}
+
+bool ReadColorCodeOrColor(const TreeNode* node, Vector4& color,
+  DliLoader::ConvertColorCode convertColorCode)
+{
+  return ReadColorCode(node->GetChild("colorCode"), color, convertColorCode) ||
+    ReadColor(node->GetChild("color"), color);
+}
+
+RendererState::Type ReadRendererState(const TreeNode& tnRendererState)
+{
+  if (tnRendererState.GetType() == TreeNode::INTEGER)
+  {
+    return static_cast<RendererState::Type>(tnRendererState.GetInteger());
+  }
+  else if (tnRendererState.GetType() == TreeNode::STRING)
+  {
+    return RendererState::Parse(tnRendererState.GetString());
+  }
+  else
+  {
+    return -1;
+  }
+}
+
+///@brief Reads arc properties.
+void ReadArcField(const TreeNode* eArc, ArcNode& arc)
+{
+  ReadBool(eArc->GetChild("antiAliasing"), arc.mAntiAliasing);
+  ReadInt(eArc->GetChild("arcCaps"), arc.mArcCaps);
+  ReadFloat(eArc->GetChild("radius"), arc.mRadius);
+
+  arc.mStartAngleDegrees = .0f;
+  ReadFloat(eArc->GetChild("startAngle"), arc.mStartAngleDegrees);
+
+  arc.mEndAngleDegrees = .0f;
+  ReadFloat(eArc->GetChild("endAngle"), arc.mEndAngleDegrees);
+}
+
+const TreeNode *Tidx(const TreeNode *node, int index)
+{
+  int i = 0;
+  for (TreeNode::ConstIterator it = (*node).CBegin(); it != (*node).CEnd(); ++it, ++i)
+  {
+    if (i == index)
+    {
+      return &((*it).second);
+    }
+  }
+  return NULL;
+}
+
+const TreeNode* RequireChild(const TreeNode* node, const std::string& childName)
+{
+  auto child = node->GetChild(childName);
+  if (!child)
+  {
+    ExceptionFlinger flinger(ASSERT_LOCATION);
+    flinger << "Failed to find child node '" << childName << "'";
+    if (auto nodeName = node->GetName())
+    {
+      flinger << " on '" << nodeName << "'";
+    }
+    flinger << ".";
+  }
+  return child;
+}
+
+void ParseProperties(const Toolkit::TreeNode& node, Property::Array& array);
+
+void ParseProperties(const Toolkit::TreeNode& node, Property::Map& map)
+{
+  DALI_ASSERT_DEBUG(node.GetType() == TreeNode::OBJECT);
+  for (auto i0 = node.CBegin(), i1 = node.CEnd(); i0 != i1; ++i0)
+  {
+    auto kv = *i0;
+    switch (kv.second.GetType())
+    {
+    case TreeNode::ARRAY:
+    {
+      Property::Array array;
+      ParseProperties(kv.second, array);
+      map.Insert(kv.first, array);
+    } break;
+
+    case TreeNode::OBJECT:
+    {
+      Property::Map innerMap;
+      ParseProperties(kv.second, innerMap);
+      map.Insert(kv.first, innerMap);
+    } break;
+
+    case TreeNode::STRING:
+      map.Insert(kv.first, kv.second.GetString());
+      break;
+
+    case TreeNode::INTEGER:
+      map.Insert(kv.first, kv.second.GetInteger());
+      break;
+
+    case TreeNode::BOOLEAN:
+      map.Insert(kv.first, kv.second.GetBoolean());
+      break;
+
+    case TreeNode::FLOAT:
+      map.Insert(kv.first, kv.second.GetFloat());
+      break;
+
+    case TreeNode::IS_NULL:
+      break;
+    }
+  }
+}
+
+void ParseProperties(const Toolkit::TreeNode& node, Property::Array& array)
+{
+  DALI_ASSERT_DEBUG(node.GetType() == TreeNode::ARRAY);
+  for (auto i0 = node.CBegin(), i1 = node.CEnd(); i0 != i1; ++i0)
+  {
+    auto kv = *i0;
+    switch (kv.second.GetType())
+    {
+    case TreeNode::ARRAY:
+    {
+      Property::Array innerArray;
+      ParseProperties(kv.second, innerArray);
+      array.PushBack(innerArray);
+    } break;
+
+    case TreeNode::OBJECT:
+    {
+      Property::Map map;
+      ParseProperties(kv.second, map);
+      array.PushBack(map);
+    } break;
+
+    case TreeNode::STRING:
+      array.PushBack(kv.second.GetString());
+      break;
+
+    case TreeNode::INTEGER:
+      array.PushBack(kv.second.GetInteger());
+      break;
+
+    case TreeNode::BOOLEAN:
+      array.PushBack(kv.second.GetBoolean());
+      break;
+
+    case TreeNode::FLOAT:
+      array.PushBack(kv.second.GetFloat());
+      break;
+
+    case TreeNode::IS_NULL:
+      break;
+    }
+  }
+}
+
+}//namespace
+
+struct DliLoader::Impl
+{
+  StringCallback mOnError = DefaultErrorCallback;
+  Toolkit::JsonParser mParser;
+
+  void ParseScene(LoadParams& params);
+
+private:
+  std::map<Index, Matrix>  mInverseBindMatrices;
+
+  /**
+   * @brief Due to .dli nodes being processed in depth-first traversal with orphans being
+   *  ignored, features that rely on node indices (which is more compact and closer to
+   *  glTF) require a mapping from .dli node indices to those in the resulting SceneDefinition.
+   *  The index mapper is responsible for maintaing this mapping, and resolving node IDs
+   *  once the processing of the nodes has finished.
+   * @note The resolution requires the whole scene graph to finish parsing, therefore any
+   *  node extensions relying on node IDs will see the dli ID in their processor.
+   */
+  struct IIndexMapper
+  {
+    /**
+     * @brief Attempts to create a mapping from a node's @a dli index to its @a scene
+     *  index.
+     * @return Whether the operation was successful.
+     */
+    virtual bool Map(Index iDli, Index iScene) =0;
+
+    /**
+     * @return The scene index for the node's @a dli index.
+     */
+    virtual Index Resolve(Index iDli) =0;
+  };
+
+  /**
+   * @brief Traverses the DOM tree created by LoadDocument() in an attempt to create
+   *  an intermediate representation of resources and nodes.
+   */
+  void ParseSceneInternal(Index iScene, const Toolkit::TreeNode* tnScenes,
+    const Toolkit::TreeNode* tnNodes, LoadParams& params);
+
+  void ParseSkeletons(const Toolkit::TreeNode* skeletons, SceneDefinition& scene, ResourceBundle& resources);
+  void ParseEnvironments(const Toolkit::TreeNode* environments, ResourceBundle& resources);
+  void ParseMaterials(const Toolkit::TreeNode* materials, ConvertColorCode convertColorCode,
+    ResourceBundle& resources);
+
+  void ParseNodes(const Toolkit::TreeNode* nodes, Index index, LoadParams& params);
+  void ParseNodesInternal(const Toolkit::TreeNode* nodes, Index index,
+    std::vector<Index>& inOutParentStack, LoadParams& params, IIndexMapper& indexMapper);
+
+  void ParseAnimations(const Toolkit::TreeNode* animations, LoadParams& params);
+  void ParseAnimationGroups(const Toolkit::TreeNode* animationGroups, LoadParams& params);
+
+  void ParseShaders(const Toolkit::TreeNode* shaders, ResourceBundle& resources);
+  void ParseMeshes(const Toolkit::TreeNode* meshes, ResourceBundle& resources);
+
+  void GetCameraParameters(std::vector<CameraParameters>& cameras) const;
+  void GetLightParameters(std::vector<LightParameters>& lights) const;
+};
+
+DliLoader::DliLoader()
+: mImpl{ new Impl }
+{}
+
+DliLoader::~DliLoader() = default;
+
+void DliLoader::SetErrorCallback(StringCallback onError)
+{
+  mImpl->mOnError = onError;
+}
+
+bool DliLoader::LoadScene(const std::string& uri, LoadParams& params)
+{
+  std::string daliBuffer = LoadTextFile(uri.c_str());
+
+  auto& parser = mImpl->mParser;
+  parser = JsonParser::New();
+  if (!parser.Parse(daliBuffer))
+  {
+    return false;
+  }
+
+  mImpl->ParseScene(params);
+  return true;
+}
+
+std::string DliLoader::GetParseError() const
+{
+  std::stringstream stream;
+
+  auto& parser = mImpl->mParser;
+  if (parser.ParseError())
+  {
+    stream << "position: " << parser.GetErrorPosition() << ", line: " << parser.GetErrorLineNumber() << ", column: " << parser.GetErrorColumn() << ", description: " << parser.GetErrorDescription() << ".";
+  }
+
+  return stream.str();
+}
+
+void DliLoader::Impl::ParseScene(LoadParams& params)
+{
+  auto& input = params.input;
+  auto& output = params.output;
+
+  // get index of root node.
+  auto docRoot = mParser.GetRoot();
+
+  // Process resources first - these are shared
+  if (auto environments = docRoot->GetChild("environment"))
+  {
+    ParseEnvironments(environments, output.mResources);  // NOTE: must precede parsing of materials
+  }
+
+  if (auto meshes = docRoot->GetChild("meshes"))
+  {
+    ParseMeshes(meshes, output.mResources);
+  }
+
+  if (auto shaders = docRoot->GetChild("shaders"))
+  {
+    ParseShaders(shaders, output.mResources);
+  }
+
+  if (auto materials = docRoot->GetChild("materials"))
+  {
+    ParseMaterials(materials, input.mConvertColorCode, output.mResources);
+  }
+
+  for (auto& c : input.mPreNodeCategoryProcessors)
+  {
+    if (auto node = docRoot->GetChild(c.first))
+    {
+      Property::Array array;
+      ParseProperties(*node, array);
+      c.second(std::move(array), mOnError);
+    }
+  }
+
+  // Process scenes
+  Index iScene = 0;  // default scene
+  ReadIndex(docRoot->GetChild("scene"), iScene);
+
+  auto tnScenes = RequireChild(docRoot, "scenes");
+  auto tnNodes = RequireChild(docRoot, "nodes");
+  ParseSceneInternal(iScene, tnScenes, tnNodes, params);
+
+  ParseSkeletons(docRoot->GetChild("skeletons"), output.mScene, output.mResources);
+
+  output.mScene.EnsureUniqueSkinningShaderInstances(output.mResources);
+  output.mScene.EnsureUniqueBlendShapeShaderInstances(output.mResources);
+
+  // Ger cameras and lights
+  GetCameraParameters(output.mCameraParameters);
+  GetLightParameters(output.mLightParameters);
+
+  // Post-node processors and animations last
+  for (auto& c : input.mPostNodeCategoryProcessors)
+  {
+    if (auto node = docRoot->GetChild(c.first))
+    {
+      Property::Array array;
+      ParseProperties(*node, array);
+      c.second(std::move(array), mOnError);
+    }
+  }
+
+  if (auto animations = docRoot->GetChild("animations"))
+  {
+    ParseAnimations(animations, params);
+  }
+
+  if (!output.mAnimationDefinitions.empty())
+  {
+    if (auto animationGroups = docRoot->GetChild("animationGroups"))
+    {
+      ParseAnimationGroups(animationGroups, params);
+    }
+  }
+}
+
+void DliLoader::Impl::ParseSceneInternal(Index iScene, const Toolkit::TreeNode* tnScenes,
+  const Toolkit::TreeNode* tnNodes, LoadParams& params)
+{
+  auto getSceneRootIdx = [&](Index iScene) {
+    auto tn = Tidx(tnScenes, iScene);  // now a "scene" object
+    if (!tn)
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << iScene << " is out of bounds access into " << SCENES << ".";
+    }
+
+    tn = RequireChild(tn, NODES);  // now a "nodes" array
+    if (tn->GetType() != TreeNode::ARRAY)
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << SCENES << "[" << iScene << "]." << NODES <<
+        " has an invalid type; array required.";
+    }
+
+    if (tn->Size() < 1)
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << SCENES << "[" << iScene << "]." << NODES <<
+        " must define a node id.";
+    }
+
+    tn = Tidx(tn, 0);  // now the first element of the array
+    Index iRootNode;
+    if (!ReadIndex(tn, iRootNode))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << SCENES << "[" << iScene << "]." << NODES <<
+        " has an invalid value for root node index: '" << iRootNode << "'.";
+    }
+
+    if (iRootNode >= tnNodes->Size())
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Root node index << " << iRootNode << " of scene " << iScene << " is out of bounds.";
+    }
+
+    tn = Tidx(tnNodes, iRootNode);  // now a "node" object
+    if (tn->GetType() != TreeNode::OBJECT)
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Root node of scene " << iScene << " is of invalid JSON type; object required";
+    }
+
+    return iRootNode;
+  };
+
+  Index iRootNode = getSceneRootIdx(iScene);
+  ParseNodes(tnNodes, iRootNode, params);
+
+  auto& scene = params.output.mScene;
+  scene.AddRootNode(0);
+
+  for (Index i = 0; i < iScene; ++i)
+  {
+    Index iRootNode = getSceneRootIdx(i);
+    const Index iRoot = scene.GetNodeCount();
+    ParseNodes(tnNodes, iRootNode, params);
+    scene.AddRootNode(iRoot);
+  }
+
+  auto numScenes = tnScenes->Size();
+  for (Index i = iScene + 1; i < numScenes; ++i)
+  {
+    Index iRootNode = getSceneRootIdx(i);
+    const Index iRoot = scene.GetNodeCount();
+    ParseNodes(tnNodes, iRootNode, params);
+    scene.AddRootNode(iRoot);
+  }
+}
+
+void DliLoader::Impl::ParseSkeletons(const TreeNode* skeletons, SceneDefinition& scene, ResourceBundle& resources)
+{
+  if (skeletons)
+  {
+    auto iStart = skeletons->CBegin();
+    for (auto i0 = iStart, i1 = skeletons->CEnd(); i0 != i1; ++i0)
+    {
+      auto& node = (*i0).second;
+      std::string skeletonRootName;
+      if (ReadString(node.GetChild(NODE), skeletonRootName))
+      {
+        SkeletonDefinition skeleton;
+        if (!scene.FindNode(skeletonRootName, &skeleton.mRootNodeIdx))
+        {
+          ExceptionFlinger(ASSERT_LOCATION) << FormatString("Skeleton %d: node '%s' not defined.", resources.mSkeletons.size(), skeletonRootName.c_str());
+        }
+
+        uint32_t jointCount = 0;
+        std::function<void(Index)> visitFn;
+        auto& ibms = mInverseBindMatrices;
+        visitFn = [&](Index id) {
+          auto node = scene.GetNode(id);
+          jointCount += ibms.find(id) != ibms.end();
+
+          for (auto i : node->mChildren)
+          {
+            visitFn(i);
+          }
+        };
+        visitFn(skeleton.mRootNodeIdx);
+
+        if (jointCount > Skinning::MAX_JOINTS)
+        {
+          mOnError(FormatString("Skeleton %d: joint count exceeds supported limit.", resources.mSkeletons.size()));
+          jointCount = Skinning::MAX_JOINTS;
+        }
+
+        skeleton.mJoints.reserve(jointCount);
+
+        visitFn = [&](Index id) {
+          auto iFind = ibms.find(id);
+          if (iFind != ibms.end() && skeleton.mJoints.size() < Skinning::MAX_JOINTS)
+          {
+            skeleton.mJoints.push_back({ id, iFind->second });
+          }
+
+          auto node = scene.GetNode(id);
+          for (auto i : node->mChildren)
+          {
+            visitFn(i);
+          }
+        };
+        visitFn(skeleton.mRootNodeIdx);
+
+        resources.mSkeletons.push_back(std::move(skeleton));
+      }
+      else
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "skeleton " << std::distance(iStart, i0) <<
+          ": Missing required attribute '"<< NODE <<"'.";
+      }
+    }
+  }
+}
+
+void DliLoader::Impl::ParseEnvironments(const TreeNode* environments, ResourceBundle& resources)
+{
+  Matrix cubeOrientation(Matrix::IDENTITY);
+
+  for (auto i0 = environments->CBegin(), i1 = environments->CEnd(); i0 != i1; ++i0)
+  {
+    auto& node = (*i0).second;
+
+    EnvironmentDefinition envDef;
+    ReadString(node.GetChild("cubeSpecular"), envDef.mSpecularMapPath);
+    ReadString(node.GetChild("cubeDiffuse"), envDef.mDiffuseMapPath);
+    ToUnixFileSeparators(envDef.mSpecularMapPath);
+    ToUnixFileSeparators(envDef.mDiffuseMapPath);
+    envDef.mIblIntensity = 1.0f;
+    ReadFloat(node.GetChild("iblIntensity"), envDef.mIblIntensity);
+    if (ReadVector(node.GetChild("cubeInitialOrientation"), cubeOrientation.AsFloat(), 16u))
+    {
+      envDef.mCubeOrientation = Quaternion(cubeOrientation);
+    }
+
+    resources.mEnvironmentMaps.emplace_back(std::move(envDef), EnvironmentDefinition::Textures());
+  }
+
+  // NOTE: guarantees environmentMaps to have an empty environment.
+  if (resources.mEnvironmentMaps.empty())
+  {
+    resources.mEnvironmentMaps.emplace_back(EnvironmentDefinition(), EnvironmentDefinition::Textures());
+  }
+}
+
+void DliLoader::Impl::ParseShaders(const TreeNode* shaders, ResourceBundle& resources)
+{
+  uint32_t iShader = 0;
+  for (auto i0 = shaders->CBegin(), i1 = shaders->CEnd(); i0 != i1; ++i0, ++iShader)
+  {
+    auto& node = (*i0).second;
+    ShaderDefinition shaderDef;
+    ReadStringVector(node.GetChild("defines"), shaderDef.mDefines);
+
+    // Read shader hints. Possible values are:
+    //                         Don't define for No hints.
+    // "OUTPUT_IS_TRANSPARENT" Might generate transparent alpha from opaque inputs.
+    //     "MODIFIES_GEOMETRY" Might change position of vertices, this option disables any culling optimizations.
+
+    ReadStringVector(node.GetChild( HINTS ), shaderDef.mHints);
+
+    if (ReadString(node.GetChild("vertex"), shaderDef.mVertexShaderPath) &&
+      ReadString(node.GetChild("fragment"), shaderDef.mFragmentShaderPath))
+    {
+      ToUnixFileSeparators(shaderDef.mVertexShaderPath);
+      ToUnixFileSeparators(shaderDef.mFragmentShaderPath);
+
+      for (TreeNode::ConstIterator j0 = node.CBegin(), j1 = node.CEnd(); j0 != j1; ++j0)
+      {
+        const TreeNode::KeyNodePair& keyValue = *j0;
+        const std::string& key = keyValue.first;
+        const TreeNode& value = keyValue.second;
+
+        Property::Value uniformValue;
+        if (key.compare("vertex") == 0 || key.compare("fragment") == 0 || key.compare("defines") == 0 || key.compare(HINTS) == 0)
+        {
+          continue;
+        }
+        else if (key.compare("rendererState") == 0)
+        {
+          shaderDef.mRendererState = ReadRendererState(keyValue.second);
+        }
+        else if (value.GetType() == TreeNode::INTEGER || value.GetType() == TreeNode::FLOAT)
+        {
+          float f = 0.f;
+          ReadFloat(&value, f);
+          uniformValue = f;
+        }
+        else if (value.GetType() == TreeNode::BOOLEAN)
+        {
+          DALI_LOG_WARNING("\"bool\" uniforms are handled as floats in shader");
+          bool value = false;
+          if (ReadBool(&keyValue.second, value))
+          {
+            uniformValue = value ? 1.0f : 0.0f;
+          }
+        }
+        else switch (auto size = GetNumericalArraySize(&value))
+        {
+        case 16:
+        {
+          Matrix m;
+          ReadVector(&value, m.AsFloat(), size);
+          uniformValue = m;
+          break;
+        }
+
+        case 9:
+        {
+          Matrix3 m;
+          ReadVector(&value, m.AsFloat(), size);
+          uniformValue = m;
+          break;
+        }
+
+        case 4:
+        {
+          Vector4 v;
+          ReadVector(&value, v.AsFloat(), size);
+          uniformValue = v;
+          break;
+        }
+
+        case 3:
+        {
+          Vector3 v;
+          ReadVector(&value, v.AsFloat(), size);
+          uniformValue = v;
+          break;
+        }
+
+        case 2:
+        {
+          Vector2 v;
+          ReadVector(&value, v.AsFloat(), size);
+          uniformValue = v;
+          break;
+        }
+
+        default:
+          mOnError(FormatString(
+            "shader %d: Ignoring uniform '%s': failed to infer type from %d elements.",
+            iShader, key.c_str()));
+          break;
+        }
+
+        if (Property::NONE != uniformValue.GetType())
+        {
+          shaderDef.mUniforms.Insert(key, uniformValue);
+        }
+      }
+
+      resources.mShaders.emplace_back(std::move(shaderDef), Shader());
+    }
+    else
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "shader " << iShader <<
+        ": Missing vertex / fragment shader definition.";
+    }
+  }
+}
+
+void DliLoader::Impl::ParseMeshes(const TreeNode* meshes, ResourceBundle& resources)
+{
+  for (auto i0 = meshes->CBegin(), i1 = meshes->CEnd(); i0 != i1; ++i0)
+  {
+    auto& node = (*i0).second;
+
+    MeshDefinition  meshDef;
+    if (!ReadString(node.GetChild(URI), meshDef.mUri))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "mesh " << resources.mMeshes.size() <<
+        ": Missing required attribute '" << URI << "'.";
+    }
+
+    ToUnixFileSeparators(meshDef.mUri);
+
+    std::string primitive;
+    if (ReadString(node.GetChild("primitive"), primitive))
+    {
+      if (primitive == "LINES")
+      {
+        meshDef.mPrimitiveType = Geometry::LINES;
+      }
+      else if (primitive == "POINTS")
+      {
+        meshDef.mPrimitiveType = Geometry::POINTS;
+      }
+      else if (primitive != "TRIANGLES")
+      {
+        mOnError(FormatString(
+          "mesh %d: Using TRIANGLES instead of unsupported primitive type '%s'.",
+          resources.mMeshes.size(), primitive.c_str()));
+      }
+    }
+
+    int attributes;
+    if (ReadInt(node.GetChild("attributes"), attributes))
+    {
+      if (MaskMatch(attributes, MeshDefinition::INDICES) &&
+        !ReadAttribAccessor(node.GetChild("indices"), meshDef.mIndices))
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << FormatString("mesh %d: Failed to read %s.",
+          resources.mMeshes.size(), "indices");
+      }
+
+      if (MaskMatch(attributes, MeshDefinition::POSITIONS) &&
+        !ReadAttribAccessor(node.GetChild("positions"), meshDef.mPositions))
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << FormatString("mesh %d: Failed to read %s.",
+          resources.mMeshes.size(), "positions");
+      }
+
+      if (MaskMatch(attributes, MeshDefinition::NORMALS) &&
+        !ReadAttribAccessor(node.GetChild("normals"), meshDef.mNormals))
+      {
+        mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(),
+          "normals"));
+      }
+
+      if (MaskMatch(attributes, MeshDefinition::TEX_COORDS) &&
+        !ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords))
+      {
+        mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(),
+          "textures"));
+      }
+
+      if (MaskMatch(attributes, MeshDefinition::TANGENTS) &&
+        !ReadAttribAccessor(node.GetChild("tangents"), meshDef.mTangents))
+      {
+        mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(),
+          "tangents"));
+      }
+
+      // NOTE: we're no longer reading bitangents as these are calculated in the shaders.
+      if (ReadIndex(node.GetChild("skeleton"), meshDef.mSkeletonIdx))
+      {
+        if (!MaskMatch(attributes, MeshDefinition::JOINTS_0) &&
+          !MaskMatch(attributes, MeshDefinition::WEIGHTS_0))
+        {
+          mOnError(FormatString("mesh %d: Expected joints0 / weights0 attribute(s) missing.",
+            resources.mMeshes.size()));
+        }
+        else if (!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints0) ||
+          !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights0))
+        {
+          mOnError(FormatString("mesh %d: Failed to read skinning information.",
+            resources.mMeshes.size()));
+        }
+      }
+
+      if (auto blendshapeHeader = node.GetChild(BLEND_SHAPE_HEADER))
+      {
+        std::string blendShapeVersion;
+        ReadString(blendshapeHeader->GetChild(VERSION), blendShapeVersion);
+
+        if (0u == blendShapeVersion.compare(BLEND_SHAPE_VERSION_1_0))
+        {
+          meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_1_0;
+        }
+        else if (0u == blendShapeVersion.compare(BLEND_SHAPE_VERSION_2_0))
+        {
+          meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+        }
+
+        switch (meshDef.mBlendShapeVersion)
+        {
+          case BlendShapes::Version::VERSION_1_0:
+          case BlendShapes::Version::VERSION_2_0: // FALL THROUGH
+          {
+            ReadAttribBlob(blendshapeHeader, meshDef.mBlendShapeHeader);
+            break;
+          }
+          default:
+          {
+            // nothing to do
+            break;
+          }
+        }
+      }
+
+      if (auto blendShapes = node.GetChild(BLEND_SHAPES) )
+      {
+        meshDef.mBlendShapes.resize(blendShapes->Size());
+
+        auto index = 0u;
+        for (auto it = blendShapes->CBegin(), endIt = blendShapes->CEnd(); it != endIt; ++it, ++index)
+        {
+          // Each blend shape is stored as the difference with the original mesh.
+
+          auto& blendShapeNode = (*it).second;
+
+          auto& blendShape = meshDef.mBlendShapes[index];
+          ReadString(blendShapeNode.GetChild("name"), blendShape.name);
+          if (auto position = blendShapeNode.GetChild("positions"))
+          {
+            ReadAttribAccessor(position, blendShape.deltas);
+          }
+          if (auto normals = blendShapeNode.GetChild("normals"))
+          {
+            ReadAttribAccessor(normals, blendShape.normals);
+          }
+          if (auto tangents = blendShapeNode.GetChild("tangents"))
+          {
+            ReadAttribAccessor(tangents, blendShape.tangents);
+          }
+          ReadFloat(blendShapeNode.GetChild("weight"), blendShape.weight);
+        }
+      }
+
+      bool flipV;
+      if (ReadBool(node.GetChild("flipV"), flipV))
+      {
+        meshDef.mFlags |= flipV * MeshDefinition::FLIP_UVS_VERTICAL;
+      }
+
+      resources.mMeshes.emplace_back(std::move(meshDef), MeshGeometry());
+    }
+  }
+}
+
+void DliLoader::Impl::ParseMaterials(const TreeNode* materials, ConvertColorCode convertColorCode,
+  ResourceBundle& resources)
+{
+  for (auto i0 = materials->CBegin(), i1 = materials->CEnd(); i0 != i1; ++i0)
+  {
+    auto& node = (*i0).second;
+
+    MaterialDefinition materialDef;
+    if (auto eEnvironment = node.GetChild("environment"))
+    {
+      ReadIndex(eEnvironment, materialDef.mEnvironmentIdx);
+      if (static_cast<unsigned int>(materialDef.mEnvironmentIdx) >= resources.mEnvironmentMaps.size())
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "material " << resources.mMaterials.size() <<
+          ": Environment index " << materialDef.mEnvironmentIdx << " out of bounds (" <<
+          resources.mEnvironmentMaps.size() << ").";
+      }
+    }
+
+    //TODO : need to consider AGIF
+    std::vector<std::string> texturePaths;
+    std::string texturePath;
+    if (ReadString(node.GetChild("albedoMap"), texturePath))
+    {
+      ToUnixFileSeparators(texturePath);
+      const auto semantic = MaterialDefinition::ALBEDO;
+      materialDef.mTextureStages.push_back({ semantic, TextureDefinition{ std::move(texturePath) } });
+      materialDef.mFlags |= semantic | MaterialDefinition::TRANSPARENCY;  // NOTE: only in dli does single / separate ALBEDO texture mean TRANSPARENCY.
+    }
+    if (ReadString(node.GetChild("albedoMetallicMap"), texturePath))
+    {
+      ToUnixFileSeparators(texturePath);
+
+      if (MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
+      {
+        mOnError(FormatString("material %d: conflicting semantics; already set %s.", resources.mMaterials.size(), "albedo"));
+      }
+
+      const auto semantic = MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC;
+      materialDef.mTextureStages.push_back({ semantic, TextureDefinition{ std::move(texturePath) } });
+      materialDef.mFlags |= semantic;
+    }
+
+    if (ReadString(node.GetChild("metallicRoughnessMap"), texturePath))
+    {
+      ToUnixFileSeparators(texturePath);
+
+      if (MaskMatch(materialDef.mFlags, MaterialDefinition::METALLIC))
+      {
+        mOnError(FormatString("material %d: conflicting semantics; already set %s.", resources.mMaterials.size(), "metallic"));
+      }
+
+      const auto semantic = MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS;
+      materialDef.mTextureStages.push_back({ semantic, TextureDefinition{ std::move(texturePath) } });
+      materialDef.mFlags |= semantic |
+        // We have a metallic-roughhness map and the first texture did not have albedo semantics - we're in the transparency workflow.
+        (MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO) * MaterialDefinition::TRANSPARENCY);
+    }
+
+    if (ReadString(node.GetChild("normalMap"), texturePath))
+    {
+      ToUnixFileSeparators(texturePath);
+
+      const auto semantic = MaterialDefinition::NORMAL;
+      materialDef.mTextureStages.push_back({ semantic, TextureDefinition{ std::move(texturePath) } });
+      materialDef.mFlags |= semantic |
+        // We have a standalone normal map and the first texture did not have albedo semantics - we're in the transparency workflow.
+        (MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO) * MaterialDefinition::TRANSPARENCY);
+    }
+
+    if (ReadString(node.GetChild("normalRoughnessMap"), texturePath))
+    {
+      ToUnixFileSeparators(texturePath);
+
+      if (MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
+      {
+        mOnError(FormatString("material %d: conflicting semantics; already set %s.", resources.mMaterials.size(), "normal"));
+      }
+
+      if (MaskMatch(materialDef.mFlags, MaterialDefinition::ROUGHNESS))
+      {
+        mOnError(FormatString("material %d: conflicting semantics; already set %s.", resources.mMaterials.size(), "roughness"));
+      }
+
+      if (MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY))
+      {
+        mOnError(FormatString("material %d: conflicting semantics; already set %s.", resources.mMaterials.size(), "transparency"));
+      }
+
+      const auto semantic = MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS;
+      materialDef.mTextureStages.push_back({ semantic, TextureDefinition{ std::move(texturePath) } });
+      materialDef.mFlags |= semantic;
+    }
+
+    if (ReadString(node.GetChild("subsurfaceMap"), texturePath))
+    {
+      ToUnixFileSeparators(texturePath);
+
+      const auto semantic = MaterialDefinition::SUBSURFACE;
+      materialDef.mTextureStages.push_back({ semantic, TextureDefinition{ std::move(texturePath) } });
+      materialDef.mFlags |= semantic;
+    }
+
+    if (ReadColorCodeOrColor(&node, materialDef.mColor, convertColorCode) &&
+      materialDef.mColor.a < 1.0f)
+    {
+      materialDef.mFlags |= MaterialDefinition::TRANSPARENCY;
+    }
+
+    ReadFloat(node.GetChild("metallic"), materialDef.mMetallic);
+    ReadFloat(node.GetChild("roughness"), materialDef.mRoughness);
+
+    bool mipmaps;
+    if (ReadBool(node.GetChild("mipmap"), mipmaps) && mipmaps)
+    {
+      for (auto& ts : materialDef.mTextureStages)
+      {
+        ts.mTexture.mSamplerFlags |= SamplerFlags::FILTER_MIPMAP_LINEAR;
+      }
+    }
+
+    resources.mMaterials.emplace_back(std::move(materialDef), TextureSet());
+  }
+}
+
+void DliLoader::Impl::ParseNodes(const TreeNode* const nodes, Index index, LoadParams& params)
+{
+  std::vector<Index> parents;
+  parents.reserve(8);
+
+  struct IndexMapper : IIndexMapper
+  {
+    IndexMapper(size_t numNodes)
+    {
+      mIndices.reserve(numNodes);
+    }
+
+    virtual bool Map(Index iDli, Index iScene) override
+    {
+      Entry idx{ iDli, iScene };
+      auto iInsert = std::lower_bound(mIndices.begin(), mIndices.end(), idx);
+      if (iInsert == mIndices.end() || iInsert->iDli != iDli)
+      {
+        mIndices.insert(iInsert, idx);
+      }
+      else if (iInsert->iScene != iScene)
+      {
+        return false;
+      }
+      return true;
+    }
+
+    virtual unsigned int Resolve(Index iDli) override
+    {
+      auto iFind = std::lower_bound(mIndices.begin(), mIndices.end(), iDli,
+        [](const Entry& idx, Index iDli) {
+          return idx.iDli < iDli;
+        });
+      DALI_ASSERT_ALWAYS(iFind != mIndices.end());
+      return iFind->iScene;
+    }
+
+  private:
+    struct Entry
+    {
+      unsigned int iDli;
+      unsigned int iScene;
+
+      bool operator<(const Entry& other) const
+      {
+        return iDli < other.iDli;
+      }
+    };
+    std::vector<Entry> mIndices;
+  } mapper(nodes->Size());
+  ParseNodesInternal(nodes, index, parents, params, mapper);
+
+  auto& scene = params.output.mScene;
+  for (size_t i0 = 0, i1 = scene.GetNodeCount(); i0 < i1; ++i0)
+  {
+    for (auto& c : scene.GetNode(i0)->mConstraints)
+    {
+      c.mSourceIdx = mapper.Resolve(c.mSourceIdx);
+    }
+  }
+}
+
+void DliLoader::Impl::ParseNodesInternal(const TreeNode* const nodes, Index index,
+  std::vector<Index>& inOutParentStack, LoadParams& params, IIndexMapper& mapper)
+{
+  // Properties that may be resolved from a JSON value with ReadInt() -- or default to 0.
+  struct IndexProperty { ResourceType::Value type; const TreeNode* source; Index& target; };
+  std::vector<IndexProperty> resourceIds;
+  resourceIds.reserve(4);
+
+  if (auto node = Tidx(nodes, index))
+  {
+    NodeDefinition nodeDef;
+    nodeDef.mParentIdx = inOutParentStack.empty() ? INVALID_INDEX : inOutParentStack.back();
+
+    // name
+    ReadString(node->GetChild(NAME), nodeDef.mName);
+
+    // transform
+    ReadModelTransform(node, nodeDef.mOrientation, nodeDef.mPosition, nodeDef.mScale);
+
+    // Reads the size of the node.
+    //
+    // * It can be given as 'size' or 'bounds'.
+    // * The sdk saves the 'size' as a vector2 in some cases.
+    // * To avoid size related issues the following code attemps
+    //   to read the 'size/bounds' as a vector3 first, if it's
+    //   not successful then reads it as a vector2.
+    ReadVector(node->GetChild("size"), nodeDef.mSize.AsFloat(), 3) ||
+      ReadVector(node->GetChild("size"), nodeDef.mSize.AsFloat(), 2) ||
+        ReadVector(node->GetChild("bounds"), nodeDef.mSize.AsFloat(), 3) ||
+          ReadVector(node->GetChild("bounds"), nodeDef.mSize.AsFloat(), 2);
+
+    // visibility
+    ReadBool(node->GetChild("visible"), nodeDef.mIsVisible);
+
+    // type classification
+    if (auto eCustomization = node->GetChild("customization"))  // customization
+    {
+      std::string tag;
+      if (ReadString(eCustomization->GetChild("tag"), tag))
+      {
+        nodeDef.mCustomization.reset(new NodeDefinition::CustomizationDefinition{ tag });
+      }
+    }
+    else // something renderable maybe
+    {
+      std::unique_ptr<NodeDefinition::Renderable> renderable;
+      ModelNode* modelNode = nullptr;  // no ownership, aliasing renderable for the right type.
+
+      const TreeNode*  eRenderable = nullptr;
+      if ((eRenderable = node->GetChild("model")))
+      {
+        // check for mesh before allocating - this can't be missing.
+        auto eMesh = eRenderable->GetChild("mesh");
+        if (!eMesh)
+        {
+          ExceptionFlinger(ASSERT_LOCATION) << "node " << nodeDef.mName << ": Missing mesh definition.";
+        }
+
+        modelNode = new ModelNode();
+        renderable.reset(modelNode);
+
+        resourceIds.push_back({ ResourceType::Mesh, eMesh, modelNode->mMeshIdx });
+      }
+      else if ((eRenderable = node->GetChild("arc")))
+      {
+        // check for mesh before allocating - this can't be missing.
+        auto eMesh = eRenderable->GetChild("mesh");
+        if (!eMesh)
+        {
+          ExceptionFlinger(ASSERT_LOCATION) << "node " << nodeDef.mName << ": Missing mesh definition.";
+        }
+
+        auto arcNode = new ArcNode;
+        renderable.reset(arcNode);
+        modelNode = arcNode;
+
+        resourceIds.push_back({ ResourceType::Mesh, eMesh, arcNode->mMeshIdx });
+
+        ReadArcField(eRenderable, *arcNode);
+      }
+
+      if (renderable)  // process common properties of all renderables + register payload
+      {
+        // shader
+        renderable->mShaderIdx = 0;
+        auto eShader = eRenderable->GetChild("shader");
+        resourceIds.push_back({ ResourceType::Shader, eShader, renderable->mShaderIdx });
+
+        // color
+        if (modelNode)
+        {
+          modelNode->mMaterialIdx = 0;  // must offer default of 0
+          auto eMaterial = eRenderable->GetChild("material");
+          resourceIds.push_back({ ResourceType::Material, eMaterial, modelNode->mMaterialIdx });
+
+          if (!ReadColorCodeOrColor(eRenderable, modelNode->mColor, params.input.mConvertColorCode))
+          {
+            ReadColorCodeOrColor(node, modelNode->mColor, params.input.mConvertColorCode);
+          }
+        }
+
+        nodeDef.mRenderable = std::move(renderable);
+      }
+    }
+
+    // Resolve ints - default to 0 if undefined
+    auto& output = params.output;
+    for (auto& idRes : resourceIds)
+    {
+      Index iCheck = 0;
+      switch (idRes.type)
+      {
+      case ResourceType::Shader:
+        iCheck = output.mResources.mShaders.size();
+        break;
+
+      case ResourceType::Mesh:
+        iCheck = output.mResources.mMeshes.size();
+        break;
+
+      case ResourceType::Material:
+        iCheck = output.mResources.mMaterials.size();
+        break;
+
+      default:
+        ExceptionFlinger(ASSERT_LOCATION) << "node " << index << ": Invalid resource type: " <<
+          idRes.type << " (Programmer error)";
+      }
+
+      if (!idRes.source)
+      {
+        idRes.target = 0;
+      }
+      else if (idRes.source->GetType() != TreeNode::INTEGER)
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "node " << index << ": Invalid " <<
+          GetResourceTypeName(idRes.type) << " index type.";
+      }
+      else
+      {
+        idRes.target = idRes.source->GetInteger();
+      }
+
+      if (idRes.target >= iCheck)
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "node " << index << ": " <<
+          GetResourceTypeName(idRes.type) << " index " << idRes.target << " out of bounds (" <<
+          iCheck << ").";
+      }
+    }
+    resourceIds.clear();
+
+    // Extra properties
+    if (auto eExtras = node->GetChild("extras"))
+    {
+      auto& extras = nodeDef.mExtras;
+      extras.reserve(eExtras->Size());
+
+      NodeDefinition::Extra e;
+      for (auto i0 = eExtras->CBegin(), i1 = eExtras->CEnd(); i0 != i1; ++i0)
+      {
+        auto eExtra = *i0;
+        e.mKey = eExtra.first;
+        if (e.mKey.empty())
+        {
+          mOnError(FormatString("node %d: empty string is invalid for name of extra %d; ignored.",
+            index, extras.size()));
+          continue;
+        }
+
+        e.mValue = ReadPropertyValue(eExtra.second);
+        if (e.mValue.GetType() == Property::Type::NONE)
+        {
+          mOnError(FormatString("node %d: failed to interpret value of extra '%s' : %s; ignored.",
+            index, e.mKey.c_str(), eExtra.second.GetString()));
+        }
+        else
+        {
+          auto iInsert = std::lower_bound(extras.begin(), extras.end(), e);
+          if (iInsert != extras.end() && iInsert->mKey == e.mKey)
+          {
+            mOnError(FormatString("node %d: extra '%s' already defined; overriding with %s.",
+              index, e.mKey.c_str(), eExtra.second.GetString()));
+            *iInsert = std::move(e);
+          }
+          else
+          {
+            extras.insert(iInsert, e);
+          }
+        }
+      }
+    }
+
+    // Constraints
+    if (auto eConstraints = node->GetChild("constraints"))
+    {
+      auto& constraints = nodeDef.mConstraints;
+      constraints.reserve(eConstraints->Size());
+
+      ConstraintDefinition cDef;
+      for (auto i0 = eConstraints->CBegin(), i1 = eConstraints->CEnd(); i0 != i1; ++i0)
+      {
+        auto eConstraint = *i0;
+        if (!ReadIndex(&eConstraint.second, cDef.mSourceIdx))
+        {
+          mOnError(FormatString("node %d: node ID %s for constraint %d is invalid; ignored.",
+            index, eConstraint.second.GetString(), constraints.size()));
+        }
+        else
+        {
+          cDef.mProperty = eConstraint.first;
+
+          auto iInsert = std::lower_bound(constraints.begin(), constraints.end(), cDef);
+          if (iInsert != constraints.end() && *iInsert == cDef)
+          {
+            mOnError(FormatString("node %d: constraint %s@%d already defined; ignoring.",
+              index, cDef.mProperty.c_str(), cDef.mSourceIdx));
+          }
+          else
+          {
+            constraints.insert(iInsert, cDef);
+          }
+        }
+      }
+    }
+
+    // Determine index for mapping
+    const unsigned int myIndex = output.mScene.GetNodeCount();
+    if (!mapper.Map(index, myIndex))
+    {
+      mOnError(FormatString("node %d: error mapping dli index %d: node has multiple parents. Ignoring subtree."));
+      return;
+    }
+
+    // if the node is a bone in a skeletal animation, it will have the inverse bind pose matrix.
+    Matrix invBindMatrix{ false };
+    if (ReadVector(node->GetChild("inverseBindPoseMatrix"), invBindMatrix.AsFloat(), 16u))  // TODO: more robust error checking?
+    {
+      mInverseBindMatrices[myIndex] = invBindMatrix;
+    }
+
+    // Register nodeDef
+    auto rawDef = output.mScene.AddNode(std::make_unique<NodeDefinition>(std::move(nodeDef)));
+    if (rawDef)  // NOTE: no ownership. Guaranteed to stay in scope.
+    {
+      // ...And only then parse children.
+      if (auto children = node->GetChild("children"))
+      {
+        inOutParentStack.push_back(myIndex);
+
+        rawDef->mChildren.reserve(children->Size());
+
+        uint32_t iChild = 0;
+        for (auto j0 = children->CBegin(), j1 = children->CEnd(); j0 != j1; ++j0, ++iChild)
+        {
+          auto& child = (*j0).second;
+          if (child.GetType() == TreeNode::INTEGER)
+          {
+            ParseNodesInternal(nodes, child.GetInteger(), inOutParentStack, params, mapper); // child object is created in scene definition.
+          }
+          else
+          {
+            ExceptionFlinger(ASSERT_LOCATION) << "node " << index << ", child " << iChild <<
+              ": invalid index type.";
+          }
+        }
+
+        inOutParentStack.pop_back();
+      }
+      else if (rawDef->mCustomization)
+      {
+        mOnError(FormatString("node %d: not an actual customization without children.", index));
+      }
+
+      if (auto proc = params.input.mNodePropertyProcessor)  // optional processing
+      {
+        // WARNING: constraint IDs are not resolved at this point.
+        Property::Map nodeData;
+        ParseProperties(*node, nodeData);
+        proc(*rawDef, std::move(nodeData), mOnError);
+      }
+    }
+    else
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Node " << index << ": name already used.";
+    }
+  }
+}
+
+void DliLoader::Impl::ParseAnimations(const TreeNode* tnAnimations, LoadParams& params)
+{
+  auto& definitions = params.output.mAnimationDefinitions;
+  definitions.reserve(definitions.size() + tnAnimations->Size());
+
+  for (TreeNode::ConstIterator iAnim = tnAnimations->CBegin(), iAnimEnd = tnAnimations->CEnd();
+    iAnim != iAnimEnd; ++iAnim)
+  {
+    const TreeNode& tnAnim = (*iAnim).second;
+    AnimationDefinition animDef;
+    ReadString(tnAnim.GetChild(NAME), animDef.mName);
+
+    auto iFind = std::lower_bound(definitions.begin(), definitions.end(), animDef,
+      [](const AnimationDefinition& ad0, const AnimationDefinition& ad1) {
+      return ad0.mName < ad1.mName;
+    });
+    const bool overwrite = iFind != definitions.end() && iFind->mName == animDef.mName;
+    if (overwrite)
+    {
+      mOnError(FormatString("Pre-existing animation with name '%s' is being overwritten.", animDef.mName.c_str()));
+    }
+
+    // Duration -- We need something that animated properties' delay / duration can
+    // be expressed as a multiple of; 0 won't work. This is small enough (i.e. shorter
+    // than our frame delay) to not be restrictive WRT replaying. If anything needs
+    // to occur more frequently, then Animations are likely not your solution anyway.
+    animDef.mDuration = AnimationDefinition::MIN_DURATION_SECONDS;
+    if (!ReadFloat(tnAnim.GetChild("duration"), animDef.mDuration))
+    {
+      mOnError(FormatString("Animation '%s' fails to define '%s', defaulting to %f.",
+        animDef.mName.c_str(), "duration", animDef.mDuration));
+    }
+
+    // Get loop count - # of playbacks. Default is once. 0 means repeat indefinitely.
+    animDef.mLoopCount = 1;
+    if (ReadInt(tnAnim.GetChild("loopCount"), animDef.mLoopCount) &&
+      animDef.mLoopCount < 0)
+    {
+      animDef.mLoopCount = 0;
+    }
+
+    std::string endAction;
+    if (ReadString(tnAnim.GetChild("endAction"), endAction))
+    {
+      if ("BAKE" == endAction)
+      {
+        animDef.mEndAction = Animation::BAKE;
+      }
+      else if ("DISCARD" == endAction)
+      {
+        animDef.mEndAction = Animation::DISCARD;
+      }
+      else if ("BAKE_FINAL" == endAction)
+      {
+        animDef.mEndAction = Animation::BAKE_FINAL;
+      }
+    }
+
+    if (ReadString(tnAnim.GetChild("disconnectAction"), endAction))
+    {
+      if ("BAKE" == endAction)
+      {
+        animDef.mDisconnectAction = Animation::BAKE;
+      }
+      else if ("DISCARD" == endAction)
+      {
+        animDef.mDisconnectAction = Animation::DISCARD;
+      }
+      else if ("BAKE_FINAL" == endAction)
+      {
+        animDef.mDisconnectAction = Animation::BAKE_FINAL;
+      }
+    }
+
+    if (const TreeNode* tnProperties = tnAnim.GetChild("properties"))
+    {
+      animDef.mProperties.reserve(tnProperties->Size());
+      for (TreeNode::ConstIterator iProperty = tnProperties->CBegin(), iPropertyEnd = tnProperties->CEnd();
+        iProperty != iPropertyEnd; ++iProperty)
+      {
+        const TreeNode &tnProperty = (*iProperty).second;
+
+        AnimatedProperty animProp;
+        if (!ReadString(tnProperty.GetChild("node"), animProp.mNodeName))
+        {
+          mOnError(FormatString("Animation '%s': Failed to read the 'node' tag.", animDef.mName.c_str()));
+          continue;
+        }
+
+        if (!ReadString(tnProperty.GetChild("property"), animProp.mPropertyName))
+        {
+          mOnError(FormatString("Animation '%s': Failed to read the 'property' tag", animDef.mName.c_str()));
+          continue;
+        }
+
+        // these are the defaults
+        animProp.mTimePeriod.delaySeconds = 0.f;
+        animProp.mTimePeriod.durationSeconds = animDef.mDuration;
+        if (!ReadTimePeriod(tnProperty.GetChild("timePeriod"), animProp.mTimePeriod))
+        {
+          mOnError(FormatString("Animation '%s': timePeriod missing in Property #%d: defaulting to %f.",
+            animDef.mName.c_str(), animDef.mProperties.size(), animProp.mTimePeriod.durationSeconds));
+        }
+
+        std::string alphaFunctionValue;
+        if (ReadString(tnProperty.GetChild("alphaFunction"), alphaFunctionValue))
+        {
+          animProp.mAlphaFunction = GetAlphaFunction(alphaFunctionValue);
+        }
+
+        if (const TreeNode* tnKeyFramesBin = tnProperty.GetChild("keyFramesBin"))
+        {
+          DALI_ASSERT_ALWAYS(!animProp.mPropertyName.empty() && "Animation must specify a property name");
+
+          std::ifstream binAniFile;
+          std::string animationFilename;
+          if (ReadString(tnKeyFramesBin->GetChild(URL), animationFilename))
+          {
+            std::string animationFullPath = params.input.mAnimationsPath + animationFilename;
+            binAniFile.open(animationFullPath, std::ios::binary);
+            if (binAniFile.fail())
+            {
+              ExceptionFlinger(ASSERT_LOCATION) << "Failed to open animation data '" <<
+                animationFullPath << "'";
+            }
+          }
+
+          int byteOffset = 0;
+          ReadInt(tnKeyFramesBin->GetChild("byteOffset"), byteOffset);
+          DALI_ASSERT_ALWAYS(byteOffset >= 0);
+
+          binAniFile.seekg(byteOffset, std::ios::beg);
+
+          int numKeys = 0;
+          ReadInt(tnKeyFramesBin->GetChild("numKeys"), numKeys);
+          DALI_ASSERT_ALWAYS(numKeys >= 0);
+
+          animProp.mKeyFrames = KeyFrames::New();
+
+          //In binary animation file only is saved the position, rotation, scale and blend shape weight keys.
+          //so, if it is vector3 we assume is position or scale keys, if it is vector4 we assume is rotation,
+          // otherwise are blend shape weight keys.
+          // TODO support for binary header with size information
+          Property::Type propType = Property::FLOAT;  // assume blend shape weights
+          if (animProp.mPropertyName == "orientation")
+          {
+            propType = Property::VECTOR4;
+          }
+          else if ((animProp.mPropertyName == "position") || (animProp.mPropertyName == "scale"))
+          {
+            propType = Property::VECTOR3;
+          }
+
+          //alphafunction is reserved for future implementation
+          // NOTE: right now we're just using AlphaFunction::LINEAR.
+          unsigned char dummyAlphaFunction;
+
+          float progress;
+          Property::Value propValue;
+          for (int key = 0; key < numKeys; key++)
+          {
+            binAniFile.read(reinterpret_cast<char*>(&progress), sizeof(float));
+            if (propType == Property::VECTOR3)
+            {
+              Vector3 value;
+              binAniFile.read(reinterpret_cast<char*>(value.AsFloat()), sizeof(float) * 3);
+              propValue = Property::Value(value);
+            }
+            else if (propType == Property::VECTOR4)
+            {
+              Vector4 value;
+              binAniFile.read(reinterpret_cast<char*>(value.AsFloat()), sizeof(float) * 4);
+              propValue = Property::Value(Quaternion(value));
+            }
+            else
+            {
+              float value;
+              binAniFile.read(reinterpret_cast<char*>(&value), sizeof(float));
+              propValue = Property::Value(value);
+            }
+
+            binAniFile.read(reinterpret_cast<char*>(&dummyAlphaFunction), sizeof(unsigned char));
+
+            animProp.mKeyFrames.Add(progress, propValue, AlphaFunction::LINEAR);
+          }
+        }
+        else if (const TreeNode* tnKeyFrames = tnProperty.GetChild("keyFrames"))
+        {
+          DALI_ASSERT_ALWAYS(!animProp.mPropertyName.empty() && "Animation must specify a property name");
+          animProp.mKeyFrames = KeyFrames::New();
+
+          float progress = 0.0f;
+          for (auto i0 = tnKeyFrames->CBegin(), i1 = tnKeyFrames->CEnd(); i1 != i0; ++i0)
+          {
+            const TreeNode::KeyNodePair& kfKeyChild = *i0;
+            bool readResult = ReadFloat(kfKeyChild.second.GetChild("progress"), progress);
+            DALI_ASSERT_ALWAYS(readResult && "Key frame entry must have 'progress'");
+
+            const TreeNode* tnValue = kfKeyChild.second.GetChild("value");
+            DALI_ASSERT_ALWAYS(tnValue && "Key frame entry must have 'value'");
+
+            // For the "orientation" property, convert from Vector4 -> Rotation value
+            // This work-around is preferable to a null-pointer exception in the DALi update thread
+            Property::Value propValue(ReadPropertyValue(*tnValue));
+            if (propValue.GetType() == Property::VECTOR4 &&
+              animProp.mPropertyName == "orientation")
+            {
+              Vector4 v;
+              propValue.Get(v);
+              propValue = Property::Value(Quaternion(v.w, v.x, v.y, v.z));
+            }
+
+            AlphaFunction kfAlphaFunction(AlphaFunction::DEFAULT);
+            std::string alphaFuncStr;
+            if (ReadString(kfKeyChild.second.GetChild("alphaFunction"), alphaFuncStr))
+            {
+              kfAlphaFunction = GetAlphaFunction(alphaFuncStr);
+            }
+
+            animProp.mKeyFrames.Add(progress, propValue, kfAlphaFunction);
+          }
+        }
+        else
+        {
+          const TreeNode* tnValue = tnProperty.GetChild("value");
+          if (tnValue)
+          {
+            animProp.mValue.reset(new AnimatedProperty::Value{ ReadPropertyValue(*tnValue) });
+          }
+          else
+          {
+            mOnError(FormatString("Property '%s' fails to define target value.",
+              animProp.mPropertyName.c_str()));
+          }
+
+          ReadBool(tnProperty.GetChild("relative"), animProp.mValue->mIsRelative);
+        }
+
+        animDef.mProperties.push_back(std::move(animProp));
+      }
+    }
+
+    if (overwrite)
+    {
+      *iFind = std::move(animDef);
+    }
+    else
+    {
+      iFind = definitions.insert(iFind, std::move(animDef));
+    }
+
+    if (auto proc = params.input.mAnimationPropertyProcessor)  // optional processing
+    {
+      Property::Map map;
+      ParseProperties(tnAnim, map);
+      proc(animDef, std::move(map), mOnError);
+    }
+  }
+}
+
+void DliLoader::Impl::ParseAnimationGroups(const Toolkit::TreeNode* tnAnimationGroups, LoadParams& params)
+{
+  auto& animGroups = params.output.mAnimationGroupDefinitions;
+
+  int numGroups = 0;
+  for (auto iGroups = tnAnimationGroups->CBegin(), iGroupsEnd = tnAnimationGroups->CEnd();
+    iGroups != iGroupsEnd; ++iGroups, ++numGroups)
+  {
+    const auto& tnGroup = *iGroups;
+    auto tnName = tnGroup.second.GetChild(NAME);
+    std::string groupName;
+    if (!tnName || !ReadString(tnName, groupName))
+    {
+      mOnError(FormatString("Failed to get the name for the Animation group %d; ignoring.", numGroups));
+      continue;
+    }
+
+    auto iFind = std::lower_bound(animGroups.begin(), animGroups.end(), groupName,
+      [](const AnimationGroupDefinition& group, const std::string& name) {
+      return group.mName < name;
+    });
+    if (iFind != animGroups.end() && iFind->mName == groupName)
+    {
+      mOnError(FormatString("Animation group with name '%s' already exists; new entries will be merged.", groupName.c_str()));
+    }
+    else
+    {
+      iFind = animGroups.insert(iFind, AnimationGroupDefinition{});
+    }
+
+    iFind->mName = groupName;
+
+    auto tnAnims = tnGroup.second.GetChild("animations");
+    if (tnAnims && tnAnims->Size() > 0)
+    {
+      auto& anims = iFind->mAnimations;
+      anims.reserve(anims.size() + tnAnims->Size());
+      for (auto iAnims = tnAnims->CBegin(), iAnimsEnd = tnAnims->CEnd(); iAnims != iAnimsEnd; ++iAnims)
+      {
+        anims.push_back((*iAnims).second.GetString());
+      }
+    }
+  }
+}
+
+void DliLoader::Impl::GetCameraParameters(std::vector<CameraParameters>& cameras) const
+{
+  if (const TreeNode* jsonCameras = mParser.GetRoot()->GetChild("cameras"))
+  {
+    cameras.resize(jsonCameras->Size());
+    auto iCamera = cameras.begin();
+    for (auto i0 = jsonCameras->CBegin(), i1 = jsonCameras->CEnd(); i0 != i1; ++i0)
+    {
+      auto& jsonCamera = (*i0).second;
+
+      ReadFloat(jsonCamera.GetChild("fov"), iCamera->yFov);
+      ReadFloat(jsonCamera.GetChild("near"), iCamera->zNear);
+      ReadFloat(jsonCamera.GetChild("far"), iCamera->zFar);
+      if (ReadVector(jsonCamera.GetChild("orthographic"), iCamera->orthographicSize.AsFloat(), 4u))
+      {
+        iCamera->isPerspective = false;
+      }
+
+      if (auto jsonMatrix = jsonCamera.GetChild("matrix"))
+      {
+        ReadVector(jsonMatrix, iCamera->matrix.AsFloat(), 16u);
+      }
+
+      ++iCamera;
+    }
+  }
+}
+
+void DliLoader::Impl::GetLightParameters(std::vector<LightParameters>& lights) const
+{
+  if (const TreeNode* jsonLights = mParser.GetRoot()->GetChild("lights"))
+  {
+    lights.resize(jsonLights->Size());
+    auto iLight = lights.begin();
+    for (auto i0 = jsonLights->CBegin(), i1 = jsonLights->CEnd(); i0 != i1; ++i0)
+    {
+      auto& jsonLight = (*i0).second;
+      if (!ReadVector(jsonLight.GetChild("matrix"), iLight->transform.AsFloat(), 16))
+      {
+        mOnError(
+          FormatString("Failed to parse light %d - \"matrix\" child with 16 floats expected.\n",
+            std::distance(jsonLights->CBegin(), i0)));
+        continue;
+      }
+
+      int shadowMapSize = 0;
+      if (ReadInt(jsonLight.GetChild(SHADOW_MAP_SIZE), shadowMapSize) && shadowMapSize < 0)
+      {
+        mOnError(
+          FormatString("Failed to parse light %d - %s has an invalid value.",
+            std::distance(jsonLights->CBegin(), i0), SHADOW_MAP_SIZE));
+        continue;
+      }
+      iLight->shadowMapSize = shadowMapSize;
+
+      float orthoSize = 0.f;
+      if (ReadFloat(jsonLight.GetChild(ORTHOGRAPHIC_SIZE), orthoSize) &&
+        (orthoSize < .0f || std::isnan(orthoSize) || std::isinf(orthoSize)))
+      {
+        mOnError(
+          FormatString("Failed to parse light %d - %s has an invalid value.",
+            std::distance(jsonLights->CBegin(), i0), ORTHOGRAPHIC_SIZE));
+        continue;
+      }
+      iLight->orthographicSize = orthoSize;
+
+      if ((iLight->shadowMapSize > 0) != (iLight->orthographicSize > .0f))
+      {
+        mOnError(FormatString(
+          "Light %d: Both shadow map size and orthographic size must be set for shadows to work.",
+            std::distance(jsonLights->CBegin(), i0)));
+      }
+
+      if (!ReadVector(jsonLight.GetChild("color"), iLight->color.AsFloat(), 3))  // color is optional
+      {
+        iLight->color = Vector3::ONE;  // default to white
+      }
+
+      if (!ReadFloat(jsonLight.GetChild("intensity"), iLight->intensity))  // intensity is optional
+      {
+        iLight->intensity = 1.0f;  // default to 1.0
+      }
+
+      if (!ReadFloat(jsonLight.GetChild("shadowIntensity"), iLight->shadowIntensity))  // intensity is optional
+      {
+        iLight->shadowIntensity = 1.0f;  // default to 1.0
+      }
+
+      ++iLight;
+    }
+  }
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/dli-loader.h b/dali-scene-loader/public-api/dli-loader.h
new file mode 100644 (file)
index 0000000..e09d4d0
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef DALI_SCENE_LOADER_DLI_LOADER_H
+#define DALI_SCENE_LOADER_DLI_LOADER_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+ // INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/animation-definition.h"
+#include "dali-scene-loader/public-api/customization.h"
+#include "dali-scene-loader/public-api/string-callback.h"
+#include "dali-scene-loader/public-api/index.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+typedef std::pair<std::string, std::string> Metadata;
+
+// Forward declarations
+struct LoadResult;
+struct CameraParameters;
+struct LightParameters;
+struct TextParameters;
+
+class ResourceBundle;
+struct NodeDefinition;
+class SceneDefinition;
+
+class DALI_SCENE_LOADER_API DliLoader
+{
+public:
+  using ConvertFontCode = void(*)(const std::string& code, std::string& fontFamily, std::string& slant, std::string& weight, float& size);
+  using ConvertColorCode = Vector4(*)(const std::string& code);
+
+  using CategoryProcessor = std::function<void(Property::Array&& categoryData, StringCallback onError)>;
+  using CategoryProcessorVector = std::vector<std::pair<std::string /*name*/, CategoryProcessor>>;
+
+  using NodeProcessor = std::function<void(const NodeDefinition& nodeDef,
+    Property::Map&& nodeData, StringCallback onError)>;
+
+  using AnimationProcessor = std::function<void(const AnimationDefinition& animDef,
+    Property::Map&& animData, StringCallback onError)>;
+
+  struct InputParams
+  {
+    /**
+     * @brief The absolute path of animation binaries referenced in the .dli.
+     */
+    std::string mAnimationsPath;
+
+    /**
+     * @brief Provides a facility to determine a color from a code instead of RGB(A) values.
+     */
+    ConvertColorCode mConvertColorCode;
+
+    /**
+     * @brief A collection of handlers, mapped to the names of the top level (i.e. below
+     *  root) element, whom they will attempt to process. This will take place before
+     *  the parsing of scene Nodes and Animations, but after skeletons, environment, mesh,
+     *  shader and material resources.
+     */
+    CategoryProcessorVector mPreNodeCategoryProcessors;
+
+    /**
+     * @brief A collection of handlers, mapped to the names of the top level (i.e. below
+     *  root) element, whom they will attempt to process. This will take place after
+     *  the parsing of the scene Nodes and Animations.
+     */
+    CategoryProcessorVector mPostNodeCategoryProcessors;
+
+    /**
+     * @brief Provides an extension point to nodes. If provided, this function will be
+     *  called with each JSON element and definition, of a scene node.
+     * @note Constraints rely on ID resolution (from .dli to scene definition), which
+     *  takes place after the parsing of the nodes; therefore AT THIS POINT the node
+     *  IDs seen in constraints will still be the .dli IDs - NOT to be relied on for
+     *  indexing into mScene.
+     */
+    NodeProcessor mNodePropertyProcessor;
+
+    /**
+     * @brief Provides an extension point to animations. If provided, this function will be
+     *  called with each JSON element and fully processed definition, of an animation.
+     */
+    AnimationProcessor mAnimationPropertyProcessor;
+  };
+
+  struct LoadParams
+  {
+    InputParams const& input;
+    LoadResult& output;
+  };
+
+  DliLoader();
+  ~DliLoader();
+
+  /**
+   * @brief Sets the callback that messages from non-fatal errors get posted to.
+   *  Uses DefaultErrorCallback by default.
+   */
+  void SetErrorCallback(StringCallback onError);
+
+  /**
+   * @brief Attempts to load and parse a .dli document into a DOM tree.
+   * @return Whether the operation was successful.
+   */
+  bool LoadScene(const std::string& uri, LoadParams& params);
+
+  /**
+   * @return The error string describing how the parse has failed, if any.
+   */
+  std::string GetParseError() const;
+
+private:
+  struct Impl;
+  const std::unique_ptr<Impl> mImpl;
+};
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_DLI_LOADER_H
diff --git a/dali-scene-loader/public-api/environment-definition.cpp b/dali-scene-loader/public-api/environment-definition.cpp
new file mode 100644 (file)
index 0000000..16c8e2c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/environment-definition.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+EnvironmentDefinition::RawData
+  EnvironmentDefinition::LoadRaw(const std::string& environmentsPath) const
+{
+  RawData raw;
+  auto loadFn = [&environmentsPath](const std::string& path, CubeData& cd) {
+    if (path.empty())
+    {
+      cd.data.resize(6);
+      for (auto& face : cd.data)
+      {
+        face.push_back(PixelData::New(new uint8_t[3]{ 0xff, 0xff, 0xff }, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
+      }
+    }
+    else if(!LoadCubeMapData(environmentsPath + path, cd))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to load cubemap texture from '" <<
+        path << "'.";
+    }
+  };
+
+  loadFn(mDiffuseMapPath, raw.mDiffuse);
+  loadFn(mSpecularMapPath, raw.mSpecular);
+  return raw;
+}
+
+EnvironmentDefinition::Textures EnvironmentDefinition::Load(RawData&& raw) const
+{
+  Textures textures;
+
+  // This texture should have 6 faces and only one mipmap
+  if (!raw.mDiffuse.data.empty())
+  {
+    textures.mDiffuse = raw.mDiffuse.CreateTexture();
+  }
+
+  // This texture should have 6 faces and 6 mipmaps
+  if (!raw.mSpecular.data.empty())
+  {
+    textures.mSpecular = raw.mSpecular.CreateTexture();
+  }
+  return textures;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/environment-definition.h b/dali-scene-loader/public-api/environment-definition.h
new file mode 100644 (file)
index 0000000..1b1906f
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef DALI_SCENE_LOADER_ENVIRONMENT_DEFINITION_H
+#define DALI_SCENE_LOADER_ENVIRONMENT_DEFINITION_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+ // INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/ktx-loader.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/rendering/texture.h"
+#include "dali/public-api/math/quaternion.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Defines an environment map with either or both of radiance
+ *  and irradiance maps.
+ */
+struct DALI_SCENE_LOADER_API EnvironmentDefinition
+{
+  struct Textures
+  {
+    Texture mDiffuse;  // irradiance
+    Texture mSpecular;  // radiance
+
+    bool IsLoaded() const
+    {
+      return mDiffuse || mSpecular;
+    }
+  };
+
+  struct RawData
+  {
+    CubeData mDiffuse;
+    CubeData mSpecular;
+  };
+
+  using EnvironmentData = std::pair<EnvironmentDefinition, Textures>;
+  using Vector = std::vector<EnvironmentData>;
+
+  EnvironmentDefinition() = default;
+
+  EnvironmentDefinition(const EnvironmentDefinition&) = delete;
+  EnvironmentDefinition& operator=(const EnvironmentDefinition&) = delete;
+
+  EnvironmentDefinition(EnvironmentDefinition&&) = default;
+  EnvironmentDefinition& operator=(EnvironmentDefinition&&) = default;
+
+  /**
+   * @brief Loads raw pixel data for the given diffuse and specular maps.
+   * @note This can be done on any thread.
+   */
+  RawData LoadRaw(const std::string& environmentsPath) const;
+
+  /**
+   * @brief Creates DALi cubemap Textures from the pixel data in @a raw, then
+   *  returns them in a Textures object.
+   * @note This must only be called from the event thread.
+   */
+  Textures Load(RawData&& raw) const;
+
+public: // DATA
+  std::string mDiffuseMapPath;
+  std::string mSpecularMapPath;
+  Quaternion mCubeOrientation = Quaternion::IDENTITY;
+  float mIblIntensity = 1.0f;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_ENVIRONMENT_DEFINITION_H
diff --git a/dali-scene-loader/public-api/file.list b/dali-scene-loader/public-api/file.list
new file mode 100644 (file)
index 0000000..9c5fcbf
--- /dev/null
@@ -0,0 +1,28 @@
+set(scene_loader_public_api_dir "${scene_loader_dir}/public-api")
+
+set(scene_loader_src_files ${scene_loader_src_files}
+       ${scene_loader_public_api_dir}/alpha-function-helper.cpp
+       ${scene_loader_public_api_dir}/animated-property.cpp
+       ${scene_loader_public_api_dir}/animation-definition.cpp
+       ${scene_loader_public_api_dir}/blend-shape-details.cpp
+       ${scene_loader_public_api_dir}/camera-parameters.cpp
+       ${scene_loader_public_api_dir}/customization.cpp
+       ${scene_loader_public_api_dir}/dli-loader.cpp
+       ${scene_loader_public_api_dir}/environment-definition.cpp
+       ${scene_loader_public_api_dir}/gltf2-loader.cpp
+       ${scene_loader_public_api_dir}/ktx-loader.cpp
+       ${scene_loader_public_api_dir}/material-definition.cpp
+       ${scene_loader_public_api_dir}/matrix-stack.cpp
+       ${scene_loader_public_api_dir}/mesh-definition.cpp
+       ${scene_loader_public_api_dir}/node-definition.cpp
+       ${scene_loader_public_api_dir}/parse-renderer-state.cpp
+       ${scene_loader_public_api_dir}/renderer-state.cpp
+       ${scene_loader_public_api_dir}/resource-bundle.cpp
+       ${scene_loader_public_api_dir}/scene-definition.cpp
+       ${scene_loader_public_api_dir}/shader-definition.cpp
+       ${scene_loader_public_api_dir}/shader-definition-factory.cpp
+       ${scene_loader_public_api_dir}/skinning-details.cpp
+       ${scene_loader_public_api_dir}/string-callback.cpp
+       ${scene_loader_public_api_dir}/utils.cpp
+       ${scene_loader_public_api_dir}/view-projection.cpp
+)
diff --git a/dali-scene-loader/public-api/gltf2-loader.cpp b/dali-scene-loader/public-api/gltf2-loader.cpp
new file mode 100644 (file)
index 0000000..ed08a41
--- /dev/null
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/load-result.h"
+#include "dali-scene-loader/public-api/scene-definition.h"
+#include "dali-scene-loader/public-api/resource-bundle.h"
+#include "dali-scene-loader/public-api/gltf2-loader.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include "dali-scene-loader/public-api/shader-definition-factory.h"
+#include "dali-scene-loader/internal/gltf2-asset.h"
+#include "dali/public-api/math/quaternion.h"
+#include <fstream>
+
+#define ENUM_STRING_MAPPING(t, x) { #x, t::x }
+
+namespace gt = gltf2;
+namespace js = json;
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+const std::string POSITION_PROPERTY("position");
+const std::string ORIENTATION_PROPERTY("orientation");
+const std::string SCALE_PROPERTY("scale");
+const std::string BLEND_SHAPE_WEIGHTS_UNIFORM("uBlendShapeWeight");
+
+const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
+  Geometry::POINTS,
+  Geometry::LINES,
+  Geometry::LINE_LOOP,
+  Geometry::LINE_STRIP,
+  Geometry::TRIANGLES,
+  Geometry::TRIANGLE_STRIP,
+  Geometry::TRIANGLE_FAN
+}; //...because Dali swaps the last two.
+
+struct AttributeMapping
+{
+  gt::Attribute::Type mType;
+  MeshDefinition::Accessor MeshDefinition::* mAccessor;
+  uint16_t mElementSizeRequired;
+} ATTRIBUTE_MAPPINGS[]{
+  { gt::Attribute::NORMAL, &MeshDefinition::mNormals, sizeof(Vector3) },
+  { gt::Attribute::TANGENT, &MeshDefinition::mTangents, sizeof(Vector3) },
+  { gt::Attribute::TEXCOORD_0, &MeshDefinition::mTexCoords, sizeof(Vector2) },
+  { gt::Attribute::JOINTS_0, &MeshDefinition::mJoints0, sizeof(Vector4) },
+  { gt::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4) },
+};
+
+std::vector<gt::Animation> ReadAnimationArray(const json_value_s& j)
+{
+  gt::Animation proxy;
+  SetRefReaderObject(proxy);
+
+  auto results = js::Read::Array<gt::Animation, js::ObjectReader<gt::Animation>::Read>(j);
+
+  for (auto& animation : results)
+  {
+    for (auto& channel : animation.mChannels)
+    {
+      channel.mSampler.UpdateVector(animation.mSamplers);
+    }
+  }
+
+  return results;
+}
+
+void ApplyAccessorMinMax(const gt::Accessor& acc, float* values)
+{
+  DALI_ASSERT_ALWAYS(acc.mMax.empty() || gt::AccessorType::ElementCount(acc.mType) == acc.mMax.size());
+  DALI_ASSERT_ALWAYS(acc.mMin.empty() || gt::AccessorType::ElementCount(acc.mType) == acc.mMin.size());
+  MeshDefinition::Blob::ApplyMinMax(acc.mMin, acc.mMax, acc.mCount, values);
+}
+
+const auto BUFFER_READER = std::move(js::Reader<gt::Buffer>()
+  .Register(*js::MakeProperty("byteLength", js::Read::Number<uint32_t>, &gt::Buffer::mByteLength))
+  .Register(*js::MakeProperty("uri", js::Read::StringView, &gt::Buffer::mUri))
+);
+
+const auto BUFFER_VIEW_READER = std::move(js::Reader<gt::BufferView>()
+  .Register(*js::MakeProperty("buffer", gt::RefReader<gt::Document>::Read<gt::Buffer, &gt::Document::mBuffers>, &gt::BufferView::mBuffer))
+  .Register(*js::MakeProperty("byteOffset", js::Read::Number<uint32_t>, &gt::BufferView::mByteOffset))
+  .Register(*js::MakeProperty("byteLength", js::Read::Number<uint32_t>, &gt::BufferView::mByteLength))
+  .Register(*js::MakeProperty("byteStride", js::Read::Number<uint32_t>, &gt::BufferView::mByteStride))
+  .Register(*js::MakeProperty("target", js::Read::Number<uint32_t>, &gt::BufferView::mTarget))
+);
+
+const auto BUFFER_VIEW_CLIENT_READER = std::move(js::Reader<gt::BufferViewClient>()
+  .Register(*js::MakeProperty("bufferView", gt::RefReader<gt::Document>::Read<gt::BufferView, &gt::Document::mBufferViews>, &gt::BufferViewClient::mBufferView))
+  .Register(*js::MakeProperty("byteOffset", js::Read::Number<uint32_t>, &gt::BufferViewClient::mByteOffset))
+);
+
+const auto COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER = std::move(js::Reader<gt::ComponentTypedBufferViewClient>()
+  .Register(*new js::Property<gt::ComponentTypedBufferViewClient, gt::Ref<gt::BufferView>>("bufferView", gt::RefReader<gt::Document>::Read<gt::BufferView, &gt::Document::mBufferViews>, &gt::ComponentTypedBufferViewClient::mBufferView))
+  .Register(*new js::Property<gt::ComponentTypedBufferViewClient, uint32_t>("byteOffset", js::Read::Number<uint32_t>, &gt::ComponentTypedBufferViewClient::mByteOffset))
+  .Register(*js::MakeProperty("componentType", js::Read::Enum<gt::Component::Type>, &gt::ComponentTypedBufferViewClient::mComponentType))
+);
+
+const auto ACCESSOR_SPARSE_READER = std::move(js::Reader<gt::Accessor::Sparse>()
+  .Register(*js::MakeProperty("count", js::Read::Number<uint32_t>, &gt::Accessor::Sparse::mCount))
+  .Register(*js::MakeProperty("indices", js::ObjectReader<gt::ComponentTypedBufferViewClient>::Read,
+    &gt::Accessor::Sparse::mIndices))
+  .Register(*js::MakeProperty("values", js::ObjectReader<gt::BufferViewClient>::Read,
+    &gt::Accessor::Sparse::mValues))
+);
+
+const auto ACCESSOR_READER = std::move(js::Reader<gt::Accessor>()
+  .Register(*new js::Property<gt::Accessor, gt::Ref<gt::BufferView>>("bufferView",
+    gt::RefReader<gt::Document>::Read<gt::BufferView, &gt::Document::mBufferViews>, &gt::Accessor::mBufferView))
+  .Register(*new js::Property<gt::Accessor, uint32_t>("byteOffset",
+    js::Read::Number<uint32_t>, &gt::Accessor::mByteOffset))
+  .Register(*new js::Property<gt::Accessor, gt::Component::Type>("componentType",
+    js::Read::Enum<gt::Component::Type>, &gt::Accessor::mComponentType))
+  .Register(*new js::Property<gt::Accessor, std::string_view>("name", js::Read::StringView, &gt::Accessor::mName))
+  .Register(*js::MakeProperty("count", js::Read::Number<uint32_t>, &gt::Accessor::mCount))
+  .Register(*js::MakeProperty("normalized", js::Read::Boolean, &gt::Accessor::mNormalized))
+  .Register(*js::MakeProperty("type", gt::ReadStringEnum<gt::AccessorType>, &gt::Accessor::mType))
+  .Register(*js::MakeProperty("min", js::Read::Array<float, js::Read::Number>, &gt::Accessor::mMin))
+  .Register(*js::MakeProperty("max", js::Read::Array<float, js::Read::Number>, &gt::Accessor::mMax))
+  .Register(*new js::Property<gt::Accessor, gt::Accessor::Sparse>("sparse", js::ObjectReader<gt::Accessor::Sparse>::Read,
+    &gt::Accessor::SetSparse))
+);
+
+const auto IMAGE_READER = std::move(js::Reader<gt::Image>()
+  .Register(*new js::Property<gt::Image, std::string_view>("name", js::Read::StringView, &gt::Material::mName))
+  .Register(*js::MakeProperty("uri", js::Read::StringView, &gt::Image::mUri))
+  .Register(*js::MakeProperty("mimeType", js::Read::StringView, &gt::Image::mMimeType))
+  .Register(*js::MakeProperty("bufferView", gt::RefReader<gt::Document>::Read<gt::BufferView, &gt::Document::mBufferViews>, &gt::Image::mBufferView))
+);
+
+const auto SAMPLER_READER = std::move(js::Reader<gt::Sampler>()
+  .Register(*js::MakeProperty("minFilter", js::Read::Enum<gt::Filter::Type>, &gt::Sampler::mMinFilter))
+  .Register(*js::MakeProperty("magFilter", js::Read::Enum<gt::Filter::Type>, &gt::Sampler::mMagFilter))
+  .Register(*js::MakeProperty("wrapS", js::Read::Enum<gt::Wrap::Type>, &gt::Sampler::mWrapS))
+  .Register(*js::MakeProperty("wrapT", js::Read::Enum<gt::Wrap::Type>, &gt::Sampler::mWrapT))
+);
+
+const auto TEXURE_READER = std::move(js::Reader<gt::Texture>()
+  .Register(*js::MakeProperty("source", gt::RefReader<gt::Document>::Read<gt::Image, &gt::Document::mImages>, &gt::Texture::mSource))
+  .Register(*js::MakeProperty("sampler", gt::RefReader<gt::Document>::Read<gt::Sampler, &gt::Document::mSamplers>, &gt::Texture::mSampler))
+);
+
+const auto TEXURE_INFO_READER = std::move(js::Reader<gt::TextureInfo>()
+  .Register(*js::MakeProperty("index", gt::RefReader<gt::Document>::Read<gt::Texture, &gt::Document::mTextures>, &gt::TextureInfo::mTexture))
+  .Register(*js::MakeProperty("texCoord", js::Read::Number<uint32_t>, &gt::TextureInfo::mTexCoord))
+  .Register(*js::MakeProperty("scale", js::Read::Number<float>, &gt::TextureInfo::mScale))
+);
+
+const auto MATERIAL_PBR_READER = std::move(js::Reader<gt::Material::Pbr>()
+  .Register(*js::MakeProperty("baseColorFactor", gt::ReadDaliVector<Vector4>, &gt::Material::Pbr::mBaseColorFactor))
+  .Register(*js::MakeProperty("baseColorTexture", js::ObjectReader<gt::TextureInfo>::Read,
+    &gt::Material::Pbr::mBaseColorTexture))
+  .Register(*js::MakeProperty("metallicFactor", js::Read::Number<float>, &gt::Material::Pbr::mMetallicFactor))
+  .Register(*js::MakeProperty("roughnessFactor", js::Read::Number<float>, &gt::Material::Pbr::mRoughnessFactor))
+  .Register(*js::MakeProperty("metallicRoughnessTexture", js::ObjectReader<gt::TextureInfo>::Read,
+    &gt::Material::Pbr::mMetallicRoughnessTexture))
+);
+
+const auto MATERIAL_READER = std::move(js::Reader<gt::Material>()
+  .Register(*new js::Property<gt::Material, std::string_view>("name", js::Read::StringView, &gt::Material::mName))
+  .Register(*js::MakeProperty("pbrMetallicRoughness", js::ObjectReader<gt::Material::Pbr>::Read, &gt::Material::mPbrMetallicRoughness))
+  .Register(*js::MakeProperty("normalTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::Material::mNormalTexture))
+  .Register(*js::MakeProperty("occlusionTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::Material::mOcclusionTexture))
+  .Register(*js::MakeProperty("emissiveTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::Material::mEmissiveTexture))
+  .Register(*js::MakeProperty("emissiveFactor", gt::ReadDaliVector<Vector3>, &gt::Material::mEmissiveFactor))
+  .Register(*js::MakeProperty("alphaMode", gt::ReadStringEnum<gt::AlphaMode>, &gt::Material::mAlphaMode))
+  .Register(*js::MakeProperty("alphaCutoff", js::Read::Number<float>, &gt::Material::mAlphaCutoff))
+);
+
+std::map<gt::Attribute::Type, gt::Ref<gt::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
+{
+  auto& jo = js::Cast<json_object_s>(j);
+  std::map<gt::Attribute::Type, gt::Ref<gt::Accessor>> result;
+
+  auto i = jo.start;
+  while (i)
+  {
+    auto jstr = *i->name;
+    result[gt::Attribute::FromString(jstr.string, jstr.string_size)] = gt::RefReader<gt::Document>::Read<gt::Accessor, &gt::Document::mAccessors>(*i->value);
+    i = i->next;
+  }
+  return result;
+}
+
+std::vector<std::map<gt::Attribute::Type, gt::Ref<gt::Accessor>>> ReadMeshPrimitiveTargets(const json_value_s& j)
+{
+  auto& jo = js::Cast<json_array_s>(j);
+  std::vector<std::map<gt::Attribute::Type, gt::Ref<gt::Accessor>>> result;
+
+  result.reserve(jo.length);
+
+  auto i = jo.start;
+  while (i)
+  {
+    result.push_back(std::move(ReadMeshPrimitiveAttributes(*i->value)));
+    i = i->next;
+  }
+
+  return result;
+}
+
+const auto MESH_PRIMITIVE_READER = std::move(js::Reader<gt::Mesh::Primitive>()
+  .Register(*js::MakeProperty("attributes", ReadMeshPrimitiveAttributes, &gt::Mesh::Primitive::mAttributes))
+  .Register(*js::MakeProperty("indices", gt::RefReader<gt::Document>::Read<gt::Accessor, &gt::Document::mAccessors>, &gt::Mesh::Primitive::mIndices))
+  .Register(*js::MakeProperty("material", gt::RefReader<gt::Document>::Read<gt::Material, &gt::Document::mMaterials>, &gt::Mesh::Primitive::mMaterial))
+  .Register(*js::MakeProperty("mode", js::Read::Enum<gt::Mesh::Primitive::Mode>, &gt::Mesh::Primitive::mMode))
+  .Register(*js::MakeProperty("targets", ReadMeshPrimitiveTargets, &gt::Mesh::Primitive::mTargets))
+);
+
+const auto MESH_READER = std::move(js::Reader<gt::Mesh>()
+  .Register(*new js::Property<gt::Mesh, std::string_view>("name", js::Read::StringView, &gt::Mesh::mName))
+  .Register(*js::MakeProperty("primitives",
+    js::Read::Array<gt::Mesh::Primitive, js::ObjectReader<gt::Mesh::Primitive>::Read>, &gt::Mesh::mPrimitives))
+  .Register(*js::MakeProperty("weights", js::Read::Array<float, js::Read::Number>, &gt::Mesh::mWeights))
+);
+
+const auto SKIN_READER = std::move(js::Reader<gt::Skin>()
+  .Register(*new js::Property<gt::Skin, std::string_view>("name", js::Read::StringView, &gt::Skin::mName))
+  .Register(*js::MakeProperty("inverseBindMatrices",
+    gt::RefReader<gt::Document>::Read<gt::Accessor, &gt::Document::mAccessors>, &gt::Skin::mInverseBindMatrices))
+  .Register(*js::MakeProperty("skeleton",
+    gt::RefReader<gt::Document>::Read<gt::Node, &gt::Document::mNodes>, &gt::Skin::mSkeleton))
+  .Register(*js::MakeProperty("joints",
+    js::Read::Array<gt::Ref<gt::Node>, gt::RefReader<gt::Document>::Read<gt::Node, &gt::Document::mNodes>>, &gt::Skin::mJoints))
+);
+
+const auto CAMERA_PERSPECTIVE_READER = std::move(js::Reader<gt::Camera::Perspective>()
+  .Register(*js::MakeProperty("aspectRatio", js::Read::Number<float>, &gt::Camera::Perspective::mAspectRatio))
+  .Register(*js::MakeProperty("yfov", js::Read::Number<float>, &gt::Camera::Perspective::mYFov))
+  .Register(*js::MakeProperty("zfar", js::Read::Number<float>, &gt::Camera::Perspective::mZFar))
+  .Register(*js::MakeProperty("znear", js::Read::Number<float>, &gt::Camera::Perspective::mZNear))
+);  // TODO: infinite perspective projection, where znear is omitted
+
+const auto CAMERA_ORTHOGRAPHIC_READER = std::move(js::Reader<gt::Camera::Orthographic>()
+  .Register(*js::MakeProperty("xmag", js::Read::Number<float>, &gt::Camera::Orthographic::mXMag))
+  .Register(*js::MakeProperty("ymag", js::Read::Number<float>, &gt::Camera::Orthographic::mXMag))
+  .Register(*js::MakeProperty("zfar", js::Read::Number<float>, &gt::Camera::Orthographic::mZFar))
+  .Register(*js::MakeProperty("znear", js::Read::Number<float>, &gt::Camera::Orthographic::mZNear))
+);
+
+const auto CAMERA_READER = std::move(js::Reader<gt::Camera>()
+  .Register(*new js::Property<gt::Camera, std::string_view>("name", js::Read::StringView, &gt::Camera::mName))
+  .Register(*js::MakeProperty("type", js::Read::StringView, &gt::Camera::mType))
+  .Register(*js::MakeProperty("perspective", js::ObjectReader<gt::Camera::Perspective>::Read, &gt::Camera::mPerspective))
+  .Register(*js::MakeProperty("orthographic", js::ObjectReader<gt::Camera::Orthographic>::Read, &gt::Camera::mOrthographic))
+);
+
+const auto NODE_READER = std::move(js::Reader<gt::Node>()
+  .Register(*new js::Property<gt::Node, std::string_view>("name", js::Read::StringView, &gt::Node::mName))
+  .Register(*js::MakeProperty("translation", gt::ReadDaliVector<Vector3>, &gt::Node::mTranslation))
+  .Register(*js::MakeProperty("rotation", gt::ReadQuaternion, &gt::Node::mRotation))
+  .Register(*js::MakeProperty("scale", gt::ReadDaliVector<Vector3>, &gt::Node::mScale))
+  .Register(*new js::Property<gt::Node, Matrix>("matrix", gt::ReadDaliVector<Matrix>, &gt::Node::SetMatrix))
+  .Register(*js::MakeProperty("camera", gt::RefReader<gt::Document>::Read<gt::Camera, &gt::Document::mCameras>,
+    &gt::Node::mCamera))
+  .Register(*js::MakeProperty("children", js::Read::Array<gt::Ref<gt::Node>, gt::RefReader<gt::Document>::Read<gt::Node, &gt::Document::mNodes>>,
+    &gt::Node::mChildren))
+  .Register(*js::MakeProperty("mesh", gt::RefReader<gt::Document>::Read<gt::Mesh, &gt::Document::mMeshes>, &gt::Node::mMesh))
+  .Register(*js::MakeProperty("skin", gt::RefReader<gt::Document>::Read<gt::Skin, &gt::Document::mSkins>, &gt::Node::mSkin))
+);
+
+const auto ANIMATION_SAMPLER_READER = std::move(js::Reader<gt::Animation::Sampler>()
+  .Register(*js::MakeProperty("input", gt::RefReader<gt::Document>::Read<gt::Accessor, &gt::Document::mAccessors>,
+    &gt::Animation::Sampler::mInput))
+  .Register(*js::MakeProperty("output", gt::RefReader<gt::Document>::Read<gt::Accessor, &gt::Document::mAccessors>,
+    &gt::Animation::Sampler::mOutput))
+  .Register(*js::MakeProperty("interpolation", gt::ReadStringEnum<gt::Animation::Sampler::Interpolation>, &gt::Animation::Sampler::mInterpolation))
+);
+
+const auto ANIMATION_TARGET_READER = std::move(js::Reader<gt::Animation::Channel::Target>()
+  .Register(*js::MakeProperty("node", gt::RefReader<gt::Document>::Read<gt::Node, &gt::Document::mNodes>,
+    &gt::Animation::Channel::Target::mNode))
+  .Register(*js::MakeProperty("path", gt::ReadStringEnum<gt::Animation::Channel::Target>,
+    &gt::Animation::Channel::Target::mPath))
+);
+
+const auto ANIMATION_CHANNEL_READER = std::move(js::Reader<gt::Animation::Channel>()
+  .Register(*js::MakeProperty("target", js::ObjectReader<gt::Animation::Channel::Target>::Read, &gt::Animation::Channel::mTarget))
+  .Register(*js::MakeProperty("sampler", gt::RefReader<gt::Animation>::Read<gt::Animation::Sampler, &gt::Animation::mSamplers>, &gt::Animation::Channel::mSampler))
+);
+
+const auto ANIMATION_READER = std::move(js::Reader<gt::Animation>()
+  .Register(*new js::Property<gt::Animation, std::string_view>("name", js::Read::StringView, &gt::Animation::mName))
+  .Register(*js::MakeProperty("samplers",
+    js::Read::Array<gt::Animation::Sampler, js::ObjectReader<gt::Animation::Sampler>::Read>, &gt::Animation::mSamplers))
+  .Register(*js::MakeProperty("channels",
+    js::Read::Array<gt::Animation::Channel, js::ObjectReader<gt::Animation::Channel>::Read>, &gt::Animation::mChannels))
+);
+
+const auto SCENE_READER = std::move(js::Reader<gt::Scene>()
+  .Register(*new js::Property<gt::Scene, std::string_view>("name", js::Read::StringView, &gt::Scene::mName))
+  .Register(*js::MakeProperty("nodes",
+    js::Read::Array<gt::Ref<gt::Node>, gt::RefReader<gt::Document>::Read<gt::Node, &gt::Document::mNodes>>, &gt::Scene::mNodes))
+);
+
+const auto DOCUMENT_READER = std::move(js::Reader<gt::Document>()
+  .Register(*js::MakeProperty("buffers",
+    js::Read::Array<gt::Buffer, js::ObjectReader<gt::Buffer>::Read>, &gt::Document::mBuffers))
+  .Register(*js::MakeProperty("bufferViews",
+    js::Read::Array<gt::BufferView, js::ObjectReader<gt::BufferView>::Read>, &gt::Document::mBufferViews))
+  .Register(*js::MakeProperty("accessors",
+    js::Read::Array<gt::Accessor, js::ObjectReader<gt::Accessor>::Read>, &gt::Document::mAccessors))
+  .Register(*js::MakeProperty("images",
+    js::Read::Array<gt::Image, js::ObjectReader<gt::Image>::Read>, &gt::Document::mImages))
+  .Register(*js::MakeProperty("samplers",
+    js::Read::Array<gt::Sampler, js::ObjectReader<gt::Sampler>::Read>, &gt::Document::mSamplers))
+  .Register(*js::MakeProperty("textures",
+    js::Read::Array<gt::Texture, js::ObjectReader<gt::Texture>::Read>, &gt::Document::mTextures))
+  .Register(*js::MakeProperty("materials",
+    js::Read::Array<gt::Material, js::ObjectReader<gt::Material>::Read>, &gt::Document::mMaterials))
+  .Register(*js::MakeProperty("meshes",
+    js::Read::Array<gt::Mesh, js::ObjectReader<gt::Mesh>::Read>, &gt::Document::mMeshes))
+  .Register(*js::MakeProperty("skins",
+    js::Read::Array<gt::Skin, js::ObjectReader<gt::Skin>::Read>, &gt::Document::mSkins))
+  .Register(*js::MakeProperty("cameras",
+    js::Read::Array<gt::Camera, js::ObjectReader<gt::Camera>::Read>, &gt::Document::mCameras))
+  .Register(*js::MakeProperty("nodes",
+    js::Read::Array<gt::Node, js::ObjectReader<gt::Node>::Read>, &gt::Document::mNodes))
+  .Register(*js::MakeProperty("animations",
+    ReadAnimationArray, &gt::Document::mAnimations))
+  .Register(*js::MakeProperty("scenes",
+    js::Read::Array<gt::Scene, js::ObjectReader<gt::Scene>::Read>, &gt::Document::mScenes))
+  .Register(*js::MakeProperty("scene", gt::RefReader<gt::Document>::Read<gt::Scene, &gt::Document::mScenes>, &gt::Document::mScene))
+);
+
+struct NodeMapping
+{
+  Index gltfIdx;
+  Index runtimeIdx;
+};
+
+bool operator<(const NodeMapping& mapping, Index gltfIdx)
+{
+  return mapping.gltfIdx < gltfIdx;
+}
+
+class NodeIndexMapper
+{
+public:
+  NodeIndexMapper() = default;
+  NodeIndexMapper(const NodeIndexMapper&) = delete;
+  NodeIndexMapper& operator=(const NodeIndexMapper&) = delete;
+
+  ///@brief Registers a mapping of the @a gltfIdx of a node to its @a runtimeIdx .
+  ///@note If the indices are the same, the registration is omitted, in order to
+  /// save growing a vector.
+  void RegisterMapping(Index gltfIdx, Index runtimeIdx)
+  {
+    if (gltfIdx != runtimeIdx)
+    {
+      auto iInsert = std::lower_bound(mNodes.begin(), mNodes.end(), gltfIdx);
+      DALI_ASSERT_DEBUG(iInsert == mNodes.end() || iInsert->gltfIdx != gltfIdx);
+      mNodes.insert(iInsert, NodeMapping{ gltfIdx, runtimeIdx });
+    }
+  }
+
+  ///@brief Retrieves the runtime index of a Node, mapped to the given @a gltfIdx.
+  Index GetRuntimeId(Index gltfIdx) const
+  {
+    auto iFind = std::lower_bound(mNodes.begin(), mNodes.end(), gltfIdx);  // using custom operator<
+    return (iFind != mNodes.end() && iFind->gltfIdx == gltfIdx) ? iFind->runtimeIdx : gltfIdx;
+  }
+
+private:
+  std::vector<NodeMapping> mNodes;
+};
+
+struct ConversionContext
+{
+  LoadResult&  mOutput;
+
+  std::string mPath;
+  Index mDefaultMaterial;
+
+  std::vector<Index>  mMeshIds;
+  NodeIndexMapper mNodeIndices;
+};
+
+SamplerFlags::Type ConvertWrapMode(gt::Wrap::Type w)
+{
+  switch (w)
+  {
+  case gt::Wrap::REPEAT:
+    return SamplerFlags::WRAP_REPEAT;
+  case gt::Wrap::CLAMP_TO_EDGE:
+    return SamplerFlags::WRAP_CLAMP;
+  case gt::Wrap::MIRRORED_REPEAT:
+    return SamplerFlags::WRAP_MIRROR;
+  default:
+    throw std::runtime_error("Invalid wrap type.");
+  }
+}
+
+SamplerFlags::Type ConvertSampler(const gt::Ref<gt::Sampler>& s)
+{
+  if (s)
+  {
+    return (s->mMinFilter < gt::Filter::NEAREST_MIPMAP_NEAREST) ? (s->mMinFilter - gt::Filter::NEAREST) :
+      ((s->mMinFilter - gt::Filter::NEAREST_MIPMAP_NEAREST) + 2) |
+      ((s->mMagFilter - gt::Filter::NEAREST) << SamplerFlags::FILTER_MAG_SHIFT) |
+      (ConvertWrapMode(s->mWrapS) << SamplerFlags::WRAP_S_SHIFT) |
+      (ConvertWrapMode(s->mWrapT) << SamplerFlags::WRAP_T_SHIFT);
+  }
+  else
+  {
+    // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#texturesampler
+    // "The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used."
+    // "What is an auto filtering", I hear you ask. Since there's nothing else to determine mipmapping from - including glTF image
+    // properties, if not in some extension -, we will simply assume linear filtering.
+    return SamplerFlags::FILTER_LINEAR | (SamplerFlags::FILTER_LINEAR << SamplerFlags::FILTER_MAG_SHIFT) |
+      (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_S_SHIFT) | (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_T_SHIFT);
+  }
+}
+
+TextureDefinition ConvertTextureInfo(const gt::TextureInfo& mm)
+{
+  return TextureDefinition{ std::string(mm.mTexture->mSource->mUri), ConvertSampler(mm.mTexture->mSampler) };
+}
+
+void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials)& outMaterials)
+{
+  MaterialDefinition matDef;
+
+  auto& pbr = m.mPbrMetallicRoughness;
+  if (m.mAlphaMode != gt::AlphaMode::OPAQUE || pbr.mBaseColorFactor.a < 1.f)
+  {
+    matDef.mFlags |= MaterialDefinition::TRANSPARENCY;
+  }
+
+  if (m.mAlphaMode == gt::AlphaMode::MASK)
+  {
+    matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, m.mAlphaCutoff)));
+  }
+
+  matDef.mColor = pbr.mBaseColorFactor;
+
+  matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture);
+  if (pbr.mBaseColorTexture)
+  {
+    const auto semantic = MaterialDefinition::ALBEDO;
+    matDef.mTextureStages.push_back({ semantic, ConvertTextureInfo(pbr.mBaseColorTexture) });
+    // TODO: and there had better be one
+    matDef.mFlags |= semantic;
+  }
+
+  matDef.mMetallic = pbr.mMetallicFactor;
+  matDef.mRoughness = pbr.mRoughnessFactor;
+
+  if (pbr.mMetallicRoughnessTexture)
+  {
+    const auto semantic = MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+      MaterialDefinition::GLTF_CHANNELS;
+    matDef.mTextureStages.push_back({ semantic, ConvertTextureInfo(pbr.mMetallicRoughnessTexture) });
+    // TODO: and there had better be one
+    matDef.mFlags |= semantic;
+  }
+
+  if (m.mNormalTexture)
+  {
+    const auto semantic = MaterialDefinition::NORMAL;
+    matDef.mTextureStages.push_back({ semantic, ConvertTextureInfo(m.mNormalTexture) });
+    // TODO: and there had better be one
+    matDef.mFlags |= semantic;
+  }
+
+  // TODO: handle doubleSided
+
+  outMaterials.emplace_back(std::move(matDef), TextureSet());
+}
+
+void ConvertMaterials(const gt::Document& doc, ConversionContext& cctx)
+{
+  auto& outMaterials = cctx.mOutput.mResources.mMaterials;
+  outMaterials.reserve(doc.mMaterials.size());
+
+  for (auto& m : doc.mMaterials)
+  {
+    ConvertMaterial(m, outMaterials);
+  }
+}
+
+MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gt::Accessor& acc)
+{
+  DALI_ASSERT_ALWAYS((acc.mBufferView &&
+    (acc.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) ||
+    (acc.mSparse && !acc.mBufferView));
+
+  DALI_ASSERT_ALWAYS(!acc.mSparse ||
+    ((acc.mSparse->mIndices.mBufferView && (acc.mSparse->mIndices.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) &&
+    (acc.mSparse->mValues.mBufferView && (acc.mSparse->mValues.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max()))));
+
+
+  MeshDefinition::SparseBlob sparseBlob;
+  if (acc.mSparse)
+  {
+    const gt::Accessor::Sparse& sparse = *acc.mSparse;
+    const gt::ComponentTypedBufferViewClient& indices = sparse.mIndices;
+    const gt::BufferViewClient& values = sparse.mValues;
+
+    MeshDefinition::Blob indicesBlob(
+      indices.mBufferView->mByteOffset + indices.mByteOffset,
+      sparse.mCount * indices.GetBytesPerComponent(),
+      static_cast<uint16_t>(indices.mBufferView->mByteStride),
+      static_cast<uint16_t>(indices.GetBytesPerComponent()),
+      {}, {}
+    );
+    MeshDefinition::Blob valuesBlob(
+      values.mBufferView->mByteOffset + values.mByteOffset,
+      sparse.mCount * acc.GetElementSizeBytes(),
+      static_cast<uint16_t>(values.mBufferView->mByteStride),
+      static_cast<uint16_t>(acc.GetElementSizeBytes()),
+      {}, {}
+    );
+
+    sparseBlob = std::move(MeshDefinition::SparseBlob(std::move(indicesBlob), std::move(valuesBlob), acc.mSparse->mCount));
+  }
+
+  uint32_t bufferViewOffset = 0u;
+  uint32_t bufferViewStride = 0u;
+  if (acc.mBufferView)
+  {
+    bufferViewOffset = acc.mBufferView->mByteOffset;
+    bufferViewStride = acc.mBufferView->mByteStride;
+  }
+
+  return MeshDefinition::Accessor{
+    std::move(MeshDefinition::Blob{bufferViewOffset + acc.mByteOffset,
+      acc.GetBytesLength(),
+      static_cast<uint16_t>(bufferViewStride),
+      static_cast<uint16_t>(acc.GetElementSizeBytes()),
+      acc.mMin,
+      acc.mMax}),
+    std::move(sparseBlob) };
+}
+
+void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx)
+{
+  uint32_t meshCount = 0;
+  cctx.mMeshIds.reserve(doc.mMeshes.size());
+  for (auto& m : doc.mMeshes)
+  {
+    cctx.mMeshIds.push_back(meshCount);
+    meshCount += m.mPrimitives.size();
+  }
+
+  auto& outMeshes = cctx.mOutput.mResources.mMeshes;
+  outMeshes.reserve(meshCount);
+  for (auto& m : doc.mMeshes)
+  {
+    for (auto& p : m.mPrimitives)
+    {
+      MeshDefinition meshDef;
+
+      auto& attribs = p.mAttributes;
+      meshDef.mUri = attribs.begin()->second->mBufferView->mBuffer->mUri;
+      meshDef.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[p.mMode];
+
+      auto& accPositions = *attribs.find(gt::Attribute::POSITION)->second;
+      meshDef.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
+
+      const bool needNormalsTangents = accPositions.mType == gt::AccessorType::VEC3;
+      for (auto& am : ATTRIBUTE_MAPPINGS)
+      {
+        auto iFind = attribs.find(am.mType);
+        if (iFind != attribs.end())
+        {
+          DALI_ASSERT_DEBUG(iFind->second->mBufferView->mBuffer->mUri.compare(meshDef.mUri) == 0);
+          auto& accessor = meshDef.*(am.mAccessor);
+          accessor = ConvertMeshPrimitiveAccessor(*iFind->second);
+
+          // Fixing up -- a few of glTF2 sample models have VEC4 tangents; we need VEC3s.
+          if (iFind->first == gt::Attribute::TANGENT && (accessor.mBlob.mElementSizeHint > am.mElementSizeRequired))
+          {
+            accessor.mBlob.mStride = std::max(static_cast<uint16_t>(accessor.mBlob.mStride + accessor.mBlob.mElementSizeHint - am.mElementSizeRequired),
+              accessor.mBlob.mElementSizeHint);
+            accessor.mBlob.mElementSizeHint = am.mElementSizeRequired;
+          }
+
+          if (iFind->first == gt::Attribute::JOINTS_0)
+          {
+            meshDef.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
+            DALI_ASSERT_DEBUG(MaskMatch(meshDef.mFlags, MeshDefinition::U16_JOINT_IDS) || iFind->second->mComponentType == gt::Component::FLOAT);
+          }
+        }
+        else if (needNormalsTangents)
+        {
+          switch (am.mType)
+          {
+          case gt::Attribute::NORMAL:
+            meshDef.RequestNormals();
+            break;
+
+          case gt::Attribute::TANGENT:
+            meshDef.RequestTangents();
+            break;
+
+          default:
+            break;
+          }
+        }
+      }
+
+      if (p.mIndices)
+      {
+        meshDef.mIndices = ConvertMeshPrimitiveAccessor(*p.mIndices);
+        meshDef.mFlags |= (p.mIndices->mComponentType == gt::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES;
+        DALI_ASSERT_DEBUG(MaskMatch(meshDef.mFlags, MeshDefinition::U32_INDICES) || p.mIndices->mComponentType == gt::Component::UNSIGNED_SHORT);
+      }
+
+      if (!p.mTargets.empty())
+      {
+        meshDef.mBlendShapes.reserve(p.mTargets.size());
+        meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+        for (const auto& target : p.mTargets)
+        {
+          MeshDefinition::BlendShape blendShape;
+
+          auto endIt = target.end();
+          auto it = target.find(gt::Attribute::POSITION);
+          if (it != endIt)
+          {
+            blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
+          }
+          it = target.find(gt::Attribute::NORMAL);
+          if (it != endIt)
+          {
+            blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
+          }
+          it = target.find(gt::Attribute::TANGENT);
+          if (it != endIt)
+          {
+            blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
+          }
+
+          if (!m.mWeights.empty())
+          {
+            blendShape.weight = m.mWeights[meshDef.mBlendShapes.size()];
+          }
+
+          meshDef.mBlendShapes.push_back(std::move(blendShape));
+        }
+      }
+
+      outMeshes.push_back({ std::move(meshDef), MeshGeometry{} });
+    }
+  }
+}
+
+ModelNode* MakeModelNode(const gt::Mesh::Primitive& prim, ConversionContext& cctx)
+{
+  auto modelNode = new ModelNode();
+
+  modelNode->mShaderIdx = 0;  // TODO: further thought
+
+  auto materialIdx = prim.mMaterial.GetIndex();
+  if (INVALID_INDEX == materialIdx)
+  {
+    // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material
+    if (INVALID_INDEX == cctx.mDefaultMaterial)
+    {
+      auto& outMaterials = cctx.mOutput.mResources.mMaterials;
+      cctx.mDefaultMaterial = outMaterials.size();
+
+      ConvertMaterial(gt::Material{}, outMaterials);
+    }
+
+    materialIdx = cctx.mDefaultMaterial;
+  }
+
+  modelNode->mMaterialIdx = materialIdx;
+
+  return modelNode;
+}
+
+void ConvertCamera(const gt::Camera& camera, CameraParameters& camParams)
+{
+  camParams.isPerspective = camera.mType.compare("perspective") == 0;
+  if (camParams.isPerspective)
+  {
+    auto& perspective = camera.mPerspective;
+    camParams.yFov = Degree(Radian(perspective.mYFov)).degree;
+    camParams.zNear = perspective.mZNear;
+    camParams.zFar = perspective.mZFar;
+    // TODO: yes, we seem to ignore aspectRatio in CameraParameters.
+  }
+  else
+  {
+    auto& ortho = camera.mOrthographic;
+    camParams.orthographicSize = Vector4(-ortho.mXMag, ortho.mXMag, ortho.mYMag, -ortho.mYMag) * .5f;
+    camParams.zNear = ortho.mZNear;
+    camParams.zFar = ortho.mZFar;
+  }
+}
+
+void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& cctx)
+{
+  auto& output = cctx.mOutput;
+  auto& scene = output.mScene;
+  auto& resources = output.mResources;
+
+  const auto idx = scene.GetNodeCount();
+  auto weakNode = scene.AddNode([&]() {
+    std::unique_ptr<NodeDefinition> nodeDef{ new NodeDefinition() };
+
+    nodeDef->mParentIdx = parentIdx;
+    nodeDef->mName = node.mName;
+    if (nodeDef->mName.empty())
+    {
+      // TODO: Production quality generation of unique names.
+      nodeDef->mName = std::to_string(reinterpret_cast<uintptr_t>(nodeDef.get()));
+    }
+
+    if (!node.mSkin)  // Nodes with skinned meshes are not supposed to have local transforms.
+    {
+      nodeDef->mPosition = node.mTranslation;
+      nodeDef->mOrientation = node.mRotation;
+      nodeDef->mScale = node.mScale;
+    }
+
+    return nodeDef;
+  }());
+  if (!weakNode)
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Node name '" << node.mName << "' is not unique; scene is invalid.";
+  }
+
+  cctx.mNodeIndices.RegisterMapping(gltfIdx, idx);
+
+  Index skeletonIdx = node.mSkin ? node.mSkin.GetIndex() : INVALID_INDEX;
+  if (node.mMesh && !node.mMesh->mPrimitives.empty())
+  {
+    auto& mesh = *node.mMesh;
+
+    auto iPrim = mesh.mPrimitives.begin();
+    auto modelNode = MakeModelNode(*iPrim, cctx);
+    auto meshIdx = cctx.mMeshIds[node.mMesh.GetIndex()];
+    modelNode->mMeshIdx = meshIdx;
+
+    weakNode->mRenderable.reset(modelNode);
+
+    DALI_ASSERT_DEBUG(resources.mMeshes[meshIdx].first.mSkeletonIdx == INVALID_INDEX ||
+      resources.mMeshes[meshIdx].first.mSkeletonIdx == skeletonIdx);
+    resources.mMeshes[meshIdx].first.mSkeletonIdx = skeletonIdx;
+
+    // As does model-exporter, we'll create anonymous child nodes for additional mesh( primitiv)es.
+    while (++iPrim != mesh.mPrimitives.end())
+    {
+      std::unique_ptr<NodeDefinition> child{ new NodeDefinition };
+      child->mParentIdx = idx;
+
+      auto childModel = MakeModelNode(*iPrim, cctx);
+
+      ++meshIdx;
+      childModel->mMeshIdx = meshIdx;
+
+      child->mRenderable.reset(childModel);
+
+      scene.AddNode(std::move(child));
+
+      DALI_ASSERT_DEBUG(resources.mMeshes[meshIdx].first.mSkeletonIdx == INVALID_INDEX ||
+        resources.mMeshes[meshIdx].first.mSkeletonIdx == skeletonIdx);
+      resources.mMeshes[meshIdx].first.mSkeletonIdx = skeletonIdx;
+    }
+  }
+
+  if (node.mCamera)
+  {
+    CameraParameters camParams;
+    ConvertCamera(*node.mCamera, camParams);
+
+    camParams.matrix.SetTransformComponents(node.mScale, node.mRotation, node.mTranslation);
+    output.mCameraParameters.push_back(camParams);
+  }
+
+  for (auto& n : node.mChildren)
+  {
+    ConvertNode(*n, n.GetIndex(), idx, cctx);
+  }
+}
+
+void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx)
+{
+  auto& outScene = cctx.mOutput.mScene;
+  Index rootIdx = outScene.GetNodeCount();
+  switch (scene.mNodes.size())
+  {
+  case 0:
+    break;
+
+  case 1:
+    ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, cctx);
+    outScene.AddRootNode(rootIdx);
+    break;
+
+  default:
+    {
+      std::unique_ptr<NodeDefinition> sceneRoot{ new NodeDefinition() };
+      sceneRoot->mName = "GLTF_LOADER_SCENE_ROOT_" + std::to_string(outScene.GetRoots().size());
+
+      outScene.AddNode(std::move(sceneRoot));
+      outScene.AddRootNode(rootIdx);
+
+      for (auto& n : scene.mNodes)
+      {
+        ConvertNode(*n, n.GetIndex(), rootIdx, cctx);
+      }
+      break;
+    }
+  }
+}
+
+void ConvertNodes(const gt::Document& doc, ConversionContext& cctx)
+{
+  ConvertSceneNodes(*doc.mScene, cctx);
+
+  for (uint32_t i = 0, i1 = doc.mScene.GetIndex(); i < i1; ++i)
+  {
+    ConvertSceneNodes(doc.mScenes[i], cctx);
+  }
+
+  for (uint32_t i = doc.mScene.GetIndex() + 1; i < doc.mScenes.size(); ++i)
+  {
+    ConvertSceneNodes(doc.mScenes[i], cctx);
+  }
+}
+
+template <typename T>
+void LoadDataFromAccessor(const std::string& path, Vector<T>& dataBuffer, uint32_t offset, uint32_t size)
+{
+  std::ifstream animationBinaryFile(path, std::ifstream::binary);
+
+  if (!animationBinaryFile.is_open())
+  {
+    throw std::runtime_error("Failed to load " + path);
+  }
+
+  animationBinaryFile.seekg(offset);
+  animationBinaryFile.read(reinterpret_cast<char*>(dataBuffer.Begin()), size);
+  animationBinaryFile.close();
+}
+
+template <typename T>
+float LoadDataFromAccessors(const std::string& path, const gltf2::Accessor& input, const gltf2::Accessor& output, Vector<float>& inputDataBuffer, Vector<T>& outputDataBuffer)
+{
+  inputDataBuffer.Resize(input.mCount);
+  outputDataBuffer.Resize(output.mCount);
+
+  const uint32_t inputDataBufferSize = input.GetBytesLength();
+  const uint32_t outputDataBufferSize = output.GetBytesLength();
+
+  LoadDataFromAccessor<float>(path + std::string(input.mBufferView->mBuffer->mUri), inputDataBuffer,
+    input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize);
+  LoadDataFromAccessor<T>(path + std::string(output.mBufferView->mBuffer->mUri), outputDataBuffer,
+    output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize);
+  ApplyAccessorMinMax(output, reinterpret_cast<float*>(outputDataBuffer.begin()));
+
+  return inputDataBuffer[input.mCount - 1u];
+}
+
+template<typename T>
+float LoadKeyFrames(const std::string& path, const gt::Animation::Channel& channel, KeyFrames& keyFrames, gt::Animation::Channel::Target::Type type)
+{
+  const gltf2::Accessor& input = *channel.mSampler->mInput;
+  const gltf2::Accessor& output = *channel.mSampler->mOutput;
+
+  Vector<float> inputDataBuffer;
+  Vector<T> outputDataBuffer;
+
+  const float duration = LoadDataFromAccessors<T>(path, input, output, inputDataBuffer, outputDataBuffer);
+
+  for (uint32_t i = 0; i < input.mCount; ++i)
+  {
+    keyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i]);
+  }
+
+  return duration;
+}
+
+float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Channel& channel, const std::string& nodeName, uint32_t& propertyIndex, std::vector<SceneLoader::AnimatedProperty>& properties)
+{
+  const gltf2::Accessor& input = *channel.mSampler->mInput;
+  const gltf2::Accessor& output = *channel.mSampler->mOutput;
+
+  Vector<float> inputDataBuffer;
+  Vector<float> outputDataBuffer;
+
+  const float duration = LoadDataFromAccessors<float>(path, input, output, inputDataBuffer, outputDataBuffer);
+
+  char weightNameBuffer[32];
+  char* const pWeightName = weightNameBuffer + sprintf(weightNameBuffer, "%s[", BLEND_SHAPE_WEIGHTS_UNIFORM.c_str());
+  for (uint32_t weightIndex = 0u, endWeightIndex = channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount; weightIndex < endWeightIndex; ++weightIndex)
+  {
+    AnimatedProperty& animatedProperty = properties[propertyIndex++];
+
+    animatedProperty.mNodeName = nodeName;
+    sprintf(pWeightName, "%d]", weightIndex);
+    animatedProperty.mPropertyName = std::string(weightNameBuffer);
+
+    animatedProperty.mKeyFrames = KeyFrames::New();
+    for (uint32_t i = 0; i < input.mCount; ++i)
+    {
+      animatedProperty.mKeyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i*endWeightIndex + weightIndex]);
+    }
+
+    animatedProperty.mTimePeriod = { 0.f, duration };
+  }
+
+  return duration;
+}
+
+void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
+{
+  auto& output = cctx.mOutput;
+
+  output.mAnimationDefinitions.reserve(output.mAnimationDefinitions.size() + doc.mAnimations.size());
+
+  for (const auto& animation : doc.mAnimations)
+  {
+    AnimationDefinition animationDef;
+
+    if (!animation.mName.empty())
+    {
+      animationDef.mName = animation.mName;
+    }
+
+    uint32_t numberOfProperties = 0u;
+
+    for (const auto& channel : animation.mChannels)
+    {
+      numberOfProperties += channel.mSampler->mOutput->mCount;
+    }
+    animationDef.mProperties.resize(numberOfProperties);
+
+    Index propertyIndex = 0u;
+    for (const auto& channel : animation.mChannels)
+    {
+      std::string nodeName;
+      if (!channel.mTarget.mNode->mName.empty())
+      {
+        nodeName = channel.mTarget.mNode->mName;
+      }
+      else
+      {
+        Index index = cctx.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
+        nodeName = cctx.mOutput.mScene.GetNode(index)->mName;
+      }
+
+      float duration = 0.f;
+
+      switch (channel.mTarget.mPath)
+      {
+        case gt::Animation::Channel::Target::TRANSLATION:
+        {
+          AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex];
+
+          animatedProperty.mNodeName = nodeName;
+          animatedProperty.mPropertyName = POSITION_PROPERTY;
+
+          animatedProperty.mKeyFrames = KeyFrames::New();
+          duration = LoadKeyFrames<Vector3>(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
+
+          animatedProperty.mTimePeriod = { 0.f, duration };
+          break;
+        }
+        case gt::Animation::Channel::Target::ROTATION:
+        {
+          AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex];
+
+          animatedProperty.mNodeName = nodeName;
+          animatedProperty.mPropertyName = ORIENTATION_PROPERTY;
+
+          animatedProperty.mKeyFrames = KeyFrames::New();
+          duration = LoadKeyFrames<Quaternion>(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
+
+          animatedProperty.mTimePeriod = { 0.f, duration };
+          break;
+        }
+        case gt::Animation::Channel::Target::SCALE:
+        {
+          AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex];
+
+          animatedProperty.mNodeName = nodeName;
+          animatedProperty.mPropertyName = SCALE_PROPERTY;
+
+          animatedProperty.mKeyFrames = KeyFrames::New();
+          duration = LoadKeyFrames<Vector3>(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
+
+          animatedProperty.mTimePeriod = { 0.f, duration };
+          break;
+        }
+        case gt::Animation::Channel::Target::WEIGHTS:
+        {
+          duration = LoadBlendShapeKeyFrames(cctx.mPath, channel, nodeName, propertyIndex, animationDef.mProperties);
+
+          break;
+        }
+        default:
+        {
+          // nothing to animate.
+          break;
+        }
+      }
+
+      animationDef.mDuration = std::max(duration, animationDef.mDuration);
+
+      ++propertyIndex;
+    }
+
+    output.mAnimationDefinitions.push_back(std::move(animationDef));
+  }
+}
+
+void ProcessSkins(const gt::Document& doc, ConversionContext& cctx)
+{
+  // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skininversebindmatrices
+  // If an inverseBindMatrices accessor was provided, we'll load the joint data from the buffer,
+  // otherwise we'll set identity matrices for inverse bind pose.
+  struct IInverseBindMatrixProvider
+  {
+    virtual ~IInverseBindMatrixProvider() {}
+    virtual void Provide(Matrix& ibm) = 0;
+  };
+
+  struct InverseBindMatrixAccessor : public IInverseBindMatrixProvider
+  {
+    std::ifstream mStream;
+    const uint32_t mElementSizeBytes;
+
+    InverseBindMatrixAccessor(const gt::Accessor& accessor, const std::string& path)
+    : mStream(path + std::string(accessor.mBufferView->mBuffer->mUri), std::ios::binary),
+      mElementSizeBytes(accessor.GetElementSizeBytes())
+    {
+      DALI_ASSERT_ALWAYS(mStream);
+      DALI_ASSERT_DEBUG(accessor.mType == gt::AccessorType::MAT4 && accessor.mComponentType == gt::Component::FLOAT);
+
+      mStream.seekg(accessor.mBufferView->mByteOffset + accessor.mByteOffset);
+    }
+
+    virtual void Provide(Matrix& ibm) override
+    {
+      DALI_ASSERT_ALWAYS(mStream.read(reinterpret_cast<char*>(ibm.AsFloat()), mElementSizeBytes));
+    }
+  };
+
+  struct DefaultInverseBindMatrixProvider : public IInverseBindMatrixProvider
+  {
+    virtual void Provide(Matrix& ibm) override
+    {
+      ibm = Matrix::IDENTITY;
+    }
+  };
+
+  auto& resources = cctx.mOutput.mResources;
+  resources.mSkeletons.reserve(doc.mSkins.size());
+
+  for (auto& s : doc.mSkins)
+  {
+    std::unique_ptr<IInverseBindMatrixProvider> ibmProvider;
+    if (s.mInverseBindMatrices)
+    {
+      ibmProvider.reset(new InverseBindMatrixAccessor(*s.mInverseBindMatrices, cctx.mPath));
+    }
+    else
+    {
+      ibmProvider.reset(new DefaultInverseBindMatrixProvider());
+    }
+
+    SkeletonDefinition skeleton;
+    if (s.mSkeleton.GetIndex() != INVALID_INDEX)
+    {
+      skeleton.mRootNodeIdx = cctx.mNodeIndices.GetRuntimeId(s.mSkeleton.GetIndex());
+    }
+
+    skeleton.mJoints.resize(s.mJoints.size());
+    auto iJoint = skeleton.mJoints.begin();
+    for (auto& j : s.mJoints)
+    {
+      iJoint->mNodeIdx = cctx.mNodeIndices.GetRuntimeId(j.GetIndex());
+
+      ibmProvider->Provide(iJoint->mInverseBindMatrix);
+
+      ++iJoint;
+    }
+
+    resources.mSkeletons.push_back(std::move(skeleton));
+  }
+}
+
+void ProduceShaders(ShaderDefinitionFactory& shaderFactory, SceneDefinition& scene)
+{
+  for (size_t i0 = 0, i1 = scene.GetNodeCount(); i0 != i1; ++i0)
+  {
+    auto nodeDef = scene.GetNode(i0);
+    if (auto renderable = nodeDef->mRenderable.get())
+    {
+      renderable->mShaderIdx = shaderFactory.ProduceShader(*nodeDef);
+    }
+  }
+}
+
+void SetObjectReaders()
+{
+  js::SetObjectReader(BUFFER_READER);
+  js::SetObjectReader(BUFFER_VIEW_READER);
+  js::SetObjectReader(BUFFER_VIEW_CLIENT_READER);
+  js::SetObjectReader(COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER);
+  js::SetObjectReader(ACCESSOR_SPARSE_READER);
+  js::SetObjectReader(ACCESSOR_READER);
+  js::SetObjectReader(IMAGE_READER);
+  js::SetObjectReader(SAMPLER_READER);
+  js::SetObjectReader(TEXURE_READER);
+  js::SetObjectReader(TEXURE_INFO_READER);
+  js::SetObjectReader(MATERIAL_PBR_READER);
+  js::SetObjectReader(MATERIAL_READER);
+  js::SetObjectReader(MESH_PRIMITIVE_READER);
+  js::SetObjectReader(MESH_READER);
+  js::SetObjectReader(SKIN_READER);
+  js::SetObjectReader(CAMERA_PERSPECTIVE_READER);
+  js::SetObjectReader(CAMERA_ORTHOGRAPHIC_READER);
+  js::SetObjectReader(CAMERA_READER);
+  js::SetObjectReader(NODE_READER);
+  js::SetObjectReader(ANIMATION_SAMPLER_READER);
+  js::SetObjectReader(ANIMATION_TARGET_READER);
+  js::SetObjectReader(ANIMATION_CHANNEL_READER);
+  js::SetObjectReader(ANIMATION_READER);
+  js::SetObjectReader(SCENE_READER);
+}
+
+}  // nonamespace
+
+void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactory, LoadResult& params)
+{
+  bool failed = false;
+  auto js = LoadTextFile(url.c_str(), &failed);
+  if (failed)
+  {
+    throw std::runtime_error("Failed to load " + url);
+  }
+
+  json::unique_ptr root(json_parse(js.c_str(), js.size()));
+  if (!root)
+  {
+    throw std::runtime_error("Failed to parse " + url);
+  }
+
+  static bool setObjectReaders = true;
+  if (setObjectReaders)
+  {
+    // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.
+    SetObjectReaders();
+    setObjectReaders = false;
+  }
+
+  gt::Document doc;
+
+  auto& rootObj = js::Cast<json_object_s>(*root);
+  auto jsAsset = js::FindObjectChild("asset", rootObj);
+  auto jsAssetVersion = js::FindObjectChild("version", js::Cast<json_object_s>(*jsAsset));
+  doc.mAsset.mVersion = js::Read::StringView(*jsAssetVersion);
+
+  gt::SetRefReaderObject(doc);
+  DOCUMENT_READER.Read(rootObj, doc);
+
+  auto path = url.substr(0, url.rfind('/') + 1);
+  ConversionContext cctx{ params, path, INVALID_INDEX };
+
+  ConvertMaterials(doc, cctx);
+  ConvertMeshes(doc, cctx);
+  ConvertNodes(doc, cctx);
+  ConvertAnimations(doc, cctx);
+
+  ProcessSkins(doc, cctx);
+
+  ProduceShaders(shaderFactory, params.mScene);
+  params.mScene.EnsureUniqueSkinningShaderInstances(params.mResources);
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/gltf2-loader.h b/dali-scene-loader/public-api/gltf2-loader.h
new file mode 100644 (file)
index 0000000..ce3ec79
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_SCENE_LOADER_GLTF2_LOADER_H
+#define DALI_SCENE_LOADER_GLTF2_LOADER_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+ // INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+struct CameraParameters;
+struct LoadResult;
+class ShaderDefinitionFactory;
+
+/**
+ * @brief Loads the scene from the glTF file located at @a url, storing the results in @a params.
+ * @note Will throw std::runtime_error for JSON entities with types mismatching expectations, carrying
+ *  invalid values, or I/O errors.
+ */
+DALI_SCENE_LOADER_API void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactory, LoadResult& params);
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_GLTF2_LOADER_H
diff --git a/dali-scene-loader/public-api/index.h b/dali-scene-loader/public-api/index.h
new file mode 100644 (file)
index 0000000..278f19a
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef DALI_SCENE_LOADER_INDEX_H_
+#define DALI_SCENE_LOADER_INDEX_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include <cstdint>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+using Index = uint32_t;
+
+constexpr Index INVALID_INDEX = static_cast<Index>(-1);
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_INDEX_H_
diff --git a/dali-scene-loader/public-api/ktx-loader.cpp b/dali-scene-loader/public-api/ktx-loader.cpp
new file mode 100644 (file)
index 0000000..839c03c
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+ // FILE HEADER
+#include "dali-scene-loader/public-api/ktx-loader.h"
+
+ // EXTERNAL INCLUDES
+#include "dali/public-api/rendering/texture.h"
+#include <fstream>
+#include <memory>
+
+namespace Dali
+{
+
+namespace
+{
+
+// http://github.khronos.org/KTX-Specification/
+const uint8_t KTX_ID_HEAD[] = { 0xAB, 0x4B, 0x54, 0x58, 0x20 };
+const uint8_t KTX_ID_TAIL[] = { 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
+
+const uint8_t KTX_VERSION_1_1[] = { 0x31, 0x31 };
+const uint8_t KTX_VERSION_2_0[] = { 0x32, 0x30 };
+
+static_assert(sizeof(KTX_ID_HEAD) + sizeof(KTX_ID_TAIL) == 10);
+static_assert(sizeof(KTX_VERSION_1_1) == 2);
+static_assert(sizeof(KTX_VERSION_2_0) == sizeof(KTX_VERSION_1_1));
+
+void FreeBuffer(uint8_t* buffer)
+{
+  delete[] buffer;
+}
+} // namespace
+
+namespace SceneLoader
+{
+struct KtxFileHeader
+{
+  uint8_t   identifier[12];
+  uint32_t  endianness;
+  uint32_t  glType;    //(UNSIGNED_BYTE, UNSIGNED_SHORT_5_6_5, etc.)
+  uint32_t  glTypeSize;
+  uint32_t  glFormat;  //(RGB, RGBA, BGRA, etc.)
+  uint32_t  glInternalFormat; //For uncompressed textures, specifies the internalformat parameter passed to glTexStorage*D or glTexImage*D
+  uint32_t  glBaseInternalFormat;
+  uint32_t  pixelWidth;
+  uint32_t  pixelHeight;
+  uint32_t  pixelDepth;
+  uint32_t  numberOfArrayElements;
+  uint32_t  numberOfFaces; //Cube map faces are stored in the order: +X, -X, +Y, -Y, +Z, -Z.
+  uint32_t  numberOfMipmapLevels;
+  uint32_t  bytesOfKeyValueData;
+
+  bool IsIdentifierValid() const
+  {
+    return std::equal(KTX_ID_HEAD, std::end(KTX_ID_HEAD), identifier) &&
+      (std::equal(KTX_VERSION_1_1, std::end(KTX_VERSION_1_1), identifier + sizeof(KTX_ID_HEAD)) ||
+        std::equal(KTX_VERSION_2_0, std::end(KTX_VERSION_2_0), identifier + sizeof(KTX_ID_HEAD))) &&
+      std::equal(KTX_ID_TAIL, std::end(KTX_ID_TAIL), identifier + (sizeof(KTX_ID_HEAD) + sizeof(KTX_VERSION_1_1)));
+  }
+};
+
+/**
+ * Convert KTX format to Pixel::Format
+ */
+bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Pixel::Format& format)
+{
+  switch (ktxPixelFormat)
+  {
+  case 0x93B0: // GL_COMPRESSED_RGBA_ASTC_4x4
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR;
+    break;
+  }
+  case 0x93B1: // GL_COMPRESSED_RGBA_ASTC_5x4
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR;
+    break;
+  }
+  case 0x93B2: // GL_COMPRESSED_RGBA_ASTC_5x5
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR;
+    break;
+  }
+  case 0x93B3: // GL_COMPRESSED_RGBA_ASTC_6x5
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR;
+    break;
+  }
+  case 0x93B4: // GL_COMPRESSED_RGBA_ASTC_6x6
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR;
+    break;
+  }
+  case 0x93B5: // GL_COMPRESSED_RGBA_ASTC_8x5
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR;
+    break;
+  }
+  case 0x93B6: // GL_COMPRESSED_RGBA_ASTC_8x6
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR;
+    break;
+  }
+  case 0x93B7: // GL_COMPRESSED_RGBA_ASTC_8x8
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR;
+    break;
+  }
+  case 0x93B8: // GL_COMPRESSED_RGBA_ASTC_10x5
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR;
+    break;
+  }
+  case 0x93B9: // GL_COMPRESSED_RGBA_ASTC_10x6
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR;
+    break;
+  }
+  case 0x93BA: // GL_COMPRESSED_RGBA_ASTC_10x8
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR;
+    break;
+  }
+  case 0x93BB: // GL_COMPRESSED_RGBA_ASTC_10x10
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR;
+    break;
+  }
+  case 0x93BC: // GL_COMPRESSED_RGBA_ASTC_12x10
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR;
+    break;
+  }
+  case 0x93BD: // GL_COMPRESSED_RGBA_ASTC_12x12
+  {
+    format = Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR;
+    break;
+  }
+  case 0x881B: // GL_RGB16F
+  {
+    format = Pixel::RGB16F;
+    break;
+  }
+  case 0x8815: // GL_RGB32F
+  {
+    format = Pixel::RGB32F;
+    break;
+  }
+  case 0x8C3A: // GL_R11F_G11F_B10F
+  {
+    format = Pixel::RGB32F;
+    break;
+  }
+  case 0x8D7C: // GL_RGBA8UI
+  {
+    format = Pixel::RGBA8888;
+    break;
+  }
+  case 0x8D7D: // GL_RGB8UI
+  {
+    format = Pixel::RGB888;
+    break;
+  }
+  default:
+  {
+    return false;
+  }
+  }
+
+  return true;
+}
+
+Texture CubeData::CreateTexture() const
+{
+  Texture texture = Texture::New(TextureType::TEXTURE_CUBE, data[0][0].GetPixelFormat(),
+    data[0][0].GetWidth(), data[0][0].GetHeight());
+  for (size_t iSide = 0u, iEndSize = data.size(); iSide < iEndSize; ++iSide)
+  {
+    auto& side = data[iSide];
+    for (size_t iMipLevel = 0u, iEndMipLevel = data[0].size(); iMipLevel < iEndMipLevel; ++iMipLevel)
+    {
+      texture.Upload(side[iMipLevel], CubeMapLayer::POSITIVE_X + iSide, iMipLevel,
+        0u, 0u, side[iMipLevel].GetWidth(), side[iMipLevel].GetHeight());
+    }
+  }
+
+  return texture;
+}
+
+bool LoadCubeMapData(const std::string& path, CubeData& cubedata)
+{
+  std::fstream fp(path, std::ios::in | std::ios::binary);
+  if (fp.is_open() == false)
+  {
+    return false;
+  }
+
+  KtxFileHeader header;
+  if (fp.read(reinterpret_cast<char*>(&header), sizeof(KtxFileHeader)).good() == false)
+  {
+    return false;
+  }
+
+  if (!header.IsIdentifierValid())
+  {
+    return false;
+  }
+
+  // Skip the key-values:
+  if (fp.seekg(header.bytesOfKeyValueData, fp.cur).good() == false)
+  {
+    return false;
+  }
+
+  header.numberOfMipmapLevels = std::max(header.numberOfMipmapLevels, 1u);
+  header.numberOfArrayElements = std::max(header.numberOfArrayElements, 1u);
+  header.pixelDepth = std::max(header.pixelDepth, 1u);
+  header.pixelHeight = std::max(header.pixelHeight, 1u);
+
+  cubedata.data.resize(header.numberOfFaces);
+  for (uint32_t face = 0u; face < header.numberOfFaces; ++face)
+  {
+    cubedata.data[face].resize(header.numberOfMipmapLevels);
+  }
+
+  Pixel::Format daliformat = Pixel::RGB888;
+
+  ConvertPixelFormat(header.glInternalFormat, daliformat);
+
+  for (uint32_t mipmapLevel = 0u; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel)
+  {
+    uint32_t byteSize = 0u;
+    if (fp.read(reinterpret_cast<char*>(&byteSize), sizeof(byteSize)).good() == false)
+    {
+      return false;
+    }
+
+    if (0u != byteSize % 4u)
+    {
+      byteSize += 4u - byteSize % 4u;
+    }
+
+    for (uint32_t arrayElement = 0u; arrayElement < header.numberOfArrayElements; ++arrayElement) //arrayElement must be 0 or 1
+    {
+      for (uint32_t face = 0u; face < header.numberOfFaces; ++face)
+      {
+        std::unique_ptr<uint8_t, void(*)(uint8_t*)>img(new uint8_t[byteSize], FreeBuffer);
+        if (fp.read(reinterpret_cast<char*>(img.get()), byteSize).good() == false)
+        {
+          return false;
+        }
+        cubedata.data[face][mipmapLevel] = PixelData::New(img.release(), byteSize, header.pixelWidth, header.pixelHeight, daliformat, PixelData::DELETE_ARRAY);
+      }
+    }
+
+    header.pixelHeight /= 2u;
+    header.pixelWidth /= 2u;
+  }
+
+  return true;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/ktx-loader.h b/dali-scene-loader/public-api/ktx-loader.h
new file mode 100644 (file)
index 0000000..6167fef
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_SCENE_LOADER_KTX_LOADER_H
+#define DALI_SCENE_LOADER_KTX_LOADER_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/public-api/images/pixel-data.h"
+#include "dali/public-api/rendering/texture.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Stores the pixel data objects for each face of the cube texture and their mipmaps.
+ */
+struct DALI_SCENE_LOADER_API CubeData
+{
+  std::vector< std::vector<PixelData> > data;
+
+  Texture CreateTexture() const;
+};
+
+/**
+ * @brief Loads cube map data texture from a ktx file.
+ *
+ * @param[in] path The file path.
+ * @param[out] cubedata The data structure with all pixel data objects.
+ */
+DALI_SCENE_LOADER_API bool LoadCubeMapData(const std::string& path, CubeData& cubedata);
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_KTX_LOADER_H
diff --git a/dali-scene-loader/public-api/light-parameters.h b/dali-scene-loader/public-api/light-parameters.h
new file mode 100644 (file)
index 0000000..0d8d514
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_SCENE_LOADER_LIGHT_PARAMETERS_H
+#define DALI_SCENE_LOADER_LIGHT_PARAMETERS_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/matrix.h"
+#include "dali/public-api/math/vector3.h"
+#include <stdint.h>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+struct DALI_SCENE_LOADER_API LightParameters
+{
+  Matrix transform;
+
+  Vector3 color;
+  float intensity;
+  float shadowIntensity;
+  uint32_t shadowMapSize;
+  float orthographicSize;
+};
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_LIGHT_PARAMETERS_H
diff --git a/dali-scene-loader/public-api/load-result.h b/dali-scene-loader/public-api/load-result.h
new file mode 100644 (file)
index 0000000..ca05bfd
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_SCENE_LOADER_OUTPUT_H
+#define DALI_SCENE_LOADER_OUTPUT_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/animation-definition.h"
+#include "dali-scene-loader/public-api/light-parameters.h"
+#include "dali-scene-loader/public-api/camera-parameters.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+class ResourceBundle;
+class SceneDefinition;
+
+/**
+ * @brief The outputs from loading and processing a scene.
+ */
+struct DALI_SCENE_LOADER_API LoadResult
+{
+  /**
+   * @brief The bundle to store resources in.
+   */
+  ResourceBundle& mResources;
+
+  /**
+   * @brief The scene definition to populate.
+   */
+  SceneDefinition& mScene;
+
+  /**
+   * @brief The list of animation definitions, in lexicographical order of their names.
+   */
+  std::vector<AnimationDefinition>& mAnimationDefinitions;
+
+  /**
+   * @brief The list of animation group definitions, in lexicographical order of their names.
+   */
+  std::vector<AnimationGroupDefinition>& mAnimationGroupDefinitions;
+
+  /**
+   * @brief The camera parameters that were loaded from the scene.
+   */
+  std::vector<CameraParameters>& mCameraParameters;
+
+  /**
+   * @brief The light parameters that were loaded from the scene.
+   */
+  std::vector<LightParameters>& mLightParameters;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_OUTPUT_H
diff --git a/dali-scene-loader/public-api/material-definition.cpp b/dali-scene-loader/public-api/material-definition.cpp
new file mode 100644 (file)
index 0000000..ca1244b
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/material-definition.h"
+
+// EXTERNAL INCLUDES
+#include "dali-toolkit/public-api/image-loader/sync-image-loader.h"
+
+namespace Dali
+{
+using namespace Toolkit;
+
+namespace SceneLoader
+{
+namespace
+{
+
+constexpr SamplerFlags::Type FILTER_MODES_FROM_DALI[]{
+  SamplerFlags::FILTER_LINEAR | SamplerFlags::FILTER_MIPMAP_NEAREST,
+  SamplerFlags::FILTER_LINEAR,
+  SamplerFlags::FILTER_NEAREST,
+  SamplerFlags::FILTER_LINEAR,
+  SamplerFlags::FILTER_NEAREST | SamplerFlags::FILTER_MIPMAP_NEAREST,
+  SamplerFlags::FILTER_LINEAR | SamplerFlags::FILTER_MIPMAP_NEAREST,
+  SamplerFlags::FILTER_NEAREST | SamplerFlags::FILTER_MIPMAP_LINEAR,
+  SamplerFlags::FILTER_LINEAR | SamplerFlags::FILTER_MIPMAP_LINEAR,
+};
+
+constexpr SamplerFlags::Type WRAP_MODES_FROM_DALI[]{
+  SamplerFlags::WRAP_CLAMP,
+  SamplerFlags::WRAP_CLAMP,
+  SamplerFlags::WRAP_REPEAT,
+  SamplerFlags::WRAP_MIRROR,
+};
+
+constexpr FilterMode::Type  FILTER_MODES_TO_DALI[]{
+  FilterMode::NEAREST,
+  FilterMode::LINEAR,
+  FilterMode::NEAREST_MIPMAP_NEAREST,
+  FilterMode::LINEAR_MIPMAP_NEAREST,
+  FilterMode::NEAREST_MIPMAP_LINEAR,
+  FilterMode::LINEAR_MIPMAP_LINEAR,
+};
+
+constexpr WrapMode::Type WRAP_MODES_TO_DALI[]{
+  WrapMode::REPEAT,
+  WrapMode::CLAMP_TO_EDGE,
+  WrapMode::MIRRORED_REPEAT
+};
+
+const SamplerFlags::Type SINGLE_VALUE_SAMPLER = SamplerFlags::Encode(FilterMode::NEAREST, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
+}
+
+SamplerFlags::Type SamplerFlags::Encode(FilterMode::Type minFilter, FilterMode::Type magFilter, WrapMode::Type wrapS, WrapMode::Type wrapT)
+{
+  return FILTER_MODES_FROM_DALI[minFilter] | ((FILTER_MODES_FROM_DALI[magFilter] & FILTER_MAG_BITS) << FILTER_MAG_SHIFT) |
+    (WRAP_MODES_FROM_DALI[wrapS] << WRAP_S_SHIFT) | (WRAP_MODES_FROM_DALI[wrapT] << WRAP_T_SHIFT);
+}
+
+FilterMode::Type SamplerFlags::GetMinFilter(Type flags)
+{
+  return FILTER_MODES_TO_DALI[flags & FILTER_MIN_MASK];
+}
+
+FilterMode::Type SamplerFlags::GetMagFilter(Type flags)
+{
+  return FILTER_MODES_TO_DALI[(flags >> FILTER_MAG_SHIFT) & FILTER_MAG_MASK];
+}
+
+WrapMode::Type SamplerFlags::GetWrapS(Type flags)
+{
+  return WRAP_MODES_TO_DALI[(flags >> WRAP_S_SHIFT) & WRAP_S_MASK];
+}
+
+WrapMode::Type SamplerFlags::GetWrapT(Type flags)
+{
+  return WRAP_MODES_TO_DALI[(flags >> WRAP_T_SHIFT) & WRAP_T_MASK];
+}
+
+Sampler SamplerFlags::MakeSampler(Type flags)
+{
+  auto sampler = Sampler::New();
+  sampler.SetFilterMode(GetMinFilter(flags), GetMagFilter(flags));
+  sampler.SetWrapMode(GetWrapS(flags), GetWrapT(flags));
+  return sampler;
+}
+
+MaterialDefinition::RawData
+  MaterialDefinition::LoadRaw(const std::string& imagesPath) const
+{
+  RawData raw;
+
+  const bool hasTransparency = MaskMatch(mFlags, TRANSPARENCY);
+  uint32_t numBuffers = mTextureStages.size() + (hasTransparency ?
+    !CheckTextures(ALBEDO) + !CheckTextures(METALLIC | ROUGHNESS) + !CheckTextures(NORMAL) :
+    !CheckTextures(ALBEDO | METALLIC) + !CheckTextures(NORMAL | ROUGHNESS));
+  if (numBuffers == 0)
+  {
+    return raw;
+  }
+  raw.mTextures.reserve(numBuffers);
+
+  // Load textures
+  auto iTexture = mTextureStages.cbegin();
+  auto checkStage = [&](uint32_t flags) {
+    return iTexture != mTextureStages.end() && MaskMatch(iTexture->mSemantic, flags);
+  };
+
+  // Check for compulsory textures: Albedo, Metallic, Roughness, Normal
+  if (checkStage(ALBEDO | METALLIC))
+  {
+    raw.mTextures.push_back({ SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags });
+    ++iTexture;
+
+    if (checkStage(NORMAL | ROUGHNESS))
+    {
+      raw.mTextures.push_back({ SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags });
+      ++iTexture;
+    }
+    else // single value normal-roughness
+    {
+      const auto bufferSize = 4;
+      uint8_t* buffer = new uint8_t[bufferSize]{ 0x7f, 0x7f, 0xff, 0xff }; // normal of (0, 0, 1), roughness of 1
+      raw.mTextures.push_back({ PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGBA8888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER });
+    }
+  }
+  else
+  {
+    if (checkStage(ALBEDO))
+    {
+      raw.mTextures.push_back({ SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags });
+      ++iTexture;
+    }
+    else // single value albedo, albedo-alpha or albedo-metallic
+    {
+      uint32_t bufferSize = 4;
+      uint8_t* buffer = nullptr;
+      auto format = Pixel::Format::RGBA8888;
+      if (hasTransparency)  // albedo-alpha
+      {
+        buffer = new uint8_t[bufferSize];
+        buffer[3] = static_cast<uint8_t>(mColor.a * 255.f);
+      }
+      else if (!checkStage(METALLIC | ROUGHNESS))  // albedo-metallic
+      {
+        buffer = new uint8_t[bufferSize];
+        buffer[3] = 0xff;  // metallic of 1.0
+      }
+      else  // albedo
+      {
+        bufferSize = 3;
+        buffer = new uint8_t[bufferSize];
+        format = Pixel::Format::RGB888;
+      }
+      buffer[0] = static_cast<uint8_t>(mColor.r * 255.f);
+      buffer[1] = static_cast<uint8_t>(mColor.g * 255.f);
+      buffer[2] = static_cast<uint8_t>(mColor.b * 255.f);
+      raw.mTextures.push_back({ PixelData::New(buffer, bufferSize, 1, 1, format, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER });
+    }
+
+    // If we have transparency, or an image based albedo map, we will have to continue with separate metallicRoughness + normal.
+    const bool createMetallicRoughnessAndNormal = hasTransparency || std::distance(mTextureStages.begin(), iTexture) > 0;
+    if (checkStage(METALLIC | ROUGHNESS))
+    {
+      raw.mTextures.push_back({ SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags });
+      ++iTexture;
+    }
+    else if (createMetallicRoughnessAndNormal)
+    {
+      // NOTE: we want to set both metallic and roughness to 1.0; dli uses the R & A channels,
+      // glTF2 uses B & G, so we might as well just set all components to 1.0.
+      const auto bufferSize = 4;
+      uint8_t* buffer = new uint8_t[bufferSize]{ 0xff, 0xff, 0xff, 0xff };
+      raw.mTextures.push_back({ PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGBA8888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER });
+    }
+
+    if (checkStage(NORMAL))
+    {
+      raw.mTextures.push_back({ SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags });
+      ++iTexture;
+    }
+    else if (createMetallicRoughnessAndNormal)
+    {
+      const auto bufferSize = 3;
+      uint8_t* buffer = new uint8_t[bufferSize]{ 0x7f, 0x7f, 0xff };  // normal of (0, 0, 1)
+      raw.mTextures.push_back({ PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER });
+    }
+    else // single-value normal-roughness
+    {
+      const auto bufferSize = 4;
+      uint8_t* buffer = new uint8_t[bufferSize]{ 0x7f, 0x7f, 0xff, 0xff };  // normal of (0, 0, 1), roughness of 1.0
+      raw.mTextures.push_back({ PixelData::New(buffer, bufferSize, 1, 1, Pixel::RGBA8888, PixelData::DELETE_ARRAY), SINGLE_VALUE_SAMPLER });
+    }
+  }
+
+  // Extra textures. TODO: emissive, occlusion etc.
+  if (checkStage(SUBSURFACE))
+  {
+    raw.mTextures.push_back({ SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags });
+    ++iTexture;
+  }
+
+  return raw;
+}
+
+TextureSet MaterialDefinition::Load(const EnvironmentDefinition::Vector& environments, RawData&& raw) const
+{
+  auto textureSet = TextureSet::New();
+
+  uint32_t n = 0;
+  for (auto& tData : raw.mTextures)
+  {
+    auto& pixels = tData.mPixels;
+    auto texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
+    texture.Upload(tData.mPixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight());
+    if (tData.mSamplerFlags & SamplerFlags::MIPMAP_MASK)
+    {
+      texture.GenerateMipmaps();
+    }
+
+    textureSet.SetTexture(n, texture);
+    textureSet.SetSampler(n, SamplerFlags::MakeSampler(tData.mSamplerFlags));
+
+    ++n;
+  }
+
+  // Assign textures to slots -- starting with 2D ones, then cubemaps, if any.
+  if (mEnvironmentIdx < environments.size())
+  {
+    auto& envTextures = environments[mEnvironmentIdx].second;
+    if (envTextures.mDiffuse)
+    {
+      textureSet.SetTexture(n, envTextures.mDiffuse);
+      ++n;
+    }
+
+    if (envTextures.mSpecular)
+    {
+      auto specularSampler = Sampler::New();
+      specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
+      specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
+
+      textureSet.SetTexture(n, envTextures.mSpecular);
+      textureSet.SetSampler(n, specularSampler);
+    }
+  }
+  else
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Environment index (" << mEnvironmentIdx << ") out of bounds (" <<
+      environments.size() << ").";
+  }
+
+  return textureSet;
+}
+
+bool MaterialDefinition::CheckTextures(uint32_t flags) const
+{
+  return std::find_if(mTextureStages.begin(), mTextureStages.end(), [flags](const TextureStage& ts) {
+    return MaskMatch(ts.mSemantic, flags);
+  }) != mTextureStages.end();
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/material-definition.h b/dali-scene-loader/public-api/material-definition.h
new file mode 100644 (file)
index 0000000..619e849
--- /dev/null
@@ -0,0 +1,237 @@
+#ifndef DALI_SCENE_LOADER_MATERIAL_DEFINITION_H
+#define DALI_SCENE_LOADER_MATERIAL_DEFINITION_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/environment-definition.h"
+#include "dali-scene-loader/public-api/index.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/vector4.h"
+#include "dali/public-api/common/vector-wrapper.h"
+#include <cmath>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Helper enum for encoding and decoding sampler states.
+ */
+struct DALI_SCENE_LOADER_API SamplerFlags
+{
+  using Type = uint8_t;
+
+  enum Values : Type
+  {
+    // Filter - 3 bits
+    FILTER_NEAREST = 0,
+    FILTER_LINEAR = NthBit(0),
+    FILTER_MIPMAP_NEAREST = NthBit(1),
+    FILTER_MIPMAP_LINEAR = NthBit(2),
+
+    // Wrap - 2 bits
+    WRAP_REPEAT = 0,
+    WRAP_CLAMP = NthBit(0),
+    WRAP_MIRROR = NthBit(1),
+
+    // Layout - apply shift, then mask
+    FILTER_MIN_BITS = 3,
+    FILTER_MIN_MASK = NthBit(FILTER_MIN_BITS) - 1,
+
+    FILTER_MAG_BITS = 1,
+    FILTER_MAG_SHIFT = FILTER_MIN_BITS,
+    FILTER_MAG_MASK = NthBit(FILTER_MAG_BITS) - 1,
+
+    WRAP_S_BITS = 2,
+    WRAP_S_SHIFT = FILTER_MAG_SHIFT + FILTER_MAG_BITS,
+    WRAP_S_MASK = NthBit(WRAP_S_BITS) - 1,
+
+    WRAP_T_BITS = 2,
+    WRAP_T_SHIFT = WRAP_S_SHIFT + WRAP_S_BITS,
+    WRAP_T_MASK = NthBit(WRAP_T_BITS) - 1,
+
+    // Diagnostics
+    MIPMAP_MASK = FILTER_MIPMAP_LINEAR | FILTER_MIPMAP_NEAREST,
+
+    // Default
+    DEFAULT = FILTER_LINEAR | (FILTER_LINEAR << FILTER_MAG_SHIFT) | (WRAP_REPEAT << WRAP_S_SHIFT) | (WRAP_REPEAT << WRAP_T_SHIFT),  // LINEAR filters, REPEAT wraps
+  };
+
+  /**
+   * @return SamplerFlags bit pattern calculated from the given Dali Sampler settings.
+   */
+  static Type Encode(FilterMode::Type minFilter, FilterMode::Type magFilter,
+    WrapMode::Type wrapS, WrapMode::Type wrapT);
+
+  /**
+   * @brief Decodes the minification filter patter of @a flags into the corresponding FilterMode.
+   */
+  static FilterMode::Type  GetMinFilter(Type flags);
+
+  /**
+   * @brief Decodes the magnification filter patter of @a flags into the corresponding FilterMode.
+   */
+  static FilterMode::Type  GetMagFilter(Type flags);
+
+  /**
+   * @brief Decodes the horizontal wrap pattern of @a flags into the corresponding WrapMode.
+   */
+  static WrapMode::Type GetWrapS(Type flags);
+
+  /**
+   * @brief Decodes the vertical wrap pattern of @a flags into the corresponding WrapMode.
+   */
+  static WrapMode::Type GetWrapT(Type flags);
+
+  /**
+   * @brief Creates a Sampler with the settings encoded in @a flags.
+   */
+  static Sampler MakeSampler(Type flags);
+};
+
+/**
+ * @brief Defines a texture from a combination of an image URI and its sampler definition.
+ */
+struct DALI_SCENE_LOADER_API TextureDefinition
+{
+  std::string mImageUri;
+  SamplerFlags::Type mSamplerFlags;
+
+  TextureDefinition(const std::string& imageUri = "", SamplerFlags::Type samplerFlags = SamplerFlags::DEFAULT)
+  :  mImageUri(imageUri),
+    mSamplerFlags(samplerFlags)
+  {}
+};
+
+/**
+ * @brief Defines a material with a number of texture stages, whether mipmappping
+ *  is enabled, and an index of an environment (usually of all environments in a
+ *  scene). Textures from the environment are added last when the DALi TextureSet
+ *  is being created.
+ */
+struct DALI_SCENE_LOADER_API MaterialDefinition
+{
+  enum Flags : uint32_t
+  {
+    // Texture semantics
+    ALBEDO = NthBit(0),
+    METALLIC = NthBit(1),
+    ROUGHNESS = NthBit(2),
+    NORMAL = NthBit(3),
+    EMISSIVE = NthBit(4),  // TODO: support
+    OCCLUSION = NthBit(5),  // TODO: support
+    SUBSURFACE = NthBit(6),  // Note: dli-only
+
+    // Other binary options
+    TRANSPARENCY = NthBit(20),
+    GLTF_CHANNELS = NthBit(21),  // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture
+
+    // Alpha cutoff - reserved from the 24th bit
+    ALPHA_CUTOFF_BITS = 8,
+    ALPHA_CUTOFF_SHIFT = sizeof(uint32_t) * 8 - ALPHA_CUTOFF_BITS,
+    ALPHA_CUTOFF_MASK = (1 << ALPHA_CUTOFF_BITS) - 1,
+  };
+
+  /**
+   * @brief A(n image based) texture that's used in a material.
+   */
+  struct TextureStage
+  {
+    uint32_t mSemantic;
+    TextureDefinition mTexture;
+  };
+
+  using Vector = std::vector<std::pair<MaterialDefinition, TextureSet>>;
+
+  struct RawData
+  {
+    struct TextureData
+    {
+      PixelData mPixels;
+      SamplerFlags::Type mSamplerFlags;
+    };
+
+    std::vector<TextureData> mTextures;
+  };
+
+  MaterialDefinition() = default;
+
+  MaterialDefinition(const MaterialDefinition&) = delete;
+  MaterialDefinition& operator=(const MaterialDefinition&) = delete;
+
+  MaterialDefinition(MaterialDefinition&&) = default;
+  MaterialDefinition& operator=(MaterialDefinition&&) = default;
+
+  /**
+   * @brief Loads (or, in the case of solid color materials, creates) raw pixel data,
+   *  which is then returned.
+   * @note This may be called from any thread.
+   */
+  RawData LoadRaw(const std::string& imagesPath) const;
+
+  /**
+   * @brief Creates Textures from the pixel data in @a raw, gets the
+   *  the cube maps from the iEnvironment'th element of @a environments,
+   *  then creates a DALi TextureSet and returns it.
+   * @note This must be called from the event thread.
+   * @note The textures are added in the following order: 2D, cube maps.
+   */
+  TextureSet Load(const EnvironmentDefinition::Vector& environments, RawData&& raw) const;
+
+  /**
+   * @brief Checks if the given mask matches any of the textures defined.
+   */
+  bool CheckTextures(uint32_t flags) const;
+
+  /**
+   * @return The alpha test reference value.
+   * @note A value of 0.f means no alpha testing.
+   */
+  float GetAlphaCutoff() const
+  {
+    return ((mFlags >> ALPHA_CUTOFF_SHIFT) & ALPHA_CUTOFF_MASK) / 255.f;
+  }
+
+  /**
+   * @brief Encodes the alpha test reference @a value in flags.
+   * @note A value of 0.f means no alpha testing.
+   */
+  void SetAlphaCutoff(float value)
+  {
+    DALI_ASSERT_DEBUG(value >= 0.f && value <= 1.f);
+    mFlags |= static_cast<uint8_t>(std::round(value * 255.f)) << ALPHA_CUTOFF_SHIFT;
+  }
+
+public: // DATA
+  uint32_t mFlags = 0x0;
+
+  Index mEnvironmentIdx = 0;
+  Vector4 mColor = Color::WHITE;
+  float mMetallic = 1.f;
+  float mRoughness = 1.f;
+  std::vector<TextureStage> mTextureStages;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_MATERIAL_DEFINITION_H
diff --git a/dali-scene-loader/public-api/matrix-stack.cpp b/dali-scene-loader/public-api/matrix-stack.cpp
new file mode 100644 (file)
index 0000000..9d4454f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2020 Samsung Electronics Co., Ltd.
+*
+* 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 "dali-scene-loader/public-api/matrix-stack.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+MatrixStack::MatrixStack()
+{
+  mStack.reserve(16);
+}
+
+bool MatrixStack::IsEmpty() const
+{
+  return mStack.empty();
+}
+
+void MatrixStack::Push(const Matrix& model)
+{
+  if (mStack.empty())
+  {
+    mStack.push_back(model);
+  }
+  else
+  {
+    Matrix m{ false };
+    Matrix::Multiply(m, model, mStack.back());
+    mStack.push_back(m);
+  }
+}
+
+const Matrix& MatrixStack::Top() const
+{
+  return mStack.back();
+}
+
+void MatrixStack::Pop()
+{
+  DALI_ASSERT_ALWAYS(mStack.size() > 0);
+  mStack.pop_back();
+}
+
+void MatrixStack::PopAll()
+{
+  mStack.clear();
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/matrix-stack.h b/dali-scene-loader/public-api/matrix-stack.h
new file mode 100644 (file)
index 0000000..f764da1
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_SCENE_LOADER_MATRIX_STACK_H_
+#define DALI_SCENE_LOADER_MATRIX_STACK_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/matrix.h"
+#include "dali/public-api/common/vector-wrapper.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief A stack of matrices whereby each newly pushed matrix is stored
+ *  after being multiplied by the previous one (if any).
+ * @note Current implementation reserves space for 16 matrices.
+ */
+class DALI_SCENE_LOADER_API MatrixStack
+{
+public:
+  MatrixStack();
+
+  bool IsEmpty() const;
+  void Push(const Matrix& model);
+  const Matrix& Top() const;
+  void Pop();
+  void PopAll();  // clears the stack, but retains the storage.
+
+private:
+  std::vector<Matrix> mStack;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_MATRIX_STACK_H_
diff --git a/dali-scene-loader/public-api/mesh-definition.cpp b/dali-scene-loader/public-api/mesh-definition.cpp
new file mode 100644 (file)
index 0000000..19d4544
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/mesh-definition.h"
+
+// EXTERNAL INCLUDES
+#include "dali/devel-api/adaptor-framework/pixel-buffer.h"
+#include <fstream>
+#include <cstring>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+
+using Uint16Vector4 = uint16_t[4];
+
+class IndexProvider
+{
+public:
+  IndexProvider(const uint16_t* indices)
+  : mData(reinterpret_cast<uintptr_t>(indices)),
+    mFunc(indices ? IncrementPointer : Increment)
+  {}
+
+  uint16_t operator()()
+  {
+    return mFunc(mData);
+  }
+
+private:
+  static uint16_t Increment(uintptr_t& data)
+  {
+    return static_cast<uint16_t>(data++);
+  }
+
+  static uint16_t IncrementPointer(uintptr_t& data)
+  {
+    auto iPtr = reinterpret_cast<const uint16_t*>(data);
+    auto result = *iPtr;
+    data = reinterpret_cast<uintptr_t>(++iPtr);
+    return result;
+  }
+
+  uintptr_t mData;
+  uint16_t(*mFunc)(uintptr_t&);
+};
+
+
+const std::string QUAD_STRING("quad");
+
+///@brief Reads a blob from the given stream @a source into @a target, which must have
+/// at least @a descriptor.length bytes.
+bool ReadBlob(const MeshDefinition::Blob& descriptor, std::istream& source, uint8_t* target)
+{
+  if (!source.seekg(descriptor.mOffset, std::istream::beg))
+  {
+    return false;
+  }
+
+  if (descriptor.IsConsecutive())
+  {
+    return !!source.read(reinterpret_cast<char*>(target), descriptor.mLength);
+  }
+  else
+  {
+    DALI_ASSERT_DEBUG(descriptor.mStride > descriptor.mElementSizeHint);
+    const uint32_t diff = descriptor.mStride - descriptor.mElementSizeHint;
+    uint32_t readSize = 0;
+    while (readSize < descriptor.mLength &&
+      source.read(reinterpret_cast<char*>(target), descriptor.mElementSizeHint) &&
+      source.seekg(diff, std::istream::cur))
+    {
+      readSize += descriptor.mStride;
+      target += descriptor.mElementSizeHint;
+    }
+    return readSize == descriptor.mLength;
+  }
+}
+
+template <typename T>
+void ReadValues(const std::vector<uint8_t>& valuesBuffer, const std::vector<uint8_t>& indicesBuffer, uint8_t* target, uint32_t count, uint32_t elementSizeHint)
+{
+  const T* const indicesPtr = reinterpret_cast<const T* const>(indicesBuffer.data());
+  for (uint32_t index = 0u; index < count; ++index)
+  {
+    uint32_t valuesIndex = indicesPtr[index] * elementSizeHint;
+    memcpy(target + valuesIndex, &valuesBuffer[index * elementSizeHint], elementSizeHint);
+  }
+}
+
+bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, uint8_t* target)
+{
+  bool success = false;
+
+  if (accessor.mBlob.IsDefined())
+  {
+    success = ReadBlob(accessor.mBlob, source, target);
+    if (!success)
+    {
+      return false;
+    }
+  }
+
+  if (accessor.mSparse)
+  {
+    const MeshDefinition::Blob& indices = accessor.mSparse->mIndices;
+    const MeshDefinition::Blob& values = accessor.mSparse->mValues;
+
+    if (!indices.IsDefined() || !values.IsDefined())
+    {
+      return false;
+    }
+
+    const auto indicesBufferSize = indices.GetBufferSize();
+    std::vector<uint8_t> indicesBuffer(indicesBufferSize);
+    success = ReadBlob(indices, source, indicesBuffer.data());
+    if (!success)
+    {
+      return false;
+    }
+
+    const auto valuesBufferSize = values.GetBufferSize();
+    std::vector<uint8_t> valuesBuffer(valuesBufferSize);
+    success = ReadBlob(values, source, valuesBuffer.data());
+    if (!success)
+    {
+      return false;
+    }
+
+    switch (indices.mElementSizeHint)
+    {
+    case 1u:
+    {
+      ReadValues<uint8_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
+      break;
+    }
+    case 2u:
+    {
+      ReadValues<uint16_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
+      break;
+    }
+    case 4u:
+    {
+      ReadValues<uint32_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
+      break;
+    }
+    default:
+      DALI_ASSERT_DEBUG(!"Unsupported type for an index");
+    }
+  }
+
+  return success;
+}
+
+void GenerateNormals(MeshDefinition::RawData& raw)
+{
+  auto& attribs = raw.mAttribs;
+  DALI_ASSERT_DEBUG(attribs.size() > 0);  // positions
+  IndexProvider getIndex(raw.mIndices.data());
+
+  const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : raw.mIndices.size();
+
+  auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
+
+  std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
+  auto normals = reinterpret_cast<Vector3*>(buffer.data());
+
+  for (uint32_t i = 0; i < numIndices; i += 3)
+  {
+    uint16_t indices[]{ getIndex(), getIndex(), getIndex() };
+    Vector3 pos[]{ positions[indices[0]], positions[indices[1]], positions[indices[2]] };
+
+    Vector3 a = pos[1] - pos[0];
+    Vector3 b = pos[2] - pos[0];
+
+    Vector3 normal(a.Cross(b));
+    normals[indices[0]] += normal;
+    normals[indices[1]] += normal;
+    normals[indices[2]] += normal;
+  }
+
+  auto iEnd = normals + attribs[0].mNumElements;
+  while (normals != iEnd)
+  {
+    normals->Normalize();
+    ++normals;
+  }
+
+  attribs.push_back({ "aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer) });
+}
+
+void GenerateTangentsWithUvs(MeshDefinition::RawData& raw)
+{
+  auto& attribs = raw.mAttribs;
+  DALI_ASSERT_DEBUG(attribs.size() > 2);  // positions, normals, uvs
+  IndexProvider getIndex(raw.mIndices.data());
+
+  const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : raw.mIndices.size();
+
+  auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
+  auto* uvs = reinterpret_cast<const Vector2*>(attribs[2].mData.data());
+
+  std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
+  auto tangents = reinterpret_cast<Vector3*>(buffer.data());
+
+  for (uint32_t i = 0; i < numIndices; i += 3)
+  {
+    uint16_t indices[]{ getIndex(), getIndex(), getIndex() };
+    Vector3 pos[]{ positions[indices[0]], positions[indices[1]], positions[indices[2]] };
+    Vector2 uv[]{ uvs[indices[0]], uvs[indices[1]], uvs[indices[2]] };
+
+    float x0 = pos[1].x - pos[0].x;
+    float y0 = pos[1].y - pos[0].y;
+    float z0 = pos[1].z - pos[0].z;
+
+    float x1 = pos[2].x - pos[0].x;
+    float y1 = pos[2].y - pos[0].y;
+    float z1 = pos[2].z - pos[0].z;
+
+    float s0 = uv[1].x - uv[0].x;
+    float t0 = uv[1].y - uv[0].y;
+
+    float s1 = uv[2].x - uv[0].x;
+    float t1 = uv[2].y - uv[0].y;
+
+    float r = 1.f / (s0 * t1 - t0 * s1);
+    Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r);
+    tangents[indices[0]] += tangent;
+    tangents[indices[1]] += tangent;
+    tangents[indices[2]] += tangent;
+  }
+
+  auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
+  auto iEnd = normals + attribs[1].mNumElements;
+  while (normals != iEnd)
+  {
+    *tangents -= *normals * normals->Dot(*tangents);
+    tangents->Normalize();
+
+    ++tangents;
+    ++normals;
+  }
+  attribs.push_back({ "aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer) });
+}
+
+void GenerateTangents(MeshDefinition::RawData& raw)
+{
+  auto& attribs = raw.mAttribs;
+  DALI_ASSERT_DEBUG(attribs.size() > 1);  // positions, normals
+
+  auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
+
+  std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
+  auto tangents = reinterpret_cast<Vector3*>(buffer.data());
+
+  auto iEnd = normals + attribs[1].mNumElements;
+  while (normals != iEnd)
+  {
+    Vector3 t[]{ normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS) };
+
+    *tangents = t[t[1].LengthSquared() > t[0].LengthSquared()];
+    *tangents -= *normals * normals->Dot(*tangents);
+    tangents->Normalize();
+
+    ++tangents;
+    ++normals;
+  }
+  attribs.push_back({ "aTangent", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer) });
+}
+
+void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uint32_t& textureHeight)
+{
+  DALI_ASSERT_DEBUG(0u != totalTextureSize && "totalTextureSize is zero.")
+
+    // Calculate the dimensions of the texture.
+    // The total size of the texture is the length of the blend shapes blob.
+
+    textureWidth = 0u;
+  textureHeight = 0u;
+
+  if (0u == totalTextureSize)
+  {
+    // nothing to do.
+    return;
+  }
+
+  const uint32_t pow2 = static_cast<uint32_t>(ceil(log2(totalTextureSize)));
+  const uint32_t powWidth = pow2 >> 1u;
+  const uint32_t powHeight = pow2 - powWidth;
+
+  textureWidth = 1u << powWidth;
+  textureHeight = 1u << powHeight;
+}
+
+void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::ifstream& binFile, const std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor)
+{
+  uint32_t geometryBufferIndex = 0u;
+  float maxDistance = 0.f;
+  Vector3* geometryBufferV3 = reinterpret_cast<Vector3*>(geometryBuffer);
+  for (const auto& blendShape : blendShapes)
+  {
+    if (blendShape.deltas.IsDefined())
+    {
+      DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0u) ||
+        blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
+        "Blend Shape position buffer length not a multiple of element size");
+
+      const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
+      std::vector<uint8_t> buffer(bufferSize);
+      if (ReadAccessor(blendShape.deltas, binFile, buffer.data()))
+      {
+        blendShape.deltas.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
+        // Calculate the difference with the original mesh.
+        // Find the max distance to normalize the deltas.
+        const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
+
+        for (uint32_t index = 0u; index < numberOfVertices; ++index)
+        {
+          Vector3& delta = geometryBufferV3[geometryBufferIndex++];
+          delta = deltasBuffer[index];
+
+          maxDistance = std::max(maxDistance, delta.LengthSquared());
+        }
+      }
+    }
+
+    if (blendShape.normals.IsDefined())
+    {
+      DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0u) ||
+        blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
+        "Blend Shape normals buffer length not a multiple of element size");
+
+      const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
+      std::vector<uint8_t> buffer(bufferSize);
+      if (ReadAccessor(blendShape.normals, binFile, buffer.data()))
+      {
+        blendShape.normals.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
+
+        // Calculate the difference with the original mesh, and translate to make all values positive.
+        const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
+
+        for (uint32_t index = 0u; index < numberOfVertices; ++index)
+        {
+          Vector3& delta = geometryBufferV3[geometryBufferIndex++];
+          delta = deltasBuffer[index];
+
+          delta.x *= 0.5f;
+          delta.y *= 0.5f;
+          delta.z *= 0.5f;
+
+          delta.x += 0.5f;
+          delta.y += 0.5f;
+          delta.z += 0.5f;
+        }
+      }
+    }
+
+    if (blendShape.tangents.IsDefined())
+    {
+      DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0u) ||
+        blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
+        "Blend Shape tangents buffer length not a multiple of element size");
+
+      const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
+      std::vector<uint8_t> buffer(bufferSize);
+      if (ReadAccessor(blendShape.tangents, binFile, buffer.data()))
+      {
+        blendShape.tangents.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
+
+        // Calculate the difference with the original mesh, and translate to make all values positive.
+        const Vector3* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
+
+        for (uint32_t index = 0u; index < numberOfVertices; ++index)
+        {
+          Vector3& delta = geometryBufferV3[geometryBufferIndex++];
+          delta = deltasBuffer[index];
+
+          delta.x *= 0.5f;
+          delta.y *= 0.5f;
+          delta.z *= 0.5f;
+
+          delta.x += 0.5f;
+          delta.y += 0.5f;
+          delta.z += 0.5f;
+        }
+      }
+    }
+  }
+
+  geometryBufferIndex = 0u;
+  for (const auto& blendShape : blendShapes)
+  {
+    // Normalize all the deltas and translate to a possitive value.
+    // Deltas are going to be passed to the shader in a color texture
+    // whose values that are less than zero are clamped.
+    if (blendShape.deltas.IsDefined())
+    {
+
+      const float normalizeFactor = (fabsf(maxDistance) < Math::MACHINE_EPSILON_1000) ? 1.f : (0.5f / sqrtf(maxDistance));
+
+      for (uint32_t index = 0u; index < numberOfVertices; ++index)
+      {
+        Vector3& delta = geometryBufferV3[geometryBufferIndex++];
+        delta.x = Clamp(((delta.x * normalizeFactor) + 0.5f), 0.f, 1.f);
+        delta.y = Clamp(((delta.y * normalizeFactor) + 0.5f), 0.f, 1.f);
+        delta.z = Clamp(((delta.z * normalizeFactor) + 0.5f), 0.f, 1.f);
+      }
+
+      // Calculate and store the unnormalize factor.
+      blendShapeUnnormalizeFactor = 1.f / normalizeFactor;
+    }
+
+    if (blendShape.normals.IsDefined())
+    {
+      geometryBufferIndex += numberOfVertices;
+    }
+
+    if (blendShape.tangents.IsDefined())
+    {
+      geometryBufferIndex += numberOfVertices;
+    }
+  }
+}
+
+}
+
+MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
+:  mIndices{indices},
+  mValues{values},
+  mCount{count}
+{}
+
+MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob,
+  const MeshDefinition::SparseBlob& sparse)
+:  mBlob{blob},
+  mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr}
+{}
+
+void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max,
+  uint32_t count, float* values)
+{
+  DALI_ASSERT_DEBUG(max.empty() || max.size() == min.size());
+  const auto numComponents = std::max(min.size(), max.size());
+
+  using ClampFn = void(*)(const float*, const float*, uint32_t, float&);
+  ClampFn clampFn = min.empty() ?
+    (max.empty() ?
+      static_cast<ClampFn>(nullptr) :
+      [](const float* min, const float* max, uint32_t i, float& value) {
+        value = std::min(max[i], value);
+      }) :
+    (max.empty() ?
+      [](const float* min, const float* max, uint32_t i, float& value) {
+        value = std::max(min[i], value);
+      } :
+      [](const float* min, const float* max, uint32_t i, float& value) {
+        value = std::min(std::max(min[i], value), max[i]);
+      });
+
+  auto end = values + count * numComponents;
+  while (values != end)
+  {
+    auto nextElement = values + numComponents;
+    uint32_t i = 0;
+    while (values != nextElement)
+    {
+      clampFn(min.data(), max.data(), i, *values);
+      ++values;
+      ++i;
+    }
+  }
+}
+
+uint32_t MeshDefinition::Blob::GetBufferSize() const
+{
+  return IsConsecutive() ? mLength : (mLength * mElementSizeHint / mStride);
+}
+
+void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values) const
+{
+  ApplyMinMax(mMin, mMax, count, values);
+}
+
+void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
+{
+  Property::Map attribMap;
+  attribMap[mName] = mType;
+  VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
+  attribBuffer.SetData(mData.data(), mNumElements);
+
+  g.AddVertexBuffer(attribBuffer);
+}
+
+bool MeshDefinition::IsQuad() const
+{
+  return CaseInsensitiveStringCompare("quad", mUri);
+}
+
+bool MeshDefinition::IsSkinned() const
+{
+  return mJoints0.IsDefined() && mWeights0.IsDefined();
+}
+
+bool MeshDefinition::HasBlendShapes() const
+{
+  return !mBlendShapes.empty();
+}
+
+void MeshDefinition::RequestNormals()
+{
+  mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
+}
+
+void MeshDefinition::RequestTangents()
+{
+  mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
+}
+
+MeshDefinition::RawData
+  MeshDefinition::LoadRaw(const std::string& modelsPath) const
+{
+  RawData raw;
+  if (IsQuad())
+  {
+    return raw;
+  }
+
+  const std::string meshPath = modelsPath + mUri;
+  std::ifstream binFile(meshPath, std::ios::binary);
+  if (!binFile)
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to read geometry data from '" << meshPath << "'";
+  }
+
+  if (mIndices.IsDefined())
+  {
+    if (MaskMatch(mFlags, U32_INDICES))
+    {
+      DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
+        mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
+        "Index buffer length not a multiple of element size");
+      const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
+      raw.mIndices.resize(indexCount * 2);  // NOTE: we need space for uint32_ts initially.
+      if (!ReadAccessor(mIndices, binFile, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << meshPath << "'.";
+      }
+
+      auto u16s = raw.mIndices.data();
+      auto u32s = reinterpret_cast<uint32_t*>(raw.mIndices.data());
+      auto end = u32s + indexCount;
+      while (u32s != end)
+      {
+        *u16s = static_cast<uint16_t>(*u32s);
+        ++u16s;
+        ++u32s;
+      }
+
+      raw.mIndices.resize(indexCount);
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
+        mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
+        "Index buffer length not a multiple of element size");
+      raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
+      if (!ReadAccessor(mIndices, binFile, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << meshPath << "'.";
+      }
+    }
+  }
+
+  std::vector<Vector3> positions;
+  if (mPositions.IsDefined())
+  {
+    DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
+      mPositions.mBlob.mStride >= sizeof(Vector3)) &&
+      "Position buffer length not a multiple of element size");
+    const auto bufferSize = mPositions.mBlob.GetBufferSize();
+    std::vector<uint8_t> buffer(bufferSize);
+    if (!ReadAccessor(mPositions, binFile, buffer.data()))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << meshPath << "'.";
+    }
+
+    uint32_t numVector3 = bufferSize / sizeof(Vector3);
+    mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
+
+    if (HasBlendShapes())
+    {
+      positions.resize(numVector3);
+      std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
+    }
+
+    raw.mAttribs.push_back({ "aPosition", Property::VECTOR3, numVector3, std::move(buffer) });
+  }
+
+  const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
+  auto hasNormals = mNormals.IsDefined();
+  if (hasNormals)
+  {
+    DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
+      mNormals.mBlob.mStride >= sizeof(Vector3)) &&
+      "Normal buffer length not a multiple of element size");
+    const auto bufferSize = mNormals.mBlob.GetBufferSize();
+    std::vector<uint8_t> buffer(bufferSize);
+    if (!ReadAccessor(mNormals, binFile, buffer.data()))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << meshPath << "'.";
+    }
+
+    mNormals.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
+
+    raw.mAttribs.push_back({ "aNormal", Property::VECTOR3,
+      static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer) });
+  }
+  else if (mNormals.mBlob.mLength != 0 && isTriangles)
+  {
+    DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
+    GenerateNormals(raw);
+    hasNormals = true;
+  }
+
+  const auto hasUvs = mTexCoords.IsDefined();
+  if (hasUvs)
+  {
+    DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
+      mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
+      "Normal buffer length not a multiple of element size");
+    const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
+    std::vector<uint8_t> buffer(bufferSize);
+    if (!ReadAccessor(mTexCoords, binFile, buffer.data()))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << meshPath << "'.";
+    }
+
+    const auto uvCount = bufferSize / sizeof(Vector2);
+    if (MaskMatch(mFlags, FLIP_UVS_VERTICAL))
+    {
+      auto uv = reinterpret_cast<Vector2*>(buffer.data());
+      auto uvEnd = uv + uvCount;
+      while (uv != uvEnd)
+      {
+        uv->y = 1.0f - uv->y;
+        ++uv;
+      }
+    }
+
+    mTexCoords.mBlob.ApplyMinMax(bufferSize / sizeof(Vector2), reinterpret_cast<float*>(buffer.data()));
+
+    raw.mAttribs.push_back({ "aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount),
+      std::move(buffer) });
+  }
+
+  if (mTangents.IsDefined())
+  {
+    DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % sizeof(Vector3) == 0) ||
+      mTangents.mBlob.mStride >= sizeof(Vector3)) &&
+      "Tangents buffer length not a multiple of element size");
+    const auto bufferSize = mTangents.mBlob.GetBufferSize();
+    std::vector<uint8_t> buffer(bufferSize);
+    if (!ReadAccessor(mTangents, binFile, buffer.data()))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << meshPath << "'.";
+    }
+
+    mTangents.mBlob.ApplyMinMax(bufferSize / sizeof(Vector3), reinterpret_cast<float*>(buffer.data()));
+
+    raw.mAttribs.push_back({ "aTangent", Property::VECTOR3,
+      static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer) });
+  }
+  else if (mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
+  {
+    DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
+    hasUvs ? GenerateTangentsWithUvs(raw) : GenerateTangents(raw);
+  }
+
+  if (IsSkinned())
+  {
+    if (MaskMatch(mFlags, U16_JOINT_IDS))
+    {
+      DALI_ASSERT_ALWAYS(((mJoints0.mBlob.mLength % sizeof(Uint16Vector4) == 0) ||
+        mJoints0.mBlob.mStride >= sizeof(Uint16Vector4)) &&
+        "Joints buffer length not a multiple of element size");
+      const auto inBufferSize = mJoints0.mBlob.GetBufferSize();
+      std::vector<uint8_t> buffer(inBufferSize * 2);
+      auto u16s = buffer.data() + inBufferSize;
+      if (!ReadAccessor(mJoints0, binFile, u16s))
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
+      }
+
+      auto floats = reinterpret_cast<float*>(buffer.data());
+      auto end = u16s + inBufferSize;
+      while (u16s != end)
+      {
+        auto value = *reinterpret_cast<uint16_t*>(u16s);
+        *floats = static_cast<float>(value);
+
+        u16s += sizeof(uint16_t);
+        ++floats;
+      }
+      raw.mAttribs.push_back({ "aJoints", Property::VECTOR4,
+        static_cast<uint32_t>(buffer.size() / sizeof(Vector4)), std::move(buffer) });
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS(((mJoints0.mBlob.mLength % sizeof(Vector4) == 0) ||
+        mJoints0.mBlob.mStride >= sizeof(Vector4)) &&
+        "Joints buffer length not a multiple of element size");
+      const auto bufferSize = mJoints0.mBlob.GetBufferSize();
+      std::vector<uint8_t> buffer(bufferSize);
+      if (!ReadAccessor(mJoints0, binFile, buffer.data()))
+      {
+        ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
+      }
+
+      raw.mAttribs.push_back({ "aJoints", Property::VECTOR4,
+        static_cast<uint32_t>(bufferSize / sizeof(Vector4)), std::move(buffer) });
+    }
+
+    DALI_ASSERT_ALWAYS(((mWeights0.mBlob.mLength % sizeof(Vector4) == 0) ||
+      mWeights0.mBlob.mStride >= sizeof(Vector4)) &&
+      "Weights buffer length not a multiple of element size");
+    const auto bufferSize = mWeights0.mBlob.GetBufferSize();
+    std::vector<uint8_t> buffer(bufferSize);
+    if (!ReadAccessor(mWeights0, binFile, buffer.data()))
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << meshPath << "'.";
+    }
+
+    raw.mAttribs.push_back({ "aWeights", Property::VECTOR4,
+      static_cast<uint32_t>(bufferSize / sizeof(Vector4)), std::move(buffer) });
+  }
+
+  // Calculate the Blob for the blend shapes.
+  Blob blendShapesBlob;
+  blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
+  blendShapesBlob.mLength = 0u;
+
+  for (const auto& blendShape : mBlendShapes)
+  {
+    for (auto i : { &blendShape.deltas, &blendShape.normals, &blendShape.tangents })
+    {
+      if (i->IsDefined())
+      {
+        blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, i->mBlob.mOffset);
+        blendShapesBlob.mLength += i->mBlob.mLength;
+      }
+    }
+  }
+
+  if (HasBlendShapes())
+  {
+    const uint32_t numberOfVertices = mPositions.mBlob.mLength / sizeof(Vector3);
+
+    // Calculate the size of one buffer inside the texture.
+    raw.mBlendShapeBufferOffset = numberOfVertices;
+
+    bool calculateGltf2BlendShapes = false;
+    uint32_t textureWidth = 0u;
+    uint32_t textureHeight = 0u;
+
+    if (!mBlendShapeHeader.IsDefined())
+    {
+      CalculateTextureSize(blendShapesBlob.mLength / sizeof(Vector3), textureWidth, textureHeight);
+      calculateGltf2BlendShapes = true;
+    }
+    else
+    {
+      uint16_t header[2u];
+      ReadBlob(mBlendShapeHeader, binFile, reinterpret_cast<uint8_t*>(header));
+      textureWidth = header[0u];
+      textureHeight = header[1u];
+    }
+
+    const uint32_t numberOfBlendShapes = mBlendShapes.size();
+    raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
+
+    Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
+    uint8_t* geometryBuffer = geometryPixelBuffer.GetBuffer();
+
+    if (calculateGltf2BlendShapes)
+    {
+      CalculateGltf2BlendShapes(geometryBuffer, binFile, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u]);
+    }
+    else
+    {
+      Blob unnormalizeFactorBlob;
+      unnormalizeFactorBlob.mLength = sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes);
+
+      if (blendShapesBlob.IsDefined())
+      {
+        if (ReadBlob(blendShapesBlob, binFile, geometryBuffer))
+        {
+          unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
+        }
+      }
+
+      // Read the unnormalize factors.
+      if (unnormalizeFactorBlob.IsDefined())
+      {
+        ReadBlob(unnormalizeFactorBlob, binFile, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
+      }
+    }
+    raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
+  }
+
+  return raw;
+}
+
+MeshGeometry MeshDefinition::Load(RawData&& raw) const
+{
+  MeshGeometry meshGeometry;
+  meshGeometry.geometry = Geometry::New();
+  meshGeometry.geometry.SetType(mPrimitiveType);
+
+  if (IsQuad())  // TODO: do this in raw data; provide MakeTexturedQuadGeometry() that only creates buffers.
+  {
+    auto options = MaskMatch(mFlags, FLIP_UVS_VERTICAL) ? TexturedQuadOptions::FLIP_VERTICAL : 0;
+    meshGeometry.geometry = MakeTexturedQuadGeometry(options);
+  }
+  else
+  {
+    if (!raw.mIndices.empty())
+    {
+      meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size());
+    }
+
+    for (auto& a : raw.mAttribs)
+    {
+      a.AttachBuffer(meshGeometry.geometry);
+    }
+
+    if (HasBlendShapes())
+    {
+      meshGeometry.blendShapeBufferOffset = raw.mBlendShapeBufferOffset;
+      meshGeometry.blendShapeUnnormalizeFactor = std::move(raw.mBlendShapeUnnormalizeFactor);
+
+      meshGeometry.blendShapeGeometry = Texture::New(  TextureType::TEXTURE_2D,
+                              raw.mBlendShapeData.GetPixelFormat(),
+                              raw.mBlendShapeData.GetWidth(),
+                              raw.mBlendShapeData.GetHeight());
+      meshGeometry.blendShapeGeometry.Upload(raw.mBlendShapeData);
+    }
+  }
+
+  return meshGeometry;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/mesh-definition.h b/dali-scene-loader/public-api/mesh-definition.h
new file mode 100644 (file)
index 0000000..6a1eaa6
--- /dev/null
@@ -0,0 +1,266 @@
+#ifndef DALI_SCENE_LOADER_MESH_DEFINITION_H
+#define DALI_SCENE_LOADER_MESH_DEFINITION_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+#include "dali-scene-loader/public-api/mesh-geometry.h"
+#include "dali-scene-loader/public-api/blend-shape-details.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include "dali-scene-loader/public-api/index.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include <memory>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Defines a mesh with its attributes, the primitive type to render it as,
+ *  and the file to load it from with the offset and length information for the
+ *  individual attribute buffers.
+ */
+struct DALI_SCENE_LOADER_API MeshDefinition
+{
+  using Vector = std::vector<std::pair<MeshDefinition, MeshGeometry>>;
+
+  enum : uint32_t { INVALID = std::numeric_limits<uint32_t>::max() };
+
+  enum Flags : uint16_t
+  {
+    FLIP_UVS_VERTICAL = NthBit(0),
+    U32_INDICES = NthBit(1),  // default is unsigned short
+    U16_JOINT_IDS = NthBit(2), // default is floats
+  };
+
+  enum Attributes
+  {
+    INDICES = NthBit(0),
+    POSITIONS = NthBit(1),
+    NORMALS = NthBit(2),
+    TEX_COORDS = NthBit(3),
+    TANGENTS = NthBit(4),
+    LEGACY_BITANGENTS = NthBit(5),  // these are ignored; we're calculating them in the (PBR) shader.
+    JOINTS_0 = NthBit(6),
+    WEIGHTS_0 = NthBit(7),
+  };
+
+  /**
+   * @brief Describes raw data in terms of its position and size in a buffer.
+   *  All units in bytes.
+   */
+  struct Blob
+  {
+    uint32_t mOffset = INVALID;  // the default means that the blob is undefined.
+    uint32_t mLength = 0;  // if the blob is undefined, its data may still be generated. This is enabled by setting length to some non-0 value. Refer to MeshDefinition for details.
+    uint16_t mStride = 0;  // ignore if 0
+    uint16_t mElementSizeHint = 0;  // ignore if 0 or stride == 0
+    std::vector<float> mMin;
+    std::vector<float> mMax;
+
+    static void ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max, uint32_t count, float* values);
+
+    Blob() = default;
+
+    Blob(uint32_t offset, uint32_t length, uint16_t stride = 0, uint16_t elementSizeHint = 0,
+      const std::vector<float>& min = {}, const std::vector<float>& max = {})
+      : mOffset(offset),
+      mLength(length),
+      mStride(stride),
+      mElementSizeHint(elementSizeHint),
+      mMin(min),
+      mMax(max)
+    {}
+
+    /**
+     * @brief Calculates the size of a tightly-packed buffer for the elements from the blob.
+     */
+    uint32_t GetBufferSize() const;
+
+    /**
+     * @brief Convenience method to tell whether a Blob has meaningful data.
+     */
+    bool IsDefined() const
+    {
+      return mOffset != INVALID;
+    }
+
+    /**
+     * @brief Convenience method to tell whether the elements stored in the blob follow each
+     *  other tightly. The opposite would be interleaving.
+     */
+    bool IsConsecutive() const
+    {
+      return mStride == 0 || mStride == mElementSizeHint;
+    }
+
+    /**
+     * @brief Applies the min / max values, if they're defined.
+     */
+    void ApplyMinMax(uint32_t count, float* values) const;
+  };
+
+  /**
+   * @brief A sparse blob describes a change in a reference Blob.
+   * @p indices describe what positions of the reference Blob change and
+   * @p values describe the new values.
+   */
+  struct SparseBlob
+  {
+    SparseBlob() = default;
+
+    SparseBlob(const Blob& indices, const Blob& values, uint32_t count);
+
+    Blob mIndices;
+    Blob mValues;
+    uint32_t mCount = 0u;
+  };
+
+  struct Accessor
+  {
+    Blob mBlob;
+    std::unique_ptr<SparseBlob> mSparse;
+
+    Accessor() = default;
+
+    Accessor(const Accessor&) = delete;
+    Accessor& operator=(const Accessor&) = delete;
+
+    Accessor(Accessor&&) = default;
+    Accessor& operator=(Accessor&&) = default;
+
+    Accessor(const MeshDefinition::Blob& blob,
+      const MeshDefinition::SparseBlob& sparse);
+
+    bool IsDefined() const
+    {
+      return mBlob.IsDefined() || (mSparse && (mSparse->mIndices.IsDefined() && mSparse->mValues.IsDefined()));
+    }
+  };
+
+  /**
+   * @brief Stores a blend shape.
+   */
+  struct BlendShape
+  {
+    std::string name;
+    Accessor deltas;
+    Accessor normals;
+    Accessor tangents;
+    float weight = 0.f;
+  };
+
+  struct RawData
+  {
+    struct Attrib
+    {
+      std::string mName;
+      Property::Type mType;
+      uint32_t mNumElements;
+      std::vector<uint8_t> mData;
+
+      void AttachBuffer(Geometry& g) const;
+    };
+
+    std::vector<uint16_t> mIndices;
+    std::vector<Attrib> mAttribs;
+
+    unsigned int mBlendShapeBufferOffset;
+    Dali::Vector<float> mBlendShapeUnnormalizeFactor;
+    PixelData mBlendShapeData;
+  };
+
+  MeshDefinition() = default;
+
+  MeshDefinition(const MeshDefinition&) = delete;
+  MeshDefinition& operator=(const MeshDefinition&) = delete;
+
+  MeshDefinition(MeshDefinition&&) = default;
+  MeshDefinition& operator=(MeshDefinition&&) = default;
+
+  /**
+   * @brief Determines whether the mesh definition is that of a quad.
+   */
+  bool IsQuad() const;
+
+  /**
+   * @brief Determines whether the mesh is used for skeletal animation.
+   */
+  bool IsSkinned() const;
+
+  /**
+   * @brief Whether the mesh has blend shapes.
+   */
+  bool HasBlendShapes() const;
+
+  /**
+   * @brief Requests normals to be generated.
+   * @note Generation happens in LoadRaw().
+   * @note Must have Vector3 positions defined.
+   */
+  void RequestNormals();
+
+  /**
+   * @brief Requests tangents to be generated.
+   * @note Generation happens in LoadRaw().
+   * @note Must have Vector3 normals defined.
+   */
+  void RequestTangents();
+
+  /**
+   * @brief Loads raw geometry data, which includes index (optional) and
+   *  attribute buffers, as well as blend shape data. This is then returned.
+   * @note This can be done on any thread.
+   */
+  RawData LoadRaw(const std::string& modelsPath) const;
+
+  /**
+   * @brief Creates a MeshGeometry based firstly on the value of the uri member:
+   *  if it is "quad", a textured quad is created; otherwise it uses the
+   *  attribute (and index) buffers and blend shape information (if available)
+   *  from @a raw.
+   *  If mFlipVertical was set, the UVs are flipped in Y, i.e. v = 1.0 - v.
+   */
+  MeshGeometry Load(RawData&& raw) const;
+
+public: // DATA
+  uint32_t mFlags = 0x0;
+  Geometry::Type mPrimitiveType = Geometry::TRIANGLES;
+  std::string mUri;
+  Accessor mIndices;
+  Accessor mPositions;
+  Accessor mNormals;  // data can be generated based on positions
+  Accessor mTexCoords;
+  Accessor mTangents;  // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available)
+  Accessor mJoints0;
+  Accessor mWeights0;
+
+  Blob mBlendShapeHeader;
+  std::vector<BlendShape> mBlendShapes;
+  BlendShapes::Version mBlendShapeVersion = BlendShapes::Version::INVALID;
+
+  Index mSkeletonIdx = INVALID_INDEX;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_MESH_DEFINITION_H
diff --git a/dali-scene-loader/public-api/mesh-geometry.h b/dali-scene-loader/public-api/mesh-geometry.h
new file mode 100644 (file)
index 0000000..bf282da
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef DALI_SCENE_LOADER_MESH_GEOMETRY_H
+#define DALI_SCENE_LOADER_MESH_GEOMETRY_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/rendering/geometry.h"
+#include "dali/public-api/rendering/texture.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+struct DALI_SCENE_LOADER_API MeshGeometry
+{
+  Geometry geometry;                         ///< The array of vertices.
+  Texture blendShapeGeometry;                ///< The array of vertices of the different blend shapes encoded inside a texture with power of two dimensions.
+  Vector<float> blendShapeUnnormalizeFactor; ///< Factor used to unnormalize the geometry of the blend shape.
+  unsigned int blendShapeBufferOffset;             ///< Offset used to calculate the start of each blend shape.
+};
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_MESH_GEOMETRY_H
diff --git a/dali-scene-loader/public-api/node-definition.cpp b/dali-scene-loader/public-api/node-definition.cpp
new file mode 100644 (file)
index 0000000..a277371
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL
+#include "dali-scene-loader/public-api/node-definition.h"
+#include "dali-scene-loader/public-api/renderer-state.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+void NodeDefinition::Renderable::RegisterResources(IResourceReceiver& receiver) const
+{
+  receiver.Register(ResourceType::Shader, mShaderIdx);
+}
+
+void NodeDefinition::Renderable::ReflectResources(IResourceReflector& reflector)
+{
+  reflector.Reflect(ResourceType::Shader, mShaderIdx);
+}
+
+void NodeDefinition::Renderable::OnCreate(const NodeDefinition& node, CreateParams& params,
+  Actor& actor) const
+{
+  DALI_ASSERT_DEBUG(mShaderIdx != INVALID_INDEX);
+  auto& resources = params.mResources;
+  Shader shader = resources.mShaders[mShaderIdx].second;
+
+  static Geometry defaultGeometry = Geometry::New();
+  Renderer renderer = Renderer::New(defaultGeometry, shader);
+
+  RendererState::Apply(resources.mShaders[mShaderIdx].first.mRendererState, renderer);
+
+  actor.AddRenderer(renderer);
+}
+
+const std::string NodeDefinition::ORIGINAL_MATRIX_PROPERTY_NAME = "originalMatrix";
+
+Actor NodeDefinition::CreateActor(CreateParams& params) const
+{
+  Actor actor = Actor::New();
+  SetActorCentered(actor);
+
+  actor.SetProperty(Actor::Property::NAME, mName);
+  actor.SetProperty(Actor::Property::POSITION, mPosition);
+  actor.SetProperty(Actor::Property::ORIENTATION, mOrientation);
+  actor.SetProperty(Actor::Property::SCALE, mScale);
+  actor.SetProperty(Actor::Property::SIZE, mSize);
+  actor.SetProperty(Actor::Property::VISIBLE, mIsVisible);
+
+  actor.RegisterProperty(ORIGINAL_MATRIX_PROPERTY_NAME, GetLocalSpace(), Property::AccessMode::READ_ONLY);
+
+  if (mRenderable)
+  {
+    mRenderable->OnCreate(*this, params, actor);
+  }
+
+  for (auto& e : mExtras)
+  {
+    actor.RegisterProperty(e.mKey, e.mValue);
+  }
+
+  for (auto& c : mConstraints)
+  {
+    params.mConstrainables.push_back(ConstraintRequest{ &c, actor });
+  }
+
+  return actor;
+}
+
+Matrix NodeDefinition::GetLocalSpace() const
+{
+  Matrix localSpace{ false };
+  localSpace.SetTransformComponents(mScale, mOrientation, mPosition);
+  return localSpace;
+}
+
+void ModelNode::RegisterResources(IResourceReceiver& receiver) const
+{
+  Renderable::RegisterResources(receiver);
+  receiver.Register(ResourceType::Mesh, mMeshIdx);
+  receiver.Register(ResourceType::Material, mMaterialIdx);
+}
+
+void ModelNode::ReflectResources(IResourceReflector& reflector)
+{
+  Renderable::ReflectResources(reflector);
+  reflector.Reflect(ResourceType::Mesh, mMeshIdx);
+  reflector.Reflect(ResourceType::Material, mMaterialIdx);
+}
+
+void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
+{
+  DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
+  Renderable::OnCreate(node, params, actor);
+
+  auto& resources = params.mResources;
+  auto& mesh = resources.mMeshes[mMeshIdx];
+
+  auto renderer = actor.GetRendererAt(0);
+  Geometry geometry = mesh.second.geometry;
+  renderer.SetGeometry(geometry);
+
+  auto shader = renderer.GetShader();
+
+  if (mesh.first.IsSkinned())
+  {
+    params.mSkinnables.push_back(SkinningShaderConfigurationRequest{ mesh.first.mSkeletonIdx, shader });
+  }
+
+  if (mesh.first.HasBlendShapes())
+  {
+    params.mBlendshapeRequests.push_back(BlendshapeShaderConfigurationRequest{ node.mName, mMeshIdx, shader });
+  }
+
+  TextureSet textures = resources.mMaterials[mMaterialIdx].second;
+
+  // Set the blend shape texture.
+  if (mesh.second.blendShapeGeometry)
+  {
+    TextureSet newTextureSet = TextureSet::New();
+    newTextureSet.SetTexture(0u, mesh.second.blendShapeGeometry);
+
+    const unsigned int numberOfTextures = textures.GetTextureCount();
+    for (unsigned int index = 0u; index < numberOfTextures; ++index)
+    {
+      const unsigned int newIndex = index + 1u;
+      newTextureSet.SetTexture(newIndex, textures.GetTexture(index));
+      newTextureSet.SetSampler(newIndex, textures.GetSampler(index));
+    }
+
+    textures = newTextureSet;
+  }
+
+  renderer.SetTextures(textures);
+
+  actor.SetProperty(Actor::Property::COLOR, mColor);
+
+  auto& matDef = resources.mMaterials[mMaterialIdx].first;
+  actor.RegisterProperty("uMetallicFactor", matDef.mMetallic);
+  actor.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
+
+  Index envIdx = matDef.mEnvironmentIdx;
+  actor.RegisterProperty("uIblIntensity", resources.mEnvironmentMaps[envIdx].first.mIblIntensity);
+
+  const auto alphaCutoff = matDef.GetAlphaCutoff();
+  if (alphaCutoff > 0.f)
+  {
+    actor.RegisterProperty("uAlphaThreshold", alphaCutoff);
+  }
+}
+
+void ArcNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params,
+  Actor& actor) const
+{
+  ModelNode::OnCreate(node, params, actor);
+
+  actor.RegisterProperty("antiAliasing", mAntiAliasing ? 1 : 0);
+  actor.RegisterProperty("arcCaps", mArcCaps);
+  actor.RegisterProperty("radius", mRadius);
+
+  const float startAngleRadians = mStartAngleDegrees * Math::PI_OVER_180;
+  Vector2 startPolar{ std::cos(startAngleRadians), std::sin(startAngleRadians) };
+  actor.RegisterProperty("startAngle", startPolar);
+
+  const float endAngleRadians = mEndAngleDegrees * Math::PI_OVER_180;
+  Vector2 endPolar{ std::cos(endAngleRadians), std::sin(endAngleRadians) };
+  actor.RegisterProperty("endAngle", endPolar);
+}
+
+void ArcNode::GetEndVectorWithDiffAngle(float startAngle, float diffAngle, Vector2& endVector)
+{
+  float endAngle = 0.f;
+
+  if (diffAngle <= 0.001f)
+  {
+    //0.001 is used to ensure is empty arc when startAngle = endAngle + 360 * N
+    endAngle = startAngle + 0.001f;
+  }
+  else if (diffAngle >= 360.f)
+  {
+    endAngle = diffAngle + 359.99f;
+  }
+  else
+  {
+    endAngle = startAngle + 360.0f + diffAngle;
+  }
+  endVector.x = cosf(endAngle * Math::PI_OVER_180);
+  endVector.y = sinf(endAngle * Math::PI_OVER_180);
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/node-definition.h b/dali-scene-loader/public-api/node-definition.h
new file mode 100644 (file)
index 0000000..994ec18
--- /dev/null
@@ -0,0 +1,280 @@
+#ifndef DALI_SCENE_LOADER_NODE_DEFINITION_H_
+#define DALI_SCENE_LOADER_NODE_DEFINITION_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/customization.h"
+#include "dali-scene-loader/public-api/matrix-stack.h"
+#include "dali-scene-loader/public-api/resource-bundle.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/quaternion.h"
+#include "dali/public-api/math/matrix.h"
+#include "dali/public-api/math/vector4.h"
+#include "dali/public-api/actors/actor.h"
+#include <string>
+#include <memory>
+#include <functional>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+class ViewProjection;
+
+/**
+ * @brief Interface to report (const) resource ids to.
+ */
+class DALI_SCENE_LOADER_API IResourceReceiver
+{
+public:
+  virtual ~IResourceReceiver()
+  {}
+
+  virtual void Register(ResourceType::Value type, Index id) = 0;
+};
+
+/**
+ * @brief Interface to report modifiable resource ids to.
+ * @note These are supposed to be transient. Obviously, the references collected
+ *  this way must not outlive the objects that they came from.
+ */
+class DALI_SCENE_LOADER_API IResourceReflector
+{
+public:
+  virtual ~IResourceReflector()
+  {}
+
+  virtual void Reflect(ResourceType::Value type, Index& id) = 0;
+};
+
+/**
+ * @brief Intermediate representation for a constraint that shall be
+ *  set up after the Actors were created. The target of the constraint
+ *  is the node definition that carries it.
+ */
+struct DALI_SCENE_LOADER_API ConstraintDefinition
+{
+  std::string mProperty;  ///< name of the property to constrain.
+  Index mSourceIdx;  ///< index of the node to serve as the source of the constraint.
+
+  bool operator<(const ConstraintDefinition& other) const
+  {
+    return mProperty < other.mProperty;
+  }
+
+  bool operator==(const ConstraintDefinition& other) const
+  {
+    return mSourceIdx == other.mSourceIdx && mProperty == other.mProperty;
+  }
+
+  bool operator!=(const ConstraintDefinition& other) const
+  {
+    return !operator==(other);
+  }
+};
+
+struct DALI_SCENE_LOADER_API Transforms
+{
+  MatrixStack modelStack;
+  const ViewProjection& viewProjection;
+};
+
+/**
+ * @brief Information about a skeleton and the shader that needs to be configured with it.
+ * @note Multiple skeletons shalt not share the same shader.
+ */
+struct DALI_SCENE_LOADER_API SkinningShaderConfigurationRequest
+{
+  Index mSkeletonIdx;
+  Shader mShader;
+
+  bool operator<(const SkinningShaderConfigurationRequest& other) const
+  {
+    return mShader < other.mShader;
+  }
+};
+
+/**
+ * @brief Needed to configure blend shape properties.
+ */
+struct DALI_SCENE_LOADER_API BlendshapeShaderConfigurationRequest
+{
+  std::string mNodeName;
+  Index mMeshIdx;
+  Shader mShader;
+
+  bool operator<(const BlendshapeShaderConfigurationRequest& other) const
+  {
+    return mShader < other.mShader;
+  }
+};
+
+/**
+ * @brief Request for creating a constraint, output from NodeDefinition::OnCreate.
+ */
+struct DALI_SCENE_LOADER_API ConstraintRequest
+{
+  const ConstraintDefinition* const mConstraint;  ///< Definition of the constraint to create.
+  Actor mTarget;  ///< Target of the constraint.
+};
+
+/**
+ * @brief Defines a node, consisting of a name, a transform, a size, a list of child nodes,
+ *  and slots for customization and rendering logic, which are mutually exclusive in the
+ *  current implementation.
+ */
+struct DALI_SCENE_LOADER_API NodeDefinition
+{
+public:  // TYPES
+  using Vector = std::vector<NodeDefinition>;
+
+  struct CreateParams
+  {
+  public: // input
+    const ResourceBundle& mResources;
+    Transforms& mXforms;
+
+  public: // output
+    std::vector<ConstraintRequest> mConstrainables;
+    std::vector<SkinningShaderConfigurationRequest> mSkinnables;
+    std::vector<BlendshapeShaderConfigurationRequest> mBlendshapeRequests;
+  };
+
+  class DALI_SCENE_LOADER_API Renderable
+  {
+  public: // DATA
+    Index mShaderIdx = INVALID_INDEX;
+
+  public: // METHODS
+    virtual ~Renderable() {}
+
+    virtual void RegisterResources(IResourceReceiver& receiver) const;
+    virtual void ReflectResources(IResourceReflector& reflector);
+    virtual void OnCreate(const NodeDefinition& node, CreateParams& params, Actor& actor) const;
+  };
+
+  struct CustomizationDefinition
+  {
+    std::string mTag;
+
+    Index GetChildId(const Customization::Choices& choices, const NodeDefinition& node)
+    {
+      auto choice = choices.Get(mTag);
+      return std::min(choice != Customization::NONE ? choice : 0,
+        static_cast<Index>(node.mChildren.size() - 1));
+    }
+  };
+
+  class IVisitor
+  {
+  public:
+    virtual void Start(NodeDefinition& n) = 0;
+    virtual void Finish(NodeDefinition& n) = 0;
+
+  protected:
+    ~IVisitor() {}
+  };
+
+  class IConstVisitor
+  {
+  public:
+    virtual void Start(const NodeDefinition& n) = 0;
+    virtual void Finish(const NodeDefinition& n) = 0;
+
+  protected:
+    ~IConstVisitor() {}
+  };
+
+  struct Extra
+  {
+    std::string mKey;
+    Property::Value mValue;
+
+    bool operator<(const Extra& other) const
+    {
+      return mKey < other.mKey;
+    }
+  };
+
+public:  // METHODS
+  /**
+   * @brief Creates a DALi Actor from this definition only.
+   * @note Not recursive.
+   */
+  Actor CreateActor(CreateParams& params) const;
+
+  Matrix GetLocalSpace() const;
+
+public: // DATA
+  static const std::string ORIGINAL_MATRIX_PROPERTY_NAME;
+
+  std::string mName;
+
+  Vector3 mPosition = Vector3::ZERO;
+  Quaternion mOrientation = Quaternion::IDENTITY;
+  Vector3 mScale = Vector3::ONE;
+  Vector3 mSize = Vector3::ONE;
+
+  bool mIsVisible = true;
+
+  std::unique_ptr<Renderable> mRenderable;
+  std::unique_ptr<CustomizationDefinition> mCustomization;
+  std::vector<Extra> mExtras;
+  std::vector<ConstraintDefinition> mConstraints;
+
+  std::vector<Index> mChildren;
+  Index mParentIdx = INVALID_INDEX;
+};
+
+class DALI_SCENE_LOADER_API ModelNode : public NodeDefinition::Renderable
+{
+public: // DATA
+  Vector4 mColor = Color::WHITE;
+  Index mMeshIdx = INVALID_INDEX;
+  Index mMaterialIdx = INVALID_INDEX;
+
+public: // METHODS
+  void RegisterResources(IResourceReceiver& receiver) const override;
+  void ReflectResources(IResourceReflector& reflector) override;
+  void OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const override;
+};
+
+/**
+ * @brief Parameters for an Arc node.
+ */
+class DALI_SCENE_LOADER_API ArcNode : public ModelNode
+{
+public: // DATA
+  bool mAntiAliasing = true;
+  int mArcCaps = 0;
+  float mStartAngleDegrees = .0f;
+  float mEndAngleDegrees = .0f;
+  float mRadius = .0f;
+
+public: // METHODS
+  static void GetEndVectorWithDiffAngle(float startAngle, float endAngle, Vector2& endVector);
+
+  void OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const override;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_NODE_DEFINITION_H_
diff --git a/dali-scene-loader/public-api/parse-renderer-state.cpp b/dali-scene-loader/public-api/parse-renderer-state.cpp
new file mode 100644 (file)
index 0000000..c60b1d4
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/parse-renderer-state.h"
+#include "dali/devel-api/common/map-wrapper.h"
+#include <cstring>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace RendererState
+{
+namespace
+{
+
+std::map<std::string_view, Type> COMPARISONS{
+#define DECL_COMPARISON(x) { #x, Comparison::x }
+  DECL_COMPARISON(NEVER),
+  DECL_COMPARISON(ALWAYS),
+  DECL_COMPARISON(LESS),
+  DECL_COMPARISON(GREATER),
+  DECL_COMPARISON(EQUAL),
+  DECL_COMPARISON(NOT_EQUAL),
+  DECL_COMPARISON(LESS_EQUAL),
+  DECL_COMPARISON(GREATER_EQUAL),
+#undef DECL_COMPARISON
+};
+
+Type InterpretComparison(const std::string_view& str)
+{
+  Type value = 0x0;
+  auto iFind = COMPARISONS.find(str);
+  if (iFind != COMPARISONS.end())
+  {
+    value = iFind->second;
+  }
+  return value;
+}
+
+std::map<std::string_view, Type> BLEND_FACTORS{
+#define DECL_BLEND_FACTOR(x) { #x, SceneLoader::BlendFactor::x }
+  DECL_BLEND_FACTOR(ZERO),
+  DECL_BLEND_FACTOR(ONE),
+  DECL_BLEND_FACTOR(SRC_COLOR),
+  DECL_BLEND_FACTOR(ONE_MINUS_SRC_COLOR),
+  DECL_BLEND_FACTOR(SRC_ALPHA),
+  DECL_BLEND_FACTOR(ONE_MINUS_SRC_ALPHA),
+  DECL_BLEND_FACTOR(DST_ALPHA),
+  DECL_BLEND_FACTOR(ONE_MINUS_DST_ALPHA),
+  DECL_BLEND_FACTOR(DST_COLOR),
+  DECL_BLEND_FACTOR(ONE_MINUS_DST_COLOR),
+  DECL_BLEND_FACTOR(SRC_ALPHA_SATURATE),
+  DECL_BLEND_FACTOR(CONSTANT_COLOR),
+  DECL_BLEND_FACTOR(ONE_MINUS_CONSTANT_COLOR),
+  DECL_BLEND_FACTOR(CONSTANT_ALPHA),
+  DECL_BLEND_FACTOR(ONE_MINUS_CONSTANT_ALPHA),
+#undef DECL_BLEND_FACTOR
+};
+
+Type InterpretBlendFactor(const std::string_view& str, uint8_t item)
+{
+  Type value = 0x0;
+  auto iFind = BLEND_FACTORS.find(str);
+  if (iFind != BLEND_FACTORS.end())
+  {
+    value = iFind->second << (BLEND_FACTOR_BASE_SHIFT + BLEND_FACTOR_ITEM_BITS * item);
+  }
+  return value;
+}
+
+std::map<std::string_view, Type> BUFFER_MODES{
+#define DECL_BUFFER_MODE(x) { #x, BufferMode::x }
+  DECL_BUFFER_MODE(NONE),
+  DECL_BUFFER_MODE(AUTO),
+  DECL_BUFFER_MODE(COLOR),
+  DECL_BUFFER_MODE(STENCIL),
+  DECL_BUFFER_MODE(COLOR_STENCIL),
+};
+
+Type InterpretBufferMode(const std::string_view& str)
+{
+  Type value = 0x0;
+  auto iFind = BUFFER_MODES.find(str);
+  if (iFind != BUFFER_MODES.end())
+  {
+    value = iFind->second << BUFFER_MODE_SHIFT;
+  }
+  return value;
+}
+
+std::map<std::string_view, Type(*)(const std::string_view&)> RENDERER_STATE_PROCESSORS{
+  { "DEPTH_WRITE", [](const std::string_view&) -> Type { return DEPTH_WRITE; } },
+  { "DEPTH_TEST", [](const std::string_view&) -> Type { return DEPTH_TEST; } },
+  { "CULL_FRONT", [](const std::string_view&) -> Type { return CULL_FRONT; } },
+  { "CULL_BACK", [](const std::string_view&) -> Type { return CULL_BACK; } },
+  { "ALPHA_BLEND", [](const std::string_view&) -> Type { return ALPHA_BLEND; } },
+  { "DEPTH_FUNC", [](const std::string_view& arg) -> Type {
+    Type value = (arg[0] == ':') ?
+      (InterpretComparison(std::string_view(arg.data() + 1, arg.size() - 1)) << DEPTH_FUNCTION_SHIFT) : 0x0;
+    return value;
+  } },
+  { "BLEND_SRC_RGB", [](const std::string_view& arg) -> Type {
+    Type value = (arg[0] == ':') ? InterpretBlendFactor(std::string_view(arg.data() + 1, arg.size() - 1), 0) : 0x0;
+    return value;
+  }},
+  { "BLEND_DST_RGB", [](const std::string_view& arg) -> Type {
+    Type value = (arg[0] == ':') ? InterpretBlendFactor(std::string_view(arg.data() + 1, arg.size() - 1), 1) : 0x0;
+    return value;
+  }},
+  { "BLEND_SRC_ALPHA", [](const std::string_view& arg) -> Type {
+    Type value = (arg[0] == ':') ? InterpretBlendFactor(std::string_view(arg.data() + 1, arg.size() - 1), 2) : 0x0;
+    return value;
+  }},
+  { "BLEND_DST_ALPHA", [](const std::string_view& arg) -> Type {
+    Type value = (arg[0] == ':') ? InterpretBlendFactor(std::string_view(arg.data() + 1, arg.size() - 1), 3) : 0x0;
+    return value;
+  }},
+  { "BUFFER_MODE", [](const std::string_view& arg) -> Type {
+    Type value = (arg[0] == ':') ? InterpretBufferMode(std::string_view(arg.data() + 1, arg.size() - 1)) : 0x0;
+    return value;
+  }},
+};
+
+}
+
+Type Parse(const char* string, size_t length, StringCallback onError)
+{
+  if (length == 0)
+  {
+    length = strlen(string);
+  }
+
+  Type value = 0x0;
+  auto iEnd = string + length;
+  while (string != iEnd)
+  {
+    auto iNextToken = std::find(string, iEnd, '|');
+    auto iColon = std::find(string, iNextToken, ':');
+    auto i = RENDERER_STATE_PROCESSORS.find(std::string_view(string, iColon - string));
+    if (i != RENDERER_STATE_PROCESSORS.end() && size_t(std::distance(string, iNextToken)) >= i->first.size())
+    {
+      value |= i->second(std::string_view(string + i->first.size(), iNextToken - iColon));
+    }
+    else
+    {
+      onError("Not a valid RendererState: " + std::string(string, iNextToken));
+    }
+
+    string = iNextToken + (iNextToken != iEnd);
+  }
+
+  return value;
+}
+
+}  // RendererState
+}
+}
diff --git a/dali-scene-loader/public-api/parse-renderer-state.h b/dali-scene-loader/public-api/parse-renderer-state.h
new file mode 100644 (file)
index 0000000..97792aa
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef DALI_SCENE_LOADER_INTERPRET_RENDERER_STATE_H
+#define DALI_SCENE_LOADER_INTERPRET_RENDERER_STATE_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/renderer-state.h"
+#include "dali-scene-loader/public-api/string-callback.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace RendererState
+{
+
+/*
+ * @brief Attempts to interpret a string for renderer states, which can be a combination of the following
+ *  (using '|' as a delimiter, if multiple specified):<br/>
+ *  - one of Value, exc. for NONE or those with the _BITS, _SHIFT, _MASK or _ITEMS suffix;<br/>
+ *  - DEPTH_FUNC:${one of Comparison::Type, exc. OMIT};<br/>
+ *  - BLEND_(SRC_DST)_(RGB|ALPHA):${one of BlendFactor::Type, exc. OMIT};<br/>
+ *  - BUFFER_MODE:${one of BufferMode::Type, exc. OMIT};
+ * @param string The string to parse;
+ * @param length The length of the string; If left at 0, strlen() will be called, which of
+ *   course is only suitable i the string is null-terminated.
+ * @param onError The callback to call when an error occurred.
+ * @note No other characters are allowed.
+ */
+DALI_SCENE_LOADER_API Type Parse(const char* string, size_t length = 0, StringCallback onError = DefaultErrorCallback);
+
+}
+}
+}
+
+#endif //DALI_SCENE_LOADER_INTERPRET_RENDERER_STATE_H
diff --git a/dali-scene-loader/public-api/renderer-state.cpp b/dali-scene-loader/public-api/renderer-state.cpp
new file mode 100644 (file)
index 0000000..c3888a0
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/renderer-state.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+// NOTE: values for BlendFactor aren't contiguous, hence we need a mapping.
+const Dali::BlendFactor::Type  kBlendFactors[] = {
+  Dali::BlendFactor::ZERO,
+  Dali::BlendFactor::ONE,
+  Dali::BlendFactor::SRC_COLOR,
+  Dali::BlendFactor::ONE_MINUS_SRC_COLOR,
+  Dali::BlendFactor::SRC_ALPHA,
+  Dali::BlendFactor::ONE_MINUS_SRC_ALPHA,
+  Dali::BlendFactor::DST_ALPHA,
+  Dali::BlendFactor::ONE_MINUS_DST_ALPHA,
+  Dali::BlendFactor::DST_COLOR,
+  Dali::BlendFactor::ONE_MINUS_DST_COLOR,
+  Dali::BlendFactor::SRC_ALPHA_SATURATE,
+  Dali::BlendFactor::CONSTANT_COLOR,
+  Dali::BlendFactor::ONE_MINUS_CONSTANT_COLOR,
+  Dali::BlendFactor::CONSTANT_ALPHA,
+  Dali::BlendFactor::ONE_MINUS_CONSTANT_ALPHA,
+};
+}
+
+namespace RendererState
+{
+#define RENDERER_SET_PROPERTY(name, value) renderer.SetProperty(Renderer::Property::name, (value))
+
+void Apply(Type rendererState, Renderer& renderer)
+{
+  RENDERER_SET_PROPERTY(DEPTH_WRITE_MODE, MaskMatch(rendererState, DEPTH_WRITE) ? DepthWriteMode::ON : DepthWriteMode::OFF);
+  RENDERER_SET_PROPERTY(DEPTH_TEST_MODE, MaskMatch(rendererState, DEPTH_TEST) ? DepthTestMode::ON : DepthTestMode::OFF);
+
+  RENDERER_SET_PROPERTY(BLEND_MODE, MaskMatch(rendererState, ALPHA_BLEND) ? BlendMode::ON : BlendMode::OFF);
+
+  const bool cullBack = MaskMatch(rendererState, CULL_BACK);
+  RENDERER_SET_PROPERTY(FACE_CULLING_MODE, MaskMatch(rendererState, CULL_FRONT) ?
+    (cullBack ? FaceCullingMode::FRONT_AND_BACK : FaceCullingMode::FRONT) :
+    (cullBack ? FaceCullingMode::BACK : FaceCullingMode::NONE));
+
+  if (auto depthFunc = (rendererState & DEPTH_FUNCTION_MASK) >> DEPTH_FUNCTION_SHIFT)
+  {
+    RENDERER_SET_PROPERTY(DEPTH_FUNCTION, static_cast<DepthFunction::Type>(depthFunc - 1));
+  }
+
+  if (auto blendFactors = (rendererState & BLEND_FACTOR_MASK) >> BLEND_FACTOR_BASE_SHIFT)
+  {
+    if (auto srcRgb = (blendFactors & BLEND_FACTOR_ITEM_MASK))
+    {
+      RENDERER_SET_PROPERTY(BLEND_FACTOR_SRC_RGB, kBlendFactors[static_cast<BlendFactor::Type>(srcRgb - 1)]);
+    }
+
+    blendFactors >>= BLEND_FACTOR_ITEM_BITS;
+    if (auto dstRgb = (blendFactors & BLEND_FACTOR_ITEM_MASK))
+    {
+      RENDERER_SET_PROPERTY(BLEND_FACTOR_DEST_RGB, kBlendFactors[static_cast<BlendFactor::Type>(dstRgb - 1)]);
+    }
+
+    blendFactors >>= BLEND_FACTOR_ITEM_BITS;
+    if (auto srcAlpha = (blendFactors & BLEND_FACTOR_ITEM_MASK))
+    {
+      RENDERER_SET_PROPERTY(BLEND_FACTOR_SRC_ALPHA, kBlendFactors[static_cast<BlendFactor::Type>(srcAlpha - 1)]);
+    }
+
+    blendFactors >>= BLEND_FACTOR_ITEM_BITS;
+    if (auto dstAlpha = (blendFactors & BLEND_FACTOR_ITEM_MASK))
+    {
+      RENDERER_SET_PROPERTY(BLEND_FACTOR_DEST_ALPHA, kBlendFactors[static_cast<BlendFactor::Type>(dstAlpha - 1)]);
+    }
+  }
+
+  if (auto bufferMode = (rendererState & BUFFER_MODE_MASK) >> BUFFER_MODE_SHIFT)
+  {
+    RENDERER_SET_PROPERTY(RENDER_MODE, static_cast<RenderMode::Type>(bufferMode - 1));
+  }
+}
+
+} // RendererState
+
+}
+}
diff --git a/dali-scene-loader/public-api/renderer-state.h b/dali-scene-loader/public-api/renderer-state.h
new file mode 100644 (file)
index 0000000..dc1bf63
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef DALI_SCENE_LOADER_RENDERER_STATE_H
+#define DALI_SCENE_LOADER_RENDERER_STATE_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/rendering/renderer.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/*
+ * @brief Contains values for comparison functions used in depth and stencil testing.
+ * @note Relative order of members must match DepthFunction::Type and StencilFunction::Type.
+ */
+struct DALI_SCENE_LOADER_API Comparison
+{
+  enum Type
+  {
+    OMIT,  // not specified; will not be set.
+    NEVER,
+    ALWAYS,
+    LESS,
+    GREATER,
+    EQUAL,
+    NOT_EQUAL,
+    LESS_EQUAL,
+    GREATER_EQUAL
+  };
+
+  Comparison() = delete;
+};
+
+/*
+ * @brief Determines the blend factor used.
+ * @note Relative order of members must match BlendFactor::Type.
+ */
+struct DALI_SCENE_LOADER_API BlendFactor
+{
+  enum Type
+  {
+    OMIT,  // not specified - will not be updated
+    ZERO,
+    ONE,  // default for source alpha
+    SRC_COLOR,
+    ONE_MINUS_SRC_COLOR,
+    SRC_ALPHA,  // default for source RGB
+    ONE_MINUS_SRC_ALPHA,  // default for destination RGB and destination alpha
+    DST_ALPHA,
+    ONE_MINUS_DST_ALPHA,
+    DST_COLOR,
+    ONE_MINUS_DST_COLOR,
+    SRC_ALPHA_SATURATE,
+    CONSTANT_COLOR,
+    ONE_MINUS_CONSTANT_COLOR,
+    CONSTANT_ALPHA,
+    ONE_MINUS_CONSTANT_ALPHA,
+  };
+
+  BlendFactor() = delete;
+};
+
+/*
+ * @brief Determines which buffers shall the Renderer write into.
+ * @note Relative order of members must match RenderMode::Type.
+ */
+struct DALI_SCENE_LOADER_API BufferMode
+{
+  enum Type
+  {
+    OMIT,  ///< not specified - will not be updated
+    NONE,  ///< Don’t write to either color or stencil buffer (But will potentially render to depth buffer).
+    AUTO,  ///< Writes are managed by the Actor Clipping API. This is DALi's default.
+    COLOR,  ///< Ignore stencil properties.  Write to the color buffer.
+    STENCIL,  ///< Use the stencil properties. Do not write to the color buffer.
+    COLOR_STENCIL  ///< Use the stencil properties AND Write to the color buffer.
+  };
+
+  BufferMode() = delete;
+};
+
+/*
+ * @brief Contains values and functionality for configuring Renderers.
+ */
+namespace RendererState
+{
+
+using Type = uint32_t;  // 8 bits reserved for flags, 4 * 4 bit for blend factors, 4 bits for depth function
+
+enum DALI_SCENE_LOADER_API Value : Type
+{
+  NONE = 0x0,
+
+  DEPTH_WRITE = 0x01,
+  DEPTH_TEST = 0x02,
+
+  CULL_FRONT = 0x04,
+  CULL_BACK = 0x08,
+
+  ALPHA_BLEND = 0x10,
+
+  DEPTH_FUNCTION_SHIFT = 6,
+  DEPTH_FUNCTION_BITS = 4,
+  DEPTH_FUNCTION_MASK = ((1 << DEPTH_FUNCTION_BITS) - 1) << DEPTH_FUNCTION_SHIFT,
+
+  BLEND_FACTOR_BASE_SHIFT = DEPTH_FUNCTION_SHIFT + DEPTH_FUNCTION_BITS,
+  BLEND_FACTOR_ITEM_BITS = 4,
+  BLEND_FACTOR_ITEMS = 4,
+  BLEND_FACTOR_BITS = BLEND_FACTOR_ITEM_BITS * BLEND_FACTOR_ITEMS,
+  BLEND_FACTOR_MASK = ((1 << BLEND_FACTOR_BITS) - 1) << BLEND_FACTOR_BASE_SHIFT,
+  BLEND_FACTOR_ITEM_MASK = (1 << BLEND_FACTOR_ITEM_BITS) - 1,  // after rshifting by BLEND_FACTOR_BASE_SHIFT
+
+  // Buffer mode is DALi's RenderMode, just to avoid too much conflation.
+  BUFFER_MODE_BITS = 3u,
+  BUFFER_MODE_SHIFT = 32u - BUFFER_MODE_BITS,  // from end
+  BUFFER_MODE_MASK = ((1u << BUFFER_MODE_BITS) - 1u) << BUFFER_MODE_SHIFT,
+
+  DEFAULT = DEPTH_WRITE | DEPTH_TEST | CULL_BACK | (Comparison::LESS_EQUAL << DEPTH_FUNCTION_SHIFT),
+};
+
+/*
+ * @brief Encodes the given blend factors into a RenderMode value, maskable into other options,
+ *  passable into ApplyRenderMode().
+ */
+inline
+DALI_SCENE_LOADER_API constexpr uint32_t FromBlendFactors(BlendFactor::Type srcRgb, BlendFactor::Type destRgb,
+  BlendFactor::Type srcAlpha, BlendFactor::Type destAlpha)
+{
+  return (srcRgb | (destRgb << BLEND_FACTOR_ITEM_BITS) | (srcAlpha << (BLEND_FACTOR_ITEM_BITS * 2)) |
+    (destAlpha << (BLEND_FACTOR_ITEM_BITS * 3))) << BLEND_FACTOR_BASE_SHIFT;
+}
+
+/*
+ * @brief Applies the settings encoded in @a rendererState, to a @a renderer.
+ * @note Depth function is only set if not Comparison::OMIT.
+ * @note Blend factors are only set if not BlendFactor::OMIT.
+ * @note Buffer mode is only set is not BufferMode::OMIT.
+ */
+DALI_SCENE_LOADER_API void Apply(Type rendererState, Renderer& renderer);
+
+} // RendererState
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_RENDERER_STATE_H
diff --git a/dali-scene-loader/public-api/resource-bundle.cpp b/dali-scene-loader/public-api/resource-bundle.cpp
new file mode 100644 (file)
index 0000000..9ff10f6
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include "dali-scene-loader/public-api/resource-bundle.h"
+
+// EXTERNAL
+#include "dali/public-api/rendering/sampler.h"
+#include "dali-toolkit/public-api/image-loader/sync-image-loader.h"
+#include <fstream>
+#include <istream>
+#include <cstring>
+#include <fstream>
+
+namespace Dali
+{
+using namespace Toolkit;
+
+namespace SceneLoader
+{
+namespace
+{
+
+const char* const RESOURCE_TYPE_NAMES[] = {
+  "Environment",
+  "Shader",
+  "Mesh",
+  "Material",
+};
+
+}  // nonamespace
+
+const char* GetResourceTypeName(ResourceType::Value type)
+{
+  return RESOURCE_TYPE_NAMES[static_cast<int>(type)];
+}
+
+ResourceRefCounts ResourceBundle::CreateRefCounter() const
+{
+  ResourceRefCounts refCounts(4);
+  refCounts[ResourceType::Environment].Resize(mEnvironmentMaps.size(), 0u);
+  refCounts[ResourceType::Shader].Resize(mShaders.size(), 0u);
+  refCounts[ResourceType::Mesh].Resize(mMeshes.size(), 0u);
+  refCounts[ResourceType::Material].Resize(mMaterials.size(), 0u);
+  return refCounts;
+}
+
+void ResourceBundle::CountEnvironmentReferences(ResourceRefCounts& refCounts) const
+{
+  auto& environmentRefCounts = refCounts[ResourceType::Environment];
+
+  const auto& materialRefs = refCounts[ResourceType::Material];
+  for (uint32_t i = 0, iEnd = materialRefs.Size(); i != iEnd; ++i)
+  {
+    if (materialRefs[i] > 0)
+    {
+      ++environmentRefCounts[mMaterials[i].first.mEnvironmentIdx];
+    }
+  }
+}
+
+void ResourceBundle::LoadResources(const ResourceRefCounts& refCounts, PathProvider pathProvider, Options::Type options)
+{
+  const auto kForceLoad = MaskMatch(options, Options::ForceReload);
+  const auto kKeepUnused = MaskMatch(options, Options::KeepUnused);
+
+  const auto& refCountEnvMaps = refCounts[ResourceType::Environment];
+  auto environmentsPath = pathProvider(ResourceType::Environment);
+  for (uint32_t i = 0, iEnd = refCountEnvMaps.Size(); i != iEnd; ++i)
+  {
+    auto refCount = refCountEnvMaps[i];
+    auto& iEnvMap = mEnvironmentMaps[i];
+    if (refCount > 0 && (kForceLoad || !iEnvMap.second.IsLoaded()))
+    {
+      auto raw = iEnvMap.first.LoadRaw(environmentsPath);
+      iEnvMap.second = iEnvMap.first.Load(std::move(raw));
+    }
+    else if (!kKeepUnused && refCount == 0 && iEnvMap.second.IsLoaded())
+    {
+      iEnvMap.second.mDiffuse = Texture();
+      iEnvMap.second.mSpecular = Texture();
+    }
+  }
+
+  const auto& refCountShaders = refCounts[ResourceType::Shader];
+  auto shadersPath = pathProvider(ResourceType::Shader);
+  for (uint32_t i = 0, iEnd = refCountShaders.Size(); i != iEnd; ++i)
+  {
+    auto refCount = refCountShaders[i];
+    auto& iShader = mShaders[i];
+    if (refCount > 0 && (kForceLoad || !iShader.second))
+    {
+      auto raw = iShader.first.LoadRaw(shadersPath);
+      iShader.second = iShader.first.Load(std::move(raw));
+    }
+    else if(!kKeepUnused && refCount == 0 && iShader.second)
+    {
+      iShader.second = Shader();
+    }
+  }
+
+  const auto& refCountMeshes = refCounts[ResourceType::Mesh];
+  auto modelsPath = pathProvider(ResourceType::Mesh);
+  for (uint32_t i = 0, iEnd = refCountMeshes.Size(); i != iEnd; ++i)
+  {
+    auto refCount = refCountMeshes[i];
+    auto& iMesh = mMeshes[i];
+    if (refCount > 0 && (kForceLoad || !iMesh.second.geometry))
+    {
+      auto raw = iMesh.first.LoadRaw(modelsPath);
+      iMesh.second = iMesh.first.Load(std::move(raw));
+    }
+    else if (!kKeepUnused && refCount == 0 && iMesh.second.geometry)
+    {
+      iMesh.second.geometry = Geometry();
+    }
+  }
+
+  const auto& refCountMaterials = refCounts[ResourceType::Material];
+  auto imagesPath = pathProvider(ResourceType::Material);
+  for (uint32_t i = 0, iEnd = refCountMaterials.Size(); i != iEnd; ++i)
+  {
+    auto refCount = refCountMaterials[i];
+    auto& iMaterial = mMaterials[i];
+    if (refCount > 0 && (kForceLoad || !iMaterial.second))
+    {
+      auto raw = iMaterial.first.LoadRaw(imagesPath);
+      iMaterial.second = iMaterial.first.Load(mEnvironmentMaps, std::move(raw));
+    }
+    else if (!kKeepUnused && refCount == 0 && iMaterial.second)
+    {
+      iMaterial.second = TextureSet();
+    }
+  }
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/resource-bundle.h b/dali-scene-loader/public-api/resource-bundle.h
new file mode 100644 (file)
index 0000000..16860ec
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef DALI_SCENE_LOADER_RESOURCE_BUNDLE_H_
+#define DALI_SCENE_LOADER_RESOURCE_BUNDLE_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL
+#include "dali-scene-loader/public-api/mesh-definition.h"
+#include "dali-scene-loader/public-api/material-definition.h"
+#include "dali-scene-loader/public-api/environment-definition.h"
+#include "dali-scene-loader/public-api/shader-definition.h"
+#include "dali-scene-loader/public-api/skeleton-definition.h"
+
+// EXTERNAL
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/public-api/rendering/shader.h"
+#include "dali/public-api/rendering/texture-set.h"
+#include <memory>
+#include <functional>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/*
+ * @brief The types of resources that .dli may define.
+ */
+struct DALI_SCENE_LOADER_API ResourceType
+{
+  enum Value
+  {
+    Environment,
+    Shader,
+    Mesh,
+    Material,
+  };
+
+  ResourceType() = delete;
+};
+
+/*
+ * @return The string value corresponding to the given resource @a type.
+ */
+DALI_SCENE_LOADER_API const char* GetResourceTypeName(ResourceType::Value type);
+
+using ResourceRefCounts = std::vector<Vector<uint32_t>>;
+
+/*
+ * @brief Stores all resource definitions along with the DALi resources that
+ *  could be created from them, directly indexible into with values from a dli
+ *  document.
+ */
+class DALI_SCENE_LOADER_API ResourceBundle
+{
+public:
+  struct Options
+  {
+    using Type = uint8_t;
+
+    enum Value : Type
+    {
+      None = 0,
+      ForceReload = NthBit(0),  ///< Load resources [again] even if they were already loaded.
+      KeepUnused = NthBit(1)  ///<s Don't reset handles to resources that had a 0 reference count.
+    };
+  };
+
+  using PathProvider = std::function<std::string(ResourceType::Value)>;
+
+  ResourceBundle() = default;
+
+  ResourceBundle(const ResourceBundle&) = delete;
+  ResourceBundle& operator=(const ResourceBundle&) = delete;
+
+  ResourceBundle(ResourceBundle&&) = default;
+  ResourceBundle& operator=(ResourceBundle&&) = default;
+
+  /*
+   * @return A ResourceRefCounts object with the correct number of entries for
+   *  all resource types (based on the various resource definition vectors),
+   *  with all reference counts set to 0.
+   */
+  ResourceRefCounts CreateRefCounter() const;
+
+  /*
+   * @brief Based on a ResourceRefCounts, and more specifically the reference
+   *  count of materials therein, it will calculate the reference count of
+   *  environment maps.
+   */
+  void CountEnvironmentReferences(ResourceRefCounts& refCounts) const;
+
+  /*
+   * @brief Performs the loading of all resources based on their respective
+   *  reference count in @a refCounts. Resources that had a non-zero ref count will be
+   *  loaded unless we already have a handle to them (OR the ForceReload option was specified).
+   *  Any handles we have to resources that come in with a zero ref count will be reset,
+   *  UNLESS the KeepUnused option was specified.
+   */
+  void LoadResources(const ResourceRefCounts& refCounts,
+    PathProvider pathProvider,
+    Options::Type options = Options::None);
+
+public: // DATA
+  EnvironmentDefinition::Vector mEnvironmentMaps;
+  ShaderDefinition::Vector mShaders;
+  MeshDefinition::Vector mMeshes;
+  MaterialDefinition::Vector mMaterials;
+
+  SkeletonDefinition::Vector mSkeletons;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_RESOURCE_BUNDLE_H_
diff --git a/dali-scene-loader/public-api/scene-definition.cpp b/dali-scene-loader/public-api/scene-definition.cpp
new file mode 100644 (file)
index 0000000..0bafc3b
--- /dev/null
@@ -0,0 +1,1236 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL
+#include "dali/public-api/animation/constraints.h"
+#include "dali/devel-api/common/map-wrapper.h"
+
+// INTERNAL
+#include "dali-scene-loader/public-api/scene-definition.h"
+#include "dali-scene-loader/public-api/blend-shape-details.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include "dali-scene-loader/public-api/skinning-details.h"
+
+//#define DEBUG_SCENE_DEFINITION
+//#define DEBUG_JOINTS
+
+#if defined(DEBUG_SCENE_DEFINITION) || defined(DEBUG_JOINTS)
+#define DEBUG_ONLY(x) x
+#else
+#define DEBUG_ONLY(x)
+#endif
+
+#define LOGD(x) DEBUG_ONLY(printf x ; printf("\n"); fflush(stdout))
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+
+const std::string JOINT_MATRIX{ "jointMatrix" };
+
+const std::map<Property::Type, Constraint(*)(Actor&, Property::Index)> sConstraintFactory = {
+  {
+    Property::Type::BOOLEAN,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<bool>(a, i, [](bool& current, const PropertyInputContainer& inputs) {
+        current = inputs[0]->GetBoolean();
+      });
+    }
+  },
+  {
+    Property::Type::INTEGER,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<int>(a, i, [](int& current, const PropertyInputContainer& inputs) {
+        current = inputs[0]->GetInteger();
+      });
+    }
+  },
+  {
+    Property::Type::FLOAT,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<float>(a, i, EqualToConstraint());
+    }
+  },
+  {
+    Property::Type::VECTOR2,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<Vector2>(a, i, EqualToConstraint());
+    }
+  },
+  {
+    Property::Type::VECTOR3,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<Vector3>(a, i, EqualToConstraint());
+    }
+  },
+  {
+    Property::Type::VECTOR4,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<Vector4>(a, i, EqualToConstraint());
+    }
+  },
+  {
+    Property::Type::MATRIX,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<Matrix>(a, i, EqualToConstraint());
+    }
+  },
+  {
+    Property::Type::MATRIX3,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<Matrix3>(a, i, EqualToConstraint());
+    }
+  },
+  {
+    Property::Type::ROTATION,
+    [](Actor& a, Property::Index i) {
+      return Constraint::New<Quaternion>(a, i, EqualToConstraint());
+    }
+  },
+};
+
+struct ResourceReflector : IResourceReflector
+{
+  Index* iMesh = nullptr;
+  Index* iShader = nullptr;
+
+  void Reflect(ResourceType::Value type, Index& id)
+  {
+    switch (type)
+    {
+    case ResourceType::Shader:
+      DALI_ASSERT_ALWAYS(!iShader && "Shader index already assigned!");
+      iShader = &id;
+      break;
+
+    case ResourceType::Mesh:
+      DALI_ASSERT_ALWAYS(!iMesh && "Mesh index already assigned!");
+      iMesh = &id;
+      break;
+
+    default:  // Other resource types are not relevant to the problem at hand.
+      break;
+    }
+  }
+};
+
+
+#ifdef DEBUG_JOINTS
+const char* JOINT_DEBUG_VSH = "#version 300 es\n"
+DALI_COMPOSE_SHADER(
+  precision mediump float;
+  uniform mat4 uMvpMatrix;
+  in vec3 aPosition;
+  in float aColor;
+  flat out float vColor;
+  void main() {
+    vColor = aColor;
+    gl_Position = uMvpMatrix * vec4(aPosition, 1.0);
+  });
+
+const char* JOINT_DEBUG_FSH = "#version 300 es\n"
+DALI_COMPOSE_SHADER(
+  precision mediump float;
+  flat in float vColor;
+  out vec4 FragColor;
+  void main() {
+    vec3 rgb = vec3(fract(vColor), fract(vColor * 0.00390625), fract(vColor * 0.00390625 * 0.00390625));
+    FragColor = vec4(rgb, 1.);
+  });
+
+Shader sJointDebugShader;
+int sNumScenes = 0;
+
+void EnsureJointDebugShaderCreated()
+{
+  if (0 == sNumScenes)
+  {
+    sJointDebugShader = Shader::New(JOINT_DEBUG_VSH, JOINT_DEBUG_FSH);
+  }
+  ++sNumScenes;
+}
+
+void AddJointDebugVisual(Actor aJoint)
+{
+  Property::Map attribs;
+  attribs["aPosition"] = Property::Type::VECTOR3;
+  attribs["aColor"] = Property::Type::FLOAT;
+
+  PropertyBuffer vbo = PropertyBuffer::New(attribs);
+
+  struct Vertex
+  {
+    Vector3 pos;
+    float color;
+  } vertices[] = {
+    { Vector3::ZERO, .999f + .999f * 256.f + .999f * 256.f * 256.f },
+    { Vector3::XAXIS, .999f },
+    { Vector3::YAXIS, .999f * 256.f },
+    { Vector3::ZAXIS, .999f * 256.f * 256.f },
+  };
+
+  vbo.SetData(&vertices, std::extent<decltype(vertices)>::value);
+
+  uint16_t indices[] = { 0, 1, 0, 2, 0, 3 };
+
+  Geometry geo = Geometry::New();
+  geo.AddVertexBuffer(vbo);
+  geo.SetIndexBuffer(indices, std::extent<decltype(indices)>::value);
+  geo.SetType(Geometry::LINES);
+
+  Renderer r = Renderer::New(geo, sJointDebugShader);
+  aJoint.AddRenderer(r);
+
+  aJoint.SetVisible(true);
+}
+#endif  //DEBUG_JOINTS
+
+class ActorCreatorVisitor : public NodeDefinition::IConstVisitor
+{
+public:
+  ActorCreatorVisitor(NodeDefinition::CreateParams& params)
+  :  mCreationContext(params)
+  {}
+
+  void Start(const NodeDefinition& n)
+  {
+    mCreationContext.mXforms.modelStack.Push(n.GetLocalSpace());
+
+    Actor a = n.CreateActor(mCreationContext);
+    if (!mActorStack.empty())
+    {
+      mActorStack.back().Add(a);
+    }
+    else
+    {
+      mRoot = a;
+    }
+    mActorStack.push_back(a);
+  }
+
+  void Finish(const NodeDefinition& n)
+  {
+    mActorStack.pop_back();
+    mCreationContext.mXforms.modelStack.Pop();
+  }
+
+  Actor GetRoot() const
+  {
+    return mRoot;
+  }
+
+private:
+  NodeDefinition::CreateParams& mCreationContext;
+  std::vector<Actor> mActorStack;
+  Actor mRoot;
+};
+
+bool IsAncestor(const SceneDefinition& scene, Index ancestor, Index node, Index rootHint = INVALID_INDEX)
+{
+  bool isAncestor = false;
+  while (node != rootHint && !isAncestor)
+  {
+    node = scene.GetNode(node)->mParentIdx;
+    isAncestor = ancestor == node;
+  }
+  return isAncestor;
+}
+
+void InsertUniqueSorted(std::vector<Index>& data, Index value)
+{
+  auto iInsert = std::lower_bound(data.begin(), data.end(), value);
+  if (iInsert == data.end() || *iInsert != value)
+  {
+    data.insert(iInsert, value);
+  }
+}
+
+void RemoveFromSorted(std::vector<Index>& data, Index value)
+{
+  auto iRemove = std::lower_bound(data.begin(), data.end(), value);
+  if (iRemove != data.end() && *iRemove == value)
+  {
+    data.erase(iRemove);
+  }
+}
+
+Property::Index ConfigureJointMatrix(Actor actor, Actor ancestor, Property::Index propJointMatrix)
+{
+  Actor parent = actor.GetParent();
+  if (parent != ancestor)
+  {
+    propJointMatrix = ConfigureJointMatrix(parent, ancestor, propJointMatrix);
+  }
+
+  auto myPropJointMatrix = actor.GetPropertyIndex(JOINT_MATRIX);
+  if (myPropJointMatrix == Property::INVALID_INDEX)
+  {
+    myPropJointMatrix = actor.RegisterProperty(JOINT_MATRIX, Matrix{ false });
+    Constraint constraint = Constraint::New<Matrix>(actor, propJointMatrix,
+      [](Matrix& output, const PropertyInputContainer& inputs)
+      {
+        Matrix jointMatrix{ false };
+        jointMatrix.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3());
+
+        Matrix::Multiply(output, jointMatrix, inputs[2]->GetMatrix());
+      });
+    constraint.AddSource(Source{ actor, Actor::Property::ORIENTATION });
+    constraint.AddSource(Source{ actor, Actor::Property::POSITION });
+    constraint.AddSource(Source{ parent, propJointMatrix });
+    constraint.Apply();
+  }
+
+  return myPropJointMatrix;
+}
+
+void SortAndDeduplicateSkinningRequests(std::vector<SkinningShaderConfigurationRequest>& requests)
+{
+  // Sort requests by shaders.
+  std::sort(requests.begin(), requests.end());
+
+  // Remove duplicates.
+  auto i = requests.begin();
+  auto iEnd = requests.end();
+  Shader s = i->mShader;
+  Index skeletonIdx = i->mSkeletonIdx;
+  ++i;
+  do
+  {
+    // Multiple identical shader instances are removed.
+    while (i != iEnd && i->mShader == s)
+    {
+      // Cannot have multiple skeletons input to the same shader.
+      // NOTE: DliModel now makes sure this doesn't happen.
+      DALI_ASSERT_ALWAYS(i->mSkeletonIdx == skeletonIdx &&
+        "Skinning shader must not be shared between different skeletons.");
+
+      i->mShader = Shader();
+      ++i;
+    }
+
+    if (i == iEnd)
+    {
+      break;
+    }
+    s = i->mShader;
+    skeletonIdx = i->mSkeletonIdx;
+    ++i;
+  } while (true);
+
+  requests.erase(std::remove_if(requests.begin(), requests.end(), [](const SkinningShaderConfigurationRequest& sscr)
+  {
+    return !sscr.mShader;
+  }), requests.end());
+}
+
+void ConfigureBoneMatrix(const Matrix& ibm, Actor joint, Shader& shader, Index& boneIdx)
+{
+  // Register bone transform on shader.
+  char propertyNameBuffer[32];
+  snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Skinning::BONE_UNIFORM_NAME.c_str(), boneIdx);
+  DALI_ASSERT_DEBUG(shader.GetPropertyIndex(propertyNameBuffer) == Property::INVALID_INDEX);
+  auto propBoneXform = shader.RegisterProperty(propertyNameBuffer, Matrix{ false });
+
+  // Constrain bone matrix to joint transform.
+  Constraint constraint = Constraint::New<Matrix>(shader, propBoneXform,
+    [ibm](Matrix& output, const PropertyInputContainer& inputs)
+    {
+      Matrix::Multiply(output, ibm, inputs[0]->GetMatrix());
+    });
+
+  auto propJointMatrix = joint.GetPropertyIndex(JOINT_MATRIX);
+  constraint.AddSource(Source{ joint, propJointMatrix });
+  constraint.Apply();
+
+  ++boneIdx;
+}
+
+template <class Visitor, class SceneDefinition>
+void VisitInternal(Index iNode, const Customization::Choices& choices, Visitor& v, SceneDefinition& sd)
+{
+  auto& node = *sd.GetNode(iNode);
+  v.Start(node);
+
+  if (node.mCustomization)
+  {
+    if (!node.mChildren.empty())
+    {
+      auto choice = choices.Get(node.mCustomization->mTag);
+      Index i = std::min(choice != Customization::NONE ? choice : 0, static_cast<Index>(node.mChildren.size() - 1));
+      sd.Visit(node.mChildren[i], choices, v);
+    }
+  }
+  else
+  {
+    for (auto i : node.mChildren)
+    {
+      sd.Visit(i, choices, v);
+    }
+  }
+
+  v.Finish(node);
+}
+
+} // nonamespace
+
+SceneDefinition::SceneDefinition()
+{
+  mNodes.reserve(128);
+
+#ifdef DEBUG_JOINTS
+  EnsureJointDebugShaderCreated();
+#endif
+}
+
+SceneDefinition::SceneDefinition(SceneDefinition&& other)
+:  mNodes(std::move(other.mNodes)),
+  mRootNodeIds(std::move(other.mRootNodeIds))
+{
+#ifdef DEBUG_JOINTS
+  EnsureJointDebugShaderCreated();
+#endif
+}
+
+SceneDefinition::~SceneDefinition()
+{
+#ifdef DEBUG_JOINTS
+  --sNumScenes;
+  if (sNumScenes == 0)
+  {
+    sJointDebugShader = Shader();
+  }
+#endif
+}
+
+uint32_t SceneLoader::SceneDefinition::AddRootNode(Index iNode)
+{
+  if (iNode < mNodes.size())
+  {
+    uint32_t result = mRootNodeIds.size();
+    mRootNodeIds.push_back(iNode);
+    return result;
+  }
+  else
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to add new root with node " << iNode << " -- index out of bounds.";
+    return -1;
+  }
+}
+
+const std::vector<Index>& SceneDefinition::GetRoots() const
+{
+  return mRootNodeIds;
+}
+
+void SceneDefinition::RemoveRootNode(Index iRoot)
+{
+  if (iRoot < mRootNodeIds.size())
+  {
+    mRootNodeIds.erase(mRootNodeIds.begin() + iRoot);
+  }
+  else
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to remove root " << iRoot << " -- index out of bounds.";
+  }
+}
+
+uint32_t SceneDefinition::GetNodeCount() const
+{
+  return mNodes.size();
+}
+
+const NodeDefinition* SceneDefinition::GetNode(Index iNode) const
+{
+  return mNodes[iNode].get();
+}
+
+NodeDefinition* SceneDefinition::GetNode(Index iNode)
+{
+  return mNodes[iNode].get();
+}
+
+void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IVisitor& v)
+{
+  VisitInternal(iNode, choices, v, *this);
+}
+
+void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IConstVisitor& v) const
+{
+  VisitInternal(iNode, choices, v, *this);
+}
+
+void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choices& choices, ResourceRefCounts& refCounts) const
+{
+  struct RefCounter : IResourceReceiver
+  {
+    ResourceRefCounts* refCounts;
+
+    void Register(ResourceType::Value type, Index id)
+    {
+      ++(*refCounts)[type][id];
+    }
+  };
+
+  struct : NodeDefinition::IConstVisitor
+  {
+    RefCounter counter;
+
+    void Start(const NodeDefinition& n)
+    {
+      if (n.mRenderable)
+      {
+        n.mRenderable->RegisterResources(counter);
+      }
+    }
+
+    void Finish(const NodeDefinition& n)
+    {}
+
+  } refCounterVisitor;
+  refCounterVisitor.counter.refCounts = &refCounts;
+
+  Visit(iNode, choices, refCounterVisitor);
+}
+
+Actor SceneDefinition::CreateNodes(Index iNode, const Customization::Choices & choices,
+  NodeDefinition::CreateParams& params) const
+{
+  ActorCreatorVisitor actorCreatorVisitor(params);
+
+  Visit(iNode, choices, actorCreatorVisitor);
+
+  return actorCreatorVisitor.GetRoot();
+}
+
+void SceneDefinition::GetCustomizationOptions(const Customization::Choices& choices,
+  Customization::Map& outCustomizationOptions, Customization::Choices* outMissingChoices) const
+{
+  struct : NodeDefinition::IConstVisitor
+  {
+    const Customization::Choices* choices;  // choices that we know about.
+    Customization::Map* options;  // tags are registered here. NO OWNERSHIP.
+    Customization::Choices* missingChoices;  // tags will be registered with the default 0. NO OWNERSHIP.
+
+    void Start(const NodeDefinition& n)
+    {
+      if (n.mCustomization)
+      {
+        const std::string& tag = n.mCustomization->mTag;
+        if (missingChoices != nullptr && choices->Get(tag) == Customization::NONE)
+        {
+          missingChoices->Set(tag, 0);
+        }
+
+        auto customization = options->Get(tag);
+        if (!customization)
+        {
+          customization = options->Set(tag, {});
+        }
+        customization->nodes.push_back(n.mName);
+        customization->numOptions = std::max(customization->numOptions,
+          static_cast<uint32_t>(n.mChildren.size()));
+      }
+    }
+
+    void Finish(const NodeDefinition& n)
+    {}
+
+  } customizationRegistrationVisitor;
+  customizationRegistrationVisitor.choices = &choices;
+  customizationRegistrationVisitor.options = &outCustomizationOptions;
+  customizationRegistrationVisitor.missingChoices = outMissingChoices;
+
+  for (auto i : mRootNodeIds)
+  {
+    Visit(i, choices, customizationRegistrationVisitor);
+  }
+}
+
+NodeDefinition* SceneDefinition::AddNode(std::unique_ptr<NodeDefinition>&& nodeDef)
+{
+  if (FindNode(nodeDef->mName))
+  {
+    return nullptr;
+  }
+
+  // add next index (to which we're about to push) as a child to the designated parent, if any.
+  if (nodeDef->mParentIdx != INVALID_INDEX)
+  {
+    mNodes[nodeDef->mParentIdx]->mChildren.push_back(mNodes.size());
+  }
+
+  mNodes.push_back(std::move(nodeDef));
+
+  return mNodes.back().get();
+}
+
+bool SceneDefinition::ReparentNode(const std::string& name, const std::string& newParentName, Index siblingOrder)
+{
+  LOGD(("reparenting %s to %s @ %d", name.c_str(), newParentName.c_str(), siblingOrder));
+
+  std::unique_ptr<NodeDefinition>* nodePtr = nullptr;
+  std::unique_ptr<NodeDefinition>* newParentPtr = nullptr;
+  if (!FindNode(name, &nodePtr) || !FindNode(newParentName, &newParentPtr))
+  {
+    return false;
+  }
+
+  auto& node = *nodePtr;
+  auto iNode = std::distance(mNodes.data(), nodePtr);
+
+  DEBUG_ONLY(auto dumpNode = [](NodeDefinition const& n) {
+    std::ostringstream stream;
+    stream << n.mName << " (" << n.mParentIdx << "):";
+    for (auto i : n.mChildren)
+    {
+      stream << i << ", ";
+    }
+    LOGD(("%s", stream.str().c_str()));
+  };)
+
+  // Remove node from children of previous parent (if any).
+  if (node->mParentIdx != INVALID_INDEX)
+  {
+    LOGD(("old parent:"));
+    DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
+
+    auto& children = mNodes[node->mParentIdx]->mChildren;
+    children.erase(std::remove(children.begin(), children.end(), iNode), children.end());
+
+    DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
+  }
+
+  // Register node to new parent.
+  LOGD(("new parent:"));
+  DEBUG_ONLY(dumpNode(**newParentPtr);)
+  auto& children = (*newParentPtr)->mChildren;
+  if (siblingOrder > children.size())
+  {
+    siblingOrder = children.size();
+  }
+  children.insert(children.begin() + siblingOrder, 1, iNode);
+  DEBUG_ONLY(dumpNode(**newParentPtr);)
+
+  // Update parent index.
+  LOGD(("node:"));
+  DEBUG_ONLY(dumpNode(*node);)
+  auto iParent = std::distance(mNodes.data(), newParentPtr);
+  node->mParentIdx = iParent;
+  DEBUG_ONLY(dumpNode(*node);)
+  return true;
+}
+
+bool SceneDefinition::RemoveNode(const std::string& name)
+{
+  std::unique_ptr<NodeDefinition>* node = nullptr;
+  if (!FindNode(name, &node))
+  {
+    return false;
+  }
+
+  // Reset node def pointers recursively.
+  auto& thisNodes = mNodes;
+  unsigned int numReset = 0;
+  std::function<void(std::unique_ptr<NodeDefinition>&)> resetFn =
+    [&thisNodes, &resetFn, &numReset](std::unique_ptr<NodeDefinition>& nd) {
+    LOGD(("resetting %d", &nd - thisNodes.data()));
+    for (auto i : nd->mChildren)
+    {
+      resetFn(thisNodes[i]);
+    }
+    nd.reset();
+    ++numReset;
+  };
+
+  resetFn(*node);
+
+  // Gather indices of dead nodes into a vector which we sort on insertion.
+  std::vector<Index> offsets;
+  offsets.reserve(numReset);
+  for (auto& n : mNodes)
+  {
+    if (!n)
+    {
+      offsets.push_back(std::distance(mNodes.data(), &n));
+    }
+  }
+
+  // Erase dead nodes as they don't have to be processed anymore.
+  mNodes.erase(std::remove(mNodes.begin(), mNodes.end(), decltype(mNodes)::value_type()), mNodes.end());
+
+  // Offset all indices (parent and child) by the index they'd sort into in offsets.
+  enum { INDEX_FOR_REMOVAL = INVALID_INDEX };
+  auto offsetter = [&offsets](Index& i) {
+    auto iFind = std::lower_bound(offsets.begin(), offsets.end(), i);
+    if (iFind != offsets.end() && *iFind == i)
+    {
+      LOGD(("marking %d for removal.", i));
+      i = INDEX_FOR_REMOVAL;
+      return false;
+    }
+    else
+    {
+      auto distance = std::distance(offsets.begin(), iFind);
+      if (distance > 0)
+      {
+        LOGD(("offsetting %d by %d.", i, distance));
+        i -= distance;
+      }
+      return true;
+    }
+  };
+
+  for (auto& nd : mNodes)
+  {
+    bool parentOffsetResult = offsetter(nd->mParentIdx);
+    DALI_ASSERT_ALWAYS(parentOffsetResult);  // since nodes were recursively removed, we should not be finding invalid parents at this point.
+
+    auto& children = nd->mChildren;
+    for (auto i0 = children.begin(), i1 = children.end(); i0 != i1; ++i0)
+    {
+      offsetter(*i0);
+    }
+
+    children.erase(std::remove(children.begin(), children.end(), INDEX_FOR_REMOVAL), children.end());
+  }
+
+  return true;
+}
+
+void SceneDefinition::GetNodeModelStack(Index index, MatrixStack& model) const
+{
+  auto& thisNodes = mNodes;
+  std::function<void(int)> buildStack = [&model, &thisNodes, &buildStack](int i) {
+    auto node = thisNodes[i].get();
+    if (node->mParentIdx != INVALID_INDEX)
+    {
+      buildStack(node->mParentIdx);
+    }
+    model.Push(node->GetLocalSpace());
+  };
+  buildStack(index);
+}
+
+NodeDefinition* SceneDefinition::FindNode(const std::string &name, Index* outIndex)
+{
+  auto iBegin = mNodes.begin();
+  auto iEnd = mNodes.end();
+  auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) {
+    return nd->mName == name;
+  });
+
+  auto result = iFind != iEnd ? iFind->get() : nullptr;
+  if (result && outIndex)
+  {
+    *outIndex = std::distance(iBegin, iFind);
+  }
+  return result;
+}
+
+const NodeDefinition* SceneDefinition::FindNode(const std::string &name, Index* outIndex) const
+{
+  auto iBegin = mNodes.begin();
+  auto iEnd = mNodes.end();
+  auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) {
+    return nd->mName == name;
+  });
+
+  auto result = iFind != iEnd ? iFind->get() : nullptr;
+  if (result && outIndex)
+  {
+    *outIndex = std::distance(iBegin, iFind);
+  }
+  return result;
+}
+
+Index SceneDefinition::FindNodeIndex(const NodeDefinition& node) const
+{
+  auto iBegin = mNodes.begin();
+  auto iEnd = mNodes.end();
+  auto iFind = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr<NodeDefinition>& n) {
+    return n.get() == &node;
+  });
+  return iFind != iEnd ? std::distance(iBegin, iFind) : INVALID_INDEX;
+}
+
+void SceneDefinition::FindNodes(NodePredicate predicate, NodeConsumer consumer,
+  unsigned int limit)
+{
+  unsigned int n = 0;
+  for (auto& defp : mNodes)
+  {
+    if (predicate(*defp))
+    {
+      consumer(*defp);
+      ++n;
+      if (n == limit)
+      {
+        break;
+      }
+    }
+  }
+}
+
+void SceneDefinition::FindNodes(NodePredicate predicate, ConstNodeConsumer consumer,
+  unsigned int limit) const
+{
+  unsigned int n = 0;
+  for (auto& defp : mNodes)
+  {
+    if (predicate(*defp))
+    {
+      consumer(*defp);
+      ++n;
+      if (n == limit)
+      {
+        break;
+      }
+    }
+  }
+}
+
+void SceneDefinition::ApplyConstraints(Actor& root,
+  std::vector<ConstraintRequest>&& constrainables, StringCallback onError) const
+{
+  for (auto& cr : constrainables)
+  {
+    auto& nodeDef = mNodes[cr.mConstraint->mSourceIdx];
+    auto sourceName = nodeDef->mName.c_str();
+    Property::Index iTarget = cr.mTarget.GetPropertyIndex(cr.mConstraint->mProperty);
+    if (iTarget != Property::INVALID_INDEX)
+    {
+      auto propertyType = cr.mTarget.GetPropertyType(iTarget);
+      auto iFind = sConstraintFactory.find(propertyType);
+      if (iFind == sConstraintFactory.end())
+      {
+        onError(FormatString("node '%s': Property '%s' has unsupported type '%s'; ignored.",
+          sourceName, cr.mConstraint->mProperty.c_str(), PropertyTypes::GetName(propertyType)));
+        continue;
+      }
+
+      Constraint constraint = iFind->second(cr.mTarget, iTarget);
+
+      Actor source = root.FindChildByName(nodeDef->mName);
+      if (!source)
+      {
+        auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
+        onError(FormatString("node '%s': Failed to locate constraint source %s@%s; ignored.",
+          sourceName, cr.mConstraint->mProperty.c_str(), targetName.c_str()));
+        continue;
+      }
+      else if (source == cr.mTarget)
+      {
+        onError(FormatString("node '%s': Cyclic constraint definition for property '%s'; ignored.",
+          sourceName, cr.mConstraint->mProperty.c_str()));
+        continue;
+      }
+
+      Property::Index iSource = source.GetPropertyIndex(cr.mConstraint->mProperty);
+      constraint.AddSource(Source{ source, iSource });
+      constraint.Apply();
+    }
+    else
+    {
+      auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
+      onError(FormatString("node '%s': Failed to create constraint for property %s@%s; ignored.",
+        sourceName, cr.mConstraint->mProperty.c_str(), targetName.c_str()));
+    }
+  }
+}
+
+void SceneDefinition::ConfigureSkeletonJoints(uint32_t iRoot, const SkeletonDefinition::Vector& skeletons, Actor root) const
+{
+  // 1, For each skeleton, for each joint, walk upwards until we reach mNodes[iRoot]. If we do, record +1
+  // to the refcount of each node we have visited, in our temporary registry. Those with refcount 1
+  // are the leaves, while the most descendant node with the highest refcount is the root of the skeleton.
+  std::map<Index, std::vector<Index>> rootsJoints;
+  std::vector<Index> path;
+  path.reserve(16);
+  for (auto& s : skeletons)
+  {
+    std::map<uint32_t, uint32_t>  jointRefs;
+    for (auto& j : s.mJoints)
+    {
+      auto nodeIdx = j.mNodeIdx;
+      do // Traverse upwards and record each node we have visited until we reach the scene root.
+      {
+        path.push_back(nodeIdx);
+        if (nodeIdx == iRoot)
+        {
+          break;
+        }
+        auto node = GetNode(nodeIdx);
+        nodeIdx = node->mParentIdx;
+      }
+      while (nodeIdx != INVALID_INDEX);
+
+      if (nodeIdx == iRoot)  // If the joint is in the correct scene, increment the reference count for all visited nodes.
+      {
+        for (auto i : path)
+        {
+          ++jointRefs[i];
+        }
+      }
+
+      path.clear();
+    }
+
+    // Only record the skeleton if we have encountered the root of the current scene.
+    if (jointRefs.empty())
+    {
+      continue;
+    }
+
+    Index root = s.mRootNodeIdx;
+    uint32_t maxRef = 0;
+    auto iFind = jointRefs.find(root);
+    if (iFind != jointRefs.end())
+    {
+      maxRef = iFind->second;
+    }
+
+    std::vector<Index> joints;
+    for (auto& j : jointRefs)  // NOTE: jointRefs are sorted, so joints will also be.
+    {
+      // The most descendant node with the highest ref count is the root of the skeleton.
+      if (j.second > maxRef || (j.second == maxRef && IsAncestor(*this, root, j.first, iRoot)))
+      {
+        maxRef = j.second;
+
+        RemoveFromSorted(joints, root);
+        root = j.first;
+      }
+      else if (j.second == 1)  // This one's a leaf.
+      {
+        InsertUniqueSorted(joints, j.first);
+      }
+    }
+
+    // Merge skeletons that share the same root.
+    auto& finalJoints = rootsJoints[root];
+    for (auto j : joints)
+    {
+      if (std::find_if(finalJoints.begin(), finalJoints.end(), [this, j, root](Index jj) {
+        return IsAncestor(*this, j, jj, root);
+      }) != finalJoints.end())
+      {
+        continue;  // if the joint is found to be an ancestor of another joint already registered, move on.
+      }
+
+      auto i = j;
+      while (i != root)  // See if the current joint is a better leaf, i.e. descended from another leaf - which we'll then remove.
+      {
+        auto node = GetNode(i);
+        i = node->mParentIdx;
+
+        RemoveFromSorted(finalJoints, i);
+      }
+
+      InsertUniqueSorted(finalJoints, j);
+    }
+  }
+
+  // 2, Merge records where one root joint is descendant of another. Handle leaf node changes - remove previous
+  // leaf nodes that now have descendants, and add new ones.
+  auto iRoots = rootsJoints.begin();
+  auto iRootsEnd = rootsJoints.end();
+  while (iRoots != iRootsEnd)
+  {
+    auto i = iRoots->first;
+    bool merged = false;
+    while (i != iRoot)  // Starting with the root joint of the skeleton, traverse upwards.
+    {
+      auto node = GetNode(i);
+      i = node->mParentIdx;
+
+      auto iFind = rootsJoints.find(i);
+      if (iFind != rootsJoints.end())  // Check if we've reached the root of another skeleton.
+      {
+        // Now find out which leaf of iFind is an ancestor, if any.
+        auto iFindLeaf = std::find_if(iFind->second.begin(), iFind->second.end(), [this, iRoots, iFind](Index j) {
+          return IsAncestor(*this, j, iRoots->first, iFind->first);
+        });
+        if (iFindLeaf != iFind->second.end())
+        {
+          iFind->second.erase(iFindLeaf);  // Will no longer be a leaf -- remove it.
+        }
+
+        // Merge iRoots with iFind
+        auto& targetJoints = iFind->second;
+        if (iRoots->second.empty())  // The root is a leaf.
+        {
+          InsertUniqueSorted(targetJoints, iRoots->first);
+        }
+        else for (auto j : iRoots->second)
+        {
+          InsertUniqueSorted(targetJoints, j);
+        }
+
+        merged = true;
+        break;  // Traverse no more
+      }
+    }
+
+    iRoots = merged ? rootsJoints.erase(iRoots) : std::next(iRoots);
+  }
+
+  // 3, For each root, register joint matrices and constraints
+  for (auto r : rootsJoints)
+  {
+    auto node = GetNode(r.first);
+    auto rootJoint = root.FindChildByName(node->mName);
+    DALI_ASSERT_ALWAYS(!!rootJoint);
+
+    DALI_ASSERT_DEBUG(rootJoint.GetPropertyIndex(JOINT_MATRIX) == Property::INVALID_INDEX);
+    auto propJointMatrix = rootJoint.RegisterProperty(JOINT_MATRIX, Matrix{ false });
+    Constraint constraint = Constraint::New<Matrix>(rootJoint, propJointMatrix,
+      [](Matrix& output, const PropertyInputContainer& inputs)
+      {
+        output.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3());
+      });
+    constraint.AddSource(Source(rootJoint, Actor::Property::ORIENTATION));
+    constraint.AddSource(Source(rootJoint, Actor::Property::POSITION));
+    constraint.Apply();
+
+    for (auto j : r.second)
+    {
+      node = GetNode(j);
+      auto joint = rootJoint.FindChildByName(node->mName);
+      ConfigureJointMatrix(joint, rootJoint, propJointMatrix);
+    }
+  }
+}
+
+void SceneDefinition::EnsureUniqueSkinningShaderInstances(ResourceBundle& resources) const
+{
+  std::map<Index, std::map<Index, std::vector<Index*>>> skinningShaderUsers;
+  for (auto& node : mNodes)
+  {
+    if (node->mRenderable)
+    {
+      ResourceReflector reflector;
+      node->mRenderable->ReflectResources(reflector);
+
+      if (reflector.iMesh)
+      {
+        const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
+        if (mesh.IsSkinned())
+        {
+          skinningShaderUsers[*reflector.iShader][mesh.mSkeletonIdx].push_back(reflector.iShader);
+        }
+      }
+    }
+  }
+
+  // For each shader, and each skeleton using the same shader as the first skeleton,
+  // update the shader references (from nodes with skinned meshes) with a new copy of
+  // the shader definition from the node using the first skeleton.
+  for (auto& users : skinningShaderUsers)
+  {
+    auto& skeletons = users.second;
+    auto iterSkeleton = skeletons.begin();
+    // skipping the first skeleton.
+    ++iterSkeleton;
+
+    resources.mShaders.reserve(resources.mShaders.size() + std::distance(iterSkeleton, skeletons.end()));
+    const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
+
+    while (iterSkeleton != skeletons.end())
+    {
+      Index iShader = resources.mShaders.size();
+      resources.mShaders.push_back({ shaderDef, Shader() });
+
+      for (auto& i : iterSkeleton->second)
+      {
+        *i = iShader;
+      }
+      ++iterSkeleton;
+    }
+  }
+}
+
+void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle& resources,
+  Actor rootActor, std::vector<SkinningShaderConfigurationRequest>&& requests) const
+{
+  if (requests.empty())
+  {
+    return;
+  }
+
+  SortAndDeduplicateSkinningRequests(requests);
+
+  for (auto& i : requests)
+  {
+    auto& skeleton = resources.mSkeletons[i.mSkeletonIdx];
+    if (skeleton.mJoints.empty())
+    {
+      LOGD(("Skeleton %d has no joints.", i.mSkeletonIdx));
+      continue;
+    }
+
+    Index boneIdx = 0;
+    for (auto& j : skeleton.mJoints)
+    {
+      auto node = GetNode(j.mNodeIdx);
+      Actor actor = rootActor.FindChildByName(node->mName);
+      ConfigureBoneMatrix(j.mInverseBindMatrix, actor, i.mShader, boneIdx);
+    }
+  }
+}
+
+bool SceneDefinition::ConfigureBlendshapeShaders(const ResourceBundle& resources,
+  Actor rootActor, std::vector<BlendshapeShaderConfigurationRequest>&& requests,
+  StringCallback onError ) const
+{
+  if (requests.empty())
+  {
+    return true;
+  }
+
+  // Sort requests by shaders.
+  std::sort(requests.begin(), requests.end());
+
+  // Remove duplicates.
+  auto i = requests.begin();
+  auto iEnd = requests.end();
+  Shader s = i->mShader;
+  ++i;
+  do
+  {
+    // Multiple identical shader instances are removed.
+    while (i != iEnd && i->mShader == s)
+    {
+      i->mShader = Shader();
+      ++i;
+    }
+
+    if (i == iEnd)
+    {
+      break;
+    }
+    s = i->mShader;
+    ++i;
+  } while (true);
+
+  requests.erase(std::remove_if(requests.begin(), requests.end(), [](const BlendshapeShaderConfigurationRequest& bscr)
+  {
+    return !bscr.mShader;
+  }), requests.end());
+
+  // Configure the rest.
+  bool ok = true;
+
+  for (auto& i : requests)
+  {
+    Index iNode;
+    if (FindNode(i.mNodeName, &iNode))
+    {
+      const auto& node = GetNode(iNode);
+
+      const auto& mesh = resources.mMeshes[i.mMeshIdx];
+
+      if (mesh.first.HasBlendShapes())
+      {
+        Actor actor = rootActor.FindChildByName(node->mName);
+
+        // Sets the property to be animated.
+        BlendShapes::ConfigureProperties(mesh, i.mShader, actor);
+      }
+    }
+  }
+
+  return ok;
+}
+
+void SceneDefinition::EnsureUniqueBlendShapeShaderInstances(ResourceBundle& resources) const
+{
+  std::map<Index, std::map<std::string, std::vector<Index*>>> blendShapeShaderUsers;
+  for (auto& node : mNodes)
+  {
+    if (node->mRenderable)
+    {
+      ResourceReflector reflector;
+      node->mRenderable->ReflectResources(reflector);
+
+      if (reflector.iMesh)
+      {
+        const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
+        if (mesh.HasBlendShapes())
+        {
+          blendShapeShaderUsers[*reflector.iShader][node->mName].push_back(reflector.iShader);
+        }
+      }
+    }
+  }
+
+  for (auto& users : blendShapeShaderUsers)
+  {
+    resources.mShaders.reserve(resources.mShaders.size() + users.second.size() - 1u);
+    const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
+
+    auto nodesIt = users.second.begin();
+    auto nodesEndIt = users.second.end();
+    // skipping the first node.
+    ++nodesIt;
+    while(nodesIt != nodesEndIt)
+    {
+      Index iShader = resources.mShaders.size();
+      resources.mShaders.push_back({ shaderDef, Shader() });
+
+      auto& nodes = *nodesIt;
+      for (auto& shader : nodes.second)
+      {
+        *shader = iShader;
+      }
+      ++nodesIt;
+    }
+  }
+}
+
+SceneDefinition& SceneDefinition::operator=(SceneDefinition&& other)
+{
+  SceneDefinition temp(std::move(other));
+  std::swap(mNodes, temp.mNodes);
+  std::swap(mRootNodeIds, temp.mRootNodeIds);
+  return *this;
+}
+
+bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr<NodeDefinition>** result)
+{
+  // We're searching from the end assuming a higher probability of operations targeting
+  // recently added nodes. (conf.: root, which is immovable, cannot be removed, and was
+  // the first to be added, is index 0.)
+  auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(),
+    [&name](const std::unique_ptr<NodeDefinition>& nd) {
+      return nd->mName == name;
+    }).base();
+
+  const bool success = iFind != mNodes.begin();
+  if (success && result)
+  {
+    --iFind;
+    *result = &*iFind;
+  }
+
+  return success;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/scene-definition.h b/dali-scene-loader/public-api/scene-definition.h
new file mode 100644 (file)
index 0000000..66ea758
--- /dev/null
@@ -0,0 +1,278 @@
+#ifndef DALI_SCENE_LOADER_SCENE_DEFINITION_H_
+#define DALI_SCENE_LOADER_SCENE_DEFINITION_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/customization.h"
+#include "dali-scene-loader/public-api/utils.h"
+#include "dali-scene-loader/public-api/node-definition.h"
+#include "dali-scene-loader/public-api/string-callback.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/quaternion.h"
+#include "dali/public-api/math/matrix.h"
+#include "dali/public-api/math/vector4.h"
+#include "dali/public-api/actors/actor.h"
+#include <string>
+#include <memory>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+class MatrixStack;
+
+/*
+ * @brief Intermediate representation of a scene with functionality required to
+ *  create DALi objects (Actors, Renderers) from it.
+ */
+class DALI_SCENE_LOADER_API SceneDefinition
+{
+public:  // TYPES
+  using NodePredicate = std::function<bool(const NodeDefinition&)>;
+  using NodeConsumer = std::function<void(NodeDefinition&)>;
+  using ConstNodeConsumer = std::function<void(const NodeDefinition&)>;
+
+public: // METHODS
+  SceneDefinition();
+  SceneDefinition(SceneDefinition&& other);
+  ~SceneDefinition();
+
+  /*
+   * @brief Registers a scene root node.
+   * @return The index of the scene root node *registration*.
+   */
+  Index AddRootNode(Index iNode);
+
+  /*
+   * @return the list of scene root node IDs in the order of their loading.
+   */
+  const std::vector<Index>& GetRoots() const;
+
+  /*
+   * @brief Removes scene root registration at the given index @a iRoot.
+   * @note @a iRoot is the index of the registration (i.e. into the vector returned by GetRoots()),
+   *  not of the node.
+   */
+  void RemoveRootNode(Index iRoot);
+
+  /*
+   * @return The number of node( definition)s in the scene.
+   */
+  uint32_t GetNodeCount() const;
+
+  /*
+   * @return Const pointer to the node (definition) at the given index.
+   */
+  const NodeDefinition* GetNode(Index iNode) const;
+
+  /*
+   * @return Pointer to the node (definition) at the given index.
+   */
+  NodeDefinition* GetNode(Index iNode);
+
+  /*
+   * @brief Traverses the scene starting from the node at the given index into
+   *  nodes, using the given customization @a choices and the visitor @a v.
+   */
+  void Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IVisitor& v);
+
+  /*
+   * @brief Traverses the scene starting from the node at the given index into
+   *  nodes, using the given customization @a choices and the visitor @a v.
+   */
+  void Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IConstVisitor& v) const;
+
+  /*
+   * @brief Counts the references to meshes, shaders, materials that nodes in
+   *  the scene are holding, writing the results into @a refCounts.
+   * @note @a refCounts' entries must have the correct size. Use ResourceBundle::GetRefCounter().
+   */
+  void CountResourceRefs(Index iNode, const Customization::Choices& choices, ResourceRefCounts& refCounts) const;
+
+  /*
+   * @brief Given a bundle of @a resources that are loaded, and customization
+   *  @a choices, this method traverses the scene, creating the actors and renderers
+   *  from node definitions.
+   * @return Handle to the root actor.
+   */
+  Actor CreateNodes(Index iNode, const Customization::Choices& choices,
+    NodeDefinition::CreateParams& params) const;
+
+  /*
+   * @brief Creates / update a registry of mappings from customization tags to
+   *  a lists of names of customizable nodes under each tag, and the number of
+   *  options. If @a outMissingChoices was specified, each tag that it encounters
+   *  in the scene but not in @a choices, will be registered on it with the default
+   *  choice of 0.
+   */
+  void GetCustomizationOptions(const Customization::Choices& choices,
+    Customization::Map& outCustomizationOptions,
+    Customization::Choices* outMissingChoices) const;
+
+  /*
+   * @brief Attempts to add @a nodeDef to the end of nodes, and its index to the end of
+   *  its parent's list of children (if iParent != NodeDefinition::INVALID_PARENT).
+   * @return If the operation was successful - which requires nodeDef->name to be unique -
+   *  a pointer to the stored node definition; nullptr otherwise.
+   */
+  NodeDefinition* AddNode(std::unique_ptr<NodeDefinition>&& nodeDef);
+
+  /*
+   * @brief Moves the node to some other parent and / or to a different index.
+   * @return Whether the operation was successful.
+   * @note This is currently breaking an assumption of never having a child of a node at a lower
+   *  index as that of the node itself, due to the fact that we're only changing parent ids (and
+   *  entries into the vector of children of node definitions), to save the complication of having
+   *  to move about, and offset indices to, everything past the reparented node. This should be
+   *  sufficient AT LEAST AS LONG AS we recreate the SceneDefinition when loading the scene; if
+   *  we ever needed to serialize it, we should ensure correct ordering of nodes.
+   */
+  bool ReparentNode(const std::string& name, const std::string& newParentName, Index siblingOrder);
+
+  /*
+   * @brief Removes a node with the given name, including all of its children, and updating
+   *  the indices on all remaining node definitions.
+   * @return Whether the operation was successful.
+   */
+  bool RemoveNode(const std::string& name);
+
+  /*
+   * @brief Builds the model matrix stack for the node at the given @a index.
+   * @note It only pushes new matrices; does not require the stack to be empty (or cares if it was not).
+   */
+  void GetNodeModelStack(Index index, MatrixStack& model) const;
+
+  /*
+   * @brief Attempts to find the definition of a node with the given @a name. Only upon
+   *  success, and if @a outIndex is non-null, the index of the node is written to it.
+   * @return Pointer to the node definition; nullptr if not found.
+   * @note No ownership transfer.
+   */
+  NodeDefinition* FindNode(const std::string& name, Index* outIndex = nullptr);
+
+  /*
+   * @brief Attempts to find the definition of a node with the given @a name. Only upon
+   *  success, and if @a outIndex is non-null, the index of the node is written to it.
+   * @return Pointer to the node definition; nullptr if not found.
+   * @note No ownership transfer.
+   */
+  const NodeDefinition* FindNode(const std::string& name, Index* outIndex = nullptr) const;
+
+  /*
+   * @return The index of the given NodeDefinition@ a node, or -1 if the node definition
+   *  was not found.
+   */
+  Index FindNodeIndex(const NodeDefinition& node) const;
+
+  /*
+   * @brief Calls @a consumer with up to @a limit NodeDefinitions that evaluate to true
+   *  with @a predicate.
+   * @note A @a limit value of 0 means no limit.
+   */
+  void FindNodes(NodePredicate predicate, NodeConsumer consumer, unsigned int limit = 0);
+
+  /*
+   * @brief Calls @a consumer with up to @a limit NodeDefinitions that evaluate to true
+   *  with @a predicate.
+   * @note A @a limit value of 0 means no limit.
+   */
+  void FindNodes(NodePredicate predicate, ConstNodeConsumer consumer, unsigned int limit = 0) const;
+
+  /*
+   * @brief Applies constraints from the given requests.
+   */
+  void ApplyConstraints(Actor& root,
+    std::vector<ConstraintRequest>&& constrainables,
+    StringCallback onError = DefaultErrorCallback) const;
+
+  /*
+   * @brief Sets up joint matrix properties and constraints on actors that are involved in skeletal
+   *  animation (i.e. those that are between (inclusive) the lower and upper bounds of any skeleton),
+   *  to ensure the correct update of meshes skinned to these skeletons.
+   * @param iRoot The index of the scene root node. Skeletons that aren't descendants of this node
+   *  will be ignored.
+   * @param skeletons The list of skeletons that require setting up.
+   * @param rootActor The Actor corresponding to the root node, which will be used to locate
+   *  other actors.
+   */
+  void ConfigureSkeletonJoints(uint32_t iRoot, const SkeletonDefinition::Vector& skeletons, Actor rootActor) const;
+
+  /*
+   * @brief Ensures that there is no overlap between shaders used by nodes that have
+   *  meshes skinned to different skeletons.
+   */
+  void EnsureUniqueSkinningShaderInstances(ResourceBundle& resources) const;
+
+  /*
+   * @brief Performs the configuration of the given skinning shaders with the given skeleton
+   *   This means that the absolute transforms of the joints are calculated and set as one of
+   *   the uniforms in the mat4 @b uBone array (in depth first traversal). Further, the following
+   *   are created:<br />
+   *   - a @b jointMatrix property on each joint Actor;<br />
+   *   - constraint from the Actor's local position and rotation (and if it has a @e joint
+   *     parent, the jointMatrix of the parent) to its @b jointMatrix property;<br />
+   *   - a constraint from the the Actor's @b jointMatrix property to the related entry in
+   *     the shader's @b uBone property;<br />
+   *   This ensures the automatic update of the skeletal animation, should any of the joints'
+   *   transform changes, by whatever means.
+   * @return The success of the operations. Error messages will be posted to the optional
+   *   @a onError callback.
+   * @note A maximum of SkinningDetails::MAX_JOINTS joints per skeleton are supported at the moment.
+   * @note Even if multiple skinned meshes use the same skinning shader, the correct number
+   *   of separate instances need to be declared in the .dli to avoid clashing uniform
+   *   definitions and constraints.
+   */
+  void ConfigureSkinningShaders(const ResourceBundle& resources,
+    Actor root, std::vector<SkinningShaderConfigurationRequest>&& requests) const;
+
+  /*
+   * @brief Ensures there is no two meshes with blend shapes sharing the same shader.
+   */
+  void EnsureUniqueBlendShapeShaderInstances(ResourceBundle& resources) const;
+
+  /**
+   * @brief Performs the configuration of the given blend shapes.
+   *
+   * For each node with blend shapes it registers into the actor the weights properties for each morph target
+   * and some needed uniforms into the shader.
+   * 
+   * @param[in] root The root actor.
+   * @param[in] requests The requests to configure blend shapes.
+   * @param[in] resources The resources bundle. Meshes need to be accessed to configure the blend shapes.
+   * @param[in] onError The error callback.
+   */
+  bool ConfigureBlendshapeShaders(const ResourceBundle& resources,
+    Actor root, std::vector<BlendshapeShaderConfigurationRequest>&& requests,
+    StringCallback onError = DefaultErrorCallback) const;
+
+  SceneDefinition& operator=(SceneDefinition&& other);
+
+private: // METHODS
+  bool FindNode(const std::string& name, std::unique_ptr<NodeDefinition>** result);
+
+private: // DATA
+  std::vector<std::unique_ptr<NodeDefinition>> mNodes;  // size unknown up front (may discard nodes).
+  std::vector<Index> mRootNodeIds;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_SCENE_DEFINITION_H_
diff --git a/dali-scene-loader/public-api/shader-definition-factory.cpp b/dali-scene-loader/public-api/shader-definition-factory.cpp
new file mode 100644 (file)
index 0000000..f0a2ad8
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/internal/hash.h"
+#include "dali-scene-loader/public-api/shader-definition-factory.h"
+#include "dali-scene-loader/public-api/node-definition.h"
+#include "dali-scene-loader/public-api/blend-shape-details.h"
+#include "dali/devel-api/common/map-wrapper.h"
+#include <cstring>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+struct ResourceReceiver : IResourceReceiver
+{
+  const ResourceBundle& mResources;
+  const MeshDefinition* mMeshDef = nullptr;
+  const MaterialDefinition* mMaterialDef = nullptr;
+
+  ResourceReceiver(const ResourceBundle& resources)
+  : mResources(resources)
+  {}
+
+  void Register(ResourceType::Value type, Index id) override
+  {
+    switch (type)
+    {
+    case ResourceType::Mesh:
+      mMeshDef = &mResources.mMeshes[id].first;
+      break;
+
+    case ResourceType::Material:
+      mMaterialDef = &mResources.mMaterials[id].first;
+      break;
+
+    default:
+      break;
+    }
+  }
+};
+
+const std::string PBR_SHADER_NAME = "dli_pbr";
+
+void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
+{
+  for (const auto& blendShape : blendShapes)
+  {
+    hasPositions = hasPositions || blendShape.deltas.IsDefined();
+    hasNormals = hasNormals || blendShape.normals.IsDefined();
+    hasTangents = hasTangents || blendShape.tangents.IsDefined();
+  }
+}
+
+uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
+{
+  Hash hash;
+
+  // note: could be per vertex / fragment component - in WatchViewer, these have the same name.
+  hash.Add(PBR_SHADER_NAME);
+
+  const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
+  hash.Add(hasTransparency);
+
+  if (hasTransparency ||
+    materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
+    materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
+    materialDef.CheckTextures(MaterialDefinition::NORMAL))
+  {
+    hash.Add("3TEX");
+  }
+
+  if (materialDef.GetAlphaCutoff() > 0.f)
+  {
+    hash.Add("ALPH"/*A_TEST*/);
+  }
+
+  if (MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
+  {
+    hash.Add("SSS");
+  }
+
+  if (MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
+  {
+    hash.Add("GLTF"/*_CHANNELS*/);
+  }
+
+  if (meshDef.IsSkinned())
+  {
+    hash.Add("SKIN"/*NING*/);
+  }
+
+  if (MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
+  {
+    hash.Add("FLIP"/*_V*/);
+  }
+
+  if (meshDef.HasBlendShapes())
+  {
+    bool hasPositions = false;
+    bool hasNormals = false;
+    bool hasTangents = false;
+    RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
+    if (hasPositions)
+    {
+      hash.Add("MORPHPOS");
+    }
+
+    if (hasNormals)
+    {
+      hash.Add("MORPHNOR");
+    }
+
+    if (hasTangents)
+    {
+      hash.Add("MORPHTAN");
+    }
+
+    if (hasPositions || hasNormals || hasTangents)
+    {
+      hash.Add("MORPH");
+
+      if (BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
+      {
+        hash.Add("MORPHV2");
+      }
+    }
+  }
+
+  return hash;
+}
+}
+
+struct ShaderDefinitionFactory::Impl
+{
+  ResourceBundle* mResources;  // no ownership
+  std::map<uint64_t, Index> mShaderMap;
+};
+
+ShaderDefinitionFactory::ShaderDefinitionFactory()
+: mImpl{ new Impl() }
+{}
+
+ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
+
+void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
+{
+  mImpl->mResources = &resources;
+  mImpl->mShaderMap.clear();
+}
+
+Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
+{
+  DALI_ASSERT_DEBUG(nodeDef.mRenderable);
+
+  auto& resources = *mImpl->mResources;
+  ResourceReceiver receiver{ resources };
+  nodeDef.mRenderable->RegisterResources(receiver);
+  if (!(receiver.mMeshDef && receiver.mMaterialDef))
+  {
+    return INVALID_INDEX;
+  }
+
+  auto& shaderMap = mImpl->mShaderMap;
+  uint64_t hash = HashNode(nodeDef, *receiver.mMaterialDef, *receiver.mMeshDef);
+  auto iFind = shaderMap.find(hash);
+  if (iFind != shaderMap.end())
+  {
+    return iFind->second;
+  }
+
+  ShaderDefinition shaderDef;
+  shaderDef.mVertexShaderPath = PBR_SHADER_NAME + ".vsh";
+  shaderDef.mFragmentShaderPath = PBR_SHADER_NAME + ".fsh";
+  shaderDef.mRendererState = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
+
+  auto& materialDef = *receiver.mMaterialDef;
+  const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
+  if (hasTransparency)
+  {
+    // TODO: this requires more granularity
+    shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
+  }
+
+  if (hasTransparency ||
+    materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
+    materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
+    materialDef.CheckTextures(MaterialDefinition::NORMAL))
+  {
+    shaderDef.mDefines.push_back("THREE_TEX");
+  }
+
+  if (materialDef.GetAlphaCutoff() > 0.f)
+  {
+    shaderDef.mDefines.push_back("ALPHA_TEST");
+  }
+
+  if (MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
+  {
+    shaderDef.mDefines.push_back("SSS");
+  }
+
+  if (MaskMatch(receiver.mMaterialDef->mFlags, MaterialDefinition::GLTF_CHANNELS))
+  {
+    shaderDef.mDefines.push_back("GLTF_CHANNELS");
+  }
+
+  const auto& meshDef = *receiver.mMeshDef;
+  if (meshDef.IsSkinned())
+  {
+    shaderDef.mDefines.push_back("SKINNING");
+  }
+
+  if (MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
+  {
+    shaderDef.mDefines.push_back("FLIP_V");
+  }
+
+  if (meshDef.HasBlendShapes())
+  {
+    bool hasPositions = false;
+    bool hasNormals = false;
+    bool hasTangents = false;
+    RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
+
+    if (hasPositions)
+    {
+      shaderDef.mDefines.push_back("MORPH_POSITION");
+    }
+
+    if (hasNormals)
+    {
+      shaderDef.mDefines.push_back("MORPH_NORMAL");
+    }
+
+    if (hasTangents)
+    {
+      shaderDef.mDefines.push_back("MORPH_TANGENT");
+    }
+
+    if (hasPositions || hasNormals || hasTangents)
+    {
+      shaderDef.mDefines.push_back("MORPH");
+
+      if (BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
+      {
+        shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
+      }
+    }
+  }
+
+  shaderDef.mUniforms["uMaxLOD"] = 6.f;
+  shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
+
+  Index result = resources.mShaders.size();
+  shaderMap[hash] = result;
+
+  resources.mShaders.emplace_back(std::move(shaderDef), Shader());
+
+  return result;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/shader-definition-factory.h b/dali-scene-loader/public-api/shader-definition-factory.h
new file mode 100644 (file)
index 0000000..4f55bbe
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef DALI_SCENE_LOADER_SHADER_DEFINITION_FACTORY_H_
+#define DALI_SCENE_LOADER_SHADER_DEFINITION_FACTORY_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/index.h"
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDER
+#include <memory>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+struct NodeDefinition;
+class ResourceBundle;
+
+class DALI_SCENE_LOADER_API ShaderDefinitionFactory
+{
+public:
+  ShaderDefinitionFactory();
+  ~ShaderDefinitionFactory();
+
+  /*
+   * @brief Input for meshes and materials, output for shaders.
+   */
+  void SetResources(ResourceBundle& resources);
+
+  /*
+   * @brief Produces the index of a shader, which should be used to index into the shaders
+   *  vector of the ResourceBundle which was provided for the factory. This shader will be
+   *  created if one with the given settings hasn't been created by the factory yet (shaders
+   *  already existing in the ResourceBundle are ignored), otherwise the index of the previously
+   *  created shader will be returned.
+   */
+  Index ProduceShader(const NodeDefinition& nodeDef);
+
+private:
+  struct Impl;
+  const std::unique_ptr<Impl> mImpl;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_SHADER_DEFINITION_FACTORY_H_
diff --git a/dali-scene-loader/public-api/shader-definition.cpp b/dali-scene-loader/public-api/shader-definition.cpp
new file mode 100644 (file)
index 0000000..5fbec33
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/shader-definition.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+
+const std::string SHADER_HINT_OUTPUT_IS_TRANSPARENT("OUTPUT_IS_TRANSPARENT"); ///< Might generate transparent alpha from opaque inputs.
+const std::string SHADER_HINT_MODIFIES_GEOMETRY("MODIFIES_GEOMETRY");     ///< Might change position of vertices, this option disables any culling optimizations.
+
+}
+
+ShaderDefinition::ShaderDefinition(const ShaderDefinition& other)
+: mRendererState(other.mRendererState),
+  mVertexShaderPath(other.mVertexShaderPath),
+  mFragmentShaderPath(other.mFragmentShaderPath),
+  mDefines(other.mDefines),
+  mHints(other.mHints),
+  mUniforms(other.mUniforms)
+{}
+
+void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& definevar)
+{
+  const std::string IF_1 = "#if 1";
+
+  std::size_t found = shaderCode.find(definevar);
+  while (found != std::string::npos)
+  {
+    // Greater then "@" character means is a letter,
+    // therefore is not has the definevar we looking for.
+    if ((found + definevar.length()) < shaderCode.length() && shaderCode.at(found + definevar.length()) > '@')
+    {
+      found = shaderCode.find(definevar, found + definevar.length());
+      continue;
+    }
+    if (found > 0u && shaderCode.at(found - 1) > '@')
+    {
+      found = shaderCode.find(definevar, found + definevar.length());
+      continue;
+    }
+
+    std::size_t defidx = shaderCode.rfind("#ifdef", found);
+    std::size_t newlineidx = shaderCode.rfind("\n", found);
+    if (newlineidx < defidx && defidx != std::string::npos)
+    {
+      shaderCode.replace(defidx, found - defidx + definevar.length(), IF_1);
+      found = defidx + IF_1.length();
+    }
+    else
+    {
+      found += definevar.length();
+    }
+    found = shaderCode.find(definevar, found);
+  }
+}
+
+ShaderDefinition::RawData
+  ShaderDefinition::LoadRaw(const std::string& shadersPath) const
+{
+  RawData raw;
+
+  bool fail = false;
+  raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
+  if (!fail)
+  {
+    raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
+    if (!fail)
+    {
+      for (auto definevar : mDefines)
+      {
+        ApplyDefine(raw.mVertexShaderSource, definevar);
+        ApplyDefine(raw.mFragmentShaderSource, definevar);
+      }
+    }
+    else
+    {
+      ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" <<
+        shadersPath + mFragmentShaderPath << "'.";
+    }
+  }
+  else
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" <<
+      shadersPath + mVertexShaderPath << "'.";
+  }
+  return raw;
+}
+
+Shader ShaderDefinition::Load(RawData&& raw) const
+{
+  uint32_t hints = Shader::Hint::NONE;
+  for (const auto& hint : mHints)
+  {
+    if (hint == SHADER_HINT_OUTPUT_IS_TRANSPARENT)
+    {
+      hints |= Shader::Hint::OUTPUT_IS_TRANSPARENT;
+    }
+    else if (hint == SHADER_HINT_MODIFIES_GEOMETRY)
+    {
+      hints |= Shader::Hint::MODIFIES_GEOMETRY;
+    }
+  }
+
+  Shader shader = Shader::New(raw.mVertexShaderSource, raw.mFragmentShaderSource,
+    static_cast<Shader::Hint::Value>(hints));
+  for (Property::Map::SizeType i0 = 0, i1 = mUniforms.Count(); i0 != i1; ++i0)
+  {
+    auto pair = mUniforms.GetKeyValue(i0);
+    DALI_ASSERT_ALWAYS(pair.first.type == Property::Key::STRING);
+    shader.RegisterProperty(pair.first.stringKey, pair.second);
+  }
+
+  return shader;
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/shader-definition.h b/dali-scene-loader/public-api/shader-definition.h
new file mode 100644 (file)
index 0000000..29693fb
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef DALI_SCENE_LOADER_SHADER_DEFINITION_H
+#define DALI_SCENE_LOADER_SHADER_DEFINITION_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/renderer-state.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/public-api/rendering/shader.h"
+#include <memory>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/*
+ * @brief Defines a shader with paths to the files which define its
+ *  vertex and fragment components, and a mapping of uniform names (which are
+ *  used to refer to them in GLSL) to data.
+ */
+struct DALI_SCENE_LOADER_API ShaderDefinition
+{
+  using Vector = std::vector<std::pair<ShaderDefinition, Shader>>;
+
+  struct RawData
+  {
+    std::string mVertexShaderSource;
+    std::string mFragmentShaderSource;
+  };
+
+  /*
+   * @brief Apply the defines values to shader.
+   */
+  static void ApplyDefine(std::string& shaderCode, const std::string& definevar);
+
+  ShaderDefinition() = default;
+
+  ShaderDefinition(const ShaderDefinition& other);
+  ShaderDefinition& operator=(const ShaderDefinition& other);
+
+  ShaderDefinition(ShaderDefinition&&) = default;
+  ShaderDefinition& operator=(ShaderDefinition&&) = default;
+
+  /*
+   * @brief Attempts to load the source of the vertex and fragment shaders,
+   *  then performs pre-processing of defines.
+   * @note This may be called from any thread.
+   */
+  RawData LoadRaw(const std::string& shadersPath) const;
+
+  /*
+   * @brief Creates a DALi Shader from the sources in @a raw, traverses
+   *  uniforms to get them to register their data against their name,
+   *  then returns the Shader.
+   * @note This must be called from the event thread.
+   */
+  Shader Load(RawData&& raw) const;
+
+public: // DATA
+  RendererState::Type mRendererState = RendererState::NONE;
+
+  std::string mVertexShaderPath;
+  std::string mFragmentShaderPath;
+  std::vector<std::string> mDefines;
+  std::vector<std::string> mHints;
+
+  Property::Map mUniforms;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_SHADER_DEFINITION_H
diff --git a/dali-scene-loader/public-api/skeleton-definition.h b/dali-scene-loader/public-api/skeleton-definition.h
new file mode 100644 (file)
index 0000000..a06f19b
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_SCENE_LOADER_SKELETON_H
+#define DALI_SCENE_LOADER_SKELETON_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/index.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/public-api/math/matrix.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/*
+ * @brief A set of joints (stored as node indices), and an optional root node index.
+ * @note The list of joints must not be empty and must not contain INVALID_INDEX.
+ * @note Client code should not change the order of joints, as they are indexed by mesh vertex data.
+ * @note Client code should make no assumption about the relation of the joint IDs.
+ */
+struct DALI_SCENE_LOADER_API SkeletonDefinition
+{
+  struct Joint
+  {
+    Index mNodeIdx;
+    Matrix mInverseBindMatrix;
+  };
+
+  using Vector = std::vector<SkeletonDefinition>;
+
+  Index mRootNodeIdx = INVALID_INDEX;
+  std::vector<Joint> mJoints;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_SKELETON_H
diff --git a/dali-scene-loader/public-api/skinning-details.cpp b/dali-scene-loader/public-api/skinning-details.cpp
new file mode 100644 (file)
index 0000000..92ded02
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/skinning-details.h"
+#include "dali/public-api/rendering/shader.h"
+#include "dali/public-api/object/property.h"
+#include "dali/public-api/animation/constraints.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+const unsigned int Skinning::MAX_JOINTS = 64;
+
+const std::string Skinning::BONE_UNIFORM_NAME = "uBone";
+
+}
+}
diff --git a/dali-scene-loader/public-api/skinning-details.h b/dali-scene-loader/public-api/skinning-details.h
new file mode 100644 (file)
index 0000000..38dd628
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_SCENE_LOADER_SKINNING_DETAILS_H_
+#define DALI_SCENE_LOADER_SKINNING_DETAILS_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/rendering/shader.h"
+#include <string>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+struct DALI_SCENE_LOADER_API Skinning
+{
+  /*
+   * @brief Upper limit on the number of joints supported.
+   */
+  static const uint32_t MAX_JOINTS;
+
+  /*
+   * @brief Name of bone matrix uniform (array).
+   */
+  static const std::string BONE_UNIFORM_NAME;
+};
+
+}
+}
+
+#endif // DALI_SCENE_LOADER_SKINNING_DETAILS_H_
diff --git a/dali-scene-loader/public-api/string-callback.cpp b/dali-scene-loader/public-api/string-callback.cpp
new file mode 100644 (file)
index 0000000..d13fc15
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/string-callback.h"
+#include "dali/integration-api/debug.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+void DefaultErrorCallback(const std::string& message)
+{
+  DALI_LOG_ERROR("%s", message.c_str());
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/string-callback.h b/dali-scene-loader/public-api/string-callback.h
new file mode 100644 (file)
index 0000000..9569b2d
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DALI_SCENE_LOADER_STRING_CALLBACK_H
+#define DALI_SCENE_LOADER_STRING_CALLBACK_H
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include <functional>
+#include <string>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/*
+ * @brief A callback to post strings to.
+ */
+using StringCallback = std::function<void(const std::string&)>;
+
+/*
+ * @brief Simply passes the formatted message to LOGE().
+ */
+DALI_SCENE_LOADER_API void DefaultErrorCallback(const std::string& message);
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_STRING_CALLBACK_H
diff --git a/dali-scene-loader/public-api/utils.cpp b/dali-scene-loader/public-api/utils.cpp
new file mode 100644 (file)
index 0000000..773bf17
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL
+#include "dali-scene-loader/public-api/utils.h"
+
+// EXTERNAL
+#include "dali/public-api/common/vector-wrapper.h"
+#include "dali/public-api/animation/constraints.h"
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <stdarg.h>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+namespace
+{
+thread_local char sExceptionFlingerMessageBuffer[ExceptionFlinger::MESSAGE_BUFFER_SIZE]{};
+}
+
+char* ExceptionFlinger::GetMessageBuffer()
+{
+  return sExceptionFlingerMessageBuffer;
+}
+
+std::string FormatString(const char* format, ...)
+{
+  va_list vl;
+  va_start(vl, format);
+  va_list vl2;
+  va_copy(vl2, vl);
+
+  size_t sizeRequired = vsnprintf(nullptr, 0, format, vl);
+  va_end(vl);
+
+  ++sizeRequired;
+  std::string result(sizeRequired, '\0');
+  vsnprintf(&result[0], sizeRequired, format, vl2);
+  va_end(vl2);
+
+  return result;
+}
+
+std::string LoadTextFile(const char * path, bool* fail)
+{
+  std::ifstream inFile(path);
+  if (inFile)
+  {
+    std::istreambuf_iterator<char> eos;
+    std::istreambuf_iterator<char> i(inFile.rdbuf());
+    return std::string(i, eos);
+  }
+  else if (fail)
+  {
+    *fail = true;
+  }
+  return std::string();
+}
+
+Geometry MakeTexturedQuadGeometry(TexturedQuadOptions::Type options)
+{
+  Property::Map properties;
+  properties.Insert("aPosition", Property::VECTOR3);
+  properties.Insert("aTexCoord", Property::VECTOR2);
+
+  std::vector<uint8_t> bytes;
+  size_t stride = 0;
+  size_t uvOffset = 0;
+  struct
+  {
+    Vector3 aPosition;
+    Vector2 aTexCoord;
+  } vertices[] = {
+    { Vector3(-0.5f, 0.5f, 0.0f), Vector2(0.0f, .0f) },
+    { Vector3(0.5f, 0.5f, 0.0f), Vector2(1.0f, .0f) },
+    { Vector3(-0.5f, -0.5f, 0.0f), Vector2(0.0f, 1.0f) },
+    { Vector3(0.5f, -0.5f, 0.0f), Vector2(1.0f, 1.0f) }
+  };
+
+  bytes.resize(sizeof(vertices));
+  stride = sizeof(vertices[0]);
+  uvOffset = reinterpret_cast<const uint8_t*>(&vertices[0].aTexCoord) - reinterpret_cast<const uint8_t*>(&vertices[0]);
+
+  std::memcpy(bytes.data(), vertices, sizeof(vertices));
+
+  if (MaskMatch(options, TexturedQuadOptions::FLIP_VERTICAL))
+  {
+    Vector2* uv = reinterpret_cast<Vector2*>(reinterpret_cast<uint8_t*>(bytes.data()) + uvOffset);
+    for (int i = 0; i < 4; ++i)
+    {
+      uv->y = 1.0f - uv->y;
+      uv = reinterpret_cast<Vector2*>(reinterpret_cast<uint8_t*>(uv) + stride);
+    }
+  }
+
+  VertexBuffer vertexBuffer = VertexBuffer::New(properties);
+  vertexBuffer.SetData(bytes.data(), bytes.size() / stride);
+
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer(vertexBuffer);
+  geometry.SetType(Geometry::TRIANGLE_STRIP);
+  return geometry;
+}
+
+void ToUnixFileSeparators(std::string& path)
+{
+  std::replace(path.begin(), path.end(), '\\', '/');
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/utils.h b/dali-scene-loader/public-api/utils.h
new file mode 100644 (file)
index 0000000..09c30e1
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef DALI_SCENE_LOADER_UTILS_H_
+#define DALI_SCENE_LOADER_UTILS_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/actors/actor.h"
+#include "dali/public-api/rendering/renderer.h"
+#include "dali/public-api/common/dali-common.h"
+#include <sstream>
+#include <cctype>
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/*
+ * @brief Fixed size backing buffer to use with std::ostreams where control over
+ *  allocations (which this does not make), is required.
+ * @note All stream insertions that would overflow the buffer that StreamBuffer
+ *  was created with, will fail.
+ */
+class DALI_SCENE_LOADER_API StreamBuffer : public std::basic_streambuf<char>
+{
+public:
+  StreamBuffer(char* buffer, size_t size)
+  {
+    setp(buffer, buffer + size);
+  }
+};
+
+/*
+ * @brief Wraps an ostream with a pre-allocated, fixed size backing buffer
+ *  which a message can be formatted into. Upon destruction, it throws a
+ *  DaliException with the message.
+ */
+class DALI_SCENE_LOADER_API ExceptionFlinger
+{
+public:
+  enum { MESSAGE_BUFFER_SIZE = 512 };
+
+  ExceptionFlinger(const char* location)
+  : mLocation(location),
+    mStreamBuffer(GetMessageBuffer(), MESSAGE_BUFFER_SIZE - 1),
+    mStream(&mStreamBuffer)
+  {}
+
+  ~ExceptionFlinger() noexcept(false)
+  {
+    operator<<('\0');
+    throw DaliException(mLocation, GetMessageBuffer());
+  }
+
+  template <typename T>
+  ExceptionFlinger& operator<<(const T& rhs)
+  {
+    mStream << rhs;
+    return *this;
+  }
+
+private:
+  static char* GetMessageBuffer();
+
+  const char* mLocation;
+  StreamBuffer mStreamBuffer;
+  std::ostream mStream;
+};
+
+/*
+ * @brief Formats the given printf-style varargs into a std::string.
+ */
+DALI_SCENE_LOADER_API std::string FormatString(const char* format, ...);
+
+/*
+ * @return The @n th bit in a bitmask.
+ */
+DALI_SCENE_LOADER_API constexpr size_t NthBit(size_t n) { return 1 << n; }
+
+/*
+ * @return Whether all of @a mask 's bits are set on @a value.
+ */
+inline
+DALI_SCENE_LOADER_API bool MaskMatch(uint32_t value, uint32_t mask)
+{
+  return (value & mask) == mask;
+}
+
+/*
+ * @brief Convert a four-letter(, null-terminated) string literal into a uint32_t.
+ */
+inline
+DALI_SCENE_LOADER_API constexpr uint32_t FourCC(const char(&fourCC)[5])
+{
+  return (fourCC[3] << 24) | (fourCC[2] << 16) | (fourCC[1] << 8) | fourCC[0];
+}
+
+/*
+ * @brief Insensitive case compare function.
+ * @param[in] a, compare string
+ * @param[in] b, compare string
+ * @return true if strings are equal
+ */
+inline
+DALI_SCENE_LOADER_API bool CaseInsensitiveCharacterCompare( unsigned char a, unsigned char b )
+{
+  // Converts to lower case in the current locale.
+  return std::tolower( a ) == std::tolower( b );
+}
+
+/*
+ * @return true if the lower cased ASCII strings are equal.
+ * @param[in] a, compare string
+ * @param[in] b, compare string
+ */
+inline
+DALI_SCENE_LOADER_API bool CaseInsensitiveStringCompare( const std::string& a, const std::string& b )
+{
+  bool result = false;
+  if( a.length() == b.length() )
+  {
+    result = std::equal( a.begin(), a.end(), b.begin(), &CaseInsensitiveCharacterCompare );
+  }
+  return result;
+}
+
+/*
+ * @brief Attempts to load the contents of a text file; returns empty string on
+ *  failure. A pointer to a boolean may be passed in @a fail; this will be set
+ *  to true in case of failure (should only be checked if the returned string
+ *  was empty()).
+ */
+DALI_SCENE_LOADER_API std::string LoadTextFile(const char* path, bool* fail = nullptr);
+
+/*
+ * @brief Makes a number of calls to @a fn, passing to each one the given
+ *  @a actor then each of its children, in depth-first traversal.
+ * @note @a fn must not change the actor hierarchy during traversal.
+ * @note Use of a @a fn that is itself recursing in @a is also discouraged
+ *  for performance and stability reasons.
+ */
+template <typename Func>
+inline
+DALI_SCENE_LOADER_API void VisitActor(Actor a, Func fn)
+{
+  fn(a);
+
+  unsigned int numChildren = a.GetChildCount();
+  for(unsigned int i = 0; i < numChildren; ++i)
+  {
+    VisitActor(a.GetChildAt(i), fn);
+  }
+}
+
+/*
+ * @brief Convenience function to set the given actor @a 's anchor point
+ *  and parent origin to center.
+ */
+inline
+DALI_SCENE_LOADER_API void SetActorCentered(Actor a)
+{
+  a.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  a.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+}
+
+namespace TexturedQuadOptions
+{
+using Type = uint32_t;
+
+enum DALI_SCENE_LOADER_API Values : Type
+{
+  NONE = 0x00,
+  FLIP_VERTICAL = 0x01,
+};
+}
+
+/*
+ * @brief Makes... geometry for a textured quad.
+ */
+DALI_SCENE_LOADER_API Geometry MakeTexturedQuadGeometry(TexturedQuadOptions::Type options = TexturedQuadOptions::NONE);
+
+/*
+ * @brief Fixes the path of a file. Replaces the '\\' separator by the '/' one.
+ * @param[in,out] path The path to be fixed.
+ */
+DALI_SCENE_LOADER_API void ToUnixFileSeparators( std::string& path );
+
+}
+}
+
+#endif /* DALI_SCENE_LOADER_UTILS_H_ */
diff --git a/dali-scene-loader/public-api/view-projection.cpp b/dali-scene-loader/public-api/view-projection.cpp
new file mode 100644 (file)
index 0000000..ed8cbe3
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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 "dali-scene-loader/public-api/view-projection.h"
+#include "dali-scene-loader/public-api/utils.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+void ViewProjection::Update()
+{
+  Matrix::Multiply(mViewProjection, mView, mProjection);
+
+  mInvProjection = mProjection;
+  if (!mInvProjection.Invert())
+  {
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to find inverse of projection matrix " << mProjection << ".";
+  }
+}
+
+}
+}
diff --git a/dali-scene-loader/public-api/view-projection.h b/dali-scene-loader/public-api/view-projection.h
new file mode 100644 (file)
index 0000000..70efc4f
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_SCENE_LOADER_VIEW_PROJECTION_H_
+#define DALI_SCENE_LOADER_VIEW_PROJECTION_H_
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "dali-scene-loader/public-api/api.h"
+
+// EXTERNAL INCLUDES
+#include "dali/public-api/math/matrix.h"
+
+namespace Dali
+{
+namespace SceneLoader
+{
+
+/**
+ * @brief Contains view and projection matrices, also caching the view-projection
+ *      and inverse projection matrices.
+ */
+class ViewProjection
+{
+public:
+  Matrix& GetView() { return mView; }
+  Matrix& GetProjection() { return mProjection; }
+
+  /*
+   * @brief Updates the cached view projection and inverse projection matrices.
+   */
+  void Update();
+
+  const Matrix& GetView() const { return mView; }
+  const Matrix& GetProjection() const { return mProjection; }
+  const Matrix& GetInverseProjection() const { return mInvProjection; }
+  const Matrix& GetViewProjection() const { return mViewProjection; }
+
+private:
+  Matrix mView;
+  Matrix mProjection;
+  Matrix mInvProjection;
+  Matrix mViewProjection;
+};
+
+}
+}
+
+#endif //DALI_SCENE_LOADER_VIEW_PROJECTION_H_
diff --git a/dali-scene-loader/third-party/json.h b/dali-scene-loader/third-party/json.h
new file mode 100644 (file)
index 0000000..925c50b
--- /dev/null
@@ -0,0 +1,3134 @@
+/*
+   The latest version of this library is available on GitHub;
+   https://github.com/sheredom/json.h.
+*/
+
+/*
+   This is free and unencumbered software released into the public domain.
+
+   Anyone is free to copy, modify, publish, use, compile, sell, or
+   distribute this software, either in source code form or as a compiled
+   binary, for any purpose, commercial or non-commercial, and by any
+   means.
+
+   In jurisdictions that recognize copyright laws, the author or authors
+   of this software dedicate any and all copyright interest in the
+   software to the public domain. We make this dedication for the benefit
+   of the public at large and to the detriment of our heirs and
+   successors. We intend this dedication to be an overt act of
+   relinquishment in perpetuity of all present and future rights to this
+   software under copyright law.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+
+   For more information, please refer to <http://unlicense.org/>.
+*/
+
+#ifndef SHEREDOM_JSON_H_INCLUDED
+#define SHEREDOM_JSON_H_INCLUDED
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+
+/* disable 'bytes padding added after construct' warning */
+#pragma warning(disable : 4820)
+#endif
+
+#include <stddef.h>
+
+#if defined(__clang__) || defined(__GNUC__)
+#define json_weak __attribute__((weak))
+#elif defined(_MSC_VER)
+#define json_weak __inline
+#else
+#error Non clang, non gcc, non MSVC compiler found!
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  struct json_value_s;
+  struct json_parse_result_s;
+
+  enum json_parse_flags_e {
+    json_parse_flags_default = 0,
+
+    /* allow trailing commas in objects and arrays. For example, both [true,] and
+       {"a" : null,} would be allowed with this option on. */
+    json_parse_flags_allow_trailing_comma = 0x1,
+
+    /* allow unquoted keys for objects. For example, {a : null} would be allowed
+       with this option on. */
+    json_parse_flags_allow_unquoted_keys = 0x2,
+
+    /* allow a global unbracketed object. For example, a : null, b : true, c : {}
+       would be allowed with this option on. */
+    json_parse_flags_allow_global_object = 0x4,
+
+    /* allow objects to use '=' instead of ':' between key/value pairs. For
+       example, a = null, b : true would be allowed with this option on. */
+    json_parse_flags_allow_equals_in_object = 0x8,
+
+    /* allow that objects don't have to have comma separators between key/value
+       pairs. */
+    json_parse_flags_allow_no_commas = 0x10,
+
+    /* allow c-style comments (either variants) to be ignored in the input JSON
+       file. */
+    json_parse_flags_allow_c_style_comments = 0x20,
+
+    /* deprecated flag, unused. */
+    json_parse_flags_deprecated = 0x40,
+
+    /* record location information for each value. */
+    json_parse_flags_allow_location_information = 0x80,
+
+    /* allow strings to be 'single quoted'. */
+    json_parse_flags_allow_single_quoted_strings = 0x100,
+
+    /* allow numbers to be hexadecimal. */
+    json_parse_flags_allow_hexadecimal_numbers = 0x200,
+
+    /* allow numbers like +123 to be parsed. */
+    json_parse_flags_allow_leading_plus_sign = 0x400,
+
+    /* allow numbers like .0123 or 123. to be parsed. */
+    json_parse_flags_allow_leading_or_trailing_decimal_point = 0x800,
+
+    /* allow Infinity, -Infinity, NaN, -NaN. */
+    json_parse_flags_allow_inf_and_nan = 0x1000,
+
+    /* allow multi line string values. */
+    json_parse_flags_allow_multi_line_strings = 0x2000,
+
+    /* allow simplified JSON to be parsed. Simplified JSON is an enabling of a set
+       of other parsing options. */
+    json_parse_flags_allow_simplified_json =
+    (json_parse_flags_allow_trailing_comma |
+      json_parse_flags_allow_unquoted_keys |
+      json_parse_flags_allow_global_object |
+      json_parse_flags_allow_equals_in_object |
+      json_parse_flags_allow_no_commas),
+
+    /* allow JSON5 to be parsed. JSON5 is an enabling of a set of other parsing
+       options. */
+    json_parse_flags_allow_json5 =
+    (json_parse_flags_allow_trailing_comma |
+      json_parse_flags_allow_unquoted_keys |
+      json_parse_flags_allow_c_style_comments |
+      json_parse_flags_allow_single_quoted_strings |
+      json_parse_flags_allow_hexadecimal_numbers |
+      json_parse_flags_allow_leading_plus_sign |
+      json_parse_flags_allow_leading_or_trailing_decimal_point |
+      json_parse_flags_allow_inf_and_nan |
+      json_parse_flags_allow_multi_line_strings)
+  };
+
+  /* Parse a JSON text file, returning a pointer to the root of the JSON
+   * structure. json_parse performs 1 call to malloc for the entire encoding.
+   * Returns 0 if an error occurred (malformed JSON input, or malloc failed). */
+  json_weak struct json_value_s *json_parse(const void *src, size_t src_size);
+
+  /* Parse a JSON text file, returning a pointer to the root of the JSON
+   * structure. json_parse performs 1 call to malloc for the entire encoding.
+   * Returns 0 if an error occurred (malformed JSON input, or malloc failed). If
+   * an error occurred, the result struct (if not NULL) will explain the type of
+   * error, and the location in the input it occurred. */
+  json_weak struct json_value_s *
+    json_parse_ex(const void *src, size_t src_size, size_t flags_bitset,
+      void *(*alloc_func_ptr)(void *, size_t), void *user_data,
+      struct json_parse_result_s *result);
+
+  /* Write out a minified JSON utf-8 string. This string is an encoding of the
+   * minimal string characters required to still encode the same data.
+   * json_write_minified performs 1 call to malloc for the entire encoding. Return
+   * 0 if an error occurred (malformed JSON input, or malloc failed). The out_size
+   * parameter is optional as the utf-8 string is null terminated. */
+  json_weak void *json_write_minified(const struct json_value_s *value,
+    size_t *out_size);
+
+  /* Write out a pretty JSON utf-8 string. This string is encoded such that the
+   * resultant JSON is pretty in that it is easily human readable. The indent and
+   * newline parameters allow a user to specify what kind of indentation and
+   * newline they want (two spaces / three spaces / tabs? \r, \n, \r\n ?). Both
+   * indent and newline can be NULL, indent defaults to two spaces ("  "), and
+   * newline defaults to linux newlines ('\n' as the newline character).
+   * json_write_pretty performs 1 call to malloc for the entire encoding. Return 0
+   * if an error occurred (malformed JSON input, or malloc failed). The out_size
+   * parameter is optional as the utf-8 string is null terminated. */
+  json_weak void *json_write_pretty(const struct json_value_s *value,
+    const char *indent, const char *newline,
+    size_t *out_size);
+
+  /* Reinterpret a JSON value as a string. Returns null is the value was not a
+   * string. */
+  json_weak struct json_string_s *
+    json_value_as_string(struct json_value_s *const value);
+
+  /* Reinterpret a JSON value as a number. Returns null is the value was not a
+   * number. */
+  json_weak struct json_number_s *
+    json_value_as_number(struct json_value_s *const value);
+
+  /* Reinterpret a JSON value as an object. Returns null is the value was not an
+   * object. */
+  json_weak struct json_object_s *
+    json_value_as_object(struct json_value_s *const value);
+
+  /* Reinterpret a JSON value as an array. Returns null is the value was not an
+   * array. */
+  json_weak struct json_array_s *
+    json_value_as_array(struct json_value_s *const value);
+
+  /* Whether the value is true. */
+  json_weak int json_value_is_true(const struct json_value_s *const value);
+
+  /* Whether the value is false. */
+  json_weak int json_value_is_false(const struct json_value_s *const value);
+
+  /* Whether the value is null. */
+  json_weak int json_value_is_null(const struct json_value_s *const value);
+
+  /* The various types JSON values can be. Used to identify what a value is. */
+  enum json_type_e {
+    json_type_string,
+    json_type_number,
+    json_type_object,
+    json_type_array,
+    json_type_true,
+    json_type_false,
+    json_type_null
+  };
+
+  /* A JSON string value. */
+  struct json_string_s {
+    /* utf-8 string */
+    const char *string;
+    /* The size (in bytes) of the string */
+    size_t string_size;
+  };
+
+  /* A JSON string value (extended). */
+  struct json_string_ex_s {
+    /* The JSON string this extends. */
+    struct json_string_s string;
+
+    /* The character offset for the value in the JSON input. */
+    size_t offset;
+
+    /* The line number for the value in the JSON input. */
+    size_t line_no;
+
+    /* The row number for the value in the JSON input, in bytes. */
+    size_t row_no;
+  };
+
+  /* A JSON number value. */
+  struct json_number_s {
+    /* ASCII string containing representation of the number. */
+    const char *number;
+    /* the size (in bytes) of the number. */
+    size_t number_size;
+  };
+
+  /* an element of a JSON object. */
+  struct json_object_element_s {
+    /* the name of this element. */
+    struct json_string_s *name;
+    /* the value of this element. */
+    struct json_value_s *value;
+    /* the next object element (can be NULL if the last element in the object). */
+    struct json_object_element_s *next;
+  };
+
+  /* a JSON object value. */
+  struct json_object_s {
+    /* a linked list of the elements in the object. */
+    struct json_object_element_s *start;
+    /* the number of elements in the object. */
+    size_t length;
+  };
+
+  /* an element of a JSON array. */
+  struct json_array_element_s {
+    /* the value of this element. */
+    struct json_value_s *value;
+    /* the next array element (can be NULL if the last element in the array). */
+    struct json_array_element_s *next;
+  };
+
+  /* a JSON array value. */
+  struct json_array_s {
+    /* a linked list of the elements in the array. */
+    struct json_array_element_s *start;
+    /* the number of elements in the array. */
+    size_t length;
+  };
+
+  /* a JSON value. */
+  struct json_value_s {
+    /* a pointer to either a json_string_s, json_number_s, json_object_s, or. */
+    /* json_array_s. Should be cast to the appropriate struct type based on what.
+     */
+     /* the type of this value is. */
+    void *payload;
+    /* must be one of json_type_e. If type is json_type_true, json_type_false, or.
+     */
+     /* json_type_null, payload will be NULL. */
+    size_t type;
+  };
+
+  /* a JSON value (extended). */
+  struct json_value_ex_s {
+    /* the JSON value this extends. */
+    struct json_value_s value;
+
+    /* the character offset for the value in the JSON input. */
+    size_t offset;
+
+    /* the line number for the value in the JSON input. */
+    size_t line_no;
+
+    /* the row number for the value in the JSON input, in bytes. */
+    size_t row_no;
+  };
+
+  /* a parsing error code. */
+  enum json_parse_error_e {
+    /* no error occurred (huzzah!). */
+    json_parse_error_none = 0,
+
+    /* expected either a comma or a closing '}' or ']' to close an object or. */
+    /* array! */
+    json_parse_error_expected_comma_or_closing_bracket,
+
+    /* colon separating name/value pair was missing! */
+    json_parse_error_expected_colon,
+
+    /* expected string to begin with '"'! */
+    json_parse_error_expected_opening_quote,
+
+    /* invalid escaped sequence in string! */
+    json_parse_error_invalid_string_escape_sequence,
+
+    /* invalid number format! */
+    json_parse_error_invalid_number_format,
+
+    /* invalid value! */
+    json_parse_error_invalid_value,
+
+    /* reached end of buffer before object/array was complete! */
+    json_parse_error_premature_end_of_buffer,
+
+    /* string was malformed! */
+    json_parse_error_invalid_string,
+
+    /* a call to malloc, or a user provider allocator, failed. */
+    json_parse_error_allocator_failed,
+
+    /* the JSON input had unexpected trailing characters that weren't part of the.
+     */
+     /* JSON value. */
+     json_parse_error_unexpected_trailing_characters,
+
+     /* catch-all error for everything else that exploded (real bad chi!). */
+     json_parse_error_unknown
+  };
+
+  /* error report from json_parse_ex(). */
+  struct json_parse_result_s {
+    /* the error code (one of json_parse_error_e). */
+    size_t error;
+
+    /* the character offset for the error in the JSON input. */
+    size_t error_offset;
+
+    /* the line number for the error in the JSON input. */
+    size_t error_line_no;
+
+    /* the row number for the error, in bytes. */
+    size_t error_row_no;
+  };
+
+#ifdef __cplusplus
+} /* extern "C". */
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#include <stdlib.h>
+
+#if defined(_MSC_VER)
+#define json_strtoumax _strtoui64
+#define json_uintmax_t unsigned __int64
+#else
+#include <inttypes.h>
+#define json_strtoumax strtoumax
+#define json_uintmax_t uintmax_t
+#endif
+
+#if defined(__cplusplus) && (__cplusplus >= 201103L)
+#define json_null nullptr
+#else
+#define json_null 0
+#endif
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+
+/* we do one big allocation via malloc, then cast aligned slices of this for. */
+/* our structures - we don't have a way to tell the compiler we know what we. */
+/* are doing, so disable the warning instead! */
+#pragma clang diagnostic ignored "-Wcast-align"
+
+/* We use C style casts everywhere. */
+#pragma clang diagnostic ignored "-Wold-style-cast"
+
+/* We need long long for strtoull. */
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+
+/* Who cares if nullptr doesn't work with C++98, we don't use it there! */
+#pragma clang diagnostic ignored "-Wc++98-compat"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#elif defined(_MSC_VER)
+#pragma warning(push)
+
+/* disable 'function selected for inline expansion' warning. */
+#pragma warning(disable : 4711)
+
+/* disable '#pragma warning: there is no warning number' warning. */
+#pragma warning(disable : 4619)
+
+/* disable 'warning number not a valid compiler warning' warning. */
+#pragma warning(disable : 4616)
+
+/* disable 'Compiler will insert Spectre mitigation for memory load if
+ * /Qspectre. */
+ /* switch specified' warning. */
+#pragma warning(disable : 5045)
+#endif
+
+struct json_parse_state_s {
+  const char *src;
+  size_t size;
+  size_t offset;
+  size_t flags_bitset;
+  char *data;
+  char *dom;
+  size_t dom_size;
+  size_t data_size;
+  size_t line_no;     /* line counter for error reporting. */
+  size_t line_offset; /* (offset-line_offset) is the character number (in
+                         bytes). */
+  size_t error;
+};
+
+json_weak int json_hexadecimal_digit(const char c);
+int json_hexadecimal_digit(const char c) {
+  if ('0' <= c && c <= '9') {
+    return c - '0';
+  }
+  if ('a' <= c && c <= 'f') {
+    return c - 'a' + 10;
+  }
+  if ('A' <= c && c <= 'F') {
+    return c - 'A' + 10;
+  }
+  return -1;
+}
+
+json_weak int json_hexadecimal_value(const char * c, const unsigned long size, unsigned long * result);
+int json_hexadecimal_value(const char * c, const unsigned long size, unsigned long * result) {
+  const char * p;
+  int digit;
+
+  if (size > sizeof(unsigned long) * 2) {
+    return 0;
+  }
+
+  *result = 0;
+  for (p = c; (unsigned long)(p - c) < size; ++p) {
+    *result <<= 4;
+    digit = json_hexadecimal_digit(*p);
+    if (digit < 0 || digit > 15) {
+      return 0;
+    }
+    *result |= (unsigned char)digit;
+  }
+  return 1;
+}
+
+json_weak int json_skip_whitespace(struct json_parse_state_s *state);
+int json_skip_whitespace(struct json_parse_state_s *state) {
+  size_t offset = state->offset;
+  const size_t size = state->size;
+  const char *const src = state->src;
+
+  /* the only valid whitespace according to ECMA-404 is ' ', '\n', '\r' and
+   * '\t'. */
+  switch (src[offset]) {
+  default:
+    return 0;
+  case ' ':
+  case '\r':
+  case '\t':
+  case '\n':
+    break;
+  }
+
+  do {
+    switch (src[offset]) {
+    default:
+      /* Update offset. */
+      state->offset = offset;
+      return 1;
+    case ' ':
+    case '\r':
+    case '\t':
+      break;
+    case '\n':
+      state->line_no++;
+      state->line_offset = offset;
+      break;
+    }
+
+    offset++;
+  } while (offset < size);
+
+  /* Update offset. */
+  state->offset = offset;
+  return 1;
+}
+
+json_weak int json_skip_c_style_comments(struct json_parse_state_s *state);
+int json_skip_c_style_comments(struct json_parse_state_s *state) {
+  /* do we have a comment?. */
+  if ('/' == state->src[state->offset]) {
+    /* skip '/'. */
+    state->offset++;
+
+    if ('/' == state->src[state->offset]) {
+      /* we had a comment of the form //. */
+
+      /* skip second '/'. */
+      state->offset++;
+
+      while (state->offset < state->size) {
+        switch (state->src[state->offset]) {
+        default:
+          /* skip the character in the comment. */
+          state->offset++;
+          break;
+        case '\n':
+          /* if we have a newline, our comment has ended! Skip the newline. */
+          state->offset++;
+
+          /* we entered a newline, so move our line info forward. */
+          state->line_no++;
+          state->line_offset = state->offset;
+          return 1;
+        }
+      }
+
+      /* we reached the end of the JSON file! */
+      return 1;
+    }
+    else if ('*' == state->src[state->offset]) {
+      /* we had a comment in the C-style long form. */
+
+      /* skip '*'. */
+      state->offset++;
+
+      while (state->offset + 1 < state->size) {
+        if (('*' == state->src[state->offset]) &&
+          ('/' == state->src[state->offset + 1])) {
+          /* we reached the end of our comment! */
+          state->offset += 2;
+          return 1;
+        }
+        else if ('\n' == state->src[state->offset]) {
+          /* we entered a newline, so move our line info forward. */
+          state->line_no++;
+          state->line_offset = state->offset;
+        }
+
+        /* skip character within comment. */
+        state->offset++;
+      }
+
+      /* Comment wasn't ended correctly which is a failure. */
+      return 1;
+    }
+  }
+
+  /* we didn't have any comment, which is ok too! */
+  return 0;
+}
+
+json_weak int json_skip_all_skippables(struct json_parse_state_s *state);
+int json_skip_all_skippables(struct json_parse_state_s *state) {
+  /* skip all whitespace and other skippables until there are none left. note
+   * that the previous version suffered from read past errors should. the
+   * stream end on json_skip_c_style_comments eg. '{"a" ' with comments flag.
+   */
+
+  int did_consume = 0;
+  const size_t size = state->size;
+
+  if (json_parse_flags_allow_c_style_comments & state->flags_bitset) {
+    do {
+      if (state->offset == size) {
+        state->error = json_parse_error_premature_end_of_buffer;
+        return 1;
+      }
+
+      did_consume = json_skip_whitespace(state);
+
+      /* This should really be checked on access, not in front of every call.
+       */
+      if (state->offset == size) {
+        state->error = json_parse_error_premature_end_of_buffer;
+        return 1;
+      }
+
+      did_consume |= json_skip_c_style_comments(state);
+    } while (0 != did_consume);
+  }
+  else {
+    do {
+      if (state->offset == size) {
+        state->error = json_parse_error_premature_end_of_buffer;
+        return 1;
+      }
+
+      did_consume = json_skip_whitespace(state);
+    } while (0 != did_consume);
+  }
+
+  if (state->offset == size) {
+    state->error = json_parse_error_premature_end_of_buffer;
+    return 1;
+  }
+
+  return 0;
+}
+
+json_weak int json_get_value_size(struct json_parse_state_s *state,
+  int is_global_object);
+
+json_weak int json_get_string_size(struct json_parse_state_s *state,
+  size_t is_key);
+int json_get_string_size(struct json_parse_state_s *state,
+  size_t is_key) {
+  size_t offset = state->offset;
+  const size_t size = state->size;
+  size_t data_size = 0;
+  const char *const src = state->src;
+  const int is_single_quote = '\'' == src[offset];
+  const char quote_to_use = is_single_quote ? '\'' : '"';
+  const size_t flags_bitset = state->flags_bitset;
+  unsigned long codepoint;
+  unsigned long high_surrogate = 0;
+
+  if ((json_parse_flags_allow_location_information & flags_bitset) != 0 &&
+    is_key != 0) {
+    state->dom_size += sizeof(struct json_string_ex_s);
+  }
+  else {
+    state->dom_size += sizeof(struct json_string_s);
+  }
+
+  if ('"' != src[offset]) {
+    /* if we are allowed single quoted strings check for that too. */
+    if (!((json_parse_flags_allow_single_quoted_strings & flags_bitset) &&
+      is_single_quote)) {
+      state->error = json_parse_error_expected_opening_quote;
+      state->offset = offset;
+      return 1;
+    }
+  }
+
+  /* skip leading '"' or '\''. */
+  offset++;
+
+  while ((offset < size) && (quote_to_use != src[offset])) {
+    /* add space for the character. */
+    data_size++;
+
+    if ('\\' == src[offset]) {
+      /* skip reverse solidus character. */
+      offset++;
+
+      if (offset == size) {
+        state->error = json_parse_error_premature_end_of_buffer;
+        state->offset = offset;
+        return 1;
+      }
+
+      switch (src[offset]) {
+      default:
+        state->error = json_parse_error_invalid_string_escape_sequence;
+        state->offset = offset;
+        return 1;
+      case '"':
+      case '\\':
+      case '/':
+      case 'b':
+      case 'f':
+      case 'n':
+      case 'r':
+      case 't':
+        /* all valid characters! */
+        offset++;
+        break;
+      case 'u':
+        if (!(offset + 5 < size)) {
+          /* invalid escaped unicode sequence! */
+          state->error = json_parse_error_invalid_string_escape_sequence;
+          state->offset = offset;
+          return 1;
+        }
+
+        codepoint = 0;
+        if (!json_hexadecimal_value(&src[offset + 1], 4, &codepoint)) {
+          /* escaped unicode sequences must contain 4 hexadecimal digits! */
+          state->error = json_parse_error_invalid_string_escape_sequence;
+          state->offset = offset;
+          return 1;
+        }
+
+        /* Valid sequence!
+         * see: https://en.wikipedia.org/wiki/UTF-8#Invalid_code_points.
+         *      1       7       U + 0000        U + 007F        0xxxxxxx.
+         *      2       11      U + 0080        U + 07FF        110xxxxx
+         * 10xxxxxx.
+         *      3       16      U + 0800        U + FFFF        1110xxxx
+         * 10xxxxxx        10xxxxxx.
+         *      4       21      U + 10000       U + 10FFFF      11110xxx
+         * 10xxxxxx        10xxxxxx        10xxxxxx.
+         * Note: the high and low surrogate halves used by UTF-16 (U+D800
+         * through U+DFFF) and code points not encodable by UTF-16 (those after
+         * U+10FFFF) are not legal Unicode values, and their UTF-8 encoding must
+         * be treated as an invalid byte sequence. */
+
+        if (high_surrogate != 0) {
+          /* we previously read the high half of the \uxxxx\uxxxx pair, so now
+           * we expect the low half. */
+          if (codepoint >= 0xdc00 &&
+            codepoint <= 0xdfff) { /* low surrogate range. */
+            data_size += 3;
+            high_surrogate = 0;
+          }
+          else {
+            state->error = json_parse_error_invalid_string_escape_sequence;
+            state->offset = offset;
+            return 1;
+          }
+        }
+        else if (codepoint <= 0x7f) {
+          data_size += 0;
+        }
+        else if (codepoint <= 0x7ff) {
+          data_size += 1;
+        }
+        else if (codepoint >= 0xd800 &&
+          codepoint <= 0xdbff) { /* high surrogate range. */
+ /* The codepoint is the first half of a "utf-16 surrogate pair". so we
+  * need the other half for it to be valid: \uHHHH\uLLLL. */
+          if (offset + 11 > size || '\\' != src[offset + 5] ||
+            'u' != src[offset + 6]) {
+            state->error = json_parse_error_invalid_string_escape_sequence;
+            state->offset = offset;
+            return 1;
+          }
+          high_surrogate = codepoint;
+        }
+        else if (codepoint >= 0xd800 &&
+          codepoint <= 0xdfff) { /* low surrogate range. */
+ /* we did not read the other half before. */
+          state->error = json_parse_error_invalid_string_escape_sequence;
+          state->offset = offset;
+          return 1;
+        }
+        else {
+          data_size += 2;
+        }
+        /* escaped codepoints after 0xffff are supported in json through utf-16
+         * surrogate pairs: \uD83D\uDD25 for U+1F525. */
+
+        offset += 5;
+        break;
+      }
+    }
+    else if (('\r' == src[offset]) || ('\n' == src[offset])) {
+      if (!(json_parse_flags_allow_multi_line_strings & flags_bitset)) {
+        /* invalid escaped unicode sequence! */
+        state->error = json_parse_error_invalid_string_escape_sequence;
+        state->offset = offset;
+        return 1;
+      }
+
+      offset++;
+    }
+    else {
+      /* skip character (valid part of sequence). */
+      offset++;
+    }
+  }
+
+  /* skip trailing '"' or '\''. */
+  offset++;
+
+  /* add enough space to store the string. */
+  state->data_size += data_size;
+
+  /* one more byte for null terminator ending the string! */
+  state->data_size++;
+
+  /* update offset. */
+  state->offset = offset;
+
+  return 0;
+}
+
+json_weak int is_valid_unquoted_key_char(const char c);
+int is_valid_unquoted_key_char(const char c) {
+  return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
+    ('A' <= c && c <= 'Z') || ('_' == c));
+}
+
+json_weak int json_get_key_size(struct json_parse_state_s *state);
+int json_get_key_size(struct json_parse_state_s *state) {
+  const size_t flags_bitset = state->flags_bitset;
+
+  if (json_parse_flags_allow_unquoted_keys & flags_bitset) {
+    size_t offset = state->offset;
+    const size_t size = state->size;
+    const char *const src = state->src;
+    size_t data_size = state->data_size;
+
+    /* if we are allowing unquoted keys, first grok for a quote... */
+    if ('"' == src[offset]) {
+      /* ... if we got a comma, just parse the key as a string as normal. */
+      return json_get_string_size(state, 1);
+    }
+    else if ((json_parse_flags_allow_single_quoted_strings & flags_bitset) &&
+      ('\'' == src[offset])) {
+      /* ... if we got a comma, just parse the key as a string as normal. */
+      return json_get_string_size(state, 1);
+    }
+    else {
+      while ((offset < size) && is_valid_unquoted_key_char(src[offset])) {
+        offset++;
+        data_size++;
+      }
+
+      /* one more byte for null terminator ending the string! */
+      data_size++;
+
+      if (json_parse_flags_allow_location_information & flags_bitset) {
+        state->dom_size += sizeof(struct json_string_ex_s);
+      }
+      else {
+        state->dom_size += sizeof(struct json_string_s);
+      }
+
+      /* update offset. */
+      state->offset = offset;
+
+      /* update data_size. */
+      state->data_size = data_size;
+
+      return 0;
+    }
+  }
+  else {
+    /* we are only allowed to have quoted keys, so just parse a string! */
+    return json_get_string_size(state, 1);
+  }
+}
+
+json_weak int json_get_object_size(struct json_parse_state_s *state,
+  int is_global_object);
+int json_get_object_size(struct json_parse_state_s *state,
+  int is_global_object) {
+  const size_t flags_bitset = state->flags_bitset;
+  const char *const src = state->src;
+  const size_t size = state->size;
+  size_t elements = 0;
+  int allow_comma = 0;
+
+  if (is_global_object) {
+    /* if we found an opening '{' of an object, we actually have a normal JSON
+     * object at the root of the DOM... */
+    if (!json_skip_all_skippables(state) && '{' == state->src[state->offset]) {
+      /* . and we don't actually have a global object after all! */
+      is_global_object = 0;
+    }
+  }
+
+  if (!is_global_object) {
+    if ('{' != src[state->offset]) {
+      state->error = json_parse_error_unknown;
+      return 1;
+    }
+
+    /* skip leading '{'. */
+    state->offset++;
+  }
+
+  state->dom_size += sizeof(struct json_object_s);
+
+  while (state->offset < size) {
+    if (!is_global_object) {
+      if (json_skip_all_skippables(state)) {
+        state->error = json_parse_error_premature_end_of_buffer;
+        return 1;
+      }
+      if ('}' == src[state->offset]) {
+        /* skip trailing '}'. */
+        state->offset++;
+
+        /* finished the object! */
+        break;
+      }
+    }
+    else {
+      /* we don't require brackets, so that means the object ends when the input
+       * stream ends! */
+      if (json_skip_all_skippables(state)) {
+        break;
+      }
+    }
+
+    /* if we parsed at least once element previously, grok for a comma. */
+    if (allow_comma) {
+      if (',' == src[state->offset]) {
+        /* skip comma. */
+        state->offset++;
+        allow_comma = 0;
+      }
+      else if (json_parse_flags_allow_no_commas & flags_bitset) {
+        /* we don't require a comma, and we didn't find one, which is ok! */
+        allow_comma = 0;
+      }
+      else {
+        /* otherwise we are required to have a comma, and we found none. */
+        state->error = json_parse_error_expected_comma_or_closing_bracket;
+        return 1;
+      }
+
+      if (json_parse_flags_allow_trailing_comma & flags_bitset) {
+        continue;
+      }
+      else {
+        if (json_skip_all_skippables(state)) {
+          state->error = json_parse_error_premature_end_of_buffer;
+          return 1;
+        }
+      }
+    }
+
+    if (json_get_key_size(state)) {
+      /* key parsing failed! */
+      state->error = json_parse_error_invalid_string;
+      return 1;
+    }
+
+    if (json_skip_all_skippables(state)) {
+      state->error = json_parse_error_premature_end_of_buffer;
+      return 1;
+    }
+
+    if (json_parse_flags_allow_equals_in_object & flags_bitset) {
+      const char current = src[state->offset];
+      if ((':' != current) && ('=' != current)) {
+        state->error = json_parse_error_expected_colon;
+        return 1;
+      }
+    }
+    else {
+      if (':' != src[state->offset]) {
+        state->error = json_parse_error_expected_colon;
+        return 1;
+      }
+    }
+
+    /* skip colon. */
+    state->offset++;
+
+    if (json_skip_all_skippables(state)) {
+      state->error = json_parse_error_premature_end_of_buffer;
+      return 1;
+    }
+
+    if (json_get_value_size(state, /* is_global_object = */ 0)) {
+      /* value parsing failed! */
+      return 1;
+    }
+
+    /* successfully parsed a name/value pair! */
+    elements++;
+    allow_comma = 1;
+  }
+
+  state->dom_size += sizeof(struct json_object_element_s) * elements;
+
+  return 0;
+}
+
+json_weak int json_get_array_size(struct json_parse_state_s *state);
+int json_get_array_size(struct json_parse_state_s *state) {
+  const size_t flags_bitset = state->flags_bitset;
+  size_t elements = 0;
+  int allow_comma = 0;
+  const char *const src = state->src;
+  const size_t size = state->size;
+
+  if ('[' != src[state->offset]) {
+    /* expected array to begin with leading '['. */
+    state->error = json_parse_error_unknown;
+    return 1;
+  }
+
+  /* skip leading '['. */
+  state->offset++;
+
+  state->dom_size += sizeof(struct json_array_s);
+
+  while (state->offset < size) {
+    if (json_skip_all_skippables(state)) {
+      state->error = json_parse_error_premature_end_of_buffer;
+      return 1;
+    }
+
+    if (']' == src[state->offset]) {
+      /* skip trailing ']'. */
+      state->offset++;
+
+      state->dom_size += sizeof(struct json_array_element_s) * elements;
+
+      /* finished the object! */
+      return 0;
+    }
+
+    /* if we parsed at least once element previously, grok for a comma. */
+    if (allow_comma) {
+      if (',' == src[state->offset]) {
+        /* skip comma. */
+        state->offset++;
+        allow_comma = 0;
+      }
+      else if (!(json_parse_flags_allow_no_commas & flags_bitset)) {
+        state->error = json_parse_error_expected_comma_or_closing_bracket;
+        return 1;
+      }
+
+      if (json_parse_flags_allow_trailing_comma & flags_bitset) {
+        allow_comma = 0;
+        continue;
+      }
+      else {
+        if (json_skip_all_skippables(state)) {
+          state->error = json_parse_error_premature_end_of_buffer;
+          return 1;
+        }
+      }
+    }
+
+    if (json_get_value_size(state, /* is_global_object = */ 0)) {
+      /* value parsing failed! */
+      return 1;
+    }
+
+    /* successfully parsed an array element! */
+    elements++;
+    allow_comma = 1;
+  }
+
+  /* we consumed the entire input before finding the closing ']' of the array!
+   */
+  state->error = json_parse_error_premature_end_of_buffer;
+  return 1;
+}
+
+json_weak int json_get_number_size(struct json_parse_state_s *state);
+int json_get_number_size(struct json_parse_state_s *state) {
+  const size_t flags_bitset = state->flags_bitset;
+  size_t offset = state->offset;
+  const size_t size = state->size;
+  int had_leading_digits = 0;
+  const char *const src = state->src;
+
+  state->dom_size += sizeof(struct json_number_s);
+
+  if ((json_parse_flags_allow_hexadecimal_numbers & flags_bitset) &&
+    (offset + 1 < size) && ('0' == src[offset]) &&
+    (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) {
+    /* skip the leading 0x that identifies a hexadecimal number. */
+    offset += 2;
+
+    /* consume hexadecimal digits. */
+    while ((offset < size) && (('0' <= src[offset] && src[offset] <= '9') ||
+      ('a' <= src[offset] && src[offset] <= 'f') ||
+      ('A' <= src[offset] && src[offset] <= 'F'))) {
+      offset++;
+    }
+  }
+  else {
+    int found_sign = 0;
+    int inf_or_nan = 0;
+
+    if ((offset < size) &&
+      (('-' == src[offset]) ||
+      ((json_parse_flags_allow_leading_plus_sign & flags_bitset) &&
+        ('+' == src[offset])))) {
+      /* skip valid leading '-' or '+'. */
+      offset++;
+
+      found_sign = 1;
+    }
+
+    if (json_parse_flags_allow_inf_and_nan & flags_bitset) {
+      const char inf[9] = "Infinity";
+      const size_t inf_strlen = sizeof(inf) - 1;
+      const char nan[4] = "NaN";
+      const size_t nan_strlen = sizeof(nan) - 1;
+
+      if (offset + inf_strlen < size) {
+        int found = 1;
+        size_t i;
+        for (i = 0; i < inf_strlen; i++) {
+          if (inf[i] != src[offset + i]) {
+            found = 0;
+            break;
+          }
+        }
+
+        if (found) {
+          /* We found our special 'Infinity' keyword! */
+          offset += inf_strlen;
+
+          inf_or_nan = 1;
+        }
+      }
+
+      if (offset + nan_strlen < size) {
+        int found = 1;
+        size_t i;
+        for (i = 0; i < nan_strlen; i++) {
+          if (nan[i] != src[offset + i]) {
+            found = 0;
+            break;
+          }
+        }
+
+        if (found) {
+          /* We found our special 'NaN' keyword! */
+          offset += nan_strlen;
+
+          inf_or_nan = 1;
+        }
+      }
+    }
+
+    if (found_sign && !inf_or_nan && (offset < size) &&
+      !('0' <= src[offset] && src[offset] <= '9')) {
+      /* check if we are allowing leading '.'. */
+      if (!(json_parse_flags_allow_leading_or_trailing_decimal_point &
+        flags_bitset) ||
+        ('.' != src[offset])) {
+        /* a leading '-' must be immediately followed by any digit! */
+        state->error = json_parse_error_invalid_number_format;
+        state->offset = offset;
+        return 1;
+      }
+    }
+
+    if ((offset < size) && ('0' == src[offset])) {
+      /* skip valid '0'. */
+      offset++;
+
+      /* we need to record whether we had any leading digits for checks later.
+       */
+      had_leading_digits = 1;
+
+      if ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
+        /* a leading '0' must not be immediately followed by any digit! */
+        state->error = json_parse_error_invalid_number_format;
+        state->offset = offset;
+        return 1;
+      }
+    }
+
+    /* the main digits of our number next. */
+    while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
+      offset++;
+
+      /* we need to record whether we had any leading digits for checks later.
+       */
+      had_leading_digits = 1;
+    }
+
+    if ((offset < size) && ('.' == src[offset])) {
+      offset++;
+
+      if (!('0' <= src[offset] && src[offset] <= '9')) {
+        if (!(json_parse_flags_allow_leading_or_trailing_decimal_point &
+          flags_bitset) ||
+          !had_leading_digits) {
+          /* a decimal point must be followed by at least one digit. */
+          state->error = json_parse_error_invalid_number_format;
+          state->offset = offset;
+          return 1;
+        }
+      }
+
+      /* a decimal point can be followed by more digits of course! */
+      while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
+        offset++;
+      }
+    }
+
+    if ((offset < size) && ('e' == src[offset] || 'E' == src[offset])) {
+      /* our number has an exponent! Wkip 'e' or 'E'. */
+      offset++;
+
+      if ((offset < size) && ('-' == src[offset] || '+' == src[offset])) {
+        /* skip optional '-' or '+'. */
+        offset++;
+      }
+
+      /* consume exponent digits. */
+      while ((offset < size) && ('0' <= src[offset] && src[offset] <= '9')) {
+        offset++;
+      }
+    }
+  }
+
+  if (offset < size) {
+    switch (src[offset]) {
+    case ' ':
+    case '\t':
+    case '\r':
+    case '\n':
+    case '}':
+    case ',':
+    case ']':
+      /* all of the above are ok. */
+      break;
+    case '=':
+      if (json_parse_flags_allow_equals_in_object & flags_bitset) {
+        break;
+      }
+
+      state->error = json_parse_error_invalid_number_format;
+      state->offset = offset;
+      return 1;
+    default:
+      state->error = json_parse_error_invalid_number_format;
+      state->offset = offset;
+      return 1;
+    }
+  }
+
+  state->data_size += offset - state->offset;
+
+  /* one more byte for null terminator ending the number string! */
+  state->data_size++;
+
+  /* update offset. */
+  state->offset = offset;
+
+  return 0;
+}
+
+json_weak int json_get_value_size(struct json_parse_state_s *state,
+  int is_global_object);
+int json_get_value_size(struct json_parse_state_s *state,
+  int is_global_object) {
+  const size_t flags_bitset = state->flags_bitset;
+  const char *const src = state->src;
+  size_t offset;
+  const size_t size = state->size;
+
+  if (json_parse_flags_allow_location_information & flags_bitset) {
+    state->dom_size += sizeof(struct json_value_ex_s);
+  }
+  else {
+    state->dom_size += sizeof(struct json_value_s);
+  }
+
+  if (is_global_object) {
+    return json_get_object_size(state, /* is_global_object = */ 1);
+  }
+  else {
+    if (json_skip_all_skippables(state)) {
+      state->error = json_parse_error_premature_end_of_buffer;
+      return 1;
+    }
+
+    /* can cache offset now. */
+    offset = state->offset;
+
+    switch (src[offset]) {
+    case '"':
+      return json_get_string_size(state, 0);
+    case '\'':
+      if (json_parse_flags_allow_single_quoted_strings & flags_bitset) {
+        return json_get_string_size(state, 0);
+      }
+      else {
+        /* invalid value! */
+        state->error = json_parse_error_invalid_value;
+        return 1;
+      }
+    case '{':
+      return json_get_object_size(state, /* is_global_object = */ 0);
+    case '[':
+      return json_get_array_size(state);
+    case '-':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      return json_get_number_size(state);
+    case '+':
+      if (json_parse_flags_allow_leading_plus_sign & flags_bitset) {
+        return json_get_number_size(state);
+      }
+      else {
+        /* invalid value! */
+        state->error = json_parse_error_invalid_number_format;
+        return 1;
+      }
+    case '.':
+      if (json_parse_flags_allow_leading_or_trailing_decimal_point &
+        flags_bitset) {
+        return json_get_number_size(state);
+      }
+      else {
+        /* invalid value! */
+        state->error = json_parse_error_invalid_number_format;
+        return 1;
+      }
+    default:
+      if ((offset + 4) <= size && 't' == src[offset + 0] &&
+        'r' == src[offset + 1] && 'u' == src[offset + 2] &&
+        'e' == src[offset + 3]) {
+        state->offset += 4;
+        return 0;
+      }
+      else if ((offset + 5) <= size && 'f' == src[offset + 0] &&
+        'a' == src[offset + 1] && 'l' == src[offset + 2] &&
+        's' == src[offset + 3] && 'e' == src[offset + 4]) {
+        state->offset += 5;
+        return 0;
+      }
+      else if ((offset + 4) <= size && 'n' == state->src[offset + 0] &&
+        'u' == state->src[offset + 1] &&
+        'l' == state->src[offset + 2] &&
+        'l' == state->src[offset + 3]) {
+        state->offset += 4;
+        return 0;
+      }
+      else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
+        (offset + 3) <= size && 'N' == src[offset + 0] &&
+        'a' == src[offset + 1] && 'N' == src[offset + 2]) {
+        return json_get_number_size(state);
+      }
+      else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
+        (offset + 8) <= size && 'I' == src[offset + 0] &&
+        'n' == src[offset + 1] && 'f' == src[offset + 2] &&
+        'i' == src[offset + 3] && 'n' == src[offset + 4] &&
+        'i' == src[offset + 5] && 't' == src[offset + 6] &&
+        'y' == src[offset + 7]) {
+        return json_get_number_size(state);
+      }
+
+      /* invalid value! */
+      state->error = json_parse_error_invalid_value;
+      return 1;
+    }
+  }
+}
+
+json_weak void json_parse_value(struct json_parse_state_s *state,
+  int is_global_object, struct json_value_s *value);
+
+json_weak void json_parse_string(struct json_parse_state_s *state,
+  struct json_string_s *string);
+void json_parse_string(struct json_parse_state_s *state,
+  struct json_string_s *string) {
+  size_t offset = state->offset;
+  size_t bytes_written = 0;
+  const char *const src = state->src;
+  const char quote_to_use = '\'' == src[offset] ? '\'' : '"';
+  char *data = state->data;
+  unsigned long high_surrogate = 0;
+  unsigned long codepoint;
+
+  string->string = data;
+
+  /* skip leading '"' or '\''. */
+  offset++;
+
+  while (quote_to_use != src[offset]) {
+    if ('\\' == src[offset]) {
+      /* skip the reverse solidus. */
+      offset++;
+
+      switch (src[offset++]) {
+      default:
+        return; /* we cannot ever reach here. */
+      case 'u': {
+        codepoint = 0;
+        if (!json_hexadecimal_value(&src[offset], 4, &codepoint)) {
+          return; /* this shouldn't happen as the value was already validated.
+                   */
+        }
+
+        offset += 4;
+
+        if (codepoint <= 0x7fu) {
+          data[bytes_written++] = (char)codepoint; /* 0xxxxxxx. */
+        }
+        else if (codepoint <= 0x7ffu) {
+          data[bytes_written++] =
+            (char)(0xc0u | (codepoint >> 6)); /* 110xxxxx. */
+          data[bytes_written++] =
+            (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */
+        }
+        else if (codepoint >= 0xd800 &&
+          codepoint <= 0xdbff) { /* high surrogate. */
+          high_surrogate = codepoint;
+          continue; /* we need the low half to form a complete codepoint. */
+        }
+        else if (codepoint >= 0xdc00 &&
+          codepoint <= 0xdfff) { /* low surrogate. */
+ /* combine with the previously read half to obtain the complete
+  * codepoint. */
+          const unsigned long surrogate_offset = 0x10000u - (0xD800u << 10) - 0xDC00u;
+          codepoint = (high_surrogate << 10) + codepoint + surrogate_offset;
+          high_surrogate = 0;
+          data[bytes_written++] =
+            (char)(0xF0u | (codepoint >> 18)); /* 11110xxx. */
+          data[bytes_written++] =
+            (char)(0x80u | ((codepoint >> 12) & 0x3fu)); /* 10xxxxxx. */
+          data[bytes_written++] =
+            (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */
+          data[bytes_written++] =
+            (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */
+        }
+        else {
+          /* we assume the value was validated and thus is within the valid
+           * range. */
+          data[bytes_written++] =
+            (char)(0xe0u | (codepoint >> 12)); /* 1110xxxx. */
+          data[bytes_written++] =
+            (char)(0x80u | ((codepoint >> 6) & 0x3fu)); /* 10xxxxxx. */
+          data[bytes_written++] =
+            (char)(0x80u | (codepoint & 0x3fu)); /* 10xxxxxx. */
+        }
+      } break;
+      case '"':
+        data[bytes_written++] = '"';
+        break;
+      case '\\':
+        data[bytes_written++] = '\\';
+        break;
+      case '/':
+        data[bytes_written++] = '/';
+        break;
+      case 'b':
+        data[bytes_written++] = '\b';
+        break;
+      case 'f':
+        data[bytes_written++] = '\f';
+        break;
+      case 'n':
+        data[bytes_written++] = '\n';
+        break;
+      case 'r':
+        data[bytes_written++] = '\r';
+        break;
+      case 't':
+        data[bytes_written++] = '\t';
+        break;
+      case '\r':
+        data[bytes_written++] = '\r';
+
+        /* check if we have a "\r\n" sequence. */
+        if ('\n' == src[offset]) {
+          data[bytes_written++] = '\n';
+          offset++;
+        }
+
+        break;
+      case '\n':
+        data[bytes_written++] = '\n';
+        break;
+      }
+    }
+    else {
+      /* copy the character. */
+      data[bytes_written++] = src[offset++];
+    }
+  }
+
+  /* skip trailing '"' or '\''. */
+  offset++;
+
+  /* record the size of the string. */
+  string->string_size = bytes_written;
+
+  /* add null terminator to string. */
+  data[bytes_written++] = '\0';
+
+  /* move data along. */
+  state->data += bytes_written;
+
+  /* update offset. */
+  state->offset = offset;
+}
+
+json_weak void json_parse_key(struct json_parse_state_s *state,
+  struct json_string_s *string);
+void json_parse_key(struct json_parse_state_s *state,
+  struct json_string_s *string) {
+  if (json_parse_flags_allow_unquoted_keys & state->flags_bitset) {
+    const char *const src = state->src;
+    char *const data = state->data;
+    size_t offset = state->offset;
+
+    /* if we are allowing unquoted keys, check for quoted anyway... */
+    if (('"' == src[offset]) || ('\'' == src[offset])) {
+      /* ... if we got a quote, just parse the key as a string as normal. */
+      json_parse_string(state, string);
+    }
+    else {
+      size_t size = 0;
+
+      string->string = state->data;
+
+      while (is_valid_unquoted_key_char(src[offset])) {
+        data[size++] = src[offset++];
+      }
+
+      /* add null terminator to string. */
+      data[size] = '\0';
+
+      /* record the size of the string. */
+      string->string_size = size++;
+
+      /* move data along. */
+      state->data += size;
+
+      /* update offset. */
+      state->offset = offset;
+    }
+  }
+  else {
+    /* we are only allowed to have quoted keys, so just parse a string! */
+    json_parse_string(state, string);
+  }
+}
+
+json_weak void json_parse_object(struct json_parse_state_s *state,
+  int is_global_object,
+  struct json_object_s *object);
+void json_parse_object(struct json_parse_state_s *state,
+  int is_global_object,
+  struct json_object_s *object) {
+  const size_t flags_bitset = state->flags_bitset;
+  const size_t size = state->size;
+  const char *const src = state->src;
+  size_t elements = 0;
+  int allow_comma = 0;
+  struct json_object_element_s *previous = json_null;
+
+  if (is_global_object) {
+    /* if we skipped some whitespace, and then found an opening '{' of an. */
+    /* object, we actually have a normal JSON object at the root of the DOM...
+     */
+    if ('{' == src[state->offset]) {
+      /* . and we don't actually have a global object after all! */
+      is_global_object = 0;
+    }
+  }
+
+  if (!is_global_object) {
+    /* skip leading '{'. */
+    state->offset++;
+  }
+
+  (void)json_skip_all_skippables(state);
+
+  /* reset elements. */
+  elements = 0;
+
+  while (state->offset < size) {
+    struct json_object_element_s *element = json_null;
+    struct json_string_s *string = json_null;
+    struct json_value_s *value = json_null;
+
+    if (!is_global_object) {
+      (void)json_skip_all_skippables(state);
+
+      if ('}' == src[state->offset]) {
+        /* skip trailing '}'. */
+        state->offset++;
+
+        /* finished the object! */
+        break;
+      }
+    }
+    else {
+      if (json_skip_all_skippables(state)) {
+        /* global object ends when the file ends! */
+        break;
+      }
+    }
+
+    /* if we parsed at least one element previously, grok for a comma. */
+    if (allow_comma) {
+      if (',' == src[state->offset]) {
+        /* skip comma. */
+        state->offset++;
+        allow_comma = 0;
+        continue;
+      }
+    }
+
+    element = (struct json_object_element_s *)state->dom;
+
+    state->dom += sizeof(struct json_object_element_s);
+
+    if (json_null == previous) {
+      /* this is our first element, so record it in our object. */
+      object->start = element;
+    }
+    else {
+      previous->next = element;
+    }
+
+    previous = element;
+
+    if (json_parse_flags_allow_location_information & flags_bitset) {
+      struct json_string_ex_s *string_ex =
+        (struct json_string_ex_s *)state->dom;
+      state->dom += sizeof(struct json_string_ex_s);
+
+      string_ex->offset = state->offset;
+      string_ex->line_no = state->line_no;
+      string_ex->row_no = state->offset - state->line_offset;
+
+      string = &(string_ex->string);
+    }
+    else {
+      string = (struct json_string_s *)state->dom;
+      state->dom += sizeof(struct json_string_s);
+    }
+
+    element->name = string;
+
+    (void)json_parse_key(state, string);
+
+    (void)json_skip_all_skippables(state);
+
+    /* skip colon or equals. */
+    state->offset++;
+
+    (void)json_skip_all_skippables(state);
+
+    if (json_parse_flags_allow_location_information & flags_bitset) {
+      struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom;
+      state->dom += sizeof(struct json_value_ex_s);
+
+      value_ex->offset = state->offset;
+      value_ex->line_no = state->line_no;
+      value_ex->row_no = state->offset - state->line_offset;
+
+      value = &(value_ex->value);
+    }
+    else {
+      value = (struct json_value_s *)state->dom;
+      state->dom += sizeof(struct json_value_s);
+    }
+
+    element->value = value;
+
+    json_parse_value(state, /* is_global_object = */ 0, value);
+
+    /* successfully parsed a name/value pair! */
+    elements++;
+    allow_comma = 1;
+  }
+
+  /* if we had at least one element, end the linked list. */
+  if (previous) {
+    previous->next = json_null;
+  }
+
+  if (0 == elements) {
+    object->start = json_null;
+  }
+
+  object->length = elements;
+}
+
+json_weak void json_parse_array(struct json_parse_state_s *state,
+  struct json_array_s *array);
+void json_parse_array(struct json_parse_state_s *state,
+  struct json_array_s *array) {
+  const char *const src = state->src;
+  const size_t size = state->size;
+  size_t elements = 0;
+  int allow_comma = 0;
+  struct json_array_element_s *previous = json_null;
+
+  /* skip leading '['. */
+  state->offset++;
+
+  (void)json_skip_all_skippables(state);
+
+  /* reset elements. */
+  elements = 0;
+
+  do {
+    struct json_array_element_s *element = json_null;
+    struct json_value_s *value = json_null;
+
+    (void)json_skip_all_skippables(state);
+
+    if (']' == src[state->offset]) {
+      /* skip trailing ']'. */
+      state->offset++;
+
+      /* finished the array! */
+      break;
+    }
+
+    /* if we parsed at least one element previously, grok for a comma. */
+    if (allow_comma) {
+      if (',' == src[state->offset]) {
+        /* skip comma. */
+        state->offset++;
+        allow_comma = 0;
+        continue;
+      }
+    }
+
+    element = (struct json_array_element_s *)state->dom;
+
+    state->dom += sizeof(struct json_array_element_s);
+
+    if (json_null == previous) {
+      /* this is our first element, so record it in our array. */
+      array->start = element;
+    }
+    else {
+      previous->next = element;
+    }
+
+    previous = element;
+
+    if (json_parse_flags_allow_location_information & state->flags_bitset) {
+      struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state->dom;
+      state->dom += sizeof(struct json_value_ex_s);
+
+      value_ex->offset = state->offset;
+      value_ex->line_no = state->line_no;
+      value_ex->row_no = state->offset - state->line_offset;
+
+      value = &(value_ex->value);
+    }
+    else {
+      value = (struct json_value_s *)state->dom;
+      state->dom += sizeof(struct json_value_s);
+    }
+
+    element->value = value;
+
+    json_parse_value(state, /* is_global_object = */ 0, value);
+
+    /* successfully parsed an array element! */
+    elements++;
+    allow_comma = 1;
+  } while (state->offset < size);
+
+  /* end the linked list. */
+  if (previous) {
+    previous->next = json_null;
+  }
+
+  if (0 == elements) {
+    array->start = json_null;
+  }
+
+  array->length = elements;
+}
+
+json_weak void json_parse_number(struct json_parse_state_s *state,
+  struct json_number_s *number);
+void json_parse_number(struct json_parse_state_s *state,
+  struct json_number_s *number) {
+  const size_t flags_bitset = state->flags_bitset;
+  size_t offset = state->offset;
+  const size_t size = state->size;
+  size_t bytes_written = 0;
+  const char *const src = state->src;
+  char *data = state->data;
+
+  number->number = data;
+
+  if (json_parse_flags_allow_hexadecimal_numbers & flags_bitset) {
+    if (('0' == src[offset]) &&
+      (('x' == src[offset + 1]) || ('X' == src[offset + 1]))) {
+      /* consume hexadecimal digits. */
+      while ((offset < size) &&
+        (('0' <= src[offset] && src[offset] <= '9') ||
+        ('a' <= src[offset] && src[offset] <= 'f') ||
+          ('A' <= src[offset] && src[offset] <= 'F') ||
+          ('x' == src[offset]) || ('X' == src[offset]))) {
+        data[bytes_written++] = src[offset++];
+      }
+    }
+  }
+
+  while (offset < size) {
+    int end = 0;
+
+    switch (src[offset]) {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '.':
+    case 'e':
+    case 'E':
+    case '+':
+    case '-':
+      data[bytes_written++] = src[offset++];
+      break;
+    default:
+      end = 1;
+      break;
+    }
+
+    if (0 != end) {
+      break;
+    }
+  }
+
+  if (json_parse_flags_allow_inf_and_nan & flags_bitset) {
+    const size_t inf_strlen = 8; /* = strlen("Infinity");. */
+    const size_t nan_strlen = 3; /* = strlen("NaN");. */
+
+    if (offset + inf_strlen < size) {
+      if ('I' == src[offset]) {
+        size_t i;
+        /* We found our special 'Infinity' keyword! */
+        for (i = 0; i < inf_strlen; i++) {
+          data[bytes_written++] = src[offset++];
+        }
+      }
+    }
+
+    if (offset + nan_strlen < size) {
+      if ('N' == src[offset]) {
+        size_t i;
+        /* We found our special 'NaN' keyword! */
+        for (i = 0; i < nan_strlen; i++) {
+          data[bytes_written++] = src[offset++];
+        }
+      }
+    }
+  }
+
+  /* record the size of the number. */
+  number->number_size = bytes_written;
+  /* add null terminator to number string. */
+  data[bytes_written++] = '\0';
+  /* move data along. */
+  state->data += bytes_written;
+  /* update offset. */
+  state->offset = offset;
+}
+
+json_weak void json_parse_value(struct json_parse_state_s *state,
+  int is_global_object, struct json_value_s *value);
+void json_parse_value(struct json_parse_state_s *state,
+  int is_global_object, struct json_value_s *value) {
+  const size_t flags_bitset = state->flags_bitset;
+  const char *const src = state->src;
+  const size_t size = state->size;
+  size_t offset;
+
+  (void)json_skip_all_skippables(state);
+
+  /* cache offset now. */
+  offset = state->offset;
+
+  if (is_global_object) {
+    value->type = json_type_object;
+    value->payload = state->dom;
+    state->dom += sizeof(struct json_object_s);
+    json_parse_object(state, /* is_global_object = */ 1,
+      (struct json_object_s *)value->payload);
+  }
+  else {
+    switch (src[offset]) {
+    case '"':
+    case '\'':
+      value->type = json_type_string;
+      value->payload = state->dom;
+      state->dom += sizeof(struct json_string_s);
+      json_parse_string(state, (struct json_string_s *)value->payload);
+      break;
+    case '{':
+      value->type = json_type_object;
+      value->payload = state->dom;
+      state->dom += sizeof(struct json_object_s);
+      json_parse_object(state, /* is_global_object = */ 0,
+        (struct json_object_s *)value->payload);
+      break;
+    case '[':
+      value->type = json_type_array;
+      value->payload = state->dom;
+      state->dom += sizeof(struct json_array_s);
+      json_parse_array(state, (struct json_array_s *)value->payload);
+      break;
+    case '-':
+    case '+':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '.':
+      value->type = json_type_number;
+      value->payload = state->dom;
+      state->dom += sizeof(struct json_number_s);
+      json_parse_number(state, (struct json_number_s *)value->payload);
+      break;
+    default:
+      if ((offset + 4) <= size && 't' == src[offset + 0] &&
+        'r' == src[offset + 1] && 'u' == src[offset + 2] &&
+        'e' == src[offset + 3]) {
+        value->type = json_type_true;
+        value->payload = json_null;
+        state->offset += 4;
+      }
+      else if ((offset + 5) <= size && 'f' == src[offset + 0] &&
+        'a' == src[offset + 1] && 'l' == src[offset + 2] &&
+        's' == src[offset + 3] && 'e' == src[offset + 4]) {
+        value->type = json_type_false;
+        value->payload = json_null;
+        state->offset += 5;
+      }
+      else if ((offset + 4) <= size && 'n' == src[offset + 0] &&
+        'u' == src[offset + 1] && 'l' == src[offset + 2] &&
+        'l' == src[offset + 3]) {
+        value->type = json_type_null;
+        value->payload = json_null;
+        state->offset += 4;
+      }
+      else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
+        (offset + 3) <= size && 'N' == src[offset + 0] &&
+        'a' == src[offset + 1] && 'N' == src[offset + 2]) {
+        value->type = json_type_number;
+        value->payload = state->dom;
+        state->dom += sizeof(struct json_number_s);
+        json_parse_number(state, (struct json_number_s *)value->payload);
+      }
+      else if ((json_parse_flags_allow_inf_and_nan & flags_bitset) &&
+        (offset + 8) <= size && 'I' == src[offset + 0] &&
+        'n' == src[offset + 1] && 'f' == src[offset + 2] &&
+        'i' == src[offset + 3] && 'n' == src[offset + 4] &&
+        'i' == src[offset + 5] && 't' == src[offset + 6] &&
+        'y' == src[offset + 7]) {
+        value->type = json_type_number;
+        value->payload = state->dom;
+        state->dom += sizeof(struct json_number_s);
+        json_parse_number(state, (struct json_number_s *)value->payload);
+      }
+      break;
+    }
+  }
+}
+
+struct json_value_s *
+  json_parse_ex(const void *src, size_t src_size, size_t flags_bitset,
+    void *(*alloc_func_ptr)(void *user_data, size_t size),
+    void *user_data, struct json_parse_result_s *result) {
+  struct json_parse_state_s state;
+  void *allocation;
+  struct json_value_s *value;
+  size_t total_size;
+  int input_error;
+
+  if (result) {
+    result->error = json_parse_error_none;
+    result->error_offset = 0;
+    result->error_line_no = 0;
+    result->error_row_no = 0;
+  }
+
+  if (json_null == src) {
+    /* invalid src pointer was null! */
+    return json_null;
+  }
+
+  state.src = (const char *)src;
+  state.size = src_size;
+  state.offset = 0;
+  state.line_no = 1;
+  state.line_offset = 0;
+  state.error = json_parse_error_none;
+  state.dom_size = 0;
+  state.data_size = 0;
+  state.flags_bitset = flags_bitset;
+
+  input_error = json_get_value_size(
+    &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset));
+
+  if (0 == input_error) {
+    json_skip_all_skippables(&state);
+
+    if (state.offset != state.size) {
+      /* our parsing didn't have an error, but there are characters remaining in
+       * the input that weren't part of the JSON! */
+
+      state.error = json_parse_error_unexpected_trailing_characters;
+      input_error = 1;
+    }
+  }
+
+  if (input_error) {
+    /* parsing value's size failed (most likely an invalid JSON DOM!). */
+    if (result) {
+      result->error = state.error;
+      result->error_offset = state.offset;
+      result->error_line_no = state.line_no;
+      result->error_row_no = state.offset - state.line_offset;
+    }
+    return json_null;
+  }
+
+  /* our total allocation is the combination of the dom and data sizes (we. */
+  /* first encode the structure of the JSON, and then the data referenced by. */
+  /* the JSON values). */
+  total_size = state.dom_size + state.data_size;
+
+  if (json_null == alloc_func_ptr) {
+    allocation = malloc(total_size);
+  }
+  else {
+    allocation = alloc_func_ptr(user_data, total_size);
+  }
+
+  if (json_null == allocation) {
+    /* malloc failed! */
+    if (result) {
+      result->error = json_parse_error_allocator_failed;
+      result->error_offset = 0;
+      result->error_line_no = 0;
+      result->error_row_no = 0;
+    }
+
+    return json_null;
+  }
+
+  /* reset offset so we can reuse it. */
+  state.offset = 0;
+
+  /* reset the line information so we can reuse it. */
+  state.line_no = 1;
+  state.line_offset = 0;
+
+  state.dom = (char *)allocation;
+  state.data = state.dom + state.dom_size;
+
+  if (json_parse_flags_allow_location_information & state.flags_bitset) {
+    struct json_value_ex_s *value_ex = (struct json_value_ex_s *)state.dom;
+    state.dom += sizeof(struct json_value_ex_s);
+
+    value_ex->offset = state.offset;
+    value_ex->line_no = state.line_no;
+    value_ex->row_no = state.offset - state.line_offset;
+
+    value = &(value_ex->value);
+  }
+  else {
+    value = (struct json_value_s *)state.dom;
+    state.dom += sizeof(struct json_value_s);
+  }
+
+  json_parse_value(
+    &state, (int)(json_parse_flags_allow_global_object & state.flags_bitset),
+    value);
+
+  return (struct json_value_s *)allocation;
+}
+
+struct json_value_s *json_parse(const void *src, size_t src_size) {
+  return json_parse_ex(src, src_size, json_parse_flags_default, json_null,
+    json_null, json_null);
+}
+
+struct json_string_s *json_value_as_string(struct json_value_s *const value) {
+  if (value->type != json_type_string) {
+    return json_null;
+  }
+
+  return (struct json_string_s *)value->payload;
+}
+
+struct json_number_s *json_value_as_number(struct json_value_s *const value) {
+  if (value->type != json_type_number) {
+    return json_null;
+  }
+
+  return (struct json_number_s *)value->payload;
+}
+
+struct json_object_s *json_value_as_object(struct json_value_s *const value) {
+  if (value->type != json_type_object) {
+    return json_null;
+  }
+
+  return (struct json_object_s *)value->payload;
+}
+
+struct json_array_s *json_value_as_array(struct json_value_s *const value) {
+  if (value->type != json_type_array) {
+    return json_null;
+  }
+
+  return (struct json_array_s *)value->payload;
+}
+
+int json_value_is_true(const struct json_value_s *const value) {
+  return value->type == json_type_true;
+}
+
+int json_value_is_false(const struct json_value_s *const value) {
+  return value->type == json_type_false;
+}
+
+int json_value_is_null(const struct json_value_s *const value) {
+  return value->type == json_type_null;
+}
+
+json_weak int json_write_minified_get_value_size(const struct json_value_s *value,
+  size_t *size);
+
+json_weak int json_write_get_number_size(const struct json_number_s *number,
+  size_t *size);
+int json_write_get_number_size(const struct json_number_s *number,
+  size_t *size) {
+  json_uintmax_t parsed_number;
+  size_t i;
+
+  if (number->number_size >= 2) {
+    switch (number->number[1]) {
+    default:
+      break;
+    case 'x':
+    case 'X':
+      /* the number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal
+       * so we have to do extra work to convert it to a non-hexadecimal for JSON
+       * output. */
+      parsed_number = json_strtoumax(number->number, json_null, 0);
+
+      i = 0;
+
+      while (0 != parsed_number) {
+        parsed_number /= 10;
+        i++;
+      }
+
+      *size += i;
+      return 0;
+    }
+  }
+
+  /* check to see if the number has leading/trailing decimal point. */
+  i = 0;
+
+  /* skip any leading '+' or '-'. */
+  if ((i < number->number_size) &&
+    (('+' == number->number[i]) || ('-' == number->number[i]))) {
+    i++;
+  }
+
+  /* check if we have infinity. */
+  if ((i < number->number_size) && ('I' == number->number[i])) {
+    const char *inf = "Infinity";
+    size_t k;
+
+    for (k = i; k < number->number_size; k++) {
+      const char c = *inf++;
+
+      /* Check if we found the Infinity string! */
+      if ('\0' == c) {
+        break;
+      }
+      else if (c != number->number[k]) {
+        break;
+      }
+    }
+
+    if ('\0' == *inf) {
+      /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */
+      *size += 22;
+
+      /* if we had a leading '-' we need to record it in the JSON output. */
+      if ('-' == number->number[0]) {
+        *size += 1;
+      }
+    }
+
+    return 0;
+  }
+
+  /* check if we have nan. */
+  if ((i < number->number_size) && ('N' == number->number[i])) {
+    const char *nan = "NaN";
+    size_t k;
+
+    for (k = i; k < number->number_size; k++) {
+      const char c = *nan++;
+
+      /* Check if we found the NaN string! */
+      if ('\0' == c) {
+        break;
+      }
+      else if (c != number->number[k]) {
+        break;
+      }
+    }
+
+    if ('\0' == *nan) {
+      /* NaN becomes 1 because JSON can't support it. */
+      *size += 1;
+
+      return 0;
+    }
+  }
+
+  /* if we had a leading decimal point. */
+  if ((i < number->number_size) && ('.' == number->number[i])) {
+    /* 1 + because we had a leading decimal point. */
+    *size += 1;
+    goto cleanup;
+  }
+
+  for (; i < number->number_size; i++) {
+    const char c = number->number[i];
+    if (!('0' <= c && c <= '9')) {
+      break;
+    }
+  }
+
+  /* if we had a trailing decimal point. */
+  if ((i + 1 == number->number_size) && ('.' == number->number[i])) {
+    /* 1 + because we had a trailing decimal point. */
+    *size += 1;
+    goto cleanup;
+  }
+
+cleanup:
+  *size += number->number_size; /* the actual string of the number. */
+
+  /* if we had a leading '+' we don't record it in the JSON output. */
+  if ('+' == number->number[0]) {
+    *size -= 1;
+  }
+
+  return 0;
+}
+
+json_weak int json_write_get_string_size(const struct json_string_s *string,
+  size_t *size);
+int json_write_get_string_size(const struct json_string_s *string,
+  size_t *size) {
+  size_t i;
+  for (i = 0; i < string->string_size; i++) {
+    switch (string->string[i]) {
+    case '"':
+    case '\\':
+    case '\b':
+    case '\f':
+    case '\n':
+    case '\r':
+    case '\t':
+      *size += 2;
+      break;
+    default:
+      *size += 1;
+      break;
+    }
+  }
+
+  *size += 2; /* need to encode the surrounding '"' characters. */
+
+  return 0;
+}
+
+json_weak int json_write_minified_get_array_size(const struct json_array_s *array,
+  size_t *size);
+int json_write_minified_get_array_size(const struct json_array_s *array,
+  size_t *size) {
+  struct json_array_element_s *element;
+
+  *size += 2; /* '[' and ']'. */
+
+  if (1 < array->length) {
+    *size += array->length - 1; /* ','s seperate each element. */
+  }
+
+  for (element = array->start; json_null != element; element = element->next) {
+    if (json_write_minified_get_value_size(element->value, size)) {
+      /* value was malformed! */
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+json_weak int
+json_write_minified_get_object_size(const struct json_object_s *object,
+  size_t *size);
+int
+json_write_minified_get_object_size(const struct json_object_s *object,
+  size_t *size) {
+  struct json_object_element_s *element;
+
+  *size += 2; /* '{' and '}'. */
+
+  *size += object->length; /* ':'s seperate each name/value pair. */
+
+  if (1 < object->length) {
+    *size += object->length - 1; /* ','s seperate each element. */
+  }
+
+  for (element = object->start; json_null != element; element = element->next) {
+    if (json_write_get_string_size(element->name, size)) {
+      /* string was malformed! */
+      return 1;
+    }
+
+    if (json_write_minified_get_value_size(element->value, size)) {
+      /* value was malformed! */
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+json_weak int json_write_minified_get_value_size(const struct json_value_s *value,
+  size_t *size);
+int json_write_minified_get_value_size(const struct json_value_s *value,
+  size_t *size) {
+  switch (value->type) {
+  default:
+    /* unknown value type found! */
+    return 1;
+  case json_type_number:
+    return json_write_get_number_size((struct json_number_s *)value->payload,
+      size);
+  case json_type_string:
+    return json_write_get_string_size((struct json_string_s *)value->payload,
+      size);
+  case json_type_array:
+    return json_write_minified_get_array_size(
+      (struct json_array_s *)value->payload, size);
+  case json_type_object:
+    return json_write_minified_get_object_size(
+      (struct json_object_s *)value->payload, size);
+  case json_type_true:
+    *size += 4; /* the string "true". */
+    return 0;
+  case json_type_false:
+    *size += 5; /* the string "false". */
+    return 0;
+  case json_type_null:
+    *size += 4; /* the string "null". */
+    return 0;
+  }
+}
+
+json_weak char *json_write_minified_value(const struct json_value_s *value,
+  char *data);
+
+json_weak char *json_write_number(const struct json_number_s *number, char *data);
+char *json_write_number(const struct json_number_s *number, char *data) {
+  json_uintmax_t parsed_number, backup;
+  size_t i;
+
+  if (number->number_size >= 2) {
+    switch (number->number[1]) {
+    default:
+      break;
+    case 'x':
+    case 'X':
+      /* The number is a json_parse_flags_allow_hexadecimal_numbers hexadecimal
+       * so we have to do extra work to convert it to a non-hexadecimal for JSON
+       * output. */
+      parsed_number = json_strtoumax(number->number, json_null, 0);
+
+      /* We need a copy of parsed number twice, so take a backup of it. */
+      backup = parsed_number;
+
+      i = 0;
+
+      while (0 != parsed_number) {
+        parsed_number /= 10;
+        i++;
+      }
+
+      /* Restore parsed_number to its original value stored in the backup. */
+      parsed_number = backup;
+
+      /* Now use backup to take a copy of i, or the length of the string. */
+      backup = i;
+
+      do {
+        *(data + i - 1) = '0' + (char)(parsed_number % 10);
+        parsed_number /= 10;
+        i--;
+      } while (0 != parsed_number);
+
+      data += backup;
+
+      return data;
+    }
+  }
+
+  /* check to see if the number has leading/trailing decimal point. */
+  i = 0;
+
+  /* skip any leading '-'. */
+  if ((i < number->number_size) &&
+    (('+' == number->number[i]) || ('-' == number->number[i]))) {
+    i++;
+  }
+
+  /* check if we have infinity. */
+  if ((i < number->number_size) && ('I' == number->number[i])) {
+    const char *inf = "Infinity";
+    size_t k;
+
+    for (k = i; k < number->number_size; k++) {
+      const char c = *inf++;
+
+      /* Check if we found the Infinity string! */
+      if ('\0' == c) {
+        break;
+      }
+      else if (c != number->number[k]) {
+        break;
+      }
+    }
+
+    if ('\0' == *inf++) {
+      const char *dbl_max;
+
+      /* if we had a leading '-' we need to record it in the JSON output. */
+      if ('-' == number->number[0]) {
+        *data++ = '-';
+      }
+
+      /* Inf becomes 1.7976931348623158e308 because JSON can't support it. */
+      for (dbl_max = "1.7976931348623158e308"; '\0' != *dbl_max; dbl_max++) {
+        *data++ = *dbl_max;
+      }
+
+      return data;
+    }
+  }
+
+  /* check if we have nan. */
+  if ((i < number->number_size) && ('N' == number->number[i])) {
+    const char *nan = "NaN";
+    size_t k;
+
+    for (k = i; k < number->number_size; k++) {
+      const char c = *nan++;
+
+      /* Check if we found the NaN string! */
+      if ('\0' == c) {
+        break;
+      }
+      else if (c != number->number[k]) {
+        break;
+      }
+    }
+
+    if ('\0' == *nan++) {
+      /* NaN becomes 0 because JSON can't support it. */
+      *data++ = '0';
+      return data;
+    }
+  }
+
+  /* if we had a leading decimal point. */
+  if ((i < number->number_size) && ('.' == number->number[i])) {
+    i = 0;
+
+    /* skip any leading '+'. */
+    if ('+' == number->number[i]) {
+      i++;
+    }
+
+    /* output the leading '-' if we had one. */
+    if ('-' == number->number[i]) {
+      *data++ = '-';
+      i++;
+    }
+
+    /* insert a '0' to fix the leading decimal point for JSON output. */
+    *data++ = '0';
+
+    /* and output the rest of the number as normal. */
+    for (; i < number->number_size; i++) {
+      *data++ = number->number[i];
+    }
+
+    return data;
+  }
+
+  for (; i < number->number_size; i++) {
+    const char c = number->number[i];
+    if (!('0' <= c && c <= '9')) {
+      break;
+    }
+  }
+
+  /* if we had a trailing decimal point. */
+  if ((i + 1 == number->number_size) && ('.' == number->number[i])) {
+    i = 0;
+
+    /* skip any leading '+'. */
+    if ('+' == number->number[i]) {
+      i++;
+    }
+
+    /* output the leading '-' if we had one. */
+    if ('-' == number->number[i]) {
+      *data++ = '-';
+      i++;
+    }
+
+    /* and output the rest of the number as normal. */
+    for (; i < number->number_size; i++) {
+      *data++ = number->number[i];
+    }
+
+    /* insert a '0' to fix the trailing decimal point for JSON output. */
+    *data++ = '0';
+
+    return data;
+  }
+
+  i = 0;
+
+  /* skip any leading '+'. */
+  if ('+' == number->number[i]) {
+    i++;
+  }
+
+  for (; i < number->number_size; i++) {
+    *data++ = number->number[i];
+  }
+
+  return data;
+}
+
+json_weak char *json_write_string(const struct json_string_s *string, char *data);
+char *json_write_string(const struct json_string_s *string, char *data) {
+  size_t i;
+
+  *data++ = '"'; /* open the string. */
+
+  for (i = 0; i < string->string_size; i++) {
+    switch (string->string[i]) {
+    case '"':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = '"';
+      break;
+    case '\\':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = '\\';
+      break;
+    case '\b':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = 'b';
+      break;
+    case '\f':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = 'f';
+      break;
+    case '\n':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = 'n';
+      break;
+    case '\r':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = 'r';
+      break;
+    case '\t':
+      *data++ = '\\'; /* escape the control character. */
+      *data++ = 't';
+      break;
+    default:
+      *data++ = string->string[i];
+      break;
+    }
+  }
+
+  *data++ = '"'; /* close the string. */
+
+  return data;
+}
+
+json_weak char *json_write_minified_array(const struct json_array_s *array,
+  char *data);
+char *json_write_minified_array(const struct json_array_s *array,
+  char *data) {
+  struct json_array_element_s *element = json_null;
+
+  *data++ = '['; /* open the array. */
+
+  for (element = array->start; json_null != element; element = element->next) {
+    if (element != array->start) {
+      *data++ = ','; /* ','s seperate each element. */
+    }
+
+    data = json_write_minified_value(element->value, data);
+
+    if (json_null == data) {
+      /* value was malformed! */
+      return json_null;
+    }
+  }
+
+  *data++ = ']'; /* close the array. */
+
+  return data;
+}
+
+json_weak char *json_write_minified_object(const struct json_object_s *object,
+  char *data);
+char *json_write_minified_object(const struct json_object_s *object,
+  char *data) {
+  struct json_object_element_s *element = json_null;
+
+  *data++ = '{'; /* open the object. */
+
+  for (element = object->start; json_null != element;
+    element = element->next) {
+    if (element != object->start) {
+      *data++ = ','; /* ','s seperate each element. */
+    }
+
+    data = json_write_string(element->name, data);
+
+    if (json_null == data) {
+      /* string was malformed! */
+      return json_null;
+    }
+
+    *data++ = ':'; /* ':'s seperate each name/value pair. */
+
+    data = json_write_minified_value(element->value, data);
+
+    if (json_null == data) {
+      /* value was malformed! */
+      return json_null;
+    }
+  }
+
+  *data++ = '}'; /* close the object. */
+
+  return data;
+}
+
+json_weak char *json_write_minified_value(const struct json_value_s *value,
+  char *data);
+char *json_write_minified_value(const struct json_value_s *value,
+  char *data) {
+  switch (value->type) {
+  default:
+    /* unknown value type found! */
+    return json_null;
+  case json_type_number:
+    return json_write_number((struct json_number_s *)value->payload, data);
+  case json_type_string:
+    return json_write_string((struct json_string_s *)value->payload, data);
+  case json_type_array:
+    return json_write_minified_array((struct json_array_s *)value->payload,
+      data);
+  case json_type_object:
+    return json_write_minified_object((struct json_object_s *)value->payload,
+      data);
+  case json_type_true:
+    data[0] = 't';
+    data[1] = 'r';
+    data[2] = 'u';
+    data[3] = 'e';
+    return data + 4;
+  case json_type_false:
+    data[0] = 'f';
+    data[1] = 'a';
+    data[2] = 'l';
+    data[3] = 's';
+    data[4] = 'e';
+    return data + 5;
+  case json_type_null:
+    data[0] = 'n';
+    data[1] = 'u';
+    data[2] = 'l';
+    data[3] = 'l';
+    return data + 4;
+  }
+}
+
+void *json_write_minified(const struct json_value_s *value, size_t *out_size) {
+  size_t size = 0;
+  char *data = json_null;
+  char *data_end = json_null;
+
+  if (json_null == value) {
+    return json_null;
+  }
+
+  if (json_write_minified_get_value_size(value, &size)) {
+    /* value was malformed! */
+    return json_null;
+  }
+
+  size += 1; /* for the '\0' null terminating character. */
+
+  data = (char *)malloc(size);
+
+  if (json_null == data) {
+    /* malloc failed! */
+    return json_null;
+  }
+
+  data_end = json_write_minified_value(value, data);
+
+  if (json_null == data_end) {
+    /* bad chi occurred! */
+    free(data);
+    return json_null;
+  }
+
+  /* null terminated the string. */
+  *data_end = '\0';
+
+  if (json_null != out_size) {
+    *out_size = size;
+  }
+
+  return data;
+}
+
+json_weak int json_write_pretty_get_value_size(const struct json_value_s *value,
+  size_t depth, size_t indent_size,
+  size_t newline_size, size_t *size);
+
+json_weak int json_write_pretty_get_array_size(const struct json_array_s *array,
+  size_t depth, size_t indent_size,
+  size_t newline_size, size_t *size);
+int json_write_pretty_get_array_size(const struct json_array_s *array,
+  size_t depth, size_t indent_size,
+  size_t newline_size, size_t *size) {
+  struct json_array_element_s *element;
+
+  *size += 1; /* '['. */
+
+  if (0 < array->length) {
+    /* if we have any elements we need to add a newline after our '['. */
+    *size += newline_size;
+
+    *size += array->length - 1; /* ','s seperate each element. */
+
+    for (element = array->start; json_null != element;
+      element = element->next) {
+      /* each element gets an indent. */
+      *size += (depth + 1) * indent_size;
+
+      if (json_write_pretty_get_value_size(element->value, depth + 1,
+        indent_size, newline_size, size)) {
+        /* value was malformed! */
+        return 1;
+      }
+
+      /* each element gets a newline too. */
+      *size += newline_size;
+    }
+
+    /* since we wrote out some elements, need to add a newline and indentation.
+     */
+     /* to the trailing ']'. */
+    *size += depth * indent_size;
+  }
+
+  *size += 1; /* ']'. */
+
+  return 0;
+}
+
+json_weak int json_write_pretty_get_object_size(const struct json_object_s *object,
+  size_t depth, size_t indent_size,
+  size_t newline_size,
+  size_t *size);
+int json_write_pretty_get_object_size(const struct json_object_s *object,
+  size_t depth, size_t indent_size,
+  size_t newline_size,
+  size_t *size) {
+  struct json_object_element_s *element;
+
+  *size += 1; /* '{'. */
+
+  if (0 < object->length) {
+    *size += newline_size; /* need a newline next. */
+
+    *size += object->length - 1; /* ','s seperate each element. */
+
+    for (element = object->start; json_null != element;
+      element = element->next) {
+      /* each element gets an indent and newline. */
+      *size += (depth + 1) * indent_size;
+      *size += newline_size;
+
+      if (json_write_get_string_size(element->name, size)) {
+        /* string was malformed! */
+        return 1;
+      }
+
+      *size += 3; /* seperate each name/value pair with " : ". */
+
+      if (json_write_pretty_get_value_size(element->value, depth + 1,
+        indent_size, newline_size, size)) {
+        /* value was malformed! */
+        return 1;
+      }
+    }
+
+    *size += depth * indent_size;
+  }
+
+  *size += 1; /* '}'. */
+
+  return 0;
+}
+
+json_weak int json_write_pretty_get_value_size(const struct json_value_s *value,
+  size_t depth, size_t indent_size,
+  size_t newline_size, size_t *size);
+int json_write_pretty_get_value_size(const struct json_value_s *value,
+  size_t depth, size_t indent_size,
+  size_t newline_size, size_t *size) {
+  switch (value->type) {
+  default:
+    /* unknown value type found! */
+    return 1;
+  case json_type_number:
+    return json_write_get_number_size((struct json_number_s *)value->payload,
+      size);
+  case json_type_string:
+    return json_write_get_string_size((struct json_string_s *)value->payload,
+      size);
+  case json_type_array:
+    return json_write_pretty_get_array_size(
+      (struct json_array_s *)value->payload, depth, indent_size, newline_size,
+      size);
+  case json_type_object:
+    return json_write_pretty_get_object_size(
+      (struct json_object_s *)value->payload, depth, indent_size,
+      newline_size, size);
+  case json_type_true:
+    *size += 4; /* the string "true". */
+    return 0;
+  case json_type_false:
+    *size += 5; /* the string "false". */
+    return 0;
+  case json_type_null:
+    *size += 4; /* the string "null". */
+    return 0;
+  }
+}
+
+json_weak char *json_write_pretty_value(const struct json_value_s *value,
+  size_t depth, const char *indent,
+  const char *newline, char *data);
+
+json_weak char *json_write_pretty_array(const struct json_array_s *array,
+  size_t depth, const char *indent,
+  const char *newline, char *data);
+char *json_write_pretty_array(const struct json_array_s *array,
+  size_t depth, const char *indent,
+  const char *newline, char *data) {
+  size_t k, m;
+  struct json_array_element_s *element;
+
+  *data++ = '['; /* open the array. */
+
+  if (0 < array->length) {
+    for (k = 0; '\0' != newline[k]; k++) {
+      *data++ = newline[k];
+    }
+
+    for (element = array->start; json_null != element;
+      element = element->next) {
+      if (element != array->start) {
+        *data++ = ','; /* ','s seperate each element. */
+
+        for (k = 0; '\0' != newline[k]; k++) {
+          *data++ = newline[k];
+        }
+      }
+
+      for (k = 0; k < depth + 1; k++) {
+        for (m = 0; '\0' != indent[m]; m++) {
+          *data++ = indent[m];
+        }
+      }
+
+      data = json_write_pretty_value(element->value, depth + 1, indent, newline,
+        data);
+
+      if (json_null == data) {
+        /* value was malformed! */
+        return json_null;
+      }
+    }
+
+    for (k = 0; '\0' != newline[k]; k++) {
+      *data++ = newline[k];
+    }
+
+    for (k = 0; k < depth; k++) {
+      for (m = 0; '\0' != indent[m]; m++) {
+        *data++ = indent[m];
+      }
+    }
+  }
+
+  *data++ = ']'; /* close the array. */
+
+  return data;
+}
+
+json_weak char *json_write_pretty_object(const struct json_object_s *object,
+  size_t depth, const char *indent,
+  const char *newline, char *data);
+char *json_write_pretty_object(const struct json_object_s *object,
+  size_t depth, const char *indent,
+  const char *newline, char *data) {
+  size_t k, m;
+  struct json_object_element_s *element;
+
+  *data++ = '{'; /* open the object. */
+
+  if (0 < object->length) {
+    for (k = 0; '\0' != newline[k]; k++) {
+      *data++ = newline[k];
+    }
+
+    for (element = object->start; json_null != element;
+      element = element->next) {
+      if (element != object->start) {
+        *data++ = ','; /* ','s seperate each element. */
+
+        for (k = 0; '\0' != newline[k]; k++) {
+          *data++ = newline[k];
+        }
+      }
+
+      for (k = 0; k < depth + 1; k++) {
+        for (m = 0; '\0' != indent[m]; m++) {
+          *data++ = indent[m];
+        }
+      }
+
+      data = json_write_string(element->name, data);
+
+      if (json_null == data) {
+        /* string was malformed! */
+        return json_null;
+      }
+
+      /* " : "s seperate each name/value pair. */
+      *data++ = ' ';
+      *data++ = ':';
+      *data++ = ' ';
+
+      data = json_write_pretty_value(element->value, depth + 1, indent, newline,
+        data);
+
+      if (json_null == data) {
+        /* value was malformed! */
+        return json_null;
+      }
+    }
+
+    for (k = 0; '\0' != newline[k]; k++) {
+      *data++ = newline[k];
+    }
+
+    for (k = 0; k < depth; k++) {
+      for (m = 0; '\0' != indent[m]; m++) {
+        *data++ = indent[m];
+      }
+    }
+  }
+
+  *data++ = '}'; /* close the object. */
+
+  return data;
+}
+
+json_weak char *json_write_pretty_value(const struct json_value_s *value,
+  size_t depth, const char *indent,
+  const char *newline, char *data);
+char *json_write_pretty_value(const struct json_value_s *value,
+  size_t depth, const char *indent,
+  const char *newline, char *data) {
+  switch (value->type) {
+  default:
+    /* unknown value type found! */
+    return json_null;
+  case json_type_number:
+    return json_write_number((struct json_number_s *)value->payload, data);
+  case json_type_string:
+    return json_write_string((struct json_string_s *)value->payload, data);
+  case json_type_array:
+    return json_write_pretty_array((struct json_array_s *)value->payload, depth,
+      indent, newline, data);
+  case json_type_object:
+    return json_write_pretty_object((struct json_object_s *)value->payload,
+      depth, indent, newline, data);
+  case json_type_true:
+    data[0] = 't';
+    data[1] = 'r';
+    data[2] = 'u';
+    data[3] = 'e';
+    return data + 4;
+  case json_type_false:
+    data[0] = 'f';
+    data[1] = 'a';
+    data[2] = 'l';
+    data[3] = 's';
+    data[4] = 'e';
+    return data + 5;
+  case json_type_null:
+    data[0] = 'n';
+    data[1] = 'u';
+    data[2] = 'l';
+    data[3] = 'l';
+    return data + 4;
+  }
+}
+
+void *json_write_pretty(const struct json_value_s *value, const char *indent,
+  const char *newline, size_t *out_size) {
+  size_t size = 0;
+  size_t indent_size = 0;
+  size_t newline_size = 0;
+  char *data = json_null;
+  char *data_end = json_null;
+
+  if (json_null == value) {
+    return json_null;
+  }
+
+  if (json_null == indent) {
+    indent = "  "; /* default to two spaces. */
+  }
+
+  if (json_null == newline) {
+    newline = "\n"; /* default to linux newlines. */
+  }
+
+  while ('\0' != indent[indent_size]) {
+    ++indent_size; /* skip non-null terminating characters. */
+  }
+
+  while ('\0' != newline[newline_size]) {
+    ++newline_size; /* skip non-null terminating characters. */
+  }
+
+  if (json_write_pretty_get_value_size(value, 0, indent_size, newline_size,
+    &size)) {
+    /* value was malformed! */
+    return json_null;
+  }
+
+  size += 1; /* for the '\0' null terminating character. */
+
+  data = (char *)malloc(size);
+
+  if (json_null == data) {
+    /* malloc failed! */
+    return json_null;
+  }
+
+  data_end = json_write_pretty_value(value, 0, indent, newline, data);
+
+  if (json_null == data_end) {
+    /* bad chi occurred! */
+    free(data);
+    return json_null;
+  }
+
+  /* null terminated the string. */
+  *data_end = '\0';
+
+  if (json_null != out_size) {
+    *out_size = size;
+  }
+
+  return data;
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif /* SHEREDOM_JSON_H_INCLUDED. */
index 7f2a6f0..ec2879b 100644 (file)
@@ -80,6 +80,28 @@ Requires:   %{name} = %{version}-%{release}
 Application development package for Dali 3D engine toolkit - headers and package config
 
 ##############################
 Application development package for Dali 3D engine toolkit - headers and package config
 
 ##############################
+# dali-scene-loader
+##############################
+%define dali2_scene_loader dali2-scene-loader
+%package -n %{dali2_scene_loader}
+Summary:    DLI scene loading library
+Group:      System/Libraries
+License:    Apache-2.0
+
+BuildRequires:  pkgconfig(dali2-toolkit)
+
+%description -n %{dali2_scene_loader}
+Provides functionality for loading and displaying DLI format scenes. See README.md for more details.
+
+%package -n %{dali2_scene_loader}-devel
+Summary:    Development components for dali-scene-loader
+Group:      Development/Building
+Requires:   %{dali2_scene_loader} = %{version}-%{release}
+
+%description -n %{dali2_scene_loader}-devel
+Development components for dali-scene-loader.
+
+##############################
 # Preparation
 ##############################
 %prep
 # Preparation
 ##############################
 %prep
@@ -93,6 +115,8 @@ Application development package for Dali 3D engine toolkit - headers and package
 %define dali_toolkit_style_files    %{dali_data_ro_dir}/toolkit/styles/
 %define dev_include_path %{_includedir}
 
 %define dali_toolkit_style_files    %{dali_data_ro_dir}/toolkit/styles/
 %define dev_include_path %{_includedir}
 
+%define dali_xml_file_dir     %TZ_SYS_RO_PACKAGES
+
 # PO
 {
 cd %{_builddir}/dali2-toolkit-%{version}/dali-toolkit/po
 # PO
 {
 cd %{_builddir}/dali2-toolkit-%{version}/dali-toolkit/po
@@ -116,6 +140,10 @@ CXXFLAGS+=" --coverage "
 LDFLAGS+=" --coverage "
 %endif
 
 LDFLAGS+=" --coverage "
 %endif
 
+%ifarch %{arm}
+CXXFLAGS+=" -D_ARCH_ARM_"
+%endif
+
 libtoolize --force
 cd %{_builddir}/dali2-toolkit-%{version}/build/tizen
 
 libtoolize --force
 cd %{_builddir}/dali2-toolkit-%{version}/build/tizen
 
@@ -388,3 +416,18 @@ esac
 %{dali_toolkit_style_files}/1920x1080/*
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
 %{dali_toolkit_style_files}/1920x1080/*
 %{dali_toolkit_style_files}/default-feedback-theme.json
 %{_datadir}/locale/*/LC_MESSAGES/*
+
+%files -n %{dali2_scene_loader}
+%if 0%{?enable_dali_smack_rules}
+%manifest dali-scene-loader.manifest-smack
+%else
+%manifest dali-scene-loader.manifest
+%endif
+%defattr(-,root,root,-)
+%{_libdir}/lib%{dali2_scene_loader}.so
+%license LICENSE
+
+%files -n %{dali2_scene_loader}-devel
+%defattr(-,root,root,-)
+%{_includedir}/dali-scene-loader/public-api/*
+%{_libdir}/pkgconfig/dali2-scene-loader.pc