From bbeca8e4fe97920ec0f0956e6824eb9fefeba34e Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 3 Nov 2020 04:12:13 -0500 Subject: [PATCH 01/24] i'll debug tomorrow --- source/MainMenuState.hx | 4 ++++ source/TitleState.hx | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index 19ddb46bb..4fd7decdd 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -15,7 +15,11 @@ class MainMenuState extends MusicBeatState var menuItems:FlxTypedGroup; + #if !switch var optionShit:Array = ['story mode', 'freeplay', 'donate']; + #else + var optionShit:Array = ['story mode', 'freeplay']; + #end var magenta:FlxSprite; var camFollow:FlxObject; diff --git a/source/TitleState.hx b/source/TitleState.hx index 172e8fed4..b6be87a6e 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -59,14 +59,11 @@ class TitleState extends MusicBeatState #if (!switch && !debug && NG_LOGIN) - var ng:NGio = new NGio(APIStuff.API, APIStuff.EncKey); #end #if SKIP_TO_PLAYSTATE - FlxG.switchState(new StoryMenuState()); - #else startIntro(); #end @@ -200,11 +197,15 @@ class TitleState extends MusicBeatState { if (gamepad.justPressed.START) pressedEnter = true; + + #if switch + if (gamepad.justPressed.B) + pressedEnter = true; + #end } if (pressedEnter && !transitioning && skippedIntro) { - #if !switch NGio.unlockMedal(60960); #end From 71f5d24586e8fccb03082df90824865acda9b172 Mon Sep 17 00:00:00 2001 From: Brandon Date: Thu, 5 Nov 2020 01:51:31 -0500 Subject: [PATCH 02/24] tracing the sound.time issue --- source/PlayState.hx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/PlayState.hx b/source/PlayState.hx index 0163efc84..06b41a2dd 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -583,7 +583,10 @@ class PlayState extends MusicBeatState { super.update(elapsed); - // trace("SONG POS: " + Conductor.songPosition); + trace("FlxG.elapsed: " + FlxG.elapsed); + trace("FlxG.sound.music.time: " + FlxG.sound.music.time); + trace("FlxG.sound.music.playing: " + FlxG.sound.music.playing); + //trace("SONG POS: " + Conductor.songPosition); // FlxG.sound.music.pitch = 2; if (FlxG.keys.justPressed.ENTER && startedCountdown) @@ -634,7 +637,8 @@ class PlayState extends MusicBeatState } else { - Conductor.songPosition = FlxG.sound.music.time; + //Conductor.songPosition = FlxG.sound.music.time; + Conductor.songPosition += FlxG.elapsed * 1000; if (!paused) { From de56282aec871cc9d35916b80f38432b243a250f Mon Sep 17 00:00:00 2001 From: Brandon Date: Thu, 5 Nov 2020 05:08:40 -0500 Subject: [PATCH 03/24] added debugs and cheats and we usin fmod --- Preloader.hx | 70 ++++++++++++++++++++++++++++++++++++++++++++ Project.xml | 5 ++-- source/Controls.hx | 18 +++++++++++- source/PlayState.hx | 24 ++++++++++++--- source/TitleState.hx | 4 +++ 5 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 Preloader.hx diff --git a/Preloader.hx b/Preloader.hx new file mode 100644 index 000000000..37b63aadf --- /dev/null +++ b/Preloader.hx @@ -0,0 +1,70 @@ +package ; + +import flixel.system.FlxBasePreloader; +import openfl.display.Sprite; +import flash.text.Font; +import flash.text.TextField; +import flash.text.TextFormat; +import flash.display.Bitmap; +import flash.display.BitmapData; +import flash.display.BlendMode; +import flash.display.Sprite; +import flash.Lib; +import flixel.FlxG; + +@:bitmap("assets/images/preloaderArt.png") class LogoImage extends BitmapData { } + +class Preloader extends FlxBasePreloader +{ + #if !js + public function new(MinDisplayTime:Float=5, ?AllowedURLs:Array) + { + super(MinDisplayTime, AllowedURLs); + } + + var logo:Sprite; + + override function create():Void + { + this._width = Lib.current.stage.stageWidth; + this._height = Lib.current.stage.stageHeight; + + var ratio:Float = this._width / 800; //This allows us to scale assets depending on the size of the screen. + + logo = new Sprite(); + logo.addChild(new Bitmap(new LogoImage(0,0))); //Sets the graphic of the sprite to a Bitmap object, which uses our embedded BitmapData class. + logo.scaleX = logo.scaleY = ratio; + logo.x = ((this._width) / 2) - ((logo.width) / 2); + logo.y = (this._height / 2) - ((logo.height) / 2); + addChild(logo); //Adds the graphic to the NMEPreloader's buffer. + + super.create(); + } + + override function update(Percent:Float):Void + { + if (Percent < 0.1) + { + logo.alpha = 0; + } + else if (Percent < 0.25) + { + logo.alpha = 0; + } + else if (Percent < 0.5) + { + logo.alpha = 1; + } + else if ((Percent > 0.75) && (Percent < 0.9)) + { + logo.alpha = 0; + } + else if (Percent > 0.9) + { + logo.alpha = 1; + } + + super.update(Percent); + } + #end +} \ No newline at end of file diff --git a/Project.xml b/Project.xml index d7c38fa32..a947bbb18 100644 --- a/Project.xml +++ b/Project.xml @@ -2,11 +2,12 @@ - + - + + diff --git a/source/Controls.hx b/source/Controls.hx index b251ac61d..dc11a616a 100644 --- a/source/Controls.hx +++ b/source/Controls.hx @@ -30,6 +30,7 @@ enum abstract Action(String) to String from String var BACK = "back"; var PAUSE = "pause"; var RESET = "reset"; + var CHEAT = "cheat"; } #else @:enum @@ -51,6 +52,7 @@ abstract Action(String) to String from String var BACK = "back"; var PAUSE = "pause"; var RESET = "reset"; + var CHEAT = "cheat"; } #end @@ -75,6 +77,7 @@ enum Control ACCEPT; BACK; PAUSE; + CHEAT; } enum KeyboardScheme @@ -107,6 +110,7 @@ class Controls extends FlxActionSet var _back = new FlxActionDigital(Action.BACK); var _pause = new FlxActionDigital(Action.PAUSE); var _reset = new FlxActionDigital(Action.RESET); + var _cheat = new FlxActionDigital(Action.CHEAT); #if (haxe >= "4.0.0") var byName:Map = []; @@ -197,6 +201,11 @@ class Controls extends FlxActionSet inline function get_RESET() return _reset.check(); + public var CHEAT(get, never):Bool; + + inline function get_CHEAT() + return _cheat.check(); + #if (haxe >= "4.0.0") public function new(name, scheme = None) { @@ -218,6 +227,7 @@ class Controls extends FlxActionSet add(_back); add(_pause); add(_reset); + add(_cheat); for (action in digitalActions) byName[action.name] = action; @@ -245,6 +255,7 @@ class Controls extends FlxActionSet add(_back); add(_pause); add(_reset); + add(_cheat); for (action in digitalActions) byName[action.name] = action; @@ -298,6 +309,7 @@ class Controls extends FlxActionSet case BACK: _back; case PAUSE: _pause; case RESET: _reset; + case CHEAT: _cheat; } } @@ -341,6 +353,8 @@ class Controls extends FlxActionSet func(_pause, JUST_PRESSED); case RESET: func(_reset, JUST_PRESSED); + case CHEAT: + func(_cheat, JUST_PRESSED); } } @@ -628,7 +642,9 @@ class Controls extends FlxActionSet Control.LEFT => [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT], Control.RIGHT => [DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT], Control.PAUSE => [START], - Control.RESET => [Y] + //Swap Y and X for switch + Control.RESET => [Y], + Control.CHEAT => [X] ]); #end } diff --git a/source/PlayState.hx b/source/PlayState.hx index 06b41a2dd..e65bfa35a 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -583,9 +583,13 @@ class PlayState extends MusicBeatState { super.update(elapsed); - trace("FlxG.elapsed: " + FlxG.elapsed); + #if lime + trace("IT'S LIME"); + #end + + //trace("FlxG.elapsed: " + FlxG.elapsed); trace("FlxG.sound.music.time: " + FlxG.sound.music.time); - trace("FlxG.sound.music.playing: " + FlxG.sound.music.playing); + //trace("FlxG.sound.music.playing: " + FlxG.sound.music.playing); //trace("SONG POS: " + Conductor.songPosition); // FlxG.sound.music.pitch = 2; @@ -727,6 +731,18 @@ class PlayState extends MusicBeatState } // better streaming of shit + //RESET = Quick Game Over Screen + if (controls.RESET){ + health = 0; + trace("RESET = True"); + } + + //CHEAT = brandon's a pussy + if (controls.CHEAT){ + health += 1; + trace("User is cheating!"); + } + if (health <= 0) { boyfriend.stunned = true; @@ -1288,9 +1304,9 @@ class PlayState extends MusicBeatState if (vocals.time > Conductor.songPosition + Conductor.stepCrochet || vocals.time < Conductor.songPosition - Conductor.stepCrochet) { - vocals.pause(); + //vocals.pause(); vocals.time = Conductor.songPosition; - vocals.play(); + //vocals.play(); } } diff --git a/source/TitleState.hx b/source/TitleState.hx index b6be87a6e..699de8a54 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -76,6 +76,10 @@ class TitleState extends MusicBeatState function startIntro() { + #if switch + initialized = true; + #end + if (!initialized) { var diamond:FlxGraphic = FlxGraphic.fromClass(GraphicTransTileDiamond); From 7dc874d622236591234de906b9134152a22a02bd Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 6 Nov 2020 21:17:27 -0500 Subject: [PATCH 04/24] caught up to cam --- CHANGELOG.md | 41 ++++++++++++---- Project.xml | 12 +++-- source/ChartingState.hx | 9 ++++ source/FreeplayState.hx | 97 +++++++++++++++++++++++++++++++++++-- source/Highscore.hx | 85 ++++++++++++++++++++++++++++++++ source/MainMenuState.hx | 13 ++++- source/MenuItem.hx | 13 ++--- source/MusicBeatSubstate.hx | 1 + source/NGio.hx | 9 ++++ source/OptionsMenu.hx | 29 +++++++++++ source/OptionsSubState.hx | 11 +++++ source/PlayState.hx | 35 ++++++------- source/StoryMenuState.hx | 42 ++++++++++------ source/TitleState.hx | 38 +++++++++------ 14 files changed, 360 insertions(+), 75 deletions(-) create mode 100644 source/Highscore.hx create mode 100644 source/OptionsMenu.hx create mode 100644 source/OptionsSubState.hx diff --git a/CHANGELOG.md b/CHANGELOG.md index 875bc460f..94888a81d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,37 @@ # Changelog All notable changes will be documented in this file. -## [1.1.0] -### Added -- 32bit support -- Controller (dancepads) support -- Pause screen -- Main Menu overhaul -- Cool intro screen thing -- Uh lots of bullshit -- Remind me to actually add this later lmaooo +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.0.0] - 2020-10-05 +## [0.2.1.2] - 2020-11-06 +### Fixed +- Story mode scores not properly resetting, leading to VERY inflated highscores on the leaderboards. This also requires me to clear the scores that are on the leaderboard right now, sorry! +- Difficulty on storymode and in freeplay scores + +## [0.2.1.1] - 2020-11-06 +### Fixed +- Week 2 not unlocking properly + +## [0.2.1] - 2020-11-06 +### Added +- Scores to the freeplay menu +- A few new intro boot messages. +- Lightning effect in Spooky stages +- Campaign scores, can now compete on scoreboards for campaign! +- Can now change difficulties in Freeplay mode + +### Changed +- Balanced out Normal mode for the harder songs(Dadbattle and Spookeez, not South yet). Should be much easier all around. +- Put tutorial in it's own 'week', so that if you want to play week 1, you don't have to play the tutorial. + +### Fixed +- One of the charting bits on South and Spookeez during the intro. + +## [0.2.0] - 2020-11-01 +### Added +- Uhh Newgrounds release lolol I always lose track of shit. + +## [0.1.0] - 2020-10-05 ### Added - Uh, everything. This the game's initial gamejam release. We put it out \ No newline at end of file diff --git a/Project.xml b/Project.xml index a947bbb18..5da40d92f 100644 --- a/Project.xml +++ b/Project.xml @@ -2,7 +2,7 @@ - + @@ -45,8 +45,9 @@ - + + @@ -58,6 +59,9 @@ + + + @@ -100,7 +104,5 @@ - - - + diff --git a/source/ChartingState.hx b/source/ChartingState.hx index 070d55597..deeb34924 100644 --- a/source/ChartingState.hx +++ b/source/ChartingState.hx @@ -28,7 +28,9 @@ import openfl.events.Event; import openfl.events.IOErrorEvent; import openfl.events.IOErrorEvent; import openfl.events.IOErrorEvent; +import openfl.media.Sound; import openfl.net.FileReference; +import openfl.utils.ByteArray; using StringTools; @@ -762,6 +764,13 @@ class ChartingState extends MusicBeatState FlxG.resetState(); } + var mp3File:Sound; + var waveForm:FlxSprite; + + function drawWave():Void + { + } + private function saveLevel() { var json = { diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 193744704..ad336ce8a 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -1,10 +1,15 @@ package; +import flash.text.TextField; import flixel.FlxG; import flixel.FlxSprite; import flixel.addons.display.FlxGridOverlay; import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.math.FlxMath; import flixel.text.FlxText; +import flixel.util.FlxColor; +import htmlparser.HtmlDocument; +import lime.utils.Assets; class FreeplayState extends MusicBeatState { @@ -12,13 +17,22 @@ class FreeplayState extends MusicBeatState var selector:FlxText; var curSelected:Int = 0; + var curDifficulty:Int = 1; + + var scoreText:FlxText; + var diffText:FlxText; + var lerpScore:Int = 0; + var intendedScore:Int = 0; private var grpSongs:FlxTypedGroup; override function create() { - if (!FlxG.sound.music.playing) - FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + if (FlxG.sound.music != null) + { + if (!FlxG.sound.music.playing) + FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + } var isDebug:Bool = false; @@ -53,7 +67,23 @@ class FreeplayState extends MusicBeatState // songText.screenCenter(X); } + scoreText = new FlxText(FlxG.width * 0.7, 5, 0, "", 32); + // scoreText.autoSize = false; + scoreText.setFormat("assets/fonts/vcr.ttf", 32, FlxColor.WHITE, RIGHT); + // scoreText.alignment = RIGHT; + + var scoreBG:FlxSprite = new FlxSprite(scoreText.x - 6, 0).makeGraphic(Std.int(FlxG.width * 0.35), 66, 0xFF000000); + scoreBG.alpha = 0.6; + add(scoreBG); + + diffText = new FlxText(scoreText.x, scoreText.y + 36, 0, "", 24); + diffText.font = scoreText.font; + add(diffText); + + add(scoreText); + changeSelection(); + changeDiff(); // FlxG.sound.playMusic('assets/music/title' + TitleState.soundExt, 0); // FlxG.sound.music.fadeIn(2, 0, 0.8); @@ -65,12 +95,33 @@ class FreeplayState extends MusicBeatState var swag:Alphabet = new Alphabet(1, 0, "swag"); + // JUST DOIN THIS SHIT FOR TESTING!!! + /* + var md:String = Markdown.markdownToHtml(Assets.getText('CHANGELOG.md')); + + var texFel:TextField = new TextField(); + texFel.width = FlxG.width; + texFel.height = FlxG.height; + // texFel. + texFel.htmlText = md; + + FlxG.stage.addChild(texFel); + + // scoreText.textField.htmlText = md; + + trace(md); + */ + super.create(); } override function update(elapsed:Float) { super.update(elapsed); + + lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.4)); + scoreText.text = "PERSONAL BEST:" + lerpScore; + var upP = controls.UP_P; var downP = controls.DOWN_P; var accepted = controls.ACCEPT; @@ -84,6 +135,11 @@ class FreeplayState extends MusicBeatState changeSelection(1); } + if (controls.LEFT_P) + changeDiff(-1); + if (controls.RIGHT_P) + changeDiff(1); + if (controls.BACK) { FlxG.switchState(new MainMenuState()); @@ -91,15 +147,45 @@ class FreeplayState extends MusicBeatState if (accepted) { - PlayState.SONG = Song.loadFromJson(songs[curSelected].toLowerCase(), songs[curSelected].toLowerCase()); + var poop:String = Highscore.formatSong(songs[curSelected].toLowerCase(), curDifficulty); + + trace(poop); + + PlayState.SONG = Song.loadFromJson(poop, songs[curSelected].toLowerCase()); PlayState.isStoryMode = false; + PlayState.storyDifficulty = curDifficulty; FlxG.switchState(new PlayState()); - FlxG.sound.music.stop(); + if (FlxG.sound.music != null) + FlxG.sound.music.stop(); + } + } + + function changeDiff(change:Int = 0) + { + curDifficulty += change; + + if (curDifficulty < 0) + curDifficulty = 2; + if (curDifficulty > 2) + curDifficulty = 0; + + intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); + + switch (curDifficulty) + { + case 0: + diffText.text = "EASY"; + case 1: + diffText.text = 'NORMAL'; + case 2: + diffText.text = "HARD"; } } function changeSelection(change:Int = 0) { + NGio.logEvent('Fresh'); + curSelected += change; if (curSelected < 0) @@ -109,6 +195,9 @@ class FreeplayState extends MusicBeatState // selector.y = (70 * curSelected) + 30; + intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); + // lerpScore = 0; + var bullShit:Int = 0; for (item in grpSongs.members) diff --git a/source/Highscore.hx b/source/Highscore.hx new file mode 100644 index 000000000..b57870518 --- /dev/null +++ b/source/Highscore.hx @@ -0,0 +1,85 @@ +package; + +import flixel.FlxG; + +class Highscore +{ + public static var songScores:Map = new Map(); + + public static function saveScore(song:String, score:Int = 0, ?diff:Int = 0):Void + { + var daSong:String = formatSong(song, diff); + + NGio.postScore(score, song); + + if (songScores.exists(daSong)) + { + if (songScores.get(daSong) < score) + setScore(daSong, score); + } + else + setScore(daSong, score); + } + + public static function saveWeekScore(week:Int = 1, score:Int = 0, ?diff:Int = 0):Void + { + NGio.postScore(score, "Week " + week); + + var daWeek:String = formatSong('week' + week, diff); + + if (songScores.exists(daWeek)) + { + if (songScores.get(daWeek) < score) + setScore(daWeek, score); + } + else + setScore(daWeek, score); + } + + /** + * YOU SHOULD FORMAT SONG WITH formatSong() BEFORE TOSSING IN SONG VARIABLE + */ + static function setScore(song:String, score:Int):Void + { + // Reminder that I don't need to format this song, it should come formatted! + songScores.set(song, score); + FlxG.save.data.songScores = songScores; + FlxG.save.flush(); + } + + public static function formatSong(song:String, diff:Int):String + { + var daSong:String = song; + + if (diff == 0) + daSong += '-easy'; + else if (diff == 2) + daSong += '-hard'; + + return daSong; + } + + public static function getScore(song:String, diff:Int):Int + { + if (!songScores.exists(formatSong(song, diff))) + setScore(formatSong(song, diff), 0); + + return songScores.get(formatSong(song, diff)); + } + + public static function getWeekScore(week:Int, diff:Int):Int + { + if (!songScores.exists(formatSong('week' + week, diff))) + setScore(formatSong('week' + week, diff), 0); + + return songScores.get(formatSong('week' + week, diff)); + } + + public static function load():Void + { + if (FlxG.save.data.songScores != null) + { + songScores = FlxG.save.data.songScores; + } + } +} diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index 4fd7decdd..6f2ff630d 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -6,8 +6,11 @@ import flixel.FlxSprite; import flixel.effects.FlxFlicker; import flixel.graphics.frames.FlxAtlasFrames; import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.text.FlxText; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; +import flixel.util.FlxColor; +import lime.app.Application; class MainMenuState extends MusicBeatState { @@ -40,7 +43,7 @@ class MainMenuState extends MusicBeatState camFollow = new FlxObject(0, 0, 1, 1); add(camFollow); - magenta = new FlxSprite(-80).loadGraphic(AssetPaths.menuBGMagenta__png); + magenta = new FlxSprite(-80).loadGraphic(AssetPaths.menuDesat__png); magenta.scrollFactor.x = 0; magenta.scrollFactor.y = 0.18; magenta.setGraphicSize(Std.int(magenta.width * 1.1)); @@ -48,6 +51,7 @@ class MainMenuState extends MusicBeatState magenta.screenCenter(); magenta.visible = false; magenta.antialiasing = true; + magenta.color = 0xFFfd719b; add(magenta); // magenta.scrollFactor.set(); @@ -72,6 +76,11 @@ class MainMenuState extends MusicBeatState FlxG.camera.follow(camFollow, null, 0.06); + var versionShit:FlxText = new FlxText(5, FlxG.height - 18, 0, "v" + Application.current.meta.get('version')); + versionShit.scrollFactor.set(); + versionShit.setFormat("VCR OSD Mono", 16, FlxColor.WHITE, LEFT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK); + add(versionShit); + changeItem(); super.create(); @@ -137,6 +146,8 @@ class MainMenuState extends MusicBeatState FlxG.switchState(new StoryMenuState()); case 'freeplay': FlxG.switchState(new FreeplayState()); + case 'options': + FlxG.switchState(new OptionsMenu()); } }); } diff --git a/source/MenuItem.hx b/source/MenuItem.hx index 5aae4ee28..e5bf62c9e 100644 --- a/source/MenuItem.hx +++ b/source/MenuItem.hx @@ -10,7 +10,7 @@ class MenuItem extends FlxSpriteGroup public var targetY:Float = 0; public var week:FlxSprite; - public function new(x:Float, y:Float, weekNum:Int = 0, unlocked:Bool = false) + public function new(x:Float, y:Float, weekNum:Int = 0) { super(x, y); @@ -18,18 +18,15 @@ class MenuItem extends FlxSpriteGroup week = new FlxSprite(); week.frames = tex; - week.animation.addByPrefix('week0', "WEEK1 select", 24); - week.animation.addByPrefix('week1', "week2 select", 24); + // TUTORIAL IS WEEK 0 + week.animation.addByPrefix('week0', 'tutorial selected', 24); + week.animation.addByPrefix('week1', "WEEK1 select", 24); + week.animation.addByPrefix('week2', "week2 select", 24); add(week); week.animation.play('week' + weekNum); week.animation.pause(); week.updateHitbox(); - - if (!unlocked) - { - week.alpha = 0.6; - } } override function update(elapsed:Float) diff --git a/source/MusicBeatSubstate.hx b/source/MusicBeatSubstate.hx index 0e452e9cd..511f597a7 100644 --- a/source/MusicBeatSubstate.hx +++ b/source/MusicBeatSubstate.hx @@ -1,5 +1,6 @@ package; +import flixel.FlxG; import flixel.FlxSubState; class MusicBeatSubstate extends FlxSubState diff --git a/source/NGio.hx b/source/NGio.hx index f90bca4c4..2073c073b 100644 --- a/source/NGio.hx +++ b/source/NGio.hx @@ -146,6 +146,15 @@ class NGio // NGio.scoreboardArray = NG.core.scoreBoards.get(8004).scores; } + inline static public function logEvent(event:String) + { + if (isLoggedIn) + { + NG.core.calls.event.logEvent(event); + trace('should have logged: ' + event); + } + } + inline static public function unlockMedal(id:Int) { if (isLoggedIn) diff --git a/source/OptionsMenu.hx b/source/OptionsMenu.hx new file mode 100644 index 000000000..c79c3ec70 --- /dev/null +++ b/source/OptionsMenu.hx @@ -0,0 +1,29 @@ +package; + +import flixel.FlxG; +import flixel.FlxSprite; +import flixel.util.FlxColor; + +class OptionsMenu extends MusicBeatState +{ + override function create() + { + var menuBG:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.menuDesat__png); + menuBG.color = 0xFFea71fd; + menuBG.setGraphicSize(Std.int(menuBG.width * 1.1)); + menuBG.updateHitbox(); + menuBG.screenCenter(); + menuBG.antialiasing = true; + add(menuBG); + + super.create(); + } + + override function update(elapsed:Float) + { + if (controls.BACK) + FlxG.switchState(new MainMenuState()); + + super.update(elapsed); + } +} diff --git a/source/OptionsSubState.hx b/source/OptionsSubState.hx new file mode 100644 index 000000000..1995b868a --- /dev/null +++ b/source/OptionsSubState.hx @@ -0,0 +1,11 @@ +package; + +class OptionsSubState extends MusicBeatSubstate +{ + var textMenuItems:Array = ['Master Volume', 'Sound Volume']; + + public function new() + { + super(); + } +} diff --git a/source/PlayState.hx b/source/PlayState.hx index e65bfa35a..87a435f22 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -37,6 +37,7 @@ class PlayState extends MusicBeatState public static var curLevel:String = 'Tutorial'; public static var SONG:SwagSong; public static var isStoryMode:Bool = false; + public static var storyWeek:Int = 0; public static var storyPlaylist:Array = []; public static var storyDifficulty:Int = 1; @@ -83,6 +84,8 @@ class PlayState extends MusicBeatState var talking:Bool = true; var songScore:Int = 0; + public static var campaignScore:Int = 0; + override public function create() { // var gameCam:FlxCamera = FlxG.camera; @@ -460,7 +463,7 @@ class PlayState extends MusicBeatState daBeats += 1; } - trace(unspawnNotes.length); + // trace(unspawnNotes.length); // playerCounter += 1; unspawnNotes.sort(sortByShit); @@ -562,7 +565,7 @@ class PlayState extends MusicBeatState { if (FlxG.sound.music != null) { - vocals.time = FlxG.sound.music.time; + vocals.time = Conductor.songPosition; FlxG.sound.music.play(); vocals.play(); @@ -602,9 +605,9 @@ class PlayState extends MusicBeatState openSubState(new PauseSubState(boyfriend.getScreenPosition().x, boyfriend.getScreenPosition().y)); } - if (FlxG.keys.justPressed.ESCAPE) + if (FlxG.keys.justPressed.SEVEN) { - // FlxG.switchState(new ChartingState()); + FlxG.switchState(new ChartingState()); } // FlxG.watch.addQuick('VOL', vocals.amplitudeLeft); @@ -641,8 +644,7 @@ class PlayState extends MusicBeatState } else { - //Conductor.songPosition = FlxG.sound.music.time; - Conductor.songPosition += FlxG.elapsed * 1000; + Conductor.songPosition = FlxG.sound.music.time; if (!paused) { @@ -812,6 +814,7 @@ class PlayState extends MusicBeatState } daNote.y = (strumLine.y - (Conductor.songPosition - daNote.strumTime) * (0.45 * PlayState.SONG.speed)); + // WIP interpolation shit? Need to fix the pause issue // daNote.y = (strumLine.y - (songTime - daNote.strumTime) * (0.45 * PlayState.SONG.speed)); @@ -838,16 +841,12 @@ class PlayState extends MusicBeatState function endSong():Void { - trace('SONG DONE' + isStoryMode); - - - #if !switch - NGio.postScore(songScore, SONG.song); - #end - + Highscore.saveScore(SONG.song, songScore, storyDifficulty); if (isStoryMode) { + campaignScore += songScore; + storyPlaylist.remove(storyPlaylist[0]); if (storyPlaylist.length <= 0) @@ -856,12 +855,12 @@ class PlayState extends MusicBeatState FlxG.switchState(new StoryMenuState()); - StoryMenuState.weekUnlocked[1] = true; + StoryMenuState.weekUnlocked[2] = true; #if !switch NGio.unlockMedal(60961); #end - + Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty); FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; FlxG.save.flush(); @@ -1041,7 +1040,6 @@ class PlayState extends MusicBeatState if (daNote.canBeHit && daNote.mustPress && !daNote.tooLate) { possibleNotes.push(daNote); - trace('NOTE-' + daNote.strumTime + ' ADDED'); } }); @@ -1234,7 +1232,6 @@ class PlayState extends MusicBeatState function noteCheck(keyP:Bool, note:Note):Void { - trace(note.noteData + ' note check here ' + keyP); if (keyP) goodNoteHit(note); else @@ -1304,9 +1301,9 @@ class PlayState extends MusicBeatState if (vocals.time > Conductor.songPosition + Conductor.stepCrochet || vocals.time < Conductor.songPosition - Conductor.stepCrochet) { - //vocals.pause(); + vocals.pause(); vocals.time = Conductor.songPosition; - //vocals.play(); + vocals.play(); } } diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index d88ab4833..0f4b5c018 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -5,6 +5,7 @@ import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; import flixel.group.FlxGroup.FlxTypedGroup; import flixel.group.FlxGroup; +import flixel.math.FlxMath; import flixel.text.FlxText; import flixel.tweens.FlxTween; import flixel.util.FlxTimer; @@ -16,12 +17,12 @@ class StoryMenuState extends MusicBeatState { var scoreText:FlxText; - var weekData:Array = [['Tutorial', 'Bopeebo', 'Fresh', 'Dadbattle'], ['Spookeez', 'South']]; + var weekData:Array = [['Tutorial'], ['Bopeebo', 'Fresh', 'Dadbattle'], ['Spookeez', 'South']]; var curDifficulty:Int = 1; - public static var weekUnlocked:Array = [true, false]; + public static var weekUnlocked:Array = [true, true, false]; - var weekCharacters:Array = [['dad', 'bf', 'gf'], ['spooky', 'bf', 'gf']]; + var weekCharacters:Array = [['dad', 'bf', 'gf'], ['dad', 'bf', 'gf'], ['spooky', 'bf', 'gf']]; var curWeek:Int = 0; var txtTracklist:FlxText; @@ -38,8 +39,11 @@ class StoryMenuState extends MusicBeatState override function create() { - if (!FlxG.sound.music.playing) - FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + if (FlxG.sound.music != null) + { + if (!FlxG.sound.music.playing) + FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + } persistentUpdate = persistentDraw = true; @@ -65,12 +69,7 @@ class StoryMenuState extends MusicBeatState for (i in 0...weekData.length) { - var unlocked:Bool = true; - - if (i == 1) - unlocked = false; - - var weekThing:MenuItem = new MenuItem(0, yellowBG.y + yellowBG.height + 10, i, unlocked); + var weekThing:MenuItem = new MenuItem(0, yellowBG.y + yellowBG.height + 10, i); weekThing.y += ((weekThing.height + 20) * i); weekThing.targetY = i; grpWeekText.add(weekThing); @@ -79,6 +78,7 @@ class StoryMenuState extends MusicBeatState weekThing.antialiasing = true; // weekThing.updateHitbox(); + // Needs an offset thingie if (!weekUnlocked[i]) { var lock:FlxSprite = new FlxSprite(weekThing.width + 10 + weekThing.x); @@ -117,7 +117,7 @@ class StoryMenuState extends MusicBeatState difficultySelectors = new FlxGroup(); add(difficultySelectors); - leftArrow = new FlxSprite(grpWeekText.members[0].x + 370, grpWeekText.members[0].y + 10); + leftArrow = new FlxSprite(grpWeekText.members[0].x + grpWeekText.members[0].width + 10, grpWeekText.members[0].y + 10); leftArrow.frames = ui_tex; leftArrow.animation.addByPrefix('idle', "arrow left"); leftArrow.animation.addByPrefix('press', "arrow push left"); @@ -150,7 +150,7 @@ class StoryMenuState extends MusicBeatState txtTracklist.color = 0xFFe55777; add(txtTracklist); // add(rankText); - // add(scoreText); + add(scoreText); updateText(); @@ -160,7 +160,9 @@ class StoryMenuState extends MusicBeatState override function update(elapsed:Float) { // scoreText.setFormat('VCR OSD Mono', 32); - // scoreText.text = "Score SHIT"; + lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.5)); + + scoreText.text = "WEEK SCORE:" + lerpScore; // FlxG.watch.addQuick('font', scoreText.font); difficultySelectors.visible = weekUnlocked[curWeek]; @@ -245,6 +247,8 @@ class StoryMenuState extends MusicBeatState PlayState.storyDifficulty = curDifficulty; PlayState.SONG = Song.loadFromJson(PlayState.storyPlaylist[0].toLowerCase() + diffic, PlayState.storyPlaylist[0].toLowerCase()); + PlayState.storyWeek = curWeek; + PlayState.campaignScore = 0; new FlxTimer().start(1, function(tmr:FlxTimer) { if (FlxG.sound.music != null) @@ -282,10 +286,14 @@ class StoryMenuState extends MusicBeatState // USING THESE WEIRD VALUES SO THAT IT DOESNT FLOAT UP sprDifficulty.y = leftArrow.y - 15; + intendedScore = Highscore.getWeekScore(curWeek, curDifficulty); FlxTween.tween(sprDifficulty, {y: leftArrow.y + 15, alpha: 1}, 0.07); } + var lerpScore:Int = 0; + var intendedScore:Int = 0; + function changeWeek(change:Int = 0):Void { curWeek += change; @@ -300,6 +308,10 @@ class StoryMenuState extends MusicBeatState for (item in grpWeekText.members) { item.targetY = bullShit - curWeek; + if (item.targetY == Std.int(0) && weekUnlocked[curWeek]) + item.alpha = 1; + else + item.alpha = 0.6; bullShit++; } @@ -326,5 +338,7 @@ class StoryMenuState extends MusicBeatState txtTracklist.screenCenter(X); txtTracklist.x -= FlxG.width * 0.35; + + intendedScore = Highscore.getWeekScore(curWeek, curDifficulty); } } diff --git a/source/TitleState.hx b/source/TitleState.hx index 699de8a54..f4d3274aa 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -36,13 +36,13 @@ class TitleState extends MusicBeatState ['Ritz dx', 'rest in peace'], ['rate five', 'pls no blam'], ['rhythm gaming', 'ultimate'], ['game of the year', 'forever'], ['you already know', 'we really out here'], ['rise and grind', 'love to luis'], ['like parappa', 'but cooler'], ['album of the year', 'chuckie finster'], ["free gitaroo man", "with love to wandaboy"], ['better than geometry dash', 'fight me robtop'], - ['kiddbrute for president', 'vote now']]; + ['kiddbrute for president', 'vote now'], ['play dead estate', 'on newgrounds'], ['this is a god damn prototype', 'we workin on it okay'], + ['WOMEN ARE real', 'this is official']]; var curWacky:Array = []; var wackyImage:FlxSprite; - override public function create():Void { #if (!web) @@ -57,11 +57,22 @@ class TitleState extends MusicBeatState super.create(); - #if (!switch && !debug && NG_LOGIN) var ng:NGio = new NGio(APIStuff.API, APIStuff.EncKey); #end + FlxG.save.bind('funkin', 'ninjamuffin99'); + + Highscore.load(); + + if (FlxG.save.data.weekUnlocked != null) + { + StoryMenuState.weekUnlocked = FlxG.save.data.weekUnlocked; + + if (StoryMenuState.weekUnlocked.length < 3) + StoryMenuState.weekUnlocked.insert(0, true); + } + #if SKIP_TO_PLAYSTATE FlxG.switchState(new StoryMenuState()); #else @@ -76,10 +87,6 @@ class TitleState extends MusicBeatState function startIntro() { - #if switch - initialized = true; - #end - if (!initialized) { var diamond:FlxGraphic = FlxGraphic.fromClass(GraphicTransTileDiamond); @@ -100,13 +107,6 @@ class TitleState extends MusicBeatState FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt, 0); FlxG.sound.music.fadeIn(4, 0, 0.7); - - FlxG.save.bind('funkin', 'ninjamuffin99'); - - if (FlxG.save.data.weekUnlocked != null) - { - StoryMenuState.weekUnlocked = FlxG.save.data.weekUnlocked; - } } Conductor.changeBPM(102); @@ -192,6 +192,12 @@ class TitleState extends MusicBeatState override function update(elapsed:Float) { Conductor.songPosition = FlxG.sound.music.time; + // FlxG.watch.addQuick('amp', FlxG.sound.music.amplitude); + + if (FlxG.keys.justPressed.F) + { + FlxG.fullscreen = !FlxG.fullscreen; + } var pressedEnter:Bool = FlxG.keys.justPressed.ENTER; @@ -212,6 +218,10 @@ class TitleState extends MusicBeatState { #if !switch NGio.unlockMedal(60960); + + // If it's Friday according to da clock + if (Date.now().getDay() == 5) + NGio.unlockMedal(61034); #end titleText.animation.play('press'); From e4f72e1979f3b252527e01088a82b48b2ecd3ace Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 6 Nov 2020 21:18:55 -0500 Subject: [PATCH 05/24] caught up to cam again --- Project.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.xml b/Project.xml index 5da40d92f..38c988e31 100644 --- a/Project.xml +++ b/Project.xml @@ -60,8 +60,8 @@ - - + + From 179492e9a193196bad202605761f9a1858a29811 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 6 Nov 2020 21:24:03 -0500 Subject: [PATCH 06/24] uhhh --- Project.xml | 2 +- source/FreeplayState.hx | 2 +- source/PlayState.hx | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Project.xml b/Project.xml index 38c988e31..22b04d7d8 100644 --- a/Project.xml +++ b/Project.xml @@ -59,7 +59,7 @@ - + diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index ad336ce8a..1457fbf18 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -8,7 +8,7 @@ import flixel.group.FlxGroup.FlxTypedGroup; import flixel.math.FlxMath; import flixel.text.FlxText; import flixel.util.FlxColor; -import htmlparser.HtmlDocument; +//import htmlparser.HtmlDocument; import lime.utils.Assets; class FreeplayState extends MusicBeatState diff --git a/source/PlayState.hx b/source/PlayState.hx index 87a435f22..a0540eb9f 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -841,7 +841,9 @@ class PlayState extends MusicBeatState function endSong():Void { + #if !switch Highscore.saveScore(SONG.song, songScore, storyDifficulty); + #end if (isStoryMode) { @@ -859,8 +861,8 @@ class PlayState extends MusicBeatState #if !switch NGio.unlockMedal(60961); - #end Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty); + #end FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; FlxG.save.flush(); From 7062391e70cff4e4bffbedb79e32d761ae9f0336 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 6 Nov 2020 21:34:04 -0500 Subject: [PATCH 07/24] boo george --- source/io/newgrounds/Call.hx | 227 --------- source/io/newgrounds/NG.hx | 475 ------------------ source/io/newgrounds/NGLite.hx | 287 ----------- .../io/newgrounds/components/AppComponent.hx | 44 -- source/io/newgrounds/components/Component.hx | 13 - .../io/newgrounds/components/ComponentList.hx | 25 - .../newgrounds/components/EventComponent.hx | 16 - .../newgrounds/components/GatewayComponent.hx | 25 - .../newgrounds/components/LoaderComponent.hx | 44 -- .../newgrounds/components/MedalComponent.hx | 21 - .../components/ScoreBoardComponent.hx | 114 ----- source/io/newgrounds/crypto/Cipher.hx | 8 - .../io/newgrounds/crypto/EncryptionFormat.hx | 7 - source/io/newgrounds/crypto/Rc4.hx | 68 --- source/io/newgrounds/objects/Error.hx | 20 - source/io/newgrounds/objects/Medal.hx | 118 ----- source/io/newgrounds/objects/Object.hx | 33 -- source/io/newgrounds/objects/Score.hx | 17 - source/io/newgrounds/objects/ScoreBoard.hx | 76 --- source/io/newgrounds/objects/Session.hx | 65 --- source/io/newgrounds/objects/User.hx | 19 - source/io/newgrounds/objects/UserIcons.hx | 14 - .../io/newgrounds/objects/events/Response.hx | 43 -- source/io/newgrounds/objects/events/Result.hx | 109 ---- source/io/newgrounds/swf/LoadingBar.hx | 23 - source/io/newgrounds/swf/MedalPopup.hx | 151 ------ source/io/newgrounds/swf/ScoreBrowser.hx | 250 --------- source/io/newgrounds/swf/common/BaseAsset.hx | 35 -- source/io/newgrounds/swf/common/Button.hx | 151 ------ source/io/newgrounds/swf/common/DropDown.hx | 88 ---- source/io/newgrounds/utils/AsyncHttp.hx | 203 -------- source/io/newgrounds/utils/Dispatcher.hx | 118 ----- 32 files changed, 2907 deletions(-) delete mode 100644 source/io/newgrounds/Call.hx delete mode 100644 source/io/newgrounds/NG.hx delete mode 100644 source/io/newgrounds/NGLite.hx delete mode 100644 source/io/newgrounds/components/AppComponent.hx delete mode 100644 source/io/newgrounds/components/Component.hx delete mode 100644 source/io/newgrounds/components/ComponentList.hx delete mode 100644 source/io/newgrounds/components/EventComponent.hx delete mode 100644 source/io/newgrounds/components/GatewayComponent.hx delete mode 100644 source/io/newgrounds/components/LoaderComponent.hx delete mode 100644 source/io/newgrounds/components/MedalComponent.hx delete mode 100644 source/io/newgrounds/components/ScoreBoardComponent.hx delete mode 100644 source/io/newgrounds/crypto/Cipher.hx delete mode 100644 source/io/newgrounds/crypto/EncryptionFormat.hx delete mode 100644 source/io/newgrounds/crypto/Rc4.hx delete mode 100644 source/io/newgrounds/objects/Error.hx delete mode 100644 source/io/newgrounds/objects/Medal.hx delete mode 100644 source/io/newgrounds/objects/Object.hx delete mode 100644 source/io/newgrounds/objects/Score.hx delete mode 100644 source/io/newgrounds/objects/ScoreBoard.hx delete mode 100644 source/io/newgrounds/objects/Session.hx delete mode 100644 source/io/newgrounds/objects/User.hx delete mode 100644 source/io/newgrounds/objects/UserIcons.hx delete mode 100644 source/io/newgrounds/objects/events/Response.hx delete mode 100644 source/io/newgrounds/objects/events/Result.hx delete mode 100644 source/io/newgrounds/swf/LoadingBar.hx delete mode 100644 source/io/newgrounds/swf/MedalPopup.hx delete mode 100644 source/io/newgrounds/swf/ScoreBrowser.hx delete mode 100644 source/io/newgrounds/swf/common/BaseAsset.hx delete mode 100644 source/io/newgrounds/swf/common/Button.hx delete mode 100644 source/io/newgrounds/swf/common/DropDown.hx delete mode 100644 source/io/newgrounds/utils/AsyncHttp.hx delete mode 100644 source/io/newgrounds/utils/Dispatcher.hx diff --git a/source/io/newgrounds/Call.hx b/source/io/newgrounds/Call.hx deleted file mode 100644 index bd5d7acaf..000000000 --- a/source/io/newgrounds/Call.hx +++ /dev/null @@ -1,227 +0,0 @@ -package io.newgrounds; - -import io.newgrounds.utils.Dispatcher; -import io.newgrounds.utils.AsyncHttp; -import io.newgrounds.objects.Error; -import io.newgrounds.objects.events.Result; -import io.newgrounds.objects.events.Result.ResultBase; -import io.newgrounds.objects.events.Response; - -import haxe.ds.StringMap; -import haxe.Json; - -/** A generic way to handle calls agnostic to their type */ -interface ICallable { - - public var component(default, null):String; - - public function send():Void; - public function queue():Void; - public function destroy():Void; -} - -class Call - implements ICallable { - - public var component(default, null):String; - - var _core:NGLite; - var _properties:StringMap; - var _parameters:StringMap; - var _requireSession:Bool; - var _isSecure:Bool; - - // --- BASICALLY SIGNALS - var _dataHandlers:TypedDispatcher>; - var _successHandlers:Dispatcher; - var _httpErrorHandlers:TypedDispatcher; - var _statusHandlers:TypedDispatcher; - - public function new (core:NGLite, component:String, requireSession:Bool = false, isSecure:Bool = false) { - - _core = core; - this.component = component; - _requireSession = requireSession; - _isSecure = isSecure && core.encryptionHandler != null; - } - - /** adds a property to the input's object. **/ - public function addProperty(name:String, value:Dynamic):Call { - - if (_properties == null) - _properties = new StringMap(); - - _properties.set(name, value); - - return this; - } - - /** adds a parameter to the call's component object. **/ - public function addComponentParameter(name:String, value:Dynamic, defaultValue:Dynamic = null):Call { - - if (value == defaultValue)//TODO?: allow sending null value - return this; - - if (_parameters == null) - _parameters = new StringMap(); - - _parameters.set(name, value); - - return this; - } - - /** Handy callback setter for chained call modifiers. Called when ng.io replies successfully */ - public function addDataHandler(handler:Response->Void):Call { - - if (_dataHandlers == null) - _dataHandlers = new TypedDispatcher>(); - - _dataHandlers.add(handler); - return this; - } - - /** Handy callback setter for chained call modifiers. Called when ng.io replies successfully */ - public function addSuccessHandler(handler:Void->Void):Call { - - if (_successHandlers == null) - _successHandlers = new Dispatcher(); - - _successHandlers.add(handler); - return this; - } - - /** Handy callback setter for chained call modifiers. Called when ng.io does not reply for any reason */ - public function addErrorHandler(handler:Error->Void):Call { - - if (_httpErrorHandlers == null) - _httpErrorHandlers = new TypedDispatcher(); - - _httpErrorHandlers.add(handler); - return this; - } - - /** Handy callback setter for chained call modifiers. No idea when this is called; */ - public function addStatusHandler(handler:Int->Void):Call {//TODO:learn what this is for - - if (_statusHandlers == null) - _statusHandlers = new TypedDispatcher(); - - _statusHandlers.add(handler); - return this; - } - - /** - * Sends the call to the server, do not modify this object after calling this - * @param secure If encryption is enabled, it will encrypt the call. - **/ - public function send():Void { - - var data:Dynamic = {}; - data.app_id = _core.appId; - data.call = {}; - data.call.component = component; - - if (_core.debug) - addProperty("debug", true); - - if (_properties == null || !_properties.exists("session_id")) { - // --- HAS NO SESSION ID - - if (_core.sessionId != null) { - // --- AUTO ADD SESSION ID - - addProperty("session_id", _core.sessionId); - - } else if (_requireSession){ - - _core.logError(new Error('cannot send "$component" call without a sessionId')); - return; - } - } - - if (_properties != null) { - - for (field in _properties.keys()) - Reflect.setField(data, field, _properties.get(field)); - } - - if (_parameters != null) { - - data.call.parameters = {}; - - for (field in _parameters.keys()) - Reflect.setField(data.call.parameters, field, _parameters.get(field)); - } - - _core.logVerbose('Post - ${Json.stringify(data)}'); - - if (_isSecure) { - - var secureData = _core.encryptionHandler(Json.stringify(data.call)); - data.call = {}; - data.call.secure = secureData; - - _core.logVerbose(' secure - $secureData'); - } - - _core.markCallPending(this); - - AsyncHttp.send(_core, Json.stringify(data), onData, onHttpError, onStatus); - } - - /** Adds the call to the queue */ - public function queue():Void { - - _core.queueCall(this); - } - - function onData(reply:String):Void { - - _core.logVerbose('Reply - $reply'); - - if (_dataHandlers == null && _successHandlers == null) - return; - - var response = new Response(_core, reply); - - if (_dataHandlers != null) - _dataHandlers.dispatch(response); - - if (response.success && response.result.success && _successHandlers != null) - _successHandlers.dispatch(); - - destroy(); - } - - function onHttpError(message:String):Void { - - _core.logError(message); - - if (_httpErrorHandlers == null) - return; - - var error = new Error(message); - _httpErrorHandlers.dispatch(error); - } - - function onStatus(status:Int):Void { - - if (_statusHandlers == null) - return; - - _statusHandlers.dispatch(status); - } - - public function destroy():Void { - - _core = null; - - _properties = null; - _parameters = null; - - _dataHandlers = null; - _successHandlers = null; - _httpErrorHandlers = null; - _statusHandlers = null; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/NG.hx b/source/io/newgrounds/NG.hx deleted file mode 100644 index 3445443ee..000000000 --- a/source/io/newgrounds/NG.hx +++ /dev/null @@ -1,475 +0,0 @@ -package io.newgrounds; - -#if ng_lite -typedef NG = NGLite; //TODO: test and make lite UI -#else -import io.newgrounds.utils.Dispatcher; -import io.newgrounds.objects.Error; -import io.newgrounds.objects.events.Result.SessionResult; -import io.newgrounds.objects.events.Result.MedalListResult; -import io.newgrounds.objects.events.Result.ScoreBoardResult; -import io.newgrounds.objects.events.Response; -import io.newgrounds.objects.User; -import io.newgrounds.objects.Medal; -import io.newgrounds.objects.Session; -import io.newgrounds.objects.ScoreBoard; - -import haxe.ds.IntMap; -import haxe.Timer; - -/** - * The Newgrounds API for Haxe. - * Contains many things ripped from MSGhero - * - https://github.com/MSGhero/NG.hx - * @author GeoKureli - */ -class NG extends NGLite { - - static public var core(default, null):NG; - static public var onCoreReady(default, null):Dispatcher = new Dispatcher(); - - // --- DATA - - /** The logged in user */ - public var user(get, never):User; - function get_user():User { - - if (_session == null) - return null; - - return _session.user; - } - public var passportUrl(get, never):String; - function get_passportUrl():String { - - if (_session == null || _session.status != SessionStatus.REQUEST_LOGIN) - return null; - - return _session.passportUrl; - } - public var medals(default, null):IntMap; - public var scoreBoards(default, null):IntMap; - - // --- EVENTS - - public var onLogin(default, null):Dispatcher; - public var onLogOut(default, null):Dispatcher; - public var onMedalsLoaded(default, null):Dispatcher; - public var onScoreBoardsLoaded(default, null):Dispatcher; - - // --- MISC - - public var loggedIn(default, null):Bool; - public var attemptingLogin(default, null):Bool; - - var _loginCancelled:Bool; - var _passportCallback:Void->Void; - - var _session:Session; - - /** - * Iniitializes the API, call before utilizing any other component - * @param appId The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. - * @param sessionId A unique session id used to identify the active user. - **/ - public function new(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void) { - - _session = new Session(this); - onLogin = new Dispatcher(); - onLogOut = new Dispatcher(); - onMedalsLoaded = new Dispatcher(); - onScoreBoardsLoaded = new Dispatcher(); - - attemptingLogin = sessionId != null; - - super(appId, sessionId, onSessionFail); - } - - /** - * Creates NG.core, the heart and soul of the API. This is not the only way to create an instance, - * nor is NG a forced singleton, but it's the only way to set the static NG.core. - **/ - static public function create(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void):Void { - - core = new NG(appId, sessionId, onSessionFail); - - onCoreReady.dispatch(); - } - - /** - * Creates NG.core, and tries to create a session. This is not the only way to create an instance, - * nor is NG a forced singleton, but it's the only way to set the static NG.core. - **/ - static public function createAndCheckSession - ( appId = "test" - , backupSession:String = null - , ?onSessionFail:Error->Void - ):Void { - - var session = NGLite.getSessionId(); - if (session == null) - session = backupSession; - - create(appId, session, onSessionFail); - - core.host = getHost(); - if (core.sessionId != null) - core.attemptingLogin = true; - } - - // ------------------------------------------------------------------------------------------- - // APP - // ------------------------------------------------------------------------------------------- - - override function checkInitialSession(failHandler:Error->Void, response:Response):Void { - - onSessionReceive(response, null, null, failHandler); - } - - /** - * Begins the login process - * - * @param onSuccess Called when the login is a success - * @param onPending Called when the passportUrl has been identified, call NG.core.openPassportLink - * to open the link continue the process. Leave as null to open the url automatically - * NOTE: Browser games must open links on click events or else it will be blocked by - * the popup blocker. - * @param onFail - * @param onCancel Called when the user denies the passport connection. - */ - public function requestLogin - ( onSuccess:Void->Void = null - , onPending:Void->Void = null - , onFail :Error->Void = null - , onCancel :Void->Void = null - ):Void { - - if (attemptingLogin) { - - logError("cannot request another login until the previous attempt is complete"); - return; - } - - if (loggedIn) { - - logError("cannot log in, already logged in"); - return; - } - - attemptingLogin = true; - _loginCancelled = false; - _passportCallback = null; - - var call = calls.app.startSession(true) - .addDataHandler(onSessionReceive.bind(_, onSuccess, onPending, onFail, onCancel)); - - if (onFail != null) - call.addErrorHandler(onFail); - - call.send(); - } - - function onSessionReceive - ( response :Response - , onSuccess:Void->Void = null - , onPending:Void->Void = null - , onFail :Error->Void = null - , onCancel :Void->Void = null - ):Void { - - if (!response.success || !response.result.success) { - - sessionId = null; - endLoginAndCall(null); - - if (onFail != null) - onFail(!response.success ? response.error : response.result.error); - - return; - } - - _session.parse(response.result.data.session); - sessionId = _session.id; - - logVerbose('session started - status: ${_session.status}'); - - if (_session.status == SessionStatus.REQUEST_LOGIN) { - - _passportCallback = checkSession.bind(null, onSuccess, onCancel); - if (onPending != null) - onPending(); - else - openPassportUrl(); - - } else - checkSession(null, onSuccess, onCancel); - } - - /** - * Call this once the passport link is established and it will load the passport URL and - * start checking for session connect periodically - */ - public function openPassportUrl():Void { - - if (passportUrl != null) { - - logVerbose('loading passport: ${passportUrl}'); - openPassportHelper(passportUrl); - onPassportUrlOpen(); - - } else - logError("Cannot open passport"); - } - - - static function openPassportHelper(url:String):Void { - var window = "_blank"; - - #if flash - flash.Lib.getURL(new flash.net.URLRequest(url), window); - #elseif (js && html5) - js.Browser.window.open(url, window); - #elseif desktop - - #if (sys && windows) - Sys.command("start", ["", url]); - #elseif mac - Sys.command("/usr/bin/open", [url]); - #elseif linux - Sys.command("/usr/bin/xdg-open", [path, "&"]); - #end - - #elseif android - JNI.createStaticMethod - ( "org/haxe/lime/GameActivity" - , "openURL" - , "(Ljava/lang/String;Ljava/lang/String;)V" - ) (url, window); - #end - } - - /** - * Call this once the passport link is established and it will start checking for session connect periodically - */ - public function onPassportUrlOpen():Void { - - if (_passportCallback != null) - _passportCallback(); - - _passportCallback = null; - } - - function checkSession(response:Response, onSucceess:Void->Void, onCancel:Void->Void):Void { - - if (response != null) { - - if (!response.success || !response.result.success) { - - log("login cancelled via passport"); - - endLoginAndCall(onCancel); - return; - } - - _session.parse(response.result.data.session); - } - - if (_session.status == SessionStatus.USER_LOADED) { - - loggedIn = true; - endLoginAndCall(onSucceess); - onLogin.dispatch(); - - } else if (_session.status == SessionStatus.REQUEST_LOGIN){ - - var call = calls.app.checkSession() - .addDataHandler(checkSession.bind(_, onSucceess, onCancel)); - - // Wait 3 seconds and try again - timer(3.0, - function():Void { - - // Check if cancelLoginRequest was called - if (!_loginCancelled) - call.send(); - else { - - log("login cancelled via cancelLoginRequest"); - endLoginAndCall(onCancel); - } - } - ); - - } else - // The user cancelled the passport - endLoginAndCall(onCancel); - } - - public function cancelLoginRequest():Void { - - if (attemptingLogin) - _loginCancelled = true; - } - - function endLoginAndCall(callback:Void->Void):Void { - - attemptingLogin = false; - _loginCancelled = false; - - if (callback != null) - callback(); - } - - public function logOut(onComplete:Void->Void = null):Void { - - var call = calls.app.endSession() - .addSuccessHandler(onLogOutSuccessful); - - if (onComplete != null) - call.addSuccessHandler(onComplete); - - call.addSuccessHandler(onLogOut.dispatch) - .send(); - } - - function onLogOutSuccessful():Void { - - _session.expire(); - sessionId = null; - loggedIn = false; - } - - // ------------------------------------------------------------------------------------------- - // MEDALS - // ------------------------------------------------------------------------------------------- - - public function requestMedals(onSuccess:Void->Void = null, onFail:Error->Void = null):Void { - - var call = calls.medal.getList() - .addDataHandler(onMedalsReceived); - - if (onSuccess != null) - call.addSuccessHandler(onSuccess); - - if (onFail != null) - call.addErrorHandler(onFail); - - call.send(); - } - - function onMedalsReceived(response:Response):Void { - - if (!response.success || !response.result.success) - return; - - var idList:Array = new Array(); - - if (medals == null) { - - medals = new IntMap(); - - for (medalData in response.result.data.medals) { - - var medal = new Medal(this, medalData); - medals.set(medal.id, medal); - idList.push(medal.id); - } - } else { - - for (medalData in response.result.data.medals) { - - medals.get(medalData.id).parse(medalData); - idList.push(medalData.id); - } - } - - logVerbose('${response.result.data.medals.length} Medals received [${idList.join(", ")}]'); - - onMedalsLoaded.dispatch(); - } - - // ------------------------------------------------------------------------------------------- - // SCOREBOARDS - // ------------------------------------------------------------------------------------------- - - public function requestScoreBoards(onSuccess:Void->Void = null, onFail:Error->Void = null):Void { - - if (scoreBoards != null) { - - log("aborting scoreboard request, all scoreboards are loaded"); - - if (onSuccess != null) - onSuccess(); - - return; - } - - var call = calls.scoreBoard.getBoards() - .addDataHandler(onBoardsReceived); - - if (onSuccess != null) - call.addSuccessHandler(onSuccess); - - if (onFail != null) - call.addErrorHandler(onFail); - - call.send(); - } - - function onBoardsReceived(response:Response):Void { - - if (!response.success || !response.result.success) - return; - - var idList:Array = new Array(); - - if (scoreBoards == null) { - - scoreBoards = new IntMap(); - - for (boardData in response.result.data.scoreboards) { - - var board = new ScoreBoard(this, boardData); - scoreBoards.set(board.id, board); - idList.push(board.id); - } - } - - logVerbose('${response.result.data.scoreboards.length} ScoreBoards received [${idList.join(", ")}]'); - - onScoreBoardsLoaded.dispatch(); - } - - // ------------------------------------------------------------------------------------------- - // HELPERS - // ------------------------------------------------------------------------------------------- - - function timer(delay:Float, callback:Void->Void):Void { - - var timer = new Timer(Std.int(delay * 1000)); - timer.run = function func():Void { - - timer.stop(); - callback(); - } - } - - static var urlParser:EReg = ~/^(?:http[s]?:\/\/)?([^:\/\s]+)(:[0-9]+)?((?:\/\w+)*\/)([\w\-\.]+[^#?\s]+)([^#\s]*)?(#[\w\-]+)?$/i;//TODO:trim - /** Used to get the current web host of your game. */ - static public function getHost():String { - - var url = NGLite.getUrl(); - - if (url == null || url == "") - return ""; - - if (url.indexOf("file") == 0) - return ""; - - if (urlParser.match(url)) - return urlParser.matched(1); - - return ""; - } -} -#end \ No newline at end of file diff --git a/source/io/newgrounds/NGLite.hx b/source/io/newgrounds/NGLite.hx deleted file mode 100644 index 0c9d5bdf5..000000000 --- a/source/io/newgrounds/NGLite.hx +++ /dev/null @@ -1,287 +0,0 @@ -package io.newgrounds; - -import haxe.crypto.Base64; -import haxe.io.Bytes; -import haxe.PosInfos; - -import io.newgrounds.Call.ICallable; -import io.newgrounds.components.ComponentList; -import io.newgrounds.crypto.EncryptionFormat; -import io.newgrounds.crypto.Cipher; -import io.newgrounds.crypto.Rc4; -import io.newgrounds.objects.Error; -import io.newgrounds.objects.events.Response; -import io.newgrounds.objects.events.Result.ResultBase; -import io.newgrounds.objects.events.Result.SessionResult; -import io.newgrounds.utils.Dispatcher; - -#if !(html5 || flash || desktop || neko) - #error "Target not supported, use: Flash, JS/HTML5, cpp or maybe neko"; -#end - -/** - * The barebones NG.io API. Allows API calls with code completion - * and retrieves server data via strongly typed Objects - * - * Contains many things ripped from MSGhero's repo - * - https://github.com/MSGhero/NG.hx - * - * @author GeoKureli - */ -class NGLite { - - static public var core(default, null):NGLite; - static public var onCoreReady(default, null):Dispatcher = new Dispatcher(); - - /** Enables verbose logging */ - public var verbose:Bool; - public var debug:Bool; - /** The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. */ - public var appId(default, null):String; - /** The name of the host the game is being played on */ - public var host:String; - - @:isVar - public var sessionId(default, set):String; - function set_sessionId(value:String):String { - - return this.sessionId = value == "" ? null : value; - } - - /** Components used to call the NG server directly */ - public var calls(default, null):ComponentList; - - /** - * Converts an object to an encrypted string that can be decrypted by the server. - * Set your preffered encrypter here, - * or just call setDefaultEcryptionHandler with your app's encryption settings - **/ - public var encryptionHandler:String->String; - - /** - * Iniitializes the API, call before utilizing any other component - * @param appId The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. - * @param sessionId A unique session id used to identify the active user. - **/ - public function new(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void) { - - this.appId = appId; - this.sessionId = sessionId; - - calls = new ComponentList(this); - - if (this.sessionId != null) { - - calls.app.checkSession() - .addDataHandler(checkInitialSession.bind(onSessionFail)) - .addErrorHandler(initialSessionFail.bind(onSessionFail)) - .send(); - } - } - - function checkInitialSession(onFail:Error->Void, response:Response):Void { - - if (!response.success || !response.result.success || response.result.data.session.expired) { - - initialSessionFail(onFail, response.success ? response.result.error : response.error); - } - } - - function initialSessionFail(onFail:Error->Void, error:Error):Void { - - sessionId = null; - - if (onFail != null) - onFail(error); - } - - /** - * Creates NG.core, the heart and soul of the API. This is not the only way to create an instance, - * nor is NG a forced singleton, but it's the only way to set the static NG.core. - **/ - static public function create(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void):Void { - - core = new NGLite(appId, sessionId, onSessionFail); - - onCoreReady.dispatch(); - } - - /** - * Creates NG.core, and tries to create a session. This is not the only way to create an instance, - * nor is NG a forced singleton, but it's the only way to set the static NG.core. - **/ - static public function createAndCheckSession - ( appId = "test" - , backupSession:String = null - , ?onSessionFail:Error->Void - ):Void { - - var session = getSessionId(); - if (session == null) - session = backupSession; - - create(appId, session, onSessionFail); - } - - inline static public function getUrl():String { - - #if html5 - return js.Browser.document.location.href; - #elseif flash - return flash.Lib.current.stage.loaderInfo != null - ? flash.Lib.current.stage.loaderInfo.url - : null; - #else - return null; - #end - } - - static public function getSessionId():String { - - #if html5 - - var url = getUrl(); - - // Check for URL params - var index = url.indexOf("?"); - if (index != -1) { - - // Check for session ID in params - for (param in url.substr(index + 1).split("&")) { - - index = param.indexOf("="); - if (index != -1 && param.substr(0, index) == "ngio_session_id") - return param.substr(index + 1); - } - } - - #elseif flash - - if (flash.Lib.current.stage.loaderInfo != null - && Reflect.hasField(flash.Lib.current.stage.loaderInfo.parameters, "ngio_session_id")) - return Reflect.field(flash.Lib.current.stage.loaderInfo.parameters, "ngio_session_id"); - - #end - - return null; - - // --- EXAMPLE LOADER PARAMS - //{ "1517703669" : "" - //, "ng_username" : "GeoKureli" - //, "NewgroundsAPI_SessionID" : "F1LusbG6P8Qf91w7zeUE37c1752563f366688ac6153996d12eeb111a2f60w2xn" - //, "NewgroundsAPI_PublisherID" : 1 - //, "NewgroundsAPI_UserID" : 488329 - //, "NewgroundsAPI_SandboxID" : "5a76520e4ae1e" - //, "ngio_session_id" : "0c6c4e02567a5116734ba1a0cd841dac28a42e79302290" - //, "NewgroundsAPI_UserName" : "GeoKureli" - //} - } - - // ------------------------------------------------------------------------------------------- - // CALLS - // ------------------------------------------------------------------------------------------- - - var _queuedCalls:Array = new Array(); - var _pendingCalls:Array = new Array(); - - @:allow(io.newgrounds.Call) - @:generic - function queueCall(call:Call):Void { - - logVerbose('queued - ${call.component}'); - - _queuedCalls.push(call); - checkQueue(); - } - - @:allow(io.newgrounds.Call) - @:generic - function markCallPending(call:Call):Void { - - _pendingCalls.push(call); - - call.addDataHandler(function (_):Void { onCallComplete(call); }); - call.addErrorHandler(function (_):Void { onCallComplete(call); }); - } - - function onCallComplete(call:ICallable):Void { - - _pendingCalls.remove(call); - checkQueue(); - } - - function checkQueue():Void { - - if (_pendingCalls.length == 0 && _queuedCalls.length > 0) - _queuedCalls.shift().send(); - } - - // ------------------------------------------------------------------------------------------- - // LOGGING / ERRORS - // ------------------------------------------------------------------------------------------- - - /** Called internally, set this to your preferred logging method */ - dynamic public function log(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow - - haxe.Log.trace('[Newgrounds API] :: ${any}', pos); - } - - /** used internally, logs if verbose is true */ - inline public function logVerbose(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow - - if (verbose) - log(any, pos); - } - - /** Used internally. Logs by default, set this to your preferred error handling method */ - dynamic public function logError(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow - - log('Error: $any', pos); - } - - /** used internally, calls log error if the condition is false. EX: if (assert(data != null, "null data")) */ - inline public function assert(condition:Bool, msg:Dynamic, ?pos:PosInfos):Bool {//TODO: limit access via @:allow - if (!condition) - logError(msg, pos); - - return condition; - } - - // ------------------------------------------------------------------------------------------- - // ENCRYPTION - // ------------------------------------------------------------------------------------------- - - /** Sets */ - public function initEncryption - ( key :String - , cipher:Cipher = Cipher.RC4 - , format:EncryptionFormat = EncryptionFormat.BASE_64 - ):Void { - - if (cipher == Cipher.NONE) - encryptionHandler = null; - else if (cipher == Cipher.RC4) - encryptionHandler = encryptRc4.bind(key, format); - else - throw "aes not yet implemented"; - } - - function encryptRc4(key:String, format:EncryptionFormat, data:String):String { - - if (format == EncryptionFormat.HEX) - throw "hex format not yet implemented"; - - var keyBytes:Bytes; - if (format == EncryptionFormat.BASE_64) - keyBytes = Base64.decode(key); - else - keyBytes = null;//TODO - - var dataBytes = new Rc4(keyBytes).crypt(Bytes.ofString(data)); - - if (format == EncryptionFormat.BASE_64) - return Base64.encode(dataBytes); - - return null; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/components/AppComponent.hx b/source/io/newgrounds/components/AppComponent.hx deleted file mode 100644 index 1ea5b8b16..000000000 --- a/source/io/newgrounds/components/AppComponent.hx +++ /dev/null @@ -1,44 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.objects.events.Result; -import io.newgrounds.objects.events.Result.SessionResult; -import io.newgrounds.NGLite; - -class AppComponent extends Component { - - public function new (core:NGLite) { super(core); } - - public function startSession(force:Bool = false):Call { - - return new Call(_core, "App.startSession") - .addComponentParameter("force", force, false); - } - - public function checkSession():Call { - - return new Call(_core, "App.checkSession", true); - } - - public function endSession():Call { - - return new Call(_core, "App.endSession", true); - } - - public function getCurrentVersion(version:String):Call { - - return new Call(_core, "App.getCurrentVersion") - .addComponentParameter("version", version); - } - - public function getHostLicense():Call { - - return new Call(_core, "App.getHostLicense") - .addComponentParameter("host", _core.host); - } - - public function logView():Call { - - return new Call(_core, "App.logView") - .addComponentParameter("host", _core.host); - } -} \ No newline at end of file diff --git a/source/io/newgrounds/components/Component.hx b/source/io/newgrounds/components/Component.hx deleted file mode 100644 index 3c588ff19..000000000 --- a/source/io/newgrounds/components/Component.hx +++ /dev/null @@ -1,13 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.NGLite; - -class Component { - - var _core:NGLite; - - public function new(core:NGLite) { - - this._core = core; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/components/ComponentList.hx b/source/io/newgrounds/components/ComponentList.hx deleted file mode 100644 index 315abf4ed..000000000 --- a/source/io/newgrounds/components/ComponentList.hx +++ /dev/null @@ -1,25 +0,0 @@ -package io.newgrounds.components; -class ComponentList { - - var _core:NGLite; - - // --- COMPONENTS - public var medal : MedalComponent; - public var app : AppComponent; - public var event : EventComponent; - public var scoreBoard: ScoreBoardComponent; - public var loader : LoaderComponent; - public var gateway : GatewayComponent; - - public function new(core:NGLite) { - - _core = core; - - medal = new MedalComponent (_core); - app = new AppComponent (_core); - event = new EventComponent (_core); - scoreBoard = new ScoreBoardComponent(_core); - loader = new LoaderComponent (_core); - gateway = new GatewayComponent (_core); - } -} diff --git a/source/io/newgrounds/components/EventComponent.hx b/source/io/newgrounds/components/EventComponent.hx deleted file mode 100644 index 2e631773e..000000000 --- a/source/io/newgrounds/components/EventComponent.hx +++ /dev/null @@ -1,16 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.objects.events.Result.LogEventResult; -import io.newgrounds.NGLite; - -class EventComponent extends Component { - - public function new (core:NGLite){ super(core); } - - public function logEvent(eventName:String):Call { - - return new Call(_core, "Event.logEvent") - .addComponentParameter("event_name", eventName) - .addComponentParameter("host", _core.host); - } -} \ No newline at end of file diff --git a/source/io/newgrounds/components/GatewayComponent.hx b/source/io/newgrounds/components/GatewayComponent.hx deleted file mode 100644 index 4f0ece617..000000000 --- a/source/io/newgrounds/components/GatewayComponent.hx +++ /dev/null @@ -1,25 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.objects.events.Result; -import io.newgrounds.NGLite; - -class GatewayComponent extends Component { - - public function new (core:NGLite){ super(core); } - - public function getDatetime():Call { - - return new Call(_core, "Gateway.getDatetime"); - } - - public function getVersion():Call { - - return new Call(_core, "Gateway.getVersion"); - } - - public function ping():Call { - - return new Call(_core, "Gateway.ping"); - } - -} \ No newline at end of file diff --git a/source/io/newgrounds/components/LoaderComponent.hx b/source/io/newgrounds/components/LoaderComponent.hx deleted file mode 100644 index 717cc2eb2..000000000 --- a/source/io/newgrounds/components/LoaderComponent.hx +++ /dev/null @@ -1,44 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.objects.events.Result; -import io.newgrounds.NGLite; - -class LoaderComponent extends Component { - - public function new (core:NGLite){ super(core); } - - public function loadAuthorUrl(redirect:Bool = false):Call { - - return new Call(_core, "Loader.loadAuthorUrl") - .addComponentParameter("host", _core.host) - .addComponentParameter("redirect", redirect, true); - } - - public function loadMoreGames(redirect:Bool = false):Call { - - return new Call(_core, "Loader.loadMoreGames") - .addComponentParameter("host", _core.host) - .addComponentParameter("redirect", redirect, true); - } - - public function loadNewgrounds(redirect:Bool = false):Call { - - return new Call(_core, "Loader.loadNewgrounds") - .addComponentParameter("host", _core.host) - .addComponentParameter("redirect", redirect, true); - } - - public function loadOfficialUrl(redirect:Bool = false):Call { - - return new Call(_core, "Loader.loadOfficialUrl") - .addComponentParameter("host", _core.host) - .addComponentParameter("redirect", redirect, true); - } - - public function loadReferral(redirect:Bool = false):Call { - - return new Call(_core, "Loader.loadReferral") - .addComponentParameter("host", _core.host) - .addComponentParameter("redirect", redirect, true); - } -} \ No newline at end of file diff --git a/source/io/newgrounds/components/MedalComponent.hx b/source/io/newgrounds/components/MedalComponent.hx deleted file mode 100644 index 7e56621c4..000000000 --- a/source/io/newgrounds/components/MedalComponent.hx +++ /dev/null @@ -1,21 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.objects.events.Result; -import io.newgrounds.Call; -import io.newgrounds.NGLite; - -class MedalComponent extends Component { - - public function new(core:NGLite):Void { super(core); } - - public function unlock(id:Int):Call { - - return new Call(_core, "Medal.unlock", true, true) - .addComponentParameter("id", id); - } - - public function getList():Call { - - return new Call(_core, "Medal.getList"); - } -} \ No newline at end of file diff --git a/source/io/newgrounds/components/ScoreBoardComponent.hx b/source/io/newgrounds/components/ScoreBoardComponent.hx deleted file mode 100644 index 7417e67c6..000000000 --- a/source/io/newgrounds/components/ScoreBoardComponent.hx +++ /dev/null @@ -1,114 +0,0 @@ -package io.newgrounds.components; - -import io.newgrounds.objects.User; -import io.newgrounds.objects.events.Response; -import io.newgrounds.objects.events.Result; -import io.newgrounds.objects.events.Result.ScoreBoardResult; -import io.newgrounds.objects.events.Result.ScoreResult; -import io.newgrounds.NGLite; -import io.newgrounds.objects.ScoreBoard; - -import haxe.ds.IntMap; - -class ScoreBoardComponent extends Component { - - public var allById:IntMap; - - public function new (core:NGLite){ super(core); } - - // ------------------------------------------------------------------------------------------- - // GET SCORES - // ------------------------------------------------------------------------------------------- - - public function getBoards():Call { - - return new Call(_core, "ScoreBoard.getBoards"); - } - - /*function onBoardsReceive(response:Response):Void { - - if (!response.result.success) - return; - - allById = new IntMap(); - - for (boardData in response.result.scoreboards) - createBoard(boardData); - - _core.log('${response.result.scoreboards.length} ScoreBoards loaded'); - }*/ - - // ------------------------------------------------------------------------------------------- - // GET SCORES - // ------------------------------------------------------------------------------------------- - - public function getScores - ( id :Int - , limit :Int = 10 - , skip :Int = 0 - , period:Period = Period.DAY - , social:Bool = false - , tag :String = null - , user :Dynamic = null - ):Call { - - if (user != null && !Std.is(user, String) && !Std.is(user, Int)) - user = user.id; - - return new Call(_core, "ScoreBoard.getScores") - .addComponentParameter("id" , id ) - .addComponentParameter("limit" , limit , 10) - .addComponentParameter("skip" , skip , 0) - .addComponentParameter("period", period, Period.DAY) - .addComponentParameter("social", social, false) - .addComponentParameter("tag" , tag , null) - .addComponentParameter("user" , user , null); - } - - // ------------------------------------------------------------------------------------------- - // POST SCORE - // ------------------------------------------------------------------------------------------- - - public function postScore(id:Int, value:Int, tag:String = null):Call { - - return new Call(_core, "ScoreBoard.postScore", true, true) - .addComponentParameter("id" , id) - .addComponentParameter("value", value) - .addComponentParameter("tag" , tag , null); - } - - /*function onScorePosted(response:Response):Void { - - if (!response.result.success) - return; - - allById = new IntMap(); - - //createBoard(data.data.scoreBoard).parseScores(data.data.scores); - }*/ - - inline function createBoard(data:Dynamic):ScoreBoard { - - var board = new ScoreBoard(_core, data); - _core.logVerbose('created $board'); - - allById.set(board.id, board); - - return board; - } -} - -@:enum -abstract Period(String) to String from String{ - - /** Indicates scores are from the current day. */ - var DAY = "D"; - /** Indicates scores are from the current week. */ - var WEEK = "W"; - /** Indicates scores are from the current month. */ - var MONTH = "M"; - /** Indicates scores are from the current year. */ - var YEAR = "Y"; - /** Indicates scores are from all-time. */ - var ALL = "A"; -} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/Cipher.hx b/source/io/newgrounds/crypto/Cipher.hx deleted file mode 100644 index 2f4c00753..000000000 --- a/source/io/newgrounds/crypto/Cipher.hx +++ /dev/null @@ -1,8 +0,0 @@ -package io.newgrounds.crypto; - -@:enum -abstract Cipher(String) to String{ - var NONE = "none"; - var AES_128 = "aes128"; - var RC4 = "rc4"; -} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/EncryptionFormat.hx b/source/io/newgrounds/crypto/EncryptionFormat.hx deleted file mode 100644 index 6e8f17fd6..000000000 --- a/source/io/newgrounds/crypto/EncryptionFormat.hx +++ /dev/null @@ -1,7 +0,0 @@ -package io.newgrounds.crypto; - -@:enum -abstract EncryptionFormat(String) to String { - var BASE_64 = "base64"; - var HEX = "hex"; -} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/Rc4.hx b/source/io/newgrounds/crypto/Rc4.hx deleted file mode 100644 index 54dafa74b..000000000 --- a/source/io/newgrounds/crypto/Rc4.hx +++ /dev/null @@ -1,68 +0,0 @@ -package io.newgrounds.crypto; - -import haxe.io.Bytes; - -/** - * The following was straight-up ganked from https://github.com/iskolbin/rc4hx - * - * You da real MVP iskolbin... - * - * The MIT License (MIT) - * - * Copyright (c) 2015 iskolbin - * - * 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. -**/ -class Rc4 { - var perm = Bytes.alloc( 256 ); - var index1: Int = 0; - var index2: Int = 0; - - public function new( key: Bytes ) { - for ( i in 0...256 ) { - perm.set( i, i ); - } - - var j: Int = 0; - for ( i in 0...256 ) { - j = ( j + perm.get( i ) + key.get( i % key.length )) % 256; - swap( i, j ); - } - } - - inline function swap( i: Int, j: Int ): Void { - var temp = perm.get( i ); - perm.set( i, perm.get( j )); - perm.set( j, temp ); - } - - public function crypt( input: Bytes ): Bytes { - var output = Bytes.alloc( input.length ); - - for ( i in 0...input.length ) { - index1 = ( index1 + 1 ) % 256; - index2 = ( index2 + perm.get( index1 )) % 256; - swap( index1, index2 ); - var j = ( perm.get( index1 ) + perm.get( index2 )) % 256; - output.set( i, input.get( i ) ^ perm.get( j )); - } - - return output; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Error.hx b/source/io/newgrounds/objects/Error.hx deleted file mode 100644 index 6e82e4e2e..000000000 --- a/source/io/newgrounds/objects/Error.hx +++ /dev/null @@ -1,20 +0,0 @@ -package io.newgrounds.objects; -class Error { - - public var code(default, null):Int; - public var message(default, null):String; - - public function new (message:String, code:Int = 0) { - - this.message = message; - this.code = code; - } - - public function toString():String { - - if (code > 0) - return '#$code - $message'; - - return message; - } -} diff --git a/source/io/newgrounds/objects/Medal.hx b/source/io/newgrounds/objects/Medal.hx deleted file mode 100644 index 3cecc7a6b..000000000 --- a/source/io/newgrounds/objects/Medal.hx +++ /dev/null @@ -1,118 +0,0 @@ -package io.newgrounds.objects; - -import io.newgrounds.objects.events.Response; -import io.newgrounds.objects.events.Result.MedalUnlockResult; -import io.newgrounds.utils.Dispatcher; -import io.newgrounds.NGLite; - -class Medal extends Object { - - inline static public var EASY :Int = 1; - inline static public var MODERATE :Int = 2; - inline static public var CHALLENGING:Int = 3; - inline static public var DIFFICULT :Int = 4; - inline static public var BRUTAL :Int = 5; - - static var difficultyNames:Array = - [ "Easy" - , "Moderate" - , "Challenging" - , "Difficult" - , "Brutal" - ]; - // --- FROM SERVER - public var id (default, null):Int; - public var name (default, null):String; - public var description(default, null):String; - public var icon (default, null):String; - public var value (default, null):Int; - public var difficulty (default, null):Int; - public var secret (default, null):Bool; - public var unlocked (default, null):Bool; - // --- HELPERS - public var difficultyName(get, never):String; - - public var onUnlock:Dispatcher; - - public function new(core:NGLite, data:Dynamic = null):Void { - - onUnlock = new Dispatcher(); - - super(core, data); - } - - @:allow(io.newgrounds.NG) - override function parse(data:Dynamic):Void { - - var wasLocked = !unlocked; - - id = data.id; - name = data.name; - description = data.description; - icon = data.icon; - value = data.value; - difficulty = data.difficulty; - secret = data.secret == 1; - unlocked = data.unlocked; - - super.parse(data); - - if (wasLocked && unlocked) - onUnlock.dispatch(); - - } - - public function sendUnlock():Void { - - if (_core.sessionId == null) { - // --- Unlock regardless, show medal popup to encourage NG signup - unlocked = true; - onUnlock.dispatch(); - //TODO: save unlock in local save - } - - _core.calls.medal.unlock(id) - .addDataHandler(onUnlockResponse) - .send(); - } - - function onUnlockResponse(response:Response):Void { - - if (response.success && response.result.success) { - - parse(response.result.data.medal); - - // --- Unlock response doesn't include unlock=true, so parse won't change it. - if (!unlocked) { - - unlocked = true; - onUnlock.dispatch(); - } - } - } - - /** Locks the medal on the client and sends an unlock request, Server responds the same either way. */ - public function sendDebugUnlock():Void { - - if (NG.core.sessionId == null) { - - onUnlock.dispatch(); - - } else { - - unlocked = false; - - sendUnlock(); - } - } - - public function get_difficultyName():String { - - return difficultyNames[difficulty - 1]; - } - - public function toString():String { - - return 'Medal: $id@$name (${unlocked ? "unlocked" : "locked"}, $value pts, $difficultyName).'; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Object.hx b/source/io/newgrounds/objects/Object.hx deleted file mode 100644 index 32abd0fe5..000000000 --- a/source/io/newgrounds/objects/Object.hx +++ /dev/null @@ -1,33 +0,0 @@ -package io.newgrounds.objects; - -import io.newgrounds.utils.Dispatcher; -import io.newgrounds.NGLite; - -class Object { - - var _core:NGLite; - - public var onUpdate(default, null):Dispatcher; - - public function new(core:NGLite, data:Dynamic = null) { - - this._core = core; - - onUpdate = new Dispatcher(); - - if (data != null) - parse(data); - } - - @:allow(io.newgrounds.NGLite) - function parse(data:Dynamic):Void { - - onUpdate.dispatch(); - } - - - public function destroy():Void { - - _core = null; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Score.hx b/source/io/newgrounds/objects/Score.hx deleted file mode 100644 index 0eb698267..000000000 --- a/source/io/newgrounds/objects/Score.hx +++ /dev/null @@ -1,17 +0,0 @@ -package io.newgrounds.objects; - -/** We don't want to serialize scores since there's a bajillion of them. */ -typedef Score = { - - /** The value value in the format selected in your scoreboard settings. */ - var formatted_value:String; - - /** The tag attached to this value (if any). */ - var tag:String; - - /** The user who earned value. If this property is absent, the value belongs to the active user. */ - var user:User; - - /** The integer value of the value. */ - var value:Int; -} \ No newline at end of file diff --git a/source/io/newgrounds/objects/ScoreBoard.hx b/source/io/newgrounds/objects/ScoreBoard.hx deleted file mode 100644 index 1859b0808..000000000 --- a/source/io/newgrounds/objects/ScoreBoard.hx +++ /dev/null @@ -1,76 +0,0 @@ -package io.newgrounds.objects; - -import io.newgrounds.components.ScoreBoardComponent.Period; -import io.newgrounds.objects.events.Response; -import io.newgrounds.objects.events.Result; -import io.newgrounds.objects.events.Result.ScoreResult; -import io.newgrounds.NGLite; - -class ScoreBoard extends Object { - - public var scores(default, null):Array; - - /** The numeric ID of the scoreboard.*/ - public var id(default, null):Int; - - /** The name of the scoreboard. */ - public var name(default, null):String; - - public function new(core:NGLite, data:Dynamic):Void {super(core, data); } - - override function parse(data:Dynamic):Void { - - id = data.id; - name = data.name; - - super.parse(data); - } - - /** - * Fetches score data from the server, this removes all of the existing scores cached - * - * We don't unify the old and new scores because a user's rank or score may change between requests - */ - public function requestScores - ( limit :Int = 10 - , skip :Int = 0 - , period:Period = Period.ALL - , social:Bool = false - , tag :String = null - , user :Dynamic = null - ):Void { - - _core.calls.scoreBoard.getScores(id, limit, skip, period, social, tag, user) - .addDataHandler(onScoresReceived) - .send(); - } - - function onScoresReceived(response:Response):Void { - - if (!response.success || !response.result.success) - return; - - scores = response.result.data.scores; - _core.logVerbose('received ${scores.length} scores'); - - onUpdate.dispatch(); - } - - public function postScore(value :Int, tag:String = null):Void { - - _core.calls.scoreBoard.postScore(id, value, tag) - .addDataHandler(onScorePosted) - .send(); - } - - function onScorePosted(response:Response):Void { - - - } - - public function toString():String { - - return 'ScoreBoard: $id@$name'; - } - -} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Session.hx b/source/io/newgrounds/objects/Session.hx deleted file mode 100644 index 887df7927..000000000 --- a/source/io/newgrounds/objects/Session.hx +++ /dev/null @@ -1,65 +0,0 @@ -package io.newgrounds.objects; - -class Session extends Object { - - /** If true, the session_id is expired. Use App.startSession to get a new one.*/ - public var expired(default, null):Bool; - - /** A unique session identifier */ - public var id(default, null):String; - - /** If the session has no associated user but is not expired, this property will provide a URL that can be used to sign the user in. */ - public var passportUrl(default, null):String; - - /** If true, the user would like you to remember their session id. */ - public var remember(default, null):Bool; - - /** If the user has not signed in, or granted access to your app, this will be null */ - public var user(default, null):User; - - //TODO:desciption - public var status(get, never):SessionStatus; - - public function new(core:NGLite, data:Dynamic = null) { super(core, data); } - - override public function parse(data:Dynamic):Void { - - id = data.id; - expired = data.expired; - passportUrl = data.passport_url; - remember = data.remember; - - // --- KEEP THE SAME INSTANCE - if (user == null) - user = data.user; - // TODO?: update original user instance with new data. (probly not) - - super.parse(data); - } - - public function get_status():SessionStatus { - - if (expired || id == null || id == "") - return SessionStatus.SESSION_EXPIRED; - - if (user != null && user.name != null && user.name != "") - return SessionStatus.USER_LOADED; - - return SessionStatus.REQUEST_LOGIN; - } - - public function expire():Void { - - expired = true; - id = null; - user = null; - } -} - -@:enum -abstract SessionStatus(String) { - - var SESSION_EXPIRED = "session-expired"; - var REQUEST_LOGIN = "request-login"; - var USER_LOADED = "user-loaded"; -} \ No newline at end of file diff --git a/source/io/newgrounds/objects/User.hx b/source/io/newgrounds/objects/User.hx deleted file mode 100644 index 1ff7ce00c..000000000 --- a/source/io/newgrounds/objects/User.hx +++ /dev/null @@ -1,19 +0,0 @@ -package io.newgrounds.objects; - -typedef User = { - - /** The user's icon images. */ - var icons:UserIcons; - - /** The user's numeric ID. */ - var id:Int; - - /** The user's textual name. */ - var name:String; - - /** Returns true if the user has a Newgrounds Supporter upgrade. */ - var supporter:Bool; - - /** The user's NG profile url. */ - var url:String; -} diff --git a/source/io/newgrounds/objects/UserIcons.hx b/source/io/newgrounds/objects/UserIcons.hx deleted file mode 100644 index b5e56b22a..000000000 --- a/source/io/newgrounds/objects/UserIcons.hx +++ /dev/null @@ -1,14 +0,0 @@ -package io.newgrounds.objects; - -typedef UserIcons = { - - /**The URL of the user's large icon. */ - var large:String; - - /** The URL of the user's medium icon. */ - var medium:String; - - /** The URL of the user's small icon. */ - var small:String; -} - diff --git a/source/io/newgrounds/objects/events/Response.hx b/source/io/newgrounds/objects/events/Response.hx deleted file mode 100644 index 107dc2be3..000000000 --- a/source/io/newgrounds/objects/events/Response.hx +++ /dev/null @@ -1,43 +0,0 @@ -package io.newgrounds.objects.events; - -import io.newgrounds.objects.events.Result.ResultBase; -import haxe.Json; -import io.newgrounds.objects.Error; - -typedef DebugResponse = { - - var exec_time:Int; - var input:Dynamic; -} - -class Response { - - public var success(default, null):Bool; - public var error(default, null):Error; - public var debug(default, null):DebugResponse; - public var result(default, null):Result; - - public function new (core:NGLite, reply:String) { - - var data:Dynamic; - - try { - data = Json.parse(reply); - - } catch (e:Dynamic) { - - data = Json.parse('{"success":false,"error":{"message":"${Std.string(reply)}","code":0}}'); - } - - success = data.success; - debug = data.debug; - - if (!success) { - error = new Error(data.error.message, data.error.code); - core.logError('Call unseccessful: $error'); - return; - } - - result = new Result(core, data.result); - } -} diff --git a/source/io/newgrounds/objects/events/Result.hx b/source/io/newgrounds/objects/events/Result.hx deleted file mode 100644 index eaf872616..000000000 --- a/source/io/newgrounds/objects/events/Result.hx +++ /dev/null @@ -1,109 +0,0 @@ -package io.newgrounds.objects.events; - -class Result { - - public var echo(default, null):String; - public var component(default, null):String; - - public var data(default, null):T; - public var success(default, null):Bool; - public var debug(default, null):Bool; - public var error(default, null):Error; - - public function new(core:NGLite, data:Dynamic) { - - echo = data.echo; - component = data.component; - - data = data.data; - success = data.success; - debug = data.debug; - - if(!data.success) { - - error = new Error(data.error.message, data.error.code); - core.logError('$component fail: $error'); - - } else - this.data = data; - } -} - -typedef ResultBase = { }; - -typedef SessionResult = { - > ResultBase, - - var session:Dynamic; -} - -typedef GetHostResult = { - > ResultBase, - - var host_approved:Bool; -} - -typedef GetCurrentVersionResult = { - > ResultBase, - - var current_version:String; - var client_deprecated:Bool; -} - -typedef LogEventResult = { - > ResultBase, - - var event_name:String; -} - -typedef GetDateTimeResult = { - > ResultBase, - - var datetime:String; -} - -typedef GetVersionResult = { - > ResultBase, - - var version:String; -} - -typedef PingResult = { - > ResultBase, - - var pong:String; -} - -typedef MedalListResult = { - > ResultBase, - - var medals:Array; -} - -typedef MedalUnlockResult = { - > ResultBase, - - var medal_score:String; - var medal:Dynamic; -} - -typedef ScoreBoardResult = { - > ResultBase, - - var scoreboards:Array; -} - -typedef ScoreResult = { - > ResultBase, - - var scores:Array; - var scoreboard:Dynamic; -} - -typedef PostScoreResult = { - > ResultBase, - - var tag:String; - var scoreboard:Dynamic; - var score:Score; -} \ No newline at end of file diff --git a/source/io/newgrounds/swf/LoadingBar.hx b/source/io/newgrounds/swf/LoadingBar.hx deleted file mode 100644 index 9c7c590a8..000000000 --- a/source/io/newgrounds/swf/LoadingBar.hx +++ /dev/null @@ -1,23 +0,0 @@ -package io.newgrounds.swf; - -import openfl.display.MovieClip; - -class LoadingBar extends MovieClip { - - public var bar(default, null):MovieClip; - - public function new() { - super(); - - setProgress(0.0); - } - - /** - * - * @param value The ratio of bytes loaded to bytes total - */ - public function setProgress(value:Float):Void { - - bar.gotoAndStop(1 + Std.int(value * (bar.totalFrames - 1))); - } -} diff --git a/source/io/newgrounds/swf/MedalPopup.hx b/source/io/newgrounds/swf/MedalPopup.hx deleted file mode 100644 index f55ef4266..000000000 --- a/source/io/newgrounds/swf/MedalPopup.hx +++ /dev/null @@ -1,151 +0,0 @@ -package io.newgrounds.swf; - -import io.newgrounds.swf.common.BaseAsset; -import io.newgrounds.objects.Medal; - -import openfl.text.TextFieldAutoSize; -import openfl.text.TextField; -import openfl.display.DisplayObject; -import openfl.display.Loader; -import openfl.display.MovieClip; -import openfl.net.URLRequest; -import openfl.events.Event; - -class MedalPopup extends BaseAsset { - - static inline var FRAME_HIDDEN:String = "hidden"; - static inline var FRAME_MEDAL_UNLOCKED:String = "medalUnlocked"; - static inline var FRAME_INTRO_COMPLETE:String = "introComplete"; - static inline var FRAME_UNLOCK_COMPLETE:String = "unlockComplete"; - static inline var MIN_TEXT_SIZE:Int = 12; - - public var medalIcon(default, null):MovieClip; - public var medalName(default, null):MovieClip; - public var medalPoints(default, null):MovieClip; - - public var alwaysOnTop:Bool; - #if !ng_lite - public var requiresSession:Bool; - #end - - var _animQueue = new ArrayVoid>(); - var _scrollSpeed:Float; - - public function new() { - super(); - - mouseEnabled = false; - mouseChildren = false; - - hide(); - addFrameScript(totalFrames - 1, onUnlockAnimComplete); - } - - function hide():Void { - - visible = false; - gotoAndStop(FRAME_HIDDEN); - } - - #if !ng_lite - override function onReady():Void { - super.onReady(); - - if (NG.core.medals != null) - onMedalsLoaded(); - else - NG.core.onLogin.addOnce(NG.core.requestMedals.bind(onMedalsLoaded)); - } - - function onMedalsLoaded():Void { - - for (medal in NG.core.medals) - medal.onUnlock.add(onMedalOnlock.bind(medal)); - } - - function onMedalOnlock(medal:Medal):Void { - - if (requiresSession && !NG.core.loggedIn) - return; - - var loader = new Loader(); - loader.load(new URLRequest(medal.icon)); - - playAnim(loader, medal.name, medal.value); - } - - #end - - public function playAnim(icon:DisplayObject, name:String, value:Int):Void { - - if (currentLabel == FRAME_HIDDEN) - playNextAnim(icon, name, value); - else - _animQueue.push(playNextAnim.bind(icon, name, value)); - } - - function playNextAnim(icon:DisplayObject, name:String, value:Int):Void { - - visible = true; - gotoAndPlay(FRAME_MEDAL_UNLOCKED); - - if (alwaysOnTop && parent != null) { - - parent.setChildIndex(this, parent.numChildren - 1); - } - - while(medalIcon.numChildren > 0) - medalIcon.removeChildAt(0); - - cast(medalPoints.getChildByName("field"), TextField).text = Std.string(value); - - var field:TextField = cast medalName.getChildByName("field"); - field.autoSize = TextFieldAutoSize.LEFT; - field.x = 0; - field.text = ""; - var oldWidth = medalName.width; - field.text = name; - - _scrollSpeed = 0; - if (field.width > oldWidth + 4) { - - field.x = oldWidth + 4; - initScroll(field); - } - - medalIcon.addChild(icon); - } - - function initScroll(field:TextField):Void { - //TODO: Find out why scrollrect didn't work - - var animDuration = 0; - - for (frame in currentLabels){ - - if (frame.name == FRAME_INTRO_COMPLETE ) - animDuration -= frame.frame; - else if (frame.name == FRAME_UNLOCK_COMPLETE) - animDuration += frame.frame; - } - - _scrollSpeed = (field.width + field.x + 4) / animDuration; - field.addEventListener(Event.ENTER_FRAME, updateScroll); - } - - function updateScroll(e:Event):Void{ - - if (currentLabel == FRAME_INTRO_COMPLETE) - cast (e.currentTarget, TextField).x -= _scrollSpeed; - } - - function onUnlockAnimComplete():Void { - - cast (medalName.getChildByName("field"), TextField).removeEventListener(Event.ENTER_FRAME, updateScroll); - - if (_animQueue.length == 0) - hide(); - else - (_animQueue.shift())(); - } -} diff --git a/source/io/newgrounds/swf/ScoreBrowser.hx b/source/io/newgrounds/swf/ScoreBrowser.hx deleted file mode 100644 index c4232c22b..000000000 --- a/source/io/newgrounds/swf/ScoreBrowser.hx +++ /dev/null @@ -1,250 +0,0 @@ -package io.newgrounds.swf; - -import openfl.events.Event; -import io.newgrounds.swf.common.DropDown; -import io.newgrounds.objects.Score; -import io.newgrounds.objects.events.Result.ScoreBoardResult; -import io.newgrounds.objects.events.Result.ScoreResult; -import io.newgrounds.objects.events.Response; -import io.newgrounds.swf.common.BaseAsset; -import io.newgrounds.swf.common.Button; -import io.newgrounds.components.ScoreBoardComponent.Period; - -import openfl.display.MovieClip; -import openfl.text.TextField; - -class ScoreBrowser extends BaseAsset { - - public var prevButton (default, null):MovieClip; - public var nextButton (default, null):MovieClip; - public var reloadButton (default, null):MovieClip; - public var listBox (default, null):MovieClip; - public var loadingIcon (default, null):MovieClip; - public var errorIcon (default, null):MovieClip; - public var scoreContainer(default, null):MovieClip; - public var titleField (default, null):TextField; - public var pageField (default, null):TextField; - - public var period(get, set):Period; - function get_period():Period { return _periodDropDown.value; } - function set_period(value:Period):Period { return _periodDropDown.value = value; } - - public var title(get, set):String; - function get_title():String { return titleField.text; } - function set_title(value:String):String { return titleField.text = value; } - - public var tag(default, set):String; - function set_tag(value:String):String { - - if (this.tag != value) { - - this.tag = value; - delayReload(); - } - - return value; - } - - public var social(default, set):Bool; - function set_social(value:Bool):Bool { - - if (this.social != value) { - - this.social = value; - delayReload(); - } - - return value; - } - - public var boardId(default, set):Int; - function set_boardId(value:Int):Int { - - _boardIDSet = true; - - if (this.boardId != value) { - - this.boardId = value; - delayReload(); - } - - return value; - } - - public var page(default, set):Int; - function set_page(value:Int):Int { - - if (this.page != value) { - - this.page = value; - delayReload(); - } - - return value; - } - - var _scores:Array; - var _limit:Int = 0; - var _periodDropDown:DropDown; - var _boardIDSet:Bool; - - public function new() { super(); } - - override function setDefaults():Void { - super.setDefaults(); - - boardId = -1; - _boardIDSet = false; - - scoreContainer.visible = false; - loadingIcon.visible = false; - reloadButton.visible = false; - errorIcon.visible = false; - errorIcon.addFrameScript(errorIcon.totalFrames - 1, errorIcon.stop); - - //TODO: prevent memory leaks? - new Button(prevButton, onPrevClick); - new Button(nextButton, onNextClick); - new Button(reloadButton, reload); - _periodDropDown = new DropDown(listBox, delayReload); - _periodDropDown.addItem("Current day" , Period.DAY ); - _periodDropDown.addItem("Current week" , Period.WEEK ); - _periodDropDown.addItem("Current month", Period.MONTH); - _periodDropDown.addItem("Current year" , Period.YEAR ); - _periodDropDown.addItem("All time" , Period.ALL ); - _periodDropDown.value = Period.ALL; - - _scores = new Array(); - while(true) { - - var score:MovieClip = cast scoreContainer.getChildByName('score${_scores.length}'); - if (score == null) - break; - - new Button(score); - _scores.push(score); - } - - _limit = _scores.length; - } - - override function onReady():Void { - super.onReady(); - - if (boardId == -1 && !_boardIDSet) { - - #if ng_lite - NG.core.calls.scoreBoard.getBoards() - .addDataHandler(onBoardsRecieved) - .queue(); - #else - if (NG.core.scoreBoards != null) - onBoardsLoaded(); - else - NG.core.requestScoreBoards(onBoardsLoaded); - #end - } - - reload(); - } - - #if ng_lite - function onBoardsRecieved(response:Response):Void { - - if (response.success && response.result.success) { - - for (board in response.result.data.scoreboards) { - - NG.core.log('No boardId specified defaulting to ${board.name}'); - boardId = board.id; - return; - } - } - } - #else - function onBoardsLoaded():Void { - - for (board in NG.core.scoreBoards) { - - NG.core.log('No boardId specified defaulting to ${board.name}'); - boardId = board.id; - return; - } - } - #end - - /** Used internally to avoid multiple server requests from various property changes in a small time-frame. **/ - function delayReload():Void { - - addEventListener(Event.EXIT_FRAME, onDelayComplete); - } - - function onDelayComplete(e:Event):Void { reload(); } - - public function reload():Void { - removeEventListener(Event.EXIT_FRAME, onDelayComplete); - - errorIcon.visible = false; - scoreContainer.visible = false; - pageField.text = 'page ${page + 1}'; - - if (_coreReady && boardId != -1 && _limit > 0 && period != null) { - - loadingIcon.visible = true; - - NG.core.calls.scoreBoard.getScores(boardId, _limit, _limit * page, period, social, tag) - .addDataHandler(onScoresReceive) - .send(); - } - } - - function onScoresReceive(response:Response):Void { - - loadingIcon.visible = false; - - if (response.success && response.result.success) { - - scoreContainer.visible = true; - - var i = _limit; - while(i > 0) { - i--; - - if (i < response.result.data.scores.length) - drawScore(i, response.result.data.scores[i], _scores[i]); - else - drawScore(i, null, _scores[i]); - } - - } else { - - errorIcon.visible = true; - errorIcon.gotoAndPlay(1); - reloadButton.visible = true; - } - } - - inline function drawScore(rank:Int, score:Score, asset:MovieClip):Void { - - if (score == null) - asset.visible = false; - else { - - asset.visible = true; - cast (asset.getChildByName("nameField" ), TextField).text = score.user.name; - cast (asset.getChildByName("scoreField"), TextField).text = score.formatted_value; - cast (asset.getChildByName("rankField" ), TextField).text = Std.string(rank + 1); - } - } - - function onPrevClick():Void { - - if (page > 0) - page--; - } - - function onNextClick():Void { - - page++; - } -} diff --git a/source/io/newgrounds/swf/common/BaseAsset.hx b/source/io/newgrounds/swf/common/BaseAsset.hx deleted file mode 100644 index da1f6126f..000000000 --- a/source/io/newgrounds/swf/common/BaseAsset.hx +++ /dev/null @@ -1,35 +0,0 @@ -package io.newgrounds.swf.common; - -import openfl.events.Event; -import openfl.display.MovieClip; - -class BaseAsset extends MovieClip { - - var _coreReady:Bool = false; - - public function new() { - super(); - - setDefaults(); - - if (stage != null) - onAdded(null); - else - addEventListener(Event.ADDED_TO_STAGE, onAdded); - } - - function setDefaults():Void { } - - function onAdded(e:Event):Void { - - if (NG.core != null) - onReady(); - else - NG.onCoreReady.add(onReady); - } - - function onReady():Void { - - _coreReady = true; - } -} diff --git a/source/io/newgrounds/swf/common/Button.hx b/source/io/newgrounds/swf/common/Button.hx deleted file mode 100644 index 5f4617528..000000000 --- a/source/io/newgrounds/swf/common/Button.hx +++ /dev/null @@ -1,151 +0,0 @@ -package io.newgrounds.swf.common; - -import openfl.display.Stage; -import openfl.events.Event; -import openfl.events.MouseEvent; -import openfl.display.MovieClip; - -class Button { - - var _enabled:Bool; - public var enabled(get, set):Bool; - function get_enabled():Bool { return _enabled; } - function set_enabled(value:Bool):Bool { - - if (value != _enabled) { - - _enabled = value; - updateEnabled(); - } - - return value; - } - - public var onClick:Void->Void; - public var onOver:Void->Void; - public var onOut:Void->Void; - - var _target:MovieClip; - var _down:Bool; - var _over:Bool; - var _foundLabels:Array; - - public function new(target:MovieClip, onClick:Void->Void = null, onOver:Void->Void = null, onOut:Void->Void = null) { - - _target = target; - this.onClick = onClick; - this.onOver = onOver; - this.onOut = onOut; - - _foundLabels = new Array(); - for (label in _target.currentLabels) - _foundLabels.push(label.name); - - _target.stop(); - _target.addEventListener(Event.ADDED_TO_STAGE, onAdded); - if (target.stage != null) - onAdded(null); - - enabled = true; - } - - function onAdded(e:Event):Void { - - var stage = _target.stage; - stage.addEventListener(MouseEvent.MOUSE_UP, mouseHandler); - _target.addEventListener(MouseEvent.MOUSE_OVER, mouseHandler); - _target.addEventListener(MouseEvent.MOUSE_OUT, mouseHandler); - _target.addEventListener(MouseEvent.MOUSE_DOWN, mouseHandler); - _target.addEventListener(MouseEvent.CLICK, mouseHandler); - - function selfRemoveEvent(e:Event):Void { - - _target.removeEventListener(Event.REMOVED_FROM_STAGE, selfRemoveEvent); - onRemove(e, stage); - } - _target.addEventListener(Event.REMOVED_FROM_STAGE, selfRemoveEvent); - } - - function onRemove(e:Event, stage:Stage):Void { - - stage.removeEventListener(MouseEvent.MOUSE_UP, mouseHandler); - _target.removeEventListener(MouseEvent.MOUSE_OVER, mouseHandler); - _target.removeEventListener(MouseEvent.MOUSE_OUT, mouseHandler); - _target.removeEventListener(MouseEvent.MOUSE_DOWN, mouseHandler); - _target.removeEventListener(MouseEvent.CLICK, mouseHandler); - } - - function mouseHandler(event:MouseEvent):Void { - - switch(event.type) { - - case MouseEvent.MOUSE_OVER: - - _over = true; - - if (onOver != null) - onOver(); - - case MouseEvent.MOUSE_OUT: - - _over = false; - - if (onOut != null) - onOut(); - - case MouseEvent.MOUSE_DOWN: - - _down = true; - - case MouseEvent.MOUSE_UP: - - _down = false; - - case MouseEvent.CLICK: - - if (enabled && onClick != null) - onClick(); - } - updateState(); - } - - function updateEnabled():Void { - - updateState(); - - _target.useHandCursor = enabled; - _target.buttonMode = enabled; - } - - function updateState():Void { - - var state = determineState(); - - if (_target.currentLabel != state && _foundLabels.indexOf(state) != -1) - _target.gotoAndStop(state); - } - - function determineState():String { - - if (enabled) { - - if (_over) - return _down ? "down" : "over"; - - return "up"; - - } - return "disabled"; - } - - public function destroy():Void { - - _target.removeEventListener(Event.ADDED_TO_STAGE, onAdded); - - _target = null; - onClick = null; - onOver = null; - onOut = null; - _foundLabels = null; - } -} diff --git a/source/io/newgrounds/swf/common/DropDown.hx b/source/io/newgrounds/swf/common/DropDown.hx deleted file mode 100644 index a882cf39b..000000000 --- a/source/io/newgrounds/swf/common/DropDown.hx +++ /dev/null @@ -1,88 +0,0 @@ -package io.newgrounds.swf.common; - - -import haxe.ds.StringMap; - -import openfl.display.MovieClip; -import openfl.display.Sprite; -import openfl.text.TextField; - -class DropDown { - - public var value(default, set):String; - function set_value(v:String):String { - - if (this.value == v) - return v; - - this.value = v; - _selectedLabel.text = _values.get(v); - - if (_onChange != null) - _onChange(); - - return v; - } - - var _choiceContainer:Sprite; - var _selectedLabel:TextField; - var _onChange:Void->Void; - var _values:StringMap; - var _unusedChoices:Array; - - public function new(target:MovieClip, label:String = "", onChange:Void->Void = null) { - - _onChange = onChange; - - _selectedLabel = cast cast(target.getChildByName("currentItem"), MovieClip).getChildByName("label"); - _selectedLabel.text = label; - - _values = new StringMap(); - - new Button(cast target.getChildByName("button"), onClickExpand); - new Button(cast target.getChildByName("currentItem"), onClickExpand); - _choiceContainer = new Sprite(); - _choiceContainer.visible = false; - target.addChild(_choiceContainer); - - _unusedChoices = new Array(); - while(true) { - - var item:MovieClip = cast target.getChildByName('item${_unusedChoices.length}'); - if (item == null) - break; - - target.removeChild(item); - _unusedChoices.push(item); - } - } - - public function addItem(name:String, value:String):Void { - - _values.set(value, name); - - if (_unusedChoices.length == 0) { - - NG.core.logError('cannot create another dropBox item max=${_choiceContainer.numChildren}'); - return; - } - - var button = _unusedChoices.shift(); - cast(button.getChildByName("label"), TextField).text = name; - _choiceContainer.addChild(button); - - new Button(button, onChoiceClick.bind(value)); - } - - function onClickExpand():Void { - - _choiceContainer.visible = !_choiceContainer.visible; - } - - function onChoiceClick(name:String):Void { - - value = name; - - _choiceContainer.visible = false; - } -} \ No newline at end of file diff --git a/source/io/newgrounds/utils/AsyncHttp.hx b/source/io/newgrounds/utils/AsyncHttp.hx deleted file mode 100644 index 4fbe14388..000000000 --- a/source/io/newgrounds/utils/AsyncHttp.hx +++ /dev/null @@ -1,203 +0,0 @@ -package io.newgrounds.utils; - -import io.newgrounds.NGLite; - -import haxe.Http; -import haxe.Timer; - -#if neko -import neko.vm.Thread; -#elseif java -import java.vm.Thread; -#elseif cpp -import cpp.vm.Thread; -#end - -/** - * Uses Threading to turn hxcpp's synchronous http requests into asynchronous processes - * - * @author GeoKureli - */ -class AsyncHttp { - - inline static var PATH:String = "https://newgrounds.io/gateway_v3.php"; - - static public function send - ( core:NGLite - , data:String - , onData:String->Void - , onError:String->Void - , onStatus:Int->Void - ) { - - core.logVerbose('sending: $data'); - - #if (neko || java || cpp) - sendAsync(core, data, onData, onError, onStatus); - #else - sendSync(core, data, onData, onError, onStatus); - #end - } - - static function sendSync - ( core:NGLite - , data:String - , onData:String->Void - , onError:String->Void - , onStatus:Int->Void - ):Void { - - var http = new Http(PATH); - http.setParameter("input", data); - http.onData = onData; - http.onError = onError; - http.onStatus = onStatus; - // #if js http.async = async; #end - http.request(true); - } - - #if (neko || java || cpp) - static var _deadPool:Array = []; - static var _livePool:Array = []; - static var _map:Map = new Map(); - static var _timer:Timer; - - static var _count:Int = 0; - - var _core:NGLite; - var _key:Int; - var _onData:String->Void; - var _onError:String->Void; - var _onStatus:Int->Void; - var _worker:Thread; - - public function new (core:NGLite) { - - _core = core; - _worker = Thread.create(sendThreaded); - _key = _count++; - _map[_key] = this; - _core.logVerbose('async http created: $_key'); - } - - function start(data:String, onData:String->Void, onError:String->Void, onStatus:Int->Void) { - - _core.logVerbose('async http started: $_key'); - - if (_livePool.length == 0) - startTimer(); - - _deadPool.remove(this); - _livePool.push(this); - - _onData = onData; - _onError = onError; - _onStatus = onStatus; - _worker.sendMessage({ source:Thread.current(), args:data, key:_key, core:_core }); - } - - function handleMessage(data:ReplyData):Void { - - _core.logVerbose('handling message: $_key'); - - if (data.status != null) { - - _core.logVerbose('\t- status: ${data.status}'); - _onStatus(cast data.status); - return; - } - - var tempFunc:Void->Void; - if (data.data != null) { - - _core.logVerbose('\t- data'); - tempFunc = _onData.bind(data.data); - - } else { - - _core.logVerbose('\t- error'); - tempFunc = _onError.bind(data.error); - } - - cleanUp(); - // Delay the call until destroy so that we're more likely to use a single - // thread on daisy-chained calls - tempFunc(); - } - - inline function cleanUp():Void { - - _onData = null; - _onError = null; - - _deadPool.push(this); - _livePool.remove(this); - - if (_livePool.length == 0) - stopTimer(); - } - - static function sendAsync - ( core:NGLite - , data:String - , onData:String->Void - , onError:String->Void - , onStatus:Int->Void - ):Void { - - var http:AsyncHttp; - if (_deadPool.length == 0) - http = new AsyncHttp(core); - else - http = _deadPool[0]; - - http.start(data, onData, onError, onStatus); - } - - static function startTimer():Void { - - if (_timer != null) - return; - - _timer = new Timer(1000 / 60.0); - _timer.run = update; - } - - static function stopTimer():Void { - - _timer.stop(); - _timer = null; - } - - static public function update():Void { - - var message:ReplyData = cast Thread.readMessage(false); - if (message != null) - _map[message.key].handleMessage(message); - } - - static function sendThreaded():Void { - - while(true) { - - var data:LoaderData = cast Thread.readMessage(true); - data.core.logVerbose('start message received: ${data.key}'); - - sendSync - ( data.core - , data.args - , function(reply ) { data.source.sendMessage({ key:data.key, data :reply }); } - , function(error ) { data.source.sendMessage({ key:data.key, error :error }); } - , function(status) { data.source.sendMessage({ key:data.key, status:status }); } - ); - } - } - - #end -} - - -#if (neko || java || cpp) -typedef LoaderData = { source:Thread, key:Int, args:String, core:NGLite }; -typedef ReplyData = { key:Int, ?data:String, ?error:String, ?status:Null }; -#end \ No newline at end of file diff --git a/source/io/newgrounds/utils/Dispatcher.hx b/source/io/newgrounds/utils/Dispatcher.hx deleted file mode 100644 index 699da01da..000000000 --- a/source/io/newgrounds/utils/Dispatcher.hx +++ /dev/null @@ -1,118 +0,0 @@ -package io.newgrounds.utils; - -/** - * Basically shitty signals, but I didn't want to have external references. -**/ -class Dispatcher { - - var _list:ArrayVoid>; - var _once:ArrayVoid>; - - public function new() { - - _list = new ArrayVoid>(); - _once = new ArrayVoid>(); - } - - public function add(handler:Void->Void, once:Bool = false):Bool { - - if (_list.indexOf(handler) != -1) { - - // ---- REMOVE ONCE - if (!once && _once.indexOf(handler) != -1) - _once.remove(handler); - - return false; - } - - _list.unshift(handler); - if (once) - _once.unshift(handler); - - return true; - } - - inline public function addOnce(handler:Void->Void):Bool { - - return add(handler, true); - } - - public function remove(handler:Void->Void):Bool { - - _once.remove(handler); - return _list.remove(handler); - } - - public function dispatch():Void { - - var i = _list.length - 1; - while(i >= 0) { - - var handler = _list[i]; - - if (_once.remove(handler)) - _list.remove(handler); - - handler(); - - i--; - } - } -} - -class TypedDispatcher { - - var _list:ArrayVoid>; - var _once:ArrayVoid>; - - public function new() { - - _list = new ArrayVoid>(); - _once = new ArrayVoid>(); - } - - public function add(handler:T->Void, once:Bool = false):Bool { - - if (_list.indexOf(handler) != -1) { - - // ---- REMOVE ONCE - if (!once && _once.indexOf(handler) != -1) - _once.remove(handler); - - return false; - } - - _list.unshift(handler); - if (once) - _once.unshift(handler); - - return true; - } - - inline public function addOnce(handler:T->Void):Bool { - - return add(handler, true); - } - - public function remove(handler:T->Void):Bool { - - _once.remove(handler); - return _list.remove(handler); - } - - public function dispatch(arg:T):Void { - - var i = _list.length - 1; - while(i >= 0) { - - var handler = _list[i]; - - if (_once.remove(handler)) - _list.remove(handler); - - handler(arg); - - i--; - } - } -} \ No newline at end of file From 4c0186f5fb91332310176ce4add0d768d99482d2 Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 6 Nov 2020 21:59:51 -0500 Subject: [PATCH 08/24] Update Highscore.hx --- source/Highscore.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/Highscore.hx b/source/Highscore.hx index b57870518..4b14746fd 100644 --- a/source/Highscore.hx +++ b/source/Highscore.hx @@ -10,7 +10,9 @@ class Highscore { var daSong:String = formatSong(song, diff); + #if !switch NGio.postScore(score, song); + #end if (songScores.exists(daSong)) { @@ -23,7 +25,9 @@ class Highscore public static function saveWeekScore(week:Int = 1, score:Int = 0, ?diff:Int = 0):Void { + #if !switch NGio.postScore(score, "Week " + week); + #end var daWeek:String = formatSong('week' + week, diff); From 99741f0a65f277c15581965574a3a5a8b2c05a4e Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 00:05:58 -0500 Subject: [PATCH 09/24] crash on story menu --- Preloader.hx | 2 +- Project.xml | 7 ++++--- README.md | 2 ++ source/FreeplayState.hx | 2 ++ source/PlayState.hx | 8 +++++--- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index 37b63aadf..79998e6ea 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -29,7 +29,7 @@ class Preloader extends FlxBasePreloader this._width = Lib.current.stage.stageWidth; this._height = Lib.current.stage.stageHeight; - var ratio:Float = this._width / 800; //This allows us to scale assets depending on the size of the screen. + var ratio:Float = this._width / 1920; //This allows us to scale assets depending on the size of the screen. logo = new Sprite(); logo.addChild(new Bitmap(new LogoImage(0,0))); //Sets the graphic of the sprite to a Bitmap object, which uses our embedded BitmapData class. diff --git a/Project.xml b/Project.xml index 22b04d7d8..4db7fe335 100644 --- a/Project.xml +++ b/Project.xml @@ -37,8 +37,8 @@ - - + + @@ -59,7 +59,8 @@ - + + diff --git a/README.md b/README.md index 84ae25647..e06994275 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,5 @@ This is the repository for Friday Night Funkin, a game originally made for Ludum Play the Ludum Dare prototype here: https://ninja-muffin24.itch.io/friday-night-funkin Play the Newgrounds one here: https://www.newgrounds.com/portal/view/770371 + +## BrandyBuizel porting this shit like a G to Nintendo Switch \ No newline at end of file diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 1457fbf18..213c91c3d 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -184,7 +184,9 @@ class FreeplayState extends MusicBeatState function changeSelection(change:Int = 0) { + #if !switch NGio.logEvent('Fresh'); + #end curSelected += change; diff --git a/source/PlayState.hx b/source/PlayState.hx index a0540eb9f..51cc7874d 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -30,6 +30,9 @@ import flixel.util.FlxTimer; import haxe.Json; import lime.utils.Assets; +//New Audio BS +//import faxe.Faxe; + using StringTools; class PlayState extends MusicBeatState @@ -841,9 +844,7 @@ class PlayState extends MusicBeatState function endSong():Void { - #if !switch Highscore.saveScore(SONG.song, songScore, storyDifficulty); - #end if (isStoryMode) { @@ -861,9 +862,10 @@ class PlayState extends MusicBeatState #if !switch NGio.unlockMedal(60961); - Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty); #end + Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty); + FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; FlxG.save.flush(); } From e84bb65b1d68bee54f75bf519dc36b9f276eb38c Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 02:29:20 -0500 Subject: [PATCH 10/24] new preloader -added preloader aniamtion -modified export bat, -added right stick controls -switch preorders tagline --- Preloader.hx | 32 ++++++++++++-------------------- source/Controls.hx | 8 ++++---- source/TitleState.hx | 2 +- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index 79998e6ea..234205867 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -29,7 +29,7 @@ class Preloader extends FlxBasePreloader this._width = Lib.current.stage.stageWidth; this._height = Lib.current.stage.stageHeight; - var ratio:Float = this._width / 1920; //This allows us to scale assets depending on the size of the screen. + var ratio:Float = this._width / 2560; //This allows us to scale assets depending on the size of the screen. logo = new Sprite(); logo.addChild(new Bitmap(new LogoImage(0,0))); //Sets the graphic of the sprite to a Bitmap object, which uses our embedded BitmapData class. @@ -43,27 +43,19 @@ class Preloader extends FlxBasePreloader override function update(Percent:Float):Void { - if (Percent < 0.1) + if(Percent < 75) { - logo.alpha = 0; + logo.scaleX += Percent / 1280; + logo.scaleY += Percent / 1280; + logo.x -= Percent * 0.9; + logo.y -= Percent / 1.6; + }else{ + logo.scaleX = this._width / 1280; + logo.scaleY = this._width / 1280; + logo.x = ((this._width) / 2) - ((logo.width) / 2); + logo.y = (this._height / 2) - ((logo.height) / 2); } - else if (Percent < 0.25) - { - logo.alpha = 0; - } - else if (Percent < 0.5) - { - logo.alpha = 1; - } - else if ((Percent > 0.75) && (Percent < 0.9)) - { - logo.alpha = 0; - } - else if (Percent > 0.9) - { - logo.alpha = 1; - } - + super.update(Percent); } #end diff --git a/source/Controls.hx b/source/Controls.hx index dc11a616a..7d1e2c40e 100644 --- a/source/Controls.hx +++ b/source/Controls.hx @@ -637,10 +637,10 @@ class Controls extends FlxActionSet //Swap A and B for switch Control.ACCEPT => [B], Control.BACK => [A], - Control.UP => [DPAD_UP, LEFT_STICK_DIGITAL_UP], - Control.DOWN => [DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN], - Control.LEFT => [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT], - Control.RIGHT => [DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT], + Control.UP => [DPAD_UP, LEFT_STICK_DIGITAL_UP, RIGHT_STICK_DIGITAL_UP], + Control.DOWN => [DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN, RIGHT_STICK_DIGITAL_DOWN], + Control.LEFT => [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT], + Control.RIGHT => [DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT], Control.PAUSE => [START], //Swap Y and X for switch Control.RESET => [Y], diff --git a/source/TitleState.hx b/source/TitleState.hx index f4d3274aa..e908828f8 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -37,7 +37,7 @@ class TitleState extends MusicBeatState ['you already know', 'we really out here'], ['rise and grind', 'love to luis'], ['like parappa', 'but cooler'], ['album of the year', 'chuckie finster'], ["free gitaroo man", "with love to wandaboy"], ['better than geometry dash', 'fight me robtop'], ['kiddbrute for president', 'vote now'], ['play dead estate', 'on newgrounds'], ['this is a god damn prototype', 'we workin on it okay'], - ['WOMEN ARE real', 'this is official']]; + ['WOMEN ARE real', 'this is official'], ['Nintendo Switch', 'Pre-orders now available']]; var curWacky:Array = []; From 77c9422088219089d67577a2b06661f6ac13116d Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 15:52:21 -0500 Subject: [PATCH 11/24] haha , also highscore.hx breaks switch --- Preloader.hx | 2 +- source/FreeplayState.hx | 6 ++++++ source/MainMenuState.hx | 2 ++ source/PlayState.hx | 5 +++-- source/StoryMenuState.hx | 17 +++++++++++++++++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index 234205867..6f12b403a 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -43,7 +43,7 @@ class Preloader extends FlxBasePreloader override function update(Percent:Float):Void { - if(Percent < 75) + if(Percent < 69) { logo.scaleX += Percent / 1280; logo.scaleY += Percent / 1280; diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 213c91c3d..59839368f 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -119,6 +119,8 @@ class FreeplayState extends MusicBeatState { super.update(elapsed); + trace("Freeplay Menu Updating"); + lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.4)); scoreText.text = "PERSONAL BEST:" + lerpScore; @@ -169,7 +171,9 @@ class FreeplayState extends MusicBeatState if (curDifficulty > 2) curDifficulty = 0; + #if !switch intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); + #end switch (curDifficulty) { @@ -197,7 +201,9 @@ class FreeplayState extends MusicBeatState // selector.y = (70 * curSelected) + 30; + #if !switch intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); + #end // lerpScore = 0; var bullShit:Int = 0; diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index 6f2ff630d..d92735e51 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -144,8 +144,10 @@ class MainMenuState extends MusicBeatState { case 'story mode': FlxG.switchState(new StoryMenuState()); + trace("Story Menu Selected"); case 'freeplay': FlxG.switchState(new FreeplayState()); + trace("Freeplay Menu Selected"); case 'options': FlxG.switchState(new OptionsMenu()); } diff --git a/source/PlayState.hx b/source/PlayState.hx index 51cc7874d..f4e4fd579 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -844,7 +844,9 @@ class PlayState extends MusicBeatState function endSong():Void { + #if !switch Highscore.saveScore(SONG.song, songScore, storyDifficulty); + #end if (isStoryMode) { @@ -862,9 +864,8 @@ class PlayState extends MusicBeatState #if !switch NGio.unlockMedal(60961); - #end - Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty); + #end FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; FlxG.save.flush(); diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index 0f4b5c018..9c49dce25 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -67,6 +67,8 @@ class StoryMenuState extends MusicBeatState grpLocks = new FlxTypedGroup(); add(grpLocks); + trace("Line 70"); + for (i in 0...weekData.length) { var weekThing:MenuItem = new MenuItem(0, yellowBG.y + yellowBG.height + 10, i); @@ -91,6 +93,8 @@ class StoryMenuState extends MusicBeatState } } + trace("Line 96"); + for (char in 0...3) { var weekCharacterThing:MenuCharacter = new MenuCharacter((FlxG.width * 0.25) * (1 + char) - 150, weekCharacters[curWeek][char]); @@ -117,6 +121,8 @@ class StoryMenuState extends MusicBeatState difficultySelectors = new FlxGroup(); add(difficultySelectors); + trace("Line 124"); + leftArrow = new FlxSprite(grpWeekText.members[0].x + grpWeekText.members[0].width + 10, grpWeekText.members[0].y + 10); leftArrow.frames = ui_tex; leftArrow.animation.addByPrefix('idle', "arrow left"); @@ -141,6 +147,8 @@ class StoryMenuState extends MusicBeatState rightArrow.animation.play('idle'); difficultySelectors.add(rightArrow); + trace("Line 150"); + add(yellowBG); add(grpWeekCharacters); @@ -154,11 +162,15 @@ class StoryMenuState extends MusicBeatState updateText(); + trace("Line 165"); + super.create(); } override function update(elapsed:Float) { + trace("Story Menu Updating"); + // scoreText.setFormat('VCR OSD Mono', 32); lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.5)); @@ -286,7 +298,10 @@ class StoryMenuState extends MusicBeatState // USING THESE WEIRD VALUES SO THAT IT DOESNT FLOAT UP sprDifficulty.y = leftArrow.y - 15; + + #if !switch intendedScore = Highscore.getWeekScore(curWeek, curDifficulty); + #end FlxTween.tween(sprDifficulty, {y: leftArrow.y + 15, alpha: 1}, 0.07); } @@ -339,6 +354,8 @@ class StoryMenuState extends MusicBeatState txtTracklist.screenCenter(X); txtTracklist.x -= FlxG.width * 0.35; + #if !switch intendedScore = Highscore.getWeekScore(curWeek, curDifficulty); + #end } } From 9de490f296e7ef91195cc27e2507ee0e4195a3f3 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 16:13:41 -0500 Subject: [PATCH 12/24] game works again, twin-stick is fun --- Preloader.hx | 4 ++-- source/FreeplayState.hx | 2 -- source/PlayState.hx | 12 +++++++----- source/StoryMenuState.hx | 2 -- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index 6f12b403a..75769d7f3 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -47,8 +47,8 @@ class Preloader extends FlxBasePreloader { logo.scaleX += Percent / 1280; logo.scaleY += Percent / 1280; - logo.x -= Percent * 0.9; - logo.y -= Percent / 1.6; + logo.x -= Percent * 0.86; + logo.y -= Percent / 1.5; }else{ logo.scaleX = this._width / 1280; logo.scaleY = this._width / 1280; diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 59839368f..2db5f397d 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -119,8 +119,6 @@ class FreeplayState extends MusicBeatState { super.update(elapsed); - trace("Freeplay Menu Updating"); - lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.4)); scoreText.text = "PERSONAL BEST:" + lerpScore; diff --git a/source/PlayState.hx b/source/PlayState.hx index f4e4fd579..5ba6e82cb 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -288,6 +288,10 @@ class PlayState extends MusicBeatState // cameras = [FlxG.cameras.list[1]]; + #if lime + trace("IT'S LIME"); + #end + super.create(); } @@ -589,12 +593,9 @@ class PlayState extends MusicBeatState { super.update(elapsed); - #if lime - trace("IT'S LIME"); - #end - //trace("FlxG.elapsed: " + FlxG.elapsed); trace("FlxG.sound.music.time: " + FlxG.sound.music.time); + trace("Conductor.songPosition: " + Conductor.songPosition); //trace("FlxG.sound.music.playing: " + FlxG.sound.music.playing); //trace("SONG POS: " + Conductor.songPosition); // FlxG.sound.music.pitch = 2; @@ -647,7 +648,8 @@ class PlayState extends MusicBeatState } else { - Conductor.songPosition = FlxG.sound.music.time; + //Conductor.songPosition = FlxG.sound.music.time; + Conductor.songPosition += FlxG.elapsed * 1000; if (!paused) { diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index 9c49dce25..5cde2bd4d 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -169,8 +169,6 @@ class StoryMenuState extends MusicBeatState override function update(elapsed:Float) { - trace("Story Menu Updating"); - // scoreText.setFormat('VCR OSD Mono', 32); lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.5)); From 1d972a1313834be4574c86f57a68411a5681b419 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 16:51:55 -0500 Subject: [PATCH 13/24] Update Project.xml --- Project.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Project.xml b/Project.xml index 4db7fe335..844783cd8 100644 --- a/Project.xml +++ b/Project.xml @@ -4,10 +4,12 @@ + + + - - + From aa787059e4a5a3a89d9011b15488d034adb664ea Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 16:59:25 -0500 Subject: [PATCH 14/24] caught up to hard mode --- CHANGELOG.md | 1 + source/PlayState.hx | 3 +++ source/TitleState.hx | 2 ++ 3 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94888a81d..97b677da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Story mode scores not properly resetting, leading to VERY inflated highscores on the leaderboards. This also requires me to clear the scores that are on the leaderboard right now, sorry! - Difficulty on storymode and in freeplay scores +- Hard mode difficulty on campaign levels have been fixed ## [0.2.1.1] - 2020-11-06 ### Fixed diff --git a/source/PlayState.hx b/source/PlayState.hx index 5ba6e82cb..b5a3ce503 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -882,6 +882,9 @@ class PlayState extends MusicBeatState if (storyDifficulty == 2) difficulty == '-hard'; + trace('LOADING NEXT SONG'); + trace(PlayState.storyPlaylist[0].toLowerCase() + difficulty); + PlayState.SONG = Song.loadFromJson(PlayState.storyPlaylist[0].toLowerCase() + difficulty, PlayState.storyPlaylist[0]); FlxG.switchState(new PlayState()); } diff --git a/source/TitleState.hx b/source/TitleState.hx index e908828f8..8aa74a16d 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -13,6 +13,8 @@ import flixel.group.FlxGroup; import flixel.input.gamepad.FlxGamepad; import flixel.math.FlxPoint; import flixel.math.FlxRect; +import flixel.system.FlxSound; +import flixel.system.ui.FlxSoundTray; import flixel.text.FlxText; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; From 62061915a6ce7fe0b355f83eaa8b50ee9c38c3cf Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 17:18:13 -0500 Subject: [PATCH 15/24] moved preloaderArt out --- Preloader.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Preloader.hx b/Preloader.hx index 75769d7f3..509f9c4ba 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -12,7 +12,7 @@ import flash.display.Sprite; import flash.Lib; import flixel.FlxG; -@:bitmap("assets/images/preloaderArt.png") class LogoImage extends BitmapData { } +@:bitmap("art/preloaderArt.png") class LogoImage extends BitmapData { } class Preloader extends FlxBasePreloader { From 9428d5cfaf0d93b2c1d97fcf6af0632ce0d581e6 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 17:59:36 -0500 Subject: [PATCH 16/24] Update Preloader.hx --- Preloader.hx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index 509f9c4ba..ac2f37f8a 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -2,9 +2,6 @@ package ; import flixel.system.FlxBasePreloader; import openfl.display.Sprite; -import flash.text.Font; -import flash.text.TextField; -import flash.text.TextFormat; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; @@ -16,8 +13,7 @@ import flixel.FlxG; class Preloader extends FlxBasePreloader { - #if !js - public function new(MinDisplayTime:Float=5, ?AllowedURLs:Array) + public function new(MinDisplayTime:Float=4, ?AllowedURLs:Array) { super(MinDisplayTime, AllowedURLs); } @@ -58,5 +54,4 @@ class Preloader extends FlxBasePreloader super.update(Percent); } - #end } \ No newline at end of file From fa7a560cb0bb1f87d76116fcd5f4e52721fc05a1 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 7 Nov 2020 19:56:29 -0500 Subject: [PATCH 17/24] custom icon, multiple game directories --- Project.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Project.xml b/Project.xml index 844783cd8..e7efe94ca 100644 --- a/Project.xml +++ b/Project.xml @@ -3,8 +3,8 @@ - - + + - + From bc91e6d3b809467b9e6c463e0d28354d9f949333 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 9 Nov 2020 21:59:55 -0500 Subject: [PATCH 18/24] before i \**** up --- source/Snd.hx | 1288 +++++++++++++++++++++++++++++++++++++++++++++++ source/SndTV.hx | 332 ++++++++++++ 2 files changed, 1620 insertions(+) create mode 100644 source/Snd.hx create mode 100644 source/SndTV.hx diff --git a/source/Snd.hx b/source/Snd.hx new file mode 100644 index 000000000..33aedae66 --- /dev/null +++ b/source/Snd.hx @@ -0,0 +1,1288 @@ +import faxe.Faxe; + +import SndTV; +using StringTools; + +//praise delahee, i'll figure out what this shit means later! + +class Channel { + public var name:String; + public var onEnd : Void -> Void = null; + public var isDebug = false; + + var started = true; + var paused = false; + var disposed = false; + var completed = false; + + inline function new( ?name:String = null ){ + if ( name == null ) + this.name = C.EMPTY_STRING; + else + this.name = name; + } + + public function poolBack(){ + #if false + //trace("pool back"); + #end + started = false; + paused = false; + disposed = true; + completed = true; + isDebug = false; + } + + public function reset(){ + started = false; + paused = false; + disposed = false; + completed = false; + isDebug = false; + } + + public function stop(){ + started = false; + } + + public function pause(){ + paused = false; + started = true; + } + + public function resume(){ + paused = true; + started = true; + } + + public function dispose(){ + setVolume(0);//prevent any further listen + disposed = true; + onEnd = null; + } + + public function onComplete() { + completed = true; + #if !prod + //trace("onComplete " + haxe.Timer.stamp() ); + #end + //stop(); + if( onEnd!=null ) { + var cb = onEnd; + onEnd = null; + cb(); + } + } + + public function isComplete(){ + #if !prod + if ( completed ){ + //trace("already completed"); + } + + if ( started ){ + //trace("started ok"); + } + #end + + return completed || (started && !isPlaying()); + } + + //returns in secs + public function getPlayCursorSec() : Float { + throw "override me"; + return 0.0; + } + + //returns in secs + public function getPlayCursorMs() : Float { + throw "override me"; + return 0.0; + } + + public function setPlayCursorSec(posSec:Float) { + setPlayCursorMs( posSec * 1000.0 ); + } + + public function setPlayCursorMs(posMs:Float) { + throw "override me"; + } + + public function isPlaying(){ + throw "override me"; + return false; + } + + public function getVolume():Float{ + throw "override me"; + return 0.0; + } + + public function setVolume(v:Float){ + throw "override me"; + } + + public function setNbLoops(nb:Int){ + + } +} + +class ChannelEventInstance extends Channel {//basically a sound instance + public static var EMPTY_STRING = ""; + public var data : FmodStudioEventInstanceRef = null; + + function new(?name:String){ + super(name); + started = false; + //instance does not start playing + } + + public static var pool = { + var p = new hxd.Pool(ChannelEventInstance); + //p.actives = null; + p; + } + + public static function alloc(data : FmodStudioEventInstanceRef, ?name:String=null ){ + var s = pool.alloc(); + + s.reset(); + + s.data = data; + s.name = name == null ? EMPTY_STRING : name; + return s; + } + + public static function delete( c : ChannelEventInstance){ + c.dispose(); + pool.delete(c); + } + + public function getData() return data; + + public override function dispose(){ + super.dispose(); + if ( data != null){ + data.release(); + data = null; + } + } + + public override function poolBack(){ + super.poolBack(); + ChannelEventInstance.delete(this); + } + + public override function stop(){ + if (data != null) data.stop(FmodStudioStopMode.StopAllowFadeout()); + super.stop(); + } + + public override function pause(){ + super.pause(); + if(data!=null) data.setPaused(true); + } + + public override function resume(){ + super.resume(); + if(data!=null) data.setPaused(false); + } + + public override function isPlaying(){ + if ( completed ) return false; + + if ( data == null ) { + //#if !prod + //trace("[CEI]no data " + name); + //#end + return false; + } + + var b : Bool = false; + data.getPaused( Cpp.addr(b)); + #if !prod + //trace("getPaused:"+b); + #end + return !b; + } + + //returns in secs + public override function getPlayCursorSec() : Float { + if ( data == null ) return 0.0; + + var pos : Int = 0; + var res = data.getTimelinePosition( Cpp.addr(pos) ); + var posF : Float = 1.0 * pos / 1000.0; + return posF; + } + + //returns in secs + public override function getPlayCursorMs() : Float { + if ( data == null ) return 0.0; + + var pos : Int = 0; + var res = data.getTimelinePosition( Cpp.addr(pos) ); + return 1.0 * pos; + } + + public override function setPlayCursorMs(posMs:Float) { + if ( data == null ) return; + + if ( posMs < 0.0) posMs = 0.0; + var pos : Int = 0; + pos = Math.round( posMs ); + var res = data.setTimelinePosition( pos ); + if ( res != FMOD_OK){ + #if debug + //trace("[SND][Channel]{"+name+"} Repositionning S err " + FaxeRef.fmodResultToString(res)+" to :"+pos+" ("+posMs+")"); + #end + } + + #if debug + //trace("setPlayCursorMs "+posMs); + #end + } + + public override function setNbLoops(nb:Int){ + + } + + public override function getVolume() : Float{ + if (data == null ) return 0.0; + + var vol : cpp.Float32 = 0.0; + var fvol : cpp.Float32 = 0.0; + var res = data.getVolume( Cpp.addr(vol),Cpp.addr(fvol) ); + if ( res != FMOD_OK){ + #if debug + //trace("[SND][Channel]{"+name+"} getVolume err " + FaxeRef.fmodResultToString(res)); + #end + } + return vol; + } + + public override function setVolume(v:Float){ + if (data == null ){ + //#if debug + //trace("no data for "+name); + //#end + return; + } + + var res = data.setVolume( hxd.Math.clamp(v,0,1) ); + if ( res != FMOD_OK){ + //#if debug + //trace("[SND][Channel]{"+name+"} setVolume err " + FaxeRef.fmodResultToString(res)); + //#end + } + else { + //if ( isDebug ){ + //#if !prod + //trace("[SND][Channel]{"+name+"} setVolume ok " + v); + //#end + //} + } + } +} + +class ChannelLowLevel extends Channel{ + + public static var EMPTY_STRING = ""; + public var data : FmodChannelRef = null; + + function new( data : FmodChannelRef, ?name:String ){ + super(name); + this.data = data; + started = true; + } + + public static var pool = { + var p = new hxd.Pool(ChannelLowLevel); + //p.actives = null; + p; + } + + public static function alloc(data : FmodChannelRef, ?name ){ + var s = pool.alloc(); + + s.reset(); + + s.data = data; + s.name = name == null?EMPTY_STRING:name; + + return s; + } + + public static function delete( c : ChannelLowLevel){ + c.dispose(); + pool.delete(c); + } + + public function getData(){ + return data; + } + + public override function poolBack(){ + super.poolBack(); + ChannelLowLevel.delete(this); + } + + public override function stop(){ + if (data != null) data.stop(); + super.stop(); + } + + public override function pause(){ + super.pause(); + if(data!=null) data.setPaused(true); + } + + public override function resume(){ + super.resume(); + if(data!=null) data.setPaused(false); + } + + public override function dispose(){ + super.dispose(); + data = null; + } + + public override function isPlaying(){ + if ( completed ) return false; + + if (data == null) { + //#if !prod + //trace("no data no playing! "+name); + //#end + return false; + } + var b : Bool = false; + var res = data.isPlaying( Cpp.addr(b)); + if ( res != FMOD_OK ){ + //#if debug + //trace("[SND][ChannelLowLevel]{"+name+"} isPlaying err " + FaxeRef.fmodResultToString(res)); + //#end + return false; + } + return b; + } + + //returns in secs + public override function getPlayCursorSec() : Float { + if (data == null) return 0.0; + + var pos : cpp.UInt32 = 0; + var res = data.getPosition( Cpp.addr(pos), faxe.Faxe.FmodTimeUnit.FTM_MS ); + var posF : Float = 1.0 * pos * 1000.0; + return posF; + } + + //returns in secs + public override function getPlayCursorMs() : Float { + if (data == null) return 0.0; + + var pos : cpp.UInt32 = 0; + var res = data.getPosition( Cpp.addr(pos), faxe.Faxe.FmodTimeUnit.FTM_MS ); + return 1.0 * pos; + } + + + public override function setPlayCursorMs(posMs:Float) { + if (data == null) return; + + if ( posMs < 0.0) posMs = 0.0; + var posU : cpp.UInt32 = 0; + posU = Math.round( posMs ); + var res = data.setPosition( posU, FmodTimeUnit.FTM_MS ); + if ( res != FMOD_OK){ + //#if debug + //trace("[SND][Channel]{"+name+"} Repositionning S err " + FaxeRef.fmodResultToString(res)+" to :"+posU+" ("+posMs+")"); + //#end + } + } + + public override function setNbLoops(nb:Int){ + if (data == null) return; + data.setMode(FmodMode.FMOD_LOOP_NORMAL); + data.setLoopCount(nb); + } + + public override function getVolume():Float{ + if (data == null) return 0.0; + + var vol : cpp.Float32 = 0.0; + var res = data.getVolume( Cpp.addr(vol) ); + if ( res != FMOD_OK){ + //#if debug + //trace("[SND][Channel]{"+name+"} getVolume err " + FaxeRef.fmodResultToString(res)); + //#end + } + return vol; + } + + public override function setVolume(v:Float){ + if (data == null) { + //if ( isDebug ){ + //#if !prod + //trace("[SND][Channel]{"+name+"} setVolume no data"); + //#end + //} + return; + } + + var vcl = hxd.Math.clamp(v, 0, 1); + var res = data.setVolume( vcl ); + if ( res != FMOD_OK){ + //#if !prod + //trace("[SND][Channel]{"+name+"} setVolume err " + FaxeRef.fmodResultToString(res)); + //#end + } + else { + if ( isDebug ){ + //#if !prod + //trace("[SND][Channel]{"+name+"} setVolume ok " + v+" corrected:"+vcl); + //#end + } + } + } + + +} + +class Sound { + /** + * length is in seconds + */ + public var name = ""; + public var length(get, null) : Float; + public var id3 : Dynamic = null; + public var isDebug = false; + + var disposed = false; + + function new( ?name:String=null ){ + disposed = false; + } + + function get_length() : Float{ + return 0.0; + } + + //returns in msec + public function getDuration(): Float{ + return getDurationMs(); + } + + public function getDurationSec() : Float{ + return length; + } + + public function getDurationMs() : Float{ + return length * 1000.0; + } + + public function dispose(){ + if (disposed) return; + disposed = true; + } + + public function play( ?offsetMs : Float = 0.0, ?nbLoops:Int = 1, ?volume:Float = 1.0 ) : Channel { + return null; + } +} + +class SoundLowLevel extends Sound{ + + public var data : FmodSoundRef = null; + + public function new( data : cpp.Pointer, ?name:String = null ){ + super(name); + this.data = Cpp.ref(data); + } + + public function getData(){ + return data; + } + + public override function dispose(){ + super.dispose(); + + if ( Snd.released ) { + data = null; + return; + } + + if(data!=null) + data.release(); + data = null; + } + + //returns in secs + override function get_length() : Float{ + if (disposed) return 0.0; + + var pos : cpp.UInt32 = 0; + var res = data.getLength( Cpp.addr(pos), FmodTimeUnit.FTM_MS ); + if ( res != FMOD_OK ){ + #if debug + //trace("impossible to retrieve sound len"); + #end + } + var posF = 1.0 * pos / 1000.0; + return posF; + } + + public override function play( ?offsetMs : Float = 0.0, ?nbLoops:Int = 1, ?volume:Float = 1.0) : Channel { + var nativeChan : FmodChannelRef = FaxeRef.playSoundWithHandle( data , false); + var chan = ChannelLowLevel.alloc( nativeChan, name ); + + #if debug + //trace("[Sound] offset " + offsetMs); + //trace("play " + haxe.Timer.stamp() ); + #end + + @:privateAccess chan.started = true; + @:privateAccess chan.completed = false; + @:privateAccess chan.disposed = false; + @:privateAccess chan.paused = false; + + + if( offsetMs != 0.0 ) chan.setPlayCursorMs( offsetMs ); + if( volume != 1.0 ) chan.setVolume( volume ); + if( nbLoops > 1 ) chan.setNbLoops( nbLoops ); + + return chan; + } +} + + +class SoundEvent extends Sound{ + + public var data : FmodStudioEventDescriptionRef = null; + + public function new( data : FmodStudioEventDescriptionRef, ?name:String = null ){ + super(name); + this.data = data; + } + + public override function dispose(){ + super.dispose(); + + if ( Snd.released ) { + data = null; + return; + } + + if ( data != null){ + data.releaseAllInstances(); + data = null; + } + } + public function getData(){ + return data; + } + + //returns in secs + override function get_length() : Float{ + if (disposed) return 0.0; + + var pos : Int = 0; + var res = data.getLength( Cpp.addr(pos) ); + if ( res != FMOD_OK ){ + //#if !prod + //trace("impossible to retrieve sound len"); + //#end + } + var posF = 1.0 * pos / 1000.0; + return posF; + } + + public override function play( ?offsetMs : Float = 0.0, ?nbLoops:Int = 1, ?volume:Float = 1.0) : Channel{ + var nativeInstance : FmodStudioEventInstanceRef = data.createInstance(); + var chan = ChannelEventInstance.alloc( nativeInstance, name ); + + //#if !prod + //trace("play " + haxe.Timer.stamp() ); + //#end + nativeInstance.start(); + + @:privateAccess chan.started = true; + @:privateAccess chan.completed = false; + @:privateAccess chan.disposed = false; + @:privateAccess chan.paused = false; + + if( offsetMs != 0.0 ) chan.setPlayCursorMs( offsetMs ); + if( volume != 1.0 ) chan.setVolume( volume ); + + return chan; + } +} + +class Snd { + public static var EMPTY_STRING = ""; + public static var PLAYING : hxd.Stack = new hxd.Stack(); + static var MUTED = false; + static var DISABLED = false; + static var GLOBAL_VOLUME = 1.0; + static var TW = new SndTV(); + + public var name : String ; + public var pan : Float = 0.0; + public var volume(default,set) : Float = 1.0; + public var curPlay : Null = null; + public var bus = otherBus; + public var isDebug = true; + /** + * for when stop is called explicitly + * allows disposal + */ + public var onStop = new hxd.Signal(); + public var sound : Sound = null; + + var onEnd : NullVoid> = null; + static var fmodSystem : FmodSystemRef = null; + + public static var otherBus = new SndBus(); + public static var sfxBus = new SndBus(); + public static var musicBus = new SndBus(); + + public function new( snd : Sound, ?name:String ) { + volume = 1; + pan = 0; + sound = snd; + muted = false; + this.name = name==null?EMPTY_STRING:name; + } + + public function isLoaded() { + return sound!=null; + } + + //does not dispose sound, only instanced + public function stop(){ + + TW.terminate(this);//prevent reentrancy of fadeStop() stop() not cutting any sound + + PLAYING.remove(this); + + if ( isPlaying() && !onStop.isTriggering ) + onStop.trigger(); + + if ( curPlay != null){ + curPlay.dispose(); + curPlay.poolBack(); + curPlay = null; + #if !prod + //trace(name+" stopped"); + //Lib.showStack(); + #end + } + + //bus = otherBus; + } + + public function dispose(){ + //#if !prod + //trace(name+" disposing"); + //#end + + if ( isPlaying() ){ + stop(); + } + + if ( curPlay != null){ + curPlay.dispose(); + curPlay.poolBack(); + curPlay = null; + //#if !prod + //trace(name+" disposed"); + //#end + } + + if ( sound != null) { + sound.dispose(); + sound = null; + } + + onStop.dispose(); + + onEnd = null; + curPlay = null; + } + + /** + * + * @return in ms + */ + public inline function getPlayCursor() : Float { + if ( curPlay == null) return 0.0; + return curPlay.getPlayCursorMs(); + } + + + public function play(?vol:Float, ?pan:Float) : Snd { + if( vol == null ) vol = volume; + if( pan == null ) pan = this.pan; + + start(0, vol, 0.0); + + return this; + } + + /** + * launches the sound, stops previous and rewrite the cur play dropping it into oblivion for the gc + */ + public function start(loops:Int=0, vol:Float=1.0, ?startOffsetMs:Float=0.0) { + if ( DISABLED ) { + //#if debug + //trace("[SND] Disabled"); + //#end + return; + } + if ( sound == null ){ + //#if debug + //trace("[SND] no inner sound"); + //#end + return; + } + + if ( isPlaying() ){ + //#if !prod + //trace(name+" interrupting "); + //#end + + stop(); + } + + TW.terminate(this); + + this.volume = vol; + this.pan = normalizePanning(pan); + + PLAYING.push(this); + curPlay = sound.play( startOffsetMs, loops, getRealVolume()); + + if ( curPlay == null){ + //#if !prod + //trace(" play missed?"); + //#end + } + else { + //#if !prod + //trace("started"); + //#end + } + } + + /** + * launches the sound and rewrite the cur play dropping it into oblivion for the gc + */ + public function startNoStop(?loops:Int=0, ?vol:Float=1.0, ?startOffsetMs:Float=0.0) : Null{ + if ( DISABLED ) { + //#if debug + //trace("[SND] Disabled"); + //#end + return null; + } + if ( sound == null ){ + //#if debug + //trace("[SND] no inner sound"); + //#end + return null; + } + + this.volume = vol; + this.pan = normalizePanning(pan); + + curPlay = sound.play( startOffsetMs, loops, getRealVolume()); + + return curPlay; + } + + public inline function getDuration() { + return getDurationMs(); + } + + public inline function getDurationSec() { + return sound.length; + } + + /** + * returns in ms + */ + public inline function getDurationMs() { + return sound.length * 1000.0; + } + + public static inline + function trunk(v:Float, digit:Int) : Float{ + var hl = Math.pow( 10.0 , digit ); + return Std.int( v * hl ) / hl; + } + + public static function dumpMemory(){ + var v0 : Int = 0; + var v1 : Int = 0; + var v2 : Int = 0; + + var v0p : cpp.Pointer = Cpp.addr(v0); + var v1p : cpp.Pointer = Cpp.addr(v1); + var v2p : cpp.Pointer = Cpp.addr(v2); + var str = ""; + var res = fmodSystem.getSoundRAM( v0p, v1p, v2p ); + if ( res != FMOD_OK){ + //#if debug + //trace("[SND] cannot fetch snd ram dump "); + //#end + } + + inline function f( val :Float) : Float{ + return trunk(val, 2); + } + + if( v2 > 0 ){ + str+="fmod Sound chip RAM all:" + f(v0 / 1024.0) + "KB \t max:" + f(v1 / 1024.0) + "KB \t total: " + f(v2 / 1024.0) + " KB\r\n"; + } + + v0 = 0; + v1 = 0; + + var res = FaxeRef.Memory_GetStats( v0p, v1p, false ); + str += "fmod Motherboard chip RAM all:" + f(v0 / 1024.0) + "KB \t max:" + f(v1 / 1024.0) + "KB \t total: " + f(v2 / 1024.0) + " KB"; + return str; + } + + public function playLoop(?loops = 9999, ?vol:Float=1.0, ?startOffset = 0.0) : Snd { + if( vol==null ) + vol = volume; + + start(loops, vol, startOffset); + return this; + } + + function set_volume(v:Float) { + volume = v; + refresh(); + return volume; + } + + public function setVolume(v:Float) { + set_volume(v); + } + + public inline function getRealPanning() { + return pan; + } + + public function setPanning(p:Float) { + pan = p; + refresh(); + } + + public function onEndOnce(cb:Void->Void) { + onEnd = cb; + } + + public function fadePlay(?fadeDuration = 100, ?endVolume:Float=1.0 ) { + var p = play(0.0001); + if ( p == null ){ + //trace("nothing ret"); + } + else { + if ( p.curPlay == null){ + //trace("no curplay wtf?"); + } + else + { + //trace("curplay ok"); + } + } + tweenVolume(endVolume, fadeDuration); + return p; + } + + public function fadePlayLoop(?fadeDuration = 100, ?endVolume:Float=1.0 , ?loops=9999) { + var p = playLoop(loops,0); + tweenVolume(endVolume, fadeDuration); + return p; + } + + public function fadeStop( ?fadeDuration = 100 ) { + if ( !isPlaying()){ + //#if !prod + //trace("not playing " + name+" winn not unfade");//can cause reentrancy issues + //#end + return null; + } + + isDebug = true; + var t = tweenVolume(0, fadeDuration); + t.onEnd = _stop; + return t; + } + + public var muted : Bool = false; + + public function toggleMute() { + muted = !muted;//todo + setVolume(volume); + } + public function mute() { + muted = true; + setVolume(volume); + } + public function unmute() { + muted = false; + setVolume(volume); + } + + public function isPlaying(){ + if ( curPlay == null ){ + #if !prod + //trace("no curplay"); + #end + return false; + } + return curPlay.isPlaying(); + } + + public static function init(){ + #if debug + trace("[Snd] fmod init"); + #end + Faxe.fmod_init( 256 ); + fmodSystem = FaxeRef.getSystem(); + released = false; + } + + public static var released = true; + + public static function release(){ + TW.terminateAll(); + for (s in PLAYING) + s.dispose(); + PLAYING.hardReset(); + released = true; + //trace("releasing fmod"); + Faxe.fmod_release(); + #if !prod + trace("fmod released"); + #end + } + + public static function setGlobalVolume(vol:Float) { + GLOBAL_VOLUME = normalizeVolume(vol); + refreshAll(); + } + + function refresh() { + if ( curPlay != null ) { + var vol = getRealVolume(); + //trace("r:"+vol); + curPlay.setVolume( vol ); + } + else { + //#if debug + //trace("[Snd] no playin no refresh "+name); + //#end + } + } + + public function setPlayCursorSec( pos:Float ) { + if (curPlay != null) { + curPlay.setPlayCursorSec(pos); + } + else { + //#if debug + //trace("setPlayCursorSec/no current instance"); + //#end + } + } + + public function setPlayCursorMs( pos:Float ){ + if (curPlay != null) + curPlay.setPlayCursorMs(pos); + else { + //#if debug + //trace("setPlayCursorMs/no current instance"); + //#end + } + } + + public function tweenVolume(v:Float, ?easing:h2d.Tweenie.TType, ?milliseconds:Float=100) : TweenV { + if ( easing == null ) easing = h2d.Tweenie.TType.TEase; + var t = TW.create(this, TVVVolume, v, easing, milliseconds); + //#if !prod + //trace("tweening " + name+" to " + v); + //#end + return t; + } + + public function tweenPan(v:Float, ?easing:h2d.Tweenie.TType, ?milliseconds:Float=100) : TweenV { + if ( easing == null ) easing = h2d.Tweenie.TType.TEase; + var t = TW.create(this, TVVPan, v, easing, milliseconds); + return t; + } + + public inline function getRealVolume() { + var v = volume * GLOBAL_VOLUME * (DISABLED?0:1) * (MUTED?0:1) * (muted?0:1) * bus.volume; + if ( v <= 0.001) + v = 0.0; + return normalizeVolume(v); + } + + static inline function normalizeVolume(f:Float) { + return hxd.Math.clamp(f, 0,1); + } + + static inline function normalizePanning(f:Float) { + return hxd.Math.clamp(f, -1,1); + } + + static var _stop = function(t:TweenV){ + #if !prod + //if( t.parent != null ) + //trace(t.parent.name+" cbk stopped"); + //else + //trace(" unbound stop called"); + #end + t.parent.stop(); + } + + static var _refresh = function(t:TweenV) { + + //avoid unwanted crash + if ( released ){ + //#if !prod + //trace("sorry released"); + //#end + return; + } + + t.parent.refresh(); + } + + static function refreshAll() { + for(s in PLAYING) + s.refresh(); + } + + function onComplete(){ + //#if debug + //trace("onComplete " + haxe.Timer.stamp()); + //#end + + if (curPlay != null) { + curPlay.onComplete(); + } + + stop(); + } + + public function isComplete(){ + if ( curPlay == null ) { + //#if!prod + //trace("comp: no cur play"); + //#end + return true; + } + return curPlay.isComplete(); + } + + ////////////////////////////////////// + /////////////////////STATICS////////// + ////////////////////////////////////// + + public static var DEBUG_TRACK = false; + + //@:noDebug + public static function loadSound( path:String, streaming : Bool, blocking : Bool ) : Sound { + + if ( released ) { + //#if(!prod) + //trace("FMOD not active "+path); + //#end + return null; + } + + var mode = FMOD_DEFAULT; + + if ( streaming ) mode |= FMOD_CREATESTREAM; + if ( !blocking ) mode |= FMOD_NONBLOCKING; + + mode |= FmodMode.FMOD_2D; + + + if( DEBUG_TRACK) trace("Snd:loading " + path); + + var snd : cpp.RawPointer = cast null; + var sndR : cpp.RawPointer> = cpp.RawPointer.addressOf(snd); + + #if switch + if ( !path.startsWith("rom:")) + path = "rom://" + path; + #end + + var res : FmodResult = fmodSystem.createSound( + Cpp.cstring(path), + mode, + Cpp.nullptr(), + sndR + ); + + if ( res != FMOD_OK){ + #if(!prod) + trace("unable to load " + path + " code:" + res+" msg:"+FaxeRef.fmodResultToString(res)); + #end + return null; + } + + var n:String = null; + + #if debug + n = new bm.Path(path).getFilename(); + #end + + return new SoundLowLevel(cpp.Pointer.fromRaw(snd),n); + } + + public static function loadEvent( path:String ) : Sound { + if ( released ) { + //#if (!prod) + //trace("FMOD not active "+path); + //#end + return null; + } + + + if( DEBUG_TRACK) trace("Snd:loadingEvent " + path); + + if ( !path.startsWith("event:/")) + path = "event:/" + path; + + var fss : FmodStudioSystemRef = faxe.FaxeRef.getStudioSystem(); + var ev = fss.getEvent( path); + + if ( ev == null ) return null; + + if ( !ev.isLoaded() ){ + var t0 = haxe.Timer.stamp(); + ev.loadSampleData(); + var t1 = haxe.Timer.stamp(); + #if debug + //trace("time to preload:" + (t1 - t0)); + #end + } + + return new SoundEvent( ev, path); + } + + public static function fromFaxe( path:String ) : Snd { + if ( released ) { + //#if (!prod) + //trace("FMOD not active "+path); + //#end + return null; + } + + var s : cpp.Pointer = faxe.Faxe.fmod_get_sound(path ); + if ( s == null){ + #if (!prod) + trace("unable to find " + path); + #end + return null; + } + + var n:String = null; + + #if debug + n = new bm.Path(path).getFilename(); + #end + + return new Snd( new SoundLowLevel(s,n), path); + } + + public static function loadSfx( path:String ) : Snd { + var s : Sound = loadSound(path, false, false); + if ( s == null) return null; + return new Snd( s, s.name); + } + + public static function loadSong( path:String ) : Snd { + var s : Sound = loadSound(path, true, true); + if ( s == null) return null; + return new Snd( s, s.name); + } + + public static function load( path:String, streaming=false,blocking=true ) : Snd { + var s : Sound = loadSound(path, streaming, blocking); + if ( s == null) { + #if !prod + trace("no such file " + path); + #end + return null; + } + return new Snd( s, s.name); + } + + public static function terminateTweens() { + TW.terminateAll(); + } + + public static function update() { + for ( p in PLAYING.backWardIterator()) + if ( p.isComplete()){ + #if !prod + //trace("[Snd] isComplete " + p); + #end + p.onComplete(); + } + TW.update();//let tweens complete + + if(!released ) Faxe.fmod_update(); + } + + public static function loadSingleBank( filename : String ) : Null{ + if ( released ) { + #if debug + trace("FMOD not active "+filename); + #end + return null; + } + + if ( filename.endsWith(".fsb")) { + #if debug + trace("fsb files not supported"); + #end + return null;//old fmod format is not supported + } + + var t0 = haxe.Timer.stamp(); + var fsys = FaxeRef.getStudioSystem(); + var fbank : cpp.RawPointer < FmodStudioBank > = null; + + //trace("trying to load " + filename); + + Lib.loadMode(); + var result = fsys.loadBankFile( + cpp.ConstCharStar.fromString( filename ), + FmodStudioLoadBank.FMOD_STUDIO_LOAD_BANK_NONBLOCKING, + cpp.RawPointer.addressOf(fbank)); + Lib.playMode(); + + if (result != FMOD_OK) { + #if debug + trace("FMOD failed to LOAD sound bank with errcode:" + result + " errmsg:" + FaxeRef.fmodResultToString(result) + "\n"); + #end + return null; + } + //else + // trace("loading..."); + + var t1 = haxe.Timer.stamp(); + #if debug + //trace("time to load bank:" + (t1 - t0)+"s"); + #end + return cast fbank; + } +} \ No newline at end of file diff --git a/source/SndTV.hx b/source/SndTV.hx new file mode 100644 index 000000000..62e69f455 --- /dev/null +++ b/source/SndTV.hx @@ -0,0 +1,332 @@ +import h2d.Tweenie.TType; + +//praise delahee, i'll figure out what this shit means later! + +enum TVVar{ + TVVVolume; + TVVPan; +} + +@:publicFields +class TweenV { + static var GUID = 0; + var uid = 0; + + var man : SndTV; + var parent : Snd; + var n : Float; + var ln : Float; + var speed : Float; + var from : Float; + var to : Float; + var type : TType; + var plays : Int; // -1 = infini, 1 et plus = nombre d'exécutions (1 par défaut) + var varType : TVVar; + var onUpdate : NullVoid>; + var onEnd : NullVoid>; + var isDebug = false; + + public inline function new ( + parent:Snd , + n:Float , + ln:Float , + varType:TVVar, + speed:Float , + from:Float , + to:Float , + type:h2d.Tweenie.TType , + plays , + onUpdate , + onEnd + ) { + this.parent = parent ; + this.n = n ; + this.ln = ln ; + this.varType = varType ; + this.speed = speed ; + this.from = from ; + this.to = to ; + this.type = type ; + this.plays = plays ; + this.onUpdate = onUpdate ; + this.onEnd = onEnd ; + } + + public inline function reset( + parent:Snd , + n:Float , + ln:Float , + varType:TVVar, + speed:Float , + from:Float , + to:Float , + type:TType , + plays:Int , + onUpdate , + onEnd + ) { + this.parent = parent ; + this.n = n ; + this.ln = ln ; + this.speed = speed ; + this.from = from ; + this.to = to ; + this.type = type ; + this.plays = plays ; + this.onUpdate = onUpdate ; + this.onEnd = onEnd ; + this.varType = varType ; + isDebug = false; + uid = GUID++; + } + + public function clear(){ + n = 0.0; + ln = 0.0; + speed = 0.0; + plays = 0; + from = 0.0; + to = 0.0; + parent = null; + onEnd = null; + onUpdate = null; + isDebug = false; + uid = GUID++; + } + + + public + inline + function apply( val ) { + switch(varType){ + case TVVVolume: { + parent.volume = val; + #if debug + if( isDebug ) + trace("tv:" + val); + #end + } + case TVVPan: parent.pan = val; + } + + } + + public inline function kill( withCbk = true ) { + if ( withCbk ) + man.terminateTween( this ); + else + man.forceTerminateTween( this) ; + } + +} + +/** + * tween order is not respected + */ +class SndTV { + static var DEFAULT_DURATION = DateTools.seconds(1); + public var fps = 60.0; + public var isDebug = false; + + var tlist : hxd.Stack; + + public function new() { + tlist = new hxd.Stack(); + tlist.reserve(8); + } + + function onError(e) { + trace(e); + } + + public function count() { + return tlist.length; + } + + public inline function create(parent:Snd, vartype:TVVar, to:Float, ?tp:h2d.Tweenie.TType, ?duration_ms:Float) : TweenV{ + return create_(parent, vartype, to, tp, duration_ms); + } + + public function exists(p:Snd) { + for (t in tlist) + if (t.parent == p ) + return true; + return false; + } + + public var pool : hxd.Stack = new hxd.Stack(); + + function create_(p:Snd, vartype:TVVar,to:Float, ?tp:h2d.Tweenie.TType, ?duration_ms:Float) : TweenV{ + if ( duration_ms==null ) + duration_ms = DEFAULT_DURATION; + + #if debug + if ( p == null ) trace("tween2 creation failed to:"+to+" tp:"+tp); + #end + + if ( tp==null ) tp = TEase; + + { + // on supprime les tweens précédents appliqués à la même variable + for(t in tlist.backWardIterator()) + if(t.parent==p && t.varType == vartype) { + forceTerminateTween(t); + } + } + + var from = switch( vartype ){ + case TVVVolume : p.volume; + case TVVPan : p.pan; + } + var t : TweenV; + if (pool.length == 0){ + t = new TweenV( + p, + 0.0, + 0.0, + vartype, + 1 / ( duration_ms*fps/1000 ), // une seconde + from, + to, + tp, + 1, + null, + null + ); + } + else { + t = pool.pop(); + t.reset( + p, + 0.0, + 0.0, + vartype, + 1 / ( duration_ms*fps/1000 ), // une seconde + from, + to, + tp, + 1, + null, + null + ); + + } + + if( t.from==t.to ) + t.ln = 1; // tweening inutile : mais on s'assure ainsi qu'un update() et un end() seront bien appelés + + t.man = this; + tlist.push(t); + + return t; + } + + public static inline + function fastPow2(n:Float):Float { + return n*n; + } + + public static inline + function fastPow3(n:Float):Float { + return n*n*n; + } + + public static inline + function bezier(t:Float, p0:Float, p1:Float,p2:Float, p3:Float) { + return + fastPow3(1-t)*p0 + + 3*( t*fastPow2(1-t)*p1 + fastPow2(t)*(1-t)*p2 ) + + fastPow3(t)*p3; + } + + // suppression du tween sans aucun appel aux callbacks onUpdate, onUpdateT et onEnd (!) + public function killWithoutCallbacks(parent:Snd) { + for (t in tlist.backWardIterator()) + if (t.parent==parent ){ + forceTerminateTween(t); + return true; + } + return false; + } + + public function terminate(parent:Snd) { + for (t in tlist.backWardIterator()) + if (t.parent==parent){ + forceTerminateTween(t); + } + } + + public function forceTerminateTween(t:TweenV) { + var tOk = tlist.remove(t); + if( tOk ){ + t.clear(); + pool.push(t); + } + } + + public function terminateTween(t:TweenV, ?fl_allowLoop=false) { + var v = t.from + (t.to - t.from) * h2d.Tweenie.interp(t.type, 1); + t.apply(v); + onUpdate(t, 1); + + var ouid = t.uid; + + onEnd(t); + + if( ouid == t.uid ){ + if( fl_allowLoop && (t.plays==-1 || t.plays>1) ) { + if( t.plays!=-1 ) + t.plays--; + t.n = t.ln = 0; + } + else { + forceTerminateTween(t); + } + } + } + + public function terminateAll() { + for(t in tlist) + t.ln = 1; + update(); + } + + inline + function onUpdate(t:TweenV, n:Float) { + if ( t.onUpdate!=null ) + t.onUpdate(t); + } + + inline + function onEnd(t:TweenV) { + if ( t.onEnd!=null ) + t.onEnd(t); + } + + public function update(?tmod = 1.0) { + if ( tlist.length > 0 ) { + for (t in tlist.backWardIterator() ) { + var dist = t.to-t.from; + if (t.type==TRand) + t.ln+=if(Std.random(100)<33) t.speed * tmod else 0; + else + t.ln += t.speed * tmod; + + t.n = h2d.Tweenie.interp(t.type, t.ln); + + if ( t.ln<1 ) { + // en cours... + var val = t.from + t.n*dist; + + t.apply(val); + + onUpdate(t, t.ln); + } + else // fini ! + { + terminateTween(t, true); + } + } + } + } +} \ No newline at end of file From 11ba4ac690d37a76402baccda6ef9c49d4d675e0 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Nov 2020 12:52:49 -0500 Subject: [PATCH 19/24] added lucky, highscore fix?? --- source/Character.hx | 18 +++++++++++++++++- source/Highscore.hx | 4 ++++ source/TitleState.hx | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/source/Character.hx b/source/Character.hx index 937fd310c..427e7bb11 100644 --- a/source/Character.hx +++ b/source/Character.hx @@ -52,7 +52,6 @@ class Character extends FlxSprite addOffset('scared'); playAnim('danceRight'); - case 'dad': // DAD ANIMATION LOADING CODE tex = FlxAtlasFrames.fromSparrow(AssetPaths.DADDY_DEAREST__png, AssetPaths.DADDY_DEAREST__xml); @@ -103,6 +102,21 @@ class Character extends FlxSprite addOffset("singLEFT", -30); addOffset("singDOWN", -30, -40); playAnim('idle'); + case 'lucky': + tex = FlxAtlasFrames.fromSparrow(AssetPaths.lucky_guitar_assets__png, AssetPaths.lucky_guitar_assets__xml); + frames = tex; + animation.addByPrefix('idle', 'lucky guitar idle', 24); + animation.addByPrefix('singUP', 'lucky UP NOTE', 24); + animation.addByPrefix('singRIGHT', 'lucky sing right', 24); + animation.addByPrefix('singDOWN', 'lucky DOWN note', 24); + animation.addByPrefix('singLEFT', 'lucky sing left', 24); + + addOffset('idle'); + addOffset("singUP", -6, 50); + addOffset("singRIGHT", 0, 27); + addOffset("singLEFT", -10, 10); + addOffset("singDOWN", 0, -30); + playAnim('idle'); } } @@ -135,6 +149,8 @@ class Character extends FlxSprite playAnim('idle'); case 'monster': playAnim('idle'); + case 'lucky': + playAnim('idle'); } } diff --git a/source/Highscore.hx b/source/Highscore.hx index 4b14746fd..462f70d1b 100644 --- a/source/Highscore.hx +++ b/source/Highscore.hx @@ -4,7 +4,11 @@ import flixel.FlxG; class Highscore { + #if (haxe >= "4.0.0") public static var songScores:Map = new Map(); + #else + public static var songScores:Map = new Map(); + #end public static function saveScore(song:String, score:Int = 0, ?diff:Int = 0):Void { diff --git a/source/TitleState.hx b/source/TitleState.hx index 8aa74a16d..51fb8250b 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -59,7 +59,7 @@ class TitleState extends MusicBeatState super.create(); - #if (!switch && !debug && NG_LOGIN) + #if (web && !debug && NG_LOGIN) var ng:NGio = new NGio(APIStuff.API, APIStuff.EncKey); #end From 6c04bb8e233d9a1eb9493dc72dca45d12c9b1e74 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Nov 2020 13:08:18 -0500 Subject: [PATCH 20/24] caught up 11/10/20 --- Preloader.hx | 2 +- source/FreeplayState.hx | 9 ++++----- source/PlayState.hx | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index ac2f37f8a..6882d8d06 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -44,7 +44,7 @@ class Preloader extends FlxBasePreloader logo.scaleX += Percent / 1280; logo.scaleY += Percent / 1280; logo.x -= Percent * 0.86; - logo.y -= Percent / 1.5; + logo.y -= Percent / 1.4; }else{ logo.scaleX = this._width / 1280; logo.scaleY = this._width / 1280; diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 2db5f397d..b938f1aac 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -8,7 +8,6 @@ import flixel.group.FlxGroup.FlxTypedGroup; import flixel.math.FlxMath; import flixel.text.FlxText; import flixel.util.FlxColor; -//import htmlparser.HtmlDocument; import lime.utils.Assets; class FreeplayState extends MusicBeatState @@ -120,6 +119,10 @@ class FreeplayState extends MusicBeatState super.update(elapsed); lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.4)); + + if (Math.abs(lerpScore - intendedScore) <= 10) + lerpScore = intendedScore; + scoreText.text = "PERSONAL BEST:" + lerpScore; var upP = controls.UP_P; @@ -169,9 +172,7 @@ class FreeplayState extends MusicBeatState if (curDifficulty > 2) curDifficulty = 0; - #if !switch intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); - #end switch (curDifficulty) { @@ -199,9 +200,7 @@ class FreeplayState extends MusicBeatState // selector.y = (70 * curSelected) + 30; - #if !switch intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); - #end // lerpScore = 0; var bullShit:Int = 0; diff --git a/source/PlayState.hx b/source/PlayState.hx index b5a3ce503..35a8b9f7c 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -880,7 +880,7 @@ class PlayState extends MusicBeatState difficulty = '-easy'; if (storyDifficulty == 2) - difficulty == '-hard'; + difficulty = '-hard'; trace('LOADING NEXT SONG'); trace(PlayState.storyPlaylist[0].toLowerCase() + difficulty); From 68958963a367c57b9f70567fb1dc99208e3e5574 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 10 Nov 2020 15:07:34 -0500 Subject: [PATCH 21/24] did the meme on switch --- Preloader.hx | 8 ++++---- source/Character.hx | 20 ++++++++++---------- source/FreeplayState.hx | 5 ++++- source/PlayState.hx | 1 + 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Preloader.hx b/Preloader.hx index 6882d8d06..932df79b7 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -41,10 +41,10 @@ class Preloader extends FlxBasePreloader { if(Percent < 69) { - logo.scaleX += Percent / 1280; - logo.scaleY += Percent / 1280; - logo.x -= Percent * 0.86; - logo.y -= Percent / 1.4; + logo.scaleX += Percent / 1920; + logo.scaleY += Percent / 1920; + logo.x -= Percent * 0.6; + logo.y -= Percent / 2; }else{ logo.scaleX = this._width / 1280; logo.scaleY = this._width / 1280; diff --git a/source/Character.hx b/source/Character.hx index 427e7bb11..da51e2321 100644 --- a/source/Character.hx +++ b/source/Character.hx @@ -105,17 +105,17 @@ class Character extends FlxSprite case 'lucky': tex = FlxAtlasFrames.fromSparrow(AssetPaths.lucky_guitar_assets__png, AssetPaths.lucky_guitar_assets__xml); frames = tex; - animation.addByPrefix('idle', 'lucky guitar idle', 24); - animation.addByPrefix('singUP', 'lucky UP NOTE', 24); - animation.addByPrefix('singRIGHT', 'lucky sing right', 24); - animation.addByPrefix('singDOWN', 'lucky DOWN note', 24); - animation.addByPrefix('singLEFT', 'lucky sing left', 24); + animation.addByPrefix('idle', 'lucky guitar idle', 24, false); + animation.addByPrefix('singUP', 'lucky UP NOTE', 24, false); + animation.addByPrefix('singRIGHT', 'lucky sing right', 24, false); + animation.addByPrefix('singDOWN', 'lucky DOWN note', 24, false); + animation.addByPrefix('singLEFT', 'lucky sing left', 24, false); - addOffset('idle'); - addOffset("singUP", -6, 50); - addOffset("singRIGHT", 0, 27); - addOffset("singLEFT", -10, 10); - addOffset("singDOWN", 0, -30); + addOffset('idle', 0, -180); + addOffset("singUP", 200, -180); + addOffset("singRIGHT", 200, -180); + addOffset("singLEFT", 200, -180); + addOffset("singDOWN", 200, -180); playAnim('idle'); } } diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index b938f1aac..7b0dbbe8b 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -151,7 +151,6 @@ class FreeplayState extends MusicBeatState if (accepted) { var poop:String = Highscore.formatSong(songs[curSelected].toLowerCase(), curDifficulty); - trace(poop); PlayState.SONG = Song.loadFromJson(poop, songs[curSelected].toLowerCase()); @@ -172,7 +171,9 @@ class FreeplayState extends MusicBeatState if (curDifficulty > 2) curDifficulty = 0; + #if !switch intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); + #end switch (curDifficulty) { @@ -200,8 +201,10 @@ class FreeplayState extends MusicBeatState // selector.y = (70 * curSelected) + 30; + #if !switch intendedScore = Highscore.getScore(songs[curSelected], curDifficulty); // lerpScore = 0; + #end var bullShit:Int = 0; diff --git a/source/PlayState.hx b/source/PlayState.hx index 35a8b9f7c..5a0989afa 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -679,6 +679,7 @@ class PlayState extends MusicBeatState if (camFollow.x != dad.getMidpoint().x + 150 && !PlayState.SONG.notes[Std.int(curStep / 16)].mustHitSection) { camFollow.setPosition(dad.getMidpoint().x + 150, dad.getMidpoint().y - 100); + //camFollow.setPosition(lucky.getMidpoint().x - 120, lucky.getMidpoint().y + 210); vocals.volume = 1; if (SONG.song.toLowerCase() == 'tutorial') From e30ed8e6e5505db5e80d3ab222b9c7f0e4949cd7 Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 11 Nov 2020 05:00:13 -0500 Subject: [PATCH 22/24] update to master 11/11/20 --- CHANGELOG.md | 5 +++++ Project.xml | 1 + source/Boyfriend.hx | 8 ++++++++ source/Character.hx | 28 ++++++++++++++++++++++++++++ source/Note.hx | 2 ++ source/PlayState.hx | 13 +++++++------ source/TitleState.hx | 6 +++++- 7 files changed, 56 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b677da3..114615a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Fixed +- Cleaned up some charting on South on hard mode +- Fixed some animation timings, should feel both better to play, and watch. + ## [0.2.1.2] - 2020-11-06 ### Fixed - Story mode scores not properly resetting, leading to VERY inflated highscores on the leaderboards. This also requires me to clear the scores that are on the leaderboard right now, sorry! diff --git a/Project.xml b/Project.xml index e7efe94ca..9dd031d07 100644 --- a/Project.xml +++ b/Project.xml @@ -108,4 +108,5 @@ + diff --git a/source/Boyfriend.hx b/source/Boyfriend.hx index 1a8c6cf07..5efc70987 100644 --- a/source/Boyfriend.hx +++ b/source/Boyfriend.hx @@ -3,6 +3,7 @@ package; import flixel.FlxG; import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; +import flixel.util.FlxTimer; using StringTools; @@ -54,6 +55,13 @@ class Boyfriend extends Character override function update(elapsed:Float) { + if (animation.curAnim.name.startsWith('sing')) + { + holdTimer += elapsed; + } + else + holdTimer = 0; + if (animation.curAnim.name.endsWith('miss') && animation.curAnim.finished && !debugMode) { playAnim('idle', true, false, 10); diff --git a/source/Character.hx b/source/Character.hx index da51e2321..813fe4ab6 100644 --- a/source/Character.hx +++ b/source/Character.hx @@ -3,6 +3,8 @@ package; import flixel.FlxSprite; import flixel.graphics.frames.FlxAtlasFrames; +using StringTools; + class Character extends FlxSprite { public var animOffsets:Map>; @@ -11,6 +13,8 @@ class Character extends FlxSprite public var isPlayer:Bool = false; public var curCharacter:String = 'bf'; + public var holdTimer:Float = 0; + public function new(x:Float, y:Float, ?character:String = "bf", ?isPlayer:Bool = false) { animOffsets = new Map>(); @@ -52,6 +56,7 @@ class Character extends FlxSprite addOffset('scared'); playAnim('danceRight'); + case 'dad': // DAD ANIMATION LOADING CODE tex = FlxAtlasFrames.fromSparrow(AssetPaths.DADDY_DEAREST__png, AssetPaths.DADDY_DEAREST__xml); @@ -120,6 +125,29 @@ class Character extends FlxSprite } } + override function update(elapsed:Float) + { + if (curCharacter != 'bf') + { + if (animation.curAnim.name.startsWith('sing')) + { + holdTimer += elapsed; + } + + var dadVar:Float = 4; + + if (curCharacter == 'dad') + dadVar = 6.1; + if (holdTimer >= Conductor.stepCrochet * dadVar * 0.001) + { + dance(); + holdTimer = 0; + } + } + + super.update(elapsed); + } + private var danced:Bool = false; /** diff --git a/source/Note.hx b/source/Note.hx index 748cbe185..06825e717 100644 --- a/source/Note.hx +++ b/source/Note.hx @@ -37,6 +37,8 @@ class Note extends FlxSprite isSustainNote = sustainNote; x += 50; + // MAKE SURE ITS DEFINITELY OFF SCREEN? + y -= 2000; this.strumTime = strumTime; this.noteData = noteData; diff --git a/source/PlayState.hx b/source/PlayState.hx index 5a0989afa..17ec105dc 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -30,9 +30,6 @@ import flixel.util.FlxTimer; import haxe.Json; import lime.utils.Assets; -//New Audio BS -//import faxe.Faxe; - using StringTools; class PlayState extends MusicBeatState @@ -811,6 +808,8 @@ class PlayState extends MusicBeatState dad.playAnim('singLEFT', true); } + dad.holdTimer = 0; + if (SONG.needsVoices) vocals.volume = 1; @@ -869,7 +868,7 @@ class PlayState extends MusicBeatState NGio.unlockMedal(60961); Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty); #end - + FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; FlxG.save.flush(); } @@ -1044,6 +1043,8 @@ class PlayState extends MusicBeatState // FlxG.watch.addQuick('asdfa', upP); if ((upP || rightP || downP || leftP) && !boyfriend.stunned && generatedMusic) { + boyfriend.holdTimer = 0; + var possibleNotes:Array = []; notes.forEachAlive(function(daNote:Note) @@ -1114,9 +1115,9 @@ class PlayState extends MusicBeatState }); } - if (upR || leftR || rightR || downR) + if (boyfriend.holdTimer > Conductor.stepCrochet * 4 * 0.001 && !up && !down && !right && !left) { - if (boyfriend.animation.curAnim.name.startsWith('sing')) + if (boyfriend.animation.curAnim.name.startsWith('sing') && !boyfriend.animation.curAnim.name.endsWith('miss')) { boyfriend.playAnim('idle'); } diff --git a/source/TitleState.hx b/source/TitleState.hx index 51fb8250b..3fc2b4ac5 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -38,7 +38,7 @@ class TitleState extends MusicBeatState ['Ritz dx', 'rest in peace'], ['rate five', 'pls no blam'], ['rhythm gaming', 'ultimate'], ['game of the year', 'forever'], ['you already know', 'we really out here'], ['rise and grind', 'love to luis'], ['like parappa', 'but cooler'], ['album of the year', 'chuckie finster'], ["free gitaroo man", "with love to wandaboy"], ['better than geometry dash', 'fight me robtop'], - ['kiddbrute for president', 'vote now'], ['play dead estate', 'on newgrounds'], ['this is a god damn prototype', 'we workin on it okay'], + ['kiddbrute for president', 'vote now'], ['play dead estate', 'on newgrounds'], ['this a god damn prototype', 'we workin on it okay'], ['WOMEN ARE real', 'this is official'], ['Nintendo Switch', 'Pre-orders now available']]; var curWacky:Array = []; @@ -106,6 +106,10 @@ class TitleState extends MusicBeatState transIn = FlxTransitionableState.defaultTransIn; transOut = FlxTransitionableState.defaultTransOut; + // var music:FlxSound = new FlxSound(); + // music.loadStream('assets/music/freakyMenu' + TitleState.soundExt); + // FlxG.sound.list.add(music); + // music.play(); FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt, 0); FlxG.sound.music.fadeIn(4, 0, 0.7); From ded18739e1420a6c40c3eb40fa8785944f7c8eee Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 16 Nov 2020 15:29:18 -0500 Subject: [PATCH 23/24] caught up 11/16/20 --- CHANGELOG.md | 3 +++ Preloader.hx | 2 +- source/ChartingState.hx | 24 ++++++++++++++++-------- source/MusicBeatState.hx | 2 +- source/TitleState.hx | 29 ++++++++++++++++++----------- 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 114615a79..9d899d9f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Moved all the intro texts to its own txt file instead of being hardcoded, this allows for much easier customization. File is in the data folder, called "introText.txt", follow the format in there and you're probably good to go! ### Fixed - Cleaned up some charting on South on hard mode - Fixed some animation timings, should feel both better to play, and watch. +- Maaaybe fixed notes popping up randomly at the top of the screen for a frame or two? If this isn't fixed, uhh yall shout at me lolol ## [0.2.1.2] - 2020-11-06 ### Fixed diff --git a/Preloader.hx b/Preloader.hx index 932df79b7..c979c9c79 100644 --- a/Preloader.hx +++ b/Preloader.hx @@ -13,7 +13,7 @@ import flixel.FlxG; class Preloader extends FlxBasePreloader { - public function new(MinDisplayTime:Float=4, ?AllowedURLs:Array) + public function new(MinDisplayTime:Float=3, ?AllowedURLs:Array) { super(MinDisplayTime, AllowedURLs); } diff --git a/source/ChartingState.hx b/source/ChartingState.hx index deeb34924..1dd6eb0b6 100644 --- a/source/ChartingState.hx +++ b/source/ChartingState.hx @@ -374,16 +374,24 @@ class ChartingState extends MusicBeatState var updatedSection:Bool = false; + function lengthBpmBullshit():Float + { + if (_song.notes[curSection].changeBPM) + return _song.notes[curSection].lengthInSteps * (_song.notes[curSection].bpm / _song.bpm); + else + return _song.notes[curSection].lengthInSteps; + } + override function update(elapsed:Float) { Conductor.songPosition = FlxG.sound.music.time; _song.song = typingShit.text; - strumLine.y = getYfromStrum(Conductor.songPosition % (Conductor.stepCrochet * _song.notes[curSection].lengthInSteps)); + strumLine.y = getYfromStrum(Conductor.songPosition % (Conductor.stepCrochet * lengthBpmBullshit())); if (curBeat % 4 == 0) { - if (curStep > (_song.notes[curSection].lengthInSteps) * (curSection + 1)) + if (curStep > lengthBpmBullshit() * (curSection + 1)) { trace(curStep); trace((_song.notes[curSection].lengthInSteps) * (curSection + 1)); @@ -525,14 +533,14 @@ class ChartingState extends MusicBeatState vocals.pause(); var daNum:Int = 0; - var daLength:Int = 0; + var daLength:Float = 0; while (daNum <= sec) { - daLength += _song.notes[daNum].lengthInSteps; + daLength += lengthBpmBullshit(); daNum++; } - FlxG.sound.music.time = (daLength - (_song.notes[sec].lengthInSteps)) * Conductor.stepCrochet; + FlxG.sound.music.time = (daLength - lengthBpmBullshit()) * Conductor.stepCrochet; vocals.time = FlxG.sound.music.time; updateCurStep(); } @@ -620,7 +628,7 @@ class ChartingState extends MusicBeatState note.setGraphicSize(GRID_SIZE, GRID_SIZE); note.updateHitbox(); note.x = Math.floor(daNoteInfo * GRID_SIZE); - note.y = getYfromStrum(daStrumTime) % gridBG.height; + note.y = Math.floor(getYfromStrum(daStrumTime)) % gridBG.height; curRenderedNotes.add(note); @@ -691,7 +699,7 @@ class ChartingState extends MusicBeatState private function addNote():Void { - var noteStrum = Math.round(getStrumTime(dummyArrow.y) + (curSection * (Conductor.stepCrochet * 16))); + var noteStrum = getStrumTime(dummyArrow.y) + (curSection * (Conductor.stepCrochet * lengthBpmBullshit())); var noteData = Math.floor(FlxG.mouse.x / GRID_SIZE); var noteSus = 0; @@ -699,7 +707,7 @@ class ChartingState extends MusicBeatState curSelectedNote = _song.notes[curSection].sectionNotes[_song.notes[curSection].sectionNotes.length - 1]; - trace(getStrumTime(dummyArrow.y) + (curSection * (Conductor.stepCrochet * 16))); + trace(getStrumTime(dummyArrow.y) + (curSection * (Conductor.stepCrochet * lengthBpmBullshit()))); trace(curSection); updateGrid(); diff --git a/source/MusicBeatState.hx b/source/MusicBeatState.hx index 791cd95c7..0d9da14a5 100644 --- a/source/MusicBeatState.hx +++ b/source/MusicBeatState.hx @@ -34,7 +34,7 @@ class MusicBeatState extends FlxUIState everyStep(); updateCurStep(); - curBeat = Math.round(curStep / 4); + curBeat = Math.floor(curStep / 4); super.update(elapsed); } diff --git a/source/TitleState.hx b/source/TitleState.hx index 3fc2b4ac5..fdd89ac19 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -20,6 +20,7 @@ import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.util.FlxColor; import flixel.util.FlxTimer; +import lime.utils.Assets; class TitleState extends MusicBeatState { @@ -32,15 +33,6 @@ class TitleState extends MusicBeatState var textGroup:FlxGroup; var ngSpr:FlxSprite; - var wackyIntros:Array> = [ - ['Shoutouts to tom fulp', 'lmao'], ["Ludum dare", "extraordinaire"], ['Cyberzone', 'coming soon'], ['love to thriftman', 'swag'], - ['ULTIMATE RHYTHM GAMING', 'probably'], ['DOPE ASS GAME', 'playstation magazine'], ['in loving memory of', 'henryeyes'], ['dancin', 'forever'], - ['Ritz dx', 'rest in peace'], ['rate five', 'pls no blam'], ['rhythm gaming', 'ultimate'], ['game of the year', 'forever'], - ['you already know', 'we really out here'], ['rise and grind', 'love to luis'], ['like parappa', 'but cooler'], - ['album of the year', 'chuckie finster'], ["free gitaroo man", "with love to wandaboy"], ['better than geometry dash', 'fight me robtop'], - ['kiddbrute for president', 'vote now'], ['play dead estate', 'on newgrounds'], ['this a god damn prototype', 'we workin on it okay'], - ['WOMEN ARE real', 'this is official'], ['Nintendo Switch', 'Pre-orders now available']]; - var curWacky:Array = []; var wackyImage:FlxSprite; @@ -53,7 +45,7 @@ class TitleState extends MusicBeatState PlayerSettings.init(); - curWacky = FlxG.random.getObject(wackyIntros); + curWacky = FlxG.random.getObject(getIntroTextShit()); // DEBUG BULLSHIT @@ -76,7 +68,7 @@ class TitleState extends MusicBeatState } #if SKIP_TO_PLAYSTATE - FlxG.switchState(new StoryMenuState()); + FlxG.switchState(new ChartingState()); #else startIntro(); #end @@ -193,6 +185,21 @@ class TitleState extends MusicBeatState // credGroup.add(credTextShit); } + function getIntroTextShit():Array> + { + var fullText:String = Assets.getText('assets/data/introText.txt'); + + var firstArray:Array = fullText.split('\n'); + var swagGoodArray:Array> = []; + + for (i in firstArray) + { + swagGoodArray.push(i.split('--')); + } + + return swagGoodArray; + } + var transitioning:Bool = false; override function update(elapsed:Float) From d6243b794e92c786c610e391229555f3cc37aa3c Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 24 Nov 2020 22:53:48 -0500 Subject: [PATCH 24/24] 11/24/2020 --- CHANGELOG.md | 16 +++- Project.xml | 2 +- docs/img/skin-funkin-cardbordtoast.jpg | Bin 0 -> 237156 bytes docs/index.html | 36 +++++++-- docs/styles.css | 97 +++++++++++++++++++++++ source/ChartingState.hx | 31 +++++++- source/FreeplayState.hx | 24 ++++-- source/MainMenuState.hx | 4 + source/MusicBeatState.hx | 15 +++- source/PauseSubState.hx | 104 ++++++++++++++++++++++--- source/PlayState.hx | 18 +++-- 11 files changed, 316 insertions(+), 31 deletions(-) create mode 100644 docs/img/skin-funkin-cardbordtoast.jpg create mode 100644 docs/styles.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d899d9f3..ee6e75211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,23 @@ All notable changes will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.2.2] - 2020-11-20 +### Added +- Music playing on the freeplay menu. +- UI sounds on freeplay menu +- Score now shows mid-song. +- Menu on pause screen! Can resume, and restart song, or go back to main menu. +- New music made for pause menu! + ### Changed - Moved all the intro texts to its own txt file instead of being hardcoded, this allows for much easier customization. File is in the data folder, called "introText.txt", follow the format in there and you're probably good to go! ### Fixed +- Fixed soft lock when pausing on song finish ([shoutouts gedehari](https://github.com/ninjamuffin99/Funkin/issues/15)) +- Think I fixed issue that led to in-game scores being off by 2 ([shoutouts Mike](https://github.com/ninjamuffin99/Funkin/issues/4)) +- Should have fixed the 1 frame note appearance thing. ([shoutouts Mike](https://github.com/ninjamuffin99/Funkin/issues/6)) - Cleaned up some charting on South on hard mode -- Fixed some animation timings, should feel both better to play, and watch. -- Maaaybe fixed notes popping up randomly at the top of the screen for a frame or two? If this isn't fixed, uhh yall shout at me lolol +- Fixed some animation timings, should feel both better to play, and watch. (shoutouts Dave/Ivan lol) +- Animation issue where GF would freak out on the title screen if you returned to it([shoutouts MultiXIII](https://github.com/ninjamuffin99/Funkin/issues/12)). ## [0.2.1.2] - 2020-11-06 ### Fixed diff --git a/Project.xml b/Project.xml index 9dd031d07..cd6bf48e1 100644 --- a/Project.xml +++ b/Project.xml @@ -2,7 +2,7 @@ - + diff --git a/docs/img/skin-funkin-cardbordtoast.jpg b/docs/img/skin-funkin-cardbordtoast.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd0e96e606b5fcf83f912e0a4e43bc05a9f92364 GIT binary patch literal 237156 zcmb5VbwC^M)-4>QMT*nn)O0DzCEKfuErKn8$;j{f(B zfqJ0=6YCKsDsUcSJ;K7pdGZ7o2NxF)pO^p-j|dMJm*6QO5itoVDd`h}r({n_$WZen zf4>Cn?x{r8Vv`vHwkJx@#7by&v|&IvEFECnz?+6JABH>ms`~_ z^30q`#&zWgn_r8J{QKLGA1}45JDCM6+)$0p0`M^YIbdRd6riusM#`Nj_)8>qaBy&l zV9s~+Zw#*@8Pd?18U8C?p#M+&uMG?gtpDux9km^&CDQ3KcP++a|8{wXzL~!-}kf0$t_FJJn5SPi=8Vdz0$4* zxbnGd1H6T(f&?npE00pS$Z45tg?(-vhKtvgc3N~jXsVs^>0gy&CBU&$pneC-UGn#i_l3y}~S3*|wij6@G8_<^zt zxUuo#cRko=wo)a(f)%;uP1D5-j_A+uWp+>f5}Mj1ldE}>uO`o3N@lB&eDbJNyDoo9i z+sTwT+Ab+?+-q0UN=A&yNw}{^^wX7^8Vk%}`OC;~VcqG~1)9d2W`o*i8!ds4@Hx9j zJb0C*M}CFg>gcTagUI&N({2RKGoAEk@71Gt{TpXYKxt-nh8rvFO`*ZxUzRi6_yN(B z$doirr3^RSG!W}sli-h)OBKfFm*(CKA~(Q zU}oh)?cH`;Vn6RKtr)A>)|Zz*ln2Wtnlqh0p^@~0LSOTB$=fBmn&){@kGA4K6Wr*wU93K2rv|%&HQnZrA zJZRlmo)%p-H`vuhU!lBaQnt+j`*G5AW$7h7UZUlKy43`KGGok%g|skR05!wZVj*XN zF{OXb{4?D2^_{|{k|d)IbV`wte7vQ7SC%}9MMyzEKeEJ+EFuQnMJ=TB;`Zwn+=H?kh`NSX+Z8WRG*-5 zOS~!Hs`0W^;CWaXA3pywx+lp>@x`o~U4B1oZ2C44HcNlHU|VBBr)c3xf42}6-{uFj zxeS%7=I3ovCk+>Dv$#<`4G@0}3K`<&u%nK$O8iRy^-$3+_6~JN=ljt5u~WbWAggzT zf3gh|{aaOH)P>3=4`}G9T6T6{pyOw&{-J0q96U_5d=HZ%jtYQ`8UglIFn%$#}}oQ&5%zA(s~;wUHT=>gmM*qE&jzLkc~O+8Bg>$&HANZMpC9aJDthY zdf=s(^Ajqx`qF8!KNtg1ii8$)_plfo*hVM`}A~a_f>z&2+SosFI zW*4ujQrs>;ij`eUARCf&t0+Mb(V13I`v9<#_ZJ7Pgdz;jYv8lT1hOd-bz3XOp$)s< z-y5Z_W3%tYO=TVcGtp=57d%(y2fk9h`*Azgxe>6tF0x~)d1gsgi9hjZ1+&kRC}Uq>$P-e3$;q8XeQ7E}gL-Y4qgBCWO7nFjmY1R#LTjCwndfKYGTdvpqjX{FzLw zziZ-5a3_HGPDSmOWA-@p0q{~pAFc_XfDu|s^$)l`0IE0j*YWHQpH})n6!D`4TmtiO zYI?I-HD=cM+Ei;xTO6S@Ec-pbtODuI=+!0z#Ft+6zT@A<1q&KsD1Ks6v72+BS?5cm z%TGwGEnJJx-S^(w5~T-`GojA)ze0N4oj$S=7SWiz=&H1T%$9VwiF>E7pL65MQ)QSc zzGt6TUU1SP-+3L_n7nnOvC~y;A{cWBb%Yj8=kCZ@@;saHG0<);ll|5de<&e|IP(w8fUllk!-Mrw6X=LAyrtJ#DG}tMuk@-K541BEiR|mH$eV;N>^Ruyf^-)Y z_q;C%9vM@L{QL}AR9k83A(1j>@FfwAo z#u7I>i6FT-D97N8kFMlr@+c#n?e~RTzXgp!56#VneYJesX5wgz{%6F=xt9Vf%}qOn ztm7~(uX7Xpm5G>NKA&x=m?*QZxeAiM-KeTLBIu}N8;V7_Vr=pxmapp7h6HnLi#$DRs1X*vVx z=H;{O8nZlCXN-p?Luu=}PHZQ*Q1@u4!)R)Jbs!X8RkJv2g&$q8lU<0ujCc3!%IDMr z0<_C4UAIUdJ9!G4a(4+>`_!Wadj~bdDPt=m#N?O8RG5|fDOLgL)RWt4C%1g1l&B~N zb;MZ>z&L-SIP%N&xz$rvH?M4#vvXxVrXy-82Tx%>N{xoE1e|r}v^Z2aAq*Ad8To8J z#aUC^Su{gqgVrK8@^!+7;MR@ClP7!z7lE&&e*Brbm2V%*_cY-!5^!Q9eN%CtsoR7{ zoQu`;8DyU>U=|=EKNb!g=BRGw5yq3S7qNlrrkixqGK8QF$M$bmCXO^-28rNkm9e?* zb|E#(pDdO#>UM8wX8kwt>eO_QRW{C5yUUT^6>87_cecBrGiYqHRe=T$? zOTFQTfn2^?M*amKGKoH~jUKX=xI$lo`C59^J=y5pZ4wZA5h zy|lI=a}l@Zu(!#16IiCozjwMohi}V!kw~p;Lk4NCAZ%|5D zHJ%>fQ+(Ba0AM>4Z3eyt%6FaZ6|p(RTp5oZz()q<>j{j4jObOXy53U_?N=DwUc72> zqVQF{(;J=%C&yPy?GE=Duke2|S15|X{L-yfrCmKa!QZ6oQ*Fw2S`XD|GV_hae$SE8 zA>kA{I$=TEz&(AC)gLD$O#nNOPb6n&^ScKC^M{T-ce**Caqb@n=$LXn`DQztzw+3o zRKZv>lh|TZ`^;Wx-mBWCE@gLSA=+A#kg4BQnM0yS$vwCMXy2*4MPrIm*A{J7w#hgk$Vv~w4pIJZS1Cy^g{n3Od~kV0JYncb0oxu%1IXxNl) zXG{%?9zS8%71u^)>3D9xVFlsH@gn!JP2%_ipxfp~vurIQ9k@nshol0+uj`rG;yO1( zEF}|Yv*0m|@AN9c@+R3(JkyL#nvK+qI>WIdb$U->Nvk99?gJolJ2YyrNi;bSrVn0+8Wk-P^lkx>Li1}^|$k?*${$1>LBextuvFKKp2hm8^JNe+Lfq%{T|Ci3Nueb zRr1qir;L~GQknD~K8B=9j`yzImP*93mDi>p0DGowpjxhBodOfiy%H-O?dob@RWW#5 zl!?@;5ENXG{{WD;iTBPPqdX~vpS0k=ne4MErtoCi+M0dln*XZRQYNa#=z^05;c~fm z-9*D>72d1y%z65&fX#PVL?I17PXm)<$;<*I9bzD)l|-=&e-z#_A5@}$}lSs9Hw#u&jN-NXIA|N)jsU0YjACGVmY*tt7JIxA| z(CC`mz7*G@9H)$xBE5)KBnnQS?r2-u9MdAttv=bYV0mkd88<$6MjT`EX<;nWvO*9N^fhflcN{UAf+}jePO-T{aIhG| z_Y?*Og5O`QabKf`){rvP&RQsl^7bA0IVKe}$%WN~Vuu2-b0*)eA?&;olRV<&){EP-SX+t zj38GXDXHw})R=n!_B1%HI?*5@-$TS9N?i&Ha+~o1ojg5E;5lu}IsCbYpLC|o`a!hz z^tffdA$(laYzN$hdCOu9-e?WaEE_B7H!Pv=yPAs@PqpITR_1}isA>Y}Jn0AN=IMUZ z&{oCm3m9MY?a}-?|K=$McIWP$iuH~?H%$-PS_(oCT5}L$k)N#oK%(IB5jCZYsMjF5B#oCf!Wtt2XrCBQ^ztP8Bq|H_ zYPkO-)Qow;b#H_%!fRkEa|?pRhgvc5wqFWa&qb+lph6;(qCLc7dKaYFR%_ zQEN)5>dd}&+ZeRUht6)%{|M(xNbX{n%k~uJ(I$_?7OTK(;Y5f_BW#-c%amE6@9@-K z#)MGclStF+jQqBl;Nv|P4|;YKt|tR|wGb{))s-YQ6txoz-r8-4@D}?7Dyx>}s|M5U zvoyNZGgUYx!pCyerrUu#X&ZKW2xXp>WD_al*f5ByltA6esz_naZ_jvl&-;*&sUayF zDPoFQnSx3=lN(z-50))VYuceF{X30I$L2TL-^(czmnPUeJ2gS!FrIg3yX?01#-we#o?kBCHm?I^V$(~MH1>5ix-NaAjqs-k zUG8@(uX+#2jxM0Io`fP0#Sz6W!uR!-HD3ta6_-@?u=H~m3a^*q12m<4;u4yDDjxt& z5r&&;MNmiHOl5b!7lE=qM%_NyKBFubyip3WzrY^lyOOJi$%R3yPK2&1TFR;#pB>n8 zW6)tgN9D3vO=ZT|-5U*D&!uQx3X<=nj1VJ-&HfV8XU%dA4ofrcbm|}Do@xj*#XJCn zMkqUu)MGN4e5Jba0?2p}T^4KPuahw#XU_C23Z{}1)pw6=H4b5A*E_);?Z_rts${pZ zb=beJnmb%bAp*K(|#7V8oFs{oSiZt-CTVSb{O%P+U0ipHGGWvPWNUi5#~ z(pPS~K^tect#nhf{LGX0V+iVG}*i$db%z5y5 znpMkzd$L9#96*IeTo<)fllu|HmZ;pDi)8dDWo5X)W(Rw;-B{Dh2rJu!f`!;z<8?nX zvii|K^RUutF20`PM)2Wg*-`3`Z(&qgs0dX~sp@?~Sc>|0=dg=8BAfXSo~o`+6kZ88 zmzePls;4i9PR}@6gbf}e-?y}tiK~&4{kry`Ca{}*bK#s}MGcvWIz}C^Axlak)krU2 ztVAFTu_$@TEb4M53eJBOw328nJkL(0*wv67lY@;XahLpk(mgBcpzz$g{mqr|+5wU{ zHa#nO$!sCHECNEme`iAR4|VcyT!MPXi*G0Nt{2ju+Lupq%gw#v^d#M0CgcV;YVBwwnzzhU(N=qFcA_P&}-!PTW1 z%;NAAPQ&-1H-6^YKjuqQk&yKwm)h5^_0kdPdQi*dq4doWl=R`~87E-eA_{Y`VETMc z$Edo>SEV8eUx~P`mSPRuf9&C7ItyVb9iE?KM{rj(j$Z4I+hc6+6U?CyPWaF%Z9aA0Cs8PI^IYVg3R9^*qbp%wCym&-_(>tZ)Lhu#)Ww3> z@e#)B$1rKF7tLhbbFuh9$*ta0{w~1;%wBGDmFn(pCr|0i-BVAI=JdghZYtu74K*=$ zY=&*GMkD(JAo^8lqi#!f*ptM!U)Cw+vozAbtfMPo9!EQ>zZw{Ddbc?pnAy)}!J{^( zWZ#4@Pn-6vrbx-Pj!Uw>bp5n6Fn9-t>3h1pg|xt1HPdUz^$-nW7PM*i454atRJuJ$7^*UpO3L#Sfe z=wha}*rmDH4|aLGIA^;i^@b@pIFBJX_y;ozdkCRulz-Tj7wG@3i?IH~uB74QFrf63 zG=|*}1>Dz>OcOjh(U_C(h@So%&^+x%NgM!A>6hHErI~-Q<*=fpk{lE}gMv4I*%?%> zM`0P%6cr&hp}oSha8F^G0Sp%=c2pFlZF zcVq?^RUI|a`8RlY$>QvXRPMRYseH_uQ;CB7T-PbxvVNZ*LuFIVOk>N$wkF-G%z&;m;XVYev28&;Fb}kjC97kI{)iofg z;Dx@cwMcIMhTVw&n61 z61+No#t&KYCW@-Gs#r*=QS3$izV6zEjm->*PWYPVtHe`W@=r78<1eL zkHRA&$8GzP0bPi_-yA<(VxtkuNUSc3;RtFbsK_D|?FFSE8rM@}37>_#;SfA46!|8% z_D;~K@r}lT?7=H5-m^6isubmgSc)n~tQFVLj|~i&R02E#vf^U2nvi?4+G?c)3)jX$ z?wHY}X)(#~hhD`^oe%;nj&8Hc2@0cmUA9!H$~iUCYW`7c^5}`qO%>8d!YS6>m`%#Z z5J#O*P{O-4`9~lkHP8U*omF0OaVtabX04SpHtO!)!Ps;Fa;I{?D)DGj@21oJsk0A- z!XRCaOY{-BdntJJPm)&BBRb5sSGFpDLlu+i6jMLJPl-O8QCpDzKA|k0Ny~hx=mf4! z>Tv3+t}XfssphWNUnzB&_oUkl&VBhUX4D53W%6qInwo{ zguuTh?7)kx!jbMW;blyj04yJat77Aql(I9!ZqI6@|Q{!Ts55;7_`A&)U_4fSmskW!gQ@j1Jt~ft*)EcZblXqF%i3W)Vsg9s^7Cn zt}$;4;&y`RB))2xXT~HhxEp%X=RzY=)OT^fC{pC^lhF>bHKMn)q#aSSyjabk{J!8=D=Gwa~LJhn`GqDdfUdz!vdHIdnmJx z*MqbIe%s%^3*zsgQU^;8i%4)lyV*8E4J5B*YqLfgJbOLP(Yzfj6KpnG4<_hT`D*!m zX&g^nU|8u~%1aW!-Mjdo0!O%s21}38ql&|4@%Kg1Dgu;tw#J)OrW#Kk0IWVUpc)Z5 zsSS&8!isHKB3ZG|P7eUkK6ju&Hs7GX3o^-l^X&$ms+U$plo{l0o#M-GbS4LeOg*43 z!d>6T&*Y@CYex;D>9C6 z=g5O5@k}(S1}m9U6L!7P`vI=+*>0zSsmDGr)5)T{WD#IH_yLeaKLp)47U&KT|1a+R zU$fF|vg5`cBuK{#i=2BilIVOo>oXzBApOlN9p&TOP5zu6j#Klj0LB^;cZ~!_pul+l z&TN5!o(5uwkl>svnf<80w0a6vde{bRq|-_o+o~`e(4*6h?Cily>gy{XuBJTwhYDS=qYI^EK{Q0^Nxu4>F{5d2j(yl z@n6%2A_@1FQt}(d%Cgqwj zrrqHb4TzIpi_t@dH%94C!ivnSi^B6JMRDRQL$4fu#108%E)S6N-K!D9X2wxnY}X~Y z}9<p|$3b(1vU|VC>+mFs8%iCkTRm>!xW{w%b+7|bG@||1nXBYWBpb_O*mYmOzyqIuG^4B%8m&Q%#W<&PTQzRZd`--F9do77yg=Jizo>%(oEE~ zof>no`?MUR4Po~y93;+gD55<)Zw<|r9HU%P)1YvK=Aige0)oVBUHGoOztCH;o#MSe zXUOqJTerZ9#3RD*F+%T>72}enfpT-O^_4@vY#HydF=JQpQaYXn4(AWR&eeI=X43_x zE=btcv2TGX-$K&#jVaA49mXVopl!lFbVt5obIYsV0lwX0T*Ocn)v+v;iZQNs>^4pInl0IDOhr0k&gL@L@01}38Y1ygFz({V(eUJ z;;X$5E=~Nxq z#>7Hoj~?$u^CjU2F(AEeX)%1;vt8~_HKl*7iHLuTLpa_uL+gJ=JZUeSFC`(}qupk7 zNRL8siCBUV8a&j+WtG#DH8#*jjwOo5E#diQ+k5Lwo{Api9eQtQLDhb;`gj*;+2DgT z0H2uR_uD=}Eg`88N-0K{2*UA^GqzM8Wq+YX$?0a6p_=%EO2Z+R(9H(`^|cB}e;HAE zI?J6Jg_VjAo<$n-wd}VHmL*q16<4D6ZqZ8n`QmTH^M}-b-bvE44EYq`E%QvU22$r| zuZsbBgbi8dT|KUSdEyzNqM?+djr)Xxa5f+BQvBEFblvs_-i&XcZ(0hqV-(JpOSH#a zuVd8;)Ol!E#060je(1hQ%24H<;aCdZ9A=PN%nur7>1HeZPs1_fBPgJ15^XErbGfEB zR$`MDW}m4xz4id0kM~fVm8m!6l4Fnj6}lNz3)#M#gU;@;`%L6`RSHzABRY>;Z3$(K(NOos^p8EAXCtvR-aB zh$5mXdtpg>w*Vu0YkSVA&xecQGena&F#K3L4XVYM0;O9xgpo&7h~8jq(O0*b>Yus! zfB2~Rj8YvTF_0H`XWuGB_{M0|U%8*aHpAjg%z~dq?9dNWhyvO77c>`Mi+aWWbimBO z@##*fD(=`*^0s`<;gv!nw3wR;_HNBv;kKhcAz@24W&0f`*C)WbNNk}ymhsr%N6eWH z&M6Uu+<_~1%XQUf*CKv24pz#su9+hT%X`=HO!?y?_9L|u)1yd2f>AGUoH6b=L>EY( zzlr?lMzfFw%b1s9U9B8&^&Cr+Mf!?=vlE4?;O;K{zd z*Kxp&P$(Q8v8zvwxiVQ(7*c9Q8OuVC4-(WUp?S8NMe2vh0}hF-45^5GD}71Q!s-lN z)ASKXMx3ZTeckk0OyXO4&}4~{fDN2?x98+G+>ZykQMAE(JnI5O0dJvILix!pwc=io z&TW@kdPSGE--q!$#hUJHYg6&Tbx=|no6~fQK)KeW`>fCJ^K)gww=G7i<6dw7$s_;o zgwk7li8fhs_c7nI2zNC8;>H5BxT=fyb)3bN^AkA6as@mW=G(6AJ7+xVBvL*1FdeKhx7}mB4D!N0P`gMajq8ecXdez-akuqFyCX**x5Y|0-Q{ zh{8&sv{lrDbtatF&kV&xo#)%POruJaE&q7(i{0!;k?7*HcrJ9K6CEYgwo1TpQ8kM_ z(EzH&8fVzCl{#C!yz7>XhohV$mo$^gKSR)4Oyb(V$yypEpr9m}|Kw~%9J=>!u~$^| zbaP7Yk9it>siEQ!)}oLX4Bx*oyuisJfLo*JjRK~~NZdEps2R3#64dWWg7SU5MX53j z|8jx+wSk~y7Zf^p#KW9}%I>JZttD1OQ}~CDCXzl)yECCutt9l8>>*09V0oE-sXTJE zCUwM>-EXHuk1zAu~(RHI&B!|1Lfj_Mt~KHo#@u zrF7JCSmE?j<#4IHi}&u*_dUt{R(utUsj0ntI*;^#IMHO>&1QB4@2#=eO3ax+N42@T zXlD=jW!kZEk<1}d?!EX$p*ZypLB^v?1ejJc*e=6%B+rNnGem(ZrkzvUAs%k!t@R#$ zqMaMNh@i=0;p|zS^8^waqz8G|%w6p*NOxx9Cftme|A<57Y%H_UMNSV>1u6@+K^`6M z)4I;p%uP-3aVj|1a3(-mK&F``dEyc%GroT#XZqym1kw-wa~7C>^IjyONDEn-Il(3< zt8~d0tky)-MNOb*8$tX4*Z}vPNND{=fLN6oQ|1WqUf!{W`iVe#d$ff^88T&ea8awR4V zw_l90b)Z_!oQv{2-w~jE2U~9#y(2ZRV*|RNCv4&UWUZbs{_xlDoC#JR*(MyA`|IZK zo-!pcvhrWa8oymV67~Az#mp6b0Z@#+8fd4fW_qW zGxb^Zf@&|akN2K-n(2ElqDn1(aVr~1-#>{@nW{d$X?60;^I@ChGn$DhG6O>^Xe3a2 zW2v|+Qmxd&TCmx5mx1Z4wh&Xu%fU~g^cyYrD0xJ0eYfN6j<9bZT%ep+pO+1#U)vcz znXNU|Uq8!2f&j7yT{UYCR$5bIZFhBm&=~2CNI}6kM^Ws-zP?M#OJ^bf; zsP4zwM3&(#`Z(hNda+^MI^&eKfOXRFppxxY0gAgbt`>;~@8uhU_|Q2Hx~w_*QS!z> zy#xn0o_rQd}+H zn20HKKq1svjxoXgA^6P^m4xi;sw$cT*9^(lZG3!Y;gbMU9M^vxaNia(9qhIS_!+8Q($B|43Bhb0vQ-Qr#(&dB7^z^PJW-&ZJ;dNk9?Bn=#>K! zK2ef6uS!VySrat3##8UNIuYE{v>pWem_Gnoa__Sj_6M=vsjpyux(p258ENAQU6-m^ zliJCX@T(QbHnk_SG~{$&P{+O3Hd4D#%rxUPF(j>-|t`(;r?^)>y@@VBY`z{ zmA9C*4}jNJWo7a=VkAL!YN{k&ob%ux+kcQKwut5Hs*|xVROmSNPu1P+JYv65h<9(Q};W77gar$ z?THBtTQUL($4S`OQbFjr5Fvb^4K76HCPJR7P0}<#9$K=Dg>=3u3Me~Fr z?L-l8@%}xml|6!rZMM`{vP_Sjvs%crmT;&DJhi9lpO4w~+ z{sumG^6YVtG0S2z3O|$Bp`XcG8Jui`WuGjN3LXrbA_&RuPftq1!%|@Q*IA?w0QXaS zHn^}Ehx6&)?O98{OSb&KGQ)U!@SwzLBuG%`y3MB zKb{TjC!X`&+^*1U38^zh%l8zh%{{W{o8Q~x+WWq{A$8^cXHF-)3nmCd1mSEtYw5KE z4CIaA_FFk1YvE~)#$ZXomHHT8m3-V0mjIy}2hk5%=_Cc@`0{bvPaqb8@jkePv&E-* zjAE*ER?xJ{=fQoHS7z^!lR+g|dLcXI*@)lwgM-ISCzX~j*xYez#o`eVHLI=>D~WWAejc;2MPC`67bod0SJ zFHq?fdp1M?W%vARe28{rL}ly0TEPoeg93IMhKj3qN=naN+j|rm8lNPhTokl%s7Ee3 zQ2F>D_r%j4gGiKgQGoi7L>WC%g>N;^57bxwM{HmX`Kwnjym;{qC0hIwfZe|YX>bVG z!h~ij{F~P!BG{9((jdi;R~Z2}TwOZP^Dx#s0N+&PTYqTenkx5A-70yDpNQP>xXamJ zj6*}qLW|ygH;yRY_{8fD=#Ae^>iKgLsOD~P+{Du>xohH)br(xVud^VMt;|HF(leUO zZ^sbVILnVKC?4z8r&69gV|V7~>@yi~Zod-^#^0<5LcvhCR$+rrL*ZY(FZ$W$e#}xA z`$e^3BINGn*K9<_mv>UyqU|ZfhTz`IH|+B(e&>vydrL|zYG3uUe`3rnp?v#QKYrER zPuTEywsP()aV{<=stW&GgE!dR)S^rimHzc)zpq)%Smm3dx3!8EWA`?UR|&O18h4pl z8wnVAHF(OARC2-JAAh~Ha(jAH%j0rlBm~(AqUJvkOXL9%kGf%`5BKWs zzDuR+gO3P{PIMn{h}_#4@#LY~efy9)9%*ngxWVRCY`(RAX(ijQyze^PwLC0Yf|S@V zypR~0802D#A8MLvoQr0pn4`$4L|Om;6QRh1pF>}|imRo+Tb|iU3H4K{?mqyAas*wZ zS{A;Zr!faXp(FkEgd4M!s+18HlwD-+@eE|8Gq~xj7JIw-u54+7odt0m9A_WI00K@AF zt>j79f6&oq+eJ0uP)62(flFVDSbC@}%rGEF)U<$`0=(M-5?|s44L~Bg6wSPOkp8a$ z7xc1tlRuO5>GYkxF47-6l-cS)#3P-OQuGtYqnw$57s+0!mp{eWiqn!XY!a;Y?Q|jm0FeiIMzAopg;C2;>mxt z<5b=SL{-ELy+@`xQl8_Q=b9B>rgGzbI>BvaRExFL)84hel38O*;}jl&_aD5RYMa}O zI5`R63qM?fa;Kn$LJ~gcM^K4m$(XHqi`o^L)QRA=SU5CDNldI}8k9Mv>8uB}lgD`X zp9giWRL`c?zxlABR?BM|*{S7UySr~NR&~WiRs@mb*?!e?=J@D1-k`u-L_)LR(qaba zR8KzGR4;EWw_L$?)45Mbu7wtrAK8@>@B;hZ0-29v$eyT|OLe-gW}MP$o_=^I{~dj0 zL!-Nz(III3+3b3W>WQM6minMCPb`q7*Ua{Vi-+@Bw`6?3f;blk#J((mH_UqiN)@-; zW3j4Xa=o^@Jq0QDRlh-5c46FoX{-$f0DkbV6+lp;UjU)V=*ZUk9QpbI8;!`FkoJv^ z@ZExA`~3lplvjxb_g?qPl2X~EHrY37W`ZzJ5cQ9%G936b##iUdmrmV_$q#_g>p8yu zA}tSbJ~r}|s0F4mG0H3W)nX8E*zzSk)~+MT!~>vs>(q@T>0~Z_aa}ik1jVjMMr;`k zRq(ll!mYIf1chm2KP;(|kzmHx?Bp2wh-az{D4VaiU=jT}HL6feNj43q%P=)^7mCmq zdIKuWPh4UBNo?nTt794q31(Kz8k_O+&r*st5U&dSuuAZ1Tp+qT-vFxj*?G4keLTSL z+o?t6;1JLF;a-^Ln~L6@8jtYZMx$N- zA!U|Xgo{V_Sa*xj+Wby&PnFa9naUZ8FsOm-!^l;`kJ3vk>(WFf?22k?gvacnK4t!~ z^%%~4Q;}0}`n2I7lGV`BioSnmZFY+{s0OUN%&v8FbJ!U67@Hr-3zL*s6u2r>W>=l> z^U;|qRFV*!;J$FUYUYUF(~voL7&`VHUx_`T5BK&4?g4tg7J(%6O2=-iwAOEQ@SKr5 z^|aUbToBG1CHE}uVMo?!1bOOFQ!Nf2-y)7qKfA^@Z<|hyXkBmq$kJGZRo}?+t@YNe z+dSN715X0_Zj&tX;yd8o7MpMR9)bAEb#F#WYN)?z+DPX8j$*z}Ioe_` z&V=48I8ZTpoVPJ$L9T$}rm7RM7lwX# zbm2wiNI?2{1*gZXR_zp|&JD_##Y9@l|oPdf{^i5c`58i%g(Z_WMTjAx6 zMHqLFuE=L3nhot*`*X9t1P58-{{^G}F4$i?6&@|HWSad{Nop=MuLL*diDJM!n-}t| zb;jApb2SB6&zComX(oDFedF*A#+H|7ZFKYWw%#sN(_HP_yOL&~3YWx|yN3^y@^EbK zO?H+({)|J6H39p?HM&w`2qidL70!GbuAQ&<+*1&o955U`!Y}v%Y`YwVV_2hapVhzW z)u>Z@ggf!-FHgKO6}mx4EJ}PQlxoghTO@Mj;T0EA(h^#h_v`G@AHGJ(uez5~Z=KtT zVDI{SYd{w%o+~#uSyE}BL|24tVnog@!390C!R>QV-iC{v+n64NH!w$Sxm z!Xz~?H+Pg1#lH+621=J83l90)cCvG5;c(*Q;;W!N#V_qe$ECtGyy3*%{Gwi-M^wP) z-6S_#u<5&Jf4(L*1)4(()SsI8oYgl5B=MM~E_y@+PH>+tD%ebuHd5nzm_$Y7UnIV` zyhywj`gnXML9rGwReL&-^G!mI(Ghl8VRU6jJudzf7`NLEibH6C9VwR2z&{&M!ZsdnJ@?2&1;Nv~!sq)`C;QC?EO!~EyvLcq z2S7@Rd_~u3$98}D)#`#AZmA!^pbgd^4Pp3<(d85@HWWG{VR@bMSTGAiz@|bj8*=0V$GXF3BZ1pny?wo98{PWmeNAZiRc0pJF>C zS>~nIfDhfPzGD~`qm#&enwJSmfAFk;lZ^S#9hGQfV- zPzeHBoFaPw5PIy>r!dl4_nkz{rWf2sd+KG36ijOQ1@62{ev0-R)PCeQ@J|gE{({<*0$SQHJS{BFw-dJ|juvB;H%O=fg9@00E}kkm@j2og#Y! zgII{XI=r99u#tS0_R+{?;Fs+dLA|7%Et@jqx={T;${Fri4*=PNW1siyg}oW3-!H+2 zWhKaGd^#vk8uwvG*^x|lG=0R37*fY69qgyrF-(Yl5lNTxA!(=7zIbSJEeX1J=$)JAI~gQg!Yp(H8MLQ#y0QSTA)F@l$DHXO*3j%i0Bx#H{SxdQ5he&5~`rC`JV| z6?I0CUhv2Lw#7BUBAlqJ0*~j;<$QILje7N8mE3<#3C6lI@+P_`5bP*Qv^!tvFA#@Tafa#JiR z_X>lsYq5SG`+J3^MB9XRg7+)?PP_+1zR7F>EFbs~@RXeCf+6w7V7p5d)RT`mn$ay& z7VO=#y#^XvZoFNNgKZV@mGHKaR^wz1{v%+=nj-PWWIkc)qBMqsV3>Aw&0-15y0S?w zHON8TQP`sik-ev(nLaze#&oLUlj3_pG&4T?I{r+jp9NLXe?RVd1)uLVEEx-zsuL6S z$C`C2sB#QiD%zkBtoDk9z8 zDhd+Pox%dr-LQbP(%l`)(%m7s!Y&})ARx8$(y(y<58lu7yuWvz`M=*84?8>H&M=&F zUDu~B3u^!G#VSD`=LGiyl2D5H&4$HW*k80YXtRl}z7;O9w*QiR`x5W2LKuHz$_?e{ z(MWwAwS;u)#*&FbDl!vpaz5{>^ZqV{Rp(=wUlAuG>Wm*&kJ{yqXFCE^0cC7aJN#NQ zslHA=fTwfa#;OA>b3Di#MI9^m4*veHyK^>(r636wcuh+VaNRgU2OMSG(&Nv#^`z+I z7ii5W3U)bP#XL9XPk8tWJyT9R$vwIb{GK;RB7PV<&iZG9L&^e+PUk6fQVLhZe*3A> zdY0kG7ubAU4e5YIeg`;=|2Q-u!QwAhFv2Ko<4t0L2YPjl1C*CD!im7V!iEWU)s{_i zcW-SVJ!m&H_&E^X3=MGu*&SR-LYqS#jL%3>arJKtkOcN|ipO;uLppJciNY3tRZ!Nh zs)!|byteeT1uG7!0X5coHFCQ2L{a|pWeuY%4lk|0E%=mo={{eV$TwxA>8e3SwSK)Th3;YrRdt@D3lN&tl}IxBNxWPzK(I9kgeGFs2&STc{>%4BY$#r44s62nvND zi9U$*Or9eYSD!`aq7-SaoFF4Yn-3RY8}Lq*0;%CUuU6huY1kglgIW!2d3b0J>T?ja z>b+cVi(70*T=OZCd`BL&s`IzSzYG!}jn#drKg%~}x+Un#=3Jnn7l-zY4E zNGx;x5}fj=IhD^KN(f}tc_H&tPN4gwY&TL+ZaKti$BaZ%Nsj?seHJxPz2+`3+wuxD zeev3?Q+Y4%8-y%&HBWCYIL%hTz$tVKvLGB)>p?aA57u|&8br`23IU5bRX|C!nOwBX zscauSqY5q91s~J>gJrM1JaDF(An`7Xb=FWiH77I5RGtmK6mlhY;;GrwLo0Tgxb
Me`~;wYWo{xeQ+ExR-(GA&It%@mdkky7eYmEu61hnS*!r}!77#RsD4sgLh1)j zeS3Qnv9AvtU79sbO*tetY2}X4ITfl<0KD=RfkZ`XhWO+@f;>Al*-UkDoHu}cFHp!k zeD;Z2NH}`3(|$$f;e@%6fwo56vbctzzcNyFYzsln*-dzOe(IgMkz)3gTb|Ea!AK{A zK%6GHK)Pu$kr!|LG-&gS;8?_{w-ZYOEFDJa42~28ZYeKAkP9tDvnLYTyFroAjZI@l z`ON`~(>jg*x2TD8lgPYbhatQUx(Ta zJky$l28#$R7p{Mys@gq0ZBoxazP(}ouY<=GS$xok=QMxs&7MMN+6*^qtto{R)kAKS z^+}c+jUuX^j;wTGbhD_B&7c48GltsmTWwe+Im4;xmwTu)yM_^fldYiDYCTc;4Lr2} z^SpvL#}%f{ckfL-@_jFdCo48N#g4-4GkVb^u3rSxAdSE_<-3&cAKl@?7wqD8u5Ml| zNK6=adfdGlRx#iW*=B_mbj%X=*0za8 zw2xo3y`)NC)1sE-eK74N6!}fST;>TC^IAgKmWe) zj*@{7SKcb}kXfGXxRzQ15O{rl<*7D_OfmuHLC!}1zW(a$)$4b+j(`BVo@N85Bo0G7 zfq*A6yAKkWqOU_;qjPthtCC#hlJ4Bx{LI`A9T4yW5)8_IM)dydYQTmiu|OFI`{}TD z0JT|YOc(xazJCz_h?~C}CnF(|eQyvhQn`8Lm_?SgwEFmok&Q^$aGCYn6wiSn`edz$}z{w?+=h11L^(j{qFE{#yt))68b3Le+Vv92v z&ONUUrqaLonk_c=R~e{s4|j|SkWO_quRr3O{2U>8S>&wZ!Mbs0TiY`6*bP9-_avZ4 ztd&(wk@ud3cugBnsKi*6-uK^Jd_|+?>S5U=+RM=cjU@C8Q~NKf^tK7uG9Wtd{dO=% zj(N=&+4CoPAZG#=^7xWyx;;7hB67Q|02MnhFyqGMPAl}=Q}nHLA(X`mPE_%}E%v(V z0OAq9J}r90(Y=Z;K0Xwb*X77lt|7MGFXeEMEwz-|Je6SoQmq}HX{_ztW0USMM@_x) z%?D(JdH1uA;zWEavReY#Wjs3q5pa950BzJs!NfZ`?;akvV3>O9YDG6>$QKl}Y#7hM zH|Org7fzgldx?W6Q!(9OSK?)UY;99`hN9L+F_^Xv}xRj?FZL^rcy-*RxbM z!ON=wR20#_Yg{R7A8H-d$?633(~Q%<!3;T`pEW*q>@EcZ?Tgcfv6zK^k$KBW#1oL+%%3m2`f$vb3yqVSB;w^NAwDh;;+i& z`y3;17gQ9+*btl^4)DM-RW&8y_Z~r$a+pu( z6qxHEsvJ-glv#M3o+Lk0Buf-?jJRNvO-f zY`dfO_k|8<%k*aIgKPms)9Pj8jpkwTg3$$$DEKP#h(*DNzKlJ}=;z*br#dsmhXqn9 zaZTA<6MU>E)NO*RQ;}5d`V9J z>^2kjpVZKef+d(~$=eX`b0(yy$Lx&~qg4ZU;!QVIQxR~UB$$+bY&W&IT}!jBX!pr$ z8Goexhw{Ae+}UbMk%-!8I-98x^a)ra-4sN&a&4$k2HjvbMY+Oh+S~Tr`Xb|cPVC;9 z35quIoqq=p6;2^z7e0d^ybo2?5VGwC%3*CkJO^obbnzI+*m9T|SjFaUgm-fidp zD0lfE*TYXAhP@#=mkS{}Gf@19bfze}a1phz~?ph$nAhrySD zrf%Hyy=94;QrWq{?*#{RT`(&2!BAkZh|_s?Lw}wZ$7bMCTmeE)ew7t=9>sBLqsm3) z+O^|rP$;eSTcTdrj=NL!ON#1~K$tv_zG=Rt6hf%TP)hlf`PY$z$vER=e0>*pH(6&w zkp!Vm0ktIcKy9YhX~yjD&p}5iQj40qU_*_NRFpiqin9VYTF}gRm z0U?8`nZ>uKi-#ftDtwefbLCP^DGeOf-iB|{y7^M&WvAa`mnfB&)(_-$hZJL~(|En+ ztk2?L2DXN7pH5Rrt_&PilEBG2cK=SI!0_^a&cdsp9kC}dS)u8F5F%|o1^tLOE&&sn)fs<5h^v| z^Au_~KMr?GZ{Zwl_T?`7lss<+dKL_cWG!Dl*xIk|$sGW<~!#`h^{kc&9?k1xNHZx^#I;kc4NQFttVA<5CV1wer0&|2MY;ty3wyM?51j{JoywYP*XET2?Ybw1nv_Q)-^p+Ulvc!FtfDkdg=3kR?xzX}rgkhanQ&PP4nj?eB&^@`F- zcLQ?i~zRQi?%T>}jq__E%KoFPE8p(pb(gM@kV~w>}52Mup zZTJIDE9D0^Z|XihjV8Gt{}rg&e1Km3$s5)8Z#8ZeXwfh6a*gla^4hnwHa_12<^Qhp z?^RW93;SDoE+DoDU+1=I0M2WF+*=zTaQXY<7ThSjSM3k{G%#NK`QyLqV_@q7OI);y zQ5OC-8GAx!2C=A&!LTg(kC#JLW77VjQx(E8%tpOw!(>D20TciM)(I z=L1sF^e0SXd`v&)7wIcSiVwqc(M=0al==bnximHZ`SOuD*HdOA00IsxM5)853>ETh zoN#yE&U`?o(<^8oN~lRk{-Oeax-HLLdKFus+uJuL>={=I>5C&n0&!+`iHrCR@SaF{ zVH!-1iN$mZCur3G7qNZpDeGN#u#*Ix;g|#AOo<7Nr?{z`^70TwJ(^b_ZMhfF_dA-f zoF<*YxUCoeczdil3yeO66|C3Jk5^w5&54RPw`ES|^%xR4Ed<8d!<`=i`ooH9uh@TPPP%nS29oX4PAI|2uQ zO51IchpN-Hu4@i9w7*B(Gc3|Pt~J>}yvQtASo&R3CB#Fp^!5J!!R`h9I3(OzC$PKL*6YGLKYX$L&B$s;kC$qs0Qotu!!RX6uk6gZr zeChUyQB2++KvOQdUO00d?D~918+J>W!V8=feMsmhjgbdQ_t?AA*_tT%2Uh?QMO5m~6P$g38(Q%+c``=#5$-D1SSj z2)h|GRS<9ZC~(*N)5?@|M^5uT$RGR<7Fd7Dvs=(yl2+#4OEU0|mVPJ32 zL<9birwb?2_ByyRR5%B%ND5!&TL{o7cg$WmeIU@43mpHt<$e~^!7{Zav{XB?zS~`Q zu{1!8kN7Y_&+KrOasr>(>R$eR95mrh#*7_)x(@-n8_Y_^AS!I;k z9&*#itxVAIVasu*K9Qr(=kL8mE7B#t;08=wzFh${cRPfyIBTO~Sn3imsQ_1Bsgf;pvpz3c=Tl`*fw<0sQcXvp!DW& z1j5C+^X?qoE2Q>{m>S}Fw7D%SKDBdA#dVq?9%QE@=o20pgqTZnDU=Qkpbx=^3TZBcP7;z8rpLD1hph#av4_1! zII~Y^ba@Uz?424#v+)PXQi8mKbL``r?_GCVgBzIC2BpN|n^CXhnbvA4C-P{j;;S(2 ztp+v|>fd^l3TDFDF~>J@G090ho0RW`OkW3CwftYx^uGoAs9PQjedrFyk+IM3p2aTE z#9Y;j04Qyan6uxf-iHPUK&XN)4Gn;#+%<)fjdxhpa* zsL99ClSuAk3uilkzd)2a9qjdv8>N-BHu~;9S{gCi$VMEjOC@;UvFZDtvG8sW5pPw&8$5o2=ewmjQ-`lz3M)UF9FF4Q~1RqJOX+Xa;1{ z{z2!Qy0^rOR-i~QvLx`;uv&!p1dWJF__`J=f>_0PzYh3}wpBQ%}4Po7_Gsg1$UAF6|hu&dD_hIBvr% z8^I$=#DH)q9N1lQ${&b`4I4FeX_F9elhom!n+tIHw7eUA+UOgguRPIB6-&IcIG5x2 zCd8YutK%{LLE)1Du4ZsGciDjXyq^CjN4jR!fmcArFkrC13!nk!FDH0aZjtgkGapHS zi5PSY0e!<;;NScE_W^iAL*7=F*5X}SY@1AP(Qk<;5CbG=D3HP=?zZov| z7CD5zIK+#u9B00U^Rp)XE@|W&wx_LNMNvzr?>Yhl$P|Z}c*wdf<8Lul$@pSffsqry z)Op?p%Bvl$w#HHV%<|c(^)-kpu>8fb6|WHVn)Dj*O7+dgEaAlVe>u{o96_2|f+>K> zeq*uqid8Kim0Ur5mhw2{+_cGATgXz>(dhZtbfo8L=A%wX8{xZ9Tv^EU-W1ZT z`oercr;wz3E^=6Ti=)O)?c`q3_|OB}B8IpPrXcA%CG;cm_~nfj5qRajpE+-5cEbNKARKDFp) z=or#ReayvTe9-dAy1G?B+S?X|kk#?1mDas7n6sgqV%;eR!#oM=**Wr$&jt}v4B(U3 zj;PWNHiY&Z9Gqia*cqA(K3tL!umRmQ_EP?3WQEKL(LMfd9;6R;*{O|tC|!qf1!5`z zKL!TE5zrppLU~Z82xn-?5oS665vr#uat!A;N>V!l$ly;!Q}cNKuL-QBdN^`_l>qb! z<9P>_r3dp2^@Mzz`EIzw%vy)}ke{2i--8f4y+N(sYGxsu{z+eg5Lq-Kq2eqCb zPvOT9s(#(07(|1Ajtk%8b zAFNG}isSZat51~NmXbCTy*1fWXv4RAy%(h01qhn?N%5X|7_o$RiE<1&c4Mt_F(F)kL%Zb{zj+{MTuN z^wf>y2o(x+DrVwm^%Q@-v=1zn1;VLV^;lV!!RDd2T#4^-?Tth?f@G!V{{NgitlZr= z^X7pby5VG6Uz)5T-Gay>tlu`a^rt^(-*;-wjOCP~)Fg_U+Mm=cjAjZHArGudlJg%I8Zn3>k4Y85)LPxttp}~*g>!iY>zbSDkL2LB*~7I z-)>Uce0j_(T84^&xma=mvAgHOdU?C1L1keL!u`cYj1=GFi!Y+FMs>}(6~1$4@BP74 zjAY0;QFz%OF9W8ynhJp4U!aPzc;--78A;4W*khDQ-;TaB0?v&aUGpy7{~Y#Y<7@tG9P4ntJj? zHrqbShLqn0W(J$U2pL5+CDKxhiO|F+%~$mJXJ_@~Gu)^V_xLy8pz-vSAEH&pYb}GL9^zKf8bn3BzWJYzGlU~Wa zZ#E2zKQ1MuX@;WR9+GwrA}xfd2dm2D2wYDAwHV9?u|P6z3sXrXdzP@m+&1i@_sq(L z=lmm`Q?0A|>N{=^Yk*|CrV-;OD5hEAEQBiPY1 z!}M+YHIo;u!xC4#CqwT5uWg6`r}alylD_=Y(=o#n;D1x3&$vzPxzS(TYj_Z~#k$SX zBOWQh3|EE8;|R4&W)Qx<6GI1irqRES+L{3p2MR>p&iI}TbiaT5S_tXx^e}my!YUx! zU&Q}Wylq6a=f>OXe4d-ceB^7NzKurGyOgLpwhH;Uj+C;Io&7;KZqGGKy*i;v%o4|n z1bwPO9(x)KdoUDGh6>Ir$=&2#Yth~skW+4KVqH{fC zv+u2{`&-OOHfd3%PsOb6M+ti=c_y2*sjEE-KOKSNFoq%F!+u6Qy4Zb zwij0GjZ-N1vG_g*%^@bMNRap@`DE9T_h?>5my-8zy9TlmRk-7Tiqh1K6yJ@8n+eL7 zhZV0DkL6-zsn*ebZ9Y;z(k}he)Vx$yOZ)V92ZN_~`!M+^YCFCK-8~oO1sa=f3hv{f z@q>mIQZuQ4c6!*x9soD3$~R*63X>fKa!vS`bS|E`I0&%xn z4frsg;SlTWbAQDN=|WA%M(>9@+v5Bsz_Oq@q?|)lEcfL|Rc85GPQ7eo&0>|+mlY&@ zo^<-H?}WVK>lU%d9Y5He36!U0vgq*-@15asJ z3N}wmgVFSTKkmuo%qPON;~h8PhU=@8cP+;OYK1O#kAY6FK}y1L4!ofqNbsy=p7~4s zQ_^|Nu6GWH6i1|}#la{vWI_IHnW^Q9j>{`6&|#bt*_gWpN+lRvG>P2|P+_|4RdWK!2;(RYQXtK>ACgG27EkA)crNTmLOWS~5 z5(1;(lr#iC^Po!CTT$3hJ<($rXR9@3nDk;A0cWY?5Q24PUd3TyCC>Li$pJX!^HoD` zB?rROi=(qGGUrU5hY5&w4Sn>BAdY48Ld)5C6(o6>*_IsnMNFsGb1zZw#wOF`bR?ff z&*!JDWNF`Bq-s)@D$>89hp?2p~rLHVJfY)TdSmKj?+32!pZF`G@ zZR^W}l_;$fTNY3XSDn3w)yx&~l7nrm2+`HM=`ly;3LTXsGa_lqL-kKAa?qr_38DR| zO$Z&pFg5!%*W;Y}0feL(pj6eql&(0B<&iY!FID?piIc0u~Vg}wlo=6KO^ z_7wKPd^zo0S@FYDB5LBm8}mrsXqT7cQoW+pp*sZy6d(Q*fcKJ;3Aw6Q^v~a&dFzK+ zw*IhS>^ zGK<>%-WV|8^NT0+S2siiO;HN;(*Q z4;y^bxy(ONpJN>AGGv8>McXi5w8Wu3YQ0l1otF8_Is?5k8ktx9(#Q=V1x>kzXSM%U zlK;5A)s^1MuWL#9^)@&;NB zwyBe`f7f7K{C`oXcjdjoF?!y!Q)R8+3MIEnG3-VTETt7A#K-jY{d+u;my=fKuA&Oo zEVzwFNm;{wnR-L5;*0fFX1w{YX$sX(>$3YQ%@!oSH~xd=p%Tng_1e|Kd<>Nb9$WJ+ zSB+@n*98T3%uJhhSnNggDI4{)aQ;x^V`D3M(@b^s$KUx{gEel{)VpZY1$>qyO@pz= zEZ7>ZoP9J)giJ{w_TA}gQR-DaccuCSBv6Smn~oTxoT%eC05q-$Buu) z^I|gG*ZH`(Bwf#+OXK1j1BDuB?lfTEb6?_N|A~ z|3;wxz5}S^ZvAe5^Y;ELY%etxw+>sJg{2ETtsUO2Ts-=Gkc;bR;i)=e1n`5AH{N6) zNai+&itNvj5@kp-4CelT_dkM2ssouW3Zza!yy;V(kyMxVyB=ncQ=a}qzBJXBgNItO zM$zVK<^mmW1yX8ljqwY$-CKR^`Xe<|S~zs6Igfoiu0#>V;sZ3g(W5SUwaZ7c){sw3 zf;d_WIxcjYUcS%Ns?lLTH!zu~6!Qf|3s+30OUk+FgojWu*R@0%S1m9V8qu!b!Rmkh z-V#tCav4gF7wH2leI|B#kz)0t)kPsyzjU0RM?R&7IilNiyF^QRtdAZsAKOZBcK$Z6 ztX(-&WY7K~@sM)s{=wbpf}(XsH%sFVxf!mk|C53dE_H1)?u7fr2a zJ$>93CTf`Of3V8b3zzbonSlW24CS@+3PgsmoAQXo!Zo_PWSO?qSNcJCpC+;-wQ*pm zMExJEZx{fnnhB)Cog>@OS5z6Y^Z?wj>Rjn-t5H*$os;Jyso-X(F1-)lB^0`N-}46u zpCxbWKN!4^N7Z%2Rl+#gET%Y>ZV?S-$BWeD8Vri=roniLfu=Umx)JlDB>>fbep{l`26?QefwIpGK8~HC|DBcfB2v0 zF!t$HLri~5ht&#qb3o%ZT;>!-I!FB;O6qI6r}G})4O zL5aJl_{cWg$|deZw+UaL-56N4#WD_#8MRW2Z{@#e|D7YbH|;4;Rf*lW=c|6q*f-rl zJ5e&K7N0&9I+Mmdl!~lUFBXpDjAs@VDi3(k5(SYR8ye2bWAda8339APqMn-fiLA2P zUmFq&t?jY92K|W@_pHd2Fp}a&S66#~M%093GtC)Q@uEQTn^OS|BigbW5GaH5~Xe^%tZ)09p)9~OG(^mvPICaNEO79pr% z+Rmx=-6or5xu`K%tyxd&eU`-w_iGg~T8~Q(zwLnze0Un9DhYLBSL5|SSm@xpZ*7T8 z*UMeXx0yHd>_Z_pU|^lnnsfCclKy1VOZJ#JR@@YRopRJn$iNOaJ+I^?EYg?Xyc6?0 zLLuyrpjqxsshM}Yr4oj6Bxw!PWZnJ4wz^YjEk)I;l7A~tKT3izB|((u>7oFFw5NK6l zNw637TiYQvQId{7rH%};$~x$9MH5Zq2Zam^By~8R&hK#ZMpNYzQv*@qh_KdfOta4gsdY~(kC_(nbFx!+rR{!GP!5Z#u5Hptf zh>S0xIkwd8s*dd+ER_At$CD-^viPQ&$LC^H90<-7DT;V*)YDCs&wi9kc1}%~c~fiX zT63vchneJvn14|K>=u!sgC^{|g&dra_?b!&iTDq%JVlX=ym;uSnmdE?MqP6he?>&O z9+mP^b)mkvF7_bqg^!yMki)B@l06cztRgHk?d`FpqM{=w6~EV&mMO$$ zn(3}?!F?wtO(iURY7o;*E8EKsyH5k|m8jHR+HME`IU6yaZo}3bP-uF`KcFR70${b8 zNszL`co^xrHlc7G^-^T!tKdBmU17YvG%*0ypETyW+G!_W-3JySDSo}u`lAjLJKyP` z3AVSc^QSe5%MZo*s8uzWv!+YOxS$d#=wsW!cqMr(Wfj85yz%tlK_nsXp}Z5d%;{a{ zH8xM`tavdT9;yPJr4yr?dW2^Q(_k`uttpta#d7Q!Q>u%O-1PgOPq^?!#KaAO(GU#e zkAmB&PU}mHXY)=!psorkgIv-t3+$r}-UhE4KfXk_%-Th%QA3^=B9S)cgCD z$#2K+EA>nKS^r{V^HBe+ppWW+vFi@7$?!I+=4qG5n@r`1F{$^re>K2)^7fYDe~Y^e zp!#p`0D8Q?sc}FL`84LXkp#4RpMZCP?EppovY&6a1KfS-n{Yp~Z`{aKs&3c4?nnJw zoT~TqR4qd+rNRsaPG;I^e>`m2TYkRkAQ;_zlK)lgicNGv3!c=QWB6vw$$RFzAo##h zyF$%W|3wfvb#O3sdz_6KZJ4C?dqTbloPO1$ezlT8_EK6<7^cu1!y~=p=?&JXr_oqm zh`OxmKJG5tnCbHfALgP3AlU4zc1aiFD!wD( zGkJH~V-3k;*E3=*KVcr_!Tflyo?B^)M{RYk70A^32dj2XbL^mJ%(To#UjNbIc_{X0 zX$u3DERQS60qX)n?8TwR_V=0+!vA)|0tvt zn?lSUyRwl6P?M^e6JkU6XQS?!>BSiKJB!Vg%#wCtyP^pw6ur4%R3r!Vo)d(QZ1v( z;gH+<2MY)Dx!XO!zaRkKoA-G+YmJgT;)J|)#eVq^t{A~iC4$0*bnide?uPB zZjISYFlY4d$!>LV6_AA>HOtb=w&1i#YHYVu5dnC6)kwgYyce%^Q{9(Q*^RoNCaXYV zgpWAu167A(&`d}^l^KV4A6L(0G2^n)tj-v_14yi6piP2!?P?7=fWgCU(g2B9q{n=@2+^$3d4`J$`nO=TD;T#u+R;e;;Qh&Gm zRvl8M%pECcQcS(3iJ#ZuwI%x_bu&(7cAyI=y z)z7}<$BJmT9Iox}F8fm<31gBKL=ax_!)wq^f)&-}G!w-0HM8N+bMINKMz6U0vNgL| zvquxH5hE>oM}oV%odtc6M5pi83^=K4CxgGSEZPDa=1(tKuM62f*wI}E`VzG|Tr_=O z`qExkc=k1M%uBnp;c=J#YwXyvt4{(MS#jboqb>w}(cKqL7g0eF^#qX{ua`*jhdKGG z&CbarJh|zX@JR&_^$+z>)9YNEW(K6->1WiCE1%1N@>B!l)e#)E2d$dT+cvIa(P}+o}PZk1A z`8rcM7#f1JVjsJD#Gn%85ckvccG!2d9%=q>KEG?wNss@Ne_0rO+(uaKE5rD!tj`28 z;y)(`&0uS=fdc6umk@OgROzoNm+^z~YeCNsbNp_i@!klvantlN=N3`Qr%vzxmW}`a z%VY4u#|8POkcIN++fchydJ5eI8+$RM%(b$6chc9BU8_bPi0b~prn88MX_M3#XY`>p z*77|w-sbd?a9Jnp2|q1xO_H&(l(!c-Aog{3+j7`=qzd#bT=1n}q87F*9hcWMr4*Uk z39GEoJL7x#azEz%J_hVWeMmx=6suw^9g;K~a14X5^w+)+ErF&E!ZXAn|qptS8y;QwGPc5YuQ zF0UJ|1S_h(9x7hpJf1&PkIG$kGFT{-LJY21^r^G?Y_G6UW|qYy8q}W~wO=c~LV>D2 zn2iu^dEcZJb6O(xCBiX1?-mm^C%j99{`6@8@O#;jN0!oca`V*-542t*TD*d zNx#s zy=TD;AW5;!sg+8_BXcmP+n9&#@A|jQtsQLUS4+iw&9%U6r&A!_N>AW=A!;S^vob@* z&*vd`qf$vr@Qzrz_yNz`H`^%c zO1q99AskY<*Jz)f$C5V@NeJ{ch(+C>*M;7Z$_mUw0xQbYs|W|_-d}R3!rUO6}Nb1efdD-=kSZ}V^0a~bC;Nt zoBK+`m1QuEzzg!=%}aK1_}l{YUGq$70yWYGM&|#^Jx^uC$~i?R%_z#2mi*e&P}F5u zY8AtMVir%MiG|jcd=^qD$LtnxRVX%y*X{Lm8{|Q} z(`!I24}dq;ME4vE&1#F)w&65WhwfpVQ7_Ac?f1X!jcs$+FgX_IJS=u|@U~m!&=M&X zUZPORFcf&;=T&5+NAtXvf*r)&$_`82I(mHk`C9u&GqrOWZMrE9R5jHQ-q}@dH61D* zbj9YvvN%8dvPUgg=^w1rY<35S7HKU0uR!*Y$_cfYVVm^Ixn08bYpzWfTzEqgDCEmj z)sp-Em~_$QLmI%IR3I;fKmUoe-h?y@*rGSaQc&`1%dxtla|M%uS{gekc7(B2Cb3J< z4iA4B1{Q9LS%;DNAuA(oWG^5}p9C6f#R3ju`TWU}`_1STlmT_XynEV5XgXAvMYRM! z+4aiM4*aIu0S86u*4$VsqX$#i;1UWKi0u$%A1^DT&-&+P0=r-fi|KMHzmrX{S*GI zRF>f(BODY=NW{}c8`alTUJ>)Tvv7`TZT<%~0QT&ZZWVhDvDxDNVxDu=5YzJNkO~mE z5_Zls(=xB2@wb1~I8q^Smw)^j<9e~6_7eRp>6aE~$n-y0>`r`FY-RyFr$D8YIo3GXiNW%nO^QVSU*y%UUUdH5>oi`wGZ_1dxQ%EXz`4ag)TL0 zctbQA^%UU2Yfbl277m7Hd*$89d2%@4<}_9$-KILKvu0sU&oBvA<5yMT?Q9RdU!Zod zx#LhK?i={(sWOGXcJDQipqaHaq1%E^zau>3o2p0M*f&meOa2x|>`RxoYy!4FvzUii zCITu16ccxAcW0H=4ZGvIcXjs3b;7N6!gB#A71(GD0P8D#R4h3vZK|+4&3E<`KZl_& zJSR{957N$I2rTd=tZb85Td84j@CfvtkY@2ShMASnHfM?ae z$Fez~$Q~l#Cz#%qr`?gHc&KK-Gj6_dbnNJSDH{tk@*yV@8eri(iuG0Eq_>gcpRh$n zfB1e|1MvZYsWSsfYCFfgp&Oz91O5L$Ux4ruFBO{!zEdP};7@lOA3pVa^gy`WHjXRj z47d5&w(1^&TAV$O{m`(K`{z}b()znToe`CaWXhS>Sk7mRJ8S28S~=$)Dc)z-`erhx zsoQ!LkD0+$f_g&~v!<6X)M zw#Q7ya+E}IkMW+v+MaQ+sON!NZk zRn!32xv05!w7I6$pF3hv)nc@U$^(Cgbh(8vUSo@i8ibdjPwv!5F0`t3U#aOr?8$Fi za5WDT3ta<@aKfsC_hY77bQ9Oi!#JQm11o86b6q(jAIXkCd;i}Z6;RMs?mu|+M&+aO zf3{Z-UIE|m`2Xa<0-C(!=S8^Ri*Q-N4wCl*VES{akMo3dsS+kiC>@&hqwZ{H)>MoO z4#Zoih0_t`TWpZbAMQMx(QE7Q0M?_&Ve&5|%gW8@V+Ih`Wum?p0BSO`*}bwxdb9?h zO$4Q|9W$!{7b6$0P$M@8JAQFT2!~Te_gJ2y212&M2@md@Nu1m49I{%_d`Xn!u@mld zagBvk;LhEe(jI(dyvhv(%BMghx|J&A_h#cesRA(XOJODNGPLGY1dW$H!+y|)pe$Xm z1zvZnz;qhYH0mjG(@;-d`Tu6n20RWzqBm}V$LWjI1-&j8Az6?J&l+~9MxkN^!s*f2Ce)$u zECO!WzDUca!r=HPWS+`1X`(}zo1c2L7JG3Xu!J%;pgy$@k@!q%P}ah z+MUh!lwIIqvU2G|=4Hz_-ZZn9U-a9$PI!5=y^%h9y6rf{=EC(M$-t^kMN0SO84lvW zN_#Q=QjgbSx$vOgV!=%q*_1)rm6H!l7N}j z%tWSfsZuC{6jdiW^0<`#Is&Ai?vl00aZ4lR^R&?1Q@I*V} zyHQ~D8<8aPQ$YMMLC1LPY;x6rWlv+N-o8*IZPU`|zK;?2H84G0zJnvZ{12AqG7*W3a(t|H=HvE_N$;Vh7B1Y5hdXD>(^p`Q-eu2#SKTX& zZFL99voCf$W_H~=UYWOlB>-z=ERuJ;G%K3?xdBvjAg=qU^KeSz4>`vX3irCw7OFXLqDhX!Nq)v(s zCyd)%lYTJ&W-Zq_6Ll$sYJx0>fa75Hwiy-6w5cL$QIRx_%k>LB8`BTr5``~sA?W`& zxNSK*Y{LH2bpH9p%Hes|Swd!w4#CJO=Tx}r(`~Vwg0V*{So-I32^U}qx!gfDsO=m$ z3e~4=2^1B=ljpIov;D!xxPcz|4c`h>+9}&a`2^Gee2M_9qi3)}fQ6kOw^Q|91*+lz zaLaJA7-LU6-XG)WDi0s-1cO}{9EG&gT^60q)?R%EA%KO*V+HcWfAG?Zb1u_FqCN?| z`^X=|NjW2uOGTPfop=oyVUQWkAdCP42%VC5`0ra{B1^v&eQm>*BYga{qXpr4ad%>m}`rtc~-be0aKs$%X6qG_MUm@(1okpOc8LfNFlxB%RX# z9@ze0@4OY}GYkQit`x|!3qSeP3q5-DO-d!o4c0b*d4tl67i%)}N;R5O(vjq1pZg~K zE^)6=S8u#}DIhr!M5Y;go$I+u4_))M80#A)A?#HldMVNKyl`(_F^UgaYqM3}Jr_{h ze>2rIaTnVy?z4k6k3+Yb3)%li+gpaU*+uKR)SxX^DintncPSKy(td^Fh2T!p;10p1 zg%&AR+?@cy-91PN!9#Hk7Th(^^Y&YNt!uA+ogaH2nLkMKH@um1jxnC+e%ykSsJP~j zb&WY1HvP_?I`qzs9^m!| zuUO6bmh`utpbd?3rxWkUnd-|adn1vhgI$x*44aGvy#-A_E1dZG{Ij!}s&r%1}vZCUxavK<_E1*e6)&Ya%E(f}@ED@Zf zYL(NmsWd`2gcWSnl^)xzPGQ!N^>0~`5k%eOi+T51G9P}LvwB*=#nm;IuN&mrk{NJO zz?sU(Hp42EdJZ1FxS=pT;!3%_$(0BZlkrzs{}AwNT=rvFYVlxD{u-mLf{xAl{ygpH z8~W9uc9)iii3a4%g9Vn)6Yxd$o-jMVip^0`i#6na@&UQx1QodOEdXCNTNTvo(G4=5 z82R&};=ndAdaHhCy)?;WlOw&`DwGFmbrf8#5map2u+gzt-CtHGg0^oXvQ$yMWivEh z`o`2a{+wlArO_cVr?iV&s-JMh{%V@{0xX^K)OOE-*g52s6sE^OR4!O>+A~nKG>^hQ z=uD2Dbm`Dg&n`#vc#9teSMDyew0X2>;xF0RaIvNa^y!)$w24EC0szFI$tD^xk-G&S z&pqrdk67xwuO0@YG<*iN1Qn@hY|0Ti^djh*=@Q21ElSI=zddwP-_tCAu@S0Yi{AIa zb&yDFj`weQ6dGa;_W)>}_Mvg+=Htdx$DGL1Q|~6auW>%b`$JxT@M;f<-m}~1E?NKh z@<=k6KocEA){8^hlcpZ>>+%1=BTPcjpP1HR8+Re6rO4@a0aPfhHd^t!RdKHHvKQA- zF!rMQ00=k`PH)<);z!H{iU15Qo~=mg%Yb4DoFrAoln2ys|Cn}@5vTe^b@VyCP>~tu z;i<``H0eHm0!&|B4QpkJiQEYo65Ry`%71?gmru4AmZ4%?w5+Kb4$R$C)}hrNObMU~ z@GPL_&07D1cj@6xPjZ;wsUF)_1i{<@QskKnHzTogYt<4@$ocF&RzDj^cpJ&$sG)93 zW6~ETH=5FjvY*(EIl3EC+LgT@uv{y$96e)a?YgPRK8bS|0Ic-a;-dU zOf^n9M{siJjl0j(Qeax?pG)a(zp#;*&Cb67@_z0{@!b?Ku`KM*%u#k!U>A&h;_puY z(HK`EPS2ozBr56Q0|gMw^`viEropi93r_!QQERmjEKwvyCrV2#VfJtEGb&A(OERU6r$UR4wVR0b0;o6oIvxD;rs5WLuyV&qnz)_izM`AP&6OHPY#sc z?UU@OSEIi%jw-k<`EG!OKsQZpM0H2Np~!=EcvE2mspDnq`y?Z{+SB$A9<)Dk)<`5os_eb!G}yUQV!otIj`PgLbNy1n zo<5?>Os6q1)mB@xOrt;5@5>@%`*@LhiM$4!`=HwlE%OwZN&i1sbU_9~?^=3-G#HVy zCYK1w{(1T@gReM9z%W>1LNNbhp%F8zFxDz*Q@t_G()6Gk4VjmKw(3p4jdxQo`w7V> zQ_>hSB-(?=ajxtPW0bApYJV@-tLm5cwf=6={#qp3L&}ZPt+%#JCiuiCzgRrK2gt3g z(5q)7VQs9&aX#hyrFlJT7vwKv7Bns*azaRN{d^rC&=|LSYK%-1_r2ncpxZVK)IEi5 z6zlgpiiBxB+MwF3rhW9`2?H&jfW}^EOTuAP_D~BKc;D4SI?RwhT?3}dy-8HFS9myW z3pW7q22+c@l;5p#F$&=9_LMSH3l}@sI^EtZr%Zn?fJmNvcI~$MH40@fw!G-mPbi@TZ};Mlj+SE!bMI7=zB~xXxySkk&vubL(KoTY2gkFG zIohpdR~_)RJ#6b}Ay(ZI)j3gY+dFBM0(5=~lirko@B8*cr!Y68u^&0AudrgpCD#Mq zWEmfiLq(#p4;`->7oP7Gv29AcvQ=3DtZ_K0!Thf-y}E1Hj3Lh|xgZLUuu#d#BeG4q zUf->83`O4sq3km4yASYDz>XADg`oGP%doHH%T7)@(z{5ASO} zfm!dRvadd8ExaCdwt`CI9M9~Im!>o>t*r3=BHRKL$6b17DbAxO=ohPBRjh`Zb936A zN!b=%W7<%@^vPS@7kXvOit}jb9RwdK$zCQ+oJa#zZb^UNq`UCAO7X;s`+6-~c^jd4 zJgTAX?Pne-IDr2Z;4Sr_U50CfReN_e)!UQ0MbMK>XePT83}1UCX_uufZkqDfN2-;4 zFIs(GpQc)!bgGx63xfBvwk(s}8$B9_CB{j@BJCE6f;Z{QuO9}Xu)dj4>U1pZN6w4z z0E@fwj%h@lGx4h9G41OT$v^`=zv#%r{Nr_;*b!6lscHGsBUqs!^$s#BEyj4;CeXUcBM`pC8Z^I)-H*Jv-F>@feVuJDdyI zjSLdJ6=c|Bd{18f_eS)^e~q3@o6soDTS!j5Fo4u$-?~D#@sj; zhM7KD3hA;=*~*r0&mzS-LhP<*BPI}^if%N zT!R=nX4<;xa9Nh;u<0wm!UsaNO(H9QuvpCTI*X}W!ejY8OwDAAM27;lMjR+ zD-^?Gko`rKI+s3)BCGZLo&Q;8J;aZG_a@;99&sO=;I--4oV_uzHtEY_YMo}$1R4p1!sPHh;|G)ho z{xQ4ETOZMX@Q@Q+?!!Hc0fiX~+pFI2HAdcpr+k11M_k+{ zXUB0=XML11;<-RSmCTU@($_YE?2)bjQCxaFuUy<=8f-k)^8->kV`JNCkN%RB-|LQ8 z0Ko?d!JFyL&mvp+Z~VpK3(sAHs5YQ}LkLnoP)YlVopR!>Gnz5pF43KOfpngf5X;Fg zw0v$LH@H=jSX+>u2+qLu8q1ucRx6@((|-SPom%LhT?JqWs*yCu@NrJ@ z+l$6bAc5xZ3jL|}{_imPgJwZ8V3J_~sLu}>{Ds*c07VUuas6-V#NWiJUk^Y1=6yJ8 zN8U=8lZ2pkeEun!aq^!1{_*sD*lkI%=oX zi&F6}o>4P~POj89=^>GuqClIsV{B2vXETgDhYUm*a;pcU^(Em>ZI?~XaQCKDtESMV z)^T)L%efx{s<^`q#H+nxX>WG>v1hrk;>G5|?}}NCkz9x59CcUboQAf8_t%NjKG)b5 zcTRtg>i~ZpWvF#k+tAmZ+kWmo^bsAbd;Pd`Ts}63=4(Y3!x6*&|pf^R+Fq z9j&XdIs1F~(zT78v|f)Ci@2W6>-SdTOk_7pGVHW#x< z4x*eEO~#5o&bO<;O3~Pz%0i7C*5P_%BwZFvU$$;u{TMtG)bxDVhkYVRT4&h0G7RK> zIFk`rusB_PV;dv={+}$i){AV%*J(wd#_uX^+H|KRQKlPRe|aousJ`F6#Jkn@vAftq zPHmy@BVgDD7M*aqd=W|(48eas;S)|B-B{KyWYv>48WS`4inr}|prw2UsYLPOVFPYm z6_ii`=0P+i26V4*hbTp&lz2FX=R7UmJeYE0gD9ejNkK*RqRL6zumdVywY-<)` zeaeiU{;PL#*u8cOon6d^c5In~Mxowy3F7ipTXzh*R&X*GWLz~CG=RNeF?mHpXtcMd zo6{?`Rgq9M3VJ7`m{TxWV&RErV1NEW4_AfS#D|+=mx6@=U9tE~1 zsQG+rYRlc0YKeP{M0;>8-~p6fQcDSh)P7OXrDejpk93l0k|lFb6vHj*uAb}h$1t{w zGNI%VA)-2rS}y^wR=9$gR=#@D7{=0WSr*48THm9##{e`B1S)6ypT%G{z)r>QZCH4T z_AfQzViSB38cU*}xRK3nS!+%?VOb4lvd)hQb`-5C`|CTDvF4PjF%xkGs}~Uzcvda> z{at<`C_~fC*BVW68pm2DMRUuC2mRB)l^Yj&!(q*V>@mfAoT^&S&gi zhX(MuT+{z3sy4YiyWq$dK{RhzHfmXagxgY_czV+XMY-gWG7-Dmrv;;_hUQ7jC%LI= zV8ZC?2wEf-H@BG{fAaCzpGZl?@O$r@9@FxZ9mkia1ORgPvH172={Tnb&xH^o{RLfqA>0D9vC}d1>1OcS_-*K> z&tUkQp$>&2gLRoZGLqvN7I{nBhu|_$_#7P&HQ)>kS08#7aWU?RvY4zT1;_>z5(`gS zKFX)6NJw2Ws~0xt_hr#DCgShT>v2hU{&LtO&4FSQE3(U*PBiyFjS>(9lv0{L)E~3# zl@sEr|KQniTOu@woWsS!?42$@lcI{N#n|hEQf1Dr{{ zuU7mOmhV1|hGhfw&Hv$Im90^FwTIAv%kRHO&+3`%GRbblGP5acoCsgo2dAmV{I)fy zlOBLeMgZ_(R70nUFqqNoOO;ES0@WJqtv0BPONs|Te94~d-in=cj%=<>tmRZUWwK}b z!ZZYxidPw+6PsXnI-a@O@0eKiv%bki;QLuZJbd|4HWurkyIyH0>e#f|w%8qojAal| zlbZhYsi>SDjL7Qa*D*K1^Q9{&m}FJ|eE&P!cxX%XAuJ)`x|_z~4BD7lx1&8m(R1fV z7nsl9eWb==kWW6C>BFijEVSw!QZ`iTxFWJ+7ShV;l4rHgr+cHVL0%nj7GIHvA-)?e z^wUQiKKDE)t1H>i4}p@S56#UZMqAzOyz*@9=Jv10<>%Y5A044hd4|n zGGp9iGyrcee$Cz34uYTVLt{opEP?ic=6QA7Tkl+&Z7@5GNBV;1Yi+_F7E4W>pmDa| zLW9b)OJ5Q1d4pQxJK$vpmjkYsMO3QhZtr7@kf{xNG-ie%0{BVAj0j`JJASG#4I_q0 zh(}6!sWqp8rTDRIx;3YtpqC+@mldB_QhZwQ`1@YKis$@LDfqr5J%UEQC~kQ}Y+*|C zUQV-!U*(cj)YUJ5NA*j^6*PJzYK(J2*xzhRPpziETt)C~(R7DBLJmDkA*z1&Z9~dB zKRRv7z14n|@WrVV6RJltx@TLgb`RQ6Q+@E3C=4I+16d(>KdoH z#0_d8HNq7HdPJ5syw=}bXO`FZjCGtO;A-?u!0&wS4q@)tCu*o96kg>MT>xs(X|a4B zsk)%zI+_> z?SQk3E8zup8+s?vbaRab*jLmG=&mA?yV_}r6~5!j=(`NS`B+`OT6Cx8>t2f`00zBk z&?``q*lN}CoAi5{|GclkfH{YDf-snjDjVR@)0NYTC)4l<{=w@58{A2oPU-oAs~NX2 zKWyQ$i?kz!T?j6pZ%pk~tx4mTE?n22gLjWxgMYm;t_SO^Cp^@Y7|M$il&@CyXssdBUotHFaTsLY z35fLm?!%7mO5I}WKOlM0o}f-2{H{$@Qz7;9npw3$1o(j6G!%K6u?-$c>fY<)SfkX` zPCC|T`C`FvTkz4d$H*}c?}eD_*JVrn6wOU=DMZ8R9U|i~-QUlJN(9&^U}ugN(k+e& zaAtQ)A+u~-d?p@P`=m-KhD5j#umy- z#B3qXI{JenT@!2@r#y)6^Ne3oOp%^25%1r!BzUv)2TxEzpuT3{f)Xb=T&wodC0yxC zn7#v++A-g+Ko;U+=ocs`F<6kdZoLZfYGn%{JDIawXFjvHZ`auUowMDk(-P-o?Bzsj zjc#+wbr2!&LuuM*I?Shhm|26^u3`-bSidc|xMc=S9v-guwrnFVx`DoLw|%R{e+10l zzD-y!fzQfUw7OV;2B3NSbuvfd_b9;>X9=rLNnztE5#bV$(CR*%WM2Dp(ts-e!lmFG zG5xCsJ?JZ=q6N$5XDa+nqTC0^rc+1Ib8ktBSJaBc%GKB^vx;)^T$uChaF)t9F)_!P zd#i!%f7=bgK!Xd|XbNvxNK;r|Yz8av$Kcn>#4lTG78wK52GFB+WP}e(N_#YmoF&J= z%1C-jOe&0B9YN!`v+3+UMBph+Epu%3IZ@AaO%W@Kay`nz_kz2O(>%nHB2Fx4PHp(k zT&vwPsv_Sn!|{a)!?Ngq#4`mvB5;s{m``(vjC&_ITz{CcDL<2kp``jfo|!dWiSzfG z_NOsuSQK!N$q!#^V3K1ZlMmnL_3v9Nk`ACSH%Rv@z3n>jj)r|Ejoh`+JR&QXTMDAV z^^}o}7iEXeWEbF@U9V@Skj+b>P=}p<>#UbV0U6mb}rjwO8@Oi}|i+31SYh5Vp&wPYurl zntThsSH49YE@*rj=a!nb8jJ{-PYY&i7cp$Cnz|Q<^PEXRX?(LWs}4& z8M_x#0-%qq$N=fAv9Nypb;0G{J>AIe<$aM$8wZv&14e-89Nz)Le%^)PvbJJj16<5| zh;vt6`x#cg&qSE~{gb6~!@#cO&l&Cv#m9r!q#Pc>H$uSO4P4dm%lCI0V`SGu(KsRm zCwQJ>dfak;_&&?}Kkaw@&b-l=IxQ@!NTV1nEp!CmX(Ntcnjp*h@#)AW5iK9$?s!A; zohJpr6u=NEVVym`JAoij`?8f9BnV+Osq${k>Jm&A>~>xFNW7Fgm*1zd(ezX(HQd@$ zY!Z43J;9~KFH>PFc3dbpdEyQXo>4b%cwOa)C*1v9ugZ3x6G_k+k~{HI9N?1pe_*6x z2rpp%d+7c>ZGrx7FmvI<%(9E9@KNiiZ?S-GH#7-S?~S=-Ob}t7^zKpTL}Z5JFD3q( z!EwRa)|?o49BQeVIdJk{31)))Cr^-&FI{;X$p!RbN26rMuZS(zCyl&429QqOQaUtq z0(^qV6T_=QKLpFvYL4bL@%rFUPka9zk*$?u5`#+{LEElhw%F5Gt+ukTZ7vV%84~Jm zE?~~6f0CwLEpU|8mssDux<0C;uwttt_qt<1GkFI~X(>ndR|OyQMh5NfmYB-pZXtqj zjNO@-wUSO=x8iFIpAVXl2(tqCgUb&f-kiPmVIFPq^x+;NIpG~6ZxiasxRku2L6a_g#g0YX8xeNAgxHFr;PJxYX{VxyteG_z5;tNK+$$sb%L# zndZOoQ0pO!8Qz!$6*tj=r*{#;|+=5Hku) ztQi<0?JXw->g?M@_V()++g$`8 zxN^@vZPnLc!-Bqx!4`IPI2(Gim-L+H#OpF*|H0VY=h@#e5#daIUwd7|g9#eKre%(M zZGECBkZM0N?eBo-E}g=rWAs#eTpAgCg9loxn)ZK0-Ar{g)W(OgK4wN3k65hx5g+@p z4FAD9c^G}Out1OnC3iE+POyuyGy_cY96Om ze0h?gRaFN6m>@d8QW}F1Vr56iDWthC|A>D1Z#hYrXv1s+G3I;#fQVA2fA@W-ajbzn ze8!31!1mHOo{HgO5QqE7shLIcp*d{h{Xcm8H!@bLLYpmvF&)vVV2~v5&8)PyZ_Dlw zVL;Z`>}ee_C75y}enoi=e=Ka?Yr9n|LN7y3Rzwc}ZK%!v*j3g4RptYv8^On`_dY(- z)&!7xa(JiH2aNUNF9pI;53j}JmQ!he^p|TIOfj?(A=*Y%u%ag}sBii z;wk42N;|8o^)5wjuU52uZhlib0ZBR`PzS&6GEE&d{DUVi#(sR@f$NRB9D$#SroKL1 z95c&+M8I+wd3zx4wZQ>i@M!VN4`T4+3a2U~1*nx@fVu!KwMV+0uDU<;nW-@xSum~OE!F{T*5NQ9k7^^*D$2`?3@CxO4-{=mJnn>W$( z_{Ut(<(v$mhE2n5kvG*ZEG=XdKXSjRxjpL7_V*_8zq^1UDUGTOq4msR2+C1>Zmis0 zO8-*mpDgx&+d9o10C*V$DdXudzo=n-ZpcV}XuhDXWfzm9sEY>r*&e0`P*L+~*0Rci zDhXGXm-rkpR>8L!)#g-TF;xi|AE%&;nXAjWR{c}NCY8f0?+os)+6%`lwc|9KZI<0> z_TxiO4mu5?`!_-qnB4`^)!(arHev8%omU2tv~LR-=-GF?6rnS=)gbILaBRXM5c<}B zpq1YXiMcLld?Hk2Yl9$5_%bXvzh7p_Ga>(2S~ESK=TsX>7o=tIFDS||9<-b(t?Z)YL{gbuI?M+H+L9*WASBXqjHqK6lLY9|6?D1C`_7J@A(E~@n=_`IqZUXO>?kfB+@*C~ zc%)&Daszpr^};c$+WAG`a;e_+WBs40pK%F2Gz4%9$_R@&Il4a6se@ziNkEcTGhYDx zlYpEbHkxK_&B8ztiq4<2tniRjkSdg}Hs2&0gQbQw%_-fr<6Yt(=d+Kem!E5iQr06& z^++Rm@)V`Xndl2{QtK&F&{(xex?kc&@Wb~GrQ8!aOy>T+Bxa>3RqVs`+~^5avae@^ zQ--aCL+{FN^IOE&&?WOp`FtG+>?qj2pbY$G3?$OfRpkA%*N~oyoKlC3X||ISQxNIG znY-sPDeAv^UAJ!&XQ-@eI?-TALlFih)2HF~ro+LS+Ayl>9oKpSj8E5 z<^<~l8A%Gz)%(gkZ^V*_mnQu9fsq%hIH%rqzSiuZ>@)UDzU~E{{)oTvRsZ6 z#fjsc(t<9JrZTzxd}RB_fr`ZZ*D37yw^f%cqP3;P2W&oFX2i5ca;pj_mT;FN>=X2j z)7OQZQ5};%l0kIIT-QAS%WF6PzAm-FfH4SOum;mJOb7DcOgIhxZG7HC(GikG7PA8= z*W#n8@EcYWU}`D3I^|trGoTU?<`~b@#<72}7qtGYe1GJiZQe#Hr;R+ce}HJtoi~GLw)WNHk9H*JAbW`sW_Qe{AVb zK)~mJGr^z!RBKz3F<#6C62l&v1aqJtN9S>AbeI+i*4EOKs+E0thZXe4|6(Q1s87>E z>6R1Jmy41R!-oCFME*Lwgzfly7w{=128Zkd8kDeJqK%7;EXFRHGI#sIKj){WLws1|)I3eWmbed`UnAq&yGS8(me z%sHz!uW;<4(fBx?!jtBdbvsTT5V*%}66*aa5=weYZ{VpczZHR=g8&CW zlBIVtmz**X$s9)suv23>)B-eX*hOpQM?brPobvO{*^p{*RT_Ro9sJwoYr?eJ1x@^# zA_p2D@yw8WjcyDf3%)G=MnTJH!+=#2r^k*x_l+x^CalBVQ+*J=< zlUQe1?-~$%{H#-WZ%<&GbNaNRDlhQC7?f=S;045qNngtv(?|}EFXy^e6Q4ksY5bmUS*_&_;A))E$p=x5rRwMbz+q zA|F&>bK8d*ze4T?@shd6%B3TKSy5QCH5VcT_!nq@0%@^NyKVnb{D>!`vvliTu^E0K zBoH3dJDP9wU74m=@X_9YIexq|bHbon98I?bGm$sH2dTEZWJsq}DQ8}3*Ra4|6Mc9p z={(`5XFlfZM!bj8iCLm%F6kDY>8^BpiUUAXKd``ZnPSr(9PF%U;xEW?hS(a0zs-fC zBPJL9qbu-vSb4HS#ZI~uR;Ep7ZGS{`0=X%&2;5As2y=y2J6 zokEN@DJVJ%)IS6kyO?V-WJz2srLT!=H`Qt5VEPbNI3Ebu0epc?)+GeSGBj5_M%KJM z(HpHZ?GoCu@sS|a0mY`)1#IuRhhho|C7REQsG)!fJl#;qls9N*fOD_#NTC-6tcq1+uU$XI=bPa zOXULLzHqpv%k1?CBRRt>lMnbFLH(D=^jG-vcS-oTyN!GUhL``#BA@SRh_FT&(J%xQ zFr2a#Q2=4FhLJQ|HzB_7bk9)@5h7HB8H(opuKPQJbo~`^DC2&fiH`dI@31_LcrY)0 zQ^IOw-PDHTkUtjMC~TN>qOVHK31L=DHvho1vv4``q)|ZTCP(VZcELFM#Se_Ww>6{k zb=H$GJNt5va4kq#M|DlCmF6>g>gKO_s^uC;i3v#(ZBcbmT?h{4xIk|oNKf=!=PHF3 zt^X)`ll##>KNo^K8QEpo#L1NGPXFNT>P$V*&ZieulH&R9{a(z-R?PHBh{IE-UAVp& zDeyM%Q@CDKzAJ@2Cen=V?0v!rHd#m>brdNzFgdLX7F^I_itMxQ&pY~bLdjtu{xD;? z%FT8ILBn_P2M>|oagwiWvJr1`;KI(IzXV~uy|I@$Zmr0xXSiO8JWwTpz-MFun($oY z!S6wH{m=FuU}qYU@Xx;p8}i|;k?v4T+< zZfBXh;ki#iBC=|=YSzZ1y0m(MB}y6GUMSCqXWy_APOzp7ZbsGE(zyG3H>ou9jP3J5 zUB7+gRw!JbS6A1j0sb?3vmm@G=OC$jOBcw!s-^v28fn)cfh&Pyv)6S=-x14vd@qV& znuE4u4fRPQ=5DO7R)*dcal(6nLD7xDJm+>utYpq^(ymz2a1$!C_s)~d;E)kvN2?2_ zzCU;gM#fxJ5~@?AG}8$tjRE*;zB@{qGim}Xy!B5ehjXm*zJoU^edC}i!LqngB<4k8~$!sAswSba-CJ{&KgP&6rmZk$bSk4=#@Al;V)#z>m4 z_N{iU|C3y60S5UvGP%yQzWt|o0YeU)9A~`!_47{o++D?c1?->h1(P#)K<;t>L#S}C zfIJfzP5r-qVKy0s}xzb-{zattD!1NUnt#Na2H2b)9bNeU4 zH)7!$yKd}OlzO!@AR@QzEgKc)*f7Z*g6SQN6sIDJ(uW;`$7w!MDHBvH3M(UDZz;(G z@!LRx+y{-jGFh8;!N|t!5Q{_ex%P@rlYUvtSM@?FQf;sT6okl4$sB1wh5 zUaM}d0$HRnF8uS|eNd}=$vraQL>XUjH8oPBg}&+IWr>NS#~1OUbR+)QWTFKMl;#_D zt7+%5MsZ59$N6+-4_~)0PuwOVtB@&2n90sqH{Ik~jw3HdjNuuONih^+xkAtqT{w3q z^%H5sc2O*byx77_d?bR?y*aJZ@Y_lC7VUT_)|`>&$XF{BOHn{Gh7@KL>2Lhz5EA@% zx4#wPmGyN{s)H=H#HKungz@oAhAm54>B6CGn!&Y*mwqaXd>}&4K%zHdZ^AfQw8puH z!;7*G9}jQpJ$#x|0yRRh%6(yewR>wK2rJ{4b#k( z%s0Q2MaUmlVs&gekcW%rw ziGHnLz_=N5_IVHi#{YViv874*emE=nB&oQ&oHV@hnU`=*Vwm^pkBb?dp$jh~%tGxJ ze}GXdoT7L4a&o*%Z-|uGE2!uV^*t57P`%O|J#D>SAM-Z7eAB+MwOn+Zu3~d7hyS6Z zoV#T8$TL}QWc8FPT9WB(bfNDtB3`Pitde;5<*>n4ZLG?c+L-Lm$(Mv~{1Pvvr{mU! zIf8Cw5xlG0XB(JpM*8y-TVERpf0WJ)>rrc*Nnl&vGToXBD%i9q`MGAHOEsAG`?aA$ zivmf-49xRti)Ug%_doP5n~?KJjjVo^=5oYBliT+LMTxxO zi8fMghcWfoCw>0U)ceNVDsMgt6*wW)dKUt`63$zDzr5lioO!~Vjiq@b^#@PrpGvyo z^hoAa0fET#AM`ZRk!LQVe!)q=v|o6S1ko~$|C?;u?J;@tVa>}EN*iz-xTEJQLFVYz#!@KBT zaHsO&Mjqg!VamP#bw3j@tpYkU_Uyk=$#>Df$)~IYq)7Y^E9^f{)StS+bHzWp5qy>- zC*gh3&wq3_+jK9urM40Gik3S#fYCzNa(t{3>h~DfjFtlA!uHE@ogc<7gaF3B#;Euy zg^rzqN2KFCPDKu-p;~IOl_Q&{HtUYk<|@Hm<36g}o9NI~B~a;`C(?OE;`QU+X&a!p zIXV$P!{nlfYR$*^?gtKTiB zDG@BO*3&QDb|X}*`?%WrP~Q8_?m(oJv4(mzu<4bNyYrY;NcN6!J6d~ijc3ilDMgDX zw)Z9|HHF)*XeZ6{;xXan5#mQnOb3GBV)5^? z_cW*B66m*dJzb9z6|Z&dL(BSnC#UA=8bsIRzjmo}ec>CY=_U9up-V;^n`1bOy!bdM zYwQEKc}~TOb9Q24#}8*xKYIkyBnXPZ2m~_ma4P;XBdU3!6$yv1xCB7VMe1CSY#sBt zm#p=)#~SoNK&Jbn*Xy(4a4)N3>@vVemmc0k&d1pMQZz~AbPdK2Zv05H^NJg{EU^5# zUQ=4H5})|er00ir_e{Sdeo9g}daIYNrOEIfmo3%wC|o7877{@quMP!k3GDWHOV3pt zffS+kw8!tD@2*EeqZ^)Rmg3MqmE=Zl-AgqSNPidtRBqa4b+d)mr{#$pg>T6T_-H7=@B<5?Z;)J#IiwI?&?BdO`m{sAXV>TBq=-#Cp_o2aYJKd&woB@#vNyw4YbMrUH?m$ z>|U5GN5r#)Plc7CE|1UfL&WW>D3Ho}7e53U0X#t<-S5yR%goGoCl==Z?*bg1p&!#N>pMu{1EOxcq<#roR`&8jfQu3%Oc+9ryj-O^0AIM zDyM{gQu4z5a64z?mDO7xDz{-yzx+RV&XFKwHSFBOK3#fy;*$h;pitdbOvIb} zVWZ;YRMh+}*0th@w<&SPNLRSX43%SqRK~?zxPJHSY17n7DmQ+k{O$PJ$MU)n3SoLR z-nm}LQ}l!us(k@I=nl(1@n?)y+!S%NTOd<GyGzafCz;bz!{^9Ch3V)>d!VJpP~DSjrMf&}De$9tyni=% z*3NCGC%AIO(E9xV4-b8gn}0BJ{!qy|BS#qA@~--jj18&2o4cO!zDLTiO;7=(R`yKi z?xdG}Hb13H)G^!iP-5=s7ZcJ{ONnfcZwsGh1Z^T0$rymX3J?4H0;F*Zs>|dOL zwCOYrHje8JAAxO~*tlYwN5*+w)K5IWk<|@89f{rD%{987g^H2cjpQGGR8WtuBfz6= zlel`zyjHkApl+Dy;%kttZTRwyCC_>7xnI;2Va_v-X8(4@>eDe$StFw;k6=6@WO(^? zMjyGXR?j#}N}BAu&!p0O1v_-V6*=~31WeJRXlc&*F%G>64wOQmha(RZ#xHU`<>Yc+`|jx{3G?p45b4tb0>H=@1S~vd!6)?6fHL z?RE`obVBm!rG0F1$%j99VfiChjdOX%sf*68&moh^LIG|>uG#K-Ro`;vy=DVTVuob5 zTa=gvH5>f_H9HXf@HhM+;Xp9SGrH{}3-(Hh0d+QSxl(r5#?0Pf zJl37+MD6ngY2#9S2JHo|*pCBQVj(roTz7WwHfug3Nq!TR-Cf~WMW=Y|aYF>7kJuq$ z-46I#*lA&Y9*<_~J~y?n!OpwTHtolYKJ$(piS=+6+1tImJQfX`*bdDwomWvzT0O6Q za;wHH<;xk%{V6VoBO^tjhfY_?BMEKrAxtZZ*8Usm;l8`X2NQhDPt%0?hD_lEP->dO z86_-hzpQ@Qw%hxmYTq~h3r;bkuzK1da0#A@mzw9Q^i{)E5 zwy-`%mmfio-*QfcN`Y(O*(rWlqN-IK zm+N!wk~!Tgd{HT7l$mrS7oeDCY_Ot^&-(x6PvdLS z&+@f>m-(XD^@S+2hQM3H`XZjYW`Q!3hlyZoYtDjof#}9?CGc+d=!%r^Nw2D4)g3g& zX7xPQ*^%d{X^X@q3fR-BDnrX+mgm5n=g@=mlbg~yjw@|wD**sBqp5op6sl|^6hV~a z49T^x{;3&-lAr0nkp2DQJiZ@rm~2;;)%rNP4~ki(T3VMURx!B!T)Rs@R;s;i0-f4kw+ay7c%GuVD_K;b_S2t^H6(H^4#PYZ%X??H4u@zx z8AXaOb)+)eD^SjQ66+VHyRIFu5ivVJm+N|nGtQZat0)WVEjocF+T|npC(X1v%@S$e zi-nWg#~4P&r`>v_3KdUFv=Y^eY82w@U7nPFrjW+kvUX3hV|b{V4e8p06@GCRz3R~$ zoMtl{$zBp#thYII9Zw!&>5nP17$#O&SO2awXJ^;T8YU9Si?ihLO(NxVtn2ar0rY`!a5GSYp;@D_S#EORYu6I<3?7C@`dw59uS4AQ7d2H~l zD+$sJs0-)ipbA(%U&_iyWrl5wtL(J{ghnn70A;O?A7>nE_Y{A|X#diJ&4;?v(AH+@ zjmqCOkA1)f!0Lfv+Md#9%0S^)z+Gf%Qy`8b+^bN-w&aVs{G6p()l=+PEQEEWo-hD9 z@J_4WjBWLxGfh-h2WhBd8z_EaKYbe3c1xSuuzHe*M=ZUaS5zStNGxizM<=|aE>tYp zsD{4|X91ag&BT*Z9O-%8y;{+OHE7NYC8SR>J)9Q)WH547g8K&-2N*HP)(mCC6)IPq zDIzMmTK?cwShIr&);?U8YAVa-HkA%Ya)g0V+m_M;c@xCJ1V@HpVzZQ{HZdR*V7~N5 z2D61|4g0$b0&8L|Y5opN=4L}Fa3u-1xf#v8iwj)eDE`i_vD@GoQ4&3dJx(f|d`D`3 zFumlQK~?^g*G%p^Jj{JqDnBb|MOeT37^~QP(F$MHW>rjJR0SZmj+=-JN6L(li&NVd ziFKwFX1~=;?6;b)wN?aNFl()T8JIa|$s2pQpllIaK;iZztQ%}Cd5(Io^ezi;QJSN2w zf4RCwCfE)?HTi~5%MV7E&v66Q_<^{g=BuYF8##0zalCGwK6<2ME^lW(l_frSQQK-r zFeYxD&Fopp6OVhH7=9XSwrdizvOz`MsA}T3{SAi9`QQ?~U^mT377KzZezkdLyimOz z$}BD1K|ao9Nl!sVs?GMzoUN-#jsA7`nXKEI!l8j;X}vtI>4n<>{p&T-(26e`uj)R3 zy2_3*crR)()lLrvd^>R!tGq6rJEx&$YSgfGP7mud$6K9boF&n>I$F!R1kT?)w=Qy@%8rd z*5@Jje;m^KetGzno;wDhykY@|`7Xq}{nWR2|Gu;&_#egGMv44XIz=!1%kW{pWLoZ7 z_;d1V0&kgx=gkGI?DFJMjsnZSo9fUudEX%G0{e-`bMqk6LaprOg&!%QDvdxc5=CEK z!hjZx6W&k5e+m^tWpv?Yc#H8R>Zm_dzn&1e&DestD6w2+?{7S9G^V!#h=68NXQcK= zxE4ajEmWDfZL9t4mLGP)!6t&F+d>nG4!~Z@QCc?K=oe>X8yaVTVb))5!sQyXw)nRG zlBRFnMGpflab@Kv=b3C74@D4{xI`j z!4&(C8X${WN%*n%b%$c2>0Im-BHDSFo1d6BYaYeU+ z3;S-JunGRWA88MX54YuH)za30(Kw!oHkFKLp>h;QmO>o?%7Xq{Vyskc(Wv6m4QotL%Me)V7sda@*;_|N8TNmJ zC?JT0fJ%pibazWQbeFU+ba#gW5;Amm$Iu-Ef&wzq-6b(}ce^(}&+pxLcmLQudmUnc zo8cVJ+~54fhE?Ejb;E}!E-iqHiTx&w*m`+VkdCSH2Z^hgYNShklfY=S-cR+ZL8Ejwv99o%p0(H!}W>(QQ7wE9-eRA9+q-0c(_ z3g39WoYGR+WqeGStnq65vy3a=Cz#fEoyER;lJ#ZTA+uUe0P_xRyJ*66TDBEi%sIv( z3EPP(fZC)Duwq!M@+scz9NNj95n+hDrm$!G;-$2@wKIp1fmgorVxNcGFZkQ>V5WU# zgLp+<3i->sof2&_%Fp!OHZZZA%sbTb+~{~zx}+@dcbP0Jwqi;D&To+L7;iBqpz>?Y zQy^XAG}jAeb+RgP1&j1mx->GVeI0XDI=5N0gfa7}RD}6XvI{ZVB_tUT)>^Tvf3n=G z)Q;kN7dWZAqhhn3*pek?Hd8T7Y ztT0D&EAbf%vZZD9Cl5>}JZqc$=Vw;ZM~GHHaH`q1FY$`>1M&U=fWfxMgJhJ}GpZ+Z zyPGaD%3xpT^#1(A!GAd$*fmwT(vdU<-pCcK3H4SANzbjk?wMxU2ztx=W zm0FV2TD5&AR(zk&u|1E;zMmx86VYW~(d|~G^Q~u%p)rQAm^YK7fftDqf8n;ooB@Q_ zQ1w&y0<7CRF`yN-FtZ<;k6lrHv3j}iqU*@@g9Z#$KZzvuFpAPjS z{FkKjcUY_Y1r5Kr+l1RN3KY~vh$wkIH9_esDlg$qUMjZ^NL$`LG@@v%zE)VrS>AbGLNd234pH?`U z??5J}MkHE=*0E)!?W>}u6${jamqr4E7EI=dF|8y{_M{i}v}yNTsw4r@8{u0}IM6<2RQQyK&7; zD}rBIW`ZqT<-2!2iTVle7nOY7jmNrse?h+Uq7v~TIL>aiA{Do+V^$Hp@30Dgkk4QV z^RAEJ`uDP{?6~;bxqJfsW`mBS3zEEES)!EbV_CFwDL#;7PWN&ZF*SjHyrJzxvq$V- zBv(1E#Nu>vK>ol-nf}*_U<6bQ@CLq;P znV9Q^MQr8JzaGLrm!C!Q>42o*LX5^l9VJo>JC^kly@w*M$}?{IP1Lx9Lmroa6u6vv zavS?P48S{+-WpXFw`~O%4j8#EZ2|^?>9csPQ(BvfKR%+oC*K+zJ9K}RGg-MIdx=We zF(_Nff&$yx$9N9Xx(u=5a(rho&M7i66I?0VQ6FWYwDW>`z^kLp+@QD!1%8w3t$jfY z!-`O4`l5yPLqX8(5?U)@!_hb=E%l%>aOR7{>e^}WN!F3$SV z*EC{vs{5Q$NKq>BU3smJ*P@%S;H`JYfmkPN6a}gN1=C*g*j4g` z3m4|t7ZyjeB+2Jj3ZR(l37+uA56%m8Dr;rPgj4onq4>Kb+ zFMwqq;Os~a$th(U=j=B&6&iyZ13@O#jXN}UE=)$@<+n)ypw&TLNE;>5-T9${& zW+Oj;|5hHfnlj*lP3nXiLv{ASgtIgkF9_>`f`>Q`29BdEc23}hL7(d_gbKFCzSh{- zXr4g7-*%a)Gw8jVgKuaW)!3k6=`J!S*+!9&-muYbTx7y;Xz1wUBJ7mPY&bVa0%yBO z5({+6@*6Nrx{ju9N>W7ozQ;qpn~{Vw$9@zi8+RVo#B9aed1|KXK~r?eNvBovG3V9NfbhK_o$@IdOne zzlB7+qs0VBN3u!(yhBT#=0P7#RB#L-^SpID^EJ|Pot7LaOd7jwu_q6og;+U_D_X4A zQzs<`v?XMhaW6z==OP~9@%h2Vq0_%cRJRq#sM$^#aiOS2q+j_P5zr|(Y)<9J%25uc z2&3z8hu3vQvl_&w#%iKU&2O76w!UrN@}i{>OPB=rnypcq3v9{9aH4%Q1KJTq2)I0gaKN`>CVKbrX(Q1F!t#b| z?lC&ZSFHZ-!lVA5Pm~P-*LU^f&X3^JpJx{`r+W0ALLEtHh`enC!j15Ih&At2yx>^l zE1Ez)O8r3fK9rOHN$cX_DdvQ>#n098Q?$&8x#wAZ7D;>f&Sk0!jbXpJm5q*>B!a})?9;T$j-PyRO6JUo zDAJ`Q!=&;_zN9|t&L?2lXc(RGd499?^;qk)@sE|*0mP6Gf!2JTi$Acxuw&Lrkw@$0 zAHSV4J${tO2Pq|c#!Wm76a$brFLsANmcfO))UJ4R*`*xLAnHl`jyM`#vR>*f$R}B> zC4mFT0@SO~1hm%VDqj$nS2#$M)EnJ(lh2XaW#mz^y{vVcCv*)@-x)d1_mrwq5a!+q zcoVx2)JID+m+|A0PbodmLpQ?EKF(Dz#de!Q1H`$pL8OuNqTzys!quD$p=7r{UoO-H z3pAMgA&zztTMyc*<$U~h#8rh6J`$;P+FI!J&PM_2 zZdk-?45%M+++2w86}PGP*S%}Zva>fb_+h;%PpVwA;HULfzaW2c*U#a@Nl@%y567S% zpkTvx;qheUk3fj79%W=s1>FdkzK`#NhJrdk*M1z5lf?jiwTxIGWfDNqMXvqVOEUnJ z@8>)(H6QzB0DsmU^AZ;qW#rYDCy!_kz`YsxR$5@mH|zHRInzW29T=rs1EX|6D>LmW z6~n)^*i(#!z#+O9(nQMrJ*tJeso`c?Xxu$>L?3wQ$Dt(F(wO=eb}Pwp7LlI@PB0sx zU}j@Gq|Tl=O!R2eMplqRD0jvbg`b2N9bfdVuq#O97r>D;-XT9LgHf4N{=R=@8x(Ey z*;TH#H6M=S&ce&JS2aeMJVf4Z6>=6sqEv={fzJ|uUGA#tQhLofy1AH8eI0=H#^FM$ zuau)>W_F4*^_;{B%cf^3h7$X>SS6wL93p@e;GRQg~*ty0Wnt(ruEsau+YQSb1YaK}8mo6%e5Zi-l~kp41BPyR9% zxnFe7`HNYXLw6X1!tq~BoZw*^PvJt(^l9g!PSQSP(&CsJv(Jg3OA8Espd~ViGF5G;+a&5AvKh`PPMEtrsL6^L^(tqoMyUR68cCUVS zc+ib=*2nTJ&dF;OD$Uj@n%Yq1^CjA;cC?B~kN18-#fl$-d7wW$^*VE_fQ2AoRM1xF!zzA*sq3ty-k|`0a}nO-Fn4@(KUa zRB>DLmLL|N+=+Q=9krj~--Gt{QzrUg>lk?pycVHuF9wjv(OCrV!Za+X-T20Q6D`aV zr&*HC^f{v8O=z><`LfjWl@Dg}rr2e{{hyHobK?dAlIgbml!C$JspGZz^5Rw_jnaP8 zioGq4{QR9X`Xs0HfjJ97ID7-!rq||lWZzu$q_Gqyp9`Wt)vyo(I}@%Et}tl8ZP|C> zi$SNi<=)BoQ)IHygEbALmnJs+<7h|h_%_l=^pY=3?&7-z2kndii6tn@CA@5w0#j7c z|COb|VVqU~K{=wnGhYtC zD3;ks+x5HNiQH4sr+POPZ3&h61mkXm^C|H*PNVkRO`096Ak7wJ#SwL>=j2<$U;p8b zN#WY(OM0VcGCdln91d38)q9geB9#|t3l(Vsx`}?nWZetK#apfqH+mEErTqR65OSPJ zGK-XRd-kb;(ht1ba$i{pd$R4;Z~OK~bBR?E{!Xjd^usnfQSltCRp=|TL9*|D-`yKN z^lfIhCNfyU4sMZ4x%#3ivbroOeq!&eZ?mv&Zg$c+^O3O%TE4}F$qmloKU+hOtMsWr zwx8oWS2b6QQx4^&15pec}F-1^eb4m)zVOlI$ZFM<6Gs zZ&1G72zxtF9=X7C&wZUEG)nCx=##sscBtC?d()Ja+)n7XV3;!=>8%%1)7HvUZ zvHmM+K3xN>S(xq92$6}5lSLs*DgWwl11m2VWuZQTFNjrA*F8Q|OpX@4gSbC4cl99q z^LRfM_p`fL0R?Qa2(8P%NE+0%x}fhv!O<}wFs<%wdgbT+hmx#2Xusjfb}io}QYURc zgTYLB%-df-BEv^t6r@9hv<;u7oi2YsLD1^#IE7jjJXyZS#Y}DEEpF!);E?D%9t@ zE%nu1Ct@;}UUWI^OuT2H~hlnlPFobb7#t0hL_^cruhn<0M>M znOEXK5BpLUMdfiY{diEUIT}(nG_Xp#TJ=Z7Z(d0}%Acn#cqo`&1B!a8eYFe9f04d- zaV&Q;*V}Bj0KBzu5FqIDGiSh;Y^!akj&Tj5mh>xq;7hURZLehsg-_xW*X zW}kR2j0Hu$*OyN@l)6bbZMiqJ%e6s zlet&UkPf!V;Wg1A5topfioWehC)?KE%IRk|#F;$P^(C%q&ZXC4(@=m>)X_>&)$hTU z>S;D9AQ=WDTP<)>I!!7ZZK~m>CT8YZ)fQ>nHLrnct#5 z(l;L`&HvX=;vHM|1s*czT1II#2|Jh~A4{eO-tg<*hwZs)fe3n3-CW5Gb+w?<0)&V5 zBK~{cHFw#T_sfg}C48?h^+n${e0*VOi6-!)NhZcbT>rqb!^qW(bWk)szf*5z%j;c0 z{FVA-N@=sjD(6BzN3m94Nb+4-*H6m8F=Sa>5|*&edL!0}THhDYiA2#j?o#8Znf>0V zhduY7!{+2DXGJX072}KAujt3HOLh_&rULy{{KNf}HM<7Aghs641-+X$)m>G-V775H z2)S8udviahuT9OFa~rK7RoNecc`B**k&Olm33kOcD+?|cIu`jCI$(Mbzr>+pg_iSZ zNQLGpewp;3t!8G8OZ_)8k#-0vh01D`XWls7YQTxEvUmpcL0`9gEIV}^m^&7R#s7G# zY6J@ws0HL?J6HnJgPENs(|o_ksUfUQrdH`&aWrcFB1v{mC)maPt|)&;Nred!bbjuyXX zd+ZUo`|=zJ4Ca`_j#HX_DbJ`{Y$63CSw`WRy?8B?#3~s0Xb(@C&VNln!L7eozPMk42Tqx2nqAe z8}V9F6O4bvr-hC8h$4e--dv8ulIIF{T2)Tc(@sl_Pu*t;=IIKLBMa|af(AKn3T{@j zGkT=#^`NN$4+Wt|I$^L-mEb2D5J@C`s@x68a&odZ9#sL>X~8v~->OP(? zbL?qNG{I`B5cO42hTe^43qCz2W)HZfyJ!D>He1hW8?XlaR9-qEa=4xxh=Y#>dx{zyJwjUA$!ugt;i` z10jf`k!?t4-~cR;k_6^p*^Cleg*Wqxs8(&&PBpg$x!?JoN$h&XS)IxI_)v2s)9*`n z1enU$NHV%J@FoT^YPZ07Fg zMKEYrBQwaAtX<~UkAOoopWRN}xa9cu0w7hDQoF`A-{$$0tkTUR_8@ZlzaFxcS0q;L zrkgtaVqjypdQ}HMuirWw8ef7Oq~B9F-kdKr7Z6k5%Pm+_i1>gGRxV5K_qTduQ0j&ZJtGZrsfa`0g@0~c~ z4_n~Kz9pPaF>blrxK__`7?q9mfLW)DTizR;7TE6`!Mn46WCe zHgA;j9U@LY#Pz5lkbB>b;~o~xTL+uDRx16O?n?FbXmt)>9B3XPrkx|B^0-jZA?$7z zguYu<`g}KRr<&f9jQm|Gh&FP3vpuYqQ{z`omqKsmT3on1tRo1%%1+p$^<$MRv`YCn z^reZ9ls#bDuDW3W$Yu2d+K4^fx2$I~J$W21*}5RPdLJjhPv? z<%Q@rH23hu_j3PiF{Xr{<#RSbpSZI=wSer?%x5f z`|l~jK>Gan9$2gKD|v-}igwac)hFs}PYO*>ABLG+M(e0GN9K$1l#6FzPT|TNl7PNy ziUB0GnU+ac5#Dk;sDv0Z>4x1OZOKhc=5AA0%ebSHJ)uRJ-?+qN^|L0wn`g70jks`Z z^sj`r`jQ?9?ExbZc+G@SnlaLXTIr%2qKJDGoEH&k)EgBc0KoSz!J$Wp<7`uAp@KhL zH=mbW%iiN!*yZaiO6ED1Uegsn7zAWtu?p=aW~e29;_~glJ(eV$Ru@~@1I_Q$j0#NN zC0gWPx#dR>qw%ErrF!=x>*nN!bgj{IeCerR%pr(-{<&*s?3FhIzgPCV8w8Ov{JHTS z{KENa8BGw*TC7${M>)_2Q?$vj8snkbZ_F-rb#~l6N@|efOem4J6-lq>&q^JrcKaZ# z^y0PRTpSkl7IJI-_)fk}thUmidSY#HbnoXI9E$WCwU zZ2^n^)SC(a!V|Mnd6BL&FoT1j9vpDcL)3NNd2b)?vEgz=gNgfe@=3l~+Q``TNcPkT z0;prCD`y=nebrFiwWInNRaUyTlE8oF!9j>TlVtma)gKbktU;r=jd~95iZ9!qLT|{X zjG0WQ2UH?;-Fv6qo>^>sKR47vjGKn(lra_TY|nZkI4d!}TbMA3=0DJ-GO`HtZR_`e zMUP|5UsV8_wYyuT&_#Q*>ykcJ2j(&}lcC|m6OEB%E?v72I?Mt2w>RWN+Cv0yiMX#I z)JHw!+GA;B-WOPt7MJ!w&5xsY|ZNEEt`PMfne z{fk7*5}?9I7CGF$X=dHPC{o@vQoO^)%04oBAU9gZYHz-`DfqaMN&tw3ckT-fe)IB-4r^bX#z&8lQGwD^JapcQ1;n z8;H3ob3Ro?vz$$U4WP~Tl-_8Qn&ejcH(7OB+1QSQBCHwh4;=sj$$0;`Yx26yf6`|C z!y{KNXavf2E7YZs7hNF6-81!zUvHPpI&l>Zkg$vL|}`B|)k zFcTZr{q(&Yr+4H#qm>7iO2sI5opivAhSjF}DnwK==Z9maG6p^{|K4)lo2YH+&80deM*NwNkp1G+nTyffkxl>uQ0xeX_ER7h)|YJz z!v@04S=+hT{9`v)AkH*+fP!9at-v??2kk!Wcx}Kh;PB_d`Vz;Px%bIHYe_9Enj&~r z7jA=_8|`Lm-J|qi6m|v!{7DVP_%xMyI<kF(-^CTlpD z*9Kj1PH0>3LB1^cx7Q@atJOnB?(H5O1GXyi{yX-|05Lj6LIXL*KT%ul&Na%*X-6fF^Bw57MK}NNP}J7t7zbwt7weyLbCWH_W+AFw+dbxq0rY z1?%?b^gSzxc0e`&-M~3JVu6}*2~;sZ)4E+s;03pTNpiY^DoWtn1QIGva}RJ8lqGo4 zIIS)+8W9n4+ed%`z|7@@}lG)Bf&@ zFBkPXrc{|CDr}X$60&*}8wf~jKUs`{B(%z29E98zWG4?2E^4(-;FMx;y=J|*wuUT} zyoLE&4w!9x*>t&iOT z_tLesZo0xP5pTc@vXr;cSD*a+V(AA}SsYe4_6sPR-wvHc2U`LzK`@riNy%_LOk45s z6BTpLbM;sx<+2W1{ML<<^k2z7Rtwa^)6Nhtn_tPggP{RaFCo`0KIFwC?Q{Y?Nk-WV zy9-3h_-$lC2FU07cRkue5xWa?@Y){L-c8sYd-8UOh*9?7j-n%#cv7nh=$Fg#CrCd1 z;;UGiiEb~z;TKrVN}=FcV?c8N#1!^#ny_#0|9Ke!8Wd9hgP7t56f4BJ0rGwVF!p@~ zNKP?^eUqpVr+Kgb$lQ{8{Ov$s#0%iA9u>D9&*MV(KPQF$e;z#raMAc@I$2EeM|d!wUQ*Kn`ix9J8=aec`?{SRF&iC!;sZZ$FKY{FWv)84nt`U{GS0a)VCw5(WN9A- zoe*J?=Ki6UcFh$j_j&Glp1+6^%<>cc`p!I)ADazASsYqorqGnj-HBi$q!0#7iJA`(_%St{p|NcENzSa!=4@JO`D8Jf;;hCi>BUR zBoj8PIX>O7LYhOlD9LbWS(jDxvBS-~S2U2aU-duN>mA!+@Bz;$rAUk!HHb!Ec|nIB z9$6t9R2w(&7auIWYsPrMHR$(;(Zt%8(aC`_1b=xkwDz0pj>!pZu#`x(iD!Q%==yNh zdV|3=)>}U$U!6KFzeF|av^eVCKDo%H+z66IJGLWQ+_hq9w#f1IbVs#l+|o?Ig@jHU z4>0Z>g$Odb|JpwhtOS2+*xJ$ATKOv6WEsibetkX(%s ze4|dxE|oREQvtDy_+fK1sHmp~&46x#Cl8LSSk#^QSR|b%_*g)!-qM;Ts0tAUPGDPkFP$S;=BXRcvR}&V zR6RK&oVpGyQdf(Y_YoXNG(Ui}89(ajDnp$}fy(EIg%oah<`j+SkJ#MRtO~K$g(TrD z&YOzI2M#!;0wgmgw(eE-nKT@nVy#5AX^t)vbfLT*%^fx9n0gXFIH;=c&Te-gFFO9q zj_+@Em`Q%R8l5K%9<36OwfE2Gc;$icf1-8a;6;-ag2cl@-RV z!irWLOjR-MkORPS)tBe9e)nnn>r<1I$O!Vi582_q2?w#VHJKFY8;G=9V;;!bfagE( zvdRvfd)uj4xH{|$GUPT-dwly1$odV@QJ;$4ae_8HeR5t_)YNE$q&|4OQ2hD5_V8Ey%kQ&yR)2esUm~DkKVJh zxO@(n{_NIg^3e}_+T2U9k`=E*dSn|Ab@q4uGQ+agYeqKiF{aJuV ziy>P>yU8~qzS+aGAN&^DdV`!|PlJFwEz4_0||*q!yudH0$a>Di%ilxPq>B_c)4Uhy5vnzf%n1d@5FLU}!iS z9Q2V)^ZPl$3O-=ZupsOcNhyl>@A#Dl$UG^fJ?QUh0iq2R1CSv8%~{J-WM2X_Upyec z{8Re+2McbeV*N3R>FDCn#W5l!KH*qXr{wLfp^5sFM1D9GE?wZCGV>PV?`ry=>w_1^bnM){dNeyK2u z*Bb3nI7GoH3q+undaL@EuGb}JxXw)1{Ex<7|3oo#F^BgOV^@88)DN zYr6Kz5akzW)1H+tn+-2r;8Ccoz)&@l)~1{wTWL(WDY;Km;xT&X-EGEX2geloUh&N8 z!hJUbI^0U<{FXC0@2jB7~FOavbgYv5hY31nnATv=vL`chu)`$i<)EP zpC@g*SS$#*IiCYFhyaqK^?C!{LO~~ZZnD19z2lY18sC*x7raq`)`97z^h(LhO@Z!g z*y8KEOB`l1t%E_F-{q@SOl&;iaTDBi#7(u$2`OU&UPB z*q`}IOU~>yfM1m9PEVHhvnUnH!0bD=cXY&5+EgFbUj9^#8JP;Ic`7RJ?9`~l8=sM= zU&UvS?N<-w^6@WajU0>F`@m~Ce*M-oX&G|=^E%HDpX^-!FH+=K1odm&*k_LhOuXMQ znsqxbc0TQiFHl2cGDi~y_)=h@MS{ddXpGoq!l$p47;~qH6kdE3HSHTIBe(Exw=RobeU0(E)k&OtL)V! zklkQ;ea|*dY8Kknbm5udSbcR&`qt@xdvnRZO4==`_)YPB5!E6=-q}k^zGD(!?(pJ$ z%ZrG5iB%5?gnaXKEf*}=Cm(gWHIINm_w8~TM~m3~@4@cRGcyZcJp5vsuly|us7cC% z^Z6J=npOxGS}*;*^ZAe-41f1*V&pT!*P&vgFcHdz~r_nMPEb6xr zc*7kucs`hoCbY!2%R}B@NL_Ad9%465=RQ~t6jJDj8bR^JMn8NrG@_z%zoH%8iPo4g_(aad>V09B2tBAEPlkmU{{MyMiyrk4g`1l$6Q8V3hD* zh#6lO^lr5xeJQj#R^*L*eo%p3EV+*UX;$M=GTUw+bN}f8k96%?Jqw$DUr&~^NTw$^REwV}=vL5`+#tv%pe9wTf>O5R=KQ(SvXQn~M;b@$pua;uJGP`T^hgPSCWtmdEot;(+F%lm!3u&g8oK`Qw zx5QB^J82x?_nBF(V1lDaRzfp@UMs$*hP#L9+0k+j4Y{`J^%P!Xes<@?iIeM60CIO^ zYYFVE&^Dj0?#g#Sl;+{77 z{AG^Ir|n!yjbgRVCnO#R!;CbyQRlUkN z5yKn8mAkL0FS(5=vY5Fp(snRid@FPMYK7t0tM)~fZ@iU_p%i(ps@C#-A%%v#oAeR| zA|yPMH=Bhn9qOE=ivr)O)3-HvN;G`;RtUJAU!N5+I(ud6apdl3JRF2@Gx~5W@vi~1 ztR?QydV#Nib!;FH%Ih&tBG4?GarC~w4I#{1p<;mRfwKCXrAlstj&a!W+$=9sC-f<`O0jwuxxU}n&acg@zGoq+JvT!K@<%1qjd>-W9$@Eov>_F@T5{a}9FG2RKB<>OjHw2+7KHntDri{c&(MBf$ zzF@6gJ47u?_%0uq>u3kmiwX#*)K3qS>|Gv0cs#2jVv$ALuM)$VrKxlti!@{lS zqOE1^CP9bdU{^*Iz-EwbI_A}K$`52~{UD0~E5>vTX(p1na;_}bQ#oc-HZmNRH!iP3 zD%tIg>kjyC@@BpuMg{T2zHz`{yu-l(llvzipT_S@T>&qL46P8U=N6<~-}$|V-F^jU z2WKzp5|w`k%2f40{_(xqC}|P(gS%Pq${w6TazOws%nnnXn2bw4!>FZam2~Q_72R!Hu=-qcz z;-uE@G>z5F*IltL7{xOF8QahhhN!Qt_*7a$(kJL#4gMm5&b0`NJ2tp<+qK@b5>lve zr#K4QovH<|VV{sn$3QcB#}h@{9PgKEzW!P{Wu_Ip5=__~shkDRmdWVFCJv`6;Q_F( z$!~TAJ=SOxadCXI1mnf31;X47H!s~q8ZITD%dxPUjm*BY-tI=5{xT4MZdk`mzo?PZ{*B35P1=CO<{P^jwYe;fXk=)yKfbf|At$teEC<#fj`&S zXEFlRP11w=oC6HBC+-|+*gb^YUub>T1NYBe-Vqd=o${G;C9>p8S5Y`r?`GHA)8Pk0 z6FmchAAbMPLEP_c>-_Ne^o;0qqJn?yv|!&ROU+s?de$|~@3lx{>(G_An0Caf)9ae% zv}TB#ZVKdsNAhHu=C5I&sP%X#<7R*9G*qjgR3qtXZ9a<0sgv;$D31r4ATyHPNFL{x z8$RdKby@JB_)sU|ZzIivBQT-zaK-}BvZ`t2cw>hs!_juu_O{shIvAi~=J0d#_1v-D zz8xt02+(J}s`OFU>+K71R!xqYxjR}cs3Dc$mstIuw~ZBh*z-IS;5CK1oJK(4E)|Zz z#ijCkpQVZ?$JIh9$KlKxaFE9brMZ;yz{N!+9&;Cet2ne*^lMc9;P8He?VG4%%%U`V zbeIIKV-AoWK8MGtM)r@U$F&eG%72epq>*{d?0T)#LeM_Ws;*Ad-%P?eR{MGHQtnkW z@VF(`&pi5F6=0(Sl-Z{$vRcgxJ|1^5kT`4-06vx!mSGxC^3t7rD+3?rQ1DGYN1AHx z`SIPT`SL<$kyM8&^fEzFTX3phD%<~IYoHanMTBd0`5?z|P|>}66puwG4&zz^DlqYS zf5LI)%CKSCzIgK8N~`E0aS5*YDPP9j>D3*+cZ0k78#ve2!yeGlD_NnVmf3-h>sY_^ z-ep3$@{XbnL+`8Nhd0ls)`O zbyVPHex${SbK^c%KL7<4@Z|&DK0Y5XAbk|9$b0$}t>2X#`6Ad&PL#}?HtA=TjOIJu zQG1QPCkNQYi3VA4$#a9y^_HHk%1u|cPPBR(#W8>B4-id+ znQaAF#m6aCM4xH66y0Iiu?+qq^F|#OSvj2tyCjHPzp`y5N>&u+k~vM)*T1IOvsl!V zE6*pf^YY!qm;jjgmJ{zFI`&+Ctur6!ZD-FF7~qW%PT<-q=lCn`(ctSe0)yml%H2zbntdSj9a z!gk~%xGzY`&&FKJjy9C^=vzBvjfAT!1n=m+{%UAlx*mh;9Kfx2}{!Wd&zH%!k z8ik?an3e{F8G!7U8Ib2ngcZOpU34ma!Ujr4I@w`aXjr0}xH(Sm)eGdzvSjhzZ8IY0N+gmaXg*^D?NY2;fxAk)gHmQo*mnokZDzV} zWLTkuy7iV8Ep8ki3hF`8*H!5ptX@$KT~;2CdFvfNCySn7E2XwqLmZ)k!C?Jms}< z8-L7R_%A{0FJc~R^-ryzz8%U)pDJ;VrUiS6PZ>&EdC3}rr z#;`<~MCXzY)kd)S44@navCaR29@VEC(rblYBeMc{zp7|fg7~!7KmKP+fCh*y(8M8o ziVHoKEf$KS8F*P<^n<+yKCwcT#QU8ul5yK_9!j4ZSha>aY+mPi7|_7GhCczLt)XB$ zYLoDT@-3v9$beb=)=B*6yC|RqLF^p`=h97oeA`Is z@KH>&jb86W7rA^2*$dGGflBN^QXUK@YArx>jC_GY$+Wr2OYIcv%|8 z>1kwb{P|KmfICqJd`0!AeXBbAQo;SbIuI6su@nOk5-=nz10%&X z{?k0s0>uKLRreSV@TDG$g`CoV#5V>gaJN%EP03f$e1y-BJkGoT^nui)KKSGLf3{BS zD)0ZbPLIo&$3KUW$B;uwS+%P6EGJ&~(eFFZ@=-w?yeU@y-A0h^^@mkO1wTsk8Sike zQ+;pTzeq2S{WWdoyW9b+h!K0uQjGZYqU&<9ligYOij0tkDMhN9)urhM)d zQG6U~i#qr?Gm_M@)H0y(IuG`qg@$?OxKjpSu?uyu+o)8l!SHkI7FnnIgJ~E6NF?PuyjU>4$XBDY4rk&crr7cpIyWPX{0N<&lgW4`+Tkyfy-2IKqw9qK&=Q5)YyK`3xY<>@9dmI64Km4RbFFVe?H#+|I3oQaj=8ku$)tuWi!#WAKXoirGe%lKA6iYW0~& zi0_2xARr?UpJ~XyLdqV+@9p6wSc79)Fry4hGK{^<&f&6;KmyMGC? zMuU-D%cXcVp5MOCEXl-e;n0I<0jUJcPTwN%9C)jyrFXaJRmv*yAFymH4 zruh0YRycKou!QBDF4n#I{n0!!lBFY>GmJWO9V`?GXtytcYu9uHds6_iJxIyamqrU(9 z$C3j0=Sqq5Py%-~_rJBN)MFWdN~8YohyU7y%C@}c|D9!1MyS3@_%}m&oTH$`0I~aj z9bABJ^QdX@_>PhQfSaW79?%&9wA1^~)EeS6gaWez*s2gouo04}3Yi!L+&wBO+ zUJun>wVB=Pkyk29>F?Z@#=6*tuV0g8Tl=?f9TY=9??O6WXsj?Mtsc2KE-AjJbAO3~ zJ|V-|fKXHQl~+80LgiGUYO~|Vf01k*kAI$dNL<0k@BNbMUMH-6YL!b^J|3s8OK(<* zvgWu`Dqe7nw4g2<-L7@xyYO5A5D%)|>fP01*cTI46S$=_ovO)h6Yv-6I{4zJVsjz+ zI^$C{CrY12i2WL9zMSdL0g(!qZs@K;vq`d;f~4Aa3a$^s862|(S{n8mxLtdxs*QF8 z8c|Yvk;sK5{AcriX-|KyAxBa21u|g!qbG(?Ou04n(-d2|$-b%hi!`Th+CE94AtI*b z$HQ=M#w$Acy4W-&_UPKwXQ9U0$hxS}IYT|*WOMybQr*Qj%K-D$(1#C-coQ&d|2n?s zab6Sl<@#{)sr~Eny}TmpS?7k9DI;|>snDIy6>Lq-XvR6WHPr&Ji0U;XenKkujJ*Y- zGmWIGHYSs=Rq`fJsHpE#nANm@fCflSc4FQYi+ZvMYC}@d^7X_vY5u8z)TK^^(ht@f z`n?3xO8t4K6c3@5*Wwgu-9EiT`n4Vv254`YDr_?Yv9QocySSV0_>@QJ`8F?I=i$7E zY3WM%i2??%?|8gZJZcLu66q(4%O1^T&=y{nBp41WPME22BnsFGi{O}SiIG~5_%X9- zSlRL>@kRyXA{pZBAo8`D9C-NVJRSO!J=jX6%WC(;9@r3PM)Gb$B)nbfZnlaT_0|C% z--@=uw>HE~B^Ck|(8-9clm5{v>3t#{V|wtG+mBFRrh-vfw2in4f3^Rej&>2Q?{>zksTvG670v;3(6l_yBnj zpp(C&{6ENh%c!>6s9Th_v`~suibGq9TX81^S}0yDxTe9~owgKrch}%9!HT90?hXZt z1$U=+^Sh5QZ!c=|H z0J0&Rz~6UZhDhG)^z6QyL1qQuW^nkAxgJZ|>q6w}0&;#94;{D+qXX0nb=+!(Ne~@+ zd7Wd+m#|ADm-dtP#P#ns3SsnhAYFkdF~)H3YoL%O2K(_=wZkZ>!w~ucjUA5msA<9d zmuqJAk#d+r?JA8F^%9=ks}GIk?H_nl0Li&GMB;K$>gB5cr1Edxs{m!Mm&Fg0{;6}_ zQxc0XgMelG-F>&*z4Y0b`&e!G9;f)HFYkf;N0;|X{^-Cf>c!$$FQayVAi;0&#^?aVa2Uy&QvX{h z6tmAxE6V1#<=Qy8?vkwyvX52+kXP<+Q@a51=8Pva<&VJw1opM5BljY6@st{tCJuoR zex>5EP+K_#K5|AMDk&S6Stg>uWk@j7?_{PSR>r}n#MY&&ti#5*!84oD@9Rb9w`K6m z%cS!(mbI_A`9ady=gE%NyWGlzZ4@Cmt`a5(zvbw>F^Zj{wQ{#Gnxk1AJ!7pX)x0Q7 zc}6u`LXmyx-ykOp*p+OXDor?z7gyIj+H9>Ob#bJ6S+-f?)pZ6drSR*jf+w!7?8j0% z-Asma^v15WX)ymqyRy+2OZJ&=v&Ri&Lu{Ox;Nde)H14c-s3;38ys)9=$_<2$xi6cn z;b$|k@{4ud?JA|W@8!aMp+&y7pKg(X6W6e&Gp#rC=eRzvKKYKOWR-J%8#7sb8#ng^GPE%A58hjgXcY!S`|G~6&8fne`=BvJGHR`{O&rE|Spk?t<>9CFe{xB^;X>PY#3 zQEaQ-hU?OjxERQzRJLJ)ikddF_@AjfRst^Q{F_0?w6;ZyR0SK+1wrwB9JU2|Mf<4q zan&Z9?=@r}tIFSqpz-Yiq}%<3?WC>&%S%!f5V6w7Pcc{ca5+Iy{C>fbi((;+pKnzA zWw*3vnCcXjow1JcRW{3cM~gjK%T0K<7G9he3bpfWc}%SdB&tH@MUV_&F>I8uQlq+J zoav&6C~Xig4s-sDcB;{8U;u~v!PGA8*OK7e1ZP!HO^>YtdH$3t?l7AE$KW$iioaM) zVgtrFPr2Yv6fvzdCv`}HXhu1RMv=p}W7TZ6a;NNj5wf=UspTxRoJKU^k13f^^AvnRg0HF}*g2eFM z|Bg%i*CgXH4=^$Phd7qq7eIv@h`@lrLITtQbTmb&EdYr54`?~4W zOlN>(lO6vkP>GxL&*@VmvJ1HyZ11};UyX*f%LEnEX z)^1o^rVz>PnxONYW}DCTduMuK0hFv-RT9=T>r3~NcjL|gwdfJXmxdyM*_=<(aZ_mO z81MLebFwhZC{UmDO8--RCbMkpwIF_s?StQbRpMXH$ZgpiIKs-6$$)RK^%139g*Qp2 zLiMmG>+i7v$wAM;z)aJy{gQ+68tl=0$`bbCNqB5=Ej-_Zs976xcTYW46oKn5FwQGv z-w#f}FN`#~ZM*>`jxGRIeaR70`sE`LV!m;n0inj?GTgFHRBMMfFASVUE=(0i%}(6S zoOc(Gt1jAz4pX~YqyzPwlMJb+gmJ(%Riv`<3{x_LZ%u>!3mJ77HZoX7@(V188T)D) z@EijTPpR~T(cP^yU{Ym9u}!wsq~!q=;&u@>=c>}q4cF3$mcjW~@PtR~`{YeHlhnh9 ztotuLQCSI?=IfRFxESih(R$%ECc2s->+<5hY6iS4!XT-8;)?(W!}Af#)r!x>zr*^MeiltTV7jC(T+i^Mij%u>-AS&jNk@ z3EziC>2zx|iU>Q5-J;88x)(Kxw_y07u!a~(Jfhea9#j7Q)=S?AWzbt_ehoA^nfK)* z3*U)L)hj=N*g@kSYwVa%EPb3>D^5`k@8@UaD!z|tUK`)XIrjsIY*0xr_)rf7Y z>0?bdzvYfEDpO4~N__JyENi*WhL-_lWc7d*02^^xWLP?u;#b_4fA5D`y(S(pi;^HA zV4FeTT(K}jRkyOpZ3>8H??!#(E@CF!%ctzF9^J~Fqi&Ba&R=a%=1Rh|As%eg-DmaU zKKMH0*oIKpVY-A&tx`a31ok%%PPkdTvua|784cgE20UPI>W1?QM_jXdN3fypbew~I zs7Q?_b}v?%rFWkufAP9$$5MJ^NUZzt*nu7mb^PW@vkRrLWUF+aAY^w6w0^ zNjaq9$}ID9s4d%CJLjE?o=4&=zRJN&o6T`a^ zQd-S08@(VXfvosv5|W6yuaCukF7#d6{z4WmeL`SbFVD3f^cS9e`&C9?k4HY;a9v3$ zzYo}+4XH=g$h6|Ir6^s- z#ySWULtu0YCf{5{d^%5L+a_#*GLMW#v2#iil$rN^Qejb7Wc{zF85W*{-{ z>*lANMmaV#@2^D?rI8yr$V8b@xrGKDe!NvYIb)pi{#1oYKRhcN2Jd$DjDTE^z_>j! z7>mzHz1UJ&^0M%%3q`_1u?O(JY zDv^1aEJt~cq}R*qm_!umh3Xk0a)+yW7k$<>q>=m$pkgF z8X7<6A203}+Ok~sm#Q^TA9`vWCA)(by%YGX zq($T7%EIOOyJlNARR5xl7ZzRwLgR0FK|1KE>Vc*_SEefzwEVsL4k$p7IR>bL-7^7z zF!&zDVpAo&Uz+aI=X)$3Sm^L& z7D6U4HfXeoJRQkxeF6)_LQdHcCs`YU3eB zopfDw;z{#Px%Uq>-5LgvuY9d=Shz5Vnc6dOqkD>db;tMyqQ@##utE^9?Fy7im zpZziP$EC$fe+%PWcZ%nLdP9J?d7w>bH##~oR72Ixn-&s~_1##x=}c*6sjNoIO@GqV zsil5-Tfnen(mLGvA-(Igkhh$Exy7R9S-bQlZ(-71u#00tntkuQJ!a&|{G~+{9m+KaV0QxfH#~SiNBYV6!r8WCbykjFxKsCP?v$y(fWj6#$ zYXrK+yNvCISUs8f#%PW4>^zA-)VFh)9tnnJ7^_)ITN(eb?L2RnTxe}g(3a8OR$7ki zv5B~edT_h19&w5;HE#7H5JR|a?&AolwjIUZLdWfMqL4ABK!vVR?@>;xUYtRlWUZ}| zJe=Df8ojb5!>6i08upXF7Tt~RpU7jiyDCl|Y7XO@bL*OSgMM};B)HNxov9-gP|wTO zV?k^k*mPuWx4C!hKsus*iduM8hihP9aHkC$zgrzTV&)31%HOcQZsL12YZv)`0#dCj zWgd!wCTf&X0Vw~&1us*m-t32<{B+-mrv_%RCi=))yAMRoLS|&tk#z}0iFA}qkArk| zZaxE~ao?L7P+xJHF1&SJf(2jvKH7(@GKDm{Hk_v}ys3^Wi%lpDdmbJ+{*;87--S+g zU6QlZW$0$S9H>B@#?i&Ab%ePLlj`)SGGKrTVb z4>#WwELLmqolRWaFo;j^iGr$dKWy00u7HZyU}vO#y%2NZRSimmXT`EE;ZhAPUmmyL z#;;O2ttoZHzt+Z4QPTo2TLVTC5E}n8#NLnq8MoZ`Ct2}DG$g+W7hbi)xk`MoNa(k0 z*6|yOnqBsH!uA@Mz?rJm42>W)C=(}WC(OnZ0VEIs$MdfoKq0Q60r5BX91XY^LR7rA z@UZJL`9Hh4^z{>R{`M9mFS7r~-9P3lUmq?_Ibj0CW}?wiCJh)1l*z@}i^znVK&HZ)^@9oT5hdBDFQ3s&@G#RH)pPsElWu07 zbGINcC$afJWb&%^Y}m!i==)1>KjVawjC@;ZZB6Ul9u4OwX1g>=5X@om;@vM__}}N3 zpa}QDi9;_eJvNG*n*|VJ=I&A(L%B0-p}v37)VB@p#@Gj%y@*Wpor(Dp#s)cmh>b3< zljv%{lt=13&+UQ#@oY*4_(7sOXKob}#@EMTALM4NlF%QTynjy|`g#+A#3OXnOGZ!~ z%-!+nb-A@qXj&|qo~0I37&G$_)G7_IhRjkcH-^N^wT(oGogot=7F1^Yy)7<0!Z5&C z;GdWNp|7_jkqrb+iLwQx%X>5NeuvjZW{W#=W>fCCI4=S!i4Ky2$Mm;GJ~SjAwU&*+ z)%g-ceZpHaC{8_RNNsDSJdn%NX?(c(FP$M2=5A9>NjI@Mp(cq53KqQVFhzmo&7GU8 zGiYXQgvBvv#!bk&QBpEZ#wwVEDon{Z{ke|YrNwwv;%$rF}c#?{gdTpI?~3(LEnos2fOB7Ka|8k;fAu^B!ZDMW(YB{U%un-{Bh{ej*&N1&Dj zew?r)@vl04$wWj}KQ*hWI9TCIGPcret-?P26@Sr4ZPF~IcMelJ-v0Vxdb-RCNJZ~I z2}J#hS)%b!AG_97v$Pt1{Vo#;`H)Hhx^C#Yt8Ftdc>EXbPQ)qssC|7~0US%Md?Ib? zNtnR#7j40YYVEq;<2F6x4EUqTg%l}FAolK|nq9Qk>!M@1u|O@v;legyc5Z(Mx-6ox zB?4X4clG;Bh?lg@ca{_%`guMZal>!WoE!=0(whi(i=~7^O|Mf*Iw5!(I5=?TBw z=ea~OGyAaiZbZp!t7LgKwp<3|dL#d(y*nQM(`lmW_{OsQ9wFAf22Sb?Vn?`KsMlEyl+FiPUdjqP&<>XKV9FD76lW4a~DPtAv zmIi1?;brU079eO?{dZC7OqvSGPOVH6EAO3tN3?D0%$7E5dWd(SdYR=$^w0(^3*6l6 z5cn5`a90S%`_^+yf-}P0d)40HB|GR4XHL{T%jKw*^8z&!w_gPE0pC3f6YUP}kRlVl z8yO4Gc+Ju!Ad}QbT-;PIR`azi5~230{@ab*FC5W2Vb+~;t^V=m3A*DR;{y6R!^ak< z8Kl!@-V*PqJ7r^%)nV)>Rob<9{zYZX>IQ*D$T(`0GpS_CnLu5~kDq|Fq=a&F{3(CH z9s3_Kp+C=s@DS1s*J?ujsRClLD%s{Z=s`HeAh#r6=h5t>aLp5E8qSFm%Jsmcg#5g7 zk0~c^2w(E9p$yO7HM4=)y z%BqE5dlPv}JsJ9n_VAWt_v#8I7Pq%&Y2wHQ`^+|I0lEXLZ)7MfH|dMyhBPVzZF4jRk()@QQEE%ahCh~ArU#q<%#ch$MpbL&NN31C)1xa zS`tRxl~obo2#FHMB9F7lL0vu{IH8nbcG!Vo+g(Be1jMrYEG`?dg%K+SOTXjtodw!I zPDV_;Ia;EGGvo_}KD;qdQ8}tgvY;F48MTAV$m4Z?{8m?^zPlD_32=Al@=#9Dlp%*@ zO5tfSqW&6I(*8qQ1}Nm~G2X(0`j56@C-z~R=(Nlv?n|%sS!VA}& zikYu=N*&-#{H-j@g(}Vk41HTWxnx1?wy^bNYrZf1>{px7;e+LwStzYboy6P-7E${V z_DvBzk!G%5qeHSH>**9yi^Lin(APn7l8C!LVYYE6bMrb{#oEf=!U$65-NTb6fBGmt z)40`{K)QHz{rzBC`U2y)yd~Zr^-|f|8+9`okUw|5k>`OcVjU7H)}QiSd7_YS(LVs~ zK0n58z_c$MiM^)lk-a&@=6p5Jn4cu1cL18imQREVR5nz)7gT~{Wo{8zun(I@LXm9M zP8p;ZyQ*D4L)Y8h<)e9Au>@{h#@^TIJ$V9T)N^cJmevtNN?C^_C&)3FttTG!WU}^g z&O@9sd{(TCEDvh)k9R5atEY#^Qn2@18{r)W<1~3c(^3w@Q;flgTaU$bSGEsAUZE z*p669@bv%*kwEEuqO$vZ>ugM|p4Yf_!3eBL;$PU~zP|Gh^nrE}rFWq={L$yaBMrgpu#yjJ#%5UJAznIz1zX-O4YIV0do>#29{^O$j_g)r*|8$-$1;Qhj5QqH@Oo_x)&4%*)@!ZjA|Fsz++AB6g5UjK zTg0ABI!X1gb4)QIH`k%ZR)JyO`lJ|VbrO;Vs|tDN=VR^FLYzl|-Qd4y^DC`>hczV! z6-_gtmJ994GVsVet5AnK6}OnU@~v~gbkT5#<|@zV0|^Mrf_KWjUR>zrjVnzB%*?*EC$HA87KfLH$J%!vx5~$UQe%|QS9T{R zcj$l)bu33y+a1Pd!zi9n^K2~Y`vzBa*c#GAgs#Nx05D(dQh4vEpVD8XgK;$L);sai7 zx$Idahy$T2W@y>^GWDrg)&pTQo^<5k_Le(j47!-h3W$5Lx3!P0hQ9UAgssc7DVIH=9#8>)!PS#3)(b7~Y ze)240M&|UHP%B^97~Cq-u=;+lyyJFCc-<;Q%YC$$_AF-=q`x^Qf_ zy%5{Z%3#G*p0k^BUW0Sa%il9Ku%pDbSc)Vg+w#7x+6lDQ z%$5g}1Y=#=V~25&G3g4NgYAP8m{PHW$D%=O^6$*`zi6(+hzgmp1=4`#g26dUM8$0X z-AI>#=_2D2k!=zm=E5~tf7?Tz|Gb#jF7&ursG5Krgg|Bu3|D%aUW<_tTej5tXb^hyy$nQxzQZb%o+K0!Pgh#nKNM70^ z)kv_Y=G{=@Wb>cb{{XQsvl38a=vGpjVrd5~J-V^oUKxo2cf6d9NM7s0SO}_KpPCO+ zY%_H&<~)6-M_J}J9x1JStWP%rD0QDa2zeyHWUKozTh6pQH(PH+dUJa38T6{GFr<)~;;#JgHj z>k#IU@aW6e$x>h(z^e4Bw2_wUv1*b2F1kNVt(Yw>*yYSP89`X> zb_zM@InlTw9@}-Kx($t&6C*m8`gltsJ5_QQUHBL6cVyoaZ>zVRYjs;|aj;RhynUwH z6fzV}K=)(12_`_;CYK5hulI2|$I(-6>=D`(+4t6hESy|E5?M0 zw?ipukHA!^Eso1li@R2s+EmHNQBO0N=l!Dv48e(}=C|Wg#9u4Q)Bw4!N511_7RL?o zt+Dw|<@Q%DRZp8&Aw1Lw(7i`8wF@6ofWZZi2>j^-5Pq*0>B60{ zg=;aISKdVs*Jj)8IfnE`=;-wm%30Is5l=v^z-#6U+8m+-UyiVbJ0=Gad$W%rLI2)u z4}o~%^?gi%7mWXzDaZOC%lA3aJIhaOJNRn8RpQ`CnL6~8C8d0_1?64Po6og?Tx9jr z+N;1(g4Fo2r9Yy>P09y9=B)YNhliI>phYf7td&ZZe?2`@Q+MP(UJnDasn@czNvw?j ze`Y83OgS|aR3!E6;Zu)t+(g~iIKA(!g7w&sr0P^isld7ZpfB!$GTeprMMH9`lL#0; zq)I9%&t4#sRiKf3z)5DldoNUMLVM0b-sL>gtNSn7@be-R--`gq5hUt?{2k%X`%P;9<3(=!GO$)tOHzq4~Q$+7R63I)8_0oKTS3gF1@sT z_%i)+#ALm{1$IbtCog88f2KfF%b;4fb390V((xw5sY@nCaor_8G?nM3)H2a~ea^Fe zO_ydC@L-tY<@9wdo+5kR!=gPhZ%M~48yR2biIu3+q$N~hMebUn;CE|SVr0ATOw>^A zt}Rz)a;$2#&iVrl%}6z(MVDm`E9pK_xm*{W5=6y1fG-@TWm|LHkmq;bOOu(U^kyTr3qepPLEAK0TD+2r(=LR5M|k? z<4pDja}oo>37DMg}geAsKLVXa#l1t1hdV)*G1z zL)=6))v4+G0_lU`2_%V6)$+htJ32J?xJw^;+9@&n}{&BkF^g zNP_`D9WJ1-M930jQcpPP^Gq{G=lXL6eyJVdx`DO4htKW92YvFRax;)aEIQSiAc2;5 zTi6;B&MuG`lh-VUCHS~gm8dCPO5SIgjB^ZYdJqLzp{WJ5*abl%7GVbvG=PK($KD9n z$j*`S*~ej^Q}E?g*N+OC18>);ny#T2u#w)|-SAGsD)qGODtWt?^||$UHs1xJUA;9_ zSyHxWN5;KMg5C5Bq&aU@6;N{(ly48tJpofL{zzYwouSS&$T91;3>NM!k3Bwc?KtdP z&@dJUJyKG~Y_e;O!}Z`0T6)%rJx^!Ln~)jALQCgX z{eaD>PP6M(Jclh~v9j9s;me&PY^ZFq9AkY+OF@#eaNfsR--P z%>ySgZ;lz=y)`QV_h3iuAu0GC-isSt`g9L^8kyx?v2HS;R3Bb#{f9fA%RR(BMD$`c zK*00BBf)<1;>JL>hGvY+u?G9cDBp6A3uiV$K`scN|6JdpO;Ig>VEWcGYW0_ehrA=1 zknq%8a~rAijTeX?K_w&2SD0pO=`2M>Z=)RR4G)`oiHA%ucS`>(@7lViuM`RF{fqWkZ))6pol5xJgRGufK}w9A6DK?mFEpm6W}VW# zgO}F~!5KS;mE^L#?c2Ooy7a2|kHBn_{1T2Tj(+m1fud2qv36+ShSi=DXKWd>V9+Y1 zop}vwN`leH%}FrLGsJ-it1LfDc2YdZF}C+N^V(^+$h*I2EY0{Oae5x=5P+>F#HQB? zVK!WHCOXD24%xsQ-xm_WHBzD+GtJ&zD7=74DLQKt7W`_4rzA884{kx-jDKriA!LE3 ze-h^6ntGPaPw_G$=S0D<(DJM4z$N8%8QmNErl~Lp>D=>2LHNODO0kL+7fu!^#U(eE3^-kzltuCiHLikBO+0sW;7G)j2-Q-9Ic&4iOb{!;KDjMJIR zR~Q6%&j8XX{-hApK|b!)`_z#k29~CC$y|?|dRy%LPgG7~rtCvsC!`iwoa?7^%xvCj z%YfWkBgNA65YPVcNV)5#GgMt6os=3ZDzV9pS?ocm2yZP|47;iX1W{}h!i>sPfAV#+Nb1Yaxi}ME zlyoyIz=-hU>5SPCgM<~VYzGrB@IReW1#H4h5?~qm7tZ;Ch!@t>O(;si1XHc=^OSNW zP2JH|Z<62EIHg9dh-y>K_qVx~s~kRpG4>=c8nIeokmnD6lbPRclFLgI$kmK=<>pA) zqv$R#?Btpi9ORaEDS1=KWZxO$bX~?cJsa76znlz%Z&ystxz5rLJ0t&^Qk zvl@{Lk?TRT3r>@uUp*=87c85ge&TTkt1@MM%JTh3p%5~t0xe{(fimPIpGl7xnH;N= z|B7KghX8riFEkxe*Wi<}5M76*96EZ#)7wB0(~f<9H-@9Rbw^YLN-HiT8FvHml6}4c zk*@66yLr7ZfA?vqQd74NcLBCy&bwTQ;@7=uV(d#1)oe>ooMI0%-+(P^XHXM%Vc?|P zW?XTIq%=MX`BiKUB|rMbO`SO8xK~?<-NRv#Y-jKkRRs^L%8tzSoi*sg>*T-yuxs3_ zIf9U$mA3+6)oopyN zbmk9&77VZ0^Kv?eYwtTQdd8PU@bl4<_Lvjmdwg540wzJ`**q(?=@~oYjLB|f#O8^z z(tbpcorO*0``ju;re;w>-0pGFF{jcH?BaFN3W`W)dO!nY`>4f|Gs)iE`nSiIozk#0 zksc-q`3Z>by&nv|I7wIP3#6ZbpvWAWUETb8s* zaoCD)S5SB}%Rg!oGf%*y9fG2dt+OUh0Sp?d)-dn507!<<{JP`*-cx-e+$|8p^Gpsy zztpCXv1#L(9@Rty?(5h0!0&&KpQf-Zz|B6y6dsE;`<28Vjg^q zvaA*0kpY$?;4gTh`D9{j%`cNqH^=f`ay`l8Us{$BpC`NYFhpVnl90~L{rNIt6|j9Q zu|_*lf8EIq$0d}}RD3XGr zz8Qxu)DVu_g!o68cE2J6#3=x_HA$tdH>Di&$lEKMgiPanrIzkhKq-Su%(EmJA78%< ze6)bEEL__A@mEI0JMqk@v14v4#xw7wsCZ_Bpz@04Uz^X(+iIqfR*s9ekE9*oxS!X6 z@&Uh^ha?F&uJvU4xW@GsY~!#|G7^^3;`5|jN3({Ic4i@@%g5hsDttusab!2NuEz^U z<5Mx8qjED~QQW7t#n@-1Gj#D6O@xi@dO(ov%Ln?Om#kVOK&@KcBH@l<&5v|Fxj+n; zpDc*gY^0%k5Z-CEYEsv~rmqD?yqM!ah0QS)Q2~0^!i2LCtpx&HMJ4gMs;w{96MJvO z3&xu{k`tRLZMxP%r>+=4{oJ~75J!4ds7A{r2gFb`YfpN>&JjR~%B=ZO6%6x|#g^I} zbKE0c*w6^R)j$&g!TIf7g^)h(FcS^`j*;>kvYG+jcaHO-vpNlELo6<2$vXX)?F5(7 z6;b0QQ1cN~gsA5Jwe{(i#$U8v#B;`4U!yT^un&jO@U3@UgQ9Frp~GLabBD6_vkTk( zzi8=+T4!}Yb5wGaDknMCAEE*{z{M1})Prq6+xeuRX9-((xqWxb<9ebh^&~{{VR9mK zeovpU@%g>{TBLFV0l|^74JCbQ7v?aZy zP&~$v*(?0M%Ft8CtfdK#tFA_nLT1`+sD}dArzUcc{cJ_Ot$7x>#T!Cgak?h%(P<55 z)82M#BYT?agyH3j8oZ-NeRV%g+Hd-Nk+s{d>7;LUM`qM2-{Zd%M?G_{{CB#z?*#hQ zS2g%!vMEQ~=T&Dv)S~zV{t-Se#+H0Xh&~>RK?~h zSNQeD*F(}zvg1^0R{WwP=_!;~HAZo>qWT*y{<;g4X>^O`@ixGU{>^Dx|My6f6oex0 zG$W%=CmyQCShM0Ox#-(1G56g%M0KApWSo?2f?J2Bo42_x_L8|65nq)UUzfA21Z(FV za!p$>(Nc>vE_0u)s{i=9>R$@uzxyX2FdfBY?KOA@`1f2@j5OpL#eTlwdAmRH*wkPI zpKtQb%j64PimIJ&Y=(2Fu=)5LJU2kL9p%%%zHfPQ6YSIo$i$6^vJD~qL`$z}v9o4tcDTz2E3Uh=N@%!%Qj(*|{hBF`3 zH%7+dT1k2E==Rx#6J=9ZPc4x7GP3&2+ChM}^H+=iTc%V0ul%N8(zaE}U?(@(hX{`B z+|_eD-<tQ!Hv!&A9zTZRt)5#cfhV1j8gJQw-ohO4tyo!(y&}Qflg(Wa_zA) zB8=&sn6Kn_HMnIYBX_6e)IA!EiJbF3?QjMj&3<)E|z^m939i5h1E-;pOEikL-iM}pwl-dL#HLDeYw>) zr;_k0sknb`O#W=m*7!(!(zIETy-h&VeLWF&fL)O=?!+S$St`6XV~Qas*Dsr4%z4rX ze%lgIDZ`8?jVrTyd%-sv2-0BWK}|Kq_2%l!a0ORrr}I5Y9Dh}o>0l&HX|3pw6_1h% z7n_09(~y)pM}Dg5Qo^(6O;(A_{MLo#=Astst@0{I%(4%u$7b2eG3(yn?WPd`QRM3K zQ0^44UFEp+GBBVrAPI#9caOtV3DnnfQKH?Ajmd9fi#I`RQza^`GHNikLqy%==LH!_ zqCjg_s1kcK#p9uw8>Aqw!%tw z9jcggs5Mk2`$qavY7VE(F$tuQLzEt(smVaugp8eT_j>WcA^F|NcMRT@ck{$`i4~*L zvw_deczL{K>opoMS0^HCI%LPSwEXM*^zk6Yts4h%xeM;5nuf67+9-jBb0owsYc z3_2F2RxB-6g)6*3f#}~&+q$`2p&9 zazION#nb(fdT0WIgNgTIeiI~1LamsY6P7odAAgz>60cyID1ri0RD~Baa`|OU+GvZJ zvEA-PEJA$GS@oWeLOqn6u)={tZQ=(E$x$uavk2RdA_{yI=||)xuPE}`GFhPv#cUJC zFYEN9%A|5}hm2^FKE>Drs<<2bMvx#^Q;GFfN^R`XV5s}fEzoa8Hm#!^P(6H4Y5LEh z*F}YxP-I^JdA6sPq&U1ccYgI6ODZEe`&^vycDEV%DAf_Vc;)>`CW7^)fMQTDb5kOw z6uWxN0z;+~hS#Uvp;Ig)>w<-og?CLX?6&!fBd7jc%T)}O!gA2ZuGBHZb51lnSuwb- zMLOHGj#sp#*wAu@su_t2XINT#?XIGLnqVS9C&_=^xEKx7wJC4O_7|4uo~18vi1(Ya z#lf?;?kLFBl0Vds;)B#Nh8^6o1hrkpLRR>Jav|w7s@^DQ@0O55uzP0EkHIz!p3=Ci zd)Y)u%l}``{D00d+f)}fkyJkOK!TdNW#D7dE((2(q~C*&sPz5LbB;u7wfFuoIN3n7 zLy6y+F)Z6MhQ5xV&!_qFa}O&H%2*OdOYcnyWmU>w>GXYe22wX63`;r6XUq;l&aU5e zcbx6S`0;FC4GaaOO9pN#;a9UB3v|KTXjpneh77IJAD~6L(W}J4g`(q9Qrf^;yJGeF zY4yFDR@Z$DsJ(#e4}UJpCH>h3?9@_vSG3d%Vv`I7Bdoe=--IH(>0DNYoL4QEosY;1 z@xX;iiR@z3Vt>&tynx97Qg z+`aYFtJlf`ZGc)O9=-Oy?#q{D{3%MfR56V8R(77^6vUN&kSGZ3wzOT9~b`+-qNuJpBz^adM^tSH)}x(K~Xz zNM6QZbw;q?_@S0zWIQbG1MAC94_#472Uiu3CiN{60&TNU@8L#*NL1QOJIgr&F1E>{gz~N-*JJI@77D0wxB!F%#1;nU5+WX!K*-=sNXd5%MQUXy@B~DyC4uf zaOra4iT+hhCl$;s;*^UX8JW^eauqbEkQ>9Jo7lV>n{3)^77Xp&r;$9h0gBgu(Q+2T z=-9W{?6R5DC+7RIYi`m53iw%ixROZ7!>k9;o+cAL14PF!OZ(VV#4HAt$DNO+o`BA3 zg)8r9607}W%k_Ch_YiCYZ)Z~3yFlaUO@S+z8;WtT^HfSIrDg~tKpPn?p1ONa{PcrJ zx{n{HVnay;=}nbo+lao4!ODQV3)!7cm756P>(u0`1b{xDQdcB9-Bz|H6lY->17k-< zeQ#$FRO$}A9mZ<(oeLiKVn3TNTdEV&V&h0{9shI8+F5TI=EFdA*j_pPpz@i%3S2{o z2k<_(4y7`31Aur@HUR1TXUGF0l)wSr+g!eq_2%=qk?CW->z`J6ak3-g0mNRvYHRa2 z#BSs0cDp&M($XBFIg_x72;LPYZk28S=vSu0h$&#TfonGt?$WH2X(vLZAyjG| z+a8}jzA_4^w4n$`90Rf?pKzZB*r z{>IpoePQ@qMr0T-%Mv^Te;JCSl7Mb)9vg zg~m;hF3C=oFmQ{CS*obl0iWFSZ%!21q)3%|)*C)-?g=%yX50=9Ceg+4uINJQR9>pX z6RtS@HqKh9`;VFY##;v!5T1G?n`R)e61E|iwh5V`nTRMjHU@&6|J?%@RDP6mWra|+ z?ZAQkm}Xvkai&s{vhrgYy!mDrgl~@}Nf(~|aCf{(ZPmfoB_C|f7h4{oRnNG@n0wBT z_oen)wkPZaHdYptohQ&RXIDce%PPzBr!PMwU+Zg~q-4adL;6Teu!Qnn4VPlx0Q`|a zcKV4ASHU9+NePrqLTfBvYkP13pIrV^J!0phCU1$b>dT^q0FFkH7uWCpi19$xk6JdB zJ54s8+HgM#tLrcNf##U9`C#D9ZsQ)j$!pxAcgCfSsau34ZDd=jj=IryB7#OAFGFlN z(_|j7BuSHUA000-zA~vG#el zES>$_h}0t+TM*9_jYA3JNFlL#*&G*L%!K>GFv-jH^M&)tZHM)xOU8a~!6T})1#FeD zX#)cr8vYzdgda%qqO6?duYpWi7wqUQf>Os9?pGknMzT-OCB4eS3AanW- z6tKmPY~5z-RQ(~0%vMY%kV3Q6dHlufN#A4o3*;7H6rPL?%O=urdeCx+6?Em~E5r@}s!BUBXjHyDF_p(LbI`IT-H0oYX z*Az>BC7xYdG8Ti3@uWs5B=~Eq1iEjWlFAaC@kQ8#u*)aWn7sfIB|9w|1C%h%CgFE> zF)P|fIAh1!cE_2Tt4w{|O0QB9Go|tRXh`B%sNVt@+k15Cga#epE#k+3g_(UR}*gToRZ4^-h(omczvZk~?<2GJsm zQCW?Csi=PL^fj=h(}k|@r`ltJ<8)CW@6DzLzV)cObPZ5s7p15%2oK1Y(pV<|_|Q2a z>pzfi-~ni+_Y?EmHv~-I@ykN>Ewl54(C)sa(26dPRDY#&azzv|8&2tN@(q0^;d5Qi z7!E>{zmc4%5`Tvq>$HW=CqbVEK&3sZRT)3Om8U93oLD!BQ?Olx3CmC~aim~<-88hD z+}(Z0`UL&X^JRGMVP>4qM-JX^OR{5W<*~tFSGBnKh!@0r(wH{DR>DLAr+{zRw&*=s3&Epx`|S#qaI`P`~p(vvDPC^#Nj`ei>l%W=iOpnDmk;{ z_*a9^rnR`nvTX-G&n15i=vm&;-`0JvO1UFvxG>g9nCvA@+_S6d+oN)%_Km#_`2 zy)*B|l4uAk@wRLU6%G6bY2=Vy6R>>Np6}vMF3pNWgQu!@)*Pc@eX4bbHq5_gXRVd$ zKfCr)izVH(P)nbMUJFkiTvMomHj$cPrt-!z&hN;d{%Aqu_3ki0$gR``!`h_>s1cRR zxNH&GN;^$3YaKkmc>UZ>Xxww;0f80iUo_4{yy7}^>flmQjUdzwAIf)!^01bZex6#i zBmU_P-VOVmtQvz=TDU3Q*a%#-%F~YqfPM5xWR};6P2&tfIkGuBP|<0=sZ0FV9qs-gIfth@ipo z2qbtJR5&AT*bPWDHA)S{5}RGkKjWYiS1`=+0DSl+Z6_a}+oXEU1v#ULliEgc0&;2s z@A~r=F?iw^R-Z|duRHV*2hou#t6UDL9WN+3nLo)`?`WY)ycB|{GGk){9+pk!@Jmli zs?_I5RPz>qK-e*0@Q-U{0;P>Y1=#zGgG(_R8rdVqZX%1miq)cY)Qvo1T))$k-3&%& zve^Ejb#1G4wqTiTI?bWN{oA&a7hnvdyqJCb9dH**ze#I!OSP%Yg-IQv z@Lg8N6jyR$NGRhR%lr4hj4K`(*+t%uYf^3secJn{(jxSuJ?<#6e9rx(u&VRuA`5lJ zUBLN&QTLufP4@4%FNy++fGE=|@M%sC4d>&KAj`~52tP%J4eDcGEnqI%L zqqXItbca`~!YVb2;|hYv#M9f~iEz(6)Ik~kM@|giXSfs7tF?G|3P;~s2p#+`NvBNB zp}5eHs5xjbOmgKoN=2!i7|0ls^YiyuThI>5I59y^emy;&dyE!}?F@hMuOq+jr`)75 zAaRoXU9Rb=2dH|v>(iqIb)kS8YSW3Ubtn*PJ3z9Wmhd$Y#?k z!5<=-b3cp8C?C8UF!g;La`p2}S?~qs+rjWbADy0ttT=%+$y;7R71NiRu1BfFpB>4^ z{StqnA0`3L3N$GKaKYcdC-8-)$4r*1s{#zs8yBmN4T}GQtQ!F_r3W^PU~tK{Z|xLs zl6~Uq65U5G!t#sf-0%XxFULABpFJo`sH{ZAYpECiIUqiA!B=1qhJpZsA7yza-BP{k zuHG1rb>{SZ|3BH-{}Yn^-|Qk{yoNEFVx1*&4yuNEwxA{Xi+0ye%@l5Sr|G?b|I~cg zGzz8yfsS3Q&K{ZIj>b;a1F)V~O?i5^p{*2Ye!n29(IipygYTyI%dk*s7lz%70cFxSQ*p1XJy_q4_ zD!SGx+qL9)e86@msk<@VsN^>RSUdBS%m(c?=j#z1q_e-HSgM81Ct%G)kkQxmXPIME&g?P8LEV;*5tVLH&W z;9dg3=MD|Xaq-o+K`K!)CO62mcxExg z#UO3H;k66PgFjb@Yy4p5+_NJ|9u8Gw9<*q-^8V_#141LmeR{QS_N#i<=C0`7PDFN( z4~`!8Yd2>hGT|<+e$wK9P^L1NB+)_H<51?L4n}^dKr~wVU72o(c+|(BAMxJLns1YU zMx}7g@%p#&G$eUNlG;JcyI{_nAS!S3v#LFkME4sS5#(Vn_7|g^`87*u~w5h zjPb8%vK*;w-xx%r(>(NH8p%<$3qmd4VPg7$5V4Kdy1fu;a+_^-uh$4~EZh#vwou(m ze9|N*H-kK;pZ=)xpZz2;1To!#KbP^~qcuA6B3pW*aKVVStu#(69*d{6w4+3y{ImmU z(X%z2HhC6l=3>PIF{q$Uo5)`PzxlfRzj6&~^!1PtSsTmVZ_o~B;>VUSN=bZwSJE24KexM3HT<8thAWaHrEDTKCQWy#z@ znQf((FA4-4wnuWKNF=$d%Dp)BaL4)t2%k|E^XV$9(!<*p^io+?;N)mE@b zjPiYP(2GmoqD4;t&D0WrX0^t%EZ+=S8}Kk@N!gNtghyJ-ToiLtE74(1csP2>_$yI{w|-KK9hKW+?xuhO0Q$CbCv>f9WOm>LWvutj(8lCKvxku_wC{B7*{ zSsASd-j}8cD?$ml=?+|u`!@vhGV%}#Om0s&Gmw!v5RgANUx;_LR5ldMl#;j>-m;yY zPc3u6$xrP!m~WjZ#Vm<#>70D8-8D!z4xuU()nniC%D zhtCYOT7YN$CgU2sey|mvWQeJH>MjXhlC=$Q1;77^5(@99)B}Itu(RUYdO8s!F z{hP_wkn};rmVHbvO7pE0n5V(-FY~u&2B7}Y;mHkT;8ev%`j19H0k{a=dK|Bb&%EI-Pmq*sh`+NiHr5`RjayKG>od!_27MJtsM75#0{@_9p(wE;zofrF>dC!*q%hmxfW zx`6117^#p~Nn%$v^?jS37tnDL0~t~tvQMFGhF_U+-5yX{^AcYm^>iXxs@axZ+lE;b zb=`)ct^$ogrriLN!&+R^6Pc;3>*Vxivdp4>0Hn-2d(=ZCJmamL{f&=#w8}anbEXPq zy|C0e#*;lGg6wAMgw>V3!maF{pG9|_M(K}GyfLz)p^WYscVnSQ?ADKnb!2^LpvGoQ zK-k=1p;_T{&|G@S@yr9Fndgqp4!rUW)fzATu>*;H} zFZJ@?)8yF<&1&^HK?N1S8Pz)tMqjtFjmAs-ZHbJtczZuf-$q$R86~xzRS>(XSzvr* z5!Dl`{#tWowJdG)Zx)a#`FHHtdb6e<7ag8bZ4gMcGm$3gXN%M5@)xcYsH;BNx1-N} z^mdDP;z%2=`tyjQAdL`k3deU|oSbc2V`r-CqNzMPvl!mOdxpl5KfoA6#8KLx==2=_9Tg=Dc=$ z9RFceVAHkI-{$Dt@Eva~RRtz6$CREm@a^dR{{TfJop>viPRio4bRZSXzqfSaE#;?7 zIL?@zaGEStu$|%{dFc@9HVM;FIO&H8PVUEm1e!H&A|0BBGmyS;H z#hg+mL@fP|_rkBfy@`P4t#3!rmB0LpP0{M@s1dk#C+k;lzp%-K`0I1UA-+2$K9pBu zCyK?M5M1c8rr!irP40IjJY9?NL?G4_1exc>DUIk9($(}((Cb-@IQy{Nmd|4a9y zj8UJ;PHG*SEBn=Rl+QW^$saUh{u3mZ*08Gf^WUb6yAp2`AOE+$@DAm%b=qt!F|bHo z+SDE3S}l`Z+Zhs<5Xo8?f0w$S2CvK38Bi_`7EJ$#KwL1Y-$ZT3NEX=ckLuScUd*@M z-w_{hz9;h5h_f*=W{{BIjj6_u{933ib*3|;d}g3b?yTwiO7(u3i+@n5XyUb4L?ct3 zV!i71yNT1;y)vN$NO|&yGjab^`dyIFd_7Y^MGp6?IS8LYWaK(CRtvaIBY3jN*h@y@ zAw(j(`nZ?00Qix2twe3TUWtVw*x;tZQSH+h!W8E0`M!j#(y{44!p(QaL)^lp_2U#i zk9frV9G^!d_r{eJEZ&IY!Fd{(5lS4fz~Kzsvys`O*CIMVB5=CPlPcz9(*3@Z0hCjH zX51%1HxZnYXj_ovUdy78t?g^%ftfLzEjFI>-0Gjm;U+BH3ZppYYZ-#A3ZYCCr95eq zCqP7AAtTmM_0+QdS=ca!EoIVl(%M13YMdtICFdQbdlAxB701S9c6vIU!^r(c z+Vinii-YRjprT*>+ZLy%O%)~PzZrC<=q;Y-f9MW+>!6f958OQTkcy+Y@zXGAN}? zmpFbCI+HmPPd_v!Er(K}Qf%8DPMCWd;&ST%T^2cU$%XF5t z@Ffi0NVOt)GveM(Z`CnJ-|Ld$Y!Xx-$RQa@43hXY#D$2khyE4t##=)dAKm7-FY7t9 zJp)GJ@oFTktMPn(KZ$al#)PtBLuA5>bQ{H_I`F}L*1WcYE*6aZ_b)@9nM9w%du#=M z`$6^VLf;mHI1@8?{z{Aglz5~AO@K(nBBE6;!`mcd6p_;)OKwm@mm3IB@?al7*nJ#< z5l~+8fHUKp2VLr?+Mern+4PX-m(3%wbrLgfh?0qll$8s1(_1+A2T{Qgt(2+Cm}e|z z2D1DZt#ky?;HemCO>d`bC|8Qog-muiS_;z25d|3^KDG>)imVp2-4Mlk#urak zWtmj_ghl3$y`~AUu2^qt{KFHgsD`{5$hJ>Y-V-xdRy)#vwPUF`-BHB zEpG+M&fcDUmA+HWw;vvOfZN-1LDzYfUt>$*ez??=b~@U||6=h`0T>Xf5b zYQ{2f?O$9CTe$vzGkcY>&VyD+JpUnps4>l$g;(sA8p@qep;S-mZa%cv{IGsno) z31WXcM?KZIVoGp|Tm`i`PgmJ5mCC_vFbNr)=FTZ1 zoqcV`#*5bO`OV!F#X+Wn-EC?KH9#N^~ozC;kOduP1RDOZD&Nk*myS$@!D(MogK$&a*0b zQfBj4!amyppP-u(`c}l|ljEvsD`1jJ(r* z3x0~0DzT*jL|yL;_Q!1Me$#UIb}K4>(_UovMd;UD4hDm+z_2Dh8zOV%g4BC<(PyXZ z7y%8EDhp5Q!Go9N3q}6uH#OKD1?!(uL^zHR@ukQ6Xu0IuM2FLfW-qsx1aXG&ge39S zsDB8oGNykuem;2tma%1!5;-o}iU<43I-Fj&?u80JaXYGt0&AL!6Rm`tCQ^Z37OL;> z|3k1ly<$TZj>ZkOt_+~QF$W;rMt0*!(F~fstBg-0U==V+p%FE zyCxh(J$|l^*g*}iK1sXP@%-6fc4(}H4D}z)r>-c&pe7YioovY@M{?qChRL7ro2+2I z%5b@%y796;!=s{vDJz`?GUCB<+m&Csn8tdf;f~NzHcP;ugYdO=!M90#eC`9APpTb< ztEBYCSim1j@n@4+!)7V#D{52oR?RTI$*LFIoNgkW{m7SNR9ny=4MpAr5G^(j&c+ z%IRI@_RRU7JMK7=U0}$EkNlL-oy`C<1Kj@ZA{sH+aTvg`pYuia{if7NJL+cJWZGv! zP>U;$`acF<;bt%m4usBX0&m8aG`8AS2a{IqLlrC&lu70SG!DtpESUWEW3Nj&Bkz^j z8<{TWQ10p(Rcrbe2V0Xjc1IbJbQVs$L4p#$Ejf%t4o=Lz51@5CxO>4cP8_pywl$iV z&N4;eQ_0a7Ukc$02%1R!qf6dGQvQ|DxjTtimh9cQ9KELr$J{zy^XqC&0blasn(s>} z26CwS)*hRC3)nwUj-&{WbEu1Zp|x?xRTu7qU}!mhc|4E1(7Dp;?pV5Hgc;!3L1vBS zQ!O=K2PMX9Obv^?;-*6K#NHEh4nM7xjFRSO2(INwgLunyP`qmW+v4hf?h!w}*ZlUe ztvDl#?!0B;9FghWhf&1H)di+!lSN0tDpuKfa&aSDCuxtUW#QFwb>7^`=-bES;E+{k zAHzQVQ#ySpgISb-fP%u?vxlw^xbf8m{Ba?wlJPV2&TASb2*DqOZt4}fzCtI6I4jrR zEc&}Z>#8}xidDJeVgguSo<@S$4BJ2}$nj160dhLrR(0H8DpHV4;nx{KzKy)-sHv~t zrp_KS)`3^GaW5&=wcYm)SJtD+efFl_k5ih;17_AAoH&}ooioLV*Y0>`kg45Jaq!qq z4g>mmQ$3K?4%>|n=dfc?t@T|s9WL4S|^%Op^Kk;bNp(rO94na+8z_VUi5N z$YmgDS4}VNBo7q;q~Aj6byM&>(_HCs*Q%u#;yp73hZFcd z&&ourX$LL+Q`=eH?G`eLY)c!4B@MQJqOjT2m&B8xEHPTH7szxAXuT*UgzYGmb^DyTzth0?#@^jx z2C&ztv`E~ylnhL03b<}**=r-?;}G<_(|%DxEY!)|SwcCS$Km%&zh5XRkayNh?{FhZ zj#`Ep*6-|iKJT;WgDS3`Ky`C2J)7NdRvEGvX8Ka9;Arb{;5qvc@$!aU?S1m838l2t zSG-T49{~~{;Q5EZSDRY@q_1wvItblICD=R^5bB?@CKV)!wid*-MVcu@Kq_sX%n<&X zveiKW(3UOEV+pFr^E{3<-p^Q8`OEUkIUfTL_riUGgDWlfQLvi8@ zm@b@Kw}~$lR;)95RMS71{8kwB1WMp9I(&$}#SO1b7bEEsroLW-H z$?3z7*Y71jQpU>2I{A6hI(pZlZbx+uWEiKEY#N_#hn*Ze zlAbpEluTX1>B*aPMWUA57ygzJ&r=dOm-uEjZe@>RV4h@Jwf$x~Njdl&4bJnV$p!E{ zQ=I~C+-1z}Qy|s9fwgm1&XZjUH>!P+6+F0%^8@Ou>7;Cxy{#*{ zE|k|rPuiC}$|4e*IMzwcP#0I;_6rFKGET4|7ulG+A}o(!YRA8~g@7Q2H_Z3z7TzE5 z*$B~-s=e@id6lQX{>&>CM7uEApg=zsFpeJtynS4XCsKh7ZW&3KKY{gK!BBYV@T-)n z(^+$~uU(?`G)y1PJ!Y1ir}`&K;~T+)f0+@7?GoF8Be8CS0`U>&@iIcTVF69wNi&Ri zbhG1aoRv~QzQU#>5czgOKDpfc8ipuomwjwi^#-)sf@t?cQMm10LQ_EgmeeCAmRAv` zdso-}l{BG|e2IDRJ!A7FpH{9xw>;V|=!jBvMv}0K9Dg%%1~Ee=zp?znC#G|a+wP;l z=2*9^bHV^~&~Mda9#+b@0D*bugbD%I4iY)DW3x+uh+a5Eazsr>knf@HR#7_vaQPf<;ETItvY^b%;_;#o!Zq0qJ3$(+ zY@sfLe+cj{WRY%{={vMN+^;Z*Y>SyMGi4UJ=hkDJcy>zi3VKw%q%r`Jfhpj~X8Z$UiF)N(a z?S;?S*tJf)K5~Ural5i~pS<;Z+M9uw3YrZ+rBo)c@h+MEu)Nb0secG4ewTc8igI?# zcChz8Rd&6X`N+O_hv`z8^1|d;fROPA+edG!ebx^Dtr(Z#4&m{0={kx^UjuXV>q%}S z7$8A*(L|wUBDErfO>rCu-Pk++yQii!_dgC2I*2q*^d^Pb^!E1Tjc{-6ePE>bpUe0j z^;33TsM|}ASU0vWeE;2FfOMwQWjdvdhTXe(MY!KH-YuoHKQJ`^3Ae3+lfju(RR1F6 z-STll_Hci2^{!hsp^wwN_vGsRTua%gdw^G96ZGcM!za1GWfS#CwR794X>7UlOC7K- zv|8%EVlAbciY9DRElv;aWO2nPBOr%f3ky%04@3I+{JI=B3DaL2Xnj;9x6N@`8d9Rc z2Guz${D0U~w_I}`dwI5bUe&VEmB zz7pqt{%ROuzuu+K!a;Z&htC2}vX=}@TiNTcGX1To`iG#H1p_(z3Qx~7n{68|>}bbV z-ws~ZMe^lmH-3Pt41LfWI`oYfrqsf2-Ew=v>3Dj1Ol6&)r@`8P!!)mRsp<_lHKyLT zA=*V>-5vdH>g!xjZ2Q>BTQ;TdIOcYI;1H?i$$qAQT+tz}sn7@WotRP8HpW^->(Ovz zetbT0F(@DUc&+Mfy|SKf2TRC@GWHZGhhYXK2F&bQ?O2^p0)$12bBvgym%vVoV{SR< z4TIOIEpy_}yL~n;Qs-lD?#!6z1a#Uu0qGep4d4D<0yIP+3T?p)~ z<3_lB@mm}c)y|(6hBfEDNY`Nc z5hVq-(EXO;s+=s(nn#iZ$}&oA9#eS^ndsMtaf?bp60dyyt{7p1u) z8>OQ`D&&~jU)@tYBgJ{#jg@?SBhePAp=V2 z`wMTgf@~S~sawq%<{Z7|2Y%t?M6gnre7!F){p!MzlWzo4Y6j{6jDqs8J;aqhsFmf# zp>m=TD71Z8XtC+r$5%OmFShcEJBYXR`A;oZo_9=&#$cBbCd>{oHDPfajlqemVBr+11BZ}2j*s;&NRu()Z>(=)# z_F$+Y#P?{$y9Qs$!R?U`lVRDg`0AeR{5u~Vu8)Q2Zr$tQsD}fL(oA|RkewO5dO#q(K+QOvnSRc(Xh=6j>(#Vm) z8jdLXTcU1(8sByMYx+E9)vSO?mV$mmrrYyYG1L;h?>uuH8&y^*ik@WNti4)seF^Dp z*s|cgxsZ@*y+hEjucylj&~ImX1$A<9j-NGe@}=KUOzZ=Q(oYN!%q_DQ}%j z`4ctkEa6JGZkK2c%+l%gtKRYA72ris3X#3<{cmX!Rev+5Wla+`yVU%|X7tzE`XJQ1vw`>-Ga8*4cPP8F< zzukUkU+Ew{z45H7q5i$X=lqqI@ANVdQ@ail$>=R*3!S69N5G_h$hT$0YCYDT1G`>vHzHf9H@onl~50 zgBAb8y|iGUm^1vHW?hinaXgQeVW<WQSI|nz*~Lr)+_b;V0mO84;@TxL3&a)&Yg!}bQ76vF(1!YSY#4Mk)(mXE}uyf z*5lxTA>}q!<_s5ojF~?V9X}+hU`~_!O3I>5{3L7)AX2<)Cy}I8s5_^@l0w5WZh|uG z^vqNdEYgf7c97lzbE@;^w$*+gyk%0hl#hN5(Z!dibg(FekU(-XL=l~{P9!8kTw=7( zbbUB&T=bMm8>05{VM@`H3a!42l`PiXk~Y~QNbqm z%Nry75{Q9?EBYEfbk13?Fd|G$3;MR|y=4l&Eg_pY%*12QdorQxQDl8EEB*J5IiKlo~17t9;ov_a!KX?Iro@M zZ*8C42p|6R8o@prNwLGrc%l%~;`-hvlg{b?-^altpudh*n#Z0M{GFWnL%l&_Hn_gY zv&3We8OK`^TTh~BTD~LV_wXBt<$&8oYn9Zp)y%B%O}hpUWOf59bDD3ZbKbD8KGw^S zmx&fksD3x8ioE+@l%{*&FQkuOzpcLSa$9(J1p658D!%V>J^DV4yLtiuc^lFdJ2d`p zjyyXcT__#=Oz)3{Tn|7Lw8NEd8Q(H>W}i77Y=92~=e)~*hUH0Dk8hdQkjk$Om7?l9 zpX3TDQ3pZwPBZ2vcV~vXCYh%tSWfh=w9eq^1^i-~QK!t5!!!>E{~>_hJS%XFZLc!? zAT057att{y5n9lr0g27^LV__R0uqe<)nQAA4NX;`Wi!hiKdGMrwFB&4c}_Y9zzCiA z!vkn__L@*I51U%?gqG^UJ1X{fxh>O+qAq`=k%A6_`J_H)oJ#y{HhG>eCrZgCe%|AT zq?9a0KelIEUZBok`AtrD(z__E9$)%0#Wc0#447~;g3shbc+dqJx%JCT|Wy=X~Di76L1V~&>aFS zhYk0WZ6+zY_yYg>wI%Jp%83@y@dXf}Y=el;uE7d#WEawz0&#BfLGW;T_H2rcrq@ZY0}Q+eX8B~l3(5Rc+~6t7QLxZZxTngL zbgYz)UN#uGQH*O{bUmP#SIP*4#|OBio4yd8?LPW}63)o}iMCA;)=hY_v%IHaL2S`3 zX`Gr8$>$hkdTu`FnjpyMKsL6ink=i18W9OFxp>27Zem!KQJqb=tMc*Ep*-Gn0`Ai~ z8xmG)*B562)&QX=g#1>jOaS8k!D6_}*SbOZhm2PRuq11_co=e9T{lCdslQUp>_g%Z z-#w?VQw6-JG7Y3h$e%5F$9w2@MSyNbpb+jRopDpLIPk4h;xzh52X8UdA%8yPteEgJ zFutJhOexb4Z*w_%^q$f%s^F;@j_*U!AiGO;kDkk0`G$TNwGN;E`rJDJTAg~Lv1-$o zMqZ_9OlBI$kY=W>QpP0XMj9YgL{%m zF5%!r8VXS?9#18^)}J}}P4dETpiGA^LyviVF%*u^!7e*wytx^C?o3kToZ9EY^4CE- zZcIvC5Eeg>@ETCrl}Wq=b?;+_YgBTLp)AQiGYQ@seS7{^kqSu^s`Uk7MW?mD>pi$b zw$N5K&sgJKdjc`ct4`b-22EU)`!S5YgY5d$PQY7F%nU$uN&|h{bH4@-|9V|WY5v4C zsMzjNW$Bbah6D(tey!>-AJgHUv1h<&&vwr>Q~KfIz|uCZs=!c{wDyR#tc%G6XApB; zU<4TeMY+26*5#Y;IMGT`{6e6L+Jv&;UT^L4AGuXDa<#6^c7CDYLG=FBHuq!zg z=nH6VIzQR1z4>x3LT^BScD3-(La6daMpvgvRJDP!cLV-5PEgZrj|-6h(L;xt+by|QjTP}u6QqAe`iV#dNe;FH{%tr z*my2(axVfN>VW*hMsNX|DQ`e2d%x z74$Wl>B_O4gxuq?#r%hR&s?Rku`W__3fxcAs$Kq+`dogUaGhT;B``l912gC&)!bQYK#4=u443vx_=k{DkSVq znWkTP81Yv;cvT<0{o*Cndoy)5PxlYjbuRIXrjh;l#yfCR`mNKW^dER}{e#`6+G>fN zkY!`PCqFV?;&$T(j1pu5B(*STa` zgVPNyojn!0bC*+Sxob)F31PlMq`jzUtv<7HH5e~HKfeZh8-H7RW^QXm)DB2P@$9a= z&i1$47=J${7RH(+iQ1JMG#!4v!yG6{wUM{=V0!gYR0_?sxFg24ROO<8tk3Dc;j zgkO&tDt9xtS(4MLlN)9bTEo3W4}}V~rmV|&Bxp+PE>Ys4wG9OVHc5=R;`7Q(9zlis}>q~@b2>HNy6PsiAMkV_g z9HEhTc&}?I9dnD&Ff)xOJ9+Y8ud~90-|+ps`TKtel5?i784pK&nAObJoF=;01yAp* zrxCtD6LmOnSb5dgG=|3V%avmbTwn}96s@%Rrih)vCzuJYZMI}=sTb5R+6Mw$a>($-yedY^TMz&NopzJfCTIq890w))W`qorlF5wR)_)h1agz&_SL zy$-#+(ra)(=cpn&L-*QLH4)!dW)+N3_kC>Iwf~F$Mn|rXyMpf#4Yq4LgQ@jxIOsPG_J^_tb6yHPEKQ(Y%MyUC#SH3hIZkHBTi|0~m!>sP?+x!D^g>dzsD zO)4GZqtfp8O=w|oQ=yGG$q_P7ACWqo>fY^9xw77I46v-ZUrP9`Y)JbUDR|tgbd$Kw zqV(l=@(U#WKLk|D=3_YANn|?#(45)qs!O5RNqp{sO0&CDzVphDS^s*q%^Mwtjh7a@ zjx1lq?o8WiO*FCbw2|_8D}1enUdyiZQ2{ykk4a7U&e+cVZ)jv{CT$%qMdM__*wR#2 z*LOxrjy9qS8g*_PbV?g|Wp`9#l~W)jx{m_C|i<$~_yo7NWOb$9Tzm{Y;}edUIQbiG99f)kx9 zqqAD4TZSH-;y(n#pecg9Z3AMhQc}U8FlPpVzZd!6v1KK-J8MGadP`XE?HsjP2ljS+ zF%4L6cEC!n%iP!9P~&R{M&IJFEx~W;^j;b6K>*Bzjd;~B$h7oX)ybB)p0D~|lG}KI zCa0Rjcna!Q;GIiqy48lLDTFS+SjWU1z{KC|d3FNHu~My!bkb5PlXh5yfj&%~Z;$)t zWdMH2+Abdq!{xb01#zFb`WVRQx388DRU|d(7eIaH_`;!OeVsmTHZd35s88pm2Y=Y@ zCJ*~3Q-EK#TZ6W7 z^CaPX#y{!MLU9UTtwHv6E{yfyrH}F5uMwO*9~uN9BLYOl<)z*Y*J?e}4O?S}N!Ad` zM2u8Q-I&m>es*KC-9F5e8CW({N+f_2`FvvPrI(53Wnyt+x0aAJgy}^ zER@m_g*Q|W)HuXuh~IRa*Pl}EmxPNH4o5jYz3@4o0ul+ncAj0|7KV$D8)`4{T&a|d zG1Zaul(r(iV@S?VgRUr&A3D*SQ4_YI{n_u6=Jt|CK&>Ae4&m=fM@}@Ro)Cq*P9o_~ zUE<3yfAo3xIc*O^mmN_-<`^9^>l0|0-(#j`a&TZMFp*{894Z z%%ENA2J9q_9Ys3Wg|3{u;sFy6ohI@kvaVVxU(3i!;9=M(*c-q9KJ>+H-J3LJ3Aav) zKag-COk8zW8_xO)1;jK7df;9DZ6%1iBkID%7NH2q_ffR*q@S^o7}u(YqI%F+h|xn``qjM_DP|aVVHJF;(Asm17zd&Fb3aj z%_8t=8eiS}rMNO<&_q=xa5@;JT)XiUWp^kOK4ZS&}TT%26sN=Bb*qp4OX zJyNRfeHxd9%$J}DHXmEVezCsFzx8m78K#e({>y{ZYSG1n>H?ff5tdu@YsmFB+%vM~Nx`0=*>$@sM}r(|d2ol(Xh zktZV4Mv(CauM%59n68;k($KLi&rx*7gp&qO26SADeCbMVX=};;%o_W;fV=YR;X3S? z8(AvkXf0?k5b-DZ_YBhyCK@ftE>Sjynp0T{{^Cp3z9|HKVB{l#E*9xWERxbavWPyx zG>^G7!(0G!wX3Odxd1sZDzca)avfq>hmVz5nI(RQ&Oqr?uLQg5ADIR7C(+L9XD-?q zMVI|vF@sI1FtVq1#q;9w7>OzlE@Kc5DhCOc7sX%(gT}%aU^*(xw%!U{l{HgX>a?fg~%#3GqqpI3_IxrH}r-VJx zY;hdhe&gx=`S#i&aesI4mD$&xN&7Ud@q?auO7mK(RXz|lON=|`K@IR@N)hGo*lFgi zlG8h@_k$GsKHqE@sIX{@Nw+$Mhn`f_$+7|IsB1Hq zT3Yz_B_hstoW9SuI8Vh|E9|2oPm-@;pnvl?2wE^j_mhSJG9>%?mg$1CVyCf%=o{Wv z_u1~t6-5z^^6b?!-*;nAnGtMy?H>SosTy(ZtrHEd3o&QP(n}jK@?>%R25iN6j>;Sc zb6_@WeeqVxbvI@`k(nt;3jN!8W45WmC4@$|do&0(30$C-aF8ceuuU`dbwooX-J^Kj zfKe1+jIf_W$hxoj+B`(o*|gcmKs?L%p`{&f_!3f1Dc+3E*g}^Vi&*SX)|aEoJ0te3 zRew_{UOKFc*!Pin?p-Z9`}1SaoqQaRhx2$mga`QS7Kts(V}G9j{o-n_q#Qn>(=BpW zb=JMUsR9ucgt*jB1r!Ua-~j>ZtxeD!WSQHbLNYSo@C;N zp2s)8f8HblfIlK8Gx-!KE9gJ5L^&@hRe}yi(P?IH_}kQ=v;7DT=eItJkzLu zp6FVMIA3{xz^I?&ySJxOy`K+cMutr2kK91VRO|dL39~X_NMHmf)|`J?NOz82A7b!B zCOW-uA}?7lHGc+>s9f#_X4z=3U8w1*wEpeWd@}Xmomzm+lWGmoRZ`L*X>4RndZ67) z3Rg-{!93V(nWJizc3~LFx$L(aCw9+miRAp9*m=?Pnv^|nrS@dEO}4qc_KxBWmA~W2 z^Nb9UqQSy1g^^uRHjbz?F(=*$tbWF-damQmqTf&MipFmWYJ3y3j$Bku$0|(_Rcj&N zI!$zxk1E)3wl~Z5u};6H?YP~e+9v^1uDbgzp)gYKCuhiuegGmmh^{#;(V37qE%2b* zMa;c%!`?G5u4AG{hzZXF2x*JEizdFe%c~0jJId#WBNXihOS&8!_EA7)qY+>FBbce~ zp_hz*cCHLd!x%47X?AaeyZexVWvH{eYX1^nwiWS1%q<40Ds~l|4j)atQ!?kWfNb8m zEsc+o8QOa(J-&Kys`pMu*MfDQXu0AiZFhmD)RMg$<&!&Q=VYSud(k1^sjO%sE}Da! z`yc8D$kFUnDFUDVt*dVj%NU~71wb1f-DkR1JGaBNDu>MZpi2Eo6B z?!#XEjQgUL`Um1Gk3*9**AKV}r};N`94p+|;s_6z){x#!&w+rN{~=IPBb!P<|LRBW zztAFKbHLwKgoiQb%HoW}E1AZ#OAInrl{~LjZ8E)|lMMjYtvrebqOmUG899?x5&;Q$ zelxy)WY{Mgjw{YwPuAfw=TmAvK||!;F}xuOL6zS2)t^sH(>#4@4jmU|%<+__l3i_| z^Xtj`Y{%z{%k5_lhru87rtP2RYP)Jiyz+p>J7ahzVY?MRXb6J@@gXaOM6;%kXxOAQ!a-|x&Uey@qOvOqafO?|80$hM5v&6i=3_8g17wX+NK{_@;^e7TLi9Mw|XQK>@L0V?!ZdQ*36DVHTNi_$j1+=0o$Oqep%jdpjV>70Pj0Z7;QD(AK->38CA zv{mc-kqrs?m{Rk<+f3i*2Mthsy@XL@k5FT>Lwhw6wK?wUDL&MTl$8nk1)rftD%Hg< zcN{poy$#rwQs|-Yf5UaXgVUp>P3Ya9Bs4gQ!pBJ=7BribBCBVCQ-H!uCC^AfNI3^`@w?UkIaf zYCdYWN-pJm+qyxS`-hahvyfG@Bc|X)S<>G>%&~x+oPk=Z_O<=)PGj9M!wbTbN3imP zJ5W@AdH0*mq3e9-C3d-OWQ%lr8%uM?YiTC4QWk>>T=9oVphuX0$lw(8TG|8ow{v=f zYq2q<{%pj*)<%!R=sB~aTEmpmj2daOGb0oBg!#6|4gIE)#n4DUHK#466f1egoGWpO zc+GsMjAspgX|Bjm@LynK(b5||md)wdd}KW&km`9SCm>;ArwHngf|sD7fv+_=-hH?* z0x0KrxfoYQ4S{5t_5xogsEyT1=r;knO5aA zfbO}~b&MAoIzd^erU%b$lq`tZqb0|OvlRgAsD?h^8&0G3<`p}5}5DP7xN%x8ih^iO_Q5%-n`!~{=w8EB-k;IrC3&abmK=b znyO6yHRtM7<4wFb2v2m#&9jnZL|N*lqTG&O>2Bwu5WykpVF5L!UGx+MJ7sNNDE^#I zgyyLOIyZosBj^91?ycXNj^Dn26ctoLlui{91V{G>LFtn291SBkI#g1+MAq;VRSd%`&`%k{THt9eZ7wz+pq8K*zrEk^Z7cTkLN1Z8eKWb*0LD4`VON~dH-Be ztx+Z0;`ok?Mn~D?8^<^rWcY(4j(x0WK9BdybMWNUjl`(@+wkh&b((K|RT*ar6S{gaFl`kjyRZ@jZOp_W;@5qdV4%HJCae`C2y zFI1zF7NlE72EE@3=4?E%Md77fF+S5-`ZPcBngaLwc9izGH$-?wv~=7%+qUO@L%zfw zp89t5`PYO7ElCPF#VUHvIgzcJ{Gbtum=TBp5{&&O+tR`Efj08W2t%Vt!5gh%^F6ak zh_%!}W{dieW=i({K!OEKnf9}z7od!RP^+S0b$}LAyp`%%#@COEM)%S>-=-u~3?eGx z_ciNH?YeA*&%H%2B5r=1*gfgooy-pm%Z^IBec<#Z_39Kd6{Q*<+b|CQ$yq^ zWQU+OXvg~c+$s2TkFbX=%$3(Qdx}mCg37Z7Ydgys!6g{S1$J||ea4Jtr0hZ+c6!a| z(+TSLv>-vhuT(^T?J`>{L1A5Y1y;h?;ntMa8#~HoXvCtmDu6K&@^V+wjBOiLwgNd* zhVvU0@^ZT62M-E$tI=$@U4*3>9%|A%*j#ALi-qIx)M4UD5XiX%aCvserz;?bjT7uV zc>uCxr~87Zz(0?vvZKhM96R1s1@x+luh0cb=*%=9=XoxiD@D%T-oTH97FEIrkC)~q z`}b~os3MsTaxIN;c4ww<`~OI9#f+e`^>{I!=;Rw;1`60JCY=v2DXBWCQ~LVmA5LSL zPo>v0)kbB@ntf;Qi29vk?+iD+5^Aos4=Ke)rtPQPa(JY<&oUFAHc(bN0Co){!OQGWZrCX zNZ#0u^{olm0~gc0QJM$I@|6}@D&AXEY|g%mGDbl^II7TkT11I1_(zxZhM@o9a9?wP zbmk%mEr8~--!Y=mhemSOTHK9VXW%G0<)-W^Z8K}_PBZ$=)_{RjMcZ*J68IvsLQ(kNJ6`nf-7^A%hcwO@eEoB&O)mtElL+ zF{xdbngckwwz37K{Q%wCs?F86iloC&s>O!^t!@#Y5d1yU-n^sZ-(PbPIXHNh0c}J0$5GJTGjR1A zY`hK!(Yx9iPGZ#68~-9<<$N8tetU(qRQZ|}{xk3%@`rO4E37tN=YrSE;%rt(rTPB^)ct!&N0NW~0M$^?8T=mTA-7&&#HO^==L?*>)h3}Ft z|Bg*|*1a6SAKl3Zos4NmQ3zKimiUm9UE1BYzbeo}bxgy@*C7_~wY!R;D93JwoI&q? zo|m-|Eqy<8O^!e9o#;ouZV4#ZrSpQO6z2UskipA3)k)AEEoOx>GS`_p6ZV+eXjye? zejmCHf}?$-f^;VHsbi0fs_M2XU3LiX_5118O0kGAK)C-qe!y+aOcY6)W?j9so7&R3 zG!q&4ZcjBM>4-8_kl#40SUErxBgiW=`63;z&;m%G5-)dx99Zi0ni=)#Z;*Gs^LA$$ zO+u*Lw$^b)V|;oU0HvX>R5c0nSl6_M^$4Guk*mganddv$OK+Im?O3TR;{%DyW+h=o zBLC#S^U{HRQVH-6^3!EwzdnqCSrvoTA4Ep-J`^3pfQa-#WIa`r+nn?6U*JTJW=VR7 z$}PEWI%pc9h9C1LO>-cn-XZe@@P<^cJGq3pYavz;ShUT>^bpUspaBC5Q=naG7J!TnT*Xr$b3)1iLH_D(h0A3Y>b$tm$*cybes67RNF zE*&Yhp=J^lOLsW9g9>?nE>h_gSKni0FKJK%k^o`_=vFjhW+_@OR0^&kG@pdu@-O7p zqKeJW#g<8Gjci{4OjF*V94aE@KfE%n)_=VCiw{lqYe}&>^erFtt2atNzc@CDi~WvN zeR-ss)HJ!^O1~9Z`wQIsWQ&*j@WPCBn|DbL+qTIHNVR2j)e}a31cF^Q#JzV%&3P zmK%fNIFw1A0ZqXncce^s!mWwQ#vy<-MKN$t*Ke=_t^f1WJGZa3%7%tOE|np4ifyOj z|F;qJe;0%PXFnvy)+sAPe@)fbo?FY%CG9;$Q&8~9&+;?$B4_NF9L=RS%7uPEo4D=& zJcR}=0K87iB8QqYye;h0@3L)#w{d<{cBBfhPDMKwahBHh#JrpmPzE?&7jnkyZ-38u z_M4%D(+#a&h5z3T}iHg_QwFD zwH^K#lztzc8i&MpqynSBNP~9**3$`Q>-IFwcC}6S1qQ{*uVw8_kxck~os?;pI z!`r%cb>P-^G|G})5(TMAg~^?PpUD+luKM|V^fVUiMjgl;;*rRQ=$LJ50{-D7w>MPJ zZ9nLd5cWYB$KPU8x@P2c1qa5$d&DMMm=aIRjju%c6#iuY%we1AeA3C%(shet`{=Qj z8~?<*SJbnS4IVGw$;PA3Vt<8hqfW=YGSe73QG|6%t_23ZZuoX7i<^Xx@a^`L((i)Y za}{Kp1Pask>ccA6AXt%IN_IuT_#aMzQuUyFK=~b8TW5oEmJpefHT2+xhZ}lTMne1r{E?M%1FON zOi^4pm<4JJvp_bhmlc&9!?(kM*I+7H<~HOqY(~~^6ksHX}K$w7Oga`-DWK>JMsm7=U~@C-d2=Is8q^K zzpke=hrC-O8FNz0Gi*FY(j-Vh`ERYN4_iO?deRWN%{ZljDOA) zBl}*?I%`KWu+gw$_Q2>N^u`)^Pd$X0mxqTRvb(mCOpH(0tvpLFHRe}|IC6+}zw8%n zbw9?4Kn~F@jxiBhno8wE$34a&&M5`$OcST^&PN>pkMZo9%4#;g1 zLT8>WOLjT^AC3xa%LjBVob|Kvx+pVKq>mr4YC@6@&@A0|-;d~F?ZroO0q(p5L7*eM zS;7GR|XepSJ zB?lI~X@fS3ewraHmn(4|KiWIfO(fQoVt*6uh7heh{f9F$-ChCz3HCC*bRT$c0Et~{ zE<(_F4|fxE3sCXu@FGg$NP%upTIXy-xU{~UqmQ?vaoI+^P z%LI^-YVT6$V&L|CpaqpjEVUY*gW8|#5`PTZ^&ifh)rnCjq)aJE;9lip`?$Z^oKgyX z53d3vnNa4NNgn@5Bc0`gZi54{eqm!AXQ4$7yltta0tjWzhC0M?(mR8~CT$k(Qf=2>WKcOY!?};@e_9ao7u9Lp{(#QJxNqO0NOO^~H zpw7nPk}AK-URopHpHQy|$K7NayAS8V6^Z~MWli8n(YDun6?ypBI;gI$m%&@<@lbU` zr`-F+KU)K-Y#f(N@UMFUED=p`9a;XA2dLxg*xgY5{@8_Ccxm){PFw?^GCO}loHVv> zBPXIECp>+8#qGWS_PU%Q5(WW)`cSG10vcup1ufHFzIjh>=>K$lw6R~jka0dZlk$lC znbnzB_m-P}^x*e6l&MqV9%B|k!K=45PF$HFEiaNGb?LEH_fi$9SF4=ec$xR_p< zB6ErR8vb~$L2Jg`WR7-qKc5V$+duhV3|WF^c8k#VdQZos=-*J=z?_Nlc(`^8`R3y+ zwes!m;Bj{=H*xH;c>QcCd#+I7S?zN6P!fiyi$&^!-j5 zNNp{WbTE{Zo)twzo|K_2&E3$E4o)nFSE6-F*_eInzPP)ll<8mS)uHb9;cf0_4QJbW zSll(;J21@damlm1scoEyBFeA}4Whe*IL(r*ER#@!jDXs7{TxOYvqbnP{{dQwN){;# z`E))@h^jEy6qu|n2*%8|B*j1>b@Q`I;ql-XblaDurvtTtH9wWU{@F!C!d0o{wAE_9 zExF3>qF3);L^LEI|KX^YzC}NE2sN~=4R1et`Q+A}2T5-mV6Lska z__gIR-xw!o5CQ`kF_cvpLgE+QRONRP!5p&ge&{HKT;u?O(dRE2%AHCtmWEUl%AmDg zr7;5IkQX_Fh)rRC!b<;Hw0q)2san6E4KamuQ0|xQ2I^vK`MD^gIwF`#A$G-KnVu6$ zd~3Ku+3?K{qc(^)%hn4Id)r9bnzs8|Nj4dV*XA6uRYIY-M!BH%FfpooigfY*fOr0tXjgn4bpO(kjT&O1jtc+lr*{Hb zEmZx3igp369(3iqhx3eizON8WPt;7#5K;hpjx)50x7V8b{3_wLUJZ0EGZ zBNbKy4(OGAvirBTuLIjq9P%d9HJE7p~ueI=?QSU z3YhURdez!@`NPMitwYuyr!Jx?;4*M9FshT`^ zk3Y0E$DTa)VO;B+_Z}1HBxj~rGkt3^6rHNT61;X>e^q^g%;QD)GNEaO`7|LSD zozQxWUBssNQ6A(vtCyBy8R(qX22h;~HcMX}cn_zXp6~(wrFn3$pUpI}(c?gJMrS8R zzqSjvT}(tGq>|nA-^4HMYn0lp0*=snDp2Z(LaBYwcD+y;^$Y1=LA{<=uF|t&Ifnz~ zEYMoXcHO=F=nh`>E)@IYuJ1?Rd2GaX$|XyWe6sYh=g}KN-pS|w#IJ8YT^ewgIAat; zh*gtm<(TQ)4^aiOXWyyuUX@!Yc^SEG`#kMx5f!i4U>XT=pAUimJu+s$Y+7A9UV;`2 z8eEqt@Qo?V1kC9Q>;nOQQOdWj33~_ZYPmWq`g@FXWT)G6YuNaKayGM!_-&Jnt{u4Y zvK-<^#k7EuEXsH#sM2aJrNustLcW#ihzQ{Q*}SEtBXAXBNCyOB6NMvX?@Z1Kp72Lm z1Y0uVV|AGf%CNfnHd@X=rZHn zxT+aF|GqbCc|qSsXn|4KUypj;b}RgGvcBIJelByT;eZuKW$K0vtU@B(FJ`7m+;TEr zi~m%Ji;8CuR$4S1pLNhXyoQMM!>uN!#6DXDuYXK3qIcAH*n=+3Z$1LDqw4rwe? zL$u~=@AEiBYN4cRp-SQW>0@d-h0Nu{OC$#J*}@S{XQge+}lP!^!wY(`RT`I38Vj^`6RCKa}sOLRqP8 z@aRl_m%pC1hHDYx3dZCHJ3m5Qe)pTAC?*VOcc3$GyJOO_~vr`5v0#m zT}63$DTBUgh)C;dE#4liH#t_^qzdU&8%rQ8vwNEI^HJm^XSte4W&F6U!5jEyu>x1} z!19ONR&N2T-qt#V2JptBd)K0tngB3?BlqxKVK1Nll#A_^&~mGFPw*1Mg`IOI544tt z!09qGyNBA5zD}(&FwV+p)auKPl$_^4!J!QCXyTGNcDs{dePH!O#L_O5uS&#-kxX@; zaj;914?pTyQ`>OSOP)$tNOm5UALw*$-(mOs(Jn8}HqB0sLt;|YBO{P<#}@slg$0!) z*U4AApabUx0iAtS<8*<~O%l})1+XxM?w5b8s*J|O*5LTUG>2JVqe#9qXcD{`A#T#; z)<}kNv;PeDUBhyQNIhekKs?mZWysu887~8ctS68?masaZVMph@rks~y^ZBE`M#~S* z`R+5Z0^`^V)uA)5&)*jUig276o;u@M+4G*WTF=#KRpj=iFkTfbBvBenO%&NS!&o>X zG`?C06C;0}3xE6@vD!aVV>GS#-`=Muoq%E1zl8bc32jbIj&XrGo15IEJ2zaAOA#oo zFR(xiw1Ou|<}ES|Vp9t&jek2C-0=SwDUC2sA%fI+ZBi`cR-CU2meGu~-n22K$=RYF zhgweuwXPYY>0=)9&A8-+qz1F$bMY$B3OM}35qFG>Sca$}wBd=v`mX}r$Sd=X3T85w zT{fReYc)+2VHvCvaOC^s$3xLWmJ<$|r3_&QaUH-Ss!HltyND_Zc0SlW%j#N{Ers4E z^qlhQdJ)C@DfC-9nxAVQve7CixbiQ%-7nh=sa%7_)b1Xrx(eCKHzn5j7&|cgUWrSU zYOU6sdp%O#Vln{bg%p+T1 z*WRrb=#d35mc;rp^bt*iNI_o1I^VdlHB3*%wAyE4Pt!&DA&TZE!{HT;^^bWSN^r;v z#_f}TIA)bdccPrlzEC7yJxNhF((JOEL}J))|5YXSD7DYly=O9gfX=FkUBomiYDJf9nadqm+VUXobM(h^B@zy^+k_?c!- zoT8w@ivGnfHvNX;nAJy~=}2PXNYsY*Bko1?f-S(;+XPK-^VP0NZOv$`eeFMg`IG#b zL8Ug_mKRP@)o0GKUbf!pBPy=XQ=~NLN1Y~<`Mei~5s;msdz3LbIMPC;9_@Jw3-aIz z+KNCPeG#q^=S)=sJXsYUMz(CkKIeA!<2g>tx-oub>0d|JYG`QGYtR_|@IURuYj`T{ zo4IInxpiOFL@zd9r?*4@4SA2YRIEIS!GBtYwGeX&w%Ck?O@n2T!P*RO z_#Yp72`s%v_*zQeR$dH7Ku4tNrL>rVy3A@>yR^C>sJ_lu&57@`VjSCGBJZQV2_3>_ zceBqDPB>+ZHcp8#<0_DM%9CO4Iy)n&qlIOdZOW#XO!Z zIFU~!t^YS>^LUorqzXUe*+-v>$FU|Lo~MWZojL)gaC*DzAMLj~1HBw#ZI)~0W&~7hSbM5hX*@&J@5Z(O zxC?#-UD=NARpxX%oW}QV2h^SQ3>5dR|G;}8j4!=$Fs4vqC8Qk^Bk{V7At>5YHA8lWllGbJ?&{)y;4 zdknGvBxP9S883xCc&UjqY}Gv-z8=T;b` z)eWhk47pH9b*Ar_0eq7vjTzn-KeC40W~rQ7+Nw}GKCMLoD-cAkmoXK zS>H#SLd?Q`U~#Ymon{WFZT?Vm^SoRt`EIj^|8+gbM#~v6eYz%grQ0V_(o;k%_NI0%QdM(mtm|yao_YEg{a7mN1`lXyO;d9l z5^HbaN=Mof1)i{XwyXX)+P`VPX9^7FH>69FlhX&#^s+eAPkDX!MH=S!DH-Gz+dMa; z*>ZlXnida!InEpVCLa?U_A+%<;`S}I7)SYu+NYZG-5K`pw=o;o0?k3_RFSlxVhSXh zFSIYuT~}-W(y*Sy$uB{7s=N(dC{9T6nbUuehd(XFa`NVb-jfA;hY)q^d5p$Sg<-jA zg(0rTA!=fVKU^7un(LU?qCdU8N?{<4E!3T*nIHfe-Q2kefR&FLo)e&%^c9~r&lZlg zq62-#r?|3;LQSd`+PQXRz`S2BHnckQ`sxLr+7M>=W4Gs!{C*mL?8yXf9*STzsTh=^H0$2+pK$V*4ZDuGx7V>Vwi;(MIg*Zw`-2 zp(0w~_36{-Sp)Y-85aof{A(nK?wLUd@jO@_?Qd+{)M6DI4En%Tyd90aSG5rB%2q z$>2^(YHZRa=%bs1*3R&M8~j){LaJ+)5&4otU5s3b+PGT3%(Q~ zlidE6r316!J0jvmzD;aHOP$5!VKuhvt?QN-1RJHkWFJF6)FW0Qpu7f)rUPK$7F~JFY?#;KRO5OI&GY@?= zK2i2;i$4or%1AQ0%vLOvKs!fP0dsWGcRnBSQ^nW$#!oXD`Tr`K*jcMS^V)g zJLHk(`Y4pznlxQx-%Pc1;BV((Bgb>YY14GhwG7!8VyY*TukwqhI%tG8PLFuoPelEu zwi?>3*4@Q=*>otIYs(1kCltH|?F-VGlnjtHaGFw##p%UYkT8flKeE3_S2a~ML~Fv) zt=^k7aGlDKfmLYxx{FycG~!G^V$t$p{Y_ zvl)IFzIE+Z2pf^cxa^$r=ZJ+7l|2KA^b7gDZ6U$rc5IB)YpDf|M;MeEYedPgspWcu zf)CzxP5Ro7_}Z1TGohLjw?H&zw@b-`^4RqB1ne4TO``2W&`_pk)(SFYh#FQokKLsi zFe)?RIS?g^>}uHKHg*Rbo`Pm}kITy1EmcS{hLV+|c=jrIciP-#%DD{sWA#fa6HL@D zYgu(y_xhtt1&ieHxgORlWpVs5>8);vOAP`Y=BK1koww)Tkv)z&OA{YI$+~pDBI?v+ zAB#HYu0)~E;*ugW3(@dUr%CwZMi{-9PdfR0_R>3zZZV4c8Pmj%>fKPT@Wdu&~8w zl5L#d-6oUazgw>RlG^IK8+U_upV&`0C^g=EaYA65E(U?}Gu0uy zztysF=m=jDgNidh1AfXsnXtY(>d|nd)1;j; zz?Xv$tQ?i^7?4`o5&P=hmh=g5%T#MmmrV^6V1P?-fiih3{*IC53Mu(}GiI6p(dDn{*p*rMBiI9LYw`WCb+S68#n?w~094>-lCm>JFT>Uw_)D3j4DYO!+`y#0 zCv*+WDm#HvpAUDk88j%*>=s0U*Z?h>ln9++myZ&ku*vlgo*2Ds5DU3`hUC^1@u6o5DIws5iURKz{G_&MYvu z!D{al1)dKhsyTAvcFlcVEiAbX2M1MkJ^Y$dXzlAfNSg&lEKhDZ*W)?ihGz5)hA z0l=M{p%P<9z@IB|_bjGk6x`3bZbT{^yboJiRQ`Q&UF1U_^CbSg+~{5-EM2Av{gF&> zlb0Wd2PpSidQJvPf9x}+=d0(Tjb{cXrs1s@8es;n2D(-6z2Yly8QZ<$WLwcy{jGIL zzjCc~{3lMJQMz%bNURO9rAsHqRSO*HWT163qxdd&M&FC0yWSi;xbT!4e|YQ5pl7B;R-Z`ud(c zOM9p@EsIeNH?2@?E@g~t3F19cDog~ogSaVgP>@_`Jq2z7%d^dyT8-#8R~$GIta|4T z+ba&KqNIC*OSeuYWqVUtV9Z>-Wm6rE%!Q$Pt6)@C0|3HDa%QZuCs0VuKy# zN@yTFLA83D!OrCAe z<#obw=(`Den+YMub3Yry%$&I>4pXsS4X?o@5CTrcea-V~&FZ81wOs{LXubX3ngpBewL3O$W4JjuS8m38PS~?;ukKt>8|#7A2b2D?Rs|psOaajtcx#j(s0ptBK%`>`<)v><8i+zTDLM$4gp_u zhnVz!D{8*{i#Dti7bT_Wp{-LWCY`Z0T{MiC&20V`9n7H}I ztMwIOpXnGT7_4bCkH6-1qOs5sNXN3c$wNA!Y8T=uDu`h zUml&`rXNVUhM4Pp2cyTBXeTH=76?CT;?*Mf>)T)7ZwEnHkr6qom_`SEzQlA30)ctD z#%2SmT!Rz2637njSW^$~mIz!s2ughu?E| zU9D*cnj^YcndOPPv9q%_5D(rrsxsrB?Jri2JH$-3@NncoK_eVR(z?PECnTqLK8v8_ zzpN%)WSnO$WGsT!VHu(4)7G;#?&jw)=~#-gtqZ2Nd}pC@8~WAvO$Ga#if|^%er>6T z8w&uQU$a#h@pmBDuyjOaF7Nif0dPAfu3mcd$H=#>I~k8%aSctuc{KfN!jHQajXU{k zq5b?lYX*H|h_2wS^QiUzGznToaeqL;wL7<)7EJ0*jU|M%tMtR@r~WRepkLd}OPM6{ zW#OfMy(d{td6BKig$IBqqMtYSL*H)Nl|wXb5Wn0+J8PzAU(`6D(=I>f_Q&Bj{Pxkq zPg$o-(5b0>xkY1Nj23LSFg2TxeT=nQJy3ih9!4-I>V4`Lr5lkjOkQ40mWz#U`Og*L z9tXv(a3FOK8p&~Uck@RE=B!zr&P?C*`(k6PrjXO$HppA@zkbdoqew`wpwfR=iZ$i_ zzdQi1+e-^*VS!la*WK^gHA}v@8)oZX+WtT=5fnh)LX!#9xe_dsqHaIA zu~o`DryIF)NopVl2TAIuFF=>Ysh7DQ_{Q;_gJ!#q#qipw0$_DeMekPp>e@;AJrP$|su)-zNL?eC{1w z`_nn;p)9%cdwFL`ZPtx%f1if4#~Hkn*v;!W3;4@4eRa_`wfbrAA|x$BfcN*l=jYiGiQ+(bNQNJ(I2lj z9nw-BX8tMCp0Of&CD+~4M@AL&`%!(}MTVM~>MxyIHpUNJN1owMBfeD5MJ5>$Dz2g< z$cWqvAE6Fo+XOpH;q0y5?vWKX(WMg(-r4H7aoTp~%9M9qEMnP`K_WGjr_LRMrdToD zN2}a>2ai*h@6oGzXOe>0oR5uIC+}$~@Wr)*w^4s|E8IZuJX1L%$G7Qip=N@oZ=3Ps zut^&Aa|nCwI|T`0peI*8nB>b*L<8t-s?v8tp&;v%V`7h5(#Q`z5`>axg1*1}SSyoV&T!#66OHU#j60#KAoc%SD{oUaF zDz>Q;pPgq<>wYcu=dDzcA=mOX@@XhIZ?{CQt%i(f>i0=VCd^2e?zo zA__CpFs|N8$Ideuu`-w*djMhb*KXvlsGg%^y%P|gCQSC>BIl387Gn4;(|}8m+)PIl z!s}e8uW|z~L`>J_%WON(SP4g3ipB4G(>_<(kBK_Hg4<_i2XqlAlP6kYH6KofB9R~+ z2$YHJ^gr>_oo5bAH77E>VA&^k?rfATGFJgcs>kF|HQX>zngRNm{m8M@7c$ zezf508IN9A6=CKw*GKMM!G|g_L0KK}MXF+N-UlT&%VYhCpmRR$)RuqhP6b~;=X7~bnJfL@>P}bb~l<+;| zT#{QUu;GN_*ga|$P0__r1x8#)cejiF_%UqSUN=N;jJJHZxHLo+{jotI`%pO|=F=49 zKAS3GKTZlhK=0o9I*#v^2=*p=*p}}`BoBW^l>Y2pE=diF@GzOUn8FG!3=ysSSXV{K zaM6IWZpJj?#dNo{(EmjLZtLXH%x}*KDFQMTE17h6PtZ=)jN-#O_3)--&)#8_$M&6ls0z1M!t79^5u-S`g& z-J_*>W^n_Wjm9kY0s$0b8d0RrV*#-=@Ru7H&kY{JwbdfN-6XtN;V-yt8x#cyU}5)_ zomwA+3X`x-ci5q`{I_}|#j*n8kZSyFBcW`4Xu;p2Zk(bylA4dvi4^|6Mo+a-E!y%qS>{LL$K?V~sqHmZ#>-je z-5sZ=_h-xn+hLZ~=q6hRz@}2LU%tLb!+n43 ze&+4k_y$;7!z_G3PW;91<;|^n=3Z>izh9!oZjFo!ps=XiczQD27yTF1Oq_f^>n+4To zLLcNWdVaAW#SQV!UxM;+g>eM8ihlJzxXNj8k99AQm|vQGoIh11L%t7hY)MX}H)ckg ziYARfOl4l@y#DdAaZx&+X`jC97?psu7VVt2$+{pxK369t6^s?p;#0qbcgu81Nv zQj8*r{Ig8>zw|ZvfDmOzn%wZUO9qOiUs5*kS7XmQd6}4Q`K*>%uM#2zt^JJpoze^Y zw~C7KC$ZI@%8f4>qc&wbR#$oPyjZftR%-Kvlu2H(2PWDh)n#`?v^Ze4QBx_u6d^8A zv$#;0-K3Om@uqIFb3wws*`IG@aD8thyf|*yaNvDu!f$AaU%tPmo`=9XhmdoEoNwu5 z@8Moff>~gGe|?YMF%fJiA5=RxQmGck4P$N9PGR@7x5g*J)19?yj+{C!QxC3P`qq43 zwNTPctNro8=F~y3-ZJ-tb9HT(C};_2JA`})-Ww68h6Gp|3` zmm{J-CI%bgRNH>;oVUg`^L9utKr>wrzj*w_(+g*s`WwX$^9QHu2`w6L?mCmrbax&l z*K+<}VB2>8C zPVC`MM(sj7Pf>)Yd0PwRwO)yz*PNztNINns)uP9q>+`S z>3b(mw>RPf;-O`(6zv6@$iExa2736(PfT!`Yx{|_l~s!e=tl@RcdwU5>q4>SM|~P& zxiph3Ka;n77V5)0`mUM16u`lcoD%gg>7yk%G+Dn|w7?Iv?Jz7!G`rljG%055Il-!TasJNUi4=D_oZf~j^+JdE_jCXb|EQT9YT<1-!j8V|oyK^6 z(rWWOvocA!aGiUWv~QYgEl5~}0%m+;K+m-QaOPAPf4VhabElfMPIc>!vQ6+xr%#?5 zAu=5ZzxsQ2w&e5clLY?qOA@Rw^;moe`R-WchLkI%mA#4>ai*02&4eRs({?F2p{2aa zhF6#%L)hi8eKYgTioaE0=S_X{&34YT7n+)OJU&d-{R@TDO#h7bk|aEN56ffNmd*vo z`+ncCw;)z>oU8Rdz(vNVY0JUc57e`NL)~8S<=U79SR3IxxmM$DL>c<>*E}_(uZ?TP zSM8cGIpg;gXYZ!N*KA}j&tny;=aDar=>%k%Me+NId%C(hN&m3M2TT;r@h++U!y)8{ zF~mr6HEK1Z=yYcyl;q1Vi$v;sS4Ghn^Joo-rC!Y z=U(V~H?GwSt@NDp(Q@mGg@`h}a>-1lAZ)^Jb%{e+=`$$EK4;UFD8rW`HCcR)N8MsB z`b?|GQ6PPs^>b>p5h34@Wi)`OQS9aGE&gSlHT00}s-x3)NLKiFVY#cffBqaJMgXqg zEf-70GGe)+Tq$t@Ondb`A;$jD$Fb{SIbf#MQT{V)eAG@OGvz$JM&{u;_XaQFuPw;F zas`|$(H}K&nuY5!-Bv8J`zeAcI8l54s2MX#3QCS-jg4s5u=8O^pW>xmG>h;mFb!~sX2F~M-=ZYki zG(mJpk}eTt5gFvV(kFVkewRocSFl--B0!riqZm5+xoy_jm0HT$-Rsa771CU}<&}sv*N+wM?L?2LBqNPv)m|*9eBSd0~S^Z9OK7MdK9f5{nYquJz{TofT=hy|6xU$9ys+dX!R^?CM zHfrsP*aHakz2p5Mot8b;Z-6%RzV+P_-M8Cyz2o22Z}u+vJ6$Lwt%aUMqUJiDE-J>+ z;+<+n+VrHiw2_6>FZ{zXny0B5mrRrN8HWjIPv45-7IV8pdxJK~q|>sDg2<=s@T^c{ zowa|-QV+L3v??Js+H#I$KC_oFMWOwELYLdtu9joyo{WhT%_+Ar4g2DIXuorPP^Lzilv7W}zYwr^u z`Jqy7ebVhD82JfJfOF2xJb@ipt+f&y;}45Z2XLXQ<{ zZpR{20gM}=@+=Jn9oQM;8NSft|4i}NM-WyWKgh3|GFfz*4G#G&uT=zKZNbynTIG1aAXTIZF_+O&Nab{ep*-2D`r@)B5{Y0p>KTH4 zUOI-kC8NRJBZ)1Ox~{o&dbC8TTk^vM@>6i0zHSQ7(+@QhrLfv90{1@b5PyCmQ#sMM z>2TAaP+IKD(OfNbQs8vDN57*q+Bh*Qz472uQE2g|{pw>6i@eW3t3Lg)uH6mhpc~uq zX7=wVm^E*BE!r5I%)*uUU)3F|og|_M1{-@ESSdtM6W7)62v13hGM}w;Xm>xUK*o?t z9ZdYRe^7Wk1#FpeXfzm@D43gGq*fsOm9)ordaf3s*>55IY5cArRm5)VoM-N}(A9g38|@IGe>iU5 z8QhQ;?@2A<2mM#OtB6=e*RgcBP9LwE8NSPsHqPHd8@12rWVtF%F0A+>Aac~-skaIf zSz`~RMuQ9E(_1&Hoi9KkC$}{h>L;IUob0`Jryjfj4(|{agIs#ksV{=>7vq21+vNXo zoTa`v@p97heW`Lwvn7R%R&~hC#;ISb=(WzR zTW_(|B(;z?^TwG*+=~~If?u!_KILqpY4AWLpYmYd>NUWpYZv~(n?{$_kli*zTv<@W zbInNp>Nd+h!qdoRnlc(F>g}xt(x*_)H{QrO^D+Po+$>xRV`qSe&#Rp^osQO9I(YFT zvZ>rN-YZR6J^8y}$kuznHI@?}pE`c9-#23-9DtX6U8rflOXHNG+EE-=s?b8-mx%it zupen7^>4XPI_^BE_?@PSQc zUmLmfNN2nfsGIC!_I8OD`FljB1&3zUSKIMu#vH5r&I0wq<=JR#s=_0|5Nqi`7c!MP z{M2qe(b+42e6^@{`M5{OZSzE{c>e%4bd{nyJNYE$Ds*{0oS`zBbQQLWyHuN zHGK%|kBxI*zaS`B(AC?0@1DLP0kpk2tG$P-B*R-UpwUK^4C9!H3PfYTvO4R~J zxHJK+7W~?FnrDTEM6``>;170PJ?9#h@Qk!b1CbtWMA=(+dDSpaW8?dVX?Qv%_Qa5R z2!THj6^u6VIHPh3Jsq^m4P+*Y6I(1l*K@X;A*dFt`{W*@;?NJ)mFJGGb1W+-zQjn) zi6&tleFH@P+$YhvvS1*q>x&MIe<{9?Ag|t!o4>R7|BLrY`7kfXXJY;DnfT))_^W_H z?m-2gkvA*FdLXTOiRYFfJS$=v+(<++JT;>62-ADk$q@g$ah}m%{>;b`mg)eq(RM9R z2jF-*aR0_(mK}2`?wE@U-(BD+lKDDry}`&<*-IdBac+hcr>5jwt9PMStmx1Vt?beZ zozYePZ>VS1p3{0k>aM?QpZtwFDq<^Ml!|<~DWKZq9eH&j^))2p#RA7GjQ=Lh2QCQw zKq7mv6m&ZGxf*qqQ{SVSh*aGRP;&?7yjpLt=xz%i1x)+(+rEpOBJPsCHOOh!TD-A| zF?=nkQV4?BpCr-WoQ3`$>fS0UuBhu4Bnbf$f(F+lKyY_=2oT&U913?0!4f>UI{^wW z+#P}k3J6j-g$Aj@30g?H^8NST?tbkt{?YgDamIlM9;m}%?=|O|YtFc#H3+?B)5#qE zkn@Ni5<~_%nhpyl?RXRY?%Q!GRtO5V|Ks6Nqg@9gq7{#bD|7B$J1Do(-d{8}RGf=n zx2;O=y}ZOat)u7ni^Rc<1;_(2ZcW+Zck$FBMp3nSr&RnxnOd5*Tn0=+d@sW3Kq$B;OaV217rDF^=?u4WxkPT~&wSqpj1`j8ci_a7-jNlS)q4KF{i+FzCCejG0|U)17gL7q6+a z;%oloKNT$vRL(a=GCmYCFwYh$SxP4r>IzakAe%t~uVKR2@=}GAC`2TEg*Fjep$Fx< z-ys|TErD>%KV!6(qy_R4n6Wl7oH!7(3%w zSV_^hr7R9st#}A7r%||mG6zctCSFA(8wHkq(26JglZk@3h`aLKkMcbxLw&6zazX6A zONP#4RuTzoB5@*B?@|y(4<7b$ZmE-(FDe&7}SBEN# zM9~@$QmrVT+74E+&6#x96*`|T>un{~{ent^M!Bqv^ExQ3*;aU0*tdW3tCh@LXq*GC zt*owV4QQ2|YL`l=UIEgFIds6#jL#}nRz~nwb`qQA5j?3WPso(2FdKESLltsX@JeR{ zW4ttNUyMn3>SkW3$>%)fzE#7h_e%~a9e-3Y@^j!txqDbK4t{P?KlLOW*p7*qe4M1_ z&Bm@H=6%&uH30>$t_O#OkV@3VWn}nP9C?`P@sDZU9XMDV4Y>Zo%)OLcDii-PU;g-g zXnJJxNB(lha`6{biXXgVZ*Cf_c)HWMYQLt}ggi@FuGm%!n(UIyNb{yu-pgavDnaqT zoYkS?-*-bMf(KtvX9(1omT+8{-l;7#h{U>#&G(ztj)DRKhIT9N@Hkyn__mX?=~$!w z4*4)1t%`Q&AWu1kqdj^Qi%!|}7|#V?V-sBt1X{!~Y7tK>M(c5L>?>Q|;KX6|RkD6) z#&M~BDxP%8ZZ6KqJ=HAfk}B=vcZX8bGADPZwCcA?ZwUw(sMcX}no`oB12Ofa#JSfP z6^>76g(VA&yG={74E;?*Bka67!UA)){?Nfbwa(LcLc7Idd?a7TfW(%)X}R7>tpMY` zr!eFfO%LaGW$h&k(T zddpCg7kO7zm{`IDO)cJY`=n^;u2aG1aQ!8|#HeL9^?URb#TzF+tn;fhMs@Vh zlPq&`GGnV=yWyrG!E5?Mjw?N7PThWr@kYKN2%wkdmkaIT29yRW?R*jX7=&n_iOmy> zsLdR^{(O4DCh^U6)P6DybWP#Yolyx(Uqo^PJS`lR1-eyP>MJQhMQh8d?K_1<9(sDH zlhY+dDbq&Bomdvlb5W4dvbKcMR7HPswo;3`Y$Jti{tMX~pK#9<=TSc64NBPS0qh)K zi$$cKE)IJOzY(cKCd2FIRmC})UdGDbf4F!4Jvh(Ed~i(Fv@OolO1f*!-n8T9+VXi9?<}w0o+{O%i3s^EV4BR2vFI>^A&Bl*&>)!&_W= z@udNkTQB6(`5Ki=0&uJ{v87Cjbe_*evcgQg3^iGMG?GD$d{{3Mw6(jno7t?$%)CYzVH#3)IMbVQsL5@n`EPN#(PdbVn0X9l(+isI7IVA( zu9>p|UtE=Ew5Z49pbTXbxq^ZlPj_Q;gXt-X!N7yxKsLbv%DQW-mD|HJiqqTDiOx=o zzG=^`JD@+1)w1b|qytcVLP<~;bzBP4OjUVCwV@&v@RKr+KW;k4`KI6*HkyUorE|;r zwSquw(O6M7CENn)_@O*kY_8n-v9NTD4_U$5BIv7#59fi4-0jP}W$36mFL*F_ zoZPQ*Pt^;UsFFykKi-H{VCC#sN>K0MW~yq#8?t+5N}wQc`_m0Kryw-v*R-k}C?*Pd z9;-y#AN3}? z^1s8#e288_B`VIu;YD+_-I#L3@P0gVb5D{(&Wo>A!A2lLV>^!9zi2ngA4-aXXx8VW z?HFs$o;A6G-*hTfdq!Ox)jH2xIdo(Q+`8CZQL+jcTw_%%eZl#5HRq}^j^eaDJyGs6 z+2TDBoAnwQJPWAch!Dkk6RbbNJUhl#?Eb4qQeI>$%k+253M@MudbRwJTna}E4txga zacIwWt9MCe;hy~L=q??seAto7bOfp7XGfh&_2lZf+{uaqpun@Im?c=3KK%RHIG%M3 zVOsrh@v?LR?!f94OybQf8eFUbfGF~w-nEv9G2Xz2uRF#Gtf5(-w4UiHbL*0;Y;JWc zr)?O_XV)b5^NT%w^RYrfl3zQmXHR$51pj;Bhcha!^^qlwm|A6xx*`=wV`x4PAeeUB!8RbG9C*1b64qrWNje6P)98N9{s zR;Vm*^BdQ=SoFXg8p$<1`9+OBVHEdVnfY#M^Vl^-uS+V$$gR%He zJ>W(BK=<5fsv}?X9NCcx+8wpmVaI0<%f$oEs;{QY_dxgDlzU;|NaZk z)B+SVC}wt`kH(c86#L*pi7n&p583`gcUvo33ti5AcNIV`gP3FS7jR1uXvzofn#o!) z7tie)VvzD+Tp9ei$((vQJkizjxrC850nTPa{(FkXnQJMhdD?QpC89*3%)hzZ2DdY= zx=2f5YnByfEj_;~|H|k6{yB@fpObHxRaw~qM=Sj>j7GN8v2DRx_DCntdS!Mgbg&h7 zLtsHp_NXZkIDb(iKC)RVUNS97uZRpM9==HDhQSe0f6=r+MM#^X_lOiqq$bne_WNGq zuR#>voAQk>>$72E&JJd`@e-MY@F_Z;5^_P9Wd7#q;;}5)cIDKheO66;v3vN3?aNa)YQ>EMIO!aGRet+)vr<(1+!tA8bk$)-F>Kua z^WN=|3d25WSD5!`g6mVP@cSox4~)O%!ZBM%_s-kfV5l^RI%`qOxD}NzH%(aMmQyw+ z(rW2%8edUr;J}uHvuA6`MvwSDJ~-t9eN7+Jt9p9G7lhjXqCH~iY=+kqqk@)sj>@3f%$dNOO+o&!7DCo0Ol7B>U%` z1#o8M)ZPPE=eeJ4te=m1=)l8SL_96UHD9E*+e4k`IIXh}pgz|Y<~PCkw$l1Qku$q2 zp6oOC(ZJsPsS||f4i9j& zm&z!swNPM&E$%?#@?(qtHHFMfZCYo?l?W}d&X_XaAF8Q~*0}OjDWHQqDnEJkcCaR} z<$Uy_&4zi`euP`i!~iML)2iDa=yLx#*`%iMb*jtVFJ;`QhyY9J=hLMi?_1{byza%T z`yR<;NVu{Tsk0ZReO27AQKd4}NFimfWUUObk?Ru>+tgh!eT->U(4W=Ou`^dlV;2oa z%%Kl0{z#;;>K74PSD=vcf~fwe_9XB?Gu5|Wa|E;L(^4XC#pyK#QnIN!%zS97IcybB zg^LVt%?`g<&$<8ZkUY~Ck_)7%@YwEcy%{>k!YF7+a^lkQFPdjhk?N~})Wjj@ zqf6J8vzGE2O@RO2<`I}>gfji8wdeboL$%!S&%yLxm8tsCjF;DP?i%+WqF>s9eiQvG z6#nZR_XzjhtmLVFZ3WM=zj{kNNs#NDGB4sPY7?08vU;XjQq|^8bRAKAdt8#7uGQQ_ zgHr?-D8hD#=q{7Nwx-J`R~DQ0xb2l|sf;tOxDqEfTv*%ve%lnr8r018g+JgrS1a$~2)44Jd)2)mO~K=she{UI@HhjnBp}kWIbR zR9wo(ZK_-h!;|yMVWxDvnIarz)Nb_kzjwTVfr?I$)q$>~zMr!AX*Okv>uxNg?X6Xt zw!)4PB+LcxT+Y|H7~<_x;Pa>=^p=@}55U_74GuS`(K5EeoxGe3vm<00Q(ESC%-t2r z!$sHyd;G?cm;Ur+!w2ntM+xtuh9|$O8R;+g}!`%)JDDY(NLv~uODx%pK){-;P4$SIgI3_wF?8r z1@R6z(;H#cGxSOC0>=!LYuT&r1xRWb3CDzth*@-kL3wensmBMUuL1aBsJIH6mOP^- z_$-`7#YxotGvh}u;H$JIM@uS1TPe@`6BXM}*t5UAeoifG9Sm(YJA0J6Alwn5Wz-o~ zr1`qwr(02(has{JUs5!TsZ-Ijp(6y`OLBTpLJi{P=NkBQVH5$uN=6$A?4tp zJ`n_2bWmi2IRTv(78<@k3s8+GZB0mU-ysXE1I&nRXIP00m1rTcZafEQ=19j%W8flw zho@?ws!|!E$R}Hjf6+Ah@zhe)e`$4<_HyztX%84;r962oV5O9{pzU=-wTG9fjn@ywU6WpQz8{06v6a|OLd-Y<7|*1P8Q1)4Y74~V zC%c3u?6=OvWaHj#AQoBTC3M|?=HWGlhKjBg^K9>d7T+J~;kGvvIIEhJFb6Nz32;YDd^NpJJ{n%OT5N+0f8JD4^v0k)}S) zc1clJlb9#K1&_NxeuD2i4d%GdddG6?HpfA~O#}Ingx)UmwmPk=_Jo*Q-=>EcHQR6m zMSh-XrG18WM60FGGeeC^Rx{}hsv)O2B_KivF@Ur7I(EF?Fs0h_L9%TEbI#FR(%n@t2 z_~g#kz7D1d=s4a_{EJ4w>1o;gy?NQ|1In7&A;Sq7xl?Bxd$J|b_`^V1Bv2{Xv-s)9 zR##y8wQ?&oc)<0zAk%#62|WKwOXhbD0UTdCjHteo*Q!or@U7=afJGnlFItq_F(WD@ z$f7lX>%-D#XS(dTo`oGwb|{^?X&GQXf;L^KEnVADg8E^>;>=!&PY(5liKsV?SjH-| zl`z;9ycz4;C3fR@$mwSExnjv~q7$@ITHrMb=s7kqO~Ckr88@(Hpeni4bGE+-hj}{8 zRAA0}<=N7GFY}f#Jb|47g)-Ld=GUWIZ2SY})VfN%=SL21t=1?u$cwNGD0`v%)t<+( z{@wYe-v?=?TzM<$Q(RE?vYJ|gCWpww2NYJT^1}^<^H$uaLdOn@v^S8F1@%t9kguOy z*MA}l?wqTiu4A9ou8Aqcb#NUMGfPX)8YC`KGxc5!s!c%V& zrZcC2l_T}uNPOGsL75IhTuse>0i!_IUE5KZKdAY-ObD~oG^v-mLbE@49Q$C|Tx2b1 zRi5{fReEO6-YL$4cq?M^8nYw22eIT@LXaGP`3_5TCW`5|f--Z+KMCJ|ye!_lS-QCL z*MB<_eGz{6sig?_OTv{xd{JV&M}i__&8A}`c|?h6L=&P;yey>nw%b4%Rq*#N*!b;(AZC69e2GJyPW1%MAJ*hzc@K(j4#q-rQmF zizusrt}obNU2t}d{n?sT4}5H5ra35vE#E{%iRTp|rUo!bt44{B;?yy_H($*O4eJE>8*Aq* z){0#_;tj+tm0=5Ft6628J%3AtPSi{eGuR}T91n??c0RfQjgx&!h+KUB{M7R{=UJbm z5|XYgBPFBu0j}xu76ysU_Pyo;c86cG1;hF}wt!m6QAcrs$?YQku|gO)Q6h|ZZ1R!r z;2w|Js^qSIXjQ5iBZKmIPM@&x$onz!JT^uK5ZkiTd}*KR5eH=j@#Kcwm= zJ1i@hkVW@{{FCRh)n3iyu_fdtB-_vOjCXmd%(0$q_6~U>b^`Xhui}PUQNU&9!ZVmX zW`Krb-m(0h37vX|WwTrRVHt&ItQAdf{0%!4hg~q@eq?i@VG`$aeOyC_B;Y3Svu0r5 zI;FG3N-#_vqZv@dajn0wdzJ9i6B89w7i5h59?Nfzv|JMCQd-y*0JQs=kna6rHS!i~ zDOBVqyDnN-*#9)LO#9wPf6Ipz|8!HGuVAd2mgq+)Z~0thPF`GdzV^9#ZoF-z{qWJ@ z2-)LJP%Uo&MNgrXKcCQtO^2Qorr{lIqY;twgPJ(eXUCe~6u3{`G8~cmB-KpUDR8tq ztSr0mpv;*L}c7DoxBnUQR3;?)}Ea_B%s#w<=UU6hL4|fjHJCy#F zMvsiGhBI(^uzWYakA&%k7OI-E2p5^bHRsx?CTVlMevV!{-E!Yg?Kp1T5 zbK`IP$Xme8_f1IT0?}G0kr51nw8}==LC)wJ)uZ6Kzi!u?ksrU^-HFqse#z@ zpa#^h#V+;VDBNm9h7s1QK9`c#7$j^w*OqqEzEp2uU2T;T1*ue7cm+!@O+%P?GDldsl^#y_Y2+@sxN!NAM$fk&Lqq}5P%(!>gz(sk&7 z1k!l|%GFiL(p3J*5s*}Owa^=MAU>nj9ysoKB-kV*s7R_1dh5SmrAw|L;ow@zJWCp} z_+b81@Z(RqC1vA!8J-Rm=re=8j*RMh9Gqn=`Z(Rho#XOKuXgKIbM9bNG=#r=G9~UY z-IA+DrI&Hn5N^D_fM1Xa%5-4Nz=lu2r3*nOyyK!-#M02h;p51y&aQ??_RVquD6$T` z)FFT7OY=Jo&ZH5?v_cv)VFR{tFnMo&SnJ3FeeLiiM?1UE)2bbinKS%)aRl>S>xYGoQpWu=zp5#!yp;>eh1NUDtvsO)ixwFZ-Z5 z>UaR_GWRwg#gXP$W>hHajd8kXOiqsvBRmGE$cFNAiP`@}{bFuRJ;n&qH(Zg>Y9&S; zhB%lPu(uNed<*Mwvu|K*^{NA$DML^=-+` zOmUZ;ohCoZDRzYc0w9DbUcyLLNN3HgsovO_Kr`z`@OWPs(tPyWD%Xj85vz;~d68 zOI1NRX>l_ncbVReq~t{1&sGt79Ll@TBegkLung8WYlM6Vtu^oJuwtX{N1;xO;l~5b<1~?gU;^s+sQ0e~Xlr{r-el3&VYmK8dsP8SB2*v1GgzSMT&x0c$i9;_(MAhx%$dxBCBSxKaV0WlIDp z3`$R)pljeOJ->g?ePe51Dcagl>Q$sUH|rg}MDB4pFtw^VqCM1CvL943LHH_9(CBpu zlSFv(-1+SRP(3{`P`P`ne*xnsbihAel+M93t|7LkH!^r5-rOzF)a^(x)`p<}s2Sfn zvf&@1Ji4+w<+*Bp_+_Ie!vtO7Kb`av&Yo9MC?W?&i>Js@u~)RKC8yT z3BfGB3)8n;RW;$T8PG#0>{m|8)Umts;!s|BVc_S!K;?6o(ZZuyC3ffy`Yqnr{$HZt(Rw-k}>C^@B- zz{yK2T;gy!y!DRqv`c~`w0IB>u1B|PoJ>#PL4Mw!vNb@bhH~}qGIAv3%#8og7_>SI zNq-UdhlRkd6sAz`btniRdaG5fVt>`_No+q=j5Uns(IS zXE0UfxNCTS*yvrtiP7iGmm(#tSB@RUvZVQ+-O<>U<*96g<$F=4Z}DSKtEF{b|If!O zjZOl#$bJA68paOup8m2~4)?Mp08WIP8->g>zEC7phYV?#=|(oLuz(X|x1H)>&Mz;S zl@T5*q=MNOxTJ(Lhs`KaY0wp|wmPKEIAAzNEjSW-Nsh}puC+6+a40EAkOdT~Ds9b3 zC_n($U%+Z^2?|YpTJ%a@0JJ#$lA$PY2~z;nRi(*#?20=`ceI{s$EFzF^e9^j1~(9B zbk4+XG;3~mg!~-(8dLse8Sp^lG!v6KaS-!U^eP!fm6Zm# zb!S5W?br^APtYi&J$g7Zxs#e_pFHpIHeJby@Q=F6KzsE-+?>bBP?xayhcKZ!a{p{q z!NRpPYU>zf?Nr-|5M8GXzlNqX^cz@sO5$Yjd~XhPc_5st3mF#qR$@3GM_V2N zXUYXZAP#<2M0*<60VO0eyDbt6D(Q8NI2^~mhOtIjqhtK!flV-ArLZyLGutDCV3~&h zHhgHVZZ|eR@LV_(&f}LI6zg_>>NVZnJGG)a8dxYqpBTs^VHYAD0(=DdB%tiM70{B} z9{q_0h~JpuPTk9)@{p}2KJ~_=LOvIWo& z@p9eo*J+w(W+;pXN@6Mx-+ew>H)3y76%T*Ldk#PNHLdvs=?VfS{_8tE5YRe7!l|6yj-8~c)y7aah z-}-fJPkB)~lZ5NrmAt?m{Cq#sJatRJOXV{ow~Wue*X&oRx=htVCe4M!V=RDnk8FYJ zgGbuzH!;0~(P#1mMALHDa{rGF5uNgT(yw^goZ0g0&f~d2;$=F$E0H^**xYWjw^v*A(ec#PCIr>uCifN{+S~33x20Q z(s~7nhndmMQpTFEsS`h-pg(n@F{%>Pk<0!^aVNhh_#X_^zb_%!uAq^tIolT>jDm=Q z2+PQ0)Cbypv||U^Su8nG(v^l)c>$>HaeD)?b}SIWkP3#DuvVZd&~(quKP*ABj9k}3 z8CvB>boY!6n>J0KAlWI4_NxG<^W9Eyp`a6nUmcNnX;x=sbe@P!1ckQ>|Eo|8@r9RO zB`=c`3NNbCO%1cTt7%3pdT>;bEh(l(%ic7Scx9d_Bh*rrZcnPqhysDoYRN4qXdNEB z+NfW7(793akvh-_^b_9nVDp}?!o4}R6=Lpc0S>h!XW_Qc8$a_-0M|UiLImE*`KKHbh=zF^^=K=ZQ7ap-EgAUlV4PDtR#aG>UKwQ90=cyi2;w>smruv1 zKIqH(i?-&^yem4nmwandii)P!KRjQRFd9ZyIs~S1mMf$h7JmJL5k)f~Pcm-hr0p2Y zr^XE!vKW4!>Pyl5LV?GT%p|hPYG#+ZUBfbit=+^_KSyh@K6Q;Pct1$lEk#{a*@PY} zkQI16N6hu?Rv!;@?a2%s!Re*?Z!-k_L*O_(xHEAVN?O8|vm0 z^H52ckKxt)DQhf8J|mM?(ml@TKIcNXhNqCr7MisYHjBTaABsC%x!%W*AJB7zz>y`uOqVFnGe^frDq_S^CajHd>i5V^I%8$XTfly;X;8Q(@x*83Qij##rZE4Y z_+2nUenJ4*TdrZlBmYA#0ih{Ae{>(&5i-aw2bBvaK&L{d#=G${R-7TFc=2WWjh&Q+ zVaTNbwbz2(3LL}{W~LpOvL?C7HlL$@?HA?$HTgMo1tTb?33rv$lP8Qk!B26M(l8;ooP;k6zalp$ORQJPtDB6g0UpHA)Y4<2Naf6PQDj;s z%Smdu_ZhPzL7h=eOkClh=04{!x;(h~`-|y|W|~vI2;XeZGB+aToyO!c^~zUnzB)?< z5@i9|?dmmSDskxKw0M@@VT#0LKSn)e6GTTw2~Zvo#w|F5qN;)8cNO&=TE6d$6~5RX zMs1y~lXGomJrXvmHM>p8_jYW(_do6yNJ>~8lUUdZW?u?QFoMi?cH_;`PW<4g+(ua) zG~|FO4VD6zRbajwG`*E2)mZP@JRTg+~Wpr)l6iIK{~Do03QyiOyU{KoZ$p zs?og~{`6c&D~wX3(qoKW9)+$GQQRqBf9OFz9{16BfW+uQmvF3*K!XdeTa%Fz7si(6 znW|}6g+p2qt@>RL*JNFD9eIsKICzA6F~Gz~{+CNnM$&tqCBLlUB}q4HUY_yacJr4- z5fb?rZ9+Zg2boecUQ_qon?T>sC+IE@C9xgYO_)KNcz@WVmz*aTG|}u^?onG0yYnwU z@1a3s+!SO#YYSWnqb>n3nY3c^7cGR2>~_W|Dd2Nkd?2bsToo@_@8sn@S6~c>s0B{s z$M)Tu?MDMSbThjA9i5n2Qq%JhuDdUpk~#9q0-w zeRK=L5>_R~CqVzN;ZPKoeIi9P93-2an<6k^h2~C_kFfJnQ43?*nEkaAG?$S^tFn5U z2H&oO){|K-%z%IFw)qqL?|56V=rX98v~en8)p`iY{-1bxJIi`yLoM{`RpaL331U(b zU~;eRXrt^(h#2TY{Y8VuoRn22>^*JLA9|D>P(z1p!^ojBXQh*}IoszR$2I(+Gba11 zqxMV6a~{chtJcepKL9nIF2y0+WX8`IcmPGR&9_mv%tOY-UGoB1esf5^IBTEy^Wv}) z`toUhW8sGp^$VTC@Sl@DwVGBG3UwP>&uU)NE3E8S#afnnq}Znb`FV5w$yPGS|KtpEQ1nRa{{^f6!D|ho=I1&?@{FPi;n?Ab zPcA$9%rPx!Zxy|W;z_inC$t6#{s_jmDNG+APpqiKmigAU0wGe|;!UQ(8VTzXbA7}> z_V?TuRx!WG`uqDa`qzF(p<)Z-1=)ogRseNArAHDLB#IeX`Y!^s+V9{sjbLtHP96~f z9G-n&AQ9^EHf&Jdk6z2S8HeZZgcRgKfZd%S6>Fn{?0C5;5BlV&4T>2!&5B1`LXm1;r0?fkZ~p~13F#EUoN<6It5(1El+Ga|y(!3Z6-4$&taI3jvxsAmCzrqEkOL>~2i*@+(ESEWyZN z-V+>7Ek|CjCwoVg)Lz6<6J1_mYUxa)-~}B0>#vgHgPM(a#JJ9|N}_#V;Ez0NI88h-4_9os{~M^H}*w2Y^Mo(^@AM^(#gV*44it@zTeHCjDo)W{MGu< zbN>%Z{?vlZQ`);nLw_F3H1AAYOvfqH=Ga3^Kvq0%Uy* zu{9K+1fCl5s)D~H?Z7^lYNprq?x^`VMz{vxTQS*cszaif=DhzMiw5z+{M&KNbAtY%WkEGkf{VcW zxvRQ}2H3V)l6=dG!x0Hdk{#4V9hC{h8OhmqlyCD2YL4vW>KlBx#&pB+Ikt*KxlXk5 zXx%}~c+T5X;9ecV33_HVw1=0!D9_7m#NUmZydQYVWgF><_g=8iikoS9IS+NeKIlR0a?dSBUuqhi;E-{P>a(f2*kH0@qmrMjiIfTlSo zm5y^^Rx2Yx(ZeFTL7O>H4qLH=NMtKywfg0s{mx%yc1F&sdS$EETt_3*kH^=nqo=n( z{BcoAc9)umEqxwups=SzUnyMJSt8bcCShc#&Mtk0@WbVk8gQ8k@dP;o5@nSko;rQR zW`BWnUjMDk?UnJo8vV0EP9FLZ5=1p9>w*J)crRg>l6gj2ir9mRYahq(mrcTzYhmZ`eAcLz3CT3cF>?lZ2UePAT(*k4K_ z=0eP1Bi`>*55|hPiLp?2JJo72HkHfxu|ST4m!;mSwJlNK)uNW-^-Mhlaj$z4y;XlT z@b8fgD=o)zac6lyf+b1a;-YmQY^ulEyoBZ3+n_)lbWHvyO1ZSUpHw1UXa_##OyFEj zdk)``zOLF&h&^K~VYh7V$@rP4WH=|1!e0UBsEnB zoy7p}#$2ASqWimE%*nSyCN^4aQ?FM%zxz-gM<4C)a4Hkqiv;#90#FV?ZQ3$!$)VFl zmvLw-vS4l+)ANS@;Zfl`?B;I>p_$=DKH6;@`9#73_oz zu*{SBujvD(UwB+=xXs@t26Z zG&-PU#dlNHq+EFBEq=T6I-iX6aR_6_JLZCr|0$gM$3Tpad9q|l03(Mrxb8)dzpnby zY7~V6gfrr8V#^^zCz-DRyi_E##EN%a@&etx?-)#P`9EuwXzA>1#=H}fr~lt2E;FR1 z;@ff*cpmhk$>&<@_16M7Il`6J300yIXQBIfHyM?}bm6|v-kua>#bM1silagXa=2xr zq29Q+*(XL^{qeNT?t>Tk<4gDG3P?xS{Nw1rtWQs6%QGM+{|nzVM{2b0Gu6DK2Sp^? za`^P+=Y{3@HtvR55lTw*n3I&T|dbe;5O` zp0jI^+E01jXr^9~^VLn*6f5bB*>M71zWadMecy!$RA42d{-)nwbO|0&%GVC<5WgsU z7qipZfl8}$bp`)MkolT@JP#CB$g{h1`?Lt!DTAD{X2p<=;;t7+sz>kjDv##W}8m?9s><_Va( zSX?VXX3%oZ*gUgHY6TI=s`K&bo$3n89WBOA}h|w6hW1 z+DnUt(8Jsl&Jt*zcx)fG)9|!gsS2<`v1DELxet&MbYE7y=U|_mMl}*AY|(oXd3b9@ z`n57-NO!;z4lM)VZY{_8n}?8!BN1tz`QgLO+UcTl`Or1i*J`7n3Ua{ z^CAYi6Rf_!kzPnsH8}5}Pz_2ECPNA;3JU<6)w`sSU}oREJQuBa{WO|TIC!bYW?WuD zrzC6ufhg%9^|516p?=&bR%{b@P6vbcm^Q88dxWR5vC@q^G>_>Eao zQg^)ai!biusN(g=KXb2OZAQFG=bz@}$VZ5$0zMVb_t6LXyMno6Gw9}xB$!v=9odwL zz7ZKdl2=&hQg1K@dSxU&aGJEA)aQLgg1WQFRrNH7o@mdhB85nOM2VYI@)b2V0*dYU z`AuH7%HAXmP`OItmF5*43!Bo{G#`^-FfXiDg1GW03_4VO&%H4 z?s)MSB}(Krbh~BWMi&i*oN2`Wq7ibxf_Cjbr}7SHzS6^Oav4Ek0g}NAg({aA&+uWb zVIBmd>BccpHmU*dn=wrcUR2P#8Sakeec2FW_zhyBGN-VYVC_7>>+2V5up3~}Po!@` zq{;m()fRK!gy`2{FKz?G>|yOmgc;5^r@UCW!~xH74}bYzv~Tk)9#^Ah=|BTZPb#27 zcfA>bR)L_D8%JJ7W`^HgD5DApGF!y?itFske9*h(5fHzO1~~m%F^fw0aB0Srr8&J` zHKSQ8yidYC>>L?fPG30-5`b6m78lVtrGxn(;j-n2@2ve3z}Z z9z*u}l}^=Coit^EQEGPg{A+oSW|z0UVFFNnm`rh?m$rU19_=+#&4-Jh4;iuoQFZd?`p?v0SDOFs zaf<)Nn^w7n=v5S<#wxfy3g{?H*MaohAGuskCRAgR9W9+dR1OJ*x)EGx%MuT_J)@0+ z*OV&mHg=HJ$f|sGE*R`PEE@}-F(&{I5ErPQ~tYaSF;41Ph~-@pQ-KRt8| z5~rFlSv#haDnVx%`7!MtEreY;{?Zf+iRQV(-gE;97+qYo;5u0dk$cFkD@~hQgr0|mZX$=H>KTt zGzh6v2;Bee(4_yRTf^6yd*YpG+uOu6=1%T3z@PI?0+H*W^c>>6B!`lo{9EW6MB%M( z&S{$@up}8F+#he?^WMBC_Jl%H)vqr6tQdPYDCT!rwJ$b1`?@M)Lc<{5qTyppm#Vk2 z79?$oWwPyzH~mTD&6?L-+N6}t@7JUJhmlN5)>ac9xHs6Pj32J$x(@Vm2j~UXBXC!I zG)&0ZyT4Z!Nx^Ws#~8@j;HQTQUuecy=TX=jh(6^d;3WrYzR@9N`X(&EWdeuB;aU8_ zjz-EkpUC@#>_S>QBrK%87`*hC)Mh?@4wb%|rqqb5JhW(`ETAC2hf?CF=IebTp1=5< zQo;;OV-d0;7blsiRK4rT9iWl$r_l#6>LGk?Htr!if)QZ*j;2PP?Q8z}bvzphp`b%E zlFxJ}-U^;yO1uOiL(Or#10!8dI^cmxAE9T_B`HB5Tn1n8)Cf^1pe=1LF0Bjk|op+z_^Wk&?SGin`??4==iP7bG)RD*&Hj zif%@yXng#w$1Lv~yd(L6ItpU(bQN|)qrvH4Gyt~u`fnYhhWOQrh+`?A>>to~qQz$g z?^mqU2I&YeO1>=HYVx)`B$126=TG2@d>h!xyYs=5ojh@MEjLY2om{7hH>n+1Gwn(p z_&6S{H(T)+Ei&K#mDp(TW5el%PyW-H zPobb#kK39mF>XIK-sj&Sm3{{I;!gY~hv5DJWYLmVrCOCs85{S&Vp9w{IoYeu*V$W! zkr1~_ZvOn!h7{{edE$fFLQ1fT6V2Dzo)^1WDfV-d2ilMdNp0m7@CZbTaktTN!nUoJ zQzbptW#s&`jqawa>dq@*mJKbbVfJlX>1~bV_t1S38b$6wityk++^ASwZKb*I*w%gr zwE9nE?|3Qb8+xecV~WlME#uSk2A2*?>MJJj6gU}w1&APUb26;l)&mAGLb!#@G!o7P z-4cK)^XI~~18Hq2w}Vw*%A(SDj^1vE6=!&0Uh*-vmrE9H+5SG7PKsRpfuu9;cm!CB z{hCR#xcC1Tb!QpW*8i=0+CnMC3Ppn!O0fotySo!4xVyVs3&kbHDG=NtxNGs^?gTCF z?)2vOKQiaOy))E~0(4?LO}s5Ss&v))9l<%gV}$k4PGETaiAuZ1m*IM3*5I}pC%dI3;s zrq8^gToe2h@_TxrJnf%x$3=U)jeT<#z+n&3KO$=|=HnOHk1QX`g@;KH^u8Pspy``J zot7a*0HhUkvntPZfVAy-RN;DX(6*Kk(L3ZE)@0^<)BcX(V)|aYQxd*c4eh^6bc^^N zKlwdNmrL{1H?0g>pNT#Gh7sC^QElhYHFdg%nBGx%~9pwj4}vH4rg8b9Eu*_^gO|R4m$vWfHo9qJ4*{txm6&$P3k6 zYqO^Mzf?mQ3IgjBaLHm({P8~kJ;YTVo`fh10&O!lP-{PG_Bs{NW}Zn6Xv3TecHS=; zF@^n8QsB7_uTJ+m+}L@1ifx?iQqhv0)aK1NdarqJP+u?d4OSnd)-S@oXbydKK@&(T zo-pUHGA?9?x%uHFH`jkEV0?o6c zxvZqlcc^ZK(5R|{Yko{{ItP;j(Z*eG{Y)It)LW-9h5zJB6LY1DgjD?j8dnc45EoTo zf^MjlC%^0N@?iL&QtSa-k_7b=Tb(LzaX7^LSj`f*v~W@?PW=3)npLX^9U$e@Fw|Uu z-)Q1IVc$8sdxS`$FtYAW)uydm%?aFvwaj$*?kdSK5YZW6-EJ)@MQeUl-?gB zZb^ZZ`y1IdCTPp;i<~k-gpK3BBzsJ3HFWrJkVjjfeqBN4tO;H^?aBML4$>B$@>6sy zI#`=P;N^^cZ_N9m53=tQXk4{o$glZQJby?@!ZLwY^mhlTE0E*S5BAfd!55q4#BYA_5$WYV4?bP^18bb zt@G5#z6U?8*9Mx(NFLuZF}L9QBr+AsXuN#Aiq$fL21~sD8ckT z16pe8;?%;dissYaVIh!wX=b}bM514qDCa?9+J7}TKBBQp?Xs&&o253#HZeH0iov-` z>VA5E{m|fTuaUHVUdH(4me+G`XXzz0EL`kx{zuj~SL zj>{wc6E?ZC#qb{4j`L0m&Dcv+q8>*2NJxj}J|xwxh8K1Ws7BejSdS+V+ZP~!&`hry z9PD><4sn35Ka5he9Yz(3))Wgsa&|a|U27X$x)NyV26vn8lb}h{taYqSMMexR-L{VX z2U{0z3tXxyeH^t;zd*2BDADcpPVgS9cAmwMYANBm0fWA<8zzA|+oHHrMbgnyeV*TQ zxfIlbVE{Tec~V72Pk1MT#3q zG;4k@Xvo5x$n(kd<1zd(q6ojk*#ZMuPXs!rxFcc$CeglYXy{It1VGOb(b^5@$&;9! zM!Vydw%EXLm8b)x#g~cJet)X^@uU2G0*7jQG^~mNst(2dy97|*CxG6bTYGrtv-E9g zc!|`Zm%L-)!I-BMc8q}MsqE(^rlw?59s#C;fj4bY?kDkL^DD2wo|!Mt4xmRmrzksF2q2E^I>XttYOC zriU%v1jkhW0VSCnpFwtlio47;`6m&A^`|Mb+6xc{3S zK6UDzvvmk)%g!e=xdlhwp8+3%4Hve!)by}) zdY!59IMQ}(^FF8|$g40aS39UPa4}&>T1d@p9n3-PYSw}aBbY(v_SMNbWT|UCoys?W zUbSn^D!b`20V-i(G}YrI9~DELamMC2h{h2~1a>jpc0n_O6Ff)!rP?f&A%_GZfwli27%y{>#quAB}OG_QBPw8pxy2Ih^}JE?F^v zm6f2@PfuLeqetZ^yRE~^G8?z{qObPNRD!{P$2slDRhK84VY0EES`>CO#=M$4K$Ou9b(w48BS55Q|M)0Ji14RBKNAVN2LxZRW4It6 zRhF?=X)P=(EW()XYZzkKg42ckZ?mqj!1^rhz#@8tIbFb@OZRs33x{*_w!!zS386Jw z&?UofnKkax4`v8T;*R^n$~WVofh0=JZ^kHL1pm#Clv2&W>@Wlb2iD-67f~P0E#mZ5 z-Znq5RpXVIE~>+fCXBON7yD1%_e2crr*V6z53N_Yb2-<fG}5 zmai3i!TFGQa?b9}-)ejpldrGtqE5ps$2WrR-k18RN~;Q=^jy^zR~<#CQM1S3<%~XE z9;bLbSptqs36(skM_2Q|NbBsB5!O0nlo!q!WMlJI$GP-}tXAu(W0C6e1wkLg|Gg3W z*Fyr?PKDGW^428`asFlxG1#huP;$CrAp-qwoxRENq0My^ky|HnBrvWosNRZ;I7{0a zAFfBOyn3@MsGio`KgRSaH}B@=C+t;r;;y|ib$CL-d)$+;4QlloA&Kt6S_;6^BKCb( zGTw&}6n~+F_^~U;vm{QM2`m%Xq_2U#{(VSZM#+UiZJ*rYWAK{xB12Bxc z@1Qw@OJtJ6IyIlaT|cVXmZjSk*dGu-!g^Srp(i|%bE9VH66Vt2nz(*}zXi@8+s{PX z#k;g)iqU6T)G>O=J1-rj~&`Nrr9Xt}BhGswyGtE(i=o+tNZ~%4Oy-j&_kO zay)9hc{>CiC6t^!im}RLKo4`ZY0e)>!fl?cp`XdOGorNjTFalULX&0PvUbwsQf7r~ zD}E2)aK~*L&(~+`G{k*F*$D_NXd&pvOc(f8R>o|3vZ{_Ik*`5Z>>^Q@3(lZa;Nlqh zDUgE)VEdlEqJ}w^=M%{O1o|$`d|Bg%_WA?yp{?W3SuWz0SEAS?M~g`UT1wV zaf`WbriOf&$GcsSPW|AsOaEb-WC|eOh;4;~0e9vC_xNznG+-}2$Wm`gHt($ep|ab- zoN!Zo~!>+TbKqDyv)>`Xiax4hlDKffB({7T0sPdXw>Ue zF0YY_^Ylp;YB8!Ge}OQ>AtPza{6JdT55$@&*d+gD8xC91+_Ul_mFk&$2WF~6n+Vpt zbo}XD+HA6%_`Q%FW4Q@X;tInUHz%_A;^D?6pBWoGnO`38CvrVq>@Simhh0K#`U>vBezZK|6CyMd^00Z@ z+1z!7r4@Ch(yMA@pVZWu-;vIg50qn89rYy);}1Veid9+sNk4=w@7U*Qa@-J5Arduo z%G2_uY*_H4HM#*7;93V%p{VcDJu^{fC)B10x-|*4h?I#s?Jv9_An0Ju=_h*1XBNS! zDEOd+CMh4FHp5!Iog_ryAnnSeH*wqt9wJs9?n$bfQf}^RFr?jqn-v!A-$mU>0Wz@D zA3YCPW(3S11z%iIgbeIB8B42qSZ5%eU_!5(3v)R#hwtb=_*?b^XUjqezr^Xh6p*M^EGikw z;raR{0P0jcM^+D@8Uu)RV9!S zc660#gr#w1mm#beQPmhpDJgaKMf7+?bOJu&gl+xHux@*A!5yHq!)K;yl;$SB9AQVsV+h$|9^bF7k+*d0aFnH zkFNagV+>loPh?k_yHT5v-S7uyiBdKdS&`p&I@~iV>l1WLbIpkyBL27C{C$kqnNC9D z7s^{LKYgZmkj^l_kaB%|RmP}(-s|~t=RFHann$!x@nRvVoqH3xlWaQx3h0HEkr2RH z+cJ_7;B7_rt(nL!>qR?hwM6NDUlNgstTkg88^s1$veFTrpDk%c%`7A>BGbQH{AnWr z`!A9up8uTGY$tQow$Rz;xq9Ow;CVJ9?LM%7(ei$t`dWLXoH6&k#44t&xeqGJXGYcj zYU#mX>AS{iy0&s&f`jVee0=AqoYt9d9~MOL5CS7xgoEezM?N~VnBPns!U`o+8wkgv zn!5-)A-xe?U7dcBb#HxfM6XzF(1Wru=RceLf1e7|He*@zfDI;idfJ9xVaa?L_qYpI z59p4s$Qp#pLfX#bNo+bx9n6<0U-3QG>sr9g;9DyBQeMBe5HS1?M2q#O zlS3upu7OIHB(Ls1e?}Okogt31n|rGpM>qxTza>9=puS?dd@(N{zaZjk+MqKnlXOtf z5TVM8W3_~k`&QSL^>%=Ki6|+QkpOM>HkGsUWc$X7 ze3cUyRuUj(`<~zkS!@+aPV=BCyU!j%DQb;ts}fyWA31PB@h(%D*A`SaPP}?Hv|2aNjW@B!nTBy`O2y@+0 zn*8l(6vZ{`W1jmL$@7GQrnf?0HU9F`x9%oCM&`X@h;6G*g`3=X`RhLTxE{b^)r>=| zxV{Emuj&L&)ni6?!2vPKR}QSFrWNIe6DS&lpNAJ*U^@3o*InS1Z`-Au=!a05Oyv}h z#pSm6aUO~v2fZRp3fk{pM0;;Bw4g&=Uu@2~6|bifznf&QCxuC zDCrapR|w``KQ^?dX*cy}dZ3d9(wlB>*RwmZ+r0SGly!sZsa#jgtp@S(kZH7OOgU=J zsnyB~vE2Q6)Uh8mAon#KS0wz7j;8u!q#p%_wcq$JHkKtjuJ2}+*B^bJaM(>T{T>oz z2pb#k-AS(Be(tq==z|6Vb-wtQpurmT8WSwA)R#$yNY`aX4ILNCgXv^J*5=ihHcOLI zXm)$u9;%aGzq>bE)7>l<^k1PbyE@MMX;{dO=%_5l9r;`SMJl48?XVv=DY9~<{=VxF zbsFV(5F^m|aEfpM_0Dhqv?HAZ_N<+K>q}yaEmTH*XD39nZ$^@9bBd+Gp-P)xn3B7M zh(KApt${ULH%MMd3NiGw)hW=vSIl;=FuGMT5lv1?HKh{AIeew0^eoOs`6#xD?Dpzqk57$=Kv9!`k#p6ECWgL6 ziCo1_i`Oi=1bYF;d;4I_hZPgFX{TF>t7^wvpETc`T<_&u71v)xCJC}-2esQ8FT)kv7d2+ z6}d3hOB}v2N$X$2EQGD*1)63AG7Ihl2fa@5SFLL8Jtg9X=*5aUs}x2q|HIy9F>as zAo{HKRmH)V|7a5a%fULvMK1!FW7Yp`i7albZ$B9S*?AAEVuk5wndQehL-xOa&3Gv+~b zb5N;F6eqEoNM{Rb`W0Ch4NAQ#9!@v7)$nM_ufvOWW%Yi6U>&|C^87QoL4j0|jv_Sz zq*(?yvJl;UUuM%4!}x(72u}VTQi~npimE@z4J#b1eQ2j;$q}gk`OLsr*)Xf=3Js9J zZ~QED=I@x*fP(PAhni~P$2SLV*A5>pNk@})3^=XIHp@jB0?E7ebSfq!<>;AJ@=fFG zf89Lc)DbO_B&PxZuk1P90hZY`;|V5+7@K$gOrFz4T-5m6AP)UL&Yi|}+iwP0 zB^wX@G7>DnE`D1qIVZ#-xngb~hw8a{f0#8ZF_tv!@t*11(NXgdAAaRw(ULyt&1-1D zYHcwK+Tdrvf<{p~U#f6W1p_F}nYcnLR25St`3B~=rMVC-J=7d56mIlcE5Rx86Iy0Q zNs|PO7ssN3c!z84Tm6sRNL2v1`~|h$o7I3331mo@Uub_;(yVE;`&p%BT z{vs_wG&;8otn4AgF=8QOmVm%^umo>eZBlzYyy>f()e{~EKtu9G4E9GS%uGzVIDh&W ze9&D{4eGw>zVKc6liV1%9U+BS2uSTWVNdDdO(K$=}O#(n)ADMp~$+Myxo=evYD5H3PeA|xGNNpIgL%}O;IVblzR~mRD9xz$^01F{wr(RO0!EG54 zIi%v53YTz+SY5w0nT{wI%?U0N!G_M56k#N0L=hYd;-#FwO2z0;}9K`ElQ zN{~=lRYCa&=9u^OWmtk^9>KFE!69ND$&>8iVvL zy7yQE-b0HZaWyEcCrm6!9a5dZIOM>9I7EnL{$TSd(p6Zz>%$X=YOk(WOY!>rYQHVE z2d-#3Rj`(fQxq@|SfIa7dAxo{FUhJwFSXLx&zq*81gta+8&BB@2P1GetWA=vTTR~K z!09E7D`Hz8%&^H9s)5D5pVYo$$gRwO-9WuGGG~=kmdWFq6(7w?f=VL|KPGG*P}AKN zC%2cPG{O>ODVU0QZ583&q$} zfhmaZUj>GTFC^3S>Kx;MIC+z3TfGbHLb(Ubl(~=AAaJS&w;#lfsE%yy%@!`iU{Lf5 zJWbTY&Gek6i9c9egPl^8?buv28R7=!bmU|9cg;)1T0ZNx&PEq*2LPg+ZUs=O9~9l( z!E4LIYZtsCl_;|QI)y8enK>)@W!uy%2VU|g@lf)PwG#|~2ibx4*`MT;RZS}zDTYt` zDmKEaB0oPZ#%maI50-M;)@&kD1^D2wOtY(-{dPy7B1Fx<65fM-ypS!q(+9UP;> z3~=47Cvs-5y2V!JU3%*H@f^PjC|~|!zU_D8smf_I1vi~had<{@_u_v zEGT-Sqt*SmDGtImE$ZI?)9Bmky5A4LD>+x8LD|3sSw{aP!540Y;1^5M)FyN_sUVen zE+ikDeUrPVN&?s^Z`p6q;CZZjc!f zQ{z5QCi|p=!<=~t!_?xD4B{=Y!5}bVG0>La%j=`s%#6sGd-*SQZqY0lGfTwo=h0y@ zZVBso5T=Vp-Z3*`&JQHUt+U^N=6N{vOH!`32HX9U@c_A)223R`-tn=4bD1&3$LPL=U8H$bOs>xTMd%Rm$w^m|?;vPg5;K<*^RZ$dBem&7% ze3zUV3eBU>N+ZjTzZ7>e-28H#HZSmTAJxo`hqGvG#H2dA;B-Cv?aXBKgk5FIw=lx@ z*vBvD`q6doE35pma!j@gcOxc$bP7G&??$vgrTS!EOX7!x<6=9Q5{-3EQX#qMtq|D9 z?asulF53YJ5*g$7X3Pj*bqF4iRMA(z%F-V5lb5F}LEn((-TRAV3KVbYSl>1yUO;>D zy8+3N)InsZ&n4Y;m=5{qXsfXx2c}BMq$e6@h;+yMqECs06g-(6pK*%eW*f*8p6gmP zcn>4}p*-Q;7V2O6*LtT|p3V1#Wb_oU8l+NopO{C4u2j3urnwc9ipig~Jp;}%!9vi+ zNBFE?!uaTUx;Z)#b8dLfzJt~HJ8@{rNi>?*9O+x#z#ukFN2qs@FzP6^WrK`8C z7u>2kF@cfT${;oirBO+TA>!8VLTw9pOSX0*!?ctB9o=f8pbKU9^^xf>(XTTLmZ)$q z%yzW{Zjvi&eTMwgu2pS@+FZfQ+S|h-CT^F%*`CA7Ril!En4KI-TpyK1M>C?k zVpiP^{vl+jeSH181@;vSlje;^-}guANp#^kqhi6q-J;&@=g+rRe~}2*_RYQ2g&vjA zq+dsxZUBU^Vk>B@HL?TP^;<$3gYNyLw+`fv&-(w|jlyWhOYYrL_TA{?=Bh>l-z>jt zLi{3v66_&{;fQudfU9$m%x{Kx?m9qx$1BMoBv%?kk>-l@p2*uJD~L+*7xr31b*5!H ztdKTpqj;Bxze6D-mspN`nBS@Q`uSzFJSSEn!xjHx!aQIH%1mkPsvmndTDHj$mtazl zQGb{Nb9(U~(!qb}2VcByDDn<{G1(+Y%|3e2fF0D$PT0~EkMv?WQEi7va*y*|i(z57 z$NAEv_00FfhK0dK^J>XiQ#&V2O!481TC`l6VnQ5%@&`}M!RTBCLtN9nTx4UG9 zetN*nQEwOb%E{J+ngB`DX(7_GlG=KO-9{P(=oyO4r6BL2^OH^ww0(;>t;8mG9t|7T z9m8yTP<4u{Ip(yYHLNa*qZLTV6sLw$%lf9VUyyY?9*MDAK+euV}xaa+vcPLwNofUpOArg8_jSo$KifIdF zRN_d9rhCvI`|fF6P?vuEH0(3~Jny5QFZv@_p>{7)yYCkT%?=G?W&zz~p=`R<)M2Mv zDPy8IVyCIJaZjHE{ndXa4wUJ@;NB0k8+Z0l6=A)zawr6mit3inw%`a)xJGNbGu#et zUoj+qP()N1t(@VexCHx1tB{`h%J*k>WC&X5oFI%|!vA39<4L20-;AlHNc`iS@DBiX zX-2;*(!q<*En-O2WE;1X-&m^Itg9Y!P@CU`647*U!_k#paut5f{ZUhqyx`Tf@PZT9 zN%6Ig8S_Y*;BhVQM-q(Q@4-db(Od9=D1WxXsL)9-O0OrQ0%z zQ2m~zw$3F~B8IlIpAiGhw+ddeAc-Tptb2qDfP69MeI4ozwSm#|p!F66iieIha(v_$ z3ubh8m$0ns$TVZeX_$`4i*B1hwiCyLXcWufj0nfzyyUwU`0@GM{*wbEz@B=FMPBnq=zZ1M2>}9p z*GpciYK^m<-(2CqefEBoD{CKoDE zb`iLVle(@fzvOKQg_iwzRE|rd>!=NeHMVw=dy*L!#6W&NQy&rPmgf?)*#G8Hr=@?W(*_1BHZx^+p*R_O8o_@!@5-P{K@;8?e)|3 z>FPrktUhDAFMt5_fFAIyDm}ybHUHRqCo(b;M%U&YhzIuS@`Ft-FCYD`ZAOO9RHOO& z>E#Vy+YWqmIdN}q;vZ1vj-D!b#F{4@jEMMja+POLaUldCpvBhzvIza>I8IRU0pwY9 zIK(FaOq}ar8j7TdJiojs#VM6*`HF3StSkR);^pd4cgMfJJ2~{!oaeQ*aM=B{$_oxi zJr6j!((RuyAu)ymJlI>7Oe5dNFZzBSY+p}Q>)Sx?AP^(wO%s3L9_-GlT+b!w)#DYD zRBP4Wxzx0Aa~GoHh>?Ode}FT%;x**uCDl}$I@@ubeDCUt^T`b-?*q}GhR*b#3vG#} zV2w=G$bsj54&GSWD&704hyH?ru}6NBhbr_#D<2^4xCqnZV309OOOl+rgGq3Gqws4I zq}X%ixZgT7n5O_Bsv|t_A^f{sqQkodpP`%M$@Tj9uBiBYCNQ@ZK+N~p5)l;HMtiz#vAFWKs^9KioOyZy)0sl~v z^($D+({oY#s+J@Bo7t7#r6+b}TTz4Mks-%Kw$Bou1<7E{{&8+oaCNX#AxYlB9uLD} zh%rJ+?sfL`56kbogohI)#g@$#(0EW9v!kVN-sYvAIO$(9?yB1!8y^FP^e;hTfPvXd zc;A00yrX@T{xnC$s*4518`qepOk8c|o_SZNA)$p`8=W%)orf^KZ6})gSOX3~@ikv4 z1pl#Wonpnn=ZK3r3g(wCInfF#{GBMDGm*%sMR@-tB(CnjkbK`pt(sRX<&+z=@3~ZK0Pi&g7tfl$?2Xl+`YT;Fl+R;(g{_M{n2r7ktl^R?CT&Xrh%Exc;2*~MLZ!Afql>Kg} zL!Qlru#G>{^Y4gCKC8n5Oxyi$4u$K&4bwv6xRp8rh=qsb$fo~qdybBu;*m_QW522R zlF$t;K{UXmF@L{tq@(++eCUIRGTuykmf^9$xX+1*MR$?62e$f&RnPj;mIm1|;HAHb zx~u7(WK-M&xijdrzXDalIv&zwO_G%T|IwdZdXA!q`m8d?f+gNBQ@U6L|CM2PW7>!X9>Go(xXO zsWB|agEAomwYu7;#98CV2+$}!6W?{2r$ZjGLzfaouTpD83yt=wQeGq05y1VqUMmte zR^!d$Fnc=O(B@q5fYU3_W{EKabCWA16bRE093bZAjlD@_M>P5Fl2=$Q#P16ZGE=i1 z*bU^@6)E>jNHa`2)**%S=Mn`sF_7-(u)f=G)3>&zOlETAVpZxvuGz9~PEbMpErZ0N z!8SSLjf2GzGDhmpy^5K#I1 zq|a zP6YQc`c#@wIn%VYXB&SABic=eI9igHAyd{a3)R!w=Qw|BMryaA*Ne87te?c8Sm|^g z;G4XD_X^7D*9B^XcV!;ejSWl7gAund^{=i^E6;=6Wr0&yyeE%fg0)&B5#x~_xk44V zKr+WA(a@-_i~WzzS7*LY(D_1T<|!j1^{A_fbfddPPvFWHrgFXG;o9LICsfi+h+{1> zP6h~()|y52M}~L{Wth429Z>ovwiIq|JW@+`4jyWr&0n!m$BLY4<>>*m@z3)8MPkTZ z6woUONWJzZJsw;-3g8UbhbTp3@fK?fZL5X|Wbm1guaX~pdr&gURL!ftkHXu?FhqxJ z1WtbPYnvU-rD%y9xO-npbbw!cZ*(t*VZiRCVcm&ZDX{aD{NdhuRo%fr%-Hyo+nlM! z2wXH*7yXd4=^?f&_2(v&jW4(aBF%*PgF{HjRGp)tY3x$`h9&!YHJC;>NOma;EWPIozkfM!0*#O!e< z#OgYSklwcT0r7k*+42}Jx&;{Di+-Twwjs$ek3;q+1HD|}w+~Em=gToGa9jFLHut^h zbjYP}>oy+G1(UvU51Yi_L?WGBDWaN8(4YWf8z5CJ^|pW1gZewy|Bzc6p{|%lta9Xm zkFg|)Hbz7WFpAxpKzc~1K~5ElB*IjioojL-X|HcO)(F=M{K=%y(SHtJE}3pqbRY{I z+s+?`Fl<^qc(731Xho?H$~2R@ec= zA*OFkrcBYL84XrT7O@3|N@jv)zQrtQ-qhbd<{8TxEWZFEi1TJLKc8ny1YTPq&y+{tcAC(uXfjJAmj;MC!nSs{u!~yFJKGCCe~E7 zCx#_Y6>VbL2*V2zC+s_YhZaAnP|qBww*a}brV;o0(s~T}s?BaDN-Ib9`iZ=XJyn{b zRivdqQ~kDL{bO1!vqId!CEim7a?*{iHdL0j^7z=IO*&3hLDb! z+P|GG)Q~^Z99;oDv)9NOb&Wmi+;zzO zv>l3R4~3;H`E9vYd1>Cj#6eD;ZqJ6bsPB&CTB4~JIGLl{Lm~wWw~T*k1JExW$rqtJ zW~KW4b9}t6$AuGh_}Lp|Pw*Pl0I%SR$U-aw@1-DnBy4G+cT0N0Ag$rtWw|!RTD>zp zzJv1RGUH+6YONjO%Viyw>>omb{a&VK#@*o!DjOb|2N1K@J;v3i98ic|7A78nq?|ft zxlrCsEZhV?)}(#TiY$q6t#bR2tf4w^H_OL2;k`&S5LJH-l04y}|IC_T+&Hn2dQDeN zI^n8E9mmHpoO<8=Y=E_PGh`~ri4M&ic2&Fcaq=S>IKh(Bn9fzn^FL0S-`wq=2tB_- znz!Zf3f=cyx0X&pgr){IP?n&*45M*IQ=*GN1X`Q1aAxd&3n=wO#3Cz%_#8c1hYjd- zLm#IX>Xc2i?sHLYq^en}KP)w@25e*vHd|Zh?;BB_7-v!KTt9J(vM4|6BcQPgxPO3> zuHxfPEkClfvya2y55A$Y)(xV5`6*j)L?tldX=d4_!-V`;E7MI6gC~Wd;9~rd)$@6z zr)CP+Bg1)sY*liVirl`fe{+F|_$+5VM}X3_80Jjs+5H6cRQmlZu$Bdmlpu{tt+#e5 z6w-K^5W)}bW*eb;HZ65ZZQP4TADn_hhm;A5RHcxu-3zI z19hFO&=QW^JSsCEEmnyKk`BTi1KQf$_0(4x2uXn_;G3^f+ z+Gsg0N(%vdsG^fHII!)q4#+E}Bsgo^%qZ(-?}dR>I9P`;9U#-(q!Q*~L_y@Tf5$e$ z4w_fL#^gvbAwlk(q$~W0pe%f_T1I$O)Lh(x;P_c#ukmrxIiY`#sRVhI?A;J!+jqr>mN*HOJnzsu_&LfC?Y_>e%7g19k)N= zQta1%kxoGgCN1)ko33wMOm7f{hqgI#0TeXdMLOw*ixG_z-p3kUk<;wL>7Z;nFYkg9 z(js8jY}73Z^K}6sKuM{I6k-;}>_hK93s=4DLI3Z3fTz*b#$~xhbU^sFs_$*yN}zp0 z8I-0W^_R8Gw{nLfy+5kw{3@2&25u#z{fpEC5vcz&WNTX^#&Oo>P7Csrg z2%$Q=pl(0lVvJIE$g1Avoyekk4NdYX^#1ev%I>U1tUM^Q2>gLyuF!cxySO6KL^^A2 z(GGab0rk>pdQ0w_-loc7>&@$YbmaEgd2gUo-)Jh+j2L~`!%d&+;%x}kfo^Wh%QXf% zCXT_E2(VY&OYEP`9Y-c9f9__vP{01(9XAJ*?s1(keT+lHHFjHfD%nRQ*VbJ}x@qX)D#7fGP!PVtpnTJ`g*i;nUO<4X^ zZm;?bd_9$Q8%_%NVcYRHc!HGR1U;Hkov8Ln^9Pqn>bA5_Ms!Y z_MwQcz7Bp+`*WTSfxA-N#zpfYAxM92Noq}Nxo6dqo6rw z(wq#LWHxO16`j&$SDJpeKQ-!G`uSt?q|8~M3D;XQt07-sr_0Ta1)xXaKOQf?H8=uS-}QTZw0V4gcqO1_*0ZQ<;vqM4 zq4D7H;xEz`m0#Um;ljRmalpO;^Is%Rid1T$UxbT?axZRxl(Y-h-bL#@_wxA;3ZdJX z*DGib8n!+MZ&|ZdXY{Z>Oqs!9Uzayg)#MnbW{lMsyi4hA5LN;>V4ex18_Rg{a=00p z+rDZ-?MkCx?f2%htshxwv?uV#_762OqD^8KaVNM44Q+yqs4^mBpa(}J?W@IMWJ_G( zYnYb{aC3Fv#J}{t;&;u#`l-g#&JCx_hvhl{A8kzEn0q46gr4-a%*=nL>@Q^^z`tYH z`<(`)Uyfnx8P1DF9j|mnY!BC5zZ#ymH2r=W&P?Y2sooI5x=JeaIe_-J^OA^_Tm5op z)skUj#avvvFZ_uc_~KT}H4|}OWuq(E^N@PkY0F*PsMNsnR$4BJ^A?yUozdU4^CzM_ zf(f~v6B$>)KwMO%nUUF|WWutl8mn5VI!#;eK-q_>l5f)=0qu=yJ)WjelxAw=GUz=l zC~?}BII60K`*b3T)D~Q)R=lYh@uRC3D<12aR{Pae1r+h2Jrn%>M%;{^%BZ7ND72Xo zG`wtgSnxeBH+b|4jk>{M;GM+Cl~l(BP7|$avyiyx)~i<@tMfOKG&EGkGn`DaU2uU| zvOZsJ|F-d7oKkc5?^4r9sgn;= zm@Jlc$)Eb;v!wuG=i}Y2?_fDdZR(r_=%($GTY+RLXh`3?$=&dQ7!+eI(CFq%-b6~z zkJ959{6FX(&@Sk-e%t>BF}{PASTgW^Ui%)8d332I;gq?x#z;-$Su*aIm${Y~6>p<= zba97JTElc5dP!`upRJvw@aBKP1JIV23yDe-l94SBJdXKf6HF`c=Qv<_I>(0h1t!ha z;Kgz-J;&`(;-v1{TSG*?H%VU8L1p+?Ea-E|P`-7!PNFUU3m_8LG}i?6uw0@$lN0k) zE7bI{3C!4%oT#&k!F*J7MfO(j6A+TxxU^%5eJ?WCFd~PZxM|I~*d?|31?kFCh)&XX z>l(zJx}wGtQV`lPw_EX@S3Bum`=WG0bx#1R8&jgu8dxZ;jr5K%uL~#2F7mf}I>OJ- zI=>YK(lg3TMU+k@_Ztx5;*q-OrmmXAI6@8GB!beH)tK`}ko-a958k;F4x6l?K@wxf z30`L9hYiKpcZzB* z9_{gp*QhiX+=^X!VVR{GvoYMJE3)RxCQ>kY`oz>!c#^!Rt{@iZ(_vOjFi~X0+viPd z!-nVQY=_|td_|KUFlUL%Al_hB4zP8@1hX7Jl)p(;OWna`7tG<{OY9j@Z!WC5j7Fsy zH#4DkAA#5xQx!VoxR`mO-7wii@rXqd``+t`f&I-hv*Dg?c7;!`R6gfv zf81kXZ6W6G0InpDaR;d-)ZpZj|K9BAz1S9dbBM);Bbw!c`L^7Y%-xAXFF85gF0rCy zymWFZs*PJfsk1y`?8{F$=@d>fI6p}U>vU(@%F4%m+@X2bs=B^bpD*I#j%UkEl7r{Q z2R&mJ$-q@m2*W>*=(vq+EYpZsMoewWGPG83)2Lp?)qgjdS|WO(db>jKe3Wq5hJoYH z0r2&+I{s1pj+o*eubln9CE#EynyX%r^2lOI`U#xdVAt9sq`Vl@vFdo@$9^N0JfrP4 zYWPuKF&R}6nw9f=$r(F^>6qjtN1$M{ZBBySaaq%xjM1tJx*v!vflyMgdaAP?@QE{K z=TbRte!#d)ruL-aPgTVHXMy}`uIs!1McsQxv-!vW-#V05QM6W!wyIW9)Gk`HcI`cb zTCpQmXl=EM*t^6YHAAeHqV|YQq&5knwiur~-{1YmegA!*bKm#*opYUBIoBUol9MY} zUhmiI`FuQI3H-9ZDd(l|2uvg@jCp(kuZBe!ntJe0NO^5B-DuUT!Q(7?D+Oyo0%s#K_DA%&`x3sX7z6SF*H>m`RKT=-k%R1A8+0H}+Odiz{&Pt)5|0Ii&U2reV z?*vF3`Cdaq>Yj~AIl0~;;%WusYBsRf-;SQ%cUZl}?6jcYtaqAVjMm1TpYA64pMP-` zT8K?7Z7dlWtZJKBtUM$foOAjIcV;}2(`hHA0GUk=)`}a=pu4i-9Ua9PoC;4(l!fB_ z?N_Ex2)xgBo3b8wkgIF45TqXlA`XfwJk(8#sr+$#1eZ|OnGEZDJ>?`yn z@y9st#xh7Zk$2(imdlE_Ky@N?!qGZ`FnAnr*S{i&Jx&gLCgi5AUgYj3Ds<}KWf^G| zH*Gpbc{JZR%8dThmL+|=gUaQ=?kaVCpEjM=UT*r*_M8at{^Sj~af!T+KrZ(DbWDpp zqsMY=5~D$3z~!F13X0zr!J(#*Mf4*~CTPt=@y)i3sZ;$kN&d8Za?^WNNd1Mw^kwho zYwQUs9zK~$!l`v8epFEbpf-gQlX>%hM@fMcop;)YcaC)RcmfI&0}Hl&uO^t(xXs+U z((9A+u*+Ms7{}Rgg9Pzsj;;_=P0MGucOX-)U*W`&{?j*mgzf0E&BZF*wPSRG^=-Vy zZ=T8})B#rKvE}5u_sd`S)u&jWMeX%Qf#_g6#o9><6dAm?JZSHo?90@gwF7)UWIG$4mkqq)>>Db^nLWfdWtFAc%KV=#D2%)WZs^5ApJEO*S) zi=sUU>WPrxpop{8tzv>8eMW1Ea+~u*0cAMVZocIqu&j?&%+fL!BaoJD@0ss_MxBFZ z{1PItRcuaQ$~TzZDJ#~{QLFCL7V@U62T6|!6 zYsE88!1Z_N!$-imh#e;_k@$&V+o?wELa?(*0J_dG;OI9m>)ZanhiA)*2G)GdmGVsd)cWDsaG(ik zcDfsjav#wDH1#=NY?E5YA@0wixuwJEPS20tY=+#(q@}@{DuNW0!{u3e+9x5FuF~V6 zt;FBgYjlQ1%1tch+Wu0hTN`}Egb{Kx#(v^A;^y&y4_z9Ce!gEg!bs>D>b6;?z?wZx zst!v*gEky}l26}mA}XNCiGm^Q)ypfICF5+S0M4)}(>J%D`cfbmM!BwQbKV;KlD;)7 zaYi!pAkEOpEh{ZFxW2unh{Br|>K$2ej0DL!oXgyS2Ty#-c;H6`A7a(-s4jL{sSwV6 z{qt$S2b9I%%ZhEIW*rYO8wFCgJiUBxkquGopYIP>UEM;xb|Qej(9u<#K+F$jOn6j! z)tZ;^FLz|dY#r!@)G69G?|J+>dk~K#WR2Bg-glwE29`Jor(kDXI}2(fJ_NS;`GTe( z4?UC81+WJVn$JuztJv%{Mp!OC2|2;qdgVDb&)GOzKsiIA6J84u=oC zzSkW5fMaS$w#UHEQNMR=7{??fvvZYEJGyudsKa;W@U5k$#8`dZ=|5QgU72GvMKG2I z@y=~HwOk}{k1FpEzcz+C*GzAWQ43)qxCe9H0#Nf!Tl2{@3Hh+!8|ZGZvwk6Oab#k)> z7~U(B7}U0UZu`uAkd>WpE0a>!G@i+Ua|bgqf3j!YTgzZ-4q6giN?SG7zTPOQ`>HMmp<{8%t?A)pQ>8$Whn(DykWAe6^&?cf1cl&$`_1&~z-MNab zWNtP{%1wEQu{IoPRa2bdPC~K`2>kViB<(|_#LP3>s;j|4Fz zVNKRrm6oxn`CV2WKvSvvcz<{IJSdw*022M{i>J#Djz0+W3&3x(;WUEv+2iNR`Tfb_h#z42u z%#Cp6>Z{G?9lyFib$)g&De*$8v77Jo*RCuoa`Md#v5emrqqae`UQKA!oIQj5hInF7 z#2TcQ=VF=9&9#{YyhMUuFOC#GvWv~|kz*l>p1EO3-dr|!Au^Zc&tt!D=j#~HTd6at zl8HDGE*oMC~Y?M@i+4^a(25=*{!Z?H6Zky-x-W%bhR???#@=mLIK)STPvT zquy-idR+nhl=Xt-EZo{#^!U5IFMg!rocW?1bhqiIylcy9l4*4y{wRhHO8GZZyoQeZ}o)JwZwu$aUvR@Xx zm|ui`#8XB25~7|K*^j=!NpVLn0RDllZohO9k(Ht^ErE#5LflFMoJ^S3TVFvvgtD z2{1AnS!kfg?zNFdBsw05^j<;KCwtfRF^`2-N~xSB%%Uo#(x}YvXrDu-SbLYP9Q&R( z-f5fdz{S0u#r?0d=Va^V?)Ejn?_qIY^B_bI35pRZ zJv5nvZ7ipos1@1+^1&bE7#iQt=n8WI;M*Ru0uJ!jU}}Nbw=-E|P0Q(xj`t$(a~Txn z=fAQ&z7k2l#HMzzYCrX(3R2f_GvdU*_JJ}@7!Zosn6U83(t926+ukooa=O|d9#(R3 z7*3b3Z=)9z!ta2is*E2JdR17o(;8W6%DK*Zi(@hM*L0x|k(<*Z)(+Hy zOScEInW&Ik{*`%WL9&R+x9^X$oY8AK-dBoyf(#U>d~FqJ<4M{4^gYVr!3hk0<{9KJ zskSuz;nEZI!{3dI&H#4cT5kU9Ss{G08;JN3|0H<>uUaZ~yf*T(pKhF~?5C}e@s)Ve z2gKCY)U7LZl@XWYMywh}t;HDz)D?@;xJ6{OY<}-c;Jl5U{a~f}Cc*SgAY#s`n0z( zTj?&7eoSoKExHOdZrxgL^y13i2juFcbUeyFC3i9rK`hf6?rPP<=VG9pY9EHO=M!hw zg?dY8Sng-$7L!M?n810I%@^T8@9C3vSd6m-JwK8%#Q{Gj%JgQG?l+$ z_S@aYH`=gR7OZ7aVPb)KDb_?KeJ*x$q=^j3d_Z%5PhU0t@V{F!8*(EDK@fD*dYo>Lb&{c7rdCcd7p6*MAr=bd!8 zo@4=5krq(uh7lFj#q(^K)S?vSKLm68_9NQM%VDrO#G#m?xXyA~KzQ`j)kNq3+fvA5 zy%(=?SxYOM%lg(b5x5)d2Q@`Xa@0i;vA^;k$@{ye<1^pxb@Y$i-92Nb{7wUaxtM~T zQiP;%+}+JLv(p&IuzC@%EQ>KaYZtP$iRS&dr3579eKU`D(mnT0hG?d}_X8a}VH|1`Qr8E4I zjt1hadXqV{witbHxo4hV#cRxP5zjgio0<92-iTx5;Cz>}(}DGn>!b2--=!C(txJvG z{{A}Y4uVAwSATi_%_NsC)m0^fS7rzEB>nz`G+rq4NChQ!<3GA^|Au$AvN zF!>K|U`yUibboNJW6^azJM@1gq;C<5K{q#9h+t3x@gZ2b@hs^-r*)AlpVSgi}Y zbjtVYc^$gNDEJintf77uo(zMJOyRct5(OWGc#p)+2w!zkz-*jWez=yZMU_QHpGP9| z4v|T5K!D}*j(}9GT5+2RgRbzc`s#5Ge_A_dxn1~RC0_PH2a%`d5B@lA!ZA5M$@0*x zLBN57EkUfeWRws>IhARkA;7s`spK+ao$$|$gojLlF2nRYHo4mQCIB9GU{V$PlR5aj)T`J1G-~huFslySE>@1%Cn;Ne-6!_f%TK zO}y28#r0+o9DSj0-h4P$Z+b~Gp%t~NO|<;QD1mwZA+4;; z9_NX=O;k7U5$?itho%!DhsVLjfwOlpV$K$|6|$9-(dbEwi4*(@(NIbrQeozO=8?p9 zP$XdJq$aZYufMqr%-1KOu0H ze^Z=Ip$aH>+#hwl9wFD(qUp=a;AZo}$Y4P_wfN_&*xH9KQ8J;*;$BThnb8~EQ^RV; zd#wL3=#{93BcHq%K$EofbB)eSZ^{oD3o}3SM|?j4fQ-EtT@hTbPRp%6R`2zPxYqf1 z{6Yo^o!3kn2$m=t_AQUJL$F5wV$A?w_V#u1k0gORX91p9)9q%m-<3sA;9#<*tcFsD%a>4dQ!@=e)61>A`-twOYs^rDa=IbbfBaQy? z|42k*L23p8CKm3qGnm1mRbepd0KZ=klU_o1nS~be^Uqy|)b|Z2x5ELtcO^7j=g2&H z>X`a;kQl0o8Zm`oh@5Dojiit7RC?plkQo2sd*99-pq%UW+R)8^B$nZyCQV0rwhTBS zUW;t#Gs5+|y+2c@V!y&JiXNp0=->#13+_`3&WQS8V&8}+g)U-gVy}N~YHq!CBdDbO z%4f)as^)W9t-L5Jnk?Ge)LvVQO$dXlp0V*Z^>2D+nt9$9D8L_}Tgqp585vV;57uaR zv0oq5Zwrk+##3!KCu#}x2b|>Xg$S;9q(xD9Ap$%@M7yx*I^~&bJ32>Bdf_1^!7VKz zjWt5&Zr_Furt{(l9t*(RT@^WF`fi@24U%jr+xmt0_o_ji`bwqMRTYs6|Z zM?J9wGH9ic9v=SJRX^Bqp%1C*0iVjie&|VBa3Uy7O(AO$sa~n=^@@$Z5tfolMqWkt z&>_^`^;zZK&sPMlOr5`;Z7TJk$}?QmIKGM{VDhE8W?s(R6qMGRsRqkRl;ga>E(k>EoH4#1Vp|z`9)^RX* zGdQOpHru!EW}801Toc*m z!LcPhldKC&|2PmV7XN0NE?_pC>9Q_^_rmhUKzG14+bJE^eH;sC7;8a1W7JQum4&!W z6h#n2krN*M@3OU;eQar>K^w0yazqF{ePk%1``+xMW`*-V?G^SBO{&8p_sw*UEnf7s zbk+XX4a{~`tK~rB!QWCZY2KMgJdy1p!NK!V=JkhJ3$@fggM2lyaje%(a-y!Veq<4= zceLZU1ks|QtoS{z*5gXbX=lMOa2R6H;wHXPVf3tlgQDd5H>ucA^gzgxUfU#UG?-Ey zN|nL*w)<3~-5KYAH@u#DOFAQsC|98ItYw99(ts0A)SFl2>@rxKXC#_cZfTB=%js+8P2sxT*D*YwnC;986&8CbuD=>Vj!O66G$C6MDXlZX z9ST&#%}S244BE3`o^DhH7W)fDA1*$Z#~XJjyN4Zp8@jIK6G+QjJn_BC%m3QD^6x_6 zc?mt7`PfS7uWWW$mIe(;JXOWHdX^wRquP@qCa~>4NPxNgF}23*W~&U#MCgAc3Uj!y zC}fRKkxobIsD7a!Fs9$$;DF)l6gGghs4D~{T@$pz-J$t#TB>6{q=CMYvd$p_br1Z~ zH#gPGwOb=#EU=dS)~7Bq>$UKelT*2m=RXVV0C zg}Rzw?^mnE@4KPge#-w7f-^#FufJqXA7u`8PMa~=Tm-$wp7OVL_c0Kp17l(gMY*_- zJz>Z$#STHtkTj(Q^VtKL>3oRn=`thuCdU8Q{!44t@6@l08i0E`<^TR8$?Zx!wahl7 zT0B2v|K8(<1G=`!S+U6c2{pk&Ct9DA&m#L?aPfxt3x+h{&isx7_Lh#`xG3UCzE{*PV{f)%An*p{Lq^@4J!g+_zy0m*uuN7 zkII}RcRLz0unEVbMehlzO(_x6>~e?MmHGn*d+Gsol?jZ2oydhQx+B3(Fc*3UkQrIB zU@h*FP|S2ujqTVPI~Nojck)cPJRug4uCi`AHI$Cuwoh4jEoX$|fFtv}T=7)v&M|6M ziko^Ghvtr?BBoqv>Tr9%B!keRAh7CGr!#GQO- zk0ki)-k<#Y*w=!$J}wxEVn(ue0k7!kRk92RjAZwya&nWWlXKDdQ=Nn_*rnY-=j5+% zN?rZig1bUOYy1*FHlF1fifI}6`xl*jE!=$PG=-)9rJmu^9j-_nzrF}-}2<@d? z3)U|B;<9SD_w)=tGcY6~zA=|58me&Yw+bIQ)A!Smu+&c=~_yk0-ITbci8}^sl(f|BVKWxc}*TuR;KV8;l=1X znr*BGCIjBef&~{(2lOM2M6%ND>Uti^vUY?p#7#NzFRCkNyIiGZ?|P>$)hn+(8xu&u zSoiOunsM4Kqv?{*tTZfA6IOY#UWE)sL_L*G!Lm|xrTWx+H zYF1m}XJWt;P}cgT2Xv~)`NHaG5)+|m-kL<&toUbTVNi7A1^9wG1pM*^ys(|x&ItKb zgA6MDoUziybYJW$iACqj-GEPoa7Ax{u&!1;<<&*Af2vE*ydv@nJ$bbL z3KyZ8(HtpJn5Tc^pb2gH~IW|^BMW*4!a^{i9Mqt2)ESMb)=a5kUk&~ z%h96frZm#DT=e$2Qn5P*8(pSc5CD!*O#LCOv27~T7_PiIRO%h4qU~@jdZ1 z52H{ch2Nh1;`FYu!1Uw)cL$z?ej(M+eDt)Srs4x8Vsi2W zV&3-S3C$ABiF&pCVoKZL-ie`GtzFiZDVN(-xp{A4deBQz^ry!jmZ!~gr-pn?H~cE> zSxPazW(nvh>unQstkJeabBD0S?G-+EK0a@nvnCOuR;*(*wSEtBTpx;^997k9_U!x9LKGXSaMMdnUn6CH)SKP+2xEZVplKC3blD;!{fj#oP z4q1I704q9kWjylctv;sYFOinSY?oIW_7_aNk^BUoRIgwRcBih{TC=jkD@|Kj^q%Z{ zfPWAFk*k=-%f?dJfI7^4-(o6*#N5$!62l1#pn@KqSdF&LAkF*DrEAl;=OxFNvT@Oy3kU+ad_14=1gym=J_s#f?Q6}`WBNuULxnc z+ENajyJL99B}W0P&(MY1MT=rm(XB^X36?eY#md{s04Fby^Fk*S(uEU;)g7COKQHcL z@2U#>UYzM5r<3B*8$%1TQ)yBhx~AlSJ0u#ZqP~N3uw@fj;H6t%w#DFYJJ=e;m(Sh1 zy?=4@Q9rF_0X8rRt;F3Y*32sNZFbD__{ZGqRUG_;>Px&-@{WN)IivE1N!65-9<2Cu zH~nc*(%*Z4dti1}d5qpzYqWVq6Q`v4zmp@{O5Gii3WK`UY*5GHI}Gtg4kpz}%!zl_ z^uAwNsQ|Qu79qogQns`k^F#9&=QLFG)+2`dtbfd|df?ApgbI>X&esrNO=F8;f(q$B z!TAamF0%%ffVyMgm8{E-Tgw>Iokl5>4U}QSt?%bju2l@*$~KG8<*_{hgiv4#Wea3y^+&`@^+f!iW*c?6DihN(aw2Uga`t0fZ%$8BR2KQyba3u8R@2Tey72BdD( z3zMV#4{Bd!#TA{pwnK18<7>aYi??HPy>XV1#G1v=qL|Kb5^L%|e4Ha(R_bw%c8-0r zG(91~!}s1sz5ky^!F{Fi2oq)VLDA-Yb2B_aEt}?M2Mh(nJw02Suijl*Owspw!Dxs=_&as?%+aC{#1$6i$@V`xa}ipWJoTzI^VP6G)6aiU1h0QX>OR_h!Uw zMfXyh#7|vQFrK+tV7mP}#;RO1IOOwe&*#|tnC-N0m9Evh=$EWRVL(TrsXK#ZD^*Pum4yuTnlWC>q-OlMalsis357Hv#5Z>8@@MZcEd4HV_HG>~+| z^*CI@8x-UlJf_vFE1)DT-%u3UWgGj6s@qV$0sN!2v|(suaovL7i7$b5)GX3h`gPBE z$voIJo<$Mca?E3;D|Ea{n0@T>#s^9#US^m!0lyEt00%(=U6_?#%QVyX{en^ng|JkP z5+=)cg7Vks-LETG*@(#s^Bpap#Hsr0CZ82qO?w^DB8&4Y-{#w`rL0`FgK+8MV{@y! zVhX`gpAFnCKocJu7nCtC2YF%b)9FGZ?o|VFQ_ov1+=b)qF;uzH2(+e^Kj`n$rw{uw z6Z#w6WoD2Ud&hb@JkKg)`_>lcpA0&h?XbtO|D`d?bxxDk<>#>BpOOAfyCFZhMMs5l zTPWxIc4|Rz{d%S}-1dP`wGg?MDS%i+CQE1C2v|cDh4>N1&ab0gAWn*py`>4A=7pZF zJ9WFCXG|6+L-QY#XEKj&^U7$Q`|gUO>hEL+jm=JmCPb;&ig7>Rw4yr>2YQVI_|a&D zvhEKNR9CR1vOp^XxvTgLRnk0DtMZRG-zH>pl_q=&J?RI|J4SQIKSF$d?z&C+Do#*N zEpej9x{wc=vgl|bvvWkar4mx1`1HMsF6HNkr|hziT0gY@Cd4%c!AQwpou~(^EY`oQ zG-g?u3tQHqNcE<$1X{V<2`E+F`mOFWo?S4yZGI~EARy&Z{gtmtj7aoPF=OpD8@WH* z@USg&ol>7CofB*W!Cm|NYZ2+`9O2|E|0^Zu|FjCW`r!1P0q19m|mHf zf|)!tTrKxZpp0$)_}l#6#zUpe4@8;t)CDsUzt!d$*m*Dfra>)o;Vxh92b-{PTUn=@Adwj8wQ)BSgioD zW!RQD1-#&{xpL>F6NNmkHUA@A{tZuG9B?{xu|jm%Cb)s~x0HJ6F-%P;bqOwRrOd{e z`r_>Z)a$uy481+T?xLtlIAoWtbojMw!NQaHh|2}=-RlR3tzQidVOHjoM^;V)sOp_x z$JCLsl*b#dn)5&^bb8{yjZxaP{b`fHqE#0~S^<=Succ625!YzbKIfQPasBDBU%=bo zj*-P0xY77&!$2e3q%z_C6t(?Mj_k32yMD=5{oAiKK!rF7cdn$`&AOX3d&Z%TC)WCc zA{t~ZuPw@6(B7xuoLMOMj7n=A3uIP!KcBT%d{-WmJpPmfFEaV!UK+0IChw|j38`}g za@c4!FvqbgP=o{H)e`8xt=`K!0NU`<<=B3&_M0r_O%5#8JU(H|8=9B@=7MuKY(jSQ zTN3)~Hw-Fyll|IfoDHxRe-|rEcYT}i;$7pw52uP3#!P1)?K{L%yV&z>56<7Ra$w6% zepMr1+?P2v=?9oGndiEWXeGpX_Ok;w-5F%3hlhViv}YG^PXS#q^EQx4p$|92qeDM>4Dzcye99b!9p@8@p4V$hWI;C+t81LixU! zdS~!dXTS4_rJO(K2JC+kwOJ5)wn0lk9`Tjpc{$-m+)yTFa>q;yudaMOINLk@i!{(FxWcI@pM%t zWedy1n#OE>vC%CZocnLu8Jmna(D9|mo&`01-|{-|shfN|2!X?`3!~mD6ByYIG9SfD zLP66<*ng+1ErUh!pp>~l-+5&nP%S*~@Qo+o5wLqEfg%bmty?$6dVFh8?*7J2btu&K z2EYG=&px^2W>fsqwbeW*&H11{emNgg8t|bO9YW^86J!CoDq80diIstUxl2pT~Up7FTvsndm*#iXp z>=BOAK`Uxg_J*&U_X}Dwum9qgXABu(8+;v{%e9&XtlbPp0b~Y00zB@ZPwN=r~5lf)(?vo&kk675j zE?9*GZS&pdD!sTLU=`)%Z{pxhQ^W*{tLvf8UTyc~UK47`G0^-cYGKH>BfO=-O0wTF zxfwh(G?`$U<8*El$r$v*_!WafZrQA*j(x>Dw|dmB-}ED5ZeCxa2Pn&(b!wpw&+`vd z=Cr)mv>%Q3%7H9s4`^CUHc{>Gh8Qb(!Q3|Ww10nEhA8>1dC{l+IZ;83sG3*n88_zZ zhnRkEOKKW+C0YfE5bGrAtEuThmEM2Um){@Ui*o9^=8j9cUc=bEe}|Tk88<{Xri|5R zJ#a#FmNEbKy}rLfLb!ppysMWLM57teD&ip!*SG}t3IGC7KvO1Lwlz;eXasdbzr9(? zAiaA>srvB=Yyb7sZGNAyBeq|3M!IwHf!`lUP-r;qNKyUC05s(I0H~AiWLPj@#W>cZ zmn5^U9*KR6qYu0fP<0mZ+_=T%f9lM@2O4d&7R?R}w^43f_DO46Wc{eG*X+)ghVTJ; z|CwSy;;3@>$rc_{^iOjB9MV9nygie9!SQmeN+#)qCei2<< zLLO=rqe-gs_|*MKmy*NoJ&# zMF_PF3W@(fMK|aiTIMT__`nEq3PU)_-~?h24v5+BLT#_5^1Iw6;v*d}0&`5XlL!$m zxz}i**|FM}MCpR@K04Kl(I2n3VIi2V-?w!U$spMC5j0jFT>&U1!5TI>|9}H3)E#Ej zpJk2e$Fp?2wNH?ZN(9R-Qox0?nz)ab>6mg`zflGTeWg{gUGcn1r|s-WPh2_axXE4b z(ys+H=ysBp;$IVM({|3C{w}&8m>V+z!*|XNLT0=vTQ0;V>;a(kkP5(uHTg=8zO@)S3 z8;;Dhdc|+-yJRf<8uM^`p_d12m3rEVkB|7?-rmM^L9AY4NT7R{yUZFRBmx`SqkxQ_V6NQqwgX zRkCI7eV_*DUznDV-&st)Q(Ra7a-}g*ER8iCK?rl+8W`R$c;Jcq3T03y7qULHTmF! z-TpQ8)Uia&< zzA_(0LINhwC_A;b6P2n8=@NC@-Lt{;DuHfXJLIe^Q%#{B;xt`QUuB?Rd$Zip>|8dR zHG>P~#r9)+`jPvC%WfShE-MXm%hHTG^Fc0)fUXrURXANy+S`pYHT~;+E8_ra(Rzw| z*}>-Us(vB1W8m}^6daW5vhWkC2eeC|7c*mSTwyzN09*(5Ni;rE&(SK6k@t$9z!{CY zSD9cDc?WgQA&#XZ0HT62wXgl{qcsFhPLwtKF}APRo=J88hHb+pkM*NKxqmOJTu&KI zf-YvX2&&@$ewDt#p}%up-_!y77Y7BLf;-)Un(zR?pQpT5?pH9Ez_Wdyc_llJEx$60 z0=BY!X&w&AGbnqq)xFZdQmw~<12^n}IQyVQU%B*Fj8D_21%5+ZRMC+kr<+DT9dQE1nGM7Tlzi1#{ytK^f$(5q>Yk>Nel0#RbQ3Pd9E}?IOWtd1P=M*9UIkOYqK{`lhYd5le4+g zNZw|rrd!S)MZDB6FHiHc68;>wcUf7ErJy^<=JlNHGKT-4eFYymHTqIoV=T4pThk-j z$3ibmrr}1C+FWew9+tn)w1H_~)ZZs3P-_J}dv;sTcCJM)%{EAGI?4kki)t)N&&g1Y?Rz{^4v^a7`1Nc$ll=K3-61 z{QiXX9`S^4?vR#F?8+_LQIMw4Nrzn&dSEqu@)p=*>p6TdRCysULNa%lq${rZ=B!Su^k|2~O zQ+#BI=D$uJW|A7iWz+G>%`Sq>#~YgCs0!ZK^v;tVBT`8@Zn3|$XolJEF8HMMCaQ-ccz<3W46z5t5-XE5yRdy0N(T#Wmmo|;2u3~Ro3&CQtqHgnK!A2h9YNNff9 zqkLTRvQ-KP`<9sBUFO<|U`415q@;z-%m(aQT&fhBZbHo~J|b1?5mii{r}6K6+^eeg z;|d3dzMnrtym#*@DY5lk2rU0wqGQ)|!p80adOhG$b%9(Q5CdYq8)PXhR==hLt6aLs$qV0+daPIs^G3N$^u zUTR`5^ z$D+Qy%5!1BgEimW>0CqmU)XOj$tFe?5pOkuh6i0QYEw7BR?*08PjFay=%TrTqSo~W zxc)Jmyxr=NL-}+yAn5hAMVoWvBY@AgN+XCp8PmFjl>X+vYNxL88!0L$lO(vWA)1P* ziQMj}CgNr~X2gM6GP7mpP7`PT{>`?t0W86I&AstUxr}M2O}>jd|7xK0jYhDb8dy0> zA)!)f%hy}RW_F%S-hQkftSp=GAp6B+$yor7?N>Z=GBN(vo)H<~o0K!fOB@get`TI_ z|9S6;XP=Dar~8zZr`V18rAH}qJQ^4CWPYPFw({_G|3jhv z$pgNcN3%icqxtoMNU=UO49Bb!hvOXgE&`5xi?JGn-26-0m+6?{Hw&qrJvmuz8OYaa zxF(G=djzW?ob!Q4PE6Ic!s@@y4HYLw{zqbEd0+CnMd$`u<(gA*(K%LS;Ic3Y4tH3@RIISO1*?`0K%Dr(0;AFaL?J2Wa-})D^b=8hj zABPDQe-oWon-q16N9S7D@0~~m2NTM6hn-P)S=f%U-mmk(^eE@C7P9t?xn|YZYPj)@ zQigQ_{z^TOUZzaH;|!t<*p;2Hb@uII^?KS>!jJ{wrMU9k>1u4gl(=?se3e%9Qk|gm zaMf=7;Yo5!FuV4szM-;?QFC^}pPWE=Z#BK|6v2i9&e(^!y)ETF&(t~35b$kBGPNZa z65saRXi#Yj)TTTH;G7(4o1^PLrdJ(Gu4YZYmx7|1p6tCpHkkgizQ2zO>!8qG`Z$$cd zar6m$53R4Rkq<~2XLcQ27BSPy7k5K9N6@kR^g`208O1(pAO9`Y(h`TGrmDBv)k+*Z zm^LO35}q}&U%s9+-_wY{JTp5kaCwF@tTw9NTilpB#5DQ_Si}w1`^rqHM$s8t zuoV^Ezxp~oqCNr@8DPr=vGfI4O02NRvijYO(TSAe$wDY+8gPfHUAHERSy}d=lT%z0 z)l!o-vs#$6ug<017lU1@WbVgGUK`4Ik7-WGb6gIGJLs4^yg0JD?c#fkssbKAcllg6 zS?d3w?yREP3ZOMjOAE9`3N7x%wYW_5PzMzAN-_jv*qQo6n<3AkUKYgKq_krP5M#V;Tm;v_V7J4oR zsfWw?ZxSvyIkgP9;mLi&m6<#ZuB55%c`U*ELLqFhoG)IoMQ{Ru<-sb<+SD^4=9(H6 z-0%PkPaDsJc-mks zF3**vb?)IUq0FdQdS0a?`6aEkir25DrG1(<#p^GxHD1^JZeCkPtM zIA~$!pmSyD@9+6Ol6ST-z|rA)T!2cN<|t2c_*yojy$rVE4~MNf_?dtez~sH(Fh7OQ ztU-AH+7GQ>zCZYX4iqL!JJmBsMz{>Mt(HRg;10>ThTqW~cr>)}|L_}{G_QceVW05g zKaS~W&n3x~mOOJqfxPxlZGQ=L53R%@yxhY>z2v%4yT>)I&$gE#Kjo?IHnFQUKuzIpdGq;p`bGs zP|kbJGw=^1St<@xc*12kQFgjl?Xj%nmZDay>2+oDR5LIREYdGg65jJ2X(pLsr2P*g zOc(S~!=&Jh5D#Q!UMe3@b@8fcMY7=$r|J`oyGhn$UJTRmGF#VGN6<*$*;MnHtspaF zUm%(AoVJax0`X<`MywXlQ&$jeAUNkye>|M67~Xk`d?g14qykU($rt_Ax^zzhCDm`xNdl?=y)br7QnZ zF+tZipKX0^OXA}){*ZZ86z)?h9xWjmAwGUXnhut{uq;8mU$l*5@_Ai@mZYLr@h7&Df z_3=Bqw-N_IF|^DVv|3wPMrqR2@UO%3qe=@1YA9B^fFn8vvr1(7_EDWFWoTw+2mR#J z7Qni+psOjU=pZc4sFA|q7S=5kLgx(Pu;*>8$`$ zqa{{tM4k7&Aaa_1giSo?g)ian^RwmIOe}Szopv!+(1qaT0gS>~?|w)khsTr2qX5XYAzMu4q1Lq zodT#_nW(P*N+WC5AGCLgs&(KkXC2tzN;Cmf@+fRU>u$ZQR^oyI)%nR+J=HP}mTmO=l(T&RIs-IiF3+Xb9)jmyJ} zh1;^*1Vv^iY}p1B)P7eF23$S3wO~jOq%hl)YuO}yqESO|a2IC z!gSA`{Ec|foaTo>?Sd>DGw$K(CwWKnr?qw0h&a|cP*#@?gh5(VY3_6iXCh5cDyT$% zAwB7%A7?S!4K&-UVdzSKAyUo6#Q;VX-T=&{GO;0CE zTK*N}eU*00x@e|{(7el(V#i|wH?GGpb6N4+T6r7RD40(_!<@P1)IbxN??Bl7Z!;H zK$@#}r%@L4lSkouQJYKx4rZ`t7H=^Xn%YbATAiSX3Xq%?{o;K*;S_~oM5$AoH!3)^ zW-_?x@v85plrFa9nQ=kjTfDZN;P~33?uZha>PbJ_?>0r$j)AtoJezW3`d3LcfD{FH zLhvAGDuVno|IB^I6nN&IKJ2eNDbMmJdjSM_D;;t}ZLqs(d0rezOZp`^Iqt~{p0dztLd>_#gL0VH^*{tK4C_~#MC_nRxlCaG+93Q<@kw^- z1s_NL7ySX3?EocVI@j(OmtxU{kkCseubHVRRv}Bhi&) ztys9r;QVPA>ZnJpz?*=IuR_TMc|x?uDDz~C;U~__R=kfI!wgh2XOUqk+@*C-x3ryk zv&7jj?EkexBuOsBHG;7FCz_EpoBzzUh{>M89a=YzvtGSd@C%XE`%CLLu%K*g6tiyB zGA2K{OP-l{2?k_m7MexAg)%ZOZMKH~ZrJyCniRjv^UZp%xhu6*?6c*?B@DeA4gjal znFhI7t++0#b?!^he()?Z%i6+sN>x@ED%d96)`^pSrnc#E)>^V@J6wd4oS@3u+qK4{!Mn)fX4QWX70$pJH84%ukF)=Q_Wi6;n$| znc-_VZSZ?Hx!j1-V3jz5RkV`$%#))Dl3 zuN4q0{o)@6aYz5kV3meyqbkcA3;q2cBER{Hz|Gvvgai(T_C_ZTPe1Ti*lYgfH0?Gw zRz|bw8?+gtt1gJVrEWR<71c-q3zBpBzCXP1<&`c>KW(u2^5V_PJX`ciEHMe;FfA-T z{3@x!a_QLHL4)6enXqw2n*66mze2J7L$T60QNXz#I__vV%U9rTx(8eK$8mEhFGg$2 zOV72M=k|woA%~?4T9;97wi5R#Ts zKLbI2*wqpiyV6)ZF2n9i9=M~n_cSym0UwThtFb6)mMYmBGsM(!_Y4tg>BXFqQnUmr zn`pDQzw@38;Why}4{3y*7Rxl$&4JFzFOq3{<&$f}rl`^dm@@SIfj>RdIj1ttrDyW& zy0J40ViIRQ4L4tS?Tur&^u;weksH+eaBU>8yNJjZ=2IUsEGJq)PDN`sPlxQrCYNt} zZUJ}D+L7d9I!8R{hqm(|{P!_?Zq1@vtI_t8CVwcnSw0YtF<-qO2_yVI@py5UV|D;m zPU5!MYMD~%2Xm-YUWhOKP=-isWl=K3yl}_uj5ywYWa*a{9{=&h|7bz8?e34rGQMAt zDaZ6kL5hVba9z4)=8oI6tJy>lgP5L7K9jhmzTSxjAP%cYHIf z!QabgsqV&PVkwI=0e^*H@SvuS??MMQi?;9+T3z;u-@(?3wv)ig=S^oy8rmqy&$ae$ z)!ZjVV_ez7=s*f#E~Nbm6&-ck^9+L|{b8Ykb*>wyA&mvgvVMfk%t5V#r1bmTjM%~# zIxzW%*n&qTdyVQb#~iKms}!T215zaUR!Fh{$uhNceS|nBCHD{U>fu|Ya{OGmXBH5h zXm__tox|ue+Y&6;5=_h&a{iq2z$waXB@q<3$5k?slA5(`R=`x@*;!Y&b+uZ@;t$mHVWrCM5Z=xk(QR z0qzoVMqrM0=Qaq2x&&bl^pac?S}&r*{X{WlgV?2Z5((i_yYulUwgdnCafr%aw@l7s z8{Rb(pBYXk+SC|tu>Dc!=%bTZiy({Hq|vK>$o92eKl6768Gr*MFrUA~=aya(QHh`u z{)f@6s~No&sCl6l{a&4c+zY-xfDE_Uy38(}VDns&1&{JRuW+V_&YbpsA7Oi&Jwhy7dxIj#HFem|*gzJwa!gEA3rqT|@S-x{puhMdSNx0Nnfs-Dz68<$ z5qUkDVcTJ4Bc7nXb9sBRWyct2Babi`NKShON%;BB`@>pCS8&2h!yx3-)la#FZFH4g zZ8vm=lAQtZPq`-@BTKgI@FuS$pp*rawkZJ`uZ3m@;1jI)PF3JxOv6uui34APbu&B{ zE$Jex6IuIru`)Wu0}UD27s+{oBq18w(VaG30Z%dYWeOBHGxME1I}AYa z>9aQ_04*zK6wTC;pC@)a&0RiUJV8g5*MRxjDSS^9`YP)0yJ{%;zX~?`UL21xBZo^b>3Y9lLrFIu6 zq`qPDwCHBMwdf(CaSEkUf9-|N-HB!U|2}x9?)@_zu&(b`^S>tEjs=#Elg@!ka*Z>F22RRLO&PIBC>z=?g#IPI08z0rk;ulN?n9 z>JEnNOi6=#wgsNX+2oyWFJ4tUSQ|W27S^N)V<$D}^-?RO8TZUcMmV6Ur+jN}Lf%@H zRPBB|0e(Ze;S}Ts_C!Y$qdVlRI4twTmYaLCeW-LPtvb z{5z>o>%ZQ{g%R~@($S^?o(4!@p8Fpk=Wl{Nc3i=Ap`}szvyyj!F6pfl5}(qW$tmaT zTm_349=stf$0@zK*Io#Llj|5_i5^UiCbX(I`09IohM0;vtTWU=rhl%%Wlz*3mai$0 ztg{L2f^Ddl-8lBF7+d=0@kc6~JshIH&KN=QL8{O3yf*RgP1Va;Hh9W1618tMA%zGa zNHW_Gm>`cBbrU#u;*=tvyuzQO#va!d`&vDGj8&^sYeFtvTG+TTO4nbkTE z)#aPDNW97GbvS`XM}{mu&DXJFnQm}?HRE~RuL(Xo-?%fIKOIq7<%TCRW)1xS*m=1Q1Ua@RsZ%Rze9uZ9^;V^Rprh;F=lD~bpkfkn6sk26suv(3fx{^-{4-p z0xYr$J#Zxni;N$ibG#_@LOieIqWFDN&IZ^OT}-w&a75Ep8}|#r7P5A)CKFc|>GfE;v=mrzLk5IaoB52t7vB!_C)!Q<_uT>R&_N}}N3f_-mVIU#qv6=0 z{*J;qe|UU1h{b1h`uS>l?8vQ^p+W=oC?`Mp_g|u9F&pIUbDyx83ha@?nXy-{*meCQ z@8dF!nQfX%YuVf9C|z0&8e@}J&UU+A@-on_&6+H$r#P^QC651UAd=Lm>Lx*Q@1Ipu zd>r#_fNsPdC7-1W?AREDa`M_i)k$?41{Wt!vF;i6$wh|^eBD!==L2H^?afxy8S&+; zRWEa!b*MAkMgbaIKs3?U$9%Te+TXbGQr~<(Y4vk7cS~FA{m-shioo`#e%)QX9XfL?CampV(M()H#4%>r z&TS6|2wq38$;_{ZF3@`-!G9Qdp4Lx87Kl%9&-Swf{TjiN!3#f}qR+ZW_EzD7%1IJD zdp&>FrKThSc2+I8Q2fh&?!0n+Aa`S%-GO@0aT!0~naSLca|*dNhYh<=i&OZ(L-s3I z&jd?6lJZ0MB;@Y9ZJuOaA6*?3d7Jfwr5?9|;dfh?Ayu_K5t3%a znH+Oiju!GYq*Ya#cvVn<`}18}AR)OTS5`bQeq&GLIVC0f9{x7;o%BmO!TS42hBHaIGspoqZ?3GLH-MaUCD`N^B8A+=dfiQ*Vp2CFcS?T$+O^J{cV=SPF#AubAg3dHR%@S_Lu#r05l2HB3hzj(^Dk~hC!OG!_T zzRxoj~vdLqAH<$iK1gE zG)nCpWdY+QVP+Be^{4nqe^m0FARYY84clT9x#0|IfXc94-Pp3lCi&rL^y^QFCL$^Y zX~C?FpHuaTab9PnI_E+zv(zeaV{X^WT!i3?z3+K-hBLV^WiV0lW8%GDZY_A1|VukU98@FezPEn5pzej6PEQHbhI?Ig> z%ap}-JlfD=t&8~bUh;^WmM>%fF#hNoM?27ljq*Z5!usbT=l<%l6l=9H;syFw<<`R2Yi+!2@Rv9SA3dDa1C6!^Jg3!M74XND1=L&Z1O z8b6lyKx2eJn$v>deV}FbwpB*zf~(p}?uW;`FAHu};p#3^XeT((>;kj7%x@o658Iix z7EC-osIul!QO@uXmWXS`@0<`r~S2P|x?I991(W@iKZm+&W*hsb* z%omLR52J^(Ab{s1N?bgN@Gg*I0>`kIqM4Ah;;SPZo+zS7ldzwV3x2EAqCmB~Ud5w$bDnm9$ppbAc7OcGe!`Kj{U-0b&D93{ z_M!^cy7QYfD=kyq{l3#g;=RV6`gKlaJ+8cX;E~KDfC^i&HvJP=5}>?|Ky#AQ{~(2L zy%PbMZKqoUJ&l7n&Kv4p*hMji8nchI5Vv!Ayd*&LUthi|Pn(L?w#_vigmM>E3 zJUCn>rz-RhgXo3PLdT@;s$MhfS)lRHR{@H6Z>qPEgh<_b#GrQ`S&MD++T6Je2c>kk zz{gEbe25IIxBwtW;4L2A!6EwMdA2r|=!y48Eg&P*Ae#Gh_6=izcs_fS26JTv)!lvk zE6Ay0$X@K7`WXNOJpESp(2`1<-4RcXz_r9_!C1FY6<20pQ^X^{Xww{eC!YF~#fnII z>C-CpA|0OK`s=Mv0=x%~BPszr3z#*ls#7%QdNe)dW$@EoJ38Nrn@7KV!j$sGrpu;< zaH%o+s&_!YoOBlAevOB!MXluIT9~5}T8*N$DTQ)m`aSAEAzQlJirqfy@Hl9aWe>Ip zvgs@sudM*ov;J^R$*j9on=LMlAy)FEZVzepR6|$a$TjbG<+R}LS>h0aL-N2}LTDr6 z-O0VGnlwmLT=J=irq4T(53#TRuNfl#M>_@)y43s!2$JCkaU=JKhSFM?MmKOIW!ztO z*xk236xEBc>1C6lO`HA*G2h?xlt6q%2M#ulueTeQ+>m=euMihNluA_>u=R5na+Adb z5kb|XPdLQ;U$M>=fAo4tqQkjO(`xKe2|x9`DWrZl6m;CC2A6vClN(lkWSWDssQ;0Q z(r{5=0YCy#*<`%!tHubEy;z^t-=_incUeP!!&q-r<9r?@GCxNEZyKcyaX8qGv+`4YT>eky3d#RW$ZV zNwjiP^<8!&XWj#)!{181^f09b;2dw23Xc^qx0ymWbvPUm3rabDR`N;f9?7N*_e58BBF+hUm+Tq2)D{1*1hOEGIW z%pp$EahW+vTJwvB=C7!!hvu$1(&sfF=Y(^lV(CW(8vUpVKs2lAh;r5;#GuvYOVC%r z6-AfQ4F!iIF?J*yfOjipZVoj%Qle!sf>wGPs%56?YDT5kf<^9@-h5JkuJPv0r|LD< zhL<1MY#IxK$IRw^HI(;_b;iRYP|Pe|mh^0*X%(Adgj@Rq3$q9AD^b6#Vy%Fm(SK** z*3NIBNl<7lg+_E}I^01er5@`LjB8c#S{i3b-Y4fU3A;FU@1Oyyf&k7xGD z5&2Y#aC;GBG2^+3vy(PKt(E@1&MF6^ONPr&*9y)$Wg9p%Q4dr_iR5<B8`ONhy0xN1Ezr zC9{<*?Y{7P_R;70Pu$plpE#|IY{ktjl|=%}jn4rtD(fFLm8#$nF*VBpOY74k^QqkmGen2w)IUH_J^7nqCO6PtXg7bW1XQ>L zZh_qvkm2hZTUu=rL^<|wuJ&DrPv4_o*9lpEOzB)h2oKa6tPg`G#H3-aCAm{DGM z2XUx0`!@=)s~wzGJ4j|_^ssAD#)GUbRG}x}QX)hD8H&L&*dXS8CU}DD`A(G!)gk&4IPQeH@>)KAWFY; z4N(>3XD!mwLvreS9v|h zzYhYgo{%k{f|*0O{j!L-C#ff4oBpkcaHC3x$_FO0R?+&Z zmC8?~L^zLz(3fE(x7F}NF}$Y?Y~0g@TW_SF7f*ZAMKXh~(3S$ba0k^#y({05IJ;?U zdi1E?b(ZLX+b!=78$gYmM4lyuz8A@QUlW7PjXwT?H3lyV6iJXD7PW*w@O=y z=&@>vv1Wtp%#_%tStaj115w&X=!|L=s_m+j?jxCIg67F+m!wDg^e_-0)PUKkrvIHT zJP=`&Qjgz%3wIy+FKZ*zf*d`hff;dY~>=l#2 zZiTWqkuKKM)vp8ebSvy7d~-^{=rCi4o#Z7-ox-k?CULxER}13)hIWN(wc?gbO+BP3 zapqPaZP*jBiOJIC{LkQ_+FuAp+qIJ9!{xXs8!RTIq68A}S}wjNZC=LUBRqY5%W+@k zsChzFZLl{V66OPTb9=Iqm>cZpeGqX~Y4v6Pc0Na?10(Wkiit_9iPt%G$xDp-F$zyq zNhQ*ie~&?H^>56QL(GXvk@Px#TFHU9p_>T9wx)RNFHA1%fR8g{ny`#osEruzfUvcs zdd_n;$Nr2el~rKpVo+P@D)RZQw%X;WvmagOs3^1KmJZJg&>LW*6t+{bSY;I6w^rj^tqcv20={Xb_&&TG z`Z9}p*eY{mrgCc7_$%+ORZCo_R-qArW||#bERFgB?!D!#>;|!7y%r}iOCO=wYSRS^ zNp?E;Y@6YnCy(@nrcDPS?X~iORMyi}7&ieQ%Zj~fKN5y2_7__umMYCTeNLU}LO4iL zt(nTVBlGOn)YgR`&}PO0 z^=8;o;YZywQSwU7m_kRiz+1rx;weP%;>r1*1-oQ7wH?=L4egj?Kg1-6zXT4cge_B3 z^2O*VM1A#Vro(!ZTioEXU`jSLP;UC3+(Ub5qmAW}aLm353$Ld(<%uL@Ls?a<^*+_dtI_SkG0Nb8q@dyRhS z2?q}eaHAkgCuBWu!5?|M{&&FY>88TitAsZ&(t^-k!Di=(VI`x3&|SA12GT05h)aN& zfgI;~@D#&MDb%;hruam`Z2)IL`4;owAyUv+mQ13StF^}BW{3M9P zjw0~gb~8@b8&5LS6eaU}P)|ae3KZoYjX(MA8+sI+7%;^;M0cdj*(!@9ha_F0#Zy0* zWj&=BmDfJBeB9&)fOK$%RN^z@KLj6Qz;~oRd?!A&!3ZDDJy+X&rB6ht%{b^ zihPaRmcsX=`?x6Xysvbm%E5U##hxr|hK211QB|5g=!FMMb0HetTihL^h?FNA zpVi?MTy&HS9v`!twbJOpiZAfHpEYb`ujUIczE);~%#a0`(}fDUr&slu?1F|~?;74u zaMO2MV1<0O53zY~I%Z!XHMr8Mxw;|;qP#7w5%B)ZtprhlOhVEGcCg~QqY8x-i=-Eb zQHch48%VMi2ZGyo;)Rwl%9~5MWDYau6oN>inE4#cwUSn8)_H-Mmc|b)4&1Mg9v=j? z-ZX%*es}$rc~bLEttl=0IJnaG>DHdWw;1PCtH#0&(-p}z!qp_^y2}iOgLSW;7MAAw zfSShY?T`53nuO5_=V7nBX51Lj(sko!wZWcWXH3xujVWSKK?t>@@$t}->71PMr?Ah& zl*M^>k;Qu}0sk-#qE50(ei|aVIq?`(0%3#G8u4(RK;j4cm)DfBkf(UAS*V=I({H%s)g|C+%*Cx0t zmf58C0xcSBi=Tb^-gH(Q`qpoG^dP5*ms%zo_xDT( z!2=Lsx_S2? zubLc4sCQSCf8eCB@0|G0HlT|4tFX+QR(0m{UZQO>9&+3VZ&sr1?yH) z>`5tYI!6#pdZnbEP!qdGi&y6z(9S7U9=m2|RpQ)7*9L0z~?O50ZBj zCEF%&>R;)lg?mkNVYWLew92RQJ?;(Vs64-OD3KnpG*)@O_|++WRz5$_(9eT)z7XGX zDa=B=nbdN@D@*NvNc~9P77l~HM*l`Sqdk{qg{XcHqOv_AjBM2>&v3w z|AeSki^-~32Fe5BF*?>1(TiJ6p?pHzT(&t=^35-lfwgRw=e1rcJ70DY3|DN}z0T|r6#Vw+T!mRGtIaX7{;G_3xE0q-8pA*@7 zwb-n6&@C%KcWAO)wg5V^^k)UD5qW;lMCHKXj_*{Dicn@1S5HW974Le*@dpM_!il!DxG9{*Y}F@5$$bPUi<3cU!ck z2yYI1F9w()M;nw*%8nkQ|M@a`kJbt?*BDh!OO^EP$51cN*%ia+**MJRv&8>lyft6v z!sq$pv-CFtbrn=Uk4ZO%#;}k*p;`G}2Qd}eFbIk&e#}As?c~!q^;aD0Z3*5IQCru? z)wS@Be9m2HdZ^kpvz11}JBX zT$r5%d<6~*a0leY*f9s;V4mxCzM(8+8Kef~bd|!Ic?R141laIF9LbQBv@#qYfzyF$ zlkTQ7=eMFkR6P4v8?%!xP|r;>1PrC6zm3F$FVd?T&z2T#!!^hWZ@uN*OnN3edXN+s z%=4N(vW+unb1+n_nXlBWCs1*&zw9_)`0ySMS9XZ+=4fTEk63#RNooixV{o$}3LO)& zNltEo=c&sw_LrbrOaBEyA&5)C?8$9d8QM`WJvEqVe>?P1Jl2tXD?j9ali@*)#a8j$pb>mNrL zwhbhc2h1VOZZx5g=d~dcGO`6Tg0OU;qlLZ%s4fLzkcO)Uz{_Af5lG^ z?*nK#a5FYhVVdLoK}9(?X;K5m>~|GKl>BmCem~ldU4i^`tVl#F3j;&o>p~2!1XF}) zvWU{CL$xh_$y|ntQ*;Aw^~9GL=TH&~#}d2Lh1}$!XFC?BhcJFN;}x~6M(XglsedqW zUN0~!CP>MUrEtx$-g4*9&G#qV;Y9GAVLiK?!WrI{oymF=IZ;%^729n#(vy8w>QDCV z9qwZ^rO0h;y*k?njiX84w~^x;Yw}e8=OohwW9hT#J5EYiwMn6G7L$@oH2vEMG)n7# z_r)A6l#5Xmy)9Kfnw5UREdBa))!60zpCF1vm?T6Y+aY+59L5Z|R2X6I@KOjY7>Lw{mPD zx_?&#Okvg)VMIaQ2qtAaKv_;hExtd^SfSf*3V!AuiS#t6$Y*c5cA9&Ft;*m`=+#t* zPYB2Hlj}I-wiWAP`2I!$YAsO=ANQ%hvc{%@4({7u;!M!d{=z4wsn1<$$>sav>T1Oi}h-HWrl*k!V6UhI& zC8#`&hVjJGnxbdVcqyNMhY4d1dt&|U7q+{EmoNJmvw=FhgtY8LD;u+$RxA4NF7=Vt zZwqPkFVb$T*0O#Z;;kpb|WbZH;k8JX{nRFqnMbth&P!`FN|Fd7cOQSZoNB! z0hk}KS>&_eYAM3?HwQ+QY7g|i5_UC{a-(bj<-O^)u|o?u?zgRdf2`geg)yaS)|n>0 z^Mn3gl@DDbB)*v@tAUT(I$VfhNIN?Ivhi#B_xj~aVQ+)h*wB8PRN=`!pV5}-l8tN6 zXWlyF++ik~s5(BNTg3#^_9Y}EuT4{W!Qh1ezcv%OG0E>9nW7B;O~Y+vj-btZ2)x50 zkB_1ipwD5BvI44LhDv|&N*prMws82h?=v`8>FCFE;^|_<>pGhw9cl2b=Ctq|Ix9*Y zy@)sK23mMjPZ>&aG*o9w>oZdL1rSotVfvvR98T7K`5MtF6jS{3POP!JwONsA^FfT} znm~_$QHevbccdJfqD>B5T;R_g(h)d3YB>in&WVeYhnYBzXfL-0-i$3S7%06r^%}O_ z^pI1!kYqzpN8#p_=y@9=xTgF*$E~2M5+F5@@^wM6zBgtv4f(2>q znv!wB)b(Q(b>+kAkl9X^XZzIpxQnRRVAeRY4GN!qu9@K|yF9)Q@DFEX7c1(CK!tXhzlh|fJ z_b5BBm$?5hUeFZV9lY$_bOhqRn(8XC*MPJ^ZciR+{M(KP8n{5Kn~cUMcBNSwc+>8@ z$d4;KKfpqA&N|u6fMG>t)oh~3#v%bJ^k^E9VWynZx#uLR>QmA9R#|DDkTM~b@KqAt z#XF*e8fhOgB!|XZ6>huBOMtT-KWFWjUzyg$copqVY^*6S%|ZIFUsyT3C@>P?;N%Ft zduEpQk!H0I6qGNxJ={q__^k2)sZ6Kubbk1V9-oDUwIR^!(0o!3n=0xXdUv(Q!e_E( z%OJ@q>Z#IDi-8gcdlrhiXj)Vg?1LxRdIm{yUh<8SzW5YAbd#?VV`dvhjSpQ>z^T%d zXakN(+Q@Pql~GnPE_l+ZB`?$U+cwE)O#1 z@Yj6YzlxB4(eQ*fpLYdVKT^I|ocEK0vMOJ#4V}wf73X7Y-x_;*>DiQe^%Nhi5sU*R z=@ZM>t!b`rg~4#(clh@uyhtTT<}aho=2kbN!{)e4Ik*1xUzfdF7{17rXWkI&zY?&d z>|=KQMWQb<;OK9!u|2JK2F4D7oVfWTw3|1<3aEB4vpOaWy`taAH`eCI9iW(a(g#^o z84~-zES`-f&G|R0)UJ3Ie~95IwcyVS_%dlAKdBgb9hs((h!7l4*b@z$P(MCAXpr^9 z{1PYFYEPM*_y5Lg&JAb zdI3(tzrY{t-ds&c7b+TXq;SH2RQ!?OGC(Sijz)#Poxclf1Aj%^+3FZrix%t>Bu#%H zm$Ifz*su*M6a7^{6t3E-Ob20UvBoxWbB>N;PbLrlh^8V4~06NR?!5H5ZQnt+6E_QL}J7< zCWsT1N?#}6McL8jasVE@syZ3iUmqkRX^j(J-D|9Gc_YSPp6NH|{pW(<#r^w%tfebTp zs~m~*4(vb70T(LL+rQywhs{odaV7Xp!eZDYvJbAMOJ@b@V=%}Li^_BGZM4dJlr4r zrD*GVD)S{^-QDATzW|B(QU4qkb zdUGzVp++L_3yc97`fJB2;%3yjzqJ6`+~8Hyo~Kn75#{?r)4Y~`@vubGe6$D<*)I0L zDHiLIt%Bk^Qsic400+ba^BmhMK(~)vF(J~sFP(hO{8H!JIUJ@1_U(IW@xe`EEIyws z*xg%4W_xCTnbQx<_Pk>-(J@{S(~Pm7Id9gN@RG2iOgnMhy5oxBZT(%XlAl!BrDioC zIDVXJR=@HpVn(KPHPn#@rluR%C7)8NHGg>}5J(+r-xe>B7;M{lbm;xnx%^Pvi;hnIY?SrCfQWWVx@ zgZfwGYorixmk`FwG$M5Fcm(l}N)YB2jP>qJAaFzFhmIs?m{vh=Q3b(H4qn$Wim#E| ze}m;jG+358+8ki?BkpZKjXI_YTCQ$$FS{@b{@&#JEp0yR=2cRTrC%v_2KAd>y?qdu zm>6IUiqQYnFPd%4?!-@#@gxUfL0Yr+{vSr+47w&#zL3+dpj=(B+9?~JZ*DlQboj8$ zkj7q7&4@o(?&TQw!#)OBoGkqDFLgM+JrjAOXc4Z)0~C8=fwI-N*}ZXmyXyq7VC&p9 zB{w)<0)-`q)M_dzsNb@NbSTnO$IYU*&q^wv71ln;t(;uCj4vN_35?(sOjax&(5|_L zNPn&m+4A>Fic?kR-R-dkEmC6Ko5+0Ymq-0xS20FWtkKHQe=Pfl!QzuTJ+2MiH@lU1 zu=X7FS?_)|{T+mumsFDghB~}q5O25%(+m_N ziT08f#CpJ;%U~{<@c_#H!{F9vbFW}dn(F$BAWPww0?Qb3PG$|j1l_t3tL*?nU|I4?hC^KV16;w&k?+Lk&gD_Bvnyr7UB6Lo~|$kH4RFzF)rzcU`4z5r3C_%Dgq#Kz z)GBAiG|>3#=^;e`v!M(nbw@l<^RBgM{vD=ZR=@>?GhuAPU%SSt_azc-=}4nmj3DU* z{`Wdxc@c)E@?l@T?H9WkKO3<9FJ^E5x%-U`q7`x9OXC*NDZR=WXC_ zdZsa_24t@vTW-Lgs9e}I`Lozzq6Ce?;oX|A$?LB0JpWl^yeAGURN?_Tm8oS$`cjU3!_8M(R`d^HdM$?u)3nLx2 z=sk^9#k%ATdC?R!!5$Tf9{I%A_P)8)*dDd3USqyxUzK;3hn=u)80(T`ad|1gpr3xA zxf=%ik)StyX@HPDG2@TT6|}ORF6N&SNB?0g5_X_5Kcr@pl24-dC5Fyjy(Hh}&h<(r zEYeTEvZRgZ|EYz`?cv1*$Ohynaj)V^xCKbh_~5@O;sZ*(!r<&)d-CkcFShXST>_J_ zO9ts!u}P72Lp`yC+p&J%1rxhoJ&wd}jLSg15||G3%9&ggRIof`$)uNV^bbQSu7c?I zI(c-_3qRm?G}6JEN|3jdg1f=55FJ&lsr@Kz?3g==NyY9vBFP0Rz{FnqTMKh5L_)0Q zVyR7Yj*Bz%QWmkGjMO>KOSJyNAu1$tzZQMI&pOz$hH?(gT z58p_v-4Zq*+})iZvCl7!H43EhK8^n!j$7jJ9V^Qu&K>59Td298CqsdI%*g`xHJiu> z+Kd@|p1$l%hH6TpnzIlRX?7R8BL|I4Dzw?OEKF&hj~uM7B5hzU#ghJ1mYVF5a#=yO zYOj+Aj~|VABpP>mKuJgRm)A3okRV{iO3~)zInoU`y)<%R6B&Ru@vS-|!oL{~@Q*h1 z$e~>&d-WljUjZ61(5|^TdxS3Ucw_hA>?*|NO<8TVnCB*k)6#yQeK}@_(NTTF)H_5b z!-~Th74|A?kHA;BwAWDhY?tDp*qb%9m!H8$%KmXj8JwTS9&;}7I+ zR59!)Y4W_F4a%SI;Z-Br`Wj0&GMhvb%X{Km$f-)DVnd*trJndbwBu!Mj<-6d7%}}y z?69b5a8mfmxvo5Mct(Tn7cR->AY=G3$sZ6Y!Fm89WIK*jObN~_y`*mh7W*swdJ;+Y zhfXBNywfe@D3ia`n6_@Dr*`YWrQ{z5M!`jbDKsoV@9A&1whu!0Q@~=f`kl>KPtvZS z+IN2qN%T=%x=hbLC1k zD&#NTBw(ik^NE$NGCYqAnOQv*^lJT zh#mowN16FdSs|;(RHu1tW2M-7TgkZ4$@pcszyMm|7h20Nu>VGvs4d2Nvj841JL2cG zwpK4ccsM?+yjD<9OV2H!?YVhp@3#zp8~YkCMOgPz?5#YPT)fP#sm=W_GvD<>?2ewJ zRE35owOn-jrx+D~PJwnGAEb`-NNcXEzXh62iq=5U5fNhMm0 z&%F!#5ujnLk0e$4Q8j$I<<(qrL;KA##5KnHs z#Z8{be;9Ja;Ek;aput^7!^idRqqKh*xI3X^&eE*UC{n*nqSkj3a*=uIXO?iOG$&2! z6Thqtr}!>%_mb|dVDjQ-=_^?hFZLC?V6SGG3ltdW+UU#eDDWFy%}c`e!g>j-FHjMo z$*Gd(a!{uJ3D=E*+jote&C~mS1fk^1E`^Ee4Fo~!Ub5p`1{M3~`2$3B(n|)9IGLh; z!va##^e{YU7S-5@6wVY(nl0X?(PcH*lcs+dWgL)v0}pPCd?Qz(oq&sFx}@*v?Snq& zS+YfbU~vY@sGYi zs*|bll&jq|gZ_6U@$iw3bKy&fCox;?!&t9K2&LLF2w)*HGGJRag?)LYy>6;{HQ5u` zpVELgu~kfp5THs~sB?>HbKCb|JpjA^tQ?HWMQ0VoKkx677hrme67PK{RIaxBq}h+4 zj3HWD;Mcs142DSo+p4Y$s>4#; zXxz{Dp3{%;H0dAixt+XLyx(*E?y@v2_5QqyevoZlkgp9RXwhSN4rZOHoK9}b& zJnB0#A|mEoobnH2%iLZy50;9pL`U{5)yzX(y2|R*4R(MI6c#1`Mek5GV?)k`K97>< zC{=h+a$BJx4-@MwIa4m5M}|$dgUc^RFVxbTojExtg!;@2q^grmR#B-7w%_^1l#E|$ zv-QozDvR1)wazEEHs8R6Sd?U^+d1KsGsd)BIyhQa>VWnsFT7KS6_`f_jvQo!y8dkN}a#$c6&K93zA0vXK2Q2am zRU!K1s>$g5iII$0VX4}Wp%ia7)H1z$o^$9HhC3lv)iMG`zCE&$DI3H2$wxa4g>_4R zxL&T$nfvCv?-5-?xV)3X%Cb?#?{k!8GF0ct+&CoQVpAwurII8Id`PWmE<4r>>qtuD zO5>bS{fEIMU88NUbsAYPj4qO#lGj3C9i4EsZ16N1MJVG^kq&B*(yQ!h`f|&&skZl8 zF9N=Lb9Euk&#oZFLfl??Q(&BExT>}J%;u;)6aCdijci!*Y=ggcrd(Z5D&Nus< zvu4e#e==E{Z>@m_^P0VJOPKAry`0PnlBzm&ilv`4(gJPTTR%V@!(V~ zfBhI3W=Yg|;fvQ_fQO_i+f^yLdY+}TWrLXNYzv=$?q_;Hx1UyDT5=8TXsou zJ7!*=py<@I0sCWpLmzm(%mb#oGjtVi*Rcfdjxc?$Br(l}`Q3xP`N^v`TZ3{67owP! zNcF3OZyBkh#lHt84z(_E&}9!04-f(9G^u)M&sBr{REbFGN& zIS&~1lxfcKu~Da4;1^E3+T$Axqp_Mw#gOj7j-`PfV}H<=2dr9+A_j>*(X)E(Z5Ajm9)z zS^C^&uhfxm=1VKj7SXCS<53T{@5KH*&}CCWpr2>5!r>{FD5prHxU^J(`7F0meCMmy zojHvlHm{NXnfcz&>t?xJL2J}rn4$np z?~Uqh{s$|(?>&gFd@BsVZtCT}o`-raYFL52h+wk#2A`KWC&xy6yFN*S+D5-%_Gdec z-31$G)*DD_6*0J}nn}&aM_&?JFNa;=LKdnpzMz1t?hb{sh_CiJ-;ohbYd@O1Q-1xr zeW}*e`+%uNC%K-5*)YX+-F%!UA}+v4S3|oM#eX7w8Et0m113~r&Vm5!P|jjm?~=k> zb-9hNp$o4FECAwF>k=wO9c`oi(TWJw3J~LMcdvJ5c7N{rWf;E0 zxNP5FXr1Ev-qpYml}TK4H8fs^Ey*{J&vC{_jLkVDd3` zA=Nkye`r~Mx(QpODhG#<>YDS}OQMMKYzwB;VSv!N*)+7_)I8N>Ws`zwO!1PfXG->s z-E(y|napgqT{rqT)I&k{(6HjK`s>5#YMB&yK`FtSuH|lS%t++y{wUP7Do`zUFK$?T zfUehbhs5~cv|^yr^m_+iJ~(uZRYYeS2;#Jas!ysu?G|WM?~`V!A|Jp(yl?8`N`tn( zU^n;l_J-8hm*@E@pn|-0PsMAjyv)=uzQF`7)%KX@g#MuICx0D-+|DhP)KXw~H0>5= zF0)X*m7}Y<0EoNIcna=2z)j+^eJ3}o;=sr;jZ#&dc!}%cZuNsPoLkb~mLD(fvlG>G z1s`#ETUcnoBM_^_D($7cTCj4mAiFb%FIbAeUXxvL1bd!vlLBW8|E_;-b{t~h8rN#d zJ?+2z2OlrKMLPJ$V%fS`1IxhF1qke4%}o$e81`2vp5mZj^EY{W_uTfm4(1i<6a)Lj zY0&Hx99h;wTf%d5hu)AIKRfC6h6=CH6{Bb9tfJc8swoQ96WT9Y$d=heEqv_KK$ZJF zodgzOa=+4^0n4I`QXz2aWIK=WvmRnCLVKK7&*ToCgz&*i@eXsg%bJlCs}xFG1I6pt_daBNcIP~^ zr7s4FcA=peisP*>n*K7d@kRItyT?@}cTxWZI}gy7Be!uhicXy;9_)Yaz98AQR`GRu z!=_2*cj)p2Oy;Q;n=5xc-LIw#;dJARy6qS7ZE``KxR01~1RGI%ejUF-0v82SSy2P1 zt#4C#i-uo%>Fqvw9#m5Zu#G_l%t7{Byc{AmXQMQf0=Fe~j2A0A#t1C8`k5{r2ZAuiBrZGEp z!U?7+IcRD(o=u}5-?sG1PAa?9&p-A$_E&>_`KcFEU6=O+ zyyM$7cD_<-dB57=>Xu}hYsnoNkg<~kmn+c23%f(b8iL|4Qhh|R$lHeN3nY27I%j*g z7u3SqUC&4j-HZ%VObYCgdZxMnm%`*(OiEdXnmebg-Y0@FIZ>L9lsJ+8*KidW4^I6$ zNj9Y*ZN`O+rmn=>&MjeS7Aj8+^dAI5x6l2(`x7WHawm)FOH1={xf~u6O3C6rX80;} zy%S(jCCn@%X|e^GAFvDrbShl#i_0)K5|G7J6~7NeskVhit={0ybedkLDw2}lyle{bxm?)Trr;4tipEI}I%3}hqcW4ajTgeG1n!g~oXZ}M- zBt*bL5v9lya$`)V4s`s!yi)6--D&oz43XQ`@^uRz5w*2yC)zAt;|Mic2#m9+SBVda z`;q^Z*S(ILUN+-G9y(;rZeAIRf6{eS!Xc;gG>PW!IDa|x3Ce&gj%PE9hN zDKWC*k-o0RUFhWZQ%qGNMx-L za1fBEqIOdAmL9QA)KVtis9P%BKSZ08sWaaCtt2!Z84t`A2gLu&TUKjUuqOiqZg{R>~7dsN7zBcQ>jx1&LJaOlq$>xEU ze4ox)&-r-I90Z^m>@OlE9rqQqzZC*9B)yoA-7i=>eoztw`b0x@dG~rwdKO#o6*O(V zxz9vrZ1CSPXz?IWEliXe2tAPb^3guVO=pbf%3=9&1J4SVal5E*fWnx3b@KY~9HYqP zwttzp@m-+L0b&gg)^)L06If^Imq-NpEgH9MIIAzA!-uv=`BGRl9VZ#)9Xt%K3sC@d z#dd_F%0?|iapi2|4DJo&pc_?gjGZ%Fr4)~62k#eFG~1lOR-Z!0K|Tzm#Kpvn-cCuTygL@gpix`w zJhWny<2Emy+V`f%>bV&IxKLtPOQeOxXoY3+`Y0kAB)G)Zec%hSkZBZ4Mtn$!zvM)v zr98oqw=?;Nv_0PO`K&T5#zWM@Nu%+F*WL~fdH&a8BSBl_{^d)exH6qDz(2q}u(+yN z(ysYrlo5=jZ(Wkh%V}>obdaxNQS^r}Bm&jsh^p#>H$(C4)1DwG(-NEXxzFaD{b$WGogKNW{N9`u$&BQJHUS;NNz`p z$2dr%tv*HiKe6hf`yx1XxwssPr2+-}W^4RBHTW`Sz(G0?QRERih96o=m89hGnj(kh z0LxAU;GJ_Q&XjB{t(iu@!Iwvp02rfVB%0IMxPqpzQ~3H@ORdIXI?>8Fm>n`tAMo#R zszbDgmyGF>pGeb0&2#w@`DJPE!~{5K9KjyTz%ZV`XyN+(}cNe67%SyX-$NlpR+*)oySYt}l=%0=K<(1(*elM$I zCs+no%-3^u?Pu~$?JTjOXJ-+1;ydPb7S0CvP;WBx%J{hkNqrUdNT{8dL*PDb(qKx; z*?}J9>z}ZWaqn{#D%ssd9s4DU8=7Z!xl#a;CgGl@!Yj4n&TkQvtgAfjb@&Iifu5p8 z?{6}&tzZ(8+V@8OddV+@#f)1AD=ze^C}gEpC>_h4dh@i5PJ|?WvNwxyT_t5fhsYaD zxhH^5$?wPtZp`MyzZ;NP@taSyr${iUFFoeyDC+vXEVh3xmr}l5DabRNY}u8$y`RmN z%Ahg2bc{``AZ}xvSLB5GgSgekJX`ugb?C;5W`8u9k<9B>;<4C+UN%|AVF`|yjDdH`cRob58TFq|51tSFJ4)4di8i>Qu z;IjESUV&@`Ao}@z%zoacUpKF3jm&vY2>`g(Retvn;};wkobB4A_x5Hh0pn3c}BHmHpsP~e_6SG3$LFXZC`8q9jP48 z8LScg&D~(4U}?LNNHZPkePz3yU$FI_iPF1dUz8}eNZIipEa7b6rQEWc$94T5b)pEr zGH-|4{ICUyesL#Q$<*LUPZ569gloiqb!zf|d_V8Q2(X=~Kl{T_n~qJ7x&H3kg(Ben zLnFu1xj28$eO{farud(`V=v+`_nZUm3>CtE5ADaBpFqrC17ZCx{vKKGf3^J{j&jzm z*wF90D8n+l2P;~A+M7$SLJC`XBKS_Xc0Ty13#3z{XDq&VMAWgM$sB)_%&SqRX#>WBRCi`d`(8YqcJP?h7(23fk@e%S@2#~d84WTGOOjx3R1-P^s+ z@uUxFcU}WoG!aJV67y6rigbhtf|qw>v@$y#_K1Pq(!KB#GiA*>j{ zOtW$_?8eL^GEKgQ%}pikb>}ELA!TRpGr>CEMkj&>`rAEH($1XN249!X-Qtt>8K8+e zaMg~C)JTr?Kt;Lso{V42@UCu3Ji|uVIK6OoI6D~e1U%(G- znG|5ru7U`E3Z4JcGEf>fFgwIG{r74hthGS*mdhk>VijsyN4JXHcf8T1O85i_*aWZb z)bcNeUihhVJ|sARMXKEA91G*VVMqGB_YIxG$lVPMxOzxOA;z>#mRpN!D~Z?!w6c$v zzIQA$R6O#e%U~eCY?Uncz+NwXpXK_PagM3O;`v?div)nM_ToBf>%MuHEZih|WA2`s z7GqS6q3s86lpf~~c(d1QuC9ZV^ zF(Yl_izXMmlKBLXxsUrV9G@$%R2)K4aY7}HLz_xwt&S!&y?H3<>!SulL?B=W#9rdgROX4&{btmvZQlb^HlLh zzHZ&}hu4P+f1W)<$5lptI~eV=-14LLu#ZJK7p(po`5wLDqz4rdg|`~0FGlH_zi;+2 zW(1es&J4=Ep7xpj?DxxL6QCKH&c0$A9LG~%loX|?I+Fi+$UyrtY7MLSp!p)O8~|Je z)UGs^_G6u!sauwP{!F_f?=23x253ru-k(YVG2c=41-Vvo=><+m;% z-)!#(eSP9t8q85*l#^;?9A1E#mHNu)1dhCre!Va<_UR)U4m!sl->y;NfJNP zW_+w7IvIZ$tUMWU6XeOc$|w08$EjIYSK15Cb^#6(uyu;j9#*UtP z19I*BsGN@NOcFZbq6*h6l2EQ)iJAikNF!LI5L4>DO3BaDh=}94_m_R`a+QoeSgc}j zlXZ3(Lqq*62^-`!xl@9purVRm(r@2fx}uk;o}%k;TZkLutliqTeT6eJhDggaN_GUD za<`^i-Ne*^dLkImn{$QNoL4BVg*KcT|Aw_8&PIu2h`RUe?x$eWT5@0TA^s1}v|9{L z^H4jOG|A&|H0Cd1XabH{%wo+uLl$x%_LMN~mQ#8#SIxyFvgn<+uJ|_Re0QeerOa-2 z1Y-rA-pb+$G?^)!Dc}S@=rwR3`*-AgrT$8BWcaslFVBAZp7wKgzBIT++qz6(FMLb@ z6V+CYf1yx9&mr!~p>qrti)snKVjcu7q03C(am9I%2h@ zNk4llO##q^6lmvb?8CX8j;N`KXRsM!t@t9?;%VU@rk2U~RF!^^)@TVE6EfPvZ{8IS zr*YYW%mOQV?&f4=`$mp-r!!JaG*si|R)QJo3)?$N6@q;7{V%MhwU8kPDIX=sDteP59f#B`dtogfF+=XVLGe`w^L)`(l@OJcgI%L zSXHLBa<8+FY{+}qIc$WV10co=K0hYla@}LDSYmCdj_V&EzyyH6i9E=Pe=TzKa~3mV zi<{arHj5dE7N(4O+}&Xmk_%b5I+*?DfhtJGCp#NH%~jS3lP@^b>kR==^L`; z#maNxO*DzM?KQ^bilNeL7+KxyY3p`~59~V*B{c7y6FayHset<@^}?? zq6xGvSEld6!fV0sI!E0NrMR(%<@#IwcrE4&1Gl*x47z}p!jbSIenI8;#;q^LZ3tQ< zige5e`nsMyJRG{0Z3_z@OwRNSL5a8;>l%zo4t=<*uRp{|RZZnnc$gm^Il5DRgJTo+ z?9iz|(<3xvOAE*Je<>uNE}EkE#w@h273P28x}_%b)Qd4VMxK zlg{pN&TXUAC-p&P->b%ohnDL?^8HKy!CG$W;6GS*l@C0Zt6QLhvpP^e7-3ZDnr52fJsFH2mj4wwj$S}{ zye$7cfTE3755AUNk<8$|myE2a#$R;8*re!$xh{A|9yQl7RWj1lTytgcuM__gD}_!^ zpY$~LKSQZFpcVK$@8TfrB{yA>w`EUALPAArT^QQsm_MV8;01LPqd`y;x+n&sf7;Y-cb(f6&USAGqVc zEj;xP)_s;n5EBD;zE!pO#LCiXIYn?uuZwH`Wqtab6Qxv=Zg)t@zU7tka4B~%K92BC z>bO{mX`(s1HccXpJU4qtsuh{3a&h}NJ`npThV za!$9(g60OFuwt^YeAR&-QK(BDbCIsTL3?jeqdI43<*enxOS75rdsyOx@9=^S&lGe- zYgTVuWKsl%p$wc$2u*(KBh8$(#E^Jc7j(?G?w(vo_PfUDHnTTm&*^0ks`B;!l-9J9 z(TpsM=(#!V^hEvzA2L}Nt=NqtD8JC($ohqIyXM#RG96Q>1@y21+-$lOmz@C z(Ck9~y(eJHM(9r7X-qABJo|M5+Xl@Kt%{q@J}ln-_Y!@QsBHcO!QsYE(#8kohFfZe zP||_gclgO3QyPC)2yUe!^j6KO{=p&~a|fpKJD+v`?GQC$;y!Y_Y#Le_0|wsMK~3sh zxmImH5@WYE(Z~Hl*BqkOepc4IOk7aWmzCWg5OPuy-nHACZ4no1p>jv*+i;`o3trTo^? z&xUUAZ?yLI^(PS&`~ICF-IMl0hqlb;3N4D=M|GN)JO`qUo z)SU*=KE#vxT-HUW6|uB&0bnd~1XW3-pr07aHpwN^^mxlwq?P#0$bWX>`p&z8d$_0> zVWzv@$mQ5360oSQ?fY&ZZj@An++_wwMc#tyRVyE-J^4RaMkAxLg*ChDcN^mbI^~n` zO?{$bXR$WJeBrAO=*|g6Nn{5Dd(7A7NKVd22hmbxy^#&75&-5YDH7*;Ty__S(B|>- zJaueY93H_);TzkVmVB+c8W@>7y{z5J=8r36=FSs9riWYvGhuhj4#!#h_))ayv?Gxi zlQaJ_@o797jX{^!G+Cn=5wQ-&&XuIK&?0hFvpj&DS3LCBlU$&=8;4iU&>ZEZU+=R$ zvE4ibpuqfBpC(>W4?Gj}~97s0)5aSqs;NqwhX;Tl?vI70~*Vf}UtbSq}uAN=XC4g62A@mimZA#`f!l;E+5(3cl zs-n=T6Z|R7OZlkf#{Nv!oCSRVN@A8VcQ*j;SV^6D$=CcC+98c$SP&T3!NC?Q)5v1Q zkOnd71W@eR#Y;wuueLrHf_8SN=Mc%zlZKLehryN;(`Wq?cK^>?oc`DD5SX^>SC)lL z5<3PZZR+{OvO3W23rlurqg9zz3kxuh_;a(B>+%B8K(dLXTq7q-ok=>4zrpj4UnP>C z^AMe<#w$hXM%s=?7(pukbvHi);NZG~e%vvvuoRUVzT0LUBl$wvj>Y=HEp8yNirx6D zESUkS#_nZ_WvhT5E022<^FoC>CoRGxF9S0$nk`fXawynz0Ywp$sTHf00PjhRlR9%C zWpgoyU)}M4WsVF{D|C6MW%jsfSdayJ>^UA50Or5dM)q8D2oyl)(k{<%@85VKl0<2k zlRMkYXu?X}{qP2&T2*fg8i`VE-NF8yuud&UHtBj-+8CPiFJ0xzDale_5UJ5|faQn< zvq`}e%L>WH(!nN9$dJRvHytMD{qyO&X0j|d6su0RZhdlkxaDmy85$6C1VYx zjIk5%r1_roEYI!i>Nrwz7wRp4jX5*A>fScEiL&Qa=S+yROZ(I5nW5L!NS8z{X9inX zR*SDDqMhfK#svcRBTl*eH3|#uG>5dIzSJJj>Ro~hL(4%S(k(*{o1}>_>NufPuAtIu zv*WvCXM|9NA2acK^Hg&wQ}BCvFb;c029(28<-{_vQ7|#max#kCysmEdfktbFwnwl- z8trxj_A6l!b&E{**r=>!!$G-t6P3*cGB4=CprC7?5_8H)2CjMDo=bFGv?UJNm(Q>6 z(}W(TvXW?rw5{0BTpQ+={b=K}5~ECb*PuQoP+8*^+6WdcbCwA5b}T$BBSobH>n-sz z6U;Klc06jd6TgHq3N}KKU^YbQf2)tJrH}-q%tJn(f6> z`{t6IA+3`(l!qtR?3Da)lqFYdd7oVtf$P-UF{-nB5B>IXUA^zOtru6ZW0LyW9(-U-iO{CBEMT%r zX2M9|<}4c`EX4P?!6j0e(yYV= zufPgy(i4YMI0ov|yhWsC!1{{6?k?GD!;I7Q%{z^zA6`EiRcV)p|1!Yv9hB&=Lx$`_ zzhkerd;DR%_rD{tGG5TxkSGHKBvbO1-a_`i-eGq3dMwwylbz$<;FXN{%lOs_qbK$| zu7PNZ$n`hf@csniTbWS-o5$u8*uH`Nyj;8aN81Z}I?s4&c=rmi5S%>t58XiA)!o!t zsTiv6Wcge3SAMLWwr8$@!{^F(9LvLxwF6qyU>P0hq7^l4f z_2TmOO=cXV9#z+}#j>=4Fs?iK=uS|L;a!m2X^8ogsL~jVwo`_E4D&2d&;KH=&^TU& zE4Fg(cWFU7KPs!7yA`4Sk>&9 z^fa0rZQ%bXO}!3`qSG)mWg&vNGpBmw-MlS%0)*z9JeYO3wmF58V(nBd_!jo{w`Tyxf6pwTHNWrmYhV}EN8z`Pnro8YJuj|)Ik7T3vT ziW)>Oq%xs^^OHIySy4^ejsGPk?E ze|JGT=EBrQ!NsipJ612GcrJz&p3(*IPMEy@1e!iwCyeJy;LhS^47cox-O<8-ROZ|0 z$(xt#r(il5XfV|&A)UJ>fPoc>%KGB{`QS4cuKK1ZzG6EQePDcS<5l^C34siUPEo8QOnmN z<-d;wZnjd123#j-+>a%|2!hW1(>mR0$CMRafRxQ-CifIFD_mD^dzwvAsd~taIjj{Gc_kG$MhmGEPw| zvaaW3$46Hq_%_cpB)2y5wa`z{e)h5+hP%zY<3!yDhAP7n&ddT$Cuf#J2D;ey!Jf8@ zW3S?BfB%}~Iujp>g(&aM8QGxWg1mPXyItMeutIHn+E>pL@h*%LI<9?@@iPwt!POb} z=n|)(knOAH2crUmnK*B4ObNPm@q7h!)`*rDwEEpM#!<5+O?ht(Do%q;n2h(`duvWH zY{j~EUjBpSX;VMa+;3FIPZXm&$iGuF(;vG%UZhxDfhXE#9J;~qs>$LCVE^mXAcII3 zrY6!&6n`~<3~`zf-Fr`&jvvUXLD((Cc;LC(PQ3CE?9U;tY6oPM%(W}cKkx|M=dVgp(`al&?cMCT>nG?hADv(fQ3CP18vAFE zzqn{Ej*+6R&tpt1Xv1Ox_uqrnO-|nw{;p7;7?}l1(~j02r{-+;aI1xQI?mNOpUjdM zE*Mshc-cQa@Ef9n>AHdLC6=9B)9ZD*v>t{#GrB@;o9>cYiW<~-z4tJCQA@Y^%8j1c zyJm*BN3HMs#1YV(J*#&q@@4SSM*X*qo;pfyF@2kYdy~E}bmz>DzG6)xm4YCI3Tx&i z{(F)6(t@!6@U=Gor?oYZA16_aV7qwNy4B@Rj7cebih+*)7v-1AI;G;~EDcemThw$~ z8qFCeSKZj_6ZmhdGH9~m+` zbZZ!Fu}hm+YqJmIep;Hh;qwV1F)u8-`(6+iWn!;tn7)ECcJTSg7{EyW+C$EGK_g+J z7_5o(HL!b)enOlVqID2d8tLeacwd{Q{KGSTmeV7CizyiQutJ_+_t&gw2!!}PH|R;D z3NJC{y#lijYTe)QUC?ww?LMMKzK2V4s{Mm?@MDVZSmtR0jc}bWFjm@7LUZ2>;h&l{?(H7J#L`eJ=e;sC&&%fq|~k39)@DEiXKoSK8=@`C^jF9zD-X+0hCy z-EC3&yq~=&*LxC0hpvUc{&G(^@vl7Ai49#)P4soBF|k3GJovXYTGWMYfuWXIK4;*% zs9@S7RNasgciQoux6Q!9IX6+_=9!us*6(?$K1#*AF?G7mlSmMo8foV;7*LPQ6dR&#;+4bgYYWjL~vXhxC* z8cl~hDn+3WXH~T1ds-HbNS*{5m^`Il#tS&)iS#ZIK`d(6(mOV!uRKoS@T@ZRr7%|v z9!@Wq{`C}jFej1z<0U0nn85qbEbc&(5DxD}RZ6N85oIV<`Z$6C(o$jIN9^hvK~)Zx z646pL#HL;Bo_#HECKj-mB+F%-x4dQH^W_AWD|{%~Ol9K`VY z_l9<^4cJ<0CO%-K;QQ}L7`MRrH?}bj-|Uo6V9|OJ;(Eq|5Dz}pv*l@@#@;Yi>-KDh(r*1c=vpG1B&oRpt*qQ>0vYM1=EOSk^Jt(p~CN{I}EiaSv=fgL+H$ zr!@zU&=K=sQ3f@*U6kQ5Q!t$gEm!&bBSd-D^}@TUzsUk1P)~#FsB;DGvb9LO#DA=! zjT#x+Emg3wLmc^So}%h|m^Yw;NyAg+SJBpU5V!vdugU-Xt@?kvyO(^_{rfvwOLfss z-WC8Cg?7{kcIyb5PHyR5jUUEQ(&(~xDV|0<@ey-iHH-?g2z&eCn$5bOd*73!-kdu* z7(hUC4sx0?ZzE&%Sh)o=9l{TE9z8({B^2^C*hRgK(@c(3<8Q0)!Imr*{MCGjgdWuzT zU(u0WFSNgGUI(d`GFAsvVW_+xrt_7PcGHBBC78@#X%d-+<+J%Yzd3tmIZLI*bqx7s zs+3h}PD16onuzrW^fP4rsQFyKszi$95j+b&JhE)x!^@X-Y?JTIe3j*)B_W4@`B7GB zRHt+HDRc(oD|d90unsjpj@@p8+w%Mtnz%^UGgpVA=dTiC_trn`kZkoE4+>*qKU{us zkdli%#}P1W;sC}{mYaOr;46t} zK_pQCm}>ah-jwIDF1&&WGUCgx6_ryJ_H)(YTQkH@vP?C;;%OupDc*Hz9oqV-Ry?A3 z?HhT*e(|MH>CUYWBqVe))J3O!C0U797MW3l9lLuh#x*{Y~j=I8L; zwP&}s-AW%~)X|z0RtURv>?TLf2%j78Xv1((WSgAU`h#}fWhuN|iv$4LNS?d7n>kOi7;Ix*bJAZv$A?O)!`QIhsqn|-*Kw58SJSoz*K@jt_T6@~^Ie8c z30n2QQk-XNj#@G+6Y_2o3jZM(QkwYhq9JKf9aGsM{-=bo=3J+?!Glx=l>cCTYL&@% z*9Dep3HI|OO%X0vv#Ay-h0^0 zm`QtY(p@a=s_NAChGV`~k&{H%VK#=+lgTJLu2KUD4Xo+T5b$)2v?wLxD+qr(2>uW{ zN_*mV7=`Xeo0^h%K8&?Y#g*Qr~MHR!)f9dt328ah{9#VYBCi zCOZo9+sJQTNBoub%cVuqqrN)cxcpfB`tz&&2f!TaT(R-vmk{JpmYuw5 zguVkYf;8LUoz#;|5rPij1@7>GW%Ws&7D`qLiOlkH#g?_UFhLnM3B1$I-hZMNf`0i~ zl#oR8V~r8`0^nlEaEG|OkcGXeTGaO2;jcpF&IJkiY|ge+Q)O7~`KEYxR8;vf;A1BF zh6$ec{7#s)!FaysL=PhD&VpU0!=bkA6Y-VRDF5uibR0k&;uqcd*K4y_ff1Y1sC+WQL@V>k62Ut9AZpw`qu7*X`)rQ?~+Bb4I32L6dQFL%>R zzTf~S! z-XLA-6_X=W>32nh=fuT0(4b-4g>%M+YC8t|Uc;1!+{wSRu7aQw<7}ji+EP+J%<0x; ztjrv@1%*g6A-?Bt%&lI7zlNpP5!Ru2bRDNDb8cnHs?HyR8>O>Lg{cy zE1$R%b(KE*G#h|WXNk;bbu0V!EjP9>f<}${CHg&J#V_<1mx(RQ(($cu0u|NUse!PI zFf70gOuTvRfXh)7?p^&hZ^;7kY-wL|3wm+Epx{67;}U)}i(j;H_sKP=djJ! zig)_mm;BB@CeQ|0G3g5Why@Am(U+$Z{QE)FsOBRw(V?+PbZ*6L8 z0#Cf>ry7#WsmupLDo2r>Xhuxzpk61?~U2Mh*Di=n`m} zVe!Qe)_3gfApsF^1x7rVh+1Bhc?9TI7uI4=gxG=WCDnFbMYpP3&7?jP@tej!8S{AJ zA*BtjW=hUafl*G}^4cS-FfHhruRIWYIlIM=5WCaUZ?ofn$9=Q%O~2(##4?dOvgz5a z+4rl!`POt;xt^h_*mW>N-cgIxEs*M?sHd>2F=cqesZM(H9fTK&4 z2w`j}0n72B3{gjBh5v;%Sutpy9I6si{*X!z${(=r-Z2lrZUr z$zo%;kH91_`aK}k%o$XkYQtrvgkTyJRe^4$oC@E)0p1g5&kxv8x_rPg(1)Q)frEUc});EEfyW4wffX z#msRlQS5zNHQo*RPz(PAobW+jk(&i8-XR3?{dnc{7<1J@N1UiDoO^^asyuzdokqyc z*uSnCz0%gT0p#I$v#Wg);;)TB?zj3|T9iV)M}ms9V=Vz9hqt~DEnJ2IyUv1ftd_v} z=eAselwvyqGi*$zlOP*g8b(XX=!^a9^9BbKGecsnp}#G##loqa9->+MQ^gsmymF(u z)l*FaCr?+RyV$u}ONX)xR(S%$H=MbulhmLei;iOcf{EP+yE4sQ9jUpRhQf(lQQVKN zJK4|=%$fVTrS1vVU3*J@X<{vySZLbJ)I(uc z3Hx9)d)6&>;N8XELRr-V)@^a4VG@e66V~#fO0F;C?41k!Kf68+-{`*te0v&7`tRjc zlaSzW!qEEis=%-12BVn_T&8T^C>`~-JgZR)!VbIk!DjM9+mSjq|g$@3S@8h7>TKZ%6z*4Sf)Kbr1 zKi}_XuvLQ`ayjPaW)jb*W8!j3--`pX{$g3XN%~-)Ji_RX&B`ixL@MfU`gNbY~EHs&6fd2`xTUFY$$dG{KBwxXqT2Y)J~h;4sB#qmkca!MRl5qdj9a(3lY%B zyA;>56o!kBJ?9)H7yWJR4X`A?%-vEM|329OF&8|uKS`4+S7HEq>)GiDSJ_QCW)L~R zkAcKZuftdA_GQPid$h?AA34pHjbtJ6BPX&4v8BeHq&0qjC-C!Ib9!B33b16@(_f#) z<|@V(t11T+C^V)4e|t<)#OAV`llW(me+E`aCEtWKXZ>l|@NV4*L{&GSZzyNeAFUsCQ*!0>-=8aa6HEL~l$eux0LGqph^A@gz zN6Tf(fq|i!m;e@*Hx?Q1IX+fC{`>NO$BVacR5SjdlL`Oc)A#qAc(1yMa`!N{cg^R}Xo+%MyRm#N3@>UD zYTdkKbMxg#Apg^V(`Jw#emmv49cq9SdG=}69;j(&1}PB-;FnQMi~FbzppfA3_R zG_%VaY&eVVU@ebtOy)dQaF;gw?ZIH-{^s93skHr@2q(%vo~u&0>ttggitp31^Z4ot zr|TQtvUdP;uFgDOWjbzXlhz_qX{c-H$WPR8c|k=0vKqRYLvXZ;l|vg%Ke}(-N8gwBB}4=+s%r{^ zaknH`p}{7p;3yoP!I_uG6!CBK1blZ?Du@mrBI?MyQ^5oy*O61^5{Yq2V=aD?V&DBk zm{LF)cWng{jh$MKbQFZtdUsEtb}>4j%4JGjQ0;^_LUkWAM&453@Q=>F3u<<&(?3-kA}yGW=& zZZ&McM`i<^@~};7EG)kvGZ$<+<=u49yn&2*n7Snhh6P$D1n12;SYVOQ-1X0QV4~OS zyBlme2@8sPO)+A>EK5JAt%tnc$9k|+RaA`m#8w4cT-B`Nmi}DV;m*j6M4t@_H(!{Yj2obV+;GY>hJu6XN0W0 z96A}fI(0f*HZ|+xC8|a7Iw0lJpF-J{A`7N=JL%}ilCLHe2g~CH_uQ$)+xI-}qPXqb zPY`L!;Ecv0gK^LNy4I@B*?v~B3EAx)ppb$9oS|t@=3Q~hHlOeh4KYC77?_V4$f?bv zmT%}GGd7}CN_jvSDPQOMI&3aC%7KdBb1w|=V)hzc#6+IG@qBhp_zb`q9b`{0s+OnC zrH_<*JhpnTppT9qtf;$87ur106#7`_H+SLer%eH8cXB?c`vPs+N8NcC;IxM7Br8l73{<&Hx`7j_N>Aj9~~Z>Yamg+Lm-UaDerIm+`#hmf_}rR>2q-wepZ9VwGU;S zPbaCRIXR{klOAg$oBtbm?-|wPx9yE$1C=H!y#z(1Nv~3Zh=8;py*ESey$2K(L;@(i zw-7=L9YROC(jkNvdMEVW@#cT_`|f+r*?Zq{Kb?E-dDoX@tdTKNo;-7|Ip?pq_jqS* zlRkK#G?)gi{?)m+o#lyq8aBL7fHiMkfd=KfE};_y-#uSHx=WwL{EEHZH-25?3Do|w zTIgl&;={dKqGk48cyG-q+p))#N}}!fZ^qMS*PczR9tK6Rjb`6|oAtgGRiMP#;29RTh^C9Q(Lyqb+8DgLvY z=KrIt)qnRFKS0VQese~A1>0%nJ?ZtAxeai62VJH$rtSf)idh_jyEOu{ z+G@Y)&;{N5dU^(X+!Ddxcw*#|EP2{gm6+-jP%e>i4DHrEJeUSTYfVB&V4Z30)~`2( z%Zr*bYc8kXe3E4jRVrZ#VoDFImB0S{5In>3U`k406+*P%cu`sHA$sPoGmZT~{m_;iEZsYkz0#g?2n&Omd8R1BzBMo~O^Lt~mYB-KA zh#D?9+&1OU_?YQELs^UhW}?Ey*R^dpXse7g!e77>yKm?#POVixh_iSyjDMKdcXz<_ zjK2NlD zKHGIpNYIHirlJLnML@C9-whbz{U(pb5({rN18ppg`GLg3v-tZ{Q6-WcCvf zt4%xnC-^|U_lIC<2F2GVcC-8Nmjr!CX{8@$df`l$?yqi9`AXMWY%s=QgGeq1)1f}t z^6dl8-v+_ZsObG3-Rmln@LE)>S7CK=4d*_AGJXe>&-}STMtYDsMbuyM373K>ql;x7e(0&Y2rJapj3{*h_a~WiOVw6ua4~#Pm&dUuB1k} zL7s~^xO{|zQFWTAma720Et|~cV;Ci+yE@d8Gd+V^;ln!H%d82wD%s&g={PP(u7aew z=pbpEIl(KcuQBUO)(6W(14j!#9+W22hBpbfuTkfF%>*G7F+Bapt!aay1R)(9@HXn4 zgHkj3nw}dOb|i7^Ak`BTER2xQ|3l!_YFPv^=*X&U;en{8(5GpvAcWu!Cijakl3F{8pc%J z`ebO_H0K|A6!k1w8>Gi89Lha?`CzRdiQ zr#H>sDz(J?vMD3nM|!)w1NElD>~@A{1iB*5cC-GnhrOGj;AIF|S$F69p|0jJvNi^| ziv2wOb$Ew6p8n%@N(K9i?;aBJ=*{wW7|%ZX>a}5kphLh|`Bh304RmjCcz5#kR> z9T0hv?;B{HI8$Wv1dfUMz3qIRgcwA(F74D>h)SHXIQb!*Ep%|6Gx-b6g{fdwpLIbe zZispP(bm2;@b|OCRz~jqZL185uRG-rqqjedw>%?Nbg_vznxOnc;1+=(%{`e?&9NC2 zrvG?HHSJpF>J0f6??fS4W zW9aT1r?~ucmBg5Ou;bnD&w(~k0_oo(!M1CCZ&`oVquh7c-Q`?I^_Sans+rF}5=1V} z#>ysd#K7HW`dcTeQj8=N@b~|A_&DYYy@pa)P-mcYPHMvkIX|Inj4&PY75!(@`rSgS=mK-cz{c)*dIYiz?<=Ba*K z<8`36VNZ4JNcOE)%#6lcS!{2@f4ho+_)+`-rXrJ2yO`hcnFjxzx|sj?StJd&USeKS z$)fed^?$Ubj!_tqh|x8r+@?<46s9k*))AUn{peQPUHe-p{fddk^IUY-C*)>~>+T9| z?kiF9_eBtcDKh5AdE&ei@T0FJAx_#|_%WM& zOre&gNPrq2+bgJ&PUos+qK`~O`(dA?4!u!3wdDMOm+h^f@H(-_V#!d!XavtHVsdV6 zjxph3_oh2n1OwUPXFp%v2osxQ-fW(OHm9#IJDI@;2B!N$O$0#)=`3o|;RE)`%@eRe zbOKO1W@4Sc$P9c-R&U&1{sU>|Z6Cb!{*!ey3NN4Invi?|%;_hyPu9xoF_lYC4ov&N zg-U=Aq5T3%Sj9^9wc=lG;ZEy6ZA}}p*F7lguIZvmIx?IL8luKC9}*;YUPZ49y3X!z z!tAay5*lKh{d*8rmr|MjMK4zJIh3y-*<1FO5BI&LzESfv%93)gEm>p>)tK8`mq8pq z;?Fm_z!ipxyGx3$o!1oK3(t=pUgk_tk_ZGT08$tBmd*xTZ;VwE$?Dg9L2%&5VL3g^ zw#&_A(ts4g4eX=aA}kyIJ)|kcQT~q6g(e0HbydJMSlLTg%?a&_bwD8Jb0@rHj-_ z`+4%A;JOHeL%k{gf)n6E7?>R8eh9f?Hxz&moBwNI$SvcAc})Bd<8^z8ss@<)`{}Mz z-+p!U?6vWr#HEq|MDPO`P%(PaP+1z(T=!`fU+{9yhi8LNpBi;!4V?p`jrzjlz44+i zUJlDIL@shSUR28kvox1?{O-ILlsvJs#YHkH7cr{UCsKjxwwZF z#bPt2{Oa099_Y%L)D->l%`&-2h8?-HP2}*G=;%nx=6ZY*>Spr%CH2V=wXL?45*?bt zgF*ZXCTs{2j%8yqjGx9iO{UL-39UgICq#<>hCF(wjp)sdgsLQv z{kQ%3aj3FB1Y3n1ROsto11c^*Eo#EZXTV6WgLZf7Hga)CylUD%=L^x9=TYW$NP#(7 zmCod_6OEXTwMnR(Z{BFEw@<%BYh-4RM^*?ToctMxDU(GNN>i=v4-8ZOCUoAoZn)!q z+VDxBW#&@H6biO&PZ)G@$Z((a4AqGb;sWZ8w5_x_IFh1=4Uw&$Ve*r22y3$$U5=-h zoN|M6ls~PZ)J)6eWT?_fL zr%GJ0nvZ3ZT!J!%dKB`$TY*abZ!37#P|?dBJCJ?u3}#cM06z&Xy!~=3ba-6i)gGT2 zjyN50o@!KYn@8n`9-e;@Z6LazHVM=SQ{s=_up^>h zOJPo<}s)B1pkJ72z!O7v3RiDd1_q+x74Vec5@HNWiAAf-wU%%@u~I;Q*Z z6@+apWX;|mP2lhKoc@B&95%~#1x4JFE6Oz`FWAL8Zp#d+J-OGv?flw8lQNub%qD?8 zd%^7O89u>c6D$@CL3V2JG2!ja+Z*{OCvPMYo~-IX1SXsGS>&UqVec${K6}k-DN&0T zsV5KI3&91j#X1-2FIRo=s1((B;~<(wUiXqgW@vzgtDbMu-!bp3_P@~}?jKVaRpzSS z1(FX4@TeAi+1Jz1An`ut7I8y&s60wFC$Ar$G-MUg_I9*+c!uP4)PVGZx&uDE=%Qr#36^KM510s_f9y{X$VhoB$$kiK8mgWmNtd3?mO=TTs(*HwLf6LNjx6XY1D(X~XwUY1R2YhW^mL6p@u(kY)wzKSW{V>_7 z!S^nnrMySgQmJ@pn4vFvBjLGgmsHjx<8?lgR1d3}(-^fx<;lGnvlx&{#ikr;Ir-e_ z2g5){vpToLLg?eY#Kp$f6JRkL>2}!4c{<8alndNLq|d-!6KPl|De?12bW7jq(c>Fe zFhkgYeUlQXKLt7Zd;fTDaOs+KC`;#ZjC$pPTy_F#zA{-S z8m^j!v>7MJK6sc4=gO(WlMY8d8vrYMQ$GBjRgJ2yW*Ht7jobjUDd8gHUsG$HNKTjV zL_uC}Ns(A2<~g$1OvqyzIp@TGlBR$V`Vl_@EPGP`7LjdUVMhU3GM3`;W&CH`k2rHr zM)S~GuN+0}EWE}GR>eA+qq|26dGNu!BD&8n<58kGjK(-LcUP`x7PVj?Si&I%GF61V z)`+d!v-^uf_U1eDdDzGOWlc7nSQxEA+H&y+qgIKqDLhl|L@v6}p&ko?_*Cobs=XKF zVziEvTl(>?zLfdZ4deR{V`7pq`-d<6U8l#E^?B$ytv8Vng=*qnwFdbfug5T=#6If{ ztDuL*CNzT1+&=tGeM?SA_no-u5tH53>nD@sF5Yh}C35(y?9bVWsEsp^H8nZQtI}jS zNsbnjRdDoJT!gLmkx{e04>H;Va_WD5043W~L&Nnm$#{K=w1 z)YVVe99_JUzT~n>Lj(V113gyDKn_pUz@JC&P3HWwyJ&BK0UKza5W2~p$e?y!um@55 z0KTR|oTpn6K}K95gpaQ*CNYoUlmd)u$htu_HNGts<0e!b zQGgmQt)n>d*QngsD*9|}SswjaVW3QXn(5nGA)%CM=vh9iL&Ms4=ObI`(Qgt63plSl z{tC0lll~f;e!m=z2hqn1+0F82aB0IghIAUju~-=h@$O zq(E3cgVV|je4Cah4rd+0qK2PHQ5LkQgFu_k!9Tjv=-#=@2FCP!}++~vN^Qdcw;pQu9+Uv}l zlVj6?#8lZWo8%96$D+V_vLudXU~zx$UhAD25^fD|_jO{#YO{r-#()(^Aft+lt=*|9 zI?mJT)^G1d@nS$uXCb|~`ht{_^okP(EJ@RCf46nPHPLPLAw)GWEu{3lkX}`za`?fI z9R(7D?wNa3l~-6{`@YUQO1EYG?~y4RmM-!dM6HaC>{<&W)?r~k$1Iy8b{z1|H{MQI zII?EXOUHO^G4yvZUJ6k>IJ^a>Om=F+T2wsFPj^p!qJoJNy*v{y&05ezzj|u*@bXqV zHpu2y@*>f=eWhJaxuh&&Bw>M{ekf_1nnG)&o4?h95N+DDbGIYOK zjMX{ZdXk*`@rb9n75@E|P!VSWN5+u6xUyvnDsukV47Hx3J12?J%s=v@`Y5M+Jg1ct zjcz>dGZ4ZV0SbG2?xx)!=;kUk5jEuC8S3G$$>1MX5-tE1-a|Ta#!m?y^XJH?W4&oacg4k#P=ur_~+-Lb&@288du| zey({5m3k^^%~Exi z;;0EG+kd!vT~Bf?e_sdpu?^Lj3SV)i!iVOeOS>v#KcQ%nh0SK#&~`q7Ae-S<<4uA% zgw*pK|8mGJ-VR^i>u0VlEjq0$#$3szqX^A=;cdW`hZ7H_A~V1A$8u^U2oAkQGE6h+ zJBRRQi3=9;rD?}%B0mS{<_=CCMs=vp*&j+J$j9MxX4~q%wg84Z0i3B*8S_f!_H9Zq z!wF%jSj{G3UOU{rZr%BwEA673Nfx+tT<|s@YV4isX4K2PJ#I-9k7=>9{%>)A-t}H$ zz9b&Hbh@u$w-$UEr$9Nd4r{?$CPu69SI9I%MZ&3 zC62PWA8IeMcQs7FU&HkwQ{EjtD-f{yHMF5F0*DcDMH`d#fPAC0*98pTn9~<34m9N# zT@+GFrUi10AoZngb64~4%9R}Xsbn}&SXlM<>`$54{vqhm%wL{nvMOUa)Oj77Gty_L z4rj6zpDID{of4J}Tp?er+qzr0-}+KZ((wL3A87^G!!i}o|6Jt9&Kk!R2c^PKY&HV% z82994>dcb_al&Ht2`yYTjZt3nablmuw*a@CLOP_h=4tqM4@>IurYE_zwk+hKF77i5 z<~6gm1_vc{kdci3Db)Cmign98Wmzehsz>M$QgDfbbvd;Py=KBzhckQSicP zpxmN0F}6eVb?u}iug+o1m)_s2;gTa@EGBC6{N_l&?%(bd88@*vZ|DETB*Et-(nD78 zMR}25hD@7rrT0Za?l~%E-8c?O@6YcG^<%BOa4DQV4E)9qwVaDzk+7}n?qTKdf9Tw{ z>3^bbC8{Lwmd~kgAh27a8b)k8P3br_eWz)I`b8{HL}TI=#6Jc=UCUlg5sTMj-;OLE z1-fsRaqug}7PuQ8ofnJ-S~vGuCbsgQ{vnWVg*Vn;uuoOLTRB|t8Vj5^XP4JC<{5dv za^3_+4bfKP0eZ7b3C~Q;~F=I(n==m2~MNiI$v5hoG{?|bTWadp$ zCR-=Uwd%2~obl6mm%`O^WISO;yM$`ReO>lg?%3klQ<**R0Qfweie<*|rM#9U`*ky- z(T*hgjeK2=m!_sg@%FKws{vk^9l=-+$tbZPZFq_;+UgCr2iP(vU z>#Q3@_vH2<_jxPidv1K}{Mv3e5|tKqV!$&p43l1B8rs?nRpm9L)DK0dUDSC@6s-*k zpP*Nu;Frq%ATjy>@V5W>LH_@^Bh%#*lP1B_-L&y${1O!DU3xs^U}^4A>{*%Gtf;Z> zBkB2vfZ|G5b%WyR7DHIAN#!~T;N7y=H=1vbo zFA!Tlp!zyaT>YYEv;4`V-z!e;yx%`UvJ9zpyW7eJT*q&>5&y_fj9@=d&L6S3dd|Tg zC&*>8n3v0#0MlonM}5eUC!i*Fnz+Bn>}Qo=%wUXI1$l_3))Hl%*g z{35SV2rB3Qyk*j6R4(19=NZfpEJ<21lr`U%b)MYYn;Xx7|ulpFUN%`}`}_XKL;@jJhFG zTG!AGhYA5(?>JDYqgMnkxYC6UtL5g|@Y#KWE;hgm2bto=tKwOf*l+{qa1^^hT-pDI zIIuC`wc7tOF!+yvhrf0{bzQpMsEstDvq&a8OrT*Z8P?V|HQINkFR!W%Ffkh?ZZwU@ z6=o={!MsJsHdFMt(|)N>m(fuy?;ZMU(?>b=kaW((jOW=a=iD}S99C1dzyiC8pU@ma zSl<>hAp-$s;b59+=g^9-Yr>vn$iR@iYToNLEbpT8H`N=H=Q%-Np1r2XpV?~L*nhDt zI<4UO9q!@lHM_B-UxEPfXvF@2E9tuRtR8K>2_CQc3FuSsSXCPDT!;8y0hbws4nr=b z+wtlv(_zEcQzF=-u9LF|UPpu{Pek=O@ft=O*bVg7WvKzns2YSVQY+TOZJm{;$Q3t> zCx1jatu?|k_pW(y>fx+3-2%IZixZbu0oJ|DhGt7$r#sS_aJy;`dWD&b_4Q%Z1Y7LAJ^u~-UVe-Z1 zc0t1Fi)Ak33cX*FHK7HD3kLzd44oNmM}qN-pIIXk!4rK^P5=@q@*F^!G4=8#73|BM z&;R5y{o{rEpSeTMx93fy6X5_9ub6VF_BFdZgqGmmELx;#eEx~O8|S*^t9kHrmHrmk zteV&F*Rqmc>p_WUVjt~bRqQcQX=sE*cNx;NNcw&N#UFyN4GP|x;PtCno*w=eNR=?M z61{sLDF_~t4D1@+Ka_4anjSq(*_?D9UmSaBj;beW^hAZ$m=pkfas#0Lw}mf6avT`1 z3%WvvJ(H7w`kpN-l$RVhI^oMYJvHHS15SZV6lfp(#_v2p_D8H!z10cZuG%9#{<9hW z8rLkLb&*xK=VmM^$qRL^%P>Z~cf}wrP!>rdXpgB2={oV26tAQkyd zOhM>BCFDB}*I7g#Ja@wSdKZg z3`=!oU4WjJsHg##37e~mo&1ZUX%B=Bp8{_*(zJejsREeOVFh~9zrSvHg*5`>D%ngl z{Gi2Y@}VfIg2e;vI&aQFBM9f68TX)=!^Qyb5-P?}m_wLz-evGOJR!Ee-^yJVAse4z z!qax^L)-GmWdq9#A~(d|QDfkO>#Ka|&Im{FrFsqVudE1~Vh z%r`ui+D_!p+N2*PW3szFmJ&u>>|X(djo@}#SsF!11mle1SfHeEi5L)C4WoUU%L#i+ zr268f$O)Hxu{*|}lsClbqIb3D%xA_jdEo#G-qSCBUd=|KsjF46F0E$1Z$Q(nu_Kkn zskM&B4q^#eXL{~U!BW2}y^a=T{)!KM_p%8#gH`RAQw)L~cP_PtAhmM|Iu(VN(m%Bi z0(y1sLS`SJYq*D+Q@j+~d{RL1YVY#t{mM34W)$v|-TPbgBrf~Q@#0@Z(O(UocoDXS zWxO_-msCaWKKX$b2IBuaZkp`8%^e?Igu9REXLn8zC>DjISf^~;?{;u`S9YK1kSzWxOtZu7Ek*rT>==gcOHR;1!V zK4-wJscE#jYXb4>$c_2ef-Cs|=bh3)D>4KM&iZU!BNpyZx2HOj5qf^2-r}j(DIE$Z z0R$tRK8G7YLd&5kLNIzu_8!vnGVH|eI~2w{SAs)c3893wWS?I|jU9YAHrOH}xBz(4 z{N_A!ib|et5IsKkJHMJ~e{nUdk2U?R>=CU8mXUDStA&^ShS;sS}WA#5F!}9b)a&e)NQv;T?V~D%c9K65RlD1^| zIbVv4^)M9=kULwA`*}O_G4g`qiaRs-{}9yI0JOV$?V=O7MJL7le*;avR8?^pODlu` z0LoZNv0sGRvB3KL>Xb64J4n*6X4nH`B;9A2LQaB1#`hqcW_Y<@#skfv!_)aM4CyrU z_#$F}Y4%#oJcQ|L+MKxPav|sc;1Eqr(`)>K@L@5_;|mTATlc8nkKp&TV!=#PCaf4K zHN(6;Ua>R|0$Gm02eS!vb&@5%-+w7^GwG7!4LVGWLog{_<#mGIPfURB=AYJkoycOi zzm&;A7HL&0r`QL!OoU!I`^0fpfr)ru zW<=bbUO2uiWN%v<=kzfmc0j0>iF{D;<|j_zFy=}ZX!MJ-Gk$L2l3nzlqUzr(P(oOt zAdZn6eLB_k@PhO{k5K4>{{kJsrx^(r`zJB+&ir)zdmVcqdbaij_iwdLj>cW|I%UYm zS(#!mJ@m<5-i=skw1fT*P^&Bf&T(DYaVsXMb3I*GYJ?(Tdj2r7M)DN-B2~t)1*C!qVTrS5?N7WUrhB z&6u_ss0 zK|!9H8*T|HSj^GUH-|q2RB7%0?24SGyxtX8jl{{uxO%m=ads4p<}kx|f440t!NA~} z-qU+6b396s*6nn08+WZ`uR1ijoFP<=i$6ZP2&_KzyzYsJYGtdWG_>PKtaQzf2pLW* zKhAs2UyU!WE4mIqQij(wEYoroLsv_V@lq+^P{c7lIGG6%J2EA$dRV=Kf_pHS`JHpz z?g{6L0XF%WH}&h{jauFAFF)2<#zLDnDoBUy711Mx+JC8n$I^oZ6sM?#002s?5hV+s^cK0DPVAy%{eQiKC&rEVoy?Z3u3vd$4>iUF z-#XQ&?;R?`p23u=$VJJTW=hCID}rQMNaNqT_Dg$ZucA&a?0;*68pXVGHY|h~j|ekCm_Ljxn zrU84KZlT@H@^HFNyyF()rIOJA(xRL;01k|dkYouht6GOf=6WZga|UNwBgqOtqZiyo zAv*fWqo+W~vVGKk17lm2yEbc-@(X^b$X0zD;M4dz`mt?!8b67>tbrKaooyIB*#1m5 zxmT-qh0}^l*>`}!G7^~T+7+M?`FP}C{#pK2GX5WQGL{6l&s4vRm)L%Z2T?Bbg(y!{ z%vSccFm=0zPucjH%HfBP*zivmef$0fIfptD0J3w7BQh6G9ny<*iZSgZ0r|dTj68^` zBJDz$9*hmg&dQZINJTI^5PQ7y;R<>8x8{sQ+pFuly$B9AhNsW|d0vwk9#*uu<>qmN zDCsC6V!}$PJ67CpYJgs4a@B59zTXD=@z@3I%rB3Nzd4X z`Yn(4dI5x);`w9T&mEOwFR<@7c9{e$dd)*xWNavs6Y?Fpil0R$@?JC937?8f~%dkAzGo$_rhTP1yPB zE6vkTM6`=igvY#kb9erZr#1dYtgLk*`x5!vV?v675QdphZ*3nn# zP!iaR&&yrHlCQLc|%VB{WK+K27UOns1PK zS50uH23vCm$HVyu?BdR`!yb_!hMRszoLycm7n8-_z2Vnvx#C6fb5qM=22RsC-kEWL zHxHgA8%Z6stdBT!DxemzR1yYmn_TxdFOn-DTKI&&Vj-1!(*Ydv>xT0v*eag#I#*JA zyq#U{7BQUfY^{4~esKpSIc4S_(4>hWH zFJjM6cQ)zJnc^`MRwfmXvozz=-tL@VO3yN0D^9H6b`m~QDmc-3DFLJPGK{?5y5KvD zqZ1fKZS}Z}K3iEX;D{;((?K=fsz5!3zwN@gh4V|&oKxm-hxmVk8 z9E0E<^O?}p2~CXy+r~Bwx@9QK`eMXS$z!jJ!QbCyn`op$I*i_Y>(F`4*(HtjV{4^&eE<%&=OE1r)0NgR9&1F4-BQhRsGz6| zdI3}!?$mUw93TBSE^>1y7S7htV`(!OQMnjG<4+U!q#;k7A6!E%E|GTgMJL`DF#$X( z4nXuP#|a;O3Sprn&m;RTacA=|6(OULf}%bk>N$z^*>irR6ltOdPUzX80f(kVrSWFy z(EBk`78ac9|2M~n{J+6qe(J~DWyM=05-lfrJ?-^+(p>c-Sg-9AR8Ab+`~I*&3f|oa zO3v}+^O4=N+z!vG@4{mr3HdB6$NduVmR=PL1#>jBZtAMOofNf)C9;RR>;0*1=4rM? zh7jwJ_L>4qww@}L)k$}a{JB|!^1**H?PJ){KH63uD!L`s(fQ;L0U=Y0lkW;)TQuGZ z8~%ORU4N$~N*B>G4{=|(w#KLgQs1Tj@Y9Z%<7LYZ(McL`I=GzQe~T?t;7qz9L1+eY za6VP!XTjuOUru4`?gVeM97AUZOuhPHHqN9}pjlNb%f@k_T-LclTg)a@7|4_J5vC_( z17HP-O>Jmoff78S;h%5g*W=nd@9<_S+Ihk1_|9H%CUc7V9q?z$aL3q(m4SeQWUe1& z>|D#AUoZU>+{fJh97rhyP``>3&jSlcwlTK@?dA&34sSU4G2UqPPr|%bi`yH0-P<8K z;?If+pWagVg#Q`t{FNIj9|2u zmRH}1Wf|L?Etx;6=<*BC6>VSMI-FF_Cp<~|URjQZwu``a0$i8Qdn%Fx{HiyiP>^ey zmmw&7yqx;HvFa>)1hJ(9y!yI-pm^Z*d}4zCwwQWLnT{LO(%b5)F)b}{N@_Z-i8(xo znk~aJ9_#>H3>~u`t9_1}hPS!4mekEeN%~3nou4=2At-puuHl*+)z2aE^e$iC%Bye9 zuA+L7$_n!iKhE;Dp*9MQAhE?rfawcqldN{(kS+OrD(={va&4PdD2&HJ!n@5GT~XLo zK{-idP!k_wzOGZSx&^j2ufz|PIt3gp-8>72*4Ddd!8`+tfdh-q%Fe-Sn}KY)g4=UJ zIDe#HQeEH)99<*&F5e-)D;tYGYN9y}L>}MDF0Ju5h4QpZ+V4G>*vUqxyJ>76NyTUU zJQLSg7kt?1bBzy6PI+cFW`<5oY2s!(q^GcHyMDI>-;Mp`KvQmdn=TScU(&P9LJt^~ zu(jdkV_o?d;vpEq_V;ah;kzDE#As729=p--e!XViW&8Fygx6(6sJQw^^g7O%rx%cl z2N2MALu*Xst}_srHj?Q8{x(!He^()`IcB#FQgidM1)bZalFjF>?c|(4D+a0l38Og!>l_;aEXwoK+Awt?T9O~c-wudLmI`6VH8bOh%-W>~9mW$Iy zGJ*6tv?usc;(now?=o^6qP0kbpGPS1U-XWdmMzgng2Q^tJo#yGco*k9%OfWIK*FNX zWH^q~1Lgp(Cb3p|dOX0nKIP=mE2qN9MyIDlUZPWY^#V-ytS2&sT}f54(<_45DZxo1 zV8%4{NG_mb03PZbBflWzTDuqr60BV>KNCZ*B-p>rp83n}>3=QN2SgT>Rd-%(2kZPH zC})l_c-#*AOo_T)`-Y_JpZUe+Sof4T0?+cK1p9MjJ!`XUD#<3RXyYmImi0_GPL5vH zfa^?d*;fip!3i4 zpA(76gPimHOnZZ71PV-$%Ii@bvvT9VR|6)a1FWH^RN9=7LREOkm46p{d$+CY(5=`! zXTLjvDC|zj6vc$6Xh2LRDn9pQ9)lW#%@jhoV_a@EUyWFlf2lrPk;&dyKR6ycqn zq0-|{M&9EuluX?1KC=R9H{xj=Q5$0+0I5dqNTMfQiy1TlQu3npv+IDNdHeoGv94q_ z1%%5rJgL`EK2pqlk!N5PRRU>@=%>!&f8_PN&~WM_o4!Fse^;MhL&6O!(YnggHpZ)K z>8()Hr5STSY2GZPym)=+PMY*vgVPn9BF-(9I(HbA6Dfd2N3|_XX|xSz{+x8Qrp+i!zLC1ynA%EBL3jNn6&Qc1n`oju(b-Fvj1 zBI)$^Cp;D295bX-P6RX*j;t*lNP;`gy@}U_t6m&de~}c$b^)vy(|i^&pC-y1s^hhT zVPD#WvtqFT!Ko|V`mEPN`JJhzzfHIn98Ml?&_-xVaj!}S>iL-Ow!|=S%>?|bw$I=D zKmSvo+~Jan*7Q`y~($p;3G}CODbo#>{aeKH+ z>?;@KR~w{ZuY>r4i1;l8C)AXA^q{e7;5kKuIe)FI|-U)&IgCyP_s z_RqZU$RprI_q3pDy;W4nPzsUNaC<+!S64qI9?L@5o%|c{HOkqnAa;gYX93%^!**bG zdVNVQ=fj&gx8ESeAj|+>pVtSa3MC16Pn~;eFJR_*QlyGC^EC_?Lr$BXt3w9=(lZDm z{^a!{aR}y?XzrGTS(^|Ru#0%4xWzWUhIpU10$b(d9D-0|)r-xSWhy?ycyM38fA|n= z^YQ97-W|TG{43Y3_3dCsXL>J9%F{sJV}3s~{(wr%;;Ov294Rd!aUN%_?Y z)!W!V1RD1${me+!DV<(~ib7h+%L50D9mFfL^33);+4z3{A$Wh>IK22a$ZMaLFS2Gx%My-nGr_-{6l^92~I*Qv zq`3zRO{*nit(z|9kIu3Z4!wwoa0Pbn8LSrv?SE<(rsV^7G?f+SNTpd$hdYa@e zAw9{Q%}{Qu(Cr)i2L{8198x-_%D)HWM%L#;fGdV(wi9xVGzKNDnTg)>cX-aS?AWFs z%JmQ3N$!_R&qhj}CIqmFbW?z7s1gTk2id~u3~lys3<3F!SQ zLH#gu8d=i4E^4Gli86Y9^9fINE@#O}9AUDTjR_X?OMy#m^4j>!Y`-dX5ve4yLxSX4 zl4=s@nw?*3X)-42Z2#+|{a?5kti$!!ex38;Nmu-RfzLUFNN32~pM7E|>f~7^xAY4* zgrqsgbA2~nA%<^H_oq?rAloqDYQo|p`LM=6{>ymD&MIz9dHZ!4JB-IlK|%bt#&wPTQgAy!FpKzxIoLBJ#> z&&JZk#P!=vBX-Qq6fxdWwcnsIINHZlI5`3X+#&CqPcvTtdX74ygga`?Ww))UqOuc@ zzl*X=<;(L1A#5g$qUO6w&OZHboVKYeyiyCei@_F2 z5_)U&TC;lE29ZvFk~tv93gYwUY0&c=V?7kaDvla&B8_D#Et5ao^AlV7=<^KZ97Owt--+mq3U%M_{&R}ZwC7wDee z3rUe{e)$mFf>pN$y_a=i{6)a??PNm0o@a6@j zDyzb_6K(rh`)Md;9kDej0z$f@ZY{KoD>EFAs<2TM;vhD{A2X}`_8K0CHbjSewxAY&l7=Kzk#cw4F5j_xk=r?cX@^Y0so6?UrSM5 zs_T@6UzVot#qH^W?v6#siD(VRgy8V z>~V=y8MVuOfM5{qV(=?%TR5DFSUZR&Z&=(4Z?hJw9?hK05X^!@<6c2Ri?&`ti_5`OmfGeoxph253MM9 zeBlx0Cf^$5?W-9+;o`u;iQ)7ENMWAzA0AH_oXg)A+S(mp@4)~E#_hDl`;NGXq((~n zJw=T(eVJtloZb}d`I7Ob!hTc(#hM}`DV>vk{ND(o`!r@ez9A8c;sg(TPYh1cKMs+H zeB@5fk@V=ScY3WdPgl3jI68S1;Jf|qFZ(pN=eM@bBxMUP4F=9zLLxcqU3^#sL)w(} ztf#iUx8XF6+i7hRk{LqaCSa-&IE~Y3chbonX%o}g@RVALJnNFGzb^l9V{zgtExr-u zivhAl?Fzrv@NLu#E3X9_1fUP4W?>B?zx@QFF29gVKRhPHwCmWoL+vxgg#zN-Vpb>P zQON_!JFL}AP)046(xtz?$)|bgO4PfGJV}E-dB$y_{kdM|qnQb_5tIhOvrUOS#gpRu zzk9f0==%PRvxZux(tlGeO8C;pIp4?w1WVx?6R+W)x75WcVjM%dhT7NK$ga?J6(ml! zpxEqg4IPw0IG4yI)V|AB-X%7BbmX^_$4~&-T*0P8m+%Iky?KFohNG3t$)>i?y#0GY zXnmn$M&g@c=Tnr7NYw+76du8;qBH9u=Zc&mZ2ZQY*7TjQX)qXh%M8eL$z0NI_I2|n zb4EuY)UhD3WHG@@h6`eX^g!3V(I!RdVQz12k3GF7LiqU{@||{#IRb3#CC?8DJNDTl z@r+W$qtg~QW|NloRQtpq$y$l~cXqA8!WSh?b0ASK(V9`u{t%c_7by^vKY#l4FPZ+o zEmCr$8qr*SC(l7FC_}g()4aKKp>_o{=4IEv+vQZ>d^KA<_PuO&yFvCmG)^+a|82E zFmhrY=0}jqWh!|Nv+^k&NB!7RA?5J2hxE+uoZYm3amxRwHd(u{x~OE&m1lJu;ahfxH%~GpC{>iB4%7_q8jO(sif`NvVO;x6-I$vW8x(NwwEV0Z8_J6gNPMo%Gf;mgO~QKq44iJ60I=k3V<2 zq0SfuWiND4egm$Ew}AQEh^Ox((u-jreKsj>9(?r*>skBp+`tXLQYK@U`t|CgdBt(;whga@mFspWB{hi04c3{P&{xRdH7oa97A2`zR+e9k@}ke;_!1kU^_kK@qJ zr*qxwvR)|;N|X@p-#hI(vm8%V#?jN=f`HiGMtKsg_onfL^MW#9gbzjjc8+^|J5<@@ z384-^u;kU78R@QqSZmftc%04S13$H)6TXA;xGh`DWvZE!5#Kr`2&ar6 zj@ir?s&UrJFUKM*QYXy8JtpHUE)Wb^+}Lw^apt_^%h>i!vUHF1U*8-ZCncKqmTxCx z)e46FpWZ9WLI#7!AA=wNBuk=u%DFpq>UE{n0lDa(X}NvmJuo>UCvy2@>M0RmLB^Pe zr3Q1yDZZ;II#@MKX57bc%u`ZogXFo@sBdD>c9{wpu+E8D!fDa9TP%4cfl+~t6DU>V zKkGKn@8M3u$^asR*}ZGmbW{ROuKZxWh>HF+ca$}xOrsTLLbDas=t=Rv+cEe@{jRz7 z6&mrHfLFGb>U0}KW#^o@;RpjaXj(DDn4keuzN|)f4+EPr!CCY~L#D^b06Un;FD+PrNP~u}6IR>UK?E*o&+4 z?YJgsP)x9B?VPbt<*$-XdCPmLV|<5btB9v{<%uL5V;TyO zc0$q*^~`sy%+9@qy6V`?@Lt~8;}29orPb>ef|UMc0T-tGsFq}Ii3v+G-tKwpKHiBPp(pi^=cE z-gu+YGK^6C^cD=ZoPjH)v14gAFGG=gg!y=mM)F8uchTNnytE-N7lSKa^Yy=Y-6=A8 z7%xF;NFENhQ!j4qhDtn8X9sC5(<-2ddIF#Mct@>GK@{pf70huq_QS)$iVlzXw)-Tx zz-*(3s#cMH8UD8C41!p2)@-=uKBuz`MVv!EzEr%r&B|nGQZ@vXUMMGFd_flU$qO8k z`ODGH^DT1fJUr}w)1<=#(1HB6O(zu?W- z4rVHYq~~*b1JOcQpYC!|2S+cqhoW0gU}r_+Gg&`}@!plF9wI>6=@I5-BOAI+w{1Cg zW*v{GfRocX`aa7y*s}CdR?XsqGg$7p_*`P?lSe#_dZ@p)k6fJ(@JjSA}={RNE}# zun}3ql@L`mf4;={H{`-P&I}l81090c$~;29oDs?UdJ0U5W>h%Nk;70Cddn{yWFRGy?>Aqk_cbR^~(`o1@xIc7~i+urRr zMPTx}u+6{E_Ep<6AX7*)B`U?eUy8jpJVcL(|pA}gkO)_^ntH%Oq=mQ!@hHANF z1_Nbi)L|!3`86K7$s1XAPYaWUrL%8ksyKXQ+jA3P=e$vK;Upr?d=G`w-y}4IP!nXpug z)SW%`=nWKXTb!$t6hinm12o2mX^XDyg3be_<{|k9^bD7Khe&*uVvEJA4(+nIjXkHy-J*ErZqduebw4E3=&r+ zmE3iEZna+U<(B^p=MG*=txtRNYHP+>;CWx1?mL&3hR?O;VE!7o_vrd#J0p(2d-=G} zUcK`2J%%su{N5Xz)G3>;S!tG6 z1;Rh(uTS2@*4?J>!wls=hkjbIEf~$J8Ec6`Z4N zQ(o7uHGlRII*zsxW0kO@Z`}%|2>Fku>*N&zXWW^#UB2$cAq@@$uyg*MT*`60v@Lwf zrP}PGJDU2L-7(K6q!h96hN%4JpFC%q;Hl8H`=n3Ht@o3tj<;8S@d%bXITtbUuJi8J zsa*8dd0XGnNVaKNhVRX@zIDgXdYHdVtF7VLciTg&a`)_6a+PD^FAcNnQg@T8-`*7P zzQkew-O*y^7QR$pmbt&mU4njWc_R=~{>%TW;L%_O{v(zylhW5P{-_q}&|cS4K11%A z^#Z0F*IwTLJHh8n^FQ4QE*T|X<{z?O>8QI!etwDQ_WC20-+~;N+}7G;b?*Ov69BAI B%Deyo literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html index b6ec87fd2..11137c674 100644 --- a/docs/index.html +++ b/docs/index.html @@ -13,8 +13,9 @@ Friday Night Funkin' - + + @@ -22,13 +23,38 @@
- Friday Night Funkin + Friday Night Funkin
- -

Friday Night Funkin the video game

- +

Friday Night Funkin' - Rhythm game extraordinaire

+ + +
+
+ +
+
+ + +
+

Friday Night Funkin' is a dope ass rhythm game.

+

It is made by ninjamuffin99 (programmer), PhantomArcade (animator), evilsk8r (artist), + and Kawaisprite (musician) originally for Ludum Dare 47.

+
+ + + + +
\ No newline at end of file diff --git a/docs/styles.css b/docs/styles.css new file mode 100644 index 000000000..5ee1062fb --- /dev/null +++ b/docs/styles.css @@ -0,0 +1,97 @@ +.coolBox { + background: #1a1a1aCC; + margin: 40px 4vw; + padding: 25px; + font-size: 120%; + border-radius: 10px; +} + +#wrapper +{ + padding: 20px; + margin: auto; +} + +marquee { + margin: auto; + text-align: center; + display: inline-block; +} + +h1 { + text-align: center; +} + +body { + background-image: url('img/skin-funkin-cardbordtoast.jpg'); + background-repeat: no-repeat; + background-attachment: fixed; + background-size: cover; + color:white; + background-color: #000; + font-family: Arial, Helvetica, sans-serif; + +} + +a { color:inherit; + text-decoration: none;} + + +.hovertext a{ + color:white; + text-shadow: 0px 0px #00000077; + transition: color 1s, text-shadow 1s; +} + +.hovertext a:hover +{ + text-shadow: 2px 2px #00000077; + color: #ffb50e; +} + +.linktext { + text-align: center; + display:block; + font-size: 130%; + padding-bottom: 10px; +} + +.linktext a { + font-weight: bold; +} + +.linktext a:hover { + border-radius: 5px; +} + +#itch a:hover +{ + color: #fa5c5c; +} +#twitter a:hover +{ + color: #00acee; +} + + +#coolervidwrapper { + padding-left: min(12em, 75%); + padding-right: min(12em, 75%); + min-width: 30%; +} + +.videoWrapper { + position: relative; + padding-bottom: 56.25%; /* 16:9 */ + height: 0; + + max-block-size: 1400px; +} +.videoWrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + +} diff --git a/source/ChartingState.hx b/source/ChartingState.hx index 1dd6eb0b6..f83eae315 100644 --- a/source/ChartingState.hx +++ b/source/ChartingState.hx @@ -384,6 +384,8 @@ class ChartingState extends MusicBeatState override function update(elapsed:Float) { + curStep = recalculateSteps(); + Conductor.songPosition = FlxG.sound.music.time; _song.song = typingShit.text; @@ -391,7 +393,7 @@ class ChartingState extends MusicBeatState if (curBeat % 4 == 0) { - if (curStep > lengthBpmBullshit() * (curSection + 1)) + if (curStep > 16 * (curSection + 1)) { trace(curStep); trace((_song.notes[curSection].lengthInSteps) * (curSection + 1)); @@ -406,6 +408,9 @@ class ChartingState extends MusicBeatState } } + FlxG.watch.addQuick('daBeat', curBeat); + FlxG.watch.addQuick('daStep', curStep); + if (FlxG.mouse.justPressed) { if (FlxG.mouse.overlaps(curRenderedNotes)) @@ -517,6 +522,28 @@ class ChartingState extends MusicBeatState super.update(elapsed); } + function recalculateSteps():Int + { + var steps:Int = 0; + var timeShit:Float = 0; + + for (i in 0...curSection) + { + steps += 16; + + if (_song.notes[i].changeBPM) + timeShit += (((60 / _song.notes[i].bpm) * 1000) / 4) * 16; + else + timeShit += (((60 / _song.bpm) * 1000) / 4) * 16; + } + + steps += Math.floor((FlxG.sound.music.time - timeShit) / Conductor.stepCrochet); + curStep = steps; + updateBeat(); + + return curStep; + } + function changeSection(sec:Int = 0, ?updateMusic:Bool = true):Void { trace('changing section' + sec); @@ -699,7 +726,7 @@ class ChartingState extends MusicBeatState private function addNote():Void { - var noteStrum = getStrumTime(dummyArrow.y) + (curSection * (Conductor.stepCrochet * lengthBpmBullshit())); + var noteStrum = getStrumTime(dummyArrow.y) + (curSection * (Conductor.stepCrochet * 16)); var noteData = Math.floor(FlxG.mouse.x / GRID_SIZE); var noteSus = 0; diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 7b0dbbe8b..d92e1b4c0 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -24,14 +24,17 @@ class FreeplayState extends MusicBeatState var intendedScore:Int = 0; private var grpSongs:FlxTypedGroup; + private var curPlaying:Bool = false; override function create() { - if (FlxG.sound.music != null) - { - if (!FlxG.sound.music.playing) - FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); - } + /* + if (FlxG.sound.music != null) + { + if (!FlxG.sound.music.playing) + FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + } + */ var isDebug:Bool = false; @@ -118,6 +121,11 @@ class FreeplayState extends MusicBeatState { super.update(elapsed); + if (FlxG.sound.music.volume < 0.7) + { + FlxG.sound.music.volume += 0.5 * FlxG.elapsed; + } + lerpScore = Math.floor(FlxMath.lerp(lerpScore, intendedScore, 0.4)); if (Math.abs(lerpScore - intendedScore) <= 10) @@ -151,6 +159,7 @@ class FreeplayState extends MusicBeatState if (accepted) { var poop:String = Highscore.formatSong(songs[curSelected].toLowerCase(), curDifficulty); + trace(poop); PlayState.SONG = Song.loadFromJson(poop, songs[curSelected].toLowerCase()); @@ -192,6 +201,9 @@ class FreeplayState extends MusicBeatState NGio.logEvent('Fresh'); #end + // NGio.logEvent('Fresh'); + FlxG.sound.play('assets/sounds/scrollMenu' + TitleState.soundExt, 0.4); + curSelected += change; if (curSelected < 0) @@ -206,6 +218,8 @@ class FreeplayState extends MusicBeatState // lerpScore = 0; #end + FlxG.sound.playMusic('assets/music/' + songs[curSelected] + "_Inst" + TitleState.soundExt, 0); + var bullShit:Int = 0; for (item in grpSongs.members) diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index d92735e51..ecaa59d4b 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -113,7 +113,11 @@ class MainMenuState extends MusicBeatState { if (optionShit[curSelected] == 'donate') { + #if linux + Sys.command('/usr/bin/xdg-open', ["https://ninja-muffin24.itch.io/funkin", "&"]); + #else FlxG.openURL('https://ninja-muffin24.itch.io/funkin'); + #end } else { diff --git a/source/MusicBeatState.hx b/source/MusicBeatState.hx index 0d9da14a5..0d3862002 100644 --- a/source/MusicBeatState.hx +++ b/source/MusicBeatState.hx @@ -34,11 +34,17 @@ class MusicBeatState extends FlxUIState everyStep(); updateCurStep(); - curBeat = Math.floor(curStep / 4); + // Needs to be ROUNED, rather than ceil or floor + updateBeat(); super.update(elapsed); } + private function updateBeat():Void + { + curBeat = Math.round(curStep / 4); + } + /** * CHECKS EVERY FRAME */ @@ -64,6 +70,13 @@ class MusicBeatState extends FlxUIState totalSteps += 1; lastStep += Conductor.stepCrochet; + // If the song is at least 3 steps behind + if (Conductor.songPosition > lastStep + (Conductor.stepCrochet * 3)) + { + lastStep = Conductor.songPosition; + totalSteps = Math.ceil(lastStep / Conductor.stepCrochet); + } + if (totalSteps % 4 == 0) beatHit(); } diff --git a/source/PauseSubState.hx b/source/PauseSubState.hx index dbf232b6d..1c7297043 100644 --- a/source/PauseSubState.hx +++ b/source/PauseSubState.hx @@ -4,38 +4,124 @@ import Controls.Control; import flixel.FlxG; import flixel.FlxSprite; import flixel.FlxSubState; +import flixel.group.FlxGroup.FlxTypedGroup; import flixel.input.keyboard.FlxKey; +import flixel.system.FlxSound; import flixel.util.FlxColor; -class PauseSubState extends FlxSubState +class PauseSubState extends MusicBeatSubstate { + var grpMenuShit:FlxTypedGroup; + + var menuItems:Array = ['Resume', 'Restart Song', 'Exit to menu']; + var curSelected:Int = 0; + + var pauseMusic:FlxSound; + public function new(x:Float, y:Float) { super(); + + pauseMusic = new FlxSound().loadEmbedded('assets/music/breakfast' + TitleState.soundExt, true, true); + pauseMusic.volume = 0; + pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2))); + + FlxG.sound.list.add(pauseMusic); + var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK); bg.alpha = 0.6; bg.scrollFactor.set(); add(bg); - var bf:Boyfriend = new Boyfriend(x, y); - bf.scrollFactor.set(); - // add(bf); + grpMenuShit = new FlxTypedGroup(); + add(grpMenuShit); - bf.playAnim('firstDeath'); + for (i in 0...menuItems.length) + { + var songText:Alphabet = new Alphabet(0, (70 * i) + 30, menuItems[i], true, false); + songText.isMenuItem = true; + songText.targetY = i; + grpMenuShit.add(songText); + } - bg.cameras = [FlxG.cameras.list[1]]; + changeSelection(); + + cameras = [FlxG.cameras.list[1]]; } override function update(elapsed:Float) { + if (pauseMusic.volume < 0.5) + pauseMusic.volume += 0.01 * elapsed; + super.update(elapsed); + var upP = controls.UP_P; + var downP = controls.DOWN_P; + var accepted = controls.ACCEPT; + + if (upP) + { + changeSelection(-1); + } + if (downP) + { + changeSelection(1); + } + + if (accepted) + { + var daSelected:String = menuItems[curSelected]; + + switch (daSelected) + { + case "Resume": + close(); + case "Restart Song": + FlxG.resetState(); + case "Exit to menu": + FlxG.switchState(new MainMenuState()); + } + } + if (FlxG.keys.justPressed.J) { - PlayerSettings.player1.controls.replaceBinding(Control.LEFT, Keys, FlxKey.J, null); + // for reference later! + // PlayerSettings.player1.controls.replaceBinding(Control.LEFT, Keys, FlxKey.J, null); } + } - if (FlxG.keys.justPressed.ENTER) - close(); + override function destroy() + { + pauseMusic.destroy(); + + super.destroy(); + } + + function changeSelection(change:Int = 0):Void + { + curSelected += change; + + if (curSelected < 0) + curSelected = menuItems.length - 1; + if (curSelected >= menuItems.length) + curSelected = 0; + + var bullShit:Int = 0; + + for (item in grpMenuShit.members) + { + item.targetY = bullShit - curSelected; + bullShit++; + + item.alpha = 0.6; + // item.setGraphicSize(Std.int(item.width * 0.8)); + + if (item.targetY == 0) + { + item.alpha = 1; + // item.setGraphicSize(Std.int(item.width)); + } + } } } diff --git a/source/PlayState.hx b/source/PlayState.hx index 17ec105dc..6437c0f5a 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -83,6 +83,7 @@ class PlayState extends MusicBeatState var talking:Bool = true; var songScore:Int = 0; + var scoreTxt:FlxText; public static var campaignScore:Int = 0; @@ -252,6 +253,11 @@ class PlayState extends MusicBeatState // healthBar add(healthBar); + scoreTxt = new FlxText(healthBarBG.x + healthBarBG.width - 190, healthBarBG.y + 30, 0, "", 20); + scoreTxt.setFormat("assets/fonts/vcr.ttf", 16, FlxColor.WHITE, RIGHT); + scoreTxt.scrollFactor.set(); + add(scoreTxt); + healthHeads = new FlxSprite(); var headTex = FlxAtlasFrames.fromSparrow(AssetPaths.healthHeads__png, AssetPaths.healthHeads__xml); healthHeads.frames = headTex; @@ -277,6 +283,7 @@ class PlayState extends MusicBeatState healthBar.cameras = [camHUD]; healthBarBG.cameras = [camHUD]; healthHeads.cameras = [camHUD]; + scoreTxt.cameras = [camHUD]; doof.cameras = [camHUD]; // if (SONG.song == 'South') @@ -585,19 +592,18 @@ class PlayState extends MusicBeatState private var paused:Bool = false; var startedCountdown:Bool = false; + var canPause:Bool = true; override public function update(elapsed:Float) { super.update(elapsed); - //trace("FlxG.elapsed: " + FlxG.elapsed); trace("FlxG.sound.music.time: " + FlxG.sound.music.time); trace("Conductor.songPosition: " + Conductor.songPosition); - //trace("FlxG.sound.music.playing: " + FlxG.sound.music.playing); - //trace("SONG POS: " + Conductor.songPosition); - // FlxG.sound.music.pitch = 2; - if (FlxG.keys.justPressed.ENTER && startedCountdown) + scoreTxt.text = "Score:" + songScore; + + if (FlxG.keys.justPressed.ENTER && startedCountdown && canPause) { persistentUpdate = false; persistentDraw = true; @@ -846,6 +852,8 @@ class PlayState extends MusicBeatState function endSong():Void { + canPause = false; + #if !switch Highscore.saveScore(SONG.song, songScore, storyDifficulty); #end