From 86548b6057718bc9abc1ccc63fd82bd447c0a160 Mon Sep 17 00:00:00 2001 From: Renge Date: Mon, 23 May 2022 06:00:37 -0400 Subject: [PATCH] init repo --- hw1/README.md | 17 + hw1/concentration_multi.cpp | 224 + hw3/.gitignore | 18 + hw3/dist/builtin/shaders/label.fshader | 77 + hw3/dist/builtin/shaders/label.vshader | 12 + hw3/dist/builtin/shaders/point.fshader | 7 + hw3/dist/builtin/shaders/point.vshader | 8 + hw3/dist/builtin/shaders/rect.fshader | 7 + hw3/dist/builtin/shaders/rect.vshader | 7 + hw3/dist/builtin/shaders/sprite.fshader | 9 + hw3/dist/builtin/shaders/sprite.vshader | 13 + .../images/platformer_background.png | Bin 0 -> 4787 bytes hw3/dist/demo_assets/images/wolfie2d_text.png | Bin 0 -> 701 bytes hw3/dist/demo_assets/sounds/jump.wav | Bin 0 -> 22413 bytes hw3/dist/demo_assets/sounds/title.mp3 | Bin 0 -> 1030269 bytes .../spritesheets/platformer/player.json | 27 + .../spritesheets/platformer/player.png | Bin 0 -> 268 bytes .../tilemaps/platformer/platformer.json | 453 + .../tilemaps/platformer/platformer.png | Bin 0 -> 1696 bytes .../shaders/gradient_circle.fshader | 25 + .../shaders/gradient_circle.vshader | 11 + .../shaders/linear_gradient_circle.fshader | 33 + .../shaders/linear_gradient_circle.vshader | 11 + hw3/dist/hw3_assets/sprites/road.jpg | Bin 0 -> 41845 bytes hw3/dist/hw3_assets/sprites/stone.png | Bin 0 -> 4696 bytes hw3/dist/hw3_assets/spritesheets/car.json | 139 + hw3/dist/hw3_assets/spritesheets/cars.json | 139 + hw3/dist/hw3_assets/spritesheets/cars.png | Bin 0 -> 33483 bytes hw3/gulpfile.js | 34 + hw3/package-lock.json | 9236 +++++++++++++++++ hw3/package.json | 21 + hw3/readme.md | 6 + hw3/src/Wolfie2D/AI/AIManager.ts | 65 + hw3/src/Wolfie2D/AI/ControllerAI.ts | 21 + hw3/src/Wolfie2D/AI/StateMachineAI.ts | 24 + hw3/src/Wolfie2D/DataTypes/Collection.ts | 17 + .../Wolfie2D/DataTypes/Functions/NullFunc.ts | 8 + hw3/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts | 22 + hw3/src/Wolfie2D/DataTypes/Graphs/Graph.ts | 145 + .../DataTypes/Graphs/PositionGraph.ts | 94 + hw3/src/Wolfie2D/DataTypes/Interfaces/AI.ts | 20 + .../Wolfie2D/DataTypes/Interfaces/Actor.ts | 40 + .../DataTypes/Interfaces/DebugRenderable.ts | 7 + .../DataTypes/Interfaces/Navigable.ts | 12 + .../Wolfie2D/DataTypes/Interfaces/Physical.ts | 120 + .../DataTypes/Interfaces/Positioned.ts | 10 + .../Wolfie2D/DataTypes/Interfaces/Region.ts | 21 + .../Wolfie2D/DataTypes/Interfaces/Unique.ts | 7 + .../DataTypes/Interfaces/Updateable.ts | 8 + hw3/src/Wolfie2D/DataTypes/List.ts | 63 + hw3/src/Wolfie2D/DataTypes/Map.ts | 87 + hw3/src/Wolfie2D/DataTypes/Mat4x4.ts | 167 + .../DataTypes/Physics/AreaCollision.ts | 40 + hw3/src/Wolfie2D/DataTypes/Physics/Hit.ts | 18 + hw3/src/Wolfie2D/DataTypes/QuadTree.ts | 156 + hw3/src/Wolfie2D/DataTypes/Queue.ts | 130 + hw3/src/Wolfie2D/DataTypes/RegionQuadTree.ts | 271 + .../DataTypes/Rendering/WebGLGameTexture.ts | 5 + .../DataTypes/Rendering/WebGLProgramType.ts | 29 + hw3/src/Wolfie2D/DataTypes/Shapes/AABB.ts | 339 + hw3/src/Wolfie2D/DataTypes/Shapes/Circle.ts | 76 + hw3/src/Wolfie2D/DataTypes/Shapes/Shape.ts | 169 + hw3/src/Wolfie2D/DataTypes/Spritesheet.ts | 22 + hw3/src/Wolfie2D/DataTypes/Stack.ts | 108 + hw3/src/Wolfie2D/DataTypes/State/State.ts | 54 + .../Wolfie2D/DataTypes/State/StateMachine.ts | 137 + .../Wolfie2D/DataTypes/Tilesets/TiledData.ts | 78 + .../Wolfie2D/DataTypes/Tilesets/Tileset.ts | 146 + hw3/src/Wolfie2D/DataTypes/Vec2.ts | 432 + hw3/src/Wolfie2D/Debug/Debug.ts | 197 + hw3/src/Wolfie2D/Debug/Stats.ts | 244 + hw3/src/Wolfie2D/Events/Emitter.ts | 26 + hw3/src/Wolfie2D/Events/EventQueue.ts | 125 + hw3/src/Wolfie2D/Events/GameEvent.ts | 54 + hw3/src/Wolfie2D/Events/GameEventType.ts | 91 + hw3/src/Wolfie2D/Events/Receiver.ts | 77 + hw3/src/Wolfie2D/Input/Input.ts | 322 + hw3/src/Wolfie2D/Input/InputHandler.ts | 93 + .../Wolfie2D/Loop/EnvironmentInitializer.ts | 47 + hw3/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts | 235 + hw3/src/Wolfie2D/Loop/Game.ts | 214 + hw3/src/Wolfie2D/Loop/GameLoop.ts | 69 + hw3/src/Wolfie2D/Loop/GameOptions.ts | 44 + hw3/src/Wolfie2D/Nodes/CanvasNode.ts | 137 + hw3/src/Wolfie2D/Nodes/GameNode.ts | 478 + hw3/src/Wolfie2D/Nodes/Graphic.ts | 32 + .../Wolfie2D/Nodes/Graphics/GraphicTypes.ts | 5 + hw3/src/Wolfie2D/Nodes/Graphics/Line.ts | 33 + hw3/src/Wolfie2D/Nodes/Graphics/Point.ts | 12 + hw3/src/Wolfie2D/Nodes/Graphics/Rect.ts | 46 + .../Wolfie2D/Nodes/Sprites/AnimatedSprite.ts | 49 + hw3/src/Wolfie2D/Nodes/Sprites/Sprite.ts | 35 + hw3/src/Wolfie2D/Nodes/Tilemap.ts | 119 + .../Nodes/Tilemaps/OrthogonalTilemap.ts | 190 + hw3/src/Wolfie2D/Nodes/UIElement.ts | 149 + hw3/src/Wolfie2D/Nodes/UIElements/Button.ts | 27 + hw3/src/Wolfie2D/Nodes/UIElements/Label.ts | 152 + hw3/src/Wolfie2D/Nodes/UIElements/Slider.ts | 64 + .../Wolfie2D/Nodes/UIElements/TextInput.ts | 64 + .../Nodes/UIElements/UIElementTypes.ts | 6 + .../Wolfie2D/Pathfinding/NavigationManager.ts | 39 + .../Wolfie2D/Pathfinding/NavigationPath.ts | 58 + hw3/src/Wolfie2D/Pathfinding/Navmesh.ts | 67 + .../Wolfie2D/Physics/BasicPhysicsManager.ts | 349 + hw3/src/Wolfie2D/Physics/PhysicsManager.ts | 112 + hw3/src/Wolfie2D/Playback/Recorder.ts | 93 + .../Registry/Registries/FontRegistry.ts | 0 .../Wolfie2D/Registry/Registries/Registry.ts | 21 + .../Registry/Registries/ShaderRegistry.ts | 99 + hw3/src/Wolfie2D/Registry/RegistryManager.ts | 31 + .../Rendering/Animations/AnimationManager.ts | 228 + .../Rendering/Animations/AnimationTypes.ts | 65 + .../Rendering/Animations/TweenController.ts | 213 + .../Rendering/Animations/TweenManager.ts | 40 + hw3/src/Wolfie2D/Rendering/CanvasRenderer.ts | 255 + .../CanvasRendering/GraphicRenderer.ts | 72 + .../CanvasRendering/TilemapRenderer.ts | 151 + .../CanvasRendering/UIElementRenderer.ts | 126 + .../Wolfie2D/Rendering/RenderingManager.ts | 85 + hw3/src/Wolfie2D/Rendering/WebGLRenderer.ts | 182 + .../Rendering/WebGLRendering/ShaderType.ts | 44 + .../ShaderTypes/LabelShaderType.ts | 122 + .../ShaderTypes/PointShaderType.ts | 61 + .../ShaderTypes/QuadShaderType.ts | 25 + .../ShaderTypes/RectShaderType.ts | 133 + .../ShaderTypes/SpriteShaderType.ts | 138 + .../ResourceManager/ResourceManager.ts | 1035 ++ .../Scene/Factories/CanvasNodeFactory.ts | 239 + .../Scene/Factories/FactoryManager.ts | 81 + .../Scene/Factories/TilemapFactory.ts | 232 + hw3/src/Wolfie2D/Scene/Layer.ts | 184 + .../Wolfie2D/Scene/Layers/ParallaxLayer.ts | 23 + hw3/src/Wolfie2D/Scene/Layers/UILayer.ts | 20 + hw3/src/Wolfie2D/Scene/Scene.ts | 444 + hw3/src/Wolfie2D/Scene/SceneManager.ts | 125 + hw3/src/Wolfie2D/Scene/SceneOptions.ts | 25 + hw3/src/Wolfie2D/SceneGraph/SceneGraph.ts | 131 + .../Wolfie2D/SceneGraph/SceneGraphArray.ts | 93 + .../Wolfie2D/SceneGraph/SceneGraphQuadTree.ts | 98 + hw3/src/Wolfie2D/SceneGraph/Viewport.ts | 286 + hw3/src/Wolfie2D/Sound/AudioManager.ts | 244 + hw3/src/Wolfie2D/Timing/Timer.ts | 108 + hw3/src/Wolfie2D/Timing/TimerManager.ts | 33 + hw3/src/Wolfie2D/Utils/ArrayUtils.ts | 43 + hw3/src/Wolfie2D/Utils/Color.ts | 197 + hw3/src/Wolfie2D/Utils/EaseFunctions.ts | 55 + hw3/src/Wolfie2D/Utils/GraphUtils.ts | 64 + hw3/src/Wolfie2D/Utils/MathUtils.ts | 175 + hw3/src/Wolfie2D/Utils/MemoryUtils.ts | 46 + hw3/src/Wolfie2D/Utils/Rand/Perlin.ts | 126 + hw3/src/Wolfie2D/Utils/RandUtils.ts | 64 + hw3/src/Wolfie2D/Utils/RenderingUtils.ts | 28 + hw3/src/Wolfie2D/Utils/SortingUtils.ts | 37 + hw3/src/Wolfie2D/Utils/StringUtils.ts | 14 + hw3/src/Wolfie2D/_Demos/readme.md | 2 + hw3/src/default_main.ts | 23 + hw3/src/default_scene.ts | 98 + hw3/src/demos/AudioDemo.ts | 71 + hw3/src/demos/Platformer.ts | 49 + hw3/src/demos/PlatformerPlayerController.ts | 62 + hw3/src/hw3/AI/BulletAI.ts | 72 + hw3/src/hw3/AI/CarPlayerController.ts | 110 + hw3/src/hw3/AI/RockAI.ts | 39 + hw3/src/hw3/GradientCircleShaderType.ts | 80 + hw3/src/hw3/HW3_Enums.ts | 23 + hw3/src/hw3/LinearGradientCircleShaderType.ts | 109 + hw3/src/hw3/Scenes/GameOver.ts | 41 + hw3/src/hw3/Scenes/HW3_Scene.ts | 692 ++ hw3/src/hw3/Scenes/MainMenu.ts | 133 + hw3/src/index.d.ts | 22 + hw3/src/index.html | 71 + hw3/src/main.ts | 117 + hw3/tsconfig.json | 10 + hw4/.gitignore | 18 + hw4/dist/builtin/shaders/label.fshader | 77 + hw4/dist/builtin/shaders/label.vshader | 12 + hw4/dist/builtin/shaders/point.fshader | 7 + hw4/dist/builtin/shaders/point.vshader | 8 + hw4/dist/builtin/shaders/rect.fshader | 7 + hw4/dist/builtin/shaders/rect.vshader | 7 + hw4/dist/builtin/shaders/sprite.fshader | 9 + hw4/dist/builtin/shaders/sprite.vshader | 13 + .../images/platformer_background.png | Bin 0 -> 4787 bytes hw4/dist/demo_assets/images/wolfie2d_text.png | Bin 0 -> 701 bytes hw4/dist/demo_assets/sounds/jump.wav | Bin 0 -> 22413 bytes hw4/dist/demo_assets/sounds/title.mp3 | Bin 0 -> 1030269 bytes .../spritesheets/platformer/player.json | 27 + .../spritesheets/platformer/player.png | Bin 0 -> 268 bytes .../tilemaps/platformer/platformer.json | 453 + .../tilemaps/platformer/platformer.png | Bin 0 -> 1696 bytes hw4/dist/hw4_assets/data/enemy.json | 145 + hw4/dist/hw4_assets/data/items.json | 78 + hw4/dist/hw4_assets/data/navmesh.json | 60 + hw4/dist/hw4_assets/data/weaponData.json | 45 + hw4/dist/hw4_assets/sprites/healthpack.png | Bin 0 -> 177 bytes hw4/dist/hw4_assets/sprites/inventory.png | Bin 0 -> 203 bytes hw4/dist/hw4_assets/sprites/knife.png | Bin 0 -> 211 bytes hw4/dist/hw4_assets/sprites/laserGun.png | Bin 0 -> 249 bytes hw4/dist/hw4_assets/sprites/pistol.png | Bin 0 -> 134 bytes .../spritesheets/custom_enemy1.json | 19 + .../hw4_assets/spritesheets/custom_enemy1.png | Bin 0 -> 477 bytes .../spritesheets/custom_enemy2.json | 19 + .../hw4_assets/spritesheets/custom_enemy2.png | Bin 0 -> 477 bytes .../hw4_assets/spritesheets/gun_enemy.json | 19 + .../hw4_assets/spritesheets/gun_enemy.png | Bin 0 -> 480 bytes .../hw4_assets/spritesheets/knife_enemy.json | 19 + .../hw4_assets/spritesheets/knife_enemy.png | Bin 0 -> 477 bytes hw4/dist/hw4_assets/spritesheets/player1.json | 19 + hw4/dist/hw4_assets/spritesheets/player1.png | Bin 0 -> 505 bytes hw4/dist/hw4_assets/spritesheets/player2.json | 19 + hw4/dist/hw4_assets/spritesheets/player2.png | Bin 0 -> 564 bytes hw4/dist/hw4_assets/spritesheets/slice.json | 19 + hw4/dist/hw4_assets/spritesheets/slice.png | Bin 0 -> 208 bytes hw4/dist/hw4_assets/tilemaps/TopDown_hw4.json | 65 + hw4/dist/hw4_assets/tilemaps/cse380_hw4.png | Bin 0 -> 15867 bytes .../tilemaps/cse380_hw4_tilejson.json | 86 + .../hw4_assets/tilemaps/cse380_hw4_tiles.png | Bin 0 -> 1821 bytes .../hw4_assets/tilemaps/cse380_hw4_tiles2.png | Bin 0 -> 1890 bytes hw4/dist/hw4_assets/tilemaps/top-down-hw4.png | Bin 0 -> 1648 bytes hw4/gulpfile.js | 34 + hw4/package-lock.json | 9236 +++++++++++++++++ hw4/package.json | 21 + hw4/readme.md | 6 + hw4/src/Wolfie2D/AI/AIManager.ts | 66 + hw4/src/Wolfie2D/AI/ControllerAI.ts | 22 + hw4/src/Wolfie2D/AI/GoapActionPlanner.ts | 82 + hw4/src/Wolfie2D/AI/StateMachineAI.ts | 24 + hw4/src/Wolfie2D/AI/StateMachineGoapAI.ts | 40 + hw4/src/Wolfie2D/DataTypes/Collection.ts | 17 + .../Wolfie2D/DataTypes/Functions/NullFunc.ts | 8 + hw4/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts | 22 + hw4/src/Wolfie2D/DataTypes/Graphs/Graph.ts | 145 + .../DataTypes/Graphs/PositionGraph.ts | 94 + hw4/src/Wolfie2D/DataTypes/Interfaces/AI.ts | 20 + .../Wolfie2D/DataTypes/Interfaces/Actor.ts | 42 + .../DataTypes/Interfaces/DebugRenderable.ts | 7 + .../Wolfie2D/DataTypes/Interfaces/GoapAI.ts | 42 + .../DataTypes/Interfaces/GoapAction.ts | 61 + .../DataTypes/Interfaces/Navigable.ts | 13 + .../Wolfie2D/DataTypes/Interfaces/Physical.ts | 120 + .../DataTypes/Interfaces/Positioned.ts | 10 + .../Wolfie2D/DataTypes/Interfaces/Region.ts | 21 + .../Wolfie2D/DataTypes/Interfaces/Unique.ts | 7 + .../DataTypes/Interfaces/Updateable.ts | 8 + hw4/src/Wolfie2D/DataTypes/List.ts | 63 + hw4/src/Wolfie2D/DataTypes/Map.ts | 87 + hw4/src/Wolfie2D/DataTypes/Mat4x4.ts | 167 + .../DataTypes/Physics/AreaCollision.ts | 40 + hw4/src/Wolfie2D/DataTypes/Physics/Hit.ts | 18 + hw4/src/Wolfie2D/DataTypes/QuadTree.ts | 156 + hw4/src/Wolfie2D/DataTypes/Queue.ts | 130 + hw4/src/Wolfie2D/DataTypes/RegionQuadTree.ts | 271 + .../DataTypes/Rendering/WebGLGameTexture.ts | 5 + .../DataTypes/Rendering/WebGLProgramType.ts | 29 + hw4/src/Wolfie2D/DataTypes/Shapes/AABB.ts | 339 + hw4/src/Wolfie2D/DataTypes/Shapes/Circle.ts | 76 + hw4/src/Wolfie2D/DataTypes/Shapes/Shape.ts | 169 + hw4/src/Wolfie2D/DataTypes/Spritesheet.ts | 22 + hw4/src/Wolfie2D/DataTypes/Stack.ts | 108 + hw4/src/Wolfie2D/DataTypes/State/State.ts | 54 + .../Wolfie2D/DataTypes/State/StateMachine.ts | 137 + .../Wolfie2D/DataTypes/Tilesets/TiledData.ts | 78 + .../Wolfie2D/DataTypes/Tilesets/Tileset.ts | 146 + hw4/src/Wolfie2D/DataTypes/Vec2.ts | 432 + hw4/src/Wolfie2D/Debug/Debug.ts | 197 + hw4/src/Wolfie2D/Debug/Stats.ts | 244 + hw4/src/Wolfie2D/Events/BattleSystem.ts | 38 + hw4/src/Wolfie2D/Events/Emitter.ts | 26 + hw4/src/Wolfie2D/Events/EventQueue.ts | 125 + hw4/src/Wolfie2D/Events/GameEvent.ts | 54 + hw4/src/Wolfie2D/Events/GameEventType.ts | 91 + hw4/src/Wolfie2D/Events/Receiver.ts | 77 + hw4/src/Wolfie2D/Input/Input.ts | 334 + hw4/src/Wolfie2D/Input/InputHandler.ts | 94 + .../Wolfie2D/Loop/EnvironmentInitializer.ts | 47 + hw4/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts | 235 + hw4/src/Wolfie2D/Loop/Game.ts | 214 + hw4/src/Wolfie2D/Loop/GameLoop.ts | 69 + hw4/src/Wolfie2D/Loop/GameOptions.ts | 44 + hw4/src/Wolfie2D/Nodes/CanvasNode.ts | 137 + hw4/src/Wolfie2D/Nodes/GameNode.ts | 480 + hw4/src/Wolfie2D/Nodes/Graphic.ts | 56 + .../Wolfie2D/Nodes/Graphics/GraphicTypes.ts | 6 + hw4/src/Wolfie2D/Nodes/Graphics/Line.ts | 33 + hw4/src/Wolfie2D/Nodes/Graphics/Particle.ts | 57 + hw4/src/Wolfie2D/Nodes/Graphics/Point.ts | 13 + hw4/src/Wolfie2D/Nodes/Graphics/Rect.ts | 46 + .../Wolfie2D/Nodes/Sprites/AnimatedSprite.ts | 49 + hw4/src/Wolfie2D/Nodes/Sprites/Sprite.ts | 35 + hw4/src/Wolfie2D/Nodes/Tilemap.ts | 119 + .../Nodes/Tilemaps/OrthogonalTilemap.ts | 190 + hw4/src/Wolfie2D/Nodes/UIElement.ts | 149 + hw4/src/Wolfie2D/Nodes/UIElements/Button.ts | 27 + hw4/src/Wolfie2D/Nodes/UIElements/Label.ts | 152 + hw4/src/Wolfie2D/Nodes/UIElements/Slider.ts | 64 + .../Wolfie2D/Nodes/UIElements/TextInput.ts | 64 + .../Nodes/UIElements/UIElementTypes.ts | 6 + .../Wolfie2D/Pathfinding/NavigationManager.ts | 40 + .../Wolfie2D/Pathfinding/NavigationPath.ts | 58 + hw4/src/Wolfie2D/Pathfinding/Navmesh.ts | 72 + .../Wolfie2D/Physics/BasicPhysicsManager.ts | 349 + hw4/src/Wolfie2D/Physics/PhysicsManager.ts | 112 + hw4/src/Wolfie2D/Playback/Recorder.ts | 93 + .../Registry/Registries/FontRegistry.ts | 0 .../Wolfie2D/Registry/Registries/Registry.ts | 22 + .../Registry/Registries/ShaderRegistry.ts | 99 + hw4/src/Wolfie2D/Registry/RegistryManager.ts | 31 + .../Rendering/Animations/AnimationManager.ts | 228 + .../Rendering/Animations/AnimationTypes.ts | 65 + .../Rendering/Animations/ParticleSystem.ts | 163 + .../Animations/ParticleSystemManager.ts | 40 + .../Rendering/Animations/TweenController.ts | 213 + .../Rendering/Animations/TweenManager.ts | 40 + hw4/src/Wolfie2D/Rendering/CanvasRenderer.ts | 255 + .../CanvasRendering/GraphicRenderer.ts | 72 + .../CanvasRendering/TilemapRenderer.ts | 151 + .../CanvasRendering/UIElementRenderer.ts | 126 + .../Wolfie2D/Rendering/RenderingManager.ts | 85 + hw4/src/Wolfie2D/Rendering/WebGLRenderer.ts | 182 + .../Rendering/WebGLRendering/ShaderType.ts | 44 + .../ShaderTypes/LabelShaderType.ts | 123 + .../ShaderTypes/PointShaderType.ts | 61 + .../ShaderTypes/QuadShaderType.ts | 25 + .../ShaderTypes/RectShaderType.ts | 134 + .../ShaderTypes/SpriteShaderType.ts | 138 + .../ResourceManager/ResourceManager.ts | 1035 ++ .../Scene/Factories/CanvasNodeFactory.ts | 252 + .../Scene/Factories/FactoryManager.ts | 81 + .../Scene/Factories/TilemapFactory.ts | 232 + hw4/src/Wolfie2D/Scene/Layer.ts | 184 + .../Wolfie2D/Scene/Layers/ParallaxLayer.ts | 23 + hw4/src/Wolfie2D/Scene/Layers/UILayer.ts | 20 + hw4/src/Wolfie2D/Scene/Scene.ts | 448 + hw4/src/Wolfie2D/Scene/SceneManager.ts | 125 + hw4/src/Wolfie2D/Scene/SceneOptions.ts | 25 + hw4/src/Wolfie2D/SceneGraph/SceneGraph.ts | 131 + .../Wolfie2D/SceneGraph/SceneGraphArray.ts | 93 + .../Wolfie2D/SceneGraph/SceneGraphQuadTree.ts | 98 + hw4/src/Wolfie2D/SceneGraph/Viewport.ts | 286 + hw4/src/Wolfie2D/Sound/AudioManager.ts | 244 + hw4/src/Wolfie2D/Timing/Timer.ts | 109 + hw4/src/Wolfie2D/Timing/TimerManager.ts | 33 + hw4/src/Wolfie2D/Utils/ArrayUtils.ts | 43 + hw4/src/Wolfie2D/Utils/Color.ts | 197 + hw4/src/Wolfie2D/Utils/EaseFunctions.ts | 55 + hw4/src/Wolfie2D/Utils/GraphUtils.ts | 64 + hw4/src/Wolfie2D/Utils/MathUtils.ts | 175 + hw4/src/Wolfie2D/Utils/MemoryUtils.ts | 47 + hw4/src/Wolfie2D/Utils/Rand/Perlin.ts | 126 + hw4/src/Wolfie2D/Utils/RandUtils.ts | 64 + hw4/src/Wolfie2D/Utils/RenderingUtils.ts | 28 + hw4/src/Wolfie2D/Utils/SortingUtils.ts | 37 + hw4/src/Wolfie2D/Utils/StringUtils.ts | 14 + hw4/src/Wolfie2D/_Demos/readme.md | 2 + hw4/src/default_main.ts | 23 + hw4/src/default_scene.ts | 98 + hw4/src/demos/AudioDemo.ts | 71 + hw4/src/demos/Platformer.ts | 49 + hw4/src/demos/PlatformerPlayerController.ts | 62 + hw4/src/hw4/AI/BattlerAI.ts | 11 + hw4/src/hw4/AI/EnemyAI.ts | 217 + hw4/src/hw4/AI/EnemyActions/AttackAction.ts | 47 + hw4/src/hw4/AI/EnemyActions/Berserk.ts | 41 + hw4/src/hw4/AI/EnemyActions/Move.ts | 50 + hw4/src/hw4/AI/EnemyActions/Retreat.ts | 63 + hw4/src/hw4/AI/EnemyStates/Active.ts | 138 + hw4/src/hw4/AI/EnemyStates/Alert.ts | 56 + hw4/src/hw4/AI/EnemyStates/EnemyState.ts | 13 + hw4/src/hw4/AI/EnemyStates/Guard.ts | 62 + hw4/src/hw4/AI/EnemyStates/Patrol.ts | 63 + hw4/src/hw4/AI/PlayerController.ts | 158 + hw4/src/hw4/GameSystems/BattleManager.ts | 35 + hw4/src/hw4/GameSystems/InventoryManager.ts | 112 + hw4/src/hw4/GameSystems/items/Healthpack.ts | 10 + hw4/src/hw4/GameSystems/items/Item.ts | 28 + hw4/src/hw4/GameSystems/items/Weapon.ts | 77 + .../GameSystems/items/WeaponTypes/LaserGun.ts | 102 + .../items/WeaponTypes/SemiAutoGun.ts | 102 + .../items/WeaponTypes/SingleShot.ts | 4 + .../GameSystems/items/WeaponTypes/Slice.ts | 45 + .../items/WeaponTypes/WeaponType.ts | 35 + hw4/src/hw4/Registry/WeaponRegistry.ts | 35 + hw4/src/hw4/Registry/WeaponTypeRegistry.ts | 14 + hw4/src/hw4/Scenes/GameOver.ts | 18 + hw4/src/hw4/Scenes/MainMenu.ts | 149 + hw4/src/hw4/Scenes/hw4_scene.ts | 689 ++ hw4/src/hw4/hw4_constants.ts | 17 + hw4/src/index.d.ts | 22 + hw4/src/index.html | 71 + hw4/src/main.ts | 48 + hw4/tsconfig.json | 10 + hw5/.gitignore | 18 + hw5/dist/builtin/shaders/label.fshader | 77 + hw5/dist/builtin/shaders/label.vshader | 12 + hw5/dist/builtin/shaders/point.fshader | 7 + hw5/dist/builtin/shaders/point.vshader | 8 + hw5/dist/builtin/shaders/rect.fshader | 7 + hw5/dist/builtin/shaders/rect.vshader | 7 + hw5/dist/builtin/shaders/sprite.fshader | 9 + hw5/dist/builtin/shaders/sprite.vshader | 13 + .../images/platformer_background.png | Bin 0 -> 4787 bytes hw5/dist/demo_assets/images/wolfie2d_text.png | Bin 0 -> 701 bytes hw5/dist/demo_assets/sounds/jump.wav | Bin 0 -> 22413 bytes hw5/dist/demo_assets/sounds/title.mp3 | Bin 0 -> 1030269 bytes .../spritesheets/platformer/player.json | 27 + .../spritesheets/platformer/player.png | Bin 0 -> 268 bytes .../tilemaps/platformer/platformer.json | 453 + .../tilemaps/platformer/platformer.png | Bin 0 -> 1696 bytes hw5/dist/hw5_assets/fonts/PixelSimple.ttf | Bin 0 -> 9876 bytes hw5/dist/hw5_assets/music/menu.mp3 | Bin 0 -> 1030269 bytes hw5/dist/hw5_assets/music/pop.ogg | Bin 0 -> 6050 bytes hw5/dist/hw5_assets/music/sound.wav | Bin 0 -> 116784 bytes hw5/dist/hw5_assets/sounds/jump.wav | Bin 0 -> 31789 bytes hw5/dist/hw5_assets/sounds/player_death.wav | Bin 0 -> 71533 bytes hw5/dist/hw5_assets/sounds/switch.wav | Bin 0 -> 47686 bytes .../hw5_assets/spritesheets/blueBalloon.json | 26 + .../hw5_assets/spritesheets/blueBalloon.png | Bin 0 -> 709 bytes .../hw5_assets/spritesheets/greenBalloon.json | 26 + .../hw5_assets/spritesheets/greenBalloon.png | Bin 0 -> 715 bytes .../hw5_assets/spritesheets/redBalloon.json | 26 + .../hw5_assets/spritesheets/redBalloon.png | Bin 0 -> 712 bytes hw5/dist/hw5_assets/spritesheets/spike.json | 79 + hw5/dist/hw5_assets/spritesheets/spike.png | Bin 0 -> 1061 bytes hw5/dist/hw5_assets/tilemaps/level1.json | 77 + hw5/dist/hw5_assets/tilemaps/level2.json | 77 + hw5/dist/hw5_assets/tilemaps/tileset.png | Bin 0 -> 1941 bytes hw5/gulpfile.js | 34 + hw5/package-lock.json | 9236 +++++++++++++++++ hw5/package.json | 21 + hw5/readme.md | 6 + .../Homework5/Enemies/BalloonController.ts | 51 + hw5/src/Homework5/Enemies/BalloonState.ts | 78 + hw5/src/Homework5/Enemies/Rising.ts | 25 + hw5/src/Homework5/Enemies/Sinking.ts | 25 + hw5/src/Homework5/Enemies/ZeroGravity.ts | 50 + hw5/src/Homework5/HW5_ParticleSystem.ts | 88 + hw5/src/Homework5/Player/PlayerController.ts | 154 + hw5/src/Homework5/Player/PlayerStates/Fall.ts | 25 + hw5/src/Homework5/Player/PlayerStates/Idle.ts | 49 + .../Homework5/Player/PlayerStates/InAir.ts | 20 + hw5/src/Homework5/Player/PlayerStates/Jump.ts | 46 + .../Homework5/Player/PlayerStates/OnGround.ts | 38 + .../Player/PlayerStates/PlayerState.ts | 58 + hw5/src/Homework5/Player/PlayerStates/Run.ts | 49 + hw5/src/Homework5/Player/PlayerStates/Walk.ts | 48 + hw5/src/Homework5/Scenes/GameLevel.ts | 451 + hw5/src/Homework5/Scenes/Level1.ts | 85 + hw5/src/Homework5/Scenes/Level2.ts | 52 + hw5/src/Homework5/Scenes/MainMenu.ts | 76 + hw5/src/Homework5/hw5_color.ts | 5 + hw5/src/Homework5/hw5_enums.ts | 12 + hw5/src/Wolfie2D/AI/AIManager.ts | 66 + hw5/src/Wolfie2D/AI/ControllerAI.ts | 22 + hw5/src/Wolfie2D/AI/GoapActionPlanner.ts | 82 + hw5/src/Wolfie2D/AI/StateMachineAI.ts | 24 + hw5/src/Wolfie2D/AI/StateMachineGoapAI.ts | 40 + hw5/src/Wolfie2D/DataTypes/Collection.ts | 17 + .../Wolfie2D/DataTypes/Functions/NullFunc.ts | 8 + hw5/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts | 22 + hw5/src/Wolfie2D/DataTypes/Graphs/Graph.ts | 145 + .../DataTypes/Graphs/PositionGraph.ts | 94 + hw5/src/Wolfie2D/DataTypes/Interfaces/AI.ts | 20 + .../Wolfie2D/DataTypes/Interfaces/Actor.ts | 42 + .../DataTypes/Interfaces/DebugRenderable.ts | 7 + .../Wolfie2D/DataTypes/Interfaces/GoapAI.ts | 42 + .../DataTypes/Interfaces/GoapAction.ts | 61 + .../DataTypes/Interfaces/Navigable.ts | 13 + .../Wolfie2D/DataTypes/Interfaces/Physical.ts | 120 + .../DataTypes/Interfaces/Positioned.ts | 10 + .../Wolfie2D/DataTypes/Interfaces/Region.ts | 21 + .../Wolfie2D/DataTypes/Interfaces/Unique.ts | 7 + .../DataTypes/Interfaces/Updateable.ts | 8 + hw5/src/Wolfie2D/DataTypes/List.ts | 63 + hw5/src/Wolfie2D/DataTypes/Map.ts | 87 + hw5/src/Wolfie2D/DataTypes/Mat4x4.ts | 167 + .../DataTypes/Physics/AreaCollision.ts | 40 + hw5/src/Wolfie2D/DataTypes/Physics/Hit.ts | 18 + hw5/src/Wolfie2D/DataTypes/QuadTree.ts | 156 + hw5/src/Wolfie2D/DataTypes/Queue.ts | 130 + hw5/src/Wolfie2D/DataTypes/RegionQuadTree.ts | 271 + .../DataTypes/Rendering/WebGLGameTexture.ts | 5 + .../DataTypes/Rendering/WebGLProgramType.ts | 29 + hw5/src/Wolfie2D/DataTypes/Shapes/AABB.ts | 339 + hw5/src/Wolfie2D/DataTypes/Shapes/Circle.ts | 76 + hw5/src/Wolfie2D/DataTypes/Shapes/Shape.ts | 169 + hw5/src/Wolfie2D/DataTypes/Spritesheet.ts | 22 + hw5/src/Wolfie2D/DataTypes/Stack.ts | 108 + hw5/src/Wolfie2D/DataTypes/State/State.ts | 54 + .../Wolfie2D/DataTypes/State/StateMachine.ts | 137 + .../Wolfie2D/DataTypes/Tilesets/TiledData.ts | 78 + .../Wolfie2D/DataTypes/Tilesets/Tileset.ts | 146 + hw5/src/Wolfie2D/DataTypes/Vec2.ts | 432 + hw5/src/Wolfie2D/Debug/Debug.ts | 197 + hw5/src/Wolfie2D/Debug/Stats.ts | 244 + hw5/src/Wolfie2D/Events/BattleSystem.ts | 38 + hw5/src/Wolfie2D/Events/Emitter.ts | 26 + hw5/src/Wolfie2D/Events/EventQueue.ts | 125 + hw5/src/Wolfie2D/Events/GameEvent.ts | 54 + hw5/src/Wolfie2D/Events/GameEventType.ts | 91 + hw5/src/Wolfie2D/Events/Receiver.ts | 77 + hw5/src/Wolfie2D/Input/Input.ts | 334 + hw5/src/Wolfie2D/Input/InputHandler.ts | 94 + .../Wolfie2D/Loop/EnvironmentInitializer.ts | 47 + hw5/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts | 235 + hw5/src/Wolfie2D/Loop/Game.ts | 214 + hw5/src/Wolfie2D/Loop/GameLoop.ts | 69 + hw5/src/Wolfie2D/Loop/GameOptions.ts | 44 + hw5/src/Wolfie2D/Nodes/CanvasNode.ts | 137 + hw5/src/Wolfie2D/Nodes/GameNode.ts | 480 + hw5/src/Wolfie2D/Nodes/Graphic.ts | 56 + .../Wolfie2D/Nodes/Graphics/GraphicTypes.ts | 6 + hw5/src/Wolfie2D/Nodes/Graphics/Line.ts | 33 + hw5/src/Wolfie2D/Nodes/Graphics/Particle.ts | 57 + hw5/src/Wolfie2D/Nodes/Graphics/Point.ts | 13 + hw5/src/Wolfie2D/Nodes/Graphics/Rect.ts | 46 + .../Wolfie2D/Nodes/Sprites/AnimatedSprite.ts | 49 + hw5/src/Wolfie2D/Nodes/Sprites/Sprite.ts | 35 + hw5/src/Wolfie2D/Nodes/Tilemap.ts | 119 + .../Nodes/Tilemaps/OrthogonalTilemap.ts | 190 + hw5/src/Wolfie2D/Nodes/UIElement.ts | 149 + hw5/src/Wolfie2D/Nodes/UIElements/Button.ts | 27 + hw5/src/Wolfie2D/Nodes/UIElements/Label.ts | 152 + hw5/src/Wolfie2D/Nodes/UIElements/Slider.ts | 64 + .../Wolfie2D/Nodes/UIElements/TextInput.ts | 64 + .../Nodes/UIElements/UIElementTypes.ts | 6 + .../Wolfie2D/Pathfinding/NavigationManager.ts | 40 + .../Wolfie2D/Pathfinding/NavigationPath.ts | 58 + hw5/src/Wolfie2D/Pathfinding/Navmesh.ts | 72 + .../Wolfie2D/Physics/BasicPhysicsManager.ts | 349 + hw5/src/Wolfie2D/Physics/PhysicsManager.ts | 112 + hw5/src/Wolfie2D/Playback/Recorder.ts | 93 + .../Registry/Registries/FontRegistry.ts | 0 .../Wolfie2D/Registry/Registries/Registry.ts | 22 + .../Registry/Registries/ShaderRegistry.ts | 99 + hw5/src/Wolfie2D/Registry/RegistryManager.ts | 31 + .../Rendering/Animations/AnimationManager.ts | 228 + .../Rendering/Animations/AnimationTypes.ts | 65 + .../Rendering/Animations/ParticleSystem.ts | 172 + .../Animations/ParticleSystemManager.ts | 40 + .../Rendering/Animations/TweenController.ts | 213 + .../Rendering/Animations/TweenManager.ts | 40 + hw5/src/Wolfie2D/Rendering/CanvasRenderer.ts | 255 + .../CanvasRendering/GraphicRenderer.ts | 72 + .../CanvasRendering/TilemapRenderer.ts | 151 + .../CanvasRendering/UIElementRenderer.ts | 126 + .../Wolfie2D/Rendering/RenderingManager.ts | 85 + hw5/src/Wolfie2D/Rendering/WebGLRenderer.ts | 182 + .../Rendering/WebGLRendering/ShaderType.ts | 44 + .../ShaderTypes/LabelShaderType.ts | 123 + .../ShaderTypes/PointShaderType.ts | 61 + .../ShaderTypes/QuadShaderType.ts | 25 + .../ShaderTypes/RectShaderType.ts | 134 + .../ShaderTypes/SpriteShaderType.ts | 138 + .../ResourceManager/ResourceManager.ts | 1035 ++ .../Scene/Factories/CanvasNodeFactory.ts | 252 + .../Scene/Factories/FactoryManager.ts | 81 + .../Scene/Factories/TilemapFactory.ts | 232 + hw5/src/Wolfie2D/Scene/Layer.ts | 184 + .../Wolfie2D/Scene/Layers/ParallaxLayer.ts | 23 + hw5/src/Wolfie2D/Scene/Layers/UILayer.ts | 20 + hw5/src/Wolfie2D/Scene/Scene.ts | 448 + hw5/src/Wolfie2D/Scene/SceneManager.ts | 125 + hw5/src/Wolfie2D/Scene/SceneOptions.ts | 25 + hw5/src/Wolfie2D/SceneGraph/SceneGraph.ts | 131 + .../Wolfie2D/SceneGraph/SceneGraphArray.ts | 93 + .../Wolfie2D/SceneGraph/SceneGraphQuadTree.ts | 98 + hw5/src/Wolfie2D/SceneGraph/Viewport.ts | 286 + hw5/src/Wolfie2D/Sound/AudioManager.ts | 244 + hw5/src/Wolfie2D/Timing/Timer.ts | 109 + hw5/src/Wolfie2D/Timing/TimerManager.ts | 33 + hw5/src/Wolfie2D/Utils/ArrayUtils.ts | 43 + hw5/src/Wolfie2D/Utils/Color.ts | 197 + hw5/src/Wolfie2D/Utils/EaseFunctions.ts | 55 + hw5/src/Wolfie2D/Utils/GraphUtils.ts | 64 + hw5/src/Wolfie2D/Utils/MathUtils.ts | 175 + hw5/src/Wolfie2D/Utils/MemoryUtils.ts | 47 + hw5/src/Wolfie2D/Utils/Rand/Perlin.ts | 126 + hw5/src/Wolfie2D/Utils/RandUtils.ts | 64 + hw5/src/Wolfie2D/Utils/RenderingUtils.ts | 28 + hw5/src/Wolfie2D/Utils/SortingUtils.ts | 37 + hw5/src/Wolfie2D/Utils/StringUtils.ts | 14 + hw5/src/Wolfie2D/_Demos/readme.md | 2 + hw5/src/default_main.ts | 23 + hw5/src/default_scene.ts | 98 + hw5/src/demos/AudioDemo.ts | 71 + hw5/src/demos/Platformer.ts | 49 + hw5/src/demos/PlatformerPlayerController.ts | 62 + hw5/src/index.d.ts | 22 + hw5/src/index.html | 71 + hw5/src/main.ts | 30 + hw5/tsconfig.json | 10 + 591 files changed, 80113 insertions(+) create mode 100644 hw1/README.md create mode 100644 hw1/concentration_multi.cpp create mode 100644 hw3/.gitignore create mode 100644 hw3/dist/builtin/shaders/label.fshader create mode 100644 hw3/dist/builtin/shaders/label.vshader create mode 100644 hw3/dist/builtin/shaders/point.fshader create mode 100644 hw3/dist/builtin/shaders/point.vshader create mode 100644 hw3/dist/builtin/shaders/rect.fshader create mode 100644 hw3/dist/builtin/shaders/rect.vshader create mode 100644 hw3/dist/builtin/shaders/sprite.fshader create mode 100644 hw3/dist/builtin/shaders/sprite.vshader create mode 100644 hw3/dist/demo_assets/images/platformer_background.png create mode 100644 hw3/dist/demo_assets/images/wolfie2d_text.png create mode 100644 hw3/dist/demo_assets/sounds/jump.wav create mode 100644 hw3/dist/demo_assets/sounds/title.mp3 create mode 100644 hw3/dist/demo_assets/spritesheets/platformer/player.json create mode 100644 hw3/dist/demo_assets/spritesheets/platformer/player.png create mode 100644 hw3/dist/demo_assets/tilemaps/platformer/platformer.json create mode 100644 hw3/dist/demo_assets/tilemaps/platformer/platformer.png create mode 100644 hw3/dist/hw3_assets/shaders/gradient_circle.fshader create mode 100644 hw3/dist/hw3_assets/shaders/gradient_circle.vshader create mode 100644 hw3/dist/hw3_assets/shaders/linear_gradient_circle.fshader create mode 100644 hw3/dist/hw3_assets/shaders/linear_gradient_circle.vshader create mode 100644 hw3/dist/hw3_assets/sprites/road.jpg create mode 100644 hw3/dist/hw3_assets/sprites/stone.png create mode 100644 hw3/dist/hw3_assets/spritesheets/car.json create mode 100644 hw3/dist/hw3_assets/spritesheets/cars.json create mode 100644 hw3/dist/hw3_assets/spritesheets/cars.png create mode 100644 hw3/gulpfile.js create mode 100644 hw3/package-lock.json create mode 100644 hw3/package.json create mode 100644 hw3/readme.md create mode 100644 hw3/src/Wolfie2D/AI/AIManager.ts create mode 100644 hw3/src/Wolfie2D/AI/ControllerAI.ts create mode 100644 hw3/src/Wolfie2D/AI/StateMachineAI.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Collection.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Functions/NullFunc.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Graphs/Graph.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Graphs/PositionGraph.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/AI.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Actor.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/DebugRenderable.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Navigable.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Physical.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Positioned.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Region.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Unique.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Interfaces/Updateable.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/List.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Map.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Mat4x4.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Physics/AreaCollision.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Physics/Hit.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/QuadTree.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Queue.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/RegionQuadTree.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Rendering/WebGLGameTexture.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Rendering/WebGLProgramType.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Shapes/AABB.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Shapes/Circle.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Shapes/Shape.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Spritesheet.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Stack.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/State/State.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/State/StateMachine.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Tilesets/TiledData.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Tilesets/Tileset.ts create mode 100644 hw3/src/Wolfie2D/DataTypes/Vec2.ts create mode 100644 hw3/src/Wolfie2D/Debug/Debug.ts create mode 100644 hw3/src/Wolfie2D/Debug/Stats.ts create mode 100644 hw3/src/Wolfie2D/Events/Emitter.ts create mode 100644 hw3/src/Wolfie2D/Events/EventQueue.ts create mode 100644 hw3/src/Wolfie2D/Events/GameEvent.ts create mode 100644 hw3/src/Wolfie2D/Events/GameEventType.ts create mode 100644 hw3/src/Wolfie2D/Events/Receiver.ts create mode 100644 hw3/src/Wolfie2D/Input/Input.ts create mode 100644 hw3/src/Wolfie2D/Input/InputHandler.ts create mode 100644 hw3/src/Wolfie2D/Loop/EnvironmentInitializer.ts create mode 100644 hw3/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts create mode 100644 hw3/src/Wolfie2D/Loop/Game.ts create mode 100644 hw3/src/Wolfie2D/Loop/GameLoop.ts create mode 100644 hw3/src/Wolfie2D/Loop/GameOptions.ts create mode 100644 hw3/src/Wolfie2D/Nodes/CanvasNode.ts create mode 100644 hw3/src/Wolfie2D/Nodes/GameNode.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Graphic.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Graphics/GraphicTypes.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Graphics/Line.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Graphics/Point.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Graphics/Rect.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Sprites/AnimatedSprite.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Sprites/Sprite.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Tilemap.ts create mode 100644 hw3/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts create mode 100644 hw3/src/Wolfie2D/Nodes/UIElement.ts create mode 100644 hw3/src/Wolfie2D/Nodes/UIElements/Button.ts create mode 100644 hw3/src/Wolfie2D/Nodes/UIElements/Label.ts create mode 100644 hw3/src/Wolfie2D/Nodes/UIElements/Slider.ts create mode 100644 hw3/src/Wolfie2D/Nodes/UIElements/TextInput.ts create mode 100644 hw3/src/Wolfie2D/Nodes/UIElements/UIElementTypes.ts create mode 100644 hw3/src/Wolfie2D/Pathfinding/NavigationManager.ts create mode 100644 hw3/src/Wolfie2D/Pathfinding/NavigationPath.ts create mode 100644 hw3/src/Wolfie2D/Pathfinding/Navmesh.ts create mode 100644 hw3/src/Wolfie2D/Physics/BasicPhysicsManager.ts create mode 100644 hw3/src/Wolfie2D/Physics/PhysicsManager.ts create mode 100644 hw3/src/Wolfie2D/Playback/Recorder.ts create mode 100644 hw3/src/Wolfie2D/Registry/Registries/FontRegistry.ts create mode 100644 hw3/src/Wolfie2D/Registry/Registries/Registry.ts create mode 100644 hw3/src/Wolfie2D/Registry/Registries/ShaderRegistry.ts create mode 100644 hw3/src/Wolfie2D/Registry/RegistryManager.ts create mode 100644 hw3/src/Wolfie2D/Rendering/Animations/AnimationManager.ts create mode 100644 hw3/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts create mode 100644 hw3/src/Wolfie2D/Rendering/Animations/TweenController.ts create mode 100644 hw3/src/Wolfie2D/Rendering/Animations/TweenManager.ts create mode 100644 hw3/src/Wolfie2D/Rendering/CanvasRenderer.ts create mode 100644 hw3/src/Wolfie2D/Rendering/CanvasRendering/GraphicRenderer.ts create mode 100644 hw3/src/Wolfie2D/Rendering/CanvasRendering/TilemapRenderer.ts create mode 100644 hw3/src/Wolfie2D/Rendering/CanvasRendering/UIElementRenderer.ts create mode 100644 hw3/src/Wolfie2D/Rendering/RenderingManager.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRenderer.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderType.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/LabelShaderType.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/PointShaderType.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/QuadShaderType.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType.ts create mode 100644 hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/SpriteShaderType.ts create mode 100644 hw3/src/Wolfie2D/ResourceManager/ResourceManager.ts create mode 100644 hw3/src/Wolfie2D/Scene/Factories/CanvasNodeFactory.ts create mode 100644 hw3/src/Wolfie2D/Scene/Factories/FactoryManager.ts create mode 100644 hw3/src/Wolfie2D/Scene/Factories/TilemapFactory.ts create mode 100644 hw3/src/Wolfie2D/Scene/Layer.ts create mode 100644 hw3/src/Wolfie2D/Scene/Layers/ParallaxLayer.ts create mode 100644 hw3/src/Wolfie2D/Scene/Layers/UILayer.ts create mode 100644 hw3/src/Wolfie2D/Scene/Scene.ts create mode 100644 hw3/src/Wolfie2D/Scene/SceneManager.ts create mode 100644 hw3/src/Wolfie2D/Scene/SceneOptions.ts create mode 100644 hw3/src/Wolfie2D/SceneGraph/SceneGraph.ts create mode 100644 hw3/src/Wolfie2D/SceneGraph/SceneGraphArray.ts create mode 100644 hw3/src/Wolfie2D/SceneGraph/SceneGraphQuadTree.ts create mode 100644 hw3/src/Wolfie2D/SceneGraph/Viewport.ts create mode 100644 hw3/src/Wolfie2D/Sound/AudioManager.ts create mode 100644 hw3/src/Wolfie2D/Timing/Timer.ts create mode 100644 hw3/src/Wolfie2D/Timing/TimerManager.ts create mode 100644 hw3/src/Wolfie2D/Utils/ArrayUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/Color.ts create mode 100644 hw3/src/Wolfie2D/Utils/EaseFunctions.ts create mode 100644 hw3/src/Wolfie2D/Utils/GraphUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/MathUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/MemoryUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/Rand/Perlin.ts create mode 100644 hw3/src/Wolfie2D/Utils/RandUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/RenderingUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/SortingUtils.ts create mode 100644 hw3/src/Wolfie2D/Utils/StringUtils.ts create mode 100644 hw3/src/Wolfie2D/_Demos/readme.md create mode 100644 hw3/src/default_main.ts create mode 100644 hw3/src/default_scene.ts create mode 100644 hw3/src/demos/AudioDemo.ts create mode 100644 hw3/src/demos/Platformer.ts create mode 100644 hw3/src/demos/PlatformerPlayerController.ts create mode 100644 hw3/src/hw3/AI/BulletAI.ts create mode 100644 hw3/src/hw3/AI/CarPlayerController.ts create mode 100644 hw3/src/hw3/AI/RockAI.ts create mode 100644 hw3/src/hw3/GradientCircleShaderType.ts create mode 100644 hw3/src/hw3/HW3_Enums.ts create mode 100644 hw3/src/hw3/LinearGradientCircleShaderType.ts create mode 100644 hw3/src/hw3/Scenes/GameOver.ts create mode 100644 hw3/src/hw3/Scenes/HW3_Scene.ts create mode 100644 hw3/src/hw3/Scenes/MainMenu.ts create mode 100644 hw3/src/index.d.ts create mode 100644 hw3/src/index.html create mode 100644 hw3/src/main.ts create mode 100644 hw3/tsconfig.json create mode 100644 hw4/.gitignore create mode 100644 hw4/dist/builtin/shaders/label.fshader create mode 100644 hw4/dist/builtin/shaders/label.vshader create mode 100644 hw4/dist/builtin/shaders/point.fshader create mode 100644 hw4/dist/builtin/shaders/point.vshader create mode 100644 hw4/dist/builtin/shaders/rect.fshader create mode 100644 hw4/dist/builtin/shaders/rect.vshader create mode 100644 hw4/dist/builtin/shaders/sprite.fshader create mode 100644 hw4/dist/builtin/shaders/sprite.vshader create mode 100644 hw4/dist/demo_assets/images/platformer_background.png create mode 100644 hw4/dist/demo_assets/images/wolfie2d_text.png create mode 100644 hw4/dist/demo_assets/sounds/jump.wav create mode 100644 hw4/dist/demo_assets/sounds/title.mp3 create mode 100644 hw4/dist/demo_assets/spritesheets/platformer/player.json create mode 100644 hw4/dist/demo_assets/spritesheets/platformer/player.png create mode 100644 hw4/dist/demo_assets/tilemaps/platformer/platformer.json create mode 100644 hw4/dist/demo_assets/tilemaps/platformer/platformer.png create mode 100644 hw4/dist/hw4_assets/data/enemy.json create mode 100644 hw4/dist/hw4_assets/data/items.json create mode 100644 hw4/dist/hw4_assets/data/navmesh.json create mode 100644 hw4/dist/hw4_assets/data/weaponData.json create mode 100644 hw4/dist/hw4_assets/sprites/healthpack.png create mode 100644 hw4/dist/hw4_assets/sprites/inventory.png create mode 100644 hw4/dist/hw4_assets/sprites/knife.png create mode 100644 hw4/dist/hw4_assets/sprites/laserGun.png create mode 100644 hw4/dist/hw4_assets/sprites/pistol.png create mode 100644 hw4/dist/hw4_assets/spritesheets/custom_enemy1.json create mode 100644 hw4/dist/hw4_assets/spritesheets/custom_enemy1.png create mode 100644 hw4/dist/hw4_assets/spritesheets/custom_enemy2.json create mode 100644 hw4/dist/hw4_assets/spritesheets/custom_enemy2.png create mode 100644 hw4/dist/hw4_assets/spritesheets/gun_enemy.json create mode 100644 hw4/dist/hw4_assets/spritesheets/gun_enemy.png create mode 100644 hw4/dist/hw4_assets/spritesheets/knife_enemy.json create mode 100644 hw4/dist/hw4_assets/spritesheets/knife_enemy.png create mode 100644 hw4/dist/hw4_assets/spritesheets/player1.json create mode 100644 hw4/dist/hw4_assets/spritesheets/player1.png create mode 100644 hw4/dist/hw4_assets/spritesheets/player2.json create mode 100644 hw4/dist/hw4_assets/spritesheets/player2.png create mode 100644 hw4/dist/hw4_assets/spritesheets/slice.json create mode 100644 hw4/dist/hw4_assets/spritesheets/slice.png create mode 100644 hw4/dist/hw4_assets/tilemaps/TopDown_hw4.json create mode 100644 hw4/dist/hw4_assets/tilemaps/cse380_hw4.png create mode 100644 hw4/dist/hw4_assets/tilemaps/cse380_hw4_tilejson.json create mode 100644 hw4/dist/hw4_assets/tilemaps/cse380_hw4_tiles.png create mode 100644 hw4/dist/hw4_assets/tilemaps/cse380_hw4_tiles2.png create mode 100644 hw4/dist/hw4_assets/tilemaps/top-down-hw4.png create mode 100644 hw4/gulpfile.js create mode 100644 hw4/package-lock.json create mode 100644 hw4/package.json create mode 100644 hw4/readme.md create mode 100644 hw4/src/Wolfie2D/AI/AIManager.ts create mode 100644 hw4/src/Wolfie2D/AI/ControllerAI.ts create mode 100644 hw4/src/Wolfie2D/AI/GoapActionPlanner.ts create mode 100644 hw4/src/Wolfie2D/AI/StateMachineAI.ts create mode 100644 hw4/src/Wolfie2D/AI/StateMachineGoapAI.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Collection.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Functions/NullFunc.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Graphs/Graph.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Graphs/PositionGraph.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/AI.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Actor.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/DebugRenderable.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/GoapAI.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/GoapAction.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Navigable.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Physical.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Positioned.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Region.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Unique.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Interfaces/Updateable.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/List.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Map.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Mat4x4.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Physics/AreaCollision.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Physics/Hit.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/QuadTree.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Queue.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/RegionQuadTree.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Rendering/WebGLGameTexture.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Rendering/WebGLProgramType.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Shapes/AABB.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Shapes/Circle.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Shapes/Shape.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Spritesheet.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Stack.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/State/State.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/State/StateMachine.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Tilesets/TiledData.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Tilesets/Tileset.ts create mode 100644 hw4/src/Wolfie2D/DataTypes/Vec2.ts create mode 100644 hw4/src/Wolfie2D/Debug/Debug.ts create mode 100644 hw4/src/Wolfie2D/Debug/Stats.ts create mode 100644 hw4/src/Wolfie2D/Events/BattleSystem.ts create mode 100644 hw4/src/Wolfie2D/Events/Emitter.ts create mode 100644 hw4/src/Wolfie2D/Events/EventQueue.ts create mode 100644 hw4/src/Wolfie2D/Events/GameEvent.ts create mode 100644 hw4/src/Wolfie2D/Events/GameEventType.ts create mode 100644 hw4/src/Wolfie2D/Events/Receiver.ts create mode 100644 hw4/src/Wolfie2D/Input/Input.ts create mode 100644 hw4/src/Wolfie2D/Input/InputHandler.ts create mode 100644 hw4/src/Wolfie2D/Loop/EnvironmentInitializer.ts create mode 100644 hw4/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts create mode 100644 hw4/src/Wolfie2D/Loop/Game.ts create mode 100644 hw4/src/Wolfie2D/Loop/GameLoop.ts create mode 100644 hw4/src/Wolfie2D/Loop/GameOptions.ts create mode 100644 hw4/src/Wolfie2D/Nodes/CanvasNode.ts create mode 100644 hw4/src/Wolfie2D/Nodes/GameNode.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Graphic.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Graphics/GraphicTypes.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Graphics/Line.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Graphics/Particle.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Graphics/Point.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Graphics/Rect.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Sprites/AnimatedSprite.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Sprites/Sprite.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Tilemap.ts create mode 100644 hw4/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts create mode 100644 hw4/src/Wolfie2D/Nodes/UIElement.ts create mode 100644 hw4/src/Wolfie2D/Nodes/UIElements/Button.ts create mode 100644 hw4/src/Wolfie2D/Nodes/UIElements/Label.ts create mode 100644 hw4/src/Wolfie2D/Nodes/UIElements/Slider.ts create mode 100644 hw4/src/Wolfie2D/Nodes/UIElements/TextInput.ts create mode 100644 hw4/src/Wolfie2D/Nodes/UIElements/UIElementTypes.ts create mode 100644 hw4/src/Wolfie2D/Pathfinding/NavigationManager.ts create mode 100644 hw4/src/Wolfie2D/Pathfinding/NavigationPath.ts create mode 100644 hw4/src/Wolfie2D/Pathfinding/Navmesh.ts create mode 100644 hw4/src/Wolfie2D/Physics/BasicPhysicsManager.ts create mode 100644 hw4/src/Wolfie2D/Physics/PhysicsManager.ts create mode 100644 hw4/src/Wolfie2D/Playback/Recorder.ts create mode 100644 hw4/src/Wolfie2D/Registry/Registries/FontRegistry.ts create mode 100644 hw4/src/Wolfie2D/Registry/Registries/Registry.ts create mode 100644 hw4/src/Wolfie2D/Registry/Registries/ShaderRegistry.ts create mode 100644 hw4/src/Wolfie2D/Registry/RegistryManager.ts create mode 100644 hw4/src/Wolfie2D/Rendering/Animations/AnimationManager.ts create mode 100644 hw4/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts create mode 100644 hw4/src/Wolfie2D/Rendering/Animations/ParticleSystem.ts create mode 100644 hw4/src/Wolfie2D/Rendering/Animations/ParticleSystemManager.ts create mode 100644 hw4/src/Wolfie2D/Rendering/Animations/TweenController.ts create mode 100644 hw4/src/Wolfie2D/Rendering/Animations/TweenManager.ts create mode 100644 hw4/src/Wolfie2D/Rendering/CanvasRenderer.ts create mode 100644 hw4/src/Wolfie2D/Rendering/CanvasRendering/GraphicRenderer.ts create mode 100644 hw4/src/Wolfie2D/Rendering/CanvasRendering/TilemapRenderer.ts create mode 100644 hw4/src/Wolfie2D/Rendering/CanvasRendering/UIElementRenderer.ts create mode 100644 hw4/src/Wolfie2D/Rendering/RenderingManager.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRenderer.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRendering/ShaderType.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/LabelShaderType.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/PointShaderType.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/QuadShaderType.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType.ts create mode 100644 hw4/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/SpriteShaderType.ts create mode 100644 hw4/src/Wolfie2D/ResourceManager/ResourceManager.ts create mode 100644 hw4/src/Wolfie2D/Scene/Factories/CanvasNodeFactory.ts create mode 100644 hw4/src/Wolfie2D/Scene/Factories/FactoryManager.ts create mode 100644 hw4/src/Wolfie2D/Scene/Factories/TilemapFactory.ts create mode 100644 hw4/src/Wolfie2D/Scene/Layer.ts create mode 100644 hw4/src/Wolfie2D/Scene/Layers/ParallaxLayer.ts create mode 100644 hw4/src/Wolfie2D/Scene/Layers/UILayer.ts create mode 100644 hw4/src/Wolfie2D/Scene/Scene.ts create mode 100644 hw4/src/Wolfie2D/Scene/SceneManager.ts create mode 100644 hw4/src/Wolfie2D/Scene/SceneOptions.ts create mode 100644 hw4/src/Wolfie2D/SceneGraph/SceneGraph.ts create mode 100644 hw4/src/Wolfie2D/SceneGraph/SceneGraphArray.ts create mode 100644 hw4/src/Wolfie2D/SceneGraph/SceneGraphQuadTree.ts create mode 100644 hw4/src/Wolfie2D/SceneGraph/Viewport.ts create mode 100644 hw4/src/Wolfie2D/Sound/AudioManager.ts create mode 100644 hw4/src/Wolfie2D/Timing/Timer.ts create mode 100644 hw4/src/Wolfie2D/Timing/TimerManager.ts create mode 100644 hw4/src/Wolfie2D/Utils/ArrayUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/Color.ts create mode 100644 hw4/src/Wolfie2D/Utils/EaseFunctions.ts create mode 100644 hw4/src/Wolfie2D/Utils/GraphUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/MathUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/MemoryUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/Rand/Perlin.ts create mode 100644 hw4/src/Wolfie2D/Utils/RandUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/RenderingUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/SortingUtils.ts create mode 100644 hw4/src/Wolfie2D/Utils/StringUtils.ts create mode 100644 hw4/src/Wolfie2D/_Demos/readme.md create mode 100644 hw4/src/default_main.ts create mode 100644 hw4/src/default_scene.ts create mode 100644 hw4/src/demos/AudioDemo.ts create mode 100644 hw4/src/demos/Platformer.ts create mode 100644 hw4/src/demos/PlatformerPlayerController.ts create mode 100644 hw4/src/hw4/AI/BattlerAI.ts create mode 100644 hw4/src/hw4/AI/EnemyAI.ts create mode 100644 hw4/src/hw4/AI/EnemyActions/AttackAction.ts create mode 100644 hw4/src/hw4/AI/EnemyActions/Berserk.ts create mode 100644 hw4/src/hw4/AI/EnemyActions/Move.ts create mode 100644 hw4/src/hw4/AI/EnemyActions/Retreat.ts create mode 100644 hw4/src/hw4/AI/EnemyStates/Active.ts create mode 100644 hw4/src/hw4/AI/EnemyStates/Alert.ts create mode 100644 hw4/src/hw4/AI/EnemyStates/EnemyState.ts create mode 100644 hw4/src/hw4/AI/EnemyStates/Guard.ts create mode 100644 hw4/src/hw4/AI/EnemyStates/Patrol.ts create mode 100644 hw4/src/hw4/AI/PlayerController.ts create mode 100644 hw4/src/hw4/GameSystems/BattleManager.ts create mode 100644 hw4/src/hw4/GameSystems/InventoryManager.ts create mode 100644 hw4/src/hw4/GameSystems/items/Healthpack.ts create mode 100644 hw4/src/hw4/GameSystems/items/Item.ts create mode 100644 hw4/src/hw4/GameSystems/items/Weapon.ts create mode 100644 hw4/src/hw4/GameSystems/items/WeaponTypes/LaserGun.ts create mode 100644 hw4/src/hw4/GameSystems/items/WeaponTypes/SemiAutoGun.ts create mode 100644 hw4/src/hw4/GameSystems/items/WeaponTypes/SingleShot.ts create mode 100644 hw4/src/hw4/GameSystems/items/WeaponTypes/Slice.ts create mode 100644 hw4/src/hw4/GameSystems/items/WeaponTypes/WeaponType.ts create mode 100644 hw4/src/hw4/Registry/WeaponRegistry.ts create mode 100644 hw4/src/hw4/Registry/WeaponTypeRegistry.ts create mode 100644 hw4/src/hw4/Scenes/GameOver.ts create mode 100644 hw4/src/hw4/Scenes/MainMenu.ts create mode 100644 hw4/src/hw4/Scenes/hw4_scene.ts create mode 100644 hw4/src/hw4/hw4_constants.ts create mode 100644 hw4/src/index.d.ts create mode 100644 hw4/src/index.html create mode 100644 hw4/src/main.ts create mode 100644 hw4/tsconfig.json create mode 100644 hw5/.gitignore create mode 100644 hw5/dist/builtin/shaders/label.fshader create mode 100644 hw5/dist/builtin/shaders/label.vshader create mode 100644 hw5/dist/builtin/shaders/point.fshader create mode 100644 hw5/dist/builtin/shaders/point.vshader create mode 100644 hw5/dist/builtin/shaders/rect.fshader create mode 100644 hw5/dist/builtin/shaders/rect.vshader create mode 100644 hw5/dist/builtin/shaders/sprite.fshader create mode 100644 hw5/dist/builtin/shaders/sprite.vshader create mode 100644 hw5/dist/demo_assets/images/platformer_background.png create mode 100644 hw5/dist/demo_assets/images/wolfie2d_text.png create mode 100644 hw5/dist/demo_assets/sounds/jump.wav create mode 100644 hw5/dist/demo_assets/sounds/title.mp3 create mode 100644 hw5/dist/demo_assets/spritesheets/platformer/player.json create mode 100644 hw5/dist/demo_assets/spritesheets/platformer/player.png create mode 100644 hw5/dist/demo_assets/tilemaps/platformer/platformer.json create mode 100644 hw5/dist/demo_assets/tilemaps/platformer/platformer.png create mode 100644 hw5/dist/hw5_assets/fonts/PixelSimple.ttf create mode 100644 hw5/dist/hw5_assets/music/menu.mp3 create mode 100644 hw5/dist/hw5_assets/music/pop.ogg create mode 100755 hw5/dist/hw5_assets/music/sound.wav create mode 100644 hw5/dist/hw5_assets/sounds/jump.wav create mode 100644 hw5/dist/hw5_assets/sounds/player_death.wav create mode 100644 hw5/dist/hw5_assets/sounds/switch.wav create mode 100644 hw5/dist/hw5_assets/spritesheets/blueBalloon.json create mode 100644 hw5/dist/hw5_assets/spritesheets/blueBalloon.png create mode 100644 hw5/dist/hw5_assets/spritesheets/greenBalloon.json create mode 100644 hw5/dist/hw5_assets/spritesheets/greenBalloon.png create mode 100644 hw5/dist/hw5_assets/spritesheets/redBalloon.json create mode 100644 hw5/dist/hw5_assets/spritesheets/redBalloon.png create mode 100644 hw5/dist/hw5_assets/spritesheets/spike.json create mode 100644 hw5/dist/hw5_assets/spritesheets/spike.png create mode 100644 hw5/dist/hw5_assets/tilemaps/level1.json create mode 100644 hw5/dist/hw5_assets/tilemaps/level2.json create mode 100644 hw5/dist/hw5_assets/tilemaps/tileset.png create mode 100644 hw5/gulpfile.js create mode 100644 hw5/package-lock.json create mode 100644 hw5/package.json create mode 100644 hw5/readme.md create mode 100644 hw5/src/Homework5/Enemies/BalloonController.ts create mode 100644 hw5/src/Homework5/Enemies/BalloonState.ts create mode 100644 hw5/src/Homework5/Enemies/Rising.ts create mode 100644 hw5/src/Homework5/Enemies/Sinking.ts create mode 100644 hw5/src/Homework5/Enemies/ZeroGravity.ts create mode 100644 hw5/src/Homework5/HW5_ParticleSystem.ts create mode 100644 hw5/src/Homework5/Player/PlayerController.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/Fall.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/Idle.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/InAir.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/Jump.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/OnGround.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/PlayerState.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/Run.ts create mode 100644 hw5/src/Homework5/Player/PlayerStates/Walk.ts create mode 100644 hw5/src/Homework5/Scenes/GameLevel.ts create mode 100644 hw5/src/Homework5/Scenes/Level1.ts create mode 100644 hw5/src/Homework5/Scenes/Level2.ts create mode 100644 hw5/src/Homework5/Scenes/MainMenu.ts create mode 100644 hw5/src/Homework5/hw5_color.ts create mode 100644 hw5/src/Homework5/hw5_enums.ts create mode 100644 hw5/src/Wolfie2D/AI/AIManager.ts create mode 100644 hw5/src/Wolfie2D/AI/ControllerAI.ts create mode 100644 hw5/src/Wolfie2D/AI/GoapActionPlanner.ts create mode 100644 hw5/src/Wolfie2D/AI/StateMachineAI.ts create mode 100644 hw5/src/Wolfie2D/AI/StateMachineGoapAI.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Collection.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Functions/NullFunc.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Graphs/Graph.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Graphs/PositionGraph.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/AI.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Actor.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/DebugRenderable.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/GoapAI.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/GoapAction.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Navigable.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Physical.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Positioned.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Region.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Unique.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Interfaces/Updateable.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/List.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Map.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Mat4x4.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Physics/AreaCollision.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Physics/Hit.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/QuadTree.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Queue.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/RegionQuadTree.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Rendering/WebGLGameTexture.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Rendering/WebGLProgramType.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Shapes/AABB.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Shapes/Circle.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Shapes/Shape.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Spritesheet.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Stack.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/State/State.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/State/StateMachine.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Tilesets/TiledData.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Tilesets/Tileset.ts create mode 100644 hw5/src/Wolfie2D/DataTypes/Vec2.ts create mode 100644 hw5/src/Wolfie2D/Debug/Debug.ts create mode 100644 hw5/src/Wolfie2D/Debug/Stats.ts create mode 100644 hw5/src/Wolfie2D/Events/BattleSystem.ts create mode 100644 hw5/src/Wolfie2D/Events/Emitter.ts create mode 100644 hw5/src/Wolfie2D/Events/EventQueue.ts create mode 100644 hw5/src/Wolfie2D/Events/GameEvent.ts create mode 100644 hw5/src/Wolfie2D/Events/GameEventType.ts create mode 100644 hw5/src/Wolfie2D/Events/Receiver.ts create mode 100644 hw5/src/Wolfie2D/Input/Input.ts create mode 100644 hw5/src/Wolfie2D/Input/InputHandler.ts create mode 100644 hw5/src/Wolfie2D/Loop/EnvironmentInitializer.ts create mode 100644 hw5/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts create mode 100644 hw5/src/Wolfie2D/Loop/Game.ts create mode 100644 hw5/src/Wolfie2D/Loop/GameLoop.ts create mode 100644 hw5/src/Wolfie2D/Loop/GameOptions.ts create mode 100644 hw5/src/Wolfie2D/Nodes/CanvasNode.ts create mode 100644 hw5/src/Wolfie2D/Nodes/GameNode.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Graphic.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Graphics/GraphicTypes.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Graphics/Line.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Graphics/Particle.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Graphics/Point.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Graphics/Rect.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Sprites/AnimatedSprite.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Sprites/Sprite.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Tilemap.ts create mode 100644 hw5/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts create mode 100644 hw5/src/Wolfie2D/Nodes/UIElement.ts create mode 100644 hw5/src/Wolfie2D/Nodes/UIElements/Button.ts create mode 100644 hw5/src/Wolfie2D/Nodes/UIElements/Label.ts create mode 100644 hw5/src/Wolfie2D/Nodes/UIElements/Slider.ts create mode 100644 hw5/src/Wolfie2D/Nodes/UIElements/TextInput.ts create mode 100644 hw5/src/Wolfie2D/Nodes/UIElements/UIElementTypes.ts create mode 100644 hw5/src/Wolfie2D/Pathfinding/NavigationManager.ts create mode 100644 hw5/src/Wolfie2D/Pathfinding/NavigationPath.ts create mode 100644 hw5/src/Wolfie2D/Pathfinding/Navmesh.ts create mode 100644 hw5/src/Wolfie2D/Physics/BasicPhysicsManager.ts create mode 100644 hw5/src/Wolfie2D/Physics/PhysicsManager.ts create mode 100644 hw5/src/Wolfie2D/Playback/Recorder.ts create mode 100644 hw5/src/Wolfie2D/Registry/Registries/FontRegistry.ts create mode 100644 hw5/src/Wolfie2D/Registry/Registries/Registry.ts create mode 100644 hw5/src/Wolfie2D/Registry/Registries/ShaderRegistry.ts create mode 100644 hw5/src/Wolfie2D/Registry/RegistryManager.ts create mode 100644 hw5/src/Wolfie2D/Rendering/Animations/AnimationManager.ts create mode 100644 hw5/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts create mode 100644 hw5/src/Wolfie2D/Rendering/Animations/ParticleSystem.ts create mode 100644 hw5/src/Wolfie2D/Rendering/Animations/ParticleSystemManager.ts create mode 100644 hw5/src/Wolfie2D/Rendering/Animations/TweenController.ts create mode 100644 hw5/src/Wolfie2D/Rendering/Animations/TweenManager.ts create mode 100644 hw5/src/Wolfie2D/Rendering/CanvasRenderer.ts create mode 100644 hw5/src/Wolfie2D/Rendering/CanvasRendering/GraphicRenderer.ts create mode 100644 hw5/src/Wolfie2D/Rendering/CanvasRendering/TilemapRenderer.ts create mode 100644 hw5/src/Wolfie2D/Rendering/CanvasRendering/UIElementRenderer.ts create mode 100644 hw5/src/Wolfie2D/Rendering/RenderingManager.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRenderer.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRendering/ShaderType.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/LabelShaderType.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/PointShaderType.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/QuadShaderType.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType.ts create mode 100644 hw5/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/SpriteShaderType.ts create mode 100644 hw5/src/Wolfie2D/ResourceManager/ResourceManager.ts create mode 100644 hw5/src/Wolfie2D/Scene/Factories/CanvasNodeFactory.ts create mode 100644 hw5/src/Wolfie2D/Scene/Factories/FactoryManager.ts create mode 100644 hw5/src/Wolfie2D/Scene/Factories/TilemapFactory.ts create mode 100644 hw5/src/Wolfie2D/Scene/Layer.ts create mode 100644 hw5/src/Wolfie2D/Scene/Layers/ParallaxLayer.ts create mode 100644 hw5/src/Wolfie2D/Scene/Layers/UILayer.ts create mode 100644 hw5/src/Wolfie2D/Scene/Scene.ts create mode 100644 hw5/src/Wolfie2D/Scene/SceneManager.ts create mode 100644 hw5/src/Wolfie2D/Scene/SceneOptions.ts create mode 100644 hw5/src/Wolfie2D/SceneGraph/SceneGraph.ts create mode 100644 hw5/src/Wolfie2D/SceneGraph/SceneGraphArray.ts create mode 100644 hw5/src/Wolfie2D/SceneGraph/SceneGraphQuadTree.ts create mode 100644 hw5/src/Wolfie2D/SceneGraph/Viewport.ts create mode 100644 hw5/src/Wolfie2D/Sound/AudioManager.ts create mode 100644 hw5/src/Wolfie2D/Timing/Timer.ts create mode 100644 hw5/src/Wolfie2D/Timing/TimerManager.ts create mode 100644 hw5/src/Wolfie2D/Utils/ArrayUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/Color.ts create mode 100644 hw5/src/Wolfie2D/Utils/EaseFunctions.ts create mode 100644 hw5/src/Wolfie2D/Utils/GraphUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/MathUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/MemoryUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/Rand/Perlin.ts create mode 100644 hw5/src/Wolfie2D/Utils/RandUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/RenderingUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/SortingUtils.ts create mode 100644 hw5/src/Wolfie2D/Utils/StringUtils.ts create mode 100644 hw5/src/Wolfie2D/_Demos/readme.md create mode 100644 hw5/src/default_main.ts create mode 100644 hw5/src/default_scene.ts create mode 100644 hw5/src/demos/AudioDemo.ts create mode 100644 hw5/src/demos/Platformer.ts create mode 100644 hw5/src/demos/PlatformerPlayerController.ts create mode 100644 hw5/src/index.d.ts create mode 100644 hw5/src/index.html create mode 100644 hw5/src/main.ts create mode 100644 hw5/tsconfig.json diff --git a/hw1/README.md b/hw1/README.md new file mode 100644 index 0000000..b303e50 --- /dev/null +++ b/hw1/README.md @@ -0,0 +1,17 @@ +# CSE380_HW1 +--- +## GAME concentration_multi(temp) +### prepare state +all lights are off +single click anyone to set the number of players +double click to start the game +### play state +at each player's tern, single click to select a single blink +nothing happened -- earn 1 pt +turn white for a second -- earn no pt +### end state +all lights turn white to validate +then all blink will turn to the color of the player who chose that blink +double click to reset to prepare state +## GAME 2 +## GAME 3 diff --git a/hw1/concentration_multi.cpp b/hw1/concentration_multi.cpp new file mode 100644 index 0000000..90fd71d --- /dev/null +++ b/hw1/concentration_multi.cpp @@ -0,0 +1,224 @@ +enum signalStates { PREPARE, INERT, GO, RESOLVE, CHECK, END }; +byte signalState = PREPARE; +enum player {PLAYER1, PLAYER2, PLAYER3, PLAYER4, PLAYER5, PLAYER6};//these modes will simply be different colors +byte player = PLAYER1;//the default mode when the game begins +byte player_num = 0; +byte chosen_player = 6; +Timer warn_timer; +Timer check_timer; +void loop() { + switch (signalState) { + case PREPARE: + prepareLoop(); + break; + case INERT: + case GO: + case RESOLVE: + playLoop(); + break; + case CHECK: + checkLoop(); + break; + case END: + endLoop(); + break; + } +} + +void prepareLoop() { + FOREACH_FACE(f) { + if (getSignalState(getLastValueReceivedOnFace(f)) == INERT) { + signalState = INERT; + player = getPlayer(getLastValueReceivedOnFace(f)); + player_num = player + 1; + byte sendData = (signalState << 3) + (player); + setValueSentOnAllFaces(sendData); + } + else { + if (player_num == 0) { + setColor(OFF); + } + else { + for ( byte i = 0; i < player_num; i ++) { + setColorOnFace(getColor(i+1), i); + } + } + if (buttonSingleClicked()) { + player_num = (player_num + 1) % 7; + } + if (buttonDoubleClicked() && player_num != 0) { + player = player_num - 1; + signalState = INERT; + byte sendData = (signalState << 3) + (player); + setValueSentOnAllFaces(sendData); + } + else { + setValueSentOnAllFaces(0); + } + } + } +} + +void playLoop() { + switch (signalState) { + case INERT: + inertLoop(); + break; + case GO: + goLoop(); + break; + case RESOLVE: + resolveLoop(); + break; + } + displaySignalState(); + byte sendData = (signalState << 3) + (player); + setValueSentOnAllFaces(sendData); +} + +void inertLoop() { + //set myself to GO + if (buttonSingleClicked()) { + if (chosen_player == 6) { + chosen_player = player; + } + else { + warn_timer.set(1000); + } + signalState = GO; + player = (player + 1) % (player_num);//adds one to game mode, but 3+1 becomes 0 + } + //listen for neighbors in GO + FOREACH_FACE(f) { + if (!isValueReceivedOnFaceExpired(f)) { //a neighbor! + if (getSignalState(getLastValueReceivedOnFace(f)) == GO) { //a neighbor saying GO! + signalState = GO; + player = getPlayer(getLastValueReceivedOnFace(f)); + } + } + } +} +void goLoop() { + signalState = RESOLVE; //I default to this at the start of the loop. Only if I see a problem does this not happen + //look for neighbors who have not heard the GO news + FOREACH_FACE(f) { + if (!isValueReceivedOnFaceExpired(f)) { //a neighbor! + if (getSignalState(getLastValueReceivedOnFace(f)) == INERT) {//This neighbor doesn't know it's GO time. Stay in GO + signalState = GO; + } + } + } +} + +void resolveLoop() { + if (chosen_player == 6) { + signalState = INERT; //I default to this at the start of the loop. Only if I see a problem does this not happen + } + else { + check_timer.set(2000); + signalState = CHECK; + } + //look for neighbors who have not moved to RESOLVE + FOREACH_FACE(f) { + if (!isValueReceivedOnFaceExpired(f)) { //a neighbor! + if (getSignalState(getLastValueReceivedOnFace(f)) == GO) {//This neighbor isn't in RESOLVE. Stay in RESOLVE + signalState = RESOLVE; + } + } + } +} + +void checkLoop() { + if (check_timer.isExpired()) { + setColor(OFF); + signalState = END; + } + else { + setColor(WHITE); + FOREACH_FACE(f) { + if (!isValueReceivedOnFaceExpired(f)) { //a neighbor! + if (getSignalState(getLastValueReceivedOnFace(f)) == INERT) {//This neighbor isn't in RESOLVE. Stay in RESOLVE + signalState = INERT; + } + } + } + setValueSentOnAllFaces(6 << 3); + } +} + +void endLoop() { + setColor(getColor(getRealPlayer(chosen_player))) + FOREACH_FACE(f) { + if (!isValueReceivedOnFaceExpired(f)) { //a neighbor! + if (getSignalState(getLastValueReceivedOnFace(f)) == PREPARE) {//This neighbor isn't in RESOLVE. Stay in RESOLVE + signalState = PREPARE; + player = PLAYER1; + player_num = 0; + chosen_player = 6; + setColor(OFF); + } + } + } + if (buttonDoubleClicked()) { + signalState = PREPARE; + player = PLAYER1; + player_num = 0; + chosen_player = 6; + setValueSentOnAllFaces(0); + } +} + +void displaySignalState() { + if (warn_timer.isExpired()) { + switch (signalState) { + case INERT: + setColor(getColor(getRealPlayer(player))); + break; + case GO: + case RESOLVE: + setColor(WHITE); + break; + } + } + else { + setColor(WHITE); + } +} + +Color getColor(data) { + switch (data) { + case 0: + return (makeColorRGB(0,0,0)); + break; + case 1: + return (makeColorRGB(255,0,0)); + break; + case 2: + return (makeColorRGB(0,255,0)); + break; + case 3: + return (makeColorRGB(0,0,255)); + break; + case 4: + return (makeColorRGB(255,0,255)); + break; + case 5: + return (makeColorRGB(255,255,0)); + break; + case 6: + return (makeColorRGB(0,255,255)); + break; + } +} + +byte getRealPlayer(byte data) { + return (data + 1) % player_num + 1; +} + +byte getPlayer(byte data) { + return (data & 7);//returns bits E and F +} + +byte getSignalState(byte data) { + return ((data >> 3) & 7);//returns bits C and D +} \ No newline at end of file diff --git a/hw3/.gitignore b/hw3/.gitignore new file mode 100644 index 0000000..086ddd8 --- /dev/null +++ b/hw3/.gitignore @@ -0,0 +1,18 @@ +# Exclude node modules +node_modules + +# Exclude the compiled project +dist/* + +# Include the demo_assets folder +!dist/demo_assets/ + +# Include the built-in asset folder +!dist/builtin/ + +# Include the hw1 assets +!dist/hw3_assets/ + +### IF YOU ARE MAKING A PROJECT, YOU MAY WANT TO UNCOMMENT THIS LINE ### +# !dist/assets/ + diff --git a/hw3/dist/builtin/shaders/label.fshader b/hw3/dist/builtin/shaders/label.fshader new file mode 100644 index 0000000..a248cba --- /dev/null +++ b/hw3/dist/builtin/shaders/label.fshader @@ -0,0 +1,77 @@ +precision mediump float; + +uniform vec4 u_BackgroundColor; +uniform vec4 u_BorderColor; +uniform float u_BorderWidth; +uniform float u_BorderRadius; +uniform vec2 u_MaxSize; + +varying vec4 v_Position; + +void main(){ + vec2 adj_MaxSize = u_MaxSize - u_BorderWidth; + vec2 rad_MaxSize = u_MaxSize - u_BorderRadius; + vec2 rad2_MaxSize = u_MaxSize - 2.0*u_BorderRadius; + + bool inX = (v_Position.x < adj_MaxSize.x) && (v_Position.x > -adj_MaxSize.x); + bool inY = (v_Position.y < adj_MaxSize.y) && (v_Position.y > -adj_MaxSize.y); + + bool inRadiusRangeX = (v_Position.x < rad_MaxSize.x) && (v_Position.x > -rad_MaxSize.x); + bool inRadiusRangeY = (v_Position.y < rad_MaxSize.y) && (v_Position.y > -rad_MaxSize.y); + + bool inRadius2RangeX = (v_Position.x < rad2_MaxSize.x) && (v_Position.x > -rad2_MaxSize.x); + bool inRadius2RangeY = (v_Position.y < rad2_MaxSize.y) && (v_Position.y > -rad2_MaxSize.y); + + if(inX && inY){ + // Inside bounds, draw background color + gl_FragColor = u_BackgroundColor; + } else { + // In boundary, draw border color + gl_FragColor = u_BorderColor; + } + + // This isn't working well right now + /* + if(inRadius2RangeX || inRadius2RangeY){ + // Draw normally + if(inX && inY){ + // Inside bounds, draw background color + gl_FragColor = u_BackgroundColor; + } else { + // In boundary, draw border color + gl_FragColor = u_BorderColor; + } + } else if(inRadiusRangeX || inRadiusRangeY){ + // Draw a rounded boundary for the inner part + float x = v_Position.x - sign(v_Position.x)*rad2_MaxSize.x; + float y = v_Position.y - sign(v_Position.y)*rad2_MaxSize.y; + + float radSq = x*x + y*y; + float bRadSq = u_BorderRadius*u_BorderRadius; + + if(radSq > bRadSq){ + // Outside of radius - draw as transparent + gl_FragColor = u_BorderColor; + } else { + gl_FragColor = u_BackgroundColor; + } + } else { + // Both coordinates are in the circular section + float x = v_Position.x - sign(v_Position.x)*rad_MaxSize.x; + float y = v_Position.y - sign(v_Position.y)*rad_MaxSize.y; + + float radSq = x*x + y*y; + float bRadSq = u_BorderRadius*u_BorderRadius; + + if(radSq > bRadSq){ + // Outside of radius - draw as transparent + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + } else if(sqrt(bRadSq) - sqrt(radSq) < u_BorderWidth) { + // In border + gl_FragColor = u_BorderColor; + } else { + gl_FragColor = u_BackgroundColor; + } + } + */ +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/label.vshader b/hw3/dist/builtin/shaders/label.vshader new file mode 100644 index 0000000..093de28 --- /dev/null +++ b/hw3/dist/builtin/shaders/label.vshader @@ -0,0 +1,12 @@ +attribute vec4 a_Position; + +uniform mat4 u_Transform; + +varying vec4 v_Position; + +void main(){ + gl_Position = u_Transform * a_Position; + + // Pass position to the fragment shader + v_Position = a_Position; +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/point.fshader b/hw3/dist/builtin/shaders/point.fshader new file mode 100644 index 0000000..08dd687 --- /dev/null +++ b/hw3/dist/builtin/shaders/point.fshader @@ -0,0 +1,7 @@ +precision mediump float; + +uniform vec4 u_Color; + +void main(){ + gl_FragColor = u_Color; +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/point.vshader b/hw3/dist/builtin/shaders/point.vshader new file mode 100644 index 0000000..bd147d4 --- /dev/null +++ b/hw3/dist/builtin/shaders/point.vshader @@ -0,0 +1,8 @@ +attribute vec4 a_Position; + +uniform float u_PointSize; + +void main(){ + gl_Position = a_Position; + gl_PointSize = u_PointSize; +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/rect.fshader b/hw3/dist/builtin/shaders/rect.fshader new file mode 100644 index 0000000..08dd687 --- /dev/null +++ b/hw3/dist/builtin/shaders/rect.fshader @@ -0,0 +1,7 @@ +precision mediump float; + +uniform vec4 u_Color; + +void main(){ + gl_FragColor = u_Color; +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/rect.vshader b/hw3/dist/builtin/shaders/rect.vshader new file mode 100644 index 0000000..24c7378 --- /dev/null +++ b/hw3/dist/builtin/shaders/rect.vshader @@ -0,0 +1,7 @@ +attribute vec4 a_Position; + +uniform mat4 u_Transform; + +void main(){ + gl_Position = u_Transform * a_Position; +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/sprite.fshader b/hw3/dist/builtin/shaders/sprite.fshader new file mode 100644 index 0000000..a4fb440 --- /dev/null +++ b/hw3/dist/builtin/shaders/sprite.fshader @@ -0,0 +1,9 @@ +precision mediump float; + +uniform sampler2D u_Sampler; + +varying vec2 v_TexCoord; + +void main(){ + gl_FragColor = texture2D(u_Sampler, v_TexCoord); +} \ No newline at end of file diff --git a/hw3/dist/builtin/shaders/sprite.vshader b/hw3/dist/builtin/shaders/sprite.vshader new file mode 100644 index 0000000..f04fc3c --- /dev/null +++ b/hw3/dist/builtin/shaders/sprite.vshader @@ -0,0 +1,13 @@ +attribute vec4 a_Position; +attribute vec2 a_TexCoord; + +uniform mat4 u_Transform; +uniform vec2 u_texShift; +uniform vec2 u_texScale; + +varying vec2 v_TexCoord; + +void main(){ + gl_Position = u_Transform * a_Position; + v_TexCoord = a_TexCoord*u_texScale + u_texShift; +} \ No newline at end of file diff --git a/hw3/dist/demo_assets/images/platformer_background.png b/hw3/dist/demo_assets/images/platformer_background.png new file mode 100644 index 0000000000000000000000000000000000000000..2f221a95b2b01bfa991f5a7b4f24f894a19a3ec1 GIT binary patch literal 4787 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 KAn^Ymf&T@|j!QiN literal 0 HcmV?d00001 diff --git a/hw3/dist/demo_assets/sounds/title.mp3 b/hw3/dist/demo_assets/sounds/title.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..27d66fcb8d94f393d76738ec4722fb8665b6844e GIT binary patch literal 1030269 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 w?qn`mFVo#7&qW5M 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

RGjvQ@q+?^>&wH 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� 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 SX2$hUF&5#DlX21bIzt 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̪RljqiaB2dGu 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 pdhD)1z}ibI^nC&Sc$O!K zUD{+#`u?}dX`U@b;V`6#$zlMCj$c9LiGKglRR{x*p9e$!bkHKk6@Rmp+M8eD1SA|tsIiHtc`#;d0h zy;C_N?Chw%1kIIR%%VA_#)Ch>-4hgDvPhXMYltLk+c<8Z^uP)Kr<$UltNns_Uxgog z@-|{H?Wt>_%fB4^);^x0i%qs-a%o0j>QHU&^fSSo_>Tzw_~tA4<@Qh+?4xAkj$FJ~xh?*_WKWm9ZQ8A8p zD?h)k?TzZr40^qRKCAzqbD#eW3KLdZD{rn3PYM$o(|Z82o-Z2P-2k|@rt|E!fVbqq zI35%_$~~<5Uwt*nZxwuJO_Ml?h0lP%gf4ch15|+>7OC@v=_n1;c-Sx(Gl&ENSj)dJ z=p1Azb8FUN!06GkU-~m{wlQ|GgrAL%7{W3TpV&(Ne&3nSGBa}De>h&AKu6n3puVry z`|EWT+ps^5vSO$z(@dv5X$*@%Pey30rOtwN`ypURX+hHuz%o_##^-q+KhPig( zUHz63`^@qA2MBVznIbs>NCz{E9u)=ws;#g>U%r@V@BjMCKjaw-0O)&{XRGyi?EbD> zqh*Rm${as(9vqhImlp?iXu;zF8kE291UT6iqzZXv%%wvl0O<7m_i4PP$n+f(3D55x}MjEA#G>#NO~{Y z0CB3!CE3ad^oVW(7Ts(AUn@r;kt5`{;^#J3O%01IY0hV=qOr6t6jH@C>E|bYqrW_M z6L%(x(l_TjZud*XS@jFV#A9qiC}uS(nH~@2-M;=4xmlhjX!%?B1rK3NQ-^Q%SP(NP zSq34D0IoDDC_q#Ne~~MylJiJ!_w~>2zHmYx0B}kTwG0_xt=u=^Av;vp&h-ZCPqMNC zIB~KaULp|mi9#7L5|}MqZIK~q$`TBo+{>8VeR^KFyh)ArH>s}`N9D@{{73X zLJLq7Gs&cz7r8tA;AL%1H9g#9G@7WZ(edY#CEtW`#&Y}A8`(|I=79;_s*G`}tGP+D z{FdksH~;`MqYyBO5@M=3(B~vDQd-CVL#!>$!~|eN#l8LnL~Z3j)gmD`n4pTrG*NWq z((ELzuem^g)|E}lSwL->OP4jlClZ^5=&HL84&%Rq3eM6~Z|X0hzz&X&vl*$@2ow2% z)`g8vh`O2ex7hk`N~%1l38K7(L8^y2bxyW&GfRhs!~1T_`d>zw_W}p>tEa@0AjDTmc6q1 zkJYL3Y1@m>WZOmRil+O6UCnlHRxrG81_^IxD4iU&&O)+O>r|?fB)`76GbG(8kRmRd z^D`}xA{DAEf1OGbNymGM7r*>fI!eZSgPh97;&C4oP}#-N`n-oagEk7uiIB!cR2sf( zi`FjQ4xOxT347x}2U8^>mjng(g^>9J){qPrbGh)lL_yual0*VK(W)!5B&FoE7_{Hv zk*c&N!y2BPJ`jBR_GusYEEBVVwRbpL^ZT^qMjRrDOTa-q?0^fS7rmI6(&FGd+(z%` zlmoV(inEe{X>7iO4%T(kn~l%h5xCp68wx>imkQyo#7eQ8RzmRweNn_7Ly zcu;So*U_9<*8iyPT|#x9GBJsI)LL$^42;>Ve~4ca!6sko%zyNixUoV^lhCa|tZVm_ zUWx0AsB~cKJuevsW6roXh$aTD68yJmd;w`H$9g-jDJ@rDOB95*i1=rwrW5>>( zm4r2=G=6xl9x=MkBZLRXDRCNgG-w$esus>$G`-u+MQM6T@e`R!wP$@w{$%Eyj7-pMD7z)lBN^fpW5s|!H94m4 zaQyfnIN8_9$3a*SBs|cf<3(1ci5-K1B-{F?h0Pi2ex^Ytg^Qgs^rxw6T%*>`Q@mt) zF`GY9CB|NSfng@6_MD&!2@2!|$jWX>Z7o7^s9FmZbS%l%>Bmi@k1Q&yK=yHsM@B3) zsE8dM<%@{FRWVJu)GP3+DERTh!8FNKIK@NSiOP{0uC8*D9foLmG8`XVF_*! zi5eyMtuh|ehJ0-7Y+q0cyP0Ky9EC2{O$cY;@K=vNfo^0`BmXkLIBTz@U{WcezK{&(&1eJ;OjZWP2MXFRv zS`0Nz-c-2}8kGGU@X#1pE$fMzi6=T*z(cPr2TITW(OqiCOQj|c^5&d7!-XP(B(!c7Z^-a}zoMfLY>GC>)}!J0K#x2@#U2sp8(Fq%P-@9>rFp)>pGlw+Q|# z=cCug$l0LA#}L{UwOD0OuWn)@QDKB`BJt)wVTRk!@j(G9x8>*>RkU^^h7 z54h>}!^^ybksk3xZpHvU_SQd&CBU2<)4ZkpL9{0p-;J#P-rgQ+S?Fz@8Z-7oOWQ9V zJ0!9AOFr(eN`!^9$T08O6;%bfhc+H*cZZ8?o1Cbr#56I9Sts?o1CcNo zm;i9=>E6|-tBwZ7RBBE;3dzwco-tqqN;+zjJ9f6N94%%i_v2jknDBl#9#nb zN_;;iE4I$;xLebS`HB#jCE-b^&?2kUZ!c@0bmTW0Ro--{*O+mZUVehEEp?O9S87;+ z>3T-0Gv7d%e2!S|8?%xq@m6m*ef%4W*!Nl;gn)<{{|N^R5x3_2nxSVt3YR{P=)~vpBeHkifMm zN%@CcTdnY={6T@1S1%@W3QobjJuAe8-BPwNkh|c7>UhtD-lNZ|$(Yz3YL$0-AS< zn=|0cS$QIEH-TC6gj)64J?gXAb|LR9IUAR85?ShAzux)KATv+OV)9E0G01PcwYP5> zKuO73@pi8d=pBx6ro`l{=If}S=17()EG0+;UlFR$1e^6m=fn3fZO_J}=dtg_Y966Q zIAbTGCq_g|=HoFQIf-eY!n{+4eY>OPfF^IELZgbjtxfOE6O3ZJe_ks?d|8hHgLC!NAWYeGx(@k*t05Tg4h4n&a+XgqJMwM^~ zz&WiaWGKJeWXj}UQv_WnVzFoG+C|EwufFa+bti`qS{8?sLGn^dF8@;-{lBgT{(H~= z0tM7EZksvvEN_#OX<}42W%PIZ9lT2W-zT?tXi&C<-eg<*-Xt3Lk8cD*MzmmX*!TJ^ z_gEQeu!SUQc_HDpSHW>gv}<_ex%9Z4znzf}6IC!X0)z^x137?n>jzkjjf66?P|H-T zAzph?{L!W)5BJLN5^llTHA-sfr{i$?X;+ED&7V6&17(?fYUqY7M3o-**r(G-sfbhN z+PJj2PFEC86!Kh>l<-x|YIXm{bQ$d|seeK3DZ$ia6dxXm6%gPst5J9;|6QDkMEn0&lNCMrShgka;CA(#p#O+y5@UjwiGZbo)_p{fRZ2E(X@PtN!YC5DrJr^NI8 z^D!au2^$KR;EakMuuN z_%s@@2#Gl_E~cYeIBpZk*x0nVcjAlvQSDY;he8=jgP%D^@kZ~H8HbhX+1Mt!2c7~i z%W?yaC8+r?ty_nDCnKARmrjaW=;O@z<&63S$5|7OIgW;ID4|G^xChd}7&umVRS1kU zj5tz2MgTDai5@&%aZ)m((;s%nDnk{wW6Chg4s!c9sKIYs`r|RLnyV6laRKGE(SNXKI6dA78A^Dp!)=e=AEl z0Ipn9JQPc{^Khp|rewj;76w9W?*6c|+F4X|1XnavIiq>*H-Acw>M<3sQ5ycheA4?QO7O_6xb@%~^Qr;SH< z_uIwkH&Bo|gbSVl?eKLwj0RiL&YNd6n_EL~w+po(z%^IR^?hJNJAcl!@MDD=kytu1 zQdyLHS_2xvaUoT?<`EDwsf&hAfJZc(Z;&zFj$i<8yr zY|6a9Q4SSw5tgD4EfB!I`wW&G46Ul%c>YxSN6a({Hv~aq{7K`IZ2`z#7PWRLb4_Ux zlxV%7?QHhBN~O2OAavK2nX(@6cGSWO$pfic3V z4D+zjNP;V-7O$hy*;4471AM*9kTlF;(r{X`h(0ye(@u?$2ghs0m`bDD$R(+)-z$8# zuXZ^2KC&GZTSx9Z%bED+A+&}PcvZ@BDIF?v<|TP%_Qv2xI2?IOBnWGHt-| zi}5e%is67H`z5gj>k!+5t%z!u?$j&JMm5Px;aE{jk&$Jl!6z;CEMp|?Xgr(hVf5Gyzkb*z=Ly#yOO*d zd}=NCKBi7xA2)xSIe#QK+68XWTffZ_q$EjG*uu__TGOcpuDFmIK81L}-*)Sd#<0$& zj%adv99iM3w$5W$rkWLAdkGfw%N>0W+c@Zw5R}oz8J7?)^>c9h8Ohc2rY>S^YPNKLD^C5tUK#w?Rl~nQ0bn!x-RBJyFo^zq zV8MJxRwAO=763QcTz202j~Lrq^9?{Scr(is?z=aF@*F%4hP{|WV{jY*D^jMmHS1Uh zvM-zhlhQWR!uuhfqwQ2hQL;bpvFA~qE6&-OQXbThD>P2X!8fj`d5#3yC`yd2v#*1- z!HX`&!D5x>GvZAik$?aAiU#M5$nDdbQ{?lN?n^)Ira2YOUmZ4mEv0IdcIAEbZU4FI z%fjE`6B2?&-GU19+lf1hIZ1?vMBFgX)X8znx;d~$C=!Py*>hz%zOaZj(LRhYmm>xMIsc4C{g8si|k} z7eCJc1@JnPc*82jz`)4=T99cr$Ft`KP4>>=>GH94|YrZMr+8jBl}c5P(Tc?EKu&Om%7;6 zdxgu2U7@AGR%s-xb_-Fbu10QEpvIv#4cW4aRz@ zwO)GbhA4+KE>wwT2rcVVoLH*Q%^>7LC;)q zhZRPwxcMb_na`0)trc*&8qPS6@Ov95n0r zaalosoN}soCg&Z%*gC17DOScrRF2K&kJ z9NykI95uZ2H(K&gSTgD8CN*#bu^^rfN^2I^6lDj6L)XZg8ioKtF=@!8`A4Qz* z6vuM&*u)@}x7iZGo!PHg(Y9?*%%`Ptir6(Q(=$9aD3)tjR57kuOtpIQ zWeR~X;MDK4AEpnpIk72ZiA;oQa;2unW`29Em&L&eX0VG}DHj7Kog^DpEm>zeh`fW& zP;iL(!yIWhXePEMR;NG1-Up$)wk&l60R8X)+0_%rQix((lm8qo2An%dE9kX+2L=Y zQlLw&l`A6~cGcjYWN?@(Y~vfT`h4^-d>-bts}fXD-2fMXF_EoFg-9f;Eb$m=?CaF`hspm9JduRNxLO$i%pK+WDE z(4Zj^7<=U(iVP|ml9_hy#}UnE+&fYDYLHC3m=`*?P({)R7oeW zI-+K^OSn&6swf;%PVunPD4L%}IX*4K2?OE|r=#0bpC>x*yf27B==#X>nfp<;^n~VpZQ6Rn0WQcTC^>mE=l}WK^rTB9z@@T;s64RxVuE z(lHB9>y&qDb}O&FM`h;s`J4`QYxy&lU(X+*SWbQMt~XCnInfe{uWwRLajyiZdkrD~ z!E^jKDD+vW{9`%&h(3Yzk3yqmrsO}MaM46t^)H1+C;)&>N9Tn)L68yb#?1ypzAS11 z3W6z=xg$zRVy1Q8E1&#Xyv-XS7cc|OFr8rrdkVsonNJbJ@QR^Y>p+nH=7{>rZ|4kO z=;I><3L78S->#D>l(Hpic3b%vQVc64-d)MA&HmVds*E8!Ql;f;^5Nlc(uh zb2P>Q(usz}#&@pPC_iKu%UY0#JNxqJvV56saW^s3dMoVJs-7E*YO#oB4i}xZnH*$` z!awgMj@4)3zf{B#DzadXjQx*Zd%r3|>m0*qGpV}}AW8>$% z4J6nK77S|<5J$HV>fu@}~lF`iHI1+ks^b|*e{#=aU+9PpX*)85!>-l>yS8o{AcfekW zw@IUQt?q%$(*8B1`3(?c`bAmyowt4sP@sdtA=Hc-hjjI5uzf)!#2{4*1p-N<%1UTF z-WN!S`xog(1Yrv_pFV>DQk+5^aA7wi-P!cqG;1M9ip;sK!iHn}ZAYX7{ zOPvEs)}UsKK;aV6qN+Jjs>Q!)p*t6s(==;@_v;Xm-hezSC`Iis<+vdPgWvZx!5)C=WsS*vQ zWZY+ck0Efv(*x6t(f7HpPPvcj;N{bO84z_4=)$R@YkaqL>|SFT2OQqEXr z{T41qYQPo&7zdSvW~w~15zBN8Pbxbh#`1t_!z`P0-e1g?-StA&iJue<5>gG&AWPQI z6)Kxae+{Q3xJhj_B8sEgD{Zik8)MyLn%8uUCG%+P4EB8g@G8%UXNJw=TT94lr9`7+ z^H|C87ZUqr3^g1kqjrzTZOaT}9F{Z{B<4{pyAEiwaLh(1WLt!HE1c}rSuOqa7f9PW zy(x<;a)WcyX%tzYQ7ra9-oy=f<1nDmrY)_KqaW}})5h#iDEKORjG*zLG69nhm4Ffb zVtAqbww!k5isHx{A|t$qz(5;ncvc@0X(9%GFFqD73SOiJlSbZKI%K`vfL2-=J)BuK zbN0!wE}WKkX&O*1=4np(9KUq-9i4YgW4)!!GIF&DiFO=+G|C;v{h3c7B$%9)5^9o} znw-eD>r$OkdJc>%g|oOV%+5leb7)S%Q-d~9O@)+Ia*|=l*-cbrsu)63W;!?Hp+@FZ zPQ_+nHw)`?W3$-j9j5f@nWsb4ijCqs)Nan&O?G}Fxsy(AkBg(K9f56(y6?|$OBY0L zFC+T^SPM_oM@jlZyFXnQhsn+7)nQc9hxANTkpM$Uz|>rh0yG^~rT{BKoCM*d!p}kw z1EI9Tvv2KTv^e={?_=TdkR?j#=y8u3uPC?lCJsf*_tg@LEcq!45RhGSPJH9RHoCNu z+@z&8p@_WO{RmX~My>?MZ(8{Td}udIfyTyEV$7nlcCj@>vPoh`#*4Da@SeC7vdHea zpI5xl+V4Z{@xcNGFCT$L7-R&Z3N)jvVFaUi>K-w=akm4EbjU|O)3%ay+0?j>BZgrN&t6~D@m^<5 zRRD1Jy|NvYX|rB`a++^sK=&Gb8dNs~8F-?7Y?L8X)(YRmR?yK*h(d>ov5L#T#LJ{( zS++m>GJ~Vw%kjbwMG;`J>7wL9p5z50c?cTY=j?bjifPxCBEE@=k(Tl06^-c;$YCpn z(`A80<9M7!Wo-y^LOUeUcO~P*UOdRPSI1SN6V&vI>|Jmy5;_R)7cBb8LdF)v$Y_jP zatE%2z!VS{5KSv(ola>HXq8loN+CBx zGOA9DwWr$#n#@jzn!{qPCx7SbD3TwiR)%bxmZ#_4N>>#$VtvfmpxVCvuXw{EcWave z+?Dz_C{$R^{iEglz}WeZmNU5)i;7PN03LPt9E*qipY{VDFKvn5Woiwt$v1FvE@D(? z*oMBNSvDfU=Ky=oxnOS(ZH3JuNXEQA z<2b@V_J;mV{Bl~uoC2@V%0K;aVN@zlvO_*}!TpU~k^mg$6A)AKCUVv+7_)cpNjR0M z$QAJHN8fYQkA*R64yjDh`w&gx8)~ZxceWIdgCcVtBltN>zCfWX>_+MurKkp7n|;5* z%Tl9S8p75vAnu>#&+a-quG;q#t2pz8KOkH1NnSDQ8C8*ESx$q3#cf8$m8 z;f!#BgHyhCjGbmYVL}#sUxU*3A&opS(E>(@zdMM4HvCQZc}>A}h?(*+l`Vb1s*)`+ zN|i%o^2OG?NExzKGH}Lkuw*-iY?hN-KqH9WPCs|V)oC>5R;)3T+hr2w%w01QP^TxR zDaXV!oY*7QTpoCTE*%M9>>>3|M3HK))Ns(d$SY)iC5$1{d9AClQi~!Hw6;(7`^Y>! z{X~&Z(yv=}xqSVI?Y;*Ivw?>!N$2pJ}H`@l3wU=eXHqS^@h6!vwAii;JK zCG#YPya{A%bkY1JLMX#+ae+QiN6fu5lw@{UN!JQ!f}9`$;<$HT?)&KDTXG8xY7D9N zOP1Kcdoi>oH4SebVyYn47*%R73@X8F-%qF`{NE)^~qBSmt; ze9NK!hlL&&w=eX8(q>nHGl*%jEyN_ zSc9__DrKkIcxL~eUZmMM6(N6c50^-4TJ^-2C1AAG%(Aw2C%-PJOX;a0@0dr8x|OE zsVVvz#l^<-pDDqV0x}uF6L2P&@3f*Dgp7)j%_naB=>%uwHNK=@>f?bj)RHf}$&a%m-y&0KvOnrSl)m=O0)=U%6TdgD#on9Z1Bb}_5w9wBfmI*3n?#xJFT%L= zTU_hnDee|cWNTTAu8mwBgD&>Fx5Eb86dl>G&x@1qlWW>uH)=B$DlIh3pDV9^{ZU#v zSo-!WB6pyy>nXIghKpZ>qO3%}M1KDhyb}AwM~tg45YdAhQ$X*^EmLiRPuOwuHkGrnCbd)VT$hVNm%>!$gk=dw$ztomnnj|W8ii}aq89ytv?!MY}n#)xrs>YvJb?rU~s7I?8?LfRx^R7<_Hky~dy~O3EI^F-3&1#~k z+6eMcJk@z^>>kf0)5Go^nMV?habWwXU$=|nf`mwM9=%h3Y#9^ zN$;Rm#k6pd$}O2lE#VXaau!i6+DRT4W_vV8BLQ41RmUD9f#ydHO$MQ%WLgM~QYcz> z3?4`|X-jmHkJjJ@Zm?)6glnWr5<_^Yt1C!GE+^Ui> zh!r@V)q2y4hEfGnM3nNB4FLhNl;7Xevh4h#T585b|1s5wZUwP`&~|uBABKz_#K2=q zbb7bbs_{Of#WhM=-{CjfA@#7iBoZH{JyKQEmxOn-_C_= zBoDVOzsT&8|1T6P<$uftp#PlZ|6}W4g#v0BFmQG=!{Oin$oJa~BgdE@i8oHjAMF%+ zialDl4*-yp!@`miJpiOQ;gO{WfG{Bu{e9lmi}-N_$mQh=nGy;Tm}~)DGk(|dnX;mG z#d2wCmYs=tahplV+BtZ`6%+9q%A!DvxuMdjB8Du(wE7dap{kc38*5@$-@VpQL#zb6}VmOl#EGkY{|h#(kln4wcqR_~pWEUG2}{!%e2k|72*Aaq+> zTVB_4Gktguf9Ytl5M5cHmEGv=tEfdCEy*n@eXYmvPG2tE82hA`G)?r1RQ5X?1)YyR zS1um9W=iQq4p^B9y9RG#kZ8_58I1Wqe}pCg^9<~qZzpsx2+~sIXrQG&FbwZGr~q?4 za0(@-1b9zOflI`Q`M1eVZxCR5#Knk9mYN|Wmf}g?fu}%>=YFh+F~B$oFFULZ(N}pX zcsg-~j~b-+OGP^W+dRB6xYE`7u>7Ca=Z)co`pOL+*$Lo zwcLdLNHuaO5#6LToUg|SYr5d(M;Ty1Yg~j-WO#OD3%5M{?e#g08JWEKgm%SSS~DF3 z1%N3d;akxYz$XaTC*}=!}>5rEvUS zvhX1;)Z%{_AN~yr`hhc>9rm~1o%uGsm_8f7L*cA7y$e3tNI1OF& zAoMW=g#cTD2xl~OhCVr)kyS=W0dGvHeLyH93P!MrBoc>K*u71y1FRK6T!S9hA3_?Y zR-kgumPmquCn9q>zvgq-C6~#WUG-Bkuz2;^3m0Z$I~6D9kM78^*moJ%5oxA3*~bV7 z?>+^&UQuKPw*ZKEl{%DyJq9Ku|C$|16|ihe4EI<=9SO5T`oMTQy7>J3U6)S3{1dBD zff;{|Cy0FrCkN;6A?vu-g|yMc$|v?$*9M0y_i&T*(uesm10xmkvxAXNlqqO5|X zo3NoYY342vNu-&yb8Slcc{t62#5LC7gb59LGAVWn)57pGvQ7akVJ};C>ST}4WA&U_ zuSy3deEN-rs$Z&jx5^D|F?Gg{>*>4`;iX9_EzmSvxTr_X;q;E?img-wSX0POpy%Yo zH55>P{Nj0Xfx*0zJe_BMV?%o?1`n)Kv?WGq&Dudkognof<1H&9`t6AC>w2@L##dTQ z$w~ToK)plX z=^Z?LKU^|S_+Ai{BRVlgX0qm7J!5b0V}D=e^d(u4YQVglFO}ss@w&W;$S6Tb)Kpmg z@B!9@6rjX({iQOt{=TQ+K+Wt80r(=A!jyZt$xiGRn>O}eBSDe~wC9EPR&-5CY9YFl z3Kwu&vV3uTdlOC9j;+XuW$dw4NzLGSm7bGKO-a7W%fc zPHr!EU7P-D!=I#{&pip3uILTL!p`njN|^+%H)|{D(02m>Lksb>`nFb9S_GRnjZ~49-HaA{hB1Fq(`+i9T+{QpQHKO7Ck91 zAFgm#)r>ozLfQ^LAMG;>12_`~Gp2C3Qg|&oOY+Gk1 zcUiOHDCMb0;0gvcJ0g~z?L$GtMny4 znkFy?#;qmI_qq|3`-s)2JO6>&NoD;kuHD!!T}m5pl4J3h37$d%fRV{lP2ZiO*;9k3 zx9#~vTwa~PD>WeG@dw#1n`3`ijhvBs*N;(Q@S2p-sZW2KzC8TZ>%On%|I8kk>K9b< znlBlj5-#MU`SKzf-14~*{^+j|(@p#@T-ySkAFX5Q_Y3I*v}NPxB3p!`<8bPJ(w=|u zI3NH7BE-t~o(q}Of}j)(&v)=I`@M{TFyq?g5wg~nI+hZ}5Nuw1 zoBy7f0)hSVqUgbFmGRDh`ui*H9G4&#Zj1(dpfl&1OaDuVt1c9SU%TUdS1Sp_deN4? z*%Inwh2It zzXfy;nB89hnuIRc)k)+9d#~feoVpVKd6IayVrXFX%cpq#wZDGyv`a71p~aSmJcq)0 z%lGy$HDh?NM3neNcPwJd&pFs_S!i}f^XpEz4YOP7W;OM2cdbORssRa^S1RDi1w@zr z!Sa0-L5Fqr-w(!*d4Uys-Z^FkDQJPEgK=0#6iE{R+l8L7Kil=|M$_*OHVH{bCYsVD zf%JcX7LHfmkVT(Dr}O=~n(54-HyiVux*8=%+V6QJpN4Slyr=)uH>v&w3dmtyZqwi6 znVnaie0p4tXTUfp^vbpmLl99a*-PQ}w~5=g09yDh6T(bm=ohPFPJqr{wACLN2Ve8fnXekzy7Fz6VoAH6$c>LsuwH-yk{$sz#3L0(O_8 z$u-?r&5ttskeSfd@m#(~w#I(U@XdUpR%p;?2ne zQ-I}*Ci+rBy`(>W>+HO)2>1G_{+cGFZY?F-1bVdVu6QW+&zwXHd}f1jD_7;-HlY1x z7$tR+*3ZwDE0FtrWSB|U9#!{ZEca*ak3w3=&i0p{w|>hIhycirf&DEa1RA7tgLxkk zY|$?k^zoJ~<)kyqlKp9rssE=L#)3~vid4aG{PK%#ou$yTaN%mIDCpi^bgc}m4#+gH zKrT6oUyR4Ln(UYlzZdV)IdiUcoufBleAGGa~?PlfxJ zT%LC;qKwZ1VBSdWxH{MsT&ePDa!vn4uqL%~rE0q)mMgP8R9F5JF+SE9t9K2BNRtTa zg@3xu6YXsG?E4maQzkyAXnI$zwbkCcoDZrGmy8=-u)SYCl*QuTeR8c0@y}?+{-#!< zqgUqQvLX^E89RX0rL4cKF z3Vi#(4>EMJ!8vk40JPDh9zLd80|7o@ToH}Bp5fRZIz2=6>E(D`(#uz7`(WWsX>0%= zUu~kZT#;BTG0dn)0WAvGC}UsrdqG4ZpuT9q?m9&bCH+>K&8x{@%`-dYzRkL+INHF9 zE#p>IlLvD*G9(9U0iwAB;ZYd*2AS7X<+nX#yw9if@hHeaCf5{wkJ z!10^oNA2j7XM9r3@2Q*LYNa@fY2O;ls2pScuK7kD-Wx4USJg9|{e1SGH|ANT|0ewu zE&48$UNf}Pi!eR9!=S8&Bm2ARFXcMN@rP=263=s-Q=|3e2OMrT`wt?K9kUU3+q4RNqtd$o-Em_SXgR<%MWJ{-|?S;@2AOK1V0P|YIyw;GOe;*ww9PS$p8T@m`6UK2g8g)h zAOQ>E3H?0*MDe!y*PniKpDM|4#XC$^Y3B@tU6Wt+35sG}(&{cLQ-p^ZDxL4A zJA+TJH|QCe`{c;*Fnxr8Rg`L2xC}9H#y41O*aDT@dquE`&!VKPJV#!!GnHByq044= zf(kcr8nK5b>+*GaN45+N5MKjr#f4FrrwO} zFfXu0R$3_InI3Ht8Fkj~)Jj#Q8Nw>{l3l;>=Uo4NpYHtC=u+Qj{$tt<>m|G#))(=M zy@3FiPfUg_sW~mPfBml?;y}PPGAc?L!GVdcV}8d^i?Y@@hSJJaKHbf2NK@(X>OSlx z1}TI7ZB%;84i1WnpKb=$!nMc?)5~_bMt5I<(3qahdvJR(;rD7-$DF z0snxYazd$1!F0T-^CZEQn>o=n{4i?4TGgqAf)B{T8MRgyD; zXsxFuA2>fsdmlGDF#6ga{n%u|{);G&J8$PX&=fY^pct}KN4P_FDYE-B_>V`;%lX6N z`gy|cV`nNQtt8XVRe6{P_VL6__y?9e&a-Vv097dB5TRq8~;-2Qsa zrwT{1iwotC_|mI{bQJGHBD6~3c}r;JQzU&3!`ga&dR4d_yq=Nt6&rm1>5XDzWwr&- zS!N}RlWRTU&2Snno$~en>t%M)(x}lf|J-8JF&gN(bzgH5A8}3E8XFp~D40iLc_7j^ zZsyCRw5H{}-bz=Wy?pR{u&318am9;b)+eO^=ejc)t*`NBk^JAxD`{2vPjS8_T>JSabk3^zn> z77dsd^{zYC^KO?Jj0t_oR5AlI({T}m2C6Fk09r5TltS}X? zc;sWuFSO1NWy}q^vhT5O9Lzkw{m8JnZq;|djG3Oos47K@k(9UGa$&B^ef|3Ko{l~? z$#>}qB~+vL%;s4}DrD5&ZX1j<=71*Y+-zGPVrRY0@6t!70n~M5)@Yn0-mGn`*_C!m z^Sd^UI>!@&pOeR5|7j`(PfIhU!99y(GZrVNq5>}jA_gEKi35$+m5+g# zOMF9PtTZ(ZvbC%HLa5HCS#;>$WO>XfNb$^R5wh;Il=sIFm-g~SYU4BW{OiWnFFzFH zz4m$MFQ1z$Of9SB1-&#%8+uH!eRLVuM%2C7G6wp%05hJVKbM%JjkHClkX4j3${q74 z=Mzao^7D~>Svdiim|+0y1oW?BQ2W~ZHqC6-0LeP;G{Ux;C0)$q!bu3Rcj4N?*XpM- zZd@3cWmDyYy+NDX4Db+s$gyh&%f}_fOW_8!>1p?p*vqm?&@Vxg>U~OcO1PS0CUO@G z1r9cvw*QU2w}6UkUG{yup&_`tHty~kTpM?HcPB`KySux)TY%v18YBb{9v}pbT=qKa zy!Y-N`|W$qJ?D<`-d^#;>`eSp&q3IP*0`X7__ z0BZyvNvhC!eV}KD9SZh!?M@aBhKgKZwBeySTjTQd;A5G3zEB+P@-O`8Y>=3{V{WgR zNKy+kG=!2cTWI7DH;VTImDu%meh-+qV=HgQE)C{XuFa%=3&CoVa*k3)e;c^MJLKxoInt9xXw$7cxH$Bfm*dJ zEPdic&bkJj7eLN?#v5O1H7h^ZOf^Ry@P3^JSDwz4D5#z!z|9`hn7s#=o3f*iTdM6< zRfr-sV~@OXEgzWe(K&@CYfsrrQg+hQ z0}}CWY7`4s_dWyZ2)@?&KOb+(=4{wnNj2H#`(%=WqLQ1PPng=)f~QI+daHo zTzq?N4ZO^%QSJADN1Q1GZO8=yvZ>BFIk-|40I;7w{v#j#PuA;+lEM>}E0pMo`&@+(#6>H7>G5kq*&rQ>Z7iSl z*j=-T%#W&s&}1l~x<$aggDdI1OLKz;l+?l#Tt5aT z9#Y&<2po>FA~beP1HuSwCu>BE%q4&XoQF+N7?A z`h=`HZ@KBB9U9?MuZFD7(EN6t_fu@c({igJ9~CNjp>m$OK)}8aR#>p|tvZJef@!7; zg}qU4oB07J@A$mB4>&;v#v`^brNoG?#Bkq5x0cxwxoNSe5-!9@W)oh12%T4vC5OfJ zQf&BjZ<__XdWAwGqBPZxV3)ptjyIW@;s$Q{%2Z1h9`~f$KQ68IA5ek6d&wW7fcm_= z!RFZj2LK?0|5%$2dl79w$2N{E3M%}9-%$}uM7(=^61_buQmcSApEWMQSD?Oa0lvB{Y&4_c(9SZZ zx5A=MOl_F=FZCsVVTj$GLp0EKwrIg43Y23bAj|;h8lyWKgT}XKNtU$8ctmc`yYT(^5(0wIW5T`4 zkPtIWDSH_NR(2bd*1bQm%y8vC?E1sLEMR3=L(SN!lMR*zQC4PqDr=}2AD=`t z;!HUw7%~&akM24*V8H@We$3D7r3YjlZN|*SAdR3Wu?#{Nykcu7Ril_U!a#f_i;PU9 z%sHLo0bw2h3}j%z1R_6d!$?gQXY_PiiI@tLff#?gVfqowv>(9nWp(#js>)?iLU-rB zx{JyfzV#AX`})}ukqwWi#UkJ#ZSXl|lt#=_bZ@+4@{s+6aJ&=km!B)Wk+=blYuW+8l$Y-CN# zdA?LN%TDzyBu7dfRzOQ1`S$Zy3Lzq72^9?aKYo9CNPMuZIQa-al^i5y}g zWthXVL$k_Ij)=~oPl1$K1Ns?tPY?q_4~c-#VxjN<9F&_?ZT9K1E{nhbJAE-|R&B}; zHWvo%IT%0~z$Ro1__jBd*GpPy9xM>_OJLL(IQ zo|VQ2hi$;7{Ym@z^Li*xcu1XK=i)^_UFv8$KOF!7&rHM*j#wsv@KS!LUsr{N;i%%& z^C&Dw2s?!HgA{zgJo8(HaCD&Y#D5lTX=*+3XWijd63ORL--tYHV~N!39p3Gc z_r~THW=)MIv4+RB4N@aFER^Y9r^y`{IruN_2)V8wDeBy7#yG#Q9k3!KBfP$Qx{ zHS9ttFiA33oVS-gU_g6vZiP8Kx%BOh9R6&(7W9AHdL-JvMD8? z@n4~%xr3+zSxpSSH)4T}aK_5ovsMyhVLJ(arE8y0D7^1Ag_JsX2{N-)U$<^d$_qr)0E9s-<&a=lVj+D>jRDc4*9 zcJC7_-3`4|-MFejEe7(jFX-P8l8zu2aT#2QF2c$jB9r92N2TvsCgQ zl!0>i+@An7W66Xse1N$7mRZhAdVEYa8`mbns;LK#x!h&9f@N&G7ev5q#!#L#rWSqH z$b=)^=&B+&?Dinux)2-j)4S7ngFmxXOPb3pvtzC;mH!icqU3mE6-UbPTJoqG|H}Gi z)slxML8lImG;e%{db*eyqkDgaUgULP7BnZd2RWZ$O56!`HKd4hU^mOn+vntb;$v;; zsdH(vvTU7UL${^ug%^a8O%+9NRuX;k*kAfQhE#gsW{0JLek1O`8rlC_pa6UQPHj;M z$9YTX#K&fLhPVq}Ug3G3v0aqTru})I5eWbVlpWl1f7r)BfFw$9?!c93+c=KRPiS$G z5)ikYWeXfdDC7rIYPYJp&3NYRpMtGFLp>tU&GiAn^d#bcszwj(2){7-|=(G58 zHkV)`hP6l%@<|C3&nuiDDGdTQn?NWoKh(0{Pv-?UC%;keZ-zyl%Pj?{I^X3AzX1g$ zQ>xtYiqYW^=rwV=rcO(bggd;ao_Qq4wAvoWVbUP_mRsJ*KSqFj->etz4_oNgwhebC z6|_O<7d}wO$!QNeLQ|o+OIZzcmCxL&GvFdQ+WIL^v3uq%(ejJ+&ZSIs&bX6LekEm9 zkU>B%s8^mAFEw}g8u){f>_R(ptBuogFYPL;wJQBywa$D=oVs4c(}5M!(L?Rff+GjH zna&B9*7td)Wb(j;XYRY@v=XI678+%+PbH#4|8PNKs#MOpu}G{D^znyZPu4>G9|nI3 zu_*%+-~g04g5JS=^%yWf%mO`1#OTyOwvb=Yu;V5S*?1)t1ySMP3X7*{f=`tuo|Wex zn)vq$AQ!SKCJYl%1!~wVT&wqBh0}QrSdfpD_>IOdA2M*4+;qn&2o!v8|&MT0l%YO5Ay8w!HR$ZNzPZhNQd1rSRlnf`vhiY zP0$GDJrW^RNS(cDQc(~+QBYy}S57<6($MwtwqIkXae*A2RFWa}^z?xc_3l-p?LeM- zNp(E*V|>)4+OtrH&3wjD2b^#MT-mc|E}}+Z+GH$7*A7iOV`;(Hnx%f**HGu&TT_Wz z-4ZiOM8^41rEad3&bA7~udU|#!$^VZva#@B@5I;C=6F%fd|eFdaX=7G#2GKm7o%es?u zwQp9eJnqBiLk)5uG&<@FLZMu)bUe&2EMZIZ7II2lIVTtKfm(pkStJ!cORsZ`4qMdX@ST3l? zcN=Z%Lf$NcZ-uY`un_2V%Z(W2k35)X-7JG6LpCqT*ozsrzzvLy- zf!V9f*TVdT{U(KnbUGt3#;bSg$f;Ox@O|Qqnm)s#hvIu~z>h<9KY(jX;Mg#1%jc%7 zW8LUm&EED}-vvb_(aSBzan>=2b#TdEG`OiUkJJOlHIUF+n#e)wA^h9do6~BuSF4d+-gFFw7FcLKhgHBG7V#F1#L`FqULv_Wf>_fS0j}O5oy$h`o0Og= zp)JGpH5jX2PDc;R&@_#DjlwtL{O!j&GmZpQk|@yL;58qdqa~Q$uQHVI9a97SmZ6UA zL3d0KbLPt4oL38EU0T*^uFbbow%BHWoFNN$z7d|UER3>PU|^%RzGDl&?dN5`ZqWA` zomrVH_Ew){y{3dVP4HLbFY~X4;HcEdO-^>4)g&vCd$e-1FUti|Nbuz7%shDBk`$XF z5vM{fpDLPD;5Ni~_iTBlUgy6nH_*cq?v||{*x2hi`(Ji=`hPv)|09M!L;>XsPmpr* zvnU*1%3(Z<0!iRcL1sY%y}8%rp`+2&06=plE}yP4H(hQ70xT9BOacZx%iJ!CwuZJ4 zhu&R63ZplDOGqEIP3hEh!QzlaQ0;lq9S%laVQ)#kT~#9*QWZd#bs^-6$g`cuHD(+` zqUK{nE6BgD>E_8oHY^!&zL2R16^EfKb?AKNz;s5P@#_YBO=5?mC#g@WAlm`GWYC>ov3a`145i1uT?c~NdU}6qIi8+% zHzpLdDdOA0Zr!M4HPMAr0b$f`Y1b!`t?Bcmhx$nN2!#*+hCQ#gs#f-WTz+E#fL83x zt}O-jY656jNVI5(U`h<5!XcuDss?RD@$E!1GBs|on4Sa)qm~ClCy#KD28*~*Jf+OKO`$;AqNOk8kVKDnmSi&B$PE@o*>4|vd{BEdYR7K&e$i5wQ)dl2TCrv{i@3`eaKI(PghhzZ!m zB^Y!KAMmi)Dz7WB&wD@Nlx9t=(exG;_sP$Zv5M8X6a`FsXE^igffbJUsze?5coqgq zxQP(#4L=<&%WbOQlbo2IAPn30S6h03Yf8-UPuEga9T;E%iQ<(3&I@H&S2COHoegE~ zUR^}^l_8ongKtU@sm8vhF3d11_$NOnYQllr83gz1-d&AU3^`mfc?Ekwutt=_nE z(&-g{L7yxC3uz1g7Ab`D*eGFU_&Oh+)9t#UIuaBX%PN@c4ytq7(A5ZP0{|R6NytJY z9Nq<^yJ~lPO5e(o`O2W^k1Zh7d=|gni zAxzWO2p)4%6{RM9pD$Aoto+KqX5JDi(W@g|IAw$Xf&IXt9*Uv`UhFL_1b;YGEo@+6 z{dsM7Y=zuwRcVYvjQAzraja&!R^yI#zB;ow-V8r!Hb}ENv=xhY7ZaC&E$OxIbl4Bo z*3~4tdHA3DdmUj+U51U|8r6#$TR)KW)V4gD#%&NH{hIv6 zGZr}BT1;#hf~2i6LVh4+a6}`NBZro@1k`;eR8DzY5=S*fMOtx}L}!_5+wbD&rawyL z!g?QPnrT@9J7aj|u50VL^m_j;8~MJ}uAXwW2=lRX)CEb;y~k8kyY!Rx(mh{eT21}& z_N_%QZPL!vfS_?7omZRA&tgaRI4U*9OM8nI)2~q2#)nzGrVnxIs3Me`xmfYU59gUInhKgLhT(@bXnc5)$P`q{oLv#-ou2*p0NaX6d#9Y>j2xAh{dv zbrf5|Dxgp{qT7z|LK8JZ_7HrhYra}p^!nTLLpErIs+u7&{Vn29KVA#0yVn{l`&Dy}1c#=oLd|2=bt z|B=Yx?_cw$D45wOs#U&2J9D6$@L<^`tzD#b+}D}>-erNj8O;X($N=ErzCnT9UX`n1 zhPc56Y*+A`+*77Xc4|%Yc9$M&jorjgoU^IiLTPAJeaby{pZq2(f3ZX=kDkz{w6aO# zgBoVA#`tE-kMxKTTO(%p6@W9la7uj;~H5S%44>s*S+lhA_0h%z-k?h0d(lwUN8 z(z0EFlGHmEzCG=$&DBHC)4>2Bki=Ld&iLlU)H%)sjR^Y{Iun0#wP=f56&Y|4%Y|F{wIRrGT5JypEGZ17KL)2hadf^FDjcfLsI zxfNx>%(XCcH;$GalWlc$q*Ra&qfHZr?nK%!Vw&Gr7QL9IOulU9F%0)|pk3(LTC0vm zynScT4!$I@9`^8=_LNd#PqdSrW25=V)6w!wt*w~f*B;puGmAWKm@F*Ma*`Y7lz~l! zSaf7w<)HNtCd?8SA>|gLd8`R5>SZK2jQpYFv11-(+LBGidat&}TMzGu=MRG#)=+Ru z=3s;Bbg0*gzRq3fMW%1?k*o)5Vr3F|fdenK)oBJB*B%zs%x|CD8!w8g+RYxLH89G)Hf`TJl-FtcfN^%f z5$E59Tj!-5;nSRd-~6a$r|>GC>r=O-wZKs7krnagE#w{Y7p%@a-dY!FRcSWnj;0|GYj2 z-=76N*Y3X*JV=Y6Qqdfg5wv_?qvLqvO;VadpLHzJNm6a_eg&`ltjXL>;$G8aLieewcO> z@Oy8>lJ-rt^K(6y>*V{liZvy}v&)pY1lIHlZ+?>Fz(mrVX+CX^+i`2{8swC@%(jbt zpE*HC)pYxf^G@#Err_%EeS6IGEAONpq`mifr|8!~8AEE$&9kQN0?eKN} z7>n=kh3W|IKL=kNd>g_ODk0wN^?uG*U?zt)iPJ!frD{ULKn~hgR_35)a(|D63{#dF zBu|A?!>DDuShfnby|_urEi@d@k=cE2jOCGsKNjjWnZZuysf?McxvoAXI|)VJlG*`y zMU=>k)@eT!b!WBfW-~3wxV;(R>YYHI4u?|^&t+1V6Gjj%J>HG; z1=iN`b>}o5wS^2Ch8>P&JKI`283xX+A6uLbnDn>nL}}86+NpuJ2??rex1SO=@vk~WrtG8 zP)-9mgREWvz-1gW5HW2^rrz@{4Yz*wbxgj3LGPRQ<5zx7)oq>LU!-#S!oLgWv+UFX z1Z(>dCYe!t&V31^0+$zb;yJp0=RD8s5H6d~c;pj4c%1CTusA^|^v()4KRSmj@hvP% z6mORh80OJ_X&_i%%pRX4iMEDt9XZ-Zw!@Z%eLo^bu1hm)>iskcFb4!c;l+q%g>U8v z5=4blqrsM$Lmz@b<^#acAR+)VFdP`vz`QSGjUp;bFt1uR^}Q=uQ@NQ4TUQi!-&D1g zDuJREg^$0g$S!CKj|kH}G(aYid1ouM%~QgJbcdl@)Piz0On`&N+6%ifjq+( zpJI^@S7(l=UWJ0G($x~>y)EwY4p6xkf^WAme<e`Nj7)sZUzO*g@S|b$u?-s z>9AoIpaxm%kyMH28gWI#FJ&wKbVXqsuAHwb?`$8+hm6)6^M4rJ&GN=je z-$j#kFlQAF02eecp#W~t(bA$YtX;E*QohQO%@+#lk1Y6`9mdAq&HqZNt0{q;>qe`y zDIq{RJf$S(mMjNi0ixy2sWPjrqO`IB#nxt>sv~4)5R72O5gg;iZetiJ{o7+b?4)dVRmtGolXZ3M*iO1(oYCG}6 z*4JZ-x9eUviNB{g(A4|qId{kQ$H4ATVCaBvXi!{_#v&NT_c9PDgkW+28BxI~lPYx# z(+_OGI_Qj;*&8=jaM!6jxh1m?X@nqwrTvN{`lFS^jPj>LSkmQqE#I0vVi+@r!3#Pf;PGcTuYmn zPF9X5KU3qH&qjlRHHtK&BdllDRN}1U=^yh`+^gQ*5uWhp#jhlu^YVAkb&40+Slh)9 zuDQ9B^E9;J#!L$%>{)S4z_Mk=ebr%xGrDBn8TekAK0qDjJ*G7?{9Svu$SNKd70GdS z#pL}1LRh-Dys`5q0z+KN9^{Q5w^X1HFTF_eYBnpOPR5JUJ3zKn* z$>&An(OHM2KazWg%)^x~NGx>9hALy~DruDJr1nKN;Y2`Ib}+|u$t(>cvdOGNvu+|A z<;Qf=<}uA#p0_1JLiZUb7wDo4#g2U>*@?+qLc2&=5*u4`uB$qv#IcdYO#+(Xp%ge^ zpKF%iy3QjG^-Xq9&LNC@;X6*^&0?D6D5!M$L@~=Ix#!c+eq@us8gh(R*&?e7u6!h@ zAQJNv9+b$Zo_Q`HtC2Ii#AZA!NhYU(aUc#ER-;X)r(Q;B#)drmpRLZ>qn(+pQ!w3z zi|O5ngiXM8ohnW?b?DkmC(hR$xlcJP>o$*m1z&`re0xzQQ*B$#8&tC}qLjr#!G`>U%|B%hg#uoyAMFKB@ z!e4RJUwnQc@J|T5h{8XC^J01-@K+@8A_{-SQGfCIg}^@{@FEKT1kQ`;g}`5tz>6sS z6-WKW=NAJ1gusg^{1Z4YrWXQ#MFKCP@K+r57oT4U{1XB%qVP}PyqI1H{1plOAqwyb z|8v<^Hm;&fjoJWM>J~Nn)&>9|yCyecU=itzqu&0o9x90k3uQRC`r{Y|9GJ%|x`hsrD4v*&AHZD2UiOK@?c93Yf^aY>mn2&>|xv@X)LY3Ceop0BAfB zRuSk~G?U1PE^-Exg0o)NZtjD@@44aRMD3LlraCcoJcMax46&2fDdMPmAEX{R!d&xus}Q!5n8f@0MRK*N)QPi;8(B+ zgoqLgWg#FS3<(JqPQ;H>FBl5+yn-}A2L8Ffalk?oz9=sU)a#gN3lM?%sQRD``ec44 zg_B`rlIv^5<&BltQQ*l)OcM^eheIz5@n9q>4G^O~e6v>PwwXCMZvlz{&~`+L}ue()Oz3g(_~XSj|KsnSroW&I5fBb(F9QajVuH%iK)Q}fp|NK z1!Q;y?A969ov|?)5d^T@tTO*M24E0?#5))XA~}z)?eWUuTk1|bGil8kAKF2W90kUd zg-gd~Grqo~QA!csJK{&4`5b{%gEo@)s}iAsMP2VB>4NCNf9rvutRsQtFaJx2eLlVa zf#pqLVA{_C5C9Ji{Cr2=LIB{gvht#r1d2k4h(I`KfQw*}XWUpgV*!8>G&JKrAi(jG z6>b0uD2fyUgov-T@bQrhq`K#>T8-&^tw&&xhj$mIR4Fu#m7|QxhiO z`@mG++@qDD0L%mF6aR^I1phx&l|Nff3tDJ7T7dyyVye!k_5q}l2bu=u0nkU?Rg*23 z03yfNr18&XTkn6Myn;r({5G{4@=fF2sh4^bQS+M&^||2%A*F9+(Pe8?AnA7>m!_jv{GFmcsz9K2*{E`ch}o47XE^iR8{!xFPeFjeFlq$PKwftQjY8+LDnZ zbl<;-o$-BM=j@$HF-Hon0_T$}=>+UFb0dA@-)dE!(UDSrT2_K?fR$B(dCmFV>9*u8 z+aE{Zas6o^q-7O-b{&t@PgC48MO{F(4SZj#6PJ-h4kN``or@3x5v!_ zfklTS3sy;*I9AgmU6k+qyV<60Y6mk@O^V+?HzIegf>HSCElE|h^2#LY#R=arsgUY)p}jUJBSD0uR%d<qN1Ea{Y{o5Y|)?c|2)M3@*b`Yr}xvkzj-7#@;3Z2g#J)W`QJrQ6B+*CW1l} z-w32rYro4wdzT^g7;9EA2Y0*F1|lK@gI!Y6xt99tGX9+3CV2>9(-SLnY3Zx%6Q7A) zO3gS{WKW5U1Z-P7Gf`Z5Nc%p!is`7CSE`puqqRk4*OV`DWy}^%VhG|^u28vq!WWI) zKl~>B9ecXy^ZVydKdn82WDXpfu(mL)W1Mixm1-|_@Y@>2BzZ@y9$(&Qkm4@oQkxaGMs>j=A);IppZN@$~TcH&bDID9W ze>u|U#*-7Z^yEgKSFR39q3FrX?(zrPBrbV1=wnUz$t?>k@nccrD$2Bm-O8dBr978S zm9MzBmo7dAc8aZG515N>j_ot0+AA%`RyPgpSNct)y>&j$6~}k?95nTHkPaC7VmMJc z?v$J*secg!0KhbQEL7NX?_=R(gT@h+_mi=WW46tcH;EL?!QEY)6oBV;W42Jh#+&U} zNHyXqvG>3$@pC!-DMGIink8E6np1OZ=Wx;iRm{;^m~amvL?7N=-LvqG6)J+`#@vSA zA(bW43nd0(1_OGj&R^S0Ydne>cP9$ncbUp0Jk+w5s076#PMUt;+*)zd$ibb>?RF|2 zQy^d>5U1_>^o~57X)bDhbWo$kot)B&EGnD8g{5w@h1fV8Y&Z|YW5sB(w++kD=`Ul< z>+V&k;3?a~8w^-4Mp086YY7 zi<)T@)q->RK}9C$GpFsPHrHMpM^!iG-(#v$myN%HdM}qH;ZHBQM72rPsfF_7qdTh0 zKEqgrt4O|XF0H{=E2cI?8&}QJ?_}v_>Ru2xjlz&}k;GcaTDay&Q+?)?H|)UW5Vp)7 z=+`~$okee7=xl0dSu&EgWzdeKoG3Hw#$c~rlsc`#gk8rUiXIBvm%2$E%Ufh>3FFrK zIMA+hDelJ29xJUC{Ta6JZWgDtkn*3FOZZ;|FMo;xiPy3k3y$;N%wv_s?hL8TlbnL! z!{GUA8`<)F-e;m96`KLUhSWKx5?PZ|E^wOKBI_NQuxcqtTwP?80eM!#E)~_ANW}^j)HJERS*Gu- z1}6fxTeG%9i?@fNSg@K=JxcULHMqESEKD%4(qdX1ahmv3Y!)+{ zRChN^AvV2W-Lxxd^E{a)){Sc=-7&m(+-;NY4gdhqCClNi2ed@m5~;##mV$JYAcLDB z4{|AD6Hv`I^l#&$)BwzFgN}kDEHWF2Dyj2(3OS0sYo#Uq^ioudY{)d!UUjb~4kCHq zr9{~dMx>-3Qt=l`256`*ywicYCc_`5m&72e z`l5Z+S#y@xx$3viB=9y$Y8pPCNo77x*(17R(4{VEZKGPy!ETXbSBP^fI}4Y3 zI8vQ?kZnze^mSA07j>rIqpmL5D{ajUos;fX5@nN`m-KtS5lm2A8~vprC*@T;N^dd# z?Vf3{_LQJXoenbhYrH?vlatJF`}_wvu3+Px^u#b9kxqw@+3O5slijNE3vw0bLm%a- zNMKL4nuJJ$;K+@o%q(H;RV4|HRsePOp5AQ zgK)q!xC2^o`)NIR-j@BM5kOO_>LEVf- zT%1xu&J{Q2!SCM*G4EQ~1f=h)q^U>O=vWQ%lqfOVTz;pjCgz^HOk}$H{X%p;^%<#3 zMNs2>-Q;X;5DTZ(A@B|^be7S7{<=|78pjb;d-f1o+qvMA$hOo!d<~LB#gHcemV&#l2Z}a2e!+ofWohFn{Aj0W%8l32Z!=O`QP@z?ogTOoHqKSmB_OQox7F1ju$8&H5Pm<&?kSXv zxq@F(t|2*1nq*a5$4Dz~_BtllN~+(zF=|WoCo>yzK&YYOX#n;8)ja^W)B{2z)t2INHn8ZN=wQq8=T(a6tQ7rDJGHKIjt zXHu&yRvv3WhFHS%OG(zaPF}8Ynh}ZmmtNwU;%H5s9!upZ^?60D<&JMYt70V+GV-!< zD-*K`7p3nVslh>}0LggdDbj*kRncMmILFE=4i;Hs{)l38v2mC7uoKnLj30qg!MBjy!mA2xTp{rEoviPhF#2c#yuDQ z^+E+LlF}p#ht0$r#LR~hEA~$2L`6A+vo_)Y7^`gqr2t-tEs4?%VwBUeY}+%UnG-Dj zkuZ4=WMsR0LtIT^ZzfIQleBI?7xFYBOm;Fv`C#)s(>3L*Y62=w3C?vk$#rW-=Qv6m zZp$WvbWw|awzOH7^$15fsqi5@QnbwFShC5hZF*yulAoF9r^$!ssP7v;#%&h2$YSES zr<%Z-?G{5-k2>IS$seo_&;DOObHmG>J=bzB z>!&jaPv?7%6aZvlC%NH0G()|_nU@@F8L(-hQuwe$AU@*=`5B3Ro!u9vRpj&DvMb@vP3_M;6%r#2uRd4A?-Ch_ ziuWjMe*?B^I=`|1#7bWL_>N3q=&fi7REw=V?UmY~oX#&l+E>C|C)9jP?>|4K#IDwAK_9&MbMtW)6vxvvr)gKm;xK2+` zAJcx{*4Q<3DeP}H%Vj<0KPgb!{_6Qf`W59veOg25+OwZPBp&rMp<`jH%d^?Q%$PpT zCIr?o)@`y$keHz>jhEsq1SNf#gBwj1gf*&c0~BTud1-kly3drta%eqnV9$Gb5Wtibh`@22QuHsneE#m?xuHYz9Q7* zm<--D3OxAKm4;kblHGF`3SH$hDT(z)Mn+5Rzgx`=GOL`Z53MNQC?mGdQ2Q1S(5}o93u=v1KazsrvkrdZcPf8v82Dk!4k~&ya-94{8WJYmU^1>2(c|BMy%iX2k@u8XA)QI1MU}>EH`G zV7&WeH}c>o^2XYJKjdp!Bf9DML<-q~npnn8N0Rq6Xu73@3vjEvh$Xf6B`Mr1HGX+Z z`r;|s)Ee6Fy*~~}J9?MuK_)H~xIM;HRtRiSrkdgLXgCMV>zh|hr+Rt`J_Z#{LH`(e zM`##!BbEM9wkiG)Yp@tqT4f3m{KF2^tx#ndy&oHg77zeR*(BA-{tmAgF-A=e#GT6_ zdhh^aEdU!|OETw{nScIdmm)Gv1!BeS*23ILOGASDiP(;JaqaoL#21p zg@?1}xhtw@c5R`ndmyq2?;WLUC0(99sf!GfZ<)ciBgrv#tRv#KQE z_xb>*jI47jjue8s!gP<>+s*ML8!qs(-;uLEyK5_<>|@r06N9Oso|8ID_s|4YY1oFu zZ+EKp;qSH`u=Hp&9Ihb|qUdkXN5fRUOH86IRN6IxdZ|6p6&t%3gdN_Mxt^sYUXXmF z&AsZUVbiPNdY9IP^Ugg&KLBr`(&n?vS{Pc@yfZODF@Q^sG@xyvgcu4fL*!twX)^YscdT$c9rPScmDzL@#E`cbqr#3L|2cpUUN`~k{qHSC=Y>z8*OOe3k^ zyz~~ZHZYBt4(z3)9Zo{;GBPDv8aAx+FGAYxduz1-!(yOAN99B~au#yl%L(C%Oj804 zCQp&{p_u`?6`m~V>H3=)gQO&(!7U5SUS7&W1`pW!>s7JYi$uhvZ2*v4Ek#Q$!o>`a zEQqOOi8lq-yP+ihk~t-^A*^^VM|5G|M>YV;EMQl$qgM^)a>SwYTv3xAUVIbcN!}1f z9u-u!iYpTFxNs>6ICgvm=2S#TSb~yFIyOIUrIDT{8g}GYZ-txe*+3*Cdj zsx+-Ex;?btoh#NtOqLV}W_@qlZW<@n!)bF6S7)&uaBt)HM>=pxO;?UzaGmFGV{z0H z;Y`(TGj6ChDXg$1_|9)#gM1Lem+^^+8CNkm-91&eHafQ4s*a~ZdAZR<>VdqlNO_L4 zxrmG*#hc6d`O7l835Loc-o_ZTew+ncA~|S5ZB^-eTseu4;wndq;A2-I%03`lp9_t? z5na%|8TaOGIRiGR@Pb+ZU0WPoQdG?@x+GoRA$2_h!T93Q13b)mS zUyoQg%(Y`;vO@Zp&pKBRx1FJYK(0oQRa>KBZix%oCzn$b_IiM5$}tWXv0QetORiRP zcx178m2ipH_G3e_U!w9ntu=wpJX-36Ai;lEMDX`w@bAz65Czn`XzO}JZL`ZO2kad? zq_@xiF#n&8Bw0~3lNl=d7CDh(;hPy{Mv~b;F*4WVWzh0=h(C$s&A|v7pl}H%h{Tf| z#siK!vuJP(rE>(L^zhp`qA#hB{slZc7jKP@V4=LVq6J-dFqdW~x4*VcdrY`!sk{>_ zL1zpNuECelhJ!YYHE6Y)wg_mIM!t_;P#&eS+k77tS%g+%ONKTPZim}Rs^q7{#4ndf zeurMkP8l!eou|&h$%H8l-d9J3FBNYIojxUQJlzc2wMq zRcVq)k{cgFG^2!n=e2!rueM!#ZsO^!M3;`T!XR*oLI2%z$35> zOf2NKh{Rj41Sdw4=y3MgIGDUEj2Q=3;Y55&ib%*p6;STO|0Br%J9Om%YUI7_`iRWULOBt2>hEUT>j5#3V$aG|EGoN zUk2ujBQFI06$reD!oR{OzWDG$;J=Z;OEI?pMwl;$dLi&HK;Vx+0WOTqdT|j+-g|_J zz{e!giCnf+g86u7QF8X zQ~g!_&%E7V_uC~vt7AAcHC@>OHuQ0H7~9nudXJ21S<<9w9um$uEMECcj>iR_BIU&qtT#JKFTzA_yepJq#<4*vM>0z{-sfNjFpw zS5)!V!^~xeg+u!d9AcJ5DUH243@drEP;(qUlYl}hy9qA^bF)<-f&Up6$-u4FvLX~q z)=k07D8G!!B>`+fKLiY6=W7PxX!eU!cv)FJ3?5w0Llm47qX}hYoq|K)fIvV`2Vs7@_!NA<1X*ZweT=H&@Jtl=^&OzxZzE#}|VFzP4Psl!+=UoV>+whs|1do3BY4 znrZVH9YYTqA*9gnOTbIf@#_*oQ^R+BZg9szeNf<}F&3Bf{G@;$Js^II0_}4lM|jSZ ztxef;`%HEraEiCChT_5&cEg0N4YjjlU*>?V!&@%^?k?iZH7jG9tsQcnAnFhs?O?$L zqrns$(rP9D0F_1)hVv$yph{>F2gFi~+m*<{1ZXlyi8tm4T@cd*?c!SU2#+HIJ1tSg zTkA%qElKH!q=Xuk-hok3efw!8y99taz7ckvn2kPIo;`%Hd9)!ow5q)EIyp{fTm_XT zY|}z~>*R5JgF(imh`5C(ZkjCps;8auaS>rdv_~PmH5o)F_cFrj`Ov**#Uv*CB?iUu zqe8h_f?uc`+CNn;5-H2{i-)ArC=25k-Nj zq%7PZ!jeVx*^$A0W$M+|{5e!(A2Ix7cyR}_V|Im6hP5rSh|ze^#H+)38UC{cqJKgG z<5=5PGuhS3?X2d^!}%hf{4rPB#rkyUTXRL+bT2;u;F(OxUf{(?jpbqwF0NqxO<%yT z%EgEhDr1+Kgx$ZGau|?o^{}JOG2SzqD?^nOeSCO<66i_&1{wdO!0#@Zc$i1go49XFwwCEbqixWrd>&p@8;9_+8gqx1Ke#95F_`w zm7p$cQG0Mv^N`s;>k=4YjkgLQ1vd};P%J0ochiut!oy(ZVG?}g>5MAV#WFS7$dd>% zL~|q_^Q2bvScO5qd)1Fe#N5Wz0JBGnRQ`q^641J@|Z+~ zKVH|T$pheWGO@$q3Om7}o(k|}5+62XUu$A#LM_y+P zq$z4*Y-SF53U?3uikc0pG=qT&$oec2WR)pGsEW-2$m$f9z<%oDW$pM~)ORIBK-vl) zyXeJUG{ZDYpLMmgu+HAzuouho7=CtPF`^Yini!d5YW@H=idWEXhh{j7QrysYNH2aAVl0-FHYK4=9D(+gA=XdsnqEj#&Vl`gX z980_dVWM_ZUW-pN9W1+|vfZC20r`tt{nP#L0sc+m2;_Yw_pMJaw_wN}Kc)@3wUVGN^@%(Ziu;E)xgt=qEZET%-Y4`8LdO?eIsm+|*(myH%RFVCvx z@;ii>q{!V7jL#vR;d4E_zHS28A0NTBH{z7oh#QcGWh82HRB(}XSWnfpUVNHiDiQBO zW+GB5X{xPhLl%)0c~@blRX}PfiCt^Bs>5eanNH-CT|~5CTgIGh3ozWlwNH4Mee^A! zVW`%0AxSJPbX-s=2ANW)XnyY?Pb9Ufg+a3R6PYGHeT{QdMsIyntZt2CIAA z=9j;|EdRgUSpE|V0EEgnrQqXZw(_PFTrtt!-4;rznxBWhaMRmQi?{)>=|gZeEL-(S zwWWguGI65tt=5PQkr6o-(y7AU@o!JW)u3G4;i7N@YcVk9hGCUYfRwkOltlnmRc zt?~&YP8|EG@zs^O$Z&Uu2!aZ7>3OA_c%Qi*Qyt-qM066g*EC9sxGL)G^JJ>qY1tp36gFG7EWmrtqltYA*Dzl zS8{CD#4{F&lTJrVqcl0jv4n+YoJ=JSV&=FUjIP3eXpa86cKc1vU8|8hUE|>?WusNY zktbz2H1ufzvi|U>G;|i(#Ojc`%(JW{tW#d6wlrr-=9XWcmaRSsGKiG7|1ps{?)`Nl znM=cho9>(>5ANW;mo9rvqn$F#cz_HIqMAZNsZSC>^gP)bTt{9l&v;&`p-z?ji_Ici zt;tsh`Pa_Xc^Z5LH~+U8YHepTOuKtU)$ga`@lLvV>U))i=X%32uAXEV&SH?m%GmQg za&atu0FF}1?intdwD?4m)c{x^C<6@%BEa^xZJN|%)XQ;jI-5}|a5j6=-pVA_>`GWQ zaU(Z5A*NN2vz9w=cWnl={X=g`b(3S@2=kagW-4T~qFRnvxM@CW^pg)DZzInv+(*MhR!~Z7D z`B(aIWxKHC>tnG!{VeFphGwczEPAR`oBQ;<6|V^}6=|3u;GTgq;i|vB_TKh2LVQZYvJGQNds5iStD^NBU6)Al zp_&AZb&TISIQY}X62_;bu+IV+K%r02sb&QwY;BZ_?5Mv(?y4&NA}a~3>PlqbC8Iop zh-0j8HKXub=3e(5NikI1R4Ba0_zyPxDd!jQWzlf%>!~+Z>Vq!y44Mm97P)E`tXU+q zij?RoR;x=L7>w@+op`g(gYiekv3DN(eVPO+^vcUi@I;PKKsfcR_K5=V)5-v#8GyR| zGjM03Gu|yOX+#=HSqgN+z$=IadY*kU-(c#|6QNIO6c4#athlRwJS^QPYq;2E!zLag zSBgfH;nI8V89i^I6hv1x811O`+Zo<7B$uLML6fWeRbqj8#Kby7!z`o4)Z{|-6MaO0 z5Aah*yi4CBK+aKy#IyJMI{mzBka|1K2ucxZQ`I>fvo9e#eZszpF2 z{cDh8x_tK|!?Yi9vLtzEDJN_9WJ8v0O$~?g7$4Nb*iMd^3x0jSc=w*zA1`iB%SDRU zMZvOjdtrV)2TA=pg&n3cC+-$omuzT_v13p#5<_U!LtT}QE|z|$PIKLis%*Nd<839V zV*bYN{X9ApBoW5Xf&kP4RQJsLaU&42RCe>5MS%5#MzVJ16C@9Kk>7dIU& z-p4~UfP*cSzqIz4+v8*%dm6=1{9{gvX7t293O`fI4-nF6Gh^L<`m*p}>4Sr<8fvHC z!=>`+?guuLT$w^)7xT-ZiWa)KX^{?q@(^5b!uW}(nYaT#MkK~yf2DX!iX~tosNV{- z6wjGRQ5!EQ9ctkTSYA)V2fEg8^nRkAPgh!Y%aBLVgCWqz2E+63)j`B>*IH%rBO0;o z!$P&nMS{B$nH)ZZYjo}==ne}ZD;7&98vH7@wbm)P*{|0fXW-;q*DFM{l9!@%P&Js` za;^MUZ8UriL8S`D#b@+;=XyxJ)WdqtDaH^mH#Rdf+bY^#Mi1JwpCo$!DXr)WE=WUe z(%!RdL{Mi#u<)FVdn{htg-kAX3IBa)vH{PU-)P?s$G6iJ*{`ZdZF~iAlL_6>Z(ZCn z{kZJ?J64>6m>F2a@o@K(Z_OcNV|G;T#xSrJx7^N@=37J$q_D z#kw`v1XmvtM{JFnpBgHG#lsAG!0$I2D5mcT9Ad2Ds@1ZMn{i92CjE%NNab-~Sl86g z&^}69urGXDld(9%6*RYxwB$JoJ5)>VY3x4MQmm`KHyV!J^*-uaH{lXD-Wj-;9v~A5uCd0ct0wSZSHhW0YDsp@b)4U`$d>x5z$lPp@%{NI0Tyl0 zW+lO?GwWViSqy&YG{A57gH>u%c3KM3_KabeQX(w$#3bg~OuP$^l2rB2nQx5Lw4q+ZG9uf{WK+@%@YoTI{-{s+ee zib$0!mJIK{&_Ca9&8Evf17o=~_;;f5^?W536wmFdEcsW{-=9Pn+0}hY;dN{Bne)tT z00ZP@Ltu_7Ct_sLRMAL*p^0!bnIY*VvWcUE0dxg!Q>m*mOZ42CIk4`14S)Q!P)a## zPK~)cqHacmj1_gM?T#=?xD!#aw+5lwxDUx3pAefZcHnhzOJ+23_zb1f@ZBY88Q>?u z9c|>rkB!f*kKdKBjfD}c8B2%riBxJ-t~g1mm|EqW+|8lfx5+&tGl|t@*2{$OUYr+t z+3JcJkTpem7HEZNLtSmQtA)<-d3X*$28&h{ps;N){ynki)tMcuc@O{$vjdYmSr+cN!yb;(JlHRqIDWu8FPjzWcJgMoMVoaidShe&ZaIYMSVuIgI_N7 zkc~GxlTyHHB%7u$RTop>BE0#?%L>po7gSzh7<%8LV6KZtX^~)5gc@UhCT94q+SK@= z5r3)QMx)9|;WlM+_}e~3S5dc?_ZR`FSdB<%+GvBg%f?v3O;?I_B)S!^G92BjC}h1V z^c>}EqwNQcOJK*T;66)+5miG?<4ge7b(1BXb5tpR;+{XV25X{C)%+l6x}vldjd~L2 zD-IVLP>_`JPt&)(t!^{$B;9iEN=@7oG24$N7*vt}I2`^31u1)F$4>v76K96F4{Uj0 zOaTCZ9vKS`9B)=3>WU|7SD|6{i=6`L&7wlGUjYkfRw2RaC>``R zhz>{h5haMFF)Hs_gN67ilf5HZKN2O*yGzU_!b03Ok(>s*Z3 zypk;6cW)a05?U6x-TC9X^ht2q*yfApUz<-WdJDhXN8fVCcj`@<@1+iaaNFL>Gi8T` zd4sAeF4&v_d3r{9Q`}avQi4L*zuG?JS4esE8B*RI^h~GCOif7!0pMXM0an=4_=q!m zku&%x%I^?>6fg-v@_NXWfLMGani;zU6bv}9)wMYUzKsK?{{3{y)VuFLM?YZ(e?Uo9 zI9$TIdYG#-wOh?6Rc~@2ketBdK!{~EGQRXAx6@|KpCkPF_iRu|!KMyJ=_fV+i@?vW z)_l6UjcU0Xif@*HzcwQ}LP7mG!&Qvi88zSc{qjD1RQiPI7bzCfW7My=yuV2wC#k)tuFx{KM#p;HGxw8na-G%wg-LqTYXm{9N*PXd!E){=H_(4Wo|n zB3$(k7BYXDJB0I(jKnTiG=1|wA03&*wmRdV!oO@awJ!vEY6TR&P2b8ELsP}slzigD zi;~+&UBArLDk$ELfs8~nsIa>OzkQE&i<>=UiaBGdA*&`npIU#%x`6Ua(4}0yU_P5I z^eA5l6~*QMRD1Xr6yEzPEWJVDs-8jc4GLtJ=iu3%UZvh%E26dZN&tWwfCSJ)hq;d) z@w5ycB9>6c+CktMroino<9BDDfZ*u>v{SGF)B5+8jy5(5E}HLj&YxX$D{mXMdwo27 z7{1qDu0-DYU&iwtubg$w6D(d-e zHu-Wwi2Td%+We^+HMw-WVP@oSMRC=s>Pm%{jN-N&cFJVFMnF+ z+YuSjT+RswUUXxQ36eJ!%%a+WuIMlF6=Vi7K72x-h@eIP9!<>bC~MAo&djg1{AVk2 zgzHw=RN3|K$5*zsr?FqFpYHh)eE=|EfH-W19cGRyQ#L6EXb~kU62MVMft0%hGZY=6 z7*x~%TT>8)U@@0XV#vj*|#lX;^R4aDiTVAL0O zZWW47kkR{S)3yOtkSUj)-Kp?ib-ms-%}PFgy3cs=%6Cy%e|+6`dNH=}6YeOZu%IYy z9YcLmBdjB^r_yqD`)hcq|GG-G=JDs)|<>-9i^`Nuc}H$(O@ zcR8zPMOL(-?q4p-9PBQC&%VkhTjiX|8ZiitlXM|+CUho3}iU7V^DWp(=<3r>oBFo`uFxM`6`>kP5WpZ7JAvTMzC=#Ko83IUul9)`RZiMV5!`C?zvQE_@RUL9+1o3b%lz?(5in7*3ZX$} z4A|2EG~Gse>T6U05Al?Zp6#h!HR|-O`0`6Fue-iiOKIKpFvIhL*PpF&vK zM&=RBO1O4YLF%Oi;iaVO!_F=IMX3)VaW_Qei)UY7be#97e>|n~@ENTwd4>PRC@wML_;4t)(oFCDVpFteLD4u1S^6w0XvH+?$*Cyv#dkEO>>-G#(dI^5h9J-m+xG zSAll9jYdDeL&p9O)ffH=1@twakJ6zTmTuRWb_t$nF7FD9`dH1+haR|fN2W!5I8h;| zkHs!wvHsW`0)UZ%@FEy2Pzv5+1mFk?@IhgIY{+LtwUo2dTuH#YF{7my32d#<9XoNU~6fP7j z$>AWkFk%dZuvq|A<9b;aQWb#)2Gh^m#t!tZ6-`>3@61d{rl(cV3F0Qu$F^sFr$k$D z1veZ#2r6; z&o6!Rd3)S-d3wBm;O|XwomvR6x60W#|CbK_-v!2hH#ELU$^U--`vm^`1pem<{8K0Z z5HswGQ!N32dvrXH8Z!X6@>IRE3jo9yVdUcz2fSI3aI8PWqQSE47a=1do&WW0dMdwT zh^-xx_n7Aa!e_`D{*=dp!$RGeIDnc3NuNZOJ~Ira3(@)DQ!%GBwZbWTtn!u4aioy) zrXXP_$fJcTQoPxwR$X@A-*x*9p&#dc`aSohhJoR?28TkNu=DE&`h0Ki>s2?Rp-#d{ zkO#$N-PbSnuj$ibNz<0Dzth&}b9lb39V!=k^Cv%2MBb5Bqks9i@A*iBmt7t=dYE47 z`lqjj{Y94M>3_8YwcudB0%_=Ne|-P$=}GDdLpx%-Jz%TpcXK9#o|%Q{gP*yp$e zk*1hi4BSP)lqH}5;c$%5mDo?-aux9fn;plo;5uOhyM7`wDP|r#@woXO*zBN&H&<2k zY&cl7P$;-miW&WTzZnPzNx<6O9liib*kFv`2##6o69Iq|E(m1i6=W$F{22#Me4b8L zdO9TO(=Y3wCsYZ$;5!ru>|28;5yvcDTqJXc1QOsV_WLVijIfaf5|*S}5358!IHPHj zsu%7EevC0YkMH$GEsu*248*E1RT=Lj4ev@4_fMP7Hz!gUaZ91dt}0t-kPrvWsTBl7?6Zh~gb}rJnJuZFjZ9B$OHzPH z1JY~oFATCTfei)>r^9JX3*vC=&2#H_5Z~@Neul|nN6^EXLYKj!@?ry&?Jy%D0O4%< z`$NHdQ4EkNxDPiV1Yih;zLAlH9V{k6<18Uy3iJC&5L(a<0*DL@TG+814w~miUP$Bu zm*l??nTbly8-V>oQUC?!(WA^ScAHTgJpW*i2{NVw#|Dl;=)SO`_1Zs(7#VojP(eLI8)Eb;A!C2sM#n;KYD zX$i=`l@uc8Y_->%cVIUz&blsp0LIq&>MFZCF*VI+3_Zfw09Z3vI7Q7wN-|RM{v84| zQql}XtCP8EsCKcKubr6cGmmVQ1{Lzgs=9EMc3ePXVqu(j1gAu7fq7t(BtfP@Vk8_z zBIy!j)S@^iuttlG49Nnk!Z`mn70F;1&B`pAT*w>|$31@9OD=GIir8~@K64F4c0Dz4 z^c9;Xe)h%t=dr+Q%T~9ot$zZ9a@Mmpu~&A>gOgL6AdJ2I_jrCFyynd*4yZj+5GJ?D zcHDdc2M9$r+R-4Tt3fO6732EJ>XQNiI)KWFQ*nJ17Crho3_ST+Ciw=4kI4}5D< zq?8uq4-W2U2Js89r%Wv5>*7_*2HwpF<~}&YX_d(0HrEvSYE={ewxp6GzC^PMB@!R} zOC83-*-C|hAVn!qRv0@X$NyKa!bA{jm;%x*w$F&wItUscz!CNy#Gu|M%Q%Vu+nC0E zoLk6MhZon#_&4r_Qi&}0&*k-7H1?g|v$Id&0-2m+Ln^7p1ubeiWR4pMEztr<)w_AlhDUh01*VnWQ zuYbfof&m&ScV@ElfOHT}dWs(}g}yr%%*SDMgf4id1NH)~gySX;`7^TEekA9rQa zvLBfWIK8DElZtfn!}D#Ws`#|Yi3?;~G&)2}%3~g-=q@hcN!k&{hHaY0y{dX*ltW?v zbUd2Wk(Se7V(1Szo=%)?WQeu2M{GnRY2##@N za+D-#osESyAD5)NU+rXAUxBrYf{<8Fp>n67MU7tqfI-ohoyrcN6pO4hDMEr((~%j} zyGI{t44Zlfl1FRW3wSrml_>Ro*Y8&ke;J16N9B@elf^A-8r%~LJ420flw^hRllUu~ zYP8cb%TA4mc0Md?T#Hmam!$PuZQVF{k33N&D9+^GrdNNQ%tx54t!S693eF+{St-4E zy|KhWO^S%DfhI$R$&*EA#hUz4O;6(Gm{vvV2RXvMhv5-2bgk;VzU4@bP6x(Y7Xm8a z8FzL(ZCDq$kz@)fJt}LZ)jBStoi0lQ+Om8mO@X1y#le`JS;*h3b0}#F;cTbQ&7Xyo z8Rc^5{JVPpfBwn;fBEoFD4>)x*)2NyShyWJ6RWtQsggfUNYt^L!hIK@=NU!adHbRM zw;mWlpMyx7Iz|uy77Z#bF@!Q0pEkF@axy|6){s)i3H*h*GgHQzEr5$Xy|Jttwz=ZK zf)HIw1-Y{g$^bLZw@}NBqzi8s5sDwIZht3n%6)dVu~M6^iZaNGbWrpRE3Jf)mVyph zPS#DA8ibgfsi)9Z#jds(8Tl0!UC0e8zK~=#p4d)ixl?4MM^T*oY6*L$0R0W0LSmD( z%ed@TcTc1RaBGqwE9Leurjz%$oIP^p&t*bm(`)?vH!b&Zn>BvQSUmia-cu$x;Wt0AvcRWTiM0 zMtGRcMPE~TU1o#xgL}rbC{*B4|&V zs?=OKw?L711PS@lRPP!(&EZdGaLL*oSUIWt5ulcZ44&=b8vAQ;+a_h2Pxl<^Nsph^ zvX%WUyd6wVYVzv8$R?JXohreHB+|vm+$TK-vW9Oj)g8UGbE5!YhIU6W$wN4QwMe3{ zLx#VE^e@3Bkw`znlN2A869Wg#%u3uE0IWjL?Aj8QPp0zimqN+$u|b3=_U8R3UpgBeb%&#^LreX&KEKhl~#Gz!c@c2+H9;Xea! zy9aLf60J(Byczp|C6;^G#QTO+6Wzn9j`)bt`e=}a1cE2tE2e?H%9LK6-BSU9M)n6u z@eTw@F}o4qO*?Kqt!y5h_n0H8xYuELO-ddEuZdYcX$G5v4x8EC!5<;_rJ3kW+gc^f zF&T%j9LsnXSC0UA-2YgI5ot-@Kf!1?la_V%|m{ z#0y~cRbAZojsaHWz>f$(zc^vmwydhsKXvi~9l;EXCpcfVNfR_~AiSD*KlwoEbfLwo z(>F0^n@0=j9^@?cADCLahUFIGdXEvu^h#FT{L0#@|u0=BKlQRDUC zp{I<9%#6}Z?3_F{3sXL~b+%Y^a>Hic1&_FCRw++)a!dzy4zjYMPi91S5GZmK z-ehJh#&yutBqnlpFlZq2uZy|sM9AvRUOXL9HOXfLlWv72x@>l)?io#KNHXC&jM~+X zWgUWBTem8sfApV`tUKs$U?GK0Xbh{Evx{;k&opFnT#8+cN^i)KB@%{RdUHSU_CE@MD2mpJ6v1p#5;6&dUjuy<7y z3Bx5NB6jN&eAf#!MQC&Yu6DzGhN+@#e&SB%o>ht=hSG2+c2$qHne~yVl+X%1i>1Py zW~!z;Yw)Y?Jd`7mf_SfT`sJ~mjNY~v^UQ6%75T|Nch%thE^SG+DKjQ zrg1VD!|=rtgC@hHIE)Z_P|+KBAhf7Z^rw(~Lnm(PphBqVxPHzKg-$0 zbpc9ae|VH>m~O)Tfv#Mc+ThLEHe#~vR(Y>h*rbyuX9hwg()rw0t23Kel&kghp!ntC zTc%@G%X{mh$;KQlXg>f90HAhk7KcK~C!(Z7+RlXI#Lf6Mq8-EZ2G5G3ZZH(3$uF%8 z1I(ZNiAO4M4K5Ib5h|c_2aC!}0<6pq^eKz7XZ7S8A-|k?6EcoZUbHaFtObo*<#&Zb zPh1?d1O>b~A$QNK8HyeC?Q#Z!8Q6#_y0*0z`RfYbr2M8TIO{k9hm&##l!{T9%l^jl zrF*6(1|lSe%E$MM-_tD&GQ^u6Zs0^{qFpLJc;!b(~U zQ(*=jhtT0$15&s3Z*94K8-1z625!&C-rX{JRQ-k=bKg{^SmvX7YL z&@K%CLnMj`mx2&dzL~&n;;@%Mv`lQ3eUx|&-n`q) zYV*G;(_GsVm{rPxMn&-KchKLc#T+(MF)oeXDtXq1%G;4*UAZ5;K9vAqU;*MXbdBAy z1p;IK+W79hvsC zHf%*}D`Rnht5{*l+!>`H6u~vWKB&wVOJf0P3FbUCaRHgi7PtxhJY@}=*@}pJd+<8q zkr>F=Y!IkmACd$Yx(4+GMynP`aTG{8t{INKKp3U6qV>4G(OB%76`Yh;7hH`STToAl-E{r18e1JD2f;jfL! z*)wRXtnBXK;nGk{*!}@a+|2%dSaEFqnT`x0i{_TrW_MNom|tLrnTE~B>&oGM^|%G3zGtDWe}%B#o1*epi z`{T$xmzU50fC&O1W_xpb`W9x5jABrOQX0&6^gzrOp8OzyJS>wyJ1#I9DGd3L$i(piTXug|B0d{Hknw`i~GqExqBe=e=rlLj#nJ$ftmi)n+91Txf#N164v{$0x( zGwoT1YtM60CSUK)asODp#@S@vFB1G;X@`G7;mA(iG1JFvYX*hIlMU_N%$)F*`FYG! z=W*_|i2FaF06=0@1-%o1@Si!c0R{)>DzT3AI3QRY+t^7X-on~HIB}!DbNQiwCZOI> zL|C)}g%VPAho8XteC1#2#cTG!>LT+fnsUB!C-rZ(A`a&ja|t5s`^}!)z(*<+uFUSZ zM3u|SIF5MYydRVA@Sm5xq|yFVn)YZO(mIRM>2n!T6~CiQp`wi$;+PP%Atdn1lv16Jn14HJBQAE zGINWNl&Kv#O8e4iv3@i4wdNmq0DwFB&HN9=_bVHE;80OTOQbT*M#RO(ykwQ|*Kc*# z$5rY4XHMuXX&E-@Ns%~%X%pOKs<&_@1Gsi&KO2|e)I~>t({jG$Hp=uJ8hERglG*Yr*J{QsKGq)!iOpg| z8>4>8+4(cyie8CYyC(nKd;4>pw8BB0tB5nx<80v`!IW;c)%mRcXQh5oouiD@@oZU; zlg!2=tWp!dtXpm*qph2fTiq5dg>I{-;uia3ah;|3%r@TGpeMw?-#I>rYPu(t|RTi!w4+kXk03ruuAx;tp@a)Nc7o zUKviiM0Y8skjMtN4E8rS?#hF==@}UdKwIQbfT;kV%w<0AHGzT-CkBl46ezb_zEC}Wl%|E=-sp*9l15@{PKuZ#>s}u5ynVrZ zX&;L&RmStsf@1M6=lEWc5nbwTZt_mVAT(c*onV!#=LTw+fuq>XrLhr_mhiypGDk%r z54HAiw)%?Z_#M(3`MvYUm-lh?hqbQGbKozUjLh#Zn`YT@In0aOGPX`TNgA<_Uyn_` zlg#w-)w-I{*(DcaFMj#kcoz15YEXJRoPY26Hz**MdCrj3+dv*>eT&~;OoGrCL@s;u zhhVzsdfWezK1igXNs-G+0b%zFPlNk+#C4=W86ZITKtBK>1&~1BtD5O(vZ~cs4tB6x z76CSbu(h+!=M(0*1xuT;<+8Y|N%mm?vcH1haNyaA0F)F`%cGUTT9dZi545eya$kFx zxwv?%jp;J7R@OBNJj}sc;@3zR6SHPoV}Agdw68eql&Y3MT1gFxJeEYIH4&}n)3biE^zR!MKIF8m z$LPS%hwrTbLQm^mR$9V-5^J>_rf#*_@_BpPeE<6WE^>WxELIuXW%N@R0D}PGK=UO+ z!$O5dmLb9g!{}pKn3=&6A_4%!5Loe|M?ve_kNO&;Il-01kO!P$GZ`JndPyna`LncX z8FIVD8rN7L49OkWt7G+IsBjk@UNA2vQ{gbYbXxTuf*D*{e zve#Hj)AiWM+1}X5{^a^;@|`6UIR_`>spr<4Cm(gB6wLg=pFzr54|9wIc;-W;#5915 z27N%@5IQ5gS!^BBC&RLxtRIw(r&W$@bF3!I4!w2+kh*f_A{8iC^nzjeRZZ2Lq&>N^ z^To%Onft#l@Ap@#d}GS7)H6Xt(5EkL`$Tu2KJz`L<0YXv>Y^{Z>Pm~G*}xJ^QE1$v z2S<|sCjTT7_&VE+%~yOm8-03<`0>@%GkxQwA#-=oD!kXV-cPpG%&J*ui0h%NFRPun z<9&VoPQcjn>$NU)@vSJ7aAGD%nx7%9KdVf!6;zs2>A~5LJ}HCQyl!49UW1)FfO+n< zg=;dbBf_I%{d73B8K+wdJBh!1n4-`q>n_OT^>-yz|3rmqBChwdcV^$GFS9*%Tv(TF^cO zbS{X9g0DYaUU~c$Tg4UTS59cJeY}=mtwBq3ShopG*Im-t*Trak{Dax?YWnx=)(DI z4Fx4E0e}#7Yp9wqtkR5wk z8g^s~_?aLD_@GkEZ>~mHCpDI8ex9P%K$n`L8RnU-`{lHBHyJot-`cc5qhhP^aj??e z2}!H_Z+*vf&+D2WU6N^X3pv*qc9nX|cGd{YBkGC|F99gMUpCWg-D~`>u?ebDYggQ> zmVP>!H@|mVd7smM*ge{N8>K3st`XZx?_A`+v(YVfN@kuf7=5vQv+{EL@;C6)=&eed zS~|MI7w+w=83Hpj02s+_c<1Jq4Jj}p13(!X$x#qB*q~1t0iZ567!TXd#?Njz|7#9i zU-ePz^5Q%enVsGLI;tc&O$evJ!4RZ?#Oeeq&kRo=c<*=oLB^8!<5K25J=J?_0(%>m zYBqZEZ=ypVz4izjQc1qjBZ95RPwBwz4X zzGj(F@~6gS+q*PgA}xX!lf1FCUC*Q_f~~4jF>>Yo`g~#)&N#l=b@O>9x(HbXf@{S)}%x<)2lfjH&C_pD$rx7=R_9+;V4WNkp1LJ!1j_FQ%*v zBMtZpqJ2y03cR^Ei$ar?=XaH|4Aye{!DkQUu|jy+^wVABJKs zLuVws*xs{#HGi@+PnB>zJiYLBArznwcAl)#ygir|e7Y@JqF?gAi~#L*Q))bWN>j9N zrkpOoz!f-Z(d%ahgVU}nYT87@W+D@@s^_=o;_0ZR$zGMS8DW}@Nk?d_FnV%%3D3tEcd zv1i+U`wB`|Fk+SR-XZ%OR011Nxpoi@=|H5w%8=AMowz6oc3;7kR8*p=FyA| zTi**OOErYa%~YH~&J3SjGm>%mxMJwy)D2CO<#iZ|{fb~W4f!TAO!h}}UzDtm=b-GI zwH=j%=diE&(J4Up==(drFSDXN%GX!e;ZFtSw~5cU*R=;Bs;hPz{zp!26YXSo3Tc4}Cp-Gct;^BvvDe zY=^`D_Q{@PJL`ksdIcFfo|_Tfp;*xek47k#znB07#*IKj zu!zjqEf^($018l~QqA&_AP$M;w}PySv{V_c$c>B3o@9z;3tcD>&ZNUT6iL<^rl2GgYg44SJBJ(kyLqMhEn=Y@Mgj7uj;)tdNVS7SaodW^s-|uS!9A8YTA!{3cKUhHt`;}=pokqXi zw5!(VO?vC94Za?=4&nG>e5AtVc4{d6AMCwlRGZz_?;YIT-GT>~;ub7Ou;5ZG5VW|J z7I$|kP~4%o6)0ZZp;%j-q6G>qP~ouez0doeamMq!`+3g!^p2bBLo#w@u8hpzO8(be z>so8hN@oNJ)aY$L)9PgE*L<)vT<6?Sq5WaLp=r2e_mYmB8Z(m zR`sIDcZ;65NTApeJiOjeW`oSJO_<`1Q}uG&ZJpat0k~jvXo?2J;YdS`g99=*{&s4z z{0Ve>?e1g>;#?HDss%M7Zl$7>!f&ta`u_`(@Q+QBo2USShq%$pg5ohgByxVt z<@|pdcs;gzB=G-x0{;vY9^7z1`B&aD~wRvh*8fD%0_u*?G z!G}bC2nyY|Yl)~j5ZvE_+F;vM85mVrs?F3SbX#%Sln)oM>TkS}i1EpHv6z#b4+Z6; z&v!d@<2_&$4>g!EB9zR0rR%At5{$FQ=5iL&jKdHD)Y(ag$$;aahYS72K5Oc#=egww zC7Ul(q-~+t2&q+*JqGNzWe_6)E#>i|6_A)}y6j&*L#hOD8lm zCZD3N^tXsivVns~8f4!+*xuhurcQ{KrKslp{-vRYVl?2#7cYq9HxT?Z{yCaapEluS zb|hinBz)3yuyjb+PvgY^#$T=O?+*`7Uiz|THD#)^9h@2qKncL;eG&W%$UDSs0!G&+TJd zlG{*ovXL_WvPLD2#J5tgRA5FIMC!Jl<&WeE>9Zt6Ws@HSTE_G4%NBE4*E8AC7E@be z6R;^--vI#00EQE1TL21{m>LRWbY0RpA!-PKm`V}(CG~7nNKmjG7C8X7&yqiU>OCFC zZ|d}zL+AZh+KqhoVZpT7$P>{{XSVkDt_6_?(rOhUhfr2<6q&Nj}eN$d$9Sv>vQmRM~kI& zt7=POwjV0-_^mo?KxojFDP=S_AxdSm$c zQ%YOpiwM9w%J0~X!G%mY0=P^e*%R3ZQIKfFdG^n6f`7DnI2LABex0fF!9kgtGiy!O zdGwKZA=p;sXd^%*uhe~XB!pE5UL?sw^_W6NWxUNlHoy2rkOz5f*;vZucVw*TNrV3S zl>hl~c_&GA;1TyfU*6wOlJY?N`KO-PCEp=y?$;Rfm=TBfoA$nN*J}Y`B(G#R*A?rY|toLVnY2e!( zYVoZvG1{WsR1$mGP>LnJS7pr0(@IJVyl}_(>)?+nF1kqrpkK1xMlCZJy`qRCP-Ykmz`ZwY*v*=gB zt2vD_66!lYILC^9T_n(+Uny47kj3YFM6lx=RZY#OIN387CuIq?DhKqrmb6u=Y>~fY zIE}XP1a=s?ma*u!YtCd~va~AU=`Q|0I_gT1Db?tmk(?b}(s@&#apGpd%kCfhgdf!A z(2ox`rOM(i_jbxFs6FF$Rp&0_dO=vC%ek@%D$BER@mRup;lR5y`w))ipqs?dP<~eD z-3_dWe9pw(eCrcyB$q$xFfv8XuGQsgR{csZY0;et9OC}&>w^-Inn`ctWqadhvbaCg z_Oc!7bL^N?=o8kU$8X?4>*UvA)S$O<#i4MksID2|s%-|DM|5a?LsanoLdPe)>xdUs z_~cPIaj~I>Z+l5+rkoRlr^~7z#oX9&@Kgb+eElh-4qL>1WM#e{R$;U)k8sy5LaZJ& zy!N?}TmCem;OfbAz_N3FF(Wf`jp89-QRW;c;T>tuAwYulg?a`9|Z^%m(I7LahDaE=uPJDNg>!O0)zL>nlk-h+nSAJ7F4Vcy+|>LY;Jh3&m;EwjMKBQqn+au z?`pIzrFp70!3w9M*i;goh9^Hq7UH>}vJv9OL2!TZ7@2htO$yoiW(ygD8xP zbLBsX0)VW6S_mpno~gTHQJFi-V8n~=fv#L%Rm9joaGu!_o2vF_#8|Ij46%W+n#;Xq ziQnS?Lg`TK5AO;apzDac@+IO zH_*?%n*_fzwQ`RYO7%b7)ezHg`EWMy1#3j~3xh)=5|O8SsK6NTs%omA_Z`V%jkt!s zeFdESwQisn@8(oMLxoF5F!l-_RRv?5I;S%qOcOy+OMxPe!eR)UO}5I)U6XxT)Me^_~;?$CGwP=1$%lG$Cq93RNB zu8C{ss2yDzhP>JpMYV?7CYxCv(fAuyEk>}!u?T#sg;o-ss=+H`SgVYf@2an_*qd`Z=rju<`%!cPiKa{;@KYnD~6;i34 zO^|6wGdem_;$~~Ad-x}HIdZzw+QdD{=4#8}nc+z-XC_z2TaVbu1T$DpFW6G~VK*q+ z2!2s}MnJx*u2_>0-OoKYNpz}7MkrtPo2LrT8C#{dA(0u@yQE$J7q=b%KjMdf z4j<5i;2-pGU#!fWbR9j^2L=+ODBxRtjSrPW$WKaN0Qd=mA)Ip5!4Z~vuAvc)AEvZ^ zuA&L6NaS?XPIyj1v2S1D)OqL}`POel>BRb61H0XR=KW zw)HWP1-B2bfp?$2&p+f~Iy*KPoMP^(mhH_n%m4iy2C!rTr0NEXAYu2Fe?-Hvd6WD4 zM-w(8(ObyfIP)MkkL;T$g~@Ko;#c!d9Kk4WzTr#bFQ&*>4qXR|ycWu-yZ9)&TNgZP zz(~}t)Y5DZa^fB&-G$p{+Mxmp(&%aF7b|M^QB5<9z&@>~W_sTvz=Pm)3~{^f ztr4n#2V7!b+SXza4RpyQR}LG|7ExK9 z3)Pdb3XU}`dn9bBy88^Jrbx(dq_<}uTUcYEx-XHDmV~pH_6khKOEbeY(ugNFuvovC;U!jLd}Hy=+(_-uTOo)rVNIOdS#J(pI|tDGzzV$#I6-zG%|sQEI( z`XghT2;8>yI5wDO1hjhOzveOe`LPv`y#h3_1PUPjb>Nc$K^@K2FPSH!N|JimKX=o^ zH5f!N|KZa2x6)J_sU#+lR|Fkf{SRT6pdW2tIC1!^a&upVf}AcQ(uOc47T}%^#x|N; zGtfn)O2P;fK|NEbOd(e9^{xSCv@WY1vq1cU(_h9;pS82b-gXx{bYh-aRKj2M&7feJ zXk7~{7Cj3$R(ZqthE1){otC@g5Ig=M5iC(A1B%3!pdRQIk3GjH(kKdN2q#G?-I%(6 zV(UI*vI?D!j+&T4fcg&Y=-@mXY)k;uH|8({v)T`W1sCd}3L-P%Ol(`G8ET)}Ro5qH z7t=(WdM=ZJs7S(h1T4GNUBlRH#G z5Ac}e(S2XUH|^^HOV)@fGm(C{@A=9 z`I?qm7W}xE2_Hq7*Xm-DsShzcDI<;w0K`FQjzfT2BLShp#TbBPifbv}fj9+A;#row zOa~%88VRZ)NQjjXp-d)>IEU!@IozCTjF|j7*N?+xCyT<-TjhBT1>5m6=iKn3>R3si z*Nnv28(T&e-1M}{B~6fZ-=;>rujNt#rBZCl-)MH9?JmZDf5J1WVSB0L+daqcr)QLl zb>UE%Q*Z2vG#)4<@3yAQV)EAKQ(o-vb%JJAD4oq#(K`%jVHw<2Eo6P=_0Yx|+(bgV zv&aPYd}yd{r%u-A`5sT1qWnL#0~>1@lL4PiP82mtZTkTL=7q?+O$f zl1exK`VhyHF0+LOnmDpKWt#PQyvCh16HSR;uK(Cx!Tio=@MKIc%IF61tbaz6AWT%R zFGHtov(|BtC7kMQQ3>QguQ0tH2LEyO#%!k2KB$JjU9`-TzJ2*E5eX+1Kk)tLP6&oP z(lsd{TDxz6=^JX)`*6awlZ0dd5i6V!y-yKN5F9e-7JT~URj@x+;x_?rb5_FER0if# z-DVEyVKN#*g|RkHqx)%*7)6YPkfZGx$^N1>cHg1CBrcq^%}7aQRsNT(sf#(ig(DEcVH%6yKlc^d6`6L zCh+~G&z6&V%(|V$KvPB^D0gpYFgCn zU$kzFUl?VIgNd*yDHUZblW)#LY0Oia0LZ}FV!#S!e9<|fm@6S&4~ZKAlfWlC-kQ>4 z@+R=Ed9?u?qocUQ8q-*Gn9&rcO$!~j*lLRn9dx%a-;_Hn%a%LU{h^Kfi5sjHzUoYr zgC>V>DCP{Pp?(!F~&WQfd zfGKW!j}FU3IszPI7xVUgk}c6)t?7RrUvUq06`MZ@4pYv;F>c{oUH*!v2t34)eoIm$F(fd2pkHAiV)vabhS zj;cL#ZC9)?Ttl#oqnF1k_UV){hGaglU`Om{5(DpZp~Uv08?+udD6u!^yd-*)U2u)W z;TYs?tH5eK#G3}Cr6Lj0Sn`xHofrp^W$VsnKYkdzsg|?KCL$*ph?5}WMP1Fn9qm|} znhu<W85wXWife7&)IZU2K8=Y1S7lf~GrOAfDcPr1WBxq?Fu~NK%>b%ho=+<`^K{4avTad=*J$#n`6X-uMf`&(mDsGtW$`oa1vR?4~y@>i3c&J zg1~YgueK4{oDx1EW{8z&O>b4Nx~*Y`g~A0O(4+0ZYc_6-WA#sl!CJ~(#9mVYWSo9y zvwS^voUij`fv&o9pPn9%MYbo+xu;{Ey(?=X_31!idEuhF|9oN`z5jI?*o%(f^0(5ZaEGy_mxye zIe@}h)kUNz;xHVP3?n^A$iyFQwKhOniCtTwS3R4>K;{Tnu0h zS083Wz{~_hFw$+u3}Q=Ytm#{Kl~Bm<5dIDbMAbT)- z+ir?Gds>m6y3Rqi%jaG2bwcx*yDxTReeYc_eG;fB*`=A~{Ez%3Q}soWE-`r^YYF1{ zw!~|b-|Xy`k)oYJhGOxt_n=nnBc?HES1a(aT)I0v^WJ~?)nrWkxBUM-On4Yp{3QyQ zQR+UrB+uXjhpyuaE+-vNu|9C~?p;r8N$kNldOHDB4Mi~vlvvnx+h;|PuxL^=a_<4B z*>ip%g7q%KdFdrVJr+Ov}P}izx?tR%Swco6*+Dm+y1F5zqZf z9M750-q*KYw(=TZtWO~O4x3Q>GHaSW;jB7xJB(_S;ke`}cvp5Rol{tqy?9kl^jbqt zO4M)nnjeMeOZw2^^Gsy$rN+-PwtN-Xh{;54=Z!~lD~dJ5jljI3pm9?FeeJx_v81V* zu9F~bNM4(8N2o>VR| zl%K^4g}GwdMcWQ$%Lp2(g%bNW9=hnXbZ{#*3!h;`FtLIsxKk0y-F7 zy|ZNTb;%2zA-qV(E#H>KV>_;M)#>b=9Mm-Jz{!HkWo&IsvU(Xj#I+W54xVXC>lStF z(r=EnH0_$3r4a$kE96V7^~=5nA;dKCobM9vV?hrqmA>Io*&K6u(xA*@qgxY7&@!fx zhceFl?}{(?e$luZ&Kd9?)BR&}UQ;kCBA;21 zDKvMYS_=0eA?p!IRgCi$1tcLmUqrZIgxqC4A@HUA2n(Qm{W&s$I&La{mJZq$Z;4A) zVdp0ui#G*SPW12_odaJQubUTfF#aVR-|$gzLX#TXx0gJ6b9)@+6Cn4`e|q;{SpKZ? z)^owl|CUfv-PV?Nn8r}#G}^q49lNF`dt<~apPi=+$?nm8oNb@_!sZ8oVP%W*e(II$jtE}gbiABj(n71uwKFyQTVteNVwyi8q@tb4tC|Q#@RGM>wEvE^REk*(vypsF zVtuxD`nPDVd?f#kIN|>h1%ZI^<`r|deLiD@=Q#BYA*YP>hZz&+(xqe{1v`-da`cve zxX@!a&#cICM=<5N2nntF3N5XXxi1KYgGK6@OKgH^gpF$l^*5$w4NkCs_7X?eK*!=c zyVbsIqY}B?NqJYrE0Ra;@#WG2c77Yn)am)?O9OKc5H)93!P3(}Q^`#e{?E*{ppDz)um!Zg78VNlV0`1!(wgaf{s*%TndzE@gTLupEH~M6Vw|PJm!W0{$Q}6eTxb{y20SRK^TUO#V%6egP!1o2czR>JLOZ zjeU5zpk=G-GrKR`K4>pKV=3xa*p8TeV)b%I#%%jdFR?hnj03*Rn!*RT|EYa#Q1zCp zAXU?|MgIqB=E9`?if^)W*t%o9%Vm@T=$@F&i0K2hF-htB)1%(b_3WejueT~DdlSE# z$JqUmFPc6zNb!~l_XdzbxCehubS<5I3z|MuBQdgtI57G1!H0I^(xgpia;bWpYJZ8Y znM{cK1)&;*5Z=Y4QyTjZlg0ML2n_%DwEr|P5ZY_df}f>y5_fFa8jTcU;~C{uf;~Y( z7$rxXZpDZ%$b=m-*%B>9jiGMv!I%}O|VJtXU3856b^h10%@t*W~Qv9ou?UUqJ-S@TU_3 zK}}SJizbcHZ77zewZf)4mIAVNTX~oFTfbc`itH{`zBISPjM^Jt=M5eo)@LRBYy|Jn z8*7gAH<N`s zYLYRV_u)8`!!aR`RmLQbv^83-U?)njT$^>MjBhcU4I$79v1z4>**Qsy`oUy?MLyuO z+7s;0byXtNJX*6`@m29A6&|H`e%7s&q_ME_`HNW*gEB!_7Y|$)qE(5-?#pj6YC9Z5 z;G;8S&hqh-$+hs3=IXSb_s|uY$sgJ?d;@S0iO#G zE6tvCPBBeh|8?>^3>o{wKQlj1WwS6gIGw+~y`KMFD29q-$H8(Cz-%XgtW2JWP8uAS z*Dt5(UCS&?QFm41R(H3Src=E58=rDKd$`({ORFN1TPH-dOwEOl4n^Nlk5#>RSs$2w z7o6(riFOjHVU+v>POCI8{c-P&o+j*L-rf^4EjbL`;=ba|WV=+C)xG^?K6G>8pdWNW zCh#HG4`e^Rty-!gU!X>($%|(eR(nHxE~ma#FYUq=(MwGX$nxXh{)m@fvSe3@MxxKo z#1t#=&t^~=w+m-;MBOz>A;M(Fw>amX`!8Rg-1jcry1f|4oc{UFoNo;fXN|a~|BlX6 zG-GL{Mt!MlToucK&X1U8d8J`HXW&InPHWo=YMizgP8c3~`cP@2aI-0f`|?YBP0out zxJy{-5{g`dM8h~EaVg&LX@WseB|O1Dhr8x{>FwNAgg+x1ddlJ(p008pbW^T&b^Y|7 z8r#u~WmALYOlbls2<{JQ?()>0=w(gLw#b^5^1B5O%7vjF*VeZ}Ad#iuEU!3@6YS1c zj>^sAt}{!Wj+sa=y$$gfeX16s>z)uFVnwQqnYXm8hi`t7$$X>SU$rgIb@d_8ow?3Y zyshOfWyrhw(=uws>`<0y=GN%yzIAII9zpDImDA;J7GZb^>!^Jzt){u-*^;aILfVEL z^GdF?N>4}}!gGaEH?lh=)6qH>DV|y=dVhgRSU(>vB8rMf9psra#p3QxamiNtMGRD| z_N$BMX#c5`v8m;5tK2LIzg93BwF<@kxsCqoBPtsUJGG-vgV^6L{X1 ztRI=jC6Vjx)>3MxO`ES>P0E6w=Ial((p7tHb88NDDOjak8oKa^Ziz_{l-0~NIQk{4 z^@x0?Rjn~ebg7dmb*FP|Zw=wR5@4Mw>+lfu&#rR&lCt;kwEJkV+qh7K{LZaPY$x6IK91un#UH)T-&Rv41!kK|HuV|4-6u6S)zL-&9 zk6|3ssOB>(eJSvE2YQeu0Fm!h^~jXKs`FA*wHAZUqU$Md;T1}{7k=d_9mE+?DV2`g z*?b-+qQiX4b(#6BYT@gIE$Q9nyjc{TfsyE2r7y0{JaPnS@cPEB5B<9HZM-5eEkl3* zhF7JQDMaEqaQbzbtM+D%T1HZX8aV(oq}gnQldvhwGfDW?`VS~Km z+!lBO02J3ztR_leB3sw+{XF`TGFpAR>BwlIX*6qmOlg?F7Vl#OYvmU#?DXo&>Ce#{ z#fBUi3)5N;cSo`uN}KlsS2i(oiC_U33Y#4Us$e|2tDp z55I=T?47HPvB7$ z{yn2di$?-~D*}(A@VDyjM`s@i{CfhAqVVq-Jz6{x_*)Tp6otQ4cRxD&NZ{WScoc#oK%-e234BTeR8y+T^pAc!Gt1 zS%}B&NbaCnraX2kKHRAu_=WaKLM3^48DMM4(pq@)}=Y4-(qg1@#N?Aw>9=-WWMAvvjL=V8*@s;qS zUFek`5a+inLp|3hNlU~4tDy9UQFZC5l)Sv zzSqLXL2bU?4nh2>#3!&H(~3zL9}-at>tJ$FWA@hp+qp?n-*b^;ITnxR7%=h(CB)XS zmJ^eweKPL#@iLNZ;lwGmtWEaXCeer-Cn*sFzQ)M~lD#G+R!r!uL>uJ*viMUKE86#? zo3?nW8q5}bnrl~dsSFwY{EV!`h)_YRU1ZoE1-t!&b9_FtM&3b9$yUg384RtYL6!;z zq?C(K%#t?e%u?*)$Fwou;lYIfF8_2JLN{iSi(BPG=BsPGj6J_b4>*iQdrpf}pDQZ=TVnbAd^ZHMLaM zKC{^omaBpy%_%B3&1!lpEwgs?^%+8fBn zWIOwlUpa+Il0cZFH+9#EnLbx!T1D`SRUJsMrAc_CX{&WNp8Zn580jgxi0?b18Lv{B z)m>CYXocTOnhw)(IU2Pf%PW*nAvJdLMTP!9)i#QvPx@Xls^DAH)LXGNea~rz?*QuGr|TSSL7%QU?8&?WA-88Mh%u#AfFpLSM@kOlXQJU4O!ITfZ1amE$&)Cg)Y3T zDwuf;Dv-&YG6x1UNhd2}>MPj?y`{A9gn$tQ^BZw|D75c+N~@U7(57&$Wg$nT8*^Ex zYehRO5~@@4{zcQ+N~HS6%iZKVgO@801^^-yo0pczvx9#+eMl)l~jWr zuuef%nmQS^q;Zj#0);ecHQa5Fv?aWh!r>beHkjD1=%qDdWy*OPIVvY0id#GU)K(q% zv~b4rydjf0Kt9rh-=9LS4+2TCkrQrtqAUxE$(El0$24KhPSG>x>>z7z#1Gn&m-n90 z1d>OvOo&w`!ctFrjHz_{svol9I-l^UtC8OQkX92Kb@vZWC#vvvm`X)oGG^lKHdbP!6a;1{IF%@BFMMV}U-(2~j;$EP0L z5-x0;tZQ8A#tud_9lQu(3+4mVX* zV+HzD>s9+fhQlGB*;bQ_No8W@cm)$-$Io{#KZz$-u!7ziaIk{c=c>7t6rj4g9yJ!= zZX<49ai5KKgHfzqu|IbDOtpgh^+E>koOP8l>O2O@eOh)u3gKYQaq@k*@_Vbnh=BIx zPhe0=*-+vV@E(+D=oL`AFykr^k^AR*){Wt`3>9*Ipx5}$YhdHxo@H$OdSpM$Y4;to zfk1pajY}9nsfujmm zhM=)=g)zQN-S+D6suF{yy$~!APZ<{tZB_7jRYv3^PwS9+XQZ~Qls5D-+)GTUCA?Ty z#j#AHB0SGXG5^vf2b&4}C7*bQV-MQi%b&25gYBU^(P|wElkTA|Zh-;!SlPK+cO{2I zn|88XrdpkY3&2VHa9!#_UdJ5~r|-i+W0MacE_)}a<^q31K5^>rAeFe50rc>bf0x(w zFHt~dceIBtys>pV)i_-9K1rm(mp85~%muYus-jHXj%tE_BFR=aN7pvaWo1cQ-o zB?;{#CDB#C#K80y+I2rkQYcYTxr-PF^U3L6yb`EQDYJ#Z;#i-?HnA zqSjQmr6Gj(s^s4sd>$0h$e&g$j;ZuniGJf7B51lqie{Sy%WGB!7&pS2l}L`V+5jwI zsYsXEl~0&J#BpefC#T6qFtiK`C`Ub`6M_R5mBATfEnsQ0BBr^U)Kh~Z3LWyglWvIy zjs7CPU{iMdArWf_F?R(ae{}+^VdqAe46yGdo=Tl6x&8h9He)uD_CD!u_O?*YaAF-b zI@h5XwjjCW=OXQ~g%QX^Y=oMc(nfDI;sBbxr>8!fAwggGl`Clvpx2Dr*W0-K6q~T0 zGePM5UVMbgs81U6Dmsye!G0S83m8pdjSrjkg8C9zb9@zC#RZ>P)i&IUg};goX{z`1 zi}qm0b?VgPJS~7aEIK)@3v{|9?(z(4geazdM-ltgY)$G#QtIHr?#fTOkw;1Rp&=u7 z51aDWg%}j9y5&!Xd|M`_F^k4EuC#km)E6P~(a;{3RYD|G?>FV35Z7ciTL9nm$ar~V z(S%3k*XS(@cTaRj@Sk^oUN^7-VB!(tY+~{I?lv{bA+cRh4NUkm+X*BCWn$Ydbgs$!#7rAANPPwye{P?a>rK7(ebUv` zrW40qk5LEM6Fe;oT8W@TJ)|~^S&v75!j6tAa>8oesSqhE1tm$I7qd{3>ve#V2qURA zrT9xB+?b&4`m2Lj&;-l$du9H~@n)`=g1B#uO;tse9vjt?+hR%^X8pOz_iyei{_WrY z;ivu|9RCspFk)(<)?fRJ3sskQ5*KYxzVKO3R#;YZdH#o{a{&KCLo~hA38w8^7E2X( zvta(oTtTWB%V;Wo&?~a&0hHiasVolC%cAJr7&ir6&ycA(&WB3Q4?BTn1fJ=R=qoYj z(_CI@p6I}#K6lccJ`gt8CPEbs+7Y=#ZGgg>C1Mo1hI!21VA;w=qF zQ(j&wO9(WUP%U~{o9H|NmWgjz71;}cTRA0_l&zjD#lVf1twx-nDjp^d21PLkVvuFw z7E$4NRTC49V(0mlhQ+xpb;)??;m{X}kuBmOBoPCeKm+l{*JvYk@WyWjo4mHtEDVrc z(dvDwnGwFqP4s^Ns`fCpm3j(v#ysOrMyE9zQx2nN>Y7}O0#XN95+j+BBPlUB>X3BJTvKxDTq#a__o$8rt;X5qD1K(Q z4oGS2dr_gyj-}c*8OIH@$*5ABL#fCmvqABj;cHq{fSH&^G`|KRHP&n2KQza7o*Naq zX3O@*1?vZw2HzyO`;W6d_i2r}=QjtFKoGTPuN^11ZPqN>0*}6673u{J0LL*dMq$VzweX@w}D^-8Qwxgm^NH`n3k62}> zH0Sy(CTAPPIk0bTs-=YN-z9P0)HM4pizWTk0`f#(Jd+GZXL0gyEF~h1oX{W{KLUtC zB*jcU8d);N`dyR0)AiUidp*nCxmRh(-P8<-G-m7X|UEaISTy zx>kFFxX4SY9x9ly;IM%h>lo>pdOt6B{Vx(Vpd5}%Pe`(;m&MYT7~Dx zo#8#_x)(z`MZgPVy4PdDsX381poGnFb6UmtGhpZm`!H?He1InfD~nFLQ^K4Eqn#BO ziRDiLy(6OOTne~#rzjh6&I~kOHGVU;bLs|3Y`N`IfVjI_ugWMasB4}?PdIqwb~PFl zXtihQA%Qw<*w7;FD4UbM%n(nFAN&-~(%@R-U7UQDX*Fz6jWJiF7QT&;W?jxRiH)kl z3HL0sFD>zUKaou-Va5L|UZe)qp{J#5<_%preKjP5!!rvWl7mh|x{%D}4Pd@3l zeTJ_4WgBSk4y3S>;n;?HDsye->{FlkjYmV9n$R+@4dv%dcM&0o?CV}XYf zNKB!3!w0jF;;q|Q9w95AlGNstTv68hyXP}H?6D+^&9=;hnApfdVxfZk`lS_`34AuV z5bkscPj)G%WgdGMP7o0H_fV{GMuh!ILo!c%2xsWpz-CtX+c z!exvxEMDu~arP|_BSmpGd{2as7nknf_kw}#x zh}Y4M#NTAOO0THe=qP8&_g?RB?fk-jnxO43QNXT{vLAh$WOIHHe@o$h@{%$CH7>7J z+7LY*BAM!)xC|(BCX*lC;XrJ~#Bh%%Nm&W1vbCjM_@PufTd4@D4&UA88)t!#tHVY`qmDV!fR=@{ zxW(HPrEh~1luAZcf0WjumRNxP{;Z$`c@$XEXk???kO_%yX$j!x9vZ>~r}(wOU@~MS z5{Q;9zf9%{#l4O6Zv8DDtjzF=)}fe*=uu596^md-03dYhTw`CCARB~+%T3I{=ew6J zcS;l`wMa-3^1?}akV{E5vYjPIJy&tph_O;FL`_Pyxl`Q zy4z*}W&TwxoMPLm5r%l#6eFmNjnp^J%M{=!!;g~+q#+0^WE&TntCWppx;d#u%Pq=z zi!nYn6PH2eY=Az(7IhctvFas9AuJN2vzRP}H;_8Uq+@bcC8=0>xas`z@Q5E2swPPm zDZ-6qn;oaFQi9yAAr~%A5eHWSZ{$3ZD#tU)bM^D*^d3*y-vgxYg6)x3`Q@Y!_l zFGSyeM5-bq$H?{Ngvr|s04kZDXi%cL6B&xW*65+LOYh1&^od6X@LkHPgfJpA62q!} zmgO4ibRbe7;XaYTU_+#N9T7oa8ZNlV{A`xUMiQ@Wq|x4z^DnhhUC^Zs_d(7tCxKmd zAv-+tF|Ps&#|36bSDew#xNuWjx^R)oZaZ$dhS}#sjd_kw_NDrZ_H~EytGw|Nn@NWs zzQOWa{=vfA(aH6rvlb{TAFVq3m?Eiq3dvZJ8ox8tWQ7^CQd+IkPYuA#DNF=REVEu) zSoO+fLb1v6ICzt+i5rbEQCDLgar@l(teWMDb#}R@dkJ1q+FDhN?FZCUt!)=_XUcJdsEj8X9F`N;)S+*I4 z+D%fwO+A$2T`E^x+@MJDq`+(&mBe(?@tZUVu`2u#V^ z?;>00V-+R;EhVRY=_4Xf%|a|wD>a%UiDE%ueCvuNIM|I<2)UpsEc5R(5Vf# zRx}+7E1qY)bMkQNWB+^6hPoSCRWt|6|!b`U|5=cQ>BZAu3*bR!FThBY=M%;B<83yEz9} zM508+x0Z|NFCIZd5*!#~*Uc|E(WUQUQ9m%(?R!TYRXBgvbCl7v1tS;1o6EX7Lm-Sg7j*Gl zC{T3P(`>MR%88YZOBE?H8Re$A(l`qb%xv=H_@R=$nHX*|?c1{1E@?DHq9x2>7n!*F!-bkG z26GqOf@W@m;R6wYtQhu4LjjG*yz_jgy4Z=r#4MA!i}B2~G`qk<|D)sU+ytjcRnRrU zow1ZTGu;+Vt`kZ7MNo!|V<&Ur;+%cl>Z`4`u-tumd?#a$LtUt0GQ7m1b{QW-k31Ej zNM%zlL1{KdmM5pJx zzaxC*eizx7C8nzF7WRchp;rv6(*zP#suCWakQO!t&o$7?{`f>k`EVmJKkANgRY-H# zG@(K}b6Y_>ZLs!So)-8eFs_lB=Rl#ZShTSHiDgHT7ad~cbvy|Hl2VP3ROt$3G* zc3M#=sI;%M0L#`fdhba*(8RrfO@HXh6MwsQLv|td+J^cP0v+9Z+BFbDH=LsoMKP}^ zr!KgXgs^*#BerPYP!>YZ{Y7{5cmJ3|fogkqlIF44y8><@9HQ|{+!m*$-2T2J>v>Jg zFpw8=bfx9En+^)TVhB4GvXz@jnPCXPqUGFhqHNp^k`iq6UbT}TwemBV;L3!*kvL84 zUV+3_R(pl`01F$R@C6#C;d`Vf+z|e&==0>1CO7}uX0>ron(`x#kCI7g4fl#PYz`eY z?kz{e8>(u=e%=L`EaCYCDLyPp-Cy)ulo!eO_m}tE(0$1fPZsOqkJ(bBg;KCZqMkt2 zh`sog(z7Xq`auagwB;A!aZsV5@s5H-s}22EQFrbZwKf(I&Q;o)A4b|N9nBot+jpwb zSazmFr?@j#_SEs;NgG&(Utk+Ebcl24jgkLIIqb2g_%>{3W&NMdH$JXi`p<_}kMBGZ z_&XB#=ajsM&*b2XpIbX$`5!(@s%?f<)FbQLJSgP1(y#0oA1IF1FnKMU+a zd}&oheo96}iLY(Sn2t!@77Ga536Uxboapm^dE)RDrE(2y|8}Rsymvn@jja)lt>{e= z9wdW(wc^WITG(Mr)#o65t7Z-`31J8eQeUTgX*5!fqI?yTd{Qk{;hulk0M=`uaY)Iu z|3;(u({fTI^wd{&3Nia^5#_#E=qzz?WTFVGO%6vPsb+r4D1OE%!CGs$QIX^UAt8mvA&jbWU^~Cav_2ZC52eebX(5{)kd6+L>+1u&L&plY1r##! zP+_Eo_q$Q{$$1fDhlVEov;DswuhP==4(ts12Hs0@G}8R*q$a2!($GA=^T=ZOgMxV< zu1~z2n>Hl{NlbqsKPCXc;!$ED$Rr4(v@sL07A%o5$Zp2nm<&7?Nd6z}y=8D*O_L_t zVrFKRTC5f`w6Mj@3@w($l4V(pEoNqBMw6JC*99jR4$77i(SZ{@oH+n^8XauQ_-KAi$Dd7q2vZl!Ez2y7khc0I<)T zCeFVebAN#X$~;t8{S^T4i(?{o zdKWllq-Z)?jgO|+BO?%C)@0!4<&Moy_8WVlu{Z-2`y-{u`k*^ zEVM;LU<{&Vd`Gf<*~ zrknHXiZgDtp`4xu#s-%@t?XWvD4mu3QX?ifUi|RfLP$qL(q*aZ(kzzSmjWvJv{RSv zwpB8e&js%QpAE-q|8>&MEb~aeK|)#8#k`6uG;~Zm8}n*U@x`B1vFv0KzrOuu%?kR- zM8RIJNedu~@s?I*b6~40^R(8abouSX*Vzm7B1jP_`Wn~4>G+wgRtC3g0sF?)OEFHE z(t8kP#t@TsKGU!AZB|4WQ-D!gG`uhy&gN| zabbR@I)qjZKCDFZuv#I+)RYFc1(_H*ZY;6OOH;8O2%yi&8K~ItnXK<{WISvYPLrvl z=R>$dR#1tsn+oaY=9dPPZ;O4O?`HtOeUo?1uhB7&AF*1yY}pHc*bzJ!Dplu#29~&kiaG5nhAjJZYiSfw2XvlGw`GkbLM!&H+eq3NR{^& zSw>C^knxxLf#LdcP?TfL_$<`PoPX1I`0qx9mxliU1$Y)7drh4rYxiT!b99eOby}h_ z-dV?8MEG{7(Umv=QRAf{(qK*qN-Gqeu#V5^TJZH~$EI?&!oz?;*7Cg9BKxpsO^_Xd z$m6lF%3isCob^1M(15Z~L6nRe-&~{|BRpA5U{s()Cc-=|V=+vZ1dTm5Zt^QqJQ8DR z_7@~b-_%D1atK25w5a^0IOET+pT5R^XFy|(iyPH$vyUD&<>vxYp{ol=qc3)jLnaxP z5@4>};*v}mr`cz13yZcRbS@AYnPyK80G*O`HbjzgfgrRd`Tbj29uF(hE2kp`1t{ZT zB}yHJy!HA7UwcLS)x9}qb_t8&LbswqG!e6+J|QXo?%XRo*OA(ucaVmgCZ9GOpyW)-mDZ%iiJba_ z6zjv4a7quz7g|=lP+kyDkr9fGNk%$TN9;)#jw4-VwrmuRY2jrF?=z77`6=WW-D921 zJOF^gI87X}JHnh8JMT+k?OrF3UAks5DyAIoK|9qlHzEax(@HL)nHCYCthsGxlzc9R z^E=1UH(jgGn+9fwuGu-n96fdeue>$dI}!v&hFLo|MZawhQSE zCjD>x*lfGl>G^Fu$pD)9X%>czf`rYgMitIFCnoFH9!Q#0 zHT)-iV7)=&QsL#5J4{rejPWq!SY2uLL5^e&vlcA?Y(1Wkk1+&68UTRb#oXrwVsU!? zI^Yw;UM)mL-{jP;^t{kf+CFn>#RDw9SASF>3#28vABh!iFvfrE@__kja%(K@-wn?{ zzNR|KWqe<*LC+hJ6owDNI|NwY7&`c=af zr4y-hrIcNdqcf?|+cJVlA}F^R_8|)IZLHiB@6hq-mzW|6oYUj9l!=*HM9y!}6K)-ExVWe5BBEH{+w~5cNm0}EFX+6&PwY!okVlZKrDd_oR3heD zs}7NO89^sYl_mwiCAo5e3E@M{jn4(A@8JCK=-&l2WMs6w6QBQX`cO{0%QU{9&kLQI zTS*-#^NPRdyy#aan#fkVWV?6NTtA{xVO_VW0&oem>Jxd6W|En;2r>11g5)+&#V+Dv zbq{H~dh_uM8goCM#wS41CcpI!#vjnh@Fs&Xeo06=;~&VoZ`t9Oar|*H;4D!jgQ=)7 zvYt)0U%&T$37#1NtG8}bVIu2bO+JkHr0pB3Ooi7-S8LWLAbop3b@Q!+A4kAT6dd=U zM#FaEFqm^Lis=(gDINIaP(M5|6877bvmr4zHAX?BCgqCs=rRUfK6k|a%iiUia_KPD5~j%!9FA6|ANsOm+G zPD*fqP%?~f^9JFbi0L6fUtciIC>&)ldrW;%L}}>RoXxQtdVIu9f2$Hz%S0(B*74E3 zQ}eiDRT+*h_%aJN;NMkf$J^k_V>Y##&7XFh!t14>TVk4vG(C0?_Kkr_BtDKMaE*E5 zdUWS1%cr~2sWFxD@(jDYa%=r)faFaGd&TaaK6KUZDP>kPUr1A1mLi4pOP#kyd9FZ- zmBrlM(m}tQOv&43nXO97iaovhK2nT)Lr{z%J$B6I@KI`fytK!(PQ~-}MSz>HE}L&; zK#u+aIc2@Ud%4?GZz*sHE&!gOYMeY3AWf?P{==`gyA{eri%wOL9DUQLNHej|&awwA z4)7*@$O|i@6L)t>MRD=0j+1@e^VYbYSL^I_a2fX<(|&Uy=Shxgorx-mm%uR=<3qV> z{^BywfH~C5Q$n+#ls?Jk6EA~GD`fmG?_C;EyfUS5DRS4>(N!dQMR!ireTwalQr zu}ICr`rCDV3Vlb|LvRmngj$qU=i898j*3l_IF}BvU_us2CK-@S#OAulBc3dV9--+Z zNsig%RW^Kh1n?H2CmQl#j$#J*G7X+-J_ZTM`qz7kmQ?a8X%J*ZLvhh2B2v%1O+hR~ zsV&3FZX2Fc3`Tvoj9IE0axZa-+sNU}Q;MXSU`A{(*${+MAv@ien>1g68n%?c(5#C? z5Xa)6OhQ#mqCL^+I63_EElANWxUmut@& zT647Vbx=+_I3v6<9`ebUTvH}SHdq_}w`fQI^1J`vxckdeVE$%5agk)}z7zjo=5d)w zCsIJjwRg3|!dLndB-sn#p+yY=(24q`U#BRe*|aPd?*o5}w6WW1>ReX24;fQ?=XyIy zP9i>w%td(x7@)>>piP(}3Ji!5#DjIqg_bMpv<^!nnv|)k?syXri-Y_tbS_-OVg3-p znhnD|$_2)W)b|Q?(J(vXqBJcq*#`j-XIwnb+2Q4q$Py?;%ab-5$0)~Gy*&z=AZE3wFVktai$oRF*bctTOMzx z9+KpQAEtcC38YG)?6O(ot^n0usKPxaPcy%wPu7&7MR-`vunmS1$&MW3R zczY4&rN~w;z>-uhQ(x|&QbWh?%k|zw&`=3KtcHaa=y-q&F;Wc?r{Q<+zb!@6MJ#n> zuTjN`?P3lAj`RymtZ+#~yMLwzUQ`_t5}rsx-OZ#W+0Y}{h>~Yu?P!f3hOhTT@E&nsoBJIKn*BYGRT!N^9N$hTGkx zwVAdply_RmJoPx>nZ(dt#>|F0jWUWq7vik)w!S$-Bid&*CFu#Ld1+7`9*M*XA?VSkmet9$T4*`OPRJ>nHL49JX zd+4C_u*2Bw405^wH65smlU4qaNLf{4#gym3{XPZYczzjeh7E?^(Nbh0YlvGXAGq-g z!zpr@KGiF08*#J0m0n{IiC13XJTF7@tGmAHG|T-xA{i7eORP_Lwykc3rU zA`s8_!zpF?yk!pSxXFv(}e~Ca}~#ldUE7P9?<) zt>1tvz6jumHbyG5wXQ=nnt)mkXHAq>`f*~RXclM^V>QMFAx}}4MYtBowleb870VLb zKy>GP%2`W72!j+l)fkhdjOu)Bj5_ZMbjxj+n%^0E!tx+S8~DyJORUXUST<(ffKFZh zzw$l)0~9bv5gov3uhiUk6Hv8X&l>3}R(8}rh(+-CZjN_Vxg&lIPkta!gM$E4R9!qE z?>Ggz8>@!5?52lPKQ`EH$*@g3Yage#6m`S_B(OxfYigSpJmo26PlMS~=mMBo2QVe% zj-(j}e|NEsPk4;r_u{+~RX=1Ws4>S#d2;W2M{r4e^tyDiC+ci};1vlo%W>>Nqm928 zr|?hpX{PmsUfImF#^kdSeWvLJ<6vsFQ{_&Alg%j4Hh;7QPup^o>H?ri0;7l{zIU|= zZiXd30Y6yz-I&}*7PR^d9HV+UIwni@qLqyftmoqlo=DE;U-yrx0$`St*Y+KCP6_gv z^6RuJry@8h{BwlKXoMr9gn6xtCb08Bvk}uRBlhzZvmyNYl@2aP6|&!k%?NXgd9d6% zEEYzsA<5|58hnyc>wMb5C3RhRRjGHL_4!qlR_w*!@5;Y`TSPN|T(~Okq)uY(dk9qvMlfta~4!vhSWdu6dt31jg5g@A>0er}_EGQ3qA~ z^K+BMID;;IkYDB-YX zYoUzI)13u1R0PUa^#a;`jZ?X%zXdL^wgAYD7%mrssLGnQAcM{oqH@|hKOKYn1ujJ% zlE@no&63&$U2wX=LV9-%hDYg*FJoE6nXIm;4qIbTwPS&#TjC_z%~YhUtZ${Cy!UlZ ziA0?2&-3`98OHi!_kGXS9PB{lIET(mG8&dRk8&R^Plu@#;&}lQ{Qc5Gr3pP1Pbw_W zhz^mgg?-Nw4#w(qN7OR_9!bpb78RF)!kSSmkxR+kgPcOxDL5w;=Bh zP_j;>saf=$o`bfd39SCGv%Fdt5Q007#tBnN4}q)RpsI7f@d!^O?FNO0p}^@h6Ps}* z37kU_KeMpG>G9zkLO0cy5@RcPR>*5C4WMdVZ*%XXz5oymkUD+#BA9@@q;;Fl=nJ^7 z-__LpIwN7o#u)gSU#+?9$VR8kex_`y8`(YY{|;Ykz`LZDiZ#PPN|%48NJ!Bx;^#5A zq~x8BSZS}n>RjP)$)k^gwLQMRm#~M3k!rLglYG003T9H;aQA{}bq_yODb67`F4jX! zgVBzyq6a&w2W*@_dFCOanTfA!r!cvppg$m#aS1ya<+*5-!QZO?)tX| z{tIg0ABMu;)n)$+&g|bJ{jGujqz3*5h5w}D{_gg-2L7vR;4ha#-~T=IL4Y2MR{a8F zq+F&PZQIHp9^4iMJ_w&q5B*wN;*pSuYmY8@KP|O(2GmM@#g-Vn9rplym z1_Ro?aNPxmsNgxDX%-9*HWv6&7?~`q7=h2zKS<}1tFV;HGq<-7BxSVZVGxO^bg%OW zQIJK!W%C-sjTlJg-Mrtmk$Tci zkhp$szv}Vu4^Mv73qJbu_eA~wWTO6O$ASMJK$?Gm0`^Ix!#st*|Ni|nIm0U)O0%m1 zQ7)^S@DFWO@>7y8S(o56A9t{5wiaZO5LW#Qr>Dq8F_Xn5)hCez{+v52F)*0m`$eN( zC#Robat@to_i_&WIh(-OrYw|_rVWY4r@gHZk-LTJmT*OEc^2ckdJ;NU*yOdk7bO1? zU)PQ4no*Li@Z{9JAGY{xfKw(_x1v|gO0@KPt^>^4nX*UU7cLrfhIduQ>)PgVZVE^)k zt|fct&mZgs!6d{n+kYd(<8aC=ef=QDLAd&(rhzs-!3DBI$uI!cDd*`Ts8Bxb!uU}I zgeZCX{{e)-Q!0f|q#qHC=V(Xt5_n96$aIWpHD)BbjSu+Be!H{NrvEHLhn+Fjp|eU9 z{MJ-5{;A1Gzqs5$>jby}@k5+$Bk=_^txsP*e zre7dnoJ;cd`Vo~E0XtF&r{E(b7DV(GswTFp)>vxJOVV)+)B1y7k?xQP+h$48Sf0(P z(C>C^Dac3>ABVPsE=KFC6JfiiQTw{u^eK69Z6$#-Vo7n$xtFG%u_Z0iQ5Mvslh^%!bmcHy#sMIuw?3t{mI1%621iU{g1BAxg#mal=$1~oR&6%V0R9M$ zFjYkwD&9-YA^JK?a;679!)JAiUM+Uoof9((>O+PPyL=zFZ~>1e@(so!V!`b3{2b<} z=!Op8(|v^&dk}+tOm0_pydTt^=v5!Bn@)zjuH)@dxVv*|e4v^tSX6^qEzC$!kNEld zo}meFv1JR=lYi}esk?E~>olhoJ*0NW+Nq>3XYQ1l6#%jwC-*4BPcrsulzMpe6EZq7 zE4HUP$Dy!M-RXLMbx2BJ7MG~SF9^h)JQzfXozjO#uZ~mVV8lS1+NIWx)dVAE%OfPh z2IH04j$yG!DR}c$@m*9-r-rX~WK)0Vw%YL)Fr}}W~g%e2gCr=oA?6>0is+dv;26?Sh-n75&4u8&V21i8GdaTj7|^+v}o zw@xN2c66P~bi_N)N@{0R)SW|azxPk0J;+&qZ>zmo6np5rEPtH#oGNeglUi{b;r;~x zm=2bNt8T?l;UaK?`)HH2vpx)0s0vC?~&Z8p+bu9<0PDtr2KCcbV*KtJ;CZqrzw zyret2Sbe5kUP)IWmqRBdrr3Z%^VFJWoH>g?<1SPwG2@eL_$*7*%%tldjkUVP^~bx6 zdQF0*n$+U**CO~!y_P+0#e_s|&-^mTPnTvndmWtGQWtY~#XmHAfrGS2Kh&SU_nvuj zea9-rXWGWfu|0dA*An*>(i{M-AF-9zw_TGI#*ZUJMoY39Je5WzLW_4sp7h3r&t?-X zK;o!^|O;g!cqy2u87_}*H^qZIRh5h(|6(14b_`4K^@$Nf=$wbC9)i*Lv zcgwL9A0z7Ja2WB5&mCT@0;3yX)s7^!f4DFN5?-IpY;n)7O#`oK*S#i*t;g60eBZrJ z$W0!BT-g?`q*y+u!-U%%duJO}MTcre)}L7uAIIH3HolDK)O7dzglf)z=h#?~_fQ`k z&w1HK=muh_p-JICtm!#F$l4m~m0o}o2({;TJr9|oHj#Q1x^OJ2tR&45v(%{~YdY9m zF7VD3`Yhz9dz{r|W%+H|D1I!Ye!Mx*orxHTNkBaqJr{z@MnJlPm3c~w#G~sYXXHp5 zl@x!I3J>3_)WfLPg#GoJs|}jb5%xjO9_ecU1sNKd*$+8v$jPNbR|b2o*eUPfZhs2> zd8$OKK&|Cl& zOU)iRISEo+sZ8fVa6FEs4#w@}3+L1!Berl%Nvow_wmA7QBUXI#VXEE5Zmd3%)MOnB z+_F~GmZEnY*YR2&Z9A2nrUwHfBlT%e*lC3{@@>=fEvZ+u&}5cm^?g9ZtSR$%3zGd&vkS&8{pC^bLe7p(mevg1dB~AxGLYY-XD}M^r({i$B2|U(V2WKTYWy#yWag$S2jz?Y*5gE z;9BT8V!mEh7|5LCN7f*~oD??$ZC{S)SivK>`b2Z^0G%QFk*Mlg6(P9H%QD^urzVeX z$9`+(e!MQ1Nv7U^@GjQB8QFL^54*t8jD*H~Jno9OX6sN_l|&)u+cyAW7#c(*M`R(0 zDSsHXT29vk^UM-04@)yweTDxx=>hX_dEpM6d4!Uox{PBKI-yh%RxKRW3Zf+|3|Gm zvUexGVSctAweR$GNhTvL$bxCHFPU96m!!Wuq*;A5g_k=;>6h|2RmIz)R*veud2%1Y zS+vMcu=3B(=h`25imA}m9G{rY-i7kUA5AEd&;C+9;L-kYR&r{QZw+h}{VZ&z9fFi***7tsZnWcS+t+tltd!1DXMFMf%0DWjOM*ONb4pJx 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�W)haEjBElS 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 z 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 Fe*mw8$O-@e literal 0 HcmV?d00001 diff --git a/hw3/dist/demo_assets/spritesheets/platformer/player.json b/hw3/dist/demo_assets/spritesheets/platformer/player.json new file mode 100644 index 0000000..c9eab64 --- /dev/null +++ b/hw3/dist/demo_assets/spritesheets/platformer/player.json @@ -0,0 +1,27 @@ +{ + "name": "PlatformerPlayer", + "spriteSheetImage": "player.png", + "spriteWidth": 16, + "spriteHeight": 16, + "columns": 5, + "rows": 1, + "durationType": "time", + "animations": [ + { + "name": "IDLE", + "frames": [ {"index": 0, "duration": 1} ] + }, + { + "name": "WALK", + "frames": [ {"index": 0, "duration": 16}, {"index": 1, "duration": 16}, {"index": 2, "duration": 16}, {"index": 3, "duration": 16} ] + }, + { + "name": "JUMP", + "frames":[ {"index": 4, "duration": 32}] + }, + { + "name": "FALL", + "frames":[ {"index": 4, "duration": 32}] + } + ] +} \ No newline at end of file diff --git a/hw3/dist/demo_assets/spritesheets/platformer/player.png b/hw3/dist/demo_assets/spritesheets/platformer/player.png new file mode 100644 index 0000000000000000000000000000000000000000..4db71ac37e1a3ba3c701a7228ed56639e3ca091a GIT binary patch literal 268 zcmV+n0rUQeP)Px##z{m$R9J=Wm%$RlAP7W5r~m)U^inzmSB02NIPx*T1iAfRCt{2oy~FFJPd}Zoh`&aE!ekQl2VcezEZvhl2VdOZgvZ{(}{A(aEHq! z#2L_pp*hQr#}rlqP*AzP=vlb_U$Fx)fWV!oWenGHAkF00RI*M2jl@7 znLY-fg1{Il1xR7hXV%cWy@dR?=zAHkB9HiUGJj%aT0D2zh{WN-09^t}*%kSgJkThdrw50l<8)-f#B>9h~;Qt-3F) zL@EZ*E{a*!bzQkd36ez(mTLfe$h8&V=JoIrO5PaS0{I0y+~fhM_5W~xN>M^tN*?aV z;M*ZN3(%mnXvB(~iUC^NYhgwKD63-4XH&HF-vXEh9vmpZ!MRKWYfV+yMq(N`T3|R! z9^fVh*ir_LPt1KmB^5}P6octj8 z9jW9+O4}`T9`Hduz`-$75=Qw@?Z|vio}2&SOD$oBOTdy(zc+)UDc5v)08i+zQhyhy*Y)=D zxsvi6Bjf={?Tb6tOH(a;37TkI02AhCR3(_99zeYVqoe)*7W}{LX~j$;XjDFb`E>dG z>*w#Q?U)|&_aCnny}bpg;DZANI5>y_m>>q|#J8{inVK1V|M7qFi{9Jk$8s(vU4XU0 zcg|*?BrvG}o}7kj%V)r34B($OD+A!oaLNrJ2Ixra|1{>=HGOPpUjy<0KpfK+U`D9f zglF$y6EQ#m+!$c1eTtg_JCWNhVnzF3k1F@Q1lc6+8RKu=kXxg_1r> z-G@IVAcYRLg@gvB(?Sc z7U1AO0Xj0mECvd|q{R1IF!dBr04BMoyyxIcSQsdPaeBKED1cG+avM+pCVLDNmV*t$ zsTatxhjKvyI$=5T4}k&*vFDs$@>);;Ccl3E&OYs>OUChWy8ydc6mbOC)*u zl=T23)3PeK$CFM01rWqP@il4S)Uhdr=oMqY1u&s1cxwkNXE_dA6l$HC7@(w}lX}-M qbsZFh3<#w#T1&@>0Ti*2Ecy%M@${2|+`(V~0000BP}LV*T%TC~NXxR&Bjptw7T0SFfafB40HoLt%AQ6=H*rYC?z2v z{DJ?E7r-$Apaqf^05CSOvXByd|58Cw>E-vfpNpoprP)vWAD%& zziN7>qid-R+UXc{x3U0r4jQZu$VUDA!?ycwYyGeTzuOivQoNvjQbG3X&%fDPzuC4{ zW>%nmdcNLH7UZ^6U3B zO$Pv2E&u?C&|hs@aR5NI7XW}c_p6OK6#zi`0svGEn`v5T{xKLx&?ES#PXNGa4gi3l z2mqjr003~xKL`5jy}$m8|HF5E33?AM=zE%iZl3{00A0XKfH1%Wpbek~S@Zx}03Cqo zX&%4}00;ZNe18Q0zCc2Je}saBgn)#Gf`@&FU3&?s75BL20 z#`h2T@m6ps2nZ-R7-*P3cKL5TJhcFTu;2>d3J_p~0B|4}1Q6`01Aq_u`@q2=Ktuca z3jm;?Az{HFV4i`)fnL{o0RRIH7ZL{U88jRW45)X|{t%ErC}$ zLdyRsV;s~6E*RkZ0Dd0>Xhe`uFwn4|S6P6d-wy&D5(*pw1_J7jQG$U(0O=rKK_Sz> zg+^iE0d42q1tPaNcdgQpIf9$>g1pK4A(muQ|`1lI1gO9i;NKLK7S*z*@-&eS{s-fid>w{6p5FkYA$)_M#u zFElgMkYez&Z+r9mvK&3JGHK&^lqJ znuJ9Y445O78XqB&eNAEMOoNB=j4#aoff$**iyKPbRcF68LIhDQC(5vtZEB}pF>-}j zJ!D$rrMD{Pb*5@?zq6+H^jOi^gHwLN!uNf>wQ9fB#Chw5w6E{TEAgb~C z>-TkJDAC(+B-yUGvUCoq!Z*X;bWvMaWcftiijciIj}(t11_JfdfG@z_X*~g0`iG=< zAuw*b)GQPcP_Tf=ffCyZK^)b4yW)!h+YK&=T!s$uO;&n;Ys->;y*Y6~v?UjPJvq?S zTzHUN(AS>T#Ar$Lb&vgX{%PJ=iIDCQ5*ghGixlCHH;(PS1JbxTW737Nr=afLLEW2^ zdDzkx%Ol&7S;7Gd2?^ugHTHYn1&cg}h|a%nV04Uuxx$Tlz>lf&63=-T#cnkFz<9zM zf6J;o!|8Njva+qtS25kOX}G;%s&R2vS?`mkO9>o1FOTGtWfP{XT*=;KE)sp6_@_bY z8}bT>f(ZlyK&zR{Q3LrU(c0MAAlA3nn|v;grmX3UiOP= z(>JZJ+V+;H#hoPi*}!PlX$&(cO(7+dF)D2K^iK}i`ML4ZV#oH_U6s)`r7x3ZKR+UD zKLHBYA7XBDgPyIR*~uc97X_-GmAFlVBgD(zh6gLnc5+ZbhKi3H_wP309$&#u9y`bu zNHxUU+PVxrNW_~jF?LimNLl5{RLB+aNht059?#vpnfY}j7>~@G0Qx- zA1)rxBaep_Q8eIA3u(jY6o4Olb$D7N+}_|o?J#fhVu_qqEey#v%0L`%ZPaq&jYcEl zs3w8!l01d`mGg#0F$*6b;ExpyCC-U~quV-nlH^ZgBE0vVub*@K!Yx7S5=mK%z;-=) zk?so2nl0k?IcG!vrwW{oDyi*746Vt+hL`syD~tF()p3^Hg{wJ>9B*89au~*|%&3** zS1^RzRE*u*Kg#E16hu!>Iw>QaS|?!cg28;bH09Fu)c2a;5m@NWwsOk zKHvvg(F^6{kq+;>iVbXD(y>8*Yz)-#nj4(A4$ORuUh&}GLZ$*o*FTh7{lHIqA5DA-Y^>dz)x|bj`u?wcCNud5I)p@d?l|i6o@4zoDRlk1M~{NXT`BJb3s7ST*p;q_wdqmS12c z$Ypr+>`uMiyeN29S*#>h6^dpNF2FC-OUz`bLhYQdux4k;W2v_1evTm{-n-PDyW-r( zV)Djkd{ul14Z)h9oy3wKM?BB0@oUkRyi-(K-G?NPN4^leaLsSHkJsA}VnZv2d6bO_ zv^LAA2;qv)P+tTEvU3NRCW)*T`xV^1^6YrNR zh@nHX$)G+J@(`*zVi&QNyDlx3ei#v$XhH7Kyl9K zLlsBKc^(!d-|amrEH_KSWKv1xez|C1AR4E^Fjwa=2Umn;$$wXf{?L%#litjJ%zG;Z ze+o^|3AFM*?OzTvR(9kU)8 zEMbaBp8z<~qsJ~MtiDzrYF%grb?R$^v<^e2C$+{%e>o%dVJG=1*+;V5^20gT#fc|? zH+S0TZ;mF_%-G0;%(7PGcV~mWkuzqke&L$3UNP% zcQv9k)Es~13~Ora@u*RQ(^wGcop6_Cv=Omg!5a0((9#40b#$YTwEuZ*sIJB(=bC<+ia>Y+HCUe`Luyj$@z3{UDLv1>^cCyPfYc~7;~)l^1ii&HkSyVJ+;QM zlv8eqcL=-YUP-gBMV2t zRaAEs>s~y3Ho8!g!=pMWh;w#ToadB}5|47LFZq^8$R$`Dwdj3)?{p5P#mE0%6BMif zUqFQ3!hKzR0v=5&N9LvS&7ESL!?8IZ-#|Cr#&iiYiC1ExyRlB|CkVnF=& zgru~DgaFbd@d|bS2m{-&a}h8dtep$Dqrvlq*Kk)bay`qo^`XV#)_%>=cVR@1Av!^| z|DAXw#cT}}k3_W>Dw)`0Q25+OX!rKiA?~nKB)oDPl^6DqME^J-*pkK!L`Ld>TZuYR zc?;jBEbO;RD=mV*#YXNI-whC|YBR0s{H*I(PNA7Z? zrd`BG^b&Au;i}bKR+#6VI0@T{`)sKULM9)mPYLM5MaZhfn8iMGTGNB!nQ(`mfX=dp-X@cVZndS|0^pYOT%{hUE7skE&YDYemY`G^& zs1x64=;z}eV>#4VbH@95)N%-$DVC-`7jI$ddcM{gZ>7$d^_qxoKni#4ADnWp7QuQL z)W@1fS>T@Pn^#%PDjd2m@b9EV_4?Yj%Tpl^VtQTN@+g-uZjkeFt_egQ^$UHHf zCg-2SjF;to)w*m)Bk{hGd?-_RF-@u$x^V;k&MEx)=*k0OpK{mm`$D%=0^ zQM~+I5ujws>q^O`NME3gp zi@4+tEI0w}wcU+Br_d(?Bmz3YOnW?ylu>4Ed(-KOqBrk|FR9&h(*%KDlfR%CCf zqy3JgB|vdWoUiD#z*C>1eDILt381xMtQK1DQz0LDiq9CIOLuP}e7r#JkgG_=$6st^ z9^>X3&=^#7pp^UUB?eyADP>@7)Ii`G2SQ?&s78gA^r+#WNH@E}efA}+**>56%O6pzs;R6(lA49B6b@`^!z8ktNyke|c#=y6=!y`up%k%G;T7x~0_G}kd^Bh8 zUIjX`jqv(Uvt=tR%Bw8h5XFy;j9T_kyL1*GfmM<+9UAXfvDe!AgYuWP98e~Q%+jif zOCy|>df#U?q4O{%`~+a|b83w`Jyi21Ted@EB+9fm@=kuasA(Kiw%bqq+#!DJd|0Y{ zHI|c!vS%&Nu_dUZ`s1wC$VNOaTTxWxnP_3VBWqjt6-m`vUKTv^Yc~KTI2CCEANN)l z#si#dh0B|pBQLyj>BpnacP@gRt_9f-aS}ZB{Ay^JaK(jTuTc)y^Av_wXS z7%Do`)?_W6MNs#3j_#V*F1OWzk8?>j*U*&Z*G7e+tC^&52ljubKTDw@P@Di$|v>5$W>I-MMUR0xpbVAMdgfGDfUp_Zj5TN8dFgkFo ztVRzCfI#ikD9Spbt!&u~iNx5Wzt*!4-jmEz#_v&@M~VWR;Vt<3iE$RZzIwj%mQ~k@ zooVD#Asn`oh&OpI7W*dR^Dy^i90C6Q_vt$^ympVCXSl4|^jZwoQD~^fx!T(*r!8Y! zOx=n_%-3EfkDhkXeX2O=`%0BDUocZvY!T<50JbX!o05SkjKO-c5lL|?LIKfqrz~_q z#7Qks+LTQm^3N;_Is@Ay{`31wmgt*k z3%AZk^O(fa`sZOoZO)3?^h8LKlJc57{q19UmBUvG#NW`D9Ff*nF%2AvopgQ9B=46kc_GW#^p!@GH49}5 z47bBY0y0UV;TmgQHouJB)9Xc*o1E>MaZvM zOBmN=tJ&JMdjE=!#FIKSf#|UyzmK6RAHW?euXQiOIOKkyS4+hN29UFN4v3n+;i^^$ z@#OyW5KuH|iK}oK%2NvYrqQ2ju;#xLBYiVl1;t3WNcf(62~&mCGxPhi8|3x8L_`JJ zOMB3bnF$tey0sXvb8b`|o5FVmbsj~7$SjKOJM=R;Uv`^iSEach7!}7a1I-X(`7gf; zjd}wm(~ZjLlQ}8Kk|LU44;{(ry_O`qNjavYTk#!irq1w z`yjDmXGI-P*fMh6+4>UaBDeR@l1ramD6x%h_k-$iaPk{$Z9VE~fa>Sh&y#$nB_}4Z z^M#3^(mMyslH&F9R;|W`u%`lQYEp%>26bG*v|Lo$TnjZHZ(ph@I$_xm@HcBIIHN!K z`o4w1F}10|u~4@y6UfM%%71U! zYj9jjyL6p7=75>`dKGfTYO}Vj9Pk&WBA3K&eooc-3%=cwWs|(if5;&C1>GA%%=AT4`J}zfjslK7u3(z2rtV;ewwXCML6lYTK6CflRw_I)Avwx-K*x^* zrPj;h2T}sa_XA@BJOo_yTI(`QTyl53wH<|nK@AGidMk)yG}Y7sMep35>&V7cy`z@X>nIGq^!l5+8n`ULN- zCX^l!KeeBE6c@^7k8zg+#WnKhoJR5G7yuz&eXcz(7Yt!A#I29@S%< z9LkmRihL;neoS(-kY4%!08v?vF+n&dAYW7AUR~^3(|Bb&LRVZA$f9%=;P0KdQHz*24D^sac8Cv*AgITvuQ<&GOIk6s(I!IF(hD~ifc zEPj;T4Z=2NpwaVv)MO>=OJPom~CYob6m*&7A{||2mhs`Kt<;Mbv`^~ zR~LP++M5r~`|etIOUpM6eWRhxi3F#M6O#vaAhe`$2LzMjb7Prskk>r{0w`-c7&a(n zSgQ%bcTKoASoL^m$-!H!Rp#BzaI5>dW&9}vf~Kw-O)flTo8>MW)9kAc)mgO0+3`?> z`-5xs7Ue;pSM%q!c*`UuCbi)^f|O$lHGV^pnPCt-qX#0J&8hn#^IO z#vxSKZR6b&pwsc2#gPp^sh0(H!Y&4?>4)F&FALeaa!r=l#kIZxAD@s+M{ zOwBx}FdnvG89`^rkS80*{gtRIf;qE`itU4ZN__6c+p6qrk!TOdaMme~7-rRqyvm87 z==G!Hv?SL;{U^ZAdsjHD>D#W9$4K&93XAdU_e$y{<7A)j2LnH`sW89D^EwexEye-p zGa35MAE>!CBnWa3i_nOI=81e^u_~X;XB`e@Lo;802+RviCp53dhZHhPcLkOvEHPmb zQjaSnoWY5**6w@3i?(i0IU(h5`lrQs7Hv3vFaAi-98AC#-E#tq+$A>>F=#*1M<8YE za#Dz+VG%MR$Sou+%s@$xsYRY;$C&4u-(RSrUeJ!iVsGouqws>6-%!m+bdxs(pi0@k z&wWq51NF`8ehq`wiu#^r3$wOgfRZC;OcIn_rCWRG5fYAoyc^sPek$c7X7dpJS$L0L zY>#iG)_;ikkjDu!{nwZeK}d45g7dTDumNO)-Kwj}y5Z~=1dfBmNp;!jYR4x4W7Q{B z|c9^&I${ec2Q-NbciU~UA;>0Hk?^IwFPj!R2b{o z$)s-xh^T6HVRa6O^h~g9UFmdTA0s+Ep15eI5J}1mH zbCJSVZRe&=)zp)1uG&U}wzd3crCb_y={6s_?t^?9J5OO?SUZyHr>pcJC^aV8*bOsv zyeA`6{De+l2Xfc86#!FnI&cy)^pcapcd^Nk7e9HLMs2BiWh92*dqsPzM*z_To4I&j z2S{&NC~Z*A>1`$P8xl$*fPBfDq3~eBY2nje>%+1sMCPF9*srq~y40>$DG3Y}AlA=v zkA|b40J7Yd&FfiKey>GDwo~{aZce}L<~&Z{hhYfZSQ0(~m`(vZ(l%fYvr$mr5HqUThYi@-tz6((IA};fDeUVME_|VYy*qmH^^&hUrOl3YLkolBa zV6>1KXtfhA4+<_o=_vS*ge_+Rni9VBnGoc`68Lw59D~|0-e|=*Mui0PKZKe@vLy%q z3#ciyzr%06dPEv>A>1jSfX1%9^Qx-dAZE(=@#EYcLf*I>Fvl{IPf6oD9HSz^HS5LO=ZzI_h;L*&BQ^qb*)b25#;erZ$V>Ot3AxBcux%$~ zMGRlDg_ULvF(EZAH{4F0-uP{(^I82)yL%`I_uG(Q2WQ%{UaA{JwNdQo>)kDkDeNVS z=4Q$$qd7*i8O#}!tw6?5Em79Xh$|hBTjES*MdX;{xBh#|=b^s@Gx{35ynkP%m=|BX zi-2^a6%yw~_T}qprY+BQ|9jg^!Npa@#&7pxAJ4rJhh)9}$s2AtxBK0CN^EmDAQhV` zl{9r`0-clj)ly%|wTW-`JUdracpeD8F@-NxCpk-`bBx>V*6seWmC8B^50%Q&ahB;- zkkq+sWYmaX9zo%t@y9)-y`f_>0VE-$bA=~B3)(oT(*Re=g%{3ZVua6|>%mxO6B0^mu?8g4U5M*xJ z!ERb|06HB7Mb078w(xgl1SM6?b3eLF#>HfqaFN7dHf&-r2&foq@Q~T2zA;e2KuAw$ z9+zSa1_XH6I~TlIxG#uGviB;&M6jbYnR_GAdrBKsh+tEKczUGF6Z@!H`~+}IxQ8-0 zcYW!Ars)wWa!Gdf<^H1j{x4X_0Q%os1ad?OB>#`FP#&senL*8JShZo27Il1zaJhbD(;7TV(#->=>yMNp$_FZ5aWrS)i#C(?7#No z^1e&qwZg&?_bQ7>r?CM6bp zI{!z`y|eNyh`7mH5w0+X0$SmvhKu!*4ar8oq3){smdfo=MDdeo*RlB%*0NA=w=7A3 z1cBA?RF3eB%M*R$+l0ZlhE)j}0>WDWmQwUIpNQbz^CB16CWh!VA zHz|f=dIDr}8Y|3d(`cOPCNc?*(8g$vAPbW{;5hASg@-457P-^n&9#KG8PrO31JHB5$~_7e$-Hq zW!TU22r6_$m{XEit&n~FdN$5`%Qcjc5b_S~>##wn$vzi_#hf5z?&&^OJkwgZj4)0< z)FO@&Lhy!%1rv)63ShqCYO#G^;R0K^&mK-X@?>-Jo<0SzRxM>GV;`Rg%Yy{7d0Y1TZJ>kkBgyrQDEynfZir7Jo6`CE(+ zhHNqt9+O?K*Gw9T3v0p_3SSwXygY!uW0kMh#*)U$X*Jl0W@*>XirO4*YUw7ZHJs_* zhQ-e605hDGOHAHLUeLzv@b9>H(cZ8xn}7TZmae$1lH~jlUSdSLXJ*H3m)OC^L!%9s zBpzv!QK5b8eIn^`?(5i4AekE3{#F+N%FEEIIer043WQc?Oz297Oc-JknS}s5HBX03TzLq`wU1iR}JwR7$9`5J;J$#d@H^))4skC z@W>tNKAb^7)gj1*C<0%t)9IF%P8tXrCU8Stw72m$3fsI!E&RQw3Awk0~s_UpxF;b&h)XoY_%jSG3xk;HoC7PGkrugAXrajks zo-&x7+D38BH10i}(-!fYLD|-gZQo*RFKtgtm!d|InnE)Z)5+>Q2L7-=^+9k<_1Mwz zX%hopRi>Bz;Xm@OXlBiH7sI_2^_S5?b7MHhURH#}j{l2lL0wHNx@nQ^b$dPV&9>e5 zF_8YzS>;uqRlnZ8(%SebB>WJrCpV`FM1lK*BJ7s+TH>(+taEu3TsIFzJbYfr^ww+- z?y8+8+Rn}2nU|I);Z=I)SPUk#IJ2X$E3XQzAD+WATcrgv(J=&=e3|S3qV@D@>1(?a!_-Kw9!b#NnABvmt?dkbBGz}pY2** zq0kSE_%N^b51g7D28<8d^^s6WeMh-t^L2dM&U3uPf~YG*!CeGa6?U78Td!>Uc}T58 z%ffOzH+l3>MrIr*-O)qax4LDQ7WqCjnkR6W!C8=0kUa;f0+Vq!2l5Z#G;_7~Hh9@i zae_P&yl?XZR@}pS^PsxQmB2RSRU+3?O6X!~f%l1h+ug2g!Ne~RJJGC5hhOuU^qZ&; z&}&NxqwMfPIx2rw{j?fY+`dg*plzZ+ql*)D%yv(%uUqhZ(ym;Tz&a`}xESi=(f-4p zT92os<%}QeQqjB%7{-B$KLSY0iEfD@vv%wt1V}&@Bspw=|4?g7(7_PmE4OlupmW^w zipoi5*iqu-L(`%<`IWJhEmUV=?RlNT&ZjwhZs5wdXCudl#j!{rTw8tQ zh44rnalul;d^+*W3^FAhDiCT+hDvustBv^NbBY8@Yx&xV;$0rkJ}Mrxh>1LVfOvda za_UDA9ScGi->=rq*K>bb8@@@P#7g}}xvKUxCE{T|IuXo_6W+XBxJt1@_|cvF(?$;E z+z1b!1t)@MJeBLqe}TShaPSfX%vt{OQA#!c8aCyz*dZ4A5@e&#oBidsq|A=+1CrxY zgz8*IHMubtZn!S`mYu)Zs}xZAbAqtv?}8H03ZbcKTB@nN9{*jr)55bjQBrzl0H2cm z2e0lSJ{I6!KL;Xfy9!Jlp?YRakdFA?LG@#+9DJk}Uj|>%(IkE@j%<(b#fD}3CjF!@+icV6U zCbw<#hxI~x>QO&+Is0r2|C=e&627=rEC_W^JN-q!1J?-&$G<0Qs}hihnkvP_$Kso) zVDgjr{KIj;52<{-<@$FY!GM`8Gr-FCJ4{^x$I*k;DbdP;`d34uuaVsr&Olh zn&>N5eM9Zn0m7TU1L`Nzt4Et?ck2FO4z}*+A|TG2NV8;pp_VwpqGrLwsp_&=W~u#u zg2n)x*gzVzMu@8d_{*Rs$*F>gKk*qM(iVF`r5%wiqxcVneGmos&)A1)5{vu~wF)u= z_y@g}a_9Jso&abaDo&t0T{RnWqDPRZhbtj!U+IOJiQscG{etlJePIe>;?*o1mCNmX zy)A0gv#u?qNFuY6hdmU!PReT%K6AlBQCo!@r#=EgyGi~gw>>$T5GxB|3!(HXkE-?? z$oeMFW=Q!=#Xjl5TU67&ncSC&;+Dplw&Rt`^!sJQo;(a=wTG5s{XsXf^esmi=Wnoa zC)It%=z|mAZ_QOeiLBfp#&>pF#UcLXb2#bxu37r%qT{a`j*IMc$U zplFDh-}Nf$0ztzP7w{ZsLOkwm6Gg^-=zg!K^t+o`NnG71Ky>J;%?z-2>x1x_rA0)X z|F=-X$^`RctV1N46J3LGz1)7mQ=uzoK#}y7C79Rjqru5NXg zNo4?ofoHu#CZaD-E82i?k+Ic)MhOxVyy^8{({SRs#MZN$z291*J`h>s{VOG9cdl~r zH$p1=4?+s|uIaQ^1*!gsBFen&4<;LQK*A2RGmH#k*vAdj5bq{f%nI~MOTM)xi5tRb zOx!EH?_WvVWG@oPig?Wl8{mUH6$9po(D@oSeJ%*c7HPYjY5NLdP@$MJm_7r!?al6I zBUxJSy(U^Q_Wm?Sxh)?oV*OG*@F_j^_p-#Z zuP3FVLKsx9)raUTW8NRNJ(>q3#^z~$r>#KrFiIf`4-nlA1Sovh(SYXh3rH@_G? zm4Qk#!+8JeczLb?^eN^gqs)oF&_didrVkk+;_0~|IQFi9qbj%Tv5&GdF2N`F)Nzm|kH4z-EqPv`uBjNi=ixm(% zRE&xA*l#4E`Bl+U29!X&hMDWG#7{$-mv%XGW|b~PUs2|QcJlq~awu!@!h2c6;9VJ^ zkp5WQYX)h0``9%icf(l3LI0#h_D;TUCnMHTE_q+mGnfkUgW0PNrrD>HY=yKKSb_sd zvQqPm%Gk=lrx*?hH+Q1>F0GfESuI_Wm0!9MbZ}5mfHjq-CAyz~yPqlRL6i4ANp*Nwng>$z#hK}5r1*qT>LJCWsrum6(nlKm-y z$rt^ph9L=e2ckRr)c$MM@Lb}!-pBX}P=EY4iu|h!bYqZi6T*)G~ zc&af|ihV!$nXY{XadVODy-e+lzzW7H<_(2hKm0Y6|FzNqya^d(`Pu;;_qz1WHHV?h z7Lx2do$Rzsy7{77>wnG=?zE|J`i*?uUNtir)EcC7=gZ;oQD?_Z3=?2^clGuEM&pQ2 zy>X1)`vVpI`W+ReXqW$Li@v3j70QsK7_jxBUDSJ=8!8-qQ074{CXSG4u~}1?VSz8N zk;ypuUmXV3^4PEy^%uG%^vw@M&&EIk5m{L`Iesw-Jc+KbO&AcqwIt>-29Lh~M*pi8 zo6dx48(Ef3tDv;h*tMpm8&eHjj&MSB1H(esMV>B>yY#RqWtUyze2LOpk4a_(iRMqg zLP(9f+!e#(259U9{3<74qQgcpoTODBO5MxUsk9L428XYD5mnJ8oNb)*PniPzKcOmp zcRoZH&?zH!=L9NCm0GfMf2w5!Eq488-_9JH#_e#gXg>j9_~WW8^`4mQz+{i~$m3(*}z0^I3zu*d=b1yf+%w8_C8&dY7t1d5DfGn@SG| ztmIM!Xfy!@Albo^fBik>_UiQgQN|_9BWzJWVLq}Q-!mqRlG8(Z++ywr=#+SSr#+hG z3Qto<{WAp@`12MVGfEf|ugI}-CRx@f|3iE3KK+nOyymfQ9r=h6bBL0bu;|G2ZQtf8 zX7J#Np^h|OT10!Kzb#^X)6$QJBDQYQ*1ExE%A$N^p1}|<$CzEvnQX)*ynaUBZ&QIR zKDwcdA#w^wGMVme8bV-?KnU^zeF_u;C@Zsd6x8S7OfgZyE@E-?5_d< zC3jz=!nholy5F#kEP3$h1I+tha0O#^;%^%jw;#qY!`l5S4_zid<($}9f>gH6>ro)n z?#44uj+KIvpyH>9^H<%`XG^{y&SQv8!aW$Aps(o0pJ9h)F#O%R9lRy6#HrQ+$-8Ot42xM{pp<;3&7e+lI+Q!ei z`=Pp3I5y~2t|hZSJ>u`CDYXc-G_m_{R0!EFu%!H|5Q2Z?IVZmW1Fr%X-%)aPC`n*Y z@d0zbixFYhDK>^yc{J6$d~}Do1|MXXPts(x?Dib3UZDX<@lj3_q@sNz?bB_ERk>pA zk~g-w=**oUf3c-^U+sI{cKqmWkjQ#Of}=M3s1r$LQeGWGD;vaI{RGIyj01%7iJ23H z_Kdh%6kUCom>AQHRm{wFgwH3b&j_tZV5~pbf%8iz@2fj_wK7o|B_)Ql_>!)dC~+DE zr)5UCX{>ffzZr!@?edl&Y~&d0Izw3^M8GK^j!RTMYo1xLx>XjrYja`vvJrhG5d{h| zq}Qt3Lb%h)p3*|48xQz`p(zb#P1)wbjnLdW6Zwg@dw&F;`2q>>iad^v+-qEJH$ODlc{ z%sWat_ADweRz@PLwAG4DFsma{xW0I#1*@*Q$W*N@^ldPuSU#_zGAez4yuwch(?oD- zqO?3FY9jVPp>eW*fE$ZviQ|2go?z;{c(2^xZpgibWisqJw-DdEJoaHHJ9BCi{oex) z{REGc{2RF+Cv_~w$dWh>^sa^|3>qg@4){KzR*S$VEt!Vp#oyR z1ma6sc=c^G(kaGfViN$VZ`q%<(ojG2a1yz@1F(~mY^id}>Xz25a*XEbe1yFnC7`;^ zF{ZanwN$m&RSLcM?f-kR0#+;|C7Lvc_!zIUxwb9|G>}(<#yKc>3bE$8ABM)xp4DF) zR1U2Z7;_(OoqVn|!vN9p?zhJmmG&~o8xw~bA7>Uy6}2TPb;6b_r9F|GK?#UfeB z^?^rYa>&3Sg$|vXnO&w2PtX4%72$ah>u0vaT)H(Mrstd&Vu{jMW4vlz?gfQZX2&*> z%-T3*wfy|0tkX5Ly3gYRHjh>)2X82zCzrJBlgT&1W?1&rM9yo=)f=AUlBqGABiOk5KaLFs z?tD-#ppyj7P&xuh5L~+N@d@j(xBQ13LOo6LZF$LEs z+MSP+=ZG(^&h{m*&0r8;JVPvNs=I%pRh%0^^~JbGtVsmkvC1?`mhP)5H~v?_9sA6a zm7wE^Xw>^-@8`1^u=H@YI`ts<#VfpsaW9@2Sp3j6xj zdr6!m`Rv|xm1i%xcVze(f3lOrti*jpC2XB zFXF3Povjixh%AnB_nQ(P4V^R$isp6`_#V{NGl!6+*(2kzWS@!FejY0+BsVfUe^-<}>*IWd0d?Y|tOCxw;O17@6ZoT~kSNv-4LI8p zB(|Kp9zs<3ANr%*i9Xhg|9japRxGCsYFXnXvVq4u!k3FTLZu>D>%dOV{-hFvlvep^ z7tA|(0jgU=lM!@OKJgEr-<0UGONlvp76^Fv$lvh<$Z*{=T`k@879z2tuNu-X_qw8B z{w@AsSI9cl{%W!OxE9`=F?Kof6+vyI^`V=@RWR!yO*(IcM0}pfRm@5JQ&X_qC6YS3 za*YGVDAm7SPeD->lA)1u!&Z7_GRpjF*Umb@QC$JCa@>qLFR+=2A3Be4Wpg=!f@*f6 z3x-!#kTN(gK!!CHDG-S!PKc%_EPEMP-Xp(5F9$5~4fyZ_MrHY{x_P(luWK%h^+O1f z&L02MB^63){wcUo`C4Pa{ZW6xyy>&=n(=}VKt0N~*JD-p3!Eb|B^SFZ+I9P-T>DlO zNY-|+G&vSEG|T>Wu7qnF0c}L1Lcv<@6IC=EOGZ?>x8-L>H{dB%1DbiCeKpun4X=4a zwTi);#4B1MElaMqLXe6r_#Z35Kh;)-Tz|ROu0bnp>^COjFGQ?)ROUK)$bM5X+Ao!; zRUB|&L&EP}S|&G`i*GcZFZS3{+RSFgz0-badXJ87SDT&vT%Q|vAy~}wSawnH0pgOx z5gt=OWTW{k2jVf2`_mJk6^$3Taam$2Tb{52Xp*N%x5rW%m zRV-Snpu`a$q^CfjYF^pf9vHjz%1N?1@HK&>>hqefmwAb6>b{cwu<5y0JOgZ<35(Su z4b$SWmvp2diPQ2urqT$9f@54dy_ua~$aIF;ZNHEW>fSupn8D=ggpu%@?q$bf6z!qG zq0X_fP@gMK8j6mmh>htiiVIr6H$wmR%Zub<{!p0xY8jT!dZzw6zba+6j9{b@GNx?& zt03^l)e#Jw33u-Jzf=~pD={luY?yrqJ7l9f@mGGRe?TWJ^gn6R4n(o=Z5YK*HQVpaeMTh})+91cU|`gJ*8f2vG>>iNk)dj5Y$L_cCS z4G1V(;QXfM4|2SN3Io3G_z$HTvh=~m|97bdn5||LHv#9r>oY*J2G?gq))nJs%(d_? z%JcV;mwH`Zli*083rX0O! zJOa)|b`#lKbwLV8n6F7i3utSohoR#xj9xO!u~lId*;$2NBNKdl8l1uUP&unh9r*l0 z8^rL&GaLc0@MTD_O%iPZGYe#qH)10%5c;B8xAVyLc=O-1FX5Z4%A$)jhIA=|jf)nF zcU8E%vPG-POjuPEPkAKL-pCv16cR0d`6*iyTAfK=HsVDHDgBM@d~lKN0F)G322~xX zB3gxzjIkZE_X!-b$uX_{6EN|Qa<5J2_Ml&KuTqmaxZZ!jRI*TJs3jdjU%JOu z)Kpoubft1|D|qmcl^40VI4@RKrgoXupyJeJg9D5`GWb*BKGOryWxCNV?*Shs&+{N5 z?&-|OZK-Q(%=YcI48w~rTCJU_sy4N)846$LwJp6%7IN4kcNBYPHm1#~NIl|{v(x=u zxw&E6I_Wo<*c6G+8iRdbjJ04S@7$3|N$Ks3Rh7xRQh3$BJ56DZQz?&*px+G6%JC%7 z6%CSB*>u9EU1k(&Jba(I^+2?-NU^b{i~ALgmwaF#7CYBkL1}SyIjI@bf?BAre&UT_ z>OCi?t)I0T(U2i zQ2nVg*e#)1ol!%mI>frvC-pZWv`dr*r;L#(*rO6*pr z%W5TVd0=J;MU0mil`xi9=!*3V4CmZ8oS3y!do=brmkH5c)I-8AT8AD#h>|)CW8B8o zya>EOn|adLWePVSIeP2;a(gdvoWOW_<9^Q|xV|B8F-psM@5`+EZdD$)YdN{F;{3rM$gOLsR&3KEji z2-4jR8xZO4-lTLlN`ucAG4MLqIrnwnbDsIlIL?;8m~nq0n0P-opfQ5`Tx%Hz*Hcpk5RuTosJXRcljYQMQCHOs4@G?12#wYmBoq;1#w5x z0Uc@Wr(^BQvK!~>OIt;hq(4;-E8<&$Hg|}XP%W#TFBf5faiMHP2?O-E=Wqf6sUmCUZ@QxzZodG?rL8_!}G$DMbf z-__>Th~K+@5nSI#B|moxEe-&gaCbdevLm6=`-ojr$p=e9{h3w{QtbOM6v%r`wSKdj z-nCP7>&|K7t2Ay&3-Lk_c2hxdA#Y^8U6p_79)Bcl2n@0ie5)|N}W(0;1@ z;%=-y_-T#e0s;o}B%2<2+f-YF<%1%{_SGDOrb!dFRPF7S4Rv3weTDMsR=RyVzv>0_ zR`RDY@2O=;h=fpva4p(X*Y{$n8pO{D-UyEyK$@uREuxJ?i6m8Hg8G>19n;)A<^$4n z^Yq8i_{^mixH~YFBc;>2l$cpaxu3jfaLmYmTVPadl0bungoO)xm}76C!%aJU{%%Vv z-{QGXhVT5NF0X@+4jzMhaIuUOa+amFqh}Kk%8UMES2qqntuRen28G*eOK3QT-LaK6 zX0ECycXJFUsr4zu0h~|KT?hn{W|DBK_}Ut_B6OK@Y@f2pD8~bOVnL~FYbx_KXWB`g zX!(;9xrk>-m*`D%4Ynu)jcT3GzJXl(o;4S3^6ks>9N(LK_%2L`17!5_2{R)!8}!7z z=KZHQb2jq~*55#y`7e!NE1}00tIHW9$JZMr1su>%8r@#q&`8T+{`!+t*>uFLKV;Jn ztgltEX+ZF5VWu~?9v{S@A=xzssR@DbIorCy2lm#iH1)h#aI@Qw;0H5aR2f)3 zH&}X2EKUidi-+Vh#N(089cag$FPNZ*+mys;*ejMf}7ssKSE+zM|_s-tg3qF@k9w@qQLN8K`Qie z0r!r#YH{t?T7>AZB<9bsRi;L23S6%^tIQD)k%aH681)G4m~@6x@CKnP#34OM#YXxrqC+ zoE_98=2k4E-M4baRtgwgiyKU~j(r^_@>sb{AwJj`YNyqGx8C*JoAGR;`PXnHWqQV7 z4%N3poAaqaUt|S#g(%FS3t-SX6A9vL9)@>aYT0VC0U3@x%t5(|hckz2cFH>L<#5&& z1;WeRF(!4h0QLwzZK6m zQavvqlmFA&15XHqvJlub7cPlU=X4r!Nge_sMFHH7@zTS~IpEu=JKGBRK-{_EwiHHd{ znDL^>FfoX;9H1zU0~Ez)h#y)34#~;@EsnCq*q8WH#R0$TRTe3wlPFyy)Eji;O!pE~ zGuFT6kbIR*)>I-8i1X;1G2!SpgyuEbpVp$;WLbIOv>{s@q*hEsWOZeKn)Ps^T~}bCnK%MXB1(g;vqxZpSvgP~2~#zJ`^aL;Ey()BQkrY74`iara-!-v zQk#bRj_A|xs1GR8pOZ)QA0KoFFh#q6NTfs$k$xK$ixPh_%)XS=4|G(x{PVMzavLvX z7{~ez1dR=+vb+5cOE~o zIaihY@PZG9@6p?Q&=gz%Y(bgpP^@6%noi?tc2P1u!!1(=8LnPx!y=OM1@o5GYL>xX z!=7=2{ZG{R52EYXGG}+IQnfIPXt<0mbi(8^R2kycB^c!z6C4qK@@c=B*~0Wo%};8Ld9J+tpj_Bf@) zO@HSjKTP+K~6vJ2yp)vCZts!N{cLWnxA~ zrFh9y;l|Jyk3SsGM*$y3dXyG-#u)1c^>^aIu(4s@6$#bvBKwWaSm!faBaLbpj&OAjS&m1<$Xlw`1E!<6N!dJW5E_PE3NBP0qYM|AM zr#yS(C){PtVT$}4BCQlHZ8S^kfjCBKvG$y-ASNi8fSiJAe-FU3M9-WUHgAtHg2du2 zC;G_q6B*ZMQjfTZOiFXf%}#!}ITRpV2lcY=VYTs#0e64FUdxxx>B!5ueNl#fXFv#w zDFmlbM=Cv4JI(0yaj6h3l_6GcfQ{frvK_{o%}qz0kB4{qMHMrQ8FlbMOd8V^Rk{SkTQFC4G2;B9SuF`xu2;pmKsIq3R5%6F8%W6`wOkfm!i^aZ(vHQos3~Mcy(K#AbB`rX|9)#ET_ef3f2H%2ni< zSds~00PCZ3buf9f9M02EModc;AQ01hN+Q_-!%`|@b6^ChPSE%Z(V-Xe1sKWFhn)W%3a7sO!gHhUo=K34 zJz=_CWVA2_ntD=@L^HW&dsAT+6mA|!RbOwQ^LnEH2r{h$CK5J7@Qqys34_9%Fx)X8 z&daiz(}LA;_V+s%mT4%1(xxYS_cLBx832etvpHl0&!+YR<2FusiS&>5T<;pr-@~a$;e=|~ObhMiz89@^&kBCYNzvmT z79uVp8}t6hOG+K9yzTL)ui90;eU3WWl=DcZ?NQ3NQhIP*@4hSTP_oH?uT~iJZban1 zb`R1+STNqNWAI-?kfK)yWA}}N@jD23^oEsRI_VuBgPskOm%8)Ij_fZ1nOm5=S8U)^ zNj**W*6`@Hcz;2*dwFP>lS(hg6jURO+kQF!U~)2iqKX?v=u9v@;aiEbHMNiJ@TtjM zJ@FMypj@@(Qht*fUc7o8vtRU|5TdIs zXzs#xaKL)*A#F@Q(A~Pfh86(T4wg<&kAv6UemjCDD()i!#o|O}BiJ*EIc<1Ta|i#> z+&#lr*vNZMqBzM>-PV$hCHS;z11e1w*+*A?0v-x*0;m=7WcxwCx%0L|Vbeb@0Gwy}}&>`Gktf$lhOjyr{1_MMM$ELYu;#F}dF1ed!JQ*GrZs?k*%4nu#| zRCY>T#tAmu&yVksC%ibV+(3+HF;8A4lP%?P;LHkZ?E; zQ-SHVctGt)EI}^X{jN1;bMSbv0p1OT@vX(4FiUMk9&!(-^C=~_@%>tmHZ;ecl!u$)!-=Dxe)%AHXi|iVwRXJakI%+j2G0MsIXHUTz2Lkd{NrCLzlXxOw zAl>u)`z_*%od=*8t~B<=5}e2MME_m5Mzv=`KgkDQw6w zT8ptwr0-fPifS&Z9=7{`MvQ2BVy;^A}u;Krd$91|^*&Fb(*D+&sg zmq%0;?9Jz4sVHF%lbb4R+L?tJIaa2~RnRNi+tO@?FpTvVPyk(l%t|-x_BA%S4!wBr z`SMe>sCQUfD7UZ{#raX3`zOryqZo^yVc(O1vX8Hz=&70*o5}_IL07+c7Aq7wiuk|k zLAd4)ue03F(T+Te-Q6h`=fG*|65cuY{USA+^qS~!>3Q4a!qds9ElR)}q#G{SJ^RXH zVDSOzedHF>(cmyNemwI6q59c%D8C1mY?dy zgQ;2;0Zlg(L9^-%sVb_-$o3QIBQ9;P2Tgk{)$HVA0k{sHjZ`%`>vPE&uIju*%q}T7 zQZj|QGHw{sm0yHZqPmkl;JCgJ83998E(y;xlj2IYtsIm>FXp&!`cot}WX!A*AiqyX zn~vO1(g4BR0c`N)(WQ&^C>uC>=D_FbK4&9|w8IkeUc8+9SZwuE3F_Geeqd2bYeLS@ z-5g7aPsEj{LbD3bUQ7lF<=7u(ZUS)EG)ktI_yTHnIcur!e8#J{Y9omy%fGU*2<~Fd#0V^Iahg2qoQ%*t zdTilaXl8Y;5w>3=nW*o@8nD7RqZQZs3a?$E#J>>n@gj1Qdz?NuB_ypN-~lwZKQ{qT z(SD-Hcf#Hfi6;>?BXHqzL_(U&`VFd{lI?E@xIDYUoqM%&i_7G}vTGCofaQlj(C#(hw*Q{7{BHTh z==>ftLRV|7%)j*G10%l^u=eV&gW+DkXmojGzr#K;1A_kt z2h1gYNd+xue&s}-Xw8qK_^loPW{gD_f%lpUm5rdhUi-K-={Jz|fx>z5>dWyYQ`&oZ z1IJMr-XV_pQ9BM##*6g?ipjeo)#BRYjE(UxLPztGrXVnf6qmX>PaiitMjMb^Q{(rc zj%^&9JS+&T3(~e(K;h%k4be&5i#(z3nNKSY!2t(ns;cC$az4 z@WT$JBFnOO$lNa6o_#58M)Y5Z@8s+H7*=pL59GQt4`(xW4ZC#d)X^=BC^0OUq6p3& zhNa zN09Z?JlbQw1gtUA+;@Ux-P_o{wc+wi{w@HB#)}^uP69l8I=@FmSWPA|CV}N z^nCrTDuP5nkathiwFrGv{=!>YAF9}5#x3uB|2938=?#>=2hSHu66w+}*Nj*|p(3)O z_3@3_F2_kL{qZ48`3Wk@=B=siMI|V#61{|Ze2Nvka^K|-3^)y{5`F`1vXYN;-*HH9 zA(_?tK_K3OgNMEc%-#(5*$fy*2RfvgaE*0b@q(RU)K(bPq5v641X3)*q9r%KE048( zCx|m8InxAq&d*^6S1^17vE@{eYjfwxbuqW%IYdp%k6dH7ANz#?kl61@JWaXTP`Tk} z4#PFdlVWxbR9}_|-g(Iu!}x1$H7%MbKeDv3C^J{e`GGVcZtt@FhaEzxvQJk2hYlf! z0fjF9m1j?y3aHE#%m}!+1o$4=aqu`-ets2jEvX4Wlrc&8wgCd_gk0c>@zl14uBj)flwzKE_RQtQy*rOIK$nn99;{5bH>g(HH+xM z3@P_Nnl#Y}Z~x@CR`|AiY@lSUOnYW*by~_Ql zVXT9HiggsZqzP?iNSISx+hJ^YcHVv^9sH74UYhThwUfwY*7%25kJ2E8gV*u`D1a?E zy&i6;(hy=%t0gD8wrpEy2-~^{I|e)ivTHl3|93qCe=>4anLoGZmi-7Rt6S0_eq5x< ziVvrac=fo+*hnjfHJ-;dl<71du?T#Sn<4yu92e&NwQvIi$HwQ+`gS3$z?5xN5I)>W zxk!|pZ}xcD3e_Pog|mzHfDH50_8X{-+tbV1G$4YY=RM=Tn`6R(Qt#djZeA01mEED4 zMwKOnX$^XDOr~wHm!YX=&%W6sUA>QYbMM9)8LQ(b^y3h7RGeb!GYQZT`-t(uc&QWH zvrUF-ON?*w;vJ~xnTfzPnJr-{cQ_WFiMs3h?(!=~zEl;++q`uGB`@CQtBtNB+XH*Q z(BuP^N~04-o`*e(=YqqI%5!=v-N)i-z_U9^Zb$^%W>WKT;t+mM-h8de?0&cV*(!VI z7an02_^6HEnoMw3+$B5m-hC<`FMcpsilFV=?aSo4ZbucAV9nlf@g|W)$*&*?6+=)0$8cI|q5#Pv%$tP8cTV zXAbHomIa^`q)xb@Oh+%N*L%Xe1{0lO$k!_+a*ZThv-k~5!i2Vdk~2X3%NmHtbkoL6 zBKki*kd(Z5goVkkM6l9-anoZ9_~`8VE zqx#d;ezbVR618vrcx3>4##_L33*uY;&g##;_uX;(<-h8(h5cUI@pbUp65~N7?3ZqneBB#i1+OKp2M z2>s`Vjn!}4sH`l0lx7eUYiG5q*;wvu+X$tN- zPvOkXMDAr1!pPA>!j83Ef1k#zEB7_f`Rx~&WjV=p5FDY`I~F+!3zimx`K$>XvSaba zY1e$)V1iIwKgA)Dv80TVfMa(*xdl8ToQ}50&NJ6I!N#qMVKKydC76=-gf)VXGA5P? zh)sUwLEC`QySh3KH{tgBl8K6d*JI}CWwlGk`2`~sKuH)5!h{zJ87##rwDmOd{ya0S zbx3N)D1()8B;dSXKzzaOKFP7C?1<0B%=Pk#RmR&BI#5v1cDE%5l*x~%(qNA97- z!^Fj!-SbLct#as`#7`zZp?mSA#?3LkX*iI;wh|fu?{HK9yLdi&QJfy=*hfvoDV=pG@74Kl}^WHm}W*B z(zo8R6JPMCXob_X zYSIBe=c)s!Pcl46tOO9FM#wPuw(zbnjfXFnbC3Oc$vDjXZ=*b>-OiX9J+B5 z#8&&uSUj7>zU-p6%j10;thER?CzoFeWV%@3HXNL!Hqsf#8rw@Z^D`cNV)o=KFdbUv z3_wQQ_83GYAe0c2Tz}YZG>*<4jys+YdfAJm@G&=Xx0XSRjBSOOE|1ohY_=roX?Y@< z{&bD#!Iuf+h}e1`9?ChbaqM(1(SPr1^-CuSH43|-Z$`3Hw$KdeN+J7-uEK@Z$3~z`DZ`^4rqp_H!CM8mZ zOgqMXyVV8{MXp)MLs~(heIZo=V#H zw*56pANHLu39|D?EMLhpW#Adrw|n2uA5DFq^d8r&xXPr7nbEBJ z=$;16f_Ott!YMplNvsfSG@=J%c-JCAgAcV&nbJt*QO=OFa>AyZ!fn&PVpN7sPq3ME zO9jox*taMxe{+vSlLF<;| z#2Ko+mv+w1FQ<=!c`sa?efcpI;5t4o2lVYg#wR&YTctUq>{ zWOw3ujREz|N0R()jEGuQL4;KR3+;zI3hON&Bp@cE>4H?_UWRFWO@)o(<6pU75L~U$ zfs4R{iNykt4*rX@e}o#uz2lROJy^!CG}NB-^RPWp@|d{lh^8_fl6)!~;3=Z+J7w1| z9^jpb(`Jdqb8}x(TXJO4V_$!otp4TImK>bWjbSWki}}Sc+f9{UXr&LN3eOZ zp+pjjnOOe*W95f$%24Wg$QDpoz^=K74M_fb0S?SYeK3v2#oelc<-=bhUOY3-o>|Rn zpBP-h4<^&RmBadQn==<(3XYsybJkP9H-h}`Jr#<(Zo9`F?5&5CP!7DlqjGJZH9e{- z%Ny=QNjx^Bdps6xERcgUITaa}x=TTkBSPXTE|A;+6Y=;r(7L+nDHC5oV4CF_^kv;StASOibwr1{yYyQ8se^fgL9+aS-nvdM&S?Z|Y z-8?MIWB*wQaw{m|MYT-TB$+lF`1~oWY&97^Z;nLkU~MT+Rcln-L%3@H=g+Wc`uCO) z8kQUB&^Z#wMUXhCW}QS2U2kbVXg;|uf&mlYhV^(dSd28GUBtS)YTc1pGvGn!o{;cr zw^_|6rZKkbVTKZ$5JF+o%KNVoy_$~4Y40o!$?@D`Uv(218yg19%rdFmpFvVqmeP&_ znkWMp^}00Zp68|+uVp7>P`wPADzrB z@-LMa*$LRc*zK9%mk8~NfH`h+AYE(>(1(t;wtNGPbF`P((`>a3em%lhS27N`&1FTQ(_RK$GBkMi4k2zx#VjT`_OXe+|@yP*t{ z`+tooN=~^VSpCK~0$aqZKT1LVC~)?v_>Pffy-_aq@303TCDv~sze})k*R|^pD6e`1 zj7L}cuR0CG!ISOb5Svikss2O8sPH{?oib}e!{X=AQ}Q>=?0jLIZZ zhajp$Y?wCYu_{~DDX)8&leHV~;BqdZUzITn$4>%Z`fHoS|E~j%(5{RjpnjQaZ_+;g zQXb(~Nf3K|e$5Yq$oGjSW#sqqrw1kGLCW_!W-!RaDD2ZW(6O6pBJEz$&P$vdMA)!Q z;pOB@HP$=2P4K3yg5S253J5i` zdEmadta@SKP%be`KzzESth?&S@V2V@*IVf!32r&owFBub4^@1D<3oJcHllC z!@orH+Pp2c`s}(Y(bFju<}>v_B?;gEC{lg2xun(yw&H$a3=7u@K|UJ=I#VCjsLjG2 zfg!LjlP6UHbJ?qzaxEt!78HA*IM;xJyDMtb!9yZ1`Ukb_ruxmypF`E{yqudl!S)sM zM8_UIR?BF15_8Qot8))^HR%tQ@1kF|p^%`_NTzX9O{TR<*Qz?^VBS`7XuQKG;Op>Q zOoUGekM17k`$pDOL_?NvGoPhXbB4LhCRP`_XL{SCqbH|{A#f=IxXz4`XT|%Gi2nM09V7cM z&S5la<4oS0x$A|#4vTnukMC~N9(|jFtVuQZyDgp4qa4ZD+{}SP;b^)gG8fF^a%sVi zO+tMz7}Y@I9g?KHMSXE!7ggwI*d6t)9zvQUFj+gNfBG~b-|qAS5qQ^;THVK|l~bZ4 zHO$nl3Y=CG4uknN>H^BKOsSFSVGOeaLHhA;)R_1K36Y^c!%vr-uI#Db>zdxS1a5*F z3a!&S=fffMxt+cFsh*Xp5BxKf;)tf6+{W34d3V z(f+zo$Onsd!2?ps4=c})c;XIv3pW{8;115|Y}|&*DD(c4({r7~SJolI zN+Ugz&5xNxBt$5&B?z*pCo5ky%3%98wRKCcz3kSj{)Zh!(m+Si`hV^y;vipNH~jpW zJZ*%th9$51o)l_AerOlhghq`VP2e-HxqY_yBU$;%Px-^%H1NAdleCTH$$&uUqw&mT7^lSp8e_I6DhxLLachu9W(htQ~; z3q|%<_Sov}Px(7~^u8*9bTbe4p7MO$P5K+?OzS01!71DjRV-336LvLTH61Y*!kRZn z&RM&8DP+q`b4+7#Vsr_BIGK9Knj;e1+d_Eyf40e2)p$b0SEg4KKhV2TMl24vSl*LD zijAIw!L|uh-wW0+uj#J^3@YX`}0y-#FOuUJ(`L0q~`98Ccq&sdB zGvY&Q8^&L)Qbk_M*lXByjTjrQ;pNKP2U_W@tHz>wpdp>e@*AfW_6^iYDko#DXidq*C}vevXa!bs^NYSr6DgVa@hLIY1;L zXQ2hxhl554lxs_-`l6lG%8dZP}RPp@4-l;WyB7ZIFTgIoTO^$efD^ zsbs!D4|3;{U0@4irPR6`cc5{(n(;?t%c@Vpo0}&Nz4(R2BH`lff}J*XlzLO`r^a|p z%VGW>o;MQvFl4oE-HKyMHDaOIOTD;jxKWKvTPm!g(v^zUl5jLsoj-ycyjR>NU!fDr zY{IeilFn}wj}I-YS)Cv`E6XL_dA(Qd-20V}*gfssI)|=Gh2G(j3ZPoox$x<>-!^tr8Ab}8hA88y zP&8WjJyS_D+}#X*lCj9p^P~fdNY|+Zy9?mBK$x$kT;N0{HzJ8oH-8zQURpYyxm8ze zj^1Lly4oa=7k3cXRMX4CG=;mxOc3T@d$R8?hH&e|`RIgb7cY!keyO_%h=!eC~)Wa?1DwY!}dG5PJl(lahnsQxz?T&VoowE0aHJ90)aE=^W;}uxZEqI>WqaM+O zz(flvS3mw_v`TEEGzs?i3D=~pfh3(DmLHBg3zCb;Jnak^5-EWX6GN)UQ4C;N3^rVs z&wRXZr%wM*MYO;_t11J7_CE>{?3>akO#h~WU*mNXzT`G*K!C;;{}{2_&?3f)k@@>@hUq4Y(Sk6D=nh zl0Y;v9IL>Scl`WI(Eo3Rbu?_}Cg1{zmpLf+?B(vh&HXmOqq70c`O`Rl)k*T}@_5_t zr%P5T-a}nP>p?szDY;MbA}i;%*|6~=Q)KG~DL>hfXcq#p^?j6*`@f)>|5^$1Ke%Tr z0t8(L*(tVPwvqOozHD7dZZanC!J{7<5a9^yeKc#_dgp|$#z>{+cS}g`_s%3NsCcQ??77aHgrLO%0xBidWdPu&2IRsUnu7W+!aNUO~xjJwQEA^p@>h+)miOGW%HT$zPUu1@7PsS9|UqWOts!G;9>JZq$yB`=bBip!Ar z?r3oej|j;ojMl`bMTrbol$e0Hbi9usT&blP?jxERrdb-8Guha&z4x6ADOJSn!?IEb z7S21)iGlN0xpV#lsVNezsx`SgAr{G5D?(3V7M8WJqL_F;B88laxS_47g; zFt(?AvAv)=PZ{-b-xvF77@d(O)E3?%Y3~s6?2z`tXET z&Zw|+2b&asq7?GwxDY)*y zci+cKRlRe(b6W3#`Hvs?r0rymO2*w3WI@c6t~CPZ9}=subc~GixWl^6=mQSclrEb5 z6Skte!b|5ba=+MvpvF54D0o}MRrTn( zmF7z-{!W@!w)B``RHh|aba%%oQ{DoinN8lD>sq)7wr)o=zxYGo7r%bqMsNsbPYJw( zRZnA`bV#ESex&41)*lcmLa=ZO^<3MkgzCBBf+3>GCTLOiiR~ligAL$J@4)CIp#N3i=3d)!5)~882DTM3rGA zeTT z?7k!ZRy|Y77SUN1XKv(4_#*ztfQ-$}Fa_>pL}&q&{tRj7gdPJuQ}+2LgMEE!wmBp# z16xy1atR-J(JdZf_(quJ^0##-wCo*R{W#{y9S{M0%t$Lpa=@JoU1=e|k4!gwd-y`nzZ7cckw@wIH)Kc&teQ@B85o`kISMI5Vep4+<{ zxn+fugzDr`pOQ|(mu{Y6;RKVZSAh2evhd>HDvl1zF&E_Tg9i5FS7g|HoU$#Qa>$pc zoP}C!B$xK1`qIGGo$cMD&onL+1VkUq(3ycFK9@ZyS+$@rjl;%8LP9!LJ40+8I3_p7 zVck7tmTul(E>bcfG!8od+W73v=V?O!g@du%r|9msZcnP2T2nis12h>SP2<%3`;4uF zI1hNvB3u=)kd%D)Yw?0ZXV;C};j-b~wsOP}T8)bBMMx1%y*KBfVXJWJA<2Z zQ=JUlHKDoErY5&lC?cYl^x?STt>9-P^BLbk1|*!Z+)EweO*B^SuUIq?u^iOwz07^P zCI!lFqF75!%SCdfoETj7E>IDi&TUoRhfk)L(A{_=r_i>YAuCO}V&Axs=Spb_{slcB z%KWqJn^gP}(;vw55TKboITQ;uZ)kNuLnVEtf zHzb*T&otx}N&h7C11$6pKXB*SR6jnXMTy=j;y|plPN9M^v~`-IPR(0-_f&jRItBy?+~ zK{JB2?ajufDf79eZ=k(nXQzlqkJELc;zih_On1`+&OEWC7_`hA7fentdQ*3Q6rTui zgYrxQoHtduD>ASNlAw=Dd8QZdqZqKAesJkI3$|{m{ zySz%9S?W*$cR(5o3Zqd%OT=(h_{{bcpYIeT#lD^kXUkMl!;C95p9Xl@mWE}(Hg}5~U z9kzeipFO;WnQ0cs{RcFN>uqj zQ!?u%H@#g+z~%tiibA~TsNz6Oe4<7FEW=XWdx$l_tE{n)KF{Dh#0Rh5Op)8uVql-6 zyReG#B+lzJCA!!+f93NE{CUP#Hdn<~>N;fJ3!PKKC%ZLP3qvOJ8aYqC=IcvRMR_<3 zu~9p?PJyt-Ewneh@Z+9#P7zc*SP0fJct*K_q#mt&5)PN$ij6>?rb&mUMqu_4RJ0pd z==VY!b+nI)Jv6RH{)kI#v2AcTWn?M5@&F5Q#(3pmTY&MlC3wmYwbN`d-A%Z~JvWCN zEW0mAd7&Zbw46Te__epI<3P2_U5STrLGDv+{b?c~3E7hPpsM1XOp%7Mm6p2LISv*~Vx$yu*?T`UR~#=J>8; zEZzyF^up8~-xG0;%dl;EyX$5oks(YWVe|;`*f8}Stk9v;_UGds^W@Q9nGdTfyF5OQq&b^SRq8M1%YA9K|yPSt#M_10jq`d zb71?hry}cQ^~MW65B4yzgclI%4Pl%p1^h-JPApy>%lyg@_TNe-k~Y*<&`#YSk!|~o zE547kB{*#tKQqGO;TW=eM66d7(t&I6`&IToHQ8E!nrjD|Y$*?DJspzWqL(#p?L4n(m?U0J z5WUo&z06AARLQC4YqmU9Yt_jvcpJP!U8;75THHAlR`(vlonz#TSx7e|O_*ptSsli4 z`Sq*D1Mag|v8Qccp2^NBWm~OfT%@0-GAC5{=S2;U2tBgsyk`d-dv(@5_>7XV$}kUD zYI`9VHbepPa$AHX)+fUi29qAc2th%3pX~N+*3g2|bt?B;G3_tqJidXt1%$_R+{i7# z5NW+}Dav*G>gtc1cD5CtOZbj+?Nyu?8yJm@{z9A%rGfa8aIzfaQ!-?B~Rka+K z#RkLVvA9}rRbY)|9Yy1V5%)8N%N|vDK8bW4T=cz@kjSM!TuM%iA@6&m_#E)l@|%7m zIhZUZ>uy#ZBzyAS!f&}5S4K2@7S4E)<~A+=0*dQovX5MW!X4E62b}{*B835ukC^Ko zHBgZaR0W~?mUk<)pOg@ZRpTx~tVoSTXKF4TP7e62dk}hZrlCSU-%K7MdfO z&D|v{GEax6Np~BG$RmCnvcJ5;|E_KNIEy*c>9S!-qx`#f=>Ah>%FlPRYTpzB;GkM0?Znp(J+D-yJexBx?Zg4jSA`{{5;~uKx>NHa&>`v}E zj@$MMX+)ueTqQ>xa78!;98^^42l^NqZ$%_e*{u(YP!1L+?OuCneT~6zwz{VRbMG+= z^g%^)d|cFYhVfEZT@_#R*@t2ZPWF`i@z@W3NzU!}cdDS$Liay*wF|1*_*6FH(6*~o zBtF&WL=#772sncM{TM0!B8h4I;y=Iy=EJuy3<2_-z z;sy3r?W<<#jiqlTuDAJg`}A(MrfK)veWsRf8tPk^VMzT>PMD7q?p2#N;{XApAH}Wm zEk6$a6sq9i>)%faLut|04mtCFFMACXSb6|e8uQ{%G_KZvI7yQM zCTYh1d6M?Kiy(^=ryw@U0q4CPU!10CI#J7$%y&Zf>Z944v~@?kjivx|=T(Fg_Fq%W z)rQ1;krUQErAt)Y1ir{F_i3|th8kDO$_sVuc#QB0$spNR9ng+TS1*7(a{Ut>EB!6F z?vG1T_%ZZ8GR+6-f}u|g^l^EaWaoolZ_%1OSV48Qpx=FHQHJ=zs~u|q|4(?Zm_$WE z$BPdcmH)*N*d7z#-~$e}zwbD_HbQeJ?LnTE1K{61d*E8~GU?Y4-_A?oJRpZfaz*!u zg^XeiE{v+sr{#oRzk!e&Q+JBS^J#H8lXfOMYpD$g=U-j04~@jn z=Wo_la8e_~^{+C86^b&4*VXm)AAG>#b@X8%DHaMDDk?I23~zR^&Ue|v8j8yxz;eM+ zcSQRfIIi7r8TUtdl*SOAp2)Qb@ZXQv$c36+#&m|slYkd{ai^WPD z->GLzWZ)^iPOj83(qJOyo-EdJ;aNTqY^hlqyhA|*!5>%yTalP8BHSn_BvOfg67Tk> z*yz2HQa8kZU6zVTtt~|aiXizc5k>< z#EKLWoHNKNeo_*4vRVobwQ2ctE>Ad6dEy(4W+P`LyQ8Jm!ZV{#EKXHf)-^Mgl{YCw zs~pd-=N@VN16Nn^$5&VJ>m*?NTU|zRU4Buzzaaw<{S5|y2jpec<^X`1@gC z^ZS{@Pa*kxd%rXm$2OkSZzSbgR3ORse$(;U6j5j|$xIYOWempH_RnIV{K6&_6 oeFN>YteG~L}?{3sMEi~P=116Pife-ltBa}C^Goc)jO8tt)v66vnp^nqK-cSZKh z-Y;}}@Js{WEn(a*Fr3v(v*ODPT_1g$nS5^6lGL+&Y{|@KVA#*l+|=&h{)o?8qM{k~ z&`;J^O*kA09KSWDn)Hqf3>b}zc;1j7bgy?T+hUTFL}SbRCB}Il9-6MFGA)FQe=u3k zk76X@!K*b*)>9?F(b?D5-=zsfmY3Do*C^;;RHpB>V5&rxwVBTJrND0}43lSN6g0-O zn94ArK=x1hMDO=vo%5!XqXu8j-w9v!WvnmzW?OrM-JQmoYmG30QwTf%=gZNz4(dsv zLmCd@al%#ZU&~H2u(FHwJEat&^@SdMv|f0jSRK0XOJBq`$x9FUD{B_|HolJkKRvKR z9@n5ehZO1+Onq%LINkdGcH+duv&pN+K1Q|o8BBf8Hfhytb1VL7HhR(cN*fieJfe${(g=%ztxXJ;q~^}W$aO6A|6QOF))q6t z#;o6%61+V(X8;%XnEs2WuyCv8A6IVPi%iwVuO3`{Kymxo)JNL}uQOP`Yu`$*Xv|gX zuEi7Xy*;C@hYBJ5V*+*e9i6Ym8rk zn07GWh*$<>t(uSFmWG6={<1{eEyxDMQ z=^Tn$kpwbJA#9$(ztSM{pps~<`vIMUMjAzi~HQ}1eRN+KSw_-3X=z<&Jl|j25 zH;`BADWPCE4Ntqu`J7j9`Zr7inx?)XxIFLAhddMP^R<0J>5n*qy3N;(JajIDc#3z( zQ|Op>l~^-7wXCW95B|G-Rj2(ATK~sAL>tM}zX(7?AyO7e%ToJG!H^|tzYi1;A>F?Y zz%UC-mdc6&&w!0O>fpv#92uJD)0^PCm6$S64Sn}X7?6i`E1Cvmg$EVrlRt_`M2KsK zCcnkAbMylWTeJ4NA6hIA&OiR;ozH}?&!EHT>lG?}b#$q`LZ1$CxggA2HPA}N8#p4R zk=L&91pG4h;6dTcDk)eUB*DB4&`b(}yH_?o&rSFVL~Z-(bg;kH^VLD)+~V!dAV$ z_sX#5iu#ODh1!Ylj|@@=bJYY-v#|+o zwY?-PocZiX(>v{Os@{*0V<6&li<{H-$kn{<87w4o%~mMD+hm~B&%F63Xy>c<1rZyatzwLxzu!eS2%ax$Pa~HADsBPCp9CPkZXH;4Y6Azta9-gI)~-98YQg5i~`y@0#8#UvwDZTX$E#H=H8sY zfv*Sy3V;IQd_jq$Ld%c-il^!V-ZpX?MaeWEB9r|GNUa1^MQk?#6(B!SXC{1u91daG z4qvD2FzxhpA0KErY^&S9-F0d(BJT5vvHZ@Ty^8znbiIyl&k{90R5Zt|jZ&_)saw8E z`OPn{VZ7&H;j=FdLp`9BU!2qi1sciOLe#|2OY*SZOTu$zeHdV_N{llJ(frw<*El6D zrJ`R$2pYn520pN+J%~9sV_KOa7b2Nlo3pw|@IfT=*3$~T2bh^TiT?Snyvpj=Y>=jq zc#V(E_Enpe4IP--D|i(kRy81xXk7P_w3JJdLIQigU92PQ>hE5Q7Tw;yML%Ow?M~&) zOY8c45+~D4*3@mkbix2x6Gpt4C}AzGrx^-jMm^@M!+i0pes;mt?4Kn%>J;fb?Qlm+TUZTG!I zr}~P_r3bsW2Z1{-pW|kcoTg%-`>pJ5RGy-eJeX%71aNYk{2SD!fzoM^|86b;To+e3 z%?IfqN9Kw!=p<;kNJ!zJStiNVYXgD)iUIFZ{bgjev{Q96-!bn}( z*L+CwI^QM&ihxMmFw!@!B&j=#Lg=iUkdL+8-Jc99mNHZ>CMkhNM{2dJMGN7swRFPc>MrH-J+*ZQjMow8 zZu#1S20?CnzY1?g-E$Yw5U+z0^1n4YE1M0s8k(Y4oZCIJg&dAm^b_8jpsFQ&ytwau z2WWErFzKxGG-9DkSlNmP1Hw&5Mt8q@v@9gkX6C0Tw&fmUBVjh4NKerFajzbxVUpIhFX`}Y?qm>D^&Umk{*D?IZS z5FF19fU~ffq|C#9&V7sv5>DoCT|59(?fuK3YXXpz)cB!Ai8s$jDMYrLkq|qdr!rFp zV&E)ZvR@gGOZ`-?FF@ZG|M75s#)h`srtn@Q`RI(D-#H9;ZD7S5Cd5^d)mg}Ci+&BK z(pXWgyjk;O1oje>;aMP9>bC0GgOfBOjakZTPrVAdn)K^UqK@dUr$$AamH=pxmBE^_ z_C~v6i_~P;w)RiFIc(D_6&2xt9;7fSIhRiCc76`G!`=daC2{DV2@0Bc{-6uz7KzI2 zFj49*IcMNV#yVZo4}WCWtx5Gv7B3kNLw}uolOM3=s&!OtJ=n%>#}99ML>sk6qhm&w zB-Ff)4gja2gt&c|s`v-fbC(UvU`eSd6Ear{5|0BFnu`V=0vEJEB?T*mEkB7jyEbx2 zLUtYOv;nK;v;u@b;9YsSk!&ygg~6FemymL=I5vA)Ct*zg02KOf=Ki}FKx|(q;hDFc zYN}l7cE&x?Z1re#;11=MEQ4A56#5a0ISJd}&sn@4q|KZ~gs zmKU$YvZ~r8$|2fh@L0;cS}Ci{X8}K{>f$eOZVSJKBsN+@n|sLv*C_)kSh4+3?uE?u%F=Z zA~uB;i~3XGr5iH9%Lcpy3+0CrX~$1rrvk3mHLc)Fb+>YRf20!*qgE07BsHZ2HDAwA zv9ypvu0B~sW39k@gEko_{7CM>@_zDAE3Sx7-6msB{L+_7RLg@%lT z+pu4{0DG4M$-cWoz(VyMZILE-Qhp|-et`V`~*`9^j{qN as>Lf8+G`(@(ZCxciu)#Sms=ZlpZq`3p|KGF literal 0 HcmV?d00001 diff --git a/hw3/dist/hw3_assets/spritesheets/car.json b/hw3/dist/hw3_assets/spritesheets/car.json new file mode 100644 index 0000000..e50dc3f --- /dev/null +++ b/hw3/dist/hw3_assets/spritesheets/car.json @@ -0,0 +1,139 @@ +{ + "name": "cars", + "spriteSheetImage": "cars.png", + "spriteWidth": 256, + "spriteHeight": 256, + "leftBuffer": 0, + "rightBuffer": 0, + "topBuffer": 0, + "bottomBuffer": 0, + "columns": 3, + "rows": 4, + "animations": [ + { + "name": "driving", + "repeat": true, + "frames": [ + { + "index": 0, + "duration": 10 + }, + { + "index": 1, + "duration": 10 + } + ] + }, + { + "name": "firing", + "repeat": true, + "frames": [ + { + "index": 0, + "duration": 10 + }, + { + "index": 2, + "duration": 10 + }, + { + "index": 3, + "duration": 10 + } + ] + }, + { + "name": "damage", + "repeat": true, + "frames": [ + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, { + "index": 5, + "duration": 6 + } + ] + }, + { + "name": "dying", + "repeat": false, + "next": "dead", + "frames": [ + { + "index": 6, + "duration": 10 + }, + { + "index": 7, + "duration": 10 + }, + { + "index": 8, + "duration": 10 + }, + { + "index": 9, + "duration": 10 + }, + { + "index": 10, + "duration": 10 + }, + { + "index": 11, + "duration": 10 + } + ] + }, + { + "name": "dead", + "repeat": true, + "frames": [ + { + "index": 11, + "duration": 20 + } + ] + } + ] +} diff --git a/hw3/dist/hw3_assets/spritesheets/cars.json b/hw3/dist/hw3_assets/spritesheets/cars.json new file mode 100644 index 0000000..e50dc3f --- /dev/null +++ b/hw3/dist/hw3_assets/spritesheets/cars.json @@ -0,0 +1,139 @@ +{ + "name": "cars", + "spriteSheetImage": "cars.png", + "spriteWidth": 256, + "spriteHeight": 256, + "leftBuffer": 0, + "rightBuffer": 0, + "topBuffer": 0, + "bottomBuffer": 0, + "columns": 3, + "rows": 4, + "animations": [ + { + "name": "driving", + "repeat": true, + "frames": [ + { + "index": 0, + "duration": 10 + }, + { + "index": 1, + "duration": 10 + } + ] + }, + { + "name": "firing", + "repeat": true, + "frames": [ + { + "index": 0, + "duration": 10 + }, + { + "index": 2, + "duration": 10 + }, + { + "index": 3, + "duration": 10 + } + ] + }, + { + "name": "damage", + "repeat": true, + "frames": [ + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, + { + "index": 5, + "duration": 6 + }, + { + "index": 4, + "duration": 6 + }, { + "index": 5, + "duration": 6 + } + ] + }, + { + "name": "dying", + "repeat": false, + "next": "dead", + "frames": [ + { + "index": 6, + "duration": 10 + }, + { + "index": 7, + "duration": 10 + }, + { + "index": 8, + "duration": 10 + }, + { + "index": 9, + "duration": 10 + }, + { + "index": 10, + "duration": 10 + }, + { + "index": 11, + "duration": 10 + } + ] + }, + { + "name": "dead", + "repeat": true, + "frames": [ + { + "index": 11, + "duration": 20 + } + ] + } + ] +} diff --git a/hw3/dist/hw3_assets/spritesheets/cars.png b/hw3/dist/hw3_assets/spritesheets/cars.png new file mode 100644 index 0000000000000000000000000000000000000000..9d239178c3c4d179223d3a9ae4c85d2d20446b69 GIT binary patch literal 33483 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.4.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "dev": true, + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "dev": true, + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "dev": true, + "dependencies": { + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "JSONStream": "^1.0.3", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + }, + "bin": { + "browser-pack": "bin/cmd.js" + } + }, + "node_modules/browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "dependencies": { + "resolve": "1.1.7" + } + }, + "node_modules/browser-resolve/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "node_modules/browserify": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.5.1.tgz", + "integrity": "sha512-EQX0h59Pp+0GtSRb5rL6OTfrttlzv+uyaUVlK6GX3w11SQ0jKPKyjC/54RhPR2ib2KmfcELM06e8FxcI5XNU2A==", + "dev": true, + "dependencies": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^2.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "browserify": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-rsa/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cached-path-relative": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", + "dev": true + }, + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "dev": true, + "dependencies": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + } + }, + "node_modules/combine-source-map/node_modules/convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "dev": true, + "dependencies": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", + "dev": true + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "node_modules/deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "dev": true, + "dependencies": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + }, + "bin": { + "deps-sort": "bin/cmd.js" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dev": true, + "dependencies": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true, + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "dependencies": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/events": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/gulp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.0.tgz", + "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=", + "dev": true, + "dependencies": { + "glob-watcher": "^5.0.0", + "gulp-cli": "^2.0.0", + "undertaker": "^1.0.0", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-typescript": { + "version": "6.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-6.0.0-alpha.1.tgz", + "integrity": "sha512-KoT0TTfjfT7w3JItHkgFH1T/zK4oXWC+a8xxKfniRfVcA0Fa1bKrIhztYelYmb+95RB80OLMBreknYkdwzdi2Q==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "plugin-error": "^1.0.1", + "source-map": "^0.7.3", + "through2": "^3.0.1", + "vinyl": "^2.2.0", + "vinyl-fs": "^3.0.3" + }, + "engines": { + "node": ">= 8" + }, + "peerDependencies": { + "typescript": "~2.7.1 || >=2.8.0-dev || >=2.9.0-dev || ~3.0.0 || >=3.0.0-dev || >=3.1.0-dev || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.7.0-dev " + } + }, + "node_modules/gulp-typescript/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-typescript/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/gulp-typescript/node_modules/through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "node_modules/gulp/node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "dev": true, + "dependencies": { + "source-map": "~0.5.3" + } + }, + "node_modules/insert-module-globals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", + "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", + "dev": true, + "dependencies": { + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + }, + "bin": { + "insert-module-globals": "bin/cmd.js" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", + "dev": true, + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", + "dev": true + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "dev": true, + "dependencies": { + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "module-deps": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/module-deps/node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, + "dependencies": { + "resolve": "^1.17.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outpipe": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", + "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=", + "dev": true, + "dependencies": { + "shell-quote": "^1.4.2" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "dev": true, + "dependencies": { + "path-platform": "~0.11.15" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "dependencies": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "dev": true, + "dependencies": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, + "node_modules/shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "dev": true, + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, + "node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dev": true, + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/stream-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", + "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", + "dev": true, + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "node_modules/stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "dev": true, + "dependencies": { + "minimist": "^1.1.0" + } + }, + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "dependencies": { + "acorn-node": "^1.2.0" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "dev": true, + "dependencies": { + "process": "~0.11.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/tsconfig": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz", + "integrity": "sha1-X0J45wGACWeo/Dg/0ZZIh48qbjo=", + "dev": true, + "dependencies": { + "any-promise": "^1.3.0", + "parse-json": "^2.2.0", + "strip-bom": "^2.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.0.tgz", + "integrity": "sha512-Dt8RL7mSz39PMOIAthxQfM0OpqmasXyWOrI0U260OF+tdz7CJV1jhP2X80aXmMP/8Y2928rRq9rESXY0xzESlg==", + "dev": true, + "dependencies": { + "convert-source-map": "^1.1.0", + "fs.realpath": "^1.0.0", + "object-assign": "^4.1.0", + "semver": "^6.1.0", + "through2": "^2.0.0", + "tsconfig": "^5.0.3" + }, + "engines": { + "node": ">=0.12" + }, + "peerDependencies": { + "browserify": ">= 10.x", + "typescript": ">= 2.8" + } + }, + "node_modules/tsify/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", + "dev": true, + "bin": { + "umd": "bin/cli.js" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "dev": true, + "dependencies": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + }, + "bin": { + "undeclared-identifiers": "bin.js" + } + }, + "node_modules/undertaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-source-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz", + "integrity": "sha1-84pa+53R6Ttl1VBGmsYYKsT1S44=", + "dev": true, + "dependencies": { + "through2": "^2.0.3", + "vinyl": "^2.1.0" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "node_modules/watchify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", + "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "browserify": "^16.1.0", + "chokidar": "^2.1.1", + "defined": "^1.0.0", + "outpipe": "^1.1.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "watchify": "bin/cmd.js" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "node_modules/yargs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "5.0.0-security.0" + } + }, + "node_modules/yargs-parser": { + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + }, + "dependencies": { + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "dev": true, + "requires": { + "buffer-equal": "^1.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true + }, + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "dev": true, + "requires": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "requires": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "requires": { + "async-done": "^1.2.2" + } + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "dev": true, + "requires": { + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "JSONStream": "^1.0.3", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + } + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browserify": { + "version": "16.5.1", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.5.1.tgz", + "integrity": "sha512-EQX0h59Pp+0GtSRb5rL6OTfrttlzv+uyaUVlK6GX3w11SQ0jKPKyjC/54RhPR2ib2KmfcELM06e8FxcI5XNU2A==", + "dev": true, + "requires": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^2.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cached-path-relative": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "dev": true, + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + }, + "dependencies": { + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", + "dev": true + } + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "dev": true, + "requires": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "dev": true, + "requires": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dev": true, + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "events": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + } + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "gulp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.0.tgz", + "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=", + "dev": true, + "requires": { + "glob-watcher": "^5.0.0", + "gulp-cli": "^2.0.0", + "undertaker": "^1.0.0", + "vinyl-fs": "^3.0.0" + }, + "dependencies": { + "gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + } + } + } + }, + "gulp-typescript": { + "version": "6.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-6.0.0-alpha.1.tgz", + "integrity": "sha512-KoT0TTfjfT7w3JItHkgFH1T/zK4oXWC+a8xxKfniRfVcA0Fa1bKrIhztYelYmb+95RB80OLMBreknYkdwzdi2Q==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "plugin-error": "^1.0.1", + "source-map": "^0.7.3", + "through2": "^3.0.1", + "vinyl": "^2.2.0", + "vinyl-fs": "^3.0.3" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "^1.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", + "dev": true + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "dev": true, + "requires": { + "source-map": "~0.5.3" + } + }, + "insert-module-globals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", + "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", + "dev": true, + "requires": { + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "requires": { + "flush-write-stream": "^1.0.2" + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", + "dev": true + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "dev": true, + "requires": { + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, + "requires": { + "resolve": "^1.17.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true + }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "requires": { + "once": "^1.3.2" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "outpipe": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", + "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=", + "dev": true, + "requires": { + "shell-quote": "^1.4.2" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "dev": true, + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + } + }, + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "requires": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "requires": { + "value-or-function": "^3.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "requires": { + "sver-compat": "^1.5.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "dev": true, + "requires": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, + "shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "dev": true, + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dev": true, + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "stream-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", + "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "dev": true, + "requires": { + "minimist": "^1.1.0" + } + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "requires": { + "acorn-node": "^1.2.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "dev": true, + "requires": { + "process": "~0.11.0" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "requires": { + "through2": "^2.0.3" + } + }, + "tsconfig": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz", + "integrity": "sha1-X0J45wGACWeo/Dg/0ZZIh48qbjo=", + "dev": true, + "requires": { + "any-promise": "^1.3.0", + "parse-json": "^2.2.0", + "strip-bom": "^2.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "tsify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.0.tgz", + "integrity": "sha512-Dt8RL7mSz39PMOIAthxQfM0OpqmasXyWOrI0U260OF+tdz7CJV1jhP2X80aXmMP/8Y2928rRq9rESXY0xzESlg==", + "dev": true, + "requires": { + "convert-source-map": "^1.1.0", + "fs.realpath": "^1.0.0", + "object-assign": "^4.1.0", + "semver": "^6.1.0", + "through2": "^2.0.0", + "tsconfig": "^5.0.3" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "dev": true, + "requires": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "undertaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + } + }, + "vinyl-source-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz", + "integrity": "sha1-84pa+53R6Ttl1VBGmsYYKsT1S44=", + "dev": true, + "requires": { + "through2": "^2.0.3", + "vinyl": "^2.1.0" + } + }, + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "requires": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", + "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "browserify": "^16.1.0", + "chokidar": "^2.1.1", + "defined": "^1.0.0", + "outpipe": "^1.1.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "5.0.0-security.0" + } + }, + "yargs-parser": { + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + } +} diff --git a/hw3/package.json b/hw3/package.json new file mode 100644 index 0000000..082dd9d --- /dev/null +++ b/hw3/package.json @@ -0,0 +1,21 @@ +{ + "name": "wolfie2d", + "version": "1.0.0", + "description": "A game engine written in TypeScript", + "main": "./dist/main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Joe Weaver", + "license": "ISC", + "devDependencies": { + "browserify": "^16.5.1", + "fancy-log": "^1.3.3", + "gulp": "^4.0.0", + "gulp-typescript": "^6.0.0-alpha.1", + "tsify": "^5.0.0", + "typescript": "^3.9.7", + "vinyl-source-stream": "^2.0.0", + "watchify": "^3.11.1" + } +} diff --git a/hw3/readme.md b/hw3/readme.md new file mode 100644 index 0000000..641825d --- /dev/null +++ b/hw3/readme.md @@ -0,0 +1,6 @@ +# Game Engine +## How to transpile and run + +Start gulp by just running `gulp` in the console. Start the code by running `dist/main.js` with Web Server for Chrome or a similar product. Anytime you save, gulp should recompile the code automatically. + +Setup follows [this helpful guide from TypeScript] (https://www.typescriptlang.org/docs/handbook/gulp.html) (Up through Watchify). \ No newline at end of file diff --git a/hw3/src/Wolfie2D/AI/AIManager.ts b/hw3/src/Wolfie2D/AI/AIManager.ts new file mode 100644 index 0000000..026e0c6 --- /dev/null +++ b/hw3/src/Wolfie2D/AI/AIManager.ts @@ -0,0 +1,65 @@ +import Actor from "../DataTypes/Interfaces/Actor"; +import Updateable from "../DataTypes/Interfaces/Updateable"; +import AI from "../DataTypes/Interfaces/AI"; +import Map from "../DataTypes/Map"; + +/** + * A manager class for all of the AI in a scene. + * Keeps a list of registered actors and handles AI generation for actors. + */ +export default class AIManager implements Updateable { + /** The array of registered actors */ + actors: Array; + /** Maps AI names to their constructors */ + registeredAI: Map; + + constructor(){ + this.actors = new Array(); + this.registeredAI = new Map(); + } + + /** + * Registers an actor with the AIManager + * @param actor The actor to register + */ + registerActor(actor: Actor): void { + this.actors.push(actor); + } + + removeActor(actor: Actor): void { + let index = this.actors.indexOf(actor); + + if(index !== -1){ + this.actors.splice(index, 1); + } + } + + /** + * Registers an AI with the AIManager for use later on + * @param name The name of the AI to register + * @param constr The constructor for the AI + */ + registerAI(name: string, constr: new () => T ): void { + this.registeredAI.add(name, constr); + } + + /** + * Generates an AI instance from its name + * @param name The name of the AI to add + * @returns A new AI instance + */ + generateAI(name: string): AI { + if(this.registeredAI.has(name)){ + return new (this.registeredAI.get(name))(); + } else { + throw `Cannot create AI with name ${name}, no AI with that name is registered`; + } + } + + update(deltaT: number): void { + // Run the ai for every active actor + this.actors.forEach(actor => { if(actor.aiActive) actor.ai.update(deltaT) }); + } +} + +type AIConstructor = new () => T; \ No newline at end of file diff --git a/hw3/src/Wolfie2D/AI/ControllerAI.ts b/hw3/src/Wolfie2D/AI/ControllerAI.ts new file mode 100644 index 0000000..005e375 --- /dev/null +++ b/hw3/src/Wolfie2D/AI/ControllerAI.ts @@ -0,0 +1,21 @@ +import AI from "../DataTypes/Interfaces/AI"; +import GameEvent from "../Events/GameEvent"; +import GameNode from "../Nodes/GameNode"; + +export default abstract class ControllerAI implements AI { + /** The owner of this controller */ + owner: GameNode; + + /** Removes the instance of the owner of this AI */ + destroy(): void { + delete this.owner; + } + + abstract initializeAI(owner: GameNode, options: Record): void; + + abstract activate(options: Record): void; + + abstract handleEvent(event: GameEvent): void; + + abstract update(deltaT: number): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/AI/StateMachineAI.ts b/hw3/src/Wolfie2D/AI/StateMachineAI.ts new file mode 100644 index 0000000..b3bcd9f --- /dev/null +++ b/hw3/src/Wolfie2D/AI/StateMachineAI.ts @@ -0,0 +1,24 @@ +import AI from "../DataTypes/Interfaces/AI"; +import StateMachine from "../DataTypes/State/StateMachine"; +import GameNode from "../Nodes/GameNode"; + +/** + * A version of a @reference[StateMachine] that is configured to work as an AI controller for a @reference[GameNode] + */ +export default class StateMachineAI extends StateMachine implements AI { + /** The GameNode that uses this StateMachine for its AI */ + protected owner: GameNode; + + // @implemented + initializeAI(owner: GameNode, config: Record): void {} + + // @implemented + destroy(){ + // Get rid of our reference to the owner + delete this.owner; + this.receiver.destroy(); + } + + // @implemented + activate(options: Record): void {} +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Collection.ts b/hw3/src/Wolfie2D/DataTypes/Collection.ts new file mode 100644 index 0000000..25b0635 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Collection.ts @@ -0,0 +1,17 @@ +// @ignorePage + +/** + * An interface for all iterable data custom data structures + */ +export default interface Collection { + /** + * Iterates through all of the items in this data structure. + * @param func The function to evaluate of every item in the collection + */ + forEach(func: Function): void; + + /** + * Clears the contents of the data structure + */ + clear(): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Functions/NullFunc.ts b/hw3/src/Wolfie2D/DataTypes/Functions/NullFunc.ts new file mode 100644 index 0000000..9808300 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Functions/NullFunc.ts @@ -0,0 +1,8 @@ +// @ignorePage + +/** + * A placeholder function for No Operation. Does nothing + */ +const NullFunc = () => {}; + +export default NullFunc; \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts b/hw3/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts new file mode 100644 index 0000000..3011ad9 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Graphs/EdgeNode.ts @@ -0,0 +1,22 @@ +/** + * A linked-list for the edges in a @reference[Graph]. + */ +export default class EdgeNode { + /** The node in the Graph this edge connects to */ + y: number; + /** The weight of this EdgeNode */ + weight: number; + /** The next EdgeNode in the linked-list */ + next: EdgeNode; + + /** + * Creates a new EdgeNode + * @param index The index of the node this edge connects to + * @param weight The weight of this edge + */ + constructor(index: number, weight?: number){ + this.y = index; + this.next = null; + this.weight = weight ? weight : 1; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Graphs/Graph.ts b/hw3/src/Wolfie2D/DataTypes/Graphs/Graph.ts new file mode 100644 index 0000000..21168c2 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Graphs/Graph.ts @@ -0,0 +1,145 @@ +import EdgeNode from "./EdgeNode"; + +export const MAX_V = 100; + +/** + * An implementation of a graph data structure using edge lists. Inspired by The Algorithm Design Manual. + */ +export default class Graph { + /** An array of edges at the node specified by the index */ + edges: Array; + /** An array representing the degree of the node specified by the index */ + degree: Array; + /** The number of vertices in the graph */ + numVertices: number; + /** The number of edges in the graph */ + numEdges: number; + /** Whether or not the graph is directed */ + directed: boolean; + /** Whether or not the graph is weighted */ + weighted: boolean; + + /** + * Constructs a new graph + * @param directed Whether or not this graph is directed + */ + constructor(directed: boolean = false){ + this.directed = directed; + this.weighted = false; + + this.numVertices = 0; + this.numEdges = 0; + + this.edges = new Array(MAX_V); + this.degree = new Array(MAX_V); + } + + /** Adds a node to this graph and returns the index of it + * @returns The index of the new node + */ + addNode(): number { + this.numVertices++; + return this.numVertices; + } + + /** Adds an edge between node x and y, with an optional weight + * @param x The index of the start of the edge + * @param y The index of the end of the edge + * @param weight The optional weight of the new edge + */ + addEdge(x: number, y: number, weight?: number): void { + let edge = new EdgeNode(y, weight); + + + + if(this.edges[x]){ + edge.next = this.edges[x]; + } + + this.edges[x] = edge; + + if(!this.directed){ + edge = new EdgeNode(x, weight); + + if(this.edges[y]){ + edge.next = this.edges[y]; + } + + this.edges[y] = edge; + } + + this.numEdges += 1; + } + + /** + * Checks whether or not an edge exists between two nodes. + * This check is directional if this is a directed graph. + * @param x The first node + * @param y The second node + * @returns true if an edge exists, false otherwise + */ + edgeExists(x: number, y: number): boolean { + let edge = this.edges[x]; + + while(edge !== null){ + if(edge.y === y){ + return true; + } + edge = edge.next; + } + } + + /** + * Gets the edge list associated with node x + * @param x The index of the node + * @returns The head of a linked-list of edges + */ + getEdges(x: number): EdgeNode { + return this.edges[x]; + } + + /** + * Gets the degree associated with node x + * @param x The index of the node + */ + getDegree(x: number): number { + return this.degree[x]; + } + + /** + * Converts the specifed node into a string + * @param index The index of the node to convert to a string + * @returns The string representation of the node: "Node x" + */ + protected nodeToString(index: number): string { + return "Node " + index; + } + + /** + * Converts the Graph into a string format + * @returns The graph as a string + */ + toString(): string { + let retval = ""; + + for(let i = 0; i < this.numVertices; i++){ + let edge = this.edges[i]; + let edgeStr = ""; + while(edge !== null){ + edgeStr += edge.y.toString(); + if(this.weighted){ + edgeStr += " (" + edge.weight + ")"; + } + if(edge.next !== null){ + edgeStr += ", "; + } + + edge = edge.next; + } + + retval += this.nodeToString(i) + ": " + edgeStr + "\n"; + } + + return retval; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Graphs/PositionGraph.ts b/hw3/src/Wolfie2D/DataTypes/Graphs/PositionGraph.ts new file mode 100644 index 0000000..cca9d77 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Graphs/PositionGraph.ts @@ -0,0 +1,94 @@ +import Graph, { MAX_V } from "./Graph"; +import Vec2 from "../Vec2"; +import DebugRenderable from "../Interfaces/DebugRenderable"; + +/** + * An extension of Graph that has nodes with positions in 2D space. + * This is a weighted graph (though not inherently directd) +*/ +export default class PositionGraph extends Graph implements DebugRenderable { + /** An array of the positions of the nodes in this graph */ + positions: Array; + + /** + * Createes a new PositionGraph + * @param directed Whether or not this graph is directed + */ + constructor(directed: boolean = false){ + super(directed); + this.positions = new Array(MAX_V); + } + + /** + * Adds a positioned node to this graph + * @param position The position of the node to add + * @returns The index of the added node + */ + addPositionedNode(position: Vec2): number { + this.positions[this.numVertices] = position; + return this.addNode(); + } + + /** + * Changes the position of a node. + * Automatically adjusts the weights of the graph tied to this node. + * As such, be warned that this function has an O(n + m) running time, and use it sparingly. + * @param index The index of the node + * @param position The new position of the node + */ + setNodePosition(index: number, position: Vec2): void { + this.positions[index] = position; + + // Recalculate all weights associated with this index + for(let i = 0; i < this.numEdges; i++){ + + let edge = this.edges[i]; + + while(edge !== null){ + // If this node is on either side of the edge, recalculate weight + if(i === index || edge.y === index){ + edge.weight = this.positions[i].distanceTo(this.positions[edge.y]); + } + + edge = edge.next; + } + } + } + + /** + * Gets the position of a node + * @param index The index of the node + * @returns The position of the node + */ + getNodePosition(index: number): Vec2 { + return this.positions[index]; + } + + /** + * Adds an edge to this graph between node x and y. + * Automatically calculates the weight of the edge as the distance between the nodes. + * @param x The beginning of the edge + * @param y The end of the edge + */ + addEdge(x: number, y: number): void { + if(!this.positions[x] || !this.positions[y]){ + throw "Can't add edge to un-positioned node!"; + } + + // Weight is the distance between the nodes + let weight = this.positions[x].distanceTo(this.positions[y]); + + super.addEdge(x, y, weight); + } + + // @override + protected nodeToString(index: number): string { + return "Node " + index + " - " + this.positions[index].toString(); + } + + debugRender = (): void => { + // for(let point of this.positions){ + // ctx.fillRect((point.x - origin.x - 4)*zoom, (point.y - origin.y - 4)*zoom, 8, 8); + // } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/AI.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/AI.ts new file mode 100644 index 0000000..625358b --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/AI.ts @@ -0,0 +1,20 @@ +import GameEvent from "../../Events/GameEvent"; +import GameNode from "../../Nodes/GameNode"; +import Updateable from "./Updateable"; + +/** + * Defines a controller for a bot or a human. Must be able to update + */ +export default interface AI extends Updateable { + /** Initializes the AI with the actor and any additional config */ + initializeAI(owner: GameNode, options: Record): void; + + /** Clears references from to the owner */ + destroy(): void; + + /** Activates this AI from a stopped state and allows variables to be passed in */ + activate(options: Record): void; + + /** Handles events from the Actor */ + handleEvent(event: GameEvent): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Actor.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Actor.ts new file mode 100644 index 0000000..c26f62e --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Actor.ts @@ -0,0 +1,40 @@ +import NavigationPath from "../../Pathfinding/NavigationPath"; +import AI from "./AI"; + +/** + * A game object that has an AI and can perform its own actions every update cycle + */ +export default interface Actor { + /** The AI of the actor */ + ai: AI; + + /** The activity status of the actor */ + aiActive: boolean; + + /** The path that navigation will follow */ + path: NavigationPath; + + /** A flag representing whether or not the actor is currently pathfinding */ + pathfinding: boolean; + + /** + * Adds an AI to this Actor. + * @param ai The name of the AI, or the actual AI, to add to the Actor. + * @param options The options to give to the AI for initialization. + */ + addAI(ai: string | (new () => T), options: Record): void; + + /** + * Sets the AI to start/stop for this Actor. + * @param active The new active status of the AI. + * @param options An object that allows options to be pased to the activated AI + */ + setAIActive(active: boolean, options: Record): void; + + /** + * Moves this GameNode along a path + * @param speed The speed to move with + * @param path The path we're moving along + */ + moveOnPath(speed: number, path: NavigationPath): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/DebugRenderable.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/DebugRenderable.ts new file mode 100644 index 0000000..b440c7c --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/DebugRenderable.ts @@ -0,0 +1,7 @@ +/** + * Represents a game object that can be rendered in Debug mode + */ +export default interface DebugRenderable { + /** Renders the debugging information for this object. */ + debugRender(): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Navigable.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Navigable.ts new file mode 100644 index 0000000..8f80c0f --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Navigable.ts @@ -0,0 +1,12 @@ +import Vec2 from "../Vec2"; +import NavigationPath from "../../Pathfinding/NavigationPath"; + +/** Represents an entity that can be navigated on. */ +export default interface Navigable { + /** + * Gets a new navigation path based on this Navigable object. + * @param fromPosition The position to start navigation from. + * @param toPosition The position to navigate to. + */ + getNavigationPath(fromPosition: Vec2, toPosition: Vec2): NavigationPath; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Physical.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Physical.ts new file mode 100644 index 0000000..989a2f5 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Physical.ts @@ -0,0 +1,120 @@ +import Shape from "../Shapes/Shape"; +import AABB from "../Shapes/AABB"; +import Vec2 from "../Vec2"; +import Map from "../Map"; + +/** + * Describes an object that can opt into physics. + */ +export default interface Physical { + /** A flag for whether or not this object has initialized game physics. */ + hasPhysics: boolean; + + /** Represents whether the object is moving or not. */ + moving: boolean; + + /** Represent whether the object is frozen from moving or not. */ + frozen: boolean; + + /** Represents whether the object is on the ground or not. */ + onGround: boolean; + + /** Reprsents whether the object is on the wall or not. */ + onWall: boolean; + + /** Reprsents whether the object is on the ceiling or not. */ + onCeiling: boolean; + + /** Represnts whether this object has active physics or not. */ + active: boolean; + + /** The shape of the collider for this physics object. */ + collisionShape: Shape; + + /** The offset of the collision shape from the center of the node */ + colliderOffset: Vec2; + + /** Represents whether this object can move or not. */ + isStatic: boolean; + + /** Represents whether this object is collidable (solid) or not. */ + isCollidable: boolean; + + /** Represnts whether this object is a trigger or not. */ + isTrigger: boolean; + + /** The trigger mask for this node */ + triggerMask: number; + + /** Events to trigger for collision enters. */ + triggerEnters: Array; + + /** Events to trigger for collision exits */ + triggerExits: Array; + + /** A vector that allows velocity to be passed to the physics engine */ + _velocity: Vec2; + + /** The rectangle swept by the movement of this object, if dynamic */ + sweptRect: AABB; + + /** A boolean representing whether or not the node just collided with the tilemap */ + collidedWithTilemap: boolean; + + /** The physics group this node belongs to */ + group: number; + + isPlayer: boolean; + + isColliding: boolean; + + /*---------- FUNCTIONS ----------*/ + + /** + * Tells the physics engine to handle a move by this object. + * @param velocity The velocity with which to move the object. + */ + move(velocity: Vec2): void; + + /** + * The move actually done by the physics engine after collision checks are done. + * @param velocity The velocity with which the object will move. + */ + finishMove(): void; + + /** + * Adds physics to this object + * @param collisionShape The shape of this collider for this object + * @param isCollidable Whether this object will be able to collide with other objects + * @param isStatic Whether this object will be static or not + */ + addPhysics(collisionShape?: Shape, colliderOffset?: Vec2, isCollidable?: boolean, isStatic?: boolean): void; + + /** Removes this object from the physics system */ + removePhysics(): void; + + /** Prevents this object from participating in all collisions and triggers. It can still move. */ + disablePhysics(): void; + + /** Enables this object to participate in collisions and triggers. This is only necessary if disablePhysics was called */ + enablePhysics(): void; + + /** + * Sets this object to be a trigger for a specific group + * @param group The name of the group that activates the trigger + * @param onEnter The name of the event to send when this trigger is activated + * @param onExit The name of the event to send when this trigger stops being activated + */ + setTrigger(group: string, onEnter: string, onExit: string): void; + + /** + * Sets the physics group of this node + * @param group The name of the group + */ + setGroup(group: string): void; + + /** + * If used before "move()", it will tell you the velocity of the node after its last movement + */ + getLastVelocity(): Vec2; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Positioned.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Positioned.ts new file mode 100644 index 0000000..9da68e8 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Positioned.ts @@ -0,0 +1,10 @@ +import Vec2 from "../Vec2"; + +/** An object that has a position */ +export default interface Positioned { + /** The center of this object. */ + position: Vec2; + + /** The center of this object relative to the viewport. */ + readonly relativePosition: Vec2; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Region.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Region.ts new file mode 100644 index 0000000..019fce3 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Region.ts @@ -0,0 +1,21 @@ +import Vec2 from "../Vec2"; +import AABB from "../Shapes/AABB"; + +/** An object that is a region, with a size, scale, and boundary. */ +export default interface Region { + /** The size of this object. */ + size: Vec2; + + /** The scale of this object. */ + scale: Vec2; + + /** The size of the object taking into account the zoom and scale */ + readonly sizeWithZoom: Vec2; + + /** The bounding box of this object. */ + boundary: AABB; +} + +export function isRegion(arg: any): boolean { + return arg && arg.size && arg.scale && arg.boundary; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Unique.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Unique.ts new file mode 100644 index 0000000..7e04e25 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Unique.ts @@ -0,0 +1,7 @@ +/** + * Represents an object with a unique id + */ +export default interface Unique { + /** The unique id of this object. */ + id: number; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Interfaces/Updateable.ts b/hw3/src/Wolfie2D/DataTypes/Interfaces/Updateable.ts new file mode 100644 index 0000000..0df2cf6 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Interfaces/Updateable.ts @@ -0,0 +1,8 @@ +/** Represents a game object that can be updated */ +export default interface Updateable { + /** + * Updates this object. + * @param deltaT The timestep of the update. + */ + update(deltaT: number): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/List.ts b/hw3/src/Wolfie2D/DataTypes/List.ts new file mode 100644 index 0000000..2a86182 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/List.ts @@ -0,0 +1,63 @@ +import Collection from "./Collection"; + +/** + * A doubly linked list + */ +export default class List implements Collection { + + private head: ListItem; + private tail: ListItem; + private _size: number; + + constructor(){ + this.head = null; + this.tail = null; + this._size = 0; + } + + get size(): number { + return this._size; + } + + add(value: T){ + if(this._size === 0){ + // There were no items in the list previously, so head and tail are the same + this.head = new ListItem(value, null, null); + this.tail = this.head; + } else { + this.tail.next = new ListItem(value, this.tail, null); + this.tail = this.tail.next; + } + + // Increment the size + this._size += 1; + } + + forEach(func: Function): void { + let p = this.head; + + while(p !== null){ + func(p.value); + p = p.next; + } + } + + clear(): void { + this.head = null + this.tail = null + this._size = 0; + } + +} + +class ListItem { + value: T; + next: ListItem; + prev: ListItem; + + constructor(value: T, next: ListItem, prev: ListItem){ + this.value = value; + this.next = next; + this.prev = prev; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Map.ts b/hw3/src/Wolfie2D/DataTypes/Map.ts new file mode 100644 index 0000000..7937de6 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Map.ts @@ -0,0 +1,87 @@ +import Collection from "./Collection"; + +/** + * Associates strings with elements of type T + */ +export default class Map implements Collection { + private map: Record; + + /** Creates a new map */ + constructor(){ + this.map = {}; + } + + /** + * Adds a value T stored at a key. + * @param key The key of the item to be stored + * @param value The item to be stored + */ + add(key: string, value: T): void { + this.map[key] = value; + } + + /** + * Get the value associated with a key. + * @param key The key of the item + * @returns The item at the key or undefined + */ + get(key: string): T { + return this.map[key]; + } + + /** + * An alias of add. Sets the value stored at key to the new specified value + * @param key The key of the item to be stored + * @param value The item to be stored + */ + set(key: string, value: T): void { + this.add(key, value); + } + + /** + * Returns true if there is a value stored at the specified key, false otherwise. + * @param key The key to check + * @returns A boolean representing whether or not there is an item at the given key. + */ + has(key: string): boolean { + return this.map[key] !== undefined; + } + + /** + * Returns an array of all of the keys in this map. + * @returns An array containing all keys in the map. + */ + keys(): Array { + return Object.keys(this.map); + } + + // @implemented + forEach(func: (key: string) => void): void { + Object.keys(this.map).forEach(key => func(key)); + } + + /** + * Deletes an item associated with a key + * @param key The key at which to delete an item + */ + delete(key: string): void { + delete this.map[key]; + } + + // @implemented + clear(): void { + this.forEach(key => delete this.map[key]); + } + + /** + * Converts this map to a string representation. + * @returns The string representation of this map. + */ + toString(): string { + let str = ""; + + this.forEach((key) => str += key + " -> " + this.get(key).toString() + "\n"); + + return str; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Mat4x4.ts b/hw3/src/Wolfie2D/DataTypes/Mat4x4.ts new file mode 100644 index 0000000..c0765bb --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Mat4x4.ts @@ -0,0 +1,167 @@ +import Vec2 from "./Vec2"; + +/** A 4x4 matrix0 */ +export default class Mat4x4 { + private mat: Float32Array; + + constructor(){ + this.mat = new Float32Array([ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + ]); + } + + // Static members + static get IDENTITY(): Mat4x4 { + return new Mat4x4().identity(); + } + + static get ZERO(): Mat4x4 { + return new Mat4x4().zero(); + } + + // Accessors + set _00(x: number) { + this.mat[0] = x; + } + + set(col: number, row: number, value: number): Mat4x4 { + if(col < 0 || col > 3 || row < 0 || row > 3){ + throw `Error - index (${col}, ${row}) is out of bounds for Mat4x4` + } + this.mat[row*4 + col] = value; + + return this; + } + + get(col: number, row: number): number { + return this.mat[row*4 + col]; + } + + setAll(...items: Array): Mat4x4 { + this.mat.set(items); + return this; + } + + identity(): Mat4x4 { + return this.setAll( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ) + } + + zero(): Mat4x4 { + return this.setAll( + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + ); + } + + /** + * Makes this Mat4x4 a rotation matrix of the specified number of radians ccw + * @param zRadians The number of radians to rotate + * @returns this Mat4x4 + */ + rotate(zRadians: number): Mat4x4 { + return this.setAll( + Math.cos(zRadians), -Math.sin(zRadians), 0, 0, + Math.sin(zRadians), Math.cos(zRadians), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + } + + /** + * Turns this Mat4x4 into a translation matrix of the specified translation + * @param translation The translation in x and y + * @returns this Mat4x4 + */ + translate(translation: Vec2 | Float32Array): Mat4x4 { + // If translation is a vec, get its array + if(translation instanceof Vec2){ + translation = translation.toArray(); + } + + return this.setAll( + 1, 0, 0, translation[0], + 0, 1, 0, translation[1], + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + } + + scale(scale: Vec2 | Float32Array | number): Mat4x4 { + // Make sure scale is a float32Array + if(scale instanceof Vec2){ + scale = scale.toArray(); + } else if(!(scale instanceof Float32Array)){ + scale = new Float32Array([scale, scale]); + } + + return this.setAll( + scale[0], 0, 0, 0, + 0, scale[1], 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + } + + /** + * Returns a new Mat4x4 that represents the right side multiplication THIS x OTHER + * @param other The other Mat4x4 to multiply by + * @returns a new Mat4x4 containing the product of these two Mat4x4s + */ + mult(other: Mat4x4, out?: Mat4x4): Mat4x4 { + let temp = new Float32Array(16); + + for(let i = 0; i < 4; i++){ + for(let j = 0; j < 4; j++){ + let value = 0; + for(let k = 0; k < 4; k++){ + value += this.get(k, i) * other.get(j, k); + } + temp[j*4 + i] = value; + } + } + + if(out !== undefined){ + return out.setAll(...temp); + } else { + return new Mat4x4().setAll(...temp); + } + } + + /** + * Multiplies all given matricies in order. e.g. MULT(A, B, C) -> A*B*C + * @param mats A list of Mat4x4s to multiply in order + * @returns A new Mat4x4 holding the result of the operation + */ + static MULT(...mats: Array): Mat4x4 { + // Create a new array + let temp = Mat4x4.IDENTITY; + + // Multiply by every array in order, in place + for(let i = 0; i < mats.length; i++){ + temp.mult(mats[i], temp); + } + + return temp; + } + + toArray(): Float32Array { + return this.mat; + } + + toString(): string { + return `|${this.mat[0].toFixed(2)}, ${this.mat[1].toFixed(2)}, ${this.mat[2].toFixed(2)}, ${this.mat[3].toFixed(2)}|\n` + + `|${this.mat[4].toFixed(2)}, ${this.mat[5].toFixed(2)}, ${this.mat[6].toFixed(2)}, ${this.mat[7].toFixed(2)}|\n` + + `|${this.mat[8].toFixed(2)}, ${this.mat[9].toFixed(2)}, ${this.mat[10].toFixed(2)}, ${this.mat[11].toFixed(2)}|\n` + + `|${this.mat[12].toFixed(2)}, ${this.mat[13].toFixed(2)}, ${this.mat[14].toFixed(2)}, ${this.mat[15].toFixed(2)}|`; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Physics/AreaCollision.ts b/hw3/src/Wolfie2D/DataTypes/Physics/AreaCollision.ts new file mode 100644 index 0000000..1d2b94e --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Physics/AreaCollision.ts @@ -0,0 +1,40 @@ +import Physical from "../Interfaces/Physical"; +import AABB from "../Shapes/AABB"; +import Vec2 from "../Vec2"; +import Hit from "./Hit"; + +/** + * A class that contains the area of overlap of two colliding objects to allow for sorting by the physics system. + */ +export default class AreaCollision { + /** The area of the overlap for the colliding objects */ + area: number; + + /** The AABB of the other collider in this collision */ + collider: AABB; + + /** Type of the collision */ + type: string; + + /** Ther other object in the collision */ + other: Physical; + + /** The tile, if this was a tilemap collision */ + tile: Vec2; + + /** The physics hit for this object */ + hit: Hit; + + /** + * Creates a new AreaCollision object + * @param area The area of the collision + * @param collider The other collider + */ + constructor(area: number, collider: AABB, other: Physical, type: string, tile: Vec2){ + this.area = area; + this.collider = collider; + this.other = other; + this.type = type; + this.tile = tile; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Physics/Hit.ts b/hw3/src/Wolfie2D/DataTypes/Physics/Hit.ts new file mode 100644 index 0000000..7ee1a6a --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Physics/Hit.ts @@ -0,0 +1,18 @@ +import Vec2 from "../Vec2"; + +/** + * An object representing the data collected from a physics hit between two geometric objects. + * Inspired by the helpful collision documentation @link(here)(https://noonat.github.io/intersect/). + */ +export default class Hit { + /** The time of the collision. Only numbers 0 through 1 happen in this frame. */ + time: number; + /** The near times of the collision */ + nearTimes: Vec2 = Vec2.ZERO; + /** The position of the collision */ + pos: Vec2 = Vec2.ZERO; + /** The overlap distance of the hit */ + delta: Vec2 = Vec2.ZERO; + /** The normal vector of the hit */ + normal: Vec2 = Vec2.ZERO; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/QuadTree.ts b/hw3/src/Wolfie2D/DataTypes/QuadTree.ts new file mode 100644 index 0000000..25c77d5 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/QuadTree.ts @@ -0,0 +1,156 @@ +import Vec2 from "./Vec2"; +import Collection from "./Collection"; +import AABB from "./Shapes/AABB" +import Positioned from "./Interfaces/Positioned"; + +// TODO - Make max depth + +// @ignorePage + +/** + * Primarily used to organize the scene graph + */ +export default class QuadTree implements Collection { + /** + * The center of this quadtree + */ + protected boundary: AABB; + + /** + * The number of elements this quadtree root can hold before splitting + */ + protected capacity: number; + + /** + * The maximum height of the quadtree from this root + */ + protected maxDepth: number; + + /** + * Represents whether the quadtree is a root or a leaf + */ + protected divided: boolean; + + /** + * The array of the items in this quadtree + */ + protected items: Array; + + // The child quadtrees of this one + protected nw: QuadTree; + protected ne: QuadTree; + protected sw: QuadTree; + protected se: QuadTree; + + constructor(center: Vec2, size: Vec2, maxDepth?: number, capacity?: number){ + this.boundary = new AABB(center, size); + this.maxDepth = maxDepth !== undefined ? maxDepth : 10 + this.capacity = capacity ? capacity : 10; + + // If we're at the bottom of the tree, don't set a max size + if(this.maxDepth === 0){ + this.capacity = Infinity; + } + + this.divided = false; + this.items = new Array(); + } + + /** + * Inserts a new item into this quadtree. Defers to children if this quadtree is divided + * or divides the quadtree if capacity is exceeded with this add. + * @param item The item to add to the quadtree + */ + insert(item: T){ + // If the item is inside of the bounds of this quadtree + if(this.boundary.containsPointSoft(item.position)){ + if(this.divided){ + // Defer to the children + this.deferInsert(item); + } else if (this.items.length < this.capacity){ + // Add to this items list + this.items.push(item); + } else { + // We aren't divided, but are at capacity - divide + this.subdivide(); + this.deferInsert(item); + this.divided = true; + } + } + } + + /** + * Divides this quadtree up into 4 smaller ones - called through insert. + */ + protected subdivide(): void { + let x = this.boundary.x; + let y = this.boundary.y; + let hw = this.boundary.hw; + let hh = this.boundary.hh; + + this.nw = new QuadTree(new Vec2(x-hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1); + this.ne = new QuadTree(new Vec2(x+hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1) + this.sw = new QuadTree(new Vec2(x-hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1) + this.se = new QuadTree(new Vec2(x+hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1) + + this.distributeItems(); + } + + /** + * Distributes the items of this quadtree into its children. + */ + protected distributeItems(): void { + this.items.forEach(item => this.deferInsert(item)); + + // Delete the items from this array + this.items.forEach((item, index) => delete this.items[index]); + this.items.length = 0; + } + + /** + * Defers this insertion to the children of this quadtree + * @param item + */ + protected deferInsert(item: T): void { + this.nw.insert(item); + this.ne.insert(item); + this.sw.insert(item); + this.se.insert(item); + } + + /** + * Renders the quadtree for demo purposes. + * @param ctx + */ + public render_demo(ctx: CanvasRenderingContext2D): void { + ctx.strokeStyle = "#FF0000"; + ctx.strokeRect(this.boundary.x - this.boundary.hw, this.boundary.y - this.boundary.hh, 2*this.boundary.hw, 2*this.boundary.hh); + + if(this.divided){ + this.nw.render_demo(ctx); + this.ne.render_demo(ctx); + this.sw.render_demo(ctx); + this.se.render_demo(ctx); + } + } + + forEach(func: Function): void { + // If divided, send the call down + if(this.divided){ + this.nw.forEach(func); + this.ne.forEach(func); + this.sw.forEach(func); + this.se.forEach(func); + } else { + // Otherwise, iterate over items + for(let i = 0; i < this.items.length; i++){ + func(this.items[i]); + } + } + } + + clear(): void { + throw new Error("Method not implemented."); + } + +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Queue.ts b/hw3/src/Wolfie2D/DataTypes/Queue.ts new file mode 100644 index 0000000..ad47adb --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Queue.ts @@ -0,0 +1,130 @@ +import Collection from "./Collection"; + +/** + * A FIFO queue with elements of type T + */ +export default class Queue implements Collection { + /** The maximum number of elements in the Queue */ + private readonly MAX_ELEMENTS: number; + + /** The internal representation of the queue */ + private q: Array; + + /** The head of the queue */ + private head: number; + + /** The tail of the queue */ + private tail: number; + + /** The current number of items in the queue */ + private size: number; + + /** + * Constructs a new queue + * @param maxElements The maximum size of the stack + */ + constructor(maxElements: number = 100){ + this.MAX_ELEMENTS = maxElements; + this.q = new Array(this.MAX_ELEMENTS); + this.head = 0; + this.tail = 0; + this.size = 0; + } + + /** + * Adds an item to the back of the queue + * @param item The item to add to the back of the queue + */ + enqueue(item: T): void{ + if((this.tail + 1) % this.MAX_ELEMENTS === this.head){ + throw new Error("Queue full - cannot add element"); + } + + this.size += 1; + this.q[this.tail] = item; + this.tail = (this.tail + 1) % this.MAX_ELEMENTS; + } + + /** + * Retrieves an item from the front of the queue + * @returns The item at the front of the queue + */ + dequeue(): T { + if(this.head === this.tail){ + throw new Error("Queue empty - cannot remove element"); + } + + + this.size -= 1; + let item = this.q[this.head]; + // Now delete the item + delete this.q[this.head]; + this.head = (this.head + 1) % this.MAX_ELEMENTS; + + return item; + } + + /** + * Returns the item at the front of the queue, but does not remove it + * @returns The item at the front of the queue + */ + peekNext(): T { + if(this.head === this.tail){ + throw "Queue empty - cannot get element" + } + + let item = this.q[this.head]; + + return item; + } + + /** + * Returns true if the queue has items in it, false otherwise + * @returns A boolean representing whether or not this queue has items + */ + hasItems(): boolean { + return this.head !== this.tail; + } + + /** + * Returns the number of elements in the queue. + * @returns The size of the queue + */ + getSize(): number { + return this.size; + } + + // @implemented + clear(): void { + this.forEach((item, index) => delete this.q[index]); + this.size = 0; + this.head = this.tail; + } + + // @implemented + forEach(func: (item: T, index?: number) => void): void { + let i = this.head; + while(i !== this.tail){ + func(this.q[i], i); + i = (i + 1) % this.MAX_ELEMENTS; + } + } + + /** + * Converts this queue into a string format + * @returns A string representing this queue + */ + toString(): string { + let retval = ""; + + this.forEach( (item, index) => { + let str = item.toString() + if(index !== 0){ + str += " -> " + } + retval = str + retval; + }); + + return "Top -> " + retval; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/RegionQuadTree.ts b/hw3/src/Wolfie2D/DataTypes/RegionQuadTree.ts new file mode 100644 index 0000000..b8d19fe --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/RegionQuadTree.ts @@ -0,0 +1,271 @@ +import Vec2 from "./Vec2"; +import Collection from "./Collection"; +import AABB from "./Shapes/AABB"; +import Region from "./Interfaces/Region"; +import Unique from "./Interfaces/Unique"; +import Map from "./Map"; + +/** + * A quadtree data structure implemented to work with regions rather than points. + * Elements in this quadtree have a position and an area, and thus can span multiple + * quadtree branches. + */ +export default class QuadTree implements Collection { + /** The center of this quadtree */ + protected boundary: AABB; + + /** The number of elements this quadtree root can hold before splitting */ + protected capacity: number; + + /** The maximum height of the quadtree from this root */ + protected maxDepth: number; + + /** Represents whether the quadtree is a root or a leaf */ + protected divided: boolean; + + /** The array of the items in this quadtree */ + protected items: Array; + + // The child quadtrees of this one + /** The top left child */ + protected nw: QuadTree; + /** The top right child */ + protected ne: QuadTree; + /** The bottom left child */ + protected sw: QuadTree; + /** The bottom right child */ + protected se: QuadTree; + + constructor(center: Vec2, size: Vec2, maxDepth?: number, capacity?: number){ + this.boundary = new AABB(center, size); + this.maxDepth = maxDepth !== undefined ? maxDepth : 10 + this.capacity = capacity ? capacity : 10; + + // If we're at the bottom of the tree, don't set a max size + if(this.maxDepth === 1){ + this.capacity = Infinity; + } + + this.divided = false; + this.items = new Array(); + + // Create all of the children for this quadtree if there are any + if(this.maxDepth > 1){ + let x = this.boundary.x; + let y = this.boundary.y; + let hw = this.boundary.hw; + let hh = this.boundary.hh; + + this.nw = new QuadTree(new Vec2(x-hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity); + this.ne = new QuadTree(new Vec2(x+hw/2, y-hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity); + this.sw = new QuadTree(new Vec2(x-hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity); + this.se = new QuadTree(new Vec2(x+hw/2, y+hh/2), new Vec2(hw/2, hh/2), this.maxDepth - 1, this.capacity); + } + } + + /** + * Inserts a new item into this quadtree. Defers to children if this quadtree is divided + * or divides the quadtree if capacity is exceeded with this add. + * @param item The item to add to the quadtree + */ + insert(item: T): void { + // If the item is inside of the bounds of this quadtree + if(this.boundary.overlaps(item.boundary)){ + if(this.divided){ + // Defer to the children + this.deferInsert(item); + } else if (this.items.length < this.capacity){ + // Add to this items list + this.items.push(item); + } else { + // We aren't divided, but are at capacity - divide + this.subdivide(); + this.deferInsert(item); + } + } + } + + /** + * Returns all items at this point. + * @param point The point to query at + * @returns A list of all elements in the quadtree that contain the specified point + */ + queryPoint(point: Vec2): Array { + // A matrix to keep track of our results + let results = new Array(); + + // A map to keep track of the items we've already found + let uniqueMap = new Map(); + + // Query and return + this._queryPoint(point, results, uniqueMap); + return results; + } + + // @ignoreFunction + /** + * A recursive function called by queryPoint + * @param point The point being queried + * @param results The results matrix + * @param uniqueMap A map that stores the unique ids of the results so we know what was already found + */ + protected _queryPoint(point: Vec2, results: Array, uniqueMap: Map): void { + // Does this quadtree even contain the point? + if(!this.boundary.containsPointSoft(point)) return; + + // If the matrix is divided, ask its children for results + if(this.divided){ + this.nw._queryPoint(point, results, uniqueMap); + this.ne._queryPoint(point, results, uniqueMap); + this.sw._queryPoint(point, results, uniqueMap); + this.se._queryPoint(point, results, uniqueMap); + } else { + // Otherwise, return a set of the items + for(let item of this.items){ + let id = item.id.toString(); + // If the item hasn't been found yet and it contains the point + if(!uniqueMap.has(id) && item.boundary.containsPoint(point)){ + // Add it to our found points + uniqueMap.add(id, item); + results.push(item); + } + } + } + } + + /** + * Returns all items in this region + * @param boundary The region to check + * @param inclusionCheck Allows for additional inclusion checks to further refine searches + * @returns A list of all elements in the specified region + */ + queryRegion(boundary: AABB): Array { + // A matrix to keep track of our results + let results = new Array(); + + // A map to keep track of the items we've already found + let uniqueMap = new Array(); + + // Query and return + this._queryRegion(boundary, results, uniqueMap); + return results; + } + + // @ignoreFunction + /** + * A recursive function called by queryPoint + * @param point The point being queried + * @param results The results matrix + * @param uniqueMap A map that stores the unique ids of the results so we know what was already found + */ + protected _queryRegion(boundary: AABB, results: Array, uniqueMap: Array): void { + // Does this quadtree even contain the point? + if(!this.boundary.overlaps(boundary)) return; + + // If the matrix is divided, ask its children for results + if(this.divided){ + this.nw._queryRegion(boundary, results, uniqueMap); + this.ne._queryRegion(boundary, results, uniqueMap); + this.sw._queryRegion(boundary, results, uniqueMap); + this.se._queryRegion(boundary, results, uniqueMap); + } else { + // Otherwise, return a set of the items + for(let item of this.items){ + // TODO - This is REALLY slow for some reason when we check for unique keys + + // let id = item.getId().toString(); + // // If the item hasn't been found yet and it contains the point + // if(!uniqueMap.has(id) && item.getBoundary().overlaps(boundary)){ + // // Add it to our found points + // uniqueMap.add(id, item); + // results.push(item); + // } + + // Maybe this is better? Just use a boolean array with no string nonsense? + if(item.id >= uniqueMap.length || !uniqueMap[item.id]){ + if(item.boundary.overlaps(boundary)){ + results.push(item); + uniqueMap[item.id] = true; + } + } + } + } + } + + /** + * Divides this quadtree up into 4 smaller ones - called through insert. + */ + protected subdivide(): void { + this.divided = true; + this.distributeItems(); + } + + /** + * Distributes the items of this quadtree into its children. + */ + protected distributeItems(): void { + this.items.forEach(item => this.deferInsert(item)); + + // Delete the items from this array + this.items.forEach((item, index) => delete this.items[index]); + this.items.length = 0; + } + + /** + * Defers this insertion to the children of this quadtree + * @param item The item to insert + */ + protected deferInsert(item: T): void { + this.nw.insert(item); + this.ne.insert(item); + this.sw.insert(item); + this.se.insert(item); + } + + public render_demo(ctx: CanvasRenderingContext2D, origin: Vec2, zoom: number): void { + ctx.strokeStyle = "#0000FF"; + ctx.strokeRect((this.boundary.x - this.boundary.hw - origin.x)*zoom, (this.boundary.y - this.boundary.hh - origin.y)*zoom, 2*this.boundary.hw*zoom, 2*this.boundary.hh*zoom); + + if(this.divided){ + this.nw.render_demo(ctx, origin, zoom); + this.ne.render_demo(ctx, origin, zoom); + this.sw.render_demo(ctx, origin, zoom); + this.se.render_demo(ctx, origin, zoom); + } + } + + // @implemented + forEach(func: Function): void { + // If divided, send the call down + if(this.divided){ + this.nw.forEach(func); + this.ne.forEach(func); + this.sw.forEach(func); + this.se.forEach(func); + } else { + // Otherwise, iterate over items + for(let i = 0; i < this.items.length; i++){ + func(this.items[i]); + } + } + } + + // @implemented + clear(): void { + if(this.nw){ + this.nw.clear(); + this.ne.clear(); + this.sw.clear(); + this.se.clear(); + } + + for(let item in this.items){ + delete this.items[item]; + } + + this.items.length = 0; + + this.divided = false; + } + +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Rendering/WebGLGameTexture.ts b/hw3/src/Wolfie2D/DataTypes/Rendering/WebGLGameTexture.ts new file mode 100644 index 0000000..c111c66 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Rendering/WebGLGameTexture.ts @@ -0,0 +1,5 @@ +export default class WebGLGameTexture { + webGLTextureId: number; + webGLTexture: WebGLTexture; + imageKey: string; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Rendering/WebGLProgramType.ts b/hw3/src/Wolfie2D/DataTypes/Rendering/WebGLProgramType.ts new file mode 100644 index 0000000..6452dfa --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Rendering/WebGLProgramType.ts @@ -0,0 +1,29 @@ +/** A container for info about a webGL shader program */ +export default class WebGLProgramType { + /** A webGL program */ + program: WebGLProgram; + + /** A vertex shader */ + vertexShader: WebGLShader; + + /** A fragment shader */ + fragmentShader: WebGLShader; + + /** + * Deletes this shader program + */ + delete(gl: WebGLRenderingContext): void { + // Clean up all aspects of this program + if(this.program){ + gl.deleteProgram(this.program); + } + + if(this.vertexShader){ + gl.deleteShader(this.vertexShader); + } + + if(this.fragmentShader){ + gl.deleteShader(this.fragmentShader); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Shapes/AABB.ts b/hw3/src/Wolfie2D/DataTypes/Shapes/AABB.ts new file mode 100644 index 0000000..d80c9db --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Shapes/AABB.ts @@ -0,0 +1,339 @@ +import Shape from "./Shape"; +import Vec2 from "../Vec2"; +import MathUtils from "../../Utils/MathUtils"; +import Circle from "./Circle"; +import Hit from "../Physics/Hit"; + +/** + * An Axis-Aligned Bounding Box. In other words, a rectangle that is always aligned to the x-y grid. + * Inspired by the helpful collision documentation @link(here)(https://noonat.github.io/intersect/). + */ +export default class AABB extends Shape { + center: Vec2; + halfSize: Vec2; + + /** + * Creates a new AABB + * @param center The center of the AABB + * @param halfSize The half size of the AABB - The distance from the center to an edge in x and y + */ + constructor(center?: Vec2, halfSize?: Vec2){ + super(); + this.center = center ? center : new Vec2(0, 0); + this.halfSize = halfSize ? halfSize : new Vec2(0, 0); + } + + /** Returns a point representing the top left corner of the AABB */ + get topLeft(): Vec2 { + return new Vec2(this.left, this.top) + } + + /** Returns a point representing the top right corner of the AABB */ + get topRight(): Vec2 { + return new Vec2(this.right, this.top) + } + + /** Returns a point representing the bottom left corner of the AABB */ + get bottomLeft(): Vec2 { + return new Vec2(this.left, this.bottom) + } + + /** Returns a point representing the bottom right corner of the AABB */ + get bottomRight(): Vec2 { + return new Vec2(this.right, this.bottom) + } + + // @override + getBoundingRect(): AABB { + return this.clone(); + } + + // @override + getBoundingCircle(): Circle { + let r = Math.max(this.hw, this.hh) + return new Circle(this.center.clone(), r); + } + + // @deprecated + getHalfSize(): Vec2 { + return this.halfSize; + } + + // @deprecated + setHalfSize(halfSize: Vec2): void { + this.halfSize = halfSize; + } + + // TODO - move these all to the Shape class + /** + * A simple boolean check of whether this AABB contains a point + * @param point The point to check + * @returns A boolean representing whether this AABB contains the specified point + */ + containsPoint(point: Vec2): boolean { + return point.x >= this.x - this.hw && point.x <= this.x + this.hw + && point.y >= this.y - this.hh && point.y <= this.y + this.hh + } + + /** + * A simple boolean check of whether this AABB contains a point + * @param point The point to check + * @returns A boolean representing whether this AABB contains the specified point + */ + intersectPoint(point: Vec2): boolean { + let dx = point.x - this.x; + let px = this.hw - Math.abs(dx); + + if(px <= 0){ + return false; + } + + let dy = point.y - this.y; + let py = this.hh - Math.abs(dy); + + if(py <= 0){ + return false; + } + + return true; + } + + /** + * A boolean check of whether this AABB contains a point with soft left and top boundaries. + * In other words, if the top left is (0, 0), the point (0, 0) is not in the AABB + * @param point The point to check + * @returns A boolean representing whether this AABB contains the specified point + */ + containsPointSoft(point: Vec2): boolean { + return point.x > this.x - this.hw && point.x <= this.x + this.hw + && point.y > this.y - this.hh && point.y <= this.y + this.hh + } + + + /** + * Returns the data from the intersection of this AABB with a line segment from a point in a direction + * @param point The point that the line segment starts from + * @param delta The direction and distance of the segment + * @param padding Pads the AABB to make it wider for the intersection test + * @returns The Hit object representing the intersection, or null if there was no intersection + */ + intersectSegment(point: Vec2, delta: Vec2, padding?: Vec2): Hit { + let paddingX = padding ? padding.x : 0; + let paddingY = padding ? padding.y : 0; + + let scaleX = 1/delta.x; + let scaleY = 1/delta.y; + + let signX = MathUtils.sign(scaleX); + let signY = MathUtils.sign(scaleY); + + let tnearx = scaleX*(this.x - signX*(this.hw + paddingX) - point.x); + let tneary = scaleY*(this.y - signY*(this.hh + paddingY) - point.y); + let tfarx = scaleX*(this.x + signX*(this.hw + paddingX) - point.x); + let tfary = scaleY*(this.y + signY*(this.hh + paddingY) - point.y); + + if(tnearx > tfary || tneary > tfarx){ + // We aren't colliding - we clear one axis before intersecting another + return null; + } + + let tnear = Math.max(tnearx, tneary); + + // Double check for NaNs + if(tnearx !== tnearx){ + tnear = tneary; + } else if (tneary !== tneary){ + tnear = tnearx; + } + + let tfar = Math.min(tfarx, tfary); + + if(tnear === -Infinity){ + return null; + } + + if(tnear >= 1 || tfar <= 0){ + return null; + } + + // We are colliding + let hit = new Hit(); + hit.time = MathUtils.clamp01(tnear); + hit.nearTimes.x = tnearx; + hit.nearTimes.y = tneary; + + if(tnearx > tneary){ + // We hit on the left or right size + hit.normal.x = -signX; + hit.normal.y = 0; + } else if(Math.abs(tnearx - tneary) < 0.0001){ + // We hit on the corner + hit.normal.x = -signX; + hit.normal.y = -signY; + hit.normal.normalize(); + } else { + // We hit on the top or bottom + hit.normal.x = 0; + hit.normal.y = -signY; + } + + hit.delta.x = (1.0 - hit.time) * -delta.x; + hit.delta.y = (1.0 - hit.time) * -delta.y; + hit.pos.x = point.x + delta.x * hit.time; + hit.pos.y = point.y + delta.y * hit.time; + + return hit; + } + + // @override + overlaps(other: Shape): boolean { + if(other instanceof AABB){ + return this.overlapsAABB(other); + } + throw "Overlap not defined between these shapes." + } + + /** + * A simple boolean check of whether this AABB overlaps another + * @param other The other AABB to check against + * @returns True if this AABB overlaps the other, false otherwise + */ + protected overlapsAABB(other: AABB): boolean { + let dx = other.x - this.x; + let px = this.hw + other.hw - Math.abs(dx); + + if(px <= 0){ + return false; + } + + let dy = other.y - this.y; + let py = this.hh + other.hh - Math.abs(dy); + + if(py <= 0){ + return false; + } + + return true; + } + + /** + * Determines whether these AABBs are JUST touching - not overlapping. + * Vec2.x is -1 if the other is to the left, 1 if to the right. + * Likewise, Vec2.y is -1 if the other is on top, 1 if on bottom. + * @param other The other AABB to check + * @returns The collision sides stored in a Vec2 if the AABBs are touching, null otherwise + */ + touchesAABB(other: AABB): Vec2 { + let dx = other.x - this.x; + let px = this.hw + other.hw - Math.abs(dx); + + let dy = other.y - this.y; + let py = this.hh + other.hh - Math.abs(dy); + + // If one axis is just touching and the other is overlapping, true + if((px === 0 && py >= 0) || (py === 0 && px >= 0)){ + let ret = new Vec2(); + + if(px === 0){ + ret.x = other.x < this.x ? -1 : 1; + } + + if(py === 0){ + ret.y = other.y < this.y ? -1 : 1; + } + + return ret; + } else { + return null; + } + } + + /** + * Determines whether these AABBs are JUST touching - not overlapping. + * Also, if they are only touching corners, they are considered not touching. + * Vec2.x is -1 if the other is to the left, 1 if to the right. + * Likewise, Vec2.y is -1 if the other is on top, 1 if on bottom. + * @param other The other AABB to check + * @returns The side of the touch, stored as a Vec2, or null if there is no touch + */ + touchesAABBWithoutCorners(other: AABB): Vec2 { + let dx = other.x - this.x; + let px = this.hw + other.hw - Math.abs(dx); + + let dy = other.y - this.y; + let py = this.hh + other.hh - Math.abs(dy); + + // If one axis is touching, and the other is strictly overlapping + if((px === 0 && py > 0) || (py === 0 && px > 0)){ + let ret = new Vec2(); + + if(px === 0){ + ret.x = other.x < this.x ? -1 : 1; + } else { + ret.y = other.y < this.y ? -1 : 1; + } + + return ret; + + } else { + return null; + } + } + + /** + * Calculates the area of the overlap between this AABB and another + * @param other The other AABB + * @returns The area of the overlap between the AABBs + */ + overlapArea(other: AABB): number { + let leftx = Math.max(this.x - this.hw, other.x - other.hw); + let rightx = Math.min(this.x + this.hw, other.x + other.hw); + let dx = rightx - leftx; + + let lefty = Math.max(this.y - this.hh, other.y - other.hh); + let righty = Math.min(this.y + this.hh, other.y + other.hh); + let dy = righty - lefty; + + if(dx < 0 || dy < 0) return 0; + + return dx*dy; + } + + /** + * Moves and resizes this rect from its current position to the position specified + * @param velocity The movement of the rect from its position + * @param fromPosition A position specified to be the starting point of sweeping + * @param halfSize The halfSize of the sweeping rect + */ + sweep(velocity: Vec2, fromPosition?: Vec2, halfSize?: Vec2): void { + if(!fromPosition){ + fromPosition = this.center; + } + + if(!halfSize){ + halfSize = this.halfSize; + } + + let centerX = fromPosition.x + velocity.x/2; + let centerY = fromPosition.y + velocity.y/2; + + let minX = Math.min(fromPosition.x - halfSize.x, fromPosition.x + velocity.x - halfSize.x); + let minY = Math.min(fromPosition.y - halfSize.y, fromPosition.y + velocity.y - halfSize.y); + + this.center.set(centerX, centerY); + this.halfSize.set(centerX - minX, centerY - minY); + } + + // @override + clone(): AABB { + return new AABB(this.center.clone(), this.halfSize.clone()); + } + + /** + * Converts this AABB to a string format + * @returns (center: (x, y), halfSize: (x, y)) + */ + toString(): string { + return "(center: " + this.center.toString() + ", half-size: " + this.halfSize.toString() + ")" + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Shapes/Circle.ts b/hw3/src/Wolfie2D/DataTypes/Shapes/Circle.ts new file mode 100644 index 0000000..004ab79 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Shapes/Circle.ts @@ -0,0 +1,76 @@ +import Vec2 from "../Vec2"; +import AABB from "./AABB"; +import Shape from "./Shape"; + +/** + * A Circle + */ +export default class Circle extends Shape { + private _center: Vec2; + radius: number; + + /** + * Creates a new Circle + * @param center The center of the circle + * @param radius The radius of the circle + */ + constructor(center: Vec2, radius: number) { + super(); + this._center = center ? center : new Vec2(0, 0); + this.radius = radius ? radius : 0; + } + + get center(): Vec2 { + return this._center; + } + + set center(center: Vec2) { + this._center = center; + } + + get halfSize(): Vec2 { + return new Vec2(this.radius, this.radius); + } + + get r(): number { + return this.radius; + } + + set r(radius: number) { + this.radius = radius; + } + + // @override + /** + * A simple boolean check of whether this AABB contains a point + * @param point The point to check + * @returns A boolean representing whether this AABB contains the specified point + */ + containsPoint(point: Vec2): boolean { + return this.center.distanceSqTo(point) <= this.radius*this.radius; + } + + // @override + getBoundingRect(): AABB { + return new AABB(this._center.clone(), new Vec2(this.radius, this.radius)); + } + + // @override + getBoundingCircle(): Circle { + return this.clone(); + } + + // @override + overlaps(other: Shape): boolean { + throw new Error("Method not implemented."); + } + + // @override + clone(): Circle { + return new Circle(this._center.clone(), this.radius); + } + + toString(): string { + return "(center: " + this.center.toString() + ", radius: " + this.radius + ")"; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Shapes/Shape.ts b/hw3/src/Wolfie2D/DataTypes/Shapes/Shape.ts new file mode 100644 index 0000000..04113c9 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Shapes/Shape.ts @@ -0,0 +1,169 @@ +import Vec2 from "../Vec2"; +import AABB from "./AABB"; +import Circle from "./Circle"; + +/** + * An abstract Shape class that acts as an interface for better interactions with subclasses. + */ +export default abstract class Shape { + abstract get center(): Vec2; + + abstract set center(center: Vec2); + + abstract get halfSize(): Vec2; + + get x(): number { + return this.center.x; + } + + get y(): number { + return this.center.y; + } + + get hw(): number { + return this.halfSize.x; + } + + get hh(): number { + return this.halfSize.y; + } + + get top(): number { + return this.y - this.hh; + } + + get bottom(): number { + return this.y + this.hh; + } + + get left(): number { + return this.x - this.hw; + } + + get right(): number { + return this.x + this.hw; + } + + /** + * Gets a bounding rectangle for this shape. Warning - may be the same as this Shape. + * For instance, the bounding circle of an AABB is itself. Use clone() if you need a new shape. + * @returns An AABB that bounds this shape + */ + abstract getBoundingRect(): AABB; + + /** + * Gets a bounding circle for this shape. Warning - may be the same as this Shape. + * For instance, the bounding circle of a Circle is itself. Use clone() if you need a new shape. + * @returns A Circle that bounds this shape + */ + abstract getBoundingCircle(): Circle; + + /** + * Returns a copy of this Shape + * @returns A new copy of this shape + */ + abstract clone(): Shape; + + /** + * Checks if this shape overlaps another + * @param other The other shape to check against + * @returns a boolean that represents whether this Shape overlaps the other one + */ + abstract overlaps(other: Shape): boolean; + + /** + * A simple boolean check of whether this Shape contains a point + * @param point The point to check + * @returns A boolean representing whether this Shape contains the specified point + */ + abstract containsPoint(point: Vec2): boolean; + + static getTimeOfCollision(A: Shape, velA: Vec2, B: Shape, velB: Vec2): [Vec2, Vec2, boolean, boolean] { + if(A instanceof AABB && B instanceof AABB){ + return Shape.getTimeOfCollision_AABB_AABB(A, velA, B, velB); + } + } + + private static getTimeOfCollision_AABB_AABB(A: AABB, velA: Vec2, B: Shape, velB: Vec2): [Vec2, Vec2, boolean, boolean] { + let posSmaller = A.center; + let posLarger = B.center; + + let sizeSmaller = A.halfSize; + let sizeLarger = B.halfSize; + + let firstContact = new Vec2(0, 0); + let lastContact = new Vec2(0, 0); + + let collidingX = false; + let collidingY = false; + + // Sort by position + if(posLarger.x < posSmaller.x){ + // Swap, because smaller is further right than larger + let temp: Vec2; + temp = sizeSmaller; + sizeSmaller = sizeLarger; + sizeLarger = temp; + + temp = posSmaller; + posSmaller = posLarger; + posLarger = temp; + + temp = velA; + velA = velB; + velB = temp; + } + + // A is left, B is right + firstContact.x = Infinity; + lastContact.x = Infinity; + + if (posLarger.x - sizeLarger.x >= posSmaller.x + sizeSmaller.x){ + // If we aren't currently colliding + let relVel = velA.x - velB.x; + + if(relVel > 0){ + // If they are moving towards each other + firstContact.x = ((posLarger.x - sizeLarger.x) - (posSmaller.x + sizeSmaller.x))/(relVel); + lastContact.x = ((posLarger.x + sizeLarger.x) - (posSmaller.x - sizeSmaller.x))/(relVel); + } + } else { + collidingX = true; + } + + if(posLarger.y < posSmaller.y){ + // Swap, because smaller is further up than larger + let temp: Vec2; + temp = sizeSmaller; + sizeSmaller = sizeLarger; + sizeLarger = temp; + + temp = posSmaller; + posSmaller = posLarger; + posLarger = temp; + + temp = velA; + velA = velB; + velB = temp; + } + + // A is top, B is bottom + firstContact.y = Infinity; + lastContact.y = Infinity; + + if (posLarger.y - sizeLarger.y >= posSmaller.y + sizeSmaller.y){ + // If we aren't currently colliding + let relVel = velA.y - velB.y; + + if(relVel > 0){ + // If they are moving towards each other + firstContact.y = ((posLarger.y - sizeLarger.y) - (posSmaller.y + sizeSmaller.y))/(relVel); + lastContact.y = ((posLarger.y + sizeLarger.y) - (posSmaller.y - sizeSmaller.y))/(relVel); + } + } else { + collidingY = true; + } + + return [firstContact, lastContact, collidingX, collidingY]; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Spritesheet.ts b/hw3/src/Wolfie2D/DataTypes/Spritesheet.ts new file mode 100644 index 0000000..d1f845c --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Spritesheet.ts @@ -0,0 +1,22 @@ +import { AnimationData } from "../Rendering/Animations/AnimationTypes"; + +/** A class representing data contained in a spritesheet. + * Spritesheets are the images associated with sprites, and contain images indexed in a grid, which + * correspond to animations. + */ +export default class Spritesheet { + /** The name of the spritesheet */ + name: string; + /** The image key of the spritesheet */ + spriteSheetImage: string; + /** The width of the sprite */ + spriteWidth: number; + /** The height of the sprite */ + spriteHeight: number; + /** The number of columns in the spritesheet */ + columns: number; + /** The number of rows in the spritesheet */ + rows: number; + /** An array of the animations associated with this spritesheet */ + animations: Array; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Stack.ts b/hw3/src/Wolfie2D/DataTypes/Stack.ts new file mode 100644 index 0000000..d45d5b5 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Stack.ts @@ -0,0 +1,108 @@ +import Collection from "./Collection"; + +/** + * A LIFO stack with items of type T + */ +export default class Stack implements Collection { + /** The maximum number of elements in the Stack */ + private MAX_ELEMENTS: number; + + /** The internal representation of the stack */ + private stack: Array; + + /** The head of the stack */ + private head: number; + + /** + * Constructs a new stack + * @param maxElements The maximum size of the stack + */ + constructor(maxElements: number = 100){ + this.MAX_ELEMENTS = maxElements; + this.stack = new Array(this.MAX_ELEMENTS); + this.head = -1; + } + + /** + * Adds an item to the top of the stack + * @param item The new item to add to the stack + */ + push(item: T): void { + if(this.head + 1 === this.MAX_ELEMENTS){ + throw "Stack full - cannot add element"; + } + this.head += 1; + this.stack[this.head] = item; + } + + /** + * Removes an item from the top of the stack + * @returns The item at the top of the stack + */ + pop(): T { + if(this.head === -1){ + throw "Stack empty - cannot remove element"; + } + this.head -= 1; + return this.stack[this.head + 1]; + } + + /** + * Returns the element currently at the top of the stack + * @returns The item at the top of the stack + */ + peek(): T { + if(this.head === -1){ + throw "Stack empty - cannot get element"; + } + return this.stack[this.head]; + } + + /** Returns true if this stack is empty + * @returns A boolean that represents whether or not the stack is empty + */ + isEmpty(): boolean { + return this.head === -1; + } + + // @implemented + clear(): void { + this.forEach((item, index) => delete this.stack[index]); + this.head = -1; + } + + /** + * Returns the number of items currently in the stack + * @returns The number of items in the stack + */ + size(): number { + return this.head + 1; + } + + // @implemented + forEach(func: (item: T, index?: number) => void): void{ + let i = 0; + while(i <= this.head){ + func(this.stack[i], i); + i += 1; + } + } + + /** + * Converts this stack into a string format + * @returns A string representing this stack + */ + toString(): string { + let retval = ""; + + this.forEach( (item, index) => { + let str = item.toString() + if(index !== 0){ + str += " -> " + } + retval = str + retval; + }); + + return "Top -> " + retval; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/State/State.ts b/hw3/src/Wolfie2D/DataTypes/State/State.ts new file mode 100644 index 0000000..469ce1d --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/State/State.ts @@ -0,0 +1,54 @@ +import Emitter from "../../Events/Emitter"; +import GameEvent from "../../Events/GameEvent"; +import Updateable from "../Interfaces/Updateable"; +import StateMachine from "./StateMachine"; + +/** + * An abstract implementation of a state for a @reference[StateMachine]. + * This class should be extended to allow for custom state behaviors. + */ +export default abstract class State implements Updateable { + /** The StateMachine that uses this State */ + protected parent: StateMachine; + + /** An event emitter */ + protected emitter: Emitter; + + /** + * Constructs a new State + * @param parent The parent StateMachine of this state + */ + constructor(parent: StateMachine) { + this.parent = parent; + this.emitter = new Emitter(); + } + + /** + * A method that is called when this state is entered. Use this to initialize any variables before updates occur. + * @param options Information to pass to this state + */ + abstract onEnter(options: Record): void; + + /** + * A lifecycle method that handles an input event, such as taking damage. + * @param event The GameEvent to process + */ + abstract handleInput(event: GameEvent): void; + + // @implemented + abstract update(deltaT: number): void; + + /** + * Tells the state machine that this state has ended, and makes it transition to the new state specified + * @param stateName The name of the state to transition to + */ + protected finished(stateName: string): void { + this.parent.changeState(stateName); + } + + /** + * A lifecycle method is called when the state is ending. + * @returns info to pass to the next state + */ + abstract onExit(): Record; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/State/StateMachine.ts b/hw3/src/Wolfie2D/DataTypes/State/StateMachine.ts new file mode 100644 index 0000000..a6382e7 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/State/StateMachine.ts @@ -0,0 +1,137 @@ +import Stack from "../Stack"; +import State from "./State"; +import Map from "../Map"; +import GameEvent from "../../Events/GameEvent"; +import Receiver from "../../Events/Receiver"; +import Emitter from "../../Events/Emitter"; +import Updateable from "../Interfaces/Updateable"; + +/** + * An implementation of a Push Down Automata State machine. States can also be hierarchical + * for more flexibility, as described in @link(Game Programming Patterns)(https://gameprogrammingpatterns.com/state.html). + */ +export default class StateMachine implements Updateable { + /** A stack of the current states */ + protected stack: Stack; + /** A mape of state keys to actual state instances */ + protected stateMap: Map; + /** The current state */ + protected currentState: State; + /** An event receiver */ + protected receiver: Receiver; + /** An event emitter */ + protected emitter: Emitter; + /** A boolean representing whether or not this StateMachine is currently active */ + protected active: boolean; + /** A boolean representing whether or not this StateMachine should emit an event on state change */ + protected emitEventOnStateChange: boolean; + /** The name of the event to be emitted on state change */ + protected stateChangeEventName: string; + + /** + * Creates a new StateMachine + */ + constructor(){ + this.stack = new Stack(); + this.stateMap = new Map(); + this.receiver = new Receiver(); + this.emitter = new Emitter(); + this.emitEventOnStateChange = false; + } + + /** + * Sets the activity state of this state machine + * @param flag True if you want to set this machine running, false otherwise + */ + setActive(flag: boolean): void { + this.active = flag; + } + + /** + * Makes this state machine emit an event any time its state changes + * @param stateChangeEventName The name of the event to emit + */ + setEmitEventOnStateChange(stateChangeEventName: string): void { + this.emitEventOnStateChange = true; + this.stateChangeEventName = stateChangeEventName; + } + + /** + * Stops this state machine from emitting events on state change. + */ + cancelEmitEventOnStateChange(): void { + this.emitEventOnStateChange = false; + } + + /** + * Initializes this state machine with an initial state and sets it running + * @param initialState The name of initial state of the state machine + */ + initialize(initialState: string, options: Record = {}): void { + this.stack.push(this.stateMap.get(initialState)); + this.currentState = this.stack.peek(); + this.currentState.onEnter(options); + this.setActive(true); + } + + /** + * Adds a state to this state machine + * @param stateName The name of the state to add + * @param state The state to add + */ + addState(stateName: string, state: State): void { + this.stateMap.add(stateName, state); + } + + /** + * Changes the state of this state machine to the provided string + * @param state The string name of the state to change to + */ + changeState(state: string): void { + // Exit the current state + let options = this.currentState.onExit(); + + // Make sure the correct state is at the top of the stack + if(state === "previous"){ + // Pop the current state off the stack + this.stack.pop(); + } else { + // Retrieve the new state from the statemap and put it at the top of the stack + this.stack.pop(); + this.stack.push(this.stateMap.get(state)); + } + + // Retreive the new state from the stack + this.currentState = this.stack.peek(); + + // Emit an event if turned on + if(this.emitEventOnStateChange){ + this.emitter.fireEvent(this.stateChangeEventName, {state: this.currentState}); + } + + // Enter the new state + this.currentState.onEnter(options); + } + + /** + * Handles input. This happens at the very beginning of this state machine's update cycle. + * @param event The game event to process + */ + handleEvent(event: GameEvent): void { + if(this.active){ + this.currentState.handleInput(event); + } + } + + // @implemented + update(deltaT: number): void { + // Distribute events + while(this.receiver.hasNextEvent()){ + let event = this.receiver.getNextEvent(); + this.handleEvent(event); + } + + // Delegate the update to the current state + this.currentState.update(deltaT); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Tilesets/TiledData.ts b/hw3/src/Wolfie2D/DataTypes/Tilesets/TiledData.ts new file mode 100644 index 0000000..25146db --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Tilesets/TiledData.ts @@ -0,0 +1,78 @@ +// @ignorePage +/** + * a representation of Tiled's tilemap data + */ +export class TiledTilemapData { + height: number; + width: number; + tileheight: number; + tilewidth: number; + orientation: string; + layers: Array; + tilesets: Array; +} + +/** + * A representation of a custom layer property in a Tiled tilemap + */ +export class TiledLayerProperty { + name: string; + type: string; + value: any; +} + +/** + * A representation of a tileset in a Tiled tilemap + */ +export class TiledTilesetData { + columns: number; + tilewidth: number; + tileheight: number; + tilecount: number; + firstgid: number; + imageheight: number; + imagewidth: number; + margin: number; + spacing: number; + name: string; + image: string; + tiles: Array +} + +/** + * A representation of a layer in a Tiled tilemap + */ +export class TiledLayerData { + data: number[]; + x: number; + y: number; + width: number; + height: number; + name: string; + opacity: number; + visible: boolean; + properties: TiledLayerProperty[]; + type: string; + objects: Array; +} + +export class TiledObject { + gid: number; + height: number; + width: number; + id: number; + name: string;; + properties: Array; + rotation: number; + type: string; + visible: boolean; + x: number; + y: number; +} + +export class TiledCollectionTile { + id: number; + image: string; + imageheight: number; + imagewidth: number; +} diff --git a/hw3/src/Wolfie2D/DataTypes/Tilesets/Tileset.ts b/hw3/src/Wolfie2D/DataTypes/Tilesets/Tileset.ts new file mode 100644 index 0000000..e3d6419 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Tilesets/Tileset.ts @@ -0,0 +1,146 @@ +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Vec2 from "../Vec2"; +import { TiledTilesetData } from "./TiledData"; + +/** + * The data representation of a Tileset for the game engine. This represents one image, + * with a startIndex if required (as it is with Tiled using two images in one tilset). + */ +export default class Tileset { + /** The key of the image used by this tileset */ + protected imageKey: string; + /** The size of the tileset image */ + protected imageSize: Vec2; + /** The index of 0th image of this tileset */ + protected startIndex: number; + /** The index of the last image of this tilset */ + protected endIndex: number; + /** The size of the tiles in this tileset */ + protected tileSize: Vec2; + /** The number of rows in this tileset */ + protected numRows: number; + /** The number of columns in this tileset */ + protected numCols: number; + + // TODO: Change this to be more general and work with other tileset formats + constructor(tilesetData: TiledTilesetData){ + // Defer handling of the data to a helper class + this.initFromTiledData(tilesetData); + } + + /** + * Initialize the tileset from the data from a Tiled json file + * @param tiledData The parsed object from a Tiled json file + */ + initFromTiledData(tiledData: TiledTilesetData): void { + this.numRows = tiledData.tilecount/tiledData.columns; + this.numCols = tiledData.columns; + this.startIndex = tiledData.firstgid; + this.endIndex = this.startIndex + tiledData.tilecount - 1; + this.tileSize = new Vec2(tiledData.tilewidth, tiledData.tilewidth); + this.imageKey = tiledData.image; + this.imageSize = new Vec2(tiledData.imagewidth, tiledData.imageheight); + } + + /** + * Gets the image key associated with this tilemap + * @returns The image key of this tilemap + */ + getImageKey(): string { + return this.imageKey; + } + + /** + * Returns a Vec2 containing the left and top offset from the image origin for this tile. + * @param tileIndex The index of the tile from startIndex to endIndex of this tileset + * @returns A Vec2 containing the offset for the specified tile. + */ + getImageOffsetForTile(tileIndex: number): Vec2 { + // Get the true index + let index = tileIndex - this.startIndex; + let row = Math.floor(index / this.numCols); + let col = index % this.numCols; + let width = this.tileSize.x; + let height = this.tileSize.y; + + // Calculate the position to start a crop in the tileset image + let left = col * width; + let top = row * height; + + return new Vec2(left, top); + } + + /** + * Gets the start index + * @returns The start index + */ + getStartIndex(): number { + return this.startIndex; + } + + /** + * Gets the tile set + * @returns A Vec2 containing the tile size + */ + getTileSize(): Vec2 { + return this.tileSize; + } + + /** + * Gets the number of rows in the tileset + * @returns The number of rows + */ + getNumRows(): number { + return this.numRows; + } + + /** + * Gets the number of columns in the tilset + * @returns The number of columns + */ + getNumCols(): number { + return this.numCols; + } + + getTileCount(): number { + return this.endIndex - this.startIndex + 1; + } + + /** + * Checks whether or not this tilset contains the specified tile index. This is used for rendering. + * @param tileIndex The index of the tile to check + * @returns A boolean representing whether or not this tilset uses the specified index + */ + hasTile(tileIndex: number): boolean { + return tileIndex >= this.startIndex && tileIndex <= this.endIndex; + } + + /** + * Render a singular tile with index tileIndex from the tileset located at position dataIndex + * @param ctx The rendering context + * @param tileIndex The value of the tile to render + * @param dataIndex The index of the tile in the data array + * @param worldSize The size of the world + * @param origin The viewport origin in the current layer + * @param scale The scale of the tilemap + */ + renderTile(ctx: CanvasRenderingContext2D, tileIndex: number, dataIndex: number, maxCols: number, origin: Vec2, scale: Vec2, zoom: number): void { + let image = ResourceManager.getInstance().getImage(this.imageKey); + + // Get the true index + let index = tileIndex - this.startIndex; + let row = Math.floor(index / this.numCols); + let col = index % this.numCols; + let width = this.tileSize.x; + let height = this.tileSize.y; + + // Calculate the position to start a crop in the tileset image + let left = col * width; + let top = row * height; + + // Calculate the position in the world to render the tile + let x = Math.floor((dataIndex % maxCols) * width * scale.x); + let y = Math.floor(Math.floor(dataIndex / maxCols) * height * scale.y); + ctx.drawImage(image, left, top, width, height, Math.floor((x - origin.x)*zoom), Math.floor((y - origin.y)*zoom), Math.ceil(width * scale.x * zoom), Math.ceil(height * scale.y * zoom)); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/DataTypes/Vec2.ts b/hw3/src/Wolfie2D/DataTypes/Vec2.ts new file mode 100644 index 0000000..1764525 --- /dev/null +++ b/hw3/src/Wolfie2D/DataTypes/Vec2.ts @@ -0,0 +1,432 @@ +import MathUtils from "../Utils/MathUtils"; + +/** + * A two-dimensional vector (x, y) + */ +export default class Vec2 { + + // Store x and y in an array + /** The array that stores the actual vector values x and y */ + private vec: Float32Array; + + /** + * When this vector changes its value, do something + */ + private onChange: Function = () => {}; + + /** + * Creates a new Vec2 + * @param x The x value of the vector + * @param y The y value of the vector + */ + constructor(x: number = 0, y: number = 0) { + this.vec = new Float32Array(2); + this.vec[0] = x; + this.vec[1] = y; + } + + // Expose x and y with getters and setters + get x() { + return this.vec[0]; + } + + set x(x: number) { + this.vec[0] = x; + + if(this.onChange){ + this.onChange(); + } + } + + get y() { + return this.vec[1]; + } + + set y(y: number) { + this.vec[1] = y; + + if(this.onChange){ + this.onChange(); + } + } + + static get ZERO() { + return new Vec2(0, 0); + } + + static readonly ZERO_STATIC = new Vec2(0, 0); + + static get INF() { + return new Vec2(Infinity, Infinity); + } + + static get UP() { + return new Vec2(0, -1); + } + + static get DOWN() { + return new Vec2(0, 1); + } + + static get LEFT() { + return new Vec2(-1, 0); + } + + static get RIGHT() { + return new Vec2(1, 0); + } + + /** + * The squared magnitude of the vector. This tends to be faster, so use it in situations where taking the + * square root doesn't matter, like for comparing distances. + * @returns The squared magnitude of the vector + */ + magSq(): number { + return this.x*this.x + this.y*this.y; + } + + /** + * The magnitude of the vector. + * @returns The magnitude of the vector. + */ + mag(): number { + return Math.sqrt(this.magSq()); + } + + /** + * Divdes x and y by the magnitude to obtain the unit vector in the direction of this vector. + * @returns This vector as a unit vector. + */ + normalize(): Vec2 { + if(this.x === 0 && this.y === 0) return this; + let mag = this.mag(); + this.x /= mag; + this.y /= mag; + return this; + } + + /** + * Works like normalize(), but returns a new Vec2 + * @returns A new vector that is the unit vector for this one + */ + normalized(): Vec2 { + if(this.isZero()){ + return this; + } + + let mag = this.mag(); + return new Vec2(this.x/mag, this.y/mag); + } + + /** + * Sets the x and y elements of this vector to zero. + * @returns This vector, with x and y set to zero. + */ + zero(): Vec2 { + return this.set(0, 0); + } + + /** + * Sets the vector's x and y based on the angle provided. Goes counter clockwise. + * @param angle The angle in radians + * @param radius The magnitude of the vector at the specified angle + * @returns This vector. + */ + setToAngle(angle: number, radius: number = 1): Vec2 { + this.x = MathUtils.floorToPlace(Math.cos(angle)*radius, 5); + this.y = MathUtils.floorToPlace(-Math.sin(angle)*radius, 5); + return this; + } + + /** + * Returns a vector that point from this vector to another one + * @param other The vector to point to + * @returns A new Vec2 that points from this vector to the one provided + */ + vecTo(other: Vec2): Vec2 { + return new Vec2(other.x - this.x, other.y - this.y); + } + + /** + * Returns a vector containing the direction from this vector to another + * @param other The vector to point to + * @returns A new Vec2 that points from this vector to the one provided. This new Vec2 will be a unit vector. + */ + dirTo(other: Vec2): Vec2 { + return this.vecTo(other).normalize(); + } + + /** + * Keeps the vector's direction, but sets its magnitude to be the provided magnitude + * @param magnitude The magnitude the vector should be + * @returns This vector with its magnitude set to the new magnitude + */ + scaleTo(magnitude: number): Vec2 { + return this.normalize().scale(magnitude); + } + + /** + * Scales x and y by the number provided, or if two number are provided, scales them individually. + * @param factor The scaling factor for the vector, or for only the x-component if yFactor is provided + * @param yFactor The scaling factor for the y-component of the vector + * @returns This vector after scaling + */ + scale(factor: number, yFactor: number = null): Vec2 { + if(yFactor !== null){ + this.x *= factor; + this.y *= yFactor; + return this; + } + this.x *= factor; + this.y *= factor; + return this; + } + + /** + * Returns a scaled version of this vector without modifying it. + * @param factor The scaling factor for the vector, or for only the x-component if yFactor is provided + * @param yFactor The scaling factor for the y-component of the vector + * @returns A new vector that has the values of this vector after scaling + */ + scaled(factor: number, yFactor: number = null): Vec2 { + return this.clone().scale(factor, yFactor); + } + + /** + * Rotates the vector counter-clockwise by the angle amount specified + * @param angle The angle to rotate by in radians + * @returns This vector after rotation. + */ + rotateCCW(angle: number): Vec2 { + let cs = Math.cos(angle); + let sn = Math.sin(angle); + let tempX = this.x*cs - this.y*sn; + let tempY = this.x*sn + this.y*cs; + this.x = tempX; + this.y = tempY; + return this; + } + + /** + * Sets the vectors coordinates to be the ones provided + * @param x The new x value for this vector + * @param y The new y value for this vector + * @returns This vector + */ + set(x: number, y: number): Vec2 { + this.x = x; + this.y = y; + return this; + } + + /** + * Copies the values of the other Vec2 into this one. + * @param other The Vec2 to copy + * @returns This vector with its values set to the vector provided + */ + copy(other: Vec2): Vec2 { + return this.set(other.x, other.y); + } + + /** + * Adds this vector the another vector + * @param other The Vec2 to add to this one + * @returns This vector after adding the one provided + */ + add(other: Vec2): Vec2 { + this.x += other.x; + this.y += other.y; + return this; + } + + /** + * Increments the fields of this vector. Both are incremented with a, if only a is provided. + * @param a The first number to increment by + * @param b The second number to increment by + * @returnss This vector after incrementing + */ + inc(a: number, b?: number): Vec2 { + if(b === undefined){ + this.x += a; + this.y += a; + } else { + this.x += a; + this.y += b; + } + return this; + } + + /** + * Subtracts another vector from this vector + * @param other The Vec2 to subtract from this one + * @returns This vector after subtracting the one provided + */ + sub(other: Vec2): Vec2 { + this.x -= other.x; + this.y -= other.y; + return this; + } + + /** + * Multiplies this vector with another vector element-wise. In other words, this.x *= other.x and this.y *= other.y + * @param other The Vec2 to multiply this one by + * @returns This vector after multiplying its components by this one + */ + mult(other: Vec2): Vec2 { + this.x *= other.x; + this.y *= other.y; + return this; + } + + /** + * Divides this vector with another vector element-wise. In other words, this.x /= other.x and this.y /= other.y + * @param other The vector to divide this one by + * @returns This vector after division + */ + div(other: Vec2): Vec2 { + if(other.x === 0 || other.y === 0) throw "Divide by zero error"; + this.x /= other.x; + this.y /= other.y; + return this; + } + + /** + * Does an element wise remainder operation on this vector. this.x %= other.x and this.y %= other.y + * @param other The other vector + * @returns this vector + */ + remainder(other: Vec2): Vec2 { + this.x = this.x % other.x; + this.y = this.y % other.y; + return this; + } + + /** + * Returns the squared distance between this vector and another vector + * @param other The vector to compute distance squared to + * @returns The squared distance between this vector and the one provided + */ + distanceSqTo(other: Vec2): number { + return (this.x - other.x)*(this.x - other.x) + (this.y - other.y)*(this.y - other.y); + } + + /** + * Returns the distance between this vector and another vector + * @param other The vector to compute distance to + * @returns The distance between this vector and the one provided + */ + distanceTo(other: Vec2): number { + return Math.sqrt(this.distanceSqTo(other)); + } + + /** + * Returns the dot product of this vector and another + * @param other The vector to compute the dot product with + * @returns The dot product of this vector and the one provided. + */ + dot(other: Vec2): number { + return this.x*other.x + this.y*other.y; + } + + /** + * Returns the angle counter-clockwise in radians from this vector to another vector + * @param other The vector to compute the angle to + * @returns The angle, rotating CCW, from this vector to the other vector + */ + angleToCCW(other: Vec2): number { + let dot = this.dot(other); + let det = this.x*other.y - this.y*other.x; + let angle = -Math.atan2(det, dot); + + if(angle < 0){ + angle += 2*Math.PI; + } + + return angle; + } + + /** + * Returns a string representation of this vector rounded to 1 decimal point + * @returns This vector as a string + */ + toString(): string { + return this.toFixed(); + } + + /** + * Returns a string representation of this vector rounded to the specified number of decimal points + * @param numDecimalPoints The number of decimal points to create a string to + * @returns This vector as a string + */ + toFixed(numDecimalPoints: number = 1): string { + return "(" + this.x.toFixed(numDecimalPoints) + ", " + this.y.toFixed(numDecimalPoints) + ")"; + } + + /** + * Returns a new vector with the same coordinates as this one. + * @returns A new Vec2 with the same values as this one + */ + clone(): Vec2 { + return new Vec2(this.x, this.y); + } + + /** + * Returns true if this vector and other have the EXACT same x and y (not assured to be safe for floats) + * @param other The vector to check against + * @returns A boolean representing the equality of the two vectors + */ + strictEquals(other: Vec2): boolean { + return this.x === other.x && this.y === other.y; + } + + /** + * Returns true if this vector and other have the same x and y + * @param other The vector to check against + * @returns A boolean representing the equality of the two vectors + */ + equals(other: Vec2): boolean { + let xEq = Math.abs(this.x - other.x) < 0.0000001; + let yEq = Math.abs(this.y - other.y) < 0.0000001; + + return xEq && yEq; + } + + /** + * Returns true if this vector is the zero vector exactly (not assured to be safe for floats). + * @returns A boolean representing the equality of this vector and the zero vector + */ + strictIsZero(): boolean { + return this.x === 0 && this.y === 0; + } + + /** + * Returns true if this x and y for this vector are both zero. + * @returns A boolean representing the equality of this vector and the zero vector + */ + isZero(): boolean { + return Math.abs(this.x) < 0.0000001 && Math.abs(this.y) < 0.0000001; + } + + /** + * Sets the function that is called whenever this vector is changed. + * @param f The function to be called + */ + setOnChange(f: Function): void { + this.onChange = f; + } + + toArray(): Float32Array { + return this.vec; + } + + /** + * Performs linear interpolation between two vectors + * @param a The first vector + * @param b The second vector + * @param t The time of the lerp, with 0 being vector A, and 1 being vector B + * @returns A new Vec2 representing the lerp between vector a and b. + */ + static lerp(a: Vec2, b: Vec2, t: number): Vec2 { + return new Vec2(MathUtils.lerp(a.x, b.x, t), MathUtils.lerp(a.y, b.y, t)); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Debug/Debug.ts b/hw3/src/Wolfie2D/Debug/Debug.ts new file mode 100644 index 0000000..22cfc8b --- /dev/null +++ b/hw3/src/Wolfie2D/Debug/Debug.ts @@ -0,0 +1,197 @@ +import Map from "../DataTypes/Map"; +import Vec2 from "../DataTypes/Vec2"; +import GameNode from "../Nodes/GameNode"; +import Color from "../Utils/Color"; + +/** + * A util class for rendering Debug messages to the canvas. + */ +export default class Debug { + + /** A map of log messages to display on the screen */ + private static logMessages: Map = new Map(); + + /** An array of game nodes to render debug info for */ + private static nodes: Array; + + /** The rendering context for any debug messages */ + private static debugRenderingContext: CanvasRenderingContext2D; + + /** The size of the debug canvas */ + private static debugCanvasSize: Vec2; + + /** The rendering color for text */ + private static defaultTextColor: Color = Color.WHITE; + + /** + * Add a message to display on the debug screen + * @param id A unique ID for this message + * @param messages The messages to print to the debug screen + */ + static log(id: string, ...messages: any): void { + // let message = ""; + // for(let i = 0; i < messages.length; i++){ + // message += messages[i].toString(); + // } + // Join all messages with spaces + let message = messages.map((m: any) => m.toString()).join(" "); + this.logMessages.add(id, message); + } + + /** + * Deletes a a key from the log and stops it from keeping up space on the screen + * @param id The id of the log item to clear + */ + static clearLogItem(id: string): void { + this.logMessages.delete(id); + } + + /** + * Sets the list of nodes to render with the debugger + * @param nodes The new list of nodes + */ + static setNodes(nodes: Array): void { + this.nodes = nodes; + } + + /** + * Draws a box at the specified position + * @param center The center of the box + * @param halfSize The dimensions of the box + * @param filled A boolean for whether or not the box is filled + * @param color The color of the box to draw + */ + static drawBox(center: Vec2, halfSize: Vec2, filled: boolean, color: Color): void { + let alpha = this.debugRenderingContext.globalAlpha; + this.debugRenderingContext.globalAlpha = color.a; + + if(filled){ + this.debugRenderingContext.fillStyle = color.toString(); + this.debugRenderingContext.fillRect(center.x - halfSize.x, center.y - halfSize.y, halfSize.x*2, halfSize.y*2); + } else { + let lineWidth = 2; + this.debugRenderingContext.lineWidth = lineWidth; + this.debugRenderingContext.strokeStyle = color.toString(); + this.debugRenderingContext.strokeRect(center.x - halfSize.x, center.y - halfSize.y, halfSize.x*2, halfSize.y*2); + } + + this.debugRenderingContext.globalAlpha = alpha; + } + + /** + * Draws a circle at the specified position + * @param center The center of the circle + * @param radius The dimensions of the box + * @param filled A boolean for whether or not the circle is filled + * @param color The color of the circle + */ + static drawCircle(center: Vec2, radius: number, filled: boolean, color: Color): void { + let alpha = this.debugRenderingContext.globalAlpha; + this.debugRenderingContext.globalAlpha = color.a; + + if(filled){ + this.debugRenderingContext.fillStyle = color.toString(); + this.debugRenderingContext.beginPath(); + this.debugRenderingContext.arc(center.x, center.y, radius, 0, 2 * Math.PI); + this.debugRenderingContext.closePath(); + this.debugRenderingContext.fill(); + } else { + let lineWidth = 2; + this.debugRenderingContext.lineWidth = lineWidth; + this.debugRenderingContext.strokeStyle = color.toString(); + this.debugRenderingContext.beginPath(); + this.debugRenderingContext.arc(center.x, center.y, radius, 0, 2 * Math.PI); + this.debugRenderingContext.closePath(); + this.debugRenderingContext.stroke(); + } + + this.debugRenderingContext.globalAlpha = alpha; + } + + /** + * Draws a ray at the specified position + * @param from The starting position of the ray + * @param to The ending position of the ray + * @param color The color of the ray + */ + static drawRay(from: Vec2, to: Vec2, color: Color): void { + this.debugRenderingContext.lineWidth = 2; + this.debugRenderingContext.strokeStyle = color.toString(); + + this.debugRenderingContext.beginPath(); + this.debugRenderingContext.moveTo(from.x, from.y); + this.debugRenderingContext.lineTo(to.x, to.y); + this.debugRenderingContext.closePath(); + this.debugRenderingContext.stroke(); + } + + /** + * Draws a point at the specified position + * @param pos The position of the point + * @param color The color of the point + */ + static drawPoint(pos: Vec2, color: Color): void { + let pointSize = 6; + this.debugRenderingContext.fillStyle = color.toString(); + this.debugRenderingContext.fillRect(pos.x - pointSize/2, pos.y - pointSize/2, pointSize, pointSize); + } + + /** + * Sets the default rendering color for text for the debugger + * @param color The color to render the text + */ + static setDefaultTextColor(color: Color): void { + this.defaultTextColor = color; + } + + /** + * Performs any necessary setup operations on the Debug canvas + * @param canvas The debug canvas + * @param width The desired width of the canvas + * @param height The desired height of the canvas + * @returns The rendering context extracted from the canvas + */ + static initializeDebugCanvas(canvas: HTMLCanvasElement, width: number, height: number): CanvasRenderingContext2D { + canvas.width = width; + canvas.height = height; + + this.debugCanvasSize = new Vec2(width, height); + + this.debugRenderingContext = canvas.getContext("2d"); + + return this.debugRenderingContext; + } + + /** Clears the debug canvas */ + static clearCanvas(): void { + this.debugRenderingContext.clearRect(0, 0, this.debugCanvasSize.x, this.debugCanvasSize.y); + } + + /** Renders the text and nodes sent to the Debug system */ + static render(): void { + this.renderText(); + this.renderNodes(); + } + + /** Renders the text sent to the Debug canvas */ + static renderText(): void { + let y = 20; + this.debugRenderingContext.font = "20px Arial"; + this.debugRenderingContext.fillStyle = this.defaultTextColor.toString(); + + // Draw all of the text + this.logMessages.forEach((key: string) => { + this.debugRenderingContext.fillText(this.logMessages.get(key), 10, y) + y += 30; + }); + } + + /** Renders the nodes registered with the debug canvas */ + static renderNodes(): void { + if(this.nodes){ + this.nodes.forEach(node => { + node.debugRender(); + }); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Debug/Stats.ts b/hw3/src/Wolfie2D/Debug/Stats.ts new file mode 100644 index 0000000..e9febd4 --- /dev/null +++ b/hw3/src/Wolfie2D/Debug/Stats.ts @@ -0,0 +1,244 @@ +import Color from "../Utils/Color"; + +// @ignorePage +export default class Stats extends Object { + // The fps of the game. + private static prevfps: Array; + private static readonly NUM_POINTS: number = 60; + private static ctx: CanvasRenderingContext2D; + private static CANVAS_WIDTH: number = 300; + private static CANVAS_HEIGHT: number = 300; + private static statsDiv: HTMLDivElement; + private static graphChoices: HTMLSelectElement; + + // Quadtree stats + private static prevClearTimes: Array; + private static SGClearTimes: Array; + private static avgSGClearTime: number; + + private static prevFillTimes: Array; + private static SGFillTimes: Array; + private static avgSGFillTime: number; + + private static prevUpdateTimes: Array; + private static SGUpdateTimes: Array; + private static avgSGUpdateTime: number; + + private static prevQueryTimes: Array; + private static SGQueryTimes: Array; + private static avgSGQueryTime: number; + + static initStats(): void { + let canvas = document.getElementById("stats-canvas"); + canvas.width = this.CANVAS_WIDTH; + canvas.height = this.CANVAS_HEIGHT; + this.ctx = canvas.getContext("2d"); + + this.statsDiv = document.getElementById("stats-display"); + + this.prevfps = new Array(); + + this.prevClearTimes = new Array(); + this.SGClearTimes = new Array(); + this.avgSGClearTime = 0; + + this.prevFillTimes = new Array(); + this.SGFillTimes = new Array(); + this.avgSGFillTime = 0; + + this.prevUpdateTimes = new Array(); + this.SGUpdateTimes = new Array(); + this.avgSGUpdateTime = 0; + + this.prevQueryTimes = new Array(); + this.SGQueryTimes = new Array(); + this.avgSGQueryTime = 0; + + let clearTime = document.createElement("span"); + clearTime.setAttribute("id", "sgclear"); + let fillTime = document.createElement("span"); + fillTime.setAttribute("id", "sgfill"); + let updateTime = document.createElement("span"); + updateTime.setAttribute("id", "sgupdate"); + let queryTime = document.createElement("span"); + queryTime.setAttribute("id", "sgquery"); + let br1 = document.createElement("br"); + let br2 = document.createElement("br"); + let br3 = document.createElement("br"); + + this.statsDiv.append(clearTime, br1, fillTime, br2, updateTime, br3, queryTime); + + this.graphChoices = document.getElementById("chart-option"); + let option1 = document.createElement("option"); + option1.value = "prevfps"; + option1.label = "FPS"; + let option2 = document.createElement("option"); + option2.value = "prevClearTimes"; + option2.label = "Clear Time"; + let option3 = document.createElement("option"); + option3.value = "prevFillTimes"; + option3.label = "Fill time"; + let option4 = document.createElement("option"); + option4.value = "prevUpdateTimes"; + option4.label = "Update time"; + let option5 = document.createElement("option"); + option5.value = "prevQueryTimes"; + option5.label = "Query Time"; + let optionAll = document.createElement("option"); + optionAll.value = "all"; + optionAll.label = "All"; + this.graphChoices.append(option1, option2, option3, option4, option5, optionAll); + } + + static updateFPS(fps: number): void { + this.prevfps.push(fps); + if(this.prevfps.length > Stats.NUM_POINTS){ + this.prevfps.shift(); + } + + if(this.SGClearTimes.length > 0){ + this.prevClearTimes.push(this.avgSGClearTime); + if(this.prevClearTimes.length > this.NUM_POINTS){ + this.prevClearTimes.shift(); + } + } + if(this.SGFillTimes.length > 0){ + this.prevFillTimes.push(this.avgSGFillTime); + if(this.prevFillTimes.length > this.NUM_POINTS){ + this.prevFillTimes.shift(); + } + } + if(this.SGUpdateTimes.length > 0){ + this.prevUpdateTimes.push(this.avgSGUpdateTime); + if(this.prevUpdateTimes.length > this.NUM_POINTS){ + this.prevUpdateTimes.shift(); + } + } + if(this.SGQueryTimes.length > 0){ + this.prevQueryTimes.push(this.avgSGQueryTime); + if(this.prevQueryTimes.length > this.NUM_POINTS){ + this.prevQueryTimes.shift(); + } + } + + this.updateSGStats(); + } + + static log(key: string, data: any): void { + if(key === "sgclear"){ + this.SGClearTimes.push(data); + if(this.SGClearTimes.length > 100){ + this.SGClearTimes.shift(); + } + } else if(key === "sgfill"){ + this.SGFillTimes.push(data); + if(this.SGFillTimes.length > 100){ + this.SGFillTimes.shift(); + } + } else if(key === "sgupdate"){ + this.SGUpdateTimes.push(data); + if(this.SGUpdateTimes.length > 100){ + this.SGUpdateTimes.shift(); + } + } else if(key === "sgquery"){ + this.SGQueryTimes.push(data); + if(this.SGQueryTimes.length > 1000){ + this.SGQueryTimes.shift(); + } + } + + } + + static render(): void { + // Display stats + this.drawCharts(); + } + + static drawCharts(){ + this.ctx.clearRect(0, 0, this.CANVAS_WIDTH, this.CANVAS_HEIGHT); + + let paramString = this.graphChoices.value; + + if(paramString === "prevfps" || paramString === "all"){ + let param = this.prevfps; + let color = Color.BLUE.toString(); + this.drawChart(param, color); + } + if(paramString === "prevClearTimes" || paramString === "all"){ + let param = this.prevClearTimes; + let color = Color.RED.toString(); + this.drawChart(param, color); + } + if(paramString === "prevFillTimes" || paramString === "all"){ + let param = this.prevFillTimes; + let color = Color.GREEN.toString(); + this.drawChart(param, color); + } + if(paramString === "prevUpdateTimes" || paramString === "all"){ + let param = this.prevUpdateTimes; + let color = Color.CYAN.toString(); + this.drawChart(param, color); + } + if(paramString === "prevQueryTimes" || paramString === "all"){ + let param = this.prevQueryTimes; + let color = Color.ORANGE.toString(); + this.drawChart(param, color); + } + } + + static drawChart(param: Array, color: string){ + this.ctx.strokeStyle = Color.BLACK.toString(); + this.ctx.beginPath(); + this.ctx.moveTo(10, 10); + this.ctx.lineTo(10, this.CANVAS_HEIGHT - 10); + this.ctx.closePath(); + this.ctx.stroke(); + this.ctx.beginPath(); + this.ctx.moveTo(10, this.CANVAS_HEIGHT - 10); + this.ctx.lineTo(this.CANVAS_WIDTH - 10, this.CANVAS_HEIGHT - 10); + this.ctx.closePath(); + this.ctx.stroke(); + + let max = Math.max(...param); + let prevX = 10; + let prevY = this.CANVAS_HEIGHT - 10 - param[0]/max*(this.CANVAS_HEIGHT-20); + this.ctx.strokeStyle = color; + + for(let i = 1; i < param.length; i++){ + let fps = param[i]; + let x = 10 + i*(this.CANVAS_WIDTH - 20)/this.NUM_POINTS; + let y = this.CANVAS_HEIGHT - 10 - fps/max*(this.CANVAS_HEIGHT-20) + this.ctx.beginPath(); + this.ctx.moveTo(prevX, prevY); + this.ctx.lineTo(x, y); + this.ctx.closePath(); + this.ctx.stroke(); + + prevX = x; + prevY = y; + } + } + + static updateSGStats(){ + if(this.SGClearTimes.length > 0){ + this.avgSGClearTime = this.SGClearTimes.reduce((acc, val) => acc + val)/this.SGClearTimes.length; + } + + if(this.SGFillTimes.length > 0){ + this.avgSGFillTime = this.SGFillTimes.reduce((acc, val) => acc + val)/this.SGFillTimes.length; + } + + if(this.SGUpdateTimes.length > 0){ + this.avgSGUpdateTime = this.SGUpdateTimes.reduce((acc, val) => acc + val)/this.SGUpdateTimes.length; + } + + if(this.SGQueryTimes.length > 0){ + this.avgSGQueryTime = this.SGQueryTimes.reduce((acc, val) => acc + val)/this.SGQueryTimes.length; + } + + document.getElementById("sgclear").innerHTML = "Avg SG clear time: " + this.avgSGClearTime; + document.getElementById("sgfill").innerHTML = "Avg SG fill time: " + this.avgSGFillTime; + document.getElementById("sgupdate").innerHTML = "Avg SG update time: " + this.avgSGUpdateTime; + document.getElementById("sgquery").innerHTML = "Avg SG query time: " + this.avgSGQueryTime; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Events/Emitter.ts b/hw3/src/Wolfie2D/Events/Emitter.ts new file mode 100644 index 0000000..ce6abc5 --- /dev/null +++ b/hw3/src/Wolfie2D/Events/Emitter.ts @@ -0,0 +1,26 @@ +import Map from "../DataTypes/Map"; +import EventQueue from "./EventQueue"; +import GameEvent from "./GameEvent"; + +/** + * An event emitter object other systems can use to hook into the EventQueue. + * Provides an easy interface for firing off events. + */ +export default class Emitter { + /** A reference to the EventQueue */ + private eventQueue: EventQueue; + + /** Creates a new Emitter */ + constructor(){ + this.eventQueue = EventQueue.getInstance(); + } + + /** + * Emit and event of type eventType with the data packet data + * @param eventType The name of the event to fire off + * @param data A @reference[Map] or record containing any data about the event + */ + fireEvent(eventType: string, data: Map | Record = null): void { + this.eventQueue.addEvent(new GameEvent(eventType, data)); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Events/EventQueue.ts b/hw3/src/Wolfie2D/Events/EventQueue.ts new file mode 100644 index 0000000..f6718dc --- /dev/null +++ b/hw3/src/Wolfie2D/Events/EventQueue.ts @@ -0,0 +1,125 @@ +import Queue from "../DataTypes/Queue"; +import Map from "../DataTypes/Map"; +import GameEvent from "./GameEvent"; +import Receiver from "./Receiver"; +import { GameEventType } from "./GameEventType"; + +/** + * The main event system of the game engine. + * Events are sent to the EventQueue, which handles distribution to any systems that are listening for those events. + * This allows for handling of input without having classes directly hook into javascript event handles, + * and allows otherwise separate classes to communicate with each other cleanly, such as a Player object + * requesting a sound be played by the audio system. + * + * The distribution of @reference[GameEvent]s happens as follows: + * + * Events are recieved throughout a frame and are queued up by the EventQueue. + * At the beginning of the next frame, events are sent out to any receivers that are hooked into the event type. + * @reference[Receiver]s are then free to process events as they see fit. + * + * Overall, the EventQueue can be considered as something similar to an email server, + * and the @reference[Receiver]s can be considered as the client inboxes. + * + * See @link(Game Programming Patterns)(https://gameprogrammingpatterns.com/event-queue.html) for more discussion on EventQueues + */ +export default class EventQueue { + private static instance: EventQueue = null; + + /** The maximum number of events visible */ + private readonly MAX_SIZE: number; + + /** The actual queue of events */ + private q: Queue; + + /** The map of receivers registered for an event name */ + private receivers: Map>; + + private constructor(){ + this.MAX_SIZE = 100; + this.q = new Queue(this.MAX_SIZE); + this.receivers = new Map>(); + } + + /** Retrieves the instance of the Singleton EventQueue */ + static getInstance(): EventQueue { + if(this.instance === null){ + this.instance = new EventQueue(); + } + + return this.instance; + } + + /** Adds an event to the EventQueue. + * This is exposed to the rest of the game engine through the @reference[Emitter] class */ + addEvent(event: GameEvent): void { + this.q.enqueue(event); + } + + /** + * Associates a receiver with a type of event. Every time this event appears in the future, + * it will be given to the receiver (and any others watching that type). + * This is exposed to the rest of the game engine through the @reference[Receiver] class + * @param receiver The event receiver + * @param type The type or types of events to subscribe to + */ + subscribe(receiver: Receiver, type: string | Array): void { + if(type instanceof Array){ + // If it is an array, subscribe to all event types + for(let t of type){ + this.addListener(receiver, t); + } + } else { + this.addListener(receiver, type); + } + } + + /** + * Unsubscribes the specified receiver from all events, or from whatever events are provided + * @param receiver The receiver to unsubscribe + * @param keys The events to unsubscribe from. If none are provided, unsubscribe from all + */ + unsubscribe(receiver: Receiver, ...events: Array): void { + this.receivers.forEach(eventName => { + // If keys were provided, only continue if this key is one of them + if(events.length > 0 && events.indexOf(eventName) === -1) return; + + // Find the index of our receiver for this key + let index = this.receivers.get(eventName).indexOf(receiver); + + // If an index was found, remove the receiver + if(index !== -1){ + this.receivers.get(eventName).splice(index, 1); + } + }); + } + + // Associate the receiver and the type + private addListener(receiver: Receiver, type: string): void { + if(this.receivers.has(type)){ + this.receivers.get(type).push(receiver); + } else { + this.receivers.add(type, [receiver]); + } + } + + update(deltaT: number): void { + while(this.q.hasItems()){ + // Retrieve each event + let event = this.q.dequeue(); + + // If a receiver has this event type, send it the event + if(this.receivers.has(event.type)){ + for(let receiver of this.receivers.get(event.type)){ + receiver.receive(event); + } + } + + // If a receiver is subscribed to all events, send it the event + if(this.receivers.has(GameEventType.ALL)){ + for(let receiver of this.receivers.get(GameEventType.ALL)){ + receiver.receive(event); + } + } + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Events/GameEvent.ts b/hw3/src/Wolfie2D/Events/GameEvent.ts new file mode 100644 index 0000000..93eaa21 --- /dev/null +++ b/hw3/src/Wolfie2D/Events/GameEvent.ts @@ -0,0 +1,54 @@ +import Map from "../DataTypes/Map" + +/** + * A representation of an in-game event that is passed through the @reference[EventQueue] + */ +export default class GameEvent { + /** The type of the event */ + public type: string; + /** The data contained by the event */ + public data: Map; + /** The time of the event in ms */ + public time: number; + + /** + * Creates a new GameEvent. + * This is handled implicitly through the @reference[Emitter] class + * @param type The type of the GameEvent + * @param data The data contained by the GameEvent + */ + constructor(type: string, data: Map | Record = null) { + // Parse the game event data + if (data === null) { + this.data = new Map(); + } else if (!(data instanceof Map)){ + // data is a raw object, unpack + this.data = new Map(); + for(let key in data){ + this.data.add(key, data[key]); + } + } else { + this.data = data; + } + + this.type = type; + this.time = Date.now(); + } + + /** + * Checks the type of the GameEvent + * @param type The type to check + * @returns True if the GameEvent is the specified type, false otherwise. + */ + isType(type: string): boolean { + return this.type === type; + } + + /** + * Returns this GameEvent as a string + * @returns The string representation of the GameEvent + */ + toString(): string { + return this.type + ": @" + this.time; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Events/GameEventType.ts b/hw3/src/Wolfie2D/Events/GameEventType.ts new file mode 100644 index 0000000..7f83505 --- /dev/null +++ b/hw3/src/Wolfie2D/Events/GameEventType.ts @@ -0,0 +1,91 @@ +// @ignorePage + +export enum GameEventType { + /** + * Mouse Down event. Has data: {position: Vec2 - Mouse Position} + */ + MOUSE_DOWN = "mouse_down", + /** + * Mouse Up event. Has data: {position: Vec2 - Mouse Position} + */ + MOUSE_UP = "mouse_up", + /** + * Mouse Move event. Has data: {position: Vec2 - Mouse Position} + */ + MOUSE_MOVE = "mouse_move", + + /** + * Key Down event. Has data: {key: string - The key that is down} + */ + KEY_DOWN = "key_down", + + /** + * Key Up event. Has data: {key: string - The key that is up} + */ + KEY_UP = "key_up", + + /** + * Canvas Blur event. Has data: {} + */ + CANVAS_BLUR = "canvas_blur", + + /** + * Mouse wheel up event. Has data: {} + */ + WHEEL_UP = "wheel_up", + + /** + * Mouse wheel down event. Has data: {} + */ + WHEEL_DOWN = "wheel_down", + + /** + * Start Recording event. Has data: {} + */ + START_RECORDING = "start_recording", + + /** + * Stop Recording event. Has data: {} + */ + STOP_RECORDING = "stop_recording", + + /** + * Play Recording event. Has data: {} + */ + PLAY_RECORDING = "play_recording", + + /** + * Play Sound event. Has data: {key: string, loop: boolean, holdReference: boolean } + */ + PLAY_SOUND = "play_sound", + + /** + * Play Sound event. Has data: {key: string} + */ + STOP_SOUND = "stop_sound", + + /** + * Play Sound event. Has data: {key: string, loop: boolean, holdReference: boolean, channel: AudioChannelType } + */ + PLAY_SFX = "play_sfx", + + /** + * Play Sound event. Has data: {key: string, loop: boolean, holdReference: boolean } + */ + PLAY_MUSIC = "play_music", + + /** + * Mute audio channel event. Has data: {channel: AudioChannelType} + */ + MUTE_CHANNEL = "mute_channel", + + /** + * Unmute audio channel event. Has data: {channel: AudioChannelType} + */ + UNMUTE_CHANNEL = "unmute_channel", + + /** + * Encompasses all event types. Used for receivers only. + */ + ALL = "all", +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Events/Receiver.ts b/hw3/src/Wolfie2D/Events/Receiver.ts new file mode 100644 index 0000000..3b3f680 --- /dev/null +++ b/hw3/src/Wolfie2D/Events/Receiver.ts @@ -0,0 +1,77 @@ +import Queue from "../DataTypes/Queue"; +import EventQueue from "./EventQueue"; +import GameEvent from "./GameEvent"; + +/** + * Receives subscribed events from the EventQueue. + */ +export default class Receiver { + /** The maximum number of events this Receiver can hold at one time */ + readonly MAX_SIZE: number; + + /** The inbox of the Receiver */ + private q: Queue; + + /** Creates a new Receiver */ + constructor(){ + this.MAX_SIZE = 100; + this.q = new Queue(this.MAX_SIZE); + } + + destroy(){ + EventQueue.getInstance().unsubscribe(this); + } + + /** + * Adds these types of events to this receiver's queue every update. + * @param eventTypes The types of events this receiver will be subscribed to + */ + subscribe(eventTypes: string | Array): void { + EventQueue.getInstance().subscribe(this, eventTypes); + this.q.clear(); + } + + /** + * Adds an event to the queue of this reciever. This is used by the @reference[EventQueue] to distribute events + * @param event The event to receive + */ + receive(event: GameEvent): void { + try{ + this.q.enqueue(event); + } catch(e){ + console.warn("Receiver overflow for event " + event.toString()); + throw e; + } + } + + /** + * Retrieves the next event from the receiver's queue + * @returns The next GameEvent + */ + getNextEvent(): GameEvent { + return this.q.dequeue(); + } + + /** + * Looks at the next event in the receiver's queue, but doesn't remove it from the queue + * @returns The next GameEvent + */ + peekNextEvent(): GameEvent { + return this.q.peekNext() + } + + /** + * Returns true if the receiver has any events in its queue + * @returns True if the receiver has another event, false otherwise + */ + hasNextEvent(): boolean { + return this.q.hasItems(); + } + + /** + * Ignore all events this frame + */ + ignoreEvents(): void { + this.q.clear(); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Input/Input.ts b/hw3/src/Wolfie2D/Input/Input.ts new file mode 100644 index 0000000..b9c7720 --- /dev/null +++ b/hw3/src/Wolfie2D/Input/Input.ts @@ -0,0 +1,322 @@ +import Receiver from "../Events/Receiver"; +import Map from "../DataTypes/Map"; +import Vec2 from "../DataTypes/Vec2"; +import EventQueue from "../Events/EventQueue"; +import Viewport from "../SceneGraph/Viewport"; +import GameEvent from "../Events/GameEvent"; +import { GameEventType } from "../Events/GameEventType"; + +/** + * Receives input events from the @reference[EventQueue] and allows for easy access of information about input by other systems + */ +export default class Input { + private static mousePressed: boolean; + private static mouseJustPressed: boolean; + + private static keyJustPressed: Map; + private static keyPressed: Map; + + private static mousePosition: Vec2; + private static mousePressPosition: Vec2; + + private static scrollDirection: number; + private static justScrolled: boolean; + + private static eventQueue: EventQueue; + private static receiver: Receiver; + private static viewport: Viewport; + + private static keyMap: Map>; + + private static keysDisabled: boolean; + private static mouseDisabled: boolean; + + /** + * Initializes the Input object + * @param viewport A reference to the viewport of the game + */ + static initialize(viewport: Viewport, keyMap: Array>){ + Input.viewport = viewport; + Input.mousePressed = false; + Input.mouseJustPressed = false; + Input.receiver = new Receiver(); + Input.keyJustPressed = new Map(); + Input.keyPressed = new Map(); + Input.mousePosition = new Vec2(0, 0); + Input.mousePressPosition = new Vec2(0, 0); + Input.scrollDirection = 0; + Input.justScrolled = false; + Input.keysDisabled = false; + Input.mouseDisabled = false; + + // Initialize the keymap + Input.keyMap = new Map(); + + // Add all keys to the keymap + for(let entry in keyMap){ + let name = keyMap[entry].name; + let keys = keyMap[entry].keys; + Input.keyMap.add(name, keys); + } + + Input.eventQueue = EventQueue.getInstance(); + // Subscribe to all input events + Input.eventQueue.subscribe(Input.receiver, [GameEventType.MOUSE_DOWN, GameEventType.MOUSE_UP, GameEventType.MOUSE_MOVE, + GameEventType.KEY_DOWN, GameEventType.KEY_UP, GameEventType.CANVAS_BLUR, GameEventType.WHEEL_UP, GameEventType.WHEEL_DOWN]); + } + + static update(deltaT: number): void { + // Reset the justPressed values to false + Input.mouseJustPressed = false; + Input.keyJustPressed.forEach((key: string) => Input.keyJustPressed.set(key, false)); + Input.justScrolled = false; + Input.scrollDirection = 0; + + while(Input.receiver.hasNextEvent()){ + let event = Input.receiver.getNextEvent(); + + // Handle each event type + if(event.type === GameEventType.MOUSE_DOWN){ + Input.mouseJustPressed = true; + Input.mousePressed = true; + Input.mousePressPosition = event.data.get("position"); + } + + if(event.type === GameEventType.MOUSE_UP){ + Input.mousePressed = false; + } + + if(event.type === GameEventType.MOUSE_MOVE){ + Input.mousePosition = event.data.get("position"); + } + + if(event.type === GameEventType.KEY_DOWN){ + let key = event.data.get("key"); + // Handle space bar + if(key === " "){ + key = "space"; + } + if(!Input.keyPressed.get(key)){ + Input.keyJustPressed.set(key, true); + Input.keyPressed.set(key, true); + } + } + + if(event.type === GameEventType.KEY_UP){ + let key = event.data.get("key"); + // Handle space bar + if(key === " "){ + key = "space"; + } + Input.keyPressed.set(key, false); + } + + if(event.type === GameEventType.CANVAS_BLUR){ + Input.clearKeyPresses() + } + + if(event.type === GameEventType.WHEEL_UP){ + Input.scrollDirection = -1; + Input.justScrolled = true; + } else if(event.type === GameEventType.WHEEL_DOWN){ + Input.scrollDirection = 1; + Input.justScrolled = true; + } + } + } + + private static clearKeyPresses(): void { + Input.keyJustPressed.forEach((key: string) => Input.keyJustPressed.set(key, false)); + Input.keyPressed.forEach((key: string) => Input.keyPressed.set(key, false)); + } + + /** + * Returns whether or not a key was newly pressed Input frame. + * If the key is still pressed from last frame and wasn't re-pressed, Input will return false. + * @param key The key + * @returns True if the key was just pressed, false otherwise + */ + static isKeyJustPressed(key: string): boolean { + if(Input.keysDisabled) return false; + + if(Input.keyJustPressed.has(key)){ + return Input.keyJustPressed.get(key) + } else { + return false; + } + } + + /** + * Returns an array of all of the keys that are newly pressed Input frame. + * If a key is still pressed from last frame and wasn't re-pressed, it will not be in Input list. + * @returns An array of all of the newly pressed keys. + */ + static getKeysJustPressed(): Array { + if(Input.keysDisabled) return []; + + let keys = Array(); + Input.keyJustPressed.forEach(key => { + if(Input.keyJustPressed.get(key)){ + keys.push(key); + } + }); + return keys; + } + + /** + * Returns whether or not a key is being pressed. + * @param key The key + * @returns True if the key is currently pressed, false otherwise + */ + static isKeyPressed(key: string): boolean { + if(Input.keysDisabled) return false; + + if(Input.keyPressed.has(key)){ + return Input.keyPressed.get(key) + } else { + return false; + } + } + + /** + * Changes the binding of an input name to keys + * @param inputName The name of the input + * @param keys The corresponding keys + */ + static changeKeyBinding(inputName: string, keys: Array): void { + Input.keyMap.set(inputName, keys); + } + + /** + * Clears all key bindings + */ + static clearAllKeyBindings(): void { + Input.keyMap.clear(); + } + + /** + * Returns whether or not an input was just pressed this frame + * @param inputName The name of the input + * @returns True if the input was just pressed, false otherwise + */ + static isJustPressed(inputName: string): boolean { + if(Input.keysDisabled) return false; + + if(Input.keyMap.has(inputName)){ + const keys = Input.keyMap.get(inputName); + let justPressed = false; + + for(let key of keys){ + justPressed = justPressed || Input.isKeyJustPressed(key); + } + + return justPressed; + } else { + return false; + } + } + + /** + * Returns whether or not an input is currently pressed + * @param inputName The name of the input + * @returns True if the input is pressed, false otherwise + */ + static isPressed(inputName: string): boolean { + if(Input.keysDisabled) return false; + + if(Input.keyMap.has(inputName)){ + const keys = Input.keyMap.get(inputName); + let pressed = false; + + for(let key of keys){ + pressed = pressed || Input.isKeyPressed(key); + } + + return pressed; + } else { + return false; + } + } + + /** + * Returns whether or not the mouse was newly pressed Input frame + * @returns True if the mouse was just pressed, false otherwise + */ + static isMouseJustPressed(): boolean { + return Input.mouseJustPressed && !Input.mouseDisabled; + } + + /** + * Returns whether or not the mouse is currently pressed + * @returns True if the mouse is currently pressed, false otherwise + */ + static isMousePressed(): boolean { + return Input.mousePressed && !Input.mouseDisabled; + } + + /** + * Returns whether the user scrolled or not + * @returns True if the user just scrolled Input frame, false otherwise + */ + static didJustScroll(): boolean { + return Input.justScrolled && !Input.mouseDisabled; + } + + /** + * Gets the direction of the scroll + * @returns -1 if the user scrolled up, 1 if they scrolled down + */ + static getScrollDirection(): number { + return Input.scrollDirection; + } + + /** + * Gets the position of the player's mouse + * @returns The mouse position stored as a Vec2 + */ + static getMousePosition(): Vec2 { + return Input.mousePosition.scaled(1/this.viewport.getZoomLevel()); + } + + /** + * Gets the position of the player's mouse in the game world, + * taking into consideration the scrolling of the viewport + * @returns The mouse position stored as a Vec2 + */ + static getGlobalMousePosition(): Vec2 { + return Input.mousePosition.clone().scale(1/this.viewport.getZoomLevel()).add(Input.viewport.getOrigin()); + } + + /** + * Gets the position of the last mouse press + * @returns The mouse position stored as a Vec2 + */ + static getMousePressPosition(): Vec2 { + return Input.mousePressPosition; + } + + /** + * Gets the position of the last mouse press in the game world, + * taking into consideration the scrolling of the viewport + * @returns The mouse position stored as a Vec2 + */ + static getGlobalMousePressPosition(): Vec2 { + return Input.mousePressPosition.clone().add(Input.viewport.getOrigin()); + } + + /** + * Disables all keypress and mouse click inputs + */ + static disableInput(): void { + Input.keysDisabled = true; + Input.mouseDisabled = true; + } + + /** + * Enables all keypress and mouse click inputs + */ + static enableInput(): void { + Input.keysDisabled = false; + Input.mouseDisabled = false; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Input/InputHandler.ts b/hw3/src/Wolfie2D/Input/InputHandler.ts new file mode 100644 index 0000000..4d34811 --- /dev/null +++ b/hw3/src/Wolfie2D/Input/InputHandler.ts @@ -0,0 +1,93 @@ +import EventQueue from "../Events/EventQueue"; +import Vec2 from "../DataTypes/Vec2"; +import GameEvent from "../Events/GameEvent"; +import { GameEventType } from "../Events/GameEventType"; + +/** + * Handles communication with the web browser to receive asynchronous events and send them to the @reference[EventQueue] + */ +export default class InputHandler { + private eventQueue: EventQueue; + + /** + * Creates a new InputHandler + * @param canvas The game canvas + */ + constructor(canvas: HTMLCanvasElement){ + this.eventQueue = EventQueue.getInstance(); + + canvas.onmousedown = (event) => this.handleMouseDown(event, canvas); + canvas.onmouseup = (event) => this.handleMouseUp(event, canvas); + canvas.oncontextmenu = this.handleContextMenu; + canvas.onmousemove = (event) => this.handleMouseMove(event, canvas); + document.onkeydown = this.handleKeyDown; + document.onkeyup = this.handleKeyUp; + document.onblur = this.handleBlur; + document.oncontextmenu = this.handleBlur; + document.onwheel = this.handleWheel; + } + + private handleMouseDown = (event: MouseEvent, canvas: HTMLCanvasElement): void => { + let pos = this.getMousePosition(event, canvas); + let gameEvent = new GameEvent(GameEventType.MOUSE_DOWN, {position: pos}); + this.eventQueue.addEvent(gameEvent); + } + + private handleMouseUp = (event: MouseEvent, canvas: HTMLCanvasElement): void => { + let pos = this.getMousePosition(event, canvas); + let gameEvent = new GameEvent(GameEventType.MOUSE_UP, {position: pos}); + this.eventQueue.addEvent(gameEvent); + } + + private handleMouseMove = (event: MouseEvent, canvas: HTMLCanvasElement): void => { + let pos = this.getMousePosition(event, canvas); + let gameEvent = new GameEvent(GameEventType.MOUSE_MOVE, {position: pos}); + this.eventQueue.addEvent(gameEvent); + } + + private handleKeyDown = (event: KeyboardEvent): void => { + let key = this.getKey(event); + let gameEvent = new GameEvent(GameEventType.KEY_DOWN, {key: key}); + this.eventQueue.addEvent(gameEvent); + } + + private handleKeyUp = (event: KeyboardEvent): void => { + let key = this.getKey(event); + let gameEvent = new GameEvent(GameEventType.KEY_UP, {key: key}); + this.eventQueue.addEvent(gameEvent); + } + + private handleBlur = (event: Event): void => { + let gameEvent = new GameEvent(GameEventType.CANVAS_BLUR, {}); + this.eventQueue.addEvent(gameEvent); + } + + private handleContextMenu = (event: Event): void => { + event.preventDefault(); + event.stopPropagation(); + } + + private handleWheel = (event: WheelEvent): void => { + event.preventDefault(); + event.stopPropagation(); + + let gameEvent: GameEvent; + if(event.deltaY < 0){ + gameEvent = new GameEvent(GameEventType.WHEEL_UP, {}); + } else { + gameEvent = new GameEvent(GameEventType.WHEEL_DOWN, {}); + } + this.eventQueue.addEvent(gameEvent); + } + + private getKey(keyEvent: KeyboardEvent){ + return keyEvent.key.toLowerCase(); + } + + private getMousePosition(mouseEvent: MouseEvent, canvas: HTMLCanvasElement): Vec2 { + let rect = canvas.getBoundingClientRect(); + let x = mouseEvent.clientX - rect.left; + let y = mouseEvent.clientY - rect.top; + return new Vec2(x, y); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Loop/EnvironmentInitializer.ts b/hw3/src/Wolfie2D/Loop/EnvironmentInitializer.ts new file mode 100644 index 0000000..ff73726 --- /dev/null +++ b/hw3/src/Wolfie2D/Loop/EnvironmentInitializer.ts @@ -0,0 +1,47 @@ +import {} from "../../index"; // This import allows us to modify the CanvasRenderingContext2D to add extra functionality +// @ignorePage + +/** + * Sets up the environment of the game engine + */ +export default class EnvironmentInitializer { + static setup(){ + CanvasRenderingContext2D.prototype.roundedRect = function(x: number, y: number, w: number, h: number, r: number): void { + // Clamp the radius between 0 and the min of the width or height + if(r < 0) r = 0; + if(r > Math.min(w, h)) r = Math.min(w, h); + + // Draw the rounded rect + this.beginPath(); + + // Top + this.moveTo(x + r, y); + this.lineTo(x + w - r, y); + this.arcTo(x + w, y, x + w, y + r, r); + + // Right + this.lineTo(x + w, y + h - r); + this.arcTo(x + w, y + h, x + w - r, y + h, r); + + // Bottom + this.lineTo(x + r, y + h); + this.arcTo(x, y + h, x, y + h - r, r); + + // Left + this.lineTo(x, y + r); + this.arcTo(x, y, x + r, y, r) + + this.closePath(); + } + + CanvasRenderingContext2D.prototype.strokeRoundedRect = function(x, y, w, h, r){ + this.roundedRect(x, y, w, h, r); + this.stroke(); + } + + CanvasRenderingContext2D.prototype.fillRoundedRect = function(x, y, w, h, r){ + this.roundedRect(x, y, w, h, r); + this.fill(); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts b/hw3/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts new file mode 100644 index 0000000..49abe5c --- /dev/null +++ b/hw3/src/Wolfie2D/Loop/FixedUpdateGameLoop.ts @@ -0,0 +1,235 @@ +import GameLoop from "./GameLoop"; +import Debug from "../Debug/Debug"; +import Stats from "../Debug/Stats"; + +/** + * A game loop with a fixed update time and a variable render time. + * Every frame, the game updates until all time since the last frame has been processed. + * If too much time has passed, such as if the last update was too slow, + * or if the browser was put into the background, the loop will panic and discard time. + * A render happens at the end of every frame. This happens as fast as possible unless specified. + * A loop of this type allows for deterministic behavior - No matter what the frame rate is, the update should behave the same, + * as it is occuring in a fixed interval. + */ +export default class FixedUpdateGameLoop extends GameLoop { + + /** The max allowed update fps.*/ + private maxUpdateFPS: number; + + /** The timestep for each update. This is the deltaT passed to update calls. */ + private updateTimestep: number; + + /** The amount of time we are yet to simulate. */ + private frameDelta: number; + + /** The time when the last frame was drawn. */ + private lastFrameTime: number; + + /** The minimum time we want to wait between game frames. */ + private minFrameDelay: number; + + /** The current frame of the game. */ + private frame: number; + + /** The actual fps of the game. */ + private fps: number; + + /** The time between fps measurement updates. */ + private fpsUpdateInterval: number; + + /** The time of the last fps update. */ + private lastFpsUpdate: number; + + /** The number of frames since the last fps update was done. */ + private framesSinceLastFpsUpdate: number; + + /** The status of whether or not the game loop has started. */ + private started: boolean; + + /** The status of whether or not the game loop is paused */ + private paused: boolean; + + /** The status of whether or not the game loop is currently running. */ + private running: boolean; + + /** The number of update steps this iteration of the game loop. */ + private numUpdateSteps: number; + + constructor() { + super(); + this.maxUpdateFPS = 60; + this.updateTimestep = Math.floor(1000/this.maxUpdateFPS); + this.frameDelta = 0; + this.lastFrameTime = 0; + this.minFrameDelay = 0; + this.frame = 0; + this.fps = this.maxUpdateFPS; // Initialize the fps to the max allowed fps + this.fpsUpdateInterval = 1000; + this.lastFpsUpdate = 0; + this.framesSinceLastFpsUpdate = 0; + this.started = false; + this.paused = false; + this.running = false; + this.numUpdateSteps = 0; + } + + getFPS(): number { + return 0; + } + + /** + * Updates the frame count and sum of time for the framerate of the game + * @param timestep The current time in ms + */ + protected updateFPS(timestamp: number): void { + this.fps = 0.9 * this.framesSinceLastFpsUpdate * 1000 / (timestamp - this.lastFpsUpdate) +(1 - 0.9) * this.fps; + this.lastFpsUpdate = timestamp; + this.framesSinceLastFpsUpdate = 0; + + Debug.log("fps", "FPS: " + this.fps.toFixed(1)); + Stats.updateFPS(this.fps); + } + + /** + * Changes the maximum allowed physics framerate of the game + * @param initMax The max framerate + */ + setMaxUpdateFPS(initMax: number): void { + this.maxUpdateFPS = initMax; + this.updateTimestep = Math.floor(1000/this.maxUpdateFPS); + } + + /** + * Sets the maximum rendering framerate + * @param maxFPS The max framerate + */ + setMaxFPS(maxFPS: number): void { + this.minFrameDelay = 1000/maxFPS; + } + + /** + * This function is called when the game loop panics, i.e. it tries to process too much time in an entire frame. + * This will reset the amount of time back to zero. + * @returns The amount of time we are discarding from processing. + */ + resetFrameDelta() : number { + let oldFrameDelta = this.frameDelta; + this.frameDelta = 0; + return oldFrameDelta; + } + + /** + * Starts up the game loop and calls the first requestAnimationFrame + */ + start(): void { + if(!this.started){ + this.started = true; + + window.requestAnimationFrame((timestamp) => this.doFirstFrame(timestamp)); + } + } + + pause(): void { + this.paused = true; + } + + resume(): void { + this.paused = false; + } + + /** + * The first game frame - initializes the first frame time and begins the render + * @param timestamp The current time in ms + */ + protected doFirstFrame(timestamp: number): void { + this.running = true; + + this._doRender(); + + this.lastFrameTime = timestamp; + this.lastFpsUpdate = timestamp; + this.framesSinceLastFpsUpdate = 0; + + window.requestAnimationFrame((t) => this.doFrame(t)); + } + + /** + * Handles any processing that needs to be done at the start of the frame + * @param timestamp The time of the frame in ms + */ + protected startFrame(timestamp: number): void { + // Update the amount of time we need our update to process + this.frameDelta += timestamp - this.lastFrameTime; + + // Set the new time of the last frame + this.lastFrameTime = timestamp; + + // Update the estimate of the framerate + if(timestamp > this.lastFpsUpdate + this.fpsUpdateInterval){ + this.updateFPS(timestamp); + } + + // Increment the number of frames + this.frame++; + this.framesSinceLastFpsUpdate++; + } + + /** + * The main loop of the game. Updates until the current time is reached. Renders once + * @param timestamp The current time in ms + */ + protected doFrame = (timestamp: number): void => { + // If a pause was executed, stop doing the loop. + if(this.paused){ + return; + } + + // Request animation frame to prepare for another update or render + window.requestAnimationFrame((t) => this.doFrame(t)); + + // If we are trying to render too soon, do nothing. + if(timestamp < this.lastFrameTime + this.minFrameDelay){ + return; + } + + // A frame is actually happening + this.startFrame(timestamp); + + // Update while there is still time to make up. If we do too many update steps, panic and exit the loop. + this.numUpdateSteps = 0; + let panic = false; + + while(this.frameDelta >= this.updateTimestep){ + // Do an update + this._doUpdate(this.updateTimestep/1000); + + // Remove the update step time from the time we have to process + this.frameDelta -= this.updateTimestep; + + // Increment steps and check if we've done too many + this.numUpdateSteps++; + if(this.numUpdateSteps > 100){ + panic = true; + break; + } + } + + // Updates are done, render + this._doRender(); + + // Wrap up the frame + this.finishFrame(panic); + } + + /** + * Wraps up the frame and handles the panic state if there is one + * @param panic Whether or not the loop panicked + */ + protected finishFrame(panic: boolean): void { + if(panic) { + var discardedTime = Math.round(this.resetFrameDelta()); + console.warn('Main loop panicked, probably because the browser tab was put in the background. Discarding ' + discardedTime + 'ms'); + } + } + +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Loop/Game.ts b/hw3/src/Wolfie2D/Loop/Game.ts new file mode 100644 index 0000000..0014bdb --- /dev/null +++ b/hw3/src/Wolfie2D/Loop/Game.ts @@ -0,0 +1,214 @@ +import EventQueue from "../Events/EventQueue"; +import Input from "../Input/Input"; +import InputHandler from "../Input/InputHandler"; +import Recorder from "../Playback/Recorder"; +import Debug from "../Debug/Debug"; +import ResourceManager from "../ResourceManager/ResourceManager"; +import Viewport from "../SceneGraph/Viewport"; +import SceneManager from "../Scene/SceneManager"; +import AudioManager from "../Sound/AudioManager"; +import Stats from "../Debug/Stats"; +import RenderingManager from "../Rendering/RenderingManager"; +import CanvasRenderer from "../Rendering/CanvasRenderer"; +import Color from "../Utils/Color"; +import GameOptions from "./GameOptions"; +import GameLoop from "./GameLoop"; +import FixedUpdateGameLoop from "./FixedUpdateGameLoop"; +import EnvironmentInitializer from "./EnvironmentInitializer"; +import Vec2 from "../DataTypes/Vec2"; +import RegistryManager from "../Registry/RegistryManager"; +import WebGLRenderer from "../Rendering/WebGLRenderer"; +import Scene from "../Scene/Scene"; + +/** + * The main loop of the game engine. + * Handles the update order, and initializes all subsystems. + * The Game manages the update cycle, and requests animation frames to render to the browser. + */ +export default class Game { + gameOptions: GameOptions; + private showDebug: boolean; + private showStats: boolean; + + // The game loop + private loop: GameLoop; + + // Game canvas and its width and height + readonly GAME_CANVAS: HTMLCanvasElement; + readonly DEBUG_CANVAS: HTMLCanvasElement; + readonly WIDTH: number; + readonly HEIGHT: number; + private viewport: Viewport; + private ctx: CanvasRenderingContext2D | WebGLRenderingContext; + private clearColor: Color; + + // All of the necessary subsystems that need to run here + private eventQueue: EventQueue; + private inputHandler: InputHandler; + private recorder: Recorder; + private resourceManager: ResourceManager; + private sceneManager: SceneManager; + private audioManager: AudioManager; + private renderingManager: RenderingManager; + + /** + * Creates a new Game + * @param options The options for Game initialization + */ + constructor(options?: Record){ + // Before anything else, build the environment + EnvironmentInitializer.setup(); + + // Typecast the config object to a GameConfig object + this.gameOptions = GameOptions.parse(options); + + this.showDebug = this.gameOptions.showDebug; + this.showStats = this.gameOptions.showStats; + + // Create an instance of a game loop + this.loop = new FixedUpdateGameLoop(); + + // Get the game canvas and give it a background color + this.GAME_CANVAS = document.getElementById("game-canvas"); + this.DEBUG_CANVAS = document.getElementById("debug-canvas"); + + // Give the canvas a size and get the rendering context + this.WIDTH = this.gameOptions.canvasSize.x; + this.HEIGHT = this.gameOptions.canvasSize.y; + + // This step MUST happen before the resource manager does anything + if(this.gameOptions.useWebGL){ + this.renderingManager = new WebGLRenderer(); + } else { + this.renderingManager = new CanvasRenderer(); + } + this.initializeGameWindow(); + this.ctx = this.renderingManager.initializeCanvas(this.GAME_CANVAS, this.WIDTH, this.HEIGHT); + this.clearColor = new Color(this.gameOptions.clearColor.r, this.gameOptions.clearColor.g, this.gameOptions.clearColor.b); + + // Initialize debugging and stats + Debug.initializeDebugCanvas(this.DEBUG_CANVAS, this.WIDTH, this.HEIGHT); + Stats.initStats(); + + if(this.gameOptions.showStats) { + // Find the stats output and make it no longer hidden + document.getElementById("stats").hidden = false; + } + + // Size the viewport to the game canvas + const canvasSize = new Vec2(this.WIDTH, this.HEIGHT); + this.viewport = new Viewport(canvasSize, this.gameOptions.zoomLevel); + + // Initialize all necessary game subsystems + this.eventQueue = EventQueue.getInstance(); + this.inputHandler = new InputHandler(this.GAME_CANVAS); + Input.initialize(this.viewport, this.gameOptions.inputs); + this.recorder = new Recorder(); + this.resourceManager = ResourceManager.getInstance(); + this.sceneManager = new SceneManager(this.viewport, this.renderingManager); + this.audioManager = AudioManager.getInstance(); + } + + /** + * Set up the game window that holds the canvases + */ + private initializeGameWindow(): void { + const gameWindow = document.getElementById("game-window"); + + // Set the height of the game window + gameWindow.style.width = this.WIDTH + "px"; + gameWindow.style.height = this.HEIGHT + "px"; + } + + /** + * Retreives the SceneManager from the Game + * @returns The SceneManager + */ + getSceneManager(): SceneManager { + return this.sceneManager; + } + + /** + * Starts the game + */ + start(InitialScene: new (...args: any) => Scene, options: Record): void { + // Set the update function of the loop + this.loop.doUpdate = (deltaT: number) => this.update(deltaT); + + // Set the render function of the loop + this.loop.doRender = () => this.render(); + + // Preload registry items + RegistryManager.preload(); + + // Load the items with the resource manager + this.resourceManager.loadResourcesFromQueue(() => { + // When we're done loading, start the loop + console.log("Finished Preload - loading first scene"); + this.sceneManager.changeToScene(InitialScene, {}, options); + this.loop.start(); + }); + } + + /** + * Updates all necessary subsystems of the game. Defers scene updates to the sceneManager + * @param deltaT The time sine the last update + */ + update(deltaT: number): void { + try{ + // Handle all events that happened since the start of the last loop + this.eventQueue.update(deltaT); + + // Update the input data structures so game objects can see the input + Input.update(deltaT); + + // Update the recording of the game + this.recorder.update(deltaT); + + // Update all scenes + this.sceneManager.update(deltaT); + + // Update all sounds + this.audioManager.update(deltaT); + + // Load or unload any resources if needed + this.resourceManager.update(deltaT); + } catch(e){ + this.loop.pause(); + console.warn("Uncaught Error in Update - Crashing gracefully"); + console.error(e); + } + } + + /** + * Clears the canvas and defers scene rendering to the sceneManager. Renders the debug canvas + */ + render(): void { + try{ + // Clear the canvases + Debug.clearCanvas(); + + this.renderingManager.clear(this.clearColor); + + this.sceneManager.render(); + + // Hacky debug mode + if(Input.isKeyJustPressed("g")){ + this.showDebug = !this.showDebug; + } + + // Debug render + if(this.showDebug){ + Debug.render(); + } + + if(this.showStats){ + Stats.render(); + } + } catch(e){ + this.loop.pause(); + console.warn("Uncaught Error in Render - Crashing gracefully"); + console.error(e); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Loop/GameLoop.ts b/hw3/src/Wolfie2D/Loop/GameLoop.ts new file mode 100644 index 0000000..ea7da06 --- /dev/null +++ b/hw3/src/Wolfie2D/Loop/GameLoop.ts @@ -0,0 +1,69 @@ +import NullFunc from "../DataTypes/Functions/NullFunc"; + +/** + * The main game loop of the game. Keeps track of fps and handles scheduling of updates and rendering. + * This class is left abstract, so that a subclass can handle exactly how the loop is scheduled. + * For an example of different types of game loop scheduling, check out @link(Game Programming Patterns)(https://gameprogrammingpatterns.com/game-loop.html) + */ +export default abstract class GameLoop { + + /** The function to call when an update occurs */ + protected _doUpdate: Function = NullFunc; + + set doUpdate(update: Function){ + this._doUpdate = update; + } + + /** The function to call when a render occurs */ + protected _doRender: Function = NullFunc; + + + set doRender(render: Function){ + this._doRender = render; + } + + /** + * Retrieves the current FPS of the game + */ + abstract getFPS(): number; + + /** + * Starts up the game loop + */ + abstract start(): void; + + /** + * Pauses the game loop, usually for an error condition. + */ + abstract pause(): void; + + /** + * Resumes the game loop. + */ + abstract resume(): void; + + /** + * Runs the first frame of the game. No update occurs here, only a render. + * This is needed to initialize delta time values + * @param timestamp The timestamp of the frame. This is received from the browser + */ + protected abstract doFirstFrame(timestamp: number): void; + + /** + * Run before any updates or the render of a frame. + * @param timestamp The timestamp of the frame. This is received from the browser + */ + protected abstract startFrame(timestamp: number): void; + + /** + * The core of the frame, where any necessary updates occur, and where a render happens + * @param timestamp The timestamp of the frame. This is received from the browser + */ + protected abstract doFrame(timestamp: number): void; + + /** + * Wraps up the frame + * @param panic Whether or not the update cycle panicked. This happens when too many updates try to happen in a single frame + */ + protected abstract finishFrame(panic: boolean): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Loop/GameOptions.ts b/hw3/src/Wolfie2D/Loop/GameOptions.ts new file mode 100644 index 0000000..a9112fb --- /dev/null +++ b/hw3/src/Wolfie2D/Loop/GameOptions.ts @@ -0,0 +1,44 @@ +// @ignorePage + +/** The options for initializing the @reference[GameLoop] */ +export default class GameOptions { + /** The size of the viewport */ + canvasSize: {x: number, y: number}; + + /* The default level of zoom */ + zoomLevel: number; + + /** The color to clear the canvas to each frame */ + clearColor: {r: number, g: number, b: number} + + /* A list of input bindings */ + inputs: Array<{name: string, keys: Array}>; + + /* Whether or not the debug rendering should occur */ + showDebug: boolean; + + /* Whether or not the stats rendering should occur */ + showStats: boolean; + + /* Whether or not to use webGL */ + useWebGL: boolean; + + /** + * Parses the data in the raw options object + * @param options The game options as a Record + * @returns A version of the options converted to a GameOptions object + */ + static parse(options: Record): GameOptions { + let gOpt = new GameOptions(); + + gOpt.canvasSize = options.canvasSize ? options.canvasSize : {x: 800, y: 600}; + gOpt.zoomLevel = options.zoomLevel ? options.zoomLevel : 1; + gOpt.clearColor = options.clearColor ? options.clearColor : {r: 255, g: 255, b: 255}; + gOpt.inputs = options.inputs ? options.inputs : []; + gOpt.showDebug = !!options.showDebug; + gOpt.showStats = !!options.showStats; + gOpt.useWebGL = !!options.useWebGL; + + return gOpt; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/CanvasNode.ts b/hw3/src/Wolfie2D/Nodes/CanvasNode.ts new file mode 100644 index 0000000..d257b5e --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/CanvasNode.ts @@ -0,0 +1,137 @@ +import GameNode from "./GameNode"; +import Vec2 from "../DataTypes/Vec2"; +import Region from "../DataTypes/Interfaces/Region"; +import AABB from "../DataTypes/Shapes/AABB"; +import Debug from "../Debug/Debug"; +import Color from "../Utils/Color"; + +/** + * The representation of an object in the game world that can be drawn to the screen + */ +export default abstract class CanvasNode extends GameNode implements Region { + private _size: Vec2; + private _scale: Vec2; + private _boundary: AABB; + private _hasCustomShader: boolean; + private _customShaderKey: string; + private _alpha: number; + + /** A flag for whether or not the CanvasNode is visible */ + visible: boolean = true; + + constructor(){ + super(); + this._size = new Vec2(0, 0); + this._size.setOnChange(() => this.sizeChanged()); + this._scale = new Vec2(1, 1); + this._scale.setOnChange(() => this.scaleChanged()); + this._boundary = new AABB(); + this.updateBoundary(); + + this._hasCustomShader = false; + } + + get alpha(): number { + return this._alpha; + } + + set alpha(a: number) { + this._alpha = a; + } + + get size(): Vec2 { + return this._size; + } + + set size(size: Vec2){ + this._size = size; + // Enter as a lambda to bind "this" + this._size.setOnChange(() => this.sizeChanged()); + this.sizeChanged(); + } + + get scale(): Vec2 { + return this._scale; + } + + set scale(scale: Vec2){ + this._scale = scale; + // Enter as a lambda to bind "this" + this._scale.setOnChange(() => this.scaleChanged()); + this.scaleChanged(); + } + + set scaleX(value: number) { + this.scale.x = value; + } + + set scaleY(value: number) { + this.scale.y = value; + } + + get hasCustomShader(): boolean { + return this._hasCustomShader; + } + + get customShaderKey(): string { + return this._customShaderKey; + } + + // @override + protected positionChanged(): void { + super.positionChanged(); + this.updateBoundary(); + } + + /** Called if the size vector is changed or replaced. */ + protected sizeChanged(): void { + this.updateBoundary(); + } + + /** Called if the scale vector is changed or replaced */ + protected scaleChanged(): void { + this.updateBoundary(); + } + + // @docIgnore + /** Called if the position, size, or scale of the CanvasNode is changed. Updates the boundary. */ + private updateBoundary(): void { + this._boundary.center.set(this.position.x, this.position.y); + this._boundary.halfSize.set(this.size.x*this.scale.x/2, this.size.y*this.scale.y/2); + } + + get boundary(): AABB { + return this._boundary; + } + + get sizeWithZoom(): Vec2 { + let zoom = this.scene.getViewScale(); + + return this.boundary.halfSize.clone().scaled(zoom, zoom); + } + + /** + * Adds a custom shader to this CanvasNode + * @param key The registry key of the ShaderType + */ + useCustomShader(key: string): void { + this._hasCustomShader = true; + this._customShaderKey = key; + } + + /** + * Returns true if the point (x, y) is inside of this canvas object + * @param x The x position of the point + * @param y The y position of the point + * @returns A flag representing whether or not this node contains the point. + */ + contains(x: number, y: number): boolean { + return this._boundary.containsPoint(new Vec2(x, y)); + } + + // @implemented + debugRender(): void { + Debug.drawBox(this.relativePosition, this.sizeWithZoom, false, Color.BLUE); + super.debugRender(); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/GameNode.ts b/hw3/src/Wolfie2D/Nodes/GameNode.ts new file mode 100644 index 0000000..6ae3794 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/GameNode.ts @@ -0,0 +1,478 @@ +import Vec2 from "../DataTypes/Vec2"; +import Receiver from "../Events/Receiver"; +import Emitter from "../Events/Emitter"; +import Scene from "../Scene/Scene"; +import Layer from "../Scene/Layer"; +import AI from "../DataTypes/Interfaces/AI"; +import Physical from "../DataTypes/Interfaces/Physical"; +import Positioned from "../DataTypes/Interfaces/Positioned"; +import { isRegion } from "../DataTypes/Interfaces/Region"; +import Unique from "../DataTypes/Interfaces/Unique"; +import Updateable from "../DataTypes/Interfaces/Updateable"; +import DebugRenderable from "../DataTypes/Interfaces/DebugRenderable"; +import Actor from "../DataTypes/Interfaces/Actor"; +import Shape from "../DataTypes/Shapes/Shape"; +import AABB from "../DataTypes/Shapes/AABB"; +import NavigationPath from "../Pathfinding/NavigationPath"; +import TweenController from "../Rendering/Animations/TweenController"; +import Debug from "../Debug/Debug"; +import Color from "../Utils/Color"; +import Circle from "../DataTypes/Shapes/Circle"; + +/** + * The representation of an object in the game world. + * To construct GameNodes, see the @reference[Scene] documentation. + */ +export default abstract class GameNode implements Positioned, Unique, Updateable, Physical, Actor, DebugRenderable { + /*---------- POSITIONED ----------*/ + private _position: Vec2; + + /*---------- UNIQUE ----------*/ + private _id: number; + + /*---------- PHYSICAL ----------*/ + hasPhysics: boolean = false; + moving: boolean = false; + frozen: boolean = false; + onGround: boolean = false; + onWall: boolean = false; + onCeiling: boolean = false; + active: boolean = false; + collisionShape: Shape; + colliderOffset: Vec2; + isStatic: boolean; + isCollidable: boolean; + isTrigger: boolean; + triggerMask: number; + triggerEnters: Array; + triggerExits: Array; + _velocity: Vec2; + sweptRect: AABB; + collidedWithTilemap: boolean; + group: number; + isPlayer: boolean; + isColliding: boolean = false; + + /*---------- ACTOR ----------*/ + _ai: AI; + aiActive: boolean; + path: NavigationPath; + pathfinding: boolean = false; + + /*---------- GENERAL ----------*/ + /** An event receiver. */ + protected receiver: Receiver; + /** An event emitter. */ + protected emitter: Emitter; + /** A reference to the scene this GameNode is a part of. */ + protected scene: Scene; + /** The visual layer this GameNode resides in. */ + protected layer: Layer; + /** A utility that allows the use of tweens on this GameNode */ + tweens: TweenController; + /** A tweenable property for rotation. Does not affect the bounding box of this GameNode - Only rendering. */ + rotation: number; + /** The opacity value of this GameNode */ + abstract set alpha(a: number); + + abstract get alpha(): number; + + // Constructor docs are ignored, as the user should NOT create new GameNodes with a raw constructor + constructor(){ + this._position = new Vec2(0, 0); + this._position.setOnChange(() => this.positionChanged()); + this.receiver = new Receiver(); + this.emitter = new Emitter(); + this.tweens = new TweenController(this); + this.rotation = 0; + } + + destroy(){ + this.tweens.destroy(); + this.receiver.destroy(); + + if(this.hasPhysics){ + this.removePhysics(); + } + + if(this._ai){ + this._ai.destroy(); + delete this._ai; + this.scene.getAIManager().removeActor(this); + } + + this.scene.remove(this); + + this.layer.removeNode(this); + } + + /*---------- POSITIONED ----------*/ + get position(): Vec2 { + return this._position; + } + + set position(pos: Vec2) { + this._position = pos; + this._position.setOnChange(() => this.positionChanged()); + this.positionChanged(); + } + + get relativePosition(): Vec2 { + return this.inRelativeCoordinates(this.position); + } + + /** + * Converts a point to coordinates relative to the zoom and origin of this node + * @param point The point to conver + * @returns A new Vec2 representing the point in relative coordinates + */ + inRelativeCoordinates(point: Vec2): Vec2 { + let origin = this.scene.getViewTranslation(this); + let zoom = this.scene.getViewScale(); + return point.clone().sub(origin).scale(zoom); + } + + /*---------- UNIQUE ----------*/ + get id(): number { + return this._id; + } + + set id(id: number) { + // id can only be set once + if(this._id === undefined){ + this._id = id; + } else { + throw "Attempted to assign id to object that already has id." + } + } + + /*---------- PHYSICAL ----------*/ + // @implemented + /** + * @param velocity The velocity with which to move the object. + */ + move(velocity: Vec2): void { + if(this.frozen) return; + this.moving = true; + this._velocity = velocity; + }; + + moveOnPath(speed: number, path: NavigationPath): void { + if(this.frozen) return; + this.path = path; + let dir = path.getMoveDirection(this); + this.moving = true; + this.pathfinding = true; + this._velocity = dir.scale(speed); + } + + // @implemented + /** + * @param velocity The velocity with which the object will move. + */ + finishMove(): void { + this.moving = false; + this.position.add(this._velocity); + if(this.pathfinding){ + this.path.handlePathProgress(this); + this.path = null; + this.pathfinding = false; + } + } + + // @implemented + /** + * @param collisionShape The collider for this object. If this has a region (implements Region), + * it will be used when no collision shape is specified (or if collision shape is null). + * @param isCollidable Whether this is collidable or not. True by default. + * @param isStatic Whether this is static or not. False by default + */ + addPhysics(collisionShape?: Shape, colliderOffset?: Vec2, isCollidable: boolean = true, isStatic: boolean = false): void { + // Initialize the physics variables + this.hasPhysics = true; + this.moving = false; + this.onGround = false; + this.onWall = false; + this.onCeiling = false; + this.active = true; + this.isCollidable = isCollidable; + this.isStatic = isStatic; + this.isTrigger = false; + this.triggerMask = 0; + this.triggerEnters = new Array(32); + this.triggerExits = new Array(32); + this._velocity = Vec2.ZERO; + this.sweptRect = new AABB(); + this.collidedWithTilemap = false; + this.group = -1; // The default group, collides with everything + + // Set the collision shape if provided, or simply use the the region if there is one. + if(collisionShape){ + this.collisionShape = collisionShape; + this.collisionShape.center = this.position; + } else if (isRegion(this)) { + // If the gamenode has a region and no other is specified, use that + this.collisionShape = (this).boundary.clone(); + } else { + throw "No collision shape specified for physics object." + } + + // If we were provided with a collider offset, set it. Otherwise there is no offset, so use the zero vector + if(colliderOffset){ + this.colliderOffset = colliderOffset; + } else { + this.colliderOffset = Vec2.ZERO; + } + + // Initialize the swept rect + this.sweptRect = this.collisionShape.getBoundingRect(); + + // Register the object with physics + this.scene.getPhysicsManager().registerObject(this); + } + + /** Removes this object from the physics system */ + removePhysics(): void { + // Remove this from the physics manager + this.scene.getPhysicsManager().deregisterObject(this); + + // Nullify all physics fields + this.hasPhysics = false; + this.moving = false; + this.onGround = false; + this.onWall = false; + this.onCeiling = false; + this.active = false; + this.isCollidable = false; + this.isStatic = false; + this.isTrigger = false; + this.triggerMask = 0; + this.triggerEnters = null; + this.triggerExits = null; + this._velocity = Vec2.ZERO; + this.sweptRect = null; + this.collidedWithTilemap = false; + this.group = -1; + this.collisionShape = null; + this.colliderOffset = Vec2.ZERO; + this.sweptRect = null; + } + + /** Disables physics movement for this node */ + freeze(): void { + this.frozen = true; + } + + /** Reenables physics movement for this node */ + unfreeze(): void { + this.frozen = false; + } + + /** Prevents this object from participating in all collisions and triggers. It can still move. */ + disablePhysics(): void { + this.active = false; + } + + /** Enables this object to participate in collisions and triggers. This is only necessary if disablePhysics was called */ + enablePhysics(): void { + this.active = true; + } + + /** + * Sets the collider for this GameNode + * @param collider The new collider to use + */ + setCollisionShape(collider: Shape): void { + this.collisionShape = collider; + this.collisionShape.center.copy(this.position); + } + + // @implemented + /** + * Sets this object to be a trigger for a specific group + * @param group The name of the group that activates the trigger + * @param onEnter The name of the event to send when this trigger is activated + * @param onExit The name of the event to send when this trigger stops being activated + */ + setTrigger(group: string, onEnter: string, onExit: string): void { + // Make this object a trigger + this.isTrigger = true; + + // Get the number of the physics layer + let layerNumber = this.scene.getPhysicsManager().getGroupNumber(group); + + if(layerNumber === 0){ + console.warn(`Trigger for GameNode ${this.id} not set - group "${group}" was not recognized by the physics manager.`); + return; + } + + // Add this to the trigger mask + this.triggerMask |= layerNumber; + + // Layer numbers are bits, so get which bit it is + let index = Math.log2(layerNumber); + + // Set the event names + this.triggerEnters[index] = onEnter; + this.triggerExits[index] = onExit; + }; + + // @implemented + /** + * @param group The physics group this node should belong to + */ + setGroup(group: string): void { + this.scene.getPhysicsManager().setGroup(this, group); + } + + // @implemened + getLastVelocity(): Vec2 { + return this._velocity; + } + + /*---------- ACTOR ----------*/ + get ai(): AI { + return this._ai; + } + + set ai(ai: AI) { + if(!this._ai){ + // If we haven't been previously had an ai, register us with the ai manager + this.scene.getAIManager().registerActor(this); + } + + this._ai = ai; + this.aiActive = true; + } + + // @implemented + addAI(ai: string | (new () => T), options?: Record): void { + if(!this._ai){ + this.scene.getAIManager().registerActor(this); + } + + if(typeof ai === "string"){ + this._ai = this.scene.getAIManager().generateAI(ai); + } else { + this._ai = new ai(); + } + + this._ai.initializeAI(this, options); + + this.aiActive = true; + } + + // @implemented + setAIActive(active: boolean, options: Record): void { + this.aiActive = active; + if(this.aiActive){ + this.ai.activate(options); + } + } + + /*---------- TWEENABLE PROPERTIES ----------*/ + set positionX(value: number) { + this.position.x = value; + } + + set positionY(value: number) { + this.position.y = value; + } + + abstract set scaleX(value: number); + + abstract set scaleY(value: number); + + /*---------- GAME NODE ----------*/ + /** + * Sets the scene for this object. + * @param scene The scene this object belongs to. + */ + setScene(scene: Scene): void { + this.scene = scene; + } + + /** + * Gets the scene this object is in. + * @returns The scene this object belongs to + */ + getScene(): Scene { + return this.scene; + } + + /** + * Sets the layer of this object. + * @param layer The layer this object will be on. + */ + setLayer(layer: Layer): void { + this.layer = layer; + } + + /** + * Returns the layer this object is on. + * @returns This layer this object is on. + */ + getLayer(): Layer { + return this.layer; + } + + /** Called if the position vector is modified or replaced */ + protected positionChanged(): void { + if(this.collisionShape){ + if(this.colliderOffset){ + this.collisionShape.center = this.position.clone().add(this.colliderOffset); + } else { + this.collisionShape.center = this.position.clone(); + } + + } + }; + + /** + * Updates this GameNode + * @param deltaT The timestep of the update. + */ + update(deltaT: number): void { + // Defer event handling to AI. + while(this.receiver.hasNextEvent()){ + this._ai.handleEvent(this.receiver.getNextEvent()); + } + } + + // @implemented + debugRender(): void { + // Draw the position of this GameNode + Debug.drawPoint(this.relativePosition, Color.BLUE); + + // If velocity is not zero, draw a vector for it + if(this._velocity && !this._velocity.isZero()){ + Debug.drawRay(this.relativePosition, this._velocity.clone().scaleTo(20).add(this.relativePosition), Color.BLUE); + } + + // If this has a collider, draw it + if(this.collisionShape){ + let color = this.isColliding ? Color.RED : Color.GREEN; + + if(this.isTrigger){ + color = Color.MAGENTA; + } + + color.a = 0.2; + + if(this.collisionShape instanceof AABB){ + Debug.drawBox(this.inRelativeCoordinates(this.collisionShape.center), this.collisionShape.halfSize.scaled(this.scene.getViewScale()), true, color); + } else if(this.collisionShape instanceof Circle){ + Debug.drawCircle(this.inRelativeCoordinates(this.collisionShape.center), this.collisionShape.hw*this.scene.getViewScale(), true, color); + } + } + } +} + +export enum TweenableProperties{ + posX = "positionX", + posY = "positionY", + scaleX = "scaleX", + scaleY = "scaleY", + rotation = "rotation", + alpha = "alpha" +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Graphic.ts b/hw3/src/Wolfie2D/Nodes/Graphic.ts new file mode 100644 index 0000000..79383ad --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Graphic.ts @@ -0,0 +1,32 @@ +import CanvasNode from "./CanvasNode"; +import Color from "../Utils/Color"; + +/** + * The representation of a game object that doesn't rely on any resources to render - it is drawn to the screen by the canvas + */ +export default abstract class Graphic extends CanvasNode { + /** The color of the Graphic */ + color: Color; + + constructor(){ + super(); + this.color = Color.RED; + } + + get alpha(): number { + return this.color.a; + } + + set alpha(a: number) { + this.color.a = a; + } + + // @deprecated + /** + * Sets the color of the Graphic. DEPRECATED + * @param color The new color of the Graphic. + */ + setColor(color: Color){ + this.color = color; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Graphics/GraphicTypes.ts b/hw3/src/Wolfie2D/Nodes/Graphics/GraphicTypes.ts new file mode 100644 index 0000000..3631c46 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Graphics/GraphicTypes.ts @@ -0,0 +1,5 @@ +export enum GraphicType { + POINT = "POINT", + RECT = "RECT", + LINE = "LINE", +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Graphics/Line.ts b/hw3/src/Wolfie2D/Nodes/Graphics/Line.ts new file mode 100644 index 0000000..b6242ee --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Graphics/Line.ts @@ -0,0 +1,33 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Graphic from "../Graphic"; + +export default class Line extends Graphic { + protected _end: Vec2; + thickness: number; + + constructor(start: Vec2, end: Vec2){ + super(); + this.start = start; + this.end = end; + this.thickness = 2; + + // Does this really have a meaning for lines? + this.size.set(5, 5); + } + + set start(pos: Vec2){ + this.position = pos; + } + + get start(): Vec2 { + return this.position; + } + + set end(pos: Vec2){ + this._end = pos; + } + + get end(): Vec2 { + return this._end; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Graphics/Point.ts b/hw3/src/Wolfie2D/Nodes/Graphics/Point.ts new file mode 100644 index 0000000..0f75c5a --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Graphics/Point.ts @@ -0,0 +1,12 @@ +import Graphic from "../Graphic"; +import Vec2 from "../../DataTypes/Vec2"; + +/** A basic point to be drawn on the screen. */ +export default class Point extends Graphic { + + constructor(position: Vec2){ + super(); + this.position = position; + this.size.set(5, 5); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Graphics/Rect.ts b/hw3/src/Wolfie2D/Nodes/Graphics/Rect.ts new file mode 100644 index 0000000..7bac72a --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Graphics/Rect.ts @@ -0,0 +1,46 @@ +import Graphic from "../Graphic"; +import Vec2 from "../../DataTypes/Vec2"; +import Color from "../../Utils/Color"; + +/** A basic rectangle to be drawn on the screen. */ +export default class Rect extends Graphic { + + /** The border color of the Rect */ + borderColor: Color; + + /** The width of the border */ + borderWidth: number; + + constructor(position: Vec2, size: Vec2){ + super(); + this.position = position; + this.size = size; + this.borderColor = Color.TRANSPARENT; + this.borderWidth = 0; + } + + /** + * Sets the border color of this rectangle + * @param color The border color + */ + setBorderColor(color: Color): void { + this.borderColor = color; + } + + // @deprecated + getBorderColor(): Color { + return this.borderColor; + } + + /** + * Sets the border width of this rectangle + * @param width The width of the rectangle in pixels + */ + setBorderWidth(width: number){ + this.borderWidth = width; + } + + getBorderWidth(): number { + return this.borderWidth; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Sprites/AnimatedSprite.ts b/hw3/src/Wolfie2D/Nodes/Sprites/AnimatedSprite.ts new file mode 100644 index 0000000..bdd909f --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Sprites/AnimatedSprite.ts @@ -0,0 +1,49 @@ +import Sprite from "./Sprite"; +import AnimationManager from "../../Rendering/Animations/AnimationManager"; +import Spritesheet from "../../DataTypes/Spritesheet"; +import Vec2 from "../../DataTypes/Vec2"; + +/** An sprite with specified animation frames. */ +export default class AnimatedSprite extends Sprite { + /** The number of columns in this sprite sheet */ + protected numCols: number; + + get cols(): number { + return this.numCols; + } + + /** The number of rows in this sprite sheet */ + protected numRows: number; + + get rows(): number { + return this.numRows; + } + + /** The animationManager for this sprite */ + animation: AnimationManager; + + constructor(spritesheet: Spritesheet){ + super(spritesheet.name); + this.numCols = spritesheet.columns; + this.numRows = spritesheet.rows; + + // Set the size of the sprite to the sprite size specified by the spritesheet + this.size.set(spritesheet.spriteWidth, spritesheet.spriteHeight); + + this.animation = new AnimationManager(this); + + // Add the animations to the animated sprite + for(let animation of spritesheet.animations){ + this.animation.add(animation.name, animation); + } + } + + /** + * Gets the image offset for the current index of animation + * @param index The index we're at in the animation + * @returns A Vec2 containing the image offset + */ + getAnimationOffset(index: number): Vec2 { + return new Vec2((index % this.numCols) * this.size.x, Math.floor(index / this.numCols) * this.size.y); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Sprites/Sprite.ts b/hw3/src/Wolfie2D/Nodes/Sprites/Sprite.ts new file mode 100644 index 0000000..4184e1b --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Sprites/Sprite.ts @@ -0,0 +1,35 @@ +import CanvasNode from "../CanvasNode"; +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Vec2 from "../../DataTypes/Vec2"; + +/** + * The representation of a sprite - an in-game image + */ +export default class Sprite extends CanvasNode { + /** The id of the image from the resourceManager */ + imageId: string; + /** The offset of the sprite in an atlas image */ + imageOffset: Vec2; + /** Whether or not the x-axis should be inverted on render */ + invertX: boolean; + /** Whether or not the y-axis should be inverted on render */ + invertY: boolean; + + constructor(imageId: string){ + super(); + this.imageId = imageId; + let image = ResourceManager.getInstance().getImage(this.imageId); + this.size = new Vec2(image.width, image.height); + this.imageOffset = Vec2.ZERO; + this.invertX = false; + this.invertY = false; + } + + /** + * Sets the offset of the sprite from (0, 0) in the image's coordinates + * @param offset The offset of the sprite from (0, 0) in image coordinates + */ + setImageOffset(offset: Vec2): void { + this.imageOffset = offset; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Tilemap.ts b/hw3/src/Wolfie2D/Nodes/Tilemap.ts new file mode 100644 index 0000000..4f821f4 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Tilemap.ts @@ -0,0 +1,119 @@ +import Vec2 from "../DataTypes/Vec2"; +import Tileset from "../DataTypes/Tilesets/Tileset"; +import { TiledTilemapData, TiledLayerData } from "../DataTypes/Tilesets/TiledData" +import CanvasNode from "./CanvasNode"; +import PhysicsManager from "../Physics/PhysicsManager"; + +/** + * The representation of a tilemap - this can consist of a combination of tilesets in one layer + */ +export default abstract class Tilemap extends CanvasNode { + /** An array of the tilesets that this tilemap uses */ + protected tilesets: Array; + + /** The size of a tile in this tilemap */ + protected tileSize: Vec2; + + /** An array of tile data */ + protected data: Array; + + /** An array of tile collision data */ + protected collisionMap: Array; + + /** The name of the tilemap */ + name: string; + + // TODO: Make this no longer be specific to Tiled + constructor(tilemapData: TiledTilemapData, layer: TiledLayerData, tilesets: Array, scale: Vec2) { + super(); + this.tilesets = tilesets; + this.tileSize = new Vec2(0, 0); + this.name = layer.name; + + let tilecount = 0; + for(let tileset of tilesets){ + tilecount += tileset.getTileCount() + 1; + } + + this.collisionMap = new Array(tilecount); + for(let i = 0; i < this.collisionMap.length; i++){ + this.collisionMap[i] = false; + } + + // Defer parsing of the data to child classes - this allows for isometric vs. orthographic tilemaps and handling of Tiled data or other data + this.parseTilemapData(tilemapData, layer); + this.scale.set(scale.x, scale.y); + } + + /** + * Returns an array of the tilesets associated with this tilemap + * @returns An array of all of the tilesets assocaited with this tilemap. + */ + getTilesets(): Tileset[] { + return this.tilesets; + } + + /** + * Returns the size of tiles in this tilemap as they appear in the game world after scaling + * @returns A vector containing the size of tiles in this tilemap as they appear in the game world after scaling. + */ + getTileSize(): Vec2 { + return this.tileSize.scaled(this.scale.x, this.scale.y); + } + + /** + * Gets the tile size taking zoom into account + * @returns The tile size with zoom + */ + getTileSizeWithZoom(): Vec2 { + let zoom = this.scene.getViewScale(); + + return this.getTileSize().scale(zoom); + } + + /** + * Adds this tilemap to the physics system + */ + addPhysics(): void { + this.hasPhysics = true; + this.active = true; + this.group = -1; + this.scene.getPhysicsManager().registerTilemap(this); + } + + /** + * Returns the value of the tile at the specified position + * @param worldCoords The position in world coordinates + * @returns A number that represents the data value of the tile at the specified world position. + */ + abstract getTileAtWorldPosition(worldCoords: Vec2): number; + + /** + * Returns the world position of the top left corner of the tile at the specified index + * @param index The index of the tile in the tileData array + * @returns The world position of the tile at the specified index + */ + abstract getTileWorldPosition(index: number): Vec2; + + /** + * Returns the value of the tile at the specified index + * @param index The index of the tile in the tileData array + * @returns The value of the tile in the tileData array + */ + abstract getTile(index: number): number; + + /** + * Sets the tile at the specified index + * @param index The index of the tile + * @param type The new data value of the tile + */ + abstract setTile(index: number, type: number): void; + + // TODO: This shouldn't use tiled data specifically - it should be more general + /** + * Sets up the tileset using the data loaded from file + * @param tilemapData The tilemap data from file + * @param layer The layer data from file + */ + protected abstract parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts b/hw3/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts new file mode 100644 index 0000000..9b9703e --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts @@ -0,0 +1,190 @@ +import Tilemap from "../Tilemap"; +import Vec2 from "../../DataTypes/Vec2"; +import { TiledTilemapData, TiledLayerData } from "../../DataTypes/Tilesets/TiledData"; +import Debug from "../../Debug/Debug"; +import Color from "../../Utils/Color"; + +/** + * The representation of an orthogonal tilemap - i.e. a top down or platformer tilemap + */ +export default class OrthogonalTilemap extends Tilemap { + /** The number of columns in the tilemap */ + protected numCols: number; + /** The number of rows in the tilemap */ + protected numRows: number; + + // @override + protected parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void { + // The size of the tilemap in local space + this.numCols = tilemapData.width; + this.numRows = tilemapData.height; + + // The size of tiles + this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight); + + // The size of the tilemap on the canvas + this.size.set(this.numCols * this.tileSize.x, this.numRows * this.tileSize.y); + this.position.copy(this.size.scaled(0.5)); + this.data = layer.data; + this.visible = layer.visible; + + // Whether the tilemap is collidable or not + this.isCollidable = false; + if(layer.properties){ + for(let item of layer.properties){ + if(item.name === "Collidable"){ + this.isCollidable = item.value; + + // Set all tiles besides "empty: 0" to be collidable + for(let i = 1; i < this.collisionMap.length; i++){ + this.collisionMap[i] = true; + } + } + } + } + } + + /** + * Gets the dimensions of the tilemap + * @returns A Vec2 containing the number of columns and the number of rows in the tilemap. + */ + getDimensions(): Vec2 { + return new Vec2(this.numCols, this.numRows); + } + + /** + * Gets the data value of the tile at the specified world position + * @param worldCoords The coordinates in world space + * @returns The data value of the tile + */ + getTileAtWorldPosition(worldCoords: Vec2): number { + let localCoords = this.getColRowAt(worldCoords); + return this.getTileAtRowCol(localCoords); + } + + /** + * Get the tile at the specified row and column + * @param rowCol The coordinates in tilemap space + * @returns The data value of the tile + */ + getTileAtRowCol(rowCol: Vec2): number { + if(rowCol.x < 0 || rowCol.x >= this.numCols || rowCol.y < 0 || rowCol.y >= this.numRows){ + return -1; + } + + return this.data[rowCol.y * this.numCols + rowCol.x]; + } + + /** + * Gets the world position of the tile at the specified index + * @param index The index of the tile + * @returns A Vec2 containing the world position of the tile + */ + getTileWorldPosition(index: number): Vec2 { + // Get the local position + let col = index % this.numCols; + let row = Math.floor(index / this.numCols); + + // Get the world position + let x = col * this.tileSize.x; + let y = row * this.tileSize.y; + + return new Vec2(x, y); + } + + /** + * Gets the data value of the tile at the specified index + * @param index The index of the tile + * @returns The data value of the tile + */ + getTile(index: number): number { + return this.data[index]; + } + + // @override + setTile(index: number, type: number): void { + this.data[index] = type; + } + + /** + * Sets the tile at the specified row and column + * @param rowCol The position of the tile in tilemap space + * @param type The new data value of the tile + */ + setTileAtRowCol(rowCol: Vec2, type: number): void { + let index = rowCol.y * this.numCols + rowCol.x; + this.setTile(index, type); + } + + /** + * Returns true if the tile at the specified row and column of the tilemap is collidable + * @param indexOrCol The index of the tile or the column it is in + * @param row The row the tile is in + * @returns A flag representing whether or not the tile is collidable. + */ + isTileCollidable(indexOrCol: number, row?: number): boolean { + // The value of the tile + let tile = 0; + + if(row){ + // We have a column and a row + tile = this.getTileAtRowCol(new Vec2(indexOrCol, row)); + + if(tile < 0){ + return false; + } + } else { + if(indexOrCol < 0 || indexOrCol >= this.data.length){ + // Tiles that don't exist aren't collidable + return false; + } + // We have an index + tile = this.getTile(indexOrCol); + } + + return this.collisionMap[tile]; + } + + /** + * Takes in world coordinates and returns the row and column of the tile at that position + * @param worldCoords The coordinates of the potential tile in world space + * @returns A Vec2 containing the coordinates of the potential tile in tilemap space + */ + getColRowAt(worldCoords: Vec2): Vec2 { + let col = Math.floor(worldCoords.x / this.tileSize.x / this.scale.x); + let row = Math.floor(worldCoords.y / this.tileSize.y / this.scale.y); + + return new Vec2(col, row); + } + + // @override + update(deltaT: number): void {} + + // @override + debugRender(){ + // Half of the tile size + let zoomedHalfTileSize = this.getTileSizeWithZoom().scaled(0.5); + let halfTileSize = this.getTileSize().scaled(0.5); + + // The center of the top left tile + let topLeft = this.position.clone().sub(this.size.scaled(0.5)); + + // A vec to store the center + let center = Vec2.ZERO; + + for(let col = 0; col < this.numCols; col++){ + // Calculate the x-position + center.x = topLeft.x + col*2*halfTileSize.x + halfTileSize.x; + + for(let row = 0; row < this.numRows; row++){ + if(this.isCollidable && this.isTileCollidable(col, row)){ + // Calculate the y-position + center.y = topLeft.y + row*2*halfTileSize.y + halfTileSize.y; + + // Draw a box for this tile + Debug.drawBox(this.inRelativeCoordinates(center), zoomedHalfTileSize, false, Color.BLUE); + } + } + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/UIElement.ts b/hw3/src/Wolfie2D/Nodes/UIElement.ts new file mode 100644 index 0000000..f6cb36b --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/UIElement.ts @@ -0,0 +1,149 @@ +import CanvasNode from "./CanvasNode"; +import Color from "../Utils/Color"; +import Vec2 from "../DataTypes/Vec2"; +import Input from "../Input/Input"; + +/** + * The representation of a UIElement - the parent class of things like buttons + */ +export default abstract class UIElement extends CanvasNode { + // Style attributes - TODO - abstract this into a style object/interface + /** The backgound color */ + backgroundColor: Color; + /** The border color */ + borderColor: Color; + /** The border radius */ + borderRadius: number; + /** The border width */ + borderWidth: number; + /** The padding */ + padding: Vec2; + + // EventAttributes + /** The reaction of this UIElement on a click */ + onClick: Function; + /** The event propagated on click */ + onClickEventId: string; + /** The reaction to the release of a click */ + onRelease: Function; + /** The event propagated on the release of a click */ + onReleaseEventId: string; + /** The reaction when a mouse enters this UIElement */ + onEnter: Function; + /** The event propagated when a mouse enters this UIElement */ + onEnterEventId: string; + /** The reaction when a mouse leaves this UIElement */ + onLeave: Function; + /** The event propogated when a mouse leaves this UIElement */ + onLeaveEventId: string; + + /** Whether or not this UIElement is currently clicked on */ + protected isClicked: boolean; + /** Whether or not this UIElement is currently hovered over */ + protected isEntered: boolean; + + constructor(position: Vec2){ + super(); + this.position = position; + + this.backgroundColor = new Color(0, 0, 0, 0); + this.borderColor = new Color(0, 0, 0, 0); + this.borderRadius = 5; + this.borderWidth = 1; + this.padding = Vec2.ZERO; + + this.onClick = null; + this.onClickEventId = null; + this.onRelease = null; + this.onReleaseEventId = null; + + this.onEnter = null; + this.onEnterEventId = null; + this.onLeave = null; + this.onLeaveEventId = null; + + this.isClicked = false; + this.isEntered = false; + } + + // @deprecated + setBackgroundColor(color: Color): void { + this.backgroundColor = color; + } + + // @deprecated + setPadding(padding: Vec2): void { + this.padding.copy(padding); + } + + update(deltaT: number): void { + super.update(deltaT); + + // See of this object was just clicked + if(Input.isMouseJustPressed()){ + let clickPos = Input.getMousePressPosition(); + if(this.contains(clickPos.x, clickPos.y) && this.visible && !this.layer.isHidden()){ + this.isClicked = true; + + if(this.onClick !== null){ + this.onClick(); + } + if(this.onClickEventId !== null){ + let data = {}; + this.emitter.fireEvent(this.onClickEventId, data); + } + } + } + + // If the mouse wasn't just pressed, then we definitely weren't clicked + if(!Input.isMousePressed()){ + if(this.isClicked){ + this.isClicked = false; + } + } + + // Check if the mouse is hovering over this element + let mousePos = Input.getMousePosition(); + if(mousePos && this.contains(mousePos.x, mousePos.y)){ + this.isEntered = true; + + if(this.onEnter !== null){ + this.onEnter(); + } + if(this.onEnterEventId !== null){ + let data = {}; + this.emitter.fireEvent(this.onEnterEventId, data); + } + + } else if(this.isEntered) { + this.isEntered = false; + + if(this.onLeave !== null){ + this.onLeave(); + } + if(this.onLeaveEventId !== null){ + let data = {}; + this.emitter.fireEvent(this.onLeaveEventId, data); + } + } else if(this.isClicked) { + // If mouse is dragged off of element while down, it is not clicked anymore + this.isClicked = false; + } + } + + /** + * Overridable method for calculating background color - useful for elements that want to be colored on different after certain events + * @returns The background color of the UIElement + */ + calculateBackgroundColor(): Color { + return this.backgroundColor; + } + + /** + * Overridable method for calculating border color - useful for elements that want to be colored on different after certain events + * @returns The border color of the UIElement + */ + calculateBorderColor(): Color { + return this.borderColor; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/UIElements/Button.ts b/hw3/src/Wolfie2D/Nodes/UIElements/Button.ts new file mode 100644 index 0000000..8953854 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/UIElements/Button.ts @@ -0,0 +1,27 @@ +import Label from "./Label"; +import Color from "../../Utils/Color"; +import Vec2 from "../../DataTypes/Vec2"; + +/** A clickable button UIElement */ +export default class Button extends Label { + + constructor(position: Vec2, text: string){ + super(position, text); + + this.backgroundColor = new Color(150, 75, 203); + this.borderColor = new Color(41, 46, 30); + this.textColor = new Color(255, 255, 255); + } + + // @override + calculateBackgroundColor(): Color { + // Change the background color if clicked or hovered + if(this.isEntered && !this.isClicked){ + return this.backgroundColor.lighten(); + } else if(this.isClicked){ + return this.backgroundColor.darken(); + } else { + return this.backgroundColor; + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/UIElements/Label.ts b/hw3/src/Wolfie2D/Nodes/UIElements/Label.ts new file mode 100644 index 0000000..e89eb80 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/UIElements/Label.ts @@ -0,0 +1,152 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Color from "../../Utils/Color"; +import UIElement from "../UIElement"; + +/** A basic text-containing label */ +export default class Label extends UIElement{ + /** The color of the text of this UIElement */ + textColor: Color; + /** The value of the text of this UIElement */ + text: string; + /** The name of the font */ + font: string; + /** The size of the font */ + fontSize: number; + /** The horizontal alignment of the text within the label */ + protected hAlign: string; + /** The vertical alignment of text within the label */ + protected vAlign: string; + + /** A flag for if the width of the text has been measured on the canvas for auto width assignment */ + protected sizeAssigned: boolean; + + constructor(position: Vec2, text: string){ + super(position); + this.text = text; + this.textColor = new Color(0, 0, 0, 1); + this.font = "Arial"; + this.fontSize = 30; + this.hAlign = "center"; + this.vAlign = "center"; + + this.sizeAssigned = false; + } + + // @deprecated + setText(text: string): void { + this.text = text; + } + + // @deprecated + setTextColor(color: Color): void { + this.textColor = color; + } + + /** + * Gets a string containg the font details for rendering + * @returns A string containing the font details + */ + getFontString(): string { + return this.fontSize + "px " + this.font; + } + + /** + * Overridable method for calculating text color - useful for elements that want to be colored on different after certain events + * @returns a string containg the text color + */ + calculateTextColor(): string { + return this.textColor.toStringRGBA(); + } + + /** + * Uses the canvas to calculate the width of the text + * @param ctx The rendering context + * @returns A number representing the rendered text width + */ + protected calculateTextWidth(ctx: CanvasRenderingContext2D): number { + ctx.font = this.fontSize + "px " + this.font; + return ctx.measureText(this.text).width; + } + + setHAlign(align: string): void { + this.hAlign = align; + } + + setVAlign(align: string): void { + this.vAlign = align; + } + + /** + * Calculate the offset of the text - this is used for rendering text with different alignments + * @param ctx The rendering context + * @returns The offset of the text in a Vec2 + */ + calculateTextOffset(ctx: CanvasRenderingContext2D): Vec2 { + let textWidth = this.calculateTextWidth(ctx); + + let offset = new Vec2(0, 0); + + let hDiff = this.size.x - textWidth; + if(this.hAlign === HAlign.CENTER){ + offset.x = hDiff/2; + } else if (this.hAlign === HAlign.RIGHT){ + offset.x = hDiff; + } + + if(this.vAlign === VAlign.TOP){ + ctx.textBaseline = "top"; + offset.y = 0; + } else if (this.vAlign === VAlign.BOTTOM){ + ctx.textBaseline = "bottom"; + offset.y = this.size.y; + } else { + ctx.textBaseline = "middle"; + offset.y = this.size.y/2; + } + + return offset; + } + + protected sizeChanged(): void { + super.sizeChanged(); + this.sizeAssigned = true; + } + + /** + * Automatically sizes the element to the text within it + * @param ctx The rendering context + */ + protected autoSize(ctx: CanvasRenderingContext2D): void { + let width = this.calculateTextWidth(ctx); + let height = this.fontSize; + this.size.set(width + this.padding.x*2, height + this.padding.y*2); + this.sizeAssigned = true; + } + + /** + * Initially assigns a size to the UIElement if none is provided + * @param ctx The rendering context + */ + handleInitialSizing(ctx: CanvasRenderingContext2D): void { + if(!this.sizeAssigned){ + this.autoSize(ctx); + } + } + + /** On the next render, size this element to it's current text using its current font size */ + sizeToText(): void { + this.sizeAssigned = false; + } +} + +export enum VAlign { + TOP = "top", + CENTER = "center", + BOTTOM = "bottom" +} + +export enum HAlign { + LEFT = "left", + CENTER = "center", + RIGHT = "right" +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/UIElements/Slider.ts b/hw3/src/Wolfie2D/Nodes/UIElements/Slider.ts new file mode 100644 index 0000000..f9a88b4 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/UIElements/Slider.ts @@ -0,0 +1,64 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Input from "../../Input/Input"; +import Color from "../../Utils/Color"; +import MathUtils from "../../Utils/MathUtils"; +import UIElement from "../UIElement"; + +/** A slider UIElement */ +export default class Slider extends UIElement { + /** The value of the slider from [0, 1] */ + protected value: number; + /** The color of the slider nib */ + public nibColor: Color; + /** The size of the nib */ + public nibSize: Vec2; + /** The color of the slider track */ + public sliderColor: Color; + /** The reaction of this UIElement to a value change */ + public onValueChange: Function; + /** The event propagated by this UIElement when value changes */ + public onValueChangeEventId: string; + + constructor(position: Vec2, initValue: number){ + super(position); + + this.value = initValue; + this.nibColor = Color.RED; + this.sliderColor = Color.BLACK; + this.backgroundColor = Color.TRANSPARENT; + this.borderColor = Color.TRANSPARENT; + this.nibSize = new Vec2(10, 20); + + // Set a default size + this.size.set(200, 20); + } + + /** + * Retrieves the value of the slider + * @returns The value of the slider + */ + getValue(): number { + return this.value; + } + + /** A method called in response to the value changing */ + protected valueChanged(): void { + if(this.onValueChange){ + this.onValueChange(this.value); + } + + if(this.onValueChangeEventId){ + this.emitter.fireEvent(this.onValueChangeEventId, {target: this, value: this.value}); + } + } + + update(deltaT: number): void { + super.update(deltaT); + + if(this.isClicked){ + let val = MathUtils.invLerp(this.position.x - this.size.x/2, this.position.x + this.size.x/2, Input.getMousePosition().x); + this.value = MathUtils.clamp01(val); + this.valueChanged(); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/UIElements/TextInput.ts b/hw3/src/Wolfie2D/Nodes/UIElements/TextInput.ts new file mode 100644 index 0000000..0bae845 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/UIElements/TextInput.ts @@ -0,0 +1,64 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Color from "../../Utils/Color"; +import Label from "./Label"; +import Input from "../../Input/Input"; + +/** A text input UIElement */ +export default class TextInput extends Label { + /** A flag the represents whether the user can type in this TextInput */ + focused: boolean; + /** The position of the cursor in this TextInput */ + cursorCounter: number; + + constructor(position: Vec2){ + super(position, ""); + + this.focused = false; + this.cursorCounter = 0; + + // Give a default size to the x only + this.size.set(200, this.fontSize); + this.hAlign = "left"; + + this.borderColor = Color.BLACK; + this.backgroundColor = Color.WHITE; + } + + update(deltaT: number): void { + super.update(deltaT); + + if(Input.isMouseJustPressed()){ + let clickPos = Input.getMousePressPosition(); + if(this.contains(clickPos.x, clickPos.y)){ + this.focused = true; + this.cursorCounter = 30; + } else { + this.focused = false; + } + } + + if(this.focused){ + let keys = Input.getKeysJustPressed(); + let nums = "1234567890"; + let specialChars = "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?"; + let letters = "qwertyuiopasdfghjklzxcvbnm"; + let mask = nums + specialChars + letters; + keys = keys.filter(key => mask.includes(key)); + let shiftPressed = Input.isKeyPressed("shift"); + let backspacePressed = Input.isKeyJustPressed("backspace"); + let spacePressed = Input.isKeyJustPressed("space"); + + if(backspacePressed){ + this.text = this.text.substring(0, this.text.length - 1); + } else if(spacePressed){ + this.text += " "; + } else if(keys.length > 0) { + if(shiftPressed){ + this.text += keys[0].toUpperCase(); + } else { + this.text += keys[0]; + } + } + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Nodes/UIElements/UIElementTypes.ts b/hw3/src/Wolfie2D/Nodes/UIElements/UIElementTypes.ts new file mode 100644 index 0000000..6530db2 --- /dev/null +++ b/hw3/src/Wolfie2D/Nodes/UIElements/UIElementTypes.ts @@ -0,0 +1,6 @@ +export enum UIElementType { + BUTTON = "BUTTON", + LABEL = "LABEL", + SLIDER = "SLIDER", + TEXT_INPUT = "TEXTINPUT" +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Pathfinding/NavigationManager.ts b/hw3/src/Wolfie2D/Pathfinding/NavigationManager.ts new file mode 100644 index 0000000..1daf89d --- /dev/null +++ b/hw3/src/Wolfie2D/Pathfinding/NavigationManager.ts @@ -0,0 +1,39 @@ +import Navigable from "../DataTypes/Interfaces/Navigable"; +import Map from "../DataTypes/Map"; +import Vec2 from "../DataTypes/Vec2"; +import NavigationPath from "./NavigationPath"; + +/** + * The manager class for navigation. + * Handles all navigable entities, such and allows them to be accessed by outside systems by requesting a path + * from one position to another. + */ +export default class NavigationManager { + /** The list of all navigable entities */ + protected navigableEntities: Map; + + constructor(){ + this.navigableEntities = new Map(); + } + + /** + * Adds a navigable entity to the NavigationManager + * @param navName The name of the navigable entitry + * @param nav The actual Navigable instance + */ + addNavigableEntity(navName: string, nav: Navigable): void { + this.navigableEntities.add(navName, nav); + } + + /** + * Gets a path frome one point to another using a specified Navigable object + * @param navName The name of the registered Navigable object + * @param fromPosition The starting position of navigation + * @param toPosition The ending position of Navigation + * @returns A NavigationPath containing the route to take over the Navigable entity to get between the provided positions. + */ + getPath(navName: string, fromPosition: Vec2, toPosition: Vec2): NavigationPath { + let nav = this.navigableEntities.get(navName); + return nav.getNavigationPath(fromPosition.clone(), toPosition.clone()); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Pathfinding/NavigationPath.ts b/hw3/src/Wolfie2D/Pathfinding/NavigationPath.ts new file mode 100644 index 0000000..52ff112 --- /dev/null +++ b/hw3/src/Wolfie2D/Pathfinding/NavigationPath.ts @@ -0,0 +1,58 @@ +import Stack from "../DataTypes/Stack"; +import Vec2 from "../DataTypes/Vec2"; +import GameNode from "../Nodes/GameNode"; + +/** + * A path that AIs can follow. Uses finishMove() in Physical to determine progress on the route + */ +export default class NavigationPath { + /** The navigation path, stored as a stack of next positions */ + protected path: Stack; + /** The current direction of movement */ + protected currentMoveDirection: Vec2; + /** The distance a node must be to a point to consider it as having arrived */ + protected distanceThreshold: number; + + /** + * Constructs a new NavigationPath + * @param path The path of nodes to take + */ + constructor(path: Stack){ + this.path = path; + this.currentMoveDirection = Vec2.ZERO; + this.distanceThreshold = 4; + } + + /** + * Returns the status of navigation along this NavigationPath + * @returns True if the node has reached the end of the path, false otherwise + */ + isDone(): boolean { + return this.path.isEmpty(); + } + + /** + * Gets the movement direction in the current position along the path + * @param node The node to move along the path + * @returns The movement direction as a Vec2 + */ + getMoveDirection(node: GameNode): Vec2 { + // Return direction to next point in the nav + return node.position.dirTo(this.path.peek()); + } + + /** + * Updates this NavigationPath to the current state of the GameNode + * @param node The node moving along the path + */ + handlePathProgress(node: GameNode): void { + if(node.position.distanceSqTo(this.path.peek()) < this.distanceThreshold*this.distanceThreshold){ + // We've reached our node, move on to the next destination + this.path.pop(); + } + } + + toString(): string { + return this.path.toString() + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Pathfinding/Navmesh.ts b/hw3/src/Wolfie2D/Pathfinding/Navmesh.ts new file mode 100644 index 0000000..4b62765 --- /dev/null +++ b/hw3/src/Wolfie2D/Pathfinding/Navmesh.ts @@ -0,0 +1,67 @@ +import PositionGraph from "../DataTypes/Graphs/PositionGraph"; +import Navigable from "../DataTypes/Interfaces/Navigable"; +import Stack from "../DataTypes/Stack"; +import Vec2 from "../DataTypes/Vec2"; +import GraphUtils from "../Utils/GraphUtils"; +import NavigationPath from "./NavigationPath"; + +/** + * An implementation of a Navmesh. Navmeshes are graphs in the game world along which nodes can move. + */ +export default class Navmesh implements Navigable { + /** The graph of points in the NavMesh */ + protected graph: PositionGraph; + + /** + * Creates a new Navmesh from the points in the speecified graph + * @param graph The graph to construct a navmesh from + */ + constructor(graph: PositionGraph){ + this.graph = graph; + } + + // @implemented + getNavigationPath(fromPosition: Vec2, toPosition: Vec2): NavigationPath { + let start = this.getClosestNode(fromPosition); + let end = this.getClosestNode(toPosition); + + let parent = GraphUtils.djikstra(this.graph, start); + + let pathStack = new Stack(this.graph.numVertices); + + // Push the final position and the final position in the graph + pathStack.push(toPosition.clone()); + pathStack.push(this.graph.positions[end]); + + // Add all parents along the path + let i = end; + while(parent[i] !== -1){ + pathStack.push(this.graph.positions[parent[i]]); + i = parent[i]; + } + + return new NavigationPath(pathStack); + } + + /** + * Gets the closest node in this Navmesh to the specified position + * @param position The position to query + * @returns The index of the closest node in the Navmesh to the position + */ + protected getClosestNode(position: Vec2): number { + let n = this.graph.numVertices; + let i = 1; + let index = 0; + let dist = position.distanceSqTo(this.graph.positions[0]); + while(i < n){ + let d = position.distanceSqTo(this.graph.positions[i]); + if(d < dist){ + dist = d; + index = i; + } + i++; + } + + return index; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Physics/BasicPhysicsManager.ts b/hw3/src/Wolfie2D/Physics/BasicPhysicsManager.ts new file mode 100644 index 0000000..0b5086a --- /dev/null +++ b/hw3/src/Wolfie2D/Physics/BasicPhysicsManager.ts @@ -0,0 +1,349 @@ +import GameNode from "../Nodes/GameNode"; +import Physical from "../DataTypes/Interfaces/Physical"; +import Tilemap from "../Nodes/Tilemap"; +import PhysicsManager from "./PhysicsManager"; +import Vec2 from "../DataTypes/Vec2"; +import AABB from "../DataTypes/Shapes/AABB"; +import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap"; +import AreaCollision from "../DataTypes/Physics/AreaCollision"; +import Unique from "../DataTypes/Interfaces/Unique"; + +/** + * ALGORITHM: + * In an effort to keep things simple and working effectively, each dynamic node will resolve its + * collisions considering the rest of the world as static. + * + * Collision detecting will happen first. This can be considered a broad phase, but it is not especially + * efficient, as it does not need to be for this game engine. Every dynamic node is checked against every + * other node for collision area. If collision area is non-zero (meaning the current node sweeps into another), + * it is added to a list of hits. + * + * INITIALIZATION: + * - Physics constants are reset + * - Swept shapes are recalculated. If a node isn't moving, it is skipped. + * + * COLLISION DETECTION: + * - For a node, collision area will be calculated using the swept AABB of the node against every other AABB in a static state + * - These collisions will be sorted by area in descending order + * + * COLLISION RESOLUTION: + * - For each hit, time of collision is calculated using a swept line through the AABB of the static node expanded + * with minkowski sums (discretely, but the concept is there) + * - The collision is resolved based on the near time of the collision (from method of separated axes) + * - X is resolved by near x, Y by near y. + * - There is some fudging to allow for sliding along walls of separate colliders. Sorting by area also helps with this. + * - Corner to corner collisions are resolve to favor x-movement. This is in consideration of platformers, to give + * the player some help with jumps + * + * Pros: + * - Everything happens with a consistent time. There is a distinct before and after for each resolution. + * - No back-tracking needs to be done. Once we resolve a node, it is definitively resolved. + * + * Cons: + * - Nodes that are processed early have movement priority over other nodes. This can lead to some undesirable interactions. + */ +export default class BasicPhysicsManager extends PhysicsManager { + + /** The array of static nodes */ + protected staticNodes: Array; + + /** The array of dynamic nodes */ + protected dynamicNodes: Array; + + /** The array of tilemaps */ + protected tilemaps: Array; + + /** An array of the collision masks for each group */ + protected collisionMasks: Array; + + constructor(options: Record){ + super(); + this.staticNodes = new Array(); + this.dynamicNodes = new Array(); + this.tilemaps = new Array(); + this.collisionMasks = new Array(32); + + // Parse options + this.parseOptions(options); + } + + /** + * Parses the options for constructing the physics manager + * @param options A record of options + */ + protected parseOptions(options: Record): void { + if(options.groupNames !== undefined && options.collisions !== undefined){ + for(let i = 0; i < options.groupNames.length; i++){ + let group = options.groupNames[i]; + + // Register the group name and number + this.groupNames[i] = group; + + this.groupMap.set(group, 1 << i); + + let collisionMask = 0; + + for(let j = 0; j < options.collisions[i].length; j++){ + if(options.collisions[i][j]){ + collisionMask |= 1 << j; + } + } + + this.collisionMasks[i] = collisionMask; + } + } + } + + // @override + registerObject(node: Physical): void { + if(node.isStatic){ + // Static and not collidable + this.staticNodes.push(node); + } else { + // Dynamic and not collidable + this.dynamicNodes.push(node); + } + } + + // @override + deregisterObject(node: Physical): void { + if(node.isStatic){ + // Remove the node from the static list + const index = this.staticNodes.indexOf(node); + this.staticNodes.splice(index, 1); + } else { + // Remove the node from the dynamic list + const index = this.dynamicNodes.indexOf(node); + this.dynamicNodes.splice(index, 1); + } + } + + // @override + registerTilemap(tilemap: Tilemap): void { + this.tilemaps.push(tilemap); + } + + // @override + deregisterTilemap(tilemap: Tilemap): void { + const index = this.tilemaps.indexOf(tilemap); + this.tilemaps.splice(index, 1); + } + + // @override + update(deltaT: number): void { + for(let node of this.dynamicNodes){ + /*---------- INITIALIZATION PHASE ----------*/ + // Clear frame dependent boolean values for each node + node.onGround = false; + node.onCeiling = false; + node.onWall = false; + node.collidedWithTilemap = false; + node.isColliding = false; + + // If this node is not active, don't process it + if(!node.active){ + continue; + } + + // Update the swept shapes of each node + if(node.moving){ + // If moving, reflect that in the swept shape + node.sweptRect.sweep(node._velocity, node.collisionShape.center, node.collisionShape.halfSize); + } else { + // If our node isn't moving, don't bother to check it (other nodes will detect if they run into it) + node._velocity.zero(); + continue; + } + + /*---------- DETECTION PHASE ----------*/ + // Gather a set of overlaps + let overlaps = new Array(); + + let groupIndex = node.group === -1 ? -1 : Math.log2(node.group); + + // First, check this node against every static node (order doesn't actually matter here, since we sort anyways) + for(let other of this.staticNodes){ + // Ignore inactive nodes + if(!other.active) continue; + + let collider = other.collisionShape.getBoundingRect(); + let area = node.sweptRect.overlapArea(collider); + if(area > 0){ + // We had a collision + overlaps.push(new AreaCollision(area, collider, other, "GameNode", null)); + } + } + + // Then, check it against every dynamic node + for(let other of this.dynamicNodes){ + // Ignore ourselves + if(node === other) continue; + + // Ignore inactive nodes + if(!other.active) continue; + + let collider = other.collisionShape.getBoundingRect(); + let area = node.sweptRect.overlapArea(collider); + if(area > 0){ + // We had a collision + overlaps.push(new AreaCollision(area, collider, other, "GameNode", null)); + } + } + + // Lastly, gather a set of AABBs from the tilemap. + // This step involves the most extra work, so it is abstracted into a method + for(let tilemap of this.tilemaps){ + // Ignore inactive tilemaps + if(!tilemap.active) continue; + + if(tilemap instanceof OrthogonalTilemap){ + this.collideWithOrthogonalTilemap(node, tilemap, overlaps); + } + } + + // Sort the overlaps by area + overlaps = overlaps.sort((a, b) => b.area - a.area); + + // Keep track of hits to use later + let hits = []; + + /*---------- RESOLUTION PHASE ----------*/ + // For every overlap, determine if we need to collide with it and when + for(let overlap of overlaps){ + // Ignore nodes we don't interact with + if( groupIndex !== -1 && overlap.other.group !== -1 && ((this.collisionMasks[groupIndex] & overlap.other.group) === 0) ) continue; + + // Do a swept line test on the static AABB with this AABB size as padding (this is basically using a minkowski sum!) + // Start the sweep at the position of this node with a delta of _velocity + const point = node.collisionShape.center; + const delta = node._velocity; + const padding = node.collisionShape.halfSize; + const otherAABB = overlap.collider; + + + const hit = otherAABB.intersectSegment(node.collisionShape.center, node._velocity, node.collisionShape.halfSize); + + overlap.hit = hit; + + if(hit !== null){ + hits.push(hit); + + // We got a hit, resolve with the time inside of the hit + let tnearx = hit.nearTimes.x; + let tneary = hit.nearTimes.y; + + // Allow edge clipping (edge overlaps don't count, only area overlaps) + // Importantly don't allow both cases to be true. Then we clip through corners. Favor x to help players land jumps + if(tnearx < 1.0 && (point.y === otherAABB.top - padding.y || point.y === otherAABB.bottom + padding.y) && delta.x !== 0) { + tnearx = 1.0; + } else if(tneary < 1.0 && (point.x === otherAABB.left - padding.x || point.x === otherAABB.right + padding.x) && delta.y !== 0) { + tneary = 1.0; + } + + + if(hit.nearTimes.x >= 0 && hit.nearTimes.x < 1){ + // Any tilemap objects that made it here are collidable + if(overlap.type === "Tilemap" || overlap.other.isCollidable){ + node._velocity.x = node._velocity.x * tnearx; + node.isColliding = true; + } + } + + if(hit.nearTimes.y >= 0 && hit.nearTimes.y < 1){ + // Any tilemap objects that made it here are collidable + if(overlap.type === "Tilemap" || overlap.other.isCollidable){ + node._velocity.y = node._velocity.y * tneary; + node.isColliding = true; + } + } + } + } + + /*---------- INFORMATION/TRIGGER PHASE ----------*/ + // Check if we ended up on the ground, ceiling or wall + // Also check for triggers + for(let overlap of overlaps){ + // Check for a trigger. If we care about the trigger, react + if(overlap.other.isTrigger && (overlap.other.triggerMask & node.group)){ + // Get the bit that this group is represented by + let index = Math.floor(Math.log2(node.group)); + + // Extract the triggerEnter event name + this.emitter.fireEvent(overlap.other.triggerEnters[index], { + node: (node).id, + other: (overlap.other).id + }); + } + + // Ignore collision sides for nodes we don't interact with + if( groupIndex !== -1 && overlap.other.group !== -1 && ((this.collisionMasks[groupIndex] & overlap.other.group) === 0)) continue; + + // Only check for direction if the overlap was collidable + if(overlap.type === "Tilemap" || overlap.other.isCollidable){ + let collisionSide = overlap.collider.touchesAABBWithoutCorners(node.collisionShape.getBoundingRect()); + if(collisionSide !== null){ + // If we touch, not including corner cases, check the collision normal + if(overlap.hit !== null){ + // If we hit a tilemap, keep track of it + if(overlap.type == "Tilemap"){ + node.collidedWithTilemap = true; + } + + if(collisionSide.y === -1){ + // Node is on top of overlap, so onGround + node.onGround = true; + } else if(collisionSide.y === 1){ + // Node is on bottom of overlap, so onCeiling + node.onCeiling = true; + } else { + // Node wasn't touching on y, so it is touching on x + node.onWall = true; + } + } + } + } + } + + // Resolve the collision with the node, and move it + node.finishMove(); + } + } + + /** + * Handles a collision between this node and an orthogonal tilemap + * @param node The node + * @param tilemap The tilemap the node may be colliding with + * @param overlaps The list of overlaps + */ + protected collideWithOrthogonalTilemap(node: Physical, tilemap: OrthogonalTilemap, overlaps: Array): void { + // Get the min and max x and y coordinates of the moving node + let min = new Vec2(node.sweptRect.left, node.sweptRect.top); + let max = new Vec2(node.sweptRect.right, node.sweptRect.bottom); + + // Convert the min/max x/y to the min and max row/col in the tilemap array + let minIndex = tilemap.getColRowAt(min); + let maxIndex = tilemap.getColRowAt(max); + + let tileSize = tilemap.getTileSize(); + + // Loop over all possible tiles (which isn't many in the scope of the velocity per frame) + for(let col = minIndex.x; col <= maxIndex.x; col++){ + for(let row = minIndex.y; row <= maxIndex.y; row++){ + if(tilemap.isTileCollidable(col, row)){ + // Get the position of this tile + let tilePos = new Vec2(col * tileSize.x + tileSize.x/2, row * tileSize.y + tileSize.y/2); + + // Create a new collider for this tile + let collider = new AABB(tilePos, tileSize.scaled(1/2)); + + // Calculate collision area between the node and the tile + let area = node.sweptRect.overlapArea(collider); + if(area > 0){ + // We had a collision + overlaps.push(new AreaCollision(area, collider, tilemap, "Tilemap", new Vec2(col, row))); + } + } + } + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Physics/PhysicsManager.ts b/hw3/src/Wolfie2D/Physics/PhysicsManager.ts new file mode 100644 index 0000000..b35bccd --- /dev/null +++ b/hw3/src/Wolfie2D/Physics/PhysicsManager.ts @@ -0,0 +1,112 @@ +import Updateable from "../DataTypes/Interfaces/Updateable"; +import Tilemap from "../Nodes/Tilemap"; +import Receiver from "../Events/Receiver"; +import Emitter from "../Events/Emitter"; +import Map from "../DataTypes/Map"; +import Physical from "../DataTypes/Interfaces/Physical"; + +/** + * An abstract physics manager. + * This class exposes functions for subclasses to implement that should allow for a working physics system to be created. + */ +export default abstract class PhysicsManager implements Updateable { + /** The event receiver for the physics system */ + protected receiver: Receiver; + /** The event emitter for the physics system */ + protected emitter: Emitter; + + /** Maps layer names to numbers */ + protected groupMap: Map; + + /** Maps layer numbers to names */ + protected groupNames: Array; + + /** The default group name */ + protected static readonly DEFAULT_GROUP = "Default"; + + constructor(){ + this.receiver = new Receiver(); + this.emitter = new Emitter(); + + // The creation and implementation of layers is deferred to the subclass + this.groupMap = new Map(); + this.groupNames = new Array(); + } + + destroy(): void { + this.receiver.destroy(); + } + + /** + * Registers a gamenode with this physics manager + * @param object The object to register + */ + abstract registerObject(object: Physical): void; + + + /** + * Removes references to this object from the physics managerr + * @param object The object to deregister + */ + abstract deregisterObject(object: Physical): void; + + /** + * Registers a tilemap with this physics manager + * @param tilemap The tilemap to register + */ + abstract registerTilemap(tilemap: Tilemap): void; + + /** + * Removes references to this tilemap from the physics managerr + * @param tilemap The object to deregister + */ + abstract deregisterTilemap(tilemap: Tilemap): void; + + abstract update(deltaT: number): void; + + /** + * Sets the physics layer of the GameNode + * @param node The GameNode + * @param group The group that the GameNode should be on + */ + setGroup(node: Physical, group: string): void { + node.group = this.groupMap.get(group); + } + + /** + * Retrieves the layer number associated with the provided name + * @param layer The name of the layer + * @returns The layer number, or 0 if there is not a layer with that name registered + */ + getGroupNumber(group: string): number { + if(this.groupMap.has(group)){ + return this.groupMap.get(group); + } else{ + return 0; + } + } + + /** + * Gets all group names associated with the number provided + * @param groups A mask of groups + * @returns All groups contained in the mask + */ + getGroupNames(groups: number): Array { + if(groups === -1){ + return [PhysicsManager.DEFAULT_GROUP]; + } else { + let g = 1; + let names = []; + + for(let i = 0; i < 32; i++){ + if(g & groups){ + // This group is in the groups number + names.push(this.groupNames[i]); + } + + // Shift the bit over + g = g << 1; + } + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Playback/Recorder.ts b/hw3/src/Wolfie2D/Playback/Recorder.ts new file mode 100644 index 0000000..676cb09 --- /dev/null +++ b/hw3/src/Wolfie2D/Playback/Recorder.ts @@ -0,0 +1,93 @@ +import Queue from "../DataTypes/Queue"; +import Receiver from "../Events/Receiver"; +import GameEvent from "../Events/GameEvent"; +import EventQueue from "../Events/EventQueue"; +import { GameEventType } from "../Events/GameEventType"; + +// @ignorePage + +export default class Recorder { + private receiver: Receiver; + private log: Queue; + private recording: boolean; + private eventQueue: EventQueue; + private frame: number; + private playing: boolean; + + constructor(){ + this.receiver = new Receiver(); + this.log = new Queue(1000); + this.recording = false; + this.playing = false; + this.frame = 0; + + this.eventQueue = EventQueue.getInstance(); + this.eventQueue.subscribe(this.receiver, "all"); + } + + update(deltaT: number): void { + if(this.recording){ + this.frame += 1; + } + + if(this.playing){ + // If playing, ignore events, just feed the record to the event queue + this.receiver.ignoreEvents(); + + /* + While there is a next item, and while it should occur in this frame, + send the event. i.e., while current_frame * current_delta_t is greater + than recorded_frame * recorded_delta_t + */ + while(this.log.hasItems() + && this.log.peekNext().frame * this.log.peekNext().delta < this.frame * deltaT){ + let event = this.log.dequeue().event; + console.log(event); + this.eventQueue.addEvent(event); + } + + if(!this.log.hasItems()){ + this.playing = false; + } + + this.frame += 1; + } else { + // If not playing, handle events + while(this.receiver.hasNextEvent()){ + let event = this.receiver.getNextEvent(); + + if(event.type === GameEventType.STOP_RECORDING){ + this.recording = false; + } + + if(this.recording){ + this.log.enqueue(new LogItem(this.frame, deltaT, event)); + } + + if(event.type === GameEventType.START_RECORDING){ + this.log.clear(); + this.recording = true; + this.frame = 0 + } + + if(event.type === GameEventType.PLAY_RECORDING){ + this.frame = 0; + this.recording = false; + this.playing = true; + } + } + } + } +} + +class LogItem { + frame: number; + delta: number; + event: GameEvent; + + constructor(frame: number, deltaT: number, event: GameEvent){ + this.frame = frame; + this.delta = deltaT; + this.event = event; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Registry/Registries/FontRegistry.ts b/hw3/src/Wolfie2D/Registry/Registries/FontRegistry.ts new file mode 100644 index 0000000..e69de29 diff --git a/hw3/src/Wolfie2D/Registry/Registries/Registry.ts b/hw3/src/Wolfie2D/Registry/Registries/Registry.ts new file mode 100644 index 0000000..f67d135 --- /dev/null +++ b/hw3/src/Wolfie2D/Registry/Registries/Registry.ts @@ -0,0 +1,21 @@ +import Map from "../../DataTypes/Map"; + +export default abstract class Registry extends Map{ + + /** Preloads registry data */ + public abstract preload(): void; + + /** + * Registers an item and preloads any necessary files + * @param key The key to register this item with + * @param args Any additional arguments needed for registration + */ + public abstract registerAndPreloadItem(key: string, ...args: any): void; + + /** + * Registers an item and preloads any necessary files + * @param key The key to register this item with + * @param args Any aditional arguments needed for registration + */ + public abstract registerItem(key: string, ...args: any): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Registry/Registries/ShaderRegistry.ts b/hw3/src/Wolfie2D/Registry/Registries/ShaderRegistry.ts new file mode 100644 index 0000000..7e566a3 --- /dev/null +++ b/hw3/src/Wolfie2D/Registry/Registries/ShaderRegistry.ts @@ -0,0 +1,99 @@ +import Map from "../../DataTypes/Map"; +import ShaderType from "../../Rendering/WebGLRendering/ShaderType"; +import LabelShaderType from "../../Rendering/WebGLRendering/ShaderTypes/LabelShaderType"; +import PointShaderType from "../../Rendering/WebGLRendering/ShaderTypes/PointShaderType"; +import RectShaderType from "../../Rendering/WebGLRendering/ShaderTypes/RectShaderType"; +import SpriteShaderType from "../../Rendering/WebGLRendering/ShaderTypes/SpriteShaderType"; +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Registry from "./Registry"; + +/** + * A registry that handles shaders + */ +export default class ShaderRegistry extends Registry { + + // Shader names + public static POINT_SHADER = "point"; + public static RECT_SHADER = "rect"; + public static SPRITE_SHADER = "sprite"; + public static LABEL_SHADER = "label"; + + private registryItems: Array = new Array(); + + /** + * Preloads all built-in shaders + */ + public preload(){ + // Get the resourceManager and queue all built-in shaders for preloading + const rm = ResourceManager.getInstance(); + + // Queue a load for the point shader + this.registerAndPreloadItem(ShaderRegistry.POINT_SHADER, PointShaderType, "builtin/shaders/point.vshader", "builtin/shaders/point.fshader"); + + // Queue a load for the rect shader + this.registerAndPreloadItem(ShaderRegistry.RECT_SHADER, RectShaderType, "builtin/shaders/rect.vshader", "builtin/shaders/rect.fshader"); + + // Queue a load for the sprite shader + this.registerAndPreloadItem(ShaderRegistry.SPRITE_SHADER, SpriteShaderType, "builtin/shaders/sprite.vshader", "builtin/shaders/sprite.fshader"); + + // Queue a load for the label shader + this.registerAndPreloadItem(ShaderRegistry.LABEL_SHADER, LabelShaderType, "builtin/shaders/label.vshader", "builtin/shaders/label.fshader"); + + // Queue a load for any preloaded items + for(let item of this.registryItems){ + const shader = new item.constr(item.key); + shader.initBufferObject(); + this.add(item.key, shader); + + // Load if desired + if(item.preload !== undefined){ + rm.shader(item.key, item.preload.vshaderLocation, item.preload.fshaderLocation); + } + } + } + + /** + * Registers a shader in the registry and loads it before the game begins + * @param key The key you wish to assign to the shader + * @param constr The constructor of the ShaderType + * @param vshaderLocation The location of the vertex shader + * @param fshaderLocation the location of the fragment shader + */ + public registerAndPreloadItem(key: string, constr: new (programKey: string) => ShaderType, vshaderLocation: string, fshaderLocation: string): void { + let shaderPreload = new ShaderPreload(); + shaderPreload.vshaderLocation = vshaderLocation; + shaderPreload.fshaderLocation = fshaderLocation; + + let registryItem = new ShaderRegistryItem(); + registryItem.key = key; + registryItem.constr = constr; + registryItem.preload = shaderPreload; + + this.registryItems.push(registryItem); + } + + /** + * Registers a shader in the registry. NOTE: If you use this, you MUST load the shader before use. + * If you wish to preload the shader, use registerAndPreloadItem() + * @param key The key you wish to assign to the shader + * @param constr The constructor of the ShaderType + */ + public registerItem(key: string, constr: new (programKey: string) => ShaderType): void { + let registryItem = new ShaderRegistryItem(); + registryItem.key = key; + registryItem.constr = constr; + + this.registryItems.push(registryItem); + } +} + +class ShaderRegistryItem { + key: string; + constr: new (programKey: string) => ShaderType; + preload: ShaderPreload; +} + +class ShaderPreload { + vshaderLocation: string; + fshaderLocation: string; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Registry/RegistryManager.ts b/hw3/src/Wolfie2D/Registry/RegistryManager.ts new file mode 100644 index 0000000..d3cd802 --- /dev/null +++ b/hw3/src/Wolfie2D/Registry/RegistryManager.ts @@ -0,0 +1,31 @@ +import Map from "../DataTypes/Map"; +import Registry from "./Registries/Registry"; +import ShaderRegistry from "./Registries/ShaderRegistry"; + +/** + * The Registry is the system's way of converting classes and types into string + * representations for use elsewhere in the application. + * It allows classes to be accessed without explicitly using constructors in code, + * and for resources to be loaded at Game creation time. + */ +export default class RegistryManager { + + public static shaders = new ShaderRegistry(); + + /** Additional custom registries to add to the registry manager */ + protected static registries: Map> = new Map(); + + static preload(){ + this.shaders.preload(); + + this.registries.forEach((key: string) => this.registries.get(key).preload()); + } + + static addCustomRegistry(name: string, registry: Registry){ + this.registries.add(name, registry); + } + + static getRegistry(key: string){ + return this.registries.get(key); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/Animations/AnimationManager.ts b/hw3/src/Wolfie2D/Rendering/Animations/AnimationManager.ts new file mode 100644 index 0000000..a976ef3 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/Animations/AnimationManager.ts @@ -0,0 +1,228 @@ +import Map from "../../DataTypes/Map"; +import Emitter from "../../Events/Emitter"; +import CanvasNode from "../../Nodes/CanvasNode"; +import { AnimationData, AnimationState } from "./AnimationTypes"; + +/** + * An animation manager class for an animated CanvasNode. + * This class keeps track of the possible animations, as well as the current animation state, + * and abstracts all interactions with playing, pausing, and stopping animations as well as + * creating new animations from the CanvasNode. + */ +export default class AnimationManager { + /** The owner of this animation manager */ + protected owner: CanvasNode; + + /** The current animation state of this sprite */ + protected animationState: AnimationState; + + /** The name of the current animation of this sprite */ + protected currentAnimation: string; + + /** The current frame of this animation */ + protected currentFrame: number; + + /** The progress of the current animation through the current frame */ + protected frameProgress: number; + + /** Whether the current animation is looping or not */ + protected loop: boolean; + + /** The map of animations */ + protected animations: Map; + + /** The name of the event (if any) to send when the current animation stops playing. */ + protected onEndEvent: string; + + /** The event emitter for this animation manager */ + protected emitter: Emitter; + + /** A queued animation */ + protected pendingAnimation: string; + + /** The loop status of a pending animation */ + protected pendingLoop: boolean; + + /** The onEnd event of a pending animation */ + protected pendingOnEnd: string; + + /** + * Creates a new AnimationManager + * @param owner The owner of the AnimationManager + */ + constructor(owner: CanvasNode){ + this.owner = owner; + this.animationState = AnimationState.STOPPED; + this.currentAnimation = ""; + this.currentFrame = 0; + this.frameProgress = 0; + this.loop = false; + this.animations = new Map(); + this.onEndEvent = null; + this.emitter = new Emitter(); + } + + /** + * Add an animation to this sprite + * @param key The unique key of the animation + * @param animation The animation data + */ + add(key: string, animation: AnimationData): void { + this.animations.add(key, animation); + } + + /** + * Gets the index specified by the current animation and current frame + * @returns The index in the current animation + */ + getIndex(): number { + if(this.animations.has(this.currentAnimation)){ + return this.animations.get(this.currentAnimation).frames[this.currentFrame].index; + } else { + // No current animation, warn the user + console.warn(`Animation index was requested, but the current animation: ${this.currentAnimation} was invalid`); + return 0; + } + } + + /** + * Determines whether the specified animation is currently playing + * @param key The key of the animation to check + * @returns true if the specified animation is playing, false otherwise + */ + isPlaying(key: string): boolean { + return this.currentAnimation === key && this.animationState === AnimationState.PLAYING; + } + + /** + * Retrieves the current animation index and advances the animation frame + * @returns The index of the animation frame + */ + getIndexAndAdvanceAnimation(): number { + // If we aren't playing, we won't be advancing the animation + if(!(this.animationState === AnimationState.PLAYING)){ + return this.getIndex(); + } + + if(this.animations.has(this.currentAnimation)){ + let currentAnimation = this.animations.get(this.currentAnimation); + let index = currentAnimation.frames[this.currentFrame].index; + + // Advance the animation + this.frameProgress += 1; + if(this.frameProgress >= currentAnimation.frames[this.currentFrame].duration){ + // We have been on this frame for its whole duration, go to the next one + this.frameProgress = 0; + this.currentFrame += 1; + + if(this.currentFrame >= currentAnimation.frames.length){ + // We have reached the end of this animation + if(this.loop){ + this.currentFrame = 0; + this.frameProgress = 0; + } else { + this.endCurrentAnimation(); + } + } + } + + // Return the current index + return index; + } else { + // No current animation, can't advance. Warn the user + console.warn(`Animation index and advance was requested, but the current animation (${this.currentAnimation}) in node with id: ${this.owner.id} was invalid`); + return 0; + } + } + + /** Ends the current animation and fires any necessary events, as well as starting any new animations */ + protected endCurrentAnimation(): void { + this.currentFrame = 0; + this.animationState = AnimationState.STOPPED; + + if(this.onEndEvent !== null){ + this.emitter.fireEvent(this.onEndEvent, {owner: this.owner.id, animation: this.currentAnimation}); + } + + // If there is a pending animation, play it + if(this.pendingAnimation !== null){ + this.play(this.pendingAnimation, this.pendingLoop, this.pendingOnEnd); + } + } + + /** + * Plays the specified animation. Does not restart it if it is already playing + * @param animation The name of the animation to play + * @param loop Whether or not to loop the animation. False by default + * @param onEnd The name of an event to send when this animation naturally stops playing. This only matters if loop is false. + */ + playIfNotAlready(animation: string, loop?: boolean, onEnd?: string): void { + if(this.currentAnimation !== animation){ + this.play(animation, loop, onEnd); + } + } + + /** + * Plays the specified animation + * @param animation The name of the animation to play + * @param loop Whether or not to loop the animation. False by default + * @param onEnd The name of an event to send when this animation naturally stops playing. This only matters if loop is false. + */ + play(animation: string, loop?: boolean, onEnd?: string): void { + this.currentAnimation = animation; + this.currentFrame = 0; + this.frameProgress = 0; + this.animationState = AnimationState.PLAYING; + + // If loop arg was provided, use that + if(loop !== undefined){ + this.loop = loop; + } else { + // Otherwise, use what the json file specified + this.loop = this.animations.get(animation).repeat; + } + + if(onEnd !== undefined){ + this.onEndEvent = onEnd; + } else { + this.onEndEvent = null; + } + + // Reset pending animation + this.pendingAnimation = null; + } + + /** + * Queues a single animation to be played after the current one. Does NOT stack. + * Queueing additional animations past 1 will just replace the queued animation + * @param animation The animation to queue + * @param loop Whether or not the loop the queued animation + * @param onEnd The event to fire when the queued animation ends + */ + queue(animation: string, loop: boolean = false, onEnd?: string): void { + this.pendingAnimation = animation; + this.pendingLoop = loop; + if(onEnd !== undefined){ + this.pendingOnEnd = onEnd; + } else { + this.pendingOnEnd = null; + } + } + + /** Pauses the current animation */ + pause(): void { + this.animationState = AnimationState.PAUSED; + } + + /** Resumes the current animation if possible */ + resume(): void { + if(this.animationState === AnimationState.PAUSED){ + this.animationState = AnimationState.PLAYING; + } + } + + /** Stops the current animation. The animation cannot be resumed after this. */ + stop(): void { + this.animationState = AnimationState.STOPPED; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts b/hw3/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts new file mode 100644 index 0000000..5f172de --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts @@ -0,0 +1,65 @@ +import { TweenableProperties } from "../../Nodes/GameNode"; +import { EaseFunctionType } from "../../Utils/EaseFunctions"; + +// @ignorePage + +export enum AnimationState { + STOPPED = 0, + PAUSED = 1, + PLAYING = 2, +} + +export class AnimationData { + name: string; + frames: Array<{index: number, duration: number}>; + repeat: boolean = false; +} + +export class TweenEffect { + /** The property to tween */ + property: TweenableProperties; + + /** Whether or not the Tween should reset the property to its original value after playing */ + resetOnComplete: boolean; + + /** The starting value for the tween */ + start: any; + + /** The ending value for the tween */ + end: any; + + /** The ease function to use */ + ease: EaseFunctionType; + + /** DO NOT MODIFY - The original value of the property - set automatically */ + initialValue: number; +} + +export class TweenData { + // Members for initialization by the user + /** The amount of time in ms to wait before executing the tween */ + startDelay: number; + /** The duration of time over which the value with change from start to end */ + duration: number; + /** An array of the effects on the properties of the object */ + effects: Array; + /** Whether or not this tween should reverse from end to start for each property when it finishes */ + reverseOnComplete: boolean; + /** Whether or not this tween should loop when it completes */ + loop: boolean; + /** The name of the event to send (if any) when the tween finishes playing */ + onEnd: string + + // Members for management by the tween manager + /** The progress of this tween through its effects */ + progress: number; + + /** The amount of time in ms that has passed from when this tween started running */ + elapsedTime: number; + + /** The state of this tween */ + animationState: AnimationState; + + /** Whether or not this tween is currently reversing */ + reversing: boolean; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/Animations/TweenController.ts b/hw3/src/Wolfie2D/Rendering/Animations/TweenController.ts new file mode 100644 index 0000000..082208d --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/Animations/TweenController.ts @@ -0,0 +1,213 @@ +import Map from "../../DataTypes/Map"; +import GameNode from "../../Nodes/GameNode"; +import { AnimationState, TweenData } from "./AnimationTypes"; +import EaseFunctions from "../../Utils/EaseFunctions"; +import MathUtils from "../../Utils/MathUtils"; +import TweenManager from "./TweenManager"; +import Emitter from "../../Events/Emitter"; + +/** + * A manager for the tweens of a GameNode. + * Tweens are short animations played by interpolating between two properties using an easing function. + * For a good visual representation of easing functions, check out @link(https://easings.net/)(https://easings.net/). + * Multiple tween can be played at the same time, as long as they don't change the same property. + * This allows for some interesting polishes or animations that may be very difficult to do with sprite work alone + * - especially pixel art (such as rotations or scaling). + */ +export default class TweenController { + /** The GameNode this TweenController acts upon */ + protected owner: GameNode; + /** The list of created tweens */ + protected tweens: Map; + /** An event emitter */ + protected emitter: Emitter; + + /** + * Creates a new TweenController + * @param owner The owner of the TweenController + */ + constructor(owner: GameNode){ + this.owner = owner; + this.tweens = new Map(); + this.emitter = new Emitter(); + + // Give ourselves to the TweenManager + TweenManager.getInstance().registerTweenController(this); + } + + /** + * Destroys this TweenController + */ + destroy(){ + // Only the gamenode and the tween manager should have a reference to this + delete this.owner.tweens; + TweenManager.getInstance().deregisterTweenController(this); + } + + /** + * Add a tween to this game node + * @param key The name of the tween + * @param tween The data of the tween + */ + add(key: string, tween: Record | TweenData): void { + let typedTween = tween; + + // Initialize members that we need (and the user didn't provide) + typedTween.progress = 0; + typedTween.elapsedTime = 0; + typedTween.animationState = AnimationState.STOPPED; + + this.tweens.add(key, typedTween); + } + + /** + * Play a tween with a certain name + * @param key The name of the tween to play + * @param loop Whether or not the tween should loop + */ + play(key: string, loop?: boolean): void { + if(this.tweens.has(key)){ + let tween = this.tweens.get(key); + + // Set loop if needed + if(loop !== undefined){ + tween.loop = loop; + } + + // Set the initial values + for(let effect of tween.effects){ + if(effect.resetOnComplete){ + effect.initialValue = this.owner[effect.property]; + } + } + + // Start the tween running + tween.animationState = AnimationState.PLAYING; + tween.elapsedTime = 0; + tween.progress = 0; + tween.reversing = false; + } else { + console.warn(`Tried to play tween "${key}" on node with id ${this.owner.id}, but no such tween exists`); + } + } + + /** + * Pauses a playing tween. Does not affect tweens that are stopped. + * @param key The name of the tween to pause. + */ + pause(key: string): void { + if(this.tweens.has(key)){ + this.tweens.get(key).animationState = AnimationState.PAUSED; + } + } + + /** + * Resumes a paused tween. + * @param key The name of the tween to resume + */ + resume(key: string): void { + if(this.tweens.has(key)){ + let tween = this.tweens.get(key); + if(tween.animationState === AnimationState.PAUSED) + tween.animationState = AnimationState.PLAYING; + } + } + + /** + * Stops a currently playing tween + * @param key The key of the tween + */ + stop(key: string): void { + if(this.tweens.has(key)){ + let tween = this.tweens.get(key); + tween.animationState = AnimationState.STOPPED; + + // Return to the initial values + for(let effect of tween.effects){ + if(effect.resetOnComplete){ + this.owner[effect.property] = effect.initialValue; + } + } + } + } + + /** + * The natural stop of a currently playing tween + * @param key The key of the tween + */ + protected end(key: string): void { + this.stop(key); + if(this.tweens.has(key)){ + // Get the tween + let tween = this.tweens.get(key); + + // If it has an onEnd, send an event + if(tween.onEnd){ + this.emitter.fireEvent(tween.onEnd, {key: key, node: this.owner.id}); + } + } + } + + /** + * Stops all currently playing tweens + */ + stopAll(): void { + this.tweens.forEach(key => this.stop(key)); + } + + update(deltaT: number): void { + this.tweens.forEach(key => { + let tween = this.tweens.get(key); + if(tween.animationState === AnimationState.PLAYING){ + // Update the progress of the tween + tween.elapsedTime += deltaT*1000; + + // If we're past the startDelay, do the tween + if(tween.elapsedTime >= tween.startDelay){ + if(!tween.reversing && tween.elapsedTime >= tween.startDelay + tween.duration){ + // If we're over time, stop the tween, loop, or reverse + if(tween.reverseOnComplete){ + // If we're over time and can reverse, do so + tween.reversing = true; + } else if(tween.loop){ + // If we can't reverse and can loop, do so + tween.elapsedTime -= tween.duration; + } else { + // We aren't looping and can't reverse, so stop + this.end(key); + } + } + + // Check for the end of reversing + if(tween.reversing && tween.elapsedTime >= tween.startDelay + 2*tween.duration){ + if(tween.loop){ + tween.reversing = false; + tween.elapsedTime -= 2*tween.duration; + } else { + this.end(key); + } + } + + // Update the progress, make sure it is between 0 and 1. Errors from this should never be large + if(tween.reversing){ + tween.progress = MathUtils.clamp01((2*tween.duration - (tween.elapsedTime- tween.startDelay))/tween.duration); + } else { + tween.progress = MathUtils.clamp01((tween.elapsedTime - tween.startDelay)/tween.duration); + } + + for(let effect of tween.effects){ + + // Get the value from the ease function that corresponds to our progress + let ease = EaseFunctions[effect.ease](tween.progress); + + // Use the value to lerp the property + let value = MathUtils.lerp(effect.start, effect.end, ease); + + // Assign the value of the property + this.owner[effect.property] = value; + } + } + } + }); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/Animations/TweenManager.ts b/hw3/src/Wolfie2D/Rendering/Animations/TweenManager.ts new file mode 100644 index 0000000..ad33c3e --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/Animations/TweenManager.ts @@ -0,0 +1,40 @@ +import Updateable from "../../DataTypes/Interfaces/Updateable"; +import TweenController from "./TweenController"; + +export default class TweenManager implements Updateable { + + private static instance: TweenManager = null; + + protected tweenControllers: Array; + + private constructor(){ + this.tweenControllers = new Array(); + } + + static getInstance(): TweenManager { + if(TweenManager.instance === null){ + TweenManager.instance = new TweenManager(); + } + + return TweenManager.instance; + } + + registerTweenController(controller: TweenController){ + this.tweenControllers.push(controller); + } + + deregisterTweenController(controller: TweenController){ + let index = this.tweenControllers.indexOf(controller); + this.tweenControllers.splice(index, 1); + } + + clearTweenControllers(){ + this.tweenControllers = new Array(); + } + + update(deltaT: number): void { + for(let tweenController of this.tweenControllers){ + tweenController.update(deltaT); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/CanvasRenderer.ts b/hw3/src/Wolfie2D/Rendering/CanvasRenderer.ts new file mode 100644 index 0000000..152c435 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/CanvasRenderer.ts @@ -0,0 +1,255 @@ +import Map from "../DataTypes/Map"; +import CanvasNode from "../Nodes/CanvasNode"; +import Graphic from "../Nodes/Graphic"; +import Point from "../Nodes/Graphics/Point"; +import Rect from "../Nodes/Graphics/Rect"; +import Sprite from "../Nodes/Sprites/Sprite"; +import Tilemap from "../Nodes/Tilemap"; +import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap"; +import UIElement from "../Nodes/UIElement"; +import UILayer from "../Scene/Layers/UILayer"; +import Scene from "../Scene/Scene"; +import GraphicRenderer from "./CanvasRendering/GraphicRenderer"; +import RenderingManager from "./RenderingManager" +import TilemapRenderer from "./CanvasRendering/TilemapRenderer"; +import UIElementRenderer from "./CanvasRendering/UIElementRenderer"; +import Label from "../Nodes/UIElements/Label"; +import Button from "../Nodes/UIElements/Button"; +import Slider from "../Nodes/UIElements/Slider"; +import TextInput from "../Nodes/UIElements/TextInput"; +import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite"; +import Vec2 from "../DataTypes/Vec2"; +import Color from "../Utils/Color"; +import Line from "../Nodes/Graphics/Line"; +import Debug from "../Debug/Debug"; + +/** + * An implementation of the RenderingManager class using CanvasRenderingContext2D. + */ +export default class CanvasRenderer extends RenderingManager { + protected ctx: CanvasRenderingContext2D; + protected graphicRenderer: GraphicRenderer; + protected tilemapRenderer: TilemapRenderer; + protected uiElementRenderer: UIElementRenderer; + + protected origin: Vec2; + protected zoom: number; + + protected worldSize: Vec2; + + constructor(){ + super(); + } + + // @override + setScene(scene: Scene){ + this.scene = scene; + this.graphicRenderer.setScene(scene); + this.tilemapRenderer.setScene(scene); + this.uiElementRenderer.setScene(scene); + } + + // @override + initializeCanvas(canvas: HTMLCanvasElement, width: number, height: number): CanvasRenderingContext2D { + canvas.width = width; + canvas.height = height; + + this.worldSize = new Vec2(width, height); + + this.ctx = canvas.getContext("2d"); + + this.graphicRenderer = new GraphicRenderer(this.ctx); + this.tilemapRenderer = new TilemapRenderer(this.ctx); + this.uiElementRenderer = new UIElementRenderer(this.ctx) + + // For crisp pixel art + this.ctx.imageSmoothingEnabled = false; + + return this.ctx; + } + + // @override + render(visibleSet: CanvasNode[], tilemaps: Tilemap[], uiLayers: Map): void { + // Sort by depth, then by visible set by y-value + visibleSet.sort((a, b) => { + if(a.getLayer().getDepth() === b.getLayer().getDepth()){ + return (a.boundary.bottom) - (b.boundary.bottom); + } else { + return a.getLayer().getDepth() - b.getLayer().getDepth(); + } + }); + + let tilemapIndex = 0; + let tilemapLength = tilemaps.length; + + let visibleSetIndex = 0; + let visibleSetLength = visibleSet.length; + + while(tilemapIndex < tilemapLength || visibleSetIndex < visibleSetLength){ + // Check conditions where we've already reached the edge of one list + if(tilemapIndex >= tilemapLength){ + // Only render the remaining visible set + let node = visibleSet[visibleSetIndex++]; + if(node.visible){ + this.renderNode(node); + } + continue; + } + + if(visibleSetIndex >= visibleSetLength){ + // Only render tilemaps + this.renderTilemap(tilemaps[tilemapIndex++]); + continue; + } + + // Render whichever is further down + if(tilemaps[tilemapIndex].getLayer().getDepth() <= visibleSet[visibleSetIndex].getLayer().getDepth()){ + this.renderTilemap(tilemaps[tilemapIndex++]); + } else { + let node = visibleSet[visibleSetIndex++]; + if(node.visible){ + this.renderNode(node); + } + } + } + + // Render the uiLayers on top of everything else + let sortedUILayers = new Array(); + + uiLayers.forEach(key => sortedUILayers.push(uiLayers.get(key))); + + sortedUILayers = sortedUILayers.sort((ui1, ui2) => ui1.getDepth() - ui2.getDepth()); + + sortedUILayers.forEach(uiLayer => { + if(!uiLayer.isHidden()) + uiLayer.getItems().forEach(node => { + if((node).visible){ + this.renderNode(node) + } + }) + }); + } + + /** + * Renders a specified CanvasNode + * @param node The CanvasNode to render + */ + protected renderNode(node: CanvasNode): void { + // Calculate the origin of the viewport according to this sprite + this.origin = this.scene.getViewTranslation(node); + + // Get the zoom level of the scene + this.zoom = this.scene.getViewScale(); + + // Move the canvas to the position of the node and rotate + let xScale = 1; + let yScale = 1; + + if(node instanceof Sprite){ + xScale = node.invertX ? -1 : 1; + yScale = node.invertY ? -1 : 1; + } + + this.ctx.setTransform(xScale, 0, 0, yScale, (node.position.x - this.origin.x)*this.zoom, (node.position.y - this.origin.y)*this.zoom); + this.ctx.rotate(-node.rotation); + let globalAlpha = this.ctx.globalAlpha; + if(node instanceof Rect){ + Debug.log("node" + node.id, "Node" + node.id + " Alpha: " + node.alpha); + } + this.ctx.globalAlpha = node.alpha; + + if(node instanceof AnimatedSprite){ + this.renderAnimatedSprite(node); + } else if(node instanceof Sprite){ + this.renderSprite(node); + } else if(node instanceof Graphic){ + this.renderGraphic(node); + } else if(node instanceof UIElement){ + this.renderUIElement(node); + } + + this.ctx.globalAlpha = globalAlpha; + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + } + + // @override + protected renderSprite(sprite: Sprite): void { + // Get the image from the resource manager + let image = this.resourceManager.getImage(sprite.imageId); + + /* + Coordinates in the space of the image: + image crop start -> x, y + image crop size -> w, h + Coordinates in the space of the world + image draw start -> x, y + image draw size -> w, h + */ + this.ctx.drawImage(image, + sprite.imageOffset.x, sprite.imageOffset.y, + sprite.size.x, sprite.size.y, + (-sprite.size.x*sprite.scale.x/2)*this.zoom, (-sprite.size.y*sprite.scale.y/2)*this.zoom, + sprite.size.x * sprite.scale.x*this.zoom, sprite.size.y * sprite.scale.y*this.zoom); + } + + // @override + protected renderAnimatedSprite(sprite: AnimatedSprite): void { + // Get the image from the resource manager + let image = this.resourceManager.getImage(sprite.imageId); + + let animationIndex = sprite.animation.getIndexAndAdvanceAnimation(); + + let animationOffset = sprite.getAnimationOffset(animationIndex); + + /* + Coordinates in the space of the image: + image crop start -> x, y + image crop size -> w, h + Coordinates in the space of the world (given we moved) + image draw start -> -w/2, -h/2 + image draw size -> w, h + */ + this.ctx.drawImage(image, + sprite.imageOffset.x + animationOffset.x, sprite.imageOffset.y + animationOffset.y, + sprite.size.x, sprite.size.y, + (-sprite.size.x*sprite.scale.x/2)*this.zoom, (-sprite.size.y*sprite.scale.y/2)*this.zoom, + sprite.size.x * sprite.scale.x*this.zoom, sprite.size.y * sprite.scale.y*this.zoom); + } + + // @override + protected renderGraphic(graphic: Graphic): void { + if(graphic instanceof Point){ + this.graphicRenderer.renderPoint(graphic, this.zoom); + } else if(graphic instanceof Line){ + this.graphicRenderer.renderLine(graphic, this.origin, this.zoom); + } else if(graphic instanceof Rect){ + this.graphicRenderer.renderRect(graphic, this.zoom); + } + } + + // @override + protected renderTilemap(tilemap: Tilemap): void { + if(tilemap instanceof OrthogonalTilemap){ + this.tilemapRenderer.renderOrthogonalTilemap(tilemap); + } + } + + // @override + protected renderUIElement(uiElement: UIElement): void { + if(uiElement instanceof Label){ + this.uiElementRenderer.renderLabel(uiElement); + } else if(uiElement instanceof Button){ + this.uiElementRenderer.renderButton(uiElement); + } else if(uiElement instanceof Slider){ + this.uiElementRenderer.renderSlider(uiElement); + } else if(uiElement instanceof TextInput){ + this.uiElementRenderer.renderTextInput(uiElement); + } + } + + clear(clearColor: Color): void { + this.ctx.clearRect(0, 0, this.worldSize.x, this.worldSize.y); + this.ctx.fillStyle = clearColor.toString(); + this.ctx.fillRect(0, 0, this.worldSize.x, this.worldSize.y); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/CanvasRendering/GraphicRenderer.ts b/hw3/src/Wolfie2D/Rendering/CanvasRendering/GraphicRenderer.ts new file mode 100644 index 0000000..230249d --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/CanvasRendering/GraphicRenderer.ts @@ -0,0 +1,72 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Line from "../../Nodes/Graphics/Line"; +import Point from "../../Nodes/Graphics/Point"; +import Rect from "../../Nodes/Graphics/Rect"; +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Scene from "../../Scene/Scene"; + +/** + * A utility class to help the @reference[CanvasRenderer] render @reference[Graphic]s + */ +export default class GraphicRenderer { + /** The resource manager of the game engine */ + protected resourceManager: ResourceManager; + /** The current scene */ + protected scene: Scene; + /** The rendering context */ + protected ctx: CanvasRenderingContext2D; + + constructor(ctx: CanvasRenderingContext2D){ + this.resourceManager = ResourceManager.getInstance(); + this.ctx = ctx; + } + + /** + * Sets the scene of this GraphicRenderer + * @param scene The current scene + */ + setScene(scene: Scene): void { + this.scene = scene; + } + + /** + * Renders a point + * @param point The point to render + * @param zoom The zoom level + */ + renderPoint(point: Point, zoom: number): void { + this.ctx.fillStyle = point.color.toStringRGBA(); + this.ctx.fillRect((-point.size.x/2)*zoom, (-point.size.y/2)*zoom, + point.size.x*zoom, point.size.y*zoom); + } + + renderLine(line: Line, origin: Vec2, zoom: number): void { + this.ctx.strokeStyle = line.color.toStringRGBA(); + this.ctx.lineWidth = line.thickness; + this.ctx.beginPath(); + this.ctx.moveTo(0, 0); + this.ctx.lineTo((line.end.x - line.start.x)*zoom, (line.end.y - line.start.y)*zoom); + this.ctx.closePath(); + this.ctx.stroke(); + } + + /** + * Renders a rect + * @param rect The rect to render + * @param zoom The zoom level + */ + renderRect(rect: Rect, zoom: number): void { + // Draw the interior of the rect + if(rect.color.a !== 0){ + this.ctx.fillStyle = rect.color.toStringRGB(); + this.ctx.fillRect((-rect.size.x/2)*zoom, (-rect.size.y/2)*zoom, rect.size.x*zoom, rect.size.y*zoom); + } + + // Draw the border of the rect if it isn't transparent + if(rect.borderColor.a !== 0){ + this.ctx.strokeStyle = rect.getBorderColor().toStringRGB(); + this.ctx.lineWidth = rect.getBorderWidth(); + this.ctx.strokeRect((-rect.size.x/2)*zoom, (-rect.size.y/2)*zoom, rect.size.x*zoom, rect.size.y*zoom); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/CanvasRendering/TilemapRenderer.ts b/hw3/src/Wolfie2D/Rendering/CanvasRendering/TilemapRenderer.ts new file mode 100644 index 0000000..c7d06e7 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/CanvasRendering/TilemapRenderer.ts @@ -0,0 +1,151 @@ +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Scene from "../../Scene/Scene"; +import OrthogonalTilemap from "../../Nodes/Tilemaps/OrthogonalTilemap"; +import Vec2 from "../../DataTypes/Vec2"; +import Tileset from "../../DataTypes/Tilesets/Tileset"; + +/** + * A utility class for the @reference[CanvasRenderer] to render @reference[Tilemap]s + */ +export default class TilemapRenderer { + protected resourceManager: ResourceManager; + protected scene: Scene; + protected ctx: CanvasRenderingContext2D; + + constructor(ctx: CanvasRenderingContext2D){ + this.resourceManager = ResourceManager.getInstance(); + this.ctx = ctx; + } + + /** + * Sets the scene of this TilemapRenderer + * @param scene The current scene + */ + setScene(scene: Scene): void { + this.scene = scene; + } + + /** + * Renders an orthogonal tilemap + * @param tilemap The tilemap to render + */ + renderOrthogonalTilemap(tilemap: OrthogonalTilemap): void { + let previousAlpha = this.ctx.globalAlpha; + this.ctx.globalAlpha = tilemap.getLayer().getAlpha(); + + let origin = this.scene.getViewTranslation(tilemap); + let size = this.scene.getViewport().getHalfSize(); + let zoom = this.scene.getViewScale(); + let bottomRight = origin.clone().add(size.scaled(2*zoom)); + + if(tilemap.visible){ + let minColRow = tilemap.getColRowAt(origin); + let maxColRow = tilemap.getColRowAt(bottomRight); + + for(let x = minColRow.x; x <= maxColRow.x; x++){ + for(let y = minColRow.y; y <= maxColRow.y; y++){ + // Get the tile at this position + let tile = tilemap.getTileAtRowCol(new Vec2(x, y)); + + // Extract the rot/flip parameters if there are any + const mask = (0xE << 28); + const rotFlip = ((mask & tile) >> 28) & 0xF; + tile = tile & ~mask; + + // Find the tileset that owns this tile index and render + for(let tileset of tilemap.getTilesets()){ + if(tileset.hasTile(tile)){ + this.renderTile(tileset, tile, x, y, origin, tilemap.scale, zoom, rotFlip); + } + } + } + } + } + + this.ctx.globalAlpha = previousAlpha; + } + + /** + * Renders a tile + * @param tileset The tileset this tile belongs to + * @param tileIndex The index of the tile + * @param tilemapRow The row of the tile in the tilemap + * @param tilemapCol The column of the tile in the tilemap + * @param origin The origin of the viewport + * @param scale The scale of the tilemap + * @param zoom The zoom level of the viewport + */ + protected renderTile(tileset: Tileset, tileIndex: number, tilemapRow: number, tilemapCol: number, origin: Vec2, scale: Vec2, zoom: number, rotFlip: number): void { + let image = this.resourceManager.getImage(tileset.getImageKey()); + + // Get the true index + let index = tileIndex - tileset.getStartIndex(); + + // Get the row and col of the tile in image space + let row = Math.floor(index / tileset.getNumCols()); + let col = index % tileset.getNumCols(); + let width = tileset.getTileSize().x; + let height = tileset.getTileSize().y; + + // Calculate the position to start a crop in the tileset image + let left = col * width; + let top = row * height; + + // Calculate the position in the world to render the tile + let x = Math.floor(tilemapRow * width * scale.x); + let y = Math.floor(tilemapCol * height * scale.y); + + let worldX = Math.floor((x - origin.x)*zoom); + let worldY = Math.floor((y - origin.y)*zoom); + let worldWidth = Math.ceil(width * scale.x * zoom); + let worldHeight = Math.ceil(height * scale.y * zoom); + + if(rotFlip !== 0){ + let scaleX = 1; + let scaleY = 1; + let shearX = 0; + let shearY = 0; + + // Flip on the x-axis + if(rotFlip & 8){ + scaleX = -1; + } + + // Flip on the y-axis + if(rotFlip & 4){ + scaleY = -1; + } + + // Flip over the line y=x + if(rotFlip & 2){ + shearX = scaleY; + shearY = scaleX; + scaleX = 0; + scaleY = 0; + } + + this.ctx.setTransform(scaleX, shearX, shearY, scaleY, worldX + worldWidth/2, worldY + worldHeight/2); + + // Render the tile + this.ctx.drawImage(image, + left, top, + width, height, + -worldWidth/2, -worldHeight/2, + worldWidth, worldHeight); + + if(rotFlip !== 0){ + this.ctx.setTransform(1, 0, 0, 1, 0, 0); + } + } else { + // No rotations, don't do the calculations, just render the tile + // Render the tile + this.ctx.drawImage(image, + left, top, + width, height, + worldX, worldY, + worldWidth, worldHeight); + } + + + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/CanvasRendering/UIElementRenderer.ts b/hw3/src/Wolfie2D/Rendering/CanvasRendering/UIElementRenderer.ts new file mode 100644 index 0000000..56c872e --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/CanvasRendering/UIElementRenderer.ts @@ -0,0 +1,126 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Button from "../../Nodes/UIElements/Button"; +import Label from "../../Nodes/UIElements/Label"; +import Slider from "../../Nodes/UIElements/Slider"; +import TextInput from "../../Nodes/UIElements/TextInput"; +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Scene from "../../Scene/Scene"; +import MathUtils from "../../Utils/MathUtils"; + +/** + * A utility class to help the @reference[CanvasRenderer] render @reference[UIElement]s + */ +export default class UIElementRenderer { + protected resourceManager: ResourceManager; + protected scene: Scene; + protected ctx: CanvasRenderingContext2D; + + constructor(ctx: CanvasRenderingContext2D){ + this.resourceManager = ResourceManager.getInstance(); + this.ctx = ctx; + } + + /** + * Sets the scene of this UIElementRenderer + * @param scene The current scene + */ + setScene(scene: Scene): void { + this.scene = scene; + } + + /** + * Renders a label + * @param label The label to render + */ + renderLabel(label: Label): void { + // If the size is unassigned (by the user or automatically) assign it + label.handleInitialSizing(this.ctx); + + // Grab the global alpha so we can adjust it for this render + let previousAlpha = this.ctx.globalAlpha; + + // Get the font and text position in label + this.ctx.font = label.getFontString(); + let offset = label.calculateTextOffset(this.ctx); + + // Stroke and fill a rounded rect and give it text + this.ctx.globalAlpha = label.backgroundColor.a; + this.ctx.fillStyle = label.calculateBackgroundColor().toStringRGBA(); + this.ctx.fillRoundedRect(-label.size.x/2, -label.size.y/2, + label.size.x, label.size.y, label.borderRadius); + + this.ctx.strokeStyle = label.calculateBorderColor().toStringRGBA(); + this.ctx.globalAlpha = label.borderColor.a; + this.ctx.lineWidth = label.borderWidth; + this.ctx.strokeRoundedRect(-label.size.x/2, -label.size.y/2, + label.size.x, label.size.y, label.borderRadius); + + this.ctx.fillStyle = label.calculateTextColor(); + this.ctx.globalAlpha = label.textColor.a; + this.ctx.fillText(label.text, offset.x - label.size.x/2, offset.y - label.size.y/2); + + this.ctx.globalAlpha = previousAlpha; + } + + /** + * Renders a button + * @param button The button to render + */ + renderButton(button: Button): void { + this.renderLabel(button); + } + + /** + * Renders a slider + * @param slider The slider to render + */ + renderSlider(slider: Slider): void { + // Grab the global alpha so we can adjust it for this render + let previousAlpha = this.ctx.globalAlpha; + this.ctx.globalAlpha = slider.getLayer().getAlpha(); + + // Calcualate the slider size + let sliderSize = new Vec2(slider.size.x, 2); + + // Draw the slider + this.ctx.fillStyle = slider.sliderColor.toString(); + this.ctx.fillRoundedRect(-sliderSize.x/2, -sliderSize.y/2, + sliderSize.x, sliderSize.y, slider.borderRadius); + + // Calculate the nib size and position + let x = MathUtils.lerp(-slider.size.x/2, slider.size.x/2, slider.getValue()); + + // Draw the nib + this.ctx.fillStyle = slider.nibColor.toString(); + this.ctx.fillRoundedRect(x-slider.nibSize.x/2, -slider.nibSize.y/2, + slider.nibSize.x, slider.nibSize.y, slider.borderRadius); + + // Reset the alpha + this.ctx.globalAlpha = previousAlpha; + } + + /** + * Renders a textInput + * @param textInput The textInput to render + */ + renderTextInput(textInput: TextInput): void { + // Show a cursor sometimes + if(textInput.focused && textInput.cursorCounter % 60 > 30){ + textInput.text += "|"; + } + + this.renderLabel(textInput); + + if(textInput.focused){ + if(textInput.cursorCounter % 60 > 30){ + textInput.text = textInput.text.substring(0, textInput.text.length - 1); + } + + textInput.cursorCounter += 1; + if(textInput.cursorCounter >= 60){ + textInput.cursorCounter = 0; + } + } + } + +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/RenderingManager.ts b/hw3/src/Wolfie2D/Rendering/RenderingManager.ts new file mode 100644 index 0000000..3f4f91d --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/RenderingManager.ts @@ -0,0 +1,85 @@ +import Map from "../DataTypes/Map"; +import CanvasNode from "../Nodes/CanvasNode"; +import Graphic from "../Nodes/Graphic"; +import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite"; +import Sprite from "../Nodes/Sprites/Sprite"; +import Tilemap from "../Nodes/Tilemap"; +import UIElement from "../Nodes/UIElement"; +import ResourceManager from "../ResourceManager/ResourceManager"; +import UILayer from "../Scene/Layers/UILayer"; +import Scene from "../Scene/Scene"; +import Color from "../Utils/Color"; + +/** + * An abstract framework to put all rendering in once place in the application + */ +export default abstract class RenderingManager { + /** The ResourceManager */ + protected resourceManager: ResourceManager; + + /** The scene currently being rendered */ + protected scene: Scene; + + constructor(){ + this.resourceManager = ResourceManager.getInstance(); + } + + /** + * Sets the scene currently being rendered + * @param scene The current Scene + */ + setScene(scene: Scene): void { + this.scene = scene; + } + + /** + * Initialize the canvas for the game + * @param canvas The canvas element + * @param width The desired width of the canvas + * @param height The desired height of the canvas + * @returns The rendering context of the canvas + */ + abstract initializeCanvas(canvas: HTMLCanvasElement, width: number, height: number): any; + + /** + * Renders the visible set of CanvasNodes and visible portions of tilemaps, as well as any UIElement in UILayers + * @param visibleSet The visible set of CanvasNodes + * @param tilemaps The tilemaps used in the application + * @param uiLayers The user interface layers + */ + abstract render(visibleSet: Array, tilemaps: Array, uiLayers: Map): void; + + /** Clears the canvas */ + abstract clear(color: Color): void; + + /** + * Renders a sprite + * @param sprite The sprite to render + */ + protected abstract renderSprite(sprite: Sprite): void; + + /** + * Renders an animated sprite + * @param sprite The animated sprite to render + */ + protected abstract renderAnimatedSprite(sprite: AnimatedSprite): void; + + /** + * Renders a graphic + * @param graphic The graphic to render + */ + protected abstract renderGraphic(graphic: Graphic): void; + + /** + * Renders a tilemap + * @param tilemap The tilemap to render + */ + protected abstract renderTilemap(tilemap: Tilemap): void; + + + /** + * Renders a UIElement + * @param uiElement The UIElement to render + */ + protected abstract renderUIElement(uiElement: UIElement): void; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRenderer.ts b/hw3/src/Wolfie2D/Rendering/WebGLRenderer.ts new file mode 100644 index 0000000..0ad5a19 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRenderer.ts @@ -0,0 +1,182 @@ +import Graph from "../DataTypes/Graphs/Graph"; +import Map from "../DataTypes/Map"; +import Vec2 from "../DataTypes/Vec2"; +import Debug from "../Debug/Debug"; +import CanvasNode from "../Nodes/CanvasNode"; +import Graphic from "../Nodes/Graphic"; +import { GraphicType } from "../Nodes/Graphics/GraphicTypes"; +import Point from "../Nodes/Graphics/Point"; +import Rect from "../Nodes/Graphics/Rect"; +import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite"; +import Sprite from "../Nodes/Sprites/Sprite"; +import Tilemap from "../Nodes/Tilemap"; +import UIElement from "../Nodes/UIElement"; +import Label from "../Nodes/UIElements/Label"; +import ShaderRegistry from "../Registry/Registries/ShaderRegistry"; +import RegistryManager from "../Registry/RegistryManager"; +import ResourceManager from "../ResourceManager/ResourceManager"; +import ParallaxLayer from "../Scene/Layers/ParallaxLayer"; +import UILayer from "../Scene/Layers/UILayer"; +import Color from "../Utils/Color"; +import RenderingUtils from "../Utils/RenderingUtils"; +import RenderingManager from "./RenderingManager"; +import ShaderType from "./WebGLRendering/ShaderType"; + +export default class WebGLRenderer extends RenderingManager { + + protected origin: Vec2; + protected zoom: number; + protected worldSize: Vec2; + + protected gl: WebGLRenderingContext; + protected textCtx: CanvasRenderingContext2D; + + initializeCanvas(canvas: HTMLCanvasElement, width: number, height: number): WebGLRenderingContext { + canvas.width = width; + canvas.height = height; + + this.worldSize = Vec2.ZERO; + this.worldSize.x = width; + this.worldSize.y = height; + + // Get the WebGL context + this.gl = canvas.getContext("webgl"); + + this.gl.viewport(0, 0, canvas.width, canvas.height); + + this.gl.disable(this.gl.DEPTH_TEST); + this.gl.enable(this.gl.BLEND); + this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA); + this.gl.enable(this.gl.CULL_FACE); + + // Tell the resource manager we're using WebGL + ResourceManager.getInstance().useWebGL(true, this.gl); + + // Show the text canvas and get its context + let textCanvas = document.getElementById("text-canvas"); + textCanvas.hidden = false; + this.textCtx = textCanvas.getContext("2d"); + + // Size the text canvas to be the same as the game canvas + textCanvas.height = height; + textCanvas.width = width; + + return this.gl; + } + + render(visibleSet: CanvasNode[], tilemaps: Tilemap[], uiLayers: Map): void { + for(let node of visibleSet){ + this.renderNode(node); + } + + uiLayers.forEach(key => { + if(!uiLayers.get(key).isHidden()) + uiLayers.get(key).getItems().forEach(node => this.renderNode(node)) + }); + } + + clear(color: Color): void { + this.gl.clearColor(color.r, color.g, color.b, color.a); + this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); + + this.textCtx.clearRect(0, 0, this.worldSize.x, this.worldSize.y); + } + + protected renderNode(node: CanvasNode): void { + // Calculate the origin of the viewport according to this sprite + this.origin = this.scene.getViewTranslation(node); + + // Get the zoom level of the scene + this.zoom = this.scene.getViewScale(); + + if(node.hasCustomShader){ + // If the node has a custom shader, render using that + this.renderCustom(node); + } else if(node instanceof Graphic){ + this.renderGraphic(node); + } else if(node instanceof Sprite){ + if(node instanceof AnimatedSprite){ + this.renderAnimatedSprite(node); + } else { + this.renderSprite(node); + } + } else if(node instanceof UIElement){ + this.renderUIElement(node); + } + } + + protected renderSprite(sprite: Sprite): void { + let shader = RegistryManager.shaders.get(ShaderRegistry.SPRITE_SHADER); + let options = this.addOptions(shader.getOptions(sprite), sprite); + shader.render(this.gl, options); + } + + protected renderAnimatedSprite(sprite: AnimatedSprite): void { + let shader = RegistryManager.shaders.get(ShaderRegistry.SPRITE_SHADER); + let options = this.addOptions(shader.getOptions(sprite), sprite); + shader.render(this.gl, options); + } + + protected renderGraphic(graphic: Graphic): void { + + if(graphic instanceof Point){ + let shader = RegistryManager.shaders.get(ShaderRegistry.POINT_SHADER); + let options = this.addOptions(shader.getOptions(graphic), graphic); + shader.render(this.gl, options); + } else if(graphic instanceof Rect) { + let shader = RegistryManager.shaders.get(ShaderRegistry.RECT_SHADER); + let options = this.addOptions(shader.getOptions(graphic), graphic); + shader.render(this.gl, options); + } + } + + protected renderTilemap(tilemap: Tilemap): void { + throw new Error("Method not implemented."); + } + + protected renderUIElement(uiElement: UIElement): void { + if(uiElement instanceof Label){ + let shader = RegistryManager.shaders.get(ShaderRegistry.LABEL_SHADER); + let options = this.addOptions(shader.getOptions(uiElement), uiElement); + shader.render(this.gl, options); + + this.textCtx.setTransform(1, 0, 0, 1, (uiElement.position.x - this.origin.x)*this.zoom, (uiElement.position.y - this.origin.y)*this.zoom); + this.textCtx.rotate(-uiElement.rotation); + let globalAlpha = this.textCtx.globalAlpha; + this.textCtx.globalAlpha = uiElement.alpha; + + // Render text + this.textCtx.font = uiElement.getFontString(); + let offset = uiElement.calculateTextOffset(this.textCtx); + this.textCtx.fillStyle = uiElement.calculateTextColor(); + this.textCtx.globalAlpha = uiElement.textColor.a; + this.textCtx.fillText(uiElement.text, offset.x - uiElement.size.x/2, offset.y - uiElement.size.y/2); + + this.textCtx.globalAlpha = globalAlpha; + this.textCtx.setTransform(1, 0, 0, 1, 0, 0); + } + } + + protected renderCustom(node: CanvasNode): void { + let shader = RegistryManager.shaders.get(node.customShaderKey); + let options = this.addOptions(shader.getOptions(node), node); + shader.render(this.gl, options); + } + + protected addOptions(options: Record, node: CanvasNode): Record { + // Give the shader access to the world size + options.worldSize = this.worldSize; + + // Adjust the origin position to the parallax + let layer = node.getLayer(); + let parallax = new Vec2(1, 1); + if(layer instanceof ParallaxLayer){ + parallax = (layer).parallax; + } + + options.origin = this.origin.clone().mult(parallax); + + return options; + } + +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderType.ts b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderType.ts new file mode 100644 index 0000000..897dc09 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderType.ts @@ -0,0 +1,44 @@ +import Map from "../../DataTypes/Map"; +import CanvasNode from "../../Nodes/CanvasNode"; +import ResourceManager from "../../ResourceManager/ResourceManager"; + +/** + * A wrapper class for WebGL shaders. + * This class is a singleton, and there is only one for each shader type. + * All objects that use this shader type will refer to and modify this same type. + */ +export default abstract class ShaderType { + /** The name of this shader */ + protected name: string; + + /** The key to the WebGLProgram in the ResourceManager */ + protected programKey: string; + + /** A reference to the resource manager */ + protected resourceManager: ResourceManager; + + constructor(programKey: string){ + this.programKey = programKey; + this.resourceManager = ResourceManager.getInstance(); + } + + /** + * Initializes any buffer objects associated with this shader type. + * @param gl The WebGL rendering context + */ + abstract initBufferObject(): void; + + /** + * Loads any uniforms + * @param gl The WebGL rendering context + * @param options Information about the object we're currently rendering + */ + abstract render(gl: WebGLRenderingContext, options: Record): void; + + /** + * Extracts the options from the CanvasNode and gives them to the render function + * @param node The node to get options from + * @returns An object containing the options that should be passed to the render function + */ + getOptions(node: CanvasNode): Record {return {};} +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/LabelShaderType.ts b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/LabelShaderType.ts new file mode 100644 index 0000000..7582ec0 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/LabelShaderType.ts @@ -0,0 +1,122 @@ +import Mat4x4 from "../../../DataTypes/Mat4x4"; +import Vec2 from "../../../DataTypes/Vec2"; +import Debug from "../../../Debug/Debug"; +import Rect from "../../../Nodes/Graphics/Rect"; +import Label from "../../../Nodes/UIElements/Label"; +import ResourceManager from "../../../ResourceManager/ResourceManager"; +import QuadShaderType from "./QuadShaderType"; + +export default class LabelShaderType extends QuadShaderType { + + constructor(programKey: string){ + super(programKey); + this.resourceManager = ResourceManager.getInstance(); + } + + initBufferObject(): void { + this.bufferObjectKey = "label"; + this.resourceManager.createBuffer(this.bufferObjectKey); + } + + render(gl: WebGLRenderingContext, options: Record): void { + const backgroundColor = options.backgroundColor.toWebGL(); + const borderColor = options.borderColor.toWebGL(); + + const program = this.resourceManager.getShaderProgram(this.programKey); + const buffer = this.resourceManager.getBuffer(this.bufferObjectKey); + + gl.useProgram(program); + + const vertexData = this.getVertices(options.size.x, options.size.y); + + const FSIZE = vertexData.BYTES_PER_ELEMENT; + + // Bind the buffer + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); + + // Attributes + const a_Position = gl.getAttribLocation(program, "a_Position"); + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE); + gl.enableVertexAttribArray(a_Position); + + // Uniforms + const u_BackgroundColor = gl.getUniformLocation(program, "u_BackgroundColor"); + gl.uniform4fv(u_BackgroundColor, backgroundColor); + + const u_BorderColor = gl.getUniformLocation(program, "u_BorderColor"); + gl.uniform4fv(u_BorderColor, borderColor); + + const u_MaxSize = gl.getUniformLocation(program, "u_MaxSize"); + gl.uniform2f(u_MaxSize, -vertexData[0], vertexData[1]); + + // Get transformation matrix + // We want a square for our rendering space, so get the maximum dimension of our quad + let maxDimension = Math.max(options.size.x, options.size.y); + + const u_BorderWidth = gl.getUniformLocation(program, "u_BorderWidth"); + gl.uniform1f(u_BorderWidth, options.borderWidth/maxDimension); + + const u_BorderRadius = gl.getUniformLocation(program, "u_BorderRadius"); + gl.uniform1f(u_BorderRadius, options.borderRadius/maxDimension); + + // The size of the rendering space will be a square with this maximum dimension + let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y); + + // Center our translations around (0, 0) + const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension; + const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension; + + // Create our transformation matrix + this.translation.translate(new Float32Array([translateX, translateY])); + this.scale.scale(size); + this.rotation.rotate(options.rotation); + let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation); + + // Pass the translation matrix to our shader + const u_Transform = gl.getUniformLocation(program, "u_Transform"); + gl.uniformMatrix4fv(u_Transform, false, transformation.toArray()); + + // Draw the quad + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + /** + * The rendering space always has to be a square, so make sure its square w.r.t to the largest dimension + * @param w The width of the quad in pixels + * @param h The height of the quad in pixels + * @returns An array of the vertices of the quad + */ + getVertices(w: number, h: number): Float32Array { + let x, y; + + if(h > w){ + y = 0.5; + x = w/(2*h); + } else { + x = 0.5; + y = h/(2*w); + } + + return new Float32Array([ + -x, y, + -x, -y, + x, y, + x, -y + ]); + } + + getOptions(rect: Label): Record { + let options: Record = { + position: rect.position, + backgroundColor: rect.calculateBackgroundColor(), + borderColor: rect.calculateBorderColor(), + borderWidth: rect.borderWidth, + borderRadius: rect.borderRadius, + size: rect.size, + rotation: rect.rotation + } + + return options; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/PointShaderType.ts b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/PointShaderType.ts new file mode 100644 index 0000000..e7ae466 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/PointShaderType.ts @@ -0,0 +1,61 @@ +import Debug from "../../../Debug/Debug"; +import Point from "../../../Nodes/Graphics/Point"; +import ResourceManager from "../../../ResourceManager/ResourceManager"; +import RenderingUtils from "../../../Utils/RenderingUtils"; +import ShaderType from "../ShaderType"; + +export default class PointShaderType extends ShaderType { + + protected bufferObjectKey: string; + + constructor(programKey: string){ + super(programKey); + } + + initBufferObject(): void { + this.bufferObjectKey = "point"; + this.resourceManager.createBuffer(this.bufferObjectKey); + } + + render(gl: WebGLRenderingContext, options: Record): void { + let position = RenderingUtils.toWebGLCoords(options.position, options.origin, options.worldSize); + let color = RenderingUtils.toWebGLColor(options.color); + + const program = this.resourceManager.getShaderProgram(this.programKey); + const buffer = this.resourceManager.getBuffer(this.bufferObjectKey); + + gl.useProgram(program); + + const vertexData = position; + + const FSIZE = vertexData.BYTES_PER_ELEMENT; + + // Bind the buffer + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); + + // Attributes + const a_Position = gl.getAttribLocation(program, "a_Position"); + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE); + gl.enableVertexAttribArray(a_Position); + + // Uniforms + const u_Color = gl.getUniformLocation(program, "u_Color"); + gl.uniform4fv(u_Color, color); + + const u_PointSize = gl.getUniformLocation(program, "u_PointSize"); + gl.uniform1f(u_PointSize, options.pointSize); + + gl.drawArrays(gl.POINTS, 0, 1); + } + + getOptions(point: Point): Record { + let options: Record = { + position: point.position, + color: point.color, + pointSize: point.size, + } + + return options; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/QuadShaderType.ts b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/QuadShaderType.ts new file mode 100644 index 0000000..fa524f1 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/QuadShaderType.ts @@ -0,0 +1,25 @@ +import Mat4x4 from "../../../DataTypes/Mat4x4"; +import ShaderType from "../ShaderType"; + +/** Represents any WebGL objects that have a quad mesh (i.e. a rectangular game object composed of only two triangles) */ +export default abstract class QuadShaderType extends ShaderType { + /** The key to the buffer object for this shader */ + protected bufferObjectKey: string; + + /** The scale matric */ + protected scale: Mat4x4; + + /** The rotation matrix */ + protected rotation: Mat4x4; + + /** The translation matrix */ + protected translation: Mat4x4; + + constructor(programKey: string){ + super(programKey); + + this.scale = Mat4x4.IDENTITY; + this.rotation = Mat4x4.IDENTITY; + this.translation = Mat4x4.IDENTITY; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType.ts b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType.ts new file mode 100644 index 0000000..e977434 --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType.ts @@ -0,0 +1,133 @@ +import Mat4x4 from "../../../DataTypes/Mat4x4"; +import Vec2 from "../../../DataTypes/Vec2"; +import Rect from "../../../Nodes/Graphics/Rect"; +import ResourceManager from "../../../ResourceManager/ResourceManager"; +import QuadShaderType from "./QuadShaderType"; + +export default class RectShaderType extends QuadShaderType { + + constructor(programKey: string){ + super(programKey); + this.resourceManager = ResourceManager.getInstance(); + } + + initBufferObject(): void { + this.bufferObjectKey = "rect"; + this.resourceManager.createBuffer(this.bufferObjectKey); + } + + render(gl: WebGLRenderingContext, options: Record): void { + const color = options.color.toWebGL(); + + const program = this.resourceManager.getShaderProgram(this.programKey); + const buffer = this.resourceManager.getBuffer(this.bufferObjectKey); + + gl.useProgram(program); + + const vertexData = this.getVertices(options.size.x, options.size.y); + + const FSIZE = vertexData.BYTES_PER_ELEMENT; + + // Bind the buffer + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); + + // Attributes + const a_Position = gl.getAttribLocation(program, "a_Position"); + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE); + gl.enableVertexAttribArray(a_Position); + + // Uniforms + const u_Color = gl.getUniformLocation(program, "u_Color"); + gl.uniform4fv(u_Color, color); + + // Get transformation matrix + // We want a square for our rendering space, so get the maximum dimension of our quad + let maxDimension = Math.max(options.size.x, options.size.y); + + // The size of the rendering space will be a square with this maximum dimension + let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y); + + // Center our translations around (0, 0) + const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension; + const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension; + + // Create our transformation matrix + this.translation.translate(new Float32Array([translateX, translateY])); + this.scale.scale(size); + this.rotation.rotate(options.rotation); + let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation); + + // Pass the translation matrix to our shader + const u_Transform = gl.getUniformLocation(program, "u_Transform"); + gl.uniformMatrix4fv(u_Transform, false, transformation.toArray()); + + // Draw the quad + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + + /* + So as it turns out, WebGL has an issue with non-square quads. + It doesn't like when you don't have a 1-1 scale, and rotations are entirely messed up if this is not the case. + To solve this, I used the scale of the LARGEST dimension of the quad to make a square, then adjusted the vertex coordinates inside of that. + A diagram of the solution follows. + + There is a bounding square for the quad with dimensions hxh (in this case, since height is the largest dimension). + The offset in the vertical direction is therefore 0.5, as it is normally. + However, the offset in the horizontal direction is not so straightforward, but isn't conceptually hard. + All we really have to do is a range change from [0, height/2] to [0, 0.5], where our value is t = width/2, and 0 <= t <= height/2. + + So now we have our rect, in a space scaled with respect to the largest dimension. + Rotations work as you would expect, even for long rectangles. + + 0.5 + __ __ __ __ __ __ __ + | |88888888888| | + | |88888888888| | + | |88888888888| | + -0.5|_ _|88888888888|_ _|0.5 + | |88888888888| | + | |88888888888| | + | |88888888888| | + |___|88888888888|___| + -0.5 + + The getVertices function below does as described, and converts the range + */ + /** + * The rendering space always has to be a square, so make sure its square w.r.t to the largest dimension + * @param w The width of the quad in pixels + * @param h The height of the quad in pixels + * @returns An array of the vertices of the quad + */ + getVertices(w: number, h: number): Float32Array { + let x, y; + + if(h > w){ + y = 0.5; + x = w/(2*h); + } else { + x = 0.5; + y = h/(2*w); + } + + return new Float32Array([ + -x, y, + -x, -y, + x, y, + x, -y + ]); + } + + getOptions(rect: Rect): Record { + let options: Record = { + position: rect.position, + color: rect.color, + size: rect.size, + rotation: rect.rotation + } + + return options; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/SpriteShaderType.ts b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/SpriteShaderType.ts new file mode 100644 index 0000000..511d39a --- /dev/null +++ b/hw3/src/Wolfie2D/Rendering/WebGLRendering/ShaderTypes/SpriteShaderType.ts @@ -0,0 +1,138 @@ +import Mat4x4 from "../../../DataTypes/Mat4x4"; +import Vec2 from "../../../DataTypes/Vec2"; +import Debug from "../../../Debug/Debug"; +import AnimatedSprite from "../../../Nodes/Sprites/AnimatedSprite"; +import Sprite from "../../../Nodes/Sprites/Sprite"; +import ResourceManager from "../../../ResourceManager/ResourceManager"; +import QuadShaderType from "./QuadShaderType"; + +/** A shader for sprites and animated sprites */ +export default class SpriteShaderType extends QuadShaderType { + constructor(programKey: string){ + super(programKey); + this.resourceManager = ResourceManager.getInstance(); + } + + initBufferObject(): void { + this.bufferObjectKey = "sprite"; + this.resourceManager.createBuffer(this.bufferObjectKey); + } + + render(gl: WebGLRenderingContext, options: Record): void { + const program = this.resourceManager.getShaderProgram(this.programKey); + const buffer = this.resourceManager.getBuffer(this.bufferObjectKey); + const texture = this.resourceManager.getTexture(options.imageKey); + + gl.useProgram(program); + + const vertexData = this.getVertices(options.size.x, options.size.y, options.scale); + + const FSIZE = vertexData.BYTES_PER_ELEMENT; + + // Bind the buffer + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); + + // Attributes + const a_Position = gl.getAttribLocation(program, "a_Position"); + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 4 * FSIZE, 0 * FSIZE); + gl.enableVertexAttribArray(a_Position); + + const a_TexCoord = gl.getAttribLocation(program, "a_TexCoord"); + gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, 4 * FSIZE, 2*FSIZE); + gl.enableVertexAttribArray(a_TexCoord); + + // Uniforms + // Get transformation matrix + // We want a square for our rendering space, so get the maximum dimension of our quad + let maxDimension = Math.max(options.size.x, options.size.y); + + // The size of the rendering space will be a square with this maximum dimension + let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y); + + // Center our translations around (0, 0) + const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension; + const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension; + + // Create our transformation matrix + this.translation.translate(new Float32Array([translateX, translateY])); + this.scale.scale(size); + this.rotation.rotate(options.rotation); + let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation); + + // Pass the translation matrix to our shader + const u_Transform = gl.getUniformLocation(program, "u_Transform"); + gl.uniformMatrix4fv(u_Transform, false, transformation.toArray()); + + // Set up our sampler with our assigned texture unit + const u_Sampler = gl.getUniformLocation(program, "u_Sampler"); + gl.uniform1i(u_Sampler, texture); + + // Pass in texShift + const u_texShift = gl.getUniformLocation(program, "u_texShift"); + gl.uniform2fv(u_texShift, options.texShift); + + // Pass in texScale + const u_texScale = gl.getUniformLocation(program, "u_texScale"); + gl.uniform2fv(u_texScale, options.texScale); + + // Draw the quad + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + /** + * The rendering space always has to be a square, so make sure its square w.r.t to the largest dimension + * @param w The width of the quad in pixels + * @param h The height of the quad in pixels + * @returns An array of the vertices of the quad + */ + getVertices(w: number, h: number, scale: Float32Array): Float32Array { + let x, y; + + if(h > w){ + y = 0.5; + x = w/(2*h); + } else { + x = 0.5; + y = h/(2*w); + } + + // Scale the rendering space if needed + x *= scale[0]; + y *= scale[1]; + + return new Float32Array([ + -x, y, 0.0, 0.0, + -x, -y, 0.0, 1.0, + x, y, 1.0, 0.0, + x, -y, 1.0, 1.0 + ]); + } + + getOptions(sprite: Sprite): Record { + let texShift; + let texScale; + + if(sprite instanceof AnimatedSprite){ + let animationIndex = sprite.animation.getIndexAndAdvanceAnimation(); + let offset = sprite.getAnimationOffset(animationIndex); + texShift = new Float32Array([offset.x / (sprite.cols * sprite.size.x), offset.y / (sprite.rows * sprite.size.y)]); + texScale = new Float32Array([1/(sprite.cols), 1/(sprite.rows)]); + } else { + texShift = new Float32Array([0, 0]); + texScale = new Float32Array([1, 1]); + } + + let options: Record = { + position: sprite.position, + rotation: sprite.rotation, + size: sprite.size, + scale: sprite.scale.toArray(), + imageKey: sprite.imageId, + texShift, + texScale + } + + return options; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/ResourceManager/ResourceManager.ts b/hw3/src/Wolfie2D/ResourceManager/ResourceManager.ts new file mode 100644 index 0000000..501495a --- /dev/null +++ b/hw3/src/Wolfie2D/ResourceManager/ResourceManager.ts @@ -0,0 +1,1035 @@ +import Map from "../DataTypes/Map"; +import Queue from "../DataTypes/Queue"; +import { TiledTilemapData } from "../DataTypes/Tilesets/TiledData"; +import StringUtils from "../Utils/StringUtils"; +import AudioManager from "../Sound/AudioManager"; +import Spritesheet from "../DataTypes/Spritesheet"; +import WebGLProgramType from "../DataTypes/Rendering/WebGLProgramType"; + +/** + * The resource manager for the game engine. + * The resource manager interfaces with the loadable assets of a game such as images, data files, + * and sounds, which are all found in the dist folder. + * This class controls loading and updates the @reference[Scene] with the loading progress, so that the scene does + * not start before all necessary assets are loaded. + */ +export default class ResourceManager { + // Instance for the singleton class + private static instance: ResourceManager; + + // Booleans to keep track of whether or not the ResourceManager is currently loading something + /** Whether or not any resources are loading */ + private loading: boolean; + /** A boolean to indicate that the assets just finished loading */ + private justLoaded: boolean; + + // Functions to do something when loading progresses or is completed such as render a loading screen + /** A function that is called when loading progresses */ + public onLoadProgress: Function; + /** A function that is called when loading completes */ + public onLoadComplete: Function; + + + /** Number to keep track of how many images need to be loaded*/ + private loadonly_imagesLoaded: number; + /** Number to keep track of how many images are loaded */ + private loadonly_imagesToLoad: number; + /** The queue of images we must load */ + private loadonly_imageLoadingQueue: Queue; + /** A map of the images that are currently loaded and being used by the scene. The reference to these images only exist here for easy cleanup. */ + private images: Map; + + /** Number to keep track of how many tilemaps need to be loaded */ + private loadonly_spritesheetsLoaded: number; + /** Number to keep track of how many tilemaps are loaded */ + private loadonly_spritesheetsToLoad: number; + /** The queue of tilemaps we must load */ + private loadonly_spritesheetLoadingQueue: Queue; + /** A map of the tilemaps that are currently loaded and (presumably) being used by the scene */ + private spritesheets: Map; + + /** Number to keep track of how many tilemaps need to be loaded */ + private loadonly_tilemapsLoaded: number; + /** Number to keep track of how many tilemaps are loaded */ + private loadonly_tilemapsToLoad: number; + /** The queue of tilemaps we must load */ + private loadonly_tilemapLoadingQueue: Queue; + /** A map of the tilemaps that are currently loaded and (presumably) being used by the scene */ + private tilemaps: Map; + + /** Number to keep track of how many sounds need to be loaded */ + private loadonly_audioLoaded: number; + /** Number to keep track of how many sounds are loaded */ + private loadonly_audioToLoad: number; + /** The queue of sounds we must load */ + private loadonly_audioLoadingQueue: Queue; + /** A map of the sounds that are currently loaded and (presumably) being used by the scene */ + private audioBuffers: Map; + + /** The total number of "types" of things that need to be loaded (i.e. images and tilemaps) */ + private loadonly_typesToLoad: number; + + private loadonly_jsonLoaded: number; + private loadonly_jsonToLoad: number; + private loadonly_jsonLoadingQueue: Queue; + private jsonObjects: Map>; + + /* ########## INFORMATION SPECIAL TO WEBGL ########## */ + private gl_WebGLActive: boolean; + + private loadonly_gl_ShaderProgramsLoaded: number; + private loadonly_gl_ShaderProgramsToLoad: number; + private loadonly_gl_ShaderLoadingQueue: Queue; + + private gl_ShaderPrograms: Map; + + private gl_Textures: Map; + private gl_NextTextureID: number; + private gl_Buffers: Map; + + private gl: WebGLRenderingContext; + + /* ########## UNLOADING AND EXCLUSION LIST ########## */ + /** A list of resources that will be unloaded at the end of the current scene */ + private resourcesToUnload: Array; + + /** A list of resources to keep until further notice */ + private resourcesToKeep: Array; + + private constructor(){ + this.loading = false; + this.justLoaded = false; + + this.loadonly_imagesLoaded = 0; + this.loadonly_imagesToLoad = 0; + this.loadonly_imageLoadingQueue = new Queue(); + this.images = new Map(); + + this.loadonly_spritesheetsLoaded = 0; + this.loadonly_spritesheetsToLoad = 0; + this.loadonly_spritesheetLoadingQueue = new Queue(); + this.spritesheets = new Map(); + + this.loadonly_tilemapsLoaded = 0; + this.loadonly_tilemapsToLoad = 0; + this.loadonly_tilemapLoadingQueue = new Queue(); + this.tilemaps = new Map(); + + this.loadonly_audioLoaded = 0; + this.loadonly_audioToLoad = 0; + this.loadonly_audioLoadingQueue = new Queue(); + this.audioBuffers = new Map(); + + this.loadonly_jsonLoaded = 0; + this.loadonly_jsonToLoad = 0; + this.loadonly_jsonLoadingQueue = new Queue(); + this.jsonObjects = new Map(); + + this.loadonly_gl_ShaderProgramsLoaded = 0; + this.loadonly_gl_ShaderProgramsToLoad = 0; + this.loadonly_gl_ShaderLoadingQueue = new Queue(); + + this.gl_ShaderPrograms = new Map(); + + this.gl_Textures = new Map(); + this.gl_NextTextureID = 0; + this.gl_Buffers = new Map(); + + this.resourcesToUnload = new Array(); + this.resourcesToKeep = new Array(); + }; + + /* ######################################## SINGLETON ########################################*/ + /** + * Returns the current instance of this class or a new instance if none exist + * @returns The resource manager + */ + static getInstance(): ResourceManager { + if(!this.instance){ + this.instance = new ResourceManager(); + } + + return this.instance; + } + + /* ######################################## PUBLIC FUNCTION ########################################*/ + /** + * Activates or deactivates the use of WebGL + * @param flag True if WebGL should be used, false otherwise + * @param gl The instance of the graphics context, if applicable + */ + public useWebGL(flag: boolean, gl: WebGLRenderingContext): void { + this.gl_WebGLActive = flag; + + if(this.gl_WebGLActive){ + this.gl = gl; + } + } + + /** + * Loads an image from file + * @param key The key to associate the loaded image with + * @param path The path to the image to load + */ + public image(key: string, path: string): void { + this.loadonly_imageLoadingQueue.enqueue({key: key, path: path}); + } + + /** + * Tells the resource manager to keep this resource + * @param key The key of the resource + */ + public keepImage(key: string): void { + this.keepResource(key, ResourceType.IMAGE); + } + + /** + * Retrieves a loaded image + * @param key The key of the loaded image + * @returns The image element associated with this key + */ + public getImage(key: string): HTMLImageElement { + let image = this.images.get(key); + if(image === undefined){ + throw `There is no image associated with key "${key}"` + } + return image; + } + + /** + * Loads a spritesheet from file + * @param key The key to associate the loaded spritesheet with + * @param path The path to the spritesheet to load + */ + public spritesheet(key: string, path: string): void { + this.loadonly_spritesheetLoadingQueue.enqueue({key: key, path: path}); + } + + /** + * Tells the resource manager to keep this resource + * @param key The key of the resource + */ + public keepSpritesheet(key: string): void { + this.keepResource(key, ResourceType.SPRITESHEET); + } + + /** + * Retrieves a loaded spritesheet + * @param key The key of the spritesheet to load + * @returns The loaded Spritesheet + */ + public getSpritesheet(key: string): Spritesheet { + return this.spritesheets.get(key); + } + + /** + * Loads an audio file + * @param key The key to associate with the loaded audio file + * @param path The path to the audio file to load + */ + public audio(key: string, path: string): void { + this.loadonly_audioLoadingQueue.enqueue({key: key, path: path}); + } + + /** + * Tells the resource manager to keep this resource + * @param key The key of the resource + */ + public keepAudio(key: string): void { + this.keepResource(key, ResourceType.AUDIO); + } + + /** + * Retrieves a loaded audio file + * @param key The key of the audio file to load + * @returns The AudioBuffer created from the loaded audio fle + */ + public getAudio(key: string): AudioBuffer { + return this.audioBuffers.get(key); + } + + /** + * Load a tilemap from a json file. Automatically loads related images + * @param key The key to associate with the loaded tilemap + * @param path The path to the tilemap to load + */ + public tilemap(key: string, path: string): void { + this.loadonly_tilemapLoadingQueue.enqueue({key: key, path: path}); + } + + /** + * Tells the resource manager to keep this resource + * @param key The key of the resource + */ + public keepTilemap(key: string): void { + this.keepResource(key, ResourceType.TILEMAP); + } + + /** + * Retreives a loaded tilemap + * @param key The key of the loaded tilemap + * @returns The tilemap data associated with the key + */ + public getTilemap(key: string): TiledTilemapData { + return this.tilemaps.get(key); + } + + /** + * Loads an object from a json file. + * @param key The key to associate with the loaded object + * @param path The path to the json file to load + */ + public object(key: string, path: string){ + this.loadonly_jsonLoadingQueue.enqueue({key: key, path: path}); + } + + /** + * Tells the resource manager to keep this resource + * @param key The key of the resource + */ + public keepObject(key: string): void { + this.keepResource(key, ResourceType.JSON); + } + + /** + * Retreives a loaded object + * @param key The key of the loaded object + * @returns The object data associated with the key + */ + public getObject(key: string){ + return this.jsonObjects.get(key); + } + + /* ######################################## LOAD FUNCTION ########################################*/ + /** + * Loads all resources currently in the queue + * @param callback The function to cal when the resources are finished loading + */ + loadResourcesFromQueue(callback: Function): void { + this.loadonly_typesToLoad = 5; + + this.loading = true; + + // Load everything in the queues. Tilemaps have to come before images because they will add new images to the queue + this.loadTilemapsFromQueue(() => { + console.log("Loaded Tilemaps"); + this.loadSpritesheetsFromQueue(() => { + console.log("Loaded Spritesheets"); + this.loadImagesFromQueue(() => { + console.log("Loaded Images"); + this.loadAudioFromQueue(() => { + console.log("Loaded Audio"); + this.loadObjectsFromQueue(() => { + console.log("Loaded Objects"); + + if(this.gl_WebGLActive){ + this.gl_LoadShadersFromQueue(() => { + console.log("Loaded Shaders"); + this.finishLoading(callback); + }); + } else { + this.finishLoading(callback); + } + }) + }); + }); + }); + }); + } + + private finishLoading(callback: Function): void { + // Done loading + this.loading = false; + this.justLoaded = true; + callback(); + } + + /* ######################################## UNLOAD FUNCTION ########################################*/ + + private keepResource(key: string, type: ResourceType): void { + console.log("Keep resource..."); + for(let i = 0; i < this.resourcesToUnload.length; i++){ + let resource = this.resourcesToUnload[i]; + if(resource.key === key && resource.resourceType === type){ + console.log("Found resource " + key + " of type " + type + ". Keeping."); + let resourceToMove = this.resourcesToUnload.splice(i, 1); + this.resourcesToKeep.push(...resourceToMove); + return; + } + } + } + + /** + * Deletes references to all resources in the resource manager + */ + unloadAllResources(): void { + this.loading = false; + this.justLoaded = false; + + for(let resource of this.resourcesToUnload){ + // Unload the resource + this.unloadResource(resource); + } + } + + private unloadResource(resource: ResourceReference): void { + // Delete the resource itself + switch(resource.resourceType){ + case ResourceType.IMAGE: + this.images.delete(resource.key); + if(this.gl_WebGLActive){ + this.gl_Textures.delete(resource.key); + } + break; + case ResourceType.TILEMAP: + this.tilemaps.delete(resource.key); + break; + case ResourceType.SPRITESHEET: + this.spritesheets.delete(resource.key); + break; + case ResourceType.AUDIO: + this.audioBuffers.delete(resource.key); + break; + case ResourceType.JSON: + this.jsonObjects.delete(resource.key); + break; + /*case ResourceType.SHADER: + this.gl_ShaderPrograms.get(resource.key).delete(this.gl); + this.gl_ShaderPrograms.delete(resource.key); + break;*/ + } + + // Delete any dependencies + for(let dependency of resource.dependencies){ + this.unloadResource(dependency); + } + } + + /* ######################################## WORK FUNCTIONS ########################################*/ + /** + * Loads all tilemaps currently in the tilemap loading queue + * @param onFinishLoading The function to call when loading is complete + */ + private loadTilemapsFromQueue(onFinishLoading: Function): void { + this.loadonly_tilemapsToLoad = this.loadonly_tilemapLoadingQueue.getSize(); + this.loadonly_tilemapsLoaded = 0; + + // If no items to load, we're finished + if(this.loadonly_tilemapsToLoad === 0){ + onFinishLoading(); + return; + } + + while(this.loadonly_tilemapLoadingQueue.hasItems()){ + let tilemap = this.loadonly_tilemapLoadingQueue.dequeue(); + this.loadTilemap(tilemap.key, tilemap.path, onFinishLoading); + } + } + + /** + * Loads a singular tilemap + * @param key The key of the tilemap + * @param pathToTilemapJSON The path to the tilemap JSON file + * @param callbackIfLast The function to call if this is the last tilemap to load + */ + private loadTilemap(key: string, pathToTilemapJSON: string, callbackIfLast: Function): void { + this.loadTextFile(pathToTilemapJSON, (fileText: string) => { + let tilemapObject = JSON.parse(fileText); + + // We can parse the object later - it's much faster than loading + this.tilemaps.add(key, tilemapObject); + let resource = new ResourceReference(key, ResourceType.TILEMAP); + + // Grab the tileset images we need to load and add them to the imageloading queue + for(let tileset of tilemapObject.tilesets){ + if(tileset.image){ + let key = tileset.image; + let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key; + this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true}); + + // Add this image as a dependency to the tilemap + resource.addDependency(new ResourceReference(key, ResourceType.IMAGE)); + } else if(tileset.tiles){ + for(let tile of tileset.tiles){ + let key = tile.image; + let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key; + this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true}); + + // Add this image as a dependency to the tilemap + resource.addDependency(new ResourceReference(key, ResourceType.IMAGE)); + } + } + } + + // Add the resource reference to the list of resource to unload + this.resourcesToUnload.push(resource); + + // Finish loading + this.finishLoadingTilemap(callbackIfLast); + }); + } + + /** + * Finish loading a tilemap. Calls the callback function if this is the last tilemap being loaded + * @param callback The function to call if this is the last tilemap to load + */ + private finishLoadingTilemap(callback: Function): void { + this.loadonly_tilemapsLoaded += 1; + + if(this.loadonly_tilemapsLoaded === this.loadonly_tilemapsToLoad){ + // We're done loading tilemaps + callback(); + } + } + + /** + * Loads all spritesheets currently in the spritesheet loading queue + * @param onFinishLoading The function to call when the spritesheets are done loading + */ + private loadSpritesheetsFromQueue(onFinishLoading: Function): void { + this.loadonly_spritesheetsToLoad = this.loadonly_spritesheetLoadingQueue.getSize(); + this.loadonly_spritesheetsLoaded = 0; + + // If no items to load, we're finished + if(this.loadonly_spritesheetsToLoad === 0){ + onFinishLoading(); + return; + } + + while(this.loadonly_spritesheetLoadingQueue.hasItems()){ + let spritesheet = this.loadonly_spritesheetLoadingQueue.dequeue(); + this.loadSpritesheet(spritesheet.key, spritesheet.path, onFinishLoading); + } + } + + /** + * Loads a singular spritesheet + * @param key The key of the spritesheet to load + * @param pathToSpritesheetJSON The path to the spritesheet JSON file + * @param callbackIfLast The function to call if this is the last spritesheet + */ + private loadSpritesheet(key: string, pathToSpritesheetJSON: string, callbackIfLast: Function): void { + this.loadTextFile(pathToSpritesheetJSON, (fileText: string) => { + let spritesheet = JSON.parse(fileText); + + // We can parse the object later - it's much faster than loading + this.spritesheets.add(key, spritesheet); + + let resource = new ResourceReference(key, ResourceType.SPRITESHEET); + + // Grab the image we need to load and add it to the imageloading queue + let path = StringUtils.getPathFromFilePath(pathToSpritesheetJSON) + spritesheet.spriteSheetImage; + this.loadonly_imageLoadingQueue.enqueue({key: spritesheet.name, path: path, isDependency: true}); + + resource.addDependency(new ResourceReference(spritesheet.name, ResourceType.IMAGE)); + this.resourcesToUnload.push(resource); + + // Finish loading + this.finishLoadingSpritesheet(callbackIfLast); + }); + } + + /** + * Finish loading a spritesheet. Calls the callback function if this is the last spritesheet being loaded + * @param callback The function to call if this is the last spritesheet to load + */ + private finishLoadingSpritesheet(callback: Function): void { + this.loadonly_spritesheetsLoaded += 1; + + if(this.loadonly_spritesheetsLoaded === this.loadonly_spritesheetsToLoad){ + // We're done loading spritesheets + callback(); + } + } + + /** + * Loads all images currently in the image loading queue + * @param onFinishLoading The function to call when there are no more images to load + */ + private loadImagesFromQueue(onFinishLoading: Function): void { + this.loadonly_imagesToLoad = this.loadonly_imageLoadingQueue.getSize(); + this.loadonly_imagesLoaded = 0; + + // If no items to load, we're finished + if(this.loadonly_imagesToLoad === 0){ + onFinishLoading(); + return; + } + + while(this.loadonly_imageLoadingQueue.hasItems()){ + let image = this.loadonly_imageLoadingQueue.dequeue(); + this.loadImage(image.key, image.path, image.isDependency, onFinishLoading); + } + } + + /** + * Loads a singular image + * @param key The key of the image to load + * @param path The path to the image to load + * @param callbackIfLast The function to call if this is the last image + */ + public loadImage(key: string, path: string, isDependency: boolean, callbackIfLast: Function): void { + var image = new Image(); + + image.onload = () => { + // Add to loaded images + this.images.add(key, image); + + // If not a dependency, push it to the unload list. Otherwise it's managed by something else + if(!isDependency){ + this.resourcesToUnload.push(new ResourceReference(key, ResourceType.IMAGE)); + } + + // If WebGL is active, create a texture + if(this.gl_WebGLActive){ + this.createWebGLTexture(key, image); + } + + // Finish image load + this.finishLoadingImage(callbackIfLast); + } + + image.src = path; + } + + /** + * Finish loading an image. If this is the last image, it calls the callback function + * @param callback The function to call if this is the last image + */ + private finishLoadingImage(callback: Function): void { + this.loadonly_imagesLoaded += 1; + + if(this.loadonly_imagesLoaded === this.loadonly_imagesToLoad ){ + // We're done loading images + callback(); + } + } + + /** + * Loads all audio currently in the tilemap loading queue + * @param onFinishLoading The function to call when tilemaps are done loading + */ + private loadAudioFromQueue(onFinishLoading: Function){ + this.loadonly_audioToLoad = this.loadonly_audioLoadingQueue.getSize(); + this.loadonly_audioLoaded = 0; + + // If no items to load, we're finished + if(this.loadonly_audioToLoad === 0){ + onFinishLoading(); + return; + } + + while(this.loadonly_audioLoadingQueue.hasItems()){ + let audio = this.loadonly_audioLoadingQueue.dequeue(); + this.loadAudio(audio.key, audio.path, onFinishLoading); + } + } + + /** + * Load a singular audio file + * @param key The key to the audio file to load + * @param path The path to the audio file to load + * @param callbackIfLast The function to call if this is the last audio file to load + */ + private loadAudio(key: string, path: string, callbackIfLast: Function): void { + let audioCtx = AudioManager.getInstance().getAudioContext(); + + let request = new XMLHttpRequest(); + request.open('GET', path, true); + request.responseType = 'arraybuffer'; + + request.onload = () => { + audioCtx.decodeAudioData(request.response, (buffer) => { + // Add to list of audio buffers + this.audioBuffers.add(key, buffer); + this.resourcesToUnload.push(new ResourceReference(key, ResourceType.AUDIO)); + + // Finish loading sound + this.finishLoadingAudio(callbackIfLast); + }, (error) =>{ + throw "Error loading sound"; + }); + } + request.send(); + } + + /** + * Finish loading an audio file. Calls the callback functon if this is the last audio sample being loaded. + * @param callback The function to call if this is the last audio file to load + */ + private finishLoadingAudio(callback: Function): void { + this.loadonly_audioLoaded += 1; + + if(this.loadonly_audioLoaded === this.loadonly_audioToLoad){ + // We're done loading audio + callback(); + } + } + + /** + * Loads all objects currently in the object loading queue + * @param onFinishLoading The function to call when there are no more objects to load + */ + private loadObjectsFromQueue(onFinishLoading: Function): void { + this.loadonly_jsonToLoad = this.loadonly_jsonLoadingQueue.getSize(); + this.loadonly_jsonLoaded = 0; + + // If no items to load, we're finished + if(this.loadonly_jsonToLoad === 0){ + onFinishLoading(); + return; + } + + while(this.loadonly_jsonLoadingQueue.hasItems()){ + let obj = this.loadonly_jsonLoadingQueue.dequeue(); + this.loadObject(obj.key, obj.path, onFinishLoading); + } + } + + /** + * Loads a singular object + * @param key The key of the object to load + * @param path The path to the object to load + * @param callbackIfLast The function to call if this is the last object + */ + public loadObject(key: string, path: string, callbackIfLast: Function): void { + this.loadTextFile(path, (fileText: string) => { + let obj = JSON.parse(fileText); + this.jsonObjects.add(key, obj); + + this.resourcesToUnload.push(new ResourceReference(key, ResourceType.JSON)); + + this.finishLoadingObject(callbackIfLast); + }); + } + + /** + * Finish loading an object. If this is the last object, it calls the callback function + * @param callback The function to call if this is the last object + */ + private finishLoadingObject(callback: Function): void { + this.loadonly_jsonLoaded += 1; + + if(this.loadonly_jsonLoaded === this.loadonly_jsonToLoad){ + // We're done loading objects + callback(); + } + } + + /* ########## WEBGL SPECIFIC FUNCTIONS ########## */ + + public getTexture(key: string): number { + return this.gl_Textures.get(key); + } + + public getShaderProgram(key: string): WebGLProgram { + return this.gl_ShaderPrograms.get(key).program; + } + + public getBuffer(key: string): WebGLBuffer { + return this.gl_Buffers.get(key); + } + + private createWebGLTexture(imageKey: string, image: HTMLImageElement): void { + // Get the texture ID + const textureID = this.getTextureID(this.gl_NextTextureID); + + // Create the texture + const texture = this.gl.createTexture(); + + // Set up the texture + // Enable texture0 + this.gl.activeTexture(textureID); + + // Bind our texture to texture 0 + this.gl.bindTexture(this.gl.TEXTURE_2D, texture); + + // Set the texture parameters + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + + // Set the texture image + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image); + + // Add the texture to our map with the same key as the image + this.gl_Textures.add(imageKey, this.gl_NextTextureID); + + // Increment the key + this.gl_NextTextureID += 1; + } + + private getTextureID(id: number): number { + // Start with 9 cases - this can be expanded if needed, but for the best performance, + // Textures should be stitched into an atlas + switch(id){ + case 0: return this.gl.TEXTURE0; + case 1: return this.gl.TEXTURE1; + case 2: return this.gl.TEXTURE2; + case 3: return this.gl.TEXTURE3; + case 4: return this.gl.TEXTURE4; + case 5: return this.gl.TEXTURE5; + case 6: return this.gl.TEXTURE6; + case 7: return this.gl.TEXTURE7; + case 8: return this.gl.TEXTURE8; + default: return this.gl.TEXTURE9; + } + } + + public createBuffer(key: string): void { + if(this.gl_WebGLActive){ + let buffer = this.gl.createBuffer(); + + this.gl_Buffers.add(key, buffer); + } + } + + /** + * Enqueues loading of a new shader program + * @param key The key of the shader program + * @param vShaderFilepath + * @param fShaderFilepath + */ + public shader(key: string, vShaderFilepath: string, fShaderFilepath: string): void { + let splitPath = vShaderFilepath.split("."); + let end = splitPath[splitPath.length - 1]; + + if(end !== "vshader"){ + throw `${vShaderFilepath} is not a valid vertex shader - must end in ".vshader`; + } + + splitPath = fShaderFilepath.split("."); + end = splitPath[splitPath.length - 1]; + + if(end !== "fshader"){ + throw `${fShaderFilepath} is not a valid vertex shader - must end in ".fshader`; + } + + let paths = new KeyPath_Shader(); + paths.key = key; + paths.vpath = vShaderFilepath; + paths.fpath = fShaderFilepath; + + this.loadonly_gl_ShaderLoadingQueue.enqueue(paths); + } + + /** + * Tells the resource manager to keep this resource + * @param key The key of the resource + */ + public keepShader(key: string): void { + this.keepResource(key, ResourceType.IMAGE); + } + + private gl_LoadShadersFromQueue(onFinishLoading: Function): void { + this.loadonly_gl_ShaderProgramsToLoad = this.loadonly_gl_ShaderLoadingQueue.getSize(); + this.loadonly_gl_ShaderProgramsLoaded = 0; + + // If webGL isn'active or there are no items to load, we're finished + if(!this.gl_WebGLActive || this.loadonly_gl_ShaderProgramsToLoad === 0){ + onFinishLoading(); + return; + } + + while(this.loadonly_gl_ShaderLoadingQueue.hasItems()){ + let shader = this.loadonly_gl_ShaderLoadingQueue.dequeue(); + this.gl_LoadShader(shader.key, shader.vpath, shader.fpath, onFinishLoading); + } + } + + private gl_LoadShader(key: string, vpath: string, fpath: string, callbackIfLast: Function): void { + this.loadTextFile(vpath, (vFileText: string) => { + const vShader = vFileText; + + this.loadTextFile(fpath, (fFileText: string) => { + const fShader = fFileText + + // Extract the program and shaders + const [shaderProgram, vertexShader, fragmentShader] = this.createShaderProgram(vShader, fShader); + + // Create a wrapper type + const programWrapper = new WebGLProgramType(); + programWrapper.program = shaderProgram; + programWrapper.vertexShader = vertexShader; + programWrapper.fragmentShader = fragmentShader; + + // Add to our map + this.gl_ShaderPrograms.add(key, programWrapper); + + this.resourcesToUnload.push(new ResourceReference(key, ResourceType.SHADER)); + + // Finish loading + this.gl_FinishLoadingShader(callbackIfLast); + }); + }); + } + + private gl_FinishLoadingShader(callback: Function): void { + this.loadonly_gl_ShaderProgramsLoaded += 1; + + if(this.loadonly_gl_ShaderProgramsLoaded === this.loadonly_gl_ShaderProgramsToLoad){ + // We're done loading shaders + callback(); + } + } + + private createShaderProgram(vShaderSource: string, fShaderSource: string){ + const vertexShader = this.loadVertexShader(vShaderSource); + const fragmentShader = this.loadFragmentShader(fShaderSource); + + if(vertexShader === null || fragmentShader === null){ + // We had a problem intializing - error + return null; + } + + // Create a shader program + const program = this.gl.createProgram(); + if(!program) { + // Error creating + console.warn("Failed to create program"); + return null; + } + + // Attach our vertex and fragment shader + this.gl.attachShader(program, vertexShader); + this.gl.attachShader(program, fragmentShader); + + // Link + this.gl.linkProgram(program); + if(!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){ + // Error linking + const error = this.gl.getProgramInfoLog(program); + console.warn("Failed to link program: " + error); + + // Clean up + this.gl.deleteProgram(program); + this.gl.deleteShader(vertexShader); + this.gl.deleteShader(fragmentShader); + return null; + } + + // We successfully create a program + return [program, vertexShader, fragmentShader]; + } + + private loadVertexShader(shaderSource: string): WebGLShader{ + // Create a new vertex shader + return this.loadShader(this.gl.VERTEX_SHADER, shaderSource); + } + + private loadFragmentShader(shaderSource: string): WebGLShader{ + // Create a new fragment shader + return this.loadShader(this.gl.FRAGMENT_SHADER, shaderSource); + } + + private loadShader(type: number, shaderSource: string): WebGLShader{ + const shader = this.gl.createShader(type); + + // If we couldn't create the shader, error + if(shader === null){ + console.warn("Unable to create shader"); + return null; + } + + // Add the source to the shader and compile + this.gl.shaderSource(shader, shaderSource); + this.gl.compileShader(shader); + + // Make sure there were no errors during this process + if(!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){ + // Not compiled - error + const error = this.gl.getShaderInfoLog(shader); + console.warn("Failed to compile shader: " + error); + + // Clean up + this.gl.deleteShader(shader); + return null; + } + + // Sucess, so return the shader + return shader; + } + + /* ########## GENERAL LOADING FUNCTIONS ########## */ + + private loadTextFile(textFilePath: string, callback: Function): void { + let xobj: XMLHttpRequest = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open('GET', textFilePath, true); + xobj.onreadystatechange = function () { + if ((xobj.readyState == 4) && (xobj.status == 200)) { + callback(xobj.responseText); + } + }; + xobj.send(null); + } + + /* ########## LOADING BAR INFO ########## */ + + private getLoadPercent(): number { + return (this.loadonly_tilemapsLoaded/this.loadonly_tilemapsToLoad + + this.loadonly_spritesheetsLoaded/this.loadonly_spritesheetsToLoad + + this.loadonly_imagesLoaded/this.loadonly_imagesToLoad + + this.loadonly_audioLoaded/this.loadonly_audioToLoad) + / this.loadonly_typesToLoad; + } + + update(deltaT: number): void { + if(this.loading){ + if(this.onLoadProgress){ + this.onLoadProgress(this.getLoadPercent()); + } + } else if(this.justLoaded){ + this.justLoaded = false; + if(this.onLoadComplete){ + this.onLoadComplete(); + } + } + } +} + +/** + * A class representing a reference to a resource. + * This is used for the exemption list to assure assets and their dependencies don't get + * destroyed if they are still needed. + */ +class ResourceReference { + key: string; + resourceType: ResourceType; + dependencies: Array; + + constructor(key: string, resourceType: ResourceType){ + this.key = key; + this.resourceType = resourceType; + this. dependencies = new Array(); + } + + addDependency(resource: ResourceReference): void { + this.dependencies.push(resource); + } +} + + +enum ResourceType { + IMAGE = "IMAGE", + TILEMAP = "TILEMAP", + SPRITESHEET = "SPRITESHEET", + AUDIO = "AUDIO", + JSON = "JSON", + SHADER = "SHADER" +} + +/** + * A pair representing a key and the path of the resource to load + */ +class KeyPathPair { + key: string; + path: string; + isDependency?: boolean = false; +} + +class KeyPath_Shader { + key: string; + vpath: string; + fpath: string; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Factories/CanvasNodeFactory.ts b/hw3/src/Wolfie2D/Scene/Factories/CanvasNodeFactory.ts new file mode 100644 index 0000000..9611850 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Factories/CanvasNodeFactory.ts @@ -0,0 +1,239 @@ +import Scene from "../Scene"; +import UIElement from "../../Nodes/UIElement"; +import Graphic from "../../Nodes/Graphic"; +import Sprite from "../../Nodes/Sprites/Sprite"; +import AnimatedSprite from "../../Nodes/Sprites/AnimatedSprite"; +import { GraphicType } from "../../Nodes/Graphics/GraphicTypes"; +import { UIElementType } from "../../Nodes/UIElements/UIElementTypes"; +import Point from "../../Nodes/Graphics/Point"; +import Vec2 from "../../DataTypes/Vec2"; +import Button from "../../Nodes/UIElements/Button"; +import Label from "../../Nodes/UIElements/Label"; +import Slider from "../../Nodes/UIElements/Slider"; +import TextInput from "../../Nodes/UIElements/TextInput"; +import Rect from "../../Nodes/Graphics/Rect"; +import ResourceManager from "../../ResourceManager/ResourceManager"; +import Line from "../../Nodes/Graphics/Line"; + +// @ignorePage + +/** + * A factory that abstracts adding @reference[CanvasNode]s to the @reference[Scene]. + * Access methods in this factory through Scene.add.[methodName](). + */ +export default class CanvasNodeFactory { + protected scene: Scene; + protected resourceManager: ResourceManager; + + init(scene: Scene): void { + this.scene = scene; + this.resourceManager = ResourceManager.getInstance(); + } + + /** + * Adds an instance of a UIElement to the current scene - i.e. any class that extends UIElement + * @param type The type of UIElement to add + * @param layerName The layer to add the UIElement to + * @param options Any additional arguments to feed to the constructor + * @returns A new UIElement + */ + addUIElement = (type: string | UIElementType, layerName: string, options?: Record): UIElement => { + // Get the layer + let layer = this.scene.getLayer(layerName); + + let instance: UIElement; + + switch(type){ + case UIElementType.BUTTON: + instance = this.buildButton(options); + break; + case UIElementType.LABEL: + instance = this.buildLabel(options); + break; + case UIElementType.SLIDER: + instance = this.buildSlider(options); + break; + case UIElementType.TEXT_INPUT: + instance = this.buildTextInput(options); + break; + default: + throw `UIElementType '${type}' does not exist, or is registered incorrectly.` + } + + instance.setScene(this.scene); + instance.id = this.scene.generateId(); + this.scene.getSceneGraph().addNode(instance); + + // Add instance to layer + layer.addNode(instance) + + return instance; + } + + /** + * Adds a sprite to the current scene + * @param key The key of the image the sprite will represent + * @param layerName The layer on which to add the sprite + * @returns A new Sprite + */ + addSprite = (key: string, layerName: string): Sprite => { + let layer = this.scene.getLayer(layerName); + + let instance = new Sprite(key); + + // Add instance to scene + instance.setScene(this.scene); + instance.id = this.scene.generateId(); + + if(!(this.scene.isParallaxLayer(layerName) || this.scene.isUILayer(layerName))){ + this.scene.getSceneGraph().addNode(instance); + } + + // Add instance to layer + layer.addNode(instance); + + return instance; + } + + /** + * Adds an AnimatedSprite to the current scene + * @param key The key of the image the sprite will represent + * @param layerName The layer on which to add the sprite + * @returns A new AnimatedSprite + */ + addAnimatedSprite = (key: string, layerName: string): AnimatedSprite => { + let layer = this.scene.getLayer(layerName); + let spritesheet = this.resourceManager.getSpritesheet(key); + let instance = new AnimatedSprite(spritesheet); + + // Add instance fo scene + instance.setScene(this.scene); + instance.id = this.scene.generateId(); + + if(!(this.scene.isParallaxLayer(layerName) || this.scene.isUILayer(layerName))){ + this.scene.getSceneGraph().addNode(instance); + } + + // Add instance to layer + layer.addNode(instance); + + return instance; + } + + /** + * Adds a new graphic element to the current Scene + * @param type The type of graphic to add + * @param layerName The layer on which to add the graphic + * @param options Any additional arguments to send to the graphic constructor + * @returns A new Graphic + */ + addGraphic = (type: GraphicType | string, layerName: string, options?: Record): Graphic => { + // Get the layer + let layer = this.scene.getLayer(layerName); + + let instance: Graphic; + + switch(type){ + case GraphicType.POINT: + instance = this.buildPoint(options); + break; + case GraphicType.LINE: + instance = this.buildLine(options); + break; + case GraphicType.RECT: + instance = this.buildRect(options); + break; + default: + throw `GraphicType '${type}' does not exist, or is registered incorrectly.` + } + + // Add instance to scene + instance.setScene(this.scene); + instance.id = this.scene.generateId(); + + if(!(this.scene.isParallaxLayer(layerName) || this.scene.isUILayer(layerName))){ + this.scene.getSceneGraph().addNode(instance); + } + + // Add instance to layer + layer.addNode(instance); + + return instance; + } + + /* ---------- BUILDERS ---------- */ + + buildButton(options?: Record): Button { + this.checkIfPropExists("Button", options, "position", Vec2, "Vec2"); + this.checkIfPropExists("Button", options, "text", "string"); + + return new Button(options.position, options.text); + } + + buildLabel(options?: Record): Label { + this.checkIfPropExists("Label", options, "position", Vec2, "Vec2"); + this.checkIfPropExists("Label", options, "text", "string"); + + return new Label(options.position, options.text) + } + + buildSlider(options: Record): Slider { + this.checkIfPropExists("Slider", options, "position", Vec2, "Vec2"); + + let initValue = 0; + if(options.value !== undefined){ + initValue = options.value; + } + + return new Slider(options.position, initValue); + } + + buildTextInput(options: Record): TextInput { + this.checkIfPropExists("TextInput", options, "position", Vec2, "Vec2"); + + return new TextInput(options.position); + } + + buildPoint(options?: Record): Point { + this.checkIfPropExists("Point", options, "position", Vec2, "Vec2"); + + return new Point(options.position); + } + + buildLine(options?: Record): Point { + this.checkIfPropExists("Line", options, "start", Vec2, "Vec2"); + this.checkIfPropExists("Line", options, "end", Vec2, "Vec2"); + + return new Line(options.start, options.end); + } + + buildRect(options?: Record): Rect { + this.checkIfPropExists("Rect", options, "position", Vec2, "Vec2"); + this.checkIfPropExists("Rect", options, "size", Vec2, "Vec2"); + + return new Rect(options.position, options.size); + } + + /* ---------- ERROR HANDLING ---------- */ + + checkIfPropExists(objectName: string, options: Record, prop: string, type: (new (...args: any) => T) | string, typeName?: string){ + if(!options || options[prop] === undefined){ + // Check that the options object has the property + throw `${objectName} object requires argument ${prop} of type ${typeName}, but none was provided.`; + } else { + // Check that the property has the correct type + if((typeof type) === "string"){ + if(!(typeof options[prop] === type)){ + throw `${objectName} object requires argument ${prop} of type ${type}, but provided ${prop} was not of type ${type}.`; + } + } else if(type instanceof Function){ + // If type is a constructor, check against that + if(!(options[prop] instanceof type)){ + throw `${objectName} object requires argument ${prop} of type ${typeName}, but provided ${prop} was not of type ${typeName}.`; + } + } else { + throw `${objectName} object requires argument ${prop} of type ${typeName}, but provided ${prop} was not of type ${typeName}.`; + } + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Factories/FactoryManager.ts b/hw3/src/Wolfie2D/Scene/Factories/FactoryManager.ts new file mode 100644 index 0000000..455e539 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Factories/FactoryManager.ts @@ -0,0 +1,81 @@ +import Scene from "../Scene"; +import CanvasNodeFactory from "./CanvasNodeFactory"; +import TilemapFactory from "./TilemapFactory"; +import Tilemap from "../../Nodes/Tilemap"; +import { UIElementType } from "../../Nodes/UIElements/UIElementTypes"; +import UIElement from "../../Nodes/UIElement"; +import Sprite from "../../Nodes/Sprites/Sprite"; +import { GraphicType } from "../../Nodes/Graphics/GraphicTypes"; +import Graphic from "../../Nodes/Graphic"; +import AnimatedSprite from "../../Nodes/Sprites/AnimatedSprite"; +import Vec2 from "../../DataTypes/Vec2"; +import Layer from "../Layer"; + +/** + * The manager of all factories used for adding @reference[GameNode]s to the @reference[Scene]. + */ +export default class FactoryManager { + + // Constructors are called here to allow assignment of their functions to functions in this class + private canvasNodeFactory: CanvasNodeFactory = new CanvasNodeFactory(); + private tilemapFactory: TilemapFactory = new TilemapFactory(); + + constructor(scene: Scene, tilemaps: Array){ + this.canvasNodeFactory.init(scene); + this.tilemapFactory.init(scene, tilemaps); + } + + // Expose all of the factories through the factory manager + /** + * Adds an instance of a UIElement to the current scene - i.e. any class that extends UIElement + * @param type The type of UIElement to add + * @param layerName The layer to add the UIElement to + * @param options Any additional arguments to feed to the constructor + * @returns A new UIElement + */ + uiElement(type: string | UIElementType, layerName: string, options?: Record): UIElement { + return this.canvasNodeFactory.addUIElement(type, layerName, options); + } + + /** + * Adds a sprite to the current scene + * @param key The key of the image the sprite will represent + * @param layerName The layer on which to add the sprite + * @returns A new Sprite + */ + sprite(key: string, layerName: string): Sprite { + return this.canvasNodeFactory.addSprite(key, layerName); + } + + /** + * Adds an AnimatedSprite to the current scene + * @param key The key of the image the sprite will represent + * @param layerName The layer on which to add the sprite + * @returns A new AnimatedSprite + */ + animatedSprite(key: string, layerName: string): AnimatedSprite { + return this.canvasNodeFactory.addAnimatedSprite(key, layerName); + } + + /** + * Adds a new graphic element to the current Scene + * @param type The type of graphic to add + * @param layerName The layer on which to add the graphic + * @param options Any additional arguments to send to the graphic constructor + * @returns A new Graphic + */ + graphic(type: GraphicType | string, layerName: string, options?: Record): Graphic { + return this.canvasNodeFactory.addGraphic(type, layerName, options); + } + + /** + * Adds a tilemap to the scene + * @param key The key of the loaded tilemap to load + * @param constr The constructor of the desired tilemap + * @param args Additional arguments to send to the tilemap constructor + * @returns An array of Layers, each of which contains a layer of the tilemap as its own Tilemap instance. + */ + tilemap(key: string, scale?: Vec2): Array { + return this.tilemapFactory.add(key, scale); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Factories/TilemapFactory.ts b/hw3/src/Wolfie2D/Scene/Factories/TilemapFactory.ts new file mode 100644 index 0000000..d41f7a1 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Factories/TilemapFactory.ts @@ -0,0 +1,232 @@ +import Scene from "../Scene"; +import Tilemap from "../../Nodes/Tilemap"; +import ResourceManager from "../../ResourceManager/ResourceManager"; +import OrthogonalTilemap from "../../Nodes/Tilemaps/OrthogonalTilemap"; +import Layer from "../Layer"; +import Tileset from "../../DataTypes/Tilesets/Tileset"; +import Vec2 from "../../DataTypes/Vec2"; +import { TiledCollectionTile } from "../../DataTypes/Tilesets/TiledData"; +import Sprite from "../../Nodes/Sprites/Sprite"; +import PositionGraph from "../../DataTypes/Graphs/PositionGraph"; +import Navmesh from "../../Pathfinding/Navmesh"; + +// @ignorePage + +/** + * A factory that abstracts adding @reference[Tilemap]s to the @reference[Scene]. + * Access methods in this factory through Scene.add.[methodName](). + */ +export default class TilemapFactory { + private scene: Scene; + private tilemaps: Array; + private resourceManager: ResourceManager; + + init(scene: Scene, tilemaps: Array): void { + this.scene = scene; + this.tilemaps = tilemaps; + this.resourceManager = ResourceManager.getInstance(); + } + + // TODO - This is specifically catered to Tiled tilemaps right now. In the future, + // it would be good to have a "parseTilemap" function that would convert the tilemap + // data into a standard format. This could allow for support from other programs + // or the development of an internal level builder tool + /** + * Adds a tilemap to the scene + * @param key The key of the loaded tilemap to load + * @param constr The constructor of the desired tilemap + * @param args Additional arguments to send to the tilemap constructor + * @returns An array of Layers, each of which contains a layer of the tilemap as its own Tilemap instance. + */ + add = (key: string, scale: Vec2 = new Vec2(1, 1)): Array => { + // Get Tilemap Data + let tilemapData = this.resourceManager.getTilemap(key); + + // Set the constructor for this tilemap to either be orthographic or isometric + let constr: new(...args: any) => Tilemap; + if(tilemapData.orientation === "orthographic"){ + constr = OrthogonalTilemap; + } else { + // No isometric tilemap support right now, so Orthographic tilemap + constr = OrthogonalTilemap; + } + + // Initialize the return value array + let sceneLayers = new Array(); + + // Create all of the tilesets for this tilemap + let tilesets = new Array(); + + let collectionTiles = new Array(); + + for(let tileset of tilemapData.tilesets){ + if(tileset.image){ + // If this is a standard tileset and not a collection, create a tileset for it. + // TODO - We are ignoring collection tilesets for now. This is likely not a great idea in practice, + // as theoretically someone could want to use one for a standard tilemap. We are assuming for now + // that we only want to use them for object layers + tilesets.push(new Tileset(tileset)); + } else { + tileset.tiles.forEach(tile => tile.id += tileset.firstgid); + collectionTiles.push(...tileset.tiles); + } + } + + // Loop over the layers of the tilemap and create tiledlayers or object layers + for(let layer of tilemapData.layers){ + + let sceneLayer; + let isParallaxLayer = false; + let depth = 0; + + if(layer.properties){ + for(let prop of layer.properties){ + if(prop.name === "Parallax"){ + isParallaxLayer = prop.value; + } else if(prop.name === "Depth") { + depth = prop.value; + } + } + } + + if(isParallaxLayer){ + sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1), depth); + } else { + sceneLayer = this.scene.addLayer(layer.name, depth); + } + + if(layer.type === "tilelayer"){ + // Create a new tilemap object for the layer + let tilemap = new constr(tilemapData, layer, tilesets, scale); + tilemap.id = this.scene.generateId(); + tilemap.setScene(this.scene); + + // Add tilemap to scene + this.tilemaps.push(tilemap); + + sceneLayer.addNode(tilemap); + + // Register tilemap with physics if it's collidable + if(tilemap.isCollidable){ + tilemap.addPhysics(); + + if(layer.properties){ + for(let item of layer.properties){ + if(item.name === "Group"){ + tilemap.setGroup(item.value); + } + } + } + } + } else { + + let isNavmeshPoints = false; + let navmeshName; + let edges; + if(layer.properties){ + for(let prop of layer.properties){ + if(prop.name === "NavmeshPoints"){ + isNavmeshPoints = true; + } else if(prop.name === "name"){ + navmeshName = prop.value; + } else if(prop.name === "edges"){ + edges = prop.value + } + } + } + + if(isNavmeshPoints){ + let g = new PositionGraph(); + + for(let obj of layer.objects){ + g.addPositionedNode(new Vec2(obj.x, obj.y)); + } + + for(let edge of edges){ + g.addEdge(edge.from, edge.to); + } + + this.scene.getNavigationManager().addNavigableEntity(navmeshName, new Navmesh(g)); + + continue; + } + + // Layer is an object layer, so add each object as a sprite to a new layer + for(let obj of layer.objects){ + // Check if obj is collidable + let hasPhysics = false; + let isCollidable = false; + let isTrigger = false; + let onEnter = null; + let onExit = null; + let triggerGroup = null; + let group = ""; + + if(obj.properties){ + for(let prop of obj.properties){ + if(prop.name === "HasPhysics"){ + hasPhysics = prop.value; + } else if(prop.name === "Collidable"){ + isCollidable = prop.value; + } else if(prop.name === "Group"){ + group = prop.value; + } else if(prop.name === "IsTrigger"){ + isTrigger = prop.value; + } else if(prop.name === "TriggerGroup"){ + triggerGroup = prop.value; + } else if(prop.name === "TriggerOnEnter"){ + onEnter = prop.value; + } else if(prop.name === "TriggerOnExit"){ + onExit = prop.value; + } + } + } + + let sprite: Sprite; + + // Check if obj is a tile from a tileset + for(let tileset of tilesets){ + if(tileset.hasTile(obj.gid)){ + // The object is a tile from this set + let imageKey = tileset.getImageKey(); + let offset = tileset.getImageOffsetForTile(obj.gid); + sprite = this.scene.add.sprite(imageKey, layer.name); + let size = tileset.getTileSize().clone(); + sprite.position.set((obj.x + size.x/2)*scale.x, (obj.y - size.y/2)*scale.y); + sprite.setImageOffset(offset); + sprite.size.copy(size); + sprite.scale.set(scale.x, scale.y); + } + } + + // Not in a tileset, must correspond to a collection + if(!sprite){ + for(let tile of collectionTiles){ + if(obj.gid === tile.id){ + let imageKey = tile.image; + sprite = this.scene.add.sprite(imageKey, layer.name); + sprite.position.set((obj.x + tile.imagewidth/2)*scale.x, (obj.y - tile.imageheight/2)*scale.y); + sprite.scale.set(scale.x, scale.y); + } + } + } + + // Now we have sprite. Associate it with our physics object if there is one + if(hasPhysics){ + // Make the sprite a static physics object + sprite.addPhysics(sprite.boundary.clone(), Vec2.ZERO, isCollidable, true); + sprite.setGroup(group); + if(isTrigger && triggerGroup !== null){ + sprite.setTrigger(triggerGroup, onEnter, onExit); + } + } + } + } + + // Update the return value + sceneLayers.push(sceneLayer); + } + + return sceneLayers; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Layer.ts b/hw3/src/Wolfie2D/Scene/Layer.ts new file mode 100644 index 0000000..54535ca --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Layer.ts @@ -0,0 +1,184 @@ +import Scene from "./Scene"; +import MathUtils from "../Utils/MathUtils"; +import GameNode from "../Nodes/GameNode"; + + +/** + * A layer in the scene. Layers are used for sorting @reference[GameNode]s by depth. + */ +export default class Layer { + /** The scene this layer belongs to */ + protected scene: Scene; + + /** The name of this layer */ + protected name: string; + + /** Whether this layer is paused or not */ + protected paused: boolean; + + /** Whether this layer is hidden from being rendered or not */ + protected hidden: boolean; + + /** The global alpha level of this layer */ + protected alpha: number; + + /** An array of the GameNodes that belong to this layer */ + protected items: Array; + + /** Whether or not this layer should be ysorted */ + protected ySort: boolean; + + /** The depth of this layer compared to other layers */ + protected depth: number; + + /** + * Creates a new layer. To do this in a game, use the addLayer() method in @refrence[Scene] + * @param scene The scene to add the layer to + * @param name The name of the layer + */ + constructor(scene: Scene, name: string){ + this.scene = scene; + this.name = name; + this.paused = false; + this.hidden = false; + this.alpha = 1; + this.items = new Array(); + this.ySort = false; + this.depth = 0; + } + + /** + * Retreives the name of the layer + * @returns The name of the layer + */ + getName(): string { + return this.name; + } + + /** + * Pauses/Unpauses the layer. Affects all elements in this layer + * @param pauseValue True if the layer should be paused, false if not + */ + setPaused(pauseValue: boolean): void { + this.paused = pauseValue; + } + + /** + * Returns whether or not the layer is paused + */ + isPaused(): boolean { + return this.paused; + } + + /** + * Sets the opacity of the layer + * @param alpha The new opacity value in the range [0, 1] + */ + setAlpha(alpha: number): void { + this.alpha = MathUtils.clamp(alpha, 0, 1); + } + + /** + * Gets the opacity of the layer + * @returns The opacity + */ + getAlpha(): number { + return this.alpha; + } + + /** + * Sets the layer's hidden value. If hidden, a layer will not be rendered, but will still update + * @param hidden The hidden value of the layer + */ + setHidden(hidden: boolean): void { + this.hidden = hidden; + } + + /** + * Returns the hideen value of the lyaer + * @returns True if the scene is hidden, false otherwise + */ + isHidden(): boolean { + return this.hidden; + } + + /** Pauses this scene and hides it */ + disable(): void { + this.paused = true; + this.hidden = true; + } + + /** Unpauses this layer and makes it visible */ + enable(): void { + this.paused = false; + this.hidden = false; + } + + /** + * Sets whether or not the scene will ySort automatically. + * ySorting means that CanvasNodes on this layer will have their depth sorted depending on their y-value. + * This means that if an object is "higher" in the scene, it will sort behind objects that are "lower". + * This is useful for 3/4 view games, or similar situations, where you sometimes want to be in front of objects, + * and other times want to be behind the same objects. + * @param ySort True if ySorting should be active, false if not + */ + setYSort(ySort: boolean): void { + this.ySort = ySort; + } + + /** + * Gets the ySort status of the scene + * @returns True if ySorting is occurring, false otherwise + */ + getYSort(): boolean { + return this.ySort; + } + + /** + * Sets the depth of the layer compared to other layers. A larger number means the layer will be closer to the screen. + * @param depth The depth of the layer. + */ + setDepth(depth: number): void { + this.depth = depth; + } + + /** + * Retrieves the depth of the layer. + * @returns The depth + */ + getDepth(): number { + return this.depth; + } + + /** + * Adds a node to this layer + * @param node The node to add to this layer. + */ + addNode(node: GameNode): void { + this.items.push(node); + node.setLayer(this); + } + + /** + * Removes a node from this layer + * @param node The node to remove + * @returns true if the node was removed, false otherwise + */ + removeNode(node: GameNode): void { + // Find and remove the node + let index = this.items.indexOf(node); + + if(index !== -1){ + this.items.splice(index, 1); + node.setLayer(undefined); + } + } + + /** + * Retreives all GameNodes from this layer + * @returns an Array that contains all of the GameNodes in this layer. + */ + getItems(): Array { + return this.items; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Layers/ParallaxLayer.ts b/hw3/src/Wolfie2D/Scene/Layers/ParallaxLayer.ts new file mode 100644 index 0000000..0260139 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Layers/ParallaxLayer.ts @@ -0,0 +1,23 @@ +import Layer from "../Layer"; +import Vec2 from "../../DataTypes/Vec2"; +import Scene from "../Scene"; + +/** + * An extension of a Layer that has a parallax value. + */ +export default class ParallaxLayer extends Layer { + /** The value of the parallax of the Layer */ + parallax: Vec2; + + /** + * Creates a new ParallaxLayer. + * Use addParallaxLayer() in @reference[Scene] to add a layer of this type to your game. + * @param scene The Scene to add this ParallaxLayer to + * @param name The name of the ParallaxLayer + * @param parallax The parallax level + */ + constructor(scene: Scene, name: string, parallax: Vec2){ + super(scene, name); + this.parallax = parallax; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Layers/UILayer.ts b/hw3/src/Wolfie2D/Scene/Layers/UILayer.ts new file mode 100644 index 0000000..5843129 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Layers/UILayer.ts @@ -0,0 +1,20 @@ +import Vec2 from "../../DataTypes/Vec2"; +import Scene from "../Scene"; +import ParallaxLayer from "./ParallaxLayer"; + +/** + * A Layer strictly to be used for managing UIElements. + * This is intended to be a Layer that always stays in the same place, + * and thus renders things like a HUD or an inventory without taking into consideration the \reference[Viewport] scroll. + */ +export default class UILayer extends ParallaxLayer { + /** + * Creates a new UILayer. + * Use addUILayer() in @reference[Scene] to add a layer of this type to your game. + * @param scene The Scene to add this UILayer to + * @param name The name of the UILayer + */ + constructor(scene: Scene, name: string){ + super(scene, name, Vec2.ZERO); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/Scene.ts b/hw3/src/Wolfie2D/Scene/Scene.ts new file mode 100644 index 0000000..ee7f5a3 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/Scene.ts @@ -0,0 +1,444 @@ +import Layer from "./Layer"; +import Viewport from "../SceneGraph/Viewport"; +import Vec2 from "../DataTypes/Vec2"; +import SceneGraph from "../SceneGraph/SceneGraph"; +import PhysicsManager from "../Physics/PhysicsManager"; +import BasicPhysicsManager from "../Physics/BasicPhysicsManager"; +import SceneGraphArray from "../SceneGraph/SceneGraphArray"; +import FactoryManager from "./Factories/FactoryManager"; +import Tilemap from "../Nodes/Tilemap"; +import ResourceManager from "../ResourceManager/ResourceManager"; +import Game from "../Loop/Game"; +import SceneManager from "./SceneManager"; +import Receiver from "../Events/Receiver"; +import Emitter from "../Events/Emitter"; +import Updateable from "../DataTypes/Interfaces/Updateable"; +import NavigationManager from "../Pathfinding/NavigationManager"; +import AIManager from "../AI/AIManager"; +import Map from "../DataTypes/Map"; +import ParallaxLayer from "./Layers/ParallaxLayer"; +import UILayer from "./Layers/UILayer"; +import CanvasNode from "../Nodes/CanvasNode"; +import GameNode from "../Nodes/GameNode"; +import SceneOptions from "./SceneOptions"; +import RenderingManager from "../Rendering/RenderingManager"; +import Debug from "../Debug/Debug"; +import TimerManager from "../Timing/TimerManager"; +import TweenManager from "../Rendering/Animations/TweenManager"; + +/** + * Scenes are the main container in the game engine. + * Your main scene is the current level or menu of the game, and will contain all of the GameNodes needed. + * Scenes provide an easy way to load assets, add assets to the game world, and unload assets, + * and have lifecycle methods exposed for these functions. + */ +export default class Scene implements Updateable { + /** The size of the game world. */ + protected worldSize: Vec2; + + /** The viewport. */ + protected viewport: Viewport; + + /** A flag that represents whether this scene is running or not. */ + protected running: boolean; + + /** The manager of this scene. */ + protected sceneManager: SceneManager; + + /** The receiver for this scene. */ + protected receiver: Receiver; + + /** The emitter for this scene. */ + protected emitter: Emitter; + + /** This list of tilemaps in this scene. */ + protected tilemaps: Array; + + /** A map from layer names to the layers themselves */ + protected layers: Map; + + /** A map from parallax layer names to the parallax layers themselves */ + protected parallaxLayers: Map; + + /** A map from uiLayer names to the uiLayers themselves */ + protected uiLayers: Map; + + /** The scene graph of the Scene*/ + protected sceneGraph: SceneGraph; + + /** The physics manager of the Scene */ + protected physicsManager: PhysicsManager; + + /** The navigation manager of the Scene */ + protected navManager: NavigationManager; + + /** The AI manager of the Scene */ + protected aiManager: AIManager; + + /** The renderingManager of the scene */ + protected renderingManager: RenderingManager; + + /** An interface that allows the adding of different nodes to the scene */ + public add: FactoryManager; + + /** An interface that allows the loading of different files for use in the scene. An alias for resourceManager */ + public load: ResourceManager; + + /** An interface that allows the loading and unloading of different files for use in the scene */ + public resourceManager: ResourceManager; + + /** The configuration options for this scene */ + public sceneOptions: SceneOptions; + + /** + * Creates a new Scene. To add a new Scene in your game, use changeToScene() in @reference[SceneManager] + * @param viewport The viewport of the game + * @param sceneManager The SceneManager that owns this Scene + * @param renderingManager The RenderingManager that will handle this Scene's rendering + * @param game The instance of the Game + * @param options The options for Scene initialization + */ + constructor(viewport: Viewport, sceneManager: SceneManager, renderingManager: RenderingManager, options: Record){ + this.sceneOptions = SceneOptions.parse(options === undefined ? {} : options); + + this.worldSize = new Vec2(500, 500); + this.viewport = viewport; + this.viewport.setBounds(0, 0, 2560, 1280); + this.running = false; + this.sceneManager = sceneManager; + this.receiver = new Receiver(); + this.emitter = new Emitter(); + + this.tilemaps = new Array(); + this.sceneGraph = new SceneGraphArray(this.viewport, this); + + this.layers = new Map(); + this.uiLayers = new Map(); + this.parallaxLayers = new Map(); + + this.physicsManager = new BasicPhysicsManager(this.sceneOptions.physics); + this.navManager = new NavigationManager(); + this.aiManager = new AIManager(); + this.renderingManager = renderingManager; + + this.add = new FactoryManager(this, this.tilemaps); + + this.load = ResourceManager.getInstance() + this.resourceManager = this.load; + + // Get the timer manager and clear any existing timers + TimerManager.getInstance().clearTimers(); + } + + /** A lifecycle method that gets called immediately after a new scene is created, before anything else. */ + initScene(init: Record): void {} + + /** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */ + loadScene(): void {} + + /** A lifecycle method called strictly after loadScene(). Create any game objects you wish to use in the scene here. */ + startScene(): void {} + + /** + * A lifecycle method called every frame of the game. This is where you can dynamically do things like add in new enemies + * @param delta The time this frame represents + */ + updateScene(deltaT: number): void {} + + /** A lifecycle method that gets called on scene destruction. Specify which files you no longer need for garbage collection. */ + unloadScene(): void {} + + update(deltaT: number): void { + this.updateScene(deltaT); + + // Do time updates + TimerManager.getInstance().update(deltaT); + + // Do all AI updates + this.aiManager.update(deltaT); + + // Update all physics objects + this.physicsManager.update(deltaT); + + // Update all canvas objects + this.sceneGraph.update(deltaT); + + // Update all tilemaps + this.tilemaps.forEach(tilemap => { + if(!tilemap.getLayer().isPaused()){ + tilemap.update(deltaT); + } + }); + + // Update all tweens + TweenManager.getInstance().update(deltaT); + + // Update viewport + this.viewport.update(deltaT); + } + + /** + * Collects renderable sets and coordinates with the RenderingManager to draw the Scene + */ + render(): void { + // Get the visible set of nodes + let visibleSet = this.sceneGraph.getVisibleSet(); + + // Add parallax layer items to the visible set (we're rendering them all for now) + this.parallaxLayers.forEach(key => { + let pLayer = this.parallaxLayers.get(key); + for(let node of pLayer.getItems()){ + if(node instanceof CanvasNode){ + visibleSet.push(node); + } + } + }); + + // Send the visible set, tilemaps, and uiLayers to the renderer + this.renderingManager.render(visibleSet, this.tilemaps, this.uiLayers); + + let nodes = this.sceneGraph.getAllNodes(); + this.tilemaps.forEach(tilemap => tilemap.visible ? nodes.push(tilemap) : 0); + Debug.setNodes(nodes); + } + + /** + * Sets the scene as running or not + * @param running True if the Scene should be running, false if not + */ + setRunning(running: boolean): void { + this.running = running; + } + + /** + * Returns whether or not the Scene is running + * @returns True if the scene is running, false otherwise + */ + isRunning(): boolean { + return this.running; + } + + /** + * Removes a node from this Scene + * @param node The node to remove + */ + remove(node: GameNode): void { + // Remove from the scene graph + if(node instanceof CanvasNode){ + this.sceneGraph.removeNode(node); + } + + } + + /** Destroys this scene and all nodes in it */ + destroy(): void { + for(let node of this.sceneGraph.getAllNodes()){ + node.destroy(); + } + + for(let tilemap of this.tilemaps){ + tilemap.destroy(); + } + + this.receiver.destroy(); + + delete this.sceneGraph; + delete this.physicsManager; + delete this.navManager; + delete this.aiManager; + delete this.receiver; + } + + /** + * Adds a new layer to the scene and returns it + * @param name The name of the new layer + * @param depth The depth of the layer + * @returns The newly created Layer + */ + addLayer(name: string, depth?: number): Layer { + if(this.layers.has(name) || this.parallaxLayers.has(name) || this.uiLayers.has(name)){ + throw `Layer with name ${name} already exists`; + } + + let layer = new Layer(this, name); + + this.layers.add(name, layer); + + if(depth){ + layer.setDepth(depth); + } + + return layer; + } + + /** + * Adds a new parallax layer to this scene and returns it + * @param name The name of the parallax layer + * @param parallax The parallax level + * @param depth The depth of the layer + * @returns The newly created ParallaxLayer + */ + addParallaxLayer(name: string, parallax: Vec2, depth?: number): ParallaxLayer { + if(this.layers.has(name) || this.parallaxLayers.has(name) || this.uiLayers.has(name)){ + throw `Layer with name ${name} already exists`; + } + + let layer = new ParallaxLayer(this, name, parallax); + + this.parallaxLayers.add(name, layer); + + if(depth){ + layer.setDepth(depth); + } + + return layer; + } + + /** + * Adds a new UILayer to the scene + * @param name The name of the new UIlayer + * @returns The newly created UILayer + */ + addUILayer(name: string): UILayer { + if(this.layers.has(name) || this.parallaxLayers.has(name) || this.uiLayers.has(name)){ + throw `Layer with name ${name} already exists`; + } + + let layer = new UILayer(this, name); + + this.uiLayers.add(name, layer); + + return layer; + } + + /** + * Gets a layer from the scene by name if it exists. + * This can be a Layer or any of its subclasses + * @param name The name of the layer + * @returns The Layer found with that name + */ + getLayer(name: string): Layer { + if(this.layers.has(name)){ + return this.layers.get(name); + } else if(this.parallaxLayers.has(name)){ + return this.parallaxLayers.get(name); + } else if(this.uiLayers.has(name)){ + return this.uiLayers.get(name); + } else { + throw `Requested layer ${name} does not exist.`; + } + } + + /** + * Returns true if this layer is a ParallaxLayer + * @param name The name of the layer + * @returns True if this layer is a ParallaxLayer + */ + isParallaxLayer(name: string): boolean { + return this.parallaxLayers.has(name); + } + + /** + * Returns true if this layer is a UILayer + * @param name The name of the layer + * @returns True if this layer is ParallaxLayer + */ + isUILayer(name: string): boolean { + return this.uiLayers.has(name); + } + + /** + * Returns the translation of this node with respect to camera space (due to the viewport moving). + * This value is affected by the parallax level of the @reference[Layer] the node is on. + * @param node The node to check the viewport with respect to + * @returns A Vec2 containing the translation of viewport with respect to this node. + */ + getViewTranslation(node: GameNode): Vec2 { + let layer = node.getLayer(); + + if(layer instanceof ParallaxLayer || layer instanceof UILayer){ + return this.viewport.getOrigin().mult(layer.parallax); + } else { + return this.viewport.getOrigin(); + } + } + + /** + * Returns the scale level of the view + * @returns The zoom level of the viewport + */ + getViewScale(): number { + return this.viewport.getZoomLevel(); + } + + /** + * Returns the Viewport associated with this scene + * @returns The current Viewport + */ + getViewport(): Viewport { + return this.viewport; + } + + /** + * Gets the world size of this Scene + * @returns The world size in a Vec2 + */ + getWorldSize(): Vec2 { + return this.worldSize; + } + + /** + * Gets the SceneGraph associated with this Scene + * @returns The SceneGraph + */ + getSceneGraph(): SceneGraph { + return this.sceneGraph; + } + + /** + * Gets the PhysicsManager associated with this Scene + * @returns The PhysicsManager + */ + getPhysicsManager(): PhysicsManager { + return this.physicsManager; + } + + /** + * Gets the NavigationManager associated with this Scene + * @returns The NavigationManager + */ + getNavigationManager(): NavigationManager { + return this.navManager; + } + + /** + * Gets the AIManager associated with this Scene + * @returns The AIManager + */ + getAIManager(): AIManager { + return this.aiManager; + } + + /** + * Generates an ID for a GameNode + * @returns The new ID + */ + generateId(): number { + return this.sceneManager.generateId(); + } + + /** + * Retrieves a Tilemap in this Scene + * @param name The name of the Tilemap + * @returns The Tilemap, if one this name exists, otherwise null + */ + getTilemap(name: string): Tilemap { + for(let tilemap of this .tilemaps){ + if(tilemap.name === name){ + return tilemap; + } + } + + return null; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/SceneManager.ts b/hw3/src/Wolfie2D/Scene/SceneManager.ts new file mode 100644 index 0000000..0809a30 --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/SceneManager.ts @@ -0,0 +1,125 @@ +import Scene from "./Scene"; +import ResourceManager from "../ResourceManager/ResourceManager"; +import Viewport from "../SceneGraph/Viewport"; +import RenderingManager from "../Rendering/RenderingManager"; +import MemoryUtils from "../Utils/MemoryUtils"; + +/** + * The SceneManager acts as an interface to create Scenes, and handles the lifecycle methods of Scenes. + * It gives Scenes access to information they need from the @reference[Game] class while keeping a layer of separation. + */ +export default class SceneManager { + /** The current Scene of the game */ + protected currentScene: Scene; + + /** The Viewport of the game */ + protected viewport: Viewport; + + /** A reference to the ResourceManager */ + protected resourceManager: ResourceManager; + + /** A counter to keep track of game ids */ + protected idCounter: number; + + /** The RenderingManager of the game */ + protected renderingManager: RenderingManager; + + /** For consistency, only change scenes at the beginning of the update cycle */ + protected pendingScene: Scene; + protected pendingSceneInit: Record; + + /** + * Creates a new SceneManager + * @param viewport The Viewport of the game + * @param game The Game instance + * @param renderingManager The RenderingManager of the game + */ + constructor(viewport: Viewport, renderingManager: RenderingManager){ + this.resourceManager = ResourceManager.getInstance(); + this.viewport = viewport; + this.renderingManager = renderingManager; + this.idCounter = 0; + this.pendingScene = null; + } + + /** + * Add a scene as the main scene. + * Use this method if you've created a subclass of Scene, and you want to add it as the main Scene. + * @param constr The constructor of the scene to add + * @param init An object to pass to the init function of the new scene + */ + public changeToScene(constr: new (...args: any) => T, init?: Record, options?: Record): void { + console.log("Creating the new scene - change is pending until next update"); + this.pendingScene = new constr(this.viewport, this, this.renderingManager, options); + this.pendingSceneInit = init; + } + + protected doSceneChange(){ + console.log("Performing scene change"); + this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y); + + if(this.currentScene){ + console.log("Unloading old scene") + this.currentScene.unloadScene(); + + console.log("Destroying old scene"); + this.currentScene.destroy(); + } + + console.log("Unloading old resources..."); + this.resourceManager.unloadAllResources(); + + // Make the pending scene the current one + this.currentScene = this.pendingScene; + + // Make the pending scene null + this.pendingScene = null; + + // Init the scene + this.currentScene.initScene(this.pendingSceneInit); + + // Enqueue all scene asset loads + this.currentScene.loadScene(); + + // Load all assets + console.log("Starting Scene Load"); + this.resourceManager.loadResourcesFromQueue(() => { + console.log("Starting Scene"); + this.currentScene.startScene(); + this.currentScene.setRunning(true); + }); + + this.renderingManager.setScene(this.currentScene); + } + + /** + * Generates a unique ID + * @returns A new ID + */ + public generateId(): number { + return this.idCounter++; + } + + /** + * Renders the current Scene + */ + public render(): void { + if(this.currentScene){ + this.currentScene.render(); + } + } + + /** + * Updates the current Scene + * @param deltaT The timestep of the Scene + */ + public update(deltaT: number){ + if(this.pendingScene !== null){ + this.doSceneChange(); + } + + if(this.currentScene && this.currentScene.isRunning()){ + this.currentScene.update(deltaT); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Scene/SceneOptions.ts b/hw3/src/Wolfie2D/Scene/SceneOptions.ts new file mode 100644 index 0000000..e52f6be --- /dev/null +++ b/hw3/src/Wolfie2D/Scene/SceneOptions.ts @@ -0,0 +1,25 @@ +import ArrayUtils from "../Utils/ArrayUtils"; + +// @ignorePage + +/** + * The options to give a @reference[Scene] for initialization + */ +export default class SceneOptions { + physics: { + groups: Array, + collisions: Array>; + } + + static parse(options: Record): SceneOptions{ + let sOpt = new SceneOptions(); + + if(options.physics === undefined){ + sOpt.physics = {groups: undefined, collisions: undefined}; + } else { + sOpt.physics = options.physics; + } + + return sOpt; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/SceneGraph/SceneGraph.ts b/hw3/src/Wolfie2D/SceneGraph/SceneGraph.ts new file mode 100644 index 0000000..cdde06f --- /dev/null +++ b/hw3/src/Wolfie2D/SceneGraph/SceneGraph.ts @@ -0,0 +1,131 @@ +import Viewport from "./Viewport"; +import CanvasNode from "../Nodes/CanvasNode"; +import Map from "../DataTypes/Map"; +import Vec2 from "../DataTypes/Vec2"; +import Scene from "../Scene/Scene"; +import AABB from "../DataTypes/Shapes/AABB"; + +/** + * An abstract interface of a SceneGraph. + * Exposes methods for use by other code, but leaves the implementation up to the subclasses. + * The SceneGraph manages the positions of all GameNodes, and can easily prune a visible set for rendering. + */ +export default abstract class SceneGraph { + /** A reference to the viewport */ + protected viewport: Viewport; + /** A map of CanvasNodes in this SceneGraph */ + protected nodeMap: Array; + /** A counter of IDs for nodes in this SceneGraph */ + protected idCounter: number; + /** A reference to the Scene this SceneGraph belongs to */ + protected scene: Scene; + + /** + * Creates a new SceneGraph + * @param viewport The viewport + * @param scene The Scene this SceneGraph belongs to + */ + constructor(viewport: Viewport, scene: Scene){ + this.viewport = viewport; + this.scene = scene; + this.nodeMap = new Array(); + this.idCounter = 0; + } + + /** + * Add a node to the SceneGraph + * @param node The CanvasNode to add to the SceneGraph + * @returns The SceneGraph ID of this newly added CanvasNode + */ + addNode(node: CanvasNode): number { + this.nodeMap[node.id] = node; + this.addNodeSpecific(node, this.idCounter); + this.idCounter += 1; + return this.idCounter - 1; + }; + + /** + * An overridable method to add a CanvasNode to the specific data structure of the SceneGraph + * @param node The node to add to the data structure + * @param id The id of the CanvasNode + */ + protected abstract addNodeSpecific(node: CanvasNode, id: number): void; + + /** + * Removes a node from the SceneGraph + * @param node The node to remove + */ + removeNode(node: CanvasNode): void { + // Find and remove node in O(n) + this.nodeMap[node.id] = undefined; + this.removeNodeSpecific(node, node.id); + }; + + /** + * The specific implementation of removing a node + * @param node The node to remove + * @param id The id of the node to remove + */ + protected abstract removeNodeSpecific(node: CanvasNode, id: number): void; + + /** + * Get a specific node using its id + * @param id The id of the CanvasNode to retrieve + * @returns The node with this ID + */ + getNode(id: number): CanvasNode { + return this.nodeMap[id]; + } + + /** + * Returns the nodes at specific coordinates + * @param vecOrX The x-coordinate of the position, or the coordinates in a Vec2 + * @param y The y-coordinate of the position + * @returns An array of nodes found at the position provided + */ + getNodesAt(vecOrX: Vec2 | number, y: number = null): Array { + if(vecOrX instanceof Vec2){ + return this.getNodesAtCoords(vecOrX.x, vecOrX.y); + } else { + return this.getNodesAtCoords(vecOrX, y); + } + } + + /** + * Returns the nodes that overlap a specific boundary + * @param boundary The region to check + * @returns An array of nodes found overlapping the provided boundary + */ + abstract getNodesInRegion(boundary: AABB): Array; + + /** + * Returns all nodes in the SceneGraph + * @returns An Array containing all nodes in the SceneGraph + */ + getAllNodes(): Array { + let arr = new Array(); + for(let i = 0; i < this.nodeMap.length; i++){ + if(this.nodeMap[i] !== undefined){ + arr.push(this.nodeMap[i]); + } + } + return arr; + } + + /** + * The specific implementation of getting a node at certain coordinates + * @param x The x-coordinates of the node + * @param y The y-coordinates of the node + */ + protected abstract getNodesAtCoords(x: number, y: number): Array; + + abstract update(deltaT: number): void; + + abstract render(ctx: CanvasRenderingContext2D): void; + + /** + * Gets the visible set of CanvasNodes based on the @reference[Viewport] + * @returns An array containing all visible nodes in the SceneGraph + */ + abstract getVisibleSet(): Array; +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/SceneGraph/SceneGraphArray.ts b/hw3/src/Wolfie2D/SceneGraph/SceneGraphArray.ts new file mode 100644 index 0000000..d07ced4 --- /dev/null +++ b/hw3/src/Wolfie2D/SceneGraph/SceneGraphArray.ts @@ -0,0 +1,93 @@ +import SceneGraph from "./SceneGraph"; +import CanvasNode from "../Nodes/CanvasNode"; +import Viewport from "./Viewport"; +import Scene from "../Scene/Scene"; +import AABB from "../DataTypes/Shapes/AABB"; +import Stats from "../Debug/Stats"; + +/** + * An implementation of a SceneGraph that simply stored CanvasNodes in an array. + */ +export default class SceneGraphArray extends SceneGraph { + /** The list of CanvasNodes in this SceneGraph */ + private nodeList: Array; + + /** + * Creates a new SceneGraphArray + * @param viewport The Viewport + * @param scene The Scene this SceneGraph belongs to + */ + constructor(viewport: Viewport, scene: Scene){ + super(viewport, scene); + + this.nodeList = new Array(); + } + + // @override + protected addNodeSpecific(node: CanvasNode, id: number): void { + this.nodeList.push(node); + } + + // @override + protected removeNodeSpecific(node: CanvasNode, id: number): void { + let index = this.nodeList.indexOf(node); + if(index > -1){ + this.nodeList.splice(index, 1); + } + } + + // @override + getNodesAtCoords(x: number, y: number): Array { + let results = []; + + for(let node of this.nodeList){ + if(node.contains(x, y)){ + results.push(node); + } + } + + return results; + } + + // @override + getNodesInRegion(boundary: AABB): Array { + let t0 = performance.now(); + let results = []; + + for(let node of this.nodeList){ + if(boundary.overlaps(node.boundary)){ + results.push(node); + } + } + let t1 = performance.now(); + Stats.log("sgquery", (t1-t0)); + + return results; + } + + update(deltaT: number): void { + let t0 = performance.now(); + for(let node of this.nodeList){ + if(!node.getLayer().isPaused()){ + node.update(deltaT); + } + } + let t1 = performance.now(); + Stats.log("sgupdate", (t1-t0)); + } + + render(ctx: CanvasRenderingContext2D): void {} + + // @override + getVisibleSet(): Array { + let visibleSet = new Array(); + + for(let node of this.nodeList){ + if(!node.getLayer().isHidden() && node.visible && this.viewport.includes(node)){ + visibleSet.push(node); + } + } + + return visibleSet; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/SceneGraph/SceneGraphQuadTree.ts b/hw3/src/Wolfie2D/SceneGraph/SceneGraphQuadTree.ts new file mode 100644 index 0000000..47dd0f7 --- /dev/null +++ b/hw3/src/Wolfie2D/SceneGraph/SceneGraphQuadTree.ts @@ -0,0 +1,98 @@ +import SceneGraph from "./SceneGraph"; +import CanvasNode from "../Nodes/CanvasNode"; +import Viewport from "./Viewport"; +import Scene from "../Scene/Scene"; +import RegionQuadTree from "../DataTypes/RegionQuadTree"; +import Vec2 from "../DataTypes/Vec2"; +import AABB from "../DataTypes/Shapes/AABB"; +import Stats from "../Debug/Stats"; + +/** + * An implementation of a SceneGraph that uses a @reference[RegionQuadTree] to store @reference[CanvasNode]s. + */ +export default class SceneGraphQuadTree extends SceneGraph { + /** The QuadTree used to store the CanvasNodes */ + private qt: RegionQuadTree; + + /** A list of nodes to help out the QuadTree */ + private nodes: Array; + + /** + * Creates a new SceneGraphQuadTree + * @param viewport The Viewport + * @param scene The Scene this SceneGraph belongs to + */ + constructor(viewport: Viewport, scene: Scene){ + super(viewport, scene); + + let size = this.scene.getWorldSize(); + this.qt = new RegionQuadTree(size.clone().scale(1/2), size.clone().scale(1/2), 5, 30); + this.nodes = new Array(); + } + + // @override + protected addNodeSpecific(node: CanvasNode, id: number): void { + this.nodes.push(node); + } + + // @override + protected removeNodeSpecific(node: CanvasNode, id: number): void { + let index = this.nodes.indexOf(node); + if(index >= 0){ + this.nodes.splice(index, 1); + } + } + + // @override + getNodesAtCoords(x: number, y: number): Array { + return this.qt.queryPoint(new Vec2(x, y)); + } + + // @override + getNodesInRegion(boundary: AABB): Array { + let t0 = performance.now(); + let res = this.qt.queryRegion(boundary); + let t1 = performance.now(); + + Stats.log("sgquery", (t1-t0)); + + return res; + } + + update(deltaT: number): void { + let t0 = performance.now(); + this.qt.clear(); + let t1 = performance.now(); + + Stats.log("sgclear", (t1-t0)); + + t0 = performance.now(); + for(let node of this.nodes){ + this.qt.insert(node); + } + t1 = performance.now(); + + Stats.log("sgfill", (t1-t0)); + + t0 = performance.now(); + this.nodes.forEach((node: CanvasNode) => node.update(deltaT)); + t1 = performance.now(); + + Stats.log("sgupdate", (t1-t0)); + } + + render(ctx: CanvasRenderingContext2D): void { + let origin = this.viewport.getOrigin(); + let zoom = this.viewport.getZoomLevel(); + this.qt.render_demo(ctx, origin, zoom); + } + + // @override + getVisibleSet(): Array { + let visibleSet = this.qt.queryRegion(this.viewport.getView()); + + visibleSet = visibleSet.filter(node => !node.getLayer().isHidden()); + + return visibleSet; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/SceneGraph/Viewport.ts b/hw3/src/Wolfie2D/SceneGraph/Viewport.ts new file mode 100644 index 0000000..d2eceba --- /dev/null +++ b/hw3/src/Wolfie2D/SceneGraph/Viewport.ts @@ -0,0 +1,286 @@ +import Vec2 from "../DataTypes/Vec2"; +import GameNode from "../Nodes/GameNode"; +import CanvasNode from "../Nodes/CanvasNode"; +import MathUtils from "../Utils/MathUtils"; +import Queue from "../DataTypes/Queue"; +import AABB from "../DataTypes/Shapes/AABB"; +import Input from "../Input/Input"; +import ParallaxLayer from "../Scene/Layers/ParallaxLayer"; +import UILayer from "../Scene/Layers/UILayer"; + +/** + * The viewport of the game. Corresponds to the visible window displayed in the browser. + * The viewport keeps track of its position in the game world, and can act as a camera to follow objects. + */ +export default class Viewport { + /** The AABB that contains the position and size of the viewport view */ + private view: AABB; + /** The boundary for the viewport. This represents the limits to where the viewport can go */ + private boundary: AABB; + /** The GameNode the Viewport is following */ + private following: GameNode; + /** The position the GameNode is focusing on. This is overridden if "following" is set. */ + private focus: Vec2; + + /** A queue of previous positions of what this viewport is following. Used for smoothing viewport movement */ + private lastPositions: Queue; + + /** The number of previous positions this viewport tracks */ + private smoothingFactor: number; + + /** A boolean tha represents whether the player can zoom by scrolling with the mouse wheel */ + private scrollZoomEnabled: boolean; + + /** The amount that is zoomed in or out. */ + private ZOOM_FACTOR: number = 1.2; + + /** The size of the canvas */ + private canvasSize: Vec2; + + constructor(canvasSize: Vec2, zoomLevel: number){ + this.view = new AABB(Vec2.ZERO, Vec2.ZERO); + this.boundary = new AABB(Vec2.ZERO, Vec2.ZERO); + this.lastPositions = new Queue(); + this.smoothingFactor = 10; + this.scrollZoomEnabled = false; + this.canvasSize = Vec2.ZERO; + this.focus = Vec2.ZERO; + + // Set the size of the canvas + this.setCanvasSize(canvasSize); + + // Set the size of the viewport + this.setSize(canvasSize); + this.setZoomLevel(zoomLevel); + + // Set the center (and make the viewport stay there) + this.setCenter(this.view.halfSize.clone()); + this.setFocus(this.view.halfSize.clone()); + } + + /** Enables the viewport to zoom in and out */ + enableZoom(): void { + this.scrollZoomEnabled = true; + } + + /** + * Returns the position of the viewport + * @returns The center of the viewport as a Vec2 + */ + getCenter(): Vec2 { + return this.view.center; + } + + /** + * Returns a new Vec2 with the origin of the viewport + * @returns The top left cornder of the Vieport as a Vec2 + */ + getOrigin(): Vec2 { + return new Vec2(this.view.left, this.view.top); + } + + /** + * Returns the region visible to this viewport + * @returns The AABB containing the region visible to the viewport + */ + getView(): AABB { + return this.view; + } + + /** + * Set the position of the viewport + * @param vecOrX The new position or the x-coordinate of the new position + * @param y The y-coordinate of the new position + */ + setCenter(vecOrX: Vec2 | number, y: number = null): void { + let pos: Vec2; + if(vecOrX instanceof Vec2){ + pos = vecOrX; + } else { + pos = new Vec2(vecOrX, y); + } + + this.view.center = pos; + } + + /** + * Returns the size of the viewport as a Vec2 + * @returns The half-size of the viewport as a Vec2 + */ + getHalfSize(): Vec2 { + return this.view.getHalfSize(); + } + + /** + * Sets the size of the viewport + * @param vecOrX The new width of the viewport or the new size as a Vec2 + * @param y The new height of the viewport + */ + setSize(vecOrX: Vec2 | number, y: number = null): void { + if(vecOrX instanceof Vec2){ + this.view.setHalfSize(vecOrX.scaled(1/2)); + } else { + this.view.setHalfSize(new Vec2(vecOrX/2, y/2)); + } + } + + /** + * Sets the half-size of the viewport + * @param vecOrX The new half-width of the viewport or the new half-size as a Vec2 + * @param y The new height of the viewport + */ + setHalfSize(vecOrX: Vec2 | number, y: number = null): void { + if(vecOrX instanceof Vec2){ + this.view.setHalfSize(vecOrX.clone()); + } else { + this.view.setHalfSize(new Vec2(vecOrX, y)); + } + } + + /** + * Updates the viewport with the size of the current Canvas + * @param vecOrX The width of the canvas, or the canvas size as a Vec2 + * @param y The height of the canvas + */ + setCanvasSize(vecOrX: Vec2 | number, y: number = null): void { + if(vecOrX instanceof Vec2){ + this.canvasSize = vecOrX.clone(); + } else { + this.canvasSize = new Vec2(vecOrX, y); + } + } + + /** + * Sets the zoom level of the viewport + * @param zoom The zoom level + */ + setZoomLevel(zoom: number): void { + this.view.halfSize.copy(this.canvasSize.scaled(1/zoom/2)); + } + + /** + * Gets the zoom level of the viewport + * @returns The zoom level + */ + getZoomLevel(): number { + return this.canvasSize.x/this.view.hw/2 + } + + /** + * Sets the smoothing factor for the viewport movement. + * @param smoothingFactor The smoothing factor for the viewport + */ + setSmoothingFactor(smoothingFactor: number): void { + if(smoothingFactor < 1) smoothingFactor = 1; + this.smoothingFactor = smoothingFactor; + } + + /** + * Tells the viewport to focus on a point. Overidden by "following". + * @param focus The point the viewport should focus on + */ + setFocus(focus: Vec2): void { + this.focus.copy(focus); + } + + /** + * Returns true if the CanvasNode is inside of the viewport + * @param node The node to check + * @returns True if the node is currently visible in the viewport, false if not + */ + includes(node: CanvasNode): boolean { + let parallax = node.getLayer() instanceof ParallaxLayer || node.getLayer() instanceof UILayer ? (node.getLayer()).parallax : new Vec2(1, 1); + let center = this.view.center.clone(); + this.view.center.mult(parallax); + let overlaps = this.view.overlaps(node.boundary); + this.view.center = center + return overlaps; + } + + // TODO: Put some error handling on this for trying to make the bounds too small for the viewport + // TODO: This should probably be done automatically, or should consider the aspect ratio or something + /** + * Sets the bounds of the viewport + * @param lowerX The left edge of the viewport + * @param lowerY The top edge of the viewport + * @param upperX The right edge of the viewport + * @param upperY The bottom edge of the viewport + */ + setBounds(lowerX: number, lowerY: number, upperX: number, upperY: number): void { + let hwidth = (upperX - lowerX)/2; + let hheight = (upperY - lowerY)/2; + let x = lowerX + hwidth; + let y = lowerY + hheight; + this.boundary.center.set(x, y); + this.boundary.halfSize.set(hwidth, hheight); + } + + /** + * Make the viewport follow the specified GameNode + * @param node The GameNode to follow + */ + follow(node: GameNode): void { + this.following = node; + } + + updateView(): void { + if(this.lastPositions.getSize() > this.smoothingFactor){ + this.lastPositions.dequeue(); + } + + // Get the average of the last 10 positions + let pos = Vec2.ZERO; + this.lastPositions.forEach(position => pos.add(position)); + pos.scale(1/this.lastPositions.getSize()); + + // Set this position either to the object or to its bounds + pos.x = MathUtils.clamp(pos.x, this.boundary.left + this.view.hw, this.boundary.right - this.view.hw); + pos.y = MathUtils.clamp(pos.y, this.boundary.top + this.view.hh, this.boundary.bottom - this.view.hh); + + // Assure there are no lines in the tilemap + pos.x = Math.floor(pos.x); + pos.y = Math.floor(pos.y); + + this.view.center.copy(pos); + } + + update(deltaT: number): void { + // If zoom is enabled + if(this.scrollZoomEnabled){ + if(Input.didJustScroll()){ + let currentSize = this.view.getHalfSize().clone(); + if(Input.getScrollDirection() < 0){ + // Zoom in + currentSize.scale(1/this.ZOOM_FACTOR); + } else { + // Zoom out + currentSize.scale(this.ZOOM_FACTOR); + } + + if(currentSize.x > this.boundary.hw){ + let factor = this.boundary.hw/currentSize.x; + currentSize.x = this.boundary.hw; + currentSize.y *= factor; + } + + if(currentSize.y > this.boundary.hh){ + let factor = this.boundary.hh/currentSize.y; + currentSize.y = this.boundary.hh; + currentSize.x *= factor; + } + + this.view.setHalfSize(currentSize); + } + } + + // If viewport is following an object + if(this.following){ + // Update our list of previous positions + this.lastPositions.enqueue(this.following.position.clone()); + } else { + this.lastPositions.enqueue(this.focus); + } + + this.updateView(); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Sound/AudioManager.ts b/hw3/src/Wolfie2D/Sound/AudioManager.ts new file mode 100644 index 0000000..0e438d2 --- /dev/null +++ b/hw3/src/Wolfie2D/Sound/AudioManager.ts @@ -0,0 +1,244 @@ +import Map from "../DataTypes/Map"; +import Receiver from "../Events/Receiver"; +import ResourceManager from "../ResourceManager/ResourceManager"; +import { GameEventType } from "../Events/GameEventType"; + +/** + * Manages any sounds or music needed for the game. + * Through the EventQueue, exposes interface to play sounds so GameNodes can activate sounds without + * needing direct references to the audio system + */ +export default class AudioManager { + private static instance: AudioManager; + + /** The event receiver of this AudioManager */ + private receiver: Receiver; + + /** A Map of the names of currently playing (or paused) sounds to their AudioBuffers */ + private currentSounds: Map; + + private audioCtx: AudioContext; + + private gainNodes: Array; + + private constructor(){ + this.initAudio(); + this.receiver = new Receiver(); + this.receiver.subscribe([ + GameEventType.PLAY_SOUND, + GameEventType.STOP_SOUND, + GameEventType.PLAY_MUSIC, + GameEventType.PLAY_SFX, + GameEventType.MUTE_CHANNEL, + GameEventType.UNMUTE_CHANNEL + ]); + this.currentSounds = new Map(); + + this.gainNodes = new Array(MAX_AUDIO_CHANNELS); + this.initGainNodes(); + } + + /** + * Get the instance of the AudioManager class or create a new one if none exists + * @returns The AudioManager + */ + public static getInstance(): AudioManager { + if(!this.instance){ + this.instance = new AudioManager(); + } + return this.instance; + } + + /** + * Initializes the webAudio context + */ + private initAudio(): void { + try { + window.AudioContext = window.AudioContext;// || window.webkitAudioContext; + this.audioCtx = new AudioContext(); + console.log('Web Audio API successfully loaded'); + } catch(e) { + console.warn('Web Audio API is not supported in this browser'); + } + } + + private initGainNodes(): void { + for(let i = 0; i < MAX_AUDIO_CHANNELS; i++){ + this.gainNodes[i] = this.audioCtx.createGain(); + } + } + + /** + * Returns the current audio context + * @returns The AudioContext + */ + public getAudioContext(): AudioContext { + return this.audioCtx; + } + + /* + According to the MDN, create a new sound for every call: + + An AudioBufferSourceNode can only be played once; after each call to start(), you have to create a new node + if you want to play the same sound again. Fortunately, these nodes are very inexpensive to create, and the + actual AudioBuffers can be reused for multiple plays of the sound. Indeed, you can use these nodes in a + "fire and forget" manner: create the node, call start() to begin playing the sound, and don't even bother to + hold a reference to it. It will automatically be garbage-collected at an appropriate time, which won't be + until sometime after the sound has finished playing. + */ + /** + * Creates a new sound from the key of a loaded audio file + * @param key The key of the loaded audio file to create a new sound for + * @returns The newly created AudioBuffer + */ + protected createSound(key: string, holdReference: boolean, channel: AudioChannelType, options: Map): AudioBufferSourceNode { + // Get audio buffer + let buffer = ResourceManager.getInstance().getAudio(key); + + // Create a sound source + var source = this.audioCtx.createBufferSource(); + + // Tell the source which sound to play + source.buffer = buffer; + + // Add any additional nodes + const nodes: Array = [source]; + + // Do any additional nodes here? + // Of course, there aren't any supported yet... + + // Add the gain node for this channel + nodes.push(this.gainNodes[channel]); + + // Connect any nodes along the path + for(let i = 1; i < nodes.length; i++){ + nodes[i-1].connect(nodes[i]); + } + + // Connect the source to the context's destination + nodes[nodes.length - 1].connect(this.audioCtx.destination); + + return source; + } + + /** + * Play the sound specified by the key + * @param key The key of the sound to play + * @param loop A boolean for whether or not to loop the sound + * @param holdReference A boolean for whether or not we want to hold on to a reference of the audio node. This is good for playing music on a loop that will eventually need to be stopped. + */ + protected playSound(key: string, loop: boolean, holdReference: boolean, channel: AudioChannelType, options: Map): void { + let sound = this.createSound(key, holdReference, channel, options); + + if(loop){ + sound.loop = true; + } + + // Add a reference of the new sound to a map. This will allow us to stop a looping or long sound at a later time + if(holdReference){ + this.currentSounds.add(key, sound); + } + + sound.start(); + } + + /** + * Stop the sound specified by the key + */ + protected stopSound(key: string): void { + let sound = this.currentSounds.get(key); + if(sound){ + sound.stop(); + this.currentSounds.delete(key); + } + } + + protected muteChannel(channel: AudioChannelType){ + this.gainNodes[channel].gain.setValueAtTime(0, this.audioCtx.currentTime); + } + + protected unmuteChannel(channel: AudioChannelType){ + this.gainNodes[channel].gain.setValueAtTime(1, this.audioCtx.currentTime); + } + + /** + * Sets the volume of a channel using the GainNode for that channel. For more + * information on GainNodes, see https://developer.mozilla.org/en-US/docs/Web/API/GainNode + * @param channel The audio channel to set the volume for + * @param volume The volume of the channel. 0 is muted. Values below zero will be set to zero. + */ + static setVolume(channel: AudioChannelType, volume: number){ + if(volume < 0){ + volume = 0; + } + + const am = AudioManager.getInstance(); + am.gainNodes[channel].gain.setValueAtTime(volume, am.audioCtx.currentTime); + } + + /** + * Returns the GainNode for this channel. + * Learn more about GainNodes here https://developer.mozilla.org/en-US/docs/Web/API/GainNode + * DON'T USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING + * @param channel The channel + * @returns The GainNode for the specified channel + */ + getChannelGainNode(channel: AudioChannelType){ + return this.gainNodes[channel]; + } + + update(deltaT: number): void { + // Play each audio clip requested + // TODO - Add logic to merge sounds if there are multiple of the same key + while(this.receiver.hasNextEvent()){ + let event = this.receiver.getNextEvent(); + if(event.type === GameEventType.PLAY_SOUND || event.type === GameEventType.PLAY_MUSIC || event.type === GameEventType.PLAY_SFX){ + let soundKey = event.data.get("key"); + let loop = event.data.get("loop"); + let holdReference = event.data.get("holdReference"); + + let channel = AudioChannelType.DEFAULT; + + if(event.type === GameEventType.PLAY_MUSIC){ + channel = AudioChannelType.MUSIC; + } else if(GameEventType.PLAY_SFX){ + channel = AudioChannelType.SFX; + } else if(event.data.has("channel")){ + channel = event.data.get("channel"); + } + + this.playSound(soundKey, loop, holdReference, channel, event.data); + } + + if(event.type === GameEventType.STOP_SOUND){ + let soundKey = event.data.get("key"); + this.stopSound(soundKey); + } + + if(event.type === GameEventType.MUTE_CHANNEL){ + this.muteChannel(event.data.get("channel")); + } + + if(event.type === GameEventType.UNMUTE_CHANNEL){ + this.unmuteChannel(event.data.get("channel")); + } + } + } +} + +export enum AudioChannelType { + DEFAULT = 0, + SFX = 1, + MUSIC = 2, + CUSTOM_1 = 3, + CUSTOM_2 = 4, + CUSTOM_3 = 5, + CUSTOM_4 = 6, + CUSTOM_5 = 7, + CUSTOM_6 = 8, + CUSTOM_7 = 9, + CUSTOM_8 = 10, + CUSTOM_9 = 11, +} + +export const MAX_AUDIO_CHANNELS = 12; \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Timing/Timer.ts b/hw3/src/Wolfie2D/Timing/Timer.ts new file mode 100644 index 0000000..d22d235 --- /dev/null +++ b/hw3/src/Wolfie2D/Timing/Timer.ts @@ -0,0 +1,108 @@ +import Updateable from "../DataTypes/Interfaces/Updateable"; +import MathUtils from "../Utils/MathUtils"; +import TimerManager from "./TimerManager"; + +export default class Timer implements Updateable { + + /** The current state of this timer */ + protected state: TimerState; + + /** The function to call when this timer ends */ + protected onEnd: Function; + + /** Whether or not this timer should loop */ + protected loop: boolean; + + /** The total amount of time this timer runs for */ + protected totalTime: number; + + /** The amount of time left on the current run */ + protected timeLeft: number; + + /** The number of times this timer has been run */ + protected numRuns: number; + + constructor(time: number, onEnd?: Function, loop: boolean = false){ + // Register this timer + TimerManager.getInstance().addTimer(this); + + this.totalTime = time; + this.timeLeft = 0; + this.onEnd = onEnd; + this.loop = loop; + this.state = TimerState.STOPPED; + this.numRuns = 0; + } + + isStopped(){ + return this.state === TimerState.STOPPED; + } + + isPaused(){ + return this.state === TimerState.PAUSED; + } + + /** + * Returns whether or not this timer has been run before + * @returns true if it has been run at least once (after the latest reset), and false otherwise + */ + hasRun(): boolean { + return this.numRuns > 0; + } + + start(time?: number){ + if(time !== undefined){ + this.totalTime = time; + } + this.state = TimerState.ACTIVE; + this.timeLeft = this.totalTime; + } + + /** Resets this timer. Sets the progress back to zero, and sets the number of runs back to zero */ + reset(){ + this.timeLeft = this.totalTime; + this.numRuns = 0; + } + + pause(): void { + this.state = TimerState.PAUSED; + } + + update(deltaT: number){ + if(this.state === TimerState.ACTIVE){ + this.timeLeft -= deltaT*1000; + + if(this.timeLeft <= 0){ + this.timeLeft = MathUtils.clampLow0(this.timeLeft); + this.end(); + } + } + } + + protected end(){ + // Update the state + this.state = TimerState.STOPPED; + this.numRuns += 1; + + // Call the end function if there is one + if(this.onEnd){ + this.onEnd(); + } + + // Loop if we want to + if(this.loop){ + this.state = TimerState.ACTIVE; + this.timeLeft = this.totalTime; + } + } + + toString(): string{ + return "Timer: " + this.state + " - Time Left: " + this.timeLeft + "ms of " + this.totalTime + "ms"; + } +} + +export enum TimerState { + ACTIVE = "ACTIVE", + PAUSED = "PAUSED", + STOPPED = "STOPPED" +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Timing/TimerManager.ts b/hw3/src/Wolfie2D/Timing/TimerManager.ts new file mode 100644 index 0000000..6ac83d1 --- /dev/null +++ b/hw3/src/Wolfie2D/Timing/TimerManager.ts @@ -0,0 +1,33 @@ +import Updateable from "../DataTypes/Interfaces/Updateable"; +import Timer from "./Timer"; + +export default class TimerManager implements Updateable { + + protected timers: Array; + + constructor(){ + this.timers = new Array(); + } + + protected static instance: TimerManager; + + static getInstance(): TimerManager { + if(!this.instance){ + this.instance = new TimerManager(); + } + + return this.instance; + } + + addTimer(timer: Timer){ + this.timers.push(timer); + } + + clearTimers(){ + this.timers = new Array(); + } + + update(deltaT: number): void { + this.timers.forEach(timer => timer.update(deltaT)); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/ArrayUtils.ts b/hw3/src/Wolfie2D/Utils/ArrayUtils.ts new file mode 100644 index 0000000..9ee99d4 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/ArrayUtils.ts @@ -0,0 +1,43 @@ +/** A class containing some utility functions for Arrays */ +export default class ArrayUtils { + /** + * Returns a 2d array of dim1 x dim2 filled with 1s + * @param dim1 The first dimension of the array to create + * @param dim2 The second dimension of the array to create + * @returns A dim1 x dim2 Array filled with 1s + */ + static ones2d(dim1: number, dim2: number): number[][] { + let arr = new Array>(dim1); + + for(let i = 0; i < arr.length; i++){ + arr[i] = new Array(dim2); + + for(let j = 0; j < arr[i].length; j++){ + arr[i][j] = 1; + } + } + + return arr; + } + + /** + * Returns a 2d array of dim1 x dim2 filled with true or false + * @param dim1 The first dimension of the array to create + * @param dim2 The second dimension of the array to create + * @param flag The boolean to fill the array with + * @returns A dim1 x dim2 Array filled with flag + */ + static bool2d(dim1: number, dim2: number, flag: boolean): boolean[][] { + let arr = new Array>(dim1); + + for(let i = 0; i < arr.length; i++){ + arr[i] = new Array(dim2); + + for(let j = 0; j < arr[i].length; j++){ + arr[i][j] = flag; + } + } + + return arr; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/Color.ts b/hw3/src/Wolfie2D/Utils/Color.ts new file mode 100644 index 0000000..e7f89d0 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/Color.ts @@ -0,0 +1,197 @@ +import MathUtils from "./MathUtils"; + +// TODO: This should be moved to the datatypes folder +/** + * A Color util class that keeps track of colors like a vector, but can be converted into a string format + */ +export default class Color { + /** The red value */ + public r: number; + /** The green value */ + public g: number; + /** The blue value */ + public b: number; + /** The alpha value */ + public a: number; + + /** + * Creates a new color + * @param r Red + * @param g Green + * @param b Blue + * @param a Alpha + */ + constructor(r: number = 0, g: number = 0, b: number = 0, a: number = 1){ + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + /** + * Transparent color + * @returns rgba(0, 0, 0, 0) + */ + static get TRANSPARENT(): Color { + return new Color(0, 0, 0, 0); + } + + /** + * Red color + * @returns rgb(255, 0, 0) + */ + static get RED(): Color { + return new Color(255, 0, 0, 1); + } + + /** + * Green color + * @returns rgb(0, 255, 0) + */ + static get GREEN(): Color { + return new Color(0, 255, 0, 1); + } + + /** + * Blue color + * @returns rgb(0, 0, 255) + */ + static get BLUE(): Color { + return new Color(0, 0, 255, 1); + } + + /** + * Yellow color + * @returns rgb(255, 255, 0) + */ + static get YELLOW(): Color { + return new Color(255, 255, 0, 1); + } + + /** + * Magenta color + * @returns rgb(255, 0, 255) + */ + static get MAGENTA(): Color { + return new Color(255, 0, 255, 1); + } + + /** + * Cyan color + * @returns rgb(0, 255, 255) + */ + static get CYAN(): Color { + return new Color(0, 255, 255, 1); + } + + /** + * White color + * @returns rgb(255, 255, 255) + */ + static get WHITE(): Color { + return new Color(255, 255, 255, 1); + } + + /** + * Black color + * @returns rgb(0, 0, 0) + */ + static get BLACK(): Color { + return new Color(0, 0, 0, 1); + } + + /** + * Orange color + * @returns rgb(255, 100, 0) + */ + static get ORANGE(): Color { + return new Color(255, 100, 0, 1); + } + + /** + * Sets the color to the values provided + * @param r Red + * @param g Green + * @param b Blue + * @param a Alpha + */ + set(r: number, g: number, b: number, a: number = 1): void { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + /** + * Returns a new color slightly lighter than the current color + * @returns A new lighter Color + */ + lighten(): Color { + return new Color(MathUtils.clamp(this.r + 40, 0, 255), MathUtils.clamp(this.g + 40, 0, 255), MathUtils.clamp(this.b + 40, 0, 255), MathUtils.clamp(this.a + 10, 0, 255)); + } + + /** + * Returns a new color slightly darker than the current color + * @returns A new darker Color + */ + darken(): Color { + return new Color(MathUtils.clamp(this.r - 40, 0, 255), MathUtils.clamp(this.g - 40, 0, 255), MathUtils.clamp(this.b - 40, 0, 255), MathUtils.clamp(this.a + 10, 0, 255)); + } + + /** + * Returns this color as an array + * @returns [r, g, b, a] + */ + toArray(): [number, number, number, number] { + return [this.r, this.g, this.b, this.a]; + } + + /** + * Returns the color as a string of the form #RRGGBB + * @returns #RRGGBB + */ + toString(): string { + return "#" + MathUtils.toHex(this.r, 2) + MathUtils.toHex(this.g, 2) + MathUtils.toHex(this.b, 2); + } + + /** + * Returns the color as a string of the form rgb(r, g, b) + * @returns rgb(r, g, b) + */ + toStringRGB(): string { + return "rgb(" + this.r.toString() + ", " + this.g.toString() + ", " + this.b.toString() + ")"; + } + + /** + * Returns the color as a string of the form rgba(r, g, b, a) + * @returns rgba(r, g, b, a) + */ + toStringRGBA(): string { + if(this.a === 0){ + return this.toStringRGB(); + } + return "rgba(" + this.r.toString() + ", " + this.g.toString() + ", " + this.b.toString() + ", " + this.a.toString() +")" + } + + /** + * Turns this color into a float32Array and changes color range to [0.0, 1.0] + * @returns a Float32Array containing the color + */ + toWebGL(): Float32Array { + return new Float32Array([ + this.r/255, + this.g/255, + this.b/255, + this.a + ]); + } + + static fromStringHex(str: string): Color { + let i = 0; + if(str.charAt(0) == "#") i+= 1; + let r = MathUtils.fromHex(str.substring(i, i+2)); + let g = MathUtils.fromHex(str.substring(i+2, i+4)); + let b = MathUtils.fromHex(str.substring(i+4, i+6)); + return new Color(r, g, b); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/EaseFunctions.ts b/hw3/src/Wolfie2D/Utils/EaseFunctions.ts new file mode 100644 index 0000000..6633c3a --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/EaseFunctions.ts @@ -0,0 +1,55 @@ +// @ignorePage + +export default class EaseFunctions { + + static easeInOutSine(x: number): number { + return -(Math.cos(Math.PI * x) - 1) / 2; + } + + static easeOutInSine(x: number): number { + return x < 0.5 ? -Math.cos(Math.PI*(x + 0.5))/2 : -Math.cos(Math.PI*(x - 0.5))/2 + 1; + } + + static easeOutSine(x: number): number { + return Math.sin((x * Math.PI) / 2); + } + + static easeInSine(x: number): number { + return 1 - Math.cos((x * Math.PI) / 2); + } + + static easeInOutQuint(x: number): number { + return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2; + } + + static easeInOutQuad(x: number): number { + return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2; + } + + static easeOutInQuad(x: number): number { + return x < 0.5 ? this.easeOutIn_OutPow(x, 2) : this.easeOutIn_InPow(x, 2); + } + + private static easeOutIn_OutPow(x: number, pow: number): number { + return 0.5 - Math.pow(-2 * x + 1, pow) / 2; + } + + private static easeOutIn_InPow(x: number, pow: number): number { + return 0.5 + Math.pow(2 * x - 1, pow) / 2; + } +} + +export enum EaseFunctionType { + // SINE + IN_OUT_SINE = "easeInOutSine", + OUT_IN_SINE = "easeOutInSine", + IN_SINE = "easeInSine", + OUT_SINE = "easeOutSine", + + // QUAD + IN_OUT_QUAD = "easeInOutQuad", + OUT_IN_QUAD = "easeOutInQuad", + + // QUINT + IN_OUT_QUINT = "easeInOutQuint" +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/GraphUtils.ts b/hw3/src/Wolfie2D/Utils/GraphUtils.ts new file mode 100644 index 0000000..774e76d --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/GraphUtils.ts @@ -0,0 +1,64 @@ +import Graph from "../DataTypes/Graphs/Graph"; +import EdgeNode from "../DataTypes/Graphs/EdgeNode"; + +/** A class to provides some utility functions for graphs */ +export default class GraphUtils { + + /** + * An implementation of Djikstra's shortest path algorithm based on the one described in The Algorithm Design Manual. + * @param g The graph + * @param start The number to start the shortest path from + * @returns An array containing the parent of each node of the Graph in the shortest path. + */ + static djikstra(g: Graph, start: number): Array { + let i: number; // Counter + let p: EdgeNode; // Pointer to edgenode + let inTree: Array = new Array(g.numVertices); + let distance: Array = new Array(g.numVertices); + let parent: Array = new Array(g.numVertices); + let v: number; // Current vertex to process + let w: number; // Candidate for next vertex + let weight: number; // Edge weight + let dist; // Best current distance from start + + for(i = 0; i < g.numVertices; i++){ + inTree[i] = false; + distance[i] = Infinity; + parent[i] = -1; + } + + distance[start] = 0; + v = start; + + while(!inTree[v]){ + inTree[v] = true; + p = g.edges[v]; + + while(p !== null){ + w = p.y; + weight = p.weight; + + if(distance[w] > distance[v] + weight){ + distance[w] = distance[v] + weight; + parent[w] = v; + } + + p = p.next; + } + + v = 0; + + dist = Infinity; + + for(i = 0; i <= g.numVertices; i++){ + if(!inTree[i] && dist > distance[i]){ + dist = distance; + v = i; + } + } + } + + return parent; + + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/MathUtils.ts b/hw3/src/Wolfie2D/Utils/MathUtils.ts new file mode 100644 index 0000000..edd1def --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/MathUtils.ts @@ -0,0 +1,175 @@ +import Vec2 from "../DataTypes/Vec2"; + +/** A class containing some utility functions for math operations */ +export default class MathUtils { + /** + * Returns the sign of the value provided + * @param x The value to extract the sign from + * @returns -1 if the number is less than 0, 1 otherwise + */ + static sign(x: number): number { + return x < 0 ? -1 : 1; + } + + /** + * Returns whether or not x is between a and b + * @param a The min bound + * @param b The max bound + * @param x The value to check + * @param exclusive Whether or not a and b are exclusive bounds + * @returns True if x is between a and b, false otherwise + */ + static between(a: number, b: number, x: number, exclusive?: boolean): boolean { + if(exclusive){ + return (a < x) && (x < b); + } else { + return (a <= x) && (x <= b); + } + } + + /** + * Clamps the value x to the range [min, max], rounding up or down if needed + * @param x The value to be clamped + * @param min The min of the range + * @param max The max of the range + * @returns x, if it is between min and max, or min/max if it exceeds their bounds + */ + static clamp(x: number, min: number, max: number): number { + if(x < min) return min; + if(x > max) return max; + return x; + } + + /** + * Clamps the value x to the range between 0 and 1 + * @param x The value to be clamped + * @returns x, if it is between 0 and 1, or 0/1 if it exceeds their bounds + */ + static clamp01(x: number): number { + return MathUtils.clamp(x, 0, 1); + } + + /** + * Clamps the lower end of the value of x to the range to min + * @param x The value to be clamped + * @param min The minimum allowed value of x + * @returns x, if it is greater than min, otherwise min + */ + static clampLow(x: number, min: number): number { + return x < min ? min : x; + } + + /** + * Clamps the lower end of the value of x to zero + * @param x The value to be clamped + * @returns x, if it is greater than 0, otherwise 0 + */ + static clampLow0(x: number): number { + return MathUtils.clampLow(x, 0); + } + + static clampMagnitude(v: Vec2, m: number): Vec2 { + if(v.magSq() > m*m){ + return v.scaleTo(m); + } else{ + return v; + } + } + + static changeRange(x: number, min: number, max: number, newMin: number, newMax: number): number { + return this.lerp(newMin, newMax, this.invLerp(min, max, x)); + } + + /** + * Linear Interpolation + * @param a The first value for the interpolation bound + * @param b The second value for the interpolation bound + * @param t The time we are interpolating to + * @returns The value between a and b at time t + */ + static lerp(a: number, b: number, t: number): number { + return a + t * (b - a); + } + + /** + * Inverse Linear Interpolation. Finds the time at which a value between a and b would occur + * @param a The first value for the interpolation bound + * @param b The second value for the interpolation bound + * @param value The current value + * @returns The time at which the current value occurs between a and b + */ + static invLerp(a: number, b: number, value: number){ + return (value - a)/(b - a); + } + + /** + * Cuts off decimal points of a number after a specified place + * @param num The number to floor + * @param place The last decimal place of the new number + * @returns The floored number + */ + static floorToPlace(num: number, place: number): number { + if(place === 0){ + return Math.floor(num); + } + + let factor = 10; + while(place > 1){ + factor != 10; + place--; + } + + return Math.floor(num*factor)/factor; + + } + + /** + * Returns a number from a hex string + * @param str the string containing the hex number + * @returns the number in decimal represented by the hex string + */ + static fromHex(str: string): number { + return parseInt(str, 16); + } + + /** + * Returns the number as a hexadecimal + * @param num The number to convert to hex + * @param minLength The length of the returned hex string (adds zero padding if needed) + * @returns The hex representation of the number as a string + */ + static toHex(num: number, minLength: number = null): string { + let factor = 1; + while(factor*16 < num){ + factor *= 16; + } + let hexStr = ""; + while(factor >= 1){ + let digit = Math.floor(num/factor); + hexStr += MathUtils.toHexDigit(digit); + num -= digit * factor; + factor /= 16; + } + + if(minLength !== null){ + while(hexStr.length < minLength){ + hexStr = "0" + hexStr; + } + } + + return hexStr; + } + + /** + * Converts a digit to hexadecimal. In this case, a digit is between 0 and 15 inclusive + * @param num The digit to convert to hexadecimal + * @returns The hex representation of the digit as a string + */ + static toHexDigit(num: number): string { + if(num < 10){ + return "" + num; + } else { + return String.fromCharCode(65 + num - 10); + } + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/MemoryUtils.ts b/hw3/src/Wolfie2D/Utils/MemoryUtils.ts new file mode 100644 index 0000000..be5e011 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/MemoryUtils.ts @@ -0,0 +1,46 @@ +import Stack from "../DataTypes/Stack"; + +export default class MemoryUtils { + /** + * Returns an approximate size in bytes of any object + * @param obj The object to get the size of + * @returns An approximation of the number of bytes in the object provided + */ + static approxSizeOf(obj: any): number { + let objectList = new Array(); + let stack = new Stack(10000); + stack.push(obj); + let bytes = 0; + + while(!stack.isEmpty()){ + let item = stack.pop(); + + // We aren't interested in counting window and document + if(item === window || item === document) continue; + + if((typeof item) === "boolean"){ + bytes += 4; + } else if((typeof item) === "number"){ + bytes += 8; + } else if((typeof item) === "string"){ + bytes += item.length; + } else if((typeof item) === "object" && objectList.indexOf(item) === -1){ + // We haven't seen this object before - log it + objectList.push(item); + + // Get the number of bytes in all of its fields + for(let field in item){ + try { + stack.push(item[field]); + } catch(e){ + console.log("Pushing item: ", + item[field]); + console.warn(`Ran out of room counting memory (Stack has size ${stack.size()}) - returning current number of bytes`); + return bytes; + } + } + } + } + + return bytes; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/Rand/Perlin.ts b/hw3/src/Wolfie2D/Utils/Rand/Perlin.ts new file mode 100644 index 0000000..0327e5d --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/Rand/Perlin.ts @@ -0,0 +1,126 @@ +import MathUtils from "../MathUtils"; + +const permutation = [ 151,160,137,91,90,15, + 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, + 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, + 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, + 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, + 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, + 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, + 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, + 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, + 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, + 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, + 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, + 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 +]; + +/** + * A noise generator + */ +export default class Perlin { + + private p: Int16Array; + private repeat: number; + + constructor(){ + this.p = new Int16Array(512); + for(let i = 0; i < 512; i++){ + this.p[i] = permutation[i%256]; + } + this.repeat = -1; + } + + /** + * Returns a random perlin noise value + * @param x An input value + * @param y An input value + * @param z An input value + * @returns A noise value + */ + perlin(x: number, y: number, z: number = 0): number { + if(this.repeat > 0) { + x = x%this.repeat; + y = y%this.repeat; + z = z%this.repeat; + } + + // Get the position of the unit cube of (x, y, z) + let xi = Math.floor(x) & 255; + let yi = Math.floor(y) & 255; + let zi = Math.floor(z) & 255; + // Get the position of (x, y, z) in that unit cube + let xf = x - Math.floor(x); + let yf = y - Math.floor(y); + let zf = z - Math.floor(z); + + // Use the fade function to relax the coordinates towards a whole value + let u = this.fade(xf); + let v = this.fade(yf); + let w = this.fade(zf); + + // Perlin noise hash function + let aaa = this.p[this.p[this.p[ xi ]+ yi ]+ zi ]; + let aba = this.p[this.p[this.p[ xi ]+this.inc(yi)]+ zi ]; + let aab = this.p[this.p[this.p[ xi ]+ yi ]+this.inc(zi)]; + let abb = this.p[this.p[this.p[ xi ]+this.inc(yi)]+this.inc(zi)]; + let baa = this.p[this.p[this.p[this.inc(xi)]+ yi ]+ zi ]; + let bba = this.p[this.p[this.p[this.inc(xi)]+this.inc(yi)]+ zi ]; + let bab = this.p[this.p[this.p[this.inc(xi)]+ yi ]+this.inc(zi)]; + let bbb = this.p[this.p[this.p[this.inc(xi)]+this.inc(yi)]+this.inc(zi)]; + + // Calculate the value of the perlin noies + let x1 = MathUtils.lerp(this.grad (aaa, xf , yf , zf), this.grad (baa, xf-1, yf , zf), u); + let x2 = MathUtils.lerp(this.grad (aba, xf , yf-1, zf), this.grad (bba, xf-1, yf-1, zf), u); + let y1 = MathUtils.lerp(x1, x2, v); + + x1 = MathUtils.lerp(this.grad (aab, xf , yf , zf-1), this.grad (bab, xf-1, yf , zf-1), u); + x2 = MathUtils.lerp(this.grad (abb, xf , yf-1, zf-1), this.grad (bbb, xf-1, yf-1, zf-1), u); + let y2 = MathUtils.lerp (x1, x2, v); + + return (MathUtils.lerp(y1, y2, w) + 1)/2; + } + + grad(hash: number, x: number, y: number, z: number){ + switch(hash & 0xF) + { + case 0x0: return x + y; + case 0x1: return -x + y; + case 0x2: return x - y; + case 0x3: return -x - y; + case 0x4: return x + z; + case 0x5: return -x + z; + case 0x6: return x - z; + case 0x7: return -x - z; + case 0x8: return y + z; + case 0x9: return -y + z; + case 0xA: return y - z; + case 0xB: return -y - z; + case 0xC: return y + x; + case 0xD: return -y + z; + case 0xE: return y - x; + case 0xF: return -y - z; + default: return 0; // never happens + } + } + + /** + * Safe increment that doesn't go beyond the repeat value + * @param num The number to increment + */ + inc(num: number){ + num++; + if(this.repeat > 0){ + num %= this.repeat; + } + return num; + } + + /** + * The fade function 6t^5 - 15t^4 + 10t^3 + * @param t The value we are applying the fade to + */ + fade(t: number){ + return t*t*t*(t*(t*6 - 15) + 10); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/RandUtils.ts b/hw3/src/Wolfie2D/Utils/RandUtils.ts new file mode 100644 index 0000000..a1cac17 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/RandUtils.ts @@ -0,0 +1,64 @@ +import MathUtils from "./MathUtils"; +import Color from "./Color"; +import Perlin from "./Rand/Perlin"; +import Vec2 from "../DataTypes/Vec2"; + +class Noise { + p: Perlin = new Perlin(); + + perlin(x: number, y: number, z?: number): number { + return this.p.perlin(x, y, z); + } +} + +/** A class that has some random generator utils */ +export default class RandUtils { + /** + * Generates a random integer in the specified range + * @param min The min of the range (inclusive) + * @param max The max of the range (exclusive) + * @returns A random int in the range [min, max) + */ + static randInt(min: number, max: number): number { + return Math.floor(Math.random()*(max - min) + min); + } + + /** + * Generates a random float in the specified range + * @param min The min of the range (inclusive) + * @param max The max of the range (exclusive) + * @returns A random float in the range [min, max) + */ + static randFloat(min: number, max: number): number { + return Math.random()*(max - min) + min; + } + + /** + * Generates a random hexadecimal number in the specified range + * @param min The min of the range (inclusive) + * @param max The max of the range (exclusive) + * @returns a random hex number in the range [min, max) as a string + */ + static randHex(min: number, max: number): string { + return MathUtils.toHex(RandUtils.randInt(min, max)); + } + + /** + * Generates a random color + * @returns A random Color + */ + static randColor(): Color { + let r = RandUtils.randInt(0, 256); + let g = RandUtils.randInt(0, 256); + let b = RandUtils.randInt(0, 256); + return new Color(r, g, b); + } + + static randVec(minX: number, maxX: number, minY: number, maxY: number): Vec2 { + return new Vec2(this.randFloat(minX, maxX), this.randFloat(minY, maxY)); + } + + /** A noise generator */ + static noise: Noise = new Noise(); + +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/RenderingUtils.ts b/hw3/src/Wolfie2D/Utils/RenderingUtils.ts new file mode 100644 index 0000000..f822227 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/RenderingUtils.ts @@ -0,0 +1,28 @@ +import Vec2 from "../DataTypes/Vec2"; +import Color from "./Color"; +import MathUtils from "./MathUtils"; + +export default class RenderingUtils { + static toWebGLCoords(point: Vec2, origin: Vec2, worldSize: Vec2): Float32Array { + return new Float32Array([ + MathUtils.changeRange(point.x, origin.x, origin.x + worldSize.x, -1, 1), + MathUtils.changeRange(point.y, origin.y, origin.y + worldSize.y, 1, -1) + ]); + } + + static toWebGLScale(size: Vec2, worldSize: Vec2): Float32Array { + return new Float32Array([ + 2*size.x/worldSize.x, + 2*size.y/worldSize.y, + ]); + } + + static toWebGLColor(color: Color): Float32Array { + return new Float32Array([ + MathUtils.changeRange(color.r, 0, 255, 0, 1), + MathUtils.changeRange(color.g, 0, 255, 0, 1), + MathUtils.changeRange(color.b, 0, 255, 0, 1), + color.a + ]); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/SortingUtils.ts b/hw3/src/Wolfie2D/Utils/SortingUtils.ts new file mode 100644 index 0000000..b5eec67 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/SortingUtils.ts @@ -0,0 +1,37 @@ +/** Some utility functions for sorting arrays */ +export default class SortingUtils { + /** + * An implementation of insertion sort. + * In game engines, this is particularly useful to sort node positions because of temporal coherence - + * the idea that nodes are almost in the same place as last frame, and thus, in a frame-to-frame comparison, + * nodes essentially do not change position. + * This means we have a nearly sorted array of nodes if we keep track of this, + * so something like insertion sort actually becomes essentailly O(n), + * as it performs very well on nearly sorted arrays. + * @param arr The array to sort in place + * @param comparator Compares element a and b in the array. Returns -1 if a < b, 0 if a = b, and 1 if a > b + */ + static insertionSort(arr: Array, comparator: (a: T, b: T) => number): void { + let i = 1; + let j; + while(i < arr.length){ + j = i; + while(j > 0 && comparator(arr[j-1], arr[j]) > 0){ + SortingUtils.swap(arr, j-1, j); + } + i += 1; + } + } + + /** + * Swaps two elements in the provided array + * @param arr The array to perform the swap on in place + * @param i The first index + * @param j The second index + */ + static swap(arr: Array, i: number, j: number): void { + let temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/Utils/StringUtils.ts b/hw3/src/Wolfie2D/Utils/StringUtils.ts new file mode 100644 index 0000000..672c050 --- /dev/null +++ b/hw3/src/Wolfie2D/Utils/StringUtils.ts @@ -0,0 +1,14 @@ +/** Some utility functions for dealing with strings */ +export default class StringUtils { + /** + * Extracts the path from a filepath that includes the file + * @param filePath the filepath to extract the path from + * @returns The path portion of the filepath provided + */ + static getPathFromFilePath(filePath: string): string { + let splitPath = filePath.split("/"); + splitPath.pop(); + splitPath.push(""); + return splitPath.join("/"); + } +} \ No newline at end of file diff --git a/hw3/src/Wolfie2D/_Demos/readme.md b/hw3/src/Wolfie2D/_Demos/readme.md new file mode 100644 index 0000000..6086b2f --- /dev/null +++ b/hw3/src/Wolfie2D/_Demos/readme.md @@ -0,0 +1,2 @@ +# Demos +This folder contains the demo projects created in the guides section of the Wolfie2D documentation, as well as any extra demos created for Wolfie2D. \ No newline at end of file diff --git a/hw3/src/default_main.ts b/hw3/src/default_main.ts new file mode 100644 index 0000000..32278ae --- /dev/null +++ b/hw3/src/default_main.ts @@ -0,0 +1,23 @@ +import Game from "./Wolfie2D/Loop/Game"; +import default_scene from "./default_scene"; + +// The main function is your entrypoint into Wolfie2D. Specify your first scene and any options here. +(function main(){ + // Run any tests + runTests(); + + // Set up options for our game + let options = { + canvasSize: {x: 1200, y: 800}, // The size of the game + clearColor: {r: 0, g: 0, b: 0}, // The color the game clears to + useWebGL: true + } + + // Create a game with the options specified + const game = new Game(options); + + // Start our game + game.start(default_scene, {}); +})(); + +function runTests(){}; \ No newline at end of file diff --git a/hw3/src/default_scene.ts b/hw3/src/default_scene.ts new file mode 100644 index 0000000..9281de1 --- /dev/null +++ b/hw3/src/default_scene.ts @@ -0,0 +1,98 @@ +/* #################### IMPORTS #################### */ +// Import from Wolfie2D or your own files here +import Vec2 from "./Wolfie2D/DataTypes/Vec2"; +import Input from "./Wolfie2D/Input/Input"; +import Graphic from "./Wolfie2D/Nodes/Graphic"; +import { GraphicType } from "./Wolfie2D/Nodes/Graphics/GraphicTypes"; +import Sprite from "./Wolfie2D/Nodes/Sprites/Sprite"; +import Scene from "./Wolfie2D/Scene/Scene"; +import Color from "./Wolfie2D/Utils/Color"; + + +/* #################### CLASS DEFINITION #################### */ + +// Welcome to Wolfie2D! +// This is a simple sample scene so something displays when you run the game. +export default class default_scene extends Scene { + /* ########## MEMBER DEFINITIONS ##########*/ + private logo: Sprite; + private player: Graphic; + + /* ########## BUILT-IN FUNCTIONS ########## */ + // The following are built-in abstract Scene functions you are meant to extend. + // They represent the lifecycle of a Scene, and thus allow you to load and start your scene + + // loadScene() is where you should load initial assets needed for your scene. + // it is called strictly before startScene, so you are assured all assets will be loaded before + // the scene begins + loadScene(): void { + // Load any assets here. For example, to load an image (or a sprite): + + // The first argument is the key of the sprite (you get to decide what it is). + // The second argument is the path to the actual image. + // Paths start in the "dist/" folder, so start building your path from there + this.load.image("logo", "demo_assets/images/wolfie2d_text.png"); + } + + // startScene() is where you should build any game objects you wish to have in your scene, + // or where you should initialize any other things you will need in your scene + // Once again, this occurs strictly after loadScene(), so anything you loaded there will be available + startScene(): void { + // Create any game objects here. For example, to add the sprite we previously loaded: + + // First, create a layer for it to go on + this.addLayer("primary"); + + // The first argument is the key we specified in "this.load.image" + // The second argument is the name of the layer + this.logo = this.add.sprite("logo", "primary"); + + // Now, let's make sure our logo is in a good position + let center = this.viewport.getCenter(); + this.logo.position.set(center.x, center.y); + + + + // We can also create game objects (such as graphics and UIElements) without using loaded assets + // Lets add a rectangle to use as the player object + // For some game objects, you have to specify an options object. In this case, position and size: + let options = { + size: new Vec2(50, 50), + position: new Vec2(center.x, center.y + 100) + } + + // Create the rect + this.player = this.add.graphic(GraphicType.RECT, "primary", options); + + // Now, let's change the color of our player + this.player.color = Color.ORANGE; + } + + // updateScene() is where you can handle any frame by frame updates to your scene. + // For the most part, GameNode logic can be abstracted to AI, but there may be + // things you want to control for the whole scene, like player score. + // The argument to updateScene is the time step of the update frame + updateScene(deltaT: number): void { + // For our update, lets create a basic player controller + // First, lets handle the input + const direction = Vec2.ZERO; + + // Sum the x-direction keys + direction.x = (Input.isKeyPressed("a") ? -1 : 0) + (Input.isKeyPressed("d") ? 1 : 0); + + // Sum the y-direction keys + direction.y = (Input.isKeyPressed("w") ? -1 : 0) + (Input.isKeyPressed("s") ? 1 : 0); + + // We don't want to move faster in diagonals, so normalize + direction.normalize(); + + // We want to move 100 units per second, not per frame, so multiply by deltaT when moving + const speed = 100 * deltaT; + + // Scale our direction to speed + const velocity = direction.scale(speed); + + // Finally, adjust the position of the player + this.player.position.add(velocity); + } +} \ No newline at end of file diff --git a/hw3/src/demos/AudioDemo.ts b/hw3/src/demos/AudioDemo.ts new file mode 100644 index 0000000..9b5c58f --- /dev/null +++ b/hw3/src/demos/AudioDemo.ts @@ -0,0 +1,71 @@ +import Vec2 from "../Wolfie2D/DataTypes/Vec2"; +import { GameEventType } from "../Wolfie2D/Events/GameEventType"; +import Input from "../Wolfie2D/Input/Input"; +import Label from "../Wolfie2D/Nodes/UIElements/Label"; +import Slider from "../Wolfie2D/Nodes/UIElements/Slider"; +import { UIElementType } from "../Wolfie2D/Nodes/UIElements/UIElementTypes"; +import Scene from "../Wolfie2D/Scene/Scene"; +import AudioManager, { AudioChannelType } from "../Wolfie2D/Sound/AudioManager"; +import Color from "../Wolfie2D/Utils/Color"; + +export default class Test extends Scene { + loadScene(){ + this.load.audio("song", "demo_assets/sounds/title.mp3"); + this.load.audio("sfx", "demo_assets/sounds/jump.wav"); + } + + startScene(){ + this.emitter.fireEvent(GameEventType.PLAY_MUSIC, {key: "song", loop: true, holdReference: true}); + + this.addLayer("Main"); + + // Initialize value to 1 (music is at max) + let slider = this.add.uiElement(UIElementType.SLIDER, "Main", {position: new Vec2(600, 600), value: 1}); + + // UI Stuff + slider.size = new Vec2(200, 50); + slider.nibSize = new Vec2(30, 30); + slider.nibColor = Color.WHITE; + slider.sliderColor = Color.WHITE; + + slider.onValueChange = (value: number) => { + // Use a non-linear value->volume function, since sound is wack + AudioManager.setVolume(AudioChannelType.MUSIC, value*value); + } + + // Initialize value to 1 (music is at max) + let sfxslider = this.add.uiElement(UIElementType.SLIDER, "Main", {position: new Vec2(600, 700), value: 1}); + + // UI Stuff + sfxslider.size = new Vec2(200, 50); + sfxslider.nibSize = new Vec2(30, 30); + sfxslider.nibColor = Color.WHITE; + sfxslider.sliderColor = Color.WHITE; + + sfxslider.onValueChange = (value: number) => { + // Use a non-linear value->volume function, since sound is wack + AudioManager.setVolume(AudioChannelType.SFX, value*value); + } + + (this.add.uiElement(UIElementType.LABEL, "Main", {position: new Vec2(600, 100), text: "1 - Play a sound"}) as Label).textColor = Color.WHITE; + (this.add.uiElement(UIElementType.LABEL, "Main", {position: new Vec2(600, 200), text: "2 - Mute music"}) as Label).textColor = Color.WHITE; + (this.add.uiElement(UIElementType.LABEL, "Main", {position: new Vec2(600, 300), text: "3 - Unmute music"}) as Label).textColor = Color.WHITE; + (this.add.uiElement(UIElementType.LABEL, "Main", {position: new Vec2(600, 400), text: "4 - Fade out music"}) as Label).textColor = Color.WHITE; + } + + updateScene(deltaT: number){ + if(Input.isKeyJustPressed("1")){ + this.emitter.fireEvent(GameEventType.PLAY_SFX, {key: "sfx", loop: false, holdReference: false}); + } else if(Input.isKeyJustPressed("2")){ + this.emitter.fireEvent(GameEventType.MUTE_CHANNEL, {channel: AudioChannelType.MUSIC}); + } else if(Input.isKeyJustPressed("3")){ + this.emitter.fireEvent(GameEventType.UNMUTE_CHANNEL, {channel: AudioChannelType.MUSIC}); + } else if(Input.isKeyJustPressed("4")){ + // https://developer.mozilla.org/en-US/docs/Web/API/AudioParam + const am = AudioManager.getInstance(); + const ctx = am.getAudioContext(); + const gainNode = am.getChannelGainNode(AudioChannelType.MUSIC); + gainNode.gain.setTargetAtTime(0, ctx.currentTime, 0.5); + } + } +} \ No newline at end of file diff --git a/hw3/src/demos/Platformer.ts b/hw3/src/demos/Platformer.ts new file mode 100644 index 0000000..9eb409a --- /dev/null +++ b/hw3/src/demos/Platformer.ts @@ -0,0 +1,49 @@ +import PlayerController from "./PlatformerPlayerController"; +import Vec2 from "../Wolfie2D/DataTypes/Vec2"; +import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite"; +import Scene from "../Wolfie2D/Scene/Scene"; + +export default class Platformer extends Scene { + private player: AnimatedSprite; + + // Load any assets you will need for the project here + loadScene(){ + // Load the player spritesheet + this.load.spritesheet("player", "demo_assets/spritesheets/platformer/player.json"); + + // Load the tilemap + this.load.tilemap("platformer", "demo_assets/tilemaps/platformer/platformer.json"); + + // Load the background image + this.load.image("background", "demo_assets/images/platformer_background.png"); + + // Load a jump sound + this.load.audio("jump", "demo_assets/sounds/jump.wav"); + } + + // Add GameObjects to the scene + startScene(){ + this.addLayer("primary", 1); + + // Add the player in the starting position + this.player = this.add.animatedSprite("player", "primary"); + this.player.animation.play("IDLE"); + this.player.position.set(3*16, 18*16); + + // Add physics so the player can move + this.player.addPhysics(); + this.player.addAI(PlayerController, {jumpSoundKey: "jump"}); + + // Size of the tilemap is 64x20. Tile size is 16x16 + this.viewport.setBounds(0, 0, 64*16, 20*16); + this.viewport.follow(this.player); + + // Add the tilemap. Top left corner is (0, 0) by default + this.add.tilemap("platformer"); + + // Add a background to the scene + this.addParallaxLayer("bg", new Vec2(0.5, 1), -1); + let bg = this.add.sprite("background", "bg"); + bg.position.set(bg.size.x/2, bg.size.y/2); + } +} \ No newline at end of file diff --git a/hw3/src/demos/PlatformerPlayerController.ts b/hw3/src/demos/PlatformerPlayerController.ts new file mode 100644 index 0000000..60d7be7 --- /dev/null +++ b/hw3/src/demos/PlatformerPlayerController.ts @@ -0,0 +1,62 @@ +import ControllerAI from "../Wolfie2D/AI/ControllerAI"; +import AI from "../Wolfie2D/DataTypes/Interfaces/AI"; +import Emitter from "../Wolfie2D/Events/Emitter"; +import GameEvent from "../Wolfie2D/Events/GameEvent"; +import { GameEventType } from "../Wolfie2D/Events/GameEventType"; +import Input from "../Wolfie2D/Input/Input"; +import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite"; + +export default class PlayerController extends ControllerAI { + public owner: AnimatedSprite; + protected jumpSoundKey: string; + protected emitter: Emitter; + + initializeAI(owner: AnimatedSprite, options: Record): void { + this.owner = owner; + this.jumpSoundKey = options.jumpSoundKey; + this.emitter = new Emitter(); + } + + activate(options: Record): void {} + + handleEvent(event: GameEvent): void { + // Do nothing for now + } + + update(deltaT: number): void { + // Get the direction from key presses + const x = (Input.isPressed("left") ? -1 : 0) + (Input.isPressed("right") ? 1 : 0); + + // Get last velocity and override x + const velocity = this.owner.getLastVelocity(); + velocity.x = x * 100 * deltaT; + + // Check for jump condition + if(this.owner.onGround && Input.isJustPressed("jump")){ + // We are jumping + velocity.y = -250*deltaT; + + // Loop our jump animation + this.owner.animation.play("JUMP", true); + + // Play the jump sound + this.emitter.fireEvent(GameEventType.PLAY_SOUND, {key: this.jumpSoundKey, loop: false}); + } else { + velocity.y += 10*deltaT; + } + + if(this.owner.onGround && !Input.isJustPressed("jump")){ + // If we're on the ground, but aren't jumping, show walk animation + if(velocity.x === 0){ + this.owner.animation.playIfNotAlready("IDLE", true); + } else { + this.owner.animation.playIfNotAlready("WALK", true); + } + } + + // If we're walking left, flip the sprite + this.owner.invertX = velocity.x < 0; + + this.owner.move(velocity); + } +} \ No newline at end of file diff --git a/hw3/src/hw3/AI/BulletAI.ts b/hw3/src/hw3/AI/BulletAI.ts new file mode 100644 index 0000000..907930f --- /dev/null +++ b/hw3/src/hw3/AI/BulletAI.ts @@ -0,0 +1,72 @@ +import AI from "../../Wolfie2D/DataTypes/Interfaces/AI"; +import Vec2 from "../../Wolfie2D/DataTypes/Vec2"; +import Emitter from "../../Wolfie2D/Events/Emitter"; +import GameEvent from "../../Wolfie2D/Events/GameEvent"; +import Receiver from "../../Wolfie2D/Events/Receiver"; +import Graphic from "../../Wolfie2D/Nodes/Graphic"; +import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite"; +import MathUtils from "../../Wolfie2D/Utils/MathUtils"; +import { Homework3Event, Homework3Animations } from "../HW3_Enums"; + +/** + * This class controls our bullet behavior. Bullets will start out at a certain speed and then accelerate until they either + * hit a obstacle or leave the screen. + */ +export default class BulletBehavior implements AI { + // The owner of this AI + private owner: Graphic; + + // The velocity + private current_speed: number; + private start_speed: number; + + // Some vars to keep put bounds on the speed of the bullet + static SPEED_INC: number = 75; + static MAX_SPEED: number = 700; + + // An event emitter and receiver to hook into the event system + private receiver: Receiver + + initializeAI(owner: Graphic, options: Record): void { + this.owner = owner; + + this.current_speed = options.speed;; + + this.receiver = new Receiver(); + + this.receiver.subscribe(Homework3Event.BULLET_USED); + } + + activate(options: Record): void { + this.start_speed = options.speed; + this.current_speed = this.start_speed; + } + + + handleEvent(event: GameEvent): void { + // If the bullet used was the same as this bullet, then reset the speed + if (event.data.get("id") == this.owner.id) { + this.current_speed = this.start_speed; + } + } + + update(deltaT: number): void { + while(this.receiver.hasNextEvent()){ + this.handleEvent(this.receiver.getNextEvent()); + } + + if(this.owner.visible){ + //While this bullet is active, accelerate the bullet to a max speed over time. + this.current_speed += deltaT * BulletBehavior.SPEED_INC; + this.current_speed = MathUtils.clamp(this.current_speed, this.start_speed, BulletBehavior.MAX_SPEED); + + // Update the position + this.owner.position.add(Vec2.UP.scaled(deltaT * this.current_speed)); + } + } + + destroy(): void { + + } + +} \ No newline at end of file diff --git a/hw3/src/hw3/AI/CarPlayerController.ts b/hw3/src/hw3/AI/CarPlayerController.ts new file mode 100644 index 0000000..f4086db --- /dev/null +++ b/hw3/src/hw3/AI/CarPlayerController.ts @@ -0,0 +1,110 @@ +import AI from "../../Wolfie2D/DataTypes/Interfaces/AI"; +import Vec2 from "../../Wolfie2D/DataTypes/Vec2"; +import Debug from "../../Wolfie2D/Debug/Debug"; +import Emitter from "../../Wolfie2D/Events/Emitter"; +import GameEvent from "../../Wolfie2D/Events/GameEvent"; +import Receiver from "../../Wolfie2D/Events/Receiver"; +import Input from "../../Wolfie2D/Input/Input"; +import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite"; +import MathUtils from "../../Wolfie2D/Utils/MathUtils"; +import { Homework3Event } from "../HW3_Enums"; + +export default class CarPlayerController implements AI { + // We want to be able to control our owner, so keep track of them + private owner: AnimatedSprite; + + // The speed the car is moving + private MIN_SPEED: number = 300; + private MAX_SPEED: number = 500; + private speed: number; + + private isDead: boolean = false; + + // A receiver and emitter to hook into the event queue + private receiver: Receiver; + private emitter: Emitter; + + // HOMEWORK 3 + /** + * This method initializes all variables inside of this AI class, and sets + * up anything we need it do. + * + * You should subscribe to the correct event for player damage here using the Receiver. + * The AI will react to the event in handleEvent() - you just need to make sure + * it is subscribed to them. + * + * Also note the names of animations when calling this.owner.animation.play, you do not need to implement these parts but + * note that you either need to adjust the names of the animations to what you have or rename the animations where appropriate. + * + * @param owner The owner of this AI - i.e. the player + * @param options The list of options for ai initialization + */ + initializeAI(owner: AnimatedSprite, options: Record): void { + this.owner = owner; + + //Start with MIN_SPEED + this.speed = this.MIN_SPEED; + + this.receiver = new Receiver(); + this.emitter = new Emitter(); + } + + activate(options: Record){}; + + handleEvent(event: GameEvent): void { + // We need to handle animations when we get hurt + if(event.type === Homework3Event.PLAYER_DAMAGE){ + if(event.data.get("health") === 0){ + // Play animation and queue event to end game + this.owner.animation.play("dying", false, Homework3Event.PLAYER_DEAD); + this.owner.animation.queue("dead", true); + this.isDead = true; + } else { + this.owner.animation.play("damage", false, Homework3Event.PLAYER_I_FRAMES_END); + } + } + } + + update(deltaT: number): void { + if(this.isDead) return; + + while(this.receiver.hasNextEvent()){ + this.handleEvent(this.receiver.getNextEvent()); + } + + //HOMEWORK 3 + //When the player clicks their mouse, a bullet should be fired by using the SHOOT_BULLET event. + //Note that you shouldn't be able to fire a bullet while holding shift. + + + //If shift is currently being held down, increase the speed of the car. If not, check if mouse click has been pressed to shoot a bullet. + if(Input.isKeyPressed("shift")) { + this.speed = this.MAX_SPEED; + } + else { + if (Input.isMouseJustPressed() || Input.isKeyJustPressed("j")) { + this.owner.animation.play("firing", false, Homework3Event.PLAYER_I_FRAMES_END); + this.emitter.fireEvent(Homework3Event.SHOOT_BULLET, {position: this.owner.position.clone()}); + } + this.speed = this.MIN_SPEED; + } + + // We need to handle player input for movement + let forwardAxis = (Input.isPressed('forward') ? 1 : 0) + (Input.isPressed('backward') ? -1 : 0); + let horizontalAxis = (Input.isPressed('left') ? -1 : 0) + (Input.isPressed('right') ? 1 : 0); + + let movement = Vec2.UP.scaled(forwardAxis * this.speed); + movement = movement.add(new Vec2(horizontalAxis * this.speed, 0)); + + // Move the player + this.owner.position.add(movement.scaled(deltaT)); + + // Animations + if(!this.owner.animation.isPlaying("damage") && !this.owner.animation.isPlaying("dying") && !this.owner.animation.isPlaying("firing")){ + this.owner.animation.playIfNotAlready("driving"); + } + } + destroy(): void { + + } +} diff --git a/hw3/src/hw3/AI/RockAI.ts b/hw3/src/hw3/AI/RockAI.ts new file mode 100644 index 0000000..3361dbd --- /dev/null +++ b/hw3/src/hw3/AI/RockAI.ts @@ -0,0 +1,39 @@ +import AI from "../../Wolfie2D/DataTypes/Interfaces/AI"; +import Vec2 from "../../Wolfie2D/DataTypes/Vec2"; +import Debug from "../../Wolfie2D/Debug/Debug"; +import GameEvent from "../../Wolfie2D/Events/GameEvent"; +import GameNode from "../../Wolfie2D/Nodes/GameNode"; +import Graphic from "../../Wolfie2D/Nodes/Graphic"; + +export default class RockAI implements AI { + // The owner of this AI + protected owner: Graphic; + + // The direction of an rock + public direction: Vec2; + + // The speed all rocks move at + public static SPEED: number = 10; + + initializeAI(owner: Graphic, options: Record): void { + this.owner = owner; + this.direction = Vec2.ZERO; + } + + activate(options: Record): void { + this.direction = options.direction; + } + + handleEvent(event: GameEvent): void { + // Do nothing + } + + update(deltaT: number): void { + if(this.owner.visible) + this.owner.position.add(Vec2.DOWN.scaled(RockAI.SPEED * deltaT)); + } + + destroy(): void { + + } +} \ No newline at end of file diff --git a/hw3/src/hw3/GradientCircleShaderType.ts b/hw3/src/hw3/GradientCircleShaderType.ts new file mode 100644 index 0000000..c5827d7 --- /dev/null +++ b/hw3/src/hw3/GradientCircleShaderType.ts @@ -0,0 +1,80 @@ +import Map from "../Wolfie2D/DataTypes/Map"; +import Mat4x4 from "../Wolfie2D/DataTypes/Mat4x4"; +import Vec2 from "../Wolfie2D/DataTypes/Vec2"; +import Graphic from "../Wolfie2D/Nodes/Graphic"; +import Rect from "../Wolfie2D/Nodes/Graphics/Rect"; +import RectShaderType from "../Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType"; +import Color from "../Wolfie2D/Utils/Color"; + + +export default class GradientCircleShaderType extends RectShaderType { + + initBufferObject(): void { + this.bufferObjectKey = "gradient_circle"; + this.resourceManager.createBuffer(this.bufferObjectKey); + } + + render(gl: WebGLRenderingContext, options: Record): void { + // Get our program and buffer object + const program = this.resourceManager.getShaderProgram(this.programKey); + const buffer = this.resourceManager.getBuffer(this.bufferObjectKey); + + // Let WebGL know we're using our shader program + gl.useProgram(program); + + // Get our vertex data + const vertexData = this.getVertices(options.size.x, options.size.y); + const FSIZE = vertexData.BYTES_PER_ELEMENT; + + // Bind the buffer + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); + + /* ##### ATTRIBUTES ##### */ + // No texture, the only thing we care about is vertex position + const a_Position = gl.getAttribLocation(program, "a_Position"); + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE); + gl.enableVertexAttribArray(a_Position); + + /* ##### UNIFORMS ##### */ + + // Get transformation matrix + // We have a square for our rendering space, so get the maximum dimension of our quad + let maxDimension = Math.max(options.size.x, options.size.y); + + // The size of the rendering space will be a square with this maximum dimension + let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y); + + // Center our translations around (0, 0) + const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension; + const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension; + + // Create our transformation matrix + this.translation.translate(new Float32Array([translateX, translateY])); + this.scale.scale(size); + this.rotation.rotate(options.rotation); + let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation); + + // Pass the translation matrix to our shader + const u_Transform = gl.getUniformLocation(program, "u_Transform"); + gl.uniformMatrix4fv(u_Transform, false, transformation.toArray()); + + //color + let webGL_color = options.color.toWebGL(); + const circle_Color = gl.getUniformLocation(program, "circle_Color"); + gl.uniform4f(circle_Color, webGL_color[0], webGL_color[1], webGL_color[2], webGL_color[3]); + + // Draw the quad + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + getOptions(gc: Rect): Record { + let options: Record = { + position: gc.position, + size: gc.size, + rotation: gc.rotation, + color: gc.color + } + return options; + } +} \ No newline at end of file diff --git a/hw3/src/hw3/HW3_Enums.ts b/hw3/src/hw3/HW3_Enums.ts new file mode 100644 index 0000000..4bb0770 --- /dev/null +++ b/hw3/src/hw3/HW3_Enums.ts @@ -0,0 +1,23 @@ +export enum Homework3Event { + PLAY_GAME = "PLAY_GAME", + CONTROLS = "CONTROLS", + ABOUT = "ABOUT", + MENU = "MENU", + + PLAYER_DAMAGE = "PLAYER_DAMAGE", + PLAYER_I_FRAMES_END = "PLAYER_I_FRAMES_END", + PLAYER_DEAD = "PLAYER_DEAD", + SHOOT_BULLET = "SHOOT_BULLET", + BULLET_USED = "BULLET_USED" +} + +export enum Homework3Shaders { + GRADIENT_CIRCLE = "GRADIENT_CIRCLE", + LINEAR_GRADIENT_CIRCLE = "LINEAR_GRADIENT_CIRCLE" +} + +export enum Homework3Animations { + CAR_IDLE = "idle", + CAR_BOOST = "boost", + CAR_DIE = "explode" +} \ No newline at end of file diff --git a/hw3/src/hw3/LinearGradientCircleShaderType.ts b/hw3/src/hw3/LinearGradientCircleShaderType.ts new file mode 100644 index 0000000..6c2b8bc --- /dev/null +++ b/hw3/src/hw3/LinearGradientCircleShaderType.ts @@ -0,0 +1,109 @@ +import Map from "../Wolfie2D/DataTypes/Map"; +import Mat4x4 from "../Wolfie2D/DataTypes/Mat4x4"; +import Vec2 from "../Wolfie2D/DataTypes/Vec2"; +import Graphic from "../Wolfie2D/Nodes/Graphic"; +import Rect from "../Wolfie2D/Nodes/Graphics/Rect"; +import RectShaderType from "../Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType"; +import Color from "../Wolfie2D/Utils/Color"; + +/** + * The linear gradient circle is technically rendered on a quad, and is similar to a rect, so we'll extend the RectShaderType + */ +export default class LinearGradientCircleShaderType extends RectShaderType { + + initBufferObject(): void { + this.bufferObjectKey = "linear_gradient_circle"; + this.resourceManager.createBuffer(this.bufferObjectKey); + } + + // HOMEWORK 3 + /** + * You should modify this method to pass another color into LinearGradientCircles + * + * Think about the best way to pass data to the shader: + * Is color static throughout the shader program (uniforms)? Or does it depend on the vertex (attributes)? + * Is color interpolated depending on the position of the fragment between vertices (varying)? + * + * You may look at the variables passed to the shader in this render function, as well as those + * in other ShaderTypes. + * + * @param gl The rendering context + * @param options The options object received from the getOptions() method + */ + render(gl: WebGLRenderingContext, options: Record): void { + // Get our program and buffer object + const program = this.resourceManager.getShaderProgram(this.programKey); + const buffer = this.resourceManager.getBuffer(this.bufferObjectKey); + + // Let WebGL know we're using our shader program + gl.useProgram(program); + + // Get our vertex data + const vertexData = this.getVertices(options.size.x, options.size.y); + const FSIZE = vertexData.BYTES_PER_ELEMENT; + + // Bind the buffer + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); + + /* ##### ATTRIBUTES ##### */ + // No texture, the only thing we care about is vertex position + const a_Position = gl.getAttribLocation(program, "a_Position"); + gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE); + gl.enableVertexAttribArray(a_Position); + + /* ##### UNIFORMS ##### */ + + // Get transformation matrix + // We have a square for our rendering space, so get the maximum dimension of our quad + let maxDimension = Math.max(options.size.x, options.size.y); + + // The size of the rendering space will be a square with this maximum dimension + let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y); + + // Center our translations around (0, 0) + const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension; + const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension; + + // Create our transformation matrix + this.translation.translate(new Float32Array([translateX, translateY])); + this.scale.scale(size); + this.rotation.rotate(options.rotation); + let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation); + + // Pass the translation matrix to our shader + const u_Transform = gl.getUniformLocation(program, "u_Transform"); + gl.uniformMatrix4fv(u_Transform, false, transformation.toArray()); + + //color + + + let webGL_color = options.color.toWebGL(); + const circle_Color = gl.getUniformLocation(program, "circle_Color"); + gl.uniform4f(circle_Color, webGL_color[0], webGL_color[1], webGL_color[2], webGL_color[3]); + + let default_color = Color.BLUE.toWebGL(); + const default_Color = gl.getUniformLocation(program, "default_Color"); + gl.uniform4f(default_Color, default_color[0], default_color[1], default_color[2], default_color[3]); + + // Draw the quad + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + // HOMEWORK 3 + /** + * This method decides what options get passed to the above render() method. + * You should modify this class to allow you to pass another color into the render method. + * The second color you pass in should be blue, and this can be hardcoded into this method since + * Rect only has 1 color field. + */ + getOptions(gc: Rect): Record { + let options: Record = { + position: gc.position, + size: gc.size, + rotation: gc.rotation, + color: gc.color, + } + return options; + } +} \ No newline at end of file diff --git a/hw3/src/hw3/Scenes/GameOver.ts b/hw3/src/hw3/Scenes/GameOver.ts new file mode 100644 index 0000000..e51b4c3 --- /dev/null +++ b/hw3/src/hw3/Scenes/GameOver.ts @@ -0,0 +1,41 @@ +import Vec2 from "../../Wolfie2D/DataTypes/Vec2"; +import Input from "../../Wolfie2D/Input/Input"; +import Label from "../../Wolfie2D/Nodes/UIElements/Label"; +import { UIElementType } from "../../Wolfie2D/Nodes/UIElements/UIElementTypes"; +import Scene from "../../Wolfie2D/Scene/Scene"; +import Color from "../../Wolfie2D/Utils/Color"; +import MainMenu from "./MainMenu"; + +export default class GameOver extends Scene { + private score: number; + private minerals: number; + + initScene(options: Record){ + this.score = options.score; + this.minerals = options.minerals; + } + + startScene() { + const center = this.viewport.getCenter(); + + this.addUILayer("primary"); + + const gameOver =