From ae057940afd7eed123642ac55a40aee3f51ce989 Mon Sep 17 00:00:00 2001 From: Kevin Weispfennig Date: Sat, 26 Nov 2022 02:22:02 +0100 Subject: [PATCH] Update framework --- app_web/game.js | 4 +- framework/asset-manager/downloader.d.ts | 12 + framework/asset-manager/downloader.js | 50 + framework/asset-manager/index.d.ts | 18 + framework/asset-manager/index.js | 71 + framework/asset-manager/manifest.d.ts | 2 + framework/asset-manager/manifest.js | 40 + framework/asset-manager/queue.d.ts | 8 + framework/asset-manager/queue.js | 19 + framework/asset-manager/storage.d.ts | 11 + framework/asset-manager/storage.js | 48 + framework/asset-manager/test/index.d.ts | 1 + framework/asset-manager/test/index.js | 5 + framework/asset-manager/utils.d.ts | 1 + framework/asset-manager/utils.js | 8 + framework/ecs/component.d.ts | 12 + framework/ecs/component.js | 11 + framework/ecs/entity.d.ts | 19 + framework/ecs/entity.js | 23 + framework/ecs/index.d.ts | 28 + framework/ecs/index.js | 105 + framework/ecs/query.d.ts | 15 + framework/ecs/query.js | 34 + framework/ecs/system.d.ts | 6 + framework/ecs/system.js | 10 + {src/framework => framework}/engine.js | 0 .../event-bus/event-bus.d.ts | 22 +- .../event-bus}/event-bus.js | 60 +- framework/event-bus/index.d.ts | 13 + framework/event-bus/index.js | 44 + {src/framework => framework}/game/game.d.ts | 0 {src/framework => framework}/game/game.js | 0 framework/game/index.d.ts | 26 + framework/game/index.js | 44 + .../game/scenes/ecs-scene.d.ts | 58 +- .../game/scenes/ecs-scene.js | 98 +- framework/index.d.ts | 7 + framework/index.js | 7 + framework/input/index.d.ts | 13 + framework/input/index.js | 34 + framework/input/input-factory.d.ts | 1 + framework/input/input-factory.js | 14 + framework/input/inputs/base-input.d.ts | 10 + framework/input/inputs/base-input.js | 12 + framework/input/inputs/joystick.d.ts | 6 + framework/input/inputs/joystick.js | 6 + framework/input/inputs/keyboard.d.ts | 18 + framework/input/inputs/keyboard.js | 50 + framework/input/inputs/mouse.d.ts | 34 + framework/input/inputs/mouse.js | 87 + framework/input/interfaces/state.d.ts | 4 + framework/input/interfaces/state.js | 1 + framework/input/keycodes.d.ts | 122 + framework/input/keycodes.js | 122 + {src/framework => framework}/package.json | 66 +- framework/physics/aabb.d.ts | 2 + framework/physics/aabb.js | 17 + .../physics/index.d.ts | 0 .../quadtree.js => framework/physics/index.js | 0 framework/physics/object.d.ts | 7 + framework/physics/object.js | 2 + framework/physics/octree.d.ts | 39 + framework/physics/octree.js | 206 ++ .../physics/octtree.d.ts | 76 +- .../physics/octtree.js | 386 +-- .../physics/quadtree.d.ts | 0 .../physics/quadtree.js | 0 .../framework => framework}/physics/vec3.d.ts | 26 +- {src/framework => framework}/physics/vec3.js | 56 +- framework/physics/world.d.ts | 23 + framework/physics/world.js | 54 + framework/resonator/audio-context.d.ts | 11 + framework/resonator/audio-context.js | 39 + framework/resonator/audio-graph.d.ts | 21 + framework/resonator/audio-graph.js | 46 + framework/resonator/data-pool-item.d.ts | 12 + framework/resonator/data-pool-item.js | 26 + framework/resonator/data-pool.d.ts | 12 + framework/resonator/data-pool.js | 48 + framework/resonator/effect-bus.d.ts | 8 + framework/resonator/effect-bus.js | 12 + framework/resonator/effect-chain.d.ts | 14 + framework/resonator/effect-chain.js | 45 + framework/resonator/effects/base-effect.d.ts | 15 + framework/resonator/effects/base-effect.js | 23 + framework/resonator/effects/convolver.d.ts | 10 + framework/resonator/effects/convolver.js | 20 + framework/resonator/index.d.ts | 22 + framework/resonator/index.js | 78 + framework/resonator/loaders/asset-loader.d.ts | 10 + framework/resonator/loaders/asset-loader.js | 36 + framework/resonator/loaders/base-loader.d.ts | 3 + framework/resonator/loaders/base-loader.js | 1 + framework/resonator/loaders/http-loader.d.ts | 4 + framework/resonator/loaders/http-loader.js | 18 + .../resonator/scenes/resonance-scene.d.ts | 14 + framework/resonator/scenes/resonance-scene.js | 40 + .../resonator/scenes/webaudio-scene.d.ts | 14 + framework/resonator/scenes/webaudio-scene.js | 42 + framework/resonator/sources/audio-source.d.ts | 37 + framework/resonator/sources/audio-source.js | 148 ++ framework/resonator/sources/base-source.d.ts | 12 + framework/resonator/sources/base-source.js | 1 + framework/resonator/sources/source-type.d.ts | 5 + framework/resonator/sources/source-type.js | 6 + .../resonator/sources/streaming-source.d.ts | 33 + .../resonator/sources/streaming-source.js | 99 + .../vendor/resonance-es6/attenuation.d.ts | 40 + .../vendor/resonance-es6/attenuation.js | 151 ++ .../resonator/vendor/resonance-es6/d.d.ts | 217 ++ framework/resonator/vendor/resonance-es6/d.js | 0 .../vendor/resonance-es6/directivity.d.ts | 47 + .../vendor/resonance-es6/directivity.js | 117 + .../resonance-es6/early-reflections.d.ts | 56 + .../vendor/resonance-es6/early-reflections.js | 212 ++ .../vendor/resonance-es6/encoder.d.ts | 64 + .../resonator/vendor/resonance-es6/encoder.js | 194 ++ .../resonance-es6/late-reflections.d.ts | 42 + .../vendor/resonance-es6/late-reflections.js | 187 ++ .../vendor/resonance-es6/listener.d.ts | 49 + .../vendor/resonance-es6/listener.js | 168 ++ .../resonator/vendor/resonance-es6/main.d.ts | 2 + .../resonator/vendor/resonance-es6/main.js | 23 + .../vendor/resonance-es6/resonance-audio.d.ts | 130 + .../vendor/resonance-es6/resonance-audio.js | 213 ++ .../resonator/vendor/resonance-es6/room.d.ts | 55 + .../resonator/vendor/resonance-es6/room.js | 300 +++ .../vendor/resonance-es6/source.d.ts | 182 ++ .../resonator/vendor/resonance-es6/source.js | 308 +++ .../vendor/resonance-es6/tables.d.ts | 38 + .../resonator/vendor/resonance-es6/tables.js | 1144 +++++++++ .../resonator/vendor/resonance-es6/utils.d.ts | 98 + .../resonator/vendor/resonance-es6/utils.js | 379 +++ .../vendor/resonance-es6/version.d.ts | 2 + .../resonator/vendor/resonance-es6/version.js | 24 + .../resonator/vendor/tsm/constants.d.ts | 2 +- .../resonator/vendor/tsm/constants.js | 2 +- .../resonator/vendor/tsm/mat2.d.ts | 46 +- .../resonator/vendor/tsm/mat2.js | 322 +-- .../resonator/vendor}/tsm/mat3.d.ts | 56 +- .../resonator/vendor/tsm/mat3.js | 784 +++--- .../resonator/vendor}/tsm/mat4.d.ts | 66 +- .../resonator/vendor/tsm/mat4.js | 1158 ++++----- .../resonator/vendor/tsm/quat.d.ts | 94 +- .../resonator/vendor}/tsm/quat.js | 808 +++--- .../resonator/vendor/tsm/tsm.d.ts | 34 +- .../resonator/vendor/tsm/tsm.js | 80 +- .../resonator/vendor}/tsm/vec2.d.ts | 80 +- .../resonator/vendor}/tsm/vec2.js | 430 ++-- .../resonator/vendor}/tsm/vec3.d.ts | 94 +- .../resonator/vendor}/tsm/vec3.js | 558 ++-- .../resonator/vendor/tsm/vec4.d.ts | 108 +- .../resonator/vendor/tsm/vec4.js | 554 ++-- framework/scene/index.d.ts | 0 framework/scene/index.js | 0 framework/scene/manager.d.ts | 12 + framework/scene/manager.js | 33 + framework/scene/scene.d.ts | 10 + framework/scene/scene.js | 1 + framework/scheduler/index.d.ts | 12 + framework/scheduler/index.js | 37 + framework/scheduler/node.d.ts | 4 + framework/scheduler/node.js | 1 + framework/scheduler/raf.d.ts | 10 + framework/scheduler/raf.js | 24 + framework/scheduler/scheduler-node.d.ts | 0 framework/scheduler/scheduler-node.js | 0 framework/scheduler/timer.d.ts | 14 + framework/scheduler/timer.js | 39 + .../tsm/constants.d.ts | 2 +- {src/framework => framework}/tsm/constants.js | 2 +- {src/framework => framework}/tsm/mat2.d.ts | 46 +- {src/framework => framework}/tsm/mat2.js | 322 +-- .../vendor => framework}/tsm/mat3.d.ts | 56 +- {src/framework => framework}/tsm/mat3.js | 784 +++--- .../vendor => framework}/tsm/mat4.d.ts | 66 +- {src/framework => framework}/tsm/mat4.js | 1158 ++++----- {src/framework => framework}/tsm/quat.d.ts | 94 +- .../vendor => framework}/tsm/quat.js | 808 +++--- {src/framework => framework}/tsm/tsm.d.ts | 34 +- {src/framework => framework}/tsm/tsm.js | 80 +- .../vendor => framework}/tsm/vec2.d.ts | 80 +- .../vendor => framework}/tsm/vec2.js | 430 ++-- .../vendor => framework}/tsm/vec3.d.ts | 94 +- .../vendor => framework}/tsm/vec3.js | 558 ++-- {src/framework => framework}/tsm/vec4.d.ts | 108 +- {src/framework => framework}/tsm/vec4.js | 554 ++-- framework/tts/index.d.ts | 7 + framework/tts/index.js | 12 + framework/tts/output-factory.d.ts | 5 + framework/tts/output-factory.js | 17 + framework/tts/outputs/aria.d.ts | 11 + framework/tts/outputs/aria.js | 32 + framework/tts/outputs/base-output.d.ts | 5 + framework/tts/outputs/base-output.js | 11 + framework/tts/outputs/webtts.d.ts | 3 + framework/tts/outputs/webtts.js | 3 + framework/ui/index.d.ts | 1 + framework/ui/index.js | 2 + framework/ui/menu/index.d.ts | 39 + framework/ui/menu/index.js | 145 ++ .../ui/menu/interfaces/playable-sound.d.ts | 3 + .../ui/menu/interfaces/playable-sound.js | 1 + framework/ui/menu/interfaces/sound-set.d.ts | 17 + framework/ui/menu/interfaces/sound-set.js | 1 + framework/ui/menu/items/base-item.d.ts | 13 + framework/ui/menu/items/base-item.js | 29 + framework/ui/menu/items/checkbox-item.d.ts | 10 + framework/ui/menu/items/checkbox-item.js | 32 + framework/ui/menu/items/edit-item.d.ts | 13 + framework/ui/menu/items/edit-item.js | 42 + framework/ui/menu/items/index.d.ts | 6 + framework/ui/menu/items/index.js | 6 + framework/ui/menu/items/menu-item.d.ts | 10 + framework/ui/menu/items/menu-item.js | 29 + framework/ui/menu/items/selector-item.d.ts | 21 + framework/ui/menu/items/selector-item.js | 62 + framework/ui/menu/items/slider-item.d.ts | 15 + framework/ui/menu/items/slider-item.js | 42 + framework/ui/menu/keyboard-manager.d.ts | 8 + framework/ui/menu/keyboard-manager.js | 40 + framework/ui/menu/menu.d.ts | 0 framework/ui/menu/menu.js | 0 framework/ui/menu/sound-manager.d.ts | 16 + framework/ui/menu/sound-manager.js | 84 + framework/ui/text/index.d.ts | 28 + framework/ui/text/index.js | 102 + .../ui/text/interfaces/playable-sound.d.ts | 3 + .../ui/text/interfaces/playable-sound.js | 1 + framework/ui/text/interfaces/sound-set.d.ts | 7 + framework/ui/text/interfaces/sound-set.js | 1 + framework/ui/text/keyboard-manager.d.ts | 8 + framework/ui/text/keyboard-manager.js | 25 + framework/ui/text/line.d.ts | 13 + framework/ui/text/line.js | 45 + framework/ui/text/sound-manager.d.ts | 13 + framework/ui/text/sound-manager.js | 27 + .../world/component.d.ts | 10 +- .../world/component.js | 10 +- .../world/ecs-world.d.ts | 48 +- .../world/ecs-world.js | 80 +- .../framework => framework}/world/entity.d.ts | 12 +- {src/framework => framework}/world/entity.js | 10 +- .../world/event-bus.d.ts | 22 +- .../world}/event-bus.js | 60 +- framework/world/index.d.ts | 3 + framework/world/index.js | 1 + {src/framework => framework}/world/query.d.ts | 26 +- {src/framework => framework}/world/query.js | 54 +- .../framework => framework}/world/system.d.ts | 12 +- {src/framework => framework}/world/system.js | 16 +- src/engine/room.js | 176 +- src/framework/asset-manager/downloader.d.ts | 24 +- src/framework/asset-manager/downloader.js | 100 +- src/framework/asset-manager/index.d.ts | 36 +- src/framework/asset-manager/index.js | 142 +- src/framework/asset-manager/manifest.d.ts | 4 +- src/framework/asset-manager/manifest.js | 80 +- src/framework/asset-manager/queue.d.ts | 16 +- src/framework/asset-manager/queue.js | 38 +- src/framework/asset-manager/storage.d.ts | 22 +- src/framework/asset-manager/storage.js | 96 +- src/framework/asset-manager/test/index.d.ts | 2 +- src/framework/asset-manager/test/index.js | 10 +- src/framework/asset-manager/utils.d.ts | 2 +- src/framework/asset-manager/utils.js | 16 +- src/framework/ecs/component.d.ts | 24 +- src/framework/ecs/component.js | 22 +- src/framework/ecs/entity.d.ts | 38 +- src/framework/ecs/entity.js | 46 +- src/framework/ecs/index.d.ts | 57 +- src/framework/ecs/index.js | 218 +- src/framework/ecs/query.d.ts | 30 +- src/framework/ecs/query.js | 68 +- src/framework/ecs/system.d.ts | 19 +- src/framework/ecs/system.js | 32 +- src/framework/event-bus/index.d.ts | 26 +- src/framework/event-bus/index.js | 88 +- src/framework/game/game-config.d.ts | 7 + src/framework/game/game-config.js | 6 + src/framework/game/index.d.ts | 54 +- src/framework/game/index.js | 90 +- src/framework/index.d.ts | 14 +- src/framework/index.js | 14 +- src/framework/input/index.d.ts | 26 +- src/framework/input/index.js | 68 +- src/framework/input/input-factory.d.ts | 2 +- src/framework/input/input-factory.js | 33 +- src/framework/input/inputs/base-input.d.ts | 25 +- src/framework/input/inputs/base-input.js | 29 +- src/framework/input/inputs/gamepad.d.ts | 6 + src/framework/input/inputs/gamepad.js | 14 + src/framework/input/inputs/joystick.d.ts | 12 +- src/framework/input/inputs/joystick.js | 12 +- src/framework/input/inputs/keyboard.d.ts | 36 +- src/framework/input/inputs/keyboard.js | 100 +- src/framework/input/inputs/mouse.d.ts | 68 +- src/framework/input/inputs/mouse.js | 174 +- src/framework/input/interfaces/state.d.ts | 8 +- src/framework/input/interfaces/state.js | 2 +- src/framework/input/keycodes.d.ts | 244 +- src/framework/input/keycodes.js | 244 +- src/framework/math/box.d.ts | 11 + src/framework/math/box.js | 48 + src/framework/math/constants.d.ts | 1 + src/framework/math/constants.js | 1 + src/framework/math/mat2.d.ts | 23 + src/framework/math/mat2.js | 161 ++ src/framework/math/mat3.d.ts | 28 + src/framework/math/mat3.js | 392 +++ src/framework/math/mat4.d.ts | 33 + src/framework/math/mat4.js | 579 +++++ src/framework/math/quat.d.ts | 49 + src/framework/math/quat.js | 452 ++++ src/framework/math/ray.d.ts | 8 + src/framework/math/ray.js | 31 + src/framework/math/sphere.d.ts | 0 src/framework/math/sphere.js | 0 src/framework/math/tsm.d.ts | 17 + src/framework/math/tsm.js | 40 + src/framework/math/vec2.d.ts | 40 + src/framework/math/vec2.js | 215 ++ src/framework/math/vec3.d.ts | 48 + src/framework/math/vec3.js | 291 +++ src/framework/math/vec4.d.ts | 54 + src/framework/math/vec4.js | 277 ++ src/framework/physics/aabb.d.ts | 4 +- src/framework/physics/aabb.js | 34 +- src/framework/physics/broadphase.d.ts | 7 + src/framework/physics/broadphase.js | 25 + src/framework/physics/collision/check.d.ts | 2 + src/framework/physics/collision/check.js | 6 + .../physics/collision/collision-event.d.ts | 7 + .../physics/collision/collision-event.js | 9 + src/framework/physics/collision/diff.d.ts | 9 + src/framework/physics/collision/diff.js | 41 + src/framework/physics/collision/index.d.ts | 14 + src/framework/physics/collision/index.js | 36 + src/framework/physics/collision/solver.d.ts | 5 + src/framework/physics/collision/solver.js | 15 + src/framework/physics/narrowphase.d.ts | 7 + src/framework/physics/narrowphase.js | 28 + src/framework/physics/object-type.d.ts | 4 + src/framework/physics/object-type.js | 5 + src/framework/physics/object.d.ts | 29 +- src/framework/physics/object.js | 57 +- src/framework/physics/octree.d.ts | 66 +- src/framework/physics/octree.js | 385 ++- src/framework/physics/processor.d.ts | 4 + src/framework/physics/processor.js | 1 + src/framework/physics/processors/gravity.d.ts | 7 + src/framework/physics/processors/gravity.js | 19 + src/framework/physics/terrain/index.d.ts | 14 + src/framework/physics/terrain/index.js | 99 + src/framework/physics/world.d.ts | 61 +- src/framework/physics/world.js | 130 +- src/framework/resonator/audio-context.d.ts | 22 +- src/framework/resonator/audio-context.js | 78 +- src/framework/resonator/audio-graph.d.ts | 42 +- src/framework/resonator/audio-graph.js | 92 +- src/framework/resonator/data-pool-item.d.ts | 24 +- src/framework/resonator/data-pool-item.js | 52 +- src/framework/resonator/data-pool.d.ts | 24 +- src/framework/resonator/data-pool.js | 96 +- src/framework/resonator/effect-bus.d.ts | 16 +- src/framework/resonator/effect-bus.js | 24 +- src/framework/resonator/effect-chain.d.ts | 28 +- src/framework/resonator/effect-chain.js | 90 +- .../resonator/effects/base-effect.d.ts | 30 +- .../resonator/effects/base-effect.js | 46 +- .../resonator/effects/convolver.d.ts | 20 +- src/framework/resonator/effects/convolver.js | 40 +- src/framework/resonator/index.d.ts | 44 +- src/framework/resonator/index.js | 156 +- .../resonator/loaders/asset-loader.d.ts | 20 +- .../resonator/loaders/asset-loader.js | 72 +- .../resonator/loaders/base-loader.d.ts | 6 +- .../resonator/loaders/base-loader.js | 2 +- .../resonator/loaders/http-loader.d.ts | 8 +- .../resonator/loaders/http-loader.js | 36 +- .../resonator/scenes/resonance-scene.d.ts | 28 +- .../resonator/scenes/resonance-scene.js | 80 +- .../resonator/scenes/webaudio-scene.d.ts | 28 +- .../resonator/scenes/webaudio-scene.js | 84 +- .../resonator/sources/audio-source.d.ts | 74 +- .../resonator/sources/audio-source.js | 296 +-- .../resonator/sources/base-source.d.ts | 24 +- .../resonator/sources/base-source.js | 2 +- .../resonator/sources/source-type.d.ts | 10 +- .../resonator/sources/source-type.js | 12 +- .../resonator/sources/streaming-source.d.ts | 66 +- .../resonator/sources/streaming-source.js | 198 +- .../vendor/resonance-es6/attenuation.d.ts | 80 +- .../vendor/resonance-es6/attenuation.js | 302 +-- .../resonator/vendor/resonance-es6/d.d.ts | 434 ++-- .../vendor/resonance-es6/directivity.d.ts | 94 +- .../vendor/resonance-es6/directivity.js | 234 +- .../resonance-es6/early-reflections.d.ts | 112 +- .../vendor/resonance-es6/early-reflections.js | 424 +-- .../vendor/resonance-es6/encoder.d.ts | 128 +- .../resonator/vendor/resonance-es6/encoder.js | 388 +-- .../resonance-es6/late-reflections.d.ts | 84 +- .../vendor/resonance-es6/late-reflections.js | 374 +-- .../vendor/resonance-es6/listener.d.ts | 98 +- .../vendor/resonance-es6/listener.js | 336 +-- .../resonator/vendor/resonance-es6/main.d.ts | 4 +- .../resonator/vendor/resonance-es6/main.js | 46 +- .../vendor/resonance-es6/resonance-audio.d.ts | 260 +- .../vendor/resonance-es6/resonance-audio.js | 426 +-- .../resonator/vendor/resonance-es6/room.d.ts | 110 +- .../resonator/vendor/resonance-es6/room.js | 600 ++--- .../vendor/resonance-es6/source.d.ts | 364 +-- .../resonator/vendor/resonance-es6/source.js | 616 ++--- .../vendor/resonance-es6/tables.d.ts | 76 +- .../resonator/vendor/resonance-es6/tables.js | 2288 ++++++++--------- .../resonator/vendor/resonance-es6/utils.d.ts | 196 +- .../resonator/vendor/resonance-es6/utils.js | 758 +++--- .../vendor/resonance-es6/version.d.ts | 4 +- .../resonator/vendor/resonance-es6/version.js | 48 +- src/framework/scene/manager.d.ts | 24 +- src/framework/scene/manager.js | 66 +- src/framework/scene/scene.d.ts | 20 +- src/framework/scene/scene.js | 15 +- src/framework/scheduler/index.d.ts | 24 +- src/framework/scheduler/index.js | 74 +- src/framework/scheduler/node.d.ts | 8 +- src/framework/scheduler/node.js | 2 +- src/framework/scheduler/raf.d.ts | 20 +- src/framework/scheduler/raf.js | 48 +- src/framework/scheduler/timer.d.ts | 28 +- src/framework/scheduler/timer.js | 78 +- src/framework/tts/index.d.ts | 14 +- src/framework/tts/index.js | 24 +- src/framework/tts/output-factory.d.ts | 10 +- src/framework/tts/output-factory.js | 34 +- src/framework/tts/outputs/aria.d.ts | 22 +- src/framework/tts/outputs/aria.js | 64 +- src/framework/tts/outputs/base-output.d.ts | 10 +- src/framework/tts/outputs/base-output.js | 22 +- src/framework/tts/outputs/webtts.d.ts | 12 +- src/framework/tts/outputs/webtts.js | 22 +- .../ui/dialog/control-container.d.ts | 8 + src/framework/ui/dialog/control-container.js | 11 + .../ui/dialog/controls/base-control.d.ts | 10 + .../ui/dialog/controls/base-control.js | 24 + .../ui/dialog/controls/button-control.d.ts | 3 + .../ui/dialog/controls/button-control.js | 3 + .../ui/dialog/controls/checkbox-control.d.ts | 0 .../ui/dialog/controls/checkbox-control.js | 0 .../ui/dialog/controls/list-control.d.ts | 0 .../ui/dialog/controls/list-control.js | 0 .../ui/dialog/controls/slider-control.d.ts | 0 .../ui/dialog/controls/slider-control.js | 0 .../ui/dialog/controls/text-control.d.ts | 0 .../ui/dialog/controls/text-control.js | 0 .../ui/dialog/controls/tree-control.d.ts | 0 .../ui/dialog/controls/tree-control.js | 0 src/framework/ui/dialog/index.d.ts | 14 + src/framework/ui/dialog/index.js | 24 + .../ui/dialog/interfaces/playable-sound.d.ts | 3 + .../ui/dialog/interfaces/playable-sound.js | 1 + .../ui/dialog/interfaces/sound-set.d.ts | 17 + .../ui/dialog/interfaces/sound-set.js | 1 + src/framework/ui/dialog/key-manager.d.ts | 5 + src/framework/ui/dialog/key-manager.js | 5 + src/framework/ui/dialog/sound-manager.d.ts | 4 + src/framework/ui/dialog/sound-manager.js | 3 + src/framework/ui/index.d.ts | 2 +- src/framework/ui/index.js | 4 +- src/framework/ui/menu/index.d.ts | 78 +- src/framework/ui/menu/index.js | 290 +-- .../ui/menu/interfaces/playable-sound.d.ts | 6 +- .../ui/menu/interfaces/playable-sound.js | 2 +- .../ui/menu/interfaces/sound-set.d.ts | 34 +- src/framework/ui/menu/interfaces/sound-set.js | 2 +- src/framework/ui/menu/items/base-item.d.ts | 26 +- src/framework/ui/menu/items/base-item.js | 58 +- .../ui/menu/items/checkbox-item.d.ts | 20 +- src/framework/ui/menu/items/checkbox-item.js | 64 +- src/framework/ui/menu/items/edit-item.d.ts | 26 +- src/framework/ui/menu/items/edit-item.js | 84 +- src/framework/ui/menu/items/index.d.ts | 12 +- src/framework/ui/menu/items/index.js | 12 +- src/framework/ui/menu/items/menu-item.d.ts | 20 +- src/framework/ui/menu/items/menu-item.js | 58 +- .../ui/menu/items/selector-item.d.ts | 42 +- src/framework/ui/menu/items/selector-item.js | 124 +- src/framework/ui/menu/items/slider-item.d.ts | 30 +- src/framework/ui/menu/items/slider-item.js | 84 +- src/framework/ui/menu/keyboard-manager.d.ts | 16 +- src/framework/ui/menu/keyboard-manager.js | 80 +- src/framework/ui/menu/sound-manager.d.ts | 32 +- src/framework/ui/menu/sound-manager.js | 168 +- src/framework/ui/text/index.d.ts | 56 +- src/framework/ui/text/index.js | 204 +- .../ui/text/interfaces/playable-sound.d.ts | 6 +- .../ui/text/interfaces/playable-sound.js | 2 +- .../ui/text/interfaces/sound-set.d.ts | 14 +- src/framework/ui/text/interfaces/sound-set.js | 2 +- src/framework/ui/text/keyboard-manager.d.ts | 16 +- src/framework/ui/text/keyboard-manager.js | 50 +- src/framework/ui/text/line.d.ts | 26 +- src/framework/ui/text/line.js | 90 +- src/framework/ui/text/sound-manager.d.ts | 26 +- src/framework/ui/text/sound-manager.js | 54 +- src/framework/world/index.d.ts | 8 +- src/framework/world/index.js | 7 +- src/game/commands/meow.js | 4 +- 508 files changed, 26011 insertions(+), 14248 deletions(-) create mode 100644 framework/asset-manager/downloader.d.ts create mode 100644 framework/asset-manager/downloader.js create mode 100644 framework/asset-manager/index.d.ts create mode 100644 framework/asset-manager/index.js create mode 100644 framework/asset-manager/manifest.d.ts create mode 100644 framework/asset-manager/manifest.js create mode 100644 framework/asset-manager/queue.d.ts create mode 100644 framework/asset-manager/queue.js create mode 100644 framework/asset-manager/storage.d.ts create mode 100644 framework/asset-manager/storage.js create mode 100644 framework/asset-manager/test/index.d.ts create mode 100644 framework/asset-manager/test/index.js create mode 100644 framework/asset-manager/utils.d.ts create mode 100644 framework/asset-manager/utils.js create mode 100644 framework/ecs/component.d.ts create mode 100644 framework/ecs/component.js create mode 100644 framework/ecs/entity.d.ts create mode 100644 framework/ecs/entity.js create mode 100644 framework/ecs/index.d.ts create mode 100644 framework/ecs/index.js create mode 100644 framework/ecs/query.d.ts create mode 100644 framework/ecs/query.js create mode 100644 framework/ecs/system.d.ts create mode 100644 framework/ecs/system.js rename {src/framework => framework}/engine.js (100%) rename {src/framework => framework}/event-bus/event-bus.d.ts (96%) rename {src/framework/world => framework/event-bus}/event-bus.js (95%) create mode 100644 framework/event-bus/index.d.ts create mode 100644 framework/event-bus/index.js rename {src/framework => framework}/game/game.d.ts (100%) rename {src/framework => framework}/game/game.js (100%) create mode 100644 framework/game/index.d.ts create mode 100644 framework/game/index.js rename {src/framework => framework}/game/scenes/ecs-scene.d.ts (97%) rename {src/framework => framework}/game/scenes/ecs-scene.js (96%) create mode 100644 framework/index.d.ts create mode 100644 framework/index.js create mode 100644 framework/input/index.d.ts create mode 100644 framework/input/index.js create mode 100644 framework/input/input-factory.d.ts create mode 100644 framework/input/input-factory.js create mode 100644 framework/input/inputs/base-input.d.ts create mode 100644 framework/input/inputs/base-input.js create mode 100644 framework/input/inputs/joystick.d.ts create mode 100644 framework/input/inputs/joystick.js create mode 100644 framework/input/inputs/keyboard.d.ts create mode 100644 framework/input/inputs/keyboard.js create mode 100644 framework/input/inputs/mouse.d.ts create mode 100644 framework/input/inputs/mouse.js create mode 100644 framework/input/interfaces/state.d.ts create mode 100644 framework/input/interfaces/state.js create mode 100644 framework/input/keycodes.d.ts create mode 100644 framework/input/keycodes.js rename {src/framework => framework}/package.json (96%) create mode 100644 framework/physics/aabb.d.ts create mode 100644 framework/physics/aabb.js rename src/framework/physics/quadtree.d.ts => framework/physics/index.d.ts (100%) rename src/framework/physics/quadtree.js => framework/physics/index.js (100%) create mode 100644 framework/physics/object.d.ts create mode 100644 framework/physics/object.js create mode 100644 framework/physics/octree.d.ts create mode 100644 framework/physics/octree.js rename {src/framework => framework}/physics/octtree.d.ts (96%) rename {src/framework => framework}/physics/octtree.js (97%) rename src/framework/scheduler/scheduler-node.d.ts => framework/physics/quadtree.d.ts (100%) rename src/framework/scheduler/scheduler-node.js => framework/physics/quadtree.js (100%) rename {src/framework => framework}/physics/vec3.d.ts (95%) rename {src/framework => framework}/physics/vec3.js (95%) create mode 100644 framework/physics/world.d.ts create mode 100644 framework/physics/world.js create mode 100644 framework/resonator/audio-context.d.ts create mode 100644 framework/resonator/audio-context.js create mode 100644 framework/resonator/audio-graph.d.ts create mode 100644 framework/resonator/audio-graph.js create mode 100644 framework/resonator/data-pool-item.d.ts create mode 100644 framework/resonator/data-pool-item.js create mode 100644 framework/resonator/data-pool.d.ts create mode 100644 framework/resonator/data-pool.js create mode 100644 framework/resonator/effect-bus.d.ts create mode 100644 framework/resonator/effect-bus.js create mode 100644 framework/resonator/effect-chain.d.ts create mode 100644 framework/resonator/effect-chain.js create mode 100644 framework/resonator/effects/base-effect.d.ts create mode 100644 framework/resonator/effects/base-effect.js create mode 100644 framework/resonator/effects/convolver.d.ts create mode 100644 framework/resonator/effects/convolver.js create mode 100644 framework/resonator/index.d.ts create mode 100644 framework/resonator/index.js create mode 100644 framework/resonator/loaders/asset-loader.d.ts create mode 100644 framework/resonator/loaders/asset-loader.js create mode 100644 framework/resonator/loaders/base-loader.d.ts create mode 100644 framework/resonator/loaders/base-loader.js create mode 100644 framework/resonator/loaders/http-loader.d.ts create mode 100644 framework/resonator/loaders/http-loader.js create mode 100644 framework/resonator/scenes/resonance-scene.d.ts create mode 100644 framework/resonator/scenes/resonance-scene.js create mode 100644 framework/resonator/scenes/webaudio-scene.d.ts create mode 100644 framework/resonator/scenes/webaudio-scene.js create mode 100644 framework/resonator/sources/audio-source.d.ts create mode 100644 framework/resonator/sources/audio-source.js create mode 100644 framework/resonator/sources/base-source.d.ts create mode 100644 framework/resonator/sources/base-source.js create mode 100644 framework/resonator/sources/source-type.d.ts create mode 100644 framework/resonator/sources/source-type.js create mode 100644 framework/resonator/sources/streaming-source.d.ts create mode 100644 framework/resonator/sources/streaming-source.js create mode 100644 framework/resonator/vendor/resonance-es6/attenuation.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/attenuation.js create mode 100644 framework/resonator/vendor/resonance-es6/d.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/d.js create mode 100644 framework/resonator/vendor/resonance-es6/directivity.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/directivity.js create mode 100644 framework/resonator/vendor/resonance-es6/early-reflections.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/early-reflections.js create mode 100644 framework/resonator/vendor/resonance-es6/encoder.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/encoder.js create mode 100644 framework/resonator/vendor/resonance-es6/late-reflections.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/late-reflections.js create mode 100644 framework/resonator/vendor/resonance-es6/listener.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/listener.js create mode 100644 framework/resonator/vendor/resonance-es6/main.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/main.js create mode 100644 framework/resonator/vendor/resonance-es6/resonance-audio.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/resonance-audio.js create mode 100644 framework/resonator/vendor/resonance-es6/room.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/room.js create mode 100644 framework/resonator/vendor/resonance-es6/source.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/source.js create mode 100644 framework/resonator/vendor/resonance-es6/tables.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/tables.js create mode 100644 framework/resonator/vendor/resonance-es6/utils.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/utils.js create mode 100644 framework/resonator/vendor/resonance-es6/version.d.ts create mode 100644 framework/resonator/vendor/resonance-es6/version.js rename {src/framework => framework}/resonator/vendor/tsm/constants.d.ts (97%) rename {src/framework => framework}/resonator/vendor/tsm/constants.js (96%) rename {src/framework => framework}/resonator/vendor/tsm/mat2.d.ts (96%) rename {src/framework => framework}/resonator/vendor/tsm/mat2.js (96%) rename {src/framework => framework/resonator/vendor}/tsm/mat3.d.ts (96%) rename {src/framework => framework}/resonator/vendor/tsm/mat3.js (97%) rename {src/framework => framework/resonator/vendor}/tsm/mat4.d.ts (97%) rename {src/framework => framework}/resonator/vendor/tsm/mat4.js (97%) rename {src/framework => framework}/resonator/vendor/tsm/quat.d.ts (97%) rename {src/framework => framework/resonator/vendor}/tsm/quat.js (96%) rename {src/framework => framework}/resonator/vendor/tsm/tsm.d.ts (95%) rename {src/framework => framework}/resonator/vendor/tsm/tsm.js (96%) rename {src/framework => framework/resonator/vendor}/tsm/vec2.d.ts (97%) rename {src/framework => framework/resonator/vendor}/tsm/vec2.js (95%) rename {src/framework => framework/resonator/vendor}/tsm/vec3.d.ts (97%) rename {src/framework => framework/resonator/vendor}/tsm/vec3.js (96%) rename {src/framework => framework}/resonator/vendor/tsm/vec4.d.ts (97%) rename {src/framework => framework}/resonator/vendor/tsm/vec4.js (96%) create mode 100644 framework/scene/index.d.ts create mode 100644 framework/scene/index.js create mode 100644 framework/scene/manager.d.ts create mode 100644 framework/scene/manager.js create mode 100644 framework/scene/scene.d.ts create mode 100644 framework/scene/scene.js create mode 100644 framework/scheduler/index.d.ts create mode 100644 framework/scheduler/index.js create mode 100644 framework/scheduler/node.d.ts create mode 100644 framework/scheduler/node.js create mode 100644 framework/scheduler/raf.d.ts create mode 100644 framework/scheduler/raf.js create mode 100644 framework/scheduler/scheduler-node.d.ts create mode 100644 framework/scheduler/scheduler-node.js create mode 100644 framework/scheduler/timer.d.ts create mode 100644 framework/scheduler/timer.js rename {src/framework => framework}/tsm/constants.d.ts (97%) rename {src/framework => framework}/tsm/constants.js (96%) rename {src/framework => framework}/tsm/mat2.d.ts (96%) rename {src/framework => framework}/tsm/mat2.js (96%) rename {src/framework/resonator/vendor => framework}/tsm/mat3.d.ts (96%) rename {src/framework => framework}/tsm/mat3.js (97%) rename {src/framework/resonator/vendor => framework}/tsm/mat4.d.ts (97%) rename {src/framework => framework}/tsm/mat4.js (97%) rename {src/framework => framework}/tsm/quat.d.ts (97%) rename {src/framework/resonator/vendor => framework}/tsm/quat.js (96%) rename {src/framework => framework}/tsm/tsm.d.ts (95%) rename {src/framework => framework}/tsm/tsm.js (96%) rename {src/framework/resonator/vendor => framework}/tsm/vec2.d.ts (97%) rename {src/framework/resonator/vendor => framework}/tsm/vec2.js (95%) rename {src/framework/resonator/vendor => framework}/tsm/vec3.d.ts (97%) rename {src/framework/resonator/vendor => framework}/tsm/vec3.js (96%) rename {src/framework => framework}/tsm/vec4.d.ts (97%) rename {src/framework => framework}/tsm/vec4.js (96%) create mode 100644 framework/tts/index.d.ts create mode 100644 framework/tts/index.js create mode 100644 framework/tts/output-factory.d.ts create mode 100644 framework/tts/output-factory.js create mode 100644 framework/tts/outputs/aria.d.ts create mode 100644 framework/tts/outputs/aria.js create mode 100644 framework/tts/outputs/base-output.d.ts create mode 100644 framework/tts/outputs/base-output.js create mode 100644 framework/tts/outputs/webtts.d.ts create mode 100644 framework/tts/outputs/webtts.js create mode 100644 framework/ui/index.d.ts create mode 100644 framework/ui/index.js create mode 100644 framework/ui/menu/index.d.ts create mode 100644 framework/ui/menu/index.js create mode 100644 framework/ui/menu/interfaces/playable-sound.d.ts create mode 100644 framework/ui/menu/interfaces/playable-sound.js create mode 100644 framework/ui/menu/interfaces/sound-set.d.ts create mode 100644 framework/ui/menu/interfaces/sound-set.js create mode 100644 framework/ui/menu/items/base-item.d.ts create mode 100644 framework/ui/menu/items/base-item.js create mode 100644 framework/ui/menu/items/checkbox-item.d.ts create mode 100644 framework/ui/menu/items/checkbox-item.js create mode 100644 framework/ui/menu/items/edit-item.d.ts create mode 100644 framework/ui/menu/items/edit-item.js create mode 100644 framework/ui/menu/items/index.d.ts create mode 100644 framework/ui/menu/items/index.js create mode 100644 framework/ui/menu/items/menu-item.d.ts create mode 100644 framework/ui/menu/items/menu-item.js create mode 100644 framework/ui/menu/items/selector-item.d.ts create mode 100644 framework/ui/menu/items/selector-item.js create mode 100644 framework/ui/menu/items/slider-item.d.ts create mode 100644 framework/ui/menu/items/slider-item.js create mode 100644 framework/ui/menu/keyboard-manager.d.ts create mode 100644 framework/ui/menu/keyboard-manager.js create mode 100644 framework/ui/menu/menu.d.ts create mode 100644 framework/ui/menu/menu.js create mode 100644 framework/ui/menu/sound-manager.d.ts create mode 100644 framework/ui/menu/sound-manager.js create mode 100644 framework/ui/text/index.d.ts create mode 100644 framework/ui/text/index.js create mode 100644 framework/ui/text/interfaces/playable-sound.d.ts create mode 100644 framework/ui/text/interfaces/playable-sound.js create mode 100644 framework/ui/text/interfaces/sound-set.d.ts create mode 100644 framework/ui/text/interfaces/sound-set.js create mode 100644 framework/ui/text/keyboard-manager.d.ts create mode 100644 framework/ui/text/keyboard-manager.js create mode 100644 framework/ui/text/line.d.ts create mode 100644 framework/ui/text/line.js create mode 100644 framework/ui/text/sound-manager.d.ts create mode 100644 framework/ui/text/sound-manager.js rename {src/framework => framework}/world/component.d.ts (95%) rename {src/framework => framework}/world/component.js (94%) rename {src/framework => framework}/world/ecs-world.d.ts (97%) rename {src/framework => framework}/world/ecs-world.js (96%) rename {src/framework => framework}/world/entity.d.ts (96%) rename {src/framework => framework}/world/entity.js (94%) rename {src/framework => framework}/world/event-bus.d.ts (96%) rename {src/framework/event-bus => framework/world}/event-bus.js (95%) create mode 100644 framework/world/index.d.ts create mode 100644 framework/world/index.js rename {src/framework => framework}/world/query.d.ts (97%) rename {src/framework => framework}/world/query.js (97%) rename {src/framework => framework}/world/system.d.ts (96%) rename {src/framework => framework}/world/system.js (95%) create mode 100644 src/framework/game/game-config.d.ts create mode 100644 src/framework/game/game-config.js create mode 100644 src/framework/input/inputs/gamepad.d.ts create mode 100644 src/framework/input/inputs/gamepad.js create mode 100644 src/framework/math/box.d.ts create mode 100644 src/framework/math/box.js create mode 100644 src/framework/math/constants.d.ts create mode 100644 src/framework/math/constants.js create mode 100644 src/framework/math/mat2.d.ts create mode 100644 src/framework/math/mat2.js create mode 100644 src/framework/math/mat3.d.ts create mode 100644 src/framework/math/mat3.js create mode 100644 src/framework/math/mat4.d.ts create mode 100644 src/framework/math/mat4.js create mode 100644 src/framework/math/quat.d.ts create mode 100644 src/framework/math/quat.js create mode 100644 src/framework/math/ray.d.ts create mode 100644 src/framework/math/ray.js create mode 100644 src/framework/math/sphere.d.ts create mode 100644 src/framework/math/sphere.js create mode 100644 src/framework/math/tsm.d.ts create mode 100644 src/framework/math/tsm.js create mode 100644 src/framework/math/vec2.d.ts create mode 100644 src/framework/math/vec2.js create mode 100644 src/framework/math/vec3.d.ts create mode 100644 src/framework/math/vec3.js create mode 100644 src/framework/math/vec4.d.ts create mode 100644 src/framework/math/vec4.js create mode 100644 src/framework/physics/broadphase.d.ts create mode 100644 src/framework/physics/broadphase.js create mode 100644 src/framework/physics/collision/check.d.ts create mode 100644 src/framework/physics/collision/check.js create mode 100644 src/framework/physics/collision/collision-event.d.ts create mode 100644 src/framework/physics/collision/collision-event.js create mode 100644 src/framework/physics/collision/diff.d.ts create mode 100644 src/framework/physics/collision/diff.js create mode 100644 src/framework/physics/collision/index.d.ts create mode 100644 src/framework/physics/collision/index.js create mode 100644 src/framework/physics/collision/solver.d.ts create mode 100644 src/framework/physics/collision/solver.js create mode 100644 src/framework/physics/narrowphase.d.ts create mode 100644 src/framework/physics/narrowphase.js create mode 100644 src/framework/physics/object-type.d.ts create mode 100644 src/framework/physics/object-type.js create mode 100644 src/framework/physics/processor.d.ts create mode 100644 src/framework/physics/processor.js create mode 100644 src/framework/physics/processors/gravity.d.ts create mode 100644 src/framework/physics/processors/gravity.js create mode 100644 src/framework/physics/terrain/index.d.ts create mode 100644 src/framework/physics/terrain/index.js create mode 100644 src/framework/ui/dialog/control-container.d.ts create mode 100644 src/framework/ui/dialog/control-container.js create mode 100644 src/framework/ui/dialog/controls/base-control.d.ts create mode 100644 src/framework/ui/dialog/controls/base-control.js create mode 100644 src/framework/ui/dialog/controls/button-control.d.ts create mode 100644 src/framework/ui/dialog/controls/button-control.js create mode 100644 src/framework/ui/dialog/controls/checkbox-control.d.ts create mode 100644 src/framework/ui/dialog/controls/checkbox-control.js create mode 100644 src/framework/ui/dialog/controls/list-control.d.ts create mode 100644 src/framework/ui/dialog/controls/list-control.js create mode 100644 src/framework/ui/dialog/controls/slider-control.d.ts create mode 100644 src/framework/ui/dialog/controls/slider-control.js create mode 100644 src/framework/ui/dialog/controls/text-control.d.ts create mode 100644 src/framework/ui/dialog/controls/text-control.js create mode 100644 src/framework/ui/dialog/controls/tree-control.d.ts create mode 100644 src/framework/ui/dialog/controls/tree-control.js create mode 100644 src/framework/ui/dialog/index.d.ts create mode 100644 src/framework/ui/dialog/index.js create mode 100644 src/framework/ui/dialog/interfaces/playable-sound.d.ts create mode 100644 src/framework/ui/dialog/interfaces/playable-sound.js create mode 100644 src/framework/ui/dialog/interfaces/sound-set.d.ts create mode 100644 src/framework/ui/dialog/interfaces/sound-set.js create mode 100644 src/framework/ui/dialog/key-manager.d.ts create mode 100644 src/framework/ui/dialog/key-manager.js create mode 100644 src/framework/ui/dialog/sound-manager.d.ts create mode 100644 src/framework/ui/dialog/sound-manager.js diff --git a/app_web/game.js b/app_web/game.js index 45b765c..6ab733c 100644 --- a/app_web/game.js +++ b/app_web/game.js @@ -1,2 +1,2 @@ -(()=>{"use strict";var t={729:t=>{var e=Object.prototype.hasOwnProperty,s="~";function i(){}function n(t,e,s){this.fn=t,this.context=e,this.once=s||!1}function a(t,e,i,a,h){if("function"!=typeof i)throw new TypeError("The listener must be a function");var r=new n(i,a||t,h),o=s?s+e:e;return t._events[o]?t._events[o].fn?t._events[o]=[t._events[o],r]:t._events[o].push(r):(t._events[o]=r,t._eventsCount++),t}function h(t,e){0==--t._eventsCount?t._events=new i:delete t._events[e]}function r(){this._events=new i,this._eventsCount=0}Object.create&&(i.prototype=Object.create(null),(new i).__proto__||(s=!1)),r.prototype.eventNames=function(){var t,i,n=[];if(0===this._eventsCount)return n;for(i in t=this._events)e.call(t,i)&&n.push(s?i.slice(1):i);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(t)):n},r.prototype.listeners=function(t){var e=s?s+t:t,i=this._events[e];if(!i)return[];if(i.fn)return[i.fn];for(var n=0,a=i.length,h=new Array(a);n{var e=t&&t.__esModule?()=>t.default:()=>t;return s.d(e,{a:e}),e},s.d=(t,e)=>{for(var i in e)s.o(e,i)&&!s.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},s.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{const t=new class{constructor(){this.states=new Map}get(t){return this.states.has(t)?this.states.get(t):null}set(t,e){return this.states.set(t,e)}serialize(){const t=this.states.entries(),e=[];for(let s of t)e.push(s);return e}deserialize(t){this.states=new Map(t)}};class e{constructor(){this.inventory=[],this.currentRoom="start",this.context=null}addItem(t){this.inventory.push(t)}removeItem(t){this.inventory=this.inventory.filter((e=>e!=t))}getInventory(){return this.inventory.map((t=>this.context.getItem(t)))}}class i{speak(t){}stop(){}setOptions(t){}}class n extends i{constructor(t={}){super(),this.timeout=100,this.timeout=t.timeout||100,this.init()}init(){this.container=document.createElement("div"),this.container.setAttribute("aria-live","polite"),this.speechDisplay=document.createElement("div"),this.speechDisplay.setAttribute("aria-live","polite"),this.container.append(this.speechDisplay),document.body.appendChild(this.container),document.body.insertBefore(this.container,document.body.firstChild)}speak(t){this.clearDisplay();const e=document.createTextNode(t),s=document.createElement("p");s.appendChild(e),this.speechDisplay.appendChild(s),setTimeout(this.clearDisplay.bind(this),this.timeout)}stop(){this.clearDisplay()}clearDisplay(){this.speechDisplay.innerHTML=""}}class a extends i{}class h{constructor(t=function(t="aria"){return"webtts"===t?a:n}()){this.output=t}speak(t){this.output.speak(t)}stop(){this.output.stop()}}var r=function(t,e,s,i){return new(s||(s=Promise))((function(n,a){function h(t){try{o(i.next(t))}catch(t){a(t)}}function r(t){try{o(i.throw(t))}catch(t){a(t)}}function o(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}o((i=i.apply(t,e||[])).next())}))};class o{constructor(){this.context=new AudioContext}getContext(){return this.context}createGain(){return this.context.createGain()}getOutputDestination(){return this.context.destination}createBufferSource(){return this.context.createBufferSource()}decodeAudioData(t){return r(this,void 0,void 0,(function*(){return yield this.context.decodeAudioData(t)}))}createPanner(){return this.context.createPanner()}createMediaElementSource(t){return this.context.createMediaElementSource(t)}}var u=s(729),l=s.n(u);class c{constructor(t){this.values=new Float32Array(4),void 0!==t&&(this.xyzw=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get w(){return this.values[3]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}get xyzw(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set w(t){this.values[3]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set xyzw(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}get r(){return this.values[0]}get g(){return this.values[1]}get b(){return this.values[2]}get a(){return this.values[3]}get rg(){return[this.values[0],this.values[1]]}get rgb(){return[this.values[0],this.values[1],this.values[2]]}get rgba(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set r(t){this.values[0]=t}set g(t){this.values[1]=t}set b(t){this.values[2]=t}set a(t){this.values[3]=t}set rg(t){this.values[0]=t[0],this.values[1]=t[1]}set rgb(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set rgba(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}at(t){return this.values[t]}reset(){this.x=0,this.y=0,this.z=0,this.w=0}copy(t){return t||(t=new c),t.x=this.x,t.y=this.y,t.z=this.z,t.w=this.w,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t.z=-this.z,t.w=-this.w,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e)&&(!(Math.abs(this.y-t.y)>e)&&(!(Math.abs(this.z-t.z)>e)&&!(Math.abs(this.w-t.w)>e)))}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y,s=this.z,i=this.w;return t*t+e*e+s*s+i*i}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}subtract(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e.z*=t,e.w*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x*=0,t.y*=0,t.z*=0,t.w*=0,t):(e=1/e,t.x*=e,t.y*=e,t.z*=e,t.w*=e,t)}multiplyMat4(t,e){return e||(e=this),t.multiplyVec4(this,e)}static mix(t,e,s,i){return i||(i=new c),i.x=t.x+s*(e.x-t.x),i.y=t.y+s*(e.y-t.y),i.z=t.z+s*(e.z-t.z),i.w=t.w+s*(e.w-t.w),i}static sum(t,e,s){return s||(s=new c),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s.w=t.w+e.w,s}static difference(t,e,s){return s||(s=new c),s.x=t.x-e.x,s.y=t.y-e.y,s.z=t.z-e.z,s.w=t.w-e.w,s}static product(t,e,s){return s||(s=new c),s.x=t.x*e.x,s.y=t.y*e.y,s.z=t.z*e.z,s.w=t.w*e.w,s}static quotient(t,e,s){return s||(s=new c),s.x=t.x/e.x,s.y=t.y/e.y,s.z=t.z/e.z,s.w=t.w/e.w,s}}c.zero=new c([0,0,0,1]),c.one=new c([1,1,1,1]);class v{constructor(t){this.values=new Float32Array(16),void 0!==t&&this.init(t)}at(t){return this.values[t]}init(t){for(let e=0;e<16;e++)this.values[e]=t[e];return this}reset(){for(let t=0;t<16;t++)this.values[t]=0}copy(t){t||(t=new v);for(let e=0;e<16;e++)t.values[e]=this.values[e];return t}all(){const t=[];for(let e=0;e<16;e++)t[e]=this.values[e];return t}row(t){return[this.values[4*t+0],this.values[4*t+1],this.values[4*t+2],this.values[4*t+3]]}col(t){return[this.values[t],this.values[t+4],this.values[t+8],this.values[t+12]]}equals(t,e=1e-5){for(let s=0;s<16;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}determinant(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],a=this.values[5],h=this.values[6],r=this.values[7],o=this.values[8],u=this.values[9],l=this.values[10],c=this.values[11],v=this.values[12],d=this.values[13],m=this.values[14],y=this.values[15];return(t*a-e*n)*(l*y-c*m)-(t*h-s*n)*(u*y-c*d)+(t*r-i*n)*(u*m-l*d)+(e*h-s*a)*(o*y-c*v)-(e*r-i*a)*(o*m-l*v)+(s*r-i*h)*(o*d-u*v)}setIdentity(){return this.values[0]=1,this.values[1]=0,this.values[2]=0,this.values[3]=0,this.values[4]=0,this.values[5]=1,this.values[6]=0,this.values[7]=0,this.values[8]=0,this.values[9]=0,this.values[10]=1,this.values[11]=0,this.values[12]=0,this.values[13]=0,this.values[14]=0,this.values[15]=1,this}transpose(){const t=this.values[1],e=this.values[2],s=this.values[3],i=this.values[6],n=this.values[7],a=this.values[11];return this.values[1]=this.values[4],this.values[2]=this.values[8],this.values[3]=this.values[12],this.values[4]=t,this.values[6]=this.values[9],this.values[7]=this.values[13],this.values[8]=e,this.values[9]=i,this.values[11]=this.values[14],this.values[12]=s,this.values[13]=n,this.values[14]=a,this}inverse(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],a=this.values[5],h=this.values[6],r=this.values[7],o=this.values[8],u=this.values[9],l=this.values[10],c=this.values[11],v=this.values[12],d=this.values[13],m=this.values[14],y=this.values[15],p=t*a-e*n,x=t*h-s*n,w=t*r-i*n,f=e*h-s*a,g=e*r-i*a,b=s*r-i*h,z=o*d-u*v,k=o*m-l*v,I=o*y-c*v,C=u*m-l*d,E=u*y-c*d,M=l*y-c*m;let T=p*M-x*E+w*C+f*I-g*k+b*z;return T?(T=1/T,this.values[0]=(a*M-h*E+r*C)*T,this.values[1]=(-e*M+s*E-i*C)*T,this.values[2]=(d*b-m*g+y*f)*T,this.values[3]=(-u*b+l*g-c*f)*T,this.values[4]=(-n*M+h*I-r*k)*T,this.values[5]=(t*M-s*I+i*k)*T,this.values[6]=(-v*b+m*w-y*x)*T,this.values[7]=(o*b-l*w+c*x)*T,this.values[8]=(n*E-a*I+r*z)*T,this.values[9]=(-t*E+e*I-i*z)*T,this.values[10]=(v*g-d*w+y*p)*T,this.values[11]=(-o*g+u*w-c*p)*T,this.values[12]=(-n*C+a*k-h*z)*T,this.values[13]=(t*C-e*k+s*z)*T,this.values[14]=(-v*f+d*x-m*p)*T,this.values[15]=(o*f-u*x+l*p)*T,this):null}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],n=this.values[3],a=this.values[4],h=this.values[5],r=this.values[6],o=this.values[7],u=this.values[8],l=this.values[9],c=this.values[10],v=this.values[11],d=this.values[12],m=this.values[13],y=this.values[14],p=this.values[15];let x=t.at(0),w=t.at(1),f=t.at(2),g=t.at(3);return this.values[0]=x*e+w*a+f*u+g*d,this.values[1]=x*s+w*h+f*l+g*m,this.values[2]=x*i+w*r+f*c+g*y,this.values[3]=x*n+w*o+f*v+g*p,x=t.at(4),w=t.at(5),f=t.at(6),g=t.at(7),this.values[4]=x*e+w*a+f*u+g*d,this.values[5]=x*s+w*h+f*l+g*m,this.values[6]=x*i+w*r+f*c+g*y,this.values[7]=x*n+w*o+f*v+g*p,x=t.at(8),w=t.at(9),f=t.at(10),g=t.at(11),this.values[8]=x*e+w*a+f*u+g*d,this.values[9]=x*s+w*h+f*l+g*m,this.values[10]=x*i+w*r+f*c+g*y,this.values[11]=x*n+w*o+f*v+g*p,x=t.at(12),w=t.at(13),f=t.at(14),g=t.at(15),this.values[12]=x*e+w*a+f*u+g*d,this.values[13]=x*s+w*h+f*l+g*m,this.values[14]=x*i+w*r+f*c+g*y,this.values[15]=x*n+w*o+f*v+g*p,this}multiplyVec3(t){const e=t.x,s=t.y,i=t.z;return new p([this.values[0]*e+this.values[4]*s+this.values[8]*i+this.values[12],this.values[1]*e+this.values[5]*s+this.values[9]*i+this.values[13],this.values[2]*e+this.values[6]*s+this.values[10]*i+this.values[14]])}multiplyVec4(t,e){e||(e=new c);const s=t.x,i=t.y,n=t.z,a=t.w;return e.x=this.values[0]*s+this.values[4]*i+this.values[8]*n+this.values[12]*a,e.y=this.values[1]*s+this.values[5]*i+this.values[9]*n+this.values[13]*a,e.z=this.values[2]*s+this.values[6]*i+this.values[10]*n+this.values[14]*a,e.w=this.values[3]*s+this.values[7]*i+this.values[11]*n+this.values[15]*a,e}toMat3(){return new m([this.values[0],this.values[1],this.values[2],this.values[4],this.values[5],this.values[6],this.values[8],this.values[9],this.values[10]])}toInverseMat3(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[4],n=this.values[5],a=this.values[6],h=this.values[8],r=this.values[9],o=this.values[10],u=o*n-a*r,l=-o*i+a*h,c=r*i-n*h;let v=t*u+e*l+s*c;return v?(v=1/v,new m([u*v,(-o*e+s*r)*v,(a*e-s*n)*v,l*v,(o*t-s*h)*v,(-a*t+s*i)*v,c*v,(-r*t+e*h)*v,(n*t-e*i)*v])):null}translate(t){const e=t.x,s=t.y,i=t.z;return this.values[12]+=this.values[0]*e+this.values[4]*s+this.values[8]*i,this.values[13]+=this.values[1]*e+this.values[5]*s+this.values[9]*i,this.values[14]+=this.values[2]*e+this.values[6]*s+this.values[10]*i,this.values[15]+=this.values[3]*e+this.values[7]*s+this.values[11]*i,this}scale(t){const e=t.x,s=t.y,i=t.z;return this.values[0]*=e,this.values[1]*=e,this.values[2]*=e,this.values[3]*=e,this.values[4]*=s,this.values[5]*=s,this.values[6]*=s,this.values[7]*=s,this.values[8]*=i,this.values[9]*=i,this.values[10]*=i,this.values[11]*=i,this}rotate(t,e){let s=e.x,i=e.y,n=e.z,a=Math.sqrt(s*s+i*i+n*n);if(!a)return null;1!==a&&(a=1/a,s*=a,i*=a,n*=a);const h=Math.sin(t),r=Math.cos(t),o=1-r,u=this.values[0],l=this.values[1],c=this.values[2],v=this.values[3],d=this.values[4],m=this.values[5],y=this.values[6],p=this.values[7],x=this.values[8],w=this.values[9],f=this.values[10],g=this.values[11],b=s*s*o+r,z=i*s*o+n*h,k=n*s*o-i*h,I=s*i*o-n*h,C=i*i*o+r,E=n*i*o+s*h,M=s*n*o+i*h,T=i*n*o-s*h,D=n*n*o+r;return this.values[0]=u*b+d*z+x*k,this.values[1]=l*b+m*z+w*k,this.values[2]=c*b+y*z+f*k,this.values[3]=v*b+p*z+g*k,this.values[4]=u*I+d*C+x*E,this.values[5]=l*I+m*C+w*E,this.values[6]=c*I+y*C+f*E,this.values[7]=v*I+p*C+g*E,this.values[8]=u*M+d*T+x*D,this.values[9]=l*M+m*T+w*D,this.values[10]=c*M+y*T+f*D,this.values[11]=v*M+p*T+g*D,this}static frustum(t,e,s,i,n,a){const h=e-t,r=i-s,o=a-n;return new v([2*n/h,0,0,0,0,2*n/r,0,0,(e+t)/h,(i+s)/r,-(a+n)/o,-1,0,0,-a*n*2/o,0])}static perspective(t,e,s,i){const n=s*Math.tan(t*Math.PI/360),a=n*e;return v.frustum(-a,a,-n,n,s,i)}static orthographic(t,e,s,i,n,a){const h=e-t,r=i-s,o=a-n;return new v([2/h,0,0,0,0,2/r,0,0,0,0,-2/o,0,-(t+e)/h,-(i+s)/r,-(a+n)/o,1])}static lookAt(t,e,s=p.up){if(t.equals(e))return this.identity;const i=p.difference(t,e).normalize(),n=p.cross(s,i).normalize(),a=p.cross(i,n).normalize();return new v([n.x,a.x,i.x,0,n.y,a.y,i.y,0,n.z,a.z,i.z,0,-p.dot(n,t),-p.dot(a,t),-p.dot(i,t),1])}static product(t,e,s){const i=t.at(0),n=t.at(1),a=t.at(2),h=t.at(3),r=t.at(4),o=t.at(5),u=t.at(6),l=t.at(7),c=t.at(8),d=t.at(9),m=t.at(10),y=t.at(11),p=t.at(12),x=t.at(13),w=t.at(14),f=t.at(15),g=e.at(0),b=e.at(1),z=e.at(2),k=e.at(3),I=e.at(4),C=e.at(5),E=e.at(6),M=e.at(7),T=e.at(8),D=e.at(9),A=e.at(10),N=e.at(11),S=e.at(12),R=e.at(13),V=e.at(14),L=e.at(15);return s?(s.init([g*i+b*r+z*c+k*p,g*n+b*o+z*d+k*x,g*a+b*u+z*m+k*w,g*h+b*l+z*y+k*f,I*i+C*r+E*c+M*p,I*n+C*o+E*d+M*x,I*a+C*u+E*m+M*w,I*h+C*l+E*y+M*f,T*i+D*r+A*c+N*p,T*n+D*o+A*d+N*x,T*a+D*u+A*m+N*w,T*h+D*l+A*y+N*f,S*i+R*r+V*c+L*p,S*n+R*o+V*d+L*x,S*a+R*u+V*m+L*w,S*h+R*l+V*y+L*f]),s):new v([g*i+b*r+z*c+k*p,g*n+b*o+z*d+k*x,g*a+b*u+z*m+k*w,g*h+b*l+z*y+k*f,I*i+C*r+E*c+M*p,I*n+C*o+E*d+M*x,I*a+C*u+E*m+M*w,I*h+C*l+E*y+M*f,T*i+D*r+A*c+N*p,T*n+D*o+A*d+N*x,T*a+D*u+A*m+N*w,T*h+D*l+A*y+N*f,S*i+R*r+V*c+L*p,S*n+R*o+V*d+L*x,S*a+R*u+V*m+L*w,S*h+R*l+V*y+L*f])}}v.identity=(new v).setIdentity();class d{constructor(t){this.values=new Float32Array(2),void 0!==t&&(this.xy=t)}get x(){return this.values[0]}get y(){return this.values[1]}get xy(){return[this.values[0],this.values[1]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}at(t){return this.values[t]}reset(){this.x=0,this.y=0}copy(t){return t||(t=new d),t.x=this.x,t.y=this.y,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e)&&!(Math.abs(this.y-t.y)>e)}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y;return t*t+e*e}add(t){return this.x+=t.x,this.y+=t.y,this}subtract(t){return this.x-=t.x,this.y-=t.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}divide(t){return this.x/=t.x,this.y/=t.y,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x=0,t.y=0,t):(e=1/e,t.x*=e,t.y*=e,t)}multiplyMat2(t,e){return e||(e=this),t.multiplyVec2(this,e)}multiplyMat3(t,e){return e||(e=this),t.multiplyVec2(this,e)}static cross(t,e,s){s||(s=new p);const i=t.x,n=t.y,a=e.x,h=i*e.y-n*a;return s.x=0,s.y=0,s.z=h,s}static dot(t,e){return t.x*e.x+t.y*e.y}static distance(t,e){return Math.sqrt(this.squaredDistance(t,e))}static squaredDistance(t,e){const s=e.x-t.x,i=e.y-t.y;return s*s+i*i}static direction(t,e,s){s||(s=new d);const i=t.x-e.x,n=t.y-e.y;let a=Math.sqrt(i*i+n*n);return 0===a?(s.x=0,s.y=0,s):(a=1/a,s.x=i*a,s.y=n*a,s)}static mix(t,e,s,i){i||(i=new d);const n=t.x,a=t.y,h=e.x,r=e.y;return i.x=n+s*(h-n),i.y=a+s*(r-a),i}static sum(t,e,s){return s||(s=new d),s.x=t.x+e.x,s.y=t.y+e.y,s}static difference(t,e,s){return s||(s=new d),s.x=t.x-e.x,s.y=t.y-e.y,s}static product(t,e,s){return s||(s=new d),s.x=t.x*e.x,s.y=t.y*e.y,s}static quotient(t,e,s){return s||(s=new d),s.x=t.x/e.x,s.y=t.y/e.y,s}}d.zero=new d([0,0]),d.one=new d([1,1]);class m{constructor(t){this.values=new Float32Array(9),void 0!==t&&this.init(t)}at(t){return this.values[t]}init(t){for(let e=0;e<9;e++)this.values[e]=t[e];return this}reset(){for(let t=0;t<9;t++)this.values[t]=0}copy(t){t||(t=new m);for(let e=0;e<9;e++)t.values[e]=this.values[e];return t}all(){const t=[];for(let e=0;e<9;e++)t[e]=this.values[e];return t}row(t){return[this.values[3*t+0],this.values[3*t+1],this.values[3*t+2]]}col(t){return[this.values[t],this.values[t+3],this.values[t+6]]}equals(t,e=1e-5){for(let s=0;s<9;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}determinant(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],a=this.values[5],h=this.values[6],r=this.values[7],o=this.values[8];return t*(o*n-a*r)+e*(-o*i+a*h)+s*(r*i-n*h)}setIdentity(){return this.values[0]=1,this.values[1]=0,this.values[2]=0,this.values[3]=0,this.values[4]=1,this.values[5]=0,this.values[6]=0,this.values[7]=0,this.values[8]=1,this}transpose(){const t=this.values[1],e=this.values[2],s=this.values[5];return this.values[1]=this.values[3],this.values[2]=this.values[6],this.values[3]=t,this.values[5]=this.values[7],this.values[6]=e,this.values[7]=s,this}inverse(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],a=this.values[5],h=this.values[6],r=this.values[7],o=this.values[8],u=o*n-a*r,l=-o*i+a*h,c=r*i-n*h;let v=t*u+e*l+s*c;return v?(v=1/v,this.values[0]=u*v,this.values[1]=(-o*e+s*r)*v,this.values[2]=(a*e-s*n)*v,this.values[3]=l*v,this.values[4]=(o*t-s*h)*v,this.values[5]=(-a*t+s*i)*v,this.values[6]=c*v,this.values[7]=(-r*t+e*h)*v,this.values[8]=(n*t-e*i)*v,this):null}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],n=this.values[3],a=this.values[4],h=this.values[5],r=this.values[6],o=this.values[7],u=this.values[8],l=t.at(0),c=t.at(1),v=t.at(2),d=t.at(3),m=t.at(4),y=t.at(5),p=t.at(6),x=t.at(7),w=t.at(8);return this.values[0]=l*e+c*n+v*r,this.values[1]=l*s+c*a+v*o,this.values[2]=l*i+c*h+v*u,this.values[3]=d*e+m*n+y*r,this.values[4]=d*s+m*a+y*o,this.values[5]=d*i+m*h+y*u,this.values[6]=p*e+x*n+w*r,this.values[7]=p*s+x*a+w*o,this.values[8]=p*i+x*h+w*u,this}multiplyVec2(t,e){const s=t.x,i=t.y;return e?(e.xy=[s*this.values[0]+i*this.values[3]+this.values[6],s*this.values[1]+i*this.values[4]+this.values[7]],e):new d([s*this.values[0]+i*this.values[3]+this.values[6],s*this.values[1]+i*this.values[4]+this.values[7]])}multiplyVec3(t,e){const s=t.x,i=t.y,n=t.z;return e?(e.xyz=[s*this.values[0]+i*this.values[3]+n*this.values[6],s*this.values[1]+i*this.values[4]+n*this.values[7],s*this.values[2]+i*this.values[5]+n*this.values[8]],e):new p([s*this.values[0]+i*this.values[3]+n*this.values[6],s*this.values[1]+i*this.values[4]+n*this.values[7],s*this.values[2]+i*this.values[5]+n*this.values[8]])}toMat4(t){return t?(t.init([this.values[0],this.values[1],this.values[2],0,this.values[3],this.values[4],this.values[5],0,this.values[6],this.values[7],this.values[8],0,0,0,0,1]),t):new v([this.values[0],this.values[1],this.values[2],0,this.values[3],this.values[4],this.values[5],0,this.values[6],this.values[7],this.values[8],0,0,0,0,1])}toQuat(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],n=this.values[4],a=this.values[5],h=this.values[6],r=this.values[7],o=this.values[8],u=t-n-o,l=n-t-o,c=o-t-n;let v=0,d=t+n+o;u>d&&(d=u,v=1),l>d&&(d=l,v=2),c>d&&(d=c,v=3);const m=.5*Math.sqrt(d+1),p=.25/m,x=new y;switch(v){case 0:x.w=m,x.x=(a-r)*p,x.y=(h-s)*p,x.z=(e-i)*p;break;case 1:x.w=(a-r)*p,x.x=m,x.y=(e+i)*p,x.z=(h+s)*p;break;case 2:x.w=(h-s)*p,x.x=(e+i)*p,x.y=m,x.z=(a+r)*p;break;case 3:x.w=(e-i)*p,x.x=(h+s)*p,x.y=(a+r)*p,x.z=m}return x}rotate(t,e){let s=e.x,i=e.y,n=e.z,a=Math.sqrt(s*s+i*i+n*n);if(!a)return null;1!==a&&(a=1/a,s*=a,i*=a,n*=a);const h=Math.sin(t),r=Math.cos(t),o=1-r,u=this.values[0],l=this.values[1],c=this.values[2],v=this.values[4],d=this.values[5],m=this.values[6],y=this.values[8],p=this.values[9],x=this.values[10],w=s*s*o+r,f=i*s*o+n*h,g=n*s*o-i*h,b=s*i*o-n*h,z=i*i*o+r,k=n*i*o+s*h,I=s*n*o+i*h,C=i*n*o-s*h,E=n*n*o+r;return this.values[0]=u*w+v*f+y*g,this.values[1]=l*w+d*f+p*g,this.values[2]=c*w+m*f+x*g,this.values[3]=u*b+v*z+y*k,this.values[4]=l*b+d*z+p*k,this.values[5]=c*b+m*z+x*k,this.values[6]=u*I+v*C+y*E,this.values[7]=l*I+d*C+p*E,this.values[8]=c*I+m*C+x*E,this}static product(t,e,s){const i=t.at(0),n=t.at(1),a=t.at(2),h=t.at(3),r=t.at(4),o=t.at(5),u=t.at(6),l=t.at(7),c=t.at(8),v=e.at(0),d=e.at(1),y=e.at(2),p=e.at(3),x=e.at(4),w=e.at(5),f=e.at(6),g=e.at(7),b=e.at(8);return s?(s.init([v*i+d*h+y*u,v*n+d*r+y*l,v*a+d*o+y*c,p*i+x*h+w*u,p*n+x*r+w*l,p*a+x*o+w*c,f*i+g*h+b*u,f*n+g*r+b*l,f*a+g*o+b*c]),s):new m([v*i+d*h+y*u,v*n+d*r+y*l,v*a+d*o+y*c,p*i+x*h+w*u,p*n+x*r+w*l,p*a+x*o+w*c,f*i+g*h+b*u,f*n+g*r+b*l,f*a+g*o+b*c])}}m.identity=(new m).setIdentity();class y{constructor(t){this.values=new Float32Array(4),void 0!==t&&(this.xyzw=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get w(){return this.values[3]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}get xyzw(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set w(t){this.values[3]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set xyzw(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}at(t){return this.values[t]}reset(){for(let t=0;t<4;t++)this.values[t]=0}copy(t){t||(t=new y);for(let e=0;e<4;e++)t.values[e]=this.values[e];return t}roll(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.atan2(2*(t*e+i*s),i*i+t*t-e*e-s*s)}pitch(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.atan2(2*(e*s+i*t),i*i-t*t-e*e+s*s)}yaw(){return Math.asin(2*(this.x*this.z-this.w*this.y))}equals(t,e=1e-5){for(let s=0;s<4;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}setIdentity(){return this.x=0,this.y=0,this.z=0,this.w=1,this}calculateW(){const t=this.x,e=this.y,s=this.z;return this.w=-Math.sqrt(Math.abs(1-t*t-e*e-s*s)),this}inverse(){const t=y.dot(this,this);if(!t)return this.xyzw=[0,0,0,0],this;const e=t?1/t:0;return this.x*=-e,this.y*=-e,this.z*=-e,this.w*=e,this}conjugate(){return this.values[0]*=-1,this.values[1]*=-1,this.values[2]*=-1,this}length(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.sqrt(t*t+e*e+s*s+i*i)}normalize(t){t||(t=this);const e=this.x,s=this.y,i=this.z,n=this.w;let a=Math.sqrt(e*e+s*s+i*i+n*n);return a?(a=1/a,t.x=e*a,t.y=s*a,t.z=i*a,t.w=n*a,t):(t.x=0,t.y=0,t.z=0,t.w=0,t)}add(t){for(let e=0;e<4;e++)this.values[e]+=t.at(e);return this}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],n=this.values[3],a=t.x,h=t.y,r=t.z,o=t.w;return this.x=e*o+n*a+s*r-i*h,this.y=s*o+n*h+i*a-e*r,this.z=i*o+n*r+e*h-s*a,this.w=n*o-e*a-s*h-i*r,this}multiplyVec3(t,e){e||(e=new p);const s=t.x,i=t.y,n=t.z,a=this.x,h=this.y,r=this.z,o=this.w,u=o*s+h*n-r*i,l=o*i+r*s-a*n,c=o*n+a*i-h*s,v=-a*s-h*i-r*n;return e.x=u*o+v*-a+l*-r-c*-h,e.y=l*o+v*-h+c*-a-u*-r,e.z=c*o+v*-r+u*-h-l*-a,e}toMat3(t){t||(t=new m);const e=this.x,s=this.y,i=this.z,n=this.w,a=e+e,h=s+s,r=i+i,o=e*a,u=e*h,l=e*r,c=s*h,v=s*r,d=i*r,y=n*a,p=n*h,x=n*r;return t.init([1-(c+d),u+x,l-p,u-x,1-(o+d),v+y,l+p,v-y,1-(o+c)]),t}toMat4(t){t||(t=new v);const e=this.x,s=this.y,i=this.z,n=this.w,a=e+e,h=s+s,r=i+i,o=e*a,u=e*h,l=e*r,c=s*h,d=s*r,m=i*r,y=n*a,p=n*h,x=n*r;return t.init([1-(c+m),u+x,l-p,0,u-x,1-(o+m),d+y,0,l+p,d-y,1-(o+c),0,0,0,0,1]),t}static dot(t,e){return t.x*e.x+t.y*e.y+t.z*e.z+t.w*e.w}static sum(t,e,s){return s||(s=new y),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s.w=t.w+e.w,s}static product(t,e,s){s||(s=new y);const i=t.x,n=t.y,a=t.z,h=t.w,r=e.x,o=e.y,u=e.z,l=e.w;return s.x=i*l+h*r+n*u-a*o,s.y=n*l+h*o+a*r-i*u,s.z=a*l+h*u+i*o-n*r,s.w=h*l-i*r-n*o-a*u,s}static cross(t,e,s){s||(s=new y);const i=t.x,n=t.y,a=t.z,h=t.w,r=e.x,o=e.y,u=e.z,l=e.w;return s.x=h*u+a*l+i*o-n*r,s.y=h*l-i*r-n*o-a*u,s.z=h*r+i*l+n*u-a*o,s.w=h*o+n*l+a*r-i*u,s}static shortMix(t,e,s,i){if(i||(i=new y),s<=0)return i.xyzw=t.xyzw,i;if(s>=1)return i.xyzw=e.xyzw,i;let n=y.dot(t,e);const a=e.copy();let h,r;if(n<0&&(a.inverse(),n=-n),n>.9999)h=1-s,r=0+s;else{const t=Math.sqrt(1-n*n),e=Math.atan2(t,n),i=1/t;h=Math.sin((1-s)*e)*i,r=Math.sin((0+s)*e)*i}return i.x=h*t.x+r*a.x,i.y=h*t.y+r*a.y,i.z=h*t.z+r*a.z,i.w=h*t.w+r*a.w,i}static mix(t,e,s,i){i||(i=new y);const n=t.x*e.x+t.y*e.y+t.z*e.z+t.w*e.w;if(Math.abs(n)>=1)return i.xyzw=t.xyzw,i;const a=Math.acos(n),h=Math.sqrt(1-n*n);if(Math.abs(h)<.001)return i.x=.5*t.x+.5*e.x,i.y=.5*t.y+.5*e.y,i.z=.5*t.z+.5*e.z,i.w=.5*t.w+.5*e.w,i;const r=Math.sin((1-s)*a)/h,o=Math.sin(s*a)/h;return i.x=t.x*r+e.x*o,i.y=t.y*r+e.y*o,i.z=t.z*r+e.z*o,i.w=t.w*r+e.w*o,i}static fromAxisAngle(t,e,s){s||(s=new y),e*=.5;const i=Math.sin(e);return s.x=t.x*i,s.y=t.y*i,s.z=t.z*i,s.w=Math.cos(e),s}}y.identity=(new y).setIdentity();class p{constructor(t){this.values=new Float32Array(3),void 0!==t&&(this.xyz=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}at(t){return this.values[t]}reset(){this.x=0,this.y=0,this.z=0}copy(t){return t||(t=new p),t.x=this.x,t.y=this.y,t.z=this.z,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t.z=-this.z,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e)&&(!(Math.abs(this.y-t.y)>e)&&!(Math.abs(this.z-t.z)>e))}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y,s=this.z;return t*t+e*e+s*s}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}subtract(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e.z*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x=0,t.y=0,t.z=0,t):(e=1/e,t.x*=e,t.y*=e,t.z*=e,t)}multiplyByMat3(t,e){return e||(e=this),t.multiplyVec3(this,e)}multiplyByQuat(t,e){return e||(e=this),t.multiplyVec3(this,e)}toQuat(t){t||(t=new y);const e=new p,s=new p;return e.x=Math.cos(.5*this.x),s.x=Math.sin(.5*this.x),e.y=Math.cos(.5*this.y),s.y=Math.sin(.5*this.y),e.z=Math.cos(.5*this.z),s.z=Math.sin(.5*this.z),t.x=s.x*e.y*e.z-e.x*s.y*s.z,t.y=e.x*s.y*e.z+s.x*e.y*s.z,t.z=e.x*e.y*s.z-s.x*s.y*e.z,t.w=e.x*e.y*e.z+s.x*s.y*s.z,t}static cross(t,e,s){s||(s=new p);const i=t.x,n=t.y,a=t.z,h=e.x,r=e.y,o=e.z;return s.x=n*o-a*r,s.y=a*h-i*o,s.z=i*r-n*h,s}static dot(t,e){const s=t.x,i=t.y,n=t.z;return s*e.x+i*e.y+n*e.z}static distance(t,e){e.x,t.x,e.y,t.y,e.z,t.z;return Math.sqrt(this.squaredDistance(t,e))}static squaredDistance(t,e){const s=e.x-t.x,i=e.y-t.y,n=e.z-t.z;return s*s+i*i+n*n}static direction(t,e,s){s||(s=new p);const i=t.x-e.x,n=t.y-e.y,a=t.z-e.z;let h=Math.sqrt(i*i+n*n+a*a);return 0===h?(s.x=0,s.y=0,s.z=0,s):(h=1/h,s.x=i*h,s.y=n*h,s.z=a*h,s)}static mix(t,e,s,i){return i||(i=new p),i.x=t.x+s*(e.x-t.x),i.y=t.y+s*(e.y-t.y),i.z=t.z+s*(e.z-t.z),i}static sum(t,e,s){return s||(s=new p),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s}static difference(t,e,s){return s||(s=new p),s.x=t.x-e.x,s.y=t.y-e.y,s.z=t.z-e.z,s}static product(t,e,s){return s||(s=new p),s.x=t.x*e.x,s.y=t.y*e.y,s.z=t.z*e.z,s}static quotient(t,e,s){return s||(s=new p),s.x=t.x/e.x,s.y=t.y/e.y,s.z=t.z/e.z,s}}p.zero=new p([0,0,0]),p.one=new p([1,1,1]),p.up=new p([0,1,0]),p.right=new p([1,0,0]),p.forward=new p([0,0,1]);class x extends(l()){constructor(t){super(),this.context=t,this.scene=this.context.getContext().createGain(),this.listener=this.context.getContext().listener,this.init()}init(){}createSource(){const t=this.context.getContext().createPanner();return t.panningModel="HRTF",t.distanceModel="linear",t.maxDistance=20,t.refDistance=2,t.connect(this.scene),t}getOutput(){return this.scene}getInput(){return this.scene}setListenerPosition(t,e,s){this.listener.setPosition(t,e,s)}setListenerOrientation(t,e){let s=new p([t.x,t.y,t.z]),i=s.copy();p.cross(i,new p([e.x,e.y,e.z]),i),p.cross(i,s,i),s.normalize(),i.normalize(),this.listener.setOrientation(s.x,s.y,s.z,i.x,i.y,i.z)}}class w{constructor(t,e,s,i){this.effects=[],this.context=t,this.graph=e,this.inputNode=s,this.outputNode=i,this.updateConnections()}applyEffect(t){this.effects.push(t),this.updateConnections()}removeEffect(t){this.effects.forEach((e=>{t===e&&e.disconnect()})),this.effects=this.effects.filter((e=>t!==e)),this.updateConnections()}updateConnections(){if(0==this.effects.length)return void this.inputNode.connect(this.outputNode);let t=null,e=null;this.effects.forEach((s=>{t=s,e?t.connectInput(e.getOutput()):t.connectInput(this.inputNode),e=t})),t&&t.connectOutput(this.outputNode)}}class f{constructor(t,e,s=!1){this.scene=t,this.context=e,this.swapChannels=s,this.init()}init(){this.effectsBus=this.context.createGain(),this.worldBus=this.context.createGain(),this.secondaryBus=this.context.createGain(),this.master=this.context.createGain(),this.scene.getOutput().connect(this.worldBus),this.worldBus.connect(this.effectsBus),this.effects=new w(this.context,this,this.effectsBus,this.master),this.secondaryBus.connect(this.master),this.swapChannels?(this.channelSplitter=this.context.getContext().createChannelSplitter(2),this.channelMerger=this.context.getContext().createChannelMerger(2),this.master.connect(this.channelSplitter),this.channelSplitter.connect(this.channelMerger,0,1),this.channelSplitter.connect(this.channelMerger,1,0),this.channelMerger.connect(this.context.getOutputDestination())):this.master.connect(this.context.getOutputDestination())}connectToMaster(t){t.connect(this.master)}connectToUI(t){t.connect(this.secondaryBus)}applyEffect(t){this.effects.applyEffect(t)}removeEffect(t){this.effects.removeEffect(t)}}var g;!function(t){t[t.WorldSource=0]="WorldSource",t[t.UISource=1]="UISource",t[t.MasterSource=2]="MasterSource"}(g||(g={}));class b{constructor(t,e,s,i=null,n=g.WorldSource){this.position={x:0,y:0,z:0},this.buffer=i,this.context=s,this.scene=e,this.graph=t,this.type=n,this.playbackRate=1,this.volume=1,this.init()}init(){this.gain=this.context.createGain(),this.stop=this.stop.bind(this)}getBuffer(){return this.buffer}setBuffer(t){this.buffer=t,this.playOnLoad&&(this.play(),this.playOnLoad=!1)}play(t=0,e=0,s=(this.buffer?this.buffer.duration:0)){this.playing&&this.node&&this.stop(),this.buffer?(this.node||(this.node=this.context.createBufferSource(),this.node.buffer=this.buffer,this.createConnections()),this.node&&(this.node.playbackRate.value=this.playbackRate,this.node.start(t,e,s),this.node.loop=this.looping,this.playing=!0,this.sceneNode&&this.sceneNode.setPosition(this.position.x,this.position.y,this.position.z),this.node.addEventListener("ended",this.stop))):this.playOnLoad=!0}setPosition(t,e,s){this.position={x:t,y:e,z:s},this.sceneNode&&this.sceneNode.setPosition(t,e,s)}setPlaybackRate(t){this.playbackRate=t,this.node&&(this.node.playbackRate.value=t)}getPlaybackRate(){return this.playbackRate}setVolume(t){this.volume=t,this.gain&&(this.gain.gain.value=t)}getVolume(){return this.volume}createConnections(){switch(this.type){case g.WorldSource:this.sceneNode||(this.sceneNode=this.scene.createSource()),this.node.connect(this.gain),this.gain.connect(this.sceneNode);break;case g.UISource:this.node.connect(this.gain),this.graph.connectToUI(this.gain);break;default:this.node.connect(this.gain),this.graph.connectToMaster(this.gain)}}stop(){this.playing=!1,this.node&&(this.node.removeEventListener("ended",this.stop),this.node.stop(),this.node.disconnect(),this.node=null,this.playing=!1,this.sceneNode&&(this.sceneNode.disconnect(),this.sceneNode=null))}destroy(){this.stop(),this.node=null,this.sceneNode=null,this.buffer=null,this.context=null,this.graph=null,this.scene=null}loop(t){this.looping=t,this.node&&(this.node.loop=t)}fadeOut(t){this.gain.gain.setValueAtTime(this.getVolume(),this.context.getContext().currentTime),this.node&&(this.gain.gain.exponentialRampToValueAtTime(1e-4,this.context.getContext().currentTime+t),setTimeout((()=>this.stop()),1e3*t))}fadeIn(t){this.gain.gain.setValueAtTime(1e-4,this.context.getContext().currentTime),this.node||this.play(),this.gain.gain.exponentialRampToValueAtTime(this.volume,this.context.getContext().currentTime+t)}}class z{constructor(t,e=null,s=null){this.name=t,this.data=e,this.decodedData=s}getData(){return this.data}setData(t){this.data=t}getDecodedData(){return this.decodedData}setDecodedData(t){this.decodedData=this.decodedData}getName(){return this.name}setName(t){this.name=t}}var k=function(t,e,s,i){return new(s||(s=Promise))((function(n,a){function h(t){try{o(i.next(t))}catch(t){a(t)}}function r(t){try{o(i.throw(t))}catch(t){a(t)}}function o(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}o((i=i.apply(t,e||[])).next())}))};class I{get(t){return k(this,void 0,void 0,(function*(){const e=yield fetch(t);return yield e.arrayBuffer()}))}}var C=function(t,e,s,i){return new(s||(s=Promise))((function(n,a){function h(t){try{o(i.next(t))}catch(t){a(t)}}function r(t){try{o(i.throw(t))}catch(t){a(t)}}function o(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}o((i=i.apply(t,e||[])).next())}))};class E extends(l()){constructor(t,e=new I,s=512){super(),this.loader=e,this.data={},this.maxData=s,this.context=t}get(t){return C(this,void 0,void 0,(function*(){if(this.data[t])return this.data[t].getDecodedData();{const e=yield this.loader.get(t),s=yield this.context.decodeAudioData(e),i=new z(t,e,s);Object.keys(this.data).length;return this.maxData,this.data[t]=i,i.getDecodedData()}}))}clear(){this.data={}}}class M extends class{constructor(t,e,s){this.graph=e,this.context=t,this.effectParams=s}connectOutput(t){this.effectNode.connect(t)}connectInput(t){this.inputNode=t,this.effectNode&&this.inputNode.connect(this.effectNode)}getOutput(){return this.effectNode}disconnect(){this.inputNode.disconnect(),this.effectNode.disconnect()}}{constructor(t,e,s){super(t,e,s),console.log("Creating convolver"),this.effectNode=this.context.getContext().createConvolver(),this.effectNode.buffer=this.effectParams.buffer}connectInput(t){this.channelSplitter=this.context.getContext().createChannelSplitter(2),this.channelMerger=this.context.getContext().createChannelMerger(2),this.channelSplitter.connect(this.channelMerger,0,0),this.channelSplitter.connect(this.channelMerger,1,0),this.channelSplitter.connect(this.channelMerger,0,1),this.channelSplitter.connect(this.channelMerger,1,1),t.connect(this.channelSplitter),this.channelMerger.connect(this.effectNode),this.inputNode=t}}class T{constructor(t,e,s,i,n=g.MasterSource){this.graph=t,this.scene=e,this.context=s,this.element=i,this.type=n,this.position={x:0,y:0,z:0},this.init()}init(){this.node=this.context.createMediaElementSource(this.element),this.gain=this.context.createGain(),this.createConnections(),this.element.addEventListener("canplay",(t=>{this.canPlay=!0,this.playOnAvailable&&this.play()}))}play(t=0,e=0,s=0){this.canPlay&&this.element.play(),this.playOnAvailable=!0}stop(){this.element.pause()}getVolume(){return this.element.volume}setVolume(t){this.element.volume=t}getPlaybackRate(){return this.element.playbackRate}setPlaybackRate(t){this.element.playbackRate=t}createConnections(){if(this.type===g.WorldSource)this.sceneNode||(this.sceneNode=this.scene.createSource()),this.node.connect(this.gain),this.gain.connect(this.sceneNode);else this.node.connect(this.gain),this.graph.connectToMaster(this.gain)}setPosition(t,e,s){this.position={x:t,y:e,z:s},this.sceneNode&&this.sceneNode.setPosition(t,e,s)}destroy(){this.stop(),this.element=null,this.graph=null,this.context=null,this.node=null,this.sceneNode=null,this.scene=null}loop(t){this.element.loop=!0}fadeIn(t){this.gain.gain.setValueAtTime(1e-4,this.context.getContext().currentTime),this.node||this.play(),this.gain.gain.exponentialRampToValueAtTime(this.getVolume(),this.context.getContext().currentTime+t)}fadeOut(t){this.gain.gain.setValueAtTime(this.getVolume(),this.context.getContext().currentTime),this.node&&(this.gain.gain.exponentialRampToValueAtTime(1e-4,this.context.getContext().currentTime+t),setTimeout((()=>this.stop()),1e3*t))}}var D=function(t,e,s,i){return new(s||(s=Promise))((function(n,a){function h(t){try{o(i.next(t))}catch(t){a(t)}}function r(t){try{o(i.throw(t))}catch(t){a(t)}}function o(t){var e;t.done?n(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}o((i=i.apply(t,e||[])).next())}))};class A{constructor(t=new I){this.loader=t,this.environmentImpulse=null,this.context=new o,this.scene=new x(this.context),this.graph=new f(this.scene,this.context,!1),this.dataPool=new E(this.context,this.loader)}load(t,e=g.WorldSource){return D(this,void 0,void 0,(function*(){const s=yield this.dataPool.get(t);return this.createSource(e,s)}))}loadImmediate(t,e=g.WorldSource){const s=new b(this.graph,this.scene,this.context,null,e);return this.dataPool.get(t).then((t=>{s.setBuffer(t)})),s}stream(t,e=g.MasterSource){const s=new Audio(t);s.crossOrigin="anonymous",s.volume=1;return new T(this.graph,this.scene,this.context,s,e)}createSource(t,e){return new b(this.graph,this.scene,this.context,e)}setEnvironmentImpulse(t){return D(this,void 0,void 0,(function*(){if(this.environmentImpulse&&this.graph.removeEffect(this.environmentImpulse),null===t)return;const e=yield this.dataPool.get(t);this.environmentImpulse=new M(this.context,this.graph,{buffer:e}),this.graph.applyEffect(this.environmentImpulse)}))}setListenerPosition(t,e,s){this.scene.setListenerPosition(t,e,s)}setListenerOrientation(t,e){this.scene.setListenerOrientation(t,e)}clearDataPool(){this.dataPool.clear()}}class N{constructor(){this.res=new A,this.ambience=null,this.music=null,this.ambienceVolume=1,this.musicVolume=1,this.sfxVolume=1,this.previousAmbience="",this.previousMusic=""}play(t){const e=this.res.loadImmediate(t);e.setVolume(this.sfxVolume),e.play()}async setAmbience(t){if(t!==this.previousAmbience){if(this.ambience){const t=this.ambience;this.ambience=null,setTimeout((()=>t.fadeOut(6)),1500),setTimeout((()=>t.destroy()),6e3)}t&&(this.previousAmbience=t,this.ambience=this.res.stream(t,0),this.ambience.setVolume(this.ambienceVolume),this.ambience.play(),this.ambience.loop(!0),this.ambience.fadeIn(3))}}setMusic(t){if(t!==this.previousMusic){if(this.music){const t=this.music;setTimeout((()=>t.fadeOut(2)),500),setTimeout((()=>t.destroy()),2e3)}t&&(this.previousMusic=t,this.music=this.res.stream(t,1),this.music.setVolume(this.musicVolume),this.music.play(),this.music.fadeIn(2))}}setImpulse(t){this.res.setEnvironmentImpulse(t)}setMusicVolume(t){this.musicVolume=t,this.music&&this.music.setVolume(t)}setAmbienceVolume(t){this.ambienceVolume=t,this.ambience&&this.ambience.setVolume(t)}setSFXVolume(t){this.sfxVolume=t}}class S{constructor(){this.tts=new h(new n),this.history=document.getElementById("output-area"),this.sound=new N}say(t){if(""===t)return;this.sound.play("assets/scroll.wav");const e=document.createElement("p");t.split("\n").forEach((t=>{e.appendChild(document.createTextNode(t)),e.appendChild(document.createElement("br"))})),this.history.appendChild(e)}play(t){this.sound.play(t)}setAmbience(t){return this.sound.setAmbience(t)}setMusic(t){return this.sound.setMusic(t)}setImpulse(t){this.sound.setImpulse(t)}}class R{constructor(t,e){this.handler=t,this.output=e,this.echoInput=!0,this.inputField=document.getElementById("input-area"),this.init()}setEcho(t){this.echoInput=t}init(){this.inputField.addEventListener("keydown",(t=>{if(13==t.which){const t=this.inputField.value;this.inputField.value="",this.echoInput&&this.output.say(`> ${t}`),this.handler.doCommand(t)}}))}}const V=[[["look","l"],function(t,e){if(1==t.length)e.examineRoom();else{const s=e.getRoom(e.player.currentRoom).getItems();let i=null;for(let e of s)if(e.name.includes(t[1])){i=e;break}if(!i){const s=e.player.getInventory();for(let e of s)if(e.name.includes(t[1])){i=e;break}}i?(e.output.say(`You look at ${i.name}.`),e.output.say(i.description)):e.output.say(`I could not find a ${t[1]}.`)}}],[["use","interact"],async function(t,e){const s=e.getRoom(e.player.currentRoom).getItems();let i=null;for(let e of s)if(e.name.includes(t[1])){i=e;break}if(!i){const s=e.player.getInventory();for(let e of s)if(e.name.includes(t[1])){i=e;break}}i?await i.onUse():e.output.say(`I could not find a ${t[1]}.`)}],[["take","get"],function(t,e){const s=e.getRoom(e.player.currentRoom),i=s.getItems();let n=null;for(let e of i)if(e.name.includes(t[1])){n=e;break}n?n.takeable?(s.removeItem(n.id),e.player.addItem(n.id),e.print(`You take ${n.name}.`),n.onTake()):e.print(`You can't take ${n.name}.`):e.print(`You can't find any ${t[1]}.`)}],[["drop","put"],function(t,e){const s=e.getRoom(e.player.currentRoom),i=e.player.getInventory();let n=null;for(let e of i)if(e.name.includes(t[1])){n=e;break}n?(e.player.removeItem(n.id),s.addItem(n.id),e.print(`You set ${n.name} down on the floor.`),n.onDrop()):e.print(`You're not carrying a ${t[1]}`)}],["echo",function(t,e){"on"!=t[1]&&"off"!=t[1]?e.print("Usage: echo "):(e.setInputEcho("on"==t[1]),e.print(`Command echo is now ${t[1]}.`))}],["save",function(t,e){e.print("Saving game..."),e.save()}],["load",function(t,e){e.print("Loading game..."),e.load()}],["volume",function(t,e){if(t.length<3)return e.print("Usage: volume <0-100>");const s=parseInt(t[2]);if(s>100||s<1)return e.print("No higher than 100 and no less than 1.");if("sfx"==t[1])e.output.sound.setSFXVolume(s/100);else if("music"==t[1])e.output.sound.setMusicVolume(s/100);else{if("ambience"!=t[1])return e.print("Invalid channel. Either ambience, sfx or music is allowed.");e.output.sound.setAmbienceVolume(s/100)}e.print(`${t[1]} volume set to ${s}%`)}],[["i","inv","inventory"],function(t,e){const s=e.player.getInventory();if(s.length<1)return e.print("You're not carrying anything.");let i="You are carrying ";s.forEach(((t,e)=>{ethis.commands.set(t,e))):this.commands.set(t,e)}addCommands(t){t.forEach((t=>{this.addCommand(t[0],t[1])}))}addDefaultCommands(){this.addCommands(V)}matchDirection(t){for(let e of L)if(e[0]==t)return e[1]}}class P{constructor(t){this.context=t}save(){const t={state:this.context.state.serialize(),itemLocations:this.serializeItemLocations(),player:{currentRoom:this.context.player.currentRoom,inventory:this.context.player.inventory},volumes:{music:this.context.output.sound.musicVolume,sfx:this.context.output.sound.sfxVolume,ambience:this.context.output.sound.ambienceVolume}};localStorage.setItem("save",JSON.stringify(t))}load(){const t=JSON.parse(localStorage.getItem("save"));this.context.state.deserialize(t.state),this.deserializeItemLocations(t.itemLocations),this.deserializePlayer(t.player),this.context.output.sound.setSFXVolume(t.volumes.sfx),this.context.output.sound.setMusicVolume(t.volumes.music),this.context.output.sound.setAmbienceVolume(t.volumes.ambience)}serializeItemLocations(){return this.context.rooms.map((t=>[t.id,t.objects]))}deserializeItemLocations(t){t.forEach((t=>{this.context.getRoom(t[0]).objects=t[1]}))}deserializePlayer(t){this.context.move(t.currentRoom),this.context.player.inventory=t.inventory}}class B{constructor(s=!0){this.newGame=s,this.player=new e,this.state=t,this.rooms=[],this.items=[],this.output=new S,this.commandHandler=new O(this),this.input=new R(this.commandHandler,this.output),this.visitedRooms=new Map,this.interval=null,this.Serialization=new P(this)}print(t){this.output.say(t)}async tell(t,e){for(let s of t)this.print(s),await this.wait(e)}init(s){this.rooms=s.rooms.map((t=>(t.context=this,t))),this.items=s.items.map((t=>(t.context=this,t))),this.state=s.state||t,this.commandHandler.addCommands(s.commands),this.player=new e,this.player.context=this,this.newGame?this.move(this.player.currentRoom):this.Serialization.load(),this.start()}advanceTick(){this.items.forEach((t=>t.onTick())),this.rooms.forEach((t=>t.onTick()))}start(){this.interval=setInterval((()=>this.advanceTick()),1e3)}stop(){clearInterval(this.interval),this.interval=null}examineRoom(){const t=this.getRoom(this.player.currentRoom);this.output.say(t.title),this.visitedRooms.get(this.player.currentRoom)||""==t.firstDescription?this.output.say(t.description):this.output.say(t.firstDescription),this.examineItems(),this.examineExits()}examineItems(){const t=this.getRoom(this.player.currentRoom).getItems();if(t.length<1)return;let e="You see ";t.forEach(((s,i)=>{i{ie.id==t))}getItem(t){return this.items.find((e=>e.id==t))}wait(t){return new Promise(((e,s)=>{setTimeout(e,t)}))}async move(t){const e=this.getRoom(this.player.currentRoom),s=this.getRoom(t);e.canExit()&&s.canEnter()&&(await e.onExit(),await s.onEnter(),this.player.currentRoom=t,this.examineRoom(),this.visitedRooms.set(t,!0))}enableCommandInput(t){this.commandHandler.enabled=t}setInputEcho(t){this.input.setEcho(t)}save(){this.Serialization.save()}load(){this.Serialization.load()}}class q{constructor(){this.id="room",this.title="A room",this.description="You see nothing special",this.firstDescription="",this.objects=[],this.exits=new Map,this.enterCallback=null,this.exitCallback=null,this.canEnterLogic=null,this.canExitLogic=null,this.tickCallback=null,this.context=null,this.music=null,this.ambience=null,this.impulse=null}async onEnter(){if(this.context.output.setMusic(this.music),this.context.output.setAmbience(this.ambience),this.context.output.setImpulse(this.impulse),this.enterCallback)return this.enterCallback(this.context)}async onExit(){if(this.exitCallback)return this.exitCallback(this.context)}canEnter(){return!this.canEnterLogic||this.canEnterLogic(this.context)}canExit(){return!this.canExitLogic||this.canExitLogic(this.context)}addExit(t,e){return this.exits.set(t,e),this}getExit(t){return this.exits.get(t)}addItem(t){this.objects.push(t)}removeItem(t){this.objects=this.objects.filter((e=>e!=t))}addEnterCallback(t){this.enterCallback=t.bind(this)}addExitCallback(t){this.exitCallback=t.bind(this)}addEnterLogic(t){this.canEnterLogic=t.bind(this)}addExitLogic(t){this.canExitLogic=t.bind(this)}addTickCallback(t){this.tickCallback=t.bind(this)}getItems(){return this.objects.map((t=>this.context.getItem(t)))}async onTick(){if(this.tickCallback)return this.tickCallback(this.context)}}class Y{constructor(){this.room=new q}withID(t){return this.room.id=t,this}withTitle(t){return this.room.title=t,this}withFirstDescription(t){return this.room.firstDescription=t,this}withDescription(t){return this.room.description=t,this}withExit(t,e){return this.room.addExit(t,e),this}withItem(t){return this.room.addItem(t),this}withEnterCallback(t){return this.room.addEnterCallback(t),this}withExitCallback(t){return this.room.addExitCallback(t),this}withEnterLogic(t){return this.room.addEnterLogic(t),this}withExitLogic(t){return this.room.addExitLogic(t),this}withTick(t){return this.room.addTickCallback(t),this}withMusic(t){return this.room.music=t,this}withAmbience(t){return this.room.ambience=t,this}withImpulse(t){return this.room.impulse=t,this}create(){return this.room}}const _=(new Y).withID("start").withTitle("A small spherical alcove").withFirstDescription("You find yourself in a small, spherical alcove. It feels cold and dark, save from a dim glow which seems to be eluminating the area from the north.\nThe surface appears to be unnaturally smooth, as if melted away using acidic means. It's warm to the touch.").withDescription("A spherical alcove. The smooth surface appears to be melted away using acidic means. There's a dim glow shining in from the north.").withExit("north","tunnel1").withEnterCallback((async function(t){if(t.state.get("start.awoken"))return;const{output:e,wait:s}=t;t.enableCommandInput(!1),await t.tell(["You slowly wake up.","you're not sure if you were ever conscious about waking up, but right now, you're clearly aware that you were previously asleep.","In fact, a lot of your thoughts seem foreign to you.","You're not sure how to feel about this.","God the headache...","OK, time to think about this.","Huh, something else you never did before.","Where are you?","You reach up and touch your head.","OK, that seems to be in order. Your antennae are still there, your mouth parts seem in tact...","Hmm. All this is strange.","No use sitting around. You get up and slowly examine your surroundings."],3e3),t.enableCommandInput(!0),t.state.set("start.awoken",!0)})).create(),U=(new Y).withID("tunnel1").withTitle("A long dark tunnel").withFirstDescription("You slowly make your way out of the little alcove, heading north into a smooth, tube-shaped tunnel.\nYou notice razor thin threads coming out of the ceiling, weaving and slithering along the length of the tunnel towards the north. Thery provide a dim glow, which must have been the light you saw before.").withDescription("A tube-shaped tunnel. Thin threads seem to exit the ceiling here, eminating a soft glow.").withExit("south","start").withExit("north","central1").create(),F=(new Y).withID("central1").withTitle("A large spherical chamber").withFirstDescription("You exit the tunnel into a large, spherical chamber.\nThere are many more threads across the walls and ceiling here, the glow enveloping you fully in its unnatural light.\nThe chamber appears to be large, able to fit hundreds of you inside.\nTo the northeast, northwest, southeast and southwest you notice large statues representing ants. Threads seem to lead right into them.").withDescription("A large, spherical chamber. Glowing threads criss-cross the walls and ceiling. Around you, statues of ants.").withExit("northwest","statue1").withExit("northeast","statue2").withExit("southwest","statue3").withExit("southeast","statue4").withExit("south","tunnel1").create(),$=(new Y).withID("statue1").withTitle("The northwestern part of the central chamber").withFirstDescription("You walk over to the northwestern part of the central chamber.\n It is almost entirely taken up by a huge ant statue. One of its six legs are extended outwards, attached to which is a small, round device.").withDescription("").withExit("southeast","central1").withItem("statue1").create(),j=(new Y).withID("statue2").withTitle("The northeastern part of the central chamber").withFirstDescription("You walk over to the northeastern part of the central chamber.\n It is almost entirely taken up by a huge ant statue. Two of its six legs are extended outwards, attached to which is a large, rectangular device.").withDescription("").withExit("southwest","central1").withItem("statue2").create(),G=(new Y).withID("statue3").withTitle("The southwestern part of the central chamber").withFirstDescription("You walk over to the southwestern part of the central chamber.\n It is almost entirely taken up by a huge ant statue. Three of its six legs are extended outwards, attached to which is a round stone tablet.").withDescription("").withExit("northeast","central1").withItem("statue3").create();class W{constructor(){this.id="item",this.name="An item",this.description="You see nothing special about this item",this.usable=!0,this.takeable=!0,this.useCallback=null,this.takeCallback=null,this.dropCallback=null,this.tickCallback=null,this.context=null}async onUse(){if(this.useCallback)return this.useCallback(this.context)}async onTake(){if(this.takeCallback)return this.takeCallback(this.context)}async onDrop(){if(this.dropCallback)return this.dropCallback(this.context)}async onTick(){if(this.tickCallback)return this.tickCallback(this.context)}addUseCallback(t){this.useCallback=t.bind(this)}addTakeCallback(t){this.takeCallback=t.bind(this)}addDropCallback(t){this.dropCallback=t.bind(this)}addTickCallback(t){this.tickCallback=t.bind(this)}}class H{constructor(){this.item=new W}withID(t){return this.item.id=t,this}withName(t){return this.item.name=t,this}withDescription(t){return this.item.description=t,this}isUsable(t){return this.item.usable=t,this}isTakeable(t){return this.item.takeable=t,this}withUseCallback(t){return this.item.addUseCallback(t),this}withTakeCallback(t){return this.item.addTakeCallback(t),this}withDropCallback(t){return this.item.addDropCallback(t),this}withTickCallback(t){return this.item.addTickCallback(t),this}create(){return this.item}}const Q=(new H).withID("statue4").withName("a huge ant statue").withDescription("Before you is a big statue of an ant, in the process of falling over. All of its legs are bent at the joints.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You can't seem to figure out what to do with this yet.")})).create(),X=[...[_,U,F,$,j,G,Q]],J=[(new H).withID("stone").withName("a dull stone").withDescription("There is nothing remarkable about this rough, bland stone.").isTakeable(!0).isUsable(!0).withTakeCallback((async function(t){t.print(`The ${this.id} feels heavy in your hands.`)})).withDropCallback((async function(t){t.print("It bounces back and forth a little.")})).withUseCallback((async function(t){t.print(`You can't really figure out what to do with ${this.name} yet`)})).create(),(new H).withID("torch").withName("a torch").withDescription("A standard torch that provides light.").isUsable(!0).isTakeable(!0).withUseCallback((async function(t){t.print("You try to light the torch but fail.")})).create(),(new H).withID("cup").withName("a cup").withDescription("A standard coffee cup").isTakeable(!0).isUsable(!1).create(),(new H).withID("statue1").withName("a huge ant statue").withDescription("Before you stands a big ant statue. One of its six legs is extended outwards, attached to a round device.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You press the button on the round device attached to the statue's arm.")})).create(),(new H).withID("statue2").withName("a huge ant statue").withDescription("Before you stands a big ant statue. Two of its six legs is extended outwards, attached to a rectangular device.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You press the button on the rectangular device attached to the statue's arm.")})).create(),(new H).withID("statue3").withName("a huge ant statue").withDescription("Before you stands a big ant statue. Three of its six legs are extended outwards, attached to a round stone tablet.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You examine the stone tablet in the statue's hands. There appear to be symbols on it which you can make out.")})).create(),Q];async function K(t,e){e.print("You meow.")}function Z(t){new B(t).init({rooms:X,commands:[[["meow","mew"],K]],items:J})}localStorage.getItem("save")&&(document.getElementById("save-game-found").hidden=!1,document.getElementById("before-play").hidden=!0,document.getElementById("load-save-game").addEventListener("click",(()=>{document.getElementById("save-game-found").hidden=!0,document.getElementById("play-area").hidden=!1,Z(!1)})),document.getElementById("start-new-game").addEventListener("click",(()=>{document.getElementById("save-game-found").hidden=!0,document.getElementById("play-area").hidden=!1,Z(!0)}))),document.getElementById("begin").addEventListener("click",(()=>{document.getElementById("before-play").hidden=!0,document.getElementById("play-area").hidden=!1,Z(!0)}))})()})(); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,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UUFBUyxFQUNwRDVpQixTQUFTd1osZUFBZSxhQUFhb0osUUFBUyxFQUM5Q0QsR0FBVSxNQUVkM2lCLFNBQVN3WixlQUFlLGtCQUFrQjNFLGlCQUFpQixTQUFTLEtBQ2hFN1UsU0FBU3daLGVBQWUsbUJBQW1Cb0osUUFBUyxFQUNwRDVpQixTQUFTd1osZUFBZSxhQUFhb0osUUFBUyxFQUM5Q0QsR0FBVSxPQUlsQjNpQixTQUFTd1osZUFBZSxTQUFTM0UsaUJBQWlCLFNBQVMsS0FDdkQ3VSxTQUFTd1osZUFBZSxlQUFlb0osUUFBUyxFQUNoRDVpQixTQUFTd1osZUFBZSxhQUFhb0osUUFBUyxFQUM5Q0QsR0FBVSxPIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vbm9kZV9tb2R1bGVzL2V2ZW50ZW1pdHRlcjMvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnL3dlYnBhY2svYm9vdHN0cmFwIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy93ZWJwYWNrL3J1bnRpbWUvY29tcGF0IGdldCBkZWZhdWx0IGV4cG9ydCIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvd2VicGFjay9ydW50aW1lL2RlZmluZSBwcm9wZXJ0eSBnZXR0ZXJzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy93ZWJwYWNrL3J1bnRpbWUvaGFzT3duUHJvcGVydHkgc2hvcnRoYW5kIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvc3RhdGUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9wbGF5ZXIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0cy9iYXNlLW91dHB1dC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3R0cy9vdXRwdXRzL2FyaWEuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0cy93ZWJ0dHMuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0LWZhY3RvcnkuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvYXVkaW8tY29udGV4dC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3RzbS92ZWM0LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvdHNtL21hdDQuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90c20vdmVjMi5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3RzbS9tYXQzLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvdHNtL3F1YXQuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90c20vdmVjMy5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3Jlc29uYXRvci9zY2VuZXMvd2ViYXVkaW8tc2NlbmUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZWZmZWN0LWNoYWluLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvcmVzb25hdG9yL2F1ZGlvLWdyYXBoLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvcmVzb25hdG9yL3NvdXJjZXMvc291cmNlLXR5cGUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3Ivc291cmNlcy9hdWRpby1zb3VyY2UuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZGF0YS1wb29sLWl0ZW0uanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvbG9hZGVycy9odHRwLWxvYWRlci5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3Jlc29uYXRvci9kYXRhLXBvb2wuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZWZmZWN0cy9jb252b2x2ZXIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZWZmZWN0cy9iYXNlLWVmZmVjdC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3Jlc29uYXRvci9zb3VyY2VzL3N0cmVhbWluZy1zb3VyY2UuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9zb3VuZC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL291dHB1dC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2lucHV0LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy9sb29rLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMvdXNlLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMvdGFrZS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2NvbW1hbmRzL2Ryb3AuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy9lY2hvLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMvc2F2ZS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2NvbW1hbmRzL2xvYWQuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy92b2x1bWUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy9pbnZlbnRvcnkuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9zZXJpYWxpemF0aW9uLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9yb29tLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvYnVpbGRlcnMvcm9vbS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL3N0YXJ0LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL3Jvb21zL2xhaXIvdHVubmVsMS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL2NlbnRyYWwxLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL3Jvb21zL2xhaXIvc3RhdHVlMS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL3N0YXR1ZTIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvcm9vbXMvbGFpci9zdGF0dWUzLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvaXRlbS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2J1aWxkZXJzL2l0ZW0uanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvaXRlbXMvc3RhdHVlNC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9pbmRleC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL2luZGV4LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL2luZGV4LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL3N0b25lLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL3RvcmNoLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL2N1cC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9pdGVtcy9zdGF0dWUxLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL3N0YXR1ZTIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvaXRlbXMvc3RhdHVlMy5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9jb21tYW5kcy9tZW93LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIid1c2Ugc3RyaWN0JztcblxudmFyIGhhcyA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHlcbiAgLCBwcmVmaXggPSAnfic7XG5cbi8qKlxuICogQ29uc3RydWN0b3IgdG8gY3JlYXRlIGEgc3RvcmFnZSBmb3Igb3VyIGBFRWAgb2JqZWN0cy5cbiAqIEFuIGBFdmVudHNgIGluc3RhbmNlIGlzIGEgcGxhaW4gb2JqZWN0IHdob3NlIHByb3BlcnRpZXMgYXJlIGV2ZW50IG5hbWVzLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gRXZlbnRzKCkge31cblxuLy9cbi8vIFdlIHRyeSB0byBub3QgaW5oZXJpdCBmcm9tIGBPYmplY3QucHJvdG90eXBlYC4gSW4gc29tZSBlbmdpbmVzIGNyZWF0aW5nIGFuXG4vLyBpbnN0YW5jZSBpbiB0aGlzIHdheSBpcyBmYXN0ZXIgdGhhbiBjYWxsaW5nIGBPYmplY3QuY3JlYXRlKG51bGwpYCBkaXJlY3RseS5cbi8vIElmIGBPYmplY3QuY3JlYXRlKG51bGwpYCBpcyBub3Qgc3VwcG9ydGVkIHdlIHByZWZpeCB0aGUgZXZlbnQgbmFtZXMgd2l0aCBhXG4vLyBjaGFyYWN0ZXIgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIGJ1aWx0LWluIG9iamVjdCBwcm9wZXJ0aWVzIGFyZSBub3Rcbi8vIG92ZXJyaWRkZW4gb3IgdXNlZCBhcyBhbiBhdHRhY2sgdmVjdG9yLlxuLy9cbmlmIChPYmplY3QuY3JlYXRlKSB7XG4gIEV2ZW50cy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuXG4gIC8vXG4gIC8vIFRoaXMgaGFjayBpcyBuZWVkZWQgYmVjYXVzZSB0aGUgYF9fcHJvdG9fX2AgcHJvcGVydHkgaXMgc3RpbGwgaW5oZXJpdGVkIGluXG4gIC8vIHNvbWUgb2xkIGJyb3dzZXJzIGxpa2UgQW5kcm9pZCA0LCBpUGhvbmUgNS4xLCBPcGVyYSAxMSBhbmQgU2FmYXJpIDUuXG4gIC8vXG4gIGlmICghbmV3IEV2ZW50cygpLl9fcHJvdG9fXykgcHJlZml4ID0gZmFsc2U7XG59XG5cbi8qKlxuICogUmVwcmVzZW50YXRpb24gb2YgYSBzaW5nbGUgZXZlbnQgbGlzdGVuZXIuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBjb250ZXh0IFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gW29uY2U9ZmFsc2VdIFNwZWNpZnkgaWYgdGhlIGxpc3RlbmVyIGlzIGEgb25lLXRpbWUgbGlzdGVuZXIuXG4gKiBAY29uc3RydWN0b3JcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIEVFKGZuLCBjb250ZXh0LCBvbmNlKSB7XG4gIHRoaXMuZm4gPSBmbjtcbiAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcbiAgdGhpcy5vbmNlID0gb25jZSB8fCBmYWxzZTtcbn1cblxuLyoqXG4gKiBBZGQgYSBsaXN0ZW5lciBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0ge0V2ZW50RW1pdHRlcn0gZW1pdHRlciBSZWZlcmVuY2UgdG8gdGhlIGBFdmVudEVtaXR0ZXJgIGluc3RhbmNlLlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBjb250ZXh0IFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb25jZSBTcGVjaWZ5IGlmIHRoZSBsaXN0ZW5lciBpcyBhIG9uZS10aW1lIGxpc3RlbmVyLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn1cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGFkZExpc3RlbmVyKGVtaXR0ZXIsIGV2ZW50LCBmbiwgY29udGV4dCwgb25jZSkge1xuICBpZiAodHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVGhlIGxpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuICB9XG5cbiAgdmFyIGxpc3RlbmVyID0gbmV3IEVFKGZuLCBjb250ZXh0IHx8IGVtaXR0ZXIsIG9uY2UpXG4gICAgLCBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50O1xuXG4gIGlmICghZW1pdHRlci5fZXZlbnRzW2V2dF0pIGVtaXR0ZXIuX2V2ZW50c1tldnRdID0gbGlzdGVuZXIsIGVtaXR0ZXIuX2V2ZW50c0NvdW50Kys7XG4gIGVsc2UgaWYgKCFlbWl0dGVyLl9ldmVudHNbZXZ0XS5mbikgZW1pdHRlci5fZXZlbnRzW2V2dF0ucHVzaChsaXN0ZW5lcik7XG4gIGVsc2UgZW1pdHRlci5fZXZlbnRzW2V2dF0gPSBbZW1pdHRlci5fZXZlbnRzW2V2dF0sIGxpc3RlbmVyXTtcblxuICByZXR1cm4gZW1pdHRlcjtcbn1cblxuLyoqXG4gKiBDbGVhciBldmVudCBieSBuYW1lLlxuICpcbiAqIEBwYXJhbSB7RXZlbnRFbWl0dGVyfSBlbWl0dGVyIFJlZmVyZW5jZSB0byB0aGUgYEV2ZW50RW1pdHRlcmAgaW5zdGFuY2UuXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZ0IFRoZSBFdmVudCBuYW1lLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gY2xlYXJFdmVudChlbWl0dGVyLCBldnQpIHtcbiAgaWYgKC0tZW1pdHRlci5fZXZlbnRzQ291bnQgPT09IDApIGVtaXR0ZXIuX2V2ZW50cyA9IG5ldyBFdmVudHMoKTtcbiAgZWxzZSBkZWxldGUgZW1pdHRlci5fZXZlbnRzW2V2dF07XG59XG5cbi8qKlxuICogTWluaW1hbCBgRXZlbnRFbWl0dGVyYCBpbnRlcmZhY2UgdGhhdCBpcyBtb2xkZWQgYWdhaW5zdCB0aGUgTm9kZS5qc1xuICogYEV2ZW50RW1pdHRlcmAgaW50ZXJmYWNlLlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHB1YmxpY1xuICovXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIHRoaXMuX2V2ZW50cyA9IG5ldyBFdmVudHMoKTtcbiAgdGhpcy5fZXZlbnRzQ291bnQgPSAwO1xufVxuXG4vKipcbiAqIFJldHVybiBhbiBhcnJheSBsaXN0aW5nIHRoZSBldmVudHMgZm9yIHdoaWNoIHRoZSBlbWl0dGVyIGhhcyByZWdpc3RlcmVkXG4gKiBsaXN0ZW5lcnMuXG4gKlxuICogQHJldHVybnMge0FycmF5fVxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmV2ZW50TmFtZXMgPSBmdW5jdGlvbiBldmVudE5hbWVzKCkge1xuICB2YXIgbmFtZXMgPSBbXVxuICAgICwgZXZlbnRzXG4gICAgLCBuYW1lO1xuXG4gIGlmICh0aGlzLl9ldmVudHNDb3VudCA9PT0gMCkgcmV0dXJuIG5hbWVzO1xuXG4gIGZvciAobmFtZSBpbiAoZXZlbnRzID0gdGhpcy5fZXZlbnRzKSkge1xuICAgIGlmIChoYXMuY2FsbChldmVudHMsIG5hbWUpKSBuYW1lcy5wdXNoKHByZWZpeCA/IG5hbWUuc2xpY2UoMSkgOiBuYW1lKTtcbiAgfVxuXG4gIGlmIChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKSB7XG4gICAgcmV0dXJuIG5hbWVzLmNvbmNhdChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKGV2ZW50cykpO1xuICB9XG5cbiAgcmV0dXJuIG5hbWVzO1xufTtcblxuLyoqXG4gKiBSZXR1cm4gdGhlIGxpc3RlbmVycyByZWdpc3RlcmVkIGZvciBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldmVudCBUaGUgZXZlbnQgbmFtZS5cbiAqIEByZXR1cm5zIHtBcnJheX0gVGhlIHJlZ2lzdGVyZWQgbGlzdGVuZXJzLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmxpc3RlbmVycyA9IGZ1bmN0aW9uIGxpc3RlbmVycyhldmVudCkge1xuICB2YXIgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudFxuICAgICwgaGFuZGxlcnMgPSB0aGlzLl9ldmVudHNbZXZ0XTtcblxuICBpZiAoIWhhbmRsZXJzKSByZXR1cm4gW107XG4gIGlmIChoYW5kbGVycy5mbikgcmV0dXJuIFtoYW5kbGVycy5mbl07XG5cbiAgZm9yICh2YXIgaSA9IDAsIGwgPSBoYW5kbGVycy5sZW5ndGgsIGVlID0gbmV3IEFycmF5KGwpOyBpIDwgbDsgaSsrKSB7XG4gICAgZWVbaV0gPSBoYW5kbGVyc1tpXS5mbjtcbiAgfVxuXG4gIHJldHVybiBlZTtcbn07XG5cbi8qKlxuICogUmV0dXJuIHRoZSBudW1iZXIgb2YgbGlzdGVuZXJzIGxpc3RlbmluZyB0byBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldmVudCBUaGUgZXZlbnQgbmFtZS5cbiAqIEByZXR1cm5zIHtOdW1iZXJ9IFRoZSBudW1iZXIgb2YgbGlzdGVuZXJzLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbiBsaXN0ZW5lckNvdW50KGV2ZW50KSB7XG4gIHZhciBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50XG4gICAgLCBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbZXZ0XTtcblxuICBpZiAoIWxpc3RlbmVycykgcmV0dXJuIDA7XG4gIGlmIChsaXN0ZW5lcnMuZm4pIHJldHVybiAxO1xuICByZXR1cm4gbGlzdGVuZXJzLmxlbmd0aDtcbn07XG5cbi8qKlxuICogQ2FsbHMgZWFjaCBvZiB0aGUgbGlzdGVuZXJzIHJlZ2lzdGVyZWQgZm9yIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHJldHVybnMge0Jvb2xlYW59IGB0cnVlYCBpZiB0aGUgZXZlbnQgaGFkIGxpc3RlbmVycywgZWxzZSBgZmFsc2VgLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbiBlbWl0KGV2ZW50LCBhMSwgYTIsIGEzLCBhNCwgYTUpIHtcbiAgdmFyIGV2dCA9IHByZWZpeCA/IHByZWZpeCArIGV2ZW50IDogZXZlbnQ7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHNbZXZ0XSkgcmV0dXJuIGZhbHNlO1xuXG4gIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbZXZ0XVxuICAgICwgbGVuID0gYXJndW1lbnRzLmxlbmd0aFxuICAgICwgYXJnc1xuICAgICwgaTtcblxuICBpZiAobGlzdGVuZXJzLmZuKSB7XG4gICAgaWYgKGxpc3RlbmVycy5vbmNlKSB0aGlzLnJlbW92ZUxpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcnMuZm4sIHVuZGVmaW5lZCwgdHJ1ZSk7XG5cbiAgICBzd2l0Y2ggKGxlbikge1xuICAgICAgY2FzZSAxOiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQpLCB0cnVlO1xuICAgICAgY2FzZSAyOiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExKSwgdHJ1ZTtcbiAgICAgIGNhc2UgMzogcmV0dXJuIGxpc3RlbmVycy5mbi5jYWxsKGxpc3RlbmVycy5jb250ZXh0LCBhMSwgYTIpLCB0cnVlO1xuICAgICAgY2FzZSA0OiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiwgYTMpLCB0cnVlO1xuICAgICAgY2FzZSA1OiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiwgYTMsIGE0KSwgdHJ1ZTtcbiAgICAgIGNhc2UgNjogcmV0dXJuIGxpc3RlbmVycy5mbi5jYWxsKGxpc3RlbmVycy5jb250ZXh0LCBhMSwgYTIsIGEzLCBhNCwgYTUpLCB0cnVlO1xuICAgIH1cblxuICAgIGZvciAoaSA9IDEsIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0xKTsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICB9XG5cbiAgICBsaXN0ZW5lcnMuZm4uYXBwbHkobGlzdGVuZXJzLmNvbnRleHQsIGFyZ3MpO1xuICB9IGVsc2Uge1xuICAgIHZhciBsZW5ndGggPSBsaXN0ZW5lcnMubGVuZ3RoXG4gICAgICAsIGo7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChsaXN0ZW5lcnNbaV0ub25jZSkgdGhpcy5yZW1vdmVMaXN0ZW5lcihldmVudCwgbGlzdGVuZXJzW2ldLmZuLCB1bmRlZmluZWQsIHRydWUpO1xuXG4gICAgICBzd2l0Y2ggKGxlbikge1xuICAgICAgICBjYXNlIDE6IGxpc3RlbmVyc1tpXS5mbi5jYWxsKGxpc3RlbmVyc1tpXS5jb250ZXh0KTsgYnJlYWs7XG4gICAgICAgIGNhc2UgMjogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQsIGExKTsgYnJlYWs7XG4gICAgICAgIGNhc2UgMzogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQsIGExLCBhMik7IGJyZWFrO1xuICAgICAgICBjYXNlIDQ6IGxpc3RlbmVyc1tpXS5mbi5jYWxsKGxpc3RlbmVyc1tpXS5jb250ZXh0LCBhMSwgYTIsIGEzKTsgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgaWYgKCFhcmdzKSBmb3IgKGogPSAxLCBhcmdzID0gbmV3IEFycmF5KGxlbiAtMSk7IGogPCBsZW47IGorKykge1xuICAgICAgICAgICAgYXJnc1tqIC0gMV0gPSBhcmd1bWVudHNbal07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbGlzdGVuZXJzW2ldLmZuLmFwcGx5KGxpc3RlbmVyc1tpXS5jb250ZXh0LCBhcmdzKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8qKlxuICogQWRkIGEgbGlzdGVuZXIgZm9yIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBbY29udGV4dD10aGlzXSBUaGUgY29udGV4dCB0byBpbnZva2UgdGhlIGxpc3RlbmVyIHdpdGguXG4gKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfSBgdGhpc2AuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBmdW5jdGlvbiBvbihldmVudCwgZm4sIGNvbnRleHQpIHtcbiAgcmV0dXJuIGFkZExpc3RlbmVyKHRoaXMsIGV2ZW50LCBmbiwgY29udGV4dCwgZmFsc2UpO1xufTtcblxuLyoqXG4gKiBBZGQgYSBvbmUtdGltZSBsaXN0ZW5lciBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IFtjb250ZXh0PXRoaXNdIFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbmNlID0gZnVuY3Rpb24gb25jZShldmVudCwgZm4sIGNvbnRleHQpIHtcbiAgcmV0dXJuIGFkZExpc3RlbmVyKHRoaXMsIGV2ZW50LCBmbiwgY29udGV4dCwgdHJ1ZSk7XG59O1xuXG4vKipcbiAqIFJlbW92ZSB0aGUgbGlzdGVuZXJzIG9mIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gT25seSByZW1vdmUgdGhlIGxpc3RlbmVycyB0aGF0IG1hdGNoIHRoaXMgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IGNvbnRleHQgT25seSByZW1vdmUgdGhlIGxpc3RlbmVycyB0aGF0IGhhdmUgdGhpcyBjb250ZXh0LlxuICogQHBhcmFtIHtCb29sZWFufSBvbmNlIE9ubHkgcmVtb3ZlIG9uZS10aW1lIGxpc3RlbmVycy5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uIHJlbW92ZUxpc3RlbmVyKGV2ZW50LCBmbiwgY29udGV4dCwgb25jZSkge1xuICB2YXIgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudDtcblxuICBpZiAoIXRoaXMuX2V2ZW50c1tldnRdKSByZXR1cm4gdGhpcztcbiAgaWYgKCFmbikge1xuICAgIGNsZWFyRXZlbnQodGhpcywgZXZ0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbZXZ0XTtcblxuICBpZiAobGlzdGVuZXJzLmZuKSB7XG4gICAgaWYgKFxuICAgICAgbGlzdGVuZXJzLmZuID09PSBmbiAmJlxuICAgICAgKCFvbmNlIHx8IGxpc3RlbmVycy5vbmNlKSAmJlxuICAgICAgKCFjb250ZXh0IHx8IGxpc3RlbmVycy5jb250ZXh0ID09PSBjb250ZXh0KVxuICAgICkge1xuICAgICAgY2xlYXJFdmVudCh0aGlzLCBldnQpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBmb3IgKHZhciBpID0gMCwgZXZlbnRzID0gW10sIGxlbmd0aCA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgaWYgKFxuICAgICAgICBsaXN0ZW5lcnNbaV0uZm4gIT09IGZuIHx8XG4gICAgICAgIChvbmNlICYmICFsaXN0ZW5lcnNbaV0ub25jZSkgfHxcbiAgICAgICAgKGNvbnRleHQgJiYgbGlzdGVuZXJzW2ldLmNvbnRleHQgIT09IGNvbnRleHQpXG4gICAgICApIHtcbiAgICAgICAgZXZlbnRzLnB1c2gobGlzdGVuZXJzW2ldKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL1xuICAgIC8vIFJlc2V0IHRoZSBhcnJheSwgb3IgcmVtb3ZlIGl0IGNvbXBsZXRlbHkgaWYgd2UgaGF2ZSBubyBtb3JlIGxpc3RlbmVycy5cbiAgICAvL1xuICAgIGlmIChldmVudHMubGVuZ3RoKSB0aGlzLl9ldmVudHNbZXZ0XSA9IGV2ZW50cy5sZW5ndGggPT09IDEgPyBldmVudHNbMF0gOiBldmVudHM7XG4gICAgZWxzZSBjbGVhckV2ZW50KHRoaXMsIGV2dCk7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogUmVtb3ZlIGFsbCBsaXN0ZW5lcnMsIG9yIHRob3NlIG9mIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IFtldmVudF0gVGhlIGV2ZW50IG5hbWUuXG4gKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfSBgdGhpc2AuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24gcmVtb3ZlQWxsTGlzdGVuZXJzKGV2ZW50KSB7XG4gIHZhciBldnQ7XG5cbiAgaWYgKGV2ZW50KSB7XG4gICAgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudDtcbiAgICBpZiAodGhpcy5fZXZlbnRzW2V2dF0pIGNsZWFyRXZlbnQodGhpcywgZXZ0KTtcbiAgfSBlbHNlIHtcbiAgICB0aGlzLl9ldmVudHMgPSBuZXcgRXZlbnRzKCk7XG4gICAgdGhpcy5fZXZlbnRzQ291bnQgPSAwO1xuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vL1xuLy8gQWxpYXMgbWV0aG9kcyBuYW1lcyBiZWNhdXNlIHBlb3BsZSByb2xsIGxpa2UgdGhhdC5cbi8vXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9mZiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlTGlzdGVuZXI7XG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyID0gRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbjtcblxuLy9cbi8vIEV4cG9zZSB0aGUgcHJlZml4LlxuLy9cbkV2ZW50RW1pdHRlci5wcmVmaXhlZCA9IHByZWZpeDtcblxuLy9cbi8vIEFsbG93IGBFdmVudEVtaXR0ZXJgIHRvIGJlIGltcG9ydGVkIGFzIG1vZHVsZSBuYW1lc3BhY2UuXG4vL1xuRXZlbnRFbWl0dGVyLkV2ZW50RW1pdHRlciA9IEV2ZW50RW1pdHRlcjtcblxuLy9cbi8vIEV4cG9zZSB0aGUgbW9kdWxlLlxuLy9cbmlmICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIG1vZHVsZSkge1xuICBtb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcbn1cbiIsIi8vIFRoZSBtb2R1bGUgY2FjaGVcbnZhciBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18gPSB7fTtcblxuLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbmZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG5cdHZhciBjYWNoZWRNb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdO1xuXHRpZiAoY2FjaGVkTW9kdWxlICE9PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gY2FjaGVkTW9kdWxlLmV4cG9ydHM7XG5cdH1cblx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcblx0dmFyIG1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF0gPSB7XG5cdFx0Ly8gbm8gbW9kdWxlLmlkIG5lZWRlZFxuXHRcdC8vIG5vIG1vZHVsZS5sb2FkZWQgbmVlZGVkXG5cdFx0ZXhwb3J0czoge31cblx0fTtcblxuXHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblx0X193ZWJwYWNrX21vZHVsZXNfX1ttb2R1bGVJZF0obW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cblx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcblx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xufVxuXG4iLCIvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuX193ZWJwYWNrX3JlcXVpcmVfXy5uID0gKG1vZHVsZSkgPT4ge1xuXHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cblx0XHQoKSA9PiAobW9kdWxlWydkZWZhdWx0J10pIDpcblx0XHQoKSA9PiAobW9kdWxlKTtcblx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgeyBhOiBnZXR0ZXIgfSk7XG5cdHJldHVybiBnZXR0ZXI7XG59OyIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCJjbGFzcyBTdGF0ZSB7XHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgICAgICB0aGlzLnN0YXRlcyA9IG5ldyBNYXAoKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXQoa2V5KSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlcy5oYXMoa2V5KSkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVzLmdldChrZXkpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldChrZXksIHZhbHVlKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVzLnNldChrZXksIHZhbHVlKTtcclxuICAgIH1cclxuXHJcbiAgICBzZXJpYWxpemUoKSB7XHJcbiAgICAgICAgY29uc3QgZW50cmllcyA9IHRoaXMuc3RhdGVzLmVudHJpZXMoKTtcclxuICAgICAgICBjb25zdCBlbnRyeW1hcCA9IFtdO1xyXG4gICAgICAgIGZvciAobGV0IHN0YXRlIG9mIGVudHJpZXMpIHtcclxuICAgICAgICAgICAgZW50cnltYXAucHVzaChzdGF0ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBlbnRyeW1hcDtcclxuICAgIH1cclxuXHJcbiAgICBkZXNlcmlhbGl6ZShkYXRhKSB7XHJcbiAgICAgICAgdGhpcy5zdGF0ZXMgPSBuZXcgTWFwKGRhdGEpO1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBuZXcgU3RhdGUoKTsiLCJleHBvcnQgZGVmYXVsdCBjbGFzcyBQbGF5ZXIge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5pbnZlbnRvcnkgPSBbXTtcclxuICAgICAgICB0aGlzLmN1cnJlbnRSb29tID0gXCJzdGFydFwiO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkSXRlbShpZCkge1xyXG4gICAgICAgIHRoaXMuaW52ZW50b3J5LnB1c2goaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHJlbW92ZUl0ZW0oaWQpIHtcclxuICAgICAgICB0aGlzLmludmVudG9yeSA9IHRoaXMuaW52ZW50b3J5LmZpbHRlcigoaXRlbSkgPT4gaXRlbSAhPSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0SW52ZW50b3J5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmludmVudG9yeS5tYXAoKGl0ZW0pID0+IHRoaXMuY29udGV4dC5nZXRJdGVtKGl0ZW0pKTtcclxuICAgIH1cclxufSIsImV4cG9ydCBjbGFzcyBCYXNlT3V0cHV0IHtcclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHNldE9wdGlvbnMob3B0aW9ucykge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlT3V0cHV0IH0gZnJvbSAnLi9iYXNlLW91dHB1dCc7XHJcbmV4cG9ydCBjbGFzcyBBcmlhT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0ge30pIHtcclxuICAgICAgICBzdXBlcigpO1xyXG4gICAgICAgIHRoaXMudGltZW91dCA9IDEwMDtcclxuICAgICAgICB0aGlzLnRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgfHwgMTAwO1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLnNldEF0dHJpYnV0ZSgnYXJpYS1saXZlJywgJ3BvbGl0ZScpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheS5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGl2ZScsICdwb2xpdGUnKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmQodGhpcy5zcGVlY2hEaXNwbGF5KTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHRoaXMuY29udGFpbmVyKTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5Lmluc2VydEJlZm9yZSh0aGlzLmNvbnRhaW5lciwgZG9jdW1lbnQuYm9keS5maXJzdENoaWxkKTtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLmNsZWFyRGlzcGxheSgpO1xyXG4gICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSh0ZXh0KTtcclxuICAgICAgICBjb25zdCBwYXJhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO1xyXG4gICAgICAgIHBhcmEuYXBwZW5kQ2hpbGQobm9kZSk7XHJcbiAgICAgICAgdGhpcy5zcGVlY2hEaXNwbGF5LmFwcGVuZENoaWxkKHBhcmEpO1xyXG4gICAgICAgIHNldFRpbWVvdXQodGhpcy5jbGVhckRpc3BsYXkuYmluZCh0aGlzKSwgdGhpcy50aW1lb3V0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5jbGVhckRpc3BsYXkoKTtcclxuICAgIH1cclxuICAgIGNsZWFyRGlzcGxheSgpIHtcclxuICAgICAgICB0aGlzLnNwZWVjaERpc3BsYXkuaW5uZXJIVE1MID0gJyc7XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgQmFzZU91dHB1dCB9IGZyb20gJy4vYmFzZS1vdXRwdXQnO1xyXG5leHBvcnQgY2xhc3MgV2ViVFRTT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbn1cclxuIiwiaW1wb3J0IHsgY3JlYXRlT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXQtZmFjdG9yeSc7XHJcbmV4cG9ydCBjbGFzcyBUVFMge1xyXG4gICAgY29uc3RydWN0b3Iob3V0cHV0ID0gY3JlYXRlT3V0cHV0KCkpIHtcclxuICAgICAgICB0aGlzLm91dHB1dCA9IG91dHB1dDtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLm91dHB1dC5zcGVhayh0ZXh0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQuc3RvcCgpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IEJhc2VPdXRwdXQgfSBmcm9tICcuL291dHB1dHMvYmFzZS1vdXRwdXQnO1xyXG5pbXBvcnQgeyBBcmlhT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXRzL2FyaWEnO1xyXG5pbXBvcnQgeyBXZWJUVFNPdXRwdXQgfSBmcm9tICcuL291dHB1dHMvd2VidHRzJztcclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU91dHB1dChrZXkgPSAnYXJpYScpIHtcclxuICAgIHN3aXRjaCAoa2V5KSB7XHJcbiAgICAgICAgY2FzZSAnYXJpYSc6XHJcbiAgICAgICAgICAgIHJldHVybiBBcmlhT3V0cHV0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlICd3ZWJ0dHMnOlxyXG4gICAgICAgICAgICByZXR1cm4gV2ViVFRTT3V0cHV0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICByZXR1cm4gQXJpYU91dHB1dDtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICB9XHJcbn1cclxuZXhwb3J0IHsgV2ViVFRTT3V0cHV0LCBBcmlhT3V0cHV0LCBCYXNlT3V0cHV0IH07XHJcbiIsIi8vIHNpbXBsZSB3cmFwcGVyIGFyb3VuZCB0aGUgQXVkaW9Db250ZXh0XHJcbi8vIGV2ZW50dWFsbHkgd2lsbCBiZSB1c2VkIHRvIGRlYWwgd2l0aCBjcm9zcyBicm93c2VyIGlzc3Vlc1xyXG52YXIgX19hd2FpdGVyID0gKHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIpIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcclxuICAgIGZ1bmN0aW9uIGFkb3B0KHZhbHVlKSB7IHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7IHJlc29sdmUodmFsdWUpOyB9KTsgfVxyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogYWRvcHQocmVzdWx0LnZhbHVlKS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn07XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFJlc29uYXRvckF1ZGlvQ29udGV4dCB7XHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBuZXcgQXVkaW9Db250ZXh0KCk7XHJcbiAgICB9XHJcbiAgICBnZXRDb250ZXh0KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQ7XHJcbiAgICB9XHJcbiAgICBjcmVhdGVHYWluKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuY3JlYXRlR2FpbigpO1xyXG4gICAgfVxyXG4gICAgZ2V0T3V0cHV0RGVzdGluYXRpb24oKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5kZXN0aW5hdGlvbjtcclxuICAgIH1cclxuICAgIGNyZWF0ZUJ1ZmZlclNvdXJjZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmNyZWF0ZUJ1ZmZlclNvdXJjZSgpO1xyXG4gICAgfVxyXG4gICAgZGVjb2RlQXVkaW9EYXRhKGRhdGEpIHtcclxuICAgICAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xyXG4gICAgICAgICAgICByZXR1cm4geWllbGQgdGhpcy5jb250ZXh0LmRlY29kZUF1ZGlvRGF0YShkYXRhKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIGNyZWF0ZVBhbm5lcigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmNyZWF0ZVBhbm5lcigpO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlTWVkaWFFbGVtZW50U291cmNlKGVsZW1lbnQpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmNyZWF0ZU1lZGlhRWxlbWVudFNvdXJjZShlbGVtZW50KTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBlcHNpbG9uIH0gZnJvbSAnLi9jb25zdGFudHMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyB2ZWM0IHtcclxuICAgIGNvbnN0cnVjdG9yKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSg0KTtcclxuICAgICAgICBpZiAodmFsdWVzICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy54eXp3ID0gdmFsdWVzO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldCB4KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1swXTtcclxuICAgIH1cclxuICAgIGdldCB5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGdldCB6KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIGdldCB3KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1szXTtcclxuICAgIH1cclxuICAgIGdldCB4eSgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHl6KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHl6dygpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXSwgdGhpcy52YWx1ZXNbMl0sIHRoaXMudmFsdWVzWzNdXTtcclxuICAgIH1cclxuICAgIHNldCB4KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB5KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB6KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB3KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB4eSh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIHNldCB4eXoodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBzZXQgeHl6dyh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlc1syXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHZhbHVlc1szXTtcclxuICAgIH1cclxuICAgIGdldCByKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1swXTtcclxuICAgIH1cclxuICAgIGdldCBnKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGdldCBiKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIGdldCBhKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1szXTtcclxuICAgIH1cclxuICAgIGdldCByZygpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXV07XHJcbiAgICB9XHJcbiAgICBnZXQgcmdiKCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXV07XHJcbiAgICB9XHJcbiAgICBnZXQgcmdiYSgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXSwgdGhpcy52YWx1ZXNbMl0sIHRoaXMudmFsdWVzWzNdXTtcclxuICAgIH1cclxuICAgIHNldCByKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCBnKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCBiKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCBhKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCByZyh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIHNldCByZ2IodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBzZXQgcmdiYSh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlc1syXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHZhbHVlc1szXTtcclxuICAgIH1cclxuICAgIGF0KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzW2luZGV4XTtcclxuICAgIH1cclxuICAgIHJlc2V0KCkge1xyXG4gICAgICAgIHRoaXMueCA9IDA7XHJcbiAgICAgICAgdGhpcy55ID0gMDtcclxuICAgICAgICB0aGlzLnogPSAwO1xyXG4gICAgICAgIHRoaXMudyA9IDA7XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSB0aGlzLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdGhpcy56O1xyXG4gICAgICAgIGRlc3QudyA9IHRoaXMudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG5lZ2F0ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSAtdGhpcy54O1xyXG4gICAgICAgIGRlc3QueSA9IC10aGlzLnk7XHJcbiAgICAgICAgZGVzdC56ID0gLXRoaXMuejtcclxuICAgICAgICBkZXN0LncgPSAtdGhpcy53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKHZlY3RvciwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnggLSB2ZWN0b3IueCkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy55IC0gdmVjdG9yLnkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueiAtIHZlY3Rvci56KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLncgLSB2ZWN0b3IudykgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIGxlbmd0aCgpIHtcclxuICAgICAgICByZXR1cm4gTWF0aC5zcXJ0KHRoaXMuc3F1YXJlZExlbmd0aCgpKTtcclxuICAgIH1cclxuICAgIHNxdWFyZWRMZW5ndGgoKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICByZXR1cm4geCAqIHggKyB5ICogeSArIHogKiB6ICsgdyAqIHc7XHJcbiAgICB9XHJcbiAgICBhZGQodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54ICs9IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSArPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogKz0gdmVjdG9yLno7XHJcbiAgICAgICAgdGhpcy53ICs9IHZlY3Rvci53O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc3VidHJhY3QodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54IC09IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAtPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogLT0gdmVjdG9yLno7XHJcbiAgICAgICAgdGhpcy53IC09IHZlY3Rvci53O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHkodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54ICo9IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAqPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogKj0gdmVjdG9yLno7XHJcbiAgICAgICAgdGhpcy53ICo9IHZlY3Rvci53O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgZGl2aWRlKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAvPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgLz0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56IC89IHZlY3Rvci56O1xyXG4gICAgICAgIHRoaXMudyAvPSB2ZWN0b3IudztcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNjYWxlKHZhbHVlLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC55ICo9IHZhbHVlO1xyXG4gICAgICAgIGRlc3QueiAqPSB2YWx1ZTtcclxuICAgICAgICBkZXN0LncgKj0gdmFsdWU7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBub3JtYWxpemUoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IHRoaXMubGVuZ3RoKCk7XHJcbiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICBkZXN0LnggKj0gMDtcclxuICAgICAgICAgICAgZGVzdC55ICo9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueiAqPSAwO1xyXG4gICAgICAgICAgICBkZXN0LncgKj0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEuMCAvIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnggKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueSAqPSBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC56ICo9IGxlbmd0aDtcclxuICAgICAgICBkZXN0LncgKj0gbGVuZ3RoO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlNYXQ0KG1hdHJpeCwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIG1hdHJpeC5tdWx0aXBseVZlYzQodGhpcywgZGVzdCk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgbWl4KHZlY3RvciwgdmVjdG9yMiwgdGltZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB0aW1lICogKHZlY3RvcjIueCAtIHZlY3Rvci54KTtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSArIHRpbWUgKiAodmVjdG9yMi55IC0gdmVjdG9yLnkpO1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56ICsgdGltZSAqICh2ZWN0b3IyLnogLSB2ZWN0b3Iueik7XHJcbiAgICAgICAgZGVzdC53ID0gdmVjdG9yLncgKyB0aW1lICogKHZlY3RvcjIudyAtIHZlY3Rvci53KTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBzdW0odmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCArIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSArIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiArIHZlY3RvcjIuejtcclxuICAgICAgICBkZXN0LncgPSB2ZWN0b3IudyArIHZlY3RvcjIudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkaWZmZXJlbmNlKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggLSB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgLSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogLSB2ZWN0b3IyLno7XHJcbiAgICAgICAgZGVzdC53ID0gdmVjdG9yLncgLSB2ZWN0b3IyLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcHJvZHVjdCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54ICogdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICogdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56ICogdmVjdG9yMi56O1xyXG4gICAgICAgIGRlc3QudyA9IHZlY3Rvci53ICogdmVjdG9yMi53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHF1b3RpZW50KHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggLyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgLyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogLyB2ZWN0b3IyLno7XHJcbiAgICAgICAgZGVzdC53ID0gdmVjdG9yLncgLyB2ZWN0b3IyLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbn1cclxudmVjNC56ZXJvID0gbmV3IHZlYzQoWzAsIDAsIDAsIDFdKTtcclxudmVjNC5vbmUgPSBuZXcgdmVjNChbMSwgMSwgMSwgMV0pO1xyXG4iLCJpbXBvcnQgbWF0MyBmcm9tICcuL21hdDMnO1xyXG5pbXBvcnQgdmVjMyBmcm9tICcuL3ZlYzMnO1xyXG5pbXBvcnQgdmVjNCBmcm9tICcuL3ZlYzQnO1xyXG5pbXBvcnQgeyBlcHNpbG9uIH0gZnJvbSAnLi9jb25zdGFudHMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBtYXQ0IHtcclxuICAgIGNvbnN0cnVjdG9yKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSgxNik7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuaW5pdCh2YWx1ZXMpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGF0KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzW2luZGV4XTtcclxuICAgIH1cclxuICAgIGluaXQodmFsdWVzKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2ldID0gdmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHJlc2V0KCkge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTY7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpXSA9IDA7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgY29weShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgbWF0NCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcclxuICAgICAgICAgICAgZGVzdC52YWx1ZXNbaV0gPSB0aGlzLnZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBhbGwoKSB7XHJcbiAgICAgICAgY29uc3QgZGF0YSA9IFtdO1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTY7IGkrKykge1xyXG4gICAgICAgICAgICBkYXRhW2ldID0gdGhpcy52YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBkYXRhO1xyXG4gICAgfVxyXG4gICAgcm93KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiA0ICsgMF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogNCArIDFdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDQgKyAyXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiA0ICsgM11cclxuICAgICAgICBdO1xyXG4gICAgfVxyXG4gICAgY29sKGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXhdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCArIDRdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCArIDhdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCArIDEyXVxyXG4gICAgICAgIF07XHJcbiAgICB9XHJcbiAgICBlcXVhbHMobWF0cml4LCB0aHJlc2hvbGQgPSBlcHNpbG9uKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XHJcbiAgICAgICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnZhbHVlc1tpXSAtIG1hdHJpeC5hdChpKSkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIGRldGVybWluYW50KCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGEwMyA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGExMyA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzEwXTtcclxuICAgICAgICBjb25zdCBhMjMgPSB0aGlzLnZhbHVlc1sxMV07XHJcbiAgICAgICAgY29uc3QgYTMwID0gdGhpcy52YWx1ZXNbMTJdO1xyXG4gICAgICAgIGNvbnN0IGEzMSA9IHRoaXMudmFsdWVzWzEzXTtcclxuICAgICAgICBjb25zdCBhMzIgPSB0aGlzLnZhbHVlc1sxNF07XHJcbiAgICAgICAgY29uc3QgYTMzID0gdGhpcy52YWx1ZXNbMTVdO1xyXG4gICAgICAgIGNvbnN0IGRldDAwID0gYTAwICogYTExIC0gYTAxICogYTEwO1xyXG4gICAgICAgIGNvbnN0IGRldDAxID0gYTAwICogYTEyIC0gYTAyICogYTEwO1xyXG4gICAgICAgIGNvbnN0IGRldDAyID0gYTAwICogYTEzIC0gYTAzICogYTEwO1xyXG4gICAgICAgIGNvbnN0IGRldDAzID0gYTAxICogYTEyIC0gYTAyICogYTExO1xyXG4gICAgICAgIGNvbnN0IGRldDA0ID0gYTAxICogYTEzIC0gYTAzICogYTExO1xyXG4gICAgICAgIGNvbnN0IGRldDA1ID0gYTAyICogYTEzIC0gYTAzICogYTEyO1xyXG4gICAgICAgIGNvbnN0IGRldDA2ID0gYTIwICogYTMxIC0gYTIxICogYTMwO1xyXG4gICAgICAgIGNvbnN0IGRldDA3ID0gYTIwICogYTMyIC0gYTIyICogYTMwO1xyXG4gICAgICAgIGNvbnN0IGRldDA4ID0gYTIwICogYTMzIC0gYTIzICogYTMwO1xyXG4gICAgICAgIGNvbnN0IGRldDA5ID0gYTIxICogYTMyIC0gYTIyICogYTMxO1xyXG4gICAgICAgIGNvbnN0IGRldDEwID0gYTIxICogYTMzIC0gYTIzICogYTMxO1xyXG4gICAgICAgIGNvbnN0IGRldDExID0gYTIyICogYTMzIC0gYTIzICogYTMyO1xyXG4gICAgICAgIHJldHVybiAoZGV0MDAgKiBkZXQxMSAtXHJcbiAgICAgICAgICAgIGRldDAxICogZGV0MTAgK1xyXG4gICAgICAgICAgICBkZXQwMiAqIGRldDA5ICtcclxuICAgICAgICAgICAgZGV0MDMgKiBkZXQwOCAtXHJcbiAgICAgICAgICAgIGRldDA0ICogZGV0MDcgK1xyXG4gICAgICAgICAgICBkZXQwNSAqIGRldDA2KTtcclxuICAgIH1cclxuICAgIHNldElkZW50aXR5KCkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzldID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMF0gPSAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzExXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTJdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxM10gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE0XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTVdID0gMTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHRyYW5zcG9zZSgpIHtcclxuICAgICAgICBjb25zdCB0ZW1wMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCB0ZW1wMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCB0ZW1wMDMgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCB0ZW1wMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCB0ZW1wMTMgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCB0ZW1wMjMgPSB0aGlzLnZhbHVlc1sxMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdGhpcy52YWx1ZXNbMTJdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gdGVtcDAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSB0aGlzLnZhbHVlc1sxM107XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSB0ZW1wMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOV0gPSB0ZW1wMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTFdID0gdGhpcy52YWx1ZXNbMTRdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEyXSA9IHRlbXAwMztcclxuICAgICAgICB0aGlzLnZhbHVlc1sxM10gPSB0ZW1wMTM7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTRdID0gdGVtcDIzO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgaW52ZXJzZSgpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMDMgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMTMgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1sxMF07XHJcbiAgICAgICAgY29uc3QgYTIzID0gdGhpcy52YWx1ZXNbMTFdO1xyXG4gICAgICAgIGNvbnN0IGEzMCA9IHRoaXMudmFsdWVzWzEyXTtcclxuICAgICAgICBjb25zdCBhMzEgPSB0aGlzLnZhbHVlc1sxM107XHJcbiAgICAgICAgY29uc3QgYTMyID0gdGhpcy52YWx1ZXNbMTRdO1xyXG4gICAgICAgIGNvbnN0IGEzMyA9IHRoaXMudmFsdWVzWzE1XTtcclxuICAgICAgICBjb25zdCBkZXQwMCA9IGEwMCAqIGExMSAtIGEwMSAqIGExMDtcclxuICAgICAgICBjb25zdCBkZXQwMSA9IGEwMCAqIGExMiAtIGEwMiAqIGExMDtcclxuICAgICAgICBjb25zdCBkZXQwMiA9IGEwMCAqIGExMyAtIGEwMyAqIGExMDtcclxuICAgICAgICBjb25zdCBkZXQwMyA9IGEwMSAqIGExMiAtIGEwMiAqIGExMTtcclxuICAgICAgICBjb25zdCBkZXQwNCA9IGEwMSAqIGExMyAtIGEwMyAqIGExMTtcclxuICAgICAgICBjb25zdCBkZXQwNSA9IGEwMiAqIGExMyAtIGEwMyAqIGExMjtcclxuICAgICAgICBjb25zdCBkZXQwNiA9IGEyMCAqIGEzMSAtIGEyMSAqIGEzMDtcclxuICAgICAgICBjb25zdCBkZXQwNyA9IGEyMCAqIGEzMiAtIGEyMiAqIGEzMDtcclxuICAgICAgICBjb25zdCBkZXQwOCA9IGEyMCAqIGEzMyAtIGEyMyAqIGEzMDtcclxuICAgICAgICBjb25zdCBkZXQwOSA9IGEyMSAqIGEzMiAtIGEyMiAqIGEzMTtcclxuICAgICAgICBjb25zdCBkZXQxMCA9IGEyMSAqIGEzMyAtIGEyMyAqIGEzMTtcclxuICAgICAgICBjb25zdCBkZXQxMSA9IGEyMiAqIGEzMyAtIGEyMyAqIGEzMjtcclxuICAgICAgICBsZXQgZGV0ID0gZGV0MDAgKiBkZXQxMSAtXHJcbiAgICAgICAgICAgIGRldDAxICogZGV0MTAgK1xyXG4gICAgICAgICAgICBkZXQwMiAqIGRldDA5ICtcclxuICAgICAgICAgICAgZGV0MDMgKiBkZXQwOCAtXHJcbiAgICAgICAgICAgIGRldDA0ICogZGV0MDcgK1xyXG4gICAgICAgICAgICBkZXQwNSAqIGRldDA2O1xyXG4gICAgICAgIGlmICghZGV0KSB7XHJcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXQgPSAxLjAgLyBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSAoYTExICogZGV0MTEgLSBhMTIgKiBkZXQxMCArIGExMyAqIGRldDA5KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9ICgtYTAxICogZGV0MTEgKyBhMDIgKiBkZXQxMCAtIGEwMyAqIGRldDA5KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IChhMzEgKiBkZXQwNSAtIGEzMiAqIGRldDA0ICsgYTMzICogZGV0MDMpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gKC1hMjEgKiBkZXQwNSArIGEyMiAqIGRldDA0IC0gYTIzICogZGV0MDMpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gKC1hMTAgKiBkZXQxMSArIGExMiAqIGRldDA4IC0gYTEzICogZGV0MDcpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gKGEwMCAqIGRldDExIC0gYTAyICogZGV0MDggKyBhMDMgKiBkZXQwNykgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSAoLWEzMCAqIGRldDA1ICsgYTMyICogZGV0MDIgLSBhMzMgKiBkZXQwMSkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSAoYTIwICogZGV0MDUgLSBhMjIgKiBkZXQwMiArIGEyMyAqIGRldDAxKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IChhMTAgKiBkZXQxMCAtIGExMSAqIGRldDA4ICsgYTEzICogZGV0MDYpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzldID0gKC1hMDAgKiBkZXQxMCArIGEwMSAqIGRldDA4IC0gYTAzICogZGV0MDYpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEwXSA9IChhMzAgKiBkZXQwNCAtIGEzMSAqIGRldDAyICsgYTMzICogZGV0MDApICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzExXSA9ICgtYTIwICogZGV0MDQgKyBhMjEgKiBkZXQwMiAtIGEyMyAqIGRldDAwKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMl0gPSAoLWExMCAqIGRldDA5ICsgYTExICogZGV0MDcgLSBhMTIgKiBkZXQwNikgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTNdID0gKGEwMCAqIGRldDA5IC0gYTAxICogZGV0MDcgKyBhMDIgKiBkZXQwNikgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTRdID0gKC1hMzAgKiBkZXQwMyArIGEzMSAqIGRldDAxIC0gYTMyICogZGV0MDApICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE1XSA9IChhMjAgKiBkZXQwMyAtIGEyMSAqIGRldDAxICsgYTIyICogZGV0MDApICogZGV0O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHkobWF0cml4KSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTAzID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTEzID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbMTBdO1xyXG4gICAgICAgIGNvbnN0IGEyMyA9IHRoaXMudmFsdWVzWzExXTtcclxuICAgICAgICBjb25zdCBhMzAgPSB0aGlzLnZhbHVlc1sxMl07XHJcbiAgICAgICAgY29uc3QgYTMxID0gdGhpcy52YWx1ZXNbMTNdO1xyXG4gICAgICAgIGNvbnN0IGEzMiA9IHRoaXMudmFsdWVzWzE0XTtcclxuICAgICAgICBjb25zdCBhMzMgPSB0aGlzLnZhbHVlc1sxNV07XHJcbiAgICAgICAgbGV0IGIwID0gbWF0cml4LmF0KDApO1xyXG4gICAgICAgIGxldCBiMSA9IG1hdHJpeC5hdCgxKTtcclxuICAgICAgICBsZXQgYjIgPSBtYXRyaXguYXQoMik7XHJcbiAgICAgICAgbGV0IGIzID0gbWF0cml4LmF0KDMpO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gYjAgKiBhMDAgKyBiMSAqIGExMCArIGIyICogYTIwICsgYjMgKiBhMzA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSBiMCAqIGEwMSArIGIxICogYTExICsgYjIgKiBhMjEgKyBiMyAqIGEzMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gYjAgKiBhMDMgKyBiMSAqIGExMyArIGIyICogYTIzICsgYjMgKiBhMzM7XHJcbiAgICAgICAgYjAgPSBtYXRyaXguYXQoNCk7XHJcbiAgICAgICAgYjEgPSBtYXRyaXguYXQoNSk7XHJcbiAgICAgICAgYjIgPSBtYXRyaXguYXQoNik7XHJcbiAgICAgICAgYjMgPSBtYXRyaXguYXQoNyk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSBiMCAqIGEwMCArIGIxICogYTEwICsgYjIgKiBhMjAgKyBiMyAqIGEzMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSBiMCAqIGEwMyArIGIxICogYTEzICsgYjIgKiBhMjMgKyBiMyAqIGEzMztcclxuICAgICAgICBiMCA9IG1hdHJpeC5hdCg4KTtcclxuICAgICAgICBiMSA9IG1hdHJpeC5hdCg5KTtcclxuICAgICAgICBiMiA9IG1hdHJpeC5hdCgxMCk7XHJcbiAgICAgICAgYjMgPSBtYXRyaXguYXQoMTEpO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gYjAgKiBhMDAgKyBiMSAqIGExMCArIGIyICogYTIwICsgYjMgKiBhMzA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOV0gPSBiMCAqIGEwMSArIGIxICogYTExICsgYjIgKiBhMjEgKyBiMyAqIGEzMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMF0gPSBiMCAqIGEwMiArIGIxICogYTEyICsgYjIgKiBhMjIgKyBiMyAqIGEzMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMV0gPSBiMCAqIGEwMyArIGIxICogYTEzICsgYjIgKiBhMjMgKyBiMyAqIGEzMztcclxuICAgICAgICBiMCA9IG1hdHJpeC5hdCgxMik7XHJcbiAgICAgICAgYjEgPSBtYXRyaXguYXQoMTMpO1xyXG4gICAgICAgIGIyID0gbWF0cml4LmF0KDE0KTtcclxuICAgICAgICBiMyA9IG1hdHJpeC5hdCgxNSk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTJdID0gYjAgKiBhMDAgKyBiMSAqIGExMCArIGIyICogYTIwICsgYjMgKiBhMzA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTNdID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTRdID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTVdID0gYjAgKiBhMDMgKyBiMSAqIGExMyArIGIyICogYTIzICsgYjMgKiBhMzM7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseVZlYzModmVjdG9yKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgcmV0dXJuIG5ldyB2ZWMzKFtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMF0gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzRdICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s4XSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTJdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1sxXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNV0gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzldICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxM10sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzJdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s2XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTBdICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxNF1cclxuICAgICAgICBdKTtcclxuICAgIH1cclxuICAgIG11bHRpcGx5VmVjNCh2ZWN0b3IsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB2ZWN0b3IudztcclxuICAgICAgICBkZXN0LnggPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1swXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNF0gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzhdICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxMl0gKiB3O1xyXG4gICAgICAgIGRlc3QueSA9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzFdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s1XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbOV0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzEzXSAqIHc7XHJcbiAgICAgICAgZGVzdC56ID1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMl0gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzZdICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxMF0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzE0XSAqIHc7XHJcbiAgICAgICAgZGVzdC53ID1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbM10gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzddICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxMV0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzE1XSAqIHc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICB0b01hdDMoKSB7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBtYXQzKFtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzFdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1syXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbNF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzVdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbOF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzldLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1sxMF1cclxuICAgICAgICBdKTtcclxuICAgIH1cclxuICAgIHRvSW52ZXJzZU1hdDMoKSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbMTBdO1xyXG4gICAgICAgIGNvbnN0IGRldDAxID0gYTIyICogYTExIC0gYTEyICogYTIxO1xyXG4gICAgICAgIGNvbnN0IGRldDExID0gLWEyMiAqIGExMCArIGExMiAqIGEyMDtcclxuICAgICAgICBjb25zdCBkZXQyMSA9IGEyMSAqIGExMCAtIGExMSAqIGEyMDtcclxuICAgICAgICBsZXQgZGV0ID0gYTAwICogZGV0MDEgKyBhMDEgKiBkZXQxMSArIGEwMiAqIGRldDIxO1xyXG4gICAgICAgIGlmICghZGV0KSB7XHJcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXQgPSAxLjAgLyBkZXQ7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBtYXQzKFtcclxuICAgICAgICAgICAgZGV0MDEgKiBkZXQsXHJcbiAgICAgICAgICAgICgtYTIyICogYTAxICsgYTAyICogYTIxKSAqIGRldCxcclxuICAgICAgICAgICAgKGExMiAqIGEwMSAtIGEwMiAqIGExMSkgKiBkZXQsXHJcbiAgICAgICAgICAgIGRldDExICogZGV0LFxyXG4gICAgICAgICAgICAoYTIyICogYTAwIC0gYTAyICogYTIwKSAqIGRldCxcclxuICAgICAgICAgICAgKC1hMTIgKiBhMDAgKyBhMDIgKiBhMTApICogZGV0LFxyXG4gICAgICAgICAgICBkZXQyMSAqIGRldCxcclxuICAgICAgICAgICAgKC1hMjEgKiBhMDAgKyBhMDEgKiBhMjApICogZGV0LFxyXG4gICAgICAgICAgICAoYTExICogYTAwIC0gYTAxICogYTEwKSAqIGRldFxyXG4gICAgICAgIF0pO1xyXG4gICAgfVxyXG4gICAgdHJhbnNsYXRlKHZlY3Rvcikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEyXSArPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1swXSAqIHggKyB0aGlzLnZhbHVlc1s0XSAqIHkgKyB0aGlzLnZhbHVlc1s4XSAqIHo7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTNdICs9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzFdICogeCArIHRoaXMudmFsdWVzWzVdICogeSArIHRoaXMudmFsdWVzWzldICogejtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNF0gKz1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMl0gKiB4ICsgdGhpcy52YWx1ZXNbNl0gKiB5ICsgdGhpcy52YWx1ZXNbMTBdICogejtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNV0gKz1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbM10gKiB4ICsgdGhpcy52YWx1ZXNbN10gKiB5ICsgdGhpcy52YWx1ZXNbMTFdICogejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNjYWxlKHZlY3Rvcikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdICo9IHg7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gKj0geDtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSAqPSB4O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdICo9IHg7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gKj0geTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSAqPSB5O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdICo9IHk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gKj0geTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSAqPSB6O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzldICo9IHo7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTBdICo9IHo7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTFdICo9IHo7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICByb3RhdGUoYW5nbGUsIGF4aXMpIHtcclxuICAgICAgICBsZXQgeCA9IGF4aXMueDtcclxuICAgICAgICBsZXQgeSA9IGF4aXMueTtcclxuICAgICAgICBsZXQgeiA9IGF4aXMuejtcclxuICAgICAgICBsZXQgbGVuZ3RoID0gTWF0aC5zcXJ0KHggKiB4ICsgeSAqIHkgKyB6ICogeik7XHJcbiAgICAgICAgaWYgKCFsZW5ndGgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChsZW5ndGggIT09IDEpIHtcclxuICAgICAgICAgICAgbGVuZ3RoID0gMSAvIGxlbmd0aDtcclxuICAgICAgICAgICAgeCAqPSBsZW5ndGg7XHJcbiAgICAgICAgICAgIHkgKj0gbGVuZ3RoO1xyXG4gICAgICAgICAgICB6ICo9IGxlbmd0aDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcyA9IE1hdGguc2luKGFuZ2xlKTtcclxuICAgICAgICBjb25zdCBjID0gTWF0aC5jb3MoYW5nbGUpO1xyXG4gICAgICAgIGNvbnN0IHQgPSAxLjAgLSBjO1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGEwMyA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGExMyA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzEwXTtcclxuICAgICAgICBjb25zdCBhMjMgPSB0aGlzLnZhbHVlc1sxMV07XHJcbiAgICAgICAgY29uc3QgYjAwID0geCAqIHggKiB0ICsgYztcclxuICAgICAgICBjb25zdCBiMDEgPSB5ICogeCAqIHQgKyB6ICogcztcclxuICAgICAgICBjb25zdCBiMDIgPSB6ICogeCAqIHQgLSB5ICogcztcclxuICAgICAgICBjb25zdCBiMTAgPSB4ICogeSAqIHQgLSB6ICogcztcclxuICAgICAgICBjb25zdCBiMTEgPSB5ICogeSAqIHQgKyBjO1xyXG4gICAgICAgIGNvbnN0IGIxMiA9IHogKiB5ICogdCArIHggKiBzO1xyXG4gICAgICAgIGNvbnN0IGIyMCA9IHggKiB6ICogdCArIHkgKiBzO1xyXG4gICAgICAgIGNvbnN0IGIyMSA9IHkgKiB6ICogdCAtIHggKiBzO1xyXG4gICAgICAgIGNvbnN0IGIyMiA9IHogKiB6ICogdCArIGM7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSBhMDAgKiBiMDAgKyBhMTAgKiBiMDEgKyBhMjAgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSBhMDEgKiBiMDAgKyBhMTEgKiBiMDEgKyBhMjEgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSBhMDIgKiBiMDAgKyBhMTIgKiBiMDEgKyBhMjIgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSBhMDMgKiBiMDAgKyBhMTMgKiBiMDEgKyBhMjMgKiBiMDI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSBhMDAgKiBiMTAgKyBhMTAgKiBiMTEgKyBhMjAgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSBhMDEgKiBiMTAgKyBhMTEgKiBiMTEgKyBhMjEgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSBhMDIgKiBiMTAgKyBhMTIgKiBiMTEgKyBhMjIgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSBhMDMgKiBiMTAgKyBhMTMgKiBiMTEgKyBhMjMgKiBiMTI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSBhMDAgKiBiMjAgKyBhMTAgKiBiMjEgKyBhMjAgKiBiMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOV0gPSBhMDEgKiBiMjAgKyBhMTEgKiBiMjEgKyBhMjEgKiBiMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTBdID0gYTAyICogYjIwICsgYTEyICogYjIxICsgYTIyICogYjIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzExXSA9IGEwMyAqIGIyMCArIGExMyAqIGIyMSArIGEyMyAqIGIyMjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHN0YXRpYyBmcnVzdHVtKGxlZnQsIHJpZ2h0LCBib3R0b20sIHRvcCwgbmVhciwgZmFyKSB7XHJcbiAgICAgICAgY29uc3QgcmwgPSByaWdodCAtIGxlZnQ7XHJcbiAgICAgICAgY29uc3QgdGIgPSB0b3AgLSBib3R0b207XHJcbiAgICAgICAgY29uc3QgZm4gPSBmYXIgLSBuZWFyO1xyXG4gICAgICAgIHJldHVybiBuZXcgbWF0NChbXHJcbiAgICAgICAgICAgIChuZWFyICogMikgLyBybCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgKG5lYXIgKiAyKSAvIHRiLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAocmlnaHQgKyBsZWZ0KSAvIHJsLFxyXG4gICAgICAgICAgICAodG9wICsgYm90dG9tKSAvIHRiLFxyXG4gICAgICAgICAgICAtKGZhciArIG5lYXIpIC8gZm4sXHJcbiAgICAgICAgICAgIC0xLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAtKGZhciAqIG5lYXIgKiAyKSAvIGZuLFxyXG4gICAgICAgICAgICAwXHJcbiAgICAgICAgXSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcGVyc3BlY3RpdmUoZm92LCBhc3BlY3QsIG5lYXIsIGZhcikge1xyXG4gICAgICAgIGNvbnN0IHRvcCA9IG5lYXIgKiBNYXRoLnRhbigoZm92ICogTWF0aC5QSSkgLyAzNjAuMCk7XHJcbiAgICAgICAgY29uc3QgcmlnaHQgPSB0b3AgKiBhc3BlY3Q7XHJcbiAgICAgICAgcmV0dXJuIG1hdDQuZnJ1c3R1bSgtcmlnaHQsIHJpZ2h0LCAtdG9wLCB0b3AsIG5lYXIsIGZhcik7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgb3J0aG9ncmFwaGljKGxlZnQsIHJpZ2h0LCBib3R0b20sIHRvcCwgbmVhciwgZmFyKSB7XHJcbiAgICAgICAgY29uc3QgcmwgPSByaWdodCAtIGxlZnQ7XHJcbiAgICAgICAgY29uc3QgdGIgPSB0b3AgLSBib3R0b207XHJcbiAgICAgICAgY29uc3QgZm4gPSBmYXIgLSBuZWFyO1xyXG4gICAgICAgIHJldHVybiBuZXcgbWF0NChbXHJcbiAgICAgICAgICAgIDIgLyBybCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMiAvIHRiLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAtMiAvIGZuLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAtKGxlZnQgKyByaWdodCkgLyBybCxcclxuICAgICAgICAgICAgLSh0b3AgKyBib3R0b20pIC8gdGIsXHJcbiAgICAgICAgICAgIC0oZmFyICsgbmVhcikgLyBmbixcclxuICAgICAgICAgICAgMVxyXG4gICAgICAgIF0pO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGxvb2tBdChwb3NpdGlvbiwgdGFyZ2V0LCB1cCA9IHZlYzMudXApIHtcclxuICAgICAgICBpZiAocG9zaXRpb24uZXF1YWxzKHRhcmdldCkpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuaWRlbnRpdHk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHogPSB2ZWMzLmRpZmZlcmVuY2UocG9zaXRpb24sIHRhcmdldCkubm9ybWFsaXplKCk7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlYzMuY3Jvc3ModXAsIHopLm5vcm1hbGl6ZSgpO1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWMzLmNyb3NzKHosIHgpLm5vcm1hbGl6ZSgpO1xyXG4gICAgICAgIHJldHVybiBuZXcgbWF0NChbXHJcbiAgICAgICAgICAgIHgueCxcclxuICAgICAgICAgICAgeS54LFxyXG4gICAgICAgICAgICB6LngsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIHgueSxcclxuICAgICAgICAgICAgeS55LFxyXG4gICAgICAgICAgICB6LnksXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIHgueixcclxuICAgICAgICAgICAgeS56LFxyXG4gICAgICAgICAgICB6LnosXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIC12ZWMzLmRvdCh4LCBwb3NpdGlvbiksXHJcbiAgICAgICAgICAgIC12ZWMzLmRvdCh5LCBwb3NpdGlvbiksXHJcbiAgICAgICAgICAgIC12ZWMzLmRvdCh6LCBwb3NpdGlvbiksXHJcbiAgICAgICAgICAgIDFcclxuICAgICAgICBdKTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBwcm9kdWN0KG0xLCBtMiwgcmVzdWx0KSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gbTEuYXQoMCk7XHJcbiAgICAgICAgY29uc3QgYTAxID0gbTEuYXQoMSk7XHJcbiAgICAgICAgY29uc3QgYTAyID0gbTEuYXQoMik7XHJcbiAgICAgICAgY29uc3QgYTAzID0gbTEuYXQoMyk7XHJcbiAgICAgICAgY29uc3QgYTEwID0gbTEuYXQoNCk7XHJcbiAgICAgICAgY29uc3QgYTExID0gbTEuYXQoNSk7XHJcbiAgICAgICAgY29uc3QgYTEyID0gbTEuYXQoNik7XHJcbiAgICAgICAgY29uc3QgYTEzID0gbTEuYXQoNyk7XHJcbiAgICAgICAgY29uc3QgYTIwID0gbTEuYXQoOCk7XHJcbiAgICAgICAgY29uc3QgYTIxID0gbTEuYXQoOSk7XHJcbiAgICAgICAgY29uc3QgYTIyID0gbTEuYXQoMTApO1xyXG4gICAgICAgIGNvbnN0IGEyMyA9IG0xLmF0KDExKTtcclxuICAgICAgICBjb25zdCBhMzAgPSBtMS5hdCgxMik7XHJcbiAgICAgICAgY29uc3QgYTMxID0gbTEuYXQoMTMpO1xyXG4gICAgICAgIGNvbnN0IGEzMiA9IG0xLmF0KDE0KTtcclxuICAgICAgICBjb25zdCBhMzMgPSBtMS5hdCgxNSk7XHJcbiAgICAgICAgY29uc3QgYjAwID0gbTIuYXQoMCk7XHJcbiAgICAgICAgY29uc3QgYjAxID0gbTIuYXQoMSk7XHJcbiAgICAgICAgY29uc3QgYjAyID0gbTIuYXQoMik7XHJcbiAgICAgICAgY29uc3QgYjAzID0gbTIuYXQoMyk7XHJcbiAgICAgICAgY29uc3QgYjEwID0gbTIuYXQoNCk7XHJcbiAgICAgICAgY29uc3QgYjExID0gbTIuYXQoNSk7XHJcbiAgICAgICAgY29uc3QgYjEyID0gbTIuYXQoNik7XHJcbiAgICAgICAgY29uc3QgYjEzID0gbTIuYXQoNyk7XHJcbiAgICAgICAgY29uc3QgYjIwID0gbTIuYXQoOCk7XHJcbiAgICAgICAgY29uc3QgYjIxID0gbTIuYXQoOSk7XHJcbiAgICAgICAgY29uc3QgYjIyID0gbTIuYXQoMTApO1xyXG4gICAgICAgIGNvbnN0IGIyMyA9IG0yLmF0KDExKTtcclxuICAgICAgICBjb25zdCBiMzAgPSBtMi5hdCgxMik7XHJcbiAgICAgICAgY29uc3QgYjMxID0gbTIuYXQoMTMpO1xyXG4gICAgICAgIGNvbnN0IGIzMiA9IG0yLmF0KDE0KTtcclxuICAgICAgICBjb25zdCBiMzMgPSBtMi5hdCgxNSk7XHJcbiAgICAgICAgaWYgKHJlc3VsdCkge1xyXG4gICAgICAgICAgICByZXN1bHQuaW5pdChbXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDAgKyBiMDEgKiBhMTAgKyBiMDIgKiBhMjAgKyBiMDMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDEgKyBiMDEgKiBhMTEgKyBiMDIgKiBhMjEgKyBiMDMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDIgKyBiMDEgKiBhMTIgKyBiMDIgKiBhMjIgKyBiMDMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDMgKyBiMDEgKiBhMTMgKyBiMDIgKiBhMjMgKyBiMDMgKiBhMzMsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDAgKyBiMTEgKiBhMTAgKyBiMTIgKiBhMjAgKyBiMTMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDEgKyBiMTEgKiBhMTEgKyBiMTIgKiBhMjEgKyBiMTMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDIgKyBiMTEgKiBhMTIgKyBiMTIgKiBhMjIgKyBiMTMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDMgKyBiMTEgKiBhMTMgKyBiMTIgKiBhMjMgKyBiMTMgKiBhMzMsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDAgKyBiMjEgKiBhMTAgKyBiMjIgKiBhMjAgKyBiMjMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDEgKyBiMjEgKiBhMTEgKyBiMjIgKiBhMjEgKyBiMjMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDIgKyBiMjEgKiBhMTIgKyBiMjIgKiBhMjIgKyBiMjMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDMgKyBiMjEgKiBhMTMgKyBiMjIgKiBhMjMgKyBiMjMgKiBhMzMsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDAgKyBiMzEgKiBhMTAgKyBiMzIgKiBhMjAgKyBiMzMgKiBhMzAsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDEgKyBiMzEgKiBhMTEgKyBiMzIgKiBhMjEgKyBiMzMgKiBhMzEsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDIgKyBiMzEgKiBhMTIgKyBiMzIgKiBhMjIgKyBiMzMgKiBhMzIsXHJcbiAgICAgICAgICAgICAgICBiMzAgKiBhMDMgKyBiMzEgKiBhMTMgKyBiMzIgKiBhMjMgKyBiMzMgKiBhMzNcclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbmV3IG1hdDQoW1xyXG4gICAgICAgICAgICAgICAgYjAwICogYTAwICsgYjAxICogYTEwICsgYjAyICogYTIwICsgYjAzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAxICsgYjAxICogYTExICsgYjAyICogYTIxICsgYjAzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAyICsgYjAxICogYTEyICsgYjAyICogYTIyICsgYjAzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAzICsgYjAxICogYTEzICsgYjAyICogYTIzICsgYjAzICogYTMzLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAwICsgYjExICogYTEwICsgYjEyICogYTIwICsgYjEzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAxICsgYjExICogYTExICsgYjEyICogYTIxICsgYjEzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAyICsgYjExICogYTEyICsgYjEyICogYTIyICsgYjEzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAzICsgYjExICogYTEzICsgYjEyICogYTIzICsgYjEzICogYTMzLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAwICsgYjIxICogYTEwICsgYjIyICogYTIwICsgYjIzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAxICsgYjIxICogYTExICsgYjIyICogYTIxICsgYjIzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAyICsgYjIxICogYTEyICsgYjIyICogYTIyICsgYjIzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAzICsgYjIxICogYTEzICsgYjIyICogYTIzICsgYjIzICogYTMzLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAwICsgYjMxICogYTEwICsgYjMyICogYTIwICsgYjMzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAxICsgYjMxICogYTExICsgYjMyICogYTIxICsgYjMzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAyICsgYjMxICogYTEyICsgYjMyICogYTIyICsgYjMzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAzICsgYjMxICogYTEzICsgYjMyICogYTIzICsgYjMzICogYTMzXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG5tYXQ0LmlkZW50aXR5ID0gbmV3IG1hdDQoKS5zZXRJZGVudGl0eSgpO1xyXG4iLCJpbXBvcnQgdmVjMyBmcm9tICcuL3ZlYzMnO1xyXG5pbXBvcnQgeyBlcHNpbG9uIH0gZnJvbSAnLi9jb25zdGFudHMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyB2ZWMyIHtcclxuICAgIGNvbnN0cnVjdG9yKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSgyKTtcclxuICAgICAgICBpZiAodmFsdWVzICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy54eSA9IHZhbHVlcztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBnZXQgeCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMF07XHJcbiAgICB9XHJcbiAgICBnZXQgeSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV1dO1xyXG4gICAgfVxyXG4gICAgc2V0IHgodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHkodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgdGhpcy54ID0gMDtcclxuICAgICAgICB0aGlzLnkgPSAwO1xyXG4gICAgfVxyXG4gICAgY29weShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB0aGlzLng7XHJcbiAgICAgICAgZGVzdC55ID0gdGhpcy55O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbmVnYXRlKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IC10aGlzLng7XHJcbiAgICAgICAgZGVzdC55ID0gLXRoaXMueTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIGVxdWFscyh2ZWN0b3IsIHRocmVzaG9sZCA9IGVwc2lsb24pIHtcclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy54IC0gdmVjdG9yLngpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueSAtIHZlY3Rvci55KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgbGVuZ3RoKCkge1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkTGVuZ3RoKCkpO1xyXG4gICAgfVxyXG4gICAgc3F1YXJlZExlbmd0aCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgcmV0dXJuIHggKiB4ICsgeSAqIHk7XHJcbiAgICB9XHJcbiAgICBhZGQodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54ICs9IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSArPSB2ZWN0b3IueTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHN1YnRyYWN0KHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAtPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgLT0gdmVjdG9yLnk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggKj0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55ICo9IHZlY3Rvci55O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgZGl2aWRlKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAvPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgLz0gdmVjdG9yLnk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzY2FsZSh2YWx1ZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ICo9IHZhbHVlO1xyXG4gICAgICAgIGRlc3QueSAqPSB2YWx1ZTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG5vcm1hbGl6ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcclxuICAgICAgICBpZiAobGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueSA9IDA7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZW5ndGggPSAxLjAgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ICo9IGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgKj0gbGVuZ3RoO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlNYXQyKG1hdHJpeCwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIG1hdHJpeC5tdWx0aXBseVZlYzIodGhpcywgZGVzdCk7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseU1hdDMobWF0cml4LCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gbWF0cml4Lm11bHRpcGx5VmVjMih0aGlzLCBkZXN0KTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBjcm9zcyh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeDIgPSB2ZWN0b3IyLng7XHJcbiAgICAgICAgY29uc3QgeTIgPSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHggKiB5MiAtIHkgKiB4MjtcclxuICAgICAgICBkZXN0LnggPSAwO1xyXG4gICAgICAgIGRlc3QueSA9IDA7XHJcbiAgICAgICAgZGVzdC56ID0gejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkb3QodmVjdG9yLCB2ZWN0b3IyKSB7XHJcbiAgICAgICAgcmV0dXJuIHZlY3Rvci54ICogdmVjdG9yMi54ICsgdmVjdG9yLnkgKiB2ZWN0b3IyLnk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCh0aGlzLnNxdWFyZWREaXN0YW5jZSh2ZWN0b3IsIHZlY3RvcjIpKTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBzcXVhcmVkRGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3RvcjIueCAtIHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IyLnkgLSB2ZWN0b3IueTtcclxuICAgICAgICByZXR1cm4geCAqIHggKyB5ICogeTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBkaXJlY3Rpb24odmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLnggLSB2ZWN0b3IyLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55IC0gdmVjdG9yMi55O1xyXG4gICAgICAgIGxldCBsZW5ndGggPSBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSk7XHJcbiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICBkZXN0LnggPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnkgPSAwO1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGVuZ3RoID0gMSAvIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnggPSB4ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueSA9IHkgKiBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgbWl4KHZlY3RvciwgdmVjdG9yMiwgdGltZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB4MiA9IHZlY3RvcjIueDtcclxuICAgICAgICBjb25zdCB5MiA9IHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnggPSB4ICsgdGltZSAqICh4MiAtIHgpO1xyXG4gICAgICAgIGRlc3QueSA9IHkgKyB0aW1lICogKHkyIC0geSk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3VtKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlmZmVyZW5jZSh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC0gdmVjdG9yMi55O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAqIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAqIHZlY3RvcjIueTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBxdW90aWVudCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC8gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC8gdmVjdG9yMi55O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG59XHJcbnZlYzIuemVybyA9IG5ldyB2ZWMyKFswLCAwXSk7XHJcbnZlYzIub25lID0gbmV3IHZlYzIoWzEsIDFdKTtcclxuIiwiaW1wb3J0IG1hdDQgZnJvbSAnLi9tYXQ0JztcclxuaW1wb3J0IHF1YXQgZnJvbSAnLi9xdWF0JztcclxuaW1wb3J0IHZlYzIgZnJvbSAnLi92ZWMyJztcclxuaW1wb3J0IHZlYzMgZnJvbSAnLi92ZWMzJztcclxuaW1wb3J0IHsgZXBzaWxvbiB9IGZyb20gJy4vY29uc3RhbnRzJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgbWF0MyB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoOSk7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuaW5pdCh2YWx1ZXMpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGF0KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzW2luZGV4XTtcclxuICAgIH1cclxuICAgIGluaXQodmFsdWVzKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA5OyBpKyspIHtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaV0gPSB2YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA5OyBpKyspIHtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaV0gPSAwO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGNvcHkoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IG1hdDMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA5OyBpKyspIHtcclxuICAgICAgICAgICAgZGVzdC52YWx1ZXNbaV0gPSB0aGlzLnZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBhbGwoKSB7XHJcbiAgICAgICAgY29uc3QgZGF0YSA9IFtdO1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgOTsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRhdGFbaV0gPSB0aGlzLnZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGRhdGE7XHJcbiAgICB9XHJcbiAgICByb3coaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDMgKyAwXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiAzICsgMV0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogMyArIDJdXHJcbiAgICAgICAgXTtcclxuICAgIH1cclxuICAgIGNvbChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbaW5kZXhdLCB0aGlzLnZhbHVlc1tpbmRleCArIDNdLCB0aGlzLnZhbHVlc1tpbmRleCArIDZdXTtcclxuICAgIH1cclxuICAgIGVxdWFscyhtYXRyaXgsIHRocmVzaG9sZCA9IGVwc2lsb24pIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDk7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoTWF0aC5hYnModGhpcy52YWx1ZXNbaV0gLSBtYXRyaXguYXQoaSkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBkZXRlcm1pbmFudCgpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBkZXQwMSA9IGEyMiAqIGExMSAtIGExMiAqIGEyMTtcclxuICAgICAgICBjb25zdCBkZXQxMSA9IC1hMjIgKiBhMTAgKyBhMTIgKiBhMjA7XHJcbiAgICAgICAgY29uc3QgZGV0MjEgPSBhMjEgKiBhMTAgLSBhMTEgKiBhMjA7XHJcbiAgICAgICAgcmV0dXJuIGEwMCAqIGRldDAxICsgYTAxICogZGV0MTEgKyBhMDIgKiBkZXQyMTtcclxuICAgIH1cclxuICAgIHNldElkZW50aXR5KCkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSAxO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgdHJhbnNwb3NlKCkge1xyXG4gICAgICAgIGNvbnN0IHRlbXAwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IHRlbXAwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IHRlbXAxMiA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHRlbXAwMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gdGVtcDAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gdGVtcDEyO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgaW52ZXJzZSgpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBkZXQwMSA9IGEyMiAqIGExMSAtIGExMiAqIGEyMTtcclxuICAgICAgICBjb25zdCBkZXQxMSA9IC1hMjIgKiBhMTAgKyBhMTIgKiBhMjA7XHJcbiAgICAgICAgY29uc3QgZGV0MjEgPSBhMjEgKiBhMTAgLSBhMTEgKiBhMjA7XHJcbiAgICAgICAgbGV0IGRldCA9IGEwMCAqIGRldDAxICsgYTAxICogZGV0MTEgKyBhMDIgKiBkZXQyMTtcclxuICAgICAgICBpZiAoIWRldCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGV0ID0gMS4wIC8gZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gZGV0MDEgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSAoLWEyMiAqIGEwMSArIGEwMiAqIGEyMSkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSAoYTEyICogYTAxIC0gYTAyICogYTExKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IGRldDExICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gKGEyMiAqIGEwMCAtIGEwMiAqIGEyMCkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSAoLWExMiAqIGEwMCArIGEwMiAqIGExMCkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSBkZXQyMSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9ICgtYTIxICogYTAwICsgYTAxICogYTIwKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IChhMTEgKiBhMDAgLSBhMDEgKiBhMTApICogZGV0O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHkobWF0cml4KSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYjAwID0gbWF0cml4LmF0KDApO1xyXG4gICAgICAgIGNvbnN0IGIwMSA9IG1hdHJpeC5hdCgxKTtcclxuICAgICAgICBjb25zdCBiMDIgPSBtYXRyaXguYXQoMik7XHJcbiAgICAgICAgY29uc3QgYjEwID0gbWF0cml4LmF0KDMpO1xyXG4gICAgICAgIGNvbnN0IGIxMSA9IG1hdHJpeC5hdCg0KTtcclxuICAgICAgICBjb25zdCBiMTIgPSBtYXRyaXguYXQoNSk7XHJcbiAgICAgICAgY29uc3QgYjIwID0gbWF0cml4LmF0KDYpO1xyXG4gICAgICAgIGNvbnN0IGIyMSA9IG1hdHJpeC5hdCg3KTtcclxuICAgICAgICBjb25zdCBiMjIgPSBtYXRyaXguYXQoOCk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSBiMDAgKiBhMDAgKyBiMDEgKiBhMTAgKyBiMDIgKiBhMjA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSBiMDAgKiBhMDEgKyBiMDEgKiBhMTEgKyBiMDIgKiBhMjE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSBiMDAgKiBhMDIgKyBiMDEgKiBhMTIgKyBiMDIgKiBhMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSBiMTAgKiBhMDAgKyBiMTEgKiBhMTAgKyBiMTIgKiBhMjA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSBiMTAgKiBhMDEgKyBiMTEgKiBhMTEgKyBiMTIgKiBhMjE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSBiMTAgKiBhMDIgKyBiMTEgKiBhMTIgKyBiMTIgKiBhMjI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNl0gPSBiMjAgKiBhMDAgKyBiMjEgKiBhMTAgKyBiMjIgKiBhMjA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSBiMjAgKiBhMDEgKyBiMjEgKiBhMTEgKyBiMjIgKiBhMjE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSBiMjAgKiBhMDIgKyBiMjEgKiBhMTIgKyBiMjIgKiBhMjI7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseVZlYzIodmVjdG9yLCByZXN1bHQpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGlmIChyZXN1bHQpIHtcclxuICAgICAgICAgICAgcmVzdWx0Lnh5ID0gW1xyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzBdICsgeSAqIHRoaXMudmFsdWVzWzNdICsgdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMV0gKyB5ICogdGhpcy52YWx1ZXNbNF0gKyB0aGlzLnZhbHVlc1s3XVxyXG4gICAgICAgICAgICBdO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyB2ZWMyKFtcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1swXSArIHkgKiB0aGlzLnZhbHVlc1szXSArIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzFdICsgeSAqIHRoaXMudmFsdWVzWzRdICsgdGhpcy52YWx1ZXNbN11cclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlWZWMzKHZlY3RvciwgcmVzdWx0KSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgaWYgKHJlc3VsdCkge1xyXG4gICAgICAgICAgICByZXN1bHQueHl6ID0gW1xyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzBdICsgeSAqIHRoaXMudmFsdWVzWzNdICsgeiAqIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzFdICsgeSAqIHRoaXMudmFsdWVzWzRdICsgeiAqIHRoaXMudmFsdWVzWzddLFxyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzJdICsgeSAqIHRoaXMudmFsdWVzWzVdICsgeiAqIHRoaXMudmFsdWVzWzhdXHJcbiAgICAgICAgICAgIF07XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbmV3IHZlYzMoW1xyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzBdICsgeSAqIHRoaXMudmFsdWVzWzNdICsgeiAqIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzFdICsgeSAqIHRoaXMudmFsdWVzWzRdICsgeiAqIHRoaXMudmFsdWVzWzddLFxyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzJdICsgeSAqIHRoaXMudmFsdWVzWzVdICsgeiAqIHRoaXMudmFsdWVzWzhdXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHRvTWF0NChyZXN1bHQpIHtcclxuICAgICAgICBpZiAocmVzdWx0KSB7XHJcbiAgICAgICAgICAgIHJlc3VsdC5pbml0KFtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzBdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMV0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1syXSxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1szXSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzRdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNV0sXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s3XSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzhdLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDFcclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbmV3IG1hdDQoW1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMF0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxXSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzJdLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzNdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNF0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s1XSxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzddLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbOF0sXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMVxyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICB0b1F1YXQoKSB7XHJcbiAgICAgICAgY29uc3QgbTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgbTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgbTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgbTEwID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgbTExID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgbTEyID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgbTIwID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgbTIxID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgbTIyID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgZm91clhTcXVhcmVkTWludXMxID0gbTAwIC0gbTExIC0gbTIyO1xyXG4gICAgICAgIGNvbnN0IGZvdXJZU3F1YXJlZE1pbnVzMSA9IG0xMSAtIG0wMCAtIG0yMjtcclxuICAgICAgICBjb25zdCBmb3VyWlNxdWFyZWRNaW51czEgPSBtMjIgLSBtMDAgLSBtMTE7XHJcbiAgICAgICAgY29uc3QgZm91cldTcXVhcmVkTWludXMxID0gbTAwICsgbTExICsgbTIyO1xyXG4gICAgICAgIGxldCBiaWdnZXN0SW5kZXggPSAwO1xyXG4gICAgICAgIGxldCBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEgPSBmb3VyV1NxdWFyZWRNaW51czE7XHJcbiAgICAgICAgaWYgKGZvdXJYU3F1YXJlZE1pbnVzMSA+IGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSkge1xyXG4gICAgICAgICAgICBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEgPSBmb3VyWFNxdWFyZWRNaW51czE7XHJcbiAgICAgICAgICAgIGJpZ2dlc3RJbmRleCA9IDE7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChmb3VyWVNxdWFyZWRNaW51czEgPiBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEpIHtcclxuICAgICAgICAgICAgZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxID0gZm91cllTcXVhcmVkTWludXMxO1xyXG4gICAgICAgICAgICBiaWdnZXN0SW5kZXggPSAyO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZm91clpTcXVhcmVkTWludXMxID4gZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxKSB7XHJcbiAgICAgICAgICAgIGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSA9IGZvdXJaU3F1YXJlZE1pbnVzMTtcclxuICAgICAgICAgICAgYmlnZ2VzdEluZGV4ID0gMztcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgYmlnZ2VzdFZhbCA9IE1hdGguc3FydChmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEgKyAxKSAqIDAuNTtcclxuICAgICAgICBjb25zdCBtdWx0ID0gMC4yNSAvIGJpZ2dlc3RWYWw7XHJcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICBzd2l0Y2ggKGJpZ2dlc3RJbmRleCkge1xyXG4gICAgICAgICAgICBjYXNlIDA6XHJcbiAgICAgICAgICAgICAgICByZXN1bHQudyA9IGJpZ2dlc3RWYWw7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueCA9IChtMTIgLSBtMjEpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC55ID0gKG0yMCAtIG0wMikgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnogPSAobTAxIC0gbTEwKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSAxOlxyXG4gICAgICAgICAgICAgICAgcmVzdWx0LncgPSAobTEyIC0gbTIxKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueCA9IGJpZ2dlc3RWYWw7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueSA9IChtMDEgKyBtMTApICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC56ID0gKG0yMCArIG0wMikgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgMjpcclxuICAgICAgICAgICAgICAgIHJlc3VsdC53ID0gKG0yMCAtIG0wMikgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnggPSAobTAxICsgbTEwKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueSA9IGJpZ2dlc3RWYWw7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueiA9IChtMTIgKyBtMjEpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlIDM6XHJcbiAgICAgICAgICAgICAgICByZXN1bHQudyA9IChtMDEgLSBtMTApICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC54ID0gKG0yMCArIG0wMikgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnkgPSAobTEyICsgbTIxKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueiA9IGJpZ2dlc3RWYWw7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH1cclxuICAgIHJvdGF0ZShhbmdsZSwgYXhpcykge1xyXG4gICAgICAgIGxldCB4ID0gYXhpcy54O1xyXG4gICAgICAgIGxldCB5ID0gYXhpcy55O1xyXG4gICAgICAgIGxldCB6ID0gYXhpcy56O1xyXG4gICAgICAgIGxldCBsZW5ndGggPSBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSArIHogKiB6KTtcclxuICAgICAgICBpZiAoIWxlbmd0aCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGxlbmd0aCAhPT0gMSkge1xyXG4gICAgICAgICAgICBsZW5ndGggPSAxIC8gbGVuZ3RoO1xyXG4gICAgICAgICAgICB4ICo9IGxlbmd0aDtcclxuICAgICAgICAgICAgeSAqPSBsZW5ndGg7XHJcbiAgICAgICAgICAgIHogKj0gbGVuZ3RoO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBzID0gTWF0aC5zaW4oYW5nbGUpO1xyXG4gICAgICAgIGNvbnN0IGMgPSBNYXRoLmNvcyhhbmdsZSk7XHJcbiAgICAgICAgY29uc3QgdCA9IDEuMCAtIGM7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbMTBdO1xyXG4gICAgICAgIGNvbnN0IGIwMCA9IHggKiB4ICogdCArIGM7XHJcbiAgICAgICAgY29uc3QgYjAxID0geSAqIHggKiB0ICsgeiAqIHM7XHJcbiAgICAgICAgY29uc3QgYjAyID0geiAqIHggKiB0IC0geSAqIHM7XHJcbiAgICAgICAgY29uc3QgYjEwID0geCAqIHkgKiB0IC0geiAqIHM7XHJcbiAgICAgICAgY29uc3QgYjExID0geSAqIHkgKiB0ICsgYztcclxuICAgICAgICBjb25zdCBiMTIgPSB6ICogeSAqIHQgKyB4ICogcztcclxuICAgICAgICBjb25zdCBiMjAgPSB4ICogeiAqIHQgKyB5ICogcztcclxuICAgICAgICBjb25zdCBiMjEgPSB5ICogeiAqIHQgLSB4ICogcztcclxuICAgICAgICBjb25zdCBiMjIgPSB6ICogeiAqIHQgKyBjO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gYTAwICogYjAwICsgYTEwICogYjAxICsgYTIwICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gYTAxICogYjAwICsgYTExICogYjAxICsgYTIxICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gYTAyICogYjAwICsgYTEyICogYjAxICsgYTIyICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gYTAwICogYjEwICsgYTEwICogYjExICsgYTIwICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gYTAxICogYjEwICsgYTExICogYjExICsgYTIxICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gYTAyICogYjEwICsgYTEyICogYjExICsgYTIyICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gYTAwICogYjIwICsgYTEwICogYjIxICsgYTIwICogYjIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gYTAxICogYjIwICsgYTExICogYjIxICsgYTIxICogYjIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gYTAyICogYjIwICsgYTEyICogYjIxICsgYTIyICogYjIyO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QobTEsIG0yLCByZXN1bHQpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSBtMS5hdCgwKTtcclxuICAgICAgICBjb25zdCBhMDEgPSBtMS5hdCgxKTtcclxuICAgICAgICBjb25zdCBhMDIgPSBtMS5hdCgyKTtcclxuICAgICAgICBjb25zdCBhMTAgPSBtMS5hdCgzKTtcclxuICAgICAgICBjb25zdCBhMTEgPSBtMS5hdCg0KTtcclxuICAgICAgICBjb25zdCBhMTIgPSBtMS5hdCg1KTtcclxuICAgICAgICBjb25zdCBhMjAgPSBtMS5hdCg2KTtcclxuICAgICAgICBjb25zdCBhMjEgPSBtMS5hdCg3KTtcclxuICAgICAgICBjb25zdCBhMjIgPSBtMS5hdCg4KTtcclxuICAgICAgICBjb25zdCBiMDAgPSBtMi5hdCgwKTtcclxuICAgICAgICBjb25zdCBiMDEgPSBtMi5hdCgxKTtcclxuICAgICAgICBjb25zdCBiMDIgPSBtMi5hdCgyKTtcclxuICAgICAgICBjb25zdCBiMTAgPSBtMi5hdCgzKTtcclxuICAgICAgICBjb25zdCBiMTEgPSBtMi5hdCg0KTtcclxuICAgICAgICBjb25zdCBiMTIgPSBtMi5hdCg1KTtcclxuICAgICAgICBjb25zdCBiMjAgPSBtMi5hdCg2KTtcclxuICAgICAgICBjb25zdCBiMjEgPSBtMi5hdCg3KTtcclxuICAgICAgICBjb25zdCBiMjIgPSBtMi5hdCg4KTtcclxuICAgICAgICBpZiAocmVzdWx0KSB7XHJcbiAgICAgICAgICAgIHJlc3VsdC5pbml0KFtcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMCArIGIwMSAqIGExMCArIGIwMiAqIGEyMCxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMSArIGIwMSAqIGExMSArIGIwMiAqIGEyMSxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMiArIGIwMSAqIGExMiArIGIwMiAqIGEyMixcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMCArIGIxMSAqIGExMCArIGIxMiAqIGEyMCxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMSArIGIxMSAqIGExMSArIGIxMiAqIGEyMSxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMiArIGIxMSAqIGExMiArIGIxMiAqIGEyMixcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMCArIGIyMSAqIGExMCArIGIyMiAqIGEyMCxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMSArIGIyMSAqIGExMSArIGIyMiAqIGEyMSxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMiArIGIyMSAqIGExMiArIGIyMiAqIGEyMlxyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXcgbWF0MyhbXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDAgKyBiMDEgKiBhMTAgKyBiMDIgKiBhMjAsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDEgKyBiMDEgKiBhMTEgKyBiMDIgKiBhMjEsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDIgKyBiMDEgKiBhMTIgKyBiMDIgKiBhMjIsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDAgKyBiMTEgKiBhMTAgKyBiMTIgKiBhMjAsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDEgKyBiMTEgKiBhMTEgKyBiMTIgKiBhMjEsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDIgKyBiMTEgKiBhMTIgKyBiMTIgKiBhMjIsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDAgKyBiMjEgKiBhMTAgKyBiMjIgKiBhMjAsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDEgKyBiMjEgKiBhMTEgKyBiMjIgKiBhMjEsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDIgKyBiMjEgKiBhMTIgKyBiMjIgKiBhMjJcclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbm1hdDMuaWRlbnRpdHkgPSBuZXcgbWF0MygpLnNldElkZW50aXR5KCk7XHJcbiIsImltcG9ydCBtYXQzIGZyb20gJy4vbWF0Myc7XHJcbmltcG9ydCBtYXQ0IGZyb20gJy4vbWF0NCc7XHJcbmltcG9ydCB2ZWMzIGZyb20gJy4vdmVjMyc7XHJcbmltcG9ydCB7IGVwc2lsb24gfSBmcm9tICcuL2NvbnN0YW50cyc7XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIHF1YXQge1xyXG4gICAgY29uc3RydWN0b3IodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KDQpO1xyXG4gICAgICAgIGlmICh2YWx1ZXMgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICB0aGlzLnh5encgPSB2YWx1ZXM7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZ2V0IHgoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzBdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHooKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHcoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzNdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdXTtcclxuICAgIH1cclxuICAgIGdldCB4eXooKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdXTtcclxuICAgIH1cclxuICAgIGdldCB4eXp3KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXSwgdGhpcy52YWx1ZXNbM11dO1xyXG4gICAgfVxyXG4gICAgc2V0IHgodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHkodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHoodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHcodmFsdWUpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5eih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIHNldCB4eXp3KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdmFsdWVzWzNdO1xyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA0OyBpKyspIHtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaV0gPSAwO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGNvcHkoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA0OyBpKyspIHtcclxuICAgICAgICAgICAgZGVzdC52YWx1ZXNbaV0gPSB0aGlzLnZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICByb2xsKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguYXRhbjIoMi4wICogKHggKiB5ICsgdyAqIHopLCB3ICogdyArIHggKiB4IC0geSAqIHkgLSB6ICogeik7XHJcbiAgICB9XHJcbiAgICBwaXRjaCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIHJldHVybiBNYXRoLmF0YW4yKDIuMCAqICh5ICogeiArIHcgKiB4KSwgdyAqIHcgLSB4ICogeCAtIHkgKiB5ICsgeiAqIHopO1xyXG4gICAgfVxyXG4gICAgeWF3KCkge1xyXG4gICAgICAgIHJldHVybiBNYXRoLmFzaW4oMi4wICogKHRoaXMueCAqIHRoaXMueiAtIHRoaXMudyAqIHRoaXMueSkpO1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKHZlY3RvciwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnZhbHVlc1tpXSAtIHZlY3Rvci5hdChpKSkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIHNldElkZW50aXR5KCkge1xyXG4gICAgICAgIHRoaXMueCA9IDA7XHJcbiAgICAgICAgdGhpcy55ID0gMDtcclxuICAgICAgICB0aGlzLnogPSAwO1xyXG4gICAgICAgIHRoaXMudyA9IDE7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBjYWxjdWxhdGVXKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIHRoaXMudyA9IC1NYXRoLnNxcnQoTWF0aC5hYnMoMS4wIC0geCAqIHggLSB5ICogeSAtIHogKiB6KSk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBpbnZlcnNlKCkge1xyXG4gICAgICAgIGNvbnN0IGRvdCA9IHF1YXQuZG90KHRoaXMsIHRoaXMpO1xyXG4gICAgICAgIGlmICghZG90KSB7XHJcbiAgICAgICAgICAgIHRoaXMueHl6dyA9IFswLCAwLCAwLCAwXTtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGludkRvdCA9IGRvdCA/IDEuMCAvIGRvdCA6IDA7XHJcbiAgICAgICAgdGhpcy54ICo9IC1pbnZEb3Q7XHJcbiAgICAgICAgdGhpcy55ICo9IC1pbnZEb3Q7XHJcbiAgICAgICAgdGhpcy56ICo9IC1pbnZEb3Q7XHJcbiAgICAgICAgdGhpcy53ICo9IGludkRvdDtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGNvbmp1Z2F0ZSgpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSAqPSAtMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSAqPSAtMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSAqPSAtMTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGxlbmd0aCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSArIHogKiB6ICsgdyAqIHcpO1xyXG4gICAgfVxyXG4gICAgbm9ybWFsaXplKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogdyk7XHJcbiAgICAgICAgaWYgKCFsZW5ndGgpIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICAgICAgZGVzdC56ID0gMDtcclxuICAgICAgICAgICAgZGVzdC53ID0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ID0geCAqIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgPSB5ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueiA9IHogKiBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC53ID0gdyAqIGxlbmd0aDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIGFkZChvdGhlcikge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNDsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2ldICs9IG90aGVyLmF0KGkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5KG90aGVyKSB7XHJcbiAgICAgICAgY29uc3QgcTF4ID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgcTF5ID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgcTF6ID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgcTF3ID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgcTJ4ID0gb3RoZXIueDtcclxuICAgICAgICBjb25zdCBxMnkgPSBvdGhlci55O1xyXG4gICAgICAgIGNvbnN0IHEyeiA9IG90aGVyLno7XHJcbiAgICAgICAgY29uc3QgcTJ3ID0gb3RoZXIudztcclxuICAgICAgICB0aGlzLnggPSBxMXggKiBxMncgKyBxMXcgKiBxMnggKyBxMXkgKiBxMnogLSBxMXogKiBxMnk7XHJcbiAgICAgICAgdGhpcy55ID0gcTF5ICogcTJ3ICsgcTF3ICogcTJ5ICsgcTF6ICogcTJ4IC0gcTF4ICogcTJ6O1xyXG4gICAgICAgIHRoaXMueiA9IHExeiAqIHEydyArIHExdyAqIHEyeiArIHExeCAqIHEyeSAtIHExeSAqIHEyeDtcclxuICAgICAgICB0aGlzLncgPSBxMXcgKiBxMncgLSBxMXggKiBxMnggLSBxMXkgKiBxMnkgLSBxMXogKiBxMno7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseVZlYzModmVjdG9yLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICBjb25zdCBxeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCBxeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCBxeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCBxdyA9IHRoaXMudztcclxuICAgICAgICBjb25zdCBpeCA9IHF3ICogeCArIHF5ICogeiAtIHF6ICogeTtcclxuICAgICAgICBjb25zdCBpeSA9IHF3ICogeSArIHF6ICogeCAtIHF4ICogejtcclxuICAgICAgICBjb25zdCBpeiA9IHF3ICogeiArIHF4ICogeSAtIHF5ICogeDtcclxuICAgICAgICBjb25zdCBpdyA9IC1xeCAqIHggLSBxeSAqIHkgLSBxeiAqIHo7XHJcbiAgICAgICAgZGVzdC54ID0gaXggKiBxdyArIGl3ICogLXF4ICsgaXkgKiAtcXogLSBpeiAqIC1xeTtcclxuICAgICAgICBkZXN0LnkgPSBpeSAqIHF3ICsgaXcgKiAtcXkgKyBpeiAqIC1xeCAtIGl4ICogLXF6O1xyXG4gICAgICAgIGRlc3QueiA9IGl6ICogcXcgKyBpdyAqIC1xeiArIGl4ICogLXF5IC0gaXkgKiAtcXg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICB0b01hdDMoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IG1hdDMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICBjb25zdCB4MiA9IHggKyB4O1xyXG4gICAgICAgIGNvbnN0IHkyID0geSArIHk7XHJcbiAgICAgICAgY29uc3QgejIgPSB6ICsgejtcclxuICAgICAgICBjb25zdCB4eCA9IHggKiB4MjtcclxuICAgICAgICBjb25zdCB4eSA9IHggKiB5MjtcclxuICAgICAgICBjb25zdCB4eiA9IHggKiB6MjtcclxuICAgICAgICBjb25zdCB5eSA9IHkgKiB5MjtcclxuICAgICAgICBjb25zdCB5eiA9IHkgKiB6MjtcclxuICAgICAgICBjb25zdCB6eiA9IHogKiB6MjtcclxuICAgICAgICBjb25zdCB3eCA9IHcgKiB4MjtcclxuICAgICAgICBjb25zdCB3eSA9IHcgKiB5MjtcclxuICAgICAgICBjb25zdCB3eiA9IHcgKiB6MjtcclxuICAgICAgICBkZXN0LmluaXQoW1xyXG4gICAgICAgICAgICAxIC0gKHl5ICsgenopLFxyXG4gICAgICAgICAgICB4eSArIHd6LFxyXG4gICAgICAgICAgICB4eiAtIHd5LFxyXG4gICAgICAgICAgICB4eSAtIHd6LFxyXG4gICAgICAgICAgICAxIC0gKHh4ICsgenopLFxyXG4gICAgICAgICAgICB5eiArIHd4LFxyXG4gICAgICAgICAgICB4eiArIHd5LFxyXG4gICAgICAgICAgICB5eiAtIHd4LFxyXG4gICAgICAgICAgICAxIC0gKHh4ICsgeXkpXHJcbiAgICAgICAgXSk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICB0b01hdDQoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IG1hdDQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICBjb25zdCB4MiA9IHggKyB4O1xyXG4gICAgICAgIGNvbnN0IHkyID0geSArIHk7XHJcbiAgICAgICAgY29uc3QgejIgPSB6ICsgejtcclxuICAgICAgICBjb25zdCB4eCA9IHggKiB4MjtcclxuICAgICAgICBjb25zdCB4eSA9IHggKiB5MjtcclxuICAgICAgICBjb25zdCB4eiA9IHggKiB6MjtcclxuICAgICAgICBjb25zdCB5eSA9IHkgKiB5MjtcclxuICAgICAgICBjb25zdCB5eiA9IHkgKiB6MjtcclxuICAgICAgICBjb25zdCB6eiA9IHogKiB6MjtcclxuICAgICAgICBjb25zdCB3eCA9IHcgKiB4MjtcclxuICAgICAgICBjb25zdCB3eSA9IHcgKiB5MjtcclxuICAgICAgICBjb25zdCB3eiA9IHcgKiB6MjtcclxuICAgICAgICBkZXN0LmluaXQoW1xyXG4gICAgICAgICAgICAxIC0gKHl5ICsgenopLFxyXG4gICAgICAgICAgICB4eSArIHd6LFxyXG4gICAgICAgICAgICB4eiAtIHd5LFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICB4eSAtIHd6LFxyXG4gICAgICAgICAgICAxIC0gKHh4ICsgenopLFxyXG4gICAgICAgICAgICB5eiArIHd4LFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICB4eiArIHd5LFxyXG4gICAgICAgICAgICB5eiAtIHd4LFxyXG4gICAgICAgICAgICAxIC0gKHh4ICsgeXkpLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAxXHJcbiAgICAgICAgXSk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZG90KHExLCBxMikge1xyXG4gICAgICAgIHJldHVybiBxMS54ICogcTIueCArIHExLnkgKiBxMi55ICsgcTEueiAqIHEyLnogKyBxMS53ICogcTIudztcclxuICAgIH1cclxuICAgIHN0YXRpYyBzdW0ocTEsIHEyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSBxMS54ICsgcTIueDtcclxuICAgICAgICBkZXN0LnkgPSBxMS55ICsgcTIueTtcclxuICAgICAgICBkZXN0LnogPSBxMS56ICsgcTIuejtcclxuICAgICAgICBkZXN0LncgPSBxMS53ICsgcTIudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBwcm9kdWN0KHExLCBxMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcTF4ID0gcTEueDtcclxuICAgICAgICBjb25zdCBxMXkgPSBxMS55O1xyXG4gICAgICAgIGNvbnN0IHExeiA9IHExLno7XHJcbiAgICAgICAgY29uc3QgcTF3ID0gcTEudztcclxuICAgICAgICBjb25zdCBxMnggPSBxMi54O1xyXG4gICAgICAgIGNvbnN0IHEyeSA9IHEyLnk7XHJcbiAgICAgICAgY29uc3QgcTJ6ID0gcTIuejtcclxuICAgICAgICBjb25zdCBxMncgPSBxMi53O1xyXG4gICAgICAgIGRlc3QueCA9IHExeCAqIHEydyArIHExdyAqIHEyeCArIHExeSAqIHEyeiAtIHExeiAqIHEyeTtcclxuICAgICAgICBkZXN0LnkgPSBxMXkgKiBxMncgKyBxMXcgKiBxMnkgKyBxMXogKiBxMnggLSBxMXggKiBxMno7XHJcbiAgICAgICAgZGVzdC56ID0gcTF6ICogcTJ3ICsgcTF3ICogcTJ6ICsgcTF4ICogcTJ5IC0gcTF5ICogcTJ4O1xyXG4gICAgICAgIGRlc3QudyA9IHExdyAqIHEydyAtIHExeCAqIHEyeCAtIHExeSAqIHEyeSAtIHExeiAqIHEyejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBjcm9zcyhxMSwgcTIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHExeCA9IHExLng7XHJcbiAgICAgICAgY29uc3QgcTF5ID0gcTEueTtcclxuICAgICAgICBjb25zdCBxMXogPSBxMS56O1xyXG4gICAgICAgIGNvbnN0IHExdyA9IHExLnc7XHJcbiAgICAgICAgY29uc3QgcTJ4ID0gcTIueDtcclxuICAgICAgICBjb25zdCBxMnkgPSBxMi55O1xyXG4gICAgICAgIGNvbnN0IHEyeiA9IHEyLno7XHJcbiAgICAgICAgY29uc3QgcTJ3ID0gcTIudztcclxuICAgICAgICBkZXN0LnggPSBxMXcgKiBxMnogKyBxMXogKiBxMncgKyBxMXggKiBxMnkgLSBxMXkgKiBxMng7XHJcbiAgICAgICAgZGVzdC55ID0gcTF3ICogcTJ3IC0gcTF4ICogcTJ4IC0gcTF5ICogcTJ5IC0gcTF6ICogcTJ6O1xyXG4gICAgICAgIGRlc3QueiA9IHExdyAqIHEyeCArIHExeCAqIHEydyArIHExeSAqIHEyeiAtIHExeiAqIHEyeTtcclxuICAgICAgICBkZXN0LncgPSBxMXcgKiBxMnkgKyBxMXkgKiBxMncgKyBxMXogKiBxMnggLSBxMXggKiBxMno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc2hvcnRNaXgocTEsIHEyLCB0aW1lLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodGltZSA8PSAwLjApIHtcclxuICAgICAgICAgICAgZGVzdC54eXp3ID0gcTEueHl6dztcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2UgaWYgKHRpbWUgPj0gMS4wKSB7XHJcbiAgICAgICAgICAgIGRlc3QueHl6dyA9IHEyLnh5enc7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgY29zID0gcXVhdC5kb3QocTEsIHEyKTtcclxuICAgICAgICBjb25zdCBxMmEgPSBxMi5jb3B5KCk7XHJcbiAgICAgICAgaWYgKGNvcyA8IDAuMCkge1xyXG4gICAgICAgICAgICBxMmEuaW52ZXJzZSgpO1xyXG4gICAgICAgICAgICBjb3MgPSAtY29zO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgazA7XHJcbiAgICAgICAgbGV0IGsxO1xyXG4gICAgICAgIGlmIChjb3MgPiAwLjk5OTkpIHtcclxuICAgICAgICAgICAgazAgPSAxIC0gdGltZTtcclxuICAgICAgICAgICAgazEgPSAwICsgdGltZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHNpbiA9IE1hdGguc3FydCgxIC0gY29zICogY29zKTtcclxuICAgICAgICAgICAgY29uc3QgYW5nbGUgPSBNYXRoLmF0YW4yKHNpbiwgY29zKTtcclxuICAgICAgICAgICAgY29uc3Qgb25lT3ZlclNpbiA9IDEgLyBzaW47XHJcbiAgICAgICAgICAgIGswID0gTWF0aC5zaW4oKDEgLSB0aW1lKSAqIGFuZ2xlKSAqIG9uZU92ZXJTaW47XHJcbiAgICAgICAgICAgIGsxID0gTWF0aC5zaW4oKDAgKyB0aW1lKSAqIGFuZ2xlKSAqIG9uZU92ZXJTaW47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IGswICogcTEueCArIGsxICogcTJhLng7XHJcbiAgICAgICAgZGVzdC55ID0gazAgKiBxMS55ICsgazEgKiBxMmEueTtcclxuICAgICAgICBkZXN0LnogPSBrMCAqIHExLnogKyBrMSAqIHEyYS56O1xyXG4gICAgICAgIGRlc3QudyA9IGswICogcTEudyArIGsxICogcTJhLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgbWl4KHExLCBxMiwgdGltZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgY29zSGFsZlRoZXRhID0gcTEueCAqIHEyLnggKyBxMS55ICogcTIueSArIHExLnogKiBxMi56ICsgcTEudyAqIHEyLnc7XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKGNvc0hhbGZUaGV0YSkgPj0gMS4wKSB7XHJcbiAgICAgICAgICAgIGRlc3QueHl6dyA9IHExLnh5enc7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBoYWxmVGhldGEgPSBNYXRoLmFjb3MoY29zSGFsZlRoZXRhKTtcclxuICAgICAgICBjb25zdCBzaW5IYWxmVGhldGEgPSBNYXRoLnNxcnQoMS4wIC0gY29zSGFsZlRoZXRhICogY29zSGFsZlRoZXRhKTtcclxuICAgICAgICBpZiAoTWF0aC5hYnMoc2luSGFsZlRoZXRhKSA8IDAuMDAxKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCA9IHExLnggKiAwLjUgKyBxMi54ICogMC41O1xyXG4gICAgICAgICAgICBkZXN0LnkgPSBxMS55ICogMC41ICsgcTIueSAqIDAuNTtcclxuICAgICAgICAgICAgZGVzdC56ID0gcTEueiAqIDAuNSArIHEyLnogKiAwLjU7XHJcbiAgICAgICAgICAgIGRlc3QudyA9IHExLncgKiAwLjUgKyBxMi53ICogMC41O1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcmF0aW9BID0gTWF0aC5zaW4oKDEgLSB0aW1lKSAqIGhhbGZUaGV0YSkgLyBzaW5IYWxmVGhldGE7XHJcbiAgICAgICAgY29uc3QgcmF0aW9CID0gTWF0aC5zaW4odGltZSAqIGhhbGZUaGV0YSkgLyBzaW5IYWxmVGhldGE7XHJcbiAgICAgICAgZGVzdC54ID0gcTEueCAqIHJhdGlvQSArIHEyLnggKiByYXRpb0I7XHJcbiAgICAgICAgZGVzdC55ID0gcTEueSAqIHJhdGlvQSArIHEyLnkgKiByYXRpb0I7XHJcbiAgICAgICAgZGVzdC56ID0gcTEueiAqIHJhdGlvQSArIHEyLnogKiByYXRpb0I7XHJcbiAgICAgICAgZGVzdC53ID0gcTEudyAqIHJhdGlvQSArIHEyLncgKiByYXRpb0I7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZnJvbUF4aXNBbmdsZShheGlzLCBhbmdsZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgYW5nbGUgKj0gMC41O1xyXG4gICAgICAgIGNvbnN0IHNpbiA9IE1hdGguc2luKGFuZ2xlKTtcclxuICAgICAgICBkZXN0LnggPSBheGlzLnggKiBzaW47XHJcbiAgICAgICAgZGVzdC55ID0gYXhpcy55ICogc2luO1xyXG4gICAgICAgIGRlc3QueiA9IGF4aXMueiAqIHNpbjtcclxuICAgICAgICBkZXN0LncgPSBNYXRoLmNvcyhhbmdsZSk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbn1cclxucXVhdC5pZGVudGl0eSA9IG5ldyBxdWF0KCkuc2V0SWRlbnRpdHkoKTtcclxuIiwiaW1wb3J0IHF1YXQgZnJvbSAnLi9xdWF0JztcclxuaW1wb3J0IHsgZXBzaWxvbiB9IGZyb20gJy4vY29uc3RhbnRzJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgdmVjMyB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoMyk7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMueHl6ID0gdmFsdWVzO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldCB4KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1swXTtcclxuICAgIH1cclxuICAgIGdldCB5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGdldCB6KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIGdldCB4eSgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHl6KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXV07XHJcbiAgICB9XHJcbiAgICBzZXQgeCh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeih2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeHkodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBzZXQgeHl6KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgdGhpcy54ID0gMDtcclxuICAgICAgICB0aGlzLnkgPSAwO1xyXG4gICAgICAgIHRoaXMueiA9IDA7XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSB0aGlzLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdGhpcy56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbmVnYXRlKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IC10aGlzLng7XHJcbiAgICAgICAgZGVzdC55ID0gLXRoaXMueTtcclxuICAgICAgICBkZXN0LnogPSAtdGhpcy56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKHZlY3RvciwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnggLSB2ZWN0b3IueCkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy55IC0gdmVjdG9yLnkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueiAtIHZlY3Rvci56KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgbGVuZ3RoKCkge1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkTGVuZ3RoKCkpO1xyXG4gICAgfVxyXG4gICAgc3F1YXJlZExlbmd0aCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICByZXR1cm4geCAqIHggKyB5ICogeSArIHogKiB6O1xyXG4gICAgfVxyXG4gICAgYWRkKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCArPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKz0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56ICs9IHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc3VidHJhY3QodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54IC09IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAtPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogLT0gdmVjdG9yLno7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggKj0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55ICo9IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAqPSB2ZWN0b3IuejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGRpdmlkZSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLz0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC89IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAvPSB2ZWN0b3IuejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNjYWxlKHZhbHVlLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC55ICo9IHZhbHVlO1xyXG4gICAgICAgIGRlc3QueiAqPSB2YWx1ZTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG5vcm1hbGl6ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcclxuICAgICAgICBpZiAobGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueSA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueiA9IDA7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZW5ndGggPSAxLjAgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ICo9IGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueiAqPSBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseUJ5TWF0MyhtYXRyaXgsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBtYXRyaXgubXVsdGlwbHlWZWMzKHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlCeVF1YXQocXVhdGVybmlvbiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHF1YXRlcm5pb24ubXVsdGlwbHlWZWMzKHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgdG9RdWF0KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGMgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIGNvbnN0IHMgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIGMueCA9IE1hdGguY29zKHRoaXMueCAqIDAuNSk7XHJcbiAgICAgICAgcy54ID0gTWF0aC5zaW4odGhpcy54ICogMC41KTtcclxuICAgICAgICBjLnkgPSBNYXRoLmNvcyh0aGlzLnkgKiAwLjUpO1xyXG4gICAgICAgIHMueSA9IE1hdGguc2luKHRoaXMueSAqIDAuNSk7XHJcbiAgICAgICAgYy56ID0gTWF0aC5jb3ModGhpcy56ICogMC41KTtcclxuICAgICAgICBzLnogPSBNYXRoLnNpbih0aGlzLnogKiAwLjUpO1xyXG4gICAgICAgIGRlc3QueCA9IHMueCAqIGMueSAqIGMueiAtIGMueCAqIHMueSAqIHMuejtcclxuICAgICAgICBkZXN0LnkgPSBjLnggKiBzLnkgKiBjLnogKyBzLnggKiBjLnkgKiBzLno7XHJcbiAgICAgICAgZGVzdC56ID0gYy54ICogYy55ICogcy56IC0gcy54ICogcy55ICogYy56O1xyXG4gICAgICAgIGRlc3QudyA9IGMueCAqIGMueSAqIGMueiArIHMueCAqIHMueSAqIHMuejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBjcm9zcyh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIGNvbnN0IHgyID0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkyID0gdmVjdG9yMi55O1xyXG4gICAgICAgIGNvbnN0IHoyID0gdmVjdG9yMi56O1xyXG4gICAgICAgIGRlc3QueCA9IHkgKiB6MiAtIHogKiB5MjtcclxuICAgICAgICBkZXN0LnkgPSB6ICogeDIgLSB4ICogejI7XHJcbiAgICAgICAgZGVzdC56ID0geCAqIHkyIC0geSAqIHgyO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRvdCh2ZWN0b3IsIHZlY3RvcjIpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICBjb25zdCB4MiA9IHZlY3RvcjIueDtcclxuICAgICAgICBjb25zdCB5MiA9IHZlY3RvcjIueTtcclxuICAgICAgICBjb25zdCB6MiA9IHZlY3RvcjIuejtcclxuICAgICAgICByZXR1cm4geCAqIHgyICsgeSAqIHkyICsgeiAqIHoyO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IyLnggLSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yMi55IC0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3RvcjIueiAtIHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkRGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3F1YXJlZERpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IyLnggLSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yMi55IC0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3RvcjIueiAtIHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5ICsgeiAqIHo7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlyZWN0aW9uKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueSAtIHZlY3RvcjIueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLnogLSB2ZWN0b3IyLno7XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHopO1xyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICAgICAgZGVzdC56ID0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ID0geCAqIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgPSB5ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueiA9IHogKiBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgbWl4KHZlY3RvciwgdmVjdG9yMiwgdGltZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB0aW1lICogKHZlY3RvcjIueCAtIHZlY3Rvci54KTtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSArIHRpbWUgKiAodmVjdG9yMi55IC0gdmVjdG9yLnkpO1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56ICsgdGltZSAqICh2ZWN0b3IyLnogLSB2ZWN0b3Iueik7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3VtKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogKyB2ZWN0b3IyLno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlmZmVyZW5jZSh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC0gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56IC0gdmVjdG9yMi56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAqIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAqIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiAqIHZlY3RvcjIuejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBxdW90aWVudCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC8gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC8gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56IC8gdmVjdG9yMi56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG59XHJcbnZlYzMuemVybyA9IG5ldyB2ZWMzKFswLCAwLCAwXSk7XHJcbnZlYzMub25lID0gbmV3IHZlYzMoWzEsIDEsIDFdKTtcclxudmVjMy51cCA9IG5ldyB2ZWMzKFswLCAxLCAwXSk7XHJcbnZlYzMucmlnaHQgPSBuZXcgdmVjMyhbMSwgMCwgMF0pO1xyXG52ZWMzLmZvcndhcmQgPSBuZXcgdmVjMyhbMCwgMCwgMV0pO1xyXG4iLCIvLyBUaGUgY29kZSB0aGF0IGRlYWxzIHdpdGggM2QgYXVkaW9cclxuaW1wb3J0IEV2ZW50RW1pdHRlciBmcm9tICdldmVudGVtaXR0ZXIzJztcclxuaW1wb3J0IHZlYzMgZnJvbSAnLi4vLi4vdHNtL3ZlYzMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZXNvbmF0b3JTY2VuZSBleHRlbmRzIEV2ZW50RW1pdHRlciB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0KSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xyXG4gICAgICAgIHRoaXMuc2NlbmUgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICB0aGlzLmxpc3RlbmVyID0gdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5saXN0ZW5lcjtcclxuICAgICAgICB0aGlzLmluaXQoKTtcclxuICAgIH1cclxuICAgIGluaXQoKSB7XHJcbiAgICAgICAgLy8gdGhpcy5zY2VuZS5vdXRwdXQuY29ubmVjdCh0aGlzLmNvbnRleHQuZ2V0T3V0cHV0RGVzdGluYXRpb24oKSk7XHJcbiAgICB9XHJcbiAgICBjcmVhdGVTb3VyY2UoKSB7XHJcbiAgICAgICAgY29uc3Qgbm9kZSA9IHRoaXMuY29udGV4dC5nZXRDb250ZXh0KCkuY3JlYXRlUGFubmVyKCk7XHJcbiAgICAgICAgbm9kZS5wYW5uaW5nTW9kZWwgPSAnSFJURic7XHJcbiAgICAgICAgbm9kZS5kaXN0YW5jZU1vZGVsID0gJ2xpbmVhcic7XHJcbiAgICAgICAgbm9kZS5tYXhEaXN0YW5jZSA9IDIwO1xyXG4gICAgICAgIG5vZGUucmVmRGlzdGFuY2UgPSAyO1xyXG4gICAgICAgIG5vZGUuY29ubmVjdCh0aGlzLnNjZW5lKTtcclxuICAgICAgICByZXR1cm4gbm9kZTtcclxuICAgIH1cclxuICAgIGdldE91dHB1dCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zY2VuZTtcclxuICAgIH1cclxuICAgIGdldElucHV0KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnNjZW5lO1xyXG4gICAgfVxyXG4gICAgc2V0TGlzdGVuZXJQb3NpdGlvbih4LCB5LCB6KSB7XHJcbiAgICAgICAgdGhpcy5saXN0ZW5lci5zZXRQb3NpdGlvbih4LCB5LCB6KTtcclxuICAgIH1cclxuICAgIHNldExpc3RlbmVyT3JpZW50YXRpb24oZm9yd2FyZCwgcmF3dXApIHtcclxuICAgICAgICBsZXQgZndkID0gbmV3IHZlYzMoW2ZvcndhcmQueCwgZm9yd2FyZC55LCBmb3J3YXJkLnpdKTtcclxuICAgICAgICBsZXQgdXAgPSBmd2QuY29weSgpO1xyXG4gICAgICAgIHZlYzMuY3Jvc3ModXAsIG5ldyB2ZWMzKFtyYXd1cC54LCByYXd1cC55LCByYXd1cC56XSksIHVwKTtcclxuICAgICAgICB2ZWMzLmNyb3NzKHVwLCBmd2QsIHVwKTtcclxuICAgICAgICBmd2Qubm9ybWFsaXplKCk7XHJcbiAgICAgICAgdXAubm9ybWFsaXplKCk7XHJcbiAgICAgICAgdGhpcy5saXN0ZW5lci5zZXRPcmllbnRhdGlvbihmd2QueCwgZndkLnksIGZ3ZC56LCB1cC54LCB1cC55LCB1cC56KTtcclxuICAgIH1cclxufVxyXG4iLCIvLyBBIGNoYWluIG9mIGVmZmVjdHMgdGhhdCBjb25uZWN0IHRvIHRoZSBlZmZlY3QgYnVzXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEVmZmVjdENoYWluIHtcclxuICAgIGNvbnN0cnVjdG9yKGNvbnRleHQsIGdyYXBoLCBpbnB1dCwgb3V0cHV0KSB7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzID0gW107XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcclxuICAgICAgICB0aGlzLmdyYXBoID0gZ3JhcGg7XHJcbiAgICAgICAgdGhpcy5pbnB1dE5vZGUgPSBpbnB1dDtcclxuICAgICAgICB0aGlzLm91dHB1dE5vZGUgPSBvdXRwdXQ7XHJcbiAgICAgICAgdGhpcy51cGRhdGVDb25uZWN0aW9ucygpO1xyXG4gICAgfVxyXG4gICAgYXBwbHlFZmZlY3QoZWZmZWN0KSB7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzLnB1c2goZWZmZWN0KTtcclxuICAgICAgICB0aGlzLnVwZGF0ZUNvbm5lY3Rpb25zKCk7XHJcbiAgICB9XHJcbiAgICByZW1vdmVFZmZlY3QoZWZmZWN0KSB7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzLmZvckVhY2goKGN1cnJFZmZlY3QpID0+IHtcclxuICAgICAgICAgICAgaWYgKGVmZmVjdCA9PT0gY3VyckVmZmVjdCkge1xyXG4gICAgICAgICAgICAgICAgY3VyckVmZmVjdC5kaXNjb25uZWN0KCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgICB0aGlzLmVmZmVjdHMgPSB0aGlzLmVmZmVjdHMuZmlsdGVyKChjdXJyRWZmZWN0KSA9PiBlZmZlY3QgIT09IGN1cnJFZmZlY3QpO1xyXG4gICAgICAgIHRoaXMudXBkYXRlQ29ubmVjdGlvbnMoKTtcclxuICAgIH1cclxuICAgIHVwZGF0ZUNvbm5lY3Rpb25zKCkge1xyXG4gICAgICAgIGlmICh0aGlzLmVmZmVjdHMubGVuZ3RoID09IDApIHtcclxuICAgICAgICAgICAgdGhpcy5pbnB1dE5vZGUuY29ubmVjdCh0aGlzLm91dHB1dE5vZGUpO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBjdXJyZW50ID0gbnVsbDtcclxuICAgICAgICBsZXQgcHJldmlvdXMgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuZWZmZWN0cy5mb3JFYWNoKChlZmZlY3QpID0+IHtcclxuICAgICAgICAgICAgY3VycmVudCA9IGVmZmVjdDtcclxuICAgICAgICAgICAgaWYgKHByZXZpb3VzKSB7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50LmNvbm5lY3RJbnB1dChwcmV2aW91cy5nZXRPdXRwdXQoKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50LmNvbm5lY3RJbnB1dCh0aGlzLmlucHV0Tm9kZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcHJldmlvdXMgPSBjdXJyZW50O1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGlmIChjdXJyZW50KSB7XHJcbiAgICAgICAgICAgIGN1cnJlbnQuY29ubmVjdE91dHB1dCh0aGlzLm91dHB1dE5vZGUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCIvLyB0aGlzIGlzIHRoZSBtaXhlciB0aGF0IHRha2VzIGFsbCB0aGUgZGlmZmVyZW50IG91dHB1dHMgYW5kIG1peGVzIHRoZW0gaW50byB0aGUgMiBidXNzZXM6XHJcbi8vIFdvcmxkQnVzOiBUaGUgZGlyZWN0aW9uYWwgYXVkaW9cclxuLy8gU2Vjb25kYXJ5QnVzOiBBbGwgdGhlIFVJIGFuZCB0aGluZ3MgdGhhdCBhcmUgbm9uIGRpcmVjdGlvbmFsXHJcbmltcG9ydCBFZmZlY3RDaGFpbiBmcm9tICcuL2VmZmVjdC1jaGFpbic7XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEF1ZGlvR3JhcGgge1xyXG4gICAgY29uc3RydWN0b3Ioc2NlbmUsIGNvbnRleHQsIHN3YXBDaGFubmVscyA9IGZhbHNlKSB7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IHNjZW5lO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5zd2FwQ2hhbm5lbHMgPSBzd2FwQ2hhbm5lbHM7XHJcbiAgICAgICAgdGhpcy5pbml0KCk7XHJcbiAgICB9XHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHRoaXMuZWZmZWN0c0J1cyA9IHRoaXMuY29udGV4dC5jcmVhdGVHYWluKCk7XHJcbiAgICAgICAgdGhpcy53b3JsZEJ1cyA9IHRoaXMuY29udGV4dC5jcmVhdGVHYWluKCk7XHJcbiAgICAgICAgdGhpcy5zZWNvbmRhcnlCdXMgPSB0aGlzLmNvbnRleHQuY3JlYXRlR2FpbigpO1xyXG4gICAgICAgIHRoaXMubWFzdGVyID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICB0aGlzLnNjZW5lLmdldE91dHB1dCgpLmNvbm5lY3QodGhpcy53b3JsZEJ1cyk7XHJcbiAgICAgICAgLy8gdGhpcy53b3JsZEJ1cy5jb25uZWN0KHRoaXMubWFzdGVyKTtcclxuICAgICAgICB0aGlzLndvcmxkQnVzLmNvbm5lY3QodGhpcy5lZmZlY3RzQnVzKTtcclxuICAgICAgICB0aGlzLmVmZmVjdHMgPSBuZXcgRWZmZWN0Q2hhaW4odGhpcy5jb250ZXh0LCB0aGlzLCB0aGlzLmVmZmVjdHNCdXMsIHRoaXMubWFzdGVyKTtcclxuICAgICAgICB0aGlzLnNlY29uZGFyeUJ1cy5jb25uZWN0KHRoaXMubWFzdGVyKTtcclxuICAgICAgICBpZiAodGhpcy5zd2FwQ2hhbm5lbHMpIHtcclxuICAgICAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUNoYW5uZWxTcGxpdHRlcigyKTtcclxuICAgICAgICAgICAgdGhpcy5jaGFubmVsTWVyZ2VyID0gdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jcmVhdGVDaGFubmVsTWVyZ2VyKDIpO1xyXG4gICAgICAgICAgICB0aGlzLm1hc3Rlci5jb25uZWN0KHRoaXMuY2hhbm5lbFNwbGl0dGVyKTtcclxuICAgICAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIuY29ubmVjdCh0aGlzLmNoYW5uZWxNZXJnZXIsIDAsIDEpO1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxTcGxpdHRlci5jb25uZWN0KHRoaXMuY2hhbm5lbE1lcmdlciwgMSwgMCk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhbm5lbE1lcmdlci5jb25uZWN0KHRoaXMuY29udGV4dC5nZXRPdXRwdXREZXN0aW5hdGlvbigpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMubWFzdGVyLmNvbm5lY3QodGhpcy5jb250ZXh0LmdldE91dHB1dERlc3RpbmF0aW9uKCkpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGNvbm5lY3RUb01hc3RlcihpbnB1dCkge1xyXG4gICAgICAgIGlucHV0LmNvbm5lY3QodGhpcy5tYXN0ZXIpO1xyXG4gICAgfVxyXG4gICAgY29ubmVjdFRvVUkoaW5wdXQpIHtcclxuICAgICAgICBpbnB1dC5jb25uZWN0KHRoaXMuc2Vjb25kYXJ5QnVzKTtcclxuICAgIH1cclxuICAgIGFwcGx5RWZmZWN0KGVmZmVjdCkge1xyXG4gICAgICAgIHRoaXMuZWZmZWN0cy5hcHBseUVmZmVjdChlZmZlY3QpO1xyXG4gICAgfVxyXG4gICAgcmVtb3ZlRWZmZWN0KGVmZmVjdCkge1xyXG4gICAgICAgIHRoaXMuZWZmZWN0cy5yZW1vdmVFZmZlY3QoZWZmZWN0KTtcclxuICAgIH1cclxufVxyXG4iLCJleHBvcnQgdmFyIFNvdXJjZVR5cGU7XHJcbihmdW5jdGlvbiAoU291cmNlVHlwZSkge1xyXG4gICAgU291cmNlVHlwZVtTb3VyY2VUeXBlW1wiV29ybGRTb3VyY2VcIl0gPSAwXSA9IFwiV29ybGRTb3VyY2VcIjtcclxuICAgIFNvdXJjZVR5cGVbU291cmNlVHlwZVtcIlVJU291cmNlXCJdID0gMV0gPSBcIlVJU291cmNlXCI7XHJcbiAgICBTb3VyY2VUeXBlW1NvdXJjZVR5cGVbXCJNYXN0ZXJTb3VyY2VcIl0gPSAyXSA9IFwiTWFzdGVyU291cmNlXCI7XHJcbn0pKFNvdXJjZVR5cGUgfHwgKFNvdXJjZVR5cGUgPSB7fSkpO1xyXG4iLCIvLyBhbiBhdWRpbyBzb3VyY2VcclxuLy8gVGhpcyBpcyB0aGUgYWN0dWFsIHNvdW5kXHJcbmltcG9ydCB7IFNvdXJjZVR5cGUgfSBmcm9tICcuL3NvdXJjZS10eXBlJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQXVkaW9Tb3VyY2Uge1xyXG4gICAgY29uc3RydWN0b3IoZ3JhcGgsIHNjZW5lLCBjb250ZXh0LCBidWZmZXIgPSBudWxsLCB0eXBlID0gU291cmNlVHlwZS5Xb3JsZFNvdXJjZSkge1xyXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSB7XHJcbiAgICAgICAgICAgIHg6IDAsXHJcbiAgICAgICAgICAgIHk6IDAsXHJcbiAgICAgICAgICAgIHo6IDBcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMuYnVmZmVyID0gYnVmZmVyO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IHNjZW5lO1xyXG4gICAgICAgIHRoaXMuZ3JhcGggPSBncmFwaDtcclxuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xyXG4gICAgICAgIHRoaXMucGxheWJhY2tSYXRlID0gMTtcclxuICAgICAgICB0aGlzLnZvbHVtZSA9IDE7XHJcbiAgICAgICAgdGhpcy5pbml0KCk7XHJcbiAgICB9XHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHRoaXMuZ2FpbiA9IHRoaXMuY29udGV4dC5jcmVhdGVHYWluKCk7XHJcbiAgICAgICAgLy8gYmluZCBtZXRob2RzIHNvIHdlIGNhbiBhZGQgYW5kIHJlbW92dmUgdGhlbSBmcm9tIGV2ZW50IGxpc3RlbmVyc1xyXG4gICAgICAgIHRoaXMuc3RvcCA9IHRoaXMuc3RvcC5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG4gICAgZ2V0QnVmZmVyKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmJ1ZmZlcjtcclxuICAgIH1cclxuICAgIHNldEJ1ZmZlcihkYXRhKSB7XHJcbiAgICAgICAgdGhpcy5idWZmZXIgPSBkYXRhO1xyXG4gICAgICAgIGlmICh0aGlzLnBsYXlPbkxvYWQpIHtcclxuICAgICAgICAgICAgdGhpcy5wbGF5KCk7XHJcbiAgICAgICAgICAgIHRoaXMucGxheU9uTG9hZCA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHBsYXkod2hlbiA9IDAsIG9mZnNldCA9IDAsIGR1cmF0aW9uID0gdGhpcy5idWZmZXIgPyB0aGlzLmJ1ZmZlci5kdXJhdGlvbiA6IDApIHtcclxuICAgICAgICBpZiAodGhpcy5wbGF5aW5nICYmIHRoaXMubm9kZSkge1xyXG4gICAgICAgICAgICB0aGlzLnN0b3AoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCF0aGlzLmJ1ZmZlcikge1xyXG4gICAgICAgICAgICB0aGlzLnBsYXlPbkxvYWQgPSB0cnVlO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghdGhpcy5ub2RlKSB7XHJcbiAgICAgICAgICAgIHRoaXMubm9kZSA9IHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLmJ1ZmZlciA9IHRoaXMuYnVmZmVyO1xyXG4gICAgICAgICAgICB0aGlzLmNyZWF0ZUNvbm5lY3Rpb25zKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLnBsYXliYWNrUmF0ZS52YWx1ZSA9IHRoaXMucGxheWJhY2tSYXRlO1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUuc3RhcnQod2hlbiwgb2Zmc2V0LCBkdXJhdGlvbik7XHJcbiAgICAgICAgICAgIHRoaXMubm9kZS5sb29wID0gdGhpcy5sb29waW5nO1xyXG4gICAgICAgICAgICB0aGlzLnBsYXlpbmcgPSB0cnVlO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5zY2VuZU5vZGUpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuc2NlbmVOb2RlLnNldFBvc2l0aW9uKHRoaXMucG9zaXRpb24ueCwgdGhpcy5wb3NpdGlvbi55LCB0aGlzLnBvc2l0aW9uLnopO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRoaXMubm9kZS5hZGRFdmVudExpc3RlbmVyKCdlbmRlZCcsIHRoaXMuc3RvcCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgc2V0UG9zaXRpb24oeCwgeSwgeikge1xyXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSB7XHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHksXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICB9O1xyXG4gICAgICAgIGlmICh0aGlzLnNjZW5lTm9kZSlcclxuICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUuc2V0UG9zaXRpb24oeCwgeSwgeik7XHJcbiAgICB9XHJcbiAgICBzZXRQbGF5YmFja1JhdGUocmF0ZSkge1xyXG4gICAgICAgIHRoaXMucGxheWJhY2tSYXRlID0gcmF0ZTtcclxuICAgICAgICBpZiAodGhpcy5ub2RlKVxyXG4gICAgICAgICAgICB0aGlzLm5vZGUucGxheWJhY2tSYXRlLnZhbHVlID0gcmF0ZTtcclxuICAgIH1cclxuICAgIGdldFBsYXliYWNrUmF0ZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5wbGF5YmFja1JhdGU7XHJcbiAgICB9XHJcbiAgICBzZXRWb2x1bWUodm9sdW1lKSB7XHJcbiAgICAgICAgdGhpcy52b2x1bWUgPSB2b2x1bWU7XHJcbiAgICAgICAgaWYgKHRoaXMuZ2FpbilcclxuICAgICAgICAgICAgdGhpcy5nYWluLmdhaW4udmFsdWUgPSB2b2x1bWU7XHJcbiAgICB9XHJcbiAgICBnZXRWb2x1bWUoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudm9sdW1lO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlQ29ubmVjdGlvbnMoKSB7XHJcbiAgICAgICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcclxuICAgICAgICAgICAgY2FzZSBTb3VyY2VUeXBlLldvcmxkU291cmNlOlxyXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLnNjZW5lTm9kZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2NlbmVOb2RlID0gdGhpcy5zY2VuZS5jcmVhdGVTb3VyY2UoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHRoaXMubm9kZS5jb25uZWN0KHRoaXMuZ2Fpbik7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmdhaW4uY29ubmVjdCh0aGlzLnNjZW5lTm9kZSk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSBTb3VyY2VUeXBlLlVJU291cmNlOlxyXG4gICAgICAgICAgICAgICAgdGhpcy5ub2RlLmNvbm5lY3QodGhpcy5nYWluKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuZ3JhcGguY29ubmVjdFRvVUkodGhpcy5nYWluKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgdGhpcy5ub2RlLmNvbm5lY3QodGhpcy5nYWluKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuZ3JhcGguY29ubmVjdFRvTWFzdGVyKHRoaXMuZ2Fpbik7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHRoaXMucGxheWluZyA9IGZhbHNlO1xyXG4gICAgICAgIGlmICh0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2VuZGVkJywgdGhpcy5zdG9wKTtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLnN0b3AoKTtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLmRpc2Nvbm5lY3QoKTtcclxuICAgICAgICAgICAgdGhpcy5ub2RlID0gbnVsbDtcclxuICAgICAgICAgICAgdGhpcy5wbGF5aW5nID0gZmFsc2U7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNjZW5lTm9kZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUuZGlzY29ubmVjdCgpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUgPSBudWxsO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZGVzdHJveSgpIHtcclxuICAgICAgICB0aGlzLnN0b3AoKTtcclxuICAgICAgICAvLyBzZXQgYWxsIHJlZnMgdG8gbnVsbCB0byBlbmNvdXJhZ2UgZ2NcclxuICAgICAgICB0aGlzLm5vZGUgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuc2NlbmVOb2RlID0gbnVsbDtcclxuICAgICAgICB0aGlzLmJ1ZmZlciA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLmdyYXBoID0gbnVsbDtcclxuICAgICAgICB0aGlzLnNjZW5lID0gbnVsbDtcclxuICAgIH1cclxuICAgIGxvb3AodmFsdWUpIHtcclxuICAgICAgICB0aGlzLmxvb3BpbmcgPSB2YWx1ZTtcclxuICAgICAgICBpZiAodGhpcy5ub2RlKSB7XHJcbiAgICAgICAgICAgIHRoaXMubm9kZS5sb29wID0gdmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZmFkZU91dCh0aW1lKSB7XHJcbiAgICAgICAgdGhpcy5nYWluLmdhaW4uc2V0VmFsdWVBdFRpbWUodGhpcy5nZXRWb2x1bWUoKSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSk7XHJcbiAgICAgICAgaWYgKCF0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmdhaW4uZ2Fpbi5leHBvbmVudGlhbFJhbXBUb1ZhbHVlQXRUaW1lKDAuMDAwMSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSArIHRpbWUpO1xyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zdG9wKCksIHRpbWUgKiAxMDAwKTtcclxuICAgIH1cclxuICAgIGZhZGVJbih0aW1lKSB7XHJcbiAgICAgICAgdGhpcy5nYWluLmdhaW4uc2V0VmFsdWVBdFRpbWUoMC4wMDAxLCB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmN1cnJlbnRUaW1lKTtcclxuICAgICAgICBpZiAoIXRoaXMubm9kZSkge1xyXG4gICAgICAgICAgICB0aGlzLnBsYXkoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5nYWluLmdhaW4uZXhwb25lbnRpYWxSYW1wVG9WYWx1ZUF0VGltZSh0aGlzLnZvbHVtZSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSArIHRpbWUpO1xyXG4gICAgfVxyXG59XHJcbiIsIi8vIEFuIGl0ZW0gaW4gdGhlIGRhdGEgcG9vbFxyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBEYXRhUG9vbEl0ZW0ge1xyXG4gICAgY29uc3RydWN0b3IobmFtZSwgZGF0YSA9IG51bGwsIGRlY29kZWREYXRhID0gbnVsbCkge1xyXG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XHJcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcclxuICAgICAgICB0aGlzLmRlY29kZWREYXRhID0gZGVjb2RlZERhdGE7XHJcbiAgICB9XHJcbiAgICBnZXREYXRhKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmRhdGE7XHJcbiAgICB9XHJcbiAgICBzZXREYXRhKGRhdGEpIHtcclxuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xyXG4gICAgfVxyXG4gICAgZ2V0RGVjb2RlZERhdGEoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVjb2RlZERhdGE7XHJcbiAgICB9XHJcbiAgICBzZXREZWNvZGVkRGF0YShkYXRhKSB7XHJcbiAgICAgICAgdGhpcy5kZWNvZGVkRGF0YSA9IHRoaXMuZGVjb2RlZERhdGE7XHJcbiAgICB9XHJcbiAgICBnZXROYW1lKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLm5hbWU7XHJcbiAgICB9XHJcbiAgICBzZXROYW1lKG5hbWUpIHtcclxuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xyXG4gICAgfVxyXG59XHJcbiIsInZhciBfX2F3YWl0ZXIgPSAodGhpcyAmJiB0aGlzLl9fYXdhaXRlcikgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHsgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZSh2YWx1ZSk7IH0pOyB9XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufTtcclxuZXhwb3J0IGNsYXNzIEhUVFBMb2FkZXIge1xyXG4gICAgZ2V0KHBhdGgpIHtcclxuICAgICAgICByZXR1cm4gX19hd2FpdGVyKHRoaXMsIHZvaWQgMCwgdm9pZCAwLCBmdW5jdGlvbiogKCkge1xyXG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSB5aWVsZCBmZXRjaChwYXRoKTtcclxuICAgICAgICAgICAgY29uc3QgYnVmZmVyID0geWllbGQgcmVzdWx0LmFycmF5QnVmZmVyKCk7XHJcbiAgICAgICAgICAgIHJldHVybiBidWZmZXI7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbn1cclxuIiwiLy8gYSBkYXRhIHBvb2wgaG9sZHMgZnJlcXVlbnRseSBwbGF5ZWQgc291bmRzIGluIG1lbW9yeSB0b2dldGhlciB3aXRoIGRlY29kZWQgYXVkaW8gZGF0YSB0byBubyBsb25nZXIgaGF2ZSB0byBkZWNvZGUgdGhlbSBmcm9tIHRoZSBjYWNoZSB3aGVuIGxvYWRlZCBhZ2FpblxyXG52YXIgX19hd2FpdGVyID0gKHRoaXMgJiYgdGhpcy5fX2F3YWl0ZXIpIHx8IGZ1bmN0aW9uICh0aGlzQXJnLCBfYXJndW1lbnRzLCBQLCBnZW5lcmF0b3IpIHtcclxuICAgIGZ1bmN0aW9uIGFkb3B0KHZhbHVlKSB7IHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7IHJlc29sdmUodmFsdWUpOyB9KTsgfVxyXG4gICAgcmV0dXJuIG5ldyAoUCB8fCAoUCA9IFByb21pc2UpKShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XHJcbiAgICAgICAgZnVuY3Rpb24gZnVsZmlsbGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yLm5leHQodmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yW1widGhyb3dcIl0odmFsdWUpKTsgfSBjYXRjaCAoZSkgeyByZWplY3QoZSk7IH0gfVxyXG4gICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogYWRvcHQocmVzdWx0LnZhbHVlKS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9XHJcbiAgICAgICAgc3RlcCgoZ2VuZXJhdG9yID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pKS5uZXh0KCkpO1xyXG4gICAgfSk7XHJcbn07XHJcbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnZXZlbnRlbWl0dGVyMyc7XHJcbmltcG9ydCBEYXRhUG9vbEl0ZW0gZnJvbSAnLi9kYXRhLXBvb2wtaXRlbSc7XHJcbmltcG9ydCB7IEhUVFBMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvaHR0cC1sb2FkZXInO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBEYXRhUG9vbCBleHRlbmRzIEV2ZW50RW1pdHRlciB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBsb2FkZXIgPSBuZXcgSFRUUExvYWRlcigpLCBtYXhEYXRhID0gNTEyKSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLmxvYWRlciA9IGxvYWRlcjtcclxuICAgICAgICB0aGlzLmRhdGEgPSB7fTtcclxuICAgICAgICB0aGlzLm1heERhdGEgPSBtYXhEYXRhO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICB9XHJcbiAgICBnZXQocGF0aCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmRhdGFbcGF0aF0pIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmRhdGFbcGF0aF0uZ2V0RGVjb2RlZERhdGEoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGJ1ZmZlciA9IHlpZWxkIHRoaXMubG9hZGVyLmdldChwYXRoKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGRlY29kZWQgPSB5aWVsZCB0aGlzLmNvbnRleHQuZGVjb2RlQXVkaW9EYXRhKGJ1ZmZlcik7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtID0gbmV3IERhdGFQb29sSXRlbShwYXRoLCBidWZmZXIsIGRlY29kZWQpO1xyXG4gICAgICAgICAgICAgICAgY29uc3QgbGVuZ3RoID0gT2JqZWN0LmtleXModGhpcy5kYXRhKS5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgICBpZiAobGVuZ3RoIDwgdGhpcy5tYXhEYXRhKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhW3BhdGhdID0gaXRlbTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IGZpZ3VyZSBvdXQgYSBtb3JlIGNsZXZlciBzb2x1dGlvbiB0aGFuIGp1c3QgcmVtb3ZpbmcgdGhlIGZpcnN0IGxvYWRlZCBkYXRhLiBMaWtlIHRyYWNraW5nIGhvdyBtdWNoIGNlcnRhaW4gZGF0YSBpcyBuZWVkZWQgYW5kIHByaW9yaXRpemUgdGhlbS5cclxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zdCBwYXRoczogc3RyaW5nW10gPSBPYmplY3Qua2V5cyh0aGlzLmRhdGEpO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIGRlbGV0ZSB0aGlzLmRhdGFbcGF0aHNbMF1dO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0YVtwYXRoXSA9IGl0ZW07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gaXRlbS5nZXREZWNvZGVkRGF0YSgpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjbGVhcigpIHtcclxuICAgICAgICB0aGlzLmRhdGEgPSB7fTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgQmFzZUVmZmVjdCBmcm9tICcuL2Jhc2UtZWZmZWN0JztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29udm9sdmVyIGV4dGVuZHMgQmFzZUVmZmVjdCB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBncmFwaCwgcGFyYW1zKSB7XHJcbiAgICAgICAgc3VwZXIoY29udGV4dCwgZ3JhcGgsIHBhcmFtcyk7XHJcbiAgICAgICAgY29uc29sZS5sb2coYENyZWF0aW5nIGNvbnZvbHZlcmApO1xyXG4gICAgICAgIHRoaXMuZWZmZWN0Tm9kZSA9IHRoaXMuY29udGV4dC5nZXRDb250ZXh0KCkuY3JlYXRlQ29udm9sdmVyKCk7XHJcbiAgICAgICAgdGhpcy5lZmZlY3ROb2RlLmJ1ZmZlciA9IHRoaXMuZWZmZWN0UGFyYW1zLmJ1ZmZlcjtcclxuICAgIH1cclxuICAgIGNvbm5lY3RJbnB1dChub2RlKSB7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUNoYW5uZWxTcGxpdHRlcigyKTtcclxuICAgICAgICB0aGlzLmNoYW5uZWxNZXJnZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUNoYW5uZWxNZXJnZXIoMik7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIuY29ubmVjdCh0aGlzLmNoYW5uZWxNZXJnZXIsIDAsIDApO1xyXG4gICAgICAgIHRoaXMuY2hhbm5lbFNwbGl0dGVyLmNvbm5lY3QodGhpcy5jaGFubmVsTWVyZ2VyLCAxLCAwKTtcclxuICAgICAgICB0aGlzLmNoYW5uZWxTcGxpdHRlci5jb25uZWN0KHRoaXMuY2hhbm5lbE1lcmdlciwgMCwgMSk7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIuY29ubmVjdCh0aGlzLmNoYW5uZWxNZXJnZXIsIDEsIDEpO1xyXG4gICAgICAgIG5vZGUuY29ubmVjdCh0aGlzLmNoYW5uZWxTcGxpdHRlcik7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsTWVyZ2VyLmNvbm5lY3QodGhpcy5lZmZlY3ROb2RlKTtcclxuICAgICAgICB0aGlzLmlucHV0Tm9kZSA9IG5vZGU7XHJcbiAgICB9XHJcbn1cclxuIiwiZXhwb3J0IGRlZmF1bHQgY2xhc3MgQmFzZUVmZmVjdCB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBncmFwaCwgcGFyYW1zKSB7XHJcbiAgICAgICAgdGhpcy5ncmFwaCA9IGdyYXBoO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RQYXJhbXMgPSBwYXJhbXM7XHJcbiAgICB9XHJcbiAgICBjb25uZWN0T3V0cHV0KG5vZGUpIHtcclxuICAgICAgICB0aGlzLmVmZmVjdE5vZGUuY29ubmVjdChub2RlKTtcclxuICAgIH1cclxuICAgIGNvbm5lY3RJbnB1dChub2RlKSB7XHJcbiAgICAgICAgdGhpcy5pbnB1dE5vZGUgPSBub2RlO1xyXG4gICAgICAgIGlmICh0aGlzLmVmZmVjdE5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5pbnB1dE5vZGUuY29ubmVjdCh0aGlzLmVmZmVjdE5vZGUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldE91dHB1dCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5lZmZlY3ROb2RlO1xyXG4gICAgfVxyXG4gICAgZGlzY29ubmVjdCgpIHtcclxuICAgICAgICB0aGlzLmlucHV0Tm9kZS5kaXNjb25uZWN0KCk7XHJcbiAgICAgICAgdGhpcy5lZmZlY3ROb2RlLmRpc2Nvbm5lY3QoKTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBTb3VyY2VUeXBlIH0gZnJvbSAnLi9zb3VyY2UtdHlwZSc7XHJcbmV4cG9ydCBjbGFzcyBTdHJlYW1pbmdTb3VyY2Uge1xyXG4gICAgY29uc3RydWN0b3IoZ3JhcGgsIHNjZW5lLCBjb250ZXh0LCBlbGVtZW50LCB0eXBlID0gU291cmNlVHlwZS5NYXN0ZXJTb3VyY2UpIHtcclxuICAgICAgICB0aGlzLmdyYXBoID0gZ3JhcGg7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IHNjZW5lO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcclxuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xyXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSB7XHJcbiAgICAgICAgICAgIHg6IDAsXHJcbiAgICAgICAgICAgIHk6IDAsXHJcbiAgICAgICAgICAgIHo6IDBcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLm5vZGUgPSB0aGlzLmNvbnRleHQuY3JlYXRlTWVkaWFFbGVtZW50U291cmNlKHRoaXMuZWxlbWVudCk7XHJcbiAgICAgICAgdGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICB0aGlzLmNyZWF0ZUNvbm5lY3Rpb25zKCk7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NhbnBsYXknLCAoZXZlbnQpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5jYW5QbGF5ID0gdHJ1ZTtcclxuICAgICAgICAgICAgaWYgKHRoaXMucGxheU9uQXZhaWxhYmxlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnBsYXkoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgcGxheSh3aGVuID0gMCwgb2Zmc2V0ID0gMCwgZHVyYXRpb24gPSAwKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuY2FuUGxheSkge1xyXG4gICAgICAgICAgICB0aGlzLmVsZW1lbnQucGxheSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnBsYXlPbkF2YWlsYWJsZSA9IHRydWU7XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHRoaXMuZWxlbWVudC5wYXVzZSgpO1xyXG4gICAgfVxyXG4gICAgZ2V0Vm9sdW1lKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmVsZW1lbnQudm9sdW1lO1xyXG4gICAgfVxyXG4gICAgc2V0Vm9sdW1lKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LnZvbHVtZSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgZ2V0UGxheWJhY2tSYXRlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmVsZW1lbnQucGxheWJhY2tSYXRlO1xyXG4gICAgfVxyXG4gICAgc2V0UGxheWJhY2tSYXRlKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LnBsYXliYWNrUmF0ZSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlQ29ubmVjdGlvbnMoKSB7XHJcbiAgICAgICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcclxuICAgICAgICAgICAgY2FzZSBTb3VyY2VUeXBlLldvcmxkU291cmNlOlxyXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLnNjZW5lTm9kZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2NlbmVOb2RlID0gdGhpcy5zY2VuZS5jcmVhdGVTb3VyY2UoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHRoaXMubm9kZS5jb25uZWN0KHRoaXMuZ2Fpbik7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmdhaW4uY29ubmVjdCh0aGlzLnNjZW5lTm9kZSk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgIHRoaXMubm9kZS5jb25uZWN0KHRoaXMuZ2Fpbik7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmdyYXBoLmNvbm5lY3RUb01hc3Rlcih0aGlzLmdhaW4pO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgc2V0UG9zaXRpb24oeCwgeSwgeikge1xyXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSB7XHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHksXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICB9O1xyXG4gICAgICAgIGlmICh0aGlzLnNjZW5lTm9kZSlcclxuICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUuc2V0UG9zaXRpb24oeCwgeSwgeik7XHJcbiAgICB9XHJcbiAgICBkZXN0cm95KCkge1xyXG4gICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgIHRoaXMuZWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5ncmFwaCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLm5vZGUgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuc2NlbmVOb2RlID0gbnVsbDtcclxuICAgICAgICB0aGlzLnNjZW5lID0gbnVsbDtcclxuICAgIH1cclxuICAgIGxvb3AodmFsdWUpIHtcclxuICAgICAgICB0aGlzLmVsZW1lbnQubG9vcCA9IHRydWU7XHJcbiAgICB9XHJcbiAgICBmYWRlSW4odGltZSkge1xyXG4gICAgICAgIHRoaXMuZ2Fpbi5nYWluLnNldFZhbHVlQXRUaW1lKDAuMDAwMSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSk7XHJcbiAgICAgICAgaWYgKCF0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5wbGF5KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuZ2Fpbi5nYWluLmV4cG9uZW50aWFsUmFtcFRvVmFsdWVBdFRpbWUodGhpcy5nZXRWb2x1bWUoKSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSArIHRpbWUpO1xyXG4gICAgfVxyXG4gICAgZmFkZU91dCh0aW1lKSB7XHJcbiAgICAgICAgdGhpcy5nYWluLmdhaW4uc2V0VmFsdWVBdFRpbWUodGhpcy5nZXRWb2x1bWUoKSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSk7XHJcbiAgICAgICAgaWYgKCF0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmdhaW4uZ2Fpbi5leHBvbmVudGlhbFJhbXBUb1ZhbHVlQXRUaW1lKDAuMDAwMSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSArIHRpbWUpO1xyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zdG9wKCksIHRpbWUgKiAxMDAwKTtcclxuICAgIH1cclxufVxyXG4iLCIvLyB0aGUgbWFpbiBtb2R1bGUgZm9yIFJlc29uYXRvclxyXG4vLyBBUEksIGV0Yy5cclxudmFyIF9fYXdhaXRlciA9ICh0aGlzICYmIHRoaXMuX19hd2FpdGVyKSB8fCBmdW5jdGlvbiAodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkgeyByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHZhbHVlKTsgfSk7IH1cclxuICAgIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG4gICAgICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkgeyByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTsgfVxyXG4gICAgICAgIHN0ZXAoKGdlbmVyYXRvciA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSkubmV4dCgpKTtcclxuICAgIH0pO1xyXG59O1xyXG5pbXBvcnQgUmVzb25hdG9yQXVkaW9Db250ZXh0IGZyb20gJy4vYXVkaW8tY29udGV4dCc7XHJcbmltcG9ydCBSZXNvbmF0b3JTY2VuZSBmcm9tICcuL3NjZW5lcy93ZWJhdWRpby1zY2VuZSc7XHJcbmltcG9ydCBBdWRpb0dyYXBoIGZyb20gJy4vYXVkaW8tZ3JhcGgnO1xyXG5pbXBvcnQgQXVkaW9Tb3VyY2UgZnJvbSAnLi9zb3VyY2VzL2F1ZGlvLXNvdXJjZSc7XHJcbmltcG9ydCBEYXRhUG9vbCBmcm9tICcuL2RhdGEtcG9vbCc7XHJcbmltcG9ydCBDb252b2x2ZXIgZnJvbSAnLi9lZmZlY3RzL2NvbnZvbHZlcic7XHJcbmltcG9ydCB7IEhUVFBMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvaHR0cC1sb2FkZXInO1xyXG5pbXBvcnQgeyBTb3VyY2VUeXBlIH0gZnJvbSAnLi9zb3VyY2VzL3NvdXJjZS10eXBlJztcclxuaW1wb3J0IHsgU3RyZWFtaW5nU291cmNlIH0gZnJvbSAnLi9zb3VyY2VzL3N0cmVhbWluZy1zb3VyY2UnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZXNvbmF0b3Ige1xyXG4gICAgY29uc3RydWN0b3IobG9hZGVyID0gbmV3IEhUVFBMb2FkZXIoKSkge1xyXG4gICAgICAgIHRoaXMubG9hZGVyID0gbG9hZGVyO1xyXG4gICAgICAgIHRoaXMuZW52aXJvbm1lbnRJbXB1bHNlID0gbnVsbDtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBuZXcgUmVzb25hdG9yQXVkaW9Db250ZXh0KCk7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IG5ldyBSZXNvbmF0b3JTY2VuZSh0aGlzLmNvbnRleHQpO1xyXG4gICAgICAgIHRoaXMuZ3JhcGggPSBuZXcgQXVkaW9HcmFwaCh0aGlzLnNjZW5lLCB0aGlzLmNvbnRleHQsIGZhbHNlKTtcclxuICAgICAgICB0aGlzLmRhdGFQb29sID0gbmV3IERhdGFQb29sKHRoaXMuY29udGV4dCwgdGhpcy5sb2FkZXIpO1xyXG4gICAgfVxyXG4gICAgbG9hZChwYXRoLCB0eXBlID0gU291cmNlVHlwZS5Xb3JsZFNvdXJjZSkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGRhdGEgPSB5aWVsZCB0aGlzLmRhdGFQb29sLmdldChwYXRoKTtcclxuICAgICAgICAgICAgY29uc3Qgc291cmNlID0gdGhpcy5jcmVhdGVTb3VyY2UodHlwZSwgZGF0YSk7XHJcbiAgICAgICAgICAgIHJldHVybiBzb3VyY2U7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBsb2FkSW1tZWRpYXRlKHBhdGgsIHR5cGUgPSBTb3VyY2VUeXBlLldvcmxkU291cmNlKSB7XHJcbiAgICAgICAgY29uc3Qgc291cmNlID0gbmV3IEF1ZGlvU291cmNlKHRoaXMuZ3JhcGgsIHRoaXMuc2NlbmUsIHRoaXMuY29udGV4dCwgbnVsbCwgdHlwZSk7XHJcbiAgICAgICAgdGhpcy5kYXRhUG9vbC5nZXQocGF0aCkudGhlbigoZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICBzb3VyY2Uuc2V0QnVmZmVyKGRhdGEpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBzb3VyY2U7XHJcbiAgICB9XHJcbiAgICBzdHJlYW0ocGF0aCwgdHlwZSA9IFNvdXJjZVR5cGUuTWFzdGVyU291cmNlKSB7XHJcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ldyBBdWRpbyhwYXRoKTtcclxuICAgICAgICBlbGVtZW50LmNyb3NzT3JpZ2luID0gJ2Fub255bW91cyc7XHJcbiAgICAgICAgZWxlbWVudC52b2x1bWUgPSAxO1xyXG4gICAgICAgIGNvbnN0IHNvdXJjZSA9IG5ldyBTdHJlYW1pbmdTb3VyY2UodGhpcy5ncmFwaCwgdGhpcy5zY2VuZSwgdGhpcy5jb250ZXh0LCBlbGVtZW50LCB0eXBlKTtcclxuICAgICAgICByZXR1cm4gc291cmNlO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlU291cmNlKHR5cGUsIGRhdGEpIHtcclxuICAgICAgICByZXR1cm4gbmV3IEF1ZGlvU291cmNlKHRoaXMuZ3JhcGgsIHRoaXMuc2NlbmUsIHRoaXMuY29udGV4dCwgZGF0YSk7XHJcbiAgICB9XHJcbiAgICBzZXRFbnZpcm9ubWVudEltcHVsc2UoZmlsZSkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmVudmlyb25tZW50SW1wdWxzZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5ncmFwaC5yZW1vdmVFZmZlY3QodGhpcy5lbnZpcm9ubWVudEltcHVsc2UpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGlmIChmaWxlID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgYnVmZmVyID0geWllbGQgdGhpcy5kYXRhUG9vbC5nZXQoZmlsZSk7XHJcbiAgICAgICAgICAgIHRoaXMuZW52aXJvbm1lbnRJbXB1bHNlID0gbmV3IENvbnZvbHZlcih0aGlzLmNvbnRleHQsIHRoaXMuZ3JhcGgsIHtcclxuICAgICAgICAgICAgICAgIGJ1ZmZlclxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgdGhpcy5ncmFwaC5hcHBseUVmZmVjdCh0aGlzLmVudmlyb25tZW50SW1wdWxzZSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBzZXRMaXN0ZW5lclBvc2l0aW9uKHgsIHksIHopIHtcclxuICAgICAgICB0aGlzLnNjZW5lLnNldExpc3RlbmVyUG9zaXRpb24oeCwgeSwgeik7XHJcbiAgICB9XHJcbiAgICBzZXRMaXN0ZW5lck9yaWVudGF0aW9uKGZvcndhcmQsIHVwKSB7XHJcbiAgICAgICAgdGhpcy5zY2VuZS5zZXRMaXN0ZW5lck9yaWVudGF0aW9uKGZvcndhcmQsIHVwKTtcclxuICAgIH1cclxuICAgIGNsZWFyRGF0YVBvb2woKSB7XHJcbiAgICAgICAgdGhpcy5kYXRhUG9vbC5jbGVhcigpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCBSZXNvbmF0b3IgZnJvbSAnLi4vZnJhbWV3b3JrL3Jlc29uYXRvcic7XHJcblxyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU291bmQge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5yZXMgPSBuZXcgUmVzb25hdG9yKCk7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZSA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5tdXNpYyA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZVZvbHVtZSA9IDE7XHJcbiAgICAgICAgdGhpcy5tdXNpY1ZvbHVtZSA9IDE7XHJcbiAgICAgICAgdGhpcy5zZnhWb2x1bWUgPSAxO1xyXG4gICAgICAgIHRoaXMucHJldmlvdXNBbWJpZW5jZSA9IFwiXCI7XHJcbiAgICAgICAgdGhpcy5wcmV2aW91c011c2ljID0gXCJcIjtcclxuICAgIH1cclxuXHJcbiAgICBwbGF5KGZpbGUpIHtcclxuICAgICAgICBjb25zdCBzb3VuZCA9IHRoaXMucmVzLmxvYWRJbW1lZGlhdGUoZmlsZSk7XHJcbiAgICAgICAgc291bmQuc2V0Vm9sdW1lKHRoaXMuc2Z4Vm9sdW1lKTtcclxuICAgICAgICBzb3VuZC5wbGF5KCk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgc2V0QW1iaWVuY2UoZmlsZSkge1xyXG4gICAgICAgIGlmIChmaWxlID09PSB0aGlzLnByZXZpb3VzQW1iaWVuY2UpIHJldHVybjtcclxuICAgICAgICBpZiAodGhpcy5hbWJpZW5jZSkge1xyXG4gICAgICAgICAgICBjb25zdCBwcmV2aW91c0FtYmllbmNlID0gdGhpcy5hbWJpZW5jZTtcclxuICAgICAgICAgICAgdGhpcy5hbWJpZW5jZSA9IG51bGw7XHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gcHJldmlvdXNBbWJpZW5jZS5mYWRlT3V0KDYpLCAxNTAwKTtcclxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiBwcmV2aW91c0FtYmllbmNlLmRlc3Ryb3koKSwgNjAwMCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghZmlsZSkgcmV0dXJuO1xyXG4gICAgICAgIHRoaXMucHJldmlvdXNBbWJpZW5jZSA9IGZpbGU7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZSA9IHRoaXMucmVzLnN0cmVhbShmaWxlLCAwKTtcclxuICAgICAgICB0aGlzLmFtYmllbmNlLnNldFZvbHVtZSh0aGlzLmFtYmllbmNlVm9sdW1lKTtcclxuICAgICAgICB0aGlzLmFtYmllbmNlLnBsYXkoKTtcclxuICAgICAgICB0aGlzLmFtYmllbmNlLmxvb3AodHJ1ZSk7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZS5mYWRlSW4oMyk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0TXVzaWMoZmlsZSkge1xyXG4gICAgICAgIGlmIChmaWxlID09PSB0aGlzLnByZXZpb3VzTXVzaWMpIHJldHVybjtcclxuICAgICAgICBpZiAodGhpcy5tdXNpYykge1xyXG4gICAgICAgICAgICBjb25zdCBwcmV2aW91c011c2ljID0gdGhpcy5tdXNpYztcclxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiBwcmV2aW91c011c2ljLmZhZGVPdXQoMiksIDUwMCk7XHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gcHJldmlvdXNNdXNpYy5kZXN0cm95KCksIDIwMDApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIWZpbGUpIHJldHVybjtcclxuICAgICAgICB0aGlzLnByZXZpb3VzTXVzaWMgPSBmaWxlO1xyXG4gICAgICAgIHRoaXMubXVzaWMgPSB0aGlzLnJlcy5zdHJlYW0oZmlsZSwgMSk7XHJcbiAgICAgICAgdGhpcy5tdXNpYy5zZXRWb2x1bWUodGhpcy5tdXNpY1ZvbHVtZSk7XHJcbiAgICAgICAgdGhpcy5tdXNpYy5wbGF5KCk7XHJcbiAgICAgICAgdGhpcy5tdXNpYy5mYWRlSW4oMik7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0SW1wdWxzZShmaWxlKSB7XHJcbiAgICAgICAgdGhpcy5yZXMuc2V0RW52aXJvbm1lbnRJbXB1bHNlKGZpbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldE11c2ljVm9sdW1lKHZvbHVtZSkge1xyXG4gICAgICAgIHRoaXMubXVzaWNWb2x1bWUgPSB2b2x1bWU7XHJcbiAgICAgICAgaWYgKHRoaXMubXVzaWMpIHRoaXMubXVzaWMuc2V0Vm9sdW1lKHZvbHVtZSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0QW1iaWVuY2VWb2x1bWUodm9sdW1lKSB7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZVZvbHVtZSA9IHZvbHVtZTtcclxuICAgICAgICBpZiAodGhpcy5hbWJpZW5jZSkgdGhpcy5hbWJpZW5jZS5zZXRWb2x1bWUodm9sdW1lKTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRTRlhWb2x1bWUodm9sdW1lKSB7XHJcbiAgICAgICAgdGhpcy5zZnhWb2x1bWUgPSB2b2x1bWU7XHJcbiAgICB9XHJcbn0iLCJpbXBvcnQgeyBUVFMgfSBmcm9tICcuLi9mcmFtZXdvcmsvdHRzJztcclxuaW1wb3J0IHsgQXJpYU91dHB1dCB9IGZyb20gJy4uL2ZyYW1ld29yay90dHMvb3V0cHV0cy9hcmlhJztcclxuaW1wb3J0IFNvdW5kIGZyb20gJy4vc291bmQnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgT3V0cHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMudHRzID0gbmV3IFRUUyhuZXcgQXJpYU91dHB1dCgpKTtcclxuICAgICAgICB0aGlzLmhpc3RvcnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcIm91dHB1dC1hcmVhXCIpO1xyXG4gICAgICAgIHRoaXMuc291bmQgPSBuZXcgU291bmQoKTtcclxuICAgIH1cclxuXHJcbiAgICBzYXkoc3RyaW5nKSB7XHJcbiAgICAgICAgaWYgKHN0cmluZyA9PT0gXCJcIikgcmV0dXJuO1xyXG4gICAgICAgIHRoaXMuc291bmQucGxheShgYXNzZXRzL3Njcm9sbC53YXZgKTtcclxuICAgICAgICBjb25zdCBub2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInBcIik7XHJcbiAgICAgICAgc3RyaW5nLnNwbGl0KFwiXFxuXCIpLmZvckVhY2goKGxpbmUpID0+IHtcclxuICAgICAgICAgICAgbm9kZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShsaW5lKSk7XHJcbiAgICAgICAgICAgIG5vZGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImJyXCIpKTtcclxuICAgICAgICAgICAgLy8gdGhpcy50dHMuc3BlYWsobGluZSwgZmFsc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuaGlzdG9yeS5hcHBlbmRDaGlsZChub2RlKTtcclxuICAgICAgICAvLyB0aGlzLnR0cy5zcGVhayhzdHJpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIHBsYXkoZmlsZSkge1xyXG4gICAgICAgIHRoaXMuc291bmQucGxheShmaWxlKTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRBbWJpZW5jZShmaWxlKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc291bmQuc2V0QW1iaWVuY2UoZmlsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0TXVzaWMoZmlsZSkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnNvdW5kLnNldE11c2ljKGZpbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldEltcHVsc2UoZmlsZSkge1xyXG4gICAgICAgIHRoaXMuc291bmQuc2V0SW1wdWxzZShmaWxlKTtcclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGNsYXNzIElucHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKGNvbW1hbmRIYW5kbGVyLCBvdXRwdXRIYW5kbGVyKSB7XHJcbiAgICAgICAgdGhpcy5oYW5kbGVyID0gY29tbWFuZEhhbmRsZXI7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQgPSBvdXRwdXRIYW5kbGVyO1xyXG4gICAgICAgIHRoaXMuZWNob0lucHV0ID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLmlucHV0RmllbGQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImlucHV0LWFyZWFcIik7XHJcbiAgICAgICAgdGhpcy5pbml0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0RWNobyh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMuZWNob0lucHV0ID0gdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLmlucHV0RmllbGQuYWRkRXZlbnRMaXN0ZW5lcihcImtleWRvd25cIiwgKGUpID0+IHtcclxuICAgICAgICAgICAgaWYgKGUud2hpY2ggPT0gMTMpIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbCA9IHRoaXMuaW5wdXRGaWVsZC52YWx1ZTtcclxuICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRGaWVsZC52YWx1ZSA9IFwiXCI7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5lY2hvSW5wdXQpIHRoaXMub3V0cHV0LnNheShgPiAke3ZhbH1gKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlci5kb0NvbW1hbmQodmFsKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pXHJcbiAgICB9XHJcbn0iLCJpbXBvcnQgTG9va0NvbW1hbmQgZnJvbSBcIi4vY29tbWFuZHMvbG9va1wiO1xyXG5pbXBvcnQgVXNlQ29tbWFuZCBmcm9tIFwiLi9jb21tYW5kcy91c2VcIjtcclxuaW1wb3J0IFRha2VDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL3Rha2VcIjtcclxuaW1wb3J0IERyb3BDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2Ryb3BcIjtcclxuaW1wb3J0IEVjaG9Db21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2VjaG9cIjtcclxuaW1wb3J0IFNhdmVDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL3NhdmVcIjtcclxuaW1wb3J0IExvYWRDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2xvYWRcIjtcclxuaW1wb3J0IFZvbHVtZUNvbW1hbmQgZnJvbSBcIi4vY29tbWFuZHMvdm9sdW1lXCI7XHJcbmltcG9ydCBJbnZlbnRvcnlDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2ludmVudG9yeVwiO1xyXG5cclxuY29uc3QgZGVmYXVsdENvbW1hbmRzID0gW1xyXG4gICAgW1tcImxvb2tcIiwgXCJsXCJdLCBMb29rQ29tbWFuZF0sXHJcbiAgICBbW1widXNlXCIsIFwiaW50ZXJhY3RcIl0sIFVzZUNvbW1hbmRdLFxyXG4gICAgW1tcInRha2VcIiwgXCJnZXRcIl0sIFRha2VDb21tYW5kXSxcclxuICAgIFtbXCJkcm9wXCIsIFwicHV0XCJdLCBEcm9wQ29tbWFuZF0sXHJcbiAgICBbXCJlY2hvXCIsIEVjaG9Db21tYW5kXSxcclxuICAgIFtcInNhdmVcIiwgU2F2ZUNvbW1hbmRdLFxyXG4gICAgW1wibG9hZFwiLCBMb2FkQ29tbWFuZF0sXHJcbiAgICBbXCJ2b2x1bWVcIiwgVm9sdW1lQ29tbWFuZF0sXHJcbiAgICBbW1wiaVwiLCBcImludlwiLCBcImludmVudG9yeVwiXSwgSW52ZW50b3J5Q29tbWFuZF1cclxuXTtcclxuXHJcbmNvbnN0IGRpcmVjdGlvbk1hcCA9IFtcclxuICAgIFtcIm5cIiwgXCJub3J0aFwiXSxcclxuICAgIFtcIm5lXCIsIFwibm9ydGhlYXN0XCJdLFxyXG4gICAgW1wiZVwiLCBcImVhc3RcIl0sXHJcbiAgICBbXCJzZVwiLCBcInNvdXRoZWFzdFwiXSxcclxuICAgIFtcInNcIiwgXCJzb3V0aFwiXSxcclxuICAgIFtcInN3XCIsIFwic291dGh3ZXN0XCJdLFxyXG4gICAgW1wid1wiLCBcIndlc3RcIl0sXHJcbiAgICBbXCJud1wiLCBcIm5vcnRod2VzdFwiXSxcclxuICAgIFtcInVcIiwgXCJ1cFwiXSxcclxuICAgIFtcImRcIiwgXCJkb3duXCJdXHJcbl07XHJcblxyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDb21tYW5kcyB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBjb21tYW5kcykge1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5jb21tYW5kcyA9IGNvbW1hbmRzIHx8IG5ldyBNYXAoKTtcclxuICAgICAgICB0aGlzLmVuYWJsZWQgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuYWRkRGVmYXVsdENvbW1hbmRzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZG9Db21tYW5kKHN0cikge1xyXG4gICAgICAgIGlmICghdGhpcy5lbmFibGVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5wcmludChgWW91IGNhbid0IHNlZW0gdG8gZG8gYW55dGhpbmcgYXQgdGhlIG1vbWVudC5gKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCByb29tID0gdGhpcy5jb250ZXh0LmdldFJvb20odGhpcy5jb250ZXh0LnBsYXllci5jdXJyZW50Um9vbSk7XHJcbiAgICAgICAgY29uc3Qgc3BsaXQgPSBzdHIuc3BsaXQoXCIgXCIpO1xyXG4gICAgICAgIGlmICh0aGlzLmNvbW1hbmRzLmdldChzcGxpdFswXSkpIHtcclxuICAgICAgICAgICAgdGhpcy5jb21tYW5kcy5nZXQoc3BsaXRbMF0pKHNwbGl0LCB0aGlzLmNvbnRleHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICBjb25zdCBkaXJlY3Rpb24gPSB0aGlzLm1hdGNoRGlyZWN0aW9uKHNwbGl0WzBdKTtcclxuXHJcbiAgICAgICAgaWYgKHJvb20uZ2V0RXhpdChkaXJlY3Rpb24pKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5tb3ZlKHJvb20uZ2V0RXhpdChkaXJlY3Rpb24pKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgYWRkQ29tbWFuZChuYW1lLCBmdW5jKSB7XHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkobmFtZSkpIHtcclxuICAgICAgICAgICAgbmFtZS5mb3JFYWNoKChjb21tYW5kKSA9PiB0aGlzLmNvbW1hbmRzLnNldChjb21tYW5kLCBmdW5jKSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5jb21tYW5kcy5zZXQobmFtZSwgZnVuYyk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFkZENvbW1hbmRzKGNvbW1hbmRzKSB7XHJcbiAgICAgICAgY29tbWFuZHMuZm9yRWFjaCgoY29tbWFuZCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmFkZENvbW1hbmQoY29tbWFuZFswXSwgY29tbWFuZFsxXSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRGVmYXVsdENvbW1hbmRzKCkge1xyXG4gICAgICAgIHRoaXMuYWRkQ29tbWFuZHMoZGVmYXVsdENvbW1hbmRzKTtcclxuICAgIH1cclxuXHJcbiAgICBtYXRjaERpcmVjdGlvbihzdHIpIHtcclxuICAgICAgICBmb3IgKGxldCBkaXIgb2YgZGlyZWN0aW9uTWFwKSB7XHJcbiAgICAgICAgICAgIGlmIChkaXJbMF0gPT0gc3RyKSByZXR1cm4gZGlyWzFdO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIExvb2tDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGlmIChhcmdzLmxlbmd0aCA9PSAxKSB7XHJcbiAgICAgICAgY29udGV4dC5leGFtaW5lUm9vbSgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBjb25zdCByb29tID0gY29udGV4dC5nZXRSb29tKGNvbnRleHQucGxheWVyLmN1cnJlbnRSb29tKTtcclxuICAgICAgICBjb25zdCBpdGVtcyA9IHJvb20uZ2V0SXRlbXMoKTtcclxuICAgICAgICBsZXQgaXRlbSA9IG51bGw7XHJcbiAgICAgICAgZm9yIChsZXQgaSBvZiBpdGVtcykge1xyXG4gICAgICAgICAgICBpZiAoaS5uYW1lLmluY2x1ZGVzKGFyZ3NbMV0pKSB7XHJcbiAgICAgICAgICAgICAgICBpdGVtID0gaTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghaXRlbSkge1xyXG4gICAgICAgICAgICBjb25zdCBpdGVtcyA9IGNvbnRleHQucGxheWVyLmdldEludmVudG9yeSgpO1xyXG4gICAgICAgICAgICBmb3IgKGxldCBpIG9mIGl0ZW1zKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoaS5uYW1lLmluY2x1ZGVzKGFyZ3NbMV0pKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaXRlbSA9IGk7XHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCFpdGVtKSB7XHJcbiAgICAgICAgICAgIGNvbnRleHQub3V0cHV0LnNheShgSSBjb3VsZCBub3QgZmluZCBhICR7YXJnc1sxXX0uYCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgY29udGV4dC5vdXRwdXQuc2F5KGBZb3UgbG9vayBhdCAke2l0ZW0ubmFtZX0uYCk7XHJcbiAgICAgICAgICAgIGNvbnRleHQub3V0cHV0LnNheShpdGVtLmRlc2NyaXB0aW9uKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBVc2VDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGNvbnN0IHJvb20gPSBjb250ZXh0LmdldFJvb20oY29udGV4dC5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgY29uc3QgaXRlbXMgPSByb29tLmdldEl0ZW1zKCk7XHJcbiAgICBsZXQgaXRlbSA9IG51bGw7XHJcbiAgICBmb3IgKGxldCBpIG9mIGl0ZW1zKSB7XHJcbiAgICAgICAgaWYgKGkubmFtZS5pbmNsdWRlcyhhcmdzWzFdKSkge1xyXG4gICAgICAgICAgICBpdGVtID0gaTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYgKCFpdGVtKSB7XHJcbiAgICAgICAgY29uc3QgaXRlbXMgPSBjb250ZXh0LnBsYXllci5nZXRJbnZlbnRvcnkoKTtcclxuICAgICAgICBmb3IgKGxldCBpIG9mIGl0ZW1zKSB7XHJcbiAgICAgICAgICAgIGlmIChpLm5hbWUuaW5jbHVkZXMoYXJnc1sxXSkpIHtcclxuICAgICAgICAgICAgICAgIGl0ZW0gPSBpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoIWl0ZW0pIHtcclxuICAgICAgICBjb250ZXh0Lm91dHB1dC5zYXkoYEkgY291bGQgbm90IGZpbmQgYSAke2FyZ3NbMV19LmApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBhd2FpdCBpdGVtLm9uVXNlKCk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBUYWtlQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb25zdCByb29tID0gY29udGV4dC5nZXRSb29tKGNvbnRleHQucGxheWVyLmN1cnJlbnRSb29tKTtcclxuICAgIGNvbnN0IGl0ZW1zID0gcm9vbS5nZXRJdGVtcygpO1xyXG4gICAgbGV0IGl0ZW0gPSBudWxsO1xyXG4gICAgZm9yIChsZXQgaSBvZiBpdGVtcykge1xyXG4gICAgICAgIGlmIChpLm5hbWUuaW5jbHVkZXMoYXJnc1sxXSkpIHtcclxuICAgICAgICAgICAgaXRlbSA9IGk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGlmICghaXRlbSkge1xyXG4gICAgICAgIGNvbnRleHQucHJpbnQoYFlvdSBjYW4ndCBmaW5kIGFueSAke2FyZ3NbMV19LmApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoIWl0ZW0udGFrZWFibGUpIHtcclxuICAgICAgICAgICAgY29udGV4dC5wcmludChgWW91IGNhbid0IHRha2UgJHtpdGVtLm5hbWV9LmApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHJvb20ucmVtb3ZlSXRlbShpdGVtLmlkKTtcclxuICAgICAgICAgICAgY29udGV4dC5wbGF5ZXIuYWRkSXRlbShpdGVtLmlkKTtcclxuICAgICAgICAgICAgY29udGV4dC5wcmludChgWW91IHRha2UgJHtpdGVtLm5hbWV9LmApO1xyXG4gICAgICAgICAgICBpdGVtLm9uVGFrZSgpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIERyb3BDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGNvbnN0IHJvb20gPSBjb250ZXh0LmdldFJvb20oY29udGV4dC5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgY29uc3QgaXRlbXMgPSBjb250ZXh0LnBsYXllci5nZXRJbnZlbnRvcnkoKTtcclxuICAgIGxldCBpdGVtID0gbnVsbDtcclxuICAgIGZvciAobGV0IGkgb2YgaXRlbXMpIHtcclxuICAgICAgICBpZiAoaS5uYW1lLmluY2x1ZGVzKGFyZ3NbMV0pKSB7XHJcbiAgICAgICAgICAgIGl0ZW0gPSBpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoIWl0ZW0pIHtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBZb3UncmUgbm90IGNhcnJ5aW5nIGEgJHthcmdzWzFdfWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBjb250ZXh0LnBsYXllci5yZW1vdmVJdGVtKGl0ZW0uaWQpO1xyXG4gICAgICAgIHJvb20uYWRkSXRlbShpdGVtLmlkKTtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBZb3Ugc2V0ICR7aXRlbS5uYW1lfSBkb3duIG9uIHRoZSBmbG9vci5gKTtcclxuICAgICAgICBpdGVtLm9uRHJvcCgpO1xyXG4gICAgfVxyXG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRWNob0NvbW1hbmQoYXJncywgY29udGV4dCkge1xyXG4gICAgaWYgKGFyZ3NbMV0gIT0gXCJvblwiICYmIGFyZ3NbMV0gIT0gXCJvZmZcIikge1xyXG4gICAgICAgIGNvbnRleHQucHJpbnQoYFVzYWdlOiBlY2hvIDxvbi9vZmY+YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnRleHQuc2V0SW5wdXRFY2hvKGFyZ3NbMV0gPT0gXCJvblwiID8gdHJ1ZSA6IGZhbHNlKTtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBDb21tYW5kIGVjaG8gaXMgbm93ICR7YXJnc1sxXX0uYCk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBTYXZlQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBTYXZpbmcgZ2FtZS4uLmApO1xyXG4gICAgY29udGV4dC5zYXZlKCk7XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBMb2FkQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBMb2FkaW5nIGdhbWUuLi5gKTtcclxuICAgIGNvbnRleHQubG9hZCgpO1xyXG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gVm9sdW1lQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBpZiAoYXJncy5sZW5ndGggPCAzKSB7XHJcbiAgICAgICAgcmV0dXJuIGNvbnRleHQucHJpbnQoYFVzYWdlOiB2b2x1bWUgPG11c2ljL3NmeC9hbWJpZW5jZT4gPDAtMTAwPmApO1xyXG4gICAgfVxyXG4gICAgY29uc3QgdmFsdWUgPSBwYXJzZUludChhcmdzWzJdKTtcclxuICAgIGlmICh2YWx1ZSA+IDEwMCB8fCB2YWx1ZSA8IDEpIHtcclxuICAgICAgICByZXR1cm4gY29udGV4dC5wcmludChgTm8gaGlnaGVyIHRoYW4gMTAwIGFuZCBubyBsZXNzIHRoYW4gMS5gKTtcclxuICAgIH1cclxuICAgIGlmIChhcmdzWzFdID09IFwic2Z4XCIpIHtcclxuICAgICAgICBjb250ZXh0Lm91dHB1dC5zb3VuZC5zZXRTRlhWb2x1bWUodmFsdWUvMTAwKTtcclxuICAgIH0gZWxzZSBpZiAoYXJnc1sxXSA9PSBcIm11c2ljXCIpIHtcclxuICAgICAgICBjb250ZXh0Lm91dHB1dC5zb3VuZC5zZXRNdXNpY1ZvbHVtZSh2YWx1ZS8xMDApO1xyXG4gICAgfSBlbHNlIGlmIChhcmdzWzFdID09IFwiYW1iaWVuY2VcIikge1xyXG4gICAgICAgIGNvbnRleHQub3V0cHV0LnNvdW5kLnNldEFtYmllbmNlVm9sdW1lKHZhbHVlLzEwMCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiBjb250ZXh0LnByaW50KGBJbnZhbGlkIGNoYW5uZWwuIEVpdGhlciBhbWJpZW5jZSwgc2Z4IG9yIG11c2ljIGlzIGFsbG93ZWQuYCk7XHJcbiAgICB9XHJcbiAgICBjb250ZXh0LnByaW50KGAke2FyZ3NbMV19IHZvbHVtZSBzZXQgdG8gJHt2YWx1ZX0lYClcclxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEludmVudG9yeUNvbW1hbmQoYXJncywgY29udGV4dCkge1xyXG4gICAgY29uc3QgaXRlbXMgPSBjb250ZXh0LnBsYXllci5nZXRJbnZlbnRvcnkoKTtcclxuICAgIGlmIChpdGVtcy5sZW5ndGggPCAxKSByZXR1cm4gY29udGV4dC5wcmludChgWW91J3JlIG5vdCBjYXJyeWluZyBhbnl0aGluZy5gKTtcclxuICAgIGxldCBpdGVtRGVzY3JpcHRpb24gPSBgWW91IGFyZSBjYXJyeWluZyBgO1xyXG4gICAgaXRlbXMuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcclxuICAgICAgICBpZiAoaW5kZXggPCBpdGVtcy5sZW5ndGggLSAyKSB7XHJcbiAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBgJHtpdGVtLm5hbWV9LCBgO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoaW5kZXggPCBpdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBgJHtpdGVtLm5hbWV9IGFuZCBgO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBpdGVtLm5hbWVcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxuICAgIGNvbnRleHQucHJpbnQoaXRlbURlc2NyaXB0aW9uICsgXCIuXCIpO1xyXG59IiwiZXhwb3J0IGRlZmF1bHQgY2xhc3MgU2VyaWFsaXphdGlvbiB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0KSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcclxuICAgIH1cclxuXHJcbiAgICBzYXZlKCkge1xyXG4gICAgICAgIGNvbnN0IHNhdmVvYmogPSB7XHJcbiAgICAgICAgICAgIHN0YXRlOiB0aGlzLmNvbnRleHQuc3RhdGUuc2VyaWFsaXplKCksXHJcbiAgICAgICAgICAgIGl0ZW1Mb2NhdGlvbnM6IHRoaXMuc2VyaWFsaXplSXRlbUxvY2F0aW9ucygpLFxyXG4gICAgICAgICAgICBwbGF5ZXI6ICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGN1cnJlbnRSb29tOiB0aGlzLmNvbnRleHQucGxheWVyLmN1cnJlbnRSb29tLFxyXG4gICAgICAgICAgICAgICAgaW52ZW50b3J5OiB0aGlzLmNvbnRleHQucGxheWVyLmludmVudG9yeVxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB2b2x1bWVzOiB7XHJcbiAgICAgICAgICAgICAgICBtdXNpYzogdGhpcy5jb250ZXh0Lm91dHB1dC5zb3VuZC5tdXNpY1ZvbHVtZSxcclxuICAgICAgICAgICAgICAgIHNmeDogdGhpcy5jb250ZXh0Lm91dHB1dC5zb3VuZC5zZnhWb2x1bWUsXHJcbiAgICAgICAgICAgICAgICBhbWJpZW5jZTogdGhpcy5jb250ZXh0Lm91dHB1dC5zb3VuZC5hbWJpZW5jZVZvbHVtZVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShcInNhdmVcIiwgSlNPTi5zdHJpbmdpZnkoc2F2ZW9iaikpO1xyXG4gICAgfVxyXG5cclxuICAgIGxvYWQoKSB7XHJcbiAgICAgICAgY29uc3QgbG9hZG9iaiA9IEpTT04ucGFyc2UobG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJzYXZlXCIpKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQuc3RhdGUuZGVzZXJpYWxpemUobG9hZG9iai5zdGF0ZSk7XHJcbiAgICAgICAgdGhpcy5kZXNlcmlhbGl6ZUl0ZW1Mb2NhdGlvbnMobG9hZG9iai5pdGVtTG9jYXRpb25zKTtcclxuICAgICAgICB0aGlzLmRlc2VyaWFsaXplUGxheWVyKGxvYWRvYmoucGxheWVyKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQub3V0cHV0LnNvdW5kLnNldFNGWFZvbHVtZShsb2Fkb2JqLnZvbHVtZXMuc2Z4KTtcclxuICAgICAgICB0aGlzLmNvbnRleHQub3V0cHV0LnNvdW5kLnNldE11c2ljVm9sdW1lKGxvYWRvYmoudm9sdW1lcy5tdXNpYyk7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0Lm91dHB1dC5zb3VuZC5zZXRBbWJpZW5jZVZvbHVtZShsb2Fkb2JqLnZvbHVtZXMuYW1iaWVuY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIHNlcmlhbGl6ZUl0ZW1Mb2NhdGlvbnMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5yb29tcy5tYXAoKGl0ZW0pID0+IHtcclxuICAgICAgICAgICAgcmV0dXJuIFtpdGVtLmlkLCBcclxuICAgICAgICAgICAgICAgIGl0ZW0ub2JqZWN0c1xyXG4gICAgICAgICAgICBdXHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgZGVzZXJpYWxpemVJdGVtTG9jYXRpb25zKGl0ZW1zKSB7XHJcbiAgICAgICAgaXRlbXMuZm9yRWFjaCgoaXRlbSkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5jb250ZXh0LmdldFJvb20oaXRlbVswXSk7XHJcbiAgICAgICAgICAgIHJvb20ub2JqZWN0cyA9IGl0ZW1bMV07XHJcbiAgICAgICAgfSlcclxuICAgIH1cclxuXHJcbiAgICBkZXNlcmlhbGl6ZVBsYXllcihwbGF5ZXIpIHtcclxuICAgICAgICB0aGlzLmNvbnRleHQubW92ZShwbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIHRoaXMuY29udGV4dC5wbGF5ZXIuaW52ZW50b3J5ID0gcGxheWVyLmludmVudG9yeTtcclxuICAgIH1cclxufSIsImltcG9ydCBTdGF0ZSBmcm9tICcuL3N0YXRlJztcclxuaW1wb3J0IFJvb20gZnJvbSAnLi9yb29tJztcclxuaW1wb3J0IFBsYXllciBmcm9tICcuL3BsYXllcic7XHJcbmltcG9ydCBPdXRwdXQgZnJvbSAnLi9vdXRwdXQnO1xyXG5pbXBvcnQgSW5wdXQgZnJvbSAnLi9pbnB1dCc7XHJcbmltcG9ydCBDb21tYW5kcyBmcm9tICcuL2NvbW1hbmRzJztcclxuaW1wb3J0IFNlcmlhbGl6YXRpb24gZnJvbSAnLi9zZXJpYWxpemF0aW9uJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEdhbWUge1xyXG4gICAgY29uc3RydWN0b3IobmV3R2FtZSA9IHRydWUpIHtcclxuICAgICAgICB0aGlzLm5ld0dhbWUgPSBuZXdHYW1lO1xyXG4gICAgICAgIHRoaXMucGxheWVyID0gbmV3IFBsYXllcigpO1xyXG4gICAgICAgIHRoaXMuc3RhdGUgPSBTdGF0ZTtcclxuICAgICAgICB0aGlzLnJvb21zID0gW107XHJcbiAgICAgICAgdGhpcy5pdGVtcyA9IFtdO1xyXG4gICAgICAgIHRoaXMub3V0cHV0ID0gbmV3IE91dHB1dCgpO1xyXG4gICAgICAgIHRoaXMuY29tbWFuZEhhbmRsZXIgPSBuZXcgQ29tbWFuZHModGhpcyk7XHJcbiAgICAgICAgdGhpcy5pbnB1dCA9IG5ldyBJbnB1dCh0aGlzLmNvbW1hbmRIYW5kbGVyLCB0aGlzLm91dHB1dCk7XHJcbiAgICAgICAgdGhpcy52aXNpdGVkUm9vbXMgPSBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5pbnRlcnZhbCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5TZXJpYWxpemF0aW9uID0gbmV3IFNlcmlhbGl6YXRpb24odGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpbnQoc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHN0cmluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgdGVsbChsaW5lcywgdGltZSkge1xyXG4gICAgICAgIGZvciAobGV0IGxpbmUgb2YgbGluZXMpIHtcclxuICAgICAgICAgICAgdGhpcy5wcmludChsaW5lKTtcclxuICAgICAgICAgICAgYXdhaXQgdGhpcy53YWl0KHRpbWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpbml0KGRhdGEpIHtcclxuICAgICAgICB0aGlzLnJvb21zID0gZGF0YS5yb29tcy5tYXAoKHJvb20pID0+IHtcclxuICAgICAgICAgICAgcm9vbS5jb250ZXh0ID0gdGhpcztcclxuICAgICAgICAgICAgcmV0dXJuIHJvb207XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5pdGVtcyA9IGRhdGEuaXRlbXMubWFwKChpdGVtKSA9PiB7XHJcbiAgICAgICAgICAgIGl0ZW0uY29udGV4dCA9IHRoaXM7XHJcbiAgICAgICAgICAgIHJldHVybiBpdGVtO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuc3RhdGUgPSBkYXRhLnN0YXRlIHx8IFN0YXRlO1xyXG4gICAgICAgIHRoaXMuY29tbWFuZEhhbmRsZXIuYWRkQ29tbWFuZHMoZGF0YS5jb21tYW5kcyk7XHJcbiAgICAgICAgdGhpcy5wbGF5ZXIgPSBuZXcgUGxheWVyKCk7XHJcbiAgICAgICAgdGhpcy5wbGF5ZXIuY29udGV4dCA9IHRoaXM7XHJcbiAgICAgICAgaWYgKHRoaXMubmV3R2FtZSkge1xyXG4gICAgICAgICAgICB0aGlzLm1vdmUodGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuU2VyaWFsaXphdGlvbi5sb2FkKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuc3RhcnQoKTtcclxuICAgIH1cclxuXHJcbiAgICBhZHZhbmNlVGljaygpIHtcclxuICAgICAgICB0aGlzLml0ZW1zLmZvckVhY2goKGl0ZW0pID0+IGl0ZW0ub25UaWNrKCkpO1xyXG4gICAgICAgIHRoaXMucm9vbXMuZm9yRWFjaCgocm9vbSkgPT4gcm9vbS5vblRpY2soKSk7XHJcbiAgICB9XHJcblxyXG4gICAgc3RhcnQoKSB7XHJcbiAgICAgICAgdGhpcy5pbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHRoaXMuYWR2YW5jZVRpY2soKSwgMTAwMCk7XHJcbiAgICB9XHJcblxyXG4gICAgc3RvcCgpIHtcclxuICAgICAgICBjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWwpO1xyXG4gICAgICAgIHRoaXMuaW50ZXJ2YWwgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGV4YW1pbmVSb29tKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnNheShyb29tLnRpdGxlKTtcclxuICAgICAgICBpZiAoIXRoaXMudmlzaXRlZFJvb21zLmdldCh0aGlzLnBsYXllci5jdXJyZW50Um9vbSkgJiYgcm9vbS5maXJzdERlc2NyaXB0aW9uICE9IFwiXCIpIHtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHJvb20uZmlyc3REZXNjcmlwdGlvbik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHJvb20uZGVzY3JpcHRpb24pO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmV4YW1pbmVJdGVtcygpO1xyXG4gICAgICAgIHRoaXMuZXhhbWluZUV4aXRzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZXhhbWluZUl0ZW1zKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGNvbnN0IGl0ZW1zID0gcm9vbS5nZXRJdGVtcygpO1xyXG4gICAgICAgIGlmIChpdGVtcy5sZW5ndGggPCAxKSByZXR1cm47XHJcbiAgICAgICAgbGV0IGl0ZW1EZXNjcmlwdGlvbiA9IGBZb3Ugc2VlIGA7XHJcbiAgICAgICAgaXRlbXMuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcclxuICAgICAgICAgICAgaWYgKGluZGV4IDwgaXRlbXMubGVuZ3RoIC0gMikge1xyXG4gICAgICAgICAgICAgICAgaXRlbURlc2NyaXB0aW9uICs9IGAke2l0ZW0ubmFtZX0sIGA7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoaW5kZXggPCBpdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgICAgICBpdGVtRGVzY3JpcHRpb24gKz0gYCR7aXRlbS5uYW1lfSBhbmQgYDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBpdGVtLm5hbWVcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnNheShpdGVtRGVzY3JpcHRpb24gKyBcIi5cIik7XHJcbiAgICB9XHJcblxyXG4gICAgZXhhbWluZUV4aXRzKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGxldCBleGl0cyA9IFtdO1xyXG4gICAgICAgIGxldCBleGl0RGVzY3JpcHRpb24gPSBcIllvdSBjYW4gZ28gXCI7XHJcbiAgICAgICAgY29uc3QgZXhpdEtleXMgPSByb29tLmV4aXRzLmtleXMoKTtcclxuICAgICAgICBmb3IgKGxldCBleGl0IG9mIGV4aXRLZXlzKSB7XHJcbiAgICAgICAgICAgIGV4aXRzLnB1c2goZXhpdCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGV4aXRzLmZvckVhY2goKGl0ZW0sIGluZGV4KSA9PiB7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA8IGV4aXRzLmxlbmd0aCAtIDIpIHtcclxuICAgICAgICAgICAgICAgIGV4aXREZXNjcmlwdGlvbiArPSBgJHtpdGVtfSwgYDtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChpbmRleCA8IGV4aXRzLmxlbmd0aCAtIDEpIHtcclxuICAgICAgICAgICAgICAgIGV4aXREZXNjcmlwdGlvbiArPSBgJHtpdGVtfSBhbmQgYDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGV4aXREZXNjcmlwdGlvbiArPSBpdGVtXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgICB0aGlzLm91dHB1dC5zYXkoZXhpdERlc2NyaXB0aW9uICsgXCIuXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIGdldFJvb20oaWQpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yb29tcy5maW5kKChyb29tKSA9PiByb29tLmlkID09IGlkKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRJdGVtKGlkKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS5pZCA9PSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgd2FpdChtcykge1xyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG1vdmUocm9vbUlEKSB7XHJcbiAgICAgICAgY29uc3QgY3VycmVudFJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGNvbnN0IG5ld1Jvb20gPSB0aGlzLmdldFJvb20ocm9vbUlEKTtcclxuICAgICAgICBpZiAoY3VycmVudFJvb20uY2FuRXhpdCgpICYmIG5ld1Jvb20uY2FuRW50ZXIoKSkge1xyXG4gICAgICAgICAgICBhd2FpdCBjdXJyZW50Um9vbS5vbkV4aXQoKTtcclxuICAgICAgICAgICAgYXdhaXQgbmV3Um9vbS5vbkVudGVyKCk7XHJcbiAgICAgICAgICAgIHRoaXMucGxheWVyLmN1cnJlbnRSb29tID0gcm9vbUlEO1xyXG4gICAgICAgICAgICB0aGlzLmV4YW1pbmVSb29tKCk7XHJcbiAgICAgICAgICAgIHRoaXMudmlzaXRlZFJvb21zLnNldChyb29tSUQsIHRydWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBlbmFibGVDb21tYW5kSW5wdXQodmFsdWUpIHtcclxuICAgICAgICB0aGlzLmNvbW1hbmRIYW5kbGVyLmVuYWJsZWQgPSB2YWx1ZTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRJbnB1dEVjaG8odmFsdWUpIHtcclxuICAgICAgICB0aGlzLmlucHV0LnNldEVjaG8odmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHNhdmUoKSB7XHJcbiAgICAgICAgdGhpcy5TZXJpYWxpemF0aW9uLnNhdmUoKTtcclxuICAgIH1cclxuXHJcbiAgICBsb2FkKCkge1xyXG4gICAgICAgIHRoaXMuU2VyaWFsaXphdGlvbi5sb2FkKCk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBjbGFzcyBSb29tIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuaWQgPSBcInJvb21cIjtcclxuICAgICAgICB0aGlzLnRpdGxlID0gXCJBIHJvb21cIjtcclxuICAgICAgICB0aGlzLmRlc2NyaXB0aW9uID0gXCJZb3Ugc2VlIG5vdGhpbmcgc3BlY2lhbFwiO1xyXG4gICAgICAgIHRoaXMuZmlyc3REZXNjcmlwdGlvbiA9IFwiXCI7XHJcbiAgICAgICAgdGhpcy5vYmplY3RzID0gW107XHJcbiAgICAgICAgdGhpcy5leGl0cyA9IG5ldyBNYXAoKTtcclxuICAgICAgICB0aGlzLmVudGVyQ2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuZXhpdENhbGxiYWNrID0gbnVsbDtcclxuICAgICAgICB0aGlzLmNhbkVudGVyTG9naWMgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuY2FuRXhpdExvZ2ljID0gbnVsbDtcclxuICAgICAgICB0aGlzLnRpY2tDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLm11c2ljID0gbnVsbDtcclxuICAgICAgICB0aGlzLmFtYmllbmNlID0gbnVsbDtcclxuICAgICAgICB0aGlzLmltcHVsc2UgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uRW50ZXIoKSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0Lm91dHB1dC5zZXRNdXNpYyh0aGlzLm11c2ljKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQub3V0cHV0LnNldEFtYmllbmNlKHRoaXMuYW1iaWVuY2UpO1xyXG4gICAgICAgIHRoaXMuY29udGV4dC5vdXRwdXQuc2V0SW1wdWxzZSh0aGlzLmltcHVsc2UpO1xyXG4gICAgICAgIGlmICh0aGlzLmVudGVyQ2FsbGJhY2spIHJldHVybiB0aGlzLmVudGVyQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkV4aXQoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZXhpdENhbGxiYWNrKSByZXR1cm4gdGhpcy5leGl0Q2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBjYW5FbnRlcigpIHtcclxuICAgICAgICBpZiAodGhpcy5jYW5FbnRlckxvZ2ljKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNhbkVudGVyTG9naWModGhpcy5jb250ZXh0KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgY2FuRXhpdCgpIHtcclxuICAgICAgICBpZiAodGhpcy5jYW5FeGl0TG9naWMpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FuRXhpdExvZ2ljKHRoaXMuY29udGV4dCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEV4aXQoZGlyZWN0aW9uLCByb29tSUQpIHtcclxuICAgICAgICB0aGlzLmV4aXRzLnNldChkaXJlY3Rpb24sIHJvb21JRCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0RXhpdChkaXJlY3Rpb24pIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5leGl0cy5nZXQoZGlyZWN0aW9uKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGRJdGVtKGl0ZW0pIHtcclxuICAgICAgICB0aGlzLm9iamVjdHMucHVzaChpdGVtKTtcclxuICAgIH1cclxuXHJcbiAgICByZW1vdmVJdGVtKGlkKSB7XHJcbiAgICAgICAgdGhpcy5vYmplY3RzID0gdGhpcy5vYmplY3RzLmZpbHRlcigoaXRlbSkgPT4gaXRlbSAhPSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRW50ZXJDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuZW50ZXJDYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRXhpdENhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5leGl0Q2FsbGJhY2sgPSBjYWxsYmFjay5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEVudGVyTG9naWMoZnVuYykge1xyXG4gICAgICAgIHRoaXMuY2FuRW50ZXJMb2dpYyA9IGZ1bmMuYmluZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGRFeGl0TG9naWMoZnVuYykge1xyXG4gICAgICAgIHRoaXMuY2FuRXhpdExvZ2ljID0gZnVuYy5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZFRpY2tDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMudGlja0NhbGxiYWNrID0gY2FsbGJhY2suYmluZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRJdGVtcygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5vYmplY3RzLm1hcCgoaXRlbSkgPT4gdGhpcy5jb250ZXh0LmdldEl0ZW0oaXRlbSkpO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uVGljaygpIHtcclxuICAgICAgICBpZiAodGhpcy50aWNrQ2FsbGJhY2spIHJldHVybiB0aGlzLnRpY2tDYWxsYmFjayh0aGlzLmNvbnRleHQpO1xyXG4gICAgfVxyXG59IiwiaW1wb3J0IFJvb20gZnJvbSAnLi4vcm9vbSc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSb29tQnVpbGRlciB7XHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgICAgICB0aGlzLnJvb20gPSBuZXcgUm9vbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhJRChJRCkge1xyXG4gICAgICAgIHRoaXMucm9vbS5pZCA9IElEO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhUaXRsZSh0aXRsZSkge1xyXG4gICAgICAgIHRoaXMucm9vbS50aXRsZSA9IHRpdGxlO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhGaXJzdERlc2NyaXB0aW9uKGRlc2NyaXB0aW9uKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmZpcnN0RGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRGVzY3JpcHRpb24oZGVzY3JpcHRpb24pIHtcclxuICAgICAgICB0aGlzLnJvb20uZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRXhpdChkaXJlY3Rpb24sIHJvb21JRCkge1xyXG4gICAgICAgIHRoaXMucm9vbS5hZGRFeGl0KGRpcmVjdGlvbiwgcm9vbUlEKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoSXRlbShpdGVtSUQpIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkSXRlbShpdGVtSUQpO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhFbnRlckNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEVudGVyQ2FsbGJhY2soY2FsbGJhY2spO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhFeGl0Q2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkRXhpdENhbGxiYWNrKGNhbGxiYWNrKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRW50ZXJMb2dpYyhmdW5jKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEVudGVyTG9naWMoZnVuYyk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEV4aXRMb2dpYyhmdW5jKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEV4aXRMb2dpYyhmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoVGljayhmdW5jKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZFRpY2tDYWxsYmFjayhmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoTXVzaWMoZmlsZSkge1xyXG4gICAgICAgIHRoaXMucm9vbS5tdXNpYyA9IGZpbGU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEFtYmllbmNlKGZpbGUpIHtcclxuICAgICAgICB0aGlzLnJvb20uYW1iaWVuY2UgPSBmaWxlO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhJbXB1bHNlKGZpbGUpIHtcclxuICAgICAgICB0aGlzLnJvb20uaW1wdWxzZSA9IGZpbGU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIGNyZWF0ZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yb29tO1xyXG4gICAgfVxyXG59IiwiaW1wb3J0IFJvb21CdWlsZGVyIGZyb20gJy4uLy4uLy4uL2VuZ2luZS9idWlsZGVycy9yb29tJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGFydFwiKVxyXG4ud2l0aFRpdGxlKFwiQSBzbWFsbCBzcGhlcmljYWwgYWxjb3ZlXCIpXHJcbi53aXRoRmlyc3REZXNjcmlwdGlvbihcclxuYFlvdSBmaW5kIHlvdXJzZWxmIGluIGEgc21hbGwsIHNwaGVyaWNhbCBhbGNvdmUuIEl0IGZlZWxzIGNvbGQgYW5kIGRhcmssIHNhdmUgZnJvbSBhIGRpbSBnbG93IHdoaWNoIHNlZW1zIHRvIGJlIGVsdW1pbmF0aW5nIHRoZSBhcmVhIGZyb20gdGhlIG5vcnRoLlxyXG5UaGUgc3VyZmFjZSBhcHBlYXJzIHRvIGJlIHVubmF0dXJhbGx5IHNtb290aCwgYXMgaWYgbWVsdGVkIGF3YXkgdXNpbmcgYWNpZGljIG1lYW5zLiBJdCdzIHdhcm0gdG8gdGhlIHRvdWNoLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG5gQSBzcGhlcmljYWwgYWxjb3ZlLiBUaGUgc21vb3RoIHN1cmZhY2UgYXBwZWFycyB0byBiZSBtZWx0ZWQgYXdheSB1c2luZyBhY2lkaWMgbWVhbnMuIFRoZXJlJ3MgYSBkaW0gZ2xvdyBzaGluaW5nIGluIGZyb20gdGhlIG5vcnRoLmBcclxuKVxyXG4ud2l0aEV4aXQoXCJub3J0aFwiLCBcInR1bm5lbDFcIilcclxuLndpdGhFbnRlckNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uKGNvbnRleHQpIHtcclxuICAgIGlmIChjb250ZXh0LnN0YXRlLmdldChcInN0YXJ0LmF3b2tlblwiKSkgcmV0dXJuO1xyXG4gICAgY29uc3QgeyBvdXRwdXQsIHdhaXQgfSA9IGNvbnRleHQ7XHJcbiAgICBjb250ZXh0LmVuYWJsZUNvbW1hbmRJbnB1dChmYWxzZSk7XHJcbiAgICBhd2FpdCBjb250ZXh0LnRlbGwoW1xyXG4gICAgICAgIFwiWW91IHNsb3dseSB3YWtlIHVwLlwiLFxyXG4gICAgICAgIFwieW91J3JlIG5vdCBzdXJlIGlmIHlvdSB3ZXJlIGV2ZXIgY29uc2Npb3VzIGFib3V0IHdha2luZyB1cCwgYnV0IHJpZ2h0IG5vdywgeW91J3JlIGNsZWFybHkgYXdhcmUgdGhhdCB5b3Ugd2VyZSBwcmV2aW91c2x5IGFzbGVlcC5cIixcclxuICAgICAgICBcIkluIGZhY3QsIGEgbG90IG9mIHlvdXIgdGhvdWdodHMgc2VlbSBmb3JlaWduIHRvIHlvdS5cIixcclxuICAgICAgICBcIllvdSdyZSBub3Qgc3VyZSBob3cgdG8gZmVlbCBhYm91dCB0aGlzLlwiLFxyXG4gICAgICAgIFwiR29kIHRoZSBoZWFkYWNoZS4uLlwiLFxyXG4gICAgICAgIFwiT0ssIHRpbWUgdG8gdGhpbmsgYWJvdXQgdGhpcy5cIixcclxuICAgICAgICBcIkh1aCwgc29tZXRoaW5nIGVsc2UgeW91IG5ldmVyIGRpZCBiZWZvcmUuXCIsXHJcbiAgICAgICAgXCJXaGVyZSBhcmUgeW91P1wiLFxyXG4gICAgICAgIFwiWW91IHJlYWNoIHVwIGFuZCB0b3VjaCB5b3VyIGhlYWQuXCIsXHJcbiAgICAgICAgXCJPSywgdGhhdCBzZWVtcyB0byBiZSBpbiBvcmRlci4gWW91ciBhbnRlbm5hZSBhcmUgc3RpbGwgdGhlcmUsIHlvdXIgbW91dGggcGFydHMgc2VlbSBpbiB0YWN0Li4uXCIsXHJcbiAgICAgICAgXCJIbW0uIEFsbCB0aGlzIGlzIHN0cmFuZ2UuXCIsXHJcbiAgICAgICAgXCJObyB1c2Ugc2l0dGluZyBhcm91bmQuIFlvdSBnZXQgdXAgYW5kIHNsb3dseSBleGFtaW5lIHlvdXIgc3Vycm91bmRpbmdzLlwiXHJcbiAgICBdLCAzMDAwKTtcclxuICAgIGNvbnRleHQuZW5hYmxlQ29tbWFuZElucHV0KHRydWUpO1xyXG4gICAgY29udGV4dC5zdGF0ZS5zZXQoXCJzdGFydC5hd29rZW5cIiwgdHJ1ZSk7XHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgUm9vbUJ1aWxkZXIgZnJvbSAnLi4vLi4vLi4vZW5naW5lL2J1aWxkZXJzL3Jvb20nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IFJvb21CdWlsZGVyKClcclxuLndpdGhJRChcInR1bm5lbDFcIilcclxuLndpdGhUaXRsZShcIkEgbG9uZyBkYXJrIHR1bm5lbFwiKVxyXG4ud2l0aEZpcnN0RGVzY3JpcHRpb24oXHJcbmBZb3Ugc2xvd2x5IG1ha2UgeW91ciB3YXkgb3V0IG9mIHRoZSBsaXR0bGUgYWxjb3ZlLCBoZWFkaW5nIG5vcnRoIGludG8gYSBzbW9vdGgsIHR1YmUtc2hhcGVkIHR1bm5lbC5cclxuWW91IG5vdGljZSByYXpvciB0aGluIHRocmVhZHMgY29taW5nIG91dCBvZiB0aGUgY2VpbGluZywgd2VhdmluZyBhbmQgc2xpdGhlcmluZyBhbG9uZyB0aGUgbGVuZ3RoIG9mIHRoZSB0dW5uZWwgdG93YXJkcyB0aGUgbm9ydGguIFRoZXJ5IHByb3ZpZGUgYSBkaW0gZ2xvdywgd2hpY2ggbXVzdCBoYXZlIGJlZW4gdGhlIGxpZ2h0IHlvdSBzYXcgYmVmb3JlLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG5gQSB0dWJlLXNoYXBlZCB0dW5uZWwuIFRoaW4gdGhyZWFkcyBzZWVtIHRvIGV4aXQgdGhlIGNlaWxpbmcgaGVyZSwgZW1pbmF0aW5nIGEgc29mdCBnbG93LmBcclxuKVxyXG4ud2l0aEV4aXQoXCJzb3V0aFwiLCBcInN0YXJ0XCIpXHJcbi53aXRoRXhpdChcIm5vcnRoXCIsIFwiY2VudHJhbDFcIilcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBSb29tQnVpbGRlciBmcm9tIFwiLi4vLi4vLi4vZW5naW5lL2J1aWxkZXJzL3Jvb21cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJjZW50cmFsMVwiKVxyXG4ud2l0aFRpdGxlKFwiQSBsYXJnZSBzcGhlcmljYWwgY2hhbWJlclwiKVxyXG4ud2l0aEZpcnN0RGVzY3JpcHRpb24oXHJcbmBZb3UgZXhpdCB0aGUgdHVubmVsIGludG8gYSBsYXJnZSwgc3BoZXJpY2FsIGNoYW1iZXIuXHJcblRoZXJlIGFyZSBtYW55IG1vcmUgdGhyZWFkcyBhY3Jvc3MgdGhlIHdhbGxzIGFuZCBjZWlsaW5nIGhlcmUsIHRoZSBnbG93IGVudmVsb3BpbmcgeW91IGZ1bGx5IGluIGl0cyB1bm5hdHVyYWwgIGxpZ2h0LlxyXG5UaGUgY2hhbWJlciBhcHBlYXJzIHRvIGJlIGxhcmdlLCBhYmxlIHRvIGZpdCBodW5kcmVkcyBvZiB5b3UgaW5zaWRlLlxyXG5UbyB0aGUgbm9ydGhlYXN0LCBub3J0aHdlc3QsIHNvdXRoZWFzdCBhbmQgc291dGh3ZXN0IHlvdSBub3RpY2UgbGFyZ2Ugc3RhdHVlcyByZXByZXNlbnRpbmcgYW50cy4gVGhyZWFkcyBzZWVtIHRvIGxlYWQgcmlnaHQgaW50byB0aGVtLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG5gQSBsYXJnZSwgc3BoZXJpY2FsIGNoYW1iZXIuIEdsb3dpbmcgdGhyZWFkcyBjcmlzcy1jcm9zcyB0aGUgd2FsbHMgYW5kIGNlaWxpbmcuIEFyb3VuZCB5b3UsIHN0YXR1ZXMgb2YgYW50cy5gXHJcbilcclxuLndpdGhFeGl0KFwibm9ydGh3ZXN0XCIsIFwic3RhdHVlMVwiKVxyXG4ud2l0aEV4aXQoXCJub3J0aGVhc3RcIiwgXCJzdGF0dWUyXCIpXHJcbi53aXRoRXhpdChcInNvdXRod2VzdFwiLCBcInN0YXR1ZTNcIilcclxuLndpdGhFeGl0KFwic291dGhlYXN0XCIsIFwic3RhdHVlNFwiKVxyXG4ud2l0aEV4aXQoXCJzb3V0aFwiLCBcInR1bm5lbDFcIilcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBSb29tQnVpbGRlciBmcm9tIFwiLi4vLi4vLi4vZW5naW5lL2J1aWxkZXJzL3Jvb21cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGF0dWUxXCIpXHJcbi53aXRoVGl0bGUoXCJUaGUgbm9ydGh3ZXN0ZXJuIHBhcnQgb2YgdGhlIGNlbnRyYWwgY2hhbWJlclwiKVxyXG4ud2l0aEZpcnN0RGVzY3JpcHRpb24oXHJcbiAgICBgWW91IHdhbGsgb3ZlciB0byB0aGUgbm9ydGh3ZXN0ZXJuIHBhcnQgb2YgdGhlIGNlbnRyYWwgY2hhbWJlci5cclxuICAgIEl0IGlzIGFsbW9zdCBlbnRpcmVseSB0YWtlbiB1cCBieSBhIGh1Z2UgYW50IHN0YXR1ZS4gT25lIG9mIGl0cyBzaXggbGVncyBhcmUgZXh0ZW5kZWQgb3V0d2FyZHMsIGF0dGFjaGVkIHRvIHdoaWNoIGlzIGEgc21hbGwsIHJvdW5kIGRldmljZS5gXHJcbilcclxuLndpdGhEZXNjcmlwdGlvbihcclxuICAgIGBgXHJcbilcclxuLndpdGhFeGl0KFwic291dGhlYXN0XCIsIFwiY2VudHJhbDFcIilcclxuLndpdGhJdGVtKFwic3RhdHVlMVwiKVxyXG4uY3JlYXRlKCk7IiwiaW1wb3J0IFJvb21CdWlsZGVyIGZyb20gXCIuLi8uLi8uLi9lbmdpbmUvYnVpbGRlcnMvcm9vbVwiO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IFJvb21CdWlsZGVyKClcclxuLndpdGhJRChcInN0YXR1ZTJcIilcclxuLndpdGhUaXRsZShcIlRoZSBub3J0aGVhc3Rlcm4gcGFydCBvZiB0aGUgY2VudHJhbCBjaGFtYmVyXCIpXHJcbi53aXRoRmlyc3REZXNjcmlwdGlvbihcclxuICAgIGBZb3Ugd2FsayBvdmVyIHRvIHRoZSBub3J0aGVhc3Rlcm4gcGFydCBvZiB0aGUgY2VudHJhbCBjaGFtYmVyLlxyXG4gICAgSXQgaXMgYWxtb3N0IGVudGlyZWx5IHRha2VuIHVwIGJ5IGEgaHVnZSBhbnQgc3RhdHVlLiBUd28gb2YgaXRzIHNpeCBsZWdzIGFyZSBleHRlbmRlZCBvdXR3YXJkcywgYXR0YWNoZWQgdG8gd2hpY2ggaXMgYSBsYXJnZSwgcmVjdGFuZ3VsYXIgZGV2aWNlLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG4gICAgYGBcclxuKVxyXG4ud2l0aEV4aXQoXCJzb3V0aHdlc3RcIiwgXCJjZW50cmFsMVwiKVxyXG4ud2l0aEl0ZW0oXCJzdGF0dWUyXCIpXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgUm9vbUJ1aWxkZXIgZnJvbSBcIi4uLy4uLy4uL2VuZ2luZS9idWlsZGVycy9yb29tXCI7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBuZXcgUm9vbUJ1aWxkZXIoKVxyXG4ud2l0aElEKFwic3RhdHVlM1wiKVxyXG4ud2l0aFRpdGxlKFwiVGhlIHNvdXRod2VzdGVybiBwYXJ0IG9mIHRoZSBjZW50cmFsIGNoYW1iZXJcIilcclxuLndpdGhGaXJzdERlc2NyaXB0aW9uKFxyXG4gICAgYFlvdSB3YWxrIG92ZXIgdG8gdGhlIHNvdXRod2VzdGVybiBwYXJ0IG9mIHRoZSBjZW50cmFsIGNoYW1iZXIuXHJcbiAgICBJdCBpcyBhbG1vc3QgZW50aXJlbHkgdGFrZW4gdXAgYnkgYSBodWdlIGFudCBzdGF0dWUuIFRocmVlIG9mIGl0cyBzaXggbGVncyBhcmUgZXh0ZW5kZWQgb3V0d2FyZHMsIGF0dGFjaGVkIHRvIHdoaWNoIGlzIGEgcm91bmQgc3RvbmUgdGFibGV0LmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG4gICAgYGBcclxuKVxyXG4ud2l0aEV4aXQoXCJub3J0aGVhc3RcIiwgXCJjZW50cmFsMVwiKVxyXG4ud2l0aEl0ZW0oXCJzdGF0dWUzXCIpXHJcbi5jcmVhdGUoKTsiLCJleHBvcnQgZGVmYXVsdCBjbGFzcyBJdGVtIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuaWQgPSBcIml0ZW1cIjtcclxuICAgICAgICB0aGlzLm5hbWUgPSBcIkFuIGl0ZW1cIjtcclxuICAgICAgICB0aGlzLmRlc2NyaXB0aW9uID0gXCJZb3Ugc2VlIG5vdGhpbmcgc3BlY2lhbCBhYm91dCB0aGlzIGl0ZW1cIjtcclxuICAgICAgICB0aGlzLnVzYWJsZSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy50YWtlYWJsZSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy51c2VDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy50YWtlQ2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuZHJvcENhbGxiYWNrID0gbnVsbDtcclxuICAgICAgICB0aGlzLnRpY2tDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvblVzZSgpIHtcclxuICAgICAgICBpZiAodGhpcy51c2VDYWxsYmFjaykgcmV0dXJuIHRoaXMudXNlQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvblRha2UoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMudGFrZUNhbGxiYWNrKSByZXR1cm4gdGhpcy50YWtlQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkRyb3AoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZHJvcENhbGxiYWNrKSByZXR1cm4gdGhpcy5kcm9wQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuICAgIGFzeW5jIG9uVGljaygpIHtcclxuICAgICAgICBpZiAodGhpcy50aWNrQ2FsbGJhY2spIHJldHVybiB0aGlzLnRpY2tDYWxsYmFjayh0aGlzLmNvbnRleHQpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZFVzZUNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy51c2VDYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkVGFrZUNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy50YWtlQ2FsbGJhY2sgPSBjYWxsYmFjay5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZERyb3BDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuZHJvcENhbGxiYWNrID0gY2FsbGJhY2suYmluZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGRUaWNrQ2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLnRpY2tDYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcbn0iLCJpbXBvcnQgSXRlbSBmcm9tICcuLi9pdGVtJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEl0ZW1CdWlsZGVyIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuaXRlbSA9IG5ldyBJdGVtKCk7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aElEKElEKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtLmlkID0gSUQ7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aE5hbWUobmFtZSkge1xyXG4gICAgICAgIHRoaXMuaXRlbS5uYW1lID0gbmFtZTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRGVzY3JpcHRpb24oZGVzY3JpcHRpb24pIHtcclxuICAgICAgICB0aGlzLml0ZW0uZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICBpc1VzYWJsZSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMuaXRlbS51c2FibGUgPSB2YWx1ZTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICBpc1Rha2VhYmxlKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtLnRha2VhYmxlID0gdmFsdWU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aFVzZUNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtLmFkZFVzZUNhbGxiYWNrKGNhbGxiYWNrKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoVGFrZUNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtLmFkZFRha2VDYWxsYmFjayhjYWxsYmFjayk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aERyb3BDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuaXRlbS5hZGREcm9wQ2FsbGJhY2soY2FsbGJhY2spO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICB3aXRoVGlja0NhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtLmFkZFRpY2tDYWxsYmFjayhjYWxsYmFjayk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgY3JlYXRlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLml0ZW07XHJcbiAgICB9XHJcbn0iLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSAnLi4vLi4vZW5naW5lL2J1aWxkZXJzL2l0ZW0nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IEl0ZW1CdWlsZGVyKClcclxuLndpdGhJRChcInN0YXR1ZTRcIilcclxuLndpdGhOYW1lKFwiYSBodWdlIGFudCBzdGF0dWVcIilcclxuLndpdGhEZXNjcmlwdGlvbihcclxuICAgIGBCZWZvcmUgeW91IGlzIGEgYmlnIHN0YXR1ZSBvZiBhbiBhbnQsIGluIHRoZSBwcm9jZXNzIG9mIGZhbGxpbmcgb3Zlci4gQWxsIG9mIGl0cyBsZWdzIGFyZSBiZW50IGF0IHRoZSBqb2ludHMuYFxyXG4pXHJcbi5pc1Rha2VhYmxlKGZhbHNlKVxyXG4uaXNVc2FibGUodHJ1ZSlcclxuLndpdGhVc2VDYWxsYmFjayhhc3luYyBmdW5jdGlvbiAoY29udGV4dCkge1xyXG4gICAgY29udGV4dC5wcmludChgWW91IGNhbid0IHNlZW0gdG8gZmlndXJlIG91dCB3aGF0IHRvIGRvIHdpdGggdGhpcyB5ZXQuYClcclxufSlcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBMYWlyIGZyb20gJy4vbGFpcic7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBbXHJcbiAgICAuLi5MYWlyXHJcbl07IiwiaW1wb3J0IFN0YXJ0IGZyb20gJy4vc3RhcnQnO1xyXG5pbXBvcnQgVHVubmVsMSBmcm9tICcuL3R1bm5lbDEnO1xyXG5pbXBvcnQgY2VudHJhbDEgZnJvbSAnLi9jZW50cmFsMSc7XHJcbmltcG9ydCBzdGF0dWUxIGZyb20gJy4vc3RhdHVlMSc7XHJcbmltcG9ydCBzdGF0dWUyIGZyb20gJy4vc3RhdHVlMic7XHJcbmltcG9ydCBzdGF0dWUzIGZyb20gJy4vc3RhdHVlMyc7XHJcbmltcG9ydCBzdGF0dWU0IGZyb20gJy4uLy4uL2l0ZW1zL3N0YXR1ZTQnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgW1xyXG4gICAgU3RhcnQsXHJcbiAgICBUdW5uZWwxLFxyXG4gICAgY2VudHJhbDEsXHJcbiAgICBzdGF0dWUxLFxyXG4gICAgc3RhdHVlMixcclxuICAgIHN0YXR1ZTMsXHJcbiAgICBzdGF0dWU0XHJcbl07IiwiaW1wb3J0IFN0b25lIGZyb20gJy4vc3RvbmUnO1xyXG5pbXBvcnQgVG9yY2ggZnJvbSAnLi90b3JjaCc7XHJcbmltcG9ydCBDdXAgZnJvbSAnLi9jdXAnO1xyXG5pbXBvcnQgU3RhdHVlMSBmcm9tICcuL3N0YXR1ZTEnO1xyXG5pbXBvcnQgc3RhdHVlMiBmcm9tICcuL3N0YXR1ZTInO1xyXG5pbXBvcnQgc3RhdHVlMyBmcm9tICcuL3N0YXR1ZTMnO1xyXG5pbXBvcnQgc3RhdHVlNCBmcm9tICcuL3N0YXR1ZTQnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgW1xyXG4gICAgU3RvbmUsXHJcbiAgICBUb3JjaCxcclxuICAgIEN1cCxcclxuICAgIFN0YXR1ZTEsXHJcbiAgICBzdGF0dWUyLFxyXG4gICAgc3RhdHVlMyxcclxuICAgIHN0YXR1ZTRcclxuXSIsImltcG9ydCBJdGVtQnVpbGRlciBmcm9tIFwiLi4vLi4vZW5naW5lL2J1aWxkZXJzL2l0ZW1cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBJdGVtQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdG9uZVwiKVxyXG4ud2l0aE5hbWUoXCJhIGR1bGwgc3RvbmVcIilcclxuLndpdGhEZXNjcmlwdGlvbihcIlRoZXJlIGlzIG5vdGhpbmcgcmVtYXJrYWJsZSBhYm91dCB0aGlzIHJvdWdoLCBibGFuZCBzdG9uZS5cIilcclxuLmlzVGFrZWFibGUodHJ1ZSlcclxuLmlzVXNhYmxlKHRydWUpXHJcbi53aXRoVGFrZUNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uKGNvbnRleHQpIHtcclxuICAgIGNvbnRleHQucHJpbnQoYFRoZSAke3RoaXMuaWR9IGZlZWxzIGhlYXZ5IGluIHlvdXIgaGFuZHMuYCk7XHJcbn0pXHJcbi53aXRoRHJvcENhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uKGNvbnRleHQpIHtcclxuICAgIGNvbnRleHQucHJpbnQoYEl0IGJvdW5jZXMgYmFjayBhbmQgZm9ydGggYSBsaXR0bGUuYClcclxufSlcclxuLndpdGhVc2VDYWxsYmFjayhhc3luYyBmdW5jdGlvbihjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgY2FuJ3QgcmVhbGx5IGZpZ3VyZSBvdXQgd2hhdCB0byBkbyB3aXRoICR7dGhpcy5uYW1lfSB5ZXRgKTtcclxufSlcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBJdGVtQnVpbGRlciBmcm9tIFwiLi4vLi4vZW5naW5lL2J1aWxkZXJzL2l0ZW1cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBJdGVtQnVpbGRlcigpXHJcbi53aXRoSUQoXCJ0b3JjaFwiKVxyXG4ud2l0aE5hbWUoXCJhIHRvcmNoXCIpXHJcbi53aXRoRGVzY3JpcHRpb24oXCJBIHN0YW5kYXJkIHRvcmNoIHRoYXQgcHJvdmlkZXMgbGlnaHQuXCIpXHJcbi5pc1VzYWJsZSh0cnVlKVxyXG4uaXNUYWtlYWJsZSh0cnVlKVxyXG4ud2l0aFVzZUNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uKGNvbnRleHQpIHtcclxuICAgIGNvbnRleHQucHJpbnQoYFlvdSB0cnkgdG8gbGlnaHQgdGhlIHRvcmNoIGJ1dCBmYWlsLmApXHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSBcIi4uLy4uL2VuZ2luZS9idWlsZGVycy9pdGVtXCI7XHJcbmltcG9ydCBJdGVtIGZyb20gXCIuLi8uLi9lbmdpbmUvaXRlbVwiO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IEl0ZW1CdWlsZGVyKClcclxuLndpdGhJRChcImN1cFwiKVxyXG4ud2l0aE5hbWUoXCJhIGN1cFwiKVxyXG4ud2l0aERlc2NyaXB0aW9uKFwiQSBzdGFuZGFyZCBjb2ZmZWUgY3VwXCIpXHJcbi5pc1Rha2VhYmxlKHRydWUpXHJcbi5pc1VzYWJsZShmYWxzZSlcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBJdGVtQnVpbGRlciBmcm9tICcuLi8uLi9lbmdpbmUvYnVpbGRlcnMvaXRlbSc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBuZXcgSXRlbUJ1aWxkZXIoKVxyXG4ud2l0aElEKFwic3RhdHVlMVwiKVxyXG4ud2l0aE5hbWUoXCJhIGh1Z2UgYW50IHN0YXR1ZVwiKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG4gICAgYEJlZm9yZSB5b3Ugc3RhbmRzIGEgYmlnIGFudCBzdGF0dWUuIE9uZSBvZiBpdHMgc2l4IGxlZ3MgaXMgZXh0ZW5kZWQgb3V0d2FyZHMsIGF0dGFjaGVkIHRvIGEgcm91bmQgZGV2aWNlLmBcclxuKVxyXG4uaXNUYWtlYWJsZShmYWxzZSlcclxuLmlzVXNhYmxlKHRydWUpXHJcbi53aXRoVXNlQ2FsbGJhY2soYXN5bmMgZnVuY3Rpb24gKGNvbnRleHQpIHtcclxuICAgIGNvbnRleHQucHJpbnQoYFlvdSBwcmVzcyB0aGUgYnV0dG9uIG9uIHRoZSByb3VuZCBkZXZpY2UgYXR0YWNoZWQgdG8gdGhlIHN0YXR1ZSdzIGFybS5gKVxyXG59KVxyXG4uY3JlYXRlKCk7IiwiaW1wb3J0IEl0ZW1CdWlsZGVyIGZyb20gJy4uLy4uL2VuZ2luZS9idWlsZGVycy9pdGVtJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBJdGVtQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGF0dWUyXCIpXHJcbi53aXRoTmFtZShcImEgaHVnZSBhbnQgc3RhdHVlXCIpXHJcbi53aXRoRGVzY3JpcHRpb24oXHJcbiAgICBgQmVmb3JlIHlvdSBzdGFuZHMgYSBiaWcgYW50IHN0YXR1ZS4gVHdvIG9mIGl0cyBzaXggbGVncyBpcyBleHRlbmRlZCBvdXR3YXJkcywgYXR0YWNoZWQgdG8gYSByZWN0YW5ndWxhciBkZXZpY2UuYFxyXG4pXHJcbi5pc1Rha2VhYmxlKGZhbHNlKVxyXG4uaXNVc2FibGUodHJ1ZSlcclxuLndpdGhVc2VDYWxsYmFjayhhc3luYyBmdW5jdGlvbiAoY29udGV4dCkge1xyXG4gICAgY29udGV4dC5wcmludChgWW91IHByZXNzIHRoZSBidXR0b24gb24gdGhlIHJlY3Rhbmd1bGFyIGRldmljZSBhdHRhY2hlZCB0byB0aGUgc3RhdHVlJ3MgYXJtLmApXHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSAnLi4vLi4vZW5naW5lL2J1aWxkZXJzL2l0ZW0nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IEl0ZW1CdWlsZGVyKClcclxuLndpdGhJRChcInN0YXR1ZTNcIilcclxuLndpdGhOYW1lKFwiYSBodWdlIGFudCBzdGF0dWVcIilcclxuLndpdGhEZXNjcmlwdGlvbihcclxuICAgIGBCZWZvcmUgeW91IHN0YW5kcyBhIGJpZyBhbnQgc3RhdHVlLiBUaHJlZSBvZiBpdHMgc2l4IGxlZ3MgYXJlIGV4dGVuZGVkIG91dHdhcmRzLCBhdHRhY2hlZCB0byBhIHJvdW5kIHN0b25lIHRhYmxldC5gXHJcbilcclxuLmlzVGFrZWFibGUoZmFsc2UpXHJcbi5pc1VzYWJsZSh0cnVlKVxyXG4ud2l0aFVzZUNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uIChjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgZXhhbWluZSB0aGUgc3RvbmUgdGFibGV0IGluIHRoZSBzdGF0dWUncyBoYW5kcy4gVGhlcmUgYXBwZWFyIHRvIGJlIHN5bWJvbHMgb24gaXQgd2hpY2ggeW91IGNhbiBtYWtlIG91dC5gKTtcclxufSlcclxuLmNyZWF0ZSgpOyIsImV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIE1lb3dDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGNvbnRleHQucHJpbnQoYFlvdSBtZW93LmApO1xyXG59IiwiaW1wb3J0IEdhbWUgZnJvbSAnLi4vZW5naW5lJztcclxuaW1wb3J0IFJvb21zIGZyb20gJy4vcm9vbXMnO1xyXG5pbXBvcnQgSXRlbXMgZnJvbSAnLi9pdGVtcyc7XHJcbmltcG9ydCBNZW93Q29tbWFuZCBmcm9tICcuL2NvbW1hbmRzL21lb3cnO1xyXG5cclxuaWYgKGxvY2FsU3RvcmFnZS5nZXRJdGVtKFwic2F2ZVwiKSkge1xyXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJzYXZlLWdhbWUtZm91bmRcIikuaGlkZGVuID0gZmFsc2U7XHJcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImJlZm9yZS1wbGF5XCIpLmhpZGRlbiA9IHRydWU7XHJcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImxvYWQtc2F2ZS1nYW1lXCIpLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCAoKSA9PiB7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJzYXZlLWdhbWUtZm91bmRcIikuaGlkZGVuID0gdHJ1ZTtcclxuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInBsYXktYXJlYVwiKS5oaWRkZW4gPSBmYWxzZTtcclxuICAgICAgICBzdGFydEdhbWUoZmFsc2UpO1xyXG4gICAgfSlcclxuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwic3RhcnQtbmV3LWdhbWVcIikuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcclxuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInNhdmUtZ2FtZS1mb3VuZFwiKS5oaWRkZW4gPSB0cnVlO1xyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwicGxheS1hcmVhXCIpLmhpZGRlbiA9IGZhbHNlO1xyXG4gICAgICAgIHN0YXJ0R2FtZSh0cnVlKTtcclxuICAgIH0pXHJcbn1cclxuXHJcbmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiYmVnaW5cIikuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcclxuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiYmVmb3JlLXBsYXlcIikuaGlkZGVuID0gdHJ1ZTtcclxuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwicGxheS1hcmVhXCIpLmhpZGRlbiA9IGZhbHNlO1xyXG4gICAgc3RhcnRHYW1lKHRydWUpO1xyXG59KVxyXG5cclxuZnVuY3Rpb24gc3RhcnRHYW1lKG5ld0dhbWUpIHtcclxuICAgIGNvbnN0IGdhbWUgPSBuZXcgR2FtZShuZXdHYW1lKTtcclxuXHJcbiAgICBnYW1lLmluaXQoe1xyXG4gICAgICAgIHJvb21zOiBSb29tcyxcclxuICAgICAgICBjb21tYW5kczogW1xyXG4gICAgICAgICAgICBbW1wibWVvd1wiLCBcIm1ld1wiXSwgTWVvd0NvbW1hbmRdXHJcbiAgICAgICAgXSxcclxuICAgICAgICBpdGVtczogSXRlbXNcclxuICAgIH0pO1xyXG59XHJcbiJdLCJuYW1lcyI6WyJoYXMiLCJPYmplY3QiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsInByZWZpeCIsIkV2ZW50cyIsIkVFIiwiZm4iLCJjb250ZXh0Iiwib25jZSIsInRoaXMiLCJhZGRMaXN0ZW5lciIsImVtaXR0ZXIiLCJldmVudCIsIlR5cGVFcnJvciIsImxpc3RlbmVyIiwiZXZ0IiwiX2V2ZW50cyIsInB1c2giLCJfZXZlbnRzQ291bnQiLCJjbGVhckV2ZW50IiwiRXZlbnRFbWl0dGVyIiwiY3JlYXRlIiwiX19wcm90b19fIiwiZXZlbnROYW1lcyIsImV2ZW50cyIsIm5hbWUiLCJuYW1lcyIsImNhbGwiLCJzbGljZSIsImdldE93blByb3BlcnR5U3ltYm9scyIsImNvbmNhdCIsImxpc3RlbmVycyIsImhhbmRsZXJzIiwiaSIsImwiLCJsZW5ndGgiLCJlZSIsIkFycmF5IiwibGlzdGVuZXJDb3VudCIsImVtaXQiLCJhMSIsImEyIiwiYTMiLCJhNCIsImE1IiwiYXJncyIsImxlbiIsImFyZ3VtZW50cyIsInJlbW92ZUxpc3RlbmVyIiwidW5kZWZpbmVkIiwiYXBwbHkiLCJqIiwib24iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJvZmYiLCJwcmVmaXhlZCIsIm1vZHVsZSIsImV4cG9ydHMiLCJfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18iLCJfX3dlYnBhY2tfcmVxdWlyZV9fIiwibW9kdWxlSWQiLCJjYWNoZWRNb2R1bGUiLCJfX3dlYnBhY2tfbW9kdWxlc19fIiwibiIsImdldHRlciIsIl9fZXNNb2R1bGUiLCJkIiwiYSIsImRlZmluaXRpb24iLCJrZXkiLCJvIiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwiZ2V0Iiwib2JqIiwicHJvcCIsImNvbnN0cnVjdG9yIiwic3RhdGVzIiwiTWFwIiwic2V0IiwidmFsdWUiLCJzZXJpYWxpemUiLCJlbnRyaWVzIiwiZW50cnltYXAiLCJzdGF0ZSIsImRlc2VyaWFsaXplIiwiZGF0YSIsIlBsYXllciIsImludmVudG9yeSIsImN1cnJlbnRSb29tIiwiYWRkSXRlbSIsImlkIiwicmVtb3ZlSXRlbSIsImZpbHRlciIsIml0ZW0iLCJnZXRJbnZlbnRvcnkiLCJtYXAiLCJnZXRJdGVtIiwiQmFzZU91dHB1dCIsInNwZWFrIiwidGV4dCIsInN0b3AiLCJzZXRPcHRpb25zIiwib3B0aW9ucyIsIkFyaWFPdXRwdXQiLCJzdXBlciIsInRpbWVvdXQiLCJpbml0IiwiY29udGFpbmVyIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50Iiwic2V0QXR0cmlidXRlIiwic3BlZWNoRGlzcGxheSIsImFwcGVuZCIsImJvZHkiLCJhcHBlbmRDaGlsZCIsImluc2VydEJlZm9yZSIsImZpcnN0Q2hpbGQiLCJjbGVhckRpc3BsYXkiLCJub2RlIiwiY3JlYXRlVGV4dE5vZGUiLCJwYXJhIiwic2V0VGltZW91dCIsImJpbmQiLCJpbm5lckhUTUwiLCJXZWJUVFNPdXRwdXQiLCJUVFMiLCJvdXRwdXQiLCJjcmVhdGVPdXRwdXQiLCJfX2F3YWl0ZXIiLCJ0aGlzQXJnIiwiX2FyZ3VtZW50cyIsIlAiLCJnZW5lcmF0b3IiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsImZ1bGZpbGxlZCIsInN0ZXAiLCJuZXh0IiwiZSIsInJlamVjdGVkIiwicmVzdWx0IiwiZG9uZSIsInRoZW4iLCJSZXNvbmF0b3JBdWRpb0NvbnRleHQiLCJBdWRpb0NvbnRleHQiLCJnZXRDb250ZXh0IiwiY3JlYXRlR2FpbiIsImdldE91dHB1dERlc3RpbmF0aW9uIiwiZGVzdGluYXRpb24iLCJjcmVhdGVCdWZmZXJTb3VyY2UiLCJkZWNvZGVBdWRpb0RhdGEiLCJjcmVhdGVQYW5uZXIiLCJjcmVhdGVNZWRpYUVsZW1lbnRTb3VyY2UiLCJlbGVtZW50IiwidmVjNCIsInZhbHVlcyIsIkZsb2F0MzJBcnJheSIsInh5enciLCJ4IiwieSIsInoiLCJ3IiwieHkiLCJ4eXoiLCJyIiwiZyIsImIiLCJyZyIsInJnYiIsInJnYmEiLCJhdCIsImluZGV4IiwicmVzZXQiLCJjb3B5IiwiZGVzdCIsIm5lZ2F0ZSIsImVxdWFscyIsInZlY3RvciIsInRocmVzaG9sZCIsImVwc2lsb24iLCJNYXRoIiwiYWJzIiwic3FydCIsInNxdWFyZWRMZW5ndGgiLCJhZGQiLCJzdWJ0cmFjdCIsIm11bHRpcGx5IiwiZGl2aWRlIiwic2NhbGUiLCJub3JtYWxpemUiLCJtdWx0aXBseU1hdDQiLCJtYXRyaXgiLCJtdWx0aXBseVZlYzQiLCJzdGF0aWMiLCJ2ZWN0b3IyIiwidGltZSIsInplcm8iLCJvbmUiLCJtYXQ0IiwiYWxsIiwicm93IiwiY29sIiwiZGV0ZXJtaW5hbnQiLCJhMDAiLCJhMDEiLCJhMDIiLCJhMDMiLCJhMTAiLCJhMTEiLCJhMTIiLCJhMTMiLCJhMjAiLCJhMjEiLCJhMjIiLCJhMjMiLCJhMzAiLCJhMzEiLCJhMzIiLCJhMzMiLCJzZXRJZGVudGl0eSIsInRyYW5zcG9zZSIsInRlbXAwMSIsInRlbXAwMiIsInRlbXAwMyIsInRlbXAxMiIsInRlbXAxMyIsInRlbXAyMyIsImludmVyc2UiLCJkZXQwMCIsImRldDAxIiwiZGV0MDIiLCJkZXQwMyIsImRldDA0IiwiZGV0MDUiLCJkZXQwNiIsImRldDA3IiwiZGV0MDgiLCJkZXQwOSIsImRldDEwIiwiZGV0MTEiLCJkZXQiLCJiMCIsImIxIiwiYjIiLCJiMyIsIm11bHRpcGx5VmVjMyIsInZlYzMiLCJ0b01hdDMiLCJtYXQzIiwidG9JbnZlcnNlTWF0MyIsImRldDIxIiwidHJhbnNsYXRlIiwicm90YXRlIiwiYW5nbGUiLCJheGlzIiwicyIsInNpbiIsImMiLCJjb3MiLCJ0IiwiYjAwIiwiYjAxIiwiYjAyIiwiYjEwIiwiYjExIiwiYjEyIiwiYjIwIiwiYjIxIiwiYjIyIiwibGVmdCIsInJpZ2h0IiwiYm90dG9tIiwidG9wIiwibmVhciIsImZhciIsInJsIiwidGIiLCJmb3YiLCJhc3BlY3QiLCJ0YW4iLCJQSSIsImZydXN0dW0iLCJwb3NpdGlvbiIsInRhcmdldCIsInVwIiwiaWRlbnRpdHkiLCJkaWZmZXJlbmNlIiwiY3Jvc3MiLCJkb3QiLCJtMSIsIm0yIiwiYjAzIiwiYjEzIiwiYjIzIiwiYjMwIiwiYjMxIiwiYjMyIiwiYjMzIiwidmVjMiIsIm11bHRpcGx5TWF0MiIsIm11bHRpcGx5VmVjMiIsIm11bHRpcGx5TWF0MyIsIngyIiwic3F1YXJlZERpc3RhbmNlIiwieTIiLCJ0b01hdDQiLCJ0b1F1YXQiLCJtMDAiLCJtMDEiLCJtMDIiLCJtMTAiLCJtMTEiLCJtMTIiLCJtMjAiLCJtMjEiLCJtMjIiLCJmb3VyWFNxdWFyZWRNaW51czEiLCJmb3VyWVNxdWFyZWRNaW51czEiLCJmb3VyWlNxdWFyZWRNaW51czEiLCJiaWdnZXN0SW5kZXgiLCJmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEiLCJiaWdnZXN0VmFsIiwibXVsdCIsInF1YXQiLCJyb2xsIiwiYXRhbjIiLCJwaXRjaCIsInlhdyIsImFzaW4iLCJjYWxjdWxhdGVXIiwiaW52RG90IiwiY29uanVnYXRlIiwib3RoZXIiLCJxMXgiLCJxMXkiLCJxMXoiLCJxMXciLCJxMngiLCJxMnkiLCJxMnoiLCJxMnciLCJxeCIsInF5IiwicXoiLCJxdyIsIml4IiwiaXkiLCJpeiIsIml3IiwiejIiLCJ4eCIsInh6IiwieXkiLCJ5eiIsInp6Iiwid3giLCJ3eSIsInd6IiwicTEiLCJxMiIsInEyYSIsImswIiwiazEiLCJvbmVPdmVyU2luIiwiY29zSGFsZlRoZXRhIiwiaGFsZlRoZXRhIiwiYWNvcyIsInNpbkhhbGZUaGV0YSIsInJhdGlvQSIsInJhdGlvQiIsIm11bHRpcGx5QnlNYXQzIiwibXVsdGlwbHlCeVF1YXQiLCJxdWF0ZXJuaW9uIiwiZm9yd2FyZCIsIlJlc29uYXRvclNjZW5lIiwic2NlbmUiLCJjcmVhdGVTb3VyY2UiLCJwYW5uaW5nTW9kZWwiLCJkaXN0YW5jZU1vZGVsIiwibWF4RGlzdGFuY2UiLCJyZWZEaXN0YW5jZSIsImNvbm5lY3QiLCJnZXRPdXRwdXQiLCJnZXRJbnB1dCIsInNldExpc3RlbmVyUG9zaXRpb24iLCJzZXRQb3NpdGlvbiIsInNldExpc3RlbmVyT3JpZW50YXRpb24iLCJyYXd1cCIsImZ3ZCIsInNldE9yaWVudGF0aW9uIiwiRWZmZWN0Q2hhaW4iLCJncmFwaCIsImlucHV0IiwiZWZmZWN0cyIsImlucHV0Tm9kZSIsIm91dHB1dE5vZGUiLCJ1cGRhdGVDb25uZWN0aW9ucyIsImFwcGx5RWZmZWN0IiwiZWZmZWN0IiwicmVtb3ZlRWZmZWN0IiwiZm9yRWFjaCIsImN1cnJFZmZlY3QiLCJkaXNjb25uZWN0IiwiY3VycmVudCIsInByZXZpb3VzIiwiY29ubmVjdElucHV0IiwiY29ubmVjdE91dHB1dCIsIkF1ZGlvR3JhcGgiLCJzd2FwQ2hhbm5lbHMiLCJlZmZlY3RzQnVzIiwid29ybGRCdXMiLCJzZWNvbmRhcnlCdXMiLCJtYXN0ZXIiLCJjaGFubmVsU3BsaXR0ZXIiLCJjcmVhdGVDaGFubmVsU3BsaXR0ZXIiLCJjaGFubmVsTWVyZ2VyIiwiY3JlYXRlQ2hhbm5lbE1lcmdlciIsImNvbm5lY3RUb01hc3RlciIsImNvbm5lY3RUb1VJIiwiU291cmNlVHlwZSIsIkF1ZGlvU291cmNlIiwiYnVmZmVyIiwidHlwZSIsIldvcmxkU291cmNlIiwicGxheWJhY2tSYXRlIiwidm9sdW1lIiwiZ2FpbiIsImdldEJ1ZmZlciIsInNldEJ1ZmZlciIsInBsYXlPbkxvYWQiLCJwbGF5Iiwid2hlbiIsIm9mZnNldCIsImR1cmF0aW9uIiwicGxheWluZyIsImNyZWF0ZUNvbm5lY3Rpb25zIiwic3RhcnQiLCJsb29wIiwibG9vcGluZyIsInNjZW5lTm9kZSIsImFkZEV2ZW50TGlzdGVuZXIiLCJzZXRQbGF5YmFja1JhdGUiLCJyYXRlIiwiZ2V0UGxheWJhY2tSYXRlIiwic2V0Vm9sdW1lIiwiZ2V0Vm9sdW1lIiwiVUlTb3VyY2UiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwiZGVzdHJveSIsImZhZGVPdXQiLCJzZXRWYWx1ZUF0VGltZSIsImN1cnJlbnRUaW1lIiwiZXhwb25lbnRpYWxSYW1wVG9WYWx1ZUF0VGltZSIsImZhZGVJbiIsIkRhdGFQb29sSXRlbSIsImRlY29kZWREYXRhIiwiZ2V0RGF0YSIsInNldERhdGEiLCJnZXREZWNvZGVkRGF0YSIsInNldERlY29kZWREYXRhIiwiZ2V0TmFtZSIsInNldE5hbWUiLCJIVFRQTG9hZGVyIiwicGF0aCIsImZldGNoIiwiYXJyYXlCdWZmZXIiLCJEYXRhUG9vbCIsImxvYWRlciIsIm1heERhdGEiLCJkZWNvZGVkIiwia2V5cyIsImNsZWFyIiwiQ29udm9sdmVyIiwicGFyYW1zIiwiZWZmZWN0UGFyYW1zIiwiZWZmZWN0Tm9kZSIsImNvbnNvbGUiLCJsb2ciLCJjcmVhdGVDb252b2x2ZXIiLCJTdHJlYW1pbmdTb3VyY2UiLCJNYXN0ZXJTb3VyY2UiLCJjYW5QbGF5IiwicGxheU9uQXZhaWxhYmxlIiwicGF1c2UiLCJSZXNvbmF0b3IiLCJlbnZpcm9ubWVudEltcHVsc2UiLCJkYXRhUG9vbCIsImxvYWQiLCJsb2FkSW1tZWRpYXRlIiwic291cmNlIiwic3RyZWFtIiwiQXVkaW8iLCJjcm9zc09yaWdpbiIsInNldEVudmlyb25tZW50SW1wdWxzZSIsImZpbGUiLCJjbGVhckRhdGFQb29sIiwiU291bmQiLCJyZXMiLCJhbWJpZW5jZSIsIm11c2ljIiwiYW1iaWVuY2VWb2x1bWUiLCJtdXNpY1ZvbHVtZSIsInNmeFZvbHVtZSIsInByZXZpb3VzQW1iaWVuY2UiLCJwcmV2aW91c011c2ljIiwic291bmQiLCJhc3luYyIsInNldE11c2ljIiwic2V0SW1wdWxzZSIsInNldE11c2ljVm9sdW1lIiwic2V0QW1iaWVuY2VWb2x1bWUiLCJzZXRTRlhWb2x1bWUiLCJPdXRwdXQiLCJ0dHMiLCJoaXN0b3J5IiwiZ2V0RWxlbWVudEJ5SWQiLCJzYXkiLCJzdHJpbmciLCJzcGxpdCIsImxpbmUiLCJzZXRBbWJpZW5jZSIsIklucHV0IiwiY29tbWFuZEhhbmRsZXIiLCJvdXRwdXRIYW5kbGVyIiwiaGFuZGxlciIsImVjaG9JbnB1dCIsImlucHV0RmllbGQiLCJzZXRFY2hvIiwid2hpY2giLCJ2YWwiLCJkb0NvbW1hbmQiLCJkZWZhdWx0Q29tbWFuZHMiLCJleGFtaW5lUm9vbSIsIml0ZW1zIiwiZ2V0Um9vbSIsInBsYXllciIsImdldEl0ZW1zIiwiaW5jbHVkZXMiLCJkZXNjcmlwdGlvbiIsIm9uVXNlIiwicm9vbSIsInRha2VhYmxlIiwicHJpbnQiLCJvblRha2UiLCJvbkRyb3AiLCJzZXRJbnB1dEVjaG8iLCJzYXZlIiwicGFyc2VJbnQiLCJpdGVtRGVzY3JpcHRpb24iLCJkaXJlY3Rpb25NYXAiLCJDb21tYW5kcyIsImNvbW1hbmRzIiwiZW5hYmxlZCIsImFkZERlZmF1bHRDb21tYW5kcyIsInN0ciIsImRpcmVjdGlvbiIsIm1hdGNoRGlyZWN0aW9uIiwiZ2V0RXhpdCIsIm1vdmUiLCJhZGRDb21tYW5kIiwiZnVuYyIsImlzQXJyYXkiLCJjb21tYW5kIiwiYWRkQ29tbWFuZHMiLCJkaXIiLCJTZXJpYWxpemF0aW9uIiwic2F2ZW9iaiIsIml0ZW1Mb2NhdGlvbnMiLCJzZXJpYWxpemVJdGVtTG9jYXRpb25zIiwidm9sdW1lcyIsInNmeCIsImxvY2FsU3RvcmFnZSIsInNldEl0ZW0iLCJKU09OIiwic3RyaW5naWZ5IiwibG9hZG9iaiIsInBhcnNlIiwiZGVzZXJpYWxpemVJdGVtTG9jYXRpb25zIiwiZGVzZXJpYWxpemVQbGF5ZXIiLCJyb29tcyIsIm9iamVjdHMiLCJHYW1lIiwibmV3R2FtZSIsInZpc2l0ZWRSb29tcyIsImludGVydmFsIiwibGluZXMiLCJ3YWl0IiwiYWR2YW5jZVRpY2siLCJvblRpY2siLCJzZXRJbnRlcnZhbCIsImNsZWFySW50ZXJ2YWwiLCJ0aXRsZSIsImZpcnN0RGVzY3JpcHRpb24iLCJleGFtaW5lSXRlbXMiLCJleGFtaW5lRXhpdHMiLCJleGl0cyIsImV4aXREZXNjcmlwdGlvbiIsImV4aXRLZXlzIiwiZXhpdCIsImZpbmQiLCJtcyIsInJvb21JRCIsIm5ld1Jvb20iLCJjYW5FeGl0IiwiY2FuRW50ZXIiLCJvbkV4aXQiLCJvbkVudGVyIiwiZW5hYmxlQ29tbWFuZElucHV0IiwiUm9vbSIsImVudGVyQ2FsbGJhY2siLCJleGl0Q2FsbGJhY2siLCJjYW5FbnRlckxvZ2ljIiwiY2FuRXhpdExvZ2ljIiwidGlja0NhbGxiYWNrIiwiaW1wdWxzZSIsImFkZEV4aXQiLCJhZGRFbnRlckNhbGxiYWNrIiwiY2FsbGJhY2siLCJhZGRFeGl0Q2FsbGJhY2siLCJhZGRFbnRlckxvZ2ljIiwiYWRkRXhpdExvZ2ljIiwiYWRkVGlja0NhbGxiYWNrIiwiUm9vbUJ1aWxkZXIiLCJ3aXRoSUQiLCJJRCIsIndpdGhUaXRsZSIsIndpdGhGaXJzdERlc2NyaXB0aW9uIiwid2l0aERlc2NyaXB0aW9uIiwid2l0aEV4aXQiLCJ3aXRoSXRlbSIsIml0ZW1JRCIsIndpdGhFbnRlckNhbGxiYWNrIiwid2l0aEV4aXRDYWxsYmFjayIsIndpdGhFbnRlckxvZ2ljIiwid2l0aEV4aXRMb2dpYyIsIndpdGhUaWNrIiwid2l0aE11c2ljIiwid2l0aEFtYmllbmNlIiwid2l0aEltcHVsc2UiLCJ0ZWxsIiwiSXRlbSIsInVzYWJsZSIsInVzZUNhbGxiYWNrIiwidGFrZUNhbGxiYWNrIiwiZHJvcENhbGxiYWNrIiwiYWRkVXNlQ2FsbGJhY2siLCJhZGRUYWtlQ2FsbGJhY2siLCJhZGREcm9wQ2FsbGJhY2siLCJJdGVtQnVpbGRlciIsIndpdGhOYW1lIiwiaXNVc2FibGUiLCJpc1Rha2VhYmxlIiwid2l0aFVzZUNhbGxiYWNrIiwid2l0aFRha2VDYWxsYmFjayIsIndpdGhEcm9wQ2FsbGJhY2siLCJ3aXRoVGlja0NhbGxiYWNrIiwiY2VudHJhbDEiLCJzdGF0dWUxIiwic3RhdHVlMiIsInN0YXR1ZTMiLCJzdGF0dWU0IiwiTWVvd0NvbW1hbmQiLCJzdGFydEdhbWUiLCJoaWRkZW4iXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file +(()=>{"use strict";class t{constructor(){this.states=new Map}get(t,e=null){return this.states.has(t)?this.states.get(t):(this.states.set(t,e),e)}set(t,e){return this.states.set(t,e)}change(t,e=1){let s=this.get(t,0);s+=e,this.set(t,s)}serialize(){const t=this.states.entries(),e=[];for(let s of t)e.push(s);return e}deserialize(t){this.states=new Map(t)}}class e{constructor(){this.inventory=[],this.currentRoom="start",this.context=null}addItem(t){this.inventory.push(t)}removeItem(t){this.inventory=this.inventory.filter((e=>e!=t))}getInventory(){return this.inventory.map((t=>this.context.getItem(t)))}}class s{speak(t){}stop(){}setOptions(t){}}class i extends s{constructor(t={}){super(),this.timeout=100,this.timeout=t.timeout||100,this.init()}init(){this.container=document.createElement("div"),this.container.setAttribute("aria-live","polite"),this.speechDisplay=document.createElement("div"),this.speechDisplay.setAttribute("aria-live","polite"),this.container.append(this.speechDisplay),document.body.appendChild(this.container),document.body.insertBefore(this.container,document.body.firstChild)}speak(t){this.clearDisplay();const e=document.createTextNode(t),s=document.createElement("p");s.appendChild(e),this.speechDisplay.appendChild(s),setTimeout(this.clearDisplay.bind(this),this.timeout)}stop(){this.clearDisplay()}clearDisplay(){this.speechDisplay.innerHTML=""}}class a extends s{constructor(t={}){super(),this.rate=t.rate||1,this.synth=window.speechSynthesis}speak(t){let e=new SpeechSynthesisUtterance(t);e.rate=this.rate,this.synth.speak(e)}stop(){this.synth.cancel()}setOptions(t){this.rate=t.rate||1}}class n{constructor(t=function(t="aria"){return"webtts"===t?new a:new i}()){this.output=t}speak(t){this.output.speak(t)}stop(){this.output.stop()}}var h=function(t,e,s,i){return new(s||(s=Promise))((function(a,n){function h(t){try{u(i.next(t))}catch(t){n(t)}}function r(t){try{u(i.throw(t))}catch(t){n(t)}}function u(t){var e;t.done?a(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}u((i=i.apply(t,e||[])).next())}))};class r{constructor(){this.context=new AudioContext}getContext(){return this.context}createGain(){return this.context.createGain()}getOutputDestination(){return this.context.destination}createBufferSource(){return this.context.createBufferSource()}decodeAudioData(t){return h(this,void 0,void 0,(function*(){return yield this.context.decodeAudioData(t)}))}createPanner(){return this.context.createPanner()}createMediaElementSource(t){return this.context.createMediaElementSource(t)}}class u{constructor(){this.events=new Map}emit(t,e={}){let s=this.events.get(t);if(s)s.subscribers.forEach((t=>{t(e)}));else{let e=new o(t);this.events.set(t,e)}}subscribe(t,e){let s=this.events.get(t);s||(s=new o(t),this.events.set(t,s)),s.subscribers.push(e)}unsubscribe(t,e){if(this.events.has(t)){let s=this.events.get(t);s.subscribers=s.subscribers.filter((t=>t!==e)),s.subscribers.length<1&&this.events.delete(t)}}unsubscribeAll(t){this.events.has(t)&&this.events.delete(t)}}class o{constructor(t){this.id=t,this.subscribers=[]}}class l{constructor(t){this.values=new Float32Array(4),void 0!==t&&(this.xyzw=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get w(){return this.values[3]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}get xyzw(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set w(t){this.values[3]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set xyzw(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}get r(){return this.values[0]}get g(){return this.values[1]}get b(){return this.values[2]}get a(){return this.values[3]}get rg(){return[this.values[0],this.values[1]]}get rgb(){return[this.values[0],this.values[1],this.values[2]]}get rgba(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set r(t){this.values[0]=t}set g(t){this.values[1]=t}set b(t){this.values[2]=t}set a(t){this.values[3]=t}set rg(t){this.values[0]=t[0],this.values[1]=t[1]}set rgb(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set rgba(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}at(t){return this.values[t]}reset(){this.x=0,this.y=0,this.z=0,this.w=0}copy(t){return t||(t=new l),t.x=this.x,t.y=this.y,t.z=this.z,t.w=this.w,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t.z=-this.z,t.w=-this.w,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e)&&(!(Math.abs(this.y-t.y)>e)&&(!(Math.abs(this.z-t.z)>e)&&!(Math.abs(this.w-t.w)>e)))}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y,s=this.z,i=this.w;return t*t+e*e+s*s+i*i}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}subtract(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e.z*=t,e.w*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x*=0,t.y*=0,t.z*=0,t.w*=0,t):(e=1/e,t.x*=e,t.y*=e,t.z*=e,t.w*=e,t)}multiplyMat4(t,e){return e||(e=this),t.multiplyVec4(this,e)}static mix(t,e,s,i){return i||(i=new l),i.x=t.x+s*(e.x-t.x),i.y=t.y+s*(e.y-t.y),i.z=t.z+s*(e.z-t.z),i.w=t.w+s*(e.w-t.w),i}static sum(t,e,s){return s||(s=new l),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s.w=t.w+e.w,s}static difference(t,e,s){return s||(s=new l),s.x=t.x-e.x,s.y=t.y-e.y,s.z=t.z-e.z,s.w=t.w-e.w,s}static product(t,e,s){return s||(s=new l),s.x=t.x*e.x,s.y=t.y*e.y,s.z=t.z*e.z,s.w=t.w*e.w,s}static quotient(t,e,s){return s||(s=new l),s.x=t.x/e.x,s.y=t.y/e.y,s.z=t.z/e.z,s.w=t.w/e.w,s}}l.zero=new l([0,0,0,1]),l.one=new l([1,1,1,1]);class c{constructor(t){this.values=new Float32Array(16),void 0!==t&&this.init(t)}at(t){return this.values[t]}init(t){for(let e=0;e<16;e++)this.values[e]=t[e];return this}reset(){for(let t=0;t<16;t++)this.values[t]=0}copy(t){t||(t=new c);for(let e=0;e<16;e++)t.values[e]=this.values[e];return t}all(){const t=[];for(let e=0;e<16;e++)t[e]=this.values[e];return t}row(t){return[this.values[4*t+0],this.values[4*t+1],this.values[4*t+2],this.values[4*t+3]]}col(t){return[this.values[t],this.values[t+4],this.values[t+8],this.values[t+12]]}equals(t,e=1e-5){for(let s=0;s<16;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}determinant(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],a=this.values[4],n=this.values[5],h=this.values[6],r=this.values[7],u=this.values[8],o=this.values[9],l=this.values[10],c=this.values[11],v=this.values[12],d=this.values[13],m=this.values[14],y=this.values[15];return(t*n-e*a)*(l*y-c*m)-(t*h-s*a)*(o*y-c*d)+(t*r-i*a)*(o*m-l*d)+(e*h-s*n)*(u*y-c*v)-(e*r-i*n)*(u*m-l*v)+(s*r-i*h)*(u*d-o*v)}setIdentity(){return this.values[0]=1,this.values[1]=0,this.values[2]=0,this.values[3]=0,this.values[4]=0,this.values[5]=1,this.values[6]=0,this.values[7]=0,this.values[8]=0,this.values[9]=0,this.values[10]=1,this.values[11]=0,this.values[12]=0,this.values[13]=0,this.values[14]=0,this.values[15]=1,this}transpose(){const t=this.values[1],e=this.values[2],s=this.values[3],i=this.values[6],a=this.values[7],n=this.values[11];return this.values[1]=this.values[4],this.values[2]=this.values[8],this.values[3]=this.values[12],this.values[4]=t,this.values[6]=this.values[9],this.values[7]=this.values[13],this.values[8]=e,this.values[9]=i,this.values[11]=this.values[14],this.values[12]=s,this.values[13]=a,this.values[14]=n,this}inverse(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],a=this.values[4],n=this.values[5],h=this.values[6],r=this.values[7],u=this.values[8],o=this.values[9],l=this.values[10],c=this.values[11],v=this.values[12],d=this.values[13],m=this.values[14],y=this.values[15],p=t*n-e*a,x=t*h-s*a,w=t*r-i*a,f=e*h-s*n,g=e*r-i*n,b=s*r-i*h,z=u*d-o*v,k=u*m-l*v,I=u*y-c*v,C=o*m-l*d,M=o*y-c*d,E=l*y-c*m;let T=p*E-x*M+w*C+f*I-g*k+b*z;return T?(T=1/T,this.values[0]=(n*E-h*M+r*C)*T,this.values[1]=(-e*E+s*M-i*C)*T,this.values[2]=(d*b-m*g+y*f)*T,this.values[3]=(-o*b+l*g-c*f)*T,this.values[4]=(-a*E+h*I-r*k)*T,this.values[5]=(t*E-s*I+i*k)*T,this.values[6]=(-v*b+m*w-y*x)*T,this.values[7]=(u*b-l*w+c*x)*T,this.values[8]=(a*M-n*I+r*z)*T,this.values[9]=(-t*M+e*I-i*z)*T,this.values[10]=(v*g-d*w+y*p)*T,this.values[11]=(-u*g+o*w-c*p)*T,this.values[12]=(-a*C+n*k-h*z)*T,this.values[13]=(t*C-e*k+s*z)*T,this.values[14]=(-v*f+d*x-m*p)*T,this.values[15]=(u*f-o*x+l*p)*T,this):null}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],a=this.values[3],n=this.values[4],h=this.values[5],r=this.values[6],u=this.values[7],o=this.values[8],l=this.values[9],c=this.values[10],v=this.values[11],d=this.values[12],m=this.values[13],y=this.values[14],p=this.values[15];let x=t.at(0),w=t.at(1),f=t.at(2),g=t.at(3);return this.values[0]=x*e+w*n+f*o+g*d,this.values[1]=x*s+w*h+f*l+g*m,this.values[2]=x*i+w*r+f*c+g*y,this.values[3]=x*a+w*u+f*v+g*p,x=t.at(4),w=t.at(5),f=t.at(6),g=t.at(7),this.values[4]=x*e+w*n+f*o+g*d,this.values[5]=x*s+w*h+f*l+g*m,this.values[6]=x*i+w*r+f*c+g*y,this.values[7]=x*a+w*u+f*v+g*p,x=t.at(8),w=t.at(9),f=t.at(10),g=t.at(11),this.values[8]=x*e+w*n+f*o+g*d,this.values[9]=x*s+w*h+f*l+g*m,this.values[10]=x*i+w*r+f*c+g*y,this.values[11]=x*a+w*u+f*v+g*p,x=t.at(12),w=t.at(13),f=t.at(14),g=t.at(15),this.values[12]=x*e+w*n+f*o+g*d,this.values[13]=x*s+w*h+f*l+g*m,this.values[14]=x*i+w*r+f*c+g*y,this.values[15]=x*a+w*u+f*v+g*p,this}multiplyVec3(t){const e=t.x,s=t.y,i=t.z;return new y([this.values[0]*e+this.values[4]*s+this.values[8]*i+this.values[12],this.values[1]*e+this.values[5]*s+this.values[9]*i+this.values[13],this.values[2]*e+this.values[6]*s+this.values[10]*i+this.values[14]])}multiplyVec4(t,e){e||(e=new l);const s=t.x,i=t.y,a=t.z,n=t.w;return e.x=this.values[0]*s+this.values[4]*i+this.values[8]*a+this.values[12]*n,e.y=this.values[1]*s+this.values[5]*i+this.values[9]*a+this.values[13]*n,e.z=this.values[2]*s+this.values[6]*i+this.values[10]*a+this.values[14]*n,e.w=this.values[3]*s+this.values[7]*i+this.values[11]*a+this.values[15]*n,e}toMat3(){return new d([this.values[0],this.values[1],this.values[2],this.values[4],this.values[5],this.values[6],this.values[8],this.values[9],this.values[10]])}toInverseMat3(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[4],a=this.values[5],n=this.values[6],h=this.values[8],r=this.values[9],u=this.values[10],o=u*a-n*r,l=-u*i+n*h,c=r*i-a*h;let v=t*o+e*l+s*c;return v?(v=1/v,new d([o*v,(-u*e+s*r)*v,(n*e-s*a)*v,l*v,(u*t-s*h)*v,(-n*t+s*i)*v,c*v,(-r*t+e*h)*v,(a*t-e*i)*v])):null}translate(t){const e=t.x,s=t.y,i=t.z;return this.values[12]+=this.values[0]*e+this.values[4]*s+this.values[8]*i,this.values[13]+=this.values[1]*e+this.values[5]*s+this.values[9]*i,this.values[14]+=this.values[2]*e+this.values[6]*s+this.values[10]*i,this.values[15]+=this.values[3]*e+this.values[7]*s+this.values[11]*i,this}scale(t){const e=t.x,s=t.y,i=t.z;return this.values[0]*=e,this.values[1]*=e,this.values[2]*=e,this.values[3]*=e,this.values[4]*=s,this.values[5]*=s,this.values[6]*=s,this.values[7]*=s,this.values[8]*=i,this.values[9]*=i,this.values[10]*=i,this.values[11]*=i,this}rotate(t,e){let s=e.x,i=e.y,a=e.z,n=Math.sqrt(s*s+i*i+a*a);if(!n)return null;1!==n&&(n=1/n,s*=n,i*=n,a*=n);const h=Math.sin(t),r=Math.cos(t),u=1-r,o=this.values[0],l=this.values[1],c=this.values[2],v=this.values[3],d=this.values[4],m=this.values[5],y=this.values[6],p=this.values[7],x=this.values[8],w=this.values[9],f=this.values[10],g=this.values[11],b=s*s*u+r,z=i*s*u+a*h,k=a*s*u-i*h,I=s*i*u-a*h,C=i*i*u+r,M=a*i*u+s*h,E=s*a*u+i*h,T=i*a*u-s*h,D=a*a*u+r;return this.values[0]=o*b+d*z+x*k,this.values[1]=l*b+m*z+w*k,this.values[2]=c*b+y*z+f*k,this.values[3]=v*b+p*z+g*k,this.values[4]=o*I+d*C+x*M,this.values[5]=l*I+m*C+w*M,this.values[6]=c*I+y*C+f*M,this.values[7]=v*I+p*C+g*M,this.values[8]=o*E+d*T+x*D,this.values[9]=l*E+m*T+w*D,this.values[10]=c*E+y*T+f*D,this.values[11]=v*E+p*T+g*D,this}static frustum(t,e,s,i,a,n){const h=e-t,r=i-s,u=n-a;return new c([2*a/h,0,0,0,0,2*a/r,0,0,(e+t)/h,(i+s)/r,-(n+a)/u,-1,0,0,-n*a*2/u,0])}static perspective(t,e,s,i){const a=s*Math.tan(t*Math.PI/360),n=a*e;return c.frustum(-n,n,-a,a,s,i)}static orthographic(t,e,s,i,a,n){const h=e-t,r=i-s,u=n-a;return new c([2/h,0,0,0,0,2/r,0,0,0,0,-2/u,0,-(t+e)/h,-(i+s)/r,-(n+a)/u,1])}static lookAt(t,e,s=y.up){if(t.equals(e))return this.identity;const i=y.difference(t,e).normalize(),a=y.cross(s,i).normalize(),n=y.cross(i,a).normalize();return new c([a.x,n.x,i.x,0,a.y,n.y,i.y,0,a.z,n.z,i.z,0,-y.dot(a,t),-y.dot(n,t),-y.dot(i,t),1])}static product(t,e,s){const i=t.at(0),a=t.at(1),n=t.at(2),h=t.at(3),r=t.at(4),u=t.at(5),o=t.at(6),l=t.at(7),v=t.at(8),d=t.at(9),m=t.at(10),y=t.at(11),p=t.at(12),x=t.at(13),w=t.at(14),f=t.at(15),g=e.at(0),b=e.at(1),z=e.at(2),k=e.at(3),I=e.at(4),C=e.at(5),M=e.at(6),E=e.at(7),T=e.at(8),D=e.at(9),S=e.at(10),A=e.at(11),R=e.at(12),V=e.at(13),N=e.at(14),L=e.at(15);return s?(s.init([g*i+b*r+z*v+k*p,g*a+b*u+z*d+k*x,g*n+b*o+z*m+k*w,g*h+b*l+z*y+k*f,I*i+C*r+M*v+E*p,I*a+C*u+M*d+E*x,I*n+C*o+M*m+E*w,I*h+C*l+M*y+E*f,T*i+D*r+S*v+A*p,T*a+D*u+S*d+A*x,T*n+D*o+S*m+A*w,T*h+D*l+S*y+A*f,R*i+V*r+N*v+L*p,R*a+V*u+N*d+L*x,R*n+V*o+N*m+L*w,R*h+V*l+N*y+L*f]),s):new c([g*i+b*r+z*v+k*p,g*a+b*u+z*d+k*x,g*n+b*o+z*m+k*w,g*h+b*l+z*y+k*f,I*i+C*r+M*v+E*p,I*a+C*u+M*d+E*x,I*n+C*o+M*m+E*w,I*h+C*l+M*y+E*f,T*i+D*r+S*v+A*p,T*a+D*u+S*d+A*x,T*n+D*o+S*m+A*w,T*h+D*l+S*y+A*f,R*i+V*r+N*v+L*p,R*a+V*u+N*d+L*x,R*n+V*o+N*m+L*w,R*h+V*l+N*y+L*f])}}c.identity=(new c).setIdentity();class v{constructor(t){this.values=new Float32Array(2),void 0!==t&&(this.xy=t)}get x(){return this.values[0]}get y(){return this.values[1]}get xy(){return[this.values[0],this.values[1]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}at(t){return this.values[t]}reset(){this.x=0,this.y=0}copy(t){return t||(t=new v),t.x=this.x,t.y=this.y,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e)&&!(Math.abs(this.y-t.y)>e)}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y;return t*t+e*e}add(t){return this.x+=t.x,this.y+=t.y,this}subtract(t){return this.x-=t.x,this.y-=t.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}divide(t){return this.x/=t.x,this.y/=t.y,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x=0,t.y=0,t):(e=1/e,t.x*=e,t.y*=e,t)}multiplyMat2(t,e){return e||(e=this),t.multiplyVec2(this,e)}multiplyMat3(t,e){return e||(e=this),t.multiplyVec2(this,e)}static cross(t,e,s){s||(s=new y);const i=t.x,a=t.y,n=e.x,h=i*e.y-a*n;return s.x=0,s.y=0,s.z=h,s}static dot(t,e){return t.x*e.x+t.y*e.y}static distance(t,e){return Math.sqrt(this.squaredDistance(t,e))}static squaredDistance(t,e){const s=e.x-t.x,i=e.y-t.y;return s*s+i*i}static direction(t,e,s){s||(s=new v);const i=t.x-e.x,a=t.y-e.y;let n=Math.sqrt(i*i+a*a);return 0===n?(s.x=0,s.y=0,s):(n=1/n,s.x=i*n,s.y=a*n,s)}static mix(t,e,s,i){i||(i=new v);const a=t.x,n=t.y,h=e.x,r=e.y;return i.x=a+s*(h-a),i.y=n+s*(r-n),i}static sum(t,e,s){return s||(s=new v),s.x=t.x+e.x,s.y=t.y+e.y,s}static difference(t,e,s){return s||(s=new v),s.x=t.x-e.x,s.y=t.y-e.y,s}static product(t,e,s){return s||(s=new v),s.x=t.x*e.x,s.y=t.y*e.y,s}static quotient(t,e,s){return s||(s=new v),s.x=t.x/e.x,s.y=t.y/e.y,s}}v.zero=new v([0,0]),v.one=new v([1,1]);class d{constructor(t){this.values=new Float32Array(9),void 0!==t&&this.init(t)}at(t){return this.values[t]}init(t){for(let e=0;e<9;e++)this.values[e]=t[e];return this}reset(){for(let t=0;t<9;t++)this.values[t]=0}copy(t){t||(t=new d);for(let e=0;e<9;e++)t.values[e]=this.values[e];return t}all(){const t=[];for(let e=0;e<9;e++)t[e]=this.values[e];return t}row(t){return[this.values[3*t+0],this.values[3*t+1],this.values[3*t+2]]}col(t){return[this.values[t],this.values[t+3],this.values[t+6]]}equals(t,e=1e-5){for(let s=0;s<9;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}determinant(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],a=this.values[4],n=this.values[5],h=this.values[6],r=this.values[7],u=this.values[8];return t*(u*a-n*r)+e*(-u*i+n*h)+s*(r*i-a*h)}setIdentity(){return this.values[0]=1,this.values[1]=0,this.values[2]=0,this.values[3]=0,this.values[4]=1,this.values[5]=0,this.values[6]=0,this.values[7]=0,this.values[8]=1,this}transpose(){const t=this.values[1],e=this.values[2],s=this.values[5];return this.values[1]=this.values[3],this.values[2]=this.values[6],this.values[3]=t,this.values[5]=this.values[7],this.values[6]=e,this.values[7]=s,this}inverse(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],a=this.values[4],n=this.values[5],h=this.values[6],r=this.values[7],u=this.values[8],o=u*a-n*r,l=-u*i+n*h,c=r*i-a*h;let v=t*o+e*l+s*c;return v?(v=1/v,this.values[0]=o*v,this.values[1]=(-u*e+s*r)*v,this.values[2]=(n*e-s*a)*v,this.values[3]=l*v,this.values[4]=(u*t-s*h)*v,this.values[5]=(-n*t+s*i)*v,this.values[6]=c*v,this.values[7]=(-r*t+e*h)*v,this.values[8]=(a*t-e*i)*v,this):null}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],a=this.values[3],n=this.values[4],h=this.values[5],r=this.values[6],u=this.values[7],o=this.values[8],l=t.at(0),c=t.at(1),v=t.at(2),d=t.at(3),m=t.at(4),y=t.at(5),p=t.at(6),x=t.at(7),w=t.at(8);return this.values[0]=l*e+c*a+v*r,this.values[1]=l*s+c*n+v*u,this.values[2]=l*i+c*h+v*o,this.values[3]=d*e+m*a+y*r,this.values[4]=d*s+m*n+y*u,this.values[5]=d*i+m*h+y*o,this.values[6]=p*e+x*a+w*r,this.values[7]=p*s+x*n+w*u,this.values[8]=p*i+x*h+w*o,this}multiplyVec2(t,e){const s=t.x,i=t.y;return e?(e.xy=[s*this.values[0]+i*this.values[3]+this.values[6],s*this.values[1]+i*this.values[4]+this.values[7]],e):new v([s*this.values[0]+i*this.values[3]+this.values[6],s*this.values[1]+i*this.values[4]+this.values[7]])}multiplyVec3(t,e){const s=t.x,i=t.y,a=t.z;return e?(e.xyz=[s*this.values[0]+i*this.values[3]+a*this.values[6],s*this.values[1]+i*this.values[4]+a*this.values[7],s*this.values[2]+i*this.values[5]+a*this.values[8]],e):new y([s*this.values[0]+i*this.values[3]+a*this.values[6],s*this.values[1]+i*this.values[4]+a*this.values[7],s*this.values[2]+i*this.values[5]+a*this.values[8]])}toMat4(t){return t?(t.init([this.values[0],this.values[1],this.values[2],0,this.values[3],this.values[4],this.values[5],0,this.values[6],this.values[7],this.values[8],0,0,0,0,1]),t):new c([this.values[0],this.values[1],this.values[2],0,this.values[3],this.values[4],this.values[5],0,this.values[6],this.values[7],this.values[8],0,0,0,0,1])}toQuat(){const t=this.values[0],e=this.values[1],s=this.values[2],i=this.values[3],a=this.values[4],n=this.values[5],h=this.values[6],r=this.values[7],u=this.values[8],o=t-a-u,l=a-t-u,c=u-t-a;let v=0,d=t+a+u;o>d&&(d=o,v=1),l>d&&(d=l,v=2),c>d&&(d=c,v=3);const y=.5*Math.sqrt(d+1),p=.25/y,x=new m;switch(v){case 0:x.w=y,x.x=(n-r)*p,x.y=(h-s)*p,x.z=(e-i)*p;break;case 1:x.w=(n-r)*p,x.x=y,x.y=(e+i)*p,x.z=(h+s)*p;break;case 2:x.w=(h-s)*p,x.x=(e+i)*p,x.y=y,x.z=(n+r)*p;break;case 3:x.w=(e-i)*p,x.x=(h+s)*p,x.y=(n+r)*p,x.z=y}return x}rotate(t,e){let s=e.x,i=e.y,a=e.z,n=Math.sqrt(s*s+i*i+a*a);if(!n)return null;1!==n&&(n=1/n,s*=n,i*=n,a*=n);const h=Math.sin(t),r=Math.cos(t),u=1-r,o=this.values[0],l=this.values[1],c=this.values[2],v=this.values[4],d=this.values[5],m=this.values[6],y=this.values[8],p=this.values[9],x=this.values[10],w=s*s*u+r,f=i*s*u+a*h,g=a*s*u-i*h,b=s*i*u-a*h,z=i*i*u+r,k=a*i*u+s*h,I=s*a*u+i*h,C=i*a*u-s*h,M=a*a*u+r;return this.values[0]=o*w+v*f+y*g,this.values[1]=l*w+d*f+p*g,this.values[2]=c*w+m*f+x*g,this.values[3]=o*b+v*z+y*k,this.values[4]=l*b+d*z+p*k,this.values[5]=c*b+m*z+x*k,this.values[6]=o*I+v*C+y*M,this.values[7]=l*I+d*C+p*M,this.values[8]=c*I+m*C+x*M,this}static product(t,e,s){const i=t.at(0),a=t.at(1),n=t.at(2),h=t.at(3),r=t.at(4),u=t.at(5),o=t.at(6),l=t.at(7),c=t.at(8),v=e.at(0),m=e.at(1),y=e.at(2),p=e.at(3),x=e.at(4),w=e.at(5),f=e.at(6),g=e.at(7),b=e.at(8);return s?(s.init([v*i+m*h+y*o,v*a+m*r+y*l,v*n+m*u+y*c,p*i+x*h+w*o,p*a+x*r+w*l,p*n+x*u+w*c,f*i+g*h+b*o,f*a+g*r+b*l,f*n+g*u+b*c]),s):new d([v*i+m*h+y*o,v*a+m*r+y*l,v*n+m*u+y*c,p*i+x*h+w*o,p*a+x*r+w*l,p*n+x*u+w*c,f*i+g*h+b*o,f*a+g*r+b*l,f*n+g*u+b*c])}}d.identity=(new d).setIdentity();class m{constructor(t){this.values=new Float32Array(4),void 0!==t&&(this.xyzw=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get w(){return this.values[3]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}get xyzw(){return[this.values[0],this.values[1],this.values[2],this.values[3]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set w(t){this.values[3]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}set xyzw(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2],this.values[3]=t[3]}at(t){return this.values[t]}reset(){for(let t=0;t<4;t++)this.values[t]=0}copy(t){t||(t=new m);for(let e=0;e<4;e++)t.values[e]=this.values[e];return t}roll(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.atan2(2*(t*e+i*s),i*i+t*t-e*e-s*s)}pitch(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.atan2(2*(e*s+i*t),i*i-t*t-e*e+s*s)}yaw(){return Math.asin(2*(this.x*this.z-this.w*this.y))}equals(t,e=1e-5){for(let s=0;s<4;s++)if(Math.abs(this.values[s]-t.at(s))>e)return!1;return!0}setIdentity(){return this.x=0,this.y=0,this.z=0,this.w=1,this}calculateW(){const t=this.x,e=this.y,s=this.z;return this.w=-Math.sqrt(Math.abs(1-t*t-e*e-s*s)),this}inverse(){const t=m.dot(this,this);if(!t)return this.xyzw=[0,0,0,0],this;const e=t?1/t:0;return this.x*=-e,this.y*=-e,this.z*=-e,this.w*=e,this}conjugate(){return this.values[0]*=-1,this.values[1]*=-1,this.values[2]*=-1,this}length(){const t=this.x,e=this.y,s=this.z,i=this.w;return Math.sqrt(t*t+e*e+s*s+i*i)}normalize(t){t||(t=this);const e=this.x,s=this.y,i=this.z,a=this.w;let n=Math.sqrt(e*e+s*s+i*i+a*a);return n?(n=1/n,t.x=e*n,t.y=s*n,t.z=i*n,t.w=a*n,t):(t.x=0,t.y=0,t.z=0,t.w=0,t)}add(t){for(let e=0;e<4;e++)this.values[e]+=t.at(e);return this}multiply(t){const e=this.values[0],s=this.values[1],i=this.values[2],a=this.values[3],n=t.x,h=t.y,r=t.z,u=t.w;return this.x=e*u+a*n+s*r-i*h,this.y=s*u+a*h+i*n-e*r,this.z=i*u+a*r+e*h-s*n,this.w=a*u-e*n-s*h-i*r,this}multiplyVec3(t,e){e||(e=new y);const s=t.x,i=t.y,a=t.z,n=this.x,h=this.y,r=this.z,u=this.w,o=u*s+h*a-r*i,l=u*i+r*s-n*a,c=u*a+n*i-h*s,v=-n*s-h*i-r*a;return e.x=o*u+v*-n+l*-r-c*-h,e.y=l*u+v*-h+c*-n-o*-r,e.z=c*u+v*-r+o*-h-l*-n,e}toMat3(t){t||(t=new d);const e=this.x,s=this.y,i=this.z,a=this.w,n=e+e,h=s+s,r=i+i,u=e*n,o=e*h,l=e*r,c=s*h,v=s*r,m=i*r,y=a*n,p=a*h,x=a*r;return t.init([1-(c+m),o+x,l-p,o-x,1-(u+m),v+y,l+p,v-y,1-(u+c)]),t}toMat4(t){t||(t=new c);const e=this.x,s=this.y,i=this.z,a=this.w,n=e+e,h=s+s,r=i+i,u=e*n,o=e*h,l=e*r,v=s*h,d=s*r,m=i*r,y=a*n,p=a*h,x=a*r;return t.init([1-(v+m),o+x,l-p,0,o-x,1-(u+m),d+y,0,l+p,d-y,1-(u+v),0,0,0,0,1]),t}static dot(t,e){return t.x*e.x+t.y*e.y+t.z*e.z+t.w*e.w}static sum(t,e,s){return s||(s=new m),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s.w=t.w+e.w,s}static product(t,e,s){s||(s=new m);const i=t.x,a=t.y,n=t.z,h=t.w,r=e.x,u=e.y,o=e.z,l=e.w;return s.x=i*l+h*r+a*o-n*u,s.y=a*l+h*u+n*r-i*o,s.z=n*l+h*o+i*u-a*r,s.w=h*l-i*r-a*u-n*o,s}static cross(t,e,s){s||(s=new m);const i=t.x,a=t.y,n=t.z,h=t.w,r=e.x,u=e.y,o=e.z,l=e.w;return s.x=h*o+n*l+i*u-a*r,s.y=h*l-i*r-a*u-n*o,s.z=h*r+i*l+a*o-n*u,s.w=h*u+a*l+n*r-i*o,s}static shortMix(t,e,s,i){if(i||(i=new m),s<=0)return i.xyzw=t.xyzw,i;if(s>=1)return i.xyzw=e.xyzw,i;let a=m.dot(t,e);const n=e.copy();let h,r;if(a<0&&(n.inverse(),a=-a),a>.9999)h=1-s,r=0+s;else{const t=Math.sqrt(1-a*a),e=Math.atan2(t,a),i=1/t;h=Math.sin((1-s)*e)*i,r=Math.sin((0+s)*e)*i}return i.x=h*t.x+r*n.x,i.y=h*t.y+r*n.y,i.z=h*t.z+r*n.z,i.w=h*t.w+r*n.w,i}static mix(t,e,s,i){i||(i=new m);const a=t.x*e.x+t.y*e.y+t.z*e.z+t.w*e.w;if(Math.abs(a)>=1)return i.xyzw=t.xyzw,i;const n=Math.acos(a),h=Math.sqrt(1-a*a);if(Math.abs(h)<.001)return i.x=.5*t.x+.5*e.x,i.y=.5*t.y+.5*e.y,i.z=.5*t.z+.5*e.z,i.w=.5*t.w+.5*e.w,i;const r=Math.sin((1-s)*n)/h,u=Math.sin(s*n)/h;return i.x=t.x*r+e.x*u,i.y=t.y*r+e.y*u,i.z=t.z*r+e.z*u,i.w=t.w*r+e.w*u,i}static fromAxisAngle(t,e,s){s||(s=new m),e*=.5;const i=Math.sin(e);return s.x=t.x*i,s.y=t.y*i,s.z=t.z*i,s.w=Math.cos(e),s}static fromVectors(t,e,s){s||(s=new m([0,0,0,1]));let i=function(t,e,s){if(ts)return s;return t}(y.dot(t,e),-1,1),a=y.cross(t,e),n=Math.sqrt(t.squaredLength()*e.squaredLength())+i;return n<1e-4&&(s=new m([-t.z,t.y,t.x,0]).normalize()),s=new m([n,a.x,a.y,a.z]).normalize()}static fromAxisRadians(t,e,s,i,a){a||(a=new m([0,0,0,1]));let n=new y([t,e,s]).length();if(0==n)return m.identity;n=1/n;let h=0;h=i<0?2*Math.PI- -1*i%(2*Math.PI):i%(2*Math.PI);let r=Math.sin(h/2),u=Math.cos(h/2);return a.x=n*t*r,a.y=n*e*r,a.z=n*s*r,a.w=u,a.normalize(),a}}m.identity=(new m).setIdentity();class y{constructor(t){this.values=new Float32Array(3),void 0!==t&&(this.xyz=t)}get x(){return this.values[0]}get y(){return this.values[1]}get z(){return this.values[2]}get xy(){return[this.values[0],this.values[1]]}get xyz(){return[this.values[0],this.values[1],this.values[2]]}set x(t){this.values[0]=t}set y(t){this.values[1]=t}set z(t){this.values[2]=t}set xy(t){this.values[0]=t[0],this.values[1]=t[1]}set xyz(t){this.values[0]=t[0],this.values[1]=t[1],this.values[2]=t[2]}at(t){return this.values[t]}reset(){this.x=0,this.y=0,this.z=0}copy(t){return t||(t=new y),t.x=this.x,t.y=this.y,t.z=this.z,t}negate(t){return t||(t=this),t.x=-this.x,t.y=-this.y,t.z=-this.z,t}equals(t,e=1e-5){return!(Math.abs(this.x-t.x)>e)&&(!(Math.abs(this.y-t.y)>e)&&!(Math.abs(this.z-t.z)>e))}length(){return Math.sqrt(this.squaredLength())}squaredLength(){const t=this.x,e=this.y,s=this.z;return t*t+e*e+s*s}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}subtract(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}scale(t,e){return e||(e=this),e.x*=t,e.y*=t,e.z*=t,e}normalize(t){t||(t=this);let e=this.length();return 1===e?this:0===e?(t.x=0,t.y=0,t.z=0,t):(e=1/e,t.x*=e,t.y*=e,t.z*=e,t)}multiplyByMat3(t,e){return e||(e=this),t.multiplyVec3(this,e)}multiplyByQuat(t,e){return e||(e=this),t.multiplyVec3(this,e)}toQuat(t){t||(t=new m);const e=new y,s=new y;return e.x=Math.cos(.5*this.x),s.x=Math.sin(.5*this.x),e.y=Math.cos(.5*this.y),s.y=Math.sin(.5*this.y),e.z=Math.cos(.5*this.z),s.z=Math.sin(.5*this.z),t.x=s.x*e.y*e.z-e.x*s.y*s.z,t.y=e.x*s.y*e.z+s.x*e.y*s.z,t.z=e.x*e.y*s.z-s.x*s.y*e.z,t.w=e.x*e.y*e.z+s.x*s.y*s.z,t}static cross(t,e,s){s||(s=new y);const i=t.x,a=t.y,n=t.z,h=e.x,r=e.y,u=e.z;return s.x=a*u-n*r,s.y=n*h-i*u,s.z=i*r-a*h,s}static dot(t,e){const s=t.x,i=t.y,a=t.z;return s*e.x+i*e.y+a*e.z}static distance(t,e){e.x,t.x,e.y,t.y,e.z,t.z;return Math.sqrt(this.squaredDistance(t,e))}static squaredDistance(t,e){const s=e.x-t.x,i=e.y-t.y,a=e.z-t.z;return s*s+i*i+a*a}static direction(t,e,s){s||(s=new y);const i=t.x-e.x,a=t.y-e.y,n=t.z-e.z;let h=Math.sqrt(i*i+a*a+n*n);return 0===h?(s.x=0,s.y=0,s.z=0,s):(h=1/h,s.x=i*h,s.y=a*h,s.z=n*h,s)}static mix(t,e,s,i){return i||(i=new y),i.x=t.x+s*(e.x-t.x),i.y=t.y+s*(e.y-t.y),i.z=t.z+s*(e.z-t.z),i}static sum(t,e,s){return s||(s=new y),s.x=t.x+e.x,s.y=t.y+e.y,s.z=t.z+e.z,s}static difference(t,e,s){return s||(s=new y),s.x=t.x-e.x,s.y=t.y-e.y,s.z=t.z-e.z,s}static product(t,e,s){return s||(s=new y),s.x=t.x*e.x,s.y=t.y*e.y,s.z=t.z*e.z,s}static quotient(t,e,s){return s||(s=new y),s.x=t.x/e.x,s.y=t.y/e.y,s.z=t.z/e.z,s}static rotate(t,e,s){s||(s=new y);let i=2*(e.y*t.z-e.z*t.y),a=2*(e.z*t.x-e.x*t.z),n=2*(e.x*t.y-e.y*t.x);return s.x=t.x+i*e.w+(e.y*n-e.z*a),s.y=t.y+a*e.w+(e.z*i-e.x*n),s.z=t.z+n*e.w+(e.x*a-e.y*i),s}}y.zero=new y([0,0,0]),y.one=new y([1,1,1]),y.up=new y([0,1,0]),y.right=new y([1,0,0]),y.forward=new y([0,0,1]);class p extends u{constructor(t){super(),this.context=t,this.scene=this.context.getContext().createGain(),this.listener=this.context.getContext().listener,this.init()}init(){}createSource(){const t=this.context.getContext().createPanner();return t.panningModel="HRTF",t.distanceModel="linear",t.maxDistance=20,t.refDistance=2,t.connect(this.scene),t}getOutput(){return this.scene}getInput(){return this.scene}setListenerPosition(t,e,s){this.listener.setPosition(t,e,s)}setListenerOrientation(t,e){let s=new y([t.x,t.y,t.z]),i=s.copy();y.cross(i,new y([e.x,e.y,e.z]),i),y.cross(i,s,i),s.normalize(),i.normalize(),this.listener.setOrientation(s.x,s.y,s.z,i.x,i.y,i.z)}}class x{constructor(t,e,s,i){this.effects=[],this.context=t,this.graph=e,this.inputNode=s,this.outputNode=i,this.updateConnections()}applyEffect(t){this.effects.push(t),this.updateConnections()}removeEffect(t){this.effects.forEach((e=>{t===e&&e.disconnect()})),this.effects=this.effects.filter((e=>t!==e)),this.updateConnections()}updateConnections(){if(0==this.effects.length)return void this.inputNode.connect(this.outputNode);let t=null,e=null;this.effects.forEach((s=>{t=s,e?t.connectInput(e.getOutput()):t.connectInput(this.inputNode),e=t})),t&&t.connectOutput(this.outputNode)}}class w{constructor(t,e,s=!1){this.scene=t,this.context=e,this.swapChannels=s,this.init()}init(){this.effectsBus=this.context.createGain(),this.worldBus=this.context.createGain(),this.secondaryBus=this.context.createGain(),this.master=this.context.createGain(),this.scene.getOutput().connect(this.worldBus),this.worldBus.connect(this.effectsBus),this.effects=new x(this.context,this,this.effectsBus,this.master),this.secondaryBus.connect(this.master),this.swapChannels?(this.channelSplitter=this.context.getContext().createChannelSplitter(2),this.channelMerger=this.context.getContext().createChannelMerger(2),this.master.connect(this.channelSplitter),this.channelSplitter.connect(this.channelMerger,0,1),this.channelSplitter.connect(this.channelMerger,1,0),this.channelMerger.connect(this.context.getOutputDestination())):this.master.connect(this.context.getOutputDestination())}connectToMaster(t){t.connect(this.master)}connectToUI(t){t.connect(this.secondaryBus)}applyEffect(t){this.effects.applyEffect(t)}removeEffect(t){this.effects.removeEffect(t)}}var f;!function(t){t[t.WorldSource=0]="WorldSource",t[t.UISource=1]="UISource",t[t.MasterSource=2]="MasterSource"}(f||(f={}));class g{constructor(t,e,s,i=null,a=f.WorldSource){this.position={x:0,y:0,z:0},this.buffer=i,this.context=s,this.scene=e,this.graph=t,this.type=a,this.playbackRate=1,this.volume=1,this.init()}init(){this.gain=this.context.createGain(),this.stop=this.stop.bind(this)}getBuffer(){return this.buffer}setBuffer(t){this.buffer=t,this.playOnLoad&&(this.play(),this.playOnLoad=!1)}play(t=0,e=0,s=(this.buffer?this.buffer.duration:0)){this.playing&&this.node&&this.stop(),this.buffer?(this.node||(this.node=this.context.createBufferSource(),this.node.buffer=this.buffer,this.createConnections()),this.node&&(this.node.playbackRate.value=this.playbackRate,this.node.start(t,e,s),this.node.loop=this.looping,this.playing=!0,this.sceneNode&&this.sceneNode.setPosition(this.position.x,this.position.y,this.position.z),this.node.addEventListener("ended",this.stop))):this.playOnLoad=!0}setPosition(t,e,s){this.position={x:t,y:e,z:s},this.sceneNode&&this.sceneNode.setPosition(t,e,s)}setPlaybackRate(t){this.playbackRate=t,this.node&&(this.node.playbackRate.value=t)}getPlaybackRate(){return this.playbackRate}setVolume(t){this.volume=t,this.gain&&(this.gain.gain.value=t)}getVolume(){return this.volume}createConnections(){switch(this.type){case f.WorldSource:this.sceneNode||(this.sceneNode=this.scene.createSource()),this.node.connect(this.gain),this.gain.connect(this.sceneNode);break;case f.UISource:this.node.connect(this.gain),this.graph.connectToUI(this.gain);break;default:this.node.connect(this.gain),this.graph.connectToMaster(this.gain)}}stop(){this.playing=!1,this.node&&(this.node.removeEventListener("ended",this.stop),this.node.stop(),this.node.disconnect(),this.node=null,this.playing=!1,this.sceneNode&&(this.sceneNode.disconnect(),this.sceneNode=null))}destroy(){this.stop(),this.node=null,this.sceneNode=null,this.buffer=null,this.context=null,this.graph=null,this.scene=null}loop(t){this.looping=t,this.node&&(this.node.loop=t)}fadeOut(t){this.gain.gain.setValueAtTime(this.getVolume(),this.context.getContext().currentTime),this.node&&(this.gain.gain.exponentialRampToValueAtTime(1e-4,this.context.getContext().currentTime+t),setTimeout((()=>this.stop()),1e3*t))}fadeIn(t){this.gain.gain.setValueAtTime(1e-4,this.context.getContext().currentTime),this.node||this.play(),this.gain.gain.exponentialRampToValueAtTime(this.volume,this.context.getContext().currentTime+t)}}class b{constructor(t,e=null,s=null){this.name=t,this.data=e,this.decodedData=s}getData(){return this.data}setData(t){this.data=t}getDecodedData(){return this.decodedData}setDecodedData(t){this.decodedData=this.decodedData}getName(){return this.name}setName(t){this.name=t}}var z=function(t,e,s,i){return new(s||(s=Promise))((function(a,n){function h(t){try{u(i.next(t))}catch(t){n(t)}}function r(t){try{u(i.throw(t))}catch(t){n(t)}}function u(t){var e;t.done?a(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}u((i=i.apply(t,e||[])).next())}))};class k{get(t){return z(this,void 0,void 0,(function*(){const e=yield fetch(t);return yield e.arrayBuffer()}))}}var I=function(t,e,s,i){return new(s||(s=Promise))((function(a,n){function h(t){try{u(i.next(t))}catch(t){n(t)}}function r(t){try{u(i.throw(t))}catch(t){n(t)}}function u(t){var e;t.done?a(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}u((i=i.apply(t,e||[])).next())}))};class C extends u{constructor(t,e=new k,s=512){super(),this.loader=e,this.data={},this.maxData=s,this.context=t}get(t){return I(this,void 0,void 0,(function*(){if(this.data[t])return this.data[t].getDecodedData();{const e=yield this.loader.get(t),s=yield this.context.decodeAudioData(e),i=new b(t,e,s);Object.keys(this.data).length;return this.maxData,this.data[t]=i,i.getDecodedData()}}))}clear(){this.data={}}}class M extends class{constructor(t,e,s){this.graph=e,this.context=t,this.effectParams=s}connectOutput(t){this.effectNode.connect(t)}connectInput(t){this.inputNode=t,this.effectNode&&this.inputNode.connect(this.effectNode)}getOutput(){return this.effectNode}disconnect(){this.inputNode.disconnect(),this.effectNode.disconnect()}}{constructor(t,e,s){super(t,e,s),console.log("Creating convolver"),this.effectNode=this.context.getContext().createConvolver(),this.effectNode.buffer=this.effectParams.buffer}connectInput(t){this.channelSplitter=this.context.getContext().createChannelSplitter(2),this.channelMerger=this.context.getContext().createChannelMerger(2),this.channelSplitter.connect(this.channelMerger,0,0),this.channelSplitter.connect(this.channelMerger,1,0),this.channelSplitter.connect(this.channelMerger,0,1),this.channelSplitter.connect(this.channelMerger,1,1),t.connect(this.channelSplitter),this.channelMerger.connect(this.effectNode),this.inputNode=t}}class E{constructor(t,e,s,i,a=f.MasterSource){this.graph=t,this.scene=e,this.context=s,this.element=i,this.type=a,this.position={x:0,y:0,z:0},this.init()}init(){this.node=this.context.createMediaElementSource(this.element),this.gain=this.context.createGain(),this.createConnections(),this.element.addEventListener("canplay",(t=>{this.canPlay=!0,this.playOnAvailable&&this.play()}))}play(t=0,e=0,s=0){this.canPlay&&this.element.play(),this.playOnAvailable=!0}stop(){this.element.pause()}getVolume(){return this.element.volume}setVolume(t){this.element.volume=t}getPlaybackRate(){return this.element.playbackRate}setPlaybackRate(t){this.element.playbackRate=t}createConnections(){if(this.type===f.WorldSource)this.sceneNode||(this.sceneNode=this.scene.createSource()),this.node.connect(this.gain),this.gain.connect(this.sceneNode);else this.node.connect(this.gain),this.graph.connectToMaster(this.gain)}setPosition(t,e,s){this.position={x:t,y:e,z:s},this.sceneNode&&this.sceneNode.setPosition(t,e,s)}destroy(){this.stop(),this.element=null,this.graph=null,this.context=null,this.node=null,this.sceneNode=null,this.scene=null}loop(t){this.element.loop=!0}fadeIn(t){this.gain.gain.setValueAtTime(1e-4,this.context.getContext().currentTime),this.node||this.play(),this.gain.gain.exponentialRampToValueAtTime(this.getVolume(),this.context.getContext().currentTime+t)}fadeOut(t){this.gain.gain.setValueAtTime(this.getVolume(),this.context.getContext().currentTime),this.node&&(this.gain.gain.exponentialRampToValueAtTime(1e-4,this.context.getContext().currentTime+t),setTimeout((()=>this.stop()),1e3*t))}}var T=function(t,e,s,i){return new(s||(s=Promise))((function(a,n){function h(t){try{u(i.next(t))}catch(t){n(t)}}function r(t){try{u(i.throw(t))}catch(t){n(t)}}function u(t){var e;t.done?a(t.value):(e=t.value,e instanceof s?e:new s((function(t){t(e)}))).then(h,r)}u((i=i.apply(t,e||[])).next())}))};class D{constructor(t=new k){this.loader=t,this.environmentImpulse=null,this.context=new r,this.scene=new p(this.context),this.graph=new w(this.scene,this.context,!1),this.dataPool=new C(this.context,this.loader)}load(t,e=f.WorldSource){return T(this,void 0,void 0,(function*(){const s=yield this.dataPool.get(t);return this.createSource(e,s)}))}loadImmediate(t,e=f.WorldSource){const s=new g(this.graph,this.scene,this.context,null,e);return this.dataPool.get(t).then((t=>{s.setBuffer(t)})),s}stream(t,e=f.MasterSource){const s=new Audio(t);s.crossOrigin="anonymous",s.volume=1;return new E(this.graph,this.scene,this.context,s,e)}createSource(t,e){return new g(this.graph,this.scene,this.context,e)}setEnvironmentImpulse(t){return T(this,void 0,void 0,(function*(){if(this.environmentImpulse&&this.graph.removeEffect(this.environmentImpulse),null===t)return;const e=yield this.dataPool.get(t);this.environmentImpulse=new M(this.context,this.graph,{buffer:e}),this.graph.applyEffect(this.environmentImpulse)}))}setListenerPosition(t,e,s){this.scene.setListenerPosition(t,e,s)}setListenerOrientation(t,e){this.scene.setListenerOrientation(t,e)}clearDataPool(){this.dataPool.clear()}}class S{constructor(){this.res=new D,this.ambience=null,this.music=null,this.ambienceVolume=1,this.musicVolume=1,this.sfxVolume=1,this.previousAmbience="",this.previousMusic=""}play(t){const e=this.res.loadImmediate(t);e.setVolume(this.sfxVolume),e.play()}async setAmbience(t){if(t!==this.previousAmbience){if(this.ambience){const t=this.ambience;this.ambience=null,setTimeout((()=>t.fadeOut(6)),1500),setTimeout((()=>t.destroy()),6e3)}t&&(this.previousAmbience=t,this.ambience=this.res.stream(t,0),this.ambience.setVolume(this.ambienceVolume),this.ambience.play(),this.ambience.loop(!0),this.ambience.fadeIn(3))}}setMusic(t){if(t!==this.previousMusic){if(this.music){const t=this.music;setTimeout((()=>t.fadeOut(2)),500),setTimeout((()=>t.destroy()),2e3)}t&&(this.previousMusic=t,this.music=this.res.stream(t,1),this.music.setVolume(this.musicVolume),this.music.play(),this.music.fadeIn(2))}}setImpulse(t){this.res.setEnvironmentImpulse(t)}setMusicVolume(t){this.musicVolume=t,this.music&&this.music.setVolume(t)}setAmbienceVolume(t){this.ambienceVolume=t,this.ambience&&this.ambience.setVolume(t)}setSFXVolume(t){this.sfxVolume=t}}class A{constructor(){this.tts=new n(new i),this.history=document.getElementById("output-area"),this.sound=new S}say(t){if(""===t)return;this.sound.play("assets/scroll.wav");const e=document.createElement("p");t.split("\n").forEach((t=>{e.appendChild(document.createTextNode(t)),e.appendChild(document.createElement("br"))})),this.history.appendChild(e)}play(t){this.sound.play(t)}setAmbience(t){return this.sound.setAmbience(t)}setMusic(t){return this.sound.setMusic(t)}setImpulse(t){this.sound.setImpulse(t)}}class R{constructor(t,e){this.handler=t,this.output=e,this.echoInput=!0,this.inputField=document.getElementById("input-area"),this.history=[],this.historyCursor=0,this.init()}setEcho(t){this.echoInput=t}init(){this.inputField.addEventListener("keydown",(t=>{if("ArrowUp"===t.key)this.historyCursor>0&&(this.historyCursor--,this.inputField.value=this.history[this.historyCursor]);else if("ArrowDown"===t.key)this.historyCursor ${t}`),this.handler.doCommand(t)}}))}addToInputHistory(t){this.history.push(t),this.historyCursor=this.history.length}}const V=[[["look","l"],function(t,e){if(1==t.length)e.examineRoom();else{const s=e.getRoom(e.player.currentRoom).getItems();let i=null;for(let e of s)if(e.name.includes(t[1])){i=e;break}if(!i){const s=e.player.getInventory();for(let e of s)if(e.name.includes(t[1])){i=e;break}}i?(e.output.say(`You look at ${i.name}.`),e.output.say(i.description)):e.output.say(`I could not find a ${t[1]}.`)}}],[["use","interact"],async function(t,e){const s=e.getRoom(e.player.currentRoom).getItems();let i=null;for(let e of s)if(e.name.includes(t[1])){i=e;break}if(!i){const s=e.player.getInventory();for(let e of s)if(e.name.includes(t[1])){i=e;break}}i?await i.onUse():e.output.say(`I could not find a ${t[1]}.`)}],[["take","get"],function(t,e){const s=e.getRoom(e.player.currentRoom),i=s.getItems();let a=null;for(let e of i)if(e.name.includes(t[1])){a=e;break}a?a.takeable?(s.removeItem(a.id),e.player.addItem(a.id),e.print(`You take ${a.name}.`),a.onTake()):e.print(`You can't take ${a.name}.`):e.print(`You can't find any ${t[1]}.`)}],[["drop","put"],function(t,e){const s=e.getRoom(e.player.currentRoom),i=e.player.getInventory();let a=null;for(let e of i)if(e.name.includes(t[1])){a=e;break}a?(e.player.removeItem(a.id),s.addItem(a.id),e.print(`You set ${a.name} down on the floor.`),a.onDrop()):e.print(`You're not carrying a ${t[1]}`)}],["echo",function(t,e){"on"!=t[1]&&"off"!=t[1]?e.print("Usage: echo "):(e.setInputEcho("on"==t[1]),e.print(`Command echo is now ${t[1]}.`))}],["save",function(t,e){e.print("Saving game..."),e.save()}],["load",function(t,e){e.print("Loading game..."),e.load()}],["volume",function(t,e){if(t.length<3)return e.print("Usage: volume <0-100>");const s=parseInt(t[2]);if(s>100||s<1)return e.print("No higher than 100 and no less than 1.");if("sfx"==t[1])e.output.sound.setSFXVolume(s/100);else if("music"==t[1])e.output.sound.setMusicVolume(s/100);else{if("ambience"!=t[1])return e.print("Invalid channel. Either ambience, sfx or music is allowed.");e.output.sound.setAmbienceVolume(s/100)}e.print(`${t[1]} volume set to ${s}%`)}],[["i","inv","inventory"],function(t,e){const s=e.player.getInventory();if(s.length<1)return e.print("You're not carrying anything.");let i="You are carrying ";s.forEach(((t,e)=>{ethis.commands.set(t,e))):this.commands.set(t,e)}addCommands(t){t.forEach((t=>{this.addCommand(t[0],t[1])}))}addDefaultCommands(){this.addCommands(V)}matchDirection(t){for(let e of N)if(e[0]==t)return e[1]}}class q{constructor(t){this.context=t}save(){const t={state:this.context.state.serialize(),itemLocations:this.serializeItemLocations(),itemStates:this.serializeItemStates(),player:{currentRoom:this.context.player.currentRoom,inventory:this.context.player.inventory},volumes:{music:this.context.output.sound.musicVolume,sfx:this.context.output.sound.sfxVolume,ambience:this.context.output.sound.ambienceVolume}};localStorage.setItem("save",JSON.stringify(t))}load(){const t=JSON.parse(localStorage.getItem("save"));this.context.state.deserialize(t.state),this.deserializeItemLocations(t.itemLocations),this.deserializeItemStates(t.itemStates),this.deserializePlayer(t.player),this.context.output.sound.setSFXVolume(t.volumes.sfx),this.context.output.sound.setMusicVolume(t.volumes.music),this.context.output.sound.setAmbienceVolume(t.volumes.ambience)}serializeItemLocations(){return this.context.rooms.map((t=>[t.id,t.objects]))}deserializeItemLocations(t){t.forEach((t=>{this.context.getRoom(t[0]).objects=t[1]}))}deserializeItemStates(t){t.forEach((t=>{this.context.getItem(t[0]).state.deserialize(t[1])}))}deserializePlayer(t){this.context.move(t.currentRoom),this.context.player.inventory=t.inventory}serializeItemStates(){return this.context.items.map((t=>[t.id,t.state.serialize()]))}}class P{constructor(s=!0){this.newGame=s,this.player=new e,this.state=new t,this.rooms=[],this.items=[],this.output=new A,this.commandHandler=new L(this),this.input=new R(this.commandHandler,this.output),this.visitedRooms=new Map,this.interval=null,this.Serialization=new q(this)}print(t){this.output.say(t)}async tell(t,e){for(let s of t)this.print(s),await this.wait(e)}init(s){this.rooms=s.rooms.map((t=>(t.context=this,t))),this.items=s.items.map((t=>(t.context=this,t))),this.state=s.state||new t,this.commandHandler.addCommands(s.commands),this.player=new e,this.player.context=this,this.newGame?this.move(this.player.currentRoom):this.Serialization.load(),this.start()}advanceTick(){this.items.forEach((t=>t.onTick())),this.rooms.forEach((t=>t.onTick()))}start(){this.interval=setInterval((()=>this.advanceTick()),1e3)}stop(){clearInterval(this.interval),this.interval=null}examineRoom(){const t=this.getRoom(this.player.currentRoom);this.output.say(t.title),this.visitedRooms.get(this.player.currentRoom)||""==t.firstDescription?this.output.say(t.description):this.output.say(t.firstDescription),this.examineItems(),this.examineExits()}examineItems(){const t=this.getRoom(this.player.currentRoom).getItems();if(t.length<1)return;let e="You see ";t.forEach(((s,i)=>{i{ie.id==t))}getItem(t){return this.items.find((e=>e.id==t))}wait(t){return new Promise(((e,s)=>{setTimeout(e,t)}))}async move(t){const e=this.getRoom(this.player.currentRoom),s=this.getRoom(t);e.canExit()&&s.canEnter()&&(await e.onExit(),await s.onEnter(),this.player.currentRoom=t,this.examineRoom(),this.visitedRooms.set(t,!0))}enableCommandInput(t){this.commandHandler.enabled=t}setInputEcho(t){this.input.setEcho(t)}save(){this.Serialization.save()}load(){this.Serialization.load()}}class B{constructor(){this.id="room",this.title="A room",this.description="You see nothing special",this.firstDescription="",this.objects=[],this.exits=new Map,this.enterCallback=null,this.exitCallback=null,this.canEnterLogic=null,this.canExitLogic=null,this.tickCallback=null,this.context=null,this.music=null,this.ambience=null,this.impulse=null}async onEnter(){if(this.context.output.setMusic(this.music),this.context.output.setAmbience(this.ambience),this.context.output.setImpulse(this.impulse),this.enterCallback)return this.enterCallback(this.context)}async onExit(){if(this.exitCallback)return this.exitCallback(this.context)}canEnter(){return!this.canEnterLogic||this.canEnterLogic(this.context)}canExit(){return!this.canExitLogic||this.canExitLogic(this.context)}addExit(t,e){return this.exits.set(t,e),this}getExit(t){return this.exits.get(t)}addItem(t){this.objects.push(t)}removeItem(t){this.objects=this.objects.filter((e=>e!=t))}addEnterCallback(t){this.enterCallback=t.bind(this)}addExitCallback(t){this.exitCallback=t.bind(this)}addEnterLogic(t){this.canEnterLogic=t.bind(this)}addExitLogic(t){this.canExitLogic=t.bind(this)}addTickCallback(t){this.tickCallback=t.bind(this)}getItems(){return this.objects.map((t=>this.context.getItem(t)))}async onTick(){if(this.tickCallback)return this.tickCallback(this.context)}}class Y{constructor(){this.room=new B}withID(t){return this.room.id=t,this}withTitle(t){return this.room.title=t,this}withFirstDescription(t){return this.room.firstDescription=t,this}withDescription(t){return this.room.description=t,this}withExit(t,e){return this.room.addExit(t,e),this}withItem(t){return this.room.addItem(t),this}withEnterCallback(t){return this.room.addEnterCallback(t),this}withExitCallback(t){return this.room.addExitCallback(t),this}withEnterLogic(t){return this.room.addEnterLogic(t),this}withExitLogic(t){return this.room.addExitLogic(t),this}withTick(t){return this.room.addTickCallback(t),this}withMusic(t){return this.room.music=t,this}withAmbience(t){return this.room.ambience=t,this}withImpulse(t){return this.room.impulse=t,this}create(){return this.room}}const O=(new Y).withID("start").withTitle("A small spherical alcove").withFirstDescription("You find yourself in a small, spherical alcove. It feels cold and dark, save from a dim glow which seems to be eluminating the area from the north.\nThe surface appears to be unnaturally smooth, as if melted away using acidic means. It's warm to the touch.").withDescription("A spherical alcove. The smooth surface appears to be melted away using acidic means. There's a dim glow shining in from the north.").withExit("north","tunnel1").withEnterCallback((async function(t){if(t.state.get("start.awoken"))return;const{output:e,wait:s}=t;t.enableCommandInput(!1),await t.tell(["You slowly wake up.","you're not sure if you were ever conscious about waking up, but right now, you're clearly aware that you were previously asleep.","In fact, a lot of your thoughts seem foreign to you.","You're not sure how to feel about this.","God the headache...","OK, time to think about this.","Huh, something else you never did before.","Where are you?","You reach up and touch your head.","OK, that seems to be in order. Your antennae are still there, your mouth parts seem in tact...","Hmm. All this is strange.","No use sitting around. You get up and slowly examine your surroundings."],3e3),t.enableCommandInput(!0),t.state.set("start.awoken",!0)})).create(),U=(new Y).withID("tunnel1").withTitle("A long dark tunnel").withFirstDescription("You slowly make your way out of the little alcove, heading north into a smooth, tube-shaped tunnel.\nYou notice razor thin threads coming out of the ceiling, weaving and slithering along the length of the tunnel towards the north. Thery provide a dim glow, which must have been the light you saw before.").withDescription("A tube-shaped tunnel. Thin threads seem to exit the ceiling here, eminating a soft glow.").withExit("south","start").withExit("north","central1").create(),F=(new Y).withID("central1").withTitle("A large spherical chamber").withFirstDescription("You exit the tunnel into a large, spherical chamber.\nThere are many more threads across the walls and ceiling here, the glow enveloping you fully in its unnatural light.\nThe chamber appears to be large, able to fit hundreds of you inside.\nTo the northeast, northwest, southeast and southwest you notice large statues representing ants. Threads seem to lead right into them.").withDescription("A large, spherical chamber. Glowing threads criss-cross the walls and ceiling. Around you, statues of ants.").withExit("northwest","statue1").withExit("northeast","statue2").withExit("southwest","statue3").withExit("southeast","statue4").withExit("south","tunnel1").create(),$=(new Y).withID("statue1").withTitle("The northwestern part of the central chamber").withFirstDescription("You walk over to the northwestern part of the central chamber.\n It is almost entirely taken up by a huge ant statue. One of its six legs are extended outwards, attached to which is a small, round device.").withDescription("").withExit("southeast","central1").withItem("statue1").create(),G=(new Y).withID("statue2").withTitle("The northeastern part of the central chamber").withFirstDescription("You walk over to the northeastern part of the central chamber.\n It is almost entirely taken up by a huge ant statue. Two of its six legs are extended outwards, attached to which is a large, rectangular device.").withDescription("").withExit("southwest","central1").withItem("statue2").create(),j=(new Y).withID("statue3").withTitle("The southwestern part of the central chamber").withFirstDescription("You walk over to the southwestern part of the central chamber.\n It is almost entirely taken up by a huge ant statue. Three of its six legs are extended outwards, attached to which is a round stone tablet.").withDescription("").withExit("northeast","central1").withItem("statue3").create();class H{constructor(){this.id="item",this.name="An item",this.description="You see nothing special about this item",this.type="item",this.state=new t,this.usable=!0,this.takeable=!0,this.useCallback=null,this.takeCallback=null,this.dropCallback=null,this.tickCallback=null,this.context=null}async onUse(){if(this.useCallback)return this.useCallback(this.context)}async onTake(){if(this.takeCallback)return this.takeCallback(this.context)}async onDrop(){if(this.dropCallback)return this.dropCallback(this.context)}async onTick(){if(this.tickCallback)return this.tickCallback(this.context)}addUseCallback(t){this.useCallback=t.bind(this)}addTakeCallback(t){this.takeCallback=t.bind(this)}addDropCallback(t){this.dropCallback=t.bind(this)}addTickCallback(t){this.tickCallback=t.bind(this)}setState(t,e){return this.state.set(t,e)}getState(t){return this.state.get(t)}}class W{constructor(){this.item=new H}withID(t){return this.item.id=t,this}withName(t){return this.item.name=t,this}withDescription(t){return this.item.description=t,this}withType(t){this.item.type=t}withState(t,e){return this.item.setState(t,e),this}isUsable(t){return this.item.usable=t,this}isTakeable(t){return this.item.takeable=t,this}withUseCallback(t){return this.item.addUseCallback(t),this}withTakeCallback(t){return this.item.addTakeCallback(t),this}withDropCallback(t){return this.item.addDropCallback(t),this}withTickCallback(t){return this.item.addTickCallback(t),this}create(){return this.item}}const Q=(new W).withID("statue4").withName("a huge ant statue").withDescription("Before you is a big statue of an ant, in the process of falling over. All of its legs are bent at the joints.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You can't seem to figure out what to do with this yet.")})).create(),X=[...[O,U,F,$,G,j,Q]],J=[(new W).withID("stone").withName("a dull stone").withDescription("There is nothing remarkable about this rough, bland stone.").isTakeable(!0).isUsable(!0).withTakeCallback((async function(t){t.print(`The ${this.id} feels heavy in your hands.`)})).withDropCallback((async function(t){t.print("It bounces back and forth a little.")})).withUseCallback((async function(t){t.print(`You can't really figure out what to do with ${this.name} yet`)})).create(),(new W).withID("torch").withName("a torch").withDescription("A standard torch that provides light.").isUsable(!0).isTakeable(!0).withUseCallback((async function(t){t.print("You try to light the torch but fail.")})).create(),(new W).withID("cup").withName("a cup").withDescription("A standard coffee cup").isTakeable(!0).isUsable(!1).create(),(new W).withID("statue1").withName("a huge ant statue").withDescription("Before you stands a big ant statue. One of its six legs is extended outwards, attached to a round device.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You press the button on the round device attached to the statue's arm.");let e=t.state.get("statue1.pressed",0);e++,t.state.set("statue1.pressed",e),3==e&&(t.print("You hear a sattisfying click."),t.state.set("statues.unlocked",!0)),t.state.get("statue1.pressed")>2&&t.state.get("statue2.pressed")>1&&(t.print("You hear a low rumble somewhere deep within the bowels of the structure."),t.state.set("statues.unlocked",!0))})).create(),(new W).withID("statue2").withName("a huge ant statue").withDescription("Before you stands a big ant statue. Two of its six legs is extended outwards, attached to a rectangular device.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You press the button on the rectangular device attached to the statue's arm.");let e=t.state.get("statue2.pressed",0);e++,t.state.set("statue2.pressed",e),2==e&&t.print("You hear a sattisfying click."),t.state.get("statue1.pressed")>2&&t.state.get("statue2.pressed")>1&&(t.print("You hear a low rumble somewhere deep within the bowels of the structure."),t.state.set("statues.unlocked",!0))})).create(),(new W).withID("statue3").withName("a huge ant statue").withDescription("Before you stands a big ant statue. Three of its six legs are extended outwards, attached to a round stone tablet.").isTakeable(!1).isUsable(!0).withUseCallback((async function(t){t.print("You examine the stone tablet in the statue's hands. There appear to be symbols on it which you can make out.")})).create(),Q];async function K(t,e){e.print("You meow.")}function Z(t){new P(t).init({rooms:X,commands:[[["meow","mew"],K]],items:J})}localStorage.getItem("save")&&(document.getElementById("save-game-found").hidden=!1,document.getElementById("before-play").hidden=!0,document.getElementById("load-save-game").addEventListener("click",(()=>{document.getElementById("save-game-found").hidden=!0,document.getElementById("play-area").hidden=!1,Z(!1)})),document.getElementById("start-new-game").addEventListener("click",(()=>{document.getElementById("save-game-found").hidden=!0,document.getElementById("play-area").hidden=!1,Z(!0)}))),document.getElementById("begin").addEventListener("click",(()=>{document.getElementById("before-play").hidden=!0,document.getElementById("play-area").hidden=!1,Z(!0)}))})(); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2FtZS5qcyIsIm1hcHBpbmdzIjoibUJBQWUsTUFBTUEsRUFDakJDLGNBQ0lDLEtBQUtDLE9BQVMsSUFBSUMsSUFHdEJDLElBQUlDLEVBQUtDLEVBQWUsTUFDcEIsT0FBS0wsS0FBS0MsT0FBT0ssSUFBSUYsR0FJZEosS0FBS0MsT0FBT0UsSUFBSUMsSUFIbkJKLEtBQUtDLE9BQU9NLElBQUlILEVBQUtDLEdBQ2RBLEdBS2ZFLElBQUlILEVBQUtJLEdBQ0wsT0FBT1IsS0FBS0MsT0FBT00sSUFBSUgsRUFBS0ksR0FHaENDLE9BQU9MLEVBQUtNLEVBQVMsR0FDakIsSUFBSUMsRUFBTVgsS0FBS0csSUFBSUMsRUFBSyxHQUN4Qk8sR0FBT0QsRUFDUFYsS0FBS08sSUFBSUgsRUFBS08sR0FHbEJDLFlBQ0ksTUFBTUMsRUFBVWIsS0FBS0MsT0FBT1ksVUFDdEJDLEVBQVcsR0FDakIsSUFBSyxJQUFJQyxLQUFTRixFQUNkQyxFQUFTRSxLQUFLRCxHQUVsQixPQUFPRCxFQUdYRyxZQUFZQyxHQUNSbEIsS0FBS0MsT0FBUyxJQUFJQyxJQUFJZ0IsSUNqQ2YsTUFBTUMsRUFDakJwQixjQUNJQyxLQUFLb0IsVUFBWSxHQUNqQnBCLEtBQUtxQixZQUFjLFFBQ25CckIsS0FBS3NCLFFBQVUsS0FHbkJDLFFBQVFDLEdBQ0p4QixLQUFLb0IsVUFBVUosS0FBS1EsR0FHeEJDLFdBQVdELEdBQ1B4QixLQUFLb0IsVUFBWXBCLEtBQUtvQixVQUFVTSxRQUFRQyxHQUFTQSxHQUFRSCxJQUc3REksZUFDSSxPQUFPNUIsS0FBS29CLFVBQVVTLEtBQUtGLEdBQVMzQixLQUFLc0IsUUFBUVEsUUFBUUgsTUNoQjFELE1BQU1JLEVBQ1RDLE1BQU1DLElBR05DLFFBR0FDLFdBQVdDLEtDTlIsTUFBTUMsVUFBbUJOLEVBQzVCaEMsWUFBWXFDLEVBQVUsSUFDbEJFLFFBQ0F0QyxLQUFLdUMsUUFBVSxJQUNmdkMsS0FBS3VDLFFBQVVILEVBQVFHLFNBQVcsSUFDbEN2QyxLQUFLd0MsT0FFVEEsT0FDSXhDLEtBQUt5QyxVQUFZQyxTQUFTQyxjQUFjLE9BQ3hDM0MsS0FBS3lDLFVBQVVHLGFBQWEsWUFBYSxVQUN6QzVDLEtBQUs2QyxjQUFnQkgsU0FBU0MsY0FBYyxPQUM1QzNDLEtBQUs2QyxjQUFjRCxhQUFhLFlBQWEsVUFDN0M1QyxLQUFLeUMsVUFBVUssT0FBTzlDLEtBQUs2QyxlQUMzQkgsU0FBU0ssS0FBS0MsWUFBWWhELEtBQUt5QyxXQUMvQkMsU0FBU0ssS0FBS0UsYUFBYWpELEtBQUt5QyxVQUFXQyxTQUFTSyxLQUFLRyxZQUU3RGxCLE1BQU1DLEdBQ0ZqQyxLQUFLbUQsZUFDTCxNQUFNQyxFQUFPVixTQUFTVyxlQUFlcEIsR0FDL0JxQixFQUFPWixTQUFTQyxjQUFjLEtBQ3BDVyxFQUFLTixZQUFZSSxHQUNqQnBELEtBQUs2QyxjQUFjRyxZQUFZTSxHQUMvQkMsV0FBV3ZELEtBQUttRCxhQUFhSyxLQUFLeEQsTUFBT0EsS0FBS3VDLFNBRWxETCxPQUNJbEMsS0FBS21ELGVBRVRBLGVBQ0luRCxLQUFLNkMsY0FBY1ksVUFBWSxJQzVCaEMsTUFBTUMsVUFBcUIzQixFQUM5QmhDLFlBQVlxQyxFQUFVLElBQ2xCRSxRQUNBdEMsS0FBSzJELEtBQU92QixFQUFRdUIsTUFBUSxFQUM1QjNELEtBQUs0RCxNQUFRQyxPQUFPQyxnQkFFeEI5QixNQUFNQyxHQUNGLElBQUk4QixFQUFZLElBQUlDLHlCQUF5Qi9CLEdBQzdDOEIsRUFBVUosS0FBTzNELEtBQUsyRCxLQUN0QjNELEtBQUs0RCxNQUFNNUIsTUFBTStCLEdBRXJCN0IsT0FDSWxDLEtBQUs0RCxNQUFNSyxTQUVmOUIsV0FBV0MsR0FDUHBDLEtBQUsyRCxLQUFPdkIsRUFBUXVCLE1BQVEsR0NmN0IsTUFBTU8sRUFDVG5FLFlBQVlvRSxFQ0NULFNBQXNCL0QsRUFBTSxRQUMvQixNQUlTLFdBSkRBLEVBS08sSUFBSXNELEVBR0osSUFBSXJCLEVEVkUrQixJQUNqQnBFLEtBQUttRSxPQUFTQSxFQUVsQm5DLE1BQU1DLEdBQ0ZqQyxLQUFLbUUsT0FBT25DLE1BQU1DLEdBRXRCQyxPQUNJbEMsS0FBS21FLE9BQU9qQyxRRVBwQixJQUFJbUMsRUFBd0MsU0FBVUMsRUFBU0MsRUFBWUMsRUFBR0MsR0FFMUUsT0FBTyxJQUFLRCxJQUFNQSxFQUFJRSxXQUFVLFNBQVVDLEVBQVNDLEdBQy9DLFNBQVNDLEVBQVVyRSxHQUFTLElBQU1zRSxFQUFLTCxFQUFVTSxLQUFLdkUsSUFBVyxNQUFPd0UsR0FBS0osRUFBT0ksSUFDcEYsU0FBU0MsRUFBU3pFLEdBQVMsSUFBTXNFLEVBQUtMLEVBQWlCLE1BQUVqRSxJQUFXLE1BQU93RSxHQUFLSixFQUFPSSxJQUN2RixTQUFTRixFQUFLSSxHQUpsQixJQUFlMUUsRUFJYTBFLEVBQU9DLEtBQU9SLEVBQVFPLEVBQU8xRSxRQUoxQ0EsRUFJeUQwRSxFQUFPMUUsTUFKaERBLGFBQWlCZ0UsRUFBSWhFLEVBQVEsSUFBSWdFLEdBQUUsU0FBVUcsR0FBV0EsRUFBUW5FLE9BSVQ0RSxLQUFLUCxFQUFXSSxHQUNsR0gsR0FBTUwsRUFBWUEsRUFBVVksTUFBTWYsRUFBU0MsR0FBYyxLQUFLUSxZQUd2RCxNQUFNTyxFQUNqQnZGLGNBQ0lDLEtBQUtzQixRQUFVLElBQUlpRSxhQUV2QkMsYUFDSSxPQUFPeEYsS0FBS3NCLFFBRWhCbUUsYUFDSSxPQUFPekYsS0FBS3NCLFFBQVFtRSxhQUV4QkMsdUJBQ0ksT0FBTzFGLEtBQUtzQixRQUFRcUUsWUFFeEJDLHFCQUNJLE9BQU81RixLQUFLc0IsUUFBUXNFLHFCQUV4QkMsZ0JBQWdCM0UsR0FDWixPQUFPbUQsRUFBVXJFLFVBQU0sT0FBUSxHQUFRLFlBQ25DLGFBQWFBLEtBQUtzQixRQUFRdUUsZ0JBQWdCM0UsTUFHbEQ0RSxlQUNJLE9BQU85RixLQUFLc0IsUUFBUXdFLGVBRXhCQyx5QkFBeUJDLEdBQ3JCLE9BQU9oRyxLQUFLc0IsUUFBUXlFLHlCQUF5QkMsSUNwQzlDLE1BQU1DLEVBQ1RsRyxjQUNJQyxLQUFLa0csT0FBUyxJQUFJaEcsSUFFdEJpRyxLQUFLM0UsRUFBSU4sRUFBTyxJQUNaLElBQUlrRixFQUFLcEcsS0FBS2tHLE9BQU8vRixJQUFJcUIsR0FDekIsR0FBSzRFLEVBS0xBLEVBQUdDLFlBQVlDLFNBQVNDLElBQ3BCQSxFQUFXckYsVUFOZixDQUNJLElBQUlrRixFQUFLLElBQUlJLEVBQVVoRixHQUN2QnhCLEtBQUtrRyxPQUFPM0YsSUFBSWlCLEVBQUk0RSxJQU81QkssVUFBVWpGLEVBQUkrRSxHQUNWLElBQUlILEVBQUtwRyxLQUFLa0csT0FBTy9GLElBQUlxQixHQUNwQjRFLElBQ0RBLEVBQUssSUFBSUksRUFBVWhGLEdBQ25CeEIsS0FBS2tHLE9BQU8zRixJQUFJaUIsRUFBSTRFLElBRXhCQSxFQUFHQyxZQUFZckYsS0FBS3VGLEdBRXhCRyxZQUFZbEYsRUFBSStFLEdBQ1osR0FBSXZHLEtBQUtrRyxPQUFPNUYsSUFBSWtCLEdBQUssQ0FDckIsSUFBSTRFLEVBQUtwRyxLQUFLa0csT0FBTy9GLElBQUlxQixHQUN6QjRFLEVBQUdDLFlBQWNELEVBQUdDLFlBQVkzRSxRQUFRaUYsR0FBT0EsSUFBT0osSUFDbERILEVBQUdDLFlBQVlPLE9BQVMsR0FDeEI1RyxLQUFLa0csT0FBT1csT0FBT3JGLElBSS9Cc0YsZUFBZXRGLEdBQ1B4QixLQUFLa0csT0FBTzVGLElBQUlrQixJQUNoQnhCLEtBQUtrRyxPQUFPVyxPQUFPckYsSUFJeEIsTUFBTWdGLEVBQ1R6RyxZQUFZeUIsR0FDUnhCLEtBQUt3QixHQUFLQSxFQUNWeEIsS0FBS3FHLFlBQWMsSUN4Q1osTUFBTVUsRUFDakJoSCxZQUFZaUgsR0FDUmhILEtBQUtnSCxPQUFTLElBQUlDLGFBQWEsUUFDaEJDLElBQVhGLElBQ0FoSCxLQUFLbUgsS0FBT0gsR0FHaEJJLFFBQ0EsT0FBT3BILEtBQUtnSCxPQUFPLEdBRW5CSyxRQUNBLE9BQU9ySCxLQUFLZ0gsT0FBTyxHQUVuQk0sUUFDQSxPQUFPdEgsS0FBS2dILE9BQU8sR0FFbkJPLFFBQ0EsT0FBT3ZILEtBQUtnSCxPQUFPLEdBRW5CUSxTQUNBLE1BQU8sQ0FBQ3hILEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxJQUVwQ1MsVUFDQSxNQUFPLENBQUN6SCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLElBRXBERyxXQUNBLE1BQU8sQ0FBQ25ILEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLElBRXBFSSxNQUFFNUcsR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCNkcsTUFBRTdHLEdBQ0ZSLEtBQUtnSCxPQUFPLEdBQUt4RyxFQUVqQjhHLE1BQUU5RyxHQUNGUixLQUFLZ0gsT0FBTyxHQUFLeEcsRUFFakIrRyxNQUFFL0csR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCZ0gsT0FBR1IsR0FDSGhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBRXhCUyxRQUFJVCxHQUNKaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBRXhCRyxTQUFLSCxHQUNMaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBQ3hCaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUV4QlUsUUFDQSxPQUFPMUgsS0FBS2dILE9BQU8sR0FFbkJXLFFBQ0EsT0FBTzNILEtBQUtnSCxPQUFPLEdBRW5CWSxRQUNBLE9BQU81SCxLQUFLZ0gsT0FBTyxHQUVuQmEsUUFDQSxPQUFPN0gsS0FBS2dILE9BQU8sR0FFbkJjLFNBQ0EsTUFBTyxDQUFDOUgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLElBRXBDZSxVQUNBLE1BQU8sQ0FBQy9ILEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sSUFFcERnQixXQUNBLE1BQU8sQ0FBQ2hJLEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLElBRXBFVSxNQUFFbEgsR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCbUgsTUFBRW5ILEdBQ0ZSLEtBQUtnSCxPQUFPLEdBQUt4RyxFQUVqQm9ILE1BQUVwSCxHQUNGUixLQUFLZ0gsT0FBTyxHQUFLeEcsRUFFakJxSCxNQUFFckgsR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCc0gsT0FBR2QsR0FDSGhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBRXhCZSxRQUFJZixHQUNKaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBRXhCZ0IsU0FBS2hCLEdBQ0xoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBQ3hCaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBRTVCaUIsR0FBR0MsR0FDQyxPQUFPbEksS0FBS2dILE9BQU9rQixHQUV2QkMsUUFDSW5JLEtBQUtvSCxFQUFJLEVBQ1RwSCxLQUFLcUgsRUFBSSxFQUNUckgsS0FBS3NILEVBQUksRUFDVHRILEtBQUt1SCxFQUFJLEVBRWJhLEtBQUtDLEdBUUQsT0FQS0EsSUFDREEsRUFBTyxJQUFJdEIsR0FFZnNCLEVBQUtqQixFQUFJcEgsS0FBS29ILEVBQ2RpQixFQUFLaEIsRUFBSXJILEtBQUtxSCxFQUNkZ0IsRUFBS2YsRUFBSXRILEtBQUtzSCxFQUNkZSxFQUFLZCxFQUFJdkgsS0FBS3VILEVBQ1BjLEVBRVhDLE9BQU9ELEdBUUgsT0FQS0EsSUFDREEsRUFBT3JJLE1BRVhxSSxFQUFLakIsR0FBS3BILEtBQUtvSCxFQUNmaUIsRUFBS2hCLEdBQUtySCxLQUFLcUgsRUFDZmdCLEVBQUtmLEdBQUt0SCxLQUFLc0gsRUFDZmUsRUFBS2QsR0FBS3ZILEtBQUt1SCxFQUNSYyxFQUVYRSxPQUFPQyxFQUFRQyxFQUFZQyxNQUN2QixRQUFJQyxLQUFLQyxJQUFJNUksS0FBS29ILEVBQUlvQixFQUFPcEIsR0FBS3FCLE9BRzlCRSxLQUFLQyxJQUFJNUksS0FBS3FILEVBQUltQixFQUFPbkIsR0FBS29CLE9BRzlCRSxLQUFLQyxJQUFJNUksS0FBS3NILEVBQUlrQixFQUFPbEIsR0FBS21CLE1BRzlCRSxLQUFLQyxJQUFJNUksS0FBS3VILEVBQUlpQixFQUFPakIsR0FBS2tCLEtBS3RDN0IsU0FDSSxPQUFPK0IsS0FBS0UsS0FBSzdJLEtBQUs4SSxpQkFFMUJBLGdCQUNJLE1BQU0xQixFQUFJcEgsS0FBS29ILEVBQ1RDLEVBQUlySCxLQUFLcUgsRUFDVEMsRUFBSXRILEtBQUtzSCxFQUNUQyxFQUFJdkgsS0FBS3VILEVBQ2YsT0FBT0gsRUFBSUEsRUFBSUMsRUFBSUEsRUFBSUMsRUFBSUEsRUFBSUMsRUFBSUEsRUFFdkN3QixJQUFJUCxHQUtBLE9BSkF4SSxLQUFLb0gsR0FBS29CLEVBQU9wQixFQUNqQnBILEtBQUtxSCxHQUFLbUIsRUFBT25CLEVBQ2pCckgsS0FBS3NILEdBQUtrQixFQUFPbEIsRUFDakJ0SCxLQUFLdUgsR0FBS2lCLEVBQU9qQixFQUNWdkgsS0FFWGdKLFNBQVNSLEdBS0wsT0FKQXhJLEtBQUtvSCxHQUFLb0IsRUFBT3BCLEVBQ2pCcEgsS0FBS3FILEdBQUttQixFQUFPbkIsRUFDakJySCxLQUFLc0gsR0FBS2tCLEVBQU9sQixFQUNqQnRILEtBQUt1SCxHQUFLaUIsRUFBT2pCLEVBQ1Z2SCxLQUVYaUosU0FBU1QsR0FLTCxPQUpBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNqQnJILEtBQUtzSCxHQUFLa0IsRUFBT2xCLEVBQ2pCdEgsS0FBS3VILEdBQUtpQixFQUFPakIsRUFDVnZILEtBRVhrSixPQUFPVixHQUtILE9BSkF4SSxLQUFLb0gsR0FBS29CLEVBQU9wQixFQUNqQnBILEtBQUtxSCxHQUFLbUIsRUFBT25CLEVBQ2pCckgsS0FBS3NILEdBQUtrQixFQUFPbEIsRUFDakJ0SCxLQUFLdUgsR0FBS2lCLEVBQU9qQixFQUNWdkgsS0FFWG1KLE1BQU0zSSxFQUFPNkgsR0FRVCxPQVBLQSxJQUNEQSxFQUFPckksTUFFWHFJLEVBQUtqQixHQUFLNUcsRUFDVjZILEVBQUtoQixHQUFLN0csRUFDVjZILEVBQUtmLEdBQUs5RyxFQUNWNkgsRUFBS2QsR0FBSy9HLEVBQ0g2SCxFQUVYZSxVQUFVZixHQUNEQSxJQUNEQSxFQUFPckksTUFFWCxJQUFJNEcsRUFBUzVHLEtBQUs0RyxTQUNsQixPQUFlLElBQVhBLEVBQ081RyxLQUVJLElBQVg0RyxHQUNBeUIsRUFBS2pCLEdBQUssRUFDVmlCLEVBQUtoQixHQUFLLEVBQ1ZnQixFQUFLZixHQUFLLEVBQ1ZlLEVBQUtkLEdBQUssRUFDSGMsSUFFWHpCLEVBQVMsRUFBTUEsRUFDZnlCLEVBQUtqQixHQUFLUixFQUNWeUIsRUFBS2hCLEdBQUtULEVBQ1Z5QixFQUFLZixHQUFLVixFQUNWeUIsRUFBS2QsR0FBS1gsRUFDSHlCLEdBRVhnQixhQUFhQyxFQUFRakIsR0FJakIsT0FIS0EsSUFDREEsRUFBT3JJLE1BRUpzSixFQUFPQyxhQUFhdkosS0FBTXFJLEdBRXJDbUIsV0FBV2hCLEVBQVFpQixFQUFTQyxFQUFNckIsR0FROUIsT0FQS0EsSUFDREEsRUFBTyxJQUFJdEIsR0FFZnNCLEVBQUtqQixFQUFJb0IsRUFBT3BCLEVBQUlzQyxHQUFRRCxFQUFRckMsRUFBSW9CLEVBQU9wQixHQUMvQ2lCLEVBQUtoQixFQUFJbUIsRUFBT25CLEVBQUlxQyxHQUFRRCxFQUFRcEMsRUFBSW1CLEVBQU9uQixHQUMvQ2dCLEVBQUtmLEVBQUlrQixFQUFPbEIsRUFBSW9DLEdBQVFELEVBQVFuQyxFQUFJa0IsRUFBT2xCLEdBQy9DZSxFQUFLZCxFQUFJaUIsRUFBT2pCLEVBQUltQyxHQUFRRCxFQUFRbEMsRUFBSWlCLEVBQU9qQixHQUN4Q2MsRUFFWG1CLFdBQVdoQixFQUFRaUIsRUFBU3BCLEdBUXhCLE9BUEtBLElBQ0RBLEVBQU8sSUFBSXRCLEdBRWZzQixFQUFLakIsRUFBSW9CLEVBQU9wQixFQUFJcUMsRUFBUXJDLEVBQzVCaUIsRUFBS2hCLEVBQUltQixFQUFPbkIsRUFBSW9DLEVBQVFwQyxFQUM1QmdCLEVBQUtmLEVBQUlrQixFQUFPbEIsRUFBSW1DLEVBQVFuQyxFQUM1QmUsRUFBS2QsRUFBSWlCLEVBQU9qQixFQUFJa0MsRUFBUWxDLEVBQ3JCYyxFQUVYbUIsa0JBQWtCaEIsRUFBUWlCLEVBQVNwQixHQVEvQixPQVBLQSxJQUNEQSxFQUFPLElBQUl0QixHQUVmc0IsRUFBS2pCLEVBQUlvQixFQUFPcEIsRUFBSXFDLEVBQVFyQyxFQUM1QmlCLEVBQUtoQixFQUFJbUIsRUFBT25CLEVBQUlvQyxFQUFRcEMsRUFDNUJnQixFQUFLZixFQUFJa0IsRUFBT2xCLEVBQUltQyxFQUFRbkMsRUFDNUJlLEVBQUtkLEVBQUlpQixFQUFPakIsRUFBSWtDLEVBQVFsQyxFQUNyQmMsRUFFWG1CLGVBQWVoQixFQUFRaUIsRUFBU3BCLEdBUTVCLE9BUEtBLElBQ0RBLEVBQU8sSUFBSXRCLEdBRWZzQixFQUFLakIsRUFBSW9CLEVBQU9wQixFQUFJcUMsRUFBUXJDLEVBQzVCaUIsRUFBS2hCLEVBQUltQixFQUFPbkIsRUFBSW9DLEVBQVFwQyxFQUM1QmdCLEVBQUtmLEVBQUlrQixFQUFPbEIsRUFBSW1DLEVBQVFuQyxFQUM1QmUsRUFBS2QsRUFBSWlCLEVBQU9qQixFQUFJa0MsRUFBUWxDLEVBQ3JCYyxFQUVYbUIsZ0JBQWdCaEIsRUFBUWlCLEVBQVNwQixHQVE3QixPQVBLQSxJQUNEQSxFQUFPLElBQUl0QixHQUVmc0IsRUFBS2pCLEVBQUlvQixFQUFPcEIsRUFBSXFDLEVBQVFyQyxFQUM1QmlCLEVBQUtoQixFQUFJbUIsRUFBT25CLEVBQUlvQyxFQUFRcEMsRUFDNUJnQixFQUFLZixFQUFJa0IsRUFBT2xCLEVBQUltQyxFQUFRbkMsRUFDNUJlLEVBQUtkLEVBQUlpQixFQUFPakIsRUFBSWtDLEVBQVFsQyxFQUNyQmMsR0FHZnRCLEVBQUs0QyxLQUFPLElBQUk1QyxFQUFLLENBQUMsRUFBRyxFQUFHLEVBQUcsSUFDL0JBLEVBQUs2QyxJQUFNLElBQUk3QyxFQUFLLENBQUMsRUFBRyxFQUFHLEVBQUcsSUNoUmYsTUFBTThDLEVBQ2pCOUosWUFBWWlILEdBQ1JoSCxLQUFLZ0gsT0FBUyxJQUFJQyxhQUFhLFNBQ2hCQyxJQUFYRixHQUNBaEgsS0FBS3dDLEtBQUt3RSxHQUdsQmlCLEdBQUdDLEdBQ0MsT0FBT2xJLEtBQUtnSCxPQUFPa0IsR0FFdkIxRixLQUFLd0UsR0FDRCxJQUFLLElBQUk4QyxFQUFJLEVBQUdBLEVBQUksR0FBSUEsSUFDcEI5SixLQUFLZ0gsT0FBTzhDLEdBQUs5QyxFQUFPOEMsR0FFNUIsT0FBTzlKLEtBRVhtSSxRQUNJLElBQUssSUFBSTJCLEVBQUksRUFBR0EsRUFBSSxHQUFJQSxJQUNwQjlKLEtBQUtnSCxPQUFPOEMsR0FBSyxFQUd6QjFCLEtBQUtDLEdBQ0lBLElBQ0RBLEVBQU8sSUFBSXdCLEdBRWYsSUFBSyxJQUFJQyxFQUFJLEVBQUdBLEVBQUksR0FBSUEsSUFDcEJ6QixFQUFLckIsT0FBTzhDLEdBQUs5SixLQUFLZ0gsT0FBTzhDLEdBRWpDLE9BQU96QixFQUVYMEIsTUFDSSxNQUFNN0ksRUFBTyxHQUNiLElBQUssSUFBSTRJLEVBQUksRUFBR0EsRUFBSSxHQUFJQSxJQUNwQjVJLEVBQUs0SSxHQUFLOUosS0FBS2dILE9BQU84QyxHQUUxQixPQUFPNUksRUFFWDhJLElBQUk5QixHQUNBLE1BQU8sQ0FDSGxJLEtBQUtnSCxPQUFlLEVBQVJrQixFQUFZLEdBQ3hCbEksS0FBS2dILE9BQWUsRUFBUmtCLEVBQVksR0FDeEJsSSxLQUFLZ0gsT0FBZSxFQUFSa0IsRUFBWSxHQUN4QmxJLEtBQUtnSCxPQUFlLEVBQVJrQixFQUFZLElBR2hDK0IsSUFBSS9CLEdBQ0EsTUFBTyxDQUNIbEksS0FBS2dILE9BQU9rQixHQUNabEksS0FBS2dILE9BQU9rQixFQUFRLEdBQ3BCbEksS0FBS2dILE9BQU9rQixFQUFRLEdBQ3BCbEksS0FBS2dILE9BQU9rQixFQUFRLEtBRzVCSyxPQUFPZSxFQUFRYixFQUFZQyxNQUN2QixJQUFLLElBQUlvQixFQUFJLEVBQUdBLEVBQUksR0FBSUEsSUFDcEIsR0FBSW5CLEtBQUtDLElBQUk1SSxLQUFLZ0gsT0FBTzhDLEdBQUtSLEVBQU9yQixHQUFHNkIsSUFBTXJCLEVBQzFDLE9BQU8sRUFHZixPQUFPLEVBRVh5QixjQUNJLE1BQU1DLEVBQU1uSyxLQUFLZ0gsT0FBTyxHQUNsQm9ELEVBQU1wSyxLQUFLZ0gsT0FBTyxHQUNsQnFELEVBQU1ySyxLQUFLZ0gsT0FBTyxHQUNsQnNELEVBQU10SyxLQUFLZ0gsT0FBTyxHQUNsQnVELEVBQU12SyxLQUFLZ0gsT0FBTyxHQUNsQndELEVBQU14SyxLQUFLZ0gsT0FBTyxHQUNsQnlELEVBQU16SyxLQUFLZ0gsT0FBTyxHQUNsQjBELEVBQU0xSyxLQUFLZ0gsT0FBTyxHQUNsQjJELEVBQU0zSyxLQUFLZ0gsT0FBTyxHQUNsQjRELEVBQU01SyxLQUFLZ0gsT0FBTyxHQUNsQjZELEVBQU03SyxLQUFLZ0gsT0FBTyxJQUNsQjhELEVBQU05SyxLQUFLZ0gsT0FBTyxJQUNsQitELEVBQU0vSyxLQUFLZ0gsT0FBTyxJQUNsQmdFLEVBQU1oTCxLQUFLZ0gsT0FBTyxJQUNsQmlFLEVBQU1qTCxLQUFLZ0gsT0FBTyxJQUNsQmtFLEVBQU1sTCxLQUFLZ0gsT0FBTyxJQWF4QixPQVpjbUQsRUFBTUssRUFBTUosRUFBTUcsSUFXbEJNLEVBQU1LLEVBQU1KLEVBQU1HLElBVmxCZCxFQUFNTSxFQUFNSixFQUFNRSxJQVNsQkssRUFBTU0sRUFBTUosRUFBTUUsSUFSbEJiLEVBQU1PLEVBQU1KLEVBQU1DLElBT2xCSyxFQUFNSyxFQUFNSixFQUFNRyxJQU5sQlosRUFBTUssRUFBTUosRUFBTUcsSUFLbEJHLEVBQU1PLEVBQU1KLEVBQU1DLElBSmxCWCxFQUFNTSxFQUFNSixFQUFNRSxJQUdsQkcsRUFBTU0sRUFBTUosRUFBTUUsSUFGbEJWLEVBQU1LLEVBQU1KLEVBQU1HLElBQ2xCRSxFQUFNSyxFQUFNSixFQUFNRyxHQWFwQ0ksY0FpQkksT0FoQkFuTCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sR0FBSyxFQUNqQmhILEtBQUtnSCxPQUFPLEdBQUssRUFDakJoSCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sR0FBSyxFQUNqQmhILEtBQUtnSCxPQUFPLEdBQUssRUFDakJoSCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sR0FBSyxFQUNqQmhILEtBQUtnSCxPQUFPLEdBQUssRUFDakJoSCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sSUFBTSxFQUNsQmhILEtBQUtnSCxPQUFPLElBQU0sRUFDbEJoSCxLQUFLZ0gsT0FBTyxJQUFNLEVBQ2xCaEgsS0FBS2dILE9BQU8sSUFBTSxFQUNsQmhILEtBQUtnSCxPQUFPLElBQU0sRUFDbEJoSCxLQUFLZ0gsT0FBTyxJQUFNLEVBQ1hoSCxLQUVYb0wsWUFDSSxNQUFNQyxFQUFTckwsS0FBS2dILE9BQU8sR0FDckJzRSxFQUFTdEwsS0FBS2dILE9BQU8sR0FDckJ1RSxFQUFTdkwsS0FBS2dILE9BQU8sR0FDckJ3RSxFQUFTeEwsS0FBS2dILE9BQU8sR0FDckJ5RSxFQUFTekwsS0FBS2dILE9BQU8sR0FDckIwRSxFQUFTMUwsS0FBS2dILE9BQU8sSUFhM0IsT0FaQWhILEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxHQUM3QmhILEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxHQUM3QmhILEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxJQUM3QmhILEtBQUtnSCxPQUFPLEdBQUtxRSxFQUNqQnJMLEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxHQUM3QmhILEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxJQUM3QmhILEtBQUtnSCxPQUFPLEdBQUtzRSxFQUNqQnRMLEtBQUtnSCxPQUFPLEdBQUt3RSxFQUNqQnhMLEtBQUtnSCxPQUFPLElBQU1oSCxLQUFLZ0gsT0FBTyxJQUM5QmhILEtBQUtnSCxPQUFPLElBQU11RSxFQUNsQnZMLEtBQUtnSCxPQUFPLElBQU15RSxFQUNsQnpMLEtBQUtnSCxPQUFPLElBQU0wRSxFQUNYMUwsS0FFWDJMLFVBQ0ksTUFBTXhCLEVBQU1uSyxLQUFLZ0gsT0FBTyxHQUNsQm9ELEVBQU1wSyxLQUFLZ0gsT0FBTyxHQUNsQnFELEVBQU1ySyxLQUFLZ0gsT0FBTyxHQUNsQnNELEVBQU10SyxLQUFLZ0gsT0FBTyxHQUNsQnVELEVBQU12SyxLQUFLZ0gsT0FBTyxHQUNsQndELEVBQU14SyxLQUFLZ0gsT0FBTyxHQUNsQnlELEVBQU16SyxLQUFLZ0gsT0FBTyxHQUNsQjBELEVBQU0xSyxLQUFLZ0gsT0FBTyxHQUNsQjJELEVBQU0zSyxLQUFLZ0gsT0FBTyxHQUNsQjRELEVBQU01SyxLQUFLZ0gsT0FBTyxHQUNsQjZELEVBQU03SyxLQUFLZ0gsT0FBTyxJQUNsQjhELEVBQU05SyxLQUFLZ0gsT0FBTyxJQUNsQitELEVBQU0vSyxLQUFLZ0gsT0FBTyxJQUNsQmdFLEVBQU1oTCxLQUFLZ0gsT0FBTyxJQUNsQmlFLEVBQU1qTCxLQUFLZ0gsT0FBTyxJQUNsQmtFLEVBQU1sTCxLQUFLZ0gsT0FBTyxJQUNsQjRFLEVBQVF6QixFQUFNSyxFQUFNSixFQUFNRyxFQUMxQnNCLEVBQVExQixFQUFNTSxFQUFNSixFQUFNRSxFQUMxQnVCLEVBQVEzQixFQUFNTyxFQUFNSixFQUFNQyxFQUMxQndCLEVBQVEzQixFQUFNSyxFQUFNSixFQUFNRyxFQUMxQndCLEVBQVE1QixFQUFNTSxFQUFNSixFQUFNRSxFQUMxQnlCLEVBQVE1QixFQUFNSyxFQUFNSixFQUFNRyxFQUMxQnlCLEVBQVF2QixFQUFNSyxFQUFNSixFQUFNRyxFQUMxQm9CLEVBQVF4QixFQUFNTSxFQUFNSixFQUFNRSxFQUMxQnFCLEVBQVF6QixFQUFNTyxFQUFNSixFQUFNQyxFQUMxQnNCLEVBQVF6QixFQUFNSyxFQUFNSixFQUFNRyxFQUMxQnNCLEVBQVExQixFQUFNTSxFQUFNSixFQUFNRSxFQUMxQnVCLEVBQVExQixFQUFNSyxFQUFNSixFQUFNRyxFQUNoQyxJQUFJdUIsRUFBTVosRUFBUVcsRUFDZFYsRUFBUVMsRUFDUlIsRUFBUU8sRUFDUk4sRUFBUUssRUFDUkosRUFBUUcsRUFDUkYsRUFBUUMsRUFDWixPQUFLTSxHQUdMQSxFQUFNLEVBQU1BLEVBQ1p4TSxLQUFLZ0gsT0FBTyxJQUFNd0QsRUFBTStCLEVBQVE5QixFQUFNNkIsRUFBUTVCLEVBQU0yQixHQUFTRyxFQUM3RHhNLEtBQUtnSCxPQUFPLEtBQU9vRCxFQUFNbUMsRUFBUWxDLEVBQU1pQyxFQUFRaEMsRUFBTStCLEdBQVNHLEVBQzlEeE0sS0FBS2dILE9BQU8sSUFBTWdFLEVBQU1pQixFQUFRaEIsRUFBTWUsRUFBUWQsRUFBTWEsR0FBU1MsRUFDN0R4TSxLQUFLZ0gsT0FBTyxLQUFPNEQsRUFBTXFCLEVBQVFwQixFQUFNbUIsRUFBUWxCLEVBQU1pQixHQUFTUyxFQUM5RHhNLEtBQUtnSCxPQUFPLEtBQU91RCxFQUFNZ0MsRUFBUTlCLEVBQU0yQixFQUFRMUIsRUFBTXlCLEdBQVNLLEVBQzlEeE0sS0FBS2dILE9BQU8sSUFBTW1ELEVBQU1vQyxFQUFRbEMsRUFBTStCLEVBQVE5QixFQUFNNkIsR0FBU0ssRUFDN0R4TSxLQUFLZ0gsT0FBTyxLQUFPK0QsRUFBTWtCLEVBQVFoQixFQUFNYSxFQUFRWixFQUFNVyxHQUFTVyxFQUM5RHhNLEtBQUtnSCxPQUFPLElBQU0yRCxFQUFNc0IsRUFBUXBCLEVBQU1pQixFQUFRaEIsRUFBTWUsR0FBU1csRUFDN0R4TSxLQUFLZ0gsT0FBTyxJQUFNdUQsRUFBTStCLEVBQVE5QixFQUFNNEIsRUFBUTFCLEVBQU13QixHQUFTTSxFQUM3RHhNLEtBQUtnSCxPQUFPLEtBQU9tRCxFQUFNbUMsRUFBUWxDLEVBQU1nQyxFQUFROUIsRUFBTTRCLEdBQVNNLEVBQzlEeE0sS0FBS2dILE9BQU8sS0FBTytELEVBQU1pQixFQUFRaEIsRUFBTWMsRUFBUVosRUFBTVUsR0FBU1ksRUFDOUR4TSxLQUFLZ0gsT0FBTyxNQUFRMkQsRUFBTXFCLEVBQVFwQixFQUFNa0IsRUFBUWhCLEVBQU1jLEdBQVNZLEVBQy9EeE0sS0FBS2dILE9BQU8sTUFBUXVELEVBQU04QixFQUFRN0IsRUFBTTJCLEVBQVExQixFQUFNeUIsR0FBU00sRUFDL0R4TSxLQUFLZ0gsT0FBTyxLQUFPbUQsRUFBTWtDLEVBQVFqQyxFQUFNK0IsRUFBUTlCLEVBQU02QixHQUFTTSxFQUM5RHhNLEtBQUtnSCxPQUFPLE1BQVErRCxFQUFNZ0IsRUFBUWYsRUFBTWEsRUFBUVosRUFBTVcsR0FBU1ksRUFDL0R4TSxLQUFLZ0gsT0FBTyxLQUFPMkQsRUFBTW9CLEVBQVFuQixFQUFNaUIsRUFBUWhCLEVBQU1lLEdBQVNZLEVBQ3ZEeE0sTUFuQkksS0FxQmZpSixTQUFTSyxHQUNMLE1BQU1hLEVBQU1uSyxLQUFLZ0gsT0FBTyxHQUNsQm9ELEVBQU1wSyxLQUFLZ0gsT0FBTyxHQUNsQnFELEVBQU1ySyxLQUFLZ0gsT0FBTyxHQUNsQnNELEVBQU10SyxLQUFLZ0gsT0FBTyxHQUNsQnVELEVBQU12SyxLQUFLZ0gsT0FBTyxHQUNsQndELEVBQU14SyxLQUFLZ0gsT0FBTyxHQUNsQnlELEVBQU16SyxLQUFLZ0gsT0FBTyxHQUNsQjBELEVBQU0xSyxLQUFLZ0gsT0FBTyxHQUNsQjJELEVBQU0zSyxLQUFLZ0gsT0FBTyxHQUNsQjRELEVBQU01SyxLQUFLZ0gsT0FBTyxHQUNsQjZELEVBQU03SyxLQUFLZ0gsT0FBTyxJQUNsQjhELEVBQU05SyxLQUFLZ0gsT0FBTyxJQUNsQitELEVBQU0vSyxLQUFLZ0gsT0FBTyxJQUNsQmdFLEVBQU1oTCxLQUFLZ0gsT0FBTyxJQUNsQmlFLEVBQU1qTCxLQUFLZ0gsT0FBTyxJQUNsQmtFLEVBQU1sTCxLQUFLZ0gsT0FBTyxJQUN4QixJQUFJeUYsRUFBS25ELEVBQU9yQixHQUFHLEdBQ2Z5RSxFQUFLcEQsRUFBT3JCLEdBQUcsR0FDZjBFLEVBQUtyRCxFQUFPckIsR0FBRyxHQUNmMkUsRUFBS3RELEVBQU9yQixHQUFHLEdBNkJuQixPQTVCQWpJLEtBQUtnSCxPQUFPLEdBQUt5RixFQUFLdEMsRUFBTXVDLEVBQUtuQyxFQUFNb0MsRUFBS2hDLEVBQU1pQyxFQUFLN0IsRUFDdkQvSyxLQUFLZ0gsT0FBTyxHQUFLeUYsRUFBS3JDLEVBQU1zQyxFQUFLbEMsRUFBTW1DLEVBQUsvQixFQUFNZ0MsRUFBSzVCLEVBQ3ZEaEwsS0FBS2dILE9BQU8sR0FBS3lGLEVBQUtwQyxFQUFNcUMsRUFBS2pDLEVBQU1rQyxFQUFLOUIsRUFBTStCLEVBQUszQixFQUN2RGpMLEtBQUtnSCxPQUFPLEdBQUt5RixFQUFLbkMsRUFBTW9DLEVBQUtoQyxFQUFNaUMsRUFBSzdCLEVBQU04QixFQUFLMUIsRUFDdkR1QixFQUFLbkQsRUFBT3JCLEdBQUcsR0FDZnlFLEVBQUtwRCxFQUFPckIsR0FBRyxHQUNmMEUsRUFBS3JELEVBQU9yQixHQUFHLEdBQ2YyRSxFQUFLdEQsRUFBT3JCLEdBQUcsR0FDZmpJLEtBQUtnSCxPQUFPLEdBQUt5RixFQUFLdEMsRUFBTXVDLEVBQUtuQyxFQUFNb0MsRUFBS2hDLEVBQU1pQyxFQUFLN0IsRUFDdkQvSyxLQUFLZ0gsT0FBTyxHQUFLeUYsRUFBS3JDLEVBQU1zQyxFQUFLbEMsRUFBTW1DLEVBQUsvQixFQUFNZ0MsRUFBSzVCLEVBQ3ZEaEwsS0FBS2dILE9BQU8sR0FBS3lGLEVBQUtwQyxFQUFNcUMsRUFBS2pDLEVBQU1rQyxFQUFLOUIsRUFBTStCLEVBQUszQixFQUN2RGpMLEtBQUtnSCxPQUFPLEdBQUt5RixFQUFLbkMsRUFBTW9DLEVBQUtoQyxFQUFNaUMsRUFBSzdCLEVBQU04QixFQUFLMUIsRUFDdkR1QixFQUFLbkQsRUFBT3JCLEdBQUcsR0FDZnlFLEVBQUtwRCxFQUFPckIsR0FBRyxHQUNmMEUsRUFBS3JELEVBQU9yQixHQUFHLElBQ2YyRSxFQUFLdEQsRUFBT3JCLEdBQUcsSUFDZmpJLEtBQUtnSCxPQUFPLEdBQUt5RixFQUFLdEMsRUFBTXVDLEVBQUtuQyxFQUFNb0MsRUFBS2hDLEVBQU1pQyxFQUFLN0IsRUFDdkQvSyxLQUFLZ0gsT0FBTyxHQUFLeUYsRUFBS3JDLEVBQU1zQyxFQUFLbEMsRUFBTW1DLEVBQUsvQixFQUFNZ0MsRUFBSzVCLEVBQ3ZEaEwsS0FBS2dILE9BQU8sSUFBTXlGLEVBQUtwQyxFQUFNcUMsRUFBS2pDLEVBQU1rQyxFQUFLOUIsRUFBTStCLEVBQUszQixFQUN4RGpMLEtBQUtnSCxPQUFPLElBQU15RixFQUFLbkMsRUFBTW9DLEVBQUtoQyxFQUFNaUMsRUFBSzdCLEVBQU04QixFQUFLMUIsRUFDeER1QixFQUFLbkQsRUFBT3JCLEdBQUcsSUFDZnlFLEVBQUtwRCxFQUFPckIsR0FBRyxJQUNmMEUsRUFBS3JELEVBQU9yQixHQUFHLElBQ2YyRSxFQUFLdEQsRUFBT3JCLEdBQUcsSUFDZmpJLEtBQUtnSCxPQUFPLElBQU15RixFQUFLdEMsRUFBTXVDLEVBQUtuQyxFQUFNb0MsRUFBS2hDLEVBQU1pQyxFQUFLN0IsRUFDeEQvSyxLQUFLZ0gsT0FBTyxJQUFNeUYsRUFBS3JDLEVBQU1zQyxFQUFLbEMsRUFBTW1DLEVBQUsvQixFQUFNZ0MsRUFBSzVCLEVBQ3hEaEwsS0FBS2dILE9BQU8sSUFBTXlGLEVBQUtwQyxFQUFNcUMsRUFBS2pDLEVBQU1rQyxFQUFLOUIsRUFBTStCLEVBQUszQixFQUN4RGpMLEtBQUtnSCxPQUFPLElBQU15RixFQUFLbkMsRUFBTW9DLEVBQUtoQyxFQUFNaUMsRUFBSzdCLEVBQU04QixFQUFLMUIsRUFDakRsTCxLQUVYNk0sYUFBYXJFLEdBQ1QsTUFBTXBCLEVBQUlvQixFQUFPcEIsRUFDWEMsRUFBSW1CLEVBQU9uQixFQUNYQyxFQUFJa0IsRUFBT2xCLEVBQ2pCLE9BQU8sSUFBSXdGLEVBQUssQ0FDWjlNLEtBQUtnSCxPQUFPLEdBQUtJLEVBQ2JwSCxLQUFLZ0gsT0FBTyxHQUFLSyxFQUNqQnJILEtBQUtnSCxPQUFPLEdBQUtNLEVBQ2pCdEgsS0FBS2dILE9BQU8sSUFDaEJoSCxLQUFLZ0gsT0FBTyxHQUFLSSxFQUNicEgsS0FBS2dILE9BQU8sR0FBS0ssRUFDakJySCxLQUFLZ0gsT0FBTyxHQUFLTSxFQUNqQnRILEtBQUtnSCxPQUFPLElBQ2hCaEgsS0FBS2dILE9BQU8sR0FBS0ksRUFDYnBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQ2pCckgsS0FBS2dILE9BQU8sSUFBTU0sRUFDbEJ0SCxLQUFLZ0gsT0FBTyxNQUd4QnVDLGFBQWFmLEVBQVFILEdBQ1pBLElBQ0RBLEVBQU8sSUFBSXRCLEdBRWYsTUFBTUssRUFBSW9CLEVBQU9wQixFQUNYQyxFQUFJbUIsRUFBT25CLEVBQ1hDLEVBQUlrQixFQUFPbEIsRUFDWEMsRUFBSWlCLEVBQU9qQixFQXFCakIsT0FwQkFjLEVBQUtqQixFQUNEcEgsS0FBS2dILE9BQU8sR0FBS0ksRUFDYnBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQ2pCckgsS0FBS2dILE9BQU8sR0FBS00sRUFDakJ0SCxLQUFLZ0gsT0FBTyxJQUFNTyxFQUMxQmMsRUFBS2hCLEVBQ0RySCxLQUFLZ0gsT0FBTyxHQUFLSSxFQUNicEgsS0FBS2dILE9BQU8sR0FBS0ssRUFDakJySCxLQUFLZ0gsT0FBTyxHQUFLTSxFQUNqQnRILEtBQUtnSCxPQUFPLElBQU1PLEVBQzFCYyxFQUFLZixFQUNEdEgsS0FBS2dILE9BQU8sR0FBS0ksRUFDYnBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQ2pCckgsS0FBS2dILE9BQU8sSUFBTU0sRUFDbEJ0SCxLQUFLZ0gsT0FBTyxJQUFNTyxFQUMxQmMsRUFBS2QsRUFDRHZILEtBQUtnSCxPQUFPLEdBQUtJLEVBQ2JwSCxLQUFLZ0gsT0FBTyxHQUFLSyxFQUNqQnJILEtBQUtnSCxPQUFPLElBQU1NLEVBQ2xCdEgsS0FBS2dILE9BQU8sSUFBTU8sRUFDbkJjLEVBRVgwRSxTQUNJLE9BQU8sSUFBSUMsRUFBSyxDQUNaaE4sS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxHQUNaaEgsS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxHQUNaaEgsS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxNQUdwQmlHLGdCQUNJLE1BQU05QyxFQUFNbkssS0FBS2dILE9BQU8sR0FDbEJvRCxFQUFNcEssS0FBS2dILE9BQU8sR0FDbEJxRCxFQUFNckssS0FBS2dILE9BQU8sR0FDbEJ1RCxFQUFNdkssS0FBS2dILE9BQU8sR0FDbEJ3RCxFQUFNeEssS0FBS2dILE9BQU8sR0FDbEJ5RCxFQUFNekssS0FBS2dILE9BQU8sR0FDbEIyRCxFQUFNM0ssS0FBS2dILE9BQU8sR0FDbEI0RCxFQUFNNUssS0FBS2dILE9BQU8sR0FDbEI2RCxFQUFNN0ssS0FBS2dILE9BQU8sSUFDbEI2RSxFQUFRaEIsRUFBTUwsRUFBTUMsRUFBTUcsRUFDMUIyQixHQUFTMUIsRUFBTU4sRUFBTUUsRUFBTUUsRUFDM0J1QyxFQUFRdEMsRUFBTUwsRUFBTUMsRUFBTUcsRUFDaEMsSUFBSTZCLEVBQU1yQyxFQUFNMEIsRUFBUXpCLEVBQU1tQyxFQUFRbEMsRUFBTTZDLEVBQzVDLE9BQUtWLEdBR0xBLEVBQU0sRUFBTUEsRUFDTCxJQUFJUSxFQUFLLENBQ1puQixFQUFRVyxJQUNOM0IsRUFBTVQsRUFBTUMsRUFBTU8sR0FBTzRCLEdBQzFCL0IsRUFBTUwsRUFBTUMsRUFBTUcsR0FBT2dDLEVBQzFCRCxFQUFRQyxHQUNQM0IsRUFBTVYsRUFBTUUsRUFBTU0sR0FBTzZCLElBQ3hCL0IsRUFBTU4sRUFBTUUsRUFBTUUsR0FBT2lDLEVBQzNCVSxFQUFRVixJQUNONUIsRUFBTVQsRUFBTUMsRUFBTU8sR0FBTzZCLEdBQzFCaEMsRUFBTUwsRUFBTUMsRUFBTUcsR0FBT2lDLEtBWm5CLEtBZWZXLFVBQVUzRSxHQUNOLE1BQU1wQixFQUFJb0IsRUFBT3BCLEVBQ1hDLEVBQUltQixFQUFPbkIsRUFDWEMsRUFBSWtCLEVBQU9sQixFQVNqQixPQVJBdEgsS0FBS2dILE9BQU8sS0FDUmhILEtBQUtnSCxPQUFPLEdBQUtJLEVBQUlwSCxLQUFLZ0gsT0FBTyxHQUFLSyxFQUFJckgsS0FBS2dILE9BQU8sR0FBS00sRUFDL0R0SCxLQUFLZ0gsT0FBTyxLQUNSaEgsS0FBS2dILE9BQU8sR0FBS0ksRUFBSXBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQUlySCxLQUFLZ0gsT0FBTyxHQUFLTSxFQUMvRHRILEtBQUtnSCxPQUFPLEtBQ1JoSCxLQUFLZ0gsT0FBTyxHQUFLSSxFQUFJcEgsS0FBS2dILE9BQU8sR0FBS0ssRUFBSXJILEtBQUtnSCxPQUFPLElBQU1NLEVBQ2hFdEgsS0FBS2dILE9BQU8sS0FDUmhILEtBQUtnSCxPQUFPLEdBQUtJLEVBQUlwSCxLQUFLZ0gsT0FBTyxHQUFLSyxFQUFJckgsS0FBS2dILE9BQU8sSUFBTU0sRUFDekR0SCxLQUVYbUosTUFBTVgsR0FDRixNQUFNcEIsRUFBSW9CLEVBQU9wQixFQUNYQyxFQUFJbUIsRUFBT25CLEVBQ1hDLEVBQUlrQixFQUFPbEIsRUFhakIsT0FaQXRILEtBQUtnSCxPQUFPLElBQU1JLEVBQ2xCcEgsS0FBS2dILE9BQU8sSUFBTUksRUFDbEJwSCxLQUFLZ0gsT0FBTyxJQUFNSSxFQUNsQnBILEtBQUtnSCxPQUFPLElBQU1JLEVBQ2xCcEgsS0FBS2dILE9BQU8sSUFBTUssRUFDbEJySCxLQUFLZ0gsT0FBTyxJQUFNSyxFQUNsQnJILEtBQUtnSCxPQUFPLElBQU1LLEVBQ2xCckgsS0FBS2dILE9BQU8sSUFBTUssRUFDbEJySCxLQUFLZ0gsT0FBTyxJQUFNTSxFQUNsQnRILEtBQUtnSCxPQUFPLElBQU1NLEVBQ2xCdEgsS0FBS2dILE9BQU8sS0FBT00sRUFDbkJ0SCxLQUFLZ0gsT0FBTyxLQUFPTSxFQUNadEgsS0FFWG9OLE9BQU9DLEVBQU9DLEdBQ1YsSUFBSWxHLEVBQUlrRyxFQUFLbEcsRUFDVEMsRUFBSWlHLEVBQUtqRyxFQUNUQyxFQUFJZ0csRUFBS2hHLEVBQ1RWLEVBQVMrQixLQUFLRSxLQUFLekIsRUFBSUEsRUFBSUMsRUFBSUEsRUFBSUMsRUFBSUEsR0FDM0MsSUFBS1YsRUFDRCxPQUFPLEtBRUksSUFBWEEsSUFDQUEsRUFBUyxFQUFJQSxFQUNiUSxHQUFLUixFQUNMUyxHQUFLVCxFQUNMVSxHQUFLVixHQUVULE1BQU0yRyxFQUFJNUUsS0FBSzZFLElBQUlILEdBQ2JJLEVBQUk5RSxLQUFLK0UsSUFBSUwsR0FDYk0sRUFBSSxFQUFNRixFQUNWdEQsRUFBTW5LLEtBQUtnSCxPQUFPLEdBQ2xCb0QsRUFBTXBLLEtBQUtnSCxPQUFPLEdBQ2xCcUQsRUFBTXJLLEtBQUtnSCxPQUFPLEdBQ2xCc0QsRUFBTXRLLEtBQUtnSCxPQUFPLEdBQ2xCdUQsRUFBTXZLLEtBQUtnSCxPQUFPLEdBQ2xCd0QsRUFBTXhLLEtBQUtnSCxPQUFPLEdBQ2xCeUQsRUFBTXpLLEtBQUtnSCxPQUFPLEdBQ2xCMEQsRUFBTTFLLEtBQUtnSCxPQUFPLEdBQ2xCMkQsRUFBTTNLLEtBQUtnSCxPQUFPLEdBQ2xCNEQsRUFBTTVLLEtBQUtnSCxPQUFPLEdBQ2xCNkQsRUFBTTdLLEtBQUtnSCxPQUFPLElBQ2xCOEQsRUFBTTlLLEtBQUtnSCxPQUFPLElBQ2xCNEcsRUFBTXhHLEVBQUlBLEVBQUl1RyxFQUFJRixFQUNsQkksRUFBTXhHLEVBQUlELEVBQUl1RyxFQUFJckcsRUFBSWlHLEVBQ3RCTyxFQUFNeEcsRUFBSUYsRUFBSXVHLEVBQUl0RyxFQUFJa0csRUFDdEJRLEVBQU0zRyxFQUFJQyxFQUFJc0csRUFBSXJHLEVBQUlpRyxFQUN0QlMsRUFBTTNHLEVBQUlBLEVBQUlzRyxFQUFJRixFQUNsQlEsRUFBTTNHLEVBQUlELEVBQUlzRyxFQUFJdkcsRUFBSW1HLEVBQ3RCVyxFQUFNOUcsRUFBSUUsRUFBSXFHLEVBQUl0RyxFQUFJa0csRUFDdEJZLEVBQU05RyxFQUFJQyxFQUFJcUcsRUFBSXZHLEVBQUltRyxFQUN0QmEsRUFBTTlHLEVBQUlBLEVBQUlxRyxFQUFJRixFQWF4QixPQVpBek4sS0FBS2dILE9BQU8sR0FBS21ELEVBQU15RCxFQUFNckQsRUFBTXNELEVBQU1sRCxFQUFNbUQsRUFDL0M5TixLQUFLZ0gsT0FBTyxHQUFLb0QsRUFBTXdELEVBQU1wRCxFQUFNcUQsRUFBTWpELEVBQU1rRCxFQUMvQzlOLEtBQUtnSCxPQUFPLEdBQUtxRCxFQUFNdUQsRUFBTW5ELEVBQU1vRCxFQUFNaEQsRUFBTWlELEVBQy9DOU4sS0FBS2dILE9BQU8sR0FBS3NELEVBQU1zRCxFQUFNbEQsRUFBTW1ELEVBQU0vQyxFQUFNZ0QsRUFDL0M5TixLQUFLZ0gsT0FBTyxHQUFLbUQsRUFBTTRELEVBQU14RCxFQUFNeUQsRUFBTXJELEVBQU1zRCxFQUMvQ2pPLEtBQUtnSCxPQUFPLEdBQUtvRCxFQUFNMkQsRUFBTXZELEVBQU13RCxFQUFNcEQsRUFBTXFELEVBQy9Dak8sS0FBS2dILE9BQU8sR0FBS3FELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQU1uRCxFQUFNb0QsRUFDL0NqTyxLQUFLZ0gsT0FBTyxHQUFLc0QsRUFBTXlELEVBQU1yRCxFQUFNc0QsRUFBTWxELEVBQU1tRCxFQUMvQ2pPLEtBQUtnSCxPQUFPLEdBQUttRCxFQUFNK0QsRUFBTTNELEVBQU00RCxFQUFNeEQsRUFBTXlELEVBQy9DcE8sS0FBS2dILE9BQU8sR0FBS29ELEVBQU04RCxFQUFNMUQsRUFBTTJELEVBQU12RCxFQUFNd0QsRUFDL0NwTyxLQUFLZ0gsT0FBTyxJQUFNcUQsRUFBTTZELEVBQU16RCxFQUFNMEQsRUFBTXRELEVBQU11RCxFQUNoRHBPLEtBQUtnSCxPQUFPLElBQU1zRCxFQUFNNEQsRUFBTXhELEVBQU15RCxFQUFNckQsRUFBTXNELEVBQ3pDcE8sS0FFWHdKLGVBQWU2RSxFQUFNQyxFQUFPQyxFQUFRQyxFQUFLQyxFQUFNQyxHQUMzQyxNQUFNQyxFQUFLTCxFQUFRRCxFQUNiTyxFQUFLSixFQUFNRCxFQUNYNUgsRUFBSytILEVBQU1ELEVBQ2pCLE9BQU8sSUFBSTVFLEVBQUssQ0FDSixFQUFQNEUsRUFBWUUsRUFDYixFQUNBLEVBQ0EsRUFDQSxFQUNRLEVBQVBGLEVBQVlHLEVBQ2IsRUFDQSxHQUNDTixFQUFRRCxHQUFRTSxHQUNoQkgsRUFBTUQsR0FBVUssSUFDZkYsRUFBTUQsR0FBUTlILEdBQ2YsRUFDRCxFQUNBLEdBQ0UrSCxFQUFNRCxFQUFPLEVBQUs5SCxFQUNwQixJQUdSNkMsbUJBQW1CcUYsRUFBS0MsRUFBUUwsRUFBTUMsR0FDbEMsTUFBTUYsRUFBTUMsRUFBTzlGLEtBQUtvRyxJQUFLRixFQUFNbEcsS0FBS3FHLEdBQU0sS0FDeENWLEVBQVFFLEVBQU1NLEVBQ3BCLE9BQU9qRixFQUFLb0YsU0FBU1gsRUFBT0EsR0FBUUUsRUFBS0EsRUFBS0MsRUFBTUMsR0FFeERsRixvQkFBb0I2RSxFQUFNQyxFQUFPQyxFQUFRQyxFQUFLQyxFQUFNQyxHQUNoRCxNQUFNQyxFQUFLTCxFQUFRRCxFQUNiTyxFQUFLSixFQUFNRCxFQUNYNUgsRUFBSytILEVBQU1ELEVBQ2pCLE9BQU8sSUFBSTVFLEVBQUssQ0FDWixFQUFJOEUsRUFDSixFQUNBLEVBQ0EsRUFDQSxFQUNBLEVBQUlDLEVBQ0osRUFDQSxFQUNBLEVBQ0EsR0FDQyxFQUFJakksRUFDTCxJQUNFMEgsRUFBT0MsR0FBU0ssSUFDaEJILEVBQU1ELEdBQVVLLElBQ2hCRixFQUFNRCxHQUFROUgsRUFDaEIsSUFHUjZDLGNBQWMwRixFQUFVQyxFQUFRQyxFQUFLdEMsRUFBS3NDLElBQ3RDLEdBQUlGLEVBQVMzRyxPQUFPNEcsR0FDaEIsT0FBT25QLEtBQUtxUCxTQUVoQixNQUFNL0gsRUFBSXdGLEVBQUt3QyxXQUFXSixFQUFVQyxHQUFRL0YsWUFDdENoQyxFQUFJMEYsRUFBS3lDLE1BQU1ILEVBQUk5SCxHQUFHOEIsWUFDdEIvQixFQUFJeUYsRUFBS3lDLE1BQU1qSSxFQUFHRixHQUFHZ0MsWUFDM0IsT0FBTyxJQUFJUyxFQUFLLENBQ1p6QyxFQUFFQSxFQUNGQyxFQUFFRCxFQUNGRSxFQUFFRixFQUNGLEVBQ0FBLEVBQUVDLEVBQ0ZBLEVBQUVBLEVBQ0ZDLEVBQUVELEVBQ0YsRUFDQUQsRUFBRUUsRUFDRkQsRUFBRUMsRUFDRkEsRUFBRUEsRUFDRixHQUNDd0YsRUFBSzBDLElBQUlwSSxFQUFHOEgsSUFDWnBDLEVBQUswQyxJQUFJbkksRUFBRzZILElBQ1pwQyxFQUFLMEMsSUFBSWxJLEVBQUc0SCxHQUNiLElBR1IxRixlQUFlaUcsRUFBSUMsRUFBSXhLLEdBQ25CLE1BQU1pRixFQUFNc0YsRUFBR3hILEdBQUcsR0FDWm1DLEVBQU1xRixFQUFHeEgsR0FBRyxHQUNab0MsRUFBTW9GLEVBQUd4SCxHQUFHLEdBQ1pxQyxFQUFNbUYsRUFBR3hILEdBQUcsR0FDWnNDLEVBQU1rRixFQUFHeEgsR0FBRyxHQUNadUMsRUFBTWlGLEVBQUd4SCxHQUFHLEdBQ1p3QyxFQUFNZ0YsRUFBR3hILEdBQUcsR0FDWnlDLEVBQU0rRSxFQUFHeEgsR0FBRyxHQUNaMEMsRUFBTThFLEVBQUd4SCxHQUFHLEdBQ1oyQyxFQUFNNkUsRUFBR3hILEdBQUcsR0FDWjRDLEVBQU00RSxFQUFHeEgsR0FBRyxJQUNaNkMsRUFBTTJFLEVBQUd4SCxHQUFHLElBQ1o4QyxFQUFNMEUsRUFBR3hILEdBQUcsSUFDWitDLEVBQU15RSxFQUFHeEgsR0FBRyxJQUNaZ0QsRUFBTXdFLEVBQUd4SCxHQUFHLElBQ1ppRCxFQUFNdUUsRUFBR3hILEdBQUcsSUFDWjJGLEVBQU04QixFQUFHekgsR0FBRyxHQUNaNEYsRUFBTTZCLEVBQUd6SCxHQUFHLEdBQ1o2RixFQUFNNEIsRUFBR3pILEdBQUcsR0FDWjBILEVBQU1ELEVBQUd6SCxHQUFHLEdBQ1o4RixFQUFNMkIsRUFBR3pILEdBQUcsR0FDWitGLEVBQU0wQixFQUFHekgsR0FBRyxHQUNaZ0csRUFBTXlCLEVBQUd6SCxHQUFHLEdBQ1oySCxFQUFNRixFQUFHekgsR0FBRyxHQUNaaUcsRUFBTXdCLEVBQUd6SCxHQUFHLEdBQ1prRyxFQUFNdUIsRUFBR3pILEdBQUcsR0FDWm1HLEVBQU1zQixFQUFHekgsR0FBRyxJQUNaNEgsRUFBTUgsRUFBR3pILEdBQUcsSUFDWjZILEVBQU1KLEVBQUd6SCxHQUFHLElBQ1o4SCxFQUFNTCxFQUFHekgsR0FBRyxJQUNaK0gsRUFBTU4sRUFBR3pILEdBQUcsSUFDWmdJLEVBQU1QLEVBQUd6SCxHQUFHLElBQ2xCLE9BQUkvQyxHQUNBQSxFQUFPMUMsS0FBSyxDQUNSb0wsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQU1uRCxFQUFNZ0YsRUFBTTVFLEVBQzFDNkMsRUFBTXhELEVBQU15RCxFQUFNckQsRUFBTXNELEVBQU1sRCxFQUFNK0UsRUFBTTNFLEVBQzFDNEMsRUFBTXZELEVBQU13RCxFQUFNcEQsRUFBTXFELEVBQU1qRCxFQUFNOEUsRUFBTTFFLEVBQzFDMkMsRUFBTXRELEVBQU11RCxFQUFNbkQsRUFBTW9ELEVBQU1oRCxFQUFNNkUsRUFBTXpFLEVBQzFDNkMsRUFBTTVELEVBQU02RCxFQUFNekQsRUFBTTBELEVBQU10RCxFQUFNaUYsRUFBTTdFLEVBQzFDZ0QsRUFBTTNELEVBQU00RCxFQUFNeEQsRUFBTXlELEVBQU1yRCxFQUFNZ0YsRUFBTTVFLEVBQzFDK0MsRUFBTTFELEVBQU0yRCxFQUFNdkQsRUFBTXdELEVBQU1wRCxFQUFNK0UsRUFBTTNFLEVBQzFDOEMsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQU1uRCxFQUFNOEUsRUFBTTFFLEVBQzFDZ0QsRUFBTS9ELEVBQU1nRSxFQUFNNUQsRUFBTTZELEVBQU16RCxFQUFNa0YsRUFBTTlFLEVBQzFDbUQsRUFBTTlELEVBQU0rRCxFQUFNM0QsRUFBTTRELEVBQU14RCxFQUFNaUYsRUFBTTdFLEVBQzFDa0QsRUFBTTdELEVBQU04RCxFQUFNMUQsRUFBTTJELEVBQU12RCxFQUFNZ0YsRUFBTTVFLEVBQzFDaUQsRUFBTTVELEVBQU02RCxFQUFNekQsRUFBTTBELEVBQU10RCxFQUFNK0UsRUFBTTNFLEVBQzFDNEUsRUFBTTNGLEVBQU00RixFQUFNeEYsRUFBTXlGLEVBQU1yRixFQUFNc0YsRUFBTWxGLEVBQzFDK0UsRUFBTTFGLEVBQU0yRixFQUFNdkYsRUFBTXdGLEVBQU1wRixFQUFNcUYsRUFBTWpGLEVBQzFDOEUsRUFBTXpGLEVBQU0wRixFQUFNdEYsRUFBTXVGLEVBQU1uRixFQUFNb0YsRUFBTWhGLEVBQzFDNkUsRUFBTXhGLEVBQU15RixFQUFNckYsRUFBTXNGLEVBQU1sRixFQUFNbUYsRUFBTS9FLElBRXZDaEcsR0FHQSxJQUFJMkUsRUFBSyxDQUNaK0QsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQU1uRCxFQUFNZ0YsRUFBTTVFLEVBQzFDNkMsRUFBTXhELEVBQU15RCxFQUFNckQsRUFBTXNELEVBQU1sRCxFQUFNK0UsRUFBTTNFLEVBQzFDNEMsRUFBTXZELEVBQU13RCxFQUFNcEQsRUFBTXFELEVBQU1qRCxFQUFNOEUsRUFBTTFFLEVBQzFDMkMsRUFBTXRELEVBQU11RCxFQUFNbkQsRUFBTW9ELEVBQU1oRCxFQUFNNkUsRUFBTXpFLEVBQzFDNkMsRUFBTTVELEVBQU02RCxFQUFNekQsRUFBTTBELEVBQU10RCxFQUFNaUYsRUFBTTdFLEVBQzFDZ0QsRUFBTTNELEVBQU00RCxFQUFNeEQsRUFBTXlELEVBQU1yRCxFQUFNZ0YsRUFBTTVFLEVBQzFDK0MsRUFBTTFELEVBQU0yRCxFQUFNdkQsRUFBTXdELEVBQU1wRCxFQUFNK0UsRUFBTTNFLEVBQzFDOEMsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQU1uRCxFQUFNOEUsRUFBTTFFLEVBQzFDZ0QsRUFBTS9ELEVBQU1nRSxFQUFNNUQsRUFBTTZELEVBQU16RCxFQUFNa0YsRUFBTTlFLEVBQzFDbUQsRUFBTTlELEVBQU0rRCxFQUFNM0QsRUFBTTRELEVBQU14RCxFQUFNaUYsRUFBTTdFLEVBQzFDa0QsRUFBTTdELEVBQU04RCxFQUFNMUQsRUFBTTJELEVBQU12RCxFQUFNZ0YsRUFBTTVFLEVBQzFDaUQsRUFBTTVELEVBQU02RCxFQUFNekQsRUFBTTBELEVBQU10RCxFQUFNK0UsRUFBTTNFLEVBQzFDNEUsRUFBTTNGLEVBQU00RixFQUFNeEYsRUFBTXlGLEVBQU1yRixFQUFNc0YsRUFBTWxGLEVBQzFDK0UsRUFBTTFGLEVBQU0yRixFQUFNdkYsRUFBTXdGLEVBQU1wRixFQUFNcUYsRUFBTWpGLEVBQzFDOEUsRUFBTXpGLEVBQU0wRixFQUFNdEYsRUFBTXVGLEVBQU1uRixFQUFNb0YsRUFBTWhGLEVBQzFDNkUsRUFBTXhGLEVBQU15RixFQUFNckYsRUFBTXNGLEVBQU1sRixFQUFNbUYsRUFBTS9FLEtBSzFEckIsRUFBS3dGLFVBQVcsSUFBSXhGLEdBQU9zQixjQ2hrQlosTUFBTStFLEVBQ2pCblEsWUFBWWlILEdBQ1JoSCxLQUFLZ0gsT0FBUyxJQUFJQyxhQUFhLFFBQ2hCQyxJQUFYRixJQUNBaEgsS0FBS3dILEdBQUtSLEdBR2RJLFFBQ0EsT0FBT3BILEtBQUtnSCxPQUFPLEdBRW5CSyxRQUNBLE9BQU9ySCxLQUFLZ0gsT0FBTyxHQUVuQlEsU0FDQSxNQUFPLENBQUN4SCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sSUFFcENJLE1BQUU1RyxHQUNGUixLQUFLZ0gsT0FBTyxHQUFLeEcsRUFFakI2RyxNQUFFN0csR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCZ0gsT0FBR1IsR0FDSGhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBRTVCaUIsR0FBR0MsR0FDQyxPQUFPbEksS0FBS2dILE9BQU9rQixHQUV2QkMsUUFDSW5JLEtBQUtvSCxFQUFJLEVBQ1RwSCxLQUFLcUgsRUFBSSxFQUViZSxLQUFLQyxHQU1ELE9BTEtBLElBQ0RBLEVBQU8sSUFBSTZILEdBRWY3SCxFQUFLakIsRUFBSXBILEtBQUtvSCxFQUNkaUIsRUFBS2hCLEVBQUlySCxLQUFLcUgsRUFDUGdCLEVBRVhDLE9BQU9ELEdBTUgsT0FMS0EsSUFDREEsRUFBT3JJLE1BRVhxSSxFQUFLakIsR0FBS3BILEtBQUtvSCxFQUNmaUIsRUFBS2hCLEdBQUtySCxLQUFLcUgsRUFDUmdCLEVBRVhFLE9BQU9DLEVBQVFDLEVBQVlDLE1BQ3ZCLFFBQUlDLEtBQUtDLElBQUk1SSxLQUFLb0gsRUFBSW9CLEVBQU9wQixHQUFLcUIsTUFHOUJFLEtBQUtDLElBQUk1SSxLQUFLcUgsRUFBSW1CLEVBQU9uQixHQUFLb0IsR0FLdEM3QixTQUNJLE9BQU8rQixLQUFLRSxLQUFLN0ksS0FBSzhJLGlCQUUxQkEsZ0JBQ0ksTUFBTTFCLEVBQUlwSCxLQUFLb0gsRUFDVEMsRUFBSXJILEtBQUtxSCxFQUNmLE9BQU9ELEVBQUlBLEVBQUlDLEVBQUlBLEVBRXZCMEIsSUFBSVAsR0FHQSxPQUZBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNWckgsS0FFWGdKLFNBQVNSLEdBR0wsT0FGQXhJLEtBQUtvSCxHQUFLb0IsRUFBT3BCLEVBQ2pCcEgsS0FBS3FILEdBQUttQixFQUFPbkIsRUFDVnJILEtBRVhpSixTQUFTVCxHQUdMLE9BRkF4SSxLQUFLb0gsR0FBS29CLEVBQU9wQixFQUNqQnBILEtBQUtxSCxHQUFLbUIsRUFBT25CLEVBQ1ZySCxLQUVYa0osT0FBT1YsR0FHSCxPQUZBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNWckgsS0FFWG1KLE1BQU0zSSxFQUFPNkgsR0FNVCxPQUxLQSxJQUNEQSxFQUFPckksTUFFWHFJLEVBQUtqQixHQUFLNUcsRUFDVjZILEVBQUtoQixHQUFLN0csRUFDSDZILEVBRVhlLFVBQVVmLEdBQ0RBLElBQ0RBLEVBQU9ySSxNQUVYLElBQUk0RyxFQUFTNUcsS0FBSzRHLFNBQ2xCLE9BQWUsSUFBWEEsRUFDTzVHLEtBRUksSUFBWDRHLEdBQ0F5QixFQUFLakIsRUFBSSxFQUNUaUIsRUFBS2hCLEVBQUksRUFDRmdCLElBRVh6QixFQUFTLEVBQU1BLEVBQ2Z5QixFQUFLakIsR0FBS1IsRUFDVnlCLEVBQUtoQixHQUFLVCxFQUNIeUIsR0FFWDhILGFBQWE3RyxFQUFRakIsR0FJakIsT0FIS0EsSUFDREEsRUFBT3JJLE1BRUpzSixFQUFPOEcsYUFBYXBRLEtBQU1xSSxHQUVyQ2dJLGFBQWEvRyxFQUFRakIsR0FJakIsT0FIS0EsSUFDREEsRUFBT3JJLE1BRUpzSixFQUFPOEcsYUFBYXBRLEtBQU1xSSxHQUVyQ21CLGFBQWFoQixFQUFRaUIsRUFBU3BCLEdBQ3JCQSxJQUNEQSxFQUFPLElBQUl5RSxHQUVmLE1BQU0xRixFQUFJb0IsRUFBT3BCLEVBQ1hDLEVBQUltQixFQUFPbkIsRUFDWGlKLEVBQUs3RyxFQUFRckMsRUFFYkUsRUFBSUYsRUFEQ3FDLEVBQVFwQyxFQUNBQSxFQUFJaUosRUFJdkIsT0FIQWpJLEVBQUtqQixFQUFJLEVBQ1RpQixFQUFLaEIsRUFBSSxFQUNUZ0IsRUFBS2YsRUFBSUEsRUFDRmUsRUFFWG1CLFdBQVdoQixFQUFRaUIsR0FDZixPQUFPakIsRUFBT3BCLEVBQUlxQyxFQUFRckMsRUFBSW9CLEVBQU9uQixFQUFJb0MsRUFBUXBDLEVBRXJEbUMsZ0JBQWdCaEIsRUFBUWlCLEdBQ3BCLE9BQU9kLEtBQUtFLEtBQUs3SSxLQUFLdVEsZ0JBQWdCL0gsRUFBUWlCLElBRWxERCx1QkFBdUJoQixFQUFRaUIsR0FDM0IsTUFBTXJDLEVBQUlxQyxFQUFRckMsRUFBSW9CLEVBQU9wQixFQUN2QkMsRUFBSW9DLEVBQVFwQyxFQUFJbUIsRUFBT25CLEVBQzdCLE9BQU9ELEVBQUlBLEVBQUlDLEVBQUlBLEVBRXZCbUMsaUJBQWlCaEIsRUFBUWlCLEVBQVNwQixHQUN6QkEsSUFDREEsRUFBTyxJQUFJNkgsR0FFZixNQUFNOUksRUFBSW9CLEVBQU9wQixFQUFJcUMsRUFBUXJDLEVBQ3ZCQyxFQUFJbUIsRUFBT25CLEVBQUlvQyxFQUFRcEMsRUFDN0IsSUFBSVQsRUFBUytCLEtBQUtFLEtBQUt6QixFQUFJQSxFQUFJQyxFQUFJQSxHQUNuQyxPQUFlLElBQVhULEdBQ0F5QixFQUFLakIsRUFBSSxFQUNUaUIsRUFBS2hCLEVBQUksRUFDRmdCLElBRVh6QixFQUFTLEVBQUlBLEVBQ2J5QixFQUFLakIsRUFBSUEsRUFBSVIsRUFDYnlCLEVBQUtoQixFQUFJQSxFQUFJVCxFQUNOeUIsR0FFWG1CLFdBQVdoQixFQUFRaUIsRUFBU0MsRUFBTXJCLEdBQ3pCQSxJQUNEQSxFQUFPLElBQUk2SCxHQUVmLE1BQU05SSxFQUFJb0IsRUFBT3BCLEVBQ1hDLEVBQUltQixFQUFPbkIsRUFDWGlKLEVBQUs3RyxFQUFRckMsRUFDYm9KLEVBQUsvRyxFQUFRcEMsRUFHbkIsT0FGQWdCLEVBQUtqQixFQUFJQSxFQUFJc0MsR0FBUTRHLEVBQUtsSixHQUMxQmlCLEVBQUtoQixFQUFJQSxFQUFJcUMsR0FBUThHLEVBQUtuSixHQUNuQmdCLEVBRVhtQixXQUFXaEIsRUFBUWlCLEVBQVNwQixHQU14QixPQUxLQSxJQUNEQSxFQUFPLElBQUk2SCxHQUVmN0gsRUFBS2pCLEVBQUlvQixFQUFPcEIsRUFBSXFDLEVBQVFyQyxFQUM1QmlCLEVBQUtoQixFQUFJbUIsRUFBT25CLEVBQUlvQyxFQUFRcEMsRUFDckJnQixFQUVYbUIsa0JBQWtCaEIsRUFBUWlCLEVBQVNwQixHQU0vQixPQUxLQSxJQUNEQSxFQUFPLElBQUk2SCxHQUVmN0gsRUFBS2pCLEVBQUlvQixFQUFPcEIsRUFBSXFDLEVBQVFyQyxFQUM1QmlCLEVBQUtoQixFQUFJbUIsRUFBT25CLEVBQUlvQyxFQUFRcEMsRUFDckJnQixFQUVYbUIsZUFBZWhCLEVBQVFpQixFQUFTcEIsR0FNNUIsT0FMS0EsSUFDREEsRUFBTyxJQUFJNkgsR0FFZjdILEVBQUtqQixFQUFJb0IsRUFBT3BCLEVBQUlxQyxFQUFRckMsRUFDNUJpQixFQUFLaEIsRUFBSW1CLEVBQU9uQixFQUFJb0MsRUFBUXBDLEVBQ3JCZ0IsRUFFWG1CLGdCQUFnQmhCLEVBQVFpQixFQUFTcEIsR0FNN0IsT0FMS0EsSUFDREEsRUFBTyxJQUFJNkgsR0FFZjdILEVBQUtqQixFQUFJb0IsRUFBT3BCLEVBQUlxQyxFQUFRckMsRUFDNUJpQixFQUFLaEIsRUFBSW1CLEVBQU9uQixFQUFJb0MsRUFBUXBDLEVBQ3JCZ0IsR0FHZjZILEVBQUt2RyxLQUFPLElBQUl1RyxFQUFLLENBQUMsRUFBRyxJQUN6QkEsRUFBS3RHLElBQU0sSUFBSXNHLEVBQUssQ0FBQyxFQUFHLElDak5ULE1BQU1sRCxFQUNqQmpOLFlBQVlpSCxHQUNSaEgsS0FBS2dILE9BQVMsSUFBSUMsYUFBYSxRQUNoQkMsSUFBWEYsR0FDQWhILEtBQUt3QyxLQUFLd0UsR0FHbEJpQixHQUFHQyxHQUNDLE9BQU9sSSxLQUFLZ0gsT0FBT2tCLEdBRXZCMUYsS0FBS3dFLEdBQ0QsSUFBSyxJQUFJOEMsRUFBSSxFQUFHQSxFQUFJLEVBQUdBLElBQ25COUosS0FBS2dILE9BQU84QyxHQUFLOUMsRUFBTzhDLEdBRTVCLE9BQU85SixLQUVYbUksUUFDSSxJQUFLLElBQUkyQixFQUFJLEVBQUdBLEVBQUksRUFBR0EsSUFDbkI5SixLQUFLZ0gsT0FBTzhDLEdBQUssRUFHekIxQixLQUFLQyxHQUNJQSxJQUNEQSxFQUFPLElBQUkyRSxHQUVmLElBQUssSUFBSWxELEVBQUksRUFBR0EsRUFBSSxFQUFHQSxJQUNuQnpCLEVBQUtyQixPQUFPOEMsR0FBSzlKLEtBQUtnSCxPQUFPOEMsR0FFakMsT0FBT3pCLEVBRVgwQixNQUNJLE1BQU03SSxFQUFPLEdBQ2IsSUFBSyxJQUFJNEksRUFBSSxFQUFHQSxFQUFJLEVBQUdBLElBQ25CNUksRUFBSzRJLEdBQUs5SixLQUFLZ0gsT0FBTzhDLEdBRTFCLE9BQU81SSxFQUVYOEksSUFBSTlCLEdBQ0EsTUFBTyxDQUNIbEksS0FBS2dILE9BQWUsRUFBUmtCLEVBQVksR0FDeEJsSSxLQUFLZ0gsT0FBZSxFQUFSa0IsRUFBWSxHQUN4QmxJLEtBQUtnSCxPQUFlLEVBQVJrQixFQUFZLElBR2hDK0IsSUFBSS9CLEdBQ0EsTUFBTyxDQUFDbEksS0FBS2dILE9BQU9rQixHQUFRbEksS0FBS2dILE9BQU9rQixFQUFRLEdBQUlsSSxLQUFLZ0gsT0FBT2tCLEVBQVEsSUFFNUVLLE9BQU9lLEVBQVFiLEVBQVlDLE1BQ3ZCLElBQUssSUFBSW9CLEVBQUksRUFBR0EsRUFBSSxFQUFHQSxJQUNuQixHQUFJbkIsS0FBS0MsSUFBSTVJLEtBQUtnSCxPQUFPOEMsR0FBS1IsRUFBT3JCLEdBQUc2QixJQUFNckIsRUFDMUMsT0FBTyxFQUdmLE9BQU8sRUFFWHlCLGNBQ0ksTUFBTUMsRUFBTW5LLEtBQUtnSCxPQUFPLEdBQ2xCb0QsRUFBTXBLLEtBQUtnSCxPQUFPLEdBQ2xCcUQsRUFBTXJLLEtBQUtnSCxPQUFPLEdBQ2xCdUQsRUFBTXZLLEtBQUtnSCxPQUFPLEdBQ2xCd0QsRUFBTXhLLEtBQUtnSCxPQUFPLEdBQ2xCeUQsRUFBTXpLLEtBQUtnSCxPQUFPLEdBQ2xCMkQsRUFBTTNLLEtBQUtnSCxPQUFPLEdBQ2xCNEQsRUFBTTVLLEtBQUtnSCxPQUFPLEdBQ2xCNkQsRUFBTTdLLEtBQUtnSCxPQUFPLEdBSXhCLE9BQU9tRCxHQUhPVSxFQUFNTCxFQUFNQyxFQUFNRyxHQUdYUixJQUZOUyxFQUFNTixFQUFNRSxFQUFNRSxHQUVFTixHQURyQk8sRUFBTUwsRUFBTUMsRUFBTUcsR0FHcENRLGNBVUksT0FUQW5MLEtBQUtnSCxPQUFPLEdBQUssRUFDakJoSCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sR0FBSyxFQUNqQmhILEtBQUtnSCxPQUFPLEdBQUssRUFDakJoSCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sR0FBSyxFQUNqQmhILEtBQUtnSCxPQUFPLEdBQUssRUFDakJoSCxLQUFLZ0gsT0FBTyxHQUFLLEVBQ2pCaEgsS0FBS2dILE9BQU8sR0FBSyxFQUNWaEgsS0FFWG9MLFlBQ0ksTUFBTUMsRUFBU3JMLEtBQUtnSCxPQUFPLEdBQ3JCc0UsRUFBU3RMLEtBQUtnSCxPQUFPLEdBQ3JCd0UsRUFBU3hMLEtBQUtnSCxPQUFPLEdBTzNCLE9BTkFoSCxLQUFLZ0gsT0FBTyxHQUFLaEgsS0FBS2dILE9BQU8sR0FDN0JoSCxLQUFLZ0gsT0FBTyxHQUFLaEgsS0FBS2dILE9BQU8sR0FDN0JoSCxLQUFLZ0gsT0FBTyxHQUFLcUUsRUFDakJyTCxLQUFLZ0gsT0FBTyxHQUFLaEgsS0FBS2dILE9BQU8sR0FDN0JoSCxLQUFLZ0gsT0FBTyxHQUFLc0UsRUFDakJ0TCxLQUFLZ0gsT0FBTyxHQUFLd0UsRUFDVnhMLEtBRVgyTCxVQUNJLE1BQU14QixFQUFNbkssS0FBS2dILE9BQU8sR0FDbEJvRCxFQUFNcEssS0FBS2dILE9BQU8sR0FDbEJxRCxFQUFNckssS0FBS2dILE9BQU8sR0FDbEJ1RCxFQUFNdkssS0FBS2dILE9BQU8sR0FDbEJ3RCxFQUFNeEssS0FBS2dILE9BQU8sR0FDbEJ5RCxFQUFNekssS0FBS2dILE9BQU8sR0FDbEIyRCxFQUFNM0ssS0FBS2dILE9BQU8sR0FDbEI0RCxFQUFNNUssS0FBS2dILE9BQU8sR0FDbEI2RCxFQUFNN0ssS0FBS2dILE9BQU8sR0FDbEI2RSxFQUFRaEIsRUFBTUwsRUFBTUMsRUFBTUcsRUFDMUIyQixHQUFTMUIsRUFBTU4sRUFBTUUsRUFBTUUsRUFDM0J1QyxFQUFRdEMsRUFBTUwsRUFBTUMsRUFBTUcsRUFDaEMsSUFBSTZCLEVBQU1yQyxFQUFNMEIsRUFBUXpCLEVBQU1tQyxFQUFRbEMsRUFBTTZDLEVBQzVDLE9BQUtWLEdBR0xBLEVBQU0sRUFBTUEsRUFDWnhNLEtBQUtnSCxPQUFPLEdBQUs2RSxFQUFRVyxFQUN6QnhNLEtBQUtnSCxPQUFPLEtBQU82RCxFQUFNVCxFQUFNQyxFQUFNTyxHQUFPNEIsRUFDNUN4TSxLQUFLZ0gsT0FBTyxJQUFNeUQsRUFBTUwsRUFBTUMsRUFBTUcsR0FBT2dDLEVBQzNDeE0sS0FBS2dILE9BQU8sR0FBS3VGLEVBQVFDLEVBQ3pCeE0sS0FBS2dILE9BQU8sSUFBTTZELEVBQU1WLEVBQU1FLEVBQU1NLEdBQU82QixFQUMzQ3hNLEtBQUtnSCxPQUFPLEtBQU95RCxFQUFNTixFQUFNRSxFQUFNRSxHQUFPaUMsRUFDNUN4TSxLQUFLZ0gsT0FBTyxHQUFLa0csRUFBUVYsRUFDekJ4TSxLQUFLZ0gsT0FBTyxLQUFPNEQsRUFBTVQsRUFBTUMsRUFBTU8sR0FBTzZCLEVBQzVDeE0sS0FBS2dILE9BQU8sSUFBTXdELEVBQU1MLEVBQU1DLEVBQU1HLEdBQU9pQyxFQUNwQ3hNLE1BWkksS0FjZmlKLFNBQVNLLEdBQ0wsTUFBTWEsRUFBTW5LLEtBQUtnSCxPQUFPLEdBQ2xCb0QsRUFBTXBLLEtBQUtnSCxPQUFPLEdBQ2xCcUQsRUFBTXJLLEtBQUtnSCxPQUFPLEdBQ2xCdUQsRUFBTXZLLEtBQUtnSCxPQUFPLEdBQ2xCd0QsRUFBTXhLLEtBQUtnSCxPQUFPLEdBQ2xCeUQsRUFBTXpLLEtBQUtnSCxPQUFPLEdBQ2xCMkQsRUFBTTNLLEtBQUtnSCxPQUFPLEdBQ2xCNEQsRUFBTTVLLEtBQUtnSCxPQUFPLEdBQ2xCNkQsRUFBTTdLLEtBQUtnSCxPQUFPLEdBQ2xCNEcsRUFBTXRFLEVBQU9yQixHQUFHLEdBQ2hCNEYsRUFBTXZFLEVBQU9yQixHQUFHLEdBQ2hCNkYsRUFBTXhFLEVBQU9yQixHQUFHLEdBQ2hCOEYsRUFBTXpFLEVBQU9yQixHQUFHLEdBQ2hCK0YsRUFBTTFFLEVBQU9yQixHQUFHLEdBQ2hCZ0csRUFBTTNFLEVBQU9yQixHQUFHLEdBQ2hCaUcsRUFBTTVFLEVBQU9yQixHQUFHLEdBQ2hCa0csRUFBTTdFLEVBQU9yQixHQUFHLEdBQ2hCbUcsRUFBTTlFLEVBQU9yQixHQUFHLEdBVXRCLE9BVEFqSSxLQUFLZ0gsT0FBTyxHQUFLNEcsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQU1uRCxFQUMvQzNLLEtBQUtnSCxPQUFPLEdBQUs0RyxFQUFNeEQsRUFBTXlELEVBQU1yRCxFQUFNc0QsRUFBTWxELEVBQy9DNUssS0FBS2dILE9BQU8sR0FBSzRHLEVBQU12RCxFQUFNd0QsRUFBTXBELEVBQU1xRCxFQUFNakQsRUFDL0M3SyxLQUFLZ0gsT0FBTyxHQUFLK0csRUFBTTVELEVBQU02RCxFQUFNekQsRUFBTTBELEVBQU10RCxFQUMvQzNLLEtBQUtnSCxPQUFPLEdBQUsrRyxFQUFNM0QsRUFBTTRELEVBQU14RCxFQUFNeUQsRUFBTXJELEVBQy9DNUssS0FBS2dILE9BQU8sR0FBSytHLEVBQU0xRCxFQUFNMkQsRUFBTXZELEVBQU13RCxFQUFNcEQsRUFDL0M3SyxLQUFLZ0gsT0FBTyxHQUFLa0gsRUFBTS9ELEVBQU1nRSxFQUFNNUQsRUFBTTZELEVBQU16RCxFQUMvQzNLLEtBQUtnSCxPQUFPLEdBQUtrSCxFQUFNOUQsRUFBTStELEVBQU0zRCxFQUFNNEQsRUFBTXhELEVBQy9DNUssS0FBS2dILE9BQU8sR0FBS2tILEVBQU03RCxFQUFNOEQsRUFBTTFELEVBQU0yRCxFQUFNdkQsRUFDeEM3SyxLQUVYb1EsYUFBYTVILEVBQVF0RCxHQUNqQixNQUFNa0MsRUFBSW9CLEVBQU9wQixFQUNYQyxFQUFJbUIsRUFBT25CLEVBQ2pCLE9BQUluQyxHQUNBQSxFQUFPc0MsR0FBSyxDQUNSSixFQUFJcEgsS0FBS2dILE9BQU8sR0FBS0ssRUFBSXJILEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxHQUN0REksRUFBSXBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQUlySCxLQUFLZ0gsT0FBTyxHQUFLaEgsS0FBS2dILE9BQU8sSUFFbkQ5QixHQUdBLElBQUlnTCxFQUFLLENBQ1o5SSxFQUFJcEgsS0FBS2dILE9BQU8sR0FBS0ssRUFBSXJILEtBQUtnSCxPQUFPLEdBQUtoSCxLQUFLZ0gsT0FBTyxHQUN0REksRUFBSXBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQUlySCxLQUFLZ0gsT0FBTyxHQUFLaEgsS0FBS2dILE9BQU8sS0FJbEU2RixhQUFhckUsRUFBUXRELEdBQ2pCLE1BQU1rQyxFQUFJb0IsRUFBT3BCLEVBQ1hDLEVBQUltQixFQUFPbkIsRUFDWEMsRUFBSWtCLEVBQU9sQixFQUNqQixPQUFJcEMsR0FDQUEsRUFBT3VDLElBQU0sQ0FDVEwsRUFBSXBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQUlySCxLQUFLZ0gsT0FBTyxHQUFLTSxFQUFJdEgsS0FBS2dILE9BQU8sR0FDMURJLEVBQUlwSCxLQUFLZ0gsT0FBTyxHQUFLSyxFQUFJckgsS0FBS2dILE9BQU8sR0FBS00sRUFBSXRILEtBQUtnSCxPQUFPLEdBQzFESSxFQUFJcEgsS0FBS2dILE9BQU8sR0FBS0ssRUFBSXJILEtBQUtnSCxPQUFPLEdBQUtNLEVBQUl0SCxLQUFLZ0gsT0FBTyxJQUV2RDlCLEdBR0EsSUFBSTRILEVBQUssQ0FDWjFGLEVBQUlwSCxLQUFLZ0gsT0FBTyxHQUFLSyxFQUFJckgsS0FBS2dILE9BQU8sR0FBS00sRUFBSXRILEtBQUtnSCxPQUFPLEdBQzFESSxFQUFJcEgsS0FBS2dILE9BQU8sR0FBS0ssRUFBSXJILEtBQUtnSCxPQUFPLEdBQUtNLEVBQUl0SCxLQUFLZ0gsT0FBTyxHQUMxREksRUFBSXBILEtBQUtnSCxPQUFPLEdBQUtLLEVBQUlySCxLQUFLZ0gsT0FBTyxHQUFLTSxFQUFJdEgsS0FBS2dILE9BQU8sS0FJdEV5SixPQUFPdkwsR0FDSCxPQUFJQSxHQUNBQSxFQUFPMUMsS0FBSyxDQUNSeEMsS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxHQUNaLEVBQ0FoSCxLQUFLZ0gsT0FBTyxHQUNaaEgsS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1osRUFDQWhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxHQUNaaEgsS0FBS2dILE9BQU8sR0FDWixFQUNBLEVBQ0EsRUFDQSxFQUNBLElBRUc5QixHQUdBLElBQUkyRSxFQUFLLENBQ1o3SixLQUFLZ0gsT0FBTyxHQUNaaEgsS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1osRUFDQWhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxHQUNaaEgsS0FBS2dILE9BQU8sR0FDWixFQUNBaEgsS0FBS2dILE9BQU8sR0FDWmhILEtBQUtnSCxPQUFPLEdBQ1poSCxLQUFLZ0gsT0FBTyxHQUNaLEVBQ0EsRUFDQSxFQUNBLEVBQ0EsSUFJWjBKLFNBQ0ksTUFBTUMsRUFBTTNRLEtBQUtnSCxPQUFPLEdBQ2xCNEosRUFBTTVRLEtBQUtnSCxPQUFPLEdBQ2xCNkosRUFBTTdRLEtBQUtnSCxPQUFPLEdBQ2xCOEosRUFBTTlRLEtBQUtnSCxPQUFPLEdBQ2xCK0osRUFBTS9RLEtBQUtnSCxPQUFPLEdBQ2xCZ0ssRUFBTWhSLEtBQUtnSCxPQUFPLEdBQ2xCaUssRUFBTWpSLEtBQUtnSCxPQUFPLEdBQ2xCa0ssRUFBTWxSLEtBQUtnSCxPQUFPLEdBQ2xCbUssRUFBTW5SLEtBQUtnSCxPQUFPLEdBQ2xCb0ssRUFBcUJULEVBQU1JLEVBQU1JLEVBQ2pDRSxFQUFxQk4sRUFBTUosRUFBTVEsRUFDakNHLEVBQXFCSCxFQUFNUixFQUFNSSxFQUV2QyxJQUFJUSxFQUFlLEVBQ2ZDLEVBRnVCYixFQUFNSSxFQUFNSSxFQUduQ0MsRUFBcUJJLElBQ3JCQSxFQUEyQkosRUFDM0JHLEVBQWUsR0FFZkYsRUFBcUJHLElBQ3JCQSxFQUEyQkgsRUFDM0JFLEVBQWUsR0FFZkQsRUFBcUJFLElBQ3JCQSxFQUEyQkYsRUFDM0JDLEVBQWUsR0FFbkIsTUFBTUUsRUFBdUQsR0FBMUM5SSxLQUFLRSxLQUFLMkksRUFBMkIsR0FDbERFLEVBQU8sSUFBT0QsRUFDZHZNLEVBQVMsSUFBSXlNLEVBQ25CLE9BQVFKLEdBQ0osS0FBSyxFQUNEck0sRUFBT3FDLEVBQUlrSyxFQUNYdk0sRUFBT2tDLEdBQUs0SixFQUFNRSxHQUFPUSxFQUN6QnhNLEVBQU9tQyxHQUFLNEosRUFBTUosR0FBT2EsRUFDekJ4TSxFQUFPb0MsR0FBS3NKLEVBQU1FLEdBQU9ZLEVBQ3pCLE1BQ0osS0FBSyxFQUNEeE0sRUFBT3FDLEdBQUt5SixFQUFNRSxHQUFPUSxFQUN6QnhNLEVBQU9rQyxFQUFJcUssRUFDWHZNLEVBQU9tQyxHQUFLdUosRUFBTUUsR0FBT1ksRUFDekJ4TSxFQUFPb0MsR0FBSzJKLEVBQU1KLEdBQU9hLEVBQ3pCLE1BQ0osS0FBSyxFQUNEeE0sRUFBT3FDLEdBQUswSixFQUFNSixHQUFPYSxFQUN6QnhNLEVBQU9rQyxHQUFLd0osRUFBTUUsR0FBT1ksRUFDekJ4TSxFQUFPbUMsRUFBSW9LLEVBQ1h2TSxFQUFPb0MsR0FBSzBKLEVBQU1FLEdBQU9RLEVBQ3pCLE1BQ0osS0FBSyxFQUNEeE0sRUFBT3FDLEdBQUtxSixFQUFNRSxHQUFPWSxFQUN6QnhNLEVBQU9rQyxHQUFLNkosRUFBTUosR0FBT2EsRUFDekJ4TSxFQUFPbUMsR0FBSzJKLEVBQU1FLEdBQU9RLEVBQ3pCeE0sRUFBT29DLEVBQUltSyxFQUduQixPQUFPdk0sRUFFWGtJLE9BQU9DLEVBQU9DLEdBQ1YsSUFBSWxHLEVBQUlrRyxFQUFLbEcsRUFDVEMsRUFBSWlHLEVBQUtqRyxFQUNUQyxFQUFJZ0csRUFBS2hHLEVBQ1RWLEVBQVMrQixLQUFLRSxLQUFLekIsRUFBSUEsRUFBSUMsRUFBSUEsRUFBSUMsRUFBSUEsR0FDM0MsSUFBS1YsRUFDRCxPQUFPLEtBRUksSUFBWEEsSUFDQUEsRUFBUyxFQUFJQSxFQUNiUSxHQUFLUixFQUNMUyxHQUFLVCxFQUNMVSxHQUFLVixHQUVULE1BQU0yRyxFQUFJNUUsS0FBSzZFLElBQUlILEdBQ2JJLEVBQUk5RSxLQUFLK0UsSUFBSUwsR0FDYk0sRUFBSSxFQUFNRixFQUNWdEQsRUFBTW5LLEtBQUtnSCxPQUFPLEdBQ2xCb0QsRUFBTXBLLEtBQUtnSCxPQUFPLEdBQ2xCcUQsRUFBTXJLLEtBQUtnSCxPQUFPLEdBQ2xCdUQsRUFBTXZLLEtBQUtnSCxPQUFPLEdBQ2xCd0QsRUFBTXhLLEtBQUtnSCxPQUFPLEdBQ2xCeUQsRUFBTXpLLEtBQUtnSCxPQUFPLEdBQ2xCMkQsRUFBTTNLLEtBQUtnSCxPQUFPLEdBQ2xCNEQsRUFBTTVLLEtBQUtnSCxPQUFPLEdBQ2xCNkQsRUFBTTdLLEtBQUtnSCxPQUFPLElBQ2xCNEcsRUFBTXhHLEVBQUlBLEVBQUl1RyxFQUFJRixFQUNsQkksRUFBTXhHLEVBQUlELEVBQUl1RyxFQUFJckcsRUFBSWlHLEVBQ3RCTyxFQUFNeEcsRUFBSUYsRUFBSXVHLEVBQUl0RyxFQUFJa0csRUFDdEJRLEVBQU0zRyxFQUFJQyxFQUFJc0csRUFBSXJHLEVBQUlpRyxFQUN0QlMsRUFBTTNHLEVBQUlBLEVBQUlzRyxFQUFJRixFQUNsQlEsRUFBTTNHLEVBQUlELEVBQUlzRyxFQUFJdkcsRUFBSW1HLEVBQ3RCVyxFQUFNOUcsRUFBSUUsRUFBSXFHLEVBQUl0RyxFQUFJa0csRUFDdEJZLEVBQU05RyxFQUFJQyxFQUFJcUcsRUFBSXZHLEVBQUltRyxFQUN0QmEsRUFBTTlHLEVBQUlBLEVBQUlxRyxFQUFJRixFQVV4QixPQVRBek4sS0FBS2dILE9BQU8sR0FBS21ELEVBQU15RCxFQUFNckQsRUFBTXNELEVBQU1sRCxFQUFNbUQsRUFDL0M5TixLQUFLZ0gsT0FBTyxHQUFLb0QsRUFBTXdELEVBQU1wRCxFQUFNcUQsRUFBTWpELEVBQU1rRCxFQUMvQzlOLEtBQUtnSCxPQUFPLEdBQUtxRCxFQUFNdUQsRUFBTW5ELEVBQU1vRCxFQUFNaEQsRUFBTWlELEVBQy9DOU4sS0FBS2dILE9BQU8sR0FBS21ELEVBQU00RCxFQUFNeEQsRUFBTXlELEVBQU1yRCxFQUFNc0QsRUFDL0NqTyxLQUFLZ0gsT0FBTyxHQUFLb0QsRUFBTTJELEVBQU12RCxFQUFNd0QsRUFBTXBELEVBQU1xRCxFQUMvQ2pPLEtBQUtnSCxPQUFPLEdBQUtxRCxFQUFNMEQsRUFBTXRELEVBQU11RCxFQUFNbkQsRUFBTW9ELEVBQy9Dak8sS0FBS2dILE9BQU8sR0FBS21ELEVBQU0rRCxFQUFNM0QsRUFBTTRELEVBQU14RCxFQUFNeUQsRUFDL0NwTyxLQUFLZ0gsT0FBTyxHQUFLb0QsRUFBTThELEVBQU0xRCxFQUFNMkQsRUFBTXZELEVBQU13RCxFQUMvQ3BPLEtBQUtnSCxPQUFPLEdBQUtxRCxFQUFNNkQsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFBTXVELEVBQ3hDcE8sS0FFWHdKLGVBQWVpRyxFQUFJQyxFQUFJeEssR0FDbkIsTUFBTWlGLEVBQU1zRixFQUFHeEgsR0FBRyxHQUNabUMsRUFBTXFGLEVBQUd4SCxHQUFHLEdBQ1pvQyxFQUFNb0YsRUFBR3hILEdBQUcsR0FDWnNDLEVBQU1rRixFQUFHeEgsR0FBRyxHQUNadUMsRUFBTWlGLEVBQUd4SCxHQUFHLEdBQ1p3QyxFQUFNZ0YsRUFBR3hILEdBQUcsR0FDWjBDLEVBQU04RSxFQUFHeEgsR0FBRyxHQUNaMkMsRUFBTTZFLEVBQUd4SCxHQUFHLEdBQ1o0QyxFQUFNNEUsRUFBR3hILEdBQUcsR0FDWjJGLEVBQU04QixFQUFHekgsR0FBRyxHQUNaNEYsRUFBTTZCLEVBQUd6SCxHQUFHLEdBQ1o2RixFQUFNNEIsRUFBR3pILEdBQUcsR0FDWjhGLEVBQU0yQixFQUFHekgsR0FBRyxHQUNaK0YsRUFBTTBCLEVBQUd6SCxHQUFHLEdBQ1pnRyxFQUFNeUIsRUFBR3pILEdBQUcsR0FDWmlHLEVBQU13QixFQUFHekgsR0FBRyxHQUNaa0csRUFBTXVCLEVBQUd6SCxHQUFHLEdBQ1ptRyxFQUFNc0IsRUFBR3pILEdBQUcsR0FDbEIsT0FBSS9DLEdBQ0FBLEVBQU8xQyxLQUFLLENBQ1JvTCxFQUFNekQsRUFBTTBELEVBQU10RCxFQUFNdUQsRUFBTW5ELEVBQzlCaUQsRUFBTXhELEVBQU15RCxFQUFNckQsRUFBTXNELEVBQU1sRCxFQUM5QmdELEVBQU12RCxFQUFNd0QsRUFBTXBELEVBQU1xRCxFQUFNakQsRUFDOUJrRCxFQUFNNUQsRUFBTTZELEVBQU16RCxFQUFNMEQsRUFBTXRELEVBQzlCb0QsRUFBTTNELEVBQU00RCxFQUFNeEQsRUFBTXlELEVBQU1yRCxFQUM5Qm1ELEVBQU0xRCxFQUFNMkQsRUFBTXZELEVBQU13RCxFQUFNcEQsRUFDOUJxRCxFQUFNL0QsRUFBTWdFLEVBQU01RCxFQUFNNkQsRUFBTXpELEVBQzlCdUQsRUFBTTlELEVBQU0rRCxFQUFNM0QsRUFBTTRELEVBQU14RCxFQUM5QnNELEVBQU03RCxFQUFNOEQsRUFBTTFELEVBQU0yRCxFQUFNdkQsSUFFM0IzRixHQUdBLElBQUk4SCxFQUFLLENBQ1pZLEVBQU16RCxFQUFNMEQsRUFBTXRELEVBQU11RCxFQUFNbkQsRUFDOUJpRCxFQUFNeEQsRUFBTXlELEVBQU1yRCxFQUFNc0QsRUFBTWxELEVBQzlCZ0QsRUFBTXZELEVBQU13RCxFQUFNcEQsRUFBTXFELEVBQU1qRCxFQUM5QmtELEVBQU01RCxFQUFNNkQsRUFBTXpELEVBQU0wRCxFQUFNdEQsRUFDOUJvRCxFQUFNM0QsRUFBTTRELEVBQU14RCxFQUFNeUQsRUFBTXJELEVBQzlCbUQsRUFBTTFELEVBQU0yRCxFQUFNdkQsRUFBTXdELEVBQU1wRCxFQUM5QnFELEVBQU0vRCxFQUFNZ0UsRUFBTTVELEVBQU02RCxFQUFNekQsRUFDOUJ1RCxFQUFNOUQsRUFBTStELEVBQU0zRCxFQUFNNEQsRUFBTXhELEVBQzlCc0QsRUFBTTdELEVBQU04RCxFQUFNMUQsRUFBTTJELEVBQU12RCxLQUs5Q21DLEVBQUtxQyxVQUFXLElBQUlyQyxHQUFPN0IsY0NuWVosTUFBTXdHLEVBQ2pCNVIsWUFBWWlILEdBQ1JoSCxLQUFLZ0gsT0FBUyxJQUFJQyxhQUFhLFFBQ2hCQyxJQUFYRixJQUNBaEgsS0FBS21ILEtBQU9ILEdBR2hCSSxRQUNBLE9BQU9wSCxLQUFLZ0gsT0FBTyxHQUVuQkssUUFDQSxPQUFPckgsS0FBS2dILE9BQU8sR0FFbkJNLFFBQ0EsT0FBT3RILEtBQUtnSCxPQUFPLEdBRW5CTyxRQUNBLE9BQU92SCxLQUFLZ0gsT0FBTyxHQUVuQlEsU0FDQSxNQUFPLENBQUN4SCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sSUFFcENTLFVBQ0EsTUFBTyxDQUFDekgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxJQUVwREcsV0FDQSxNQUFPLENBQUNuSCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxJQUVwRUksTUFBRTVHLEdBQ0ZSLEtBQUtnSCxPQUFPLEdBQUt4RyxFQUVqQjZHLE1BQUU3RyxHQUNGUixLQUFLZ0gsT0FBTyxHQUFLeEcsRUFFakI4RyxNQUFFOUcsR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCK0csTUFBRS9HLEdBQ0ZSLEtBQUtnSCxPQUFPLEdBQUt4RyxFQUVqQmdILE9BQUdSLEdBQ0hoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBQ3hCaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUV4QlMsUUFBSVQsR0FDSmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBQ3hCaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUV4QkcsU0FBS0gsR0FDTGhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FDeEJoSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBQ3hCaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FFNUJpQixHQUFHQyxHQUNDLE9BQU9sSSxLQUFLZ0gsT0FBT2tCLEdBRXZCQyxRQUNJLElBQUssSUFBSTJCLEVBQUksRUFBR0EsRUFBSSxFQUFHQSxJQUNuQjlKLEtBQUtnSCxPQUFPOEMsR0FBSyxFQUd6QjFCLEtBQUtDLEdBQ0lBLElBQ0RBLEVBQU8sSUFBSXNKLEdBRWYsSUFBSyxJQUFJN0gsRUFBSSxFQUFHQSxFQUFJLEVBQUdBLElBQ25CekIsRUFBS3JCLE9BQU84QyxHQUFLOUosS0FBS2dILE9BQU84QyxHQUVqQyxPQUFPekIsRUFFWHVKLE9BQ0ksTUFBTXhLLEVBQUlwSCxLQUFLb0gsRUFDVEMsRUFBSXJILEtBQUtxSCxFQUNUQyxFQUFJdEgsS0FBS3NILEVBQ1RDLEVBQUl2SCxLQUFLdUgsRUFDZixPQUFPb0IsS0FBS2tKLE1BQU0sR0FBT3pLLEVBQUlDLEVBQUlFLEVBQUlELEdBQUlDLEVBQUlBLEVBQUlILEVBQUlBLEVBQUlDLEVBQUlBLEVBQUlDLEVBQUlBLEdBRXpFd0ssUUFDSSxNQUFNMUssRUFBSXBILEtBQUtvSCxFQUNUQyxFQUFJckgsS0FBS3FILEVBQ1RDLEVBQUl0SCxLQUFLc0gsRUFDVEMsRUFBSXZILEtBQUt1SCxFQUNmLE9BQU9vQixLQUFLa0osTUFBTSxHQUFPeEssRUFBSUMsRUFBSUMsRUFBSUgsR0FBSUcsRUFBSUEsRUFBSUgsRUFBSUEsRUFBSUMsRUFBSUEsRUFBSUMsRUFBSUEsR0FFekV5SyxNQUNJLE9BQU9wSixLQUFLcUosS0FBSyxHQUFPaFMsS0FBS29ILEVBQUlwSCxLQUFLc0gsRUFBSXRILEtBQUt1SCxFQUFJdkgsS0FBS3FILElBRTVEa0IsT0FBT0MsRUFBUUMsRUFBWUMsTUFDdkIsSUFBSyxJQUFJb0IsRUFBSSxFQUFHQSxFQUFJLEVBQUdBLElBQ25CLEdBQUluQixLQUFLQyxJQUFJNUksS0FBS2dILE9BQU84QyxHQUFLdEIsRUFBT1AsR0FBRzZCLElBQU1yQixFQUMxQyxPQUFPLEVBR2YsT0FBTyxFQUVYMEMsY0FLSSxPQUpBbkwsS0FBS29ILEVBQUksRUFDVHBILEtBQUtxSCxFQUFJLEVBQ1RySCxLQUFLc0gsRUFBSSxFQUNUdEgsS0FBS3VILEVBQUksRUFDRnZILEtBRVhpUyxhQUNJLE1BQU03SyxFQUFJcEgsS0FBS29ILEVBQ1RDLEVBQUlySCxLQUFLcUgsRUFDVEMsRUFBSXRILEtBQUtzSCxFQUVmLE9BREF0SCxLQUFLdUgsR0FBS29CLEtBQUtFLEtBQUtGLEtBQUtDLElBQUksRUFBTXhCLEVBQUlBLEVBQUlDLEVBQUlBLEVBQUlDLEVBQUlBLElBQ2hEdEgsS0FFWDJMLFVBQ0ksTUFBTTZELEVBQU1tQyxFQUFLbkMsSUFBSXhQLEtBQU1BLE1BQzNCLElBQUt3UCxFQUVELE9BREF4UCxLQUFLbUgsS0FBTyxDQUFDLEVBQUcsRUFBRyxFQUFHLEdBQ2ZuSCxLQUVYLE1BQU1rUyxFQUFTMUMsRUFBTSxFQUFNQSxFQUFNLEVBS2pDLE9BSkF4UCxLQUFLb0gsSUFBTThLLEVBQ1hsUyxLQUFLcUgsSUFBTTZLLEVBQ1hsUyxLQUFLc0gsSUFBTTRLLEVBQ1hsUyxLQUFLdUgsR0FBSzJLLEVBQ0hsUyxLQUVYbVMsWUFJSSxPQUhBblMsS0FBS2dILE9BQU8sS0FBTyxFQUNuQmhILEtBQUtnSCxPQUFPLEtBQU8sRUFDbkJoSCxLQUFLZ0gsT0FBTyxLQUFPLEVBQ1poSCxLQUVYNEcsU0FDSSxNQUFNUSxFQUFJcEgsS0FBS29ILEVBQ1RDLEVBQUlySCxLQUFLcUgsRUFDVEMsRUFBSXRILEtBQUtzSCxFQUNUQyxFQUFJdkgsS0FBS3VILEVBQ2YsT0FBT29CLEtBQUtFLEtBQUt6QixFQUFJQSxFQUFJQyxFQUFJQSxFQUFJQyxFQUFJQSxFQUFJQyxFQUFJQSxHQUVqRDZCLFVBQVVmLEdBQ0RBLElBQ0RBLEVBQU9ySSxNQUVYLE1BQU1vSCxFQUFJcEgsS0FBS29ILEVBQ1RDLEVBQUlySCxLQUFLcUgsRUFDVEMsRUFBSXRILEtBQUtzSCxFQUNUQyxFQUFJdkgsS0FBS3VILEVBQ2YsSUFBSVgsRUFBUytCLEtBQUtFLEtBQUt6QixFQUFJQSxFQUFJQyxFQUFJQSxFQUFJQyxFQUFJQSxFQUFJQyxFQUFJQSxHQUNuRCxPQUFLWCxHQU9MQSxFQUFTLEVBQUlBLEVBQ2J5QixFQUFLakIsRUFBSUEsRUFBSVIsRUFDYnlCLEVBQUtoQixFQUFJQSxFQUFJVCxFQUNieUIsRUFBS2YsRUFBSUEsRUFBSVYsRUFDYnlCLEVBQUtkLEVBQUlBLEVBQUlYLEVBQ055QixJQVhIQSxFQUFLakIsRUFBSSxFQUNUaUIsRUFBS2hCLEVBQUksRUFDVGdCLEVBQUtmLEVBQUksRUFDVGUsRUFBS2QsRUFBSSxFQUNGYyxHQVNmVSxJQUFJcUosR0FDQSxJQUFLLElBQUl0SSxFQUFJLEVBQUdBLEVBQUksRUFBR0EsSUFDbkI5SixLQUFLZ0gsT0FBTzhDLElBQU1zSSxFQUFNbkssR0FBRzZCLEdBRS9CLE9BQU85SixLQUVYaUosU0FBU21KLEdBQ0wsTUFBTUMsRUFBTXJTLEtBQUtnSCxPQUFPLEdBQ2xCc0wsRUFBTXRTLEtBQUtnSCxPQUFPLEdBQ2xCdUwsRUFBTXZTLEtBQUtnSCxPQUFPLEdBQ2xCd0wsRUFBTXhTLEtBQUtnSCxPQUFPLEdBQ2xCeUwsRUFBTUwsRUFBTWhMLEVBQ1pzTCxFQUFNTixFQUFNL0ssRUFDWnNMLEVBQU1QLEVBQU05SyxFQUNac0wsRUFBTVIsRUFBTTdLLEVBS2xCLE9BSkF2SCxLQUFLb0gsRUFBSWlMLEVBQU1PLEVBQU1KLEVBQU1DLEVBQU1ILEVBQU1LLEVBQU1KLEVBQU1HLEVBQ25EMVMsS0FBS3FILEVBQUlpTCxFQUFNTSxFQUFNSixFQUFNRSxFQUFNSCxFQUFNRSxFQUFNSixFQUFNTSxFQUNuRDNTLEtBQUtzSCxFQUFJaUwsRUFBTUssRUFBTUosRUFBTUcsRUFBTU4sRUFBTUssRUFBTUosRUFBTUcsRUFDbkR6UyxLQUFLdUgsRUFBSWlMLEVBQU1JLEVBQU1QLEVBQU1JLEVBQU1ILEVBQU1JLEVBQU1ILEVBQU1JLEVBQzVDM1MsS0FFWDZNLGFBQWFyRSxFQUFRSCxHQUNaQSxJQUNEQSxFQUFPLElBQUl5RSxHQUVmLE1BQU0xRixFQUFJb0IsRUFBT3BCLEVBQ1hDLEVBQUltQixFQUFPbkIsRUFDWEMsRUFBSWtCLEVBQU9sQixFQUNYdUwsRUFBSzdTLEtBQUtvSCxFQUNWMEwsRUFBSzlTLEtBQUtxSCxFQUNWMEwsRUFBSy9TLEtBQUtzSCxFQUNWMEwsRUFBS2hULEtBQUt1SCxFQUNWMEwsRUFBS0QsRUFBSzVMLEVBQUkwTCxFQUFLeEwsRUFBSXlMLEVBQUsxTCxFQUM1QjZMLEVBQUtGLEVBQUszTCxFQUFJMEwsRUFBSzNMLEVBQUl5TCxFQUFLdkwsRUFDNUI2TCxFQUFLSCxFQUFLMUwsRUFBSXVMLEVBQUt4TCxFQUFJeUwsRUFBSzFMLEVBQzVCZ00sR0FBTVAsRUFBS3pMLEVBQUkwTCxFQUFLekwsRUFBSTBMLEVBQUt6TCxFQUluQyxPQUhBZSxFQUFLakIsRUFBSTZMLEVBQUtELEVBQUtJLEdBQU1QLEVBQUtLLEdBQU1ILEVBQUtJLEdBQU1MLEVBQy9DekssRUFBS2hCLEVBQUk2TCxFQUFLRixFQUFLSSxHQUFNTixFQUFLSyxHQUFNTixFQUFLSSxHQUFNRixFQUMvQzFLLEVBQUtmLEVBQUk2TCxFQUFLSCxFQUFLSSxHQUFNTCxFQUFLRSxHQUFNSCxFQUFLSSxHQUFNTCxFQUN4Q3hLLEVBRVgwRSxPQUFPMUUsR0FDRUEsSUFDREEsRUFBTyxJQUFJMkUsR0FFZixNQUFNNUYsRUFBSXBILEtBQUtvSCxFQUNUQyxFQUFJckgsS0FBS3FILEVBQ1RDLEVBQUl0SCxLQUFLc0gsRUFDVEMsRUFBSXZILEtBQUt1SCxFQUNUK0ksRUFBS2xKLEVBQUlBLEVBQ1RvSixFQUFLbkosRUFBSUEsRUFDVGdNLEVBQUsvTCxFQUFJQSxFQUNUZ00sRUFBS2xNLEVBQUlrSixFQUNUOUksRUFBS0osRUFBSW9KLEVBQ1QrQyxFQUFLbk0sRUFBSWlNLEVBQ1RHLEVBQUtuTSxFQUFJbUosRUFDVGlELEVBQUtwTSxFQUFJZ00sRUFDVEssRUFBS3BNLEVBQUkrTCxFQUNUTSxFQUFLcE0sRUFBSStJLEVBQ1RzRCxFQUFLck0sRUFBSWlKLEVBQ1RxRCxFQUFLdE0sRUFBSThMLEVBWWYsT0FYQWhMLEVBQUs3RixLQUFLLENBQ04sR0FBS2dSLEVBQUtFLEdBQ1ZsTSxFQUFLcU0sRUFDTE4sRUFBS0ssRUFDTHBNLEVBQUtxTSxFQUNMLEdBQUtQLEVBQUtJLEdBQ1ZELEVBQUtFLEVBQ0xKLEVBQUtLLEVBQ0xILEVBQUtFLEVBQ0wsR0FBS0wsRUFBS0UsS0FFUG5MLEVBRVhvSSxPQUFPcEksR0FDRUEsSUFDREEsRUFBTyxJQUFJd0IsR0FFZixNQUFNekMsRUFBSXBILEtBQUtvSCxFQUNUQyxFQUFJckgsS0FBS3FILEVBQ1RDLEVBQUl0SCxLQUFLc0gsRUFDVEMsRUFBSXZILEtBQUt1SCxFQUNUK0ksRUFBS2xKLEVBQUlBLEVBQ1RvSixFQUFLbkosRUFBSUEsRUFDVGdNLEVBQUsvTCxFQUFJQSxFQUNUZ00sRUFBS2xNLEVBQUlrSixFQUNUOUksRUFBS0osRUFBSW9KLEVBQ1QrQyxFQUFLbk0sRUFBSWlNLEVBQ1RHLEVBQUtuTSxFQUFJbUosRUFDVGlELEVBQUtwTSxFQUFJZ00sRUFDVEssRUFBS3BNLEVBQUkrTCxFQUNUTSxFQUFLcE0sRUFBSStJLEVBQ1RzRCxFQUFLck0sRUFBSWlKLEVBQ1RxRCxFQUFLdE0sRUFBSThMLEVBbUJmLE9BbEJBaEwsRUFBSzdGLEtBQUssQ0FDTixHQUFLZ1IsRUFBS0UsR0FDVmxNLEVBQUtxTSxFQUNMTixFQUFLSyxFQUNMLEVBQ0FwTSxFQUFLcU0sRUFDTCxHQUFLUCxFQUFLSSxHQUNWRCxFQUFLRSxFQUNMLEVBQ0FKLEVBQUtLLEVBQ0xILEVBQUtFLEVBQ0wsR0FBS0wsRUFBS0UsR0FDVixFQUNBLEVBQ0EsRUFDQSxFQUNBLElBRUduTCxFQUVYbUIsV0FBV3NLLEVBQUlDLEdBQ1gsT0FBT0QsRUFBRzFNLEVBQUkyTSxFQUFHM00sRUFBSTBNLEVBQUd6TSxFQUFJME0sRUFBRzFNLEVBQUl5TSxFQUFHeE0sRUFBSXlNLEVBQUd6TSxFQUFJd00sRUFBR3ZNLEVBQUl3TSxFQUFHeE0sRUFFL0RpQyxXQUFXc0ssRUFBSUMsRUFBSTFMLEdBUWYsT0FQS0EsSUFDREEsRUFBTyxJQUFJc0osR0FFZnRKLEVBQUtqQixFQUFJME0sRUFBRzFNLEVBQUkyTSxFQUFHM00sRUFDbkJpQixFQUFLaEIsRUFBSXlNLEVBQUd6TSxFQUFJME0sRUFBRzFNLEVBQ25CZ0IsRUFBS2YsRUFBSXdNLEVBQUd4TSxFQUFJeU0sRUFBR3pNLEVBQ25CZSxFQUFLZCxFQUFJdU0sRUFBR3ZNLEVBQUl3TSxFQUFHeE0sRUFDWmMsRUFFWG1CLGVBQWVzSyxFQUFJQyxFQUFJMUwsR0FDZEEsSUFDREEsRUFBTyxJQUFJc0osR0FFZixNQUFNVSxFQUFNeUIsRUFBRzFNLEVBQ1RrTCxFQUFNd0IsRUFBR3pNLEVBQ1RrTCxFQUFNdUIsRUFBR3hNLEVBQ1RrTCxFQUFNc0IsRUFBR3ZNLEVBQ1RrTCxFQUFNc0IsRUFBRzNNLEVBQ1RzTCxFQUFNcUIsRUFBRzFNLEVBQ1RzTCxFQUFNb0IsRUFBR3pNLEVBQ1RzTCxFQUFNbUIsRUFBR3hNLEVBS2YsT0FKQWMsRUFBS2pCLEVBQUlpTCxFQUFNTyxFQUFNSixFQUFNQyxFQUFNSCxFQUFNSyxFQUFNSixFQUFNRyxFQUNuRHJLLEVBQUtoQixFQUFJaUwsRUFBTU0sRUFBTUosRUFBTUUsRUFBTUgsRUFBTUUsRUFBTUosRUFBTU0sRUFDbkR0SyxFQUFLZixFQUFJaUwsRUFBTUssRUFBTUosRUFBTUcsRUFBTU4sRUFBTUssRUFBTUosRUFBTUcsRUFDbkRwSyxFQUFLZCxFQUFJaUwsRUFBTUksRUFBTVAsRUFBTUksRUFBTUgsRUFBTUksRUFBTUgsRUFBTUksRUFDNUN0SyxFQUVYbUIsYUFBYXNLLEVBQUlDLEVBQUkxTCxHQUNaQSxJQUNEQSxFQUFPLElBQUlzSixHQUVmLE1BQU1VLEVBQU15QixFQUFHMU0sRUFDVGtMLEVBQU13QixFQUFHek0sRUFDVGtMLEVBQU11QixFQUFHeE0sRUFDVGtMLEVBQU1zQixFQUFHdk0sRUFDVGtMLEVBQU1zQixFQUFHM00sRUFDVHNMLEVBQU1xQixFQUFHMU0sRUFDVHNMLEVBQU1vQixFQUFHek0sRUFDVHNMLEVBQU1tQixFQUFHeE0sRUFLZixPQUpBYyxFQUFLakIsRUFBSW9MLEVBQU1HLEVBQU1KLEVBQU1LLEVBQU1QLEVBQU1LLEVBQU1KLEVBQU1HLEVBQ25EcEssRUFBS2hCLEVBQUltTCxFQUFNSSxFQUFNUCxFQUFNSSxFQUFNSCxFQUFNSSxFQUFNSCxFQUFNSSxFQUNuRHRLLEVBQUtmLEVBQUlrTCxFQUFNQyxFQUFNSixFQUFNTyxFQUFNTixFQUFNSyxFQUFNSixFQUFNRyxFQUNuRHJLLEVBQUtkLEVBQUlpTCxFQUFNRSxFQUFNSixFQUFNTSxFQUFNTCxFQUFNRSxFQUFNSixFQUFNTSxFQUM1Q3RLLEVBRVhtQixnQkFBZ0JzSyxFQUFJQyxFQUFJckssRUFBTXJCLEdBSTFCLEdBSEtBLElBQ0RBLEVBQU8sSUFBSXNKLEdBRVhqSSxHQUFRLEVBRVIsT0FEQXJCLEVBQUtsQixLQUFPMk0sRUFBRzNNLEtBQ1JrQixFQUVOLEdBQUlxQixHQUFRLEVBRWIsT0FEQXJCLEVBQUtsQixLQUFPNE0sRUFBRzVNLEtBQ1JrQixFQUVYLElBQUlxRixFQUFNaUUsRUFBS25DLElBQUlzRSxFQUFJQyxHQUN2QixNQUFNQyxFQUFNRCxFQUFHM0wsT0FLZixJQUFJNkwsRUFDQUMsRUFDSixHQU5JeEcsRUFBTSxJQUNOc0csRUFBSXJJLFVBQ0orQixHQUFPQSxHQUlQQSxFQUFNLE1BQ051RyxFQUFLLEVBQUl2SyxFQUNUd0ssRUFBSyxFQUFJeEssTUFFUixDQUNELE1BQU04RCxFQUFNN0UsS0FBS0UsS0FBSyxFQUFJNkUsRUFBTUEsR0FDMUJMLEVBQVExRSxLQUFLa0osTUFBTXJFLEVBQUtFLEdBQ3hCeUcsRUFBYSxFQUFJM0csRUFDdkJ5RyxFQUFLdEwsS0FBSzZFLEtBQUssRUFBSTlELEdBQVEyRCxHQUFTOEcsRUFDcENELEVBQUt2TCxLQUFLNkUsS0FBSyxFQUFJOUQsR0FBUTJELEdBQVM4RyxFQU14QyxPQUpBOUwsRUFBS2pCLEVBQUk2TSxFQUFLSCxFQUFHMU0sRUFBSThNLEVBQUtGLEVBQUk1TSxFQUM5QmlCLEVBQUtoQixFQUFJNE0sRUFBS0gsRUFBR3pNLEVBQUk2TSxFQUFLRixFQUFJM00sRUFDOUJnQixFQUFLZixFQUFJMk0sRUFBS0gsRUFBR3hNLEVBQUk0TSxFQUFLRixFQUFJMU0sRUFDOUJlLEVBQUtkLEVBQUkwTSxFQUFLSCxFQUFHdk0sRUFBSTJNLEVBQUtGLEVBQUl6TSxFQUN2QmMsRUFFWG1CLFdBQVdzSyxFQUFJQyxFQUFJckssRUFBTXJCLEdBQ2hCQSxJQUNEQSxFQUFPLElBQUlzSixHQUVmLE1BQU15QyxFQUFlTixFQUFHMU0sRUFBSTJNLEVBQUczTSxFQUFJME0sRUFBR3pNLEVBQUkwTSxFQUFHMU0sRUFBSXlNLEVBQUd4TSxFQUFJeU0sRUFBR3pNLEVBQUl3TSxFQUFHdk0sRUFBSXdNLEVBQUd4TSxFQUN6RSxHQUFJb0IsS0FBS0MsSUFBSXdMLElBQWlCLEVBRTFCLE9BREEvTCxFQUFLbEIsS0FBTzJNLEVBQUczTSxLQUNSa0IsRUFFWCxNQUFNZ00sRUFBWTFMLEtBQUsyTCxLQUFLRixHQUN0QkcsRUFBZTVMLEtBQUtFLEtBQUssRUFBTXVMLEVBQWVBLEdBQ3BELEdBQUl6TCxLQUFLQyxJQUFJMkwsR0FBZ0IsS0FLekIsT0FKQWxNLEVBQUtqQixFQUFXLEdBQVAwTSxFQUFHMU0sRUFBaUIsR0FBUDJNLEVBQUczTSxFQUN6QmlCLEVBQUtoQixFQUFXLEdBQVB5TSxFQUFHek0sRUFBaUIsR0FBUDBNLEVBQUcxTSxFQUN6QmdCLEVBQUtmLEVBQVcsR0FBUHdNLEVBQUd4TSxFQUFpQixHQUFQeU0sRUFBR3pNLEVBQ3pCZSxFQUFLZCxFQUFXLEdBQVB1TSxFQUFHdk0sRUFBaUIsR0FBUHdNLEVBQUd4TSxFQUNsQmMsRUFFWCxNQUFNbU0sRUFBUzdMLEtBQUs2RSxLQUFLLEVBQUk5RCxHQUFRMkssR0FBYUUsRUFDNUNFLEVBQVM5TCxLQUFLNkUsSUFBSTlELEVBQU8ySyxHQUFhRSxFQUs1QyxPQUpBbE0sRUFBS2pCLEVBQUkwTSxFQUFHMU0sRUFBSW9OLEVBQVNULEVBQUczTSxFQUFJcU4sRUFDaENwTSxFQUFLaEIsRUFBSXlNLEVBQUd6TSxFQUFJbU4sRUFBU1QsRUFBRzFNLEVBQUlvTixFQUNoQ3BNLEVBQUtmLEVBQUl3TSxFQUFHeE0sRUFBSWtOLEVBQVNULEVBQUd6TSxFQUFJbU4sRUFDaENwTSxFQUFLZCxFQUFJdU0sRUFBR3ZNLEVBQUlpTixFQUFTVCxFQUFHeE0sRUFBSWtOLEVBQ3pCcE0sRUFFWG1CLHFCQUFxQjhELEVBQU1ELEVBQU9oRixHQUN6QkEsSUFDREEsRUFBTyxJQUFJc0osR0FFZnRFLEdBQVMsR0FDVCxNQUFNRyxFQUFNN0UsS0FBSzZFLElBQUlILEdBS3JCLE9BSkFoRixFQUFLakIsRUFBSWtHLEVBQUtsRyxFQUFJb0csRUFDbEJuRixFQUFLaEIsRUFBSWlHLEVBQUtqRyxFQUFJbUcsRUFDbEJuRixFQUFLZixFQUFJZ0csRUFBS2hHLEVBQUlrRyxFQUNsQm5GLEVBQUtkLEVBQUlvQixLQUFLK0UsSUFBSUwsR0FDWGhGLEVBRVhtQixtQkFBbUJrTCxFQUFHQyxFQUFHdE0sR0FDaEJBLElBQ0RBLEVBQU8sSUFBSXNKLEVBQUssQ0FBQyxFQUFHLEVBQUcsRUFBRyxLQUU5QixJQUFJaUQsRUFxQ1osU0FBZXhOLEVBQUdTLEVBQUdELEdBQ2pCLEdBQUlSLEVBQUlTLEVBQ0osT0FBT0EsRUFFTixHQUFJVCxFQUFJUSxFQUNULE9BQU9BLEVBRVgsT0FBT1IsRUE1Q0t5TixDQUFNL0gsRUFBSzBDLElBQUlrRixFQUFHQyxJQUFLLEVBQUcsR0FDOUJySCxFQUFPUixFQUFLeUMsTUFBTW1GLEVBQUdDLEdBQ3JCM0IsRUFBS3JLLEtBQUtFLEtBQUs2TCxFQUFFNUwsZ0JBQWtCNkwsRUFBRTdMLGlCQUFtQjhMLEVBSzVELE9BSkk1QixFQUFLLE9BQ0wzSyxFQUFPLElBQUlzSixFQUFLLEVBQUUrQyxFQUFFcE4sRUFBR29OLEVBQUVyTixFQUFHcU4sRUFBRXROLEVBQUcsSUFBSWdDLGFBRXpDZixFQUFPLElBQUlzSixFQUFLLENBQUNxQixFQUFJMUYsRUFBS2xHLEVBQUdrRyxFQUFLakcsRUFBR2lHLEVBQUtoRyxJQUFJOEIsWUFHbERJLHVCQUF1QnBDLEVBQUdDLEVBQUdDLEVBQUd3TixFQUFTek0sR0FDaENBLElBQ0RBLEVBQU8sSUFBSXNKLEVBQUssQ0FBQyxFQUFHLEVBQUcsRUFBRyxLQUU5QixJQUNJaUQsRUFETyxJQUFJOUgsRUFBSyxDQUFDMUYsRUFBR0MsRUFBR0MsSUFDZFYsU0FDYixHQUFTLEdBQUxnTyxFQUNBLE9BQU9qRCxFQUFLdEMsU0FFaEJ1RixFQUFJLEVBQUlBLEVBQ1IsSUFBSUcsRUFBVSxFQUVWQSxFQURBRCxFQUFVLEVBQ1csRUFBVm5NLEtBQUtxRyxLQUFZLEVBQUk4RixHQUFxQixFQUFWbk0sS0FBS3FHLElBR3RDOEYsR0FBcUIsRUFBVm5NLEtBQUtxRyxJQUU5QixJQUFJZ0csRUFBUXJNLEtBQUs2RSxJQUFJdUgsRUFBVSxHQUMzQkUsRUFBUXRNLEtBQUsrRSxJQUFJcUgsRUFBVSxHQU0vQixPQUxBMU0sRUFBS2pCLEVBQUl3TixFQUFJeE4sRUFBSTROLEVBQ2pCM00sRUFBS2hCLEVBQUl1TixFQUFJdk4sRUFBSTJOLEVBQ2pCM00sRUFBS2YsRUFBSXNOLEVBQUl0TixFQUFJME4sRUFDakIzTSxFQUFLZCxFQUFJME4sRUFDVDVNLEVBQUtlLFlBQ0VmLEdBR2ZzSixFQUFLdEMsVUFBVyxJQUFJc0MsR0FBT3hHLGNDeGJaLE1BQU0yQixFQUNqQi9NLFlBQVlpSCxHQUNSaEgsS0FBS2dILE9BQVMsSUFBSUMsYUFBYSxRQUNoQkMsSUFBWEYsSUFDQWhILEtBQUt5SCxJQUFNVCxHQUdmSSxRQUNBLE9BQU9wSCxLQUFLZ0gsT0FBTyxHQUVuQkssUUFDQSxPQUFPckgsS0FBS2dILE9BQU8sR0FFbkJNLFFBQ0EsT0FBT3RILEtBQUtnSCxPQUFPLEdBRW5CUSxTQUNBLE1BQU8sQ0FBQ3hILEtBQUtnSCxPQUFPLEdBQUloSCxLQUFLZ0gsT0FBTyxJQUVwQ1MsVUFDQSxNQUFPLENBQUN6SCxLQUFLZ0gsT0FBTyxHQUFJaEgsS0FBS2dILE9BQU8sR0FBSWhILEtBQUtnSCxPQUFPLElBRXBESSxNQUFFNUcsR0FDRlIsS0FBS2dILE9BQU8sR0FBS3hHLEVBRWpCNkcsTUFBRTdHLEdBQ0ZSLEtBQUtnSCxPQUFPLEdBQUt4RyxFQUVqQjhHLE1BQUU5RyxHQUNGUixLQUFLZ0gsT0FBTyxHQUFLeEcsRUFFakJnSCxPQUFHUixHQUNIaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FFeEJTLFFBQUlULEdBQ0poSCxLQUFLZ0gsT0FBTyxHQUFLQSxFQUFPLEdBQ3hCaEgsS0FBS2dILE9BQU8sR0FBS0EsRUFBTyxHQUN4QmhILEtBQUtnSCxPQUFPLEdBQUtBLEVBQU8sR0FFNUJpQixHQUFHQyxHQUNDLE9BQU9sSSxLQUFLZ0gsT0FBT2tCLEdBRXZCQyxRQUNJbkksS0FBS29ILEVBQUksRUFDVHBILEtBQUtxSCxFQUFJLEVBQ1RySCxLQUFLc0gsRUFBSSxFQUViYyxLQUFLQyxHQU9ELE9BTktBLElBQ0RBLEVBQU8sSUFBSXlFLEdBRWZ6RSxFQUFLakIsRUFBSXBILEtBQUtvSCxFQUNkaUIsRUFBS2hCLEVBQUlySCxLQUFLcUgsRUFDZGdCLEVBQUtmLEVBQUl0SCxLQUFLc0gsRUFDUGUsRUFFWEMsT0FBT0QsR0FPSCxPQU5LQSxJQUNEQSxFQUFPckksTUFFWHFJLEVBQUtqQixHQUFLcEgsS0FBS29ILEVBQ2ZpQixFQUFLaEIsR0FBS3JILEtBQUtxSCxFQUNmZ0IsRUFBS2YsR0FBS3RILEtBQUtzSCxFQUNSZSxFQUVYRSxPQUFPQyxFQUFRQyxFQUFZQyxNQUN2QixRQUFJQyxLQUFLQyxJQUFJNUksS0FBS29ILEVBQUlvQixFQUFPcEIsR0FBS3FCLE9BRzlCRSxLQUFLQyxJQUFJNUksS0FBS3FILEVBQUltQixFQUFPbkIsR0FBS29CLE1BRzlCRSxLQUFLQyxJQUFJNUksS0FBS3NILEVBQUlrQixFQUFPbEIsR0FBS21CLElBS3RDN0IsU0FDSSxPQUFPK0IsS0FBS0UsS0FBSzdJLEtBQUs4SSxpQkFFMUJBLGdCQUNJLE1BQU0xQixFQUFJcEgsS0FBS29ILEVBQ1RDLEVBQUlySCxLQUFLcUgsRUFDVEMsRUFBSXRILEtBQUtzSCxFQUNmLE9BQU9GLEVBQUlBLEVBQUlDLEVBQUlBLEVBQUlDLEVBQUlBLEVBRS9CeUIsSUFBSVAsR0FJQSxPQUhBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNqQnJILEtBQUtzSCxHQUFLa0IsRUFBT2xCLEVBQ1Z0SCxLQUVYZ0osU0FBU1IsR0FJTCxPQUhBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNqQnJILEtBQUtzSCxHQUFLa0IsRUFBT2xCLEVBQ1Z0SCxLQUVYaUosU0FBU1QsR0FJTCxPQUhBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNqQnJILEtBQUtzSCxHQUFLa0IsRUFBT2xCLEVBQ1Z0SCxLQUVYa0osT0FBT1YsR0FJSCxPQUhBeEksS0FBS29ILEdBQUtvQixFQUFPcEIsRUFDakJwSCxLQUFLcUgsR0FBS21CLEVBQU9uQixFQUNqQnJILEtBQUtzSCxHQUFLa0IsRUFBT2xCLEVBQ1Z0SCxLQUVYbUosTUFBTTNJLEVBQU82SCxHQU9ULE9BTktBLElBQ0RBLEVBQU9ySSxNQUVYcUksRUFBS2pCLEdBQUs1RyxFQUNWNkgsRUFBS2hCLEdBQUs3RyxFQUNWNkgsRUFBS2YsR0FBSzlHLEVBQ0g2SCxFQUVYZSxVQUFVZixHQUNEQSxJQUNEQSxFQUFPckksTUFFWCxJQUFJNEcsRUFBUzVHLEtBQUs0RyxTQUNsQixPQUFlLElBQVhBLEVBQ081RyxLQUVJLElBQVg0RyxHQUNBeUIsRUFBS2pCLEVBQUksRUFDVGlCLEVBQUtoQixFQUFJLEVBQ1RnQixFQUFLZixFQUFJLEVBQ0ZlLElBRVh6QixFQUFTLEVBQU1BLEVBQ2Z5QixFQUFLakIsR0FBS1IsRUFDVnlCLEVBQUtoQixHQUFLVCxFQUNWeUIsRUFBS2YsR0FBS1YsRUFDSHlCLEdBRVg2TSxlQUFlNUwsRUFBUWpCLEdBSW5CLE9BSEtBLElBQ0RBLEVBQU9ySSxNQUVKc0osRUFBT3VELGFBQWE3TSxLQUFNcUksR0FFckM4TSxlQUFlQyxFQUFZL00sR0FJdkIsT0FIS0EsSUFDREEsRUFBT3JJLE1BRUpvVixFQUFXdkksYUFBYTdNLEtBQU1xSSxHQUV6Q3FJLE9BQU9ySSxHQUNFQSxJQUNEQSxFQUFPLElBQUlzSixHQUVmLE1BQU1sRSxFQUFJLElBQUlYLEVBQ1JTLEVBQUksSUFBSVQsRUFXZCxPQVZBVyxFQUFFckcsRUFBSXVCLEtBQUsrRSxJQUFhLEdBQVQxTixLQUFLb0gsR0FDcEJtRyxFQUFFbkcsRUFBSXVCLEtBQUs2RSxJQUFhLEdBQVR4TixLQUFLb0gsR0FDcEJxRyxFQUFFcEcsRUFBSXNCLEtBQUsrRSxJQUFhLEdBQVQxTixLQUFLcUgsR0FDcEJrRyxFQUFFbEcsRUFBSXNCLEtBQUs2RSxJQUFhLEdBQVR4TixLQUFLcUgsR0FDcEJvRyxFQUFFbkcsRUFBSXFCLEtBQUsrRSxJQUFhLEdBQVQxTixLQUFLc0gsR0FDcEJpRyxFQUFFakcsRUFBSXFCLEtBQUs2RSxJQUFhLEdBQVR4TixLQUFLc0gsR0FDcEJlLEVBQUtqQixFQUFJbUcsRUFBRW5HLEVBQUlxRyxFQUFFcEcsRUFBSW9HLEVBQUVuRyxFQUFJbUcsRUFBRXJHLEVBQUltRyxFQUFFbEcsRUFBSWtHLEVBQUVqRyxFQUN6Q2UsRUFBS2hCLEVBQUlvRyxFQUFFckcsRUFBSW1HLEVBQUVsRyxFQUFJb0csRUFBRW5HLEVBQUlpRyxFQUFFbkcsRUFBSXFHLEVBQUVwRyxFQUFJa0csRUFBRWpHLEVBQ3pDZSxFQUFLZixFQUFJbUcsRUFBRXJHLEVBQUlxRyxFQUFFcEcsRUFBSWtHLEVBQUVqRyxFQUFJaUcsRUFBRW5HLEVBQUltRyxFQUFFbEcsRUFBSW9HLEVBQUVuRyxFQUN6Q2UsRUFBS2QsRUFBSWtHLEVBQUVyRyxFQUFJcUcsRUFBRXBHLEVBQUlvRyxFQUFFbkcsRUFBSWlHLEVBQUVuRyxFQUFJbUcsRUFBRWxHLEVBQUlrRyxFQUFFakcsRUFDbENlLEVBRVhtQixhQUFhaEIsRUFBUWlCLEVBQVNwQixHQUNyQkEsSUFDREEsRUFBTyxJQUFJeUUsR0FFZixNQUFNMUYsRUFBSW9CLEVBQU9wQixFQUNYQyxFQUFJbUIsRUFBT25CLEVBQ1hDLEVBQUlrQixFQUFPbEIsRUFDWGdKLEVBQUs3RyxFQUFRckMsRUFDYm9KLEVBQUsvRyxFQUFRcEMsRUFDYmdNLEVBQUs1SixFQUFRbkMsRUFJbkIsT0FIQWUsRUFBS2pCLEVBQUlDLEVBQUlnTSxFQUFLL0wsRUFBSWtKLEVBQ3RCbkksRUFBS2hCLEVBQUlDLEVBQUlnSixFQUFLbEosRUFBSWlNLEVBQ3RCaEwsRUFBS2YsRUFBSUYsRUFBSW9KLEVBQUtuSixFQUFJaUosRUFDZmpJLEVBRVhtQixXQUFXaEIsRUFBUWlCLEdBQ2YsTUFBTXJDLEVBQUlvQixFQUFPcEIsRUFDWEMsRUFBSW1CLEVBQU9uQixFQUNYQyxFQUFJa0IsRUFBT2xCLEVBSWpCLE9BQU9GLEVBSElxQyxFQUFRckMsRUFHSEMsRUFGTG9DLEVBQVFwQyxFQUVNQyxFQURkbUMsRUFBUW5DLEVBR3ZCa0MsZ0JBQWdCaEIsRUFBUWlCLEdBQ1ZBLEVBQVFyQyxFQUFJb0IsRUFBT3BCLEVBQ25CcUMsRUFBUXBDLEVBQUltQixFQUFPbkIsRUFDbkJvQyxFQUFRbkMsRUFBSWtCLEVBQU9sQixFQUM3QixPQUFPcUIsS0FBS0UsS0FBSzdJLEtBQUt1USxnQkFBZ0IvSCxFQUFRaUIsSUFFbERELHVCQUF1QmhCLEVBQVFpQixHQUMzQixNQUFNckMsRUFBSXFDLEVBQVFyQyxFQUFJb0IsRUFBT3BCLEVBQ3ZCQyxFQUFJb0MsRUFBUXBDLEVBQUltQixFQUFPbkIsRUFDdkJDLEVBQUltQyxFQUFRbkMsRUFBSWtCLEVBQU9sQixFQUM3QixPQUFPRixFQUFJQSxFQUFJQyxFQUFJQSxFQUFJQyxFQUFJQSxFQUUvQmtDLGlCQUFpQmhCLEVBQVFpQixFQUFTcEIsR0FDekJBLElBQ0RBLEVBQU8sSUFBSXlFLEdBRWYsTUFBTTFGLEVBQUlvQixFQUFPcEIsRUFBSXFDLEVBQVFyQyxFQUN2QkMsRUFBSW1CLEVBQU9uQixFQUFJb0MsRUFBUXBDLEVBQ3ZCQyxFQUFJa0IsRUFBT2xCLEVBQUltQyxFQUFRbkMsRUFDN0IsSUFBSVYsRUFBUytCLEtBQUtFLEtBQUt6QixFQUFJQSxFQUFJQyxFQUFJQSxFQUFJQyxFQUFJQSxHQUMzQyxPQUFlLElBQVhWLEdBQ0F5QixFQUFLakIsRUFBSSxFQUNUaUIsRUFBS2hCLEVBQUksRUFDVGdCLEVBQUtmLEVBQUksRUFDRmUsSUFFWHpCLEVBQVMsRUFBSUEsRUFDYnlCLEVBQUtqQixFQUFJQSxFQUFJUixFQUNieUIsRUFBS2hCLEVBQUlBLEVBQUlULEVBQ2J5QixFQUFLZixFQUFJQSxFQUFJVixFQUNOeUIsR0FFWG1CLFdBQVdoQixFQUFRaUIsRUFBU0MsRUFBTXJCLEdBTzlCLE9BTktBLElBQ0RBLEVBQU8sSUFBSXlFLEdBRWZ6RSxFQUFLakIsRUFBSW9CLEVBQU9wQixFQUFJc0MsR0FBUUQsRUFBUXJDLEVBQUlvQixFQUFPcEIsR0FDL0NpQixFQUFLaEIsRUFBSW1CLEVBQU9uQixFQUFJcUMsR0FBUUQsRUFBUXBDLEVBQUltQixFQUFPbkIsR0FDL0NnQixFQUFLZixFQUFJa0IsRUFBT2xCLEVBQUlvQyxHQUFRRCxFQUFRbkMsRUFBSWtCLEVBQU9sQixHQUN4Q2UsRUFFWG1CLFdBQVdoQixFQUFRaUIsRUFBU3BCLEdBT3hCLE9BTktBLElBQ0RBLEVBQU8sSUFBSXlFLEdBRWZ6RSxFQUFLakIsRUFBSW9CLEVBQU9wQixFQUFJcUMsRUFBUXJDLEVBQzVCaUIsRUFBS2hCLEVBQUltQixFQUFPbkIsRUFBSW9DLEVBQVFwQyxFQUM1QmdCLEVBQUtmLEVBQUlrQixFQUFPbEIsRUFBSW1DLEVBQVFuQyxFQUNyQmUsRUFFWG1CLGtCQUFrQmhCLEVBQVFpQixFQUFTcEIsR0FPL0IsT0FOS0EsSUFDREEsRUFBTyxJQUFJeUUsR0FFZnpFLEVBQUtqQixFQUFJb0IsRUFBT3BCLEVBQUlxQyxFQUFRckMsRUFDNUJpQixFQUFLaEIsRUFBSW1CLEVBQU9uQixFQUFJb0MsRUFBUXBDLEVBQzVCZ0IsRUFBS2YsRUFBSWtCLEVBQU9sQixFQUFJbUMsRUFBUW5DLEVBQ3JCZSxFQUVYbUIsZUFBZWhCLEVBQVFpQixFQUFTcEIsR0FPNUIsT0FOS0EsSUFDREEsRUFBTyxJQUFJeUUsR0FFZnpFLEVBQUtqQixFQUFJb0IsRUFBT3BCLEVBQUlxQyxFQUFRckMsRUFDNUJpQixFQUFLaEIsRUFBSW1CLEVBQU9uQixFQUFJb0MsRUFBUXBDLEVBQzVCZ0IsRUFBS2YsRUFBSWtCLEVBQU9sQixFQUFJbUMsRUFBUW5DLEVBQ3JCZSxFQUVYbUIsZ0JBQWdCaEIsRUFBUWlCLEVBQVNwQixHQU83QixPQU5LQSxJQUNEQSxFQUFPLElBQUl5RSxHQUVmekUsRUFBS2pCLEVBQUlvQixFQUFPcEIsRUFBSXFDLEVBQVFyQyxFQUM1QmlCLEVBQUtoQixFQUFJbUIsRUFBT25CLEVBQUlvQyxFQUFRcEMsRUFDNUJnQixFQUFLZixFQUFJa0IsRUFBT2xCLEVBQUltQyxFQUFRbkMsRUFDckJlLEVBRVhtQixjQUFjaEosRUFBTzZVLEVBQVVoTixHQUN0QkEsSUFDREEsRUFBTyxJQUFJeUUsR0FFZixJQUFJMUYsRUFBSSxHQUFLaU8sRUFBU2hPLEVBQUk3RyxFQUFNOEcsRUFBSStOLEVBQVMvTixFQUFJOUcsRUFBTTZHLEdBQ25EQSxFQUFJLEdBQUtnTyxFQUFTL04sRUFBSTlHLEVBQU00RyxFQUFJaU8sRUFBU2pPLEVBQUk1RyxFQUFNOEcsR0FDbkRBLEVBQUksR0FBSytOLEVBQVNqTyxFQUFJNUcsRUFBTTZHLEVBQUlnTyxFQUFTaE8sRUFBSTdHLEVBQU00RyxHQUl2RCxPQUhBaUIsRUFBS2pCLEVBQUk1RyxFQUFNNEcsRUFBSUEsRUFBSWlPLEVBQVM5TixHQUFLOE4sRUFBU2hPLEVBQUlDLEVBQUkrTixFQUFTL04sRUFBSUQsR0FDbkVnQixFQUFLaEIsRUFBSTdHLEVBQU02RyxFQUFJQSxFQUFJZ08sRUFBUzlOLEdBQUs4TixFQUFTL04sRUFBSUYsRUFBSWlPLEVBQVNqTyxFQUFJRSxHQUNuRWUsRUFBS2YsRUFBSTlHLEVBQU04RyxFQUFJQSxFQUFJK04sRUFBUzlOLEdBQUs4TixFQUFTak8sRUFBSUMsRUFBSWdPLEVBQVNoTyxFQUFJRCxHQUM1RGlCLEdBR2Z5RSxFQUFLbkQsS0FBTyxJQUFJbUQsRUFBSyxDQUFDLEVBQUcsRUFBRyxJQUM1QkEsRUFBS2xELElBQU0sSUFBSWtELEVBQUssQ0FBQyxFQUFHLEVBQUcsSUFDM0JBLEVBQUtzQyxHQUFLLElBQUl0QyxFQUFLLENBQUMsRUFBRyxFQUFHLElBQzFCQSxFQUFLd0IsTUFBUSxJQUFJeEIsRUFBSyxDQUFDLEVBQUcsRUFBRyxJQUM3QkEsRUFBS3dJLFFBQVUsSUFBSXhJLEVBQUssQ0FBQyxFQUFHLEVBQUcsSUMvUmhCLE1BQU15SSxVQUF1QnRQLEVBQ3hDbEcsWUFBWXVCLEdBQ1JnQixRQUNBdEMsS0FBS3NCLFFBQVVBLEVBQ2Z0QixLQUFLd1YsTUFBUXhWLEtBQUtzQixRQUFRa0UsYUFBYUMsYUFDdkN6RixLQUFLeVYsU0FBV3pWLEtBQUtzQixRQUFRa0UsYUFBYWlRLFNBQzFDelYsS0FBS3dDLE9BRVRBLFFBR0FrVCxlQUNJLE1BQU10UyxFQUFPcEQsS0FBS3NCLFFBQVFrRSxhQUFhTSxlQU12QyxPQUxBMUMsRUFBS3VTLGFBQWUsT0FDcEJ2UyxFQUFLd1MsY0FBZ0IsU0FDckJ4UyxFQUFLeVMsWUFBYyxHQUNuQnpTLEVBQUswUyxZQUFjLEVBQ25CMVMsRUFBSzJTLFFBQVEvVixLQUFLd1YsT0FDWHBTLEVBRVg0UyxZQUNJLE9BQU9oVyxLQUFLd1YsTUFFaEJTLFdBQ0ksT0FBT2pXLEtBQUt3VixNQUVoQlUsb0JBQW9COU8sRUFBR0MsRUFBR0MsR0FDdEJ0SCxLQUFLeVYsU0FBU1UsWUFBWS9PLEVBQUdDLEVBQUdDLEdBRXBDOE8sdUJBQXVCZCxFQUFTZSxHQUM1QixJQUFJQyxFQUFNLElBQUl4SixFQUFLLENBQUN3SSxFQUFRbE8sRUFBR2tPLEVBQVFqTyxFQUFHaU8sRUFBUWhPLElBQzlDOEgsRUFBS2tILEVBQUlsTyxPQUNiMEUsRUFBS3lDLE1BQU1ILEVBQUksSUFBSXRDLEVBQUssQ0FBQ3VKLEVBQU1qUCxFQUFHaVAsRUFBTWhQLEVBQUdnUCxFQUFNL08sSUFBSzhILEdBQ3REdEMsRUFBS3lDLE1BQU1ILEVBQUlrSCxFQUFLbEgsR0FDcEJrSCxFQUFJbE4sWUFDSmdHLEVBQUdoRyxZQUNIcEosS0FBS3lWLFNBQVNjLGVBQWVELEVBQUlsUCxFQUFHa1AsRUFBSWpQLEVBQUdpUCxFQUFJaFAsRUFBRzhILEVBQUdoSSxFQUFHZ0ksRUFBRy9ILEVBQUcrSCxFQUFHOUgsSUN0QzFELE1BQU1rUCxFQUNqQnpXLFlBQVl1QixFQUFTbVYsRUFBT0MsRUFBT3ZTLEdBQy9CbkUsS0FBSzJXLFFBQVUsR0FDZjNXLEtBQUtzQixRQUFVQSxFQUNmdEIsS0FBS3lXLE1BQVFBLEVBQ2J6VyxLQUFLNFcsVUFBWUYsRUFDakIxVyxLQUFLNlcsV0FBYTFTLEVBQ2xCbkUsS0FBSzhXLG9CQUVUQyxZQUFZQyxHQUNSaFgsS0FBSzJXLFFBQVEzVixLQUFLZ1csR0FDbEJoWCxLQUFLOFcsb0JBRVRHLGFBQWFELEdBQ1RoWCxLQUFLMlcsUUFBUXJRLFNBQVM0USxJQUNkRixJQUFXRSxHQUNYQSxFQUFXQyxnQkFHbkJuWCxLQUFLMlcsUUFBVTNXLEtBQUsyVyxRQUFRalYsUUFBUXdWLEdBQWVGLElBQVdFLElBQzlEbFgsS0FBSzhXLG9CQUVUQSxvQkFDSSxHQUEyQixHQUF2QjlXLEtBQUsyVyxRQUFRL1AsT0FFYixZQURBNUcsS0FBSzRXLFVBQVViLFFBQVEvVixLQUFLNlcsWUFHaEMsSUFBSU8sRUFBVSxLQUNWQyxFQUFXLEtBQ2ZyWCxLQUFLMlcsUUFBUXJRLFNBQVMwUSxJQUNsQkksRUFBVUosRUFDTkssRUFDQUQsRUFBUUUsYUFBYUQsRUFBU3JCLGFBRzlCb0IsRUFBUUUsYUFBYXRYLEtBQUs0VyxXQUU5QlMsRUFBV0QsS0FFWEEsR0FDQUEsRUFBUUcsY0FBY3ZYLEtBQUs2VyxhQ3JDeEIsTUFBTVcsRUFDakJ6WCxZQUFZeVYsRUFBT2xVLEVBQVNtVyxHQUFlLEdBQ3ZDelgsS0FBS3dWLE1BQVFBLEVBQ2J4VixLQUFLc0IsUUFBVUEsRUFDZnRCLEtBQUt5WCxhQUFlQSxFQUNwQnpYLEtBQUt3QyxPQUVUQSxPQUNJeEMsS0FBSzBYLFdBQWExWCxLQUFLc0IsUUFBUW1FLGFBQy9CekYsS0FBSzJYLFNBQVczWCxLQUFLc0IsUUFBUW1FLGFBQzdCekYsS0FBSzRYLGFBQWU1WCxLQUFLc0IsUUFBUW1FLGFBQ2pDekYsS0FBSzZYLE9BQVM3WCxLQUFLc0IsUUFBUW1FLGFBQzNCekYsS0FBS3dWLE1BQU1RLFlBQVlELFFBQVEvVixLQUFLMlgsVUFFcEMzWCxLQUFLMlgsU0FBUzVCLFFBQVEvVixLQUFLMFgsWUFDM0IxWCxLQUFLMlcsUUFBVSxJQUFJSCxFQUFZeFcsS0FBS3NCLFFBQVN0QixLQUFNQSxLQUFLMFgsV0FBWTFYLEtBQUs2WCxRQUN6RTdYLEtBQUs0WCxhQUFhN0IsUUFBUS9WLEtBQUs2WCxRQUMzQjdYLEtBQUt5WCxjQUNMelgsS0FBSzhYLGdCQUFrQjlYLEtBQUtzQixRQUFRa0UsYUFBYXVTLHNCQUFzQixHQUN2RS9YLEtBQUtnWSxjQUFnQmhZLEtBQUtzQixRQUFRa0UsYUFBYXlTLG9CQUFvQixHQUNuRWpZLEtBQUs2WCxPQUFPOUIsUUFBUS9WLEtBQUs4WCxpQkFDekI5WCxLQUFLOFgsZ0JBQWdCL0IsUUFBUS9WLEtBQUtnWSxjQUFlLEVBQUcsR0FDcERoWSxLQUFLOFgsZ0JBQWdCL0IsUUFBUS9WLEtBQUtnWSxjQUFlLEVBQUcsR0FDcERoWSxLQUFLZ1ksY0FBY2pDLFFBQVEvVixLQUFLc0IsUUFBUW9FLHlCQUd4QzFGLEtBQUs2WCxPQUFPOUIsUUFBUS9WLEtBQUtzQixRQUFRb0Usd0JBR3pDd1MsZ0JBQWdCeEIsR0FDWkEsRUFBTVgsUUFBUS9WLEtBQUs2WCxRQUV2Qk0sWUFBWXpCLEdBQ1JBLEVBQU1YLFFBQVEvVixLQUFLNFgsY0FFdkJiLFlBQVlDLEdBQ1JoWCxLQUFLMlcsUUFBUUksWUFBWUMsR0FFN0JDLGFBQWFELEdBQ1RoWCxLQUFLMlcsUUFBUU0sYUFBYUQsSUMzQzNCLElBQUlvQixHQUNYLFNBQVdBLEdBQ1BBLEVBQVdBLEVBQXdCLFlBQUksR0FBSyxjQUM1Q0EsRUFBV0EsRUFBcUIsU0FBSSxHQUFLLFdBQ3pDQSxFQUFXQSxFQUF5QixhQUFJLEdBQUssZUFIakQsQ0FJR0EsSUFBZUEsRUFBYSxLQ0ZoQixNQUFNQyxFQUNqQnRZLFlBQVkwVyxFQUFPakIsRUFBT2xVLEVBQVNnWCxFQUFTLEtBQU1DLEVBQU9ILEVBQVdJLGFBQ2hFeFksS0FBS2tQLFNBQVcsQ0FDWjlILEVBQUcsRUFDSEMsRUFBRyxFQUNIQyxFQUFHLEdBRVB0SCxLQUFLc1ksT0FBU0EsRUFDZHRZLEtBQUtzQixRQUFVQSxFQUNmdEIsS0FBS3dWLE1BQVFBLEVBQ2J4VixLQUFLeVcsTUFBUUEsRUFDYnpXLEtBQUt1WSxLQUFPQSxFQUNadlksS0FBS3lZLGFBQWUsRUFDcEJ6WSxLQUFLMFksT0FBUyxFQUNkMVksS0FBS3dDLE9BRVRBLE9BQ0l4QyxLQUFLMlksS0FBTzNZLEtBQUtzQixRQUFRbUUsYUFFekJ6RixLQUFLa0MsS0FBT2xDLEtBQUtrQyxLQUFLc0IsS0FBS3hELE1BRS9CNFksWUFDSSxPQUFPNVksS0FBS3NZLE9BRWhCTyxVQUFVM1gsR0FDTmxCLEtBQUtzWSxPQUFTcFgsRUFDVmxCLEtBQUs4WSxhQUNMOVksS0FBSytZLE9BQ0wvWSxLQUFLOFksWUFBYSxHQUcxQkMsS0FBS0MsRUFBTyxFQUFHQyxFQUFTLEVBQUdDLEdBQVdsWixLQUFLc1ksT0FBU3RZLEtBQUtzWSxPQUFPWSxTQUFXLElBQ25FbFosS0FBS21aLFNBQVduWixLQUFLb0QsTUFDckJwRCxLQUFLa0MsT0FFSmxDLEtBQUtzWSxRQUlMdFksS0FBS29ELE9BQ05wRCxLQUFLb0QsS0FBT3BELEtBQUtzQixRQUFRc0UscUJBQ3pCNUYsS0FBS29ELEtBQUtrVixPQUFTdFksS0FBS3NZLE9BQ3hCdFksS0FBS29aLHFCQUVMcFosS0FBS29ELE9BQ0xwRCxLQUFLb0QsS0FBS3FWLGFBQWFqWSxNQUFRUixLQUFLeVksYUFDcEN6WSxLQUFLb0QsS0FBS2lXLE1BQU1MLEVBQU1DLEVBQVFDLEdBQzlCbFosS0FBS29ELEtBQUtrVyxLQUFPdFosS0FBS3VaLFFBQ3RCdlosS0FBS21aLFNBQVUsRUFDWG5aLEtBQUt3WixXQUNMeFosS0FBS3daLFVBQVVyRCxZQUFZblcsS0FBS2tQLFNBQVM5SCxFQUFHcEgsS0FBS2tQLFNBQVM3SCxFQUFHckgsS0FBS2tQLFNBQVM1SCxHQUUvRXRILEtBQUtvRCxLQUFLcVcsaUJBQWlCLFFBQVN6WixLQUFLa0MsUUFoQnpDbEMsS0FBSzhZLFlBQWEsRUFtQjFCM0MsWUFBWS9PLEVBQUdDLEVBQUdDLEdBQ2R0SCxLQUFLa1AsU0FBVyxDQUNaOUgsRUFBQUEsRUFDQUMsRUFBQUEsRUFDQUMsRUFBQUEsR0FFQXRILEtBQUt3WixXQUNMeFosS0FBS3daLFVBQVVyRCxZQUFZL08sRUFBR0MsRUFBR0MsR0FFekNvUyxnQkFBZ0IvVixHQUNaM0QsS0FBS3lZLGFBQWU5VSxFQUNoQjNELEtBQUtvRCxPQUNMcEQsS0FBS29ELEtBQUtxVixhQUFhalksTUFBUW1ELEdBRXZDZ1csa0JBQ0ksT0FBTzNaLEtBQUt5WSxhQUVoQm1CLFVBQVVsQixHQUNOMVksS0FBSzBZLE9BQVNBLEVBQ1YxWSxLQUFLMlksT0FDTDNZLEtBQUsyWSxLQUFLQSxLQUFLblksTUFBUWtZLEdBRS9CbUIsWUFDSSxPQUFPN1osS0FBSzBZLE9BRWhCVSxvQkFDSSxPQUFRcFosS0FBS3VZLE1BQ1QsS0FBS0gsRUFBV0ksWUFDUHhZLEtBQUt3WixZQUNOeFosS0FBS3daLFVBQVl4WixLQUFLd1YsTUFBTUUsZ0JBRWhDMVYsS0FBS29ELEtBQUsyUyxRQUFRL1YsS0FBSzJZLE1BQ3ZCM1ksS0FBSzJZLEtBQUs1QyxRQUFRL1YsS0FBS3daLFdBQ3ZCLE1BQ0osS0FBS3BCLEVBQVcwQixTQUNaOVosS0FBS29ELEtBQUsyUyxRQUFRL1YsS0FBSzJZLE1BQ3ZCM1ksS0FBS3lXLE1BQU0wQixZQUFZblksS0FBSzJZLE1BQzVCLE1BQ0osUUFDSTNZLEtBQUtvRCxLQUFLMlMsUUFBUS9WLEtBQUsyWSxNQUN2QjNZLEtBQUt5VyxNQUFNeUIsZ0JBQWdCbFksS0FBSzJZLE9BSTVDelcsT0FDSWxDLEtBQUttWixTQUFVLEVBQ1huWixLQUFLb0QsT0FDTHBELEtBQUtvRCxLQUFLMlcsb0JBQW9CLFFBQVMvWixLQUFLa0MsTUFDNUNsQyxLQUFLb0QsS0FBS2xCLE9BQ1ZsQyxLQUFLb0QsS0FBSytULGFBQ1ZuWCxLQUFLb0QsS0FBTyxLQUNacEQsS0FBS21aLFNBQVUsRUFDWG5aLEtBQUt3WixZQUNMeFosS0FBS3daLFVBQVVyQyxhQUNmblgsS0FBS3daLFVBQVksT0FJN0JRLFVBQ0loYSxLQUFLa0MsT0FFTGxDLEtBQUtvRCxLQUFPLEtBQ1pwRCxLQUFLd1osVUFBWSxLQUNqQnhaLEtBQUtzWSxPQUFTLEtBQ2R0WSxLQUFLc0IsUUFBVSxLQUNmdEIsS0FBS3lXLE1BQVEsS0FDYnpXLEtBQUt3VixNQUFRLEtBRWpCOEQsS0FBSzlZLEdBQ0RSLEtBQUt1WixRQUFVL1ksRUFDWFIsS0FBS29ELE9BQ0xwRCxLQUFLb0QsS0FBS2tXLEtBQU85WSxHQUd6QnlaLFFBQVF2USxHQUNKMUosS0FBSzJZLEtBQUtBLEtBQUt1QixlQUFlbGEsS0FBSzZaLFlBQWE3WixLQUFLc0IsUUFBUWtFLGFBQWEyVSxhQUNyRW5hLEtBQUtvRCxPQUdWcEQsS0FBSzJZLEtBQUtBLEtBQUt5Qiw2QkFBNkIsS0FBUXBhLEtBQUtzQixRQUFRa0UsYUFBYTJVLFlBQWN6USxHQUM1Rm5HLFlBQVcsSUFBTXZELEtBQUtrQyxRQUFlLElBQVB3SCxJQUVsQzJRLE9BQU8zUSxHQUNIMUosS0FBSzJZLEtBQUtBLEtBQUt1QixlQUFlLEtBQVFsYSxLQUFLc0IsUUFBUWtFLGFBQWEyVSxhQUMzRG5hLEtBQUtvRCxNQUNOcEQsS0FBSytZLE9BRVQvWSxLQUFLMlksS0FBS0EsS0FBS3lCLDZCQUE2QnBhLEtBQUswWSxPQUFRMVksS0FBS3NCLFFBQVFrRSxhQUFhMlUsWUFBY3pRLElDaEoxRixNQUFNNFEsRUFDakJ2YSxZQUFZd2EsRUFBTXJaLEVBQU8sS0FBTXNaLEVBQWMsTUFDekN4YSxLQUFLdWEsS0FBT0EsRUFDWnZhLEtBQUtrQixLQUFPQSxFQUNabEIsS0FBS3dhLFlBQWNBLEVBRXZCQyxVQUNJLE9BQU96YSxLQUFLa0IsS0FFaEJ3WixRQUFReFosR0FDSmxCLEtBQUtrQixLQUFPQSxFQUVoQnlaLGlCQUNJLE9BQU8zYSxLQUFLd2EsWUFFaEJJLGVBQWUxWixHQUNYbEIsS0FBS3dhLFlBQWN4YSxLQUFLd2EsWUFFNUJLLFVBQ0ksT0FBTzdhLEtBQUt1YSxLQUVoQk8sUUFBUVAsR0FDSnZhLEtBQUt1YSxLQUFPQSxHQ3ZCcEIsSUFBSSxFQUF3QyxTQUFValcsRUFBU0MsRUFBWUMsRUFBR0MsR0FFMUUsT0FBTyxJQUFLRCxJQUFNQSxFQUFJRSxXQUFVLFNBQVVDLEVBQVNDLEdBQy9DLFNBQVNDLEVBQVVyRSxHQUFTLElBQU1zRSxFQUFLTCxFQUFVTSxLQUFLdkUsSUFBVyxNQUFPd0UsR0FBS0osRUFBT0ksSUFDcEYsU0FBU0MsRUFBU3pFLEdBQVMsSUFBTXNFLEVBQUtMLEVBQWlCLE1BQUVqRSxJQUFXLE1BQU93RSxHQUFLSixFQUFPSSxJQUN2RixTQUFTRixFQUFLSSxHQUpsQixJQUFlMUUsRUFJYTBFLEVBQU9DLEtBQU9SLEVBQVFPLEVBQU8xRSxRQUoxQ0EsRUFJeUQwRSxFQUFPMUUsTUFKaERBLGFBQWlCZ0UsRUFBSWhFLEVBQVEsSUFBSWdFLEdBQUUsU0FBVUcsR0FBV0EsRUFBUW5FLE9BSVQ0RSxLQUFLUCxFQUFXSSxHQUNsR0gsR0FBTUwsRUFBWUEsRUFBVVksTUFBTWYsRUFBU0MsR0FBYyxLQUFLUSxZQUcvRCxNQUFNZ1csRUFDVDVhLElBQUk2YSxHQUNBLE9BQU8sRUFBVWhiLFVBQU0sT0FBUSxHQUFRLFlBQ25DLE1BQU1rRixRQUFlK1YsTUFBTUQsR0FFM0IsYUFEcUI5VixFQUFPZ1csa0JDWnhDLElBQUksRUFBd0MsU0FBVTVXLEVBQVNDLEVBQVlDLEVBQUdDLEdBRTFFLE9BQU8sSUFBS0QsSUFBTUEsRUFBSUUsV0FBVSxTQUFVQyxFQUFTQyxHQUMvQyxTQUFTQyxFQUFVckUsR0FBUyxJQUFNc0UsRUFBS0wsRUFBVU0sS0FBS3ZFLElBQVcsTUFBT3dFLEdBQUtKLEVBQU9JLElBQ3BGLFNBQVNDLEVBQVN6RSxHQUFTLElBQU1zRSxFQUFLTCxFQUFpQixNQUFFakUsSUFBVyxNQUFPd0UsR0FBS0osRUFBT0ksSUFDdkYsU0FBU0YsRUFBS0ksR0FKbEIsSUFBZTFFLEVBSWEwRSxFQUFPQyxLQUFPUixFQUFRTyxFQUFPMUUsUUFKMUNBLEVBSXlEMEUsRUFBTzFFLE1BSmhEQSxhQUFpQmdFLEVBQUloRSxFQUFRLElBQUlnRSxHQUFFLFNBQVVHLEdBQVdBLEVBQVFuRSxPQUlUNEUsS0FBS1AsRUFBV0ksR0FDbEdILEdBQU1MLEVBQVlBLEVBQVVZLE1BQU1mLEVBQVNDLEdBQWMsS0FBS1EsWUFNdkQsTUFBTW9XLFVBQWlCbFYsRUFDbENsRyxZQUFZdUIsRUFBUzhaLEVBQVMsSUFBSUwsRUFBY00sRUFBVSxLQUN0RC9ZLFFBQ0F0QyxLQUFLb2IsT0FBU0EsRUFDZHBiLEtBQUtrQixLQUFPLEdBQ1psQixLQUFLcWIsUUFBVUEsRUFDZnJiLEtBQUtzQixRQUFVQSxFQUVuQm5CLElBQUk2YSxHQUNBLE9BQU8sRUFBVWhiLFVBQU0sT0FBUSxHQUFRLFlBQ25DLEdBQUlBLEtBQUtrQixLQUFLOFosR0FDVixPQUFPaGIsS0FBS2tCLEtBQUs4WixHQUFNTCxpQkFFdEIsQ0FDRCxNQUFNckMsUUFBZXRZLEtBQUtvYixPQUFPamIsSUFBSTZhLEdBQy9CTSxRQUFnQnRiLEtBQUtzQixRQUFRdUUsZ0JBQWdCeVMsR0FDN0MzVyxFQUFPLElBQUkyWSxFQUFhVSxFQUFNMUMsRUFBUWdELEdBQzdCQyxPQUFPQyxLQUFLeGIsS0FBS2tCLE1BQU0wRixPQVV0QyxPQVRhNUcsS0FBS3FiLFFBQ2RyYixLQUFLa0IsS0FBSzhaLEdBQVFyWixFQVFmQSxFQUFLZ1oscUJBSXhCYyxRQUNJemIsS0FBS2tCLEtBQU8sSUM1Q0wsTUFBTXdhLFVDRE4sTUFDWDNiLFlBQVl1QixFQUFTbVYsRUFBT2tGLEdBQ3hCM2IsS0FBS3lXLE1BQVFBLEVBQ2J6VyxLQUFLc0IsUUFBVUEsRUFDZnRCLEtBQUs0YixhQUFlRCxFQUV4QnBFLGNBQWNuVSxHQUNWcEQsS0FBSzZiLFdBQVc5RixRQUFRM1MsR0FFNUJrVSxhQUFhbFUsR0FDVHBELEtBQUs0VyxVQUFZeFQsRUFDYnBELEtBQUs2YixZQUNMN2IsS0FBSzRXLFVBQVViLFFBQVEvVixLQUFLNmIsWUFHcEM3RixZQUNJLE9BQU9oVyxLQUFLNmIsV0FFaEIxRSxhQUNJblgsS0FBSzRXLFVBQVVPLGFBQ2ZuWCxLQUFLNmIsV0FBVzFFLGVEbEJwQnBYLFlBQVl1QixFQUFTbVYsRUFBT2tGLEdBQ3hCclosTUFBTWhCLEVBQVNtVixFQUFPa0YsR0FDdEJHLFFBQVFDLElBQUksc0JBQ1ovYixLQUFLNmIsV0FBYTdiLEtBQUtzQixRQUFRa0UsYUFBYXdXLGtCQUM1Q2hjLEtBQUs2YixXQUFXdkQsT0FBU3RZLEtBQUs0YixhQUFhdEQsT0FFL0NoQixhQUFhbFUsR0FDVHBELEtBQUs4WCxnQkFBa0I5WCxLQUFLc0IsUUFBUWtFLGFBQWF1UyxzQkFBc0IsR0FDdkUvWCxLQUFLZ1ksY0FBZ0JoWSxLQUFLc0IsUUFBUWtFLGFBQWF5UyxvQkFBb0IsR0FDbkVqWSxLQUFLOFgsZ0JBQWdCL0IsUUFBUS9WLEtBQUtnWSxjQUFlLEVBQUcsR0FDcERoWSxLQUFLOFgsZ0JBQWdCL0IsUUFBUS9WLEtBQUtnWSxjQUFlLEVBQUcsR0FDcERoWSxLQUFLOFgsZ0JBQWdCL0IsUUFBUS9WLEtBQUtnWSxjQUFlLEVBQUcsR0FDcERoWSxLQUFLOFgsZ0JBQWdCL0IsUUFBUS9WLEtBQUtnWSxjQUFlLEVBQUcsR0FDcEQ1VSxFQUFLMlMsUUFBUS9WLEtBQUs4WCxpQkFDbEI5WCxLQUFLZ1ksY0FBY2pDLFFBQVEvVixLQUFLNmIsWUFDaEM3YixLQUFLNFcsVUFBWXhULEdFaEJsQixNQUFNNlksRUFDVGxjLFlBQVkwVyxFQUFPakIsRUFBT2xVLEVBQVMwRSxFQUFTdVMsRUFBT0gsRUFBVzhELGNBQzFEbGMsS0FBS3lXLE1BQVFBLEVBQ2J6VyxLQUFLd1YsTUFBUUEsRUFDYnhWLEtBQUtzQixRQUFVQSxFQUNmdEIsS0FBS2dHLFFBQVVBLEVBQ2ZoRyxLQUFLdVksS0FBT0EsRUFDWnZZLEtBQUtrUCxTQUFXLENBQ1o5SCxFQUFHLEVBQ0hDLEVBQUcsRUFDSEMsRUFBRyxHQUVQdEgsS0FBS3dDLE9BRVRBLE9BQ0l4QyxLQUFLb0QsS0FBT3BELEtBQUtzQixRQUFReUUseUJBQXlCL0YsS0FBS2dHLFNBQ3ZEaEcsS0FBSzJZLEtBQU8zWSxLQUFLc0IsUUFBUW1FLGFBQ3pCekYsS0FBS29aLG9CQUNMcFosS0FBS2dHLFFBQVF5VCxpQkFBaUIsV0FBWTBDLElBQ3RDbmMsS0FBS29jLFNBQVUsRUFDWHBjLEtBQUtxYyxpQkFDTHJjLEtBQUsrWSxVQUlqQkEsS0FBS0MsRUFBTyxFQUFHQyxFQUFTLEVBQUdDLEVBQVcsR0FDOUJsWixLQUFLb2MsU0FDTHBjLEtBQUtnRyxRQUFRK1MsT0FFakIvWSxLQUFLcWMsaUJBQWtCLEVBRTNCbmEsT0FDSWxDLEtBQUtnRyxRQUFRc1csUUFFakJ6QyxZQUNJLE9BQU83WixLQUFLZ0csUUFBUTBTLE9BRXhCa0IsVUFBVXBaLEdBQ05SLEtBQUtnRyxRQUFRMFMsT0FBU2xZLEVBRTFCbVosa0JBQ0ksT0FBTzNaLEtBQUtnRyxRQUFReVMsYUFFeEJpQixnQkFBZ0JsWixHQUNaUixLQUFLZ0csUUFBUXlTLGFBQWVqWSxFQUVoQzRZLG9CQUNJLEdBQVFwWixLQUFLdVksT0FDSkgsRUFBV0ksWUFDUHhZLEtBQUt3WixZQUNOeFosS0FBS3daLFVBQVl4WixLQUFLd1YsTUFBTUUsZ0JBRWhDMVYsS0FBS29ELEtBQUsyUyxRQUFRL1YsS0FBSzJZLE1BQ3ZCM1ksS0FBSzJZLEtBQUs1QyxRQUFRL1YsS0FBS3daLGdCQUd2QnhaLEtBQUtvRCxLQUFLMlMsUUFBUS9WLEtBQUsyWSxNQUN2QjNZLEtBQUt5VyxNQUFNeUIsZ0JBQWdCbFksS0FBSzJZLE1BSTVDeEMsWUFBWS9PLEVBQUdDLEVBQUdDLEdBQ2R0SCxLQUFLa1AsU0FBVyxDQUNaOUgsRUFBQUEsRUFDQUMsRUFBQUEsRUFDQUMsRUFBQUEsR0FFQXRILEtBQUt3WixXQUNMeFosS0FBS3daLFVBQVVyRCxZQUFZL08sRUFBR0MsRUFBR0MsR0FFekMwUyxVQUNJaGEsS0FBS2tDLE9BQ0xsQyxLQUFLZ0csUUFBVSxLQUNmaEcsS0FBS3lXLE1BQVEsS0FDYnpXLEtBQUtzQixRQUFVLEtBQ2Z0QixLQUFLb0QsS0FBTyxLQUNacEQsS0FBS3daLFVBQVksS0FDakJ4WixLQUFLd1YsTUFBUSxLQUVqQjhELEtBQUs5WSxHQUNEUixLQUFLZ0csUUFBUXNULE1BQU8sRUFFeEJlLE9BQU8zUSxHQUNIMUosS0FBSzJZLEtBQUtBLEtBQUt1QixlQUFlLEtBQVFsYSxLQUFLc0IsUUFBUWtFLGFBQWEyVSxhQUMzRG5hLEtBQUtvRCxNQUNOcEQsS0FBSytZLE9BRVQvWSxLQUFLMlksS0FBS0EsS0FBS3lCLDZCQUE2QnBhLEtBQUs2WixZQUFhN1osS0FBS3NCLFFBQVFrRSxhQUFhMlUsWUFBY3pRLEdBRTFHdVEsUUFBUXZRLEdBQ0oxSixLQUFLMlksS0FBS0EsS0FBS3VCLGVBQWVsYSxLQUFLNlosWUFBYTdaLEtBQUtzQixRQUFRa0UsYUFBYTJVLGFBQ3JFbmEsS0FBS29ELE9BR1ZwRCxLQUFLMlksS0FBS0EsS0FBS3lCLDZCQUE2QixLQUFRcGEsS0FBS3NCLFFBQVFrRSxhQUFhMlUsWUFBY3pRLEdBQzVGbkcsWUFBVyxJQUFNdkQsS0FBS2tDLFFBQWUsSUFBUHdILEtDOUZ0QyxJQUFJLEVBQXdDLFNBQVVwRixFQUFTQyxFQUFZQyxFQUFHQyxHQUUxRSxPQUFPLElBQUtELElBQU1BLEVBQUlFLFdBQVUsU0FBVUMsRUFBU0MsR0FDL0MsU0FBU0MsRUFBVXJFLEdBQVMsSUFBTXNFLEVBQUtMLEVBQVVNLEtBQUt2RSxJQUFXLE1BQU93RSxHQUFLSixFQUFPSSxJQUNwRixTQUFTQyxFQUFTekUsR0FBUyxJQUFNc0UsRUFBS0wsRUFBaUIsTUFBRWpFLElBQVcsTUFBT3dFLEdBQUtKLEVBQU9JLElBQ3ZGLFNBQVNGLEVBQUtJLEdBSmxCLElBQWUxRSxFQUlhMEUsRUFBT0MsS0FBT1IsRUFBUU8sRUFBTzFFLFFBSjFDQSxFQUl5RDBFLEVBQU8xRSxNQUpoREEsYUFBaUJnRSxFQUFJaEUsRUFBUSxJQUFJZ0UsR0FBRSxTQUFVRyxHQUFXQSxFQUFRbkUsT0FJVDRFLEtBQUtQLEVBQVdJLEdBQ2xHSCxHQUFNTCxFQUFZQSxFQUFVWSxNQUFNZixFQUFTQyxHQUFjLEtBQUtRLFlBWXZELE1BQU13WCxFQUNqQnhjLFlBQVlxYixFQUFTLElBQUlMLEdBQ3JCL2EsS0FBS29iLE9BQVNBLEVBQ2RwYixLQUFLd2MsbUJBQXFCLEtBQzFCeGMsS0FBS3NCLFFBQVUsSUFBSWdFLEVBQ25CdEYsS0FBS3dWLE1BQVEsSUFBSUQsRUFBZXZWLEtBQUtzQixTQUNyQ3RCLEtBQUt5VyxNQUFRLElBQUllLEVBQVd4WCxLQUFLd1YsTUFBT3hWLEtBQUtzQixTQUFTLEdBQ3REdEIsS0FBS3ljLFNBQVcsSUFBSXRCLEVBQVNuYixLQUFLc0IsUUFBU3RCLEtBQUtvYixRQUVwRHNCLEtBQUsxQixFQUFNekMsRUFBT0gsRUFBV0ksYUFDekIsT0FBTyxFQUFVeFksVUFBTSxPQUFRLEdBQVEsWUFDbkMsTUFBTWtCLFFBQWFsQixLQUFLeWMsU0FBU3RjLElBQUk2YSxHQUVyQyxPQURlaGIsS0FBSzBWLGFBQWE2QyxFQUFNclgsTUFJL0N5YixjQUFjM0IsRUFBTXpDLEVBQU9ILEVBQVdJLGFBQ2xDLE1BQU1vRSxFQUFTLElBQUl2RSxFQUFZclksS0FBS3lXLE1BQU96VyxLQUFLd1YsTUFBT3hWLEtBQUtzQixRQUFTLEtBQU1pWCxHQUkzRSxPQUhBdlksS0FBS3ljLFNBQVN0YyxJQUFJNmEsR0FBTTVWLE1BQU1sRSxJQUMxQjBiLEVBQU8vRCxVQUFVM1gsTUFFZDBiLEVBRVhDLE9BQU83QixFQUFNekMsRUFBT0gsRUFBVzhELGNBQzNCLE1BQU1sVyxFQUFVLElBQUk4VyxNQUFNOUIsR0FDMUJoVixFQUFRK1csWUFBYyxZQUN0Qi9XLEVBQVEwUyxPQUFTLEVBRWpCLE9BRGUsSUFBSXVELEVBQWdCamMsS0FBS3lXLE1BQU96VyxLQUFLd1YsTUFBT3hWLEtBQUtzQixRQUFTMEUsRUFBU3VTLEdBR3RGN0MsYUFBYTZDLEVBQU1yWCxHQUNmLE9BQU8sSUFBSW1YLEVBQVlyWSxLQUFLeVcsTUFBT3pXLEtBQUt3VixNQUFPeFYsS0FBS3NCLFFBQVNKLEdBRWpFOGIsc0JBQXNCQyxHQUNsQixPQUFPLEVBQVVqZCxVQUFNLE9BQVEsR0FBUSxZQUluQyxHQUhJQSxLQUFLd2Msb0JBQ0x4YyxLQUFLeVcsTUFBTVEsYUFBYWpYLEtBQUt3YyxvQkFFcEIsT0FBVFMsRUFDQSxPQUVKLE1BQU0zRSxRQUFldFksS0FBS3ljLFNBQVN0YyxJQUFJOGMsR0FDdkNqZCxLQUFLd2MsbUJBQXFCLElBQUlkLEVBQVUxYixLQUFLc0IsUUFBU3RCLEtBQUt5VyxNQUFPLENBQzlENkIsT0FBQUEsSUFFSnRZLEtBQUt5VyxNQUFNTSxZQUFZL1csS0FBS3djLHVCQUdwQ3RHLG9CQUFvQjlPLEVBQUdDLEVBQUdDLEdBQ3RCdEgsS0FBS3dWLE1BQU1VLG9CQUFvQjlPLEVBQUdDLEVBQUdDLEdBRXpDOE8sdUJBQXVCZCxFQUFTbEcsR0FDNUJwUCxLQUFLd1YsTUFBTVksdUJBQXVCZCxFQUFTbEcsR0FFL0M4TixnQkFDSWxkLEtBQUt5YyxTQUFTaEIsU0N4RVAsTUFBTTBCLEVBQ2pCcGQsY0FDSUMsS0FBS29kLElBQU0sSUFBSWIsRUFDZnZjLEtBQUtxZCxTQUFXLEtBQ2hCcmQsS0FBS3NkLE1BQVEsS0FDYnRkLEtBQUt1ZCxlQUFpQixFQUN0QnZkLEtBQUt3ZCxZQUFjLEVBQ25CeGQsS0FBS3lkLFVBQVksRUFDakJ6ZCxLQUFLMGQsaUJBQW1CLEdBQ3hCMWQsS0FBSzJkLGNBQWdCLEdBR3pCNUUsS0FBS2tFLEdBQ0QsTUFBTVcsRUFBUTVkLEtBQUtvZCxJQUFJVCxjQUFjTSxHQUNyQ1csRUFBTWhFLFVBQVU1WixLQUFLeWQsV0FDckJHLEVBQU03RSxPQUdWOEUsa0JBQWtCWixHQUNkLEdBQUlBLElBQVNqZCxLQUFLMGQsaUJBQWxCLENBQ0EsR0FBSTFkLEtBQUtxZCxTQUFVLENBQ2YsTUFBTUssRUFBbUIxZCxLQUFLcWQsU0FDOUJyZCxLQUFLcWQsU0FBVyxLQUNoQjlaLFlBQVcsSUFBTW1hLEVBQWlCekQsUUFBUSxJQUFJLE1BQzlDMVcsWUFBVyxJQUFNbWEsRUFBaUIxRCxXQUFXLEtBRTVDaUQsSUFDTGpkLEtBQUswZCxpQkFBbUJULEVBQ3hCamQsS0FBS3FkLFNBQVdyZCxLQUFLb2QsSUFBSVAsT0FBT0ksRUFBTSxHQUN0Q2pkLEtBQUtxZCxTQUFTekQsVUFBVTVaLEtBQUt1ZCxnQkFDN0J2ZCxLQUFLcWQsU0FBU3RFLE9BQ2QvWSxLQUFLcWQsU0FBUy9ELE1BQUssR0FDbkJ0WixLQUFLcWQsU0FBU2hELE9BQU8sS0FHekJ5RCxTQUFTYixHQUNMLEdBQUlBLElBQVNqZCxLQUFLMmQsY0FBbEIsQ0FDQSxHQUFJM2QsS0FBS3NkLE1BQU8sQ0FDWixNQUFNSyxFQUFnQjNkLEtBQUtzZCxNQUMzQi9aLFlBQVcsSUFBTW9hLEVBQWMxRCxRQUFRLElBQUksS0FDM0MxVyxZQUFXLElBQU1vYSxFQUFjM0QsV0FBVyxLQUV6Q2lELElBQ0xqZCxLQUFLMmQsY0FBZ0JWLEVBQ3JCamQsS0FBS3NkLE1BQVF0ZCxLQUFLb2QsSUFBSVAsT0FBT0ksRUFBTSxHQUNuQ2pkLEtBQUtzZCxNQUFNMUQsVUFBVTVaLEtBQUt3ZCxhQUMxQnhkLEtBQUtzZCxNQUFNdkUsT0FDWC9ZLEtBQUtzZCxNQUFNakQsT0FBTyxLQUd0QjBELFdBQVdkLEdBQ1BqZCxLQUFLb2QsSUFBSUosc0JBQXNCQyxHQUduQ2UsZUFBZXRGLEdBQ1gxWSxLQUFLd2QsWUFBYzlFLEVBQ2YxWSxLQUFLc2QsT0FBT3RkLEtBQUtzZCxNQUFNMUQsVUFBVWxCLEdBR3pDdUYsa0JBQWtCdkYsR0FDZDFZLEtBQUt1ZCxlQUFpQjdFLEVBQ2xCMVksS0FBS3FkLFVBQVVyZCxLQUFLcWQsU0FBU3pELFVBQVVsQixHQUcvQ3dGLGFBQWF4RixHQUNUMVksS0FBS3lkLFVBQVkvRSxHQ2hFVixNQUFNeUYsRUFDakJwZSxjQUNJQyxLQUFLb2UsSUFBTSxJQUFJbGEsRUFBSSxJQUFJN0IsR0FDdkJyQyxLQUFLcWUsUUFBVTNiLFNBQVM0YixlQUFlLGVBQ3ZDdGUsS0FBSzRkLE1BQVEsSUFBSVQsRUFHckJvQixJQUFJQyxHQUNBLEdBQWUsS0FBWEEsRUFBZSxPQUNuQnhlLEtBQUs0ZCxNQUFNN0UsS0FBSyxxQkFDaEIsTUFBTTNWLEVBQU9WLFNBQVNDLGNBQWMsS0FDcEM2YixFQUFPQyxNQUFNLE1BQU1uWSxTQUFTb1ksSUFDeEJ0YixFQUFLSixZQUFZTixTQUFTVyxlQUFlcWIsSUFDekN0YixFQUFLSixZQUFZTixTQUFTQyxjQUFjLFVBRzVDM0MsS0FBS3FlLFFBQVFyYixZQUFZSSxHQUk3QjJWLEtBQUtrRSxHQUNEamQsS0FBSzRkLE1BQU03RSxLQUFLa0UsR0FHcEIwQixZQUFZMUIsR0FDUixPQUFPamQsS0FBSzRkLE1BQU1lLFlBQVkxQixHQUdsQ2EsU0FBU2IsR0FDTCxPQUFPamQsS0FBSzRkLE1BQU1FLFNBQVNiLEdBRy9CYyxXQUFXZCxHQUNQamQsS0FBSzRkLE1BQU1HLFdBQVdkLElDckNmLE1BQU0yQixFQUNqQjdlLFlBQVk4ZSxFQUFnQkMsR0FDeEI5ZSxLQUFLK2UsUUFBVUYsRUFDZjdlLEtBQUttRSxPQUFTMmEsRUFDZDllLEtBQUtnZixXQUFZLEVBQ2pCaGYsS0FBS2lmLFdBQWF2YyxTQUFTNGIsZUFBZSxjQUMxQ3RlLEtBQUtxZSxRQUFVLEdBQ2ZyZSxLQUFLa2YsY0FBZ0IsRUFDckJsZixLQUFLd0MsT0FHVDJjLFFBQVEzZSxHQUNKUixLQUFLZ2YsVUFBWXhlLEVBR3JCZ0MsT0FDSXhDLEtBQUtpZixXQUFXeEYsaUJBQWlCLFdBQVl6VSxJQUN6QyxHQUFjLFlBQVZBLEVBQUU1RSxJQUNFSixLQUFLa2YsY0FBZ0IsSUFDckJsZixLQUFLa2YsZ0JBQ0xsZixLQUFLaWYsV0FBV3plLE1BQVFSLEtBQUtxZSxRQUFRcmUsS0FBS2tmLHFCQUUzQyxHQUFjLGNBQVZsYSxFQUFFNUUsSUFDTEosS0FBS2tmLGNBQWdCbGYsS0FBS3FlLFFBQVF6WCxTQUNsQzVHLEtBQUtrZixnQkFDTGxmLEtBQUtpZixXQUFXemUsTUFBUVIsS0FBS3FlLFFBQVFyZSxLQUFLa2YsZ0JBQWtCLFNBRTdELEdBQWMsVUFBVmxhLEVBQUU1RSxJQUFpQixDQUMxQkosS0FBS29mLGtCQUFrQnBmLEtBQUtpZixXQUFXemUsT0FDdkMsTUFBTUcsRUFBTVgsS0FBS2lmLFdBQVd6ZSxNQUM1QlIsS0FBS2lmLFdBQVd6ZSxNQUFRLEdBQ3BCUixLQUFLZ2YsV0FBV2hmLEtBQUttRSxPQUFPb2EsSUFBSSxLQUFLNWQsS0FDekNYLEtBQUsrZSxRQUFRTSxVQUFVMWUsT0FLbkN5ZSxrQkFBa0JFLEdBQ2R0ZixLQUFLcWUsUUFBUXJkLEtBQUtzZSxHQUNsQnRmLEtBQUtrZixjQUFnQmxmLEtBQUtxZSxRQUFRelgsUUM3QjFDLE1BQU0yWSxFQUFrQixDQUNwQixDQUFDLENBQUMsT0FBUSxLQ1hDLFNBQXFCQyxFQUFNbGUsR0FDdEMsR0FBbUIsR0FBZmtlLEVBQUs1WSxPQUNMdEYsRUFBUW1lLGtCQUNMLENBQ0gsTUFDTUMsRUFET3BlLEVBQVFxZSxRQUFRcmUsRUFBUXNlLE9BQU92ZSxhQUN6QndlLFdBQ25CLElBQUlsZSxFQUFPLEtBQ1gsSUFBSyxJQUFJbUksS0FBSzRWLEVBQ1YsR0FBSTVWLEVBQUV5USxLQUFLdUYsU0FBU04sRUFBSyxJQUFLLENBQzFCN2QsRUFBT21JLEVBQ1AsTUFHUixJQUFLbkksRUFBTSxDQUNQLE1BQU0rZCxFQUFRcGUsRUFBUXNlLE9BQU9oZSxlQUM3QixJQUFLLElBQUlrSSxLQUFLNFYsRUFDVixHQUFJNVYsRUFBRXlRLEtBQUt1RixTQUFTTixFQUFLLElBQUssQ0FDMUI3ZCxFQUFPbUksRUFDUCxPQUlQbkksR0FHREwsRUFBUTZDLE9BQU9vYSxJQUFJLGVBQWU1YyxFQUFLNFksU0FDdkNqWixFQUFRNkMsT0FBT29hLElBQUk1YyxFQUFLb2UsY0FIeEJ6ZSxFQUFRNkMsT0FBT29hLElBQUksc0JBQXNCaUIsRUFBSyxVRFh0RCxDQUFDLENBQUMsTUFBTyxZRVpFM0IsZUFBMEIyQixFQUFNbGUsR0FDM0MsTUFDTW9lLEVBRE9wZSxFQUFRcWUsUUFBUXJlLEVBQVFzZSxPQUFPdmUsYUFDekJ3ZSxXQUNuQixJQUFJbGUsRUFBTyxLQUNYLElBQUssSUFBSW1JLEtBQUs0VixFQUNWLEdBQUk1VixFQUFFeVEsS0FBS3VGLFNBQVNOLEVBQUssSUFBSyxDQUMxQjdkLEVBQU9tSSxFQUNQLE1BR1IsSUFBS25JLEVBQU0sQ0FDUCxNQUFNK2QsRUFBUXBlLEVBQVFzZSxPQUFPaGUsZUFDN0IsSUFBSyxJQUFJa0ksS0FBSzRWLEVBQ1YsR0FBSTVWLEVBQUV5USxLQUFLdUYsU0FBU04sRUFBSyxJQUFLLENBQzFCN2QsRUFBT21JLEVBQ1AsT0FJUG5JLFFBR0tBLEVBQUtxZSxRQUZYMWUsRUFBUTZDLE9BQU9vYSxJQUFJLHNCQUFzQmlCLEVBQUssU0ZQbEQsQ0FBQyxDQUFDLE9BQVEsT0diQyxTQUFxQkEsRUFBTWxlLEdBQ3RDLE1BQU0yZSxFQUFPM2UsRUFBUXFlLFFBQVFyZSxFQUFRc2UsT0FBT3ZlLGFBQ3RDcWUsRUFBUU8sRUFBS0osV0FDbkIsSUFBSWxlLEVBQU8sS0FDWCxJQUFLLElBQUltSSxLQUFLNFYsRUFDVixHQUFJNVYsRUFBRXlRLEtBQUt1RixTQUFTTixFQUFLLElBQUssQ0FDMUI3ZCxFQUFPbUksRUFDUCxNQUdIbkksRUFHSUEsRUFBS3VlLFVBR05ELEVBQUt4ZSxXQUFXRSxFQUFLSCxJQUNyQkYsRUFBUXNlLE9BQU9yZSxRQUFRSSxFQUFLSCxJQUM1QkYsRUFBUTZlLE1BQU0sWUFBWXhlLEVBQUs0WSxTQUMvQjVZLEVBQUt5ZSxVQUxMOWUsRUFBUTZlLE1BQU0sa0JBQWtCeGUsRUFBSzRZLFNBSHpDalosRUFBUTZlLE1BQU0sc0JBQXNCWCxFQUFLLFNIRzdDLENBQUMsQ0FBQyxPQUFRLE9JZEMsU0FBcUJBLEVBQU1sZSxHQUN0QyxNQUFNMmUsRUFBTzNlLEVBQVFxZSxRQUFRcmUsRUFBUXNlLE9BQU92ZSxhQUN0Q3FlLEVBQVFwZSxFQUFRc2UsT0FBT2hlLGVBQzdCLElBQUlELEVBQU8sS0FDWCxJQUFLLElBQUltSSxLQUFLNFYsRUFDVixHQUFJNVYsRUFBRXlRLEtBQUt1RixTQUFTTixFQUFLLElBQUssQ0FDMUI3ZCxFQUFPbUksRUFDUCxNQUdIbkksR0FHREwsRUFBUXNlLE9BQU9uZSxXQUFXRSxFQUFLSCxJQUMvQnllLEVBQUsxZSxRQUFRSSxFQUFLSCxJQUNsQkYsRUFBUTZlLE1BQU0sV0FBV3hlLEVBQUs0WSwyQkFDOUI1WSxFQUFLMGUsVUFMTC9lLEVBQVE2ZSxNQUFNLHlCQUF5QlgsRUFBSyxRSkloRCxDQUFDLE9LZlUsU0FBcUJBLEVBQU1sZSxHQUN2QixNQUFYa2UsRUFBSyxJQUF5QixPQUFYQSxFQUFLLEdBQ3hCbGUsRUFBUTZlLE1BQU0seUJBRWQ3ZSxFQUFRZ2YsYUFBd0IsTUFBWGQsRUFBSyxJQUMxQmxlLEVBQVE2ZSxNQUFNLHVCQUF1QlgsRUFBSyxVTFc5QyxDQUFDLE9NaEJVLFNBQXFCQSxFQUFNbGUsR0FDdENBLEVBQVE2ZSxNQUFNLGtCQUNkN2UsRUFBUWlmLFNOZVIsQ0FBQyxPT2pCVSxTQUFxQmYsRUFBTWxlLEdBQ3RDQSxFQUFRNmUsTUFBTSxtQkFDZDdlLEVBQVFvYixTUGdCUixDQUFDLFNRbEJVLFNBQXVCOEMsRUFBTWxlLEdBQ3hDLEdBQUlrZSxFQUFLNVksT0FBUyxFQUNkLE9BQU90RixFQUFRNmUsTUFBTSw4Q0FFekIsTUFBTTNmLEVBQVFnZ0IsU0FBU2hCLEVBQUssSUFDNUIsR0FBSWhmLEVBQVEsS0FBT0EsRUFBUSxFQUN2QixPQUFPYyxFQUFRNmUsTUFBTSwwQ0FFekIsR0FBZSxPQUFYWCxFQUFLLEdBQ0xsZSxFQUFRNkMsT0FBT3laLE1BQU1NLGFBQWExZCxFQUFNLFVBQ3JDLEdBQWUsU0FBWGdmLEVBQUssR0FDWmxlLEVBQVE2QyxPQUFPeVosTUFBTUksZUFBZXhkLEVBQU0sU0FDdkMsSUFBZSxZQUFYZ2YsRUFBSyxHQUdaLE9BQU9sZSxFQUFRNmUsTUFBTSw4REFGckI3ZSxFQUFRNkMsT0FBT3laLE1BQU1LLGtCQUFrQnpkLEVBQU0sS0FJakRjLEVBQVE2ZSxNQUFNLEdBQUdYLEVBQUssb0JBQW9CaGYsUVJFMUMsQ0FBQyxDQUFDLElBQUssTUFBTyxhU25CSCxTQUEwQmdmLEVBQU1sZSxHQUMzQyxNQUFNb2UsRUFBUXBlLEVBQVFzZSxPQUFPaGUsZUFDN0IsR0FBSThkLEVBQU05WSxPQUFTLEVBQUcsT0FBT3RGLEVBQVE2ZSxNQUFNLGlDQUMzQyxJQUFJTSxFQUFrQixvQkFDdEJmLEVBQU1wWixTQUFRLENBQUMzRSxFQUFNdUcsS0FDYkEsRUFBUXdYLEVBQU05WSxPQUFTLEVBQ3ZCNlosR0FBbUIsR0FBRzllLEVBQUs0WSxTQUNwQnJTLEVBQVF3WCxFQUFNOVksT0FBUyxFQUM5QjZaLEdBQW1CLEdBQUc5ZSxFQUFLNFksWUFFM0JrRyxHQUFtQjllLEVBQUs0WSxRQUdoQ2paLEVBQVE2ZSxNQUFNTSxFQUFrQixRVFM5QkMsRUFBZSxDQUNqQixDQUFDLElBQUssU0FDTixDQUFDLEtBQU0sYUFDUCxDQUFDLElBQUssUUFDTixDQUFDLEtBQU0sYUFDUCxDQUFDLElBQUssU0FDTixDQUFDLEtBQU0sYUFDUCxDQUFDLElBQUssUUFDTixDQUFDLEtBQU0sYUFDUCxDQUFDLElBQUssTUFDTixDQUFDLElBQUssU0FHSyxNQUFNQyxFQUNqQjVnQixZQUFZdUIsRUFBU3NmLEdBQ2pCNWdCLEtBQUtzQixRQUFVQSxFQUNmdEIsS0FBSzRnQixTQUFXQSxHQUFZLElBQUkxZ0IsSUFDaENGLEtBQUs2Z0IsU0FBVSxFQUNmN2dCLEtBQUs4Z0IscUJBR1R6QixVQUFVQyxHQUNOLElBQUt0ZixLQUFLNmdCLFFBRU4sWUFEQTdnQixLQUFLc0IsUUFBUTZlLE1BQU0sZ0RBR3ZCLE1BQU1GLEVBQU9qZ0IsS0FBS3NCLFFBQVFxZSxRQUFRM2YsS0FBS3NCLFFBQVFzZSxPQUFPdmUsYUFDaERvZCxFQUFRYSxFQUFJYixNQUFNLEtBQ3BCemUsS0FBSzRnQixTQUFTemdCLElBQUlzZSxFQUFNLEtBQ3hCemUsS0FBSzRnQixTQUFTemdCLElBQUlzZSxFQUFNLEdBQXhCemUsQ0FBNEJ5ZSxFQUFPemUsS0FBS3NCLFNBRzVDLE1BQU15ZixFQUFZL2dCLEtBQUtnaEIsZUFBZXZDLEVBQU0sSUFFeEN3QixFQUFLZ0IsUUFBUUYsSUFDYi9nQixLQUFLc0IsUUFBUTRmLEtBQUtqQixFQUFLZ0IsUUFBUUYsSUFJdkNJLFdBQVc1RyxFQUFNNkcsR0FDVEMsTUFBTUMsUUFBUS9HLEdBQ2RBLEVBQUtqVSxTQUFTaWIsR0FBWXZoQixLQUFLNGdCLFNBQVNyZ0IsSUFBSWdoQixFQUFTSCxLQUVyRHBoQixLQUFLNGdCLFNBQVNyZ0IsSUFBSWdhLEVBQU02RyxHQUloQ0ksWUFBWVosR0FDUkEsRUFBU3RhLFNBQVNpYixJQUNkdmhCLEtBQUttaEIsV0FBV0ksRUFBUSxHQUFJQSxFQUFRLE9BSTVDVCxxQkFDSTlnQixLQUFLd2hCLFlBQVlqQyxHQUdyQnlCLGVBQWUxQixHQUNYLElBQUssSUFBSW1DLEtBQU9mLEVBQ1osR0FBSWUsRUFBSSxJQUFNbkMsRUFBSyxPQUFPbUMsRUFBSSxJVWpGM0IsTUFBTUMsRUFDakIzaEIsWUFBWXVCLEdBQ1J0QixLQUFLc0IsUUFBVUEsRUFHbkJpZixPQUNJLE1BQU1vQixFQUFVLENBQ1o1Z0IsTUFBT2YsS0FBS3NCLFFBQVFQLE1BQU1ILFlBQzFCZ2hCLGNBQWU1aEIsS0FBSzZoQix5QkFDcEJDLFdBQVk5aEIsS0FBSytoQixzQkFDakJuQyxPQUFvQixDQUNoQnZlLFlBQWFyQixLQUFLc0IsUUFBUXNlLE9BQU92ZSxZQUNqQ0QsVUFBV3BCLEtBQUtzQixRQUFRc2UsT0FBT3hlLFdBRW5DNGdCLFFBQVMsQ0FDTDFFLE1BQU90ZCxLQUFLc0IsUUFBUTZDLE9BQU95WixNQUFNSixZQUNqQ3lFLElBQUtqaUIsS0FBS3NCLFFBQVE2QyxPQUFPeVosTUFBTUgsVUFDL0JKLFNBQVVyZCxLQUFLc0IsUUFBUTZDLE9BQU95WixNQUFNTCxpQkFHNUMyRSxhQUFhQyxRQUFRLE9BQVFDLEtBQUtDLFVBQVVWLElBR2hEakYsT0FDSSxNQUFNNEYsRUFBVUYsS0FBS0csTUFBTUwsYUFBYXBnQixRQUFRLFNBQ2hEOUIsS0FBS3NCLFFBQVFQLE1BQU1FLFlBQVlxaEIsRUFBUXZoQixPQUN2Q2YsS0FBS3dpQix5QkFBeUJGLEVBQVFWLGVBQ3RDNWhCLEtBQUt5aUIsc0JBQXNCSCxFQUFRUixZQUNuQzloQixLQUFLMGlCLGtCQUFrQkosRUFBUTFDLFFBQy9CNWYsS0FBS3NCLFFBQVE2QyxPQUFPeVosTUFBTU0sYUFBYW9FLEVBQVFOLFFBQVFDLEtBQ3ZEamlCLEtBQUtzQixRQUFRNkMsT0FBT3laLE1BQU1JLGVBQWVzRSxFQUFRTixRQUFRMUUsT0FDekR0ZCxLQUFLc0IsUUFBUTZDLE9BQU95WixNQUFNSyxrQkFBa0JxRSxFQUFRTixRQUFRM0UsVUFHaEV3RSx5QkFDSSxPQUFPN2hCLEtBQUtzQixRQUFRcWhCLE1BQU05Z0IsS0FBS0YsR0FDcEIsQ0FBQ0EsRUFBS0gsR0FDVEcsRUFBS2loQixXQUtqQkoseUJBQXlCOUMsR0FDckJBLEVBQU1wWixTQUFTM0UsSUFDRTNCLEtBQUtzQixRQUFRcWUsUUFBUWhlLEVBQUssSUFDbENpaEIsUUFBVWpoQixFQUFLLE1BSTVCOGdCLHNCQUFzQi9DLEdBQ2xCQSxFQUFNcFosU0FBUzNFLElBQ0MzQixLQUFLc0IsUUFBUVEsUUFBUUgsRUFBSyxJQUNsQ1osTUFBTUUsWUFBWVUsRUFBSyxPQUluQytnQixrQkFBa0I5QyxHQUNkNWYsS0FBS3NCLFFBQVE0ZixLQUFLdEIsRUFBT3ZlLGFBQ3pCckIsS0FBS3NCLFFBQVFzZSxPQUFPeGUsVUFBWXdlLEVBQU94ZSxVQUczQzJnQixzQkFDSSxPQUFPL2hCLEtBQUtzQixRQUFRb2UsTUFBTTdkLEtBQUtGLEdBQ3BCLENBQUNBLEVBQUtILEdBQUlHLEVBQUtaLE1BQU1ILGdCQ3ZEekIsTUFBTWlpQixFQUNqQjlpQixZQUFZK2lCLEdBQVUsR0FDbEI5aUIsS0FBSzhpQixRQUFVQSxFQUNmOWlCLEtBQUs0ZixPQUFTLElBQUl6ZSxFQUNsQm5CLEtBQUtlLE1BQVEsSUFBSWpCLEVBQ2pCRSxLQUFLMmlCLE1BQVEsR0FDYjNpQixLQUFLMGYsTUFBUSxHQUNiMWYsS0FBS21FLE9BQVMsSUFBSWdhLEVBQ2xCbmUsS0FBSzZlLGVBQWlCLElBQUk4QixFQUFTM2dCLE1BQ25DQSxLQUFLMFcsTUFBUSxJQUFJa0ksRUFBTTVlLEtBQUs2ZSxlQUFnQjdlLEtBQUttRSxRQUNqRG5FLEtBQUsraUIsYUFBZSxJQUFJN2lCLElBQ3hCRixLQUFLZ2pCLFNBQVcsS0FDaEJoakIsS0FBSzBoQixjQUFnQixJQUFJQSxFQUFjMWhCLE1BRzNDbWdCLE1BQU0zQixHQUNGeGUsS0FBS21FLE9BQU9vYSxJQUFJQyxHQUdwQlgsV0FBV29GLEVBQU92WixHQUNkLElBQUssSUFBSWdWLEtBQVF1RSxFQUNiampCLEtBQUttZ0IsTUFBTXpCLFNBQ0wxZSxLQUFLa2pCLEtBQUt4WixHQUl4QmxILEtBQUt0QixHQUNEbEIsS0FBSzJpQixNQUFRemhCLEVBQUt5aEIsTUFBTTlnQixLQUFLb2UsSUFDekJBLEVBQUszZSxRQUFVdEIsS0FDUmlnQixLQUVYamdCLEtBQUswZixNQUFReGUsRUFBS3dlLE1BQU03ZCxLQUFLRixJQUN6QkEsRUFBS0wsUUFBVXRCLEtBQ1IyQixLQUVYM0IsS0FBS2UsTUFBUUcsRUFBS0gsT0FBUyxJQUFJakIsRUFDL0JFLEtBQUs2ZSxlQUFlMkMsWUFBWXRnQixFQUFLMGYsVUFDckM1Z0IsS0FBSzRmLE9BQVMsSUFBSXplLEVBQ2xCbkIsS0FBSzRmLE9BQU90ZSxRQUFVdEIsS0FDbEJBLEtBQUs4aUIsUUFDTDlpQixLQUFLa2hCLEtBQUtsaEIsS0FBSzRmLE9BQU92ZSxhQUV0QnJCLEtBQUswaEIsY0FBY2hGLE9BRXZCMWMsS0FBS3FaLFFBR1Q4SixjQUNJbmpCLEtBQUswZixNQUFNcFosU0FBUzNFLEdBQVNBLEVBQUt5aEIsV0FDbENwakIsS0FBSzJpQixNQUFNcmMsU0FBUzJaLEdBQVNBLEVBQUttRCxXQUd0Qy9KLFFBQ0lyWixLQUFLZ2pCLFNBQVdLLGFBQVksSUFBTXJqQixLQUFLbWpCLGVBQWUsS0FHMURqaEIsT0FDSW9oQixjQUFjdGpCLEtBQUtnakIsVUFDbkJoakIsS0FBS2dqQixTQUFXLEtBR3BCdkQsY0FDSSxNQUFNUSxFQUFPamdCLEtBQUsyZixRQUFRM2YsS0FBSzRmLE9BQU92ZSxhQUN0Q3JCLEtBQUttRSxPQUFPb2EsSUFBSTBCLEVBQUtzRCxPQUNoQnZqQixLQUFLK2lCLGFBQWE1aUIsSUFBSUgsS0FBSzRmLE9BQU92ZSxjQUF5QyxJQUF6QjRlLEVBQUt1RCxpQkFHeER4akIsS0FBS21FLE9BQU9vYSxJQUFJMEIsRUFBS0YsYUFGckIvZixLQUFLbUUsT0FBT29hLElBQUkwQixFQUFLdUQsa0JBSXpCeGpCLEtBQUt5akIsZUFDTHpqQixLQUFLMGpCLGVBR1RELGVBQ0ksTUFDTS9ELEVBRE8xZixLQUFLMmYsUUFBUTNmLEtBQUs0ZixPQUFPdmUsYUFDbkJ3ZSxXQUNuQixHQUFJSCxFQUFNOVksT0FBUyxFQUFHLE9BQ3RCLElBQUk2WixFQUFrQixXQUN0QmYsRUFBTXBaLFNBQVEsQ0FBQzNFLEVBQU11RyxLQUNiQSxFQUFRd1gsRUFBTTlZLE9BQVMsRUFDdkI2WixHQUFtQixHQUFHOWUsRUFBSzRZLFNBQ3BCclMsRUFBUXdYLEVBQU05WSxPQUFTLEVBQzlCNlosR0FBbUIsR0FBRzllLEVBQUs0WSxZQUUzQmtHLEdBQW1COWUsRUFBSzRZLFFBR2hDdmEsS0FBS21FLE9BQU9vYSxJQUFJa0MsRUFBa0IsS0FHdENpRCxlQUNJLE1BQU16RCxFQUFPamdCLEtBQUsyZixRQUFRM2YsS0FBSzRmLE9BQU92ZSxhQUN0QyxJQUFJc2lCLEVBQVEsR0FDUkMsRUFBa0IsY0FDdEIsTUFBTUMsRUFBVzVELEVBQUswRCxNQUFNbkksT0FDNUIsSUFBSyxJQUFJc0ksS0FBUUQsRUFDYkYsRUFBTTNpQixLQUFLOGlCLEdBRWZILEVBQU1yZCxTQUFRLENBQUMzRSxFQUFNdUcsS0FDYkEsRUFBUXliLEVBQU0vYyxPQUFTLEVBQ3ZCZ2QsR0FBbUIsR0FBR2ppQixNQUNmdUcsRUFBUXliLEVBQU0vYyxPQUFTLEVBQzlCZ2QsR0FBbUIsR0FBR2ppQixTQUV0QmlpQixHQUFtQmppQixLQUczQjNCLEtBQUttRSxPQUFPb2EsSUFBSXFGLEVBQWtCLEtBR3RDakUsUUFBUW5lLEdBQ0osT0FBT3hCLEtBQUsyaUIsTUFBTW9CLE1BQU05RCxHQUFTQSxFQUFLemUsSUFBTUEsSUFHaERNLFFBQVFOLEdBQ0osT0FBT3hCLEtBQUswZixNQUFNcUUsTUFBTXBpQixHQUFTQSxFQUFLSCxJQUFNQSxJQUdoRDBoQixLQUFLYyxHQUNELE9BQU8sSUFBSXRmLFNBQVEsQ0FBQ0MsRUFBU0MsS0FDekJyQixXQUFXb0IsRUFBU3FmLE1BSTVCbkcsV0FBV29HLEdBQ1AsTUFBTTVpQixFQUFjckIsS0FBSzJmLFFBQVEzZixLQUFLNGYsT0FBT3ZlLGFBQ3ZDNmlCLEVBQVVsa0IsS0FBSzJmLFFBQVFzRSxHQUN6QjVpQixFQUFZOGlCLFdBQWFELEVBQVFFLG1CQUMzQi9pQixFQUFZZ2pCLGVBQ1pILEVBQVFJLFVBQ2R0a0IsS0FBSzRmLE9BQU92ZSxZQUFjNGlCLEVBQzFCamtCLEtBQUt5ZixjQUNMemYsS0FBSytpQixhQUFheGlCLElBQUkwakIsR0FBUSxJQUl0Q00sbUJBQW1CL2pCLEdBQ2ZSLEtBQUs2ZSxlQUFlZ0MsUUFBVXJnQixFQUdsQzhmLGFBQWE5ZixHQUNUUixLQUFLMFcsTUFBTXlJLFFBQVEzZSxHQUd2QitmLE9BQ0l2Z0IsS0FBSzBoQixjQUFjbkIsT0FHdkI3RCxPQUNJMWMsS0FBSzBoQixjQUFjaEYsUUM3SlosTUFBTThILEVBQ2pCemtCLGNBQ0lDLEtBQUt3QixHQUFLLE9BQ1Z4QixLQUFLdWpCLE1BQVEsU0FDYnZqQixLQUFLK2YsWUFBYywwQkFDbkIvZixLQUFLd2pCLGlCQUFtQixHQUN4QnhqQixLQUFLNGlCLFFBQVUsR0FDZjVpQixLQUFLMmpCLE1BQVEsSUFBSXpqQixJQUNqQkYsS0FBS3lrQixjQUFnQixLQUNyQnprQixLQUFLMGtCLGFBQWUsS0FDcEIxa0IsS0FBSzJrQixjQUFnQixLQUNyQjNrQixLQUFLNGtCLGFBQWUsS0FDcEI1a0IsS0FBSzZrQixhQUFlLEtBQ3BCN2tCLEtBQUtzQixRQUFVLEtBQ2Z0QixLQUFLc2QsTUFBUSxLQUNidGQsS0FBS3FkLFNBQVcsS0FDaEJyZCxLQUFLOGtCLFFBQVUsS0FHbkJqSCxnQkFJSSxHQUhBN2QsS0FBS3NCLFFBQVE2QyxPQUFPMlosU0FBUzlkLEtBQUtzZCxPQUNsQ3RkLEtBQUtzQixRQUFRNkMsT0FBT3dhLFlBQVkzZSxLQUFLcWQsVUFDckNyZCxLQUFLc0IsUUFBUTZDLE9BQU80WixXQUFXL2QsS0FBSzhrQixTQUNoQzlrQixLQUFLeWtCLGNBQWUsT0FBT3prQixLQUFLeWtCLGNBQWN6a0IsS0FBS3NCLFNBRzNEdWMsZUFDSSxHQUFJN2QsS0FBSzBrQixhQUFjLE9BQU8xa0IsS0FBSzBrQixhQUFhMWtCLEtBQUtzQixTQUd6RDhpQixXQUNJLE9BQUlwa0IsS0FBSzJrQixlQUNFM2tCLEtBQUsya0IsY0FBYzNrQixLQUFLc0IsU0FLdkM2aUIsVUFDSSxPQUFJbmtCLEtBQUs0a0IsY0FDRTVrQixLQUFLNGtCLGFBQWE1a0IsS0FBS3NCLFNBS3RDeWpCLFFBQVFoRSxFQUFXa0QsR0FFZixPQURBamtCLEtBQUsyakIsTUFBTXBqQixJQUFJd2dCLEVBQVdrRCxHQUNuQmprQixLQUdYaWhCLFFBQVFGLEdBQ0osT0FBTy9nQixLQUFLMmpCLE1BQU14akIsSUFBSTRnQixHQUcxQnhmLFFBQVFJLEdBQ0ozQixLQUFLNGlCLFFBQVE1aEIsS0FBS1csR0FHdEJGLFdBQVdELEdBQ1B4QixLQUFLNGlCLFFBQVU1aUIsS0FBSzRpQixRQUFRbGhCLFFBQVFDLEdBQVNBLEdBQVFILElBR3pEd2pCLGlCQUFpQkMsR0FDYmpsQixLQUFLeWtCLGNBQWdCUSxFQUFTemhCLEtBQUt4RCxNQUd2Q2tsQixnQkFBZ0JELEdBQ1pqbEIsS0FBSzBrQixhQUFlTyxFQUFTemhCLEtBQUt4RCxNQUd0Q21sQixjQUFjL0QsR0FDVnBoQixLQUFLMmtCLGNBQWdCdkQsRUFBSzVkLEtBQUt4RCxNQUduQ29sQixhQUFhaEUsR0FDVHBoQixLQUFLNGtCLGFBQWV4RCxFQUFLNWQsS0FBS3hELE1BR2xDcWxCLGdCQUFnQkosR0FDWmpsQixLQUFLNmtCLGFBQWVJLEVBQVN6aEIsS0FBS3hELE1BR3RDNmYsV0FDSSxPQUFPN2YsS0FBSzRpQixRQUFRL2dCLEtBQUtGLEdBQVMzQixLQUFLc0IsUUFBUVEsUUFBUUgsS0FHM0RrYyxlQUNJLEdBQUk3ZCxLQUFLNmtCLGFBQWMsT0FBTzdrQixLQUFLNmtCLGFBQWE3a0IsS0FBS3NCLFVDcEY5QyxNQUFNZ2tCLEVBQ2pCdmxCLGNBQ0lDLEtBQUtpZ0IsS0FBTyxJQUFJdUUsRUFHcEJlLE9BQU9DLEdBRUgsT0FEQXhsQixLQUFLaWdCLEtBQUt6ZSxHQUFLZ2tCLEVBQ1J4bEIsS0FHWHlsQixVQUFVbEMsR0FFTixPQURBdmpCLEtBQUtpZ0IsS0FBS3NELE1BQVFBLEVBQ1h2akIsS0FHWDBsQixxQkFBcUIzRixHQUVqQixPQURBL2YsS0FBS2lnQixLQUFLdUQsaUJBQW1CekQsRUFDdEIvZixLQUdYMmxCLGdCQUFnQjVGLEdBRVosT0FEQS9mLEtBQUtpZ0IsS0FBS0YsWUFBY0EsRUFDakIvZixLQUdYNGxCLFNBQVM3RSxFQUFXa0QsR0FFaEIsT0FEQWprQixLQUFLaWdCLEtBQUs4RSxRQUFRaEUsRUFBV2tELEdBQ3RCamtCLEtBR1g2bEIsU0FBU0MsR0FFTCxPQURBOWxCLEtBQUtpZ0IsS0FBSzFlLFFBQVF1a0IsR0FDWDlsQixLQUdYK2xCLGtCQUFrQmQsR0FFZCxPQURBamxCLEtBQUtpZ0IsS0FBSytFLGlCQUFpQkMsR0FDcEJqbEIsS0FHWGdtQixpQkFBaUJmLEdBRWIsT0FEQWpsQixLQUFLaWdCLEtBQUtpRixnQkFBZ0JELEdBQ25CamxCLEtBR1hpbUIsZUFBZTdFLEdBRVgsT0FEQXBoQixLQUFLaWdCLEtBQUtrRixjQUFjL0QsR0FDakJwaEIsS0FHWGttQixjQUFjOUUsR0FFVixPQURBcGhCLEtBQUtpZ0IsS0FBS21GLGFBQWFoRSxHQUNoQnBoQixLQUdYbW1CLFNBQVMvRSxHQUVMLE9BREFwaEIsS0FBS2lnQixLQUFLb0YsZ0JBQWdCakUsR0FDbkJwaEIsS0FHWG9tQixVQUFVbkosR0FFTixPQURBamQsS0FBS2lnQixLQUFLM0MsTUFBUUwsRUFDWGpkLEtBR1hxbUIsYUFBYXBKLEdBRVQsT0FEQWpkLEtBQUtpZ0IsS0FBSzVDLFNBQVdKLEVBQ2RqZCxLQUdYc21CLFlBQVlySixHQUVSLE9BREFqZCxLQUFLaWdCLEtBQUs2RSxRQUFVN0gsRUFDYmpkLEtBR1h1bUIsU0FDSSxPQUFPdm1CLEtBQUtpZ0IsTUM1RXBCLFNBQWUsSUFBSXFGLEdBQ2xCQyxPQUFPLFNBQ1BFLFVBQVUsNEJBQ1ZDLHFCQUNELG9RQUdDQyxnQkFDRCxzSUFFQ0MsU0FBUyxRQUFTLFdBQ2xCRyxtQkFBa0JsSSxlQUFldmMsR0FDOUIsR0FBSUEsRUFBUVAsTUFBTVosSUFBSSxnQkFBaUIsT0FDdkMsTUFBTSxPQUFFZ0UsRUFBTSxLQUFFK2UsR0FBUzVoQixFQUN6QkEsRUFBUWlqQixvQkFBbUIsU0FDckJqakIsRUFBUWtsQixLQUFLLENBQ2Ysc0JBQ0EsbUlBQ0EsdURBQ0EsMENBQ0Esc0JBQ0EsZ0NBQ0EsNENBQ0EsaUJBQ0Esb0NBQ0EsaUdBQ0EsNEJBQ0EsMkVBQ0QsS0FDSGxsQixFQUFRaWpCLG9CQUFtQixHQUMzQmpqQixFQUFRUCxNQUFNUixJQUFJLGdCQUFnQixNQUVyQ2dtQixTQ2hDRCxHQUFlLElBQUlqQixHQUNsQkMsT0FBTyxXQUNQRSxVQUFVLHNCQUNWQyxxQkFDRCxtVEFHQ0MsZ0JBQ0QsNEZBRUNDLFNBQVMsUUFBUyxTQUNsQkEsU0FBUyxRQUFTLFlBQ2xCVyxTQ1pELEdBQWUsSUFBSWpCLEdBQ2xCQyxPQUFPLFlBQ1BFLFVBQVUsNkJBQ1ZDLHFCQUNELDZYQUtDQyxnQkFDRCwrR0FFQ0MsU0FBUyxZQUFhLFdBQ3RCQSxTQUFTLFlBQWEsV0FDdEJBLFNBQVMsWUFBYSxXQUN0QkEsU0FBUyxZQUFhLFdBQ3RCQSxTQUFTLFFBQVMsV0FDbEJXLFNDakJELEdBQWUsSUFBSWpCLEdBQ2xCQyxPQUFPLFdBQ1BFLFVBQVUsZ0RBQ1ZDLHFCQUNHLG1OQUdIQyxnQkFDRyxJQUVIQyxTQUFTLFlBQWEsWUFDdEJDLFNBQVMsV0FDVFUsU0NaRCxHQUFlLElBQUlqQixHQUNsQkMsT0FBTyxXQUNQRSxVQUFVLGdEQUNWQyxxQkFDRyx5TkFHSEMsZ0JBQ0csSUFFSEMsU0FBUyxZQUFhLFlBQ3RCQyxTQUFTLFdBQ1RVLFNDWkQsR0FBZSxJQUFJakIsR0FDbEJDLE9BQU8sV0FDUEUsVUFBVSxnREFDVkMscUJBQ0csb05BR0hDLGdCQUNHLElBRUhDLFNBQVMsWUFBYSxZQUN0QkMsU0FBUyxXQUNUVSxTQ1pjLE1BQU1FLEVBQ2pCMW1CLGNBQ0lDLEtBQUt3QixHQUFLLE9BQ1Z4QixLQUFLdWEsS0FBTyxVQUNadmEsS0FBSytmLFlBQWMsMENBQ25CL2YsS0FBS3VZLEtBQU8sT0FDWnZZLEtBQUtlLE1BQVEsSUFBSWpCLEVBQ2pCRSxLQUFLMG1CLFFBQVMsRUFDZDFtQixLQUFLa2dCLFVBQVcsRUFDaEJsZ0IsS0FBSzJtQixZQUFjLEtBQ25CM21CLEtBQUs0bUIsYUFBZSxLQUNwQjVtQixLQUFLNm1CLGFBQWUsS0FDcEI3bUIsS0FBSzZrQixhQUFlLEtBQ3BCN2tCLEtBQUtzQixRQUFVLEtBR25CdWMsY0FDSSxHQUFJN2QsS0FBSzJtQixZQUFhLE9BQU8zbUIsS0FBSzJtQixZQUFZM21CLEtBQUtzQixTQUd2RHVjLGVBQ0ksR0FBSTdkLEtBQUs0bUIsYUFBYyxPQUFPNW1CLEtBQUs0bUIsYUFBYTVtQixLQUFLc0IsU0FHekR1YyxlQUNJLEdBQUk3ZCxLQUFLNm1CLGFBQWMsT0FBTzdtQixLQUFLNm1CLGFBQWE3bUIsS0FBS3NCLFNBRXpEdWMsZUFDSSxHQUFJN2QsS0FBSzZrQixhQUFjLE9BQU83a0IsS0FBSzZrQixhQUFhN2tCLEtBQUtzQixTQUd6RHdsQixlQUFlN0IsR0FDWGpsQixLQUFLMm1CLFlBQWMxQixFQUFTemhCLEtBQUt4RCxNQUdyQyttQixnQkFBZ0I5QixHQUNaamxCLEtBQUs0bUIsYUFBZTNCLEVBQVN6aEIsS0FBS3hELE1BR3RDZ25CLGdCQUFnQi9CLEdBQ1pqbEIsS0FBSzZtQixhQUFlNUIsRUFBU3poQixLQUFLeEQsTUFHdENxbEIsZ0JBQWdCSixHQUNaamxCLEtBQUs2a0IsYUFBZUksRUFBU3poQixLQUFLeEQsTUFHdENpbkIsU0FBUzdtQixFQUFLSSxHQUNWLE9BQU9SLEtBQUtlLE1BQU1SLElBQUlILEVBQUtJLEdBRy9CMG1CLFNBQVM5bUIsR0FDTCxPQUFPSixLQUFLZSxNQUFNWixJQUFJQyxJQ3BEZixNQUFNK21CLEVBQ2pCcG5CLGNBQ0lDLEtBQUsyQixLQUFPLElBQUk4a0IsRUFHcEJsQixPQUFPQyxHQUVILE9BREF4bEIsS0FBSzJCLEtBQUtILEdBQUtna0IsRUFDUnhsQixLQUdYb25CLFNBQVM3TSxHQUVMLE9BREF2YSxLQUFLMkIsS0FBSzRZLEtBQU9BLEVBQ1Z2YSxLQUdYMmxCLGdCQUFnQjVGLEdBRVosT0FEQS9mLEtBQUsyQixLQUFLb2UsWUFBY0EsRUFDakIvZixLQUdYcW5CLFNBQVM5TyxHQUNMdlksS0FBSzJCLEtBQUs0VyxLQUFPQSxFQUdyQitPLFVBQVVsbkIsRUFBS0ksR0FFWCxPQURBUixLQUFLMkIsS0FBS3NsQixTQUFTN21CLEVBQUtJLEdBQ2pCUixLQUdYdW5CLFNBQVMvbUIsR0FFTCxPQURBUixLQUFLMkIsS0FBSytrQixPQUFTbG1CLEVBQ1pSLEtBR1h3bkIsV0FBV2huQixHQUVQLE9BREFSLEtBQUsyQixLQUFLdWUsU0FBVzFmLEVBQ2RSLEtBR1h5bkIsZ0JBQWdCeEMsR0FFWixPQURBamxCLEtBQUsyQixLQUFLbWxCLGVBQWU3QixHQUNsQmpsQixLQUdYMG5CLGlCQUFpQnpDLEdBRWIsT0FEQWpsQixLQUFLMkIsS0FBS29sQixnQkFBZ0I5QixHQUNuQmpsQixLQUdYMm5CLGlCQUFpQjFDLEdBRWIsT0FEQWpsQixLQUFLMkIsS0FBS3FsQixnQkFBZ0IvQixHQUNuQmpsQixLQUdYNG5CLGlCQUFpQjNDLEdBRWIsT0FEQWpsQixLQUFLMkIsS0FBSzBqQixnQkFBZ0JKLEdBQ25CamxCLEtBR1h1bUIsU0FDSSxPQUFPdm1CLEtBQUsyQixNQzVEcEIsU0FBZSxJQUFJd2xCLEdBQ2xCNUIsT0FBTyxXQUNQNkIsU0FBUyxxQkFDVHpCLGdCQUNHLGlIQUVINkIsWUFBVyxHQUNYRCxVQUFTLEdBQ1RFLGlCQUFnQjVKLGVBQWdCdmMsR0FDN0JBLEVBQVE2ZSxNQUFNLDZEQUVqQm9HLFNDWEQsTUNNQSxDQUNJLEVBQ0EsRUFDQXNCLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLElDUEosSUNOZSxJQUFJZCxHQUNsQjVCLE9BQU8sU0FDUDZCLFNBQVMsZ0JBQ1R6QixnQkFBZ0IsOERBQ2hCNkIsWUFBVyxHQUNYRCxVQUFTLEdBQ1RHLGtCQUFpQjdKLGVBQWV2YyxHQUM3QkEsRUFBUTZlLE1BQU0sT0FBT25nQixLQUFLd0Isb0NBRTdCbW1CLGtCQUFpQjlKLGVBQWV2YyxHQUM3QkEsRUFBUTZlLE1BQU0sMENBRWpCc0gsaUJBQWdCNUosZUFBZXZjLEdBQzVCQSxFQUFRNmUsTUFBTSwrQ0FBK0NuZ0IsS0FBS3VhLGVBRXJFZ00sVUNmYyxJQUFJWSxHQUNsQjVCLE9BQU8sU0FDUDZCLFNBQVMsV0FDVHpCLGdCQUFnQix5Q0FDaEI0QixVQUFTLEdBQ1RDLFlBQVcsR0FDWEMsaUJBQWdCNUosZUFBZXZjLEdBQzVCQSxFQUFRNmUsTUFBTSwyQ0FFakJvRyxVQ1JjLElBQUlZLEdBQ2xCNUIsT0FBTyxPQUNQNkIsU0FBUyxTQUNUekIsZ0JBQWdCLHlCQUNoQjZCLFlBQVcsR0FDWEQsVUFBUyxHQUNUaEIsVUNQYyxJQUFJWSxHQUNsQjVCLE9BQU8sV0FDUDZCLFNBQVMscUJBQ1R6QixnQkFDRyw2R0FFSDZCLFlBQVcsR0FDWEQsVUFBUyxHQUNURSxpQkFBZ0I1SixlQUFnQnZjLEdBQzdCQSxFQUFRNmUsTUFBTSwwRUFDZCxJQUFJM2YsRUFBUWMsRUFBUVAsTUFBTVosSUFBSSxrQkFBbUIsR0FDakRLLElBQ0FjLEVBQVFQLE1BQU1SLElBQUksa0JBQW1CQyxHQUN2QixHQUFWQSxJQUNBYyxFQUFRNmUsTUFBTSxpQ0FDZDdlLEVBQVFQLE1BQU1SLElBQUksb0JBQW9CLElBRXRDZSxFQUFRUCxNQUFNWixJQUFJLG1CQUFxQixHQUFLbUIsRUFBUVAsTUFBTVosSUFBSSxtQkFBcUIsSUFDbkZtQixFQUFRNmUsTUFBTSw0RUFDZDdlLEVBQVFQLE1BQU1SLElBQUksb0JBQW9CLE9BRzdDZ21CLFVDdEJjLElBQUlZLEdBQ2xCNUIsT0FBTyxXQUNQNkIsU0FBUyxxQkFDVHpCLGdCQUNHLG1IQUVINkIsWUFBVyxHQUNYRCxVQUFTLEdBQ1RFLGlCQUFnQjVKLGVBQWdCdmMsR0FDN0JBLEVBQVE2ZSxNQUFNLGdGQUNkLElBQUkzZixFQUFRYyxFQUFRUCxNQUFNWixJQUFJLGtCQUFtQixHQUNqREssSUFDQWMsRUFBUVAsTUFBTVIsSUFBSSxrQkFBbUJDLEdBQ3hCLEdBQVRBLEdBQ0FjLEVBQVE2ZSxNQUFNLGlDQUVkN2UsRUFBUVAsTUFBTVosSUFBSSxtQkFBcUIsR0FBS21CLEVBQVFQLE1BQU1aLElBQUksbUJBQXFCLElBQ25GbUIsRUFBUTZlLE1BQU0sNEVBQ2Q3ZSxFQUFRUCxNQUFNUixJQUFJLG9CQUFvQixPQUc3Q2dtQixVQ3JCYyxJQUFJWSxHQUNsQjVCLE9BQU8sV0FDUDZCLFNBQVMscUJBQ1R6QixnQkFDRyxzSEFFSDZCLFlBQVcsR0FDWEQsVUFBUyxHQUNURSxpQkFBZ0I1SixlQUFnQnZjLEdBQzdCQSxFQUFRNmUsTUFBTSxtSEFFakJvRyxTTkVHMEIsR09mV3BLLGVBQWVxSyxFQUFZMUksRUFBTWxlLEdBQzVDQSxFQUFRNmUsTUFBTSxhQ3lCbEIsU0FBU2dJLEVBQVVyRixHQUNGLElBQUlELEVBQUtDLEdBRWpCdGdCLEtBQUssQ0FDTm1nQixNQUFPLEVBQ1AvQixTQUFVLENBQ04sQ0FBQyxDQUFDLE9BQVEsT0FBUXNILElBRXRCeEksTUFBTyxJQTdCWHdDLGFBQWFwZ0IsUUFBUSxVQUNyQlksU0FBUzRiLGVBQWUsbUJBQW1COEosUUFBUyxFQUNwRDFsQixTQUFTNGIsZUFBZSxlQUFlOEosUUFBUyxFQUNoRDFsQixTQUFTNGIsZUFBZSxrQkFBa0I3RSxpQkFBaUIsU0FBUyxLQUNoRS9XLFNBQVM0YixlQUFlLG1CQUFtQjhKLFFBQVMsRUFDcEQxbEIsU0FBUzRiLGVBQWUsYUFBYThKLFFBQVMsRUFDOUNELEdBQVUsTUFFZHpsQixTQUFTNGIsZUFBZSxrQkFBa0I3RSxpQkFBaUIsU0FBUyxLQUNoRS9XLFNBQVM0YixlQUFlLG1CQUFtQjhKLFFBQVMsRUFDcEQxbEIsU0FBUzRiLGVBQWUsYUFBYThKLFFBQVMsRUFDOUNELEdBQVUsT0FJbEJ6bEIsU0FBUzRiLGVBQWUsU0FBUzdFLGlCQUFpQixTQUFTLEtBQ3ZEL1csU0FBUzRiLGVBQWUsZUFBZThKLFFBQVMsRUFDaEQxbEIsU0FBUzRiLGVBQWUsYUFBYThKLFFBQVMsRUFDOUNELEdBQVUsTyIsInNvdXJjZXMiOlsid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvc3RhdGUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9wbGF5ZXIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0cy9iYXNlLW91dHB1dC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3R0cy9vdXRwdXRzL2FyaWEuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0cy93ZWJ0dHMuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay90dHMvb3V0cHV0LWZhY3RvcnkuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvYXVkaW8tY29udGV4dC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL2V2ZW50LWJ1cy9pbmRleC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL21hdGgvdmVjNC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL21hdGgvbWF0NC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL21hdGgvdmVjMi5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL21hdGgvbWF0My5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL21hdGgvcXVhdC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL21hdGgvdmVjMy5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3Jlc29uYXRvci9zY2VuZXMvd2ViYXVkaW8tc2NlbmUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZWZmZWN0LWNoYWluLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvcmVzb25hdG9yL2F1ZGlvLWdyYXBoLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9mcmFtZXdvcmsvcmVzb25hdG9yL3NvdXJjZXMvc291cmNlLXR5cGUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3Ivc291cmNlcy9hdWRpby1zb3VyY2UuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZGF0YS1wb29sLWl0ZW0uanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvbG9hZGVycy9odHRwLWxvYWRlci5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3Jlc29uYXRvci9kYXRhLXBvb2wuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZWZmZWN0cy9jb252b2x2ZXIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvZWZmZWN0cy9iYXNlLWVmZmVjdC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZnJhbWV3b3JrL3Jlc29uYXRvci9zb3VyY2VzL3N0cmVhbWluZy1zb3VyY2UuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2ZyYW1ld29yay9yZXNvbmF0b3IvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9zb3VuZC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL291dHB1dC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2lucHV0LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy9sb29rLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMvdXNlLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMvdGFrZS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2NvbW1hbmRzL2Ryb3AuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy9lY2hvLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvY29tbWFuZHMvc2F2ZS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2NvbW1hbmRzL2xvYWQuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy92b2x1bWUuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9jb21tYW5kcy9pbnZlbnRvcnkuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9zZXJpYWxpemF0aW9uLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2VuZ2luZS9yb29tLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvYnVpbGRlcnMvcm9vbS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL3N0YXJ0LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL3Jvb21zL2xhaXIvdHVubmVsMS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL2NlbnRyYWwxLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL3Jvb21zL2xhaXIvc3RhdHVlMS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL3N0YXR1ZTIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvcm9vbXMvbGFpci9zdGF0dWUzLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9lbmdpbmUvaXRlbS5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZW5naW5lL2J1aWxkZXJzL2l0ZW0uanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvaXRlbXMvc3RhdHVlNC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9pbmRleC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9yb29tcy9sYWlyL2luZGV4LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL2luZGV4LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL3N0b25lLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL3RvcmNoLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL2N1cC5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9pdGVtcy9zdGF0dWUxLmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2l0ZW1zL3N0YXR1ZTIuanMiLCJ3ZWJwYWNrOi8vYXNzYXNzaW4tYnVnLy4vc3JjL2dhbWUvaXRlbXMvc3RhdHVlMy5qcyIsIndlYnBhY2s6Ly9hc3Nhc3Npbi1idWcvLi9zcmMvZ2FtZS9jb21tYW5kcy9tZW93LmpzIiwid2VicGFjazovL2Fzc2Fzc2luLWJ1Zy8uL3NyYy9nYW1lL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBkZWZhdWx0IGNsYXNzIFN0YXRlIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuc3RhdGVzID0gbmV3IE1hcCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGdldChrZXksIGRlZmF1bHRWYWx1ZSA9IG51bGwpIHtcclxuICAgICAgICBpZiAoIXRoaXMuc3RhdGVzLmhhcyhrZXkpKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc3RhdGVzLnNldChrZXksIGRlZmF1bHRWYWx1ZSk7XHJcbiAgICAgICAgICAgIHJldHVybiBkZWZhdWx0VmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzLnN0YXRlcy5nZXQoa2V5KTtcclxuICAgIH1cclxuXHJcbiAgICBzZXQoa2V5LCB2YWx1ZSkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnN0YXRlcy5zZXQoa2V5LCB2YWx1ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgY2hhbmdlKGtleSwgYW1vdW50ID0gMSkge1xyXG4gICAgICAgIGxldCB2YWwgPSB0aGlzLmdldChrZXksIDApO1xyXG4gICAgICAgIHZhbCArPSBhbW91bnQ7XHJcbiAgICAgICAgdGhpcy5zZXQoa2V5LCB2YWwpO1xyXG4gICAgfVxyXG5cclxuICAgIHNlcmlhbGl6ZSgpIHtcclxuICAgICAgICBjb25zdCBlbnRyaWVzID0gdGhpcy5zdGF0ZXMuZW50cmllcygpO1xyXG4gICAgICAgIGNvbnN0IGVudHJ5bWFwID0gW107XHJcbiAgICAgICAgZm9yIChsZXQgc3RhdGUgb2YgZW50cmllcykge1xyXG4gICAgICAgICAgICBlbnRyeW1hcC5wdXNoKHN0YXRlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGVudHJ5bWFwO1xyXG4gICAgfVxyXG5cclxuICAgIGRlc2VyaWFsaXplKGRhdGEpIHtcclxuICAgICAgICB0aGlzLnN0YXRlcyA9IG5ldyBNYXAoZGF0YSk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBjbGFzcyBQbGF5ZXIge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5pbnZlbnRvcnkgPSBbXTtcclxuICAgICAgICB0aGlzLmN1cnJlbnRSb29tID0gXCJzdGFydFwiO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkSXRlbShpZCkge1xyXG4gICAgICAgIHRoaXMuaW52ZW50b3J5LnB1c2goaWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHJlbW92ZUl0ZW0oaWQpIHtcclxuICAgICAgICB0aGlzLmludmVudG9yeSA9IHRoaXMuaW52ZW50b3J5LmZpbHRlcigoaXRlbSkgPT4gaXRlbSAhPSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0SW52ZW50b3J5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmludmVudG9yeS5tYXAoKGl0ZW0pID0+IHRoaXMuY29udGV4dC5nZXRJdGVtKGl0ZW0pKTtcclxuICAgIH1cclxufSIsImV4cG9ydCBjbGFzcyBCYXNlT3V0cHV0IHtcclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHNldE9wdGlvbnMob3B0aW9ucykge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlT3V0cHV0IH0gZnJvbSAnLi9iYXNlLW91dHB1dCc7XHJcbmV4cG9ydCBjbGFzcyBBcmlhT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0ge30pIHtcclxuICAgICAgICBzdXBlcigpO1xyXG4gICAgICAgIHRoaXMudGltZW91dCA9IDEwMDtcclxuICAgICAgICB0aGlzLnRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgfHwgMTAwO1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyLnNldEF0dHJpYnV0ZSgnYXJpYS1saXZlJywgJ3BvbGl0ZScpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgICAgIHRoaXMuc3BlZWNoRGlzcGxheS5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGl2ZScsICdwb2xpdGUnKTtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmQodGhpcy5zcGVlY2hEaXNwbGF5KTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHRoaXMuY29udGFpbmVyKTtcclxuICAgICAgICBkb2N1bWVudC5ib2R5Lmluc2VydEJlZm9yZSh0aGlzLmNvbnRhaW5lciwgZG9jdW1lbnQuYm9keS5maXJzdENoaWxkKTtcclxuICAgIH1cclxuICAgIHNwZWFrKHRleHQpIHtcclxuICAgICAgICB0aGlzLmNsZWFyRGlzcGxheSgpO1xyXG4gICAgICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSh0ZXh0KTtcclxuICAgICAgICBjb25zdCBwYXJhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO1xyXG4gICAgICAgIHBhcmEuYXBwZW5kQ2hpbGQobm9kZSk7XHJcbiAgICAgICAgdGhpcy5zcGVlY2hEaXNwbGF5LmFwcGVuZENoaWxkKHBhcmEpO1xyXG4gICAgICAgIHNldFRpbWVvdXQodGhpcy5jbGVhckRpc3BsYXkuYmluZCh0aGlzKSwgdGhpcy50aW1lb3V0KTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5jbGVhckRpc3BsYXkoKTtcclxuICAgIH1cclxuICAgIGNsZWFyRGlzcGxheSgpIHtcclxuICAgICAgICB0aGlzLnNwZWVjaERpc3BsYXkuaW5uZXJIVE1MID0gJyc7XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgQmFzZU91dHB1dCB9IGZyb20gJy4vYmFzZS1vdXRwdXQnO1xyXG5leHBvcnQgY2xhc3MgV2ViVFRTT3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XHJcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0ge30pIHtcclxuICAgICAgICBzdXBlcigpO1xyXG4gICAgICAgIHRoaXMucmF0ZSA9IG9wdGlvbnMucmF0ZSB8fCAxO1xyXG4gICAgICAgIHRoaXMuc3ludGggPSB3aW5kb3cuc3BlZWNoU3ludGhlc2lzO1xyXG4gICAgfVxyXG4gICAgc3BlYWsodGV4dCkge1xyXG4gICAgICAgIGxldCB1dHRlclRoaXMgPSBuZXcgU3BlZWNoU3ludGhlc2lzVXR0ZXJhbmNlKHRleHQpO1xyXG4gICAgICAgIHV0dGVyVGhpcy5yYXRlID0gdGhpcy5yYXRlO1xyXG4gICAgICAgIHRoaXMuc3ludGguc3BlYWsodXR0ZXJUaGlzKTtcclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5zeW50aC5jYW5jZWwoKTtcclxuICAgIH1cclxuICAgIHNldE9wdGlvbnMob3B0aW9ucykge1xyXG4gICAgICAgIHRoaXMucmF0ZSA9IG9wdGlvbnMucmF0ZSB8fCAxO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCB7IGNyZWF0ZU91dHB1dCB9IGZyb20gJy4vb3V0cHV0LWZhY3RvcnknO1xyXG5leHBvcnQgY2xhc3MgVFRTIHtcclxuICAgIGNvbnN0cnVjdG9yKG91dHB1dCA9IGNyZWF0ZU91dHB1dCgpKSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQgPSBvdXRwdXQ7XHJcbiAgICB9XHJcbiAgICBzcGVhayh0ZXh0KSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQuc3BlYWsodGV4dCk7XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnN0b3AoKTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBCYXNlT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXRzL2Jhc2Utb3V0cHV0JztcclxuaW1wb3J0IHsgQXJpYU91dHB1dCB9IGZyb20gJy4vb3V0cHV0cy9hcmlhJztcclxuaW1wb3J0IHsgV2ViVFRTT3V0cHV0IH0gZnJvbSAnLi9vdXRwdXRzL3dlYnR0cyc7XHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVPdXRwdXQoa2V5ID0gJ2FyaWEnKSB7XHJcbiAgICBzd2l0Y2ggKGtleSkge1xyXG4gICAgICAgIGNhc2UgJ2FyaWEnOlxyXG4gICAgICAgICAgICByZXR1cm4gbmV3IEFyaWFPdXRwdXQoKTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgY2FzZSAnd2VidHRzJzpcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyBXZWJUVFNPdXRwdXQoKTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyBBcmlhT3V0cHV0KCk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgfVxyXG59XHJcbmV4cG9ydCB7IFdlYlRUU091dHB1dCwgQXJpYU91dHB1dCwgQmFzZU91dHB1dCB9O1xyXG4iLCIvLyBzaW1wbGUgd3JhcHBlciBhcm91bmQgdGhlIEF1ZGlvQ29udGV4dFxyXG4vLyBldmVudHVhbGx5IHdpbGwgYmUgdXNlZCB0byBkZWFsIHdpdGggY3Jvc3MgYnJvd3NlciBpc3N1ZXNcclxudmFyIF9fYXdhaXRlciA9ICh0aGlzICYmIHRoaXMuX19hd2FpdGVyKSB8fCBmdW5jdGlvbiAodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkgeyByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHZhbHVlKTsgfSk7IH1cclxuICAgIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG4gICAgICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkgeyByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTsgfVxyXG4gICAgICAgIHN0ZXAoKGdlbmVyYXRvciA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSkubmV4dCgpKTtcclxuICAgIH0pO1xyXG59O1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZXNvbmF0b3JBdWRpb0NvbnRleHQge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbmV3IEF1ZGlvQ29udGV4dCgpO1xyXG4gICAgfVxyXG4gICAgZ2V0Q29udGV4dCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0O1xyXG4gICAgfVxyXG4gICAgY3JlYXRlR2FpbigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgIH1cclxuICAgIGdldE91dHB1dERlc3RpbmF0aW9uKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuZGVzdGluYXRpb247XHJcbiAgICB9XHJcbiAgICBjcmVhdGVCdWZmZXJTb3VyY2UoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcclxuICAgIH1cclxuICAgIGRlY29kZUF1ZGlvRGF0YShkYXRhKSB7XHJcbiAgICAgICAgcmV0dXJuIF9fYXdhaXRlcih0aGlzLCB2b2lkIDAsIHZvaWQgMCwgZnVuY3Rpb24qICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHlpZWxkIHRoaXMuY29udGV4dC5kZWNvZGVBdWRpb0RhdGEoZGF0YSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjcmVhdGVQYW5uZXIoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5jcmVhdGVQYW5uZXIoKTtcclxuICAgIH1cclxuICAgIGNyZWF0ZU1lZGlhRWxlbWVudFNvdXJjZShlbGVtZW50KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5jcmVhdGVNZWRpYUVsZW1lbnRTb3VyY2UoZWxlbWVudCk7XHJcbiAgICB9XHJcbn1cclxuIiwiZXhwb3J0IGNsYXNzIEV2ZW50QnVzIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuZXZlbnRzID0gbmV3IE1hcCgpO1xyXG4gICAgfVxyXG4gICAgZW1pdChpZCwgZGF0YSA9IHt9KSB7XHJcbiAgICAgICAgbGV0IGV2ID0gdGhpcy5ldmVudHMuZ2V0KGlkKTtcclxuICAgICAgICBpZiAoIWV2KSB7XHJcbiAgICAgICAgICAgIGxldCBldiA9IG5ldyBFdmVudEl0ZW0oaWQpO1xyXG4gICAgICAgICAgICB0aGlzLmV2ZW50cy5zZXQoaWQsIGV2KTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICBldi5zdWJzY3JpYmVycy5mb3JFYWNoKChzdWJzY3JpYmVyKSA9PiB7XHJcbiAgICAgICAgICAgIHN1YnNjcmliZXIoZGF0YSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBzdWJzY3JpYmUoaWQsIHN1YnNjcmliZXIpIHtcclxuICAgICAgICBsZXQgZXYgPSB0aGlzLmV2ZW50cy5nZXQoaWQpO1xyXG4gICAgICAgIGlmICghZXYpIHtcclxuICAgICAgICAgICAgZXYgPSBuZXcgRXZlbnRJdGVtKGlkKTtcclxuICAgICAgICAgICAgdGhpcy5ldmVudHMuc2V0KGlkLCBldik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGV2LnN1YnNjcmliZXJzLnB1c2goc3Vic2NyaWJlcik7XHJcbiAgICB9XHJcbiAgICB1bnN1YnNjcmliZShpZCwgc3Vic2NyaWJlcikge1xyXG4gICAgICAgIGlmICh0aGlzLmV2ZW50cy5oYXMoaWQpKSB7XHJcbiAgICAgICAgICAgIGxldCBldiA9IHRoaXMuZXZlbnRzLmdldChpZCk7XHJcbiAgICAgICAgICAgIGV2LnN1YnNjcmliZXJzID0gZXYuc3Vic2NyaWJlcnMuZmlsdGVyKChmbikgPT4gZm4gIT09IHN1YnNjcmliZXIpO1xyXG4gICAgICAgICAgICBpZiAoZXYuc3Vic2NyaWJlcnMubGVuZ3RoIDwgMSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5ldmVudHMuZGVsZXRlKGlkKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHVuc3Vic2NyaWJlQWxsKGlkKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZXZlbnRzLmhhcyhpZCkpIHtcclxuICAgICAgICAgICAgdGhpcy5ldmVudHMuZGVsZXRlKGlkKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuZXhwb3J0IGNsYXNzIEV2ZW50SXRlbSB7XHJcbiAgICBjb25zdHJ1Y3RvcihpZCkge1xyXG4gICAgICAgIHRoaXMuaWQgPSBpZDtcclxuICAgICAgICB0aGlzLnN1YnNjcmliZXJzID0gW107XHJcbiAgICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgZXBzaWxvbiB9IGZyb20gJy4vY29uc3RhbnRzJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgdmVjNCB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoNCk7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMueHl6dyA9IHZhbHVlcztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBnZXQgeCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMF07XHJcbiAgICB9XHJcbiAgICBnZXQgeSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBnZXQgeigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBnZXQgdygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbM107XHJcbiAgICB9XHJcbiAgICBnZXQgeHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV1dO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5eigpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXSwgdGhpcy52YWx1ZXNbMl1dO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5encoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdLCB0aGlzLnZhbHVlc1szXV07XHJcbiAgICB9XHJcbiAgICBzZXQgeCh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeih2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgdyh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeHkodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBzZXQgeHl6KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgc2V0IHh5encodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB2YWx1ZXNbM107XHJcbiAgICB9XHJcbiAgICBnZXQgcigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMF07XHJcbiAgICB9XHJcbiAgICBnZXQgZygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBnZXQgYigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBnZXQgYSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbM107XHJcbiAgICB9XHJcbiAgICBnZXQgcmcoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV1dO1xyXG4gICAgfVxyXG4gICAgZ2V0IHJnYigpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXSwgdGhpcy52YWx1ZXNbMl1dO1xyXG4gICAgfVxyXG4gICAgZ2V0IHJnYmEoKSB7XHJcbiAgICAgICAgcmV0dXJuIFt0aGlzLnZhbHVlc1swXSwgdGhpcy52YWx1ZXNbMV0sIHRoaXMudmFsdWVzWzJdLCB0aGlzLnZhbHVlc1szXV07XHJcbiAgICB9XHJcbiAgICBzZXQgcih2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgZyh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgYih2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgYSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgcmcodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBzZXQgcmdiKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgc2V0IHJnYmEodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB2YWx1ZXNbM107XHJcbiAgICB9XHJcbiAgICBhdChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1tpbmRleF07XHJcbiAgICB9XHJcbiAgICByZXNldCgpIHtcclxuICAgICAgICB0aGlzLnggPSAwO1xyXG4gICAgICAgIHRoaXMueSA9IDA7XHJcbiAgICAgICAgdGhpcy56ID0gMDtcclxuICAgICAgICB0aGlzLncgPSAwO1xyXG4gICAgfVxyXG4gICAgY29weShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB0aGlzLng7XHJcbiAgICAgICAgZGVzdC55ID0gdGhpcy55O1xyXG4gICAgICAgIGRlc3QueiA9IHRoaXMuejtcclxuICAgICAgICBkZXN0LncgPSB0aGlzLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBuZWdhdGUoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gLXRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSAtdGhpcy55O1xyXG4gICAgICAgIGRlc3QueiA9IC10aGlzLno7XHJcbiAgICAgICAgZGVzdC53ID0gLXRoaXMudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIGVxdWFscyh2ZWN0b3IsIHRocmVzaG9sZCA9IGVwc2lsb24pIHtcclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy54IC0gdmVjdG9yLngpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueSAtIHZlY3Rvci55KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnogLSB2ZWN0b3IueikgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy53IC0gdmVjdG9yLncpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBsZW5ndGgoKSB7XHJcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCh0aGlzLnNxdWFyZWRMZW5ndGgoKSk7XHJcbiAgICB9XHJcbiAgICBzcXVhcmVkTGVuZ3RoKCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgcmV0dXJuIHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3O1xyXG4gICAgfVxyXG4gICAgYWRkKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCArPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKz0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56ICs9IHZlY3Rvci56O1xyXG4gICAgICAgIHRoaXMudyArPSB2ZWN0b3IudztcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHN1YnRyYWN0KHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAtPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgLT0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56IC09IHZlY3Rvci56O1xyXG4gICAgICAgIHRoaXMudyAtPSB2ZWN0b3IudztcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5KHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCAqPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKj0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56ICo9IHZlY3Rvci56O1xyXG4gICAgICAgIHRoaXMudyAqPSB2ZWN0b3IudztcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGRpdmlkZSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLz0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC89IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAvPSB2ZWN0b3IuejtcclxuICAgICAgICB0aGlzLncgLz0gdmVjdG9yLnc7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzY2FsZSh2YWx1ZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ICo9IHZhbHVlO1xyXG4gICAgICAgIGRlc3QueSAqPSB2YWx1ZTtcclxuICAgICAgICBkZXN0LnogKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC53ICo9IHZhbHVlO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbm9ybWFsaXplKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBsZW5ndGggPSB0aGlzLmxlbmd0aCgpO1xyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVzdC54ICo9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueSAqPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnogKj0gMDtcclxuICAgICAgICAgICAgZGVzdC53ICo9IDA7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZW5ndGggPSAxLjAgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ICo9IGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueiAqPSBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC53ICo9IGxlbmd0aDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG11bHRpcGx5TWF0NChtYXRyaXgsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBtYXRyaXgubXVsdGlwbHlWZWM0KHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIG1peCh2ZWN0b3IsIHZlY3RvcjIsIHRpbWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54ICsgdGltZSAqICh2ZWN0b3IyLnggLSB2ZWN0b3IueCk7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKyB0aW1lICogKHZlY3RvcjIueSAtIHZlY3Rvci55KTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiArIHRpbWUgKiAodmVjdG9yMi56IC0gdmVjdG9yLnopO1xyXG4gICAgICAgIGRlc3QudyA9IHZlY3Rvci53ICsgdGltZSAqICh2ZWN0b3IyLncgLSB2ZWN0b3Iudyk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3VtKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogKyB2ZWN0b3IyLno7XHJcbiAgICAgICAgZGVzdC53ID0gdmVjdG9yLncgKyB2ZWN0b3IyLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlmZmVyZW5jZSh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC0gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56IC0gdmVjdG9yMi56O1xyXG4gICAgICAgIGRlc3QudyA9IHZlY3Rvci53IC0gdmVjdG9yMi53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAqIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAqIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiAqIHZlY3RvcjIuejtcclxuICAgICAgICBkZXN0LncgPSB2ZWN0b3IudyAqIHZlY3RvcjIudztcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBxdW90aWVudCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWM0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC8gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC8gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56IC8gdmVjdG9yMi56O1xyXG4gICAgICAgIGRlc3QudyA9IHZlY3Rvci53IC8gdmVjdG9yMi53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG59XHJcbnZlYzQuemVybyA9IG5ldyB2ZWM0KFswLCAwLCAwLCAxXSk7XHJcbnZlYzQub25lID0gbmV3IHZlYzQoWzEsIDEsIDEsIDFdKTtcclxuIiwiaW1wb3J0IG1hdDMgZnJvbSAnLi9tYXQzJztcclxuaW1wb3J0IHZlYzMgZnJvbSAnLi92ZWMzJztcclxuaW1wb3J0IHZlYzQgZnJvbSAnLi92ZWM0JztcclxuaW1wb3J0IHsgZXBzaWxvbiB9IGZyb20gJy4vY29uc3RhbnRzJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgbWF0NCB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoMTYpO1xyXG4gICAgICAgIGlmICh2YWx1ZXMgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICB0aGlzLmluaXQodmFsdWVzKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBhdChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1tpbmRleF07XHJcbiAgICB9XHJcbiAgICBpbml0KHZhbHVlcykge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTY7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpXSA9IHZhbHVlc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICByZXNldCgpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaV0gPSAwO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGNvcHkoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IG1hdDQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc3QudmFsdWVzW2ldID0gdGhpcy52YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgYWxsKCkge1xyXG4gICAgICAgIGNvbnN0IGRhdGEgPSBbXTtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcclxuICAgICAgICAgICAgZGF0YVtpXSA9IHRoaXMudmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZGF0YTtcclxuICAgIH1cclxuICAgIHJvdyhpbmRleCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogNCArIDBdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDQgKyAxXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiA0ICsgMl0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogNCArIDNdXHJcbiAgICAgICAgXTtcclxuICAgIH1cclxuICAgIGNvbChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKyA0XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKyA4XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKyAxMl1cclxuICAgICAgICBdO1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKG1hdHJpeCwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTY7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoTWF0aC5hYnModGhpcy52YWx1ZXNbaV0gLSBtYXRyaXguYXQoaSkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBkZXRlcm1pbmFudCgpIHtcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMDMgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMTMgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1sxMF07XHJcbiAgICAgICAgY29uc3QgYTIzID0gdGhpcy52YWx1ZXNbMTFdO1xyXG4gICAgICAgIGNvbnN0IGEzMCA9IHRoaXMudmFsdWVzWzEyXTtcclxuICAgICAgICBjb25zdCBhMzEgPSB0aGlzLnZhbHVlc1sxM107XHJcbiAgICAgICAgY29uc3QgYTMyID0gdGhpcy52YWx1ZXNbMTRdO1xyXG4gICAgICAgIGNvbnN0IGEzMyA9IHRoaXMudmFsdWVzWzE1XTtcclxuICAgICAgICBjb25zdCBkZXQwMCA9IGEwMCAqIGExMSAtIGEwMSAqIGExMDtcclxuICAgICAgICBjb25zdCBkZXQwMSA9IGEwMCAqIGExMiAtIGEwMiAqIGExMDtcclxuICAgICAgICBjb25zdCBkZXQwMiA9IGEwMCAqIGExMyAtIGEwMyAqIGExMDtcclxuICAgICAgICBjb25zdCBkZXQwMyA9IGEwMSAqIGExMiAtIGEwMiAqIGExMTtcclxuICAgICAgICBjb25zdCBkZXQwNCA9IGEwMSAqIGExMyAtIGEwMyAqIGExMTtcclxuICAgICAgICBjb25zdCBkZXQwNSA9IGEwMiAqIGExMyAtIGEwMyAqIGExMjtcclxuICAgICAgICBjb25zdCBkZXQwNiA9IGEyMCAqIGEzMSAtIGEyMSAqIGEzMDtcclxuICAgICAgICBjb25zdCBkZXQwNyA9IGEyMCAqIGEzMiAtIGEyMiAqIGEzMDtcclxuICAgICAgICBjb25zdCBkZXQwOCA9IGEyMCAqIGEzMyAtIGEyMyAqIGEzMDtcclxuICAgICAgICBjb25zdCBkZXQwOSA9IGEyMSAqIGEzMiAtIGEyMiAqIGEzMTtcclxuICAgICAgICBjb25zdCBkZXQxMCA9IGEyMSAqIGEzMyAtIGEyMyAqIGEzMTtcclxuICAgICAgICBjb25zdCBkZXQxMSA9IGEyMiAqIGEzMyAtIGEyMyAqIGEzMjtcclxuICAgICAgICByZXR1cm4gKGRldDAwICogZGV0MTEgLVxyXG4gICAgICAgICAgICBkZXQwMSAqIGRldDEwICtcclxuICAgICAgICAgICAgZGV0MDIgKiBkZXQwOSArXHJcbiAgICAgICAgICAgIGRldDAzICogZGV0MDggLVxyXG4gICAgICAgICAgICBkZXQwNCAqIGRldDA3ICtcclxuICAgICAgICAgICAgZGV0MDUgKiBkZXQwNik7XHJcbiAgICB9XHJcbiAgICBzZXRJZGVudGl0eSgpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s5XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTBdID0gMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMV0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEyXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTNdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNF0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE1XSA9IDE7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICB0cmFuc3Bvc2UoKSB7XHJcbiAgICAgICAgY29uc3QgdGVtcDAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgdGVtcDAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgdGVtcDAzID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgdGVtcDEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgdGVtcDEzID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgdGVtcDIzID0gdGhpcy52YWx1ZXNbMTFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHRoaXMudmFsdWVzWzEyXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IHRlbXAwMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gdGhpcy52YWx1ZXNbMTNdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gdGVtcDAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzldID0gdGVtcDEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzExXSA9IHRoaXMudmFsdWVzWzE0XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMl0gPSB0ZW1wMDM7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTNdID0gdGVtcDEzO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE0XSA9IHRlbXAyMztcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGludmVyc2UoKSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTAzID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTEzID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbOV07XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbMTBdO1xyXG4gICAgICAgIGNvbnN0IGEyMyA9IHRoaXMudmFsdWVzWzExXTtcclxuICAgICAgICBjb25zdCBhMzAgPSB0aGlzLnZhbHVlc1sxMl07XHJcbiAgICAgICAgY29uc3QgYTMxID0gdGhpcy52YWx1ZXNbMTNdO1xyXG4gICAgICAgIGNvbnN0IGEzMiA9IHRoaXMudmFsdWVzWzE0XTtcclxuICAgICAgICBjb25zdCBhMzMgPSB0aGlzLnZhbHVlc1sxNV07XHJcbiAgICAgICAgY29uc3QgZGV0MDAgPSBhMDAgKiBhMTEgLSBhMDEgKiBhMTA7XHJcbiAgICAgICAgY29uc3QgZGV0MDEgPSBhMDAgKiBhMTIgLSBhMDIgKiBhMTA7XHJcbiAgICAgICAgY29uc3QgZGV0MDIgPSBhMDAgKiBhMTMgLSBhMDMgKiBhMTA7XHJcbiAgICAgICAgY29uc3QgZGV0MDMgPSBhMDEgKiBhMTIgLSBhMDIgKiBhMTE7XHJcbiAgICAgICAgY29uc3QgZGV0MDQgPSBhMDEgKiBhMTMgLSBhMDMgKiBhMTE7XHJcbiAgICAgICAgY29uc3QgZGV0MDUgPSBhMDIgKiBhMTMgLSBhMDMgKiBhMTI7XHJcbiAgICAgICAgY29uc3QgZGV0MDYgPSBhMjAgKiBhMzEgLSBhMjEgKiBhMzA7XHJcbiAgICAgICAgY29uc3QgZGV0MDcgPSBhMjAgKiBhMzIgLSBhMjIgKiBhMzA7XHJcbiAgICAgICAgY29uc3QgZGV0MDggPSBhMjAgKiBhMzMgLSBhMjMgKiBhMzA7XHJcbiAgICAgICAgY29uc3QgZGV0MDkgPSBhMjEgKiBhMzIgLSBhMjIgKiBhMzE7XHJcbiAgICAgICAgY29uc3QgZGV0MTAgPSBhMjEgKiBhMzMgLSBhMjMgKiBhMzE7XHJcbiAgICAgICAgY29uc3QgZGV0MTEgPSBhMjIgKiBhMzMgLSBhMjMgKiBhMzI7XHJcbiAgICAgICAgbGV0IGRldCA9IGRldDAwICogZGV0MTEgLVxyXG4gICAgICAgICAgICBkZXQwMSAqIGRldDEwICtcclxuICAgICAgICAgICAgZGV0MDIgKiBkZXQwOSArXHJcbiAgICAgICAgICAgIGRldDAzICogZGV0MDggLVxyXG4gICAgICAgICAgICBkZXQwNCAqIGRldDA3ICtcclxuICAgICAgICAgICAgZGV0MDUgKiBkZXQwNjtcclxuICAgICAgICBpZiAoIWRldCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGV0ID0gMS4wIC8gZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gKGExMSAqIGRldDExIC0gYTEyICogZGV0MTAgKyBhMTMgKiBkZXQwOSkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSAoLWEwMSAqIGRldDExICsgYTAyICogZGV0MTAgLSBhMDMgKiBkZXQwOSkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSAoYTMxICogZGV0MDUgLSBhMzIgKiBkZXQwNCArIGEzMyAqIGRldDAzKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9ICgtYTIxICogZGV0MDUgKyBhMjIgKiBkZXQwNCAtIGEyMyAqIGRldDAzKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9ICgtYTEwICogZGV0MTEgKyBhMTIgKiBkZXQwOCAtIGExMyAqIGRldDA3KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IChhMDAgKiBkZXQxMSAtIGEwMiAqIGRldDA4ICsgYTAzICogZGV0MDcpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gKC1hMzAgKiBkZXQwNSArIGEzMiAqIGRldDAyIC0gYTMzICogZGV0MDEpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gKGEyMCAqIGRldDA1IC0gYTIyICogZGV0MDIgKyBhMjMgKiBkZXQwMSkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSAoYTEwICogZGV0MTAgLSBhMTEgKiBkZXQwOCArIGExMyAqIGRldDA2KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s5XSA9ICgtYTAwICogZGV0MTAgKyBhMDEgKiBkZXQwOCAtIGEwMyAqIGRldDA2KSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMF0gPSAoYTMwICogZGV0MDQgLSBhMzEgKiBkZXQwMiArIGEzMyAqIGRldDAwKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMV0gPSAoLWEyMCAqIGRldDA0ICsgYTIxICogZGV0MDIgLSBhMjMgKiBkZXQwMCkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTJdID0gKC1hMTAgKiBkZXQwOSArIGExMSAqIGRldDA3IC0gYTEyICogZGV0MDYpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEzXSA9IChhMDAgKiBkZXQwOSAtIGEwMSAqIGRldDA3ICsgYTAyICogZGV0MDYpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE0XSA9ICgtYTMwICogZGV0MDMgKyBhMzEgKiBkZXQwMSAtIGEzMiAqIGRldDAwKSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxNV0gPSAoYTIwICogZGV0MDMgLSBhMjEgKiBkZXQwMSArIGEyMiAqIGRldDAwKSAqIGRldDtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5KG1hdHJpeCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGEwMyA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGExMyA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzEwXTtcclxuICAgICAgICBjb25zdCBhMjMgPSB0aGlzLnZhbHVlc1sxMV07XHJcbiAgICAgICAgY29uc3QgYTMwID0gdGhpcy52YWx1ZXNbMTJdO1xyXG4gICAgICAgIGNvbnN0IGEzMSA9IHRoaXMudmFsdWVzWzEzXTtcclxuICAgICAgICBjb25zdCBhMzIgPSB0aGlzLnZhbHVlc1sxNF07XHJcbiAgICAgICAgY29uc3QgYTMzID0gdGhpcy52YWx1ZXNbMTVdO1xyXG4gICAgICAgIGxldCBiMCA9IG1hdHJpeC5hdCgwKTtcclxuICAgICAgICBsZXQgYjEgPSBtYXRyaXguYXQoMSk7XHJcbiAgICAgICAgbGV0IGIyID0gbWF0cml4LmF0KDIpO1xyXG4gICAgICAgIGxldCBiMyA9IG1hdHJpeC5hdCgzKTtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSBiMCAqIGEwMiArIGIxICogYTEyICsgYjIgKiBhMjIgKyBiMyAqIGEzMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzO1xyXG4gICAgICAgIGIwID0gbWF0cml4LmF0KDQpO1xyXG4gICAgICAgIGIxID0gbWF0cml4LmF0KDUpO1xyXG4gICAgICAgIGIyID0gbWF0cml4LmF0KDYpO1xyXG4gICAgICAgIGIzID0gbWF0cml4LmF0KDcpO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gYjAgKiBhMDAgKyBiMSAqIGExMCArIGIyICogYTIwICsgYjMgKiBhMzA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSBiMCAqIGEwMSArIGIxICogYTExICsgYjIgKiBhMjEgKyBiMyAqIGEzMTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gYjAgKiBhMDMgKyBiMSAqIGExMyArIGIyICogYTIzICsgYjMgKiBhMzM7XHJcbiAgICAgICAgYjAgPSBtYXRyaXguYXQoOCk7XHJcbiAgICAgICAgYjEgPSBtYXRyaXguYXQoOSk7XHJcbiAgICAgICAgYjIgPSBtYXRyaXguYXQoMTApO1xyXG4gICAgICAgIGIzID0gbWF0cml4LmF0KDExKTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzldID0gYjAgKiBhMDEgKyBiMSAqIGExMSArIGIyICogYTIxICsgYjMgKiBhMzE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTBdID0gYjAgKiBhMDIgKyBiMSAqIGExMiArIGIyICogYTIyICsgYjMgKiBhMzI7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTFdID0gYjAgKiBhMDMgKyBiMSAqIGExMyArIGIyICogYTIzICsgYjMgKiBhMzM7XHJcbiAgICAgICAgYjAgPSBtYXRyaXguYXQoMTIpO1xyXG4gICAgICAgIGIxID0gbWF0cml4LmF0KDEzKTtcclxuICAgICAgICBiMiA9IG1hdHJpeC5hdCgxNCk7XHJcbiAgICAgICAgYjMgPSBtYXRyaXguYXQoMTUpO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEyXSA9IGIwICogYTAwICsgYjEgKiBhMTAgKyBiMiAqIGEyMCArIGIzICogYTMwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEzXSA9IGIwICogYTAxICsgYjEgKiBhMTEgKyBiMiAqIGEyMSArIGIzICogYTMxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE0XSA9IGIwICogYTAyICsgYjEgKiBhMTIgKyBiMiAqIGEyMiArIGIzICogYTMyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzE1XSA9IGIwICogYTAzICsgYjEgKiBhMTMgKyBiMiAqIGEyMyArIGIzICogYTMzO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlWZWMzKHZlY3Rvcikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiBuZXcgdmVjMyhbXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzBdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s0XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbOF0gKiB6ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzEyXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMV0gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzVdICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s5XSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTNdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1syXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNl0gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzEwXSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTRdXHJcbiAgICAgICAgXSk7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseVZlYzQodmVjdG9yLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjNCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICBjb25zdCB3ID0gdmVjdG9yLnc7XHJcbiAgICAgICAgZGVzdC54ID1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMF0gKiB4ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzRdICogeSArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s4XSAqIHogK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTJdICogdztcclxuICAgICAgICBkZXN0LnkgPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1sxXSAqIHggK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNV0gKiB5ICtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzldICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxM10gKiB3O1xyXG4gICAgICAgIGRlc3QueiA9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzJdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s2XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTBdICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxNF0gKiB3O1xyXG4gICAgICAgIGRlc3QudyA9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzNdICogeCArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s3XSAqIHkgK1xyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTFdICogeiArXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1sxNV0gKiB3O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgdG9NYXQzKCkge1xyXG4gICAgICAgIHJldHVybiBuZXcgbWF0MyhbXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzBdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1sxXSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMl0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzRdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1s1XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzhdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1s5XSxcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMTBdXHJcbiAgICAgICAgXSk7XHJcbiAgICB9XHJcbiAgICB0b0ludmVyc2VNYXQzKCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzEwXTtcclxuICAgICAgICBjb25zdCBkZXQwMSA9IGEyMiAqIGExMSAtIGExMiAqIGEyMTtcclxuICAgICAgICBjb25zdCBkZXQxMSA9IC1hMjIgKiBhMTAgKyBhMTIgKiBhMjA7XHJcbiAgICAgICAgY29uc3QgZGV0MjEgPSBhMjEgKiBhMTAgLSBhMTEgKiBhMjA7XHJcbiAgICAgICAgbGV0IGRldCA9IGEwMCAqIGRldDAxICsgYTAxICogZGV0MTEgKyBhMDIgKiBkZXQyMTtcclxuICAgICAgICBpZiAoIWRldCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGV0ID0gMS4wIC8gZGV0O1xyXG4gICAgICAgIHJldHVybiBuZXcgbWF0MyhbXHJcbiAgICAgICAgICAgIGRldDAxICogZGV0LFxyXG4gICAgICAgICAgICAoLWEyMiAqIGEwMSArIGEwMiAqIGEyMSkgKiBkZXQsXHJcbiAgICAgICAgICAgIChhMTIgKiBhMDEgLSBhMDIgKiBhMTEpICogZGV0LFxyXG4gICAgICAgICAgICBkZXQxMSAqIGRldCxcclxuICAgICAgICAgICAgKGEyMiAqIGEwMCAtIGEwMiAqIGEyMCkgKiBkZXQsXHJcbiAgICAgICAgICAgICgtYTEyICogYTAwICsgYTAyICogYTEwKSAqIGRldCxcclxuICAgICAgICAgICAgZGV0MjEgKiBkZXQsXHJcbiAgICAgICAgICAgICgtYTIxICogYTAwICsgYTAxICogYTIwKSAqIGRldCxcclxuICAgICAgICAgICAgKGExMSAqIGEwMCAtIGEwMSAqIGExMCkgKiBkZXRcclxuICAgICAgICBdKTtcclxuICAgIH1cclxuICAgIHRyYW5zbGF0ZSh2ZWN0b3IpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMl0gKz1cclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbMF0gKiB4ICsgdGhpcy52YWx1ZXNbNF0gKiB5ICsgdGhpcy52YWx1ZXNbOF0gKiB6O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEzXSArPVxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1sxXSAqIHggKyB0aGlzLnZhbHVlc1s1XSAqIHkgKyB0aGlzLnZhbHVlc1s5XSAqIHo7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTRdICs9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzJdICogeCArIHRoaXMudmFsdWVzWzZdICogeSArIHRoaXMudmFsdWVzWzEwXSAqIHo7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMTVdICs9XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzWzNdICogeCArIHRoaXMudmFsdWVzWzddICogeSArIHRoaXMudmFsdWVzWzExXSAqIHo7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzY2FsZSh2ZWN0b3IpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSAqPSB4O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdICo9IHg7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gKj0geDtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSAqPSB4O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdICo9IHk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gKj0geTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSAqPSB5O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddICo9IHk7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gKj0gejtcclxuICAgICAgICB0aGlzLnZhbHVlc1s5XSAqPSB6O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEwXSAqPSB6O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzExXSAqPSB6O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgcm90YXRlKGFuZ2xlLCBheGlzKSB7XHJcbiAgICAgICAgbGV0IHggPSBheGlzLng7XHJcbiAgICAgICAgbGV0IHkgPSBheGlzLnk7XHJcbiAgICAgICAgbGV0IHogPSBheGlzLno7XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHopO1xyXG4gICAgICAgIGlmICghbGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobGVuZ3RoICE9PSAxKSB7XHJcbiAgICAgICAgICAgIGxlbmd0aCA9IDEgLyBsZW5ndGg7XHJcbiAgICAgICAgICAgIHggKj0gbGVuZ3RoO1xyXG4gICAgICAgICAgICB5ICo9IGxlbmd0aDtcclxuICAgICAgICAgICAgeiAqPSBsZW5ndGg7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHMgPSBNYXRoLnNpbihhbmdsZSk7XHJcbiAgICAgICAgY29uc3QgYyA9IE1hdGguY29zKGFuZ2xlKTtcclxuICAgICAgICBjb25zdCB0ID0gMS4wIC0gYztcclxuICAgICAgICBjb25zdCBhMDAgPSB0aGlzLnZhbHVlc1swXTtcclxuICAgICAgICBjb25zdCBhMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCBhMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCBhMDMgPSB0aGlzLnZhbHVlc1szXTtcclxuICAgICAgICBjb25zdCBhMTAgPSB0aGlzLnZhbHVlc1s0XTtcclxuICAgICAgICBjb25zdCBhMTEgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICBjb25zdCBhMTIgPSB0aGlzLnZhbHVlc1s2XTtcclxuICAgICAgICBjb25zdCBhMTMgPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICBjb25zdCBhMjAgPSB0aGlzLnZhbHVlc1s4XTtcclxuICAgICAgICBjb25zdCBhMjEgPSB0aGlzLnZhbHVlc1s5XTtcclxuICAgICAgICBjb25zdCBhMjIgPSB0aGlzLnZhbHVlc1sxMF07XHJcbiAgICAgICAgY29uc3QgYTIzID0gdGhpcy52YWx1ZXNbMTFdO1xyXG4gICAgICAgIGNvbnN0IGIwMCA9IHggKiB4ICogdCArIGM7XHJcbiAgICAgICAgY29uc3QgYjAxID0geSAqIHggKiB0ICsgeiAqIHM7XHJcbiAgICAgICAgY29uc3QgYjAyID0geiAqIHggKiB0IC0geSAqIHM7XHJcbiAgICAgICAgY29uc3QgYjEwID0geCAqIHkgKiB0IC0geiAqIHM7XHJcbiAgICAgICAgY29uc3QgYjExID0geSAqIHkgKiB0ICsgYztcclxuICAgICAgICBjb25zdCBiMTIgPSB6ICogeSAqIHQgKyB4ICogcztcclxuICAgICAgICBjb25zdCBiMjAgPSB4ICogeiAqIHQgKyB5ICogcztcclxuICAgICAgICBjb25zdCBiMjEgPSB5ICogeiAqIHQgLSB4ICogcztcclxuICAgICAgICBjb25zdCBiMjIgPSB6ICogeiAqIHQgKyBjO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gYTAwICogYjAwICsgYTEwICogYjAxICsgYTIwICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gYTAxICogYjAwICsgYTExICogYjAxICsgYTIxICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gYTAyICogYjAwICsgYTEyICogYjAxICsgYTIyICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gYTAzICogYjAwICsgYTEzICogYjAxICsgYTIzICogYjAyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gYTAwICogYjEwICsgYTEwICogYjExICsgYTIwICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gYTAxICogYjEwICsgYTExICogYjExICsgYTIxICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gYTAyICogYjEwICsgYTEyICogYjExICsgYTIyICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gYTAzICogYjEwICsgYTEzICogYjExICsgYTIzICogYjEyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gYTAwICogYjIwICsgYTEwICogYjIxICsgYTIwICogYjIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzldID0gYTAxICogYjIwICsgYTExICogYjIxICsgYTIxICogYjIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzEwXSA9IGEwMiAqIGIyMCArIGExMiAqIGIyMSArIGEyMiAqIGIyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxMV0gPSBhMDMgKiBiMjAgKyBhMTMgKiBiMjEgKyBhMjMgKiBiMjI7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZnJ1c3R1bShsZWZ0LCByaWdodCwgYm90dG9tLCB0b3AsIG5lYXIsIGZhcikge1xyXG4gICAgICAgIGNvbnN0IHJsID0gcmlnaHQgLSBsZWZ0O1xyXG4gICAgICAgIGNvbnN0IHRiID0gdG9wIC0gYm90dG9tO1xyXG4gICAgICAgIGNvbnN0IGZuID0gZmFyIC0gbmVhcjtcclxuICAgICAgICByZXR1cm4gbmV3IG1hdDQoW1xyXG4gICAgICAgICAgICAobmVhciAqIDIpIC8gcmwsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIChuZWFyICogMikgLyB0YixcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgKHJpZ2h0ICsgbGVmdCkgLyBybCxcclxuICAgICAgICAgICAgKHRvcCArIGJvdHRvbSkgLyB0YixcclxuICAgICAgICAgICAgLShmYXIgKyBuZWFyKSAvIGZuLFxyXG4gICAgICAgICAgICAtMSxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgLShmYXIgKiBuZWFyICogMikgLyBmbixcclxuICAgICAgICAgICAgMFxyXG4gICAgICAgIF0pO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHBlcnNwZWN0aXZlKGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIpIHtcclxuICAgICAgICBjb25zdCB0b3AgPSBuZWFyICogTWF0aC50YW4oKGZvdiAqIE1hdGguUEkpIC8gMzYwLjApO1xyXG4gICAgICAgIGNvbnN0IHJpZ2h0ID0gdG9wICogYXNwZWN0O1xyXG4gICAgICAgIHJldHVybiBtYXQ0LmZydXN0dW0oLXJpZ2h0LCByaWdodCwgLXRvcCwgdG9wLCBuZWFyLCBmYXIpO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIG9ydGhvZ3JhcGhpYyhsZWZ0LCByaWdodCwgYm90dG9tLCB0b3AsIG5lYXIsIGZhcikge1xyXG4gICAgICAgIGNvbnN0IHJsID0gcmlnaHQgLSBsZWZ0O1xyXG4gICAgICAgIGNvbnN0IHRiID0gdG9wIC0gYm90dG9tO1xyXG4gICAgICAgIGNvbnN0IGZuID0gZmFyIC0gbmVhcjtcclxuICAgICAgICByZXR1cm4gbmV3IG1hdDQoW1xyXG4gICAgICAgICAgICAyIC8gcmwsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgIDIgLyB0YixcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgLTIgLyBmbixcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgLShsZWZ0ICsgcmlnaHQpIC8gcmwsXHJcbiAgICAgICAgICAgIC0odG9wICsgYm90dG9tKSAvIHRiLFxyXG4gICAgICAgICAgICAtKGZhciArIG5lYXIpIC8gZm4sXHJcbiAgICAgICAgICAgIDFcclxuICAgICAgICBdKTtcclxuICAgIH1cclxuICAgIHN0YXRpYyBsb29rQXQocG9zaXRpb24sIHRhcmdldCwgdXAgPSB2ZWMzLnVwKSB7XHJcbiAgICAgICAgaWYgKHBvc2l0aW9uLmVxdWFscyh0YXJnZXQpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmlkZW50aXR5O1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB6ID0gdmVjMy5kaWZmZXJlbmNlKHBvc2l0aW9uLCB0YXJnZXQpLm5vcm1hbGl6ZSgpO1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWMzLmNyb3NzKHVwLCB6KS5ub3JtYWxpemUoKTtcclxuICAgICAgICBjb25zdCB5ID0gdmVjMy5jcm9zcyh6LCB4KS5ub3JtYWxpemUoKTtcclxuICAgICAgICByZXR1cm4gbmV3IG1hdDQoW1xyXG4gICAgICAgICAgICB4LngsXHJcbiAgICAgICAgICAgIHkueCxcclxuICAgICAgICAgICAgei54LFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICB4LnksXHJcbiAgICAgICAgICAgIHkueSxcclxuICAgICAgICAgICAgei55LFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICB4LnosXHJcbiAgICAgICAgICAgIHkueixcclxuICAgICAgICAgICAgei56LFxyXG4gICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAtdmVjMy5kb3QoeCwgcG9zaXRpb24pLFxyXG4gICAgICAgICAgICAtdmVjMy5kb3QoeSwgcG9zaXRpb24pLFxyXG4gICAgICAgICAgICAtdmVjMy5kb3QoeiwgcG9zaXRpb24pLFxyXG4gICAgICAgICAgICAxXHJcbiAgICAgICAgXSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcHJvZHVjdChtMSwgbTIsIHJlc3VsdCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IG0xLmF0KDApO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IG0xLmF0KDEpO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IG0xLmF0KDIpO1xyXG4gICAgICAgIGNvbnN0IGEwMyA9IG0xLmF0KDMpO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IG0xLmF0KDQpO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IG0xLmF0KDUpO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IG0xLmF0KDYpO1xyXG4gICAgICAgIGNvbnN0IGExMyA9IG0xLmF0KDcpO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IG0xLmF0KDgpO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IG0xLmF0KDkpO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IG0xLmF0KDEwKTtcclxuICAgICAgICBjb25zdCBhMjMgPSBtMS5hdCgxMSk7XHJcbiAgICAgICAgY29uc3QgYTMwID0gbTEuYXQoMTIpO1xyXG4gICAgICAgIGNvbnN0IGEzMSA9IG0xLmF0KDEzKTtcclxuICAgICAgICBjb25zdCBhMzIgPSBtMS5hdCgxNCk7XHJcbiAgICAgICAgY29uc3QgYTMzID0gbTEuYXQoMTUpO1xyXG4gICAgICAgIGNvbnN0IGIwMCA9IG0yLmF0KDApO1xyXG4gICAgICAgIGNvbnN0IGIwMSA9IG0yLmF0KDEpO1xyXG4gICAgICAgIGNvbnN0IGIwMiA9IG0yLmF0KDIpO1xyXG4gICAgICAgIGNvbnN0IGIwMyA9IG0yLmF0KDMpO1xyXG4gICAgICAgIGNvbnN0IGIxMCA9IG0yLmF0KDQpO1xyXG4gICAgICAgIGNvbnN0IGIxMSA9IG0yLmF0KDUpO1xyXG4gICAgICAgIGNvbnN0IGIxMiA9IG0yLmF0KDYpO1xyXG4gICAgICAgIGNvbnN0IGIxMyA9IG0yLmF0KDcpO1xyXG4gICAgICAgIGNvbnN0IGIyMCA9IG0yLmF0KDgpO1xyXG4gICAgICAgIGNvbnN0IGIyMSA9IG0yLmF0KDkpO1xyXG4gICAgICAgIGNvbnN0IGIyMiA9IG0yLmF0KDEwKTtcclxuICAgICAgICBjb25zdCBiMjMgPSBtMi5hdCgxMSk7XHJcbiAgICAgICAgY29uc3QgYjMwID0gbTIuYXQoMTIpO1xyXG4gICAgICAgIGNvbnN0IGIzMSA9IG0yLmF0KDEzKTtcclxuICAgICAgICBjb25zdCBiMzIgPSBtMi5hdCgxNCk7XHJcbiAgICAgICAgY29uc3QgYjMzID0gbTIuYXQoMTUpO1xyXG4gICAgICAgIGlmIChyZXN1bHQpIHtcclxuICAgICAgICAgICAgcmVzdWx0LmluaXQoW1xyXG4gICAgICAgICAgICAgICAgYjAwICogYTAwICsgYjAxICogYTEwICsgYjAyICogYTIwICsgYjAzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAxICsgYjAxICogYTExICsgYjAyICogYTIxICsgYjAzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAyICsgYjAxICogYTEyICsgYjAyICogYTIyICsgYjAzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAzICsgYjAxICogYTEzICsgYjAyICogYTIzICsgYjAzICogYTMzLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAwICsgYjExICogYTEwICsgYjEyICogYTIwICsgYjEzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAxICsgYjExICogYTExICsgYjEyICogYTIxICsgYjEzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAyICsgYjExICogYTEyICsgYjEyICogYTIyICsgYjEzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAzICsgYjExICogYTEzICsgYjEyICogYTIzICsgYjEzICogYTMzLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAwICsgYjIxICogYTEwICsgYjIyICogYTIwICsgYjIzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAxICsgYjIxICogYTExICsgYjIyICogYTIxICsgYjIzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAyICsgYjIxICogYTEyICsgYjIyICogYTIyICsgYjIzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAzICsgYjIxICogYTEzICsgYjIyICogYTIzICsgYjIzICogYTMzLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAwICsgYjMxICogYTEwICsgYjMyICogYTIwICsgYjMzICogYTMwLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAxICsgYjMxICogYTExICsgYjMyICogYTIxICsgYjMzICogYTMxLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAyICsgYjMxICogYTEyICsgYjMyICogYTIyICsgYjMzICogYTMyLFxyXG4gICAgICAgICAgICAgICAgYjMwICogYTAzICsgYjMxICogYTEzICsgYjMyICogYTIzICsgYjMzICogYTMzXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyBtYXQ0KFtcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMCArIGIwMSAqIGExMCArIGIwMiAqIGEyMCArIGIwMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMSArIGIwMSAqIGExMSArIGIwMiAqIGEyMSArIGIwMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMiArIGIwMSAqIGExMiArIGIwMiAqIGEyMiArIGIwMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIwMCAqIGEwMyArIGIwMSAqIGExMyArIGIwMiAqIGEyMyArIGIwMyAqIGEzMyxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMCArIGIxMSAqIGExMCArIGIxMiAqIGEyMCArIGIxMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMSArIGIxMSAqIGExMSArIGIxMiAqIGEyMSArIGIxMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMiArIGIxMSAqIGExMiArIGIxMiAqIGEyMiArIGIxMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIxMCAqIGEwMyArIGIxMSAqIGExMyArIGIxMiAqIGEyMyArIGIxMyAqIGEzMyxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMCArIGIyMSAqIGExMCArIGIyMiAqIGEyMCArIGIyMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMSArIGIyMSAqIGExMSArIGIyMiAqIGEyMSArIGIyMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMiArIGIyMSAqIGExMiArIGIyMiAqIGEyMiArIGIyMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIyMCAqIGEwMyArIGIyMSAqIGExMyArIGIyMiAqIGEyMyArIGIyMyAqIGEzMyxcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMCArIGIzMSAqIGExMCArIGIzMiAqIGEyMCArIGIzMyAqIGEzMCxcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMSArIGIzMSAqIGExMSArIGIzMiAqIGEyMSArIGIzMyAqIGEzMSxcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMiArIGIzMSAqIGExMiArIGIzMiAqIGEyMiArIGIzMyAqIGEzMixcclxuICAgICAgICAgICAgICAgIGIzMCAqIGEwMyArIGIzMSAqIGExMyArIGIzMiAqIGEyMyArIGIzMyAqIGEzM1xyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxubWF0NC5pZGVudGl0eSA9IG5ldyBtYXQ0KCkuc2V0SWRlbnRpdHkoKTtcclxuIiwiaW1wb3J0IHZlYzMgZnJvbSAnLi92ZWMzJztcclxuaW1wb3J0IHsgZXBzaWxvbiB9IGZyb20gJy4vY29uc3RhbnRzJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgdmVjMiB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoMik7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMueHkgPSB2YWx1ZXM7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZ2V0IHgoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzBdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHkoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzWzFdO1xyXG4gICAgfVxyXG4gICAgZ2V0IHh5KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdXTtcclxuICAgIH1cclxuICAgIHNldCB4KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB5KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB4eSh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGF0KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzW2luZGV4XTtcclxuICAgIH1cclxuICAgIHJlc2V0KCkge1xyXG4gICAgICAgIHRoaXMueCA9IDA7XHJcbiAgICAgICAgdGhpcy55ID0gMDtcclxuICAgIH1cclxuICAgIGNvcHkoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdGhpcy54O1xyXG4gICAgICAgIGRlc3QueSA9IHRoaXMueTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG5lZ2F0ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSAtdGhpcy54O1xyXG4gICAgICAgIGRlc3QueSA9IC10aGlzLnk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBlcXVhbHModmVjdG9yLCB0aHJlc2hvbGQgPSBlcHNpbG9uKSB7XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueCAtIHZlY3Rvci54KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnkgLSB2ZWN0b3IueSkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIGxlbmd0aCgpIHtcclxuICAgICAgICByZXR1cm4gTWF0aC5zcXJ0KHRoaXMuc3F1YXJlZExlbmd0aCgpKTtcclxuICAgIH1cclxuICAgIHNxdWFyZWRMZW5ndGgoKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5O1xyXG4gICAgfVxyXG4gICAgYWRkKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCArPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKz0gdmVjdG9yLnk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBzdWJ0cmFjdCh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLT0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC09IHZlY3Rvci55O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHkodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54ICo9IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAqPSB2ZWN0b3IueTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGRpdmlkZSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLz0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC89IHZlY3Rvci55O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc2NhbGUodmFsdWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCAqPSB2YWx1ZTtcclxuICAgICAgICBkZXN0LnkgKj0gdmFsdWU7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBub3JtYWxpemUoZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IHRoaXMubGVuZ3RoKCk7XHJcbiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICBkZXN0LnggPSAwO1xyXG4gICAgICAgICAgICBkZXN0LnkgPSAwO1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGVuZ3RoID0gMS4wIC8gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueCAqPSBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC55ICo9IGxlbmd0aDtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG11bHRpcGx5TWF0MihtYXRyaXgsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBtYXRyaXgubXVsdGlwbHlWZWMyKHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlNYXQzKG1hdHJpeCwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIG1hdHJpeC5tdWx0aXBseVZlYzIodGhpcywgZGVzdCk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgY3Jvc3ModmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHgyID0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkyID0gdmVjdG9yMi55O1xyXG4gICAgICAgIGNvbnN0IHogPSB4ICogeTIgLSB5ICogeDI7XHJcbiAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICBkZXN0LnkgPSAwO1xyXG4gICAgICAgIGRlc3QueiA9IHo7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZG90KHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIHJldHVybiB2ZWN0b3IueCAqIHZlY3RvcjIueCArIHZlY3Rvci55ICogdmVjdG9yMi55O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkRGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3F1YXJlZERpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IyLnggLSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yMi55IC0gdmVjdG9yLnk7XHJcbiAgICAgICAgcmV0dXJuIHggKiB4ICsgeSAqIHk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlyZWN0aW9uKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueSAtIHZlY3RvcjIueTtcclxuICAgICAgICBsZXQgbGVuZ3RoID0gTWF0aC5zcXJ0KHggKiB4ICsgeSAqIHkpO1xyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ID0geCAqIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgPSB5ICogbGVuZ3RoO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIG1peCh2ZWN0b3IsIHZlY3RvcjIsIHRpbWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeDIgPSB2ZWN0b3IyLng7XHJcbiAgICAgICAgY29uc3QgeTIgPSB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC54ID0geCArIHRpbWUgKiAoeDIgLSB4KTtcclxuICAgICAgICBkZXN0LnkgPSB5ICsgdGltZSAqICh5MiAtIHkpO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHN1bSh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54ICsgdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55ICsgdmVjdG9yMi55O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRpZmZlcmVuY2UodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAtIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAtIHZlY3RvcjIueTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBwcm9kdWN0KHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzIoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKiB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKiB2ZWN0b3IyLnk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcXVvdGllbnQodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAvIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAvIHZlY3RvcjIueTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxufVxyXG52ZWMyLnplcm8gPSBuZXcgdmVjMihbMCwgMF0pO1xyXG52ZWMyLm9uZSA9IG5ldyB2ZWMyKFsxLCAxXSk7XHJcbiIsImltcG9ydCBtYXQ0IGZyb20gJy4vbWF0NCc7XHJcbmltcG9ydCBxdWF0IGZyb20gJy4vcXVhdCc7XHJcbmltcG9ydCB2ZWMyIGZyb20gJy4vdmVjMic7XHJcbmltcG9ydCB2ZWMzIGZyb20gJy4vdmVjMyc7XHJcbmltcG9ydCB7IGVwc2lsb24gfSBmcm9tICcuL2NvbnN0YW50cyc7XHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIG1hdDMge1xyXG4gICAgY29uc3RydWN0b3IodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KDkpO1xyXG4gICAgICAgIGlmICh2YWx1ZXMgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICB0aGlzLmluaXQodmFsdWVzKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBhdChpbmRleCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1tpbmRleF07XHJcbiAgICB9XHJcbiAgICBpbml0KHZhbHVlcykge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgOTsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2ldID0gdmFsdWVzW2ldO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHJlc2V0KCkge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgOTsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2ldID0gMDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBtYXQzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgOTsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc3QudmFsdWVzW2ldID0gdGhpcy52YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgYWxsKCkge1xyXG4gICAgICAgIGNvbnN0IGRhdGEgPSBbXTtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDk7IGkrKykge1xyXG4gICAgICAgICAgICBkYXRhW2ldID0gdGhpcy52YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBkYXRhO1xyXG4gICAgfVxyXG4gICAgcm93KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgdGhpcy52YWx1ZXNbaW5kZXggKiAzICsgMF0sXHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2luZGV4ICogMyArIDFdLFxyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpbmRleCAqIDMgKyAyXVxyXG4gICAgICAgIF07XHJcbiAgICB9XHJcbiAgICBjb2woaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzW2luZGV4XSwgdGhpcy52YWx1ZXNbaW5kZXggKyAzXSwgdGhpcy52YWx1ZXNbaW5kZXggKyA2XV07XHJcbiAgICB9XHJcbiAgICBlcXVhbHMobWF0cml4LCB0aHJlc2hvbGQgPSBlcHNpbG9uKSB7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCA5OyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMudmFsdWVzW2ldIC0gbWF0cml4LmF0KGkpKSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgZGV0ZXJtaW5hbnQoKSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgZGV0MDEgPSBhMjIgKiBhMTEgLSBhMTIgKiBhMjE7XHJcbiAgICAgICAgY29uc3QgZGV0MTEgPSAtYTIyICogYTEwICsgYTEyICogYTIwO1xyXG4gICAgICAgIGNvbnN0IGRldDIxID0gYTIxICogYTEwIC0gYTExICogYTIwO1xyXG4gICAgICAgIHJldHVybiBhMDAgKiBkZXQwMSArIGEwMSAqIGRldDExICsgYTAyICogZGV0MjE7XHJcbiAgICB9XHJcbiAgICBzZXRJZGVudGl0eSgpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNF0gPSAxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gMDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IDA7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSAwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gMTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHRyYW5zcG9zZSgpIHtcclxuICAgICAgICBjb25zdCB0ZW1wMDEgPSB0aGlzLnZhbHVlc1sxXTtcclxuICAgICAgICBjb25zdCB0ZW1wMDIgPSB0aGlzLnZhbHVlc1syXTtcclxuICAgICAgICBjb25zdCB0ZW1wMTIgPSB0aGlzLnZhbHVlc1s1XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB0ZW1wMDE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbNV0gPSB0aGlzLnZhbHVlc1s3XTtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IHRlbXAwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IHRlbXAxMjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGludmVyc2UoKSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gdGhpcy52YWx1ZXNbMF07XHJcbiAgICAgICAgY29uc3QgYTAxID0gdGhpcy52YWx1ZXNbMV07XHJcbiAgICAgICAgY29uc3QgYTAyID0gdGhpcy52YWx1ZXNbMl07XHJcbiAgICAgICAgY29uc3QgYTEwID0gdGhpcy52YWx1ZXNbM107XHJcbiAgICAgICAgY29uc3QgYTExID0gdGhpcy52YWx1ZXNbNF07XHJcbiAgICAgICAgY29uc3QgYTEyID0gdGhpcy52YWx1ZXNbNV07XHJcbiAgICAgICAgY29uc3QgYTIwID0gdGhpcy52YWx1ZXNbNl07XHJcbiAgICAgICAgY29uc3QgYTIxID0gdGhpcy52YWx1ZXNbN107XHJcbiAgICAgICAgY29uc3QgYTIyID0gdGhpcy52YWx1ZXNbOF07XHJcbiAgICAgICAgY29uc3QgZGV0MDEgPSBhMjIgKiBhMTEgLSBhMTIgKiBhMjE7XHJcbiAgICAgICAgY29uc3QgZGV0MTEgPSAtYTIyICogYTEwICsgYTEyICogYTIwO1xyXG4gICAgICAgIGNvbnN0IGRldDIxID0gYTIxICogYTEwIC0gYTExICogYTIwO1xyXG4gICAgICAgIGxldCBkZXQgPSBhMDAgKiBkZXQwMSArIGEwMSAqIGRldDExICsgYTAyICogZGV0MjE7XHJcbiAgICAgICAgaWYgKCFkZXQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRldCA9IDEuMCAvIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IGRldDAxICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gKC1hMjIgKiBhMDEgKyBhMDIgKiBhMjEpICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gKGExMiAqIGEwMSAtIGEwMiAqIGExMSkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSBkZXQxMSAqIGRldDtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IChhMjIgKiBhMDAgLSBhMDIgKiBhMjApICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gKC1hMTIgKiBhMDAgKyBhMDIgKiBhMTApICogZGV0O1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gZGV0MjEgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbN10gPSAoLWEyMSAqIGEwMCArIGEwMSAqIGEyMCkgKiBkZXQ7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbOF0gPSAoYTExICogYTAwIC0gYTAxICogYTEwKSAqIGRldDtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIG11bHRpcGx5KG1hdHJpeCkge1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGIwMCA9IG1hdHJpeC5hdCgwKTtcclxuICAgICAgICBjb25zdCBiMDEgPSBtYXRyaXguYXQoMSk7XHJcbiAgICAgICAgY29uc3QgYjAyID0gbWF0cml4LmF0KDIpO1xyXG4gICAgICAgIGNvbnN0IGIxMCA9IG1hdHJpeC5hdCgzKTtcclxuICAgICAgICBjb25zdCBiMTEgPSBtYXRyaXguYXQoNCk7XHJcbiAgICAgICAgY29uc3QgYjEyID0gbWF0cml4LmF0KDUpO1xyXG4gICAgICAgIGNvbnN0IGIyMCA9IG1hdHJpeC5hdCg2KTtcclxuICAgICAgICBjb25zdCBiMjEgPSBtYXRyaXguYXQoNyk7XHJcbiAgICAgICAgY29uc3QgYjIyID0gbWF0cml4LmF0KDgpO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gYjAwICogYTAwICsgYjAxICogYTEwICsgYjAyICogYTIwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gYjAwICogYTAxICsgYjAxICogYTExICsgYjAyICogYTIxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gYjAwICogYTAyICsgYjAxICogYTEyICsgYjAyICogYTIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzNdID0gYjEwICogYTAwICsgYjExICogYTEwICsgYjEyICogYTIwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzRdID0gYjEwICogYTAxICsgYjExICogYTExICsgYjEyICogYTIxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzVdID0gYjEwICogYTAyICsgYjExICogYTEyICsgYjEyICogYTIyO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzZdID0gYjIwICogYTAwICsgYjIxICogYTEwICsgYjIyICogYTIwO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzddID0gYjIwICogYTAxICsgYjIxICogYTExICsgYjIyICogYTIxO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzhdID0gYjIwICogYTAyICsgYjIxICogYTEyICsgYjIyICogYTIyO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlWZWMyKHZlY3RvciwgcmVzdWx0KSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBpZiAocmVzdWx0KSB7XHJcbiAgICAgICAgICAgIHJlc3VsdC54eSA9IFtcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1swXSArIHkgKiB0aGlzLnZhbHVlc1szXSArIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICAgICAgeCAqIHRoaXMudmFsdWVzWzFdICsgeSAqIHRoaXMudmFsdWVzWzRdICsgdGhpcy52YWx1ZXNbN11cclxuICAgICAgICAgICAgXTtcclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiBuZXcgdmVjMihbXHJcbiAgICAgICAgICAgICAgICB4ICogdGhpcy52YWx1ZXNbMF0gKyB5ICogdGhpcy52YWx1ZXNbM10gKyB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1sxXSArIHkgKiB0aGlzLnZhbHVlc1s0XSArIHRoaXMudmFsdWVzWzddXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIG11bHRpcGx5VmVjMyh2ZWN0b3IsIHJlc3VsdCkge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIGlmIChyZXN1bHQpIHtcclxuICAgICAgICAgICAgcmVzdWx0Lnh5eiA9IFtcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1swXSArIHkgKiB0aGlzLnZhbHVlc1szXSArIHogKiB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1sxXSArIHkgKiB0aGlzLnZhbHVlc1s0XSArIHogKiB0aGlzLnZhbHVlc1s3XSxcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1syXSArIHkgKiB0aGlzLnZhbHVlc1s1XSArIHogKiB0aGlzLnZhbHVlc1s4XVxyXG4gICAgICAgICAgICBdO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyB2ZWMzKFtcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1swXSArIHkgKiB0aGlzLnZhbHVlc1szXSArIHogKiB0aGlzLnZhbHVlc1s2XSxcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1sxXSArIHkgKiB0aGlzLnZhbHVlc1s0XSArIHogKiB0aGlzLnZhbHVlc1s3XSxcclxuICAgICAgICAgICAgICAgIHggKiB0aGlzLnZhbHVlc1syXSArIHkgKiB0aGlzLnZhbHVlc1s1XSArIHogKiB0aGlzLnZhbHVlc1s4XVxyXG4gICAgICAgICAgICBdKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICB0b01hdDQocmVzdWx0KSB7XHJcbiAgICAgICAgaWYgKHJlc3VsdCkge1xyXG4gICAgICAgICAgICByZXN1bHQuaW5pdChbXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1swXSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzFdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMl0sXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbM10sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s0XSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzVdLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzZdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbN10sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s4XSxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAxXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG5ldyBtYXQ0KFtcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzBdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbMV0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1syXSxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1szXSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzRdLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNV0sXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNbNl0sXHJcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlc1s3XSxcclxuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzWzhdLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDAsXHJcbiAgICAgICAgICAgICAgICAwLFxyXG4gICAgICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgICAgIDFcclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgdG9RdWF0KCkge1xyXG4gICAgICAgIGNvbnN0IG0wMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IG0wMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IG0wMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IG0xMCA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IG0xMSA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IG0xMiA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IG0yMCA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IG0yMSA9IHRoaXMudmFsdWVzWzddO1xyXG4gICAgICAgIGNvbnN0IG0yMiA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGZvdXJYU3F1YXJlZE1pbnVzMSA9IG0wMCAtIG0xMSAtIG0yMjtcclxuICAgICAgICBjb25zdCBmb3VyWVNxdWFyZWRNaW51czEgPSBtMTEgLSBtMDAgLSBtMjI7XHJcbiAgICAgICAgY29uc3QgZm91clpTcXVhcmVkTWludXMxID0gbTIyIC0gbTAwIC0gbTExO1xyXG4gICAgICAgIGNvbnN0IGZvdXJXU3F1YXJlZE1pbnVzMSA9IG0wMCArIG0xMSArIG0yMjtcclxuICAgICAgICBsZXQgYmlnZ2VzdEluZGV4ID0gMDtcclxuICAgICAgICBsZXQgZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxID0gZm91cldTcXVhcmVkTWludXMxO1xyXG4gICAgICAgIGlmIChmb3VyWFNxdWFyZWRNaW51czEgPiBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEpIHtcclxuICAgICAgICAgICAgZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxID0gZm91clhTcXVhcmVkTWludXMxO1xyXG4gICAgICAgICAgICBiaWdnZXN0SW5kZXggPSAxO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZm91cllTcXVhcmVkTWludXMxID4gZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxKSB7XHJcbiAgICAgICAgICAgIGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSA9IGZvdXJZU3F1YXJlZE1pbnVzMTtcclxuICAgICAgICAgICAgYmlnZ2VzdEluZGV4ID0gMjtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGZvdXJaU3F1YXJlZE1pbnVzMSA+IGZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSkge1xyXG4gICAgICAgICAgICBmb3VyQmlnZ2VzdFNxdWFyZWRNaW51czEgPSBmb3VyWlNxdWFyZWRNaW51czE7XHJcbiAgICAgICAgICAgIGJpZ2dlc3RJbmRleCA9IDM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGJpZ2dlc3RWYWwgPSBNYXRoLnNxcnQoZm91ckJpZ2dlc3RTcXVhcmVkTWludXMxICsgMSkgKiAwLjU7XHJcbiAgICAgICAgY29uc3QgbXVsdCA9IDAuMjUgLyBiaWdnZXN0VmFsO1xyXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgc3dpdGNoIChiaWdnZXN0SW5kZXgpIHtcclxuICAgICAgICAgICAgY2FzZSAwOlxyXG4gICAgICAgICAgICAgICAgcmVzdWx0LncgPSBiaWdnZXN0VmFsO1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnggPSAobTEyIC0gbTIxKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueSA9IChtMjAgLSBtMDIpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC56ID0gKG0wMSAtIG0xMCkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgMTpcclxuICAgICAgICAgICAgICAgIHJlc3VsdC53ID0gKG0xMiAtIG0yMSkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnggPSBiaWdnZXN0VmFsO1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnkgPSAobTAxICsgbTEwKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueiA9IChtMjAgKyBtMDIpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlIDI6XHJcbiAgICAgICAgICAgICAgICByZXN1bHQudyA9IChtMjAgLSBtMDIpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC54ID0gKG0wMSArIG0xMCkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnkgPSBiaWdnZXN0VmFsO1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnogPSAobTEyICsgbTIxKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSAzOlxyXG4gICAgICAgICAgICAgICAgcmVzdWx0LncgPSAobTAxIC0gbTEwKSAqIG11bHQ7XHJcbiAgICAgICAgICAgICAgICByZXN1bHQueCA9IChtMjAgKyBtMDIpICogbXVsdDtcclxuICAgICAgICAgICAgICAgIHJlc3VsdC55ID0gKG0xMiArIG0yMSkgKiBtdWx0O1xyXG4gICAgICAgICAgICAgICAgcmVzdWx0LnogPSBiaWdnZXN0VmFsO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9XHJcbiAgICByb3RhdGUoYW5nbGUsIGF4aXMpIHtcclxuICAgICAgICBsZXQgeCA9IGF4aXMueDtcclxuICAgICAgICBsZXQgeSA9IGF4aXMueTtcclxuICAgICAgICBsZXQgeiA9IGF4aXMuejtcclxuICAgICAgICBsZXQgbGVuZ3RoID0gTWF0aC5zcXJ0KHggKiB4ICsgeSAqIHkgKyB6ICogeik7XHJcbiAgICAgICAgaWYgKCFsZW5ndGgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChsZW5ndGggIT09IDEpIHtcclxuICAgICAgICAgICAgbGVuZ3RoID0gMSAvIGxlbmd0aDtcclxuICAgICAgICAgICAgeCAqPSBsZW5ndGg7XHJcbiAgICAgICAgICAgIHkgKj0gbGVuZ3RoO1xyXG4gICAgICAgICAgICB6ICo9IGxlbmd0aDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcyA9IE1hdGguc2luKGFuZ2xlKTtcclxuICAgICAgICBjb25zdCBjID0gTWF0aC5jb3MoYW5nbGUpO1xyXG4gICAgICAgIGNvbnN0IHQgPSAxLjAgLSBjO1xyXG4gICAgICAgIGNvbnN0IGEwMCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IGEwMSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IGEwMiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IGExMCA9IHRoaXMudmFsdWVzWzRdO1xyXG4gICAgICAgIGNvbnN0IGExMSA9IHRoaXMudmFsdWVzWzVdO1xyXG4gICAgICAgIGNvbnN0IGExMiA9IHRoaXMudmFsdWVzWzZdO1xyXG4gICAgICAgIGNvbnN0IGEyMCA9IHRoaXMudmFsdWVzWzhdO1xyXG4gICAgICAgIGNvbnN0IGEyMSA9IHRoaXMudmFsdWVzWzldO1xyXG4gICAgICAgIGNvbnN0IGEyMiA9IHRoaXMudmFsdWVzWzEwXTtcclxuICAgICAgICBjb25zdCBiMDAgPSB4ICogeCAqIHQgKyBjO1xyXG4gICAgICAgIGNvbnN0IGIwMSA9IHkgKiB4ICogdCArIHogKiBzO1xyXG4gICAgICAgIGNvbnN0IGIwMiA9IHogKiB4ICogdCAtIHkgKiBzO1xyXG4gICAgICAgIGNvbnN0IGIxMCA9IHggKiB5ICogdCAtIHogKiBzO1xyXG4gICAgICAgIGNvbnN0IGIxMSA9IHkgKiB5ICogdCArIGM7XHJcbiAgICAgICAgY29uc3QgYjEyID0geiAqIHkgKiB0ICsgeCAqIHM7XHJcbiAgICAgICAgY29uc3QgYjIwID0geCAqIHogKiB0ICsgeSAqIHM7XHJcbiAgICAgICAgY29uc3QgYjIxID0geSAqIHogKiB0IC0geCAqIHM7XHJcbiAgICAgICAgY29uc3QgYjIyID0geiAqIHogKiB0ICsgYztcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IGEwMCAqIGIwMCArIGExMCAqIGIwMSArIGEyMCAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IGEwMSAqIGIwMCArIGExMSAqIGIwMSArIGEyMSAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IGEwMiAqIGIwMCArIGExMiAqIGIwMSArIGEyMiAqIGIwMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IGEwMCAqIGIxMCArIGExMCAqIGIxMSArIGEyMCAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s0XSA9IGEwMSAqIGIxMCArIGExMSAqIGIxMSArIGEyMSAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s1XSA9IGEwMiAqIGIxMCArIGExMiAqIGIxMSArIGEyMiAqIGIxMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s2XSA9IGEwMCAqIGIyMCArIGExMCAqIGIyMSArIGEyMCAqIGIyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s3XSA9IGEwMSAqIGIyMCArIGExMSAqIGIyMSArIGEyMSAqIGIyMjtcclxuICAgICAgICB0aGlzLnZhbHVlc1s4XSA9IGEwMiAqIGIyMCArIGExMiAqIGIyMSArIGEyMiAqIGIyMjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHN0YXRpYyBwcm9kdWN0KG0xLCBtMiwgcmVzdWx0KSB7XHJcbiAgICAgICAgY29uc3QgYTAwID0gbTEuYXQoMCk7XHJcbiAgICAgICAgY29uc3QgYTAxID0gbTEuYXQoMSk7XHJcbiAgICAgICAgY29uc3QgYTAyID0gbTEuYXQoMik7XHJcbiAgICAgICAgY29uc3QgYTEwID0gbTEuYXQoMyk7XHJcbiAgICAgICAgY29uc3QgYTExID0gbTEuYXQoNCk7XHJcbiAgICAgICAgY29uc3QgYTEyID0gbTEuYXQoNSk7XHJcbiAgICAgICAgY29uc3QgYTIwID0gbTEuYXQoNik7XHJcbiAgICAgICAgY29uc3QgYTIxID0gbTEuYXQoNyk7XHJcbiAgICAgICAgY29uc3QgYTIyID0gbTEuYXQoOCk7XHJcbiAgICAgICAgY29uc3QgYjAwID0gbTIuYXQoMCk7XHJcbiAgICAgICAgY29uc3QgYjAxID0gbTIuYXQoMSk7XHJcbiAgICAgICAgY29uc3QgYjAyID0gbTIuYXQoMik7XHJcbiAgICAgICAgY29uc3QgYjEwID0gbTIuYXQoMyk7XHJcbiAgICAgICAgY29uc3QgYjExID0gbTIuYXQoNCk7XHJcbiAgICAgICAgY29uc3QgYjEyID0gbTIuYXQoNSk7XHJcbiAgICAgICAgY29uc3QgYjIwID0gbTIuYXQoNik7XHJcbiAgICAgICAgY29uc3QgYjIxID0gbTIuYXQoNyk7XHJcbiAgICAgICAgY29uc3QgYjIyID0gbTIuYXQoOCk7XHJcbiAgICAgICAgaWYgKHJlc3VsdCkge1xyXG4gICAgICAgICAgICByZXN1bHQuaW5pdChbXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDAgKyBiMDEgKiBhMTAgKyBiMDIgKiBhMjAsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDEgKyBiMDEgKiBhMTEgKyBiMDIgKiBhMjEsXHJcbiAgICAgICAgICAgICAgICBiMDAgKiBhMDIgKyBiMDEgKiBhMTIgKyBiMDIgKiBhMjIsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDAgKyBiMTEgKiBhMTAgKyBiMTIgKiBhMjAsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDEgKyBiMTEgKiBhMTEgKyBiMTIgKiBhMjEsXHJcbiAgICAgICAgICAgICAgICBiMTAgKiBhMDIgKyBiMTEgKiBhMTIgKyBiMTIgKiBhMjIsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDAgKyBiMjEgKiBhMTAgKyBiMjIgKiBhMjAsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDEgKyBiMjEgKiBhMTEgKyBiMjIgKiBhMjEsXHJcbiAgICAgICAgICAgICAgICBiMjAgKiBhMDIgKyBiMjEgKiBhMTIgKyBiMjIgKiBhMjJcclxuICAgICAgICAgICAgXSk7XHJcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbmV3IG1hdDMoW1xyXG4gICAgICAgICAgICAgICAgYjAwICogYTAwICsgYjAxICogYTEwICsgYjAyICogYTIwLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAxICsgYjAxICogYTExICsgYjAyICogYTIxLFxyXG4gICAgICAgICAgICAgICAgYjAwICogYTAyICsgYjAxICogYTEyICsgYjAyICogYTIyLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAwICsgYjExICogYTEwICsgYjEyICogYTIwLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAxICsgYjExICogYTExICsgYjEyICogYTIxLFxyXG4gICAgICAgICAgICAgICAgYjEwICogYTAyICsgYjExICogYTEyICsgYjEyICogYTIyLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAwICsgYjIxICogYTEwICsgYjIyICogYTIwLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAxICsgYjIxICogYTExICsgYjIyICogYTIxLFxyXG4gICAgICAgICAgICAgICAgYjIwICogYTAyICsgYjIxICogYTEyICsgYjIyICogYTIyXHJcbiAgICAgICAgICAgIF0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG5tYXQzLmlkZW50aXR5ID0gbmV3IG1hdDMoKS5zZXRJZGVudGl0eSgpO1xyXG4iLCJpbXBvcnQgbWF0MyBmcm9tICcuL21hdDMnO1xyXG5pbXBvcnQgbWF0NCBmcm9tICcuL21hdDQnO1xyXG5pbXBvcnQgdmVjMyBmcm9tICcuL3ZlYzMnO1xyXG5pbXBvcnQgeyBlcHNpbG9uIH0gZnJvbSAnLi9jb25zdGFudHMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBxdWF0IHtcclxuICAgIGNvbnN0cnVjdG9yKHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSg0KTtcclxuICAgICAgICBpZiAodmFsdWVzICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy54eXp3ID0gdmFsdWVzO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldCB4KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1swXTtcclxuICAgIH1cclxuICAgIGdldCB5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGdldCB6KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIGdldCB3KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1szXTtcclxuICAgIH1cclxuICAgIGdldCB4eSgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHl6KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHl6dygpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXSwgdGhpcy52YWx1ZXNbMl0sIHRoaXMudmFsdWVzWzNdXTtcclxuICAgIH1cclxuICAgIHNldCB4KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB5KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB6KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB3KHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbM10gPSB2YWx1ZTtcclxuICAgIH1cclxuICAgIHNldCB4eSh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIHNldCB4eXoodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gPSB2YWx1ZXNbMl07XHJcbiAgICB9XHJcbiAgICBzZXQgeHl6dyh2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlc1swXSA9IHZhbHVlc1swXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1sxXSA9IHZhbHVlc1sxXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1syXSA9IHZhbHVlc1syXTtcclxuICAgICAgICB0aGlzLnZhbHVlc1szXSA9IHZhbHVlc1szXTtcclxuICAgIH1cclxuICAgIGF0KGluZGV4KSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzW2luZGV4XTtcclxuICAgIH1cclxuICAgIHJlc2V0KCkge1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNDsgaSsrKSB7XHJcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW2ldID0gMDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc3QudmFsdWVzW2ldID0gdGhpcy52YWx1ZXNbaV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgcm9sbCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIHJldHVybiBNYXRoLmF0YW4yKDIuMCAqICh4ICogeSArIHcgKiB6KSwgdyAqIHcgKyB4ICogeCAtIHkgKiB5IC0geiAqIHopO1xyXG4gICAgfVxyXG4gICAgcGl0Y2goKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICByZXR1cm4gTWF0aC5hdGFuMigyLjAgKiAoeSAqIHogKyB3ICogeCksIHcgKiB3IC0geCAqIHggLSB5ICogeSArIHogKiB6KTtcclxuICAgIH1cclxuICAgIHlhdygpIHtcclxuICAgICAgICByZXR1cm4gTWF0aC5hc2luKDIuMCAqICh0aGlzLnggKiB0aGlzLnogLSB0aGlzLncgKiB0aGlzLnkpKTtcclxuICAgIH1cclxuICAgIGVxdWFscyh2ZWN0b3IsIHRocmVzaG9sZCA9IGVwc2lsb24pIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQ7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoTWF0aC5hYnModGhpcy52YWx1ZXNbaV0gLSB2ZWN0b3IuYXQoaSkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICBzZXRJZGVudGl0eSgpIHtcclxuICAgICAgICB0aGlzLnggPSAwO1xyXG4gICAgICAgIHRoaXMueSA9IDA7XHJcbiAgICAgICAgdGhpcy56ID0gMDtcclxuICAgICAgICB0aGlzLncgPSAxO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgY2FsY3VsYXRlVygpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICB0aGlzLncgPSAtTWF0aC5zcXJ0KE1hdGguYWJzKDEuMCAtIHggKiB4IC0geSAqIHkgLSB6ICogeikpO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgaW52ZXJzZSgpIHtcclxuICAgICAgICBjb25zdCBkb3QgPSBxdWF0LmRvdCh0aGlzLCB0aGlzKTtcclxuICAgICAgICBpZiAoIWRvdCkge1xyXG4gICAgICAgICAgICB0aGlzLnh5encgPSBbMCwgMCwgMCwgMF07XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBpbnZEb3QgPSBkb3QgPyAxLjAgLyBkb3QgOiAwO1xyXG4gICAgICAgIHRoaXMueCAqPSAtaW52RG90O1xyXG4gICAgICAgIHRoaXMueSAqPSAtaW52RG90O1xyXG4gICAgICAgIHRoaXMueiAqPSAtaW52RG90O1xyXG4gICAgICAgIHRoaXMudyAqPSBpbnZEb3Q7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBjb25qdWdhdGUoKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gKj0gLTE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gKj0gLTE7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMl0gKj0gLTE7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBsZW5ndGgoKSB7XHJcbiAgICAgICAgY29uc3QgeCA9IHRoaXMueDtcclxuICAgICAgICBjb25zdCB5ID0gdGhpcy55O1xyXG4gICAgICAgIGNvbnN0IHogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgdyA9IHRoaXMudztcclxuICAgICAgICByZXR1cm4gTWF0aC5zcXJ0KHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3KTtcclxuICAgIH1cclxuICAgIG5vcm1hbGl6ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICBjb25zdCB3ID0gdGhpcy53O1xyXG4gICAgICAgIGxldCBsZW5ndGggPSBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSArIHogKiB6ICsgdyAqIHcpO1xyXG4gICAgICAgIGlmICghbGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueSA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueiA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QudyA9IDA7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZW5ndGggPSAxIC8gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueCA9IHggKiBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC55ID0geSAqIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnogPSB6ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QudyA9IHcgKiBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBhZGQob3RoZXIpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQ7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLnZhbHVlc1tpXSArPSBvdGhlci5hdChpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseShvdGhlcikge1xyXG4gICAgICAgIGNvbnN0IHExeCA9IHRoaXMudmFsdWVzWzBdO1xyXG4gICAgICAgIGNvbnN0IHExeSA9IHRoaXMudmFsdWVzWzFdO1xyXG4gICAgICAgIGNvbnN0IHExeiA9IHRoaXMudmFsdWVzWzJdO1xyXG4gICAgICAgIGNvbnN0IHExdyA9IHRoaXMudmFsdWVzWzNdO1xyXG4gICAgICAgIGNvbnN0IHEyeCA9IG90aGVyLng7XHJcbiAgICAgICAgY29uc3QgcTJ5ID0gb3RoZXIueTtcclxuICAgICAgICBjb25zdCBxMnogPSBvdGhlci56O1xyXG4gICAgICAgIGNvbnN0IHEydyA9IG90aGVyLnc7XHJcbiAgICAgICAgdGhpcy54ID0gcTF4ICogcTJ3ICsgcTF3ICogcTJ4ICsgcTF5ICogcTJ6IC0gcTF6ICogcTJ5O1xyXG4gICAgICAgIHRoaXMueSA9IHExeSAqIHEydyArIHExdyAqIHEyeSArIHExeiAqIHEyeCAtIHExeCAqIHEyejtcclxuICAgICAgICB0aGlzLnogPSBxMXogKiBxMncgKyBxMXcgKiBxMnogKyBxMXggKiBxMnkgLSBxMXkgKiBxMng7XHJcbiAgICAgICAgdGhpcy53ID0gcTF3ICogcTJ3IC0gcTF4ICogcTJ4IC0gcTF5ICogcTJ5IC0gcTF6ICogcTJ6O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlWZWMzKHZlY3RvciwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLno7XHJcbiAgICAgICAgY29uc3QgcXggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgcXkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgcXogPSB0aGlzLno7XHJcbiAgICAgICAgY29uc3QgcXcgPSB0aGlzLnc7XHJcbiAgICAgICAgY29uc3QgaXggPSBxdyAqIHggKyBxeSAqIHogLSBxeiAqIHk7XHJcbiAgICAgICAgY29uc3QgaXkgPSBxdyAqIHkgKyBxeiAqIHggLSBxeCAqIHo7XHJcbiAgICAgICAgY29uc3QgaXogPSBxdyAqIHogKyBxeCAqIHkgLSBxeSAqIHg7XHJcbiAgICAgICAgY29uc3QgaXcgPSAtcXggKiB4IC0gcXkgKiB5IC0gcXogKiB6O1xyXG4gICAgICAgIGRlc3QueCA9IGl4ICogcXcgKyBpdyAqIC1xeCArIGl5ICogLXF6IC0gaXogKiAtcXk7XHJcbiAgICAgICAgZGVzdC55ID0gaXkgKiBxdyArIGl3ICogLXF5ICsgaXogKiAtcXggLSBpeCAqIC1xejtcclxuICAgICAgICBkZXN0LnogPSBpeiAqIHF3ICsgaXcgKiAtcXogKyBpeCAqIC1xeSAtIGl5ICogLXF4O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgdG9NYXQzKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBtYXQzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgY29uc3QgeDIgPSB4ICsgeDtcclxuICAgICAgICBjb25zdCB5MiA9IHkgKyB5O1xyXG4gICAgICAgIGNvbnN0IHoyID0geiArIHo7XHJcbiAgICAgICAgY29uc3QgeHggPSB4ICogeDI7XHJcbiAgICAgICAgY29uc3QgeHkgPSB4ICogeTI7XHJcbiAgICAgICAgY29uc3QgeHogPSB4ICogejI7XHJcbiAgICAgICAgY29uc3QgeXkgPSB5ICogeTI7XHJcbiAgICAgICAgY29uc3QgeXogPSB5ICogejI7XHJcbiAgICAgICAgY29uc3QgenogPSB6ICogejI7XHJcbiAgICAgICAgY29uc3Qgd3ggPSB3ICogeDI7XHJcbiAgICAgICAgY29uc3Qgd3kgPSB3ICogeTI7XHJcbiAgICAgICAgY29uc3Qgd3ogPSB3ICogejI7XHJcbiAgICAgICAgZGVzdC5pbml0KFtcclxuICAgICAgICAgICAgMSAtICh5eSArIHp6KSxcclxuICAgICAgICAgICAgeHkgKyB3eixcclxuICAgICAgICAgICAgeHogLSB3eSxcclxuICAgICAgICAgICAgeHkgLSB3eixcclxuICAgICAgICAgICAgMSAtICh4eCArIHp6KSxcclxuICAgICAgICAgICAgeXogKyB3eCxcclxuICAgICAgICAgICAgeHogKyB3eSxcclxuICAgICAgICAgICAgeXogLSB3eCxcclxuICAgICAgICAgICAgMSAtICh4eCArIHl5KVxyXG4gICAgICAgIF0pO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgdG9NYXQ0KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBtYXQ0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB0aGlzLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHRoaXMueTtcclxuICAgICAgICBjb25zdCB6ID0gdGhpcy56O1xyXG4gICAgICAgIGNvbnN0IHcgPSB0aGlzLnc7XHJcbiAgICAgICAgY29uc3QgeDIgPSB4ICsgeDtcclxuICAgICAgICBjb25zdCB5MiA9IHkgKyB5O1xyXG4gICAgICAgIGNvbnN0IHoyID0geiArIHo7XHJcbiAgICAgICAgY29uc3QgeHggPSB4ICogeDI7XHJcbiAgICAgICAgY29uc3QgeHkgPSB4ICogeTI7XHJcbiAgICAgICAgY29uc3QgeHogPSB4ICogejI7XHJcbiAgICAgICAgY29uc3QgeXkgPSB5ICogeTI7XHJcbiAgICAgICAgY29uc3QgeXogPSB5ICogejI7XHJcbiAgICAgICAgY29uc3QgenogPSB6ICogejI7XHJcbiAgICAgICAgY29uc3Qgd3ggPSB3ICogeDI7XHJcbiAgICAgICAgY29uc3Qgd3kgPSB3ICogeTI7XHJcbiAgICAgICAgY29uc3Qgd3ogPSB3ICogejI7XHJcbiAgICAgICAgZGVzdC5pbml0KFtcclxuICAgICAgICAgICAgMSAtICh5eSArIHp6KSxcclxuICAgICAgICAgICAgeHkgKyB3eixcclxuICAgICAgICAgICAgeHogLSB3eSxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgeHkgLSB3eixcclxuICAgICAgICAgICAgMSAtICh4eCArIHp6KSxcclxuICAgICAgICAgICAgeXogKyB3eCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgeHogKyB3eSxcclxuICAgICAgICAgICAgeXogLSB3eCxcclxuICAgICAgICAgICAgMSAtICh4eCArIHl5KSxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMCxcclxuICAgICAgICAgICAgMVxyXG4gICAgICAgIF0pO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRvdChxMSwgcTIpIHtcclxuICAgICAgICByZXR1cm4gcTEueCAqIHEyLnggKyBxMS55ICogcTIueSArIHExLnogKiBxMi56ICsgcTEudyAqIHEyLnc7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3VtKHExLCBxMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gcTEueCArIHEyLng7XHJcbiAgICAgICAgZGVzdC55ID0gcTEueSArIHEyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gcTEueiArIHEyLno7XHJcbiAgICAgICAgZGVzdC53ID0gcTEudyArIHEyLnc7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgcHJvZHVjdChxMSwgcTIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHExeCA9IHExLng7XHJcbiAgICAgICAgY29uc3QgcTF5ID0gcTEueTtcclxuICAgICAgICBjb25zdCBxMXogPSBxMS56O1xyXG4gICAgICAgIGNvbnN0IHExdyA9IHExLnc7XHJcbiAgICAgICAgY29uc3QgcTJ4ID0gcTIueDtcclxuICAgICAgICBjb25zdCBxMnkgPSBxMi55O1xyXG4gICAgICAgIGNvbnN0IHEyeiA9IHEyLno7XHJcbiAgICAgICAgY29uc3QgcTJ3ID0gcTIudztcclxuICAgICAgICBkZXN0LnggPSBxMXggKiBxMncgKyBxMXcgKiBxMnggKyBxMXkgKiBxMnogLSBxMXogKiBxMnk7XHJcbiAgICAgICAgZGVzdC55ID0gcTF5ICogcTJ3ICsgcTF3ICogcTJ5ICsgcTF6ICogcTJ4IC0gcTF4ICogcTJ6O1xyXG4gICAgICAgIGRlc3QueiA9IHExeiAqIHEydyArIHExdyAqIHEyeiArIHExeCAqIHEyeSAtIHExeSAqIHEyeDtcclxuICAgICAgICBkZXN0LncgPSBxMXcgKiBxMncgLSBxMXggKiBxMnggLSBxMXkgKiBxMnkgLSBxMXogKiBxMno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgY3Jvc3MocTEsIHEyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgcXVhdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBxMXggPSBxMS54O1xyXG4gICAgICAgIGNvbnN0IHExeSA9IHExLnk7XHJcbiAgICAgICAgY29uc3QgcTF6ID0gcTEuejtcclxuICAgICAgICBjb25zdCBxMXcgPSBxMS53O1xyXG4gICAgICAgIGNvbnN0IHEyeCA9IHEyLng7XHJcbiAgICAgICAgY29uc3QgcTJ5ID0gcTIueTtcclxuICAgICAgICBjb25zdCBxMnogPSBxMi56O1xyXG4gICAgICAgIGNvbnN0IHEydyA9IHEyLnc7XHJcbiAgICAgICAgZGVzdC54ID0gcTF3ICogcTJ6ICsgcTF6ICogcTJ3ICsgcTF4ICogcTJ5IC0gcTF5ICogcTJ4O1xyXG4gICAgICAgIGRlc3QueSA9IHExdyAqIHEydyAtIHExeCAqIHEyeCAtIHExeSAqIHEyeSAtIHExeiAqIHEyejtcclxuICAgICAgICBkZXN0LnogPSBxMXcgKiBxMnggKyBxMXggKiBxMncgKyBxMXkgKiBxMnogLSBxMXogKiBxMnk7XHJcbiAgICAgICAgZGVzdC53ID0gcTF3ICogcTJ5ICsgcTF5ICogcTJ3ICsgcTF6ICogcTJ4IC0gcTF4ICogcTJ6O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHNob3J0TWl4KHExLCBxMiwgdGltZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHF1YXQoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHRpbWUgPD0gMC4wKSB7XHJcbiAgICAgICAgICAgIGRlc3QueHl6dyA9IHExLnh5enc7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIGlmICh0aW1lID49IDEuMCkge1xyXG4gICAgICAgICAgICBkZXN0Lnh5encgPSBxMi54eXp3O1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGNvcyA9IHF1YXQuZG90KHExLCBxMik7XHJcbiAgICAgICAgY29uc3QgcTJhID0gcTIuY29weSgpO1xyXG4gICAgICAgIGlmIChjb3MgPCAwLjApIHtcclxuICAgICAgICAgICAgcTJhLmludmVyc2UoKTtcclxuICAgICAgICAgICAgY29zID0gLWNvcztcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGswO1xyXG4gICAgICAgIGxldCBrMTtcclxuICAgICAgICBpZiAoY29zID4gMC45OTk5KSB7XHJcbiAgICAgICAgICAgIGswID0gMSAtIHRpbWU7XHJcbiAgICAgICAgICAgIGsxID0gMCArIHRpbWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICBjb25zdCBzaW4gPSBNYXRoLnNxcnQoMSAtIGNvcyAqIGNvcyk7XHJcbiAgICAgICAgICAgIGNvbnN0IGFuZ2xlID0gTWF0aC5hdGFuMihzaW4sIGNvcyk7XHJcbiAgICAgICAgICAgIGNvbnN0IG9uZU92ZXJTaW4gPSAxIC8gc2luO1xyXG4gICAgICAgICAgICBrMCA9IE1hdGguc2luKCgxIC0gdGltZSkgKiBhbmdsZSkgKiBvbmVPdmVyU2luO1xyXG4gICAgICAgICAgICBrMSA9IE1hdGguc2luKCgwICsgdGltZSkgKiBhbmdsZSkgKiBvbmVPdmVyU2luO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSBrMCAqIHExLnggKyBrMSAqIHEyYS54O1xyXG4gICAgICAgIGRlc3QueSA9IGswICogcTEueSArIGsxICogcTJhLnk7XHJcbiAgICAgICAgZGVzdC56ID0gazAgKiBxMS56ICsgazEgKiBxMmEuejtcclxuICAgICAgICBkZXN0LncgPSBrMCAqIHExLncgKyBrMSAqIHEyYS53O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIG1peChxMSwgcTIsIHRpbWUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGNvc0hhbGZUaGV0YSA9IHExLnggKiBxMi54ICsgcTEueSAqIHEyLnkgKyBxMS56ICogcTIueiArIHExLncgKiBxMi53O1xyXG4gICAgICAgIGlmIChNYXRoLmFicyhjb3NIYWxmVGhldGEpID49IDEuMCkge1xyXG4gICAgICAgICAgICBkZXN0Lnh5encgPSBxMS54eXp3O1xyXG4gICAgICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgaGFsZlRoZXRhID0gTWF0aC5hY29zKGNvc0hhbGZUaGV0YSk7XHJcbiAgICAgICAgY29uc3Qgc2luSGFsZlRoZXRhID0gTWF0aC5zcXJ0KDEuMCAtIGNvc0hhbGZUaGV0YSAqIGNvc0hhbGZUaGV0YSk7XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHNpbkhhbGZUaGV0YSkgPCAwLjAwMSkge1xyXG4gICAgICAgICAgICBkZXN0LnggPSBxMS54ICogMC41ICsgcTIueCAqIDAuNTtcclxuICAgICAgICAgICAgZGVzdC55ID0gcTEueSAqIDAuNSArIHEyLnkgKiAwLjU7XHJcbiAgICAgICAgICAgIGRlc3QueiA9IHExLnogKiAwLjUgKyBxMi56ICogMC41O1xyXG4gICAgICAgICAgICBkZXN0LncgPSBxMS53ICogMC41ICsgcTIudyAqIDAuNTtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHJhdGlvQSA9IE1hdGguc2luKCgxIC0gdGltZSkgKiBoYWxmVGhldGEpIC8gc2luSGFsZlRoZXRhO1xyXG4gICAgICAgIGNvbnN0IHJhdGlvQiA9IE1hdGguc2luKHRpbWUgKiBoYWxmVGhldGEpIC8gc2luSGFsZlRoZXRhO1xyXG4gICAgICAgIGRlc3QueCA9IHExLnggKiByYXRpb0EgKyBxMi54ICogcmF0aW9CO1xyXG4gICAgICAgIGRlc3QueSA9IHExLnkgKiByYXRpb0EgKyBxMi55ICogcmF0aW9CO1xyXG4gICAgICAgIGRlc3QueiA9IHExLnogKiByYXRpb0EgKyBxMi56ICogcmF0aW9CO1xyXG4gICAgICAgIGRlc3QudyA9IHExLncgKiByYXRpb0EgKyBxMi53ICogcmF0aW9CO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGZyb21BeGlzQW5nbGUoYXhpcywgYW5nbGUsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGFuZ2xlICo9IDAuNTtcclxuICAgICAgICBjb25zdCBzaW4gPSBNYXRoLnNpbihhbmdsZSk7XHJcbiAgICAgICAgZGVzdC54ID0gYXhpcy54ICogc2luO1xyXG4gICAgICAgIGRlc3QueSA9IGF4aXMueSAqIHNpbjtcclxuICAgICAgICBkZXN0LnogPSBheGlzLnogKiBzaW47XHJcbiAgICAgICAgZGVzdC53ID0gTWF0aC5jb3MoYW5nbGUpO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGZyb21WZWN0b3JzKHUsIHYsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KFswLCAwLCAwLCAxXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBkID0gY2xhbXAodmVjMy5kb3QodSwgdiksIC0xLCAxKTtcclxuICAgICAgICBsZXQgYXhpcyA9IHZlYzMuY3Jvc3ModSwgdik7XHJcbiAgICAgICAgbGV0IHF3ID0gTWF0aC5zcXJ0KHUuc3F1YXJlZExlbmd0aCgpICogdi5zcXVhcmVkTGVuZ3RoKCkpICsgZDtcclxuICAgICAgICBpZiAocXcgPCAwLjAwMDEpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KFstdS56LCB1LnksIHUueCwgMF0pLm5vcm1hbGl6ZSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0ID0gbmV3IHF1YXQoW3F3LCBheGlzLngsIGF4aXMueSwgYXhpcy56XSkubm9ybWFsaXplKCk7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZnJvbUF4aXNSYWRpYW5zKHgsIHksIHosIHJhZGlhbnMsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KFswLCAwLCAwLCAxXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCB0ZW1wID0gbmV3IHZlYzMoW3gsIHksIHpdKTtcclxuICAgICAgICBsZXQgZCA9IHRlbXAubGVuZ3RoKCk7XHJcbiAgICAgICAgaWYgKGQgPT0gMCkge1xyXG4gICAgICAgICAgICByZXR1cm4gcXVhdC5pZGVudGl0eTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZCA9IDEgLyBkO1xyXG4gICAgICAgIGxldCBsX2FuZ2xlID0gMDtcclxuICAgICAgICBpZiAocmFkaWFucyA8IDApIHtcclxuICAgICAgICAgICAgbF9hbmdsZSA9IChNYXRoLlBJICogMikgLSAoLTEgKiByYWRpYW5zICUgKE1hdGguUEkgKiAyKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICBsX2FuZ2xlID0gcmFkaWFucyAlIChNYXRoLlBJICogMik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBsX3NpbiA9IE1hdGguc2luKGxfYW5nbGUgLyAyKTtcclxuICAgICAgICBsZXQgbF9jb3MgPSBNYXRoLmNvcyhsX2FuZ2xlIC8gMik7XHJcbiAgICAgICAgZGVzdC54ID0gZCAqIHggKiBsX3NpbjtcclxuICAgICAgICBkZXN0LnkgPSBkICogeSAqIGxfc2luO1xyXG4gICAgICAgIGRlc3QueiA9IGQgKiB6ICogbF9zaW47XHJcbiAgICAgICAgZGVzdC53ID0gbF9jb3M7XHJcbiAgICAgICAgZGVzdC5ub3JtYWxpemUoKTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxufVxyXG5xdWF0LmlkZW50aXR5ID0gbmV3IHF1YXQoKS5zZXRJZGVudGl0eSgpO1xyXG5mdW5jdGlvbiBjbGFtcCh4LCBhLCBiKSB7XHJcbiAgICBpZiAoeCA8IGEpIHtcclxuICAgICAgICByZXR1cm4gYTtcclxuICAgIH1cclxuICAgIGVsc2UgaWYgKHggPiBiKSB7XHJcbiAgICAgICAgcmV0dXJuIGI7XHJcbiAgICB9XHJcbiAgICByZXR1cm4geDtcclxufVxyXG4iLCJpbXBvcnQgcXVhdCBmcm9tIFwiLi9xdWF0XCI7XHJcbmltcG9ydCB7IGVwc2lsb24gfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgdmVjMyB7XHJcbiAgICBjb25zdHJ1Y3Rvcih2YWx1ZXMpIHtcclxuICAgICAgICB0aGlzLnZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkoMyk7XHJcbiAgICAgICAgaWYgKHZhbHVlcyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMueHl6ID0gdmFsdWVzO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldCB4KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1swXTtcclxuICAgIH1cclxuICAgIGdldCB5KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1sxXTtcclxuICAgIH1cclxuICAgIGdldCB6KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlc1syXTtcclxuICAgIH1cclxuICAgIGdldCB4eSgpIHtcclxuICAgICAgICByZXR1cm4gW3RoaXMudmFsdWVzWzBdLCB0aGlzLnZhbHVlc1sxXV07XHJcbiAgICB9XHJcbiAgICBnZXQgeHl6KCkge1xyXG4gICAgICAgIHJldHVybiBbdGhpcy52YWx1ZXNbMF0sIHRoaXMudmFsdWVzWzFdLCB0aGlzLnZhbHVlc1syXV07XHJcbiAgICB9XHJcbiAgICBzZXQgeCh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeih2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWU7XHJcbiAgICB9XHJcbiAgICBzZXQgeHkodmFsdWVzKSB7XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMF0gPSB2YWx1ZXNbMF07XHJcbiAgICAgICAgdGhpcy52YWx1ZXNbMV0gPSB2YWx1ZXNbMV07XHJcbiAgICB9XHJcbiAgICBzZXQgeHl6KHZhbHVlcykge1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzBdID0gdmFsdWVzWzBdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzFdID0gdmFsdWVzWzFdO1xyXG4gICAgICAgIHRoaXMudmFsdWVzWzJdID0gdmFsdWVzWzJdO1xyXG4gICAgfVxyXG4gICAgYXQoaW5kZXgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXNbaW5kZXhdO1xyXG4gICAgfVxyXG4gICAgcmVzZXQoKSB7XHJcbiAgICAgICAgdGhpcy54ID0gMDtcclxuICAgICAgICB0aGlzLnkgPSAwO1xyXG4gICAgICAgIHRoaXMueiA9IDA7XHJcbiAgICB9XHJcbiAgICBjb3B5KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHRoaXMueDtcclxuICAgICAgICBkZXN0LnkgPSB0aGlzLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdGhpcy56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgbmVnYXRlKGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IC10aGlzLng7XHJcbiAgICAgICAgZGVzdC55ID0gLXRoaXMueTtcclxuICAgICAgICBkZXN0LnogPSAtdGhpcy56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgZXF1YWxzKHZlY3RvciwgdGhyZXNob2xkID0gZXBzaWxvbikge1xyXG4gICAgICAgIGlmIChNYXRoLmFicyh0aGlzLnggLSB2ZWN0b3IueCkgPiB0aHJlc2hvbGQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoTWF0aC5hYnModGhpcy55IC0gdmVjdG9yLnkpID4gdGhyZXNob2xkKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKE1hdGguYWJzKHRoaXMueiAtIHZlY3Rvci56KSA+IHRocmVzaG9sZCkge1xyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgbGVuZ3RoKCkge1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkTGVuZ3RoKCkpO1xyXG4gICAgfVxyXG4gICAgc3F1YXJlZExlbmd0aCgpIHtcclxuICAgICAgICBjb25zdCB4ID0gdGhpcy54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB0aGlzLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHRoaXMuejtcclxuICAgICAgICByZXR1cm4geCAqIHggKyB5ICogeSArIHogKiB6O1xyXG4gICAgfVxyXG4gICAgYWRkKHZlY3Rvcikge1xyXG4gICAgICAgIHRoaXMueCArPSB2ZWN0b3IueDtcclxuICAgICAgICB0aGlzLnkgKz0gdmVjdG9yLnk7XHJcbiAgICAgICAgdGhpcy56ICs9IHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG4gICAgc3VidHJhY3QodmVjdG9yKSB7XHJcbiAgICAgICAgdGhpcy54IC09IHZlY3Rvci54O1xyXG4gICAgICAgIHRoaXMueSAtPSB2ZWN0b3IueTtcclxuICAgICAgICB0aGlzLnogLT0gdmVjdG9yLno7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggKj0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55ICo9IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAqPSB2ZWN0b3IuejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIGRpdmlkZSh2ZWN0b3IpIHtcclxuICAgICAgICB0aGlzLnggLz0gdmVjdG9yLng7XHJcbiAgICAgICAgdGhpcy55IC89IHZlY3Rvci55O1xyXG4gICAgICAgIHRoaXMueiAvPSB2ZWN0b3IuejtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIHNjYWxlKHZhbHVlLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggKj0gdmFsdWU7XHJcbiAgICAgICAgZGVzdC55ICo9IHZhbHVlO1xyXG4gICAgICAgIGRlc3QueiAqPSB2YWx1ZTtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIG5vcm1hbGl6ZShkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcclxuICAgICAgICBpZiAobGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIGRlc3QueCA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueSA9IDA7XHJcbiAgICAgICAgICAgIGRlc3QueiA9IDA7XHJcbiAgICAgICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZW5ndGggPSAxLjAgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ICo9IGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgKj0gbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueiAqPSBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBtdWx0aXBseUJ5TWF0MyhtYXRyaXgsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IHRoaXM7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBtYXRyaXgubXVsdGlwbHlWZWMzKHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgbXVsdGlwbHlCeVF1YXQocXVhdGVybmlvbiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gdGhpcztcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHF1YXRlcm5pb24ubXVsdGlwbHlWZWMzKHRoaXMsIGRlc3QpO1xyXG4gICAgfVxyXG4gICAgdG9RdWF0KGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyBxdWF0KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IGMgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIGNvbnN0IHMgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIGMueCA9IE1hdGguY29zKHRoaXMueCAqIDAuNSk7XHJcbiAgICAgICAgcy54ID0gTWF0aC5zaW4odGhpcy54ICogMC41KTtcclxuICAgICAgICBjLnkgPSBNYXRoLmNvcyh0aGlzLnkgKiAwLjUpO1xyXG4gICAgICAgIHMueSA9IE1hdGguc2luKHRoaXMueSAqIDAuNSk7XHJcbiAgICAgICAgYy56ID0gTWF0aC5jb3ModGhpcy56ICogMC41KTtcclxuICAgICAgICBzLnogPSBNYXRoLnNpbih0aGlzLnogKiAwLjUpO1xyXG4gICAgICAgIGRlc3QueCA9IHMueCAqIGMueSAqIGMueiAtIGMueCAqIHMueSAqIHMuejtcclxuICAgICAgICBkZXN0LnkgPSBjLnggKiBzLnkgKiBjLnogKyBzLnggKiBjLnkgKiBzLno7XHJcbiAgICAgICAgZGVzdC56ID0gYy54ICogYy55ICogcy56IC0gcy54ICogcy55ICogYy56O1xyXG4gICAgICAgIGRlc3QudyA9IGMueCAqIGMueSAqIGMueiArIHMueCAqIHMueSAqIHMuejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBjcm9zcyh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3Rvci56O1xyXG4gICAgICAgIGNvbnN0IHgyID0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkyID0gdmVjdG9yMi55O1xyXG4gICAgICAgIGNvbnN0IHoyID0gdmVjdG9yMi56O1xyXG4gICAgICAgIGRlc3QueCA9IHkgKiB6MiAtIHogKiB5MjtcclxuICAgICAgICBkZXN0LnkgPSB6ICogeDIgLSB4ICogejI7XHJcbiAgICAgICAgZGVzdC56ID0geCAqIHkyIC0geSAqIHgyO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRvdCh2ZWN0b3IsIHZlY3RvcjIpIHtcclxuICAgICAgICBjb25zdCB4ID0gdmVjdG9yLng7XHJcbiAgICAgICAgY29uc3QgeSA9IHZlY3Rvci55O1xyXG4gICAgICAgIGNvbnN0IHogPSB2ZWN0b3IuejtcclxuICAgICAgICBjb25zdCB4MiA9IHZlY3RvcjIueDtcclxuICAgICAgICBjb25zdCB5MiA9IHZlY3RvcjIueTtcclxuICAgICAgICBjb25zdCB6MiA9IHZlY3RvcjIuejtcclxuICAgICAgICByZXR1cm4geCAqIHgyICsgeSAqIHkyICsgeiAqIHoyO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGRpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IyLnggLSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yMi55IC0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3RvcjIueiAtIHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiBNYXRoLnNxcnQodGhpcy5zcXVhcmVkRGlzdGFuY2UodmVjdG9yLCB2ZWN0b3IyKSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3F1YXJlZERpc3RhbmNlKHZlY3RvciwgdmVjdG9yMikge1xyXG4gICAgICAgIGNvbnN0IHggPSB2ZWN0b3IyLnggLSB2ZWN0b3IueDtcclxuICAgICAgICBjb25zdCB5ID0gdmVjdG9yMi55IC0gdmVjdG9yLnk7XHJcbiAgICAgICAgY29uc3QgeiA9IHZlY3RvcjIueiAtIHZlY3Rvci56O1xyXG4gICAgICAgIHJldHVybiB4ICogeCArIHkgKiB5ICsgeiAqIHo7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlyZWN0aW9uKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgeCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGNvbnN0IHkgPSB2ZWN0b3IueSAtIHZlY3RvcjIueTtcclxuICAgICAgICBjb25zdCB6ID0gdmVjdG9yLnogLSB2ZWN0b3IyLno7XHJcbiAgICAgICAgbGV0IGxlbmd0aCA9IE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHopO1xyXG4gICAgICAgIGlmIChsZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVzdC54ID0gMDtcclxuICAgICAgICAgICAgZGVzdC55ID0gMDtcclxuICAgICAgICAgICAgZGVzdC56ID0gMDtcclxuICAgICAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxlbmd0aCA9IDEgLyBsZW5ndGg7XHJcbiAgICAgICAgZGVzdC54ID0geCAqIGxlbmd0aDtcclxuICAgICAgICBkZXN0LnkgPSB5ICogbGVuZ3RoO1xyXG4gICAgICAgIGRlc3QueiA9IHogKiBsZW5ndGg7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgbWl4KHZlY3RvciwgdmVjdG9yMiwgdGltZSwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB0aW1lICogKHZlY3RvcjIueCAtIHZlY3Rvci54KTtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSArIHRpbWUgKiAodmVjdG9yMi55IC0gdmVjdG9yLnkpO1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56ICsgdGltZSAqICh2ZWN0b3IyLnogLSB2ZWN0b3Iueik7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgc3VtKHZlY3RvciwgdmVjdG9yMiwgZGVzdCkge1xyXG4gICAgICAgIGlmICghZGVzdCkge1xyXG4gICAgICAgICAgICBkZXN0ID0gbmV3IHZlYzMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZGVzdC54ID0gdmVjdG9yLnggKyB2ZWN0b3IyLng7XHJcbiAgICAgICAgZGVzdC55ID0gdmVjdG9yLnkgKyB2ZWN0b3IyLnk7XHJcbiAgICAgICAgZGVzdC56ID0gdmVjdG9yLnogKyB2ZWN0b3IyLno7XHJcbiAgICAgICAgcmV0dXJuIGRlc3Q7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgZGlmZmVyZW5jZSh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC0gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC0gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56IC0gdmVjdG9yMi56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHByb2R1Y3QodmVjdG9yLCB2ZWN0b3IyLCBkZXN0KSB7XHJcbiAgICAgICAgaWYgKCFkZXN0KSB7XHJcbiAgICAgICAgICAgIGRlc3QgPSBuZXcgdmVjMygpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZXN0LnggPSB2ZWN0b3IueCAqIHZlY3RvcjIueDtcclxuICAgICAgICBkZXN0LnkgPSB2ZWN0b3IueSAqIHZlY3RvcjIueTtcclxuICAgICAgICBkZXN0LnogPSB2ZWN0b3IueiAqIHZlY3RvcjIuejtcclxuICAgICAgICByZXR1cm4gZGVzdDtcclxuICAgIH1cclxuICAgIHN0YXRpYyBxdW90aWVudCh2ZWN0b3IsIHZlY3RvcjIsIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlc3QueCA9IHZlY3Rvci54IC8gdmVjdG9yMi54O1xyXG4gICAgICAgIGRlc3QueSA9IHZlY3Rvci55IC8gdmVjdG9yMi55O1xyXG4gICAgICAgIGRlc3QueiA9IHZlY3Rvci56IC8gdmVjdG9yMi56O1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG4gICAgc3RhdGljIHJvdGF0ZSh2YWx1ZSwgcm90YXRpb24sIGRlc3QpIHtcclxuICAgICAgICBpZiAoIWRlc3QpIHtcclxuICAgICAgICAgICAgZGVzdCA9IG5ldyB2ZWMzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCB4ID0gMiAqIChyb3RhdGlvbi55ICogdmFsdWUueiAtIHJvdGF0aW9uLnogKiB2YWx1ZS55KTtcclxuICAgICAgICBsZXQgeSA9IDIgKiAocm90YXRpb24ueiAqIHZhbHVlLnggLSByb3RhdGlvbi54ICogdmFsdWUueik7XHJcbiAgICAgICAgbGV0IHogPSAyICogKHJvdGF0aW9uLnggKiB2YWx1ZS55IC0gcm90YXRpb24ueSAqIHZhbHVlLngpO1xyXG4gICAgICAgIGRlc3QueCA9IHZhbHVlLnggKyB4ICogcm90YXRpb24udyArIChyb3RhdGlvbi55ICogeiAtIHJvdGF0aW9uLnogKiB5KTtcclxuICAgICAgICBkZXN0LnkgPSB2YWx1ZS55ICsgeSAqIHJvdGF0aW9uLncgKyAocm90YXRpb24ueiAqIHggLSByb3RhdGlvbi54ICogeik7XHJcbiAgICAgICAgZGVzdC56ID0gdmFsdWUueiArIHogKiByb3RhdGlvbi53ICsgKHJvdGF0aW9uLnggKiB5IC0gcm90YXRpb24ueSAqIHgpO1xyXG4gICAgICAgIHJldHVybiBkZXN0O1xyXG4gICAgfVxyXG59XHJcbnZlYzMuemVybyA9IG5ldyB2ZWMzKFswLCAwLCAwXSk7XHJcbnZlYzMub25lID0gbmV3IHZlYzMoWzEsIDEsIDFdKTtcclxudmVjMy51cCA9IG5ldyB2ZWMzKFswLCAxLCAwXSk7XHJcbnZlYzMucmlnaHQgPSBuZXcgdmVjMyhbMSwgMCwgMF0pO1xyXG52ZWMzLmZvcndhcmQgPSBuZXcgdmVjMyhbMCwgMCwgMV0pO1xyXG4iLCIvLyBUaGUgY29kZSB0aGF0IGRlYWxzIHdpdGggM2QgYXVkaW9cclxuaW1wb3J0IHsgRXZlbnRCdXMgfSBmcm9tICcuLi8uLi9ldmVudC1idXMnO1xyXG5pbXBvcnQgdmVjMyBmcm9tICcuLi8uLi9tYXRoL3ZlYzMnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZXNvbmF0b3JTY2VuZSBleHRlbmRzIEV2ZW50QnVzIHtcclxuICAgIGNvbnN0cnVjdG9yKGNvbnRleHQpIHtcclxuICAgICAgICBzdXBlcigpO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IHRoaXMuY29udGV4dC5nZXRDb250ZXh0KCkuY3JlYXRlR2FpbigpO1xyXG4gICAgICAgIHRoaXMubGlzdGVuZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmxpc3RlbmVyO1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICAvLyB0aGlzLnNjZW5lLm91dHB1dC5jb25uZWN0KHRoaXMuY29udGV4dC5nZXRPdXRwdXREZXN0aW5hdGlvbigpKTtcclxuICAgIH1cclxuICAgIGNyZWF0ZVNvdXJjZSgpIHtcclxuICAgICAgICBjb25zdCBub2RlID0gdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jcmVhdGVQYW5uZXIoKTtcclxuICAgICAgICBub2RlLnBhbm5pbmdNb2RlbCA9ICdIUlRGJztcclxuICAgICAgICBub2RlLmRpc3RhbmNlTW9kZWwgPSAnbGluZWFyJztcclxuICAgICAgICBub2RlLm1heERpc3RhbmNlID0gMjA7XHJcbiAgICAgICAgbm9kZS5yZWZEaXN0YW5jZSA9IDI7XHJcbiAgICAgICAgbm9kZS5jb25uZWN0KHRoaXMuc2NlbmUpO1xyXG4gICAgICAgIHJldHVybiBub2RlO1xyXG4gICAgfVxyXG4gICAgZ2V0T3V0cHV0KCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnNjZW5lO1xyXG4gICAgfVxyXG4gICAgZ2V0SW5wdXQoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc2NlbmU7XHJcbiAgICB9XHJcbiAgICBzZXRMaXN0ZW5lclBvc2l0aW9uKHgsIHksIHopIHtcclxuICAgICAgICB0aGlzLmxpc3RlbmVyLnNldFBvc2l0aW9uKHgsIHksIHopO1xyXG4gICAgfVxyXG4gICAgc2V0TGlzdGVuZXJPcmllbnRhdGlvbihmb3J3YXJkLCByYXd1cCkge1xyXG4gICAgICAgIGxldCBmd2QgPSBuZXcgdmVjMyhbZm9yd2FyZC54LCBmb3J3YXJkLnksIGZvcndhcmQuel0pO1xyXG4gICAgICAgIGxldCB1cCA9IGZ3ZC5jb3B5KCk7XHJcbiAgICAgICAgdmVjMy5jcm9zcyh1cCwgbmV3IHZlYzMoW3Jhd3VwLngsIHJhd3VwLnksIHJhd3VwLnpdKSwgdXApO1xyXG4gICAgICAgIHZlYzMuY3Jvc3ModXAsIGZ3ZCwgdXApO1xyXG4gICAgICAgIGZ3ZC5ub3JtYWxpemUoKTtcclxuICAgICAgICB1cC5ub3JtYWxpemUoKTtcclxuICAgICAgICB0aGlzLmxpc3RlbmVyLnNldE9yaWVudGF0aW9uKGZ3ZC54LCBmd2QueSwgZndkLnosIHVwLngsIHVwLnksIHVwLnopO1xyXG4gICAgfVxyXG59XHJcbiIsIi8vIEEgY2hhaW4gb2YgZWZmZWN0cyB0aGF0IGNvbm5lY3QgdG8gdGhlIGVmZmVjdCBidXNcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRWZmZWN0Q2hhaW4ge1xyXG4gICAgY29uc3RydWN0b3IoY29udGV4dCwgZ3JhcGgsIGlucHV0LCBvdXRwdXQpIHtcclxuICAgICAgICB0aGlzLmVmZmVjdHMgPSBbXTtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xyXG4gICAgICAgIHRoaXMuZ3JhcGggPSBncmFwaDtcclxuICAgICAgICB0aGlzLmlucHV0Tm9kZSA9IGlucHV0O1xyXG4gICAgICAgIHRoaXMub3V0cHV0Tm9kZSA9IG91dHB1dDtcclxuICAgICAgICB0aGlzLnVwZGF0ZUNvbm5lY3Rpb25zKCk7XHJcbiAgICB9XHJcbiAgICBhcHBseUVmZmVjdChlZmZlY3QpIHtcclxuICAgICAgICB0aGlzLmVmZmVjdHMucHVzaChlZmZlY3QpO1xyXG4gICAgICAgIHRoaXMudXBkYXRlQ29ubmVjdGlvbnMoKTtcclxuICAgIH1cclxuICAgIHJlbW92ZUVmZmVjdChlZmZlY3QpIHtcclxuICAgICAgICB0aGlzLmVmZmVjdHMuZm9yRWFjaCgoY3VyckVmZmVjdCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAoZWZmZWN0ID09PSBjdXJyRWZmZWN0KSB7XHJcbiAgICAgICAgICAgICAgICBjdXJyRWZmZWN0LmRpc2Nvbm5lY3QoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuZWZmZWN0cyA9IHRoaXMuZWZmZWN0cy5maWx0ZXIoKGN1cnJFZmZlY3QpID0+IGVmZmVjdCAhPT0gY3VyckVmZmVjdCk7XHJcbiAgICAgICAgdGhpcy51cGRhdGVDb25uZWN0aW9ucygpO1xyXG4gICAgfVxyXG4gICAgdXBkYXRlQ29ubmVjdGlvbnMoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZWZmZWN0cy5sZW5ndGggPT0gMCkge1xyXG4gICAgICAgICAgICB0aGlzLmlucHV0Tm9kZS5jb25uZWN0KHRoaXMub3V0cHV0Tm9kZSk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcbiAgICAgICAgbGV0IGN1cnJlbnQgPSBudWxsO1xyXG4gICAgICAgIGxldCBwcmV2aW91cyA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzLmZvckVhY2goKGVmZmVjdCkgPT4ge1xyXG4gICAgICAgICAgICBjdXJyZW50ID0gZWZmZWN0O1xyXG4gICAgICAgICAgICBpZiAocHJldmlvdXMpIHtcclxuICAgICAgICAgICAgICAgIGN1cnJlbnQuY29ubmVjdElucHV0KHByZXZpb3VzLmdldE91dHB1dCgpKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGN1cnJlbnQuY29ubmVjdElucHV0KHRoaXMuaW5wdXROb2RlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBwcmV2aW91cyA9IGN1cnJlbnQ7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKGN1cnJlbnQpIHtcclxuICAgICAgICAgICAgY3VycmVudC5jb25uZWN0T3V0cHV0KHRoaXMub3V0cHV0Tm9kZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiIsIi8vIHRoaXMgaXMgdGhlIG1peGVyIHRoYXQgdGFrZXMgYWxsIHRoZSBkaWZmZXJlbnQgb3V0cHV0cyBhbmQgbWl4ZXMgdGhlbSBpbnRvIHRoZSAyIGJ1c3NlczpcclxuLy8gV29ybGRCdXM6IFRoZSBkaXJlY3Rpb25hbCBhdWRpb1xyXG4vLyBTZWNvbmRhcnlCdXM6IEFsbCB0aGUgVUkgYW5kIHRoaW5ncyB0aGF0IGFyZSBub24gZGlyZWN0aW9uYWxcclxuaW1wb3J0IEVmZmVjdENoYWluIGZyb20gJy4vZWZmZWN0LWNoYWluJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQXVkaW9HcmFwaCB7XHJcbiAgICBjb25zdHJ1Y3RvcihzY2VuZSwgY29udGV4dCwgc3dhcENoYW5uZWxzID0gZmFsc2UpIHtcclxuICAgICAgICB0aGlzLnNjZW5lID0gc2NlbmU7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcclxuICAgICAgICB0aGlzLnN3YXBDaGFubmVscyA9IHN3YXBDaGFubmVscztcclxuICAgICAgICB0aGlzLmluaXQoKTtcclxuICAgIH1cclxuICAgIGluaXQoKSB7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzQnVzID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICB0aGlzLndvcmxkQnVzID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICB0aGlzLnNlY29uZGFyeUJ1cyA9IHRoaXMuY29udGV4dC5jcmVhdGVHYWluKCk7XHJcbiAgICAgICAgdGhpcy5tYXN0ZXIgPSB0aGlzLmNvbnRleHQuY3JlYXRlR2FpbigpO1xyXG4gICAgICAgIHRoaXMuc2NlbmUuZ2V0T3V0cHV0KCkuY29ubmVjdCh0aGlzLndvcmxkQnVzKTtcclxuICAgICAgICAvLyB0aGlzLndvcmxkQnVzLmNvbm5lY3QodGhpcy5tYXN0ZXIpO1xyXG4gICAgICAgIHRoaXMud29ybGRCdXMuY29ubmVjdCh0aGlzLmVmZmVjdHNCdXMpO1xyXG4gICAgICAgIHRoaXMuZWZmZWN0cyA9IG5ldyBFZmZlY3RDaGFpbih0aGlzLmNvbnRleHQsIHRoaXMsIHRoaXMuZWZmZWN0c0J1cywgdGhpcy5tYXN0ZXIpO1xyXG4gICAgICAgIHRoaXMuc2Vjb25kYXJ5QnVzLmNvbm5lY3QodGhpcy5tYXN0ZXIpO1xyXG4gICAgICAgIGlmICh0aGlzLnN3YXBDaGFubmVscykge1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxTcGxpdHRlciA9IHRoaXMuY29udGV4dC5nZXRDb250ZXh0KCkuY3JlYXRlQ2hhbm5lbFNwbGl0dGVyKDIpO1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxNZXJnZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUNoYW5uZWxNZXJnZXIoMik7XHJcbiAgICAgICAgICAgIHRoaXMubWFzdGVyLmNvbm5lY3QodGhpcy5jaGFubmVsU3BsaXR0ZXIpO1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5uZWxTcGxpdHRlci5jb25uZWN0KHRoaXMuY2hhbm5lbE1lcmdlciwgMCwgMSk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhbm5lbFNwbGl0dGVyLmNvbm5lY3QodGhpcy5jaGFubmVsTWVyZ2VyLCAxLCAwKTtcclxuICAgICAgICAgICAgdGhpcy5jaGFubmVsTWVyZ2VyLmNvbm5lY3QodGhpcy5jb250ZXh0LmdldE91dHB1dERlc3RpbmF0aW9uKCkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5tYXN0ZXIuY29ubmVjdCh0aGlzLmNvbnRleHQuZ2V0T3V0cHV0RGVzdGluYXRpb24oKSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgY29ubmVjdFRvTWFzdGVyKGlucHV0KSB7XHJcbiAgICAgICAgaW5wdXQuY29ubmVjdCh0aGlzLm1hc3Rlcik7XHJcbiAgICB9XHJcbiAgICBjb25uZWN0VG9VSShpbnB1dCkge1xyXG4gICAgICAgIGlucHV0LmNvbm5lY3QodGhpcy5zZWNvbmRhcnlCdXMpO1xyXG4gICAgfVxyXG4gICAgYXBwbHlFZmZlY3QoZWZmZWN0KSB7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzLmFwcGx5RWZmZWN0KGVmZmVjdCk7XHJcbiAgICB9XHJcbiAgICByZW1vdmVFZmZlY3QoZWZmZWN0KSB7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RzLnJlbW92ZUVmZmVjdChlZmZlY3QpO1xyXG4gICAgfVxyXG59XHJcbiIsImV4cG9ydCB2YXIgU291cmNlVHlwZTtcclxuKGZ1bmN0aW9uIChTb3VyY2VUeXBlKSB7XHJcbiAgICBTb3VyY2VUeXBlW1NvdXJjZVR5cGVbXCJXb3JsZFNvdXJjZVwiXSA9IDBdID0gXCJXb3JsZFNvdXJjZVwiO1xyXG4gICAgU291cmNlVHlwZVtTb3VyY2VUeXBlW1wiVUlTb3VyY2VcIl0gPSAxXSA9IFwiVUlTb3VyY2VcIjtcclxuICAgIFNvdXJjZVR5cGVbU291cmNlVHlwZVtcIk1hc3RlclNvdXJjZVwiXSA9IDJdID0gXCJNYXN0ZXJTb3VyY2VcIjtcclxufSkoU291cmNlVHlwZSB8fCAoU291cmNlVHlwZSA9IHt9KSk7XHJcbiIsIi8vIGFuIGF1ZGlvIHNvdXJjZVxyXG4vLyBUaGlzIGlzIHRoZSBhY3R1YWwgc291bmRcclxuaW1wb3J0IHsgU291cmNlVHlwZSB9IGZyb20gJy4vc291cmNlLXR5cGUnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBdWRpb1NvdXJjZSB7XHJcbiAgICBjb25zdHJ1Y3RvcihncmFwaCwgc2NlbmUsIGNvbnRleHQsIGJ1ZmZlciA9IG51bGwsIHR5cGUgPSBTb3VyY2VUeXBlLldvcmxkU291cmNlKSB7XHJcbiAgICAgICAgdGhpcy5wb3NpdGlvbiA9IHtcclxuICAgICAgICAgICAgeDogMCxcclxuICAgICAgICAgICAgeTogMCxcclxuICAgICAgICAgICAgejogMFxyXG4gICAgICAgIH07XHJcbiAgICAgICAgdGhpcy5idWZmZXIgPSBidWZmZXI7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcclxuICAgICAgICB0aGlzLnNjZW5lID0gc2NlbmU7XHJcbiAgICAgICAgdGhpcy5ncmFwaCA9IGdyYXBoO1xyXG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XHJcbiAgICAgICAgdGhpcy5wbGF5YmFja1JhdGUgPSAxO1xyXG4gICAgICAgIHRoaXMudm9sdW1lID0gMTtcclxuICAgICAgICB0aGlzLmluaXQoKTtcclxuICAgIH1cclxuICAgIGluaXQoKSB7XHJcbiAgICAgICAgdGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICAvLyBiaW5kIG1ldGhvZHMgc28gd2UgY2FuIGFkZCBhbmQgcmVtb3Z2ZSB0aGVtIGZyb20gZXZlbnQgbGlzdGVuZXJzXHJcbiAgICAgICAgdGhpcy5zdG9wID0gdGhpcy5zdG9wLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcbiAgICBnZXRCdWZmZXIoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVmZmVyO1xyXG4gICAgfVxyXG4gICAgc2V0QnVmZmVyKGRhdGEpIHtcclxuICAgICAgICB0aGlzLmJ1ZmZlciA9IGRhdGE7XHJcbiAgICAgICAgaWYgKHRoaXMucGxheU9uTG9hZCkge1xyXG4gICAgICAgICAgICB0aGlzLnBsYXkoKTtcclxuICAgICAgICAgICAgdGhpcy5wbGF5T25Mb2FkID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgcGxheSh3aGVuID0gMCwgb2Zmc2V0ID0gMCwgZHVyYXRpb24gPSB0aGlzLmJ1ZmZlciA/IHRoaXMuYnVmZmVyLmR1cmF0aW9uIDogMCkge1xyXG4gICAgICAgIGlmICh0aGlzLnBsYXlpbmcgJiYgdGhpcy5ub2RlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIXRoaXMuYnVmZmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMucGxheU9uTG9hZCA9IHRydWU7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCF0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5ub2RlID0gdGhpcy5jb250ZXh0LmNyZWF0ZUJ1ZmZlclNvdXJjZSgpO1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUuYnVmZmVyID0gdGhpcy5idWZmZXI7XHJcbiAgICAgICAgICAgIHRoaXMuY3JlYXRlQ29ubmVjdGlvbnMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHRoaXMubm9kZSkge1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUucGxheWJhY2tSYXRlLnZhbHVlID0gdGhpcy5wbGF5YmFja1JhdGU7XHJcbiAgICAgICAgICAgIHRoaXMubm9kZS5zdGFydCh3aGVuLCBvZmZzZXQsIGR1cmF0aW9uKTtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLmxvb3AgPSB0aGlzLmxvb3Bpbmc7XHJcbiAgICAgICAgICAgIHRoaXMucGxheWluZyA9IHRydWU7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLnNjZW5lTm9kZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUuc2V0UG9zaXRpb24odGhpcy5wb3NpdGlvbi54LCB0aGlzLnBvc2l0aW9uLnksIHRoaXMucG9zaXRpb24ueik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgdGhpcy5ub2RlLmFkZEV2ZW50TGlzdGVuZXIoJ2VuZGVkJywgdGhpcy5zdG9wKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBzZXRQb3NpdGlvbih4LCB5LCB6KSB7XHJcbiAgICAgICAgdGhpcy5wb3NpdGlvbiA9IHtcclxuICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgeSxcclxuICAgICAgICAgICAgelxyXG4gICAgICAgIH07XHJcbiAgICAgICAgaWYgKHRoaXMuc2NlbmVOb2RlKVxyXG4gICAgICAgICAgICB0aGlzLnNjZW5lTm9kZS5zZXRQb3NpdGlvbih4LCB5LCB6KTtcclxuICAgIH1cclxuICAgIHNldFBsYXliYWNrUmF0ZShyYXRlKSB7XHJcbiAgICAgICAgdGhpcy5wbGF5YmFja1JhdGUgPSByYXRlO1xyXG4gICAgICAgIGlmICh0aGlzLm5vZGUpXHJcbiAgICAgICAgICAgIHRoaXMubm9kZS5wbGF5YmFja1JhdGUudmFsdWUgPSByYXRlO1xyXG4gICAgfVxyXG4gICAgZ2V0UGxheWJhY2tSYXRlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnBsYXliYWNrUmF0ZTtcclxuICAgIH1cclxuICAgIHNldFZvbHVtZSh2b2x1bWUpIHtcclxuICAgICAgICB0aGlzLnZvbHVtZSA9IHZvbHVtZTtcclxuICAgICAgICBpZiAodGhpcy5nYWluKVxyXG4gICAgICAgICAgICB0aGlzLmdhaW4uZ2Fpbi52YWx1ZSA9IHZvbHVtZTtcclxuICAgIH1cclxuICAgIGdldFZvbHVtZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy52b2x1bWU7XHJcbiAgICB9XHJcbiAgICBjcmVhdGVDb25uZWN0aW9ucygpIHtcclxuICAgICAgICBzd2l0Y2ggKHRoaXMudHlwZSkge1xyXG4gICAgICAgICAgICBjYXNlIFNvdXJjZVR5cGUuV29ybGRTb3VyY2U6XHJcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuc2NlbmVOb2RlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUgPSB0aGlzLnNjZW5lLmNyZWF0ZVNvdXJjZSgpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgdGhpcy5ub2RlLmNvbm5lY3QodGhpcy5nYWluKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuZ2Fpbi5jb25uZWN0KHRoaXMuc2NlbmVOb2RlKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlIFNvdXJjZVR5cGUuVUlTb3VyY2U6XHJcbiAgICAgICAgICAgICAgICB0aGlzLm5vZGUuY29ubmVjdCh0aGlzLmdhaW4pO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5ncmFwaC5jb25uZWN0VG9VSSh0aGlzLmdhaW4pO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICB0aGlzLm5vZGUuY29ubmVjdCh0aGlzLmdhaW4pO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5ncmFwaC5jb25uZWN0VG9NYXN0ZXIodGhpcy5nYWluKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHN0b3AoKSB7XHJcbiAgICAgICAgdGhpcy5wbGF5aW5nID0gZmFsc2U7XHJcbiAgICAgICAgaWYgKHRoaXMubm9kZSkge1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUucmVtb3ZlRXZlbnRMaXN0ZW5lcignZW5kZWQnLCB0aGlzLnN0b3ApO1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUuc3RvcCgpO1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUuZGlzY29ubmVjdCgpO1xyXG4gICAgICAgICAgICB0aGlzLm5vZGUgPSBudWxsO1xyXG4gICAgICAgICAgICB0aGlzLnBsYXlpbmcgPSBmYWxzZTtcclxuICAgICAgICAgICAgaWYgKHRoaXMuc2NlbmVOb2RlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnNjZW5lTm9kZS5kaXNjb25uZWN0KCk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnNjZW5lTm9kZSA9IG51bGw7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBkZXN0cm95KCkge1xyXG4gICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgIC8vIHNldCBhbGwgcmVmcyB0byBudWxsIHRvIGVuY291cmFnZSBnY1xyXG4gICAgICAgIHRoaXMubm9kZSA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5zY2VuZU5vZGUgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuYnVmZmVyID0gbnVsbDtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuZ3JhcGggPSBudWxsO1xyXG4gICAgICAgIHRoaXMuc2NlbmUgPSBudWxsO1xyXG4gICAgfVxyXG4gICAgbG9vcCh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMubG9vcGluZyA9IHZhbHVlO1xyXG4gICAgICAgIGlmICh0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5ub2RlLmxvb3AgPSB2YWx1ZTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBmYWRlT3V0KHRpbWUpIHtcclxuICAgICAgICB0aGlzLmdhaW4uZ2Fpbi5zZXRWYWx1ZUF0VGltZSh0aGlzLmdldFZvbHVtZSgpLCB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmN1cnJlbnRUaW1lKTtcclxuICAgICAgICBpZiAoIXRoaXMubm9kZSkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuZ2Fpbi5nYWluLmV4cG9uZW50aWFsUmFtcFRvVmFsdWVBdFRpbWUoMC4wMDAxLCB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmN1cnJlbnRUaW1lICsgdGltZSk7XHJcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnN0b3AoKSwgdGltZSAqIDEwMDApO1xyXG4gICAgfVxyXG4gICAgZmFkZUluKHRpbWUpIHtcclxuICAgICAgICB0aGlzLmdhaW4uZ2Fpbi5zZXRWYWx1ZUF0VGltZSgwLjAwMDEsIHRoaXMuY29udGV4dC5nZXRDb250ZXh0KCkuY3VycmVudFRpbWUpO1xyXG4gICAgICAgIGlmICghdGhpcy5ub2RlKSB7XHJcbiAgICAgICAgICAgIHRoaXMucGxheSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmdhaW4uZ2Fpbi5leHBvbmVudGlhbFJhbXBUb1ZhbHVlQXRUaW1lKHRoaXMudm9sdW1lLCB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmN1cnJlbnRUaW1lICsgdGltZSk7XHJcbiAgICB9XHJcbn1cclxuIiwiLy8gQW4gaXRlbSBpbiB0aGUgZGF0YSBwb29sXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIERhdGFQb29sSXRlbSB7XHJcbiAgICBjb25zdHJ1Y3RvcihuYW1lLCBkYXRhID0gbnVsbCwgZGVjb2RlZERhdGEgPSBudWxsKSB7XHJcbiAgICAgICAgdGhpcy5uYW1lID0gbmFtZTtcclxuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xyXG4gICAgICAgIHRoaXMuZGVjb2RlZERhdGEgPSBkZWNvZGVkRGF0YTtcclxuICAgIH1cclxuICAgIGdldERhdGEoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YTtcclxuICAgIH1cclxuICAgIHNldERhdGEoZGF0YSkge1xyXG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XHJcbiAgICB9XHJcbiAgICBnZXREZWNvZGVkRGF0YSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5kZWNvZGVkRGF0YTtcclxuICAgIH1cclxuICAgIHNldERlY29kZWREYXRhKGRhdGEpIHtcclxuICAgICAgICB0aGlzLmRlY29kZWREYXRhID0gdGhpcy5kZWNvZGVkRGF0YTtcclxuICAgIH1cclxuICAgIGdldE5hbWUoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMubmFtZTtcclxuICAgIH1cclxuICAgIHNldE5hbWUobmFtZSkge1xyXG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XHJcbiAgICB9XHJcbn1cclxuIiwidmFyIF9fYXdhaXRlciA9ICh0aGlzICYmIHRoaXMuX19hd2FpdGVyKSB8fCBmdW5jdGlvbiAodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkgeyByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHZhbHVlKTsgfSk7IH1cclxuICAgIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG4gICAgICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkgeyByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTsgfVxyXG4gICAgICAgIHN0ZXAoKGdlbmVyYXRvciA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSkubmV4dCgpKTtcclxuICAgIH0pO1xyXG59O1xyXG5leHBvcnQgY2xhc3MgSFRUUExvYWRlciB7XHJcbiAgICBnZXQocGF0aCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHlpZWxkIGZldGNoKHBhdGgpO1xyXG4gICAgICAgICAgICBjb25zdCBidWZmZXIgPSB5aWVsZCByZXN1bHQuYXJyYXlCdWZmZXIoKTtcclxuICAgICAgICAgICAgcmV0dXJuIGJ1ZmZlcjtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxufVxyXG4iLCIvLyBhIGRhdGEgcG9vbCBob2xkcyBmcmVxdWVudGx5IHBsYXllZCBzb3VuZHMgaW4gbWVtb3J5IHRvZ2V0aGVyIHdpdGggZGVjb2RlZCBhdWRpbyBkYXRhIHRvIG5vIGxvbmdlciBoYXZlIHRvIGRlY29kZSB0aGVtIGZyb20gdGhlIGNhY2hlIHdoZW4gbG9hZGVkIGFnYWluXHJcbnZhciBfX2F3YWl0ZXIgPSAodGhpcyAmJiB0aGlzLl9fYXdhaXRlcikgfHwgZnVuY3Rpb24gKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHsgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZSh2YWx1ZSk7IH0pOyB9XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufTtcclxuaW1wb3J0IHsgRXZlbnRCdXMgfSBmcm9tICcuLi9ldmVudC1idXMnO1xyXG5pbXBvcnQgRGF0YVBvb2xJdGVtIGZyb20gJy4vZGF0YS1wb29sLWl0ZW0nO1xyXG5pbXBvcnQgeyBIVFRQTG9hZGVyIH0gZnJvbSAnLi9sb2FkZXJzL2h0dHAtbG9hZGVyJztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRGF0YVBvb2wgZXh0ZW5kcyBFdmVudEJ1cyB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBsb2FkZXIgPSBuZXcgSFRUUExvYWRlcigpLCBtYXhEYXRhID0gNTEyKSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLmxvYWRlciA9IGxvYWRlcjtcclxuICAgICAgICB0aGlzLmRhdGEgPSB7fTtcclxuICAgICAgICB0aGlzLm1heERhdGEgPSBtYXhEYXRhO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICB9XHJcbiAgICBnZXQocGF0aCkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmRhdGFbcGF0aF0pIHtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmRhdGFbcGF0aF0uZ2V0RGVjb2RlZERhdGEoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGJ1ZmZlciA9IHlpZWxkIHRoaXMubG9hZGVyLmdldChwYXRoKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGRlY29kZWQgPSB5aWVsZCB0aGlzLmNvbnRleHQuZGVjb2RlQXVkaW9EYXRhKGJ1ZmZlcik7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtID0gbmV3IERhdGFQb29sSXRlbShwYXRoLCBidWZmZXIsIGRlY29kZWQpO1xyXG4gICAgICAgICAgICAgICAgY29uc3QgbGVuZ3RoID0gT2JqZWN0LmtleXModGhpcy5kYXRhKS5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgICBpZiAobGVuZ3RoIDwgdGhpcy5tYXhEYXRhKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhW3BhdGhdID0gaXRlbTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IGZpZ3VyZSBvdXQgYSBtb3JlIGNsZXZlciBzb2x1dGlvbiB0aGFuIGp1c3QgcmVtb3ZpbmcgdGhlIGZpcnN0IGxvYWRlZCBkYXRhLiBMaWtlIHRyYWNraW5nIGhvdyBtdWNoIGNlcnRhaW4gZGF0YSBpcyBuZWVkZWQgYW5kIHByaW9yaXRpemUgdGhlbS5cclxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zdCBwYXRoczogc3RyaW5nW10gPSBPYmplY3Qua2V5cyh0aGlzLmRhdGEpO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIGRlbGV0ZSB0aGlzLmRhdGFbcGF0aHNbMF1dO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0YVtwYXRoXSA9IGl0ZW07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gaXRlbS5nZXREZWNvZGVkRGF0YSgpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBjbGVhcigpIHtcclxuICAgICAgICB0aGlzLmRhdGEgPSB7fTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgQmFzZUVmZmVjdCBmcm9tICcuL2Jhc2UtZWZmZWN0JztcclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29udm9sdmVyIGV4dGVuZHMgQmFzZUVmZmVjdCB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBncmFwaCwgcGFyYW1zKSB7XHJcbiAgICAgICAgc3VwZXIoY29udGV4dCwgZ3JhcGgsIHBhcmFtcyk7XHJcbiAgICAgICAgY29uc29sZS5sb2coYENyZWF0aW5nIGNvbnZvbHZlcmApO1xyXG4gICAgICAgIHRoaXMuZWZmZWN0Tm9kZSA9IHRoaXMuY29udGV4dC5nZXRDb250ZXh0KCkuY3JlYXRlQ29udm9sdmVyKCk7XHJcbiAgICAgICAgdGhpcy5lZmZlY3ROb2RlLmJ1ZmZlciA9IHRoaXMuZWZmZWN0UGFyYW1zLmJ1ZmZlcjtcclxuICAgIH1cclxuICAgIGNvbm5lY3RJbnB1dChub2RlKSB7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUNoYW5uZWxTcGxpdHRlcigyKTtcclxuICAgICAgICB0aGlzLmNoYW5uZWxNZXJnZXIgPSB0aGlzLmNvbnRleHQuZ2V0Q29udGV4dCgpLmNyZWF0ZUNoYW5uZWxNZXJnZXIoMik7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIuY29ubmVjdCh0aGlzLmNoYW5uZWxNZXJnZXIsIDAsIDApO1xyXG4gICAgICAgIHRoaXMuY2hhbm5lbFNwbGl0dGVyLmNvbm5lY3QodGhpcy5jaGFubmVsTWVyZ2VyLCAxLCAwKTtcclxuICAgICAgICB0aGlzLmNoYW5uZWxTcGxpdHRlci5jb25uZWN0KHRoaXMuY2hhbm5lbE1lcmdlciwgMCwgMSk7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsU3BsaXR0ZXIuY29ubmVjdCh0aGlzLmNoYW5uZWxNZXJnZXIsIDEsIDEpO1xyXG4gICAgICAgIG5vZGUuY29ubmVjdCh0aGlzLmNoYW5uZWxTcGxpdHRlcik7XHJcbiAgICAgICAgdGhpcy5jaGFubmVsTWVyZ2VyLmNvbm5lY3QodGhpcy5lZmZlY3ROb2RlKTtcclxuICAgICAgICB0aGlzLmlucHV0Tm9kZSA9IG5vZGU7XHJcbiAgICB9XHJcbn1cclxuIiwiZXhwb3J0IGRlZmF1bHQgY2xhc3MgQmFzZUVmZmVjdCB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBncmFwaCwgcGFyYW1zKSB7XHJcbiAgICAgICAgdGhpcy5ncmFwaCA9IGdyYXBoO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5lZmZlY3RQYXJhbXMgPSBwYXJhbXM7XHJcbiAgICB9XHJcbiAgICBjb25uZWN0T3V0cHV0KG5vZGUpIHtcclxuICAgICAgICB0aGlzLmVmZmVjdE5vZGUuY29ubmVjdChub2RlKTtcclxuICAgIH1cclxuICAgIGNvbm5lY3RJbnB1dChub2RlKSB7XHJcbiAgICAgICAgdGhpcy5pbnB1dE5vZGUgPSBub2RlO1xyXG4gICAgICAgIGlmICh0aGlzLmVmZmVjdE5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5pbnB1dE5vZGUuY29ubmVjdCh0aGlzLmVmZmVjdE5vZGUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGdldE91dHB1dCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5lZmZlY3ROb2RlO1xyXG4gICAgfVxyXG4gICAgZGlzY29ubmVjdCgpIHtcclxuICAgICAgICB0aGlzLmlucHV0Tm9kZS5kaXNjb25uZWN0KCk7XHJcbiAgICAgICAgdGhpcy5lZmZlY3ROb2RlLmRpc2Nvbm5lY3QoKTtcclxuICAgIH1cclxufVxyXG4iLCJpbXBvcnQgeyBTb3VyY2VUeXBlIH0gZnJvbSAnLi9zb3VyY2UtdHlwZSc7XHJcbmV4cG9ydCBjbGFzcyBTdHJlYW1pbmdTb3VyY2Uge1xyXG4gICAgY29uc3RydWN0b3IoZ3JhcGgsIHNjZW5lLCBjb250ZXh0LCBlbGVtZW50LCB0eXBlID0gU291cmNlVHlwZS5NYXN0ZXJTb3VyY2UpIHtcclxuICAgICAgICB0aGlzLmdyYXBoID0gZ3JhcGg7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IHNjZW5lO1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcclxuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xyXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSB7XHJcbiAgICAgICAgICAgIHg6IDAsXHJcbiAgICAgICAgICAgIHk6IDAsXHJcbiAgICAgICAgICAgIHo6IDBcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMuaW5pdCgpO1xyXG4gICAgfVxyXG4gICAgaW5pdCgpIHtcclxuICAgICAgICB0aGlzLm5vZGUgPSB0aGlzLmNvbnRleHQuY3JlYXRlTWVkaWFFbGVtZW50U291cmNlKHRoaXMuZWxlbWVudCk7XHJcbiAgICAgICAgdGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcclxuICAgICAgICB0aGlzLmNyZWF0ZUNvbm5lY3Rpb25zKCk7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NhbnBsYXknLCAoZXZlbnQpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5jYW5QbGF5ID0gdHJ1ZTtcclxuICAgICAgICAgICAgaWYgKHRoaXMucGxheU9uQXZhaWxhYmxlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnBsYXkoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgcGxheSh3aGVuID0gMCwgb2Zmc2V0ID0gMCwgZHVyYXRpb24gPSAwKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuY2FuUGxheSkge1xyXG4gICAgICAgICAgICB0aGlzLmVsZW1lbnQucGxheSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnBsYXlPbkF2YWlsYWJsZSA9IHRydWU7XHJcbiAgICB9XHJcbiAgICBzdG9wKCkge1xyXG4gICAgICAgIHRoaXMuZWxlbWVudC5wYXVzZSgpO1xyXG4gICAgfVxyXG4gICAgZ2V0Vm9sdW1lKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmVsZW1lbnQudm9sdW1lO1xyXG4gICAgfVxyXG4gICAgc2V0Vm9sdW1lKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LnZvbHVtZSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgZ2V0UGxheWJhY2tSYXRlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmVsZW1lbnQucGxheWJhY2tSYXRlO1xyXG4gICAgfVxyXG4gICAgc2V0UGxheWJhY2tSYXRlKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5lbGVtZW50LnBsYXliYWNrUmF0ZSA9IHZhbHVlO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlQ29ubmVjdGlvbnMoKSB7XHJcbiAgICAgICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcclxuICAgICAgICAgICAgY2FzZSBTb3VyY2VUeXBlLldvcmxkU291cmNlOlxyXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLnNjZW5lTm9kZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2NlbmVOb2RlID0gdGhpcy5zY2VuZS5jcmVhdGVTb3VyY2UoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHRoaXMubm9kZS5jb25uZWN0KHRoaXMuZ2Fpbik7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmdhaW4uY29ubmVjdCh0aGlzLnNjZW5lTm9kZSk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgIHRoaXMubm9kZS5jb25uZWN0KHRoaXMuZ2Fpbik7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmdyYXBoLmNvbm5lY3RUb01hc3Rlcih0aGlzLmdhaW4pO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgc2V0UG9zaXRpb24oeCwgeSwgeikge1xyXG4gICAgICAgIHRoaXMucG9zaXRpb24gPSB7XHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHksXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICB9O1xyXG4gICAgICAgIGlmICh0aGlzLnNjZW5lTm9kZSlcclxuICAgICAgICAgICAgdGhpcy5zY2VuZU5vZGUuc2V0UG9zaXRpb24oeCwgeSwgeik7XHJcbiAgICB9XHJcbiAgICBkZXN0cm95KCkge1xyXG4gICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgIHRoaXMuZWxlbWVudCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5ncmFwaCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLm5vZGUgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuc2NlbmVOb2RlID0gbnVsbDtcclxuICAgICAgICB0aGlzLnNjZW5lID0gbnVsbDtcclxuICAgIH1cclxuICAgIGxvb3AodmFsdWUpIHtcclxuICAgICAgICB0aGlzLmVsZW1lbnQubG9vcCA9IHRydWU7XHJcbiAgICB9XHJcbiAgICBmYWRlSW4odGltZSkge1xyXG4gICAgICAgIHRoaXMuZ2Fpbi5nYWluLnNldFZhbHVlQXRUaW1lKDAuMDAwMSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSk7XHJcbiAgICAgICAgaWYgKCF0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgdGhpcy5wbGF5KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuZ2Fpbi5nYWluLmV4cG9uZW50aWFsUmFtcFRvVmFsdWVBdFRpbWUodGhpcy5nZXRWb2x1bWUoKSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSArIHRpbWUpO1xyXG4gICAgfVxyXG4gICAgZmFkZU91dCh0aW1lKSB7XHJcbiAgICAgICAgdGhpcy5nYWluLmdhaW4uc2V0VmFsdWVBdFRpbWUodGhpcy5nZXRWb2x1bWUoKSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSk7XHJcbiAgICAgICAgaWYgKCF0aGlzLm5vZGUpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmdhaW4uZ2Fpbi5leHBvbmVudGlhbFJhbXBUb1ZhbHVlQXRUaW1lKDAuMDAwMSwgdGhpcy5jb250ZXh0LmdldENvbnRleHQoKS5jdXJyZW50VGltZSArIHRpbWUpO1xyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zdG9wKCksIHRpbWUgKiAxMDAwKTtcclxuICAgIH1cclxufVxyXG4iLCIvLyB0aGUgbWFpbiBtb2R1bGUgZm9yIFJlc29uYXRvclxyXG4vLyBBUEksIGV0Yy5cclxudmFyIF9fYXdhaXRlciA9ICh0aGlzICYmIHRoaXMuX19hd2FpdGVyKSB8fCBmdW5jdGlvbiAodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICBmdW5jdGlvbiBhZG9wdCh2YWx1ZSkgeyByZXR1cm4gdmFsdWUgaW5zdGFuY2VvZiBQID8gdmFsdWUgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHZhbHVlKTsgfSk7IH1cclxuICAgIHJldHVybiBuZXcgKFAgfHwgKFAgPSBQcm9taXNlKSkoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xyXG4gICAgICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiByZWplY3RlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvcltcInRocm93XCJdKHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH1cclxuICAgICAgICBmdW5jdGlvbiBzdGVwKHJlc3VsdCkgeyByZXN1bHQuZG9uZSA/IHJlc29sdmUocmVzdWx0LnZhbHVlKSA6IGFkb3B0KHJlc3VsdC52YWx1ZSkudGhlbihmdWxmaWxsZWQsIHJlamVjdGVkKTsgfVxyXG4gICAgICAgIHN0ZXAoKGdlbmVyYXRvciA9IGdlbmVyYXRvci5hcHBseSh0aGlzQXJnLCBfYXJndW1lbnRzIHx8IFtdKSkubmV4dCgpKTtcclxuICAgIH0pO1xyXG59O1xyXG5pbXBvcnQgUmVzb25hdG9yQXVkaW9Db250ZXh0IGZyb20gJy4vYXVkaW8tY29udGV4dCc7XHJcbmltcG9ydCBSZXNvbmF0b3JTY2VuZSBmcm9tICcuL3NjZW5lcy93ZWJhdWRpby1zY2VuZSc7XHJcbmltcG9ydCBBdWRpb0dyYXBoIGZyb20gJy4vYXVkaW8tZ3JhcGgnO1xyXG5pbXBvcnQgQXVkaW9Tb3VyY2UgZnJvbSAnLi9zb3VyY2VzL2F1ZGlvLXNvdXJjZSc7XHJcbmltcG9ydCBEYXRhUG9vbCBmcm9tICcuL2RhdGEtcG9vbCc7XHJcbmltcG9ydCBDb252b2x2ZXIgZnJvbSAnLi9lZmZlY3RzL2NvbnZvbHZlcic7XHJcbmltcG9ydCB7IEhUVFBMb2FkZXIgfSBmcm9tICcuL2xvYWRlcnMvaHR0cC1sb2FkZXInO1xyXG5pbXBvcnQgeyBTb3VyY2VUeXBlIH0gZnJvbSAnLi9zb3VyY2VzL3NvdXJjZS10eXBlJztcclxuaW1wb3J0IHsgU3RyZWFtaW5nU291cmNlIH0gZnJvbSAnLi9zb3VyY2VzL3N0cmVhbWluZy1zb3VyY2UnO1xyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZXNvbmF0b3Ige1xyXG4gICAgY29uc3RydWN0b3IobG9hZGVyID0gbmV3IEhUVFBMb2FkZXIoKSkge1xyXG4gICAgICAgIHRoaXMubG9hZGVyID0gbG9hZGVyO1xyXG4gICAgICAgIHRoaXMuZW52aXJvbm1lbnRJbXB1bHNlID0gbnVsbDtcclxuICAgICAgICB0aGlzLmNvbnRleHQgPSBuZXcgUmVzb25hdG9yQXVkaW9Db250ZXh0KCk7XHJcbiAgICAgICAgdGhpcy5zY2VuZSA9IG5ldyBSZXNvbmF0b3JTY2VuZSh0aGlzLmNvbnRleHQpO1xyXG4gICAgICAgIHRoaXMuZ3JhcGggPSBuZXcgQXVkaW9HcmFwaCh0aGlzLnNjZW5lLCB0aGlzLmNvbnRleHQsIGZhbHNlKTtcclxuICAgICAgICB0aGlzLmRhdGFQb29sID0gbmV3IERhdGFQb29sKHRoaXMuY29udGV4dCwgdGhpcy5sb2FkZXIpO1xyXG4gICAgfVxyXG4gICAgbG9hZChwYXRoLCB0eXBlID0gU291cmNlVHlwZS5Xb3JsZFNvdXJjZSkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGRhdGEgPSB5aWVsZCB0aGlzLmRhdGFQb29sLmdldChwYXRoKTtcclxuICAgICAgICAgICAgY29uc3Qgc291cmNlID0gdGhpcy5jcmVhdGVTb3VyY2UodHlwZSwgZGF0YSk7XHJcbiAgICAgICAgICAgIHJldHVybiBzb3VyY2U7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBsb2FkSW1tZWRpYXRlKHBhdGgsIHR5cGUgPSBTb3VyY2VUeXBlLldvcmxkU291cmNlKSB7XHJcbiAgICAgICAgY29uc3Qgc291cmNlID0gbmV3IEF1ZGlvU291cmNlKHRoaXMuZ3JhcGgsIHRoaXMuc2NlbmUsIHRoaXMuY29udGV4dCwgbnVsbCwgdHlwZSk7XHJcbiAgICAgICAgdGhpcy5kYXRhUG9vbC5nZXQocGF0aCkudGhlbigoZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICBzb3VyY2Uuc2V0QnVmZmVyKGRhdGEpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBzb3VyY2U7XHJcbiAgICB9XHJcbiAgICBzdHJlYW0ocGF0aCwgdHlwZSA9IFNvdXJjZVR5cGUuTWFzdGVyU291cmNlKSB7XHJcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IG5ldyBBdWRpbyhwYXRoKTtcclxuICAgICAgICBlbGVtZW50LmNyb3NzT3JpZ2luID0gJ2Fub255bW91cyc7XHJcbiAgICAgICAgZWxlbWVudC52b2x1bWUgPSAxO1xyXG4gICAgICAgIGNvbnN0IHNvdXJjZSA9IG5ldyBTdHJlYW1pbmdTb3VyY2UodGhpcy5ncmFwaCwgdGhpcy5zY2VuZSwgdGhpcy5jb250ZXh0LCBlbGVtZW50LCB0eXBlKTtcclxuICAgICAgICByZXR1cm4gc291cmNlO1xyXG4gICAgfVxyXG4gICAgY3JlYXRlU291cmNlKHR5cGUsIGRhdGEpIHtcclxuICAgICAgICByZXR1cm4gbmV3IEF1ZGlvU291cmNlKHRoaXMuZ3JhcGgsIHRoaXMuc2NlbmUsIHRoaXMuY29udGV4dCwgZGF0YSk7XHJcbiAgICB9XHJcbiAgICBzZXRFbnZpcm9ubWVudEltcHVsc2UoZmlsZSkge1xyXG4gICAgICAgIHJldHVybiBfX2F3YWl0ZXIodGhpcywgdm9pZCAwLCB2b2lkIDAsIGZ1bmN0aW9uKiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmVudmlyb25tZW50SW1wdWxzZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5ncmFwaC5yZW1vdmVFZmZlY3QodGhpcy5lbnZpcm9ubWVudEltcHVsc2UpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGlmIChmaWxlID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgYnVmZmVyID0geWllbGQgdGhpcy5kYXRhUG9vbC5nZXQoZmlsZSk7XHJcbiAgICAgICAgICAgIHRoaXMuZW52aXJvbm1lbnRJbXB1bHNlID0gbmV3IENvbnZvbHZlcih0aGlzLmNvbnRleHQsIHRoaXMuZ3JhcGgsIHtcclxuICAgICAgICAgICAgICAgIGJ1ZmZlclxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgdGhpcy5ncmFwaC5hcHBseUVmZmVjdCh0aGlzLmVudmlyb25tZW50SW1wdWxzZSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBzZXRMaXN0ZW5lclBvc2l0aW9uKHgsIHksIHopIHtcclxuICAgICAgICB0aGlzLnNjZW5lLnNldExpc3RlbmVyUG9zaXRpb24oeCwgeSwgeik7XHJcbiAgICB9XHJcbiAgICBzZXRMaXN0ZW5lck9yaWVudGF0aW9uKGZvcndhcmQsIHVwKSB7XHJcbiAgICAgICAgdGhpcy5zY2VuZS5zZXRMaXN0ZW5lck9yaWVudGF0aW9uKGZvcndhcmQsIHVwKTtcclxuICAgIH1cclxuICAgIGNsZWFyRGF0YVBvb2woKSB7XHJcbiAgICAgICAgdGhpcy5kYXRhUG9vbC5jbGVhcigpO1xyXG4gICAgfVxyXG59XHJcbiIsImltcG9ydCBSZXNvbmF0b3IgZnJvbSAnLi4vZnJhbWV3b3JrL3Jlc29uYXRvcic7XHJcblxyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU291bmQge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5yZXMgPSBuZXcgUmVzb25hdG9yKCk7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZSA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5tdXNpYyA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZVZvbHVtZSA9IDE7XHJcbiAgICAgICAgdGhpcy5tdXNpY1ZvbHVtZSA9IDE7XHJcbiAgICAgICAgdGhpcy5zZnhWb2x1bWUgPSAxO1xyXG4gICAgICAgIHRoaXMucHJldmlvdXNBbWJpZW5jZSA9IFwiXCI7XHJcbiAgICAgICAgdGhpcy5wcmV2aW91c011c2ljID0gXCJcIjtcclxuICAgIH1cclxuXHJcbiAgICBwbGF5KGZpbGUpIHtcclxuICAgICAgICBjb25zdCBzb3VuZCA9IHRoaXMucmVzLmxvYWRJbW1lZGlhdGUoZmlsZSk7XHJcbiAgICAgICAgc291bmQuc2V0Vm9sdW1lKHRoaXMuc2Z4Vm9sdW1lKTtcclxuICAgICAgICBzb3VuZC5wbGF5KCk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgc2V0QW1iaWVuY2UoZmlsZSkge1xyXG4gICAgICAgIGlmIChmaWxlID09PSB0aGlzLnByZXZpb3VzQW1iaWVuY2UpIHJldHVybjtcclxuICAgICAgICBpZiAodGhpcy5hbWJpZW5jZSkge1xyXG4gICAgICAgICAgICBjb25zdCBwcmV2aW91c0FtYmllbmNlID0gdGhpcy5hbWJpZW5jZTtcclxuICAgICAgICAgICAgdGhpcy5hbWJpZW5jZSA9IG51bGw7XHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gcHJldmlvdXNBbWJpZW5jZS5mYWRlT3V0KDYpLCAxNTAwKTtcclxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiBwcmV2aW91c0FtYmllbmNlLmRlc3Ryb3koKSwgNjAwMCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghZmlsZSkgcmV0dXJuO1xyXG4gICAgICAgIHRoaXMucHJldmlvdXNBbWJpZW5jZSA9IGZpbGU7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZSA9IHRoaXMucmVzLnN0cmVhbShmaWxlLCAwKTtcclxuICAgICAgICB0aGlzLmFtYmllbmNlLnNldFZvbHVtZSh0aGlzLmFtYmllbmNlVm9sdW1lKTtcclxuICAgICAgICB0aGlzLmFtYmllbmNlLnBsYXkoKTtcclxuICAgICAgICB0aGlzLmFtYmllbmNlLmxvb3AodHJ1ZSk7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZS5mYWRlSW4oMyk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0TXVzaWMoZmlsZSkge1xyXG4gICAgICAgIGlmIChmaWxlID09PSB0aGlzLnByZXZpb3VzTXVzaWMpIHJldHVybjtcclxuICAgICAgICBpZiAodGhpcy5tdXNpYykge1xyXG4gICAgICAgICAgICBjb25zdCBwcmV2aW91c011c2ljID0gdGhpcy5tdXNpYztcclxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiBwcmV2aW91c011c2ljLmZhZGVPdXQoMiksIDUwMCk7XHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gcHJldmlvdXNNdXNpYy5kZXN0cm95KCksIDIwMDApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIWZpbGUpIHJldHVybjtcclxuICAgICAgICB0aGlzLnByZXZpb3VzTXVzaWMgPSBmaWxlO1xyXG4gICAgICAgIHRoaXMubXVzaWMgPSB0aGlzLnJlcy5zdHJlYW0oZmlsZSwgMSk7XHJcbiAgICAgICAgdGhpcy5tdXNpYy5zZXRWb2x1bWUodGhpcy5tdXNpY1ZvbHVtZSk7XHJcbiAgICAgICAgdGhpcy5tdXNpYy5wbGF5KCk7XHJcbiAgICAgICAgdGhpcy5tdXNpYy5mYWRlSW4oMik7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0SW1wdWxzZShmaWxlKSB7XHJcbiAgICAgICAgdGhpcy5yZXMuc2V0RW52aXJvbm1lbnRJbXB1bHNlKGZpbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldE11c2ljVm9sdW1lKHZvbHVtZSkge1xyXG4gICAgICAgIHRoaXMubXVzaWNWb2x1bWUgPSB2b2x1bWU7XHJcbiAgICAgICAgaWYgKHRoaXMubXVzaWMpIHRoaXMubXVzaWMuc2V0Vm9sdW1lKHZvbHVtZSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0QW1iaWVuY2VWb2x1bWUodm9sdW1lKSB7XHJcbiAgICAgICAgdGhpcy5hbWJpZW5jZVZvbHVtZSA9IHZvbHVtZTtcclxuICAgICAgICBpZiAodGhpcy5hbWJpZW5jZSkgdGhpcy5hbWJpZW5jZS5zZXRWb2x1bWUodm9sdW1lKTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRTRlhWb2x1bWUodm9sdW1lKSB7XHJcbiAgICAgICAgdGhpcy5zZnhWb2x1bWUgPSB2b2x1bWU7XHJcbiAgICB9XHJcbn0iLCJpbXBvcnQgeyBUVFMgfSBmcm9tICcuLi9mcmFtZXdvcmsvdHRzJztcclxuaW1wb3J0IHsgQXJpYU91dHB1dCB9IGZyb20gJy4uL2ZyYW1ld29yay90dHMvb3V0cHV0cy9hcmlhJztcclxuaW1wb3J0IFNvdW5kIGZyb20gJy4vc291bmQnO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgT3V0cHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMudHRzID0gbmV3IFRUUyhuZXcgQXJpYU91dHB1dCgpKTtcclxuICAgICAgICB0aGlzLmhpc3RvcnkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcIm91dHB1dC1hcmVhXCIpO1xyXG4gICAgICAgIHRoaXMuc291bmQgPSBuZXcgU291bmQoKTtcclxuICAgIH1cclxuXHJcbiAgICBzYXkoc3RyaW5nKSB7XHJcbiAgICAgICAgaWYgKHN0cmluZyA9PT0gXCJcIikgcmV0dXJuO1xyXG4gICAgICAgIHRoaXMuc291bmQucGxheShgYXNzZXRzL3Njcm9sbC53YXZgKTtcclxuICAgICAgICBjb25zdCBub2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInBcIik7XHJcbiAgICAgICAgc3RyaW5nLnNwbGl0KFwiXFxuXCIpLmZvckVhY2goKGxpbmUpID0+IHtcclxuICAgICAgICAgICAgbm9kZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShsaW5lKSk7XHJcbiAgICAgICAgICAgIG5vZGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImJyXCIpKTtcclxuICAgICAgICAgICAgLy8gdGhpcy50dHMuc3BlYWsobGluZSwgZmFsc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuaGlzdG9yeS5hcHBlbmRDaGlsZChub2RlKTtcclxuICAgICAgICAvLyB0aGlzLnR0cy5zcGVhayhzdHJpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIHBsYXkoZmlsZSkge1xyXG4gICAgICAgIHRoaXMuc291bmQucGxheShmaWxlKTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRBbWJpZW5jZShmaWxlKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc291bmQuc2V0QW1iaWVuY2UoZmlsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0TXVzaWMoZmlsZSkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnNvdW5kLnNldE11c2ljKGZpbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHNldEltcHVsc2UoZmlsZSkge1xyXG4gICAgICAgIHRoaXMuc291bmQuc2V0SW1wdWxzZShmaWxlKTtcclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGNsYXNzIElucHV0IHtcclxuICAgIGNvbnN0cnVjdG9yKGNvbW1hbmRIYW5kbGVyLCBvdXRwdXRIYW5kbGVyKSB7XHJcbiAgICAgICAgdGhpcy5oYW5kbGVyID0gY29tbWFuZEhhbmRsZXI7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQgPSBvdXRwdXRIYW5kbGVyO1xyXG4gICAgICAgIHRoaXMuZWNob0lucHV0ID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLmlucHV0RmllbGQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImlucHV0LWFyZWFcIik7XHJcbiAgICAgICAgdGhpcy5oaXN0b3J5ID0gW107XHJcbiAgICAgICAgdGhpcy5oaXN0b3J5Q3Vyc29yID0gMDtcclxuICAgICAgICB0aGlzLmluaXQoKTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRFY2hvKHZhbHVlKSB7XHJcbiAgICAgICAgdGhpcy5lY2hvSW5wdXQgPSB2YWx1ZTtcclxuICAgIH1cclxuXHJcbiAgICBpbml0KCkge1xyXG4gICAgICAgIHRoaXMuaW5wdXRGaWVsZC5hZGRFdmVudExpc3RlbmVyKFwia2V5ZG93blwiLCAoZSkgPT4ge1xyXG4gICAgICAgICAgICBpZiAoZS5rZXkgPT09IFwiQXJyb3dVcFwiKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5oaXN0b3J5Q3Vyc29yID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGlzdG9yeUN1cnNvci0tO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRGaWVsZC52YWx1ZSA9IHRoaXMuaGlzdG9yeVt0aGlzLmhpc3RvcnlDdXJzb3JdO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGUua2V5ID09PSBcIkFycm93RG93blwiKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5oaXN0b3J5Q3Vyc29yIDwgdGhpcy5oaXN0b3J5Lmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGlzdG9yeUN1cnNvcisrO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5wdXRGaWVsZC52YWx1ZSA9IHRoaXMuaGlzdG9yeVt0aGlzLmhpc3RvcnlDdXJzb3JdID8/IFwiXCI7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoZS5rZXkgPT09IFwiRW50ZXJcIikge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5hZGRUb0lucHV0SGlzdG9yeSh0aGlzLmlucHV0RmllbGQudmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgY29uc3QgdmFsID0gdGhpcy5pbnB1dEZpZWxkLnZhbHVlO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5pbnB1dEZpZWxkLnZhbHVlID0gXCJcIjtcclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmVjaG9JbnB1dCkgdGhpcy5vdXRwdXQuc2F5KGA+ICR7dmFsfWApO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVyLmRvQ29tbWFuZCh2YWwpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSlcclxuICAgIH1cclxuXHJcbiAgICBhZGRUb0lucHV0SGlzdG9yeShzdHIpIHtcclxuICAgICAgICB0aGlzLmhpc3RvcnkucHVzaChzdHIpO1xyXG4gICAgICAgIHRoaXMuaGlzdG9yeUN1cnNvciA9IHRoaXMuaGlzdG9yeS5sZW5ndGg7XHJcbiAgICB9XHJcbn0iLCJpbXBvcnQgTG9va0NvbW1hbmQgZnJvbSBcIi4vY29tbWFuZHMvbG9va1wiO1xyXG5pbXBvcnQgVXNlQ29tbWFuZCBmcm9tIFwiLi9jb21tYW5kcy91c2VcIjtcclxuaW1wb3J0IFRha2VDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL3Rha2VcIjtcclxuaW1wb3J0IERyb3BDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2Ryb3BcIjtcclxuaW1wb3J0IEVjaG9Db21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2VjaG9cIjtcclxuaW1wb3J0IFNhdmVDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL3NhdmVcIjtcclxuaW1wb3J0IExvYWRDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2xvYWRcIjtcclxuaW1wb3J0IFZvbHVtZUNvbW1hbmQgZnJvbSBcIi4vY29tbWFuZHMvdm9sdW1lXCI7XHJcbmltcG9ydCBJbnZlbnRvcnlDb21tYW5kIGZyb20gXCIuL2NvbW1hbmRzL2ludmVudG9yeVwiO1xyXG5cclxuY29uc3QgZGVmYXVsdENvbW1hbmRzID0gW1xyXG4gICAgW1tcImxvb2tcIiwgXCJsXCJdLCBMb29rQ29tbWFuZF0sXHJcbiAgICBbW1widXNlXCIsIFwiaW50ZXJhY3RcIl0sIFVzZUNvbW1hbmRdLFxyXG4gICAgW1tcInRha2VcIiwgXCJnZXRcIl0sIFRha2VDb21tYW5kXSxcclxuICAgIFtbXCJkcm9wXCIsIFwicHV0XCJdLCBEcm9wQ29tbWFuZF0sXHJcbiAgICBbXCJlY2hvXCIsIEVjaG9Db21tYW5kXSxcclxuICAgIFtcInNhdmVcIiwgU2F2ZUNvbW1hbmRdLFxyXG4gICAgW1wibG9hZFwiLCBMb2FkQ29tbWFuZF0sXHJcbiAgICBbXCJ2b2x1bWVcIiwgVm9sdW1lQ29tbWFuZF0sXHJcbiAgICBbW1wiaVwiLCBcImludlwiLCBcImludmVudG9yeVwiXSwgSW52ZW50b3J5Q29tbWFuZF1cclxuXTtcclxuXHJcbmNvbnN0IGRpcmVjdGlvbk1hcCA9IFtcclxuICAgIFtcIm5cIiwgXCJub3J0aFwiXSxcclxuICAgIFtcIm5lXCIsIFwibm9ydGhlYXN0XCJdLFxyXG4gICAgW1wiZVwiLCBcImVhc3RcIl0sXHJcbiAgICBbXCJzZVwiLCBcInNvdXRoZWFzdFwiXSxcclxuICAgIFtcInNcIiwgXCJzb3V0aFwiXSxcclxuICAgIFtcInN3XCIsIFwic291dGh3ZXN0XCJdLFxyXG4gICAgW1wid1wiLCBcIndlc3RcIl0sXHJcbiAgICBbXCJud1wiLCBcIm5vcnRod2VzdFwiXSxcclxuICAgIFtcInVcIiwgXCJ1cFwiXSxcclxuICAgIFtcImRcIiwgXCJkb3duXCJdXHJcbl07XHJcblxyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDb21tYW5kcyB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0LCBjb21tYW5kcykge1xyXG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XHJcbiAgICAgICAgdGhpcy5jb21tYW5kcyA9IGNvbW1hbmRzIHx8IG5ldyBNYXAoKTtcclxuICAgICAgICB0aGlzLmVuYWJsZWQgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuYWRkRGVmYXVsdENvbW1hbmRzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZG9Db21tYW5kKHN0cikge1xyXG4gICAgICAgIGlmICghdGhpcy5lbmFibGVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5wcmludChgWW91IGNhbid0IHNlZW0gdG8gZG8gYW55dGhpbmcgYXQgdGhlIG1vbWVudC5gKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCByb29tID0gdGhpcy5jb250ZXh0LmdldFJvb20odGhpcy5jb250ZXh0LnBsYXllci5jdXJyZW50Um9vbSk7XHJcbiAgICAgICAgY29uc3Qgc3BsaXQgPSBzdHIuc3BsaXQoXCIgXCIpO1xyXG4gICAgICAgIGlmICh0aGlzLmNvbW1hbmRzLmdldChzcGxpdFswXSkpIHtcclxuICAgICAgICAgICAgdGhpcy5jb21tYW5kcy5nZXQoc3BsaXRbMF0pKHNwbGl0LCB0aGlzLmNvbnRleHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICBjb25zdCBkaXJlY3Rpb24gPSB0aGlzLm1hdGNoRGlyZWN0aW9uKHNwbGl0WzBdKTtcclxuXHJcbiAgICAgICAgaWYgKHJvb20uZ2V0RXhpdChkaXJlY3Rpb24pKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5tb3ZlKHJvb20uZ2V0RXhpdChkaXJlY3Rpb24pKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgYWRkQ29tbWFuZChuYW1lLCBmdW5jKSB7XHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkobmFtZSkpIHtcclxuICAgICAgICAgICAgbmFtZS5mb3JFYWNoKChjb21tYW5kKSA9PiB0aGlzLmNvbW1hbmRzLnNldChjb21tYW5kLCBmdW5jKSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5jb21tYW5kcy5zZXQobmFtZSwgZnVuYyk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGFkZENvbW1hbmRzKGNvbW1hbmRzKSB7XHJcbiAgICAgICAgY29tbWFuZHMuZm9yRWFjaCgoY29tbWFuZCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmFkZENvbW1hbmQoY29tbWFuZFswXSwgY29tbWFuZFsxXSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRGVmYXVsdENvbW1hbmRzKCkge1xyXG4gICAgICAgIHRoaXMuYWRkQ29tbWFuZHMoZGVmYXVsdENvbW1hbmRzKTtcclxuICAgIH1cclxuXHJcbiAgICBtYXRjaERpcmVjdGlvbihzdHIpIHtcclxuICAgICAgICBmb3IgKGxldCBkaXIgb2YgZGlyZWN0aW9uTWFwKSB7XHJcbiAgICAgICAgICAgIGlmIChkaXJbMF0gPT0gc3RyKSByZXR1cm4gZGlyWzFdO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIExvb2tDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGlmIChhcmdzLmxlbmd0aCA9PSAxKSB7XHJcbiAgICAgICAgY29udGV4dC5leGFtaW5lUm9vbSgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBjb25zdCByb29tID0gY29udGV4dC5nZXRSb29tKGNvbnRleHQucGxheWVyLmN1cnJlbnRSb29tKTtcclxuICAgICAgICBjb25zdCBpdGVtcyA9IHJvb20uZ2V0SXRlbXMoKTtcclxuICAgICAgICBsZXQgaXRlbSA9IG51bGw7XHJcbiAgICAgICAgZm9yIChsZXQgaSBvZiBpdGVtcykge1xyXG4gICAgICAgICAgICBpZiAoaS5uYW1lLmluY2x1ZGVzKGFyZ3NbMV0pKSB7XHJcbiAgICAgICAgICAgICAgICBpdGVtID0gaTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghaXRlbSkge1xyXG4gICAgICAgICAgICBjb25zdCBpdGVtcyA9IGNvbnRleHQucGxheWVyLmdldEludmVudG9yeSgpO1xyXG4gICAgICAgICAgICBmb3IgKGxldCBpIG9mIGl0ZW1zKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoaS5uYW1lLmluY2x1ZGVzKGFyZ3NbMV0pKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaXRlbSA9IGk7XHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCFpdGVtKSB7XHJcbiAgICAgICAgICAgIGNvbnRleHQub3V0cHV0LnNheShgSSBjb3VsZCBub3QgZmluZCBhICR7YXJnc1sxXX0uYCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgY29udGV4dC5vdXRwdXQuc2F5KGBZb3UgbG9vayBhdCAke2l0ZW0ubmFtZX0uYCk7XHJcbiAgICAgICAgICAgIGNvbnRleHQub3V0cHV0LnNheShpdGVtLmRlc2NyaXB0aW9uKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBVc2VDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGNvbnN0IHJvb20gPSBjb250ZXh0LmdldFJvb20oY29udGV4dC5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgY29uc3QgaXRlbXMgPSByb29tLmdldEl0ZW1zKCk7XHJcbiAgICBsZXQgaXRlbSA9IG51bGw7XHJcbiAgICBmb3IgKGxldCBpIG9mIGl0ZW1zKSB7XHJcbiAgICAgICAgaWYgKGkubmFtZS5pbmNsdWRlcyhhcmdzWzFdKSkge1xyXG4gICAgICAgICAgICBpdGVtID0gaTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYgKCFpdGVtKSB7XHJcbiAgICAgICAgY29uc3QgaXRlbXMgPSBjb250ZXh0LnBsYXllci5nZXRJbnZlbnRvcnkoKTtcclxuICAgICAgICBmb3IgKGxldCBpIG9mIGl0ZW1zKSB7XHJcbiAgICAgICAgICAgIGlmIChpLm5hbWUuaW5jbHVkZXMoYXJnc1sxXSkpIHtcclxuICAgICAgICAgICAgICAgIGl0ZW0gPSBpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoIWl0ZW0pIHtcclxuICAgICAgICBjb250ZXh0Lm91dHB1dC5zYXkoYEkgY291bGQgbm90IGZpbmQgYSAke2FyZ3NbMV19LmApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBhd2FpdCBpdGVtLm9uVXNlKCk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBUYWtlQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb25zdCByb29tID0gY29udGV4dC5nZXRSb29tKGNvbnRleHQucGxheWVyLmN1cnJlbnRSb29tKTtcclxuICAgIGNvbnN0IGl0ZW1zID0gcm9vbS5nZXRJdGVtcygpO1xyXG4gICAgbGV0IGl0ZW0gPSBudWxsO1xyXG4gICAgZm9yIChsZXQgaSBvZiBpdGVtcykge1xyXG4gICAgICAgIGlmIChpLm5hbWUuaW5jbHVkZXMoYXJnc1sxXSkpIHtcclxuICAgICAgICAgICAgaXRlbSA9IGk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGlmICghaXRlbSkge1xyXG4gICAgICAgIGNvbnRleHQucHJpbnQoYFlvdSBjYW4ndCBmaW5kIGFueSAke2FyZ3NbMV19LmApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoIWl0ZW0udGFrZWFibGUpIHtcclxuICAgICAgICAgICAgY29udGV4dC5wcmludChgWW91IGNhbid0IHRha2UgJHtpdGVtLm5hbWV9LmApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHJvb20ucmVtb3ZlSXRlbShpdGVtLmlkKTtcclxuICAgICAgICAgICAgY29udGV4dC5wbGF5ZXIuYWRkSXRlbShpdGVtLmlkKTtcclxuICAgICAgICAgICAgY29udGV4dC5wcmludChgWW91IHRha2UgJHtpdGVtLm5hbWV9LmApO1xyXG4gICAgICAgICAgICBpdGVtLm9uVGFrZSgpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIERyb3BDb21tYW5kKGFyZ3MsIGNvbnRleHQpIHtcclxuICAgIGNvbnN0IHJvb20gPSBjb250ZXh0LmdldFJvb20oY29udGV4dC5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgY29uc3QgaXRlbXMgPSBjb250ZXh0LnBsYXllci5nZXRJbnZlbnRvcnkoKTtcclxuICAgIGxldCBpdGVtID0gbnVsbDtcclxuICAgIGZvciAobGV0IGkgb2YgaXRlbXMpIHtcclxuICAgICAgICBpZiAoaS5uYW1lLmluY2x1ZGVzKGFyZ3NbMV0pKSB7XHJcbiAgICAgICAgICAgIGl0ZW0gPSBpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoIWl0ZW0pIHtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBZb3UncmUgbm90IGNhcnJ5aW5nIGEgJHthcmdzWzFdfWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICBjb250ZXh0LnBsYXllci5yZW1vdmVJdGVtKGl0ZW0uaWQpO1xyXG4gICAgICAgIHJvb20uYWRkSXRlbShpdGVtLmlkKTtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBZb3Ugc2V0ICR7aXRlbS5uYW1lfSBkb3duIG9uIHRoZSBmbG9vci5gKTtcclxuICAgICAgICBpdGVtLm9uRHJvcCgpO1xyXG4gICAgfVxyXG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRWNob0NvbW1hbmQoYXJncywgY29udGV4dCkge1xyXG4gICAgaWYgKGFyZ3NbMV0gIT0gXCJvblwiICYmIGFyZ3NbMV0gIT0gXCJvZmZcIikge1xyXG4gICAgICAgIGNvbnRleHQucHJpbnQoYFVzYWdlOiBlY2hvIDxvbi9vZmY+YCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnRleHQuc2V0SW5wdXRFY2hvKGFyZ3NbMV0gPT0gXCJvblwiID8gdHJ1ZSA6IGZhbHNlKTtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBDb21tYW5kIGVjaG8gaXMgbm93ICR7YXJnc1sxXX0uYCk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBTYXZlQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBTYXZpbmcgZ2FtZS4uLmApO1xyXG4gICAgY29udGV4dC5zYXZlKCk7XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBMb2FkQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBMb2FkaW5nIGdhbWUuLi5gKTtcclxuICAgIGNvbnRleHQubG9hZCgpO1xyXG59IiwiZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gVm9sdW1lQ29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBpZiAoYXJncy5sZW5ndGggPCAzKSB7XHJcbiAgICAgICAgcmV0dXJuIGNvbnRleHQucHJpbnQoYFVzYWdlOiB2b2x1bWUgPG11c2ljL3NmeC9hbWJpZW5jZT4gPDAtMTAwPmApO1xyXG4gICAgfVxyXG4gICAgY29uc3QgdmFsdWUgPSBwYXJzZUludChhcmdzWzJdKTtcclxuICAgIGlmICh2YWx1ZSA+IDEwMCB8fCB2YWx1ZSA8IDEpIHtcclxuICAgICAgICByZXR1cm4gY29udGV4dC5wcmludChgTm8gaGlnaGVyIHRoYW4gMTAwIGFuZCBubyBsZXNzIHRoYW4gMS5gKTtcclxuICAgIH1cclxuICAgIGlmIChhcmdzWzFdID09IFwic2Z4XCIpIHtcclxuICAgICAgICBjb250ZXh0Lm91dHB1dC5zb3VuZC5zZXRTRlhWb2x1bWUodmFsdWUvMTAwKTtcclxuICAgIH0gZWxzZSBpZiAoYXJnc1sxXSA9PSBcIm11c2ljXCIpIHtcclxuICAgICAgICBjb250ZXh0Lm91dHB1dC5zb3VuZC5zZXRNdXNpY1ZvbHVtZSh2YWx1ZS8xMDApO1xyXG4gICAgfSBlbHNlIGlmIChhcmdzWzFdID09IFwiYW1iaWVuY2VcIikge1xyXG4gICAgICAgIGNvbnRleHQub3V0cHV0LnNvdW5kLnNldEFtYmllbmNlVm9sdW1lKHZhbHVlLzEwMCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiBjb250ZXh0LnByaW50KGBJbnZhbGlkIGNoYW5uZWwuIEVpdGhlciBhbWJpZW5jZSwgc2Z4IG9yIG11c2ljIGlzIGFsbG93ZWQuYCk7XHJcbiAgICB9XHJcbiAgICBjb250ZXh0LnByaW50KGAke2FyZ3NbMV19IHZvbHVtZSBzZXQgdG8gJHt2YWx1ZX0lYClcclxufSIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEludmVudG9yeUNvbW1hbmQoYXJncywgY29udGV4dCkge1xyXG4gICAgY29uc3QgaXRlbXMgPSBjb250ZXh0LnBsYXllci5nZXRJbnZlbnRvcnkoKTtcclxuICAgIGlmIChpdGVtcy5sZW5ndGggPCAxKSByZXR1cm4gY29udGV4dC5wcmludChgWW91J3JlIG5vdCBjYXJyeWluZyBhbnl0aGluZy5gKTtcclxuICAgIGxldCBpdGVtRGVzY3JpcHRpb24gPSBgWW91IGFyZSBjYXJyeWluZyBgO1xyXG4gICAgaXRlbXMuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcclxuICAgICAgICBpZiAoaW5kZXggPCBpdGVtcy5sZW5ndGggLSAyKSB7XHJcbiAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBgJHtpdGVtLm5hbWV9LCBgO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoaW5kZXggPCBpdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBgJHtpdGVtLm5hbWV9IGFuZCBgO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBpdGVtLm5hbWVcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxuICAgIGNvbnRleHQucHJpbnQoaXRlbURlc2NyaXB0aW9uICsgXCIuXCIpO1xyXG59IiwiZXhwb3J0IGRlZmF1bHQgY2xhc3MgU2VyaWFsaXphdGlvbiB7XHJcbiAgICBjb25zdHJ1Y3Rvcihjb250ZXh0KSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcclxuICAgIH1cclxuXHJcbiAgICBzYXZlKCkge1xyXG4gICAgICAgIGNvbnN0IHNhdmVvYmogPSB7XHJcbiAgICAgICAgICAgIHN0YXRlOiB0aGlzLmNvbnRleHQuc3RhdGUuc2VyaWFsaXplKCksXHJcbiAgICAgICAgICAgIGl0ZW1Mb2NhdGlvbnM6IHRoaXMuc2VyaWFsaXplSXRlbUxvY2F0aW9ucygpLFxyXG4gICAgICAgICAgICBpdGVtU3RhdGVzOiB0aGlzLnNlcmlhbGl6ZUl0ZW1TdGF0ZXMoKSxcclxuICAgICAgICAgICAgcGxheWVyOiAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICBjdXJyZW50Um9vbTogdGhpcy5jb250ZXh0LnBsYXllci5jdXJyZW50Um9vbSxcclxuICAgICAgICAgICAgICAgIGludmVudG9yeTogdGhpcy5jb250ZXh0LnBsYXllci5pbnZlbnRvcnlcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgdm9sdW1lczoge1xyXG4gICAgICAgICAgICAgICAgbXVzaWM6IHRoaXMuY29udGV4dC5vdXRwdXQuc291bmQubXVzaWNWb2x1bWUsXHJcbiAgICAgICAgICAgICAgICBzZng6IHRoaXMuY29udGV4dC5vdXRwdXQuc291bmQuc2Z4Vm9sdW1lLFxyXG4gICAgICAgICAgICAgICAgYW1iaWVuY2U6IHRoaXMuY29udGV4dC5vdXRwdXQuc291bmQuYW1iaWVuY2VWb2x1bWVcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oXCJzYXZlXCIsIEpTT04uc3RyaW5naWZ5KHNhdmVvYmopKTtcclxuICAgIH1cclxuXHJcbiAgICBsb2FkKCkge1xyXG4gICAgICAgIGNvbnN0IGxvYWRvYmogPSBKU09OLnBhcnNlKGxvY2FsU3RvcmFnZS5nZXRJdGVtKFwic2F2ZVwiKSk7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0LnN0YXRlLmRlc2VyaWFsaXplKGxvYWRvYmouc3RhdGUpO1xyXG4gICAgICAgIHRoaXMuZGVzZXJpYWxpemVJdGVtTG9jYXRpb25zKGxvYWRvYmouaXRlbUxvY2F0aW9ucyk7XHJcbiAgICAgICAgdGhpcy5kZXNlcmlhbGl6ZUl0ZW1TdGF0ZXMobG9hZG9iai5pdGVtU3RhdGVzKTtcclxuICAgICAgICB0aGlzLmRlc2VyaWFsaXplUGxheWVyKGxvYWRvYmoucGxheWVyKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQub3V0cHV0LnNvdW5kLnNldFNGWFZvbHVtZShsb2Fkb2JqLnZvbHVtZXMuc2Z4KTtcclxuICAgICAgICB0aGlzLmNvbnRleHQub3V0cHV0LnNvdW5kLnNldE11c2ljVm9sdW1lKGxvYWRvYmoudm9sdW1lcy5tdXNpYyk7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0Lm91dHB1dC5zb3VuZC5zZXRBbWJpZW5jZVZvbHVtZShsb2Fkb2JqLnZvbHVtZXMuYW1iaWVuY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIHNlcmlhbGl6ZUl0ZW1Mb2NhdGlvbnMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5yb29tcy5tYXAoKGl0ZW0pID0+IHtcclxuICAgICAgICAgICAgcmV0dXJuIFtpdGVtLmlkLCBcclxuICAgICAgICAgICAgICAgIGl0ZW0ub2JqZWN0c1xyXG4gICAgICAgICAgICBdXHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgZGVzZXJpYWxpemVJdGVtTG9jYXRpb25zKGl0ZW1zKSB7XHJcbiAgICAgICAgaXRlbXMuZm9yRWFjaCgoaXRlbSkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5jb250ZXh0LmdldFJvb20oaXRlbVswXSk7XHJcbiAgICAgICAgICAgIHJvb20ub2JqZWN0cyA9IGl0ZW1bMV07XHJcbiAgICAgICAgfSlcclxuICAgIH1cclxuXHJcbiAgICBkZXNlcmlhbGl6ZUl0ZW1TdGF0ZXMoaXRlbXMpIHtcclxuICAgICAgICBpdGVtcy5mb3JFYWNoKChpdGVtKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IG9iaiA9IHRoaXMuY29udGV4dC5nZXRJdGVtKGl0ZW1bMF0pO1xyXG4gICAgICAgICAgICBvYmouc3RhdGUuZGVzZXJpYWxpemUoaXRlbVsxXSk7XHJcbiAgICAgICAgfSlcclxuICAgIH1cclxuXHJcbiAgICBkZXNlcmlhbGl6ZVBsYXllcihwbGF5ZXIpIHtcclxuICAgICAgICB0aGlzLmNvbnRleHQubW92ZShwbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIHRoaXMuY29udGV4dC5wbGF5ZXIuaW52ZW50b3J5ID0gcGxheWVyLmludmVudG9yeTtcclxuICAgIH1cclxuXHJcbiAgICBzZXJpYWxpemVJdGVtU3RhdGVzKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuaXRlbXMubWFwKChpdGVtKSA9PiB7XHJcbiAgICAgICAgICAgIHJldHVybiBbaXRlbS5pZCwgaXRlbS5zdGF0ZS5zZXJpYWxpemUoKV1cclxuICAgICAgICB9KTtcclxuICAgIH1cclxufSIsImltcG9ydCBTdGF0ZSBmcm9tICcuL3N0YXRlJztcclxuaW1wb3J0IFJvb20gZnJvbSAnLi9yb29tJztcclxuaW1wb3J0IFBsYXllciBmcm9tICcuL3BsYXllcic7XHJcbmltcG9ydCBPdXRwdXQgZnJvbSAnLi9vdXRwdXQnO1xyXG5pbXBvcnQgSW5wdXQgZnJvbSAnLi9pbnB1dCc7XHJcbmltcG9ydCBDb21tYW5kcyBmcm9tICcuL2NvbW1hbmRzJztcclxuaW1wb3J0IFNlcmlhbGl6YXRpb24gZnJvbSAnLi9zZXJpYWxpemF0aW9uJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEdhbWUge1xyXG4gICAgY29uc3RydWN0b3IobmV3R2FtZSA9IHRydWUpIHtcclxuICAgICAgICB0aGlzLm5ld0dhbWUgPSBuZXdHYW1lO1xyXG4gICAgICAgIHRoaXMucGxheWVyID0gbmV3IFBsYXllcigpO1xyXG4gICAgICAgIHRoaXMuc3RhdGUgPSBuZXcgU3RhdGUoKTtcclxuICAgICAgICB0aGlzLnJvb21zID0gW107XHJcbiAgICAgICAgdGhpcy5pdGVtcyA9IFtdO1xyXG4gICAgICAgIHRoaXMub3V0cHV0ID0gbmV3IE91dHB1dCgpO1xyXG4gICAgICAgIHRoaXMuY29tbWFuZEhhbmRsZXIgPSBuZXcgQ29tbWFuZHModGhpcyk7XHJcbiAgICAgICAgdGhpcy5pbnB1dCA9IG5ldyBJbnB1dCh0aGlzLmNvbW1hbmRIYW5kbGVyLCB0aGlzLm91dHB1dCk7XHJcbiAgICAgICAgdGhpcy52aXNpdGVkUm9vbXMgPSBuZXcgTWFwKCk7XHJcbiAgICAgICAgdGhpcy5pbnRlcnZhbCA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5TZXJpYWxpemF0aW9uID0gbmV3IFNlcmlhbGl6YXRpb24odGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpbnQoc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHN0cmluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgdGVsbChsaW5lcywgdGltZSkge1xyXG4gICAgICAgIGZvciAobGV0IGxpbmUgb2YgbGluZXMpIHtcclxuICAgICAgICAgICAgdGhpcy5wcmludChsaW5lKTtcclxuICAgICAgICAgICAgYXdhaXQgdGhpcy53YWl0KHRpbWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpbml0KGRhdGEpIHtcclxuICAgICAgICB0aGlzLnJvb21zID0gZGF0YS5yb29tcy5tYXAoKHJvb20pID0+IHtcclxuICAgICAgICAgICAgcm9vbS5jb250ZXh0ID0gdGhpcztcclxuICAgICAgICAgICAgcmV0dXJuIHJvb207XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5pdGVtcyA9IGRhdGEuaXRlbXMubWFwKChpdGVtKSA9PiB7XHJcbiAgICAgICAgICAgIGl0ZW0uY29udGV4dCA9IHRoaXM7XHJcbiAgICAgICAgICAgIHJldHVybiBpdGVtO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuc3RhdGUgPSBkYXRhLnN0YXRlIHx8IG5ldyBTdGF0ZSgpO1xyXG4gICAgICAgIHRoaXMuY29tbWFuZEhhbmRsZXIuYWRkQ29tbWFuZHMoZGF0YS5jb21tYW5kcyk7XHJcbiAgICAgICAgdGhpcy5wbGF5ZXIgPSBuZXcgUGxheWVyKCk7XHJcbiAgICAgICAgdGhpcy5wbGF5ZXIuY29udGV4dCA9IHRoaXM7XHJcbiAgICAgICAgaWYgKHRoaXMubmV3R2FtZSkge1xyXG4gICAgICAgICAgICB0aGlzLm1vdmUodGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuU2VyaWFsaXphdGlvbi5sb2FkKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuc3RhcnQoKTtcclxuICAgIH1cclxuXHJcbiAgICBhZHZhbmNlVGljaygpIHtcclxuICAgICAgICB0aGlzLml0ZW1zLmZvckVhY2goKGl0ZW0pID0+IGl0ZW0ub25UaWNrKCkpO1xyXG4gICAgICAgIHRoaXMucm9vbXMuZm9yRWFjaCgocm9vbSkgPT4gcm9vbS5vblRpY2soKSk7XHJcbiAgICB9XHJcblxyXG4gICAgc3RhcnQoKSB7XHJcbiAgICAgICAgdGhpcy5pbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHRoaXMuYWR2YW5jZVRpY2soKSwgMTAwMCk7XHJcbiAgICB9XHJcblxyXG4gICAgc3RvcCgpIHtcclxuICAgICAgICBjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWwpO1xyXG4gICAgICAgIHRoaXMuaW50ZXJ2YWwgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGV4YW1pbmVSb29tKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnNheShyb29tLnRpdGxlKTtcclxuICAgICAgICBpZiAoIXRoaXMudmlzaXRlZFJvb21zLmdldCh0aGlzLnBsYXllci5jdXJyZW50Um9vbSkgJiYgcm9vbS5maXJzdERlc2NyaXB0aW9uICE9IFwiXCIpIHtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHJvb20uZmlyc3REZXNjcmlwdGlvbik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXQuc2F5KHJvb20uZGVzY3JpcHRpb24pO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLmV4YW1pbmVJdGVtcygpO1xyXG4gICAgICAgIHRoaXMuZXhhbWluZUV4aXRzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZXhhbWluZUl0ZW1zKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGNvbnN0IGl0ZW1zID0gcm9vbS5nZXRJdGVtcygpO1xyXG4gICAgICAgIGlmIChpdGVtcy5sZW5ndGggPCAxKSByZXR1cm47XHJcbiAgICAgICAgbGV0IGl0ZW1EZXNjcmlwdGlvbiA9IGBZb3Ugc2VlIGA7XHJcbiAgICAgICAgaXRlbXMuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcclxuICAgICAgICAgICAgaWYgKGluZGV4IDwgaXRlbXMubGVuZ3RoIC0gMikge1xyXG4gICAgICAgICAgICAgICAgaXRlbURlc2NyaXB0aW9uICs9IGAke2l0ZW0ubmFtZX0sIGA7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoaW5kZXggPCBpdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgICAgICBpdGVtRGVzY3JpcHRpb24gKz0gYCR7aXRlbS5uYW1lfSBhbmQgYDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGl0ZW1EZXNjcmlwdGlvbiArPSBpdGVtLm5hbWVcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMub3V0cHV0LnNheShpdGVtRGVzY3JpcHRpb24gKyBcIi5cIik7XHJcbiAgICB9XHJcblxyXG4gICAgZXhhbWluZUV4aXRzKCkge1xyXG4gICAgICAgIGNvbnN0IHJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGxldCBleGl0cyA9IFtdO1xyXG4gICAgICAgIGxldCBleGl0RGVzY3JpcHRpb24gPSBcIllvdSBjYW4gZ28gXCI7XHJcbiAgICAgICAgY29uc3QgZXhpdEtleXMgPSByb29tLmV4aXRzLmtleXMoKTtcclxuICAgICAgICBmb3IgKGxldCBleGl0IG9mIGV4aXRLZXlzKSB7XHJcbiAgICAgICAgICAgIGV4aXRzLnB1c2goZXhpdCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGV4aXRzLmZvckVhY2goKGl0ZW0sIGluZGV4KSA9PiB7XHJcbiAgICAgICAgICAgIGlmIChpbmRleCA8IGV4aXRzLmxlbmd0aCAtIDIpIHtcclxuICAgICAgICAgICAgICAgIGV4aXREZXNjcmlwdGlvbiArPSBgJHtpdGVtfSwgYDtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChpbmRleCA8IGV4aXRzLmxlbmd0aCAtIDEpIHtcclxuICAgICAgICAgICAgICAgIGV4aXREZXNjcmlwdGlvbiArPSBgJHtpdGVtfSBhbmQgYDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGV4aXREZXNjcmlwdGlvbiArPSBpdGVtXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgICB0aGlzLm91dHB1dC5zYXkoZXhpdERlc2NyaXB0aW9uICsgXCIuXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIGdldFJvb20oaWQpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yb29tcy5maW5kKChyb29tKSA9PiByb29tLmlkID09IGlkKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRJdGVtKGlkKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS5pZCA9PSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgd2FpdChtcykge1xyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG1vdmUocm9vbUlEKSB7XHJcbiAgICAgICAgY29uc3QgY3VycmVudFJvb20gPSB0aGlzLmdldFJvb20odGhpcy5wbGF5ZXIuY3VycmVudFJvb20pO1xyXG4gICAgICAgIGNvbnN0IG5ld1Jvb20gPSB0aGlzLmdldFJvb20ocm9vbUlEKTtcclxuICAgICAgICBpZiAoY3VycmVudFJvb20uY2FuRXhpdCgpICYmIG5ld1Jvb20uY2FuRW50ZXIoKSkge1xyXG4gICAgICAgICAgICBhd2FpdCBjdXJyZW50Um9vbS5vbkV4aXQoKTtcclxuICAgICAgICAgICAgYXdhaXQgbmV3Um9vbS5vbkVudGVyKCk7XHJcbiAgICAgICAgICAgIHRoaXMucGxheWVyLmN1cnJlbnRSb29tID0gcm9vbUlEO1xyXG4gICAgICAgICAgICB0aGlzLmV4YW1pbmVSb29tKCk7XHJcbiAgICAgICAgICAgIHRoaXMudmlzaXRlZFJvb21zLnNldChyb29tSUQsIHRydWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBlbmFibGVDb21tYW5kSW5wdXQodmFsdWUpIHtcclxuICAgICAgICB0aGlzLmNvbW1hbmRIYW5kbGVyLmVuYWJsZWQgPSB2YWx1ZTtcclxuICAgIH1cclxuXHJcbiAgICBzZXRJbnB1dEVjaG8odmFsdWUpIHtcclxuICAgICAgICB0aGlzLmlucHV0LnNldEVjaG8odmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHNhdmUoKSB7XHJcbiAgICAgICAgdGhpcy5TZXJpYWxpemF0aW9uLnNhdmUoKTtcclxuICAgIH1cclxuXHJcbiAgICBsb2FkKCkge1xyXG4gICAgICAgIHRoaXMuU2VyaWFsaXphdGlvbi5sb2FkKCk7XHJcbiAgICB9XHJcbn0iLCJleHBvcnQgZGVmYXVsdCBjbGFzcyBSb29tIHtcclxuICAgIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgICAgIHRoaXMuaWQgPSBcInJvb21cIjtcclxuICAgICAgICB0aGlzLnRpdGxlID0gXCJBIHJvb21cIjtcclxuICAgICAgICB0aGlzLmRlc2NyaXB0aW9uID0gXCJZb3Ugc2VlIG5vdGhpbmcgc3BlY2lhbFwiO1xyXG4gICAgICAgIHRoaXMuZmlyc3REZXNjcmlwdGlvbiA9IFwiXCI7XHJcbiAgICAgICAgdGhpcy5vYmplY3RzID0gW107XHJcbiAgICAgICAgdGhpcy5leGl0cyA9IG5ldyBNYXAoKTtcclxuICAgICAgICB0aGlzLmVudGVyQ2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuZXhpdENhbGxiYWNrID0gbnVsbDtcclxuICAgICAgICB0aGlzLmNhbkVudGVyTG9naWMgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuY2FuRXhpdExvZ2ljID0gbnVsbDtcclxuICAgICAgICB0aGlzLnRpY2tDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLm11c2ljID0gbnVsbDtcclxuICAgICAgICB0aGlzLmFtYmllbmNlID0gbnVsbDtcclxuICAgICAgICB0aGlzLmltcHVsc2UgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uRW50ZXIoKSB7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0Lm91dHB1dC5zZXRNdXNpYyh0aGlzLm11c2ljKTtcclxuICAgICAgICB0aGlzLmNvbnRleHQub3V0cHV0LnNldEFtYmllbmNlKHRoaXMuYW1iaWVuY2UpO1xyXG4gICAgICAgIHRoaXMuY29udGV4dC5vdXRwdXQuc2V0SW1wdWxzZSh0aGlzLmltcHVsc2UpO1xyXG4gICAgICAgIGlmICh0aGlzLmVudGVyQ2FsbGJhY2spIHJldHVybiB0aGlzLmVudGVyQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkV4aXQoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZXhpdENhbGxiYWNrKSByZXR1cm4gdGhpcy5leGl0Q2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBjYW5FbnRlcigpIHtcclxuICAgICAgICBpZiAodGhpcy5jYW5FbnRlckxvZ2ljKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNhbkVudGVyTG9naWModGhpcy5jb250ZXh0KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgY2FuRXhpdCgpIHtcclxuICAgICAgICBpZiAodGhpcy5jYW5FeGl0TG9naWMpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FuRXhpdExvZ2ljKHRoaXMuY29udGV4dCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEV4aXQoZGlyZWN0aW9uLCByb29tSUQpIHtcclxuICAgICAgICB0aGlzLmV4aXRzLnNldChkaXJlY3Rpb24sIHJvb21JRCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0RXhpdChkaXJlY3Rpb24pIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5leGl0cy5nZXQoZGlyZWN0aW9uKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGRJdGVtKGl0ZW0pIHtcclxuICAgICAgICB0aGlzLm9iamVjdHMucHVzaChpdGVtKTtcclxuICAgIH1cclxuXHJcbiAgICByZW1vdmVJdGVtKGlkKSB7XHJcbiAgICAgICAgdGhpcy5vYmplY3RzID0gdGhpcy5vYmplY3RzLmZpbHRlcigoaXRlbSkgPT4gaXRlbSAhPSBpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRW50ZXJDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuZW50ZXJDYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkRXhpdENhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5leGl0Q2FsbGJhY2sgPSBjYWxsYmFjay5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEVudGVyTG9naWMoZnVuYykge1xyXG4gICAgICAgIHRoaXMuY2FuRW50ZXJMb2dpYyA9IGZ1bmMuYmluZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGRFeGl0TG9naWMoZnVuYykge1xyXG4gICAgICAgIHRoaXMuY2FuRXhpdExvZ2ljID0gZnVuYy5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZFRpY2tDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMudGlja0NhbGxiYWNrID0gY2FsbGJhY2suYmluZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRJdGVtcygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5vYmplY3RzLm1hcCgoaXRlbSkgPT4gdGhpcy5jb250ZXh0LmdldEl0ZW0oaXRlbSkpO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG9uVGljaygpIHtcclxuICAgICAgICBpZiAodGhpcy50aWNrQ2FsbGJhY2spIHJldHVybiB0aGlzLnRpY2tDYWxsYmFjayh0aGlzLmNvbnRleHQpO1xyXG4gICAgfVxyXG59IiwiaW1wb3J0IFJvb20gZnJvbSAnLi4vcm9vbSc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSb29tQnVpbGRlciB7XHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgICAgICB0aGlzLnJvb20gPSBuZXcgUm9vbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhJRChJRCkge1xyXG4gICAgICAgIHRoaXMucm9vbS5pZCA9IElEO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhUaXRsZSh0aXRsZSkge1xyXG4gICAgICAgIHRoaXMucm9vbS50aXRsZSA9IHRpdGxlO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhGaXJzdERlc2NyaXB0aW9uKGRlc2NyaXB0aW9uKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmZpcnN0RGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRGVzY3JpcHRpb24oZGVzY3JpcHRpb24pIHtcclxuICAgICAgICB0aGlzLnJvb20uZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbjtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRXhpdChkaXJlY3Rpb24sIHJvb21JRCkge1xyXG4gICAgICAgIHRoaXMucm9vbS5hZGRFeGl0KGRpcmVjdGlvbiwgcm9vbUlEKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoSXRlbShpdGVtSUQpIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkSXRlbShpdGVtSUQpO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhFbnRlckNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEVudGVyQ2FsbGJhY2soY2FsbGJhY2spO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhFeGl0Q2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLnJvb20uYWRkRXhpdENhbGxiYWNrKGNhbGxiYWNrKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoRW50ZXJMb2dpYyhmdW5jKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEVudGVyTG9naWMoZnVuYyk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEV4aXRMb2dpYyhmdW5jKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZEV4aXRMb2dpYyhmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoVGljayhmdW5jKSB7XHJcbiAgICAgICAgdGhpcy5yb29tLmFkZFRpY2tDYWxsYmFjayhmdW5jKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoTXVzaWMoZmlsZSkge1xyXG4gICAgICAgIHRoaXMucm9vbS5tdXNpYyA9IGZpbGU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aEFtYmllbmNlKGZpbGUpIHtcclxuICAgICAgICB0aGlzLnJvb20uYW1iaWVuY2UgPSBmaWxlO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhJbXB1bHNlKGZpbGUpIHtcclxuICAgICAgICB0aGlzLnJvb20uaW1wdWxzZSA9IGZpbGU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIGNyZWF0ZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yb29tO1xyXG4gICAgfVxyXG59IiwiaW1wb3J0IFJvb21CdWlsZGVyIGZyb20gJy4uLy4uLy4uL2VuZ2luZS9idWlsZGVycy9yb29tJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGFydFwiKVxyXG4ud2l0aFRpdGxlKFwiQSBzbWFsbCBzcGhlcmljYWwgYWxjb3ZlXCIpXHJcbi53aXRoRmlyc3REZXNjcmlwdGlvbihcclxuYFlvdSBmaW5kIHlvdXJzZWxmIGluIGEgc21hbGwsIHNwaGVyaWNhbCBhbGNvdmUuIEl0IGZlZWxzIGNvbGQgYW5kIGRhcmssIHNhdmUgZnJvbSBhIGRpbSBnbG93IHdoaWNoIHNlZW1zIHRvIGJlIGVsdW1pbmF0aW5nIHRoZSBhcmVhIGZyb20gdGhlIG5vcnRoLlxyXG5UaGUgc3VyZmFjZSBhcHBlYXJzIHRvIGJlIHVubmF0dXJhbGx5IHNtb290aCwgYXMgaWYgbWVsdGVkIGF3YXkgdXNpbmcgYWNpZGljIG1lYW5zLiBJdCdzIHdhcm0gdG8gdGhlIHRvdWNoLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG5gQSBzcGhlcmljYWwgYWxjb3ZlLiBUaGUgc21vb3RoIHN1cmZhY2UgYXBwZWFycyB0byBiZSBtZWx0ZWQgYXdheSB1c2luZyBhY2lkaWMgbWVhbnMuIFRoZXJlJ3MgYSBkaW0gZ2xvdyBzaGluaW5nIGluIGZyb20gdGhlIG5vcnRoLmBcclxuKVxyXG4ud2l0aEV4aXQoXCJub3J0aFwiLCBcInR1bm5lbDFcIilcclxuLndpdGhFbnRlckNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uKGNvbnRleHQpIHtcclxuICAgIGlmIChjb250ZXh0LnN0YXRlLmdldChcInN0YXJ0LmF3b2tlblwiKSkgcmV0dXJuO1xyXG4gICAgY29uc3QgeyBvdXRwdXQsIHdhaXQgfSA9IGNvbnRleHQ7XHJcbiAgICBjb250ZXh0LmVuYWJsZUNvbW1hbmRJbnB1dChmYWxzZSk7XHJcbiAgICBhd2FpdCBjb250ZXh0LnRlbGwoW1xyXG4gICAgICAgIFwiWW91IHNsb3dseSB3YWtlIHVwLlwiLFxyXG4gICAgICAgIFwieW91J3JlIG5vdCBzdXJlIGlmIHlvdSB3ZXJlIGV2ZXIgY29uc2Npb3VzIGFib3V0IHdha2luZyB1cCwgYnV0IHJpZ2h0IG5vdywgeW91J3JlIGNsZWFybHkgYXdhcmUgdGhhdCB5b3Ugd2VyZSBwcmV2aW91c2x5IGFzbGVlcC5cIixcclxuICAgICAgICBcIkluIGZhY3QsIGEgbG90IG9mIHlvdXIgdGhvdWdodHMgc2VlbSBmb3JlaWduIHRvIHlvdS5cIixcclxuICAgICAgICBcIllvdSdyZSBub3Qgc3VyZSBob3cgdG8gZmVlbCBhYm91dCB0aGlzLlwiLFxyXG4gICAgICAgIFwiR29kIHRoZSBoZWFkYWNoZS4uLlwiLFxyXG4gICAgICAgIFwiT0ssIHRpbWUgdG8gdGhpbmsgYWJvdXQgdGhpcy5cIixcclxuICAgICAgICBcIkh1aCwgc29tZXRoaW5nIGVsc2UgeW91IG5ldmVyIGRpZCBiZWZvcmUuXCIsXHJcbiAgICAgICAgXCJXaGVyZSBhcmUgeW91P1wiLFxyXG4gICAgICAgIFwiWW91IHJlYWNoIHVwIGFuZCB0b3VjaCB5b3VyIGhlYWQuXCIsXHJcbiAgICAgICAgXCJPSywgdGhhdCBzZWVtcyB0byBiZSBpbiBvcmRlci4gWW91ciBhbnRlbm5hZSBhcmUgc3RpbGwgdGhlcmUsIHlvdXIgbW91dGggcGFydHMgc2VlbSBpbiB0YWN0Li4uXCIsXHJcbiAgICAgICAgXCJIbW0uIEFsbCB0aGlzIGlzIHN0cmFuZ2UuXCIsXHJcbiAgICAgICAgXCJObyB1c2Ugc2l0dGluZyBhcm91bmQuIFlvdSBnZXQgdXAgYW5kIHNsb3dseSBleGFtaW5lIHlvdXIgc3Vycm91bmRpbmdzLlwiXHJcbiAgICBdLCAzMDAwKTtcclxuICAgIGNvbnRleHQuZW5hYmxlQ29tbWFuZElucHV0KHRydWUpO1xyXG4gICAgY29udGV4dC5zdGF0ZS5zZXQoXCJzdGFydC5hd29rZW5cIiwgdHJ1ZSk7XHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgUm9vbUJ1aWxkZXIgZnJvbSAnLi4vLi4vLi4vZW5naW5lL2J1aWxkZXJzL3Jvb20nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IFJvb21CdWlsZGVyKClcclxuLndpdGhJRChcInR1bm5lbDFcIilcclxuLndpdGhUaXRsZShcIkEgbG9uZyBkYXJrIHR1bm5lbFwiKVxyXG4ud2l0aEZpcnN0RGVzY3JpcHRpb24oXHJcbmBZb3Ugc2xvd2x5IG1ha2UgeW91ciB3YXkgb3V0IG9mIHRoZSBsaXR0bGUgYWxjb3ZlLCBoZWFkaW5nIG5vcnRoIGludG8gYSBzbW9vdGgsIHR1YmUtc2hhcGVkIHR1bm5lbC5cclxuWW91IG5vdGljZSByYXpvciB0aGluIHRocmVhZHMgY29taW5nIG91dCBvZiB0aGUgY2VpbGluZywgd2VhdmluZyBhbmQgc2xpdGhlcmluZyBhbG9uZyB0aGUgbGVuZ3RoIG9mIHRoZSB0dW5uZWwgdG93YXJkcyB0aGUgbm9ydGguIFRoZXJ5IHByb3ZpZGUgYSBkaW0gZ2xvdywgd2hpY2ggbXVzdCBoYXZlIGJlZW4gdGhlIGxpZ2h0IHlvdSBzYXcgYmVmb3JlLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG5gQSB0dWJlLXNoYXBlZCB0dW5uZWwuIFRoaW4gdGhyZWFkcyBzZWVtIHRvIGV4aXQgdGhlIGNlaWxpbmcgaGVyZSwgZW1pbmF0aW5nIGEgc29mdCBnbG93LmBcclxuKVxyXG4ud2l0aEV4aXQoXCJzb3V0aFwiLCBcInN0YXJ0XCIpXHJcbi53aXRoRXhpdChcIm5vcnRoXCIsIFwiY2VudHJhbDFcIilcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBSb29tQnVpbGRlciBmcm9tIFwiLi4vLi4vLi4vZW5naW5lL2J1aWxkZXJzL3Jvb21cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJjZW50cmFsMVwiKVxyXG4ud2l0aFRpdGxlKFwiQSBsYXJnZSBzcGhlcmljYWwgY2hhbWJlclwiKVxyXG4ud2l0aEZpcnN0RGVzY3JpcHRpb24oXHJcbmBZb3UgZXhpdCB0aGUgdHVubmVsIGludG8gYSBsYXJnZSwgc3BoZXJpY2FsIGNoYW1iZXIuXHJcblRoZXJlIGFyZSBtYW55IG1vcmUgdGhyZWFkcyBhY3Jvc3MgdGhlIHdhbGxzIGFuZCBjZWlsaW5nIGhlcmUsIHRoZSBnbG93IGVudmVsb3BpbmcgeW91IGZ1bGx5IGluIGl0cyB1bm5hdHVyYWwgIGxpZ2h0LlxyXG5UaGUgY2hhbWJlciBhcHBlYXJzIHRvIGJlIGxhcmdlLCBhYmxlIHRvIGZpdCBodW5kcmVkcyBvZiB5b3UgaW5zaWRlLlxyXG5UbyB0aGUgbm9ydGhlYXN0LCBub3J0aHdlc3QsIHNvdXRoZWFzdCBhbmQgc291dGh3ZXN0IHlvdSBub3RpY2UgbGFyZ2Ugc3RhdHVlcyByZXByZXNlbnRpbmcgYW50cy4gVGhyZWFkcyBzZWVtIHRvIGxlYWQgcmlnaHQgaW50byB0aGVtLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG5gQSBsYXJnZSwgc3BoZXJpY2FsIGNoYW1iZXIuIEdsb3dpbmcgdGhyZWFkcyBjcmlzcy1jcm9zcyB0aGUgd2FsbHMgYW5kIGNlaWxpbmcuIEFyb3VuZCB5b3UsIHN0YXR1ZXMgb2YgYW50cy5gXHJcbilcclxuLndpdGhFeGl0KFwibm9ydGh3ZXN0XCIsIFwic3RhdHVlMVwiKVxyXG4ud2l0aEV4aXQoXCJub3J0aGVhc3RcIiwgXCJzdGF0dWUyXCIpXHJcbi53aXRoRXhpdChcInNvdXRod2VzdFwiLCBcInN0YXR1ZTNcIilcclxuLndpdGhFeGl0KFwic291dGhlYXN0XCIsIFwic3RhdHVlNFwiKVxyXG4ud2l0aEV4aXQoXCJzb3V0aFwiLCBcInR1bm5lbDFcIilcclxuLmNyZWF0ZSgpOyIsImltcG9ydCBSb29tQnVpbGRlciBmcm9tIFwiLi4vLi4vLi4vZW5naW5lL2J1aWxkZXJzL3Jvb21cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBSb29tQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGF0dWUxXCIpXHJcbi53aXRoVGl0bGUoXCJUaGUgbm9ydGh3ZXN0ZXJuIHBhcnQgb2YgdGhlIGNlbnRyYWwgY2hhbWJlclwiKVxyXG4ud2l0aEZpcnN0RGVzY3JpcHRpb24oXHJcbiAgICBgWW91IHdhbGsgb3ZlciB0byB0aGUgbm9ydGh3ZXN0ZXJuIHBhcnQgb2YgdGhlIGNlbnRyYWwgY2hhbWJlci5cclxuICAgIEl0IGlzIGFsbW9zdCBlbnRpcmVseSB0YWtlbiB1cCBieSBhIGh1Z2UgYW50IHN0YXR1ZS4gT25lIG9mIGl0cyBzaXggbGVncyBhcmUgZXh0ZW5kZWQgb3V0d2FyZHMsIGF0dGFjaGVkIHRvIHdoaWNoIGlzIGEgc21hbGwsIHJvdW5kIGRldmljZS5gXHJcbilcclxuLndpdGhEZXNjcmlwdGlvbihcclxuICAgIGBgXHJcbilcclxuLndpdGhFeGl0KFwic291dGhlYXN0XCIsIFwiY2VudHJhbDFcIilcclxuLndpdGhJdGVtKFwic3RhdHVlMVwiKVxyXG4uY3JlYXRlKCk7IiwiaW1wb3J0IFJvb21CdWlsZGVyIGZyb20gXCIuLi8uLi8uLi9lbmdpbmUvYnVpbGRlcnMvcm9vbVwiO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IFJvb21CdWlsZGVyKClcclxuLndpdGhJRChcInN0YXR1ZTJcIilcclxuLndpdGhUaXRsZShcIlRoZSBub3J0aGVhc3Rlcm4gcGFydCBvZiB0aGUgY2VudHJhbCBjaGFtYmVyXCIpXHJcbi53aXRoRmlyc3REZXNjcmlwdGlvbihcclxuICAgIGBZb3Ugd2FsayBvdmVyIHRvIHRoZSBub3J0aGVhc3Rlcm4gcGFydCBvZiB0aGUgY2VudHJhbCBjaGFtYmVyLlxyXG4gICAgSXQgaXMgYWxtb3N0IGVudGlyZWx5IHRha2VuIHVwIGJ5IGEgaHVnZSBhbnQgc3RhdHVlLiBUd28gb2YgaXRzIHNpeCBsZWdzIGFyZSBleHRlbmRlZCBvdXR3YXJkcywgYXR0YWNoZWQgdG8gd2hpY2ggaXMgYSBsYXJnZSwgcmVjdGFuZ3VsYXIgZGV2aWNlLmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG4gICAgYGBcclxuKVxyXG4ud2l0aEV4aXQoXCJzb3V0aHdlc3RcIiwgXCJjZW50cmFsMVwiKVxyXG4ud2l0aEl0ZW0oXCJzdGF0dWUyXCIpXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgUm9vbUJ1aWxkZXIgZnJvbSBcIi4uLy4uLy4uL2VuZ2luZS9idWlsZGVycy9yb29tXCI7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBuZXcgUm9vbUJ1aWxkZXIoKVxyXG4ud2l0aElEKFwic3RhdHVlM1wiKVxyXG4ud2l0aFRpdGxlKFwiVGhlIHNvdXRod2VzdGVybiBwYXJ0IG9mIHRoZSBjZW50cmFsIGNoYW1iZXJcIilcclxuLndpdGhGaXJzdERlc2NyaXB0aW9uKFxyXG4gICAgYFlvdSB3YWxrIG92ZXIgdG8gdGhlIHNvdXRod2VzdGVybiBwYXJ0IG9mIHRoZSBjZW50cmFsIGNoYW1iZXIuXHJcbiAgICBJdCBpcyBhbG1vc3QgZW50aXJlbHkgdGFrZW4gdXAgYnkgYSBodWdlIGFudCBzdGF0dWUuIFRocmVlIG9mIGl0cyBzaXggbGVncyBhcmUgZXh0ZW5kZWQgb3V0d2FyZHMsIGF0dGFjaGVkIHRvIHdoaWNoIGlzIGEgcm91bmQgc3RvbmUgdGFibGV0LmBcclxuKVxyXG4ud2l0aERlc2NyaXB0aW9uKFxyXG4gICAgYGBcclxuKVxyXG4ud2l0aEV4aXQoXCJub3J0aGVhc3RcIiwgXCJjZW50cmFsMVwiKVxyXG4ud2l0aEl0ZW0oXCJzdGF0dWUzXCIpXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgU3RhdGUgZnJvbSBcIi4vc3RhdGVcIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEl0ZW0ge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5pZCA9IFwiaXRlbVwiO1xyXG4gICAgICAgIHRoaXMubmFtZSA9IFwiQW4gaXRlbVwiO1xyXG4gICAgICAgIHRoaXMuZGVzY3JpcHRpb24gPSBcIllvdSBzZWUgbm90aGluZyBzcGVjaWFsIGFib3V0IHRoaXMgaXRlbVwiO1xyXG4gICAgICAgIHRoaXMudHlwZSA9IFwiaXRlbVwiO1xyXG4gICAgICAgIHRoaXMuc3RhdGUgPSBuZXcgU3RhdGUoKTtcclxuICAgICAgICB0aGlzLnVzYWJsZSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy50YWtlYWJsZSA9IHRydWU7XHJcbiAgICAgICAgdGhpcy51c2VDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy50YWtlQ2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICAgIHRoaXMuZHJvcENhbGxiYWNrID0gbnVsbDtcclxuICAgICAgICB0aGlzLnRpY2tDYWxsYmFjayA9IG51bGw7XHJcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvblVzZSgpIHtcclxuICAgICAgICBpZiAodGhpcy51c2VDYWxsYmFjaykgcmV0dXJuIHRoaXMudXNlQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvblRha2UoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMudGFrZUNhbGxiYWNrKSByZXR1cm4gdGhpcy50YWtlQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuXHJcbiAgICBhc3luYyBvbkRyb3AoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuZHJvcENhbGxiYWNrKSByZXR1cm4gdGhpcy5kcm9wQ2FsbGJhY2sodGhpcy5jb250ZXh0KTtcclxuICAgIH1cclxuICAgIGFzeW5jIG9uVGljaygpIHtcclxuICAgICAgICBpZiAodGhpcy50aWNrQ2FsbGJhY2spIHJldHVybiB0aGlzLnRpY2tDYWxsYmFjayh0aGlzLmNvbnRleHQpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZFVzZUNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy51c2VDYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgYWRkVGFrZUNhbGxiYWNrKGNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy50YWtlQ2FsbGJhY2sgPSBjYWxsYmFjay5iaW5kKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZERyb3BDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuZHJvcENhbGxiYWNrID0gY2FsbGJhY2suYmluZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBhZGRUaWNrQ2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLnRpY2tDYWxsYmFjayA9IGNhbGxiYWNrLmJpbmQodGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0U3RhdGUoa2V5LCB2YWx1ZSkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnN0YXRlLnNldChrZXksIHZhbHVlKTtcclxuICAgIH1cclxuXHJcbiAgICBnZXRTdGF0ZShrZXkpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5nZXQoa2V5KTtcclxuICAgIH1cclxufSIsImltcG9ydCBJdGVtIGZyb20gJy4uL2l0ZW0nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSXRlbUJ1aWxkZXIge1xyXG4gICAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtID0gbmV3IEl0ZW0oKTtcclxuICAgIH1cclxuXHJcbiAgICB3aXRoSUQoSUQpIHtcclxuICAgICAgICB0aGlzLml0ZW0uaWQgPSBJRDtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuXHJcbiAgICB3aXRoTmFtZShuYW1lKSB7XHJcbiAgICAgICAgdGhpcy5pdGVtLm5hbWUgPSBuYW1lO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhEZXNjcmlwdGlvbihkZXNjcmlwdGlvbikge1xyXG4gICAgICAgIHRoaXMuaXRlbS5kZXNjcmlwdGlvbiA9IGRlc2NyaXB0aW9uO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhUeXBlKHR5cGUpIHtcclxuICAgICAgICB0aGlzLml0ZW0udHlwZSA9IHR5cGU7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aFN0YXRlKGtleSwgdmFsdWUpIHtcclxuICAgICAgICB0aGlzLml0ZW0uc2V0U3RhdGUoa2V5LCB2YWx1ZSk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgaXNVc2FibGUodmFsdWUpIHtcclxuICAgICAgICB0aGlzLml0ZW0udXNhYmxlID0gdmFsdWU7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgaXNUYWtlYWJsZSh2YWx1ZSkge1xyXG4gICAgICAgIHRoaXMuaXRlbS50YWtlYWJsZSA9IHZhbHVlO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhVc2VDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuaXRlbS5hZGRVc2VDYWxsYmFjayhjYWxsYmFjayk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgd2l0aFRha2VDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuaXRlbS5hZGRUYWtlQ2FsbGJhY2soY2FsbGJhY2spO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHdpdGhEcm9wQ2FsbGJhY2soY2FsbGJhY2spIHtcclxuICAgICAgICB0aGlzLml0ZW0uYWRkRHJvcENhbGxiYWNrKGNhbGxiYWNrKTtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgIH1cclxuICAgIFxyXG4gICAgd2l0aFRpY2tDYWxsYmFjayhjYWxsYmFjaykge1xyXG4gICAgICAgIHRoaXMuaXRlbS5hZGRUaWNrQ2FsbGJhY2soY2FsbGJhY2spO1xyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIGNyZWF0ZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5pdGVtO1xyXG4gICAgfVxyXG59IiwiaW1wb3J0IEl0ZW1CdWlsZGVyIGZyb20gJy4uLy4uL2VuZ2luZS9idWlsZGVycy9pdGVtJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBJdGVtQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGF0dWU0XCIpXHJcbi53aXRoTmFtZShcImEgaHVnZSBhbnQgc3RhdHVlXCIpXHJcbi53aXRoRGVzY3JpcHRpb24oXHJcbiAgICBgQmVmb3JlIHlvdSBpcyBhIGJpZyBzdGF0dWUgb2YgYW4gYW50LCBpbiB0aGUgcHJvY2VzcyBvZiBmYWxsaW5nIG92ZXIuIEFsbCBvZiBpdHMgbGVncyBhcmUgYmVudCBhdCB0aGUgam9pbnRzLmBcclxuKVxyXG4uaXNUYWtlYWJsZShmYWxzZSlcclxuLmlzVXNhYmxlKHRydWUpXHJcbi53aXRoVXNlQ2FsbGJhY2soYXN5bmMgZnVuY3Rpb24gKGNvbnRleHQpIHtcclxuICAgIGNvbnRleHQucHJpbnQoYFlvdSBjYW4ndCBzZWVtIHRvIGZpZ3VyZSBvdXQgd2hhdCB0byBkbyB3aXRoIHRoaXMgeWV0LmApXHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgTGFpciBmcm9tICcuL2xhaXInO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgW1xyXG4gICAgLi4uTGFpclxyXG5dOyIsImltcG9ydCBTdGFydCBmcm9tICcuL3N0YXJ0JztcclxuaW1wb3J0IFR1bm5lbDEgZnJvbSAnLi90dW5uZWwxJztcclxuaW1wb3J0IGNlbnRyYWwxIGZyb20gJy4vY2VudHJhbDEnO1xyXG5pbXBvcnQgc3RhdHVlMSBmcm9tICcuL3N0YXR1ZTEnO1xyXG5pbXBvcnQgc3RhdHVlMiBmcm9tICcuL3N0YXR1ZTInO1xyXG5pbXBvcnQgc3RhdHVlMyBmcm9tICcuL3N0YXR1ZTMnO1xyXG5pbXBvcnQgc3RhdHVlNCBmcm9tICcuLi8uLi9pdGVtcy9zdGF0dWU0JztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IFtcclxuICAgIFN0YXJ0LFxyXG4gICAgVHVubmVsMSxcclxuICAgIGNlbnRyYWwxLFxyXG4gICAgc3RhdHVlMSxcclxuICAgIHN0YXR1ZTIsXHJcbiAgICBzdGF0dWUzLFxyXG4gICAgc3RhdHVlNFxyXG5dOyIsImltcG9ydCBTdG9uZSBmcm9tICcuL3N0b25lJztcclxuaW1wb3J0IFRvcmNoIGZyb20gJy4vdG9yY2gnO1xyXG5pbXBvcnQgQ3VwIGZyb20gJy4vY3VwJztcclxuaW1wb3J0IFN0YXR1ZTEgZnJvbSAnLi9zdGF0dWUxJztcclxuaW1wb3J0IHN0YXR1ZTIgZnJvbSAnLi9zdGF0dWUyJztcclxuaW1wb3J0IHN0YXR1ZTMgZnJvbSAnLi9zdGF0dWUzJztcclxuaW1wb3J0IHN0YXR1ZTQgZnJvbSAnLi9zdGF0dWU0JztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IFtcclxuICAgIFN0b25lLFxyXG4gICAgVG9yY2gsXHJcbiAgICBDdXAsXHJcbiAgICBTdGF0dWUxLFxyXG4gICAgc3RhdHVlMixcclxuICAgIHN0YXR1ZTMsXHJcbiAgICBzdGF0dWU0XHJcbl0iLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSBcIi4uLy4uL2VuZ2luZS9idWlsZGVycy9pdGVtXCI7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBuZXcgSXRlbUJ1aWxkZXIoKVxyXG4ud2l0aElEKFwic3RvbmVcIilcclxuLndpdGhOYW1lKFwiYSBkdWxsIHN0b25lXCIpXHJcbi53aXRoRGVzY3JpcHRpb24oXCJUaGVyZSBpcyBub3RoaW5nIHJlbWFya2FibGUgYWJvdXQgdGhpcyByb3VnaCwgYmxhbmQgc3RvbmUuXCIpXHJcbi5pc1Rha2VhYmxlKHRydWUpXHJcbi5pc1VzYWJsZSh0cnVlKVxyXG4ud2l0aFRha2VDYWxsYmFjayhhc3luYyBmdW5jdGlvbihjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBUaGUgJHt0aGlzLmlkfSBmZWVscyBoZWF2eSBpbiB5b3VyIGhhbmRzLmApO1xyXG59KVxyXG4ud2l0aERyb3BDYWxsYmFjayhhc3luYyBmdW5jdGlvbihjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBJdCBib3VuY2VzIGJhY2sgYW5kIGZvcnRoIGEgbGl0dGxlLmApXHJcbn0pXHJcbi53aXRoVXNlQ2FsbGJhY2soYXN5bmMgZnVuY3Rpb24oY29udGV4dCkge1xyXG4gICAgY29udGV4dC5wcmludChgWW91IGNhbid0IHJlYWxseSBmaWd1cmUgb3V0IHdoYXQgdG8gZG8gd2l0aCAke3RoaXMubmFtZX0geWV0YCk7XHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSBcIi4uLy4uL2VuZ2luZS9idWlsZGVycy9pdGVtXCI7XHJcblxyXG5leHBvcnQgZGVmYXVsdCBuZXcgSXRlbUJ1aWxkZXIoKVxyXG4ud2l0aElEKFwidG9yY2hcIilcclxuLndpdGhOYW1lKFwiYSB0b3JjaFwiKVxyXG4ud2l0aERlc2NyaXB0aW9uKFwiQSBzdGFuZGFyZCB0b3JjaCB0aGF0IHByb3ZpZGVzIGxpZ2h0LlwiKVxyXG4uaXNVc2FibGUodHJ1ZSlcclxuLmlzVGFrZWFibGUodHJ1ZSlcclxuLndpdGhVc2VDYWxsYmFjayhhc3luYyBmdW5jdGlvbihjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgdHJ5IHRvIGxpZ2h0IHRoZSB0b3JjaCBidXQgZmFpbC5gKVxyXG59KVxyXG4uY3JlYXRlKCk7IiwiaW1wb3J0IEl0ZW1CdWlsZGVyIGZyb20gXCIuLi8uLi9lbmdpbmUvYnVpbGRlcnMvaXRlbVwiO1xyXG5pbXBvcnQgSXRlbSBmcm9tIFwiLi4vLi4vZW5naW5lL2l0ZW1cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBJdGVtQnVpbGRlcigpXHJcbi53aXRoSUQoXCJjdXBcIilcclxuLndpdGhOYW1lKFwiYSBjdXBcIilcclxuLndpdGhEZXNjcmlwdGlvbihcIkEgc3RhbmRhcmQgY29mZmVlIGN1cFwiKVxyXG4uaXNUYWtlYWJsZSh0cnVlKVxyXG4uaXNVc2FibGUoZmFsc2UpXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSAnLi4vLi4vZW5naW5lL2J1aWxkZXJzL2l0ZW0nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IEl0ZW1CdWlsZGVyKClcclxuLndpdGhJRChcInN0YXR1ZTFcIilcclxuLndpdGhOYW1lKFwiYSBodWdlIGFudCBzdGF0dWVcIilcclxuLndpdGhEZXNjcmlwdGlvbihcclxuICAgIGBCZWZvcmUgeW91IHN0YW5kcyBhIGJpZyBhbnQgc3RhdHVlLiBPbmUgb2YgaXRzIHNpeCBsZWdzIGlzIGV4dGVuZGVkIG91dHdhcmRzLCBhdHRhY2hlZCB0byBhIHJvdW5kIGRldmljZS5gXHJcbilcclxuLmlzVGFrZWFibGUoZmFsc2UpXHJcbi5pc1VzYWJsZSh0cnVlKVxyXG4ud2l0aFVzZUNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uIChjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgcHJlc3MgdGhlIGJ1dHRvbiBvbiB0aGUgcm91bmQgZGV2aWNlIGF0dGFjaGVkIHRvIHRoZSBzdGF0dWUncyBhcm0uYCk7XHJcbiAgICBsZXQgdmFsdWUgPSBjb250ZXh0LnN0YXRlLmdldChcInN0YXR1ZTEucHJlc3NlZFwiLCAwKTtcclxuICAgIHZhbHVlKys7XHJcbiAgICBjb250ZXh0LnN0YXRlLnNldChcInN0YXR1ZTEucHJlc3NlZFwiLCB2YWx1ZSk7XHJcbiAgICBpZiAodmFsdWUgID09IDMpIHtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBZb3UgaGVhciBhIHNhdHRpc2Z5aW5nIGNsaWNrLmApO1xyXG4gICAgICAgIGNvbnRleHQuc3RhdGUuc2V0KFwic3RhdHVlcy51bmxvY2tlZFwiLCB0cnVlKTtcclxuICAgIH1cclxuICAgIGlmIChjb250ZXh0LnN0YXRlLmdldCgnc3RhdHVlMS5wcmVzc2VkJykgPiAyICYmIGNvbnRleHQuc3RhdGUuZ2V0KCdzdGF0dWUyLnByZXNzZWQnKSA+IDEpIHtcclxuICAgICAgICBjb250ZXh0LnByaW50KGBZb3UgaGVhciBhIGxvdyBydW1ibGUgc29tZXdoZXJlIGRlZXAgd2l0aGluIHRoZSBib3dlbHMgb2YgdGhlIHN0cnVjdHVyZS5gKTtcclxuICAgICAgICBjb250ZXh0LnN0YXRlLnNldChcInN0YXR1ZXMudW5sb2NrZWRcIiwgdHJ1ZSk7XHJcbiAgICB9XHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJpbXBvcnQgSXRlbUJ1aWxkZXIgZnJvbSAnLi4vLi4vZW5naW5lL2J1aWxkZXJzL2l0ZW0nO1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgbmV3IEl0ZW1CdWlsZGVyKClcclxuLndpdGhJRChcInN0YXR1ZTJcIilcclxuLndpdGhOYW1lKFwiYSBodWdlIGFudCBzdGF0dWVcIilcclxuLndpdGhEZXNjcmlwdGlvbihcclxuICAgIGBCZWZvcmUgeW91IHN0YW5kcyBhIGJpZyBhbnQgc3RhdHVlLiBUd28gb2YgaXRzIHNpeCBsZWdzIGlzIGV4dGVuZGVkIG91dHdhcmRzLCBhdHRhY2hlZCB0byBhIHJlY3Rhbmd1bGFyIGRldmljZS5gXHJcbilcclxuLmlzVGFrZWFibGUoZmFsc2UpXHJcbi5pc1VzYWJsZSh0cnVlKVxyXG4ud2l0aFVzZUNhbGxiYWNrKGFzeW5jIGZ1bmN0aW9uIChjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgcHJlc3MgdGhlIGJ1dHRvbiBvbiB0aGUgcmVjdGFuZ3VsYXIgZGV2aWNlIGF0dGFjaGVkIHRvIHRoZSBzdGF0dWUncyBhcm0uYCk7XHJcbiAgICBsZXQgdmFsdWUgPSBjb250ZXh0LnN0YXRlLmdldChcInN0YXR1ZTIucHJlc3NlZFwiLCAwKTtcclxuICAgIHZhbHVlKys7XHJcbiAgICBjb250ZXh0LnN0YXRlLnNldChcInN0YXR1ZTIucHJlc3NlZFwiLCB2YWx1ZSk7XHJcbiAgICBpZiAodmFsdWUgPT0gMikge1xyXG4gICAgICAgIGNvbnRleHQucHJpbnQoYFlvdSBoZWFyIGEgc2F0dGlzZnlpbmcgY2xpY2suYCk7XHJcbiAgICB9XHJcbiAgICBpZiAoY29udGV4dC5zdGF0ZS5nZXQoJ3N0YXR1ZTEucHJlc3NlZCcpID4gMiAmJiBjb250ZXh0LnN0YXRlLmdldCgnc3RhdHVlMi5wcmVzc2VkJykgPiAxKSB7XHJcbiAgICAgICAgY29udGV4dC5wcmludChgWW91IGhlYXIgYSBsb3cgcnVtYmxlIHNvbWV3aGVyZSBkZWVwIHdpdGhpbiB0aGUgYm93ZWxzIG9mIHRoZSBzdHJ1Y3R1cmUuYCk7XHJcbiAgICAgICAgY29udGV4dC5zdGF0ZS5zZXQoXCJzdGF0dWVzLnVubG9ja2VkXCIsIHRydWUpO1xyXG4gICAgfVxyXG59KVxyXG4uY3JlYXRlKCk7IiwiaW1wb3J0IEl0ZW1CdWlsZGVyIGZyb20gJy4uLy4uL2VuZ2luZS9idWlsZGVycy9pdGVtJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IG5ldyBJdGVtQnVpbGRlcigpXHJcbi53aXRoSUQoXCJzdGF0dWUzXCIpXHJcbi53aXRoTmFtZShcImEgaHVnZSBhbnQgc3RhdHVlXCIpXHJcbi53aXRoRGVzY3JpcHRpb24oXHJcbiAgICBgQmVmb3JlIHlvdSBzdGFuZHMgYSBiaWcgYW50IHN0YXR1ZS4gVGhyZWUgb2YgaXRzIHNpeCBsZWdzIGFyZSBleHRlbmRlZCBvdXR3YXJkcywgYXR0YWNoZWQgdG8gYSByb3VuZCBzdG9uZSB0YWJsZXQuYFxyXG4pXHJcbi5pc1Rha2VhYmxlKGZhbHNlKVxyXG4uaXNVc2FibGUodHJ1ZSlcclxuLndpdGhVc2VDYWxsYmFjayhhc3luYyBmdW5jdGlvbiAoY29udGV4dCkge1xyXG4gICAgY29udGV4dC5wcmludChgWW91IGV4YW1pbmUgdGhlIHN0b25lIHRhYmxldCBpbiB0aGUgc3RhdHVlJ3MgaGFuZHMuIFRoZXJlIGFwcGVhciB0byBiZSBzeW1ib2xzIG9uIGl0IHdoaWNoIHlvdSBjYW4gbWFrZSBvdXQuYCk7XHJcbn0pXHJcbi5jcmVhdGUoKTsiLCJleHBvcnQgZGVmYXVsdCBhc3luYyBmdW5jdGlvbiBNZW93Q29tbWFuZChhcmdzLCBjb250ZXh0KSB7XHJcbiAgICBjb250ZXh0LnByaW50KGBZb3UgbWVvdy5gKTtcclxufSIsImltcG9ydCBHYW1lIGZyb20gJy4uL2VuZ2luZSc7XHJcbmltcG9ydCBSb29tcyBmcm9tICcuL3Jvb21zJztcclxuaW1wb3J0IEl0ZW1zIGZyb20gJy4vaXRlbXMnO1xyXG5pbXBvcnQgTWVvd0NvbW1hbmQgZnJvbSAnLi9jb21tYW5kcy9tZW93JztcclxuXHJcbmlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbShcInNhdmVcIikpIHtcclxuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwic2F2ZS1nYW1lLWZvdW5kXCIpLmhpZGRlbiA9IGZhbHNlO1xyXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJiZWZvcmUtcGxheVwiKS5oaWRkZW4gPSB0cnVlO1xyXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJsb2FkLXNhdmUtZ2FtZVwiKS5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgKCkgPT4ge1xyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwic2F2ZS1nYW1lLWZvdW5kXCIpLmhpZGRlbiA9IHRydWU7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJwbGF5LWFyZWFcIikuaGlkZGVuID0gZmFsc2U7XHJcbiAgICAgICAgc3RhcnRHYW1lKGZhbHNlKTtcclxuICAgIH0pXHJcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInN0YXJ0LW5ldy1nYW1lXCIpLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCAoKSA9PiB7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJzYXZlLWdhbWUtZm91bmRcIikuaGlkZGVuID0gdHJ1ZTtcclxuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInBsYXktYXJlYVwiKS5oaWRkZW4gPSBmYWxzZTtcclxuICAgICAgICBzdGFydEdhbWUodHJ1ZSk7XHJcbiAgICB9KVxyXG59XHJcblxyXG5kb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImJlZ2luXCIpLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCAoKSA9PiB7XHJcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImJlZm9yZS1wbGF5XCIpLmhpZGRlbiA9IHRydWU7XHJcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInBsYXktYXJlYVwiKS5oaWRkZW4gPSBmYWxzZTtcclxuICAgIHN0YXJ0R2FtZSh0cnVlKTtcclxufSlcclxuXHJcbmZ1bmN0aW9uIHN0YXJ0R2FtZShuZXdHYW1lKSB7XHJcbiAgICBjb25zdCBnYW1lID0gbmV3IEdhbWUobmV3R2FtZSk7XHJcblxyXG4gICAgZ2FtZS5pbml0KHtcclxuICAgICAgICByb29tczogUm9vbXMsXHJcbiAgICAgICAgY29tbWFuZHM6IFtcclxuICAgICAgICAgICAgW1tcIm1lb3dcIiwgXCJtZXdcIl0sIE1lb3dDb21tYW5kXVxyXG4gICAgICAgIF0sXHJcbiAgICAgICAgaXRlbXM6IEl0ZW1zXHJcbiAgICB9KTtcclxufVxyXG4iXSwibmFtZXMiOlsiU3RhdGUiLCJjb25zdHJ1Y3RvciIsInRoaXMiLCJzdGF0ZXMiLCJNYXAiLCJnZXQiLCJrZXkiLCJkZWZhdWx0VmFsdWUiLCJoYXMiLCJzZXQiLCJ2YWx1ZSIsImNoYW5nZSIsImFtb3VudCIsInZhbCIsInNlcmlhbGl6ZSIsImVudHJpZXMiLCJlbnRyeW1hcCIsInN0YXRlIiwicHVzaCIsImRlc2VyaWFsaXplIiwiZGF0YSIsIlBsYXllciIsImludmVudG9yeSIsImN1cnJlbnRSb29tIiwiY29udGV4dCIsImFkZEl0ZW0iLCJpZCIsInJlbW92ZUl0ZW0iLCJmaWx0ZXIiLCJpdGVtIiwiZ2V0SW52ZW50b3J5IiwibWFwIiwiZ2V0SXRlbSIsIkJhc2VPdXRwdXQiLCJzcGVhayIsInRleHQiLCJzdG9wIiwic2V0T3B0aW9ucyIsIm9wdGlvbnMiLCJBcmlhT3V0cHV0Iiwic3VwZXIiLCJ0aW1lb3V0IiwiaW5pdCIsImNvbnRhaW5lciIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsInNldEF0dHJpYnV0ZSIsInNwZWVjaERpc3BsYXkiLCJhcHBlbmQiLCJib2R5IiwiYXBwZW5kQ2hpbGQiLCJpbnNlcnRCZWZvcmUiLCJmaXJzdENoaWxkIiwiY2xlYXJEaXNwbGF5Iiwibm9kZSIsImNyZWF0ZVRleHROb2RlIiwicGFyYSIsInNldFRpbWVvdXQiLCJiaW5kIiwiaW5uZXJIVE1MIiwiV2ViVFRTT3V0cHV0IiwicmF0ZSIsInN5bnRoIiwid2luZG93Iiwic3BlZWNoU3ludGhlc2lzIiwidXR0ZXJUaGlzIiwiU3BlZWNoU3ludGhlc2lzVXR0ZXJhbmNlIiwiY2FuY2VsIiwiVFRTIiwib3V0cHV0IiwiY3JlYXRlT3V0cHV0IiwiX19hd2FpdGVyIiwidGhpc0FyZyIsIl9hcmd1bWVudHMiLCJQIiwiZ2VuZXJhdG9yIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJmdWxmaWxsZWQiLCJzdGVwIiwibmV4dCIsImUiLCJyZWplY3RlZCIsInJlc3VsdCIsImRvbmUiLCJ0aGVuIiwiYXBwbHkiLCJSZXNvbmF0b3JBdWRpb0NvbnRleHQiLCJBdWRpb0NvbnRleHQiLCJnZXRDb250ZXh0IiwiY3JlYXRlR2FpbiIsImdldE91dHB1dERlc3RpbmF0aW9uIiwiZGVzdGluYXRpb24iLCJjcmVhdGVCdWZmZXJTb3VyY2UiLCJkZWNvZGVBdWRpb0RhdGEiLCJjcmVhdGVQYW5uZXIiLCJjcmVhdGVNZWRpYUVsZW1lbnRTb3VyY2UiLCJlbGVtZW50IiwiRXZlbnRCdXMiLCJldmVudHMiLCJlbWl0IiwiZXYiLCJzdWJzY3JpYmVycyIsImZvckVhY2giLCJzdWJzY3JpYmVyIiwiRXZlbnRJdGVtIiwic3Vic2NyaWJlIiwidW5zdWJzY3JpYmUiLCJmbiIsImxlbmd0aCIsImRlbGV0ZSIsInVuc3Vic2NyaWJlQWxsIiwidmVjNCIsInZhbHVlcyIsIkZsb2F0MzJBcnJheSIsInVuZGVmaW5lZCIsInh5enciLCJ4IiwieSIsInoiLCJ3IiwieHkiLCJ4eXoiLCJyIiwiZyIsImIiLCJhIiwicmciLCJyZ2IiLCJyZ2JhIiwiYXQiLCJpbmRleCIsInJlc2V0IiwiY29weSIsImRlc3QiLCJuZWdhdGUiLCJlcXVhbHMiLCJ2ZWN0b3IiLCJ0aHJlc2hvbGQiLCJlcHNpbG9uIiwiTWF0aCIsImFicyIsInNxcnQiLCJzcXVhcmVkTGVuZ3RoIiwiYWRkIiwic3VidHJhY3QiLCJtdWx0aXBseSIsImRpdmlkZSIsInNjYWxlIiwibm9ybWFsaXplIiwibXVsdGlwbHlNYXQ0IiwibWF0cml4IiwibXVsdGlwbHlWZWM0Iiwic3RhdGljIiwidmVjdG9yMiIsInRpbWUiLCJ6ZXJvIiwib25lIiwibWF0NCIsImkiLCJhbGwiLCJyb3ciLCJjb2wiLCJkZXRlcm1pbmFudCIsImEwMCIsImEwMSIsImEwMiIsImEwMyIsImExMCIsImExMSIsImExMiIsImExMyIsImEyMCIsImEyMSIsImEyMiIsImEyMyIsImEzMCIsImEzMSIsImEzMiIsImEzMyIsInNldElkZW50aXR5IiwidHJhbnNwb3NlIiwidGVtcDAxIiwidGVtcDAyIiwidGVtcDAzIiwidGVtcDEyIiwidGVtcDEzIiwidGVtcDIzIiwiaW52ZXJzZSIsImRldDAwIiwiZGV0MDEiLCJkZXQwMiIsImRldDAzIiwiZGV0MDQiLCJkZXQwNSIsImRldDA2IiwiZGV0MDciLCJkZXQwOCIsImRldDA5IiwiZGV0MTAiLCJkZXQxMSIsImRldCIsImIwIiwiYjEiLCJiMiIsImIzIiwibXVsdGlwbHlWZWMzIiwidmVjMyIsInRvTWF0MyIsIm1hdDMiLCJ0b0ludmVyc2VNYXQzIiwiZGV0MjEiLCJ0cmFuc2xhdGUiLCJyb3RhdGUiLCJhbmdsZSIsImF4aXMiLCJzIiwic2luIiwiYyIsImNvcyIsInQiLCJiMDAiLCJiMDEiLCJiMDIiLCJiMTAiLCJiMTEiLCJiMTIiLCJiMjAiLCJiMjEiLCJiMjIiLCJsZWZ0IiwicmlnaHQiLCJib3R0b20iLCJ0b3AiLCJuZWFyIiwiZmFyIiwicmwiLCJ0YiIsImZvdiIsImFzcGVjdCIsInRhbiIsIlBJIiwiZnJ1c3R1bSIsInBvc2l0aW9uIiwidGFyZ2V0IiwidXAiLCJpZGVudGl0eSIsImRpZmZlcmVuY2UiLCJjcm9zcyIsImRvdCIsIm0xIiwibTIiLCJiMDMiLCJiMTMiLCJiMjMiLCJiMzAiLCJiMzEiLCJiMzIiLCJiMzMiLCJ2ZWMyIiwibXVsdGlwbHlNYXQyIiwibXVsdGlwbHlWZWMyIiwibXVsdGlwbHlNYXQzIiwieDIiLCJzcXVhcmVkRGlzdGFuY2UiLCJ5MiIsInRvTWF0NCIsInRvUXVhdCIsIm0wMCIsIm0wMSIsIm0wMiIsIm0xMCIsIm0xMSIsIm0xMiIsIm0yMCIsIm0yMSIsIm0yMiIsImZvdXJYU3F1YXJlZE1pbnVzMSIsImZvdXJZU3F1YXJlZE1pbnVzMSIsImZvdXJaU3F1YXJlZE1pbnVzMSIsImJpZ2dlc3RJbmRleCIsImZvdXJCaWdnZXN0U3F1YXJlZE1pbnVzMSIsImJpZ2dlc3RWYWwiLCJtdWx0IiwicXVhdCIsInJvbGwiLCJhdGFuMiIsInBpdGNoIiwieWF3IiwiYXNpbiIsImNhbGN1bGF0ZVciLCJpbnZEb3QiLCJjb25qdWdhdGUiLCJvdGhlciIsInExeCIsInExeSIsInExeiIsInExdyIsInEyeCIsInEyeSIsInEyeiIsInEydyIsInF4IiwicXkiLCJxeiIsInF3IiwiaXgiLCJpeSIsIml6IiwiaXciLCJ6MiIsInh4IiwieHoiLCJ5eSIsInl6IiwienoiLCJ3eCIsInd5Iiwid3oiLCJxMSIsInEyIiwicTJhIiwiazAiLCJrMSIsIm9uZU92ZXJTaW4iLCJjb3NIYWxmVGhldGEiLCJoYWxmVGhldGEiLCJhY29zIiwic2luSGFsZlRoZXRhIiwicmF0aW9BIiwicmF0aW9CIiwidSIsInYiLCJkIiwiY2xhbXAiLCJyYWRpYW5zIiwibF9hbmdsZSIsImxfc2luIiwibF9jb3MiLCJtdWx0aXBseUJ5TWF0MyIsIm11bHRpcGx5QnlRdWF0IiwicXVhdGVybmlvbiIsInJvdGF0aW9uIiwiZm9yd2FyZCIsIlJlc29uYXRvclNjZW5lIiwic2NlbmUiLCJsaXN0ZW5lciIsImNyZWF0ZVNvdXJjZSIsInBhbm5pbmdNb2RlbCIsImRpc3RhbmNlTW9kZWwiLCJtYXhEaXN0YW5jZSIsInJlZkRpc3RhbmNlIiwiY29ubmVjdCIsImdldE91dHB1dCIsImdldElucHV0Iiwic2V0TGlzdGVuZXJQb3NpdGlvbiIsInNldFBvc2l0aW9uIiwic2V0TGlzdGVuZXJPcmllbnRhdGlvbiIsInJhd3VwIiwiZndkIiwic2V0T3JpZW50YXRpb24iLCJFZmZlY3RDaGFpbiIsImdyYXBoIiwiaW5wdXQiLCJlZmZlY3RzIiwiaW5wdXROb2RlIiwib3V0cHV0Tm9kZSIsInVwZGF0ZUNvbm5lY3Rpb25zIiwiYXBwbHlFZmZlY3QiLCJlZmZlY3QiLCJyZW1vdmVFZmZlY3QiLCJjdXJyRWZmZWN0IiwiZGlzY29ubmVjdCIsImN1cnJlbnQiLCJwcmV2aW91cyIsImNvbm5lY3RJbnB1dCIsImNvbm5lY3RPdXRwdXQiLCJBdWRpb0dyYXBoIiwic3dhcENoYW5uZWxzIiwiZWZmZWN0c0J1cyIsIndvcmxkQnVzIiwic2Vjb25kYXJ5QnVzIiwibWFzdGVyIiwiY2hhbm5lbFNwbGl0dGVyIiwiY3JlYXRlQ2hhbm5lbFNwbGl0dGVyIiwiY2hhbm5lbE1lcmdlciIsImNyZWF0ZUNoYW5uZWxNZXJnZXIiLCJjb25uZWN0VG9NYXN0ZXIiLCJjb25uZWN0VG9VSSIsIlNvdXJjZVR5cGUiLCJBdWRpb1NvdXJjZSIsImJ1ZmZlciIsInR5cGUiLCJXb3JsZFNvdXJjZSIsInBsYXliYWNrUmF0ZSIsInZvbHVtZSIsImdhaW4iLCJnZXRCdWZmZXIiLCJzZXRCdWZmZXIiLCJwbGF5T25Mb2FkIiwicGxheSIsIndoZW4iLCJvZmZzZXQiLCJkdXJhdGlvbiIsInBsYXlpbmciLCJjcmVhdGVDb25uZWN0aW9ucyIsInN0YXJ0IiwibG9vcCIsImxvb3BpbmciLCJzY2VuZU5vZGUiLCJhZGRFdmVudExpc3RlbmVyIiwic2V0UGxheWJhY2tSYXRlIiwiZ2V0UGxheWJhY2tSYXRlIiwic2V0Vm9sdW1lIiwiZ2V0Vm9sdW1lIiwiVUlTb3VyY2UiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwiZGVzdHJveSIsImZhZGVPdXQiLCJzZXRWYWx1ZUF0VGltZSIsImN1cnJlbnRUaW1lIiwiZXhwb25lbnRpYWxSYW1wVG9WYWx1ZUF0VGltZSIsImZhZGVJbiIsIkRhdGFQb29sSXRlbSIsIm5hbWUiLCJkZWNvZGVkRGF0YSIsImdldERhdGEiLCJzZXREYXRhIiwiZ2V0RGVjb2RlZERhdGEiLCJzZXREZWNvZGVkRGF0YSIsImdldE5hbWUiLCJzZXROYW1lIiwiSFRUUExvYWRlciIsInBhdGgiLCJmZXRjaCIsImFycmF5QnVmZmVyIiwiRGF0YVBvb2wiLCJsb2FkZXIiLCJtYXhEYXRhIiwiZGVjb2RlZCIsIk9iamVjdCIsImtleXMiLCJjbGVhciIsIkNvbnZvbHZlciIsInBhcmFtcyIsImVmZmVjdFBhcmFtcyIsImVmZmVjdE5vZGUiLCJjb25zb2xlIiwibG9nIiwiY3JlYXRlQ29udm9sdmVyIiwiU3RyZWFtaW5nU291cmNlIiwiTWFzdGVyU291cmNlIiwiZXZlbnQiLCJjYW5QbGF5IiwicGxheU9uQXZhaWxhYmxlIiwicGF1c2UiLCJSZXNvbmF0b3IiLCJlbnZpcm9ubWVudEltcHVsc2UiLCJkYXRhUG9vbCIsImxvYWQiLCJsb2FkSW1tZWRpYXRlIiwic291cmNlIiwic3RyZWFtIiwiQXVkaW8iLCJjcm9zc09yaWdpbiIsInNldEVudmlyb25tZW50SW1wdWxzZSIsImZpbGUiLCJjbGVhckRhdGFQb29sIiwiU291bmQiLCJyZXMiLCJhbWJpZW5jZSIsIm11c2ljIiwiYW1iaWVuY2VWb2x1bWUiLCJtdXNpY1ZvbHVtZSIsInNmeFZvbHVtZSIsInByZXZpb3VzQW1iaWVuY2UiLCJwcmV2aW91c011c2ljIiwic291bmQiLCJhc3luYyIsInNldE11c2ljIiwic2V0SW1wdWxzZSIsInNldE11c2ljVm9sdW1lIiwic2V0QW1iaWVuY2VWb2x1bWUiLCJzZXRTRlhWb2x1bWUiLCJPdXRwdXQiLCJ0dHMiLCJoaXN0b3J5IiwiZ2V0RWxlbWVudEJ5SWQiLCJzYXkiLCJzdHJpbmciLCJzcGxpdCIsImxpbmUiLCJzZXRBbWJpZW5jZSIsIklucHV0IiwiY29tbWFuZEhhbmRsZXIiLCJvdXRwdXRIYW5kbGVyIiwiaGFuZGxlciIsImVjaG9JbnB1dCIsImlucHV0RmllbGQiLCJoaXN0b3J5Q3Vyc29yIiwic2V0RWNobyIsImFkZFRvSW5wdXRIaXN0b3J5IiwiZG9Db21tYW5kIiwic3RyIiwiZGVmYXVsdENvbW1hbmRzIiwiYXJncyIsImV4YW1pbmVSb29tIiwiaXRlbXMiLCJnZXRSb29tIiwicGxheWVyIiwiZ2V0SXRlbXMiLCJpbmNsdWRlcyIsImRlc2NyaXB0aW9uIiwib25Vc2UiLCJyb29tIiwidGFrZWFibGUiLCJwcmludCIsIm9uVGFrZSIsIm9uRHJvcCIsInNldElucHV0RWNobyIsInNhdmUiLCJwYXJzZUludCIsIml0ZW1EZXNjcmlwdGlvbiIsImRpcmVjdGlvbk1hcCIsIkNvbW1hbmRzIiwiY29tbWFuZHMiLCJlbmFibGVkIiwiYWRkRGVmYXVsdENvbW1hbmRzIiwiZGlyZWN0aW9uIiwibWF0Y2hEaXJlY3Rpb24iLCJnZXRFeGl0IiwibW92ZSIsImFkZENvbW1hbmQiLCJmdW5jIiwiQXJyYXkiLCJpc0FycmF5IiwiY29tbWFuZCIsImFkZENvbW1hbmRzIiwiZGlyIiwiU2VyaWFsaXphdGlvbiIsInNhdmVvYmoiLCJpdGVtTG9jYXRpb25zIiwic2VyaWFsaXplSXRlbUxvY2F0aW9ucyIsIml0ZW1TdGF0ZXMiLCJzZXJpYWxpemVJdGVtU3RhdGVzIiwidm9sdW1lcyIsInNmeCIsImxvY2FsU3RvcmFnZSIsInNldEl0ZW0iLCJKU09OIiwic3RyaW5naWZ5IiwibG9hZG9iaiIsInBhcnNlIiwiZGVzZXJpYWxpemVJdGVtTG9jYXRpb25zIiwiZGVzZXJpYWxpemVJdGVtU3RhdGVzIiwiZGVzZXJpYWxpemVQbGF5ZXIiLCJyb29tcyIsIm9iamVjdHMiLCJHYW1lIiwibmV3R2FtZSIsInZpc2l0ZWRSb29tcyIsImludGVydmFsIiwibGluZXMiLCJ3YWl0IiwiYWR2YW5jZVRpY2siLCJvblRpY2siLCJzZXRJbnRlcnZhbCIsImNsZWFySW50ZXJ2YWwiLCJ0aXRsZSIsImZpcnN0RGVzY3JpcHRpb24iLCJleGFtaW5lSXRlbXMiLCJleGFtaW5lRXhpdHMiLCJleGl0cyIsImV4aXREZXNjcmlwdGlvbiIsImV4aXRLZXlzIiwiZXhpdCIsImZpbmQiLCJtcyIsInJvb21JRCIsIm5ld1Jvb20iLCJjYW5FeGl0IiwiY2FuRW50ZXIiLCJvbkV4aXQiLCJvbkVudGVyIiwiZW5hYmxlQ29tbWFuZElucHV0IiwiUm9vbSIsImVudGVyQ2FsbGJhY2siLCJleGl0Q2FsbGJhY2siLCJjYW5FbnRlckxvZ2ljIiwiY2FuRXhpdExvZ2ljIiwidGlja0NhbGxiYWNrIiwiaW1wdWxzZSIsImFkZEV4aXQiLCJhZGRFbnRlckNhbGxiYWNrIiwiY2FsbGJhY2siLCJhZGRFeGl0Q2FsbGJhY2siLCJhZGRFbnRlckxvZ2ljIiwiYWRkRXhpdExvZ2ljIiwiYWRkVGlja0NhbGxiYWNrIiwiUm9vbUJ1aWxkZXIiLCJ3aXRoSUQiLCJJRCIsIndpdGhUaXRsZSIsIndpdGhGaXJzdERlc2NyaXB0aW9uIiwid2l0aERlc2NyaXB0aW9uIiwid2l0aEV4aXQiLCJ3aXRoSXRlbSIsIml0ZW1JRCIsIndpdGhFbnRlckNhbGxiYWNrIiwid2l0aEV4aXRDYWxsYmFjayIsIndpdGhFbnRlckxvZ2ljIiwid2l0aEV4aXRMb2dpYyIsIndpdGhUaWNrIiwid2l0aE11c2ljIiwid2l0aEFtYmllbmNlIiwid2l0aEltcHVsc2UiLCJjcmVhdGUiLCJ0ZWxsIiwiSXRlbSIsInVzYWJsZSIsInVzZUNhbGxiYWNrIiwidGFrZUNhbGxiYWNrIiwiZHJvcENhbGxiYWNrIiwiYWRkVXNlQ2FsbGJhY2siLCJhZGRUYWtlQ2FsbGJhY2siLCJhZGREcm9wQ2FsbGJhY2siLCJzZXRTdGF0ZSIsImdldFN0YXRlIiwiSXRlbUJ1aWxkZXIiLCJ3aXRoTmFtZSIsIndpdGhUeXBlIiwid2l0aFN0YXRlIiwiaXNVc2FibGUiLCJpc1Rha2VhYmxlIiwid2l0aFVzZUNhbGxiYWNrIiwid2l0aFRha2VDYWxsYmFjayIsIndpdGhEcm9wQ2FsbGJhY2siLCJ3aXRoVGlja0NhbGxiYWNrIiwiY2VudHJhbDEiLCJzdGF0dWUxIiwic3RhdHVlMiIsInN0YXR1ZTMiLCJzdGF0dWU0IiwiTWVvd0NvbW1hbmQiLCJzdGFydEdhbWUiLCJoaWRkZW4iXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file diff --git a/framework/asset-manager/downloader.d.ts b/framework/asset-manager/downloader.d.ts new file mode 100644 index 0000000..ba8522d --- /dev/null +++ b/framework/asset-manager/downloader.d.ts @@ -0,0 +1,12 @@ +import EventEmitter from 'eventemitter3'; +import { Queue } from './queue'; +import { AssetStorage } from './storage'; +export declare class Downloader extends EventEmitter { + private storage; + private queue; + private basePath; + constructor(storage: AssetStorage, queue: Queue, basePath?: string); + setBasePath(path: string): void; + download(): Promise; + downloadItem(path: string): Promise; +} diff --git a/framework/asset-manager/downloader.js b/framework/asset-manager/downloader.js new file mode 100644 index 0000000..c1d4761 --- /dev/null +++ b/framework/asset-manager/downloader.js @@ -0,0 +1,50 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import EventEmitter from 'eventemitter3'; +import { buildPath } from './utils'; +export class Downloader extends EventEmitter { + constructor(storage, queue, basePath = '') { + super(); + this.storage = storage; + this.queue = queue; + this.basePath = basePath; + } + setBasePath(path) { + this.basePath = this.basePath; + } + download() { + return __awaiter(this, void 0, void 0, function* () { + const downloaded = new Map(); + let numDownloaded = 0; + while (this.queue.length() > 0) { + const path = this.queue.pop(); + const item = yield this.downloadItem(buildPath(this.basePath, path)); + downloaded.set(path, item); + numDownloaded++; + this.emit('download.progress', { + downloaded: numDownloaded, + remaining: this.queue.length() + }); + } + return downloaded; + }); + } + downloadItem(path) { + return __awaiter(this, void 0, void 0, function* () { + const inCache = yield this.storage.get(path); + if (inCache) { + return inCache; + } + const response = yield fetch(path); + this.storage.add(path, response); + return response; + }); + } +} diff --git a/framework/asset-manager/index.d.ts b/framework/asset-manager/index.d.ts new file mode 100644 index 0000000..1770301 --- /dev/null +++ b/framework/asset-manager/index.d.ts @@ -0,0 +1,18 @@ +import EventEmitter from 'eventemitter3'; +export declare class AssetManager extends EventEmitter { + private name; + private basePath; + private downloader; + private queue; + private storage; + private manifest; + constructor(name: string, basePath: string); + init(): Promise; + setManifest(path: string): Promise; + enqueue(path: string): void; + download(): Promise; + downloadFromManifest(key: string): Promise; + downloadFile(path: string): Promise; + setBasePath(path: string): void; + clearCache(): void; +} diff --git a/framework/asset-manager/index.js b/framework/asset-manager/index.js new file mode 100644 index 0000000..6b58db6 --- /dev/null +++ b/framework/asset-manager/index.js @@ -0,0 +1,71 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { Downloader } from './downloader'; +import { Queue } from './queue'; +import { Manifest } from './manifest'; +import { AssetStorage } from './storage'; +import EventEmitter from 'eventemitter3'; +import { buildPath } from './utils'; +export class AssetManager extends EventEmitter { + constructor(name, basePath) { + super(); + this.name = name; + this.basePath = basePath; + this.queue = new Queue(); + this.storage = new AssetStorage(name); + this.downloader = new Downloader(this.storage, this.queue, this.basePath); + console.log(`Asset manager initialized`); + } + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this.storage.init(); + return true; + }); + } + setManifest(path) { + return __awaiter(this, void 0, void 0, function* () { + this.manifest = yield Manifest(`${this.basePath}/${path}`); + this.storage.setManifest(this.manifest); + return this.manifest; + }); + } + enqueue(path) { + this.queue.add(path); + } + download() { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.downloader.download(); + return result; + }); + } + downloadFromManifest(key) { + return __awaiter(this, void 0, void 0, function* () { + const paths = this.manifest[key]; + paths.forEach((path) => this.enqueue(path)); + this.downloader.on('download.progress', (info) => this.emit('progress', info)); + const files = yield this.downloader.download(); + this.downloader.off('download.progress'); + return files; + }); + } + downloadFile(path) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.downloader.downloadItem(buildPath(this.basePath, path)); + return result; + }); + } + setBasePath(path) { + this.basePath = this.basePath; + this.downloader.setBasePath(this.basePath); + } + clearCache() { + this.storage.clear(); + } +} diff --git a/framework/asset-manager/manifest.d.ts b/framework/asset-manager/manifest.d.ts new file mode 100644 index 0000000..f6d92c5 --- /dev/null +++ b/framework/asset-manager/manifest.d.ts @@ -0,0 +1,2 @@ +export declare function Manifest(manifestPath: string): Promise; +export declare function CheckManifest(manifest: any): boolean; diff --git a/framework/asset-manager/manifest.js b/framework/asset-manager/manifest.js new file mode 100644 index 0000000..f8d0755 --- /dev/null +++ b/framework/asset-manager/manifest.js @@ -0,0 +1,40 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import * as yaml from 'yaml'; +export function Manifest(manifestPath) { + return __awaiter(this, void 0, void 0, function* () { + try { + const response = yield fetch(manifestPath); + console.log(response); + const data = yield response.text(); + console.log(`Parsing: `, data); + const manifest = yaml.parse(data); + return manifest; + } + catch (error) { + alert(`Error occured: ${error.toString()}`); + } + }); +} +export function CheckManifest(manifest) { + const prevManifestStr = localStorage.getItem('manifest'); + if (!prevManifestStr) { + localStorage.setItem('manifest', JSON.stringify(manifest)); + return false; + } + const prevManifest = JSON.parse(prevManifestStr); + if (prevManifest.version === manifest.version) { + return true; + } + else { + localStorage.setItem('manifest', manifest); + return false; + } +} diff --git a/framework/asset-manager/queue.d.ts b/framework/asset-manager/queue.d.ts new file mode 100644 index 0000000..2bb6077 --- /dev/null +++ b/framework/asset-manager/queue.d.ts @@ -0,0 +1,8 @@ +export declare class Queue { + private items; + constructor(); + add(file: string): string[]; + remove(file: string): string[]; + pop(): string; + length(): number; +} diff --git a/framework/asset-manager/queue.js b/framework/asset-manager/queue.js new file mode 100644 index 0000000..db1d0fb --- /dev/null +++ b/framework/asset-manager/queue.js @@ -0,0 +1,19 @@ +export class Queue { + constructor() { + this.items = []; + } + add(file) { + this.items.push(file); + return this.items; + } + remove(file) { + this.items = this.items.filter((item) => item !== file); + return this.items; + } + pop() { + return this.items.pop(); + } + length() { + return this.items.length; + } +} diff --git a/framework/asset-manager/storage.d.ts b/framework/asset-manager/storage.d.ts new file mode 100644 index 0000000..d56b85e --- /dev/null +++ b/framework/asset-manager/storage.d.ts @@ -0,0 +1,11 @@ +export declare class AssetStorage { + private id; + private cache; + private manifest; + constructor(id: string); + init(): Promise; + add(request: RequestInfo, response: Response): Promise; + get(request: RequestInfo): Promise; + setManifest(manifest: any): Promise; + clear(): Promise; +} diff --git a/framework/asset-manager/storage.js b/framework/asset-manager/storage.js new file mode 100644 index 0000000..dff4729 --- /dev/null +++ b/framework/asset-manager/storage.js @@ -0,0 +1,48 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { CheckManifest } from './manifest'; +export class AssetStorage { + constructor(id) { + this.id = id; + } + init() { + return __awaiter(this, void 0, void 0, function* () { + this.cache = yield caches.open(this.id); + }); + } + add(request, response) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.cache.put(request, response); + return true; + }); + } + get(request) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.cache.match(request); + return result; + }); + } + setManifest(manifest) { + return __awaiter(this, void 0, void 0, function* () { + this.manifest = manifest; + if (!CheckManifest(this.manifest)) { + yield this.clear(); + } + }); + } + clear() { + return __awaiter(this, void 0, void 0, function* () { + const keys = yield this.cache.keys(); + keys.forEach((key) => __awaiter(this, void 0, void 0, function* () { + const result = yield this.cache.delete(key); + })); + }); + } +} diff --git a/framework/asset-manager/test/index.d.ts b/framework/asset-manager/test/index.d.ts new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/asset-manager/test/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/framework/asset-manager/test/index.js b/framework/asset-manager/test/index.js new file mode 100644 index 0000000..f93e6f6 --- /dev/null +++ b/framework/asset-manager/test/index.js @@ -0,0 +1,5 @@ +const yaml = require('yaml'); +const fs = require('fs'); +const data = fs.readFileSync('manifest.yaml'); +const parsed = yaml.parse(data.toString()); +console.log(parsed); diff --git a/framework/asset-manager/utils.d.ts b/framework/asset-manager/utils.d.ts new file mode 100644 index 0000000..0085e31 --- /dev/null +++ b/framework/asset-manager/utils.d.ts @@ -0,0 +1 @@ +export declare function buildPath(basePath: string, path: string): string; diff --git a/framework/asset-manager/utils.js b/framework/asset-manager/utils.js new file mode 100644 index 0000000..0ea13c7 --- /dev/null +++ b/framework/asset-manager/utils.js @@ -0,0 +1,8 @@ +export function buildPath(basePath, path) { + if (!basePath) { + return path; + } + else { + return `${basePath}/${path}`; + } +} diff --git a/framework/ecs/component.d.ts b/framework/ecs/component.d.ts new file mode 100644 index 0000000..f94b615 --- /dev/null +++ b/framework/ecs/component.d.ts @@ -0,0 +1,12 @@ +export declare class BaseComponent { + id: number; + properties: any; + constructor(); + clone(): BaseComponent; +} +export interface Component { + id: number; + properties: any; + clone(): BaseComponent; + new (): BaseComponent; +} diff --git a/framework/ecs/component.js b/framework/ecs/component.js new file mode 100644 index 0000000..c5d323a --- /dev/null +++ b/framework/ecs/component.js @@ -0,0 +1,11 @@ +export class BaseComponent { + constructor() { + this.id = 0; + this.properties = {}; + } + clone() { + const comp = new BaseComponent(); + comp.properties = this.properties; + return comp; + } +} diff --git a/framework/ecs/entity.d.ts b/framework/ecs/entity.d.ts new file mode 100644 index 0000000..43dc047 --- /dev/null +++ b/framework/ecs/entity.d.ts @@ -0,0 +1,19 @@ +import { BaseComponent, Component } from './component'; +export declare class BaseEntity { + id: number; + components: Map; + constructor(); + addComponent(component: Component): void; + removeComponent(component: BaseComponent): void; + getComponentIDs(): number[]; + getComponent(component: BaseComponent): BaseComponent; + getComponentByID(id: number): BaseComponent; +} +export interface Entity { + new (): BaseComponent; + addComponent(component: Component): any; + removeComponent(component: BaseComponent): any; + getComponentIDs(): number[]; + getComponent(component: BaseComponent): any; + getComponentByID(id: number): BaseComponent; +} diff --git a/framework/ecs/entity.js b/framework/ecs/entity.js new file mode 100644 index 0000000..0436a5c --- /dev/null +++ b/framework/ecs/entity.js @@ -0,0 +1,23 @@ +export class BaseEntity { + constructor() { + this.components = new Map(); + this.id = 0; + } + addComponent(component) { + let comp = new component(); + comp.id = component.id; + this.components.set(component.id, comp); + } + removeComponent(component) { + this.components.delete(component.id); + } + getComponentIDs() { + return [...this.components.keys()]; + } + getComponent(component) { + return this.components.get(component.id); + } + getComponentByID(id) { + return this.components.get(id); + } +} diff --git a/framework/ecs/index.d.ts b/framework/ecs/index.d.ts new file mode 100644 index 0000000..a4304ac --- /dev/null +++ b/framework/ecs/index.d.ts @@ -0,0 +1,28 @@ +import { Component } from './component'; +import { BaseEntity, Entity } from './entity'; +import { EventBus } from '../event-bus'; +import { Query } from './query'; +import { System } from './system'; +export declare class World { + entities: Array; + components: Map; + componentNamesToIDs: Map; + systems: Set; + nextEntityID: number; + nextComponentID: number; + nextQueryID: number; + queryCache: Array; + eventBus: EventBus; + constructor(); + run(): void; + createSystem(systemExecutor: Function): void; + addSystem(system: System): void; + addEntity(entity: BaseEntity): void; + removeEntity(entityToRemove: BaseEntity): void; + createEntity(components: Array): BaseEntity; + extendEntity(entity: Entity, components: Array): BaseEntity; + createComponent(component: Component): Component; + query(include: Array, exclude: Array): Array; + createQuery(include: Array, exclude: Array): Query; + markQueriesDirty(): void; +} diff --git a/framework/ecs/index.js b/framework/ecs/index.js new file mode 100644 index 0000000..b2786b1 --- /dev/null +++ b/framework/ecs/index.js @@ -0,0 +1,105 @@ +import { BaseEntity } from './entity'; +import { EventBus } from '../event-bus'; +import { Query } from './query'; +import { System } from './system'; +export class World { + constructor() { + this.nextEntityID = 0; + this.nextComponentID = 0; + this.nextQueryID = 0; + this.entities = new Array(); + this.systems = new Set(); + this.components = new Map(); + this.componentNamesToIDs = new Map(); + this.queryCache = new Array(); + this.eventBus = new EventBus(); + } + run() { + this.systems.forEach((system) => { + system.execute(this); + }); + } + createSystem(systemExecutor) { + const newSystem = new System(systemExecutor); + this.systems.add(newSystem); + } + addSystem(system) { + this.systems.add(system); + } + addEntity(entity) { + this.entities.push(entity); + this.markQueriesDirty(); + } + removeEntity(entityToRemove) { + this.entities = this.entities.filter((entity) => entity !== entityToRemove); + this.markQueriesDirty(); + } + createEntity(components) { + const newEntity = new BaseEntity(); + newEntity.id = this.nextEntityID; + this.nextEntityID++; + components.forEach((component) => { + if (this.componentNamesToIDs.has(component.name)) { + component.id = this.componentNamesToIDs.get(component.name); + } + else { + this.componentNamesToIDs.set(component.name, this.nextComponentID); + component.id = this.nextComponentID; + this.nextComponentID++; + } + newEntity.addComponent(component); + }); + this.entities.push(newEntity); + this.markQueriesDirty(); + return newEntity; + } + extendEntity(entity, components) { + const toClone = this.entities.find((found) => entity.name === found.constructor.name); + const cloned = new BaseEntity(); + cloned.id = this.nextEntityID; + this.nextEntityID++; + toClone.components.forEach((component) => { + cloned.addComponent(this.components.get(component.id)); + }); + components.forEach((component) => { + if (this.componentNamesToIDs.has(component.name)) { + component.id = this.componentNamesToIDs.get(component.name); + } + else { + this.componentNamesToIDs.set(component.name, this.nextComponentID); + component.id = this.nextComponentID; + this.nextComponentID++; + } + cloned.addComponent(component); + }); + this.entities.push(cloned); + return cloned; + } + createComponent(component) { + const newComponent = component; + newComponent.id = this.nextComponentID; + this.nextComponentID++; + this.components.set(newComponent.id, newComponent); + this.componentNamesToIDs.set(component.name, component.id); + return newComponent; + } + query(include, exclude) { + const query = new Query(include, exclude, this); + const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude); + if (cache) { + return cache.execute(); + } + this.queryCache.push(query); + return query.execute(); + } + createQuery(include, exclude) { + const newQuery = new Query(include, exclude, this); + newQuery.id = this.nextQueryID; + this.nextQueryID++; + this.queryCache.push(newQuery); + return newQuery; + } + markQueriesDirty() { + this.queryCache.forEach((query) => (query.isDirty = true)); + } +} diff --git a/framework/ecs/query.d.ts b/framework/ecs/query.d.ts new file mode 100644 index 0000000..f6a8160 --- /dev/null +++ b/framework/ecs/query.d.ts @@ -0,0 +1,15 @@ +import { World } from '.'; +import { Component } from './component'; +import { BaseEntity } from './entity'; +export declare class Query { + include: Array; + exclude: Array; + world: World; + id: number; + private results; + isDirty: boolean; + includeComponentIds: number[]; + excludeComponentIds: number[]; + constructor(include: Array, exclude: Array, world: World); + execute(): Array; +} diff --git a/framework/ecs/query.js b/framework/ecs/query.js new file mode 100644 index 0000000..1fca3a3 --- /dev/null +++ b/framework/ecs/query.js @@ -0,0 +1,34 @@ +export class Query { + constructor(include, exclude, world) { + this.include = include; + this.exclude = exclude; + this.world = world; + this.isDirty = true; + this.results = new Array(); + this.includeComponentIds = include.map((component) => component.id); + this.excludeComponentIds = exclude.map((component) => component.id); + this.id = 0; + } + execute() { + if (!this.isDirty && this.results) { + return this.results; + } + let filtered; + this.includeComponentIds = this.include.map((component) => this.world.componentNamesToIDs.get(component.name)); + this.excludeComponentIds = this.exclude.map((component) => this.world.componentNamesToIDs.get(component.name)); + const entities = this.world.entities.filter((entity) => { + let ids = entity.getComponentIDs(); + // let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true); + let excludes = ids + .map((id) => this.excludeComponentIds.includes(id)) + .includes(true); + let includes = ids.filter((id) => this.includeComponentIds.includes(id)); + return includes.length === this.includeComponentIds.length && !excludes; + }); + if (entities.length > 0) { + this.isDirty = false; + this.results = entities; + } + return entities; + } +} diff --git a/framework/ecs/system.d.ts b/framework/ecs/system.d.ts new file mode 100644 index 0000000..c4dbd67 --- /dev/null +++ b/framework/ecs/system.d.ts @@ -0,0 +1,6 @@ +import { World } from '.'; +export declare class System { + executor: Function; + constructor(executor: Function); + execute(world: World): void; +} diff --git a/framework/ecs/system.js b/framework/ecs/system.js new file mode 100644 index 0000000..0a43344 --- /dev/null +++ b/framework/ecs/system.js @@ -0,0 +1,10 @@ +export class System { + constructor(executor) { + this.executor = executor; + } + execute(world) { + if (this.executor) { + this.executor(world); + } + } +} diff --git a/src/framework/engine.js b/framework/engine.js similarity index 100% rename from src/framework/engine.js rename to framework/engine.js diff --git a/src/framework/event-bus/event-bus.d.ts b/framework/event-bus/event-bus.d.ts similarity index 96% rename from src/framework/event-bus/event-bus.d.ts rename to framework/event-bus/event-bus.d.ts index 24b52fb..c2fd337 100644 --- a/src/framework/event-bus/event-bus.d.ts +++ b/framework/event-bus/event-bus.d.ts @@ -1,11 +1,11 @@ -export declare class EventBus { - private events; - constructor(); - emit(id: string, data: any): void; - subscribe(id: string, subscriber: Function): void; -} -export declare class EventItem { - id: string; - subscribers: Function[]; - constructor(id: string); -} +export declare class EventBus { + private events; + constructor(); + emit(id: string, data: any): void; + subscribe(id: string, subscriber: Function): void; +} +export declare class EventItem { + id: string; + subscribers: Function[]; + constructor(id: string); +} diff --git a/src/framework/world/event-bus.js b/framework/event-bus/event-bus.js similarity index 95% rename from src/framework/world/event-bus.js rename to framework/event-bus/event-bus.js index 11ee12b..a90b6c1 100644 --- a/src/framework/world/event-bus.js +++ b/framework/event-bus/event-bus.js @@ -1,30 +1,30 @@ -export class EventBus { - constructor() { - this.events = new Map(); - } - emit(id, data) { - let ev = this.events.get(id); - if (!ev) { - let ev = new EventItem(id); - this.events.set(id, ev); - return; - } - ev.subscribers.forEach((subscriber) => { - subscriber(data); - }); - } - subscribe(id, subscriber) { - let ev = this.events.get(id); - if (!ev) { - ev = new EventItem(id); - this.events.set(id, ev); - } - ev.subscribers.push(subscriber); - } -} -export class EventItem { - constructor(id) { - this.id = id; - this.subscribers = []; - } -} +export class EventBus { + constructor() { + this.events = new Map(); + } + emit(id, data) { + let ev = this.events.get(id); + if (!ev) { + let ev = new EventItem(id); + this.events.set(id, ev); + return; + } + ev.subscribers.forEach((subscriber) => { + subscriber(data); + }); + } + subscribe(id, subscriber) { + let ev = this.events.get(id); + if (!ev) { + ev = new EventItem(id); + this.events.set(id, ev); + } + ev.subscribers.push(subscriber); + } +} +export class EventItem { + constructor(id) { + this.id = id; + this.subscribers = []; + } +} diff --git a/framework/event-bus/index.d.ts b/framework/event-bus/index.d.ts new file mode 100644 index 0000000..2689b43 --- /dev/null +++ b/framework/event-bus/index.d.ts @@ -0,0 +1,13 @@ +export declare class EventBus { + private events; + constructor(); + emit(id: string, data?: any): void; + subscribe(id: string, subscriber: Function): void; + unsubscribe(id: string, subscriber: Function): void; + unsubscribeAll(id: string): void; +} +export declare class EventItem { + id: string; + subscribers: Function[]; + constructor(id: string); +} diff --git a/framework/event-bus/index.js b/framework/event-bus/index.js new file mode 100644 index 0000000..8abe562 --- /dev/null +++ b/framework/event-bus/index.js @@ -0,0 +1,44 @@ +export class EventBus { + constructor() { + this.events = new Map(); + } + emit(id, data = {}) { + let ev = this.events.get(id); + if (!ev) { + let ev = new EventItem(id); + this.events.set(id, ev); + return; + } + ev.subscribers.forEach((subscriber) => { + subscriber(data); + }); + } + subscribe(id, subscriber) { + let ev = this.events.get(id); + if (!ev) { + ev = new EventItem(id); + this.events.set(id, ev); + } + ev.subscribers.push(subscriber); + } + unsubscribe(id, subscriber) { + if (this.events.has(id)) { + let ev = this.events.get(id); + ev.subscribers = ev.subscribers.filter((fn) => fn !== subscriber); + if (ev.subscribers.length < 1) { + this.events.delete(id); + } + } + } + unsubscribeAll(id) { + if (this.events.has(id)) { + this.events.delete(id); + } + } +} +export class EventItem { + constructor(id) { + this.id = id; + this.subscribers = []; + } +} diff --git a/src/framework/game/game.d.ts b/framework/game/game.d.ts similarity index 100% rename from src/framework/game/game.d.ts rename to framework/game/game.d.ts diff --git a/src/framework/game/game.js b/framework/game/game.js similarity index 100% rename from src/framework/game/game.js rename to framework/game/game.js diff --git a/framework/game/index.d.ts b/framework/game/index.d.ts new file mode 100644 index 0000000..9d598ae --- /dev/null +++ b/framework/game/index.d.ts @@ -0,0 +1,26 @@ +import { AssetManager } from '../asset-manager'; +import { Input } from '../input'; +import Resonator from '../resonator'; +import { Scene } from '../scene/scene'; +import { SceneManager } from '../scene/manager'; +import { Scheduler } from '../scheduler'; +import { TTS } from '../tts'; +import { HTTPLoader } from '../resonator/loaders/http-loader'; +import { EventBus } from '../event-bus'; +import { World } from '../world'; +export declare class Game extends EventBus { + assetLoader: HTTPLoader; + assetManager: AssetManager; + resonator: Resonator; + input: Input; + tts: TTS; + sceneManager: SceneManager; + scheduler: Scheduler; + world: World; + constructor(); + init(): void; + start(): void; + addScene(scene: Scene): void; + addDefaultScene(scene: Scene): void; + setWorld(world: World): void; +} diff --git a/framework/game/index.js b/framework/game/index.js new file mode 100644 index 0000000..d772448 --- /dev/null +++ b/framework/game/index.js @@ -0,0 +1,44 @@ +import { AssetManager } from '../asset-manager'; +import { Input } from '../input'; +import Resonator from '../resonator'; +import { SceneManager } from '../scene/manager'; +import { Scheduler } from '../scheduler'; +import { TTS } from '../tts'; +import { AriaOutput } from '../tts/outputs/aria'; +import { HTTPLoader } from '../resonator/loaders/http-loader'; +import { EventBus } from '../event-bus'; +export class Game extends EventBus { + constructor() { + super(); + this.init(); + } + init() { + this.assetManager = new AssetManager('game', ''); + this.assetLoader = new HTTPLoader(); + this.resonator = new Resonator(this.assetLoader); + this.input = new Input(['keyboard'], document.body); + this.tts = new TTS(new AriaOutput()); + this.sceneManager = new SceneManager(); + this.scheduler = new Scheduler(60); + this.emit('ready'); + } + start() { + this.scheduler.start(); + this.scheduler.subscribe('update.logic', (dt) => { + this.sceneManager.currentScene.update(dt); + this.world.update(dt); + }); + this.scheduler.subscribe('update.draw', (dt) => this.sceneManager.currentScene.updateDraw()); + this.sceneManager.init(); + } + addScene(scene) { + this.sceneManager.addScene(scene); + } + addDefaultScene(scene) { + this.sceneManager.addScene(scene); + this.sceneManager.setDefaultScene(scene); + } + setWorld(world) { + this.world = world; + } +} diff --git a/src/framework/game/scenes/ecs-scene.d.ts b/framework/game/scenes/ecs-scene.d.ts similarity index 97% rename from src/framework/game/scenes/ecs-scene.d.ts rename to framework/game/scenes/ecs-scene.d.ts index 6cee437..95de855 100644 --- a/src/framework/game/scenes/ecs-scene.d.ts +++ b/framework/game/scenes/ecs-scene.d.ts @@ -1,29 +1,29 @@ -import { Scene } from '../../scene/scene'; -import { World } from '../../ecs/index'; -import { Game } from '..'; -import { Component } from '../../ecs/component'; -import { System } from '../../ecs/system'; -import { Entity } from '../../ecs/entity'; -import { Query } from '../../ecs/query'; -import { SceneManager } from '../../scene/manager'; -export declare class ECSScene implements Scene { - instance: Game; - id: string; - world: World; - running: boolean; - data: any; - constructor(instance: Game); - update(): void; - updateDraw(): boolean; - onActivate(manager: SceneManager): void; - onDeactivate(): void; - onSwitch(): void; - createEntity(components: Array>): Entity; - createComponent(props: T): Component; - createSystem(systemExecutor: Function): void; - addSystem(system: System): void; - addEntity(entity: Entity): void; - removeEntity(entity: Entity): void; - createQuery(include: Array>, exclude: Array>): Query; - extendEntity(entity: Entity, components: Array>): Entity; -} +import { Scene } from '../../scene/scene'; +import { World } from '../../ecs/index'; +import { Game } from '..'; +import { Component } from '../../ecs/component'; +import { System } from '../../ecs/system'; +import { Entity } from '../../ecs/entity'; +import { Query } from '../../ecs/query'; +import { SceneManager } from '../../scene/manager'; +export declare class ECSScene implements Scene { + instance: Game; + id: string; + world: World; + running: boolean; + data: any; + constructor(instance: Game); + update(): void; + updateDraw(): boolean; + onActivate(manager: SceneManager): void; + onDeactivate(): void; + onSwitch(): void; + createEntity(components: Array>): Entity; + createComponent(props: T): Component; + createSystem(systemExecutor: Function): void; + addSystem(system: System): void; + addEntity(entity: Entity): void; + removeEntity(entity: Entity): void; + createQuery(include: Array>, exclude: Array>): Query; + extendEntity(entity: Entity, components: Array>): Entity; +} diff --git a/src/framework/game/scenes/ecs-scene.js b/framework/game/scenes/ecs-scene.js similarity index 96% rename from src/framework/game/scenes/ecs-scene.js rename to framework/game/scenes/ecs-scene.js index 4ac7412..6759dfe 100644 --- a/src/framework/game/scenes/ecs-scene.js +++ b/framework/game/scenes/ecs-scene.js @@ -1,49 +1,49 @@ -import { World } from '../../ecs/index'; -export class ECSScene { - constructor(instance) { - this.instance = instance; - this.running = true; - this.id = 'ECSScene'; - this.world = new World(); - } - update() { - if (this.running) - this.world.run(); - } - updateDraw() { - return true; - } - onActivate(manager) { - this.running = true; - } - onDeactivate() { - this.running = false; - } - onSwitch() { - return; - } - createEntity(components) { - return this.world.createEntity(components); - } - createComponent(props) { - return this.world.createComponent(props); - } - createSystem(systemExecutor) { - return this.world.createSystem(systemExecutor); - } - addSystem(system) { - return this.world.addSystem(system); - } - addEntity(entity) { - return this.world.addEntity(entity); - } - removeEntity(entity) { - return this.world.removeEntity(entity); - } - createQuery(include, exclude) { - return this.world.createQuery(include, exclude); - } - extendEntity(entity, components) { - return this.world.extendEntity(entity, components); - } -} +import { World } from '../../ecs/index'; +export class ECSScene { + constructor(instance) { + this.instance = instance; + this.running = true; + this.id = 'ECSScene'; + this.world = new World(); + } + update() { + if (this.running) + this.world.run(); + } + updateDraw() { + return true; + } + onActivate(manager) { + this.running = true; + } + onDeactivate() { + this.running = false; + } + onSwitch() { + return; + } + createEntity(components) { + return this.world.createEntity(components); + } + createComponent(props) { + return this.world.createComponent(props); + } + createSystem(systemExecutor) { + return this.world.createSystem(systemExecutor); + } + addSystem(system) { + return this.world.addSystem(system); + } + addEntity(entity) { + return this.world.addEntity(entity); + } + removeEntity(entity) { + return this.world.removeEntity(entity); + } + createQuery(include, exclude) { + return this.world.createQuery(include, exclude); + } + extendEntity(entity, components) { + return this.world.extendEntity(entity, components); + } +} diff --git a/framework/index.d.ts b/framework/index.d.ts new file mode 100644 index 0000000..68ec897 --- /dev/null +++ b/framework/index.d.ts @@ -0,0 +1,7 @@ +export * from './asset-manager'; +export * from './ecs'; +export * from './event-bus'; +export * from './input'; +export * from './resonator'; +export * from './tts'; +export * from './ui'; diff --git a/framework/index.js b/framework/index.js new file mode 100644 index 0000000..68ec897 --- /dev/null +++ b/framework/index.js @@ -0,0 +1,7 @@ +export * from './asset-manager'; +export * from './ecs'; +export * from './event-bus'; +export * from './input'; +export * from './resonator'; +export * from './tts'; +export * from './ui'; diff --git a/framework/input/index.d.ts b/framework/input/index.d.ts new file mode 100644 index 0000000..6d47da8 --- /dev/null +++ b/framework/input/index.d.ts @@ -0,0 +1,13 @@ +import { BaseInput } from './inputs/base-input'; +import { State } from './interfaces/state'; +export declare class Input { + private InputIDs; + private element; + private inputs; + constructor(InputIDs: string[], element: HTMLElement); + private init; + addInput(id: string, input: BaseInput): this; + capture(preventDefault?: boolean): void; + release(): void; + getState(): State; +} diff --git a/framework/input/index.js b/framework/input/index.js new file mode 100644 index 0000000..0b9e98d --- /dev/null +++ b/framework/input/index.js @@ -0,0 +1,34 @@ +import { createInput } from './input-factory'; +export class Input { + constructor(InputIDs, element) { + this.InputIDs = InputIDs; + this.element = element; + this.inputs = new Map(); + this.init(); + } + init() { + this.InputIDs.forEach((inputID) => { + const thing = createInput(inputID); + const instance = new thing(this.element); + this.inputs.set(inputID, instance); + }); + } + addInput(id, input) { + this.inputs.set(id, input); + return this; + } + capture(preventDefault = true) { + this.inputs.forEach((input) => input.capture(preventDefault)); + } + release() { + this.inputs.forEach((input) => input.release()); + } + getState() { + const state = {}; + this.inputs.forEach((input, inputID) => { + if (input) + state[inputID] = input.getState(); + }); + return state; + } +} diff --git a/framework/input/input-factory.d.ts b/framework/input/input-factory.d.ts new file mode 100644 index 0000000..ffd99c9 --- /dev/null +++ b/framework/input/input-factory.d.ts @@ -0,0 +1 @@ +export declare function createInput(key: string): any; diff --git a/framework/input/input-factory.js b/framework/input/input-factory.js new file mode 100644 index 0000000..1afa0f9 --- /dev/null +++ b/framework/input/input-factory.js @@ -0,0 +1,14 @@ +import { Keyboard } from './inputs/keyboard'; +import { Mouse } from './inputs/mouse'; +export function createInput(key) { + switch (key) { + case 'keyboard': + return Keyboard; + break; + case 'mouse': + return Mouse; + break; + default: + break; + } +} diff --git a/framework/input/inputs/base-input.d.ts b/framework/input/inputs/base-input.d.ts new file mode 100644 index 0000000..1518ded --- /dev/null +++ b/framework/input/inputs/base-input.d.ts @@ -0,0 +1,10 @@ +export declare class BaseInput { + protected element: HTMLElement; + protected active: boolean; + constructor(element: HTMLElement); + getState(): any; + capture(preventDefault: boolean): void; + release(): void; +} +export interface IBaseInput { +} diff --git a/framework/input/inputs/base-input.js b/framework/input/inputs/base-input.js new file mode 100644 index 0000000..b5ed417 --- /dev/null +++ b/framework/input/inputs/base-input.js @@ -0,0 +1,12 @@ +export class BaseInput { + constructor(element) { + this.element = element; + } + getState() { } + capture(preventDefault) { + return; + } + release() { + return; + } +} diff --git a/framework/input/inputs/joystick.d.ts b/framework/input/inputs/joystick.d.ts new file mode 100644 index 0000000..0eb84af --- /dev/null +++ b/framework/input/inputs/joystick.d.ts @@ -0,0 +1,6 @@ +import { BaseInput } from './base-input'; +export declare class Joystick extends BaseInput { + constructor(element: HTMLElement); +} +export interface IJoystick { +} diff --git a/framework/input/inputs/joystick.js b/framework/input/inputs/joystick.js new file mode 100644 index 0000000..8f0f1fa --- /dev/null +++ b/framework/input/inputs/joystick.js @@ -0,0 +1,6 @@ +import { BaseInput } from './base-input'; +export class Joystick extends BaseInput { + constructor(element) { + super(element); + } +} diff --git a/framework/input/inputs/keyboard.d.ts b/framework/input/inputs/keyboard.d.ts new file mode 100644 index 0000000..1c6a753 --- /dev/null +++ b/framework/input/inputs/keyboard.d.ts @@ -0,0 +1,18 @@ +import { BaseInput } from './base-input'; +export declare class Keyboard extends BaseInput { + private keysDown; + private keysJustPressed; + private keysJustReleased; + private preventDefault; + constructor(element: HTMLElement); + capture(preventDefault: boolean): void; + release(): void; + getState(): IKeyboard; + private handleKeyDown; + private handleKeyUp; +} +export interface IKeyboard { + keysDown: Map; + keysJustPressed: Map; + keysJustReleased: Map; +} diff --git a/framework/input/inputs/keyboard.js b/framework/input/inputs/keyboard.js new file mode 100644 index 0000000..fc47d15 --- /dev/null +++ b/framework/input/inputs/keyboard.js @@ -0,0 +1,50 @@ +import { BaseInput } from './base-input'; +export class Keyboard extends BaseInput { + constructor(element) { + super(element); + this.keysDown = new Map(); + this.keysJustPressed = new Map(); + this.keysJustReleased = new Map(); + this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleKeyUp = this.handleKeyUp.bind(this); + } + capture(preventDefault) { + this.active = true; + this.preventDefault = preventDefault; + this.element.addEventListener('keydown', this.handleKeyDown); + this.element.addEventListener('keyup', this.handleKeyUp); + } + release() { + this.active = false; + this.element.removeEventListener('keydown', this.handleKeyDown); + this.element.removeEventListener('keyup', this.handleKeyUp); + } + getState() { + const state = { + keysDown: new Map(this.keysDown), + keysJustPressed: new Map(this.keysJustPressed), + keysJustReleased: new Map(this.keysJustReleased) + }; + this.keysJustPressed.clear(); + this.keysJustReleased.clear(); + return state; + } + handleKeyDown(event) { + if (this.active && this.preventDefault) + event.preventDefault(); + if (this.keysDown.get(event.keyCode)) + return; + this.keysDown.set(event.keyCode, true); + this.keysJustPressed.set(event.keyCode, true); + this.keysJustReleased.set(event.keyCode, false); + } + handleKeyUp(event) { + if (this.active && this.preventDefault) + event.preventDefault(); + if (!this.keysDown.get(event.keyCode)) + return; + this.keysDown.set(event.keyCode, false); + this.keysJustPressed.set(event.keyCode, false); + this.keysJustReleased.set(event.keyCode, true); + } +} diff --git a/framework/input/inputs/mouse.d.ts b/framework/input/inputs/mouse.d.ts new file mode 100644 index 0000000..0fd532f --- /dev/null +++ b/framework/input/inputs/mouse.d.ts @@ -0,0 +1,34 @@ +import { BaseInput } from './base-input'; +export declare class Mouse extends BaseInput { + private mousePosition; + private mouseDelta; + private mouseWheel; + private mouseButtons; + constructor(element: HTMLElement); + capture(): void; + release(): void; + getState(): IMouse; + private handleMouseDown; + private handleMouseMove; + private handleMouseUp; + private handlePointerChange; +} +export declare class Position { + x: number; + y: number; +} +export declare class MouseButtons { + keysDown: Map; + keysJustPressed: Map; + keysJustReleased: Map; +} +export declare class Delta { + x: number; + y: number; +} +export interface IMouse { + mouseButtons: MouseButtons; + mousePosition: Position; + mouseWheel: Delta; + mouseDelta: Delta; +} diff --git a/framework/input/inputs/mouse.js b/framework/input/inputs/mouse.js new file mode 100644 index 0000000..2d1bf20 --- /dev/null +++ b/framework/input/inputs/mouse.js @@ -0,0 +1,87 @@ +import { BaseInput } from './base-input'; +export class Mouse extends BaseInput { + constructor(element) { + super(element); + this.mousePosition = new Position(); + this.mouseDelta = new Delta(); + this.mouseWheel = new Delta(); + this.mouseButtons = new MouseButtons(); + } + capture() { + this.handleMouseDown = this.handleMouseDown.bind(this); + this.handleMouseMove = this.handleMouseMove.bind(this); + this.handleMouseUp = this.handleMouseUp.bind(this); + this.handlePointerChange = this.handlePointerChange.bind(this); + this.active = true; + this.element.addEventListener('mousedown', this.handleMouseDown); + this.element.addEventListener('mousemove', this.handleMouseMove); + this.element.addEventListener('mouseup', this.handleMouseUp); + document.addEventListener('pointerlockchange', this.handlePointerChange); + } + release() { + this.active = false; + this.element.removeEventListener('mousedown', this.handleMouseDown); + this.element.removeEventListener('mousemove', this.handleMouseMove); + this.element.removeEventListener('mouseup', this.handleMouseUp); + } + getState() { + const { mouseButtons, mouseDelta, mousePosition, mouseWheel } = this; + const state = { + mouseButtons: { + keysDown: new Map(this.mouseButtons.keysDown), + keysJustPressed: new Map(this.mouseButtons.keysJustPressed), + keysJustReleased: new Map(this.mouseButtons.keysJustReleased) + }, + mouseDelta, + mousePosition, + mouseWheel + }; + this.mouseButtons.keysJustPressed.clear(); + this.mouseButtons.keysJustReleased.clear(); + this.mouseDelta.x = 0; + this.mouseDelta.y = 0; + return state; + } + handleMouseDown(event) { + if (this.active) + event.preventDefault(); + this.mouseButtons.keysDown.set(event.button, true); + this.mouseButtons.keysJustPressed.set(event.button, true); + this.mouseButtons.keysJustReleased.set(event.button, false); + } + handleMouseMove(event) { + if (this.active) + event.preventDefault(); + this.mousePosition.x = event.clientX; + this.mousePosition.y = event.clientY; + this.mouseDelta.x = event.movementX; + this.mouseDelta.y = event.movementY; + } + handleMouseUp(event) { + if (this.active) + event.preventDefault(); + this.mouseButtons.keysJustReleased.set(event.button, true); + this.mouseButtons.keysDown.set(event.button, false); + this.mouseButtons.keysJustPressed.set(event.button, false); + } + handlePointerChange() { + if (document.pointerLockElement !== this.element) { + this.element.addEventListener('click', () => { + this.element.requestPointerLock(); + }, { + once: true + }); + } + } +} +export class Position { +} +export class MouseButtons { + constructor() { + this.keysDown = new Map(); + this.keysJustPressed = new Map(); + this.keysJustReleased = new Map(); + } +} +export class Delta { +} diff --git a/framework/input/interfaces/state.d.ts b/framework/input/interfaces/state.d.ts new file mode 100644 index 0000000..2cdaa24 --- /dev/null +++ b/framework/input/interfaces/state.d.ts @@ -0,0 +1,4 @@ +import { IKeyboard } from '../inputs/keyboard'; +export interface State { + keyboard?: IKeyboard; +} diff --git a/framework/input/interfaces/state.js b/framework/input/interfaces/state.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/input/interfaces/state.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/input/keycodes.d.ts b/framework/input/keycodes.d.ts new file mode 100644 index 0000000..8ce351e --- /dev/null +++ b/framework/input/keycodes.d.ts @@ -0,0 +1,122 @@ +export declare let KeyCodes: { + CANCEL: number; + HELP: number; + BACK_SPACE: number; + TAB: number; + CLEAR: number; + RETURN: number; + ENTER: number; + SHIFT: number; + CONTROL: number; + ALT: number; + PAUSE: number; + CAPS_LOCK: number; + ESCAPE: number; + SPACE: number; + PAGE_UP: number; + PAGE_DOWN: number; + END: number; + HOME: number; + LEFT: number; + UP: number; + RIGHT: number; + DOWN: number; + PRINTSCREEN: number; + INSERT: number; + DELETE: number; + 0: number; + 1: number; + 2: number; + 3: number; + 4: number; + 5: number; + 6: number; + 7: number; + 8: number; + 9: number; + SEMICOLON: number; + EQUALS: number; + A: number; + B: number; + C: number; + D: number; + E: number; + F: number; + G: number; + H: number; + I: number; + J: number; + K: number; + L: number; + M: number; + N: number; + O: number; + P: number; + Q: number; + R: number; + S: number; + T: number; + U: number; + V: number; + W: number; + X: number; + Y: number; + Z: number; + CONTEXT_MENU: number; + NUMPAD0: number; + NUMPAD1: number; + NUMPAD2: number; + NUMPAD3: number; + NUMPAD4: number; + NUMPAD5: number; + NUMPAD6: number; + NUMPAD7: number; + NUMPAD8: number; + NUMPAD9: number; + MULTIPLY: number; + ADD: number; + SEPARATOR: number; + SUBTRACT: number; + DECIMAL: number; + DIVIDE: number; + F1: number; + F2: number; + F3: number; + F4: number; + F5: number; + F6: number; + F7: number; + F8: number; + F9: number; + F10: number; + F11: number; + F12: number; + F13: number; + F14: number; + F15: number; + F16: number; + F17: number; + F18: number; + F19: number; + F20: number; + F21: number; + F22: number; + F23: number; + F24: number; + NUM_LOCK: number; + SCROLL_LOCK: number; + COMMA: number; + PERIOD: number; + SLASH: number; + BACK_QUOTE: number; + OPEN_BRACKET: number; + BACK_SLASH: number; + CLOSE_BRACKET: number; + QUOTE: number; + META: number; +}; +export declare let MouseCodes: { + LEFT: number; + RIGHT: number; + MIDDLE: number; +}; diff --git a/framework/input/keycodes.js b/framework/input/keycodes.js new file mode 100644 index 0000000..03e5f9c --- /dev/null +++ b/framework/input/keycodes.js @@ -0,0 +1,122 @@ +export let KeyCodes = { + CANCEL: 3, + HELP: 6, + BACK_SPACE: 8, + TAB: 9, + CLEAR: 12, + RETURN: 13, + ENTER: 14, + SHIFT: 16, + CONTROL: 17, + ALT: 18, + PAUSE: 19, + CAPS_LOCK: 20, + ESCAPE: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + PRINTSCREEN: 44, + INSERT: 45, + DELETE: 46, + 0: 48, + 1: 49, + 2: 50, + 3: 51, + 4: 52, + 5: 53, + 6: 54, + 7: 55, + 8: 56, + 9: 57, + SEMICOLON: 59, + EQUALS: 61, + A: 65, + B: 66, + C: 67, + D: 68, + E: 69, + F: 70, + G: 71, + H: 72, + I: 73, + J: 74, + K: 75, + L: 76, + M: 77, + N: 78, + O: 79, + P: 80, + Q: 81, + R: 82, + S: 83, + T: 84, + U: 85, + V: 86, + W: 87, + X: 88, + Y: 89, + Z: 90, + CONTEXT_MENU: 93, + NUMPAD0: 96, + NUMPAD1: 97, + NUMPAD2: 98, + NUMPAD3: 99, + NUMPAD4: 100, + NUMPAD5: 101, + NUMPAD6: 102, + NUMPAD7: 103, + NUMPAD8: 104, + NUMPAD9: 105, + MULTIPLY: 106, + ADD: 107, + SEPARATOR: 108, + SUBTRACT: 109, + DECIMAL: 110, + DIVIDE: 111, + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, + F13: 124, + F14: 125, + F15: 126, + F16: 127, + F17: 128, + F18: 129, + F19: 130, + F20: 131, + F21: 132, + F22: 133, + F23: 134, + F24: 135, + NUM_LOCK: 144, + SCROLL_LOCK: 145, + COMMA: 188, + PERIOD: 190, + SLASH: 191, + BACK_QUOTE: 192, + OPEN_BRACKET: 219, + BACK_SLASH: 220, + CLOSE_BRACKET: 221, + QUOTE: 222, + META: 224 +}; +export let MouseCodes = { + LEFT: 0, + RIGHT: 1, + MIDDLE: 2 +}; diff --git a/src/framework/package.json b/framework/package.json similarity index 96% rename from src/framework/package.json rename to framework/package.json index f3248d1..007da4a 100644 --- a/src/framework/package.json +++ b/framework/package.json @@ -1,33 +1,33 @@ -{ - "name": "audiogame-tools", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "lint": "eslint . --ext .ts", - "format": "prettier --config .prettierrc engine/**/*.ts --write", - "compile:engine": "tsc", - "watch:engine": "tsc -w", - "bundle:engine": "webpack --config webpack.engine.js" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "eventemitter3": "^4.0.7", - "yaml": "^1.10.0" - }, - "devDependencies": { - "@babel/core": "^7.12.3", - "@babel/preset-env": "^7.12.1", - "@typescript-eslint/eslint-plugin": "^4.7.0", - "@typescript-eslint/parser": "^4.7.0", - "eslint": "^7.13.0", - "prettier": "^2.1.2", - "ts-loader": "^8.0.11", - "typescript": "^4.0.5", - "webpack": "^5.4.0", - "webpack-cli": "^4.2.0" - } -} +{ + "name": "audiogame-tools", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "lint": "eslint . --ext .ts", + "format": "prettier --config .prettierrc engine/**/*.ts --write", + "compile:engine": "tsc", + "watch:engine": "tsc -w", + "bundle:engine": "webpack --config webpack.engine.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "eventemitter3": "^4.0.7", + "yaml": "^1.10.0" + }, + "devDependencies": { + "@babel/core": "^7.12.3", + "@babel/preset-env": "^7.12.1", + "@typescript-eslint/eslint-plugin": "^4.7.0", + "@typescript-eslint/parser": "^4.7.0", + "eslint": "^7.13.0", + "prettier": "^2.1.2", + "ts-loader": "^8.0.11", + "typescript": "^4.0.5", + "webpack": "^5.4.0", + "webpack-cli": "^4.2.0" + } +} diff --git a/framework/physics/aabb.d.ts b/framework/physics/aabb.d.ts new file mode 100644 index 0000000..afa647b --- /dev/null +++ b/framework/physics/aabb.d.ts @@ -0,0 +1,2 @@ +import { PhysicsObject } from './object'; +export declare function AABB(obj1: PhysicsObject, obj2: PhysicsObject): boolean; diff --git a/framework/physics/aabb.js b/framework/physics/aabb.js new file mode 100644 index 0000000..29df5b8 --- /dev/null +++ b/framework/physics/aabb.js @@ -0,0 +1,17 @@ +export function AABB(obj1, obj2) { + if (checkOverlap(obj1.position.x, obj1.dimensions.x, obj2.position.x, obj2.dimensions.x)) { + return true; + } + else if (checkOverlap(obj1.position.y, obj1.dimensions.y, obj2.position.y, obj2.dimensions.y)) { + return true; + } + else if (checkOverlap(obj1.position.z, obj1.dimensions.z, obj2.position.z, obj2.dimensions.z)) { + return true; + } + return false; +} +function checkOverlap(x, w, yx, yw) { + if (x > yx || x < yx + yw || x + w > x || x + w < yx + yw) { + return true; + } +} diff --git a/src/framework/physics/quadtree.d.ts b/framework/physics/index.d.ts similarity index 100% rename from src/framework/physics/quadtree.d.ts rename to framework/physics/index.d.ts diff --git a/src/framework/physics/quadtree.js b/framework/physics/index.js similarity index 100% rename from src/framework/physics/quadtree.js rename to framework/physics/index.js diff --git a/framework/physics/object.d.ts b/framework/physics/object.d.ts new file mode 100644 index 0000000..e3298c3 --- /dev/null +++ b/framework/physics/object.d.ts @@ -0,0 +1,7 @@ +import { Vec3 } from './vec3'; +export declare class PhysicsObject { + position: Vec3; + dimensions: Vec3; + velocity: Vec3; + affectedByGravity: boolean; +} diff --git a/framework/physics/object.js b/framework/physics/object.js new file mode 100644 index 0000000..e532df6 --- /dev/null +++ b/framework/physics/object.js @@ -0,0 +1,2 @@ +export class PhysicsObject { +} diff --git a/framework/physics/octree.d.ts b/framework/physics/octree.d.ts new file mode 100644 index 0000000..310baf3 --- /dev/null +++ b/framework/physics/octree.d.ts @@ -0,0 +1,39 @@ +import { PhysicsObject } from './object'; +import { Vec3 } from './vec3'; +export declare class Octree { + private dimensions; + private maxObjects; + private maxLevels; + root: OcTreeNode; + constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number); + insert(obj: PhysicsObject): void; + find(position: Vec3, dimensions: Vec3): PhysicsObject[]; +} +export declare class OcTreeNode { + private position; + private dimensions; + private maxLevels; + private maxObjects; + private currentLevel; + objects: PhysicsObject[]; + nodes: OcTreeNode[]; + constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number, currentLevel?: number); + insert(obj: PhysicsObject): any; + find(x: number, y: number, z: number, xw: number, yh: number, zd: number): PhysicsObject[]; + split(): void; + private distributeObjectsToNodes; + getIndex(x: number, y: number, z: number): Direction; + getIndeciesForRect(x: number, y: number, z: number, xw: number, yh: number, zd: number): Direction[]; +} +declare enum Direction { + AboveUpperLeft = 0, + AboveUpperRight = 1, + AboveLowerRight = 2, + AboveLowerLeft = 3, + BelowUpperLeft = 4, + BelowUpperRight = 5, + BelowLowerRight = 6, + BelowLowerLeft = 7, + Here = 8 +} +export {}; diff --git a/framework/physics/octree.js b/framework/physics/octree.js new file mode 100644 index 0000000..75e580e --- /dev/null +++ b/framework/physics/octree.js @@ -0,0 +1,206 @@ +import { Vec3 } from './vec3'; +export class Octree { + constructor(dimensions, maxObjects = 10, maxLevels = 10) { + this.dimensions = dimensions; + this.maxObjects = maxObjects; + this.maxLevels = maxLevels; + this.root = new OcTreeNode(new Vec3({ + x: 0, + y: 0, + z: 0 + }), this.dimensions, maxLevels, maxObjects, 0); + } + insert(obj) { + this.root.insert(obj); + } + find(position, dimensions) { + return this.root.find(position.x, position.y, position.z, dimensions.x, dimensions.y, dimensions.z); + } +} +export class OcTreeNode { + constructor(position, dimensions, maxLevels, maxObjects, currentLevel = 0) { + this.position = position; + this.dimensions = dimensions; + this.maxLevels = maxLevels; + this.maxObjects = maxObjects; + this.currentLevel = currentLevel; + this.objects = []; + this.nodes = []; + } + insert(obj) { + const index = this.getIndex(obj.position.x, obj.position.y, obj.position.z); + if (index === Direction.Here) { + this.objects.push(obj); + } + else { + return this.nodes[index].insert(obj); + } + if (this.objects.length > this.maxObjects && + this.currentLevel < this.maxLevels) { + this.split(); + } + } + find(x, y, z, xw, yh, zd) { + if (this.nodes.length < 1) { + return this.objects; + } + const indecies = this.getIndeciesForRect(x, y, z, xw, yh, zd); + let results = []; + for (let i = 0; i < indecies.length - 1; i++) { + let res = this.nodes[indecies[i]].find(x, y, z, xw, yh, zd); + results.push([...res]); + } + return results; + } + split() { + const halfWidth = this.dimensions.x / 2; + const halfHeight = this.dimensions.y / 2; + const halfDepth = this.dimensions.z / 2; + this.nodes[Direction.AboveUpperLeft] = new OcTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.AboveUpperRight] = new OcTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.AboveLowerRight] = new OcTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y + halfHeight, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.AboveLowerLeft] = new OcTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y + halfHeight, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.BelowUpperLeft] = new OcTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.BelowUpperRight] = new OcTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.BelowLowerRight] = new OcTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y + halfHeight, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.nodes[Direction.BelowLowerLeft] = new OcTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y + halfHeight, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects, this.currentLevel++); + this.distributeObjectsToNodes(); + } + distributeObjectsToNodes() { + if (this.nodes.length < 8) { + this.split(); + return; + } + this.objects.forEach((obj) => { + const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z); + this.nodes[direction].insert(obj); + }); + this.objects = []; + } + getIndex(x, y, z) { + if (this.nodes.length === 0) { + return Direction.Here; + } + const halfWidth = this.dimensions.x / 2; + const halfHeight = this.dimensions.y / 2; + const halfDepth = this.dimensions.z / 2; + const isBelow = z < this.position.z + halfDepth; + const isLeft = x < this.position.x + halfWidth; + const isUpper = y > this.position.y + halfHeight; + if (isBelow) { + if (isLeft) { + if (isUpper) + return Direction.AboveUpperLeft; + else + return Direction.AboveLowerLeft; + } + else { + if (isUpper) + return Direction.AboveUpperRight; + else + return Direction.AboveLowerRight; + } + } + else { + if (isLeft) { + if (isUpper) + return Direction.BelowUpperLeft; + else + return Direction.BelowLowerLeft; + } + else { + if (isUpper) + return Direction.BelowUpperRight; + else + return Direction.BelowLowerRight; + } + } + } + getIndeciesForRect(x, y, z, xw, yh, zd) { + if (!(x > this.position.x && x < this.position.x + this.dimensions.x) || + !(y > this.position.y && y < this.position.y + this.dimensions.y) || + !(z > this.position.z && z < this.position.z + this.dimensions.z)) { + return []; + } + let indecies = []; + indecies.push(this.getIndex(x, y, z)); + indecies.push(this.getIndex(x + xw, y + yh, z + zd)); + return indecies; + } +} +var Direction; +(function (Direction) { + Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft"; + Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight"; + Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight"; + Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft"; + Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft"; + Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight"; + Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight"; + Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft"; + Direction[Direction["Here"] = 8] = "Here"; +})(Direction || (Direction = {})); diff --git a/src/framework/physics/octtree.d.ts b/framework/physics/octtree.d.ts similarity index 96% rename from src/framework/physics/octtree.d.ts rename to framework/physics/octtree.d.ts index 17b248d..8adff44 100644 --- a/src/framework/physics/octtree.d.ts +++ b/framework/physics/octtree.d.ts @@ -1,38 +1,38 @@ -import { PhysicsObject } from "./object"; -import { Vec3 } from "./vec3"; -export declare class Octtree { - private dimensions; - private maxObjects; - private maxLevels; - root: OctTreeNode; - constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number); - insert(obj: PhysicsObject): void; - find(position: Vec3, dimensions: Vec3): PhysicsObject[]; -} -export declare class OctTreeNode { - private position; - private dimensions; - private maxLevels; - private maxObjects; - objects: PhysicsObject[]; - nodes: OctTreeNode[]; - constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number); - insert(obj: PhysicsObject): void; - find(position: Vec3, dimensions: Vec3): PhysicsObject[]; - split(): void; - private distributeObjectsToNodes; - getIndex(x: number, y: number, z: number): Direction; - getIndeciesForRect(position: Vec3, dimensions: Vec3): Set; -} -declare enum Direction { - AboveUpperLeft = 0, - AboveUpperRight = 1, - AboveLowerRight = 2, - AboveLowerLeft = 3, - BelowUpperLeft = 4, - BelowUpperRight = 5, - BelowLowerRight = 6, - BelowLowerLeft = 7, - Here = 8 -} -export {}; +import { PhysicsObject } from "./object"; +import { Vec3 } from "./vec3"; +export declare class Octtree { + private dimensions; + private maxObjects; + private maxLevels; + root: OctTreeNode; + constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number); + insert(obj: PhysicsObject): void; + find(position: Vec3, dimensions: Vec3): PhysicsObject[]; +} +export declare class OctTreeNode { + private position; + private dimensions; + private maxLevels; + private maxObjects; + objects: PhysicsObject[]; + nodes: OctTreeNode[]; + constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number); + insert(obj: PhysicsObject): void; + find(position: Vec3, dimensions: Vec3): PhysicsObject[]; + split(): void; + private distributeObjectsToNodes; + getIndex(x: number, y: number, z: number): Direction; + getIndeciesForRect(position: Vec3, dimensions: Vec3): Set; +} +declare enum Direction { + AboveUpperLeft = 0, + AboveUpperRight = 1, + AboveLowerRight = 2, + AboveLowerLeft = 3, + BelowUpperLeft = 4, + BelowUpperRight = 5, + BelowLowerRight = 6, + BelowLowerLeft = 7, + Here = 8 +} +export {}; diff --git a/src/framework/physics/octtree.js b/framework/physics/octtree.js similarity index 97% rename from src/framework/physics/octtree.js rename to framework/physics/octtree.js index 46feed5..9add88c 100644 --- a/src/framework/physics/octtree.js +++ b/framework/physics/octtree.js @@ -1,193 +1,193 @@ -import { Vec3 } from "./vec3"; -export class Octtree { - constructor(dimensions, maxObjects = 10, maxLevels = 10) { - this.dimensions = dimensions; - this.maxObjects = maxObjects; - this.maxLevels = maxLevels; - this.root = new OctTreeNode(new Vec3({ - x: 0, - y: 0, - z: 0 - }), this.dimensions, maxLevels, maxObjects); - } - insert(obj) { - this.root.insert(obj); - } - find(position, dimensions) { - return this.root.find(position, dimensions); - } -} -export class OctTreeNode { - constructor(position, dimensions, maxLevels, maxObjects) { - this.position = position; - this.dimensions = dimensions; - this.maxLevels = maxLevels; - this.maxObjects = maxObjects; - this.objects = []; - this.nodes = []; - } - insert(obj) { - this.objects.push(obj); - if (this.objects.length > this.maxObjects) { - this.split(); - } - } - find(position, dimensions) { - if (!this.nodes.length) { - return this.objects; - } - const indecies = this.getIndeciesForRect(position, dimensions); - let results = []; - indecies.forEach((index) => { - let res = this.nodes[index].find(position, dimensions); - res.forEach((obj) => results.push(obj)); - }); - return results; - } - split() { - const halfWidth = this.dimensions.x / 2; - const halfHeight = this.dimensions.y / 2; - const halfDepth = this.dimensions.z / 2; - this.nodes[Direction.AboveUpperLeft] = new OctTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.AboveUpperRight] = new OctTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.AboveLowerRight] = new OctTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y + halfHeight, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.AboveLowerLeft] = new OctTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y + halfHeight, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.BelowUpperLeft] = new OctTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.BelowUpperRight] = new OctTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.BelowLowerRight] = new OctTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y + halfHeight, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.nodes[Direction.BelowLowerLeft] = new OctTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y + halfHeight, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects); - this.distributeObjectsToNodes(); - } - distributeObjectsToNodes() { - if (this.nodes.length < 8) { - this.split(); - return; - } - this.objects.forEach((obj) => { - const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z); - this.nodes[direction].insert(obj); - }); - this.objects = []; - } - getIndex(x, y, z) { - if (this.nodes.length === 0) { - return Direction.Here; - } - const halfWidth = this.dimensions.x / 2; - const halfHeight = this.dimensions.y / 2; - const halfDepth = this.dimensions.z / 2; - const isBelow = (z < this.position.z + halfDepth); - const isLeft = (x < this.position.x + halfWidth); - const isUpper = (y > this.position.y + halfHeight); - if (isBelow) { - if (isLeft) { - if (isUpper) - return Direction.AboveUpperLeft; - else - return Direction.AboveLowerLeft; - } - else { - if (isUpper) - return Direction.AboveUpperRight; - else - return Direction.AboveLowerRight; - } - } - else { - if (isLeft) { - if (isUpper) - return Direction.BelowUpperLeft; - else - return Direction.BelowLowerLeft; - } - else { - if (isUpper) - return Direction.BelowUpperRight; - else - return Direction.BelowLowerRight; - } - } - } - getIndeciesForRect(position, dimensions) { - let indecies = new Set(); - indecies.add(this.getIndex(position.x, position.y, position.z)); - indecies.add(this.getIndex(position.x + dimensions.x, position.y + dimensions.y, position.z + dimensions.z)); - return indecies; - } -} -var Direction; -(function (Direction) { - Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft"; - Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight"; - Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight"; - Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft"; - Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft"; - Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight"; - Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight"; - Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft"; - Direction[Direction["Here"] = 8] = "Here"; -})(Direction || (Direction = {})); +import { Vec3 } from "./vec3"; +export class Octtree { + constructor(dimensions, maxObjects = 10, maxLevels = 10) { + this.dimensions = dimensions; + this.maxObjects = maxObjects; + this.maxLevels = maxLevels; + this.root = new OctTreeNode(new Vec3({ + x: 0, + y: 0, + z: 0 + }), this.dimensions, maxLevels, maxObjects); + } + insert(obj) { + this.root.insert(obj); + } + find(position, dimensions) { + return this.root.find(position, dimensions); + } +} +export class OctTreeNode { + constructor(position, dimensions, maxLevels, maxObjects) { + this.position = position; + this.dimensions = dimensions; + this.maxLevels = maxLevels; + this.maxObjects = maxObjects; + this.objects = []; + this.nodes = []; + } + insert(obj) { + this.objects.push(obj); + if (this.objects.length > this.maxObjects) { + this.split(); + } + } + find(position, dimensions) { + if (!this.nodes.length) { + return this.objects; + } + const indecies = this.getIndeciesForRect(position, dimensions); + let results = []; + indecies.forEach((index) => { + let res = this.nodes[index].find(position, dimensions); + res.forEach((obj) => results.push(obj)); + }); + return results; + } + split() { + const halfWidth = this.dimensions.x / 2; + const halfHeight = this.dimensions.y / 2; + const halfDepth = this.dimensions.z / 2; + this.nodes[Direction.AboveUpperLeft] = new OctTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.AboveUpperRight] = new OctTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.AboveLowerRight] = new OctTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y + halfHeight, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.AboveLowerLeft] = new OctTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y + halfHeight, + z: this.position.z + halfDepth + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.BelowUpperLeft] = new OctTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.BelowUpperRight] = new OctTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.BelowLowerRight] = new OctTreeNode(new Vec3({ + x: this.position.x + halfWidth, + y: this.position.y + halfHeight, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.nodes[Direction.BelowLowerLeft] = new OctTreeNode(new Vec3({ + x: this.position.x, + y: this.position.y + halfHeight, + z: this.position.z + }), new Vec3({ + x: halfWidth, + y: halfHeight, + z: halfDepth + }), this.maxLevels, this.maxObjects); + this.distributeObjectsToNodes(); + } + distributeObjectsToNodes() { + if (this.nodes.length < 8) { + this.split(); + return; + } + this.objects.forEach((obj) => { + const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z); + this.nodes[direction].insert(obj); + }); + this.objects = []; + } + getIndex(x, y, z) { + if (this.nodes.length === 0) { + return Direction.Here; + } + const halfWidth = this.dimensions.x / 2; + const halfHeight = this.dimensions.y / 2; + const halfDepth = this.dimensions.z / 2; + const isBelow = (z < this.position.z + halfDepth); + const isLeft = (x < this.position.x + halfWidth); + const isUpper = (y > this.position.y + halfHeight); + if (isBelow) { + if (isLeft) { + if (isUpper) + return Direction.AboveUpperLeft; + else + return Direction.AboveLowerLeft; + } + else { + if (isUpper) + return Direction.AboveUpperRight; + else + return Direction.AboveLowerRight; + } + } + else { + if (isLeft) { + if (isUpper) + return Direction.BelowUpperLeft; + else + return Direction.BelowLowerLeft; + } + else { + if (isUpper) + return Direction.BelowUpperRight; + else + return Direction.BelowLowerRight; + } + } + } + getIndeciesForRect(position, dimensions) { + let indecies = new Set(); + indecies.add(this.getIndex(position.x, position.y, position.z)); + indecies.add(this.getIndex(position.x + dimensions.x, position.y + dimensions.y, position.z + dimensions.z)); + return indecies; + } +} +var Direction; +(function (Direction) { + Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft"; + Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight"; + Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight"; + Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft"; + Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft"; + Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight"; + Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight"; + Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft"; + Direction[Direction["Here"] = 8] = "Here"; +})(Direction || (Direction = {})); diff --git a/src/framework/scheduler/scheduler-node.d.ts b/framework/physics/quadtree.d.ts similarity index 100% rename from src/framework/scheduler/scheduler-node.d.ts rename to framework/physics/quadtree.d.ts diff --git a/src/framework/scheduler/scheduler-node.js b/framework/physics/quadtree.js similarity index 100% rename from src/framework/scheduler/scheduler-node.js rename to framework/physics/quadtree.js diff --git a/src/framework/physics/vec3.d.ts b/framework/physics/vec3.d.ts similarity index 95% rename from src/framework/physics/vec3.d.ts rename to framework/physics/vec3.d.ts index f7f50a3..e3088ec 100644 --- a/src/framework/physics/vec3.d.ts +++ b/framework/physics/vec3.d.ts @@ -1,13 +1,13 @@ -export declare class Vec3 { - x: number; - y: number; - z: number; - constructor(values?: { - x: number; - y: number; - z: number; - }); - add(vector: Vec3): void; - multiply(vector: Vec3): void; - clone(): Vec3; -} +export declare class Vec3 { + x: number; + y: number; + z: number; + constructor(values?: { + x: number; + y: number; + z: number; + }); + add(vector: Vec3): void; + multiply(vector: Vec3): void; + clone(): Vec3; +} diff --git a/src/framework/physics/vec3.js b/framework/physics/vec3.js similarity index 95% rename from src/framework/physics/vec3.js rename to framework/physics/vec3.js index abcc389..d120c78 100644 --- a/src/framework/physics/vec3.js +++ b/framework/physics/vec3.js @@ -1,28 +1,28 @@ -export class Vec3 { - constructor(values = { - x: 0, - y: 0, - z: 0 - }) { - this.x = values.x; - this.y = values.y; - this.z = values.z; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - this.z += vector.z; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - this.z *= vector.z; - } - clone() { - return new Vec3({ - x: this.x, - y: this.y, - z: this.z - }); - } -} +export class Vec3 { + constructor(values = { + x: 0, + y: 0, + z: 0 + }) { + this.x = values.x; + this.y = values.y; + this.z = values.z; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + } + clone() { + return new Vec3({ + x: this.x, + y: this.y, + z: this.z + }); + } +} diff --git a/framework/physics/world.d.ts b/framework/physics/world.d.ts new file mode 100644 index 0000000..d1830e6 --- /dev/null +++ b/framework/physics/world.d.ts @@ -0,0 +1,23 @@ +import { Octree } from './octree'; +import { EventBus } from '../event-bus'; +import { PhysicsObject } from './object'; +import { Vec3 } from './vec3'; +export declare class World extends EventBus { + objects: PhysicsObject[]; + gravity: Vec3; + dimensions: Vec3; + octreeOptions: OctreeOptions; + constructor(dimensions: Vec3, octreeOptions: OctreeOptions); + setGravity(grav: Vec3): void; + addObject(obj: PhysicsObject): void; + removeObject(obj: PhysicsObject): void; + step(dt: number): void; + checkCollisions(obj: PhysicsObject, octree: Octree): void; +} +interface OctreeOptions { + position: Vec3; + dimensions: Vec3; + maxObjects: number; + maxLevels: number; +} +export {}; diff --git a/framework/physics/world.js b/framework/physics/world.js new file mode 100644 index 0000000..8af6c71 --- /dev/null +++ b/framework/physics/world.js @@ -0,0 +1,54 @@ +import { Octree } from './octree'; +import { EventBus } from '../event-bus'; +import { Vec3 } from './vec3'; +import { AABB } from './aabb'; +export class World extends EventBus { + constructor(dimensions, octreeOptions) { + super(); + if (!octreeOptions) { + this.octreeOptions = { + position: new Vec3({ x: 0, y: 0, z: 0 }), + dimensions: new Vec3(this.dimensions), + maxLevels: 50, + maxObjects: 50 + }; + } + else { + this.octreeOptions = octreeOptions; + } + this.dimensions = dimensions; + this.objects = []; + } + setGravity(grav) { + this.gravity = grav; + } + addObject(obj) { + this.objects.push(obj); + } + removeObject(obj) { + this.objects = this.objects.filter((val) => val !== obj); + } + step(dt) { + const octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels); + this.objects.forEach((obj) => octree.insert(obj)); + this.objects.forEach((obj) => { + let velocity = obj.velocity.clone(); + velocity.multiply(new Vec3({ x: dt, y: dt, z: dt })); + let gravity = this.gravity.clone(); + gravity.multiply(new Vec3({ x: dt, y: dt, z: dt })); + obj.position.add(velocity); + if (obj.affectedByGravity) { + obj.velocity.add(gravity); + } + this.checkCollisions(obj, octree); + }); + } + checkCollisions(obj, octree) { + const potentialCandidates = octree.find(obj.position, obj.dimensions); + potentialCandidates.forEach((candidate) => { + if (AABB(obj, candidate)) { + this.emit('collision', [obj, candidate]); + } + }); + } +} diff --git a/framework/resonator/audio-context.d.ts b/framework/resonator/audio-context.d.ts new file mode 100644 index 0000000..e9db8e2 --- /dev/null +++ b/framework/resonator/audio-context.d.ts @@ -0,0 +1,11 @@ +export default class ResonatorAudioContext { + private context; + constructor(); + getContext(): AudioContext; + createGain(): any; + getOutputDestination(): AudioNode; + createBufferSource(): AudioBufferSourceNode; + decodeAudioData(data: ArrayBuffer): Promise; + createPanner(): any; + createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode; +} diff --git a/framework/resonator/audio-context.js b/framework/resonator/audio-context.js new file mode 100644 index 0000000..04d65e5 --- /dev/null +++ b/framework/resonator/audio-context.js @@ -0,0 +1,39 @@ +// simple wrapper around the AudioContext +// eventually will be used to deal with cross browser issues +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export default class ResonatorAudioContext { + constructor() { + this.context = new AudioContext(); + } + getContext() { + return this.context; + } + createGain() { + return this.context.createGain(); + } + getOutputDestination() { + return this.context.destination; + } + createBufferSource() { + return this.context.createBufferSource(); + } + decodeAudioData(data) { + return __awaiter(this, void 0, void 0, function* () { + return yield this.context.decodeAudioData(data); + }); + } + createPanner() { + return this.context.createPanner(); + } + createMediaElementSource(element) { + return this.context.createMediaElementSource(element); + } +} diff --git a/framework/resonator/audio-graph.d.ts b/framework/resonator/audio-graph.d.ts new file mode 100644 index 0000000..f0f3674 --- /dev/null +++ b/framework/resonator/audio-graph.d.ts @@ -0,0 +1,21 @@ +import ResonatorScene from './scenes/webaudio-scene'; +import ResonatorAudioContext from './audio-context'; +import BaseEffect from './effects/base-effect'; +export default class AudioGraph { + private master; + private effectsBus; + private worldBus; + private secondaryBus; + private effects; + private scene; + private context; + private swapChannels; + private channelSplitter; + private channelMerger; + constructor(scene: ResonatorScene, context: ResonatorAudioContext, swapChannels?: boolean); + init(): void; + connectToMaster(input: any): void; + connectToUI(input: AudioNode): void; + applyEffect(effect: BaseEffect): void; + removeEffect(effect: BaseEffect): void; +} diff --git a/framework/resonator/audio-graph.js b/framework/resonator/audio-graph.js new file mode 100644 index 0000000..2ce66b0 --- /dev/null +++ b/framework/resonator/audio-graph.js @@ -0,0 +1,46 @@ +// this is the mixer that takes all the different outputs and mixes them into the 2 busses: +// WorldBus: The directional audio +// SecondaryBus: All the UI and things that are non directional +import EffectChain from './effect-chain'; +export default class AudioGraph { + constructor(scene, context, swapChannels = false) { + this.scene = scene; + this.context = context; + this.swapChannels = swapChannels; + this.init(); + } + init() { + this.effectsBus = this.context.createGain(); + this.worldBus = this.context.createGain(); + this.secondaryBus = this.context.createGain(); + this.master = this.context.createGain(); + this.scene.getOutput().connect(this.worldBus); + // this.worldBus.connect(this.master); + this.worldBus.connect(this.effectsBus); + this.effects = new EffectChain(this.context, this, this.effectsBus, this.master); + this.secondaryBus.connect(this.master); + if (this.swapChannels) { + this.channelSplitter = this.context.getContext().createChannelSplitter(2); + this.channelMerger = this.context.getContext().createChannelMerger(2); + this.master.connect(this.channelSplitter); + this.channelSplitter.connect(this.channelMerger, 0, 1); + this.channelSplitter.connect(this.channelMerger, 1, 0); + this.channelMerger.connect(this.context.getOutputDestination()); + } + else { + this.master.connect(this.context.getOutputDestination()); + } + } + connectToMaster(input) { + input.connect(this.master); + } + connectToUI(input) { + input.connect(this.secondaryBus); + } + applyEffect(effect) { + this.effects.applyEffect(effect); + } + removeEffect(effect) { + this.effects.removeEffect(effect); + } +} diff --git a/framework/resonator/data-pool-item.d.ts b/framework/resonator/data-pool-item.d.ts new file mode 100644 index 0000000..0275059 --- /dev/null +++ b/framework/resonator/data-pool-item.d.ts @@ -0,0 +1,12 @@ +export default class DataPoolItem { + private name; + private data; + private decodedData; + constructor(name: string, data?: any, decodedData?: any); + getData(): any; + setData(data: any): void; + getDecodedData(): any; + setDecodedData(data: any): void; + getName(): string; + setName(name: string): void; +} diff --git a/framework/resonator/data-pool-item.js b/framework/resonator/data-pool-item.js new file mode 100644 index 0000000..9dcf647 --- /dev/null +++ b/framework/resonator/data-pool-item.js @@ -0,0 +1,26 @@ +// An item in the data pool +export default class DataPoolItem { + constructor(name, data = null, decodedData = null) { + this.name = name; + this.data = data; + this.decodedData = decodedData; + } + getData() { + return this.data; + } + setData(data) { + this.data = data; + } + getDecodedData() { + return this.decodedData; + } + setDecodedData(data) { + this.decodedData = this.decodedData; + } + getName() { + return this.name; + } + setName(name) { + this.name = name; + } +} diff --git a/framework/resonator/data-pool.d.ts b/framework/resonator/data-pool.d.ts new file mode 100644 index 0000000..5282442 --- /dev/null +++ b/framework/resonator/data-pool.d.ts @@ -0,0 +1,12 @@ +import EventEmitter from 'eventemitter3'; +import ResonatorAudioContext from './audio-context'; +import { BaseLoader } from './loaders/base-loader'; +export default class DataPool extends EventEmitter { + private loader; + private data; + private maxData; + private context; + constructor(context: ResonatorAudioContext, loader?: BaseLoader, maxData?: number); + get(path: string): Promise; + clear(): void; +} diff --git a/framework/resonator/data-pool.js b/framework/resonator/data-pool.js new file mode 100644 index 0000000..5263d4a --- /dev/null +++ b/framework/resonator/data-pool.js @@ -0,0 +1,48 @@ +// a data pool holds frequently played sounds in memory together with decoded audio data to no longer have to decode them from the cache when loaded again +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import EventEmitter from 'eventemitter3'; +import DataPoolItem from './data-pool-item'; +import { HTTPLoader } from './loaders/http-loader'; +export default class DataPool extends EventEmitter { + constructor(context, loader = new HTTPLoader(), maxData = 512) { + super(); + this.loader = loader; + this.data = {}; + this.maxData = maxData; + this.context = context; + } + get(path) { + return __awaiter(this, void 0, void 0, function* () { + if (this.data[path]) { + return this.data[path].getDecodedData(); + } + else { + const buffer = yield this.loader.get(path); + const decoded = yield this.context.decodeAudioData(buffer); + const item = new DataPoolItem(path, buffer, decoded); + const length = Object.keys(this.data).length; + if (length < this.maxData) { + this.data[path] = item; + } + else { + // TODO: figure out a more clever solution than just removing the first loaded data. Like tracking how much certain data is needed and prioritize them. + // const paths: string[] = Object.keys(this.data); + // delete this.data[paths[0]]; + this.data[path] = item; + } + return item.getDecodedData(); + } + }); + } + clear() { + this.data = {}; + } +} diff --git a/framework/resonator/effect-bus.d.ts b/framework/resonator/effect-bus.d.ts new file mode 100644 index 0000000..57fbb3d --- /dev/null +++ b/framework/resonator/effect-bus.d.ts @@ -0,0 +1,8 @@ +import ResonatorAudioContext from './audio-context'; +export default class EffectBus { + private context; + private inputNode; + private channelMerger; + constructor(context: ResonatorAudioContext, input: AudioNode, output: AudioNode); + connect(node: AudioNode): void; +} diff --git a/framework/resonator/effect-bus.js b/framework/resonator/effect-bus.js new file mode 100644 index 0000000..49fd849 --- /dev/null +++ b/framework/resonator/effect-bus.js @@ -0,0 +1,12 @@ +// Currently unused, but eventually all the effect stuff will be moved from audio graph to here to make it easier to work on +export default class EffectBus { + constructor(context, input, output) { + this.context = context; + this.inputNode = input; + this.channelMerger = this.context.getContext().createChannelMerger(1); + this.inputNode.connect(this.channelMerger); + } + connect(node) { + this.channelMerger.connect(node); + } +} diff --git a/framework/resonator/effect-chain.d.ts b/framework/resonator/effect-chain.d.ts new file mode 100644 index 0000000..1e235c6 --- /dev/null +++ b/framework/resonator/effect-chain.d.ts @@ -0,0 +1,14 @@ +import ResonatorAudioContext from './audio-context'; +import AudioGraph from './audio-graph'; +import BaseEffect from './effects/base-effect'; +export default class EffectChain { + private context; + private graph; + private effects; + private inputNode; + private outputNode; + constructor(context: ResonatorAudioContext, graph: AudioGraph, input: AudioNode, output: AudioNode); + applyEffect(effect: BaseEffect): void; + removeEffect(effect: BaseEffect): void; + private updateConnections; +} diff --git a/framework/resonator/effect-chain.js b/framework/resonator/effect-chain.js new file mode 100644 index 0000000..17c3d6b --- /dev/null +++ b/framework/resonator/effect-chain.js @@ -0,0 +1,45 @@ +// A chain of effects that connect to the effect bus +export default class EffectChain { + constructor(context, graph, input, output) { + this.effects = []; + this.context = context; + this.graph = graph; + this.inputNode = input; + this.outputNode = output; + this.updateConnections(); + } + applyEffect(effect) { + this.effects.push(effect); + this.updateConnections(); + } + removeEffect(effect) { + this.effects.forEach((currEffect) => { + if (effect === currEffect) { + currEffect.disconnect(); + } + }); + this.effects = this.effects.filter((currEffect) => effect !== currEffect); + this.updateConnections(); + } + updateConnections() { + if (this.effects.length == 0) { + this.inputNode.connect(this.outputNode); + return; + } + let current = null; + let previous = null; + this.effects.forEach((effect) => { + current = effect; + if (previous) { + current.connectInput(previous.getOutput()); + } + else { + current.connectInput(this.inputNode); + } + previous = current; + }); + if (current) { + current.connectOutput(this.outputNode); + } + } +} diff --git a/framework/resonator/effects/base-effect.d.ts b/framework/resonator/effects/base-effect.d.ts new file mode 100644 index 0000000..7233383 --- /dev/null +++ b/framework/resonator/effects/base-effect.d.ts @@ -0,0 +1,15 @@ +import ResonatorAudioContext from '../audio-context'; +import AudioGraph from '../audio-graph'; +export default class BaseEffect { + protected ready: boolean; + protected effectNode: any; + protected effectParams: any; + protected context: ResonatorAudioContext; + protected graph: AudioGraph; + protected inputNode: AudioNode; + constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any); + connectOutput(node: AudioNode): void; + connectInput(node: AudioNode): void; + getOutput(): AudioNode; + disconnect(): void; +} diff --git a/framework/resonator/effects/base-effect.js b/framework/resonator/effects/base-effect.js new file mode 100644 index 0000000..e2c04b8 --- /dev/null +++ b/framework/resonator/effects/base-effect.js @@ -0,0 +1,23 @@ +export default class BaseEffect { + constructor(context, graph, params) { + this.graph = graph; + this.context = context; + this.effectParams = params; + } + connectOutput(node) { + this.effectNode.connect(node); + } + connectInput(node) { + this.inputNode = node; + if (this.effectNode) { + this.inputNode.connect(this.effectNode); + } + } + getOutput() { + return this.effectNode; + } + disconnect() { + this.inputNode.disconnect(); + this.effectNode.disconnect(); + } +} diff --git a/framework/resonator/effects/convolver.d.ts b/framework/resonator/effects/convolver.d.ts new file mode 100644 index 0000000..be6abb9 --- /dev/null +++ b/framework/resonator/effects/convolver.d.ts @@ -0,0 +1,10 @@ +import BaseEffect from './base-effect'; +import ResonatorAudioContext from '../audio-context'; +import AudioGraph from '../audio-graph'; +export default class Convolver extends BaseEffect { + private buffer; + private channelSplitter; + private channelMerger; + constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any); + connectInput(node: AudioNode): void; +} diff --git a/framework/resonator/effects/convolver.js b/framework/resonator/effects/convolver.js new file mode 100644 index 0000000..2b798fd --- /dev/null +++ b/framework/resonator/effects/convolver.js @@ -0,0 +1,20 @@ +import BaseEffect from './base-effect'; +export default class Convolver extends BaseEffect { + constructor(context, graph, params) { + super(context, graph, params); + console.log(`Creating convolver`); + this.effectNode = this.context.getContext().createConvolver(); + this.effectNode.buffer = this.effectParams.buffer; + } + connectInput(node) { + this.channelSplitter = this.context.getContext().createChannelSplitter(2); + this.channelMerger = this.context.getContext().createChannelMerger(2); + this.channelSplitter.connect(this.channelMerger, 0, 0); + this.channelSplitter.connect(this.channelMerger, 1, 0); + this.channelSplitter.connect(this.channelMerger, 0, 1); + this.channelSplitter.connect(this.channelMerger, 1, 1); + node.connect(this.channelSplitter); + this.channelMerger.connect(this.effectNode); + this.inputNode = node; + } +} diff --git a/framework/resonator/index.d.ts b/framework/resonator/index.d.ts new file mode 100644 index 0000000..a9fd891 --- /dev/null +++ b/framework/resonator/index.d.ts @@ -0,0 +1,22 @@ +import AudioSource from './sources/audio-source'; +import { BaseLoader } from './loaders/base-loader'; +import { BaseSource } from './sources/base-source'; +import { SourceType } from './sources/source-type'; +import { StreamingSource } from './sources/streaming-source'; +export default class Resonator { + private loader; + private context; + private scene; + private graph; + private dataPool; + private environmentImpulse; + constructor(loader?: BaseLoader); + load(path: string, type?: SourceType): Promise; + loadImmediate(path: string, type?: SourceType): AudioSource; + stream(path: string, type?: SourceType): StreamingSource; + private createSource; + setEnvironmentImpulse(file: string): Promise; + setListenerPosition(x: number, y: number, z: number): void; + setListenerOrientation(forward: any, up: any): void; + clearDataPool(): void; +} diff --git a/framework/resonator/index.js b/framework/resonator/index.js new file mode 100644 index 0000000..260bb81 --- /dev/null +++ b/framework/resonator/index.js @@ -0,0 +1,78 @@ +// the main module for Resonator +// API, etc. +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ResonatorAudioContext from './audio-context'; +import ResonatorScene from './scenes/webaudio-scene'; +import AudioGraph from './audio-graph'; +import AudioSource from './sources/audio-source'; +import DataPool from './data-pool'; +import Convolver from './effects/convolver'; +import { HTTPLoader } from './loaders/http-loader'; +import { SourceType } from './sources/source-type'; +import { StreamingSource } from './sources/streaming-source'; +export default class Resonator { + constructor(loader = new HTTPLoader()) { + this.loader = loader; + this.environmentImpulse = null; + this.context = new ResonatorAudioContext(); + this.scene = new ResonatorScene(this.context); + this.graph = new AudioGraph(this.scene, this.context, false); + this.dataPool = new DataPool(this.context, this.loader); + } + load(path, type = SourceType.WorldSource) { + return __awaiter(this, void 0, void 0, function* () { + const data = yield this.dataPool.get(path); + const source = this.createSource(type, data); + return source; + }); + } + loadImmediate(path, type = SourceType.WorldSource) { + const source = new AudioSource(this.graph, this.scene, this.context, null, type); + this.dataPool.get(path).then((data) => { + source.setBuffer(data); + }); + return source; + } + stream(path, type = SourceType.MasterSource) { + const element = new Audio(path); + element.crossOrigin = 'anonymous'; + element.volume = 1; + const source = new StreamingSource(this.graph, this.scene, this.context, element, type); + return source; + } + createSource(type, data) { + return new AudioSource(this.graph, this.scene, this.context, data); + } + setEnvironmentImpulse(file) { + return __awaiter(this, void 0, void 0, function* () { + if (this.environmentImpulse) { + this.graph.removeEffect(this.environmentImpulse); + } + if (file === null) { + return; + } + const buffer = yield this.dataPool.get(file); + this.environmentImpulse = new Convolver(this.context, this.graph, { + buffer + }); + this.graph.applyEffect(this.environmentImpulse); + }); + } + setListenerPosition(x, y, z) { + this.scene.setListenerPosition(x, y, z); + } + setListenerOrientation(forward, up) { + this.scene.setListenerOrientation(forward, up); + } + clearDataPool() { + this.dataPool.clear(); + } +} diff --git a/framework/resonator/loaders/asset-loader.d.ts b/framework/resonator/loaders/asset-loader.d.ts new file mode 100644 index 0000000..d3e4641 --- /dev/null +++ b/framework/resonator/loaders/asset-loader.d.ts @@ -0,0 +1,10 @@ +import { AssetManager } from '../../asset-manager'; +import { BaseLoader } from './base-loader'; +export declare class AssetLoader implements BaseLoader { + private name; + private manager; + private assetManager; + constructor(name: string, manager?: AssetManager); + init(): Promise; + get(path: string): Promise; +} diff --git a/framework/resonator/loaders/asset-loader.js b/framework/resonator/loaders/asset-loader.js new file mode 100644 index 0000000..dddc759 --- /dev/null +++ b/framework/resonator/loaders/asset-loader.js @@ -0,0 +1,36 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +// TODO fix path when actually properly linking the packages together +import { AssetManager } from '../../asset-manager'; +export class AssetLoader { + constructor(name, manager = null) { + this.name = name; + this.manager = manager; + if (manager) { + this.assetManager = manager; + } + else { + this.assetManager = new AssetManager(name, ''); + } + } + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this.assetManager.init(); + }); + } + get(path) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.assetManager.downloadFile(path); + console.log(result); + const buffer = yield result.arrayBuffer(); + return buffer; + }); + } +} diff --git a/framework/resonator/loaders/base-loader.d.ts b/framework/resonator/loaders/base-loader.d.ts new file mode 100644 index 0000000..90a7c66 --- /dev/null +++ b/framework/resonator/loaders/base-loader.d.ts @@ -0,0 +1,3 @@ +export interface BaseLoader { + get(path: string): Promise; +} diff --git a/framework/resonator/loaders/base-loader.js b/framework/resonator/loaders/base-loader.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/resonator/loaders/base-loader.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/resonator/loaders/http-loader.d.ts b/framework/resonator/loaders/http-loader.d.ts new file mode 100644 index 0000000..c38c282 --- /dev/null +++ b/framework/resonator/loaders/http-loader.d.ts @@ -0,0 +1,4 @@ +import { BaseLoader } from './base-loader'; +export declare class HTTPLoader implements BaseLoader { + get(path: string): Promise; +} diff --git a/framework/resonator/loaders/http-loader.js b/framework/resonator/loaders/http-loader.js new file mode 100644 index 0000000..06f7dbf --- /dev/null +++ b/framework/resonator/loaders/http-loader.js @@ -0,0 +1,18 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export class HTTPLoader { + get(path) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield fetch(path); + const buffer = yield result.arrayBuffer(); + return buffer; + }); + } +} diff --git a/framework/resonator/scenes/resonance-scene.d.ts b/framework/resonator/scenes/resonance-scene.d.ts new file mode 100644 index 0000000..761223f --- /dev/null +++ b/framework/resonator/scenes/resonance-scene.d.ts @@ -0,0 +1,14 @@ +import ResonatorAudioContext from '../audio-context'; +import EventEmitter from 'eventemitter3'; +export default class Scene extends EventEmitter { + scene: any; + context: ResonatorAudioContext; + listener: AudioListener; + constructor(context: ResonatorAudioContext); + init(): void; + createSource(): any; + getOutput(): any; + getInput(): any; + setListenerPosition(x: number, y: number, z: number): void; + setListenerOrientation(forward: any, rawup: any): void; +} diff --git a/framework/resonator/scenes/resonance-scene.js b/framework/resonator/scenes/resonance-scene.js new file mode 100644 index 0000000..b0f6baa --- /dev/null +++ b/framework/resonator/scenes/resonance-scene.js @@ -0,0 +1,40 @@ +// The code that deals with 3d audio +import ResonanceAudio from '../vendor/resonance-es6/main'; +import EventEmitter from 'eventemitter3'; +import vec3 from '../../tsm/vec3'; +export default class Scene extends EventEmitter { + constructor(context) { + super(); + this.context = context; + this.scene = new ResonanceAudio(this.context.getContext(), { + ambisonicOrder: 3 + }); + this.listener = this.context.getContext().listener; + this.init(); + } + init() { + // this.scene.output.connect(this.context.getOutputDestination()); + } + createSource() { + const source = this.scene.createSource(); + return Object.assign(Object.assign({}, source), { getInput: () => source.input }); + } + getOutput() { + return this.scene.output; + } + getInput() { + return this.scene.input; + } + setListenerPosition(x, y, z) { + this.scene.setListenerPosition(x, y, z); + } + setListenerOrientation(forward, rawup) { + let fwd = new vec3([forward.x, forward.y, forward.z]); + let up = fwd.copy(); + vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up); + vec3.cross(up, fwd, up); + fwd.normalize(); + up.normalize(); + this.scene.setListenerOrientation(forward.x, forward.y, forward.z, rawup.x, rawup.y, rawup.z); + } +} diff --git a/framework/resonator/scenes/webaudio-scene.d.ts b/framework/resonator/scenes/webaudio-scene.d.ts new file mode 100644 index 0000000..d7d9bca --- /dev/null +++ b/framework/resonator/scenes/webaudio-scene.d.ts @@ -0,0 +1,14 @@ +import ResonatorAudioContext from '../audio-context'; +import EventEmitter from 'eventemitter3'; +export default class ResonatorScene extends EventEmitter { + scene: GainNode; + context: ResonatorAudioContext; + listener: AudioListener; + constructor(context: ResonatorAudioContext); + init(): void; + createSource(): any; + getOutput(): any; + getInput(): any; + setListenerPosition(x: number, y: number, z: number): void; + setListenerOrientation(forward: any, rawup: any): void; +} diff --git a/framework/resonator/scenes/webaudio-scene.js b/framework/resonator/scenes/webaudio-scene.js new file mode 100644 index 0000000..7d50490 --- /dev/null +++ b/framework/resonator/scenes/webaudio-scene.js @@ -0,0 +1,42 @@ +// The code that deals with 3d audio +import EventEmitter from 'eventemitter3'; +import vec3 from '../../tsm/vec3'; +export default class ResonatorScene extends EventEmitter { + constructor(context) { + super(); + this.context = context; + this.scene = this.context.getContext().createGain(); + this.listener = this.context.getContext().listener; + this.init(); + } + init() { + // this.scene.output.connect(this.context.getOutputDestination()); + } + createSource() { + const node = this.context.getContext().createPanner(); + node.panningModel = 'HRTF'; + node.distanceModel = 'linear'; + node.maxDistance = 20; + node.refDistance = 2; + node.connect(this.scene); + return node; + } + getOutput() { + return this.scene; + } + getInput() { + return this.scene; + } + setListenerPosition(x, y, z) { + this.listener.setPosition(x, y, z); + } + setListenerOrientation(forward, rawup) { + let fwd = new vec3([forward.x, forward.y, forward.z]); + let up = fwd.copy(); + vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up); + vec3.cross(up, fwd, up); + fwd.normalize(); + up.normalize(); + this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z); + } +} diff --git a/framework/resonator/sources/audio-source.d.ts b/framework/resonator/sources/audio-source.d.ts new file mode 100644 index 0000000..15a3c98 --- /dev/null +++ b/framework/resonator/sources/audio-source.d.ts @@ -0,0 +1,37 @@ +import ResonatorAudioContext from '../audio-context'; +import AudioGraph from '../audio-graph'; +import ResonatorScene from '../scenes/webaudio-scene'; +import { BaseSource } from './base-source'; +import { SourceType } from './source-type'; +export default class AudioSource implements BaseSource { + playing: boolean; + looping: boolean; + private node; + private sceneNode; + private buffer; + private context; + private graph; + private scene; + private playOnLoad; + private position; + private playbackRate; + private volume; + private gain; + private type; + constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType); + init(): void; + getBuffer(): AudioBuffer; + setBuffer(data: AudioBuffer): void; + play(when?: number, offset?: number, duration?: number): void; + setPosition(x: number, y: number, z: number): void; + setPlaybackRate(rate: number): void; + getPlaybackRate(): number; + setVolume(volume: number): void; + getVolume(): number; + private createConnections; + stop(): void; + destroy(): void; + loop(value: boolean): void; + fadeOut(time: number): void; + fadeIn(time: number): void; +} diff --git a/framework/resonator/sources/audio-source.js b/framework/resonator/sources/audio-source.js new file mode 100644 index 0000000..9ac0384 --- /dev/null +++ b/framework/resonator/sources/audio-source.js @@ -0,0 +1,148 @@ +// an audio source +// This is the actual sound +import { SourceType } from './source-type'; +export default class AudioSource { + constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) { + this.position = { + x: 0, + y: 0, + z: 0 + }; + this.buffer = buffer; + this.context = context; + this.scene = scene; + this.graph = graph; + this.type = type; + this.playbackRate = 1; + this.volume = 1; + this.init(); + } + init() { + this.gain = this.context.createGain(); + // bind methods so we can add and removve them from event listeners + this.stop = this.stop.bind(this); + } + getBuffer() { + return this.buffer; + } + setBuffer(data) { + this.buffer = data; + if (this.playOnLoad) { + this.play(); + this.playOnLoad = false; + } + } + play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) { + if (this.playing && this.node) { + this.stop(); + } + if (!this.buffer) { + this.playOnLoad = true; + return; + } + if (!this.node) { + this.node = this.context.createBufferSource(); + this.node.buffer = this.buffer; + this.createConnections(); + } + if (this.node) { + this.node.playbackRate.value = this.playbackRate; + this.node.start(when, offset, duration); + this.node.loop = this.looping; + this.playing = true; + if (this.sceneNode) { + this.sceneNode.setPosition(this.position.x, this.position.y, this.position.z); + } + this.node.addEventListener('ended', this.stop); + } + } + setPosition(x, y, z) { + this.position = { + x, + y, + z + }; + if (this.sceneNode) + this.sceneNode.setPosition(x, y, z); + } + setPlaybackRate(rate) { + this.playbackRate = rate; + if (this.node) + this.node.playbackRate.value = rate; + } + getPlaybackRate() { + return this.playbackRate; + } + setVolume(volume) { + this.volume = volume; + if (this.gain) + this.gain.gain.value = volume; + } + getVolume() { + return this.volume; + } + createConnections() { + switch (this.type) { + case SourceType.WorldSource: + if (!this.sceneNode) { + this.sceneNode = this.scene.createSource(); + } + this.node.connect(this.gain); + this.gain.connect(this.sceneNode); + break; + case SourceType.UISource: + this.node.connect(this.gain); + this.graph.connectToUI(this.gain); + break; + default: + this.node.connect(this.gain); + this.graph.connectToMaster(this.gain); + break; + } + } + stop() { + this.playing = false; + if (this.node) { + this.node.removeEventListener('ended', this.stop); + this.node.stop(); + this.node.disconnect(); + this.node = null; + this.playing = false; + if (this.sceneNode) { + this.sceneNode.disconnect(); + this.sceneNode = null; + } + } + } + destroy() { + this.stop(); + // set all refs to null to encourage gc + this.node = null; + this.sceneNode = null; + this.buffer = null; + this.context = null; + this.graph = null; + this.scene = null; + } + loop(value) { + this.looping = value; + if (this.node) { + this.node.loop = value; + } + } + fadeOut(time) { + this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime); + if (!this.node) { + return; + } + this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time); + setTimeout(() => this.stop(), time * 1000); + } + fadeIn(time) { + this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime); + if (!this.node) { + this.play(); + } + this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time); + } +} diff --git a/framework/resonator/sources/base-source.d.ts b/framework/resonator/sources/base-source.d.ts new file mode 100644 index 0000000..b325114 --- /dev/null +++ b/framework/resonator/sources/base-source.d.ts @@ -0,0 +1,12 @@ +export interface BaseSource { + play(when: number, offset: number, duration: number): void; + stop(): void; + setPlaybackRate(value: number): void; + getPlaybackRate(): number; + setVolume(value: number): void; + getVolume(): number; + loop(value: boolean): void; + fadeOut(time: number): void; + fadeIn(time: number): void; + destroy(): void; +} diff --git a/framework/resonator/sources/base-source.js b/framework/resonator/sources/base-source.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/resonator/sources/base-source.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/resonator/sources/source-type.d.ts b/framework/resonator/sources/source-type.d.ts new file mode 100644 index 0000000..a704b33 --- /dev/null +++ b/framework/resonator/sources/source-type.d.ts @@ -0,0 +1,5 @@ +export declare enum SourceType { + WorldSource = 0, + UISource = 1, + MasterSource = 2 +} diff --git a/framework/resonator/sources/source-type.js b/framework/resonator/sources/source-type.js new file mode 100644 index 0000000..b220487 --- /dev/null +++ b/framework/resonator/sources/source-type.js @@ -0,0 +1,6 @@ +export var SourceType; +(function (SourceType) { + SourceType[SourceType["WorldSource"] = 0] = "WorldSource"; + SourceType[SourceType["UISource"] = 1] = "UISource"; + SourceType[SourceType["MasterSource"] = 2] = "MasterSource"; +})(SourceType || (SourceType = {})); diff --git a/framework/resonator/sources/streaming-source.d.ts b/framework/resonator/sources/streaming-source.d.ts new file mode 100644 index 0000000..a8d6527 --- /dev/null +++ b/framework/resonator/sources/streaming-source.d.ts @@ -0,0 +1,33 @@ +import { BaseSource } from './base-source'; +import AudioGraph from '../audio-graph'; +import ResonatorScene from '../scenes/webaudio-scene'; +import ResonatorAudioContext from '../audio-context'; +import { SourceType } from './source-type'; +export declare class StreamingSource implements BaseSource { + private graph; + private scene; + private context; + private element; + private type; + playing: boolean; + private playOnAvailable; + private node; + private canPlay; + private sceneNode; + private gain; + private position; + constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType); + private init; + play(when?: number, offset?: number, duration?: number): void; + stop(): void; + getVolume(): number; + setVolume(value: number): void; + getPlaybackRate(): number; + setPlaybackRate(value: number): void; + private createConnections; + setPosition(x: number, y: number, z: number): void; + destroy(): void; + loop(value: boolean): void; + fadeIn(time: number): void; + fadeOut(time: number): void; +} diff --git a/framework/resonator/sources/streaming-source.js b/framework/resonator/sources/streaming-source.js new file mode 100644 index 0000000..e75889c --- /dev/null +++ b/framework/resonator/sources/streaming-source.js @@ -0,0 +1,99 @@ +import { SourceType } from './source-type'; +export class StreamingSource { + constructor(graph, scene, context, element, type = SourceType.MasterSource) { + this.graph = graph; + this.scene = scene; + this.context = context; + this.element = element; + this.type = type; + this.position = { + x: 0, + y: 0, + z: 0 + }; + this.init(); + } + init() { + this.node = this.context.createMediaElementSource(this.element); + this.gain = this.context.createGain(); + this.createConnections(); + this.element.addEventListener('canplay', (event) => { + this.canPlay = true; + if (this.playOnAvailable) { + this.play(); + } + }); + } + play(when = 0, offset = 0, duration = 0) { + if (this.canPlay) { + this.element.play(); + } + this.playOnAvailable = true; + } + stop() { + this.element.pause(); + } + getVolume() { + return this.element.volume; + } + setVolume(value) { + this.element.volume = value; + } + getPlaybackRate() { + return this.element.playbackRate; + } + setPlaybackRate(value) { + this.element.playbackRate = value; + } + createConnections() { + switch (this.type) { + case SourceType.WorldSource: + if (!this.sceneNode) { + this.sceneNode = this.scene.createSource(); + } + this.node.connect(this.gain); + this.gain.connect(this.sceneNode); + break; + default: + this.node.connect(this.gain); + this.graph.connectToMaster(this.gain); + break; + } + } + setPosition(x, y, z) { + this.position = { + x, + y, + z + }; + if (this.sceneNode) + this.sceneNode.setPosition(x, y, z); + } + destroy() { + this.stop(); + this.element = null; + this.graph = null; + this.context = null; + this.node = null; + this.sceneNode = null; + this.scene = null; + } + loop(value) { + this.element.loop = true; + } + fadeIn(time) { + this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime); + if (!this.node) { + this.play(); + } + this.gain.gain.exponentialRampToValueAtTime(this.getVolume(), this.context.getContext().currentTime + time); + } + fadeOut(time) { + this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime); + if (!this.node) { + return; + } + this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time); + setTimeout(() => this.stop(), time * 1000); + } +} diff --git a/framework/resonator/vendor/resonance-es6/attenuation.d.ts b/framework/resonator/vendor/resonance-es6/attenuation.d.ts new file mode 100644 index 0000000..267fdbe --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/attenuation.d.ts @@ -0,0 +1,40 @@ +export default Attenuation; +/** + * @class Attenuation + * @description Distance-based attenuation filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @param {Number} options.maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @param {string} options.rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + */ +declare class Attenuation { + constructor(context: any, options: any); + minDistance: any; + maxDistance: any; + _gainNode: any; + input: any; + output: any; + /** + * Set distance from the listener. + * @param {Number} distance Distance (in meters). + */ + setDistance(distance: number): void; + /** + * Set rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff: string): void; + _rolloff: string; +} diff --git a/framework/resonator/vendor/resonance-es6/attenuation.js b/framework/resonator/vendor/resonance-es6/attenuation.js new file mode 100644 index 0000000..88f8cbd --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/attenuation.js @@ -0,0 +1,151 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Distance-based attenuation filter. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class Attenuation + * @description Distance-based attenuation filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @param {Number} options.maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @param {string} options.rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + */ +class Attenuation { + constructor(context, options) { + // Public variables. + /** + * Min. distance (in meters). + * @member {Number} minDistance + * @memberof Attenuation + * @instance + */ + /** + * Max. distance (in meters). + * @member {Number} maxDistance + * @memberof Attenuation + * @instance + */ + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Attenuation + * @instance + */ + /** + * Mono (1-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Attenuation + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.minDistance == undefined) { + options.minDistance = Utils.DEFAULT_MIN_DISTANCE; + } + if (options.maxDistance == undefined) { + options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; + } + if (options.rolloff == undefined) { + options.rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; + } + // Assign values. + this.minDistance = options.minDistance; + this.maxDistance = options.maxDistance; + this.setRolloff(options.rolloff); + // Create node. + this._gainNode = context.createGain(); + // Initialize distance to max distance. + this.setDistance(options.maxDistance); + // Input/Output proxy. + this.input = this._gainNode; + this.output = this._gainNode; + } + /** + * Set distance from the listener. + * @param {Number} distance Distance (in meters). + */ + setDistance(distance) { + let gain = 1; + if (this._rolloff == 'logarithmic') { + if (distance > this.maxDistance) { + gain = 0; + } + else if (distance > this.minDistance) { + let range = this.maxDistance - this.minDistance; + if (range > Utils.EPSILON_FLOAT) { + // Compute the distance attenuation value by the logarithmic curve + // "1 / (d + 1)" with an offset of |minDistance|. + let relativeDistance = distance - this.minDistance; + let attenuation = 1 / (relativeDistance + 1); + let attenuationMax = 1 / (range + 1); + gain = (attenuation - attenuationMax) / (1 - attenuationMax); + } + } + } + else if (this._rolloff == 'linear') { + if (distance > this.maxDistance) { + gain = 0; + } + else if (distance > this.minDistance) { + let range = this.maxDistance - this.minDistance; + if (range > Utils.EPSILON_FLOAT) { + gain = (this.maxDistance - distance) / range; + } + } + } + this._gainNode.gain.value = gain; + } + /** + * Set rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff) { + let isValidModel = ~Utils.ATTENUATION_ROLLOFFS.indexOf(rolloff); + if (rolloff == undefined || !isValidModel) { + if (!isValidModel) { + Utils.log('Invalid rolloff model (\"' + rolloff + + '\"). Using default: \"' + Utils.DEFAULT_ATTENUATION_ROLLOFF + '\".'); + } + rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; + } + else { + rolloff = rolloff.toString().toLowerCase(); + } + this._rolloff = rolloff; + } +} +export default Attenuation; diff --git a/framework/resonator/vendor/resonance-es6/d.d.ts b/framework/resonator/vendor/resonance-es6/d.d.ts new file mode 100644 index 0000000..dbe531d --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/d.d.ts @@ -0,0 +1,217 @@ +declare module 'resonance-audio' { + namespace ResonanceAudio { + /** Options for constructing a new ResonanceAudio scene */ + interface Options { + /** Desired ambisonic Order */ + ambisonicOrder?: number; + /** The listener's initial position (in meters), where origin is the center of + * the room */ + listenerPosition?: Float32Array; + /** The listener's initial forward vector */ + listenerForward?: Float32Array; + /** The listener's initial up vector */ + listenerUp?: Float32Array; + /** Room dimensions (in meters) */ + dimensions?: Utils.RoomDimensions; + /** Named acoustic materials per wall */ + materials?: Utils.RoomMaterials; + /** (in meters/second) */ + speedOfSound?: number; + } + } + /** Main class for managing sources, room and listener models */ + class ResonanceAudio { + /** Binaurally-rendered stereo (2-channel) output */ + output: AudioNode; + /** Ambisonic (multichannel) input */ + ambisonicInput: AudioNode; + /** Ambisonic (multichannel) output */ + ambisonicOutput: AudioNode; + constructor(context: AudioContext, options?: ResonanceAudio.Options); + /** + * Create a new source for the scene. + * @param options + * Options for constructing a new Source. + */ + createSource(options?: Source.Options): Source; + /** + * Set the scene's desired ambisonic order. + * @param ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder: any): void; + /** + * Set the room's dimensions and wall materials. + * @param dimensions Room dimensions (in meters). + * @param materials Named acoustic materials per wall. + */ + setRoomProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + */ + setListenerPosition(x: number, y: number, z: number): any; + /** Set the source's orientation using forward and up vectors. */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param matrix + * The Three.js Matrix4 object representing the listener's world transform. + */ + setListenerFromMatrix(matrix4: Float32Array): void; + /** + * Set the speed of sound. + */ + setSpeedOfSound(speedOfSound: number): void; + } + namespace Source { + /** Options for constructing a new Source. */ + interface Options { + /** The source's initial position (in meters), where origin is the center of + * the room */ + position?: Float32Array; + /** The source's initial forward vector */ + forward?: Float32Array; + /** The source's initial up vector */ + up?: Float32Array; + /** Min. distance (in meters) */ + minDistance?: number; + /** Max. distance (in meters) */ + maxDistance?: number; + /** Rolloff model to use */ + rolloff?: string; + /** Input gain (linear) */ + gain?: number; + /** Directivity alpha */ + alpha?: number; + /** Directivity sharpness */ + sharpness?: number; + /** Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source */ + sourceWidth?: number; + } + } + /** + * Source model to spatialize an audio buffer. + */ + class Source { + constructor(scene: ResonanceAudio, options?: Source.Options); + /** Mono (1-channel) input */ + input: AudioNode; + /** + * Set source's position (in meters), where origin is the center of + * the room. + */ + setPosition(x: number, y: number, z: number): void; + /** Set source's rolloff. */ + setRolloff(rolloff: string): void; + /** Set source's minimum distance (in meters). */ + setMinDistance(minDistance: number): void; + /** Set source's maximum distance (in meters). */ + setMaxDistance(maxDistance: number): void; + /** Set source's gain (linear). */ + setGain(gain: number): void; + /** Set the source's orientation using forward and up vectors. */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** Set source's position and orientation using a + * Three.js modelViewMatrix object */ + setFromMatrix(matrix4: Float32Array): void; + /** Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source */ + setSourceWidth(sourceWidth: number): void; + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponentially + * @param alpha + * Determines directivity pattern (0 to 1). + * @param sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + */ + setDirectivityPattern(alpha: number, sharpness: number): void; + } + namespace Room { + interface Options { + /** The listener's initial position (in meters), where origin is the center of + * the room */ + listenerPosition?: Float32Array; + /** Room dimensions (in meters) */ + dimensions?: Utils.RoomDimensions; + /** Named acoustic materials per wall */ + materials?: Utils.RoomMaterials; + /** (in meters/second) */ + speedOfSound?: number; + } + } + /** + * Model that manages early and late reflections using acoustic + * properties and listener position relative to a rectangular room. + */ + class Room { + constructor(context: AudioContext, options?: Room.Options); + /** + * Set the room's dimensions and wall materials. + * @param dimensions Room dimensions (in meters) + * @param materials Named acoustic materials per wall + */ + setProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Compute distance outside room of provided position (in meters). + * @return + * Distance outside room (in meters). Returns 0 if inside room. + */ + getDistanceOutsideRoom(x: number, y: number, z: number): number; + } + namespace Listener { + interface Options { + /** Desired ambisonic order */ + ambisonicOrder: number; + /** Initial position (in meters), where origin is the center of + * the room */ + position?: Float32Array; + /** The listener's initial forward vector */ + forward?: Float32Array; + /** The listener's initial up vector */ + up?: Float32Array; + } + } + /** Listener model to spatialize sources in an environment */ + class Listener { + /** Position (in meters) */ + position: Float32Array; + /** Ambisonic (multichannel) input */ + input: AudioNode; + /** Binaurally-rendered stereo (2-channel) output */ + output: AudioNode; + /** Ambisonic (multichannel) output */ + ambisonicOutput: AudioNode; + /** + * Set the listener's orientation using forward and up vectors. + */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** Set listener's position and orientation using a + * Three.js modelViewMatrix object */ + setFromMatrix(matrix4: Float32Array): void; + } + namespace Utils { + /** Properties describing the geometry of a room. */ + interface RoomDimensions { + width: number; + height: number; + depth: number; + } + /** Properties describing the wall materials */ + interface RoomMaterials { + left: string; + right: string; + front: string; + back: string; + down: string; + up: string; + } + } +} diff --git a/framework/resonator/vendor/resonance-es6/d.js b/framework/resonator/vendor/resonance-es6/d.js new file mode 100644 index 0000000..e69de29 diff --git a/framework/resonator/vendor/resonance-es6/directivity.d.ts b/framework/resonator/vendor/resonance-es6/directivity.d.ts new file mode 100644 index 0000000..5694bf1 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/directivity.d.ts @@ -0,0 +1,47 @@ +export default Directivity; +/** + * @class Directivity + * @description Directivity/occlusion filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.alpha + * Determines directivity pattern (0 to 1). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @param {Number} options.sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ +declare class Directivity { + constructor(context: any, options: any); + _context: any; + _lowpass: any; + _cosTheta: number; + input: any; + output: any; + /** + * Compute the filter using the source's forward orientation and the listener's + * position. + * @param {Float32Array} forward The source's forward vector. + * @param {Float32Array} direction The direction from the source to the + * listener. + */ + computeAngle(forward: Float32Array, direction: Float32Array): void; + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponenentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ + setPattern(alpha: number, sharpness: number): void; + _alpha: number; + _sharpness: number; +} diff --git a/framework/resonator/vendor/resonance-es6/directivity.js b/framework/resonator/vendor/resonance-es6/directivity.js new file mode 100644 index 0000000..d465a55 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/directivity.js @@ -0,0 +1,117 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Directivity/occlusion filter. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class Directivity + * @description Directivity/occlusion filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.alpha + * Determines directivity pattern (0 to 1). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @param {Number} options.sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ +class Directivity { + constructor(context, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Directivity + * @instance + */ + /** + * Mono (1-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Directivity + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.alpha == undefined) { + options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA; + } + if (options.sharpness == undefined) { + options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS; + } + // Create audio node. + this._context = context; + this._lowpass = context.createBiquadFilter(); + // Initialize filter coefficients. + this._lowpass.type = 'lowpass'; + this._lowpass.Q.value = 0; + this._lowpass.frequency.value = context.sampleRate * 0.5; + this._cosTheta = 0; + this.setPattern(options.alpha, options.sharpness); + // Input/Output proxy. + this.input = this._lowpass; + this.output = this._lowpass; + } + /** + * Compute the filter using the source's forward orientation and the listener's + * position. + * @param {Float32Array} forward The source's forward vector. + * @param {Float32Array} direction The direction from the source to the + * listener. + */ + computeAngle(forward, direction) { + let forwardNorm = Utils.normalizeVector(forward); + let directionNorm = Utils.normalizeVector(direction); + let coeff = 1; + if (this._alpha > Utils.EPSILON_FLOAT) { + let cosTheta = forwardNorm[0] * directionNorm[0] + + forwardNorm[1] * directionNorm[1] + forwardNorm[2] * directionNorm[2]; + coeff = (1 - this._alpha) + this._alpha * cosTheta; + coeff = Math.pow(Math.abs(coeff), this._sharpness); + } + this._lowpass.frequency.value = this._context.sampleRate * 0.5 * coeff; + } + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponenentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ + setPattern(alpha, sharpness) { + // Clamp and set values. + this._alpha = Math.min(1, Math.max(0, alpha)); + this._sharpness = Math.max(1, sharpness); + // Update angle calculation using new values. + this.computeAngle([this._cosTheta * this._cosTheta, 0, 0], [1, 0, 0]); + } +} +export default Directivity; diff --git a/framework/resonator/vendor/resonance-es6/early-reflections.d.ts b/framework/resonator/vendor/resonance-es6/early-reflections.d.ts new file mode 100644 index 0000000..5dd2570 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/early-reflections.d.ts @@ -0,0 +1,56 @@ +export default EarlyReflections; +/** + * @class EarlyReflections + * @description Ray-tracing-based early reflections model. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Utils~RoomDimensions} options.dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} options.coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + * @param {Number} options.speedOfSound + * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND + * DEFAULT_SPEED_OF_SOUND}. + * @param {Float32Array} options.listenerPosition + * (in meters). Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ +declare class EarlyReflections { + constructor(context: any, options: any); + speedOfSound: any; + input: any; + output: any; + _lowpass: any; + _delays: {}; + _gains: {}; + _inverters: {}; + _merger: any; + _listenerPosition: any; + /** + * Set the listener's position (in meters), + * where [0,0,0] is the center of the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Set the room's properties which determines the characteristics of + * reflections. + * @param {Utils~RoomDimensions} dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + */ + setRoomProperties(dimensions: any, coefficients: any): void; + _coefficients: any; + _halfDimensions: {}; +} diff --git a/framework/resonator/vendor/resonance-es6/early-reflections.js b/framework/resonator/vendor/resonance-es6/early-reflections.js new file mode 100644 index 0000000..073942d --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/early-reflections.js @@ -0,0 +1,212 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Ray-tracing-based early reflections model. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class EarlyReflections + * @description Ray-tracing-based early reflections model. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Utils~RoomDimensions} options.dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} options.coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + * @param {Number} options.speedOfSound + * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND + * DEFAULT_SPEED_OF_SOUND}. + * @param {Float32Array} options.listenerPosition + * (in meters). Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ +class EarlyReflections { + constructor(context, options) { + // Public variables. + /** + * The room's speed of sound (in meters/second). + * @member {Number} speedOfSound + * @memberof EarlyReflections + * @instance + */ + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof EarlyReflections + * @instance + */ + /** + * First-order ambisonic (4-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof EarlyReflections + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.speedOfSound == undefined) { + options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + if (options.listenerPosition == undefined) { + options.listenerPosition = Utils.DEFAULT_POSITION.slice(); + } + if (options.coefficients == undefined) { + options.coefficients = {}; + Object.assign(options.coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS); + } + // Assign room's speed of sound. + this.speedOfSound = options.speedOfSound; + // Create nodes. + this.input = context.createGain(); + this.output = context.createGain(); + this._lowpass = context.createBiquadFilter(); + this._delays = {}; + this._gains = {}; // gainPerWall = (ReflectionCoeff / Attenuation) + this._inverters = {}; // 3 of these are needed for right/back/down walls. + this._merger = context.createChannelMerger(4); // First-order encoding only. + // Connect audio graph for each wall reflection. + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + this._delays[property] = + context.createDelay(Utils.MAX_DURATION); + this._gains[property] = context.createGain(); + } + } + this._inverters.right = context.createGain(); + this._inverters.down = context.createGain(); + this._inverters.back = context.createGain(); + // Initialize lowpass filter. + this._lowpass.type = 'lowpass'; + this._lowpass.frequency.value = Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY; + this._lowpass.Q.value = 0; + // Initialize encoder directions, set delay times and gains to 0. + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + this._delays[property].delayTime.value = 0; + this._gains[property].gain.value = 0; + } + } + // Initialize inverters for opposite walls ('right', 'down', 'back' only). + this._inverters.right.gain.value = -1; + this._inverters.down.gain.value = -1; + this._inverters.back.gain.value = -1; + // Connect nodes. + this.input.connect(this._lowpass); + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + this._lowpass.connect(this._delays[property]); + this._delays[property].connect(this._gains[property]); + this._gains[property].connect(this._merger, 0, 0); + } + } + // Connect gains to ambisonic channel output. + // Left: [1 1 0 0] + // Right: [1 -1 0 0] + // Up: [1 0 1 0] + // Down: [1 0 -1 0] + // Front: [1 0 0 1] + // Back: [1 0 0 -1] + this._gains.left.connect(this._merger, 0, 1); + this._gains.right.connect(this._inverters.right); + this._inverters.right.connect(this._merger, 0, 1); + this._gains.up.connect(this._merger, 0, 2); + this._gains.down.connect(this._inverters.down); + this._inverters.down.connect(this._merger, 0, 2); + this._gains.front.connect(this._merger, 0, 3); + this._gains.back.connect(this._inverters.back); + this._inverters.back.connect(this._merger, 0, 3); + this._merger.connect(this.output); + // Initialize. + this._listenerPosition = options.listenerPosition; + this.setRoomProperties(options.dimensions, options.coefficients); + } + /** + * Set the listener's position (in meters), + * where [0,0,0] is the center of the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x, y, z) { + // Assign listener position. + this._listenerPosition = [x, y, z]; + // Determine distances to each wall. + let distances = { + left: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width + x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + right: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width - x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + front: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth + z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + back: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth - z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + down: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height + y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + up: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height - y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + }; + // Assign delay & attenuation values using distances. + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + // Compute and assign delay (in seconds). + let delayInSecs = distances[property] / this.speedOfSound; + this._delays[property].delayTime.value = delayInSecs; + // Compute and assign gain, uses logarithmic rolloff: "g = R / (d + 1)" + let attenuation = this._coefficients[property] / distances[property]; + this._gains[property].gain.value = attenuation; + } + } + } + /** + * Set the room's properties which determines the characteristics of + * reflections. + * @param {Utils~RoomDimensions} dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + */ + setRoomProperties(dimensions, coefficients) { + if (dimensions == undefined) { + dimensions = {}; + Object.assign(dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); + } + if (coefficients == undefined) { + coefficients = {}; + Object.assign(coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS); + } + this._coefficients = coefficients; + // Sanitize dimensions and store half-dimensions. + this._halfDimensions = {}; + this._halfDimensions.width = dimensions.width * 0.5; + this._halfDimensions.height = dimensions.height * 0.5; + this._halfDimensions.depth = dimensions.depth * 0.5; + // Update listener position with new room properties. + this.setListenerPosition(this._listenerPosition[0], this._listenerPosition[1], this._listenerPosition[2]); + } +} +export default EarlyReflections; diff --git a/framework/resonator/vendor/resonance-es6/encoder.d.ts b/framework/resonator/vendor/resonance-es6/encoder.d.ts new file mode 100644 index 0000000..7722a6b --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/encoder.d.ts @@ -0,0 +1,64 @@ +export default Encoder; +/** + * @class Encoder + * @description Spatially encodes input using weighted spherical harmonics. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Number} options.azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} options.elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + * @param {Number} options.sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +declare class Encoder { + constructor(context: any, options: any); + _context: any; + input: any; + _channelGain: any[]; + _merger: any; + output: any; + _azimuth: any; + _elevation: any; + /** + * Set the desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder: number): void; + _ambisonicOrder: number; + /** + * Set the direction of the encoded source signal. + * @param {Number} azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + */ + setDirection(azimuth: number, elevation: number): void; + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth: number): void; + _spreadIndex: number; +} +declare namespace Encoder { + /** + * Validate the provided ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + * @return {Number} Validated/adjusted ambisonic order. + * @private + */ + function validateAmbisonicOrder(ambisonicOrder: number): number; +} diff --git a/framework/resonator/vendor/resonance-es6/encoder.js b/framework/resonator/vendor/resonance-es6/encoder.js new file mode 100644 index 0000000..0d57e04 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/encoder.js @@ -0,0 +1,194 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Spatially encodes input using weighted spherical harmonics. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Tables from './tables.js'; +import Utils from './utils.js'; +/** + * @class Encoder + * @description Spatially encodes input using weighted spherical harmonics. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Number} options.azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} options.elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + * @param {Number} options.sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +class Encoder { + constructor(context, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Encoder + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Encoder + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.ambisonicOrder == undefined) { + options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; + } + if (options.azimuth == undefined) { + options.azimuth = Utils.DEFAULT_AZIMUTH; + } + if (options.elevation == undefined) { + options.elevation = Utils.DEFAULT_ELEVATION; + } + if (options.sourceWidth == undefined) { + options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH; + } + this._context = context; + // Create I/O nodes. + this.input = context.createGain(); + this._channelGain = []; + this._merger = undefined; + this.output = context.createGain(); + // Set initial order, angle and source width. + this.setAmbisonicOrder(options.ambisonicOrder); + this._azimuth = options.azimuth; + this._elevation = options.elevation; + this.setSourceWidth(options.sourceWidth); + } + /** + * Set the desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder) { + this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder); + this.input.disconnect(); + for (let i = 0; i < this._channelGain.length; i++) { + this._channelGain[i].disconnect(); + } + if (this._merger != undefined) { + this._merger.disconnect(); + } + delete this._channelGain; + delete this._merger; + // Create audio graph. + let numChannels = (this._ambisonicOrder + 1) * (this._ambisonicOrder + 1); + this._merger = this._context.createChannelMerger(numChannels); + this._channelGain = new Array(numChannels); + for (let i = 0; i < numChannels; i++) { + this._channelGain[i] = this._context.createGain(); + this.input.connect(this._channelGain[i]); + this._channelGain[i].connect(this._merger, 0, i); + } + this._merger.connect(this.output); + } + /** + * Set the direction of the encoded source signal. + * @param {Number} azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + */ + setDirection(azimuth, elevation) { + // Format input direction to nearest indices. + if (azimuth == undefined || isNaN(azimuth)) { + azimuth = Utils.DEFAULT_AZIMUTH; + } + if (elevation == undefined || isNaN(elevation)) { + elevation = Utils.DEFAULT_ELEVATION; + } + // Store the formatted input (for updating source width). + this._azimuth = azimuth; + this._elevation = elevation; + // Format direction for index lookups. + azimuth = Math.round(azimuth % 360); + if (azimuth < 0) { + azimuth += 360; + } + elevation = Math.round(Math.min(90, Math.max(-90, elevation))) + 90; + // Assign gains to each output. + this._channelGain[0].gain.value = Tables.MAX_RE_WEIGHTS[this._spreadIndex][0]; + for (let i = 1; i <= this._ambisonicOrder; i++) { + let degreeWeight = Tables.MAX_RE_WEIGHTS[this._spreadIndex][i]; + for (let j = -i; j <= i; j++) { + let acnChannel = (i * i) + i + j; + let elevationIndex = i * (i + 1) / 2 + Math.abs(j) - 1; + let val = Tables.SPHERICAL_HARMONICS[1][elevation][elevationIndex]; + if (j != 0) { + let azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j - 1; + if (j < 0) { + azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j; + } + val *= Tables.SPHERICAL_HARMONICS[0][azimuth][azimuthIndex]; + } + this._channelGain[acnChannel].gain.value = val * degreeWeight; + } + } + } + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth) { + // The MAX_RE_WEIGHTS is a 360 x (Tables.SPHERICAL_HARMONICS_MAX_ORDER+1) + // size table. + this._spreadIndex = Math.min(359, Math.max(0, Math.round(sourceWidth))); + this.setDirection(this._azimuth, this._elevation); + } +} +/** + * Validate the provided ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + * @return {Number} Validated/adjusted ambisonic order. + * @private + */ +Encoder.validateAmbisonicOrder = ambisonicOrder => { + if (isNaN(ambisonicOrder) || ambisonicOrder == undefined) { + Utils.log('Error: Invalid ambisonic order', options.ambisonicOrder, '\nUsing ambisonicOrder=1 instead.'); + ambisonicOrder = 1; + } + else if (ambisonicOrder < 1) { + Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Min order is 1)', '\nUsing min order instead.'); + ambisonicOrder = 1; + } + else if (ambisonicOrder > Tables.SPHERICAL_HARMONICS_MAX_ORDER) { + Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Max order is', Tables.SPHERICAL_HARMONICS_MAX_ORDER, ')\nUsing max order instead.'); + options.ambisonicOrder = Tables.SPHERICAL_HARMONICS_MAX_ORDER; + } + return ambisonicOrder; +}; +export default Encoder; diff --git a/framework/resonator/vendor/resonance-es6/late-reflections.d.ts b/framework/resonator/vendor/resonance-es6/late-reflections.d.ts new file mode 100644 index 0000000..95b2353 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/late-reflections.d.ts @@ -0,0 +1,42 @@ +export default LateReflections; +/** + * @class LateReflections + * @description Late-reflections reverberation filter for Ambisonic content. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Array} options.durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}. + * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}. + * @param {Number} options.gain Output gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}. + * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency + * band. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}. + * @param {Number} options.tailonset Length (in milliseconds) of impulse + * response to apply a half-Hann window. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}. + */ +declare class LateReflections { + constructor(context: any, options: any); + _bandwidthCoeff: number; + _tailonsetSamples: number; + _context: any; + input: any; + _predelay: any; + _convolver: any; + output: any; + /** + * Re-compute a new impulse response by providing Multiband RT60 durations. + * @param {Array} durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * DEFAULT_REVERB_FREQUENCY_BANDS}. + */ + setDurations(durations: any[]): void; +} diff --git a/framework/resonator/vendor/resonance-es6/late-reflections.js b/framework/resonator/vendor/resonance-es6/late-reflections.js new file mode 100644 index 0000000..5ab6bac --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/late-reflections.js @@ -0,0 +1,187 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Late reverberation filter for Ambisonic content. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class LateReflections + * @description Late-reflections reverberation filter for Ambisonic content. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Array} options.durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}. + * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}. + * @param {Number} options.gain Output gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}. + * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency + * band. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}. + * @param {Number} options.tailonset Length (in milliseconds) of impulse + * response to apply a half-Hann window. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}. + */ +class LateReflections { + constructor(context, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof LateReflections + * @instance + */ + /** + * Mono (1-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof LateReflections + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.durations == undefined) { + options.durations = Utils.DEFAULT_REVERB_DURATIONS.slice(); + } + if (options.predelay == undefined) { + options.predelay = Utils.DEFAULT_REVERB_PREDELAY; + } + if (options.gain == undefined) { + options.gain = Utils.DEFAULT_REVERB_GAIN; + } + if (options.bandwidth == undefined) { + options.bandwidth = Utils.DEFAULT_REVERB_BANDWIDTH; + } + if (options.tailonset == undefined) { + options.tailonset = Utils.DEFAULT_REVERB_TAIL_ONSET; + } + // Assign pre-computed variables. + let delaySecs = options.predelay / 1000; + this._bandwidthCoeff = options.bandwidth * Utils.LOG2_DIV2; + this._tailonsetSamples = options.tailonset / 1000; + // Create nodes. + this._context = context; + this.input = context.createGain(); + this._predelay = context.createDelay(delaySecs); + this._convolver = context.createConvolver(); + this.output = context.createGain(); + // Set reverb attenuation. + this.output.gain.value = options.gain; + // Disable normalization. + this._convolver.normalize = false; + // Connect nodes. + this.input.connect(this._predelay); + this._predelay.connect(this._convolver); + this._convolver.connect(this.output); + // Compute IR using RT60 values. + this.setDurations(options.durations); + } + /** + * Re-compute a new impulse response by providing Multiband RT60 durations. + * @param {Array} durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * DEFAULT_REVERB_FREQUENCY_BANDS}. + */ + setDurations(durations) { + if (durations.length !== Utils.NUMBER_REVERB_FREQUENCY_BANDS) { + Utils.log('Warning: invalid number of RT60 values provided to reverb.'); + return; + } + // Compute impulse response. + let durationsSamples = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); + let sampleRate = this._context.sampleRate; + for (let i = 0; i < durations.length; i++) { + // Clamp within suitable range. + durations[i] = + Math.max(0, Math.min(Utils.DEFAULT_REVERB_MAX_DURATION, durations[i])); + // Convert seconds to samples. + durationsSamples[i] = Math.round(durations[i] * sampleRate * + Utils.DEFAULT_REVERB_DURATION_MULTIPLIER); + } + ; + // Determine max RT60 length in samples. + let durationsSamplesMax = 0; + for (let i = 0; i < durationsSamples.length; i++) { + if (durationsSamples[i] > durationsSamplesMax) { + durationsSamplesMax = durationsSamples[i]; + } + } + // Skip this step if there is no reverberation to compute. + if (durationsSamplesMax < 1) { + durationsSamplesMax = 1; + } + // Create impulse response buffer. + let buffer = this._context.createBuffer(1, durationsSamplesMax, sampleRate); + let bufferData = buffer.getChannelData(0); + // Create noise signal (computed once, referenced in each band's routine). + let noiseSignal = new Float32Array(durationsSamplesMax); + for (let i = 0; i < durationsSamplesMax; i++) { + noiseSignal[i] = Math.random() * 2 - 1; + } + // Compute the decay rate per-band and filter the decaying noise signal. + for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) { + // Compute decay rate. + let decayRate = -Utils.LOG1000 / durationsSamples[i]; + // Construct a standard one-zero, two-pole bandpass filter: + // H(z) = (b0 * z^0 + b1 * z^-1 + b2 * z^-2) / (1 + a1 * z^-1 + a2 * z^-2) + let omega = Utils.TWO_PI * + Utils.DEFAULT_REVERB_FREQUENCY_BANDS[i] / sampleRate; + let sinOmega = Math.sin(omega); + let alpha = sinOmega * Math.sinh(this._bandwidthCoeff * omega / sinOmega); + let a0CoeffReciprocal = 1 / (1 + alpha); + let b0Coeff = alpha * a0CoeffReciprocal; + let a1Coeff = -2 * Math.cos(omega) * a0CoeffReciprocal; + let a2Coeff = (1 - alpha) * a0CoeffReciprocal; + // We optimize since b2 = -b0, b1 = 0. + // Update equation for two-pole bandpass filter: + // u[n] = x[n] - a1 * x[n-1] - a2 * x[n-2] + // y[n] = b0 * (u[n] - u[n-2]) + let um1 = 0; + let um2 = 0; + for (let j = 0; j < durationsSamples[i]; j++) { + // Exponentially-decaying white noise. + let x = noiseSignal[j] * Math.exp(decayRate * j); + // Filter signal with bandpass filter and add to output. + let u = x - a1Coeff * um1 - a2Coeff * um2; + bufferData[j] += b0Coeff * (u - um2); + // Update coefficients. + um2 = um1; + um1 = u; + } + } + // Create and apply half of a Hann window to the beginning of the + // impulse response. + let halfHannLength = Math.round(this._tailonsetSamples); + for (let i = 0; i < Math.min(bufferData.length, halfHannLength); i++) { + let halfHann = 0.5 * (1 - Math.cos(Utils.TWO_PI * i / (2 * halfHannLength - 1))); + bufferData[i] *= halfHann; + } + this._convolver.buffer = buffer; + } +} +export default LateReflections; diff --git a/framework/resonator/vendor/resonance-es6/listener.d.ts b/framework/resonator/vendor/resonance-es6/listener.d.ts new file mode 100644 index 0000000..ebafa78 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/listener.d.ts @@ -0,0 +1,49 @@ +export default Listener; +/** + * @class Listener + * @description Listener model to spatialize sources in an environment. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Float32Array} options.position + * Initial position (in meters), where origin is the center of + * the room. Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Float32Array} options.forward + * The listener's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @param {Float32Array} options.up + * The listener's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + */ +declare class Listener { + constructor(context: any, options: any); + position: Float32Array; + _tempMatrix3: Float32Array; + _ambisonicOrder: number; + _context: any; + _renderer: any; + input: any; + output: any; + ambisonicOutput: any; + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix4 + * The Three.js Matrix4 object representing the listener's world transform. + */ + setFromMatrix(matrix4: any): void; +} diff --git a/framework/resonator/vendor/resonance-es6/listener.js b/framework/resonator/vendor/resonance-es6/listener.js new file mode 100644 index 0000000..be0e0e8 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/listener.js @@ -0,0 +1,168 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Listener model to spatialize sources in an environment. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Omnitone from 'omnitone/build/omnitone.esm'; +import Encoder from './encoder.js'; +import Utils from './utils.js'; +/** + * @class Listener + * @description Listener model to spatialize sources in an environment. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Float32Array} options.position + * Initial position (in meters), where origin is the center of + * the room. Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Float32Array} options.forward + * The listener's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @param {Float32Array} options.up + * The listener's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + */ +class Listener { + constructor(context, options) { + // Public variables. + /** + * Position (in meters). + * @member {Float32Array} position + * @memberof Listener + * @instance + */ + /** + * Ambisonic (multichannel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Listener + * @instance + */ + /** + * Binaurally-rendered stereo (2-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Listener + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} ambisonicOutput + * @memberof Listener + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.ambisonicOrder == undefined) { + options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; + } + if (options.position == undefined) { + options.position = Utils.DEFAULT_POSITION.slice(); + } + if (options.forward == undefined) { + options.forward = Utils.DEFAULT_FORWARD.slice(); + } + if (options.up == undefined) { + options.up = Utils.DEFAULT_UP.slice(); + } + // Member variables. + this.position = new Float32Array(3); + this._tempMatrix3 = new Float32Array(9); + // Select the appropriate HRIR filters using 2-channel chunks since + // multichannel audio is not yet supported by a majority of browsers. + this._ambisonicOrder = + Encoder.validateAmbisonicOrder(options.ambisonicOrder); + // Create audio nodes. + this._context = context; + if (this._ambisonicOrder == 1) { + this._renderer = Omnitone.createFOARenderer(context, {}); + } + else if (this._ambisonicOrder > 1) { + this._renderer = Omnitone.createHOARenderer(context, { + ambisonicOrder: this._ambisonicOrder, + }); + } + // These nodes are created in order to safely asynchronously load Omnitone + // while the rest of the scene is being created. + this.input = context.createGain(); + this.output = context.createGain(); + this.ambisonicOutput = context.createGain(); + // Initialize Omnitone (async) and connect to audio graph when complete. + let that = this; + this._renderer.initialize().then(() => { + // Connect pre-rotated soundfield to renderer. + that.input.connect(that._renderer.input); + // Connect rotated soundfield to ambisonic output. + if (that._ambisonicOrder > 1) { + that._renderer._hoaRotator.output.connect(that.ambisonicOutput); + } + else { + that._renderer._foaRotator.output.connect(that.ambisonicOutput); + } + // Connect binaurally-rendered soundfield to binaural output. + that._renderer.output.connect(that.output); + }); + // Set orientation and update rotation matrix accordingly. + this.setOrientation(options.forward[0], options.forward[1], options.forward[2], options.up[0], options.up[1], options.up[2]); + } + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { + let right = Utils.crossProduct([forwardX, forwardY, forwardZ], [upX, upY, upZ]); + this._tempMatrix3[0] = right[0]; + this._tempMatrix3[1] = right[1]; + this._tempMatrix3[2] = right[2]; + this._tempMatrix3[3] = upX; + this._tempMatrix3[4] = upY; + this._tempMatrix3[5] = upZ; + this._tempMatrix3[6] = forwardX; + this._tempMatrix3[7] = forwardY; + this._tempMatrix3[8] = forwardZ; + this._renderer.setRotationMatrix3(this._tempMatrix3); + } + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix4 + * The Three.js Matrix4 object representing the listener's world transform. + */ + setFromMatrix(matrix4) { + // Update ambisonic rotation matrix internally. + this._renderer.setRotationMatrix4(matrix4.elements); + // Extract position from matrix. + this.position[0] = matrix4.elements[12]; + this.position[1] = matrix4.elements[13]; + this.position[2] = matrix4.elements[14]; + } +} +export default Listener; diff --git a/framework/resonator/vendor/resonance-es6/main.d.ts b/framework/resonator/vendor/resonance-es6/main.d.ts new file mode 100644 index 0000000..1bc1964 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/main.d.ts @@ -0,0 +1,2 @@ +export default ResonanceAudio; +import ResonanceAudio from "./resonance-audio"; diff --git a/framework/resonator/vendor/resonance-es6/main.js b/framework/resonator/vendor/resonance-es6/main.js new file mode 100644 index 0000000..103a9a6 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/main.js @@ -0,0 +1,23 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Primary namespace for ResonanceAudio library. + * @author Andrew Allen + */ +'use strict'; +import ResonanceAudio from './resonance-audio'; +// Main module. +export default ResonanceAudio; diff --git a/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts b/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts new file mode 100644 index 0000000..cd049ef --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts @@ -0,0 +1,130 @@ +export default ResonanceAudio; +/** + * ~ResonanceAudioOptions + */ +export type ResonanceAudio = { + /** + * Desired ambisonic Order. Defaults to + * {@link Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + */ + ambisonicOrder: number; + /** + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ + listenerPosition: Float32Array; + /** + * The listener's initial forward vector. + * Defaults to {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + */ + listenerForward: Float32Array; + /** + * The listener's initial up vector. + * Defaults to {@link Utils.DEFAULT_UP DEFAULT_UP}. + */ + listenerUp: Float32Array; + /** + * ~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@link Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + */ + "": Utils; + /** + * (in meters/second). Defaults to + * {@link Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ + speedOfSound: number; +}; +/** + * Options for constructing a new ResonanceAudio scene. + * @typedef {Object} ResonanceAudio~ResonanceAudioOptions + * @property {Number} ambisonicOrder + * Desired ambisonic Order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @property {Float32Array} listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} listenerForward + * The listener's initial forward vector. + * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} listenerUp + * The listener's initial up vector. + * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @property {Utils~RoomMaterials} materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @property {Number} speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +/** + * @class ResonanceAudio + * @description Main class for managing sources, room and listener models. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {ResonanceAudio~ResonanceAudioOptions} options + * Options for constructing a new ResonanceAudio scene. + */ +declare class ResonanceAudio { + constructor(context: any, options: any); + _ambisonicOrder: number; + _sources: any[]; + _room: Room; + _listener: Listener; + _context: any; + output: any; + ambisonicOutput: any; + ambisonicInput: any; + /** + * Create a new source for the scene. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + * @return {Source} + */ + createSource(options: any): Source; + /** + * Set the scene's desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder: number): void; + /** + * Set the room's dimensions and wall materials. + * @param {Object} dimensions Room dimensions (in meters). + * @param {Object} materials Named acoustic materials per wall. + */ + setRoomProperties(dimensions: any, materials: any): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setListenerOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix + * The Three.js Matrix4 object representing the listener's world transform. + */ + setListenerFromMatrix(matrix: any): void; + /** + * Set the speed of sound. + * @param {Number} speedOfSound + */ + setSpeedOfSound(speedOfSound: number): void; +} +import Utils from "./utils.js"; +import Room from "./room.js"; +import Listener from "./listener.js"; +import Source from "./source.js"; diff --git a/framework/resonator/vendor/resonance-es6/resonance-audio.js b/framework/resonator/vendor/resonance-es6/resonance-audio.js new file mode 100644 index 0000000..7e3c6c9 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/resonance-audio.js @@ -0,0 +1,213 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 ResonanceAudio library name space and common utilities. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Listener from './listener.js'; +import Source from './source.js'; +import Room from './room.js'; +import Encoder from './encoder.js'; +import Utils from './utils.js'; +/** + * Options for constructing a new ResonanceAudio scene. + * @typedef {Object} ResonanceAudio~ResonanceAudioOptions + * @property {Number} ambisonicOrder + * Desired ambisonic Order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @property {Float32Array} listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} listenerForward + * The listener's initial forward vector. + * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} listenerUp + * The listener's initial up vector. + * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @property {Utils~RoomMaterials} materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @property {Number} speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +/** + * @class ResonanceAudio + * @description Main class for managing sources, room and listener models. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {ResonanceAudio~ResonanceAudioOptions} options + * Options for constructing a new ResonanceAudio scene. + */ +class ResonanceAudio { + constructor(context, options) { + // Public variables. + /** + * Binaurally-rendered stereo (2-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof ResonanceAudio + * @instance + */ + /** + * Ambisonic (multichannel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode} + * (For rendering input soundfields). + * @member {AudioNode} ambisonicInput + * @memberof ResonanceAudio + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode} + * (For allowing external rendering / post-processing). + * @member {AudioNode} ambisonicOutput + * @memberof ResonanceAudio + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.ambisonicOrder == undefined) { + options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; + } + if (options.listenerPosition == undefined) { + options.listenerPosition = Utils.DEFAULT_POSITION.slice(); + } + if (options.listenerForward == undefined) { + options.listenerForward = Utils.DEFAULT_FORWARD.slice(); + } + if (options.listenerUp == undefined) { + options.listenerUp = Utils.DEFAULT_UP.slice(); + } + if (options.dimensions == undefined) { + options.dimensions = {}; + Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); + } + if (options.materials == undefined) { + options.materials = {}; + Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS); + } + if (options.speedOfSound == undefined) { + options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + // Create member submodules. + this._ambisonicOrder = Encoder.validateAmbisonicOrder(options.ambisonicOrder); + this._sources = []; + this._room = new Room(context, { + listenerPosition: options.listenerPosition, + dimensions: options.dimensions, + materials: options.materials, + speedOfSound: options.speedOfSound, + }); + this._listener = new Listener(context, { + ambisonicOrder: options.ambisonicOrder, + position: options.listenerPosition, + forward: options.listenerForward, + up: options.listenerUp, + }); + // Create auxillary audio nodes. + this._context = context; + this.output = context.createGain(); + this.ambisonicOutput = context.createGain(); + this.ambisonicInput = this._listener.input; + // Connect audio graph. + this._room.output.connect(this._listener.input); + this._listener.output.connect(this.output); + this._listener.ambisonicOutput.connect(this.ambisonicOutput); + } + /** + * Create a new source for the scene. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + * @return {Source} + */ + createSource(options) { + // Create a source and push it to the internal sources array, returning + // the object's reference to the user. + let source = new Source(this, options); + this._sources[this._sources.length] = source; + return source; + } + /** + * Set the scene's desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder) { + this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder); + } + /** + * Set the room's dimensions and wall materials. + * @param {Object} dimensions Room dimensions (in meters). + * @param {Object} materials Named acoustic materials per wall. + */ + setRoomProperties(dimensions, materials) { + this._room.setProperties(dimensions, materials); + } + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x, y, z) { + // Update listener position. + this._listener.position[0] = x; + this._listener.position[1] = y; + this._listener.position[2] = z; + this._room.setListenerPosition(x, y, z); + // Update sources with new listener position. + this._sources.forEach(element => { + element._update(); + }); + } + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setListenerOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { + this._listener.setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ); + } + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix + * The Three.js Matrix4 object representing the listener's world transform. + */ + setListenerFromMatrix(matrix) { + this._listener.setFromMatrix(matrix); + // Update the rest of the scene using new listener position. + this.setListenerPosition(this._listener.position[0], this._listener.position[1], this._listener.position[2]); + } + /** + * Set the speed of sound. + * @param {Number} speedOfSound + */ + setSpeedOfSound(speedOfSound) { + this._room.speedOfSound = speedOfSound; + } +} +export default ResonanceAudio; diff --git a/framework/resonator/vendor/resonance-es6/room.d.ts b/framework/resonator/vendor/resonance-es6/room.d.ts new file mode 100644 index 0000000..ca71c23 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/room.d.ts @@ -0,0 +1,55 @@ +export default Room; +/** + * @class Room + * @description Model that manages early and late reflections using acoustic + * properties and listener position relative to a rectangular room. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Float32Array} options.listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @param {Number} options.speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +declare class Room { + constructor(context: any, options: any); + early: EarlyReflections; + late: LateReflections; + speedOfSound: any; + output: any; + _merger: any; + /** + * Set the room's dimensions and wall materials. + * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to + * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + */ + setProperties(dimensions: any, materials: any): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Compute distance outside room of provided position (in meters). + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @return {Number} + * Distance outside room (in meters). Returns 0 if inside room. + */ + getDistanceOutsideRoom(x: number, y: number, z: number): number; +} +import EarlyReflections from "./early-reflections.js"; +import LateReflections from "./late-reflections.js"; diff --git a/framework/resonator/vendor/resonance-es6/room.js b/framework/resonator/vendor/resonance-es6/room.js new file mode 100644 index 0000000..e36dfc6 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/room.js @@ -0,0 +1,300 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Complete room model with early and late reflections. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import LateReflections from './late-reflections.js'; +import EarlyReflections from './early-reflections.js'; +import Utils from './utils.js'; +/** + * Generate absorption coefficients from material names. + * @param {Object} materials + * @return {Object} + */ +function _getCoefficientsFromMaterials(materials) { + // Initialize coefficients to use defaults. + let coefficients = {}; + for (let property in Utils.DEFAULT_ROOM_MATERIALS) { + if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property)) { + coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]]; + } + } + // Sanitize materials. + if (materials == undefined) { + materials = {}; + Object.assign(materials, Utils.DEFAULT_ROOM_MATERIALS); + } + // Assign coefficients using provided materials. + for (let property in Utils.DEFAULT_ROOM_MATERIALS) { + if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property) && + materials.hasOwnProperty(property)) { + if (materials[property] in Utils.ROOM_MATERIAL_COEFFICIENTS) { + coefficients[property] = + Utils.ROOM_MATERIAL_COEFFICIENTS[materials[property]]; + } + else { + Utils.log('Material \"' + materials[property] + '\" on wall \"' + + property + '\" not found. Using \"' + + Utils.DEFAULT_ROOM_MATERIALS[property] + '\".'); + } + } + else { + Utils.log('Wall \"' + property + '\" is not defined. Default used.'); + } + } + return coefficients; +} +/** + * Sanitize coefficients. + * @param {Object} coefficients + * @return {Object} + */ +function _sanitizeCoefficients(coefficients) { + if (coefficients == undefined) { + coefficients = {}; + } + for (let property in Utils.DEFAULT_ROOM_MATERIALS) { + if (!(coefficients.hasOwnProperty(property))) { + // If element is not present, use default coefficients. + coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]]; + } + } + return coefficients; +} +/** + * Sanitize dimensions. + * @param {Utils~RoomDimensions} dimensions + * @return {Utils~RoomDimensions} + */ +function _sanitizeDimensions(dimensions) { + if (dimensions == undefined) { + dimensions = {}; + } + for (let property in Utils.DEFAULT_ROOM_DIMENSIONS) { + if (!(dimensions.hasOwnProperty(property))) { + dimensions[property] = Utils.DEFAULT_ROOM_DIMENSIONS[property]; + } + } + return dimensions; +} +/** + * Compute frequency-dependent reverb durations. + * @param {Utils~RoomDimensions} dimensions + * @param {Object} coefficients + * @param {Number} speedOfSound + * @return {Array} + */ +function _getDurationsFromProperties(dimensions, coefficients, speedOfSound) { + let durations = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); + // Sanitize inputs. + dimensions = _sanitizeDimensions(dimensions); + coefficients = _sanitizeCoefficients(coefficients); + if (speedOfSound == undefined) { + speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + // Acoustic constant. + let k = Utils.TWENTY_FOUR_LOG10 / speedOfSound; + // Compute volume, skip if room is not present. + let volume = dimensions.width * dimensions.height * dimensions.depth; + if (volume < Utils.ROOM_MIN_VOLUME) { + return durations; + } + // Room surface area. + let leftRightArea = dimensions.width * dimensions.height; + let floorCeilingArea = dimensions.width * dimensions.depth; + let frontBackArea = dimensions.depth * dimensions.height; + let totalArea = 2 * (leftRightArea + floorCeilingArea + frontBackArea); + for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) { + // Effective absorptive area. + let absorbtionArea = (coefficients.left[i] + coefficients.right[i]) * leftRightArea + + (coefficients.down[i] + coefficients.up[i]) * floorCeilingArea + + (coefficients.front[i] + coefficients.back[i]) * frontBackArea; + let meanAbsorbtionArea = absorbtionArea / totalArea; + // Compute reverberation using Eyring equation [1]. + // [1] Beranek, Leo L. "Analysis of Sabine and Eyring equations and their + // application to concert hall audience and chair absorption." The + // Journal of the Acoustical Society of America, Vol. 120, No. 3. + // (2006), pp. 1399-1399. + durations[i] = Utils.ROOM_EYRING_CORRECTION_COEFFICIENT * k * volume / + (-totalArea * Math.log(1 - meanAbsorbtionArea) + 4 * + Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS[i] * volume); + } + return durations; +} +/** + * Compute reflection coefficients from absorption coefficients. + * @param {Object} absorptionCoefficients + * @return {Object} + */ +function _computeReflectionCoefficients(absorptionCoefficients) { + let reflectionCoefficients = []; + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + // Compute average absorption coefficient (per wall). + reflectionCoefficients[property] = 0; + for (let j = 0; j < Utils.NUMBER_REFLECTION_AVERAGING_BANDS; j++) { + let bandIndex = j + Utils.ROOM_STARTING_AVERAGING_BAND; + reflectionCoefficients[property] += + absorptionCoefficients[property][bandIndex]; + } + reflectionCoefficients[property] /= + Utils.NUMBER_REFLECTION_AVERAGING_BANDS; + // Convert absorption coefficient to reflection coefficient. + reflectionCoefficients[property] = + Math.sqrt(1 - reflectionCoefficients[property]); + } + } + return reflectionCoefficients; +} +/** + * @class Room + * @description Model that manages early and late reflections using acoustic + * properties and listener position relative to a rectangular room. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Float32Array} options.listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @param {Number} options.speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +class Room { + constructor(context, options) { + // Public variables. + /** + * EarlyReflections {@link EarlyReflections EarlyReflections} submodule. + * @member {AudioNode} early + * @memberof Room + * @instance + */ + /** + * LateReflections {@link LateReflections LateReflections} submodule. + * @member {AudioNode} late + * @memberof Room + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Room + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.listenerPosition == undefined) { + options.listenerPosition = Utils.DEFAULT_POSITION.slice(); + } + if (options.dimensions == undefined) { + options.dimensions = {}; + Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); + } + if (options.materials == undefined) { + options.materials = {}; + Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS); + } + if (options.speedOfSound == undefined) { + options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + // Sanitize room-properties-related arguments. + options.dimensions = _sanitizeDimensions(options.dimensions); + let absorptionCoefficients = _getCoefficientsFromMaterials(options.materials); + let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients); + let durations = _getDurationsFromProperties(options.dimensions, absorptionCoefficients, options.speedOfSound); + // Construct submodules for early and late reflections. + this.early = new EarlyReflections(context, { + dimensions: options.dimensions, + coefficients: reflectionCoefficients, + speedOfSound: options.speedOfSound, + listenerPosition: options.listenerPosition, + }); + this.late = new LateReflections(context, { + durations: durations, + }); + this.speedOfSound = options.speedOfSound; + // Construct auxillary audio nodes. + this.output = context.createGain(); + this.early.output.connect(this.output); + this._merger = context.createChannelMerger(4); + this.late.output.connect(this._merger, 0, 0); + this._merger.connect(this.output); + } + /** + * Set the room's dimensions and wall materials. + * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to + * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + */ + setProperties(dimensions, materials) { + // Compute late response. + let absorptionCoefficients = _getCoefficientsFromMaterials(materials); + let durations = _getDurationsFromProperties(dimensions, absorptionCoefficients, this.speedOfSound); + this.late.setDurations(durations); + // Compute early response. + this.early.speedOfSound = this.speedOfSound; + let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients); + this.early.setRoomProperties(dimensions, reflectionCoefficients); + } + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x, y, z) { + this.early.speedOfSound = this.speedOfSound; + this.early.setListenerPosition(x, y, z); + // Disable room effects if the listener is outside the room boundaries. + let distance = this.getDistanceOutsideRoom(x, y, z); + let gain = 1; + if (distance > Utils.EPSILON_FLOAT) { + gain = 1 - distance / Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE; + // Clamp gain between 0 and 1. + gain = Math.max(0, Math.min(1, gain)); + } + this.output.gain.value = gain; + } + /** + * Compute distance outside room of provided position (in meters). + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @return {Number} + * Distance outside room (in meters). Returns 0 if inside room. + */ + getDistanceOutsideRoom(x, y, z) { + let dx = Math.max(0, -this.early._halfDimensions.width - x, x - this.early._halfDimensions.width); + let dy = Math.max(0, -this.early._halfDimensions.height - y, y - this.early._halfDimensions.height); + let dz = Math.max(0, -this.early._halfDimensions.depth - z, z - this.early._halfDimensions.depth); + return Math.sqrt(dx * dx + dy * dy + dz * dz); + } +} +export default Room; diff --git a/framework/resonator/vendor/resonance-es6/source.d.ts b/framework/resonator/vendor/resonance-es6/source.d.ts new file mode 100644 index 0000000..9060ecf --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/source.d.ts @@ -0,0 +1,182 @@ +export default Source; +/** + * ~SourceOptions + */ +export type Source = { + /** + * The source's initial position (in meters), where origin is the center of + * the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ + position: Float32Array; + /** + * The source's initial forward vector. Defaults to + * {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + */ + forward: Float32Array; + /** + * The source's initial up vector. Defaults to + * {@link Utils.DEFAULT_UP DEFAULT_UP}. + */ + up: Float32Array; + /** + * Min. distance (in meters). Defaults to + * {@link Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + */ + minDistance: number; + /** + * Max. distance (in meters). Defaults to + * {@link Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + */ + maxDistance: number; + /** + * Rolloff model to use, chosen from options in + * {@link Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@link Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + */ + rolloff: string; + /** + * Input gain (linear). Defaults to + * {@link Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. + */ + gain: number; + /** + * Directivity alpha. Defaults to + * {@link Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + */ + alpha: number; + /** + * Directivity sharpness. Defaults to + * {@link Utils.DEFAULT_DIRECTIVITY_SHARPNESS * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ + sharpness: number; + /** + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@link Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ + sourceWidth: number; +}; +/** + * Options for constructing a new Source. + * @typedef {Object} Source~SourceOptions + * @property {Float32Array} position + * The source's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} forward + * The source's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} up + * The source's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Number} minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @property {Number} maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @property {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + * @property {Number} gain Input gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. + * @property {Number} alpha Directivity alpha. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @property {Number} sharpness Directivity sharpness. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + * @property {Number} sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +/** + * @class Source + * @description Source model to spatialize an audio buffer. + * @param {ResonanceAudio} scene Associated {@link ResonanceAudio + * ResonanceAudio} instance. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + */ +declare class Source { + constructor(scene: any, options: any); + _scene: any; + _position: any; + _forward: any; + _up: any; + _dx: Float32Array; + _right: Float32Array; + input: any; + _directivity: Directivity; + _toEarly: any; + _toLate: any; + _attenuation: Attenuation; + _encoder: Encoder; + /** + * Set source's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setPosition(x: number, y: number, z: number): void; + _update(): void; + /** + * Set source's rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff: string): void; + /** + * Set source's minimum distance (in meters). + * @param {Number} minDistance + */ + setMinDistance(minDistance: number): void; + /** + * Set source's maximum distance (in meters). + * @param {Number} maxDistance + */ + setMaxDistance(maxDistance: number): void; + /** + * Set source's gain (linear). + * @param {Number} gain + */ + setGain(gain: number): void; + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set source's position and orientation using a + * Three.js modelViewMatrix object. + * @param {Float32Array} matrix4 + * The Matrix4 representing the object position and rotation in world space. + */ + setFromMatrix(matrix4: Float32Array): void; + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth: number): void; + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + */ + setDirectivityPattern(alpha: number, sharpness: number): void; +} +import Directivity from "./directivity.js"; +import Attenuation from "./attenuation.js"; +import Encoder from "./encoder.js"; diff --git a/framework/resonator/vendor/resonance-es6/source.js b/framework/resonator/vendor/resonance-es6/source.js new file mode 100644 index 0000000..61a7cf9 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/source.js @@ -0,0 +1,308 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Source model to spatialize an audio buffer. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Directivity from './directivity.js'; +import Attenuation from './attenuation.js'; +import Encoder from './encoder.js'; +import Utils from './utils.js'; +/** + * Options for constructing a new Source. + * @typedef {Object} Source~SourceOptions + * @property {Float32Array} position + * The source's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} forward + * The source's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} up + * The source's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Number} minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @property {Number} maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @property {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + * @property {Number} gain Input gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. + * @property {Number} alpha Directivity alpha. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @property {Number} sharpness Directivity sharpness. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + * @property {Number} sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +/** + * @class Source + * @description Source model to spatialize an audio buffer. + * @param {ResonanceAudio} scene Associated {@link ResonanceAudio + * ResonanceAudio} instance. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + */ +class Source { + constructor(scene, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Source + * @instance + */ + /** + * + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.position == undefined) { + options.position = Utils.DEFAULT_POSITION.slice(); + } + if (options.forward == undefined) { + options.forward = Utils.DEFAULT_FORWARD.slice(); + } + if (options.up == undefined) { + options.up = Utils.DEFAULT_UP.slice(); + } + if (options.minDistance == undefined) { + options.minDistance = Utils.DEFAULT_MIN_DISTANCE; + } + if (options.maxDistance == undefined) { + options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; + } + if (options.rolloff == undefined) { + options.rolloff = Utils.DEFAULT_ROLLOFF; + } + if (options.gain == undefined) { + options.gain = Utils.DEFAULT_SOURCE_GAIN; + } + if (options.alpha == undefined) { + options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA; + } + if (options.sharpness == undefined) { + options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS; + } + if (options.sourceWidth == undefined) { + options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH; + } + // Member variables. + this._scene = scene; + this._position = options.position; + this._forward = options.forward; + this._up = options.up; + this._dx = new Float32Array(3); + this._right = Utils.crossProduct(this._forward, this._up); + // Create audio nodes. + let context = scene._context; + this.input = context.createGain(); + this._directivity = new Directivity(context, { + alpha: options.alpha, + sharpness: options.sharpness, + }); + this._toEarly = context.createGain(); + this._toLate = context.createGain(); + this._attenuation = new Attenuation(context, { + minDistance: options.minDistance, + maxDistance: options.maxDistance, + rolloff: options.rolloff, + }); + this._encoder = new Encoder(context, { + ambisonicOrder: scene._ambisonicOrder, + sourceWidth: options.sourceWidth, + }); + // Connect nodes. + this.input.connect(this._toLate); + this._toLate.connect(scene._room.late.input); + this.input.connect(this._attenuation.input); + this._attenuation.output.connect(this._toEarly); + this._toEarly.connect(scene._room.early.input); + this._attenuation.output.connect(this._directivity.input); + this._directivity.output.connect(this._encoder.input); + this._encoder.output.connect(scene._listener.input); + // Assign initial conditions. + this.setPosition(options.position[0], options.position[1], options.position[2]); + this.input.gain.value = options.gain; + } + /** + * Set source's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setPosition(x, y, z) { + // Assign new position. + this._position[0] = x; + this._position[1] = y; + this._position[2] = z; + // Handle far-field effect. + let distance = this._scene._room.getDistanceOutsideRoom(this._position[0], this._position[1], this._position[2]); + let gain = _computeDistanceOutsideRoom(distance); + this._toLate.gain.value = gain; + this._toEarly.gain.value = gain; + this._update(); + } + // Update the source when changing the listener's position. + _update() { + // Compute distance to listener. + for (let i = 0; i < 3; i++) { + this._dx[i] = this._position[i] - this._scene._listener.position[i]; + } + let distance = Math.sqrt(this._dx[0] * this._dx[0] + + this._dx[1] * this._dx[1] + this._dx[2] * this._dx[2]); + if (distance > 0) { + // Normalize direction vector. + this._dx[0] /= distance; + this._dx[1] /= distance; + this._dx[2] /= distance; + } + // Compuete angle of direction vector. + let azimuth = Math.atan2(-this._dx[0], this._dx[2]) * + Utils.RADIANS_TO_DEGREES; + let elevation = Math.atan2(this._dx[1], Math.sqrt(this._dx[0] * this._dx[0] + + this._dx[2] * this._dx[2])) * Utils.RADIANS_TO_DEGREES; + // Set distance/directivity/direction values. + this._attenuation.setDistance(distance); + this._directivity.computeAngle(this._forward, this._dx); + this._encoder.setDirection(azimuth, elevation); + } + /** + * Set source's rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff) { + this._attenuation.setRolloff(rolloff); + } + /** + * Set source's minimum distance (in meters). + * @param {Number} minDistance + */ + setMinDistance(minDistance) { + this._attenuation.minDistance = minDistance; + } + /** + * Set source's maximum distance (in meters). + * @param {Number} maxDistance + */ + setMaxDistance(maxDistance) { + this._attenuation.maxDistance = maxDistance; + } + /** + * Set source's gain (linear). + * @param {Number} gain + */ + setGain(gain) { + this.input.gain.value = gain; + } + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { + this._forward[0] = forwardX; + this._forward[1] = forwardY; + this._forward[2] = forwardZ; + this._up[0] = upX; + this._up[1] = upY; + this._up[2] = upZ; + this._right = Utils.crossProduct(this._forward, this._up); + } + // TODO(bitllama): Make sure this works with Three.js as intended. + /** + * Set source's position and orientation using a + * Three.js modelViewMatrix object. + * @param {Float32Array} matrix4 + * The Matrix4 representing the object position and rotation in world space. + */ + setFromMatrix(matrix4) { + this._right[0] = matrix4.elements[0]; + this._right[1] = matrix4.elements[1]; + this._right[2] = matrix4.elements[2]; + this._up[0] = matrix4.elements[4]; + this._up[1] = matrix4.elements[5]; + this._up[2] = matrix4.elements[6]; + this._forward[0] = matrix4.elements[8]; + this._forward[1] = matrix4.elements[9]; + this._forward[2] = matrix4.elements[10]; + // Normalize to remove scaling. + this._right = Utils.normalizeVector(this._right); + this._up = Utils.normalizeVector(this._up); + this._forward = Utils.normalizeVector(this._forward); + // Update position. + this.setPosition(matrix4.elements[12], matrix4.elements[13], matrix4.elements[14]); + } + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth) { + this._encoder.setSourceWidth(sourceWidth); + this.setPosition(this._position[0], this._position[1], this._position[2]); + } + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + */ + setDirectivityPattern(alpha, sharpness) { + this._directivity.setPattern(alpha, sharpness); + this.setPosition(this._position[0], this._position[1], this._position[2]); + } +} +/** + * Determine the distance a source is outside of a room. Attenuate gain going + * to the reflections and reverb when the source is outside of the room. + * @param {Number} distance Distance in meters. + * @return {Number} Gain (linear) of source. + * @private + */ +function _computeDistanceOutsideRoom(distance) { + // We apply a linear ramp from 1 to 0 as the source is up to 1m outside. + let gain = 1; + if (distance > Utils.EPSILON_FLOAT) { + gain = 1 - distance / Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE; + // Clamp gain between 0 and 1. + gain = Math.max(0, Math.min(1, gain)); + } + return gain; +} +export default Source; diff --git a/framework/resonator/vendor/resonance-es6/tables.d.ts b/framework/resonator/vendor/resonance-es6/tables.d.ts new file mode 100644 index 0000000..29723fc --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/tables.d.ts @@ -0,0 +1,38 @@ +declare namespace _default { + export { SPHERICAL_HARMONICS }; + export { SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION }; + export { SPHERICAL_HARMONICS_ELEVATION_RESOLUTION }; + export { SPHERICAL_HARMONICS_MAX_ORDER }; + export { MAX_RE_WEIGHTS }; + export { MAX_RE_WEIGHTS_RESOLUTION }; +} +export default _default; +/** + * Pre-computed Spherical Harmonics Coefficients. + * + * This function generates an efficient lookup table of SH coefficients. It + * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm + * & Plm coefficients only depend on theta, and Em only depends on phi, we + * can separate the equation along these lines. Em does not depend on + * degree, so we only need to compute (2 * l) per azimuth Em total and + * Nlm * Plm is symmetrical across indexes, so only positive indexes are + * computed ((l + 1) * (l + 2) / 2 - 1) per elevation. + * @type {Float32Array} + */ +declare const SPHERICAL_HARMONICS: Float32Array; +/** @type {Number} */ +declare const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION: number; +/** @type {Number} */ +declare const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION: number; +/** + * The maximum allowed ambisonic order. + * @type {Number} + */ +declare const SPHERICAL_HARMONICS_MAX_ORDER: number; +/** + * Pre-computed per-band weighting coefficients for producing energy-preserving + * Max-Re sources. + */ +declare const MAX_RE_WEIGHTS: number[][]; +/** @type {Number} */ +declare const MAX_RE_WEIGHTS_RESOLUTION: number; diff --git a/framework/resonator/vendor/resonance-es6/tables.js b/framework/resonator/vendor/resonance-es6/tables.js new file mode 100644 index 0000000..fa3aae5 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/tables.js @@ -0,0 +1,1144 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Pre-computed lookup tables for encoding ambisonic sources. + * @author Andrew Allen + */ +'use strict'; +/** + * Pre-computed Spherical Harmonics Coefficients. + * + * This function generates an efficient lookup table of SH coefficients. It + * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm + * & Plm coefficients only depend on theta, and Em only depends on phi, we + * can separate the equation along these lines. Em does not depend on + * degree, so we only need to compute (2 * l) per azimuth Em total and + * Nlm * Plm is symmetrical across indexes, so only positive indexes are + * computed ((l + 1) * (l + 2) / 2 - 1) per elevation. + * @type {Float32Array} + */ +const SPHERICAL_HARMONICS = [ + [ + [0.000000, 0.000000, 0.000000, 1.000000, 1.000000, 1.000000], + [0.052336, 0.034899, 0.017452, 0.999848, 0.999391, 0.998630], + [0.104528, 0.069756, 0.034899, 0.999391, 0.997564, 0.994522], + [0.156434, 0.104528, 0.052336, 0.998630, 0.994522, 0.987688], + [0.207912, 0.139173, 0.069756, 0.997564, 0.990268, 0.978148], + [0.258819, 0.173648, 0.087156, 0.996195, 0.984808, 0.965926], + [0.309017, 0.207912, 0.104528, 0.994522, 0.978148, 0.951057], + [0.358368, 0.241922, 0.121869, 0.992546, 0.970296, 0.933580], + [0.406737, 0.275637, 0.139173, 0.990268, 0.961262, 0.913545], + [0.453990, 0.309017, 0.156434, 0.987688, 0.951057, 0.891007], + [0.500000, 0.342020, 0.173648, 0.984808, 0.939693, 0.866025], + [0.544639, 0.374607, 0.190809, 0.981627, 0.927184, 0.838671], + [0.587785, 0.406737, 0.207912, 0.978148, 0.913545, 0.809017], + [0.629320, 0.438371, 0.224951, 0.974370, 0.898794, 0.777146], + [0.669131, 0.469472, 0.241922, 0.970296, 0.882948, 0.743145], + [0.707107, 0.500000, 0.258819, 0.965926, 0.866025, 0.707107], + [0.743145, 0.529919, 0.275637, 0.961262, 0.848048, 0.669131], + [0.777146, 0.559193, 0.292372, 0.956305, 0.829038, 0.629320], + [0.809017, 0.587785, 0.309017, 0.951057, 0.809017, 0.587785], + [0.838671, 0.615661, 0.325568, 0.945519, 0.788011, 0.544639], + [0.866025, 0.642788, 0.342020, 0.939693, 0.766044, 0.500000], + [0.891007, 0.669131, 0.358368, 0.933580, 0.743145, 0.453990], + [0.913545, 0.694658, 0.374607, 0.927184, 0.719340, 0.406737], + [0.933580, 0.719340, 0.390731, 0.920505, 0.694658, 0.358368], + [0.951057, 0.743145, 0.406737, 0.913545, 0.669131, 0.309017], + [0.965926, 0.766044, 0.422618, 0.906308, 0.642788, 0.258819], + [0.978148, 0.788011, 0.438371, 0.898794, 0.615661, 0.207912], + [0.987688, 0.809017, 0.453990, 0.891007, 0.587785, 0.156434], + [0.994522, 0.829038, 0.469472, 0.882948, 0.559193, 0.104528], + [0.998630, 0.848048, 0.484810, 0.874620, 0.529919, 0.052336], + [1.000000, 0.866025, 0.500000, 0.866025, 0.500000, 0.000000], + [0.998630, 0.882948, 0.515038, 0.857167, 0.469472, -0.052336], + [0.994522, 0.898794, 0.529919, 0.848048, 0.438371, -0.104528], + [0.987688, 0.913545, 0.544639, 0.838671, 0.406737, -0.156434], + [0.978148, 0.927184, 0.559193, 0.829038, 0.374607, -0.207912], + [0.965926, 0.939693, 0.573576, 0.819152, 0.342020, -0.258819], + [0.951057, 0.951057, 0.587785, 0.809017, 0.309017, -0.309017], + [0.933580, 0.961262, 0.601815, 0.798636, 0.275637, -0.358368], + [0.913545, 0.970296, 0.615661, 0.788011, 0.241922, -0.406737], + [0.891007, 0.978148, 0.629320, 0.777146, 0.207912, -0.453990], + [0.866025, 0.984808, 0.642788, 0.766044, 0.173648, -0.500000], + [0.838671, 0.990268, 0.656059, 0.754710, 0.139173, -0.544639], + [0.809017, 0.994522, 0.669131, 0.743145, 0.104528, -0.587785], + [0.777146, 0.997564, 0.681998, 0.731354, 0.069756, -0.629320], + [0.743145, 0.999391, 0.694658, 0.719340, 0.034899, -0.669131], + [0.707107, 1.000000, 0.707107, 0.707107, 0.000000, -0.707107], + [0.669131, 0.999391, 0.719340, 0.694658, -0.034899, -0.743145], + [0.629320, 0.997564, 0.731354, 0.681998, -0.069756, -0.777146], + [0.587785, 0.994522, 0.743145, 0.669131, -0.104528, -0.809017], + [0.544639, 0.990268, 0.754710, 0.656059, -0.139173, -0.838671], + [0.500000, 0.984808, 0.766044, 0.642788, -0.173648, -0.866025], + [0.453990, 0.978148, 0.777146, 0.629320, -0.207912, -0.891007], + [0.406737, 0.970296, 0.788011, 0.615661, -0.241922, -0.913545], + [0.358368, 0.961262, 0.798636, 0.601815, -0.275637, -0.933580], + [0.309017, 0.951057, 0.809017, 0.587785, -0.309017, -0.951057], + [0.258819, 0.939693, 0.819152, 0.573576, -0.342020, -0.965926], + [0.207912, 0.927184, 0.829038, 0.559193, -0.374607, -0.978148], + [0.156434, 0.913545, 0.838671, 0.544639, -0.406737, -0.987688], + [0.104528, 0.898794, 0.848048, 0.529919, -0.438371, -0.994522], + [0.052336, 0.882948, 0.857167, 0.515038, -0.469472, -0.998630], + [0.000000, 0.866025, 0.866025, 0.500000, -0.500000, -1.000000], + [-0.052336, 0.848048, 0.874620, 0.484810, -0.529919, -0.998630], + [-0.104528, 0.829038, 0.882948, 0.469472, -0.559193, -0.994522], + [-0.156434, 0.809017, 0.891007, 0.453990, -0.587785, -0.987688], + [-0.207912, 0.788011, 0.898794, 0.438371, -0.615661, -0.978148], + [-0.258819, 0.766044, 0.906308, 0.422618, -0.642788, -0.965926], + [-0.309017, 0.743145, 0.913545, 0.406737, -0.669131, -0.951057], + [-0.358368, 0.719340, 0.920505, 0.390731, -0.694658, -0.933580], + [-0.406737, 0.694658, 0.927184, 0.374607, -0.719340, -0.913545], + [-0.453990, 0.669131, 0.933580, 0.358368, -0.743145, -0.891007], + [-0.500000, 0.642788, 0.939693, 0.342020, -0.766044, -0.866025], + [-0.544639, 0.615661, 0.945519, 0.325568, -0.788011, -0.838671], + [-0.587785, 0.587785, 0.951057, 0.309017, -0.809017, -0.809017], + [-0.629320, 0.559193, 0.956305, 0.292372, -0.829038, -0.777146], + [-0.669131, 0.529919, 0.961262, 0.275637, -0.848048, -0.743145], + [-0.707107, 0.500000, 0.965926, 0.258819, -0.866025, -0.707107], + [-0.743145, 0.469472, 0.970296, 0.241922, -0.882948, -0.669131], + [-0.777146, 0.438371, 0.974370, 0.224951, -0.898794, -0.629320], + [-0.809017, 0.406737, 0.978148, 0.207912, -0.913545, -0.587785], + [-0.838671, 0.374607, 0.981627, 0.190809, -0.927184, -0.544639], + [-0.866025, 0.342020, 0.984808, 0.173648, -0.939693, -0.500000], + [-0.891007, 0.309017, 0.987688, 0.156434, -0.951057, -0.453990], + [-0.913545, 0.275637, 0.990268, 0.139173, -0.961262, -0.406737], + [-0.933580, 0.241922, 0.992546, 0.121869, -0.970296, -0.358368], + [-0.951057, 0.207912, 0.994522, 0.104528, -0.978148, -0.309017], + [-0.965926, 0.173648, 0.996195, 0.087156, -0.984808, -0.258819], + [-0.978148, 0.139173, 0.997564, 0.069756, -0.990268, -0.207912], + [-0.987688, 0.104528, 0.998630, 0.052336, -0.994522, -0.156434], + [-0.994522, 0.069756, 0.999391, 0.034899, -0.997564, -0.104528], + [-0.998630, 0.034899, 0.999848, 0.017452, -0.999391, -0.052336], + [-1.000000, 0.000000, 1.000000, 0.000000, -1.000000, -0.000000], + [-0.998630, -0.034899, 0.999848, -0.017452, -0.999391, 0.052336], + [-0.994522, -0.069756, 0.999391, -0.034899, -0.997564, 0.104528], + [-0.987688, -0.104528, 0.998630, -0.052336, -0.994522, 0.156434], + [-0.978148, -0.139173, 0.997564, -0.069756, -0.990268, 0.207912], + [-0.965926, -0.173648, 0.996195, -0.087156, -0.984808, 0.258819], + [-0.951057, -0.207912, 0.994522, -0.104528, -0.978148, 0.309017], + [-0.933580, -0.241922, 0.992546, -0.121869, -0.970296, 0.358368], + [-0.913545, -0.275637, 0.990268, -0.139173, -0.961262, 0.406737], + [-0.891007, -0.309017, 0.987688, -0.156434, -0.951057, 0.453990], + [-0.866025, -0.342020, 0.984808, -0.173648, -0.939693, 0.500000], + [-0.838671, -0.374607, 0.981627, -0.190809, -0.927184, 0.544639], + [-0.809017, -0.406737, 0.978148, -0.207912, -0.913545, 0.587785], + [-0.777146, -0.438371, 0.974370, -0.224951, -0.898794, 0.629320], + [-0.743145, -0.469472, 0.970296, -0.241922, -0.882948, 0.669131], + [-0.707107, -0.500000, 0.965926, -0.258819, -0.866025, 0.707107], + [-0.669131, -0.529919, 0.961262, -0.275637, -0.848048, 0.743145], + [-0.629320, -0.559193, 0.956305, -0.292372, -0.829038, 0.777146], + [-0.587785, -0.587785, 0.951057, -0.309017, -0.809017, 0.809017], + [-0.544639, -0.615661, 0.945519, -0.325568, -0.788011, 0.838671], + [-0.500000, -0.642788, 0.939693, -0.342020, -0.766044, 0.866025], + [-0.453990, -0.669131, 0.933580, -0.358368, -0.743145, 0.891007], + [-0.406737, -0.694658, 0.927184, -0.374607, -0.719340, 0.913545], + [-0.358368, -0.719340, 0.920505, -0.390731, -0.694658, 0.933580], + [-0.309017, -0.743145, 0.913545, -0.406737, -0.669131, 0.951057], + [-0.258819, -0.766044, 0.906308, -0.422618, -0.642788, 0.965926], + [-0.207912, -0.788011, 0.898794, -0.438371, -0.615661, 0.978148], + [-0.156434, -0.809017, 0.891007, -0.453990, -0.587785, 0.987688], + [-0.104528, -0.829038, 0.882948, -0.469472, -0.559193, 0.994522], + [-0.052336, -0.848048, 0.874620, -0.484810, -0.529919, 0.998630], + [-0.000000, -0.866025, 0.866025, -0.500000, -0.500000, 1.000000], + [0.052336, -0.882948, 0.857167, -0.515038, -0.469472, 0.998630], + [0.104528, -0.898794, 0.848048, -0.529919, -0.438371, 0.994522], + [0.156434, -0.913545, 0.838671, -0.544639, -0.406737, 0.987688], + [0.207912, -0.927184, 0.829038, -0.559193, -0.374607, 0.978148], + [0.258819, -0.939693, 0.819152, -0.573576, -0.342020, 0.965926], + [0.309017, -0.951057, 0.809017, -0.587785, -0.309017, 0.951057], + [0.358368, -0.961262, 0.798636, -0.601815, -0.275637, 0.933580], + [0.406737, -0.970296, 0.788011, -0.615661, -0.241922, 0.913545], + [0.453990, -0.978148, 0.777146, -0.629320, -0.207912, 0.891007], + [0.500000, -0.984808, 0.766044, -0.642788, -0.173648, 0.866025], + [0.544639, -0.990268, 0.754710, -0.656059, -0.139173, 0.838671], + [0.587785, -0.994522, 0.743145, -0.669131, -0.104528, 0.809017], + [0.629320, -0.997564, 0.731354, -0.681998, -0.069756, 0.777146], + [0.669131, -0.999391, 0.719340, -0.694658, -0.034899, 0.743145], + [0.707107, -1.000000, 0.707107, -0.707107, -0.000000, 0.707107], + [0.743145, -0.999391, 0.694658, -0.719340, 0.034899, 0.669131], + [0.777146, -0.997564, 0.681998, -0.731354, 0.069756, 0.629320], + [0.809017, -0.994522, 0.669131, -0.743145, 0.104528, 0.587785], + [0.838671, -0.990268, 0.656059, -0.754710, 0.139173, 0.544639], + [0.866025, -0.984808, 0.642788, -0.766044, 0.173648, 0.500000], + [0.891007, -0.978148, 0.629320, -0.777146, 0.207912, 0.453990], + [0.913545, -0.970296, 0.615661, -0.788011, 0.241922, 0.406737], + [0.933580, -0.961262, 0.601815, -0.798636, 0.275637, 0.358368], + [0.951057, -0.951057, 0.587785, -0.809017, 0.309017, 0.309017], + [0.965926, -0.939693, 0.573576, -0.819152, 0.342020, 0.258819], + [0.978148, -0.927184, 0.559193, -0.829038, 0.374607, 0.207912], + [0.987688, -0.913545, 0.544639, -0.838671, 0.406737, 0.156434], + [0.994522, -0.898794, 0.529919, -0.848048, 0.438371, 0.104528], + [0.998630, -0.882948, 0.515038, -0.857167, 0.469472, 0.052336], + [1.000000, -0.866025, 0.500000, -0.866025, 0.500000, 0.000000], + [0.998630, -0.848048, 0.484810, -0.874620, 0.529919, -0.052336], + [0.994522, -0.829038, 0.469472, -0.882948, 0.559193, -0.104528], + [0.987688, -0.809017, 0.453990, -0.891007, 0.587785, -0.156434], + [0.978148, -0.788011, 0.438371, -0.898794, 0.615661, -0.207912], + [0.965926, -0.766044, 0.422618, -0.906308, 0.642788, -0.258819], + [0.951057, -0.743145, 0.406737, -0.913545, 0.669131, -0.309017], + [0.933580, -0.719340, 0.390731, -0.920505, 0.694658, -0.358368], + [0.913545, -0.694658, 0.374607, -0.927184, 0.719340, -0.406737], + [0.891007, -0.669131, 0.358368, -0.933580, 0.743145, -0.453990], + [0.866025, -0.642788, 0.342020, -0.939693, 0.766044, -0.500000], + [0.838671, -0.615661, 0.325568, -0.945519, 0.788011, -0.544639], + [0.809017, -0.587785, 0.309017, -0.951057, 0.809017, -0.587785], + [0.777146, -0.559193, 0.292372, -0.956305, 0.829038, -0.629320], + [0.743145, -0.529919, 0.275637, -0.961262, 0.848048, -0.669131], + [0.707107, -0.500000, 0.258819, -0.965926, 0.866025, -0.707107], + [0.669131, -0.469472, 0.241922, -0.970296, 0.882948, -0.743145], + [0.629320, -0.438371, 0.224951, -0.974370, 0.898794, -0.777146], + [0.587785, -0.406737, 0.207912, -0.978148, 0.913545, -0.809017], + [0.544639, -0.374607, 0.190809, -0.981627, 0.927184, -0.838671], + [0.500000, -0.342020, 0.173648, -0.984808, 0.939693, -0.866025], + [0.453990, -0.309017, 0.156434, -0.987688, 0.951057, -0.891007], + [0.406737, -0.275637, 0.139173, -0.990268, 0.961262, -0.913545], + [0.358368, -0.241922, 0.121869, -0.992546, 0.970296, -0.933580], + [0.309017, -0.207912, 0.104528, -0.994522, 0.978148, -0.951057], + [0.258819, -0.173648, 0.087156, -0.996195, 0.984808, -0.965926], + [0.207912, -0.139173, 0.069756, -0.997564, 0.990268, -0.978148], + [0.156434, -0.104528, 0.052336, -0.998630, 0.994522, -0.987688], + [0.104528, -0.069756, 0.034899, -0.999391, 0.997564, -0.994522], + [0.052336, -0.034899, 0.017452, -0.999848, 0.999391, -0.998630], + [0.000000, -0.000000, 0.000000, -1.000000, 1.000000, -1.000000], + [-0.052336, 0.034899, -0.017452, -0.999848, 0.999391, -0.998630], + [-0.104528, 0.069756, -0.034899, -0.999391, 0.997564, -0.994522], + [-0.156434, 0.104528, -0.052336, -0.998630, 0.994522, -0.987688], + [-0.207912, 0.139173, -0.069756, -0.997564, 0.990268, -0.978148], + [-0.258819, 0.173648, -0.087156, -0.996195, 0.984808, -0.965926], + [-0.309017, 0.207912, -0.104528, -0.994522, 0.978148, -0.951057], + [-0.358368, 0.241922, -0.121869, -0.992546, 0.970296, -0.933580], + [-0.406737, 0.275637, -0.139173, -0.990268, 0.961262, -0.913545], + [-0.453990, 0.309017, -0.156434, -0.987688, 0.951057, -0.891007], + [-0.500000, 0.342020, -0.173648, -0.984808, 0.939693, -0.866025], + [-0.544639, 0.374607, -0.190809, -0.981627, 0.927184, -0.838671], + [-0.587785, 0.406737, -0.207912, -0.978148, 0.913545, -0.809017], + [-0.629320, 0.438371, -0.224951, -0.974370, 0.898794, -0.777146], + [-0.669131, 0.469472, -0.241922, -0.970296, 0.882948, -0.743145], + [-0.707107, 0.500000, -0.258819, -0.965926, 0.866025, -0.707107], + [-0.743145, 0.529919, -0.275637, -0.961262, 0.848048, -0.669131], + [-0.777146, 0.559193, -0.292372, -0.956305, 0.829038, -0.629320], + [-0.809017, 0.587785, -0.309017, -0.951057, 0.809017, -0.587785], + [-0.838671, 0.615661, -0.325568, -0.945519, 0.788011, -0.544639], + [-0.866025, 0.642788, -0.342020, -0.939693, 0.766044, -0.500000], + [-0.891007, 0.669131, -0.358368, -0.933580, 0.743145, -0.453990], + [-0.913545, 0.694658, -0.374607, -0.927184, 0.719340, -0.406737], + [-0.933580, 0.719340, -0.390731, -0.920505, 0.694658, -0.358368], + [-0.951057, 0.743145, -0.406737, -0.913545, 0.669131, -0.309017], + [-0.965926, 0.766044, -0.422618, -0.906308, 0.642788, -0.258819], + [-0.978148, 0.788011, -0.438371, -0.898794, 0.615661, -0.207912], + [-0.987688, 0.809017, -0.453990, -0.891007, 0.587785, -0.156434], + [-0.994522, 0.829038, -0.469472, -0.882948, 0.559193, -0.104528], + [-0.998630, 0.848048, -0.484810, -0.874620, 0.529919, -0.052336], + [-1.000000, 0.866025, -0.500000, -0.866025, 0.500000, 0.000000], + [-0.998630, 0.882948, -0.515038, -0.857167, 0.469472, 0.052336], + [-0.994522, 0.898794, -0.529919, -0.848048, 0.438371, 0.104528], + [-0.987688, 0.913545, -0.544639, -0.838671, 0.406737, 0.156434], + [-0.978148, 0.927184, -0.559193, -0.829038, 0.374607, 0.207912], + [-0.965926, 0.939693, -0.573576, -0.819152, 0.342020, 0.258819], + [-0.951057, 0.951057, -0.587785, -0.809017, 0.309017, 0.309017], + [-0.933580, 0.961262, -0.601815, -0.798636, 0.275637, 0.358368], + [-0.913545, 0.970296, -0.615661, -0.788011, 0.241922, 0.406737], + [-0.891007, 0.978148, -0.629320, -0.777146, 0.207912, 0.453990], + [-0.866025, 0.984808, -0.642788, -0.766044, 0.173648, 0.500000], + [-0.838671, 0.990268, -0.656059, -0.754710, 0.139173, 0.544639], + [-0.809017, 0.994522, -0.669131, -0.743145, 0.104528, 0.587785], + [-0.777146, 0.997564, -0.681998, -0.731354, 0.069756, 0.629320], + [-0.743145, 0.999391, -0.694658, -0.719340, 0.034899, 0.669131], + [-0.707107, 1.000000, -0.707107, -0.707107, 0.000000, 0.707107], + [-0.669131, 0.999391, -0.719340, -0.694658, -0.034899, 0.743145], + [-0.629320, 0.997564, -0.731354, -0.681998, -0.069756, 0.777146], + [-0.587785, 0.994522, -0.743145, -0.669131, -0.104528, 0.809017], + [-0.544639, 0.990268, -0.754710, -0.656059, -0.139173, 0.838671], + [-0.500000, 0.984808, -0.766044, -0.642788, -0.173648, 0.866025], + [-0.453990, 0.978148, -0.777146, -0.629320, -0.207912, 0.891007], + [-0.406737, 0.970296, -0.788011, -0.615661, -0.241922, 0.913545], + [-0.358368, 0.961262, -0.798636, -0.601815, -0.275637, 0.933580], + [-0.309017, 0.951057, -0.809017, -0.587785, -0.309017, 0.951057], + [-0.258819, 0.939693, -0.819152, -0.573576, -0.342020, 0.965926], + [-0.207912, 0.927184, -0.829038, -0.559193, -0.374607, 0.978148], + [-0.156434, 0.913545, -0.838671, -0.544639, -0.406737, 0.987688], + [-0.104528, 0.898794, -0.848048, -0.529919, -0.438371, 0.994522], + [-0.052336, 0.882948, -0.857167, -0.515038, -0.469472, 0.998630], + [-0.000000, 0.866025, -0.866025, -0.500000, -0.500000, 1.000000], + [0.052336, 0.848048, -0.874620, -0.484810, -0.529919, 0.998630], + [0.104528, 0.829038, -0.882948, -0.469472, -0.559193, 0.994522], + [0.156434, 0.809017, -0.891007, -0.453990, -0.587785, 0.987688], + [0.207912, 0.788011, -0.898794, -0.438371, -0.615661, 0.978148], + [0.258819, 0.766044, -0.906308, -0.422618, -0.642788, 0.965926], + [0.309017, 0.743145, -0.913545, -0.406737, -0.669131, 0.951057], + [0.358368, 0.719340, -0.920505, -0.390731, -0.694658, 0.933580], + [0.406737, 0.694658, -0.927184, -0.374607, -0.719340, 0.913545], + [0.453990, 0.669131, -0.933580, -0.358368, -0.743145, 0.891007], + [0.500000, 0.642788, -0.939693, -0.342020, -0.766044, 0.866025], + [0.544639, 0.615661, -0.945519, -0.325568, -0.788011, 0.838671], + [0.587785, 0.587785, -0.951057, -0.309017, -0.809017, 0.809017], + [0.629320, 0.559193, -0.956305, -0.292372, -0.829038, 0.777146], + [0.669131, 0.529919, -0.961262, -0.275637, -0.848048, 0.743145], + [0.707107, 0.500000, -0.965926, -0.258819, -0.866025, 0.707107], + [0.743145, 0.469472, -0.970296, -0.241922, -0.882948, 0.669131], + [0.777146, 0.438371, -0.974370, -0.224951, -0.898794, 0.629320], + [0.809017, 0.406737, -0.978148, -0.207912, -0.913545, 0.587785], + [0.838671, 0.374607, -0.981627, -0.190809, -0.927184, 0.544639], + [0.866025, 0.342020, -0.984808, -0.173648, -0.939693, 0.500000], + [0.891007, 0.309017, -0.987688, -0.156434, -0.951057, 0.453990], + [0.913545, 0.275637, -0.990268, -0.139173, -0.961262, 0.406737], + [0.933580, 0.241922, -0.992546, -0.121869, -0.970296, 0.358368], + [0.951057, 0.207912, -0.994522, -0.104528, -0.978148, 0.309017], + [0.965926, 0.173648, -0.996195, -0.087156, -0.984808, 0.258819], + [0.978148, 0.139173, -0.997564, -0.069756, -0.990268, 0.207912], + [0.987688, 0.104528, -0.998630, -0.052336, -0.994522, 0.156434], + [0.994522, 0.069756, -0.999391, -0.034899, -0.997564, 0.104528], + [0.998630, 0.034899, -0.999848, -0.017452, -0.999391, 0.052336], + [1.000000, 0.000000, -1.000000, -0.000000, -1.000000, 0.000000], + [0.998630, -0.034899, -0.999848, 0.017452, -0.999391, -0.052336], + [0.994522, -0.069756, -0.999391, 0.034899, -0.997564, -0.104528], + [0.987688, -0.104528, -0.998630, 0.052336, -0.994522, -0.156434], + [0.978148, -0.139173, -0.997564, 0.069756, -0.990268, -0.207912], + [0.965926, -0.173648, -0.996195, 0.087156, -0.984808, -0.258819], + [0.951057, -0.207912, -0.994522, 0.104528, -0.978148, -0.309017], + [0.933580, -0.241922, -0.992546, 0.121869, -0.970296, -0.358368], + [0.913545, -0.275637, -0.990268, 0.139173, -0.961262, -0.406737], + [0.891007, -0.309017, -0.987688, 0.156434, -0.951057, -0.453990], + [0.866025, -0.342020, -0.984808, 0.173648, -0.939693, -0.500000], + [0.838671, -0.374607, -0.981627, 0.190809, -0.927184, -0.544639], + [0.809017, -0.406737, -0.978148, 0.207912, -0.913545, -0.587785], + [0.777146, -0.438371, -0.974370, 0.224951, -0.898794, -0.629320], + [0.743145, -0.469472, -0.970296, 0.241922, -0.882948, -0.669131], + [0.707107, -0.500000, -0.965926, 0.258819, -0.866025, -0.707107], + [0.669131, -0.529919, -0.961262, 0.275637, -0.848048, -0.743145], + [0.629320, -0.559193, -0.956305, 0.292372, -0.829038, -0.777146], + [0.587785, -0.587785, -0.951057, 0.309017, -0.809017, -0.809017], + [0.544639, -0.615661, -0.945519, 0.325568, -0.788011, -0.838671], + [0.500000, -0.642788, -0.939693, 0.342020, -0.766044, -0.866025], + [0.453990, -0.669131, -0.933580, 0.358368, -0.743145, -0.891007], + [0.406737, -0.694658, -0.927184, 0.374607, -0.719340, -0.913545], + [0.358368, -0.719340, -0.920505, 0.390731, -0.694658, -0.933580], + [0.309017, -0.743145, -0.913545, 0.406737, -0.669131, -0.951057], + [0.258819, -0.766044, -0.906308, 0.422618, -0.642788, -0.965926], + [0.207912, -0.788011, -0.898794, 0.438371, -0.615661, -0.978148], + [0.156434, -0.809017, -0.891007, 0.453990, -0.587785, -0.987688], + [0.104528, -0.829038, -0.882948, 0.469472, -0.559193, -0.994522], + [0.052336, -0.848048, -0.874620, 0.484810, -0.529919, -0.998630], + [0.000000, -0.866025, -0.866025, 0.500000, -0.500000, -1.000000], + [-0.052336, -0.882948, -0.857167, 0.515038, -0.469472, -0.998630], + [-0.104528, -0.898794, -0.848048, 0.529919, -0.438371, -0.994522], + [-0.156434, -0.913545, -0.838671, 0.544639, -0.406737, -0.987688], + [-0.207912, -0.927184, -0.829038, 0.559193, -0.374607, -0.978148], + [-0.258819, -0.939693, -0.819152, 0.573576, -0.342020, -0.965926], + [-0.309017, -0.951057, -0.809017, 0.587785, -0.309017, -0.951057], + [-0.358368, -0.961262, -0.798636, 0.601815, -0.275637, -0.933580], + [-0.406737, -0.970296, -0.788011, 0.615661, -0.241922, -0.913545], + [-0.453990, -0.978148, -0.777146, 0.629320, -0.207912, -0.891007], + [-0.500000, -0.984808, -0.766044, 0.642788, -0.173648, -0.866025], + [-0.544639, -0.990268, -0.754710, 0.656059, -0.139173, -0.838671], + [-0.587785, -0.994522, -0.743145, 0.669131, -0.104528, -0.809017], + [-0.629320, -0.997564, -0.731354, 0.681998, -0.069756, -0.777146], + [-0.669131, -0.999391, -0.719340, 0.694658, -0.034899, -0.743145], + [-0.707107, -1.000000, -0.707107, 0.707107, -0.000000, -0.707107], + [-0.743145, -0.999391, -0.694658, 0.719340, 0.034899, -0.669131], + [-0.777146, -0.997564, -0.681998, 0.731354, 0.069756, -0.629320], + [-0.809017, -0.994522, -0.669131, 0.743145, 0.104528, -0.587785], + [-0.838671, -0.990268, -0.656059, 0.754710, 0.139173, -0.544639], + [-0.866025, -0.984808, -0.642788, 0.766044, 0.173648, -0.500000], + [-0.891007, -0.978148, -0.629320, 0.777146, 0.207912, -0.453990], + [-0.913545, -0.970296, -0.615661, 0.788011, 0.241922, -0.406737], + [-0.933580, -0.961262, -0.601815, 0.798636, 0.275637, -0.358368], + [-0.951057, -0.951057, -0.587785, 0.809017, 0.309017, -0.309017], + [-0.965926, -0.939693, -0.573576, 0.819152, 0.342020, -0.258819], + [-0.978148, -0.927184, -0.559193, 0.829038, 0.374607, -0.207912], + [-0.987688, -0.913545, -0.544639, 0.838671, 0.406737, -0.156434], + [-0.994522, -0.898794, -0.529919, 0.848048, 0.438371, -0.104528], + [-0.998630, -0.882948, -0.515038, 0.857167, 0.469472, -0.052336], + [-1.000000, -0.866025, -0.500000, 0.866025, 0.500000, -0.000000], + [-0.998630, -0.848048, -0.484810, 0.874620, 0.529919, 0.052336], + [-0.994522, -0.829038, -0.469472, 0.882948, 0.559193, 0.104528], + [-0.987688, -0.809017, -0.453990, 0.891007, 0.587785, 0.156434], + [-0.978148, -0.788011, -0.438371, 0.898794, 0.615661, 0.207912], + [-0.965926, -0.766044, -0.422618, 0.906308, 0.642788, 0.258819], + [-0.951057, -0.743145, -0.406737, 0.913545, 0.669131, 0.309017], + [-0.933580, -0.719340, -0.390731, 0.920505, 0.694658, 0.358368], + [-0.913545, -0.694658, -0.374607, 0.927184, 0.719340, 0.406737], + [-0.891007, -0.669131, -0.358368, 0.933580, 0.743145, 0.453990], + [-0.866025, -0.642788, -0.342020, 0.939693, 0.766044, 0.500000], + [-0.838671, -0.615661, -0.325568, 0.945519, 0.788011, 0.544639], + [-0.809017, -0.587785, -0.309017, 0.951057, 0.809017, 0.587785], + [-0.777146, -0.559193, -0.292372, 0.956305, 0.829038, 0.629320], + [-0.743145, -0.529919, -0.275637, 0.961262, 0.848048, 0.669131], + [-0.707107, -0.500000, -0.258819, 0.965926, 0.866025, 0.707107], + [-0.669131, -0.469472, -0.241922, 0.970296, 0.882948, 0.743145], + [-0.629320, -0.438371, -0.224951, 0.974370, 0.898794, 0.777146], + [-0.587785, -0.406737, -0.207912, 0.978148, 0.913545, 0.809017], + [-0.544639, -0.374607, -0.190809, 0.981627, 0.927184, 0.838671], + [-0.500000, -0.342020, -0.173648, 0.984808, 0.939693, 0.866025], + [-0.453990, -0.309017, -0.156434, 0.987688, 0.951057, 0.891007], + [-0.406737, -0.275637, -0.139173, 0.990268, 0.961262, 0.913545], + [-0.358368, -0.241922, -0.121869, 0.992546, 0.970296, 0.933580], + [-0.309017, -0.207912, -0.104528, 0.994522, 0.978148, 0.951057], + [-0.258819, -0.173648, -0.087156, 0.996195, 0.984808, 0.965926], + [-0.207912, -0.139173, -0.069756, 0.997564, 0.990268, 0.978148], + [-0.156434, -0.104528, -0.052336, 0.998630, 0.994522, 0.987688], + [-0.104528, -0.069756, -0.034899, 0.999391, 0.997564, 0.994522], + [-0.052336, -0.034899, -0.017452, 0.999848, 0.999391, 0.998630], + ], + [ + [-1.000000, -0.000000, 1.000000, -0.000000, 0.000000, + -1.000000, -0.000000, 0.000000, -0.000000], + [-0.999848, 0.017452, 0.999543, -0.030224, 0.000264, + -0.999086, 0.042733, -0.000590, 0.000004], + [-0.999391, 0.034899, 0.998173, -0.060411, 0.001055, + -0.996348, 0.085356, -0.002357, 0.000034], + [-0.998630, 0.052336, 0.995891, -0.090524, 0.002372, + -0.991791, 0.127757, -0.005297, 0.000113], + [-0.997564, 0.069756, 0.992701, -0.120527, 0.004214, + -0.985429, 0.169828, -0.009400, 0.000268], + [-0.996195, 0.087156, 0.988606, -0.150384, 0.006578, + -0.977277, 0.211460, -0.014654, 0.000523], + [-0.994522, 0.104528, 0.983611, -0.180057, 0.009462, + -0.967356, 0.252544, -0.021043, 0.000903], + [-0.992546, 0.121869, 0.977722, -0.209511, 0.012862, + -0.955693, 0.292976, -0.028547, 0.001431], + [-0.990268, 0.139173, 0.970946, -0.238709, 0.016774, + -0.942316, 0.332649, -0.037143, 0.002131], + [-0.987688, 0.156434, 0.963292, -0.267617, 0.021193, + -0.927262, 0.371463, -0.046806, 0.003026], + [-0.984808, 0.173648, 0.954769, -0.296198, 0.026114, + -0.910569, 0.409317, -0.057505, 0.004140], + [-0.981627, 0.190809, 0.945388, -0.324419, 0.031530, + -0.892279, 0.446114, -0.069209, 0.005492], + [-0.978148, 0.207912, 0.935159, -0.352244, 0.037436, + -0.872441, 0.481759, -0.081880, 0.007105], + [-0.974370, 0.224951, 0.924096, -0.379641, 0.043823, + -0.851105, 0.516162, -0.095481, 0.008999], + [-0.970296, 0.241922, 0.912211, -0.406574, 0.050685, + -0.828326, 0.549233, -0.109969, 0.011193], + [-0.965926, 0.258819, 0.899519, -0.433013, 0.058013, + -0.804164, 0.580889, -0.125300, 0.013707], + [-0.961262, 0.275637, 0.886036, -0.458924, 0.065797, + -0.778680, 0.611050, -0.141427, 0.016556], + [-0.956305, 0.292372, 0.871778, -0.484275, 0.074029, + -0.751940, 0.639639, -0.158301, 0.019758], + [-0.951057, 0.309017, 0.856763, -0.509037, 0.082698, + -0.724012, 0.666583, -0.175868, 0.023329], + [-0.945519, 0.325568, 0.841008, -0.533178, 0.091794, + -0.694969, 0.691816, -0.194075, 0.027281], + [-0.939693, 0.342020, 0.824533, -0.556670, 0.101306, + -0.664885, 0.715274, -0.212865, 0.031630], + [-0.933580, 0.358368, 0.807359, -0.579484, 0.111222, + -0.633837, 0.736898, -0.232180, 0.036385], + [-0.927184, 0.374607, 0.789505, -0.601592, 0.121529, + -0.601904, 0.756637, -0.251960, 0.041559], + [-0.920505, 0.390731, 0.770994, -0.622967, 0.132217, + -0.569169, 0.774442, -0.272143, 0.047160], + [-0.913545, 0.406737, 0.751848, -0.643582, 0.143271, + -0.535715, 0.790270, -0.292666, 0.053196], + [-0.906308, 0.422618, 0.732091, -0.663414, 0.154678, + -0.501627, 0.804083, -0.313464, 0.059674], + [-0.898794, 0.438371, 0.711746, -0.682437, 0.166423, + -0.466993, 0.815850, -0.334472, 0.066599], + [-0.891007, 0.453990, 0.690839, -0.700629, 0.178494, + -0.431899, 0.825544, -0.355623, 0.073974], + [-0.882948, 0.469472, 0.669395, -0.717968, 0.190875, + -0.396436, 0.833145, -0.376851, 0.081803], + [-0.874620, 0.484810, 0.647439, -0.734431, 0.203551, + -0.360692, 0.838638, -0.398086, 0.090085], + [-0.866025, 0.500000, 0.625000, -0.750000, 0.216506, + -0.324760, 0.842012, -0.419263, 0.098821], + [-0.857167, 0.515038, 0.602104, -0.764655, 0.229726, + -0.288728, 0.843265, -0.440311, 0.108009], + [-0.848048, 0.529919, 0.578778, -0.778378, 0.243192, + -0.252688, 0.842399, -0.461164, 0.117644], + [-0.838671, 0.544639, 0.555052, -0.791154, 0.256891, + -0.216730, 0.839422, -0.481753, 0.127722], + [-0.829038, 0.559193, 0.530955, -0.802965, 0.270803, + -0.180944, 0.834347, -0.502011, 0.138237], + [-0.819152, 0.573576, 0.506515, -0.813798, 0.284914, + -0.145420, 0.827194, -0.521871, 0.149181], + [-0.809017, 0.587785, 0.481763, -0.823639, 0.299204, + -0.110246, 0.817987, -0.541266, 0.160545], + [-0.798636, 0.601815, 0.456728, -0.832477, 0.313658, + -0.075508, 0.806757, -0.560132, 0.172317], + [-0.788011, 0.615661, 0.431441, -0.840301, 0.328257, + -0.041294, 0.793541, -0.578405, 0.184487], + [-0.777146, 0.629320, 0.405934, -0.847101, 0.342984, + -0.007686, 0.778379, -0.596021, 0.197040], + [-0.766044, 0.642788, 0.380236, -0.852869, 0.357821, + 0.025233, 0.761319, -0.612921, 0.209963], + [-0.754710, 0.656059, 0.354380, -0.857597, 0.372749, + 0.057383, 0.742412, -0.629044, 0.223238], + [-0.743145, 0.669131, 0.328396, -0.861281, 0.387751, + 0.088686, 0.721714, -0.644334, 0.236850], + [-0.731354, 0.681998, 0.302317, -0.863916, 0.402807, + 0.119068, 0.699288, -0.658734, 0.250778], + [-0.719340, 0.694658, 0.276175, -0.865498, 0.417901, + 0.148454, 0.675199, -0.672190, 0.265005], + [-0.707107, 0.707107, 0.250000, -0.866025, 0.433013, + 0.176777, 0.649519, -0.684653, 0.279508], + [-0.694658, 0.719340, 0.223825, -0.865498, 0.448125, + 0.203969, 0.622322, -0.696073, 0.294267], + [-0.681998, 0.731354, 0.197683, -0.863916, 0.463218, + 0.229967, 0.593688, -0.706405, 0.309259], + [-0.669131, 0.743145, 0.171604, -0.861281, 0.478275, + 0.254712, 0.563700, -0.715605, 0.324459], + [-0.656059, 0.754710, 0.145620, -0.857597, 0.493276, + 0.278147, 0.532443, -0.723633, 0.339844], + [-0.642788, 0.766044, 0.119764, -0.852869, 0.508205, + 0.300221, 0.500009, -0.730451, 0.355387], + [-0.629320, 0.777146, 0.094066, -0.847101, 0.523041, + 0.320884, 0.466490, -0.736025, 0.371063], + [-0.615661, 0.788011, 0.068559, -0.840301, 0.537768, + 0.340093, 0.431982, -0.740324, 0.386845], + [-0.601815, 0.798636, 0.043272, -0.832477, 0.552367, + 0.357807, 0.396584, -0.743320, 0.402704], + [-0.587785, 0.809017, 0.018237, -0.823639, 0.566821, + 0.373991, 0.360397, -0.744989, 0.418613], + [-0.573576, 0.819152, -0.006515, -0.813798, 0.581112, + 0.388612, 0.323524, -0.745308, 0.434544], + [-0.559193, 0.829038, -0.030955, -0.802965, 0.595222, + 0.401645, 0.286069, -0.744262, 0.450467], + [-0.544639, 0.838671, -0.055052, -0.791154, 0.609135, + 0.413066, 0.248140, -0.741835, 0.466352], + [-0.529919, 0.848048, -0.078778, -0.778378, 0.622833, + 0.422856, 0.209843, -0.738017, 0.482171], + [-0.515038, 0.857167, -0.102104, -0.764655, 0.636300, + 0.431004, 0.171288, -0.732801, 0.497894], + [-0.500000, 0.866025, -0.125000, -0.750000, 0.649519, + 0.437500, 0.132583, -0.726184, 0.513490], + [-0.484810, 0.874620, -0.147439, -0.734431, 0.662474, + 0.442340, 0.093837, -0.718167, 0.528929], + [-0.469472, 0.882948, -0.169395, -0.717968, 0.675150, + 0.445524, 0.055160, -0.708753, 0.544183], + [-0.453990, 0.891007, -0.190839, -0.700629, 0.687531, + 0.447059, 0.016662, -0.697950, 0.559220], + [-0.438371, 0.898794, -0.211746, -0.682437, 0.699602, + 0.446953, -0.021550, -0.685769, 0.574011], + [-0.422618, 0.906308, -0.232091, -0.663414, 0.711348, + 0.445222, -0.059368, -0.672226, 0.588528], + [-0.406737, 0.913545, -0.251848, -0.643582, 0.722755, + 0.441884, -0.096684, -0.657339, 0.602741], + [-0.390731, 0.920505, -0.270994, -0.622967, 0.733809, + 0.436964, -0.133395, -0.641130, 0.616621], + [-0.374607, 0.927184, -0.289505, -0.601592, 0.744496, + 0.430488, -0.169397, -0.623624, 0.630141], + [-0.358368, 0.933580, -0.307359, -0.579484, 0.754804, + 0.422491, -0.204589, -0.604851, 0.643273], + [-0.342020, 0.939693, -0.324533, -0.556670, 0.764720, + 0.413008, -0.238872, -0.584843, 0.655990], + [-0.325568, 0.945519, -0.341008, -0.533178, 0.774231, + 0.402081, -0.272150, -0.563635, 0.668267], + [-0.309017, 0.951057, -0.356763, -0.509037, 0.783327, + 0.389754, -0.304329, -0.541266, 0.680078], + [-0.292372, 0.956305, -0.371778, -0.484275, 0.791997, + 0.376077, -0.335319, -0.517778, 0.691399], + [-0.275637, 0.961262, -0.386036, -0.458924, 0.800228, + 0.361102, -0.365034, -0.493216, 0.702207], + [-0.258819, 0.965926, -0.399519, -0.433013, 0.808013, + 0.344885, -0.393389, -0.467627, 0.712478], + [-0.241922, 0.970296, -0.412211, -0.406574, 0.815340, + 0.327486, -0.420306, -0.441061, 0.722191], + [-0.224951, 0.974370, -0.424096, -0.379641, 0.822202, + 0.308969, -0.445709, -0.413572, 0.731327], + [-0.207912, 0.978148, -0.435159, -0.352244, 0.828589, + 0.289399, -0.469527, -0.385215, 0.739866], + [-0.190809, 0.981627, -0.445388, -0.324419, 0.834495, + 0.268846, -0.491693, -0.356047, 0.747790], + [-0.173648, 0.984808, -0.454769, -0.296198, 0.839912, + 0.247382, -0.512145, -0.326129, 0.755082], + [-0.156434, 0.987688, -0.463292, -0.267617, 0.844832, + 0.225081, -0.530827, -0.295521, 0.761728], + [-0.139173, 0.990268, -0.470946, -0.238709, 0.849251, + 0.202020, -0.547684, -0.264287, 0.767712], + [-0.121869, 0.992546, -0.477722, -0.209511, 0.853163, + 0.178279, -0.562672, -0.232494, 0.773023], + [-0.104528, 0.994522, -0.483611, -0.180057, 0.856563, + 0.153937, -0.575747, -0.200207, 0.777648], + [-0.087156, 0.996195, -0.488606, -0.150384, 0.859447, + 0.129078, -0.586872, -0.167494, 0.781579], + [-0.069756, 0.997564, -0.492701, -0.120527, 0.861811, + 0.103786, -0.596018, -0.134426, 0.784806], + [-0.052336, 0.998630, -0.495891, -0.090524, 0.863653, + 0.078146, -0.603158, -0.101071, 0.787324], + [-0.034899, 0.999391, -0.498173, -0.060411, 0.864971, + 0.052243, -0.608272, -0.067500, 0.789126], + [-0.017452, 0.999848, -0.499543, -0.030224, 0.865762, + 0.026165, -0.611347, -0.033786, 0.790208], + [0.000000, 1.000000, -0.500000, 0.000000, 0.866025, + -0.000000, -0.612372, 0.000000, 0.790569], + [0.017452, 0.999848, -0.499543, 0.030224, 0.865762, + -0.026165, -0.611347, 0.033786, 0.790208], + [0.034899, 0.999391, -0.498173, 0.060411, 0.864971, + -0.052243, -0.608272, 0.067500, 0.789126], + [0.052336, 0.998630, -0.495891, 0.090524, 0.863653, + -0.078146, -0.603158, 0.101071, 0.787324], + [0.069756, 0.997564, -0.492701, 0.120527, 0.861811, + -0.103786, -0.596018, 0.134426, 0.784806], + [0.087156, 0.996195, -0.488606, 0.150384, 0.859447, + -0.129078, -0.586872, 0.167494, 0.781579], + [0.104528, 0.994522, -0.483611, 0.180057, 0.856563, + -0.153937, -0.575747, 0.200207, 0.777648], + [0.121869, 0.992546, -0.477722, 0.209511, 0.853163, + -0.178279, -0.562672, 0.232494, 0.773023], + [0.139173, 0.990268, -0.470946, 0.238709, 0.849251, + -0.202020, -0.547684, 0.264287, 0.767712], + [0.156434, 0.987688, -0.463292, 0.267617, 0.844832, + -0.225081, -0.530827, 0.295521, 0.761728], + [0.173648, 0.984808, -0.454769, 0.296198, 0.839912, + -0.247382, -0.512145, 0.326129, 0.755082], + [0.190809, 0.981627, -0.445388, 0.324419, 0.834495, + -0.268846, -0.491693, 0.356047, 0.747790], + [0.207912, 0.978148, -0.435159, 0.352244, 0.828589, + -0.289399, -0.469527, 0.385215, 0.739866], + [0.224951, 0.974370, -0.424096, 0.379641, 0.822202, + -0.308969, -0.445709, 0.413572, 0.731327], + [0.241922, 0.970296, -0.412211, 0.406574, 0.815340, + -0.327486, -0.420306, 0.441061, 0.722191], + [0.258819, 0.965926, -0.399519, 0.433013, 0.808013, + -0.344885, -0.393389, 0.467627, 0.712478], + [0.275637, 0.961262, -0.386036, 0.458924, 0.800228, + -0.361102, -0.365034, 0.493216, 0.702207], + [0.292372, 0.956305, -0.371778, 0.484275, 0.791997, + -0.376077, -0.335319, 0.517778, 0.691399], + [0.309017, 0.951057, -0.356763, 0.509037, 0.783327, + -0.389754, -0.304329, 0.541266, 0.680078], + [0.325568, 0.945519, -0.341008, 0.533178, 0.774231, + -0.402081, -0.272150, 0.563635, 0.668267], + [0.342020, 0.939693, -0.324533, 0.556670, 0.764720, + -0.413008, -0.238872, 0.584843, 0.655990], + [0.358368, 0.933580, -0.307359, 0.579484, 0.754804, + -0.422491, -0.204589, 0.604851, 0.643273], + [0.374607, 0.927184, -0.289505, 0.601592, 0.744496, + -0.430488, -0.169397, 0.623624, 0.630141], + [0.390731, 0.920505, -0.270994, 0.622967, 0.733809, + -0.436964, -0.133395, 0.641130, 0.616621], + [0.406737, 0.913545, -0.251848, 0.643582, 0.722755, + -0.441884, -0.096684, 0.657339, 0.602741], + [0.422618, 0.906308, -0.232091, 0.663414, 0.711348, + -0.445222, -0.059368, 0.672226, 0.588528], + [0.438371, 0.898794, -0.211746, 0.682437, 0.699602, + -0.446953, -0.021550, 0.685769, 0.574011], + [0.453990, 0.891007, -0.190839, 0.700629, 0.687531, + -0.447059, 0.016662, 0.697950, 0.559220], + [0.469472, 0.882948, -0.169395, 0.717968, 0.675150, + -0.445524, 0.055160, 0.708753, 0.544183], + [0.484810, 0.874620, -0.147439, 0.734431, 0.662474, + -0.442340, 0.093837, 0.718167, 0.528929], + [0.500000, 0.866025, -0.125000, 0.750000, 0.649519, + -0.437500, 0.132583, 0.726184, 0.513490], + [0.515038, 0.857167, -0.102104, 0.764655, 0.636300, + -0.431004, 0.171288, 0.732801, 0.497894], + [0.529919, 0.848048, -0.078778, 0.778378, 0.622833, + -0.422856, 0.209843, 0.738017, 0.482171], + [0.544639, 0.838671, -0.055052, 0.791154, 0.609135, + -0.413066, 0.248140, 0.741835, 0.466352], + [0.559193, 0.829038, -0.030955, 0.802965, 0.595222, + -0.401645, 0.286069, 0.744262, 0.450467], + [0.573576, 0.819152, -0.006515, 0.813798, 0.581112, + -0.388612, 0.323524, 0.745308, 0.434544], + [0.587785, 0.809017, 0.018237, 0.823639, 0.566821, + -0.373991, 0.360397, 0.744989, 0.418613], + [0.601815, 0.798636, 0.043272, 0.832477, 0.552367, + -0.357807, 0.396584, 0.743320, 0.402704], + [0.615661, 0.788011, 0.068559, 0.840301, 0.537768, + -0.340093, 0.431982, 0.740324, 0.386845], + [0.629320, 0.777146, 0.094066, 0.847101, 0.523041, + -0.320884, 0.466490, 0.736025, 0.371063], + [0.642788, 0.766044, 0.119764, 0.852869, 0.508205, + -0.300221, 0.500009, 0.730451, 0.355387], + [0.656059, 0.754710, 0.145620, 0.857597, 0.493276, + -0.278147, 0.532443, 0.723633, 0.339844], + [0.669131, 0.743145, 0.171604, 0.861281, 0.478275, + -0.254712, 0.563700, 0.715605, 0.324459], + [0.681998, 0.731354, 0.197683, 0.863916, 0.463218, + -0.229967, 0.593688, 0.706405, 0.309259], + [0.694658, 0.719340, 0.223825, 0.865498, 0.448125, + -0.203969, 0.622322, 0.696073, 0.294267], + [0.707107, 0.707107, 0.250000, 0.866025, 0.433013, + -0.176777, 0.649519, 0.684653, 0.279508], + [0.719340, 0.694658, 0.276175, 0.865498, 0.417901, + -0.148454, 0.675199, 0.672190, 0.265005], + [0.731354, 0.681998, 0.302317, 0.863916, 0.402807, + -0.119068, 0.699288, 0.658734, 0.250778], + [0.743145, 0.669131, 0.328396, 0.861281, 0.387751, + -0.088686, 0.721714, 0.644334, 0.236850], + [0.754710, 0.656059, 0.354380, 0.857597, 0.372749, + -0.057383, 0.742412, 0.629044, 0.223238], + [0.766044, 0.642788, 0.380236, 0.852869, 0.357821, + -0.025233, 0.761319, 0.612921, 0.209963], + [0.777146, 0.629320, 0.405934, 0.847101, 0.342984, + 0.007686, 0.778379, 0.596021, 0.197040], + [0.788011, 0.615661, 0.431441, 0.840301, 0.328257, + 0.041294, 0.793541, 0.578405, 0.184487], + [0.798636, 0.601815, 0.456728, 0.832477, 0.313658, + 0.075508, 0.806757, 0.560132, 0.172317], + [0.809017, 0.587785, 0.481763, 0.823639, 0.299204, + 0.110246, 0.817987, 0.541266, 0.160545], + [0.819152, 0.573576, 0.506515, 0.813798, 0.284914, + 0.145420, 0.827194, 0.521871, 0.149181], + [0.829038, 0.559193, 0.530955, 0.802965, 0.270803, + 0.180944, 0.834347, 0.502011, 0.138237], + [0.838671, 0.544639, 0.555052, 0.791154, 0.256891, + 0.216730, 0.839422, 0.481753, 0.127722], + [0.848048, 0.529919, 0.578778, 0.778378, 0.243192, + 0.252688, 0.842399, 0.461164, 0.117644], + [0.857167, 0.515038, 0.602104, 0.764655, 0.229726, + 0.288728, 0.843265, 0.440311, 0.108009], + [0.866025, 0.500000, 0.625000, 0.750000, 0.216506, + 0.324760, 0.842012, 0.419263, 0.098821], + [0.874620, 0.484810, 0.647439, 0.734431, 0.203551, + 0.360692, 0.838638, 0.398086, 0.090085], + [0.882948, 0.469472, 0.669395, 0.717968, 0.190875, + 0.396436, 0.833145, 0.376851, 0.081803], + [0.891007, 0.453990, 0.690839, 0.700629, 0.178494, + 0.431899, 0.825544, 0.355623, 0.073974], + [0.898794, 0.438371, 0.711746, 0.682437, 0.166423, + 0.466993, 0.815850, 0.334472, 0.066599], + [0.906308, 0.422618, 0.732091, 0.663414, 0.154678, + 0.501627, 0.804083, 0.313464, 0.059674], + [0.913545, 0.406737, 0.751848, 0.643582, 0.143271, + 0.535715, 0.790270, 0.292666, 0.053196], + [0.920505, 0.390731, 0.770994, 0.622967, 0.132217, + 0.569169, 0.774442, 0.272143, 0.047160], + [0.927184, 0.374607, 0.789505, 0.601592, 0.121529, + 0.601904, 0.756637, 0.251960, 0.041559], + [0.933580, 0.358368, 0.807359, 0.579484, 0.111222, + 0.633837, 0.736898, 0.232180, 0.036385], + [0.939693, 0.342020, 0.824533, 0.556670, 0.101306, + 0.664885, 0.715274, 0.212865, 0.031630], + [0.945519, 0.325568, 0.841008, 0.533178, 0.091794, + 0.694969, 0.691816, 0.194075, 0.027281], + [0.951057, 0.309017, 0.856763, 0.509037, 0.082698, + 0.724012, 0.666583, 0.175868, 0.023329], + [0.956305, 0.292372, 0.871778, 0.484275, 0.074029, + 0.751940, 0.639639, 0.158301, 0.019758], + [0.961262, 0.275637, 0.886036, 0.458924, 0.065797, + 0.778680, 0.611050, 0.141427, 0.016556], + [0.965926, 0.258819, 0.899519, 0.433013, 0.058013, + 0.804164, 0.580889, 0.125300, 0.013707], + [0.970296, 0.241922, 0.912211, 0.406574, 0.050685, + 0.828326, 0.549233, 0.109969, 0.011193], + [0.974370, 0.224951, 0.924096, 0.379641, 0.043823, + 0.851105, 0.516162, 0.095481, 0.008999], + [0.978148, 0.207912, 0.935159, 0.352244, 0.037436, + 0.872441, 0.481759, 0.081880, 0.007105], + [0.981627, 0.190809, 0.945388, 0.324419, 0.031530, + 0.892279, 0.446114, 0.069209, 0.005492], + [0.984808, 0.173648, 0.954769, 0.296198, 0.026114, + 0.910569, 0.409317, 0.057505, 0.004140], + [0.987688, 0.156434, 0.963292, 0.267617, 0.021193, + 0.927262, 0.371463, 0.046806, 0.003026], + [0.990268, 0.139173, 0.970946, 0.238709, 0.016774, + 0.942316, 0.332649, 0.037143, 0.002131], + [0.992546, 0.121869, 0.977722, 0.209511, 0.012862, + 0.955693, 0.292976, 0.028547, 0.001431], + [0.994522, 0.104528, 0.983611, 0.180057, 0.009462, + 0.967356, 0.252544, 0.021043, 0.000903], + [0.996195, 0.087156, 0.988606, 0.150384, 0.006578, + 0.977277, 0.211460, 0.014654, 0.000523], + [0.997564, 0.069756, 0.992701, 0.120527, 0.004214, + 0.985429, 0.169828, 0.009400, 0.000268], + [0.998630, 0.052336, 0.995891, 0.090524, 0.002372, + 0.991791, 0.127757, 0.005297, 0.000113], + [0.999391, 0.034899, 0.998173, 0.060411, 0.001055, + 0.996348, 0.085356, 0.002357, 0.000034], + [0.999848, 0.017452, 0.999543, 0.030224, 0.000264, + 0.999086, 0.042733, 0.000590, 0.000004], + [1.000000, -0.000000, 1.000000, -0.000000, 0.000000, + 1.000000, -0.000000, 0.000000, -0.000000], + ], +]; +/** @type {Number} */ +const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION = SPHERICAL_HARMONICS[0].length; +/** @type {Number} */ +const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION = SPHERICAL_HARMONICS[1].length; +/** + * The maximum allowed ambisonic order. + * @type {Number} + */ +const SPHERICAL_HARMONICS_MAX_ORDER = SPHERICAL_HARMONICS[0][0].length / 2; +/** + * Pre-computed per-band weighting coefficients for producing energy-preserving + * Max-Re sources. + */ +const MAX_RE_WEIGHTS = [ + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.003236, 1.002156, 0.999152, 0.990038], + [1.032370, 1.021194, 0.990433, 0.898572], + [1.062694, 1.040231, 0.979161, 0.799806], + [1.093999, 1.058954, 0.964976, 0.693603], + [1.126003, 1.077006, 0.947526, 0.579890], + [1.158345, 1.093982, 0.926474, 0.458690], + [1.190590, 1.109437, 0.901512, 0.330158], + [1.222228, 1.122890, 0.872370, 0.194621], + [1.252684, 1.133837, 0.838839, 0.052614], + [1.281987, 1.142358, 0.801199, 0.000000], + [1.312073, 1.150207, 0.760839, 0.000000], + [1.343011, 1.157424, 0.717799, 0.000000], + [1.374649, 1.163859, 0.671999, 0.000000], + [1.406809, 1.169354, 0.623371, 0.000000], + [1.439286, 1.173739, 0.571868, 0.000000], + [1.471846, 1.176837, 0.517465, 0.000000], + [1.504226, 1.178465, 0.460174, 0.000000], + [1.536133, 1.178438, 0.400043, 0.000000], + [1.567253, 1.176573, 0.337165, 0.000000], + [1.597247, 1.172695, 0.271688, 0.000000], + [1.625766, 1.166645, 0.203815, 0.000000], + [1.652455, 1.158285, 0.133806, 0.000000], + [1.676966, 1.147506, 0.061983, 0.000000], + [1.699006, 1.134261, 0.000000, 0.000000], + [1.720224, 1.119789, 0.000000, 0.000000], + [1.741631, 1.104810, 0.000000, 0.000000], + [1.763183, 1.089330, 0.000000, 0.000000], + [1.784837, 1.073356, 0.000000, 0.000000], + [1.806548, 1.056898, 0.000000, 0.000000], + [1.828269, 1.039968, 0.000000, 0.000000], + [1.849952, 1.022580, 0.000000, 0.000000], + [1.871552, 1.004752, 0.000000, 0.000000], + [1.893018, 0.986504, 0.000000, 0.000000], + [1.914305, 0.967857, 0.000000, 0.000000], + [1.935366, 0.948837, 0.000000, 0.000000], + [1.956154, 0.929471, 0.000000, 0.000000], + [1.976625, 0.909790, 0.000000, 0.000000], + [1.996736, 0.889823, 0.000000, 0.000000], + [2.016448, 0.869607, 0.000000, 0.000000], + [2.035721, 0.849175, 0.000000, 0.000000], + [2.054522, 0.828565, 0.000000, 0.000000], + [2.072818, 0.807816, 0.000000, 0.000000], + [2.090581, 0.786964, 0.000000, 0.000000], + [2.107785, 0.766051, 0.000000, 0.000000], + [2.124411, 0.745115, 0.000000, 0.000000], + [2.140439, 0.724196, 0.000000, 0.000000], + [2.155856, 0.703332, 0.000000, 0.000000], + [2.170653, 0.682561, 0.000000, 0.000000], + [2.184823, 0.661921, 0.000000, 0.000000], + [2.198364, 0.641445, 0.000000, 0.000000], + [2.211275, 0.621169, 0.000000, 0.000000], + [2.223562, 0.601125, 0.000000, 0.000000], + [2.235230, 0.581341, 0.000000, 0.000000], + [2.246289, 0.561847, 0.000000, 0.000000], + [2.256751, 0.542667, 0.000000, 0.000000], + [2.266631, 0.523826, 0.000000, 0.000000], + [2.275943, 0.505344, 0.000000, 0.000000], + [2.284707, 0.487239, 0.000000, 0.000000], + [2.292939, 0.469528, 0.000000, 0.000000], + [2.300661, 0.452225, 0.000000, 0.000000], + [2.307892, 0.435342, 0.000000, 0.000000], + [2.314654, 0.418888, 0.000000, 0.000000], + [2.320969, 0.402870, 0.000000, 0.000000], + [2.326858, 0.387294, 0.000000, 0.000000], + [2.332343, 0.372164, 0.000000, 0.000000], + [2.337445, 0.357481, 0.000000, 0.000000], + [2.342186, 0.343246, 0.000000, 0.000000], + [2.346585, 0.329458, 0.000000, 0.000000], + [2.350664, 0.316113, 0.000000, 0.000000], + [2.354442, 0.303208, 0.000000, 0.000000], + [2.357937, 0.290738, 0.000000, 0.000000], + [2.361168, 0.278698, 0.000000, 0.000000], + [2.364152, 0.267080, 0.000000, 0.000000], + [2.366906, 0.255878, 0.000000, 0.000000], + [2.369446, 0.245082, 0.000000, 0.000000], + [2.371786, 0.234685, 0.000000, 0.000000], + [2.373940, 0.224677, 0.000000, 0.000000], + [2.375923, 0.215048, 0.000000, 0.000000], + [2.377745, 0.205790, 0.000000, 0.000000], + [2.379421, 0.196891, 0.000000, 0.000000], + [2.380959, 0.188342, 0.000000, 0.000000], + [2.382372, 0.180132, 0.000000, 0.000000], + [2.383667, 0.172251, 0.000000, 0.000000], + [2.384856, 0.164689, 0.000000, 0.000000], + [2.385945, 0.157435, 0.000000, 0.000000], + [2.386943, 0.150479, 0.000000, 0.000000], + [2.387857, 0.143811, 0.000000, 0.000000], + [2.388694, 0.137421, 0.000000, 0.000000], + [2.389460, 0.131299, 0.000000, 0.000000], + [2.390160, 0.125435, 0.000000, 0.000000], + [2.390801, 0.119820, 0.000000, 0.000000], + [2.391386, 0.114445, 0.000000, 0.000000], + [2.391921, 0.109300, 0.000000, 0.000000], + [2.392410, 0.104376, 0.000000, 0.000000], + [2.392857, 0.099666, 0.000000, 0.000000], + [2.393265, 0.095160, 0.000000, 0.000000], + [2.393637, 0.090851, 0.000000, 0.000000], + [2.393977, 0.086731, 0.000000, 0.000000], + [2.394288, 0.082791, 0.000000, 0.000000], + [2.394571, 0.079025, 0.000000, 0.000000], + [2.394829, 0.075426, 0.000000, 0.000000], + [2.395064, 0.071986, 0.000000, 0.000000], + [2.395279, 0.068699, 0.000000, 0.000000], + [2.395475, 0.065558, 0.000000, 0.000000], + [2.395653, 0.062558, 0.000000, 0.000000], + [2.395816, 0.059693, 0.000000, 0.000000], + [2.395964, 0.056955, 0.000000, 0.000000], + [2.396099, 0.054341, 0.000000, 0.000000], + [2.396222, 0.051845, 0.000000, 0.000000], + [2.396334, 0.049462, 0.000000, 0.000000], + [2.396436, 0.047186, 0.000000, 0.000000], + [2.396529, 0.045013, 0.000000, 0.000000], + [2.396613, 0.042939, 0.000000, 0.000000], + [2.396691, 0.040959, 0.000000, 0.000000], + [2.396761, 0.039069, 0.000000, 0.000000], + [2.396825, 0.037266, 0.000000, 0.000000], + [2.396883, 0.035544, 0.000000, 0.000000], + [2.396936, 0.033901, 0.000000, 0.000000], + [2.396984, 0.032334, 0.000000, 0.000000], + [2.397028, 0.030838, 0.000000, 0.000000], + [2.397068, 0.029410, 0.000000, 0.000000], + [2.397104, 0.028048, 0.000000, 0.000000], + [2.397137, 0.026749, 0.000000, 0.000000], + [2.397167, 0.025509, 0.000000, 0.000000], + [2.397194, 0.024326, 0.000000, 0.000000], + [2.397219, 0.023198, 0.000000, 0.000000], + [2.397242, 0.022122, 0.000000, 0.000000], + [2.397262, 0.021095, 0.000000, 0.000000], + [2.397281, 0.020116, 0.000000, 0.000000], + [2.397298, 0.019181, 0.000000, 0.000000], + [2.397314, 0.018290, 0.000000, 0.000000], + [2.397328, 0.017441, 0.000000, 0.000000], + [2.397341, 0.016630, 0.000000, 0.000000], + [2.397352, 0.015857, 0.000000, 0.000000], + [2.397363, 0.015119, 0.000000, 0.000000], + [2.397372, 0.014416, 0.000000, 0.000000], + [2.397381, 0.013745, 0.000000, 0.000000], + [2.397389, 0.013106, 0.000000, 0.000000], + [2.397396, 0.012496, 0.000000, 0.000000], + [2.397403, 0.011914, 0.000000, 0.000000], + [2.397409, 0.011360, 0.000000, 0.000000], + [2.397414, 0.010831, 0.000000, 0.000000], + [2.397419, 0.010326, 0.000000, 0.000000], + [2.397424, 0.009845, 0.000000, 0.000000], + [2.397428, 0.009387, 0.000000, 0.000000], + [2.397432, 0.008949, 0.000000, 0.000000], + [2.397435, 0.008532, 0.000000, 0.000000], + [2.397438, 0.008135, 0.000000, 0.000000], + [2.397441, 0.007755, 0.000000, 0.000000], + [2.397443, 0.007394, 0.000000, 0.000000], + [2.397446, 0.007049, 0.000000, 0.000000], + [2.397448, 0.006721, 0.000000, 0.000000], + [2.397450, 0.006407, 0.000000, 0.000000], + [2.397451, 0.006108, 0.000000, 0.000000], + [2.397453, 0.005824, 0.000000, 0.000000], + [2.397454, 0.005552, 0.000000, 0.000000], + [2.397456, 0.005293, 0.000000, 0.000000], + [2.397457, 0.005046, 0.000000, 0.000000], + [2.397458, 0.004811, 0.000000, 0.000000], + [2.397459, 0.004586, 0.000000, 0.000000], + [2.397460, 0.004372, 0.000000, 0.000000], + [2.397461, 0.004168, 0.000000, 0.000000], + [2.397461, 0.003974, 0.000000, 0.000000], + [2.397462, 0.003788, 0.000000, 0.000000], + [2.397463, 0.003611, 0.000000, 0.000000], + [2.397463, 0.003443, 0.000000, 0.000000], + [2.397464, 0.003282, 0.000000, 0.000000], + [2.397464, 0.003129, 0.000000, 0.000000], + [2.397465, 0.002983, 0.000000, 0.000000], + [2.397465, 0.002844, 0.000000, 0.000000], + [2.397465, 0.002711, 0.000000, 0.000000], + [2.397466, 0.002584, 0.000000, 0.000000], + [2.397466, 0.002464, 0.000000, 0.000000], + [2.397466, 0.002349, 0.000000, 0.000000], + [2.397466, 0.002239, 0.000000, 0.000000], + [2.397467, 0.002135, 0.000000, 0.000000], + [2.397467, 0.002035, 0.000000, 0.000000], + [2.397467, 0.001940, 0.000000, 0.000000], + [2.397467, 0.001849, 0.000000, 0.000000], + [2.397467, 0.001763, 0.000000, 0.000000], + [2.397467, 0.001681, 0.000000, 0.000000], + [2.397468, 0.001602, 0.000000, 0.000000], + [2.397468, 0.001527, 0.000000, 0.000000], + [2.397468, 0.001456, 0.000000, 0.000000], + [2.397468, 0.001388, 0.000000, 0.000000], + [2.397468, 0.001323, 0.000000, 0.000000], + [2.397468, 0.001261, 0.000000, 0.000000], + [2.397468, 0.001202, 0.000000, 0.000000], + [2.397468, 0.001146, 0.000000, 0.000000], + [2.397468, 0.001093, 0.000000, 0.000000], + [2.397468, 0.001042, 0.000000, 0.000000], + [2.397468, 0.000993, 0.000000, 0.000000], + [2.397468, 0.000947, 0.000000, 0.000000], + [2.397468, 0.000902, 0.000000, 0.000000], + [2.397468, 0.000860, 0.000000, 0.000000], + [2.397468, 0.000820, 0.000000, 0.000000], + [2.397469, 0.000782, 0.000000, 0.000000], + [2.397469, 0.000745, 0.000000, 0.000000], + [2.397469, 0.000710, 0.000000, 0.000000], + [2.397469, 0.000677, 0.000000, 0.000000], + [2.397469, 0.000646, 0.000000, 0.000000], + [2.397469, 0.000616, 0.000000, 0.000000], + [2.397469, 0.000587, 0.000000, 0.000000], + [2.397469, 0.000559, 0.000000, 0.000000], + [2.397469, 0.000533, 0.000000, 0.000000], + [2.397469, 0.000508, 0.000000, 0.000000], + [2.397469, 0.000485, 0.000000, 0.000000], + [2.397469, 0.000462, 0.000000, 0.000000], + [2.397469, 0.000440, 0.000000, 0.000000], + [2.397469, 0.000420, 0.000000, 0.000000], + [2.397469, 0.000400, 0.000000, 0.000000], + [2.397469, 0.000381, 0.000000, 0.000000], + [2.397469, 0.000364, 0.000000, 0.000000], + [2.397469, 0.000347, 0.000000, 0.000000], + [2.397469, 0.000330, 0.000000, 0.000000], + [2.397469, 0.000315, 0.000000, 0.000000], + [2.397469, 0.000300, 0.000000, 0.000000], + [2.397469, 0.000286, 0.000000, 0.000000], + [2.397469, 0.000273, 0.000000, 0.000000], + [2.397469, 0.000260, 0.000000, 0.000000], + [2.397469, 0.000248, 0.000000, 0.000000], + [2.397469, 0.000236, 0.000000, 0.000000], + [2.397469, 0.000225, 0.000000, 0.000000], + [2.397469, 0.000215, 0.000000, 0.000000], + [2.397469, 0.000205, 0.000000, 0.000000], + [2.397469, 0.000195, 0.000000, 0.000000], + [2.397469, 0.000186, 0.000000, 0.000000], + [2.397469, 0.000177, 0.000000, 0.000000], + [2.397469, 0.000169, 0.000000, 0.000000], + [2.397469, 0.000161, 0.000000, 0.000000], + [2.397469, 0.000154, 0.000000, 0.000000], + [2.397469, 0.000147, 0.000000, 0.000000], + [2.397469, 0.000140, 0.000000, 0.000000], + [2.397469, 0.000133, 0.000000, 0.000000], + [2.397469, 0.000127, 0.000000, 0.000000], + [2.397469, 0.000121, 0.000000, 0.000000], + [2.397469, 0.000115, 0.000000, 0.000000], + [2.397469, 0.000110, 0.000000, 0.000000], + [2.397469, 0.000105, 0.000000, 0.000000], + [2.397469, 0.000100, 0.000000, 0.000000], + [2.397469, 0.000095, 0.000000, 0.000000], + [2.397469, 0.000091, 0.000000, 0.000000], + [2.397469, 0.000087, 0.000000, 0.000000], + [2.397469, 0.000083, 0.000000, 0.000000], + [2.397469, 0.000079, 0.000000, 0.000000], + [2.397469, 0.000075, 0.000000, 0.000000], + [2.397469, 0.000071, 0.000000, 0.000000], + [2.397469, 0.000068, 0.000000, 0.000000], + [2.397469, 0.000065, 0.000000, 0.000000], + [2.397469, 0.000062, 0.000000, 0.000000], + [2.397469, 0.000059, 0.000000, 0.000000], + [2.397469, 0.000056, 0.000000, 0.000000], + [2.397469, 0.000054, 0.000000, 0.000000], + [2.397469, 0.000051, 0.000000, 0.000000], + [2.397469, 0.000049, 0.000000, 0.000000], + [2.397469, 0.000046, 0.000000, 0.000000], + [2.397469, 0.000044, 0.000000, 0.000000], + [2.397469, 0.000042, 0.000000, 0.000000], + [2.397469, 0.000040, 0.000000, 0.000000], + [2.397469, 0.000038, 0.000000, 0.000000], + [2.397469, 0.000037, 0.000000, 0.000000], + [2.397469, 0.000035, 0.000000, 0.000000], + [2.397469, 0.000033, 0.000000, 0.000000], + [2.397469, 0.000032, 0.000000, 0.000000], + [2.397469, 0.000030, 0.000000, 0.000000], + [2.397469, 0.000029, 0.000000, 0.000000], + [2.397469, 0.000027, 0.000000, 0.000000], + [2.397469, 0.000026, 0.000000, 0.000000], + [2.397469, 0.000025, 0.000000, 0.000000], + [2.397469, 0.000024, 0.000000, 0.000000], + [2.397469, 0.000023, 0.000000, 0.000000], + [2.397469, 0.000022, 0.000000, 0.000000], + [2.397469, 0.000021, 0.000000, 0.000000], + [2.397469, 0.000020, 0.000000, 0.000000], + [2.397469, 0.000019, 0.000000, 0.000000], + [2.397469, 0.000018, 0.000000, 0.000000], + [2.397469, 0.000017, 0.000000, 0.000000], + [2.397469, 0.000016, 0.000000, 0.000000], + [2.397469, 0.000015, 0.000000, 0.000000], + [2.397469, 0.000015, 0.000000, 0.000000], + [2.397469, 0.000014, 0.000000, 0.000000], + [2.397469, 0.000013, 0.000000, 0.000000], + [2.397469, 0.000013, 0.000000, 0.000000], + [2.397469, 0.000012, 0.000000, 0.000000], + [2.397469, 0.000012, 0.000000, 0.000000], + [2.397469, 0.000011, 0.000000, 0.000000], + [2.397469, 0.000011, 0.000000, 0.000000], + [2.397469, 0.000010, 0.000000, 0.000000], + [2.397469, 0.000010, 0.000000, 0.000000], + [2.397469, 0.000009, 0.000000, 0.000000], + [2.397469, 0.000009, 0.000000, 0.000000], + [2.397469, 0.000008, 0.000000, 0.000000], + [2.397469, 0.000008, 0.000000, 0.000000], + [2.397469, 0.000008, 0.000000, 0.000000], + [2.397469, 0.000007, 0.000000, 0.000000], + [2.397469, 0.000007, 0.000000, 0.000000], + [2.397469, 0.000007, 0.000000, 0.000000], + [2.397469, 0.000006, 0.000000, 0.000000], + [2.397469, 0.000006, 0.000000, 0.000000], + [2.397469, 0.000006, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000001, 0.000000, 0.000000], + [2.397469, 0.000001, 0.000000, 0.000000], + [2.397469, 0.000001, 0.000000, 0.000000], +]; +/** @type {Number} */ +const MAX_RE_WEIGHTS_RESOLUTION = MAX_RE_WEIGHTS.length; +export default { + SPHERICAL_HARMONICS, + SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION, + SPHERICAL_HARMONICS_ELEVATION_RESOLUTION, + SPHERICAL_HARMONICS_MAX_ORDER, + MAX_RE_WEIGHTS, + MAX_RE_WEIGHTS_RESOLUTION +}; diff --git a/framework/resonator/vendor/resonance-es6/utils.d.ts b/framework/resonator/vendor/resonance-es6/utils.d.ts new file mode 100644 index 0000000..4835498 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/utils.d.ts @@ -0,0 +1,98 @@ +export default Utils; +/** + * @class Utils + * @description A set of defaults, constants and utility functions. + */ +declare class Utils { + /** + * Properties describing the geometry of a room. + * @typedef {Object} Utils~RoomDimensions + * @property {Number} width (in meters). + * @property {Number} height (in meters). + * @property {Number} depth (in meters). + */ + /** + * Properties describing the wall materials (from + * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS}) + * of a room. + * @typedef {Object} Utils~RoomMaterials + * @property {String} left Left-wall material name. + * @property {String} right Right-wall material name. + * @property {String} front Front-wall material name. + * @property {String} back Back-wall material name. + * @property {String} up Up-wall material name. + * @property {String} down Down-wall material name. + */ + /** + * ResonanceAudio library logging function. + * @type {Function} + * @param {any} Message to be printed out. + * @private + */ + private static log; +} +declare namespace Utils { + const DEFAULT_SOURCE_GAIN: number; + const LISTENER_MAX_OUTSIDE_ROOM_DISTANCE: number; + const SOURCE_MAX_OUTSIDE_ROOM_DISTANCE: number; + const DEFAULT_SOURCE_DISTANCE: number; + const DEFAULT_POSITION: Float32Array; + const DEFAULT_FORWARD: Float32Array; + const DEFAULT_UP: Float32Array; + const DEFAULT_RIGHT: Float32Array; + const DEFAULT_SPEED_OF_SOUND: number; + const ATTENUATION_ROLLOFFS: any[]; + const DEFAULT_ATTENUATION_ROLLOFF: string; + const DEFAULT_MIN_DISTANCE: number; + const DEFAULT_MAX_DISTANCE: number; + const DEFAULT_DIRECTIVITY_ALPHA: number; + const DEFAULT_DIRECTIVITY_SHARPNESS: number; + const DEFAULT_AZIMUTH: number; + const DEFAULT_ELEVATION: number; + const DEFAULT_AMBISONIC_ORDER: number; + const DEFAULT_SOURCE_WIDTH: number; + const DEFAULT_REFLECTION_MAX_DURATION: number; + const DEFAULT_REFLECTION_CUTOFF_FREQUENCY: number; + const DEFAULT_REFLECTION_COEFFICIENTS: any; + const DEFAULT_REFLECTION_MIN_DISTANCE: number; + const DEFAULT_ROOM_DIMENSIONS: any; + const DEFAULT_REFLECTION_MULTIPLIER: number; + const DEFAULT_REVERB_BANDWIDTH: number; + const DEFAULT_REVERB_DURATION_MULTIPLIER: number; + const DEFAULT_REVERB_PREDELAY: number; + const DEFAULT_REVERB_TAIL_ONSET: number; + const DEFAULT_REVERB_GAIN: number; + const DEFAULT_REVERB_MAX_DURATION: number; + const DEFAULT_REVERB_FREQUENCY_BANDS: any[]; + const NUMBER_REVERB_FREQUENCY_BANDS: number; + const DEFAULT_REVERB_DURATIONS: Float32Array; + const ROOM_MATERIAL_COEFFICIENTS: any; + const DEFAULT_ROOM_MATERIALS: any; + const NUMBER_REFLECTION_AVERAGING_BANDS: number; + const ROOM_STARTING_AVERAGING_BAND: number; + const ROOM_MIN_VOLUME: number; + const ROOM_AIR_ABSORPTION_COEFFICIENTS: Float32Array; + const ROOM_EYRING_CORRECTION_COEFFICIENT: number; + const TWO_PI: number; + const TWENTY_FOUR_LOG10: number; + const LOG1000: number; + const LOG2_DIV2: number; + const DEGREES_TO_RADIANS: number; + const RADIANS_TO_DEGREES: number; + const EPSILON_FLOAT: number; + /** + * Normalize a 3-d vector. + * @param {Float32Array} v 3-element vector. + * @return {Float32Array} 3-element vector. + * @private + */ + function normalizeVector(v: Float32Array): Float32Array; + /** + * Cross-product between two 3-d vectors. + * @param {Float32Array} a 3-element vector. + * @param {Float32Array} b 3-element vector. + * @return {Float32Array} + * @private + */ + function crossProduct(a: Float32Array, b: Float32Array): Float32Array; +} diff --git a/framework/resonator/vendor/resonance-es6/utils.js b/framework/resonator/vendor/resonance-es6/utils.js new file mode 100644 index 0000000..41697e4 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/utils.js @@ -0,0 +1,379 @@ +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 ResonanceAudio library common utilities, mathematical constants, + * and default values. + * @author Andrew Allen + */ +'use strict'; +/** + * @class Utils + * @description A set of defaults, constants and utility functions. + */ +class Utils { + /** + * Properties describing the geometry of a room. + * @typedef {Object} Utils~RoomDimensions + * @property {Number} width (in meters). + * @property {Number} height (in meters). + * @property {Number} depth (in meters). + */ + /** + * Properties describing the wall materials (from + * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS}) + * of a room. + * @typedef {Object} Utils~RoomMaterials + * @property {String} left Left-wall material name. + * @property {String} right Right-wall material name. + * @property {String} front Front-wall material name. + * @property {String} back Back-wall material name. + * @property {String} up Up-wall material name. + * @property {String} down Down-wall material name. + */ + /** + * ResonanceAudio library logging function. + * @type {Function} + * @param {any} Message to be printed out. + * @private + */ + static log() { + window.console.log.apply(window.console, [ + '%c[ResonanceAudio]%c ' + + Array.prototype.slice.call(arguments).join(' ') + ' %c(@' + + performance.now().toFixed(2) + 'ms)', + 'background: #BBDEFB; color: #FF5722; font-weight: 700', + 'font-weight: 400', + 'color: #AAA', + ]); + } +} +/** + * Default input gain (linear). + * @type {Number} + */ +Utils.DEFAULT_SOURCE_GAIN = 1; +/** + * Maximum outside-the-room distance to attenuate far-field listener by. + * @type {Number} + */ +Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE = 1; +/** + * Maximum outside-the-room distance to attenuate far-field sources by. + * @type {Number} + */ +Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE = 1; +/** + * Default distance from listener when setting angle. + * @type {Number} + */ +Utils.DEFAULT_SOURCE_DISTANCE = 1; +/** @type {Float32Array} */ +Utils.DEFAULT_POSITION = [0, 0, 0]; +/** @type {Float32Array} */ +Utils.DEFAULT_FORWARD = [0, 0, -1]; +/** @type {Float32Array} */ +Utils.DEFAULT_UP = [0, 1, 0]; +/** @type {Float32Array} */ +Utils.DEFAULT_RIGHT = [1, 0, 0]; +/** + * @type {Number} + */ +Utils.DEFAULT_SPEED_OF_SOUND = 343; +/** Rolloff models (e.g. 'logarithmic', 'linear', or 'none'). + * @type {Array} + */ +Utils.ATTENUATION_ROLLOFFS = ['logarithmic', 'linear', 'none']; +/** Default rolloff model ('logarithmic'). + * @type {string} + */ +Utils.DEFAULT_ATTENUATION_ROLLOFF = 'logarithmic'; +/** @type {Number} */ +Utils.DEFAULT_MIN_DISTANCE = 1; +/** @type {Number} */ +Utils.DEFAULT_MAX_DISTANCE = 1000; +/** + * The default alpha (i.e. microphone pattern). + * @type {Number} + */ +Utils.DEFAULT_DIRECTIVITY_ALPHA = 0; +/** + * The default pattern sharpness (i.e. pattern exponent). + * @type {Number} + */ +Utils.DEFAULT_DIRECTIVITY_SHARPNESS = 1; +/** + * Default azimuth (in degrees). Suitable range is 0 to 360. + * @type {Number} + */ +Utils.DEFAULT_AZIMUTH = 0; +/** + * Default elevation (in degres). + * Suitable range is from -90 (below) to 90 (above). + * @type {Number} + */ +Utils.DEFAULT_ELEVATION = 0; +/** + * The default ambisonic order. + * @type {Number} + */ +Utils.DEFAULT_AMBISONIC_ORDER = 1; +/** + * The default source width. + * @type {Number} + */ +Utils.DEFAULT_SOURCE_WIDTH = 0; +/** + * The maximum delay (in seconds) of a single wall reflection. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_MAX_DURATION = 0.5; +/** + * The -12dB cutoff frequency (in Hertz) for the lowpass filter applied to + * all reflections. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY = 6400; // Uses -12dB cutoff. +/** + * The default reflection coefficients (where 0 = no reflection, 1 = perfect + * reflection, -1 = mirrored reflection (180-degrees out of phase)). + * @type {Object} + */ +Utils.DEFAULT_REFLECTION_COEFFICIENTS = { + left: 0, right: 0, front: 0, back: 0, down: 0, up: 0, +}; +/** + * The minimum distance we consider the listener to be to any given wall. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_MIN_DISTANCE = 1; +/** + * Default room dimensions (in meters). + * @type {Object} + */ +Utils.DEFAULT_ROOM_DIMENSIONS = { + width: 0, height: 0, depth: 0, +}; +/** + * The multiplier to apply to distances from the listener to each wall. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_MULTIPLIER = 1; +/** The default bandwidth (in octaves) of the center frequencies. + * @type {Number} + */ +Utils.DEFAULT_REVERB_BANDWIDTH = 1; +/** The default multiplier applied when computing tail lengths. + * @type {Number} + */ +Utils.DEFAULT_REVERB_DURATION_MULTIPLIER = 1; +/** + * The late reflections pre-delay (in milliseconds). + * @type {Number} + */ +Utils.DEFAULT_REVERB_PREDELAY = 1.5; +/** + * The length of the beginning of the impulse response to apply a + * half-Hann window to. + * @type {Number} + */ +Utils.DEFAULT_REVERB_TAIL_ONSET = 3.8; +/** + * The default gain (linear). + * @type {Number} + */ +Utils.DEFAULT_REVERB_GAIN = 0.01; +/** + * The maximum impulse response length (in seconds). + * @type {Number} + */ +Utils.DEFAULT_REVERB_MAX_DURATION = 3; +/** + * Center frequencies of the multiband late reflections. + * Nine bands are computed by: 31.25 * 2^(0:8). + * @type {Array} + */ +Utils.DEFAULT_REVERB_FREQUENCY_BANDS = [ + 31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, +]; +/** + * The number of frequency bands. + */ +Utils.NUMBER_REVERB_FREQUENCY_BANDS = + Utils.DEFAULT_REVERB_FREQUENCY_BANDS.length; +/** + * The default multiband RT60 durations (in seconds). + * @type {Float32Array} + */ +Utils.DEFAULT_REVERB_DURATIONS = + new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); +/** + * Pre-defined frequency-dependent absorption coefficients for listed materials. + * Currently supported materials are: + *
    + *
  • 'transparent'
  • + *
  • 'acoustic-ceiling-tiles'
  • + *
  • 'brick-bare'
  • + *
  • 'brick-painted'
  • + *
  • 'concrete-block-coarse'
  • + *
  • 'concrete-block-painted'
  • + *
  • 'curtain-heavy'
  • + *
  • 'fiber-glass-insulation'
  • + *
  • 'glass-thin'
  • + *
  • 'glass-thick'
  • + *
  • 'grass'
  • + *
  • 'linoleum-on-concrete'
  • + *
  • 'marble'
  • + *
  • 'metal'
  • + *
  • 'parquet-on-concrete'
  • + *
  • 'plaster-smooth'
  • + *
  • 'plywood-panel'
  • + *
  • 'polished-concrete-or-tile'
  • + *
  • 'sheetrock'
  • + *
  • 'water-or-ice-surface'
  • + *
  • 'wood-ceiling'
  • + *
  • 'wood-panel'
  • + *
  • 'uniform'
  • + *
+ * @type {Object} + */ +Utils.ROOM_MATERIAL_COEFFICIENTS = { + 'transparent': [1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000], + 'acoustic-ceiling-tiles': [0.672, 0.675, 0.700, 0.660, 0.720, 0.920, 0.880, 0.750, 1.000], + 'brick-bare': [0.030, 0.030, 0.030, 0.030, 0.030, 0.040, 0.050, 0.070, 0.140], + 'brick-painted': [0.006, 0.007, 0.010, 0.010, 0.020, 0.020, 0.020, 0.030, 0.060], + 'concrete-block-coarse': [0.360, 0.360, 0.360, 0.440, 0.310, 0.290, 0.390, 0.250, 0.500], + 'concrete-block-painted': [0.092, 0.090, 0.100, 0.050, 0.060, 0.070, 0.090, 0.080, 0.160], + 'curtain-heavy': [0.073, 0.106, 0.140, 0.350, 0.550, 0.720, 0.700, 0.650, 1.000], + 'fiber-glass-insulation': [0.193, 0.220, 0.220, 0.820, 0.990, 0.990, 0.990, 0.990, 1.000], + 'glass-thin': [0.180, 0.169, 0.180, 0.060, 0.040, 0.030, 0.020, 0.020, 0.040], + 'glass-thick': [0.350, 0.350, 0.350, 0.250, 0.180, 0.120, 0.070, 0.040, 0.080], + 'grass': [0.050, 0.050, 0.150, 0.250, 0.400, 0.550, 0.600, 0.600, 0.600], + 'linoleum-on-concrete': [0.020, 0.020, 0.020, 0.030, 0.030, 0.030, 0.030, 0.020, 0.040], + 'marble': [0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.020, 0.020, 0.040], + 'metal': [0.030, 0.035, 0.040, 0.040, 0.050, 0.050, 0.050, 0.070, 0.090], + 'parquet-on-concrete': [0.028, 0.030, 0.040, 0.040, 0.070, 0.060, 0.060, 0.070, 0.140], + 'plaster-rough': [0.017, 0.018, 0.020, 0.030, 0.040, 0.050, 0.040, 0.030, 0.060], + 'plaster-smooth': [0.011, 0.012, 0.013, 0.015, 0.020, 0.030, 0.040, 0.050, 0.100], + 'plywood-panel': [0.400, 0.340, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220], + 'polished-concrete-or-tile': [0.008, 0.008, 0.010, 0.010, 0.015, 0.020, 0.020, 0.020, 0.040], + 'sheet-rock': [0.290, 0.279, 0.290, 0.100, 0.050, 0.040, 0.070, 0.090, 0.180], + 'water-or-ice-surface': [0.006, 0.006, 0.008, 0.008, 0.013, 0.015, 0.020, 0.025, 0.050], + 'wood-ceiling': [0.150, 0.147, 0.150, 0.110, 0.100, 0.070, 0.060, 0.070, 0.140], + 'wood-panel': [0.280, 0.280, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220], + 'uniform': [0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500], +}; +/** + * Default materials that use strings from + * {@linkcode Utils.MATERIAL_COEFFICIENTS MATERIAL_COEFFICIENTS} + * @type {Object} + */ +Utils.DEFAULT_ROOM_MATERIALS = { + left: 'transparent', right: 'transparent', front: 'transparent', + back: 'transparent', down: 'transparent', up: 'transparent', +}; +/** + * The number of bands to average over when computing reflection coefficients. + * @type {Number} + */ +Utils.NUMBER_REFLECTION_AVERAGING_BANDS = 3; +/** + * The starting band to average over when computing reflection coefficients. + * @type {Number} + */ +Utils.ROOM_STARTING_AVERAGING_BAND = 4; +/** + * The minimum threshold for room volume. + * Room model is disabled if volume is below this value. + * @type {Number} */ +Utils.ROOM_MIN_VOLUME = 1e-4; +/** + * Air absorption coefficients per frequency band. + * @type {Float32Array} + */ +Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS = + [0.0006, 0.0006, 0.0007, 0.0008, 0.0010, 0.0015, 0.0026, 0.0060, 0.0207]; +/** + * A scalar correction value to ensure Sabine and Eyring produce the same RT60 + * value at the cross-over threshold. + * @type {Number} + */ +Utils.ROOM_EYRING_CORRECTION_COEFFICIENT = 1.38; +/** + * @type {Number} + * @private + */ +Utils.TWO_PI = 6.28318530717959; +/** + * @type {Number} + * @private + */ +Utils.TWENTY_FOUR_LOG10 = 55.2620422318571; +/** + * @type {Number} + * @private + */ +Utils.LOG1000 = 6.90775527898214; +/** + * @type {Number} + * @private + */ +Utils.LOG2_DIV2 = 0.346573590279973; +/** + * @type {Number} + * @private + */ +Utils.DEGREES_TO_RADIANS = 0.017453292519943; +/** + * @type {Number} + * @private + */ +Utils.RADIANS_TO_DEGREES = 57.295779513082323; +/** + * @type {Number} + * @private + */ +Utils.EPSILON_FLOAT = 1e-8; +/** + * Normalize a 3-d vector. + * @param {Float32Array} v 3-element vector. + * @return {Float32Array} 3-element vector. + * @private + */ +Utils.normalizeVector = v => { + let n = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + if (n > Utils.EPSILON_FLOAT) { + n = 1 / n; + v[0] *= n; + v[1] *= n; + v[2] *= n; + } + return v; +}; +/** + * Cross-product between two 3-d vectors. + * @param {Float32Array} a 3-element vector. + * @param {Float32Array} b 3-element vector. + * @return {Float32Array} + * @private + */ +Utils.crossProduct = (a, b) => { + return [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0], + ]; +}; +export default Utils; diff --git a/framework/resonator/vendor/resonance-es6/version.d.ts b/framework/resonator/vendor/resonance-es6/version.d.ts new file mode 100644 index 0000000..284b937 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/version.d.ts @@ -0,0 +1,2 @@ +declare var _default: "1.0.0"; +export default _default; diff --git a/framework/resonator/vendor/resonance-es6/version.js b/framework/resonator/vendor/resonance-es6/version.js new file mode 100644 index 0000000..d32c578 --- /dev/null +++ b/framework/resonator/vendor/resonance-es6/version.js @@ -0,0 +1,24 @@ +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 ResonanceAudio version. + * @author Andrew Allen + */ +'use strict'; +/** + * ResonanceAudio library version + * @type {String} + */ +export default '1.0.0'; diff --git a/src/framework/resonator/vendor/tsm/constants.d.ts b/framework/resonator/vendor/tsm/constants.d.ts similarity index 97% rename from src/framework/resonator/vendor/tsm/constants.d.ts rename to framework/resonator/vendor/tsm/constants.d.ts index 4ceaa99..669e322 100644 --- a/src/framework/resonator/vendor/tsm/constants.d.ts +++ b/framework/resonator/vendor/tsm/constants.d.ts @@ -1 +1 @@ -export declare const epsilon = 0.00001; +export declare const epsilon = 0.00001; diff --git a/src/framework/resonator/vendor/tsm/constants.js b/framework/resonator/vendor/tsm/constants.js similarity index 96% rename from src/framework/resonator/vendor/tsm/constants.js rename to framework/resonator/vendor/tsm/constants.js index 347e812..592a1d1 100644 --- a/src/framework/resonator/vendor/tsm/constants.js +++ b/framework/resonator/vendor/tsm/constants.js @@ -1 +1 @@ -export const epsilon = 0.00001; +export const epsilon = 0.00001; diff --git a/src/framework/resonator/vendor/tsm/mat2.d.ts b/framework/resonator/vendor/tsm/mat2.d.ts similarity index 96% rename from src/framework/resonator/vendor/tsm/mat2.d.ts rename to framework/resonator/vendor/tsm/mat2.d.ts index ab03acb..09bd076 100644 --- a/src/framework/resonator/vendor/tsm/mat2.d.ts +++ b/framework/resonator/vendor/tsm/mat2.d.ts @@ -1,23 +1,23 @@ -import vec2 from './vec2'; -export default class mat2 { - constructor(values?: number[]); - private values; - static readonly identity: mat2; - at(index: number): number; - init(values: number[]): mat2; - reset(): void; - copy(dest?: mat2): mat2; - all(): number[]; - row(index: number): number[]; - col(index: number): number[]; - equals(matrix: mat2, threshold?: number): boolean; - determinant(): number; - setIdentity(): mat2; - transpose(): mat2; - inverse(): mat2; - multiply(matrix: mat2): mat2; - rotate(angle: number): mat2; - multiplyVec2(vector: vec2, result: vec2): vec2; - scale(vector: vec2): mat2; - static product(m1: mat2, m2: mat2, result: mat2): mat2; -} +import vec2 from './vec2'; +export default class mat2 { + constructor(values?: number[]); + private values; + static readonly identity: mat2; + at(index: number): number; + init(values: number[]): mat2; + reset(): void; + copy(dest?: mat2): mat2; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat2, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat2; + transpose(): mat2; + inverse(): mat2; + multiply(matrix: mat2): mat2; + rotate(angle: number): mat2; + multiplyVec2(vector: vec2, result: vec2): vec2; + scale(vector: vec2): mat2; + static product(m1: mat2, m2: mat2, result: mat2): mat2; +} diff --git a/src/framework/resonator/vendor/tsm/mat2.js b/framework/resonator/vendor/tsm/mat2.js similarity index 96% rename from src/framework/resonator/vendor/tsm/mat2.js rename to framework/resonator/vendor/tsm/mat2.js index e67db94..a1ac925 100644 --- a/src/framework/resonator/vendor/tsm/mat2.js +++ b/framework/resonator/vendor/tsm/mat2.js @@ -1,161 +1,161 @@ -import vec2 from './vec2'; -import { epsilon } from './constants'; -export default class mat2 { - constructor(values) { - this.values = new Float32Array(4); - if (values !== undefined) { - this.init(values); - } - } - at(index) { - return this.values[index]; - } - init(values) { - for (let i = 0; i < 4; i++) { - this.values[i] = values[i]; - } - return this; - } - reset() { - for (let i = 0; i < 4; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new mat2(); - } - for (let i = 0; i < 4; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - all() { - const data = []; - for (let i = 0; i < 4; i++) { - data[i] = this.values[i]; - } - return data; - } - row(index) { - return [this.values[index * 2 + 0], this.values[index * 2 + 1]]; - } - col(index) { - return [this.values[index], this.values[index + 2]]; - } - equals(matrix, threshold = epsilon) { - for (let i = 0; i < 4; i++) { - if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { - return false; - } - } - return true; - } - determinant() { - return this.values[0] * this.values[3] - this.values[2] * this.values[1]; - } - setIdentity() { - this.values[0] = 1; - this.values[1] = 0; - this.values[2] = 0; - this.values[3] = 1; - return this; - } - transpose() { - const temp = this.values[1]; - this.values[1] = this.values[2]; - this.values[2] = temp; - return this; - } - inverse() { - let det = this.determinant(); - if (!det) { - return null; - } - det = 1.0 / det; - const a11 = this.values[0]; - this.values[0] = det * this.values[3]; - this.values[1] = det * -this.values[1]; - this.values[2] = det * -this.values[2]; - this.values[3] = det * a11; - return this; - } - multiply(matrix) { - const a11 = this.values[0]; - const a12 = this.values[1]; - const a21 = this.values[2]; - const a22 = this.values[3]; - this.values[0] = a11 * matrix.at(0) + a12 * matrix.at(2); - this.values[1] = a11 * matrix.at(1) + a12 * matrix.at(3); - this.values[2] = a21 * matrix.at(0) + a22 * matrix.at(2); - this.values[3] = a21 * matrix.at(1) + a22 * matrix.at(3); - return this; - } - rotate(angle) { - const a11 = this.values[0]; - const a12 = this.values[1]; - const a21 = this.values[2]; - const a22 = this.values[3]; - const sin = Math.sin(angle); - const cos = Math.cos(angle); - this.values[0] = a11 * cos + a12 * sin; - this.values[1] = a11 * -sin + a12 * cos; - this.values[2] = a21 * cos + a22 * sin; - this.values[3] = a21 * -sin + a22 * cos; - return this; - } - multiplyVec2(vector, result) { - const x = vector.x; - const y = vector.y; - if (result) { - result.xy = [ - x * this.values[0] + y * this.values[1], - x * this.values[2] + y * this.values[3] - ]; - return result; - } - else { - return new vec2([ - x * this.values[0] + y * this.values[1], - x * this.values[2] + y * this.values[3] - ]); - } - } - scale(vector) { - const a11 = this.values[0]; - const a12 = this.values[1]; - const a21 = this.values[2]; - const a22 = this.values[3]; - const x = vector.x; - const y = vector.y; - this.values[0] = a11 * x; - this.values[1] = a12 * y; - this.values[2] = a21 * x; - this.values[3] = a22 * y; - return this; - } - static product(m1, m2, result) { - const a11 = m1.at(0); - const a12 = m1.at(1); - const a21 = m1.at(2); - const a22 = m1.at(3); - if (result) { - result.init([ - a11 * m2.at(0) + a12 * m2.at(2), - a11 * m2.at(1) + a12 * m2.at(3), - a21 * m2.at(0) + a22 * m2.at(2), - a21 * m2.at(1) + a22 * m2.at(3) - ]); - return result; - } - else { - return new mat2([ - a11 * m2.at(0) + a12 * m2.at(2), - a11 * m2.at(1) + a12 * m2.at(3), - a21 * m2.at(0) + a22 * m2.at(2), - a21 * m2.at(1) + a22 * m2.at(3) - ]); - } - } -} -mat2.identity = new mat2().setIdentity(); +import vec2 from './vec2'; +import { epsilon } from './constants'; +export default class mat2 { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 4; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 4; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat2(); + } + for (let i = 0; i < 4; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 4; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [this.values[index * 2 + 0], this.values[index * 2 + 1]]; + } + col(index) { + return [this.values[index], this.values[index + 2]]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 4; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + return this.values[0] * this.values[3] - this.values[2] * this.values[1]; + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 1; + return this; + } + transpose() { + const temp = this.values[1]; + this.values[1] = this.values[2]; + this.values[2] = temp; + return this; + } + inverse() { + let det = this.determinant(); + if (!det) { + return null; + } + det = 1.0 / det; + const a11 = this.values[0]; + this.values[0] = det * this.values[3]; + this.values[1] = det * -this.values[1]; + this.values[2] = det * -this.values[2]; + this.values[3] = det * a11; + return this; + } + multiply(matrix) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + this.values[0] = a11 * matrix.at(0) + a12 * matrix.at(2); + this.values[1] = a11 * matrix.at(1) + a12 * matrix.at(3); + this.values[2] = a21 * matrix.at(0) + a22 * matrix.at(2); + this.values[3] = a21 * matrix.at(1) + a22 * matrix.at(3); + return this; + } + rotate(angle) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + const sin = Math.sin(angle); + const cos = Math.cos(angle); + this.values[0] = a11 * cos + a12 * sin; + this.values[1] = a11 * -sin + a12 * cos; + this.values[2] = a21 * cos + a22 * sin; + this.values[3] = a21 * -sin + a22 * cos; + return this; + } + multiplyVec2(vector, result) { + const x = vector.x; + const y = vector.y; + if (result) { + result.xy = [ + x * this.values[0] + y * this.values[1], + x * this.values[2] + y * this.values[3] + ]; + return result; + } + else { + return new vec2([ + x * this.values[0] + y * this.values[1], + x * this.values[2] + y * this.values[3] + ]); + } + } + scale(vector) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + const x = vector.x; + const y = vector.y; + this.values[0] = a11 * x; + this.values[1] = a12 * y; + this.values[2] = a21 * x; + this.values[3] = a22 * y; + return this; + } + static product(m1, m2, result) { + const a11 = m1.at(0); + const a12 = m1.at(1); + const a21 = m1.at(2); + const a22 = m1.at(3); + if (result) { + result.init([ + a11 * m2.at(0) + a12 * m2.at(2), + a11 * m2.at(1) + a12 * m2.at(3), + a21 * m2.at(0) + a22 * m2.at(2), + a21 * m2.at(1) + a22 * m2.at(3) + ]); + return result; + } + else { + return new mat2([ + a11 * m2.at(0) + a12 * m2.at(2), + a11 * m2.at(1) + a12 * m2.at(3), + a21 * m2.at(0) + a22 * m2.at(2), + a21 * m2.at(1) + a22 * m2.at(3) + ]); + } + } +} +mat2.identity = new mat2().setIdentity(); diff --git a/src/framework/tsm/mat3.d.ts b/framework/resonator/vendor/tsm/mat3.d.ts similarity index 96% rename from src/framework/tsm/mat3.d.ts rename to framework/resonator/vendor/tsm/mat3.d.ts index 03bf323..3df4b3e 100644 --- a/src/framework/tsm/mat3.d.ts +++ b/framework/resonator/vendor/tsm/mat3.d.ts @@ -1,28 +1,28 @@ -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -export default class mat3 { - constructor(values?: number[]); - private values; - static readonly identity: mat3; - at(index: number): number; - init(values: number[]): mat3; - reset(): void; - copy(dest?: mat3): mat3; - all(): number[]; - row(index: number): number[]; - col(index: number): number[]; - equals(matrix: mat3, threshold?: number): boolean; - determinant(): number; - setIdentity(): mat3; - transpose(): mat3; - inverse(): mat3; - multiply(matrix: mat3): mat3; - multiplyVec2(vector: vec2, result: vec2): vec2; - multiplyVec3(vector: vec3, result: vec3): vec3; - toMat4(result: mat4): mat4; - toQuat(): quat; - rotate(angle: number, axis: vec3): mat3; - static product(m1: mat3, m2: mat3, result: mat3): mat3; -} +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +export default class mat3 { + constructor(values?: number[]); + private values; + static readonly identity: mat3; + at(index: number): number; + init(values: number[]): mat3; + reset(): void; + copy(dest?: mat3): mat3; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat3, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat3; + transpose(): mat3; + inverse(): mat3; + multiply(matrix: mat3): mat3; + multiplyVec2(vector: vec2, result: vec2): vec2; + multiplyVec3(vector: vec3, result: vec3): vec3; + toMat4(result: mat4): mat4; + toQuat(): quat; + rotate(angle: number, axis: vec3): mat3; + static product(m1: mat3, m2: mat3, result: mat3): mat3; +} diff --git a/src/framework/resonator/vendor/tsm/mat3.js b/framework/resonator/vendor/tsm/mat3.js similarity index 97% rename from src/framework/resonator/vendor/tsm/mat3.js rename to framework/resonator/vendor/tsm/mat3.js index 76e31b5..2359a3c 100644 --- a/src/framework/resonator/vendor/tsm/mat3.js +++ b/framework/resonator/vendor/tsm/mat3.js @@ -1,392 +1,392 @@ -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -import { epsilon } from './constants'; -export default class mat3 { - constructor(values) { - this.values = new Float32Array(9); - if (values !== undefined) { - this.init(values); - } - } - at(index) { - return this.values[index]; - } - init(values) { - for (let i = 0; i < 9; i++) { - this.values[i] = values[i]; - } - return this; - } - reset() { - for (let i = 0; i < 9; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new mat3(); - } - for (let i = 0; i < 9; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - all() { - const data = []; - for (let i = 0; i < 9; i++) { - data[i] = this.values[i]; - } - return data; - } - row(index) { - return [ - this.values[index * 3 + 0], - this.values[index * 3 + 1], - this.values[index * 3 + 2] - ]; - } - col(index) { - return [this.values[index], this.values[index + 3], this.values[index + 6]]; - } - equals(matrix, threshold = epsilon) { - for (let i = 0; i < 9; i++) { - if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { - return false; - } - } - return true; - } - determinant() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[3]; - const a11 = this.values[4]; - const a12 = this.values[5]; - const a20 = this.values[6]; - const a21 = this.values[7]; - const a22 = this.values[8]; - const det01 = a22 * a11 - a12 * a21; - const det11 = -a22 * a10 + a12 * a20; - const det21 = a21 * a10 - a11 * a20; - return a00 * det01 + a01 * det11 + a02 * det21; - } - setIdentity() { - this.values[0] = 1; - this.values[1] = 0; - this.values[2] = 0; - this.values[3] = 0; - this.values[4] = 1; - this.values[5] = 0; - this.values[6] = 0; - this.values[7] = 0; - this.values[8] = 1; - return this; - } - transpose() { - const temp01 = this.values[1]; - const temp02 = this.values[2]; - const temp12 = this.values[5]; - this.values[1] = this.values[3]; - this.values[2] = this.values[6]; - this.values[3] = temp01; - this.values[5] = this.values[7]; - this.values[6] = temp02; - this.values[7] = temp12; - return this; - } - inverse() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[3]; - const a11 = this.values[4]; - const a12 = this.values[5]; - const a20 = this.values[6]; - const a21 = this.values[7]; - const a22 = this.values[8]; - const det01 = a22 * a11 - a12 * a21; - const det11 = -a22 * a10 + a12 * a20; - const det21 = a21 * a10 - a11 * a20; - let det = a00 * det01 + a01 * det11 + a02 * det21; - if (!det) { - return null; - } - det = 1.0 / det; - this.values[0] = det01 * det; - this.values[1] = (-a22 * a01 + a02 * a21) * det; - this.values[2] = (a12 * a01 - a02 * a11) * det; - this.values[3] = det11 * det; - this.values[4] = (a22 * a00 - a02 * a20) * det; - this.values[5] = (-a12 * a00 + a02 * a10) * det; - this.values[6] = det21 * det; - this.values[7] = (-a21 * a00 + a01 * a20) * det; - this.values[8] = (a11 * a00 - a01 * a10) * det; - return this; - } - multiply(matrix) { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[3]; - const a11 = this.values[4]; - const a12 = this.values[5]; - const a20 = this.values[6]; - const a21 = this.values[7]; - const a22 = this.values[8]; - const b00 = matrix.at(0); - const b01 = matrix.at(1); - const b02 = matrix.at(2); - const b10 = matrix.at(3); - const b11 = matrix.at(4); - const b12 = matrix.at(5); - const b20 = matrix.at(6); - const b21 = matrix.at(7); - const b22 = matrix.at(8); - this.values[0] = b00 * a00 + b01 * a10 + b02 * a20; - this.values[1] = b00 * a01 + b01 * a11 + b02 * a21; - this.values[2] = b00 * a02 + b01 * a12 + b02 * a22; - this.values[3] = b10 * a00 + b11 * a10 + b12 * a20; - this.values[4] = b10 * a01 + b11 * a11 + b12 * a21; - this.values[5] = b10 * a02 + b11 * a12 + b12 * a22; - this.values[6] = b20 * a00 + b21 * a10 + b22 * a20; - this.values[7] = b20 * a01 + b21 * a11 + b22 * a21; - this.values[8] = b20 * a02 + b21 * a12 + b22 * a22; - return this; - } - multiplyVec2(vector, result) { - const x = vector.x; - const y = vector.y; - if (result) { - result.xy = [ - x * this.values[0] + y * this.values[3] + this.values[6], - x * this.values[1] + y * this.values[4] + this.values[7] - ]; - return result; - } - else { - return new vec2([ - x * this.values[0] + y * this.values[3] + this.values[6], - x * this.values[1] + y * this.values[4] + this.values[7] - ]); - } - } - multiplyVec3(vector, result) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - if (result) { - result.xyz = [ - x * this.values[0] + y * this.values[3] + z * this.values[6], - x * this.values[1] + y * this.values[4] + z * this.values[7], - x * this.values[2] + y * this.values[5] + z * this.values[8] - ]; - return result; - } - else { - return new vec3([ - x * this.values[0] + y * this.values[3] + z * this.values[6], - x * this.values[1] + y * this.values[4] + z * this.values[7], - x * this.values[2] + y * this.values[5] + z * this.values[8] - ]); - } - } - toMat4(result) { - if (result) { - result.init([ - this.values[0], - this.values[1], - this.values[2], - 0, - this.values[3], - this.values[4], - this.values[5], - 0, - this.values[6], - this.values[7], - this.values[8], - 0, - 0, - 0, - 0, - 1 - ]); - return result; - } - else { - return new mat4([ - this.values[0], - this.values[1], - this.values[2], - 0, - this.values[3], - this.values[4], - this.values[5], - 0, - this.values[6], - this.values[7], - this.values[8], - 0, - 0, - 0, - 0, - 1 - ]); - } - } - toQuat() { - const m00 = this.values[0]; - const m01 = this.values[1]; - const m02 = this.values[2]; - const m10 = this.values[3]; - const m11 = this.values[4]; - const m12 = this.values[5]; - const m20 = this.values[6]; - const m21 = this.values[7]; - const m22 = this.values[8]; - const fourXSquaredMinus1 = m00 - m11 - m22; - const fourYSquaredMinus1 = m11 - m00 - m22; - const fourZSquaredMinus1 = m22 - m00 - m11; - const fourWSquaredMinus1 = m00 + m11 + m22; - let biggestIndex = 0; - let fourBiggestSquaredMinus1 = fourWSquaredMinus1; - if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) { - fourBiggestSquaredMinus1 = fourXSquaredMinus1; - biggestIndex = 1; - } - if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) { - fourBiggestSquaredMinus1 = fourYSquaredMinus1; - biggestIndex = 2; - } - if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) { - fourBiggestSquaredMinus1 = fourZSquaredMinus1; - biggestIndex = 3; - } - const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5; - const mult = 0.25 / biggestVal; - const result = new quat(); - switch (biggestIndex) { - case 0: - result.w = biggestVal; - result.x = (m12 - m21) * mult; - result.y = (m20 - m02) * mult; - result.z = (m01 - m10) * mult; - break; - case 1: - result.w = (m12 - m21) * mult; - result.x = biggestVal; - result.y = (m01 + m10) * mult; - result.z = (m20 + m02) * mult; - break; - case 2: - result.w = (m20 - m02) * mult; - result.x = (m01 + m10) * mult; - result.y = biggestVal; - result.z = (m12 + m21) * mult; - break; - case 3: - result.w = (m01 - m10) * mult; - result.x = (m20 + m02) * mult; - result.y = (m12 + m21) * mult; - result.z = biggestVal; - break; - } - return result; - } - rotate(angle, axis) { - let x = axis.x; - let y = axis.y; - let z = axis.z; - let length = Math.sqrt(x * x + y * y + z * z); - if (!length) { - return null; - } - if (length !== 1) { - length = 1 / length; - x *= length; - y *= length; - z *= length; - } - const s = Math.sin(angle); - const c = Math.cos(angle); - const t = 1.0 - c; - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const b00 = x * x * t + c; - const b01 = y * x * t + z * s; - const b02 = z * x * t - y * s; - const b10 = x * y * t - z * s; - const b11 = y * y * t + c; - const b12 = z * y * t + x * s; - const b20 = x * z * t + y * s; - const b21 = y * z * t - x * s; - const b22 = z * z * t + c; - this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; - this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; - this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; - this.values[3] = a00 * b10 + a10 * b11 + a20 * b12; - this.values[4] = a01 * b10 + a11 * b11 + a21 * b12; - this.values[5] = a02 * b10 + a12 * b11 + a22 * b12; - this.values[6] = a00 * b20 + a10 * b21 + a20 * b22; - this.values[7] = a01 * b20 + a11 * b21 + a21 * b22; - this.values[8] = a02 * b20 + a12 * b21 + a22 * b22; - return this; - } - static product(m1, m2, result) { - const a00 = m1.at(0); - const a01 = m1.at(1); - const a02 = m1.at(2); - const a10 = m1.at(3); - const a11 = m1.at(4); - const a12 = m1.at(5); - const a20 = m1.at(6); - const a21 = m1.at(7); - const a22 = m1.at(8); - const b00 = m2.at(0); - const b01 = m2.at(1); - const b02 = m2.at(2); - const b10 = m2.at(3); - const b11 = m2.at(4); - const b12 = m2.at(5); - const b20 = m2.at(6); - const b21 = m2.at(7); - const b22 = m2.at(8); - if (result) { - result.init([ - b00 * a00 + b01 * a10 + b02 * a20, - b00 * a01 + b01 * a11 + b02 * a21, - b00 * a02 + b01 * a12 + b02 * a22, - b10 * a00 + b11 * a10 + b12 * a20, - b10 * a01 + b11 * a11 + b12 * a21, - b10 * a02 + b11 * a12 + b12 * a22, - b20 * a00 + b21 * a10 + b22 * a20, - b20 * a01 + b21 * a11 + b22 * a21, - b20 * a02 + b21 * a12 + b22 * a22 - ]); - return result; - } - else { - return new mat3([ - b00 * a00 + b01 * a10 + b02 * a20, - b00 * a01 + b01 * a11 + b02 * a21, - b00 * a02 + b01 * a12 + b02 * a22, - b10 * a00 + b11 * a10 + b12 * a20, - b10 * a01 + b11 * a11 + b12 * a21, - b10 * a02 + b11 * a12 + b12 * a22, - b20 * a00 + b21 * a10 + b22 * a20, - b20 * a01 + b21 * a11 + b22 * a21, - b20 * a02 + b21 * a12 + b22 * a22 - ]); - } - } -} -mat3.identity = new mat3().setIdentity(); +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class mat3 { + constructor(values) { + this.values = new Float32Array(9); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 9; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 9; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat3(); + } + for (let i = 0; i < 9; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 9; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [ + this.values[index * 3 + 0], + this.values[index * 3 + 1], + this.values[index * 3 + 2] + ]; + } + col(index) { + return [this.values[index], this.values[index + 3], this.values[index + 6]]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 9; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + return a00 * det01 + a01 * det11 + a02 * det21; + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 1; + this.values[5] = 0; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 1; + return this; + } + transpose() { + const temp01 = this.values[1]; + const temp02 = this.values[2]; + const temp12 = this.values[5]; + this.values[1] = this.values[3]; + this.values[2] = this.values[6]; + this.values[3] = temp01; + this.values[5] = this.values[7]; + this.values[6] = temp02; + this.values[7] = temp12; + return this; + } + inverse() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + let det = a00 * det01 + a01 * det11 + a02 * det21; + if (!det) { + return null; + } + det = 1.0 / det; + this.values[0] = det01 * det; + this.values[1] = (-a22 * a01 + a02 * a21) * det; + this.values[2] = (a12 * a01 - a02 * a11) * det; + this.values[3] = det11 * det; + this.values[4] = (a22 * a00 - a02 * a20) * det; + this.values[5] = (-a12 * a00 + a02 * a10) * det; + this.values[6] = det21 * det; + this.values[7] = (-a21 * a00 + a01 * a20) * det; + this.values[8] = (a11 * a00 - a01 * a10) * det; + return this; + } + multiply(matrix) { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const b00 = matrix.at(0); + const b01 = matrix.at(1); + const b02 = matrix.at(2); + const b10 = matrix.at(3); + const b11 = matrix.at(4); + const b12 = matrix.at(5); + const b20 = matrix.at(6); + const b21 = matrix.at(7); + const b22 = matrix.at(8); + this.values[0] = b00 * a00 + b01 * a10 + b02 * a20; + this.values[1] = b00 * a01 + b01 * a11 + b02 * a21; + this.values[2] = b00 * a02 + b01 * a12 + b02 * a22; + this.values[3] = b10 * a00 + b11 * a10 + b12 * a20; + this.values[4] = b10 * a01 + b11 * a11 + b12 * a21; + this.values[5] = b10 * a02 + b11 * a12 + b12 * a22; + this.values[6] = b20 * a00 + b21 * a10 + b22 * a20; + this.values[7] = b20 * a01 + b21 * a11 + b22 * a21; + this.values[8] = b20 * a02 + b21 * a12 + b22 * a22; + return this; + } + multiplyVec2(vector, result) { + const x = vector.x; + const y = vector.y; + if (result) { + result.xy = [ + x * this.values[0] + y * this.values[3] + this.values[6], + x * this.values[1] + y * this.values[4] + this.values[7] + ]; + return result; + } + else { + return new vec2([ + x * this.values[0] + y * this.values[3] + this.values[6], + x * this.values[1] + y * this.values[4] + this.values[7] + ]); + } + } + multiplyVec3(vector, result) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + if (result) { + result.xyz = [ + x * this.values[0] + y * this.values[3] + z * this.values[6], + x * this.values[1] + y * this.values[4] + z * this.values[7], + x * this.values[2] + y * this.values[5] + z * this.values[8] + ]; + return result; + } + else { + return new vec3([ + x * this.values[0] + y * this.values[3] + z * this.values[6], + x * this.values[1] + y * this.values[4] + z * this.values[7], + x * this.values[2] + y * this.values[5] + z * this.values[8] + ]); + } + } + toMat4(result) { + if (result) { + result.init([ + this.values[0], + this.values[1], + this.values[2], + 0, + this.values[3], + this.values[4], + this.values[5], + 0, + this.values[6], + this.values[7], + this.values[8], + 0, + 0, + 0, + 0, + 1 + ]); + return result; + } + else { + return new mat4([ + this.values[0], + this.values[1], + this.values[2], + 0, + this.values[3], + this.values[4], + this.values[5], + 0, + this.values[6], + this.values[7], + this.values[8], + 0, + 0, + 0, + 0, + 1 + ]); + } + } + toQuat() { + const m00 = this.values[0]; + const m01 = this.values[1]; + const m02 = this.values[2]; + const m10 = this.values[3]; + const m11 = this.values[4]; + const m12 = this.values[5]; + const m20 = this.values[6]; + const m21 = this.values[7]; + const m22 = this.values[8]; + const fourXSquaredMinus1 = m00 - m11 - m22; + const fourYSquaredMinus1 = m11 - m00 - m22; + const fourZSquaredMinus1 = m22 - m00 - m11; + const fourWSquaredMinus1 = m00 + m11 + m22; + let biggestIndex = 0; + let fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5; + const mult = 0.25 / biggestVal; + const result = new quat(); + switch (biggestIndex) { + case 0: + result.w = biggestVal; + result.x = (m12 - m21) * mult; + result.y = (m20 - m02) * mult; + result.z = (m01 - m10) * mult; + break; + case 1: + result.w = (m12 - m21) * mult; + result.x = biggestVal; + result.y = (m01 + m10) * mult; + result.z = (m20 + m02) * mult; + break; + case 2: + result.w = (m20 - m02) * mult; + result.x = (m01 + m10) * mult; + result.y = biggestVal; + result.z = (m12 + m21) * mult; + break; + case 3: + result.w = (m01 - m10) * mult; + result.x = (m20 + m02) * mult; + result.y = (m12 + m21) * mult; + result.z = biggestVal; + break; + } + return result; + } + rotate(angle, axis) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (!length) { + return null; + } + if (length !== 1) { + length = 1 / length; + x *= length; + y *= length; + z *= length; + } + const s = Math.sin(angle); + const c = Math.cos(angle); + const t = 1.0 - c; + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const b00 = x * x * t + c; + const b01 = y * x * t + z * s; + const b02 = z * x * t - y * s; + const b10 = x * y * t - z * s; + const b11 = y * y * t + c; + const b12 = z * y * t + x * s; + const b20 = x * z * t + y * s; + const b21 = y * z * t - x * s; + const b22 = z * z * t + c; + this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; + this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; + this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; + this.values[3] = a00 * b10 + a10 * b11 + a20 * b12; + this.values[4] = a01 * b10 + a11 * b11 + a21 * b12; + this.values[5] = a02 * b10 + a12 * b11 + a22 * b12; + this.values[6] = a00 * b20 + a10 * b21 + a20 * b22; + this.values[7] = a01 * b20 + a11 * b21 + a21 * b22; + this.values[8] = a02 * b20 + a12 * b21 + a22 * b22; + return this; + } + static product(m1, m2, result) { + const a00 = m1.at(0); + const a01 = m1.at(1); + const a02 = m1.at(2); + const a10 = m1.at(3); + const a11 = m1.at(4); + const a12 = m1.at(5); + const a20 = m1.at(6); + const a21 = m1.at(7); + const a22 = m1.at(8); + const b00 = m2.at(0); + const b01 = m2.at(1); + const b02 = m2.at(2); + const b10 = m2.at(3); + const b11 = m2.at(4); + const b12 = m2.at(5); + const b20 = m2.at(6); + const b21 = m2.at(7); + const b22 = m2.at(8); + if (result) { + result.init([ + b00 * a00 + b01 * a10 + b02 * a20, + b00 * a01 + b01 * a11 + b02 * a21, + b00 * a02 + b01 * a12 + b02 * a22, + b10 * a00 + b11 * a10 + b12 * a20, + b10 * a01 + b11 * a11 + b12 * a21, + b10 * a02 + b11 * a12 + b12 * a22, + b20 * a00 + b21 * a10 + b22 * a20, + b20 * a01 + b21 * a11 + b22 * a21, + b20 * a02 + b21 * a12 + b22 * a22 + ]); + return result; + } + else { + return new mat3([ + b00 * a00 + b01 * a10 + b02 * a20, + b00 * a01 + b01 * a11 + b02 * a21, + b00 * a02 + b01 * a12 + b02 * a22, + b10 * a00 + b11 * a10 + b12 * a20, + b10 * a01 + b11 * a11 + b12 * a21, + b10 * a02 + b11 * a12 + b12 * a22, + b20 * a00 + b21 * a10 + b22 * a20, + b20 * a01 + b21 * a11 + b22 * a21, + b20 * a02 + b21 * a12 + b22 * a22 + ]); + } + } +} +mat3.identity = new mat3().setIdentity(); diff --git a/src/framework/tsm/mat4.d.ts b/framework/resonator/vendor/tsm/mat4.d.ts similarity index 97% rename from src/framework/tsm/mat4.d.ts rename to framework/resonator/vendor/tsm/mat4.d.ts index 799d9a3..249550d 100644 --- a/src/framework/tsm/mat4.d.ts +++ b/framework/resonator/vendor/tsm/mat4.d.ts @@ -1,33 +1,33 @@ -import mat3 from './mat3'; -import vec3 from './vec3'; -import vec4 from './vec4'; -export default class mat4 { - constructor(values?: number[]); - private values; - static readonly identity: mat4; - at(index: number): number; - init(values: number[]): mat4; - reset(): void; - copy(dest?: mat4): mat4; - all(): number[]; - row(index: number): number[]; - col(index: number): number[]; - equals(matrix: mat4, threshold?: number): boolean; - determinant(): number; - setIdentity(): mat4; - transpose(): mat4; - inverse(): mat4; - multiply(matrix: mat4): mat4; - multiplyVec3(vector: vec3): vec3; - multiplyVec4(vector: vec4, dest?: vec4): vec4; - toMat3(): mat3; - toInverseMat3(): mat3; - translate(vector: vec3): mat4; - scale(vector: vec3): mat4; - rotate(angle: number, axis: vec3): mat4; - static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; - static perspective(fov: number, aspect: number, near: number, far: number): mat4; - static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; - static lookAt(position: vec3, target: vec3, up?: vec3): mat4; - static product(m1: mat4, m2: mat4, result: mat4): mat4; -} +import mat3 from './mat3'; +import vec3 from './vec3'; +import vec4 from './vec4'; +export default class mat4 { + constructor(values?: number[]); + private values; + static readonly identity: mat4; + at(index: number): number; + init(values: number[]): mat4; + reset(): void; + copy(dest?: mat4): mat4; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat4, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat4; + transpose(): mat4; + inverse(): mat4; + multiply(matrix: mat4): mat4; + multiplyVec3(vector: vec3): vec3; + multiplyVec4(vector: vec4, dest?: vec4): vec4; + toMat3(): mat3; + toInverseMat3(): mat3; + translate(vector: vec3): mat4; + scale(vector: vec3): mat4; + rotate(angle: number, axis: vec3): mat4; + static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; + static perspective(fov: number, aspect: number, near: number, far: number): mat4; + static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; + static lookAt(position: vec3, target: vec3, up?: vec3): mat4; + static product(m1: mat4, m2: mat4, result: mat4): mat4; +} diff --git a/src/framework/resonator/vendor/tsm/mat4.js b/framework/resonator/vendor/tsm/mat4.js similarity index 97% rename from src/framework/resonator/vendor/tsm/mat4.js rename to framework/resonator/vendor/tsm/mat4.js index 1447f4e..b8fb710 100644 --- a/src/framework/resonator/vendor/tsm/mat4.js +++ b/framework/resonator/vendor/tsm/mat4.js @@ -1,579 +1,579 @@ -import mat3 from './mat3'; -import vec3 from './vec3'; -import vec4 from './vec4'; -import { epsilon } from './constants'; -export default class mat4 { - constructor(values) { - this.values = new Float32Array(16); - if (values !== undefined) { - this.init(values); - } - } - at(index) { - return this.values[index]; - } - init(values) { - for (let i = 0; i < 16; i++) { - this.values[i] = values[i]; - } - return this; - } - reset() { - for (let i = 0; i < 16; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new mat4(); - } - for (let i = 0; i < 16; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - all() { - const data = []; - for (let i = 0; i < 16; i++) { - data[i] = this.values[i]; - } - return data; - } - row(index) { - return [ - this.values[index * 4 + 0], - this.values[index * 4 + 1], - this.values[index * 4 + 2], - this.values[index * 4 + 3] - ]; - } - col(index) { - return [ - this.values[index], - this.values[index + 4], - this.values[index + 8], - this.values[index + 12] - ]; - } - equals(matrix, threshold = epsilon) { - for (let i = 0; i < 16; i++) { - if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { - return false; - } - } - return true; - } - determinant() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const a30 = this.values[12]; - const a31 = this.values[13]; - const a32 = this.values[14]; - const a33 = this.values[15]; - const det00 = a00 * a11 - a01 * a10; - const det01 = a00 * a12 - a02 * a10; - const det02 = a00 * a13 - a03 * a10; - const det03 = a01 * a12 - a02 * a11; - const det04 = a01 * a13 - a03 * a11; - const det05 = a02 * a13 - a03 * a12; - const det06 = a20 * a31 - a21 * a30; - const det07 = a20 * a32 - a22 * a30; - const det08 = a20 * a33 - a23 * a30; - const det09 = a21 * a32 - a22 * a31; - const det10 = a21 * a33 - a23 * a31; - const det11 = a22 * a33 - a23 * a32; - return (det00 * det11 - - det01 * det10 + - det02 * det09 + - det03 * det08 - - det04 * det07 + - det05 * det06); - } - setIdentity() { - this.values[0] = 1; - this.values[1] = 0; - this.values[2] = 0; - this.values[3] = 0; - this.values[4] = 0; - this.values[5] = 1; - this.values[6] = 0; - this.values[7] = 0; - this.values[8] = 0; - this.values[9] = 0; - this.values[10] = 1; - this.values[11] = 0; - this.values[12] = 0; - this.values[13] = 0; - this.values[14] = 0; - this.values[15] = 1; - return this; - } - transpose() { - const temp01 = this.values[1]; - const temp02 = this.values[2]; - const temp03 = this.values[3]; - const temp12 = this.values[6]; - const temp13 = this.values[7]; - const temp23 = this.values[11]; - this.values[1] = this.values[4]; - this.values[2] = this.values[8]; - this.values[3] = this.values[12]; - this.values[4] = temp01; - this.values[6] = this.values[9]; - this.values[7] = this.values[13]; - this.values[8] = temp02; - this.values[9] = temp12; - this.values[11] = this.values[14]; - this.values[12] = temp03; - this.values[13] = temp13; - this.values[14] = temp23; - return this; - } - inverse() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const a30 = this.values[12]; - const a31 = this.values[13]; - const a32 = this.values[14]; - const a33 = this.values[15]; - const det00 = a00 * a11 - a01 * a10; - const det01 = a00 * a12 - a02 * a10; - const det02 = a00 * a13 - a03 * a10; - const det03 = a01 * a12 - a02 * a11; - const det04 = a01 * a13 - a03 * a11; - const det05 = a02 * a13 - a03 * a12; - const det06 = a20 * a31 - a21 * a30; - const det07 = a20 * a32 - a22 * a30; - const det08 = a20 * a33 - a23 * a30; - const det09 = a21 * a32 - a22 * a31; - const det10 = a21 * a33 - a23 * a31; - const det11 = a22 * a33 - a23 * a32; - let det = det00 * det11 - - det01 * det10 + - det02 * det09 + - det03 * det08 - - det04 * det07 + - det05 * det06; - if (!det) { - return null; - } - det = 1.0 / det; - this.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det; - this.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det; - this.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det; - this.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det; - this.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det; - this.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det; - this.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det; - this.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det; - this.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det; - this.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det; - this.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det; - this.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det; - this.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det; - this.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det; - this.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det; - this.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det; - return this; - } - multiply(matrix) { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const a30 = this.values[12]; - const a31 = this.values[13]; - const a32 = this.values[14]; - const a33 = this.values[15]; - let b0 = matrix.at(0); - let b1 = matrix.at(1); - let b2 = matrix.at(2); - let b3 = matrix.at(3); - this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - b0 = matrix.at(4); - b1 = matrix.at(5); - b2 = matrix.at(6); - b3 = matrix.at(7); - this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - b0 = matrix.at(8); - b1 = matrix.at(9); - b2 = matrix.at(10); - b3 = matrix.at(11); - this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - b0 = matrix.at(12); - b1 = matrix.at(13); - b2 = matrix.at(14); - b3 = matrix.at(15); - this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - return this; - } - multiplyVec3(vector) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - return new vec3([ - this.values[0] * x + - this.values[4] * y + - this.values[8] * z + - this.values[12], - this.values[1] * x + - this.values[5] * y + - this.values[9] * z + - this.values[13], - this.values[2] * x + - this.values[6] * y + - this.values[10] * z + - this.values[14] - ]); - } - multiplyVec4(vector, dest) { - if (!dest) { - dest = new vec4(); - } - const x = vector.x; - const y = vector.y; - const z = vector.z; - const w = vector.w; - dest.x = - this.values[0] * x + - this.values[4] * y + - this.values[8] * z + - this.values[12] * w; - dest.y = - this.values[1] * x + - this.values[5] * y + - this.values[9] * z + - this.values[13] * w; - dest.z = - this.values[2] * x + - this.values[6] * y + - this.values[10] * z + - this.values[14] * w; - dest.w = - this.values[3] * x + - this.values[7] * y + - this.values[11] * z + - this.values[15] * w; - return dest; - } - toMat3() { - return new mat3([ - this.values[0], - this.values[1], - this.values[2], - this.values[4], - this.values[5], - this.values[6], - this.values[8], - this.values[9], - this.values[10] - ]); - } - toInverseMat3() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const det01 = a22 * a11 - a12 * a21; - const det11 = -a22 * a10 + a12 * a20; - const det21 = a21 * a10 - a11 * a20; - let det = a00 * det01 + a01 * det11 + a02 * det21; - if (!det) { - return null; - } - det = 1.0 / det; - return new mat3([ - det01 * det, - (-a22 * a01 + a02 * a21) * det, - (a12 * a01 - a02 * a11) * det, - det11 * det, - (a22 * a00 - a02 * a20) * det, - (-a12 * a00 + a02 * a10) * det, - det21 * det, - (-a21 * a00 + a01 * a20) * det, - (a11 * a00 - a01 * a10) * det - ]); - } - translate(vector) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - this.values[12] += - this.values[0] * x + this.values[4] * y + this.values[8] * z; - this.values[13] += - this.values[1] * x + this.values[5] * y + this.values[9] * z; - this.values[14] += - this.values[2] * x + this.values[6] * y + this.values[10] * z; - this.values[15] += - this.values[3] * x + this.values[7] * y + this.values[11] * z; - return this; - } - scale(vector) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - this.values[0] *= x; - this.values[1] *= x; - this.values[2] *= x; - this.values[3] *= x; - this.values[4] *= y; - this.values[5] *= y; - this.values[6] *= y; - this.values[7] *= y; - this.values[8] *= z; - this.values[9] *= z; - this.values[10] *= z; - this.values[11] *= z; - return this; - } - rotate(angle, axis) { - let x = axis.x; - let y = axis.y; - let z = axis.z; - let length = Math.sqrt(x * x + y * y + z * z); - if (!length) { - return null; - } - if (length !== 1) { - length = 1 / length; - x *= length; - y *= length; - z *= length; - } - const s = Math.sin(angle); - const c = Math.cos(angle); - const t = 1.0 - c; - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const b00 = x * x * t + c; - const b01 = y * x * t + z * s; - const b02 = z * x * t - y * s; - const b10 = x * y * t - z * s; - const b11 = y * y * t + c; - const b12 = z * y * t + x * s; - const b20 = x * z * t + y * s; - const b21 = y * z * t - x * s; - const b22 = z * z * t + c; - this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; - this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; - this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; - this.values[3] = a03 * b00 + a13 * b01 + a23 * b02; - this.values[4] = a00 * b10 + a10 * b11 + a20 * b12; - this.values[5] = a01 * b10 + a11 * b11 + a21 * b12; - this.values[6] = a02 * b10 + a12 * b11 + a22 * b12; - this.values[7] = a03 * b10 + a13 * b11 + a23 * b12; - this.values[8] = a00 * b20 + a10 * b21 + a20 * b22; - this.values[9] = a01 * b20 + a11 * b21 + a21 * b22; - this.values[10] = a02 * b20 + a12 * b21 + a22 * b22; - this.values[11] = a03 * b20 + a13 * b21 + a23 * b22; - return this; - } - static frustum(left, right, bottom, top, near, far) { - const rl = right - left; - const tb = top - bottom; - const fn = far - near; - return new mat4([ - (near * 2) / rl, - 0, - 0, - 0, - 0, - (near * 2) / tb, - 0, - 0, - (right + left) / rl, - (top + bottom) / tb, - -(far + near) / fn, - -1, - 0, - 0, - -(far * near * 2) / fn, - 0 - ]); - } - static perspective(fov, aspect, near, far) { - const top = near * Math.tan((fov * Math.PI) / 360.0); - const right = top * aspect; - return mat4.frustum(-right, right, -top, top, near, far); - } - static orthographic(left, right, bottom, top, near, far) { - const rl = right - left; - const tb = top - bottom; - const fn = far - near; - return new mat4([ - 2 / rl, - 0, - 0, - 0, - 0, - 2 / tb, - 0, - 0, - 0, - 0, - -2 / fn, - 0, - -(left + right) / rl, - -(top + bottom) / tb, - -(far + near) / fn, - 1 - ]); - } - static lookAt(position, target, up = vec3.up) { - if (position.equals(target)) { - return this.identity; - } - const z = vec3.difference(position, target).normalize(); - const x = vec3.cross(up, z).normalize(); - const y = vec3.cross(z, x).normalize(); - return new mat4([ - x.x, - y.x, - z.x, - 0, - x.y, - y.y, - z.y, - 0, - x.z, - y.z, - z.z, - 0, - -vec3.dot(x, position), - -vec3.dot(y, position), - -vec3.dot(z, position), - 1 - ]); - } - static product(m1, m2, result) { - const a00 = m1.at(0); - const a01 = m1.at(1); - const a02 = m1.at(2); - const a03 = m1.at(3); - const a10 = m1.at(4); - const a11 = m1.at(5); - const a12 = m1.at(6); - const a13 = m1.at(7); - const a20 = m1.at(8); - const a21 = m1.at(9); - const a22 = m1.at(10); - const a23 = m1.at(11); - const a30 = m1.at(12); - const a31 = m1.at(13); - const a32 = m1.at(14); - const a33 = m1.at(15); - const b00 = m2.at(0); - const b01 = m2.at(1); - const b02 = m2.at(2); - const b03 = m2.at(3); - const b10 = m2.at(4); - const b11 = m2.at(5); - const b12 = m2.at(6); - const b13 = m2.at(7); - const b20 = m2.at(8); - const b21 = m2.at(9); - const b22 = m2.at(10); - const b23 = m2.at(11); - const b30 = m2.at(12); - const b31 = m2.at(13); - const b32 = m2.at(14); - const b33 = m2.at(15); - if (result) { - result.init([ - b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, - b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, - b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, - b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, - b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, - b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, - b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, - b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, - b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, - b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, - b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, - b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, - b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, - b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, - b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, - b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 - ]); - return result; - } - else { - return new mat4([ - b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, - b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, - b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, - b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, - b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, - b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, - b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, - b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, - b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, - b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, - b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, - b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, - b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, - b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, - b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, - b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 - ]); - } - } -} -mat4.identity = new mat4().setIdentity(); +import mat3 from './mat3'; +import vec3 from './vec3'; +import vec4 from './vec4'; +import { epsilon } from './constants'; +export default class mat4 { + constructor(values) { + this.values = new Float32Array(16); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 16; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 16; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat4(); + } + for (let i = 0; i < 16; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 16; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [ + this.values[index * 4 + 0], + this.values[index * 4 + 1], + this.values[index * 4 + 2], + this.values[index * 4 + 3] + ]; + } + col(index) { + return [ + this.values[index], + this.values[index + 4], + this.values[index + 8], + this.values[index + 12] + ]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 16; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + const det00 = a00 * a11 - a01 * a10; + const det01 = a00 * a12 - a02 * a10; + const det02 = a00 * a13 - a03 * a10; + const det03 = a01 * a12 - a02 * a11; + const det04 = a01 * a13 - a03 * a11; + const det05 = a02 * a13 - a03 * a12; + const det06 = a20 * a31 - a21 * a30; + const det07 = a20 * a32 - a22 * a30; + const det08 = a20 * a33 - a23 * a30; + const det09 = a21 * a32 - a22 * a31; + const det10 = a21 * a33 - a23 * a31; + const det11 = a22 * a33 - a23 * a32; + return (det00 * det11 - + det01 * det10 + + det02 * det09 + + det03 * det08 - + det04 * det07 + + det05 * det06); + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 0; + this.values[5] = 1; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 0; + this.values[9] = 0; + this.values[10] = 1; + this.values[11] = 0; + this.values[12] = 0; + this.values[13] = 0; + this.values[14] = 0; + this.values[15] = 1; + return this; + } + transpose() { + const temp01 = this.values[1]; + const temp02 = this.values[2]; + const temp03 = this.values[3]; + const temp12 = this.values[6]; + const temp13 = this.values[7]; + const temp23 = this.values[11]; + this.values[1] = this.values[4]; + this.values[2] = this.values[8]; + this.values[3] = this.values[12]; + this.values[4] = temp01; + this.values[6] = this.values[9]; + this.values[7] = this.values[13]; + this.values[8] = temp02; + this.values[9] = temp12; + this.values[11] = this.values[14]; + this.values[12] = temp03; + this.values[13] = temp13; + this.values[14] = temp23; + return this; + } + inverse() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + const det00 = a00 * a11 - a01 * a10; + const det01 = a00 * a12 - a02 * a10; + const det02 = a00 * a13 - a03 * a10; + const det03 = a01 * a12 - a02 * a11; + const det04 = a01 * a13 - a03 * a11; + const det05 = a02 * a13 - a03 * a12; + const det06 = a20 * a31 - a21 * a30; + const det07 = a20 * a32 - a22 * a30; + const det08 = a20 * a33 - a23 * a30; + const det09 = a21 * a32 - a22 * a31; + const det10 = a21 * a33 - a23 * a31; + const det11 = a22 * a33 - a23 * a32; + let det = det00 * det11 - + det01 * det10 + + det02 * det09 + + det03 * det08 - + det04 * det07 + + det05 * det06; + if (!det) { + return null; + } + det = 1.0 / det; + this.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det; + this.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det; + this.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det; + this.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det; + this.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det; + this.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det; + this.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det; + this.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det; + this.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det; + this.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det; + this.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det; + this.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det; + this.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det; + this.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det; + this.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det; + this.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det; + return this; + } + multiply(matrix) { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + let b0 = matrix.at(0); + let b1 = matrix.at(1); + let b2 = matrix.at(2); + let b3 = matrix.at(3); + this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(4); + b1 = matrix.at(5); + b2 = matrix.at(6); + b3 = matrix.at(7); + this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(8); + b1 = matrix.at(9); + b2 = matrix.at(10); + b3 = matrix.at(11); + this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(12); + b1 = matrix.at(13); + b2 = matrix.at(14); + b3 = matrix.at(15); + this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + return this; + } + multiplyVec3(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + return new vec3([ + this.values[0] * x + + this.values[4] * y + + this.values[8] * z + + this.values[12], + this.values[1] * x + + this.values[5] * y + + this.values[9] * z + + this.values[13], + this.values[2] * x + + this.values[6] * y + + this.values[10] * z + + this.values[14] + ]); + } + multiplyVec4(vector, dest) { + if (!dest) { + dest = new vec4(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const w = vector.w; + dest.x = + this.values[0] * x + + this.values[4] * y + + this.values[8] * z + + this.values[12] * w; + dest.y = + this.values[1] * x + + this.values[5] * y + + this.values[9] * z + + this.values[13] * w; + dest.z = + this.values[2] * x + + this.values[6] * y + + this.values[10] * z + + this.values[14] * w; + dest.w = + this.values[3] * x + + this.values[7] * y + + this.values[11] * z + + this.values[15] * w; + return dest; + } + toMat3() { + return new mat3([ + this.values[0], + this.values[1], + this.values[2], + this.values[4], + this.values[5], + this.values[6], + this.values[8], + this.values[9], + this.values[10] + ]); + } + toInverseMat3() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + let det = a00 * det01 + a01 * det11 + a02 * det21; + if (!det) { + return null; + } + det = 1.0 / det; + return new mat3([ + det01 * det, + (-a22 * a01 + a02 * a21) * det, + (a12 * a01 - a02 * a11) * det, + det11 * det, + (a22 * a00 - a02 * a20) * det, + (-a12 * a00 + a02 * a10) * det, + det21 * det, + (-a21 * a00 + a01 * a20) * det, + (a11 * a00 - a01 * a10) * det + ]); + } + translate(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + this.values[12] += + this.values[0] * x + this.values[4] * y + this.values[8] * z; + this.values[13] += + this.values[1] * x + this.values[5] * y + this.values[9] * z; + this.values[14] += + this.values[2] * x + this.values[6] * y + this.values[10] * z; + this.values[15] += + this.values[3] * x + this.values[7] * y + this.values[11] * z; + return this; + } + scale(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + this.values[0] *= x; + this.values[1] *= x; + this.values[2] *= x; + this.values[3] *= x; + this.values[4] *= y; + this.values[5] *= y; + this.values[6] *= y; + this.values[7] *= y; + this.values[8] *= z; + this.values[9] *= z; + this.values[10] *= z; + this.values[11] *= z; + return this; + } + rotate(angle, axis) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (!length) { + return null; + } + if (length !== 1) { + length = 1 / length; + x *= length; + y *= length; + z *= length; + } + const s = Math.sin(angle); + const c = Math.cos(angle); + const t = 1.0 - c; + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const b00 = x * x * t + c; + const b01 = y * x * t + z * s; + const b02 = z * x * t - y * s; + const b10 = x * y * t - z * s; + const b11 = y * y * t + c; + const b12 = z * y * t + x * s; + const b20 = x * z * t + y * s; + const b21 = y * z * t - x * s; + const b22 = z * z * t + c; + this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; + this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; + this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; + this.values[3] = a03 * b00 + a13 * b01 + a23 * b02; + this.values[4] = a00 * b10 + a10 * b11 + a20 * b12; + this.values[5] = a01 * b10 + a11 * b11 + a21 * b12; + this.values[6] = a02 * b10 + a12 * b11 + a22 * b12; + this.values[7] = a03 * b10 + a13 * b11 + a23 * b12; + this.values[8] = a00 * b20 + a10 * b21 + a20 * b22; + this.values[9] = a01 * b20 + a11 * b21 + a21 * b22; + this.values[10] = a02 * b20 + a12 * b21 + a22 * b22; + this.values[11] = a03 * b20 + a13 * b21 + a23 * b22; + return this; + } + static frustum(left, right, bottom, top, near, far) { + const rl = right - left; + const tb = top - bottom; + const fn = far - near; + return new mat4([ + (near * 2) / rl, + 0, + 0, + 0, + 0, + (near * 2) / tb, + 0, + 0, + (right + left) / rl, + (top + bottom) / tb, + -(far + near) / fn, + -1, + 0, + 0, + -(far * near * 2) / fn, + 0 + ]); + } + static perspective(fov, aspect, near, far) { + const top = near * Math.tan((fov * Math.PI) / 360.0); + const right = top * aspect; + return mat4.frustum(-right, right, -top, top, near, far); + } + static orthographic(left, right, bottom, top, near, far) { + const rl = right - left; + const tb = top - bottom; + const fn = far - near; + return new mat4([ + 2 / rl, + 0, + 0, + 0, + 0, + 2 / tb, + 0, + 0, + 0, + 0, + -2 / fn, + 0, + -(left + right) / rl, + -(top + bottom) / tb, + -(far + near) / fn, + 1 + ]); + } + static lookAt(position, target, up = vec3.up) { + if (position.equals(target)) { + return this.identity; + } + const z = vec3.difference(position, target).normalize(); + const x = vec3.cross(up, z).normalize(); + const y = vec3.cross(z, x).normalize(); + return new mat4([ + x.x, + y.x, + z.x, + 0, + x.y, + y.y, + z.y, + 0, + x.z, + y.z, + z.z, + 0, + -vec3.dot(x, position), + -vec3.dot(y, position), + -vec3.dot(z, position), + 1 + ]); + } + static product(m1, m2, result) { + const a00 = m1.at(0); + const a01 = m1.at(1); + const a02 = m1.at(2); + const a03 = m1.at(3); + const a10 = m1.at(4); + const a11 = m1.at(5); + const a12 = m1.at(6); + const a13 = m1.at(7); + const a20 = m1.at(8); + const a21 = m1.at(9); + const a22 = m1.at(10); + const a23 = m1.at(11); + const a30 = m1.at(12); + const a31 = m1.at(13); + const a32 = m1.at(14); + const a33 = m1.at(15); + const b00 = m2.at(0); + const b01 = m2.at(1); + const b02 = m2.at(2); + const b03 = m2.at(3); + const b10 = m2.at(4); + const b11 = m2.at(5); + const b12 = m2.at(6); + const b13 = m2.at(7); + const b20 = m2.at(8); + const b21 = m2.at(9); + const b22 = m2.at(10); + const b23 = m2.at(11); + const b30 = m2.at(12); + const b31 = m2.at(13); + const b32 = m2.at(14); + const b33 = m2.at(15); + if (result) { + result.init([ + b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, + b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, + b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, + b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, + b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, + b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, + b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, + b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, + b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, + b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, + b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, + b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, + b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, + b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, + b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, + b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 + ]); + return result; + } + else { + return new mat4([ + b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, + b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, + b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, + b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, + b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, + b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, + b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, + b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, + b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, + b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, + b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, + b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, + b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, + b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, + b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, + b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 + ]); + } + } +} +mat4.identity = new mat4().setIdentity(); diff --git a/src/framework/resonator/vendor/tsm/quat.d.ts b/framework/resonator/vendor/tsm/quat.d.ts similarity index 97% rename from src/framework/resonator/vendor/tsm/quat.d.ts rename to framework/resonator/vendor/tsm/quat.d.ts index 1195bfd..b4e9528 100644 --- a/src/framework/resonator/vendor/tsm/quat.d.ts +++ b/framework/resonator/vendor/tsm/quat.d.ts @@ -1,47 +1,47 @@ -import mat3 from './mat3'; -import mat4 from './mat4'; -import vec3 from './vec3'; -export default class quat { - get x(): number; - get y(): number; - get z(): number; - get w(): number; - get xy(): [number, number]; - get xyz(): [number, number, number]; - get xyzw(): [number, number, number, number]; - set x(value: number); - set y(value: number); - set z(value: number); - set w(value: number); - set xy(values: [number, number]); - set xyz(values: [number, number, number]); - set xyzw(values: [number, number, number, number]); - constructor(values?: [number, number, number, number]); - private values; - static readonly identity: quat; - at(index: number): number; - reset(): void; - copy(dest?: quat): quat; - roll(): number; - pitch(): number; - yaw(): number; - equals(vector: quat, threshold?: number): boolean; - setIdentity(): quat; - calculateW(): quat; - inverse(): quat; - conjugate(): quat; - length(): number; - normalize(dest?: quat): quat; - add(other: quat): quat; - multiply(other: quat): quat; - multiplyVec3(vector: vec3, dest?: vec3): vec3; - toMat3(dest?: mat3): mat3; - toMat4(dest?: mat4): mat4; - static dot(q1: quat, q2: quat): number; - static sum(q1: quat, q2: quat, dest?: quat): quat; - static product(q1: quat, q2: quat, dest?: quat): quat; - static cross(q1: quat, q2: quat, dest?: quat): quat; - static shortMix(q1: quat, q2: quat, time: number, dest?: quat): quat; - static mix(q1: quat, q2: quat, time: number, dest?: quat): quat; - static fromAxisAngle(axis: vec3, angle: number, dest?: quat): quat; -} +import mat3 from './mat3'; +import mat4 from './mat4'; +import vec3 from './vec3'; +export default class quat { + get x(): number; + get y(): number; + get z(): number; + get w(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + get xyzw(): [number, number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set w(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + set xyzw(values: [number, number, number, number]); + constructor(values?: [number, number, number, number]); + private values; + static readonly identity: quat; + at(index: number): number; + reset(): void; + copy(dest?: quat): quat; + roll(): number; + pitch(): number; + yaw(): number; + equals(vector: quat, threshold?: number): boolean; + setIdentity(): quat; + calculateW(): quat; + inverse(): quat; + conjugate(): quat; + length(): number; + normalize(dest?: quat): quat; + add(other: quat): quat; + multiply(other: quat): quat; + multiplyVec3(vector: vec3, dest?: vec3): vec3; + toMat3(dest?: mat3): mat3; + toMat4(dest?: mat4): mat4; + static dot(q1: quat, q2: quat): number; + static sum(q1: quat, q2: quat, dest?: quat): quat; + static product(q1: quat, q2: quat, dest?: quat): quat; + static cross(q1: quat, q2: quat, dest?: quat): quat; + static shortMix(q1: quat, q2: quat, time: number, dest?: quat): quat; + static mix(q1: quat, q2: quat, time: number, dest?: quat): quat; + static fromAxisAngle(axis: vec3, angle: number, dest?: quat): quat; +} diff --git a/src/framework/tsm/quat.js b/framework/resonator/vendor/tsm/quat.js similarity index 96% rename from src/framework/tsm/quat.js rename to framework/resonator/vendor/tsm/quat.js index 54c43ba..3aabbd4 100644 --- a/src/framework/tsm/quat.js +++ b/framework/resonator/vendor/tsm/quat.js @@ -1,404 +1,404 @@ -import mat3 from './mat3'; -import mat4 from './mat4'; -import vec3 from './vec3'; -import { epsilon } from './constants'; -export default class quat { - constructor(values) { - this.values = new Float32Array(4); - if (values !== undefined) { - this.xyzw = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get z() { - return this.values[2]; - } - get w() { - return this.values[3]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - get xyz() { - return [this.values[0], this.values[1], this.values[2]]; - } - get xyzw() { - return [this.values[0], this.values[1], this.values[2], this.values[3]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set z(value) { - this.values[2] = value; - } - set w(value) { - this.values[3] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set xyz(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - set xyzw(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - this.values[3] = values[3]; - } - at(index) { - return this.values[index]; - } - reset() { - for (let i = 0; i < 4; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new quat(); - } - for (let i = 0; i < 4; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - roll() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z); - } - pitch() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z); - } - yaw() { - return Math.asin(2.0 * (this.x * this.z - this.w * this.y)); - } - equals(vector, threshold = epsilon) { - for (let i = 0; i < 4; i++) { - if (Math.abs(this.values[i] - vector.at(i)) > threshold) { - return false; - } - } - return true; - } - setIdentity() { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - return this; - } - calculateW() { - const x = this.x; - const y = this.y; - const z = this.z; - this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); - return this; - } - inverse() { - const dot = quat.dot(this, this); - if (!dot) { - this.xyzw = [0, 0, 0, 0]; - return this; - } - const invDot = dot ? 1.0 / dot : 0; - this.x *= -invDot; - this.y *= -invDot; - this.z *= -invDot; - this.w *= invDot; - return this; - } - conjugate() { - this.values[0] *= -1; - this.values[1] *= -1; - this.values[2] *= -1; - return this; - } - length() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return Math.sqrt(x * x + y * y + z * z + w * w); - } - normalize(dest) { - if (!dest) { - dest = this; - } - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - let length = Math.sqrt(x * x + y * y + z * z + w * w); - if (!length) { - dest.x = 0; - dest.y = 0; - dest.z = 0; - dest.w = 0; - return dest; - } - length = 1 / length; - dest.x = x * length; - dest.y = y * length; - dest.z = z * length; - dest.w = w * length; - return dest; - } - add(other) { - for (let i = 0; i < 4; i++) { - this.values[i] += other.at(i); - } - return this; - } - multiply(other) { - const q1x = this.values[0]; - const q1y = this.values[1]; - const q1z = this.values[2]; - const q1w = this.values[3]; - const q2x = other.x; - const q2y = other.y; - const q2z = other.z; - const q2w = other.w; - this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; - this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; - this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; - this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; - return this; - } - multiplyVec3(vector, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x; - const y = vector.y; - const z = vector.z; - const qx = this.x; - const qy = this.y; - const qz = this.z; - const qw = this.w; - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = -qx * x - qy * y - qz * z; - dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return dest; - } - toMat3(dest) { - if (!dest) { - dest = new mat3(); - } - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - const x2 = x + x; - const y2 = y + y; - const z2 = z + z; - const xx = x * x2; - const xy = x * y2; - const xz = x * z2; - const yy = y * y2; - const yz = y * z2; - const zz = z * z2; - const wx = w * x2; - const wy = w * y2; - const wz = w * z2; - dest.init([ - 1 - (yy + zz), - xy + wz, - xz - wy, - xy - wz, - 1 - (xx + zz), - yz + wx, - xz + wy, - yz - wx, - 1 - (xx + yy) - ]); - return dest; - } - toMat4(dest) { - if (!dest) { - dest = new mat4(); - } - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - const x2 = x + x; - const y2 = y + y; - const z2 = z + z; - const xx = x * x2; - const xy = x * y2; - const xz = x * z2; - const yy = y * y2; - const yz = y * z2; - const zz = z * z2; - const wx = w * x2; - const wy = w * y2; - const wz = w * z2; - dest.init([ - 1 - (yy + zz), - xy + wz, - xz - wy, - 0, - xy - wz, - 1 - (xx + zz), - yz + wx, - 0, - xz + wy, - yz - wx, - 1 - (xx + yy), - 0, - 0, - 0, - 0, - 1 - ]); - return dest; - } - static dot(q1, q2) { - return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - } - static sum(q1, q2, dest) { - if (!dest) { - dest = new quat(); - } - dest.x = q1.x + q2.x; - dest.y = q1.y + q2.y; - dest.z = q1.z + q2.z; - dest.w = q1.w + q2.w; - return dest; - } - static product(q1, q2, dest) { - if (!dest) { - dest = new quat(); - } - const q1x = q1.x; - const q1y = q1.y; - const q1z = q1.z; - const q1w = q1.w; - const q2x = q2.x; - const q2y = q2.y; - const q2z = q2.z; - const q2w = q2.w; - dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; - dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; - dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; - dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; - return dest; - } - static cross(q1, q2, dest) { - if (!dest) { - dest = new quat(); - } - const q1x = q1.x; - const q1y = q1.y; - const q1z = q1.z; - const q1w = q1.w; - const q2x = q2.x; - const q2y = q2.y; - const q2z = q2.z; - const q2w = q2.w; - dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x; - dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; - dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y; - dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z; - return dest; - } - static shortMix(q1, q2, time, dest) { - if (!dest) { - dest = new quat(); - } - if (time <= 0.0) { - dest.xyzw = q1.xyzw; - return dest; - } - else if (time >= 1.0) { - dest.xyzw = q2.xyzw; - return dest; - } - let cos = quat.dot(q1, q2); - const q2a = q2.copy(); - if (cos < 0.0) { - q2a.inverse(); - cos = -cos; - } - let k0; - let k1; - if (cos > 0.9999) { - k0 = 1 - time; - k1 = 0 + time; - } - else { - const sin = Math.sqrt(1 - cos * cos); - const angle = Math.atan2(sin, cos); - const oneOverSin = 1 / sin; - k0 = Math.sin((1 - time) * angle) * oneOverSin; - k1 = Math.sin((0 + time) * angle) * oneOverSin; - } - dest.x = k0 * q1.x + k1 * q2a.x; - dest.y = k0 * q1.y + k1 * q2a.y; - dest.z = k0 * q1.z + k1 * q2a.z; - dest.w = k0 * q1.w + k1 * q2a.w; - return dest; - } - static mix(q1, q2, time, dest) { - if (!dest) { - dest = new quat(); - } - const cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - if (Math.abs(cosHalfTheta) >= 1.0) { - dest.xyzw = q1.xyzw; - return dest; - } - const halfTheta = Math.acos(cosHalfTheta); - const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); - if (Math.abs(sinHalfTheta) < 0.001) { - dest.x = q1.x * 0.5 + q2.x * 0.5; - dest.y = q1.y * 0.5 + q2.y * 0.5; - dest.z = q1.z * 0.5 + q2.z * 0.5; - dest.w = q1.w * 0.5 + q2.w * 0.5; - return dest; - } - const ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta; - const ratioB = Math.sin(time * halfTheta) / sinHalfTheta; - dest.x = q1.x * ratioA + q2.x * ratioB; - dest.y = q1.y * ratioA + q2.y * ratioB; - dest.z = q1.z * ratioA + q2.z * ratioB; - dest.w = q1.w * ratioA + q2.w * ratioB; - return dest; - } - static fromAxisAngle(axis, angle, dest) { - if (!dest) { - dest = new quat(); - } - angle *= 0.5; - const sin = Math.sin(angle); - dest.x = axis.x * sin; - dest.y = axis.y * sin; - dest.z = axis.z * sin; - dest.w = Math.cos(angle); - return dest; - } -} -quat.identity = new quat().setIdentity(); +import mat3 from './mat3'; +import mat4 from './mat4'; +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class quat { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.xyzw = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get w() { + return this.values[3]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + get xyzw() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set w(value) { + this.values[3] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set xyzw(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + at(index) { + return this.values[index]; + } + reset() { + for (let i = 0; i < 4; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new quat(); + } + for (let i = 0; i < 4; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + roll() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z); + } + pitch() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z); + } + yaw() { + return Math.asin(2.0 * (this.x * this.z - this.w * this.y)); + } + equals(vector, threshold = epsilon) { + for (let i = 0; i < 4; i++) { + if (Math.abs(this.values[i] - vector.at(i)) > threshold) { + return false; + } + } + return true; + } + setIdentity() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + return this; + } + calculateW() { + const x = this.x; + const y = this.y; + const z = this.z; + this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return this; + } + inverse() { + const dot = quat.dot(this, this); + if (!dot) { + this.xyzw = [0, 0, 0, 0]; + return this; + } + const invDot = dot ? 1.0 / dot : 0; + this.x *= -invDot; + this.y *= -invDot; + this.z *= -invDot; + this.w *= invDot; + return this; + } + conjugate() { + this.values[0] *= -1; + this.values[1] *= -1; + this.values[2] *= -1; + return this; + } + length() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.sqrt(x * x + y * y + z * z + w * w); + } + normalize(dest) { + if (!dest) { + dest = this; + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + let length = Math.sqrt(x * x + y * y + z * z + w * w); + if (!length) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + dest.w = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + dest.z = z * length; + dest.w = w * length; + return dest; + } + add(other) { + for (let i = 0; i < 4; i++) { + this.values[i] += other.at(i); + } + return this; + } + multiply(other) { + const q1x = this.values[0]; + const q1y = this.values[1]; + const q1z = this.values[2]; + const q1w = this.values[3]; + const q2x = other.x; + const q2y = other.y; + const q2z = other.z; + const q2w = other.w; + this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; + this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; + this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; + this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + return this; + } + multiplyVec3(vector, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const qx = this.x; + const qy = this.y; + const qz = this.z; + const qw = this.w; + const ix = qw * x + qy * z - qz * y; + const iy = qw * y + qz * x - qx * z; + const iz = qw * z + qx * y - qy * x; + const iw = -qx * x - qy * y - qz * z; + dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return dest; + } + toMat3(dest) { + if (!dest) { + dest = new mat3(); + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + dest.init([ + 1 - (yy + zz), + xy + wz, + xz - wy, + xy - wz, + 1 - (xx + zz), + yz + wx, + xz + wy, + yz - wx, + 1 - (xx + yy) + ]); + return dest; + } + toMat4(dest) { + if (!dest) { + dest = new mat4(); + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + dest.init([ + 1 - (yy + zz), + xy + wz, + xz - wy, + 0, + xy - wz, + 1 - (xx + zz), + yz + wx, + 0, + xz + wy, + yz - wx, + 1 - (xx + yy), + 0, + 0, + 0, + 0, + 1 + ]); + return dest; + } + static dot(q1, q2) { + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + } + static sum(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + dest.x = q1.x + q2.x; + dest.y = q1.y + q2.y; + dest.z = q1.z + q2.z; + dest.w = q1.w + q2.w; + return dest; + } + static product(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + const q1x = q1.x; + const q1y = q1.y; + const q1z = q1.z; + const q1w = q1.w; + const q2x = q2.x; + const q2y = q2.y; + const q2z = q2.z; + const q2w = q2.w; + dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; + dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; + dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; + dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + return dest; + } + static cross(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + const q1x = q1.x; + const q1y = q1.y; + const q1z = q1.z; + const q1w = q1.w; + const q2x = q2.x; + const q2y = q2.y; + const q2z = q2.z; + const q2w = q2.w; + dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x; + dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y; + dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z; + return dest; + } + static shortMix(q1, q2, time, dest) { + if (!dest) { + dest = new quat(); + } + if (time <= 0.0) { + dest.xyzw = q1.xyzw; + return dest; + } + else if (time >= 1.0) { + dest.xyzw = q2.xyzw; + return dest; + } + let cos = quat.dot(q1, q2); + const q2a = q2.copy(); + if (cos < 0.0) { + q2a.inverse(); + cos = -cos; + } + let k0; + let k1; + if (cos > 0.9999) { + k0 = 1 - time; + k1 = 0 + time; + } + else { + const sin = Math.sqrt(1 - cos * cos); + const angle = Math.atan2(sin, cos); + const oneOverSin = 1 / sin; + k0 = Math.sin((1 - time) * angle) * oneOverSin; + k1 = Math.sin((0 + time) * angle) * oneOverSin; + } + dest.x = k0 * q1.x + k1 * q2a.x; + dest.y = k0 * q1.y + k1 * q2a.y; + dest.z = k0 * q1.z + k1 * q2a.z; + dest.w = k0 * q1.w + k1 * q2a.w; + return dest; + } + static mix(q1, q2, time, dest) { + if (!dest) { + dest = new quat(); + } + const cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + if (Math.abs(cosHalfTheta) >= 1.0) { + dest.xyzw = q1.xyzw; + return dest; + } + const halfTheta = Math.acos(cosHalfTheta); + const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + if (Math.abs(sinHalfTheta) < 0.001) { + dest.x = q1.x * 0.5 + q2.x * 0.5; + dest.y = q1.y * 0.5 + q2.y * 0.5; + dest.z = q1.z * 0.5 + q2.z * 0.5; + dest.w = q1.w * 0.5 + q2.w * 0.5; + return dest; + } + const ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta; + const ratioB = Math.sin(time * halfTheta) / sinHalfTheta; + dest.x = q1.x * ratioA + q2.x * ratioB; + dest.y = q1.y * ratioA + q2.y * ratioB; + dest.z = q1.z * ratioA + q2.z * ratioB; + dest.w = q1.w * ratioA + q2.w * ratioB; + return dest; + } + static fromAxisAngle(axis, angle, dest) { + if (!dest) { + dest = new quat(); + } + angle *= 0.5; + const sin = Math.sin(angle); + dest.x = axis.x * sin; + dest.y = axis.y * sin; + dest.z = axis.z * sin; + dest.w = Math.cos(angle); + return dest; + } +} +quat.identity = new quat().setIdentity(); diff --git a/src/framework/resonator/vendor/tsm/tsm.d.ts b/framework/resonator/vendor/tsm/tsm.d.ts similarity index 95% rename from src/framework/resonator/vendor/tsm/tsm.d.ts rename to framework/resonator/vendor/tsm/tsm.d.ts index 4fcfb6d..280aeee 100644 --- a/src/framework/resonator/vendor/tsm/tsm.d.ts +++ b/framework/resonator/vendor/tsm/tsm.d.ts @@ -1,17 +1,17 @@ -import mat2 from './mat2'; -import mat3 from './mat3'; -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -import vec4 from './vec4'; -declare const _default: { - vec2: typeof vec2; - vec3: typeof vec3; - vec4: typeof vec4; - mat2: typeof mat2; - mat3: typeof mat3; - mat4: typeof mat4; - quat: typeof quat; -}; -export default _default; +import mat2 from './mat2'; +import mat3 from './mat3'; +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import vec4 from './vec4'; +declare const _default: { + vec2: typeof vec2; + vec3: typeof vec3; + vec4: typeof vec4; + mat2: typeof mat2; + mat3: typeof mat3; + mat4: typeof mat4; + quat: typeof quat; +}; +export default _default; diff --git a/src/framework/resonator/vendor/tsm/tsm.js b/framework/resonator/vendor/tsm/tsm.js similarity index 96% rename from src/framework/resonator/vendor/tsm/tsm.js rename to framework/resonator/vendor/tsm/tsm.js index def6504..91cceb3 100644 --- a/src/framework/resonator/vendor/tsm/tsm.js +++ b/framework/resonator/vendor/tsm/tsm.js @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2012, 2018 Matthias Ferch - * - * Project homepage: https://github.com/matthiasferch/tsm - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - */ -import mat2 from './mat2'; -import mat3 from './mat3'; -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -import vec4 from './vec4'; -export default { - vec2, - vec3, - vec4, - mat2, - mat3, - mat4, - quat -}; +/* + * Copyright (c) 2012, 2018 Matthias Ferch + * + * Project homepage: https://github.com/matthiasferch/tsm + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ +import mat2 from './mat2'; +import mat3 from './mat3'; +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import vec4 from './vec4'; +export default { + vec2, + vec3, + vec4, + mat2, + mat3, + mat4, + quat +}; diff --git a/src/framework/tsm/vec2.d.ts b/framework/resonator/vendor/tsm/vec2.d.ts similarity index 97% rename from src/framework/tsm/vec2.d.ts rename to framework/resonator/vendor/tsm/vec2.d.ts index 34a2e50..c7af680 100644 --- a/src/framework/tsm/vec2.d.ts +++ b/framework/resonator/vendor/tsm/vec2.d.ts @@ -1,40 +1,40 @@ -import mat2 from './mat2'; -import mat3 from './mat3'; -import vec3 from './vec3'; -export default class vec2 { - get x(): number; - get y(): number; - get xy(): [number, number]; - set x(value: number); - set y(value: number); - set xy(values: [number, number]); - constructor(values?: [number, number]); - private values; - static readonly zero: vec2; - static readonly one: vec2; - at(index: number): number; - reset(): void; - copy(dest?: vec2): vec2; - negate(dest?: vec2): vec2; - equals(vector: vec2, threshold?: number): boolean; - length(): number; - squaredLength(): number; - add(vector: vec2): vec2; - subtract(vector: vec2): vec2; - multiply(vector: vec2): vec2; - divide(vector: vec2): vec2; - scale(value: number, dest?: vec2): vec2; - normalize(dest?: vec2): vec2; - multiplyMat2(matrix: mat2, dest?: vec2): vec2; - multiplyMat3(matrix: mat3, dest?: vec2): vec2; - static cross(vector: vec2, vector2: vec2, dest?: vec3): vec3; - static dot(vector: vec2, vector2: vec2): number; - static distance(vector: vec2, vector2: vec2): number; - static squaredDistance(vector: vec2, vector2: vec2): number; - static direction(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static mix(vector: vec2, vector2: vec2, time: number, dest?: vec2): vec2; - static sum(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static difference(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static product(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static quotient(vector: vec2, vector2: vec2, dest?: vec2): vec2; -} +import mat2 from './mat2'; +import mat3 from './mat3'; +import vec3 from './vec3'; +export default class vec2 { + get x(): number; + get y(): number; + get xy(): [number, number]; + set x(value: number); + set y(value: number); + set xy(values: [number, number]); + constructor(values?: [number, number]); + private values; + static readonly zero: vec2; + static readonly one: vec2; + at(index: number): number; + reset(): void; + copy(dest?: vec2): vec2; + negate(dest?: vec2): vec2; + equals(vector: vec2, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec2): vec2; + subtract(vector: vec2): vec2; + multiply(vector: vec2): vec2; + divide(vector: vec2): vec2; + scale(value: number, dest?: vec2): vec2; + normalize(dest?: vec2): vec2; + multiplyMat2(matrix: mat2, dest?: vec2): vec2; + multiplyMat3(matrix: mat3, dest?: vec2): vec2; + static cross(vector: vec2, vector2: vec2, dest?: vec3): vec3; + static dot(vector: vec2, vector2: vec2): number; + static distance(vector: vec2, vector2: vec2): number; + static squaredDistance(vector: vec2, vector2: vec2): number; + static direction(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static mix(vector: vec2, vector2: vec2, time: number, dest?: vec2): vec2; + static sum(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static difference(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static product(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static quotient(vector: vec2, vector2: vec2, dest?: vec2): vec2; +} diff --git a/src/framework/tsm/vec2.js b/framework/resonator/vendor/tsm/vec2.js similarity index 95% rename from src/framework/tsm/vec2.js rename to framework/resonator/vendor/tsm/vec2.js index 598afdc..f319a69 100644 --- a/src/framework/tsm/vec2.js +++ b/framework/resonator/vendor/tsm/vec2.js @@ -1,215 +1,215 @@ -import vec3 from './vec3'; -import { epsilon } from './constants'; -export default class vec2 { - constructor(values) { - this.values = new Float32Array(2); - if (values !== undefined) { - this.xy = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - at(index) { - return this.values[index]; - } - reset() { - this.x = 0; - this.y = 0; - } - copy(dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = this.x; - dest.y = this.y; - return dest; - } - negate(dest) { - if (!dest) { - dest = this; - } - dest.x = -this.x; - dest.y = -this.y; - return dest; - } - equals(vector, threshold = epsilon) { - if (Math.abs(this.x - vector.x) > threshold) { - return false; - } - if (Math.abs(this.y - vector.y) > threshold) { - return false; - } - return true; - } - length() { - return Math.sqrt(this.squaredLength()); - } - squaredLength() { - const x = this.x; - const y = this.y; - return x * x + y * y; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - return this; - } - subtract(vector) { - this.x -= vector.x; - this.y -= vector.y; - return this; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - return this; - } - divide(vector) { - this.x /= vector.x; - this.y /= vector.y; - return this; - } - scale(value, dest) { - if (!dest) { - dest = this; - } - dest.x *= value; - dest.y *= value; - return dest; - } - normalize(dest) { - if (!dest) { - dest = this; - } - let length = this.length(); - if (length === 1) { - return this; - } - if (length === 0) { - dest.x = 0; - dest.y = 0; - return dest; - } - length = 1.0 / length; - dest.x *= length; - dest.y *= length; - return dest; - } - multiplyMat2(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec2(this, dest); - } - multiplyMat3(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec2(this, dest); - } - static cross(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x; - const y = vector.y; - const x2 = vector2.x; - const y2 = vector2.y; - const z = x * y2 - y * x2; - dest.x = 0; - dest.y = 0; - dest.z = z; - return dest; - } - static dot(vector, vector2) { - return vector.x * vector2.x + vector.y * vector2.y; - } - static distance(vector, vector2) { - return Math.sqrt(this.squaredDistance(vector, vector2)); - } - static squaredDistance(vector, vector2) { - const x = vector2.x - vector.x; - const y = vector2.y - vector.y; - return x * x + y * y; - } - static direction(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - const x = vector.x - vector2.x; - const y = vector.y - vector2.y; - let length = Math.sqrt(x * x + y * y); - if (length === 0) { - dest.x = 0; - dest.y = 0; - return dest; - } - length = 1 / length; - dest.x = x * length; - dest.y = y * length; - return dest; - } - static mix(vector, vector2, time, dest) { - if (!dest) { - dest = new vec2(); - } - const x = vector.x; - const y = vector.y; - const x2 = vector2.x; - const y2 = vector2.y; - dest.x = x + time * (x2 - x); - dest.y = y + time * (y2 - y); - return dest; - } - static sum(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x + vector2.x; - dest.y = vector.y + vector2.y; - return dest; - } - static difference(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x - vector2.x; - dest.y = vector.y - vector2.y; - return dest; - } - static product(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x * vector2.x; - dest.y = vector.y * vector2.y; - return dest; - } - static quotient(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x / vector2.x; - dest.y = vector.y / vector2.y; - return dest; - } -} -vec2.zero = new vec2([0, 0]); -vec2.one = new vec2([1, 1]); +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class vec2 { + constructor(values) { + this.values = new Float32Array(2); + if (values !== undefined) { + this.xy = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + } + copy(dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = this.x; + dest.y = this.y; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + return x * x + y * y; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x = 0; + dest.y = 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + return dest; + } + multiplyMat2(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec2(this, dest); + } + multiplyMat3(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec2(this, dest); + } + static cross(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const x2 = vector2.x; + const y2 = vector2.y; + const z = x * y2 - y * x2; + dest.x = 0; + dest.y = 0; + dest.z = z; + return dest; + } + static dot(vector, vector2) { + return vector.x * vector2.x + vector.y * vector2.y; + } + static distance(vector, vector2) { + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + static squaredDistance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + return x * x + y * y; + } + static direction(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + const x = vector.x - vector2.x; + const y = vector.y - vector2.y; + let length = Math.sqrt(x * x + y * y); + if (length === 0) { + dest.x = 0; + dest.y = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + return dest; + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec2(); + } + const x = vector.x; + const y = vector.y; + const x2 = vector2.x; + const y2 = vector2.y; + dest.x = x + time * (x2 - x); + dest.y = y + time * (y2 - y); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + return dest; + } +} +vec2.zero = new vec2([0, 0]); +vec2.one = new vec2([1, 1]); diff --git a/src/framework/tsm/vec3.d.ts b/framework/resonator/vendor/tsm/vec3.d.ts similarity index 97% rename from src/framework/tsm/vec3.d.ts rename to framework/resonator/vendor/tsm/vec3.d.ts index 900889a..2fb4873 100644 --- a/src/framework/tsm/vec3.d.ts +++ b/framework/resonator/vendor/tsm/vec3.d.ts @@ -1,47 +1,47 @@ -import mat3 from './mat3'; -import quat from './quat'; -export default class vec3 { - get x(): number; - get y(): number; - get z(): number; - get xy(): [number, number]; - get xyz(): [number, number, number]; - set x(value: number); - set y(value: number); - set z(value: number); - set xy(values: [number, number]); - set xyz(values: [number, number, number]); - constructor(values?: [number, number, number]); - private values; - static readonly zero: vec3; - static readonly one: vec3; - static readonly up: vec3; - static readonly right: vec3; - static readonly forward: vec3; - at(index: number): number; - reset(): void; - copy(dest?: vec3): vec3; - negate(dest?: vec3): vec3; - equals(vector: vec3, threshold?: number): boolean; - length(): number; - squaredLength(): number; - add(vector: vec3): vec3; - subtract(vector: vec3): vec3; - multiply(vector: vec3): vec3; - divide(vector: vec3): vec3; - scale(value: number, dest?: vec3): vec3; - normalize(dest?: vec3): vec3; - multiplyByMat3(matrix: mat3, dest?: vec3): vec3; - multiplyByQuat(quaternion: quat, dest?: vec3): vec3; - toQuat(dest?: quat): quat; - static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static dot(vector: vec3, vector2: vec3): number; - static distance(vector: vec3, vector2: vec3): number; - static squaredDistance(vector: vec3, vector2: vec3): number; - static direction(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static mix(vector: vec3, vector2: vec3, time: number, dest?: vec3): vec3; - static sum(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static difference(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static product(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3; -} +import mat3 from './mat3'; +import quat from './quat'; +export default class vec3 { + get x(): number; + get y(): number; + get z(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + constructor(values?: [number, number, number]); + private values; + static readonly zero: vec3; + static readonly one: vec3; + static readonly up: vec3; + static readonly right: vec3; + static readonly forward: vec3; + at(index: number): number; + reset(): void; + copy(dest?: vec3): vec3; + negate(dest?: vec3): vec3; + equals(vector: vec3, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec3): vec3; + subtract(vector: vec3): vec3; + multiply(vector: vec3): vec3; + divide(vector: vec3): vec3; + scale(value: number, dest?: vec3): vec3; + normalize(dest?: vec3): vec3; + multiplyByMat3(matrix: mat3, dest?: vec3): vec3; + multiplyByQuat(quaternion: quat, dest?: vec3): vec3; + toQuat(dest?: quat): quat; + static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static dot(vector: vec3, vector2: vec3): number; + static distance(vector: vec3, vector2: vec3): number; + static squaredDistance(vector: vec3, vector2: vec3): number; + static direction(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static mix(vector: vec3, vector2: vec3, time: number, dest?: vec3): vec3; + static sum(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static difference(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static product(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3; +} diff --git a/src/framework/tsm/vec3.js b/framework/resonator/vendor/tsm/vec3.js similarity index 96% rename from src/framework/tsm/vec3.js rename to framework/resonator/vendor/tsm/vec3.js index 26b6b21..7d8de70 100644 --- a/src/framework/tsm/vec3.js +++ b/framework/resonator/vendor/tsm/vec3.js @@ -1,279 +1,279 @@ -import quat from './quat'; -import { epsilon } from './constants'; -export default class vec3 { - constructor(values) { - this.values = new Float32Array(3); - if (values !== undefined) { - this.xyz = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get z() { - return this.values[2]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - get xyz() { - return [this.values[0], this.values[1], this.values[2]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set z(value) { - this.values[2] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set xyz(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - at(index) { - return this.values[index]; - } - reset() { - this.x = 0; - this.y = 0; - this.z = 0; - } - copy(dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = this.x; - dest.y = this.y; - dest.z = this.z; - return dest; - } - negate(dest) { - if (!dest) { - dest = this; - } - dest.x = -this.x; - dest.y = -this.y; - dest.z = -this.z; - return dest; - } - equals(vector, threshold = epsilon) { - if (Math.abs(this.x - vector.x) > threshold) { - return false; - } - if (Math.abs(this.y - vector.y) > threshold) { - return false; - } - if (Math.abs(this.z - vector.z) > threshold) { - return false; - } - return true; - } - length() { - return Math.sqrt(this.squaredLength()); - } - squaredLength() { - const x = this.x; - const y = this.y; - const z = this.z; - return x * x + y * y + z * z; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - this.z += vector.z; - return this; - } - subtract(vector) { - this.x -= vector.x; - this.y -= vector.y; - this.z -= vector.z; - return this; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - this.z *= vector.z; - return this; - } - divide(vector) { - this.x /= vector.x; - this.y /= vector.y; - this.z /= vector.z; - return this; - } - scale(value, dest) { - if (!dest) { - dest = this; - } - dest.x *= value; - dest.y *= value; - dest.z *= value; - return dest; - } - normalize(dest) { - if (!dest) { - dest = this; - } - let length = this.length(); - if (length === 1) { - return this; - } - if (length === 0) { - dest.x = 0; - dest.y = 0; - dest.z = 0; - return dest; - } - length = 1.0 / length; - dest.x *= length; - dest.y *= length; - dest.z *= length; - return dest; - } - multiplyByMat3(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec3(this, dest); - } - multiplyByQuat(quaternion, dest) { - if (!dest) { - dest = this; - } - return quaternion.multiplyVec3(this, dest); - } - toQuat(dest) { - if (!dest) { - dest = new quat(); - } - const c = new vec3(); - const s = new vec3(); - c.x = Math.cos(this.x * 0.5); - s.x = Math.sin(this.x * 0.5); - c.y = Math.cos(this.y * 0.5); - s.y = Math.sin(this.y * 0.5); - c.z = Math.cos(this.z * 0.5); - s.z = Math.sin(this.z * 0.5); - dest.x = s.x * c.y * c.z - c.x * s.y * s.z; - dest.y = c.x * s.y * c.z + s.x * c.y * s.z; - dest.z = c.x * c.y * s.z - s.x * s.y * c.z; - dest.w = c.x * c.y * c.z + s.x * s.y * s.z; - return dest; - } - static cross(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x; - const y = vector.y; - const z = vector.z; - const x2 = vector2.x; - const y2 = vector2.y; - const z2 = vector2.z; - dest.x = y * z2 - z * y2; - dest.y = z * x2 - x * z2; - dest.z = x * y2 - y * x2; - return dest; - } - static dot(vector, vector2) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - const x2 = vector2.x; - const y2 = vector2.y; - const z2 = vector2.z; - return x * x2 + y * y2 + z * z2; - } - static distance(vector, vector2) { - const x = vector2.x - vector.x; - const y = vector2.y - vector.y; - const z = vector2.z - vector.z; - return Math.sqrt(this.squaredDistance(vector, vector2)); - } - static squaredDistance(vector, vector2) { - const x = vector2.x - vector.x; - const y = vector2.y - vector.y; - const z = vector2.z - vector.z; - return x * x + y * y + z * z; - } - static direction(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x - vector2.x; - const y = vector.y - vector2.y; - const z = vector.z - vector2.z; - let length = Math.sqrt(x * x + y * y + z * z); - if (length === 0) { - dest.x = 0; - dest.y = 0; - dest.z = 0; - return dest; - } - length = 1 / length; - dest.x = x * length; - dest.y = y * length; - dest.z = z * length; - return dest; - } - static mix(vector, vector2, time, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x + time * (vector2.x - vector.x); - dest.y = vector.y + time * (vector2.y - vector.y); - dest.z = vector.z + time * (vector2.z - vector.z); - return dest; - } - static sum(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x + vector2.x; - dest.y = vector.y + vector2.y; - dest.z = vector.z + vector2.z; - return dest; - } - static difference(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x - vector2.x; - dest.y = vector.y - vector2.y; - dest.z = vector.z - vector2.z; - return dest; - } - static product(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x * vector2.x; - dest.y = vector.y * vector2.y; - dest.z = vector.z * vector2.z; - return dest; - } - static quotient(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x / vector2.x; - dest.y = vector.y / vector2.y; - dest.z = vector.z / vector2.z; - return dest; - } -} -vec3.zero = new vec3([0, 0, 0]); -vec3.one = new vec3([1, 1, 1]); -vec3.up = new vec3([0, 1, 0]); -vec3.right = new vec3([1, 0, 0]); -vec3.forward = new vec3([0, 0, 1]); +import quat from './quat'; +import { epsilon } from './constants'; +export default class vec3 { + constructor(values) { + this.values = new Float32Array(3); + if (values !== undefined) { + this.xyz = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + this.z = 0; + } + copy(dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + dest.z = -this.z; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + if (Math.abs(this.z - vector.z) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + const z = this.z; + return x * x + y * y + z * z; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + this.z /= vector.z; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + dest.z *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + dest.z *= length; + return dest; + } + multiplyByMat3(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec3(this, dest); + } + multiplyByQuat(quaternion, dest) { + if (!dest) { + dest = this; + } + return quaternion.multiplyVec3(this, dest); + } + toQuat(dest) { + if (!dest) { + dest = new quat(); + } + const c = new vec3(); + const s = new vec3(); + c.x = Math.cos(this.x * 0.5); + s.x = Math.sin(this.x * 0.5); + c.y = Math.cos(this.y * 0.5); + s.y = Math.sin(this.y * 0.5); + c.z = Math.cos(this.z * 0.5); + s.z = Math.sin(this.z * 0.5); + dest.x = s.x * c.y * c.z - c.x * s.y * s.z; + dest.y = c.x * s.y * c.z + s.x * c.y * s.z; + dest.z = c.x * c.y * s.z - s.x * s.y * c.z; + dest.w = c.x * c.y * c.z + s.x * s.y * s.z; + return dest; + } + static cross(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const x2 = vector2.x; + const y2 = vector2.y; + const z2 = vector2.z; + dest.x = y * z2 - z * y2; + dest.y = z * x2 - x * z2; + dest.z = x * y2 - y * x2; + return dest; + } + static dot(vector, vector2) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + const x2 = vector2.x; + const y2 = vector2.y; + const z2 = vector2.z; + return x * x2 + y * y2 + z * z2; + } + static distance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + const z = vector2.z - vector.z; + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + static squaredDistance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + const z = vector2.z - vector.z; + return x * x + y * y + z * z; + } + static direction(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x - vector2.x; + const y = vector.y - vector2.y; + const z = vector.z - vector2.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (length === 0) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + dest.z = z * length; + return dest; + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x + time * (vector2.x - vector.x); + dest.y = vector.y + time * (vector2.y - vector.y); + dest.z = vector.z + time * (vector2.z - vector.z); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + dest.z = vector.z + vector2.z; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + dest.z = vector.z - vector2.z; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + dest.z = vector.z * vector2.z; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + dest.z = vector.z / vector2.z; + return dest; + } +} +vec3.zero = new vec3([0, 0, 0]); +vec3.one = new vec3([1, 1, 1]); +vec3.up = new vec3([0, 1, 0]); +vec3.right = new vec3([1, 0, 0]); +vec3.forward = new vec3([0, 0, 1]); diff --git a/src/framework/resonator/vendor/tsm/vec4.d.ts b/framework/resonator/vendor/tsm/vec4.d.ts similarity index 97% rename from src/framework/resonator/vendor/tsm/vec4.d.ts rename to framework/resonator/vendor/tsm/vec4.d.ts index 35366a8..42de7df 100644 --- a/src/framework/resonator/vendor/tsm/vec4.d.ts +++ b/framework/resonator/vendor/tsm/vec4.d.ts @@ -1,54 +1,54 @@ -import mat4 from './mat4'; -export default class vec4 { - get x(): number; - get y(): number; - get z(): number; - get w(): number; - get xy(): [number, number]; - get xyz(): [number, number, number]; - get xyzw(): [number, number, number, number]; - set x(value: number); - set y(value: number); - set z(value: number); - set w(value: number); - set xy(values: [number, number]); - set xyz(values: [number, number, number]); - set xyzw(values: [number, number, number, number]); - get r(): number; - get g(): number; - get b(): number; - get a(): number; - get rg(): [number, number]; - get rgb(): [number, number, number]; - get rgba(): [number, number, number, number]; - set r(value: number); - set g(value: number); - set b(value: number); - set a(value: number); - set rg(values: [number, number]); - set rgb(values: [number, number, number]); - set rgba(values: [number, number, number, number]); - constructor(values?: [number, number, number, number]); - private values; - static readonly zero: vec4; - static readonly one: vec4; - at(index: number): number; - reset(): void; - copy(dest?: vec4): vec4; - negate(dest?: vec4): vec4; - equals(vector: vec4, threshold?: number): boolean; - length(): number; - squaredLength(): number; - add(vector: vec4): vec4; - subtract(vector: vec4): vec4; - multiply(vector: vec4): vec4; - divide(vector: vec4): vec4; - scale(value: number, dest?: vec4): vec4; - normalize(dest?: vec4): vec4; - multiplyMat4(matrix: mat4, dest?: vec4): vec4; - static mix(vector: vec4, vector2: vec4, time: number, dest?: vec4): vec4; - static sum(vector: vec4, vector2: vec4, dest?: vec4): vec4; - static difference(vector: vec4, vector2: vec4, dest?: vec4): vec4; - static product(vector: vec4, vector2: vec4, dest?: vec4): vec4; - static quotient(vector: vec4, vector2: vec4, dest?: vec4): vec4; -} +import mat4 from './mat4'; +export default class vec4 { + get x(): number; + get y(): number; + get z(): number; + get w(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + get xyzw(): [number, number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set w(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + set xyzw(values: [number, number, number, number]); + get r(): number; + get g(): number; + get b(): number; + get a(): number; + get rg(): [number, number]; + get rgb(): [number, number, number]; + get rgba(): [number, number, number, number]; + set r(value: number); + set g(value: number); + set b(value: number); + set a(value: number); + set rg(values: [number, number]); + set rgb(values: [number, number, number]); + set rgba(values: [number, number, number, number]); + constructor(values?: [number, number, number, number]); + private values; + static readonly zero: vec4; + static readonly one: vec4; + at(index: number): number; + reset(): void; + copy(dest?: vec4): vec4; + negate(dest?: vec4): vec4; + equals(vector: vec4, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec4): vec4; + subtract(vector: vec4): vec4; + multiply(vector: vec4): vec4; + divide(vector: vec4): vec4; + scale(value: number, dest?: vec4): vec4; + normalize(dest?: vec4): vec4; + multiplyMat4(matrix: mat4, dest?: vec4): vec4; + static mix(vector: vec4, vector2: vec4, time: number, dest?: vec4): vec4; + static sum(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static difference(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static product(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static quotient(vector: vec4, vector2: vec4, dest?: vec4): vec4; +} diff --git a/src/framework/resonator/vendor/tsm/vec4.js b/framework/resonator/vendor/tsm/vec4.js similarity index 96% rename from src/framework/resonator/vendor/tsm/vec4.js rename to framework/resonator/vendor/tsm/vec4.js index fd0337d..16723e7 100644 --- a/src/framework/resonator/vendor/tsm/vec4.js +++ b/framework/resonator/vendor/tsm/vec4.js @@ -1,277 +1,277 @@ -import { epsilon } from './constants'; -export default class vec4 { - constructor(values) { - this.values = new Float32Array(4); - if (values !== undefined) { - this.xyzw = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get z() { - return this.values[2]; - } - get w() { - return this.values[3]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - get xyz() { - return [this.values[0], this.values[1], this.values[2]]; - } - get xyzw() { - return [this.values[0], this.values[1], this.values[2], this.values[3]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set z(value) { - this.values[2] = value; - } - set w(value) { - this.values[3] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set xyz(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - set xyzw(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - this.values[3] = values[3]; - } - get r() { - return this.values[0]; - } - get g() { - return this.values[1]; - } - get b() { - return this.values[2]; - } - get a() { - return this.values[3]; - } - get rg() { - return [this.values[0], this.values[1]]; - } - get rgb() { - return [this.values[0], this.values[1], this.values[2]]; - } - get rgba() { - return [this.values[0], this.values[1], this.values[2], this.values[3]]; - } - set r(value) { - this.values[0] = value; - } - set g(value) { - this.values[1] = value; - } - set b(value) { - this.values[2] = value; - } - set a(value) { - this.values[3] = value; - } - set rg(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set rgb(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - set rgba(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - this.values[3] = values[3]; - } - at(index) { - return this.values[index]; - } - reset() { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 0; - } - copy(dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = this.x; - dest.y = this.y; - dest.z = this.z; - dest.w = this.w; - return dest; - } - negate(dest) { - if (!dest) { - dest = this; - } - dest.x = -this.x; - dest.y = -this.y; - dest.z = -this.z; - dest.w = -this.w; - return dest; - } - equals(vector, threshold = epsilon) { - if (Math.abs(this.x - vector.x) > threshold) { - return false; - } - if (Math.abs(this.y - vector.y) > threshold) { - return false; - } - if (Math.abs(this.z - vector.z) > threshold) { - return false; - } - if (Math.abs(this.w - vector.w) > threshold) { - return false; - } - return true; - } - length() { - return Math.sqrt(this.squaredLength()); - } - squaredLength() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return x * x + y * y + z * z + w * w; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - this.z += vector.z; - this.w += vector.w; - return this; - } - subtract(vector) { - this.x -= vector.x; - this.y -= vector.y; - this.z -= vector.z; - this.w -= vector.w; - return this; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - this.z *= vector.z; - this.w *= vector.w; - return this; - } - divide(vector) { - this.x /= vector.x; - this.y /= vector.y; - this.z /= vector.z; - this.w /= vector.w; - return this; - } - scale(value, dest) { - if (!dest) { - dest = this; - } - dest.x *= value; - dest.y *= value; - dest.z *= value; - dest.w *= value; - return dest; - } - normalize(dest) { - if (!dest) { - dest = this; - } - let length = this.length(); - if (length === 1) { - return this; - } - if (length === 0) { - dest.x *= 0; - dest.y *= 0; - dest.z *= 0; - dest.w *= 0; - return dest; - } - length = 1.0 / length; - dest.x *= length; - dest.y *= length; - dest.z *= length; - dest.w *= length; - return dest; - } - multiplyMat4(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec4(this, dest); - } - static mix(vector, vector2, time, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x + time * (vector2.x - vector.x); - dest.y = vector.y + time * (vector2.y - vector.y); - dest.z = vector.z + time * (vector2.z - vector.z); - dest.w = vector.w + time * (vector2.w - vector.w); - return dest; - } - static sum(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x + vector2.x; - dest.y = vector.y + vector2.y; - dest.z = vector.z + vector2.z; - dest.w = vector.w + vector2.w; - return dest; - } - static difference(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x - vector2.x; - dest.y = vector.y - vector2.y; - dest.z = vector.z - vector2.z; - dest.w = vector.w - vector2.w; - return dest; - } - static product(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x * vector2.x; - dest.y = vector.y * vector2.y; - dest.z = vector.z * vector2.z; - dest.w = vector.w * vector2.w; - return dest; - } - static quotient(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x / vector2.x; - dest.y = vector.y / vector2.y; - dest.z = vector.z / vector2.z; - dest.w = vector.w / vector2.w; - return dest; - } -} -vec4.zero = new vec4([0, 0, 0, 1]); -vec4.one = new vec4([1, 1, 1, 1]); +import { epsilon } from './constants'; +export default class vec4 { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.xyzw = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get w() { + return this.values[3]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + get xyzw() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set w(value) { + this.values[3] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set xyzw(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + get r() { + return this.values[0]; + } + get g() { + return this.values[1]; + } + get b() { + return this.values[2]; + } + get a() { + return this.values[3]; + } + get rg() { + return [this.values[0], this.values[1]]; + } + get rgb() { + return [this.values[0], this.values[1], this.values[2]]; + } + get rgba() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set r(value) { + this.values[0] = value; + } + set g(value) { + this.values[1] = value; + } + set b(value) { + this.values[2] = value; + } + set a(value) { + this.values[3] = value; + } + set rg(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set rgb(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set rgba(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + } + copy(dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + dest.w = this.w; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + dest.z = -this.z; + dest.w = -this.w; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + if (Math.abs(this.z - vector.z) > threshold) { + return false; + } + if (Math.abs(this.w - vector.w) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return x * x + y * y + z * z + w * w; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + this.w += vector.w; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + this.w -= vector.w; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + this.w *= vector.w; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + this.z /= vector.z; + this.w /= vector.w; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + dest.z *= value; + dest.w *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x *= 0; + dest.y *= 0; + dest.z *= 0; + dest.w *= 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + dest.z *= length; + dest.w *= length; + return dest; + } + multiplyMat4(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec4(this, dest); + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x + time * (vector2.x - vector.x); + dest.y = vector.y + time * (vector2.y - vector.y); + dest.z = vector.z + time * (vector2.z - vector.z); + dest.w = vector.w + time * (vector2.w - vector.w); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + dest.z = vector.z + vector2.z; + dest.w = vector.w + vector2.w; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + dest.z = vector.z - vector2.z; + dest.w = vector.w - vector2.w; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + dest.z = vector.z * vector2.z; + dest.w = vector.w * vector2.w; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + dest.z = vector.z / vector2.z; + dest.w = vector.w / vector2.w; + return dest; + } +} +vec4.zero = new vec4([0, 0, 0, 1]); +vec4.one = new vec4([1, 1, 1, 1]); diff --git a/framework/scene/index.d.ts b/framework/scene/index.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/framework/scene/index.js b/framework/scene/index.js new file mode 100644 index 0000000..e69de29 diff --git a/framework/scene/manager.d.ts b/framework/scene/manager.d.ts new file mode 100644 index 0000000..70aef6f --- /dev/null +++ b/framework/scene/manager.d.ts @@ -0,0 +1,12 @@ +import { Scene } from './scene'; +export declare class SceneManager { + scenes: Map; + currentScene: Scene; + defaultScene: Scene; + constructor(); + init(): void; + addScene(scene: Scene): void; + removeScene(scene: Scene): void; + switchTo(scene: Scene): void; + setDefaultScene(scene: Scene): void; +} diff --git a/framework/scene/manager.js b/framework/scene/manager.js new file mode 100644 index 0000000..662760e --- /dev/null +++ b/framework/scene/manager.js @@ -0,0 +1,33 @@ +export class SceneManager { + constructor() { + this.scenes = new Map(); + } + init() { + if (this.defaultScene) { + this.switchTo(this.defaultScene); + } + } + addScene(scene) { + this.scenes.set(scene.id, scene); + } + removeScene(scene) { + if (scene === this.currentScene) + this.currentScene.onDeactivate(); + this.scenes.delete(scene.id); + } + switchTo(scene) { + if (scene === this.currentScene) + return; + let data; + if (this.currentScene) { + this.currentScene.onDeactivate(); + data = this.currentScene.data; + } + this.currentScene = this.scenes.get(scene.id); + this.currentScene.onSwitch(data); + this.currentScene.onActivate(this); + } + setDefaultScene(scene) { + this.defaultScene = scene; + } +} diff --git a/framework/scene/scene.d.ts b/framework/scene/scene.d.ts new file mode 100644 index 0000000..dabfcff --- /dev/null +++ b/framework/scene/scene.d.ts @@ -0,0 +1,10 @@ +import { SceneManager } from './manager'; +export interface Scene { + id: string; + data: any; + onActivate(manager: SceneManager): any; + onDeactivate(): any; + onSwitch(data: any): any; + update(dt: number): any; + updateDraw(): any; +} diff --git a/framework/scene/scene.js b/framework/scene/scene.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/scene/scene.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/scheduler/index.d.ts b/framework/scheduler/index.d.ts new file mode 100644 index 0000000..b977d06 --- /dev/null +++ b/framework/scheduler/index.d.ts @@ -0,0 +1,12 @@ +import { EventBus } from '../event-bus'; +import { RAFTimer } from './raf'; +import { Timer } from './timer'; +export declare class Scheduler extends EventBus { + logicPerSecond: number; + logicTimer: Timer; + drawTimer: RAFTimer; + constructor(logicPerSecond: number); + init(): void; + start(): void; + stop(): void; +} diff --git a/framework/scheduler/index.js b/framework/scheduler/index.js new file mode 100644 index 0000000..1c61b16 --- /dev/null +++ b/framework/scheduler/index.js @@ -0,0 +1,37 @@ +import { EventBus } from '../event-bus'; +import { RAFTimer } from './raf'; +import { Timer } from './timer'; +export class Scheduler extends EventBus { + constructor(logicPerSecond) { + super(); + this.logicPerSecond = logicPerSecond; + this.init(); + } + init() { + const interval = 1000 / this.logicPerSecond; + this.logicTimer = new Timer(interval, { + id: 0, + func: (dt) => { + this.emit('preupdate.logic'); + this.emit('update.logic', dt); + this.emit('postupdate.logic'); + } + }); + this.drawTimer = new RAFTimer({ + id: 1, + func: (dt) => { + this.emit('preupdate.draw'); + this.emit('update.draw', dt); + this.emit('postupdate.draw'); + } + }); + } + start() { + this.logicTimer.start(); + this.drawTimer.start(); + } + stop() { + this.logicTimer.stop(); + this.drawTimer.stop(); + } +} diff --git a/framework/scheduler/node.d.ts b/framework/scheduler/node.d.ts new file mode 100644 index 0000000..3c534b4 --- /dev/null +++ b/framework/scheduler/node.d.ts @@ -0,0 +1,4 @@ +export interface SchedulerNode { + id: number; + func: Function; +} diff --git a/framework/scheduler/node.js b/framework/scheduler/node.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/scheduler/node.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/scheduler/raf.d.ts b/framework/scheduler/raf.d.ts new file mode 100644 index 0000000..d6dfc93 --- /dev/null +++ b/framework/scheduler/raf.d.ts @@ -0,0 +1,10 @@ +import { SchedulerNode } from './node'; +export declare class RAFTimer { + isStarted: boolean; + node: SchedulerNode; + constructor(node: SchedulerNode); + start(): void; + stop(): void; + schedule(): void; + handleResolve(): void; +} diff --git a/framework/scheduler/raf.js b/framework/scheduler/raf.js new file mode 100644 index 0000000..75fc4b2 --- /dev/null +++ b/framework/scheduler/raf.js @@ -0,0 +1,24 @@ +export class RAFTimer { + constructor(node) { + this.isStarted = false; + this.node = node; + } + start() { + this.isStarted = true; + this.schedule(); + } + stop() { + this.isStarted = false; + } + schedule() { + window.requestAnimationFrame(this.handleResolve.bind(this)); + } + handleResolve() { + if (this.node) { + this.node.func(1); + if (this.isStarted) { + this.schedule(); + } + } + } +} diff --git a/framework/scheduler/scheduler-node.d.ts b/framework/scheduler/scheduler-node.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/framework/scheduler/scheduler-node.js b/framework/scheduler/scheduler-node.js new file mode 100644 index 0000000..e69de29 diff --git a/framework/scheduler/timer.d.ts b/framework/scheduler/timer.d.ts new file mode 100644 index 0000000..b36b9f8 --- /dev/null +++ b/framework/scheduler/timer.d.ts @@ -0,0 +1,14 @@ +import { SchedulerNode } from './node'; +export declare class Timer { + time: number; + lastTime: number; + fluctuation: number; + node: SchedulerNode; + isStarted: boolean; + intervalID: number; + constructor(time: number, node: SchedulerNode); + start(): void; + stop(): void; + schedule(): void; + handleResolve(): void; +} diff --git a/framework/scheduler/timer.js b/framework/scheduler/timer.js new file mode 100644 index 0000000..8c0ec99 --- /dev/null +++ b/framework/scheduler/timer.js @@ -0,0 +1,39 @@ +export class Timer { + constructor(time, node) { + this.time = time; + this.node = node; + this.isStarted = false; + } + start() { + this.isStarted = true; + this.schedule(); + } + stop() { + if (this.isStarted) { + if (this.intervalID) { + clearTimeout(this.intervalID); + this.intervalID = null; + this.isStarted = false; + } + } + } + schedule() { + let toWait = this.time; + if (this.lastTime) { + const fluc = Date.now() - this.lastTime; + this.fluctuation = fluc; + toWait -= fluc; + } + this.lastTime = Date.now(); + this.intervalID = setTimeout(this.handleResolve.bind(this), toWait); + } + handleResolve() { + this.lastTime = Date.now(); + if (this.node) { + this.node.func(this.time / this.lastTime); + } + if (this.isStarted) { + this.schedule(); + } + } +} diff --git a/src/framework/tsm/constants.d.ts b/framework/tsm/constants.d.ts similarity index 97% rename from src/framework/tsm/constants.d.ts rename to framework/tsm/constants.d.ts index 4ceaa99..669e322 100644 --- a/src/framework/tsm/constants.d.ts +++ b/framework/tsm/constants.d.ts @@ -1 +1 @@ -export declare const epsilon = 0.00001; +export declare const epsilon = 0.00001; diff --git a/src/framework/tsm/constants.js b/framework/tsm/constants.js similarity index 96% rename from src/framework/tsm/constants.js rename to framework/tsm/constants.js index 347e812..592a1d1 100644 --- a/src/framework/tsm/constants.js +++ b/framework/tsm/constants.js @@ -1 +1 @@ -export const epsilon = 0.00001; +export const epsilon = 0.00001; diff --git a/src/framework/tsm/mat2.d.ts b/framework/tsm/mat2.d.ts similarity index 96% rename from src/framework/tsm/mat2.d.ts rename to framework/tsm/mat2.d.ts index ab03acb..09bd076 100644 --- a/src/framework/tsm/mat2.d.ts +++ b/framework/tsm/mat2.d.ts @@ -1,23 +1,23 @@ -import vec2 from './vec2'; -export default class mat2 { - constructor(values?: number[]); - private values; - static readonly identity: mat2; - at(index: number): number; - init(values: number[]): mat2; - reset(): void; - copy(dest?: mat2): mat2; - all(): number[]; - row(index: number): number[]; - col(index: number): number[]; - equals(matrix: mat2, threshold?: number): boolean; - determinant(): number; - setIdentity(): mat2; - transpose(): mat2; - inverse(): mat2; - multiply(matrix: mat2): mat2; - rotate(angle: number): mat2; - multiplyVec2(vector: vec2, result: vec2): vec2; - scale(vector: vec2): mat2; - static product(m1: mat2, m2: mat2, result: mat2): mat2; -} +import vec2 from './vec2'; +export default class mat2 { + constructor(values?: number[]); + private values; + static readonly identity: mat2; + at(index: number): number; + init(values: number[]): mat2; + reset(): void; + copy(dest?: mat2): mat2; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat2, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat2; + transpose(): mat2; + inverse(): mat2; + multiply(matrix: mat2): mat2; + rotate(angle: number): mat2; + multiplyVec2(vector: vec2, result: vec2): vec2; + scale(vector: vec2): mat2; + static product(m1: mat2, m2: mat2, result: mat2): mat2; +} diff --git a/src/framework/tsm/mat2.js b/framework/tsm/mat2.js similarity index 96% rename from src/framework/tsm/mat2.js rename to framework/tsm/mat2.js index e67db94..a1ac925 100644 --- a/src/framework/tsm/mat2.js +++ b/framework/tsm/mat2.js @@ -1,161 +1,161 @@ -import vec2 from './vec2'; -import { epsilon } from './constants'; -export default class mat2 { - constructor(values) { - this.values = new Float32Array(4); - if (values !== undefined) { - this.init(values); - } - } - at(index) { - return this.values[index]; - } - init(values) { - for (let i = 0; i < 4; i++) { - this.values[i] = values[i]; - } - return this; - } - reset() { - for (let i = 0; i < 4; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new mat2(); - } - for (let i = 0; i < 4; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - all() { - const data = []; - for (let i = 0; i < 4; i++) { - data[i] = this.values[i]; - } - return data; - } - row(index) { - return [this.values[index * 2 + 0], this.values[index * 2 + 1]]; - } - col(index) { - return [this.values[index], this.values[index + 2]]; - } - equals(matrix, threshold = epsilon) { - for (let i = 0; i < 4; i++) { - if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { - return false; - } - } - return true; - } - determinant() { - return this.values[0] * this.values[3] - this.values[2] * this.values[1]; - } - setIdentity() { - this.values[0] = 1; - this.values[1] = 0; - this.values[2] = 0; - this.values[3] = 1; - return this; - } - transpose() { - const temp = this.values[1]; - this.values[1] = this.values[2]; - this.values[2] = temp; - return this; - } - inverse() { - let det = this.determinant(); - if (!det) { - return null; - } - det = 1.0 / det; - const a11 = this.values[0]; - this.values[0] = det * this.values[3]; - this.values[1] = det * -this.values[1]; - this.values[2] = det * -this.values[2]; - this.values[3] = det * a11; - return this; - } - multiply(matrix) { - const a11 = this.values[0]; - const a12 = this.values[1]; - const a21 = this.values[2]; - const a22 = this.values[3]; - this.values[0] = a11 * matrix.at(0) + a12 * matrix.at(2); - this.values[1] = a11 * matrix.at(1) + a12 * matrix.at(3); - this.values[2] = a21 * matrix.at(0) + a22 * matrix.at(2); - this.values[3] = a21 * matrix.at(1) + a22 * matrix.at(3); - return this; - } - rotate(angle) { - const a11 = this.values[0]; - const a12 = this.values[1]; - const a21 = this.values[2]; - const a22 = this.values[3]; - const sin = Math.sin(angle); - const cos = Math.cos(angle); - this.values[0] = a11 * cos + a12 * sin; - this.values[1] = a11 * -sin + a12 * cos; - this.values[2] = a21 * cos + a22 * sin; - this.values[3] = a21 * -sin + a22 * cos; - return this; - } - multiplyVec2(vector, result) { - const x = vector.x; - const y = vector.y; - if (result) { - result.xy = [ - x * this.values[0] + y * this.values[1], - x * this.values[2] + y * this.values[3] - ]; - return result; - } - else { - return new vec2([ - x * this.values[0] + y * this.values[1], - x * this.values[2] + y * this.values[3] - ]); - } - } - scale(vector) { - const a11 = this.values[0]; - const a12 = this.values[1]; - const a21 = this.values[2]; - const a22 = this.values[3]; - const x = vector.x; - const y = vector.y; - this.values[0] = a11 * x; - this.values[1] = a12 * y; - this.values[2] = a21 * x; - this.values[3] = a22 * y; - return this; - } - static product(m1, m2, result) { - const a11 = m1.at(0); - const a12 = m1.at(1); - const a21 = m1.at(2); - const a22 = m1.at(3); - if (result) { - result.init([ - a11 * m2.at(0) + a12 * m2.at(2), - a11 * m2.at(1) + a12 * m2.at(3), - a21 * m2.at(0) + a22 * m2.at(2), - a21 * m2.at(1) + a22 * m2.at(3) - ]); - return result; - } - else { - return new mat2([ - a11 * m2.at(0) + a12 * m2.at(2), - a11 * m2.at(1) + a12 * m2.at(3), - a21 * m2.at(0) + a22 * m2.at(2), - a21 * m2.at(1) + a22 * m2.at(3) - ]); - } - } -} -mat2.identity = new mat2().setIdentity(); +import vec2 from './vec2'; +import { epsilon } from './constants'; +export default class mat2 { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 4; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 4; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat2(); + } + for (let i = 0; i < 4; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 4; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [this.values[index * 2 + 0], this.values[index * 2 + 1]]; + } + col(index) { + return [this.values[index], this.values[index + 2]]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 4; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + return this.values[0] * this.values[3] - this.values[2] * this.values[1]; + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 1; + return this; + } + transpose() { + const temp = this.values[1]; + this.values[1] = this.values[2]; + this.values[2] = temp; + return this; + } + inverse() { + let det = this.determinant(); + if (!det) { + return null; + } + det = 1.0 / det; + const a11 = this.values[0]; + this.values[0] = det * this.values[3]; + this.values[1] = det * -this.values[1]; + this.values[2] = det * -this.values[2]; + this.values[3] = det * a11; + return this; + } + multiply(matrix) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + this.values[0] = a11 * matrix.at(0) + a12 * matrix.at(2); + this.values[1] = a11 * matrix.at(1) + a12 * matrix.at(3); + this.values[2] = a21 * matrix.at(0) + a22 * matrix.at(2); + this.values[3] = a21 * matrix.at(1) + a22 * matrix.at(3); + return this; + } + rotate(angle) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + const sin = Math.sin(angle); + const cos = Math.cos(angle); + this.values[0] = a11 * cos + a12 * sin; + this.values[1] = a11 * -sin + a12 * cos; + this.values[2] = a21 * cos + a22 * sin; + this.values[3] = a21 * -sin + a22 * cos; + return this; + } + multiplyVec2(vector, result) { + const x = vector.x; + const y = vector.y; + if (result) { + result.xy = [ + x * this.values[0] + y * this.values[1], + x * this.values[2] + y * this.values[3] + ]; + return result; + } + else { + return new vec2([ + x * this.values[0] + y * this.values[1], + x * this.values[2] + y * this.values[3] + ]); + } + } + scale(vector) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + const x = vector.x; + const y = vector.y; + this.values[0] = a11 * x; + this.values[1] = a12 * y; + this.values[2] = a21 * x; + this.values[3] = a22 * y; + return this; + } + static product(m1, m2, result) { + const a11 = m1.at(0); + const a12 = m1.at(1); + const a21 = m1.at(2); + const a22 = m1.at(3); + if (result) { + result.init([ + a11 * m2.at(0) + a12 * m2.at(2), + a11 * m2.at(1) + a12 * m2.at(3), + a21 * m2.at(0) + a22 * m2.at(2), + a21 * m2.at(1) + a22 * m2.at(3) + ]); + return result; + } + else { + return new mat2([ + a11 * m2.at(0) + a12 * m2.at(2), + a11 * m2.at(1) + a12 * m2.at(3), + a21 * m2.at(0) + a22 * m2.at(2), + a21 * m2.at(1) + a22 * m2.at(3) + ]); + } + } +} +mat2.identity = new mat2().setIdentity(); diff --git a/src/framework/resonator/vendor/tsm/mat3.d.ts b/framework/tsm/mat3.d.ts similarity index 96% rename from src/framework/resonator/vendor/tsm/mat3.d.ts rename to framework/tsm/mat3.d.ts index 03bf323..3df4b3e 100644 --- a/src/framework/resonator/vendor/tsm/mat3.d.ts +++ b/framework/tsm/mat3.d.ts @@ -1,28 +1,28 @@ -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -export default class mat3 { - constructor(values?: number[]); - private values; - static readonly identity: mat3; - at(index: number): number; - init(values: number[]): mat3; - reset(): void; - copy(dest?: mat3): mat3; - all(): number[]; - row(index: number): number[]; - col(index: number): number[]; - equals(matrix: mat3, threshold?: number): boolean; - determinant(): number; - setIdentity(): mat3; - transpose(): mat3; - inverse(): mat3; - multiply(matrix: mat3): mat3; - multiplyVec2(vector: vec2, result: vec2): vec2; - multiplyVec3(vector: vec3, result: vec3): vec3; - toMat4(result: mat4): mat4; - toQuat(): quat; - rotate(angle: number, axis: vec3): mat3; - static product(m1: mat3, m2: mat3, result: mat3): mat3; -} +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +export default class mat3 { + constructor(values?: number[]); + private values; + static readonly identity: mat3; + at(index: number): number; + init(values: number[]): mat3; + reset(): void; + copy(dest?: mat3): mat3; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat3, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat3; + transpose(): mat3; + inverse(): mat3; + multiply(matrix: mat3): mat3; + multiplyVec2(vector: vec2, result: vec2): vec2; + multiplyVec3(vector: vec3, result: vec3): vec3; + toMat4(result: mat4): mat4; + toQuat(): quat; + rotate(angle: number, axis: vec3): mat3; + static product(m1: mat3, m2: mat3, result: mat3): mat3; +} diff --git a/src/framework/tsm/mat3.js b/framework/tsm/mat3.js similarity index 97% rename from src/framework/tsm/mat3.js rename to framework/tsm/mat3.js index 76e31b5..2359a3c 100644 --- a/src/framework/tsm/mat3.js +++ b/framework/tsm/mat3.js @@ -1,392 +1,392 @@ -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -import { epsilon } from './constants'; -export default class mat3 { - constructor(values) { - this.values = new Float32Array(9); - if (values !== undefined) { - this.init(values); - } - } - at(index) { - return this.values[index]; - } - init(values) { - for (let i = 0; i < 9; i++) { - this.values[i] = values[i]; - } - return this; - } - reset() { - for (let i = 0; i < 9; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new mat3(); - } - for (let i = 0; i < 9; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - all() { - const data = []; - for (let i = 0; i < 9; i++) { - data[i] = this.values[i]; - } - return data; - } - row(index) { - return [ - this.values[index * 3 + 0], - this.values[index * 3 + 1], - this.values[index * 3 + 2] - ]; - } - col(index) { - return [this.values[index], this.values[index + 3], this.values[index + 6]]; - } - equals(matrix, threshold = epsilon) { - for (let i = 0; i < 9; i++) { - if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { - return false; - } - } - return true; - } - determinant() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[3]; - const a11 = this.values[4]; - const a12 = this.values[5]; - const a20 = this.values[6]; - const a21 = this.values[7]; - const a22 = this.values[8]; - const det01 = a22 * a11 - a12 * a21; - const det11 = -a22 * a10 + a12 * a20; - const det21 = a21 * a10 - a11 * a20; - return a00 * det01 + a01 * det11 + a02 * det21; - } - setIdentity() { - this.values[0] = 1; - this.values[1] = 0; - this.values[2] = 0; - this.values[3] = 0; - this.values[4] = 1; - this.values[5] = 0; - this.values[6] = 0; - this.values[7] = 0; - this.values[8] = 1; - return this; - } - transpose() { - const temp01 = this.values[1]; - const temp02 = this.values[2]; - const temp12 = this.values[5]; - this.values[1] = this.values[3]; - this.values[2] = this.values[6]; - this.values[3] = temp01; - this.values[5] = this.values[7]; - this.values[6] = temp02; - this.values[7] = temp12; - return this; - } - inverse() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[3]; - const a11 = this.values[4]; - const a12 = this.values[5]; - const a20 = this.values[6]; - const a21 = this.values[7]; - const a22 = this.values[8]; - const det01 = a22 * a11 - a12 * a21; - const det11 = -a22 * a10 + a12 * a20; - const det21 = a21 * a10 - a11 * a20; - let det = a00 * det01 + a01 * det11 + a02 * det21; - if (!det) { - return null; - } - det = 1.0 / det; - this.values[0] = det01 * det; - this.values[1] = (-a22 * a01 + a02 * a21) * det; - this.values[2] = (a12 * a01 - a02 * a11) * det; - this.values[3] = det11 * det; - this.values[4] = (a22 * a00 - a02 * a20) * det; - this.values[5] = (-a12 * a00 + a02 * a10) * det; - this.values[6] = det21 * det; - this.values[7] = (-a21 * a00 + a01 * a20) * det; - this.values[8] = (a11 * a00 - a01 * a10) * det; - return this; - } - multiply(matrix) { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[3]; - const a11 = this.values[4]; - const a12 = this.values[5]; - const a20 = this.values[6]; - const a21 = this.values[7]; - const a22 = this.values[8]; - const b00 = matrix.at(0); - const b01 = matrix.at(1); - const b02 = matrix.at(2); - const b10 = matrix.at(3); - const b11 = matrix.at(4); - const b12 = matrix.at(5); - const b20 = matrix.at(6); - const b21 = matrix.at(7); - const b22 = matrix.at(8); - this.values[0] = b00 * a00 + b01 * a10 + b02 * a20; - this.values[1] = b00 * a01 + b01 * a11 + b02 * a21; - this.values[2] = b00 * a02 + b01 * a12 + b02 * a22; - this.values[3] = b10 * a00 + b11 * a10 + b12 * a20; - this.values[4] = b10 * a01 + b11 * a11 + b12 * a21; - this.values[5] = b10 * a02 + b11 * a12 + b12 * a22; - this.values[6] = b20 * a00 + b21 * a10 + b22 * a20; - this.values[7] = b20 * a01 + b21 * a11 + b22 * a21; - this.values[8] = b20 * a02 + b21 * a12 + b22 * a22; - return this; - } - multiplyVec2(vector, result) { - const x = vector.x; - const y = vector.y; - if (result) { - result.xy = [ - x * this.values[0] + y * this.values[3] + this.values[6], - x * this.values[1] + y * this.values[4] + this.values[7] - ]; - return result; - } - else { - return new vec2([ - x * this.values[0] + y * this.values[3] + this.values[6], - x * this.values[1] + y * this.values[4] + this.values[7] - ]); - } - } - multiplyVec3(vector, result) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - if (result) { - result.xyz = [ - x * this.values[0] + y * this.values[3] + z * this.values[6], - x * this.values[1] + y * this.values[4] + z * this.values[7], - x * this.values[2] + y * this.values[5] + z * this.values[8] - ]; - return result; - } - else { - return new vec3([ - x * this.values[0] + y * this.values[3] + z * this.values[6], - x * this.values[1] + y * this.values[4] + z * this.values[7], - x * this.values[2] + y * this.values[5] + z * this.values[8] - ]); - } - } - toMat4(result) { - if (result) { - result.init([ - this.values[0], - this.values[1], - this.values[2], - 0, - this.values[3], - this.values[4], - this.values[5], - 0, - this.values[6], - this.values[7], - this.values[8], - 0, - 0, - 0, - 0, - 1 - ]); - return result; - } - else { - return new mat4([ - this.values[0], - this.values[1], - this.values[2], - 0, - this.values[3], - this.values[4], - this.values[5], - 0, - this.values[6], - this.values[7], - this.values[8], - 0, - 0, - 0, - 0, - 1 - ]); - } - } - toQuat() { - const m00 = this.values[0]; - const m01 = this.values[1]; - const m02 = this.values[2]; - const m10 = this.values[3]; - const m11 = this.values[4]; - const m12 = this.values[5]; - const m20 = this.values[6]; - const m21 = this.values[7]; - const m22 = this.values[8]; - const fourXSquaredMinus1 = m00 - m11 - m22; - const fourYSquaredMinus1 = m11 - m00 - m22; - const fourZSquaredMinus1 = m22 - m00 - m11; - const fourWSquaredMinus1 = m00 + m11 + m22; - let biggestIndex = 0; - let fourBiggestSquaredMinus1 = fourWSquaredMinus1; - if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) { - fourBiggestSquaredMinus1 = fourXSquaredMinus1; - biggestIndex = 1; - } - if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) { - fourBiggestSquaredMinus1 = fourYSquaredMinus1; - biggestIndex = 2; - } - if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) { - fourBiggestSquaredMinus1 = fourZSquaredMinus1; - biggestIndex = 3; - } - const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5; - const mult = 0.25 / biggestVal; - const result = new quat(); - switch (biggestIndex) { - case 0: - result.w = biggestVal; - result.x = (m12 - m21) * mult; - result.y = (m20 - m02) * mult; - result.z = (m01 - m10) * mult; - break; - case 1: - result.w = (m12 - m21) * mult; - result.x = biggestVal; - result.y = (m01 + m10) * mult; - result.z = (m20 + m02) * mult; - break; - case 2: - result.w = (m20 - m02) * mult; - result.x = (m01 + m10) * mult; - result.y = biggestVal; - result.z = (m12 + m21) * mult; - break; - case 3: - result.w = (m01 - m10) * mult; - result.x = (m20 + m02) * mult; - result.y = (m12 + m21) * mult; - result.z = biggestVal; - break; - } - return result; - } - rotate(angle, axis) { - let x = axis.x; - let y = axis.y; - let z = axis.z; - let length = Math.sqrt(x * x + y * y + z * z); - if (!length) { - return null; - } - if (length !== 1) { - length = 1 / length; - x *= length; - y *= length; - z *= length; - } - const s = Math.sin(angle); - const c = Math.cos(angle); - const t = 1.0 - c; - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const b00 = x * x * t + c; - const b01 = y * x * t + z * s; - const b02 = z * x * t - y * s; - const b10 = x * y * t - z * s; - const b11 = y * y * t + c; - const b12 = z * y * t + x * s; - const b20 = x * z * t + y * s; - const b21 = y * z * t - x * s; - const b22 = z * z * t + c; - this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; - this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; - this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; - this.values[3] = a00 * b10 + a10 * b11 + a20 * b12; - this.values[4] = a01 * b10 + a11 * b11 + a21 * b12; - this.values[5] = a02 * b10 + a12 * b11 + a22 * b12; - this.values[6] = a00 * b20 + a10 * b21 + a20 * b22; - this.values[7] = a01 * b20 + a11 * b21 + a21 * b22; - this.values[8] = a02 * b20 + a12 * b21 + a22 * b22; - return this; - } - static product(m1, m2, result) { - const a00 = m1.at(0); - const a01 = m1.at(1); - const a02 = m1.at(2); - const a10 = m1.at(3); - const a11 = m1.at(4); - const a12 = m1.at(5); - const a20 = m1.at(6); - const a21 = m1.at(7); - const a22 = m1.at(8); - const b00 = m2.at(0); - const b01 = m2.at(1); - const b02 = m2.at(2); - const b10 = m2.at(3); - const b11 = m2.at(4); - const b12 = m2.at(5); - const b20 = m2.at(6); - const b21 = m2.at(7); - const b22 = m2.at(8); - if (result) { - result.init([ - b00 * a00 + b01 * a10 + b02 * a20, - b00 * a01 + b01 * a11 + b02 * a21, - b00 * a02 + b01 * a12 + b02 * a22, - b10 * a00 + b11 * a10 + b12 * a20, - b10 * a01 + b11 * a11 + b12 * a21, - b10 * a02 + b11 * a12 + b12 * a22, - b20 * a00 + b21 * a10 + b22 * a20, - b20 * a01 + b21 * a11 + b22 * a21, - b20 * a02 + b21 * a12 + b22 * a22 - ]); - return result; - } - else { - return new mat3([ - b00 * a00 + b01 * a10 + b02 * a20, - b00 * a01 + b01 * a11 + b02 * a21, - b00 * a02 + b01 * a12 + b02 * a22, - b10 * a00 + b11 * a10 + b12 * a20, - b10 * a01 + b11 * a11 + b12 * a21, - b10 * a02 + b11 * a12 + b12 * a22, - b20 * a00 + b21 * a10 + b22 * a20, - b20 * a01 + b21 * a11 + b22 * a21, - b20 * a02 + b21 * a12 + b22 * a22 - ]); - } - } -} -mat3.identity = new mat3().setIdentity(); +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class mat3 { + constructor(values) { + this.values = new Float32Array(9); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 9; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 9; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat3(); + } + for (let i = 0; i < 9; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 9; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [ + this.values[index * 3 + 0], + this.values[index * 3 + 1], + this.values[index * 3 + 2] + ]; + } + col(index) { + return [this.values[index], this.values[index + 3], this.values[index + 6]]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 9; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + return a00 * det01 + a01 * det11 + a02 * det21; + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 1; + this.values[5] = 0; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 1; + return this; + } + transpose() { + const temp01 = this.values[1]; + const temp02 = this.values[2]; + const temp12 = this.values[5]; + this.values[1] = this.values[3]; + this.values[2] = this.values[6]; + this.values[3] = temp01; + this.values[5] = this.values[7]; + this.values[6] = temp02; + this.values[7] = temp12; + return this; + } + inverse() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + let det = a00 * det01 + a01 * det11 + a02 * det21; + if (!det) { + return null; + } + det = 1.0 / det; + this.values[0] = det01 * det; + this.values[1] = (-a22 * a01 + a02 * a21) * det; + this.values[2] = (a12 * a01 - a02 * a11) * det; + this.values[3] = det11 * det; + this.values[4] = (a22 * a00 - a02 * a20) * det; + this.values[5] = (-a12 * a00 + a02 * a10) * det; + this.values[6] = det21 * det; + this.values[7] = (-a21 * a00 + a01 * a20) * det; + this.values[8] = (a11 * a00 - a01 * a10) * det; + return this; + } + multiply(matrix) { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const b00 = matrix.at(0); + const b01 = matrix.at(1); + const b02 = matrix.at(2); + const b10 = matrix.at(3); + const b11 = matrix.at(4); + const b12 = matrix.at(5); + const b20 = matrix.at(6); + const b21 = matrix.at(7); + const b22 = matrix.at(8); + this.values[0] = b00 * a00 + b01 * a10 + b02 * a20; + this.values[1] = b00 * a01 + b01 * a11 + b02 * a21; + this.values[2] = b00 * a02 + b01 * a12 + b02 * a22; + this.values[3] = b10 * a00 + b11 * a10 + b12 * a20; + this.values[4] = b10 * a01 + b11 * a11 + b12 * a21; + this.values[5] = b10 * a02 + b11 * a12 + b12 * a22; + this.values[6] = b20 * a00 + b21 * a10 + b22 * a20; + this.values[7] = b20 * a01 + b21 * a11 + b22 * a21; + this.values[8] = b20 * a02 + b21 * a12 + b22 * a22; + return this; + } + multiplyVec2(vector, result) { + const x = vector.x; + const y = vector.y; + if (result) { + result.xy = [ + x * this.values[0] + y * this.values[3] + this.values[6], + x * this.values[1] + y * this.values[4] + this.values[7] + ]; + return result; + } + else { + return new vec2([ + x * this.values[0] + y * this.values[3] + this.values[6], + x * this.values[1] + y * this.values[4] + this.values[7] + ]); + } + } + multiplyVec3(vector, result) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + if (result) { + result.xyz = [ + x * this.values[0] + y * this.values[3] + z * this.values[6], + x * this.values[1] + y * this.values[4] + z * this.values[7], + x * this.values[2] + y * this.values[5] + z * this.values[8] + ]; + return result; + } + else { + return new vec3([ + x * this.values[0] + y * this.values[3] + z * this.values[6], + x * this.values[1] + y * this.values[4] + z * this.values[7], + x * this.values[2] + y * this.values[5] + z * this.values[8] + ]); + } + } + toMat4(result) { + if (result) { + result.init([ + this.values[0], + this.values[1], + this.values[2], + 0, + this.values[3], + this.values[4], + this.values[5], + 0, + this.values[6], + this.values[7], + this.values[8], + 0, + 0, + 0, + 0, + 1 + ]); + return result; + } + else { + return new mat4([ + this.values[0], + this.values[1], + this.values[2], + 0, + this.values[3], + this.values[4], + this.values[5], + 0, + this.values[6], + this.values[7], + this.values[8], + 0, + 0, + 0, + 0, + 1 + ]); + } + } + toQuat() { + const m00 = this.values[0]; + const m01 = this.values[1]; + const m02 = this.values[2]; + const m10 = this.values[3]; + const m11 = this.values[4]; + const m12 = this.values[5]; + const m20 = this.values[6]; + const m21 = this.values[7]; + const m22 = this.values[8]; + const fourXSquaredMinus1 = m00 - m11 - m22; + const fourYSquaredMinus1 = m11 - m00 - m22; + const fourZSquaredMinus1 = m22 - m00 - m11; + const fourWSquaredMinus1 = m00 + m11 + m22; + let biggestIndex = 0; + let fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5; + const mult = 0.25 / biggestVal; + const result = new quat(); + switch (biggestIndex) { + case 0: + result.w = biggestVal; + result.x = (m12 - m21) * mult; + result.y = (m20 - m02) * mult; + result.z = (m01 - m10) * mult; + break; + case 1: + result.w = (m12 - m21) * mult; + result.x = biggestVal; + result.y = (m01 + m10) * mult; + result.z = (m20 + m02) * mult; + break; + case 2: + result.w = (m20 - m02) * mult; + result.x = (m01 + m10) * mult; + result.y = biggestVal; + result.z = (m12 + m21) * mult; + break; + case 3: + result.w = (m01 - m10) * mult; + result.x = (m20 + m02) * mult; + result.y = (m12 + m21) * mult; + result.z = biggestVal; + break; + } + return result; + } + rotate(angle, axis) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (!length) { + return null; + } + if (length !== 1) { + length = 1 / length; + x *= length; + y *= length; + z *= length; + } + const s = Math.sin(angle); + const c = Math.cos(angle); + const t = 1.0 - c; + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const b00 = x * x * t + c; + const b01 = y * x * t + z * s; + const b02 = z * x * t - y * s; + const b10 = x * y * t - z * s; + const b11 = y * y * t + c; + const b12 = z * y * t + x * s; + const b20 = x * z * t + y * s; + const b21 = y * z * t - x * s; + const b22 = z * z * t + c; + this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; + this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; + this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; + this.values[3] = a00 * b10 + a10 * b11 + a20 * b12; + this.values[4] = a01 * b10 + a11 * b11 + a21 * b12; + this.values[5] = a02 * b10 + a12 * b11 + a22 * b12; + this.values[6] = a00 * b20 + a10 * b21 + a20 * b22; + this.values[7] = a01 * b20 + a11 * b21 + a21 * b22; + this.values[8] = a02 * b20 + a12 * b21 + a22 * b22; + return this; + } + static product(m1, m2, result) { + const a00 = m1.at(0); + const a01 = m1.at(1); + const a02 = m1.at(2); + const a10 = m1.at(3); + const a11 = m1.at(4); + const a12 = m1.at(5); + const a20 = m1.at(6); + const a21 = m1.at(7); + const a22 = m1.at(8); + const b00 = m2.at(0); + const b01 = m2.at(1); + const b02 = m2.at(2); + const b10 = m2.at(3); + const b11 = m2.at(4); + const b12 = m2.at(5); + const b20 = m2.at(6); + const b21 = m2.at(7); + const b22 = m2.at(8); + if (result) { + result.init([ + b00 * a00 + b01 * a10 + b02 * a20, + b00 * a01 + b01 * a11 + b02 * a21, + b00 * a02 + b01 * a12 + b02 * a22, + b10 * a00 + b11 * a10 + b12 * a20, + b10 * a01 + b11 * a11 + b12 * a21, + b10 * a02 + b11 * a12 + b12 * a22, + b20 * a00 + b21 * a10 + b22 * a20, + b20 * a01 + b21 * a11 + b22 * a21, + b20 * a02 + b21 * a12 + b22 * a22 + ]); + return result; + } + else { + return new mat3([ + b00 * a00 + b01 * a10 + b02 * a20, + b00 * a01 + b01 * a11 + b02 * a21, + b00 * a02 + b01 * a12 + b02 * a22, + b10 * a00 + b11 * a10 + b12 * a20, + b10 * a01 + b11 * a11 + b12 * a21, + b10 * a02 + b11 * a12 + b12 * a22, + b20 * a00 + b21 * a10 + b22 * a20, + b20 * a01 + b21 * a11 + b22 * a21, + b20 * a02 + b21 * a12 + b22 * a22 + ]); + } + } +} +mat3.identity = new mat3().setIdentity(); diff --git a/src/framework/resonator/vendor/tsm/mat4.d.ts b/framework/tsm/mat4.d.ts similarity index 97% rename from src/framework/resonator/vendor/tsm/mat4.d.ts rename to framework/tsm/mat4.d.ts index 799d9a3..249550d 100644 --- a/src/framework/resonator/vendor/tsm/mat4.d.ts +++ b/framework/tsm/mat4.d.ts @@ -1,33 +1,33 @@ -import mat3 from './mat3'; -import vec3 from './vec3'; -import vec4 from './vec4'; -export default class mat4 { - constructor(values?: number[]); - private values; - static readonly identity: mat4; - at(index: number): number; - init(values: number[]): mat4; - reset(): void; - copy(dest?: mat4): mat4; - all(): number[]; - row(index: number): number[]; - col(index: number): number[]; - equals(matrix: mat4, threshold?: number): boolean; - determinant(): number; - setIdentity(): mat4; - transpose(): mat4; - inverse(): mat4; - multiply(matrix: mat4): mat4; - multiplyVec3(vector: vec3): vec3; - multiplyVec4(vector: vec4, dest?: vec4): vec4; - toMat3(): mat3; - toInverseMat3(): mat3; - translate(vector: vec3): mat4; - scale(vector: vec3): mat4; - rotate(angle: number, axis: vec3): mat4; - static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; - static perspective(fov: number, aspect: number, near: number, far: number): mat4; - static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; - static lookAt(position: vec3, target: vec3, up?: vec3): mat4; - static product(m1: mat4, m2: mat4, result: mat4): mat4; -} +import mat3 from './mat3'; +import vec3 from './vec3'; +import vec4 from './vec4'; +export default class mat4 { + constructor(values?: number[]); + private values; + static readonly identity: mat4; + at(index: number): number; + init(values: number[]): mat4; + reset(): void; + copy(dest?: mat4): mat4; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat4, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat4; + transpose(): mat4; + inverse(): mat4; + multiply(matrix: mat4): mat4; + multiplyVec3(vector: vec3): vec3; + multiplyVec4(vector: vec4, dest?: vec4): vec4; + toMat3(): mat3; + toInverseMat3(): mat3; + translate(vector: vec3): mat4; + scale(vector: vec3): mat4; + rotate(angle: number, axis: vec3): mat4; + static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; + static perspective(fov: number, aspect: number, near: number, far: number): mat4; + static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; + static lookAt(position: vec3, target: vec3, up?: vec3): mat4; + static product(m1: mat4, m2: mat4, result: mat4): mat4; +} diff --git a/src/framework/tsm/mat4.js b/framework/tsm/mat4.js similarity index 97% rename from src/framework/tsm/mat4.js rename to framework/tsm/mat4.js index 1447f4e..b8fb710 100644 --- a/src/framework/tsm/mat4.js +++ b/framework/tsm/mat4.js @@ -1,579 +1,579 @@ -import mat3 from './mat3'; -import vec3 from './vec3'; -import vec4 from './vec4'; -import { epsilon } from './constants'; -export default class mat4 { - constructor(values) { - this.values = new Float32Array(16); - if (values !== undefined) { - this.init(values); - } - } - at(index) { - return this.values[index]; - } - init(values) { - for (let i = 0; i < 16; i++) { - this.values[i] = values[i]; - } - return this; - } - reset() { - for (let i = 0; i < 16; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new mat4(); - } - for (let i = 0; i < 16; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - all() { - const data = []; - for (let i = 0; i < 16; i++) { - data[i] = this.values[i]; - } - return data; - } - row(index) { - return [ - this.values[index * 4 + 0], - this.values[index * 4 + 1], - this.values[index * 4 + 2], - this.values[index * 4 + 3] - ]; - } - col(index) { - return [ - this.values[index], - this.values[index + 4], - this.values[index + 8], - this.values[index + 12] - ]; - } - equals(matrix, threshold = epsilon) { - for (let i = 0; i < 16; i++) { - if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { - return false; - } - } - return true; - } - determinant() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const a30 = this.values[12]; - const a31 = this.values[13]; - const a32 = this.values[14]; - const a33 = this.values[15]; - const det00 = a00 * a11 - a01 * a10; - const det01 = a00 * a12 - a02 * a10; - const det02 = a00 * a13 - a03 * a10; - const det03 = a01 * a12 - a02 * a11; - const det04 = a01 * a13 - a03 * a11; - const det05 = a02 * a13 - a03 * a12; - const det06 = a20 * a31 - a21 * a30; - const det07 = a20 * a32 - a22 * a30; - const det08 = a20 * a33 - a23 * a30; - const det09 = a21 * a32 - a22 * a31; - const det10 = a21 * a33 - a23 * a31; - const det11 = a22 * a33 - a23 * a32; - return (det00 * det11 - - det01 * det10 + - det02 * det09 + - det03 * det08 - - det04 * det07 + - det05 * det06); - } - setIdentity() { - this.values[0] = 1; - this.values[1] = 0; - this.values[2] = 0; - this.values[3] = 0; - this.values[4] = 0; - this.values[5] = 1; - this.values[6] = 0; - this.values[7] = 0; - this.values[8] = 0; - this.values[9] = 0; - this.values[10] = 1; - this.values[11] = 0; - this.values[12] = 0; - this.values[13] = 0; - this.values[14] = 0; - this.values[15] = 1; - return this; - } - transpose() { - const temp01 = this.values[1]; - const temp02 = this.values[2]; - const temp03 = this.values[3]; - const temp12 = this.values[6]; - const temp13 = this.values[7]; - const temp23 = this.values[11]; - this.values[1] = this.values[4]; - this.values[2] = this.values[8]; - this.values[3] = this.values[12]; - this.values[4] = temp01; - this.values[6] = this.values[9]; - this.values[7] = this.values[13]; - this.values[8] = temp02; - this.values[9] = temp12; - this.values[11] = this.values[14]; - this.values[12] = temp03; - this.values[13] = temp13; - this.values[14] = temp23; - return this; - } - inverse() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const a30 = this.values[12]; - const a31 = this.values[13]; - const a32 = this.values[14]; - const a33 = this.values[15]; - const det00 = a00 * a11 - a01 * a10; - const det01 = a00 * a12 - a02 * a10; - const det02 = a00 * a13 - a03 * a10; - const det03 = a01 * a12 - a02 * a11; - const det04 = a01 * a13 - a03 * a11; - const det05 = a02 * a13 - a03 * a12; - const det06 = a20 * a31 - a21 * a30; - const det07 = a20 * a32 - a22 * a30; - const det08 = a20 * a33 - a23 * a30; - const det09 = a21 * a32 - a22 * a31; - const det10 = a21 * a33 - a23 * a31; - const det11 = a22 * a33 - a23 * a32; - let det = det00 * det11 - - det01 * det10 + - det02 * det09 + - det03 * det08 - - det04 * det07 + - det05 * det06; - if (!det) { - return null; - } - det = 1.0 / det; - this.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det; - this.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det; - this.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det; - this.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det; - this.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det; - this.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det; - this.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det; - this.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det; - this.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det; - this.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det; - this.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det; - this.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det; - this.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det; - this.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det; - this.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det; - this.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det; - return this; - } - multiply(matrix) { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const a30 = this.values[12]; - const a31 = this.values[13]; - const a32 = this.values[14]; - const a33 = this.values[15]; - let b0 = matrix.at(0); - let b1 = matrix.at(1); - let b2 = matrix.at(2); - let b3 = matrix.at(3); - this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - b0 = matrix.at(4); - b1 = matrix.at(5); - b2 = matrix.at(6); - b3 = matrix.at(7); - this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - b0 = matrix.at(8); - b1 = matrix.at(9); - b2 = matrix.at(10); - b3 = matrix.at(11); - this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - b0 = matrix.at(12); - b1 = matrix.at(13); - b2 = matrix.at(14); - b3 = matrix.at(15); - this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; - this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; - this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; - this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; - return this; - } - multiplyVec3(vector) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - return new vec3([ - this.values[0] * x + - this.values[4] * y + - this.values[8] * z + - this.values[12], - this.values[1] * x + - this.values[5] * y + - this.values[9] * z + - this.values[13], - this.values[2] * x + - this.values[6] * y + - this.values[10] * z + - this.values[14] - ]); - } - multiplyVec4(vector, dest) { - if (!dest) { - dest = new vec4(); - } - const x = vector.x; - const y = vector.y; - const z = vector.z; - const w = vector.w; - dest.x = - this.values[0] * x + - this.values[4] * y + - this.values[8] * z + - this.values[12] * w; - dest.y = - this.values[1] * x + - this.values[5] * y + - this.values[9] * z + - this.values[13] * w; - dest.z = - this.values[2] * x + - this.values[6] * y + - this.values[10] * z + - this.values[14] * w; - dest.w = - this.values[3] * x + - this.values[7] * y + - this.values[11] * z + - this.values[15] * w; - return dest; - } - toMat3() { - return new mat3([ - this.values[0], - this.values[1], - this.values[2], - this.values[4], - this.values[5], - this.values[6], - this.values[8], - this.values[9], - this.values[10] - ]); - } - toInverseMat3() { - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const det01 = a22 * a11 - a12 * a21; - const det11 = -a22 * a10 + a12 * a20; - const det21 = a21 * a10 - a11 * a20; - let det = a00 * det01 + a01 * det11 + a02 * det21; - if (!det) { - return null; - } - det = 1.0 / det; - return new mat3([ - det01 * det, - (-a22 * a01 + a02 * a21) * det, - (a12 * a01 - a02 * a11) * det, - det11 * det, - (a22 * a00 - a02 * a20) * det, - (-a12 * a00 + a02 * a10) * det, - det21 * det, - (-a21 * a00 + a01 * a20) * det, - (a11 * a00 - a01 * a10) * det - ]); - } - translate(vector) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - this.values[12] += - this.values[0] * x + this.values[4] * y + this.values[8] * z; - this.values[13] += - this.values[1] * x + this.values[5] * y + this.values[9] * z; - this.values[14] += - this.values[2] * x + this.values[6] * y + this.values[10] * z; - this.values[15] += - this.values[3] * x + this.values[7] * y + this.values[11] * z; - return this; - } - scale(vector) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - this.values[0] *= x; - this.values[1] *= x; - this.values[2] *= x; - this.values[3] *= x; - this.values[4] *= y; - this.values[5] *= y; - this.values[6] *= y; - this.values[7] *= y; - this.values[8] *= z; - this.values[9] *= z; - this.values[10] *= z; - this.values[11] *= z; - return this; - } - rotate(angle, axis) { - let x = axis.x; - let y = axis.y; - let z = axis.z; - let length = Math.sqrt(x * x + y * y + z * z); - if (!length) { - return null; - } - if (length !== 1) { - length = 1 / length; - x *= length; - y *= length; - z *= length; - } - const s = Math.sin(angle); - const c = Math.cos(angle); - const t = 1.0 - c; - const a00 = this.values[0]; - const a01 = this.values[1]; - const a02 = this.values[2]; - const a03 = this.values[3]; - const a10 = this.values[4]; - const a11 = this.values[5]; - const a12 = this.values[6]; - const a13 = this.values[7]; - const a20 = this.values[8]; - const a21 = this.values[9]; - const a22 = this.values[10]; - const a23 = this.values[11]; - const b00 = x * x * t + c; - const b01 = y * x * t + z * s; - const b02 = z * x * t - y * s; - const b10 = x * y * t - z * s; - const b11 = y * y * t + c; - const b12 = z * y * t + x * s; - const b20 = x * z * t + y * s; - const b21 = y * z * t - x * s; - const b22 = z * z * t + c; - this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; - this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; - this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; - this.values[3] = a03 * b00 + a13 * b01 + a23 * b02; - this.values[4] = a00 * b10 + a10 * b11 + a20 * b12; - this.values[5] = a01 * b10 + a11 * b11 + a21 * b12; - this.values[6] = a02 * b10 + a12 * b11 + a22 * b12; - this.values[7] = a03 * b10 + a13 * b11 + a23 * b12; - this.values[8] = a00 * b20 + a10 * b21 + a20 * b22; - this.values[9] = a01 * b20 + a11 * b21 + a21 * b22; - this.values[10] = a02 * b20 + a12 * b21 + a22 * b22; - this.values[11] = a03 * b20 + a13 * b21 + a23 * b22; - return this; - } - static frustum(left, right, bottom, top, near, far) { - const rl = right - left; - const tb = top - bottom; - const fn = far - near; - return new mat4([ - (near * 2) / rl, - 0, - 0, - 0, - 0, - (near * 2) / tb, - 0, - 0, - (right + left) / rl, - (top + bottom) / tb, - -(far + near) / fn, - -1, - 0, - 0, - -(far * near * 2) / fn, - 0 - ]); - } - static perspective(fov, aspect, near, far) { - const top = near * Math.tan((fov * Math.PI) / 360.0); - const right = top * aspect; - return mat4.frustum(-right, right, -top, top, near, far); - } - static orthographic(left, right, bottom, top, near, far) { - const rl = right - left; - const tb = top - bottom; - const fn = far - near; - return new mat4([ - 2 / rl, - 0, - 0, - 0, - 0, - 2 / tb, - 0, - 0, - 0, - 0, - -2 / fn, - 0, - -(left + right) / rl, - -(top + bottom) / tb, - -(far + near) / fn, - 1 - ]); - } - static lookAt(position, target, up = vec3.up) { - if (position.equals(target)) { - return this.identity; - } - const z = vec3.difference(position, target).normalize(); - const x = vec3.cross(up, z).normalize(); - const y = vec3.cross(z, x).normalize(); - return new mat4([ - x.x, - y.x, - z.x, - 0, - x.y, - y.y, - z.y, - 0, - x.z, - y.z, - z.z, - 0, - -vec3.dot(x, position), - -vec3.dot(y, position), - -vec3.dot(z, position), - 1 - ]); - } - static product(m1, m2, result) { - const a00 = m1.at(0); - const a01 = m1.at(1); - const a02 = m1.at(2); - const a03 = m1.at(3); - const a10 = m1.at(4); - const a11 = m1.at(5); - const a12 = m1.at(6); - const a13 = m1.at(7); - const a20 = m1.at(8); - const a21 = m1.at(9); - const a22 = m1.at(10); - const a23 = m1.at(11); - const a30 = m1.at(12); - const a31 = m1.at(13); - const a32 = m1.at(14); - const a33 = m1.at(15); - const b00 = m2.at(0); - const b01 = m2.at(1); - const b02 = m2.at(2); - const b03 = m2.at(3); - const b10 = m2.at(4); - const b11 = m2.at(5); - const b12 = m2.at(6); - const b13 = m2.at(7); - const b20 = m2.at(8); - const b21 = m2.at(9); - const b22 = m2.at(10); - const b23 = m2.at(11); - const b30 = m2.at(12); - const b31 = m2.at(13); - const b32 = m2.at(14); - const b33 = m2.at(15); - if (result) { - result.init([ - b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, - b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, - b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, - b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, - b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, - b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, - b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, - b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, - b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, - b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, - b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, - b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, - b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, - b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, - b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, - b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 - ]); - return result; - } - else { - return new mat4([ - b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, - b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, - b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, - b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, - b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, - b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, - b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, - b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, - b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, - b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, - b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, - b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, - b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, - b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, - b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, - b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 - ]); - } - } -} -mat4.identity = new mat4().setIdentity(); +import mat3 from './mat3'; +import vec3 from './vec3'; +import vec4 from './vec4'; +import { epsilon } from './constants'; +export default class mat4 { + constructor(values) { + this.values = new Float32Array(16); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 16; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 16; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat4(); + } + for (let i = 0; i < 16; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 16; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [ + this.values[index * 4 + 0], + this.values[index * 4 + 1], + this.values[index * 4 + 2], + this.values[index * 4 + 3] + ]; + } + col(index) { + return [ + this.values[index], + this.values[index + 4], + this.values[index + 8], + this.values[index + 12] + ]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 16; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + const det00 = a00 * a11 - a01 * a10; + const det01 = a00 * a12 - a02 * a10; + const det02 = a00 * a13 - a03 * a10; + const det03 = a01 * a12 - a02 * a11; + const det04 = a01 * a13 - a03 * a11; + const det05 = a02 * a13 - a03 * a12; + const det06 = a20 * a31 - a21 * a30; + const det07 = a20 * a32 - a22 * a30; + const det08 = a20 * a33 - a23 * a30; + const det09 = a21 * a32 - a22 * a31; + const det10 = a21 * a33 - a23 * a31; + const det11 = a22 * a33 - a23 * a32; + return (det00 * det11 - + det01 * det10 + + det02 * det09 + + det03 * det08 - + det04 * det07 + + det05 * det06); + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 0; + this.values[5] = 1; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 0; + this.values[9] = 0; + this.values[10] = 1; + this.values[11] = 0; + this.values[12] = 0; + this.values[13] = 0; + this.values[14] = 0; + this.values[15] = 1; + return this; + } + transpose() { + const temp01 = this.values[1]; + const temp02 = this.values[2]; + const temp03 = this.values[3]; + const temp12 = this.values[6]; + const temp13 = this.values[7]; + const temp23 = this.values[11]; + this.values[1] = this.values[4]; + this.values[2] = this.values[8]; + this.values[3] = this.values[12]; + this.values[4] = temp01; + this.values[6] = this.values[9]; + this.values[7] = this.values[13]; + this.values[8] = temp02; + this.values[9] = temp12; + this.values[11] = this.values[14]; + this.values[12] = temp03; + this.values[13] = temp13; + this.values[14] = temp23; + return this; + } + inverse() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + const det00 = a00 * a11 - a01 * a10; + const det01 = a00 * a12 - a02 * a10; + const det02 = a00 * a13 - a03 * a10; + const det03 = a01 * a12 - a02 * a11; + const det04 = a01 * a13 - a03 * a11; + const det05 = a02 * a13 - a03 * a12; + const det06 = a20 * a31 - a21 * a30; + const det07 = a20 * a32 - a22 * a30; + const det08 = a20 * a33 - a23 * a30; + const det09 = a21 * a32 - a22 * a31; + const det10 = a21 * a33 - a23 * a31; + const det11 = a22 * a33 - a23 * a32; + let det = det00 * det11 - + det01 * det10 + + det02 * det09 + + det03 * det08 - + det04 * det07 + + det05 * det06; + if (!det) { + return null; + } + det = 1.0 / det; + this.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det; + this.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det; + this.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det; + this.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det; + this.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det; + this.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det; + this.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det; + this.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det; + this.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det; + this.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det; + this.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det; + this.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det; + this.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det; + this.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det; + this.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det; + this.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det; + return this; + } + multiply(matrix) { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + let b0 = matrix.at(0); + let b1 = matrix.at(1); + let b2 = matrix.at(2); + let b3 = matrix.at(3); + this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(4); + b1 = matrix.at(5); + b2 = matrix.at(6); + b3 = matrix.at(7); + this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(8); + b1 = matrix.at(9); + b2 = matrix.at(10); + b3 = matrix.at(11); + this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(12); + b1 = matrix.at(13); + b2 = matrix.at(14); + b3 = matrix.at(15); + this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + return this; + } + multiplyVec3(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + return new vec3([ + this.values[0] * x + + this.values[4] * y + + this.values[8] * z + + this.values[12], + this.values[1] * x + + this.values[5] * y + + this.values[9] * z + + this.values[13], + this.values[2] * x + + this.values[6] * y + + this.values[10] * z + + this.values[14] + ]); + } + multiplyVec4(vector, dest) { + if (!dest) { + dest = new vec4(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const w = vector.w; + dest.x = + this.values[0] * x + + this.values[4] * y + + this.values[8] * z + + this.values[12] * w; + dest.y = + this.values[1] * x + + this.values[5] * y + + this.values[9] * z + + this.values[13] * w; + dest.z = + this.values[2] * x + + this.values[6] * y + + this.values[10] * z + + this.values[14] * w; + dest.w = + this.values[3] * x + + this.values[7] * y + + this.values[11] * z + + this.values[15] * w; + return dest; + } + toMat3() { + return new mat3([ + this.values[0], + this.values[1], + this.values[2], + this.values[4], + this.values[5], + this.values[6], + this.values[8], + this.values[9], + this.values[10] + ]); + } + toInverseMat3() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + let det = a00 * det01 + a01 * det11 + a02 * det21; + if (!det) { + return null; + } + det = 1.0 / det; + return new mat3([ + det01 * det, + (-a22 * a01 + a02 * a21) * det, + (a12 * a01 - a02 * a11) * det, + det11 * det, + (a22 * a00 - a02 * a20) * det, + (-a12 * a00 + a02 * a10) * det, + det21 * det, + (-a21 * a00 + a01 * a20) * det, + (a11 * a00 - a01 * a10) * det + ]); + } + translate(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + this.values[12] += + this.values[0] * x + this.values[4] * y + this.values[8] * z; + this.values[13] += + this.values[1] * x + this.values[5] * y + this.values[9] * z; + this.values[14] += + this.values[2] * x + this.values[6] * y + this.values[10] * z; + this.values[15] += + this.values[3] * x + this.values[7] * y + this.values[11] * z; + return this; + } + scale(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + this.values[0] *= x; + this.values[1] *= x; + this.values[2] *= x; + this.values[3] *= x; + this.values[4] *= y; + this.values[5] *= y; + this.values[6] *= y; + this.values[7] *= y; + this.values[8] *= z; + this.values[9] *= z; + this.values[10] *= z; + this.values[11] *= z; + return this; + } + rotate(angle, axis) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (!length) { + return null; + } + if (length !== 1) { + length = 1 / length; + x *= length; + y *= length; + z *= length; + } + const s = Math.sin(angle); + const c = Math.cos(angle); + const t = 1.0 - c; + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const b00 = x * x * t + c; + const b01 = y * x * t + z * s; + const b02 = z * x * t - y * s; + const b10 = x * y * t - z * s; + const b11 = y * y * t + c; + const b12 = z * y * t + x * s; + const b20 = x * z * t + y * s; + const b21 = y * z * t - x * s; + const b22 = z * z * t + c; + this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; + this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; + this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; + this.values[3] = a03 * b00 + a13 * b01 + a23 * b02; + this.values[4] = a00 * b10 + a10 * b11 + a20 * b12; + this.values[5] = a01 * b10 + a11 * b11 + a21 * b12; + this.values[6] = a02 * b10 + a12 * b11 + a22 * b12; + this.values[7] = a03 * b10 + a13 * b11 + a23 * b12; + this.values[8] = a00 * b20 + a10 * b21 + a20 * b22; + this.values[9] = a01 * b20 + a11 * b21 + a21 * b22; + this.values[10] = a02 * b20 + a12 * b21 + a22 * b22; + this.values[11] = a03 * b20 + a13 * b21 + a23 * b22; + return this; + } + static frustum(left, right, bottom, top, near, far) { + const rl = right - left; + const tb = top - bottom; + const fn = far - near; + return new mat4([ + (near * 2) / rl, + 0, + 0, + 0, + 0, + (near * 2) / tb, + 0, + 0, + (right + left) / rl, + (top + bottom) / tb, + -(far + near) / fn, + -1, + 0, + 0, + -(far * near * 2) / fn, + 0 + ]); + } + static perspective(fov, aspect, near, far) { + const top = near * Math.tan((fov * Math.PI) / 360.0); + const right = top * aspect; + return mat4.frustum(-right, right, -top, top, near, far); + } + static orthographic(left, right, bottom, top, near, far) { + const rl = right - left; + const tb = top - bottom; + const fn = far - near; + return new mat4([ + 2 / rl, + 0, + 0, + 0, + 0, + 2 / tb, + 0, + 0, + 0, + 0, + -2 / fn, + 0, + -(left + right) / rl, + -(top + bottom) / tb, + -(far + near) / fn, + 1 + ]); + } + static lookAt(position, target, up = vec3.up) { + if (position.equals(target)) { + return this.identity; + } + const z = vec3.difference(position, target).normalize(); + const x = vec3.cross(up, z).normalize(); + const y = vec3.cross(z, x).normalize(); + return new mat4([ + x.x, + y.x, + z.x, + 0, + x.y, + y.y, + z.y, + 0, + x.z, + y.z, + z.z, + 0, + -vec3.dot(x, position), + -vec3.dot(y, position), + -vec3.dot(z, position), + 1 + ]); + } + static product(m1, m2, result) { + const a00 = m1.at(0); + const a01 = m1.at(1); + const a02 = m1.at(2); + const a03 = m1.at(3); + const a10 = m1.at(4); + const a11 = m1.at(5); + const a12 = m1.at(6); + const a13 = m1.at(7); + const a20 = m1.at(8); + const a21 = m1.at(9); + const a22 = m1.at(10); + const a23 = m1.at(11); + const a30 = m1.at(12); + const a31 = m1.at(13); + const a32 = m1.at(14); + const a33 = m1.at(15); + const b00 = m2.at(0); + const b01 = m2.at(1); + const b02 = m2.at(2); + const b03 = m2.at(3); + const b10 = m2.at(4); + const b11 = m2.at(5); + const b12 = m2.at(6); + const b13 = m2.at(7); + const b20 = m2.at(8); + const b21 = m2.at(9); + const b22 = m2.at(10); + const b23 = m2.at(11); + const b30 = m2.at(12); + const b31 = m2.at(13); + const b32 = m2.at(14); + const b33 = m2.at(15); + if (result) { + result.init([ + b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, + b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, + b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, + b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, + b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, + b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, + b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, + b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, + b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, + b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, + b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, + b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, + b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, + b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, + b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, + b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 + ]); + return result; + } + else { + return new mat4([ + b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, + b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, + b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, + b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, + b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, + b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, + b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, + b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, + b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, + b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, + b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, + b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, + b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, + b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, + b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, + b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 + ]); + } + } +} +mat4.identity = new mat4().setIdentity(); diff --git a/src/framework/tsm/quat.d.ts b/framework/tsm/quat.d.ts similarity index 97% rename from src/framework/tsm/quat.d.ts rename to framework/tsm/quat.d.ts index 1195bfd..b4e9528 100644 --- a/src/framework/tsm/quat.d.ts +++ b/framework/tsm/quat.d.ts @@ -1,47 +1,47 @@ -import mat3 from './mat3'; -import mat4 from './mat4'; -import vec3 from './vec3'; -export default class quat { - get x(): number; - get y(): number; - get z(): number; - get w(): number; - get xy(): [number, number]; - get xyz(): [number, number, number]; - get xyzw(): [number, number, number, number]; - set x(value: number); - set y(value: number); - set z(value: number); - set w(value: number); - set xy(values: [number, number]); - set xyz(values: [number, number, number]); - set xyzw(values: [number, number, number, number]); - constructor(values?: [number, number, number, number]); - private values; - static readonly identity: quat; - at(index: number): number; - reset(): void; - copy(dest?: quat): quat; - roll(): number; - pitch(): number; - yaw(): number; - equals(vector: quat, threshold?: number): boolean; - setIdentity(): quat; - calculateW(): quat; - inverse(): quat; - conjugate(): quat; - length(): number; - normalize(dest?: quat): quat; - add(other: quat): quat; - multiply(other: quat): quat; - multiplyVec3(vector: vec3, dest?: vec3): vec3; - toMat3(dest?: mat3): mat3; - toMat4(dest?: mat4): mat4; - static dot(q1: quat, q2: quat): number; - static sum(q1: quat, q2: quat, dest?: quat): quat; - static product(q1: quat, q2: quat, dest?: quat): quat; - static cross(q1: quat, q2: quat, dest?: quat): quat; - static shortMix(q1: quat, q2: quat, time: number, dest?: quat): quat; - static mix(q1: quat, q2: quat, time: number, dest?: quat): quat; - static fromAxisAngle(axis: vec3, angle: number, dest?: quat): quat; -} +import mat3 from './mat3'; +import mat4 from './mat4'; +import vec3 from './vec3'; +export default class quat { + get x(): number; + get y(): number; + get z(): number; + get w(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + get xyzw(): [number, number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set w(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + set xyzw(values: [number, number, number, number]); + constructor(values?: [number, number, number, number]); + private values; + static readonly identity: quat; + at(index: number): number; + reset(): void; + copy(dest?: quat): quat; + roll(): number; + pitch(): number; + yaw(): number; + equals(vector: quat, threshold?: number): boolean; + setIdentity(): quat; + calculateW(): quat; + inverse(): quat; + conjugate(): quat; + length(): number; + normalize(dest?: quat): quat; + add(other: quat): quat; + multiply(other: quat): quat; + multiplyVec3(vector: vec3, dest?: vec3): vec3; + toMat3(dest?: mat3): mat3; + toMat4(dest?: mat4): mat4; + static dot(q1: quat, q2: quat): number; + static sum(q1: quat, q2: quat, dest?: quat): quat; + static product(q1: quat, q2: quat, dest?: quat): quat; + static cross(q1: quat, q2: quat, dest?: quat): quat; + static shortMix(q1: quat, q2: quat, time: number, dest?: quat): quat; + static mix(q1: quat, q2: quat, time: number, dest?: quat): quat; + static fromAxisAngle(axis: vec3, angle: number, dest?: quat): quat; +} diff --git a/src/framework/resonator/vendor/tsm/quat.js b/framework/tsm/quat.js similarity index 96% rename from src/framework/resonator/vendor/tsm/quat.js rename to framework/tsm/quat.js index 54c43ba..3aabbd4 100644 --- a/src/framework/resonator/vendor/tsm/quat.js +++ b/framework/tsm/quat.js @@ -1,404 +1,404 @@ -import mat3 from './mat3'; -import mat4 from './mat4'; -import vec3 from './vec3'; -import { epsilon } from './constants'; -export default class quat { - constructor(values) { - this.values = new Float32Array(4); - if (values !== undefined) { - this.xyzw = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get z() { - return this.values[2]; - } - get w() { - return this.values[3]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - get xyz() { - return [this.values[0], this.values[1], this.values[2]]; - } - get xyzw() { - return [this.values[0], this.values[1], this.values[2], this.values[3]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set z(value) { - this.values[2] = value; - } - set w(value) { - this.values[3] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set xyz(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - set xyzw(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - this.values[3] = values[3]; - } - at(index) { - return this.values[index]; - } - reset() { - for (let i = 0; i < 4; i++) { - this.values[i] = 0; - } - } - copy(dest) { - if (!dest) { - dest = new quat(); - } - for (let i = 0; i < 4; i++) { - dest.values[i] = this.values[i]; - } - return dest; - } - roll() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z); - } - pitch() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z); - } - yaw() { - return Math.asin(2.0 * (this.x * this.z - this.w * this.y)); - } - equals(vector, threshold = epsilon) { - for (let i = 0; i < 4; i++) { - if (Math.abs(this.values[i] - vector.at(i)) > threshold) { - return false; - } - } - return true; - } - setIdentity() { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 1; - return this; - } - calculateW() { - const x = this.x; - const y = this.y; - const z = this.z; - this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); - return this; - } - inverse() { - const dot = quat.dot(this, this); - if (!dot) { - this.xyzw = [0, 0, 0, 0]; - return this; - } - const invDot = dot ? 1.0 / dot : 0; - this.x *= -invDot; - this.y *= -invDot; - this.z *= -invDot; - this.w *= invDot; - return this; - } - conjugate() { - this.values[0] *= -1; - this.values[1] *= -1; - this.values[2] *= -1; - return this; - } - length() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return Math.sqrt(x * x + y * y + z * z + w * w); - } - normalize(dest) { - if (!dest) { - dest = this; - } - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - let length = Math.sqrt(x * x + y * y + z * z + w * w); - if (!length) { - dest.x = 0; - dest.y = 0; - dest.z = 0; - dest.w = 0; - return dest; - } - length = 1 / length; - dest.x = x * length; - dest.y = y * length; - dest.z = z * length; - dest.w = w * length; - return dest; - } - add(other) { - for (let i = 0; i < 4; i++) { - this.values[i] += other.at(i); - } - return this; - } - multiply(other) { - const q1x = this.values[0]; - const q1y = this.values[1]; - const q1z = this.values[2]; - const q1w = this.values[3]; - const q2x = other.x; - const q2y = other.y; - const q2z = other.z; - const q2w = other.w; - this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; - this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; - this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; - this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; - return this; - } - multiplyVec3(vector, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x; - const y = vector.y; - const z = vector.z; - const qx = this.x; - const qy = this.y; - const qz = this.z; - const qw = this.w; - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = -qx * x - qy * y - qz * z; - dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; - dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; - dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return dest; - } - toMat3(dest) { - if (!dest) { - dest = new mat3(); - } - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - const x2 = x + x; - const y2 = y + y; - const z2 = z + z; - const xx = x * x2; - const xy = x * y2; - const xz = x * z2; - const yy = y * y2; - const yz = y * z2; - const zz = z * z2; - const wx = w * x2; - const wy = w * y2; - const wz = w * z2; - dest.init([ - 1 - (yy + zz), - xy + wz, - xz - wy, - xy - wz, - 1 - (xx + zz), - yz + wx, - xz + wy, - yz - wx, - 1 - (xx + yy) - ]); - return dest; - } - toMat4(dest) { - if (!dest) { - dest = new mat4(); - } - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - const x2 = x + x; - const y2 = y + y; - const z2 = z + z; - const xx = x * x2; - const xy = x * y2; - const xz = x * z2; - const yy = y * y2; - const yz = y * z2; - const zz = z * z2; - const wx = w * x2; - const wy = w * y2; - const wz = w * z2; - dest.init([ - 1 - (yy + zz), - xy + wz, - xz - wy, - 0, - xy - wz, - 1 - (xx + zz), - yz + wx, - 0, - xz + wy, - yz - wx, - 1 - (xx + yy), - 0, - 0, - 0, - 0, - 1 - ]); - return dest; - } - static dot(q1, q2) { - return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - } - static sum(q1, q2, dest) { - if (!dest) { - dest = new quat(); - } - dest.x = q1.x + q2.x; - dest.y = q1.y + q2.y; - dest.z = q1.z + q2.z; - dest.w = q1.w + q2.w; - return dest; - } - static product(q1, q2, dest) { - if (!dest) { - dest = new quat(); - } - const q1x = q1.x; - const q1y = q1.y; - const q1z = q1.z; - const q1w = q1.w; - const q2x = q2.x; - const q2y = q2.y; - const q2z = q2.z; - const q2w = q2.w; - dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; - dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; - dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; - dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; - return dest; - } - static cross(q1, q2, dest) { - if (!dest) { - dest = new quat(); - } - const q1x = q1.x; - const q1y = q1.y; - const q1z = q1.z; - const q1w = q1.w; - const q2x = q2.x; - const q2y = q2.y; - const q2z = q2.z; - const q2w = q2.w; - dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x; - dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; - dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y; - dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z; - return dest; - } - static shortMix(q1, q2, time, dest) { - if (!dest) { - dest = new quat(); - } - if (time <= 0.0) { - dest.xyzw = q1.xyzw; - return dest; - } - else if (time >= 1.0) { - dest.xyzw = q2.xyzw; - return dest; - } - let cos = quat.dot(q1, q2); - const q2a = q2.copy(); - if (cos < 0.0) { - q2a.inverse(); - cos = -cos; - } - let k0; - let k1; - if (cos > 0.9999) { - k0 = 1 - time; - k1 = 0 + time; - } - else { - const sin = Math.sqrt(1 - cos * cos); - const angle = Math.atan2(sin, cos); - const oneOverSin = 1 / sin; - k0 = Math.sin((1 - time) * angle) * oneOverSin; - k1 = Math.sin((0 + time) * angle) * oneOverSin; - } - dest.x = k0 * q1.x + k1 * q2a.x; - dest.y = k0 * q1.y + k1 * q2a.y; - dest.z = k0 * q1.z + k1 * q2a.z; - dest.w = k0 * q1.w + k1 * q2a.w; - return dest; - } - static mix(q1, q2, time, dest) { - if (!dest) { - dest = new quat(); - } - const cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - if (Math.abs(cosHalfTheta) >= 1.0) { - dest.xyzw = q1.xyzw; - return dest; - } - const halfTheta = Math.acos(cosHalfTheta); - const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); - if (Math.abs(sinHalfTheta) < 0.001) { - dest.x = q1.x * 0.5 + q2.x * 0.5; - dest.y = q1.y * 0.5 + q2.y * 0.5; - dest.z = q1.z * 0.5 + q2.z * 0.5; - dest.w = q1.w * 0.5 + q2.w * 0.5; - return dest; - } - const ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta; - const ratioB = Math.sin(time * halfTheta) / sinHalfTheta; - dest.x = q1.x * ratioA + q2.x * ratioB; - dest.y = q1.y * ratioA + q2.y * ratioB; - dest.z = q1.z * ratioA + q2.z * ratioB; - dest.w = q1.w * ratioA + q2.w * ratioB; - return dest; - } - static fromAxisAngle(axis, angle, dest) { - if (!dest) { - dest = new quat(); - } - angle *= 0.5; - const sin = Math.sin(angle); - dest.x = axis.x * sin; - dest.y = axis.y * sin; - dest.z = axis.z * sin; - dest.w = Math.cos(angle); - return dest; - } -} -quat.identity = new quat().setIdentity(); +import mat3 from './mat3'; +import mat4 from './mat4'; +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class quat { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.xyzw = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get w() { + return this.values[3]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + get xyzw() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set w(value) { + this.values[3] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set xyzw(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + at(index) { + return this.values[index]; + } + reset() { + for (let i = 0; i < 4; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new quat(); + } + for (let i = 0; i < 4; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + roll() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z); + } + pitch() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z); + } + yaw() { + return Math.asin(2.0 * (this.x * this.z - this.w * this.y)); + } + equals(vector, threshold = epsilon) { + for (let i = 0; i < 4; i++) { + if (Math.abs(this.values[i] - vector.at(i)) > threshold) { + return false; + } + } + return true; + } + setIdentity() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + return this; + } + calculateW() { + const x = this.x; + const y = this.y; + const z = this.z; + this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return this; + } + inverse() { + const dot = quat.dot(this, this); + if (!dot) { + this.xyzw = [0, 0, 0, 0]; + return this; + } + const invDot = dot ? 1.0 / dot : 0; + this.x *= -invDot; + this.y *= -invDot; + this.z *= -invDot; + this.w *= invDot; + return this; + } + conjugate() { + this.values[0] *= -1; + this.values[1] *= -1; + this.values[2] *= -1; + return this; + } + length() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.sqrt(x * x + y * y + z * z + w * w); + } + normalize(dest) { + if (!dest) { + dest = this; + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + let length = Math.sqrt(x * x + y * y + z * z + w * w); + if (!length) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + dest.w = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + dest.z = z * length; + dest.w = w * length; + return dest; + } + add(other) { + for (let i = 0; i < 4; i++) { + this.values[i] += other.at(i); + } + return this; + } + multiply(other) { + const q1x = this.values[0]; + const q1y = this.values[1]; + const q1z = this.values[2]; + const q1w = this.values[3]; + const q2x = other.x; + const q2y = other.y; + const q2z = other.z; + const q2w = other.w; + this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; + this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; + this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; + this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + return this; + } + multiplyVec3(vector, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const qx = this.x; + const qy = this.y; + const qz = this.z; + const qw = this.w; + const ix = qw * x + qy * z - qz * y; + const iy = qw * y + qz * x - qx * z; + const iz = qw * z + qx * y - qy * x; + const iw = -qx * x - qy * y - qz * z; + dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return dest; + } + toMat3(dest) { + if (!dest) { + dest = new mat3(); + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + dest.init([ + 1 - (yy + zz), + xy + wz, + xz - wy, + xy - wz, + 1 - (xx + zz), + yz + wx, + xz + wy, + yz - wx, + 1 - (xx + yy) + ]); + return dest; + } + toMat4(dest) { + if (!dest) { + dest = new mat4(); + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + dest.init([ + 1 - (yy + zz), + xy + wz, + xz - wy, + 0, + xy - wz, + 1 - (xx + zz), + yz + wx, + 0, + xz + wy, + yz - wx, + 1 - (xx + yy), + 0, + 0, + 0, + 0, + 1 + ]); + return dest; + } + static dot(q1, q2) { + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + } + static sum(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + dest.x = q1.x + q2.x; + dest.y = q1.y + q2.y; + dest.z = q1.z + q2.z; + dest.w = q1.w + q2.w; + return dest; + } + static product(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + const q1x = q1.x; + const q1y = q1.y; + const q1z = q1.z; + const q1w = q1.w; + const q2x = q2.x; + const q2y = q2.y; + const q2z = q2.z; + const q2w = q2.w; + dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; + dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; + dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; + dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + return dest; + } + static cross(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + const q1x = q1.x; + const q1y = q1.y; + const q1z = q1.z; + const q1w = q1.w; + const q2x = q2.x; + const q2y = q2.y; + const q2z = q2.z; + const q2w = q2.w; + dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x; + dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y; + dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z; + return dest; + } + static shortMix(q1, q2, time, dest) { + if (!dest) { + dest = new quat(); + } + if (time <= 0.0) { + dest.xyzw = q1.xyzw; + return dest; + } + else if (time >= 1.0) { + dest.xyzw = q2.xyzw; + return dest; + } + let cos = quat.dot(q1, q2); + const q2a = q2.copy(); + if (cos < 0.0) { + q2a.inverse(); + cos = -cos; + } + let k0; + let k1; + if (cos > 0.9999) { + k0 = 1 - time; + k1 = 0 + time; + } + else { + const sin = Math.sqrt(1 - cos * cos); + const angle = Math.atan2(sin, cos); + const oneOverSin = 1 / sin; + k0 = Math.sin((1 - time) * angle) * oneOverSin; + k1 = Math.sin((0 + time) * angle) * oneOverSin; + } + dest.x = k0 * q1.x + k1 * q2a.x; + dest.y = k0 * q1.y + k1 * q2a.y; + dest.z = k0 * q1.z + k1 * q2a.z; + dest.w = k0 * q1.w + k1 * q2a.w; + return dest; + } + static mix(q1, q2, time, dest) { + if (!dest) { + dest = new quat(); + } + const cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + if (Math.abs(cosHalfTheta) >= 1.0) { + dest.xyzw = q1.xyzw; + return dest; + } + const halfTheta = Math.acos(cosHalfTheta); + const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + if (Math.abs(sinHalfTheta) < 0.001) { + dest.x = q1.x * 0.5 + q2.x * 0.5; + dest.y = q1.y * 0.5 + q2.y * 0.5; + dest.z = q1.z * 0.5 + q2.z * 0.5; + dest.w = q1.w * 0.5 + q2.w * 0.5; + return dest; + } + const ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta; + const ratioB = Math.sin(time * halfTheta) / sinHalfTheta; + dest.x = q1.x * ratioA + q2.x * ratioB; + dest.y = q1.y * ratioA + q2.y * ratioB; + dest.z = q1.z * ratioA + q2.z * ratioB; + dest.w = q1.w * ratioA + q2.w * ratioB; + return dest; + } + static fromAxisAngle(axis, angle, dest) { + if (!dest) { + dest = new quat(); + } + angle *= 0.5; + const sin = Math.sin(angle); + dest.x = axis.x * sin; + dest.y = axis.y * sin; + dest.z = axis.z * sin; + dest.w = Math.cos(angle); + return dest; + } +} +quat.identity = new quat().setIdentity(); diff --git a/src/framework/tsm/tsm.d.ts b/framework/tsm/tsm.d.ts similarity index 95% rename from src/framework/tsm/tsm.d.ts rename to framework/tsm/tsm.d.ts index 4fcfb6d..280aeee 100644 --- a/src/framework/tsm/tsm.d.ts +++ b/framework/tsm/tsm.d.ts @@ -1,17 +1,17 @@ -import mat2 from './mat2'; -import mat3 from './mat3'; -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -import vec4 from './vec4'; -declare const _default: { - vec2: typeof vec2; - vec3: typeof vec3; - vec4: typeof vec4; - mat2: typeof mat2; - mat3: typeof mat3; - mat4: typeof mat4; - quat: typeof quat; -}; -export default _default; +import mat2 from './mat2'; +import mat3 from './mat3'; +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import vec4 from './vec4'; +declare const _default: { + vec2: typeof vec2; + vec3: typeof vec3; + vec4: typeof vec4; + mat2: typeof mat2; + mat3: typeof mat3; + mat4: typeof mat4; + quat: typeof quat; +}; +export default _default; diff --git a/src/framework/tsm/tsm.js b/framework/tsm/tsm.js similarity index 96% rename from src/framework/tsm/tsm.js rename to framework/tsm/tsm.js index def6504..91cceb3 100644 --- a/src/framework/tsm/tsm.js +++ b/framework/tsm/tsm.js @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2012, 2018 Matthias Ferch - * - * Project homepage: https://github.com/matthiasferch/tsm - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - */ -import mat2 from './mat2'; -import mat3 from './mat3'; -import mat4 from './mat4'; -import quat from './quat'; -import vec2 from './vec2'; -import vec3 from './vec3'; -import vec4 from './vec4'; -export default { - vec2, - vec3, - vec4, - mat2, - mat3, - mat4, - quat -}; +/* + * Copyright (c) 2012, 2018 Matthias Ferch + * + * Project homepage: https://github.com/matthiasferch/tsm + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ +import mat2 from './mat2'; +import mat3 from './mat3'; +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import vec4 from './vec4'; +export default { + vec2, + vec3, + vec4, + mat2, + mat3, + mat4, + quat +}; diff --git a/src/framework/resonator/vendor/tsm/vec2.d.ts b/framework/tsm/vec2.d.ts similarity index 97% rename from src/framework/resonator/vendor/tsm/vec2.d.ts rename to framework/tsm/vec2.d.ts index 34a2e50..c7af680 100644 --- a/src/framework/resonator/vendor/tsm/vec2.d.ts +++ b/framework/tsm/vec2.d.ts @@ -1,40 +1,40 @@ -import mat2 from './mat2'; -import mat3 from './mat3'; -import vec3 from './vec3'; -export default class vec2 { - get x(): number; - get y(): number; - get xy(): [number, number]; - set x(value: number); - set y(value: number); - set xy(values: [number, number]); - constructor(values?: [number, number]); - private values; - static readonly zero: vec2; - static readonly one: vec2; - at(index: number): number; - reset(): void; - copy(dest?: vec2): vec2; - negate(dest?: vec2): vec2; - equals(vector: vec2, threshold?: number): boolean; - length(): number; - squaredLength(): number; - add(vector: vec2): vec2; - subtract(vector: vec2): vec2; - multiply(vector: vec2): vec2; - divide(vector: vec2): vec2; - scale(value: number, dest?: vec2): vec2; - normalize(dest?: vec2): vec2; - multiplyMat2(matrix: mat2, dest?: vec2): vec2; - multiplyMat3(matrix: mat3, dest?: vec2): vec2; - static cross(vector: vec2, vector2: vec2, dest?: vec3): vec3; - static dot(vector: vec2, vector2: vec2): number; - static distance(vector: vec2, vector2: vec2): number; - static squaredDistance(vector: vec2, vector2: vec2): number; - static direction(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static mix(vector: vec2, vector2: vec2, time: number, dest?: vec2): vec2; - static sum(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static difference(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static product(vector: vec2, vector2: vec2, dest?: vec2): vec2; - static quotient(vector: vec2, vector2: vec2, dest?: vec2): vec2; -} +import mat2 from './mat2'; +import mat3 from './mat3'; +import vec3 from './vec3'; +export default class vec2 { + get x(): number; + get y(): number; + get xy(): [number, number]; + set x(value: number); + set y(value: number); + set xy(values: [number, number]); + constructor(values?: [number, number]); + private values; + static readonly zero: vec2; + static readonly one: vec2; + at(index: number): number; + reset(): void; + copy(dest?: vec2): vec2; + negate(dest?: vec2): vec2; + equals(vector: vec2, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec2): vec2; + subtract(vector: vec2): vec2; + multiply(vector: vec2): vec2; + divide(vector: vec2): vec2; + scale(value: number, dest?: vec2): vec2; + normalize(dest?: vec2): vec2; + multiplyMat2(matrix: mat2, dest?: vec2): vec2; + multiplyMat3(matrix: mat3, dest?: vec2): vec2; + static cross(vector: vec2, vector2: vec2, dest?: vec3): vec3; + static dot(vector: vec2, vector2: vec2): number; + static distance(vector: vec2, vector2: vec2): number; + static squaredDistance(vector: vec2, vector2: vec2): number; + static direction(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static mix(vector: vec2, vector2: vec2, time: number, dest?: vec2): vec2; + static sum(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static difference(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static product(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static quotient(vector: vec2, vector2: vec2, dest?: vec2): vec2; +} diff --git a/src/framework/resonator/vendor/tsm/vec2.js b/framework/tsm/vec2.js similarity index 95% rename from src/framework/resonator/vendor/tsm/vec2.js rename to framework/tsm/vec2.js index 598afdc..f319a69 100644 --- a/src/framework/resonator/vendor/tsm/vec2.js +++ b/framework/tsm/vec2.js @@ -1,215 +1,215 @@ -import vec3 from './vec3'; -import { epsilon } from './constants'; -export default class vec2 { - constructor(values) { - this.values = new Float32Array(2); - if (values !== undefined) { - this.xy = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - at(index) { - return this.values[index]; - } - reset() { - this.x = 0; - this.y = 0; - } - copy(dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = this.x; - dest.y = this.y; - return dest; - } - negate(dest) { - if (!dest) { - dest = this; - } - dest.x = -this.x; - dest.y = -this.y; - return dest; - } - equals(vector, threshold = epsilon) { - if (Math.abs(this.x - vector.x) > threshold) { - return false; - } - if (Math.abs(this.y - vector.y) > threshold) { - return false; - } - return true; - } - length() { - return Math.sqrt(this.squaredLength()); - } - squaredLength() { - const x = this.x; - const y = this.y; - return x * x + y * y; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - return this; - } - subtract(vector) { - this.x -= vector.x; - this.y -= vector.y; - return this; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - return this; - } - divide(vector) { - this.x /= vector.x; - this.y /= vector.y; - return this; - } - scale(value, dest) { - if (!dest) { - dest = this; - } - dest.x *= value; - dest.y *= value; - return dest; - } - normalize(dest) { - if (!dest) { - dest = this; - } - let length = this.length(); - if (length === 1) { - return this; - } - if (length === 0) { - dest.x = 0; - dest.y = 0; - return dest; - } - length = 1.0 / length; - dest.x *= length; - dest.y *= length; - return dest; - } - multiplyMat2(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec2(this, dest); - } - multiplyMat3(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec2(this, dest); - } - static cross(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x; - const y = vector.y; - const x2 = vector2.x; - const y2 = vector2.y; - const z = x * y2 - y * x2; - dest.x = 0; - dest.y = 0; - dest.z = z; - return dest; - } - static dot(vector, vector2) { - return vector.x * vector2.x + vector.y * vector2.y; - } - static distance(vector, vector2) { - return Math.sqrt(this.squaredDistance(vector, vector2)); - } - static squaredDistance(vector, vector2) { - const x = vector2.x - vector.x; - const y = vector2.y - vector.y; - return x * x + y * y; - } - static direction(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - const x = vector.x - vector2.x; - const y = vector.y - vector2.y; - let length = Math.sqrt(x * x + y * y); - if (length === 0) { - dest.x = 0; - dest.y = 0; - return dest; - } - length = 1 / length; - dest.x = x * length; - dest.y = y * length; - return dest; - } - static mix(vector, vector2, time, dest) { - if (!dest) { - dest = new vec2(); - } - const x = vector.x; - const y = vector.y; - const x2 = vector2.x; - const y2 = vector2.y; - dest.x = x + time * (x2 - x); - dest.y = y + time * (y2 - y); - return dest; - } - static sum(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x + vector2.x; - dest.y = vector.y + vector2.y; - return dest; - } - static difference(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x - vector2.x; - dest.y = vector.y - vector2.y; - return dest; - } - static product(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x * vector2.x; - dest.y = vector.y * vector2.y; - return dest; - } - static quotient(vector, vector2, dest) { - if (!dest) { - dest = new vec2(); - } - dest.x = vector.x / vector2.x; - dest.y = vector.y / vector2.y; - return dest; - } -} -vec2.zero = new vec2([0, 0]); -vec2.one = new vec2([1, 1]); +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class vec2 { + constructor(values) { + this.values = new Float32Array(2); + if (values !== undefined) { + this.xy = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + } + copy(dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = this.x; + dest.y = this.y; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + return x * x + y * y; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x = 0; + dest.y = 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + return dest; + } + multiplyMat2(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec2(this, dest); + } + multiplyMat3(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec2(this, dest); + } + static cross(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const x2 = vector2.x; + const y2 = vector2.y; + const z = x * y2 - y * x2; + dest.x = 0; + dest.y = 0; + dest.z = z; + return dest; + } + static dot(vector, vector2) { + return vector.x * vector2.x + vector.y * vector2.y; + } + static distance(vector, vector2) { + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + static squaredDistance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + return x * x + y * y; + } + static direction(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + const x = vector.x - vector2.x; + const y = vector.y - vector2.y; + let length = Math.sqrt(x * x + y * y); + if (length === 0) { + dest.x = 0; + dest.y = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + return dest; + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec2(); + } + const x = vector.x; + const y = vector.y; + const x2 = vector2.x; + const y2 = vector2.y; + dest.x = x + time * (x2 - x); + dest.y = y + time * (y2 - y); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + return dest; + } +} +vec2.zero = new vec2([0, 0]); +vec2.one = new vec2([1, 1]); diff --git a/src/framework/resonator/vendor/tsm/vec3.d.ts b/framework/tsm/vec3.d.ts similarity index 97% rename from src/framework/resonator/vendor/tsm/vec3.d.ts rename to framework/tsm/vec3.d.ts index 900889a..2fb4873 100644 --- a/src/framework/resonator/vendor/tsm/vec3.d.ts +++ b/framework/tsm/vec3.d.ts @@ -1,47 +1,47 @@ -import mat3 from './mat3'; -import quat from './quat'; -export default class vec3 { - get x(): number; - get y(): number; - get z(): number; - get xy(): [number, number]; - get xyz(): [number, number, number]; - set x(value: number); - set y(value: number); - set z(value: number); - set xy(values: [number, number]); - set xyz(values: [number, number, number]); - constructor(values?: [number, number, number]); - private values; - static readonly zero: vec3; - static readonly one: vec3; - static readonly up: vec3; - static readonly right: vec3; - static readonly forward: vec3; - at(index: number): number; - reset(): void; - copy(dest?: vec3): vec3; - negate(dest?: vec3): vec3; - equals(vector: vec3, threshold?: number): boolean; - length(): number; - squaredLength(): number; - add(vector: vec3): vec3; - subtract(vector: vec3): vec3; - multiply(vector: vec3): vec3; - divide(vector: vec3): vec3; - scale(value: number, dest?: vec3): vec3; - normalize(dest?: vec3): vec3; - multiplyByMat3(matrix: mat3, dest?: vec3): vec3; - multiplyByQuat(quaternion: quat, dest?: vec3): vec3; - toQuat(dest?: quat): quat; - static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static dot(vector: vec3, vector2: vec3): number; - static distance(vector: vec3, vector2: vec3): number; - static squaredDistance(vector: vec3, vector2: vec3): number; - static direction(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static mix(vector: vec3, vector2: vec3, time: number, dest?: vec3): vec3; - static sum(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static difference(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static product(vector: vec3, vector2: vec3, dest?: vec3): vec3; - static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3; -} +import mat3 from './mat3'; +import quat from './quat'; +export default class vec3 { + get x(): number; + get y(): number; + get z(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + constructor(values?: [number, number, number]); + private values; + static readonly zero: vec3; + static readonly one: vec3; + static readonly up: vec3; + static readonly right: vec3; + static readonly forward: vec3; + at(index: number): number; + reset(): void; + copy(dest?: vec3): vec3; + negate(dest?: vec3): vec3; + equals(vector: vec3, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec3): vec3; + subtract(vector: vec3): vec3; + multiply(vector: vec3): vec3; + divide(vector: vec3): vec3; + scale(value: number, dest?: vec3): vec3; + normalize(dest?: vec3): vec3; + multiplyByMat3(matrix: mat3, dest?: vec3): vec3; + multiplyByQuat(quaternion: quat, dest?: vec3): vec3; + toQuat(dest?: quat): quat; + static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static dot(vector: vec3, vector2: vec3): number; + static distance(vector: vec3, vector2: vec3): number; + static squaredDistance(vector: vec3, vector2: vec3): number; + static direction(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static mix(vector: vec3, vector2: vec3, time: number, dest?: vec3): vec3; + static sum(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static difference(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static product(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3; +} diff --git a/src/framework/resonator/vendor/tsm/vec3.js b/framework/tsm/vec3.js similarity index 96% rename from src/framework/resonator/vendor/tsm/vec3.js rename to framework/tsm/vec3.js index 26b6b21..7d8de70 100644 --- a/src/framework/resonator/vendor/tsm/vec3.js +++ b/framework/tsm/vec3.js @@ -1,279 +1,279 @@ -import quat from './quat'; -import { epsilon } from './constants'; -export default class vec3 { - constructor(values) { - this.values = new Float32Array(3); - if (values !== undefined) { - this.xyz = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get z() { - return this.values[2]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - get xyz() { - return [this.values[0], this.values[1], this.values[2]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set z(value) { - this.values[2] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set xyz(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - at(index) { - return this.values[index]; - } - reset() { - this.x = 0; - this.y = 0; - this.z = 0; - } - copy(dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = this.x; - dest.y = this.y; - dest.z = this.z; - return dest; - } - negate(dest) { - if (!dest) { - dest = this; - } - dest.x = -this.x; - dest.y = -this.y; - dest.z = -this.z; - return dest; - } - equals(vector, threshold = epsilon) { - if (Math.abs(this.x - vector.x) > threshold) { - return false; - } - if (Math.abs(this.y - vector.y) > threshold) { - return false; - } - if (Math.abs(this.z - vector.z) > threshold) { - return false; - } - return true; - } - length() { - return Math.sqrt(this.squaredLength()); - } - squaredLength() { - const x = this.x; - const y = this.y; - const z = this.z; - return x * x + y * y + z * z; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - this.z += vector.z; - return this; - } - subtract(vector) { - this.x -= vector.x; - this.y -= vector.y; - this.z -= vector.z; - return this; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - this.z *= vector.z; - return this; - } - divide(vector) { - this.x /= vector.x; - this.y /= vector.y; - this.z /= vector.z; - return this; - } - scale(value, dest) { - if (!dest) { - dest = this; - } - dest.x *= value; - dest.y *= value; - dest.z *= value; - return dest; - } - normalize(dest) { - if (!dest) { - dest = this; - } - let length = this.length(); - if (length === 1) { - return this; - } - if (length === 0) { - dest.x = 0; - dest.y = 0; - dest.z = 0; - return dest; - } - length = 1.0 / length; - dest.x *= length; - dest.y *= length; - dest.z *= length; - return dest; - } - multiplyByMat3(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec3(this, dest); - } - multiplyByQuat(quaternion, dest) { - if (!dest) { - dest = this; - } - return quaternion.multiplyVec3(this, dest); - } - toQuat(dest) { - if (!dest) { - dest = new quat(); - } - const c = new vec3(); - const s = new vec3(); - c.x = Math.cos(this.x * 0.5); - s.x = Math.sin(this.x * 0.5); - c.y = Math.cos(this.y * 0.5); - s.y = Math.sin(this.y * 0.5); - c.z = Math.cos(this.z * 0.5); - s.z = Math.sin(this.z * 0.5); - dest.x = s.x * c.y * c.z - c.x * s.y * s.z; - dest.y = c.x * s.y * c.z + s.x * c.y * s.z; - dest.z = c.x * c.y * s.z - s.x * s.y * c.z; - dest.w = c.x * c.y * c.z + s.x * s.y * s.z; - return dest; - } - static cross(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x; - const y = vector.y; - const z = vector.z; - const x2 = vector2.x; - const y2 = vector2.y; - const z2 = vector2.z; - dest.x = y * z2 - z * y2; - dest.y = z * x2 - x * z2; - dest.z = x * y2 - y * x2; - return dest; - } - static dot(vector, vector2) { - const x = vector.x; - const y = vector.y; - const z = vector.z; - const x2 = vector2.x; - const y2 = vector2.y; - const z2 = vector2.z; - return x * x2 + y * y2 + z * z2; - } - static distance(vector, vector2) { - const x = vector2.x - vector.x; - const y = vector2.y - vector.y; - const z = vector2.z - vector.z; - return Math.sqrt(this.squaredDistance(vector, vector2)); - } - static squaredDistance(vector, vector2) { - const x = vector2.x - vector.x; - const y = vector2.y - vector.y; - const z = vector2.z - vector.z; - return x * x + y * y + z * z; - } - static direction(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - const x = vector.x - vector2.x; - const y = vector.y - vector2.y; - const z = vector.z - vector2.z; - let length = Math.sqrt(x * x + y * y + z * z); - if (length === 0) { - dest.x = 0; - dest.y = 0; - dest.z = 0; - return dest; - } - length = 1 / length; - dest.x = x * length; - dest.y = y * length; - dest.z = z * length; - return dest; - } - static mix(vector, vector2, time, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x + time * (vector2.x - vector.x); - dest.y = vector.y + time * (vector2.y - vector.y); - dest.z = vector.z + time * (vector2.z - vector.z); - return dest; - } - static sum(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x + vector2.x; - dest.y = vector.y + vector2.y; - dest.z = vector.z + vector2.z; - return dest; - } - static difference(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x - vector2.x; - dest.y = vector.y - vector2.y; - dest.z = vector.z - vector2.z; - return dest; - } - static product(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x * vector2.x; - dest.y = vector.y * vector2.y; - dest.z = vector.z * vector2.z; - return dest; - } - static quotient(vector, vector2, dest) { - if (!dest) { - dest = new vec3(); - } - dest.x = vector.x / vector2.x; - dest.y = vector.y / vector2.y; - dest.z = vector.z / vector2.z; - return dest; - } -} -vec3.zero = new vec3([0, 0, 0]); -vec3.one = new vec3([1, 1, 1]); -vec3.up = new vec3([0, 1, 0]); -vec3.right = new vec3([1, 0, 0]); -vec3.forward = new vec3([0, 0, 1]); +import quat from './quat'; +import { epsilon } from './constants'; +export default class vec3 { + constructor(values) { + this.values = new Float32Array(3); + if (values !== undefined) { + this.xyz = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + this.z = 0; + } + copy(dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + dest.z = -this.z; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + if (Math.abs(this.z - vector.z) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + const z = this.z; + return x * x + y * y + z * z; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + this.z /= vector.z; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + dest.z *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + dest.z *= length; + return dest; + } + multiplyByMat3(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec3(this, dest); + } + multiplyByQuat(quaternion, dest) { + if (!dest) { + dest = this; + } + return quaternion.multiplyVec3(this, dest); + } + toQuat(dest) { + if (!dest) { + dest = new quat(); + } + const c = new vec3(); + const s = new vec3(); + c.x = Math.cos(this.x * 0.5); + s.x = Math.sin(this.x * 0.5); + c.y = Math.cos(this.y * 0.5); + s.y = Math.sin(this.y * 0.5); + c.z = Math.cos(this.z * 0.5); + s.z = Math.sin(this.z * 0.5); + dest.x = s.x * c.y * c.z - c.x * s.y * s.z; + dest.y = c.x * s.y * c.z + s.x * c.y * s.z; + dest.z = c.x * c.y * s.z - s.x * s.y * c.z; + dest.w = c.x * c.y * c.z + s.x * s.y * s.z; + return dest; + } + static cross(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const x2 = vector2.x; + const y2 = vector2.y; + const z2 = vector2.z; + dest.x = y * z2 - z * y2; + dest.y = z * x2 - x * z2; + dest.z = x * y2 - y * x2; + return dest; + } + static dot(vector, vector2) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + const x2 = vector2.x; + const y2 = vector2.y; + const z2 = vector2.z; + return x * x2 + y * y2 + z * z2; + } + static distance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + const z = vector2.z - vector.z; + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + static squaredDistance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + const z = vector2.z - vector.z; + return x * x + y * y + z * z; + } + static direction(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x - vector2.x; + const y = vector.y - vector2.y; + const z = vector.z - vector2.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (length === 0) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + dest.z = z * length; + return dest; + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x + time * (vector2.x - vector.x); + dest.y = vector.y + time * (vector2.y - vector.y); + dest.z = vector.z + time * (vector2.z - vector.z); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + dest.z = vector.z + vector2.z; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + dest.z = vector.z - vector2.z; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + dest.z = vector.z * vector2.z; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + dest.z = vector.z / vector2.z; + return dest; + } +} +vec3.zero = new vec3([0, 0, 0]); +vec3.one = new vec3([1, 1, 1]); +vec3.up = new vec3([0, 1, 0]); +vec3.right = new vec3([1, 0, 0]); +vec3.forward = new vec3([0, 0, 1]); diff --git a/src/framework/tsm/vec4.d.ts b/framework/tsm/vec4.d.ts similarity index 97% rename from src/framework/tsm/vec4.d.ts rename to framework/tsm/vec4.d.ts index 35366a8..42de7df 100644 --- a/src/framework/tsm/vec4.d.ts +++ b/framework/tsm/vec4.d.ts @@ -1,54 +1,54 @@ -import mat4 from './mat4'; -export default class vec4 { - get x(): number; - get y(): number; - get z(): number; - get w(): number; - get xy(): [number, number]; - get xyz(): [number, number, number]; - get xyzw(): [number, number, number, number]; - set x(value: number); - set y(value: number); - set z(value: number); - set w(value: number); - set xy(values: [number, number]); - set xyz(values: [number, number, number]); - set xyzw(values: [number, number, number, number]); - get r(): number; - get g(): number; - get b(): number; - get a(): number; - get rg(): [number, number]; - get rgb(): [number, number, number]; - get rgba(): [number, number, number, number]; - set r(value: number); - set g(value: number); - set b(value: number); - set a(value: number); - set rg(values: [number, number]); - set rgb(values: [number, number, number]); - set rgba(values: [number, number, number, number]); - constructor(values?: [number, number, number, number]); - private values; - static readonly zero: vec4; - static readonly one: vec4; - at(index: number): number; - reset(): void; - copy(dest?: vec4): vec4; - negate(dest?: vec4): vec4; - equals(vector: vec4, threshold?: number): boolean; - length(): number; - squaredLength(): number; - add(vector: vec4): vec4; - subtract(vector: vec4): vec4; - multiply(vector: vec4): vec4; - divide(vector: vec4): vec4; - scale(value: number, dest?: vec4): vec4; - normalize(dest?: vec4): vec4; - multiplyMat4(matrix: mat4, dest?: vec4): vec4; - static mix(vector: vec4, vector2: vec4, time: number, dest?: vec4): vec4; - static sum(vector: vec4, vector2: vec4, dest?: vec4): vec4; - static difference(vector: vec4, vector2: vec4, dest?: vec4): vec4; - static product(vector: vec4, vector2: vec4, dest?: vec4): vec4; - static quotient(vector: vec4, vector2: vec4, dest?: vec4): vec4; -} +import mat4 from './mat4'; +export default class vec4 { + get x(): number; + get y(): number; + get z(): number; + get w(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + get xyzw(): [number, number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set w(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + set xyzw(values: [number, number, number, number]); + get r(): number; + get g(): number; + get b(): number; + get a(): number; + get rg(): [number, number]; + get rgb(): [number, number, number]; + get rgba(): [number, number, number, number]; + set r(value: number); + set g(value: number); + set b(value: number); + set a(value: number); + set rg(values: [number, number]); + set rgb(values: [number, number, number]); + set rgba(values: [number, number, number, number]); + constructor(values?: [number, number, number, number]); + private values; + static readonly zero: vec4; + static readonly one: vec4; + at(index: number): number; + reset(): void; + copy(dest?: vec4): vec4; + negate(dest?: vec4): vec4; + equals(vector: vec4, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec4): vec4; + subtract(vector: vec4): vec4; + multiply(vector: vec4): vec4; + divide(vector: vec4): vec4; + scale(value: number, dest?: vec4): vec4; + normalize(dest?: vec4): vec4; + multiplyMat4(matrix: mat4, dest?: vec4): vec4; + static mix(vector: vec4, vector2: vec4, time: number, dest?: vec4): vec4; + static sum(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static difference(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static product(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static quotient(vector: vec4, vector2: vec4, dest?: vec4): vec4; +} diff --git a/src/framework/tsm/vec4.js b/framework/tsm/vec4.js similarity index 96% rename from src/framework/tsm/vec4.js rename to framework/tsm/vec4.js index fd0337d..16723e7 100644 --- a/src/framework/tsm/vec4.js +++ b/framework/tsm/vec4.js @@ -1,277 +1,277 @@ -import { epsilon } from './constants'; -export default class vec4 { - constructor(values) { - this.values = new Float32Array(4); - if (values !== undefined) { - this.xyzw = values; - } - } - get x() { - return this.values[0]; - } - get y() { - return this.values[1]; - } - get z() { - return this.values[2]; - } - get w() { - return this.values[3]; - } - get xy() { - return [this.values[0], this.values[1]]; - } - get xyz() { - return [this.values[0], this.values[1], this.values[2]]; - } - get xyzw() { - return [this.values[0], this.values[1], this.values[2], this.values[3]]; - } - set x(value) { - this.values[0] = value; - } - set y(value) { - this.values[1] = value; - } - set z(value) { - this.values[2] = value; - } - set w(value) { - this.values[3] = value; - } - set xy(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set xyz(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - set xyzw(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - this.values[3] = values[3]; - } - get r() { - return this.values[0]; - } - get g() { - return this.values[1]; - } - get b() { - return this.values[2]; - } - get a() { - return this.values[3]; - } - get rg() { - return [this.values[0], this.values[1]]; - } - get rgb() { - return [this.values[0], this.values[1], this.values[2]]; - } - get rgba() { - return [this.values[0], this.values[1], this.values[2], this.values[3]]; - } - set r(value) { - this.values[0] = value; - } - set g(value) { - this.values[1] = value; - } - set b(value) { - this.values[2] = value; - } - set a(value) { - this.values[3] = value; - } - set rg(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - } - set rgb(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - } - set rgba(values) { - this.values[0] = values[0]; - this.values[1] = values[1]; - this.values[2] = values[2]; - this.values[3] = values[3]; - } - at(index) { - return this.values[index]; - } - reset() { - this.x = 0; - this.y = 0; - this.z = 0; - this.w = 0; - } - copy(dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = this.x; - dest.y = this.y; - dest.z = this.z; - dest.w = this.w; - return dest; - } - negate(dest) { - if (!dest) { - dest = this; - } - dest.x = -this.x; - dest.y = -this.y; - dest.z = -this.z; - dest.w = -this.w; - return dest; - } - equals(vector, threshold = epsilon) { - if (Math.abs(this.x - vector.x) > threshold) { - return false; - } - if (Math.abs(this.y - vector.y) > threshold) { - return false; - } - if (Math.abs(this.z - vector.z) > threshold) { - return false; - } - if (Math.abs(this.w - vector.w) > threshold) { - return false; - } - return true; - } - length() { - return Math.sqrt(this.squaredLength()); - } - squaredLength() { - const x = this.x; - const y = this.y; - const z = this.z; - const w = this.w; - return x * x + y * y + z * z + w * w; - } - add(vector) { - this.x += vector.x; - this.y += vector.y; - this.z += vector.z; - this.w += vector.w; - return this; - } - subtract(vector) { - this.x -= vector.x; - this.y -= vector.y; - this.z -= vector.z; - this.w -= vector.w; - return this; - } - multiply(vector) { - this.x *= vector.x; - this.y *= vector.y; - this.z *= vector.z; - this.w *= vector.w; - return this; - } - divide(vector) { - this.x /= vector.x; - this.y /= vector.y; - this.z /= vector.z; - this.w /= vector.w; - return this; - } - scale(value, dest) { - if (!dest) { - dest = this; - } - dest.x *= value; - dest.y *= value; - dest.z *= value; - dest.w *= value; - return dest; - } - normalize(dest) { - if (!dest) { - dest = this; - } - let length = this.length(); - if (length === 1) { - return this; - } - if (length === 0) { - dest.x *= 0; - dest.y *= 0; - dest.z *= 0; - dest.w *= 0; - return dest; - } - length = 1.0 / length; - dest.x *= length; - dest.y *= length; - dest.z *= length; - dest.w *= length; - return dest; - } - multiplyMat4(matrix, dest) { - if (!dest) { - dest = this; - } - return matrix.multiplyVec4(this, dest); - } - static mix(vector, vector2, time, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x + time * (vector2.x - vector.x); - dest.y = vector.y + time * (vector2.y - vector.y); - dest.z = vector.z + time * (vector2.z - vector.z); - dest.w = vector.w + time * (vector2.w - vector.w); - return dest; - } - static sum(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x + vector2.x; - dest.y = vector.y + vector2.y; - dest.z = vector.z + vector2.z; - dest.w = vector.w + vector2.w; - return dest; - } - static difference(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x - vector2.x; - dest.y = vector.y - vector2.y; - dest.z = vector.z - vector2.z; - dest.w = vector.w - vector2.w; - return dest; - } - static product(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x * vector2.x; - dest.y = vector.y * vector2.y; - dest.z = vector.z * vector2.z; - dest.w = vector.w * vector2.w; - return dest; - } - static quotient(vector, vector2, dest) { - if (!dest) { - dest = new vec4(); - } - dest.x = vector.x / vector2.x; - dest.y = vector.y / vector2.y; - dest.z = vector.z / vector2.z; - dest.w = vector.w / vector2.w; - return dest; - } -} -vec4.zero = new vec4([0, 0, 0, 1]); -vec4.one = new vec4([1, 1, 1, 1]); +import { epsilon } from './constants'; +export default class vec4 { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.xyzw = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get w() { + return this.values[3]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + get xyzw() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set w(value) { + this.values[3] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set xyzw(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + get r() { + return this.values[0]; + } + get g() { + return this.values[1]; + } + get b() { + return this.values[2]; + } + get a() { + return this.values[3]; + } + get rg() { + return [this.values[0], this.values[1]]; + } + get rgb() { + return [this.values[0], this.values[1], this.values[2]]; + } + get rgba() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set r(value) { + this.values[0] = value; + } + set g(value) { + this.values[1] = value; + } + set b(value) { + this.values[2] = value; + } + set a(value) { + this.values[3] = value; + } + set rg(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set rgb(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set rgba(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + } + copy(dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + dest.w = this.w; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + dest.z = -this.z; + dest.w = -this.w; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + if (Math.abs(this.z - vector.z) > threshold) { + return false; + } + if (Math.abs(this.w - vector.w) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return x * x + y * y + z * z + w * w; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + this.w += vector.w; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + this.w -= vector.w; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + this.w *= vector.w; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + this.z /= vector.z; + this.w /= vector.w; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + dest.z *= value; + dest.w *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x *= 0; + dest.y *= 0; + dest.z *= 0; + dest.w *= 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + dest.z *= length; + dest.w *= length; + return dest; + } + multiplyMat4(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec4(this, dest); + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x + time * (vector2.x - vector.x); + dest.y = vector.y + time * (vector2.y - vector.y); + dest.z = vector.z + time * (vector2.z - vector.z); + dest.w = vector.w + time * (vector2.w - vector.w); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + dest.z = vector.z + vector2.z; + dest.w = vector.w + vector2.w; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + dest.z = vector.z - vector2.z; + dest.w = vector.w - vector2.w; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + dest.z = vector.z * vector2.z; + dest.w = vector.w * vector2.w; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + dest.z = vector.z / vector2.z; + dest.w = vector.w / vector2.w; + return dest; + } +} +vec4.zero = new vec4([0, 0, 0, 1]); +vec4.one = new vec4([1, 1, 1, 1]); diff --git a/framework/tts/index.d.ts b/framework/tts/index.d.ts new file mode 100644 index 0000000..4848ef7 --- /dev/null +++ b/framework/tts/index.d.ts @@ -0,0 +1,7 @@ +import { BaseOutput } from './outputs/base-output'; +export declare class TTS { + private output; + constructor(output?: BaseOutput); + speak(text: string): void; + stop(): void; +} diff --git a/framework/tts/index.js b/framework/tts/index.js new file mode 100644 index 0000000..838e2ab --- /dev/null +++ b/framework/tts/index.js @@ -0,0 +1,12 @@ +import { createOutput } from './output-factory'; +export class TTS { + constructor(output = createOutput()) { + this.output = output; + } + speak(text) { + this.output.speak(text); + } + stop() { + this.output.stop(); + } +} diff --git a/framework/tts/output-factory.d.ts b/framework/tts/output-factory.d.ts new file mode 100644 index 0000000..a01e972 --- /dev/null +++ b/framework/tts/output-factory.d.ts @@ -0,0 +1,5 @@ +import { BaseOutput } from './outputs/base-output'; +import { AriaOutput } from './outputs/aria'; +import { WebTTSOutput } from './outputs/webtts'; +export declare function createOutput(key?: string): any; +export { WebTTSOutput, AriaOutput, BaseOutput }; diff --git a/framework/tts/output-factory.js b/framework/tts/output-factory.js new file mode 100644 index 0000000..8181210 --- /dev/null +++ b/framework/tts/output-factory.js @@ -0,0 +1,17 @@ +import { BaseOutput } from './outputs/base-output'; +import { AriaOutput } from './outputs/aria'; +import { WebTTSOutput } from './outputs/webtts'; +export function createOutput(key = 'aria') { + switch (key) { + case 'aria': + return AriaOutput; + break; + case 'webtts': + return WebTTSOutput; + break; + default: + return AriaOutput; + break; + } +} +export { WebTTSOutput, AriaOutput, BaseOutput }; diff --git a/framework/tts/outputs/aria.d.ts b/framework/tts/outputs/aria.d.ts new file mode 100644 index 0000000..a56ab19 --- /dev/null +++ b/framework/tts/outputs/aria.d.ts @@ -0,0 +1,11 @@ +import { BaseOutput } from './base-output'; +export declare class AriaOutput extends BaseOutput { + private container; + private speechDisplay; + private timeout; + constructor(options?: any); + private init; + speak(text: string): void; + stop(): void; + clearDisplay(): void; +} diff --git a/framework/tts/outputs/aria.js b/framework/tts/outputs/aria.js new file mode 100644 index 0000000..766eac7 --- /dev/null +++ b/framework/tts/outputs/aria.js @@ -0,0 +1,32 @@ +import { BaseOutput } from './base-output'; +export class AriaOutput extends BaseOutput { + constructor(options = {}) { + super(); + this.timeout = 100; + this.timeout = options.timeout || 100; + this.init(); + } + init() { + this.container = document.createElement('div'); + this.container.setAttribute('aria-live', 'polite'); + this.speechDisplay = document.createElement('div'); + this.speechDisplay.setAttribute('aria-live', 'polite'); + this.container.append(this.speechDisplay); + document.body.appendChild(this.container); + document.body.insertBefore(this.container, document.body.firstChild); + } + speak(text) { + this.clearDisplay(); + const node = document.createTextNode(text); + const para = document.createElement('p'); + para.appendChild(node); + this.speechDisplay.appendChild(para); + setTimeout(this.clearDisplay.bind(this), this.timeout); + } + stop() { + this.clearDisplay(); + } + clearDisplay() { + this.speechDisplay.innerHTML = ''; + } +} diff --git a/framework/tts/outputs/base-output.d.ts b/framework/tts/outputs/base-output.d.ts new file mode 100644 index 0000000..5e74a35 --- /dev/null +++ b/framework/tts/outputs/base-output.d.ts @@ -0,0 +1,5 @@ +export declare class BaseOutput { + speak(text: string): void; + stop(): void; + setOptions(options: any): void; +} diff --git a/framework/tts/outputs/base-output.js b/framework/tts/outputs/base-output.js new file mode 100644 index 0000000..497a347 --- /dev/null +++ b/framework/tts/outputs/base-output.js @@ -0,0 +1,11 @@ +export class BaseOutput { + speak(text) { + return; + } + stop() { + return; + } + setOptions(options) { + return; + } +} diff --git a/framework/tts/outputs/webtts.d.ts b/framework/tts/outputs/webtts.d.ts new file mode 100644 index 0000000..af469dd --- /dev/null +++ b/framework/tts/outputs/webtts.d.ts @@ -0,0 +1,3 @@ +import { BaseOutput } from './base-output'; +export declare class WebTTSOutput extends BaseOutput { +} diff --git a/framework/tts/outputs/webtts.js b/framework/tts/outputs/webtts.js new file mode 100644 index 0000000..b42d38d --- /dev/null +++ b/framework/tts/outputs/webtts.js @@ -0,0 +1,3 @@ +import { BaseOutput } from './base-output'; +export class WebTTSOutput extends BaseOutput { +} diff --git a/framework/ui/index.d.ts b/framework/ui/index.d.ts new file mode 100644 index 0000000..7ca64c9 --- /dev/null +++ b/framework/ui/index.d.ts @@ -0,0 +1 @@ +export * from './menu/index'; diff --git a/framework/ui/index.js b/framework/ui/index.js new file mode 100644 index 0000000..ac730ea --- /dev/null +++ b/framework/ui/index.js @@ -0,0 +1,2 @@ +export * from './menu/index'; +// export * as Text from './text'; diff --git a/framework/ui/menu/index.d.ts b/framework/ui/menu/index.d.ts new file mode 100644 index 0000000..b0bbf4c --- /dev/null +++ b/framework/ui/menu/index.d.ts @@ -0,0 +1,39 @@ +import { BaseItem } from './items/base-item'; +import { SoundSet } from './interfaces/sound-set'; +import * as EventEmitter from 'eventemitter3'; +export declare class Menu extends EventEmitter { + private title; + private menuItems; + private soundSet; + private defaultAction; + private cancelAction; + private titleContainer; + private currentItem; + private currentIndex; + private container; + private element; + private DOMNodes; + private soundManager; + private keyboardManager; + constructor(title?: string, menuItems?: BaseItem[], soundSet?: SoundSet, defaultAction?: string, cancelAction?: string); + private init; + addItem(item: BaseItem): this; + setTitle(title: string): this; + setSoundSet(soundSet: SoundSet): this; + setDefaultAction(id: string): this; + setCancelAction(id: string): this; + run(element: HTMLElement): Promise; + close(): void; + private appendToContainer; + private handleItemUpdate; + private onItemFocus; + focusNext(): void; + focusPrevious(): void; + private focusCurrentIndex; + getCurrentFocus(): BaseItem; + getContainer(): HTMLElement; + clickDefaultAction(): void; + clickCancelAction(): void; + private compile; +} +export * from './items'; diff --git a/framework/ui/menu/index.js b/framework/ui/menu/index.js new file mode 100644 index 0000000..61bbe28 --- /dev/null +++ b/framework/ui/menu/index.js @@ -0,0 +1,145 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import * as EventEmitter from 'eventemitter3'; +import { SoundManager } from './sound-manager'; +import { KeyboardManager } from './keyboard-manager'; +export class Menu extends EventEmitter { + constructor(title = 'Menu', menuItems = [], soundSet = null, defaultAction = null, cancelAction = null) { + super(); + this.title = title; + this.menuItems = menuItems; + this.soundSet = soundSet; + this.defaultAction = defaultAction; + this.cancelAction = cancelAction; + this.currentIndex = 0; + this.DOMNodes = []; + this.currentIndex = 0; + this.currentItem = null; + this.soundManager = new SoundManager(soundSet); + this.keyboardManager = new KeyboardManager(this); + this.init(); + } + init() { + this.menuItems[this.currentIndex] && + this.menuItems[this.currentIndex].focus(); + this.emit('init'); + } + addItem(item) { + this.menuItems.push(item); + this.emit('item.add', item); + return this; + } + setTitle(title) { + this.title = title; + return this; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + this.soundManager.setSoundSet(this.soundSet); + return this; + } + setDefaultAction(id) { + this.defaultAction = id; + return this; + } + setCancelAction(id) { + this.cancelAction = id; + return this; + } + run(element) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + this.element = element; + this.container = document.createElement('div'); + this.titleContainer = document.createElement('h1'); + this.titleContainer.textContent = this.title; + this.container.appendChild(this.titleContainer); + this.menuItems.forEach((item) => { + this.appendToContainer(item.getDOMNode()); + item.on('update', this.handleItemUpdate.bind(this)); + item.on('focus', this.onItemFocus.bind(this)); + item.on('choose', (event) => { + const menuMap = this.compile(); + this.soundManager.handleSound('choose'); + this.emit('choose', menuMap); + resolve(menuMap); + }); + }); + element.appendChild(this.container); + this.soundManager.handleSound('open'); + this.keyboardManager.init(); + // push some data onto the history stack so that we can use the browser's back button to exit out of the menu. + history.pushState({ menu: true }, null, null); + }); + }); + } + close() { + this.container.remove(); + this.soundManager.handleSound('close'); + this.keyboardManager.release(); + this.DOMNodes.forEach((item) => { + this.container.removeChild(item); + }); + this.emit('close'); + } + appendToContainer(node) { + this.container.appendChild(node); + this.DOMNodes.push(node); + } + handleItemUpdate(value) { + this.soundManager.handleSound(value.type, value.value); + this.emit('update', this.compile()); + } + onItemFocus(id) { + this.soundManager.handleSound('focus'); + this.currentIndex = this.menuItems.indexOf(this.menuItems.find((item) => item.getID() == id)); + this.emit('focus', this.menuItems[this.currentIndex]); + } + focusNext() { + if (this.currentIndex < this.menuItems.length - 1) { + this.currentIndex++; + } + this.focusCurrentIndex(); + } + focusPrevious() { + if (this.currentIndex > 0) { + this.currentIndex--; + } + this.focusCurrentIndex(); + } + focusCurrentIndex() { + this.menuItems[this.currentIndex].focus(); + } + getCurrentFocus() { + return this.menuItems[this.currentIndex]; + } + getContainer() { + return this.container; + } + clickDefaultAction() { + if (!this.defaultAction) + return; + const item = this.menuItems.find((item) => item.getID() === this.defaultAction); + item.click(); + } + clickCancelAction() { + if (!this.cancelAction) + return; + const node = this.menuItems.find((item) => item.getID() === this.cancelAction); + node.click(); + } + compile() { + const menuMap = new Map(); + this.menuItems.forEach((item) => menuMap.set(item.getID(), item.getContents())); + menuMap.set('selected', this.menuItems[this.currentIndex].getID()); + return menuMap; + } +} +export * from './items'; diff --git a/framework/ui/menu/interfaces/playable-sound.d.ts b/framework/ui/menu/interfaces/playable-sound.d.ts new file mode 100644 index 0000000..34bdc03 --- /dev/null +++ b/framework/ui/menu/interfaces/playable-sound.d.ts @@ -0,0 +1,3 @@ +export interface IPlayableSound { + play(): any; +} diff --git a/framework/ui/menu/interfaces/playable-sound.js b/framework/ui/menu/interfaces/playable-sound.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/ui/menu/interfaces/playable-sound.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/ui/menu/interfaces/sound-set.d.ts b/framework/ui/menu/interfaces/sound-set.d.ts new file mode 100644 index 0000000..9e44362 --- /dev/null +++ b/framework/ui/menu/interfaces/sound-set.d.ts @@ -0,0 +1,17 @@ +import { IPlayableSound } from './playable-sound'; +export interface SoundSet { + open?: IPlayableSound; + close?: IPlayableSound; + boundary?: IPlayableSound; + choose?: IPlayableSound; + move?: IPlayableSound; + scroller?: IPlayableSound; + sliderLeft?: IPlayableSound; + sliderRight?: IPlayableSound; + wrap?: IPlayableSound; + char?: IPlayableSound; + delete?: IPlayableSound; + enter?: IPlayableSound; + checked?: IPlayableSound; + unchecked?: IPlayableSound; +} diff --git a/framework/ui/menu/interfaces/sound-set.js b/framework/ui/menu/interfaces/sound-set.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/ui/menu/interfaces/sound-set.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/ui/menu/items/base-item.d.ts b/framework/ui/menu/items/base-item.d.ts new file mode 100644 index 0000000..61e75da --- /dev/null +++ b/framework/ui/menu/items/base-item.d.ts @@ -0,0 +1,13 @@ +import * as EventEmitter from 'eventemitter3'; +export declare class BaseItem extends EventEmitter { + protected id: string; + protected title: string; + protected container: HTMLElement; + constructor(id: string, title: string); + getDOMNode(): HTMLElement; + getContents(): void; + protected onFocus(event: Event): void; + focus(): void; + click(): void; + getID(): string; +} diff --git a/framework/ui/menu/items/base-item.js b/framework/ui/menu/items/base-item.js new file mode 100644 index 0000000..a530a0a --- /dev/null +++ b/framework/ui/menu/items/base-item.js @@ -0,0 +1,29 @@ +import * as EventEmitter from 'eventemitter3'; +export class BaseItem extends EventEmitter { + constructor(id, title) { + super(); + this.id = id; + this.title = title; + } + getDOMNode() { + let node = document.createTextNode(this.title); + let element = document.createElement('div'); + element.appendChild(node); + return element; + } + getContents() { + return; + } + onFocus(event) { + this.emit('focus', this.id); + } + focus() { + this.container && this.container.focus(); + } + click() { + return; + } + getID() { + return this.id; + } +} diff --git a/framework/ui/menu/items/checkbox-item.d.ts b/framework/ui/menu/items/checkbox-item.d.ts new file mode 100644 index 0000000..fccd1e6 --- /dev/null +++ b/framework/ui/menu/items/checkbox-item.d.ts @@ -0,0 +1,10 @@ +import { BaseItem } from './base-item'; +export declare class CheckboxItem extends BaseItem { + private checkboxElement; + private label; + constructor(id: string, title: string); + getDOMNode(): HTMLElement; + getContents(): boolean; + private onChange; + focus(): void; +} diff --git a/framework/ui/menu/items/checkbox-item.js b/framework/ui/menu/items/checkbox-item.js new file mode 100644 index 0000000..fc29f0a --- /dev/null +++ b/framework/ui/menu/items/checkbox-item.js @@ -0,0 +1,32 @@ +import { BaseItem } from './base-item'; +export class CheckboxItem extends BaseItem { + constructor(id, title) { + super(id, title); + } + getDOMNode() { + this.container = document.createElement('div'); + this.label = document.createElement('label'); + this.label.setAttribute('for', `chkbx_${this.id}`); + this.label.textContent = this.title; + this.checkboxElement = document.createElement('input'); + this.checkboxElement.setAttribute('type', 'checkbox'); + this.checkboxElement.setAttribute('id', `chkbx_${this.id}`); + this.checkboxElement.addEventListener('focus', this.onFocus.bind(this)); + this.checkboxElement.addEventListener('change', this.onChange.bind(this)); + this.container.appendChild(this.label); + this.container.appendChild(this.checkboxElement); + return this.container; + } + getContents() { + return this.checkboxElement.checked; + } + onChange(event) { + this.emit('update', { + type: 'checkbox', + value: this.checkboxElement.checked + }); + } + focus() { + this.checkboxElement.focus(); + } +} diff --git a/framework/ui/menu/items/edit-item.d.ts b/framework/ui/menu/items/edit-item.d.ts new file mode 100644 index 0000000..0e539f9 --- /dev/null +++ b/framework/ui/menu/items/edit-item.d.ts @@ -0,0 +1,13 @@ +import { BaseItem } from './base-item'; +export declare class EditItem extends BaseItem { + private initialText; + private isPassword; + private contents; + private label; + private editField; + constructor(id: string, title: string, initialText: string, isPassword?: boolean); + getDOMNode(): HTMLElement; + getContents(): string; + private onChange; + focus(): void; +} diff --git a/framework/ui/menu/items/edit-item.js b/framework/ui/menu/items/edit-item.js new file mode 100644 index 0000000..6376c46 --- /dev/null +++ b/framework/ui/menu/items/edit-item.js @@ -0,0 +1,42 @@ +import { BaseItem } from './base-item'; +export class EditItem extends BaseItem { + constructor(id, title, initialText, isPassword = false) { + super(id, title); + this.initialText = initialText; + this.isPassword = isPassword; + this.contents = initialText; + } + getDOMNode() { + const node = document.createElement('div'); + const label = document.createElement('label'); + label.setAttribute('for', `edit_${this.id}`); + label.textContent = this.title; + const editField = document.createElement('input'); + editField.id = `edit_${this.id}`; + editField.value = this.contents; + editField.addEventListener('keydown', this.onChange.bind(this)); + editField.addEventListener('focus', this.onFocus.bind(this)); + if (this.isPassword) { + editField.type = 'password'; + } + node.appendChild(label); + node.appendChild(editField); + node.addEventListener('focus', this.onFocus.bind(this)); + this.editField = editField; + this.label = label; + this.container = node; + return node; + } + getContents() { + return this.editField.value; + } + onChange(event) { + this.emit('update', { + type: 'edit', + value: this.editField.value + }); + } + focus() { + this.editField && this.editField.focus(); + } +} diff --git a/framework/ui/menu/items/index.d.ts b/framework/ui/menu/items/index.d.ts new file mode 100644 index 0000000..6f7e42e --- /dev/null +++ b/framework/ui/menu/items/index.d.ts @@ -0,0 +1,6 @@ +export { BaseItem } from './base-item'; +export { EditItem } from './edit-item'; +export { MenuItem } from './menu-item'; +export { SelectorItem } from './selector-item'; +export { SliderItem } from './slider-item'; +export { CheckboxItem } from './checkbox-item'; diff --git a/framework/ui/menu/items/index.js b/framework/ui/menu/items/index.js new file mode 100644 index 0000000..6f7e42e --- /dev/null +++ b/framework/ui/menu/items/index.js @@ -0,0 +1,6 @@ +export { BaseItem } from './base-item'; +export { EditItem } from './edit-item'; +export { MenuItem } from './menu-item'; +export { SelectorItem } from './selector-item'; +export { SliderItem } from './slider-item'; +export { CheckboxItem } from './checkbox-item'; diff --git a/framework/ui/menu/items/menu-item.d.ts b/framework/ui/menu/items/menu-item.d.ts new file mode 100644 index 0000000..2f4345f --- /dev/null +++ b/framework/ui/menu/items/menu-item.d.ts @@ -0,0 +1,10 @@ +import { BaseItem } from './base-item'; +export declare class MenuItem extends BaseItem { + private button; + constructor(id: string, title: string); + getDOMNode(): HTMLElement; + getContents(): string; + private handleClick; + focus(): void; + click(): void; +} diff --git a/framework/ui/menu/items/menu-item.js b/framework/ui/menu/items/menu-item.js new file mode 100644 index 0000000..a3848e8 --- /dev/null +++ b/framework/ui/menu/items/menu-item.js @@ -0,0 +1,29 @@ +import { BaseItem } from './base-item'; +export class MenuItem extends BaseItem { + constructor(id, title) { + super(id, title); + } + getDOMNode() { + const container = document.createElement('div'); + const button = document.createElement('button'); + button.textContent = this.title; + button.addEventListener('click', this.handleClick.bind(this)); + button.addEventListener('focus', this.onFocus.bind(this)); + container.appendChild(button); + this.container = container; + this.button = button; + return container; + } + getContents() { + return this.id; + } + handleClick(event) { + this.emit('choose', this.id); + } + focus() { + this.button && this.button.focus(); + } + click() { + this.button.click(); + } +} diff --git a/framework/ui/menu/items/selector-item.d.ts b/framework/ui/menu/items/selector-item.d.ts new file mode 100644 index 0000000..d88271d --- /dev/null +++ b/framework/ui/menu/items/selector-item.d.ts @@ -0,0 +1,21 @@ +import { BaseItem } from './base-item'; +export declare class SelectorItem extends BaseItem { + private items; + private listContainer; + private fieldSet; + private label; + private entries; + private currentValue; + constructor(id: string, title: string, items: SelectorEntry[]); + getDOMNode(): HTMLElement; + private buildEntries; + private onItemFocus; + getContents(): any; + private onSelectItem; + private onChangeItem; + focus(): void; +} +export interface SelectorEntry { + id: string; + title: string; +} diff --git a/framework/ui/menu/items/selector-item.js b/framework/ui/menu/items/selector-item.js new file mode 100644 index 0000000..e958501 --- /dev/null +++ b/framework/ui/menu/items/selector-item.js @@ -0,0 +1,62 @@ +import { BaseItem } from './base-item'; +export class SelectorItem extends BaseItem { + constructor(id, title, items) { + super(id, title); + this.items = items; + this.entries = []; + } + getDOMNode() { + this.container = document.createElement('div'); + this.listContainer = document.createElement('ul'); + this.label = document.createElement('legend'); + this.fieldSet = document.createElement('fieldset'); + this.fieldSet.setAttribute('class', 'radiogroup'); + this.fieldSet.id = `fs_selector_${this.id}`; + const name = document.createTextNode(this.title); + this.label.appendChild(name); + this.fieldSet.appendChild(this.label); + this.buildEntries(); + this.container.appendChild(this.fieldSet); + this.container.addEventListener('focus', this.onFocus.bind(this)); + return this.container; + } + buildEntries() { + this.items.forEach((item, index) => { + const node = document.createElement('input'); + node.type = 'radio'; + node.id = `${this.id}_${item.id}`; + node.name = this.id; + node.value = item.id || `${index}`; + node.addEventListener('focus', this.onItemFocus.bind(this)); + node.addEventListener('select', this.onSelectItem.bind(this)); + node.addEventListener('change', this.onChangeItem.bind(this)); + this.entries.push(node); + const label = document.createElement('label'); + label.setAttribute('for', `${this.id}_${item.id}`); + label.textContent = item.title; + this.fieldSet.append(node); + this.fieldSet.append(label); + }); + } + onItemFocus(event) { + console.log(`Item focused: `, event); + this.emit('focus', this.id); + } + getContents() { + return this.currentValue; + } + onSelectItem(event) { } + onChangeItem(event) { + const node = document.querySelector(`input[name = "${this.id}"]:checked`); + this.currentValue = this.items.find((item) => `${this.id}_${item.id}` === node.id); + this.emit('update', { + type: 'selector', + value: this.currentValue + }); + } + focus() { + const node = document.querySelector(`input[name = "${this.id}"]:checked`) || + this.entries[0]; + node.focus(); + } +} diff --git a/framework/ui/menu/items/slider-item.d.ts b/framework/ui/menu/items/slider-item.d.ts new file mode 100644 index 0000000..9498c69 --- /dev/null +++ b/framework/ui/menu/items/slider-item.d.ts @@ -0,0 +1,15 @@ +import { BaseItem } from './base-item'; +export declare class SliderItem extends BaseItem { + private min; + private max; + private step; + private defaultValue; + private slider; + private label; + private currentValue; + constructor(id: string, title: string, min: number, max: number, step: number, defaultValue?: number); + getDOMNode(): HTMLElement; + getContents(): string; + private onChange; + focus(): void; +} diff --git a/framework/ui/menu/items/slider-item.js b/framework/ui/menu/items/slider-item.js new file mode 100644 index 0000000..9f85da7 --- /dev/null +++ b/framework/ui/menu/items/slider-item.js @@ -0,0 +1,42 @@ +import { BaseItem } from './base-item'; +export class SliderItem extends BaseItem { + constructor(id, title, min, max, step, defaultValue = null) { + super(id, title); + this.min = min; + this.max = max; + this.step = step; + this.defaultValue = defaultValue; + } + getDOMNode() { + this.container = document.createElement('div'); + this.label = document.createElement('label'); + this.label.textContent = this.title; + this.label.setAttribute('for', `slider_${this.id}`); + this.slider = document.createElement('input'); + this.slider.id = `slider_${this.id}`; + this.slider.type = 'range'; + this.slider.setAttribute('min', this.min.toString()); + this.slider.setAttribute('max', this.max.toString()); + this.slider.setAttribute('step', this.step.toString()); + if (this.defaultValue) + this.slider.value = this.defaultValue.toString(); + this.slider.addEventListener('change', this.onChange.bind(this)); + this.slider.addEventListener('focus', this.onFocus.bind(this)); + this.container.appendChild(this.label); + this.container.appendChild(this.slider); + this.container.addEventListener('focus', this.onFocus.bind(this)); + return this.container; + } + getContents() { + return this.slider.value; + } + onChange(event) { + this.emit('update', { + type: 'slider', + value: this.slider.value + }); + } + focus() { + this.slider && this.slider.focus(); + } +} diff --git a/framework/ui/menu/keyboard-manager.d.ts b/framework/ui/menu/keyboard-manager.d.ts new file mode 100644 index 0000000..cc01943 --- /dev/null +++ b/framework/ui/menu/keyboard-manager.d.ts @@ -0,0 +1,8 @@ +import { Menu } from '.'; +export declare class KeyboardManager { + private menu; + constructor(menu: Menu); + init(): void; + private handler; + release(): void; +} diff --git a/framework/ui/menu/keyboard-manager.js b/framework/ui/menu/keyboard-manager.js new file mode 100644 index 0000000..de38169 --- /dev/null +++ b/framework/ui/menu/keyboard-manager.js @@ -0,0 +1,40 @@ +export class KeyboardManager { + constructor(menu) { + this.menu = menu; + } + init() { + this.menu + .getContainer() + .addEventListener('keydown', this.handler.bind(this)); + // This trick let's us detect the press of the back or forward buttons to exit out of the menu. + window.onpopstate = () => this.menu.clickCancelAction(); + } + handler(event) { + switch (event.key) { + case 'ArrowDown': + event.preventDefault(); + this.menu.focusNext(); + break; + case 'ArrowUp': + event.preventDefault(); + this.menu.focusPrevious(); + break; + case 'Enter': + event.preventDefault(); + this.menu.clickDefaultAction(); + break; + case 'Escape': + event.preventDefault(); + this.menu.clickCancelAction(); + break; + default: + break; + } + } + release() { + this.menu + .getContainer() + .removeEventListener('keydown', this.handler.bind(this)); + window.onpopstate = null; + } +} diff --git a/framework/ui/menu/menu.d.ts b/framework/ui/menu/menu.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/framework/ui/menu/menu.js b/framework/ui/menu/menu.js new file mode 100644 index 0000000..e69de29 diff --git a/framework/ui/menu/sound-manager.d.ts b/framework/ui/menu/sound-manager.d.ts new file mode 100644 index 0000000..18cd6fe --- /dev/null +++ b/framework/ui/menu/sound-manager.d.ts @@ -0,0 +1,16 @@ +import { SoundSet } from './interfaces/sound-set'; +export declare class SoundManager { + private soundSet; + private data; + constructor(soundSet?: SoundSet); + setSoundSet(soundSet: SoundSet): void; + handleSound(type: string, data?: any): void; + private handleEditSound; + private handleSelectorSound; + private handleSliderSound; + private handleFocusSound; + private handleOpenSound; + private handleCloseSound; + private handleChooseSound; + private handleCheckboxSound; +} diff --git a/framework/ui/menu/sound-manager.js b/framework/ui/menu/sound-manager.js new file mode 100644 index 0000000..536f779 --- /dev/null +++ b/framework/ui/menu/sound-manager.js @@ -0,0 +1,84 @@ +export class SoundManager { + constructor(soundSet = null) { + this.soundSet = null; + this.data = new Map(); + this.soundSet = soundSet; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + } + handleSound(type, data = null) { + switch (type) { + case 'edit': + this.handleEditSound(data); + break; + case 'slider': + this.handleSliderSound(data); + break; + case 'selector': + this.handleSelectorSound(data); + break; + case 'checkbox': + this.handleCheckboxSound(data); + break; + case 'focus': + this.handleFocusSound(); + break; + case 'choose': + this.handleChooseSound(); + break; + case 'open': + this.handleOpenSound(); + break; + case 'close': + this.handleCloseSound(); + break; + default: + return; + break; + } + } + handleEditSound(data) { + const prevData = this.data.get('edit') || ''; + if (data.length <= prevData.length) { + this.soundSet.delete && this.soundSet.delete.play(); + } + else { + this.soundSet.char && this.soundSet.char.play(); + } + this.data.set('edit', data); + } + handleSelectorSound(data) { + this.soundSet.scroller && this.soundSet.scroller.play(); + } + handleSliderSound(data) { + const prevData = this.data.get('slider'); + if (data < prevData) { + this.soundSet.sliderLeft && this.soundSet.sliderLeft.play(); + } + else { + this.soundSet.sliderRight && this.soundSet.sliderRight.play(); + } + this.data.set('slider', data); + } + handleFocusSound() { + this.soundSet.move && this.soundSet.move.play(); + } + handleOpenSound() { + this.soundSet.open && this.soundSet.open.play(); + } + handleCloseSound() { + this.soundSet.close && this.soundSet.close.play(); + } + handleChooseSound() { + this.soundSet.choose && this.soundSet.choose.play(); + } + handleCheckboxSound(data) { + if (data === true) { + this.soundSet.checked && this.soundSet.checked.play(); + } + else { + this.soundSet.unchecked && this.soundSet.unchecked.play(); + } + } +} diff --git a/framework/ui/text/index.d.ts b/framework/ui/text/index.d.ts new file mode 100644 index 0000000..496017b --- /dev/null +++ b/framework/ui/text/index.d.ts @@ -0,0 +1,28 @@ +import * as EventEmitter from 'eventemitter3'; +import { SoundSet } from '../menu/interfaces/sound-set'; +import { Line } from './line'; +export declare class ScrollingText extends EventEmitter { + private text; + private delimiter; + private soundSet; + private appearingCharacters; + private characterAppearSpeed; + private currentLineIndex; + private currentLine; + private lines; + private wrapper; + private container; + private soundManager; + private keyboardManager; + constructor(text?: string, delimiter?: string, soundSet?: SoundSet, appearingCharacters?: boolean, characterAppearSpeed?: number); + setText(text: string): this; + setSoundSet(soundSet: SoundSet): this; + setDelimiter(delimiter: string): this; + setAppearingCharacters(appearing: boolean): this; + setAppearingCharacterSpeed(speed: number): this; + init(): void; + run(element: HTMLElement): Promise; + displayLine(index: number): Promise; + getContainer(): HTMLElement; + getCurrentLine(): Line; +} diff --git a/framework/ui/text/index.js b/framework/ui/text/index.js new file mode 100644 index 0000000..4ea0f2d --- /dev/null +++ b/framework/ui/text/index.js @@ -0,0 +1,102 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import * as EventEmitter from 'eventemitter3'; +import { Line } from './line'; +import { SoundManager } from './sound-manager'; +import { KeyboardManager } from './keyboard-manager'; +export class ScrollingText extends EventEmitter { + constructor(text = null, delimiter = '\n', soundSet = null, appearingCharacters = false, characterAppearSpeed = 0) { + super(); + this.text = text; + this.delimiter = delimiter; + this.soundSet = soundSet; + this.appearingCharacters = appearingCharacters; + this.characterAppearSpeed = characterAppearSpeed; + this.lines = []; + this.soundManager = new SoundManager(this, this.soundSet); + this.keyboardManager = new KeyboardManager(this); + this.init(); + } + setText(text) { + this.text = text; + this.init(); + return this; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + this.init(); + this.soundManager.setSoundSet(this.soundSet); + return this; + } + setDelimiter(delimiter) { + this.delimiter = delimiter; + this.init(); + return this; + } + setAppearingCharacters(appearing) { + this.appearingCharacters = appearing; + this.init(); + return this; + } + setAppearingCharacterSpeed(speed) { + this.characterAppearSpeed = speed; + this.init(); + return this; + } + init() { + const split = this.text.split(this.delimiter); + this.lines = split.map((line) => new Line(line)); + } + run(element) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { + this.wrapper = document.createElement('div'); + this.wrapper.setAttribute('aria-role', 'polite'); + this.container = document.createElement('div'); + this.wrapper.appendChild(this.container); + element.appendChild(this.wrapper); + this.soundManager.init(); + this.keyboardManager.init(); + this.emit('open'); + let index = 0; + this.currentLineIndex = 0; + while (index < this.lines.length) { + this.currentLineIndex = index; + yield this.displayLine(index); + index++; + } + this.emit('close'); + this.keyboardManager.release(); + this.container.remove(); + resolve(); + })); + }); + } + displayLine(index) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + this.container.innerHTML = ''; + this.container.appendChild(this.lines[index].getDOMNode()); + this.lines[index].display(this.container, this.appearingCharacters, this.characterAppearSpeed); + this.lines[index].on('character.appear', (event) => this.emit('character.appear', event)); + this.lines[index].on('advance', () => { + this.emit('advance'); + resolve(); + }); + }); + }); + } + getContainer() { + return this.wrapper; + } + getCurrentLine() { + return this.lines[this.currentLineIndex]; + } +} diff --git a/framework/ui/text/interfaces/playable-sound.d.ts b/framework/ui/text/interfaces/playable-sound.d.ts new file mode 100644 index 0000000..34bdc03 --- /dev/null +++ b/framework/ui/text/interfaces/playable-sound.d.ts @@ -0,0 +1,3 @@ +export interface IPlayableSound { + play(): any; +} diff --git a/framework/ui/text/interfaces/playable-sound.js b/framework/ui/text/interfaces/playable-sound.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/ui/text/interfaces/playable-sound.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/ui/text/interfaces/sound-set.d.ts b/framework/ui/text/interfaces/sound-set.d.ts new file mode 100644 index 0000000..1a729cd --- /dev/null +++ b/framework/ui/text/interfaces/sound-set.d.ts @@ -0,0 +1,7 @@ +import { IPlayableSound } from './playable-sound'; +export interface SoundSet { + open?: IPlayableSound; + close?: IPlayableSound; + scroll?: IPlayableSound; + characterAppear?: IPlayableSound; +} diff --git a/framework/ui/text/interfaces/sound-set.js b/framework/ui/text/interfaces/sound-set.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/ui/text/interfaces/sound-set.js @@ -0,0 +1 @@ +export {}; diff --git a/framework/ui/text/keyboard-manager.d.ts b/framework/ui/text/keyboard-manager.d.ts new file mode 100644 index 0000000..829a9ca --- /dev/null +++ b/framework/ui/text/keyboard-manager.d.ts @@ -0,0 +1,8 @@ +import { ScrollingText } from '.'; +export declare class KeyboardManager { + private scrollingText; + constructor(scrollingText: ScrollingText); + init(): void; + release(): void; + private handler; +} diff --git a/framework/ui/text/keyboard-manager.js b/framework/ui/text/keyboard-manager.js new file mode 100644 index 0000000..44c744c --- /dev/null +++ b/framework/ui/text/keyboard-manager.js @@ -0,0 +1,25 @@ +export class KeyboardManager { + constructor(scrollingText) { + this.scrollingText = scrollingText; + } + init() { + this.scrollingText + .getContainer() + .addEventListener('keydown', (event) => this.handler(event)); + } + release() { + this.scrollingText + .getContainer() + .removeEventListener('keydown', (event) => this.handler(event)); + } + handler(event) { + switch (event.key) { + case 'Enter': + event.preventDefault(); + this.scrollingText.getCurrentLine().getAdvanceButton().click(); + break; + default: + break; + } + } +} diff --git a/framework/ui/text/line.d.ts b/framework/ui/text/line.d.ts new file mode 100644 index 0000000..c0bc52f --- /dev/null +++ b/framework/ui/text/line.d.ts @@ -0,0 +1,13 @@ +import * as EventEmitter from 'eventemitter3'; +export declare class Line extends EventEmitter { + private text; + private container; + private textField; + private advanceButton; + private active; + constructor(text: string); + getDOMNode(): HTMLElement; + display(element: HTMLElement, appearingCharacters?: boolean, appearingCharacterSpeed?: number): void; + private fillText; + getAdvanceButton(): HTMLElement; +} diff --git a/framework/ui/text/line.js b/framework/ui/text/line.js new file mode 100644 index 0000000..eacb5d8 --- /dev/null +++ b/framework/ui/text/line.js @@ -0,0 +1,45 @@ +import * as EventEmitter from 'eventemitter3'; +export class Line extends EventEmitter { + constructor(text) { + super(); + this.text = text; + this.active = false; + } + getDOMNode() { + this.container = document.createElement('div'); + this.container.setAttribute('aria-role', 'polite'); + this.textField = document.createElement('div'); + this.container.appendChild(this.textField); + this.advanceButton = document.createElement('button'); + this.advanceButton.textContent = 'Advance'; + this.advanceButton.addEventListener('click', (event) => { + this.emit('advance'); + this.active = false; + }); + this.container.appendChild(this.advanceButton); + return this.container; + } + display(element, appearingCharacters = false, appearingCharacterSpeed = 0) { + this.active = true; + this.textField.focus(); + if (!appearingCharacters) { + this.textField.textContent = this.text; + } + else { + this.fillText(0, appearingCharacterSpeed); + } + } + fillText(index, speed) { + if (!this.active) + return; + if (index > this.text.length) { + return; + } + this.textField.textContent += this.text.charAt(index); + this.emit('character.appear', this.textField.textContent); + setTimeout(() => this.fillText((index += 1), speed), speed); + } + getAdvanceButton() { + return this.advanceButton; + } +} diff --git a/framework/ui/text/sound-manager.d.ts b/framework/ui/text/sound-manager.d.ts new file mode 100644 index 0000000..cad51ae --- /dev/null +++ b/framework/ui/text/sound-manager.d.ts @@ -0,0 +1,13 @@ +import { SoundSet } from './interfaces/sound-set'; +import { ScrollingText } from '.'; +export declare class SoundManager { + private instance; + private soundSet; + constructor(instance: ScrollingText, soundSet: SoundSet); + setSoundSet(soundSet: SoundSet): void; + init(): void; + private handleOpen; + private handleCharacterAppear; + private handleAdvance; + private handleClose; +} diff --git a/framework/ui/text/sound-manager.js b/framework/ui/text/sound-manager.js new file mode 100644 index 0000000..f08810f --- /dev/null +++ b/framework/ui/text/sound-manager.js @@ -0,0 +1,27 @@ +export class SoundManager { + constructor(instance, soundSet) { + this.instance = instance; + this.soundSet = soundSet; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + } + init() { + this.instance.on('character.appear', this.handleCharacterAppear.bind(this)); + this.instance.on('open', this.handleOpen.bind(this)); + this.instance.on('close', this.handleClose.bind(this)); + this.instance.on('advance', this.handleAdvance.bind(this)); + } + handleOpen() { + this.soundSet.open && this.soundSet.open.play(); + } + handleCharacterAppear() { + this.soundSet.characterAppear && this.soundSet.characterAppear.play(); + } + handleAdvance() { + this.soundSet.scroll && this.soundSet.scroll.play(); + } + handleClose() { + this.soundSet.close && this.soundSet.close.play(); + } +} diff --git a/src/framework/world/component.d.ts b/framework/world/component.d.ts similarity index 95% rename from src/framework/world/component.d.ts rename to framework/world/component.d.ts index 0de71c4..d09882a 100644 --- a/src/framework/world/component.d.ts +++ b/framework/world/component.d.ts @@ -1,5 +1,5 @@ -export declare class Component { - id: number; - properties: T; - constructor(props: T); -} +export declare class Component { + id: number; + properties: T; + constructor(props: T); +} diff --git a/src/framework/world/component.js b/framework/world/component.js similarity index 94% rename from src/framework/world/component.js rename to framework/world/component.js index 1c31dba..326ebef 100644 --- a/src/framework/world/component.js +++ b/framework/world/component.js @@ -1,5 +1,5 @@ -export class Component { - constructor(props) { - this.properties = props; - } -} +export class Component { + constructor(props) { + this.properties = props; + } +} diff --git a/src/framework/world/ecs-world.d.ts b/framework/world/ecs-world.d.ts similarity index 97% rename from src/framework/world/ecs-world.d.ts rename to framework/world/ecs-world.d.ts index cfdf43d..8ea9a4f 100644 --- a/src/framework/world/ecs-world.d.ts +++ b/framework/world/ecs-world.d.ts @@ -1,24 +1,24 @@ -import { World } from '../ecs/index'; -import { Game } from '../game'; -import { Component } from '../ecs/component'; -import { System } from '../ecs/system'; -import { BaseEntity, Entity } from '../ecs/entity'; -import { Query } from '../ecs/query'; -import { World as IWorld } from '.'; -export declare class ECSWorld implements IWorld { - instance: Game; - id: string; - world: World; - running: boolean; - constructor(instance: Game); - update(): void; - updateDraw(): boolean; - createEntity(components: Array): BaseEntity; - createComponent(props: any): Component; - createSystem(systemExecutor: Function): void; - addSystem(system: System): void; - addEntity(entity: BaseEntity): void; - removeEntity(entity: BaseEntity): void; - createQuery(include: Array, exclude: Array): Query; - extendEntity(entity: Entity, components: Array): BaseEntity; -} +import { World } from '../ecs/index'; +import { Game } from '../game'; +import { Component } from '../ecs/component'; +import { System } from '../ecs/system'; +import { BaseEntity, Entity } from '../ecs/entity'; +import { Query } from '../ecs/query'; +import { World as IWorld } from '.'; +export declare class ECSWorld implements IWorld { + instance: Game; + id: string; + world: World; + running: boolean; + constructor(instance: Game); + update(): void; + updateDraw(): boolean; + createEntity(components: Array): BaseEntity; + createComponent(props: any): Component; + createSystem(systemExecutor: Function): void; + addSystem(system: System): void; + addEntity(entity: BaseEntity): void; + removeEntity(entity: BaseEntity): void; + createQuery(include: Array, exclude: Array): Query; + extendEntity(entity: Entity, components: Array): BaseEntity; +} diff --git a/src/framework/world/ecs-world.js b/framework/world/ecs-world.js similarity index 96% rename from src/framework/world/ecs-world.js rename to framework/world/ecs-world.js index f24b82d..006b5e8 100644 --- a/src/framework/world/ecs-world.js +++ b/framework/world/ecs-world.js @@ -1,40 +1,40 @@ -import { World } from '../ecs/index'; -export class ECSWorld { - constructor(instance) { - this.instance = instance; - this.running = true; - this.id = 'ECSScene'; - this.world = new World(); - } - update() { - if (this.running) - this.world.run(); - } - updateDraw() { - return true; - } - createEntity(components) { - return this.world.createEntity(components); - } - createComponent(props) { - return this.world.createComponent(props); - } - createSystem(systemExecutor) { - return this.world.createSystem(systemExecutor); - } - addSystem(system) { - return this.world.addSystem(system); - } - addEntity(entity) { - this.world.addEntity(entity); - } - removeEntity(entity) { - return this.world.removeEntity(entity); - } - createQuery(include, exclude) { - return this.world.createQuery(include, exclude); - } - extendEntity(entity, components) { - return this.world.extendEntity(entity, components); - } -} +import { World } from '../ecs/index'; +export class ECSWorld { + constructor(instance) { + this.instance = instance; + this.running = true; + this.id = 'ECSScene'; + this.world = new World(); + } + update() { + if (this.running) + this.world.run(); + } + updateDraw() { + return true; + } + createEntity(components) { + return this.world.createEntity(components); + } + createComponent(props) { + return this.world.createComponent(props); + } + createSystem(systemExecutor) { + return this.world.createSystem(systemExecutor); + } + addSystem(system) { + return this.world.addSystem(system); + } + addEntity(entity) { + this.world.addEntity(entity); + } + removeEntity(entity) { + return this.world.removeEntity(entity); + } + createQuery(include, exclude) { + return this.world.createQuery(include, exclude); + } + extendEntity(entity, components) { + return this.world.extendEntity(entity, components); + } +} diff --git a/src/framework/world/entity.d.ts b/framework/world/entity.d.ts similarity index 96% rename from src/framework/world/entity.d.ts rename to framework/world/entity.d.ts index c852bdc..538194f 100644 --- a/src/framework/world/entity.d.ts +++ b/framework/world/entity.d.ts @@ -1,6 +1,6 @@ -import { Component } from "./component"; -export declare class Entity { - id: number; - components: Array>; - constructor(); -} +import { Component } from "./component"; +export declare class Entity { + id: number; + components: Array>; + constructor(); +} diff --git a/src/framework/world/entity.js b/framework/world/entity.js similarity index 94% rename from src/framework/world/entity.js rename to framework/world/entity.js index 81cb671..be1b90a 100644 --- a/src/framework/world/entity.js +++ b/framework/world/entity.js @@ -1,5 +1,5 @@ -export class Entity { - constructor() { - this.components = new Array(); - } -} +export class Entity { + constructor() { + this.components = new Array(); + } +} diff --git a/src/framework/world/event-bus.d.ts b/framework/world/event-bus.d.ts similarity index 96% rename from src/framework/world/event-bus.d.ts rename to framework/world/event-bus.d.ts index 24b52fb..c2fd337 100644 --- a/src/framework/world/event-bus.d.ts +++ b/framework/world/event-bus.d.ts @@ -1,11 +1,11 @@ -export declare class EventBus { - private events; - constructor(); - emit(id: string, data: any): void; - subscribe(id: string, subscriber: Function): void; -} -export declare class EventItem { - id: string; - subscribers: Function[]; - constructor(id: string); -} +export declare class EventBus { + private events; + constructor(); + emit(id: string, data: any): void; + subscribe(id: string, subscriber: Function): void; +} +export declare class EventItem { + id: string; + subscribers: Function[]; + constructor(id: string); +} diff --git a/src/framework/event-bus/event-bus.js b/framework/world/event-bus.js similarity index 95% rename from src/framework/event-bus/event-bus.js rename to framework/world/event-bus.js index 11ee12b..a90b6c1 100644 --- a/src/framework/event-bus/event-bus.js +++ b/framework/world/event-bus.js @@ -1,30 +1,30 @@ -export class EventBus { - constructor() { - this.events = new Map(); - } - emit(id, data) { - let ev = this.events.get(id); - if (!ev) { - let ev = new EventItem(id); - this.events.set(id, ev); - return; - } - ev.subscribers.forEach((subscriber) => { - subscriber(data); - }); - } - subscribe(id, subscriber) { - let ev = this.events.get(id); - if (!ev) { - ev = new EventItem(id); - this.events.set(id, ev); - } - ev.subscribers.push(subscriber); - } -} -export class EventItem { - constructor(id) { - this.id = id; - this.subscribers = []; - } -} +export class EventBus { + constructor() { + this.events = new Map(); + } + emit(id, data) { + let ev = this.events.get(id); + if (!ev) { + let ev = new EventItem(id); + this.events.set(id, ev); + return; + } + ev.subscribers.forEach((subscriber) => { + subscriber(data); + }); + } + subscribe(id, subscriber) { + let ev = this.events.get(id); + if (!ev) { + ev = new EventItem(id); + this.events.set(id, ev); + } + ev.subscribers.push(subscriber); + } +} +export class EventItem { + constructor(id) { + this.id = id; + this.subscribers = []; + } +} diff --git a/framework/world/index.d.ts b/framework/world/index.d.ts new file mode 100644 index 0000000..00098de --- /dev/null +++ b/framework/world/index.d.ts @@ -0,0 +1,3 @@ +export interface World { + update(dt: number): any; +} diff --git a/framework/world/index.js b/framework/world/index.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/framework/world/index.js @@ -0,0 +1 @@ +export {}; diff --git a/src/framework/world/query.d.ts b/framework/world/query.d.ts similarity index 97% rename from src/framework/world/query.d.ts rename to framework/world/query.d.ts index f375754..ae07eee 100644 --- a/src/framework/world/query.d.ts +++ b/framework/world/query.d.ts @@ -1,13 +1,13 @@ -import { World } from "."; -import { Component } from "./component"; -import { Entity } from "./entity"; -export declare class Query { - include: Array>; - exclude: Array>; - private results; - isDirty: boolean; - includeComponentIds: number[]; - excludeComponentIds: number[]; - constructor(include: Array>, exclude: Array>); - execute(world: World): Array; -} +import { World } from "."; +import { Component } from "./component"; +import { Entity } from "./entity"; +export declare class Query { + include: Array>; + exclude: Array>; + private results; + isDirty: boolean; + includeComponentIds: number[]; + excludeComponentIds: number[]; + constructor(include: Array>, exclude: Array>); + execute(world: World): Array; +} diff --git a/src/framework/world/query.js b/framework/world/query.js similarity index 97% rename from src/framework/world/query.js rename to framework/world/query.js index c3099d0..b10eb65 100644 --- a/src/framework/world/query.js +++ b/framework/world/query.js @@ -1,27 +1,27 @@ -export class Query { - constructor(include, exclude) { - this.include = include; - this.exclude = exclude; - this.isDirty = true; - this.results = new Array(); - this.includeComponentIds = include.map((component) => component.id); - this.excludeComponentIds = exclude.map((component) => component.id); - } - execute(world) { - if (!this.isDirty && this.results) { - return this.results; - } - let filtered; - const entities = world.entities.filter(entity => { - let ids = entity.components.map(component => component.id); - let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true); - let excludes = ids.map(id => this.excludeComponentIds.includes(id)).includes(true); - return includes && !excludes; - }); - if (entities.length > 0) { - this.isDirty = false; - this.results = entities; - } - return entities; - } -} +export class Query { + constructor(include, exclude) { + this.include = include; + this.exclude = exclude; + this.isDirty = true; + this.results = new Array(); + this.includeComponentIds = include.map((component) => component.id); + this.excludeComponentIds = exclude.map((component) => component.id); + } + execute(world) { + if (!this.isDirty && this.results) { + return this.results; + } + let filtered; + const entities = world.entities.filter(entity => { + let ids = entity.components.map(component => component.id); + let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true); + let excludes = ids.map(id => this.excludeComponentIds.includes(id)).includes(true); + return includes && !excludes; + }); + if (entities.length > 0) { + this.isDirty = false; + this.results = entities; + } + return entities; + } +} diff --git a/src/framework/world/system.d.ts b/framework/world/system.d.ts similarity index 96% rename from src/framework/world/system.d.ts rename to framework/world/system.d.ts index 0645f89..dcee68b 100644 --- a/src/framework/world/system.d.ts +++ b/framework/world/system.d.ts @@ -1,6 +1,6 @@ -import { World } from "."; -export declare class System { - executor: Function; - constructor(executor: Function); - execute(world: World): void; -} +import { World } from "."; +export declare class System { + executor: Function; + constructor(executor: Function); + execute(world: World): void; +} diff --git a/src/framework/world/system.js b/framework/world/system.js similarity index 95% rename from src/framework/world/system.js rename to framework/world/system.js index f6feb3a..070c64c 100644 --- a/src/framework/world/system.js +++ b/framework/world/system.js @@ -1,8 +1,8 @@ -export class System { - constructor(executor) { } - execute(world) { - if (this.executor) { - this.executor(world); - } - } -} +export class System { + constructor(executor) { } + execute(world) { + if (this.executor) { + this.executor(world); + } + } +} diff --git a/src/engine/room.js b/src/engine/room.js index 9001711..88df23b 100644 --- a/src/engine/room.js +++ b/src/engine/room.js @@ -1,89 +1,89 @@ -export default class Room { - constructor() { - this.id = "room"; - this.title = "A room"; - this.description = "You see nothing special"; - this.firstDescription = ""; - this.objects = []; - this.exits = new Map(); - this.enterCallback = null; - this.exitCallback = null; - this.canEnterLogic = null; - this.canExitLogic = null; - this.tickCallback = null; - this.context = null; - this.music = null; - this.ambience = null; - this.impulse = null; - } - - async onEnter() { - this.context.output.setMusic(this.music); - this.context.output.setAmbience(this.ambience); - this.context.output.setImpulse(this.impulse); - if (this.enterCallback) return this.enterCallback(this.context); - } - - async onExit() { - if (this.exitCallback) return this.exitCallback(this.context); - } - - canEnter() { - if (this.canEnterLogic) { - return this.canEnterLogic(this.context); - } - return true; - } - - canExit() { - if (this.canExitLogic) { - return this.canExitLogic(this.context); - } - return true; - } - - addExit(direction, roomID) { - this.exits.set(direction, roomID); - return this; - } - - getExit(direction) { - return this.exits.get(direction); - } - - addItem(item) { - this.objects.push(item); - } - - removeItem(id) { - this.objects = this.objects.filter((item) => item != id); - } - - addEnterCallback(callback) { - this.enterCallback = callback.bind(this); - } - - addExitCallback(callback) { - this.exitCallback = callback.bind(this); - } - - addEnterLogic(func) { - this.canEnterLogic = func.bind(this); - } - - addExitLogic(func) { - this.canExitLogic = func.bind(this); - } - - addTickCallback(callback) { - this.tickCallback = callback.bind(this); - } - - getItems() { - return this.objects.map((item) => this.context.getItem(item)); - } - - async onTick() { - if (this.tickCallback) return this.tickCallback(this.context); - } +export default class Room { + constructor() { + this.id = "room"; + this.title = "A room"; + this.description = "You see nothing special"; + this.firstDescription = ""; + this.objects = []; + this.exits = new Map(); + this.enterCallback = null; + this.exitCallback = null; + this.canEnterLogic = null; + this.canExitLogic = null; + this.tickCallback = null; + this.context = null; + this.music = null; + this.ambience = null; + this.impulse = null; + } + + async onEnter() { + this.context.output.setMusic(this.music); + this.context.output.setAmbience(this.ambience); + this.context.output.setImpulse(this.impulse); + if (this.enterCallback) return this.enterCallback(this.context); + } + + async onExit() { + if (this.exitCallback) return this.exitCallback(this.context); + } + + canEnter() { + if (this.canEnterLogic) { + return this.canEnterLogic(this.context); + } + return true; + } + + canExit() { + if (this.canExitLogic) { + return this.canExitLogic(this.context); + } + return true; + } + + addExit(direction, roomID) { + this.exits.set(direction, roomID); + return this; + } + + getExit(direction) { + return this.exits.get(direction); + } + + addItem(item) { + this.objects.push(item); + } + + removeItem(id) { + this.objects = this.objects.filter((item) => item != id); + } + + addEnterCallback(callback) { + this.enterCallback = callback.bind(this); + } + + addExitCallback(callback) { + this.exitCallback = callback.bind(this); + } + + addEnterLogic(func) { + this.canEnterLogic = func.bind(this); + } + + addExitLogic(func) { + this.canExitLogic = func.bind(this); + } + + addTickCallback(callback) { + this.tickCallback = callback.bind(this); + } + + getItems() { + return this.objects.map((item) => this.context.getItem(item)); + } + + async onTick() { + if (this.tickCallback) return this.tickCallback(this.context); + } } \ No newline at end of file diff --git a/src/framework/asset-manager/downloader.d.ts b/src/framework/asset-manager/downloader.d.ts index e29dacb..e953c13 100644 --- a/src/framework/asset-manager/downloader.d.ts +++ b/src/framework/asset-manager/downloader.d.ts @@ -1,12 +1,12 @@ -import EventEmitter from 'eventemitter3'; -import { Queue } from './queue'; -import { AssetStorage } from './storage'; -export declare class Downloader extends EventEmitter { - private storage; - private queue; - private basePath; - constructor(storage: AssetStorage, queue: Queue, basePath?: string); - setBasePath(path: string): void; - download(): Promise; - downloadItem(path: string): Promise; -} +import { EventBus } from '../event-bus'; +import { Queue } from './queue'; +import { AssetStorage } from './storage'; +export declare class Downloader extends EventBus { + private storage; + private queue; + private basePath; + constructor(storage: AssetStorage, queue: Queue, basePath?: string); + setBasePath(path: string): void; + download(): Promise; + downloadItem(path: string): Promise; +} diff --git a/src/framework/asset-manager/downloader.js b/src/framework/asset-manager/downloader.js index 735fc35..ca569b2 100644 --- a/src/framework/asset-manager/downloader.js +++ b/src/framework/asset-manager/downloader.js @@ -1,50 +1,50 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import EventEmitter from 'eventemitter3'; -import { buildPath } from './utils'; -export class Downloader extends EventEmitter { - constructor(storage, queue, basePath = '') { - super(); - this.storage = storage; - this.queue = queue; - this.basePath = basePath; - } - setBasePath(path) { - this.basePath = this.basePath; - } - download() { - return __awaiter(this, void 0, void 0, function* () { - const downloaded = new Map(); - let numDownloaded = 0; - while (this.queue.length() > 0) { - const path = this.queue.pop(); - const item = yield this.downloadItem(buildPath(this.basePath, path)); - downloaded.set(path, item); - numDownloaded++; - this.emit('download.progress', { - downloaded: numDownloaded, - remaining: this.queue.length() - }); - } - return downloaded; - }); - } - downloadItem(path) { - return __awaiter(this, void 0, void 0, function* () { - const inCache = yield this.storage.get(path); - if (inCache) { - return inCache; - } - const response = yield fetch(path); - this.storage.add(path, response); - return response; - }); - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { EventBus } from '../event-bus'; +import { buildPath } from './utils'; +export class Downloader extends EventBus { + constructor(storage, queue, basePath = '') { + super(); + this.storage = storage; + this.queue = queue; + this.basePath = basePath; + } + setBasePath(path) { + this.basePath = this.basePath; + } + download() { + return __awaiter(this, void 0, void 0, function* () { + const downloaded = new Map(); + let numDownloaded = 0; + while (this.queue.length() > 0) { + const path = this.queue.pop(); + const item = yield this.downloadItem(buildPath(this.basePath, path)); + downloaded.set(path, item); + numDownloaded++; + this.emit('download.progress', { + downloaded: numDownloaded, + remaining: this.queue.length() + }); + } + return downloaded; + }); + } + downloadItem(path) { + return __awaiter(this, void 0, void 0, function* () { + const inCache = yield this.storage.get(path); + if (inCache) { + return inCache; + } + const response = yield fetch(path); + this.storage.add(path, response); + return response; + }); + } +} diff --git a/src/framework/asset-manager/index.d.ts b/src/framework/asset-manager/index.d.ts index a5207df..e363c6e 100644 --- a/src/framework/asset-manager/index.d.ts +++ b/src/framework/asset-manager/index.d.ts @@ -1,18 +1,18 @@ -import EventEmitter from 'eventemitter3'; -export declare class AssetManager extends EventEmitter { - private name; - private basePath; - private downloader; - private queue; - private storage; - private manifest; - constructor(name: string, basePath: string); - init(): Promise; - setManifest(path: string): Promise; - enqueue(path: string): void; - download(): Promise; - downloadFromManifest(key: string): Promise; - downloadFile(path: string): Promise; - setBasePath(path: string): void; - clearCache(): void; -} +import { EventBus } from '../event-bus'; +export declare class AssetManager extends EventBus { + private name; + private basePath; + private downloader; + private queue; + private storage; + private manifest; + constructor(name: string, basePath: string); + init(): Promise; + setManifest(path: string): Promise; + enqueue(path: string): void; + download(): Promise; + downloadFromManifest(key: string): Promise; + downloadFile(path: string): Promise; + setBasePath(path: string): void; + clearCache(): void; +} diff --git a/src/framework/asset-manager/index.js b/src/framework/asset-manager/index.js index 2428bea..bb4e908 100644 --- a/src/framework/asset-manager/index.js +++ b/src/framework/asset-manager/index.js @@ -1,71 +1,71 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import { Downloader } from './downloader'; -import { Queue } from './queue'; -import { Manifest } from './manifest'; -import { AssetStorage } from './storage'; -import EventEmitter from 'eventemitter3'; -import { buildPath } from './utils'; -export class AssetManager extends EventEmitter { - constructor(name, basePath) { - super(); - this.name = name; - this.basePath = basePath; - this.queue = new Queue(); - this.storage = new AssetStorage(name); - this.downloader = new Downloader(this.storage, this.queue, this.basePath); - console.log(`Asset manager initialized`); - } - init() { - return __awaiter(this, void 0, void 0, function* () { - yield this.storage.init(); - return true; - }); - } - setManifest(path) { - return __awaiter(this, void 0, void 0, function* () { - this.manifest = yield Manifest(`${this.basePath}/${path}`); - this.storage.setManifest(this.manifest); - return this.manifest; - }); - } - enqueue(path) { - this.queue.add(path); - } - download() { - return __awaiter(this, void 0, void 0, function* () { - const result = yield this.downloader.download(); - return result; - }); - } - downloadFromManifest(key) { - return __awaiter(this, void 0, void 0, function* () { - const paths = this.manifest[key]; - paths.forEach((path) => this.enqueue(path)); - this.downloader.on('download.progress', (info) => this.emit('progress', info)); - const files = yield this.downloader.download(); - this.downloader.off('download.progress'); - return files; - }); - } - downloadFile(path) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield this.downloader.downloadItem(buildPath(this.basePath, path)); - return result; - }); - } - setBasePath(path) { - this.basePath = this.basePath; - this.downloader.setBasePath(this.basePath); - } - clearCache() { - this.storage.clear(); - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { Downloader } from './downloader'; +import { Queue } from './queue'; +import { Manifest } from './manifest'; +import { AssetStorage } from './storage'; +import { EventBus } from '../event-bus'; +import { buildPath } from './utils'; +export class AssetManager extends EventBus { + constructor(name, basePath) { + super(); + this.name = name; + this.basePath = basePath; + this.queue = new Queue(); + this.storage = new AssetStorage(name); + this.downloader = new Downloader(this.storage, this.queue, this.basePath); + console.log(`Asset manager initialized`); + } + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this.storage.init(); + return true; + }); + } + setManifest(path) { + return __awaiter(this, void 0, void 0, function* () { + this.manifest = yield Manifest(`${this.basePath}/${path}`); + this.storage.setManifest(this.manifest); + return this.manifest; + }); + } + enqueue(path) { + this.queue.add(path); + } + download() { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.downloader.download(); + return result; + }); + } + downloadFromManifest(key) { + return __awaiter(this, void 0, void 0, function* () { + const paths = this.manifest[key]; + paths.forEach((path) => this.enqueue(path)); + this.downloader.subscribe('download.progress', (info) => this.emit('progress', info)); + const files = yield this.downloader.download(); + this.downloader.unsubscribeAll('download.progress'); + return files; + }); + } + downloadFile(path) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.downloader.downloadItem(buildPath(this.basePath, path)); + return result; + }); + } + setBasePath(path) { + this.basePath = path; + this.downloader.setBasePath(this.basePath); + } + clearCache() { + this.storage.clear(); + } +} diff --git a/src/framework/asset-manager/manifest.d.ts b/src/framework/asset-manager/manifest.d.ts index f4a36bf..f6d92c5 100644 --- a/src/framework/asset-manager/manifest.d.ts +++ b/src/framework/asset-manager/manifest.d.ts @@ -1,2 +1,2 @@ -export declare function Manifest(manifestPath: string): Promise; -export declare function CheckManifest(manifest: any): boolean; +export declare function Manifest(manifestPath: string): Promise; +export declare function CheckManifest(manifest: any): boolean; diff --git a/src/framework/asset-manager/manifest.js b/src/framework/asset-manager/manifest.js index d8c3f61..f8d0755 100644 --- a/src/framework/asset-manager/manifest.js +++ b/src/framework/asset-manager/manifest.js @@ -1,40 +1,40 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import * as yaml from 'yaml'; -export function Manifest(manifestPath) { - return __awaiter(this, void 0, void 0, function* () { - try { - const response = yield fetch(manifestPath); - console.log(response); - const data = yield response.text(); - console.log(`Parsing: `, data); - const manifest = yaml.parse(data); - return manifest; - } - catch (error) { - alert(`Error occured: ${error.toString()}`); - } - }); -} -export function CheckManifest(manifest) { - const prevManifestStr = localStorage.getItem('manifest'); - if (!prevManifestStr) { - localStorage.setItem('manifest', JSON.stringify(manifest)); - return false; - } - const prevManifest = JSON.parse(prevManifestStr); - if (prevManifest.version === manifest.version) { - return true; - } - else { - localStorage.setItem('manifest', manifest); - return false; - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import * as yaml from 'yaml'; +export function Manifest(manifestPath) { + return __awaiter(this, void 0, void 0, function* () { + try { + const response = yield fetch(manifestPath); + console.log(response); + const data = yield response.text(); + console.log(`Parsing: `, data); + const manifest = yaml.parse(data); + return manifest; + } + catch (error) { + alert(`Error occured: ${error.toString()}`); + } + }); +} +export function CheckManifest(manifest) { + const prevManifestStr = localStorage.getItem('manifest'); + if (!prevManifestStr) { + localStorage.setItem('manifest', JSON.stringify(manifest)); + return false; + } + const prevManifest = JSON.parse(prevManifestStr); + if (prevManifest.version === manifest.version) { + return true; + } + else { + localStorage.setItem('manifest', manifest); + return false; + } +} diff --git a/src/framework/asset-manager/queue.d.ts b/src/framework/asset-manager/queue.d.ts index c3c0026..2bb6077 100644 --- a/src/framework/asset-manager/queue.d.ts +++ b/src/framework/asset-manager/queue.d.ts @@ -1,8 +1,8 @@ -export declare class Queue { - private items; - constructor(); - add(file: string): string[]; - remove(file: string): string[]; - pop(): string; - length(): number; -} +export declare class Queue { + private items; + constructor(); + add(file: string): string[]; + remove(file: string): string[]; + pop(): string; + length(): number; +} diff --git a/src/framework/asset-manager/queue.js b/src/framework/asset-manager/queue.js index 05380a3..db1d0fb 100644 --- a/src/framework/asset-manager/queue.js +++ b/src/framework/asset-manager/queue.js @@ -1,19 +1,19 @@ -export class Queue { - constructor() { - this.items = []; - } - add(file) { - this.items.push(file); - return this.items; - } - remove(file) { - this.items = this.items.filter((item) => item !== file); - return this.items; - } - pop() { - return this.items.pop(); - } - length() { - return this.items.length; - } -} +export class Queue { + constructor() { + this.items = []; + } + add(file) { + this.items.push(file); + return this.items; + } + remove(file) { + this.items = this.items.filter((item) => item !== file); + return this.items; + } + pop() { + return this.items.pop(); + } + length() { + return this.items.length; + } +} diff --git a/src/framework/asset-manager/storage.d.ts b/src/framework/asset-manager/storage.d.ts index 36a491f..d56b85e 100644 --- a/src/framework/asset-manager/storage.d.ts +++ b/src/framework/asset-manager/storage.d.ts @@ -1,11 +1,11 @@ -export declare class AssetStorage { - private id; - private cache; - private manifest; - constructor(id: string); - init(): Promise; - add(request: RequestInfo, response: Response): Promise; - get(request: RequestInfo): Promise; - setManifest(manifest: any): Promise; - clear(): Promise; -} +export declare class AssetStorage { + private id; + private cache; + private manifest; + constructor(id: string); + init(): Promise; + add(request: RequestInfo, response: Response): Promise; + get(request: RequestInfo): Promise; + setManifest(manifest: any): Promise; + clear(): Promise; +} diff --git a/src/framework/asset-manager/storage.js b/src/framework/asset-manager/storage.js index 48b2ebd..dff4729 100644 --- a/src/framework/asset-manager/storage.js +++ b/src/framework/asset-manager/storage.js @@ -1,48 +1,48 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import { CheckManifest } from './manifest'; -export class AssetStorage { - constructor(id) { - this.id = id; - } - init() { - return __awaiter(this, void 0, void 0, function* () { - this.cache = yield caches.open(this.id); - }); - } - add(request, response) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield this.cache.put(request, response); - return true; - }); - } - get(request) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield this.cache.match(request); - return result; - }); - } - setManifest(manifest) { - return __awaiter(this, void 0, void 0, function* () { - this.manifest = manifest; - if (!CheckManifest(this.manifest)) { - yield this.clear(); - } - }); - } - clear() { - return __awaiter(this, void 0, void 0, function* () { - const keys = yield this.cache.keys(); - keys.forEach((key) => __awaiter(this, void 0, void 0, function* () { - const result = yield this.cache.delete(key); - })); - }); - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { CheckManifest } from './manifest'; +export class AssetStorage { + constructor(id) { + this.id = id; + } + init() { + return __awaiter(this, void 0, void 0, function* () { + this.cache = yield caches.open(this.id); + }); + } + add(request, response) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.cache.put(request, response); + return true; + }); + } + get(request) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.cache.match(request); + return result; + }); + } + setManifest(manifest) { + return __awaiter(this, void 0, void 0, function* () { + this.manifest = manifest; + if (!CheckManifest(this.manifest)) { + yield this.clear(); + } + }); + } + clear() { + return __awaiter(this, void 0, void 0, function* () { + const keys = yield this.cache.keys(); + keys.forEach((key) => __awaiter(this, void 0, void 0, function* () { + const result = yield this.cache.delete(key); + })); + }); + } +} diff --git a/src/framework/asset-manager/test/index.d.ts b/src/framework/asset-manager/test/index.d.ts index cb0ff5c..509db18 100644 --- a/src/framework/asset-manager/test/index.d.ts +++ b/src/framework/asset-manager/test/index.d.ts @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/asset-manager/test/index.js b/src/framework/asset-manager/test/index.js index 92d3bd5..f93e6f6 100644 --- a/src/framework/asset-manager/test/index.js +++ b/src/framework/asset-manager/test/index.js @@ -1,5 +1,5 @@ -const yaml = require('yaml'); -const fs = require('fs'); -const data = fs.readFileSync('manifest.yaml'); -const parsed = yaml.parse(data.toString()); -console.log(parsed); +const yaml = require('yaml'); +const fs = require('fs'); +const data = fs.readFileSync('manifest.yaml'); +const parsed = yaml.parse(data.toString()); +console.log(parsed); diff --git a/src/framework/asset-manager/utils.d.ts b/src/framework/asset-manager/utils.d.ts index c8f1ef4..0085e31 100644 --- a/src/framework/asset-manager/utils.d.ts +++ b/src/framework/asset-manager/utils.d.ts @@ -1 +1 @@ -export declare function buildPath(basePath: string, path: string): string; +export declare function buildPath(basePath: string, path: string): string; diff --git a/src/framework/asset-manager/utils.js b/src/framework/asset-manager/utils.js index 12e628a..0ea13c7 100644 --- a/src/framework/asset-manager/utils.js +++ b/src/framework/asset-manager/utils.js @@ -1,8 +1,8 @@ -export function buildPath(basePath, path) { - if (!basePath) { - return path; - } - else { - return `${basePath}/${path}`; - } -} +export function buildPath(basePath, path) { + if (!basePath) { + return path; + } + else { + return `${basePath}/${path}`; + } +} diff --git a/src/framework/ecs/component.d.ts b/src/framework/ecs/component.d.ts index 6617706..f94b615 100644 --- a/src/framework/ecs/component.d.ts +++ b/src/framework/ecs/component.d.ts @@ -1,12 +1,12 @@ -export declare class BaseComponent { - id: number; - properties: any; - constructor(); - clone(): BaseComponent; -} -export interface Component { - id: number; - properties: any; - clone(): BaseComponent; - new (): BaseComponent; -} +export declare class BaseComponent { + id: number; + properties: any; + constructor(); + clone(): BaseComponent; +} +export interface Component { + id: number; + properties: any; + clone(): BaseComponent; + new (): BaseComponent; +} diff --git a/src/framework/ecs/component.js b/src/framework/ecs/component.js index a9ea06b..c5d323a 100644 --- a/src/framework/ecs/component.js +++ b/src/framework/ecs/component.js @@ -1,11 +1,11 @@ -export class BaseComponent { - constructor() { - this.id = 0; - this.properties = {}; - } - clone() { - const comp = new BaseComponent(); - comp.properties = this.properties; - return comp; - } -} +export class BaseComponent { + constructor() { + this.id = 0; + this.properties = {}; + } + clone() { + const comp = new BaseComponent(); + comp.properties = this.properties; + return comp; + } +} diff --git a/src/framework/ecs/entity.d.ts b/src/framework/ecs/entity.d.ts index 800738c..43dc047 100644 --- a/src/framework/ecs/entity.d.ts +++ b/src/framework/ecs/entity.d.ts @@ -1,19 +1,19 @@ -import { BaseComponent, Component } from './component'; -export declare class BaseEntity { - id: number; - components: Map; - constructor(); - addComponent(component: Component): void; - removeComponent(component: BaseComponent): void; - getComponentIDs(): number[]; - getComponent(component: BaseComponent): BaseComponent; - getComponentByID(id: number): BaseComponent; -} -export interface Entity { - new (): BaseComponent; - addComponent(component: Component): any; - removeComponent(component: BaseComponent): any; - getComponentIDs(): number[]; - getComponent(component: BaseComponent): any; - getComponentByID(id: number): BaseComponent; -} +import { BaseComponent, Component } from './component'; +export declare class BaseEntity { + id: number; + components: Map; + constructor(); + addComponent(component: Component): void; + removeComponent(component: BaseComponent): void; + getComponentIDs(): number[]; + getComponent(component: BaseComponent): BaseComponent; + getComponentByID(id: number): BaseComponent; +} +export interface Entity { + new (): BaseComponent; + addComponent(component: Component): any; + removeComponent(component: BaseComponent): any; + getComponentIDs(): number[]; + getComponent(component: BaseComponent): any; + getComponentByID(id: number): BaseComponent; +} diff --git a/src/framework/ecs/entity.js b/src/framework/ecs/entity.js index 2732635..0436a5c 100644 --- a/src/framework/ecs/entity.js +++ b/src/framework/ecs/entity.js @@ -1,23 +1,23 @@ -export class BaseEntity { - constructor() { - this.components = new Map(); - this.id = 0; - } - addComponent(component) { - let comp = new component(); - comp.id = component.id; - this.components.set(component.id, comp); - } - removeComponent(component) { - this.components.delete(component.id); - } - getComponentIDs() { - return [...this.components.keys()]; - } - getComponent(component) { - return this.components.get(component.id); - } - getComponentByID(id) { - return this.components.get(id); - } -} +export class BaseEntity { + constructor() { + this.components = new Map(); + this.id = 0; + } + addComponent(component) { + let comp = new component(); + comp.id = component.id; + this.components.set(component.id, comp); + } + removeComponent(component) { + this.components.delete(component.id); + } + getComponentIDs() { + return [...this.components.keys()]; + } + getComponent(component) { + return this.components.get(component.id); + } + getComponentByID(id) { + return this.components.get(id); + } +} diff --git a/src/framework/ecs/index.d.ts b/src/framework/ecs/index.d.ts index 7a8314e..d0eda9e 100644 --- a/src/framework/ecs/index.d.ts +++ b/src/framework/ecs/index.d.ts @@ -1,28 +1,29 @@ -import { Component } from './component'; -import { BaseEntity, Entity } from './entity'; -import { EventBus } from '../event-bus'; -import { Query } from './query'; -import { System } from './system'; -export declare class World { - entities: Array; - components: Map; - componentNamesToIDs: Map; - systems: Set; - nextEntityID: number; - nextComponentID: number; - nextQueryID: number; - queryCache: Array; - eventBus: EventBus; - constructor(); - run(): void; - createSystem(systemExecutor: Function): void; - addSystem(system: System): void; - addEntity(entity: BaseEntity): void; - removeEntity(entityToRemove: BaseEntity): void; - createEntity(components: Array): BaseEntity; - extendEntity(entity: Entity, components: Array): BaseEntity; - createComponent(component: Component): Component; - query(include: Array, exclude: Array): Array; - createQuery(include: Array, exclude: Array): Query; - markQueriesDirty(): void; -} +import { Component } from './component'; +import { BaseEntity, Entity } from './entity'; +import { EventBus } from '../event-bus'; +import { Query } from './query'; +import { System } from './system'; +export declare class World { + entities: Array; + components: Map; + componentNamesToIDs: Map; + systems: Set; + nextEntityID: number; + nextComponentID: number; + nextQueryID: number; + queryCache: Array; + eventBus: EventBus; + isRunning: boolean; + constructor(); + run(): void; + createSystem(systemExecutor: Function): void; + addSystem(system: System): void; + addEntity(entity: BaseEntity): void; + removeEntity(entityToRemove: BaseEntity): void; + createEntity(components: Array): BaseEntity; + extendEntity(entity: Entity, components: Array): BaseEntity; + createComponent(component: Component): Component; + query(include: Array, exclude: Array): Array; + createQuery(include: Array, exclude: Array): Query; + markQueriesDirty(): void; +} diff --git a/src/framework/ecs/index.js b/src/framework/ecs/index.js index 7a7ef26..4414cc1 100644 --- a/src/framework/ecs/index.js +++ b/src/framework/ecs/index.js @@ -1,105 +1,113 @@ -import { BaseEntity } from './entity'; -import { EventBus } from '../event-bus'; -import { Query } from './query'; -import { System } from './system'; -export class World { - constructor() { - this.nextEntityID = 0; - this.nextComponentID = 0; - this.nextQueryID = 0; - this.entities = new Array(); - this.systems = new Set(); - this.components = new Map(); - this.componentNamesToIDs = new Map(); - this.queryCache = new Array(); - this.eventBus = new EventBus(); - } - run() { - this.systems.forEach((system) => { - system.execute(this); - }); - } - createSystem(systemExecutor) { - const newSystem = new System(systemExecutor); - this.systems.add(newSystem); - } - addSystem(system) { - this.systems.add(system); - } - addEntity(entity) { - this.entities.push(entity); - this.markQueriesDirty(); - } - removeEntity(entityToRemove) { - this.entities = this.entities.filter((entity) => entity !== entityToRemove); - this.markQueriesDirty(); - } - createEntity(components) { - const newEntity = new BaseEntity(); - newEntity.id = this.nextEntityID; - this.nextEntityID++; - components.forEach((component) => { - if (this.componentNamesToIDs.has(component.name)) { - component.id = this.componentNamesToIDs.get(component.name); - } - else { - this.componentNamesToIDs.set(component.name, this.nextComponentID); - component.id = this.nextComponentID; - this.nextComponentID++; - } - newEntity.addComponent(component); - }); - this.entities.push(newEntity); - this.markQueriesDirty(); - return newEntity; - } - extendEntity(entity, components) { - const toClone = this.entities.find((found) => entity.name === found.constructor.name); - const cloned = new BaseEntity(); - cloned.id = this.nextEntityID; - this.nextEntityID++; - toClone.components.forEach((component) => { - cloned.addComponent(this.components.get(component.id)); - }); - components.forEach((component) => { - if (this.componentNamesToIDs.has(component.name)) { - component.id = this.componentNamesToIDs.get(component.name); - } - else { - this.componentNamesToIDs.set(component.name, this.nextComponentID); - component.id = this.nextComponentID; - this.nextComponentID++; - } - cloned.addComponent(component); - }); - this.entities.push(cloned); - return cloned; - } - createComponent(component) { - const newComponent = component; - newComponent.id = this.nextComponentID; - this.nextComponentID++; - this.components.set(newComponent.id, newComponent); - this.componentNamesToIDs.set(component.name, component.id); - return newComponent; - } - query(include, exclude) { - const query = new Query(include, exclude, this); - const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude); - if (cache) { - return cache.execute(); - } - this.queryCache.push(query); - return query.execute(); - } - createQuery(include, exclude) { - const newQuery = new Query(include, exclude, this); - newQuery.id = this.nextQueryID; - this.nextQueryID++; - this.queryCache.push(newQuery); - return newQuery; - } - markQueriesDirty() { - this.queryCache.forEach((query) => (query.isDirty = true)); - } -} +import { BaseEntity } from './entity'; +import { EventBus } from '../event-bus'; +import { Query } from './query'; +import { System } from './system'; +export class World { + constructor() { + this.nextEntityID = 0; + this.nextComponentID = 0; + this.nextQueryID = 0; + this.entities = new Array(); + this.systems = new Set(); + this.components = new Map(); + this.componentNamesToIDs = new Map(); + this.queryCache = new Array(); + this.eventBus = new EventBus(); + this.isRunning = false; + } + run() { + if (!this.isRunning) { + this.systems.forEach((system) => system.init(this)); + } + this.systems.forEach((system) => { + system.execute(this); + }); + } + createSystem(systemExecutor) { + const newSystem = new System(systemExecutor); + this.systems.add(newSystem); + if (this.isRunning) + newSystem.init(this); + } + addSystem(system) { + this.systems.add(system); + if (this.isRunning) + system.init(this); + } + addEntity(entity) { + this.entities.push(entity); + this.markQueriesDirty(); + } + removeEntity(entityToRemove) { + this.entities = this.entities.filter((entity) => entity !== entityToRemove); + this.markQueriesDirty(); + } + createEntity(components) { + const newEntity = new BaseEntity(); + newEntity.id = this.nextEntityID; + this.nextEntityID++; + components.forEach((component) => { + if (this.componentNamesToIDs.has(component.name)) { + component.id = this.componentNamesToIDs.get(component.name); + } + else { + this.componentNamesToIDs.set(component.name, this.nextComponentID); + component.id = this.nextComponentID; + this.nextComponentID++; + } + newEntity.addComponent(component); + }); + this.entities.push(newEntity); + this.markQueriesDirty(); + return newEntity; + } + extendEntity(entity, components) { + const toClone = this.entities.find((found) => entity.name === found.constructor.name); + const cloned = new BaseEntity(); + cloned.id = this.nextEntityID; + this.nextEntityID++; + toClone.components.forEach((component) => { + cloned.addComponent(this.components.get(component.id)); + }); + components.forEach((component) => { + if (this.componentNamesToIDs.has(component.name)) { + component.id = this.componentNamesToIDs.get(component.name); + } + else { + this.componentNamesToIDs.set(component.name, this.nextComponentID); + component.id = this.nextComponentID; + this.nextComponentID++; + } + cloned.addComponent(component); + }); + this.entities.push(cloned); + return cloned; + } + createComponent(component) { + const newComponent = component; + newComponent.id = this.nextComponentID; + this.nextComponentID++; + this.components.set(newComponent.id, newComponent); + this.componentNamesToIDs.set(component.name, component.id); + return newComponent; + } + query(include, exclude) { + const query = new Query(include, exclude, this); + const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude); + if (cache) { + return cache.execute(); + } + this.queryCache.push(query); + return query.execute(); + } + createQuery(include, exclude) { + const newQuery = new Query(include, exclude, this); + newQuery.id = this.nextQueryID; + this.nextQueryID++; + this.queryCache.push(newQuery); + return newQuery; + } + markQueriesDirty() { + this.queryCache.forEach((query) => (query.isDirty = true)); + } +} diff --git a/src/framework/ecs/query.d.ts b/src/framework/ecs/query.d.ts index 37c4901..f6a8160 100644 --- a/src/framework/ecs/query.d.ts +++ b/src/framework/ecs/query.d.ts @@ -1,15 +1,15 @@ -import { World } from '.'; -import { Component } from './component'; -import { BaseEntity } from './entity'; -export declare class Query { - include: Array; - exclude: Array; - world: World; - id: number; - private results; - isDirty: boolean; - includeComponentIds: number[]; - excludeComponentIds: number[]; - constructor(include: Array, exclude: Array, world: World); - execute(): Array; -} +import { World } from '.'; +import { Component } from './component'; +import { BaseEntity } from './entity'; +export declare class Query { + include: Array; + exclude: Array; + world: World; + id: number; + private results; + isDirty: boolean; + includeComponentIds: number[]; + excludeComponentIds: number[]; + constructor(include: Array, exclude: Array, world: World); + execute(): Array; +} diff --git a/src/framework/ecs/query.js b/src/framework/ecs/query.js index 1ae868f..1fca3a3 100644 --- a/src/framework/ecs/query.js +++ b/src/framework/ecs/query.js @@ -1,34 +1,34 @@ -export class Query { - constructor(include, exclude, world) { - this.include = include; - this.exclude = exclude; - this.world = world; - this.isDirty = true; - this.results = new Array(); - this.includeComponentIds = include.map((component) => component.id); - this.excludeComponentIds = exclude.map((component) => component.id); - this.id = 0; - } - execute() { - if (!this.isDirty && this.results) { - return this.results; - } - let filtered; - this.includeComponentIds = this.include.map((component) => this.world.componentNamesToIDs.get(component.name)); - this.excludeComponentIds = this.exclude.map((component) => this.world.componentNamesToIDs.get(component.name)); - const entities = this.world.entities.filter((entity) => { - let ids = entity.getComponentIDs(); - // let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true); - let excludes = ids - .map((id) => this.excludeComponentIds.includes(id)) - .includes(true); - let includes = ids.filter((id) => this.includeComponentIds.includes(id)); - return includes.length === this.includeComponentIds.length && !excludes; - }); - if (entities.length > 0) { - this.isDirty = false; - this.results = entities; - } - return entities; - } -} +export class Query { + constructor(include, exclude, world) { + this.include = include; + this.exclude = exclude; + this.world = world; + this.isDirty = true; + this.results = new Array(); + this.includeComponentIds = include.map((component) => component.id); + this.excludeComponentIds = exclude.map((component) => component.id); + this.id = 0; + } + execute() { + if (!this.isDirty && this.results) { + return this.results; + } + let filtered; + this.includeComponentIds = this.include.map((component) => this.world.componentNamesToIDs.get(component.name)); + this.excludeComponentIds = this.exclude.map((component) => this.world.componentNamesToIDs.get(component.name)); + const entities = this.world.entities.filter((entity) => { + let ids = entity.getComponentIDs(); + // let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true); + let excludes = ids + .map((id) => this.excludeComponentIds.includes(id)) + .includes(true); + let includes = ids.filter((id) => this.includeComponentIds.includes(id)); + return includes.length === this.includeComponentIds.length && !excludes; + }); + if (entities.length > 0) { + this.isDirty = false; + this.results = entities; + } + return entities; + } +} diff --git a/src/framework/ecs/system.d.ts b/src/framework/ecs/system.d.ts index 65af5de..3ed270e 100644 --- a/src/framework/ecs/system.d.ts +++ b/src/framework/ecs/system.d.ts @@ -1,6 +1,13 @@ -import { World } from '.'; -export declare class System { - executor: Function; - constructor(executor: Function); - execute(world: World): void; -} +import { World } from '.'; +import { BaseEntity } from './entity'; +import { Query } from './query'; +export declare class System { + executor: Function; + query: Query; + constructor(executor: Function); + execute(world: World): void; + setQuery(query: Query): void; + getQuery(): Query; + executeQuery(): Array; + init(world: World): void; +} diff --git a/src/framework/ecs/system.js b/src/framework/ecs/system.js index dbccaa4..4c3d4c6 100644 --- a/src/framework/ecs/system.js +++ b/src/framework/ecs/system.js @@ -1,10 +1,22 @@ -export class System { - constructor(executor) { - this.executor = executor; - } - execute(world) { - if (this.executor) { - this.executor(world); - } - } -} +export class System { + constructor(executor) { + this.executor = executor; + } + execute(world) { + if (this.executor) { + this.executor(world); + } + } + setQuery(query) { + this.query = query; + } + getQuery() { + return this.query; + } + executeQuery() { + return this.query.execute(); + } + init(world) { + return; + } +} diff --git a/src/framework/event-bus/index.d.ts b/src/framework/event-bus/index.d.ts index a3d66e5..2689b43 100644 --- a/src/framework/event-bus/index.d.ts +++ b/src/framework/event-bus/index.d.ts @@ -1,13 +1,13 @@ -export declare class EventBus { - private events; - constructor(); - emit(id: string, data?: any): void; - subscribe(id: string, subscriber: Function): void; - unsubscribe(id: string, subscriber: Function): void; - unsubscribeAll(id: string): void; -} -export declare class EventItem { - id: string; - subscribers: Function[]; - constructor(id: string); -} +export declare class EventBus { + private events; + constructor(); + emit(id: string, data?: any): void; + subscribe(id: string, subscriber: Function): void; + unsubscribe(id: string, subscriber: Function): void; + unsubscribeAll(id: string): void; +} +export declare class EventItem { + id: string; + subscribers: Function[]; + constructor(id: string); +} diff --git a/src/framework/event-bus/index.js b/src/framework/event-bus/index.js index 20afbae..8abe562 100644 --- a/src/framework/event-bus/index.js +++ b/src/framework/event-bus/index.js @@ -1,44 +1,44 @@ -export class EventBus { - constructor() { - this.events = new Map(); - } - emit(id, data = {}) { - let ev = this.events.get(id); - if (!ev) { - let ev = new EventItem(id); - this.events.set(id, ev); - return; - } - ev.subscribers.forEach((subscriber) => { - subscriber(data); - }); - } - subscribe(id, subscriber) { - let ev = this.events.get(id); - if (!ev) { - ev = new EventItem(id); - this.events.set(id, ev); - } - ev.subscribers.push(subscriber); - } - unsubscribe(id, subscriber) { - if (this.events.has(id)) { - let ev = this.events.get(id); - ev.subscribers = ev.subscribers.filter((fn) => fn !== subscriber); - if (ev.subscribers.length < 1) { - this.events.delete(id); - } - } - } - unsubscribeAll(id) { - if (this.events.has(id)) { - this.events.delete(id); - } - } -} -export class EventItem { - constructor(id) { - this.id = id; - this.subscribers = []; - } -} +export class EventBus { + constructor() { + this.events = new Map(); + } + emit(id, data = {}) { + let ev = this.events.get(id); + if (!ev) { + let ev = new EventItem(id); + this.events.set(id, ev); + return; + } + ev.subscribers.forEach((subscriber) => { + subscriber(data); + }); + } + subscribe(id, subscriber) { + let ev = this.events.get(id); + if (!ev) { + ev = new EventItem(id); + this.events.set(id, ev); + } + ev.subscribers.push(subscriber); + } + unsubscribe(id, subscriber) { + if (this.events.has(id)) { + let ev = this.events.get(id); + ev.subscribers = ev.subscribers.filter((fn) => fn !== subscriber); + if (ev.subscribers.length < 1) { + this.events.delete(id); + } + } + } + unsubscribeAll(id) { + if (this.events.has(id)) { + this.events.delete(id); + } + } +} +export class EventItem { + constructor(id) { + this.id = id; + this.subscribers = []; + } +} diff --git a/src/framework/game/game-config.d.ts b/src/framework/game/game-config.d.ts new file mode 100644 index 0000000..96989b5 --- /dev/null +++ b/src/framework/game/game-config.d.ts @@ -0,0 +1,7 @@ +import { InputType } from '../input/inputs/base-input'; +export declare class GameConfig { + name: string; + inputTypes: InputType[]; + assetDirectory: string; + updatesPerSecond: number; +} diff --git a/src/framework/game/game-config.js b/src/framework/game/game-config.js new file mode 100644 index 0000000..cb1db73 --- /dev/null +++ b/src/framework/game/game-config.js @@ -0,0 +1,6 @@ +export class GameConfig { + constructor() { + // How many times a second to fire the update event + this.updatesPerSecond = 60; + } +} diff --git a/src/framework/game/index.d.ts b/src/framework/game/index.d.ts index 0de492c..a82a67e 100644 --- a/src/framework/game/index.d.ts +++ b/src/framework/game/index.d.ts @@ -1,26 +1,28 @@ -import { AssetManager } from '../asset-manager'; -import { Input } from '../input'; -import Resonator from '../resonator'; -import { Scene } from '../scene/scene'; -import { SceneManager } from '../scene/manager'; -import { Scheduler } from '../scheduler'; -import { TTS } from '../tts'; -import { HTTPLoader } from '../resonator/loaders/http-loader'; -import { EventBus } from '../event-bus'; -import { World } from '../world'; -export declare class Game extends EventBus { - assetLoader: HTTPLoader; - assetManager: AssetManager; - resonator: Resonator; - input: Input; - tts: TTS; - sceneManager: SceneManager; - scheduler: Scheduler; - world: World; - constructor(); - init(): void; - start(): void; - addScene(scene: Scene): void; - addDefaultScene(scene: Scene): void; - setWorld(world: World): void; -} +import { AssetManager } from '../asset-manager'; +import { EventBus } from '../event-bus'; +import { Input } from '../input'; +import Resonator from '../resonator'; +import { HTTPLoader } from '../resonator/loaders/http-loader'; +import { SceneManager } from '../scene/manager'; +import { Scene } from '../scene/scene'; +import { Scheduler } from '../scheduler'; +import { TTS } from '../tts'; +import { World } from '../world'; +import { GameConfig } from './game-config'; +export declare class Game extends EventBus { + assetLoader: HTTPLoader; + assetManager: AssetManager; + resonator: Resonator; + input: Input; + tts: TTS; + sceneManager: SceneManager; + scheduler: Scheduler; + world: World; + config: GameConfig; + constructor(config: GameConfig); + init(): void; + start(): void; + addScene(scene: Scene): void; + addDefaultScene(scene: Scene): void; + setWorld(world: World): void; +} diff --git a/src/framework/game/index.js b/src/framework/game/index.js index 91b4aa7..816ace0 100644 --- a/src/framework/game/index.js +++ b/src/framework/game/index.js @@ -1,44 +1,46 @@ -import { AssetManager } from '../asset-manager'; -import { Input } from '../input'; -import Resonator from '../resonator'; -import { SceneManager } from '../scene/manager'; -import { Scheduler } from '../scheduler'; -import { TTS } from '../tts'; -import { AriaOutput } from '../tts/outputs/aria'; -import { HTTPLoader } from '../resonator/loaders/http-loader'; -import { EventBus } from '../event-bus'; -export class Game extends EventBus { - constructor() { - super(); - this.init(); - } - init() { - this.assetManager = new AssetManager('game', ''); - this.assetLoader = new HTTPLoader(); - this.resonator = new Resonator(this.assetLoader); - this.input = new Input(['keyboard'], document.body); - this.tts = new TTS(new AriaOutput()); - this.sceneManager = new SceneManager(); - this.scheduler = new Scheduler(60); - this.emit('ready'); - } - start() { - this.scheduler.start(); - this.scheduler.subscribe('update.logic', (dt) => { - this.sceneManager.currentScene.update(dt); - this.world.update(dt); - }); - this.scheduler.subscribe('update.draw', (dt) => this.sceneManager.currentScene.updateDraw()); - this.sceneManager.init(); - } - addScene(scene) { - this.sceneManager.addScene(scene); - } - addDefaultScene(scene) { - this.sceneManager.addScene(scene); - this.sceneManager.setDefaultScene(scene); - } - setWorld(world) { - this.world = world; - } -} +import { AssetManager } from '../asset-manager'; +import { EventBus } from '../event-bus'; +import { Input } from '../input'; +import Resonator from '../resonator'; +import { HTTPLoader } from '../resonator/loaders/http-loader'; +import { SceneManager } from '../scene/manager'; +import { Scheduler } from '../scheduler'; +import { TTS } from '../tts'; +import { AriaOutput } from '../tts/outputs/aria'; +export class Game extends EventBus { + constructor(config) { + super(); + this.config = config; + this.init(); + } + init() { + this.assetManager = new AssetManager(this.config.name, this.config.assetDirectory); + this.assetLoader = new HTTPLoader(); + this.resonator = new Resonator(this.assetLoader); + this.input = new Input(this.config.inputTypes, document.body); + this.tts = new TTS(new AriaOutput()); + this.sceneManager = new SceneManager(); + this.scheduler = new Scheduler(this.config.updatesPerSecond); + this.emit('ready'); + } + start() { + this.scheduler.start(); + this.scheduler.subscribe('update.logic', (dt) => { + var _a, _b; + (_a = this.sceneManager.currentScene) === null || _a === void 0 ? void 0 : _a.update(dt); + (_b = this.world) === null || _b === void 0 ? void 0 : _b.update(dt); + }); + this.scheduler.subscribe('update.draw', (dt) => { var _a; return (_a = this.sceneManager.currentScene) === null || _a === void 0 ? void 0 : _a.updateDraw(); }); + this.sceneManager.init(); + } + addScene(scene) { + this.sceneManager.addScene(scene); + } + addDefaultScene(scene) { + this.sceneManager.addScene(scene); + this.sceneManager.setDefaultScene(scene); + } + setWorld(world) { + this.world = world; + } +} diff --git a/src/framework/index.d.ts b/src/framework/index.d.ts index 513af72..68ec897 100644 --- a/src/framework/index.d.ts +++ b/src/framework/index.d.ts @@ -1,7 +1,7 @@ -export * from './asset-manager'; -export * from './ecs'; -export * from './event-bus'; -export * from './input'; -export * from './resonator'; -export * from './tts'; -export * from './ui'; +export * from './asset-manager'; +export * from './ecs'; +export * from './event-bus'; +export * from './input'; +export * from './resonator'; +export * from './tts'; +export * from './ui'; diff --git a/src/framework/index.js b/src/framework/index.js index 513af72..68ec897 100644 --- a/src/framework/index.js +++ b/src/framework/index.js @@ -1,7 +1,7 @@ -export * from './asset-manager'; -export * from './ecs'; -export * from './event-bus'; -export * from './input'; -export * from './resonator'; -export * from './tts'; -export * from './ui'; +export * from './asset-manager'; +export * from './ecs'; +export * from './event-bus'; +export * from './input'; +export * from './resonator'; +export * from './tts'; +export * from './ui'; diff --git a/src/framework/input/index.d.ts b/src/framework/input/index.d.ts index fe7e744..6d47da8 100644 --- a/src/framework/input/index.d.ts +++ b/src/framework/input/index.d.ts @@ -1,13 +1,13 @@ -import { BaseInput } from './inputs/base-input'; -import { State } from './interfaces/state'; -export declare class Input { - private InputIDs; - private element; - private inputs; - constructor(InputIDs: string[], element: HTMLElement); - private init; - addInput(id: string, input: BaseInput): this; - capture(preventDefault?: boolean): void; - release(): void; - getState(): State; -} +import { BaseInput } from './inputs/base-input'; +import { State } from './interfaces/state'; +export declare class Input { + private InputIDs; + private element; + private inputs; + constructor(InputIDs: string[], element: HTMLElement); + private init; + addInput(id: string, input: BaseInput): this; + capture(preventDefault?: boolean): void; + release(): void; + getState(): State; +} diff --git a/src/framework/input/index.js b/src/framework/input/index.js index 595d456..0b9e98d 100644 --- a/src/framework/input/index.js +++ b/src/framework/input/index.js @@ -1,34 +1,34 @@ -import { createInput } from './input-factory'; -export class Input { - constructor(InputIDs, element) { - this.InputIDs = InputIDs; - this.element = element; - this.inputs = new Map(); - this.init(); - } - init() { - this.InputIDs.forEach((inputID) => { - const thing = createInput(inputID); - const instance = new thing(this.element); - this.inputs.set(inputID, instance); - }); - } - addInput(id, input) { - this.inputs.set(id, input); - return this; - } - capture(preventDefault = true) { - this.inputs.forEach((input) => input.capture(preventDefault)); - } - release() { - this.inputs.forEach((input) => input.release()); - } - getState() { - const state = {}; - this.inputs.forEach((input, inputID) => { - if (input) - state[inputID] = input.getState(); - }); - return state; - } -} +import { createInput } from './input-factory'; +export class Input { + constructor(InputIDs, element) { + this.InputIDs = InputIDs; + this.element = element; + this.inputs = new Map(); + this.init(); + } + init() { + this.InputIDs.forEach((inputID) => { + const thing = createInput(inputID); + const instance = new thing(this.element); + this.inputs.set(inputID, instance); + }); + } + addInput(id, input) { + this.inputs.set(id, input); + return this; + } + capture(preventDefault = true) { + this.inputs.forEach((input) => input.capture(preventDefault)); + } + release() { + this.inputs.forEach((input) => input.release()); + } + getState() { + const state = {}; + this.inputs.forEach((input, inputID) => { + if (input) + state[inputID] = input.getState(); + }); + return state; + } +} diff --git a/src/framework/input/input-factory.d.ts b/src/framework/input/input-factory.d.ts index a7e84d2..ffd99c9 100644 --- a/src/framework/input/input-factory.d.ts +++ b/src/framework/input/input-factory.d.ts @@ -1 +1 @@ -export declare function createInput(key: string): any; +export declare function createInput(key: string): any; diff --git a/src/framework/input/input-factory.js b/src/framework/input/input-factory.js index fe7e98b..cd92ac0 100644 --- a/src/framework/input/input-factory.js +++ b/src/framework/input/input-factory.js @@ -1,14 +1,19 @@ -import { Keyboard } from './inputs/keyboard'; -import { Mouse } from './inputs/mouse'; -export function createInput(key) { - switch (key) { - case 'keyboard': - return Keyboard; - break; - case 'mouse': - return Mouse; - break; - default: - break; - } -} +import { InputType } from './inputs/base-input'; +import { Keyboard } from './inputs/keyboard'; +import { Mouse } from './inputs/mouse'; +import { Gamepad } from './inputs/gamepad'; +export function createInput(key) { + switch (key) { + case InputType.Keyboard: + return Keyboard; + break; + case InputType.Mouse: + return Mouse; + break; + case InputType.Gamepad: + return Gamepad; + break; + default: + throw new Error(`Unknown input type: ${key}`); + } +} diff --git a/src/framework/input/inputs/base-input.d.ts b/src/framework/input/inputs/base-input.d.ts index 661de29..310383e 100644 --- a/src/framework/input/inputs/base-input.d.ts +++ b/src/framework/input/inputs/base-input.d.ts @@ -1,10 +1,15 @@ -export declare class BaseInput { - protected element: HTMLElement; - protected active: boolean; - constructor(element: HTMLElement); - getState(): any; - capture(preventDefault: boolean): void; - release(): void; -} -export interface IBaseInput { -} +export declare enum InputType { + Keyboard = "keyboard", + Mouse = "mouse", + Gamepad = "gamepad" +} +export declare abstract class BaseInput { + protected element: HTMLElement; + protected active: boolean; + constructor(element: HTMLElement); + abstract getState(): any; + capture(preventDefault: boolean): void; + release(): void; +} +export interface IBaseInput { +} diff --git a/src/framework/input/inputs/base-input.js b/src/framework/input/inputs/base-input.js index dc21706..282f352 100644 --- a/src/framework/input/inputs/base-input.js +++ b/src/framework/input/inputs/base-input.js @@ -1,12 +1,17 @@ -export class BaseInput { - constructor(element) { - this.element = element; - } - getState() { } - capture(preventDefault) { - return; - } - release() { - return; - } -} +export var InputType; +(function (InputType) { + InputType["Keyboard"] = "keyboard"; + InputType["Mouse"] = "mouse"; + InputType["Gamepad"] = "gamepad"; +})(InputType || (InputType = {})); +export class BaseInput { + constructor(element) { + this.element = element; + } + capture(preventDefault) { + return; + } + release() { + return; + } +} diff --git a/src/framework/input/inputs/gamepad.d.ts b/src/framework/input/inputs/gamepad.d.ts new file mode 100644 index 0000000..1b02b4e --- /dev/null +++ b/src/framework/input/inputs/gamepad.d.ts @@ -0,0 +1,6 @@ +import { BaseInput } from './base-input'; +export declare class Gamepad extends BaseInput { + getState(): number[][]; +} +export interface IGamepad { +} diff --git a/src/framework/input/inputs/gamepad.js b/src/framework/input/inputs/gamepad.js new file mode 100644 index 0000000..2ad266a --- /dev/null +++ b/src/framework/input/inputs/gamepad.js @@ -0,0 +1,14 @@ +import { BaseInput } from './base-input'; +export class Gamepad extends BaseInput { + getState() { + const gamepads = navigator.getGamepads(); + const state = gamepads + .map((gamepad) => { + if (gamepad) { + return gamepad.buttons.map((button) => button.value); + } + }) + .filter((button) => button); + return state; + } +} diff --git a/src/framework/input/inputs/joystick.d.ts b/src/framework/input/inputs/joystick.d.ts index 1c4cdd8..0eb84af 100644 --- a/src/framework/input/inputs/joystick.d.ts +++ b/src/framework/input/inputs/joystick.d.ts @@ -1,6 +1,6 @@ -import { BaseInput } from './base-input'; -export declare class Joystick extends BaseInput { - constructor(element: HTMLElement); -} -export interface IJoystick { -} +import { BaseInput } from './base-input'; +export declare class Joystick extends BaseInput { + constructor(element: HTMLElement); +} +export interface IJoystick { +} diff --git a/src/framework/input/inputs/joystick.js b/src/framework/input/inputs/joystick.js index 76e4e7b..8f0f1fa 100644 --- a/src/framework/input/inputs/joystick.js +++ b/src/framework/input/inputs/joystick.js @@ -1,6 +1,6 @@ -import { BaseInput } from './base-input'; -export class Joystick extends BaseInput { - constructor(element) { - super(element); - } -} +import { BaseInput } from './base-input'; +export class Joystick extends BaseInput { + constructor(element) { + super(element); + } +} diff --git a/src/framework/input/inputs/keyboard.d.ts b/src/framework/input/inputs/keyboard.d.ts index 915d9c9..1c6a753 100644 --- a/src/framework/input/inputs/keyboard.d.ts +++ b/src/framework/input/inputs/keyboard.d.ts @@ -1,18 +1,18 @@ -import { BaseInput } from './base-input'; -export declare class Keyboard extends BaseInput { - private keysDown; - private keysJustPressed; - private keysJustReleased; - private preventDefault; - constructor(element: HTMLElement); - capture(preventDefault: boolean): void; - release(): void; - getState(): IKeyboard; - private handleKeyDown; - private handleKeyUp; -} -export interface IKeyboard { - keysDown: Map; - keysJustPressed: Map; - keysJustReleased: Map; -} +import { BaseInput } from './base-input'; +export declare class Keyboard extends BaseInput { + private keysDown; + private keysJustPressed; + private keysJustReleased; + private preventDefault; + constructor(element: HTMLElement); + capture(preventDefault: boolean): void; + release(): void; + getState(): IKeyboard; + private handleKeyDown; + private handleKeyUp; +} +export interface IKeyboard { + keysDown: Map; + keysJustPressed: Map; + keysJustReleased: Map; +} diff --git a/src/framework/input/inputs/keyboard.js b/src/framework/input/inputs/keyboard.js index 7ea29c7..fc47d15 100644 --- a/src/framework/input/inputs/keyboard.js +++ b/src/framework/input/inputs/keyboard.js @@ -1,50 +1,50 @@ -import { BaseInput } from './base-input'; -export class Keyboard extends BaseInput { - constructor(element) { - super(element); - this.keysDown = new Map(); - this.keysJustPressed = new Map(); - this.keysJustReleased = new Map(); - this.handleKeyDown = this.handleKeyDown.bind(this); - this.handleKeyUp = this.handleKeyUp.bind(this); - } - capture(preventDefault) { - this.active = true; - this.preventDefault = preventDefault; - this.element.addEventListener('keydown', this.handleKeyDown); - this.element.addEventListener('keyup', this.handleKeyUp); - } - release() { - this.active = false; - this.element.removeEventListener('keydown', this.handleKeyDown); - this.element.removeEventListener('keyup', this.handleKeyUp); - } - getState() { - const state = { - keysDown: new Map(this.keysDown), - keysJustPressed: new Map(this.keysJustPressed), - keysJustReleased: new Map(this.keysJustReleased) - }; - this.keysJustPressed.clear(); - this.keysJustReleased.clear(); - return state; - } - handleKeyDown(event) { - if (this.active && this.preventDefault) - event.preventDefault(); - if (this.keysDown.get(event.keyCode)) - return; - this.keysDown.set(event.keyCode, true); - this.keysJustPressed.set(event.keyCode, true); - this.keysJustReleased.set(event.keyCode, false); - } - handleKeyUp(event) { - if (this.active && this.preventDefault) - event.preventDefault(); - if (!this.keysDown.get(event.keyCode)) - return; - this.keysDown.set(event.keyCode, false); - this.keysJustPressed.set(event.keyCode, false); - this.keysJustReleased.set(event.keyCode, true); - } -} +import { BaseInput } from './base-input'; +export class Keyboard extends BaseInput { + constructor(element) { + super(element); + this.keysDown = new Map(); + this.keysJustPressed = new Map(); + this.keysJustReleased = new Map(); + this.handleKeyDown = this.handleKeyDown.bind(this); + this.handleKeyUp = this.handleKeyUp.bind(this); + } + capture(preventDefault) { + this.active = true; + this.preventDefault = preventDefault; + this.element.addEventListener('keydown', this.handleKeyDown); + this.element.addEventListener('keyup', this.handleKeyUp); + } + release() { + this.active = false; + this.element.removeEventListener('keydown', this.handleKeyDown); + this.element.removeEventListener('keyup', this.handleKeyUp); + } + getState() { + const state = { + keysDown: new Map(this.keysDown), + keysJustPressed: new Map(this.keysJustPressed), + keysJustReleased: new Map(this.keysJustReleased) + }; + this.keysJustPressed.clear(); + this.keysJustReleased.clear(); + return state; + } + handleKeyDown(event) { + if (this.active && this.preventDefault) + event.preventDefault(); + if (this.keysDown.get(event.keyCode)) + return; + this.keysDown.set(event.keyCode, true); + this.keysJustPressed.set(event.keyCode, true); + this.keysJustReleased.set(event.keyCode, false); + } + handleKeyUp(event) { + if (this.active && this.preventDefault) + event.preventDefault(); + if (!this.keysDown.get(event.keyCode)) + return; + this.keysDown.set(event.keyCode, false); + this.keysJustPressed.set(event.keyCode, false); + this.keysJustReleased.set(event.keyCode, true); + } +} diff --git a/src/framework/input/inputs/mouse.d.ts b/src/framework/input/inputs/mouse.d.ts index 51ad7ea..0fd532f 100644 --- a/src/framework/input/inputs/mouse.d.ts +++ b/src/framework/input/inputs/mouse.d.ts @@ -1,34 +1,34 @@ -import { BaseInput } from './base-input'; -export declare class Mouse extends BaseInput { - private mousePosition; - private mouseDelta; - private mouseWheel; - private mouseButtons; - constructor(element: HTMLElement); - capture(): void; - release(): void; - getState(): IMouse; - private handleMouseDown; - private handleMouseMove; - private handleMouseUp; - private handlePointerChange; -} -export declare class Position { - x: number; - y: number; -} -export declare class MouseButtons { - keysDown: Map; - keysJustPressed: Map; - keysJustReleased: Map; -} -export declare class Delta { - x: number; - y: number; -} -export interface IMouse { - mouseButtons: MouseButtons; - mousePosition: Position; - mouseWheel: Delta; - mouseDelta: Delta; -} +import { BaseInput } from './base-input'; +export declare class Mouse extends BaseInput { + private mousePosition; + private mouseDelta; + private mouseWheel; + private mouseButtons; + constructor(element: HTMLElement); + capture(): void; + release(): void; + getState(): IMouse; + private handleMouseDown; + private handleMouseMove; + private handleMouseUp; + private handlePointerChange; +} +export declare class Position { + x: number; + y: number; +} +export declare class MouseButtons { + keysDown: Map; + keysJustPressed: Map; + keysJustReleased: Map; +} +export declare class Delta { + x: number; + y: number; +} +export interface IMouse { + mouseButtons: MouseButtons; + mousePosition: Position; + mouseWheel: Delta; + mouseDelta: Delta; +} diff --git a/src/framework/input/inputs/mouse.js b/src/framework/input/inputs/mouse.js index e14b4e9..2d1bf20 100644 --- a/src/framework/input/inputs/mouse.js +++ b/src/framework/input/inputs/mouse.js @@ -1,87 +1,87 @@ -import { BaseInput } from './base-input'; -export class Mouse extends BaseInput { - constructor(element) { - super(element); - this.mousePosition = new Position(); - this.mouseDelta = new Delta(); - this.mouseWheel = new Delta(); - this.mouseButtons = new MouseButtons(); - } - capture() { - this.handleMouseDown = this.handleMouseDown.bind(this); - this.handleMouseMove = this.handleMouseMove.bind(this); - this.handleMouseUp = this.handleMouseUp.bind(this); - this.handlePointerChange = this.handlePointerChange.bind(this); - this.active = true; - this.element.addEventListener('mousedown', this.handleMouseDown); - this.element.addEventListener('mousemove', this.handleMouseMove); - this.element.addEventListener('mouseup', this.handleMouseUp); - document.addEventListener('pointerlockchange', this.handlePointerChange); - } - release() { - this.active = false; - this.element.removeEventListener('mousedown', this.handleMouseDown); - this.element.removeEventListener('mousemove', this.handleMouseMove); - this.element.removeEventListener('mouseup', this.handleMouseUp); - } - getState() { - const { mouseButtons, mouseDelta, mousePosition, mouseWheel } = this; - const state = { - mouseButtons: { - keysDown: new Map(this.mouseButtons.keysDown), - keysJustPressed: new Map(this.mouseButtons.keysJustPressed), - keysJustReleased: new Map(this.mouseButtons.keysJustReleased) - }, - mouseDelta, - mousePosition, - mouseWheel - }; - this.mouseButtons.keysJustPressed.clear(); - this.mouseButtons.keysJustReleased.clear(); - this.mouseDelta.x = 0; - this.mouseDelta.y = 0; - return state; - } - handleMouseDown(event) { - if (this.active) - event.preventDefault(); - this.mouseButtons.keysDown.set(event.button, true); - this.mouseButtons.keysJustPressed.set(event.button, true); - this.mouseButtons.keysJustReleased.set(event.button, false); - } - handleMouseMove(event) { - if (this.active) - event.preventDefault(); - this.mousePosition.x = event.clientX; - this.mousePosition.y = event.clientY; - this.mouseDelta.x = event.movementX; - this.mouseDelta.y = event.movementY; - } - handleMouseUp(event) { - if (this.active) - event.preventDefault(); - this.mouseButtons.keysJustReleased.set(event.button, true); - this.mouseButtons.keysDown.set(event.button, false); - this.mouseButtons.keysJustPressed.set(event.button, false); - } - handlePointerChange() { - if (document.pointerLockElement !== this.element) { - this.element.addEventListener('click', () => { - this.element.requestPointerLock(); - }, { - once: true - }); - } - } -} -export class Position { -} -export class MouseButtons { - constructor() { - this.keysDown = new Map(); - this.keysJustPressed = new Map(); - this.keysJustReleased = new Map(); - } -} -export class Delta { -} +import { BaseInput } from './base-input'; +export class Mouse extends BaseInput { + constructor(element) { + super(element); + this.mousePosition = new Position(); + this.mouseDelta = new Delta(); + this.mouseWheel = new Delta(); + this.mouseButtons = new MouseButtons(); + } + capture() { + this.handleMouseDown = this.handleMouseDown.bind(this); + this.handleMouseMove = this.handleMouseMove.bind(this); + this.handleMouseUp = this.handleMouseUp.bind(this); + this.handlePointerChange = this.handlePointerChange.bind(this); + this.active = true; + this.element.addEventListener('mousedown', this.handleMouseDown); + this.element.addEventListener('mousemove', this.handleMouseMove); + this.element.addEventListener('mouseup', this.handleMouseUp); + document.addEventListener('pointerlockchange', this.handlePointerChange); + } + release() { + this.active = false; + this.element.removeEventListener('mousedown', this.handleMouseDown); + this.element.removeEventListener('mousemove', this.handleMouseMove); + this.element.removeEventListener('mouseup', this.handleMouseUp); + } + getState() { + const { mouseButtons, mouseDelta, mousePosition, mouseWheel } = this; + const state = { + mouseButtons: { + keysDown: new Map(this.mouseButtons.keysDown), + keysJustPressed: new Map(this.mouseButtons.keysJustPressed), + keysJustReleased: new Map(this.mouseButtons.keysJustReleased) + }, + mouseDelta, + mousePosition, + mouseWheel + }; + this.mouseButtons.keysJustPressed.clear(); + this.mouseButtons.keysJustReleased.clear(); + this.mouseDelta.x = 0; + this.mouseDelta.y = 0; + return state; + } + handleMouseDown(event) { + if (this.active) + event.preventDefault(); + this.mouseButtons.keysDown.set(event.button, true); + this.mouseButtons.keysJustPressed.set(event.button, true); + this.mouseButtons.keysJustReleased.set(event.button, false); + } + handleMouseMove(event) { + if (this.active) + event.preventDefault(); + this.mousePosition.x = event.clientX; + this.mousePosition.y = event.clientY; + this.mouseDelta.x = event.movementX; + this.mouseDelta.y = event.movementY; + } + handleMouseUp(event) { + if (this.active) + event.preventDefault(); + this.mouseButtons.keysJustReleased.set(event.button, true); + this.mouseButtons.keysDown.set(event.button, false); + this.mouseButtons.keysJustPressed.set(event.button, false); + } + handlePointerChange() { + if (document.pointerLockElement !== this.element) { + this.element.addEventListener('click', () => { + this.element.requestPointerLock(); + }, { + once: true + }); + } + } +} +export class Position { +} +export class MouseButtons { + constructor() { + this.keysDown = new Map(); + this.keysJustPressed = new Map(); + this.keysJustReleased = new Map(); + } +} +export class Delta { +} diff --git a/src/framework/input/interfaces/state.d.ts b/src/framework/input/interfaces/state.d.ts index 55fe5d4..2cdaa24 100644 --- a/src/framework/input/interfaces/state.d.ts +++ b/src/framework/input/interfaces/state.d.ts @@ -1,4 +1,4 @@ -import { IKeyboard } from '../inputs/keyboard'; -export interface State { - keyboard?: IKeyboard; -} +import { IKeyboard } from '../inputs/keyboard'; +export interface State { + keyboard?: IKeyboard; +} diff --git a/src/framework/input/interfaces/state.js b/src/framework/input/interfaces/state.js index cb0ff5c..509db18 100644 --- a/src/framework/input/interfaces/state.js +++ b/src/framework/input/interfaces/state.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/input/keycodes.d.ts b/src/framework/input/keycodes.d.ts index 3e0ca85..8ce351e 100644 --- a/src/framework/input/keycodes.d.ts +++ b/src/framework/input/keycodes.d.ts @@ -1,122 +1,122 @@ -export declare let KeyCodes: { - CANCEL: number; - HELP: number; - BACK_SPACE: number; - TAB: number; - CLEAR: number; - RETURN: number; - ENTER: number; - SHIFT: number; - CONTROL: number; - ALT: number; - PAUSE: number; - CAPS_LOCK: number; - ESCAPE: number; - SPACE: number; - PAGE_UP: number; - PAGE_DOWN: number; - END: number; - HOME: number; - LEFT: number; - UP: number; - RIGHT: number; - DOWN: number; - PRINTSCREEN: number; - INSERT: number; - DELETE: number; - 0: number; - 1: number; - 2: number; - 3: number; - 4: number; - 5: number; - 6: number; - 7: number; - 8: number; - 9: number; - SEMICOLON: number; - EQUALS: number; - A: number; - B: number; - C: number; - D: number; - E: number; - F: number; - G: number; - H: number; - I: number; - J: number; - K: number; - L: number; - M: number; - N: number; - O: number; - P: number; - Q: number; - R: number; - S: number; - T: number; - U: number; - V: number; - W: number; - X: number; - Y: number; - Z: number; - CONTEXT_MENU: number; - NUMPAD0: number; - NUMPAD1: number; - NUMPAD2: number; - NUMPAD3: number; - NUMPAD4: number; - NUMPAD5: number; - NUMPAD6: number; - NUMPAD7: number; - NUMPAD8: number; - NUMPAD9: number; - MULTIPLY: number; - ADD: number; - SEPARATOR: number; - SUBTRACT: number; - DECIMAL: number; - DIVIDE: number; - F1: number; - F2: number; - F3: number; - F4: number; - F5: number; - F6: number; - F7: number; - F8: number; - F9: number; - F10: number; - F11: number; - F12: number; - F13: number; - F14: number; - F15: number; - F16: number; - F17: number; - F18: number; - F19: number; - F20: number; - F21: number; - F22: number; - F23: number; - F24: number; - NUM_LOCK: number; - SCROLL_LOCK: number; - COMMA: number; - PERIOD: number; - SLASH: number; - BACK_QUOTE: number; - OPEN_BRACKET: number; - BACK_SLASH: number; - CLOSE_BRACKET: number; - QUOTE: number; - META: number; -}; -export declare let MouseCodes: { - LEFT: number; - RIGHT: number; - MIDDLE: number; -}; +export declare let KeyCodes: { + CANCEL: number; + HELP: number; + BACK_SPACE: number; + TAB: number; + CLEAR: number; + RETURN: number; + ENTER: number; + SHIFT: number; + CONTROL: number; + ALT: number; + PAUSE: number; + CAPS_LOCK: number; + ESCAPE: number; + SPACE: number; + PAGE_UP: number; + PAGE_DOWN: number; + END: number; + HOME: number; + LEFT: number; + UP: number; + RIGHT: number; + DOWN: number; + PRINTSCREEN: number; + INSERT: number; + DELETE: number; + 0: number; + 1: number; + 2: number; + 3: number; + 4: number; + 5: number; + 6: number; + 7: number; + 8: number; + 9: number; + SEMICOLON: number; + EQUALS: number; + A: number; + B: number; + C: number; + D: number; + E: number; + F: number; + G: number; + H: number; + I: number; + J: number; + K: number; + L: number; + M: number; + N: number; + O: number; + P: number; + Q: number; + R: number; + S: number; + T: number; + U: number; + V: number; + W: number; + X: number; + Y: number; + Z: number; + CONTEXT_MENU: number; + NUMPAD0: number; + NUMPAD1: number; + NUMPAD2: number; + NUMPAD3: number; + NUMPAD4: number; + NUMPAD5: number; + NUMPAD6: number; + NUMPAD7: number; + NUMPAD8: number; + NUMPAD9: number; + MULTIPLY: number; + ADD: number; + SEPARATOR: number; + SUBTRACT: number; + DECIMAL: number; + DIVIDE: number; + F1: number; + F2: number; + F3: number; + F4: number; + F5: number; + F6: number; + F7: number; + F8: number; + F9: number; + F10: number; + F11: number; + F12: number; + F13: number; + F14: number; + F15: number; + F16: number; + F17: number; + F18: number; + F19: number; + F20: number; + F21: number; + F22: number; + F23: number; + F24: number; + NUM_LOCK: number; + SCROLL_LOCK: number; + COMMA: number; + PERIOD: number; + SLASH: number; + BACK_QUOTE: number; + OPEN_BRACKET: number; + BACK_SLASH: number; + CLOSE_BRACKET: number; + QUOTE: number; + META: number; +}; +export declare let MouseCodes: { + LEFT: number; + RIGHT: number; + MIDDLE: number; +}; diff --git a/src/framework/input/keycodes.js b/src/framework/input/keycodes.js index 6984435..03e5f9c 100644 --- a/src/framework/input/keycodes.js +++ b/src/framework/input/keycodes.js @@ -1,122 +1,122 @@ -export let KeyCodes = { - CANCEL: 3, - HELP: 6, - BACK_SPACE: 8, - TAB: 9, - CLEAR: 12, - RETURN: 13, - ENTER: 14, - SHIFT: 16, - CONTROL: 17, - ALT: 18, - PAUSE: 19, - CAPS_LOCK: 20, - ESCAPE: 27, - SPACE: 32, - PAGE_UP: 33, - PAGE_DOWN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - PRINTSCREEN: 44, - INSERT: 45, - DELETE: 46, - 0: 48, - 1: 49, - 2: 50, - 3: 51, - 4: 52, - 5: 53, - 6: 54, - 7: 55, - 8: 56, - 9: 57, - SEMICOLON: 59, - EQUALS: 61, - A: 65, - B: 66, - C: 67, - D: 68, - E: 69, - F: 70, - G: 71, - H: 72, - I: 73, - J: 74, - K: 75, - L: 76, - M: 77, - N: 78, - O: 79, - P: 80, - Q: 81, - R: 82, - S: 83, - T: 84, - U: 85, - V: 86, - W: 87, - X: 88, - Y: 89, - Z: 90, - CONTEXT_MENU: 93, - NUMPAD0: 96, - NUMPAD1: 97, - NUMPAD2: 98, - NUMPAD3: 99, - NUMPAD4: 100, - NUMPAD5: 101, - NUMPAD6: 102, - NUMPAD7: 103, - NUMPAD8: 104, - NUMPAD9: 105, - MULTIPLY: 106, - ADD: 107, - SEPARATOR: 108, - SUBTRACT: 109, - DECIMAL: 110, - DIVIDE: 111, - F1: 112, - F2: 113, - F3: 114, - F4: 115, - F5: 116, - F6: 117, - F7: 118, - F8: 119, - F9: 120, - F10: 121, - F11: 122, - F12: 123, - F13: 124, - F14: 125, - F15: 126, - F16: 127, - F17: 128, - F18: 129, - F19: 130, - F20: 131, - F21: 132, - F22: 133, - F23: 134, - F24: 135, - NUM_LOCK: 144, - SCROLL_LOCK: 145, - COMMA: 188, - PERIOD: 190, - SLASH: 191, - BACK_QUOTE: 192, - OPEN_BRACKET: 219, - BACK_SLASH: 220, - CLOSE_BRACKET: 221, - QUOTE: 222, - META: 224 -}; -export let MouseCodes = { - LEFT: 0, - RIGHT: 1, - MIDDLE: 2 -}; +export let KeyCodes = { + CANCEL: 3, + HELP: 6, + BACK_SPACE: 8, + TAB: 9, + CLEAR: 12, + RETURN: 13, + ENTER: 14, + SHIFT: 16, + CONTROL: 17, + ALT: 18, + PAUSE: 19, + CAPS_LOCK: 20, + ESCAPE: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + PRINTSCREEN: 44, + INSERT: 45, + DELETE: 46, + 0: 48, + 1: 49, + 2: 50, + 3: 51, + 4: 52, + 5: 53, + 6: 54, + 7: 55, + 8: 56, + 9: 57, + SEMICOLON: 59, + EQUALS: 61, + A: 65, + B: 66, + C: 67, + D: 68, + E: 69, + F: 70, + G: 71, + H: 72, + I: 73, + J: 74, + K: 75, + L: 76, + M: 77, + N: 78, + O: 79, + P: 80, + Q: 81, + R: 82, + S: 83, + T: 84, + U: 85, + V: 86, + W: 87, + X: 88, + Y: 89, + Z: 90, + CONTEXT_MENU: 93, + NUMPAD0: 96, + NUMPAD1: 97, + NUMPAD2: 98, + NUMPAD3: 99, + NUMPAD4: 100, + NUMPAD5: 101, + NUMPAD6: 102, + NUMPAD7: 103, + NUMPAD8: 104, + NUMPAD9: 105, + MULTIPLY: 106, + ADD: 107, + SEPARATOR: 108, + SUBTRACT: 109, + DECIMAL: 110, + DIVIDE: 111, + F1: 112, + F2: 113, + F3: 114, + F4: 115, + F5: 116, + F6: 117, + F7: 118, + F8: 119, + F9: 120, + F10: 121, + F11: 122, + F12: 123, + F13: 124, + F14: 125, + F15: 126, + F16: 127, + F17: 128, + F18: 129, + F19: 130, + F20: 131, + F21: 132, + F22: 133, + F23: 134, + F24: 135, + NUM_LOCK: 144, + SCROLL_LOCK: 145, + COMMA: 188, + PERIOD: 190, + SLASH: 191, + BACK_QUOTE: 192, + OPEN_BRACKET: 219, + BACK_SLASH: 220, + CLOSE_BRACKET: 221, + QUOTE: 222, + META: 224 +}; +export let MouseCodes = { + LEFT: 0, + RIGHT: 1, + MIDDLE: 2 +}; diff --git a/src/framework/math/box.d.ts b/src/framework/math/box.d.ts new file mode 100644 index 0000000..1a91c1d --- /dev/null +++ b/src/framework/math/box.d.ts @@ -0,0 +1,11 @@ +import Vec3 from "./vec3"; +export default class Box { + position: Vec3; + size: Vec3; + constructor(position: Vec3, size: Vec3); + center(): Vec3; + get upperBound(): Vec3; + contains(box: Box): boolean; + overlaps(box: Box): boolean; + containsPoint(x: number, y: number, z: number): boolean; +} diff --git a/src/framework/math/box.js b/src/framework/math/box.js new file mode 100644 index 0000000..bc0adae --- /dev/null +++ b/src/framework/math/box.js @@ -0,0 +1,48 @@ +import Vec3 from "./vec3"; +export default class Box { + constructor(position, size) { + this.position = position; + this.size = size; + } + center() { + return new Vec3([ + this.position.x + this.size.x / 2, + this.position.y + this.size.y / 2, + this.position.z + this.size.z / 2, + ]); + } + get upperBound() { + return new Vec3([ + this.position.x + this.size.x, + this.position.y + this.size.y, + this.position.z + this.size.z, + ]); + } + contains(box) { + return ((box.position.x >= this.position.x && + box.position.x <= this.position.x + this.size.x && + box.position.y >= this.position.y && + box.position.y <= this.position.y + this.size.y && + box.position.z >= this.position.z && + box.position.z <= this.position.z + this.size.z) && + (box.position.x + box.size.x >= this.position.x && + box.position.x + box.size.x <= this.position.x + this.size.x && + box.position.y + box.size.y >= this.position.y && + box.position.y + box.size.y <= this.position.y + this.size.y && + box.position.z + box.size.z >= this.position.z && + box.position.z + box.size.z <= this.position.z + this.size.z)); + } + overlaps(box) { + return this.position.x <= box.position.x + box.size.x && + this.position.x + this.size.x >= box.position.x && + this.position.y <= box.position.y + box.size.y && + this.position.y + this.size.y >= box.position.y && + this.position.z <= box.position.z + box.size.z && + this.position.z + this.size.z >= box.position.z; + } + containsPoint(x, y, z) { + return (x >= this.position.x && x <= this.position.x + this.size.x && + y >= this.position.y && y <= this.position.y + this.size.y && + z >= this.position.z && z <= this.position.z + this.size.z); + } +} diff --git a/src/framework/math/constants.d.ts b/src/framework/math/constants.d.ts new file mode 100644 index 0000000..669e322 --- /dev/null +++ b/src/framework/math/constants.d.ts @@ -0,0 +1 @@ +export declare const epsilon = 0.00001; diff --git a/src/framework/math/constants.js b/src/framework/math/constants.js new file mode 100644 index 0000000..592a1d1 --- /dev/null +++ b/src/framework/math/constants.js @@ -0,0 +1 @@ +export const epsilon = 0.00001; diff --git a/src/framework/math/mat2.d.ts b/src/framework/math/mat2.d.ts new file mode 100644 index 0000000..09bd076 --- /dev/null +++ b/src/framework/math/mat2.d.ts @@ -0,0 +1,23 @@ +import vec2 from './vec2'; +export default class mat2 { + constructor(values?: number[]); + private values; + static readonly identity: mat2; + at(index: number): number; + init(values: number[]): mat2; + reset(): void; + copy(dest?: mat2): mat2; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat2, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat2; + transpose(): mat2; + inverse(): mat2; + multiply(matrix: mat2): mat2; + rotate(angle: number): mat2; + multiplyVec2(vector: vec2, result: vec2): vec2; + scale(vector: vec2): mat2; + static product(m1: mat2, m2: mat2, result: mat2): mat2; +} diff --git a/src/framework/math/mat2.js b/src/framework/math/mat2.js new file mode 100644 index 0000000..a1ac925 --- /dev/null +++ b/src/framework/math/mat2.js @@ -0,0 +1,161 @@ +import vec2 from './vec2'; +import { epsilon } from './constants'; +export default class mat2 { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 4; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 4; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat2(); + } + for (let i = 0; i < 4; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 4; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [this.values[index * 2 + 0], this.values[index * 2 + 1]]; + } + col(index) { + return [this.values[index], this.values[index + 2]]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 4; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + return this.values[0] * this.values[3] - this.values[2] * this.values[1]; + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 1; + return this; + } + transpose() { + const temp = this.values[1]; + this.values[1] = this.values[2]; + this.values[2] = temp; + return this; + } + inverse() { + let det = this.determinant(); + if (!det) { + return null; + } + det = 1.0 / det; + const a11 = this.values[0]; + this.values[0] = det * this.values[3]; + this.values[1] = det * -this.values[1]; + this.values[2] = det * -this.values[2]; + this.values[3] = det * a11; + return this; + } + multiply(matrix) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + this.values[0] = a11 * matrix.at(0) + a12 * matrix.at(2); + this.values[1] = a11 * matrix.at(1) + a12 * matrix.at(3); + this.values[2] = a21 * matrix.at(0) + a22 * matrix.at(2); + this.values[3] = a21 * matrix.at(1) + a22 * matrix.at(3); + return this; + } + rotate(angle) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + const sin = Math.sin(angle); + const cos = Math.cos(angle); + this.values[0] = a11 * cos + a12 * sin; + this.values[1] = a11 * -sin + a12 * cos; + this.values[2] = a21 * cos + a22 * sin; + this.values[3] = a21 * -sin + a22 * cos; + return this; + } + multiplyVec2(vector, result) { + const x = vector.x; + const y = vector.y; + if (result) { + result.xy = [ + x * this.values[0] + y * this.values[1], + x * this.values[2] + y * this.values[3] + ]; + return result; + } + else { + return new vec2([ + x * this.values[0] + y * this.values[1], + x * this.values[2] + y * this.values[3] + ]); + } + } + scale(vector) { + const a11 = this.values[0]; + const a12 = this.values[1]; + const a21 = this.values[2]; + const a22 = this.values[3]; + const x = vector.x; + const y = vector.y; + this.values[0] = a11 * x; + this.values[1] = a12 * y; + this.values[2] = a21 * x; + this.values[3] = a22 * y; + return this; + } + static product(m1, m2, result) { + const a11 = m1.at(0); + const a12 = m1.at(1); + const a21 = m1.at(2); + const a22 = m1.at(3); + if (result) { + result.init([ + a11 * m2.at(0) + a12 * m2.at(2), + a11 * m2.at(1) + a12 * m2.at(3), + a21 * m2.at(0) + a22 * m2.at(2), + a21 * m2.at(1) + a22 * m2.at(3) + ]); + return result; + } + else { + return new mat2([ + a11 * m2.at(0) + a12 * m2.at(2), + a11 * m2.at(1) + a12 * m2.at(3), + a21 * m2.at(0) + a22 * m2.at(2), + a21 * m2.at(1) + a22 * m2.at(3) + ]); + } + } +} +mat2.identity = new mat2().setIdentity(); diff --git a/src/framework/math/mat3.d.ts b/src/framework/math/mat3.d.ts new file mode 100644 index 0000000..3df4b3e --- /dev/null +++ b/src/framework/math/mat3.d.ts @@ -0,0 +1,28 @@ +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +export default class mat3 { + constructor(values?: number[]); + private values; + static readonly identity: mat3; + at(index: number): number; + init(values: number[]): mat3; + reset(): void; + copy(dest?: mat3): mat3; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat3, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat3; + transpose(): mat3; + inverse(): mat3; + multiply(matrix: mat3): mat3; + multiplyVec2(vector: vec2, result: vec2): vec2; + multiplyVec3(vector: vec3, result: vec3): vec3; + toMat4(result: mat4): mat4; + toQuat(): quat; + rotate(angle: number, axis: vec3): mat3; + static product(m1: mat3, m2: mat3, result: mat3): mat3; +} diff --git a/src/framework/math/mat3.js b/src/framework/math/mat3.js new file mode 100644 index 0000000..2359a3c --- /dev/null +++ b/src/framework/math/mat3.js @@ -0,0 +1,392 @@ +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class mat3 { + constructor(values) { + this.values = new Float32Array(9); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 9; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 9; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat3(); + } + for (let i = 0; i < 9; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 9; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [ + this.values[index * 3 + 0], + this.values[index * 3 + 1], + this.values[index * 3 + 2] + ]; + } + col(index) { + return [this.values[index], this.values[index + 3], this.values[index + 6]]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 9; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + return a00 * det01 + a01 * det11 + a02 * det21; + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 1; + this.values[5] = 0; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 1; + return this; + } + transpose() { + const temp01 = this.values[1]; + const temp02 = this.values[2]; + const temp12 = this.values[5]; + this.values[1] = this.values[3]; + this.values[2] = this.values[6]; + this.values[3] = temp01; + this.values[5] = this.values[7]; + this.values[6] = temp02; + this.values[7] = temp12; + return this; + } + inverse() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + let det = a00 * det01 + a01 * det11 + a02 * det21; + if (!det) { + return null; + } + det = 1.0 / det; + this.values[0] = det01 * det; + this.values[1] = (-a22 * a01 + a02 * a21) * det; + this.values[2] = (a12 * a01 - a02 * a11) * det; + this.values[3] = det11 * det; + this.values[4] = (a22 * a00 - a02 * a20) * det; + this.values[5] = (-a12 * a00 + a02 * a10) * det; + this.values[6] = det21 * det; + this.values[7] = (-a21 * a00 + a01 * a20) * det; + this.values[8] = (a11 * a00 - a01 * a10) * det; + return this; + } + multiply(matrix) { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[3]; + const a11 = this.values[4]; + const a12 = this.values[5]; + const a20 = this.values[6]; + const a21 = this.values[7]; + const a22 = this.values[8]; + const b00 = matrix.at(0); + const b01 = matrix.at(1); + const b02 = matrix.at(2); + const b10 = matrix.at(3); + const b11 = matrix.at(4); + const b12 = matrix.at(5); + const b20 = matrix.at(6); + const b21 = matrix.at(7); + const b22 = matrix.at(8); + this.values[0] = b00 * a00 + b01 * a10 + b02 * a20; + this.values[1] = b00 * a01 + b01 * a11 + b02 * a21; + this.values[2] = b00 * a02 + b01 * a12 + b02 * a22; + this.values[3] = b10 * a00 + b11 * a10 + b12 * a20; + this.values[4] = b10 * a01 + b11 * a11 + b12 * a21; + this.values[5] = b10 * a02 + b11 * a12 + b12 * a22; + this.values[6] = b20 * a00 + b21 * a10 + b22 * a20; + this.values[7] = b20 * a01 + b21 * a11 + b22 * a21; + this.values[8] = b20 * a02 + b21 * a12 + b22 * a22; + return this; + } + multiplyVec2(vector, result) { + const x = vector.x; + const y = vector.y; + if (result) { + result.xy = [ + x * this.values[0] + y * this.values[3] + this.values[6], + x * this.values[1] + y * this.values[4] + this.values[7] + ]; + return result; + } + else { + return new vec2([ + x * this.values[0] + y * this.values[3] + this.values[6], + x * this.values[1] + y * this.values[4] + this.values[7] + ]); + } + } + multiplyVec3(vector, result) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + if (result) { + result.xyz = [ + x * this.values[0] + y * this.values[3] + z * this.values[6], + x * this.values[1] + y * this.values[4] + z * this.values[7], + x * this.values[2] + y * this.values[5] + z * this.values[8] + ]; + return result; + } + else { + return new vec3([ + x * this.values[0] + y * this.values[3] + z * this.values[6], + x * this.values[1] + y * this.values[4] + z * this.values[7], + x * this.values[2] + y * this.values[5] + z * this.values[8] + ]); + } + } + toMat4(result) { + if (result) { + result.init([ + this.values[0], + this.values[1], + this.values[2], + 0, + this.values[3], + this.values[4], + this.values[5], + 0, + this.values[6], + this.values[7], + this.values[8], + 0, + 0, + 0, + 0, + 1 + ]); + return result; + } + else { + return new mat4([ + this.values[0], + this.values[1], + this.values[2], + 0, + this.values[3], + this.values[4], + this.values[5], + 0, + this.values[6], + this.values[7], + this.values[8], + 0, + 0, + 0, + 0, + 1 + ]); + } + } + toQuat() { + const m00 = this.values[0]; + const m01 = this.values[1]; + const m02 = this.values[2]; + const m10 = this.values[3]; + const m11 = this.values[4]; + const m12 = this.values[5]; + const m20 = this.values[6]; + const m21 = this.values[7]; + const m22 = this.values[8]; + const fourXSquaredMinus1 = m00 - m11 - m22; + const fourYSquaredMinus1 = m11 - m00 - m22; + const fourZSquaredMinus1 = m22 - m00 - m11; + const fourWSquaredMinus1 = m00 + m11 + m22; + let biggestIndex = 0; + let fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + const biggestVal = Math.sqrt(fourBiggestSquaredMinus1 + 1) * 0.5; + const mult = 0.25 / biggestVal; + const result = new quat(); + switch (biggestIndex) { + case 0: + result.w = biggestVal; + result.x = (m12 - m21) * mult; + result.y = (m20 - m02) * mult; + result.z = (m01 - m10) * mult; + break; + case 1: + result.w = (m12 - m21) * mult; + result.x = biggestVal; + result.y = (m01 + m10) * mult; + result.z = (m20 + m02) * mult; + break; + case 2: + result.w = (m20 - m02) * mult; + result.x = (m01 + m10) * mult; + result.y = biggestVal; + result.z = (m12 + m21) * mult; + break; + case 3: + result.w = (m01 - m10) * mult; + result.x = (m20 + m02) * mult; + result.y = (m12 + m21) * mult; + result.z = biggestVal; + break; + } + return result; + } + rotate(angle, axis) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (!length) { + return null; + } + if (length !== 1) { + length = 1 / length; + x *= length; + y *= length; + z *= length; + } + const s = Math.sin(angle); + const c = Math.cos(angle); + const t = 1.0 - c; + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const b00 = x * x * t + c; + const b01 = y * x * t + z * s; + const b02 = z * x * t - y * s; + const b10 = x * y * t - z * s; + const b11 = y * y * t + c; + const b12 = z * y * t + x * s; + const b20 = x * z * t + y * s; + const b21 = y * z * t - x * s; + const b22 = z * z * t + c; + this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; + this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; + this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; + this.values[3] = a00 * b10 + a10 * b11 + a20 * b12; + this.values[4] = a01 * b10 + a11 * b11 + a21 * b12; + this.values[5] = a02 * b10 + a12 * b11 + a22 * b12; + this.values[6] = a00 * b20 + a10 * b21 + a20 * b22; + this.values[7] = a01 * b20 + a11 * b21 + a21 * b22; + this.values[8] = a02 * b20 + a12 * b21 + a22 * b22; + return this; + } + static product(m1, m2, result) { + const a00 = m1.at(0); + const a01 = m1.at(1); + const a02 = m1.at(2); + const a10 = m1.at(3); + const a11 = m1.at(4); + const a12 = m1.at(5); + const a20 = m1.at(6); + const a21 = m1.at(7); + const a22 = m1.at(8); + const b00 = m2.at(0); + const b01 = m2.at(1); + const b02 = m2.at(2); + const b10 = m2.at(3); + const b11 = m2.at(4); + const b12 = m2.at(5); + const b20 = m2.at(6); + const b21 = m2.at(7); + const b22 = m2.at(8); + if (result) { + result.init([ + b00 * a00 + b01 * a10 + b02 * a20, + b00 * a01 + b01 * a11 + b02 * a21, + b00 * a02 + b01 * a12 + b02 * a22, + b10 * a00 + b11 * a10 + b12 * a20, + b10 * a01 + b11 * a11 + b12 * a21, + b10 * a02 + b11 * a12 + b12 * a22, + b20 * a00 + b21 * a10 + b22 * a20, + b20 * a01 + b21 * a11 + b22 * a21, + b20 * a02 + b21 * a12 + b22 * a22 + ]); + return result; + } + else { + return new mat3([ + b00 * a00 + b01 * a10 + b02 * a20, + b00 * a01 + b01 * a11 + b02 * a21, + b00 * a02 + b01 * a12 + b02 * a22, + b10 * a00 + b11 * a10 + b12 * a20, + b10 * a01 + b11 * a11 + b12 * a21, + b10 * a02 + b11 * a12 + b12 * a22, + b20 * a00 + b21 * a10 + b22 * a20, + b20 * a01 + b21 * a11 + b22 * a21, + b20 * a02 + b21 * a12 + b22 * a22 + ]); + } + } +} +mat3.identity = new mat3().setIdentity(); diff --git a/src/framework/math/mat4.d.ts b/src/framework/math/mat4.d.ts new file mode 100644 index 0000000..249550d --- /dev/null +++ b/src/framework/math/mat4.d.ts @@ -0,0 +1,33 @@ +import mat3 from './mat3'; +import vec3 from './vec3'; +import vec4 from './vec4'; +export default class mat4 { + constructor(values?: number[]); + private values; + static readonly identity: mat4; + at(index: number): number; + init(values: number[]): mat4; + reset(): void; + copy(dest?: mat4): mat4; + all(): number[]; + row(index: number): number[]; + col(index: number): number[]; + equals(matrix: mat4, threshold?: number): boolean; + determinant(): number; + setIdentity(): mat4; + transpose(): mat4; + inverse(): mat4; + multiply(matrix: mat4): mat4; + multiplyVec3(vector: vec3): vec3; + multiplyVec4(vector: vec4, dest?: vec4): vec4; + toMat3(): mat3; + toInverseMat3(): mat3; + translate(vector: vec3): mat4; + scale(vector: vec3): mat4; + rotate(angle: number, axis: vec3): mat4; + static frustum(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; + static perspective(fov: number, aspect: number, near: number, far: number): mat4; + static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): mat4; + static lookAt(position: vec3, target: vec3, up?: vec3): mat4; + static product(m1: mat4, m2: mat4, result: mat4): mat4; +} diff --git a/src/framework/math/mat4.js b/src/framework/math/mat4.js new file mode 100644 index 0000000..b8fb710 --- /dev/null +++ b/src/framework/math/mat4.js @@ -0,0 +1,579 @@ +import mat3 from './mat3'; +import vec3 from './vec3'; +import vec4 from './vec4'; +import { epsilon } from './constants'; +export default class mat4 { + constructor(values) { + this.values = new Float32Array(16); + if (values !== undefined) { + this.init(values); + } + } + at(index) { + return this.values[index]; + } + init(values) { + for (let i = 0; i < 16; i++) { + this.values[i] = values[i]; + } + return this; + } + reset() { + for (let i = 0; i < 16; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new mat4(); + } + for (let i = 0; i < 16; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + all() { + const data = []; + for (let i = 0; i < 16; i++) { + data[i] = this.values[i]; + } + return data; + } + row(index) { + return [ + this.values[index * 4 + 0], + this.values[index * 4 + 1], + this.values[index * 4 + 2], + this.values[index * 4 + 3] + ]; + } + col(index) { + return [ + this.values[index], + this.values[index + 4], + this.values[index + 8], + this.values[index + 12] + ]; + } + equals(matrix, threshold = epsilon) { + for (let i = 0; i < 16; i++) { + if (Math.abs(this.values[i] - matrix.at(i)) > threshold) { + return false; + } + } + return true; + } + determinant() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + const det00 = a00 * a11 - a01 * a10; + const det01 = a00 * a12 - a02 * a10; + const det02 = a00 * a13 - a03 * a10; + const det03 = a01 * a12 - a02 * a11; + const det04 = a01 * a13 - a03 * a11; + const det05 = a02 * a13 - a03 * a12; + const det06 = a20 * a31 - a21 * a30; + const det07 = a20 * a32 - a22 * a30; + const det08 = a20 * a33 - a23 * a30; + const det09 = a21 * a32 - a22 * a31; + const det10 = a21 * a33 - a23 * a31; + const det11 = a22 * a33 - a23 * a32; + return (det00 * det11 - + det01 * det10 + + det02 * det09 + + det03 * det08 - + det04 * det07 + + det05 * det06); + } + setIdentity() { + this.values[0] = 1; + this.values[1] = 0; + this.values[2] = 0; + this.values[3] = 0; + this.values[4] = 0; + this.values[5] = 1; + this.values[6] = 0; + this.values[7] = 0; + this.values[8] = 0; + this.values[9] = 0; + this.values[10] = 1; + this.values[11] = 0; + this.values[12] = 0; + this.values[13] = 0; + this.values[14] = 0; + this.values[15] = 1; + return this; + } + transpose() { + const temp01 = this.values[1]; + const temp02 = this.values[2]; + const temp03 = this.values[3]; + const temp12 = this.values[6]; + const temp13 = this.values[7]; + const temp23 = this.values[11]; + this.values[1] = this.values[4]; + this.values[2] = this.values[8]; + this.values[3] = this.values[12]; + this.values[4] = temp01; + this.values[6] = this.values[9]; + this.values[7] = this.values[13]; + this.values[8] = temp02; + this.values[9] = temp12; + this.values[11] = this.values[14]; + this.values[12] = temp03; + this.values[13] = temp13; + this.values[14] = temp23; + return this; + } + inverse() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + const det00 = a00 * a11 - a01 * a10; + const det01 = a00 * a12 - a02 * a10; + const det02 = a00 * a13 - a03 * a10; + const det03 = a01 * a12 - a02 * a11; + const det04 = a01 * a13 - a03 * a11; + const det05 = a02 * a13 - a03 * a12; + const det06 = a20 * a31 - a21 * a30; + const det07 = a20 * a32 - a22 * a30; + const det08 = a20 * a33 - a23 * a30; + const det09 = a21 * a32 - a22 * a31; + const det10 = a21 * a33 - a23 * a31; + const det11 = a22 * a33 - a23 * a32; + let det = det00 * det11 - + det01 * det10 + + det02 * det09 + + det03 * det08 - + det04 * det07 + + det05 * det06; + if (!det) { + return null; + } + det = 1.0 / det; + this.values[0] = (a11 * det11 - a12 * det10 + a13 * det09) * det; + this.values[1] = (-a01 * det11 + a02 * det10 - a03 * det09) * det; + this.values[2] = (a31 * det05 - a32 * det04 + a33 * det03) * det; + this.values[3] = (-a21 * det05 + a22 * det04 - a23 * det03) * det; + this.values[4] = (-a10 * det11 + a12 * det08 - a13 * det07) * det; + this.values[5] = (a00 * det11 - a02 * det08 + a03 * det07) * det; + this.values[6] = (-a30 * det05 + a32 * det02 - a33 * det01) * det; + this.values[7] = (a20 * det05 - a22 * det02 + a23 * det01) * det; + this.values[8] = (a10 * det10 - a11 * det08 + a13 * det06) * det; + this.values[9] = (-a00 * det10 + a01 * det08 - a03 * det06) * det; + this.values[10] = (a30 * det04 - a31 * det02 + a33 * det00) * det; + this.values[11] = (-a20 * det04 + a21 * det02 - a23 * det00) * det; + this.values[12] = (-a10 * det09 + a11 * det07 - a12 * det06) * det; + this.values[13] = (a00 * det09 - a01 * det07 + a02 * det06) * det; + this.values[14] = (-a30 * det03 + a31 * det01 - a32 * det00) * det; + this.values[15] = (a20 * det03 - a21 * det01 + a22 * det00) * det; + return this; + } + multiply(matrix) { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const a30 = this.values[12]; + const a31 = this.values[13]; + const a32 = this.values[14]; + const a33 = this.values[15]; + let b0 = matrix.at(0); + let b1 = matrix.at(1); + let b2 = matrix.at(2); + let b3 = matrix.at(3); + this.values[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(4); + b1 = matrix.at(5); + b2 = matrix.at(6); + b3 = matrix.at(7); + this.values[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(8); + b1 = matrix.at(9); + b2 = matrix.at(10); + b3 = matrix.at(11); + this.values[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = matrix.at(12); + b1 = matrix.at(13); + b2 = matrix.at(14); + b3 = matrix.at(15); + this.values[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + this.values[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + this.values[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + this.values[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + return this; + } + multiplyVec3(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + return new vec3([ + this.values[0] * x + + this.values[4] * y + + this.values[8] * z + + this.values[12], + this.values[1] * x + + this.values[5] * y + + this.values[9] * z + + this.values[13], + this.values[2] * x + + this.values[6] * y + + this.values[10] * z + + this.values[14] + ]); + } + multiplyVec4(vector, dest) { + if (!dest) { + dest = new vec4(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const w = vector.w; + dest.x = + this.values[0] * x + + this.values[4] * y + + this.values[8] * z + + this.values[12] * w; + dest.y = + this.values[1] * x + + this.values[5] * y + + this.values[9] * z + + this.values[13] * w; + dest.z = + this.values[2] * x + + this.values[6] * y + + this.values[10] * z + + this.values[14] * w; + dest.w = + this.values[3] * x + + this.values[7] * y + + this.values[11] * z + + this.values[15] * w; + return dest; + } + toMat3() { + return new mat3([ + this.values[0], + this.values[1], + this.values[2], + this.values[4], + this.values[5], + this.values[6], + this.values[8], + this.values[9], + this.values[10] + ]); + } + toInverseMat3() { + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const det01 = a22 * a11 - a12 * a21; + const det11 = -a22 * a10 + a12 * a20; + const det21 = a21 * a10 - a11 * a20; + let det = a00 * det01 + a01 * det11 + a02 * det21; + if (!det) { + return null; + } + det = 1.0 / det; + return new mat3([ + det01 * det, + (-a22 * a01 + a02 * a21) * det, + (a12 * a01 - a02 * a11) * det, + det11 * det, + (a22 * a00 - a02 * a20) * det, + (-a12 * a00 + a02 * a10) * det, + det21 * det, + (-a21 * a00 + a01 * a20) * det, + (a11 * a00 - a01 * a10) * det + ]); + } + translate(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + this.values[12] += + this.values[0] * x + this.values[4] * y + this.values[8] * z; + this.values[13] += + this.values[1] * x + this.values[5] * y + this.values[9] * z; + this.values[14] += + this.values[2] * x + this.values[6] * y + this.values[10] * z; + this.values[15] += + this.values[3] * x + this.values[7] * y + this.values[11] * z; + return this; + } + scale(vector) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + this.values[0] *= x; + this.values[1] *= x; + this.values[2] *= x; + this.values[3] *= x; + this.values[4] *= y; + this.values[5] *= y; + this.values[6] *= y; + this.values[7] *= y; + this.values[8] *= z; + this.values[9] *= z; + this.values[10] *= z; + this.values[11] *= z; + return this; + } + rotate(angle, axis) { + let x = axis.x; + let y = axis.y; + let z = axis.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (!length) { + return null; + } + if (length !== 1) { + length = 1 / length; + x *= length; + y *= length; + z *= length; + } + const s = Math.sin(angle); + const c = Math.cos(angle); + const t = 1.0 - c; + const a00 = this.values[0]; + const a01 = this.values[1]; + const a02 = this.values[2]; + const a03 = this.values[3]; + const a10 = this.values[4]; + const a11 = this.values[5]; + const a12 = this.values[6]; + const a13 = this.values[7]; + const a20 = this.values[8]; + const a21 = this.values[9]; + const a22 = this.values[10]; + const a23 = this.values[11]; + const b00 = x * x * t + c; + const b01 = y * x * t + z * s; + const b02 = z * x * t - y * s; + const b10 = x * y * t - z * s; + const b11 = y * y * t + c; + const b12 = z * y * t + x * s; + const b20 = x * z * t + y * s; + const b21 = y * z * t - x * s; + const b22 = z * z * t + c; + this.values[0] = a00 * b00 + a10 * b01 + a20 * b02; + this.values[1] = a01 * b00 + a11 * b01 + a21 * b02; + this.values[2] = a02 * b00 + a12 * b01 + a22 * b02; + this.values[3] = a03 * b00 + a13 * b01 + a23 * b02; + this.values[4] = a00 * b10 + a10 * b11 + a20 * b12; + this.values[5] = a01 * b10 + a11 * b11 + a21 * b12; + this.values[6] = a02 * b10 + a12 * b11 + a22 * b12; + this.values[7] = a03 * b10 + a13 * b11 + a23 * b12; + this.values[8] = a00 * b20 + a10 * b21 + a20 * b22; + this.values[9] = a01 * b20 + a11 * b21 + a21 * b22; + this.values[10] = a02 * b20 + a12 * b21 + a22 * b22; + this.values[11] = a03 * b20 + a13 * b21 + a23 * b22; + return this; + } + static frustum(left, right, bottom, top, near, far) { + const rl = right - left; + const tb = top - bottom; + const fn = far - near; + return new mat4([ + (near * 2) / rl, + 0, + 0, + 0, + 0, + (near * 2) / tb, + 0, + 0, + (right + left) / rl, + (top + bottom) / tb, + -(far + near) / fn, + -1, + 0, + 0, + -(far * near * 2) / fn, + 0 + ]); + } + static perspective(fov, aspect, near, far) { + const top = near * Math.tan((fov * Math.PI) / 360.0); + const right = top * aspect; + return mat4.frustum(-right, right, -top, top, near, far); + } + static orthographic(left, right, bottom, top, near, far) { + const rl = right - left; + const tb = top - bottom; + const fn = far - near; + return new mat4([ + 2 / rl, + 0, + 0, + 0, + 0, + 2 / tb, + 0, + 0, + 0, + 0, + -2 / fn, + 0, + -(left + right) / rl, + -(top + bottom) / tb, + -(far + near) / fn, + 1 + ]); + } + static lookAt(position, target, up = vec3.up) { + if (position.equals(target)) { + return this.identity; + } + const z = vec3.difference(position, target).normalize(); + const x = vec3.cross(up, z).normalize(); + const y = vec3.cross(z, x).normalize(); + return new mat4([ + x.x, + y.x, + z.x, + 0, + x.y, + y.y, + z.y, + 0, + x.z, + y.z, + z.z, + 0, + -vec3.dot(x, position), + -vec3.dot(y, position), + -vec3.dot(z, position), + 1 + ]); + } + static product(m1, m2, result) { + const a00 = m1.at(0); + const a01 = m1.at(1); + const a02 = m1.at(2); + const a03 = m1.at(3); + const a10 = m1.at(4); + const a11 = m1.at(5); + const a12 = m1.at(6); + const a13 = m1.at(7); + const a20 = m1.at(8); + const a21 = m1.at(9); + const a22 = m1.at(10); + const a23 = m1.at(11); + const a30 = m1.at(12); + const a31 = m1.at(13); + const a32 = m1.at(14); + const a33 = m1.at(15); + const b00 = m2.at(0); + const b01 = m2.at(1); + const b02 = m2.at(2); + const b03 = m2.at(3); + const b10 = m2.at(4); + const b11 = m2.at(5); + const b12 = m2.at(6); + const b13 = m2.at(7); + const b20 = m2.at(8); + const b21 = m2.at(9); + const b22 = m2.at(10); + const b23 = m2.at(11); + const b30 = m2.at(12); + const b31 = m2.at(13); + const b32 = m2.at(14); + const b33 = m2.at(15); + if (result) { + result.init([ + b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, + b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, + b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, + b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, + b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, + b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, + b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, + b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, + b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, + b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, + b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, + b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, + b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, + b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, + b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, + b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 + ]); + return result; + } + else { + return new mat4([ + b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, + b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, + b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, + b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, + b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, + b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, + b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, + b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, + b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, + b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, + b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, + b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, + b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, + b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, + b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, + b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 + ]); + } + } +} +mat4.identity = new mat4().setIdentity(); diff --git a/src/framework/math/quat.d.ts b/src/framework/math/quat.d.ts new file mode 100644 index 0000000..ae2b929 --- /dev/null +++ b/src/framework/math/quat.d.ts @@ -0,0 +1,49 @@ +import mat3 from './mat3'; +import mat4 from './mat4'; +import vec3 from './vec3'; +export default class quat { + get x(): number; + get y(): number; + get z(): number; + get w(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + get xyzw(): [number, number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set w(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + set xyzw(values: [number, number, number, number]); + constructor(values?: [number, number, number, number]); + private values; + static readonly identity: quat; + at(index: number): number; + reset(): void; + copy(dest?: quat): quat; + roll(): number; + pitch(): number; + yaw(): number; + equals(vector: quat, threshold?: number): boolean; + setIdentity(): quat; + calculateW(): quat; + inverse(): quat; + conjugate(): quat; + length(): number; + normalize(dest?: quat): quat; + add(other: quat): quat; + multiply(other: quat): quat; + multiplyVec3(vector: vec3, dest?: vec3): vec3; + toMat3(dest?: mat3): mat3; + toMat4(dest?: mat4): mat4; + static dot(q1: quat, q2: quat): number; + static sum(q1: quat, q2: quat, dest?: quat): quat; + static product(q1: quat, q2: quat, dest?: quat): quat; + static cross(q1: quat, q2: quat, dest?: quat): quat; + static shortMix(q1: quat, q2: quat, time: number, dest?: quat): quat; + static mix(q1: quat, q2: quat, time: number, dest?: quat): quat; + static fromAxisAngle(axis: vec3, angle: number, dest?: quat): quat; + static fromVectors(u: vec3, v: vec3, dest?: quat): quat; + static fromAxisRadians(x: number, y: number, z: number, radians: number, dest?: quat): quat; +} diff --git a/src/framework/math/quat.js b/src/framework/math/quat.js new file mode 100644 index 0000000..915ad6c --- /dev/null +++ b/src/framework/math/quat.js @@ -0,0 +1,452 @@ +import mat3 from './mat3'; +import mat4 from './mat4'; +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class quat { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.xyzw = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get w() { + return this.values[3]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + get xyzw() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set w(value) { + this.values[3] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set xyzw(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + at(index) { + return this.values[index]; + } + reset() { + for (let i = 0; i < 4; i++) { + this.values[i] = 0; + } + } + copy(dest) { + if (!dest) { + dest = new quat(); + } + for (let i = 0; i < 4; i++) { + dest.values[i] = this.values[i]; + } + return dest; + } + roll() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.atan2(2.0 * (x * y + w * z), w * w + x * x - y * y - z * z); + } + pitch() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.atan2(2.0 * (y * z + w * x), w * w - x * x - y * y + z * z); + } + yaw() { + return Math.asin(2.0 * (this.x * this.z - this.w * this.y)); + } + equals(vector, threshold = epsilon) { + for (let i = 0; i < 4; i++) { + if (Math.abs(this.values[i] - vector.at(i)) > threshold) { + return false; + } + } + return true; + } + setIdentity() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 1; + return this; + } + calculateW() { + const x = this.x; + const y = this.y; + const z = this.z; + this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return this; + } + inverse() { + const dot = quat.dot(this, this); + if (!dot) { + this.xyzw = [0, 0, 0, 0]; + return this; + } + const invDot = dot ? 1.0 / dot : 0; + this.x *= -invDot; + this.y *= -invDot; + this.z *= -invDot; + this.w *= invDot; + return this; + } + conjugate() { + this.values[0] *= -1; + this.values[1] *= -1; + this.values[2] *= -1; + return this; + } + length() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return Math.sqrt(x * x + y * y + z * z + w * w); + } + normalize(dest) { + if (!dest) { + dest = this; + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + let length = Math.sqrt(x * x + y * y + z * z + w * w); + if (!length) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + dest.w = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + dest.z = z * length; + dest.w = w * length; + return dest; + } + add(other) { + for (let i = 0; i < 4; i++) { + this.values[i] += other.at(i); + } + return this; + } + multiply(other) { + const q1x = this.values[0]; + const q1y = this.values[1]; + const q1z = this.values[2]; + const q1w = this.values[3]; + const q2x = other.x; + const q2y = other.y; + const q2z = other.z; + const q2w = other.w; + this.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; + this.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; + this.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; + this.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + return this; + } + multiplyVec3(vector, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const qx = this.x; + const qy = this.y; + const qz = this.z; + const qw = this.w; + const ix = qw * x + qy * z - qz * y; + const iy = qw * y + qz * x - qx * z; + const iz = qw * z + qx * y - qy * x; + const iw = -qx * x - qy * y - qz * z; + dest.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; + dest.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; + dest.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return dest; + } + toMat3(dest) { + if (!dest) { + dest = new mat3(); + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + dest.init([ + 1 - (yy + zz), + xy + wz, + xz - wy, + xy - wz, + 1 - (xx + zz), + yz + wx, + xz + wy, + yz - wx, + 1 - (xx + yy) + ]); + return dest; + } + toMat4(dest) { + if (!dest) { + dest = new mat4(); + } + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + const x2 = x + x; + const y2 = y + y; + const z2 = z + z; + const xx = x * x2; + const xy = x * y2; + const xz = x * z2; + const yy = y * y2; + const yz = y * z2; + const zz = z * z2; + const wx = w * x2; + const wy = w * y2; + const wz = w * z2; + dest.init([ + 1 - (yy + zz), + xy + wz, + xz - wy, + 0, + xy - wz, + 1 - (xx + zz), + yz + wx, + 0, + xz + wy, + yz - wx, + 1 - (xx + yy), + 0, + 0, + 0, + 0, + 1 + ]); + return dest; + } + static dot(q1, q2) { + return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + } + static sum(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + dest.x = q1.x + q2.x; + dest.y = q1.y + q2.y; + dest.z = q1.z + q2.z; + dest.w = q1.w + q2.w; + return dest; + } + static product(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + const q1x = q1.x; + const q1y = q1.y; + const q1z = q1.z; + const q1w = q1.w; + const q2x = q2.x; + const q2y = q2.y; + const q2z = q2.z; + const q2w = q2.w; + dest.x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y; + dest.y = q1y * q2w + q1w * q2y + q1z * q2x - q1x * q2z; + dest.z = q1z * q2w + q1w * q2z + q1x * q2y - q1y * q2x; + dest.w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + return dest; + } + static cross(q1, q2, dest) { + if (!dest) { + dest = new quat(); + } + const q1x = q1.x; + const q1y = q1.y; + const q1z = q1.z; + const q1w = q1.w; + const q2x = q2.x; + const q2y = q2.y; + const q2z = q2.z; + const q2w = q2.w; + dest.x = q1w * q2z + q1z * q2w + q1x * q2y - q1y * q2x; + dest.y = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z; + dest.z = q1w * q2x + q1x * q2w + q1y * q2z - q1z * q2y; + dest.w = q1w * q2y + q1y * q2w + q1z * q2x - q1x * q2z; + return dest; + } + static shortMix(q1, q2, time, dest) { + if (!dest) { + dest = new quat(); + } + if (time <= 0.0) { + dest.xyzw = q1.xyzw; + return dest; + } + else if (time >= 1.0) { + dest.xyzw = q2.xyzw; + return dest; + } + let cos = quat.dot(q1, q2); + const q2a = q2.copy(); + if (cos < 0.0) { + q2a.inverse(); + cos = -cos; + } + let k0; + let k1; + if (cos > 0.9999) { + k0 = 1 - time; + k1 = 0 + time; + } + else { + const sin = Math.sqrt(1 - cos * cos); + const angle = Math.atan2(sin, cos); + const oneOverSin = 1 / sin; + k0 = Math.sin((1 - time) * angle) * oneOverSin; + k1 = Math.sin((0 + time) * angle) * oneOverSin; + } + dest.x = k0 * q1.x + k1 * q2a.x; + dest.y = k0 * q1.y + k1 * q2a.y; + dest.z = k0 * q1.z + k1 * q2a.z; + dest.w = k0 * q1.w + k1 * q2a.w; + return dest; + } + static mix(q1, q2, time, dest) { + if (!dest) { + dest = new quat(); + } + const cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + if (Math.abs(cosHalfTheta) >= 1.0) { + dest.xyzw = q1.xyzw; + return dest; + } + const halfTheta = Math.acos(cosHalfTheta); + const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); + if (Math.abs(sinHalfTheta) < 0.001) { + dest.x = q1.x * 0.5 + q2.x * 0.5; + dest.y = q1.y * 0.5 + q2.y * 0.5; + dest.z = q1.z * 0.5 + q2.z * 0.5; + dest.w = q1.w * 0.5 + q2.w * 0.5; + return dest; + } + const ratioA = Math.sin((1 - time) * halfTheta) / sinHalfTheta; + const ratioB = Math.sin(time * halfTheta) / sinHalfTheta; + dest.x = q1.x * ratioA + q2.x * ratioB; + dest.y = q1.y * ratioA + q2.y * ratioB; + dest.z = q1.z * ratioA + q2.z * ratioB; + dest.w = q1.w * ratioA + q2.w * ratioB; + return dest; + } + static fromAxisAngle(axis, angle, dest) { + if (!dest) { + dest = new quat(); + } + angle *= 0.5; + const sin = Math.sin(angle); + dest.x = axis.x * sin; + dest.y = axis.y * sin; + dest.z = axis.z * sin; + dest.w = Math.cos(angle); + return dest; + } + static fromVectors(u, v, dest) { + if (!dest) { + dest = new quat([0, 0, 0, 1]); + } + let d = clamp(vec3.dot(u, v), -1, 1); + let axis = vec3.cross(u, v); + let qw = Math.sqrt(u.squaredLength() * v.squaredLength()) + d; + if (qw < 0.0001) { + dest = new quat([-u.z, u.y, u.x, 0]).normalize(); + } + dest = new quat([qw, axis.x, axis.y, axis.z]).normalize(); + return dest; + } + static fromAxisRadians(x, y, z, radians, dest) { + if (!dest) { + dest = new quat([0, 0, 0, 1]); + } + let temp = new vec3([x, y, z]); + let d = temp.length(); + if (d == 0) { + return quat.identity; + } + d = 1 / d; + let l_angle = 0; + if (radians < 0) { + l_angle = (Math.PI * 2) - (-1 * radians % (Math.PI * 2)); + } + else { + l_angle = radians % (Math.PI * 2); + } + let l_sin = Math.sin(l_angle / 2); + let l_cos = Math.cos(l_angle / 2); + dest.x = d * x * l_sin; + dest.y = d * y * l_sin; + dest.z = d * z * l_sin; + dest.w = l_cos; + dest.normalize(); + return dest; + } +} +quat.identity = new quat().setIdentity(); +function clamp(x, a, b) { + if (x < a) { + return a; + } + else if (x > b) { + return b; + } + return x; +} diff --git a/src/framework/math/ray.d.ts b/src/framework/math/ray.d.ts new file mode 100644 index 0000000..41145c5 --- /dev/null +++ b/src/framework/math/ray.d.ts @@ -0,0 +1,8 @@ +import Box from "./box"; +import vec3 from "./vec3"; +export default class Ray { + origin: vec3; + direction: vec3; + constructor(origin: vec3, direction: vec3); + intersects(box: Box): boolean; +} diff --git a/src/framework/math/ray.js b/src/framework/math/ray.js new file mode 100644 index 0000000..3e9fee7 --- /dev/null +++ b/src/framework/math/ray.js @@ -0,0 +1,31 @@ +export default class Ray { + constructor(origin, direction) { + this.origin = origin; + this.direction = direction; + } + intersects(box) { + // ray.direction is unit direction vector of ray + const dirFracX = 1 / this.direction.x; + const dirFracY = 1 / this.direction.y; + const dirFracZ = 1 / this.direction.z; + // this.position is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner + const t1 = (box.position.x - this.origin.x) * dirFracX; + const t2 = (box.upperBound.x - this.origin.x) * dirFracX; + const t3 = (box.position.y - this.origin.y) * dirFracY; + const t4 = (box.upperBound.y - this.origin.y) * dirFracY; + const t5 = (box.position.z - this.origin.z) * dirFracZ; + const t6 = (box.upperBound.z - this.origin.z) * dirFracZ; + const tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6)); + const tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6)); + // if tmax < 0, ray is intersecting AABB, but whole AABB is behind us + if (tmax < 0) { + return false; + } + // if tmin > tmax, ray doesn't intersect AABB + if (tmin > tmax) { + return false; + } + // yay! We're about to run into a thing! + return true; + } +} diff --git a/src/framework/math/sphere.d.ts b/src/framework/math/sphere.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/math/sphere.js b/src/framework/math/sphere.js new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/math/tsm.d.ts b/src/framework/math/tsm.d.ts new file mode 100644 index 0000000..280aeee --- /dev/null +++ b/src/framework/math/tsm.d.ts @@ -0,0 +1,17 @@ +import mat2 from './mat2'; +import mat3 from './mat3'; +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import vec4 from './vec4'; +declare const _default: { + vec2: typeof vec2; + vec3: typeof vec3; + vec4: typeof vec4; + mat2: typeof mat2; + mat3: typeof mat3; + mat4: typeof mat4; + quat: typeof quat; +}; +export default _default; diff --git a/src/framework/math/tsm.js b/src/framework/math/tsm.js new file mode 100644 index 0000000..91cceb3 --- /dev/null +++ b/src/framework/math/tsm.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, 2018 Matthias Ferch + * + * Project homepage: https://github.com/matthiasferch/tsm + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ +import mat2 from './mat2'; +import mat3 from './mat3'; +import mat4 from './mat4'; +import quat from './quat'; +import vec2 from './vec2'; +import vec3 from './vec3'; +import vec4 from './vec4'; +export default { + vec2, + vec3, + vec4, + mat2, + mat3, + mat4, + quat +}; diff --git a/src/framework/math/vec2.d.ts b/src/framework/math/vec2.d.ts new file mode 100644 index 0000000..c7af680 --- /dev/null +++ b/src/framework/math/vec2.d.ts @@ -0,0 +1,40 @@ +import mat2 from './mat2'; +import mat3 from './mat3'; +import vec3 from './vec3'; +export default class vec2 { + get x(): number; + get y(): number; + get xy(): [number, number]; + set x(value: number); + set y(value: number); + set xy(values: [number, number]); + constructor(values?: [number, number]); + private values; + static readonly zero: vec2; + static readonly one: vec2; + at(index: number): number; + reset(): void; + copy(dest?: vec2): vec2; + negate(dest?: vec2): vec2; + equals(vector: vec2, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec2): vec2; + subtract(vector: vec2): vec2; + multiply(vector: vec2): vec2; + divide(vector: vec2): vec2; + scale(value: number, dest?: vec2): vec2; + normalize(dest?: vec2): vec2; + multiplyMat2(matrix: mat2, dest?: vec2): vec2; + multiplyMat3(matrix: mat3, dest?: vec2): vec2; + static cross(vector: vec2, vector2: vec2, dest?: vec3): vec3; + static dot(vector: vec2, vector2: vec2): number; + static distance(vector: vec2, vector2: vec2): number; + static squaredDistance(vector: vec2, vector2: vec2): number; + static direction(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static mix(vector: vec2, vector2: vec2, time: number, dest?: vec2): vec2; + static sum(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static difference(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static product(vector: vec2, vector2: vec2, dest?: vec2): vec2; + static quotient(vector: vec2, vector2: vec2, dest?: vec2): vec2; +} diff --git a/src/framework/math/vec2.js b/src/framework/math/vec2.js new file mode 100644 index 0000000..f319a69 --- /dev/null +++ b/src/framework/math/vec2.js @@ -0,0 +1,215 @@ +import vec3 from './vec3'; +import { epsilon } from './constants'; +export default class vec2 { + constructor(values) { + this.values = new Float32Array(2); + if (values !== undefined) { + this.xy = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + } + copy(dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = this.x; + dest.y = this.y; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + return x * x + y * y; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x = 0; + dest.y = 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + return dest; + } + multiplyMat2(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec2(this, dest); + } + multiplyMat3(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec2(this, dest); + } + static cross(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const x2 = vector2.x; + const y2 = vector2.y; + const z = x * y2 - y * x2; + dest.x = 0; + dest.y = 0; + dest.z = z; + return dest; + } + static dot(vector, vector2) { + return vector.x * vector2.x + vector.y * vector2.y; + } + static distance(vector, vector2) { + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + static squaredDistance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + return x * x + y * y; + } + static direction(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + const x = vector.x - vector2.x; + const y = vector.y - vector2.y; + let length = Math.sqrt(x * x + y * y); + if (length === 0) { + dest.x = 0; + dest.y = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + return dest; + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec2(); + } + const x = vector.x; + const y = vector.y; + const x2 = vector2.x; + const y2 = vector2.y; + dest.x = x + time * (x2 - x); + dest.y = y + time * (y2 - y); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec2(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + return dest; + } +} +vec2.zero = new vec2([0, 0]); +vec2.one = new vec2([1, 1]); diff --git a/src/framework/math/vec3.d.ts b/src/framework/math/vec3.d.ts new file mode 100644 index 0000000..21b94d9 --- /dev/null +++ b/src/framework/math/vec3.d.ts @@ -0,0 +1,48 @@ +import mat3 from "./mat3"; +import quat from "./quat"; +export default class vec3 { + get x(): number; + get y(): number; + get z(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + constructor(values?: [number, number, number]); + private values; + static readonly zero: vec3; + static readonly one: vec3; + static readonly up: vec3; + static readonly right: vec3; + static readonly forward: vec3; + at(index: number): number; + reset(): void; + copy(dest?: vec3): vec3; + negate(dest?: vec3): vec3; + equals(vector: vec3, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec3): vec3; + subtract(vector: vec3): vec3; + multiply(vector: vec3): vec3; + divide(vector: vec3): vec3; + scale(value: number, dest?: vec3): vec3; + normalize(dest?: vec3): vec3; + multiplyByMat3(matrix: mat3, dest?: vec3): vec3; + multiplyByQuat(quaternion: quat, dest?: vec3): vec3; + toQuat(dest?: quat): quat; + static cross(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static dot(vector: vec3, vector2: vec3): number; + static distance(vector: vec3, vector2: vec3): number; + static squaredDistance(vector: vec3, vector2: vec3): number; + static direction(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static mix(vector: vec3, vector2: vec3, time: number, dest?: vec3): vec3; + static sum(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static difference(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static product(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static quotient(vector: vec3, vector2: vec3, dest?: vec3): vec3; + static rotate(value: vec3, rotation: quat, dest?: vec3): vec3; +} diff --git a/src/framework/math/vec3.js b/src/framework/math/vec3.js new file mode 100644 index 0000000..1181586 --- /dev/null +++ b/src/framework/math/vec3.js @@ -0,0 +1,291 @@ +import quat from "./quat"; +import { epsilon } from "./constants"; +export default class vec3 { + constructor(values) { + this.values = new Float32Array(3); + if (values !== undefined) { + this.xyz = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + this.z = 0; + } + copy(dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + dest.z = -this.z; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + if (Math.abs(this.z - vector.z) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + const z = this.z; + return x * x + y * y + z * z; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + this.z /= vector.z; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + dest.z *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + dest.z *= length; + return dest; + } + multiplyByMat3(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec3(this, dest); + } + multiplyByQuat(quaternion, dest) { + if (!dest) { + dest = this; + } + return quaternion.multiplyVec3(this, dest); + } + toQuat(dest) { + if (!dest) { + dest = new quat(); + } + const c = new vec3(); + const s = new vec3(); + c.x = Math.cos(this.x * 0.5); + s.x = Math.sin(this.x * 0.5); + c.y = Math.cos(this.y * 0.5); + s.y = Math.sin(this.y * 0.5); + c.z = Math.cos(this.z * 0.5); + s.z = Math.sin(this.z * 0.5); + dest.x = s.x * c.y * c.z - c.x * s.y * s.z; + dest.y = c.x * s.y * c.z + s.x * c.y * s.z; + dest.z = c.x * c.y * s.z - s.x * s.y * c.z; + dest.w = c.x * c.y * c.z + s.x * s.y * s.z; + return dest; + } + static cross(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x; + const y = vector.y; + const z = vector.z; + const x2 = vector2.x; + const y2 = vector2.y; + const z2 = vector2.z; + dest.x = y * z2 - z * y2; + dest.y = z * x2 - x * z2; + dest.z = x * y2 - y * x2; + return dest; + } + static dot(vector, vector2) { + const x = vector.x; + const y = vector.y; + const z = vector.z; + const x2 = vector2.x; + const y2 = vector2.y; + const z2 = vector2.z; + return x * x2 + y * y2 + z * z2; + } + static distance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + const z = vector2.z - vector.z; + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + static squaredDistance(vector, vector2) { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + const z = vector2.z - vector.z; + return x * x + y * y + z * z; + } + static direction(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + const x = vector.x - vector2.x; + const y = vector.y - vector2.y; + const z = vector.z - vector2.z; + let length = Math.sqrt(x * x + y * y + z * z); + if (length === 0) { + dest.x = 0; + dest.y = 0; + dest.z = 0; + return dest; + } + length = 1 / length; + dest.x = x * length; + dest.y = y * length; + dest.z = z * length; + return dest; + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x + time * (vector2.x - vector.x); + dest.y = vector.y + time * (vector2.y - vector.y); + dest.z = vector.z + time * (vector2.z - vector.z); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + dest.z = vector.z + vector2.z; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + dest.z = vector.z - vector2.z; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + dest.z = vector.z * vector2.z; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec3(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + dest.z = vector.z / vector2.z; + return dest; + } + static rotate(value, rotation, dest) { + if (!dest) { + dest = new vec3(); + } + let x = 2 * (rotation.y * value.z - rotation.z * value.y); + let y = 2 * (rotation.z * value.x - rotation.x * value.z); + let z = 2 * (rotation.x * value.y - rotation.y * value.x); + dest.x = value.x + x * rotation.w + (rotation.y * z - rotation.z * y); + dest.y = value.y + y * rotation.w + (rotation.z * x - rotation.x * z); + dest.z = value.z + z * rotation.w + (rotation.x * y - rotation.y * x); + return dest; + } +} +vec3.zero = new vec3([0, 0, 0]); +vec3.one = new vec3([1, 1, 1]); +vec3.up = new vec3([0, 1, 0]); +vec3.right = new vec3([1, 0, 0]); +vec3.forward = new vec3([0, 0, 1]); diff --git a/src/framework/math/vec4.d.ts b/src/framework/math/vec4.d.ts new file mode 100644 index 0000000..42de7df --- /dev/null +++ b/src/framework/math/vec4.d.ts @@ -0,0 +1,54 @@ +import mat4 from './mat4'; +export default class vec4 { + get x(): number; + get y(): number; + get z(): number; + get w(): number; + get xy(): [number, number]; + get xyz(): [number, number, number]; + get xyzw(): [number, number, number, number]; + set x(value: number); + set y(value: number); + set z(value: number); + set w(value: number); + set xy(values: [number, number]); + set xyz(values: [number, number, number]); + set xyzw(values: [number, number, number, number]); + get r(): number; + get g(): number; + get b(): number; + get a(): number; + get rg(): [number, number]; + get rgb(): [number, number, number]; + get rgba(): [number, number, number, number]; + set r(value: number); + set g(value: number); + set b(value: number); + set a(value: number); + set rg(values: [number, number]); + set rgb(values: [number, number, number]); + set rgba(values: [number, number, number, number]); + constructor(values?: [number, number, number, number]); + private values; + static readonly zero: vec4; + static readonly one: vec4; + at(index: number): number; + reset(): void; + copy(dest?: vec4): vec4; + negate(dest?: vec4): vec4; + equals(vector: vec4, threshold?: number): boolean; + length(): number; + squaredLength(): number; + add(vector: vec4): vec4; + subtract(vector: vec4): vec4; + multiply(vector: vec4): vec4; + divide(vector: vec4): vec4; + scale(value: number, dest?: vec4): vec4; + normalize(dest?: vec4): vec4; + multiplyMat4(matrix: mat4, dest?: vec4): vec4; + static mix(vector: vec4, vector2: vec4, time: number, dest?: vec4): vec4; + static sum(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static difference(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static product(vector: vec4, vector2: vec4, dest?: vec4): vec4; + static quotient(vector: vec4, vector2: vec4, dest?: vec4): vec4; +} diff --git a/src/framework/math/vec4.js b/src/framework/math/vec4.js new file mode 100644 index 0000000..16723e7 --- /dev/null +++ b/src/framework/math/vec4.js @@ -0,0 +1,277 @@ +import { epsilon } from './constants'; +export default class vec4 { + constructor(values) { + this.values = new Float32Array(4); + if (values !== undefined) { + this.xyzw = values; + } + } + get x() { + return this.values[0]; + } + get y() { + return this.values[1]; + } + get z() { + return this.values[2]; + } + get w() { + return this.values[3]; + } + get xy() { + return [this.values[0], this.values[1]]; + } + get xyz() { + return [this.values[0], this.values[1], this.values[2]]; + } + get xyzw() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set x(value) { + this.values[0] = value; + } + set y(value) { + this.values[1] = value; + } + set z(value) { + this.values[2] = value; + } + set w(value) { + this.values[3] = value; + } + set xy(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set xyz(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set xyzw(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + get r() { + return this.values[0]; + } + get g() { + return this.values[1]; + } + get b() { + return this.values[2]; + } + get a() { + return this.values[3]; + } + get rg() { + return [this.values[0], this.values[1]]; + } + get rgb() { + return [this.values[0], this.values[1], this.values[2]]; + } + get rgba() { + return [this.values[0], this.values[1], this.values[2], this.values[3]]; + } + set r(value) { + this.values[0] = value; + } + set g(value) { + this.values[1] = value; + } + set b(value) { + this.values[2] = value; + } + set a(value) { + this.values[3] = value; + } + set rg(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + set rgb(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + } + set rgba(values) { + this.values[0] = values[0]; + this.values[1] = values[1]; + this.values[2] = values[2]; + this.values[3] = values[3]; + } + at(index) { + return this.values[index]; + } + reset() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + } + copy(dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = this.x; + dest.y = this.y; + dest.z = this.z; + dest.w = this.w; + return dest; + } + negate(dest) { + if (!dest) { + dest = this; + } + dest.x = -this.x; + dest.y = -this.y; + dest.z = -this.z; + dest.w = -this.w; + return dest; + } + equals(vector, threshold = epsilon) { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + if (Math.abs(this.z - vector.z) > threshold) { + return false; + } + if (Math.abs(this.w - vector.w) > threshold) { + return false; + } + return true; + } + length() { + return Math.sqrt(this.squaredLength()); + } + squaredLength() { + const x = this.x; + const y = this.y; + const z = this.z; + const w = this.w; + return x * x + y * y + z * z + w * w; + } + add(vector) { + this.x += vector.x; + this.y += vector.y; + this.z += vector.z; + this.w += vector.w; + return this; + } + subtract(vector) { + this.x -= vector.x; + this.y -= vector.y; + this.z -= vector.z; + this.w -= vector.w; + return this; + } + multiply(vector) { + this.x *= vector.x; + this.y *= vector.y; + this.z *= vector.z; + this.w *= vector.w; + return this; + } + divide(vector) { + this.x /= vector.x; + this.y /= vector.y; + this.z /= vector.z; + this.w /= vector.w; + return this; + } + scale(value, dest) { + if (!dest) { + dest = this; + } + dest.x *= value; + dest.y *= value; + dest.z *= value; + dest.w *= value; + return dest; + } + normalize(dest) { + if (!dest) { + dest = this; + } + let length = this.length(); + if (length === 1) { + return this; + } + if (length === 0) { + dest.x *= 0; + dest.y *= 0; + dest.z *= 0; + dest.w *= 0; + return dest; + } + length = 1.0 / length; + dest.x *= length; + dest.y *= length; + dest.z *= length; + dest.w *= length; + return dest; + } + multiplyMat4(matrix, dest) { + if (!dest) { + dest = this; + } + return matrix.multiplyVec4(this, dest); + } + static mix(vector, vector2, time, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x + time * (vector2.x - vector.x); + dest.y = vector.y + time * (vector2.y - vector.y); + dest.z = vector.z + time * (vector2.z - vector.z); + dest.w = vector.w + time * (vector2.w - vector.w); + return dest; + } + static sum(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + dest.z = vector.z + vector2.z; + dest.w = vector.w + vector2.w; + return dest; + } + static difference(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + dest.z = vector.z - vector2.z; + dest.w = vector.w - vector2.w; + return dest; + } + static product(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + dest.z = vector.z * vector2.z; + dest.w = vector.w * vector2.w; + return dest; + } + static quotient(vector, vector2, dest) { + if (!dest) { + dest = new vec4(); + } + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + dest.z = vector.z / vector2.z; + dest.w = vector.w / vector2.w; + return dest; + } +} +vec4.zero = new vec4([0, 0, 0, 1]); +vec4.one = new vec4([1, 1, 1, 1]); diff --git a/src/framework/physics/aabb.d.ts b/src/framework/physics/aabb.d.ts index 31fa46c..3cf295b 100644 --- a/src/framework/physics/aabb.d.ts +++ b/src/framework/physics/aabb.d.ts @@ -1,2 +1,2 @@ -import { PhysicsObject } from './object'; -export declare function AABB(obj1: PhysicsObject, obj2: PhysicsObject): boolean; +import Box from '../math/box'; +export declare function AABB(obj1: Box, obj2: Box): boolean; diff --git a/src/framework/physics/aabb.js b/src/framework/physics/aabb.js index d9c5ab0..7e1865b 100644 --- a/src/framework/physics/aabb.js +++ b/src/framework/physics/aabb.js @@ -1,17 +1,17 @@ -export function AABB(obj1, obj2) { - if (checkOverlap(obj1.position.x, obj1.dimensions.x, obj2.position.x, obj2.dimensions.x)) { - return true; - } - else if (checkOverlap(obj1.position.y, obj1.dimensions.y, obj2.position.y, obj2.dimensions.y)) { - return true; - } - else if (checkOverlap(obj1.position.z, obj1.dimensions.z, obj2.position.z, obj2.dimensions.z)) { - return true; - } - return false; -} -function checkOverlap(x, w, yx, yw) { - if (x > yx || x < yx + yw || x + w > x || x + w < yx + yw) { - return true; - } -} +export function AABB(obj1, obj2) { + if (checkOverlap(obj1.position.x, obj1.size.x, obj2.position.x, obj2.size.x)) { + return true; + } + else if (checkOverlap(obj1.position.y, obj1.size.y, obj2.position.y, obj2.size.y)) { + return true; + } + else if (checkOverlap(obj1.position.z, obj1.size.z, obj2.position.z, obj2.size.z)) { + return true; + } + return false; +} +function checkOverlap(x, w, yx, yw) { + if (x > yx || x < yx + yw || x + w > x || x + w < yx + yw) { + return true; + } +} diff --git a/src/framework/physics/broadphase.d.ts b/src/framework/physics/broadphase.d.ts new file mode 100644 index 0000000..dcdd2d8 --- /dev/null +++ b/src/framework/physics/broadphase.d.ts @@ -0,0 +1,7 @@ +import { PhysicsObject } from "./object"; +import { World } from "./world"; +export declare class Broadphase { + private world; + constructor(world: World); + execute(): Array>; +} diff --git a/src/framework/physics/broadphase.js b/src/framework/physics/broadphase.js new file mode 100644 index 0000000..5d3b9fb --- /dev/null +++ b/src/framework/physics/broadphase.js @@ -0,0 +1,25 @@ +export class Broadphase { + constructor(world) { + this.world = world; + } + execute() { + let pairs = []; + let objs = this.world.objects; + for (let i = 0; i < objs.length; i++) { + let candidates = this.world.octree.find(objs[i].boundingBox); + if (candidates.length === 0) + continue; + let o = []; + o.push(objs[i]); + for (let j = 0; j < candidates.length; j++) { + if (objs[i] === candidates[j]) + continue; + o.push(candidates[j]); + } + if (o.length > 1) { + pairs.push(o); + } + } + return pairs; + } +} diff --git a/src/framework/physics/collision/check.d.ts b/src/framework/physics/collision/check.d.ts new file mode 100644 index 0000000..a45bd5e --- /dev/null +++ b/src/framework/physics/collision/check.d.ts @@ -0,0 +1,2 @@ +import { PhysicsObject } from "../object"; +export declare function BoxBox(a: PhysicsObject, b: PhysicsObject): boolean; diff --git a/src/framework/physics/collision/check.js b/src/framework/physics/collision/check.js new file mode 100644 index 0000000..0108356 --- /dev/null +++ b/src/framework/physics/collision/check.js @@ -0,0 +1,6 @@ +export function BoxBox(a, b) { + return true; +} +function BoxTerrain(a, b) { + return true; +} diff --git a/src/framework/physics/collision/collision-event.d.ts b/src/framework/physics/collision/collision-event.d.ts new file mode 100644 index 0000000..f9a85a2 --- /dev/null +++ b/src/framework/physics/collision/collision-event.d.ts @@ -0,0 +1,7 @@ +import { PhysicsObject } from "../object"; +export declare class CollisionEvent { + bodyA: PhysicsObject; + bodyB: PhysicsObject; + constructor(a: PhysicsObject, b: PhysicsObject); + equals(ev: CollisionEvent): boolean; +} diff --git a/src/framework/physics/collision/collision-event.js b/src/framework/physics/collision/collision-event.js new file mode 100644 index 0000000..71823a7 --- /dev/null +++ b/src/framework/physics/collision/collision-event.js @@ -0,0 +1,9 @@ +export class CollisionEvent { + constructor(a, b) { + this.bodyA = a; + this.bodyB = b; + } + equals(ev) { + return (this.bodyA === ev.bodyA && this.bodyB === ev.bodyB); + } +} diff --git a/src/framework/physics/collision/diff.d.ts b/src/framework/physics/collision/diff.d.ts new file mode 100644 index 0000000..ec6b7da --- /dev/null +++ b/src/framework/physics/collision/diff.d.ts @@ -0,0 +1,9 @@ +import { CollisionMatrix } from "."; +import { World } from "../world"; +export declare class CollisionDiff { + private world; + prevMatrix: CollisionMatrix; + currMatrix: CollisionMatrix; + constructor(world: World); + perform(): void; +} diff --git a/src/framework/physics/collision/diff.js b/src/framework/physics/collision/diff.js new file mode 100644 index 0000000..3c8d722 --- /dev/null +++ b/src/framework/physics/collision/diff.js @@ -0,0 +1,41 @@ +import { CollisionMatrix } from "."; +export class CollisionDiff { + constructor(world) { + this.world = world; + this.prevMatrix = new CollisionMatrix(world); + this.currMatrix = new CollisionMatrix(world); + } + perform() { + let added = []; + let removed = []; + if (this.prevMatrix.length() === 0 && this.currMatrix.length() === 0) { + return; + } + if (this.prevMatrix.length() === 0) { + added.push([...this.currMatrix.collisions]); + } + else if (this.currMatrix.length() === 0) { + removed.push([...this.prevMatrix.collisions]); + } + else { + for (let i = 0; i < this.currMatrix.length(); i++) { + if (this.currMatrix.getIndex(i).equals(this.prevMatrix.getIndex(i))) { + continue; + } + if (!this.currMatrix.contains(this.prevMatrix.getIndex(i))) { + removed.push(this.prevMatrix.getIndex(i)); + } + if (!this.prevMatrix.contains(this.currMatrix.getIndex(i))) { + added.push(this.currMatrix.getIndex(i)); + } + } + } + for (let i = 0; i < added.length; i++) { + this.world.emit("collision.enter", added[i]); + } + for (let i = 0; i < removed.length; i++) { + this.world.emit("collision.exit", removed[i]); + } + this.prevMatrix = this.currMatrix; + } +} diff --git a/src/framework/physics/collision/index.d.ts b/src/framework/physics/collision/index.d.ts new file mode 100644 index 0000000..693469e --- /dev/null +++ b/src/framework/physics/collision/index.d.ts @@ -0,0 +1,14 @@ +import { PhysicsObject } from "../object"; +import { World } from "../world"; +import { CollisionEvent } from "./collision-event"; +export declare class CollisionMatrix { + private world; + collisions: Array; + constructor(world: World); + add(a: PhysicsObject, b: PhysicsObject): void; + remove(a: PhysicsObject, b: PhysicsObject): void; + contains(ev: CollisionEvent): boolean; + length(): number; + getIndex(i: number): CollisionEvent; + clear(): void; +} diff --git a/src/framework/physics/collision/index.js b/src/framework/physics/collision/index.js new file mode 100644 index 0000000..34b2167 --- /dev/null +++ b/src/framework/physics/collision/index.js @@ -0,0 +1,36 @@ +import { CollisionEvent } from "./collision-event"; +export class CollisionMatrix { + constructor(world) { + this.world = world; + this.collisions = []; + } + add(a, b) { + this.collisions.push(new CollisionEvent(a, b)); + } + remove(a, b) { + for (let i = 0; i < this.collisions.length; i++) { + if (this.collisions[i].bodyA == a && this.collisions[i].bodyB == b) { + this.collisions.slice(i, 1); + return; + } + } + } + contains(ev) { + for (let i = 0; i < this.collisions.length; i++) { + if (this.collisions[i].equals(ev)) + return true; + } + return false; + } + length() { + return this.collisions.length; + } + getIndex(i) { + if (i >= this.collisions.length) + return null; + return this.collisions[i]; + } + clear() { + this.collisions = []; + } +} diff --git a/src/framework/physics/collision/solver.d.ts b/src/framework/physics/collision/solver.d.ts new file mode 100644 index 0000000..f9d735d --- /dev/null +++ b/src/framework/physics/collision/solver.d.ts @@ -0,0 +1,5 @@ +import Box from "../../math/box"; +import { PhysicsObject } from "../object"; +import { Terrain } from "../terrain"; +export declare function BoxBoxSolver(a: Box, b: Box): void; +export declare function BoxTerrainSolver(a: PhysicsObject, b: Terrain): void; diff --git a/src/framework/physics/collision/solver.js b/src/framework/physics/collision/solver.js new file mode 100644 index 0000000..b647fe5 --- /dev/null +++ b/src/framework/physics/collision/solver.js @@ -0,0 +1,15 @@ +export function BoxBoxSolver(a, b) { + if (a.position.x >= b.position.x || a.position.x <= b.position.x + b.size.x) { + a.position.x -= (a.position.x - b.position.x); + } + if (a.position.y >= b.position.y || a.position.y <= b.position.y + b.size.y) { + a.position.y -= (a.position.y - b.position.y); + } + if (a.position.z >= b.position.z || a.position.z <= b.position.z + b.size.z) { + a.position.z -= (a.position.z - b.position.z); + } +} +export function BoxTerrainSolver(a, b) { + const terrainBounds = b.getBoundingBox(a.boundingBox); + BoxBoxSolver(a.boundingBox, terrainBounds); +} diff --git a/src/framework/physics/narrowphase.d.ts b/src/framework/physics/narrowphase.d.ts new file mode 100644 index 0000000..bdd20c0 --- /dev/null +++ b/src/framework/physics/narrowphase.d.ts @@ -0,0 +1,7 @@ +import { PhysicsObject } from "./object"; +import { World } from "./world"; +export declare class Narrowphase { + private world; + constructor(world: World); + perform(objs: Array>): void; +} diff --git a/src/framework/physics/narrowphase.js b/src/framework/physics/narrowphase.js new file mode 100644 index 0000000..e39e0cd --- /dev/null +++ b/src/framework/physics/narrowphase.js @@ -0,0 +1,28 @@ +import { BoxBoxSolver, BoxTerrainSolver } from "./collision/solver"; +import { ObjectType } from "./object-type"; +export class Narrowphase { + constructor(world) { + this.world = world; + } + perform(objs) { + for (let x = 0; x < objs.length; x++) { + for (let i = 0; i < objs[x].length; i++) { + for (let j = 0; j < objs[x].length; j++) { + if (objs[x][i] === objs[x][j]) + continue; + if (objs[x][i].collidesWith(objs[x][j])) { + this.world.collisionMatrix.add(objs[x][i], objs[x][j]); + if (objs[x][i].type === ObjectType.object) { + if (objs[x][j].type == ObjectType.object) { + BoxBoxSolver(objs[x][i].boundingBox, objs[x][j].boundingBox); + } + else { + BoxTerrainSolver(objs[x][i], objs[x][j]); + } + } + } + } + } + } + } +} diff --git a/src/framework/physics/object-type.d.ts b/src/framework/physics/object-type.d.ts new file mode 100644 index 0000000..a78f560 --- /dev/null +++ b/src/framework/physics/object-type.d.ts @@ -0,0 +1,4 @@ +export declare enum ObjectType { + object = 0, + terrain = 1 +} diff --git a/src/framework/physics/object-type.js b/src/framework/physics/object-type.js new file mode 100644 index 0000000..87396cc --- /dev/null +++ b/src/framework/physics/object-type.js @@ -0,0 +1,5 @@ +export var ObjectType; +(function (ObjectType) { + ObjectType[ObjectType["object"] = 0] = "object"; + ObjectType[ObjectType["terrain"] = 1] = "terrain"; +})(ObjectType || (ObjectType = {})); diff --git a/src/framework/physics/object.d.ts b/src/framework/physics/object.d.ts index 564fa43..4868975 100644 --- a/src/framework/physics/object.d.ts +++ b/src/framework/physics/object.d.ts @@ -1,7 +1,22 @@ -import { Vec3 } from './vec3'; -export declare class PhysicsObject { - position: Vec3; - dimensions: Vec3; - velocity: Vec3; - affectedByGravity: boolean; -} +import Box from "../math/box"; +import vec3 from "../math/vec3"; +import quat from "../math/quat"; +import { ObjectType } from "./object-type"; +import { World } from "./world"; +export declare class PhysicsObject { + type: ObjectType; + boundingBox: Box; + rotation: quat; + velocity: vec3; + affectedByGravity: boolean; + collides: boolean; + isStatic: boolean; + isDirty: boolean; + collisionContacts: Set; + constructor(); + move(position: vec3): void; + lookAt(position: vec3): void; + collidesWith(obj: PhysicsObject): boolean; + onCollision(obj: PhysicsObject, world: World): boolean; + private checkCollisionContacts; +} diff --git a/src/framework/physics/object.js b/src/framework/physics/object.js index 01da65f..f784eec 100644 --- a/src/framework/physics/object.js +++ b/src/framework/physics/object.js @@ -1,2 +1,55 @@ -export class PhysicsObject { -} +import Box from "../math/box"; +import vec3 from "../math/vec3"; +import quat from "../math/quat"; +import { ObjectType } from "./object-type"; +export class PhysicsObject { + constructor() { + this.type = ObjectType.object; + this.boundingBox = new Box(new vec3([0, 0, 0]), new vec3([1, 1, 1])); + this.rotation = new quat(); + this.velocity = new vec3([0, 0, 0]); + this.affectedByGravity = true; + this.collides = true; + this.isStatic = false; + this.isDirty = true; + this.collisionContacts = new Set(); + } + move(position) { + if (this.isStatic) + return; + this.boundingBox.position = position; + this.isDirty = true; + } + lookAt(position) { + this.rotation = quat.fromVectors(this.boundingBox.position.copy(), position.copy()); + } + collidesWith(obj) { + if (obj.type !== ObjectType.terrain) { + return this.boundingBox.overlaps(obj.boundingBox); + } + else { + return obj.collidesWith(this); + } + return false; + } + onCollision(obj, world) { + if (!this.collisionContacts.has(obj)) { + this.collisionContacts.add(obj); + world.emit('collision.enter', [this, obj]); + } + if (this.isStatic) + return; + this.velocity.negate(); + this.boundingBox.position.add(this.velocity.multiply(new vec3([world.deltaTime, world.deltaTime, world.deltaTime]))); + this.velocity = new vec3([0, 0, 0]); + this.checkCollisionContacts(); + return true; + } + checkCollisionContacts() { + this.collisionContacts.forEach((contact) => { + if (!contact.collidesWith(this)) { + this.collisionContacts.delete(contact); + } + }); + } +} diff --git a/src/framework/physics/octree.d.ts b/src/framework/physics/octree.d.ts index 7da8ee5..65ac8f0 100644 --- a/src/framework/physics/octree.d.ts +++ b/src/framework/physics/octree.d.ts @@ -1,39 +1,27 @@ -import { PhysicsObject } from './object'; -import { Vec3 } from './vec3'; -export declare class Octree { - private dimensions; - private maxObjects; - private maxLevels; - root: OcTreeNode; - constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number); - insert(obj: PhysicsObject): void; - find(position: Vec3, dimensions: Vec3): PhysicsObject[]; -} -export declare class OcTreeNode { - private position; - private dimensions; - private maxLevels; - private maxObjects; - private currentLevel; - objects: PhysicsObject[]; - nodes: OcTreeNode[]; - constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number, currentLevel?: number); - insert(obj: PhysicsObject): any; - find(x: number, y: number, z: number, xw: number, yh: number, zd: number): PhysicsObject[]; - split(): void; - private distributeObjectsToNodes; - getIndex(x: number, y: number, z: number): Direction; - getIndeciesForRect(x: number, y: number, z: number, xw: number, yh: number, zd: number): Direction[]; -} -declare enum Direction { - AboveUpperLeft = 0, - AboveUpperRight = 1, - AboveLowerRight = 2, - AboveLowerLeft = 3, - BelowUpperLeft = 4, - BelowUpperRight = 5, - BelowLowerRight = 6, - BelowLowerLeft = 7, - Here = 8 -} -export {}; +import { PhysicsObject } from './object'; +import Vec3 from '../math/vec3'; +import Box from "../math/box"; +export declare class Octree { + private dimensions; + private maxObjects; + private maxLevels; + root: OcTreeNode; + constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number); + insert(obj: PhysicsObject): void; + remove(obj: PhysicsObject): void; + find(area: Box): PhysicsObject[]; +} +export declare class OcTreeNode { + private boundingBox; + private maxLevels; + private maxObjects; + private currentLevel; + objects: PhysicsObject[]; + nodes: OcTreeNode[]; + constructor(boundingBox: Box, maxLevels: number, maxObjects: number, currentLevel?: number); + insert(obj: PhysicsObject): void; + remove(obj: PhysicsObject): void; + find(area: Box): PhysicsObject[]; + split(): void; + private distributeObjectsToNodes; +} diff --git a/src/framework/physics/octree.js b/src/framework/physics/octree.js index 8e1c511..3159c1d 100644 --- a/src/framework/physics/octree.js +++ b/src/framework/physics/octree.js @@ -1,206 +1,179 @@ -import { Vec3 } from './vec3'; -export class Octree { - constructor(dimensions, maxObjects = 10, maxLevels = 10) { - this.dimensions = dimensions; - this.maxObjects = maxObjects; - this.maxLevels = maxLevels; - this.root = new OcTreeNode(new Vec3({ - x: 0, - y: 0, - z: 0 - }), this.dimensions, maxLevels, maxObjects, 0); - } - insert(obj) { - this.root.insert(obj); - } - find(position, dimensions) { - return this.root.find(position.x, position.y, position.z, dimensions.x, dimensions.y, dimensions.z); - } -} -export class OcTreeNode { - constructor(position, dimensions, maxLevels, maxObjects, currentLevel = 0) { - this.position = position; - this.dimensions = dimensions; - this.maxLevels = maxLevels; - this.maxObjects = maxObjects; - this.currentLevel = currentLevel; - this.objects = []; - this.nodes = []; - } - insert(obj) { - const index = this.getIndex(obj.position.x, obj.position.y, obj.position.z); - if (index === Direction.Here) { - this.objects.push(obj); - } - else { - return this.nodes[index].insert(obj); - } - if (this.objects.length > this.maxObjects && - this.currentLevel < this.maxLevels) { - this.split(); - } - } - find(x, y, z, xw, yh, zd) { - if (this.nodes.length < 1) { - return this.objects; - } - const indecies = this.getIndeciesForRect(x, y, z, xw, yh, zd); - let results = []; - for (let i = 0; i < indecies.length - 1; i++) { - let res = this.nodes[indecies[i]].find(x, y, z, xw, yh, zd); - results.push([...res]); - } - return results; - } - split() { - const halfWidth = this.dimensions.x / 2; - const halfHeight = this.dimensions.y / 2; - const halfDepth = this.dimensions.z / 2; - this.nodes[Direction.AboveUpperLeft] = new OcTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.AboveUpperRight] = new OcTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.AboveLowerRight] = new OcTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y + halfHeight, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.AboveLowerLeft] = new OcTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y + halfHeight, - z: this.position.z + halfDepth - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.BelowUpperLeft] = new OcTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.BelowUpperRight] = new OcTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.BelowLowerRight] = new OcTreeNode(new Vec3({ - x: this.position.x + halfWidth, - y: this.position.y + halfHeight, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.nodes[Direction.BelowLowerLeft] = new OcTreeNode(new Vec3({ - x: this.position.x, - y: this.position.y + halfHeight, - z: this.position.z - }), new Vec3({ - x: halfWidth, - y: halfHeight, - z: halfDepth - }), this.maxLevels, this.maxObjects, this.currentLevel++); - this.distributeObjectsToNodes(); - } - distributeObjectsToNodes() { - if (this.nodes.length < 8) { - this.split(); - return; - } - this.objects.forEach((obj) => { - const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z); - this.nodes[direction].insert(obj); - }); - this.objects = []; - } - getIndex(x, y, z) { - if (this.nodes.length === 0) { - return Direction.Here; - } - const halfWidth = this.dimensions.x / 2; - const halfHeight = this.dimensions.y / 2; - const halfDepth = this.dimensions.z / 2; - const isBelow = z < this.position.z + halfDepth; - const isLeft = x < this.position.x + halfWidth; - const isUpper = y > this.position.y + halfHeight; - if (isBelow) { - if (isLeft) { - if (isUpper) - return Direction.AboveUpperLeft; - else - return Direction.AboveLowerLeft; - } - else { - if (isUpper) - return Direction.AboveUpperRight; - else - return Direction.AboveLowerRight; - } - } - else { - if (isLeft) { - if (isUpper) - return Direction.BelowUpperLeft; - else - return Direction.BelowLowerLeft; - } - else { - if (isUpper) - return Direction.BelowUpperRight; - else - return Direction.BelowLowerRight; - } - } - } - getIndeciesForRect(x, y, z, xw, yh, zd) { - if (!(x > this.position.x && x < this.position.x + this.dimensions.x) || - !(y > this.position.y && y < this.position.y + this.dimensions.y) || - !(z > this.position.z && z < this.position.z + this.dimensions.z)) { - return []; - } - let indecies = []; - indecies.push(this.getIndex(x, y, z)); - indecies.push(this.getIndex(x + xw, y + yh, z + zd)); - return indecies; - } -} -var Direction; -(function (Direction) { - Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft"; - Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight"; - Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight"; - Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft"; - Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft"; - Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight"; - Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight"; - Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft"; - Direction[Direction["Here"] = 8] = "Here"; -})(Direction || (Direction = {})); +import Vec3 from '../math/vec3'; +import Box from "../math/box"; +export class Octree { + constructor(dimensions, maxObjects = 10, maxLevels = 10) { + this.dimensions = dimensions; + this.maxObjects = maxObjects; + this.maxLevels = maxLevels; + this.root = new OcTreeNode(new Box(new Vec3([ + 0, + 0, + 0 + ]), this.dimensions), maxLevels, maxObjects, 0); + } + insert(obj) { + this.root.insert(obj); + } + remove(obj) { + this.root.remove(obj); + } + find(area) { + return this.root.find(area); + } +} +export class OcTreeNode { + constructor(boundingBox, maxLevels, maxObjects, currentLevel = 0) { + this.boundingBox = boundingBox; + this.maxLevels = maxLevels; + this.maxObjects = maxObjects; + this.currentLevel = currentLevel; + this.objects = []; + this.nodes = []; + } + insert(obj) { + if (!obj.boundingBox.overlaps(this.boundingBox)) + return; + if (this.nodes.length > 1) { + for (let i = 0; i < this.nodes.length - 1; i++) { + this.nodes[i].insert(obj); + } + } + else { + this.objects.push(obj); + if (this.objects.length > this.maxObjects) { + this.split(); + } + } + } + remove(obj) { + if (obj.boundingBox.overlaps(this.boundingBox)) { + if (this.nodes.length > 1) { + for (let i = 0; i < this.nodes.length - 1; i++) { + this.nodes[i].remove(obj); + } + } + } + if (this.objects.includes(obj)) { + this.objects = this.objects.filter((item) => item !== obj); + } + } + find(area) { + let result = []; + if (area.overlaps(this.boundingBox)) { + if (this.nodes.length > 1) { + for (let i = 0; i < this.nodes.length; i++) { + let res = this.nodes[i].find(area); + if (res.length > 0) + res.forEach((item) => result.push(item)); + } + } + if (this.objects.length > 0) + this.objects.forEach((item) => result.push(item)); + } + return result; + } + split() { + if (this.currentLevel == this.maxLevels) + return; + const halfWidth = this.boundingBox.size.x / 2; + const halfHeight = this.boundingBox.size.y / 2; + const halfDepth = this.boundingBox.size.z / 2; + this.nodes[Direction.AboveUpperLeft] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x, + this.boundingBox.position.y, + this.boundingBox.position.z + halfDepth + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.AboveUpperRight] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x + halfWidth, + this.boundingBox.position.y, + this.boundingBox.position.z + halfDepth + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.AboveLowerRight] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x + halfWidth, + this.boundingBox.position.y + halfHeight, + this.boundingBox.position.z + halfDepth + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.AboveLowerLeft] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x, + this.boundingBox.position.y + halfHeight, + this.boundingBox.position.z + halfDepth + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.BelowUpperLeft] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x, + this.boundingBox.position.y, + this.boundingBox.position.z + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.BelowUpperRight] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x + halfWidth, + this.boundingBox.position.y, + this.boundingBox.position.z + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.BelowLowerRight] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x + halfWidth, + this.boundingBox.position.y + halfHeight, + this.boundingBox.position.z + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.nodes[Direction.BelowLowerLeft] = new OcTreeNode(new Box(new Vec3([ + this.boundingBox.position.x, + this.boundingBox.position.y + halfHeight, + this.boundingBox.position.z + ]), new Vec3([ + halfWidth, + halfHeight, + halfDepth + ])), this.maxLevels, this.maxObjects, this.currentLevel + 1); + this.distributeObjectsToNodes(); + } + distributeObjectsToNodes() { + if (this.nodes.length < 8) { + this.split(); + return; + } + for (let i = 0; i < this.objects.length; i++) { + for (let j = 0; j < this.nodes.length - 1; j++) { + this.nodes[j].insert(this.objects[i]); + } + } + this.objects = []; + } +} +var Direction; +(function (Direction) { + Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft"; + Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight"; + Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight"; + Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft"; + Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft"; + Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight"; + Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight"; + Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft"; + Direction[Direction["Here"] = 8] = "Here"; +})(Direction || (Direction = {})); diff --git a/src/framework/physics/processor.d.ts b/src/framework/physics/processor.d.ts new file mode 100644 index 0000000..8ba0141 --- /dev/null +++ b/src/framework/physics/processor.d.ts @@ -0,0 +1,4 @@ +import { World } from "./world"; +export interface Processor { + execute(world: World): any; +} diff --git a/src/framework/physics/processor.js b/src/framework/physics/processor.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/src/framework/physics/processor.js @@ -0,0 +1 @@ +export {}; diff --git a/src/framework/physics/processors/gravity.d.ts b/src/framework/physics/processors/gravity.d.ts new file mode 100644 index 0000000..e0f07ef --- /dev/null +++ b/src/framework/physics/processors/gravity.d.ts @@ -0,0 +1,7 @@ +import { World } from "../world"; +export declare class GravityProcessor { + private dt; + private grav; + constructor(); + execute(world: World): void; +} diff --git a/src/framework/physics/processors/gravity.js b/src/framework/physics/processors/gravity.js new file mode 100644 index 0000000..74e31ab --- /dev/null +++ b/src/framework/physics/processors/gravity.js @@ -0,0 +1,19 @@ +import vec3 from "../../math/vec3"; +export class GravityProcessor { + constructor() { + this.dt = 0; + this.grav = new vec3([0, 0, 0]); + } + execute(world) { + this.dt = this.dt; + this.grav.x = world.gravity.x * this.dt; + this.grav.y = world.gravity.y * this.dt; + this.grav.z = world.gravity.z * this.dt; + let objects = world.objects; + for (let i = 0; i < objects.length; i++) { + if (objects[i].affectedByGravity) { + objects[i].velocity.add(this.grav); + } + } + } +} diff --git a/src/framework/physics/terrain/index.d.ts b/src/framework/physics/terrain/index.d.ts new file mode 100644 index 0000000..0aa5cee --- /dev/null +++ b/src/framework/physics/terrain/index.d.ts @@ -0,0 +1,14 @@ +import Box from "../../math/box"; +import { PhysicsObject } from "../object"; +export declare class Terrain extends PhysicsObject { + heightmap: Uint8Array; + texturemap: Uint8Array; + constructor(); + setTextureMap(tmap: Uint8Array): void; + setHeightMap(hmap: Uint8Array): void; + getHeightAt(x: number, z: number): number; + getTextureAt(x: number, z: number): number; + getBoundingBox(bounds: Box): Box; + collidesWith(obj: PhysicsObject): boolean; + onCollision(obj: PhysicsObject): boolean; +} diff --git a/src/framework/physics/terrain/index.js b/src/framework/physics/terrain/index.js new file mode 100644 index 0000000..e13f7b9 --- /dev/null +++ b/src/framework/physics/terrain/index.js @@ -0,0 +1,99 @@ +import Box from "../../math/box"; +import vec3 from "../../math/vec3"; +import { PhysicsObject } from "../object"; +import { ObjectType } from "../object-type"; +export class Terrain extends PhysicsObject { + constructor() { + super(); + this.type = ObjectType.terrain; + this.heightmap = new Uint8Array(); + this.texturemap = new Uint8Array(); + } + setTextureMap(tmap) { + this.texturemap = tmap; + } + setHeightMap(hmap) { + this.heightmap = hmap; + } + getHeightAt(x, z) { + const localX = Math.floor(x - this.boundingBox.position.x); + const localZ = Math.floor(z - this.boundingBox.position.z); + const width = Math.floor(this.boundingBox.size.x); + return this.heightmap[localX * width + localZ]; + } + getTextureAt(x, z) { + const localX = Math.floor(x - this.boundingBox.position.x); + const localZ = Math.floor(z - this.boundingBox.position.z); + const width = Math.floor(this.boundingBox.size.x); + return this.heightmap[localX * width + localZ]; + } + getBoundingBox(bounds) { + const halfWidth = bounds.size.x / 2; + const halfDepth = bounds.size.z / 2; + const ax = bounds.position.x + halfWidth; + const az = bounds.position.z; + const bx = bounds.position.x; + const bz = bounds.position.z + halfDepth; + const cx = ax; + const cz = bounds.position.z + bounds.size.z; + const dx = bounds.position.x + bounds.size.x; + const dz = bounds.position.z + halfDepth; + const heights = [ + this.getHeightAt(ax, az), + this.getHeightAt(bx, bz), + this.getHeightAt(cx, cz), + this.getHeightAt(dx, dz), + ]; + const boxSize = new vec3([ + bounds.size.x, + Math.max(...heights), + bounds.size.z, + ]); + const boxPos = new vec3([ + bounds.position.x, + this.boundingBox.position.y + Math.min(...heights), + bounds.position.z, + ]); + const box = new Box(boxPos, boxSize); + return box; + } + collidesWith(obj) { + if (!this.boundingBox.overlaps(obj.boundingBox)) { + return false; + } + const halfWidth = obj.boundingBox.size.x / 2; + const halfDepth = obj.boundingBox.size.z / 2; + const ax = obj.boundingBox.position.x + halfWidth; + const az = obj.boundingBox.position.z; + const bx = obj.boundingBox.position.x; + const bz = obj.boundingBox.position.z + halfDepth; + const cx = ax; + const cz = obj.boundingBox.position.z + obj.boundingBox.size.z; + const dx = obj.boundingBox.position.x + obj.boundingBox.size.x; + const dz = obj.boundingBox.position.z + halfDepth; + const heights = [ + this.getHeightAt(ax, az), + this.getHeightAt(bx, bz), + this.getHeightAt(cx, cz), + this.getHeightAt(dx, dz), + ]; + const boxSize = new vec3([ + obj.boundingBox.size.x, + Math.max(...heights), + obj.boundingBox.size.z, + ]); + const boxPos = new vec3([ + obj.boundingBox.position.x, + this.boundingBox.position.y + Math.min(...heights), + obj.boundingBox.position.z, + ]); + const box = new Box(boxPos, boxSize); + return box.overlaps(obj.boundingBox); + } + onCollision(obj) { + if (obj.type === ObjectType.terrain) + return; + // obj.boundingBox.position.y = this.boundingBox.position.y + this.getHeightAt(obj.boundingBox.position.x, obj.boundingBox.position.z); + return true; + } +} diff --git a/src/framework/physics/world.d.ts b/src/framework/physics/world.d.ts index 4366f98..866a504 100644 --- a/src/framework/physics/world.d.ts +++ b/src/framework/physics/world.d.ts @@ -1,23 +1,38 @@ -import { Octree } from './octree'; -import { EventBus } from '../event-bus'; -import { PhysicsObject } from './object'; -import { Vec3 } from './vec3'; -export declare class World extends EventBus { - objects: PhysicsObject[]; - gravity: Vec3; - dimensions: Vec3; - octreeOptions: OctreeOptions; - constructor(dimensions: Vec3, octreeOptions: OctreeOptions); - setGravity(grav: Vec3): void; - addObject(obj: PhysicsObject): void; - removeObject(obj: PhysicsObject): void; - step(dt: number): void; - checkCollisions(obj: PhysicsObject, octree: Octree): void; -} -interface OctreeOptions { - position: Vec3; - dimensions: Vec3; - maxObjects: number; - maxLevels: number; -} -export {}; +import { EventBus } from '../event-bus'; +import Vec3 from '../math/vec3'; +import { Broadphase } from './broadphase'; +import { CollisionMatrix } from './collision'; +import { CollisionDiff } from './collision/diff'; +import { Narrowphase } from './narrowphase'; +import { PhysicsObject } from './object'; +import { Octree } from './octree'; +import { Processor } from './processor'; +import { Terrain } from './terrain'; +export declare class World extends EventBus { + objects: PhysicsObject[]; + terrain: Terrain[]; + gravity: Vec3; + dimensions: Vec3; + octreeOptions: OctreeOptions; + octree: Octree; + deltaTime: number; + narrowphase: Narrowphase; + broadphase: Broadphase; + collisionMatrix: CollisionMatrix; + collisionDiff: CollisionDiff; + processors: Processor[]; + constructor(dimensions: Vec3, octreeOptions?: OctreeOptions); + addProcessor(processor: Processor): void; + setGravity(grav: Vec3): void; + addObject(obj: PhysicsObject): void; + removeObject(obj: PhysicsObject): void; + step(dt: number): void; + checkCollisions(obj: PhysicsObject, dt: number): void; +} +interface OctreeOptions { + position: Vec3; + dimensions: Vec3; + maxObjects: number; + maxLevels: number; +} +export {}; diff --git a/src/framework/physics/world.js b/src/framework/physics/world.js index 445a17c..8839706 100644 --- a/src/framework/physics/world.js +++ b/src/framework/physics/world.js @@ -1,54 +1,76 @@ -import { Octree } from './octree'; -import { EventBus } from '../event-bus'; -import { Vec3 } from './vec3'; -import { AABB } from './aabb'; -export class World extends EventBus { - constructor(dimensions, octreeOptions) { - super(); - if (!octreeOptions) { - this.octreeOptions = { - position: new Vec3({ x: 0, y: 0, z: 0 }), - dimensions: new Vec3(this.dimensions), - maxLevels: 50, - maxObjects: 50 - }; - } - else { - this.octreeOptions = octreeOptions; - } - this.dimensions = dimensions; - this.objects = []; - } - setGravity(grav) { - this.gravity = grav; - } - addObject(obj) { - this.objects.push(obj); - } - removeObject(obj) { - this.objects = this.objects.filter((val) => val !== obj); - } - step(dt) { - const octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels); - this.objects.forEach((obj) => octree.insert(obj)); - this.objects.forEach((obj) => { - let velocity = obj.velocity.clone(); - velocity.multiply(new Vec3({ x: dt, y: dt, z: dt })); - let gravity = this.gravity.clone(); - gravity.multiply(new Vec3({ x: dt, y: dt, z: dt })); - obj.position.add(velocity); - if (obj.affectedByGravity) { - obj.velocity.add(gravity); - } - this.checkCollisions(obj, octree); - }); - } - checkCollisions(obj, octree) { - const potentialCandidates = octree.find(obj.position, obj.dimensions); - potentialCandidates.forEach((candidate) => { - if (AABB(obj, candidate)) { - this.emit('collision', [obj, candidate]); - } - }); - } -} +import { EventBus } from '../event-bus'; +import Vec3 from '../math/vec3'; +import { Broadphase } from './broadphase'; +import { CollisionMatrix } from './collision'; +import { CollisionDiff } from './collision/diff'; +import { Narrowphase } from './narrowphase'; +import { Octree } from './octree'; +export class World extends EventBus { + constructor(dimensions, octreeOptions) { + super(); + if (!octreeOptions) { + this.octreeOptions = { + position: new Vec3([0, 0, 0]), + dimensions: this.dimensions, + maxLevels: 50, + maxObjects: 50 + }; + } + else { + this.octreeOptions = octreeOptions; + } + this.dimensions = dimensions; + this.objects = []; + this.octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels); + this.narrowphase = new Narrowphase(this); + this.broadphase = new Broadphase(this); + this.collisionMatrix = new CollisionMatrix(this); + this.collisionDiff = new CollisionDiff(this); + this.processors = []; + } + addProcessor(processor) { + this.processors.push(processor); + } + setGravity(grav) { + this.gravity = grav; + } + addObject(obj) { + this.objects.push(obj); + this.octree.insert(obj); + } + removeObject(obj) { + this.objects = this.objects.filter((val) => val !== obj); + this.octree.remove(obj); + } + step(dt) { + const objects = this.objects; + this.deltaTime = dt; + for (let i = 0; i < objects.length; i++) { + const obj = objects[i]; + if (obj.isDirty) { + this.octree.remove(obj); + this.octree.insert(obj); + obj.isDirty = false; + } + const velocity = obj.velocity.copy(); + velocity.multiply(new Vec3([dt, dt, dt])); + const gravity = this.gravity.copy(); + gravity.multiply(new Vec3([dt, dt, dt])); + if (obj.affectedByGravity) { + obj.velocity.add(gravity); + } + obj.boundingBox.position.add(velocity); + if (obj.velocity.length() != 0) { + obj.isDirty = true; + } + this.checkCollisions(obj, dt); + } + } + checkCollisions(obj, dt) { + this.collisionMatrix = new CollisionMatrix(this); + const candidates = this.broadphase.execute(); + this.narrowphase.perform(candidates); + this.collisionDiff.currMatrix = this.collisionMatrix; + this.collisionDiff.perform(); + } +} diff --git a/src/framework/resonator/audio-context.d.ts b/src/framework/resonator/audio-context.d.ts index b88251b..e9db8e2 100644 --- a/src/framework/resonator/audio-context.d.ts +++ b/src/framework/resonator/audio-context.d.ts @@ -1,11 +1,11 @@ -export default class ResonatorAudioContext { - private context; - constructor(); - getContext(): AudioContext; - createGain(): any; - getOutputDestination(): AudioNode; - createBufferSource(): AudioBufferSourceNode; - decodeAudioData(data: ArrayBuffer): Promise; - createPanner(): any; - createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode; -} +export default class ResonatorAudioContext { + private context; + constructor(); + getContext(): AudioContext; + createGain(): any; + getOutputDestination(): AudioNode; + createBufferSource(): AudioBufferSourceNode; + decodeAudioData(data: ArrayBuffer): Promise; + createPanner(): any; + createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode; +} diff --git a/src/framework/resonator/audio-context.js b/src/framework/resonator/audio-context.js index fbe0d3b..04d65e5 100644 --- a/src/framework/resonator/audio-context.js +++ b/src/framework/resonator/audio-context.js @@ -1,39 +1,39 @@ -// simple wrapper around the AudioContext -// eventually will be used to deal with cross browser issues -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -export default class ResonatorAudioContext { - constructor() { - this.context = new AudioContext(); - } - getContext() { - return this.context; - } - createGain() { - return this.context.createGain(); - } - getOutputDestination() { - return this.context.destination; - } - createBufferSource() { - return this.context.createBufferSource(); - } - decodeAudioData(data) { - return __awaiter(this, void 0, void 0, function* () { - return yield this.context.decodeAudioData(data); - }); - } - createPanner() { - return this.context.createPanner(); - } - createMediaElementSource(element) { - return this.context.createMediaElementSource(element); - } -} +// simple wrapper around the AudioContext +// eventually will be used to deal with cross browser issues +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export default class ResonatorAudioContext { + constructor() { + this.context = new AudioContext(); + } + getContext() { + return this.context; + } + createGain() { + return this.context.createGain(); + } + getOutputDestination() { + return this.context.destination; + } + createBufferSource() { + return this.context.createBufferSource(); + } + decodeAudioData(data) { + return __awaiter(this, void 0, void 0, function* () { + return yield this.context.decodeAudioData(data); + }); + } + createPanner() { + return this.context.createPanner(); + } + createMediaElementSource(element) { + return this.context.createMediaElementSource(element); + } +} diff --git a/src/framework/resonator/audio-graph.d.ts b/src/framework/resonator/audio-graph.d.ts index 22bef61..f0f3674 100644 --- a/src/framework/resonator/audio-graph.d.ts +++ b/src/framework/resonator/audio-graph.d.ts @@ -1,21 +1,21 @@ -import ResonatorScene from './scenes/webaudio-scene'; -import ResonatorAudioContext from './audio-context'; -import BaseEffect from './effects/base-effect'; -export default class AudioGraph { - private master; - private effectsBus; - private worldBus; - private secondaryBus; - private effects; - private scene; - private context; - private swapChannels; - private channelSplitter; - private channelMerger; - constructor(scene: ResonatorScene, context: ResonatorAudioContext, swapChannels?: boolean); - init(): void; - connectToMaster(input: any): void; - connectToUI(input: AudioNode): void; - applyEffect(effect: BaseEffect): void; - removeEffect(effect: BaseEffect): void; -} +import ResonatorScene from './scenes/webaudio-scene'; +import ResonatorAudioContext from './audio-context'; +import BaseEffect from './effects/base-effect'; +export default class AudioGraph { + private master; + private effectsBus; + private worldBus; + private secondaryBus; + private effects; + private scene; + private context; + private swapChannels; + private channelSplitter; + private channelMerger; + constructor(scene: ResonatorScene, context: ResonatorAudioContext, swapChannels?: boolean); + init(): void; + connectToMaster(input: any): void; + connectToUI(input: AudioNode): void; + applyEffect(effect: BaseEffect): void; + removeEffect(effect: BaseEffect): void; +} diff --git a/src/framework/resonator/audio-graph.js b/src/framework/resonator/audio-graph.js index 2d72be1..2ce66b0 100644 --- a/src/framework/resonator/audio-graph.js +++ b/src/framework/resonator/audio-graph.js @@ -1,46 +1,46 @@ -// this is the mixer that takes all the different outputs and mixes them into the 2 busses: -// WorldBus: The directional audio -// SecondaryBus: All the UI and things that are non directional -import EffectChain from './effect-chain'; -export default class AudioGraph { - constructor(scene, context, swapChannels = false) { - this.scene = scene; - this.context = context; - this.swapChannels = swapChannels; - this.init(); - } - init() { - this.effectsBus = this.context.createGain(); - this.worldBus = this.context.createGain(); - this.secondaryBus = this.context.createGain(); - this.master = this.context.createGain(); - this.scene.getOutput().connect(this.worldBus); - // this.worldBus.connect(this.master); - this.worldBus.connect(this.effectsBus); - this.effects = new EffectChain(this.context, this, this.effectsBus, this.master); - this.secondaryBus.connect(this.master); - if (this.swapChannels) { - this.channelSplitter = this.context.getContext().createChannelSplitter(2); - this.channelMerger = this.context.getContext().createChannelMerger(2); - this.master.connect(this.channelSplitter); - this.channelSplitter.connect(this.channelMerger, 0, 1); - this.channelSplitter.connect(this.channelMerger, 1, 0); - this.channelMerger.connect(this.context.getOutputDestination()); - } - else { - this.master.connect(this.context.getOutputDestination()); - } - } - connectToMaster(input) { - input.connect(this.master); - } - connectToUI(input) { - input.connect(this.secondaryBus); - } - applyEffect(effect) { - this.effects.applyEffect(effect); - } - removeEffect(effect) { - this.effects.removeEffect(effect); - } -} +// this is the mixer that takes all the different outputs and mixes them into the 2 busses: +// WorldBus: The directional audio +// SecondaryBus: All the UI and things that are non directional +import EffectChain from './effect-chain'; +export default class AudioGraph { + constructor(scene, context, swapChannels = false) { + this.scene = scene; + this.context = context; + this.swapChannels = swapChannels; + this.init(); + } + init() { + this.effectsBus = this.context.createGain(); + this.worldBus = this.context.createGain(); + this.secondaryBus = this.context.createGain(); + this.master = this.context.createGain(); + this.scene.getOutput().connect(this.worldBus); + // this.worldBus.connect(this.master); + this.worldBus.connect(this.effectsBus); + this.effects = new EffectChain(this.context, this, this.effectsBus, this.master); + this.secondaryBus.connect(this.master); + if (this.swapChannels) { + this.channelSplitter = this.context.getContext().createChannelSplitter(2); + this.channelMerger = this.context.getContext().createChannelMerger(2); + this.master.connect(this.channelSplitter); + this.channelSplitter.connect(this.channelMerger, 0, 1); + this.channelSplitter.connect(this.channelMerger, 1, 0); + this.channelMerger.connect(this.context.getOutputDestination()); + } + else { + this.master.connect(this.context.getOutputDestination()); + } + } + connectToMaster(input) { + input.connect(this.master); + } + connectToUI(input) { + input.connect(this.secondaryBus); + } + applyEffect(effect) { + this.effects.applyEffect(effect); + } + removeEffect(effect) { + this.effects.removeEffect(effect); + } +} diff --git a/src/framework/resonator/data-pool-item.d.ts b/src/framework/resonator/data-pool-item.d.ts index 3dd2f4f..0275059 100644 --- a/src/framework/resonator/data-pool-item.d.ts +++ b/src/framework/resonator/data-pool-item.d.ts @@ -1,12 +1,12 @@ -export default class DataPoolItem { - private name; - private data; - private decodedData; - constructor(name: string, data?: any, decodedData?: any); - getData(): any; - setData(data: any): void; - getDecodedData(): any; - setDecodedData(data: any): void; - getName(): string; - setName(name: string): void; -} +export default class DataPoolItem { + private name; + private data; + private decodedData; + constructor(name: string, data?: any, decodedData?: any); + getData(): any; + setData(data: any): void; + getDecodedData(): any; + setDecodedData(data: any): void; + getName(): string; + setName(name: string): void; +} diff --git a/src/framework/resonator/data-pool-item.js b/src/framework/resonator/data-pool-item.js index 03b6099..9dcf647 100644 --- a/src/framework/resonator/data-pool-item.js +++ b/src/framework/resonator/data-pool-item.js @@ -1,26 +1,26 @@ -// An item in the data pool -export default class DataPoolItem { - constructor(name, data = null, decodedData = null) { - this.name = name; - this.data = data; - this.decodedData = decodedData; - } - getData() { - return this.data; - } - setData(data) { - this.data = data; - } - getDecodedData() { - return this.decodedData; - } - setDecodedData(data) { - this.decodedData = this.decodedData; - } - getName() { - return this.name; - } - setName(name) { - this.name = name; - } -} +// An item in the data pool +export default class DataPoolItem { + constructor(name, data = null, decodedData = null) { + this.name = name; + this.data = data; + this.decodedData = decodedData; + } + getData() { + return this.data; + } + setData(data) { + this.data = data; + } + getDecodedData() { + return this.decodedData; + } + setDecodedData(data) { + this.decodedData = this.decodedData; + } + getName() { + return this.name; + } + setName(name) { + this.name = name; + } +} diff --git a/src/framework/resonator/data-pool.d.ts b/src/framework/resonator/data-pool.d.ts index 6478e98..dc2b845 100644 --- a/src/framework/resonator/data-pool.d.ts +++ b/src/framework/resonator/data-pool.d.ts @@ -1,12 +1,12 @@ -import EventEmitter from 'eventemitter3'; -import ResonatorAudioContext from './audio-context'; -import { BaseLoader } from './loaders/base-loader'; -export default class DataPool extends EventEmitter { - private loader; - private data; - private maxData; - private context; - constructor(context: ResonatorAudioContext, loader?: BaseLoader, maxData?: number); - get(path: string): Promise; - clear(): void; -} +import { EventBus } from '../event-bus'; +import ResonatorAudioContext from './audio-context'; +import { BaseLoader } from './loaders/base-loader'; +export default class DataPool extends EventBus { + private loader; + private data; + private maxData; + private context; + constructor(context: ResonatorAudioContext, loader?: BaseLoader, maxData?: number); + get(path: string): Promise; + clear(): void; +} diff --git a/src/framework/resonator/data-pool.js b/src/framework/resonator/data-pool.js index c8109f8..77f25bd 100644 --- a/src/framework/resonator/data-pool.js +++ b/src/framework/resonator/data-pool.js @@ -1,48 +1,48 @@ -// a data pool holds frequently played sounds in memory together with decoded audio data to no longer have to decode them from the cache when loaded again -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import EventEmitter from 'eventemitter3'; -import DataPoolItem from './data-pool-item'; -import { HTTPLoader } from './loaders/http-loader'; -export default class DataPool extends EventEmitter { - constructor(context, loader = new HTTPLoader(), maxData = 512) { - super(); - this.loader = loader; - this.data = {}; - this.maxData = maxData; - this.context = context; - } - get(path) { - return __awaiter(this, void 0, void 0, function* () { - if (this.data[path]) { - return this.data[path].getDecodedData(); - } - else { - const buffer = yield this.loader.get(path); - const decoded = yield this.context.decodeAudioData(buffer); - const item = new DataPoolItem(path, buffer, decoded); - const length = Object.keys(this.data).length; - if (length < this.maxData) { - this.data[path] = item; - } - else { - // TODO: figure out a more clever solution than just removing the first loaded data. Like tracking how much certain data is needed and prioritize them. - // const paths: string[] = Object.keys(this.data); - // delete this.data[paths[0]]; - this.data[path] = item; - } - return item.getDecodedData(); - } - }); - } - clear() { - this.data = {}; - } -} +// a data pool holds frequently played sounds in memory together with decoded audio data to no longer have to decode them from the cache when loaded again +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { EventBus } from '../event-bus'; +import DataPoolItem from './data-pool-item'; +import { HTTPLoader } from './loaders/http-loader'; +export default class DataPool extends EventBus { + constructor(context, loader = new HTTPLoader(), maxData = 512) { + super(); + this.loader = loader; + this.data = {}; + this.maxData = maxData; + this.context = context; + } + get(path) { + return __awaiter(this, void 0, void 0, function* () { + if (this.data[path]) { + return this.data[path].getDecodedData(); + } + else { + const buffer = yield this.loader.get(path); + const decoded = yield this.context.decodeAudioData(buffer); + const item = new DataPoolItem(path, buffer, decoded); + const length = Object.keys(this.data).length; + if (length < this.maxData) { + this.data[path] = item; + } + else { + // TODO: figure out a more clever solution than just removing the first loaded data. Like tracking how much certain data is needed and prioritize them. + // const paths: string[] = Object.keys(this.data); + // delete this.data[paths[0]]; + this.data[path] = item; + } + return item.getDecodedData(); + } + }); + } + clear() { + this.data = {}; + } +} diff --git a/src/framework/resonator/effect-bus.d.ts b/src/framework/resonator/effect-bus.d.ts index c940477..57fbb3d 100644 --- a/src/framework/resonator/effect-bus.d.ts +++ b/src/framework/resonator/effect-bus.d.ts @@ -1,8 +1,8 @@ -import ResonatorAudioContext from './audio-context'; -export default class EffectBus { - private context; - private inputNode; - private channelMerger; - constructor(context: ResonatorAudioContext, input: AudioNode, output: AudioNode); - connect(node: AudioNode): void; -} +import ResonatorAudioContext from './audio-context'; +export default class EffectBus { + private context; + private inputNode; + private channelMerger; + constructor(context: ResonatorAudioContext, input: AudioNode, output: AudioNode); + connect(node: AudioNode): void; +} diff --git a/src/framework/resonator/effect-bus.js b/src/framework/resonator/effect-bus.js index 48c0fe5..49fd849 100644 --- a/src/framework/resonator/effect-bus.js +++ b/src/framework/resonator/effect-bus.js @@ -1,12 +1,12 @@ -// Currently unused, but eventually all the effect stuff will be moved from audio graph to here to make it easier to work on -export default class EffectBus { - constructor(context, input, output) { - this.context = context; - this.inputNode = input; - this.channelMerger = this.context.getContext().createChannelMerger(1); - this.inputNode.connect(this.channelMerger); - } - connect(node) { - this.channelMerger.connect(node); - } -} +// Currently unused, but eventually all the effect stuff will be moved from audio graph to here to make it easier to work on +export default class EffectBus { + constructor(context, input, output) { + this.context = context; + this.inputNode = input; + this.channelMerger = this.context.getContext().createChannelMerger(1); + this.inputNode.connect(this.channelMerger); + } + connect(node) { + this.channelMerger.connect(node); + } +} diff --git a/src/framework/resonator/effect-chain.d.ts b/src/framework/resonator/effect-chain.d.ts index 7eab8de..1e235c6 100644 --- a/src/framework/resonator/effect-chain.d.ts +++ b/src/framework/resonator/effect-chain.d.ts @@ -1,14 +1,14 @@ -import ResonatorAudioContext from './audio-context'; -import AudioGraph from './audio-graph'; -import BaseEffect from './effects/base-effect'; -export default class EffectChain { - private context; - private graph; - private effects; - private inputNode; - private outputNode; - constructor(context: ResonatorAudioContext, graph: AudioGraph, input: AudioNode, output: AudioNode); - applyEffect(effect: BaseEffect): void; - removeEffect(effect: BaseEffect): void; - private updateConnections; -} +import ResonatorAudioContext from './audio-context'; +import AudioGraph from './audio-graph'; +import BaseEffect from './effects/base-effect'; +export default class EffectChain { + private context; + private graph; + private effects; + private inputNode; + private outputNode; + constructor(context: ResonatorAudioContext, graph: AudioGraph, input: AudioNode, output: AudioNode); + applyEffect(effect: BaseEffect): void; + removeEffect(effect: BaseEffect): void; + private updateConnections; +} diff --git a/src/framework/resonator/effect-chain.js b/src/framework/resonator/effect-chain.js index 7e61834..17c3d6b 100644 --- a/src/framework/resonator/effect-chain.js +++ b/src/framework/resonator/effect-chain.js @@ -1,45 +1,45 @@ -// A chain of effects that connect to the effect bus -export default class EffectChain { - constructor(context, graph, input, output) { - this.effects = []; - this.context = context; - this.graph = graph; - this.inputNode = input; - this.outputNode = output; - this.updateConnections(); - } - applyEffect(effect) { - this.effects.push(effect); - this.updateConnections(); - } - removeEffect(effect) { - this.effects.forEach((currEffect) => { - if (effect === currEffect) { - currEffect.disconnect(); - } - }); - this.effects = this.effects.filter((currEffect) => effect !== currEffect); - this.updateConnections(); - } - updateConnections() { - if (this.effects.length == 0) { - this.inputNode.connect(this.outputNode); - return; - } - let current = null; - let previous = null; - this.effects.forEach((effect) => { - current = effect; - if (previous) { - current.connectInput(previous.getOutput()); - } - else { - current.connectInput(this.inputNode); - } - previous = current; - }); - if (current) { - current.connectOutput(this.outputNode); - } - } -} +// A chain of effects that connect to the effect bus +export default class EffectChain { + constructor(context, graph, input, output) { + this.effects = []; + this.context = context; + this.graph = graph; + this.inputNode = input; + this.outputNode = output; + this.updateConnections(); + } + applyEffect(effect) { + this.effects.push(effect); + this.updateConnections(); + } + removeEffect(effect) { + this.effects.forEach((currEffect) => { + if (effect === currEffect) { + currEffect.disconnect(); + } + }); + this.effects = this.effects.filter((currEffect) => effect !== currEffect); + this.updateConnections(); + } + updateConnections() { + if (this.effects.length == 0) { + this.inputNode.connect(this.outputNode); + return; + } + let current = null; + let previous = null; + this.effects.forEach((effect) => { + current = effect; + if (previous) { + current.connectInput(previous.getOutput()); + } + else { + current.connectInput(this.inputNode); + } + previous = current; + }); + if (current) { + current.connectOutput(this.outputNode); + } + } +} diff --git a/src/framework/resonator/effects/base-effect.d.ts b/src/framework/resonator/effects/base-effect.d.ts index 3a163ff..7233383 100644 --- a/src/framework/resonator/effects/base-effect.d.ts +++ b/src/framework/resonator/effects/base-effect.d.ts @@ -1,15 +1,15 @@ -import ResonatorAudioContext from '../audio-context'; -import AudioGraph from '../audio-graph'; -export default class BaseEffect { - protected ready: boolean; - protected effectNode: any; - protected effectParams: any; - protected context: ResonatorAudioContext; - protected graph: AudioGraph; - protected inputNode: AudioNode; - constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any); - connectOutput(node: AudioNode): void; - connectInput(node: AudioNode): void; - getOutput(): AudioNode; - disconnect(): void; -} +import ResonatorAudioContext from '../audio-context'; +import AudioGraph from '../audio-graph'; +export default class BaseEffect { + protected ready: boolean; + protected effectNode: any; + protected effectParams: any; + protected context: ResonatorAudioContext; + protected graph: AudioGraph; + protected inputNode: AudioNode; + constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any); + connectOutput(node: AudioNode): void; + connectInput(node: AudioNode): void; + getOutput(): AudioNode; + disconnect(): void; +} diff --git a/src/framework/resonator/effects/base-effect.js b/src/framework/resonator/effects/base-effect.js index 2622e95..e2c04b8 100644 --- a/src/framework/resonator/effects/base-effect.js +++ b/src/framework/resonator/effects/base-effect.js @@ -1,23 +1,23 @@ -export default class BaseEffect { - constructor(context, graph, params) { - this.graph = graph; - this.context = context; - this.effectParams = params; - } - connectOutput(node) { - this.effectNode.connect(node); - } - connectInput(node) { - this.inputNode = node; - if (this.effectNode) { - this.inputNode.connect(this.effectNode); - } - } - getOutput() { - return this.effectNode; - } - disconnect() { - this.inputNode.disconnect(); - this.effectNode.disconnect(); - } -} +export default class BaseEffect { + constructor(context, graph, params) { + this.graph = graph; + this.context = context; + this.effectParams = params; + } + connectOutput(node) { + this.effectNode.connect(node); + } + connectInput(node) { + this.inputNode = node; + if (this.effectNode) { + this.inputNode.connect(this.effectNode); + } + } + getOutput() { + return this.effectNode; + } + disconnect() { + this.inputNode.disconnect(); + this.effectNode.disconnect(); + } +} diff --git a/src/framework/resonator/effects/convolver.d.ts b/src/framework/resonator/effects/convolver.d.ts index b61a265..be6abb9 100644 --- a/src/framework/resonator/effects/convolver.d.ts +++ b/src/framework/resonator/effects/convolver.d.ts @@ -1,10 +1,10 @@ -import BaseEffect from './base-effect'; -import ResonatorAudioContext from '../audio-context'; -import AudioGraph from '../audio-graph'; -export default class Convolver extends BaseEffect { - private buffer; - private channelSplitter; - private channelMerger; - constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any); - connectInput(node: AudioNode): void; -} +import BaseEffect from './base-effect'; +import ResonatorAudioContext from '../audio-context'; +import AudioGraph from '../audio-graph'; +export default class Convolver extends BaseEffect { + private buffer; + private channelSplitter; + private channelMerger; + constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any); + connectInput(node: AudioNode): void; +} diff --git a/src/framework/resonator/effects/convolver.js b/src/framework/resonator/effects/convolver.js index 1b5a732..2b798fd 100644 --- a/src/framework/resonator/effects/convolver.js +++ b/src/framework/resonator/effects/convolver.js @@ -1,20 +1,20 @@ -import BaseEffect from './base-effect'; -export default class Convolver extends BaseEffect { - constructor(context, graph, params) { - super(context, graph, params); - console.log(`Creating convolver`); - this.effectNode = this.context.getContext().createConvolver(); - this.effectNode.buffer = this.effectParams.buffer; - } - connectInput(node) { - this.channelSplitter = this.context.getContext().createChannelSplitter(2); - this.channelMerger = this.context.getContext().createChannelMerger(2); - this.channelSplitter.connect(this.channelMerger, 0, 0); - this.channelSplitter.connect(this.channelMerger, 1, 0); - this.channelSplitter.connect(this.channelMerger, 0, 1); - this.channelSplitter.connect(this.channelMerger, 1, 1); - node.connect(this.channelSplitter); - this.channelMerger.connect(this.effectNode); - this.inputNode = node; - } -} +import BaseEffect from './base-effect'; +export default class Convolver extends BaseEffect { + constructor(context, graph, params) { + super(context, graph, params); + console.log(`Creating convolver`); + this.effectNode = this.context.getContext().createConvolver(); + this.effectNode.buffer = this.effectParams.buffer; + } + connectInput(node) { + this.channelSplitter = this.context.getContext().createChannelSplitter(2); + this.channelMerger = this.context.getContext().createChannelMerger(2); + this.channelSplitter.connect(this.channelMerger, 0, 0); + this.channelSplitter.connect(this.channelMerger, 1, 0); + this.channelSplitter.connect(this.channelMerger, 0, 1); + this.channelSplitter.connect(this.channelMerger, 1, 1); + node.connect(this.channelSplitter); + this.channelMerger.connect(this.effectNode); + this.inputNode = node; + } +} diff --git a/src/framework/resonator/index.d.ts b/src/framework/resonator/index.d.ts index 7de5ff4..a9fd891 100644 --- a/src/framework/resonator/index.d.ts +++ b/src/framework/resonator/index.d.ts @@ -1,22 +1,22 @@ -import AudioSource from './sources/audio-source'; -import { BaseLoader } from './loaders/base-loader'; -import { BaseSource } from './sources/base-source'; -import { SourceType } from './sources/source-type'; -import { StreamingSource } from './sources/streaming-source'; -export default class Resonator { - private loader; - private context; - private scene; - private graph; - private dataPool; - private environmentImpulse; - constructor(loader?: BaseLoader); - load(path: string, type?: SourceType): Promise; - loadImmediate(path: string, type?: SourceType): AudioSource; - stream(path: string, type?: SourceType): StreamingSource; - private createSource; - setEnvironmentImpulse(file: string): Promise; - setListenerPosition(x: number, y: number, z: number): void; - setListenerOrientation(forward: any, up: any): void; - clearDataPool(): void; -} +import AudioSource from './sources/audio-source'; +import { BaseLoader } from './loaders/base-loader'; +import { BaseSource } from './sources/base-source'; +import { SourceType } from './sources/source-type'; +import { StreamingSource } from './sources/streaming-source'; +export default class Resonator { + private loader; + private context; + private scene; + private graph; + private dataPool; + private environmentImpulse; + constructor(loader?: BaseLoader); + load(path: string, type?: SourceType): Promise; + loadImmediate(path: string, type?: SourceType): AudioSource; + stream(path: string, type?: SourceType): StreamingSource; + private createSource; + setEnvironmentImpulse(file: string): Promise; + setListenerPosition(x: number, y: number, z: number): void; + setListenerOrientation(forward: any, up: any): void; + clearDataPool(): void; +} diff --git a/src/framework/resonator/index.js b/src/framework/resonator/index.js index 62577e7..260bb81 100644 --- a/src/framework/resonator/index.js +++ b/src/framework/resonator/index.js @@ -1,78 +1,78 @@ -// the main module for Resonator -// API, etc. -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import ResonatorAudioContext from './audio-context'; -import ResonatorScene from './scenes/webaudio-scene'; -import AudioGraph from './audio-graph'; -import AudioSource from './sources/audio-source'; -import DataPool from './data-pool'; -import Convolver from './effects/convolver'; -import { HTTPLoader } from './loaders/http-loader'; -import { SourceType } from './sources/source-type'; -import { StreamingSource } from './sources/streaming-source'; -export default class Resonator { - constructor(loader = new HTTPLoader()) { - this.loader = loader; - this.environmentImpulse = null; - this.context = new ResonatorAudioContext(); - this.scene = new ResonatorScene(this.context); - this.graph = new AudioGraph(this.scene, this.context, false); - this.dataPool = new DataPool(this.context, this.loader); - } - load(path, type = SourceType.WorldSource) { - return __awaiter(this, void 0, void 0, function* () { - const data = yield this.dataPool.get(path); - const source = this.createSource(type, data); - return source; - }); - } - loadImmediate(path, type = SourceType.WorldSource) { - const source = new AudioSource(this.graph, this.scene, this.context, null, type); - this.dataPool.get(path).then((data) => { - source.setBuffer(data); - }); - return source; - } - stream(path, type = SourceType.MasterSource) { - const element = new Audio(path); - element.crossOrigin = 'anonymous'; - element.volume = 1; - const source = new StreamingSource(this.graph, this.scene, this.context, element, type); - return source; - } - createSource(type, data) { - return new AudioSource(this.graph, this.scene, this.context, data); - } - setEnvironmentImpulse(file) { - return __awaiter(this, void 0, void 0, function* () { - if (this.environmentImpulse) { - this.graph.removeEffect(this.environmentImpulse); - } - if (file === null) { - return; - } - const buffer = yield this.dataPool.get(file); - this.environmentImpulse = new Convolver(this.context, this.graph, { - buffer - }); - this.graph.applyEffect(this.environmentImpulse); - }); - } - setListenerPosition(x, y, z) { - this.scene.setListenerPosition(x, y, z); - } - setListenerOrientation(forward, up) { - this.scene.setListenerOrientation(forward, up); - } - clearDataPool() { - this.dataPool.clear(); - } -} +// the main module for Resonator +// API, etc. +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import ResonatorAudioContext from './audio-context'; +import ResonatorScene from './scenes/webaudio-scene'; +import AudioGraph from './audio-graph'; +import AudioSource from './sources/audio-source'; +import DataPool from './data-pool'; +import Convolver from './effects/convolver'; +import { HTTPLoader } from './loaders/http-loader'; +import { SourceType } from './sources/source-type'; +import { StreamingSource } from './sources/streaming-source'; +export default class Resonator { + constructor(loader = new HTTPLoader()) { + this.loader = loader; + this.environmentImpulse = null; + this.context = new ResonatorAudioContext(); + this.scene = new ResonatorScene(this.context); + this.graph = new AudioGraph(this.scene, this.context, false); + this.dataPool = new DataPool(this.context, this.loader); + } + load(path, type = SourceType.WorldSource) { + return __awaiter(this, void 0, void 0, function* () { + const data = yield this.dataPool.get(path); + const source = this.createSource(type, data); + return source; + }); + } + loadImmediate(path, type = SourceType.WorldSource) { + const source = new AudioSource(this.graph, this.scene, this.context, null, type); + this.dataPool.get(path).then((data) => { + source.setBuffer(data); + }); + return source; + } + stream(path, type = SourceType.MasterSource) { + const element = new Audio(path); + element.crossOrigin = 'anonymous'; + element.volume = 1; + const source = new StreamingSource(this.graph, this.scene, this.context, element, type); + return source; + } + createSource(type, data) { + return new AudioSource(this.graph, this.scene, this.context, data); + } + setEnvironmentImpulse(file) { + return __awaiter(this, void 0, void 0, function* () { + if (this.environmentImpulse) { + this.graph.removeEffect(this.environmentImpulse); + } + if (file === null) { + return; + } + const buffer = yield this.dataPool.get(file); + this.environmentImpulse = new Convolver(this.context, this.graph, { + buffer + }); + this.graph.applyEffect(this.environmentImpulse); + }); + } + setListenerPosition(x, y, z) { + this.scene.setListenerPosition(x, y, z); + } + setListenerOrientation(forward, up) { + this.scene.setListenerOrientation(forward, up); + } + clearDataPool() { + this.dataPool.clear(); + } +} diff --git a/src/framework/resonator/loaders/asset-loader.d.ts b/src/framework/resonator/loaders/asset-loader.d.ts index 012be16..d3e4641 100644 --- a/src/framework/resonator/loaders/asset-loader.d.ts +++ b/src/framework/resonator/loaders/asset-loader.d.ts @@ -1,10 +1,10 @@ -import { AssetManager } from '../../asset-manager'; -import { BaseLoader } from './base-loader'; -export declare class AssetLoader implements BaseLoader { - private name; - private manager; - private assetManager; - constructor(name: string, manager?: AssetManager); - init(): Promise; - get(path: string): Promise; -} +import { AssetManager } from '../../asset-manager'; +import { BaseLoader } from './base-loader'; +export declare class AssetLoader implements BaseLoader { + private name; + private manager; + private assetManager; + constructor(name: string, manager?: AssetManager); + init(): Promise; + get(path: string): Promise; +} diff --git a/src/framework/resonator/loaders/asset-loader.js b/src/framework/resonator/loaders/asset-loader.js index 4b6920e..dddc759 100644 --- a/src/framework/resonator/loaders/asset-loader.js +++ b/src/framework/resonator/loaders/asset-loader.js @@ -1,36 +1,36 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -// TODO fix path when actually properly linking the packages together -import { AssetManager } from '../../asset-manager'; -export class AssetLoader { - constructor(name, manager = null) { - this.name = name; - this.manager = manager; - if (manager) { - this.assetManager = manager; - } - else { - this.assetManager = new AssetManager(name, ''); - } - } - init() { - return __awaiter(this, void 0, void 0, function* () { - yield this.assetManager.init(); - }); - } - get(path) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield this.assetManager.downloadFile(path); - console.log(result); - const buffer = yield result.arrayBuffer(); - return buffer; - }); - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +// TODO fix path when actually properly linking the packages together +import { AssetManager } from '../../asset-manager'; +export class AssetLoader { + constructor(name, manager = null) { + this.name = name; + this.manager = manager; + if (manager) { + this.assetManager = manager; + } + else { + this.assetManager = new AssetManager(name, ''); + } + } + init() { + return __awaiter(this, void 0, void 0, function* () { + yield this.assetManager.init(); + }); + } + get(path) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield this.assetManager.downloadFile(path); + console.log(result); + const buffer = yield result.arrayBuffer(); + return buffer; + }); + } +} diff --git a/src/framework/resonator/loaders/base-loader.d.ts b/src/framework/resonator/loaders/base-loader.d.ts index c586898..90a7c66 100644 --- a/src/framework/resonator/loaders/base-loader.d.ts +++ b/src/framework/resonator/loaders/base-loader.d.ts @@ -1,3 +1,3 @@ -export interface BaseLoader { - get(path: string): Promise; -} +export interface BaseLoader { + get(path: string): Promise; +} diff --git a/src/framework/resonator/loaders/base-loader.js b/src/framework/resonator/loaders/base-loader.js index cb0ff5c..509db18 100644 --- a/src/framework/resonator/loaders/base-loader.js +++ b/src/framework/resonator/loaders/base-loader.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/resonator/loaders/http-loader.d.ts b/src/framework/resonator/loaders/http-loader.d.ts index a3ff342..c38c282 100644 --- a/src/framework/resonator/loaders/http-loader.d.ts +++ b/src/framework/resonator/loaders/http-loader.d.ts @@ -1,4 +1,4 @@ -import { BaseLoader } from './base-loader'; -export declare class HTTPLoader implements BaseLoader { - get(path: string): Promise; -} +import { BaseLoader } from './base-loader'; +export declare class HTTPLoader implements BaseLoader { + get(path: string): Promise; +} diff --git a/src/framework/resonator/loaders/http-loader.js b/src/framework/resonator/loaders/http-loader.js index de67b13..06f7dbf 100644 --- a/src/framework/resonator/loaders/http-loader.js +++ b/src/framework/resonator/loaders/http-loader.js @@ -1,18 +1,18 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -export class HTTPLoader { - get(path) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield fetch(path); - const buffer = yield result.arrayBuffer(); - return buffer; - }); - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export class HTTPLoader { + get(path) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield fetch(path); + const buffer = yield result.arrayBuffer(); + return buffer; + }); + } +} diff --git a/src/framework/resonator/scenes/resonance-scene.d.ts b/src/framework/resonator/scenes/resonance-scene.d.ts index 967d131..49a4c19 100644 --- a/src/framework/resonator/scenes/resonance-scene.d.ts +++ b/src/framework/resonator/scenes/resonance-scene.d.ts @@ -1,14 +1,14 @@ -import ResonatorAudioContext from '../audio-context'; -import EventEmitter from 'eventemitter3'; -export default class Scene extends EventEmitter { - scene: any; - context: ResonatorAudioContext; - listener: AudioListener; - constructor(context: ResonatorAudioContext); - init(): void; - createSource(): any; - getOutput(): any; - getInput(): any; - setListenerPosition(x: number, y: number, z: number): void; - setListenerOrientation(forward: any, rawup: any): void; -} +import ResonatorAudioContext from '../audio-context'; +import { EventBus } from '../../event-bus'; +export default class Scene extends EventBus { + scene: any; + context: ResonatorAudioContext; + listener: AudioListener; + constructor(context: ResonatorAudioContext); + init(): void; + createSource(): any; + getOutput(): any; + getInput(): any; + setListenerPosition(x: number, y: number, z: number): void; + setListenerOrientation(forward: any, rawup: any): void; +} diff --git a/src/framework/resonator/scenes/resonance-scene.js b/src/framework/resonator/scenes/resonance-scene.js index f885e91..b0b2d70 100644 --- a/src/framework/resonator/scenes/resonance-scene.js +++ b/src/framework/resonator/scenes/resonance-scene.js @@ -1,40 +1,40 @@ -// The code that deals with 3d audio -import ResonanceAudio from '../vendor/resonance-es6/main'; -import EventEmitter from 'eventemitter3'; -import vec3 from '../../tsm/vec3'; -export default class Scene extends EventEmitter { - constructor(context) { - super(); - this.context = context; - this.scene = new ResonanceAudio(this.context.getContext(), { - ambisonicOrder: 3 - }); - this.listener = this.context.getContext().listener; - this.init(); - } - init() { - // this.scene.output.connect(this.context.getOutputDestination()); - } - createSource() { - const source = this.scene.createSource(); - return Object.assign(Object.assign({}, source), { getInput: () => source.input }); - } - getOutput() { - return this.scene.output; - } - getInput() { - return this.scene.input; - } - setListenerPosition(x, y, z) { - this.scene.setListenerPosition(x, y, z); - } - setListenerOrientation(forward, rawup) { - let fwd = new vec3([forward.x, forward.y, forward.z]); - let up = fwd.copy(); - vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up); - vec3.cross(up, fwd, up); - fwd.normalize(); - up.normalize(); - this.scene.setListenerOrientation(forward.x, forward.y, forward.z, rawup.x, rawup.y, rawup.z); - } -} +// The code that deals with 3d audio +import ResonanceAudio from '../vendor/resonance-es6/main'; +import { EventBus } from '../../event-bus'; +import vec3 from '../../math/vec3'; +export default class Scene extends EventBus { + constructor(context) { + super(); + this.context = context; + this.scene = new ResonanceAudio(this.context.getContext(), { + ambisonicOrder: 3 + }); + this.listener = this.context.getContext().listener; + this.init(); + } + init() { + // this.scene.output.connect(this.context.getOutputDestination()); + } + createSource() { + const source = this.scene.createSource(); + return Object.assign(Object.assign({}, source), { getInput: () => source.input }); + } + getOutput() { + return this.scene.output; + } + getInput() { + return this.scene.input; + } + setListenerPosition(x, y, z) { + this.scene.setListenerPosition(x, y, z); + } + setListenerOrientation(forward, rawup) { + let fwd = new vec3([forward.x, forward.y, forward.z]); + let up = fwd.copy(); + vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up); + vec3.cross(up, fwd, up); + fwd.normalize(); + up.normalize(); + this.scene.setListenerOrientation(forward.x, forward.y, forward.z, rawup.x, rawup.y, rawup.z); + } +} diff --git a/src/framework/resonator/scenes/webaudio-scene.d.ts b/src/framework/resonator/scenes/webaudio-scene.d.ts index 6ae3a1f..e5ab8b2 100644 --- a/src/framework/resonator/scenes/webaudio-scene.d.ts +++ b/src/framework/resonator/scenes/webaudio-scene.d.ts @@ -1,14 +1,14 @@ -import ResonatorAudioContext from '../audio-context'; -import EventEmitter from 'eventemitter3'; -export default class ResonatorScene extends EventEmitter { - scene: GainNode; - context: ResonatorAudioContext; - listener: AudioListener; - constructor(context: ResonatorAudioContext); - init(): void; - createSource(): any; - getOutput(): any; - getInput(): any; - setListenerPosition(x: number, y: number, z: number): void; - setListenerOrientation(forward: any, rawup: any): void; -} +import ResonatorAudioContext from '../audio-context'; +import { EventBus } from '../../event-bus'; +export default class ResonatorScene extends EventBus { + scene: GainNode; + context: ResonatorAudioContext; + listener: AudioListener; + constructor(context: ResonatorAudioContext); + init(): void; + createSource(): any; + getOutput(): any; + getInput(): any; + setListenerPosition(x: number, y: number, z: number): void; + setListenerOrientation(forward: any, rawup: any): void; +} diff --git a/src/framework/resonator/scenes/webaudio-scene.js b/src/framework/resonator/scenes/webaudio-scene.js index 19fb5a4..be5704a 100644 --- a/src/framework/resonator/scenes/webaudio-scene.js +++ b/src/framework/resonator/scenes/webaudio-scene.js @@ -1,42 +1,42 @@ -// The code that deals with 3d audio -import EventEmitter from 'eventemitter3'; -import vec3 from '../../tsm/vec3'; -export default class ResonatorScene extends EventEmitter { - constructor(context) { - super(); - this.context = context; - this.scene = this.context.getContext().createGain(); - this.listener = this.context.getContext().listener; - this.init(); - } - init() { - // this.scene.output.connect(this.context.getOutputDestination()); - } - createSource() { - const node = this.context.getContext().createPanner(); - node.panningModel = 'HRTF'; - node.distanceModel = 'linear'; - node.maxDistance = 20; - node.refDistance = 2; - node.connect(this.scene); - return node; - } - getOutput() { - return this.scene; - } - getInput() { - return this.scene; - } - setListenerPosition(x, y, z) { - this.listener.setPosition(x, y, z); - } - setListenerOrientation(forward, rawup) { - let fwd = new vec3([forward.x, forward.y, forward.z]); - let up = fwd.copy(); - vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up); - vec3.cross(up, fwd, up); - fwd.normalize(); - up.normalize(); - this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z); - } -} +// The code that deals with 3d audio +import { EventBus } from '../../event-bus'; +import vec3 from '../../math/vec3'; +export default class ResonatorScene extends EventBus { + constructor(context) { + super(); + this.context = context; + this.scene = this.context.getContext().createGain(); + this.listener = this.context.getContext().listener; + this.init(); + } + init() { + // this.scene.output.connect(this.context.getOutputDestination()); + } + createSource() { + const node = this.context.getContext().createPanner(); + node.panningModel = 'HRTF'; + node.distanceModel = 'linear'; + node.maxDistance = 20; + node.refDistance = 2; + node.connect(this.scene); + return node; + } + getOutput() { + return this.scene; + } + getInput() { + return this.scene; + } + setListenerPosition(x, y, z) { + this.listener.setPosition(x, y, z); + } + setListenerOrientation(forward, rawup) { + let fwd = new vec3([forward.x, forward.y, forward.z]); + let up = fwd.copy(); + vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up); + vec3.cross(up, fwd, up); + fwd.normalize(); + up.normalize(); + this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z); + } +} diff --git a/src/framework/resonator/sources/audio-source.d.ts b/src/framework/resonator/sources/audio-source.d.ts index 130e01c..15a3c98 100644 --- a/src/framework/resonator/sources/audio-source.d.ts +++ b/src/framework/resonator/sources/audio-source.d.ts @@ -1,37 +1,37 @@ -import ResonatorAudioContext from '../audio-context'; -import AudioGraph from '../audio-graph'; -import ResonatorScene from '../scenes/webaudio-scene'; -import { BaseSource } from './base-source'; -import { SourceType } from './source-type'; -export default class AudioSource implements BaseSource { - playing: boolean; - looping: boolean; - private node; - private sceneNode; - private buffer; - private context; - private graph; - private scene; - private playOnLoad; - private position; - private playbackRate; - private volume; - private gain; - private type; - constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType); - init(): void; - getBuffer(): AudioBuffer; - setBuffer(data: AudioBuffer): void; - play(when?: number, offset?: number, duration?: number): void; - setPosition(x: number, y: number, z: number): void; - setPlaybackRate(rate: number): void; - getPlaybackRate(): number; - setVolume(volume: number): void; - getVolume(): number; - private createConnections; - stop(): void; - destroy(): void; - loop(value: boolean): void; - fadeOut(time: number): void; - fadeIn(time: number): void; -} +import ResonatorAudioContext from '../audio-context'; +import AudioGraph from '../audio-graph'; +import ResonatorScene from '../scenes/webaudio-scene'; +import { BaseSource } from './base-source'; +import { SourceType } from './source-type'; +export default class AudioSource implements BaseSource { + playing: boolean; + looping: boolean; + private node; + private sceneNode; + private buffer; + private context; + private graph; + private scene; + private playOnLoad; + private position; + private playbackRate; + private volume; + private gain; + private type; + constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType); + init(): void; + getBuffer(): AudioBuffer; + setBuffer(data: AudioBuffer): void; + play(when?: number, offset?: number, duration?: number): void; + setPosition(x: number, y: number, z: number): void; + setPlaybackRate(rate: number): void; + getPlaybackRate(): number; + setVolume(volume: number): void; + getVolume(): number; + private createConnections; + stop(): void; + destroy(): void; + loop(value: boolean): void; + fadeOut(time: number): void; + fadeIn(time: number): void; +} diff --git a/src/framework/resonator/sources/audio-source.js b/src/framework/resonator/sources/audio-source.js index fa61c97..9ac0384 100644 --- a/src/framework/resonator/sources/audio-source.js +++ b/src/framework/resonator/sources/audio-source.js @@ -1,148 +1,148 @@ -// an audio source -// This is the actual sound -import { SourceType } from './source-type'; -export default class AudioSource { - constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) { - this.position = { - x: 0, - y: 0, - z: 0 - }; - this.buffer = buffer; - this.context = context; - this.scene = scene; - this.graph = graph; - this.type = type; - this.playbackRate = 1; - this.volume = 1; - this.init(); - } - init() { - this.gain = this.context.createGain(); - // bind methods so we can add and removve them from event listeners - this.stop = this.stop.bind(this); - } - getBuffer() { - return this.buffer; - } - setBuffer(data) { - this.buffer = data; - if (this.playOnLoad) { - this.play(); - this.playOnLoad = false; - } - } - play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) { - if (this.playing && this.node) { - this.stop(); - } - if (!this.buffer) { - this.playOnLoad = true; - return; - } - if (!this.node) { - this.node = this.context.createBufferSource(); - this.node.buffer = this.buffer; - this.createConnections(); - } - if (this.node) { - this.node.playbackRate.value = this.playbackRate; - this.node.start(when, offset, duration); - this.node.loop = this.looping; - this.playing = true; - if (this.sceneNode) { - this.sceneNode.setPosition(this.position.x, this.position.y, this.position.z); - } - this.node.addEventListener('ended', this.stop); - } - } - setPosition(x, y, z) { - this.position = { - x, - y, - z - }; - if (this.sceneNode) - this.sceneNode.setPosition(x, y, z); - } - setPlaybackRate(rate) { - this.playbackRate = rate; - if (this.node) - this.node.playbackRate.value = rate; - } - getPlaybackRate() { - return this.playbackRate; - } - setVolume(volume) { - this.volume = volume; - if (this.gain) - this.gain.gain.value = volume; - } - getVolume() { - return this.volume; - } - createConnections() { - switch (this.type) { - case SourceType.WorldSource: - if (!this.sceneNode) { - this.sceneNode = this.scene.createSource(); - } - this.node.connect(this.gain); - this.gain.connect(this.sceneNode); - break; - case SourceType.UISource: - this.node.connect(this.gain); - this.graph.connectToUI(this.gain); - break; - default: - this.node.connect(this.gain); - this.graph.connectToMaster(this.gain); - break; - } - } - stop() { - this.playing = false; - if (this.node) { - this.node.removeEventListener('ended', this.stop); - this.node.stop(); - this.node.disconnect(); - this.node = null; - this.playing = false; - if (this.sceneNode) { - this.sceneNode.disconnect(); - this.sceneNode = null; - } - } - } - destroy() { - this.stop(); - // set all refs to null to encourage gc - this.node = null; - this.sceneNode = null; - this.buffer = null; - this.context = null; - this.graph = null; - this.scene = null; - } - loop(value) { - this.looping = value; - if (this.node) { - this.node.loop = value; - } - } - fadeOut(time) { - this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime); - if (!this.node) { - return; - } - this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time); - setTimeout(() => this.stop(), time * 1000); - } - fadeIn(time) { - this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime); - if (!this.node) { - this.play(); - } - this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time); - } -} +// an audio source +// This is the actual sound +import { SourceType } from './source-type'; +export default class AudioSource { + constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) { + this.position = { + x: 0, + y: 0, + z: 0 + }; + this.buffer = buffer; + this.context = context; + this.scene = scene; + this.graph = graph; + this.type = type; + this.playbackRate = 1; + this.volume = 1; + this.init(); + } + init() { + this.gain = this.context.createGain(); + // bind methods so we can add and removve them from event listeners + this.stop = this.stop.bind(this); + } + getBuffer() { + return this.buffer; + } + setBuffer(data) { + this.buffer = data; + if (this.playOnLoad) { + this.play(); + this.playOnLoad = false; + } + } + play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) { + if (this.playing && this.node) { + this.stop(); + } + if (!this.buffer) { + this.playOnLoad = true; + return; + } + if (!this.node) { + this.node = this.context.createBufferSource(); + this.node.buffer = this.buffer; + this.createConnections(); + } + if (this.node) { + this.node.playbackRate.value = this.playbackRate; + this.node.start(when, offset, duration); + this.node.loop = this.looping; + this.playing = true; + if (this.sceneNode) { + this.sceneNode.setPosition(this.position.x, this.position.y, this.position.z); + } + this.node.addEventListener('ended', this.stop); + } + } + setPosition(x, y, z) { + this.position = { + x, + y, + z + }; + if (this.sceneNode) + this.sceneNode.setPosition(x, y, z); + } + setPlaybackRate(rate) { + this.playbackRate = rate; + if (this.node) + this.node.playbackRate.value = rate; + } + getPlaybackRate() { + return this.playbackRate; + } + setVolume(volume) { + this.volume = volume; + if (this.gain) + this.gain.gain.value = volume; + } + getVolume() { + return this.volume; + } + createConnections() { + switch (this.type) { + case SourceType.WorldSource: + if (!this.sceneNode) { + this.sceneNode = this.scene.createSource(); + } + this.node.connect(this.gain); + this.gain.connect(this.sceneNode); + break; + case SourceType.UISource: + this.node.connect(this.gain); + this.graph.connectToUI(this.gain); + break; + default: + this.node.connect(this.gain); + this.graph.connectToMaster(this.gain); + break; + } + } + stop() { + this.playing = false; + if (this.node) { + this.node.removeEventListener('ended', this.stop); + this.node.stop(); + this.node.disconnect(); + this.node = null; + this.playing = false; + if (this.sceneNode) { + this.sceneNode.disconnect(); + this.sceneNode = null; + } + } + } + destroy() { + this.stop(); + // set all refs to null to encourage gc + this.node = null; + this.sceneNode = null; + this.buffer = null; + this.context = null; + this.graph = null; + this.scene = null; + } + loop(value) { + this.looping = value; + if (this.node) { + this.node.loop = value; + } + } + fadeOut(time) { + this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime); + if (!this.node) { + return; + } + this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time); + setTimeout(() => this.stop(), time * 1000); + } + fadeIn(time) { + this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime); + if (!this.node) { + this.play(); + } + this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time); + } +} diff --git a/src/framework/resonator/sources/base-source.d.ts b/src/framework/resonator/sources/base-source.d.ts index 76ac75c..b325114 100644 --- a/src/framework/resonator/sources/base-source.d.ts +++ b/src/framework/resonator/sources/base-source.d.ts @@ -1,12 +1,12 @@ -export interface BaseSource { - play(when: number, offset: number, duration: number): void; - stop(): void; - setPlaybackRate(value: number): void; - getPlaybackRate(): number; - setVolume(value: number): void; - getVolume(): number; - loop(value: boolean): void; - fadeOut(time: number): void; - fadeIn(time: number): void; - destroy(): void; -} +export interface BaseSource { + play(when: number, offset: number, duration: number): void; + stop(): void; + setPlaybackRate(value: number): void; + getPlaybackRate(): number; + setVolume(value: number): void; + getVolume(): number; + loop(value: boolean): void; + fadeOut(time: number): void; + fadeIn(time: number): void; + destroy(): void; +} diff --git a/src/framework/resonator/sources/base-source.js b/src/framework/resonator/sources/base-source.js index cb0ff5c..509db18 100644 --- a/src/framework/resonator/sources/base-source.js +++ b/src/framework/resonator/sources/base-source.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/resonator/sources/source-type.d.ts b/src/framework/resonator/sources/source-type.d.ts index c0304b1..a704b33 100644 --- a/src/framework/resonator/sources/source-type.d.ts +++ b/src/framework/resonator/sources/source-type.d.ts @@ -1,5 +1,5 @@ -export declare enum SourceType { - WorldSource = 0, - UISource = 1, - MasterSource = 2 -} +export declare enum SourceType { + WorldSource = 0, + UISource = 1, + MasterSource = 2 +} diff --git a/src/framework/resonator/sources/source-type.js b/src/framework/resonator/sources/source-type.js index 2d58552..b220487 100644 --- a/src/framework/resonator/sources/source-type.js +++ b/src/framework/resonator/sources/source-type.js @@ -1,6 +1,6 @@ -export var SourceType; -(function (SourceType) { - SourceType[SourceType["WorldSource"] = 0] = "WorldSource"; - SourceType[SourceType["UISource"] = 1] = "UISource"; - SourceType[SourceType["MasterSource"] = 2] = "MasterSource"; -})(SourceType || (SourceType = {})); +export var SourceType; +(function (SourceType) { + SourceType[SourceType["WorldSource"] = 0] = "WorldSource"; + SourceType[SourceType["UISource"] = 1] = "UISource"; + SourceType[SourceType["MasterSource"] = 2] = "MasterSource"; +})(SourceType || (SourceType = {})); diff --git a/src/framework/resonator/sources/streaming-source.d.ts b/src/framework/resonator/sources/streaming-source.d.ts index 425bc8a..a8d6527 100644 --- a/src/framework/resonator/sources/streaming-source.d.ts +++ b/src/framework/resonator/sources/streaming-source.d.ts @@ -1,33 +1,33 @@ -import { BaseSource } from './base-source'; -import AudioGraph from '../audio-graph'; -import ResonatorScene from '../scenes/webaudio-scene'; -import ResonatorAudioContext from '../audio-context'; -import { SourceType } from './source-type'; -export declare class StreamingSource implements BaseSource { - private graph; - private scene; - private context; - private element; - private type; - playing: boolean; - private playOnAvailable; - private node; - private canPlay; - private sceneNode; - private gain; - private position; - constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType); - private init; - play(when?: number, offset?: number, duration?: number): void; - stop(): void; - getVolume(): number; - setVolume(value: number): void; - getPlaybackRate(): number; - setPlaybackRate(value: number): void; - private createConnections; - setPosition(x: number, y: number, z: number): void; - destroy(): void; - loop(value: boolean): void; - fadeIn(time: number): void; - fadeOut(time: number): void; -} +import { BaseSource } from './base-source'; +import AudioGraph from '../audio-graph'; +import ResonatorScene from '../scenes/webaudio-scene'; +import ResonatorAudioContext from '../audio-context'; +import { SourceType } from './source-type'; +export declare class StreamingSource implements BaseSource { + private graph; + private scene; + private context; + private element; + private type; + playing: boolean; + private playOnAvailable; + private node; + private canPlay; + private sceneNode; + private gain; + private position; + constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, element: HTMLAudioElement, type?: SourceType); + private init; + play(when?: number, offset?: number, duration?: number): void; + stop(): void; + getVolume(): number; + setVolume(value: number): void; + getPlaybackRate(): number; + setPlaybackRate(value: number): void; + private createConnections; + setPosition(x: number, y: number, z: number): void; + destroy(): void; + loop(value: boolean): void; + fadeIn(time: number): void; + fadeOut(time: number): void; +} diff --git a/src/framework/resonator/sources/streaming-source.js b/src/framework/resonator/sources/streaming-source.js index 6d0dc34..e75889c 100644 --- a/src/framework/resonator/sources/streaming-source.js +++ b/src/framework/resonator/sources/streaming-source.js @@ -1,99 +1,99 @@ -import { SourceType } from './source-type'; -export class StreamingSource { - constructor(graph, scene, context, element, type = SourceType.MasterSource) { - this.graph = graph; - this.scene = scene; - this.context = context; - this.element = element; - this.type = type; - this.position = { - x: 0, - y: 0, - z: 0 - }; - this.init(); - } - init() { - this.node = this.context.createMediaElementSource(this.element); - this.gain = this.context.createGain(); - this.createConnections(); - this.element.addEventListener('canplay', (event) => { - this.canPlay = true; - if (this.playOnAvailable) { - this.play(); - } - }); - } - play(when = 0, offset = 0, duration = 0) { - if (this.canPlay) { - this.element.play(); - } - this.playOnAvailable = true; - } - stop() { - this.element.pause(); - } - getVolume() { - return this.element.volume; - } - setVolume(value) { - this.element.volume = value; - } - getPlaybackRate() { - return this.element.playbackRate; - } - setPlaybackRate(value) { - this.element.playbackRate = value; - } - createConnections() { - switch (this.type) { - case SourceType.WorldSource: - if (!this.sceneNode) { - this.sceneNode = this.scene.createSource(); - } - this.node.connect(this.gain); - this.gain.connect(this.sceneNode); - break; - default: - this.node.connect(this.gain); - this.graph.connectToMaster(this.gain); - break; - } - } - setPosition(x, y, z) { - this.position = { - x, - y, - z - }; - if (this.sceneNode) - this.sceneNode.setPosition(x, y, z); - } - destroy() { - this.stop(); - this.element = null; - this.graph = null; - this.context = null; - this.node = null; - this.sceneNode = null; - this.scene = null; - } - loop(value) { - this.element.loop = true; - } - fadeIn(time) { - this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime); - if (!this.node) { - this.play(); - } - this.gain.gain.exponentialRampToValueAtTime(this.getVolume(), this.context.getContext().currentTime + time); - } - fadeOut(time) { - this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime); - if (!this.node) { - return; - } - this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time); - setTimeout(() => this.stop(), time * 1000); - } -} +import { SourceType } from './source-type'; +export class StreamingSource { + constructor(graph, scene, context, element, type = SourceType.MasterSource) { + this.graph = graph; + this.scene = scene; + this.context = context; + this.element = element; + this.type = type; + this.position = { + x: 0, + y: 0, + z: 0 + }; + this.init(); + } + init() { + this.node = this.context.createMediaElementSource(this.element); + this.gain = this.context.createGain(); + this.createConnections(); + this.element.addEventListener('canplay', (event) => { + this.canPlay = true; + if (this.playOnAvailable) { + this.play(); + } + }); + } + play(when = 0, offset = 0, duration = 0) { + if (this.canPlay) { + this.element.play(); + } + this.playOnAvailable = true; + } + stop() { + this.element.pause(); + } + getVolume() { + return this.element.volume; + } + setVolume(value) { + this.element.volume = value; + } + getPlaybackRate() { + return this.element.playbackRate; + } + setPlaybackRate(value) { + this.element.playbackRate = value; + } + createConnections() { + switch (this.type) { + case SourceType.WorldSource: + if (!this.sceneNode) { + this.sceneNode = this.scene.createSource(); + } + this.node.connect(this.gain); + this.gain.connect(this.sceneNode); + break; + default: + this.node.connect(this.gain); + this.graph.connectToMaster(this.gain); + break; + } + } + setPosition(x, y, z) { + this.position = { + x, + y, + z + }; + if (this.sceneNode) + this.sceneNode.setPosition(x, y, z); + } + destroy() { + this.stop(); + this.element = null; + this.graph = null; + this.context = null; + this.node = null; + this.sceneNode = null; + this.scene = null; + } + loop(value) { + this.element.loop = true; + } + fadeIn(time) { + this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime); + if (!this.node) { + this.play(); + } + this.gain.gain.exponentialRampToValueAtTime(this.getVolume(), this.context.getContext().currentTime + time); + } + fadeOut(time) { + this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime); + if (!this.node) { + return; + } + this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time); + setTimeout(() => this.stop(), time * 1000); + } +} diff --git a/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts b/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts index e42c1c0..267fdbe 100644 --- a/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/attenuation.d.ts @@ -1,40 +1,40 @@ -export default Attenuation; -/** - * @class Attenuation - * @description Distance-based attenuation filter. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.minDistance - * Min. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. - * @param {Number} options.maxDistance - * Max. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. - * @param {string} options.rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to - * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. - */ -declare class Attenuation { - constructor(context: any, options: any); - minDistance: any; - maxDistance: any; - _gainNode: any; - input: any; - output: any; - /** - * Set distance from the listener. - * @param {Number} distance Distance (in meters). - */ - setDistance(distance: number): void; - /** - * Set rolloff. - * @param {string} rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. - */ - setRolloff(rolloff: string): void; - _rolloff: string; -} +export default Attenuation; +/** + * @class Attenuation + * @description Distance-based attenuation filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @param {Number} options.maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @param {string} options.rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + */ +declare class Attenuation { + constructor(context: any, options: any); + minDistance: any; + maxDistance: any; + _gainNode: any; + input: any; + output: any; + /** + * Set distance from the listener. + * @param {Number} distance Distance (in meters). + */ + setDistance(distance: number): void; + /** + * Set rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff: string): void; + _rolloff: string; +} diff --git a/src/framework/resonator/vendor/resonance-es6/attenuation.js b/src/framework/resonator/vendor/resonance-es6/attenuation.js index abb8584..88f8cbd 100644 --- a/src/framework/resonator/vendor/resonance-es6/attenuation.js +++ b/src/framework/resonator/vendor/resonance-es6/attenuation.js @@ -1,151 +1,151 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Distance-based attenuation filter. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Utils from './utils.js'; -/** - * @class Attenuation - * @description Distance-based attenuation filter. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.minDistance - * Min. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. - * @param {Number} options.maxDistance - * Max. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. - * @param {string} options.rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to - * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. - */ -class Attenuation { - constructor(context, options) { - // Public variables. - /** - * Min. distance (in meters). - * @member {Number} minDistance - * @memberof Attenuation - * @instance - */ - /** - * Max. distance (in meters). - * @member {Number} maxDistance - * @memberof Attenuation - * @instance - */ - /** - * Mono (1-channel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof Attenuation - * @instance - */ - /** - * Mono (1-channel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof Attenuation - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.minDistance == undefined) { - options.minDistance = Utils.DEFAULT_MIN_DISTANCE; - } - if (options.maxDistance == undefined) { - options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; - } - if (options.rolloff == undefined) { - options.rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; - } - // Assign values. - this.minDistance = options.minDistance; - this.maxDistance = options.maxDistance; - this.setRolloff(options.rolloff); - // Create node. - this._gainNode = context.createGain(); - // Initialize distance to max distance. - this.setDistance(options.maxDistance); - // Input/Output proxy. - this.input = this._gainNode; - this.output = this._gainNode; - } - /** - * Set distance from the listener. - * @param {Number} distance Distance (in meters). - */ - setDistance(distance) { - let gain = 1; - if (this._rolloff == 'logarithmic') { - if (distance > this.maxDistance) { - gain = 0; - } - else if (distance > this.minDistance) { - let range = this.maxDistance - this.minDistance; - if (range > Utils.EPSILON_FLOAT) { - // Compute the distance attenuation value by the logarithmic curve - // "1 / (d + 1)" with an offset of |minDistance|. - let relativeDistance = distance - this.minDistance; - let attenuation = 1 / (relativeDistance + 1); - let attenuationMax = 1 / (range + 1); - gain = (attenuation - attenuationMax) / (1 - attenuationMax); - } - } - } - else if (this._rolloff == 'linear') { - if (distance > this.maxDistance) { - gain = 0; - } - else if (distance > this.minDistance) { - let range = this.maxDistance - this.minDistance; - if (range > Utils.EPSILON_FLOAT) { - gain = (this.maxDistance - distance) / range; - } - } - } - this._gainNode.gain.value = gain; - } - /** - * Set rolloff. - * @param {string} rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. - */ - setRolloff(rolloff) { - let isValidModel = ~Utils.ATTENUATION_ROLLOFFS.indexOf(rolloff); - if (rolloff == undefined || !isValidModel) { - if (!isValidModel) { - Utils.log('Invalid rolloff model (\"' + rolloff + - '\"). Using default: \"' + Utils.DEFAULT_ATTENUATION_ROLLOFF + '\".'); - } - rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; - } - else { - rolloff = rolloff.toString().toLowerCase(); - } - this._rolloff = rolloff; - } -} -export default Attenuation; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Distance-based attenuation filter. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class Attenuation + * @description Distance-based attenuation filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @param {Number} options.maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @param {string} options.rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + */ +class Attenuation { + constructor(context, options) { + // Public variables. + /** + * Min. distance (in meters). + * @member {Number} minDistance + * @memberof Attenuation + * @instance + */ + /** + * Max. distance (in meters). + * @member {Number} maxDistance + * @memberof Attenuation + * @instance + */ + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Attenuation + * @instance + */ + /** + * Mono (1-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Attenuation + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.minDistance == undefined) { + options.minDistance = Utils.DEFAULT_MIN_DISTANCE; + } + if (options.maxDistance == undefined) { + options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; + } + if (options.rolloff == undefined) { + options.rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; + } + // Assign values. + this.minDistance = options.minDistance; + this.maxDistance = options.maxDistance; + this.setRolloff(options.rolloff); + // Create node. + this._gainNode = context.createGain(); + // Initialize distance to max distance. + this.setDistance(options.maxDistance); + // Input/Output proxy. + this.input = this._gainNode; + this.output = this._gainNode; + } + /** + * Set distance from the listener. + * @param {Number} distance Distance (in meters). + */ + setDistance(distance) { + let gain = 1; + if (this._rolloff == 'logarithmic') { + if (distance > this.maxDistance) { + gain = 0; + } + else if (distance > this.minDistance) { + let range = this.maxDistance - this.minDistance; + if (range > Utils.EPSILON_FLOAT) { + // Compute the distance attenuation value by the logarithmic curve + // "1 / (d + 1)" with an offset of |minDistance|. + let relativeDistance = distance - this.minDistance; + let attenuation = 1 / (relativeDistance + 1); + let attenuationMax = 1 / (range + 1); + gain = (attenuation - attenuationMax) / (1 - attenuationMax); + } + } + } + else if (this._rolloff == 'linear') { + if (distance > this.maxDistance) { + gain = 0; + } + else if (distance > this.minDistance) { + let range = this.maxDistance - this.minDistance; + if (range > Utils.EPSILON_FLOAT) { + gain = (this.maxDistance - distance) / range; + } + } + } + this._gainNode.gain.value = gain; + } + /** + * Set rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff) { + let isValidModel = ~Utils.ATTENUATION_ROLLOFFS.indexOf(rolloff); + if (rolloff == undefined || !isValidModel) { + if (!isValidModel) { + Utils.log('Invalid rolloff model (\"' + rolloff + + '\"). Using default: \"' + Utils.DEFAULT_ATTENUATION_ROLLOFF + '\".'); + } + rolloff = Utils.DEFAULT_ATTENUATION_ROLLOFF; + } + else { + rolloff = rolloff.toString().toLowerCase(); + } + this._rolloff = rolloff; + } +} +export default Attenuation; diff --git a/src/framework/resonator/vendor/resonance-es6/d.d.ts b/src/framework/resonator/vendor/resonance-es6/d.d.ts index cba0b49..dbe531d 100644 --- a/src/framework/resonator/vendor/resonance-es6/d.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/d.d.ts @@ -1,217 +1,217 @@ -declare module 'resonance-audio' { - namespace ResonanceAudio { - /** Options for constructing a new ResonanceAudio scene */ - interface Options { - /** Desired ambisonic Order */ - ambisonicOrder?: number; - /** The listener's initial position (in meters), where origin is the center of - * the room */ - listenerPosition?: Float32Array; - /** The listener's initial forward vector */ - listenerForward?: Float32Array; - /** The listener's initial up vector */ - listenerUp?: Float32Array; - /** Room dimensions (in meters) */ - dimensions?: Utils.RoomDimensions; - /** Named acoustic materials per wall */ - materials?: Utils.RoomMaterials; - /** (in meters/second) */ - speedOfSound?: number; - } - } - /** Main class for managing sources, room and listener models */ - class ResonanceAudio { - /** Binaurally-rendered stereo (2-channel) output */ - output: AudioNode; - /** Ambisonic (multichannel) input */ - ambisonicInput: AudioNode; - /** Ambisonic (multichannel) output */ - ambisonicOutput: AudioNode; - constructor(context: AudioContext, options?: ResonanceAudio.Options); - /** - * Create a new source for the scene. - * @param options - * Options for constructing a new Source. - */ - createSource(options?: Source.Options): Source; - /** - * Set the scene's desired ambisonic order. - * @param ambisonicOrder Desired ambisonic order. - */ - setAmbisonicOrder(ambisonicOrder: any): void; - /** - * Set the room's dimensions and wall materials. - * @param dimensions Room dimensions (in meters). - * @param materials Named acoustic materials per wall. - */ - setRoomProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void; - /** - * Set the listener's position (in meters), where origin is the center of - * the room. - */ - setListenerPosition(x: number, y: number, z: number): any; - /** Set the source's orientation using forward and up vectors. */ - setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; - /** - * Set the listener's position and orientation using a Three.js Matrix4 object. - * @param matrix - * The Three.js Matrix4 object representing the listener's world transform. - */ - setListenerFromMatrix(matrix4: Float32Array): void; - /** - * Set the speed of sound. - */ - setSpeedOfSound(speedOfSound: number): void; - } - namespace Source { - /** Options for constructing a new Source. */ - interface Options { - /** The source's initial position (in meters), where origin is the center of - * the room */ - position?: Float32Array; - /** The source's initial forward vector */ - forward?: Float32Array; - /** The source's initial up vector */ - up?: Float32Array; - /** Min. distance (in meters) */ - minDistance?: number; - /** Max. distance (in meters) */ - maxDistance?: number; - /** Rolloff model to use */ - rolloff?: string; - /** Input gain (linear) */ - gain?: number; - /** Directivity alpha */ - alpha?: number; - /** Directivity sharpness */ - sharpness?: number; - /** Source width (in degrees). Where 0 degrees is a point source and 360 degrees - * is an omnidirectional source */ - sourceWidth?: number; - } - } - /** - * Source model to spatialize an audio buffer. - */ - class Source { - constructor(scene: ResonanceAudio, options?: Source.Options); - /** Mono (1-channel) input */ - input: AudioNode; - /** - * Set source's position (in meters), where origin is the center of - * the room. - */ - setPosition(x: number, y: number, z: number): void; - /** Set source's rolloff. */ - setRolloff(rolloff: string): void; - /** Set source's minimum distance (in meters). */ - setMinDistance(minDistance: number): void; - /** Set source's maximum distance (in meters). */ - setMaxDistance(maxDistance: number): void; - /** Set source's gain (linear). */ - setGain(gain: number): void; - /** Set the source's orientation using forward and up vectors. */ - setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; - /** Set source's position and orientation using a - * Three.js modelViewMatrix object */ - setFromMatrix(matrix4: Float32Array): void; - /** Set the source width (in degrees). Where 0 degrees is a point source and 360 - * degrees is an omnidirectional source */ - setSourceWidth(sourceWidth: number): void; - /** - * Set source's directivity pattern (defined by alpha), where 0 is an - * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod - * pattern. The sharpness of the pattern is increased exponentially - * @param alpha - * Determines directivity pattern (0 to 1). - * @param sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). - */ - setDirectivityPattern(alpha: number, sharpness: number): void; - } - namespace Room { - interface Options { - /** The listener's initial position (in meters), where origin is the center of - * the room */ - listenerPosition?: Float32Array; - /** Room dimensions (in meters) */ - dimensions?: Utils.RoomDimensions; - /** Named acoustic materials per wall */ - materials?: Utils.RoomMaterials; - /** (in meters/second) */ - speedOfSound?: number; - } - } - /** - * Model that manages early and late reflections using acoustic - * properties and listener position relative to a rectangular room. - */ - class Room { - constructor(context: AudioContext, options?: Room.Options); - /** - * Set the room's dimensions and wall materials. - * @param dimensions Room dimensions (in meters) - * @param materials Named acoustic materials per wall - */ - setProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void; - /** - * Set the listener's position (in meters), where origin is the center of - * the room. - */ - setListenerPosition(x: number, y: number, z: number): void; - /** - * Compute distance outside room of provided position (in meters). - * @return - * Distance outside room (in meters). Returns 0 if inside room. - */ - getDistanceOutsideRoom(x: number, y: number, z: number): number; - } - namespace Listener { - interface Options { - /** Desired ambisonic order */ - ambisonicOrder: number; - /** Initial position (in meters), where origin is the center of - * the room */ - position?: Float32Array; - /** The listener's initial forward vector */ - forward?: Float32Array; - /** The listener's initial up vector */ - up?: Float32Array; - } - } - /** Listener model to spatialize sources in an environment */ - class Listener { - /** Position (in meters) */ - position: Float32Array; - /** Ambisonic (multichannel) input */ - input: AudioNode; - /** Binaurally-rendered stereo (2-channel) output */ - output: AudioNode; - /** Ambisonic (multichannel) output */ - ambisonicOutput: AudioNode; - /** - * Set the listener's orientation using forward and up vectors. - */ - setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; - /** Set listener's position and orientation using a - * Three.js modelViewMatrix object */ - setFromMatrix(matrix4: Float32Array): void; - } - namespace Utils { - /** Properties describing the geometry of a room. */ - interface RoomDimensions { - width: number; - height: number; - depth: number; - } - /** Properties describing the wall materials */ - interface RoomMaterials { - left: string; - right: string; - front: string; - back: string; - down: string; - up: string; - } - } -} +declare module 'resonance-audio' { + namespace ResonanceAudio { + /** Options for constructing a new ResonanceAudio scene */ + interface Options { + /** Desired ambisonic Order */ + ambisonicOrder?: number; + /** The listener's initial position (in meters), where origin is the center of + * the room */ + listenerPosition?: Float32Array; + /** The listener's initial forward vector */ + listenerForward?: Float32Array; + /** The listener's initial up vector */ + listenerUp?: Float32Array; + /** Room dimensions (in meters) */ + dimensions?: Utils.RoomDimensions; + /** Named acoustic materials per wall */ + materials?: Utils.RoomMaterials; + /** (in meters/second) */ + speedOfSound?: number; + } + } + /** Main class for managing sources, room and listener models */ + class ResonanceAudio { + /** Binaurally-rendered stereo (2-channel) output */ + output: AudioNode; + /** Ambisonic (multichannel) input */ + ambisonicInput: AudioNode; + /** Ambisonic (multichannel) output */ + ambisonicOutput: AudioNode; + constructor(context: AudioContext, options?: ResonanceAudio.Options); + /** + * Create a new source for the scene. + * @param options + * Options for constructing a new Source. + */ + createSource(options?: Source.Options): Source; + /** + * Set the scene's desired ambisonic order. + * @param ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder: any): void; + /** + * Set the room's dimensions and wall materials. + * @param dimensions Room dimensions (in meters). + * @param materials Named acoustic materials per wall. + */ + setRoomProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + */ + setListenerPosition(x: number, y: number, z: number): any; + /** Set the source's orientation using forward and up vectors. */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param matrix + * The Three.js Matrix4 object representing the listener's world transform. + */ + setListenerFromMatrix(matrix4: Float32Array): void; + /** + * Set the speed of sound. + */ + setSpeedOfSound(speedOfSound: number): void; + } + namespace Source { + /** Options for constructing a new Source. */ + interface Options { + /** The source's initial position (in meters), where origin is the center of + * the room */ + position?: Float32Array; + /** The source's initial forward vector */ + forward?: Float32Array; + /** The source's initial up vector */ + up?: Float32Array; + /** Min. distance (in meters) */ + minDistance?: number; + /** Max. distance (in meters) */ + maxDistance?: number; + /** Rolloff model to use */ + rolloff?: string; + /** Input gain (linear) */ + gain?: number; + /** Directivity alpha */ + alpha?: number; + /** Directivity sharpness */ + sharpness?: number; + /** Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source */ + sourceWidth?: number; + } + } + /** + * Source model to spatialize an audio buffer. + */ + class Source { + constructor(scene: ResonanceAudio, options?: Source.Options); + /** Mono (1-channel) input */ + input: AudioNode; + /** + * Set source's position (in meters), where origin is the center of + * the room. + */ + setPosition(x: number, y: number, z: number): void; + /** Set source's rolloff. */ + setRolloff(rolloff: string): void; + /** Set source's minimum distance (in meters). */ + setMinDistance(minDistance: number): void; + /** Set source's maximum distance (in meters). */ + setMaxDistance(maxDistance: number): void; + /** Set source's gain (linear). */ + setGain(gain: number): void; + /** Set the source's orientation using forward and up vectors. */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** Set source's position and orientation using a + * Three.js modelViewMatrix object */ + setFromMatrix(matrix4: Float32Array): void; + /** Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source */ + setSourceWidth(sourceWidth: number): void; + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponentially + * @param alpha + * Determines directivity pattern (0 to 1). + * @param sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + */ + setDirectivityPattern(alpha: number, sharpness: number): void; + } + namespace Room { + interface Options { + /** The listener's initial position (in meters), where origin is the center of + * the room */ + listenerPosition?: Float32Array; + /** Room dimensions (in meters) */ + dimensions?: Utils.RoomDimensions; + /** Named acoustic materials per wall */ + materials?: Utils.RoomMaterials; + /** (in meters/second) */ + speedOfSound?: number; + } + } + /** + * Model that manages early and late reflections using acoustic + * properties and listener position relative to a rectangular room. + */ + class Room { + constructor(context: AudioContext, options?: Room.Options); + /** + * Set the room's dimensions and wall materials. + * @param dimensions Room dimensions (in meters) + * @param materials Named acoustic materials per wall + */ + setProperties(dimensions: Utils.RoomDimensions, materials: Utils.RoomMaterials): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Compute distance outside room of provided position (in meters). + * @return + * Distance outside room (in meters). Returns 0 if inside room. + */ + getDistanceOutsideRoom(x: number, y: number, z: number): number; + } + namespace Listener { + interface Options { + /** Desired ambisonic order */ + ambisonicOrder: number; + /** Initial position (in meters), where origin is the center of + * the room */ + position?: Float32Array; + /** The listener's initial forward vector */ + forward?: Float32Array; + /** The listener's initial up vector */ + up?: Float32Array; + } + } + /** Listener model to spatialize sources in an environment */ + class Listener { + /** Position (in meters) */ + position: Float32Array; + /** Ambisonic (multichannel) input */ + input: AudioNode; + /** Binaurally-rendered stereo (2-channel) output */ + output: AudioNode; + /** Ambisonic (multichannel) output */ + ambisonicOutput: AudioNode; + /** + * Set the listener's orientation using forward and up vectors. + */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** Set listener's position and orientation using a + * Three.js modelViewMatrix object */ + setFromMatrix(matrix4: Float32Array): void; + } + namespace Utils { + /** Properties describing the geometry of a room. */ + interface RoomDimensions { + width: number; + height: number; + depth: number; + } + /** Properties describing the wall materials */ + interface RoomMaterials { + left: string; + right: string; + front: string; + back: string; + down: string; + up: string; + } + } +} diff --git a/src/framework/resonator/vendor/resonance-es6/directivity.d.ts b/src/framework/resonator/vendor/resonance-es6/directivity.d.ts index a280dec..5694bf1 100644 --- a/src/framework/resonator/vendor/resonance-es6/directivity.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/directivity.d.ts @@ -1,47 +1,47 @@ -export default Directivity; -/** - * @class Directivity - * @description Directivity/occlusion filter. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.alpha - * Determines directivity pattern (0 to 1). See - * {@link Directivity#setPattern setPattern} for more details. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. - * @param {Number} options.sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). See - * {@link Directivity#setPattern setPattern} for more details. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS - * DEFAULT_DIRECTIVITY_SHARPNESS}. - */ -declare class Directivity { - constructor(context: any, options: any); - _context: any; - _lowpass: any; - _cosTheta: number; - input: any; - output: any; - /** - * Compute the filter using the source's forward orientation and the listener's - * position. - * @param {Float32Array} forward The source's forward vector. - * @param {Float32Array} direction The direction from the source to the - * listener. - */ - computeAngle(forward: Float32Array, direction: Float32Array): void; - /** - * Set source's directivity pattern (defined by alpha), where 0 is an - * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod - * pattern. The sharpness of the pattern is increased exponenentially. - * @param {Number} alpha - * Determines directivity pattern (0 to 1). - * @param {Number} sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). - * DEFAULT_DIRECTIVITY_SHARPNESS}. - */ - setPattern(alpha: number, sharpness: number): void; - _alpha: number; - _sharpness: number; -} +export default Directivity; +/** + * @class Directivity + * @description Directivity/occlusion filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.alpha + * Determines directivity pattern (0 to 1). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @param {Number} options.sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ +declare class Directivity { + constructor(context: any, options: any); + _context: any; + _lowpass: any; + _cosTheta: number; + input: any; + output: any; + /** + * Compute the filter using the source's forward orientation and the listener's + * position. + * @param {Float32Array} forward The source's forward vector. + * @param {Float32Array} direction The direction from the source to the + * listener. + */ + computeAngle(forward: Float32Array, direction: Float32Array): void; + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponenentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ + setPattern(alpha: number, sharpness: number): void; + _alpha: number; + _sharpness: number; +} diff --git a/src/framework/resonator/vendor/resonance-es6/directivity.js b/src/framework/resonator/vendor/resonance-es6/directivity.js index 3a29d74..d465a55 100644 --- a/src/framework/resonator/vendor/resonance-es6/directivity.js +++ b/src/framework/resonator/vendor/resonance-es6/directivity.js @@ -1,117 +1,117 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Directivity/occlusion filter. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Utils from './utils.js'; -/** - * @class Directivity - * @description Directivity/occlusion filter. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.alpha - * Determines directivity pattern (0 to 1). See - * {@link Directivity#setPattern setPattern} for more details. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. - * @param {Number} options.sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). See - * {@link Directivity#setPattern setPattern} for more details. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS - * DEFAULT_DIRECTIVITY_SHARPNESS}. - */ -class Directivity { - constructor(context, options) { - // Public variables. - /** - * Mono (1-channel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof Directivity - * @instance - */ - /** - * Mono (1-channel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof Directivity - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.alpha == undefined) { - options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA; - } - if (options.sharpness == undefined) { - options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS; - } - // Create audio node. - this._context = context; - this._lowpass = context.createBiquadFilter(); - // Initialize filter coefficients. - this._lowpass.type = 'lowpass'; - this._lowpass.Q.value = 0; - this._lowpass.frequency.value = context.sampleRate * 0.5; - this._cosTheta = 0; - this.setPattern(options.alpha, options.sharpness); - // Input/Output proxy. - this.input = this._lowpass; - this.output = this._lowpass; - } - /** - * Compute the filter using the source's forward orientation and the listener's - * position. - * @param {Float32Array} forward The source's forward vector. - * @param {Float32Array} direction The direction from the source to the - * listener. - */ - computeAngle(forward, direction) { - let forwardNorm = Utils.normalizeVector(forward); - let directionNorm = Utils.normalizeVector(direction); - let coeff = 1; - if (this._alpha > Utils.EPSILON_FLOAT) { - let cosTheta = forwardNorm[0] * directionNorm[0] + - forwardNorm[1] * directionNorm[1] + forwardNorm[2] * directionNorm[2]; - coeff = (1 - this._alpha) + this._alpha * cosTheta; - coeff = Math.pow(Math.abs(coeff), this._sharpness); - } - this._lowpass.frequency.value = this._context.sampleRate * 0.5 * coeff; - } - /** - * Set source's directivity pattern (defined by alpha), where 0 is an - * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod - * pattern. The sharpness of the pattern is increased exponenentially. - * @param {Number} alpha - * Determines directivity pattern (0 to 1). - * @param {Number} sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). - * DEFAULT_DIRECTIVITY_SHARPNESS}. - */ - setPattern(alpha, sharpness) { - // Clamp and set values. - this._alpha = Math.min(1, Math.max(0, alpha)); - this._sharpness = Math.max(1, sharpness); - // Update angle calculation using new values. - this.computeAngle([this._cosTheta * this._cosTheta, 0, 0], [1, 0, 0]); - } -} -export default Directivity; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Directivity/occlusion filter. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class Directivity + * @description Directivity/occlusion filter. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.alpha + * Determines directivity pattern (0 to 1). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @param {Number} options.sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). See + * {@link Directivity#setPattern setPattern} for more details. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ +class Directivity { + constructor(context, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Directivity + * @instance + */ + /** + * Mono (1-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Directivity + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.alpha == undefined) { + options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA; + } + if (options.sharpness == undefined) { + options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS; + } + // Create audio node. + this._context = context; + this._lowpass = context.createBiquadFilter(); + // Initialize filter coefficients. + this._lowpass.type = 'lowpass'; + this._lowpass.Q.value = 0; + this._lowpass.frequency.value = context.sampleRate * 0.5; + this._cosTheta = 0; + this.setPattern(options.alpha, options.sharpness); + // Input/Output proxy. + this.input = this._lowpass; + this.output = this._lowpass; + } + /** + * Compute the filter using the source's forward orientation and the listener's + * position. + * @param {Float32Array} forward The source's forward vector. + * @param {Float32Array} direction The direction from the source to the + * listener. + */ + computeAngle(forward, direction) { + let forwardNorm = Utils.normalizeVector(forward); + let directionNorm = Utils.normalizeVector(direction); + let coeff = 1; + if (this._alpha > Utils.EPSILON_FLOAT) { + let cosTheta = forwardNorm[0] * directionNorm[0] + + forwardNorm[1] * directionNorm[1] + forwardNorm[2] * directionNorm[2]; + coeff = (1 - this._alpha) + this._alpha * cosTheta; + coeff = Math.pow(Math.abs(coeff), this._sharpness); + } + this._lowpass.frequency.value = this._context.sampleRate * 0.5 * coeff; + } + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponenentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ + setPattern(alpha, sharpness) { + // Clamp and set values. + this._alpha = Math.min(1, Math.max(0, alpha)); + this._sharpness = Math.max(1, sharpness); + // Update angle calculation using new values. + this.computeAngle([this._cosTheta * this._cosTheta, 0, 0], [1, 0, 0]); + } +} +export default Directivity; diff --git a/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts b/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts index 847009d..5dd2570 100644 --- a/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/early-reflections.d.ts @@ -1,56 +1,56 @@ -export default EarlyReflections; -/** - * @class EarlyReflections - * @description Ray-tracing-based early reflections model. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Utils~RoomDimensions} options.dimensions - * Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Object} options.coefficients - * Frequency-independent reflection coeffs per wall. Defaults to - * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS - * DEFAULT_REFLECTION_COEFFICIENTS}. - * @param {Number} options.speedOfSound - * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND - * DEFAULT_SPEED_OF_SOUND}. - * @param {Float32Array} options.listenerPosition - * (in meters). Defaults to - * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - */ -declare class EarlyReflections { - constructor(context: any, options: any); - speedOfSound: any; - input: any; - output: any; - _lowpass: any; - _delays: {}; - _gains: {}; - _inverters: {}; - _merger: any; - _listenerPosition: any; - /** - * Set the listener's position (in meters), - * where [0,0,0] is the center of the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setListenerPosition(x: number, y: number, z: number): void; - /** - * Set the room's properties which determines the characteristics of - * reflections. - * @param {Utils~RoomDimensions} dimensions - * Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Object} coefficients - * Frequency-independent reflection coeffs per wall. Defaults to - * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS - * DEFAULT_REFLECTION_COEFFICIENTS}. - */ - setRoomProperties(dimensions: any, coefficients: any): void; - _coefficients: any; - _halfDimensions: {}; -} +export default EarlyReflections; +/** + * @class EarlyReflections + * @description Ray-tracing-based early reflections model. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Utils~RoomDimensions} options.dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} options.coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + * @param {Number} options.speedOfSound + * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND + * DEFAULT_SPEED_OF_SOUND}. + * @param {Float32Array} options.listenerPosition + * (in meters). Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ +declare class EarlyReflections { + constructor(context: any, options: any); + speedOfSound: any; + input: any; + output: any; + _lowpass: any; + _delays: {}; + _gains: {}; + _inverters: {}; + _merger: any; + _listenerPosition: any; + /** + * Set the listener's position (in meters), + * where [0,0,0] is the center of the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Set the room's properties which determines the characteristics of + * reflections. + * @param {Utils~RoomDimensions} dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + */ + setRoomProperties(dimensions: any, coefficients: any): void; + _coefficients: any; + _halfDimensions: {}; +} diff --git a/src/framework/resonator/vendor/resonance-es6/early-reflections.js b/src/framework/resonator/vendor/resonance-es6/early-reflections.js index c3c2919..073942d 100644 --- a/src/framework/resonator/vendor/resonance-es6/early-reflections.js +++ b/src/framework/resonator/vendor/resonance-es6/early-reflections.js @@ -1,212 +1,212 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Ray-tracing-based early reflections model. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Utils from './utils.js'; -/** - * @class EarlyReflections - * @description Ray-tracing-based early reflections model. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Utils~RoomDimensions} options.dimensions - * Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Object} options.coefficients - * Frequency-independent reflection coeffs per wall. Defaults to - * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS - * DEFAULT_REFLECTION_COEFFICIENTS}. - * @param {Number} options.speedOfSound - * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND - * DEFAULT_SPEED_OF_SOUND}. - * @param {Float32Array} options.listenerPosition - * (in meters). Defaults to - * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - */ -class EarlyReflections { - constructor(context, options) { - // Public variables. - /** - * The room's speed of sound (in meters/second). - * @member {Number} speedOfSound - * @memberof EarlyReflections - * @instance - */ - /** - * Mono (1-channel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof EarlyReflections - * @instance - */ - /** - * First-order ambisonic (4-channel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof EarlyReflections - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.speedOfSound == undefined) { - options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; - } - if (options.listenerPosition == undefined) { - options.listenerPosition = Utils.DEFAULT_POSITION.slice(); - } - if (options.coefficients == undefined) { - options.coefficients = {}; - Object.assign(options.coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS); - } - // Assign room's speed of sound. - this.speedOfSound = options.speedOfSound; - // Create nodes. - this.input = context.createGain(); - this.output = context.createGain(); - this._lowpass = context.createBiquadFilter(); - this._delays = {}; - this._gains = {}; // gainPerWall = (ReflectionCoeff / Attenuation) - this._inverters = {}; // 3 of these are needed for right/back/down walls. - this._merger = context.createChannelMerger(4); // First-order encoding only. - // Connect audio graph for each wall reflection. - for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { - if (Utils.DEFAULT_REFLECTION_COEFFICIENTS - .hasOwnProperty(property)) { - this._delays[property] = - context.createDelay(Utils.MAX_DURATION); - this._gains[property] = context.createGain(); - } - } - this._inverters.right = context.createGain(); - this._inverters.down = context.createGain(); - this._inverters.back = context.createGain(); - // Initialize lowpass filter. - this._lowpass.type = 'lowpass'; - this._lowpass.frequency.value = Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY; - this._lowpass.Q.value = 0; - // Initialize encoder directions, set delay times and gains to 0. - for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { - if (Utils.DEFAULT_REFLECTION_COEFFICIENTS - .hasOwnProperty(property)) { - this._delays[property].delayTime.value = 0; - this._gains[property].gain.value = 0; - } - } - // Initialize inverters for opposite walls ('right', 'down', 'back' only). - this._inverters.right.gain.value = -1; - this._inverters.down.gain.value = -1; - this._inverters.back.gain.value = -1; - // Connect nodes. - this.input.connect(this._lowpass); - for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { - if (Utils.DEFAULT_REFLECTION_COEFFICIENTS - .hasOwnProperty(property)) { - this._lowpass.connect(this._delays[property]); - this._delays[property].connect(this._gains[property]); - this._gains[property].connect(this._merger, 0, 0); - } - } - // Connect gains to ambisonic channel output. - // Left: [1 1 0 0] - // Right: [1 -1 0 0] - // Up: [1 0 1 0] - // Down: [1 0 -1 0] - // Front: [1 0 0 1] - // Back: [1 0 0 -1] - this._gains.left.connect(this._merger, 0, 1); - this._gains.right.connect(this._inverters.right); - this._inverters.right.connect(this._merger, 0, 1); - this._gains.up.connect(this._merger, 0, 2); - this._gains.down.connect(this._inverters.down); - this._inverters.down.connect(this._merger, 0, 2); - this._gains.front.connect(this._merger, 0, 3); - this._gains.back.connect(this._inverters.back); - this._inverters.back.connect(this._merger, 0, 3); - this._merger.connect(this.output); - // Initialize. - this._listenerPosition = options.listenerPosition; - this.setRoomProperties(options.dimensions, options.coefficients); - } - /** - * Set the listener's position (in meters), - * where [0,0,0] is the center of the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setListenerPosition(x, y, z) { - // Assign listener position. - this._listenerPosition = [x, y, z]; - // Determine distances to each wall. - let distances = { - left: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width + x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, - right: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width - x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, - front: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth + z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, - back: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth - z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, - down: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height + y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, - up: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height - y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, - }; - // Assign delay & attenuation values using distances. - for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { - if (Utils.DEFAULT_REFLECTION_COEFFICIENTS - .hasOwnProperty(property)) { - // Compute and assign delay (in seconds). - let delayInSecs = distances[property] / this.speedOfSound; - this._delays[property].delayTime.value = delayInSecs; - // Compute and assign gain, uses logarithmic rolloff: "g = R / (d + 1)" - let attenuation = this._coefficients[property] / distances[property]; - this._gains[property].gain.value = attenuation; - } - } - } - /** - * Set the room's properties which determines the characteristics of - * reflections. - * @param {Utils~RoomDimensions} dimensions - * Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Object} coefficients - * Frequency-independent reflection coeffs per wall. Defaults to - * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS - * DEFAULT_REFLECTION_COEFFICIENTS}. - */ - setRoomProperties(dimensions, coefficients) { - if (dimensions == undefined) { - dimensions = {}; - Object.assign(dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); - } - if (coefficients == undefined) { - coefficients = {}; - Object.assign(coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS); - } - this._coefficients = coefficients; - // Sanitize dimensions and store half-dimensions. - this._halfDimensions = {}; - this._halfDimensions.width = dimensions.width * 0.5; - this._halfDimensions.height = dimensions.height * 0.5; - this._halfDimensions.depth = dimensions.depth * 0.5; - // Update listener position with new room properties. - this.setListenerPosition(this._listenerPosition[0], this._listenerPosition[1], this._listenerPosition[2]); - } -} -export default EarlyReflections; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Ray-tracing-based early reflections model. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class EarlyReflections + * @description Ray-tracing-based early reflections model. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Utils~RoomDimensions} options.dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} options.coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + * @param {Number} options.speedOfSound + * (in meters / second). Defaults to {@linkcode Utils.DEFAULT_SPEED_OF_SOUND + * DEFAULT_SPEED_OF_SOUND}. + * @param {Float32Array} options.listenerPosition + * (in meters). Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ +class EarlyReflections { + constructor(context, options) { + // Public variables. + /** + * The room's speed of sound (in meters/second). + * @member {Number} speedOfSound + * @memberof EarlyReflections + * @instance + */ + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof EarlyReflections + * @instance + */ + /** + * First-order ambisonic (4-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof EarlyReflections + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.speedOfSound == undefined) { + options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + if (options.listenerPosition == undefined) { + options.listenerPosition = Utils.DEFAULT_POSITION.slice(); + } + if (options.coefficients == undefined) { + options.coefficients = {}; + Object.assign(options.coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS); + } + // Assign room's speed of sound. + this.speedOfSound = options.speedOfSound; + // Create nodes. + this.input = context.createGain(); + this.output = context.createGain(); + this._lowpass = context.createBiquadFilter(); + this._delays = {}; + this._gains = {}; // gainPerWall = (ReflectionCoeff / Attenuation) + this._inverters = {}; // 3 of these are needed for right/back/down walls. + this._merger = context.createChannelMerger(4); // First-order encoding only. + // Connect audio graph for each wall reflection. + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + this._delays[property] = + context.createDelay(Utils.MAX_DURATION); + this._gains[property] = context.createGain(); + } + } + this._inverters.right = context.createGain(); + this._inverters.down = context.createGain(); + this._inverters.back = context.createGain(); + // Initialize lowpass filter. + this._lowpass.type = 'lowpass'; + this._lowpass.frequency.value = Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY; + this._lowpass.Q.value = 0; + // Initialize encoder directions, set delay times and gains to 0. + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + this._delays[property].delayTime.value = 0; + this._gains[property].gain.value = 0; + } + } + // Initialize inverters for opposite walls ('right', 'down', 'back' only). + this._inverters.right.gain.value = -1; + this._inverters.down.gain.value = -1; + this._inverters.back.gain.value = -1; + // Connect nodes. + this.input.connect(this._lowpass); + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + this._lowpass.connect(this._delays[property]); + this._delays[property].connect(this._gains[property]); + this._gains[property].connect(this._merger, 0, 0); + } + } + // Connect gains to ambisonic channel output. + // Left: [1 1 0 0] + // Right: [1 -1 0 0] + // Up: [1 0 1 0] + // Down: [1 0 -1 0] + // Front: [1 0 0 1] + // Back: [1 0 0 -1] + this._gains.left.connect(this._merger, 0, 1); + this._gains.right.connect(this._inverters.right); + this._inverters.right.connect(this._merger, 0, 1); + this._gains.up.connect(this._merger, 0, 2); + this._gains.down.connect(this._inverters.down); + this._inverters.down.connect(this._merger, 0, 2); + this._gains.front.connect(this._merger, 0, 3); + this._gains.back.connect(this._inverters.back); + this._inverters.back.connect(this._merger, 0, 3); + this._merger.connect(this.output); + // Initialize. + this._listenerPosition = options.listenerPosition; + this.setRoomProperties(options.dimensions, options.coefficients); + } + /** + * Set the listener's position (in meters), + * where [0,0,0] is the center of the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x, y, z) { + // Assign listener position. + this._listenerPosition = [x, y, z]; + // Determine distances to each wall. + let distances = { + left: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width + x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + right: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.width - x) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + front: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth + z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + back: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.depth - z) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + down: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height + y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + up: Utils.DEFAULT_REFLECTION_MULTIPLIER * Math.max(0, this._halfDimensions.height - y) + Utils.DEFAULT_REFLECTION_MIN_DISTANCE, + }; + // Assign delay & attenuation values using distances. + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + // Compute and assign delay (in seconds). + let delayInSecs = distances[property] / this.speedOfSound; + this._delays[property].delayTime.value = delayInSecs; + // Compute and assign gain, uses logarithmic rolloff: "g = R / (d + 1)" + let attenuation = this._coefficients[property] / distances[property]; + this._gains[property].gain.value = attenuation; + } + } + } + /** + * Set the room's properties which determines the characteristics of + * reflections. + * @param {Utils~RoomDimensions} dimensions + * Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Object} coefficients + * Frequency-independent reflection coeffs per wall. Defaults to + * {@linkcode Utils.DEFAULT_REFLECTION_COEFFICIENTS + * DEFAULT_REFLECTION_COEFFICIENTS}. + */ + setRoomProperties(dimensions, coefficients) { + if (dimensions == undefined) { + dimensions = {}; + Object.assign(dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); + } + if (coefficients == undefined) { + coefficients = {}; + Object.assign(coefficients, Utils.DEFAULT_REFLECTION_COEFFICIENTS); + } + this._coefficients = coefficients; + // Sanitize dimensions and store half-dimensions. + this._halfDimensions = {}; + this._halfDimensions.width = dimensions.width * 0.5; + this._halfDimensions.height = dimensions.height * 0.5; + this._halfDimensions.depth = dimensions.depth * 0.5; + // Update listener position with new room properties. + this.setListenerPosition(this._listenerPosition[0], this._listenerPosition[1], this._listenerPosition[2]); + } +} +export default EarlyReflections; diff --git a/src/framework/resonator/vendor/resonance-es6/encoder.d.ts b/src/framework/resonator/vendor/resonance-es6/encoder.d.ts index 059f638..7722a6b 100644 --- a/src/framework/resonator/vendor/resonance-es6/encoder.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/encoder.d.ts @@ -1,64 +1,64 @@ -export default Encoder; -/** - * @class Encoder - * @description Spatially encodes input using weighted spherical harmonics. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.ambisonicOrder - * Desired ambisonic order. Defaults to - * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - * @param {Number} options.azimuth - * Azimuth (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. - * @param {Number} options.elevation - * Elevation (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. - * @param {Number} options.sourceWidth - * Source width (in degrees). Where 0 degrees is a point source and 360 degrees - * is an omnidirectional source. Defaults to - * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. - */ -declare class Encoder { - constructor(context: any, options: any); - _context: any; - input: any; - _channelGain: any[]; - _merger: any; - output: any; - _azimuth: any; - _elevation: any; - /** - * Set the desired ambisonic order. - * @param {Number} ambisonicOrder Desired ambisonic order. - */ - setAmbisonicOrder(ambisonicOrder: number): void; - _ambisonicOrder: number; - /** - * Set the direction of the encoded source signal. - * @param {Number} azimuth - * Azimuth (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. - * @param {Number} elevation - * Elevation (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. - */ - setDirection(azimuth: number, elevation: number): void; - /** - * Set the source width (in degrees). Where 0 degrees is a point source and 360 - * degrees is an omnidirectional source. - * @param {Number} sourceWidth (in degrees). - */ - setSourceWidth(sourceWidth: number): void; - _spreadIndex: number; -} -declare namespace Encoder { - /** - * Validate the provided ambisonic order. - * @param {Number} ambisonicOrder Desired ambisonic order. - * @return {Number} Validated/adjusted ambisonic order. - * @private - */ - function validateAmbisonicOrder(ambisonicOrder: number): number; -} +export default Encoder; +/** + * @class Encoder + * @description Spatially encodes input using weighted spherical harmonics. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Number} options.azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} options.elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + * @param {Number} options.sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +declare class Encoder { + constructor(context: any, options: any); + _context: any; + input: any; + _channelGain: any[]; + _merger: any; + output: any; + _azimuth: any; + _elevation: any; + /** + * Set the desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder: number): void; + _ambisonicOrder: number; + /** + * Set the direction of the encoded source signal. + * @param {Number} azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + */ + setDirection(azimuth: number, elevation: number): void; + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth: number): void; + _spreadIndex: number; +} +declare namespace Encoder { + /** + * Validate the provided ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + * @return {Number} Validated/adjusted ambisonic order. + * @private + */ + function validateAmbisonicOrder(ambisonicOrder: number): number; +} diff --git a/src/framework/resonator/vendor/resonance-es6/encoder.js b/src/framework/resonator/vendor/resonance-es6/encoder.js index 2fdaf3d..0d57e04 100644 --- a/src/framework/resonator/vendor/resonance-es6/encoder.js +++ b/src/framework/resonator/vendor/resonance-es6/encoder.js @@ -1,194 +1,194 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Spatially encodes input using weighted spherical harmonics. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Tables from './tables.js'; -import Utils from './utils.js'; -/** - * @class Encoder - * @description Spatially encodes input using weighted spherical harmonics. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.ambisonicOrder - * Desired ambisonic order. Defaults to - * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - * @param {Number} options.azimuth - * Azimuth (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. - * @param {Number} options.elevation - * Elevation (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. - * @param {Number} options.sourceWidth - * Source width (in degrees). Where 0 degrees is a point source and 360 degrees - * is an omnidirectional source. Defaults to - * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. - */ -class Encoder { - constructor(context, options) { - // Public variables. - /** - * Mono (1-channel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof Encoder - * @instance - */ - /** - * Ambisonic (multichannel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof Encoder - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.ambisonicOrder == undefined) { - options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; - } - if (options.azimuth == undefined) { - options.azimuth = Utils.DEFAULT_AZIMUTH; - } - if (options.elevation == undefined) { - options.elevation = Utils.DEFAULT_ELEVATION; - } - if (options.sourceWidth == undefined) { - options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH; - } - this._context = context; - // Create I/O nodes. - this.input = context.createGain(); - this._channelGain = []; - this._merger = undefined; - this.output = context.createGain(); - // Set initial order, angle and source width. - this.setAmbisonicOrder(options.ambisonicOrder); - this._azimuth = options.azimuth; - this._elevation = options.elevation; - this.setSourceWidth(options.sourceWidth); - } - /** - * Set the desired ambisonic order. - * @param {Number} ambisonicOrder Desired ambisonic order. - */ - setAmbisonicOrder(ambisonicOrder) { - this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder); - this.input.disconnect(); - for (let i = 0; i < this._channelGain.length; i++) { - this._channelGain[i].disconnect(); - } - if (this._merger != undefined) { - this._merger.disconnect(); - } - delete this._channelGain; - delete this._merger; - // Create audio graph. - let numChannels = (this._ambisonicOrder + 1) * (this._ambisonicOrder + 1); - this._merger = this._context.createChannelMerger(numChannels); - this._channelGain = new Array(numChannels); - for (let i = 0; i < numChannels; i++) { - this._channelGain[i] = this._context.createGain(); - this.input.connect(this._channelGain[i]); - this._channelGain[i].connect(this._merger, 0, i); - } - this._merger.connect(this.output); - } - /** - * Set the direction of the encoded source signal. - * @param {Number} azimuth - * Azimuth (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. - * @param {Number} elevation - * Elevation (in degrees). Defaults to - * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. - */ - setDirection(azimuth, elevation) { - // Format input direction to nearest indices. - if (azimuth == undefined || isNaN(azimuth)) { - azimuth = Utils.DEFAULT_AZIMUTH; - } - if (elevation == undefined || isNaN(elevation)) { - elevation = Utils.DEFAULT_ELEVATION; - } - // Store the formatted input (for updating source width). - this._azimuth = azimuth; - this._elevation = elevation; - // Format direction for index lookups. - azimuth = Math.round(azimuth % 360); - if (azimuth < 0) { - azimuth += 360; - } - elevation = Math.round(Math.min(90, Math.max(-90, elevation))) + 90; - // Assign gains to each output. - this._channelGain[0].gain.value = Tables.MAX_RE_WEIGHTS[this._spreadIndex][0]; - for (let i = 1; i <= this._ambisonicOrder; i++) { - let degreeWeight = Tables.MAX_RE_WEIGHTS[this._spreadIndex][i]; - for (let j = -i; j <= i; j++) { - let acnChannel = (i * i) + i + j; - let elevationIndex = i * (i + 1) / 2 + Math.abs(j) - 1; - let val = Tables.SPHERICAL_HARMONICS[1][elevation][elevationIndex]; - if (j != 0) { - let azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j - 1; - if (j < 0) { - azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j; - } - val *= Tables.SPHERICAL_HARMONICS[0][azimuth][azimuthIndex]; - } - this._channelGain[acnChannel].gain.value = val * degreeWeight; - } - } - } - /** - * Set the source width (in degrees). Where 0 degrees is a point source and 360 - * degrees is an omnidirectional source. - * @param {Number} sourceWidth (in degrees). - */ - setSourceWidth(sourceWidth) { - // The MAX_RE_WEIGHTS is a 360 x (Tables.SPHERICAL_HARMONICS_MAX_ORDER+1) - // size table. - this._spreadIndex = Math.min(359, Math.max(0, Math.round(sourceWidth))); - this.setDirection(this._azimuth, this._elevation); - } -} -/** - * Validate the provided ambisonic order. - * @param {Number} ambisonicOrder Desired ambisonic order. - * @return {Number} Validated/adjusted ambisonic order. - * @private - */ -Encoder.validateAmbisonicOrder = ambisonicOrder => { - if (isNaN(ambisonicOrder) || ambisonicOrder == undefined) { - Utils.log('Error: Invalid ambisonic order', options.ambisonicOrder, '\nUsing ambisonicOrder=1 instead.'); - ambisonicOrder = 1; - } - else if (ambisonicOrder < 1) { - Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Min order is 1)', '\nUsing min order instead.'); - ambisonicOrder = 1; - } - else if (ambisonicOrder > Tables.SPHERICAL_HARMONICS_MAX_ORDER) { - Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Max order is', Tables.SPHERICAL_HARMONICS_MAX_ORDER, ')\nUsing max order instead.'); - options.ambisonicOrder = Tables.SPHERICAL_HARMONICS_MAX_ORDER; - } - return ambisonicOrder; -}; -export default Encoder; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Spatially encodes input using weighted spherical harmonics. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Tables from './tables.js'; +import Utils from './utils.js'; +/** + * @class Encoder + * @description Spatially encodes input using weighted spherical harmonics. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Number} options.azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} options.elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + * @param {Number} options.sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +class Encoder { + constructor(context, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Encoder + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Encoder + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.ambisonicOrder == undefined) { + options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; + } + if (options.azimuth == undefined) { + options.azimuth = Utils.DEFAULT_AZIMUTH; + } + if (options.elevation == undefined) { + options.elevation = Utils.DEFAULT_ELEVATION; + } + if (options.sourceWidth == undefined) { + options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH; + } + this._context = context; + // Create I/O nodes. + this.input = context.createGain(); + this._channelGain = []; + this._merger = undefined; + this.output = context.createGain(); + // Set initial order, angle and source width. + this.setAmbisonicOrder(options.ambisonicOrder); + this._azimuth = options.azimuth; + this._elevation = options.elevation; + this.setSourceWidth(options.sourceWidth); + } + /** + * Set the desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder) { + this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder); + this.input.disconnect(); + for (let i = 0; i < this._channelGain.length; i++) { + this._channelGain[i].disconnect(); + } + if (this._merger != undefined) { + this._merger.disconnect(); + } + delete this._channelGain; + delete this._merger; + // Create audio graph. + let numChannels = (this._ambisonicOrder + 1) * (this._ambisonicOrder + 1); + this._merger = this._context.createChannelMerger(numChannels); + this._channelGain = new Array(numChannels); + for (let i = 0; i < numChannels; i++) { + this._channelGain[i] = this._context.createGain(); + this.input.connect(this._channelGain[i]); + this._channelGain[i].connect(this._merger, 0, i); + } + this._merger.connect(this.output); + } + /** + * Set the direction of the encoded source signal. + * @param {Number} azimuth + * Azimuth (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_AZIMUTH DEFAULT_AZIMUTH}. + * @param {Number} elevation + * Elevation (in degrees). Defaults to + * {@linkcode Utils.DEFAULT_ELEVATION DEFAULT_ELEVATION}. + */ + setDirection(azimuth, elevation) { + // Format input direction to nearest indices. + if (azimuth == undefined || isNaN(azimuth)) { + azimuth = Utils.DEFAULT_AZIMUTH; + } + if (elevation == undefined || isNaN(elevation)) { + elevation = Utils.DEFAULT_ELEVATION; + } + // Store the formatted input (for updating source width). + this._azimuth = azimuth; + this._elevation = elevation; + // Format direction for index lookups. + azimuth = Math.round(azimuth % 360); + if (azimuth < 0) { + azimuth += 360; + } + elevation = Math.round(Math.min(90, Math.max(-90, elevation))) + 90; + // Assign gains to each output. + this._channelGain[0].gain.value = Tables.MAX_RE_WEIGHTS[this._spreadIndex][0]; + for (let i = 1; i <= this._ambisonicOrder; i++) { + let degreeWeight = Tables.MAX_RE_WEIGHTS[this._spreadIndex][i]; + for (let j = -i; j <= i; j++) { + let acnChannel = (i * i) + i + j; + let elevationIndex = i * (i + 1) / 2 + Math.abs(j) - 1; + let val = Tables.SPHERICAL_HARMONICS[1][elevation][elevationIndex]; + if (j != 0) { + let azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j - 1; + if (j < 0) { + azimuthIndex = Tables.SPHERICAL_HARMONICS_MAX_ORDER + j; + } + val *= Tables.SPHERICAL_HARMONICS[0][azimuth][azimuthIndex]; + } + this._channelGain[acnChannel].gain.value = val * degreeWeight; + } + } + } + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth) { + // The MAX_RE_WEIGHTS is a 360 x (Tables.SPHERICAL_HARMONICS_MAX_ORDER+1) + // size table. + this._spreadIndex = Math.min(359, Math.max(0, Math.round(sourceWidth))); + this.setDirection(this._azimuth, this._elevation); + } +} +/** + * Validate the provided ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + * @return {Number} Validated/adjusted ambisonic order. + * @private + */ +Encoder.validateAmbisonicOrder = ambisonicOrder => { + if (isNaN(ambisonicOrder) || ambisonicOrder == undefined) { + Utils.log('Error: Invalid ambisonic order', options.ambisonicOrder, '\nUsing ambisonicOrder=1 instead.'); + ambisonicOrder = 1; + } + else if (ambisonicOrder < 1) { + Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Min order is 1)', '\nUsing min order instead.'); + ambisonicOrder = 1; + } + else if (ambisonicOrder > Tables.SPHERICAL_HARMONICS_MAX_ORDER) { + Utils.log('Error: Unable to render ambisonic order', options.ambisonicOrder, '(Max order is', Tables.SPHERICAL_HARMONICS_MAX_ORDER, ')\nUsing max order instead.'); + options.ambisonicOrder = Tables.SPHERICAL_HARMONICS_MAX_ORDER; + } + return ambisonicOrder; +}; +export default Encoder; diff --git a/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts b/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts index e91ca38..95b2353 100644 --- a/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/late-reflections.d.ts @@ -1,42 +1,42 @@ -export default LateReflections; -/** - * @class LateReflections - * @description Late-reflections reverberation filter for Ambisonic content. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Array} options.durations - * Multiband RT60 durations (in seconds) for each frequency band, listed as - * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS - * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to - * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}. - * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to - * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}. - * @param {Number} options.gain Output gain (linear). Defaults to - * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}. - * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency - * band. Defaults to - * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}. - * @param {Number} options.tailonset Length (in milliseconds) of impulse - * response to apply a half-Hann window. Defaults to - * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}. - */ -declare class LateReflections { - constructor(context: any, options: any); - _bandwidthCoeff: number; - _tailonsetSamples: number; - _context: any; - input: any; - _predelay: any; - _convolver: any; - output: any; - /** - * Re-compute a new impulse response by providing Multiband RT60 durations. - * @param {Array} durations - * Multiband RT60 durations (in seconds) for each frequency band, listed as - * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS - * DEFAULT_REVERB_FREQUENCY_BANDS}. - */ - setDurations(durations: any[]): void; -} +export default LateReflections; +/** + * @class LateReflections + * @description Late-reflections reverberation filter for Ambisonic content. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Array} options.durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}. + * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}. + * @param {Number} options.gain Output gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}. + * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency + * band. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}. + * @param {Number} options.tailonset Length (in milliseconds) of impulse + * response to apply a half-Hann window. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}. + */ +declare class LateReflections { + constructor(context: any, options: any); + _bandwidthCoeff: number; + _tailonsetSamples: number; + _context: any; + input: any; + _predelay: any; + _convolver: any; + output: any; + /** + * Re-compute a new impulse response by providing Multiband RT60 durations. + * @param {Array} durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * DEFAULT_REVERB_FREQUENCY_BANDS}. + */ + setDurations(durations: any[]): void; +} diff --git a/src/framework/resonator/vendor/resonance-es6/late-reflections.js b/src/framework/resonator/vendor/resonance-es6/late-reflections.js index 3ed0d00..5ab6bac 100644 --- a/src/framework/resonator/vendor/resonance-es6/late-reflections.js +++ b/src/framework/resonator/vendor/resonance-es6/late-reflections.js @@ -1,187 +1,187 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Late reverberation filter for Ambisonic content. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Utils from './utils.js'; -/** - * @class LateReflections - * @description Late-reflections reverberation filter for Ambisonic content. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Array} options.durations - * Multiband RT60 durations (in seconds) for each frequency band, listed as - * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS - * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to - * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}. - * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to - * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}. - * @param {Number} options.gain Output gain (linear). Defaults to - * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}. - * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency - * band. Defaults to - * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}. - * @param {Number} options.tailonset Length (in milliseconds) of impulse - * response to apply a half-Hann window. Defaults to - * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}. - */ -class LateReflections { - constructor(context, options) { - // Public variables. - /** - * Mono (1-channel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof LateReflections - * @instance - */ - /** - * Mono (1-channel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof LateReflections - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.durations == undefined) { - options.durations = Utils.DEFAULT_REVERB_DURATIONS.slice(); - } - if (options.predelay == undefined) { - options.predelay = Utils.DEFAULT_REVERB_PREDELAY; - } - if (options.gain == undefined) { - options.gain = Utils.DEFAULT_REVERB_GAIN; - } - if (options.bandwidth == undefined) { - options.bandwidth = Utils.DEFAULT_REVERB_BANDWIDTH; - } - if (options.tailonset == undefined) { - options.tailonset = Utils.DEFAULT_REVERB_TAIL_ONSET; - } - // Assign pre-computed variables. - let delaySecs = options.predelay / 1000; - this._bandwidthCoeff = options.bandwidth * Utils.LOG2_DIV2; - this._tailonsetSamples = options.tailonset / 1000; - // Create nodes. - this._context = context; - this.input = context.createGain(); - this._predelay = context.createDelay(delaySecs); - this._convolver = context.createConvolver(); - this.output = context.createGain(); - // Set reverb attenuation. - this.output.gain.value = options.gain; - // Disable normalization. - this._convolver.normalize = false; - // Connect nodes. - this.input.connect(this._predelay); - this._predelay.connect(this._convolver); - this._convolver.connect(this.output); - // Compute IR using RT60 values. - this.setDurations(options.durations); - } - /** - * Re-compute a new impulse response by providing Multiband RT60 durations. - * @param {Array} durations - * Multiband RT60 durations (in seconds) for each frequency band, listed as - * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS - * DEFAULT_REVERB_FREQUENCY_BANDS}. - */ - setDurations(durations) { - if (durations.length !== Utils.NUMBER_REVERB_FREQUENCY_BANDS) { - Utils.log('Warning: invalid number of RT60 values provided to reverb.'); - return; - } - // Compute impulse response. - let durationsSamples = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); - let sampleRate = this._context.sampleRate; - for (let i = 0; i < durations.length; i++) { - // Clamp within suitable range. - durations[i] = - Math.max(0, Math.min(Utils.DEFAULT_REVERB_MAX_DURATION, durations[i])); - // Convert seconds to samples. - durationsSamples[i] = Math.round(durations[i] * sampleRate * - Utils.DEFAULT_REVERB_DURATION_MULTIPLIER); - } - ; - // Determine max RT60 length in samples. - let durationsSamplesMax = 0; - for (let i = 0; i < durationsSamples.length; i++) { - if (durationsSamples[i] > durationsSamplesMax) { - durationsSamplesMax = durationsSamples[i]; - } - } - // Skip this step if there is no reverberation to compute. - if (durationsSamplesMax < 1) { - durationsSamplesMax = 1; - } - // Create impulse response buffer. - let buffer = this._context.createBuffer(1, durationsSamplesMax, sampleRate); - let bufferData = buffer.getChannelData(0); - // Create noise signal (computed once, referenced in each band's routine). - let noiseSignal = new Float32Array(durationsSamplesMax); - for (let i = 0; i < durationsSamplesMax; i++) { - noiseSignal[i] = Math.random() * 2 - 1; - } - // Compute the decay rate per-band and filter the decaying noise signal. - for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) { - // Compute decay rate. - let decayRate = -Utils.LOG1000 / durationsSamples[i]; - // Construct a standard one-zero, two-pole bandpass filter: - // H(z) = (b0 * z^0 + b1 * z^-1 + b2 * z^-2) / (1 + a1 * z^-1 + a2 * z^-2) - let omega = Utils.TWO_PI * - Utils.DEFAULT_REVERB_FREQUENCY_BANDS[i] / sampleRate; - let sinOmega = Math.sin(omega); - let alpha = sinOmega * Math.sinh(this._bandwidthCoeff * omega / sinOmega); - let a0CoeffReciprocal = 1 / (1 + alpha); - let b0Coeff = alpha * a0CoeffReciprocal; - let a1Coeff = -2 * Math.cos(omega) * a0CoeffReciprocal; - let a2Coeff = (1 - alpha) * a0CoeffReciprocal; - // We optimize since b2 = -b0, b1 = 0. - // Update equation for two-pole bandpass filter: - // u[n] = x[n] - a1 * x[n-1] - a2 * x[n-2] - // y[n] = b0 * (u[n] - u[n-2]) - let um1 = 0; - let um2 = 0; - for (let j = 0; j < durationsSamples[i]; j++) { - // Exponentially-decaying white noise. - let x = noiseSignal[j] * Math.exp(decayRate * j); - // Filter signal with bandpass filter and add to output. - let u = x - a1Coeff * um1 - a2Coeff * um2; - bufferData[j] += b0Coeff * (u - um2); - // Update coefficients. - um2 = um1; - um1 = u; - } - } - // Create and apply half of a Hann window to the beginning of the - // impulse response. - let halfHannLength = Math.round(this._tailonsetSamples); - for (let i = 0; i < Math.min(bufferData.length, halfHannLength); i++) { - let halfHann = 0.5 * (1 - Math.cos(Utils.TWO_PI * i / (2 * halfHannLength - 1))); - bufferData[i] *= halfHann; - } - this._convolver.buffer = buffer; - } -} -export default LateReflections; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Late reverberation filter for Ambisonic content. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Utils from './utils.js'; +/** + * @class LateReflections + * @description Late-reflections reverberation filter for Ambisonic content. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Array} options.durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * FREQUDEFAULT_REVERB_FREQUENCY_BANDSENCY_BANDS}. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_DURATIONS DEFAULT_REVERB_DURATIONS}. + * @param {Number} options.predelay Pre-delay (in milliseconds). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_PREDELAY DEFAULT_REVERB_PREDELAY}. + * @param {Number} options.gain Output gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_REVERB_GAIN DEFAULT_REVERB_GAIN}. + * @param {Number} options.bandwidth Bandwidth (in octaves) for each frequency + * band. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_BANDWIDTH DEFAULT_REVERB_BANDWIDTH}. + * @param {Number} options.tailonset Length (in milliseconds) of impulse + * response to apply a half-Hann window. Defaults to + * {@linkcode Utils.DEFAULT_REVERB_TAIL_ONSET DEFAULT_REVERB_TAIL_ONSET}. + */ +class LateReflections { + constructor(context, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof LateReflections + * @instance + */ + /** + * Mono (1-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof LateReflections + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.durations == undefined) { + options.durations = Utils.DEFAULT_REVERB_DURATIONS.slice(); + } + if (options.predelay == undefined) { + options.predelay = Utils.DEFAULT_REVERB_PREDELAY; + } + if (options.gain == undefined) { + options.gain = Utils.DEFAULT_REVERB_GAIN; + } + if (options.bandwidth == undefined) { + options.bandwidth = Utils.DEFAULT_REVERB_BANDWIDTH; + } + if (options.tailonset == undefined) { + options.tailonset = Utils.DEFAULT_REVERB_TAIL_ONSET; + } + // Assign pre-computed variables. + let delaySecs = options.predelay / 1000; + this._bandwidthCoeff = options.bandwidth * Utils.LOG2_DIV2; + this._tailonsetSamples = options.tailonset / 1000; + // Create nodes. + this._context = context; + this.input = context.createGain(); + this._predelay = context.createDelay(delaySecs); + this._convolver = context.createConvolver(); + this.output = context.createGain(); + // Set reverb attenuation. + this.output.gain.value = options.gain; + // Disable normalization. + this._convolver.normalize = false; + // Connect nodes. + this.input.connect(this._predelay); + this._predelay.connect(this._convolver); + this._convolver.connect(this.output); + // Compute IR using RT60 values. + this.setDurations(options.durations); + } + /** + * Re-compute a new impulse response by providing Multiband RT60 durations. + * @param {Array} durations + * Multiband RT60 durations (in seconds) for each frequency band, listed as + * {@linkcode Utils.DEFAULT_REVERB_FREQUENCY_BANDS + * DEFAULT_REVERB_FREQUENCY_BANDS}. + */ + setDurations(durations) { + if (durations.length !== Utils.NUMBER_REVERB_FREQUENCY_BANDS) { + Utils.log('Warning: invalid number of RT60 values provided to reverb.'); + return; + } + // Compute impulse response. + let durationsSamples = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); + let sampleRate = this._context.sampleRate; + for (let i = 0; i < durations.length; i++) { + // Clamp within suitable range. + durations[i] = + Math.max(0, Math.min(Utils.DEFAULT_REVERB_MAX_DURATION, durations[i])); + // Convert seconds to samples. + durationsSamples[i] = Math.round(durations[i] * sampleRate * + Utils.DEFAULT_REVERB_DURATION_MULTIPLIER); + } + ; + // Determine max RT60 length in samples. + let durationsSamplesMax = 0; + for (let i = 0; i < durationsSamples.length; i++) { + if (durationsSamples[i] > durationsSamplesMax) { + durationsSamplesMax = durationsSamples[i]; + } + } + // Skip this step if there is no reverberation to compute. + if (durationsSamplesMax < 1) { + durationsSamplesMax = 1; + } + // Create impulse response buffer. + let buffer = this._context.createBuffer(1, durationsSamplesMax, sampleRate); + let bufferData = buffer.getChannelData(0); + // Create noise signal (computed once, referenced in each band's routine). + let noiseSignal = new Float32Array(durationsSamplesMax); + for (let i = 0; i < durationsSamplesMax; i++) { + noiseSignal[i] = Math.random() * 2 - 1; + } + // Compute the decay rate per-band and filter the decaying noise signal. + for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) { + // Compute decay rate. + let decayRate = -Utils.LOG1000 / durationsSamples[i]; + // Construct a standard one-zero, two-pole bandpass filter: + // H(z) = (b0 * z^0 + b1 * z^-1 + b2 * z^-2) / (1 + a1 * z^-1 + a2 * z^-2) + let omega = Utils.TWO_PI * + Utils.DEFAULT_REVERB_FREQUENCY_BANDS[i] / sampleRate; + let sinOmega = Math.sin(omega); + let alpha = sinOmega * Math.sinh(this._bandwidthCoeff * omega / sinOmega); + let a0CoeffReciprocal = 1 / (1 + alpha); + let b0Coeff = alpha * a0CoeffReciprocal; + let a1Coeff = -2 * Math.cos(omega) * a0CoeffReciprocal; + let a2Coeff = (1 - alpha) * a0CoeffReciprocal; + // We optimize since b2 = -b0, b1 = 0. + // Update equation for two-pole bandpass filter: + // u[n] = x[n] - a1 * x[n-1] - a2 * x[n-2] + // y[n] = b0 * (u[n] - u[n-2]) + let um1 = 0; + let um2 = 0; + for (let j = 0; j < durationsSamples[i]; j++) { + // Exponentially-decaying white noise. + let x = noiseSignal[j] * Math.exp(decayRate * j); + // Filter signal with bandpass filter and add to output. + let u = x - a1Coeff * um1 - a2Coeff * um2; + bufferData[j] += b0Coeff * (u - um2); + // Update coefficients. + um2 = um1; + um1 = u; + } + } + // Create and apply half of a Hann window to the beginning of the + // impulse response. + let halfHannLength = Math.round(this._tailonsetSamples); + for (let i = 0; i < Math.min(bufferData.length, halfHannLength); i++) { + let halfHann = 0.5 * (1 - Math.cos(Utils.TWO_PI * i / (2 * halfHannLength - 1))); + bufferData[i] *= halfHann; + } + this._convolver.buffer = buffer; + } +} +export default LateReflections; diff --git a/src/framework/resonator/vendor/resonance-es6/listener.d.ts b/src/framework/resonator/vendor/resonance-es6/listener.d.ts index 2b98e59..ebafa78 100644 --- a/src/framework/resonator/vendor/resonance-es6/listener.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/listener.d.ts @@ -1,49 +1,49 @@ -export default Listener; -/** - * @class Listener - * @description Listener model to spatialize sources in an environment. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.ambisonicOrder - * Desired ambisonic order. Defaults to - * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - * @param {Float32Array} options.position - * Initial position (in meters), where origin is the center of - * the room. Defaults to - * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @param {Float32Array} options.forward - * The listener's initial forward vector. Defaults to - * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - * @param {Float32Array} options.up - * The listener's initial up vector. Defaults to - * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. - */ -declare class Listener { - constructor(context: any, options: any); - position: Float32Array; - _tempMatrix3: Float32Array; - _ambisonicOrder: number; - _context: any; - _renderer: any; - input: any; - output: any; - ambisonicOutput: any; - /** - * Set the source's orientation using forward and up vectors. - * @param {Number} forwardX - * @param {Number} forwardY - * @param {Number} forwardZ - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - */ - setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; - /** - * Set the listener's position and orientation using a Three.js Matrix4 object. - * @param {Object} matrix4 - * The Three.js Matrix4 object representing the listener's world transform. - */ - setFromMatrix(matrix4: any): void; -} +export default Listener; +/** + * @class Listener + * @description Listener model to spatialize sources in an environment. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Float32Array} options.position + * Initial position (in meters), where origin is the center of + * the room. Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Float32Array} options.forward + * The listener's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @param {Float32Array} options.up + * The listener's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + */ +declare class Listener { + constructor(context: any, options: any); + position: Float32Array; + _tempMatrix3: Float32Array; + _ambisonicOrder: number; + _context: any; + _renderer: any; + input: any; + output: any; + ambisonicOutput: any; + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix4 + * The Three.js Matrix4 object representing the listener's world transform. + */ + setFromMatrix(matrix4: any): void; +} diff --git a/src/framework/resonator/vendor/resonance-es6/listener.js b/src/framework/resonator/vendor/resonance-es6/listener.js index 2e6b15a..be0e0e8 100644 --- a/src/framework/resonator/vendor/resonance-es6/listener.js +++ b/src/framework/resonator/vendor/resonance-es6/listener.js @@ -1,168 +1,168 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Listener model to spatialize sources in an environment. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Omnitone from 'omnitone/build/omnitone.esm'; -import Encoder from './encoder.js'; -import Utils from './utils.js'; -/** - * @class Listener - * @description Listener model to spatialize sources in an environment. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Number} options.ambisonicOrder - * Desired ambisonic order. Defaults to - * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - * @param {Float32Array} options.position - * Initial position (in meters), where origin is the center of - * the room. Defaults to - * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @param {Float32Array} options.forward - * The listener's initial forward vector. Defaults to - * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - * @param {Float32Array} options.up - * The listener's initial up vector. Defaults to - * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. - */ -class Listener { - constructor(context, options) { - // Public variables. - /** - * Position (in meters). - * @member {Float32Array} position - * @memberof Listener - * @instance - */ - /** - * Ambisonic (multichannel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof Listener - * @instance - */ - /** - * Binaurally-rendered stereo (2-channel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof Listener - * @instance - */ - /** - * Ambisonic (multichannel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} ambisonicOutput - * @memberof Listener - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.ambisonicOrder == undefined) { - options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; - } - if (options.position == undefined) { - options.position = Utils.DEFAULT_POSITION.slice(); - } - if (options.forward == undefined) { - options.forward = Utils.DEFAULT_FORWARD.slice(); - } - if (options.up == undefined) { - options.up = Utils.DEFAULT_UP.slice(); - } - // Member variables. - this.position = new Float32Array(3); - this._tempMatrix3 = new Float32Array(9); - // Select the appropriate HRIR filters using 2-channel chunks since - // multichannel audio is not yet supported by a majority of browsers. - this._ambisonicOrder = - Encoder.validateAmbisonicOrder(options.ambisonicOrder); - // Create audio nodes. - this._context = context; - if (this._ambisonicOrder == 1) { - this._renderer = Omnitone.createFOARenderer(context, {}); - } - else if (this._ambisonicOrder > 1) { - this._renderer = Omnitone.createHOARenderer(context, { - ambisonicOrder: this._ambisonicOrder, - }); - } - // These nodes are created in order to safely asynchronously load Omnitone - // while the rest of the scene is being created. - this.input = context.createGain(); - this.output = context.createGain(); - this.ambisonicOutput = context.createGain(); - // Initialize Omnitone (async) and connect to audio graph when complete. - let that = this; - this._renderer.initialize().then(() => { - // Connect pre-rotated soundfield to renderer. - that.input.connect(that._renderer.input); - // Connect rotated soundfield to ambisonic output. - if (that._ambisonicOrder > 1) { - that._renderer._hoaRotator.output.connect(that.ambisonicOutput); - } - else { - that._renderer._foaRotator.output.connect(that.ambisonicOutput); - } - // Connect binaurally-rendered soundfield to binaural output. - that._renderer.output.connect(that.output); - }); - // Set orientation and update rotation matrix accordingly. - this.setOrientation(options.forward[0], options.forward[1], options.forward[2], options.up[0], options.up[1], options.up[2]); - } - /** - * Set the source's orientation using forward and up vectors. - * @param {Number} forwardX - * @param {Number} forwardY - * @param {Number} forwardZ - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - */ - setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { - let right = Utils.crossProduct([forwardX, forwardY, forwardZ], [upX, upY, upZ]); - this._tempMatrix3[0] = right[0]; - this._tempMatrix3[1] = right[1]; - this._tempMatrix3[2] = right[2]; - this._tempMatrix3[3] = upX; - this._tempMatrix3[4] = upY; - this._tempMatrix3[5] = upZ; - this._tempMatrix3[6] = forwardX; - this._tempMatrix3[7] = forwardY; - this._tempMatrix3[8] = forwardZ; - this._renderer.setRotationMatrix3(this._tempMatrix3); - } - /** - * Set the listener's position and orientation using a Three.js Matrix4 object. - * @param {Object} matrix4 - * The Three.js Matrix4 object representing the listener's world transform. - */ - setFromMatrix(matrix4) { - // Update ambisonic rotation matrix internally. - this._renderer.setRotationMatrix4(matrix4.elements); - // Extract position from matrix. - this.position[0] = matrix4.elements[12]; - this.position[1] = matrix4.elements[13]; - this.position[2] = matrix4.elements[14]; - } -} -export default Listener; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Listener model to spatialize sources in an environment. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Omnitone from 'omnitone/build/omnitone.esm'; +import Encoder from './encoder.js'; +import Utils from './utils.js'; +/** + * @class Listener + * @description Listener model to spatialize sources in an environment. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Number} options.ambisonicOrder + * Desired ambisonic order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @param {Float32Array} options.position + * Initial position (in meters), where origin is the center of + * the room. Defaults to + * {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Float32Array} options.forward + * The listener's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @param {Float32Array} options.up + * The listener's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + */ +class Listener { + constructor(context, options) { + // Public variables. + /** + * Position (in meters). + * @member {Float32Array} position + * @memberof Listener + * @instance + */ + /** + * Ambisonic (multichannel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Listener + * @instance + */ + /** + * Binaurally-rendered stereo (2-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Listener + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} ambisonicOutput + * @memberof Listener + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.ambisonicOrder == undefined) { + options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; + } + if (options.position == undefined) { + options.position = Utils.DEFAULT_POSITION.slice(); + } + if (options.forward == undefined) { + options.forward = Utils.DEFAULT_FORWARD.slice(); + } + if (options.up == undefined) { + options.up = Utils.DEFAULT_UP.slice(); + } + // Member variables. + this.position = new Float32Array(3); + this._tempMatrix3 = new Float32Array(9); + // Select the appropriate HRIR filters using 2-channel chunks since + // multichannel audio is not yet supported by a majority of browsers. + this._ambisonicOrder = + Encoder.validateAmbisonicOrder(options.ambisonicOrder); + // Create audio nodes. + this._context = context; + if (this._ambisonicOrder == 1) { + this._renderer = Omnitone.createFOARenderer(context, {}); + } + else if (this._ambisonicOrder > 1) { + this._renderer = Omnitone.createHOARenderer(context, { + ambisonicOrder: this._ambisonicOrder, + }); + } + // These nodes are created in order to safely asynchronously load Omnitone + // while the rest of the scene is being created. + this.input = context.createGain(); + this.output = context.createGain(); + this.ambisonicOutput = context.createGain(); + // Initialize Omnitone (async) and connect to audio graph when complete. + let that = this; + this._renderer.initialize().then(() => { + // Connect pre-rotated soundfield to renderer. + that.input.connect(that._renderer.input); + // Connect rotated soundfield to ambisonic output. + if (that._ambisonicOrder > 1) { + that._renderer._hoaRotator.output.connect(that.ambisonicOutput); + } + else { + that._renderer._foaRotator.output.connect(that.ambisonicOutput); + } + // Connect binaurally-rendered soundfield to binaural output. + that._renderer.output.connect(that.output); + }); + // Set orientation and update rotation matrix accordingly. + this.setOrientation(options.forward[0], options.forward[1], options.forward[2], options.up[0], options.up[1], options.up[2]); + } + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { + let right = Utils.crossProduct([forwardX, forwardY, forwardZ], [upX, upY, upZ]); + this._tempMatrix3[0] = right[0]; + this._tempMatrix3[1] = right[1]; + this._tempMatrix3[2] = right[2]; + this._tempMatrix3[3] = upX; + this._tempMatrix3[4] = upY; + this._tempMatrix3[5] = upZ; + this._tempMatrix3[6] = forwardX; + this._tempMatrix3[7] = forwardY; + this._tempMatrix3[8] = forwardZ; + this._renderer.setRotationMatrix3(this._tempMatrix3); + } + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix4 + * The Three.js Matrix4 object representing the listener's world transform. + */ + setFromMatrix(matrix4) { + // Update ambisonic rotation matrix internally. + this._renderer.setRotationMatrix4(matrix4.elements); + // Extract position from matrix. + this.position[0] = matrix4.elements[12]; + this.position[1] = matrix4.elements[13]; + this.position[2] = matrix4.elements[14]; + } +} +export default Listener; diff --git a/src/framework/resonator/vendor/resonance-es6/main.d.ts b/src/framework/resonator/vendor/resonance-es6/main.d.ts index 384e86e..1bc1964 100644 --- a/src/framework/resonator/vendor/resonance-es6/main.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/main.d.ts @@ -1,2 +1,2 @@ -export default ResonanceAudio; -import ResonanceAudio from "./resonance-audio"; +export default ResonanceAudio; +import ResonanceAudio from "./resonance-audio"; diff --git a/src/framework/resonator/vendor/resonance-es6/main.js b/src/framework/resonator/vendor/resonance-es6/main.js index 8afdc68..103a9a6 100644 --- a/src/framework/resonator/vendor/resonance-es6/main.js +++ b/src/framework/resonator/vendor/resonance-es6/main.js @@ -1,23 +1,23 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Primary namespace for ResonanceAudio library. - * @author Andrew Allen - */ -'use strict'; -import ResonanceAudio from './resonance-audio'; -// Main module. -export default ResonanceAudio; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Primary namespace for ResonanceAudio library. + * @author Andrew Allen + */ +'use strict'; +import ResonanceAudio from './resonance-audio'; +// Main module. +export default ResonanceAudio; diff --git a/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts b/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts index 7c2194e..26c3472 100644 --- a/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/resonance-audio.d.ts @@ -1,130 +1,130 @@ -export default ResonanceAudio; -/** - * ~ResonanceAudioOptions - */ -export type ResonanceAudio = { - /** - * Desired ambisonic Order. Defaults to - * {@link Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - */ - ambisonicOrder: number; - /** - * The listener's initial position (in meters), where origin is the center of - * the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}. - */ - listenerPosition: Float32Array; - /** - * The listener's initial forward vector. - * Defaults to {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - */ - listenerForward: Float32Array; - /** - * The listener's initial up vector. - * Defaults to {@link Utils.DEFAULT_UP DEFAULT_UP}. - */ - listenerUp: Float32Array; - /** - * ~RoomDimensions} dimensions Room dimensions (in meters). Defaults to - * {@link Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - */ - "": Utils; - /** - * (in meters/second). Defaults to - * {@link Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. - */ - speedOfSound: number; -}; -/** - * Options for constructing a new ResonanceAudio scene. - * @typedef {Object} ResonanceAudio~ResonanceAudioOptions - * @property {Number} ambisonicOrder - * Desired ambisonic Order. Defaults to - * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - * @property {Float32Array} listenerPosition - * The listener's initial position (in meters), where origin is the center of - * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @property {Float32Array} listenerForward - * The listener's initial forward vector. - * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - * @property {Float32Array} listenerUp - * The listener's initial up vector. - * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. - * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @property {Utils~RoomMaterials} materials Named acoustic materials per wall. - * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. - * @property {Number} speedOfSound - * (in meters/second). Defaults to - * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. - */ -/** - * @class ResonanceAudio - * @description Main class for managing sources, room and listener models. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {ResonanceAudio~ResonanceAudioOptions} options - * Options for constructing a new ResonanceAudio scene. - */ -declare class ResonanceAudio { - constructor(context: any, options: any); - _ambisonicOrder: number; - _sources: any[]; - _room: Room; - _listener: Listener; - _context: any; - output: any; - ambisonicOutput: any; - ambisonicInput: any; - /** - * Create a new source for the scene. - * @param {Source~SourceOptions} options - * Options for constructing a new Source. - * @return {Source} - */ - createSource(options: any): Source; - /** - * Set the scene's desired ambisonic order. - * @param {Number} ambisonicOrder Desired ambisonic order. - */ - setAmbisonicOrder(ambisonicOrder: number): void; - /** - * Set the room's dimensions and wall materials. - * @param {Object} dimensions Room dimensions (in meters). - * @param {Object} materials Named acoustic materials per wall. - */ - setRoomProperties(dimensions: any, materials: any): void; - /** - * Set the listener's position (in meters), where origin is the center of - * the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setListenerPosition(x: number, y: number, z: number): void; - /** - * Set the source's orientation using forward and up vectors. - * @param {Number} forwardX - * @param {Number} forwardY - * @param {Number} forwardZ - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - */ - setListenerOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; - /** - * Set the listener's position and orientation using a Three.js Matrix4 object. - * @param {Object} matrix - * The Three.js Matrix4 object representing the listener's world transform. - */ - setListenerFromMatrix(matrix: any): void; - /** - * Set the speed of sound. - * @param {Number} speedOfSound - */ - setSpeedOfSound(speedOfSound: number): void; -} -import Utils from "./utils.js"; -import Room from "./room.js"; -import Listener from "./listener.js"; -import Source from "./source.js"; +export default ResonanceAudio; +/** + * ~ResonanceAudioOptions + */ +export type ResonanceAudio = { + /** + * Desired ambisonic Order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + */ + ambisonicOrder: number; + /** + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ + listenerPosition: Float32Array; + /** + * The listener's initial forward vector. + * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + */ + listenerForward: Float32Array; + /** + * The listener's initial up vector. + * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + */ + listenerUp: Float32Array; + /** + * ~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + */ + "": Utils; + /** + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ + speedOfSound: number; +}; +/** + * Options for constructing a new ResonanceAudio scene. + * @typedef {Object} ResonanceAudio~ResonanceAudioOptions + * @property {Number} ambisonicOrder + * Desired ambisonic Order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @property {Float32Array} listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} listenerForward + * The listener's initial forward vector. + * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} listenerUp + * The listener's initial up vector. + * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @property {Utils~RoomMaterials} materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @property {Number} speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +/** + * @class ResonanceAudio + * @description Main class for managing sources, room and listener models. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {ResonanceAudio~ResonanceAudioOptions} options + * Options for constructing a new ResonanceAudio scene. + */ +declare class ResonanceAudio { + constructor(context: any, options: any); + _ambisonicOrder: number; + _sources: any[]; + _room: Room; + _listener: Listener; + _context: any; + output: any; + ambisonicOutput: any; + ambisonicInput: any; + /** + * Create a new source for the scene. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + * @return {Source} + */ + createSource(options: any): Source; + /** + * Set the scene's desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder: number): void; + /** + * Set the room's dimensions and wall materials. + * @param {Object} dimensions Room dimensions (in meters). + * @param {Object} materials Named acoustic materials per wall. + */ + setRoomProperties(dimensions: any, materials: any): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setListenerOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix + * The Three.js Matrix4 object representing the listener's world transform. + */ + setListenerFromMatrix(matrix: any): void; + /** + * Set the speed of sound. + * @param {Number} speedOfSound + */ + setSpeedOfSound(speedOfSound: number): void; +} +import Utils from "./utils.js"; +import Room from "./room.js"; +import Listener from "./listener.js"; +import Source from "./source.js"; diff --git a/src/framework/resonator/vendor/resonance-es6/resonance-audio.js b/src/framework/resonator/vendor/resonance-es6/resonance-audio.js index 32d14f3..7e3c6c9 100644 --- a/src/framework/resonator/vendor/resonance-es6/resonance-audio.js +++ b/src/framework/resonator/vendor/resonance-es6/resonance-audio.js @@ -1,213 +1,213 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 ResonanceAudio library name space and common utilities. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Listener from './listener.js'; -import Source from './source.js'; -import Room from './room.js'; -import Encoder from './encoder.js'; -import Utils from './utils.js'; -/** - * Options for constructing a new ResonanceAudio scene. - * @typedef {Object} ResonanceAudio~ResonanceAudioOptions - * @property {Number} ambisonicOrder - * Desired ambisonic Order. Defaults to - * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. - * @property {Float32Array} listenerPosition - * The listener's initial position (in meters), where origin is the center of - * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @property {Float32Array} listenerForward - * The listener's initial forward vector. - * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - * @property {Float32Array} listenerUp - * The listener's initial up vector. - * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. - * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @property {Utils~RoomMaterials} materials Named acoustic materials per wall. - * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. - * @property {Number} speedOfSound - * (in meters/second). Defaults to - * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. - */ -/** - * @class ResonanceAudio - * @description Main class for managing sources, room and listener models. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {ResonanceAudio~ResonanceAudioOptions} options - * Options for constructing a new ResonanceAudio scene. - */ -class ResonanceAudio { - constructor(context, options) { - // Public variables. - /** - * Binaurally-rendered stereo (2-channel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof ResonanceAudio - * @instance - */ - /** - * Ambisonic (multichannel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode} - * (For rendering input soundfields). - * @member {AudioNode} ambisonicInput - * @memberof ResonanceAudio - * @instance - */ - /** - * Ambisonic (multichannel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode} - * (For allowing external rendering / post-processing). - * @member {AudioNode} ambisonicOutput - * @memberof ResonanceAudio - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.ambisonicOrder == undefined) { - options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; - } - if (options.listenerPosition == undefined) { - options.listenerPosition = Utils.DEFAULT_POSITION.slice(); - } - if (options.listenerForward == undefined) { - options.listenerForward = Utils.DEFAULT_FORWARD.slice(); - } - if (options.listenerUp == undefined) { - options.listenerUp = Utils.DEFAULT_UP.slice(); - } - if (options.dimensions == undefined) { - options.dimensions = {}; - Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); - } - if (options.materials == undefined) { - options.materials = {}; - Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS); - } - if (options.speedOfSound == undefined) { - options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; - } - // Create member submodules. - this._ambisonicOrder = Encoder.validateAmbisonicOrder(options.ambisonicOrder); - this._sources = []; - this._room = new Room(context, { - listenerPosition: options.listenerPosition, - dimensions: options.dimensions, - materials: options.materials, - speedOfSound: options.speedOfSound, - }); - this._listener = new Listener(context, { - ambisonicOrder: options.ambisonicOrder, - position: options.listenerPosition, - forward: options.listenerForward, - up: options.listenerUp, - }); - // Create auxillary audio nodes. - this._context = context; - this.output = context.createGain(); - this.ambisonicOutput = context.createGain(); - this.ambisonicInput = this._listener.input; - // Connect audio graph. - this._room.output.connect(this._listener.input); - this._listener.output.connect(this.output); - this._listener.ambisonicOutput.connect(this.ambisonicOutput); - } - /** - * Create a new source for the scene. - * @param {Source~SourceOptions} options - * Options for constructing a new Source. - * @return {Source} - */ - createSource(options) { - // Create a source and push it to the internal sources array, returning - // the object's reference to the user. - let source = new Source(this, options); - this._sources[this._sources.length] = source; - return source; - } - /** - * Set the scene's desired ambisonic order. - * @param {Number} ambisonicOrder Desired ambisonic order. - */ - setAmbisonicOrder(ambisonicOrder) { - this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder); - } - /** - * Set the room's dimensions and wall materials. - * @param {Object} dimensions Room dimensions (in meters). - * @param {Object} materials Named acoustic materials per wall. - */ - setRoomProperties(dimensions, materials) { - this._room.setProperties(dimensions, materials); - } - /** - * Set the listener's position (in meters), where origin is the center of - * the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setListenerPosition(x, y, z) { - // Update listener position. - this._listener.position[0] = x; - this._listener.position[1] = y; - this._listener.position[2] = z; - this._room.setListenerPosition(x, y, z); - // Update sources with new listener position. - this._sources.forEach(element => { - element._update(); - }); - } - /** - * Set the source's orientation using forward and up vectors. - * @param {Number} forwardX - * @param {Number} forwardY - * @param {Number} forwardZ - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - */ - setListenerOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { - this._listener.setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ); - } - /** - * Set the listener's position and orientation using a Three.js Matrix4 object. - * @param {Object} matrix - * The Three.js Matrix4 object representing the listener's world transform. - */ - setListenerFromMatrix(matrix) { - this._listener.setFromMatrix(matrix); - // Update the rest of the scene using new listener position. - this.setListenerPosition(this._listener.position[0], this._listener.position[1], this._listener.position[2]); - } - /** - * Set the speed of sound. - * @param {Number} speedOfSound - */ - setSpeedOfSound(speedOfSound) { - this._room.speedOfSound = speedOfSound; - } -} -export default ResonanceAudio; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 ResonanceAudio library name space and common utilities. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Listener from './listener.js'; +import Source from './source.js'; +import Room from './room.js'; +import Encoder from './encoder.js'; +import Utils from './utils.js'; +/** + * Options for constructing a new ResonanceAudio scene. + * @typedef {Object} ResonanceAudio~ResonanceAudioOptions + * @property {Number} ambisonicOrder + * Desired ambisonic Order. Defaults to + * {@linkcode Utils.DEFAULT_AMBISONIC_ORDER DEFAULT_AMBISONIC_ORDER}. + * @property {Float32Array} listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} listenerForward + * The listener's initial forward vector. + * Defaults to {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} listenerUp + * The listener's initial up vector. + * Defaults to {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @property {Utils~RoomMaterials} materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @property {Number} speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +/** + * @class ResonanceAudio + * @description Main class for managing sources, room and listener models. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {ResonanceAudio~ResonanceAudioOptions} options + * Options for constructing a new ResonanceAudio scene. + */ +class ResonanceAudio { + constructor(context, options) { + // Public variables. + /** + * Binaurally-rendered stereo (2-channel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof ResonanceAudio + * @instance + */ + /** + * Ambisonic (multichannel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode} + * (For rendering input soundfields). + * @member {AudioNode} ambisonicInput + * @memberof ResonanceAudio + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode} + * (For allowing external rendering / post-processing). + * @member {AudioNode} ambisonicOutput + * @memberof ResonanceAudio + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.ambisonicOrder == undefined) { + options.ambisonicOrder = Utils.DEFAULT_AMBISONIC_ORDER; + } + if (options.listenerPosition == undefined) { + options.listenerPosition = Utils.DEFAULT_POSITION.slice(); + } + if (options.listenerForward == undefined) { + options.listenerForward = Utils.DEFAULT_FORWARD.slice(); + } + if (options.listenerUp == undefined) { + options.listenerUp = Utils.DEFAULT_UP.slice(); + } + if (options.dimensions == undefined) { + options.dimensions = {}; + Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); + } + if (options.materials == undefined) { + options.materials = {}; + Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS); + } + if (options.speedOfSound == undefined) { + options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + // Create member submodules. + this._ambisonicOrder = Encoder.validateAmbisonicOrder(options.ambisonicOrder); + this._sources = []; + this._room = new Room(context, { + listenerPosition: options.listenerPosition, + dimensions: options.dimensions, + materials: options.materials, + speedOfSound: options.speedOfSound, + }); + this._listener = new Listener(context, { + ambisonicOrder: options.ambisonicOrder, + position: options.listenerPosition, + forward: options.listenerForward, + up: options.listenerUp, + }); + // Create auxillary audio nodes. + this._context = context; + this.output = context.createGain(); + this.ambisonicOutput = context.createGain(); + this.ambisonicInput = this._listener.input; + // Connect audio graph. + this._room.output.connect(this._listener.input); + this._listener.output.connect(this.output); + this._listener.ambisonicOutput.connect(this.ambisonicOutput); + } + /** + * Create a new source for the scene. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + * @return {Source} + */ + createSource(options) { + // Create a source and push it to the internal sources array, returning + // the object's reference to the user. + let source = new Source(this, options); + this._sources[this._sources.length] = source; + return source; + } + /** + * Set the scene's desired ambisonic order. + * @param {Number} ambisonicOrder Desired ambisonic order. + */ + setAmbisonicOrder(ambisonicOrder) { + this._ambisonicOrder = Encoder.validateAmbisonicOrder(ambisonicOrder); + } + /** + * Set the room's dimensions and wall materials. + * @param {Object} dimensions Room dimensions (in meters). + * @param {Object} materials Named acoustic materials per wall. + */ + setRoomProperties(dimensions, materials) { + this._room.setProperties(dimensions, materials); + } + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x, y, z) { + // Update listener position. + this._listener.position[0] = x; + this._listener.position[1] = y; + this._listener.position[2] = z; + this._room.setListenerPosition(x, y, z); + // Update sources with new listener position. + this._sources.forEach(element => { + element._update(); + }); + } + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setListenerOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { + this._listener.setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ); + } + /** + * Set the listener's position and orientation using a Three.js Matrix4 object. + * @param {Object} matrix + * The Three.js Matrix4 object representing the listener's world transform. + */ + setListenerFromMatrix(matrix) { + this._listener.setFromMatrix(matrix); + // Update the rest of the scene using new listener position. + this.setListenerPosition(this._listener.position[0], this._listener.position[1], this._listener.position[2]); + } + /** + * Set the speed of sound. + * @param {Number} speedOfSound + */ + setSpeedOfSound(speedOfSound) { + this._room.speedOfSound = speedOfSound; + } +} +export default ResonanceAudio; diff --git a/src/framework/resonator/vendor/resonance-es6/room.d.ts b/src/framework/resonator/vendor/resonance-es6/room.d.ts index a04788c..ca71c23 100644 --- a/src/framework/resonator/vendor/resonance-es6/room.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/room.d.ts @@ -1,55 +1,55 @@ -export default Room; -/** - * @class Room - * @description Model that manages early and late reflections using acoustic - * properties and listener position relative to a rectangular room. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Float32Array} options.listenerPosition - * The listener's initial position (in meters), where origin is the center of - * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall. - * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. - * @param {Number} options.speedOfSound - * (in meters/second). Defaults to - * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. - */ -declare class Room { - constructor(context: any, options: any); - early: EarlyReflections; - late: LateReflections; - speedOfSound: any; - output: any; - _merger: any; - /** - * Set the room's dimensions and wall materials. - * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to - * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. - */ - setProperties(dimensions: any, materials: any): void; - /** - * Set the listener's position (in meters), where origin is the center of - * the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setListenerPosition(x: number, y: number, z: number): void; - /** - * Compute distance outside room of provided position (in meters). - * @param {Number} x - * @param {Number} y - * @param {Number} z - * @return {Number} - * Distance outside room (in meters). Returns 0 if inside room. - */ - getDistanceOutsideRoom(x: number, y: number, z: number): number; -} -import EarlyReflections from "./early-reflections.js"; -import LateReflections from "./late-reflections.js"; +export default Room; +/** + * @class Room + * @description Model that manages early and late reflections using acoustic + * properties and listener position relative to a rectangular room. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Float32Array} options.listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @param {Number} options.speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +declare class Room { + constructor(context: any, options: any); + early: EarlyReflections; + late: LateReflections; + speedOfSound: any; + output: any; + _merger: any; + /** + * Set the room's dimensions and wall materials. + * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to + * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + */ + setProperties(dimensions: any, materials: any): void; + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x: number, y: number, z: number): void; + /** + * Compute distance outside room of provided position (in meters). + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @return {Number} + * Distance outside room (in meters). Returns 0 if inside room. + */ + getDistanceOutsideRoom(x: number, y: number, z: number): number; +} +import EarlyReflections from "./early-reflections.js"; +import LateReflections from "./late-reflections.js"; diff --git a/src/framework/resonator/vendor/resonance-es6/room.js b/src/framework/resonator/vendor/resonance-es6/room.js index e2a54c5..e36dfc6 100644 --- a/src/framework/resonator/vendor/resonance-es6/room.js +++ b/src/framework/resonator/vendor/resonance-es6/room.js @@ -1,300 +1,300 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Complete room model with early and late reflections. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import LateReflections from './late-reflections.js'; -import EarlyReflections from './early-reflections.js'; -import Utils from './utils.js'; -/** - * Generate absorption coefficients from material names. - * @param {Object} materials - * @return {Object} - */ -function _getCoefficientsFromMaterials(materials) { - // Initialize coefficients to use defaults. - let coefficients = {}; - for (let property in Utils.DEFAULT_ROOM_MATERIALS) { - if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property)) { - coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]]; - } - } - // Sanitize materials. - if (materials == undefined) { - materials = {}; - Object.assign(materials, Utils.DEFAULT_ROOM_MATERIALS); - } - // Assign coefficients using provided materials. - for (let property in Utils.DEFAULT_ROOM_MATERIALS) { - if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property) && - materials.hasOwnProperty(property)) { - if (materials[property] in Utils.ROOM_MATERIAL_COEFFICIENTS) { - coefficients[property] = - Utils.ROOM_MATERIAL_COEFFICIENTS[materials[property]]; - } - else { - Utils.log('Material \"' + materials[property] + '\" on wall \"' + - property + '\" not found. Using \"' + - Utils.DEFAULT_ROOM_MATERIALS[property] + '\".'); - } - } - else { - Utils.log('Wall \"' + property + '\" is not defined. Default used.'); - } - } - return coefficients; -} -/** - * Sanitize coefficients. - * @param {Object} coefficients - * @return {Object} - */ -function _sanitizeCoefficients(coefficients) { - if (coefficients == undefined) { - coefficients = {}; - } - for (let property in Utils.DEFAULT_ROOM_MATERIALS) { - if (!(coefficients.hasOwnProperty(property))) { - // If element is not present, use default coefficients. - coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]]; - } - } - return coefficients; -} -/** - * Sanitize dimensions. - * @param {Utils~RoomDimensions} dimensions - * @return {Utils~RoomDimensions} - */ -function _sanitizeDimensions(dimensions) { - if (dimensions == undefined) { - dimensions = {}; - } - for (let property in Utils.DEFAULT_ROOM_DIMENSIONS) { - if (!(dimensions.hasOwnProperty(property))) { - dimensions[property] = Utils.DEFAULT_ROOM_DIMENSIONS[property]; - } - } - return dimensions; -} -/** - * Compute frequency-dependent reverb durations. - * @param {Utils~RoomDimensions} dimensions - * @param {Object} coefficients - * @param {Number} speedOfSound - * @return {Array} - */ -function _getDurationsFromProperties(dimensions, coefficients, speedOfSound) { - let durations = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); - // Sanitize inputs. - dimensions = _sanitizeDimensions(dimensions); - coefficients = _sanitizeCoefficients(coefficients); - if (speedOfSound == undefined) { - speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; - } - // Acoustic constant. - let k = Utils.TWENTY_FOUR_LOG10 / speedOfSound; - // Compute volume, skip if room is not present. - let volume = dimensions.width * dimensions.height * dimensions.depth; - if (volume < Utils.ROOM_MIN_VOLUME) { - return durations; - } - // Room surface area. - let leftRightArea = dimensions.width * dimensions.height; - let floorCeilingArea = dimensions.width * dimensions.depth; - let frontBackArea = dimensions.depth * dimensions.height; - let totalArea = 2 * (leftRightArea + floorCeilingArea + frontBackArea); - for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) { - // Effective absorptive area. - let absorbtionArea = (coefficients.left[i] + coefficients.right[i]) * leftRightArea + - (coefficients.down[i] + coefficients.up[i]) * floorCeilingArea + - (coefficients.front[i] + coefficients.back[i]) * frontBackArea; - let meanAbsorbtionArea = absorbtionArea / totalArea; - // Compute reverberation using Eyring equation [1]. - // [1] Beranek, Leo L. "Analysis of Sabine and Eyring equations and their - // application to concert hall audience and chair absorption." The - // Journal of the Acoustical Society of America, Vol. 120, No. 3. - // (2006), pp. 1399-1399. - durations[i] = Utils.ROOM_EYRING_CORRECTION_COEFFICIENT * k * volume / - (-totalArea * Math.log(1 - meanAbsorbtionArea) + 4 * - Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS[i] * volume); - } - return durations; -} -/** - * Compute reflection coefficients from absorption coefficients. - * @param {Object} absorptionCoefficients - * @return {Object} - */ -function _computeReflectionCoefficients(absorptionCoefficients) { - let reflectionCoefficients = []; - for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { - if (Utils.DEFAULT_REFLECTION_COEFFICIENTS - .hasOwnProperty(property)) { - // Compute average absorption coefficient (per wall). - reflectionCoefficients[property] = 0; - for (let j = 0; j < Utils.NUMBER_REFLECTION_AVERAGING_BANDS; j++) { - let bandIndex = j + Utils.ROOM_STARTING_AVERAGING_BAND; - reflectionCoefficients[property] += - absorptionCoefficients[property][bandIndex]; - } - reflectionCoefficients[property] /= - Utils.NUMBER_REFLECTION_AVERAGING_BANDS; - // Convert absorption coefficient to reflection coefficient. - reflectionCoefficients[property] = - Math.sqrt(1 - reflectionCoefficients[property]); - } - } - return reflectionCoefficients; -} -/** - * @class Room - * @description Model that manages early and late reflections using acoustic - * properties and listener position relative to a rectangular room. - * @param {AudioContext} context - * Associated {@link -https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. - * @param {Object} options - * @param {Float32Array} options.listenerPosition - * The listener's initial position (in meters), where origin is the center of - * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall. - * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. - * @param {Number} options.speedOfSound - * (in meters/second). Defaults to - * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. - */ -class Room { - constructor(context, options) { - // Public variables. - /** - * EarlyReflections {@link EarlyReflections EarlyReflections} submodule. - * @member {AudioNode} early - * @memberof Room - * @instance - */ - /** - * LateReflections {@link LateReflections LateReflections} submodule. - * @member {AudioNode} late - * @memberof Room - * @instance - */ - /** - * Ambisonic (multichannel) output {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} output - * @memberof Room - * @instance - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.listenerPosition == undefined) { - options.listenerPosition = Utils.DEFAULT_POSITION.slice(); - } - if (options.dimensions == undefined) { - options.dimensions = {}; - Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); - } - if (options.materials == undefined) { - options.materials = {}; - Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS); - } - if (options.speedOfSound == undefined) { - options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; - } - // Sanitize room-properties-related arguments. - options.dimensions = _sanitizeDimensions(options.dimensions); - let absorptionCoefficients = _getCoefficientsFromMaterials(options.materials); - let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients); - let durations = _getDurationsFromProperties(options.dimensions, absorptionCoefficients, options.speedOfSound); - // Construct submodules for early and late reflections. - this.early = new EarlyReflections(context, { - dimensions: options.dimensions, - coefficients: reflectionCoefficients, - speedOfSound: options.speedOfSound, - listenerPosition: options.listenerPosition, - }); - this.late = new LateReflections(context, { - durations: durations, - }); - this.speedOfSound = options.speedOfSound; - // Construct auxillary audio nodes. - this.output = context.createGain(); - this.early.output.connect(this.output); - this._merger = context.createChannelMerger(4); - this.late.output.connect(this._merger, 0, 0); - this._merger.connect(this.output); - } - /** - * Set the room's dimensions and wall materials. - * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to - * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. - * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to - * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. - */ - setProperties(dimensions, materials) { - // Compute late response. - let absorptionCoefficients = _getCoefficientsFromMaterials(materials); - let durations = _getDurationsFromProperties(dimensions, absorptionCoefficients, this.speedOfSound); - this.late.setDurations(durations); - // Compute early response. - this.early.speedOfSound = this.speedOfSound; - let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients); - this.early.setRoomProperties(dimensions, reflectionCoefficients); - } - /** - * Set the listener's position (in meters), where origin is the center of - * the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setListenerPosition(x, y, z) { - this.early.speedOfSound = this.speedOfSound; - this.early.setListenerPosition(x, y, z); - // Disable room effects if the listener is outside the room boundaries. - let distance = this.getDistanceOutsideRoom(x, y, z); - let gain = 1; - if (distance > Utils.EPSILON_FLOAT) { - gain = 1 - distance / Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE; - // Clamp gain between 0 and 1. - gain = Math.max(0, Math.min(1, gain)); - } - this.output.gain.value = gain; - } - /** - * Compute distance outside room of provided position (in meters). - * @param {Number} x - * @param {Number} y - * @param {Number} z - * @return {Number} - * Distance outside room (in meters). Returns 0 if inside room. - */ - getDistanceOutsideRoom(x, y, z) { - let dx = Math.max(0, -this.early._halfDimensions.width - x, x - this.early._halfDimensions.width); - let dy = Math.max(0, -this.early._halfDimensions.height - y, y - this.early._halfDimensions.height); - let dz = Math.max(0, -this.early._halfDimensions.depth - z, z - this.early._halfDimensions.depth); - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } -} -export default Room; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Complete room model with early and late reflections. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import LateReflections from './late-reflections.js'; +import EarlyReflections from './early-reflections.js'; +import Utils from './utils.js'; +/** + * Generate absorption coefficients from material names. + * @param {Object} materials + * @return {Object} + */ +function _getCoefficientsFromMaterials(materials) { + // Initialize coefficients to use defaults. + let coefficients = {}; + for (let property in Utils.DEFAULT_ROOM_MATERIALS) { + if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property)) { + coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]]; + } + } + // Sanitize materials. + if (materials == undefined) { + materials = {}; + Object.assign(materials, Utils.DEFAULT_ROOM_MATERIALS); + } + // Assign coefficients using provided materials. + for (let property in Utils.DEFAULT_ROOM_MATERIALS) { + if (Utils.DEFAULT_ROOM_MATERIALS.hasOwnProperty(property) && + materials.hasOwnProperty(property)) { + if (materials[property] in Utils.ROOM_MATERIAL_COEFFICIENTS) { + coefficients[property] = + Utils.ROOM_MATERIAL_COEFFICIENTS[materials[property]]; + } + else { + Utils.log('Material \"' + materials[property] + '\" on wall \"' + + property + '\" not found. Using \"' + + Utils.DEFAULT_ROOM_MATERIALS[property] + '\".'); + } + } + else { + Utils.log('Wall \"' + property + '\" is not defined. Default used.'); + } + } + return coefficients; +} +/** + * Sanitize coefficients. + * @param {Object} coefficients + * @return {Object} + */ +function _sanitizeCoefficients(coefficients) { + if (coefficients == undefined) { + coefficients = {}; + } + for (let property in Utils.DEFAULT_ROOM_MATERIALS) { + if (!(coefficients.hasOwnProperty(property))) { + // If element is not present, use default coefficients. + coefficients[property] = Utils.ROOM_MATERIAL_COEFFICIENTS[Utils.DEFAULT_ROOM_MATERIALS[property]]; + } + } + return coefficients; +} +/** + * Sanitize dimensions. + * @param {Utils~RoomDimensions} dimensions + * @return {Utils~RoomDimensions} + */ +function _sanitizeDimensions(dimensions) { + if (dimensions == undefined) { + dimensions = {}; + } + for (let property in Utils.DEFAULT_ROOM_DIMENSIONS) { + if (!(dimensions.hasOwnProperty(property))) { + dimensions[property] = Utils.DEFAULT_ROOM_DIMENSIONS[property]; + } + } + return dimensions; +} +/** + * Compute frequency-dependent reverb durations. + * @param {Utils~RoomDimensions} dimensions + * @param {Object} coefficients + * @param {Number} speedOfSound + * @return {Array} + */ +function _getDurationsFromProperties(dimensions, coefficients, speedOfSound) { + let durations = new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); + // Sanitize inputs. + dimensions = _sanitizeDimensions(dimensions); + coefficients = _sanitizeCoefficients(coefficients); + if (speedOfSound == undefined) { + speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + // Acoustic constant. + let k = Utils.TWENTY_FOUR_LOG10 / speedOfSound; + // Compute volume, skip if room is not present. + let volume = dimensions.width * dimensions.height * dimensions.depth; + if (volume < Utils.ROOM_MIN_VOLUME) { + return durations; + } + // Room surface area. + let leftRightArea = dimensions.width * dimensions.height; + let floorCeilingArea = dimensions.width * dimensions.depth; + let frontBackArea = dimensions.depth * dimensions.height; + let totalArea = 2 * (leftRightArea + floorCeilingArea + frontBackArea); + for (let i = 0; i < Utils.NUMBER_REVERB_FREQUENCY_BANDS; i++) { + // Effective absorptive area. + let absorbtionArea = (coefficients.left[i] + coefficients.right[i]) * leftRightArea + + (coefficients.down[i] + coefficients.up[i]) * floorCeilingArea + + (coefficients.front[i] + coefficients.back[i]) * frontBackArea; + let meanAbsorbtionArea = absorbtionArea / totalArea; + // Compute reverberation using Eyring equation [1]. + // [1] Beranek, Leo L. "Analysis of Sabine and Eyring equations and their + // application to concert hall audience and chair absorption." The + // Journal of the Acoustical Society of America, Vol. 120, No. 3. + // (2006), pp. 1399-1399. + durations[i] = Utils.ROOM_EYRING_CORRECTION_COEFFICIENT * k * volume / + (-totalArea * Math.log(1 - meanAbsorbtionArea) + 4 * + Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS[i] * volume); + } + return durations; +} +/** + * Compute reflection coefficients from absorption coefficients. + * @param {Object} absorptionCoefficients + * @return {Object} + */ +function _computeReflectionCoefficients(absorptionCoefficients) { + let reflectionCoefficients = []; + for (let property in Utils.DEFAULT_REFLECTION_COEFFICIENTS) { + if (Utils.DEFAULT_REFLECTION_COEFFICIENTS + .hasOwnProperty(property)) { + // Compute average absorption coefficient (per wall). + reflectionCoefficients[property] = 0; + for (let j = 0; j < Utils.NUMBER_REFLECTION_AVERAGING_BANDS; j++) { + let bandIndex = j + Utils.ROOM_STARTING_AVERAGING_BAND; + reflectionCoefficients[property] += + absorptionCoefficients[property][bandIndex]; + } + reflectionCoefficients[property] /= + Utils.NUMBER_REFLECTION_AVERAGING_BANDS; + // Convert absorption coefficient to reflection coefficient. + reflectionCoefficients[property] = + Math.sqrt(1 - reflectionCoefficients[property]); + } + } + return reflectionCoefficients; +} +/** + * @class Room + * @description Model that manages early and late reflections using acoustic + * properties and listener position relative to a rectangular room. + * @param {AudioContext} context + * Associated {@link +https://developer.mozilla.org/en-US/docs/Web/API/AudioContext AudioContext}. + * @param {Object} options + * @param {Float32Array} options.listenerPosition + * The listener's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @param {Utils~RoomDimensions} options.dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} options.materials Named acoustic materials per wall. + * Defaults to {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + * @param {Number} options.speedOfSound + * (in meters/second). Defaults to + * {@linkcode Utils.DEFAULT_SPEED_OF_SOUND DEFAULT_SPEED_OF_SOUND}. + */ +class Room { + constructor(context, options) { + // Public variables. + /** + * EarlyReflections {@link EarlyReflections EarlyReflections} submodule. + * @member {AudioNode} early + * @memberof Room + * @instance + */ + /** + * LateReflections {@link LateReflections LateReflections} submodule. + * @member {AudioNode} late + * @memberof Room + * @instance + */ + /** + * Ambisonic (multichannel) output {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} output + * @memberof Room + * @instance + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.listenerPosition == undefined) { + options.listenerPosition = Utils.DEFAULT_POSITION.slice(); + } + if (options.dimensions == undefined) { + options.dimensions = {}; + Object.assign(options.dimensions, Utils.DEFAULT_ROOM_DIMENSIONS); + } + if (options.materials == undefined) { + options.materials = {}; + Object.assign(options.materials, Utils.DEFAULT_ROOM_MATERIALS); + } + if (options.speedOfSound == undefined) { + options.speedOfSound = Utils.DEFAULT_SPEED_OF_SOUND; + } + // Sanitize room-properties-related arguments. + options.dimensions = _sanitizeDimensions(options.dimensions); + let absorptionCoefficients = _getCoefficientsFromMaterials(options.materials); + let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients); + let durations = _getDurationsFromProperties(options.dimensions, absorptionCoefficients, options.speedOfSound); + // Construct submodules for early and late reflections. + this.early = new EarlyReflections(context, { + dimensions: options.dimensions, + coefficients: reflectionCoefficients, + speedOfSound: options.speedOfSound, + listenerPosition: options.listenerPosition, + }); + this.late = new LateReflections(context, { + durations: durations, + }); + this.speedOfSound = options.speedOfSound; + // Construct auxillary audio nodes. + this.output = context.createGain(); + this.early.output.connect(this.output); + this._merger = context.createChannelMerger(4); + this.late.output.connect(this._merger, 0, 0); + this._merger.connect(this.output); + } + /** + * Set the room's dimensions and wall materials. + * @param {Utils~RoomDimensions} dimensions Room dimensions (in meters). Defaults to + * {@linkcode Utils.DEFAULT_ROOM_DIMENSIONS DEFAULT_ROOM_DIMENSIONS}. + * @param {Utils~RoomMaterials} materials Named acoustic materials per wall. Defaults to + * {@linkcode Utils.DEFAULT_ROOM_MATERIALS DEFAULT_ROOM_MATERIALS}. + */ + setProperties(dimensions, materials) { + // Compute late response. + let absorptionCoefficients = _getCoefficientsFromMaterials(materials); + let durations = _getDurationsFromProperties(dimensions, absorptionCoefficients, this.speedOfSound); + this.late.setDurations(durations); + // Compute early response. + this.early.speedOfSound = this.speedOfSound; + let reflectionCoefficients = _computeReflectionCoefficients(absorptionCoefficients); + this.early.setRoomProperties(dimensions, reflectionCoefficients); + } + /** + * Set the listener's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setListenerPosition(x, y, z) { + this.early.speedOfSound = this.speedOfSound; + this.early.setListenerPosition(x, y, z); + // Disable room effects if the listener is outside the room boundaries. + let distance = this.getDistanceOutsideRoom(x, y, z); + let gain = 1; + if (distance > Utils.EPSILON_FLOAT) { + gain = 1 - distance / Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE; + // Clamp gain between 0 and 1. + gain = Math.max(0, Math.min(1, gain)); + } + this.output.gain.value = gain; + } + /** + * Compute distance outside room of provided position (in meters). + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @return {Number} + * Distance outside room (in meters). Returns 0 if inside room. + */ + getDistanceOutsideRoom(x, y, z) { + let dx = Math.max(0, -this.early._halfDimensions.width - x, x - this.early._halfDimensions.width); + let dy = Math.max(0, -this.early._halfDimensions.height - y, y - this.early._halfDimensions.height); + let dz = Math.max(0, -this.early._halfDimensions.depth - z, z - this.early._halfDimensions.depth); + return Math.sqrt(dx * dx + dy * dy + dz * dz); + } +} +export default Room; diff --git a/src/framework/resonator/vendor/resonance-es6/source.d.ts b/src/framework/resonator/vendor/resonance-es6/source.d.ts index bf24786..cdb9510 100644 --- a/src/framework/resonator/vendor/resonance-es6/source.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/source.d.ts @@ -1,182 +1,182 @@ -export default Source; -/** - * ~SourceOptions - */ -export type Source = { - /** - * The source's initial position (in meters), where origin is the center of - * the room. Defaults to {@link Utils.DEFAULT_POSITION DEFAULT_POSITION}. - */ - position: Float32Array; - /** - * The source's initial forward vector. Defaults to - * {@link Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - */ - forward: Float32Array; - /** - * The source's initial up vector. Defaults to - * {@link Utils.DEFAULT_UP DEFAULT_UP}. - */ - up: Float32Array; - /** - * Min. distance (in meters). Defaults to - * {@link Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. - */ - minDistance: number; - /** - * Max. distance (in meters). Defaults to - * {@link Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. - */ - maxDistance: number; - /** - * Rolloff model to use, chosen from options in - * {@link Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to - * {@link Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. - */ - rolloff: string; - /** - * Input gain (linear). Defaults to - * {@link Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. - */ - gain: number; - /** - * Directivity alpha. Defaults to - * {@link Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. - */ - alpha: number; - /** - * Directivity sharpness. Defaults to - * {@link Utils.DEFAULT_DIRECTIVITY_SHARPNESS * DEFAULT_DIRECTIVITY_SHARPNESS}. - */ - sharpness: number; - /** - * Source width (in degrees). Where 0 degrees is a point source and 360 degrees - * is an omnidirectional source. Defaults to - * {@link Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. - */ - sourceWidth: number; -}; -/** - * Options for constructing a new Source. - * @typedef {Object} Source~SourceOptions - * @property {Float32Array} position - * The source's initial position (in meters), where origin is the center of - * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @property {Float32Array} forward - * The source's initial forward vector. Defaults to - * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - * @property {Float32Array} up - * The source's initial up vector. Defaults to - * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. - * @property {Number} minDistance - * Min. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. - * @property {Number} maxDistance - * Max. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. - * @property {string} rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to - * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. - * @property {Number} gain Input gain (linear). Defaults to - * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. - * @property {Number} alpha Directivity alpha. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. - * @property {Number} sharpness Directivity sharpness. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS - * DEFAULT_DIRECTIVITY_SHARPNESS}. - * @property {Number} sourceWidth - * Source width (in degrees). Where 0 degrees is a point source and 360 degrees - * is an omnidirectional source. Defaults to - * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. - */ -/** - * @class Source - * @description Source model to spatialize an audio buffer. - * @param {ResonanceAudio} scene Associated {@link ResonanceAudio - * ResonanceAudio} instance. - * @param {Source~SourceOptions} options - * Options for constructing a new Source. - */ -declare class Source { - constructor(scene: any, options: any); - _scene: any; - _position: any; - _forward: any; - _up: any; - _dx: Float32Array; - _right: Float32Array; - input: any; - _directivity: Directivity; - _toEarly: any; - _toLate: any; - _attenuation: Attenuation; - _encoder: Encoder; - /** - * Set source's position (in meters), where origin is the center of - * the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setPosition(x: number, y: number, z: number): void; - _update(): void; - /** - * Set source's rolloff. - * @param {string} rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. - */ - setRolloff(rolloff: string): void; - /** - * Set source's minimum distance (in meters). - * @param {Number} minDistance - */ - setMinDistance(minDistance: number): void; - /** - * Set source's maximum distance (in meters). - * @param {Number} maxDistance - */ - setMaxDistance(maxDistance: number): void; - /** - * Set source's gain (linear). - * @param {Number} gain - */ - setGain(gain: number): void; - /** - * Set the source's orientation using forward and up vectors. - * @param {Number} forwardX - * @param {Number} forwardY - * @param {Number} forwardZ - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - */ - setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; - /** - * Set source's position and orientation using a - * Three.js modelViewMatrix object. - * @param {Float32Array} matrix4 - * The Matrix4 representing the object position and rotation in world space. - */ - setFromMatrix(matrix4: Float32Array): void; - /** - * Set the source width (in degrees). Where 0 degrees is a point source and 360 - * degrees is an omnidirectional source. - * @param {Number} sourceWidth (in degrees). - */ - setSourceWidth(sourceWidth: number): void; - /** - * Set source's directivity pattern (defined by alpha), where 0 is an - * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod - * pattern. The sharpness of the pattern is increased exponentially. - * @param {Number} alpha - * Determines directivity pattern (0 to 1). - * @param {Number} sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). - */ - setDirectivityPattern(alpha: number, sharpness: number): void; -} -import Directivity from "./directivity.js"; -import Attenuation from "./attenuation.js"; -import Encoder from "./encoder.js"; +export default Source; +/** + * ~SourceOptions + */ +export type Source = { + /** + * The source's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + */ + position: Float32Array; + /** + * The source's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + */ + forward: Float32Array; + /** + * The source's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + */ + up: Float32Array; + /** + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + */ + minDistance: number; + /** + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + */ + maxDistance: number; + /** + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + */ + rolloff: string; + /** + * Input gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. + */ + gain: number; + /** + * Directivity alpha. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + */ + alpha: number; + /** + * Directivity sharpness. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS * DEFAULT_DIRECTIVITY_SHARPNESS}. + */ + sharpness: number; + /** + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ + sourceWidth: number; +}; +/** + * Options for constructing a new Source. + * @typedef {Object} Source~SourceOptions + * @property {Float32Array} position + * The source's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} forward + * The source's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} up + * The source's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Number} minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @property {Number} maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @property {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + * @property {Number} gain Input gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. + * @property {Number} alpha Directivity alpha. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @property {Number} sharpness Directivity sharpness. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + * @property {Number} sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +/** + * @class Source + * @description Source model to spatialize an audio buffer. + * @param {ResonanceAudio} scene Associated {@link ResonanceAudio + * ResonanceAudio} instance. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + */ +declare class Source { + constructor(scene: any, options: any); + _scene: any; + _position: any; + _forward: any; + _up: any; + _dx: Float32Array; + _right: Float32Array; + input: any; + _directivity: Directivity; + _toEarly: any; + _toLate: any; + _attenuation: Attenuation; + _encoder: Encoder; + /** + * Set source's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setPosition(x: number, y: number, z: number): void; + _update(): void; + /** + * Set source's rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff: string): void; + /** + * Set source's minimum distance (in meters). + * @param {Number} minDistance + */ + setMinDistance(minDistance: number): void; + /** + * Set source's maximum distance (in meters). + * @param {Number} maxDistance + */ + setMaxDistance(maxDistance: number): void; + /** + * Set source's gain (linear). + * @param {Number} gain + */ + setGain(gain: number): void; + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX: number, forwardY: number, forwardZ: number, upX: number, upY: number, upZ: number): void; + /** + * Set source's position and orientation using a + * Three.js modelViewMatrix object. + * @param {Float32Array} matrix4 + * The Matrix4 representing the object position and rotation in world space. + */ + setFromMatrix(matrix4: Float32Array): void; + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth: number): void; + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + */ + setDirectivityPattern(alpha: number, sharpness: number): void; +} +import Directivity from "./directivity.js"; +import Attenuation from "./attenuation.js"; +import Encoder from "./encoder.js"; diff --git a/src/framework/resonator/vendor/resonance-es6/source.js b/src/framework/resonator/vendor/resonance-es6/source.js index 510a9ca..61a7cf9 100644 --- a/src/framework/resonator/vendor/resonance-es6/source.js +++ b/src/framework/resonator/vendor/resonance-es6/source.js @@ -1,308 +1,308 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Source model to spatialize an audio buffer. - * @author Andrew Allen - */ -'use strict'; -// Internal dependencies. -import Directivity from './directivity.js'; -import Attenuation from './attenuation.js'; -import Encoder from './encoder.js'; -import Utils from './utils.js'; -/** - * Options for constructing a new Source. - * @typedef {Object} Source~SourceOptions - * @property {Float32Array} position - * The source's initial position (in meters), where origin is the center of - * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. - * @property {Float32Array} forward - * The source's initial forward vector. Defaults to - * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. - * @property {Float32Array} up - * The source's initial up vector. Defaults to - * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. - * @property {Number} minDistance - * Min. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. - * @property {Number} maxDistance - * Max. distance (in meters). Defaults to - * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. - * @property {string} rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to - * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. - * @property {Number} gain Input gain (linear). Defaults to - * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. - * @property {Number} alpha Directivity alpha. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. - * @property {Number} sharpness Directivity sharpness. Defaults to - * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS - * DEFAULT_DIRECTIVITY_SHARPNESS}. - * @property {Number} sourceWidth - * Source width (in degrees). Where 0 degrees is a point source and 360 degrees - * is an omnidirectional source. Defaults to - * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. - */ -/** - * @class Source - * @description Source model to spatialize an audio buffer. - * @param {ResonanceAudio} scene Associated {@link ResonanceAudio - * ResonanceAudio} instance. - * @param {Source~SourceOptions} options - * Options for constructing a new Source. - */ -class Source { - constructor(scene, options) { - // Public variables. - /** - * Mono (1-channel) input {@link - * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. - * @member {AudioNode} input - * @memberof Source - * @instance - */ - /** - * - */ - // Use defaults for undefined arguments. - if (options == undefined) { - options = {}; - } - if (options.position == undefined) { - options.position = Utils.DEFAULT_POSITION.slice(); - } - if (options.forward == undefined) { - options.forward = Utils.DEFAULT_FORWARD.slice(); - } - if (options.up == undefined) { - options.up = Utils.DEFAULT_UP.slice(); - } - if (options.minDistance == undefined) { - options.minDistance = Utils.DEFAULT_MIN_DISTANCE; - } - if (options.maxDistance == undefined) { - options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; - } - if (options.rolloff == undefined) { - options.rolloff = Utils.DEFAULT_ROLLOFF; - } - if (options.gain == undefined) { - options.gain = Utils.DEFAULT_SOURCE_GAIN; - } - if (options.alpha == undefined) { - options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA; - } - if (options.sharpness == undefined) { - options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS; - } - if (options.sourceWidth == undefined) { - options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH; - } - // Member variables. - this._scene = scene; - this._position = options.position; - this._forward = options.forward; - this._up = options.up; - this._dx = new Float32Array(3); - this._right = Utils.crossProduct(this._forward, this._up); - // Create audio nodes. - let context = scene._context; - this.input = context.createGain(); - this._directivity = new Directivity(context, { - alpha: options.alpha, - sharpness: options.sharpness, - }); - this._toEarly = context.createGain(); - this._toLate = context.createGain(); - this._attenuation = new Attenuation(context, { - minDistance: options.minDistance, - maxDistance: options.maxDistance, - rolloff: options.rolloff, - }); - this._encoder = new Encoder(context, { - ambisonicOrder: scene._ambisonicOrder, - sourceWidth: options.sourceWidth, - }); - // Connect nodes. - this.input.connect(this._toLate); - this._toLate.connect(scene._room.late.input); - this.input.connect(this._attenuation.input); - this._attenuation.output.connect(this._toEarly); - this._toEarly.connect(scene._room.early.input); - this._attenuation.output.connect(this._directivity.input); - this._directivity.output.connect(this._encoder.input); - this._encoder.output.connect(scene._listener.input); - // Assign initial conditions. - this.setPosition(options.position[0], options.position[1], options.position[2]); - this.input.gain.value = options.gain; - } - /** - * Set source's position (in meters), where origin is the center of - * the room. - * @param {Number} x - * @param {Number} y - * @param {Number} z - */ - setPosition(x, y, z) { - // Assign new position. - this._position[0] = x; - this._position[1] = y; - this._position[2] = z; - // Handle far-field effect. - let distance = this._scene._room.getDistanceOutsideRoom(this._position[0], this._position[1], this._position[2]); - let gain = _computeDistanceOutsideRoom(distance); - this._toLate.gain.value = gain; - this._toEarly.gain.value = gain; - this._update(); - } - // Update the source when changing the listener's position. - _update() { - // Compute distance to listener. - for (let i = 0; i < 3; i++) { - this._dx[i] = this._position[i] - this._scene._listener.position[i]; - } - let distance = Math.sqrt(this._dx[0] * this._dx[0] + - this._dx[1] * this._dx[1] + this._dx[2] * this._dx[2]); - if (distance > 0) { - // Normalize direction vector. - this._dx[0] /= distance; - this._dx[1] /= distance; - this._dx[2] /= distance; - } - // Compuete angle of direction vector. - let azimuth = Math.atan2(-this._dx[0], this._dx[2]) * - Utils.RADIANS_TO_DEGREES; - let elevation = Math.atan2(this._dx[1], Math.sqrt(this._dx[0] * this._dx[0] + - this._dx[2] * this._dx[2])) * Utils.RADIANS_TO_DEGREES; - // Set distance/directivity/direction values. - this._attenuation.setDistance(distance); - this._directivity.computeAngle(this._forward, this._dx); - this._encoder.setDirection(azimuth, elevation); - } - /** - * Set source's rolloff. - * @param {string} rolloff - * Rolloff model to use, chosen from options in - * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. - */ - setRolloff(rolloff) { - this._attenuation.setRolloff(rolloff); - } - /** - * Set source's minimum distance (in meters). - * @param {Number} minDistance - */ - setMinDistance(minDistance) { - this._attenuation.minDistance = minDistance; - } - /** - * Set source's maximum distance (in meters). - * @param {Number} maxDistance - */ - setMaxDistance(maxDistance) { - this._attenuation.maxDistance = maxDistance; - } - /** - * Set source's gain (linear). - * @param {Number} gain - */ - setGain(gain) { - this.input.gain.value = gain; - } - /** - * Set the source's orientation using forward and up vectors. - * @param {Number} forwardX - * @param {Number} forwardY - * @param {Number} forwardZ - * @param {Number} upX - * @param {Number} upY - * @param {Number} upZ - */ - setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { - this._forward[0] = forwardX; - this._forward[1] = forwardY; - this._forward[2] = forwardZ; - this._up[0] = upX; - this._up[1] = upY; - this._up[2] = upZ; - this._right = Utils.crossProduct(this._forward, this._up); - } - // TODO(bitllama): Make sure this works with Three.js as intended. - /** - * Set source's position and orientation using a - * Three.js modelViewMatrix object. - * @param {Float32Array} matrix4 - * The Matrix4 representing the object position and rotation in world space. - */ - setFromMatrix(matrix4) { - this._right[0] = matrix4.elements[0]; - this._right[1] = matrix4.elements[1]; - this._right[2] = matrix4.elements[2]; - this._up[0] = matrix4.elements[4]; - this._up[1] = matrix4.elements[5]; - this._up[2] = matrix4.elements[6]; - this._forward[0] = matrix4.elements[8]; - this._forward[1] = matrix4.elements[9]; - this._forward[2] = matrix4.elements[10]; - // Normalize to remove scaling. - this._right = Utils.normalizeVector(this._right); - this._up = Utils.normalizeVector(this._up); - this._forward = Utils.normalizeVector(this._forward); - // Update position. - this.setPosition(matrix4.elements[12], matrix4.elements[13], matrix4.elements[14]); - } - /** - * Set the source width (in degrees). Where 0 degrees is a point source and 360 - * degrees is an omnidirectional source. - * @param {Number} sourceWidth (in degrees). - */ - setSourceWidth(sourceWidth) { - this._encoder.setSourceWidth(sourceWidth); - this.setPosition(this._position[0], this._position[1], this._position[2]); - } - /** - * Set source's directivity pattern (defined by alpha), where 0 is an - * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod - * pattern. The sharpness of the pattern is increased exponentially. - * @param {Number} alpha - * Determines directivity pattern (0 to 1). - * @param {Number} sharpness - * Determines the sharpness of the directivity pattern (1 to Inf). - */ - setDirectivityPattern(alpha, sharpness) { - this._directivity.setPattern(alpha, sharpness); - this.setPosition(this._position[0], this._position[1], this._position[2]); - } -} -/** - * Determine the distance a source is outside of a room. Attenuate gain going - * to the reflections and reverb when the source is outside of the room. - * @param {Number} distance Distance in meters. - * @return {Number} Gain (linear) of source. - * @private - */ -function _computeDistanceOutsideRoom(distance) { - // We apply a linear ramp from 1 to 0 as the source is up to 1m outside. - let gain = 1; - if (distance > Utils.EPSILON_FLOAT) { - gain = 1 - distance / Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE; - // Clamp gain between 0 and 1. - gain = Math.max(0, Math.min(1, gain)); - } - return gain; -} -export default Source; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Source model to spatialize an audio buffer. + * @author Andrew Allen + */ +'use strict'; +// Internal dependencies. +import Directivity from './directivity.js'; +import Attenuation from './attenuation.js'; +import Encoder from './encoder.js'; +import Utils from './utils.js'; +/** + * Options for constructing a new Source. + * @typedef {Object} Source~SourceOptions + * @property {Float32Array} position + * The source's initial position (in meters), where origin is the center of + * the room. Defaults to {@linkcode Utils.DEFAULT_POSITION DEFAULT_POSITION}. + * @property {Float32Array} forward + * The source's initial forward vector. Defaults to + * {@linkcode Utils.DEFAULT_FORWARD DEFAULT_FORWARD}. + * @property {Float32Array} up + * The source's initial up vector. Defaults to + * {@linkcode Utils.DEFAULT_UP DEFAULT_UP}. + * @property {Number} minDistance + * Min. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MIN_DISTANCE DEFAULT_MIN_DISTANCE}. + * @property {Number} maxDistance + * Max. distance (in meters). Defaults to + * {@linkcode Utils.DEFAULT_MAX_DISTANCE DEFAULT_MAX_DISTANCE}. + * @property {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. Defaults to + * {@linkcode Utils.DEFAULT_ATTENUATION_ROLLOFF DEFAULT_ATTENUATION_ROLLOFF}. + * @property {Number} gain Input gain (linear). Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_GAIN DEFAULT_SOURCE_GAIN}. + * @property {Number} alpha Directivity alpha. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_ALPHA DEFAULT_DIRECTIVITY_ALPHA}. + * @property {Number} sharpness Directivity sharpness. Defaults to + * {@linkcode Utils.DEFAULT_DIRECTIVITY_SHARPNESS + * DEFAULT_DIRECTIVITY_SHARPNESS}. + * @property {Number} sourceWidth + * Source width (in degrees). Where 0 degrees is a point source and 360 degrees + * is an omnidirectional source. Defaults to + * {@linkcode Utils.DEFAULT_SOURCE_WIDTH DEFAULT_SOURCE_WIDTH}. + */ +/** + * @class Source + * @description Source model to spatialize an audio buffer. + * @param {ResonanceAudio} scene Associated {@link ResonanceAudio + * ResonanceAudio} instance. + * @param {Source~SourceOptions} options + * Options for constructing a new Source. + */ +class Source { + constructor(scene, options) { + // Public variables. + /** + * Mono (1-channel) input {@link + * https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNode}. + * @member {AudioNode} input + * @memberof Source + * @instance + */ + /** + * + */ + // Use defaults for undefined arguments. + if (options == undefined) { + options = {}; + } + if (options.position == undefined) { + options.position = Utils.DEFAULT_POSITION.slice(); + } + if (options.forward == undefined) { + options.forward = Utils.DEFAULT_FORWARD.slice(); + } + if (options.up == undefined) { + options.up = Utils.DEFAULT_UP.slice(); + } + if (options.minDistance == undefined) { + options.minDistance = Utils.DEFAULT_MIN_DISTANCE; + } + if (options.maxDistance == undefined) { + options.maxDistance = Utils.DEFAULT_MAX_DISTANCE; + } + if (options.rolloff == undefined) { + options.rolloff = Utils.DEFAULT_ROLLOFF; + } + if (options.gain == undefined) { + options.gain = Utils.DEFAULT_SOURCE_GAIN; + } + if (options.alpha == undefined) { + options.alpha = Utils.DEFAULT_DIRECTIVITY_ALPHA; + } + if (options.sharpness == undefined) { + options.sharpness = Utils.DEFAULT_DIRECTIVITY_SHARPNESS; + } + if (options.sourceWidth == undefined) { + options.sourceWidth = Utils.DEFAULT_SOURCE_WIDTH; + } + // Member variables. + this._scene = scene; + this._position = options.position; + this._forward = options.forward; + this._up = options.up; + this._dx = new Float32Array(3); + this._right = Utils.crossProduct(this._forward, this._up); + // Create audio nodes. + let context = scene._context; + this.input = context.createGain(); + this._directivity = new Directivity(context, { + alpha: options.alpha, + sharpness: options.sharpness, + }); + this._toEarly = context.createGain(); + this._toLate = context.createGain(); + this._attenuation = new Attenuation(context, { + minDistance: options.minDistance, + maxDistance: options.maxDistance, + rolloff: options.rolloff, + }); + this._encoder = new Encoder(context, { + ambisonicOrder: scene._ambisonicOrder, + sourceWidth: options.sourceWidth, + }); + // Connect nodes. + this.input.connect(this._toLate); + this._toLate.connect(scene._room.late.input); + this.input.connect(this._attenuation.input); + this._attenuation.output.connect(this._toEarly); + this._toEarly.connect(scene._room.early.input); + this._attenuation.output.connect(this._directivity.input); + this._directivity.output.connect(this._encoder.input); + this._encoder.output.connect(scene._listener.input); + // Assign initial conditions. + this.setPosition(options.position[0], options.position[1], options.position[2]); + this.input.gain.value = options.gain; + } + /** + * Set source's position (in meters), where origin is the center of + * the room. + * @param {Number} x + * @param {Number} y + * @param {Number} z + */ + setPosition(x, y, z) { + // Assign new position. + this._position[0] = x; + this._position[1] = y; + this._position[2] = z; + // Handle far-field effect. + let distance = this._scene._room.getDistanceOutsideRoom(this._position[0], this._position[1], this._position[2]); + let gain = _computeDistanceOutsideRoom(distance); + this._toLate.gain.value = gain; + this._toEarly.gain.value = gain; + this._update(); + } + // Update the source when changing the listener's position. + _update() { + // Compute distance to listener. + for (let i = 0; i < 3; i++) { + this._dx[i] = this._position[i] - this._scene._listener.position[i]; + } + let distance = Math.sqrt(this._dx[0] * this._dx[0] + + this._dx[1] * this._dx[1] + this._dx[2] * this._dx[2]); + if (distance > 0) { + // Normalize direction vector. + this._dx[0] /= distance; + this._dx[1] /= distance; + this._dx[2] /= distance; + } + // Compuete angle of direction vector. + let azimuth = Math.atan2(-this._dx[0], this._dx[2]) * + Utils.RADIANS_TO_DEGREES; + let elevation = Math.atan2(this._dx[1], Math.sqrt(this._dx[0] * this._dx[0] + + this._dx[2] * this._dx[2])) * Utils.RADIANS_TO_DEGREES; + // Set distance/directivity/direction values. + this._attenuation.setDistance(distance); + this._directivity.computeAngle(this._forward, this._dx); + this._encoder.setDirection(azimuth, elevation); + } + /** + * Set source's rolloff. + * @param {string} rolloff + * Rolloff model to use, chosen from options in + * {@linkcode Utils.ATTENUATION_ROLLOFFS ATTENUATION_ROLLOFFS}. + */ + setRolloff(rolloff) { + this._attenuation.setRolloff(rolloff); + } + /** + * Set source's minimum distance (in meters). + * @param {Number} minDistance + */ + setMinDistance(minDistance) { + this._attenuation.minDistance = minDistance; + } + /** + * Set source's maximum distance (in meters). + * @param {Number} maxDistance + */ + setMaxDistance(maxDistance) { + this._attenuation.maxDistance = maxDistance; + } + /** + * Set source's gain (linear). + * @param {Number} gain + */ + setGain(gain) { + this.input.gain.value = gain; + } + /** + * Set the source's orientation using forward and up vectors. + * @param {Number} forwardX + * @param {Number} forwardY + * @param {Number} forwardZ + * @param {Number} upX + * @param {Number} upY + * @param {Number} upZ + */ + setOrientation(forwardX, forwardY, forwardZ, upX, upY, upZ) { + this._forward[0] = forwardX; + this._forward[1] = forwardY; + this._forward[2] = forwardZ; + this._up[0] = upX; + this._up[1] = upY; + this._up[2] = upZ; + this._right = Utils.crossProduct(this._forward, this._up); + } + // TODO(bitllama): Make sure this works with Three.js as intended. + /** + * Set source's position and orientation using a + * Three.js modelViewMatrix object. + * @param {Float32Array} matrix4 + * The Matrix4 representing the object position and rotation in world space. + */ + setFromMatrix(matrix4) { + this._right[0] = matrix4.elements[0]; + this._right[1] = matrix4.elements[1]; + this._right[2] = matrix4.elements[2]; + this._up[0] = matrix4.elements[4]; + this._up[1] = matrix4.elements[5]; + this._up[2] = matrix4.elements[6]; + this._forward[0] = matrix4.elements[8]; + this._forward[1] = matrix4.elements[9]; + this._forward[2] = matrix4.elements[10]; + // Normalize to remove scaling. + this._right = Utils.normalizeVector(this._right); + this._up = Utils.normalizeVector(this._up); + this._forward = Utils.normalizeVector(this._forward); + // Update position. + this.setPosition(matrix4.elements[12], matrix4.elements[13], matrix4.elements[14]); + } + /** + * Set the source width (in degrees). Where 0 degrees is a point source and 360 + * degrees is an omnidirectional source. + * @param {Number} sourceWidth (in degrees). + */ + setSourceWidth(sourceWidth) { + this._encoder.setSourceWidth(sourceWidth); + this.setPosition(this._position[0], this._position[1], this._position[2]); + } + /** + * Set source's directivity pattern (defined by alpha), where 0 is an + * omnidirectional pattern, 1 is a bidirectional pattern, 0.5 is a cardiod + * pattern. The sharpness of the pattern is increased exponentially. + * @param {Number} alpha + * Determines directivity pattern (0 to 1). + * @param {Number} sharpness + * Determines the sharpness of the directivity pattern (1 to Inf). + */ + setDirectivityPattern(alpha, sharpness) { + this._directivity.setPattern(alpha, sharpness); + this.setPosition(this._position[0], this._position[1], this._position[2]); + } +} +/** + * Determine the distance a source is outside of a room. Attenuate gain going + * to the reflections and reverb when the source is outside of the room. + * @param {Number} distance Distance in meters. + * @return {Number} Gain (linear) of source. + * @private + */ +function _computeDistanceOutsideRoom(distance) { + // We apply a linear ramp from 1 to 0 as the source is up to 1m outside. + let gain = 1; + if (distance > Utils.EPSILON_FLOAT) { + gain = 1 - distance / Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE; + // Clamp gain between 0 and 1. + gain = Math.max(0, Math.min(1, gain)); + } + return gain; +} +export default Source; diff --git a/src/framework/resonator/vendor/resonance-es6/tables.d.ts b/src/framework/resonator/vendor/resonance-es6/tables.d.ts index 4116808..29723fc 100644 --- a/src/framework/resonator/vendor/resonance-es6/tables.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/tables.d.ts @@ -1,38 +1,38 @@ -declare namespace _default { - export { SPHERICAL_HARMONICS }; - export { SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION }; - export { SPHERICAL_HARMONICS_ELEVATION_RESOLUTION }; - export { SPHERICAL_HARMONICS_MAX_ORDER }; - export { MAX_RE_WEIGHTS }; - export { MAX_RE_WEIGHTS_RESOLUTION }; -} -export default _default; -/** - * Pre-computed Spherical Harmonics Coefficients. - * - * This function generates an efficient lookup table of SH coefficients. It - * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm - * & Plm coefficients only depend on theta, and Em only depends on phi, we - * can separate the equation along these lines. Em does not depend on - * degree, so we only need to compute (2 * l) per azimuth Em total and - * Nlm * Plm is symmetrical across indexes, so only positive indexes are - * computed ((l + 1) * (l + 2) / 2 - 1) per elevation. - * @type {Float32Array} - */ -declare const SPHERICAL_HARMONICS: Float32Array; -/** @type {Number} */ -declare const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION: number; -/** @type {Number} */ -declare const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION: number; -/** - * The maximum allowed ambisonic order. - * @type {Number} - */ -declare const SPHERICAL_HARMONICS_MAX_ORDER: number; -/** - * Pre-computed per-band weighting coefficients for producing energy-preserving - * Max-Re sources. - */ -declare const MAX_RE_WEIGHTS: number[][]; -/** @type {Number} */ -declare const MAX_RE_WEIGHTS_RESOLUTION: number; +declare namespace _default { + export { SPHERICAL_HARMONICS }; + export { SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION }; + export { SPHERICAL_HARMONICS_ELEVATION_RESOLUTION }; + export { SPHERICAL_HARMONICS_MAX_ORDER }; + export { MAX_RE_WEIGHTS }; + export { MAX_RE_WEIGHTS_RESOLUTION }; +} +export default _default; +/** + * Pre-computed Spherical Harmonics Coefficients. + * + * This function generates an efficient lookup table of SH coefficients. It + * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm + * & Plm coefficients only depend on theta, and Em only depends on phi, we + * can separate the equation along these lines. Em does not depend on + * degree, so we only need to compute (2 * l) per azimuth Em total and + * Nlm * Plm is symmetrical across indexes, so only positive indexes are + * computed ((l + 1) * (l + 2) / 2 - 1) per elevation. + * @type {Float32Array} + */ +declare const SPHERICAL_HARMONICS: Float32Array; +/** @type {Number} */ +declare const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION: number; +/** @type {Number} */ +declare const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION: number; +/** + * The maximum allowed ambisonic order. + * @type {Number} + */ +declare const SPHERICAL_HARMONICS_MAX_ORDER: number; +/** + * Pre-computed per-band weighting coefficients for producing energy-preserving + * Max-Re sources. + */ +declare const MAX_RE_WEIGHTS: number[][]; +/** @type {Number} */ +declare const MAX_RE_WEIGHTS_RESOLUTION: number; diff --git a/src/framework/resonator/vendor/resonance-es6/tables.js b/src/framework/resonator/vendor/resonance-es6/tables.js index 90117bf..fa3aae5 100644 --- a/src/framework/resonator/vendor/resonance-es6/tables.js +++ b/src/framework/resonator/vendor/resonance-es6/tables.js @@ -1,1144 +1,1144 @@ -/** - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 Pre-computed lookup tables for encoding ambisonic sources. - * @author Andrew Allen - */ -'use strict'; -/** - * Pre-computed Spherical Harmonics Coefficients. - * - * This function generates an efficient lookup table of SH coefficients. It - * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm - * & Plm coefficients only depend on theta, and Em only depends on phi, we - * can separate the equation along these lines. Em does not depend on - * degree, so we only need to compute (2 * l) per azimuth Em total and - * Nlm * Plm is symmetrical across indexes, so only positive indexes are - * computed ((l + 1) * (l + 2) / 2 - 1) per elevation. - * @type {Float32Array} - */ -const SPHERICAL_HARMONICS = [ - [ - [0.000000, 0.000000, 0.000000, 1.000000, 1.000000, 1.000000], - [0.052336, 0.034899, 0.017452, 0.999848, 0.999391, 0.998630], - [0.104528, 0.069756, 0.034899, 0.999391, 0.997564, 0.994522], - [0.156434, 0.104528, 0.052336, 0.998630, 0.994522, 0.987688], - [0.207912, 0.139173, 0.069756, 0.997564, 0.990268, 0.978148], - [0.258819, 0.173648, 0.087156, 0.996195, 0.984808, 0.965926], - [0.309017, 0.207912, 0.104528, 0.994522, 0.978148, 0.951057], - [0.358368, 0.241922, 0.121869, 0.992546, 0.970296, 0.933580], - [0.406737, 0.275637, 0.139173, 0.990268, 0.961262, 0.913545], - [0.453990, 0.309017, 0.156434, 0.987688, 0.951057, 0.891007], - [0.500000, 0.342020, 0.173648, 0.984808, 0.939693, 0.866025], - [0.544639, 0.374607, 0.190809, 0.981627, 0.927184, 0.838671], - [0.587785, 0.406737, 0.207912, 0.978148, 0.913545, 0.809017], - [0.629320, 0.438371, 0.224951, 0.974370, 0.898794, 0.777146], - [0.669131, 0.469472, 0.241922, 0.970296, 0.882948, 0.743145], - [0.707107, 0.500000, 0.258819, 0.965926, 0.866025, 0.707107], - [0.743145, 0.529919, 0.275637, 0.961262, 0.848048, 0.669131], - [0.777146, 0.559193, 0.292372, 0.956305, 0.829038, 0.629320], - [0.809017, 0.587785, 0.309017, 0.951057, 0.809017, 0.587785], - [0.838671, 0.615661, 0.325568, 0.945519, 0.788011, 0.544639], - [0.866025, 0.642788, 0.342020, 0.939693, 0.766044, 0.500000], - [0.891007, 0.669131, 0.358368, 0.933580, 0.743145, 0.453990], - [0.913545, 0.694658, 0.374607, 0.927184, 0.719340, 0.406737], - [0.933580, 0.719340, 0.390731, 0.920505, 0.694658, 0.358368], - [0.951057, 0.743145, 0.406737, 0.913545, 0.669131, 0.309017], - [0.965926, 0.766044, 0.422618, 0.906308, 0.642788, 0.258819], - [0.978148, 0.788011, 0.438371, 0.898794, 0.615661, 0.207912], - [0.987688, 0.809017, 0.453990, 0.891007, 0.587785, 0.156434], - [0.994522, 0.829038, 0.469472, 0.882948, 0.559193, 0.104528], - [0.998630, 0.848048, 0.484810, 0.874620, 0.529919, 0.052336], - [1.000000, 0.866025, 0.500000, 0.866025, 0.500000, 0.000000], - [0.998630, 0.882948, 0.515038, 0.857167, 0.469472, -0.052336], - [0.994522, 0.898794, 0.529919, 0.848048, 0.438371, -0.104528], - [0.987688, 0.913545, 0.544639, 0.838671, 0.406737, -0.156434], - [0.978148, 0.927184, 0.559193, 0.829038, 0.374607, -0.207912], - [0.965926, 0.939693, 0.573576, 0.819152, 0.342020, -0.258819], - [0.951057, 0.951057, 0.587785, 0.809017, 0.309017, -0.309017], - [0.933580, 0.961262, 0.601815, 0.798636, 0.275637, -0.358368], - [0.913545, 0.970296, 0.615661, 0.788011, 0.241922, -0.406737], - [0.891007, 0.978148, 0.629320, 0.777146, 0.207912, -0.453990], - [0.866025, 0.984808, 0.642788, 0.766044, 0.173648, -0.500000], - [0.838671, 0.990268, 0.656059, 0.754710, 0.139173, -0.544639], - [0.809017, 0.994522, 0.669131, 0.743145, 0.104528, -0.587785], - [0.777146, 0.997564, 0.681998, 0.731354, 0.069756, -0.629320], - [0.743145, 0.999391, 0.694658, 0.719340, 0.034899, -0.669131], - [0.707107, 1.000000, 0.707107, 0.707107, 0.000000, -0.707107], - [0.669131, 0.999391, 0.719340, 0.694658, -0.034899, -0.743145], - [0.629320, 0.997564, 0.731354, 0.681998, -0.069756, -0.777146], - [0.587785, 0.994522, 0.743145, 0.669131, -0.104528, -0.809017], - [0.544639, 0.990268, 0.754710, 0.656059, -0.139173, -0.838671], - [0.500000, 0.984808, 0.766044, 0.642788, -0.173648, -0.866025], - [0.453990, 0.978148, 0.777146, 0.629320, -0.207912, -0.891007], - [0.406737, 0.970296, 0.788011, 0.615661, -0.241922, -0.913545], - [0.358368, 0.961262, 0.798636, 0.601815, -0.275637, -0.933580], - [0.309017, 0.951057, 0.809017, 0.587785, -0.309017, -0.951057], - [0.258819, 0.939693, 0.819152, 0.573576, -0.342020, -0.965926], - [0.207912, 0.927184, 0.829038, 0.559193, -0.374607, -0.978148], - [0.156434, 0.913545, 0.838671, 0.544639, -0.406737, -0.987688], - [0.104528, 0.898794, 0.848048, 0.529919, -0.438371, -0.994522], - [0.052336, 0.882948, 0.857167, 0.515038, -0.469472, -0.998630], - [0.000000, 0.866025, 0.866025, 0.500000, -0.500000, -1.000000], - [-0.052336, 0.848048, 0.874620, 0.484810, -0.529919, -0.998630], - [-0.104528, 0.829038, 0.882948, 0.469472, -0.559193, -0.994522], - [-0.156434, 0.809017, 0.891007, 0.453990, -0.587785, -0.987688], - [-0.207912, 0.788011, 0.898794, 0.438371, -0.615661, -0.978148], - [-0.258819, 0.766044, 0.906308, 0.422618, -0.642788, -0.965926], - [-0.309017, 0.743145, 0.913545, 0.406737, -0.669131, -0.951057], - [-0.358368, 0.719340, 0.920505, 0.390731, -0.694658, -0.933580], - [-0.406737, 0.694658, 0.927184, 0.374607, -0.719340, -0.913545], - [-0.453990, 0.669131, 0.933580, 0.358368, -0.743145, -0.891007], - [-0.500000, 0.642788, 0.939693, 0.342020, -0.766044, -0.866025], - [-0.544639, 0.615661, 0.945519, 0.325568, -0.788011, -0.838671], - [-0.587785, 0.587785, 0.951057, 0.309017, -0.809017, -0.809017], - [-0.629320, 0.559193, 0.956305, 0.292372, -0.829038, -0.777146], - [-0.669131, 0.529919, 0.961262, 0.275637, -0.848048, -0.743145], - [-0.707107, 0.500000, 0.965926, 0.258819, -0.866025, -0.707107], - [-0.743145, 0.469472, 0.970296, 0.241922, -0.882948, -0.669131], - [-0.777146, 0.438371, 0.974370, 0.224951, -0.898794, -0.629320], - [-0.809017, 0.406737, 0.978148, 0.207912, -0.913545, -0.587785], - [-0.838671, 0.374607, 0.981627, 0.190809, -0.927184, -0.544639], - [-0.866025, 0.342020, 0.984808, 0.173648, -0.939693, -0.500000], - [-0.891007, 0.309017, 0.987688, 0.156434, -0.951057, -0.453990], - [-0.913545, 0.275637, 0.990268, 0.139173, -0.961262, -0.406737], - [-0.933580, 0.241922, 0.992546, 0.121869, -0.970296, -0.358368], - [-0.951057, 0.207912, 0.994522, 0.104528, -0.978148, -0.309017], - [-0.965926, 0.173648, 0.996195, 0.087156, -0.984808, -0.258819], - [-0.978148, 0.139173, 0.997564, 0.069756, -0.990268, -0.207912], - [-0.987688, 0.104528, 0.998630, 0.052336, -0.994522, -0.156434], - [-0.994522, 0.069756, 0.999391, 0.034899, -0.997564, -0.104528], - [-0.998630, 0.034899, 0.999848, 0.017452, -0.999391, -0.052336], - [-1.000000, 0.000000, 1.000000, 0.000000, -1.000000, -0.000000], - [-0.998630, -0.034899, 0.999848, -0.017452, -0.999391, 0.052336], - [-0.994522, -0.069756, 0.999391, -0.034899, -0.997564, 0.104528], - [-0.987688, -0.104528, 0.998630, -0.052336, -0.994522, 0.156434], - [-0.978148, -0.139173, 0.997564, -0.069756, -0.990268, 0.207912], - [-0.965926, -0.173648, 0.996195, -0.087156, -0.984808, 0.258819], - [-0.951057, -0.207912, 0.994522, -0.104528, -0.978148, 0.309017], - [-0.933580, -0.241922, 0.992546, -0.121869, -0.970296, 0.358368], - [-0.913545, -0.275637, 0.990268, -0.139173, -0.961262, 0.406737], - [-0.891007, -0.309017, 0.987688, -0.156434, -0.951057, 0.453990], - [-0.866025, -0.342020, 0.984808, -0.173648, -0.939693, 0.500000], - [-0.838671, -0.374607, 0.981627, -0.190809, -0.927184, 0.544639], - [-0.809017, -0.406737, 0.978148, -0.207912, -0.913545, 0.587785], - [-0.777146, -0.438371, 0.974370, -0.224951, -0.898794, 0.629320], - [-0.743145, -0.469472, 0.970296, -0.241922, -0.882948, 0.669131], - [-0.707107, -0.500000, 0.965926, -0.258819, -0.866025, 0.707107], - [-0.669131, -0.529919, 0.961262, -0.275637, -0.848048, 0.743145], - [-0.629320, -0.559193, 0.956305, -0.292372, -0.829038, 0.777146], - [-0.587785, -0.587785, 0.951057, -0.309017, -0.809017, 0.809017], - [-0.544639, -0.615661, 0.945519, -0.325568, -0.788011, 0.838671], - [-0.500000, -0.642788, 0.939693, -0.342020, -0.766044, 0.866025], - [-0.453990, -0.669131, 0.933580, -0.358368, -0.743145, 0.891007], - [-0.406737, -0.694658, 0.927184, -0.374607, -0.719340, 0.913545], - [-0.358368, -0.719340, 0.920505, -0.390731, -0.694658, 0.933580], - [-0.309017, -0.743145, 0.913545, -0.406737, -0.669131, 0.951057], - [-0.258819, -0.766044, 0.906308, -0.422618, -0.642788, 0.965926], - [-0.207912, -0.788011, 0.898794, -0.438371, -0.615661, 0.978148], - [-0.156434, -0.809017, 0.891007, -0.453990, -0.587785, 0.987688], - [-0.104528, -0.829038, 0.882948, -0.469472, -0.559193, 0.994522], - [-0.052336, -0.848048, 0.874620, -0.484810, -0.529919, 0.998630], - [-0.000000, -0.866025, 0.866025, -0.500000, -0.500000, 1.000000], - [0.052336, -0.882948, 0.857167, -0.515038, -0.469472, 0.998630], - [0.104528, -0.898794, 0.848048, -0.529919, -0.438371, 0.994522], - [0.156434, -0.913545, 0.838671, -0.544639, -0.406737, 0.987688], - [0.207912, -0.927184, 0.829038, -0.559193, -0.374607, 0.978148], - [0.258819, -0.939693, 0.819152, -0.573576, -0.342020, 0.965926], - [0.309017, -0.951057, 0.809017, -0.587785, -0.309017, 0.951057], - [0.358368, -0.961262, 0.798636, -0.601815, -0.275637, 0.933580], - [0.406737, -0.970296, 0.788011, -0.615661, -0.241922, 0.913545], - [0.453990, -0.978148, 0.777146, -0.629320, -0.207912, 0.891007], - [0.500000, -0.984808, 0.766044, -0.642788, -0.173648, 0.866025], - [0.544639, -0.990268, 0.754710, -0.656059, -0.139173, 0.838671], - [0.587785, -0.994522, 0.743145, -0.669131, -0.104528, 0.809017], - [0.629320, -0.997564, 0.731354, -0.681998, -0.069756, 0.777146], - [0.669131, -0.999391, 0.719340, -0.694658, -0.034899, 0.743145], - [0.707107, -1.000000, 0.707107, -0.707107, -0.000000, 0.707107], - [0.743145, -0.999391, 0.694658, -0.719340, 0.034899, 0.669131], - [0.777146, -0.997564, 0.681998, -0.731354, 0.069756, 0.629320], - [0.809017, -0.994522, 0.669131, -0.743145, 0.104528, 0.587785], - [0.838671, -0.990268, 0.656059, -0.754710, 0.139173, 0.544639], - [0.866025, -0.984808, 0.642788, -0.766044, 0.173648, 0.500000], - [0.891007, -0.978148, 0.629320, -0.777146, 0.207912, 0.453990], - [0.913545, -0.970296, 0.615661, -0.788011, 0.241922, 0.406737], - [0.933580, -0.961262, 0.601815, -0.798636, 0.275637, 0.358368], - [0.951057, -0.951057, 0.587785, -0.809017, 0.309017, 0.309017], - [0.965926, -0.939693, 0.573576, -0.819152, 0.342020, 0.258819], - [0.978148, -0.927184, 0.559193, -0.829038, 0.374607, 0.207912], - [0.987688, -0.913545, 0.544639, -0.838671, 0.406737, 0.156434], - [0.994522, -0.898794, 0.529919, -0.848048, 0.438371, 0.104528], - [0.998630, -0.882948, 0.515038, -0.857167, 0.469472, 0.052336], - [1.000000, -0.866025, 0.500000, -0.866025, 0.500000, 0.000000], - [0.998630, -0.848048, 0.484810, -0.874620, 0.529919, -0.052336], - [0.994522, -0.829038, 0.469472, -0.882948, 0.559193, -0.104528], - [0.987688, -0.809017, 0.453990, -0.891007, 0.587785, -0.156434], - [0.978148, -0.788011, 0.438371, -0.898794, 0.615661, -0.207912], - [0.965926, -0.766044, 0.422618, -0.906308, 0.642788, -0.258819], - [0.951057, -0.743145, 0.406737, -0.913545, 0.669131, -0.309017], - [0.933580, -0.719340, 0.390731, -0.920505, 0.694658, -0.358368], - [0.913545, -0.694658, 0.374607, -0.927184, 0.719340, -0.406737], - [0.891007, -0.669131, 0.358368, -0.933580, 0.743145, -0.453990], - [0.866025, -0.642788, 0.342020, -0.939693, 0.766044, -0.500000], - [0.838671, -0.615661, 0.325568, -0.945519, 0.788011, -0.544639], - [0.809017, -0.587785, 0.309017, -0.951057, 0.809017, -0.587785], - [0.777146, -0.559193, 0.292372, -0.956305, 0.829038, -0.629320], - [0.743145, -0.529919, 0.275637, -0.961262, 0.848048, -0.669131], - [0.707107, -0.500000, 0.258819, -0.965926, 0.866025, -0.707107], - [0.669131, -0.469472, 0.241922, -0.970296, 0.882948, -0.743145], - [0.629320, -0.438371, 0.224951, -0.974370, 0.898794, -0.777146], - [0.587785, -0.406737, 0.207912, -0.978148, 0.913545, -0.809017], - [0.544639, -0.374607, 0.190809, -0.981627, 0.927184, -0.838671], - [0.500000, -0.342020, 0.173648, -0.984808, 0.939693, -0.866025], - [0.453990, -0.309017, 0.156434, -0.987688, 0.951057, -0.891007], - [0.406737, -0.275637, 0.139173, -0.990268, 0.961262, -0.913545], - [0.358368, -0.241922, 0.121869, -0.992546, 0.970296, -0.933580], - [0.309017, -0.207912, 0.104528, -0.994522, 0.978148, -0.951057], - [0.258819, -0.173648, 0.087156, -0.996195, 0.984808, -0.965926], - [0.207912, -0.139173, 0.069756, -0.997564, 0.990268, -0.978148], - [0.156434, -0.104528, 0.052336, -0.998630, 0.994522, -0.987688], - [0.104528, -0.069756, 0.034899, -0.999391, 0.997564, -0.994522], - [0.052336, -0.034899, 0.017452, -0.999848, 0.999391, -0.998630], - [0.000000, -0.000000, 0.000000, -1.000000, 1.000000, -1.000000], - [-0.052336, 0.034899, -0.017452, -0.999848, 0.999391, -0.998630], - [-0.104528, 0.069756, -0.034899, -0.999391, 0.997564, -0.994522], - [-0.156434, 0.104528, -0.052336, -0.998630, 0.994522, -0.987688], - [-0.207912, 0.139173, -0.069756, -0.997564, 0.990268, -0.978148], - [-0.258819, 0.173648, -0.087156, -0.996195, 0.984808, -0.965926], - [-0.309017, 0.207912, -0.104528, -0.994522, 0.978148, -0.951057], - [-0.358368, 0.241922, -0.121869, -0.992546, 0.970296, -0.933580], - [-0.406737, 0.275637, -0.139173, -0.990268, 0.961262, -0.913545], - [-0.453990, 0.309017, -0.156434, -0.987688, 0.951057, -0.891007], - [-0.500000, 0.342020, -0.173648, -0.984808, 0.939693, -0.866025], - [-0.544639, 0.374607, -0.190809, -0.981627, 0.927184, -0.838671], - [-0.587785, 0.406737, -0.207912, -0.978148, 0.913545, -0.809017], - [-0.629320, 0.438371, -0.224951, -0.974370, 0.898794, -0.777146], - [-0.669131, 0.469472, -0.241922, -0.970296, 0.882948, -0.743145], - [-0.707107, 0.500000, -0.258819, -0.965926, 0.866025, -0.707107], - [-0.743145, 0.529919, -0.275637, -0.961262, 0.848048, -0.669131], - [-0.777146, 0.559193, -0.292372, -0.956305, 0.829038, -0.629320], - [-0.809017, 0.587785, -0.309017, -0.951057, 0.809017, -0.587785], - [-0.838671, 0.615661, -0.325568, -0.945519, 0.788011, -0.544639], - [-0.866025, 0.642788, -0.342020, -0.939693, 0.766044, -0.500000], - [-0.891007, 0.669131, -0.358368, -0.933580, 0.743145, -0.453990], - [-0.913545, 0.694658, -0.374607, -0.927184, 0.719340, -0.406737], - [-0.933580, 0.719340, -0.390731, -0.920505, 0.694658, -0.358368], - [-0.951057, 0.743145, -0.406737, -0.913545, 0.669131, -0.309017], - [-0.965926, 0.766044, -0.422618, -0.906308, 0.642788, -0.258819], - [-0.978148, 0.788011, -0.438371, -0.898794, 0.615661, -0.207912], - [-0.987688, 0.809017, -0.453990, -0.891007, 0.587785, -0.156434], - [-0.994522, 0.829038, -0.469472, -0.882948, 0.559193, -0.104528], - [-0.998630, 0.848048, -0.484810, -0.874620, 0.529919, -0.052336], - [-1.000000, 0.866025, -0.500000, -0.866025, 0.500000, 0.000000], - [-0.998630, 0.882948, -0.515038, -0.857167, 0.469472, 0.052336], - [-0.994522, 0.898794, -0.529919, -0.848048, 0.438371, 0.104528], - [-0.987688, 0.913545, -0.544639, -0.838671, 0.406737, 0.156434], - [-0.978148, 0.927184, -0.559193, -0.829038, 0.374607, 0.207912], - [-0.965926, 0.939693, -0.573576, -0.819152, 0.342020, 0.258819], - [-0.951057, 0.951057, -0.587785, -0.809017, 0.309017, 0.309017], - [-0.933580, 0.961262, -0.601815, -0.798636, 0.275637, 0.358368], - [-0.913545, 0.970296, -0.615661, -0.788011, 0.241922, 0.406737], - [-0.891007, 0.978148, -0.629320, -0.777146, 0.207912, 0.453990], - [-0.866025, 0.984808, -0.642788, -0.766044, 0.173648, 0.500000], - [-0.838671, 0.990268, -0.656059, -0.754710, 0.139173, 0.544639], - [-0.809017, 0.994522, -0.669131, -0.743145, 0.104528, 0.587785], - [-0.777146, 0.997564, -0.681998, -0.731354, 0.069756, 0.629320], - [-0.743145, 0.999391, -0.694658, -0.719340, 0.034899, 0.669131], - [-0.707107, 1.000000, -0.707107, -0.707107, 0.000000, 0.707107], - [-0.669131, 0.999391, -0.719340, -0.694658, -0.034899, 0.743145], - [-0.629320, 0.997564, -0.731354, -0.681998, -0.069756, 0.777146], - [-0.587785, 0.994522, -0.743145, -0.669131, -0.104528, 0.809017], - [-0.544639, 0.990268, -0.754710, -0.656059, -0.139173, 0.838671], - [-0.500000, 0.984808, -0.766044, -0.642788, -0.173648, 0.866025], - [-0.453990, 0.978148, -0.777146, -0.629320, -0.207912, 0.891007], - [-0.406737, 0.970296, -0.788011, -0.615661, -0.241922, 0.913545], - [-0.358368, 0.961262, -0.798636, -0.601815, -0.275637, 0.933580], - [-0.309017, 0.951057, -0.809017, -0.587785, -0.309017, 0.951057], - [-0.258819, 0.939693, -0.819152, -0.573576, -0.342020, 0.965926], - [-0.207912, 0.927184, -0.829038, -0.559193, -0.374607, 0.978148], - [-0.156434, 0.913545, -0.838671, -0.544639, -0.406737, 0.987688], - [-0.104528, 0.898794, -0.848048, -0.529919, -0.438371, 0.994522], - [-0.052336, 0.882948, -0.857167, -0.515038, -0.469472, 0.998630], - [-0.000000, 0.866025, -0.866025, -0.500000, -0.500000, 1.000000], - [0.052336, 0.848048, -0.874620, -0.484810, -0.529919, 0.998630], - [0.104528, 0.829038, -0.882948, -0.469472, -0.559193, 0.994522], - [0.156434, 0.809017, -0.891007, -0.453990, -0.587785, 0.987688], - [0.207912, 0.788011, -0.898794, -0.438371, -0.615661, 0.978148], - [0.258819, 0.766044, -0.906308, -0.422618, -0.642788, 0.965926], - [0.309017, 0.743145, -0.913545, -0.406737, -0.669131, 0.951057], - [0.358368, 0.719340, -0.920505, -0.390731, -0.694658, 0.933580], - [0.406737, 0.694658, -0.927184, -0.374607, -0.719340, 0.913545], - [0.453990, 0.669131, -0.933580, -0.358368, -0.743145, 0.891007], - [0.500000, 0.642788, -0.939693, -0.342020, -0.766044, 0.866025], - [0.544639, 0.615661, -0.945519, -0.325568, -0.788011, 0.838671], - [0.587785, 0.587785, -0.951057, -0.309017, -0.809017, 0.809017], - [0.629320, 0.559193, -0.956305, -0.292372, -0.829038, 0.777146], - [0.669131, 0.529919, -0.961262, -0.275637, -0.848048, 0.743145], - [0.707107, 0.500000, -0.965926, -0.258819, -0.866025, 0.707107], - [0.743145, 0.469472, -0.970296, -0.241922, -0.882948, 0.669131], - [0.777146, 0.438371, -0.974370, -0.224951, -0.898794, 0.629320], - [0.809017, 0.406737, -0.978148, -0.207912, -0.913545, 0.587785], - [0.838671, 0.374607, -0.981627, -0.190809, -0.927184, 0.544639], - [0.866025, 0.342020, -0.984808, -0.173648, -0.939693, 0.500000], - [0.891007, 0.309017, -0.987688, -0.156434, -0.951057, 0.453990], - [0.913545, 0.275637, -0.990268, -0.139173, -0.961262, 0.406737], - [0.933580, 0.241922, -0.992546, -0.121869, -0.970296, 0.358368], - [0.951057, 0.207912, -0.994522, -0.104528, -0.978148, 0.309017], - [0.965926, 0.173648, -0.996195, -0.087156, -0.984808, 0.258819], - [0.978148, 0.139173, -0.997564, -0.069756, -0.990268, 0.207912], - [0.987688, 0.104528, -0.998630, -0.052336, -0.994522, 0.156434], - [0.994522, 0.069756, -0.999391, -0.034899, -0.997564, 0.104528], - [0.998630, 0.034899, -0.999848, -0.017452, -0.999391, 0.052336], - [1.000000, 0.000000, -1.000000, -0.000000, -1.000000, 0.000000], - [0.998630, -0.034899, -0.999848, 0.017452, -0.999391, -0.052336], - [0.994522, -0.069756, -0.999391, 0.034899, -0.997564, -0.104528], - [0.987688, -0.104528, -0.998630, 0.052336, -0.994522, -0.156434], - [0.978148, -0.139173, -0.997564, 0.069756, -0.990268, -0.207912], - [0.965926, -0.173648, -0.996195, 0.087156, -0.984808, -0.258819], - [0.951057, -0.207912, -0.994522, 0.104528, -0.978148, -0.309017], - [0.933580, -0.241922, -0.992546, 0.121869, -0.970296, -0.358368], - [0.913545, -0.275637, -0.990268, 0.139173, -0.961262, -0.406737], - [0.891007, -0.309017, -0.987688, 0.156434, -0.951057, -0.453990], - [0.866025, -0.342020, -0.984808, 0.173648, -0.939693, -0.500000], - [0.838671, -0.374607, -0.981627, 0.190809, -0.927184, -0.544639], - [0.809017, -0.406737, -0.978148, 0.207912, -0.913545, -0.587785], - [0.777146, -0.438371, -0.974370, 0.224951, -0.898794, -0.629320], - [0.743145, -0.469472, -0.970296, 0.241922, -0.882948, -0.669131], - [0.707107, -0.500000, -0.965926, 0.258819, -0.866025, -0.707107], - [0.669131, -0.529919, -0.961262, 0.275637, -0.848048, -0.743145], - [0.629320, -0.559193, -0.956305, 0.292372, -0.829038, -0.777146], - [0.587785, -0.587785, -0.951057, 0.309017, -0.809017, -0.809017], - [0.544639, -0.615661, -0.945519, 0.325568, -0.788011, -0.838671], - [0.500000, -0.642788, -0.939693, 0.342020, -0.766044, -0.866025], - [0.453990, -0.669131, -0.933580, 0.358368, -0.743145, -0.891007], - [0.406737, -0.694658, -0.927184, 0.374607, -0.719340, -0.913545], - [0.358368, -0.719340, -0.920505, 0.390731, -0.694658, -0.933580], - [0.309017, -0.743145, -0.913545, 0.406737, -0.669131, -0.951057], - [0.258819, -0.766044, -0.906308, 0.422618, -0.642788, -0.965926], - [0.207912, -0.788011, -0.898794, 0.438371, -0.615661, -0.978148], - [0.156434, -0.809017, -0.891007, 0.453990, -0.587785, -0.987688], - [0.104528, -0.829038, -0.882948, 0.469472, -0.559193, -0.994522], - [0.052336, -0.848048, -0.874620, 0.484810, -0.529919, -0.998630], - [0.000000, -0.866025, -0.866025, 0.500000, -0.500000, -1.000000], - [-0.052336, -0.882948, -0.857167, 0.515038, -0.469472, -0.998630], - [-0.104528, -0.898794, -0.848048, 0.529919, -0.438371, -0.994522], - [-0.156434, -0.913545, -0.838671, 0.544639, -0.406737, -0.987688], - [-0.207912, -0.927184, -0.829038, 0.559193, -0.374607, -0.978148], - [-0.258819, -0.939693, -0.819152, 0.573576, -0.342020, -0.965926], - [-0.309017, -0.951057, -0.809017, 0.587785, -0.309017, -0.951057], - [-0.358368, -0.961262, -0.798636, 0.601815, -0.275637, -0.933580], - [-0.406737, -0.970296, -0.788011, 0.615661, -0.241922, -0.913545], - [-0.453990, -0.978148, -0.777146, 0.629320, -0.207912, -0.891007], - [-0.500000, -0.984808, -0.766044, 0.642788, -0.173648, -0.866025], - [-0.544639, -0.990268, -0.754710, 0.656059, -0.139173, -0.838671], - [-0.587785, -0.994522, -0.743145, 0.669131, -0.104528, -0.809017], - [-0.629320, -0.997564, -0.731354, 0.681998, -0.069756, -0.777146], - [-0.669131, -0.999391, -0.719340, 0.694658, -0.034899, -0.743145], - [-0.707107, -1.000000, -0.707107, 0.707107, -0.000000, -0.707107], - [-0.743145, -0.999391, -0.694658, 0.719340, 0.034899, -0.669131], - [-0.777146, -0.997564, -0.681998, 0.731354, 0.069756, -0.629320], - [-0.809017, -0.994522, -0.669131, 0.743145, 0.104528, -0.587785], - [-0.838671, -0.990268, -0.656059, 0.754710, 0.139173, -0.544639], - [-0.866025, -0.984808, -0.642788, 0.766044, 0.173648, -0.500000], - [-0.891007, -0.978148, -0.629320, 0.777146, 0.207912, -0.453990], - [-0.913545, -0.970296, -0.615661, 0.788011, 0.241922, -0.406737], - [-0.933580, -0.961262, -0.601815, 0.798636, 0.275637, -0.358368], - [-0.951057, -0.951057, -0.587785, 0.809017, 0.309017, -0.309017], - [-0.965926, -0.939693, -0.573576, 0.819152, 0.342020, -0.258819], - [-0.978148, -0.927184, -0.559193, 0.829038, 0.374607, -0.207912], - [-0.987688, -0.913545, -0.544639, 0.838671, 0.406737, -0.156434], - [-0.994522, -0.898794, -0.529919, 0.848048, 0.438371, -0.104528], - [-0.998630, -0.882948, -0.515038, 0.857167, 0.469472, -0.052336], - [-1.000000, -0.866025, -0.500000, 0.866025, 0.500000, -0.000000], - [-0.998630, -0.848048, -0.484810, 0.874620, 0.529919, 0.052336], - [-0.994522, -0.829038, -0.469472, 0.882948, 0.559193, 0.104528], - [-0.987688, -0.809017, -0.453990, 0.891007, 0.587785, 0.156434], - [-0.978148, -0.788011, -0.438371, 0.898794, 0.615661, 0.207912], - [-0.965926, -0.766044, -0.422618, 0.906308, 0.642788, 0.258819], - [-0.951057, -0.743145, -0.406737, 0.913545, 0.669131, 0.309017], - [-0.933580, -0.719340, -0.390731, 0.920505, 0.694658, 0.358368], - [-0.913545, -0.694658, -0.374607, 0.927184, 0.719340, 0.406737], - [-0.891007, -0.669131, -0.358368, 0.933580, 0.743145, 0.453990], - [-0.866025, -0.642788, -0.342020, 0.939693, 0.766044, 0.500000], - [-0.838671, -0.615661, -0.325568, 0.945519, 0.788011, 0.544639], - [-0.809017, -0.587785, -0.309017, 0.951057, 0.809017, 0.587785], - [-0.777146, -0.559193, -0.292372, 0.956305, 0.829038, 0.629320], - [-0.743145, -0.529919, -0.275637, 0.961262, 0.848048, 0.669131], - [-0.707107, -0.500000, -0.258819, 0.965926, 0.866025, 0.707107], - [-0.669131, -0.469472, -0.241922, 0.970296, 0.882948, 0.743145], - [-0.629320, -0.438371, -0.224951, 0.974370, 0.898794, 0.777146], - [-0.587785, -0.406737, -0.207912, 0.978148, 0.913545, 0.809017], - [-0.544639, -0.374607, -0.190809, 0.981627, 0.927184, 0.838671], - [-0.500000, -0.342020, -0.173648, 0.984808, 0.939693, 0.866025], - [-0.453990, -0.309017, -0.156434, 0.987688, 0.951057, 0.891007], - [-0.406737, -0.275637, -0.139173, 0.990268, 0.961262, 0.913545], - [-0.358368, -0.241922, -0.121869, 0.992546, 0.970296, 0.933580], - [-0.309017, -0.207912, -0.104528, 0.994522, 0.978148, 0.951057], - [-0.258819, -0.173648, -0.087156, 0.996195, 0.984808, 0.965926], - [-0.207912, -0.139173, -0.069756, 0.997564, 0.990268, 0.978148], - [-0.156434, -0.104528, -0.052336, 0.998630, 0.994522, 0.987688], - [-0.104528, -0.069756, -0.034899, 0.999391, 0.997564, 0.994522], - [-0.052336, -0.034899, -0.017452, 0.999848, 0.999391, 0.998630], - ], - [ - [-1.000000, -0.000000, 1.000000, -0.000000, 0.000000, - -1.000000, -0.000000, 0.000000, -0.000000], - [-0.999848, 0.017452, 0.999543, -0.030224, 0.000264, - -0.999086, 0.042733, -0.000590, 0.000004], - [-0.999391, 0.034899, 0.998173, -0.060411, 0.001055, - -0.996348, 0.085356, -0.002357, 0.000034], - [-0.998630, 0.052336, 0.995891, -0.090524, 0.002372, - -0.991791, 0.127757, -0.005297, 0.000113], - [-0.997564, 0.069756, 0.992701, -0.120527, 0.004214, - -0.985429, 0.169828, -0.009400, 0.000268], - [-0.996195, 0.087156, 0.988606, -0.150384, 0.006578, - -0.977277, 0.211460, -0.014654, 0.000523], - [-0.994522, 0.104528, 0.983611, -0.180057, 0.009462, - -0.967356, 0.252544, -0.021043, 0.000903], - [-0.992546, 0.121869, 0.977722, -0.209511, 0.012862, - -0.955693, 0.292976, -0.028547, 0.001431], - [-0.990268, 0.139173, 0.970946, -0.238709, 0.016774, - -0.942316, 0.332649, -0.037143, 0.002131], - [-0.987688, 0.156434, 0.963292, -0.267617, 0.021193, - -0.927262, 0.371463, -0.046806, 0.003026], - [-0.984808, 0.173648, 0.954769, -0.296198, 0.026114, - -0.910569, 0.409317, -0.057505, 0.004140], - [-0.981627, 0.190809, 0.945388, -0.324419, 0.031530, - -0.892279, 0.446114, -0.069209, 0.005492], - [-0.978148, 0.207912, 0.935159, -0.352244, 0.037436, - -0.872441, 0.481759, -0.081880, 0.007105], - [-0.974370, 0.224951, 0.924096, -0.379641, 0.043823, - -0.851105, 0.516162, -0.095481, 0.008999], - [-0.970296, 0.241922, 0.912211, -0.406574, 0.050685, - -0.828326, 0.549233, -0.109969, 0.011193], - [-0.965926, 0.258819, 0.899519, -0.433013, 0.058013, - -0.804164, 0.580889, -0.125300, 0.013707], - [-0.961262, 0.275637, 0.886036, -0.458924, 0.065797, - -0.778680, 0.611050, -0.141427, 0.016556], - [-0.956305, 0.292372, 0.871778, -0.484275, 0.074029, - -0.751940, 0.639639, -0.158301, 0.019758], - [-0.951057, 0.309017, 0.856763, -0.509037, 0.082698, - -0.724012, 0.666583, -0.175868, 0.023329], - [-0.945519, 0.325568, 0.841008, -0.533178, 0.091794, - -0.694969, 0.691816, -0.194075, 0.027281], - [-0.939693, 0.342020, 0.824533, -0.556670, 0.101306, - -0.664885, 0.715274, -0.212865, 0.031630], - [-0.933580, 0.358368, 0.807359, -0.579484, 0.111222, - -0.633837, 0.736898, -0.232180, 0.036385], - [-0.927184, 0.374607, 0.789505, -0.601592, 0.121529, - -0.601904, 0.756637, -0.251960, 0.041559], - [-0.920505, 0.390731, 0.770994, -0.622967, 0.132217, - -0.569169, 0.774442, -0.272143, 0.047160], - [-0.913545, 0.406737, 0.751848, -0.643582, 0.143271, - -0.535715, 0.790270, -0.292666, 0.053196], - [-0.906308, 0.422618, 0.732091, -0.663414, 0.154678, - -0.501627, 0.804083, -0.313464, 0.059674], - [-0.898794, 0.438371, 0.711746, -0.682437, 0.166423, - -0.466993, 0.815850, -0.334472, 0.066599], - [-0.891007, 0.453990, 0.690839, -0.700629, 0.178494, - -0.431899, 0.825544, -0.355623, 0.073974], - [-0.882948, 0.469472, 0.669395, -0.717968, 0.190875, - -0.396436, 0.833145, -0.376851, 0.081803], - [-0.874620, 0.484810, 0.647439, -0.734431, 0.203551, - -0.360692, 0.838638, -0.398086, 0.090085], - [-0.866025, 0.500000, 0.625000, -0.750000, 0.216506, - -0.324760, 0.842012, -0.419263, 0.098821], - [-0.857167, 0.515038, 0.602104, -0.764655, 0.229726, - -0.288728, 0.843265, -0.440311, 0.108009], - [-0.848048, 0.529919, 0.578778, -0.778378, 0.243192, - -0.252688, 0.842399, -0.461164, 0.117644], - [-0.838671, 0.544639, 0.555052, -0.791154, 0.256891, - -0.216730, 0.839422, -0.481753, 0.127722], - [-0.829038, 0.559193, 0.530955, -0.802965, 0.270803, - -0.180944, 0.834347, -0.502011, 0.138237], - [-0.819152, 0.573576, 0.506515, -0.813798, 0.284914, - -0.145420, 0.827194, -0.521871, 0.149181], - [-0.809017, 0.587785, 0.481763, -0.823639, 0.299204, - -0.110246, 0.817987, -0.541266, 0.160545], - [-0.798636, 0.601815, 0.456728, -0.832477, 0.313658, - -0.075508, 0.806757, -0.560132, 0.172317], - [-0.788011, 0.615661, 0.431441, -0.840301, 0.328257, - -0.041294, 0.793541, -0.578405, 0.184487], - [-0.777146, 0.629320, 0.405934, -0.847101, 0.342984, - -0.007686, 0.778379, -0.596021, 0.197040], - [-0.766044, 0.642788, 0.380236, -0.852869, 0.357821, - 0.025233, 0.761319, -0.612921, 0.209963], - [-0.754710, 0.656059, 0.354380, -0.857597, 0.372749, - 0.057383, 0.742412, -0.629044, 0.223238], - [-0.743145, 0.669131, 0.328396, -0.861281, 0.387751, - 0.088686, 0.721714, -0.644334, 0.236850], - [-0.731354, 0.681998, 0.302317, -0.863916, 0.402807, - 0.119068, 0.699288, -0.658734, 0.250778], - [-0.719340, 0.694658, 0.276175, -0.865498, 0.417901, - 0.148454, 0.675199, -0.672190, 0.265005], - [-0.707107, 0.707107, 0.250000, -0.866025, 0.433013, - 0.176777, 0.649519, -0.684653, 0.279508], - [-0.694658, 0.719340, 0.223825, -0.865498, 0.448125, - 0.203969, 0.622322, -0.696073, 0.294267], - [-0.681998, 0.731354, 0.197683, -0.863916, 0.463218, - 0.229967, 0.593688, -0.706405, 0.309259], - [-0.669131, 0.743145, 0.171604, -0.861281, 0.478275, - 0.254712, 0.563700, -0.715605, 0.324459], - [-0.656059, 0.754710, 0.145620, -0.857597, 0.493276, - 0.278147, 0.532443, -0.723633, 0.339844], - [-0.642788, 0.766044, 0.119764, -0.852869, 0.508205, - 0.300221, 0.500009, -0.730451, 0.355387], - [-0.629320, 0.777146, 0.094066, -0.847101, 0.523041, - 0.320884, 0.466490, -0.736025, 0.371063], - [-0.615661, 0.788011, 0.068559, -0.840301, 0.537768, - 0.340093, 0.431982, -0.740324, 0.386845], - [-0.601815, 0.798636, 0.043272, -0.832477, 0.552367, - 0.357807, 0.396584, -0.743320, 0.402704], - [-0.587785, 0.809017, 0.018237, -0.823639, 0.566821, - 0.373991, 0.360397, -0.744989, 0.418613], - [-0.573576, 0.819152, -0.006515, -0.813798, 0.581112, - 0.388612, 0.323524, -0.745308, 0.434544], - [-0.559193, 0.829038, -0.030955, -0.802965, 0.595222, - 0.401645, 0.286069, -0.744262, 0.450467], - [-0.544639, 0.838671, -0.055052, -0.791154, 0.609135, - 0.413066, 0.248140, -0.741835, 0.466352], - [-0.529919, 0.848048, -0.078778, -0.778378, 0.622833, - 0.422856, 0.209843, -0.738017, 0.482171], - [-0.515038, 0.857167, -0.102104, -0.764655, 0.636300, - 0.431004, 0.171288, -0.732801, 0.497894], - [-0.500000, 0.866025, -0.125000, -0.750000, 0.649519, - 0.437500, 0.132583, -0.726184, 0.513490], - [-0.484810, 0.874620, -0.147439, -0.734431, 0.662474, - 0.442340, 0.093837, -0.718167, 0.528929], - [-0.469472, 0.882948, -0.169395, -0.717968, 0.675150, - 0.445524, 0.055160, -0.708753, 0.544183], - [-0.453990, 0.891007, -0.190839, -0.700629, 0.687531, - 0.447059, 0.016662, -0.697950, 0.559220], - [-0.438371, 0.898794, -0.211746, -0.682437, 0.699602, - 0.446953, -0.021550, -0.685769, 0.574011], - [-0.422618, 0.906308, -0.232091, -0.663414, 0.711348, - 0.445222, -0.059368, -0.672226, 0.588528], - [-0.406737, 0.913545, -0.251848, -0.643582, 0.722755, - 0.441884, -0.096684, -0.657339, 0.602741], - [-0.390731, 0.920505, -0.270994, -0.622967, 0.733809, - 0.436964, -0.133395, -0.641130, 0.616621], - [-0.374607, 0.927184, -0.289505, -0.601592, 0.744496, - 0.430488, -0.169397, -0.623624, 0.630141], - [-0.358368, 0.933580, -0.307359, -0.579484, 0.754804, - 0.422491, -0.204589, -0.604851, 0.643273], - [-0.342020, 0.939693, -0.324533, -0.556670, 0.764720, - 0.413008, -0.238872, -0.584843, 0.655990], - [-0.325568, 0.945519, -0.341008, -0.533178, 0.774231, - 0.402081, -0.272150, -0.563635, 0.668267], - [-0.309017, 0.951057, -0.356763, -0.509037, 0.783327, - 0.389754, -0.304329, -0.541266, 0.680078], - [-0.292372, 0.956305, -0.371778, -0.484275, 0.791997, - 0.376077, -0.335319, -0.517778, 0.691399], - [-0.275637, 0.961262, -0.386036, -0.458924, 0.800228, - 0.361102, -0.365034, -0.493216, 0.702207], - [-0.258819, 0.965926, -0.399519, -0.433013, 0.808013, - 0.344885, -0.393389, -0.467627, 0.712478], - [-0.241922, 0.970296, -0.412211, -0.406574, 0.815340, - 0.327486, -0.420306, -0.441061, 0.722191], - [-0.224951, 0.974370, -0.424096, -0.379641, 0.822202, - 0.308969, -0.445709, -0.413572, 0.731327], - [-0.207912, 0.978148, -0.435159, -0.352244, 0.828589, - 0.289399, -0.469527, -0.385215, 0.739866], - [-0.190809, 0.981627, -0.445388, -0.324419, 0.834495, - 0.268846, -0.491693, -0.356047, 0.747790], - [-0.173648, 0.984808, -0.454769, -0.296198, 0.839912, - 0.247382, -0.512145, -0.326129, 0.755082], - [-0.156434, 0.987688, -0.463292, -0.267617, 0.844832, - 0.225081, -0.530827, -0.295521, 0.761728], - [-0.139173, 0.990268, -0.470946, -0.238709, 0.849251, - 0.202020, -0.547684, -0.264287, 0.767712], - [-0.121869, 0.992546, -0.477722, -0.209511, 0.853163, - 0.178279, -0.562672, -0.232494, 0.773023], - [-0.104528, 0.994522, -0.483611, -0.180057, 0.856563, - 0.153937, -0.575747, -0.200207, 0.777648], - [-0.087156, 0.996195, -0.488606, -0.150384, 0.859447, - 0.129078, -0.586872, -0.167494, 0.781579], - [-0.069756, 0.997564, -0.492701, -0.120527, 0.861811, - 0.103786, -0.596018, -0.134426, 0.784806], - [-0.052336, 0.998630, -0.495891, -0.090524, 0.863653, - 0.078146, -0.603158, -0.101071, 0.787324], - [-0.034899, 0.999391, -0.498173, -0.060411, 0.864971, - 0.052243, -0.608272, -0.067500, 0.789126], - [-0.017452, 0.999848, -0.499543, -0.030224, 0.865762, - 0.026165, -0.611347, -0.033786, 0.790208], - [0.000000, 1.000000, -0.500000, 0.000000, 0.866025, - -0.000000, -0.612372, 0.000000, 0.790569], - [0.017452, 0.999848, -0.499543, 0.030224, 0.865762, - -0.026165, -0.611347, 0.033786, 0.790208], - [0.034899, 0.999391, -0.498173, 0.060411, 0.864971, - -0.052243, -0.608272, 0.067500, 0.789126], - [0.052336, 0.998630, -0.495891, 0.090524, 0.863653, - -0.078146, -0.603158, 0.101071, 0.787324], - [0.069756, 0.997564, -0.492701, 0.120527, 0.861811, - -0.103786, -0.596018, 0.134426, 0.784806], - [0.087156, 0.996195, -0.488606, 0.150384, 0.859447, - -0.129078, -0.586872, 0.167494, 0.781579], - [0.104528, 0.994522, -0.483611, 0.180057, 0.856563, - -0.153937, -0.575747, 0.200207, 0.777648], - [0.121869, 0.992546, -0.477722, 0.209511, 0.853163, - -0.178279, -0.562672, 0.232494, 0.773023], - [0.139173, 0.990268, -0.470946, 0.238709, 0.849251, - -0.202020, -0.547684, 0.264287, 0.767712], - [0.156434, 0.987688, -0.463292, 0.267617, 0.844832, - -0.225081, -0.530827, 0.295521, 0.761728], - [0.173648, 0.984808, -0.454769, 0.296198, 0.839912, - -0.247382, -0.512145, 0.326129, 0.755082], - [0.190809, 0.981627, -0.445388, 0.324419, 0.834495, - -0.268846, -0.491693, 0.356047, 0.747790], - [0.207912, 0.978148, -0.435159, 0.352244, 0.828589, - -0.289399, -0.469527, 0.385215, 0.739866], - [0.224951, 0.974370, -0.424096, 0.379641, 0.822202, - -0.308969, -0.445709, 0.413572, 0.731327], - [0.241922, 0.970296, -0.412211, 0.406574, 0.815340, - -0.327486, -0.420306, 0.441061, 0.722191], - [0.258819, 0.965926, -0.399519, 0.433013, 0.808013, - -0.344885, -0.393389, 0.467627, 0.712478], - [0.275637, 0.961262, -0.386036, 0.458924, 0.800228, - -0.361102, -0.365034, 0.493216, 0.702207], - [0.292372, 0.956305, -0.371778, 0.484275, 0.791997, - -0.376077, -0.335319, 0.517778, 0.691399], - [0.309017, 0.951057, -0.356763, 0.509037, 0.783327, - -0.389754, -0.304329, 0.541266, 0.680078], - [0.325568, 0.945519, -0.341008, 0.533178, 0.774231, - -0.402081, -0.272150, 0.563635, 0.668267], - [0.342020, 0.939693, -0.324533, 0.556670, 0.764720, - -0.413008, -0.238872, 0.584843, 0.655990], - [0.358368, 0.933580, -0.307359, 0.579484, 0.754804, - -0.422491, -0.204589, 0.604851, 0.643273], - [0.374607, 0.927184, -0.289505, 0.601592, 0.744496, - -0.430488, -0.169397, 0.623624, 0.630141], - [0.390731, 0.920505, -0.270994, 0.622967, 0.733809, - -0.436964, -0.133395, 0.641130, 0.616621], - [0.406737, 0.913545, -0.251848, 0.643582, 0.722755, - -0.441884, -0.096684, 0.657339, 0.602741], - [0.422618, 0.906308, -0.232091, 0.663414, 0.711348, - -0.445222, -0.059368, 0.672226, 0.588528], - [0.438371, 0.898794, -0.211746, 0.682437, 0.699602, - -0.446953, -0.021550, 0.685769, 0.574011], - [0.453990, 0.891007, -0.190839, 0.700629, 0.687531, - -0.447059, 0.016662, 0.697950, 0.559220], - [0.469472, 0.882948, -0.169395, 0.717968, 0.675150, - -0.445524, 0.055160, 0.708753, 0.544183], - [0.484810, 0.874620, -0.147439, 0.734431, 0.662474, - -0.442340, 0.093837, 0.718167, 0.528929], - [0.500000, 0.866025, -0.125000, 0.750000, 0.649519, - -0.437500, 0.132583, 0.726184, 0.513490], - [0.515038, 0.857167, -0.102104, 0.764655, 0.636300, - -0.431004, 0.171288, 0.732801, 0.497894], - [0.529919, 0.848048, -0.078778, 0.778378, 0.622833, - -0.422856, 0.209843, 0.738017, 0.482171], - [0.544639, 0.838671, -0.055052, 0.791154, 0.609135, - -0.413066, 0.248140, 0.741835, 0.466352], - [0.559193, 0.829038, -0.030955, 0.802965, 0.595222, - -0.401645, 0.286069, 0.744262, 0.450467], - [0.573576, 0.819152, -0.006515, 0.813798, 0.581112, - -0.388612, 0.323524, 0.745308, 0.434544], - [0.587785, 0.809017, 0.018237, 0.823639, 0.566821, - -0.373991, 0.360397, 0.744989, 0.418613], - [0.601815, 0.798636, 0.043272, 0.832477, 0.552367, - -0.357807, 0.396584, 0.743320, 0.402704], - [0.615661, 0.788011, 0.068559, 0.840301, 0.537768, - -0.340093, 0.431982, 0.740324, 0.386845], - [0.629320, 0.777146, 0.094066, 0.847101, 0.523041, - -0.320884, 0.466490, 0.736025, 0.371063], - [0.642788, 0.766044, 0.119764, 0.852869, 0.508205, - -0.300221, 0.500009, 0.730451, 0.355387], - [0.656059, 0.754710, 0.145620, 0.857597, 0.493276, - -0.278147, 0.532443, 0.723633, 0.339844], - [0.669131, 0.743145, 0.171604, 0.861281, 0.478275, - -0.254712, 0.563700, 0.715605, 0.324459], - [0.681998, 0.731354, 0.197683, 0.863916, 0.463218, - -0.229967, 0.593688, 0.706405, 0.309259], - [0.694658, 0.719340, 0.223825, 0.865498, 0.448125, - -0.203969, 0.622322, 0.696073, 0.294267], - [0.707107, 0.707107, 0.250000, 0.866025, 0.433013, - -0.176777, 0.649519, 0.684653, 0.279508], - [0.719340, 0.694658, 0.276175, 0.865498, 0.417901, - -0.148454, 0.675199, 0.672190, 0.265005], - [0.731354, 0.681998, 0.302317, 0.863916, 0.402807, - -0.119068, 0.699288, 0.658734, 0.250778], - [0.743145, 0.669131, 0.328396, 0.861281, 0.387751, - -0.088686, 0.721714, 0.644334, 0.236850], - [0.754710, 0.656059, 0.354380, 0.857597, 0.372749, - -0.057383, 0.742412, 0.629044, 0.223238], - [0.766044, 0.642788, 0.380236, 0.852869, 0.357821, - -0.025233, 0.761319, 0.612921, 0.209963], - [0.777146, 0.629320, 0.405934, 0.847101, 0.342984, - 0.007686, 0.778379, 0.596021, 0.197040], - [0.788011, 0.615661, 0.431441, 0.840301, 0.328257, - 0.041294, 0.793541, 0.578405, 0.184487], - [0.798636, 0.601815, 0.456728, 0.832477, 0.313658, - 0.075508, 0.806757, 0.560132, 0.172317], - [0.809017, 0.587785, 0.481763, 0.823639, 0.299204, - 0.110246, 0.817987, 0.541266, 0.160545], - [0.819152, 0.573576, 0.506515, 0.813798, 0.284914, - 0.145420, 0.827194, 0.521871, 0.149181], - [0.829038, 0.559193, 0.530955, 0.802965, 0.270803, - 0.180944, 0.834347, 0.502011, 0.138237], - [0.838671, 0.544639, 0.555052, 0.791154, 0.256891, - 0.216730, 0.839422, 0.481753, 0.127722], - [0.848048, 0.529919, 0.578778, 0.778378, 0.243192, - 0.252688, 0.842399, 0.461164, 0.117644], - [0.857167, 0.515038, 0.602104, 0.764655, 0.229726, - 0.288728, 0.843265, 0.440311, 0.108009], - [0.866025, 0.500000, 0.625000, 0.750000, 0.216506, - 0.324760, 0.842012, 0.419263, 0.098821], - [0.874620, 0.484810, 0.647439, 0.734431, 0.203551, - 0.360692, 0.838638, 0.398086, 0.090085], - [0.882948, 0.469472, 0.669395, 0.717968, 0.190875, - 0.396436, 0.833145, 0.376851, 0.081803], - [0.891007, 0.453990, 0.690839, 0.700629, 0.178494, - 0.431899, 0.825544, 0.355623, 0.073974], - [0.898794, 0.438371, 0.711746, 0.682437, 0.166423, - 0.466993, 0.815850, 0.334472, 0.066599], - [0.906308, 0.422618, 0.732091, 0.663414, 0.154678, - 0.501627, 0.804083, 0.313464, 0.059674], - [0.913545, 0.406737, 0.751848, 0.643582, 0.143271, - 0.535715, 0.790270, 0.292666, 0.053196], - [0.920505, 0.390731, 0.770994, 0.622967, 0.132217, - 0.569169, 0.774442, 0.272143, 0.047160], - [0.927184, 0.374607, 0.789505, 0.601592, 0.121529, - 0.601904, 0.756637, 0.251960, 0.041559], - [0.933580, 0.358368, 0.807359, 0.579484, 0.111222, - 0.633837, 0.736898, 0.232180, 0.036385], - [0.939693, 0.342020, 0.824533, 0.556670, 0.101306, - 0.664885, 0.715274, 0.212865, 0.031630], - [0.945519, 0.325568, 0.841008, 0.533178, 0.091794, - 0.694969, 0.691816, 0.194075, 0.027281], - [0.951057, 0.309017, 0.856763, 0.509037, 0.082698, - 0.724012, 0.666583, 0.175868, 0.023329], - [0.956305, 0.292372, 0.871778, 0.484275, 0.074029, - 0.751940, 0.639639, 0.158301, 0.019758], - [0.961262, 0.275637, 0.886036, 0.458924, 0.065797, - 0.778680, 0.611050, 0.141427, 0.016556], - [0.965926, 0.258819, 0.899519, 0.433013, 0.058013, - 0.804164, 0.580889, 0.125300, 0.013707], - [0.970296, 0.241922, 0.912211, 0.406574, 0.050685, - 0.828326, 0.549233, 0.109969, 0.011193], - [0.974370, 0.224951, 0.924096, 0.379641, 0.043823, - 0.851105, 0.516162, 0.095481, 0.008999], - [0.978148, 0.207912, 0.935159, 0.352244, 0.037436, - 0.872441, 0.481759, 0.081880, 0.007105], - [0.981627, 0.190809, 0.945388, 0.324419, 0.031530, - 0.892279, 0.446114, 0.069209, 0.005492], - [0.984808, 0.173648, 0.954769, 0.296198, 0.026114, - 0.910569, 0.409317, 0.057505, 0.004140], - [0.987688, 0.156434, 0.963292, 0.267617, 0.021193, - 0.927262, 0.371463, 0.046806, 0.003026], - [0.990268, 0.139173, 0.970946, 0.238709, 0.016774, - 0.942316, 0.332649, 0.037143, 0.002131], - [0.992546, 0.121869, 0.977722, 0.209511, 0.012862, - 0.955693, 0.292976, 0.028547, 0.001431], - [0.994522, 0.104528, 0.983611, 0.180057, 0.009462, - 0.967356, 0.252544, 0.021043, 0.000903], - [0.996195, 0.087156, 0.988606, 0.150384, 0.006578, - 0.977277, 0.211460, 0.014654, 0.000523], - [0.997564, 0.069756, 0.992701, 0.120527, 0.004214, - 0.985429, 0.169828, 0.009400, 0.000268], - [0.998630, 0.052336, 0.995891, 0.090524, 0.002372, - 0.991791, 0.127757, 0.005297, 0.000113], - [0.999391, 0.034899, 0.998173, 0.060411, 0.001055, - 0.996348, 0.085356, 0.002357, 0.000034], - [0.999848, 0.017452, 0.999543, 0.030224, 0.000264, - 0.999086, 0.042733, 0.000590, 0.000004], - [1.000000, -0.000000, 1.000000, -0.000000, 0.000000, - 1.000000, -0.000000, 0.000000, -0.000000], - ], -]; -/** @type {Number} */ -const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION = SPHERICAL_HARMONICS[0].length; -/** @type {Number} */ -const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION = SPHERICAL_HARMONICS[1].length; -/** - * The maximum allowed ambisonic order. - * @type {Number} - */ -const SPHERICAL_HARMONICS_MAX_ORDER = SPHERICAL_HARMONICS[0][0].length / 2; -/** - * Pre-computed per-band weighting coefficients for producing energy-preserving - * Max-Re sources. - */ -const MAX_RE_WEIGHTS = [ - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.000000, 1.000000, 1.000000, 1.000000], - [1.003236, 1.002156, 0.999152, 0.990038], - [1.032370, 1.021194, 0.990433, 0.898572], - [1.062694, 1.040231, 0.979161, 0.799806], - [1.093999, 1.058954, 0.964976, 0.693603], - [1.126003, 1.077006, 0.947526, 0.579890], - [1.158345, 1.093982, 0.926474, 0.458690], - [1.190590, 1.109437, 0.901512, 0.330158], - [1.222228, 1.122890, 0.872370, 0.194621], - [1.252684, 1.133837, 0.838839, 0.052614], - [1.281987, 1.142358, 0.801199, 0.000000], - [1.312073, 1.150207, 0.760839, 0.000000], - [1.343011, 1.157424, 0.717799, 0.000000], - [1.374649, 1.163859, 0.671999, 0.000000], - [1.406809, 1.169354, 0.623371, 0.000000], - [1.439286, 1.173739, 0.571868, 0.000000], - [1.471846, 1.176837, 0.517465, 0.000000], - [1.504226, 1.178465, 0.460174, 0.000000], - [1.536133, 1.178438, 0.400043, 0.000000], - [1.567253, 1.176573, 0.337165, 0.000000], - [1.597247, 1.172695, 0.271688, 0.000000], - [1.625766, 1.166645, 0.203815, 0.000000], - [1.652455, 1.158285, 0.133806, 0.000000], - [1.676966, 1.147506, 0.061983, 0.000000], - [1.699006, 1.134261, 0.000000, 0.000000], - [1.720224, 1.119789, 0.000000, 0.000000], - [1.741631, 1.104810, 0.000000, 0.000000], - [1.763183, 1.089330, 0.000000, 0.000000], - [1.784837, 1.073356, 0.000000, 0.000000], - [1.806548, 1.056898, 0.000000, 0.000000], - [1.828269, 1.039968, 0.000000, 0.000000], - [1.849952, 1.022580, 0.000000, 0.000000], - [1.871552, 1.004752, 0.000000, 0.000000], - [1.893018, 0.986504, 0.000000, 0.000000], - [1.914305, 0.967857, 0.000000, 0.000000], - [1.935366, 0.948837, 0.000000, 0.000000], - [1.956154, 0.929471, 0.000000, 0.000000], - [1.976625, 0.909790, 0.000000, 0.000000], - [1.996736, 0.889823, 0.000000, 0.000000], - [2.016448, 0.869607, 0.000000, 0.000000], - [2.035721, 0.849175, 0.000000, 0.000000], - [2.054522, 0.828565, 0.000000, 0.000000], - [2.072818, 0.807816, 0.000000, 0.000000], - [2.090581, 0.786964, 0.000000, 0.000000], - [2.107785, 0.766051, 0.000000, 0.000000], - [2.124411, 0.745115, 0.000000, 0.000000], - [2.140439, 0.724196, 0.000000, 0.000000], - [2.155856, 0.703332, 0.000000, 0.000000], - [2.170653, 0.682561, 0.000000, 0.000000], - [2.184823, 0.661921, 0.000000, 0.000000], - [2.198364, 0.641445, 0.000000, 0.000000], - [2.211275, 0.621169, 0.000000, 0.000000], - [2.223562, 0.601125, 0.000000, 0.000000], - [2.235230, 0.581341, 0.000000, 0.000000], - [2.246289, 0.561847, 0.000000, 0.000000], - [2.256751, 0.542667, 0.000000, 0.000000], - [2.266631, 0.523826, 0.000000, 0.000000], - [2.275943, 0.505344, 0.000000, 0.000000], - [2.284707, 0.487239, 0.000000, 0.000000], - [2.292939, 0.469528, 0.000000, 0.000000], - [2.300661, 0.452225, 0.000000, 0.000000], - [2.307892, 0.435342, 0.000000, 0.000000], - [2.314654, 0.418888, 0.000000, 0.000000], - [2.320969, 0.402870, 0.000000, 0.000000], - [2.326858, 0.387294, 0.000000, 0.000000], - [2.332343, 0.372164, 0.000000, 0.000000], - [2.337445, 0.357481, 0.000000, 0.000000], - [2.342186, 0.343246, 0.000000, 0.000000], - [2.346585, 0.329458, 0.000000, 0.000000], - [2.350664, 0.316113, 0.000000, 0.000000], - [2.354442, 0.303208, 0.000000, 0.000000], - [2.357937, 0.290738, 0.000000, 0.000000], - [2.361168, 0.278698, 0.000000, 0.000000], - [2.364152, 0.267080, 0.000000, 0.000000], - [2.366906, 0.255878, 0.000000, 0.000000], - [2.369446, 0.245082, 0.000000, 0.000000], - [2.371786, 0.234685, 0.000000, 0.000000], - [2.373940, 0.224677, 0.000000, 0.000000], - [2.375923, 0.215048, 0.000000, 0.000000], - [2.377745, 0.205790, 0.000000, 0.000000], - [2.379421, 0.196891, 0.000000, 0.000000], - [2.380959, 0.188342, 0.000000, 0.000000], - [2.382372, 0.180132, 0.000000, 0.000000], - [2.383667, 0.172251, 0.000000, 0.000000], - [2.384856, 0.164689, 0.000000, 0.000000], - [2.385945, 0.157435, 0.000000, 0.000000], - [2.386943, 0.150479, 0.000000, 0.000000], - [2.387857, 0.143811, 0.000000, 0.000000], - [2.388694, 0.137421, 0.000000, 0.000000], - [2.389460, 0.131299, 0.000000, 0.000000], - [2.390160, 0.125435, 0.000000, 0.000000], - [2.390801, 0.119820, 0.000000, 0.000000], - [2.391386, 0.114445, 0.000000, 0.000000], - [2.391921, 0.109300, 0.000000, 0.000000], - [2.392410, 0.104376, 0.000000, 0.000000], - [2.392857, 0.099666, 0.000000, 0.000000], - [2.393265, 0.095160, 0.000000, 0.000000], - [2.393637, 0.090851, 0.000000, 0.000000], - [2.393977, 0.086731, 0.000000, 0.000000], - [2.394288, 0.082791, 0.000000, 0.000000], - [2.394571, 0.079025, 0.000000, 0.000000], - [2.394829, 0.075426, 0.000000, 0.000000], - [2.395064, 0.071986, 0.000000, 0.000000], - [2.395279, 0.068699, 0.000000, 0.000000], - [2.395475, 0.065558, 0.000000, 0.000000], - [2.395653, 0.062558, 0.000000, 0.000000], - [2.395816, 0.059693, 0.000000, 0.000000], - [2.395964, 0.056955, 0.000000, 0.000000], - [2.396099, 0.054341, 0.000000, 0.000000], - [2.396222, 0.051845, 0.000000, 0.000000], - [2.396334, 0.049462, 0.000000, 0.000000], - [2.396436, 0.047186, 0.000000, 0.000000], - [2.396529, 0.045013, 0.000000, 0.000000], - [2.396613, 0.042939, 0.000000, 0.000000], - [2.396691, 0.040959, 0.000000, 0.000000], - [2.396761, 0.039069, 0.000000, 0.000000], - [2.396825, 0.037266, 0.000000, 0.000000], - [2.396883, 0.035544, 0.000000, 0.000000], - [2.396936, 0.033901, 0.000000, 0.000000], - [2.396984, 0.032334, 0.000000, 0.000000], - [2.397028, 0.030838, 0.000000, 0.000000], - [2.397068, 0.029410, 0.000000, 0.000000], - [2.397104, 0.028048, 0.000000, 0.000000], - [2.397137, 0.026749, 0.000000, 0.000000], - [2.397167, 0.025509, 0.000000, 0.000000], - [2.397194, 0.024326, 0.000000, 0.000000], - [2.397219, 0.023198, 0.000000, 0.000000], - [2.397242, 0.022122, 0.000000, 0.000000], - [2.397262, 0.021095, 0.000000, 0.000000], - [2.397281, 0.020116, 0.000000, 0.000000], - [2.397298, 0.019181, 0.000000, 0.000000], - [2.397314, 0.018290, 0.000000, 0.000000], - [2.397328, 0.017441, 0.000000, 0.000000], - [2.397341, 0.016630, 0.000000, 0.000000], - [2.397352, 0.015857, 0.000000, 0.000000], - [2.397363, 0.015119, 0.000000, 0.000000], - [2.397372, 0.014416, 0.000000, 0.000000], - [2.397381, 0.013745, 0.000000, 0.000000], - [2.397389, 0.013106, 0.000000, 0.000000], - [2.397396, 0.012496, 0.000000, 0.000000], - [2.397403, 0.011914, 0.000000, 0.000000], - [2.397409, 0.011360, 0.000000, 0.000000], - [2.397414, 0.010831, 0.000000, 0.000000], - [2.397419, 0.010326, 0.000000, 0.000000], - [2.397424, 0.009845, 0.000000, 0.000000], - [2.397428, 0.009387, 0.000000, 0.000000], - [2.397432, 0.008949, 0.000000, 0.000000], - [2.397435, 0.008532, 0.000000, 0.000000], - [2.397438, 0.008135, 0.000000, 0.000000], - [2.397441, 0.007755, 0.000000, 0.000000], - [2.397443, 0.007394, 0.000000, 0.000000], - [2.397446, 0.007049, 0.000000, 0.000000], - [2.397448, 0.006721, 0.000000, 0.000000], - [2.397450, 0.006407, 0.000000, 0.000000], - [2.397451, 0.006108, 0.000000, 0.000000], - [2.397453, 0.005824, 0.000000, 0.000000], - [2.397454, 0.005552, 0.000000, 0.000000], - [2.397456, 0.005293, 0.000000, 0.000000], - [2.397457, 0.005046, 0.000000, 0.000000], - [2.397458, 0.004811, 0.000000, 0.000000], - [2.397459, 0.004586, 0.000000, 0.000000], - [2.397460, 0.004372, 0.000000, 0.000000], - [2.397461, 0.004168, 0.000000, 0.000000], - [2.397461, 0.003974, 0.000000, 0.000000], - [2.397462, 0.003788, 0.000000, 0.000000], - [2.397463, 0.003611, 0.000000, 0.000000], - [2.397463, 0.003443, 0.000000, 0.000000], - [2.397464, 0.003282, 0.000000, 0.000000], - [2.397464, 0.003129, 0.000000, 0.000000], - [2.397465, 0.002983, 0.000000, 0.000000], - [2.397465, 0.002844, 0.000000, 0.000000], - [2.397465, 0.002711, 0.000000, 0.000000], - [2.397466, 0.002584, 0.000000, 0.000000], - [2.397466, 0.002464, 0.000000, 0.000000], - [2.397466, 0.002349, 0.000000, 0.000000], - [2.397466, 0.002239, 0.000000, 0.000000], - [2.397467, 0.002135, 0.000000, 0.000000], - [2.397467, 0.002035, 0.000000, 0.000000], - [2.397467, 0.001940, 0.000000, 0.000000], - [2.397467, 0.001849, 0.000000, 0.000000], - [2.397467, 0.001763, 0.000000, 0.000000], - [2.397467, 0.001681, 0.000000, 0.000000], - [2.397468, 0.001602, 0.000000, 0.000000], - [2.397468, 0.001527, 0.000000, 0.000000], - [2.397468, 0.001456, 0.000000, 0.000000], - [2.397468, 0.001388, 0.000000, 0.000000], - [2.397468, 0.001323, 0.000000, 0.000000], - [2.397468, 0.001261, 0.000000, 0.000000], - [2.397468, 0.001202, 0.000000, 0.000000], - [2.397468, 0.001146, 0.000000, 0.000000], - [2.397468, 0.001093, 0.000000, 0.000000], - [2.397468, 0.001042, 0.000000, 0.000000], - [2.397468, 0.000993, 0.000000, 0.000000], - [2.397468, 0.000947, 0.000000, 0.000000], - [2.397468, 0.000902, 0.000000, 0.000000], - [2.397468, 0.000860, 0.000000, 0.000000], - [2.397468, 0.000820, 0.000000, 0.000000], - [2.397469, 0.000782, 0.000000, 0.000000], - [2.397469, 0.000745, 0.000000, 0.000000], - [2.397469, 0.000710, 0.000000, 0.000000], - [2.397469, 0.000677, 0.000000, 0.000000], - [2.397469, 0.000646, 0.000000, 0.000000], - [2.397469, 0.000616, 0.000000, 0.000000], - [2.397469, 0.000587, 0.000000, 0.000000], - [2.397469, 0.000559, 0.000000, 0.000000], - [2.397469, 0.000533, 0.000000, 0.000000], - [2.397469, 0.000508, 0.000000, 0.000000], - [2.397469, 0.000485, 0.000000, 0.000000], - [2.397469, 0.000462, 0.000000, 0.000000], - [2.397469, 0.000440, 0.000000, 0.000000], - [2.397469, 0.000420, 0.000000, 0.000000], - [2.397469, 0.000400, 0.000000, 0.000000], - [2.397469, 0.000381, 0.000000, 0.000000], - [2.397469, 0.000364, 0.000000, 0.000000], - [2.397469, 0.000347, 0.000000, 0.000000], - [2.397469, 0.000330, 0.000000, 0.000000], - [2.397469, 0.000315, 0.000000, 0.000000], - [2.397469, 0.000300, 0.000000, 0.000000], - [2.397469, 0.000286, 0.000000, 0.000000], - [2.397469, 0.000273, 0.000000, 0.000000], - [2.397469, 0.000260, 0.000000, 0.000000], - [2.397469, 0.000248, 0.000000, 0.000000], - [2.397469, 0.000236, 0.000000, 0.000000], - [2.397469, 0.000225, 0.000000, 0.000000], - [2.397469, 0.000215, 0.000000, 0.000000], - [2.397469, 0.000205, 0.000000, 0.000000], - [2.397469, 0.000195, 0.000000, 0.000000], - [2.397469, 0.000186, 0.000000, 0.000000], - [2.397469, 0.000177, 0.000000, 0.000000], - [2.397469, 0.000169, 0.000000, 0.000000], - [2.397469, 0.000161, 0.000000, 0.000000], - [2.397469, 0.000154, 0.000000, 0.000000], - [2.397469, 0.000147, 0.000000, 0.000000], - [2.397469, 0.000140, 0.000000, 0.000000], - [2.397469, 0.000133, 0.000000, 0.000000], - [2.397469, 0.000127, 0.000000, 0.000000], - [2.397469, 0.000121, 0.000000, 0.000000], - [2.397469, 0.000115, 0.000000, 0.000000], - [2.397469, 0.000110, 0.000000, 0.000000], - [2.397469, 0.000105, 0.000000, 0.000000], - [2.397469, 0.000100, 0.000000, 0.000000], - [2.397469, 0.000095, 0.000000, 0.000000], - [2.397469, 0.000091, 0.000000, 0.000000], - [2.397469, 0.000087, 0.000000, 0.000000], - [2.397469, 0.000083, 0.000000, 0.000000], - [2.397469, 0.000079, 0.000000, 0.000000], - [2.397469, 0.000075, 0.000000, 0.000000], - [2.397469, 0.000071, 0.000000, 0.000000], - [2.397469, 0.000068, 0.000000, 0.000000], - [2.397469, 0.000065, 0.000000, 0.000000], - [2.397469, 0.000062, 0.000000, 0.000000], - [2.397469, 0.000059, 0.000000, 0.000000], - [2.397469, 0.000056, 0.000000, 0.000000], - [2.397469, 0.000054, 0.000000, 0.000000], - [2.397469, 0.000051, 0.000000, 0.000000], - [2.397469, 0.000049, 0.000000, 0.000000], - [2.397469, 0.000046, 0.000000, 0.000000], - [2.397469, 0.000044, 0.000000, 0.000000], - [2.397469, 0.000042, 0.000000, 0.000000], - [2.397469, 0.000040, 0.000000, 0.000000], - [2.397469, 0.000038, 0.000000, 0.000000], - [2.397469, 0.000037, 0.000000, 0.000000], - [2.397469, 0.000035, 0.000000, 0.000000], - [2.397469, 0.000033, 0.000000, 0.000000], - [2.397469, 0.000032, 0.000000, 0.000000], - [2.397469, 0.000030, 0.000000, 0.000000], - [2.397469, 0.000029, 0.000000, 0.000000], - [2.397469, 0.000027, 0.000000, 0.000000], - [2.397469, 0.000026, 0.000000, 0.000000], - [2.397469, 0.000025, 0.000000, 0.000000], - [2.397469, 0.000024, 0.000000, 0.000000], - [2.397469, 0.000023, 0.000000, 0.000000], - [2.397469, 0.000022, 0.000000, 0.000000], - [2.397469, 0.000021, 0.000000, 0.000000], - [2.397469, 0.000020, 0.000000, 0.000000], - [2.397469, 0.000019, 0.000000, 0.000000], - [2.397469, 0.000018, 0.000000, 0.000000], - [2.397469, 0.000017, 0.000000, 0.000000], - [2.397469, 0.000016, 0.000000, 0.000000], - [2.397469, 0.000015, 0.000000, 0.000000], - [2.397469, 0.000015, 0.000000, 0.000000], - [2.397469, 0.000014, 0.000000, 0.000000], - [2.397469, 0.000013, 0.000000, 0.000000], - [2.397469, 0.000013, 0.000000, 0.000000], - [2.397469, 0.000012, 0.000000, 0.000000], - [2.397469, 0.000012, 0.000000, 0.000000], - [2.397469, 0.000011, 0.000000, 0.000000], - [2.397469, 0.000011, 0.000000, 0.000000], - [2.397469, 0.000010, 0.000000, 0.000000], - [2.397469, 0.000010, 0.000000, 0.000000], - [2.397469, 0.000009, 0.000000, 0.000000], - [2.397469, 0.000009, 0.000000, 0.000000], - [2.397469, 0.000008, 0.000000, 0.000000], - [2.397469, 0.000008, 0.000000, 0.000000], - [2.397469, 0.000008, 0.000000, 0.000000], - [2.397469, 0.000007, 0.000000, 0.000000], - [2.397469, 0.000007, 0.000000, 0.000000], - [2.397469, 0.000007, 0.000000, 0.000000], - [2.397469, 0.000006, 0.000000, 0.000000], - [2.397469, 0.000006, 0.000000, 0.000000], - [2.397469, 0.000006, 0.000000, 0.000000], - [2.397469, 0.000005, 0.000000, 0.000000], - [2.397469, 0.000005, 0.000000, 0.000000], - [2.397469, 0.000005, 0.000000, 0.000000], - [2.397469, 0.000005, 0.000000, 0.000000], - [2.397469, 0.000004, 0.000000, 0.000000], - [2.397469, 0.000004, 0.000000, 0.000000], - [2.397469, 0.000004, 0.000000, 0.000000], - [2.397469, 0.000004, 0.000000, 0.000000], - [2.397469, 0.000004, 0.000000, 0.000000], - [2.397469, 0.000004, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000003, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000002, 0.000000, 0.000000], - [2.397469, 0.000001, 0.000000, 0.000000], - [2.397469, 0.000001, 0.000000, 0.000000], - [2.397469, 0.000001, 0.000000, 0.000000], -]; -/** @type {Number} */ -const MAX_RE_WEIGHTS_RESOLUTION = MAX_RE_WEIGHTS.length; -export default { - SPHERICAL_HARMONICS, - SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION, - SPHERICAL_HARMONICS_ELEVATION_RESOLUTION, - SPHERICAL_HARMONICS_MAX_ORDER, - MAX_RE_WEIGHTS, - MAX_RE_WEIGHTS_RESOLUTION -}; +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 Pre-computed lookup tables for encoding ambisonic sources. + * @author Andrew Allen + */ +'use strict'; +/** + * Pre-computed Spherical Harmonics Coefficients. + * + * This function generates an efficient lookup table of SH coefficients. It + * exploits the way SHs are generated (i.e. Ylm = Nlm * Plm * Em). Since Nlm + * & Plm coefficients only depend on theta, and Em only depends on phi, we + * can separate the equation along these lines. Em does not depend on + * degree, so we only need to compute (2 * l) per azimuth Em total and + * Nlm * Plm is symmetrical across indexes, so only positive indexes are + * computed ((l + 1) * (l + 2) / 2 - 1) per elevation. + * @type {Float32Array} + */ +const SPHERICAL_HARMONICS = [ + [ + [0.000000, 0.000000, 0.000000, 1.000000, 1.000000, 1.000000], + [0.052336, 0.034899, 0.017452, 0.999848, 0.999391, 0.998630], + [0.104528, 0.069756, 0.034899, 0.999391, 0.997564, 0.994522], + [0.156434, 0.104528, 0.052336, 0.998630, 0.994522, 0.987688], + [0.207912, 0.139173, 0.069756, 0.997564, 0.990268, 0.978148], + [0.258819, 0.173648, 0.087156, 0.996195, 0.984808, 0.965926], + [0.309017, 0.207912, 0.104528, 0.994522, 0.978148, 0.951057], + [0.358368, 0.241922, 0.121869, 0.992546, 0.970296, 0.933580], + [0.406737, 0.275637, 0.139173, 0.990268, 0.961262, 0.913545], + [0.453990, 0.309017, 0.156434, 0.987688, 0.951057, 0.891007], + [0.500000, 0.342020, 0.173648, 0.984808, 0.939693, 0.866025], + [0.544639, 0.374607, 0.190809, 0.981627, 0.927184, 0.838671], + [0.587785, 0.406737, 0.207912, 0.978148, 0.913545, 0.809017], + [0.629320, 0.438371, 0.224951, 0.974370, 0.898794, 0.777146], + [0.669131, 0.469472, 0.241922, 0.970296, 0.882948, 0.743145], + [0.707107, 0.500000, 0.258819, 0.965926, 0.866025, 0.707107], + [0.743145, 0.529919, 0.275637, 0.961262, 0.848048, 0.669131], + [0.777146, 0.559193, 0.292372, 0.956305, 0.829038, 0.629320], + [0.809017, 0.587785, 0.309017, 0.951057, 0.809017, 0.587785], + [0.838671, 0.615661, 0.325568, 0.945519, 0.788011, 0.544639], + [0.866025, 0.642788, 0.342020, 0.939693, 0.766044, 0.500000], + [0.891007, 0.669131, 0.358368, 0.933580, 0.743145, 0.453990], + [0.913545, 0.694658, 0.374607, 0.927184, 0.719340, 0.406737], + [0.933580, 0.719340, 0.390731, 0.920505, 0.694658, 0.358368], + [0.951057, 0.743145, 0.406737, 0.913545, 0.669131, 0.309017], + [0.965926, 0.766044, 0.422618, 0.906308, 0.642788, 0.258819], + [0.978148, 0.788011, 0.438371, 0.898794, 0.615661, 0.207912], + [0.987688, 0.809017, 0.453990, 0.891007, 0.587785, 0.156434], + [0.994522, 0.829038, 0.469472, 0.882948, 0.559193, 0.104528], + [0.998630, 0.848048, 0.484810, 0.874620, 0.529919, 0.052336], + [1.000000, 0.866025, 0.500000, 0.866025, 0.500000, 0.000000], + [0.998630, 0.882948, 0.515038, 0.857167, 0.469472, -0.052336], + [0.994522, 0.898794, 0.529919, 0.848048, 0.438371, -0.104528], + [0.987688, 0.913545, 0.544639, 0.838671, 0.406737, -0.156434], + [0.978148, 0.927184, 0.559193, 0.829038, 0.374607, -0.207912], + [0.965926, 0.939693, 0.573576, 0.819152, 0.342020, -0.258819], + [0.951057, 0.951057, 0.587785, 0.809017, 0.309017, -0.309017], + [0.933580, 0.961262, 0.601815, 0.798636, 0.275637, -0.358368], + [0.913545, 0.970296, 0.615661, 0.788011, 0.241922, -0.406737], + [0.891007, 0.978148, 0.629320, 0.777146, 0.207912, -0.453990], + [0.866025, 0.984808, 0.642788, 0.766044, 0.173648, -0.500000], + [0.838671, 0.990268, 0.656059, 0.754710, 0.139173, -0.544639], + [0.809017, 0.994522, 0.669131, 0.743145, 0.104528, -0.587785], + [0.777146, 0.997564, 0.681998, 0.731354, 0.069756, -0.629320], + [0.743145, 0.999391, 0.694658, 0.719340, 0.034899, -0.669131], + [0.707107, 1.000000, 0.707107, 0.707107, 0.000000, -0.707107], + [0.669131, 0.999391, 0.719340, 0.694658, -0.034899, -0.743145], + [0.629320, 0.997564, 0.731354, 0.681998, -0.069756, -0.777146], + [0.587785, 0.994522, 0.743145, 0.669131, -0.104528, -0.809017], + [0.544639, 0.990268, 0.754710, 0.656059, -0.139173, -0.838671], + [0.500000, 0.984808, 0.766044, 0.642788, -0.173648, -0.866025], + [0.453990, 0.978148, 0.777146, 0.629320, -0.207912, -0.891007], + [0.406737, 0.970296, 0.788011, 0.615661, -0.241922, -0.913545], + [0.358368, 0.961262, 0.798636, 0.601815, -0.275637, -0.933580], + [0.309017, 0.951057, 0.809017, 0.587785, -0.309017, -0.951057], + [0.258819, 0.939693, 0.819152, 0.573576, -0.342020, -0.965926], + [0.207912, 0.927184, 0.829038, 0.559193, -0.374607, -0.978148], + [0.156434, 0.913545, 0.838671, 0.544639, -0.406737, -0.987688], + [0.104528, 0.898794, 0.848048, 0.529919, -0.438371, -0.994522], + [0.052336, 0.882948, 0.857167, 0.515038, -0.469472, -0.998630], + [0.000000, 0.866025, 0.866025, 0.500000, -0.500000, -1.000000], + [-0.052336, 0.848048, 0.874620, 0.484810, -0.529919, -0.998630], + [-0.104528, 0.829038, 0.882948, 0.469472, -0.559193, -0.994522], + [-0.156434, 0.809017, 0.891007, 0.453990, -0.587785, -0.987688], + [-0.207912, 0.788011, 0.898794, 0.438371, -0.615661, -0.978148], + [-0.258819, 0.766044, 0.906308, 0.422618, -0.642788, -0.965926], + [-0.309017, 0.743145, 0.913545, 0.406737, -0.669131, -0.951057], + [-0.358368, 0.719340, 0.920505, 0.390731, -0.694658, -0.933580], + [-0.406737, 0.694658, 0.927184, 0.374607, -0.719340, -0.913545], + [-0.453990, 0.669131, 0.933580, 0.358368, -0.743145, -0.891007], + [-0.500000, 0.642788, 0.939693, 0.342020, -0.766044, -0.866025], + [-0.544639, 0.615661, 0.945519, 0.325568, -0.788011, -0.838671], + [-0.587785, 0.587785, 0.951057, 0.309017, -0.809017, -0.809017], + [-0.629320, 0.559193, 0.956305, 0.292372, -0.829038, -0.777146], + [-0.669131, 0.529919, 0.961262, 0.275637, -0.848048, -0.743145], + [-0.707107, 0.500000, 0.965926, 0.258819, -0.866025, -0.707107], + [-0.743145, 0.469472, 0.970296, 0.241922, -0.882948, -0.669131], + [-0.777146, 0.438371, 0.974370, 0.224951, -0.898794, -0.629320], + [-0.809017, 0.406737, 0.978148, 0.207912, -0.913545, -0.587785], + [-0.838671, 0.374607, 0.981627, 0.190809, -0.927184, -0.544639], + [-0.866025, 0.342020, 0.984808, 0.173648, -0.939693, -0.500000], + [-0.891007, 0.309017, 0.987688, 0.156434, -0.951057, -0.453990], + [-0.913545, 0.275637, 0.990268, 0.139173, -0.961262, -0.406737], + [-0.933580, 0.241922, 0.992546, 0.121869, -0.970296, -0.358368], + [-0.951057, 0.207912, 0.994522, 0.104528, -0.978148, -0.309017], + [-0.965926, 0.173648, 0.996195, 0.087156, -0.984808, -0.258819], + [-0.978148, 0.139173, 0.997564, 0.069756, -0.990268, -0.207912], + [-0.987688, 0.104528, 0.998630, 0.052336, -0.994522, -0.156434], + [-0.994522, 0.069756, 0.999391, 0.034899, -0.997564, -0.104528], + [-0.998630, 0.034899, 0.999848, 0.017452, -0.999391, -0.052336], + [-1.000000, 0.000000, 1.000000, 0.000000, -1.000000, -0.000000], + [-0.998630, -0.034899, 0.999848, -0.017452, -0.999391, 0.052336], + [-0.994522, -0.069756, 0.999391, -0.034899, -0.997564, 0.104528], + [-0.987688, -0.104528, 0.998630, -0.052336, -0.994522, 0.156434], + [-0.978148, -0.139173, 0.997564, -0.069756, -0.990268, 0.207912], + [-0.965926, -0.173648, 0.996195, -0.087156, -0.984808, 0.258819], + [-0.951057, -0.207912, 0.994522, -0.104528, -0.978148, 0.309017], + [-0.933580, -0.241922, 0.992546, -0.121869, -0.970296, 0.358368], + [-0.913545, -0.275637, 0.990268, -0.139173, -0.961262, 0.406737], + [-0.891007, -0.309017, 0.987688, -0.156434, -0.951057, 0.453990], + [-0.866025, -0.342020, 0.984808, -0.173648, -0.939693, 0.500000], + [-0.838671, -0.374607, 0.981627, -0.190809, -0.927184, 0.544639], + [-0.809017, -0.406737, 0.978148, -0.207912, -0.913545, 0.587785], + [-0.777146, -0.438371, 0.974370, -0.224951, -0.898794, 0.629320], + [-0.743145, -0.469472, 0.970296, -0.241922, -0.882948, 0.669131], + [-0.707107, -0.500000, 0.965926, -0.258819, -0.866025, 0.707107], + [-0.669131, -0.529919, 0.961262, -0.275637, -0.848048, 0.743145], + [-0.629320, -0.559193, 0.956305, -0.292372, -0.829038, 0.777146], + [-0.587785, -0.587785, 0.951057, -0.309017, -0.809017, 0.809017], + [-0.544639, -0.615661, 0.945519, -0.325568, -0.788011, 0.838671], + [-0.500000, -0.642788, 0.939693, -0.342020, -0.766044, 0.866025], + [-0.453990, -0.669131, 0.933580, -0.358368, -0.743145, 0.891007], + [-0.406737, -0.694658, 0.927184, -0.374607, -0.719340, 0.913545], + [-0.358368, -0.719340, 0.920505, -0.390731, -0.694658, 0.933580], + [-0.309017, -0.743145, 0.913545, -0.406737, -0.669131, 0.951057], + [-0.258819, -0.766044, 0.906308, -0.422618, -0.642788, 0.965926], + [-0.207912, -0.788011, 0.898794, -0.438371, -0.615661, 0.978148], + [-0.156434, -0.809017, 0.891007, -0.453990, -0.587785, 0.987688], + [-0.104528, -0.829038, 0.882948, -0.469472, -0.559193, 0.994522], + [-0.052336, -0.848048, 0.874620, -0.484810, -0.529919, 0.998630], + [-0.000000, -0.866025, 0.866025, -0.500000, -0.500000, 1.000000], + [0.052336, -0.882948, 0.857167, -0.515038, -0.469472, 0.998630], + [0.104528, -0.898794, 0.848048, -0.529919, -0.438371, 0.994522], + [0.156434, -0.913545, 0.838671, -0.544639, -0.406737, 0.987688], + [0.207912, -0.927184, 0.829038, -0.559193, -0.374607, 0.978148], + [0.258819, -0.939693, 0.819152, -0.573576, -0.342020, 0.965926], + [0.309017, -0.951057, 0.809017, -0.587785, -0.309017, 0.951057], + [0.358368, -0.961262, 0.798636, -0.601815, -0.275637, 0.933580], + [0.406737, -0.970296, 0.788011, -0.615661, -0.241922, 0.913545], + [0.453990, -0.978148, 0.777146, -0.629320, -0.207912, 0.891007], + [0.500000, -0.984808, 0.766044, -0.642788, -0.173648, 0.866025], + [0.544639, -0.990268, 0.754710, -0.656059, -0.139173, 0.838671], + [0.587785, -0.994522, 0.743145, -0.669131, -0.104528, 0.809017], + [0.629320, -0.997564, 0.731354, -0.681998, -0.069756, 0.777146], + [0.669131, -0.999391, 0.719340, -0.694658, -0.034899, 0.743145], + [0.707107, -1.000000, 0.707107, -0.707107, -0.000000, 0.707107], + [0.743145, -0.999391, 0.694658, -0.719340, 0.034899, 0.669131], + [0.777146, -0.997564, 0.681998, -0.731354, 0.069756, 0.629320], + [0.809017, -0.994522, 0.669131, -0.743145, 0.104528, 0.587785], + [0.838671, -0.990268, 0.656059, -0.754710, 0.139173, 0.544639], + [0.866025, -0.984808, 0.642788, -0.766044, 0.173648, 0.500000], + [0.891007, -0.978148, 0.629320, -0.777146, 0.207912, 0.453990], + [0.913545, -0.970296, 0.615661, -0.788011, 0.241922, 0.406737], + [0.933580, -0.961262, 0.601815, -0.798636, 0.275637, 0.358368], + [0.951057, -0.951057, 0.587785, -0.809017, 0.309017, 0.309017], + [0.965926, -0.939693, 0.573576, -0.819152, 0.342020, 0.258819], + [0.978148, -0.927184, 0.559193, -0.829038, 0.374607, 0.207912], + [0.987688, -0.913545, 0.544639, -0.838671, 0.406737, 0.156434], + [0.994522, -0.898794, 0.529919, -0.848048, 0.438371, 0.104528], + [0.998630, -0.882948, 0.515038, -0.857167, 0.469472, 0.052336], + [1.000000, -0.866025, 0.500000, -0.866025, 0.500000, 0.000000], + [0.998630, -0.848048, 0.484810, -0.874620, 0.529919, -0.052336], + [0.994522, -0.829038, 0.469472, -0.882948, 0.559193, -0.104528], + [0.987688, -0.809017, 0.453990, -0.891007, 0.587785, -0.156434], + [0.978148, -0.788011, 0.438371, -0.898794, 0.615661, -0.207912], + [0.965926, -0.766044, 0.422618, -0.906308, 0.642788, -0.258819], + [0.951057, -0.743145, 0.406737, -0.913545, 0.669131, -0.309017], + [0.933580, -0.719340, 0.390731, -0.920505, 0.694658, -0.358368], + [0.913545, -0.694658, 0.374607, -0.927184, 0.719340, -0.406737], + [0.891007, -0.669131, 0.358368, -0.933580, 0.743145, -0.453990], + [0.866025, -0.642788, 0.342020, -0.939693, 0.766044, -0.500000], + [0.838671, -0.615661, 0.325568, -0.945519, 0.788011, -0.544639], + [0.809017, -0.587785, 0.309017, -0.951057, 0.809017, -0.587785], + [0.777146, -0.559193, 0.292372, -0.956305, 0.829038, -0.629320], + [0.743145, -0.529919, 0.275637, -0.961262, 0.848048, -0.669131], + [0.707107, -0.500000, 0.258819, -0.965926, 0.866025, -0.707107], + [0.669131, -0.469472, 0.241922, -0.970296, 0.882948, -0.743145], + [0.629320, -0.438371, 0.224951, -0.974370, 0.898794, -0.777146], + [0.587785, -0.406737, 0.207912, -0.978148, 0.913545, -0.809017], + [0.544639, -0.374607, 0.190809, -0.981627, 0.927184, -0.838671], + [0.500000, -0.342020, 0.173648, -0.984808, 0.939693, -0.866025], + [0.453990, -0.309017, 0.156434, -0.987688, 0.951057, -0.891007], + [0.406737, -0.275637, 0.139173, -0.990268, 0.961262, -0.913545], + [0.358368, -0.241922, 0.121869, -0.992546, 0.970296, -0.933580], + [0.309017, -0.207912, 0.104528, -0.994522, 0.978148, -0.951057], + [0.258819, -0.173648, 0.087156, -0.996195, 0.984808, -0.965926], + [0.207912, -0.139173, 0.069756, -0.997564, 0.990268, -0.978148], + [0.156434, -0.104528, 0.052336, -0.998630, 0.994522, -0.987688], + [0.104528, -0.069756, 0.034899, -0.999391, 0.997564, -0.994522], + [0.052336, -0.034899, 0.017452, -0.999848, 0.999391, -0.998630], + [0.000000, -0.000000, 0.000000, -1.000000, 1.000000, -1.000000], + [-0.052336, 0.034899, -0.017452, -0.999848, 0.999391, -0.998630], + [-0.104528, 0.069756, -0.034899, -0.999391, 0.997564, -0.994522], + [-0.156434, 0.104528, -0.052336, -0.998630, 0.994522, -0.987688], + [-0.207912, 0.139173, -0.069756, -0.997564, 0.990268, -0.978148], + [-0.258819, 0.173648, -0.087156, -0.996195, 0.984808, -0.965926], + [-0.309017, 0.207912, -0.104528, -0.994522, 0.978148, -0.951057], + [-0.358368, 0.241922, -0.121869, -0.992546, 0.970296, -0.933580], + [-0.406737, 0.275637, -0.139173, -0.990268, 0.961262, -0.913545], + [-0.453990, 0.309017, -0.156434, -0.987688, 0.951057, -0.891007], + [-0.500000, 0.342020, -0.173648, -0.984808, 0.939693, -0.866025], + [-0.544639, 0.374607, -0.190809, -0.981627, 0.927184, -0.838671], + [-0.587785, 0.406737, -0.207912, -0.978148, 0.913545, -0.809017], + [-0.629320, 0.438371, -0.224951, -0.974370, 0.898794, -0.777146], + [-0.669131, 0.469472, -0.241922, -0.970296, 0.882948, -0.743145], + [-0.707107, 0.500000, -0.258819, -0.965926, 0.866025, -0.707107], + [-0.743145, 0.529919, -0.275637, -0.961262, 0.848048, -0.669131], + [-0.777146, 0.559193, -0.292372, -0.956305, 0.829038, -0.629320], + [-0.809017, 0.587785, -0.309017, -0.951057, 0.809017, -0.587785], + [-0.838671, 0.615661, -0.325568, -0.945519, 0.788011, -0.544639], + [-0.866025, 0.642788, -0.342020, -0.939693, 0.766044, -0.500000], + [-0.891007, 0.669131, -0.358368, -0.933580, 0.743145, -0.453990], + [-0.913545, 0.694658, -0.374607, -0.927184, 0.719340, -0.406737], + [-0.933580, 0.719340, -0.390731, -0.920505, 0.694658, -0.358368], + [-0.951057, 0.743145, -0.406737, -0.913545, 0.669131, -0.309017], + [-0.965926, 0.766044, -0.422618, -0.906308, 0.642788, -0.258819], + [-0.978148, 0.788011, -0.438371, -0.898794, 0.615661, -0.207912], + [-0.987688, 0.809017, -0.453990, -0.891007, 0.587785, -0.156434], + [-0.994522, 0.829038, -0.469472, -0.882948, 0.559193, -0.104528], + [-0.998630, 0.848048, -0.484810, -0.874620, 0.529919, -0.052336], + [-1.000000, 0.866025, -0.500000, -0.866025, 0.500000, 0.000000], + [-0.998630, 0.882948, -0.515038, -0.857167, 0.469472, 0.052336], + [-0.994522, 0.898794, -0.529919, -0.848048, 0.438371, 0.104528], + [-0.987688, 0.913545, -0.544639, -0.838671, 0.406737, 0.156434], + [-0.978148, 0.927184, -0.559193, -0.829038, 0.374607, 0.207912], + [-0.965926, 0.939693, -0.573576, -0.819152, 0.342020, 0.258819], + [-0.951057, 0.951057, -0.587785, -0.809017, 0.309017, 0.309017], + [-0.933580, 0.961262, -0.601815, -0.798636, 0.275637, 0.358368], + [-0.913545, 0.970296, -0.615661, -0.788011, 0.241922, 0.406737], + [-0.891007, 0.978148, -0.629320, -0.777146, 0.207912, 0.453990], + [-0.866025, 0.984808, -0.642788, -0.766044, 0.173648, 0.500000], + [-0.838671, 0.990268, -0.656059, -0.754710, 0.139173, 0.544639], + [-0.809017, 0.994522, -0.669131, -0.743145, 0.104528, 0.587785], + [-0.777146, 0.997564, -0.681998, -0.731354, 0.069756, 0.629320], + [-0.743145, 0.999391, -0.694658, -0.719340, 0.034899, 0.669131], + [-0.707107, 1.000000, -0.707107, -0.707107, 0.000000, 0.707107], + [-0.669131, 0.999391, -0.719340, -0.694658, -0.034899, 0.743145], + [-0.629320, 0.997564, -0.731354, -0.681998, -0.069756, 0.777146], + [-0.587785, 0.994522, -0.743145, -0.669131, -0.104528, 0.809017], + [-0.544639, 0.990268, -0.754710, -0.656059, -0.139173, 0.838671], + [-0.500000, 0.984808, -0.766044, -0.642788, -0.173648, 0.866025], + [-0.453990, 0.978148, -0.777146, -0.629320, -0.207912, 0.891007], + [-0.406737, 0.970296, -0.788011, -0.615661, -0.241922, 0.913545], + [-0.358368, 0.961262, -0.798636, -0.601815, -0.275637, 0.933580], + [-0.309017, 0.951057, -0.809017, -0.587785, -0.309017, 0.951057], + [-0.258819, 0.939693, -0.819152, -0.573576, -0.342020, 0.965926], + [-0.207912, 0.927184, -0.829038, -0.559193, -0.374607, 0.978148], + [-0.156434, 0.913545, -0.838671, -0.544639, -0.406737, 0.987688], + [-0.104528, 0.898794, -0.848048, -0.529919, -0.438371, 0.994522], + [-0.052336, 0.882948, -0.857167, -0.515038, -0.469472, 0.998630], + [-0.000000, 0.866025, -0.866025, -0.500000, -0.500000, 1.000000], + [0.052336, 0.848048, -0.874620, -0.484810, -0.529919, 0.998630], + [0.104528, 0.829038, -0.882948, -0.469472, -0.559193, 0.994522], + [0.156434, 0.809017, -0.891007, -0.453990, -0.587785, 0.987688], + [0.207912, 0.788011, -0.898794, -0.438371, -0.615661, 0.978148], + [0.258819, 0.766044, -0.906308, -0.422618, -0.642788, 0.965926], + [0.309017, 0.743145, -0.913545, -0.406737, -0.669131, 0.951057], + [0.358368, 0.719340, -0.920505, -0.390731, -0.694658, 0.933580], + [0.406737, 0.694658, -0.927184, -0.374607, -0.719340, 0.913545], + [0.453990, 0.669131, -0.933580, -0.358368, -0.743145, 0.891007], + [0.500000, 0.642788, -0.939693, -0.342020, -0.766044, 0.866025], + [0.544639, 0.615661, -0.945519, -0.325568, -0.788011, 0.838671], + [0.587785, 0.587785, -0.951057, -0.309017, -0.809017, 0.809017], + [0.629320, 0.559193, -0.956305, -0.292372, -0.829038, 0.777146], + [0.669131, 0.529919, -0.961262, -0.275637, -0.848048, 0.743145], + [0.707107, 0.500000, -0.965926, -0.258819, -0.866025, 0.707107], + [0.743145, 0.469472, -0.970296, -0.241922, -0.882948, 0.669131], + [0.777146, 0.438371, -0.974370, -0.224951, -0.898794, 0.629320], + [0.809017, 0.406737, -0.978148, -0.207912, -0.913545, 0.587785], + [0.838671, 0.374607, -0.981627, -0.190809, -0.927184, 0.544639], + [0.866025, 0.342020, -0.984808, -0.173648, -0.939693, 0.500000], + [0.891007, 0.309017, -0.987688, -0.156434, -0.951057, 0.453990], + [0.913545, 0.275637, -0.990268, -0.139173, -0.961262, 0.406737], + [0.933580, 0.241922, -0.992546, -0.121869, -0.970296, 0.358368], + [0.951057, 0.207912, -0.994522, -0.104528, -0.978148, 0.309017], + [0.965926, 0.173648, -0.996195, -0.087156, -0.984808, 0.258819], + [0.978148, 0.139173, -0.997564, -0.069756, -0.990268, 0.207912], + [0.987688, 0.104528, -0.998630, -0.052336, -0.994522, 0.156434], + [0.994522, 0.069756, -0.999391, -0.034899, -0.997564, 0.104528], + [0.998630, 0.034899, -0.999848, -0.017452, -0.999391, 0.052336], + [1.000000, 0.000000, -1.000000, -0.000000, -1.000000, 0.000000], + [0.998630, -0.034899, -0.999848, 0.017452, -0.999391, -0.052336], + [0.994522, -0.069756, -0.999391, 0.034899, -0.997564, -0.104528], + [0.987688, -0.104528, -0.998630, 0.052336, -0.994522, -0.156434], + [0.978148, -0.139173, -0.997564, 0.069756, -0.990268, -0.207912], + [0.965926, -0.173648, -0.996195, 0.087156, -0.984808, -0.258819], + [0.951057, -0.207912, -0.994522, 0.104528, -0.978148, -0.309017], + [0.933580, -0.241922, -0.992546, 0.121869, -0.970296, -0.358368], + [0.913545, -0.275637, -0.990268, 0.139173, -0.961262, -0.406737], + [0.891007, -0.309017, -0.987688, 0.156434, -0.951057, -0.453990], + [0.866025, -0.342020, -0.984808, 0.173648, -0.939693, -0.500000], + [0.838671, -0.374607, -0.981627, 0.190809, -0.927184, -0.544639], + [0.809017, -0.406737, -0.978148, 0.207912, -0.913545, -0.587785], + [0.777146, -0.438371, -0.974370, 0.224951, -0.898794, -0.629320], + [0.743145, -0.469472, -0.970296, 0.241922, -0.882948, -0.669131], + [0.707107, -0.500000, -0.965926, 0.258819, -0.866025, -0.707107], + [0.669131, -0.529919, -0.961262, 0.275637, -0.848048, -0.743145], + [0.629320, -0.559193, -0.956305, 0.292372, -0.829038, -0.777146], + [0.587785, -0.587785, -0.951057, 0.309017, -0.809017, -0.809017], + [0.544639, -0.615661, -0.945519, 0.325568, -0.788011, -0.838671], + [0.500000, -0.642788, -0.939693, 0.342020, -0.766044, -0.866025], + [0.453990, -0.669131, -0.933580, 0.358368, -0.743145, -0.891007], + [0.406737, -0.694658, -0.927184, 0.374607, -0.719340, -0.913545], + [0.358368, -0.719340, -0.920505, 0.390731, -0.694658, -0.933580], + [0.309017, -0.743145, -0.913545, 0.406737, -0.669131, -0.951057], + [0.258819, -0.766044, -0.906308, 0.422618, -0.642788, -0.965926], + [0.207912, -0.788011, -0.898794, 0.438371, -0.615661, -0.978148], + [0.156434, -0.809017, -0.891007, 0.453990, -0.587785, -0.987688], + [0.104528, -0.829038, -0.882948, 0.469472, -0.559193, -0.994522], + [0.052336, -0.848048, -0.874620, 0.484810, -0.529919, -0.998630], + [0.000000, -0.866025, -0.866025, 0.500000, -0.500000, -1.000000], + [-0.052336, -0.882948, -0.857167, 0.515038, -0.469472, -0.998630], + [-0.104528, -0.898794, -0.848048, 0.529919, -0.438371, -0.994522], + [-0.156434, -0.913545, -0.838671, 0.544639, -0.406737, -0.987688], + [-0.207912, -0.927184, -0.829038, 0.559193, -0.374607, -0.978148], + [-0.258819, -0.939693, -0.819152, 0.573576, -0.342020, -0.965926], + [-0.309017, -0.951057, -0.809017, 0.587785, -0.309017, -0.951057], + [-0.358368, -0.961262, -0.798636, 0.601815, -0.275637, -0.933580], + [-0.406737, -0.970296, -0.788011, 0.615661, -0.241922, -0.913545], + [-0.453990, -0.978148, -0.777146, 0.629320, -0.207912, -0.891007], + [-0.500000, -0.984808, -0.766044, 0.642788, -0.173648, -0.866025], + [-0.544639, -0.990268, -0.754710, 0.656059, -0.139173, -0.838671], + [-0.587785, -0.994522, -0.743145, 0.669131, -0.104528, -0.809017], + [-0.629320, -0.997564, -0.731354, 0.681998, -0.069756, -0.777146], + [-0.669131, -0.999391, -0.719340, 0.694658, -0.034899, -0.743145], + [-0.707107, -1.000000, -0.707107, 0.707107, -0.000000, -0.707107], + [-0.743145, -0.999391, -0.694658, 0.719340, 0.034899, -0.669131], + [-0.777146, -0.997564, -0.681998, 0.731354, 0.069756, -0.629320], + [-0.809017, -0.994522, -0.669131, 0.743145, 0.104528, -0.587785], + [-0.838671, -0.990268, -0.656059, 0.754710, 0.139173, -0.544639], + [-0.866025, -0.984808, -0.642788, 0.766044, 0.173648, -0.500000], + [-0.891007, -0.978148, -0.629320, 0.777146, 0.207912, -0.453990], + [-0.913545, -0.970296, -0.615661, 0.788011, 0.241922, -0.406737], + [-0.933580, -0.961262, -0.601815, 0.798636, 0.275637, -0.358368], + [-0.951057, -0.951057, -0.587785, 0.809017, 0.309017, -0.309017], + [-0.965926, -0.939693, -0.573576, 0.819152, 0.342020, -0.258819], + [-0.978148, -0.927184, -0.559193, 0.829038, 0.374607, -0.207912], + [-0.987688, -0.913545, -0.544639, 0.838671, 0.406737, -0.156434], + [-0.994522, -0.898794, -0.529919, 0.848048, 0.438371, -0.104528], + [-0.998630, -0.882948, -0.515038, 0.857167, 0.469472, -0.052336], + [-1.000000, -0.866025, -0.500000, 0.866025, 0.500000, -0.000000], + [-0.998630, -0.848048, -0.484810, 0.874620, 0.529919, 0.052336], + [-0.994522, -0.829038, -0.469472, 0.882948, 0.559193, 0.104528], + [-0.987688, -0.809017, -0.453990, 0.891007, 0.587785, 0.156434], + [-0.978148, -0.788011, -0.438371, 0.898794, 0.615661, 0.207912], + [-0.965926, -0.766044, -0.422618, 0.906308, 0.642788, 0.258819], + [-0.951057, -0.743145, -0.406737, 0.913545, 0.669131, 0.309017], + [-0.933580, -0.719340, -0.390731, 0.920505, 0.694658, 0.358368], + [-0.913545, -0.694658, -0.374607, 0.927184, 0.719340, 0.406737], + [-0.891007, -0.669131, -0.358368, 0.933580, 0.743145, 0.453990], + [-0.866025, -0.642788, -0.342020, 0.939693, 0.766044, 0.500000], + [-0.838671, -0.615661, -0.325568, 0.945519, 0.788011, 0.544639], + [-0.809017, -0.587785, -0.309017, 0.951057, 0.809017, 0.587785], + [-0.777146, -0.559193, -0.292372, 0.956305, 0.829038, 0.629320], + [-0.743145, -0.529919, -0.275637, 0.961262, 0.848048, 0.669131], + [-0.707107, -0.500000, -0.258819, 0.965926, 0.866025, 0.707107], + [-0.669131, -0.469472, -0.241922, 0.970296, 0.882948, 0.743145], + [-0.629320, -0.438371, -0.224951, 0.974370, 0.898794, 0.777146], + [-0.587785, -0.406737, -0.207912, 0.978148, 0.913545, 0.809017], + [-0.544639, -0.374607, -0.190809, 0.981627, 0.927184, 0.838671], + [-0.500000, -0.342020, -0.173648, 0.984808, 0.939693, 0.866025], + [-0.453990, -0.309017, -0.156434, 0.987688, 0.951057, 0.891007], + [-0.406737, -0.275637, -0.139173, 0.990268, 0.961262, 0.913545], + [-0.358368, -0.241922, -0.121869, 0.992546, 0.970296, 0.933580], + [-0.309017, -0.207912, -0.104528, 0.994522, 0.978148, 0.951057], + [-0.258819, -0.173648, -0.087156, 0.996195, 0.984808, 0.965926], + [-0.207912, -0.139173, -0.069756, 0.997564, 0.990268, 0.978148], + [-0.156434, -0.104528, -0.052336, 0.998630, 0.994522, 0.987688], + [-0.104528, -0.069756, -0.034899, 0.999391, 0.997564, 0.994522], + [-0.052336, -0.034899, -0.017452, 0.999848, 0.999391, 0.998630], + ], + [ + [-1.000000, -0.000000, 1.000000, -0.000000, 0.000000, + -1.000000, -0.000000, 0.000000, -0.000000], + [-0.999848, 0.017452, 0.999543, -0.030224, 0.000264, + -0.999086, 0.042733, -0.000590, 0.000004], + [-0.999391, 0.034899, 0.998173, -0.060411, 0.001055, + -0.996348, 0.085356, -0.002357, 0.000034], + [-0.998630, 0.052336, 0.995891, -0.090524, 0.002372, + -0.991791, 0.127757, -0.005297, 0.000113], + [-0.997564, 0.069756, 0.992701, -0.120527, 0.004214, + -0.985429, 0.169828, -0.009400, 0.000268], + [-0.996195, 0.087156, 0.988606, -0.150384, 0.006578, + -0.977277, 0.211460, -0.014654, 0.000523], + [-0.994522, 0.104528, 0.983611, -0.180057, 0.009462, + -0.967356, 0.252544, -0.021043, 0.000903], + [-0.992546, 0.121869, 0.977722, -0.209511, 0.012862, + -0.955693, 0.292976, -0.028547, 0.001431], + [-0.990268, 0.139173, 0.970946, -0.238709, 0.016774, + -0.942316, 0.332649, -0.037143, 0.002131], + [-0.987688, 0.156434, 0.963292, -0.267617, 0.021193, + -0.927262, 0.371463, -0.046806, 0.003026], + [-0.984808, 0.173648, 0.954769, -0.296198, 0.026114, + -0.910569, 0.409317, -0.057505, 0.004140], + [-0.981627, 0.190809, 0.945388, -0.324419, 0.031530, + -0.892279, 0.446114, -0.069209, 0.005492], + [-0.978148, 0.207912, 0.935159, -0.352244, 0.037436, + -0.872441, 0.481759, -0.081880, 0.007105], + [-0.974370, 0.224951, 0.924096, -0.379641, 0.043823, + -0.851105, 0.516162, -0.095481, 0.008999], + [-0.970296, 0.241922, 0.912211, -0.406574, 0.050685, + -0.828326, 0.549233, -0.109969, 0.011193], + [-0.965926, 0.258819, 0.899519, -0.433013, 0.058013, + -0.804164, 0.580889, -0.125300, 0.013707], + [-0.961262, 0.275637, 0.886036, -0.458924, 0.065797, + -0.778680, 0.611050, -0.141427, 0.016556], + [-0.956305, 0.292372, 0.871778, -0.484275, 0.074029, + -0.751940, 0.639639, -0.158301, 0.019758], + [-0.951057, 0.309017, 0.856763, -0.509037, 0.082698, + -0.724012, 0.666583, -0.175868, 0.023329], + [-0.945519, 0.325568, 0.841008, -0.533178, 0.091794, + -0.694969, 0.691816, -0.194075, 0.027281], + [-0.939693, 0.342020, 0.824533, -0.556670, 0.101306, + -0.664885, 0.715274, -0.212865, 0.031630], + [-0.933580, 0.358368, 0.807359, -0.579484, 0.111222, + -0.633837, 0.736898, -0.232180, 0.036385], + [-0.927184, 0.374607, 0.789505, -0.601592, 0.121529, + -0.601904, 0.756637, -0.251960, 0.041559], + [-0.920505, 0.390731, 0.770994, -0.622967, 0.132217, + -0.569169, 0.774442, -0.272143, 0.047160], + [-0.913545, 0.406737, 0.751848, -0.643582, 0.143271, + -0.535715, 0.790270, -0.292666, 0.053196], + [-0.906308, 0.422618, 0.732091, -0.663414, 0.154678, + -0.501627, 0.804083, -0.313464, 0.059674], + [-0.898794, 0.438371, 0.711746, -0.682437, 0.166423, + -0.466993, 0.815850, -0.334472, 0.066599], + [-0.891007, 0.453990, 0.690839, -0.700629, 0.178494, + -0.431899, 0.825544, -0.355623, 0.073974], + [-0.882948, 0.469472, 0.669395, -0.717968, 0.190875, + -0.396436, 0.833145, -0.376851, 0.081803], + [-0.874620, 0.484810, 0.647439, -0.734431, 0.203551, + -0.360692, 0.838638, -0.398086, 0.090085], + [-0.866025, 0.500000, 0.625000, -0.750000, 0.216506, + -0.324760, 0.842012, -0.419263, 0.098821], + [-0.857167, 0.515038, 0.602104, -0.764655, 0.229726, + -0.288728, 0.843265, -0.440311, 0.108009], + [-0.848048, 0.529919, 0.578778, -0.778378, 0.243192, + -0.252688, 0.842399, -0.461164, 0.117644], + [-0.838671, 0.544639, 0.555052, -0.791154, 0.256891, + -0.216730, 0.839422, -0.481753, 0.127722], + [-0.829038, 0.559193, 0.530955, -0.802965, 0.270803, + -0.180944, 0.834347, -0.502011, 0.138237], + [-0.819152, 0.573576, 0.506515, -0.813798, 0.284914, + -0.145420, 0.827194, -0.521871, 0.149181], + [-0.809017, 0.587785, 0.481763, -0.823639, 0.299204, + -0.110246, 0.817987, -0.541266, 0.160545], + [-0.798636, 0.601815, 0.456728, -0.832477, 0.313658, + -0.075508, 0.806757, -0.560132, 0.172317], + [-0.788011, 0.615661, 0.431441, -0.840301, 0.328257, + -0.041294, 0.793541, -0.578405, 0.184487], + [-0.777146, 0.629320, 0.405934, -0.847101, 0.342984, + -0.007686, 0.778379, -0.596021, 0.197040], + [-0.766044, 0.642788, 0.380236, -0.852869, 0.357821, + 0.025233, 0.761319, -0.612921, 0.209963], + [-0.754710, 0.656059, 0.354380, -0.857597, 0.372749, + 0.057383, 0.742412, -0.629044, 0.223238], + [-0.743145, 0.669131, 0.328396, -0.861281, 0.387751, + 0.088686, 0.721714, -0.644334, 0.236850], + [-0.731354, 0.681998, 0.302317, -0.863916, 0.402807, + 0.119068, 0.699288, -0.658734, 0.250778], + [-0.719340, 0.694658, 0.276175, -0.865498, 0.417901, + 0.148454, 0.675199, -0.672190, 0.265005], + [-0.707107, 0.707107, 0.250000, -0.866025, 0.433013, + 0.176777, 0.649519, -0.684653, 0.279508], + [-0.694658, 0.719340, 0.223825, -0.865498, 0.448125, + 0.203969, 0.622322, -0.696073, 0.294267], + [-0.681998, 0.731354, 0.197683, -0.863916, 0.463218, + 0.229967, 0.593688, -0.706405, 0.309259], + [-0.669131, 0.743145, 0.171604, -0.861281, 0.478275, + 0.254712, 0.563700, -0.715605, 0.324459], + [-0.656059, 0.754710, 0.145620, -0.857597, 0.493276, + 0.278147, 0.532443, -0.723633, 0.339844], + [-0.642788, 0.766044, 0.119764, -0.852869, 0.508205, + 0.300221, 0.500009, -0.730451, 0.355387], + [-0.629320, 0.777146, 0.094066, -0.847101, 0.523041, + 0.320884, 0.466490, -0.736025, 0.371063], + [-0.615661, 0.788011, 0.068559, -0.840301, 0.537768, + 0.340093, 0.431982, -0.740324, 0.386845], + [-0.601815, 0.798636, 0.043272, -0.832477, 0.552367, + 0.357807, 0.396584, -0.743320, 0.402704], + [-0.587785, 0.809017, 0.018237, -0.823639, 0.566821, + 0.373991, 0.360397, -0.744989, 0.418613], + [-0.573576, 0.819152, -0.006515, -0.813798, 0.581112, + 0.388612, 0.323524, -0.745308, 0.434544], + [-0.559193, 0.829038, -0.030955, -0.802965, 0.595222, + 0.401645, 0.286069, -0.744262, 0.450467], + [-0.544639, 0.838671, -0.055052, -0.791154, 0.609135, + 0.413066, 0.248140, -0.741835, 0.466352], + [-0.529919, 0.848048, -0.078778, -0.778378, 0.622833, + 0.422856, 0.209843, -0.738017, 0.482171], + [-0.515038, 0.857167, -0.102104, -0.764655, 0.636300, + 0.431004, 0.171288, -0.732801, 0.497894], + [-0.500000, 0.866025, -0.125000, -0.750000, 0.649519, + 0.437500, 0.132583, -0.726184, 0.513490], + [-0.484810, 0.874620, -0.147439, -0.734431, 0.662474, + 0.442340, 0.093837, -0.718167, 0.528929], + [-0.469472, 0.882948, -0.169395, -0.717968, 0.675150, + 0.445524, 0.055160, -0.708753, 0.544183], + [-0.453990, 0.891007, -0.190839, -0.700629, 0.687531, + 0.447059, 0.016662, -0.697950, 0.559220], + [-0.438371, 0.898794, -0.211746, -0.682437, 0.699602, + 0.446953, -0.021550, -0.685769, 0.574011], + [-0.422618, 0.906308, -0.232091, -0.663414, 0.711348, + 0.445222, -0.059368, -0.672226, 0.588528], + [-0.406737, 0.913545, -0.251848, -0.643582, 0.722755, + 0.441884, -0.096684, -0.657339, 0.602741], + [-0.390731, 0.920505, -0.270994, -0.622967, 0.733809, + 0.436964, -0.133395, -0.641130, 0.616621], + [-0.374607, 0.927184, -0.289505, -0.601592, 0.744496, + 0.430488, -0.169397, -0.623624, 0.630141], + [-0.358368, 0.933580, -0.307359, -0.579484, 0.754804, + 0.422491, -0.204589, -0.604851, 0.643273], + [-0.342020, 0.939693, -0.324533, -0.556670, 0.764720, + 0.413008, -0.238872, -0.584843, 0.655990], + [-0.325568, 0.945519, -0.341008, -0.533178, 0.774231, + 0.402081, -0.272150, -0.563635, 0.668267], + [-0.309017, 0.951057, -0.356763, -0.509037, 0.783327, + 0.389754, -0.304329, -0.541266, 0.680078], + [-0.292372, 0.956305, -0.371778, -0.484275, 0.791997, + 0.376077, -0.335319, -0.517778, 0.691399], + [-0.275637, 0.961262, -0.386036, -0.458924, 0.800228, + 0.361102, -0.365034, -0.493216, 0.702207], + [-0.258819, 0.965926, -0.399519, -0.433013, 0.808013, + 0.344885, -0.393389, -0.467627, 0.712478], + [-0.241922, 0.970296, -0.412211, -0.406574, 0.815340, + 0.327486, -0.420306, -0.441061, 0.722191], + [-0.224951, 0.974370, -0.424096, -0.379641, 0.822202, + 0.308969, -0.445709, -0.413572, 0.731327], + [-0.207912, 0.978148, -0.435159, -0.352244, 0.828589, + 0.289399, -0.469527, -0.385215, 0.739866], + [-0.190809, 0.981627, -0.445388, -0.324419, 0.834495, + 0.268846, -0.491693, -0.356047, 0.747790], + [-0.173648, 0.984808, -0.454769, -0.296198, 0.839912, + 0.247382, -0.512145, -0.326129, 0.755082], + [-0.156434, 0.987688, -0.463292, -0.267617, 0.844832, + 0.225081, -0.530827, -0.295521, 0.761728], + [-0.139173, 0.990268, -0.470946, -0.238709, 0.849251, + 0.202020, -0.547684, -0.264287, 0.767712], + [-0.121869, 0.992546, -0.477722, -0.209511, 0.853163, + 0.178279, -0.562672, -0.232494, 0.773023], + [-0.104528, 0.994522, -0.483611, -0.180057, 0.856563, + 0.153937, -0.575747, -0.200207, 0.777648], + [-0.087156, 0.996195, -0.488606, -0.150384, 0.859447, + 0.129078, -0.586872, -0.167494, 0.781579], + [-0.069756, 0.997564, -0.492701, -0.120527, 0.861811, + 0.103786, -0.596018, -0.134426, 0.784806], + [-0.052336, 0.998630, -0.495891, -0.090524, 0.863653, + 0.078146, -0.603158, -0.101071, 0.787324], + [-0.034899, 0.999391, -0.498173, -0.060411, 0.864971, + 0.052243, -0.608272, -0.067500, 0.789126], + [-0.017452, 0.999848, -0.499543, -0.030224, 0.865762, + 0.026165, -0.611347, -0.033786, 0.790208], + [0.000000, 1.000000, -0.500000, 0.000000, 0.866025, + -0.000000, -0.612372, 0.000000, 0.790569], + [0.017452, 0.999848, -0.499543, 0.030224, 0.865762, + -0.026165, -0.611347, 0.033786, 0.790208], + [0.034899, 0.999391, -0.498173, 0.060411, 0.864971, + -0.052243, -0.608272, 0.067500, 0.789126], + [0.052336, 0.998630, -0.495891, 0.090524, 0.863653, + -0.078146, -0.603158, 0.101071, 0.787324], + [0.069756, 0.997564, -0.492701, 0.120527, 0.861811, + -0.103786, -0.596018, 0.134426, 0.784806], + [0.087156, 0.996195, -0.488606, 0.150384, 0.859447, + -0.129078, -0.586872, 0.167494, 0.781579], + [0.104528, 0.994522, -0.483611, 0.180057, 0.856563, + -0.153937, -0.575747, 0.200207, 0.777648], + [0.121869, 0.992546, -0.477722, 0.209511, 0.853163, + -0.178279, -0.562672, 0.232494, 0.773023], + [0.139173, 0.990268, -0.470946, 0.238709, 0.849251, + -0.202020, -0.547684, 0.264287, 0.767712], + [0.156434, 0.987688, -0.463292, 0.267617, 0.844832, + -0.225081, -0.530827, 0.295521, 0.761728], + [0.173648, 0.984808, -0.454769, 0.296198, 0.839912, + -0.247382, -0.512145, 0.326129, 0.755082], + [0.190809, 0.981627, -0.445388, 0.324419, 0.834495, + -0.268846, -0.491693, 0.356047, 0.747790], + [0.207912, 0.978148, -0.435159, 0.352244, 0.828589, + -0.289399, -0.469527, 0.385215, 0.739866], + [0.224951, 0.974370, -0.424096, 0.379641, 0.822202, + -0.308969, -0.445709, 0.413572, 0.731327], + [0.241922, 0.970296, -0.412211, 0.406574, 0.815340, + -0.327486, -0.420306, 0.441061, 0.722191], + [0.258819, 0.965926, -0.399519, 0.433013, 0.808013, + -0.344885, -0.393389, 0.467627, 0.712478], + [0.275637, 0.961262, -0.386036, 0.458924, 0.800228, + -0.361102, -0.365034, 0.493216, 0.702207], + [0.292372, 0.956305, -0.371778, 0.484275, 0.791997, + -0.376077, -0.335319, 0.517778, 0.691399], + [0.309017, 0.951057, -0.356763, 0.509037, 0.783327, + -0.389754, -0.304329, 0.541266, 0.680078], + [0.325568, 0.945519, -0.341008, 0.533178, 0.774231, + -0.402081, -0.272150, 0.563635, 0.668267], + [0.342020, 0.939693, -0.324533, 0.556670, 0.764720, + -0.413008, -0.238872, 0.584843, 0.655990], + [0.358368, 0.933580, -0.307359, 0.579484, 0.754804, + -0.422491, -0.204589, 0.604851, 0.643273], + [0.374607, 0.927184, -0.289505, 0.601592, 0.744496, + -0.430488, -0.169397, 0.623624, 0.630141], + [0.390731, 0.920505, -0.270994, 0.622967, 0.733809, + -0.436964, -0.133395, 0.641130, 0.616621], + [0.406737, 0.913545, -0.251848, 0.643582, 0.722755, + -0.441884, -0.096684, 0.657339, 0.602741], + [0.422618, 0.906308, -0.232091, 0.663414, 0.711348, + -0.445222, -0.059368, 0.672226, 0.588528], + [0.438371, 0.898794, -0.211746, 0.682437, 0.699602, + -0.446953, -0.021550, 0.685769, 0.574011], + [0.453990, 0.891007, -0.190839, 0.700629, 0.687531, + -0.447059, 0.016662, 0.697950, 0.559220], + [0.469472, 0.882948, -0.169395, 0.717968, 0.675150, + -0.445524, 0.055160, 0.708753, 0.544183], + [0.484810, 0.874620, -0.147439, 0.734431, 0.662474, + -0.442340, 0.093837, 0.718167, 0.528929], + [0.500000, 0.866025, -0.125000, 0.750000, 0.649519, + -0.437500, 0.132583, 0.726184, 0.513490], + [0.515038, 0.857167, -0.102104, 0.764655, 0.636300, + -0.431004, 0.171288, 0.732801, 0.497894], + [0.529919, 0.848048, -0.078778, 0.778378, 0.622833, + -0.422856, 0.209843, 0.738017, 0.482171], + [0.544639, 0.838671, -0.055052, 0.791154, 0.609135, + -0.413066, 0.248140, 0.741835, 0.466352], + [0.559193, 0.829038, -0.030955, 0.802965, 0.595222, + -0.401645, 0.286069, 0.744262, 0.450467], + [0.573576, 0.819152, -0.006515, 0.813798, 0.581112, + -0.388612, 0.323524, 0.745308, 0.434544], + [0.587785, 0.809017, 0.018237, 0.823639, 0.566821, + -0.373991, 0.360397, 0.744989, 0.418613], + [0.601815, 0.798636, 0.043272, 0.832477, 0.552367, + -0.357807, 0.396584, 0.743320, 0.402704], + [0.615661, 0.788011, 0.068559, 0.840301, 0.537768, + -0.340093, 0.431982, 0.740324, 0.386845], + [0.629320, 0.777146, 0.094066, 0.847101, 0.523041, + -0.320884, 0.466490, 0.736025, 0.371063], + [0.642788, 0.766044, 0.119764, 0.852869, 0.508205, + -0.300221, 0.500009, 0.730451, 0.355387], + [0.656059, 0.754710, 0.145620, 0.857597, 0.493276, + -0.278147, 0.532443, 0.723633, 0.339844], + [0.669131, 0.743145, 0.171604, 0.861281, 0.478275, + -0.254712, 0.563700, 0.715605, 0.324459], + [0.681998, 0.731354, 0.197683, 0.863916, 0.463218, + -0.229967, 0.593688, 0.706405, 0.309259], + [0.694658, 0.719340, 0.223825, 0.865498, 0.448125, + -0.203969, 0.622322, 0.696073, 0.294267], + [0.707107, 0.707107, 0.250000, 0.866025, 0.433013, + -0.176777, 0.649519, 0.684653, 0.279508], + [0.719340, 0.694658, 0.276175, 0.865498, 0.417901, + -0.148454, 0.675199, 0.672190, 0.265005], + [0.731354, 0.681998, 0.302317, 0.863916, 0.402807, + -0.119068, 0.699288, 0.658734, 0.250778], + [0.743145, 0.669131, 0.328396, 0.861281, 0.387751, + -0.088686, 0.721714, 0.644334, 0.236850], + [0.754710, 0.656059, 0.354380, 0.857597, 0.372749, + -0.057383, 0.742412, 0.629044, 0.223238], + [0.766044, 0.642788, 0.380236, 0.852869, 0.357821, + -0.025233, 0.761319, 0.612921, 0.209963], + [0.777146, 0.629320, 0.405934, 0.847101, 0.342984, + 0.007686, 0.778379, 0.596021, 0.197040], + [0.788011, 0.615661, 0.431441, 0.840301, 0.328257, + 0.041294, 0.793541, 0.578405, 0.184487], + [0.798636, 0.601815, 0.456728, 0.832477, 0.313658, + 0.075508, 0.806757, 0.560132, 0.172317], + [0.809017, 0.587785, 0.481763, 0.823639, 0.299204, + 0.110246, 0.817987, 0.541266, 0.160545], + [0.819152, 0.573576, 0.506515, 0.813798, 0.284914, + 0.145420, 0.827194, 0.521871, 0.149181], + [0.829038, 0.559193, 0.530955, 0.802965, 0.270803, + 0.180944, 0.834347, 0.502011, 0.138237], + [0.838671, 0.544639, 0.555052, 0.791154, 0.256891, + 0.216730, 0.839422, 0.481753, 0.127722], + [0.848048, 0.529919, 0.578778, 0.778378, 0.243192, + 0.252688, 0.842399, 0.461164, 0.117644], + [0.857167, 0.515038, 0.602104, 0.764655, 0.229726, + 0.288728, 0.843265, 0.440311, 0.108009], + [0.866025, 0.500000, 0.625000, 0.750000, 0.216506, + 0.324760, 0.842012, 0.419263, 0.098821], + [0.874620, 0.484810, 0.647439, 0.734431, 0.203551, + 0.360692, 0.838638, 0.398086, 0.090085], + [0.882948, 0.469472, 0.669395, 0.717968, 0.190875, + 0.396436, 0.833145, 0.376851, 0.081803], + [0.891007, 0.453990, 0.690839, 0.700629, 0.178494, + 0.431899, 0.825544, 0.355623, 0.073974], + [0.898794, 0.438371, 0.711746, 0.682437, 0.166423, + 0.466993, 0.815850, 0.334472, 0.066599], + [0.906308, 0.422618, 0.732091, 0.663414, 0.154678, + 0.501627, 0.804083, 0.313464, 0.059674], + [0.913545, 0.406737, 0.751848, 0.643582, 0.143271, + 0.535715, 0.790270, 0.292666, 0.053196], + [0.920505, 0.390731, 0.770994, 0.622967, 0.132217, + 0.569169, 0.774442, 0.272143, 0.047160], + [0.927184, 0.374607, 0.789505, 0.601592, 0.121529, + 0.601904, 0.756637, 0.251960, 0.041559], + [0.933580, 0.358368, 0.807359, 0.579484, 0.111222, + 0.633837, 0.736898, 0.232180, 0.036385], + [0.939693, 0.342020, 0.824533, 0.556670, 0.101306, + 0.664885, 0.715274, 0.212865, 0.031630], + [0.945519, 0.325568, 0.841008, 0.533178, 0.091794, + 0.694969, 0.691816, 0.194075, 0.027281], + [0.951057, 0.309017, 0.856763, 0.509037, 0.082698, + 0.724012, 0.666583, 0.175868, 0.023329], + [0.956305, 0.292372, 0.871778, 0.484275, 0.074029, + 0.751940, 0.639639, 0.158301, 0.019758], + [0.961262, 0.275637, 0.886036, 0.458924, 0.065797, + 0.778680, 0.611050, 0.141427, 0.016556], + [0.965926, 0.258819, 0.899519, 0.433013, 0.058013, + 0.804164, 0.580889, 0.125300, 0.013707], + [0.970296, 0.241922, 0.912211, 0.406574, 0.050685, + 0.828326, 0.549233, 0.109969, 0.011193], + [0.974370, 0.224951, 0.924096, 0.379641, 0.043823, + 0.851105, 0.516162, 0.095481, 0.008999], + [0.978148, 0.207912, 0.935159, 0.352244, 0.037436, + 0.872441, 0.481759, 0.081880, 0.007105], + [0.981627, 0.190809, 0.945388, 0.324419, 0.031530, + 0.892279, 0.446114, 0.069209, 0.005492], + [0.984808, 0.173648, 0.954769, 0.296198, 0.026114, + 0.910569, 0.409317, 0.057505, 0.004140], + [0.987688, 0.156434, 0.963292, 0.267617, 0.021193, + 0.927262, 0.371463, 0.046806, 0.003026], + [0.990268, 0.139173, 0.970946, 0.238709, 0.016774, + 0.942316, 0.332649, 0.037143, 0.002131], + [0.992546, 0.121869, 0.977722, 0.209511, 0.012862, + 0.955693, 0.292976, 0.028547, 0.001431], + [0.994522, 0.104528, 0.983611, 0.180057, 0.009462, + 0.967356, 0.252544, 0.021043, 0.000903], + [0.996195, 0.087156, 0.988606, 0.150384, 0.006578, + 0.977277, 0.211460, 0.014654, 0.000523], + [0.997564, 0.069756, 0.992701, 0.120527, 0.004214, + 0.985429, 0.169828, 0.009400, 0.000268], + [0.998630, 0.052336, 0.995891, 0.090524, 0.002372, + 0.991791, 0.127757, 0.005297, 0.000113], + [0.999391, 0.034899, 0.998173, 0.060411, 0.001055, + 0.996348, 0.085356, 0.002357, 0.000034], + [0.999848, 0.017452, 0.999543, 0.030224, 0.000264, + 0.999086, 0.042733, 0.000590, 0.000004], + [1.000000, -0.000000, 1.000000, -0.000000, 0.000000, + 1.000000, -0.000000, 0.000000, -0.000000], + ], +]; +/** @type {Number} */ +const SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION = SPHERICAL_HARMONICS[0].length; +/** @type {Number} */ +const SPHERICAL_HARMONICS_ELEVATION_RESOLUTION = SPHERICAL_HARMONICS[1].length; +/** + * The maximum allowed ambisonic order. + * @type {Number} + */ +const SPHERICAL_HARMONICS_MAX_ORDER = SPHERICAL_HARMONICS[0][0].length / 2; +/** + * Pre-computed per-band weighting coefficients for producing energy-preserving + * Max-Re sources. + */ +const MAX_RE_WEIGHTS = [ + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.000000, 1.000000, 1.000000, 1.000000], + [1.003236, 1.002156, 0.999152, 0.990038], + [1.032370, 1.021194, 0.990433, 0.898572], + [1.062694, 1.040231, 0.979161, 0.799806], + [1.093999, 1.058954, 0.964976, 0.693603], + [1.126003, 1.077006, 0.947526, 0.579890], + [1.158345, 1.093982, 0.926474, 0.458690], + [1.190590, 1.109437, 0.901512, 0.330158], + [1.222228, 1.122890, 0.872370, 0.194621], + [1.252684, 1.133837, 0.838839, 0.052614], + [1.281987, 1.142358, 0.801199, 0.000000], + [1.312073, 1.150207, 0.760839, 0.000000], + [1.343011, 1.157424, 0.717799, 0.000000], + [1.374649, 1.163859, 0.671999, 0.000000], + [1.406809, 1.169354, 0.623371, 0.000000], + [1.439286, 1.173739, 0.571868, 0.000000], + [1.471846, 1.176837, 0.517465, 0.000000], + [1.504226, 1.178465, 0.460174, 0.000000], + [1.536133, 1.178438, 0.400043, 0.000000], + [1.567253, 1.176573, 0.337165, 0.000000], + [1.597247, 1.172695, 0.271688, 0.000000], + [1.625766, 1.166645, 0.203815, 0.000000], + [1.652455, 1.158285, 0.133806, 0.000000], + [1.676966, 1.147506, 0.061983, 0.000000], + [1.699006, 1.134261, 0.000000, 0.000000], + [1.720224, 1.119789, 0.000000, 0.000000], + [1.741631, 1.104810, 0.000000, 0.000000], + [1.763183, 1.089330, 0.000000, 0.000000], + [1.784837, 1.073356, 0.000000, 0.000000], + [1.806548, 1.056898, 0.000000, 0.000000], + [1.828269, 1.039968, 0.000000, 0.000000], + [1.849952, 1.022580, 0.000000, 0.000000], + [1.871552, 1.004752, 0.000000, 0.000000], + [1.893018, 0.986504, 0.000000, 0.000000], + [1.914305, 0.967857, 0.000000, 0.000000], + [1.935366, 0.948837, 0.000000, 0.000000], + [1.956154, 0.929471, 0.000000, 0.000000], + [1.976625, 0.909790, 0.000000, 0.000000], + [1.996736, 0.889823, 0.000000, 0.000000], + [2.016448, 0.869607, 0.000000, 0.000000], + [2.035721, 0.849175, 0.000000, 0.000000], + [2.054522, 0.828565, 0.000000, 0.000000], + [2.072818, 0.807816, 0.000000, 0.000000], + [2.090581, 0.786964, 0.000000, 0.000000], + [2.107785, 0.766051, 0.000000, 0.000000], + [2.124411, 0.745115, 0.000000, 0.000000], + [2.140439, 0.724196, 0.000000, 0.000000], + [2.155856, 0.703332, 0.000000, 0.000000], + [2.170653, 0.682561, 0.000000, 0.000000], + [2.184823, 0.661921, 0.000000, 0.000000], + [2.198364, 0.641445, 0.000000, 0.000000], + [2.211275, 0.621169, 0.000000, 0.000000], + [2.223562, 0.601125, 0.000000, 0.000000], + [2.235230, 0.581341, 0.000000, 0.000000], + [2.246289, 0.561847, 0.000000, 0.000000], + [2.256751, 0.542667, 0.000000, 0.000000], + [2.266631, 0.523826, 0.000000, 0.000000], + [2.275943, 0.505344, 0.000000, 0.000000], + [2.284707, 0.487239, 0.000000, 0.000000], + [2.292939, 0.469528, 0.000000, 0.000000], + [2.300661, 0.452225, 0.000000, 0.000000], + [2.307892, 0.435342, 0.000000, 0.000000], + [2.314654, 0.418888, 0.000000, 0.000000], + [2.320969, 0.402870, 0.000000, 0.000000], + [2.326858, 0.387294, 0.000000, 0.000000], + [2.332343, 0.372164, 0.000000, 0.000000], + [2.337445, 0.357481, 0.000000, 0.000000], + [2.342186, 0.343246, 0.000000, 0.000000], + [2.346585, 0.329458, 0.000000, 0.000000], + [2.350664, 0.316113, 0.000000, 0.000000], + [2.354442, 0.303208, 0.000000, 0.000000], + [2.357937, 0.290738, 0.000000, 0.000000], + [2.361168, 0.278698, 0.000000, 0.000000], + [2.364152, 0.267080, 0.000000, 0.000000], + [2.366906, 0.255878, 0.000000, 0.000000], + [2.369446, 0.245082, 0.000000, 0.000000], + [2.371786, 0.234685, 0.000000, 0.000000], + [2.373940, 0.224677, 0.000000, 0.000000], + [2.375923, 0.215048, 0.000000, 0.000000], + [2.377745, 0.205790, 0.000000, 0.000000], + [2.379421, 0.196891, 0.000000, 0.000000], + [2.380959, 0.188342, 0.000000, 0.000000], + [2.382372, 0.180132, 0.000000, 0.000000], + [2.383667, 0.172251, 0.000000, 0.000000], + [2.384856, 0.164689, 0.000000, 0.000000], + [2.385945, 0.157435, 0.000000, 0.000000], + [2.386943, 0.150479, 0.000000, 0.000000], + [2.387857, 0.143811, 0.000000, 0.000000], + [2.388694, 0.137421, 0.000000, 0.000000], + [2.389460, 0.131299, 0.000000, 0.000000], + [2.390160, 0.125435, 0.000000, 0.000000], + [2.390801, 0.119820, 0.000000, 0.000000], + [2.391386, 0.114445, 0.000000, 0.000000], + [2.391921, 0.109300, 0.000000, 0.000000], + [2.392410, 0.104376, 0.000000, 0.000000], + [2.392857, 0.099666, 0.000000, 0.000000], + [2.393265, 0.095160, 0.000000, 0.000000], + [2.393637, 0.090851, 0.000000, 0.000000], + [2.393977, 0.086731, 0.000000, 0.000000], + [2.394288, 0.082791, 0.000000, 0.000000], + [2.394571, 0.079025, 0.000000, 0.000000], + [2.394829, 0.075426, 0.000000, 0.000000], + [2.395064, 0.071986, 0.000000, 0.000000], + [2.395279, 0.068699, 0.000000, 0.000000], + [2.395475, 0.065558, 0.000000, 0.000000], + [2.395653, 0.062558, 0.000000, 0.000000], + [2.395816, 0.059693, 0.000000, 0.000000], + [2.395964, 0.056955, 0.000000, 0.000000], + [2.396099, 0.054341, 0.000000, 0.000000], + [2.396222, 0.051845, 0.000000, 0.000000], + [2.396334, 0.049462, 0.000000, 0.000000], + [2.396436, 0.047186, 0.000000, 0.000000], + [2.396529, 0.045013, 0.000000, 0.000000], + [2.396613, 0.042939, 0.000000, 0.000000], + [2.396691, 0.040959, 0.000000, 0.000000], + [2.396761, 0.039069, 0.000000, 0.000000], + [2.396825, 0.037266, 0.000000, 0.000000], + [2.396883, 0.035544, 0.000000, 0.000000], + [2.396936, 0.033901, 0.000000, 0.000000], + [2.396984, 0.032334, 0.000000, 0.000000], + [2.397028, 0.030838, 0.000000, 0.000000], + [2.397068, 0.029410, 0.000000, 0.000000], + [2.397104, 0.028048, 0.000000, 0.000000], + [2.397137, 0.026749, 0.000000, 0.000000], + [2.397167, 0.025509, 0.000000, 0.000000], + [2.397194, 0.024326, 0.000000, 0.000000], + [2.397219, 0.023198, 0.000000, 0.000000], + [2.397242, 0.022122, 0.000000, 0.000000], + [2.397262, 0.021095, 0.000000, 0.000000], + [2.397281, 0.020116, 0.000000, 0.000000], + [2.397298, 0.019181, 0.000000, 0.000000], + [2.397314, 0.018290, 0.000000, 0.000000], + [2.397328, 0.017441, 0.000000, 0.000000], + [2.397341, 0.016630, 0.000000, 0.000000], + [2.397352, 0.015857, 0.000000, 0.000000], + [2.397363, 0.015119, 0.000000, 0.000000], + [2.397372, 0.014416, 0.000000, 0.000000], + [2.397381, 0.013745, 0.000000, 0.000000], + [2.397389, 0.013106, 0.000000, 0.000000], + [2.397396, 0.012496, 0.000000, 0.000000], + [2.397403, 0.011914, 0.000000, 0.000000], + [2.397409, 0.011360, 0.000000, 0.000000], + [2.397414, 0.010831, 0.000000, 0.000000], + [2.397419, 0.010326, 0.000000, 0.000000], + [2.397424, 0.009845, 0.000000, 0.000000], + [2.397428, 0.009387, 0.000000, 0.000000], + [2.397432, 0.008949, 0.000000, 0.000000], + [2.397435, 0.008532, 0.000000, 0.000000], + [2.397438, 0.008135, 0.000000, 0.000000], + [2.397441, 0.007755, 0.000000, 0.000000], + [2.397443, 0.007394, 0.000000, 0.000000], + [2.397446, 0.007049, 0.000000, 0.000000], + [2.397448, 0.006721, 0.000000, 0.000000], + [2.397450, 0.006407, 0.000000, 0.000000], + [2.397451, 0.006108, 0.000000, 0.000000], + [2.397453, 0.005824, 0.000000, 0.000000], + [2.397454, 0.005552, 0.000000, 0.000000], + [2.397456, 0.005293, 0.000000, 0.000000], + [2.397457, 0.005046, 0.000000, 0.000000], + [2.397458, 0.004811, 0.000000, 0.000000], + [2.397459, 0.004586, 0.000000, 0.000000], + [2.397460, 0.004372, 0.000000, 0.000000], + [2.397461, 0.004168, 0.000000, 0.000000], + [2.397461, 0.003974, 0.000000, 0.000000], + [2.397462, 0.003788, 0.000000, 0.000000], + [2.397463, 0.003611, 0.000000, 0.000000], + [2.397463, 0.003443, 0.000000, 0.000000], + [2.397464, 0.003282, 0.000000, 0.000000], + [2.397464, 0.003129, 0.000000, 0.000000], + [2.397465, 0.002983, 0.000000, 0.000000], + [2.397465, 0.002844, 0.000000, 0.000000], + [2.397465, 0.002711, 0.000000, 0.000000], + [2.397466, 0.002584, 0.000000, 0.000000], + [2.397466, 0.002464, 0.000000, 0.000000], + [2.397466, 0.002349, 0.000000, 0.000000], + [2.397466, 0.002239, 0.000000, 0.000000], + [2.397467, 0.002135, 0.000000, 0.000000], + [2.397467, 0.002035, 0.000000, 0.000000], + [2.397467, 0.001940, 0.000000, 0.000000], + [2.397467, 0.001849, 0.000000, 0.000000], + [2.397467, 0.001763, 0.000000, 0.000000], + [2.397467, 0.001681, 0.000000, 0.000000], + [2.397468, 0.001602, 0.000000, 0.000000], + [2.397468, 0.001527, 0.000000, 0.000000], + [2.397468, 0.001456, 0.000000, 0.000000], + [2.397468, 0.001388, 0.000000, 0.000000], + [2.397468, 0.001323, 0.000000, 0.000000], + [2.397468, 0.001261, 0.000000, 0.000000], + [2.397468, 0.001202, 0.000000, 0.000000], + [2.397468, 0.001146, 0.000000, 0.000000], + [2.397468, 0.001093, 0.000000, 0.000000], + [2.397468, 0.001042, 0.000000, 0.000000], + [2.397468, 0.000993, 0.000000, 0.000000], + [2.397468, 0.000947, 0.000000, 0.000000], + [2.397468, 0.000902, 0.000000, 0.000000], + [2.397468, 0.000860, 0.000000, 0.000000], + [2.397468, 0.000820, 0.000000, 0.000000], + [2.397469, 0.000782, 0.000000, 0.000000], + [2.397469, 0.000745, 0.000000, 0.000000], + [2.397469, 0.000710, 0.000000, 0.000000], + [2.397469, 0.000677, 0.000000, 0.000000], + [2.397469, 0.000646, 0.000000, 0.000000], + [2.397469, 0.000616, 0.000000, 0.000000], + [2.397469, 0.000587, 0.000000, 0.000000], + [2.397469, 0.000559, 0.000000, 0.000000], + [2.397469, 0.000533, 0.000000, 0.000000], + [2.397469, 0.000508, 0.000000, 0.000000], + [2.397469, 0.000485, 0.000000, 0.000000], + [2.397469, 0.000462, 0.000000, 0.000000], + [2.397469, 0.000440, 0.000000, 0.000000], + [2.397469, 0.000420, 0.000000, 0.000000], + [2.397469, 0.000400, 0.000000, 0.000000], + [2.397469, 0.000381, 0.000000, 0.000000], + [2.397469, 0.000364, 0.000000, 0.000000], + [2.397469, 0.000347, 0.000000, 0.000000], + [2.397469, 0.000330, 0.000000, 0.000000], + [2.397469, 0.000315, 0.000000, 0.000000], + [2.397469, 0.000300, 0.000000, 0.000000], + [2.397469, 0.000286, 0.000000, 0.000000], + [2.397469, 0.000273, 0.000000, 0.000000], + [2.397469, 0.000260, 0.000000, 0.000000], + [2.397469, 0.000248, 0.000000, 0.000000], + [2.397469, 0.000236, 0.000000, 0.000000], + [2.397469, 0.000225, 0.000000, 0.000000], + [2.397469, 0.000215, 0.000000, 0.000000], + [2.397469, 0.000205, 0.000000, 0.000000], + [2.397469, 0.000195, 0.000000, 0.000000], + [2.397469, 0.000186, 0.000000, 0.000000], + [2.397469, 0.000177, 0.000000, 0.000000], + [2.397469, 0.000169, 0.000000, 0.000000], + [2.397469, 0.000161, 0.000000, 0.000000], + [2.397469, 0.000154, 0.000000, 0.000000], + [2.397469, 0.000147, 0.000000, 0.000000], + [2.397469, 0.000140, 0.000000, 0.000000], + [2.397469, 0.000133, 0.000000, 0.000000], + [2.397469, 0.000127, 0.000000, 0.000000], + [2.397469, 0.000121, 0.000000, 0.000000], + [2.397469, 0.000115, 0.000000, 0.000000], + [2.397469, 0.000110, 0.000000, 0.000000], + [2.397469, 0.000105, 0.000000, 0.000000], + [2.397469, 0.000100, 0.000000, 0.000000], + [2.397469, 0.000095, 0.000000, 0.000000], + [2.397469, 0.000091, 0.000000, 0.000000], + [2.397469, 0.000087, 0.000000, 0.000000], + [2.397469, 0.000083, 0.000000, 0.000000], + [2.397469, 0.000079, 0.000000, 0.000000], + [2.397469, 0.000075, 0.000000, 0.000000], + [2.397469, 0.000071, 0.000000, 0.000000], + [2.397469, 0.000068, 0.000000, 0.000000], + [2.397469, 0.000065, 0.000000, 0.000000], + [2.397469, 0.000062, 0.000000, 0.000000], + [2.397469, 0.000059, 0.000000, 0.000000], + [2.397469, 0.000056, 0.000000, 0.000000], + [2.397469, 0.000054, 0.000000, 0.000000], + [2.397469, 0.000051, 0.000000, 0.000000], + [2.397469, 0.000049, 0.000000, 0.000000], + [2.397469, 0.000046, 0.000000, 0.000000], + [2.397469, 0.000044, 0.000000, 0.000000], + [2.397469, 0.000042, 0.000000, 0.000000], + [2.397469, 0.000040, 0.000000, 0.000000], + [2.397469, 0.000038, 0.000000, 0.000000], + [2.397469, 0.000037, 0.000000, 0.000000], + [2.397469, 0.000035, 0.000000, 0.000000], + [2.397469, 0.000033, 0.000000, 0.000000], + [2.397469, 0.000032, 0.000000, 0.000000], + [2.397469, 0.000030, 0.000000, 0.000000], + [2.397469, 0.000029, 0.000000, 0.000000], + [2.397469, 0.000027, 0.000000, 0.000000], + [2.397469, 0.000026, 0.000000, 0.000000], + [2.397469, 0.000025, 0.000000, 0.000000], + [2.397469, 0.000024, 0.000000, 0.000000], + [2.397469, 0.000023, 0.000000, 0.000000], + [2.397469, 0.000022, 0.000000, 0.000000], + [2.397469, 0.000021, 0.000000, 0.000000], + [2.397469, 0.000020, 0.000000, 0.000000], + [2.397469, 0.000019, 0.000000, 0.000000], + [2.397469, 0.000018, 0.000000, 0.000000], + [2.397469, 0.000017, 0.000000, 0.000000], + [2.397469, 0.000016, 0.000000, 0.000000], + [2.397469, 0.000015, 0.000000, 0.000000], + [2.397469, 0.000015, 0.000000, 0.000000], + [2.397469, 0.000014, 0.000000, 0.000000], + [2.397469, 0.000013, 0.000000, 0.000000], + [2.397469, 0.000013, 0.000000, 0.000000], + [2.397469, 0.000012, 0.000000, 0.000000], + [2.397469, 0.000012, 0.000000, 0.000000], + [2.397469, 0.000011, 0.000000, 0.000000], + [2.397469, 0.000011, 0.000000, 0.000000], + [2.397469, 0.000010, 0.000000, 0.000000], + [2.397469, 0.000010, 0.000000, 0.000000], + [2.397469, 0.000009, 0.000000, 0.000000], + [2.397469, 0.000009, 0.000000, 0.000000], + [2.397469, 0.000008, 0.000000, 0.000000], + [2.397469, 0.000008, 0.000000, 0.000000], + [2.397469, 0.000008, 0.000000, 0.000000], + [2.397469, 0.000007, 0.000000, 0.000000], + [2.397469, 0.000007, 0.000000, 0.000000], + [2.397469, 0.000007, 0.000000, 0.000000], + [2.397469, 0.000006, 0.000000, 0.000000], + [2.397469, 0.000006, 0.000000, 0.000000], + [2.397469, 0.000006, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000005, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000004, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000003, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000002, 0.000000, 0.000000], + [2.397469, 0.000001, 0.000000, 0.000000], + [2.397469, 0.000001, 0.000000, 0.000000], + [2.397469, 0.000001, 0.000000, 0.000000], +]; +/** @type {Number} */ +const MAX_RE_WEIGHTS_RESOLUTION = MAX_RE_WEIGHTS.length; +export default { + SPHERICAL_HARMONICS, + SPHERICAL_HARMONICS_AZIMUTH_RESOLUTION, + SPHERICAL_HARMONICS_ELEVATION_RESOLUTION, + SPHERICAL_HARMONICS_MAX_ORDER, + MAX_RE_WEIGHTS, + MAX_RE_WEIGHTS_RESOLUTION +}; diff --git a/src/framework/resonator/vendor/resonance-es6/utils.d.ts b/src/framework/resonator/vendor/resonance-es6/utils.d.ts index 48d24d2..4835498 100644 --- a/src/framework/resonator/vendor/resonance-es6/utils.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/utils.d.ts @@ -1,98 +1,98 @@ -export default Utils; -/** - * @class Utils - * @description A set of defaults, constants and utility functions. - */ -declare class Utils { - /** - * Properties describing the geometry of a room. - * @typedef {Object} Utils~RoomDimensions - * @property {Number} width (in meters). - * @property {Number} height (in meters). - * @property {Number} depth (in meters). - */ - /** - * Properties describing the wall materials (from - * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS}) - * of a room. - * @typedef {Object} Utils~RoomMaterials - * @property {String} left Left-wall material name. - * @property {String} right Right-wall material name. - * @property {String} front Front-wall material name. - * @property {String} back Back-wall material name. - * @property {String} up Up-wall material name. - * @property {String} down Down-wall material name. - */ - /** - * ResonanceAudio library logging function. - * @type {Function} - * @param {any} Message to be printed out. - * @private - */ - private static log; -} -declare namespace Utils { - const DEFAULT_SOURCE_GAIN: number; - const LISTENER_MAX_OUTSIDE_ROOM_DISTANCE: number; - const SOURCE_MAX_OUTSIDE_ROOM_DISTANCE: number; - const DEFAULT_SOURCE_DISTANCE: number; - const DEFAULT_POSITION: Float32Array; - const DEFAULT_FORWARD: Float32Array; - const DEFAULT_UP: Float32Array; - const DEFAULT_RIGHT: Float32Array; - const DEFAULT_SPEED_OF_SOUND: number; - const ATTENUATION_ROLLOFFS: any[]; - const DEFAULT_ATTENUATION_ROLLOFF: string; - const DEFAULT_MIN_DISTANCE: number; - const DEFAULT_MAX_DISTANCE: number; - const DEFAULT_DIRECTIVITY_ALPHA: number; - const DEFAULT_DIRECTIVITY_SHARPNESS: number; - const DEFAULT_AZIMUTH: number; - const DEFAULT_ELEVATION: number; - const DEFAULT_AMBISONIC_ORDER: number; - const DEFAULT_SOURCE_WIDTH: number; - const DEFAULT_REFLECTION_MAX_DURATION: number; - const DEFAULT_REFLECTION_CUTOFF_FREQUENCY: number; - const DEFAULT_REFLECTION_COEFFICIENTS: any; - const DEFAULT_REFLECTION_MIN_DISTANCE: number; - const DEFAULT_ROOM_DIMENSIONS: any; - const DEFAULT_REFLECTION_MULTIPLIER: number; - const DEFAULT_REVERB_BANDWIDTH: number; - const DEFAULT_REVERB_DURATION_MULTIPLIER: number; - const DEFAULT_REVERB_PREDELAY: number; - const DEFAULT_REVERB_TAIL_ONSET: number; - const DEFAULT_REVERB_GAIN: number; - const DEFAULT_REVERB_MAX_DURATION: number; - const DEFAULT_REVERB_FREQUENCY_BANDS: any[]; - const NUMBER_REVERB_FREQUENCY_BANDS: number; - const DEFAULT_REVERB_DURATIONS: Float32Array; - const ROOM_MATERIAL_COEFFICIENTS: any; - const DEFAULT_ROOM_MATERIALS: any; - const NUMBER_REFLECTION_AVERAGING_BANDS: number; - const ROOM_STARTING_AVERAGING_BAND: number; - const ROOM_MIN_VOLUME: number; - const ROOM_AIR_ABSORPTION_COEFFICIENTS: Float32Array; - const ROOM_EYRING_CORRECTION_COEFFICIENT: number; - const TWO_PI: number; - const TWENTY_FOUR_LOG10: number; - const LOG1000: number; - const LOG2_DIV2: number; - const DEGREES_TO_RADIANS: number; - const RADIANS_TO_DEGREES: number; - const EPSILON_FLOAT: number; - /** - * Normalize a 3-d vector. - * @param {Float32Array} v 3-element vector. - * @return {Float32Array} 3-element vector. - * @private - */ - function normalizeVector(v: Float32Array): Float32Array; - /** - * Cross-product between two 3-d vectors. - * @param {Float32Array} a 3-element vector. - * @param {Float32Array} b 3-element vector. - * @return {Float32Array} - * @private - */ - function crossProduct(a: Float32Array, b: Float32Array): Float32Array; -} +export default Utils; +/** + * @class Utils + * @description A set of defaults, constants and utility functions. + */ +declare class Utils { + /** + * Properties describing the geometry of a room. + * @typedef {Object} Utils~RoomDimensions + * @property {Number} width (in meters). + * @property {Number} height (in meters). + * @property {Number} depth (in meters). + */ + /** + * Properties describing the wall materials (from + * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS}) + * of a room. + * @typedef {Object} Utils~RoomMaterials + * @property {String} left Left-wall material name. + * @property {String} right Right-wall material name. + * @property {String} front Front-wall material name. + * @property {String} back Back-wall material name. + * @property {String} up Up-wall material name. + * @property {String} down Down-wall material name. + */ + /** + * ResonanceAudio library logging function. + * @type {Function} + * @param {any} Message to be printed out. + * @private + */ + private static log; +} +declare namespace Utils { + const DEFAULT_SOURCE_GAIN: number; + const LISTENER_MAX_OUTSIDE_ROOM_DISTANCE: number; + const SOURCE_MAX_OUTSIDE_ROOM_DISTANCE: number; + const DEFAULT_SOURCE_DISTANCE: number; + const DEFAULT_POSITION: Float32Array; + const DEFAULT_FORWARD: Float32Array; + const DEFAULT_UP: Float32Array; + const DEFAULT_RIGHT: Float32Array; + const DEFAULT_SPEED_OF_SOUND: number; + const ATTENUATION_ROLLOFFS: any[]; + const DEFAULT_ATTENUATION_ROLLOFF: string; + const DEFAULT_MIN_DISTANCE: number; + const DEFAULT_MAX_DISTANCE: number; + const DEFAULT_DIRECTIVITY_ALPHA: number; + const DEFAULT_DIRECTIVITY_SHARPNESS: number; + const DEFAULT_AZIMUTH: number; + const DEFAULT_ELEVATION: number; + const DEFAULT_AMBISONIC_ORDER: number; + const DEFAULT_SOURCE_WIDTH: number; + const DEFAULT_REFLECTION_MAX_DURATION: number; + const DEFAULT_REFLECTION_CUTOFF_FREQUENCY: number; + const DEFAULT_REFLECTION_COEFFICIENTS: any; + const DEFAULT_REFLECTION_MIN_DISTANCE: number; + const DEFAULT_ROOM_DIMENSIONS: any; + const DEFAULT_REFLECTION_MULTIPLIER: number; + const DEFAULT_REVERB_BANDWIDTH: number; + const DEFAULT_REVERB_DURATION_MULTIPLIER: number; + const DEFAULT_REVERB_PREDELAY: number; + const DEFAULT_REVERB_TAIL_ONSET: number; + const DEFAULT_REVERB_GAIN: number; + const DEFAULT_REVERB_MAX_DURATION: number; + const DEFAULT_REVERB_FREQUENCY_BANDS: any[]; + const NUMBER_REVERB_FREQUENCY_BANDS: number; + const DEFAULT_REVERB_DURATIONS: Float32Array; + const ROOM_MATERIAL_COEFFICIENTS: any; + const DEFAULT_ROOM_MATERIALS: any; + const NUMBER_REFLECTION_AVERAGING_BANDS: number; + const ROOM_STARTING_AVERAGING_BAND: number; + const ROOM_MIN_VOLUME: number; + const ROOM_AIR_ABSORPTION_COEFFICIENTS: Float32Array; + const ROOM_EYRING_CORRECTION_COEFFICIENT: number; + const TWO_PI: number; + const TWENTY_FOUR_LOG10: number; + const LOG1000: number; + const LOG2_DIV2: number; + const DEGREES_TO_RADIANS: number; + const RADIANS_TO_DEGREES: number; + const EPSILON_FLOAT: number; + /** + * Normalize a 3-d vector. + * @param {Float32Array} v 3-element vector. + * @return {Float32Array} 3-element vector. + * @private + */ + function normalizeVector(v: Float32Array): Float32Array; + /** + * Cross-product between two 3-d vectors. + * @param {Float32Array} a 3-element vector. + * @param {Float32Array} b 3-element vector. + * @return {Float32Array} + * @private + */ + function crossProduct(a: Float32Array, b: Float32Array): Float32Array; +} diff --git a/src/framework/resonator/vendor/resonance-es6/utils.js b/src/framework/resonator/vendor/resonance-es6/utils.js index 5299f0c..41697e4 100644 --- a/src/framework/resonator/vendor/resonance-es6/utils.js +++ b/src/framework/resonator/vendor/resonance-es6/utils.js @@ -1,379 +1,379 @@ -/** - * @license - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 ResonanceAudio library common utilities, mathematical constants, - * and default values. - * @author Andrew Allen - */ -'use strict'; -/** - * @class Utils - * @description A set of defaults, constants and utility functions. - */ -class Utils { - /** - * Properties describing the geometry of a room. - * @typedef {Object} Utils~RoomDimensions - * @property {Number} width (in meters). - * @property {Number} height (in meters). - * @property {Number} depth (in meters). - */ - /** - * Properties describing the wall materials (from - * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS}) - * of a room. - * @typedef {Object} Utils~RoomMaterials - * @property {String} left Left-wall material name. - * @property {String} right Right-wall material name. - * @property {String} front Front-wall material name. - * @property {String} back Back-wall material name. - * @property {String} up Up-wall material name. - * @property {String} down Down-wall material name. - */ - /** - * ResonanceAudio library logging function. - * @type {Function} - * @param {any} Message to be printed out. - * @private - */ - static log() { - window.console.log.apply(window.console, [ - '%c[ResonanceAudio]%c ' - + Array.prototype.slice.call(arguments).join(' ') + ' %c(@' - + performance.now().toFixed(2) + 'ms)', - 'background: #BBDEFB; color: #FF5722; font-weight: 700', - 'font-weight: 400', - 'color: #AAA', - ]); - } -} -/** - * Default input gain (linear). - * @type {Number} - */ -Utils.DEFAULT_SOURCE_GAIN = 1; -/** - * Maximum outside-the-room distance to attenuate far-field listener by. - * @type {Number} - */ -Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE = 1; -/** - * Maximum outside-the-room distance to attenuate far-field sources by. - * @type {Number} - */ -Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE = 1; -/** - * Default distance from listener when setting angle. - * @type {Number} - */ -Utils.DEFAULT_SOURCE_DISTANCE = 1; -/** @type {Float32Array} */ -Utils.DEFAULT_POSITION = [0, 0, 0]; -/** @type {Float32Array} */ -Utils.DEFAULT_FORWARD = [0, 0, -1]; -/** @type {Float32Array} */ -Utils.DEFAULT_UP = [0, 1, 0]; -/** @type {Float32Array} */ -Utils.DEFAULT_RIGHT = [1, 0, 0]; -/** - * @type {Number} - */ -Utils.DEFAULT_SPEED_OF_SOUND = 343; -/** Rolloff models (e.g. 'logarithmic', 'linear', or 'none'). - * @type {Array} - */ -Utils.ATTENUATION_ROLLOFFS = ['logarithmic', 'linear', 'none']; -/** Default rolloff model ('logarithmic'). - * @type {string} - */ -Utils.DEFAULT_ATTENUATION_ROLLOFF = 'logarithmic'; -/** @type {Number} */ -Utils.DEFAULT_MIN_DISTANCE = 1; -/** @type {Number} */ -Utils.DEFAULT_MAX_DISTANCE = 1000; -/** - * The default alpha (i.e. microphone pattern). - * @type {Number} - */ -Utils.DEFAULT_DIRECTIVITY_ALPHA = 0; -/** - * The default pattern sharpness (i.e. pattern exponent). - * @type {Number} - */ -Utils.DEFAULT_DIRECTIVITY_SHARPNESS = 1; -/** - * Default azimuth (in degrees). Suitable range is 0 to 360. - * @type {Number} - */ -Utils.DEFAULT_AZIMUTH = 0; -/** - * Default elevation (in degres). - * Suitable range is from -90 (below) to 90 (above). - * @type {Number} - */ -Utils.DEFAULT_ELEVATION = 0; -/** - * The default ambisonic order. - * @type {Number} - */ -Utils.DEFAULT_AMBISONIC_ORDER = 1; -/** - * The default source width. - * @type {Number} - */ -Utils.DEFAULT_SOURCE_WIDTH = 0; -/** - * The maximum delay (in seconds) of a single wall reflection. - * @type {Number} - */ -Utils.DEFAULT_REFLECTION_MAX_DURATION = 0.5; -/** - * The -12dB cutoff frequency (in Hertz) for the lowpass filter applied to - * all reflections. - * @type {Number} - */ -Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY = 6400; // Uses -12dB cutoff. -/** - * The default reflection coefficients (where 0 = no reflection, 1 = perfect - * reflection, -1 = mirrored reflection (180-degrees out of phase)). - * @type {Object} - */ -Utils.DEFAULT_REFLECTION_COEFFICIENTS = { - left: 0, right: 0, front: 0, back: 0, down: 0, up: 0, -}; -/** - * The minimum distance we consider the listener to be to any given wall. - * @type {Number} - */ -Utils.DEFAULT_REFLECTION_MIN_DISTANCE = 1; -/** - * Default room dimensions (in meters). - * @type {Object} - */ -Utils.DEFAULT_ROOM_DIMENSIONS = { - width: 0, height: 0, depth: 0, -}; -/** - * The multiplier to apply to distances from the listener to each wall. - * @type {Number} - */ -Utils.DEFAULT_REFLECTION_MULTIPLIER = 1; -/** The default bandwidth (in octaves) of the center frequencies. - * @type {Number} - */ -Utils.DEFAULT_REVERB_BANDWIDTH = 1; -/** The default multiplier applied when computing tail lengths. - * @type {Number} - */ -Utils.DEFAULT_REVERB_DURATION_MULTIPLIER = 1; -/** - * The late reflections pre-delay (in milliseconds). - * @type {Number} - */ -Utils.DEFAULT_REVERB_PREDELAY = 1.5; -/** - * The length of the beginning of the impulse response to apply a - * half-Hann window to. - * @type {Number} - */ -Utils.DEFAULT_REVERB_TAIL_ONSET = 3.8; -/** - * The default gain (linear). - * @type {Number} - */ -Utils.DEFAULT_REVERB_GAIN = 0.01; -/** - * The maximum impulse response length (in seconds). - * @type {Number} - */ -Utils.DEFAULT_REVERB_MAX_DURATION = 3; -/** - * Center frequencies of the multiband late reflections. - * Nine bands are computed by: 31.25 * 2^(0:8). - * @type {Array} - */ -Utils.DEFAULT_REVERB_FREQUENCY_BANDS = [ - 31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, -]; -/** - * The number of frequency bands. - */ -Utils.NUMBER_REVERB_FREQUENCY_BANDS = - Utils.DEFAULT_REVERB_FREQUENCY_BANDS.length; -/** - * The default multiband RT60 durations (in seconds). - * @type {Float32Array} - */ -Utils.DEFAULT_REVERB_DURATIONS = - new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); -/** - * Pre-defined frequency-dependent absorption coefficients for listed materials. - * Currently supported materials are: - *
    - *
  • 'transparent'
  • - *
  • 'acoustic-ceiling-tiles'
  • - *
  • 'brick-bare'
  • - *
  • 'brick-painted'
  • - *
  • 'concrete-block-coarse'
  • - *
  • 'concrete-block-painted'
  • - *
  • 'curtain-heavy'
  • - *
  • 'fiber-glass-insulation'
  • - *
  • 'glass-thin'
  • - *
  • 'glass-thick'
  • - *
  • 'grass'
  • - *
  • 'linoleum-on-concrete'
  • - *
  • 'marble'
  • - *
  • 'metal'
  • - *
  • 'parquet-on-concrete'
  • - *
  • 'plaster-smooth'
  • - *
  • 'plywood-panel'
  • - *
  • 'polished-concrete-or-tile'
  • - *
  • 'sheetrock'
  • - *
  • 'water-or-ice-surface'
  • - *
  • 'wood-ceiling'
  • - *
  • 'wood-panel'
  • - *
  • 'uniform'
  • - *
- * @type {Object} - */ -Utils.ROOM_MATERIAL_COEFFICIENTS = { - 'transparent': [1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000], - 'acoustic-ceiling-tiles': [0.672, 0.675, 0.700, 0.660, 0.720, 0.920, 0.880, 0.750, 1.000], - 'brick-bare': [0.030, 0.030, 0.030, 0.030, 0.030, 0.040, 0.050, 0.070, 0.140], - 'brick-painted': [0.006, 0.007, 0.010, 0.010, 0.020, 0.020, 0.020, 0.030, 0.060], - 'concrete-block-coarse': [0.360, 0.360, 0.360, 0.440, 0.310, 0.290, 0.390, 0.250, 0.500], - 'concrete-block-painted': [0.092, 0.090, 0.100, 0.050, 0.060, 0.070, 0.090, 0.080, 0.160], - 'curtain-heavy': [0.073, 0.106, 0.140, 0.350, 0.550, 0.720, 0.700, 0.650, 1.000], - 'fiber-glass-insulation': [0.193, 0.220, 0.220, 0.820, 0.990, 0.990, 0.990, 0.990, 1.000], - 'glass-thin': [0.180, 0.169, 0.180, 0.060, 0.040, 0.030, 0.020, 0.020, 0.040], - 'glass-thick': [0.350, 0.350, 0.350, 0.250, 0.180, 0.120, 0.070, 0.040, 0.080], - 'grass': [0.050, 0.050, 0.150, 0.250, 0.400, 0.550, 0.600, 0.600, 0.600], - 'linoleum-on-concrete': [0.020, 0.020, 0.020, 0.030, 0.030, 0.030, 0.030, 0.020, 0.040], - 'marble': [0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.020, 0.020, 0.040], - 'metal': [0.030, 0.035, 0.040, 0.040, 0.050, 0.050, 0.050, 0.070, 0.090], - 'parquet-on-concrete': [0.028, 0.030, 0.040, 0.040, 0.070, 0.060, 0.060, 0.070, 0.140], - 'plaster-rough': [0.017, 0.018, 0.020, 0.030, 0.040, 0.050, 0.040, 0.030, 0.060], - 'plaster-smooth': [0.011, 0.012, 0.013, 0.015, 0.020, 0.030, 0.040, 0.050, 0.100], - 'plywood-panel': [0.400, 0.340, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220], - 'polished-concrete-or-tile': [0.008, 0.008, 0.010, 0.010, 0.015, 0.020, 0.020, 0.020, 0.040], - 'sheet-rock': [0.290, 0.279, 0.290, 0.100, 0.050, 0.040, 0.070, 0.090, 0.180], - 'water-or-ice-surface': [0.006, 0.006, 0.008, 0.008, 0.013, 0.015, 0.020, 0.025, 0.050], - 'wood-ceiling': [0.150, 0.147, 0.150, 0.110, 0.100, 0.070, 0.060, 0.070, 0.140], - 'wood-panel': [0.280, 0.280, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220], - 'uniform': [0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500], -}; -/** - * Default materials that use strings from - * {@linkcode Utils.MATERIAL_COEFFICIENTS MATERIAL_COEFFICIENTS} - * @type {Object} - */ -Utils.DEFAULT_ROOM_MATERIALS = { - left: 'transparent', right: 'transparent', front: 'transparent', - back: 'transparent', down: 'transparent', up: 'transparent', -}; -/** - * The number of bands to average over when computing reflection coefficients. - * @type {Number} - */ -Utils.NUMBER_REFLECTION_AVERAGING_BANDS = 3; -/** - * The starting band to average over when computing reflection coefficients. - * @type {Number} - */ -Utils.ROOM_STARTING_AVERAGING_BAND = 4; -/** - * The minimum threshold for room volume. - * Room model is disabled if volume is below this value. - * @type {Number} */ -Utils.ROOM_MIN_VOLUME = 1e-4; -/** - * Air absorption coefficients per frequency band. - * @type {Float32Array} - */ -Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS = - [0.0006, 0.0006, 0.0007, 0.0008, 0.0010, 0.0015, 0.0026, 0.0060, 0.0207]; -/** - * A scalar correction value to ensure Sabine and Eyring produce the same RT60 - * value at the cross-over threshold. - * @type {Number} - */ -Utils.ROOM_EYRING_CORRECTION_COEFFICIENT = 1.38; -/** - * @type {Number} - * @private - */ -Utils.TWO_PI = 6.28318530717959; -/** - * @type {Number} - * @private - */ -Utils.TWENTY_FOUR_LOG10 = 55.2620422318571; -/** - * @type {Number} - * @private - */ -Utils.LOG1000 = 6.90775527898214; -/** - * @type {Number} - * @private - */ -Utils.LOG2_DIV2 = 0.346573590279973; -/** - * @type {Number} - * @private - */ -Utils.DEGREES_TO_RADIANS = 0.017453292519943; -/** - * @type {Number} - * @private - */ -Utils.RADIANS_TO_DEGREES = 57.295779513082323; -/** - * @type {Number} - * @private - */ -Utils.EPSILON_FLOAT = 1e-8; -/** - * Normalize a 3-d vector. - * @param {Float32Array} v 3-element vector. - * @return {Float32Array} 3-element vector. - * @private - */ -Utils.normalizeVector = v => { - let n = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - if (n > Utils.EPSILON_FLOAT) { - n = 1 / n; - v[0] *= n; - v[1] *= n; - v[2] *= n; - } - return v; -}; -/** - * Cross-product between two 3-d vectors. - * @param {Float32Array} a 3-element vector. - * @param {Float32Array} b 3-element vector. - * @return {Float32Array} - * @private - */ -Utils.crossProduct = (a, b) => { - return [ - a[1] * b[2] - a[2] * b[1], - a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0], - ]; -}; -export default Utils; +/** + * @license + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 ResonanceAudio library common utilities, mathematical constants, + * and default values. + * @author Andrew Allen + */ +'use strict'; +/** + * @class Utils + * @description A set of defaults, constants and utility functions. + */ +class Utils { + /** + * Properties describing the geometry of a room. + * @typedef {Object} Utils~RoomDimensions + * @property {Number} width (in meters). + * @property {Number} height (in meters). + * @property {Number} depth (in meters). + */ + /** + * Properties describing the wall materials (from + * {@linkcode Utils.ROOM_MATERIAL_COEFFICIENTS ROOM_MATERIAL_COEFFICIENTS}) + * of a room. + * @typedef {Object} Utils~RoomMaterials + * @property {String} left Left-wall material name. + * @property {String} right Right-wall material name. + * @property {String} front Front-wall material name. + * @property {String} back Back-wall material name. + * @property {String} up Up-wall material name. + * @property {String} down Down-wall material name. + */ + /** + * ResonanceAudio library logging function. + * @type {Function} + * @param {any} Message to be printed out. + * @private + */ + static log() { + window.console.log.apply(window.console, [ + '%c[ResonanceAudio]%c ' + + Array.prototype.slice.call(arguments).join(' ') + ' %c(@' + + performance.now().toFixed(2) + 'ms)', + 'background: #BBDEFB; color: #FF5722; font-weight: 700', + 'font-weight: 400', + 'color: #AAA', + ]); + } +} +/** + * Default input gain (linear). + * @type {Number} + */ +Utils.DEFAULT_SOURCE_GAIN = 1; +/** + * Maximum outside-the-room distance to attenuate far-field listener by. + * @type {Number} + */ +Utils.LISTENER_MAX_OUTSIDE_ROOM_DISTANCE = 1; +/** + * Maximum outside-the-room distance to attenuate far-field sources by. + * @type {Number} + */ +Utils.SOURCE_MAX_OUTSIDE_ROOM_DISTANCE = 1; +/** + * Default distance from listener when setting angle. + * @type {Number} + */ +Utils.DEFAULT_SOURCE_DISTANCE = 1; +/** @type {Float32Array} */ +Utils.DEFAULT_POSITION = [0, 0, 0]; +/** @type {Float32Array} */ +Utils.DEFAULT_FORWARD = [0, 0, -1]; +/** @type {Float32Array} */ +Utils.DEFAULT_UP = [0, 1, 0]; +/** @type {Float32Array} */ +Utils.DEFAULT_RIGHT = [1, 0, 0]; +/** + * @type {Number} + */ +Utils.DEFAULT_SPEED_OF_SOUND = 343; +/** Rolloff models (e.g. 'logarithmic', 'linear', or 'none'). + * @type {Array} + */ +Utils.ATTENUATION_ROLLOFFS = ['logarithmic', 'linear', 'none']; +/** Default rolloff model ('logarithmic'). + * @type {string} + */ +Utils.DEFAULT_ATTENUATION_ROLLOFF = 'logarithmic'; +/** @type {Number} */ +Utils.DEFAULT_MIN_DISTANCE = 1; +/** @type {Number} */ +Utils.DEFAULT_MAX_DISTANCE = 1000; +/** + * The default alpha (i.e. microphone pattern). + * @type {Number} + */ +Utils.DEFAULT_DIRECTIVITY_ALPHA = 0; +/** + * The default pattern sharpness (i.e. pattern exponent). + * @type {Number} + */ +Utils.DEFAULT_DIRECTIVITY_SHARPNESS = 1; +/** + * Default azimuth (in degrees). Suitable range is 0 to 360. + * @type {Number} + */ +Utils.DEFAULT_AZIMUTH = 0; +/** + * Default elevation (in degres). + * Suitable range is from -90 (below) to 90 (above). + * @type {Number} + */ +Utils.DEFAULT_ELEVATION = 0; +/** + * The default ambisonic order. + * @type {Number} + */ +Utils.DEFAULT_AMBISONIC_ORDER = 1; +/** + * The default source width. + * @type {Number} + */ +Utils.DEFAULT_SOURCE_WIDTH = 0; +/** + * The maximum delay (in seconds) of a single wall reflection. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_MAX_DURATION = 0.5; +/** + * The -12dB cutoff frequency (in Hertz) for the lowpass filter applied to + * all reflections. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_CUTOFF_FREQUENCY = 6400; // Uses -12dB cutoff. +/** + * The default reflection coefficients (where 0 = no reflection, 1 = perfect + * reflection, -1 = mirrored reflection (180-degrees out of phase)). + * @type {Object} + */ +Utils.DEFAULT_REFLECTION_COEFFICIENTS = { + left: 0, right: 0, front: 0, back: 0, down: 0, up: 0, +}; +/** + * The minimum distance we consider the listener to be to any given wall. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_MIN_DISTANCE = 1; +/** + * Default room dimensions (in meters). + * @type {Object} + */ +Utils.DEFAULT_ROOM_DIMENSIONS = { + width: 0, height: 0, depth: 0, +}; +/** + * The multiplier to apply to distances from the listener to each wall. + * @type {Number} + */ +Utils.DEFAULT_REFLECTION_MULTIPLIER = 1; +/** The default bandwidth (in octaves) of the center frequencies. + * @type {Number} + */ +Utils.DEFAULT_REVERB_BANDWIDTH = 1; +/** The default multiplier applied when computing tail lengths. + * @type {Number} + */ +Utils.DEFAULT_REVERB_DURATION_MULTIPLIER = 1; +/** + * The late reflections pre-delay (in milliseconds). + * @type {Number} + */ +Utils.DEFAULT_REVERB_PREDELAY = 1.5; +/** + * The length of the beginning of the impulse response to apply a + * half-Hann window to. + * @type {Number} + */ +Utils.DEFAULT_REVERB_TAIL_ONSET = 3.8; +/** + * The default gain (linear). + * @type {Number} + */ +Utils.DEFAULT_REVERB_GAIN = 0.01; +/** + * The maximum impulse response length (in seconds). + * @type {Number} + */ +Utils.DEFAULT_REVERB_MAX_DURATION = 3; +/** + * Center frequencies of the multiband late reflections. + * Nine bands are computed by: 31.25 * 2^(0:8). + * @type {Array} + */ +Utils.DEFAULT_REVERB_FREQUENCY_BANDS = [ + 31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, +]; +/** + * The number of frequency bands. + */ +Utils.NUMBER_REVERB_FREQUENCY_BANDS = + Utils.DEFAULT_REVERB_FREQUENCY_BANDS.length; +/** + * The default multiband RT60 durations (in seconds). + * @type {Float32Array} + */ +Utils.DEFAULT_REVERB_DURATIONS = + new Float32Array(Utils.NUMBER_REVERB_FREQUENCY_BANDS); +/** + * Pre-defined frequency-dependent absorption coefficients for listed materials. + * Currently supported materials are: + *
    + *
  • 'transparent'
  • + *
  • 'acoustic-ceiling-tiles'
  • + *
  • 'brick-bare'
  • + *
  • 'brick-painted'
  • + *
  • 'concrete-block-coarse'
  • + *
  • 'concrete-block-painted'
  • + *
  • 'curtain-heavy'
  • + *
  • 'fiber-glass-insulation'
  • + *
  • 'glass-thin'
  • + *
  • 'glass-thick'
  • + *
  • 'grass'
  • + *
  • 'linoleum-on-concrete'
  • + *
  • 'marble'
  • + *
  • 'metal'
  • + *
  • 'parquet-on-concrete'
  • + *
  • 'plaster-smooth'
  • + *
  • 'plywood-panel'
  • + *
  • 'polished-concrete-or-tile'
  • + *
  • 'sheetrock'
  • + *
  • 'water-or-ice-surface'
  • + *
  • 'wood-ceiling'
  • + *
  • 'wood-panel'
  • + *
  • 'uniform'
  • + *
+ * @type {Object} + */ +Utils.ROOM_MATERIAL_COEFFICIENTS = { + 'transparent': [1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000, 1.000], + 'acoustic-ceiling-tiles': [0.672, 0.675, 0.700, 0.660, 0.720, 0.920, 0.880, 0.750, 1.000], + 'brick-bare': [0.030, 0.030, 0.030, 0.030, 0.030, 0.040, 0.050, 0.070, 0.140], + 'brick-painted': [0.006, 0.007, 0.010, 0.010, 0.020, 0.020, 0.020, 0.030, 0.060], + 'concrete-block-coarse': [0.360, 0.360, 0.360, 0.440, 0.310, 0.290, 0.390, 0.250, 0.500], + 'concrete-block-painted': [0.092, 0.090, 0.100, 0.050, 0.060, 0.070, 0.090, 0.080, 0.160], + 'curtain-heavy': [0.073, 0.106, 0.140, 0.350, 0.550, 0.720, 0.700, 0.650, 1.000], + 'fiber-glass-insulation': [0.193, 0.220, 0.220, 0.820, 0.990, 0.990, 0.990, 0.990, 1.000], + 'glass-thin': [0.180, 0.169, 0.180, 0.060, 0.040, 0.030, 0.020, 0.020, 0.040], + 'glass-thick': [0.350, 0.350, 0.350, 0.250, 0.180, 0.120, 0.070, 0.040, 0.080], + 'grass': [0.050, 0.050, 0.150, 0.250, 0.400, 0.550, 0.600, 0.600, 0.600], + 'linoleum-on-concrete': [0.020, 0.020, 0.020, 0.030, 0.030, 0.030, 0.030, 0.020, 0.040], + 'marble': [0.010, 0.010, 0.010, 0.010, 0.010, 0.010, 0.020, 0.020, 0.040], + 'metal': [0.030, 0.035, 0.040, 0.040, 0.050, 0.050, 0.050, 0.070, 0.090], + 'parquet-on-concrete': [0.028, 0.030, 0.040, 0.040, 0.070, 0.060, 0.060, 0.070, 0.140], + 'plaster-rough': [0.017, 0.018, 0.020, 0.030, 0.040, 0.050, 0.040, 0.030, 0.060], + 'plaster-smooth': [0.011, 0.012, 0.013, 0.015, 0.020, 0.030, 0.040, 0.050, 0.100], + 'plywood-panel': [0.400, 0.340, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220], + 'polished-concrete-or-tile': [0.008, 0.008, 0.010, 0.010, 0.015, 0.020, 0.020, 0.020, 0.040], + 'sheet-rock': [0.290, 0.279, 0.290, 0.100, 0.050, 0.040, 0.070, 0.090, 0.180], + 'water-or-ice-surface': [0.006, 0.006, 0.008, 0.008, 0.013, 0.015, 0.020, 0.025, 0.050], + 'wood-ceiling': [0.150, 0.147, 0.150, 0.110, 0.100, 0.070, 0.060, 0.070, 0.140], + 'wood-panel': [0.280, 0.280, 0.280, 0.220, 0.170, 0.090, 0.100, 0.110, 0.220], + 'uniform': [0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500, 0.500], +}; +/** + * Default materials that use strings from + * {@linkcode Utils.MATERIAL_COEFFICIENTS MATERIAL_COEFFICIENTS} + * @type {Object} + */ +Utils.DEFAULT_ROOM_MATERIALS = { + left: 'transparent', right: 'transparent', front: 'transparent', + back: 'transparent', down: 'transparent', up: 'transparent', +}; +/** + * The number of bands to average over when computing reflection coefficients. + * @type {Number} + */ +Utils.NUMBER_REFLECTION_AVERAGING_BANDS = 3; +/** + * The starting band to average over when computing reflection coefficients. + * @type {Number} + */ +Utils.ROOM_STARTING_AVERAGING_BAND = 4; +/** + * The minimum threshold for room volume. + * Room model is disabled if volume is below this value. + * @type {Number} */ +Utils.ROOM_MIN_VOLUME = 1e-4; +/** + * Air absorption coefficients per frequency band. + * @type {Float32Array} + */ +Utils.ROOM_AIR_ABSORPTION_COEFFICIENTS = + [0.0006, 0.0006, 0.0007, 0.0008, 0.0010, 0.0015, 0.0026, 0.0060, 0.0207]; +/** + * A scalar correction value to ensure Sabine and Eyring produce the same RT60 + * value at the cross-over threshold. + * @type {Number} + */ +Utils.ROOM_EYRING_CORRECTION_COEFFICIENT = 1.38; +/** + * @type {Number} + * @private + */ +Utils.TWO_PI = 6.28318530717959; +/** + * @type {Number} + * @private + */ +Utils.TWENTY_FOUR_LOG10 = 55.2620422318571; +/** + * @type {Number} + * @private + */ +Utils.LOG1000 = 6.90775527898214; +/** + * @type {Number} + * @private + */ +Utils.LOG2_DIV2 = 0.346573590279973; +/** + * @type {Number} + * @private + */ +Utils.DEGREES_TO_RADIANS = 0.017453292519943; +/** + * @type {Number} + * @private + */ +Utils.RADIANS_TO_DEGREES = 57.295779513082323; +/** + * @type {Number} + * @private + */ +Utils.EPSILON_FLOAT = 1e-8; +/** + * Normalize a 3-d vector. + * @param {Float32Array} v 3-element vector. + * @return {Float32Array} 3-element vector. + * @private + */ +Utils.normalizeVector = v => { + let n = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + if (n > Utils.EPSILON_FLOAT) { + n = 1 / n; + v[0] *= n; + v[1] *= n; + v[2] *= n; + } + return v; +}; +/** + * Cross-product between two 3-d vectors. + * @param {Float32Array} a 3-element vector. + * @param {Float32Array} b 3-element vector. + * @return {Float32Array} + * @private + */ +Utils.crossProduct = (a, b) => { + return [ + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0], + ]; +}; +export default Utils; diff --git a/src/framework/resonator/vendor/resonance-es6/version.d.ts b/src/framework/resonator/vendor/resonance-es6/version.d.ts index ac3a06d..a6d86f9 100644 --- a/src/framework/resonator/vendor/resonance-es6/version.d.ts +++ b/src/framework/resonator/vendor/resonance-es6/version.d.ts @@ -1,2 +1,2 @@ -declare var _default: "1.0.0"; -export default _default; +declare const _default: string; +export default _default; diff --git a/src/framework/resonator/vendor/resonance-es6/version.js b/src/framework/resonator/vendor/resonance-es6/version.js index 6719930..d32c578 100644 --- a/src/framework/resonator/vendor/resonance-es6/version.js +++ b/src/framework/resonator/vendor/resonance-es6/version.js @@ -1,24 +1,24 @@ -/** - * Copyright 2017 Google Inc. All Rights Reserved. - * 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 ResonanceAudio version. - * @author Andrew Allen - */ -'use strict'; -/** - * ResonanceAudio library version - * @type {String} - */ -export default '1.0.0'; +/** + * Copyright 2017 Google Inc. All Rights Reserved. + * 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 ResonanceAudio version. + * @author Andrew Allen + */ +'use strict'; +/** + * ResonanceAudio library version + * @type {String} + */ +export default '1.0.0'; diff --git a/src/framework/scene/manager.d.ts b/src/framework/scene/manager.d.ts index e49ae08..58d45cc 100644 --- a/src/framework/scene/manager.d.ts +++ b/src/framework/scene/manager.d.ts @@ -1,12 +1,12 @@ -import { Scene } from './scene'; -export declare class SceneManager { - scenes: Map; - currentScene: Scene; - defaultScene: Scene; - constructor(); - init(): void; - addScene(scene: Scene): void; - removeScene(scene: Scene): void; - switchTo(scene: Scene): void; - setDefaultScene(scene: Scene): void; -} +import { Scene } from './scene'; +export declare class SceneManager { + scenes: Map; + currentScene?: Scene; + defaultScene?: Scene; + constructor(); + init(): void; + addScene(scene: Scene): void; + removeScene(scene: Scene): void; + switchTo(scene: Scene): void; + setDefaultScene(scene: Scene): void; +} diff --git a/src/framework/scene/manager.js b/src/framework/scene/manager.js index 4158fac..662760e 100644 --- a/src/framework/scene/manager.js +++ b/src/framework/scene/manager.js @@ -1,33 +1,33 @@ -export class SceneManager { - constructor() { - this.scenes = new Map(); - } - init() { - if (this.defaultScene) { - this.switchTo(this.defaultScene); - } - } - addScene(scene) { - this.scenes.set(scene.id, scene); - } - removeScene(scene) { - if (scene === this.currentScene) - this.currentScene.onDeactivate(); - this.scenes.delete(scene.id); - } - switchTo(scene) { - if (scene === this.currentScene) - return; - let data; - if (this.currentScene) { - this.currentScene.onDeactivate(); - data = this.currentScene.data; - } - this.currentScene = this.scenes.get(scene.id); - this.currentScene.onSwitch(data); - this.currentScene.onActivate(this); - } - setDefaultScene(scene) { - this.defaultScene = scene; - } -} +export class SceneManager { + constructor() { + this.scenes = new Map(); + } + init() { + if (this.defaultScene) { + this.switchTo(this.defaultScene); + } + } + addScene(scene) { + this.scenes.set(scene.id, scene); + } + removeScene(scene) { + if (scene === this.currentScene) + this.currentScene.onDeactivate(); + this.scenes.delete(scene.id); + } + switchTo(scene) { + if (scene === this.currentScene) + return; + let data; + if (this.currentScene) { + this.currentScene.onDeactivate(); + data = this.currentScene.data; + } + this.currentScene = this.scenes.get(scene.id); + this.currentScene.onSwitch(data); + this.currentScene.onActivate(this); + } + setDefaultScene(scene) { + this.defaultScene = scene; + } +} diff --git a/src/framework/scene/scene.d.ts b/src/framework/scene/scene.d.ts index b52e59f..6a7cd9d 100644 --- a/src/framework/scene/scene.d.ts +++ b/src/framework/scene/scene.d.ts @@ -1,10 +1,10 @@ -import { SceneManager } from './manager'; -export interface Scene { - id: string; - data: any; - onActivate(manager: SceneManager): any; - onDeactivate(): any; - onSwitch(data: any): any; - update(dt: number): any; - updateDraw(): any; -} +import { SceneManager } from './manager'; +export declare abstract class Scene { + id: string; + data: any; + onActivate(manager: SceneManager): void; + onDeactivate(): void; + onSwitch(data: any): void; + abstract update(dt: number): void; + abstract updateDraw(): void; +} diff --git a/src/framework/scene/scene.js b/src/framework/scene/scene.js index cb0ff5c..ddaefe1 100644 --- a/src/framework/scene/scene.js +++ b/src/framework/scene/scene.js @@ -1 +1,14 @@ -export {}; +export class Scene { + // Called when the scene is activated + onActivate(manager) { + console.log(`Scene ${this.id} activated`); + } + // Called when the scene is deactivated + onDeactivate() { + console.log(`Scene ${this.id} deactivated`); + } + // Called when the scene is switched to but not yet activated. + onSwitch(data) { + this.data = data; + } +} diff --git a/src/framework/scheduler/index.d.ts b/src/framework/scheduler/index.d.ts index ddbd2ae..b977d06 100644 --- a/src/framework/scheduler/index.d.ts +++ b/src/framework/scheduler/index.d.ts @@ -1,12 +1,12 @@ -import { EventBus } from '../event-bus'; -import { RAFTimer } from './raf'; -import { Timer } from './timer'; -export declare class Scheduler extends EventBus { - logicPerSecond: number; - logicTimer: Timer; - drawTimer: RAFTimer; - constructor(logicPerSecond: number); - init(): void; - start(): void; - stop(): void; -} +import { EventBus } from '../event-bus'; +import { RAFTimer } from './raf'; +import { Timer } from './timer'; +export declare class Scheduler extends EventBus { + logicPerSecond: number; + logicTimer: Timer; + drawTimer: RAFTimer; + constructor(logicPerSecond: number); + init(): void; + start(): void; + stop(): void; +} diff --git a/src/framework/scheduler/index.js b/src/framework/scheduler/index.js index cf7b243..1c61b16 100644 --- a/src/framework/scheduler/index.js +++ b/src/framework/scheduler/index.js @@ -1,37 +1,37 @@ -import { EventBus } from '../event-bus'; -import { RAFTimer } from './raf'; -import { Timer } from './timer'; -export class Scheduler extends EventBus { - constructor(logicPerSecond) { - super(); - this.logicPerSecond = logicPerSecond; - this.init(); - } - init() { - const interval = 1000 / this.logicPerSecond; - this.logicTimer = new Timer(interval, { - id: 0, - func: (dt) => { - this.emit('preupdate.logic'); - this.emit('update.logic', dt); - this.emit('postupdate.logic'); - } - }); - this.drawTimer = new RAFTimer({ - id: 1, - func: (dt) => { - this.emit('preupdate.draw'); - this.emit('update.draw', dt); - this.emit('postupdate.draw'); - } - }); - } - start() { - this.logicTimer.start(); - this.drawTimer.start(); - } - stop() { - this.logicTimer.stop(); - this.drawTimer.stop(); - } -} +import { EventBus } from '../event-bus'; +import { RAFTimer } from './raf'; +import { Timer } from './timer'; +export class Scheduler extends EventBus { + constructor(logicPerSecond) { + super(); + this.logicPerSecond = logicPerSecond; + this.init(); + } + init() { + const interval = 1000 / this.logicPerSecond; + this.logicTimer = new Timer(interval, { + id: 0, + func: (dt) => { + this.emit('preupdate.logic'); + this.emit('update.logic', dt); + this.emit('postupdate.logic'); + } + }); + this.drawTimer = new RAFTimer({ + id: 1, + func: (dt) => { + this.emit('preupdate.draw'); + this.emit('update.draw', dt); + this.emit('postupdate.draw'); + } + }); + } + start() { + this.logicTimer.start(); + this.drawTimer.start(); + } + stop() { + this.logicTimer.stop(); + this.drawTimer.stop(); + } +} diff --git a/src/framework/scheduler/node.d.ts b/src/framework/scheduler/node.d.ts index d715c57..3c534b4 100644 --- a/src/framework/scheduler/node.d.ts +++ b/src/framework/scheduler/node.d.ts @@ -1,4 +1,4 @@ -export interface SchedulerNode { - id: number; - func: Function; -} +export interface SchedulerNode { + id: number; + func: Function; +} diff --git a/src/framework/scheduler/node.js b/src/framework/scheduler/node.js index cb0ff5c..509db18 100644 --- a/src/framework/scheduler/node.js +++ b/src/framework/scheduler/node.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/scheduler/raf.d.ts b/src/framework/scheduler/raf.d.ts index 98f9dd1..d6dfc93 100644 --- a/src/framework/scheduler/raf.d.ts +++ b/src/framework/scheduler/raf.d.ts @@ -1,10 +1,10 @@ -import { SchedulerNode } from './node'; -export declare class RAFTimer { - isStarted: boolean; - node: SchedulerNode; - constructor(node: SchedulerNode); - start(): void; - stop(): void; - schedule(): void; - handleResolve(): void; -} +import { SchedulerNode } from './node'; +export declare class RAFTimer { + isStarted: boolean; + node: SchedulerNode; + constructor(node: SchedulerNode); + start(): void; + stop(): void; + schedule(): void; + handleResolve(): void; +} diff --git a/src/framework/scheduler/raf.js b/src/framework/scheduler/raf.js index d7e5e67..75fc4b2 100644 --- a/src/framework/scheduler/raf.js +++ b/src/framework/scheduler/raf.js @@ -1,24 +1,24 @@ -export class RAFTimer { - constructor(node) { - this.isStarted = false; - this.node = node; - } - start() { - this.isStarted = true; - this.schedule(); - } - stop() { - this.isStarted = false; - } - schedule() { - window.requestAnimationFrame(this.handleResolve.bind(this)); - } - handleResolve() { - if (this.node) { - this.node.func(1); - if (this.isStarted) { - this.schedule(); - } - } - } -} +export class RAFTimer { + constructor(node) { + this.isStarted = false; + this.node = node; + } + start() { + this.isStarted = true; + this.schedule(); + } + stop() { + this.isStarted = false; + } + schedule() { + window.requestAnimationFrame(this.handleResolve.bind(this)); + } + handleResolve() { + if (this.node) { + this.node.func(1); + if (this.isStarted) { + this.schedule(); + } + } + } +} diff --git a/src/framework/scheduler/timer.d.ts b/src/framework/scheduler/timer.d.ts index ffca662..b36b9f8 100644 --- a/src/framework/scheduler/timer.d.ts +++ b/src/framework/scheduler/timer.d.ts @@ -1,14 +1,14 @@ -import { SchedulerNode } from './node'; -export declare class Timer { - time: number; - lastTime: number; - fluctuation: number; - node: SchedulerNode; - isStarted: boolean; - intervalID: number; - constructor(time: number, node: SchedulerNode); - start(): void; - stop(): void; - schedule(): void; - handleResolve(): void; -} +import { SchedulerNode } from './node'; +export declare class Timer { + time: number; + lastTime: number; + fluctuation: number; + node: SchedulerNode; + isStarted: boolean; + intervalID: number; + constructor(time: number, node: SchedulerNode); + start(): void; + stop(): void; + schedule(): void; + handleResolve(): void; +} diff --git a/src/framework/scheduler/timer.js b/src/framework/scheduler/timer.js index 2c73863..8c0ec99 100644 --- a/src/framework/scheduler/timer.js +++ b/src/framework/scheduler/timer.js @@ -1,39 +1,39 @@ -export class Timer { - constructor(time, node) { - this.time = time; - this.node = node; - this.isStarted = false; - } - start() { - this.isStarted = true; - this.schedule(); - } - stop() { - if (this.isStarted) { - if (this.intervalID) { - clearTimeout(this.intervalID); - this.intervalID = null; - this.isStarted = false; - } - } - } - schedule() { - let toWait = this.time; - if (this.lastTime) { - const fluc = Date.now() - this.lastTime; - this.fluctuation = fluc; - toWait -= fluc; - } - this.lastTime = Date.now(); - this.intervalID = setTimeout(this.handleResolve.bind(this), toWait); - } - handleResolve() { - this.lastTime = Date.now(); - if (this.node) { - this.node.func(this.time / this.lastTime); - } - if (this.isStarted) { - this.schedule(); - } - } -} +export class Timer { + constructor(time, node) { + this.time = time; + this.node = node; + this.isStarted = false; + } + start() { + this.isStarted = true; + this.schedule(); + } + stop() { + if (this.isStarted) { + if (this.intervalID) { + clearTimeout(this.intervalID); + this.intervalID = null; + this.isStarted = false; + } + } + } + schedule() { + let toWait = this.time; + if (this.lastTime) { + const fluc = Date.now() - this.lastTime; + this.fluctuation = fluc; + toWait -= fluc; + } + this.lastTime = Date.now(); + this.intervalID = setTimeout(this.handleResolve.bind(this), toWait); + } + handleResolve() { + this.lastTime = Date.now(); + if (this.node) { + this.node.func(this.time / this.lastTime); + } + if (this.isStarted) { + this.schedule(); + } + } +} diff --git a/src/framework/tts/index.d.ts b/src/framework/tts/index.d.ts index d3ca110..4848ef7 100644 --- a/src/framework/tts/index.d.ts +++ b/src/framework/tts/index.d.ts @@ -1,7 +1,7 @@ -import { BaseOutput } from './outputs/base-output'; -export declare class TTS { - private output; - constructor(output?: BaseOutput); - speak(text: string): void; - stop(): void; -} +import { BaseOutput } from './outputs/base-output'; +export declare class TTS { + private output; + constructor(output?: BaseOutput); + speak(text: string): void; + stop(): void; +} diff --git a/src/framework/tts/index.js b/src/framework/tts/index.js index 85edb61..838e2ab 100644 --- a/src/framework/tts/index.js +++ b/src/framework/tts/index.js @@ -1,12 +1,12 @@ -import { createOutput } from './output-factory'; -export class TTS { - constructor(output = createOutput()) { - this.output = output; - } - speak(text) { - this.output.speak(text); - } - stop() { - this.output.stop(); - } -} +import { createOutput } from './output-factory'; +export class TTS { + constructor(output = createOutput()) { + this.output = output; + } + speak(text) { + this.output.speak(text); + } + stop() { + this.output.stop(); + } +} diff --git a/src/framework/tts/output-factory.d.ts b/src/framework/tts/output-factory.d.ts index e034ee0..a01e972 100644 --- a/src/framework/tts/output-factory.d.ts +++ b/src/framework/tts/output-factory.d.ts @@ -1,5 +1,5 @@ -import { BaseOutput } from './outputs/base-output'; -import { AriaOutput } from './outputs/aria'; -import { WebTTSOutput } from './outputs/webtts'; -export declare function createOutput(key?: string): any; -export { WebTTSOutput, AriaOutput, BaseOutput }; +import { BaseOutput } from './outputs/base-output'; +import { AriaOutput } from './outputs/aria'; +import { WebTTSOutput } from './outputs/webtts'; +export declare function createOutput(key?: string): any; +export { WebTTSOutput, AriaOutput, BaseOutput }; diff --git a/src/framework/tts/output-factory.js b/src/framework/tts/output-factory.js index 6ef84f2..1134d43 100644 --- a/src/framework/tts/output-factory.js +++ b/src/framework/tts/output-factory.js @@ -1,17 +1,17 @@ -import { BaseOutput } from './outputs/base-output'; -import { AriaOutput } from './outputs/aria'; -import { WebTTSOutput } from './outputs/webtts'; -export function createOutput(key = 'aria') { - switch (key) { - case 'aria': - return AriaOutput; - break; - case 'webtts': - return WebTTSOutput; - break; - default: - return AriaOutput; - break; - } -} -export { WebTTSOutput, AriaOutput, BaseOutput }; +import { BaseOutput } from './outputs/base-output'; +import { AriaOutput } from './outputs/aria'; +import { WebTTSOutput } from './outputs/webtts'; +export function createOutput(key = 'aria') { + switch (key) { + case 'aria': + return new AriaOutput(); + break; + case 'webtts': + return new WebTTSOutput(); + break; + default: + return new AriaOutput(); + break; + } +} +export { WebTTSOutput, AriaOutput, BaseOutput }; diff --git a/src/framework/tts/outputs/aria.d.ts b/src/framework/tts/outputs/aria.d.ts index 5efbf8a..a56ab19 100644 --- a/src/framework/tts/outputs/aria.d.ts +++ b/src/framework/tts/outputs/aria.d.ts @@ -1,11 +1,11 @@ -import { BaseOutput } from './base-output'; -export declare class AriaOutput extends BaseOutput { - private container; - private speechDisplay; - private timeout; - constructor(options?: any); - private init; - speak(text: string): void; - stop(): void; - clearDisplay(): void; -} +import { BaseOutput } from './base-output'; +export declare class AriaOutput extends BaseOutput { + private container; + private speechDisplay; + private timeout; + constructor(options?: any); + private init; + speak(text: string): void; + stop(): void; + clearDisplay(): void; +} diff --git a/src/framework/tts/outputs/aria.js b/src/framework/tts/outputs/aria.js index f3d5ec9..766eac7 100644 --- a/src/framework/tts/outputs/aria.js +++ b/src/framework/tts/outputs/aria.js @@ -1,32 +1,32 @@ -import { BaseOutput } from './base-output'; -export class AriaOutput extends BaseOutput { - constructor(options = {}) { - super(); - this.timeout = 100; - this.timeout = options.timeout || 100; - this.init(); - } - init() { - this.container = document.createElement('div'); - this.container.setAttribute('aria-live', 'polite'); - this.speechDisplay = document.createElement('div'); - this.speechDisplay.setAttribute('aria-live', 'polite'); - this.container.append(this.speechDisplay); - document.body.appendChild(this.container); - document.body.insertBefore(this.container, document.body.firstChild); - } - speak(text) { - this.clearDisplay(); - const node = document.createTextNode(text); - const para = document.createElement('p'); - para.appendChild(node); - this.speechDisplay.appendChild(para); - setTimeout(this.clearDisplay.bind(this), this.timeout); - } - stop() { - this.clearDisplay(); - } - clearDisplay() { - this.speechDisplay.innerHTML = ''; - } -} +import { BaseOutput } from './base-output'; +export class AriaOutput extends BaseOutput { + constructor(options = {}) { + super(); + this.timeout = 100; + this.timeout = options.timeout || 100; + this.init(); + } + init() { + this.container = document.createElement('div'); + this.container.setAttribute('aria-live', 'polite'); + this.speechDisplay = document.createElement('div'); + this.speechDisplay.setAttribute('aria-live', 'polite'); + this.container.append(this.speechDisplay); + document.body.appendChild(this.container); + document.body.insertBefore(this.container, document.body.firstChild); + } + speak(text) { + this.clearDisplay(); + const node = document.createTextNode(text); + const para = document.createElement('p'); + para.appendChild(node); + this.speechDisplay.appendChild(para); + setTimeout(this.clearDisplay.bind(this), this.timeout); + } + stop() { + this.clearDisplay(); + } + clearDisplay() { + this.speechDisplay.innerHTML = ''; + } +} diff --git a/src/framework/tts/outputs/base-output.d.ts b/src/framework/tts/outputs/base-output.d.ts index a89f559..5e74a35 100644 --- a/src/framework/tts/outputs/base-output.d.ts +++ b/src/framework/tts/outputs/base-output.d.ts @@ -1,5 +1,5 @@ -export declare class BaseOutput { - speak(text: string): void; - stop(): void; - setOptions(options: any): void; -} +export declare class BaseOutput { + speak(text: string): void; + stop(): void; + setOptions(options: any): void; +} diff --git a/src/framework/tts/outputs/base-output.js b/src/framework/tts/outputs/base-output.js index 762054b..497a347 100644 --- a/src/framework/tts/outputs/base-output.js +++ b/src/framework/tts/outputs/base-output.js @@ -1,11 +1,11 @@ -export class BaseOutput { - speak(text) { - return; - } - stop() { - return; - } - setOptions(options) { - return; - } -} +export class BaseOutput { + speak(text) { + return; + } + stop() { + return; + } + setOptions(options) { + return; + } +} diff --git a/src/framework/tts/outputs/webtts.d.ts b/src/framework/tts/outputs/webtts.d.ts index 8922e09..98c6385 100644 --- a/src/framework/tts/outputs/webtts.d.ts +++ b/src/framework/tts/outputs/webtts.d.ts @@ -1,3 +1,9 @@ -import { BaseOutput } from './base-output'; -export declare class WebTTSOutput extends BaseOutput { -} +import { BaseOutput } from './base-output'; +export declare class WebTTSOutput extends BaseOutput { + private synth; + private rate; + constructor(options?: any); + speak(text: string): void; + stop(): void; + setOptions(options: any): void; +} diff --git a/src/framework/tts/outputs/webtts.js b/src/framework/tts/outputs/webtts.js index dd4baad..414bf0a 100644 --- a/src/framework/tts/outputs/webtts.js +++ b/src/framework/tts/outputs/webtts.js @@ -1,3 +1,19 @@ -import { BaseOutput } from './base-output'; -export class WebTTSOutput extends BaseOutput { -} +import { BaseOutput } from './base-output'; +export class WebTTSOutput extends BaseOutput { + constructor(options = {}) { + super(); + this.rate = options.rate || 1; + this.synth = window.speechSynthesis; + } + speak(text) { + let utterThis = new SpeechSynthesisUtterance(text); + utterThis.rate = this.rate; + this.synth.speak(utterThis); + } + stop() { + this.synth.cancel(); + } + setOptions(options) { + this.rate = options.rate || 1; + } +} diff --git a/src/framework/ui/dialog/control-container.d.ts b/src/framework/ui/dialog/control-container.d.ts new file mode 100644 index 0000000..a4fd3d4 --- /dev/null +++ b/src/framework/ui/dialog/control-container.d.ts @@ -0,0 +1,8 @@ +import { BaseControl } from "./controls/base-control"; +export declare class ControlContainer { + private controls; + constructor(controls: BaseControl[]); + init(): void; + show(): void; + hide(): void; +} diff --git a/src/framework/ui/dialog/control-container.js b/src/framework/ui/dialog/control-container.js new file mode 100644 index 0000000..7253a2e --- /dev/null +++ b/src/framework/ui/dialog/control-container.js @@ -0,0 +1,11 @@ +export class ControlContainer { + constructor(controls) { + this.controls = controls; + } + init() { + } + show() { + } + hide() { + } +} diff --git a/src/framework/ui/dialog/controls/base-control.d.ts b/src/framework/ui/dialog/controls/base-control.d.ts new file mode 100644 index 0000000..0cad728 --- /dev/null +++ b/src/framework/ui/dialog/controls/base-control.d.ts @@ -0,0 +1,10 @@ +import { EventBus } from "../../../event-bus"; +export declare class BaseControl extends EventBus { + constructor(); + show(): void; + hide(): void; + init(): void; + attach(): void; + detach(): void; + getState(): void; +} diff --git a/src/framework/ui/dialog/controls/base-control.js b/src/framework/ui/dialog/controls/base-control.js new file mode 100644 index 0000000..558cd29 --- /dev/null +++ b/src/framework/ui/dialog/controls/base-control.js @@ -0,0 +1,24 @@ +import { EventBus } from "../../../event-bus"; +export class BaseControl extends EventBus { + constructor() { + super(); + } + show() { + return; + } + hide() { + return; + } + init() { + return; + } + attach() { + return; + } + detach() { + return; + } + getState() { + return; + } +} diff --git a/src/framework/ui/dialog/controls/button-control.d.ts b/src/framework/ui/dialog/controls/button-control.d.ts new file mode 100644 index 0000000..9fbf890 --- /dev/null +++ b/src/framework/ui/dialog/controls/button-control.d.ts @@ -0,0 +1,3 @@ +import { BaseControl } from "./base-control"; +export declare class Button extends BaseControl { +} diff --git a/src/framework/ui/dialog/controls/button-control.js b/src/framework/ui/dialog/controls/button-control.js new file mode 100644 index 0000000..ece5078 --- /dev/null +++ b/src/framework/ui/dialog/controls/button-control.js @@ -0,0 +1,3 @@ +import { BaseControl } from "./base-control"; +export class Button extends BaseControl { +} diff --git a/src/framework/ui/dialog/controls/checkbox-control.d.ts b/src/framework/ui/dialog/controls/checkbox-control.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/checkbox-control.js b/src/framework/ui/dialog/controls/checkbox-control.js new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/list-control.d.ts b/src/framework/ui/dialog/controls/list-control.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/list-control.js b/src/framework/ui/dialog/controls/list-control.js new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/slider-control.d.ts b/src/framework/ui/dialog/controls/slider-control.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/slider-control.js b/src/framework/ui/dialog/controls/slider-control.js new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/text-control.d.ts b/src/framework/ui/dialog/controls/text-control.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/text-control.js b/src/framework/ui/dialog/controls/text-control.js new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/tree-control.d.ts b/src/framework/ui/dialog/controls/tree-control.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/controls/tree-control.js b/src/framework/ui/dialog/controls/tree-control.js new file mode 100644 index 0000000..e69de29 diff --git a/src/framework/ui/dialog/index.d.ts b/src/framework/ui/dialog/index.d.ts new file mode 100644 index 0000000..115d705 --- /dev/null +++ b/src/framework/ui/dialog/index.d.ts @@ -0,0 +1,14 @@ +import { EventBus } from '../../event-bus'; +import { SoundSet } from "./interfaces/sound-set"; +export declare class Dialog extends EventBus { + running: boolean; + private containers; + private target; + private focused; + private soundSet; + private soundManager; + private keyManager; + private title; + constructor(title: string, soundSet: SoundSet); + run(target: HTMLElement): Promise; +} diff --git a/src/framework/ui/dialog/index.js b/src/framework/ui/dialog/index.js new file mode 100644 index 0000000..1475a92 --- /dev/null +++ b/src/framework/ui/dialog/index.js @@ -0,0 +1,24 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { EventBus } from '../../event-bus'; +import { SoundManager } from "./sound-manager"; +import { KeyManager } from "./key-manager"; +export class Dialog extends EventBus { + constructor(title, soundSet) { + super(); + this.title = title; + this.keyManager = new KeyManager(this); + this.soundManager = new SoundManager(this); + } + run(target) { + return __awaiter(this, void 0, void 0, function* () { + }); + } +} diff --git a/src/framework/ui/dialog/interfaces/playable-sound.d.ts b/src/framework/ui/dialog/interfaces/playable-sound.d.ts new file mode 100644 index 0000000..34bdc03 --- /dev/null +++ b/src/framework/ui/dialog/interfaces/playable-sound.d.ts @@ -0,0 +1,3 @@ +export interface IPlayableSound { + play(): any; +} diff --git a/src/framework/ui/dialog/interfaces/playable-sound.js b/src/framework/ui/dialog/interfaces/playable-sound.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/src/framework/ui/dialog/interfaces/playable-sound.js @@ -0,0 +1 @@ +export {}; diff --git a/src/framework/ui/dialog/interfaces/sound-set.d.ts b/src/framework/ui/dialog/interfaces/sound-set.d.ts new file mode 100644 index 0000000..9e44362 --- /dev/null +++ b/src/framework/ui/dialog/interfaces/sound-set.d.ts @@ -0,0 +1,17 @@ +import { IPlayableSound } from './playable-sound'; +export interface SoundSet { + open?: IPlayableSound; + close?: IPlayableSound; + boundary?: IPlayableSound; + choose?: IPlayableSound; + move?: IPlayableSound; + scroller?: IPlayableSound; + sliderLeft?: IPlayableSound; + sliderRight?: IPlayableSound; + wrap?: IPlayableSound; + char?: IPlayableSound; + delete?: IPlayableSound; + enter?: IPlayableSound; + checked?: IPlayableSound; + unchecked?: IPlayableSound; +} diff --git a/src/framework/ui/dialog/interfaces/sound-set.js b/src/framework/ui/dialog/interfaces/sound-set.js new file mode 100644 index 0000000..509db18 --- /dev/null +++ b/src/framework/ui/dialog/interfaces/sound-set.js @@ -0,0 +1 @@ +export {}; diff --git a/src/framework/ui/dialog/key-manager.d.ts b/src/framework/ui/dialog/key-manager.d.ts new file mode 100644 index 0000000..ef58625 --- /dev/null +++ b/src/framework/ui/dialog/key-manager.d.ts @@ -0,0 +1,5 @@ +import { Dialog } from "."; +export declare class KeyManager { + private instance; + constructor(instance: Dialog); +} diff --git a/src/framework/ui/dialog/key-manager.js b/src/framework/ui/dialog/key-manager.js new file mode 100644 index 0000000..4eef5b5 --- /dev/null +++ b/src/framework/ui/dialog/key-manager.js @@ -0,0 +1,5 @@ +export class KeyManager { + constructor(instance) { + this.instance = instance; + } +} diff --git a/src/framework/ui/dialog/sound-manager.d.ts b/src/framework/ui/dialog/sound-manager.d.ts new file mode 100644 index 0000000..2845d0d --- /dev/null +++ b/src/framework/ui/dialog/sound-manager.d.ts @@ -0,0 +1,4 @@ +import { Dialog } from "."; +export declare class SoundManager { + constructor(instance: Dialog); +} diff --git a/src/framework/ui/dialog/sound-manager.js b/src/framework/ui/dialog/sound-manager.js new file mode 100644 index 0000000..a4c5e32 --- /dev/null +++ b/src/framework/ui/dialog/sound-manager.js @@ -0,0 +1,3 @@ +export class SoundManager { + constructor(instance) { } +} diff --git a/src/framework/ui/index.d.ts b/src/framework/ui/index.d.ts index 08963e3..7ca64c9 100644 --- a/src/framework/ui/index.d.ts +++ b/src/framework/ui/index.d.ts @@ -1 +1 @@ -export * from './menu/index'; +export * from './menu/index'; diff --git a/src/framework/ui/index.js b/src/framework/ui/index.js index 8d4cb7f..ac730ea 100644 --- a/src/framework/ui/index.js +++ b/src/framework/ui/index.js @@ -1,2 +1,2 @@ -export * from './menu/index'; -// export * as Text from './text'; +export * from './menu/index'; +// export * as Text from './text'; diff --git a/src/framework/ui/menu/index.d.ts b/src/framework/ui/menu/index.d.ts index aab85a9..bf9c99a 100644 --- a/src/framework/ui/menu/index.d.ts +++ b/src/framework/ui/menu/index.d.ts @@ -1,39 +1,39 @@ -import { BaseItem } from './items/base-item'; -import { SoundSet } from './interfaces/sound-set'; -import * as EventEmitter from 'eventemitter3'; -export declare class Menu extends EventEmitter { - private title; - private menuItems; - private soundSet; - private defaultAction; - private cancelAction; - private titleContainer; - private currentItem; - private currentIndex; - private container; - private element; - private DOMNodes; - private soundManager; - private keyboardManager; - constructor(title?: string, menuItems?: BaseItem[], soundSet?: SoundSet, defaultAction?: string, cancelAction?: string); - private init; - addItem(item: BaseItem): this; - setTitle(title: string): this; - setSoundSet(soundSet: SoundSet): this; - setDefaultAction(id: string): this; - setCancelAction(id: string): this; - run(element: HTMLElement): Promise; - close(): void; - private appendToContainer; - private handleItemUpdate; - private onItemFocus; - focusNext(): void; - focusPrevious(): void; - private focusCurrentIndex; - getCurrentFocus(): BaseItem; - getContainer(): HTMLElement; - clickDefaultAction(): void; - clickCancelAction(): void; - private compile; -} -export * from './items'; +import { BaseItem } from './items/base-item'; +import { SoundSet } from './interfaces/sound-set'; +import { EventBus } from '../../event-bus'; +export declare class Menu extends EventBus { + private title; + private menuItems; + private soundSet; + private defaultAction; + private cancelAction; + private titleContainer; + private currentItem; + private currentIndex; + private container; + private element; + private DOMNodes; + private soundManager; + private keyboardManager; + constructor(title?: string, menuItems?: BaseItem[], soundSet?: SoundSet, defaultAction?: string, cancelAction?: string); + private init; + addItem(item: BaseItem): this; + setTitle(title: string): this; + setSoundSet(soundSet: SoundSet): this; + setDefaultAction(id: string): this; + setCancelAction(id: string): this; + run(element: HTMLElement): Promise; + close(): void; + private appendToContainer; + private handleItemUpdate; + private onItemFocus; + focusNext(): void; + focusPrevious(): void; + private focusCurrentIndex; + getCurrentFocus(): BaseItem; + getContainer(): HTMLElement; + clickDefaultAction(): void; + clickCancelAction(): void; + private compile; +} +export * from './items'; diff --git a/src/framework/ui/menu/index.js b/src/framework/ui/menu/index.js index bb53ddf..057c4a2 100644 --- a/src/framework/ui/menu/index.js +++ b/src/framework/ui/menu/index.js @@ -1,145 +1,145 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import * as EventEmitter from 'eventemitter3'; -import { SoundManager } from './sound-manager'; -import { KeyboardManager } from './keyboard-manager'; -export class Menu extends EventEmitter { - constructor(title = 'Menu', menuItems = [], soundSet = null, defaultAction = null, cancelAction = null) { - super(); - this.title = title; - this.menuItems = menuItems; - this.soundSet = soundSet; - this.defaultAction = defaultAction; - this.cancelAction = cancelAction; - this.currentIndex = 0; - this.DOMNodes = []; - this.currentIndex = 0; - this.currentItem = null; - this.soundManager = new SoundManager(soundSet); - this.keyboardManager = new KeyboardManager(this); - this.init(); - } - init() { - this.menuItems[this.currentIndex] && - this.menuItems[this.currentIndex].focus(); - this.emit('init'); - } - addItem(item) { - this.menuItems.push(item); - this.emit('item.add', item); - return this; - } - setTitle(title) { - this.title = title; - return this; - } - setSoundSet(soundSet) { - this.soundSet = soundSet; - this.soundManager.setSoundSet(this.soundSet); - return this; - } - setDefaultAction(id) { - this.defaultAction = id; - return this; - } - setCancelAction(id) { - this.cancelAction = id; - return this; - } - run(element) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { - this.element = element; - this.container = document.createElement('div'); - this.titleContainer = document.createElement('h1'); - this.titleContainer.textContent = this.title; - this.container.appendChild(this.titleContainer); - this.menuItems.forEach((item) => { - this.appendToContainer(item.getDOMNode()); - item.on('update', this.handleItemUpdate.bind(this)); - item.on('focus', this.onItemFocus.bind(this)); - item.on('choose', (event) => { - const menuMap = this.compile(); - this.soundManager.handleSound('choose'); - this.emit('choose', menuMap); - resolve(menuMap); - }); - }); - element.appendChild(this.container); - this.soundManager.handleSound('open'); - this.keyboardManager.init(); - // push some data onto the history stack so that we can use the browser's back button to exit out of the menu. - history.pushState({ menu: true }, null, null); - }); - }); - } - close() { - this.container.remove(); - this.soundManager.handleSound('close'); - this.keyboardManager.release(); - this.DOMNodes.forEach((item) => { - this.container.removeChild(item); - }); - this.emit('close'); - } - appendToContainer(node) { - this.container.appendChild(node); - this.DOMNodes.push(node); - } - handleItemUpdate(value) { - this.soundManager.handleSound(value.type, value.value); - this.emit('update', this.compile()); - } - onItemFocus(id) { - this.soundManager.handleSound('focus'); - this.currentIndex = this.menuItems.indexOf(this.menuItems.find((item) => item.getID() == id)); - this.emit('focus', this.menuItems[this.currentIndex]); - } - focusNext() { - if (this.currentIndex < this.menuItems.length - 1) { - this.currentIndex++; - } - this.focusCurrentIndex(); - } - focusPrevious() { - if (this.currentIndex > 0) { - this.currentIndex--; - } - this.focusCurrentIndex(); - } - focusCurrentIndex() { - this.menuItems[this.currentIndex].focus(); - } - getCurrentFocus() { - return this.menuItems[this.currentIndex]; - } - getContainer() { - return this.container; - } - clickDefaultAction() { - if (!this.defaultAction) - return; - const item = this.menuItems.find((item) => item.getID() === this.defaultAction); - item.click(); - } - clickCancelAction() { - if (!this.cancelAction) - return; - const node = this.menuItems.find((item) => item.getID() === this.cancelAction); - node.click(); - } - compile() { - const menuMap = new Map(); - this.menuItems.forEach((item) => menuMap.set(item.getID(), item.getContents())); - menuMap.set('selected', this.menuItems[this.currentIndex].getID()); - return menuMap; - } -} -export * from './items'; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { EventBus } from '../../event-bus'; +import { SoundManager } from './sound-manager'; +import { KeyboardManager } from './keyboard-manager'; +export class Menu extends EventBus { + constructor(title = 'Menu', menuItems = [], soundSet = null, defaultAction = null, cancelAction = null) { + super(); + this.title = title; + this.menuItems = menuItems; + this.soundSet = soundSet; + this.defaultAction = defaultAction; + this.cancelAction = cancelAction; + this.currentIndex = 0; + this.DOMNodes = []; + this.currentIndex = 0; + this.currentItem = null; + this.soundManager = new SoundManager(soundSet); + this.keyboardManager = new KeyboardManager(this); + this.init(); + } + init() { + this.menuItems[this.currentIndex] && + this.menuItems[this.currentIndex].focus(); + this.emit('init'); + } + addItem(item) { + this.menuItems.push(item); + this.emit('item.add', item); + return this; + } + setTitle(title) { + this.title = title; + return this; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + this.soundManager.setSoundSet(this.soundSet); + return this; + } + setDefaultAction(id) { + this.defaultAction = id; + return this; + } + setCancelAction(id) { + this.cancelAction = id; + return this; + } + run(element) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + this.element = element; + this.container = document.createElement('div'); + this.titleContainer = document.createElement('h1'); + this.titleContainer.textContent = this.title; + this.container.appendChild(this.titleContainer); + this.menuItems.forEach((item) => { + this.appendToContainer(item.getDOMNode()); + item.subscribe('update', this.handleItemUpdate.bind(this)); + item.subscribe('focus', this.onItemFocus.bind(this)); + item.subscribe('choose', (event) => { + const menuMap = this.compile(); + this.soundManager.handleSound('choose'); + this.emit('choose', menuMap); + resolve(menuMap); + }); + }); + element.appendChild(this.container); + this.soundManager.handleSound('open'); + this.keyboardManager.init(); + // push some data onto the history stack so that we can use the browser's back button to exit out of the menu. + history.pushState({ menu: true }, null, null); + }); + }); + } + close() { + this.container.remove(); + this.soundManager.handleSound('close'); + this.keyboardManager.release(); + this.DOMNodes.forEach((item) => { + this.container.removeChild(item); + }); + this.emit('close'); + } + appendToContainer(node) { + this.container.appendChild(node); + this.DOMNodes.push(node); + } + handleItemUpdate(value) { + this.soundManager.handleSound(value.type, value.value); + this.emit('update', this.compile()); + } + onItemFocus(id) { + this.soundManager.handleSound('focus'); + this.currentIndex = this.menuItems.indexOf(this.menuItems.find((item) => item.getID() == id)); + this.emit('focus', this.menuItems[this.currentIndex]); + } + focusNext() { + if (this.currentIndex < this.menuItems.length - 1) { + this.currentIndex++; + } + this.focusCurrentIndex(); + } + focusPrevious() { + if (this.currentIndex > 0) { + this.currentIndex--; + } + this.focusCurrentIndex(); + } + focusCurrentIndex() { + this.menuItems[this.currentIndex].focus(); + } + getCurrentFocus() { + return this.menuItems[this.currentIndex]; + } + getContainer() { + return this.container; + } + clickDefaultAction() { + if (!this.defaultAction) + return; + const item = this.menuItems.find((item) => item.getID() === this.defaultAction); + item.click(); + } + clickCancelAction() { + if (!this.cancelAction) + return; + const node = this.menuItems.find((item) => item.getID() === this.cancelAction); + node.click(); + } + compile() { + const menuMap = new Map(); + this.menuItems.forEach((item) => menuMap.set(item.getID(), item.getContents())); + menuMap.set('selected', this.menuItems[this.currentIndex].getID()); + return menuMap; + } +} +export * from './items'; diff --git a/src/framework/ui/menu/interfaces/playable-sound.d.ts b/src/framework/ui/menu/interfaces/playable-sound.d.ts index 900dad8..34bdc03 100644 --- a/src/framework/ui/menu/interfaces/playable-sound.d.ts +++ b/src/framework/ui/menu/interfaces/playable-sound.d.ts @@ -1,3 +1,3 @@ -export interface IPlayableSound { - play(): any; -} +export interface IPlayableSound { + play(): any; +} diff --git a/src/framework/ui/menu/interfaces/playable-sound.js b/src/framework/ui/menu/interfaces/playable-sound.js index cb0ff5c..509db18 100644 --- a/src/framework/ui/menu/interfaces/playable-sound.js +++ b/src/framework/ui/menu/interfaces/playable-sound.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/ui/menu/interfaces/sound-set.d.ts b/src/framework/ui/menu/interfaces/sound-set.d.ts index 8297040..9e44362 100644 --- a/src/framework/ui/menu/interfaces/sound-set.d.ts +++ b/src/framework/ui/menu/interfaces/sound-set.d.ts @@ -1,17 +1,17 @@ -import { IPlayableSound } from './playable-sound'; -export interface SoundSet { - open?: IPlayableSound; - close?: IPlayableSound; - boundary?: IPlayableSound; - choose?: IPlayableSound; - move?: IPlayableSound; - scroller?: IPlayableSound; - sliderLeft?: IPlayableSound; - sliderRight?: IPlayableSound; - wrap?: IPlayableSound; - char?: IPlayableSound; - delete?: IPlayableSound; - enter?: IPlayableSound; - checked?: IPlayableSound; - unchecked?: IPlayableSound; -} +import { IPlayableSound } from './playable-sound'; +export interface SoundSet { + open?: IPlayableSound; + close?: IPlayableSound; + boundary?: IPlayableSound; + choose?: IPlayableSound; + move?: IPlayableSound; + scroller?: IPlayableSound; + sliderLeft?: IPlayableSound; + sliderRight?: IPlayableSound; + wrap?: IPlayableSound; + char?: IPlayableSound; + delete?: IPlayableSound; + enter?: IPlayableSound; + checked?: IPlayableSound; + unchecked?: IPlayableSound; +} diff --git a/src/framework/ui/menu/interfaces/sound-set.js b/src/framework/ui/menu/interfaces/sound-set.js index cb0ff5c..509db18 100644 --- a/src/framework/ui/menu/interfaces/sound-set.js +++ b/src/framework/ui/menu/interfaces/sound-set.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/ui/menu/items/base-item.d.ts b/src/framework/ui/menu/items/base-item.d.ts index 6e8bd57..8bf4254 100644 --- a/src/framework/ui/menu/items/base-item.d.ts +++ b/src/framework/ui/menu/items/base-item.d.ts @@ -1,13 +1,13 @@ -import * as EventEmitter from 'eventemitter3'; -export declare class BaseItem extends EventEmitter { - protected id: string; - protected title: string; - protected container: HTMLElement; - constructor(id: string, title: string); - getDOMNode(): HTMLElement; - getContents(): void; - protected onFocus(event: Event): void; - focus(): void; - click(): void; - getID(): string; -} +import { EventBus } from "../../../event-bus"; +export declare class BaseItem extends EventBus { + protected id: string; + protected title: string; + protected container: HTMLElement; + constructor(id: string, title: string); + getDOMNode(): HTMLElement; + getContents(): void; + protected onFocus(event: Event): void; + focus(): void; + click(): void; + getID(): string; +} diff --git a/src/framework/ui/menu/items/base-item.js b/src/framework/ui/menu/items/base-item.js index c9c64a7..93eed26 100644 --- a/src/framework/ui/menu/items/base-item.js +++ b/src/framework/ui/menu/items/base-item.js @@ -1,29 +1,29 @@ -import * as EventEmitter from 'eventemitter3'; -export class BaseItem extends EventEmitter { - constructor(id, title) { - super(); - this.id = id; - this.title = title; - } - getDOMNode() { - let node = document.createTextNode(this.title); - let element = document.createElement('div'); - element.appendChild(node); - return element; - } - getContents() { - return; - } - onFocus(event) { - this.emit('focus', this.id); - } - focus() { - this.container && this.container.focus(); - } - click() { - return; - } - getID() { - return this.id; - } -} +import { EventBus } from "../../../event-bus"; +export class BaseItem extends EventBus { + constructor(id, title) { + super(); + this.id = id; + this.title = title; + } + getDOMNode() { + let node = document.createTextNode(this.title); + let element = document.createElement('div'); + element.appendChild(node); + return element; + } + getContents() { + return; + } + onFocus(event) { + this.emit('focus', this.id); + } + focus() { + this.container && this.container.focus(); + } + click() { + return; + } + getID() { + return this.id; + } +} diff --git a/src/framework/ui/menu/items/checkbox-item.d.ts b/src/framework/ui/menu/items/checkbox-item.d.ts index faa398d..fccd1e6 100644 --- a/src/framework/ui/menu/items/checkbox-item.d.ts +++ b/src/framework/ui/menu/items/checkbox-item.d.ts @@ -1,10 +1,10 @@ -import { BaseItem } from './base-item'; -export declare class CheckboxItem extends BaseItem { - private checkboxElement; - private label; - constructor(id: string, title: string); - getDOMNode(): HTMLElement; - getContents(): boolean; - private onChange; - focus(): void; -} +import { BaseItem } from './base-item'; +export declare class CheckboxItem extends BaseItem { + private checkboxElement; + private label; + constructor(id: string, title: string); + getDOMNode(): HTMLElement; + getContents(): boolean; + private onChange; + focus(): void; +} diff --git a/src/framework/ui/menu/items/checkbox-item.js b/src/framework/ui/menu/items/checkbox-item.js index 93d539d..fc29f0a 100644 --- a/src/framework/ui/menu/items/checkbox-item.js +++ b/src/framework/ui/menu/items/checkbox-item.js @@ -1,32 +1,32 @@ -import { BaseItem } from './base-item'; -export class CheckboxItem extends BaseItem { - constructor(id, title) { - super(id, title); - } - getDOMNode() { - this.container = document.createElement('div'); - this.label = document.createElement('label'); - this.label.setAttribute('for', `chkbx_${this.id}`); - this.label.textContent = this.title; - this.checkboxElement = document.createElement('input'); - this.checkboxElement.setAttribute('type', 'checkbox'); - this.checkboxElement.setAttribute('id', `chkbx_${this.id}`); - this.checkboxElement.addEventListener('focus', this.onFocus.bind(this)); - this.checkboxElement.addEventListener('change', this.onChange.bind(this)); - this.container.appendChild(this.label); - this.container.appendChild(this.checkboxElement); - return this.container; - } - getContents() { - return this.checkboxElement.checked; - } - onChange(event) { - this.emit('update', { - type: 'checkbox', - value: this.checkboxElement.checked - }); - } - focus() { - this.checkboxElement.focus(); - } -} +import { BaseItem } from './base-item'; +export class CheckboxItem extends BaseItem { + constructor(id, title) { + super(id, title); + } + getDOMNode() { + this.container = document.createElement('div'); + this.label = document.createElement('label'); + this.label.setAttribute('for', `chkbx_${this.id}`); + this.label.textContent = this.title; + this.checkboxElement = document.createElement('input'); + this.checkboxElement.setAttribute('type', 'checkbox'); + this.checkboxElement.setAttribute('id', `chkbx_${this.id}`); + this.checkboxElement.addEventListener('focus', this.onFocus.bind(this)); + this.checkboxElement.addEventListener('change', this.onChange.bind(this)); + this.container.appendChild(this.label); + this.container.appendChild(this.checkboxElement); + return this.container; + } + getContents() { + return this.checkboxElement.checked; + } + onChange(event) { + this.emit('update', { + type: 'checkbox', + value: this.checkboxElement.checked + }); + } + focus() { + this.checkboxElement.focus(); + } +} diff --git a/src/framework/ui/menu/items/edit-item.d.ts b/src/framework/ui/menu/items/edit-item.d.ts index 2aa90b1..0e539f9 100644 --- a/src/framework/ui/menu/items/edit-item.d.ts +++ b/src/framework/ui/menu/items/edit-item.d.ts @@ -1,13 +1,13 @@ -import { BaseItem } from './base-item'; -export declare class EditItem extends BaseItem { - private initialText; - private isPassword; - private contents; - private label; - private editField; - constructor(id: string, title: string, initialText: string, isPassword?: boolean); - getDOMNode(): HTMLElement; - getContents(): string; - private onChange; - focus(): void; -} +import { BaseItem } from './base-item'; +export declare class EditItem extends BaseItem { + private initialText; + private isPassword; + private contents; + private label; + private editField; + constructor(id: string, title: string, initialText: string, isPassword?: boolean); + getDOMNode(): HTMLElement; + getContents(): string; + private onChange; + focus(): void; +} diff --git a/src/framework/ui/menu/items/edit-item.js b/src/framework/ui/menu/items/edit-item.js index 2954189..6376c46 100644 --- a/src/framework/ui/menu/items/edit-item.js +++ b/src/framework/ui/menu/items/edit-item.js @@ -1,42 +1,42 @@ -import { BaseItem } from './base-item'; -export class EditItem extends BaseItem { - constructor(id, title, initialText, isPassword = false) { - super(id, title); - this.initialText = initialText; - this.isPassword = isPassword; - this.contents = initialText; - } - getDOMNode() { - const node = document.createElement('div'); - const label = document.createElement('label'); - label.setAttribute('for', `edit_${this.id}`); - label.textContent = this.title; - const editField = document.createElement('input'); - editField.id = `edit_${this.id}`; - editField.value = this.contents; - editField.addEventListener('keydown', this.onChange.bind(this)); - editField.addEventListener('focus', this.onFocus.bind(this)); - if (this.isPassword) { - editField.type = 'password'; - } - node.appendChild(label); - node.appendChild(editField); - node.addEventListener('focus', this.onFocus.bind(this)); - this.editField = editField; - this.label = label; - this.container = node; - return node; - } - getContents() { - return this.editField.value; - } - onChange(event) { - this.emit('update', { - type: 'edit', - value: this.editField.value - }); - } - focus() { - this.editField && this.editField.focus(); - } -} +import { BaseItem } from './base-item'; +export class EditItem extends BaseItem { + constructor(id, title, initialText, isPassword = false) { + super(id, title); + this.initialText = initialText; + this.isPassword = isPassword; + this.contents = initialText; + } + getDOMNode() { + const node = document.createElement('div'); + const label = document.createElement('label'); + label.setAttribute('for', `edit_${this.id}`); + label.textContent = this.title; + const editField = document.createElement('input'); + editField.id = `edit_${this.id}`; + editField.value = this.contents; + editField.addEventListener('keydown', this.onChange.bind(this)); + editField.addEventListener('focus', this.onFocus.bind(this)); + if (this.isPassword) { + editField.type = 'password'; + } + node.appendChild(label); + node.appendChild(editField); + node.addEventListener('focus', this.onFocus.bind(this)); + this.editField = editField; + this.label = label; + this.container = node; + return node; + } + getContents() { + return this.editField.value; + } + onChange(event) { + this.emit('update', { + type: 'edit', + value: this.editField.value + }); + } + focus() { + this.editField && this.editField.focus(); + } +} diff --git a/src/framework/ui/menu/items/index.d.ts b/src/framework/ui/menu/items/index.d.ts index ef7e6d9..6f7e42e 100644 --- a/src/framework/ui/menu/items/index.d.ts +++ b/src/framework/ui/menu/items/index.d.ts @@ -1,6 +1,6 @@ -export { BaseItem } from './base-item'; -export { EditItem } from './edit-item'; -export { MenuItem } from './menu-item'; -export { SelectorItem } from './selector-item'; -export { SliderItem } from './slider-item'; -export { CheckboxItem } from './checkbox-item'; +export { BaseItem } from './base-item'; +export { EditItem } from './edit-item'; +export { MenuItem } from './menu-item'; +export { SelectorItem } from './selector-item'; +export { SliderItem } from './slider-item'; +export { CheckboxItem } from './checkbox-item'; diff --git a/src/framework/ui/menu/items/index.js b/src/framework/ui/menu/items/index.js index ef7e6d9..6f7e42e 100644 --- a/src/framework/ui/menu/items/index.js +++ b/src/framework/ui/menu/items/index.js @@ -1,6 +1,6 @@ -export { BaseItem } from './base-item'; -export { EditItem } from './edit-item'; -export { MenuItem } from './menu-item'; -export { SelectorItem } from './selector-item'; -export { SliderItem } from './slider-item'; -export { CheckboxItem } from './checkbox-item'; +export { BaseItem } from './base-item'; +export { EditItem } from './edit-item'; +export { MenuItem } from './menu-item'; +export { SelectorItem } from './selector-item'; +export { SliderItem } from './slider-item'; +export { CheckboxItem } from './checkbox-item'; diff --git a/src/framework/ui/menu/items/menu-item.d.ts b/src/framework/ui/menu/items/menu-item.d.ts index d917d70..2f4345f 100644 --- a/src/framework/ui/menu/items/menu-item.d.ts +++ b/src/framework/ui/menu/items/menu-item.d.ts @@ -1,10 +1,10 @@ -import { BaseItem } from './base-item'; -export declare class MenuItem extends BaseItem { - private button; - constructor(id: string, title: string); - getDOMNode(): HTMLElement; - getContents(): string; - private handleClick; - focus(): void; - click(): void; -} +import { BaseItem } from './base-item'; +export declare class MenuItem extends BaseItem { + private button; + constructor(id: string, title: string); + getDOMNode(): HTMLElement; + getContents(): string; + private handleClick; + focus(): void; + click(): void; +} diff --git a/src/framework/ui/menu/items/menu-item.js b/src/framework/ui/menu/items/menu-item.js index 2463340..a3848e8 100644 --- a/src/framework/ui/menu/items/menu-item.js +++ b/src/framework/ui/menu/items/menu-item.js @@ -1,29 +1,29 @@ -import { BaseItem } from './base-item'; -export class MenuItem extends BaseItem { - constructor(id, title) { - super(id, title); - } - getDOMNode() { - const container = document.createElement('div'); - const button = document.createElement('button'); - button.textContent = this.title; - button.addEventListener('click', this.handleClick.bind(this)); - button.addEventListener('focus', this.onFocus.bind(this)); - container.appendChild(button); - this.container = container; - this.button = button; - return container; - } - getContents() { - return this.id; - } - handleClick(event) { - this.emit('choose', this.id); - } - focus() { - this.button && this.button.focus(); - } - click() { - this.button.click(); - } -} +import { BaseItem } from './base-item'; +export class MenuItem extends BaseItem { + constructor(id, title) { + super(id, title); + } + getDOMNode() { + const container = document.createElement('div'); + const button = document.createElement('button'); + button.textContent = this.title; + button.addEventListener('click', this.handleClick.bind(this)); + button.addEventListener('focus', this.onFocus.bind(this)); + container.appendChild(button); + this.container = container; + this.button = button; + return container; + } + getContents() { + return this.id; + } + handleClick(event) { + this.emit('choose', this.id); + } + focus() { + this.button && this.button.focus(); + } + click() { + this.button.click(); + } +} diff --git a/src/framework/ui/menu/items/selector-item.d.ts b/src/framework/ui/menu/items/selector-item.d.ts index 6c455fb..d88271d 100644 --- a/src/framework/ui/menu/items/selector-item.d.ts +++ b/src/framework/ui/menu/items/selector-item.d.ts @@ -1,21 +1,21 @@ -import { BaseItem } from './base-item'; -export declare class SelectorItem extends BaseItem { - private items; - private listContainer; - private fieldSet; - private label; - private entries; - private currentValue; - constructor(id: string, title: string, items: SelectorEntry[]); - getDOMNode(): HTMLElement; - private buildEntries; - private onItemFocus; - getContents(): any; - private onSelectItem; - private onChangeItem; - focus(): void; -} -export interface SelectorEntry { - id: string; - title: string; -} +import { BaseItem } from './base-item'; +export declare class SelectorItem extends BaseItem { + private items; + private listContainer; + private fieldSet; + private label; + private entries; + private currentValue; + constructor(id: string, title: string, items: SelectorEntry[]); + getDOMNode(): HTMLElement; + private buildEntries; + private onItemFocus; + getContents(): any; + private onSelectItem; + private onChangeItem; + focus(): void; +} +export interface SelectorEntry { + id: string; + title: string; +} diff --git a/src/framework/ui/menu/items/selector-item.js b/src/framework/ui/menu/items/selector-item.js index ce7c1fb..e958501 100644 --- a/src/framework/ui/menu/items/selector-item.js +++ b/src/framework/ui/menu/items/selector-item.js @@ -1,62 +1,62 @@ -import { BaseItem } from './base-item'; -export class SelectorItem extends BaseItem { - constructor(id, title, items) { - super(id, title); - this.items = items; - this.entries = []; - } - getDOMNode() { - this.container = document.createElement('div'); - this.listContainer = document.createElement('ul'); - this.label = document.createElement('legend'); - this.fieldSet = document.createElement('fieldset'); - this.fieldSet.setAttribute('class', 'radiogroup'); - this.fieldSet.id = `fs_selector_${this.id}`; - const name = document.createTextNode(this.title); - this.label.appendChild(name); - this.fieldSet.appendChild(this.label); - this.buildEntries(); - this.container.appendChild(this.fieldSet); - this.container.addEventListener('focus', this.onFocus.bind(this)); - return this.container; - } - buildEntries() { - this.items.forEach((item, index) => { - const node = document.createElement('input'); - node.type = 'radio'; - node.id = `${this.id}_${item.id}`; - node.name = this.id; - node.value = item.id || `${index}`; - node.addEventListener('focus', this.onItemFocus.bind(this)); - node.addEventListener('select', this.onSelectItem.bind(this)); - node.addEventListener('change', this.onChangeItem.bind(this)); - this.entries.push(node); - const label = document.createElement('label'); - label.setAttribute('for', `${this.id}_${item.id}`); - label.textContent = item.title; - this.fieldSet.append(node); - this.fieldSet.append(label); - }); - } - onItemFocus(event) { - console.log(`Item focused: `, event); - this.emit('focus', this.id); - } - getContents() { - return this.currentValue; - } - onSelectItem(event) { } - onChangeItem(event) { - const node = document.querySelector(`input[name = "${this.id}"]:checked`); - this.currentValue = this.items.find((item) => `${this.id}_${item.id}` === node.id); - this.emit('update', { - type: 'selector', - value: this.currentValue - }); - } - focus() { - const node = document.querySelector(`input[name = "${this.id}"]:checked`) || - this.entries[0]; - node.focus(); - } -} +import { BaseItem } from './base-item'; +export class SelectorItem extends BaseItem { + constructor(id, title, items) { + super(id, title); + this.items = items; + this.entries = []; + } + getDOMNode() { + this.container = document.createElement('div'); + this.listContainer = document.createElement('ul'); + this.label = document.createElement('legend'); + this.fieldSet = document.createElement('fieldset'); + this.fieldSet.setAttribute('class', 'radiogroup'); + this.fieldSet.id = `fs_selector_${this.id}`; + const name = document.createTextNode(this.title); + this.label.appendChild(name); + this.fieldSet.appendChild(this.label); + this.buildEntries(); + this.container.appendChild(this.fieldSet); + this.container.addEventListener('focus', this.onFocus.bind(this)); + return this.container; + } + buildEntries() { + this.items.forEach((item, index) => { + const node = document.createElement('input'); + node.type = 'radio'; + node.id = `${this.id}_${item.id}`; + node.name = this.id; + node.value = item.id || `${index}`; + node.addEventListener('focus', this.onItemFocus.bind(this)); + node.addEventListener('select', this.onSelectItem.bind(this)); + node.addEventListener('change', this.onChangeItem.bind(this)); + this.entries.push(node); + const label = document.createElement('label'); + label.setAttribute('for', `${this.id}_${item.id}`); + label.textContent = item.title; + this.fieldSet.append(node); + this.fieldSet.append(label); + }); + } + onItemFocus(event) { + console.log(`Item focused: `, event); + this.emit('focus', this.id); + } + getContents() { + return this.currentValue; + } + onSelectItem(event) { } + onChangeItem(event) { + const node = document.querySelector(`input[name = "${this.id}"]:checked`); + this.currentValue = this.items.find((item) => `${this.id}_${item.id}` === node.id); + this.emit('update', { + type: 'selector', + value: this.currentValue + }); + } + focus() { + const node = document.querySelector(`input[name = "${this.id}"]:checked`) || + this.entries[0]; + node.focus(); + } +} diff --git a/src/framework/ui/menu/items/slider-item.d.ts b/src/framework/ui/menu/items/slider-item.d.ts index 505aa3d..9498c69 100644 --- a/src/framework/ui/menu/items/slider-item.d.ts +++ b/src/framework/ui/menu/items/slider-item.d.ts @@ -1,15 +1,15 @@ -import { BaseItem } from './base-item'; -export declare class SliderItem extends BaseItem { - private min; - private max; - private step; - private defaultValue; - private slider; - private label; - private currentValue; - constructor(id: string, title: string, min: number, max: number, step: number, defaultValue?: number); - getDOMNode(): HTMLElement; - getContents(): string; - private onChange; - focus(): void; -} +import { BaseItem } from './base-item'; +export declare class SliderItem extends BaseItem { + private min; + private max; + private step; + private defaultValue; + private slider; + private label; + private currentValue; + constructor(id: string, title: string, min: number, max: number, step: number, defaultValue?: number); + getDOMNode(): HTMLElement; + getContents(): string; + private onChange; + focus(): void; +} diff --git a/src/framework/ui/menu/items/slider-item.js b/src/framework/ui/menu/items/slider-item.js index 117b39d..9f85da7 100644 --- a/src/framework/ui/menu/items/slider-item.js +++ b/src/framework/ui/menu/items/slider-item.js @@ -1,42 +1,42 @@ -import { BaseItem } from './base-item'; -export class SliderItem extends BaseItem { - constructor(id, title, min, max, step, defaultValue = null) { - super(id, title); - this.min = min; - this.max = max; - this.step = step; - this.defaultValue = defaultValue; - } - getDOMNode() { - this.container = document.createElement('div'); - this.label = document.createElement('label'); - this.label.textContent = this.title; - this.label.setAttribute('for', `slider_${this.id}`); - this.slider = document.createElement('input'); - this.slider.id = `slider_${this.id}`; - this.slider.type = 'range'; - this.slider.setAttribute('min', this.min.toString()); - this.slider.setAttribute('max', this.max.toString()); - this.slider.setAttribute('step', this.step.toString()); - if (this.defaultValue) - this.slider.value = this.defaultValue.toString(); - this.slider.addEventListener('change', this.onChange.bind(this)); - this.slider.addEventListener('focus', this.onFocus.bind(this)); - this.container.appendChild(this.label); - this.container.appendChild(this.slider); - this.container.addEventListener('focus', this.onFocus.bind(this)); - return this.container; - } - getContents() { - return this.slider.value; - } - onChange(event) { - this.emit('update', { - type: 'slider', - value: this.slider.value - }); - } - focus() { - this.slider && this.slider.focus(); - } -} +import { BaseItem } from './base-item'; +export class SliderItem extends BaseItem { + constructor(id, title, min, max, step, defaultValue = null) { + super(id, title); + this.min = min; + this.max = max; + this.step = step; + this.defaultValue = defaultValue; + } + getDOMNode() { + this.container = document.createElement('div'); + this.label = document.createElement('label'); + this.label.textContent = this.title; + this.label.setAttribute('for', `slider_${this.id}`); + this.slider = document.createElement('input'); + this.slider.id = `slider_${this.id}`; + this.slider.type = 'range'; + this.slider.setAttribute('min', this.min.toString()); + this.slider.setAttribute('max', this.max.toString()); + this.slider.setAttribute('step', this.step.toString()); + if (this.defaultValue) + this.slider.value = this.defaultValue.toString(); + this.slider.addEventListener('change', this.onChange.bind(this)); + this.slider.addEventListener('focus', this.onFocus.bind(this)); + this.container.appendChild(this.label); + this.container.appendChild(this.slider); + this.container.addEventListener('focus', this.onFocus.bind(this)); + return this.container; + } + getContents() { + return this.slider.value; + } + onChange(event) { + this.emit('update', { + type: 'slider', + value: this.slider.value + }); + } + focus() { + this.slider && this.slider.focus(); + } +} diff --git a/src/framework/ui/menu/keyboard-manager.d.ts b/src/framework/ui/menu/keyboard-manager.d.ts index daf8e8c..cc01943 100644 --- a/src/framework/ui/menu/keyboard-manager.d.ts +++ b/src/framework/ui/menu/keyboard-manager.d.ts @@ -1,8 +1,8 @@ -import { Menu } from '.'; -export declare class KeyboardManager { - private menu; - constructor(menu: Menu); - init(): void; - private handler; - release(): void; -} +import { Menu } from '.'; +export declare class KeyboardManager { + private menu; + constructor(menu: Menu); + init(): void; + private handler; + release(): void; +} diff --git a/src/framework/ui/menu/keyboard-manager.js b/src/framework/ui/menu/keyboard-manager.js index 048dd0e..de38169 100644 --- a/src/framework/ui/menu/keyboard-manager.js +++ b/src/framework/ui/menu/keyboard-manager.js @@ -1,40 +1,40 @@ -export class KeyboardManager { - constructor(menu) { - this.menu = menu; - } - init() { - this.menu - .getContainer() - .addEventListener('keydown', this.handler.bind(this)); - // This trick let's us detect the press of the back or forward buttons to exit out of the menu. - window.onpopstate = () => this.menu.clickCancelAction(); - } - handler(event) { - switch (event.key) { - case 'ArrowDown': - event.preventDefault(); - this.menu.focusNext(); - break; - case 'ArrowUp': - event.preventDefault(); - this.menu.focusPrevious(); - break; - case 'Enter': - event.preventDefault(); - this.menu.clickDefaultAction(); - break; - case 'Escape': - event.preventDefault(); - this.menu.clickCancelAction(); - break; - default: - break; - } - } - release() { - this.menu - .getContainer() - .removeEventListener('keydown', this.handler.bind(this)); - window.onpopstate = null; - } -} +export class KeyboardManager { + constructor(menu) { + this.menu = menu; + } + init() { + this.menu + .getContainer() + .addEventListener('keydown', this.handler.bind(this)); + // This trick let's us detect the press of the back or forward buttons to exit out of the menu. + window.onpopstate = () => this.menu.clickCancelAction(); + } + handler(event) { + switch (event.key) { + case 'ArrowDown': + event.preventDefault(); + this.menu.focusNext(); + break; + case 'ArrowUp': + event.preventDefault(); + this.menu.focusPrevious(); + break; + case 'Enter': + event.preventDefault(); + this.menu.clickDefaultAction(); + break; + case 'Escape': + event.preventDefault(); + this.menu.clickCancelAction(); + break; + default: + break; + } + } + release() { + this.menu + .getContainer() + .removeEventListener('keydown', this.handler.bind(this)); + window.onpopstate = null; + } +} diff --git a/src/framework/ui/menu/sound-manager.d.ts b/src/framework/ui/menu/sound-manager.d.ts index bbb7e84..18cd6fe 100644 --- a/src/framework/ui/menu/sound-manager.d.ts +++ b/src/framework/ui/menu/sound-manager.d.ts @@ -1,16 +1,16 @@ -import { SoundSet } from './interfaces/sound-set'; -export declare class SoundManager { - private soundSet; - private data; - constructor(soundSet?: SoundSet); - setSoundSet(soundSet: SoundSet): void; - handleSound(type: string, data?: any): void; - private handleEditSound; - private handleSelectorSound; - private handleSliderSound; - private handleFocusSound; - private handleOpenSound; - private handleCloseSound; - private handleChooseSound; - private handleCheckboxSound; -} +import { SoundSet } from './interfaces/sound-set'; +export declare class SoundManager { + private soundSet; + private data; + constructor(soundSet?: SoundSet); + setSoundSet(soundSet: SoundSet): void; + handleSound(type: string, data?: any): void; + private handleEditSound; + private handleSelectorSound; + private handleSliderSound; + private handleFocusSound; + private handleOpenSound; + private handleCloseSound; + private handleChooseSound; + private handleCheckboxSound; +} diff --git a/src/framework/ui/menu/sound-manager.js b/src/framework/ui/menu/sound-manager.js index 77f125f..536f779 100644 --- a/src/framework/ui/menu/sound-manager.js +++ b/src/framework/ui/menu/sound-manager.js @@ -1,84 +1,84 @@ -export class SoundManager { - constructor(soundSet = null) { - this.soundSet = null; - this.data = new Map(); - this.soundSet = soundSet; - } - setSoundSet(soundSet) { - this.soundSet = soundSet; - } - handleSound(type, data = null) { - switch (type) { - case 'edit': - this.handleEditSound(data); - break; - case 'slider': - this.handleSliderSound(data); - break; - case 'selector': - this.handleSelectorSound(data); - break; - case 'checkbox': - this.handleCheckboxSound(data); - break; - case 'focus': - this.handleFocusSound(); - break; - case 'choose': - this.handleChooseSound(); - break; - case 'open': - this.handleOpenSound(); - break; - case 'close': - this.handleCloseSound(); - break; - default: - return; - break; - } - } - handleEditSound(data) { - const prevData = this.data.get('edit') || ''; - if (data.length <= prevData.length) { - this.soundSet.delete && this.soundSet.delete.play(); - } - else { - this.soundSet.char && this.soundSet.char.play(); - } - this.data.set('edit', data); - } - handleSelectorSound(data) { - this.soundSet.scroller && this.soundSet.scroller.play(); - } - handleSliderSound(data) { - const prevData = this.data.get('slider'); - if (data < prevData) { - this.soundSet.sliderLeft && this.soundSet.sliderLeft.play(); - } - else { - this.soundSet.sliderRight && this.soundSet.sliderRight.play(); - } - this.data.set('slider', data); - } - handleFocusSound() { - this.soundSet.move && this.soundSet.move.play(); - } - handleOpenSound() { - this.soundSet.open && this.soundSet.open.play(); - } - handleCloseSound() { - this.soundSet.close && this.soundSet.close.play(); - } - handleChooseSound() { - this.soundSet.choose && this.soundSet.choose.play(); - } - handleCheckboxSound(data) { - if (data === true) { - this.soundSet.checked && this.soundSet.checked.play(); - } - else { - this.soundSet.unchecked && this.soundSet.unchecked.play(); - } - } -} +export class SoundManager { + constructor(soundSet = null) { + this.soundSet = null; + this.data = new Map(); + this.soundSet = soundSet; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + } + handleSound(type, data = null) { + switch (type) { + case 'edit': + this.handleEditSound(data); + break; + case 'slider': + this.handleSliderSound(data); + break; + case 'selector': + this.handleSelectorSound(data); + break; + case 'checkbox': + this.handleCheckboxSound(data); + break; + case 'focus': + this.handleFocusSound(); + break; + case 'choose': + this.handleChooseSound(); + break; + case 'open': + this.handleOpenSound(); + break; + case 'close': + this.handleCloseSound(); + break; + default: + return; + break; + } + } + handleEditSound(data) { + const prevData = this.data.get('edit') || ''; + if (data.length <= prevData.length) { + this.soundSet.delete && this.soundSet.delete.play(); + } + else { + this.soundSet.char && this.soundSet.char.play(); + } + this.data.set('edit', data); + } + handleSelectorSound(data) { + this.soundSet.scroller && this.soundSet.scroller.play(); + } + handleSliderSound(data) { + const prevData = this.data.get('slider'); + if (data < prevData) { + this.soundSet.sliderLeft && this.soundSet.sliderLeft.play(); + } + else { + this.soundSet.sliderRight && this.soundSet.sliderRight.play(); + } + this.data.set('slider', data); + } + handleFocusSound() { + this.soundSet.move && this.soundSet.move.play(); + } + handleOpenSound() { + this.soundSet.open && this.soundSet.open.play(); + } + handleCloseSound() { + this.soundSet.close && this.soundSet.close.play(); + } + handleChooseSound() { + this.soundSet.choose && this.soundSet.choose.play(); + } + handleCheckboxSound(data) { + if (data === true) { + this.soundSet.checked && this.soundSet.checked.play(); + } + else { + this.soundSet.unchecked && this.soundSet.unchecked.play(); + } + } +} diff --git a/src/framework/ui/text/index.d.ts b/src/framework/ui/text/index.d.ts index 89a5db8..768c51d 100644 --- a/src/framework/ui/text/index.d.ts +++ b/src/framework/ui/text/index.d.ts @@ -1,28 +1,28 @@ -import * as EventEmitter from 'eventemitter3'; -import { SoundSet } from '../menu/interfaces/sound-set'; -import { Line } from './line'; -export declare class ScrollingText extends EventEmitter { - private text; - private delimiter; - private soundSet; - private appearingCharacters; - private characterAppearSpeed; - private currentLineIndex; - private currentLine; - private lines; - private wrapper; - private container; - private soundManager; - private keyboardManager; - constructor(text?: string, delimiter?: string, soundSet?: SoundSet, appearingCharacters?: boolean, characterAppearSpeed?: number); - setText(text: string): this; - setSoundSet(soundSet: SoundSet): this; - setDelimiter(delimiter: string): this; - setAppearingCharacters(appearing: boolean): this; - setAppearingCharacterSpeed(speed: number): this; - init(): void; - run(element: HTMLElement): Promise; - displayLine(index: number): Promise; - getContainer(): HTMLElement; - getCurrentLine(): Line; -} +import { EventBus } from '../../event-bus'; +import { SoundSet } from '../menu/interfaces/sound-set'; +import { Line } from './line'; +export declare class ScrollingText extends EventBus { + private text; + private delimiter; + private soundSet; + private appearingCharacters; + private characterAppearSpeed; + private currentLineIndex; + private currentLine; + private lines; + private wrapper; + private container; + private soundManager; + private keyboardManager; + constructor(text?: string, delimiter?: string, soundSet?: SoundSet, appearingCharacters?: boolean, characterAppearSpeed?: number); + setText(text: string): this; + setSoundSet(soundSet: SoundSet): this; + setDelimiter(delimiter: string): this; + setAppearingCharacters(appearing: boolean): this; + setAppearingCharacterSpeed(speed: number): this; + init(): void; + run(element: HTMLElement): Promise; + displayLine(index: number): Promise; + getContainer(): HTMLElement; + getCurrentLine(): Line; +} diff --git a/src/framework/ui/text/index.js b/src/framework/ui/text/index.js index 48dec58..ecbb0b3 100644 --- a/src/framework/ui/text/index.js +++ b/src/framework/ui/text/index.js @@ -1,102 +1,102 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import * as EventEmitter from 'eventemitter3'; -import { Line } from './line'; -import { SoundManager } from './sound-manager'; -import { KeyboardManager } from './keyboard-manager'; -export class ScrollingText extends EventEmitter { - constructor(text = null, delimiter = '\n', soundSet = null, appearingCharacters = false, characterAppearSpeed = 0) { - super(); - this.text = text; - this.delimiter = delimiter; - this.soundSet = soundSet; - this.appearingCharacters = appearingCharacters; - this.characterAppearSpeed = characterAppearSpeed; - this.lines = []; - this.soundManager = new SoundManager(this, this.soundSet); - this.keyboardManager = new KeyboardManager(this); - this.init(); - } - setText(text) { - this.text = text; - this.init(); - return this; - } - setSoundSet(soundSet) { - this.soundSet = soundSet; - this.init(); - this.soundManager.setSoundSet(this.soundSet); - return this; - } - setDelimiter(delimiter) { - this.delimiter = delimiter; - this.init(); - return this; - } - setAppearingCharacters(appearing) { - this.appearingCharacters = appearing; - this.init(); - return this; - } - setAppearingCharacterSpeed(speed) { - this.characterAppearSpeed = speed; - this.init(); - return this; - } - init() { - const split = this.text.split(this.delimiter); - this.lines = split.map((line) => new Line(line)); - } - run(element) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { - this.wrapper = document.createElement('div'); - this.wrapper.setAttribute('aria-role', 'polite'); - this.container = document.createElement('div'); - this.wrapper.appendChild(this.container); - element.appendChild(this.wrapper); - this.soundManager.init(); - this.keyboardManager.init(); - this.emit('open'); - let index = 0; - this.currentLineIndex = 0; - while (index < this.lines.length) { - this.currentLineIndex = index; - yield this.displayLine(index); - index++; - } - this.emit('close'); - this.keyboardManager.release(); - this.container.remove(); - resolve(); - })); - }); - } - displayLine(index) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { - this.container.innerHTML = ''; - this.container.appendChild(this.lines[index].getDOMNode()); - this.lines[index].display(this.container, this.appearingCharacters, this.characterAppearSpeed); - this.lines[index].on('character.appear', (event) => this.emit('character.appear', event)); - this.lines[index].on('advance', () => { - this.emit('advance'); - resolve(); - }); - }); - }); - } - getContainer() { - return this.wrapper; - } - getCurrentLine() { - return this.lines[this.currentLineIndex]; - } -} +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import { EventBus } from '../../event-bus'; +import { Line } from './line'; +import { SoundManager } from './sound-manager'; +import { KeyboardManager } from './keyboard-manager'; +export class ScrollingText extends EventBus { + constructor(text = null, delimiter = '\n', soundSet = null, appearingCharacters = false, characterAppearSpeed = 0) { + super(); + this.text = text; + this.delimiter = delimiter; + this.soundSet = soundSet; + this.appearingCharacters = appearingCharacters; + this.characterAppearSpeed = characterAppearSpeed; + this.lines = []; + this.soundManager = new SoundManager(this, this.soundSet); + this.keyboardManager = new KeyboardManager(this); + this.init(); + } + setText(text) { + this.text = text; + this.init(); + return this; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + this.init(); + this.soundManager.setSoundSet(this.soundSet); + return this; + } + setDelimiter(delimiter) { + this.delimiter = delimiter; + this.init(); + return this; + } + setAppearingCharacters(appearing) { + this.appearingCharacters = appearing; + this.init(); + return this; + } + setAppearingCharacterSpeed(speed) { + this.characterAppearSpeed = speed; + this.init(); + return this; + } + init() { + const split = this.text.split(this.delimiter); + this.lines = split.map((line) => new Line(line)); + } + run(element) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { + this.wrapper = document.createElement('div'); + this.wrapper.setAttribute('aria-role', 'polite'); + this.container = document.createElement('div'); + this.wrapper.appendChild(this.container); + element.appendChild(this.wrapper); + this.soundManager.init(); + this.keyboardManager.init(); + this.emit('open'); + let index = 0; + this.currentLineIndex = 0; + while (index < this.lines.length) { + this.currentLineIndex = index; + yield this.displayLine(index); + index++; + } + this.emit('close'); + this.keyboardManager.release(); + this.container.remove(); + resolve(); + })); + }); + } + displayLine(index) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + this.container.innerHTML = ''; + this.container.appendChild(this.lines[index].getDOMNode()); + this.lines[index].display(this.container, this.appearingCharacters, this.characterAppearSpeed); + this.lines[index].subscribe('character.appear', (event) => this.emit('character.appear', event)); + this.lines[index].subscribe('advance', () => { + this.emit('advance'); + resolve(); + }); + }); + }); + } + getContainer() { + return this.wrapper; + } + getCurrentLine() { + return this.lines[this.currentLineIndex]; + } +} diff --git a/src/framework/ui/text/interfaces/playable-sound.d.ts b/src/framework/ui/text/interfaces/playable-sound.d.ts index 900dad8..34bdc03 100644 --- a/src/framework/ui/text/interfaces/playable-sound.d.ts +++ b/src/framework/ui/text/interfaces/playable-sound.d.ts @@ -1,3 +1,3 @@ -export interface IPlayableSound { - play(): any; -} +export interface IPlayableSound { + play(): any; +} diff --git a/src/framework/ui/text/interfaces/playable-sound.js b/src/framework/ui/text/interfaces/playable-sound.js index cb0ff5c..509db18 100644 --- a/src/framework/ui/text/interfaces/playable-sound.js +++ b/src/framework/ui/text/interfaces/playable-sound.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/ui/text/interfaces/sound-set.d.ts b/src/framework/ui/text/interfaces/sound-set.d.ts index c1c4a45..1a729cd 100644 --- a/src/framework/ui/text/interfaces/sound-set.d.ts +++ b/src/framework/ui/text/interfaces/sound-set.d.ts @@ -1,7 +1,7 @@ -import { IPlayableSound } from './playable-sound'; -export interface SoundSet { - open?: IPlayableSound; - close?: IPlayableSound; - scroll?: IPlayableSound; - characterAppear?: IPlayableSound; -} +import { IPlayableSound } from './playable-sound'; +export interface SoundSet { + open?: IPlayableSound; + close?: IPlayableSound; + scroll?: IPlayableSound; + characterAppear?: IPlayableSound; +} diff --git a/src/framework/ui/text/interfaces/sound-set.js b/src/framework/ui/text/interfaces/sound-set.js index cb0ff5c..509db18 100644 --- a/src/framework/ui/text/interfaces/sound-set.js +++ b/src/framework/ui/text/interfaces/sound-set.js @@ -1 +1 @@ -export {}; +export {}; diff --git a/src/framework/ui/text/keyboard-manager.d.ts b/src/framework/ui/text/keyboard-manager.d.ts index 759f133..829a9ca 100644 --- a/src/framework/ui/text/keyboard-manager.d.ts +++ b/src/framework/ui/text/keyboard-manager.d.ts @@ -1,8 +1,8 @@ -import { ScrollingText } from '.'; -export declare class KeyboardManager { - private scrollingText; - constructor(scrollingText: ScrollingText); - init(): void; - release(): void; - private handler; -} +import { ScrollingText } from '.'; +export declare class KeyboardManager { + private scrollingText; + constructor(scrollingText: ScrollingText); + init(): void; + release(): void; + private handler; +} diff --git a/src/framework/ui/text/keyboard-manager.js b/src/framework/ui/text/keyboard-manager.js index 6fa2127..44c744c 100644 --- a/src/framework/ui/text/keyboard-manager.js +++ b/src/framework/ui/text/keyboard-manager.js @@ -1,25 +1,25 @@ -export class KeyboardManager { - constructor(scrollingText) { - this.scrollingText = scrollingText; - } - init() { - this.scrollingText - .getContainer() - .addEventListener('keydown', (event) => this.handler(event)); - } - release() { - this.scrollingText - .getContainer() - .removeEventListener('keydown', (event) => this.handler(event)); - } - handler(event) { - switch (event.key) { - case 'Enter': - event.preventDefault(); - this.scrollingText.getCurrentLine().getAdvanceButton().click(); - break; - default: - break; - } - } -} +export class KeyboardManager { + constructor(scrollingText) { + this.scrollingText = scrollingText; + } + init() { + this.scrollingText + .getContainer() + .addEventListener('keydown', (event) => this.handler(event)); + } + release() { + this.scrollingText + .getContainer() + .removeEventListener('keydown', (event) => this.handler(event)); + } + handler(event) { + switch (event.key) { + case 'Enter': + event.preventDefault(); + this.scrollingText.getCurrentLine().getAdvanceButton().click(); + break; + default: + break; + } + } +} diff --git a/src/framework/ui/text/line.d.ts b/src/framework/ui/text/line.d.ts index abb6e20..83e501a 100644 --- a/src/framework/ui/text/line.d.ts +++ b/src/framework/ui/text/line.d.ts @@ -1,13 +1,13 @@ -import * as EventEmitter from 'eventemitter3'; -export declare class Line extends EventEmitter { - private text; - private container; - private textField; - private advanceButton; - private active; - constructor(text: string); - getDOMNode(): HTMLElement; - display(element: HTMLElement, appearingCharacters?: boolean, appearingCharacterSpeed?: number): void; - private fillText; - getAdvanceButton(): HTMLElement; -} +import { EventBus } from "../../event-bus"; +export declare class Line extends EventBus { + private text; + private container; + private textField; + private advanceButton; + private active; + constructor(text: string); + getDOMNode(): HTMLElement; + display(element: HTMLElement, appearingCharacters?: boolean, appearingCharacterSpeed?: number): void; + private fillText; + getAdvanceButton(): HTMLElement; +} diff --git a/src/framework/ui/text/line.js b/src/framework/ui/text/line.js index fceff12..ce6bde2 100644 --- a/src/framework/ui/text/line.js +++ b/src/framework/ui/text/line.js @@ -1,45 +1,45 @@ -import * as EventEmitter from 'eventemitter3'; -export class Line extends EventEmitter { - constructor(text) { - super(); - this.text = text; - this.active = false; - } - getDOMNode() { - this.container = document.createElement('div'); - this.container.setAttribute('aria-role', 'polite'); - this.textField = document.createElement('div'); - this.container.appendChild(this.textField); - this.advanceButton = document.createElement('button'); - this.advanceButton.textContent = 'Advance'; - this.advanceButton.addEventListener('click', (event) => { - this.emit('advance'); - this.active = false; - }); - this.container.appendChild(this.advanceButton); - return this.container; - } - display(element, appearingCharacters = false, appearingCharacterSpeed = 0) { - this.active = true; - this.textField.focus(); - if (!appearingCharacters) { - this.textField.textContent = this.text; - } - else { - this.fillText(0, appearingCharacterSpeed); - } - } - fillText(index, speed) { - if (!this.active) - return; - if (index > this.text.length) { - return; - } - this.textField.textContent += this.text.charAt(index); - this.emit('character.appear', this.textField.textContent); - setTimeout(() => this.fillText((index += 1), speed), speed); - } - getAdvanceButton() { - return this.advanceButton; - } -} +import { EventBus } from "../../event-bus"; +export class Line extends EventBus { + constructor(text) { + super(); + this.text = text; + this.active = false; + } + getDOMNode() { + this.container = document.createElement('div'); + this.container.setAttribute('aria-role', 'polite'); + this.textField = document.createElement('div'); + this.container.appendChild(this.textField); + this.advanceButton = document.createElement('button'); + this.advanceButton.textContent = 'Advance'; + this.advanceButton.addEventListener('click', (event) => { + this.emit('advance'); + this.active = false; + }); + this.container.appendChild(this.advanceButton); + return this.container; + } + display(element, appearingCharacters = false, appearingCharacterSpeed = 0) { + this.active = true; + this.textField.focus(); + if (!appearingCharacters) { + this.textField.textContent = this.text; + } + else { + this.fillText(0, appearingCharacterSpeed); + } + } + fillText(index, speed) { + if (!this.active) + return; + if (index > this.text.length) { + return; + } + this.textField.textContent += this.text.charAt(index); + this.emit('character.appear', this.textField.textContent); + setTimeout(() => this.fillText((index += 1), speed), speed); + } + getAdvanceButton() { + return this.advanceButton; + } +} diff --git a/src/framework/ui/text/sound-manager.d.ts b/src/framework/ui/text/sound-manager.d.ts index 1348404..cad51ae 100644 --- a/src/framework/ui/text/sound-manager.d.ts +++ b/src/framework/ui/text/sound-manager.d.ts @@ -1,13 +1,13 @@ -import { SoundSet } from './interfaces/sound-set'; -import { ScrollingText } from '.'; -export declare class SoundManager { - private instance; - private soundSet; - constructor(instance: ScrollingText, soundSet: SoundSet); - setSoundSet(soundSet: SoundSet): void; - init(): void; - private handleOpen; - private handleCharacterAppear; - private handleAdvance; - private handleClose; -} +import { SoundSet } from './interfaces/sound-set'; +import { ScrollingText } from '.'; +export declare class SoundManager { + private instance; + private soundSet; + constructor(instance: ScrollingText, soundSet: SoundSet); + setSoundSet(soundSet: SoundSet): void; + init(): void; + private handleOpen; + private handleCharacterAppear; + private handleAdvance; + private handleClose; +} diff --git a/src/framework/ui/text/sound-manager.js b/src/framework/ui/text/sound-manager.js index 842d74e..3387ce9 100644 --- a/src/framework/ui/text/sound-manager.js +++ b/src/framework/ui/text/sound-manager.js @@ -1,27 +1,27 @@ -export class SoundManager { - constructor(instance, soundSet) { - this.instance = instance; - this.soundSet = soundSet; - } - setSoundSet(soundSet) { - this.soundSet = soundSet; - } - init() { - this.instance.on('character.appear', this.handleCharacterAppear.bind(this)); - this.instance.on('open', this.handleOpen.bind(this)); - this.instance.on('close', this.handleClose.bind(this)); - this.instance.on('advance', this.handleAdvance.bind(this)); - } - handleOpen() { - this.soundSet.open && this.soundSet.open.play(); - } - handleCharacterAppear() { - this.soundSet.characterAppear && this.soundSet.characterAppear.play(); - } - handleAdvance() { - this.soundSet.scroll && this.soundSet.scroll.play(); - } - handleClose() { - this.soundSet.close && this.soundSet.close.play(); - } -} +export class SoundManager { + constructor(instance, soundSet) { + this.instance = instance; + this.soundSet = soundSet; + } + setSoundSet(soundSet) { + this.soundSet = soundSet; + } + init() { + this.instance.subscribe('character.appear', this.handleCharacterAppear.bind(this)); + this.instance.subscribe('open', this.handleOpen.bind(this)); + this.instance.subscribe('close', this.handleClose.bind(this)); + this.instance.subscribe('advance', this.handleAdvance.bind(this)); + } + handleOpen() { + this.soundSet.open && this.soundSet.open.play(); + } + handleCharacterAppear() { + this.soundSet.characterAppear && this.soundSet.characterAppear.play(); + } + handleAdvance() { + this.soundSet.scroll && this.soundSet.scroll.play(); + } + handleClose() { + this.soundSet.close && this.soundSet.close.play(); + } +} diff --git a/src/framework/world/index.d.ts b/src/framework/world/index.d.ts index 27b60d3..f3674d0 100644 --- a/src/framework/world/index.d.ts +++ b/src/framework/world/index.d.ts @@ -1,3 +1,5 @@ -export interface World { - update(dt: number): any; -} +export declare class World { + private physics; + constructor(); + update(dt: number): void; +} diff --git a/src/framework/world/index.js b/src/framework/world/index.js index cb0ff5c..2c964e8 100644 --- a/src/framework/world/index.js +++ b/src/framework/world/index.js @@ -1 +1,6 @@ -export {}; +export class World { + constructor() { + } + update(dt) { + } +} diff --git a/src/game/commands/meow.js b/src/game/commands/meow.js index 9016ad9..c78513c 100644 --- a/src/game/commands/meow.js +++ b/src/game/commands/meow.js @@ -1,3 +1,3 @@ -export default async function MeowCommand(args, context) { - context.print(`You meow.`); +export default async function MeowCommand(args, context) { + context.print(`You meow.`); } \ No newline at end of file