From b6920389b0064e0cd19c017e9d59d05515550313 Mon Sep 17 00:00:00 2001 From: gered Date: Sun, 10 Aug 2014 19:10:01 -0400 Subject: [PATCH] initial commit --- .gitignore | 16 + LICENSE | 21 + README.md | 43 ++ assets/consoleFont.fnt | 101 +++++ assets/consoleFont.png | Bin 0 -> 1816 bytes assets/player.atlas.json | 6 + assets/player.png | Bin 0 -> 5162 bytes assets/readme.txt | 15 + assets/tiles/bricks.tilemesh | 7 + assets/tiles/dirt.tilemesh | 7 + assets/tiles/dirt_grass_top.tilemesh | 14 + assets/tiles/grass.tilemesh | 7 + assets/tiles/leaves.tilemesh | 8 + assets/tiles/planks.tilemesh | 7 + assets/tiles/sand.tilemesh | 7 + assets/tiles/stone_floor.tilemesh | 7 + assets/tiles/terrain.atlas.json | 6 + assets/tiles/terrain.png | Bin 0 -> 6259 bytes assets/tiles/tiles.json | 14 + assets/tiles/trunk.tilemesh | 14 + build.gradle | 40 ++ core/build.gradle | 9 + .../basicexample/BasicExampleGameApp.java | 46 +++ .../tiles3/basicexample/ContentCache.java | 43 ++ .../tiles3/basicexample/DebugInfoProcess.java | 93 +++++ .../tiles3/basicexample/GamePlayState.java | 183 +++++++++ .../ca/blarg/tiles3/basicexample/Level.java | 66 +++ .../ca/blarg/tiles3/basicexample/Prefabs.java | 38 ++ .../entities/AnimationSequence.java | 61 +++ .../entities/AnimationSequenceCollection.java | 31 ++ .../basicexample/entities/EntityState.java | 14 + .../basicexample/entities/EntityUtils.java | 13 + .../entities/FacingDirection.java | 85 ++++ .../entities/PhysicsConstants.java | 15 + .../entities/components/CameraComponent.java | 14 + .../entities/components/PlayerComponent.java | 9 + .../entities/components/StateComponent.java | 17 + .../entities/components/WorldComponent.java | 17 + .../physics/BoundingSphereComponent.java | 15 + .../physics/OrientationXZComponent.java | 18 + .../components/physics/PhysicsComponent.java | 95 +++++ .../components/physics/PositionComponent.java | 15 + .../rendering/AnimationComponent.java | 84 ++++ .../rendering/AutoAnimationComponent.java | 29 ++ .../rendering/BillboardComponent.java | 43 ++ .../entities/events/AnimationChangeEvent.java | 24 ++ .../events/AnimationFinishedEvent.java | 13 + .../entities/events/DespawnedEvent.java | 13 + .../events/EntityExitingTempStateEvent.java | 13 + .../events/EntityInTempStateEvent.java | 13 + .../events/EntityStateChangeEvent.java | 20 + .../entities/events/JumpEvent.java | 13 + .../entities/events/MoveAndTurnEvent.java | 15 + .../entities/events/MoveForwardEvent.java | 13 + .../entities/events/MoveInDirectionEvent.java | 16 + .../entities/events/SpawnedEvent.java | 13 + .../entities/events/StopMovementEvent.java | 13 + .../basicexample/entities/forces/Force.java | 87 ++++ .../entities/forces/JumpForce.java | 72 ++++ .../presets/BaseObjectEntityPreset.java | 52 +++ .../entities/presets/PlayerPreset.java | 65 +++ .../entities/subsystems/AnimationSystem.java | 175 ++++++++ .../subsystems/BillboardRenderSystem.java | 78 ++++ .../BoundingVolumeWorldPositioningSystem.java | 24 ++ .../entities/subsystems/CameraSystem.java | 68 ++++ .../subsystems/EntityStateSystem.java | 162 ++++++++ .../entities/subsystems/PhysicsSystem.java | 378 ++++++++++++++++++ .../subsystems/PreviousPositionSystem.java | 21 + .../subsystems/WorldRendererSystem.java | 80 ++++ desktop/build.gradle | 45 +++ .../basicexample/desktop/DesktopStarter.java | 16 + screenshot.png | Bin 0 -> 143862 bytes settings.gradle | 1 + 73 files changed, 2896 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/consoleFont.fnt create mode 100644 assets/consoleFont.png create mode 100644 assets/player.atlas.json create mode 100644 assets/player.png create mode 100644 assets/readme.txt create mode 100644 assets/tiles/bricks.tilemesh create mode 100644 assets/tiles/dirt.tilemesh create mode 100644 assets/tiles/dirt_grass_top.tilemesh create mode 100644 assets/tiles/grass.tilemesh create mode 100644 assets/tiles/leaves.tilemesh create mode 100644 assets/tiles/planks.tilemesh create mode 100644 assets/tiles/sand.tilemesh create mode 100644 assets/tiles/stone_floor.tilemesh create mode 100644 assets/tiles/terrain.atlas.json create mode 100644 assets/tiles/terrain.png create mode 100644 assets/tiles/tiles.json create mode 100644 assets/tiles/trunk.tilemesh create mode 100644 build.gradle create mode 100644 core/build.gradle create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/BasicExampleGameApp.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/ContentCache.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/DebugInfoProcess.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/GamePlayState.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/Level.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/Prefabs.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/AnimationSequence.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/AnimationSequenceCollection.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityState.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityUtils.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/FacingDirection.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/PhysicsConstants.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/CameraComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/PlayerComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/StateComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/WorldComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/BoundingSphereComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/OrientationXZComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PhysicsComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PositionComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AnimationComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AutoAnimationComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/BillboardComponent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationChangeEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationFinishedEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/DespawnedEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityExitingTempStateEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityInTempStateEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityStateChangeEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/JumpEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveAndTurnEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveForwardEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveInDirectionEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/SpawnedEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/StopMovementEvent.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/Force.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/JumpForce.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/BaseObjectEntityPreset.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/PlayerPreset.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/AnimationSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BillboardRenderSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BoundingVolumeWorldPositioningSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/CameraSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/EntityStateSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PhysicsSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PreviousPositionSystem.java create mode 100644 core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/WorldRendererSystem.java create mode 100644 desktop/build.gradle create mode 100644 desktop/src/main/java/ca/blarg/tiles3/basicexample/desktop/DesktopStarter.java create mode 100644 screenshot.png create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aff5aa5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.DS_Store +.gradle/ +out/ +log/ +target/ +build/ +.settings/ +.project +.classpath +.idea +*.iml +*.eml +*.ipr +*.iws +*.class +*.jar diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8d9476f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Gered King + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1f15707 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# Tiles³ Framework: Basic Example + +A basic working example application of the "Tiles³ Framework" in action. This just +show cases a complete but very, very simple application that makes use of: + +* [libGDX](http://libgdx.badlogicgames.com/) +* [gdx-toolbox](https://github.com/gered/gdx-toolbox) +* [gdx-tilemap3d](https://github.com/gered/gdx-tilemap3d) +* Basic custom entity/event system and gameplay handling code. + +This basic example is nothing more then a boring walk-around demo. Nothing too +exciting as you would expect from something called a "basic example." + +![Screenshot 2](screenshot.png) + +## What is the "Tiles³ Framework"? + +This is what I'm calling my own custom "framework" (and I'm using the word loosely here) +for building 3D tile-based top-down real-time action games. This framework is built upon +libGDX and my own libraries gdx-toolbox and gdx-tilemap3d and builds on the entity and +event system in those with a bunch of pre-built subsystems somewhat suitable for building +games. + +**This is NOT intended to be a generic game engine / library.** Rather, it is just my +common game template (for these specific types of games) which I'm giving a name +and putting up for anyone else to use. You will _very likely_ want to heavily +customize this, assuming it even meets your needs at all! + +## Running + +You will need Gradle. Clone the repository and then from a terminal: + + $ gradle desktop:run + +And it should download the project dependencies, build and then run. + +## TODO + +[[Write something here briefly explaining the project and code structure]] + +## License + +Distributed under the the MIT License. See LICENSE for more details. diff --git a/assets/consoleFont.fnt b/assets/consoleFont.fnt new file mode 100644 index 0000000..deb62bb --- /dev/null +++ b/assets/consoleFont.fnt @@ -0,0 +1,101 @@ +info face="DeluxeFontReg" size=8 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0 +common lineHeight=9 base=7 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="consoleFont.png" +chars count=95 +char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=7 xadvance=8 page=0 chnl=0 +char id=106 x=0 y=0 width=6 height=9 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=38 x=6 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=35 x=14 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=36 x=22 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=92 x=29 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=64 x=37 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=47 x=45 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=124 x=53 y=0 width=3 height=8 xoffset=3 yoffset=0 xadvance=8 page=0 chnl=0 +char id=62 x=56 y=0 width=6 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=60 x=62 y=0 width=6 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=125 x=68 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=123 x=75 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=93 x=82 y=0 width=5 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=91 x=87 y=0 width=5 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=41 x=92 y=0 width=5 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=40 x=97 y=0 width=5 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=59 x=102 y=0 width=4 height=8 xoffset=1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=63 x=106 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=33 x=113 y=0 width=3 height=8 xoffset=2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=48 x=116 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=57 x=124 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=56 x=131 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=55 x=138 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=54 x=145 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=53 x=152 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=52 x=159 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=51 x=167 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=50 x=174 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=49 x=181 y=0 width=5 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=116 x=186 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=108 x=193 y=0 width=4 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=107 x=197 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=105 x=204 y=0 width=3 height=8 xoffset=2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=104 x=207 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=102 x=214 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=100 x=221 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=98 x=228 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=90 x=235 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=89 x=243 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=88 x=250 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=87 x=258 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=86 x=266 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=85 x=273 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=84 x=280 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=83 x=287 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=82 x=294 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=81 x=301 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=80 x=308 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=79 x=315 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=78 x=322 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=77 x=330 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=76 x=338 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=75 x=345 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=74 x=353 y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=73 x=361 y=0 width=5 height=8 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=72 x=366 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=71 x=373 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=70 x=380 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=69 x=387 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=68 x=394 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=67 x=401 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=66 x=408 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=65 x=415 y=0 width=7 height=8 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=127 x=422 y=0 width=8 height=7 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=0 +char id=37 x=430 y=0 width=8 height=7 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=0 +char id=58 x=438 y=0 width=3 height=7 xoffset=2 yoffset=1 xadvance=8 page=0 chnl=0 +char id=121 x=441 y=0 width=7 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=113 x=448 y=0 width=7 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=112 x=455 y=0 width=7 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=103 x=462 y=0 width=7 height=7 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=42 x=469 y=0 width=9 height=6 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=0 +char id=43 x=478 y=0 width=7 height=6 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=0 +char id=122 x=485 y=0 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=120 x=492 y=0 width=8 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=119 x=500 y=0 width=8 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=118 x=0 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=117 x=7 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=115 x=14 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=114 x=21 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=111 x=28 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=110 x=35 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=109 x=42 y=9 width=8 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=101 x=50 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=99 x=57 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=97 x=64 y=9 width=7 height=6 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=61 x=71 y=9 width=7 height=5 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0 +char id=94 x=78 y=9 width=8 height=5 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=44 x=86 y=9 width=4 height=4 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 +char id=39 x=90 y=9 width=4 height=4 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=96 x=94 y=9 width=4 height=4 xoffset=2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=34 x=98 y=9 width=6 height=4 xoffset=1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=126 x=104 y=9 width=8 height=3 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=46 x=112 y=9 width=3 height=3 xoffset=2 yoffset=5 xadvance=8 page=0 chnl=0 +char id=95 x=115 y=9 width=9 height=2 xoffset=0 yoffset=7 xadvance=8 page=0 chnl=0 +char id=45 x=124 y=9 width=7 height=2 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +kernings count=-1 diff --git a/assets/consoleFont.png b/assets/consoleFont.png new file mode 100644 index 0000000000000000000000000000000000000000..f77bd7807953dfdc53bc1947546a70e52f83815a GIT binary patch literal 1816 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 literal 0 HcmV?d00001 diff --git a/assets/readme.txt b/assets/readme.txt new file mode 100644 index 0000000..7495d9e --- /dev/null +++ b/assets/readme.txt @@ -0,0 +1,15 @@ +Artwork Credits +--------------- + +Player sprite: + Oryx and Geese (animations) + http://forums.tigsource.com/index.php?topic=8970.0 + +Font: + DeluxeFont by codeman38 + http://www.zone38.net/font/#deluxefont + +Terrain Textures: + From an 8x8 Minecraft Texturepack that I can't find anymore. There are + several of them and none of the ones I checked, at the time I was + writing these credits, exactly match the textures I copied. :( diff --git a/assets/tiles/bricks.tilemesh b/assets/tiles/bricks.tilemesh new file mode 100644 index 0000000..39be9c4 --- /dev/null +++ b/assets/tiles/bricks.tilemesh @@ -0,0 +1,7 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 7, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} \ No newline at end of file diff --git a/assets/tiles/dirt.tilemesh b/assets/tiles/dirt.tilemesh new file mode 100644 index 0000000..8068515 --- /dev/null +++ b/assets/tiles/dirt.tilemesh @@ -0,0 +1,7 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 2, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} \ No newline at end of file diff --git a/assets/tiles/dirt_grass_top.tilemesh b/assets/tiles/dirt_grass_top.tilemesh new file mode 100644 index 0000000..8c6e489 --- /dev/null +++ b/assets/tiles/dirt_grass_top.tilemesh @@ -0,0 +1,14 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "textures": { + "top": 0, + "left": 1, + "front": 1, + "right": 1, + "back": 1, + "bottom": 2 + }, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} diff --git a/assets/tiles/grass.tilemesh b/assets/tiles/grass.tilemesh new file mode 100644 index 0000000..7bcea3a --- /dev/null +++ b/assets/tiles/grass.tilemesh @@ -0,0 +1,7 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 0, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} \ No newline at end of file diff --git a/assets/tiles/leaves.tilemesh b/assets/tiles/leaves.tilemesh new file mode 100644 index 0000000..37cba31 --- /dev/null +++ b/assets/tiles/leaves.tilemesh @@ -0,0 +1,8 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 3, + "faces": ["ALL"], + "alpha": true, + "translucency": 0.25, +} \ No newline at end of file diff --git a/assets/tiles/planks.tilemesh b/assets/tiles/planks.tilemesh new file mode 100644 index 0000000..a4eec02 --- /dev/null +++ b/assets/tiles/planks.tilemesh @@ -0,0 +1,7 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 6, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} \ No newline at end of file diff --git a/assets/tiles/sand.tilemesh b/assets/tiles/sand.tilemesh new file mode 100644 index 0000000..ac09083 --- /dev/null +++ b/assets/tiles/sand.tilemesh @@ -0,0 +1,7 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 9, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} \ No newline at end of file diff --git a/assets/tiles/stone_floor.tilemesh b/assets/tiles/stone_floor.tilemesh new file mode 100644 index 0000000..bf24b40 --- /dev/null +++ b/assets/tiles/stone_floor.tilemesh @@ -0,0 +1,7 @@ +{ + "textureAtlas": "terrain.atlas.json", + "cube": true, + "texture": 8, + "faces": ["ALL"], + "opaqueSides": ["ALL"] +} \ No newline at end of file diff --git a/assets/tiles/terrain.atlas.json b/assets/tiles/terrain.atlas.json new file mode 100644 index 0000000..904e8ac --- /dev/null +++ b/assets/tiles/terrain.atlas.json @@ -0,0 +1,6 @@ +{ + "texture": "terrain.png", + "tiles": [ + {"autogrid": true, "numTilesX": 8, "numTilesY": 8, "tileWidth": 8, "tileHeight": 8}, + ] +} \ No newline at end of file diff --git a/assets/tiles/terrain.png b/assets/tiles/terrain.png new file mode 100644 index 0000000000000000000000000000000000000000..3905ec07ad1235c42da5d589e5d78cb2ecb7a07d GIT binary patch literal 6259 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 sequences = new ObjectMap(); + + public AnimationSequenceCollection() { + } + + public AnimationSequence add(String key) { + if (sequences.containsKey(key)) + throw new UnsupportedOperationException("Sequence with that name present in collection already"); + AnimationSequence sequence = Pools.obtain(AnimationSequence.class); + sequences.put(key, sequence); + return sequence; + } + + public AnimationSequence get(String key) { + return sequences.get(key); + } + + @Override + public void reset() { + for (ObjectMap.Entry i : sequences.entries()) + Pools.free(i.value); + sequences.clear(); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityState.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityState.java new file mode 100644 index 0000000..cafebeb --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityState.java @@ -0,0 +1,14 @@ +package ca.blarg.tiles3.basicexample.entities; + +public enum EntityState { + None, + Idle, + Walking, + Falling, + Jumping, + Dead, + Punching, + Shooting, + Open, + Inactive +} \ No newline at end of file diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityUtils.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityUtils.java new file mode 100644 index 0000000..37eea84 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/EntityUtils.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.tiles3.basicexample.entities.components.physics.PositionComponent; +import com.badlogic.gdx.math.Vector3; + +public class EntityUtils { + public static void getInterpolatedPosition(Entity entity, float alpha, Vector3 outPosition) { + PositionComponent position = entity.get(PositionComponent.class); + outPosition.set(position.lastPosition); + outPosition.lerp(position.position, alpha); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/FacingDirection.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/FacingDirection.java new file mode 100644 index 0000000..6dd184e --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/FacingDirection.java @@ -0,0 +1,85 @@ +package ca.blarg.tiles3.basicexample.entities; + +import com.badlogic.gdx.math.Vector3; +import ca.blarg.gdx.math.MathHelpers; + +public enum FacingDirection { + North(0), + NorthEast(1), + East(2), + SouthEast(3), + South(4), + SouthWest(5), + West(6), + NorthWest(7); + + int value; + + private FacingDirection(int value) { + this.value = value; + } + + public int value() { + return value; + } + + /** + * the enum values and static angle constants are set such that: + * + * 1. east = +x direction + * west = -x direction + * north = -z direction + * south = +z direction + * + * 2. enum.value() * MULTIPLIER = the corresponding static angle constant for + * the enum's direction + * (e.g. FacingDirection.East.value() * MULTIPLIER == FacingDirection.EAST_ANGLE) + */ + + public static float MULTIPLIER = 45.0f; + + public static float NORTH_ANGLE = 0.0f; + public static float NORTHEAST_ANGLE = 45.0f; + public static float EAST_ANGLE = 90.0f; + public static float SOUTHEAST_ANGLE = 135.0f; + public static float SOUTH_ANGLE = 180.0f; + public static float SOUTHWEST_ANGLE = 225.0f; + public static float WEST_ANGLE = 270.0f; + public static float NORTHWEST_ANGLE = 315.0f; + + public static FacingDirection getFacingDirection(float orientationY, boolean limitToQuadrantDirections) { + final float QUADRANT_ANGLE_ADJUSTMENT = 45.0f; + final float QUADRANT_DIRECTION_DIVISOR = 90.0f; + final float OCTANT_ANGLE_ADJUSTMENT = QUADRANT_ANGLE_ADJUSTMENT / 2.0f; + final float OCTANT_DIRECTION_DIVISOR = 45.0f; + + float adjustment = limitToQuadrantDirections ? QUADRANT_ANGLE_ADJUSTMENT : OCTANT_ANGLE_ADJUSTMENT; + float divisor = limitToQuadrantDirections ? QUADRANT_DIRECTION_DIVISOR : OCTANT_DIRECTION_DIVISOR; + + // add 45 degrees initially to kind of "rotate" the 360 degree circle + // clockwise because 315 -> 360 is also part of the "east" quadrant along + // with 0 -> 45. + float adjusted = (orientationY) + adjustment; + if (adjusted >= 360.0f) + adjusted -= 360.0f; + + return FacingDirection.values()[(int)(adjusted / divisor)]; + } + + public static FacingDirection getFacingDirection(Vector3 orientation, boolean limitToQuadrantDirections) { + return getFacingDirection(orientation.y, limitToQuadrantDirections); + } + + public static FacingDirection getFacingDirectionAdjustedForCamera(float objectOrientationY, float cameraYaw, boolean limitToQuadrantDirections) { + // HACK: this pretty much means I should probably just forget about 'adjusting' the angles by 90.0f and such + // and just use the "native" orientations... + float hackyAdjustedObjectOrientationY = objectOrientationY + 180.0f; + + float difference = MathHelpers.rolloverClamp(hackyAdjustedObjectOrientationY - cameraYaw, 0.0f, 360.0f); + return getFacingDirection(difference, limitToQuadrantDirections); + } + + public static float getFacingAngle(FacingDirection direction) { + return ((float)direction.ordinal()) * MULTIPLIER; + } +} \ No newline at end of file diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/PhysicsConstants.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/PhysicsConstants.java new file mode 100644 index 0000000..8f15b0f --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/PhysicsConstants.java @@ -0,0 +1,15 @@ +package ca.blarg.tiles3.basicexample.entities; + +import com.badlogic.gdx.math.Vector3; + +public final class PhysicsConstants { + public static final float UNITS_PER_METRE = 1.0f; + + public static final float GRAVITY_SPEED = 9.8f * UNITS_PER_METRE; + public static final Vector3 GRAVITY = new Vector3(0.0f, -GRAVITY_SPEED, 0.0f); + + public static final float FRICTION_NORMAL = 0.5f; + + public static final float SLOPE_STEEP_Y_ANGLE = 46; + public static final float ON_GROUND_ZERO_TOLERANCE = 0.1f; +} \ No newline at end of file diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/CameraComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/CameraComponent.java new file mode 100644 index 0000000..cd34468 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/CameraComponent.java @@ -0,0 +1,14 @@ +package ca.blarg.tiles3.basicexample.entities.components; + +import ca.blarg.gdx.entities.Component; + +public class CameraComponent extends Component { + public boolean useEntityOrientation; + public float yAngle; + + @Override + public void reset() { + useEntityOrientation = false; + yAngle = 0.0f; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/PlayerComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/PlayerComponent.java new file mode 100644 index 0000000..6bd19d4 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/PlayerComponent.java @@ -0,0 +1,9 @@ +package ca.blarg.tiles3.basicexample.entities.components; + +import ca.blarg.gdx.entities.Component; + +public class PlayerComponent extends Component { + @Override + public void reset() { + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/StateComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/StateComponent.java new file mode 100644 index 0000000..d5e0861 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/StateComponent.java @@ -0,0 +1,17 @@ +package ca.blarg.tiles3.basicexample.entities.components; + +import ca.blarg.gdx.entities.Component; +import ca.blarg.tiles3.basicexample.entities.EntityState; + +public class StateComponent extends Component { + public EntityState state; + public EntityState actionState; + public boolean isInActionState; + + @Override + public void reset() { + state = EntityState.None; + actionState = EntityState.None; + isInActionState = false; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/WorldComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/WorldComponent.java new file mode 100644 index 0000000..0da1eff --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/WorldComponent.java @@ -0,0 +1,17 @@ +package ca.blarg.tiles3.basicexample.entities.components; + +import ca.blarg.gdx.entities.Component; +import ca.blarg.gdx.tilemap3d.TileMap; + +public class WorldComponent extends Component { + public TileMap tileMap; + public boolean renderGrid; + public boolean renderSkybox; + + @Override + public void reset() { + tileMap = null; + renderGrid = false; + renderSkybox = false; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/BoundingSphereComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/BoundingSphereComponent.java new file mode 100644 index 0000000..c96fad5 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/BoundingSphereComponent.java @@ -0,0 +1,15 @@ +package ca.blarg.tiles3.basicexample.entities.components.physics; + +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.math.collision.Sphere; +import ca.blarg.gdx.entities.Component; + +public class BoundingSphereComponent extends Component { + public final Sphere bounds = new Sphere(Vector3.Zero, 0.0f); + + @Override + public void reset() { + bounds.center.set(Vector3.Zero); + bounds.radius = 0.0f; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/OrientationXZComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/OrientationXZComponent.java new file mode 100644 index 0000000..e505bce --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/OrientationXZComponent.java @@ -0,0 +1,18 @@ +package ca.blarg.tiles3.basicexample.entities.components.physics; + +import com.badlogic.gdx.math.Vector3; +import ca.blarg.gdx.entities.Component; +import ca.blarg.gdx.math.MathHelpers; + +public class OrientationXZComponent extends Component { + public float angle = 0.0f; + + public void getDirectionVector(Vector3 out) { + MathHelpers.getDirectionVector3FromYAxis(angle, out); + } + + @Override + public void reset() { + angle = 0.0f; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PhysicsComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PhysicsComponent.java new file mode 100644 index 0000000..e3e7aed --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PhysicsComponent.java @@ -0,0 +1,95 @@ +package ca.blarg.tiles3.basicexample.entities.components.physics; + +import ca.blarg.gdx.entities.Component; +import ca.blarg.gdx.math.SweptSphere; +import ca.blarg.gdx.tilemap3d.Tile; +import ca.blarg.gdx.tilemap3d.TileCoord; +import ca.blarg.tiles3.basicexample.entities.forces.Force; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.math.collision.Ray; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Pools; + +public class PhysicsComponent extends Component { + public final Vector3 velocity = new Vector3(); + public final Vector3 lastTickVelocity = new Vector3(); + public final Vector3 currentTickVelocity = new Vector3(); + + public final Vector3 walkingVelocity = new Vector3(); + public float walkingAcceleration; + public float maxWalkSpeed; + public float friction; + + public final Array forces = new Array(false, 4, Force.class); + public final Vector3 forceVelocity = new Vector3(); + + public final SweptSphere sweptSphere = new SweptSphere(); + public final TileCoord collisionTilePosition = new TileCoord(); + public final TileCoord standingOnTilePosition = new TileCoord(); + public Tile standingOnTile; + + public boolean isWalking; + public boolean wasWalking; + public boolean isInMotion; + public boolean wasInMotion; + public boolean isFalling; + public boolean wasFalling; + public boolean isOnGround; + public boolean wasOnGround; + public boolean isSliding; + public boolean wasSliding; + + public float fallDistance; + public float lastYPosition; + public float currentFallDistance; + + public final Ray slidingPlaneNormal = new Ray(Vector3.Zero, Vector3.Zero); + public final Vector3 nearestIntersection = new Vector3(); + + public PhysicsComponent setMovementProperties(float walkingAcceleration, float maxWalkSpeed, float friction) { + this.walkingAcceleration = walkingAcceleration; + this.maxWalkSpeed = maxWalkSpeed; + this.friction = friction; + return this; + } + + public PhysicsComponent setBoundsRadius(float radius) { + sweptSphere.setRadius(radius); + return this; + } + + @Override + public void reset() { + velocity.set(Vector3.Zero); + lastTickVelocity.set(Vector3.Zero); + currentTickVelocity.set(Vector3.Zero); + walkingVelocity.set(Vector3.Zero); + walkingAcceleration = 0.0f; + maxWalkSpeed = 0.0f; + friction = 0.0f; + for (int i = 0; i < forces.size; ++i) + Pools.free(forces.get(i)); + forces.clear(); + forceVelocity.set(Vector3.Zero); + sweptSphere.reset(); + collisionTilePosition.set(0, 0, 0); + standingOnTilePosition.set(0, 0, 0); + standingOnTile = null; + isWalking = false; + wasWalking = false; + isInMotion = false; + wasInMotion = false; + isFalling = false; + wasFalling = false; + isOnGround = false; + wasOnGround = false; + isSliding = false; + wasSliding = false; + fallDistance = 0.0f; + lastYPosition = 0.0f; + currentFallDistance = 0.0f; + slidingPlaneNormal.origin.set(Vector3.Zero); + slidingPlaneNormal.direction.set(Vector3.Zero); + nearestIntersection.set(Vector3.Zero); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PositionComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PositionComponent.java new file mode 100644 index 0000000..03c168f --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/physics/PositionComponent.java @@ -0,0 +1,15 @@ +package ca.blarg.tiles3.basicexample.entities.components.physics; + +import com.badlogic.gdx.math.Vector3; +import ca.blarg.gdx.entities.Component; + +public class PositionComponent extends Component { + public final Vector3 position = new Vector3(); + public final Vector3 lastPosition = new Vector3(); + + @Override + public void reset() { + position.set(Vector3.Zero); + lastPosition.set(Vector3.Zero); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AnimationComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AnimationComponent.java new file mode 100644 index 0000000..8267d45 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AnimationComponent.java @@ -0,0 +1,84 @@ +package ca.blarg.tiles3.basicexample.entities.components.rendering; + +import ca.blarg.gdx.entities.Component; +import ca.blarg.tiles3.basicexample.entities.AnimationSequence; +import ca.blarg.tiles3.basicexample.entities.AnimationSequenceCollection; + +public class AnimationComponent extends Component { + public final AnimationSequenceCollection sequences = new AnimationSequenceCollection(); + public int currentFrame; + public int nextFrame; + public float frameTime; + public float interpolation; + public boolean isLooping; + public boolean currentSequenceUnoverrideable; + public boolean hasAnimationFinishEventBeenTriggered; + public String currentSequenceName; + public final AnimationSequence currentSequence = new AnimationSequence(); + + public boolean isAnimating() { + return (currentSequence.start != currentSequence.stop); + } + + public boolean isAnimationFinished() { + // let the last frame of a non-looping animation (even a 1-frame + // "animation") stay visible for at least the sequence's delay time as long + // as it's non-zero + if (!isLooping && currentFrame == currentSequence.stop && currentSequence.delay > 0.0f) { + if (frameTime < currentSequence.delay) + return false; // still working through the last frame time + else + return true; + + } + + return (isAnimating() && !isLooping && currentFrame == currentSequence.stop); + } + + public AnimationComponent setSequence(String name, boolean loop, boolean cannotBeOverridden) { + AnimationSequence sequence = sequences.get(name); + if (sequence == null) + return this; + + currentSequence.set(sequence); + currentSequenceName = name; + + currentFrame = currentSequence.start; + nextFrame = currentFrame + 1; + if (nextFrame > currentSequence.stop) + nextFrame = currentSequence.stop; + + frameTime = 0.0f; + interpolation = 0.0f; + isLooping = loop; + currentSequenceUnoverrideable = cannotBeOverridden; + hasAnimationFinishEventBeenTriggered = false; + return this; + } + + public AnimationComponent stopSequence() { + currentSequence.reset(); + currentFrame = 0; + nextFrame = 0; + frameTime = 0.0f; + interpolation = 0.0f; + isLooping = false; + currentSequenceUnoverrideable = false; + hasAnimationFinishEventBeenTriggered = false; + return this; + } + + @Override + public void reset() { + sequences.reset(); + currentFrame = 0; + nextFrame = 0; + frameTime = 0.0f; + interpolation = 0.0f; + isLooping = false; + currentSequenceUnoverrideable = false; + hasAnimationFinishEventBeenTriggered = false; + currentSequenceName = null; + currentSequence.reset(); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AutoAnimationComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AutoAnimationComponent.java new file mode 100644 index 0000000..7e7c516 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/AutoAnimationComponent.java @@ -0,0 +1,29 @@ +package ca.blarg.tiles3.basicexample.entities.components.rendering; + +import com.badlogic.gdx.utils.ObjectMap; +import ca.blarg.gdx.entities.Component; +import ca.blarg.tiles3.basicexample.entities.EntityState; + +public class AutoAnimationComponent extends Component { + public class AutoAnimationSequenceProperties { + public String name; + public boolean loop; + public boolean cannotBeOverridden; + } + + public final ObjectMap mappings = new ObjectMap(); + + public AutoAnimationComponent set(EntityState state, String name, boolean loop, boolean cannotBeOverridden) { + AutoAnimationSequenceProperties props = new AutoAnimationSequenceProperties(); + props.name = name; + props.loop = loop; + props.cannotBeOverridden = cannotBeOverridden; + mappings.put(state, props); + return this; + } + + @Override + public void reset() { + mappings.clear(); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/BillboardComponent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/BillboardComponent.java new file mode 100644 index 0000000..67ba511 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/components/rendering/BillboardComponent.java @@ -0,0 +1,43 @@ +package ca.blarg.tiles3.basicexample.entities.components.rendering; + +import com.badlogic.gdx.graphics.Texture; +import ca.blarg.gdx.entities.Component; +import ca.blarg.gdx.graphics.atlas.TextureAtlas; + +public class BillboardComponent extends Component { + public int tileIndex; + public float width; + public float height; + public boolean isAxisAligned; + public Texture texture; + public TextureAtlas atlas; + + public BillboardComponent set(float width, float height, Texture texture, boolean isAxisAligned) { + this.width = width; + this.height = height; + this.texture = texture; + this.isAxisAligned = isAxisAligned; + this.atlas = null; + return this; + } + + public BillboardComponent set(float width, float height, TextureAtlas atlas, int tileIndex, boolean isAxisAligned) { + this.width = width; + this.height = height; + this.atlas = atlas; + this.tileIndex = tileIndex; + this.isAxisAligned = isAxisAligned; + this.texture = null; + return this; + } + + @Override + public void reset() { + tileIndex = 0; + width = 0.0f; + height = 0.0f; + isAxisAligned = false; + texture = null; + atlas = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationChangeEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationChangeEvent.java new file mode 100644 index 0000000..a0e2da2 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationChangeEvent.java @@ -0,0 +1,24 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; +import ca.blarg.tiles3.basicexample.entities.EntityState; + +public class AnimationChangeEvent extends Event { + public Entity entity; + public String sequenceName; + public boolean changeToSequenceForState; + public EntityState state; + public boolean loop; + public boolean overrideExisting; + + @Override + public void reset() { + entity = null; + sequenceName = null; + changeToSequenceForState = false; + state = EntityState.None; + loop = false; + overrideExisting = false; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationFinishedEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationFinishedEvent.java new file mode 100644 index 0000000..50c733b --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/AnimationFinishedEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class AnimationFinishedEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/DespawnedEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/DespawnedEvent.java new file mode 100644 index 0000000..c7e303f --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/DespawnedEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class DespawnedEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityExitingTempStateEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityExitingTempStateEvent.java new file mode 100644 index 0000000..df7f880 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityExitingTempStateEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class EntityExitingTempStateEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityInTempStateEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityInTempStateEvent.java new file mode 100644 index 0000000..a2ec3a2 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityInTempStateEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class EntityInTempStateEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityStateChangeEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityStateChangeEvent.java new file mode 100644 index 0000000..c42b22f --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/EntityStateChangeEvent.java @@ -0,0 +1,20 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; +import ca.blarg.tiles3.basicexample.entities.EntityState; + +public class EntityStateChangeEvent extends Event { + public Entity entity; + public EntityState state; + public boolean isActionState; + public boolean clearExistingActionStateInfo; + + @Override + public void reset() { + entity = null; + state = EntityState.None; + isActionState = false; + clearExistingActionStateInfo = false; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/JumpEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/JumpEvent.java new file mode 100644 index 0000000..00616b8 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/JumpEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class JumpEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveAndTurnEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveAndTurnEvent.java new file mode 100644 index 0000000..b36432b --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveAndTurnEvent.java @@ -0,0 +1,15 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class MoveAndTurnEvent extends Event { + public Entity entity; + public float angle; + + @Override + public void reset() { + entity = null; + angle = 0.0f; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveForwardEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveForwardEvent.java new file mode 100644 index 0000000..bbe3082 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveForwardEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class MoveForwardEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveInDirectionEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveInDirectionEvent.java new file mode 100644 index 0000000..317d9fb --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/MoveInDirectionEvent.java @@ -0,0 +1,16 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import com.badlogic.gdx.math.Vector3; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class MoveInDirectionEvent extends Event { + public Entity entity; + public final Vector3 direction = new Vector3(); + + @Override + public void reset() { + entity = null; + direction.set(Vector3.Zero); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/SpawnedEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/SpawnedEvent.java new file mode 100644 index 0000000..755013e --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/SpawnedEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class SpawnedEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/StopMovementEvent.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/StopMovementEvent.java new file mode 100644 index 0000000..2ada7e9 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/events/StopMovementEvent.java @@ -0,0 +1,13 @@ +package ca.blarg.tiles3.basicexample.entities.events; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.events.Event; + +public class StopMovementEvent extends Event { + public Entity entity; + + @Override + public void reset() { + entity = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/Force.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/Force.java new file mode 100644 index 0000000..0a28555 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/Force.java @@ -0,0 +1,87 @@ +package ca.blarg.tiles3.basicexample.entities.forces; + +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.utils.Pool; +import ca.blarg.gdx.math.MathHelpers; + +public class Force implements Pool.Poolable { + boolean active; + final Vector3 direction = new Vector3(); + float strength; + float friction; + final Vector3 currentForce = new Vector3(); + float duration; + float minDuration; + float zeroTolerance = MathHelpers.EPSILON; + + final Vector3 tempCurrentForce = new Vector3(); + + public Force set(Vector3 direction, float strength, float friction) { + active = true; + this.direction.set(direction); + this.strength = strength; + this.friction = friction; + currentForce.set(Vector3.Zero); + duration = 0.0f; + minDuration = 0.0f; + return this; + } + + public Force setMinimumDuration(float minDuration) { + this.minDuration = minDuration; + return this; + } + + public Force setZeroTolerance(float tolerance) { + this.zeroTolerance = tolerance; + return this; + } + + public boolean isActive() { + return active; + } + + public boolean isZeroStrength() { + return MathHelpers.areAlmostEqual(strength, 0.0f, zeroTolerance); + } + + public boolean hasMinDurationPassed() { + return duration >= minDuration; + } + + public Vector3 getCurrentForce() { + tempCurrentForce.set(currentForce); + return tempCurrentForce; + } + + public void kill() { + active = false; + currentForce.set(Vector3.Zero); + } + + public void update(float delta) { + if (!active) + return; + + if (isZeroStrength()) { + kill(); + return; + } + + duration += delta; + currentForce.set(direction).scl(strength); + strength *= friction; + } + + @Override + public void reset() { + active = false; + direction.set(Vector3.Zero); + strength = 0.0f; + friction = 0.0f; + currentForce.set(Vector3.Zero); + duration = 0.0f; + minDuration = 0.0f; + zeroTolerance = MathHelpers.EPSILON; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/JumpForce.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/JumpForce.java new file mode 100644 index 0000000..4d9dbfb --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/forces/JumpForce.java @@ -0,0 +1,72 @@ +package ca.blarg.tiles3.basicexample.entities.forces; + +import ca.blarg.gdx.GameLooper; +import ca.blarg.gdx.Services; +import ca.blarg.gdx.math.MathHelpers; +import ca.blarg.tiles3.basicexample.entities.PhysicsConstants; +import ca.blarg.tiles3.basicexample.entities.components.physics.PhysicsComponent; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector3; + +public class JumpForce extends Force { + PhysicsComponent physicsComponent; + + public Force set(Vector3 direction, float strength, float friction, PhysicsComponent physicsComponent) { + // we will almost certainly want a jump to last beyond 1 update tick + float tickFrequency = Services.get(GameLooper.class).getUpdateFrequency(); + float minimumDuration = tickFrequency + 0.01f; + + super.set(direction, strength, friction) + .setMinimumDuration(minimumDuration) + .setZeroTolerance(PhysicsConstants.ON_GROUND_ZERO_TOLERANCE); + this.physicsComponent = physicsComponent; + return this; + } + + @Override + public void update(float delta) { + super.update(delta); + + // Force.update() call could potentially kill this force and then return + // here, so we should check for that first + if (!isActive()) + return; + + boolean cancelled = false; + + // jumping should be cancelled when the top of the entity hits a surface + // that is more or less perpendicular to the jumping direction (positive Y). + // it should also be stopped if the entity has landed on some ground early + // along in the jump (e.g. they jumped up to a ledge) + if (physicsComponent.sweptSphere.foundCollision || physicsComponent.isSliding) { + if (physicsComponent.isSliding || physicsComponent.slidingPlaneNormal.direction.y > 0.0f) { + // if we're sliding, then check the angle + float slideYAngle = (float)Math.acos(physicsComponent.sweptSphere.slidingPlaneNormal.dot(Vector3.Y)) * MathUtils.radiansToDegrees; + + // Y axis angle's from 135 to 225 means we hit something overhead. + // 180 degrees = hit something perfectly perpendicular to the Y axis + // HACK: also we check for a Y angle of zero as that will handle an + // edge case where the entity jumped and immediately overhead there + // is an obstacle (in this case, most of the time, the slide Y angle + // is actually for the collision below their feet...) + if ((slideYAngle > 135.0f && slideYAngle < 225.0f) || MathHelpers.areAlmostEqual(slideYAngle, 0.0f)) + cancelled = true; + } else + // not sliding, just a full-on collision with something + // (collision but not sliding means it's usually a flat area of the + // ground), so this is really IsOnGround() == TRUE (??) + cancelled = true; + } + + // don't kill it, even if there was a collision found above, if the force + // hasn't been running for the minimum duration yet + if (cancelled && hasMinDurationPassed()) + kill(); + } + + @Override + public void reset() { + super.reset(); + physicsComponent = null; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/BaseObjectEntityPreset.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/BaseObjectEntityPreset.java new file mode 100644 index 0000000..b812605 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/BaseObjectEntityPreset.java @@ -0,0 +1,52 @@ +package ca.blarg.tiles3.basicexample.entities.presets; + +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.entities.EntityPreset; +import ca.blarg.gdx.events.Event; +import ca.blarg.gdx.events.EventListener; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.tiles3.basicexample.entities.events.DespawnedEvent; +import ca.blarg.tiles3.basicexample.entities.events.SpawnedEvent; +import com.badlogic.gdx.utils.Disposable; + +public abstract class BaseObjectEntityPreset extends EntityPreset implements EventListener, Disposable { + public final EventManager eventManager; + + public BaseObjectEntityPreset(EntityManager entityManager) { + super(entityManager); + eventManager = entityManager.eventManager; + + eventManager.addListener(SpawnedEvent.class, this); + eventManager.addListener(DespawnedEvent.class, this); + } + + @Override + public void dispose() { + eventManager.removeListener(SpawnedEvent.class, this); + eventManager.removeListener(DespawnedEvent.class, this); + } + + public void onSpawn(Entity entity) { + } + + public void onDespawn(Entity entity) { + } + + @Override + public boolean handle(Event e) { + if (e instanceof SpawnedEvent) { + SpawnedEvent event = (SpawnedEvent)e; + if (event.entity.getPresetUsedToCreate() == this.getClass()) + onSpawn(event.entity); + } + + else if (e instanceof DespawnedEvent) { + DespawnedEvent event = (DespawnedEvent)e; + if (event.entity.getPresetUsedToCreate() == this.getClass()) + onDespawn(event.entity); + } + + return false; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/PlayerPreset.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/PlayerPreset.java new file mode 100644 index 0000000..ed6e0b8 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/presets/PlayerPreset.java @@ -0,0 +1,65 @@ +package ca.blarg.tiles3.basicexample.entities.presets; + +import ca.blarg.gdx.Services; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.tiles3.basicexample.ContentCache; +import ca.blarg.tiles3.basicexample.entities.EntityState; +import ca.blarg.tiles3.basicexample.entities.PhysicsConstants; +import ca.blarg.tiles3.basicexample.entities.components.CameraComponent; +import ca.blarg.tiles3.basicexample.entities.components.PlayerComponent; +import ca.blarg.tiles3.basicexample.entities.components.StateComponent; +import ca.blarg.tiles3.basicexample.entities.components.physics.*; +import ca.blarg.tiles3.basicexample.entities.components.rendering.*; + +public class PlayerPreset extends BaseObjectEntityPreset { + public PlayerPreset(EntityManager entityManager) { + super(entityManager); + } + + @Override + public Entity create(CreationArgs args) { + ContentCache content = Services.get(ContentCache.class); + + Entity entity = entityManager.add(); + entity.add(BoundingSphereComponent.class).bounds.radius = 0.5f; + entity.add(StateComponent.class).state = EntityState.Idle; + entity.add(PlayerComponent.class); + + CameraComponent camera = entity.add(CameraComponent.class); + camera.useEntityOrientation = false; + + BillboardComponent billboard = entity.add(BillboardComponent.class); + billboard.isAxisAligned = true; + billboard.atlas = content.player; + billboard.width = 1.7f; + billboard.height = 1.7f; + + AnimationComponent animations = entity.add(AnimationComponent.class); + animations.sequences.add("idle").set(0, 0, 0.0f, true, 0); + animations.sequences.add("walk").set(8, 9, 0.15f, true, 0); + animations.sequences.add("dead").set(32, 32, 0.0f); + animations.sequences.add("jump").set(8, 8, 0.0f, true, 1); + animations.sequences.add("fall").set(9, 9, 0.0f, true, 1); + animations.setSequence("idle", true, false); + + AutoAnimationComponent autoAnimation = entity.add(AutoAnimationComponent.class); + autoAnimation.set(EntityState.Idle, "idle", true, false) + .set(EntityState.Walking, "walk", true, false) + .set(EntityState.Falling, "fall", true, false) + .set(EntityState.Jumping, "jump", true, false) + .set(EntityState.Dead, "dead", false, true); + + entity.add(PhysicsComponent.class) + .setMovementProperties(1.0f, 8.0f, PhysicsConstants.FRICTION_NORMAL) + .setBoundsRadius(0.49f); + + PositionComponent position = entity.add(PositionComponent.class); + position.position.set(16.0f, 1.5f, 16.0f); + position.lastPosition.set(position.position); + + entity.add(OrientationXZComponent.class); + + return entity; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/AnimationSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/AnimationSystem.java new file mode 100644 index 0000000..7810d0f --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/AnimationSystem.java @@ -0,0 +1,175 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.math.Vector3; +import ca.blarg.gdx.Services; +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.Event; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.gdx.graphics.ViewportContext; +import ca.blarg.gdx.math.MathHelpers; +import ca.blarg.tiles3.basicexample.entities.FacingDirection; +import ca.blarg.tiles3.basicexample.entities.components.physics.OrientationXZComponent; +import ca.blarg.tiles3.basicexample.entities.components.rendering.AnimationComponent; +import ca.blarg.tiles3.basicexample.entities.components.rendering.AutoAnimationComponent; +import ca.blarg.tiles3.basicexample.entities.components.rendering.BillboardComponent; +import ca.blarg.tiles3.basicexample.entities.events.AnimationChangeEvent; +import ca.blarg.tiles3.basicexample.entities.events.AnimationFinishedEvent; + +public class AnimationSystem extends ComponentSystem { + final ViewportContext viewportContext; + + public AnimationSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + viewportContext = Services.get(ViewportContext.class); + + listenFor(AnimationChangeEvent.class); + } + + @Override + public void dispose() { + stopListeningFor(AnimationChangeEvent.class); + } + + @Override + public void onUpdateFrame(float delta) { + updateAnimationSequences(delta); + updateEntityRenderFrames(); + } + + @Override + public boolean handle(Event e) { + if (e instanceof AnimationChangeEvent) + return handle((AnimationChangeEvent)e); + + return false; + } + + private void updateAnimationSequences(float delta) { + for (Entity entity : entityManager.getAllWith(AnimationComponent.class)) { + AnimationComponent animation = entity.get(AnimationComponent.class); + + // only update active animation sequences + if (!animation.isAnimationFinished()) { + animation.frameTime += delta; + animation.interpolation += delta / animation.currentSequence.delay; + + if (animation.frameTime >= animation.currentSequence.delay) { + // move to the next frame + animation.frameTime = 0.0f; + animation.interpolation = 0.0f; + + ++animation.currentFrame; + if (animation.currentFrame > animation.currentSequence.stop) { + animation.currentFrame = animation.currentSequence.start; + if (!animation.isLooping) { + animation.currentSequence.start = animation.currentSequence.stop; + animation.currentFrame = animation.currentSequence.stop; + animation.nextFrame = animation.currentFrame; + animation.frameTime = animation.currentSequence.delay; + + continue; + } + } + + ++animation.nextFrame; + if (animation.nextFrame > animation.currentSequence.stop) { + if (!animation.isLooping) + animation.nextFrame = animation.currentSequence.stop; + else + animation.nextFrame = animation.currentSequence.start; + } + } + } else { + // animation has finished (it is not looping and has reached the end) + if (!animation.hasAnimationFinishEventBeenTriggered) { + // and we haven't yet raised an event to signal this + AnimationFinishedEvent finishedEvent = eventManager.create(AnimationFinishedEvent.class); + finishedEvent.entity = entity; + eventManager.trigger(finishedEvent); + + animation.hasAnimationFinishEventBeenTriggered = true; + } + } + } + } + + private void updateEntityRenderFrames() { + // update texture atlas frame indexes for tile-animation components with + // multi-directional animations based on the current camera orientation + for (Entity entity : entityManager.getAllWith(AnimationComponent.class)) { + AnimationComponent animation = entity.get(AnimationComponent.class); + BillboardComponent billboard = entity.get(BillboardComponent.class); + if (billboard != null) { + OrientationXZComponent orientation = entity.get(OrientationXZComponent.class); + updateBillboardFrame(billboard, animation, orientation, viewportContext.getPerspectiveCamera()); + } else + throw new UnsupportedOperationException("Unsupported animation method."); + } + } + + private boolean handle(AnimationChangeEvent e) { + if (e.changeToSequenceForState) { + // event is for an animation change to a sequence based on an entity + // state provided in the event info. requires an AutoAnimationComponent + AutoAnimationComponent autoAnimation = e.entity.get(AutoAnimationComponent.class); + if (autoAnimation != null) { + // if the entity's auto animation info has a sequence defined for + // the state specified in the event, then switch to that sequence + AutoAnimationComponent.AutoAnimationSequenceProperties sequenceProps = autoAnimation.mappings.get(e.state); + if (sequenceProps != null) { + AnimationComponent animation = e.entity.get(AnimationComponent.class); + + if (!animation.currentSequenceUnoverrideable || + animation.isAnimationFinished() || + e.overrideExisting) + animation.setSequence( + sequenceProps.name, + sequenceProps.loop, + sequenceProps.cannotBeOverridden + ); + } + } + } else { + // we're just changing to a named animation sequence directly + AnimationComponent animation = e.entity.get(AnimationComponent.class); + animation.setSequence(e.sequenceName, true, false); + } + + return false; + } + + static final Vector3 cameraPos = new Vector3(); + static final Vector3 cameraTarget = new Vector3(); + private void updateBillboardFrame(BillboardComponent billboard, AnimationComponent animation, OrientationXZComponent orientation, Camera camera) { + if (billboard.atlas == null) + return; + + if (orientation != null && animation.currentSequence.isMultiDirectional) { + // get the direction to point the entity in based on it's own facing + // direction and the direction the camera is pointed in + cameraPos.set(camera.position); + cameraTarget.set(camera.position) + .add(camera.direction); + float yaw = MathHelpers.getYAngleBetween(cameraTarget, cameraPos); + int direction = FacingDirection.getFacingDirectionAdjustedForCamera(orientation.angle, yaw, !animation.currentSequence.hasDiagonalDirections).value(); + + // +1 because sequences will be specified using start/stop frames that + // are a part of the sequence. e.g. for a 2 frame sequence using frames + // 10 and 11, you would specify start=10 and stop=11, so without +1, the + // below calc would find the length of this sequence to be 1 which is + // not correct... + int sequenceLength = animation.currentSequence.stop - animation.currentSequence.start + 1; + + // offset between frames for different directions + int offset = direction * animation.currentSequence.directionFrameOffset; + + // set the frame index + billboard.tileIndex = animation.currentFrame + (sequenceLength * direction) + offset; + } else { + billboard.tileIndex = animation.currentFrame; + } + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BillboardRenderSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BillboardRenderSystem.java new file mode 100644 index 0000000..adfc9a6 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BillboardRenderSystem.java @@ -0,0 +1,78 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.gdx.Services; +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.gdx.graphics.BillboardSpriteBatch; +import ca.blarg.gdx.graphics.ViewportContext; +import ca.blarg.tiles3.basicexample.entities.EntityUtils; +import ca.blarg.tiles3.basicexample.entities.components.physics.BoundingSphereComponent; +import ca.blarg.tiles3.basicexample.entities.components.physics.PositionComponent; +import ca.blarg.tiles3.basicexample.entities.components.rendering.BillboardComponent; +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.math.Frustum; +import com.badlogic.gdx.math.Vector3; + +public class BillboardRenderSystem extends ComponentSystem { + private static final float Y_COORD_OFFSET = -1.0f; + private final Vector3 renderPosition = new Vector3(); + + final ViewportContext viewportContext; + final BillboardSpriteBatch billboardSpriteBatch; + + public BillboardRenderSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + viewportContext = Services.get(ViewportContext.class); + billboardSpriteBatch = Services.get(BillboardSpriteBatch.class); + } + + @Override + public void onRender(float interpolation) { + Camera camera = viewportContext.getPerspectiveCamera(); + Frustum frustum = camera.frustum; + + billboardSpriteBatch.begin(camera); + + for (Entity entity : entityManager.getAllWith(BillboardComponent.class)) { + BillboardComponent billboard = entity.get(BillboardComponent.class); + PositionComponent position = entity.get(PositionComponent.class); + BoundingSphereComponent bounds = entity.get(BoundingSphereComponent.class); + + if (bounds != null) { + if (!frustum.sphereInFrustum(bounds.bounds.center, bounds.bounds.radius)) + continue; + } else { + if (!frustum.pointInFrustum(position.lastPosition)) + continue; + } + + EntityUtils.getInterpolatedPosition(entity, interpolation, renderPosition); + + BillboardSpriteBatch.Type billboardType = + (billboard.isAxisAligned ? BillboardSpriteBatch.Type.ScreenAligned : + BillboardSpriteBatch.Type.Spherical); + + float difference = (billboard.height / 2.0f) + Y_COORD_OFFSET; + if (difference > 0.0f) + renderPosition.y += difference; + renderPosition.x += 0.35f; + + if (billboard.texture != null) + billboardSpriteBatch.draw( + billboardType, billboard.texture, + renderPosition.x, renderPosition.y, renderPosition.z, + billboard.width, billboard.height + ); + else + billboardSpriteBatch.draw( + billboardType, billboard.atlas.get(billboard.tileIndex), + renderPosition.x, renderPosition.y, renderPosition.z, + billboard.width, billboard.height + ); + } + + billboardSpriteBatch.end(); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BoundingVolumeWorldPositioningSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BoundingVolumeWorldPositioningSystem.java new file mode 100644 index 0000000..4b75586 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/BoundingVolumeWorldPositioningSystem.java @@ -0,0 +1,24 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.tiles3.basicexample.entities.components.physics.BoundingSphereComponent; +import ca.blarg.tiles3.basicexample.entities.components.physics.PositionComponent; + +public class BoundingVolumeWorldPositioningSystem extends ComponentSystem { + public BoundingVolumeWorldPositioningSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + } + + @Override + public void onUpdateGameState(float delta) { + for (Entity entity : entityManager.getAllWith(BoundingSphereComponent.class)) { + BoundingSphereComponent bounds = entity.get(BoundingSphereComponent.class); + PositionComponent position = entity.get(PositionComponent.class); + + bounds.bounds.center.set(position.position); + } + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/CameraSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/CameraSystem.java new file mode 100644 index 0000000..126a98e --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/CameraSystem.java @@ -0,0 +1,68 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.gdx.Services; +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.gdx.graphics.EulerPerspectiveCamera; +import ca.blarg.gdx.graphics.ViewportContext; +import ca.blarg.gdx.math.MathHelpers; +import ca.blarg.tiles3.basicexample.entities.EntityUtils; +import ca.blarg.tiles3.basicexample.entities.components.CameraComponent; +import ca.blarg.tiles3.basicexample.entities.components.physics.OrientationXZComponent; +import com.badlogic.gdx.math.Vector3; + +public class CameraSystem extends ComponentSystem { + static final float FOLLOW_DISTANCE = 3.5f; + static final float FOLLOW_HEIGHT = 9.0f; + static final float FOLLOW_PITCH_ANGLE = 70.0f; + + final static Vector3 targetEntityDirection = new Vector3(); + final static Vector3 targetEntityPosition = new Vector3(); + final static Vector3 tmp = new Vector3(); + + final ViewportContext viewportContext; + + public CameraSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + viewportContext = Services.get(ViewportContext.class); + } + + @Override + public void dispose() { + } + + @Override + public void onRender(float interpolation) { + Entity target = entityManager.getFirstWith(CameraComponent.class); + if (target == null) + return; + + CameraComponent cameraProperties = target.get(CameraComponent.class); + + float yAngle; + if (cameraProperties.useEntityOrientation) + yAngle = target.get(OrientationXZComponent.class).angle; + else + yAngle = cameraProperties.yAngle; + + EulerPerspectiveCamera camera = (EulerPerspectiveCamera)viewportContext.getPerspectiveCamera(); + + MathHelpers.getDirectionVector3FromYAxis(yAngle, targetEntityDirection); + EntityUtils.getInterpolatedPosition(target, interpolation, targetEntityPosition); + + // get the new camera position + tmp.set(targetEntityDirection) // behind the direction the player is currently facing + .scl(-1.0f); + MathHelpers.setLengthOf(tmp, FOLLOW_DISTANCE); // FOLLOW_DISTANCE units behind ... + tmp.add(0.0f, FOLLOW_HEIGHT, 0.0f) // ... and FOLLOW_HEIGHT units up ... + .add(targetEntityPosition); // ... from the player's position + + camera.position.set(tmp); + float angle = MathHelpers.getYAngleBetween(targetEntityPosition, tmp) - 90.0f; + camera.turnTo(angle); + camera.pitchTo(FOLLOW_PITCH_ANGLE); + camera.update(); + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/EntityStateSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/EntityStateSystem.java new file mode 100644 index 0000000..42dcf99 --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/EntityStateSystem.java @@ -0,0 +1,162 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.entities.systemcomponents.InactiveComponent; +import ca.blarg.gdx.events.Event; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.tiles3.basicexample.entities.events.*; +import ca.blarg.tiles3.basicexample.entities.EntityState; +import ca.blarg.tiles3.basicexample.entities.components.StateComponent; + +public class EntityStateSystem extends ComponentSystem { + public EntityStateSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + listenFor(EntityStateChangeEvent.class); + listenFor(EntityExitingTempStateEvent.class); + listenFor(AnimationFinishedEvent.class); + listenFor(DespawnedEvent.class); + } + + @Override + public void dispose() { + stopListeningFor(EntityStateChangeEvent.class); + stopListeningFor(EntityExitingTempStateEvent.class); + stopListeningFor(AnimationFinishedEvent.class); + stopListeningFor(DespawnedEvent.class); + } + + @Override + public boolean handle(Event e) { + if (e instanceof EntityStateChangeEvent) + return handle((EntityStateChangeEvent)e); + + else if (e instanceof EntityExitingTempStateEvent) + return handle((EntityExitingTempStateEvent)e); + + else if (e instanceof AnimationFinishedEvent) + return handle((AnimationFinishedEvent)e); + + else if (e instanceof DespawnedEvent) + return handle((DespawnedEvent)e); + + return false; + } + + private boolean handle(EntityStateChangeEvent e) + { + StateComponent state = e.entity.get(StateComponent.class); + if (state != null) { + if (e.isActionState) { + // set action state first + state.actionState = e.state; + state.isInActionState = true; + + // HACK: this was mainly added to prevent the death animation from + // playing twice in a row in a somewhat rare scenario. however + // this does seem to be a sensible check regardless ... + boolean needToChangeAnimation = state.state != state.actionState; + + // trigger state change event + EntityInTempStateEvent actionStateEvent = eventManager.create(EntityInTempStateEvent.class); + actionStateEvent.entity = e.entity; + eventManager.trigger(actionStateEvent); + + if (needToChangeAnimation) { + // trigger animation change + AnimationChangeEvent animationChangeEvent = eventManager.create(AnimationChangeEvent.class); + animationChangeEvent.entity = e.entity; + animationChangeEvent.changeToSequenceForState = true; + animationChangeEvent.state = e.state; + eventManager.trigger(animationChangeEvent); + } + } else { + // HACK: this will (hopefully?) stop entity's from doing there + // death animation and then popping up to idle before + // despawning. need to verify (very hard to reproduce!) + if (state.state == EntityState.Dead && e.state == EntityState.Idle) + return false; + + // HACK: this was mainly added to prevent the death animation from + // playing twice in a row in a somewhat rare scenario. however + // this does seem to be a sensible check regardless ... + boolean needToChangeAnimation = state.state != state.actionState; + + // set non-action state + state.state = e.state; + + if (e.clearExistingActionStateInfo) { + state.actionState = EntityState.None; + state.isInActionState = false; + } + + if (needToChangeAnimation) { + // trigger animation change + AnimationChangeEvent animationChangeEvent = eventManager.create(AnimationChangeEvent.class); + animationChangeEvent.entity = e.entity; + animationChangeEvent.changeToSequenceForState = true; + animationChangeEvent.state = e.state; + + // HACK: this ensures that the death animation will play + animationChangeEvent.overrideExisting = e.state == EntityState.Dead; + + eventManager.trigger(animationChangeEvent); + } + } + } + + return false; + } + + private boolean handle(EntityExitingTempStateEvent e) { + StateComponent state = e.entity.get(StateComponent.class); + if (state != null) { + // HACK: this will (hopefully?) stop entity's from doing their + // death animation and then popping up to idle before + // despawning. need to verify (very hard to reproduce!) + if (state.state == EntityState.Dead) + return false; + + // HACK: this was mainly added to prevent the death animation from + // playing twice in a row in a somewhat rare scenario. however + // this does seem to be a sensible check regardless ... + boolean needToChangeAnimation = state.state != state.actionState; + + // clear action state info + state.isInActionState = false; + state.actionState = EntityState.None; + + if (needToChangeAnimation) { + // trigger animation change + AnimationChangeEvent animationChangeEvent = eventManager.create(AnimationChangeEvent.class); + animationChangeEvent.entity = e.entity; + animationChangeEvent.changeToSequenceForState = true; + animationChangeEvent.state = state.state; + eventManager.trigger(animationChangeEvent); + } + } + + return false; + } + + private boolean handle(AnimationFinishedEvent e) { + StateComponent state = e.entity.get(StateComponent.class); + + // TODO: this all assumes that an AnimationFinishedEvent triggered for + // an entity with a StateComponent marked as "in action state" + // should *always* trigger an EntityExitingTempStateEvent. Maybe + // this should be set up some other way with less assumptions? + if (state != null && state.isInActionState) { + EntityExitingTempStateEvent exitingTempStateEvent = eventManager.create(EntityExitingTempStateEvent.class); + exitingTempStateEvent.entity = e.entity; + eventManager.trigger(exitingTempStateEvent); + } + + return false; + } + + private boolean handle(DespawnedEvent e) { + e.entity.add(InactiveComponent.class); + return false; + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PhysicsSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PhysicsSystem.java new file mode 100644 index 0000000..58e1bbb --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PhysicsSystem.java @@ -0,0 +1,378 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.Event; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.gdx.math.MathHelpers; +import ca.blarg.gdx.math.SweptSphereHandler; +import ca.blarg.gdx.tilemap3d.TileMapSweptSphereCollisionChecker; +import ca.blarg.tiles3.basicexample.entities.EntityState; +import ca.blarg.tiles3.basicexample.entities.PhysicsConstants; +import ca.blarg.tiles3.basicexample.entities.components.WorldComponent; +import ca.blarg.tiles3.basicexample.entities.components.physics.*; +import ca.blarg.tiles3.basicexample.entities.events.*; +import ca.blarg.tiles3.basicexample.entities.forces.Force; +import ca.blarg.tiles3.basicexample.entities.forces.JumpForce; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.math.collision.Ray; +import com.badlogic.gdx.utils.Pools; + +public class PhysicsSystem extends ComponentSystem { + private class TerrainFrictionValues { + public float friction; + public float walkAcceleration; + public float maxWalkSpeed; + } + + final SweptSphereHandler sweptSphereHandler; + public final TileMapSweptSphereCollisionChecker sweptSphereWorldCollisionChecker; + + static final Vector3 tmp1 = new Vector3(); + final TerrainFrictionValues tmpTerrainFrictionValues = new TerrainFrictionValues(); + + public PhysicsSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + listenFor(MoveForwardEvent.class); + listenFor(MoveInDirectionEvent.class); + listenFor(MoveAndTurnEvent.class); + listenFor(StopMovementEvent.class); + listenFor(JumpEvent.class); + + sweptSphereWorldCollisionChecker = new TileMapSweptSphereCollisionChecker(); + sweptSphereHandler = new SweptSphereHandler(sweptSphereWorldCollisionChecker, 5); + sweptSphereHandler.possibleCollisionAreaMinOffset.set(0.0f, -0.5f, 0.0f); + sweptSphereHandler.possibleCollisionAreaMaxOffset.set(0.0f, 0.5f, 0.0f); + } + + @Override + public void dispose() { + stopListeningFor(MoveForwardEvent.class); + stopListeningFor(MoveInDirectionEvent.class); + stopListeningFor(MoveAndTurnEvent.class); + stopListeningFor(StopMovementEvent.class); + stopListeningFor(JumpEvent.class); + } + + static final Vector3 resultingVelocity = new Vector3(); + static final Vector3 gravityVelocity = new Vector3(); + @Override + public void onUpdateGameState(float delta) { + Entity worldEntity = entityManager.getFirstWith(WorldComponent.class); + if (worldEntity == null) + return; // no world to simulate physics for! + + WorldComponent world = worldEntity.get(WorldComponent.class); + sweptSphereWorldCollisionChecker.tileMap = world.tileMap; + + for (Entity entity : entityManager.getAllWith(PhysicsComponent.class)) { + PhysicsComponent physics = entity.get(PhysicsComponent.class); + PositionComponent position = entity.get(PositionComponent.class); + + // to accurately check if the entity is walking we need to check this first! + // walking only adds velocity in the XZ plane. forces can add velocity in any + // direction, so if we added them first, we couldn't just check XZ + updateIsWalkingState(physics); + + // apply forces. this directly affects velocity, so it needs to go next! + processForces(physics, delta); + + getTerrainFrictionFor(physics, tmpTerrainFrictionValues); + + // apply friction and then combine walking and force velocity's into one + // to get the entity's current velocity for this tick + physics.walkingVelocity.scl(tmpTerrainFrictionValues.friction); + + if (physics.walkingVelocity.len() <= 0.12f) + physics.walkingVelocity.set(Vector3.Zero); + if (physics.forceVelocity.len() <= 0.1f) + physics.forceVelocity.set(Vector3.Zero); + + physics.velocity.set(physics.walkingVelocity) + .add(physics.forceVelocity); + + // update last/current tick velocities + physics.lastTickVelocity.set(physics.currentTickVelocity); + physics.currentTickVelocity.set(physics.velocity) + .scl(delta); + + Vector3 gravity = gravityVelocity.set(PhysicsConstants.GRAVITY) + .scl(delta); + + physics.sweptSphere.position.set(position.position); + + resultingVelocity.set(Vector3.Zero); + sweptSphereHandler.handleMovement(physics.sweptSphere, + physics.currentTickVelocity, + gravity, + resultingVelocity, + true, + true, + PhysicsConstants.SLOPE_STEEP_Y_ANGLE); + + position.position.set(physics.sweptSphere.position); + physics.currentTickVelocity.set(resultingVelocity); + physics.collisionTilePosition.set(sweptSphereWorldCollisionChecker.lastCollisionTilePosition); + + physics.isInMotion = physics.sweptSphere.isInMotion; + physics.wasInMotion = physics.sweptSphere.wasInMotion; + physics.isFalling = physics.sweptSphere.isFalling; + physics.wasFalling = physics.sweptSphere.wasFalling; + physics.isSliding = physics.sweptSphere.isSliding; + physics.wasSliding = physics.sweptSphere.wasSliding; + physics.isOnGround = physics.sweptSphere.isOnGround; + physics.wasOnGround = physics.sweptSphere.wasOnGround; + + updateStandingTileCoords(physics, position, world); + + triggerStateChangeEvents(physics, entity); + } + } + + @Override + public boolean handle(Event e) { + if (e instanceof MoveInDirectionEvent) + return handle((MoveInDirectionEvent)e); + + else if (e instanceof MoveForwardEvent) + return handle((MoveForwardEvent)e); + + else if (e instanceof MoveAndTurnEvent) + return handle((MoveAndTurnEvent)e); + + else if (e instanceof StopMovementEvent) + return handle((StopMovementEvent)e); + + else if (e instanceof JumpEvent) + return handle((JumpEvent)e); + + return false; + } + + private boolean handle(MoveInDirectionEvent e) { + if (e.entity.has(PhysicsComponent.class)) { + move(e.entity, e.direction); + return true; + } else + return false; + } + + private boolean handle(MoveForwardEvent e) { + if (e.entity.has(PhysicsComponent.class)) { + OrientationXZComponent orientation = e.entity.get(OrientationXZComponent.class); + tmp1.set(Vector3.Zero); + MathHelpers.getDirectionVector3FromYAxis(orientation.angle, tmp1); + move(e.entity, tmp1); + return true; + } else + return false; + } + + private boolean handle(MoveAndTurnEvent e) { + if (e.entity.has(PhysicsComponent.class)) { + OrientationXZComponent orientation = e.entity.get(OrientationXZComponent.class); + orientation.angle = e.angle; + tmp1.set(Vector3.Zero); + MathHelpers.getDirectionVector3FromYAxis(orientation.angle, tmp1); + move(e.entity, tmp1); + return true; + } else + return false; + } + + private boolean handle(StopMovementEvent e) { + if (e.entity.has(PhysicsComponent.class)) { + stop(e.entity); + return true; + } else + return false; + } + + private boolean handle(JumpEvent e) { + if (e.entity.has(PhysicsComponent.class)) { + jump(e.entity); + return true; + } else + return false; + } + + private void triggerStateChangeEvents(PhysicsComponent physics, Entity entity) { + if (physics.isFalling && !physics.wasFalling) { + EntityStateChangeEvent event = eventManager.create(EntityStateChangeEvent.class); + event.state = EntityState.Falling; + event.entity = entity; + eventManager.trigger(event); + } else if (physics.wasFalling && physics.isWalking) { + EntityStateChangeEvent event = eventManager.create(EntityStateChangeEvent.class); + event.state = EntityState.Walking; + event.entity = entity; + eventManager.trigger(event); + } else if (physics.wasFalling && !physics.isFalling) { + EntityStateChangeEvent event = eventManager.create(EntityStateChangeEvent.class); + event.state = EntityState.Idle; + event.entity = entity; + eventManager.trigger(event); + } else if (physics.isWalking && !physics.wasWalking && !physics.isFalling) { + EntityStateChangeEvent event = eventManager.create(EntityStateChangeEvent.class); + event.state = EntityState.Walking; + event.entity = entity; + eventManager.trigger(event); + } else if (physics.wasWalking && !physics.isWalking) { + EntityStateChangeEvent event = eventManager.create(EntityStateChangeEvent.class); + event.state = EntityState.Idle; + event.entity = entity; + eventManager.trigger(event); + } + } + + static final Vector3 tmpMovementVelocity = new Vector3(); + private void move(Entity entity, Vector3 direction) { + PhysicsComponent physics = entity.get(PhysicsComponent.class); + + getTerrainFrictionFor(physics, tmpTerrainFrictionValues); + + float acceleration = tmpTerrainFrictionValues.walkAcceleration; + float maxSpeed = tmpTerrainFrictionValues.maxWalkSpeed; + + // currentVelocity = a * maxVelocity + (1 - a) * currentVelocity + + tmpMovementVelocity.set(direction).scl(maxSpeed) // maxVelocity + .scl(acceleration); // * a + + physics.walkingVelocity.scl(1 - acceleration) // (1 - a) * currentVelocity + .add(tmpMovementVelocity); // + (a * maxVelocity) + } + + private void stop(Entity entity) { + PhysicsComponent physics = entity.get(PhysicsComponent.class); + physics.velocity.set(Vector3.Zero); + physics.walkingVelocity.set(Vector3.Zero); + } + + private void jump(Entity entity) { + PhysicsComponent physics = entity.get(PhysicsComponent.class); + + if (!physics.isOnGround) + return; + + JumpForce newForce = Pools.obtain(JumpForce.class); + newForce.set(MathHelpers.UP_VECTOR3, PhysicsConstants.GRAVITY_SPEED * 3.0f, 0.6f, physics); + applyForce(physics, newForce); + } + + private void applyForce(PhysicsComponent physics, Force force) { + physics.forces.add(force); + } + + private void applyForce(PhysicsComponent physics, Vector3 direction, float strength, float friction) { + Force newForce = Pools.obtain(Force.class); + newForce.set(direction, strength, friction); + applyForce(physics, newForce); + } + + private void processForces(PhysicsComponent physics, float delta) { + physics.forceVelocity.set(Vector3.Zero); + for (Force force : physics.forces) { + force.update(delta); + physics.forceVelocity.add(force.getCurrentForce()); + } + + // clean up dead forces + int i = 0; + while (i < physics.forces.size) { + Force force = physics.forces.get(i); + if (!force.isActive()) { + // stay at this index for the next iteration since we just removed something (next element now at this same index) + physics.forces.removeIndex(i); + Pools.free(force); + } else + ++i; + } + } + + private void updateIsWalkingState(PhysicsComponent physics) { + physics.wasWalking = physics.isWalking; + + if (!physics.isOnGround) { + physics.isWalking = false; + return; + } + + tmp1.set(physics.walkingVelocity); + tmp1.y = 0.0f; // walking only allows the entity to get a velocity in the XZ plane + + float velocityLength = tmp1.len(); + if (MathHelpers.areAlmostEqual(velocityLength, 0.0f)) + physics.isWalking = false; + else + physics.isWalking = true; + } + + static final Vector3 tmpFeetPosition = new Vector3(); + static final Ray downRay = new Ray(Vector3.Zero, Vector3.Zero); + static final Vector3 tmpCollisionPoint = new Vector3(); + private void updateStandingTileCoords(PhysicsComponent physics, PositionComponent position, WorldComponent world) { + if (physics.isOnGround) { + int feetX = (int)position.position.x; + int feetY = (int)(position.position.y - physics.sweptSphere.radius.y - 0.01f); + int feetZ = (int)position.position.z; + + // prefer to take the tile just below the entity's feet + // however, if that tile is empty, take the collision tile + // (this can sometimes work better, as the collision tile could + // be a tile that the entity is just standing on the very edge of, but + // in fact be mostly standing on an adjacent tile... which could be the + // one we calculate to be under the entity's feet) + + physics.standingOnTile = world.tileMap.get(feetX, feetY, feetZ); + if (!physics.standingOnTile.isEmptySpace()) { + // check the distance from the entity's feet to the nearest + // collidable surface on this tile before we accept it as the + // "standing on" tile + tmpFeetPosition.set(position.position); + tmpFeetPosition.y -= physics.sweptSphere.radius.y; + downRay.set(tmpFeetPosition, MathHelpers.DOWN_VECTOR3); + tmpCollisionPoint.set(Vector3.Zero); + float collisionDistance = 0.0f; + if (world.tileMap.checkForCollisionWithTileMesh(downRay, feetX, feetY, feetZ, world.tileMap.tileMeshes, tmpCollisionPoint)) + collisionDistance = tmp1.set(tmpFeetPosition) + .sub(tmpCollisionPoint) + .len(); + + // TODO: this distance check causes issues with ramps. as you walk + // up/down the ramp, the "standing tile" tends to flip back + // and forth a bit depending on how far up or down the ramp + // you are from the top, assuming the top of the ramp is + // next to a flat surface + if (collisionDistance <= 0.1f) { + // the top of the foot tile is close enough, use it + physics.standingOnTilePosition.set(feetX, feetY, feetZ); + return; + } + } + + // use the collision tile + physics.standingOnTile = world.tileMap.get(physics.collisionTilePosition.x, physics.collisionTilePosition.y, physics.collisionTilePosition.z); + physics.standingOnTilePosition.set(physics.collisionTilePosition); + } else { + // not standing on anything + physics.standingOnTilePosition.set(0, 0, 0); + physics.standingOnTile = null; + } + } + + private void getTerrainFrictionFor(PhysicsComponent physics, final TerrainFrictionValues out) { + out.friction = physics.friction; + out.walkAcceleration = physics.walkingAcceleration; + out.maxWalkSpeed = physics.maxWalkSpeed; + + if (physics.isOnGround) { + if (physics.standingOnTile.isSlippery()) { + out.friction = 0.95f; + out.walkAcceleration = 0.5f; + out.maxWalkSpeed = 2.0f; + } + } + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PreviousPositionSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PreviousPositionSystem.java new file mode 100644 index 0000000..0f07f4e --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/PreviousPositionSystem.java @@ -0,0 +1,21 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.tiles3.basicexample.entities.components.physics.PositionComponent; + +public class PreviousPositionSystem extends ComponentSystem { + public PreviousPositionSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + } + + @Override + public void onUpdateGameState(float delta) { + for (Entity entity : entityManager.getAllWith(PositionComponent.class)) { + PositionComponent position = entity.get(PositionComponent.class); + position.lastPosition.set(position.position); + } + } +} diff --git a/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/WorldRendererSystem.java b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/WorldRendererSystem.java new file mode 100644 index 0000000..04bea9e --- /dev/null +++ b/core/src/main/java/ca/blarg/tiles3/basicexample/entities/subsystems/WorldRendererSystem.java @@ -0,0 +1,80 @@ +package ca.blarg.tiles3.basicexample.entities.subsystems; + +import ca.blarg.tiles3.basicexample.entities.components.WorldComponent; +import ca.blarg.tiles3.basicexample.entities.components.physics.PositionComponent; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g3d.ModelBatch; +import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute; +import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight; +import com.badlogic.gdx.graphics.g3d.Environment; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Vector3; +import ca.blarg.gdx.Services; +import ca.blarg.gdx.entities.ComponentSystem; +import ca.blarg.gdx.entities.Entity; +import ca.blarg.gdx.entities.EntityManager; +import ca.blarg.gdx.events.EventManager; +import ca.blarg.gdx.graphics.GraphicsHelpers; +import ca.blarg.gdx.graphics.ViewportContext; +import ca.blarg.gdx.math.MathHelpers; +import ca.blarg.gdx.tilemap3d.TileMapRenderer; + +public class WorldRendererSystem extends ComponentSystem { + final static Color AMBIENT_LIGHT = new Color(0.7f, 0.7f, 0.7f, 1.0f); + final static Color DIRECTIONAL_LIGHT = new Color(0.3f, 0.3f, 0.3f, 1.0f); + final static Vector3 renderPosition = new Vector3(); + + final TileMapRenderer tileMapRenderer; + final Environment environment; + + final ViewportContext viewportContext; + final ModelBatch modelBatch; + final ShapeRenderer shapeRenderer; + + public WorldRendererSystem(EntityManager entityManager, EventManager eventManager) { + super(entityManager, eventManager); + + viewportContext = Services.get(ViewportContext.class); + modelBatch = Services.get(ModelBatch.class); + shapeRenderer = Services.get(ShapeRenderer.class); + + tileMapRenderer = new TileMapRenderer(); + + environment = new Environment(); + environment.set(new ColorAttribute(ColorAttribute.AmbientLight, AMBIENT_LIGHT)); + environment.add(new DirectionalLight().set(DIRECTIONAL_LIGHT, MathHelpers.LEFT_VECTOR3)); + environment.add(new DirectionalLight().set(DIRECTIONAL_LIGHT, MathHelpers.RIGHT_VECTOR3)); + environment.add(new DirectionalLight().set(DIRECTIONAL_LIGHT, MathHelpers.DOWN_VECTOR3)); + } + + @Override + public void dispose() { + } + + @Override + public void onRender(float interpolation) { + Entity worldEntity = entityManager.getFirstWith(WorldComponent.class); + if (worldEntity == null) + return; + + WorldComponent world = worldEntity.get(WorldComponent.class); + PositionComponent worldPosition = worldEntity.get(PositionComponent.class); + if (worldPosition != null) + renderPosition.set(worldPosition.position); + else + renderPosition.set(Vector3.Zero); + + if (world.renderSkybox) { + // TODO + } + + if (world.renderGrid) + GraphicsHelpers.renderGridPlane(shapeRenderer, viewportContext.getPerspectiveCamera(), + world.tileMap.getWidth(), world.tileMap.getDepth(), + renderPosition.x, renderPosition.y, renderPosition.z); + + modelBatch.begin(viewportContext.getPerspectiveCamera()); + tileMapRenderer.render(modelBatch, world.tileMap, viewportContext.getPerspectiveCamera(), environment); + modelBatch.end(); + } +} diff --git a/desktop/build.gradle b/desktop/build.gradle new file mode 100644 index 0000000..8c8ebb1 --- /dev/null +++ b/desktop/build.gradle @@ -0,0 +1,45 @@ +apply plugin: "java" + +sourceCompatibility = 1.7 +sourceSets.main.java.srcDirs = [ "src/main/java/" ] +project.ext.mainClassName = "ca.blarg.tiles3.basicexample.desktop.DesktopStarter" +project.ext.assetsDir = new File("../assets"); + +task run(dependsOn: classes, type: JavaExec) { + main = project.mainClassName + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = project.assetsDir + ignoreExitValue = true +} + +task dist(type: Jar) { + from files(sourceSets.main.output.classesDir) + from files(sourceSets.main.output.resourcesDir) + from {configurations.compile.collect {zipTree(it)}} + from files(project.assetsDir); + + manifest { + attributes 'Main-Class': project.mainClassName + } +} + +dist.dependsOn classes + +eclipse { + project { + name = appName + "-desktop" + linkedResource name: 'assets', type: '2', location: 'PARENT-1-PROJECT_LOC/assets' + } +} + +task afterEclipseImport(description: "Post processing after project generation", group: "IDE") { + doLast { + def classpath = new XmlParser().parse(file(".classpath")) + new Node(classpath, "classpathentry", [ kind: 'src', path: 'assets' ]); + def writer = new FileWriter(file(".classpath")) + def printer = new XmlNodePrinter(new PrintWriter(writer)) + printer.setPreserveWhitespace(true) + printer.print(classpath) + } +} diff --git a/desktop/src/main/java/ca/blarg/tiles3/basicexample/desktop/DesktopStarter.java b/desktop/src/main/java/ca/blarg/tiles3/basicexample/desktop/DesktopStarter.java new file mode 100644 index 0000000..a06b3ce --- /dev/null +++ b/desktop/src/main/java/ca/blarg/tiles3/basicexample/desktop/DesktopStarter.java @@ -0,0 +1,16 @@ +package ca.blarg.tiles3.basicexample.desktop; + +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; +import ca.blarg.gdx.GdxGameAppListener; +import ca.blarg.tiles3.basicexample.BasicExampleGameApp; + +public class DesktopStarter { + public static void main(String[] args) { + LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration(); + cfg.title = "Tiles³ Basic Example"; + cfg.width = 1280; + cfg.height = 720; + new LwjglApplication(new GdxGameAppListener(BasicExampleGameApp.class), cfg); + } +} \ No newline at end of file diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..8d297cf6ff279774eedd1dc1f03b5db60dcc4e3c GIT binary patch literal 143862 zcmaI71yo$k(k_gcemi~1b26L8Qk67LV_~{cMmSX-QC?`_{llvJ>P%Vy5HSv z)|%dXx~i*pRX-)&6RD&iiHtyi00stzEG;Fb0tN>84GawY9uDH;$!kZ{%f}bKtGK4C zs)M41|J0lA-6*D7KFQ;KM{tqfLD>Y45O?f$969+p+qrZI^J?$Jn zsKLPag*+XNOl-_tNsY}ctn3BIF50@tNUcl-$TT?QndKct%`B~?yq(Qdy%p3@Olc6{fjT}NBi$%CNk20b#b*3Ap5san(|7dq7Kex zq#TTF3?|GhETo*Aj4bRNoSZE5q^!&=tW3-wA5I1qc3uunUREyB|6F7rqdA+J^QwqR z{Aa9>I{`9FS64?~CMFLL4@M6*Mh9mLCKetZp1(X;Ss6ZhFt~WxyBc{i*t?Mb!$Hi< z#l+dl(bdYqp7bwABVz|QR{^pQN&h_sJIDXBwRic?Yx;O$OrA!LOe~Ddf2Z_MM|t`G zcUL>R|MqrqRWbV?dH=7BUDUiB&6rfoTpZk-O+FN7PX2c&M_y59Gb2|AXEg^0+kf7o zlBI*IgNvnuBdMq=C#k%ViIx4|`+xP9m*SJT3YO@n&lY6(Y!IF;Evv=nKVFkT-hxxOH1Qx zlv`Ub8yCrwW)2P>=Kft@UUDxkxau%E^no)+>;$peRr7>mWQhTaVMd$a{C%2~hx#d% znbOKYilm}-n(O2UO($Gs5jNHCSYcfzQ=;rQyZff44RgSM8z-mn&f#4nrmQWx_7)b@ zsWN+D@9H0yhDI<+y*7go!zFz6_bep8AVj6YuR)}c87cjwH0b_EpZmp*b`CKS+5>>7 zLqDc)glF01NEQ$$6)4bMG4`SfQ&6)aN64LfR7DqrzXvM*cf5ZZ?>MzWk5HMs1Y!`E z23lJ9Qi;Nq%!I2d%}$~0k_ZJ*@P{%qF(qLb{dGHl(5B$qtLQ6NrP>-iv9~K8h2HHD zr$}kYF)Uw<^unK!$Ant(LXg7l-O}IwVgKI=zK0tENbT+IlX`o5v$6=(AT(WHRZQ)5 z1t7#QUumDC43H)_AGY_qPmtyqWx%;8Wni12NwU8`cgsdJ5vsYMq3@_-rl7O1p{d}^ z!RApZgKvV3At_0e@?ME7pE}faje|H}R{m)SLA}snAq;o;JOo%dhM{d~@%xyXnc|Z9 zq`*#x2jn;3eT`#AH09P5RU1PAh9idtT!zS_=gN|Lkd>n2s4%8u!jPRtGlq4#tQM5Y zZ_c2%a|D|t2=YUw{>HZrnxe$h{`d6WpBpJJKuJ)Yf(@Q`DfZwW5-k5CNaCA1?VO^} zo0^su`~-QGjkWbU;N8y>Fh5aNR@MxHg49aO_j!99_8CsUVY>*t02x*3c${Ogc_w57 zg{twkYQil>qFo%Qh(}wKl@i=ga~_cGh%u%F%0~^kfMA{9i3<%&rJbaELQ`g%&h>}K zT2L7gkP)KoXUa4NL4xZbF$(Y+6g3ziTf1%Z@Z}LS?>^rGI#cXEG7Yq*S3d=e1_{Sk zJhT8VL019&L@~!;&vt5B>O|r>5Y(G24UIjZ7wfUT|F3;A)OEGK?l-VMH0B2B?%^yN z7$59yB{iEr^LbFc-kvMHyaVqw%r;td3S(jse$_PqRvu0Msv~WYMBn9fk%fg@LXYkFEvC8(bRSaOpCq0-+IGY7*CdMs}uGF;Ji`jcZEe*fE zc8FlVuc77^d${XNk?<$1Ki_wUE>XBEq-SYNS`+Yrp6omUl>Nc%p}sfF#N7F$rRKh% zK%Zx2m#-{^HB^6Cl-0$2ia2eG)VL?Oim-qLE zF5Z*D$$5*VFQ@qT?Ya5}7R?3PKS+2i+|L3pW>y4wY#a%#&T_Swe7TQ1=8~7&G93VV zUdKJ(aqk^gR?f~ECf!`8cJ3{#TXxt;yyk;aGlZ7(US3>Vo#YCEZLzt;HwH~$GR>@f#oY2AQo$}?u4Ewe?NQyRgZnS zi7As46ylcK?Ea;dzCIzeBN!C0X(+Cs;Op(x-5ntotH>LDf}I(Qn2r@vrJCp3E`*7T zrPut9;h6cQ@xi4v+>|h8{6~6PhDDd_hx(-K$%$NUe(#ic7iverF4m*XSifxlPDB})Gz;^ z^ZFYZZ}@gsXEs(@Ly3AK-NUWC8cbZ!mddE(Ae6XjXAKXY?@j-+E|$C6+kF?R_0ZAL zFZo$fXuF7h25rM8esLh-)ABmI#{8u$SonFl&7(r)q9${Ax6`OlQLJIbo#V?LaAxhN z+yHK#B{BqxN^<bR;j?zK6-7KhkB6TA+X{f&CvNP|TDe~h z!5KHW)3tp&-ZK;ujqFHfEsC*gpLmDPOti&O@si!FFH%ENX2_rA1FSbc*@vV*F+N`$eyE~=^QRYuZMw$gn!X_bZIFhT?Xv`IY^Hj?d+L4Oc4<&eu%9a5a zhKd{S9S8xoe;qID%f)&J9|Z+e76fd;5Xe~*#nRRHPG+fL7iB_5$gbo5*)6i7qQ57Q zLB_61|Ht*r+#vTCL?-GZlKhaDS@cTA$(Gg6{ljz8g~QF1F3!ocDYje3HVvtJn-q^n z_U=gvT%llhHNsXcO};B$+%2>YdmFCqj&&AaU?lVmG?c$PyQ)8ndlw(9NpOVE)OaR< zTas}n$_DuHLtteh=|!GK43=*Hg1eOA&i<^8Bm-{II5h?q+E8>|UkkpF-KB37BVL*};z3z$Y2jkMxZkmFs|Qhxh-Pp-R3(-eQ# zv#{B3Gi@n=mUA?zI`xYq-~`cjZ%recXTaBamE7a==hXcC4q&QOF7=oXUuSZD)!WJd z$zP9;`>RW(EM;`hx`BXVt_$!!Q=%Ab;t4*c5J&o11rJo&l8?PrtTeBFgov1tMcV;B zz~aUsr`}Lo&D%T7$i#)nnuBIY#ypzTq0STd`5XaOVnR*Y4WlfuH`UUb;#tNK-VUWQtF^RUgMtCj+$z*Nm%ulb_YhLV4*|p34H+U+QPVR=6Na}h zSqT@aR5?!U5R8|q(T-vaSrlK1Fq8$M88wg8e2W^PPYe^iewA2x+xKN>3TRm*nlMnB zi+(RT1L1oNCIEV5r7VAQax+8}MaC)%{;BlWekQRs$x>x|ykgVpx{9mo*@1E3eaJLX zDa09zt8^E{darZ$;7qSKPo0cHO#U8EG8fpnPhXkn*}$^RBvivP_&R1TFzFOZf?7?E`vyUOpSj*ei^%E6blAl5{} zJFd;BdEgWX?N~=jzIUyjs;^p+?ltHR=VHg@zF%5L$K`iU`1srLy=}CU?~nPkP+QAM z1&3RMHc%tYcj}9hx98bPw!h#4un$V3OkYDMt;VM>we%4+O-}IgZsA18Uy?drx7qY6 zSSTIT>2eVuh+dV_{pYx7mzYj2!$=*tfg}oz+-9L zUA61U(sF*Q!NB+3>ymoZWcBvHU_|0uRbB1w?oM?|f{W|1H-e3eo8A))8w?DFL0+!2 zK!pI3%JZn87An9|q~1GgNb(J=D{mK@5)n~?wMkQYyH~>QCpI7b7%BI*B=2`26SD-? z*F88Uw6!g_v<5N7)4Fe5S3Xbd;$4bG77U&SEiap&=F~f~o`&tM)bWI6`O9@mCi(wX2~L6dfdrH06^( zx0r73n794|OixnUbr2ea1Tt=uP)ugPKu<7*p&S^um4yYYTfdh%mJ65;Gd+wHEGJwB z$0LG^BqkG?U_h5NRp+NqtI=6)e}i}O7n?gnPeU*TBkmWQK=_ofDUk~BI^nbyNDVW6 zfyp7AyEwr^b1h*+F>-jM5Qv)_O0fRlDqeDeI-PzZKms^^6sosTHY)}>qc;Yi};*XdtGj=;ghMGtzVwj zN|W)-8(I6}B1BJ6R$UrRGIu|%5D(;{zg5u~l*_3(8-Z7H4pwpV76+;ez4cZ7RN1&% zDvK;>((BS-;mk4$*J+d(nMnp(WfuDN+BiqGleh88CZ8XqOYri1d?KoAVFHA3eSSpeW`7^cB=-LB zmdDNsiPbU}CpbY(6ghCAl;QIs?vh4H-1vwmFx4|XEoP2JU#tOmn{(YQKG7;ryjpD~R2Scn8Y~gz$28C5{ zFW;w&whMul<$(rqRtKPxrOhz8w$-lv1zGPC-YsQvCMUvZ^n% z$0u5Fa0Op#%0*DrZroK4u&@vpyY%&_tptwFCQBr06}0^1?G;!u25}CKK4r7L#Ww-I z08_{OOl-xCzA*o2t$yu|x8Wr27?4VdlZln1O|?3n#o!oXsBv>t{)XZ?qF!!u`pSEF zT_;m~ErShNod`Axrpn^Rx*+T}5zNX{)5TdS8UU&fMmnsrIMW1vJJ~x$6o_}w^v)s2 z*X1XQF%tL>QoRH00bE>7b}Nm@#JsnE3Pr!dNXyB^#KcsVmI~vgLn|Y9r;w`}trb*Z z6%sE!4F2xlr_71Jyi0Cw84e1f$kVS>j*515_UY*T3@lo15T)1WuJ1tRcE3GR()6lT zU{s~qi|JJ_a^wQ@aR-B@Mzm&E=={}8{i$jd+zjp}YKTT!?eLU{GR__hV)@s@$O-r# zwFOHX>*!e{ePYAVz)JKlQ7#F8h|uhJwu(G$`rZ!vgGe>GEX@NFxUK()IYNqcST3RG zlnI-TZEV0Pw>{pAe7M6gW+?=D)`H)LCz6PvkN1*DY}yhbQGuM9V$1|hLe?pk>9YM3 zMViR29sj|o+fDc2{Gd9aKF3pRNDnGQpv7uY(HrW4w|~o)olpe+T~-n7l6rah{SJ<8 zmYT;=cUY>9`ztmfOM9&BM=Ezr8%<(rHjGvEiG;A;R#8S_Zu2F3A#d`e{&g_4=l)qQ zI#0-9P!PM@x3^tty;$j{cTILFvxa(YNERg+vo`tvTt?UR9P>Kez{5YNA$%4iZH9NCa_`aWLl;*jeA5Uthmv z$2Z5uA!@Agx$Fj3@6^YkXd6ltV4WCw*sisO_a&amrjO>4EKDpER+4J$d?MJS_@AO?l?x}kX+xO{wQfktGN_kU z`gG)@RPKM(7xh5=c2$vo(9SXk7T>@eCplRY2GPgXCPM&bk*QKrwLn1Bqtb?Uc4lXg zXXs+ZcKDme&ldra4i8^P4M%!`drS+I*N2;bwtC56Ye=r|i770s^U@S6^snNsCd<#B zj^mH2F3gcI6umKEI1-Z@4IM594iH>zEGa3e<)0;a-Bk1|+OJ3mT4Exi-K5sqS5x(^*en_MKIk7V5z!t#sP7Zn1BI=v1RFAh4Pcsd z)z#J7etPDh*wg8@y}i&)Ne_(;Qs5<8K26JPVR<=%7P5f_O2@S&F4@q@^2*ANCsE7v zl!AC^l!8iTvYzHz#M_y#s3_47 zWF1aRYgxpbQJZ=d$w?)L@MG6*?2Y+}m$zk7U6h^5yvZ;OVi=i5rHGm7BZ57fWOX!Ox(HyNC1rAd|8V8>O23 z;%WjstwP7jFB2m`rT+0Js2xCkyEiL{2 zEncS9YYa{g?`Y=b#ltO(;s*78MY(jU2~_)tl);JMm%(pq7iMQm)o3G@(08KY+^#^6k$_5LRk6wgK;H{|*xmQim?Hbwtb>Clw(KKYMKdIs~$8lbV$?;(Y{3h}=v5f~!&e+>yW` zb{cG835Cz`B-d)qTvPCe+*FO zz{J1ixjB9zB168AG=3UBKDO4hgmSpr6KWn7=5-D(SSwB3STa>&Tf>3dhqfCGqa&b& zG)2A$GNl^ArHEtZxGngu2@d5JDNh;+O~d?kD3J^Xdp(p2`BBYC3(GP3a8DG;8apY6QqAC zACrhO7=LNQ0`#OizJghYJQQhAeaDB?w<`@YG7C`jqeE2&$*)eWCFyCatt>4ueyt&}I*D(E4Hw z;BSSX_8&cp?xZ=bcpV!y3!GPQ`3692ZsxG*13=82oR;({s4#lCu=5!ET6k?L35k@dek z8$zdxrj4Y5yec=Zm!!NN$Gm9$d>WS0@PBNN{xj&y^K&nnh;D6Nos+1Tq~uPQxvA-< zfjTYrr{1IU^SF0yef_u~w9hiou$wrqSvC_o%riwzW6Z&MUU}#Vx3h$^H=zqm2x}Nw zEIlhLgxC!qF#q#s*b0#3@7*Qh)Vhq(;L-EH37M!_}abo;T~{S(wXf~!`8 z13b6q{fbvjVomlR&Po9Yj$s(5_42PUVe(cBt#_AE2VLG(=x!0qTeDL`WAmY^gMlDb z$4wg7)w)hVP#?Z0(L7&qAurx(K;LV_T`SLVI&BSQ#gwm$EnmVWLmGW2l zEGnWiFW3FfU)?xsByGjrWnMmAX(*m&KL`He((Cd=R_qy_3C}vpM9vN!Ay3RgA+O5| zgoV`r$#sC%?&w03p0^vIXK&nPBL6T<Ax3Lf z`Jlrv+e^|*6VfelbH4<9=n4j;e#tl|-%WJ&=^Y-U0bZZTC>1m*@8!_No2NXD7XbWbk#*X$%BN=0AYzyff1kq_vAgSf0USC#E#Gn^p-Ki zyIz`|x%FYws)4>K5pPHPrZEYr^u$Ssa~b0l;@j*q1HhOb3^{4;VKgZx^+!WP!(sRb z4myu0w0}v_9{GJUdvnJT1bxYmF$O3)rCHQfcAHRflbFoa={H5E&L?Ce@da@Mu%Uqj z5-KH@7$=jDK^>HoN50d)XK>2c&KsUO*Kfm@p7eyY3sFGWrSnnnp@RxO9aC^grz3*= zycOHs7Uo05ki4d>c-3*OY`HD_p9`X~A+-5e=vAP{T*f2=<%fr;;!|$@^2AX+CRfA1 zGdya0#}cpVq7sB>t;Y=4xD4JziEE)fqDm>)&x@*}Z3`tjZ9Z?U^k)(dHm~DOtC}Bi zU#^xvi8QILv3p6K+GeyBeT`uf*%8)!ug)wH#S!X}%vrExqpH5gfb@>f*{q5ZB)@|%{_|>^JT&A0(n*;fe z-1hETC_pO!2(a?PfA?KJs4d@#K><%MZQ6Be2I{ znwmi3dN~zN$}PVgESGvA(K555IBf-6e1T_tEn0Zk`z5|8y+4d)s#kwtUvGT%1AQPE z-eqXYKrWw3^18CU(!D`#_y*EvcufgPKex{Os^b_hOTZ^@i!165%6pbaR03IbmqvRk zdlX|2q#EE?$!Y040Bi)DKvEK7k54m3_Ne3-<)xLjG9wm%gso zIep4e{(M)L8OOFe&1MTqz6!YNnh6Be#zKzeQDIMQ+JxnO0RVKlASvGu5Mf^lROG~@ zVXn9!o)rD678`Q8F&nRSvD(v6@p}&b@~$LE==e9>JNy+us`QcRrv)%7O2+FW4)SlD zuIF<*o{f~#qrxm#NXuqvm!28=jK5w+4}q_RprmP7PxUPG*qDuIdZ|phTEf@#t|zNH z#LvLl^2+9CvB4woN8^yWqbJAevs)G;*)h?wqvqWv3Ktn_lp-kl#A+RV+MHf^K+Cv_&_XJE!^9pc59Of#=AMzBe)lkwT5h1(ISd)8 zbhUfj5eor&Jtk5iFz#w}Gfwt3CW423O7#5%f2$?JG$hEjpRL!yLUQaH`&D~~kHmrP z$G~MUTynnLY8-OZy~-pxtMPY>pJh*8M@<=?rUeq>!52a+gNLTKK4VP}CTpng?yrBQ z#}n#b?%@v7qKMf;^35k;5TJ(SetiRO_&3NjI!ww33a zlvdQ)IDud5PklCY3q=qSE@byBqI9GEc^L-k_5cI`$@K|VQb5gsyJLxiW8sMlDQ2&v z*oY#1oRx<3Kf1X!$4iS{5s17o#U)-hQnV(*VMiPiu*%ECIH&GLRH_c}*Qi)3yTupw zVf*+O99ulcclY-QcOlLgN%kpMe2Htf-U!;yT4d~0P|(ouci)VwDQ9)YiF~uT$c-<1 z3Ke^M{CH04q}T7PFGQbWJ*VedY1ZPpOmK)uB#jPdFkZF(S&`D+@SFCDBUQuI=} z=6LN8yf7ml&8RxM1~IT@!=n)FZSBWJ2uHmC1Z7V%^?HY!=8bOebm8YKi;((j-E#bh zM zNZ`j#f4}lR^%Csk>qeS~2G=^ABx>>(diz$DXqs*bDe_OymK+GC9o^=$t(iHQJZ!RJ zP@LYebNZY680c>G*{2MC6gnkwa%R)>yr@wQ@NSi8bhE$UM!J{azJhBbn~k-P4G$0J zjD9k!j5K%Rd}b`i$@g0lg6Hw-cBd+Tu!%K!o9bY0cQ! z3cj-WL_fjDq6~kBD_FYtCEeeFI7m<3gYUA)`|7coJU+6Pw>kMH4E9PsYvq3B=z@Fw zuJQv$XH1xq9O|1Si}TG*O%O!C4I;ns=!jepk$8Lep?Kh`*x=qR56k#W3WZ>N=M?O)S2>64xpddOqcSjBC z^c^JJLQHp0sR||Ri200q8DREsTrvSpmX0U0 zk=7fp+@w4idwP027a`-6ly$Ht;U>i?$P41oum;$AUC@W6XmH8M+2(jWi=@xQB8=nX z;`S@ZRbJA9Y-PoV5LZPq`sCn|kS2z`Hg_&8*3LeIf6wM3s=@zpLAW+SZ?V9wBL-gW zpLX|*?Cp&-+*!{Ly$I6w82IBeoq=WTv;UBLGDZnX{q^hD__}lzo=f+Txq`%gJP+=v z!j?uS$GRywqVJqti9#-?xgFXdAh&$motX+v>8GJQwK3Pp!2pXByT@f;RP*qE;XgL=scE`~kL|l(8Fhp8UvME0-pV$@p6Mv$J71F~}CYN?zn|8bPY~ zof5gcb!=TiolgTQZi}-DSv6HvFX5cG2;+Bn)hiycEL+5(vqoP!5E#$5rhEK652uS; zb~3+AMwGMR3E^`b&XII#S%&h$`!Fud5w>-7HEpc1qZlIlXAu_!@0g=EMU;}WfqA<) zg266F0rEHR#AJn>Q)GTf`LYX+b6A*uWg~O?yswOEkflMK%`AVZz0R8jgX$d<6TTII zBdzrlWYE@GYuaqS*VygIz)GOII<8RMvHC^%$;dAlDog7vSeN$~1A}vy+Z7%U=_;wL zdb%nQuHMHIs{jpTqi>bGxMk1fT#_`_oNa{rU0ec*mY!V9)Y%3FM4o@b5cXcc+h0uw z1=?Y%BR*o!V~++W@U1mDKe;lvp37WtoAZ#~&ARRKU++fMLW#HBpt%c<78^Jm$Ln$e zO(LMjKvOgazC2v$B(~Pov7vyU{TjSUaPZ+UaY-K`+#-$D$of^QX({}fAU_kuKJoK3 zLS#gY!@z94=G4dhEI_i(4^TK8YhVkXK{iFCuM2fL$q;#tBq7|@&#t&!L}+yRA^kav zkT-eEXJ{F#V_cA%E9vAy4{F+d7C)_&CvkLIoz=? zqLmAEYL8f?aS%?7HBNmBfhf8|ICQ&-knR`NUY3VcX=3fp*?e_` zy)EXcQwov1O>pOmccRPclGPG)9jF@w3M048xvpf5y612WQQr|e#epM5p3krpimQ*weM>wP~(`XG21}jsPBTCIwO7U7= zS_%(sD695a%)Thj7syvIqkNudWG}Oy9B4wZ8y5n!1!7WG9t$l8cMUS7fMz7OAhD7d zS=LGysO{JC7B$5aq7aqDqU@<=$`32_o-&T?A5P3UXQ$+BDl&O)5;Nhr%JoV|-C5vY}|$BX=#Z-9EMYHko@t?RqR)>TZdD*e4x0rE zINHX?5!1`3t3i^Tg~@yeqU&!}tV>yscMArvG-!hnV9@tEM&B%#2XkX}MB4Mmc<_PM zY=xq{6SbJ&ay_ULtY4A97XoZon-de6f%z5!CkD61i5&j6mBG1G%%wio?=oS*bs;3} z$fBIU%uhgJ*KyB`6a&i|s@vmN44v8C3+eNcLBf=A3JnTIVrKCe^)=Qj)XyE~BrKUp zO}RtbH*3f^GpGf%g8EGmKwNY&n_0w|aFUvL$d}P&q|5hL zIWh7;Sgk?!0bk^nSc8$+Qv(CjY~G%A;AtDq`|~#lp6KNVvT*L5g#oLR#V;lU{>bT_ zUvcz;#sjqGcXTdWOouUc7N7AP-Y2W*zXwPzVT{XJcH6BjKj!p#w4!H@XD1^jPW4TO z(pF%^l7IizdCrl^a%_o#c-TIfb?D%Wk{vh7`e; zgBc^Y-Rl%35CT6?K9N^o?ra1|<$}rcOA+-Byv}xswOvA4oQxaJkVGsH?VUllIl;3; zUtK*lIeF&!?vx-jlWp92`0HzU0w$Ck8g(Hx?;`?;RJ+JSPt|=!&VfJ-4@^Bkh{%p! zyFbZJHl303v>P|#eLmeEl7|iFlbe2zWFQo%?+$_#{wNeBs~IT>h}#b+?Aui%L$fma zW_C2}-J?vZ9-!}wgBGPw(uDVJG;Nb8kfqnt+upcGd5P_N{*f0xv*L*QuCFa-#@iQ% z|Jlw!)kOt$LU-dI4!sUyQUPE`Ea%vi3OGD%F4>Oo?_BBG{2Pt93HcW z&9caSJHUuS0Gpme^`P-NOoXIEAF^^f0${<!qDS@PVMG|F0wh#82oSSzXc1c2BO9YiJjx1vM6p!3%7-#5N(@SdLdj)Or z220e%`;j?jvRPyuK}+o7V~b?Qv*FFCf0-YpqNI7pROC1E$Ak@#{>VB*PcPSc4pG6= z6H!d)EuS?>Nq65JyP=-CUL@HsiHcFIJ3+dVp)=o=)O?f|JRAdB`0C%D z_sjPo=0&D;u?+Xi5MMNa_Evpa_}0^6rsi&p$q=}h2Tz1dHy(O8M(UqI$#CJC8jLj=&6DVl=Ha1e>@3{n9|JJ4K0ITiq%8Y5<6 zLw+TpwQ$!*X)Rbu8TLJfJHB(@w#j#UiK>VLQd++e~XGEfz7#i99J_d`+$QIUrKhDV;R2OF@66U!7W`fSQlOyCH7!z&j z7fD<=y;F@pV(BS5l|d#!s!8}96e=MHf&NhpX6Ma_5_9>0_PkK+mIyHULfvZJmgz!B zNh_s?*dmpwSx@V-B|80_d++r4F^(@STPMNvzwGLPuUU8;&5FyJE(8sqkjsK>wN4s! zUs&{l=KSI|M?923^-$!e?oQi3Yu{5fg$r4}nrf0t^5nQ-e!}tBsh2sVE;IrsDTR*& zb@!*<_AU$n!#f`li4na5Z!o@G9M6@pg{av`81UP6T*i`$SvYwP;7Rzl841Z+>zrlr z1WnW7kMas0#+UA3`bg^VwnxMminLrVgygQ+tzQ3G>1&fUn-sZ=k41soQq}pD{}!V- zH-6z;((OHsIpv@sPakC-L!|Q&W4(%FXYu-lZ$Unm!`tP|GV5>kLQjPxKA&DZdWRo+Q)a4KJ~U=}^> zTT(8a2(we}QIxkHHtwk*Lq>D^;^?+WDP1YbYZF&PcB48~kNfsm3CzwMh0A_lc_LOsE7BwMY$#R4LQbF|ES?!7oLxlUX42lq7n!+Xq%@9LSPL# zKR@sH`8xI$gIhtQ8-hjdklJYsN{O_S8M;~~&=Vp69zrokr;C{EZl%ixt(TdEd28A| ziQldShKU-R5dB%CKIBB4l=_f!?|3DC#e@CAS!Rsc+mWV1*`#28mkyOJQyTpGL|oTE z0T>nm22@}Twb}V*W@9&tqr?Z5yHx5zJ2cw9F4b{cjaFhKBFfpq59Cr$Fmk%GM zUPC5ynJryn;E|Ba_df2vKpl+nrPj+W7iZ0C@E0r(nuSauhWb7bhj1)yL>F4V*}Z&` zRe{j|il3ns*aW^I+2L(01zWSo$ zGT*&MGZB!N=H%w0U%@DE&X%cSo-}2{Gleii`G0z#5>^XDGcq-$h=Wk(FFKE;%~2;4 zBhrZ=r(hdpy2a#|ew1_!kfk?WX|ZJLClcMTeZ3PC@s6~C3b3s^91TCZMB0M;#BK+{ zkN385EXn+2B!wXtT&+fwm zAe1EW@H|NJDnK!i5ZPoPxO9{Fx~!>FeWoDSJtXkugvJbq&~7d%VF^Lp-~@ggTF5WS zRLvG?*_1|a>(b6bWML@&2!pW3L=%^nwf7wu!2n8=I<2TKa<{Y2*rB#@X9BEyt3BZb zL-mRW4&D}XqC-+gn@TrI$9km*A*DUqspw4SU!L0ymWZGVmAJ~x#*nkAG6)d%)1*S4 z`S4VfEa({-f4aM~z3}BBR>S2%=gAh$v`9P&VG?KK)J1V~HuoTO1K^;qaleiFR@6f) z_`WuI_S*OwIDUjI@~d(hUrl-@tL0B`jJa+~z@eTja=7L>q}trih~$2+t3~jAoYpv# z3k86)^doKworJ`vq0LHZ<%Auq_s0Uo#a0nl#bO<|988&=j_`7@URSKdHoI`L4tE|M zMrC%QdOr+)Hu_!H`mMZA+Qq!*%v^+RrEzr!%3Iq53?-F!z~2MCVm(2?TO^|m5JOD5*h0U%+kZL zV7{YI(?*Lstd*N{SsQgSd47cJj<2w|n!>LOBCq+_b&lHUdBHxuO72)uiOpc5|18zDccfbd9IK6X5~)>MVe(qi>FT5;kOK0JcXzY#En z+1zLcU(p#2)AX}?Gaf#Fm*Vm3J40(3z>RyTH0Dtr}7>w zfhJX?;1No$Wzu9ytP5@u-z_DVipUW_{TiXX+rPypuodZlzyB|cmZ zegjJwvXyf=%fuT^0=Ke2Pr`^3wurX}?zRz!J4D+%yEpeY9mq81cRGlUZUEwufQ$2Y zCnf;m77(IR7q}N(m!dLq9wq}zIR`hZTyfb(i|$A@J(P9m~qA_1);h6`}bAI{eZCG7oAe+`O=h;+W)>qtztzg~}CvR-1phIEPu z^7ygNLm-75rV!i4&7HVj{%}l9O=ZSI@15bWnYUf44HXUiKD7EhgQW&(^JbiDBczN` zrx7V2rV(=&4bREa0T+>vv$Kh;*5A~KU}b;AfiPVfN8e&{bxCGP@cUZI{EN_PmWKl3 z_x^5{7tee1SeJ)MdPnDx38%}Es$>w<5PUi0?@Xty@4|yq zz86i4O;$aMGzWrRw?<g_}!&$QHiqzY5l70rf$a^u%xdc-cs+V+0CxM+wRU zyow?j0yF%{Va58<3&W&PRYX?1<^ZGj{(Vf#K!(8gn6p4!1>D1vNkDAj&)>ZWR2^I- z1;Rn^Z5?;|yD2}s09h?MA20EjX;C>V45$J*Td z(fJ(0crf-0cu81KU*f6JfHNobK*t`9i8FM#LkB8y#wgx^`0QAz8WBb_e2 zsLXq0D6DGxVW3DV=`IKCumJ?qB&hJ=J$`TaG><}$%N;KwK=wLV5)$dnGG)UB55@Be zEBs`-bLS`y#|;@+Fc%ZFZN<==a*4#jP0ls)$Vz4*`u_o+NNXgVEZXyxQkRv2g*Q&PPvV0i_h%e9@dNh+Hhq!pvNRvS_N^nbaAzEC zP>(SL0@7(1fsg~CJ@y*Ke`bmhgfeIKm=PC#{htd2;UaOW+SzfsdRJ|A+p- z*E8!(R^8uDNDxs0%AsF2iQvD}%Z*fdWewZ${@TQ@y7lWNo4#r?_=Dh&@J9>bKX{&s z|HvoY=)OgzB@q8j{dz)O!+TI5>@y-lfoL2{7ltze!G(@0cjAmxqig!uQCM8aJbL2d z?9AAtnWUvzD6YzAfq>_B9Qd0WEx)ip=%<=u{i8zxMh~52&R#h_UKYQ-nz}Pic(351 z;v)35u4y~GRA9mPj*jL|s386$q_V1#&;Ko+K&~ll;%jLj{xd8AGzt~;NF)=atDYST2NDyQ9?z`_Y2DdB#kpw5q ze}!&waj~zjF98I>Nl3+^C_O&@n=)m})~&41G(SJz&(BY%(@`lvDC!@j%tVfiL@YPJ zqk(~e5D3njHxH*F9UL4Q&6kQQV)RD%h4X*lICfeLl?a5$iH`#7t4(kcK(Pd1I`o@K z^! z@aP98A^ziE&pCo&WtqM83|wx4e8CSc<|-o;I1$K?C*woO(rfH;m`QVH6{^ad!7L@` z{+%0FyT$eSA44$B6_VKOBC_YOnF1Q^{Tz1W{LlLo!pTlaf9iYq_4E$nD0X*OlZk;Q zo$c7U*Emd&c7=^Kgqx&w7)!omz}<&Ucr;77`U>x{s)2@~y0-cnO zRW;lws@GaZ98ihCX4{1ZM}a^5z%m~*X3QW^U_n6vjsn5;1pW&N2_cdtpdmnkK0ZDO zQivA`M}d4Ak{>CB`=C+Wp$MyVUA7l_DhsdcArN$nlpz)nl4pb$l`aw^okbpcAohP|xB&;yj-@1NaYocAeTAqClhzj%bUL+46XI zmdTaoHVj?=kI9Afdi|q*%-=^jg%@q^DbN})PGU@sipfGvM%xVXk=L{ zTy8?lCh@f2v#%K)f3*>HX5Mve&pE`g@fa_Qjodnli`z>(eZEa= zdUSbR1;w|OXWkn=z))aC@s9ucN8c%e5VKADu2*)m$+qj(7243wneGu2rvUlZyLp&o zQvE%nechtj3R2fiT*}dwyWcu+b}yY_>aWe}&pobs2+*_X7P+PoLEG|#3jO#wV zUAyDgK+6BXvg1W%CT|pzE0rdlvZA8G-`@!TwOTEKmS7Cu7hikBURt#te8mwhBmyC| z3AMo8!Csx%Gj@iauC5m2{}lPk)O)Fr|KnO+b!Fs;xZ8&=LY`7vXX04~`64D2&$0Y| z4#d#TeiAbY$e~M&?{+-@=N_C0M91wW%lp1)!CYI`qq? zp5s}R6Wps46$mO^%tchXrbV|3;lG;~QbC!yu{7M=XfQBDROVZ=-yV1>8>fYDb~E!X zA=+uz=ifDYuS1DTt!G7})Sab0any|22R4#%$>;w39iTw-L-+V%oiCV=|Ja9)iyK6N z1pb>ae|A&c%~U}PY^gj5U) zKKkyl3Fr1iK|Mn;G7Q z5;qJ+n7qgs;OWnpEb+R2`x>2l1AuqWF+oJ{J)6o$;xLq;A-(4tSD)82#=7xkTuRGJ z;}|+DOWx8zN82;0nBPCBhh)McZsb~g^>w!SzQcVT!t@hTibe5z=%LoVhCIzUGsB;s zet5%gX4Vk^Ph;PIhWgXYP0s14c&US%66w-VLQvI;K}Dj6tr>&L%h%53xd#*Zf=>%|av>GqbQ%k>-**{vfMt zo|G-30D;8x;a*~tdyUShIfQWjlMW%hiBP|=2+FG4ur47v*Ym)LpPQ2Y(r@!cvc7ro zqIX-?f0UMdxoy|3=In$tb;0bzf38Dc%d?Gi0vsZSJvD%Tmlfk4JC%(Z(P()*4b3Sq zhQ(WjnJf!9Xx1}A7YmINceitq<iO-d3R8iqW@ zK#>Rcjb6U~kB>jK?GGO>AC$%5$dQ~#LqyDrJTO#-#%O} zZ==!Nr9;4q3bN%P&nc4S%a?=CH{N&yFFOA+Gv!~MzQDgOzVbRTWbAl?3qYRq`$z~Z zgpx}6Pd!m`l}fd7<3{}C+xHr|H0yw-^TAW$!r|c zeujzZZfxZCxP~f-kAqMtsFAo*1`xyQ1;YUuEFut{!HGc53(Qjr2~vcjmjUh~y*P~; zQp5FvwI-ygP}Rh~U=k^E;q%LQ`U4glW5%Om+9xMnZa<;xja}Ss$t?9~`hSpg~(wcGn2W9p@-^CUA^V^>gUP8d@;Ky5W%FWw@ zbyNlf8~0}|%+0Ihxz|PT->uE*kXnoG(L>`+S(B7-!$wO?|Casq=;#J@0e?6OuvMIYxyS_nLFm~qnzR}%*Eci-U`)anz~Vmv8U6H&jSQm|RehBTn7 ze^Us#@pE4&FDwQRmFxS@h^xPS=~uX~z=Y|H>>xq}3dxzRCglkq%swysPd9pp{iBV? zQNGh4^w%*~ZqC+kQa_=ey1Yty9!7sSu)*x)=BB^AvUbDVRny;@M|2Zupced9Ge(>} z>3w!uxZ~s1eB{K?c0H{1tZ-J-`@2S~wYoFz|79&65h%WsE>&=#X(zWce^ddG%f}P~ zl1y9s4*0JC|FLcIm1qC><|ks;2;AjbR9f7+bvU6&5Ys9fTRL<88*b_Pp{Fin#q3zJ_2>*f4A81X00`#f)o2|__+cLj0pT!udZ*`rAt{Q>4ui0V7QEo4B|KN6Xf}>UAso` zx)0&~o`@>56f+UQiz4#Fx*vqF1;l^+TiBC&6ABQaB{PAb`5Mib#lC6ktv>8D=pQ>@ z{c^(B0JX3KM1#0SP<&(%|M3OlKY)$+da-9rDL`?i)*=)b`+^;g0)tx*C@wNti@o>l z!}!+|e;RRWP!9?8L_;zUL0BPn6G!Ssu2j#K!6T?Uz?awdoyotzV!feD25>;oR3MEy z|Kv=@ovC3|d5MMF7yb!zgt^DPV8SL=l#s+Z)x}&!qgaehVmABi{Q2XR{B**`vR=hY-uI z(s5&A>OKm;9yN9p`^I|H8WA#=J+?)GJ!3a=;WLb|OHrM!b>uAv>N8=iNY!h!+@O(s z`EuUn6#64Jq_cHHs7D*u9&H9yRGUSGRu$is$|N!a>2q=KzJPA5^Q$N)-_B0na)W%t zs3Af=kaoj*n1F*b>@GI`v>p58a(Pt=`xFD8zCKpIw;G@*q5*$2jeQmBl<%iB3cLBm zKD3<#c4HS%Ui+c2x9|AWP-DAg8rrQuuv7n$#&J(wuf_{ZG~gSUv;`e?~Ta`w6dhhYlx!hd}Jk9z`b`4i{@{zwP+ubO683TNPq?qE?NxJ;tH z#PFZNb?zC?4RCP9v2jrdR%H?yld+#w_VF*-?Y{iFvU4?r|AY#5c*AeQpJ%z)Q7=u; zGF_{V_MNV)co-}cK3rNMBJq?q`CE&NqZ5t-`%LO#=8d6#CR=pDO^Y6yl;oqH|1e)kXi&AF_y zx>~E#X)Rn~d*kq(rfY;KK)i82QX-d|bl8GK!S`Z&xOoWu1csk;yU(52dIJ5y^OjP8 zmbH09mjMs{X19sDY47;}$O#==u>*j=pFiK`M}OjIGx*jh0(If|@7{wZdMa( z6U+xFV}d04PGS1rDf&duTo$MFRB`OqZDAHB9%&Yro$6t-P+IC+$aS| zEG$4M80Y^W_=}xsbQ=-N3))vsLO)UQDDiv(Jp>FKkOCAED*of+3=>B1R}wHaec43s z=X>-r?5%(9k8=1PRPI(>dcM`gPNtwj zPpVhi9I(zb`0Ek=D@oUR7{-bLi+dN{y%f-{57Q74IP{|d2>-PjZOk!0smQOZ_v96< z+t!h1)^vwM>urc&FBO1_;Q21HzSzWW?}MhYlZT zmZi!~nXI$JqVN*n{{gwR=YY@1ndV&C>^zEfq7FvZi z%G^>SurxixBfOOf2#)dre`RSV`0d2E=Lf#rOK=j^Cjt2@uJOI}mYV2)sL zhH+w&*P5`PAK!X6YH=tyct7gj`1y&Ohogg?PaX#7fm`#TXJ*cv>A-lvP&w6_`o905 zD|KU2njo3?sYzTjyI-Jz^x84y;9H5WM$C((>IIalVUoeY@%_n$`8an;tzB~4Uc(6$ zfL;N9{sF`NabQHKcJaH0)<2HTs6LHF?OPWbI#R={4rd>k0c&mc(HTDs+lZ5zgWm5~ zoK{MdpWPi0A2$p&mAk(re!j7?KJWfDr}+B%w-R0jda5I7t`o!c*gv%Q##o46RIMLx8DC6jUd4T`e65crrQ6Oja#saDH5(^b=#qcN$I&pM# z61o5aN}*qWUAFRx1@lX3;7?UiuESn(L*!B{@S67G5|e=me@#1{iwfI|RVWKHbHTH) zA{S!cFOk;@3#~b@NXp8~i7Z5PX}WZZk6|8d`Stbh&=XPU5eP+SR0s0oKMb$o3F=sB z8hz*&O@F7YtDy=^26j_{V+DuFOdqw6FMLxFF(eB@iiEYti8C$%jEkHMwH&c`0iklAMX9_+wj08p+>D zWD=3aAO}ERX1bWj&CSizlWXP6mMsIH#0xp<>+9#tnIrPvrx`P5D4#b=jq&5h2LuF& zT;Sy71Yh0JYLU^$50C`^N*43+1ON+avIK^}W#;oUIp~R%0RX{*f`Wj5h)uKlzR+vP zt9=OyaMJH1BPIo>?l87vxLLHbqf_eT#20=r*|>|Umym)~)kO3{5;RbTLe!_MU|(tA z-jT9@F@S@qf0@h;T6Ye)mz;&aDI}s>H=qTFu9Da=y8$ou88E-MkW%=VPN;*A>3r3M z^b%qmV_&cfY-6&-FVNRNr@&$veEX)rC42d(@QwFV4I`GNn zQSUt|a-&wORVo~6>Ka*@>)N!%?9C+=xr|GQ1=kDVKOqXxYWyb@4ru;X%=RVDYR}4M zFi~Zti-nct>>3zoKtVCWv8SVT@_)0!#{^F8nea|B1{L2@#noHY%V12nB)zqC7%!?CUdKM{`5x zE2;B9Uv)4n`H3Ckk#dY2+#|Yldzgb=$KivFQ)+Aj&*0vI5WGHDbN8mnl)82QZWWnT zgccA5dUs_f68)z=)R66ypB{hiW$<2~7oDVK#*B;`^xIxn&+`kWx53T=o#LTCJkevC_qkG(?go{G(k)1g> zS^VH^BBy1=zWj=2ddD4=a00VuDk+F!s&G#Vm0zhfp>a$-h~c7)a-(;>Pp#b~c>JxnQzMSkhrOzCyL0zV&P8>GY>*$I%q( z@zkmd*{Qico@|pSs%K|J5j|OC2}_=O-Xx?w!w^*D>Spc+$lXVcM5RTduF{v~QamJJ zBzgFNZ~O<8jidK`{4;Up=QomtUbZe|?Y@)a_|;odRzgs2_I7O7sKQuMaDjt^NxYr1 zj9uxe)9Zy=ulWzV#N?Y4hEi>Oqp40{XAdjh`BA4<3w8Wq&rLt_<8R`W8^V87{*RBY z_|zJoR}=B8@?F5<_>b_V-uf%e9R5#yD9bC%Pu|Z3L87@|Wr1Es17$C)n=g!i?&oH4 zPa?U8NMoRnLh|(Vbdh>pv}h5r|I3^??7nns)~tcY00qL=={C9w*l2y34DC1wO8Wu$g>l^ zIL?3$1erhUaIJ_3=Af+#U~u# zh5&6qjVzbjtx6YIE6t%tV)^;_BM8|4@$rsIN1bTEetuFB^*r3X@b{Igro2X9Rs~X4 zF{Lmro5;e_ceFFYZ-O`HHSlKULW~$z=Tg_$9&gR!6t+TYsw;66C@$Igxn4|L^AjiV zpLNnIq!qm|skx2M8GK`k3b-+fz<)c|tP{Jjt4C3i#nF?eww~`lg&wFh^2NE04)0AA zi>xh#|Aee8QxyNfe?0q3by~I2hu; zS6+Dqa)AI@ZrQR0M}goIrvM@TL$K-dZeJ&_si(StAyk6+55Ye075s^KOLtCX_o$mW zlk){{F$gRV)e8(Y1+Wi(J+tmS_?y4=B_0#wHE{BP6WdQh{MY*hcFH(lUN4{y_!Ia4 z{&%HKbPs|EbP013A_5;W1<03y4L<1P1Kgwv5`h4s@h=`cwcqhAr_F@X#Ecv~nfC2m z;TLLTeTwt*I}B&HUkd2RC5vDs#FXF@qDff+hcDsiNl=xzJhkxkJGXAaMQwQxvi*aD zn#j+gcfdc&g5EUW=zO{&U5!w(5$L;g#vg1gBp$VXn?L>`sz>+sL;79bb=os9iuoH# zP@vHX>gVT|3i@)dzQuRS_|G=;)9gBYBtZnW1O>Ql#WJDEu+XE9G4T3<0gd~89h&2f zk0oW4?y0U<7ZsU+&M^BZV!kJyZ1cim^jcmEZo%HRYJM&v_>bX59WXo>Fuw%?T*U`f zCAY~fFawy@_)vM|`|YFVuy0Q|y?cjA0eZ0^?Im~h{8D+hcX{$(6VRhUb-PXo|54A2 z&zf%TxWbW|b4Oo2eIqy^ka}5Y`wq?3JNQB_0xCBZ1O%Zd6pBW-4mUFjkm0?K5HgFn z-~oA!(t(W%K?jNp#D5m055OOXKMp3-0m|e7O(}oVrKq&X{EN{77k~l@A`qZJ#t_bk zqd<7jZb-OLg3V5Cp8EV4A_C1+Dk_%Tr`N;H9T9=(B!FvXCI|qW_yt{_8*H3d2R8od zg4ozjL}C1b*l~fte}5OTVpEB~g}7nwhwUHf)G0v|+k;t=>1ajp>#wt0gfxl*`TQRu|8N&D zE`&R{QF)m7ud-4!s8(-+{}2jnKe)Xy1r&SNuqE=j^%wt-z4L&Ns#yE~+3cqGULgr- z5L)P=_ud48fC4H~E+~kgc&~b2@wMD5ih^)KrKq4%r1vhphfaVLl8_$K6Vl6nX6Njj zIdkTmJ(~pNzJDM0gJ(~6_p~YB`904(^UP2Qd4VwnlI~!IKtKh14&A}Ps+}uMrL?{i zdfYfrDFSvd`i&xnpBWQa@jmk_*b#@ocokYzjS_2;aE4Mm(Rdtn`1=`6$m!*Xz z*-WchX}%sup~r_Rj)D(iZfpWfMP-Gtqtrg7!q&h<+`!bxQH^V;3$d|MTbNDq0{{0K zC0m*#0m|{;%5f{z7NpWrx%#3n#%c?&Ny3j@#aB}+sfus3?&oBQI6G>#XrW|mDUXuE z!&`x)q{z%YP+1P~<&Z~lcXj_`>xm{2zHKAK@ZU)#z(eoete9I}?yBlCSx2iIFtl6%1;{8t^!PC&k^?exj zIRLMysHkn*w!!zC?eGcUhzI^+q05&;{5N631QG-TX$t#yP^L=x_#r@RNcB4pu4dg$FR(6l=IN6nd zwVdW@6sP3M``7_pkM)I%ON#AT7^n7X_!Pk*MD5NaN*LWOR?(~1b1$YHwppw*BtTu8Hwi3<%hv_ZwZ6`;x&^ z`XAnS9Pht{;t=2;kknAnZA^iEopHA#H zwzHa^sX9$7dM+I2SnefyE=`T!jn=K(rat1E!g{a%ZjwEpM*$-lT$rVL1Lcdb@+ako zIzxHzP)`+EcM7CO@v;jfbyEQWIX;tc+jejcZ{~d%L;UdCBjLH*IS3mmmiI4;G7UA4 z49T})&z!h@jt-1$|&j1?Vs$=E8rZ0 zY&<#7=won{n|3R{^>`sxFaGR#w~=rt+i}>Cs|R3;Q|Y3^(R)rxf4T3=qn>JUy7cSW zHoc%@t95tYz4cf>T#OtAo8p96K90pY%$%7CkG#+3hG>P!pRw3SHFQ!QAiyi0AtS_dT zxz3#IV$@hgWkqp*0ZCn6K7!UY?H~U*dR$c0A11^b71*c`9Qtgtdw8>uFrnjc^rxph z%ISaezF#bD7MT3Ubm@S45jm0}@f`hO@4%TO&+lZY3`f7(Y+Ea&b_yK`2ljdKjKZ0n zlQa5#GO)gna*<%RX`4PpS zRsdhFB$6OFn4co|)?06(aSos*7BFe#$Z0{-4>9mjpXs8Tig^^D8=z7o0Y*hdafbOQ zSi8m-i{~|?i6CHO`0(KhrTm>ed~H9s?jqI#dBvM00UEAOv%vqKNCKo-kXg5p4UG~c zbU=aRpJM*F8+V3Y4{F3)qBEbc?1j-^@TDsEitupl14J{gGvZ@7@gjqi1@>%OkI}rs zb=8*g5?A8Y7{dqgeb8Fsy3}I=?Ta&@7--~_0tE{3N zzoeg}i17I|940Foz)NOR#vZ%!{G4-simI6km)Gr8|C@MhK#Zj=x{yf(`NwGx>X;&# zf>effN|6E+AwocOCMc^j#!!3?fq{WMfJzKdAaj~ClmIo{t3OQ-qgZ z;+ps62W{tfT&9FT1ebncJt@Ql&nUQAa7@e{LqE#jLqkOXwj#nhY11Af>M){n}vjsK|J6n!uU8#AWk|J8S5zM#|7O;ytLHwa}?@83PCXpJsb`oz}hncHCmYf7gr316qPlIbY)l2;^KS`{nmgUguwB&+pav8@=vMa|o z4H`Q~Cx@JOH|+7Z$=;LGgu3ZJCP*S z0z(IMl8SI71wM@n@of`K34ymxU!g=`Bm~;IHBMAqwHq9Mc(!mg>03wwWD0?t-o*_5 zJ$2>}sSuc$AiI8`UsI8)idM{&6A_aiCYW@>^;qrq&nnF9hNv)~dycKs@Xn3&g5&W-KhT0k%UMgI;@?f~o^QuA@GK%~bxQv^0|cup&%h>lC8dLBJ`bZBTOTKJAs z{+PceC!PZeyngsb-|>*HmW?ImGLPVc0@)Km^!D!#-!hd>*mnZFD9+4*xg%6Uc#<@@aC(1nd- z903I)=MHjh2agS6UBz-NYKn@7{wg>X!H(3WIfQDZ6o_JdNFnfXLEf16hsvCchB_`& z2)y)fUh2m#dxTs$4+@w#-rgxhn*Q|a zMp!n!;d{rDf4m8rw4N z-8Ylho1R;@@Agk%+=4?8^sk{nKxM&0Yx&>wP#Q%7WLnS!6EN#ZVl~F5#v0Nnh@&da z#@fczS?yk)UX(&_l>g!q<60QYX-6q-O#KgS)YR6ZF|D*5O8M`?MbQKfa3&#vAte9F z$!P^C*PNQPZxsEHSzo05hlD_i|DIBjK>UZ?(C8?d_uqeCK>|elH*@ApX)tM8S{j}? zt8mEj@^TUZ0f8lZ3uz&T%$(Ec2uQw#XQ<&8U7;s@EYZ&?e)nBCYZ~DoqQHQ6Vf^@~ z5nqFUKfJ*=3L6(O6412n181M@d;bUozt0Duo$zfPWF|QTq$arFa6q)ta*CG3BS3+8 z!_Ew*i^Egy5&w0a)(P!AxAu~rX}X{d|G~T(ntZq#y+s=%{zaUp;k5Vt;|M>5oht-Y z6s5+-@8nx95&_Y5ku-@B5Iir;e-w%-cNnBXTeO7J4wiI+ zqs|X_G9;l~q;f>o5HPQ>x;1Ki$I}Ek&+e zC%48txxhRpUb#-qQBM2{6Rize#7?q*?ng%2Ei30xRG6u86w}^czf8Jw>09%eA2zpE z>$&SQm7ORRJyu$2yUWfMm3W$wOY4=DjK=fVcUCcf;kD(ApcK@yc}2jnU*?V5WXon{ z1E-E%(Wmfj-M1gAcX{#ropcEf#SH~pGK^uwr_bK>X5+T@<~ACIoBWjSu-r{%-r>7P z9x!Cc{fCDAbCSw3+@bG_%qp{Y!zz_!Sgsf|%W&&XF@#UlvW1kBI1?&;q0+ zCy{%u9y(Abehvesyi6Vl9A)p?A0$}A=$#)I(9&{MDV;+~T6&8!;IVp6VoU&#o*T02 zO8Awoqv)?(J$gW{-0H08c>0>kssXIUKbS=Vn4=|Q+REenYxQW^)XoSlDJdZ-@X3=W zRB|8%{_~h;k55Y+CaGjAxzY9;gfYSzwo^d*arWiwYofPUDhnP< zpMNyBU39^EwX%6|7j$Q@_S0M>M*}T`+#!{&ID;NJ| z&(dPAo(S#OPt7MmyP@z`+*UAT)SGls?*H0wvXx-k!f(Hk`;+>ngC96Wz|mdCjd~`M z)LF8J1T6=JNhwf0|H-x|8&;|RuzLRE`<>hzHPzEhqmf%;Sg7XWB}r{;Y$ytB;vax1 z5HHaw(5F3jX4kLXN53Sf0}mgz={Mlk2_X%8x3O@3=Q)(_&0x1roj?Kr@=zzpvsy`>O2+r&%w^2!>g^-7l{COSQ+!hj&&yg zsTmTO5Go|~iq6uT(Jy9yTReKyXiR?SMGndVJpiOYFVQgW=tV|XS_fqhq$lIjfk zk7Ydn>Fv(x6O^K6)F2dUIO;KBWDkE?M_r~+?#-H!ZxOqL#|K{1oM>%eef|pYQuDlS ze8-FGU;}Rh77QMvL$82ga2i_S1NPlWxy)CabDu+PVA$J(oLg(btN&s?NM+YMu;xd7 zGYWZcudR$#zCTF+1BC&-6h29+5x6`*J)R?ayJ`tgF=dL9Gr5a21EN7OIlmoe0bP8L^QXt|dIfQB~3N*=3XHU8R6pVEIkp@Xc!;SfpmXziE5r_lc+&F`xK*WE(eY8vt zzz%K&`(vfjkQ4wPR&DVH+C~x}>_|4pl$I;yLk1LxUSNBg^W6H~c}(h3YLDMp4PHqH z(y6c9-^uHd8PUSjmhSI&2Icd>H%Ibs*MJvC%nwCEAgKi^j|xCBKrd=wfc3wI_ac-# zm>(^;d!ZMb|LVAaA$-4Dt2c9lF%MB%RtjF_6&2(Q9|F8=tZneCR^H4Blm0$_sX5AD zct-(BV{(bJan*;Kx1`*O{(ohNu$l2f4dLT{FU$b7hRW9lDvL=jVD%hK@*i0@^9u`1 zZ3L(iCD#Z5qQ&uu7_&55ny$P(yut5F`EU5N>Esbx19_bLjnAm%75L5^~Z0W4HKW$^B;ge>5za%Ky$GvYk}YE4Q#lwR(5BsCL)hm zXJsdsBK@~0k5|F6*@jnt&!t+31w{Q|t0 zpAQ%+5^mjGUAe!kzNS79@c)33T^-q_HI{|79n6#fPj1}*EG0lI2hGzXY-I`1Bp2}U z-+xm7Vf8NH9s{O}K(kcUOc8RWY?UJlX$E3f4-ZOaqv&eenx!d8N#q_-4gvph#6reh z$Bw0b7Kz!^nMj2|so8sLz|;3~^;EC_S?U8}t{gs~p#L$&KlS{V8!zHN41Xr^AG0v% zaJJ~=@g?w+01W$i6|D}sfH~|J*3cb4*g#Uy$|-9w3yzsS4Uiv_0C6B7Vm|OM zk^pfaAZ7v_2naUF86l9O>foW*4ETllu+$^FFkCikR$cp$lX&ov7HHBy)~GrNAYLi~ z8b)*UNkT_3u?IPVi%W`M_-fd$cMhEW>=M2%K!HZ}VC8{OF+#o9L_HF29vA5yl zgYBK2b8>UZF(+u#eEdvUAlsoSUF4bs1W)oa1mlS1yukc$O%koLb1k0)hp7T0`{nPn&q8O#t`bAuug{ax zR*NcaRkZ+o2mznXlL`zP#1IJeH`yl8igX0~HEHkJf_EGgl?vBiQ6&sEN(+P-iHc&z zRhX5B+S}UswDCd=*I^KpH!>a{Wj{EXlFa<@sV(10zbp4)NOcm6*#QTO(ls&VJ`Bd$ z-hO`8R>GoHlq#EJgp4n!Vh*MHVf$Lcw096pM3D8o~{>7(V+ zCVs#ocKnd97eg?nV)+vjVgJ!*a$n{z9Q}U1bm!jYE7CV0W{?%a;6)Tj=j=^GII*i#dNx zt_Q7OThVj)tJ$d;?2>%pa3i)A3JpbVwegz_dcf4 z?ZCaeFlRoAfZ#xfHwe-unstjY3-O8#wX8M9y>q7!D-O^?3*j0cw;hINQOAWS9p2ncfvRa*1l;b}&sZP!u5FYMWG68|aK zq0cvywIcIgc5JkuJkQxEOJ=Cx@`IR|1h4QQEChC)(Y_u}>iF_Adg=SRqz9@S@h;nI zlYCBg%w3u&8|dv|MSw;)!T4eLADr(a>gxUH%BX9URK(deSe(V*!OHB3+oS)*>&*5^0VO)LM#o* z+0t}N!nfA{D0_2y2S`y{&RVyRWOgNff&RD{C>Lpx|8Vuu>a_ND_9b?C>U(`~IB5+n zu*#BtvLLR^XblBTf!q?q)a6{hdWn4N)1(P`A=sZw9jIs2i)XfN#r((Ui_;$=zzPj( zPBl30uI?A~2-s?1FHC``NK@wG?k;t31OAhK^6H_(p!BxuH<+S8xzm&Cl$if$t*1pW z^OMT_N11y5lfoZA#+xN1+?7oVgC)QuBAea;*~U~q77C@LzVD3Ey+ zz<^5b}kJbLpO29mTV)1z#oV3 z;G$-ll&OXaNw>XxLxJKtJR`NgFW60mBA|c}8yAh75U60=78>R%E#Ulz7zutwO##*1 zVQb#E+xx5Hbt zmI`djXodI>T@I$e3m48ZhcuKm3kgA&V{I8)RuN0_UuZ8{2xRJiyy#FY5(4YTf8`Zr zSO{eD-w!jFc?5(}J7ce3AH8IJL-=phKj?)O%q$FMBQ`V_1o7Vty&>#F;hc#701-y% zjpRS{EtEAH+a0Uz%-bX#{U;|UU$a|#^p_RjB}akeTT;CT6e#!n00qkZ2~eQ4mBbx9 z(?)y-pV@_9E@A!yJx$lwJ1b02!7V#Ue$q>jT25@<({6>64p#43bO=x&WBeLGQzqg+ z*S1>pGWz3A;q+&&?~bm=W9t8wER!wkCJM(C_ILk*q&m{Vx&{MKBln1XuhOr-RRN>Nhc`*&kFc^9w=yvw>3QvQRW z=B7%DCet9OzZ|Ar-F3p(TbO&X|2xqdMfP^~%KQf~OAf6>oslvAD=sZT{Kw<<(k;sR zA1MTys{f^@KVtHqf6r!e`d?0B9+UreeSVPQKi?Mct$O}jJ#~3isd4@jR6r_$3*u$D zgb~t7J=xh%e)I5v1cukxm1=>MwJINnNfBv*oPH@@k?ip$?^gm1x-h<<2R*{5m3%LH z9@(WSH0x3=uptI0aNh^VAqBq9_$xKRQ%%-4s`EzD&VetF@hX~r6x#QnJrpFsh8v*3 z>xYg>;Sc+Cq_%3xvN;>)W8H;(SXc-|hTOqc9(9NUZ>)}E_QYfcJN3ehauPmL2sG)2 zq@OWN$I&DW5)OKKo~JNTq?1k4Y>vE$4sZ) z{h3*$V~a8TtJL>sW;%Yo8KJNpHjaIKIW*)E@Ah}twU}wm;q)nkBt%a4={lf)a-N(o zwXT|&t5aR}RInua_;oX_w)j+rTw|had?rzFX&=G=Pw5wW#u7SPW4Bl1@(}!j&eXF~ z0G;R`Z`(WiHsT#<(w6?UCf-AtF_%mU@Zjpz%+dJe9Wd^`^Vo=pp2IF5;MM)RNA9;A zq?X~5i*D%hToi;4Y<5pvCrx?HP`vro*b1z()uXUn^^uylCV*=uI*>vot*orDBz(Tg zM|p4rD$S*3rNPZ0_bgxZPX*l6>a->KbU>jr-p<0pA|Y0^Y+6W*Ff}*d+QK>`nNNQ^ zU^=9W%LigZdeZzC+N*2)d65u!`}|>@6<1x(=062OO}?JSaaMBrA2uszd~z1NND7p*+t)50n0c8w+&?hma+6K;)s6ach{CU77RRI1)znTj-x-t^X-_W~kk07?0DzUnRa%EwY#GBlo4y$Xf8o`i z_|;in-|&i^h4qf_*R~rvV9&dUR!#Vxxu!71e~b1B!2qr9R;^g&uP+zcQ-fUnS#Ku%wfO?D&wk_C$ehO|ZfW8Q) zfi&|WZCH*1k!rI4@37VN?W0AG;C^O7Ncl)U0-LptZ^J|ZSC_?rR!)tus+L(V94BSU zdh1@e+k-b&I_fi1@&c z_^;EjVOI=zE#<#}02-nEgXkI4)N~LGqaH8PdDf(Jhnd2pvi`@G4ALJBm@+WDKh37! zzp|2|z|^Y)vrJIMTc*Bm0mt_gQP%Fo)l1mJNLN${sS2IYIRNJBj>TBj_dk* z=Q`IL3PPZqp>Zeb&T)?}wAcEwS`cGeNDd13!9hQw{dIgGAZM5&Kv}yX18yFp-94H2 zA7|(0c(}NBoz@92PaGS4t@}#@(FblGyo=~Z*)n4iv~iry8iqq`5X1-F>Sc)@A1Micwg%;L7q!k^(C$D!aYc`TV~xW3h)J1mf~@ zHQ`@}mSg>jGh{AA{zLVz7VVD0Ma{&b| z8NqA7Bnx7`RBs438!~@l?AF1E0>K77G(TLe{&zsjLwaK=M3YPQ$;e@;FCpiDghea& z7GIDCPw9(pFBA2c1%nC*PB_nle)VTnOC#Y3Vc|vCjEw&K3|t;C(nN_PVIlkNokH{dfy z*cIYGss7jK1;DZZYSJ|voF1-omrRpMNJvomysfOP0QqermglRjt6yQ1^IFmh_`X#G#-FH4~zRe4Fv*H z!CodArTVD(3dTM>YQJ|ZmeVh>jl=2MMRiqq0(c4tEtvJwVFbh!xMvZhw^2)YEwJqX z1_gS!x={(7Lp!vm)Gv{<-e7Y#i)Iancj+8^3!WHCd^qgm@c;xVRR(O=!)3qoGG+~@Rp(E$!d zEgdCvLV6W2ph@uM1Ex)Kdf|hi+%vIe{>?DKV1bKg6TdS+yH9==u>}f$B7rt&%pJ|C)~v0Ixrt|M30PDdz#7GiS~! zy^)NCHh$5Y(Wl<=^Kj<=>KcAb3|e;3#N+mn>@q0|Y}UWu*avWwPeKNiQb&u=M}I58 zuozGv*pLH3JPHR#M8ka~t=Cw|_LugaW{k9d-Qf`_2@p-*RKMf{Gj=B@Kd;;0p*lsX zfPMc5c0bC2fXD?br9iY_N`Z``6CT=oigDaLzximliLmI8`u7k(f%J31)|M9@TK9k_ zP+i8O6&7nT|A7regjlPPDkV+<8mhQ^w>1;w4Goc+vAe!e(7(0hgjgJR4|g&H)~%Dr zeA=?_CxE~7Gc`~MRHuqj-8?>dN>yTZ@X`(p(IhCzNa+!cBQw%W?PI#l8&(!q31gPi zxuD+cnJaU*%~=t(3cT?BSGJAQelK~Rv3WbzlVQ?fRcZ*KTrJ=`&R&efc(@8 zfmEm^8Q=jbHK_us!9glLdjkzifC`3GUX}325gFz&4)XVHkS_U1HLn7KDzK0N;=e8W zkKE5n{aoaTfVo#e0t7vu+&nS`0Alunz)~(;GJ0Dq>>Ko?etnm5XP6Qo;y*a-tgOTf zb7yH&8(37B*BQ{8^GYQ7%9N(}@P6cF^4Y^XmEE4U; zjAMQnjbv070E=9HXs-1YDwks+{Dni?;iI?rh0RuR8lM(n(noY4Z2q01%qvXX`pHh|L-1f=K6)hm%CU_{<$kUAo81uqAt6xB3H19|6#5X}MJS-Qk4+wH zDSb~K#JgXh>A4J}pO3|N){}fDNZ16mrl>h2sB>(+o&x84Sn=sAx_D)z|eqXtM z2Wx2)q;}NrH01cNekRxd)z6a8T>4WUjWYiMJH2(!)8jv<>ZWQ=(o9_v#A5liBryLm z^*_XaqEVlV6PZIE^B-wU{)3;45|LKZF72E3Zm)bk$jFtSj2hGb3#x`3|4DZ;`S0=3 zA}ov4ga5#zmp*;)=%r5|z#o(UAco};T+du0aMdbNge>v}Q!Zez6Dfr{aXfpMFIp@2 zmw*B(=LmK*017;?im~k5j`4>{9|9Tot*1cxSy4_jYUTl;KxDvZwNLxDa*586%}*uRZw;ApxNkYmMhi+=ObBdHb$C{SVaj}5znIlV{2tAn!~ z1%eVURB7Y6r5I0#q(GCxUtpbg%9E=GQj0wttn z?aKxAQnNSe2noT{U095mT1blY7?9iKf^xvpu0L)!kd7pI^*?Vg&*Z?W)zY2KM=+E* zPj^q1&xJYIU=A}{1V=r+$C00XDKMCC=rr1T{s>wf)!hYlkhV7L-20R+Vrgu2rr-sx zht*>uNc|*01w*&DwwkeYtV&CKlo-$?;H4#Vq~$X=ol!n}yd!cu)^gQB{*3!@=!aDe zETT?fP089yR#kgD2f1b6$m;3rd!i(^V`vj+}kX3d)Q z`837?Vm)Wksrdnxp+@=N9hQR^NrBXNabS4r*SP@rcD#5PyhsX6eDu)4UU-T>4TYj~ z*m(XjANrX9Y z5r1>zw*%^hz5K!=a^&jJG_wozRu<4K;~e#n7ypc zgRRwa5$>otro6zE9B9-`&DKlGfr-a&HDYZ)tf=#M}ou$o=WS zN57l;YxP)4tHLRdYPQsT>-dIU+<${9J9Z;_j!^$o`__nJMk#UbFZ(}c%JQ}vR{*W0 z`O7wjxAw4C;u`Wl;~Vjc>L&pz^si6Do*4%)`LC?J>=|5ROG5MWa`Q}0PFDEvp4Dq5 zWL9|X=wb4eo|{2aW7Mb-vtDZx(H6YAL`H(wr1$2i(f@Mtb1D8SC@MhANAjO~{qOnY zKQ`JLgjF4RuPF+YPVb;>{d!)-K@uP~{;f{!fS4mz>QrgGCt4;2AfP}&3#>EnAMw`c zpq%1ArC_hRhVmbLR9zyu60X#aSLu6=k8C&vD$g7wwLnaP4t|Wh#|rLXK!Iyt=i?sg z9t(H&!m?v>LLi_((jBbE8dnGe<009OaLTyj8~Fp3l$F?7(~|}+AKU%(+RB5Ac?h1k zXwLQ(t0&BVGc!G17tjcclWtkIX2N_J&)#p`wBuX(Iy-dI>|Z{hC#X)I_YZ0h3i_rZ zb>xvV;J^P0_#=ft(y^`- zm&BY1Ov--Krt!&mwOVbBczSP)&V&q7*d46j(0I7HDl|mrmKa}`G)E(-S_;1XY!_it4JzwIBg$w7z zFHI$^|eCWLnKOLs8|PZ zHSm&5yjOTGa(A-4s7`Lko_yvKvu-@*E|b-RnID@e1U5<_pq%~m#!9rLqq)s<#55Jf z++U_j>S!^cwyNeiKgmrWe{IqPAm5geX?Ni;lGz}0im9pO>VE&lvWrs4dBEjj;5d0d z05c*=B?33?eY&)wUb8ifMexolm(DRgt~;2Ff^KLmf+!or(Bh`Gm*26P-MId*;$v z3RT60h(CX*BWgr~BKo{2la}Fmjaf3Bc^^6s84R9^T!;@RAAQ0hKcILG+qOgbQ2Ott zFO_~iGni zFb90yhl^R`en!Jrl)^V1^kS!d&w(>YnFM7W3+>0~Hh!Ef zLWHU^(B^Vwm1SqP?Xh-g1l5*l8Fyf9_4bb7Ys6HTbvdarw$TrC;rGKmCk|K8JdBzg z|0$UAn4D?#sP!%Sk5%(A>5}MnE{u?7hn1Z z9~O_qIjt|lL6>)5P|(TZU0hNuxB6L0Nr{>|TT)W2rq0S8sI(xTBM|U$MkW;ksLX$8 z?KqPE5>t}{{rnOCNw4VWT6p(PY}`dspoh0ldFcg?6HQel!4%o;wM)-RAr5un56Jl~T#K@C7BL;s*19IO`o& z*4N+%I;~?A-JPEutU8ioK%E*r?`WQcJORxS)2{3n;KA~)b*618tpWlNq$p6D0vaoS zOq0ri%4SghIBKo1)-BlC^1e>~bbIv7j7n033u|sNs=TWuCvBp*+}}VJ%uF3o_%5pOSTZVZ`}e`xw0`L4iiILewKXUx5PUOo0OB zOm5cj-FsW4LST>4LLF;AvfrOIYWELocVYJhpQaIw^@E81rIS2{O`g5)=hfW*A?rSB zw8~G$-KUGRgQO#LbW=Ndym_bg&*18MjO{^k?ZFLjE%_D`gBt$JOnLjv=KW;aMU~=* zksD=Vm6wx4l+C8GDID-$O41`Pi3{lN+rXbP*O^me50&=YzgA%iWb&VNA;5)_h99WW zujuaes}kMLD?42n*#-s$QG)I9t(!Uy9;QbBBj3Vj1bUWZj7Zax;wL4=ar6M&z<=H? zJP1L-%(pc|s0RF}av<7g$lnhAazy3b%T9m**L5m%`rZ5EULiq&&P2cxlmAZr2VQAS zM>p-&91MR7#{yK17h<-#XNy*c;}H-^fD{E{ah047jJ?1LAP6XM?p)|U9qK!qR0_c_ zm#$~%_7m1m!2B*00`7v%bhEFyPnZna@W6%-blHb7rr|Cw<(AWS6%GGIbR2vjgRG*>V=AyC2UAp}wsNC|=Y zhFsz$Wki|Wu&dmVV!Ubl<_`LdsSmDR-TU6}I(>$Xs#4yK>((T!Feg@z5up+N;9w>$ zG0x4|t+=$rvz=RsViG|!Gfi!6oyJUq5~tt$1O86$UObW}>Q$dMlZ17*{4{+2$o#^5 zX>1>`;d3VMU-e7Nq22MGieeb%RZzs3HC0+xI`zZ((a~2pgBLisS@7kH7n%l&vQ(1G z3R_qRHBKYWC`KNF3{jx+$bduOZE8_eYW-rhlB!`8+K}aj$?H;(07+#6{98u2CUqA4 z-8ivSSVFV!%ff`m^SkM2T??Igi%D#%^W_5YMVDYmE;aY)mf@dkgK!KPR_0_u4)c+>k6HJ z(Zh$a9r|?9}bMZN_|S6VMDdj?ijRh^Uum4LV;5oBjxzfCho zH&xTE(vwr&!s*FFp#wV6g(tJ-$i_`Ro!h91D?PLGoNy-->DiG!VPWd7RA@;3BN)ML zzHJ~4Xm1F8b4h?Fmu)|$Hm(F{>jhCb)JvG4TIT1d@@E13 z@ye4PeI6&P0s^V6`Qm>@zDj30%SuU?eo|V@j9PA9E=gwfFdJ)|hK!mZzBoEF+lPno z_nQSb$NcB%>ywoRuiD-Pb~)qb&fdOaHIx7N`yYLaq`+>GJ;;U#@t@Y5p4#H>>b`B2 zXywC430Z+Y9i{%?)U5QTzH~iGy$Z?Cfu;P)@!!?`(V)$jb_d0!v_5xd4=;WG^dZk4 zEjo8JmH%=Q^flUoFO8RGXw~7{($-B zGJ!*GB+6tC`c6!?x4leJTA*DbycJK04$EKc~0Rh$Mf1w@P$3|bXb=9a5 z{}>n21jd!Z-rdg5u7tJN3x4Ft7fhA_#D7syLXaF81-N`U40n6$t+%9dAkr5}5S%b! z0-`|7f6_t@{=-q>>$t^tH^4Sv-||&*V=t|a8|W|}m)+c4gVem8yI3M*pNZcEGX(~} zpd-^GBL2hfV57nQI2=&SL!Js>Ir19~AJ}Kqx3z2_U_-pX3R>WVZ(l$Z*m20`g zXWml3@{c74SDiNVWE`m1i|pv7Ul#laiJjE`G)`DJ{Kknp$Z0EQW##2^e0D>LOH-@}e^Fm|3XZ(rnKhOiUQAsWu}=4z{+AwdHmAKotL7J$#_! z;9*k!3u+pYm7awUbn-XYCx#F1u9E*eTL&RMQuGMwG|6cxObRR#Pkk=Use60td(>yH z@4p9I&X3lTvL6k*HnyPY2=3)CjIj;d(q;$P`R}iuHqc(SzU6dxaqTrH61>Qdt$lr! z9RD5JxT(u1c927}PW}(CBqRRg@N^I~EeL@i(_O1(1OO<|*OzWvjV79AbXs}|5KrLH zKP8zlZdn~}jBb1{oOZ-4^P@$}5CzJeIpjZ%=0D0X|51>qM)0FDUE{bwxB|*a{!hMr z_{UIPS%)dGA-1^H64Bc`d{3Eq0n)iwS1rG-f#gR&Vk=eNe=pb0y=Hbh{lj?x;!Fx; znuYU2K!JV{!H5ERoveSvo#QuD{(>)&R=yym(8aS6GR8%Y9DZ>xPl47=Eu}(WacK!D z1VRGt(l++eO)La5^hkX$-?P_y&g}S2?oa)ujnB$RH$nYs6LISnd@l7~i|qe5QvS^nmUNhg$5Te+Q435lKB7*N>`a<@}G1%2;5)ClV94&8t_u4K(xRe zZ+b^c*ozG6q5=UC`2idRFRw@~Q&*MR#l6tsE*-g|*#jz#gmR-+R$dM$Fgr0v7-msQ zn?`i1fc%`AD24Cr`Pbo5{}?RYKl$r7kPt{$V8c+}t9@%M1jZ%CDW7)J_RSehiA>}i zubLQyK&CYhQq|cg<-at=(5Y4?)K~;*E8?pygJn5>;@tW1v5lX0klP`KxBXdyT3dIY&deTX5<&< zcjiWt2SpL_r@rDT-nX|l?Nklgp!|lvFW61;)19LaC^++Q6Iv^jh8hcjLRLb38X7=; z?CMup_s7?wtMmVwe?YcQd=m01A9~nvUXjb8>O( z*ZazI4jzfkS8u2hvxA@DL7Q62zs3YDHu;dq1!eujVT#Tj~z@T0M>;_P5 z%tGSo!?~Ava^=-=2L+KNvU%YW@n>$R0Rut5QuLvG3yRh!I2!m>>E14s!9uo(tIa|zs z8RD7jqduC-DNLM_mm}2kA5#LXpSilYkiKBq=bM*D`hrCbse#NWW9omjSjgf(DCzYU zC=l@(W*i=S`Mjzl%4x^ zBcedcUfMI}w^2L6%eR+tcNgNn@n1vg{r&CT3{j0JP7fa?lGq1W5WL9T)M5Q$2IrER zhfE4&dW4@8Bwz}p_|K>T3S{oDHwB*l0b)e2nceC~feml7q;ouZ+2B_E>PhjlH?dts zAuVA2{PnXg(fI$AQL4xO=S!@^v*t zKh>#(<$YE#&sI*JoKxA2+@c4x45@|DVZ~ZQjF^oLoHvk>n&N0!5x88x+&lQ!(_I+U z7K($J$Y5V`TOq3eIqT5c%DTKlI5D{ch4&N1fS=lYuJ=T`5AbZ_173xNg^3A5&2o2k z^&8?-zvl(U0Ms6TUs<4O+PXzn(!Hlwc$o4PnMlmpqUX>f_#TRz2+t@d;>xNeEs-NXY%0^>pi(6~ZcP z5v;0zOuLcm=MP&da-D7_{}sl;_&id9v$u1wv9@7WC@Mx@Tyu5AwtZ1iF;R1c5I`#C z&%;$vK#B~-@=0kWb(GpV;XuVD#kRHrvmjrvU%QSJ@nimrzH>G1XmsC~M=9`MW_G5R zhtP(gMNr+tn@KbfbKJyQTf+v>ro<-a0erGH9Dm2|Ub@)xr6CyKFCI$ij8^;L@3o>cx8+pb z-3`@LIG{=jOgmNM+uH~Q0{8N+zWyuE@1_>?UzJ=M$0TWj_#qVP(KMAL(l9tuv4)~(y7K7yjD zpFa;h32_gCLc+M`#-eY~PsGO?cG3-?dppEGFeN?h8C)-O$(A-f2$iJ=hq6bWT70-wpodQv(`MjOVu_PKyHzpO3w*LV z!M907@QZ@9AHVf_!q)4W7Em2`b8)k9<2{#w9a`AS1gN2CdX-1qzGS&vr=#BD?;ojt z6zJE3kLwQ&r`KBm{1@0e02e}3_9#=BhZ}u*H+Py*0;TJJ26POdJA%ZjjGLm7DjK{s zmOZH|wNrNzdVM4+`d*Rx;a}5g$$^_vGJVOuQ{hxqD&# zT~&{`Nx+0pM6*tJ=n-(|s2_!cy0YDHHLg{FHRbqEZdMH`1nLmZBMQV4Af~`+)24xc zrF4kBz}URJykZQ5W|IDgv5%5T$Ry9*bkj%*M2>0X7cMtMkD*fv3=DLe4U2Eof_JF{ z#l+rYQXuvM^Gv44LFAXTZ6Or#R}W4gLB1EUjPJrrd~UX_@59K`$Tx>l>(L3U{Kb$( z;#@YJXA28al*b7pBxfh~bcY+K?fgG4XL4%ko>SZ&vW)TgqAv?J4)zoUGK~}x{xWRWPhHn)MHOVi{2530uKjb*>f9&C z8|8NjlIu9uB>J|)*oks>uQ>>+kx7Rb{@Fn0ez{70Y4`PW+eHgWZE@6Zs9iT^#G`Kxa@(!5^5SWtTt#JtzALRrdYDjJRvLRB4xhjVcv)Lo;g`Fs zJNdG=v%{~FCnfj=Mwm{7l@bOHLB7x-qzC$oIMtRJ#iV)8j?T(ozp!)vQ$4--t=EF#O4tpBCMFmt@qH zK4$k{O**&N=|`|SlJ?}Bt;i9Kv^Qbcw_9|bOyy6dAdh^(q#P(xX!P#jS+i!Lx2sn1 zVISoA015;?A5{}^PX(}*tF9%aAvgOw&PGsVa|;Kf;zneT}XG2#Zp3` zQA^m9NP6cDo@*m^@I&|%db}T5Ra0TEwLJUzMZPf9(d8Tkyy9~5&zlSD*B_uYtoh&9 zaC5iKxxDvMO>K=y*_8g%dp))1r9E&K6+iKa@ZCi%8)fv@V&m?&mw06O6ygSZXE#3& zW^sR*Bz*Dlf2ujp6;ZJAPFed>!+Z3d6OV#_$7~izB0VF8>5pq%(^-g|E?%vCQqt3s z4#L9l)|S6@omQZYMOWrFiUg=&SOP?akhFT-ZLAM% z86)Ts6LyYb@*h=|fPof6Axa8RprwUnLoQY!gN(xTfLhpsX%YWXe~L@IM{LK11cp>s z*ZKLtnu`zAJOqk0g@r}wk5e%JF*-Ze^Rx12b(55@d_`rv&A zfQvo%9U|Dv>?AIM5kl+Mtply|z{PaL&(V+IM5MXf=ipnR^@Uw2O3^}jglT0pJ(UwD zwZU)w2kIt#&R)(7wqF2u7V?p&SC+!ebKq@AploFK<6Ic4o_PJ7l>e|h*vqYB$^)1X zF8RzOaHV}d?7^`TsUQF7G&(&g0+JNiY1puBZ^K3^>YGt$QALDmiw zRpwgrmp@}n-}$il=V$}ne00NmOpiRf79y8_&!%X`2B%L90q=7tteMG&)2aI}_Y_d) zfvyPD%-`n1*sqsX@Mq!|$(|puq$BJ_975rhx9J5-4muxjVl5^GOG`LFnH$I8lR|FX zxa-lj9C9U~-Q@@I_I6iX5+sRLb3I4u2G z`_4UR)!|zH+G#Lq=dI0uD|IWutsgEYvwoTm{{8-ywPwS!brcql${a z^z!9IO3A=Ze}2L(Bq(iHeBgN4%liAkS&-=!a0Xkm;O2#eg$@o5xS_uE>sjz`QEUyW z7mN13$2``dDA*UePi;#L5yvcnK_l0W^0zVh2yC5DcuC&{1Dj*(-=Glh!FUW$)97ugUt$tW$a#77$RmPKgL9UvLAF2neu@{1}OV6n2{t z0nOwuoW3NQ6&KhfnE5e$EI@%I|K%4JQ2ZA;Qg9*x;sigkd8H^Ruhx?5GK}G9q7blM z?{?MIj1VB}FvdIwX~V*7RgQkcPik&Iw8Mi>wp^`&Cm%VlgV9z6-l&&FOGs396uPb8 zNQR<;5zwz)M@mMua?~*SkCV;_MutZfr2e->Z_+40IVK1O`1gadhZIQE>rt zn~6S(E$^?Eqd;tk|9G+5-L>#>u5%m4Xuw&YZN$C3i}cJudNEx} zfvEp*2;rNpTc@ue3T%jB{?nKl52BZ*G-?FXFscvE_98ew($g($Y&^WY5e34_za^Wp z8}(JB0r&$H2wnilxMyOB|HzG3e}eP9ejBxuGfea1OZ7S(H8g_T8X;@CkWIanAZ<3T z)%um2r9Ks3HY_tl$wDlmY`Hf@!v2Vbyzk}O%2@nURFwqq2PhD{n4@lKn}Em9@X{mTsU*K90i(I0gX`t z11}8xcVMO{_VL3T#=pLCx+q2b?9DUL#s#H9oKC zOe6uyRTad4?_He-DxsRL5s${u*cZG=3S@uB^x2K|@Z$)+8x1${U;F~$DHkMD2s<+P zkJG2wWb&UHv-jaS22dc{bMlk3e5LBHCFj*+r!bQOnMsc+{-Y?cBw6GX1{6q#Rv1Vf zJSjkdXkXi@;iwoSpM8YDC2T;5Z?m9jpS-r};^XT>FE=EW02`D4^tTHpNY~%M zMf*erb@SYvsDiz{b8bp<5@(1BL)gT(FBY(+^V2Wz&7}&(uehYRqN)-dqM)b%35Uq4 zYih)c%4>p~2?P2}A|#iZ7m1FA4}rJmY?(#=pp%0r?uY!-7w12JuiFRujnB}5$S60! zf5;DR)DZvSRO*0k=kJ&+z9{3SCQT1B48O&{NhvWftg0OEp7WBQ5HQaC81C+4AaZx*1E*C7*|`Q1-_@7 z$Gt?e8n`D*IMfHJlCEZ8Jsyv*h8YlW*bkjCC43t3HF!xW5Y$jyr`ApV8T|YDhF5SxQ&7KfwMF$E zY@>2c)hTBuXIB>?&OR|tSPB{Zf@o}Sp(EBIed`Y0@}06i;*Pf6p)km7D-GwW)UJB*`wQzX0}24vKq)RBPBgH#lrLsQ9r6bL@ghRd+j5e&T< zs`IqKLDz(%54Q0uzI2}slP8})aturI^*A?an3S|ei@Fb)l^x0YJ7MQ2RC&P$6*XnV zJ0!LV%fWuPV$Nn9z9*@TSM_Il3 z55OPV0Q|Rm#`nR#cJ<&t(h&cZ4OLnxC+X26h4Ez95hGKx(_|44@E`a$Jw2VIKrIn8 zfE~dk1#$BqAPJf=W*cRF&}-rl~r*hoSOSsh*@+rTmR+X6dmn?G2T z!7hBVF6NhN@S-NNC`@7br0r6!t?aZFX5wEmwT-A1>nMb#iK@p!ArWP#E|FxDYEq!_ zsik{J3KZbmx*4WGY$z5GX@PR?;PwMWR}J{jLT66p#Ks6KrNH~YKVr_YPtQnUQXpk> zK6-Q2$172c9dn61**-whg~%Bq@1ocm6bo1n!~BP10o8w(nbn+(G%_M-n{HtIfVu?m zD79L%l7d1zC*#zP1NBH-GGZwb!kP283TSo0iy)RZ`8r@(l;OC53 zK=sB)Me9olj;~d=u&7Xdw`zWS)7^7xFChx#E6cYpzE*jVgXI6 zzf3h0DRwAET-mPfyz#dGJY3qri!5D81>_{LfaFosTZf2FRP{u$n8BNLOi;l5M@nBz z{zJ+iiu@D!PsRWRaxlEg3e+a>LKKJzSSqf|Szt&YDFlkf;kC6UO;(c{<^NTQo0$J7 zNy5^eft&4y4!CvV7`X@eg5~r-zMs1Apn2CYu1Tfz(5CXA&YIiw#eZz{h$ZDert_EL zzoOC#2OCSH{KtepPR5_WMnItt6H_252U1J@3OJ~dl}WIbmX;O~RI2!a-noS%goEQ=j3oIYaJ`EV1J6xeXX${(-)X&4O()&k=a~7|3FKg;AQZ9`)KVAkF>b-iM@?2ra(C%5Kv&k1qKDyRMlYRkJta| zxK0b&Hua;~uI4tBcwLG_{^OGSUUtnbm=wsomI43M6A6L4UWIMnlavB`bLgmYZngOAK0938K_bM zgBP z^z$9@#^i0E{_^6gNz(8B@t+H>4)6jC^m*`I9G&i8=IeQAhX{j!Z-zH|%VKh%gf|JV%Q|r@{5#QwEr1s*OjO4Ly zU-_N7WNE|AY`Y)dW%$uR+fD5OZMRKx(Toi=Nng5n&uh!yVzk|0;MBca{JHak7O~Tz zXI#!sPfukum8r4Pw)=0ty`jFS$Tf*_Mdi%DPlUAZP*VCN~SAc5}uatK2iiEs1FSAcKIw z00JWZV>TnGB_a6_j)({Z#FK2;>KEW74-ba$NahOw2Hm@c=~gpon}_I-R1Oa82@t1B8?cpDI!5-d%!dao>GbZO(Hlq6H?VyHoEcNp@@ghM}XVQPVh7&;CaMp9r_?qg3^ zcYu9Vc4$8@zw9;VJZ5xvvoWHimTrkjce9CTZd!W3@FD!P9WTR~D}0z45vXwU`@PhA z>;Ld2xHLDN-Q0gT`SQAJ{O?4^wCZUjqHfmDZ!-5Y3puA>Pg%Ni$I4whxLwMu(Emj^ z>fN>c$NH66z<=Q1%$zJQH_x~SF=`fcZxoZuG4{OKqAPQ${unpk3U*}4X54lgJ;b2b z1_JbIU{L|KH0leCG6LD?QyHAx2&Zj11^5>vB{RQEjmG0I3o5c)jZkAwjv}vIbtOJ? zP2)Z$jT!gH%FWU~PtL;n2Z!~4Q{kR}o%|^W*Q$oy-_#F2Vs=A0xjFT~1&S3)@0T-i zL49GPOd)|^aY>229s5t$5EVpe5F(Gr{0@oNiMQw*_M0n72|@jNeIn= zF<=4-$rq9@q`;SuKp+$cObGBhZbkh^7DuCgtwTfLs{bh^{sNvCh-cC|Y@JF~ZU zC)tAVKKtl7tya5xyHkGipLgCDR*YT{wDhjZ!6;CuHhP_NfZ_)k%Lr_ccK z0TM+$7r`h5Ti`4c!Sd$V(U)OET;QHEcnu-y!Js?Ut8$l6IIqo#%Sk0b){cF;2iwED z3lJ0U@D$k57*u?qq?jp*8waNe($a^NAmO#s9+=GZFw_5pvsc~QCkT}GIxMNlIN3(Jf>1 zLqcRJKz_-ihoa@Y!8X;{qSLTKAp8nWy(!u_r*ADhB)qw;S<)-C2O?3yPVI&n0+&4S zAnhb$CrxF3v_7@{?;WsF;H@`zd)^1U%xt{``>@G>n9tTt;y_edVSPi~WGd{Y`#<>Z zFZlsJzFpo`C^}oi+b%T`QaynR`*TuQlUMI}1?%}twHBff=%O9?*Sm8bzV8QLJ`Vl%uS7GCnY}AcmXW-Q5@kGU8y@Y`FwqC+6oNG0dH`^Pk%V z(_97(Cl~IEAALh(k-@3d7&H6c+7yw&P6$@kp25fBv^fRFp6@@)QqTegP1MKi7dBQs ze9qL%2k=a2Q&vLSJM@8w4!`|qJ4=D#!C^!SBwC3$+j2?C)wHxB4ETzO=Bx5_k6%Bj zdXp$}H6Xu=AW=_IgocbAowIQCO}j%@{2n@Yg8X5DzJc|P4IW;wcKqzuzsNiCZFsPK454KvZ z4Yjo%w#8no)*cZZbG7$cQbU7Epz}n2zJB1*@xP*>BCweO^jF$d`rM=s4LqXMOguFG z;)h_zfM#4RxmH9wr!;ldO|xi?ubaxtZz^HA)%2e(VuirO;aN8>+sWaZzxS+tSXA}P zR|xR&b@2>apZzCVJ==PRWKppZ%mA>IsVZL|=rJ4?5()|%yHi@^?)v*9br)betZ9^s zm=QA~%v$FuU%AvFA?RE%TDhdoes=1_`+X$@g4fEwP2PyF z^~wQJ(=p_1lau3l3jYy>z&5ckq5rll{fUWW1Z3!$rvWyp)oNmIfh`MaYQn!2KN^rm z2b7lpWz-Q?gXBd=eyuS}foT3>Ob!H}iFuHD^J)!9O0%iuos7n(K{<;UJ3F0woih9< zZ&x-~czJo5&1QqSnnB1-Yh+pvMPx4-Li@*=cQ3^#P~NcV;F?n{tPq$yXmCYov4{fG z2^R$v*!}r=r2p^$Z|iiIB_fm)R{`e&2 z<(yi`#g*Aa3dLGe4ny#Sh}Xfj+4=*}&G7sO>IL{vWlQq$;fpUON_o0Y@B(?2|mV@0(>C z)`8FEZ3V>RiB*-YBU$qa;VBxfa=lXZ_4*|n7q*w00tb1!{>*E7ogICcu&TN}&Xqd0 z$VDe|FM#cTW3yo&AIpTJ4V3h3*$FdlGR1;Ygi#=ho3y0%K|z5!9Ul6lXn%eYlRxj? zHNHOFoav6Y-y1S}qRiE2uDt8e=N~!5e`ur_&_}b^s;DlNHYPP<*VO}?cP5O;@J}pJ z@>&P2PL}R`|IycB(-aQ9tA|d6J>#&s;&^p)Gc8?RmkLf28xxT%weOpx)G^%=W-0u| z#Kjez`c|f!sL~aTnJUAQ zK(#WP=RfwtSP!b$^UZT79D3}40?8WQ>x3ZQ`5!wLQRR^j9B>R(+j?0d{|y9-4I|8| zut8<(n_=_UZDM}3|3Vv{9Odqm_Dal}z))gm^tZkLq@C$Az<=^tgBzQhZvJh9F$T|n zGM1Gy-t}uW(_Q4THC|#}r0>5q;6H2+;6LeMtr7<~0Dma|nc8vwtF0B1$9Q`Zrt$#) zktLP$yHNh4-ML?=QtwOve<=R}E8Krg$v=*~YqUe+pX)~Gw0(TY&WtDpqN*}Wfl>+3 zX`@Mi<2>%h+z_P{h{=BFpY(ct?2~Hcw~_zu4%aEr=@dgwM}Ql92M2#nQy^xi_nhHB zn=ffu36TG(pg`HTsXl^`v;Fa}`w+hG`aS2|cHm#oFSv9oc?}J5oDFRD&xL2`i$p;6 z^%Oog7ncr{Q91tnh=hR*l99{=0fmh(w0EDYK?)C!7<&A5s5f`43%;jPhT6 z`V`vj@%&eHv8dxlnvyTOXA`-L2k^)9pNnws5%1n^u%Cj+J4jirH+LgdW;b~iCm;El z5zoZ46v$@{!6=Y>E21zl++_dumtH5cNXWzJNm#-g#oT$)uvL2SVdjJ1eDE^yJTGqS z^$rF%-uneT)#7@nW@70nLHvFFm^hK5x%ijR&C_m(plPcgzWH^mQ&r9MCk>Vtm9ww0%>W9&2cj^ zm)Q^Oexv8P_+0K~H88dDws9M%p)uL+@|BcvwvsXoBMpqlP-5c&yYP#%P9PwDCpl{N z=P)L{w>Q$;p84Bk!7B)#N49j7n<(iE7KqmI%pulL)IcTOw;5-JdF$4rWnSf>YOZb2 z>~F>=4M}#s>f7{i7-!1U!_x!tgGcLEL|8;kT@A5*foq|dh1O+*!4QBfAGUT1-J-Xb zNFG8LAcv{L>l*9OGLKx#ojo!*IH-sbYRbO%wx~!_GJj+I<(gXHna3_%czU7@ac?o9rj1XGWs71_r&R7%vL>nJ0|-D?k#5&yjE%3BJ)>t7FcFngw6$v|FqkV zXhV|&iEX{V&6wVxfS66X_fD`$_aAEe7xA>?{m3gep1+S=!Jc}B&}GtMC@42aSB5)e zPCEh?y!);4gJrb9u#6GtufY-Altf*l1B2#i_YjI#agpe`5&5sLtn_s&yGpU2tiIvA z>nHIGB?msunmFI}lhew1{_frRNQ=qO1(%m!mkiZ@w|_Jr)? zLO13An>hozF^yj2m}4Jtv_Nj_&z=QapL|W?fC1L}^VR|W#vKZh!t$T;XD-EV8T-w< z_D5(+o;k3i+qUrA#WQDXYpaRzBL|4FNqGCpX5GC^hW~hD`43mTY)9#Ch?=tGc$NP#E__BjRe9pum17Wo*>zgtjQPQF#pe_xhX$Q`oKG`TLbr2)R; zvOHmyzxoFBq^YP7IYBqo)iXcZ_t0oKGH`6wqxTuE4G5P58vmKv`;oclty_=&8Wb-V zFjcubpk7bCX-~Qnwv6KL?n8wHOtu&Cx`(Ih{8!glCBuK10sbR&aAD+icrtUrtc_X; z`H5Y`?VQcIhZ|9Q8=wN}rgC%W%}V)?p9==?N8~>m{7D@o*hCN9o8mvQ>7u2~$NJmx zL0HfgxQsZJFi(LU9UUwMN^^$*3M7uh00rhqVzo>Sxf}dE-1dRAgCvf_00j~oK0tvo z<1mJu1$K%>`e_!p4^zRy8?J8vTY83EKoj36Z)1Z=T>a{$F@%WLtZ9i3$5+od9c|cA zc=nvx z4K28nuD*`Tp44~=uIzCqO~w$Hh227v4)Dq<3CofUyKq6&o#g70|22;9rN>XMdTt%I zv!bekP#7+Xx;?LUf3HNs=mLGY>XAVXec6&TLVBxOTNs*2YoWe)<){?oQslr$;ZUp*yL-gpCVQws4jelkr$QE{a+$lMkPr1OF;)s1fOf ziIJaK5agpqV-(2P@~<=Kq*^_jWWpf|R1%HTAsanm*4Y!^C>H`zk3ebGFTDJd7MoxGsA%|I z87|&-_T+`tU>W?>ly!O`{G+IqNqA_@RiK@1n zo6t$4iQYqkLeQsY5J%NXOHD&iTckMhVTY&QHg4eeZ9Uz6f6iJY3?Y&KzQ3k0psutT zRFYG{A^r=A&vE_hI5Y(e_|J(;n9U|{Wc-O$G0{K>sbcC7HJbL9R>iRDj9m*2JqX8# zNFXX>rvbT*;83+Nd5Wd|glA;2H)38yBd5-CuL1w`R5nic;PsTg;pT>G@#F8{GBX{Ow>WL z6Be!?IdwEHIu`HUpM-5h@$-lqtnKPG3HzORwK)GNHu=O4Wrqp*nkFn=lsPMn={Gy` z&5kj%2Qcacv`CHmdbk8zfbNGG#3ehwWd6@l6+B8 zdjyI%=m=x8M`8QN-8PDNlIHDrGm3?e${aEz|G?MFA9`Td*0--zUk^!6cj7I0+Y?8L z=3-8Irw!{e8C$+7g@%P}j0m+45Sk0{iA$XefA$i2;Bnw3u9tFice0Scp+#jf995Q= zC660ieZFM!qFGgS)w3QaFQ>?Vo9ghYFn5Ao!|J9?cx1kMvLE)owsZQr*$S`1KC!QU zv4w$-YuwJsHVu`Q{PUZSkMx!bPOQydGCX7id94BHZio+DbX z$HYmsA{hg8B`wn5BO~%3*F>lzTQrUQXF}t-c#T$v$1^sG$C+pL?i)ID3dVoGTeeXu z1WIk`V~=fr^;Jh(hUB=(9gN}lTW2ResFWY%#XspvYHn1&a3N?|x=cOtQ5CISb)DLt z=+GgZ48Dqvydv0(5<)2{DT$#t2s)I6jSbP<_`04*fhkW%Nhz>>GwgH&*Wou@Q(r5k zKuE;Di9;!nv9~&;`lK*C0?*W!Nm1uiVwztcnl$PxYqaPj(uk2zw{uHA(HpxMw0&V= z9Ec>(h$j|J(DxtvYR9D8$rR|JA`}L6PKpyghlbguKqZe|_Xn77<5)K=OOsTvydCR; zpVgzu$xMmsuokRePh8}k|8>FX?dL?aVT+cGJ@!G~KQaE;IxV zb1ckq^_g?=V?@k%>g#hf3IrA#6J0Cu>Qi~Sb(;xK^~laGMh&Ct6@||hoMwJBiurl_ zSQtg2RoKSb?qMJN@|BpFQ7+!qXHV@IqxfK+|7cb9!wv7Czs|UOF+&N7Osl61B^);+ zj>x_1A3GzGxVCG}E1XueVcMg1TgYK6a|%C)ll%UWZXJz;8yLA@m^}Z%Ubd_xBQ>p! zlplfTKi3Nk#(&<5eFXG@8gFxqi&u}1ipGRM-ny+;6=hL>Xk=(>BY8!I#bTi)^@)s# z#DqW&M_^6~e(jM5#(&M4miTBwo*SP3=B`+`|BKB${}H~3c;<@rgu8O+h_$-^Pi)9FXg{WU*%`ro-5CPGHk%xsJU~`?T6wQ;6HraZW97MXuzk@XjCc{G1xNd zHHa=IXDJYi#wV2kq41EI$?gXf2+N8D1OWxsyew$cydDWa&`}DMULCbL4{`Gm@#CXW z3gq}t)|}369GUD`sLu-@QQdUZp~;%o3O8}hEj@E&(3mOwXX$_Ov%siTQ&GX88WL2ZrBzfy(46!dO)GW@k)q@F{RplG z8tCB*Cid$kj&D7%Bzu)BP;z|VHwh!;oE9=hkJfhEU*W{^pBxh_i<%*C@?o46b3Q=$!RwJqe*}c8BqfK?t}MSIVXmv9#)|%tkH-T$cKdr6SAE;Bdx{8(q*A(e;dT~ zrs@`S^13#Wf1Wy6ja*B#zDLt03g&0+y_|0_ymL1*e9KAUsg=!wuo@j6WkrS}8e<#d z$(Z%sb^1E&T0H*+2L`Q?NTEC z9r<(@KNo!bE8$86l{GG9@Jy;NAB|sDerE;K@ z|KuK-t)Bph252wt349GdyN3lqbf`h2Kw^UkDDd2Gpg&DT_&&S$11RvqUI^oZCXP3D z!bd;-&h`D#py%F3CM{{Y7$pWMFgz(#Q{6_RK%BR}+7UZ;1o2N81!_*~RBCsr1jxMz zk`Sm=J7KcG`~0p`k5ZtF1n9c8w6*eS(-hjJEwD#aAs&*(&d$KV0A2`WdRw%XvN8+O z^kq#NE2q%B#>oKa)L6^0*5pa?3UBPEFFYxKxmV zv1U=K0yJxyotxx!wF^f&C*t~O;>76aRV%PPQ4xeRKShTK(Y#wUxXy9@V}fY+lRx8$ z&Mx17O#bEa1{xN-Up!~d{JP7oW>n8!GMv?@moQm-UgushZ5FuQ<~0>NB1(Ime73Za zIXB^r@A?Of%GOj_%?p7J8F+47k^X3pLJ6?^2tKqnQKjJ-X{=fH|iqF|?Sfs5AtzkLy?gf14_14*pRVhkd z?#8W8DM3J{H}Zecw{jt7(5`vZ+_`Q&uw^ehR3UUyi=ilZdUrV)0X5?2-ZVMTA>hL# zKokVQ<%kr>f*?v#S)UCZnE*W8aFG_9?lyk@Mm5g+2fKt=hFlPu>x* zPt4aXS?H%LTlr|r-GSvq3Pe4?YENHONP*oND@K8$&O;J_fK4^w?rvYdDF858gS9LJ zagAHINua>gv58IBlqTNz_MgXQxSTJJCIn7du>xx!>*{OI@41q_fV%#Mm;{`S8UD%3 zn^!-vZuHE>=f2yCh1z0m@rIu;KOjqpOT^UciA$HeazeJjJ@v%_<^M8yC3THUSSmNY zkT~piPEi=);q<*N*szqRz*}g0Hf@4#8~rZ73`Gq2U!!&0EB zT~1WD_;!w*HWJ-a*Lb~8o<_kZCvsNfG7QcC(joEH5~QE~Q#=CjG-l%4_rJypfv5yn zSaex>hDlG&KK7ymt2=4V$iyU6rNyK^l?iq90p9hCCqDZ7%gm4Fh~4|fqs0BEwhcMNgE6M1B1!_c)mNltD;6o!>V%cgNFuc<(6N);T6cl zjp0t$!$7U#i$A}y;75U!)pBtV7FnYD;vgkW;R z`p2i-2@6+;VdEd6BQ|uPbHSoluj)qUf~8pI$}J^@rCz0?O-Z0gNZAy2cMy$o^+zH;#hxW1u%t(l*?0lg~Wj0Z6WJJohH+Y$JQq% zbK}>jh-k2ZQ9HU>>E?+T{&0*2egjuQH})#hYxVsDF`Fa9BGJv)rqB!!>*=wwn@6wp z-?dbp?h5&DfEX>5E^%_7+6Z5C;QK1q6qN8^hArkpWPA)-@|9Bpsq^(E}L;JuceFE6z#=I5xfNNE^-5~PcwA)sKjlXpI$l3i=P6e`QcP z5bpmx#ImxDNP*opIgnMneSKl8?Y|?uV@WfS0+m$Vta*1xcSgrUxrmnURd{wja1=W1_4;hz*OWC52zF z$}eavw6YYKIy~L`OtonYJa3R+kj|h}s0Avq3wakXA&@{+6z_8Rd8Ou}*6@tbKB>$R z!$j}v;C~KCg}?{idGy3vXU^v-5)>yrHCuB@X(t2N6d0dArTY32840kT z9-UWUU!E;ycy!(6dR_ul&VTd&ca`#oOq2lSA2M%%|FAtF#>h6`##>Tug93tddYz;H z72qGJ?`ZFn8@N`Ad*d0jX5S#ZA}E2sX^U6;cta|FcwEKM2JA4NXuFD<$?V=v7~+~~H}k{&auV$xQyUp#gdim91|m{M~$ z&P57fGWVctVf1}{$KY7$>GoG}YKeR>YuCDJ86wL=dc#wEJ zG3Gw7%byh3?T4yw+=x$1bVvyFv#p{y_{_oC&nX>fRvfEVz9NYJq3MmnNM+ap zk=tTrNtwHcd&ZEV%n#9uO0G#d!hp~?CljK8k^1?)m;3PcZWO}Nov)8i6T`Jj!-uB# z$8+#*6OECGDHCKX>}7{4?3Q1>LEJCR%OYQ4M~t2zF98mnGECFf=9cI{_BkT|QHj}+ zdMBL%ZmbrKx|7mUU3rNK<07k0!EzE56sXgYvCP=n35t`8rNwA9`nr?F@=lYHWiN;R zgz{fm$+gt9OqT!PwR9Gg0xcc52ipGsY#Fyy6cKvtLhe_d|H`W?Q{sg+tnL=C+Ezu; z7G0SOCUmmb>zK7)&G`6sr<<4Sd8P8=pZpovDd6rdt0EN;3kS`RCWWCw*3#m{m&wS; zFn`E+{iIt;f$)WqKu}77wbP1Y^9FNmL`6kZ6o=t7IdICj$#!onDm>CT3N-6Q0+r!X zr(YIV({B6Ky08Db`6g3fXqp?KK;>`5$LQVZYf6ZYuVXGc&=wd?QVPVTgS(8(-|}8z zZkDAl8FBqJ$lUJELJ>e`lmgi}DPO+%Ht}Gh5IEt%F}Bg_$+U4Wxy!}Fa^dvUS^jx{ zhSS99qjT6vb2oRlgb|6Z3xPy~bHP>taXh^}iEi4ABroc$8FL-IR(Mz+2YjBlMijG# z4M1b8u-ck+yfLvLS``=~mKv0Xcxb&KQU$`pqbAL}i-CbHdYd3CJoSgq5GLb>PoX}g zgmBmip}nBq03UHDLs)KE-{k6AU>8RPH{V>B0P{XMj#n-lyTa9Dl zQU=MK*>#;Yq${yhS&)%fCRwC!wQFauB7|xp7Qbmr9b2ts>@?mg&xZiNK(_qT^gqHt zh4J^6I4G(pO9yHCACdpSz%PFrT*8&RjBCs<=5hVtwNFYz3n3DCtsIX1SNzdxcLp{) zACy4>W%eHz+Wpp^(-V%qCF&oeLLzhi-H-pe~;o!eU^1dED68+F0fc;(DO* z>qdi({XB;e=1-+%7}(5b7ZS!41~ah?6O|R>6nW*5Q$!Ak90DEt&;`yi@0UBjIIfj1 z5*;Q$?01Yd4p{PdGy{EGTbsckoKt2p!B-rK2E815tqu)7n-d%?tjE-9bxxPAFf|vy z(A?Xyb+p@=IU*K`o=NySQZs(GBJrj4V75(T#NKYSHcfevU?@({@p15SY*q|I6V)@p zm0)SaiY6LzIR1*T=REZeLj0Z6Z+y&1w`q$5&Rak&&Ml8S%nY+vD1TyAA>0-_UtFh9e@>DTDnqu=;IW~z* z91=KW08m_%28Rt1<<*hNol3K%k3B}*Z|%ByPoAV2P>myOMiF7V{?#&vttR)3Y3@A# z2`Fr)E(+1>+xztyTCLsvdVZ6|Z1)&xHhDLTC*VH<#P{;wnSG+BJAc=1G_D0}<<*st z{~8?Qzqr_hwybCx|2bsW&r-v!OZksx`TM_?@}I0&({k{2j{h!wM)pPC`^wIahDIC# z+38)2&1B?2;w&(>^slqClchi&1moi3FoCe>xhi5ON&`XV6v%^Mdg@?@Uf8KEpY#a@ zVs`T>P{vRS#0;fCr_DJEbkq^BrMQPif&B+ne9Syz@H`nKmR{=cjx;`*|DXc_GKf-8 z;Z?3|Prhxrt(j;>2KQR#`)S4HCD>L|bA#XXdU9;rqC+RJty$BGZ6&4G*sY^o%WnRG z!95l-852WV{Aie|Q{0F|_33Xm_w9uS0%6BQ%+WTsYAJcu0z!kq)>q&6%)zg?irhh6 zhp0S=ugpmTLIY@j3JeHx^tMN2jz{^gxuY&BoEmA5RXU0KAAmpN6jny;5U}mr@)1_q z%@#Apf8f_qGe+@SWCol8Fn@lT-#os)hVkD{remkA)_?oQ-8A@<;lHM<6;+ptz-H;T zfKAuY&Tmau<$CsQk8cB;$LT7t^?X$!Js>(fDmq*)U|~&N9oU2c36(Hx5%_os5T(G7 zkPtL497=&ib_5jI)rF6qii>R#%$~Eos%H|UASfN)fqqn4w^<654(~ue>fEF-kpg)# z@CtBS^2p<~|Gm8LnhXWDQoOH@oH{C#=;`(+A8)%P8U^wh))`wy6WTw1`M>YVP~hp_ zbfxjx&Zi(to-~@D4xYYd8A^e)8R0&eQDSUTDIr%Nn zH(0QQ+rEV5HrQ&Q?BS!B%*R z5CtNBN%VC@ebbays0StU@F(Ef&{U$zCbeC!Y+JN(8Gt|Vc~nL??dFN_cj>dUS*y4y zJ87yFw^gfP%jNIyPt^7j5)#-|x5%sILXZ1>`L<5(;~0($BhH4vme42y)c; z4uL5t9&giqH}LAyR=*hjkX+fz1DS5+-pEMD zPjc{U;w`!U@LAjPYZ&~myCb?oD_UN6+uv8x9zJnDZ4tiavaT1np;w2w(^7f9THjd+ zJ_7{gRX|U2AXReFZMw#-Yn!-?kZ2VRx+~!RIl{W~=WuLhx2n6!QN44gd>g86UP_cdw*kX9cU~9Lj^ZJz7!Fg zs<2SO0Uygluh9x4A1n_&ntBfNJ47$H{|kbsv*PKExXek409?HHkaTDBHLJ95zzbej zMC>?1*+ah$Z|2hO6JPB@<2T8d1kb?XGOt)y+av88)PcBY)V%xR;KxNtAc-a6*cbVQ z+u_Qj%-o!7`2`udIYs$UoLK(UTCGld!j@)~Pn_UOSxwSc)pq}j-x+(OW@e5PqC*5{ z1@uX^-S*FawAehMZ@Yh8s5 zmf^A7YYGct?)0?^tAHh}LrDn?(r^tzn@-d(qb`704oPFDkWD05T)MD1J@6#?&y^*j zDM)R*j#j(TCc-G@fuLURMw6T9+XZ-pganJ)ndX+}D;2PUWDJH`zAywFGHF_2ULMZh zqesL9#h==>ONRdn_Z-9i8al{LNh3pi#l%LY_Kc{JVG)qXf3r7EQSyrO{*K3RW&4r3 zmU<%mRaRG_jZE(11zgv>lgpr}DYFVHpo~h)$6mpV_3|cyAT8}6*e^}}URzrWC~#T; z4CIlge@ldtwz*De8~UB`^$cb?U&N(3OW1WMME>g&vvhUIP+&rAJdFa6zw>c8_dhpW+=JiP@R`$C3gnvC-u%DiEwar}p1oYH8u;Xp#zWCtzGl>)^qPo(GA!ElzPl79%vKtLBp=&R;bUFKq zk8j(_QlR|IFC238@*n$|r$C1H1?(ifo`i%1o&st42hrtz;_*E+8XeZv)nOFa*a#(k z76ftLB00Skg?xz)bokIPCeJqW8jp0;#X}R@yxKCo|Ps@a=wD*yWaIPJe4c=3~$MgB=%KAwdq9hi3}7TSo+KFFvw>Gs>DGLOUW z_r?u{M;dkQ%#Y@*$*kO$vC8r@H|hSwh1A3A=5Zk^0rt1eUghev?4%XBeanCO-+e6I z=}ICTox0iXF)}Mo@aBu2@ii$e$@Mp)BQ0y43(Q(jtk7@u)hw|6#uRD6 zyt{|pe71;>P3U_Cr5+B<#>{tkNf0^<{G;6}BhCWz7MvJ0K*n!axSyM2fwtr=AOGc3 ze$UF^!=R5*3HC?GME=|Hk2hT5gZ?wjVMFdk^mAxH`6zNq`0wb2yy9{~)^nc!t{*(z zsqNw64^3?^wACHmH2qHo{$y-e#&Cy@=iv{k09P7sGze4YhkPtxJG|+Xb5A%b3!b^G zgt`KO27kOLs7`C7A|NjTqSjzD;_*BMVlSSk1v27XRs1oHHUktm(feL01=^JZQ7!PS z<%@nT-xl7g-4s$FYEDxiu{}~kftVv8@kO{ofs8HH7&peHI0E*Qp%mDMh6#Z@_L(Fj zSRw_wE(8)C0lhrE*$v%E6auA8&~E5R8ZV5VJyqV;E_jnoS0rn6*hvc8&3b!zgRP~t z1>G!&X*8|qrfb*oTbr)U4KY7Ie{^fpYWa=53csP(x(P)H{Q_M!>%VKEj({}N>a<|f zcj(#8>1(kCW7yKMqV85a3tV1Zd6Pl#W=eo#=8S1;(|}DU4(rI5NdhnW`8$0%<$NHm z0$43Db{aw9*A*+xaiY`f*bS|5Jv}{Wx^11V9o_iG1Z=J1YTSibV^bsh4B3q@mS9u4 zyQ7ywG62I(r`PkFrK`)!(~I9g%fN0%tp#l8<=Dax_>a&f-ME4BA1eOwpQ{_WB}6@D zRkOCGy{k8OzKblomSE0UufNGD!-3T$r16=~MDhS!#PDUpQ_EX^P6`ReP#!oqk8=o!|(CMOLV_O<-P2SS}wytgl zYa*oc8{@}MXBegN(%3~6sIfjeBNr0J248R9~rw7^zJ1uAiub)Wqez z@MrrlYKK8^Y}T;wRRFjj^q(6~=+|1-3H2Vqu}7 zY_=PRtUufVeSLjt?q15xU^FP4&i3*4?KBx_^2)Vpf`hfO%^VdJZS7rY5OMor_F5H9 zc>XlK7QWn0hB|fvt$KZ9eRO2B-TVCFg;$7+LR>L<_>-||zgU|0_w7>n_lW`HQ6ysCM}pue%Pi$Dg~NCT9r^B-fG9i7LoR|ASe|Av4qw)#}+)itngS- ze_w^gK4HW^UWfsnGA7a84O=7|T79Z1ejHv$*1z?uPoDicz@{{$jD{7hG#~be9=*$O z*rCplNkikK9Ps1R>F|yOjr=F-kTQiFCjtHe<;PDCaAK3j;|w!JTY48<-KgLOyFN?^ zwh+zV&z~5Pao<~nCB`eC{3W*M?0LeIaW5CxvALqDzPV{|Qp(Vocos@SJGGThi5i4< ze)01OZ~4HN|AFN9qyw>g_}4w+eDfZ5A)U&jchwx#(kq*;M%te`bTn%!trZ$KMb7?R@s|XRH22h^jN;z7<3-jxB$9iRi__hvjc*s4X}ka^Cd`;)af1 zX@vD|ME=|T+i%$0gRS%h>)LnL(&QOSwVQjdCuO=n%n#XQOQ+78!g44rgtT&)5jYb4 zm9GVM*ijv#(X=T!5`Zaa!H9o~ONyJ zwsfHLpCN?)-SYdd@Fx&uTRC?OPM(xjb1(X?gOAvK#pO1rS*`djTk=J-M#uLbOr9nu z{srvdRx5*{=aCDriA;P(gn-sAD9vULGV{FdgU%hr@&#WX2Gx7AaYU!$igQCoU(r9&8NWNpkRd*IP0e?wmr(t zT;IEN6hCXIH|kG+2}ieRA{sz}o#Fv%Vh$Xj1o;PC|EwH*C^{pIr?Iu;e8ODYIo^e>p5U6NhE_vQZ!E8_ZpPC~D9Iz9gmMTmA)};cZADuR zbQW0Usp_`nsCD;n%)Qr)jD;|2sjIJvi%kIhC)YY_TBSW!%-G1f(}HMMTn@4F+bxG@ zteJ`(88I}t>5Aw@Pg%LNsje;}CZ^LQv;YmYwH_*$(~tb1Ei@_IY_Z(rixOew@TYj5 z+(1A7+x|j`gtza-Z_!_`j>Y*eccvh*&%XhS`y00S##gt9q`Q*yqA={km*9~K^f`87 z5&Iz-5$0}KpuL3m*Lh^Nh(G>>-0W81$bQgs*|3%I9r z;k^CvVLwOOQ+_#i{#VIKT%0lE21Rae)}9_0PomLkXj7lX<;C%8$JU_u277dB9p*pq zbMJFoi4-U)NrLChp!kToW>`(WTKw+qJMY5|ocG{*;(*f$1N;Xi&%9C^1@ipI!XInr zpWB!H3|Av=t22ESfv;h5m!cS%Dw>*b1hIwUtF#&MUjPX55}+bwm~?ewW<$2rvLJ}r z_!mb|$Gby^pk5LF?P_A@+G5L;3MkM*No&JK6aC~jo2pONN+}R*v>WJ*(qqUX46-*- zT>}9H(*8ut2g*=Vg7Oqd`;&}c;Ih|NviwJAaU`!OVI*N0zs}~;gz_J`L2>7}Hem@_ zrT_LWxs-0I(+%Q#6ClQ77KSkwU!uA>4xKPtd7(uUsabo>;t{G5Yb z85YSqWovqe%QdxCR-1v((tfc|jIRaYD#PbY<;Pdp2iX1=UGcP;bo|Y4ohB2yMMXsO z8(QPo%hAkJZ1VSyUJg7%egh8^-K1)LUl3S0zsaO^>gfU9BKhhb9{mf}XG`qJJfTsU zv@ENKJ`x-%rWdz%nk-z zz^3q`pTG1sg-2qSLu&z65%8MUBicMYJ@`#>2_wI?>2v@(`3)$XfRBf-j(tn8}pUtKbp;WbRzm|kT?%YMNPA#MT_{B zM`w?ffj^f2Xf`-ws7mGT<>3LglZ7>&9&YFcNwh)_Hmoj>UOEzN9#RgIPVb^LMr>7C zInZP>xmfGK)v+MYz`DDk(4w-1O6PS-lmgAmMNH%QQ}{C}MoP+NR0V`5u~Fc`&j_zS zd+kDYWJ3%ezveF+c>Sj8M2&dJ0>{b;l%ySi0;^7P#ZFTylDh!~-V!YkH8y($t$Rpc zopp@qipdhK?;g8+=9z6GHy1Gcs=8DJ2NzaB0z@fLglHMTa(w)f@k_8H%z~y5+^s(SoJ!j5* zZ98>dM!8RtpPwJ&vN_=bH82gd&ZAdOCes+{)yIxbP&4=gtUcA>%B!EbcAD@@@8_*g zY-5$S8^t9NL!*O(sS-$Oc^TG%!3HXV8^Eh0gpr}9giwBnK|>>Q$VXz#OH}WURyLr;`8(gAv{v>Jf%5Ek`t1bA{y!}2EO0cwpOVJo_nJY z4bfZ)@`AyE^ouvTS0*u;NZSYdHy14^C{U*?2$Y)-)6?nd7Jg{M?Dm&ee3`#=K@iuL#2L0&s0N z>WR6w8!(>);F{6Q8Jsr!%ruq)!_tr?fMJe8x0*h@55*G9#7-HTWI<+b3m%s0D71TjFuI`Aye)SDCIo95VjZ^xji`l z^_quAZ(o@x8Y{SCA^ms>P$n`0pg`8!Pek-K_(KCS%RCf;-fTu>P)4%c1WRFuW;6j5 zNN5P^NFK6Lgs~E!K$)97ah4jkCn_S6_9vqMFV}O}@*0zekC`^53K6=W%+MJlmLl2 z5~T_EsQOJJH|S+0z?*E!pXX~UUUTI_#M~PI4*KbPVZ0(^ts12(i;3wyxT573sPH6M z{yJ*i@%E7!gebq9JpVzBqdP^(d9b-)D(#I;cIB-R=YpsGb|&#)ncT_%{%HKSBNvy1 zAUgmGr0H{*94Mlns3>BLK$ZgKK(&Q&)sQ z(+xNhFc=M3VBUa$z!Ih?A}pc>smp-@0jTFM8hHR`jUWdLrTjLlcZEc8=EaJkTMBy)v zCs)gqC{;=%KDb?GaEE;p?Q(2J^z|ZcV42$rpSkh&?4w@`70_x?8vDi{aRBJ<{U;Yw zq@kH=xr&yWX#-YK526XERd_EaCORHWB(}MQ1d`0N3i9QJZ ziykJnhN%OIBE+{~SY43TbgM~JY_LeBXkEZAhqe#y?ke=ic0IgYo4J*!5z1e#p}oc~ z|DD{ilbs80`}gV40P-|F==I8;I(W6TdCX95U|f;}pB|=AhAkS_va4_nX%(=v%^@~8 zFR#X0t^53<7GLw=?#bLZUP?s3pRa(!TF zc*kmiL=eQ1xuI<$8y%1cg1)}EFSh(FFrYnYKtUQE%B*8zL2&Q`B82j2Q`NfR)8raP zbLl8Sjr+-SFxEif^{YfVkVb)wZBqDqO@XWe;Z~! z&RI2yc8BV;-r=Jabl4`)U%U0VwP|4O4N()aWd!SDj`rpzSGmI*p1x$NMoWl$EK@8o z+q~gL@N>b>?nYbcOHBkH$DCY(vsz~*!J}j7P{(55|2Nx+aU+V(U0eFlUF5!`G7ufm z!f}q5RpUnxUGjJDz}wFdH)7C}BX@n^@2$E}+`M>Fn!B4@acz5ukK3i65z-{CdU1)+ zG4y_Dcv_hDTIw}qTNiBQCX`seIc>|qV4G@FwRnM=BF(;v)*VQGwhmF6j0;w@9ta<1 zN>q+=By2)j+K`r(#s!ZrwojiLpQy$PY4VM zs%otu{>fx9d(*>o)NO{6w)>qzpqw*%cS~K2Soq`QPrU(9phjH zhz9si`SZX3&(FT|+h_5|GQzFlB94X_|4HFb-VS9(&AcW&>f$;h!>gQC0yKvN1({+X zQfsstk-{ep#i!^6M@4mX5Z3?8EFVE7K;h}zT>ZLxN0)rK8I}Su;Q_lMKLK5?hF(+U z5-)0EbjLw|+*nwI&wX6HasfU&N+i$Yuk3#6gFld;14RyGXM~9$$j%58L2w{wfrDG4 zTAEwJ!i7@7r|Y3nU_7ETw|4d}{#6m5Km69x=Z`)asRiZa_!S6xKzx)>bpyFAzVy`fI^w$50APn>?}fgfOx!xqdY*odZoi8mFz*)-Vi5rRllp ztPm(-=;Bf~YJ6a8SbHc=fw}iD$$tlDf)Ag0iAaI27^=x-4jo=zU0Ic1z$0K;-kG@% ztVN}WA5Ch-=gww~%KTp3D$0LC-+A^T;|I%d^uxI=wjqkH>l{N0RQk}{Pmo&=Nfov* zQ06J#d5EI2B+J}nLhYOlkFvETJ%~(P_308fG6{qdG(L?N9PUOGuk-7W0 zV?rR!Vj^Se8tarC85|sh34#4;DF3w^^ntdZi~*hmmk6u1+ufaeeY%fCzRm#tXy=Df zU6JM%@*kisZB$`!gLKMEmj5_~Xv^$3h(e$f=Hbhf7M>Xvl!C$Eir7J{5NMbGaQI^( z=XiDLL_9h)%YWQ;B~R9h>b=rfFhrA?pJkVi*j)&Mf*?V3rhwCLV6 z{-E(+Ybksw{%1m0pOq`i6Si3zE4U`xrT0mT@V<89x(^K1|!? zM2Ddn?t^S(400)AXjT7T|4)j+qHIM11T{g|5coU z0CZ?`-twnzljlF;ldL}9BwsjnC7nTO_)6i%<|d+Bg4D3kGiY5<0d7TRV`+7P13094 zF?Na;)1)SeeBc@p@dB&DXmv1KOx|AJ#Ja#&2fK9vtq!((mSck;FE#OU?H2ei%^U{QSuFdGav$sJ(ha)qYspJX(m20Y**qxPWMV+p7bp8_> zvKn$)k&mB#gLV(|?iYLu5B${@8bOM$!)=)}2>ezl#a zK)VN*kQ@e-SaUJw;StzM!0X)mmpJ__&^B7$yyAP9@42-$-ulQgSI=JQ^K%lxfUTUC;rdgG8sP@u&%>8C5`bUdZE|u-)(DxCu>8j${Kvx|*kHS{ z?IH_*QvS<-XNLzd6&tDu(kPJTjR*cji!6w$dUl@<8hwTbL@eDfH+$Zu3C=f(k|31+ z*G7Kz_Pa{@Gt`#fw(|9}7diZ$yWr}<;|;YnQL%A-_13)lE_Z?@j2ndph6%j8{iWBX zN6uWxC4&z|Q@oHGjJZFVhV6NABVpPA`JR^+S73)V z73NFdHQ&^r_OsU>L3J}W@aadtctat(bd46;^QJUgdA99{d3dVPVxJ`XFj;ETm9hy- z7fJV@I`Ka7F?R;ZP{%Derg zcL-%{#d>LVke0@XAwghsqBOFWIeZzB$rNfRAweMu*X^n!Lo|(wj%?Gmg#v}uLa%&3Z(t%!GCW+wZOtX*Q8pYQPV@z4~P`VDO+WZWt(;S z72JFS6lfck5n8cn_mC4(N%`-4WZ1OqO*XsJ^go)6d3aNYWYO6o!6P9z=fCaYta|i5 z*B_$@!bnp3vG=x0cjnGngZ|1cbNuq1SCm}EMgEgot467Ot~|vKHZLs4=wW0JqEMd* zp8w!beA^CmF=*abUts)aTExv3nke_!Ltn1~_>cA{({X0GU)Gx0Sv>rKZS|%#JpakR zXrBLA_yZdRYYG4T=G~XUCVkP;cMV>&^j%-u-knc+iQj$jo@31g4_h*^mjMORXs@B6 z0dq%)i;Ht~*ufgV93(L@5d*=2&~`Kyl1mw&K%y2XBL`mD3H`E%E?%tUy0lqf|;d~nmYwgHNj5yNt2 z(mD2r9r@}@a>r~hRc;?b>gj#E$Ie^W-xo@msv-*KuJ9iys491NBr9%@5-gaq=pL*( z06VekQ|XaXEFhyNsb?8FdWDD81K~VTnGXvUy&$6;Lp+WJZSLH(&8(` zmPgcIb=!>V55#dGW#qsfn~@pFVv#0%lb;WgVkjn3-l|#PJAU~P?N2lm7PyoH@*O)VGeySnPElH-#m#XBT2VatI5 z1&RRFS7=Bk%$~)5U?o8Kv$rOdm0atmuOAocK$m&@0}kgYs%@ywT_jv$`kIvkR?F!q z>tg=POu2mJs41BR9+*bV*b6Lm$|9L(Xt>sA-`68fkwV7uA7;w=Pazoq{=@dTp4(%9 z7|(xK4~jzl$wVrk>3>0q>0p!YA2Aa`Vb@6!|IP3A1Mny1KLCF;{)5Eq;|t)A#(xfp ze|GuL2^_>3dfBpNQrA7eVV#mt;8Gz_ieK^Z@lpz8#9?4D1e7ioPDx2YkC#V4aGzkH zANwS^E$}C0X_VqHW1AO;efjE#X-`U;D+6(nD=`ccdw_FVA%h9j)mW&-YJ^9;RY?h?T`pL<+_+FDtr3hZ z$s0`w^b*g}p(-F&<*}IOSdCD13#tva5Ex^0bXHI!R^|CGc>HTTbdgFtl{jSfM2!C| zpK=i!Qlnv?vfYSB?Bi8H9{yru@$9Sx&mUYiWvK13h(xHjFI~ir-1s@pYTKUQ!^0o@ z;qj=jgEK=FzT&qZhRy(f;liJm{?7vGVaMU5o-e^fd z_(X702@pd%b}cY1aU4Th7fj1vLNtXlJ*POx_>^c@XkH;Tzh)-%`a%jw9q{~ zR{m)n88J^%!|u;mGnFv9YIN(aC1`{+{=2fJ#BH+B6AX&w8iiIZ?jZ{J@0O`b6z4;4 zUr`~fYZN@>>aN%J$)$+}vagKiKUwjwiuut7m>D~jP7R;GUc+uHGZIpVrvv_zKb{uI ziJt}j^3AuMDQO{nFhB75OMkoNPafqzN6jw($(RiP!G0Qt2i~vr6>qxx6(#(4VCDN@>o6DwNpkUkDqpnAB_YrwE-p@* zeuG`WfkyjNPK0Q(U<~hQRL34BWjk=ZG&c!*B>OL&opvPsmaE)w)~`3U5s~&}66rc; zQs!g#5aqz}%g5wxJti*!a_U80xR*avfWGCZ8a|0^`0xK@MBJ}|X z^2oXT@pZO6Ek0K;aRm&H-K0}mAk$X!BUfPvoBwrzv=1IMEm`{S1^Gv555#~-1twc- zpw+bwPRZQzk2lu*9QqpS^rAj zd=lbpo6NiJGWB2|7#JluTBB`quHu9sVdr@9kLFO0+PnwX(+1U!8rq&Ke2n~)ys#6F zzQ*5`oBuIvoHu;_sKQ#4oiIaML_;$Oj#9-Zs=_4!H>46Ek^ii9p3+L;DVch<)VO06 z1g#We5l~dqu}Tr>ALxrfj7*ge4i3^FOFX?j#8Ie_*({A#gF+!z2gAgp5xqgQnuG>_ zCW|>-l75NjKUz5=2& z|G1m)@oOtZUah9~trZ7km5gwp-d9 zj*xe0i|EM*+cK-}+xqYCsd83(rsYTZP~NIfiDtDbj-BnlYhBrUeaHXoAFz*t<-dM4 zz<;pa6FV{yr+^9FYZ;+8B=Vp9d4htR% zV*nH=y(=)J@b>mLDK1s;m7n`SW(dAu{d$MsL*Xp2lmgek`70U)(&Rvl0$D8(*#18r znft#}oYn#-ExpZAEift+)~6b#ZzgS9wQcT*&ud4g!O=4~>ImqB`K9=QyjL?5tpd9KKd?U@$5K)-mOEMWO?|S_vr~Isys9;Ip57aaKXWix`&6h@)~P`f+}W zVWFX@gRC5`A>HdOH#Xk}f&W&ow0R+OHhs;q@3w5C@gLE~E?jupRt|ai)7`j^34udr zWq?hD-OoZFah1xw+bWbI)syM7nRKjSIrRI3cHxisX4#iJc%Dl9W}$eAc?5a4g{D6_ zM}QE9SzZtEY4h4?|97#D1 z#n0D|`O%!RFaG?-ir*?F{y|f7r90IQ#_W~1(evh=-M7zcVCR%x^Vdhfa}$YP@##*V z4e+0m!)W}cWZ(h$uOH0V*~zEe=qn5G57c)!GdB|87l_RT+tvSITm50ar++X_|D)OL zpU%Pd@cf7F1pJ2`)^q@NURjfKn~?ZE6V~PQ;hP2UCq0bizhAroIWPN}DN3HFI<3K6 zm5lM9uTL)KXN-H&XfzsP1`hmrkwUTb^z>lygizq4#gySKAt3>!K;kh$K|vS=20ujZ zs(spm_`$i|*wi=2@;4nqKhr3%wyp}LKtb+$VIf9=d~t2BjwDjx`Hy$gD6pccf=Gc0 z6XIA3Bm-ioDxsC&e7f|xH8Nkkp|uI6K$SbeTPW%F>|6VG3}%B21^T5B8cLl($5S9z zFKlCRcXzj2@)ZV69AA3;B9 z)ykIAG7}+1WSBXQ2@q8Zw`hwJN+24M|3)Xw5LH95LqA$Cf`dh)Os!T&tA-}C8C|E3 z)_SbshpEHs8U-0%->Mha%^>k0S-7H`Y}@GN$q71ULo`G zi-Ahv58nUp_Q7xu2>(gpkLN#NgG;qdY6swt$bZDwD&;>G{&@a#$fV*Q=pbTq+~p9E zH-5>5L&o}h0uW>+K#T$%I#ojhoKuU6;{5A*cT_-uun;tJGojiy&4s>rq|=#8AC#W3 zxaf26bNZd+*xf8u2r&M$@YEmgip}be|D;7S~}JS=WmD3`QN50IxTn zN)I1LpDFlTK^%%XrJwVyy0{~EL*rw2|)^3G$KOi&!qd=)@{$}?MmjA%dk*PTs$_g;?PXy&3U-Vl$g6BU6#J}IcfMqor0MO>dD2`mK)<(&| zAEbYG@MV4aTl`abx<~CU0@XM<1}*^j#T~H7eHu>ol_JgsH&&jEOd5~!ALNGuD@uVL zXewSQ1rp^zsRW440xMa3C!GcM@bKV6`O`p97-s|qwztE9&iuEg&S&uT3T2fdPpn`D zvhalyeYxy+{)TldMG-(=D+<6?aA5C}pWd7Lz)0+{`bL}ISPj!1XH-ssz+!VFi4-_- z_8rF$e%dD#_~5@cT>21-KyAIN1tS?@5mwRJvy9}HYp!028#1&P8hXpzXK<-+@Vq1! zpSBE$voVmlhl%3RZo-_Vn~HIljC%4uwJaIj9!vsSIS&DAxjbP{ND>xyP z<(&Z(c;gsX@cy1h$oqs9OYRZ9N{D(dy~&p1p2MG>z~A_Cd~zgbQ5LaGUfPPoqId5= z{mSu!A<5~?z&0sK^kl;79Lk9Lw%u=R!w$<_Jf9naGJ;GpC?eJF17|2JOr;?OhNP{0 z>Xn!6zV5*ctj^nCy{zPQL(cfNjBh~rovWT(N36w!f8Pz?ctj}dr838*6?}Jzp9Mz4 zhS#?U6(=bc-eG+Kj2dWeS9FsF2lq*_&lRgJ=y~zTD@rO(!KogFPjc&TggIYpZx3_F z^GcuO?0Il;SVNPv$+Z^0aY$O;3bp5LJ-@JXP!e9=_P+Io^j5*WVMPwmgS5O&o=lMW z<6`3MLMJZ@VnU!oQ;w1yh7K&0Ak9n`v$rSJ<%Z=yslmVtYvMY3-P4a6Pu&ZHGw3xN7Pd+<^) z06~qW&vGcSb3n>xVA*hhL<(d^8mZQdZtn4XXfyN7Qs?8<#) zG~wu>)GX;UnaTWub{Yk8DqvFh^~&b{BZC=p?!w zQlJwiU4lUC#`?pSKlFgq{h##?Y}Pb;d;4U}b<6|F!}kZS7ZL~b-xs^|Resj(xhe6< z#J_qE4DY?zQT_OYtx{&S^bG9$pzl>g3s$hNgFBza$|#HygPXKAI~azr_vWne5cYEN_?lp!X|yE z0RH6Iz)RI_?iTouVr(F@-!0onq(D23w$SmATyqr81?%;CGzttq=PLt(K0ZFgW*3S9U4Qz!-MYTJWi1Jg$4DUts& zhpp~HlCNNaHq%l?FS@+AoL0X)y*$JkhMuKj=ClFpPdCJ z+R))50PRL(UDo}L~Tzq7Sv;|39hK+G^9aQ;Kf z%JM58eEFU}zsb?F7809Cg(eN&!4;u7Fu?ekZ@%CoCd^*D*3#AQNn^de9b1P;#06;% z&0(XKVa zf5!av=;(;(P~Ki@B66N{2JRE1K!qk90n#ifEeWd{3eDHY$JlAV!8uoWJT*;JV%NO+ z=$40G10N>*k&CDY_)nx$UXN%V)r2)2(ncfY67+vaV-nih^${V+mwoA4WC(nrMuYI^ znwWw;C%C@bYkFi%beu0ETF5wc!vyKge?ISD{7Q)5-!~on%o}1yBs#qd!oV|`6QX{0 zFA?RBeEwyhR2he(RC(BpMu)_e!YY+2%x1*@0w9R41xA~1qA&?4ka!il*0;03-YdDN4iGI;8~Ll5 z3jaN)P*~?aeGQbLQgf4-@2$;VyLMpS*rL@Nng3#|sBze#cEfHMy_V_evo&x%-9M;D zdS&l*=l(H!;+=gqF#CV@-UB|0^Gy67ZIf2oqFzx&AVBmYdNp90jSU!M$9CeHvs3JI z66Y?-U6M<=e|~q)ImJ%g6Ze7(*v1$GrWer>2niu1fqGkMceT>)O1uAec1AOAo7vf- zg008%!K>Nw&b;%M@B6$@q48g9X^>I(6+$N|PM0&dFSc8hW+dth0XnJt2P8WgCmZv3 zW()j>y+y)bL1{KPbZQlVKY{;RI>gGqe69Y_`RY?wI=JI>WhXdNlB1;H592=={2$>d8QTx0K=L;^cVNyn7^z~*KleZIPweEv?`|T0WcFR`rhA*E?eMGgI0Cmm`8}R- zYuJ{`>GM0TdG!+3-`oE1;?G`rhWggik3T`LNxgsiiO=Uhv*f<}sUN@shzpW9RuVm* zf8=QoZS4NRN8h7<-ci=`(MzvTSVzJr5K!Q@-|vjkQw)kH-CIDO+`!C{c@TA{#2IVS z{8<-{utBybEhuVerAOPIzHW-tQ!r*QN*+X9F8k*trh5FP9E;u2zY@h47)5K>6#F#u zRR@vaKAD?uWxNj18xL;XE}Z=R1C%zvwM#gYH&l`>&3nB+fRe>A0CNecn+$Gzz6rn3#;Klo3< zaM>~e(QY<0)}^IpP?dl1pHJR7?>8lWqWW5PwdHmhMv7j>Oo}8h=3_@;yj)L(-LPfP)mdwInu4H za7<>bGor!y;NHQY*}S@Ydf-eAaQ7!i05~!{R$^3?9t9c%c4MIH>2W#*FA&N)B#PZg zk5sW(jaom1ga0FqsIS(JDqz`TS$@XTZM~eSA_?!CtI`SVvH*fou>hNW0_$}#5cD%rKy49Fpj7q| z5_NlhLWK`-C|}5e{=DFkjnvOmm;M}oP|pJjlnRInise!sB^ z55lZJ#SVWL-U@iP1yCTT0_6K~|1$&>7_O&4J%4F@wabk(n8d_yq>3w|_v>*V3L}$+ zF7=()zh+G!ch(&0c_|g3lu{p70S2xA^RsMIpaR4sEc{2;;kC62{3pW=EC5}`6?=gH zurnP0`7Kdtw~h!;ohwX6%uYHH;a7RYs3n=f{m$u%>o7T~Nd5!x2M!MY1pbSJ@)W0- zqsL_?k^Bc9q7?tlYU=?Qli=`5JJ`YeN0pN5bCuUBAu^@lLPwbl}os+Ye@c!ofyq!G8{Pm1ES7QwA&Ic{-Zoc#SS7}4n$!e z7Z+rnXqRFK5o|j<)?^N}tT6=>dKf#oAqn8`#4kTTd#TCWE7t$RM}I`}AHQa6rEIJN z_yb4OFJ^HC`wIrq$K}w_Xyw*9NZZ= zPZcZ}{8j9}ni!v`wNZA-4?e$@`U~`(FVb8Oc0K}N=X5#+6`&y9-Q8xhSqf}93XF@R z7{GEAs8Xp~T3SfpBLi2m6sS|$Zm1LpCR)z^Pb=l!eAP__LF!uS;PFElsT9M<+n@a5 zi{Hf~r%YJMjzLpaP1yI^t6>>;$nfzp6gciCxe*WxRWtY2wdKdzowfBpQxsVZP+)2b zza#8|$R1Fj<~XY<=`9kSOe@Z?*$W>1Cw*}L>d%LT*XQ;XPg%mpD3;P@OGVv-)8k+f z9J1$89@zogakl*n@Ru0h+KQ}tBTW%bYrqgMb=gYU*NMk$*D_&C?tbi(Pq`Pf)~xZe z@wDW$fY>(B(8{T^6x)FGNx0>Sv(oDql&R@+a-d{`{1A7!x2{Gs5^B7{Tdho*wKnW~ z!R338<}Sod!s8ipSbp5tA6jVPmbE8*v8YU0W9#d$rKe{}sQ_7>(;14f(8QGm8=s;$ z>l}RlIGxY_^A4%sm+HkFp^}{_Ah*+|ruxiL*@xaa3g$@g=e+yoGA&GB60V+^`@lxB zdA$AWKa%UHw8`-e=f%OH_zOyACeW@h$HAP;oWu#pLu|g-(Nfwu5No8YoXl(0!KkQ% zju)Mgoep=907~q3#LyDQjY=I;+gJhMPwI$NVJ1g;uJ3 za*yzV@2p@=41ZsHgn6Zw92UqYc;|1Brnq~<3(Q7dQ5Vy{Y!mV`E-1{>X;i7x3LDQ{ z6yT4OlV9wZc{4upboE(d)FuJ`WaL^ce_<&JN!aqHJGuAEQ8~-&~KX4wNwv zlmbD3dYs=0)h}2|9muKuK#P=8B?dan!ipAmZ!eVs4SCw;i=ECme0A*gdZ`px*H}-b zz=xlIoTNY&Yj&1011y{&AScnYbfQbx!=-x1XU>;L;z?r&8dKU%tQQ*LNtd|M?q>4u24UVtmo}W*>MKnY!5RV6WI? z<-fk?wU3SIgJJRMW^Gx*FlV%)#zP*jM-_qFM8YG41060f#eYf)61c9@)+yDyu|Kt1 ztwQ~QH*gnMt}JkCp;wpFW_^;Du z#mvs&$H(y>JM($82`LHnOm!&NEZ=U)bp@G?(|*;(ndQlJkWQ;LQ6iECsa?Z5NOFRx zsj;FdI`9&`SeMj5uZ>o#P2nH_cM$dl9X9Bb9`uXIpRoD9L1VOc*#zYuG92~v$P5A; z{~>EaBF}2$zwHxV-?fPM3t{;$@W*%PZ^&d3gR1QT{DFVJ%3WdGq-9zt>v5(EVq z=UO%S`-RA4Bb|W;Ghe85Pyl({=&=ON0FX7?Dn<1tZ$j&9ehm>dB!y51GC+ag->28G zdmPDmqpp6%qF7uZ-RmWchJXt;tvkK%e18S86ll&cef8${?>rY+e8hs;N;lUgFI&!0 zVA;{iDGx8GEkPEbG0`#D?gOuqx$oV%uiZ(dz&~vgH-=nam02BZ)xYz=ds|-F91sP* z|Kum}Gh-WDki}x-wx-$Zr%6$uOl+4(Q^bboNiUb4k2Er%K4)!McH+amLS#gBL~i2+ zwt;0$XIGY{7(@BVlb`(beMZHH)fnrGEXa*vd6RIBePzy78mP4<#^Lq}?I-O~k;qhc z@Z*oj@8&L?ArmAL6Sdmw4QD3pFi3Q?WK#KT-MAW8+0b5|FrXJLep$>e)pXNxTxVFUdBa6{=tV2nBlG3D zC47^HoWbXou}IO{#g2QQbX-EFzy)|v%;n!&M7_?+J$32vqrg2@>}RzjV-}BLSLwIi z9y3`J5dYPmY+JPUTl^nB1v1eOb)zUsrOWZ zegUM>QhTi78ySw#z{ZRF|h^StG z6;Xsi+Kd;MQl75@{tFKNVE&6*F-3i}l7v5u{}ylFaA@0y^6)3~ZdGkf?x<|P@W;=p zTR)w)#YCC>AAkarl9JSF z(FQ{J7yv;k1;XCPF#iQ4U^&&q)RO0`Pc-DrN}~)MqjfL^iZhcn)?w;U4kAC=@x<%j z7dPXTSOgy5cBcIlUqsw=NoRX%GJ6&;?##|xL~_jHS08=WTI-$r5G9{M(RzC7GpV?M zeNOtCX58G-)X!5X@N7f_BSC?WZ+!x$z{%0(^A2|G+xy!i%YHFWdF9{n$6NNiMe)fm zee8n?&uyeqVC{)UnK8F{#TYOJy>b0K;6M3?XoX$m)XbQvd<_HmyIK-b$~ZUE6NP$+ zuDEl{m+!u#@auCotUCJPPWamB*KZBdObk{5evM_p`VAG;SN6WQb=l@kLvjI@{!qF< zzlYtx{hy1C+>597ACAqYE2Q%l&uq1{CB`Mh81T)$b+ryA%}`NmGe>E^md|U^J&O*! zae$^%G+*jG9o%mQ$A94xhr=PWOd15~?&%3m3m$7SV}8N(-|uwm&2p`A$#3tpr8N76 zzoaM7@XBvf1ih)F8K3Fs6Wd@xop(%zq81&QleE z*v>B%{w(%Nsfs#(5x3Wm?lOpLGQS{bG#X(FR4yC{ViBHshVW%Pgh5b>0)<%6Qd_Z- zmpwYtI2vI)1H-CbDj~a*sCFYqfuJw7Xeh=LS(>rYgr$NE0O3F$zXhIppJJ77E)Ww1 z+9cxJz&;;|6CzWS_;%CKToVxg$w5gi`<0_Fu}dEq1f}>-UZg0{>F!$mJ-XfD{=XjK z3;{)&nUlTuj+aw@JDdFQ^4~4r{c|?RZB!&X3KT^q7F$~7DUe$E3@uBeb)}?}O(YX9 zzw&;mo(1dpjsrcb>1B{FVuN{*72W7x;A=$OfK=2suBB_0-kNy7AIb#(Z7aNC*1 z|Bg>Q3x2#tf1TZgY5&K*g6sq^O72OvS6T79%fF4+WOEZpVOA`2tt06Ay!vhS*M#Bt z+YGPdt2)T;U0kcjZ}wt2CEA7RIzJ-lqSb|~+1hY9*l}J;1qeFqDPzwRK9efszcA@OcFlGdl-}*qqine5 zoA-&8u(hzqHx4vn4{qrX=EG-pZG07mKTaO*HG`!T+a6Yo@w0^ZY=_^O=2~o4>Fkkk_FUP7_x3&1H?E77(2n*f|N#!|QZ9VG3mNg#baR zonlz9SbcCfKmdXy1P_q0SHpnfv}XEJ{BAW?tcBt<@c^2&oBP|yov{LDA6n}Z2HA<84A33wXHA@ zF^G|(z<{LXVlkLeCFHPsNBBDRXcl0sS7N!X;BaC>f8-|yG+rrIqNfKjCyLZX^)SI~b&+s#RTS^qChP^bwza4FT>6AvU}|p__>YvdnTmXaB2_VwyouBR8X3gc(z+O>`{@Q_ ztkdPfx)s)9>rqo5YC?8$EzwqH$CMq^G^b>w{hk_65~|vP`v{nY-MwyV2MMT;fDVGx z1L}iQw;DJD|>xR-QCH3*v&1QsZZAQ z>mt&`O38!c`EPnI#((lpO@Kd){}|RF#74s3g7wH=u%nIb5m9D2l~zvDXl^KIsBJ8- zJS#N_YM_eBtyJqM;hnGyj7vSV?apXMi3?NS<3DVJ(M zfk9MD(}d(PXX{rzvO(rE00gl!XOH;bgi16dhj-R&YeYv&4;M~#M8YE}i78?HHI=gL zy}gX4mywHb&b%kiB8{>Rc9`hZ#)8c8{;%^o-P~O_-Yca7WE86aS=|9`!6ryqDSLMn zUs5bYBXYe0|M|U(dcxG3#0W+<6}vc@TF)xszknKp%^swAhQ|}0G=JEVNx5K#KnnYa zrcVzJMA=DO6$AbwpBnby0Q_P6cjf!7eSYF7u(hgw$sLQ?q4Q#>9?GRhc2AhM9HN|S^147kfiFGy zS5g;Py}c>t))Z0^X!<*E>u~T~t)`Lb9iJ+r2$ZUJK!Mb$MM@VaukT#>z(xxc9G_DJ zrj#}_>E=;KuP}2bl%C{kbDhHW8+@pZEJCL2xFJjZ+&YX z^K;g&U`2yiSVM>J^OyL@5sRjb4z!{y|6mP+QlGln4-6e@jf{v^5n)B8RDf6z+~5Lq z2g-jjHr~`{+=QvzqwHiTF_R-yT7{EKx;Gn}N@DJa`|ADI$WKh2GK1UVU>L_vg9G;=alcHqJ&{JF8^@yr$!i*^2f(0#LRooZkyVR&uR3nv& zovgvu{lEMrU4PR;SrhMg?r+o&k6T9%l}A-80@?Y3m}O4N7euX%kRJgRsZb6&21P0dUS40Z`95=-;5s}5%xzvVFDk+W!KL?+Oh)CDySk*Ro{<`6h8O; z|GPbR;mp*;l%pTr3&kF+@xEvrwKP&xW#tI zS{2r(uHAq&TKN_W5Kv(^k?A7=brYFB5>Pi$J``Zx1S=66#F|>0WHdy6M?4Wj-#o(c zABKSP9mg1ntl>I)5WQ75YK(ZI4CxF1b~h41^T*Gz9)~$UK(>Q11njZ)lDEm-f!r#Tu50fYTj!PP*e#101wiEb_`ih5Q#TdG*)7 zrcz)^QZhN-t$FNG>UdZ7=}zj9S6OqFI^L~%drlYAq=KS*J}L z0o5v%R-=W6wg_sz5UT8ddi(8U@} zGPxA+K)(FsCG4#a{@Od-y1PUdbmk9|a9Fa(6Et86jzx^+Nk(?nUY<@29Mcf-t?iA~7^Y0&~ex>?) zHT8UCC%>(B`pcd0`P&|NsDwE^{3%eX-l)@z6a`|^*4mbkn82w38DG%8$jIRv8Cc$> zQIMIdkiChD^3tNB#mtB(6END6<7^nkj|wnYnRDBkV;}F3Q2~ZU0#yM9#D6R9`2lsb zA3oxA_Jn18NKHw_C@?qy41rN#kfiSMz+NCumlIQPDwK}Sj#zUTf)8}Bov8op!cZyy zq=efGj`T+Ry+@M&IB~gL0#h~H8x;;m0jx9e`Pe7iYf|l(l$50MNpKH|>h{a&2(>;L z^8BYnrmw)kYr}URg4Td&ogCYZtP`$X z7AR18iPYK-SA|Q_Gj(tM;-z;<3Pkl5gAq>|TM&mRAHDDb_hSC6h4A?cm(PzN9WsTx zhTbw#)#HGV1Bb4_hovJhk1j`tC6tQ^)J`KH{__N42?qFYFrNaa@C#9*_0hxUVi@Vn z4xwINa*$M)n1Fcu1(X9&5WUI{_m@M5tKt6A+uaGejBsq-bN*(IVogB?C6OKAKaOiH?fmE`<)Kkn+!fTUJMOw3EWGApsZuAUi@ z;Vog&ZG1E3Zy~OBMnN!u z#5lE<1R2PoXy0t^^fe` z_5!{<@)_-spUuTCZ2n0hHsa@b8q@|3lRgDh6>?l*~KujJS1@3=i=i+;C9e@-C zj+=T*+1XFX+NMr9y11*{9brQ99}trNWaN5F3$ z_QI>u3`llhA!Z(CRD>l$?XY&n2beXuwY@Rcl-S|Z38g2G>Ohr4TrMfBP*{gyv2-}0 z4V1(*B$QHHdz;Lv*8=4xZb6e)<0Yc@;8?s|E*f9|?1fx^LOe1iQtwW(P*ha|?i4Cf zhfU!+qdJZ;4#cCk_Ah|@Rw7`OySN+H1_hTcdd_Y9*1uE|5vsIZp(wmN(HswOlt(3D z{Eg8u90gMO~OeDwrF{_qQ$9(W);ioCnXiW)95z1=o1YF{QQY*?gS|hr>Ceu?a zXbNvDYWb?Xr>G*;8jmLQo&qLrID@22H=*_vDJ`Z<`%yCPiI=)KCq^GFe7VQjox7O9 zdJ3#>S^`B6vvgSC0IJ|=7R(t3-)RR_Vm0(hP@;|kWXN#GIe&nq5xmtYf1CVDDLK{B z>EG8|hX4Eu>k-V*;;=NMA)~+tFa%_1ZoC)*a+ZRe2_TGsVl!>SgD^{J0n?wP=)HTY zJyLT_Bzh&@6beXx@xtGz*r#wcJgMjovd~i}C_bUJhjmxVk__QM%>7={v>OkBW6tQN`;Z z8_%$w6RFeKqDn>mhc{FhFZ zM*BvwPT!KT$LC7Ccr}}7E_GhKl2*z-$|rw9o;-Dy()NrUDcxvVcQE3A^2#gV#llUu z0tD1)wWlteoH21G!=`_zZndzL>FBVGo51=EVL5|g2R&@W$7WM3ynsyi#1PPfmWcTw zVzVhcv5~ilPDqHI33r>~_#l0o*qy5Tkj4+D8GwKpsp*bH%6^5n0x1*@A%xxL*p=B~ zfAk5KQ3rP)1`W^d11wXFAuG1@gnptyF!(OEY#wkIxTX_Wh=JXUP1Z4Wt%qrxy;X;*{7*L^PiG3OzHWFh}6c*ZSZxG;5{FpQalJJ+BOlkHXKL66HpKqb)7s_0` zPE}^lSK$X_RDf!qC;?K8|ES4@2UNhoch}FKBDs)?h9$-C%RuLlORvkTg#VNaw^G*; zCYz1TjoC9sffo%IDZWH47wNH!dO9h)CsOXxE%kUN?{}M8$jjsS56GWCVq=~;UH%p5 z@BBO6CMk1n203GK@F(g8^HQL;+D+xZzTck){Kw8@P&an;hyxP`f5SxNL(T>l<84HS zP$tggjgw47_%|gfofOLS6*mvi^<(@eh-+Xh*ak>2#tK@n^dYK=--$_Pn;+=_6<)LGQe zw_Q?Xuo$QcP_9=<8v>@!mO`?(qhz{bm3p9aV+}k?E|JgO^k0<)A-`W)Q1a|KR97k z+G)2jLnjkgEV}UJ0r28X>8aUM=3wt;rRS7|<}n~I!)>wj&5g*@BrfecGB>aGl`A#%J!L zI6asdYiSRm3rWC~Rl`|qcDvDF2>Z{5E6y{(Yj~X>uDXqi)MJXkut==Q47XbVWHCWG z+{DGk!8$p>ovN8DTd@8>Ez6@@}tG_yauxRs_N+-6>bn+$bmlW#EsK zvZLiVO8C|GVIU|Y)K#WVrxPfU+yzz`9flNaWq>KGBN@tSDTo~bDG*E;Z@7NC87q{O z-#_pK_58x`Zj$Bzj(*J#X&A&Qw%g;V7`pLSO2geM>S&HJARpa0QV){Q_No zppT9M6i9swra)MxF2N}fNapj0s1&$(%Y2LiuO~(F6o^VoX7b+O9$iLIAgF`{+RACu zZyx3-5P{=k^*H|#GI?y;`4=y0rHQ=R(#gcdi0hgDi)}2eOr5}1Y8tUnw*fFypYxFU-cMR+@0F(|&tY`dt zGI@PB=_{7PHw56S@3c zro7O&*jQM-r$q;;aCH{>F@f4y1f3j!Lh*WfdZM6sbMigKi$d*C%oVy2F8O`|1?0>~%hop0W78G5EW{3WaJTk~uv&af0#Uc}hSH!4Pl|Wa(Xt zC?jb~5;y|=DUScB^6oP)O1-6zmb9UEO3ZhF0$~-PK!I|a%Mhwm3Wezf9jm8Sa^+UP9tKUfq9kL|gXt5L-&K09fTG`Nvwlzfyjc zE+xh9p9^3hdNP3Y=m*|ICbpD9wnIJi>fpuC+WN=;p)9{8_I#vREnGt8=n9K;xgCR0 zlYl$J@;jKm&=74Lh@b6o4tTsLb*~QaU+BLB;E&|LW1oCVe$vyY_N)AZMJ2m50 zbVPsBa;ME<2k-|DdG4&UTq8Hfbsjx-=H$*D5el3s0Q`A; zE;w^&Zdi;@5lEi&A7vg;puu2}iO)x+Kw*pP#(lCy#jr258q1DN>Fw!%i%r0;c^3~f1uroz-=E{8j=qn!tT^69gJD+&C zvAK~-f!ww)iGymby1BHquBm~6^nd&h8nt)Y5HkQkfm^40$r@g^bUvLve}8zv)Z9a7 ztD>(oI`Y{alg<)*=?RLv;?%ooFgl9K$;=^7?|o}Ob|(L%I1rar2NrE7cVceU1wP_b zLq%QMn2fMIda81ILHUKceRGc{#dP4#OTIM3k%Cr7B#m+q{ zmNKw_9!E7hUUs)HZpYntDw>z>e{SP5cZE_XEoVEErVf`-kqPnf1L1W6xD(q84ik6w z=%b=w48;^H!HFRT*_H*36Waz2i-arGqF?S5_JR#+v%L>_3gx?sXUj%P2k=L)qG%($ z0S(3$WfjZbuhkliVF`|aBqPu4zS`rNn4q5i zRXdu%iYrvh@VIl~M9ItrtY5{MBWI?~!xJ5G3hN{jy@f=M3&4xhQPvY{<_ksR4=D9i zrLMRH`RFHaFTD@(vX`1c*h(0K>}W+Xu>sX;V~K^FTntQ-{1#Kt(%RN0%r7?_cbW{Q zfiSh~aXR7t5-vcL=T5B9&;`Js-_J<#AGWYmQrww+pDtW`4|#sht?Q3%--ak(e0Qm; zjlx=TV7Vqa5X2IGkSr(#f}G|LbYoKOY%-Y`Y1zq5Yb?WpxkV-%ctv!2X((K8lC)gO4PB&j&8a=Wh#f8)+TTvflqpAP{m?M%Yx2(LQ z0jW9KAfT$uGX)J8ooGU;RiX8&HEJW;l^luNka#s9@S|5&o&ZsbABs{o}q4|W_TorpKejTI%fz-QlQl5L93NAV(|2e)|^ohNW(3kf$IkH->H|XTYS1IN|vHP z@+8$8y83#x)a_W^{52oHR7?FpYze<93@DHtBX-wVDyxT~%E}bOQ~UVQ6Gs$yp~zPs zyf-{A?E3j~|0B7hE9l>Ml=Ud&zkpPL9RCel8R&$iq>f_%@1<)n?!^#q2v?I+F0fPZ zz)4D?I2R`y()?)kzSs#4B|q!&_}9e4J8Y-F`bg%J0RE^^oP-b%erk%_1xA*bwY5qV zez0U_;)}?pCKlMaOvIGi^NGzisDab!{DsF;2!dDwN{w30NXJhMuOVQ`>0{iB=|yNn zm4P2rISQ0g2Xf1oS!)nYKvfkRGJ5nFwt+c4;<%vJs`O?ppumjd$aZJ?oA_-QBXxg0 zx#!kD&ll7tb@pA{clQaH=8^urf<5a9-xnMcx z7ya3w=O6m?F)61jB%^?GE6B`6$%EOj!xAcNM218j{Ozx(>(zjzf2A+$w!}_pO^``T zZ*Ome&I5WA)d{0`2hzp#u`K*icMq=asZ-UeKm7BXOn*Sr%*h3rHyKJ=C}zad7qVR} ze<70jv+=ZLpsV`Cp0{V+6tL-`)8&K*{NBDkjj|*NfpVt-+M&V<4VReBCRh;&=685< z2gEQC;XI876ReZ#?sn)0zNC#=203LVT<;-%e3#xI{2^iP4AR2S_B>xBV-+Un)! z_wFV?v+u*VI7Q&Qe|XhD0&*U~GI<_J6`E*$^)1wo^c1zmX%6cpy6?*c0qOiOQ2 z5ajc=@33jq>mzE&5hPGpnfEw-OQj1^gP$%w1jEXxG~VGr(-wol?xOYg!CM1D>v`kn zf21!^`WRR*UbuQb34(BYrM`xxvZ9QmKumPe>blvZVG8tkdsPugbG12L8F{0(|8N^g zfkhAALRKueDXEGT_$4`?Kh*c~C4 zoiY9LsndR22vuD@By!6`_uING%#9#$(;ea~aa)YqxZzVXU%dPwGK}}D6>=v{t||$G z19(8AmU1CG*Ff-J*udI9y4m1u*^IP|uqYZZ!MGDEbb!R;>4SGj!xfbppC8d}S*%bD z?1C1IJHuG$?swi(YZcrk)5W+Mtk5NE@80*>Thw0cSDIV>Xnj8Zzc)oK6};5IK37ms zAb=o8fr1J!AmOyKT&84Fs;XEky6kM;Y6^1!&bS*fTL$YK)g<^b+CBueYlaiTH&6-*gR>&chBQSDEefZfQUA%lrNu5(+r8l9=RT}}{X;noP ze1+J>lQMSstjoJksH7LV`3vSrg|D1YFsZb>gnNAjx(h&o`T2Mx2(?zF)u@{1k4rvW zCPRU23kjJ5L9KF%K#T&FS1h1F+kfu5REyW%(%)^le5RbEK(o=*X|slF{KY~EWRDV4 zZ+G=}$uvlrG>!o%XK};y!!mSq!u(4*O9zX*g z%tEt&_=7k8{1@S^n|z*3``-RoRtahpEI!F>i`i+=X?L6}Lb7>Fbn;FiGQ00rEV*#j$960~wv-|{@$$!xXFNpH zjA6)#+?zjsPT^dIRB~jrCW5sk z)lFa~PGHwj6Tij&o5Zl~YWp9brG9J5^bP2c%4*Y{c51t#1p1-2Rcb?>FnNRg_3wG@ zS$8X9h+m)c|G|-HAoc0#nPjt$(Hd?5&TjlxYB&bNPpE_ny0S z`TVFNz86$q`<&4;!k?I^#Q3e?u@0QDW@6DAHR>*KuK3e8{)4i0 z@UvH*K^yJ2q}pozsWarsaT6(dw_^%~iV{Z+YOO9@@g1=*^jGiBtuM-4XVBeh>f9|M z0%+(_4+9l2E&5&dhh4(B7!JD7K95H&>+ceZ+;rbJ~H z1_yR>-Mx=)co1i!-#_pKnZWHwe|iQSlndzg55zF31TCu{y<6cYZ-3|kaKL9s{sZ#* zQ-7A{KN&G)juj`fR5=I+6e#spY9hYxKliq^P)i&P*^-j4yjB%{a+|BHU=+LBF8ApI zTPCvT>Y{KdL$=bei1LP7dY<1Ubh-KE>{lPWH9~RYD^iQq8|6}|P&H@X zcgO&55dVonUH`-UCkU1Qq-4Az^`GCqN43P|ni$N{$sOc7D(;Z$U0Sffgs};_#Bn1K?DKH=q1e2>05X6M4 ztZKPfEKh;!zITuO&!%*x28t}9OF$F|$Ib;5NWV@MyZ$6xLON5ma>upy>MEg+W^4)%2*JwMcH zwS4@Sq@*OwJ-eX+F;v9L#at^4>ky9gpqtT{{V5g$bM$OV(uL|1Z0U&!h%HWso|5V< zBb5>wx9(gkS!i;hY2RzFDufl~2snP?7Whtg{N?kkMHz|H=qBghDr8{No7s!Zo=J)R zszeJYwGnK}9BZw;Owo%>qv-tNd=?Tyd`kfV)jrGRUT?1^LgRI*z%y0r#m9Q}N|}(o zN;v{jYgMXZTVCN`WIa|SoSb#*H1d;I5AZtamDT*(W9xy^qJMsy{Nx+|#@FgCy28o^ zc4V|n^11!?x7dm^tVhVg&Fi>7Yf5X@{^Ta|cTRsSnn=dDC(5Cfaz^;_%>U z=2NCo7Hsx%cZb#2dA-cZFLumW!P=zuxa=oCW}p7e_p=rhaQvo(c!c?M=&mJZfEZ9$ z#o}>d%R;QT!fuJzs;^^rir@ljwQaE=(*qXD0E<*5f3tNpVu+$9d&BkOQ&UzfSNBHJ z=4ND?LBLV}2HyjS6M{`IaurA`=a_Gv-J%@}|A47)&@{Sc-1HJ|NN_*f?_&m+HH zbF_(krp^?b@}Zt=!0I##C^uiUDsRA;Q*BFI%Qv&vV0Wsd*9d}HugWxF_WC<4QZ+n4 zg*rU=9yezWh{0cC93?QgMok&&Pwb#XE=ww;sQuE@vnZ>kXx93u_8euKxa3eV=!_~E z{^Q=_-lg&%`_z3RLxH_Mq4FQ&a|f342==3b^4C3@FLr_h`&Q1ZG;rY8&^HPk_z=)o z4-ULqrX-s4aqXsZ{tHO#ZTQ7Y@gFJOopx{pSFVg9pp;bay)O0E%vBVf0pLIG-w2(D ze7B;!G%Ra1dEF{I6h2q1@TYd=@HM|_(FFNV)+|Vi(W#}z)Aky1Uis{Q_K;tne%p9* z0O~s5I|xhLQ(y9~GX*P)Ms#}vCsO=Jo(zuvnESyc0OlWrW6HA<+@>Yfsq<21(KQU!zEgcIQlfa za3bxISqdp|%rSOJ;5X`*bN!f@Z50-X0;Qs%e(>8*H~wNBNrA8~kYC}PuqDhgDrual zbK|Za#uLdmo#~(|0@=oFGIJTR7OdaU?QqL1@kc~PI2GVf37E_Gx`8g8`| zmlfaA&dw2?cAGgIflJb6#7prXKIV_t4mtl(bU6u0up$tEktbNU%b+D9A_7(fVnI*h z;$mS%AQmiea0Jj8yd(xR2J7T3ofcRp=XSd>Mc_b)!a|)^Nl&p>OPinwR1SZN6=W>) zz>js*luSVpSTJ`S_e=}t6@nEMKLHEdwK6PNU(Zf~QXmLwK|aZw|0k_D*0czbx!V30 zqAKy)sV0m99S%pAiPEvNwFR(-98e(Wke*~GHqo*=lJ`HL@P0fC6I6>pZfmmg%VU97 z0>^&=$(qL=B~P9%K14w-Cx5B8{nxhxEv2c1ML?CBVhRJ=%;dE!u~{YD(E$avwXwJy zYc%)u^}z8XD=B0L!2t+P8@kL|vnGF04tf6ifo8=WTodXOCwxg&6%=i5;Y~Ae z;yFwi7~2!-+spBe7E!5Jr~(9|ht5I(AWvnjL#P7+&YyZSB>YH01Dd{vfVHv0l4Obpe@hQvq#J)F8m0K=$p1 zdaehlut?5;1xd(*H*o8HqLz+W9zmKNt3!+P3z2^5p1wbCmx=pA%awQ7m&Gdinc&?}Y->m%U$20iE%b zwPV`}3SN_KQi^>863!5CM3g@L?ug-bNq|}?{5NUF4SJDO{^RB_od4P>{6|#*hH{aE zz<+^CbTpy{hC|{p!(#(FBRhS_uOXlf=rHaDC&l1)`KgI19RK;bV7Ja?R}>O@`MoQ^ zL3SLH|3Jrq`wo5e={G4zb2GcZO-`0fb(N5i;PH6mQ%%EKW$p*X3HW|wRgF0xVZQ5} zlLuzx$5EjDD$?`;1%j^9qCsreI10?tuuPqj)c>fwOaqb31I)OXIx8?QZep+{Y$b#&V6L&(HBl~uZ6vgsM^?`QMe-;p5xLP>OE2$ zq%*di@t8@3)oR(&v3+0%`Zs1po|2NPyu)ID%52<#-U<)XSfR-Y$oOMLlRn{vdOhSl z3KG!GCd7%h_D%K%y+rf_uNN#`J=kNFF}Uf5R^wD3Aep_0prspC0f0NTr?rwFOKi_% z;uyOFS%*le0KfPg!L4&(Fprz*d2B_JdiV*-xe|s#a1BwB;sg*A9Rt717TP7kU;mGF>AZTfP`-0{qj^A+82klAAUV;n z^GgN$n^?!8_8K`v^ZG=tbNYlK+@#@Bx%MQb0;KBvf)fCO919}rzdRk8J1(i0VzqXy z_cCTr6K#zJhZ1$5)TA5eEd;R(Ocfzn@F3^{XRf;0uP$)xXfXwx)nS#_1u79(7ue9e zYnUv=Irn>*0;N7FjJZ?iPNjaJXOv|~6oIXl))B2~T87UbNKis=|vj8E~D76#psI|0(A`@*-LO3s5j$-R_=YXJSj%FrrLB1HiRghF$hZ z`8JHbJ0xO=HgaPHb+~}FkB&|kIC%c!z8hm4H|=KSnm+)49RFcmhU_(<%YXwPeMrR~ zXu;UBCNeS-13|!fGJe6}-I$md8Pt=fKx|=z&x@!}2B-GRD?%c|B(F$nYC*J&u?)Lq zzT-J0O-Kd9YTCxFTh+e=;O^h2mCQ!`&elBk*v=Q8^JxJYsR_8ZXD|$VsfK`bZ0b)R z5`-b({-?KNXXf92%i)hck@|c?b7NYvxVk-G$`V^@QVJI&#b&orW21XKUX?0B_F0R7 za`c1GSKoi9uPi1+1~T0{i5ocBD-40HOONcHFb|2Mg{vvuglvl73N6X_3Jn_)IRT?0d6Cr4NM7OQ?^CiCfzA?{ACbf$ zTV^ModrPXbSeZ8T3e8Hc(9^4^8fVN3f7DgXmB(x}%g=Yi4j)ZMs})knb$7##*xfxn zdf5oULqcPiA`qi7So_#v?Lf4TF^Kk2xtuIH!2ZwQa#3$$S1jFDx8EQ9m;d_}wX?93 zMZP%5gN{S(&it!9mK0Ty{UTqa*(Y+-vro9!R0Va6PpIFu+wHK%aq{;ILww9vi}7sS zDM`uTAo+t7 z!M(yk7A){yD;k1Beu5qj5)nnwjorASMEeNfkLN#{xFWg*_~ZCb3H*`#2YL$GSwK(0 zIt%C~WKR(%3P6F0iHX>jE*2PqYh;)Q32ZvRQDAB+V&4FNo})l1wI4@;m=S|M5@|RF zRDp!0cCmNy@$k-n#d@$#URprTzF1`e3M7XWK!I3gakDRV?Mu$So?hk~B9VHXvm1E? z%^fW;2ugj?CXsc=uPzXyz?_9j{byNsUVks~-NA%SK6i8jMk*g6U zjgV`HN*WNN2Crd6b&8fLPs_%QcplP>v19m+B$8RBf<@99ZTBxcdx~zJtW0F~>JS)4}EO+DrzvG;0F*JG?d zfawJO)7|SvpBDe&z1v<;qOM!A>R$pXckWt>$G}w|DK@oA>HvN;M5UrdA}@9XuFT0lXnYHJ!#p9e2i+;uPL z|Me}1w@reHU%9sWQU>YuV)whW`-l)Tb4s3Anbfv^wTA8^ObwGkt=k_)%@tlBDdPth z^RMaok!u_3$dfmH#Sf_!wJg70nZx?HWo2c4`20)Y#mv>L#fEF^g{FBioEDI8X*At8 zRa=}tn$@aefth4RI$wPvBVBAFq6vtdh>wGw8Z89qyn=TBd+#mYyt%j6U3L9RZe~7p z8o)+&OrwvL3wNL3`Yd(sl$pc0fl_7~6KE^JqFd0Ck&6_zV?3-Fu` znsLF+Ibv4(uekjk|B>-@!4oN;QuE*kB5OC7Ri4mb^2uR@0V}CF8?u@|9G(5e{#_3_SdCHgxB-NrG);2 z`Nw$I`VHTGNbIho>IC@XiFPK%*e-|!(_s-+wtJw9(5ThSH%UnT8yq3|Z&(SH|K9zN zt?WcNIe+wIxg^~({5PNi^It%s)o4*Nu*oRr$aGvcv|yS@Oeu(Id{p`ydvL%spqNsy zyW64gcMO_Xz<=!2X_gBx1mKV4KhQg{4g%m$;J<)p1X2YE-H(4)8aV$ORodFx!sYWD zqD)`B864O&tONuDRRPL~paN7PfC9lGqXHZVDc(WP8 zwN#OV=i<$LzYtV_BNBGWAAJiRV`3nsp^sAPVpxc52yV;J` z06dB`Mx)VYvxRt990h_W1Sf?fmjd#B!G6^VVNr>56iBM#6DQ!NsU77*(1yPCzmIw9 z)$sjxGXXn@$?O7$D1ZWGV*YUy2n)6gEJJ~s2!0uDG8kqsA^8JI?Xb_kbv=vt47214 zAJ@R;4s5i2C)Q&kBJ$_@{+)OGI@{|$mhF!?Y26sC%(`NwjZ>4;r$M*2 z%yEd7o0(z%ymqwt>cKh&+NMmNW(EfiDD}fY$7Z*|6JJJJ20Za;HClM$!-6fu#>T>X z!FIddFw_Y}hDw}n7rYk?&=cMs#d;z@&!*O-}oz5j4h}^FgVAAIJ4y)K?VSj9fFwD%) zLo^nRO^D|K7Ufu{LlpH`)N4>^$1%3t{5fLCz}NzINNO#$$(KtRnp^!l1IjpTs?z&h z*TDtrxN;)~#m!4F1oSIMKlx?G*NcFYP`8zm=Yr zQs2P#I_tpilI+Wm%i3QR=(n0qwR4wek{Cvf_s--g(BG0*a3!nS+nu|NNJ4Ey&8uxl zFT=K+U}>|oldJ%*v%7ovmK;sQgioKDU@h&zIt5a$PJ{L!c+Kh^l5UHI&oCR2t|Htl z4@23x@Sn}78MX48^|b+URE;#MFil4P!^IIWdlaj3#?m&x4;RcyYFS4CSXz!-$wFfo zd>z|&Sq;j?3MJ*tN2Nl$!ZIjWu{}*juLMuYn@yQZS?$1$nJc$&EoF4Ibhg6}*J|s8 z?UZ6o=6K&VT#LA(<9IkS)Zrkg2>xev-F#N&8h0SgSl^h$D(9y##a&l5elZB31 znMKtR$loj&8>8}7N*0qUg?Q&{Orpq)Ch!L^bJXE4SB_oB&LmDSn({?HPKaj}CrRTe zu{1;91z!0O?~kGbAe!PQrB4usfZ-BAf$|@?UVK{WEkJ?bz}F>r-NsQM`1igaZ5fDb zo-h${VY#+AH!MG!o0Ef4AhH5O7hqj|iqdD3eV!_|vx+u(4dW=t=(rq`%Q|MjJ|cLl zSe8C)uT5d=qDt&^WedehMa`pfH$K=>`R~G)6-s`MYY}ot-WJ0eKame5=BKkV7$rD(I zrcV*I(FTS$(ycp$*Y?p@D0vR1-n|AplQS`gf^p48F{U;P8M zBaqjYJvR-fy)zvxXGL|gSL=m)0Xz+XSr(p#+S=RTX(%-%6`qFT%yIBE1SV|wex1%9 zY#RE;iq&p|6>@I38`eGoDvE_nj}j9SVTGL8Xo3}TSS4f6OCJ@5rIH&2QMq*mdji$(1d znVZq}i;_D}+8jT8+GVzG95}F(^$pkkeo=|VcZx*hxyY;taD;f}17`?`iH{QGZdOJY z$PTrhL4BY_=P7xOQf4NG__Oam^P&{|DVMyyLM1H??*E)joW4#8zgAzb9+_!w2)S_j zQzakcM(}|XlK-eeE;gtF_)p2ldNM2||B)Xf`R~h*UsSXZqE*`U<4wcixnsFWu?3in zZPkc`f}Zf7SVUx4A;+O7{3m9sBcqV>D{#5(@pU}^p}hd>2mt;#{)5W}LkG`)P#2)~ z0<0s1!9$IsKr;S|1xhB!QJ_>RVIF|c-6gQbl6eLeRC!}Xt%5L1i)hs58p|nXL`}Qk zat%xpR&JzSxAmoGWbQ)VKU!Y6%Z|$CE}s3Jin`$P4(}gHMwmo3L`Ol1p+q z-LN7sI#R63UY~kj)2i)Fq(9cYIlMx#eD6`}2NrI+_2Aa+gVW(#Ru<(BOuk4!fpy?dvUhtB)k1Vkbc$0PWOcrwuhr0iZA}0v-t&pyN69|BFZi8M z!FPfFH0LdV|6E!)Uoh@8Cz^yzJo+|vr41*4w?yL?cH#i#!ltgrm&6ypti#f4ReLD)J0&8%F>B@ffT>|iIVnz{d5xp^+Au<+vF^x zTv*Y9y!nV<@YUjaqs}ngrXj4{#-_$dNFxJYx3r1T_|+U?O z625Um*RL`Ig9d|cY09+!Nw++SjTpUGk&*ej{k(7JXvD^Ujooe!&KCre++5bUiVPDd zMcLRc@Thyzj3`BMQBE1r*eSg=Ry#6QO3j(3&X1%m2qKJQ#Zv zV}Msj82?G?G9SE!Itt+My&#>VKyifX%Iu2qufqm2qCkNoG8{zUKY4*^p2v|=MSETm zSwWhb0R9W^!Z`l(D>g%r{0E!U1ax75|3=!|;7G5kSK|@UNUzt!GzR8qcxmBsyLHeY znHZMmSeVATy1JyY)DGayx+66G)&-Hi1%}^ndmQ}9H-7o$B1V2P zjbD|Nl%(>BICd!81*TrQ@KaJB7!l<{%{?C$QK$l>D*uGFCPsmi3Z?{iF@4Y+RJ?oJ zz||+F0*o`qh4II!QEz6gSp!pGpug$7s3=hF8$bVJaMygg_|Ql%3sE91&fOYW^1ul$0)i~h5Xm#EF0m!5g`Sjr;K_C%M=ID6InZ< zDqfk!EDRLFSRqrcHLexoKhPhsE(w}F+45_PTfhOA+ik4F_zyID?m*^lnBEv!HJ)-I zjmOC?V9sVPlx@=+R6vQ}ip4m8{Fr2cu^XV}})iGSYnk>5tL+=-Er|5dQ42@*7Vl zd~RY1DRS1dS&;~%a|>%hR|GGtMc@1EWjX+uCytBsfivw12wEm zDF3Pk+mqEPv%vOVV?PEfPL`~{7b_RjC`&19xCRE73tAV}uCV)+T>SWS8Spli!{L~F z3li8rF(I+Dq6eB{MLk7QLK3_+lomA}+ZyV;(jznXkI0CGS9;wMkvc`6G+7d{PPFFE zN3c#*zONeolZ-9OgQhJ5>qIT3R&t*cXEjm#q{AfQD2GpgSrcJ_iheShj@DwdOFn>X!!Z!3Hzf5E&f zhs2QAtg73qaYZ;V3S^s1kEWaHA=`689J27RJ8Wnp^vL|F)oM^}4c4B!W%^Na0^)dN zMbn?-{mARNLHlo*${nhD{-%}tO>0*}U#{6~?(FP@(G!MIa1Ht>eOStMF|HVGG;|F{ ztJMb2nDA~XXk+>)ao@=pW5g~4ZdX{LX0yox#V5AeZSiq&-<)!r>svCi(`BA-7{Yz! z=H~j17tQnsh#7%yg%U19z|~J~1c%HA(#DSi2X=DJckhz>QJ>=V(&5s&deOtcY7?;% zP~e%}pGkeYPvZiI)Vu4yw?*nY>CJDF$k3LW!QRaT6o{Px6c~Z7j9hlaS-zsYbfkHY z$cT){h>XaPiwaiGk;yzru#?#-RtSRF@+I?LB$7Uis0^VG$5XaHjL0BJTx9%(NL5XHJpl0R@hpBA2_F+kF-U+vkl6AuiIg z&6}ER4SrTydatKjG?b|*FU`-MJTg>`$cT){;7dY$`~b~{W}{hVHpI&9ay#I?U`)EZ zyWzdj?w%faZ?wCo8=f3Z1`}pufFTjQH`;EozF- zNnmRj8M$zPq{R9-R0#-TMx(JPz+%53pQuWYx~Uq_JkZ#!4R*O)M8;G~_0GS43zY&7 ze)bO*jBa^=d~4mkkAC_(JxB2GA9#XFfj{~ad-CbWDe2eT-Cm9YF*$zppX}Y4r~0M9 zd21F_U84suJF;u*)PWGjHJRa=R@(h`sjARclV} z+~MeU2p8Gj)0%1!ox!=^*XyI5Zn+)@ZWI0!yJakF0T!6RY(@i6cUqM<=|~;gq*1pj ztlV!(7Zw_i#Wp1MJXFtjq+Ka5*XeS?IS#ZMtp>H2hl@^1NUDR%06{7RN~Ig=?xbkrxLsg@0;{eg{CDyTBs7d6UM?FZpg^g&rp-m@)6fq3{J3q z9jVhXBQhd`GH<~P8!&IdYZWkWH8eNC^Oi=hhUYDKt&W)+0Tjaq>Jj-Si+t14Xtcf3 z3}7~!;59P_LQaNqz2q+}S@SS!sTv%_CIlt7Go zW^4{Y7Y?R8fHtx*U8x|LIz4V&2X8!AU3aaQ|1sw9hbO?l^Eb>QzcPFMv=9E{m6*6Z z>7HYjp+F7t)ACUnSY~Bh;24~(Hkzp&neSNT6#BR62 zYLSez3|K8O&N<{t( zRsaQpgZfr{EIqB6)8)kWJ}?j@rC`};a8TdkK#&4tzj;9Z%FRB3&n#HK0sgbqLMNow zt0zLNw2Ga32l+vN{Mrjad}~zdm>X-1kRKdjJq;=H*1#h&d{icKk65FX?eeCP3LKs& zhCJc{+xwQ9cSa=af`tSR%U-aCqpRB5+AyY1<|r^FMQ+avP@u_-l*nqcAkpcNMv0~5 z>#!nIOROmtZt*&u4i2Q55TB5rC%TI^HZ@}9!Yy8{Qo%(>`ixumZGSl|fU@>`k5S)k zENLfixvh+SqKy&N^p$!_1{DNl)Pbko|A6{a(eV^tkYgWTOe&;U>5aL?7wc7aX76({ zYH36V6qp#7sHDlsLMOLMr&9m1jmDmS3k zbwf0*j?NC)$UZJM4opu9i&ksYaB_AR80{h73zyr4-PA~L3RjbMxsiz#RCRYxw^Y$q zTPGYfCDvpHW2VBQ)fyG-1%j135WR`LPr!c+y5~#k{DhQlg5>7r%4hhks$w5)c6RpH z70H7Dl+T`hjtYXQlh`KGa!~@UMdB)Tx9L@ zs37Q!ZIA5Wn>A+$D9EnY-&R6_@I4NkOrLruc~XsfTIoXDsH$tP$%sc9c|&t!T5_t) zs`?u%gYd-Z>!or$XpvO1D*KGiuVu~aqx9IMH6jBf(fVi@dcXvaA<>A0paw&b2y4{< zk6)&*{R#(y zR0@>8O+bNt=oUdm72-JT>Gcj!4G*%^wb$T}rWtq8xw`-4$Ow+Nx?$XrzXp@#NF~S! z7Mr529kFyzO+l7$ac0E)rVq7ocRG7U>Jt`Bqb6U~xnmGb6^6^0JHbdt#zF;SNL^#UOQC1zyTDWmlmS7yCWEH)V^{^P zqo>C~r9c@Fq)*Ax6i5X@K!JWiu&q@tXJL z31}Bs%2RyWMscgUgWo~Mg(xlP+1xbAL^Ca zgLb)GU;8m<;P!&0?Cgh|$ltOt(g<4w0??0m_~D0@d+iApfml+IhK2?z>Is4|pJ5%+ zQ9WqZV9Wy%OJ!pu@Dan!#013E01HXb($*4a(J^@x9jB@}N_n~76iNn&FJ3@M?!KS@ zl3M3YsOhL6NbElmgmI$d7}Nva_TQ&mCVVeCx1fy@Ts#DujIZ89l1De zwANkt@&Js0RkiG1@Tl0VMjPvSlWI)oT9?(uHX%U^xa6+eB3!!u0UB92#-J-{%=v>{ zmt%Pv9Ui1LVwt$Hu+kO_(&aH%Ff7JXLOfzPr$fud+)zU4%jCK-Tz%PmCSKtXSCf0y zZ@Jg1uMbdF`>pL(OWTk<I@*u;lcUi;mzsT7!!luV_-HIF??r9dt=9tnb#HCL%1 zxatwQI#8vdgCMtAOoHIWOKe)aZRH}77Qj`JV${X|FOMY=MpGTxnTS^BJz@P8F82X#X~NIU;OP$ zz7FDZQtX;Jl2Rr7qSx!;84HjENr7KC?$JWsW@wUS8mO}^!$-)im!9o40QHePm1qN3$G8ah|>Mn4Ymkk<<`P%hjTq`+y%{p00q3@L7 zl5Db@xBIgDCHeMy`QBzXdD&!>Y}SdBO`OGn=ieq1tn|8bChmMpkq9c91E;T>dg={@#5B@bfRY-?Qs=oX z3o@CkdaIZE^|MtZJ8nROrU_}& zlVZyn7__OUNaccCZfcf=n8g!uLQ9Te^F922SMKP&Dyz zwhmDMsO^XWZKpG7f~t*bn_|)Sl}op1`x+SHL#WFz-M}ceZ7b#0g~L*o(;tsZdr5rJ zPKrfaxn=ZG8dTfV+QiAdWzseV3JQg4!As1swoPu>et$3?ACR(7DIY~*h&>=eusR6B ziXD5LrO%XhGMC!g?D{`|3leyqlm)uS3k(9+$sLC9PzC4ZIetnYf{H%MmCIKt{^Zz4 zht;mO>e5xHk-hTNYtn;P|MLxsCr9d_`%+ln`gi~Mp!A?%1)R1PE<-FF`ST;Mn7;Sb zn^x_9^=;}ZRf`2t1c(KxC|9=G1kxp!6T#&GlmDvb{A=#zc?3VxZ^FMCA<2tv!)Cz@>fDyBy5gmhZ&L`_L z3I$+-T2D0Epkqc;9!Q>?4*`bFwCyAx%H#0HP|-HA&+J@4LHI$`(8I$@4X5^Xp$$KN<5#Z+{7(wR0@0S!;ZC(5A{OZK7A1XkGL#VK8)D1H(L|5D zKMjRKZsq#2dI#=Wumr7pP#2bs)e#?ZiC~C*5+19e;ooMi zmz(Q3ba)&RxDN&o?tVt``pa+Ih9BJch3&JZ&r&?U?}KEiIcH3dq2~plGC#I;}Vtdqsgs%tdc1w>o5@?K8khrvtin zvVnVi!Jufe?NbfPa{&b|SXW0%MJqt`_G%jZGMUW$d*(<789uMKQj*NQrbb4e&$OQb zLFOO`D=Z%efTV`xHJ&TwN#w~zkB*H>iw@QV@uKTE3PG2Rkw&nbBDiHxG%8ojO;f}1 z&d@{+^vj=Z=kqN|iC|U(^Sv=_$+vS?UlFdYef@>sfaCjrwNsG@o;Y$0uce}Hv6O0W&(ZL$oHa_n2dh_#Yk{6vw3;-&YFHCKnDrKLD!Hnjqje+J3vKTtrisVHjS|+7pPNvBu z7v0y>A8rWw^jt{bf{l%h(yTFtyuiGT=N{R*6t+G~U_Cmpv>)}Nr>*U22gY!2UpgKuO~DCa1@XB5YhpTPrx4123@g^DUn<>^)U@$BA~5B z?|2*aDMc2jc=8RO{J_=3?Obi~n4rCUuS=+iKo9^VJw+=u4zn_Z_ zegIj>#2Ud@-nj)Qleo+$U)!f9^M=*;;0GJm)S^xNxa7Qr!j77rE6SE|lQZxTF4%Yh z|6D2Q`PnBQ{GShfM{;1X2|dr4b{XJdhy_-a1(RtR7aa2q`^IE*Sr%Tl+5sL0rjjr) z7Jqy`^;CTna85Z4%s{w?J8ez*=@JohW`v-02eF@A~l{1R|FIgu=~cF zWEti__BEb=$X8U0)XQccc64?~KgRlH5#V0=B*$|3^i?pGm`c%z2;xe^NmZ5;U3x2C z^pn3(UL8bEP|Og)^%viT{`PjsV$*`>DEkx?Wp1p=F1dTo`g3vi2K44Mj!3}NZ_nGm5f-RNC6it&r-$@_UyDt$#Z9I7n{wfcXHG;*(mlr%a^pob~)Qbi^SBbRnJQl4G3KWmW$0ni3{{XD#|0DMkw!&P|qo>Qz z1`S%Dx<%N)@!iiqf;MpQs=vH{$K9XDul$X>zJNAx@Js*p9keNkp|oo7>n}cpHgM2$ zy5fUheWYN7Qxdp4@fO<9&WEobl!oO8d~KwI-2(F_z>ESt zUBCHe#p=^9FsG7V`sj(Ll*U^jk^hNkJ99A4RuF&Qd~kt4o)_0CHQx z4nQevExNv`UOpJ^cdVI#L~_MibZSKAt63ViC7E=5z^tj#TWah-4W zDY8I-o>))A#FD|eQFSP9b8#3Lr~vg+j^zz58!eL>0udv@?akCW$kedZE>%@2TX()R zi>8b5bXwYZfue0iI-Qo9#B7bZL6s$?&h9B1nujzmH*@Apfdz_Vdd(0jqh4SuFl5lC z3okL9QuI*b)H^WzHaItcHgK?UY%1FDE1c;#i#Bj@+VV!UfuaYFrbbRH_$yn^*G^ek zT~$3k#{KY<-$5Jx?X6$`1UIp=oYWln)=%EiDJ{Z`i<%Xv@Vg2lit$-Vw5iE?=yZ#@pQhw>Qc@+i54^F>OIVt*ympbr+&1)4}^0-292+smt(sS1YeG#kh`@u8N@Ox=@`XUpeSAv@)rO=j&?_&0$*g7Q@8R|~Ma_VTfD8--9tNfj*~-Hl z%S%EwR8VImPP&rvRdh>p3-DsuhiGq9+Hu=jG~yo8$t{QsIX0{XMbmx0z@rVU?DiF1 zcITaU%6g+7*c%B}Kq+F9_4pLIAg}^XyImH>3}Q_hA~GLYxtx}DM`g=hq%&}07RZ7F zmgoWNi&!ZdFC7(KJzJqxKHl4@SoC16LZ0NA{)Kqao!-+597rd%;#8;=$1Of@C4TTn zpZs?j;oHDFSaE8_vz(!3MTM8o;B-n$OH@Hfp2KyvizF2`jNV4DtVN{0KGi&6hhh;6 z6e-|yzu@P6uD#~k@(SMcc=-5X^moN#KFHwUkq^$D$MgPx{9*2i$r?rmYvdp^PAn!f z!#A`>Y;EK=Jzttnx6z^>+&V4yKArt9)?bvL{oVa0?%LuzjeOU1-)ZEcZGD}(?M+@N zjhs+4-Im50d5JV~IPmgLLJ$ArlqQ=S;(r#Q*^+3EQ!@%-0fWa!(FP9ASlNs={N(C* z1a08p$2z10&U>T{>o0YDGVt-R#2CHqF(>SJLa#E1q;9TtHTQ8kos-~uGSgUDJnr) z1r3B18eVD`8XX1x$H1T;Xx!phS+*uWgReLTmyBk%N|IYa<6O&DKT^TAJxb?o*?80t@tbJZa*j0gE1C%^{Q(XpUoOu}{PT1@?Kt z<+(myOj+DH5wIQR#7Bs~<()r}C51W6@vDa|y6TF_s|ynIf9B4Vt*Wx^fd|mvXa4gC z(u2cso~)#?Wi?K|`W9}=dg;LKn?C#hfP??|)Yp-mnTch(8=6B6=Vpy?Ku!fwCn|8% zK~bBwHX>0YOQD$%7gZ)F8X<5Uf>wc?YN86#>J+t`+r9Xln>AUW2{^e}oZ>i#fq_cz zh#M;G>mAFTibh8~47bKv;bBrk2I67TUJUUtioKYVYqTITWZ%05RJW}y4OF+qmS(8B zEw(gJ-D1(&(=R*|z&WBKhKGlJ6QH7QO|z=o*yo;SKR_Ee*xcCEjLp{E_Q3sU0|yU1 z`3%~?!J{XSp$#0o;?obH4c3&8-vE-m8Qhxnn}7d*(PmmsK~(%8E~g->LZeb@Ac|Hu zTuwn${GghgI#p_2)B_(XtOzorbq?$PiyL$eBu>IfQ=HvA%)W~|X%8#h>ZWCsa=yCr zX#S)=$}&;ix&95OcQalaU0c*S?scK4b5OK(ofC>iA3+c?-Riba=XK#Qc(WCX&Oy<^ znp(Uop;a{EVSpY{)OmkAE_7r9LZJ{K53YU0oYXm$N6b9I=}Q2_oEG$6TjxJ7k)x6wAx>V^FK2B zK2Y#$l+RNbzO1?EFBDp!lAL?r`lV5IX|}!Y{R-`8!RDFx!OL#H-N|M)b>V-3eP0lL63;7B3o|(@kIreDM}_4s4K4>Rc!~M**c#Aj%vo8pX{IQqrnt zePIIxvC>BO3SH|ifqfztc>YB-2mN^Iq4~1A-u^kB1^RlbaGkdPYP}vabJpd91xaaorg(poUYEnjRT#VxN%iSa9|SpFIPSRohKKN7uZ(z*>i9J zZBRM0y=c?(^Wl>jv_WmeU~6t#5<(liufszlr{D$08j@(!!}b(;p#n)gG=?@@LR?7i ztTD7f{k$7T8#svbLY{K%QlMPRu3V@`$Z)>`5yvG&s8gD}7=2H{i!Rt| z?Pe%(FmJ5bD^t80T~l1)-gr+mO0%uH*am5#ig8WSmY22i^zKF;I zLGVjBEL)iatTG3}P09o1pzT)5SAMIh2`ZMZvuMzE$-yqDvNt}_W?p&h=is#Ew{4TRHEx7U%$hz6zo4+LiI_2bWFjGr^v3(z zlIX_Y?Upag7FLxIv7%5&Le$z35s$z3`ePar@T@=1y{)~<$C2F=_^;1y};##^}AGXsmj!L#kB&;|~6 z`_7;Z9K7(_JHV0szuJj5aPY*b6KDemYv)y_?cx&I8j-Foc5v=tnD6oaAYy0y_#&sA9 z4ya!QkGX4sdL=z?*Sx^V)s~GSkr<$8QbBZtY>G1k#KWY$`9Na8iY*E8FlldY>y2A{ z(44$+j~M4WIti&4Sb&-rxONgFR9D5J`?Lfpn+)@5fLu_$1a08p>btK-oAk)TU->rL zAS+r_Gk5JYNH=SjqfL5b-|pAY22QJ(=|P*OcC?4;q6TOe55p zkZWZ_{UX(?(aZo0EK&p3L@gjwoSWO5#T&P^y&1Z31z(s*_|&p^;F%SJ!R*_AV1U0d zH+z8#$N)(of_Uj$ZoC7O9zB#G+&CbDp!CGCQPXM{SRmjoD>lnqz}3~&CtmN6-@9ty z5n_ShY9}UV-DO{DM%0d2AecwE^%HkWKMJnc&VBuQco<@VpmcO{$G%*abubaoRdB6k z!aDkITyO4&6%SlTeWX`FplceT3tLSit^!@-D_t9;MYY@7-U`SRXPtmrv3X0?UUv1> z& zXNT$1@%Sl2rIU*`S~@7&V(E6P{rF*7EK6TpBiu(e>cAqZKpYd8rBE+V*V5J9MJU>6 z>39g0mD2HP!iGvG7tOzzQUk2DYu>og(%DOfsl8;?PPb=aYInKXJ!JkTvOodKgNzhS zbF0N5cFh)JjBD4@v~qhrmeyhkIJNM(36S}pQP2(G_gGWA{yDPF8{Po_V_+yIM0;tb z1)-bmwJua=<>waPkO1SDQN}&6sP>lTmSR;q-RX0w)UY|V8|xhr3p{@O_{o!`x$R^V zAR}RFwB0DkBL;_=Hv(3AS>Pg693DKtMg3oKNxi$w^owVMb|? zrl)|BFc&iKVzR^Gu2?IeyRH!%ZrKF7-IA+7w_9RdgmDpvD;<<>w9-N87AxJfDNeC; zi4on9$K^VgkZPU;=cQ23hn1Yt9>B{V^k90AL~@gF9hyu*Xmk zaI<5M5l~tLl+jdL0@A^Zjg0{-Aif|B2*9biO7^NvXW-gpAh;4NIR%#4z>8~$ zG|0(>jGA;uy9uS^ah--r2Spcj>G(=thDyhycRxNM%e|bDmtI{ZpBoU9J%k`Wm&1|} zf%S6&a-(2R48AM#Sb7F)@PKGkDCJx-ffSYmC}P)$fTjtLDBgwy_gz2 zd)#bl@a%CTm+n#He|+)X-JS{1VyT){MF!qXtqrp*EqGdP%`ir{biAP$LeN@f9Kiqb z3!H=*g62Yq1q6#Z1?fI+3@*U{)s%Jlg{Q2{l5LFY3ff>%FNa~V^qy!BMPV#1bDXkf z8_RF$79TfIdSj%~?$UM9JI^FQb{Mh=&~75)DjK9YJhioS@<72TEH3`dNSFv<0(AIY z#=t-w4)jTkfI0wI(O-)M)K#S$eQD>He52A0Soj2|Rr4fVPDJusI)G7oOnyr*CK|*@ z7(=0hu33T+(BdfFC;`oH>2wJwE8R5x#Y^{8OaM;@*xuewzE)XT+291s5fO*IzyF)Q3mTc*{_}{UyvFss(LBRqGT>9C?;CTN) zzw{$mQv`f$h-jpD0pYrp6_vx1l+;y~Rn3hprCBT4J->h_2y4yKa7!;Nl+?}A z1)ENwA9Uxyu+m*ydMFgiOLrI+323A_!j%jd0WA?CQc@^o8f3Ux%8ispOYezBDVA;&MoS0T zYHclDZ#c-{Box2Jy}*WG)DUH{Kd?A0$>GvVivH#oB}G83T7MZBN}hx<8sr!aGCV@I zW_owHbh_g%L!~QFK(Yx?AcC0*sGZ}mA2z?9P>YGz3yc0bjLOOqvi(>jp!uDCz`#&~ zB+TVB$RY}w1{to|g7Sk~WdG9AeUV5+m`?|()rsT9W_)sNK)uz z>GE#2;S4k+E|?OUw+{Fd%;)u&P^^wKMlhSwNrM7^zR ztKRGL2Ic1)D&6n%qu$oB(ox4JUE0)W=|&qK;ylv4%b;|MRiC@b^dyW%e$2mTjuk!& z^rDFxYgv?mUNnI}lLn;?8ah8{@O+$rIysa9{Ld)H3|76-mI;6eC^Nda1V*2F2Kz9O zuw;H78y|O4S}+8)8wqRa^rp5>HFQ4C$qY(6z^a}=8CliiRS#MA@bIwE*9vf+g&5^P zfEpVuoe@xq1k~eklz>`XqtE5QEugldu*Mz?g$tMW#Fi=JKoQp+BVmQhztxnlVdchI zpwU{vy}(X#AcqO4-L{YdBcKLXC9$}QiBSSt+&0J>Ym|2D1p4PXu(>25Hm`X3-Psunm%dp+s1SQ53f+$S54P!x@FcMo_mg z;1V=Lmfd^ry*W-W3ONC=0^-fF@g`Z|ceqxj!2o6{iPXz-pmcP0NI%B{ z9t8t}B0=f60OZm&1t6EMdHbMryKmp3@-=V2w+rT%0g>upU7Gqjm?NO8Tb5wFFRl>| z1{gocSwJow7l2$krxbjxzjV#p2c>J?K0eyX_%nH|efH?NNBJdw`wq7~cKe2IpFMgm zzkLrNe9{!qnqFWs|HFZ+!&U?gy6W)OU~B+UYit04KZ<1FkD{w!G*c1Ifi!NPdA%*b z=%eS=og#|CI_g4oObMoe58lXVk*}<+ZFx!!m$G^--hQ;#SSrNvw52Q)corVIkDk$d zsP4c0+$!~8-W!4cotgezcIOTF)#f`sB@>8~nQdSD=qeeG0{=sJ>Cs32^s8T@P5jEJ5w65-khmX~?oi(4DDm45uvi&8QQ}LpxZD!M zZoi~%-(e#(_1n)c6A21LQEGtAC@nkAwj&kTt(NHb1Y&lg?z^)BKPy8gD;&=|jUq@bz0z z&CjU*>E6CaFqru#p+KC6O^>S8|7?6qOT8adw0K1I0tV8bP+U|pT+JZc1G9O z#wiG07}Y;`0`snaw`Hio`v3+8Nsr|&$8=A$$I$s6i~^D|V6Zn#88pn`%P7-DW2Dj0 z`H^~ieK>aO-*6XiP5+wB&!Yb6Hb2hCDq5 zc!4#!;D;aVC!Aon5y);MoKXf==telBFsgqB1_t}OKuy?f1}k(kq}?3IsQ%r?L8c8L`fKdTZ4+J_zivq9)Ko%er3W2u} zS%6?oEeI@ic>|~mhrwHjZUZpd0{i1}ayJA7Kp#;z#2NrDfVN>z^a39VKgFq}<30bv zo1z~k)c81o=OuepJ%BZH0+M}MZ4DkDO`aH2V*pc@tC~Re?S4(|tMN&S;&nXx2mbog zvhf(pF9VuBefj(Qxq^b-Y1N9}CgHXg$WZ7A1w)2jgFVrxp+-0~Jj5CyASkxJ29wDo z-Pd5GzTVJ$B%=ZpTnhvO;2cz^0MHSv=moZdci;KBlP#OT|8xRzL1E+cO$01B2A21{ zvIWP$><&gTItE}Uf)2Q_1h(4|=>`sJv;#JDzR}f;49g!19b~`4IEdT2pIqPBR$tVb>alt z+CDsJU(3!r0b&fyZZIR9#ZeH0?fon504c^n-Nr!~2`&y2Oo|9bEHIPFluv+g+W8mW zM7{gJ^8Wjs)W!Rc>?81xs@hs{qg5hefx^ZJkllW8#=saD+}8aRJqIl~5^R)%79R;N zbQZ43K@|n?S(hUm&Mi&_7MeTU_B-kgrSpTBTIqCg_donShb^~KQBi*A%@@#4?TiKF zpRd_=6M75O)YPO#QiRh+MpBjX<#%gpg7On&0*sE0f@mqA0Z;{+0#ss)|GHcNJXp-- z0(i96`YUt+f;B<90)Wyr1;AedOaPY)fF4P(=pqxq3e3029D@0T>t< z3J&CfF;6cN1BE5PfWh;b07w8&cmgU0D(zf87hm&fHNI&Yc6fma6C|BgR9juUg(0|0 zaCdhp?(R^$xYHCZE(LFIu3uyPbUh$;BQc$wg$WwO)JX+|WqIrXu36 z?7V%&uC_fVc0&AtYCNxy$;htts3yWl_H+;ugcL&RGfnqXFz+O8Wm=4PnVO&KWJ zKth7+`M2f8S>>l#@2$D|IRLge&|+_|4{ID2Ds4^hw|Z)DS~BHA+6{mq{^yzkY>;p& zqYAsz-Y#5;e^lG{yvll)AN$&v4d|1H%)1;`XbxW?W`n)hTVvSlK^jz(@?41kgBvu# zMjUjek@awY-}SeT*@c$_U71C=JW&m@t2ip4_yX=XzUy-oonn>ph>|vp`_|Vr?)CW0ZhgGZ#qlN=+X84h10a23Q9)JD12uB7qo1j&kl`ZjEuo13>(Y$e zVQ?EV8r2w_WJ@JAX1~+RLMqNmqhZvSCtpff0`~tYXGa~iFE=P%fpvOXt z-#32*(coP{EKcOIYY|`L*bb)Csc8cNPJ#@cU{)%T6m;I-7`N6ZLVDyQj|E|q%nkP4 z`d;X^mQBq;nzo>YloKPzt6PPfqa{9GL3g?RecWPehbwPk5*Vp*3*l_{r$%*c{r&4x zVaVOK0-zE!@GA!O^ER4zlpnG;<~ITpIhX+ylA(zlkpNps%>Y|RoM_l8VMHReu~5hA zyv+*XPr+w7pZ-+?RRSW#U7g+o;cOfC@+E(%ttgvFaAB##n<3MoH%A0S;caE5E>9r5 zJRoN>A^b+WJ{duu{jr8S>gy1czpUbHI<#GJF9Wqfwf`wECr%KCxxqc0AdL>XfSHm? zoXs(8uW8Cac0IoYD&s8Pn>+rhej3RXO=ex9<^Xc|PS(6<5tDVr*4Xi}V@fntcRez_ ziJ3IpXXY$m*S{~&t09MS%B+ZBaa@SAI2{g(xhBiY3Y5_)&Z3TQLzQ`SFG_Tuuma!@ z-mTSrQGY$l=RJnEX+dowrzz8^DViElARC+h!vDI4QpJy@9`FxtDQHdtUG4oR7uOBf zVo}y+whfr9hY7uv)b;vq2m1wR4hBibcf3V(tcRpiI&-MGY81f6I4$O{K5)b9Afx^g z#45Fo(DKx$#!E{R&-Vn!1fIez`9&jq&)h`rGnc^TY-3uhrw-%y6G;vlI2d?HrM#vL zh9Ra3jP~V7vfG;Jd-faYQ;Y|%@{r6s#^3KK5gv~lS%%?1Ui(}ew%NtzHmK?!H=Nsg zc!Dcp$AHkIpE;ma4)Yz%2wo-rzP>2?yG2GS5Q38tlg^atDZ@QQ4L-U&Jvef^xbSKG=8-8` zn46}!on1CkjBipPse6(pZBF&7;6!Szq?)(yJk|5z zG*E7<>6W_ttg;smEV}PW1s9GseRma9*cj{%O}yKy3;USPg@^YdU)e9jrJW2#t8Y(N z<6Pomo(H_c;R>c4u6R(=YRb9GU98kfNJW9?FhmFV=4$_v`jv}Gi7Au`b z+!J))khZ@^{A(ZC|Pf{F0DWGa1C@W+?D4rKcQEHgO}VDYYoP+jMGUMWRz;U8l|ZiW+q zef2^~g4&?m7ra#r(fI~q&&{D-7>6jUJdUQy@80GcP-liy8GnQFDLgsct~J7iS2*EQ zMh`XA18dvc3EzSc;QaS$*vsC&FZ|%ctm(WSIr-fKa#lGVFC^ zug^jlkuTxsL>Y+T7Q@4-QLk#R>z?T3OBq*|22%PN2YLdlE;=+R=U?A0#2Vr*S^GaG zRoVh@pU6MhPWBEB{$?WzA|2=0h5}?jmP0!ud8_*zv@6gmWXeWJ8Nz8D*i{(t(M;NxitG^@geG5We&Vy<>wT^t-!@Gk zzO1Ljp7VQ}u!0)-T5pRb4)2>x>IBP>-%GyvzW`OJs9qKR$|RBhX9BLQstlI3-+|Uv zC-_EjHVMo~$*zb9Vd|Y!OJMmJBs4=ioCt0gy>uo0g;mdsPSqvN=;tVWz*BLr=H0v2 z|H3q_`}6esVawo$;6hllr^njoAl?X98`K!PkbmZ=#9j)f!&>rJcJHi6Yfvu;Ix9E2 z3`vFTS6?2G&2WPShea4)LXGFR4x7hjAViW#7wVg@P#$atH>_*mmz75%uhQ7v8*Lz{Mk?l9zuLlH* zNNtQskY-F<{M+B+J$6wx2P34#ueK6SS6S40kQxD5xX`^t#n^Q2LysHbi}}omY8rFG zHryvPMik-ak(2H9Gmk$m$9g(zW4Sa~K&tqkiO!Fs11OBFuvdpGlYpa{=J z$-0^I8F)QXpS?0qr}3p5n&;H&;qSXi-w%dYcW!XwW_shq-nYb_>ph3!uM|wd?hEQF z2MPFO%AqLuS`5;f3_(f(f<|aFx?D%TRXml52uzYLbR_0te|34x#T^-vMKnBkfk&wMf5 zu$B2s(w~lmsT}Z$aw%m$uMH_4HIojI0aXxWJNT44YBMrZV+|+@nMl|Npa{F%W(*YyqKXyWsQ)zPW7_qqPd&@NB&#NjCd3dj(f=JcUe+N>)c;-k zaN@X2*CFXW0GNU09=KJ8FcHws7D2+Ct>{#N)C#|=1Yr%^wB4>mUfTgs7@yEz+rNwT z1y#?oL`>Rnr@?#Aant^Vi;ymWvRd-|C{)ex1*l4IY*CDkjE>VofN@1piN-C;a2 z5O&x63iwDY_!`lG|2gJE<>8lxaO`6)g)MuG0g9T4J^0Ay$)#4c9m8=Gy4bPDj$>KxwDE zT1W9PsTS#f_>FzZTs%HR@Ul|X0UBnqAy^X*U01U8RO=JD+9inaFcL*q(L}zDm4_N=p*ZK=lMjWXC4VhsFD8~GZ0`{+$4b|N&!}=T}kZy@Q=ngJWtj=qQ0xx*H&yr#c zvk#lHT^+J~kq9pdl#jVQ>&wrT;pt!!`^!*4>MXAXP$4v|%(c z*&}`dPGje>09%Ik8FMazpOhX*LS22Z@{k!8S|8%?yipW8zW2wNQcCS?TPcu^UWd8? zh|qDA!l&RaI5*>hSB1=wii?A20y0w3lV82as6_d_$|}{wmw``sO^$B9h*AX);ep;G z0zj84+ToJnEsQI=qoZ85%(rrr8`9z`h*9P8x+@k=NCaqBrlw6n1*o8RxkxVCfezHA ze8wOc^`w4TWZOjim7xjp&;T`99H;vr_rg@c$BmO+9Z;>jNM*IWejX3rkRco=2M5RV zKI)xW6LlOz>`{KkLP&N3I2XmUE7k+L5-qE=JS>*n_6168g?whDn#AuwrkUJf)194< zaUII$)ayLReTOH6Fc?e;H%Y989UlflA3A(Uz8Nf!9m zcW!6>ny=gX)0TN)yk#jHkJMWWsY(_@=5*yiK2J!pZb(UIvdIz4s%NZ2m&x%ZWE?7m z1H)XvJn}QVA*vyKJb0-LwT(d5s!tpI@J~E?H(sJqK`*uc?2txSV3G&HQQBJ=cW zkx|NvVwUubZY-dpq@-hH$-10TYFsqOU6_byhho|P>86D%01UFA&Q}uk32P6;{E+e& z^WH~u+CXM(;)x~Pe}|~rkY5Zg@&p*wUDysHStoDCK8hIKUPaUXN*YSZ=!qA%`zacO z=8wplJmf^17iv$N9zDvgz-lS$MlQ zu30M7A%r_qm0fvhOZqryYDArAfdxD|}Xz$0y&Pa)}e~4~M-CnkxcEjIcZFQc%cgCakKAp!^El1TkOhg;hDxu-q5CKj|tN+Bo!vrDO z-n+m>{w#(NMxsk{bnZM#5b-HYAs`o$-atc=WEogimN4;q0JHf5+HwFjcd43`e_XC; zy1iH8LNT)jeU?0m-#t7*Cd#$=$_o$~v3^HMBQ zg4Fc-(Dv7W8z8jGssQLvm%r-VRo^{3w?ZGc)cqo} z=h-(C8CxX)iuqG5raSD-dVVYVsz+nSrkVu&8;|SND=pRA@#$BOvvryaAQd42LDlU8 z9J2Krlk@XFysSeMb=oPMs#<9M_QW+Yr`1sy2bMa$G>`&)2vAJEXVXwEaS2eG+hB;= zKg!Kod|LPSimys!VZ73HHWu%F?2THojB&r{rn^C(G3lnD4aFzi8K3{Ykj|q+DryL? z-6P5q9H!3$nSTpiNekzU5q@K4W`cuO%~?Vu!>5fHMY#Olk3|v6AXT%A?HqXRtgW0a zAoC)^Jd+YwDOs&h76Dc&esWb$g%&f{g6t^@7`9LtE}U;}!IJs!@9%+?vHvx`jab5u zA&qYd{E>>mp5s}qkh^0@*E?0q>32S(l)vyMW<=Tb7nh<5baoC2MSGMKXZAYEri&kH zALE(shVp)X6ShUWM`stn){Xuz`w`K*(&Aaw75P0i(|9WGZioizEujjjMk|mGg8ASY z&MY1KWr*&^+0V6MdO!zW+ffwqMS8C_xY|4j3s-Wz9^>v~qvW?{08%^{>f{ECkl++* zk0fL`v^cA9Xtl0{iNqoOR#WOE8gA*-C;;4lD=jW%Y%1im`%j|@cQjL%6>o^jS~Zi} zu9+9E&d$_W*(BrBbw$N44-bT$oYwHQ)6>NDG8@dO7>lxB(Xl8>Zx3*|0cgUSQBm|I zd;DQM6~6wRi>>P8@gbUkSkPPPZW#TJP6PbsxbD&!QrqHt?0uy67!e??rK3aCT}x`x zA)++9^(=oCtd}dxg1Cy^{yt$~tKFY*QWN-KfK^n6tYTXcC?V#g#1T{(;Ej(z{aKup zRn)&ky1mLud)s9@%WQD*#Z^VyR@S0T6E_@9lf3UlH^gzU6i4s^FZp%=^j8h^v<`u? zLB*mkxndi418R#s-8)hK%!%N{DctqW5Bp~F^LKFIALlokM7{4{9jrGIW_ryfGlL@n zBrzV&l{$y1bKlOlx*Bcb9_RLg+;zYolq_8=LaZ0vx*rBty9Mli$oSCBb&m(D^VEMf z7-Mbyjhf#--9C7Hyw=@P^kWHI;o3Fel88O)i#&jaZ$56TXb;NXb2XJzx1y&ecnXS%LLR(al6)mA5=)`&%l$u5^D_3|p%)>m9T3lF!%q?85(L#J(femKhdOlZWJG?4>m>az5eM7g zspD912rv+KE-LmOU&L7y+y1f_-w&h~M>Px`GL?MhBngeec^F3v%iwzK+MM{FPQbe| z;b{t|0NE?D5__;*+veMqdY^USAUmi6Qq7hR=xC>54t6jpFNT*e5mCoL zC`8Pm%jYiBIVA)TO|oK4Yz&w7N)dAJOq}sHdL|~&#qRM(<)IIPI`hZZ`rb6Teo?^hB7#u=7U8Dad zft(tq;6X2pr~L@exVh9)>loXLfmotBt&nM={3As7c6>c)M`g#x&U3I@Yp!6o_sgeb zHsI2%(Z?&)Dl&sAEDxHHU46y@A2etj|8CSUs=Yat?Mp(c>xb+rN6;URXFLmz#YwJB zsniF(S}b6f9MEe=q)Ik2DB`#{0PZgwUj7l>rx;!T2V%2QKL`C39kMAWuaFYf`_zxy zJ;_tzmW>{%GiG0^JfWS}%tbmJgmqJj!C<$1SJSZWQd`gv`etG(QT-sGG{TotLmnDs z5~V8qPEQAGVOFesKZE@`!pK`th#GBGZ_QS15!XF1Vfd(NfG0M8$I!AbE4|@ym%+wQ z#3UQ3H9`I}H0;pxqYR}kTVk~dcFmN^&wo*qIhg)XEt?Ho(R34oC6`sI;?d6?-gz-Sb(20YC4Iyos%X&JZ}UtK8>%y=rX%|Qr{%~(M4_a-pYdy=7Ulj$CZx)_S<=Ae=pYb<;%g9i z^?`+mN5=jkG7M*<71s8$Q<$u`suRKU%GE&{9b9E2uJ5Q1-Do&8b)RKhyL8xmF9xdL9B%eB;q?7p}rbPtXeFh7=daXJJ*@dKu7P#nm+ z$S_95F(6}s;ki#E3rB&r#1I^8QB!a+WH2o_whDV-l9J#cTe~eTBVDg&Sx|`g( z6_KlMQX0Q!tejoO5A~hCtXGzh;NSi2Vr_)C_wh1I(jn>HtvhC{Bw+!L+>5mGBHEdz zCMpn3s`1A}RRBbxshWL0Fna4|7-hbNmt`RO0S?KKjPLH#p#$XjT**4ocrm%%i_@=_ zr&nj`bGoyT33*F;{~cJbRTsXQ>Giez-D2-OwBmV&E>c>(RR@jS=$5ma&hF=tTDP#e z&MIWW_O$=-hvFCaw=Y;am53To&bxk2+&MI$x?P}&@z?pW3(n7y0p%8>f0iT2Q(476esA4O4*h6K zE!6?hiNneO^QI#L!s5u6gb(FE3;c+Fi2mj0)j!;B=uJO(SMXOyK2C*lMKhx`h#JzQ z5n3=PIrEDw5;Q}m=xe`8QOB8y#qCk)l1hghH(*YU&K>MbAoUO%{ZP;0$DM|m<79Q~ zxMIb3s>$48BJ338mXH|wNlEe5Dl9;ry2JSIdCjAcNu9%oqm0yCa-*@5%BPM@t! zYL%(#{nf^5h0FVx@pkU(;Ii@pdf{r&Axj#DYyMUyx2Ia&7D0ScK;>BtJ;YO%pUtFc_M7`N;jzg$ zB?jRiM>YiI09+Bb$WgUy5it3X?$=2tft%6{`fmCq>hoIt9*2*xi?juJ2~-u>CToU_ zf2x7JxA+py5d?JG*qnxeVCexgWKK$1kY(^QVt)8AN56DBfikMiP+mO#rS8X}?*C@> zeY*a4{ynmf`6Uopu}u<+iz1#zcW|wa+2)E%uO}>tL^OxU2)(hW?`wFKakCCWY|6T* z{?L;iCX@Ip##{ChSCEAhAM$d~=Qia<^!Y*c26fLbJjt+F^D6;GvEm^MI<$aZMAkp>c^QBU<96dP+m6Jk+?53>JK-opkye;O zjhXW@AV%h~7YDkvm4_v_cj7n3_C=~HO(TreyXx;#^qbiC%f{WZ)k#3P*oYU_!-)}tk2ScU1hDr}77oxKFDPx|`{7-Gz)ESsKeJFn>{U*_mUzGJl-uV`dO zm8V1<-Ws%1B0BxhfjFGNkm+FtbN-lM0sGK~K7*K&rJ92EFuBB`+|+*IemhAINDKwR z)A#>!gflaDM&e-=sR>b{>l1)EKsjJw!?eL!-n^%ECNB-RvSks)`nJYpU-9Me_~C`` zY^Cf9UIQan_EqhSIosHD6Of?FC*4%o119*79WFmD8ervfIQU4g(NC2f_$d)Ptbt`M zAG5ZGF8 z8DI;xs-kv&4PsZ7!!a|gP{LD*^wHULCqw*_w(F;&2p$vOJq;V zriEFi!zqPXeEGg6;_J~vfSR)VPXN){4&{B@i6dt)FCch61&MTD|m z#w4q$s`c(H$V8-Kw1(S7_a&$a5lU9Rvm>rI!awEhV_ zEsAYuzp7jg!)DwTAHnU<57UQ56dXli=i4~?*zfpNJwkGa^|FK+YTk5msuIAwq!0VI ztcvuTo!%EV{=l-=gG|1Td*}T+Pf#}u>YnmqGsp9^xhaFr%5r7<72H@`>Ki1u9PB7F z^Uev|#$aYS!HQj(s7W+5?2w3vk@Ow>BJ;co3i)=B4um=M{~Z20BLXQRc)M;-mV>j~ z4~?k4Kjhm^%XWSrWCiuoVvyrvopASRwUn}O=sOHwyXY2Vzacyz3oTI+P@_pK(EZot zL*AG~zaic;Mt5Rg5?1EH$b~W99;pKfqX>8@g0uvLb>?98!naid?hCmZ#5eqJ+E2|n zzOi=>+ppyff7nURq3)6f3B7%TWWdorxFo!-<7DOba7E{EvL0;SV5EQV9NtIO23I}O zPO!{Whj8wgpV>KLm#jil5u0W%7->%c_#5A+vK@S&1uUYgAl@X~#?d`>S%r-wZ*y>h z3zc>1pRLK3Muiqe8@(CBy~pwC?~6z0GrXd!DR>8FKD@8QK3GIN&v8+B{5`K&_1_<& z{C)I<+ja|XPBDL;!kvrOWnP};Wcv)gX|L;s44O$zC}0fAlVc(lAVTup)wP5vsnesg zBtJV)8r56)p({cEucn~!eoj*E_a$SO>NJ*-!e)LCFQ^V%FioVnDSOlx0fazdVtkkp zXN$@44&i+7N6F!x%$_#e^=#{B`A#N-kfvlDvL`0 z^YJM*VAsOgz4HpX&b3`aafFj*QP;?8v{AdU%9_fE1=+Ar5U1eGU0o46N&oe?JbpU) z_*foLHRWn3>^x)`&9<3FQO-e>N5SwvliPh4sPt?-7(rOVoZfnxmD+vx%4DC86*#zx z`TEpC8yY!6`t1Fy_3g(hsxSN7D`AfNRe{})smV$zS#Z!K93qlTSYn1)#-k& zA@eDQi$IN+VzwE(fiHp|=2dS4VFSI{MD(frzf-dP;J|470v=z(<7C_r4~}& z^+l-kH6zd2l~u%=_I)g_7=xf1SLJW(JkRzIaJ-#thMP{`xOo-8aT52)O>>&y-}?z~u5~JaJ?ese5lRcY>$$UJC5!l#Y2j zImN~NJqwFlp`o0$5-e#r8G&LO50zv1jMe}7^S?VA=Etr|E6TpT!acg0t|#`^&YGPE z7NCdE%k%NK#wF9Z(&z;)=ne#g%|}E9Q8&V0y6LJmG}`I8m?Uwdmr5?EJ~WUnPQYdl z+nhI3wAbZ$70ynd5TGBNN(Te8Hxv!z4$;$)H$F{Bd3M`?Edv60aq#DHTUT8UQ>-S? z&+QDleqgQHHe)j%nL-$p;W(YOQUIhl?0bQn$foq>xRZd(3Y%%O;ClcCvDml90gbL|FX zjTXSJu_;gwLi^0+X7PVN?OON&)X{d90LLRXU%=jG zH!aiHzx)>AX-m{ATB}176N($J4E^m`(oy6UkH76-!&BDKk7$_EfW)69)Je&wU+rz< zt1U>+&afUbr;ljfT2h<*Zjv7oyMk-qFgLf4G<`y{4SKGicETVWP2%ktwbNYEb%fWq z!vJ-{GQ4fzM@oNG=@s7^c?v1zgnyCUUSI}9KU-ZWk%Pk)!VwUho;y}7f zLo~-{jJ+EO-d03z@y6*Ci0?Bpu`glvC>Xc%g}(^JG|C@FA%MV}hH=z*>rQ&EZ zko#$!Whu2PMuH`kwPKJ$Aa|EqWBOKEysGmfiY=45l`Q+*uLfU3suO_<^g2U#duu6R z!sVS})6?*Bv)2D%{Pvz{MYjH%VYq+UMBJZ!uQ5pK7F?y3WP&=`Com{nO=F+ZGd39Dsz0ZbcFYhov0Qw8`bA;c0BVfr_dX(4k!d zJLSO3enIu$M|7QsUlF_^{ zaX{noII-8^r26h^(me`}8Z0vv8R+Zl^DGUwqQ?!#Q!4d!_n{8M7Fu|O7KBAiMpPOS>7B~F-{VR&57nAp1t<0$&=5h=l77#d4#gD!KNPq65eeCw{TwK$O_QAB?V zs9X)IxliY7t$4GnQ~7k)+{4xhaI0XPbdgeN7!M@B@bTDk*ngc7T;c>{(gAk!c6m6D zskf7?BhvzwEz%AShkuXtbM|L~U6yAg_pIhhL#aGAQQs6GeO*FLTst=m9zc49StR)>Sj>@Ig6US>ub zTSnv)y(X62TIB4r62tFM{6(x@U#@;B^t8$Uc>7yf%1O3wUpMHy(&cSF>z^>*_flO` zk>YncWRY$_{W!=jL^%(o8a})odEjh!cg5u;td(pS9r1ZvCh)onxy@rFm_{6Rlm-%F z$rJ+hGLTdh)Ezb0F05{7BO+u2l?wEEtJ*&&z&59!+wy&@38hi6;WB0PnyP?oe*j8S zrY%i4bm{(u7cgchn8uTOjxpl!v^*}vet%fk=xVic&ZG%E3&sh#4R)9KknW>`@}kOn z$|pwaJS}jkVN$PV`{SE_AYhetz} z^pHKxc(RuQaRJV}N}~M=A6DI^e9l!w02N!??swc2yVIY2c;BYqk2$C+89ePVdS6Ip z({NoFgGdqAdjH}CO}=Q!%Knj(RgvE%;{r)yXGP-)vX=D9UPeYyVo5ZqIlWU=q+VH0 zufpGaSn+SNfQ6{Sxi5#_?w&; zm}X>QHF0N}SA{E5X!#nz^pk=M`8CITi~+YcP>Dvua>$uMhc@^?(6?LV&lh$T=s!Zc|}cuB6ASl|IoXsYy?E=B15&hc)j`>!|8a z-=R4F3!kDdG)xEk7u{^<#W#_nkH`LcRX3IFc>#JZM7~PScw@!m(DHv&N$~X~S`q`Mj z9V%i}j&+zMb0*0mYk8b*XUDZ17wkKtWIGSp#=Fyfz z?s`k{sWO3`>$miGN0;!zok8QyK~2MA(ldrbjP+Ep)AK*vBY)F+<*yh_a-bsdv?VBc zDB3levYapR&maMu!Q8T*N61jSV*Cep)f$h z$)fPTsg_<6jh-e7HX^q|8jUix%g^nBfbWc&eU{`~Gd~_ru_AR6-BRt~y|`T-e1^MoH5cwhzKJ=?|AwW_^$wYd`AHDWl;(eg+MHX~ zzC0MQ8aYZ_x;WK);hQHrWf(xHD!^=JB?EVeuBD^J<)T`iPfzswRQT3u$d{FR#1xQk z%FyeM+41v#Lp?t_BsT?~9ZDdgifDd>3tO(7?rzWf={4hn?+f}p6$7bOl5Pg|QmAbc z<_+6OOBm>6PG{svZZvF`t~rj1MZl4Fm^k|GuKo)fZ_*+ao{r$6`A=B4Gl%xJp)n_V<(dsnmGIYcKv#Y?#%xif|Wv;~BRu*#gGl;EN7s!dT{GabM!Mg0--I2KS*V+r5E58faVYBZaM!W)eo44z8v zYYcf%sw=@Gan!f*WW1VKFjFOCX4Fqq5lZsp5a7QOEIT_&7O|*CTL=xcl;deM@)q8_ z4q&l_RRi*JAzP^Qt-gUkdDT0Rg(N(S4I z0QmDC7UT?X4YHB3KWmDf6$MQv`o42>kq?y+_$FvSLgT#P#IdjtOE| zdU*H6j>$NeFMNC^Bl3^R@G^J%%4Ju~NwE!y*O{BtpK8-fmmvH!Fy8H@Sg0hzyABsv z6mL=z2_nDnbOgPQlOoQS>A-jKS*Z+@K%}lB7L*R`lfSVeh=^0drE%~u*&ldtnQ(*o zlBLbXJ#Q+%SU^!%p?qC2l?{~}Yt08qdF%5AZ9^cb$ve)lJJs<9c2ed1!3pWUuEaS! zHsupg56I^x5`O`NfQnkYQHzgvh5h2jj2Jd(Dm@yG@3t$`8pv`N+BB*xK*et}8T~lK z^~;z%gtvO|#%nl4;QitppX_DC=w)$w!*vTS_@t`q%6p)7DyB$zOzp=F#8A=)s*;Hb z5(mCr=wro{PZ#>{kFxFIA^dG zA1snyJg3tca$?+*L3}M6 z5=BUEhYqzEqWYF-Un3K+M}An+N`)8x$v@yGwWTz5ird18pbVzb4{N}e<`{L5&e~91 zJ0&mQUYLL?L4JjjmC6`y(ZRVnjSqQ6>&>Oba{0Po7cRy80VQsANFI`4!hfOoCxG)8 z2K<6xN}%`#$2&bn7Yjj=Jt<#yD?)+(6fdVqW@scPM2KqI96YENFNeR9s;&6q1LJ;F ziNVLh0xp}i=~C$gl3*EO2AVJbfJ;5o_z(`hAOAb8V~8l=;tiQg8p`6JqZu#!@;{Br zYO&U$WO3ki86FUFSbP33t`*Lhr)yUK+8R=m(&1!OBr0jd`k$_ag6Rwof23qIJ@N}g z__cpsXOa!dkFPA2?&^aq6EEkFMIZa^^^+czf}Fn*0hZy$N;)c`c?WRr^v5U10`Tw% z35sa=O|PCmvG^*Bi`zrWhdGeGGGyGjEdZAhjGrj`t{J&-luA|MLe8t$d*+m` z=3E845sldEP|U2TOtA{{rfR&S%jq&IRib>jIQZiv`8+sl2HRq9c)IJVjzp_Jqm7ao zJOJ=lrNz&RW{(+q^e_XPwe`xd;_55P%Kq|~zCgC-u4fy^wm{tQ^XKc}bUxir6h{S4E zRtASZLf2d;SfD3o9ETvHIIJaS`zu|UZhW9l@H0*cM4VgoS4+<=xGA`nx0VrAU1>F? z)}BWNx^yNBj%S7R4DUgWL{qQKemTzlw<>c~u8v;*x6x%s@16dwYp(J%I`+;7Ystaq zJ3fEKyu8u&hy$n3 zgNg0dl#o=8d%xiBl>fE=;)vwAA<|9Tm?JrBxlG)=+z1$c&OpUbEX2{Mln@k13!kFZ8c1evDb zHUDAovMDG0PN;2nLw-Ii&h6oH0p?C!|E=_$uru>7V5XgtN#pZ}-dWdoIe5MHe+7_0 z+^JpjM?MzC5B!&)AIaV1pU45*{&?WW+?)kzE+#^;74x={aRzkWcRBd<4*{gUkE~z| z6q3CQ>CAv$U=#*~i|ZO>_z!#&Sg@W&oJ#++$H=U7ctpFW7jy)%=%`5~BCOw|<&Kw! zsj--yv3#2eA zgCrYKptS{3SYY0O&sL5XE-I?~?LS)2Wk#P8y>?`n`zrZ-d3MD*B+8mSWr^@O!3FOt z_@Ku!ZZvog&aax{rhvtW-<3;&)B*LobbVbG`#P1AkGrZOFBA|7W*?g4Mlk-0c{@MK zvW4fjb^kN~*000&U_RmM(wMwPEpERZAUx0AsPG*+{Q%Eq<6%6bM0)UK+%%S!G zl>|BmE{3#OLwZCW9Ee_IAmEdxzJ7WV`2aoXCyNN|OSiBEy(RcpL`1Kniwk-&#fbr) z&zQ0^fefFJ3d`|cf;lzhAS-m)pc!Bn|=vk*Kfc!!h zplmSv=4QXM{$Xvq-ZuUFnSzL+rDapLgJ7DNYKqXxDlJ)7gSmqr^XXEpui{~PrwLvC zCLA*x<;QCu3WBqCZLdSM40B$DUi_cho~g#)h4e$zvWI{rwqRNx4wnXj9RaOp!Ax9Fnu z{&y6%bn0{e+dvjx*LHtd(|d;Z#Qyhto8AW>f84KB+jB;8Rz~01$-NC1e)1wLHT}Zw zJr?j*HWGwmrtpHiy+tWVYonFJB9PO1Agszr_b?vjSMlZ5P4{To@r68NV-)2WPAB8B(8;i2eAyg7vf&>vMh> z4un3OGVJSM3#AIMK)Qsiv>aO=6K-Z?RRUjlGT=z_z@seu)7QtK)#UBct7@O2+grKy;#btmdQDKxSgcpp$%_D4SE~x(%Igvzh zEtPzk&%)wlNcG#O&_(X%4f3YmuuWaG+;itmq?&wpgx+7Iq|ko zJdFJ-gJDmp= z%;F=slG0M)+V`)q%~hSdKzGEwtTm&6xS189`sR*~42U(GB@K3sv4ZlH{XW@J$dL;a zy&xO;$hI^Bxj-9;pl~(R=(io@$hDRV17w7n9#g{x@{_yA%S9y}NQ4`_8Jm{yoSQANrKZJAhUX$)tf$w ztpOkN)nYMrLznsyl!CksuVH9kcU6soZQt5Q8t&xWRfU2PVhnVqAzkI(UalsLaQ23^xVt+urcl(^~|ozJq-Ta zDTuwt+C=XU#I?jPzm(m^vRhqG_v=y;C-ZhgWpc#a&YqmNxk$H)}H;TUE|=AGh2eWuypgensk3EoP0s+5Vn6i8cg8+olBaf?uaZ;WU)E~%00$pBHxIBIR zeStuL)l?zYR9(0(QXe79Qv@|NGCBgvD!!UBKmj*ido6zO-6sx;`w3Gk9NXjtwmuPX zT5C4>@R?2pd(Y}iS4ltGI*>9K3!+$G0v66+I6>SGOAjuYwaiug74SccNQ|pyQOX1| z+*t8jEDX((WMFU}(cUQNu3DN~@b0tFQB_&xs#R!hLS3j1ymQ9WX)nl1lNv6^lAE|0 zh=c*wH8L^+SXW^+;~WLl^a4NrZGLgBne!Lwzxw%CEq3Q^YfeoQ`JW;H{{vXC#rAcI z39%rnw{H`6UVrK_j1=y$Ui8R8*+;1f(1q}N=ma6HTDI2Bx2ZWIXJBB&f)R^CF?jINx=;^o8$%xFqSgBiC#gPtMsIAXm5G3m(ovkZd`G2N69S2R&FdjlxF}W;yVlW#H636n9R@TC&K-!*XwDO59$Ht&pw66~i zRN{%araWNj@mQ=cH7qmnHnhSn2falVR)ZwDH5X%;H+LZJWg_EI)6$ zuyffep7HEbE9i-{tM0h)m3MizI;i9;9-lmTK~J_(KJ?`KYwulYR35tF!1{Uf_(XR4 z)bO~J|3&KS!I=R+4B+pH!IwfN1IIA8*FwPf_R$5~eq!#5?u+j7LzxF-0Y={N)23#=0r<+%(j zl}&|YLvDNNqwFmN%B6R~Gln#`@!pGUDp#|Ps>`z(*mu1*5!Z4>v*Kwl?hzIMEIYZ7 zpV3%dDI+!GZcVMyGpHOlR~h1mKw{p<@f644X0TqMGSBP{pOd^E(kx#GH#~;YX6G zL2z(NW2?CT+^>F3OHSN7f9=+6Li0zT=Yx2DxBbyiY*-*^VP%@vyzjq0t9bk$zkR*h zPezASr+XfL?qlgkzr^tx;dqO644aCV#vHHW#5=_NgdLIpF)%PNFsLEFR!K%l9fNk_ zTq|B+!bHF=7i~2s@%z7M({tLsS9dL1<*tc2v9QtGB7YOXtD}$1hEQm1hEQm1hER(Xgr)>hf;I3sH zLkU1L^o*N`H3LV0VSrOI*=hz+GB8*HGb}OCrKH7SCC!^7csP}6ZiM+n`X{2MM>tE2 zJDD0re;2J@SzSpvqn_I)0~{OHTUr*H!tw$AfI^mIH>E%*gb)Y`)J;N2nmC7(II-g^vUS?BWJ}r^ z&1f|9-kZ^AG&35>@Av7mM|1x5-pst;`=7ul4rrSQ@$zyxiiV=X;(X}U2gn0o+HSJ} zqqy7SDJw0-orUE|@6DWm0!q#Wqf3+yX4lK_G0XiY;;{%{f9ei_qmWi$it~vfC<`{v zRgSfYcLYqG_9cbhCXget8(hcosWa$kg&*4ykidc1eUhUJwQZWSx@YJja?|;Jhmh;n z-?JIH-Z{cG7DTn54yU8eMhC1g1p57#UZoZmK{amzL0?S2rM4CUc&b%K!XXL+14Ayr zqxk6PC@_lq$Na!3PK@gSCAAh=VO9Z7p&`YRV`xa0=Upy&Fw{XxT0qI^U`Ead%trGq zTh_x|I9U}SlK)9V+8qJ&a|&$5#mG&m#DWk_4Xl|ur@6U@Znyd=GzWVA?PGjrSnQcN zT21aYE??f4=liGhKEAv-0N3os?kM2f7OJer_@lF@sLROUVX1CC0s zskN0^cJ|OMV!y)1cM{kUaA~4w--@zwfvo}osuZ5R?w72NM01FyI?zDrm{OD?|6>5F z0AVXIqs?LvoIr?rtjg#(8`TBIbhY~Cct@Oo4+sYJMs)B{*QHO}bn_%MI3J8g`nI%N z>E7?ZJiy-J%q2R#V$Z=ZkY{LHvzqgr#Q<$qvc-Z>_pQ3?E|PS5ycGY76Rf;EN(;!S z0P}Kl6Ou643M>XSbyL###>ca83=9km87Z=Ikc%P!-|c|*eit<#qB?Qh4>3F6zXfaJ@33`TI%8;E7~9u;@hqIE3<($ln&7S zVITedCRN2Ix+zevqiTH=A0>-qaKeG7=*D84b<5gW>;ub=_LBc@pADUo)XbeY&@t-h zrB`fTDX+|I{ueQg`&mZY`kGprzvgoYJsb-Xzx|8_G4kg&#b!j^T^I4gkAZ=Kfq^L? z0#>V4xL#J%(xyMX4A$zkPqiKU;Hdb^U+V4ARiQVH>>DKhHV+^Y(didY*F__)Ly@pt z4I$u~Mq&0ej?%UGPTsn=ot+)<%7R;~Od0d@nN3Ecut=~xfk0rK>!l-2 zo)s%E@Ci8H=Ef21LU0Bqfi@YDK3MfnCZ(!r9Hap0$S8zs>1& z=N1(3ZFSX>o_T+XApDcAJfO2!NKO-45a*9el`Q)~>WxacqV77`vT6o$&uP<|2B1V} zQQAoU89UbtZ~5dklIMj{x<$P~=RK%f`pAu9goJy|R#a#)3cbSg2HLFs(Ubdoy2*Ik zO+VWP>@(-8Mbtu9cNe6x)6JMkRu(z(3g|ZQ>Q8B&hX}pU>#kh5j`&}*q)b4z-oEbm zms(v=M~^YYzoLN(fddKVCv@6gtOCTqNC`fl7Z{>ys%wBDN-n@d=0qq244JSzNTN1A zk)SX=L3)58)93Rg9Kz*-*XIR>a53^I2Ql(sWTzHT7*lHJcYM@Q9HV!hOT5nSp)jwa z4vtjiY`v&&u9K}6MT(AqHODKvq2zk|UU_fvCbSKdFQ8Qyi)p=Z7_^~}4)qEM@bM#i z*Zm@KEC?U!ez}(YbqQ;E|I_Wj&O3gzom$xNFW&?IOr+Pj%+r?J0QSH>y+p|`$dYXLb5ypV_Bl=_HX#s|Z0E5mOG3@szQ zluHccqFicH91ILh0TTllY#qb2?aV$E)EoQyNE%dj$pN2)QssACkP-^X7E{& z-aV`>gw1zN>a1}Cv*fny!(%o zPuf*0*DxzvbYK)Jkh_EpzVsy&qDf46(^gY?OuT-CPVsmLCtqMq8`UPHJ7!;nZgiMn zQQhnvcKzlEvurSd(*gT5nslzYZ<~O$XD^&%f1Tbko&ELX+jP?Jyb^?3Zr!%~*`XIZ&sfyxczJFO#@smd-*VL#<usW-%F-=KrzK)L&+xQ3Nc*C~o<#6}@N z0Ra^7d#_?(Xbo8FhM`%?g>Px?Qb1wk>!%Tf54A;apUUgKXZ##tNEKrRHnw+>O!4kk zz8f;(8Dww->>EUGy6K*;2p@Z%>+{EF2xc4s54^F9S$W6f_rgq)S$gZ=cg54PL{Zlq zZ=#hC-5?;cFs)nVe`mT!^L0r3ZJ|n7OK$0E?!G~-Am?(LCQ@L)SVu3wDj@mCL z8VPe?XWY&>YuOU`SbHOF7I${K1snmZ=OZFm_rCZ7vkW`N<(0%Otq(u(E8(B;vn>w_ zY^^LI6WmbYz=$3x*PT1gN!$&5y>9a+_SXfsUKLv;7e0Dw2YgOz5!rlhujk0Vcg3(Y zHaxy~3P2+&78uWtSY4TVwQSVFUHQWjXmXmhxNzPDBU5;E1A>I3Ecs8yf8)MaXxFzdc9Jr~u^{!WWHw`KtF>NN3v-lH z$KMeUm5Lf4|>>+{&1S%No(F$T-|8aPp1+cE9k|PkeBSX#7Jv40Oqemk*E47@5^&1Sy0mmju|Yc9?Qy3X;|WR<+I!1pGbybP(tjRaX#yKi%=!jCqX- zkL^1#04y`%r~rf#(NTz*cHwk%I#xzHQi)aBgs@1mW(cbvx<^1}PHH*^wNlzzjCLw( z5N-1{vY&Rrb+`G)#^Ch=8DXdl=M?!P@P{{_5`Vc&j0M3X6UO93Fc<_>I77ojfC{Io zvIe+;NZBt6}S;1qQ9 z$Nj;kW zZn1J*NT~oNgHi!r>ZLg@pOIYvC);@|I|mXudA|I^|B@i{SZG8a(`Oq@@n@c0k)?U& zY$}Zl!~c>6LU04N)$vD3t&)ibn9W%EHNaoWSCEgK}H)olZA4WOPd}bXf0sAp5v%KYfTeC^>iXq@jZXv%VdKdbFch4 zS=Iun1=R6JA&7(+{ugI^{18L+7TwHaNzJn`26|P6#0`K zEwfs)@-=6X6vaGwh5?cK5)6e{GIp0t2&{FJrHQaE*~F7uIG)O6bU1SMR9B4k#P<|R zGEALnVf5cZL+9yTYwp|Dc;hr48ECgZAmK0)Oxj@q0Lh1SIxx;aI0Z2UCJ`}#*^5@E zrEe0(f(Qdn6POh4{LgKgy=#qTGTA|BoQ%39_@C_O?|0CIxOPhYBzX}ejC#Yskie3~ z=u2=DO=e#=><*a5CL&m}iODU@#~6gu3sVqCGE4zTHGKN@^UN}z7I4AVTc0i^eRwDVZqK<$X$2T7Tj`*ELh64w@H2D(%GJs?C*Y9?F z+zG`P3ygp_e_lTOtJCQUjDZ2~aI)xOrxPMrVEnJk1@1F40bU)>YmlE`0F5Z1k8BZ? zh91sFR8|UBKz2gDwjL&0Y2Fa=bsaOydkYX%I>JV@Q40vR_3Y@x6Ug(WFi-pWC7>PtCLP=Me!No!_*f8kz z;YcJae_DQiK0Go_W_W$RBCS^aQUSgZA20(XCb~!#m~n6nIRMHP2nK-?0Oh6S!1ND( z_TeVdAWSRn{M&>(2^W)K@b-`1=a9BzBqv?@^PAcHZ`pU?{K?>&7ysc2W;tOj2pd3l zKmu3P)^aJMY&9nY906e<9RbrD3)26WvQ!R#{=V(DI_a?>!r{Pt8d)Z81AqiaK!RE7 z6)C~0^ZWgid0fnnF#uzd1M{1N{3as+_Zm#xGjwhv7b`V2)HSfb3zw0gP-a8;$e;ZZ zteIQ$b&?{SILyi0_vT}u*%zoSL15MQ!8LvDgJK$Gxbw7tNl}3R$!i4;PmEjhQgup5 z(Gf5yXe1V-$ZQwCGvx@FEI#<(m&EVfGJTd@uOU39Vq_MwM#YuI{6%ydHN6HC zce!8^=6rLmjhjJ{>0oFI75t)HgdzrJdq}+h7+o|%Kn3`hPxffDJ0oFDyh>7x1yK!D z-aex)u95rmzSrex0aivBrt~lag;andVKIZXdSFMuY_%t1U?>OWMoJALLlu*1@|(0n z`|4y9vUFH=IqgFCr=4WjZ|#g~f^x&V-LP#@Y;lpmHTFME(~%Reo?%vA>g@)UPn)0k zF12v?V?vPx0yadEMP|jr*;V{$*JtcC6G7VJ5}6J#JP|Ja2CX7JfBv*Lman*Z=4@ck zGp9}nr=j`$ziFSsu2WwCo5rJ$&y3YVEGD5h=f+1j2sQGh)iSz zvRK6>#_*b{xKY>Mf4`XBr18IGk(Wzm@AL%`iovA9fvIGEjdgRWBEmLZVeD53<+rOSC6h#Y ze4bH1=VIqRK3F@2u7wy5hv|h#7&zQ)2A?1}8e|k&6@i|~N^TuO0&Xb6pAmxrQgdU5 ztjs80JDOOeaw#IgYsAQ-L6MMIcC{vwT=Hm8B&3kqzqhSctK03?_`OY#34&n&66WRR zaR$4>Vjv|}hThwDn+<+XYE2}!$5U2Xnii1~M=gY%krY*clL6t0F!3>(jm#&Nvke@L zl-Y8Lk2ZfSQ|nI}j=d^p-W)?-gdl$u|0~H&b++yGc?t4IeDE!;9N;k$0|P)t1W`GL zhO{pv!Ai9+B&>wQ%Q`h0Wl^4${S)#0+ctz zm;|c=}gRB(Lm1 zyg`y9Ai??gHswq)i@Y?lURlCe5L&icG!;`i79@>0*}faOUT-AHpNto3TeD7hha2y> zRl;dK9J{rVCK!${N zB4a@$BdKs;VGuu-`Xr0$T3)BX#wCjv-nTdzXD8 znG#-LB%q1sN7xE1%@NRZ@w5i1-oViaTa!NFPY+{PCmeYBZGTPt9Ud8E6LB^LOcrB2 zx2wZBOprftDrT#oo}UXnv|hGj_W^JpJIyA8bd9E*WPq7!p3T zc{yM(P+?&auqGG`0&9FDV3}i^4UFY-xm+;6fklEbsYIfr!Xjajut<|cB%{e#1Ra?5 zB5^37-T@{(QNaqVbUGM-^NHM(uN>{@g)!uMd1FD!*OIBEhYw1LOI11+M4@oty!_nM z`5%n``PH+t*IuV7ieFGrfE6=rDf5gM^zZ6kd*5LJd*yNA+D~A6W3}~|X;fp(o zzxRCqL8TkPRt9S6O-5DSJqvLG4~)ztH)%)OnM6jA8%4P21Qa7fnXrV!YN=e z5efmr3MEnk3aEq?SkZJaCl2fmcob~e{qKIbZ0i~oy6_Z_3b1j7vgF{m5B!>1n6>I! z)m_$bKt+bOHg@3OPm@}&^lFeoVY{9Td;t{8Suoaj<+bwf|H7(0$h&eCP z3cT7tR$?%3y*XJa`5XbMQnN??$O$7gD5=?8x@F}6w*U);DOFXX=9sb$1DD4R(febQS1JTdYy? zcNO2UB9pdU6XSoJcKi5Xt)v)UHkuk{HQhIhy@pW%_6_!>_eEcrZtaW8ib)J?Dbpa| zN;?$gTUkbKWO?XdkyL)@lztBg@rCl{R5MJLor=3RE|}SX=<+$q{kBj*jc(v`1muGN z|06gber+iVSt@xDmK$+u`<4-&p-)f!rF&}jh-?PK6RgW#ACJ+m#9t0c4nYZjg;W2>7!MH-cd$)99U1+V*}?9*f< zpAa}_65|NyAEPssG}KK4_8Gi92%p^L0pIdw3zU6bpZF+SF&M-IXN@T>DQ#?M1nR+!JvMN#SDq0mmm^SD&<6y+)&a)lChzriKJ-X!6MmhcH)l8*4rsa42Musj4ZyL zRPMX9-%hYpF1O2Kv8Z-C1;>MMBPjPOFcMS_N(3XV?~)@>d!O7N>JJg0;Z7GH|0A&c zwZ9Q_Hjz1m`O=7_9Tnwe)CcB&8H$9CfLQ>7{89XGYIU8wXGXr5vKa6i76Su6EYW$U zs-+``hSOYu4Nh?saCnwK-^Ft`wK1T>fo4DBO6)Jk?x zYKmZDK`pS_K)zq{C15m;dFc=6j{4djA#6@9cGY$qjWqW$rv~T}w?;!VqD|sM6 zFh7BDz{G?jlY@_$ zj4*H+H#TOiS}gvY!sL$+W;5ye(Y)$v{DQ{7z`!&@E>u-kscET@ah?M=l%n$-xS^Ee z%4uT_A{_zM0b6~TI{#A$^2UOw84er?CVtBZGrweU-CwPjeC+v)oyze)l~XROtQ}Eq zXvDzCbQ%F8yVa#Ka%H%o6y?g3N;fGp1uVz}D=>0@3UhB-`903P*alHCUthqWZ z;mf`4*W0fk7LK2YXFUGe?t4=_ZU1F-SWKn08nJUUCPPe;omHFeh||#F3j%w7_~Onb zx2~7W|9bj3C!gCgpYA?;iE@1rF-LS57#RzdHA%RkvYspBhLYS+5+)U4f`uM-wwn8Nw_9CiJ-64X;!aQoK;wpNxWNO!V*&r`q}wiTG1 z86>jF9(m$(IT+J(_4Qbp+{^vrA|LW33u$B1HzL57k}PL^5&^+0#!<5 z9?jnB%DwI}(t`1M|_;V^28(Qn<3wN_^T{tUArZ6&RvOA)Egt@oYq` zz}@YKiI42EMIzXx4+A45IEEZDGMfx-1TUn9AefC@CpVzX(-{GR*(l23l{-1yeVV$@ zMNtzm>0tU#oULCnRb|=-WN8)yeey*h`BZ>NYv8$$4@#hY2~~h{^OX?sp~#=eLq2={ z&9prEPL>}YLH>x3$4#1KG0zU0iA%WN{2!7JK*UY}37 z?o)!nOE&})oKM<;k{tnW`_|U@)dw|H2!Wt|nf_9n^79pHUQRAYK(X(p(QGT5A)|Rk zO$RBA%z|nTNvUcwGS)*eQ;@k<*GzE-RM{5Hbf4)CYsbVC;fNP^6 zT@NeE!D=XOD6;@86}+abRFt({j8w2llBE*UP?DvBMUqh}WNABTQlW3Ea0c8|GD?*x zHSW literal 0 HcmV?d00001 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..fd944c9 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include "core", "desktop"