From 3a9b17a57089a0a47ba04a0fcbec6516f1357f53 Mon Sep 17 00:00:00 2001 From: nick Date: Sun, 7 Feb 2021 15:53:51 +0900 Subject: [PATCH] initial commit --- .env | 4 + .gitignore | 6 + Procfile | 1 + Procfile.windows | 1 + README.md | 45 + api/__init__.py | 0 api/currently_playing.py | 161 + api/spotify.py | 58 + app.json | 22 + assets/logo.svg | 72175 ++++++++++++++++ firefox_extension/Youtube_Video_Title_Get.js | 185 + firefox_extension/background.js | 52 + firefox_extension/manifest.json | 44 + firefox_extension/utils.js | 91 + gettingstarted/settings.py | 119 + gettingstarted/static/humans.txt | 0 gettingstarted/urls.py | 22 + gettingstarted/wsgi.py | 16 + hello/__init__.py | 0 hello/migrations/0001_initial.py | 23 + hello/migrations/0002_add_songs.py | 37 + .../0003_history_has_timestamp_as_id.py | 27 + .../0004_song_pk_both_id_and_kind.py | 17 + hello/migrations/__init__.py | 0 hello/models.py | 26 + hello/static/Spotify_Icon_RGB_Green.png | Bin 0 -> 16410 bytes hello/static/lang-logo.png | Bin 0 -> 2217 bytes hello/static/logo_web.png | Bin 0 -> 98368 bytes hello/static/logo_web.svg | 117 + hello/static/yt_logo_rgb_dark.png | Bin 0 -> 7438 bytes hello/templates/base.html | 228 + hello/templates/index2.html | 555 + hello/tests.py | 19 + hello/verify.py | 45 + hello/views.py | 55 + manage.py | 10 + requirements.txt | 5 + runtime.txt | 1 + 38 files changed, 74167 insertions(+) create mode 100644 .env create mode 100644 .gitignore create mode 100644 Procfile create mode 100644 Procfile.windows create mode 100644 README.md create mode 100644 api/__init__.py create mode 100644 api/currently_playing.py create mode 100644 api/spotify.py create mode 100644 app.json create mode 100644 assets/logo.svg create mode 100644 firefox_extension/Youtube_Video_Title_Get.js create mode 100644 firefox_extension/background.js create mode 100644 firefox_extension/manifest.json create mode 100644 firefox_extension/utils.js create mode 100644 gettingstarted/settings.py create mode 100644 gettingstarted/static/humans.txt create mode 100644 gettingstarted/urls.py create mode 100644 gettingstarted/wsgi.py create mode 100644 hello/__init__.py create mode 100644 hello/migrations/0001_initial.py create mode 100644 hello/migrations/0002_add_songs.py create mode 100644 hello/migrations/0003_history_has_timestamp_as_id.py create mode 100644 hello/migrations/0004_song_pk_both_id_and_kind.py create mode 100644 hello/migrations/__init__.py create mode 100644 hello/models.py create mode 100644 hello/static/Spotify_Icon_RGB_Green.png create mode 100644 hello/static/lang-logo.png create mode 100644 hello/static/logo_web.png create mode 100644 hello/static/logo_web.svg create mode 100644 hello/static/yt_logo_rgb_dark.png create mode 100644 hello/templates/base.html create mode 100644 hello/templates/index2.html create mode 100644 hello/tests.py create mode 100644 hello/verify.py create mode 100644 hello/views.py create mode 100644 manage.py create mode 100644 requirements.txt create mode 100644 runtime.txt diff --git a/.env b/.env new file mode 100644 index 0000000..2e565b9 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +SPOTIPY_CLIENT_ID=clientid +SPOTIPY_CLIENT_SECRET=clientsecret +SPOTIPY_REDIRECT_URI=callback +RADIO_REFRESH_TOKEN=token \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9a9b42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +venv +*.pyc +staticfiles +.env +db.sqlite3 +getting-started/* \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..ad538ae --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn gettingstarted.wsgi --log-file - diff --git a/Procfile.windows b/Procfile.windows new file mode 100644 index 0000000..00832b6 --- /dev/null +++ b/Procfile.windows @@ -0,0 +1 @@ +web: python manage.py runserver 0.0.0.0:7000 diff --git a/README.md b/README.md new file mode 100644 index 0000000..786406a --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Python: Getting Started + +A barebones Django app, which can easily be deployed to Heroku. + +This application supports the [Getting Started with Python on Heroku](https://devcenter.heroku.com/articles/getting-started-with-python) article - check it out. + +## Running Locally + +Make sure you have Python 3.7 [installed locally](http://install.python-guide.org). To push to Heroku, you'll need to install the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli), as well as [Postgres](https://devcenter.heroku.com/articles/heroku-postgresql#local-setup). + +```sh +$ git clone https://github.com/heroku/python-getting-started.git +$ cd python-getting-started + +$ python3 -m venv getting-started +$ pip install -r requirements.txt + +$ createdb python_getting_started + +$ python manage.py migrate +$ python manage.py collectstatic + +$ heroku local +``` + +Your app should now be running on [localhost:5000](http://localhost:5000/). + +## Deploying to Heroku + +```sh +$ heroku create +$ git push heroku main + +$ heroku run python manage.py migrate +$ heroku open +``` +or + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) + +## Documentation + +For more information about using Python on Heroku, see these Dev Center articles: + +- [Python on Heroku](https://devcenter.heroku.com/categories/python) diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/api/currently_playing.py b/api/currently_playing.py new file mode 100644 index 0000000..89efc43 --- /dev/null +++ b/api/currently_playing.py @@ -0,0 +1,161 @@ +from datetime import datetime, timedelta +import time +import api.spotify as spotify +import hello.models +import json + +Currently_Playing = None +Kind = None +Progress_Ms = 0 +Duration_Ms = 0 +Is_Playing = False +PlayedAt = 0 # timestamp in ms + + +# Datetime of the last check of Spotify +Last_Spotify_Check = datetime.min +Check_Every = timedelta(seconds=10) + +# because history can be a bit finnicky, we add some extra checks before adding to history +# check most recent history song. If same as current song... +# check if (played_at + duration_ms) <= now +# if so, don't add. Because The old song couldn't finished playing, and its the same song, so just ignore it. +def check_add_history(song, timestamp, duration_ms): + h = hello.models.History.objects.order_by("-Timestamp").first() + if h is not None: + if h.Timestamp == timestamp: + print(f"Not adding {song.Id} to history because of a Timestamp conflict.") + return + if h.Song.Id == song.Id: + # most recent history item is the same as this one, so check the time info + td = timedelta(milliseconds=duration_ms) + if (h.Timestamp + td) >= datetime.now(): + print(f"Not adding {song.Id} to history because it didn't pass the history time-check") + return + h = hello.models.History.objects.create(Timestamp=timestamp, Song=song) + h.save() + return + + +# Tries to add the Spotify song to the database, and place it in the history table too +# Skips adding to history if the Played AT timestamp was already seen +def add_spotify_to_history(spot): + played = datetime.fromtimestamp(int(spot["timestamp"] / 1000)) + songId = spot["item"]["id"] + jdump = json.dumps(spot["item"]) + # first try to add the basic song info to the Songs table + msong = song_get_or_create(songId, "spotify", jdump) + # next, try to add it to the History table + check_add_history(msong, played, spot["item"]["duration_ms"]) + return + +def add_song(obj): + global Currently_Playing, Kind, Progress_Ms, Duration_Ms, PlayedAt, Is_Playing + if obj["kind"] == "youtube": + ytPlayed = int(obj["timestamp"]) + ytId = obj["item"]["id"] + ytPlaying = obj["is_playing"] + + oldId = Currently_Playing["item"]["id"] if Currently_Playing is not None else "" + + if Kind == "spotify" and not ytPlaying: + print("Tried to replace a spotify track with a youtube one, but youtube was paused. Skipping") + return + # only set PlayedAt if the song actually changed. + if oldId != ytId: + PlayedAt = ytPlayed + played = datetime.fromtimestamp(ytPlayed) + jdump = json.dumps(obj["item"]) + Is_Playing = ytPlaying + Kind = "youtube" + Duration_Ms = obj["item"]["duration_ms"] + Progress_Ms = obj["progress_ms"] + Currently_Playing = obj + msong = song_get_or_create(ytId, "youtube", jdump) + # only add to history if we actually play the video and its a different song + if ytPlaying and oldId != ytId: + check_add_history(msong, played, obj["item"]["duration_ms"]) + return + +def song_get_or_create(id, kind, jdata): + song = hello.models.Song.objects.filter(Id=id, Kind=kind).first() + if not song: + song = hello.models.Song.objects.create(Id=id, Kind=kind, JsonData=jdata) + return song + +def get_currently_playing() -> int: + global Currently_Playing, Kind, Progress_Ms, Duration_Ms, PlayedAt, Last_Spotify_Check, Is_Playing + now = datetime.now() + # Prioritize returning any currently playing Spotify song + if (Currently_Playing is None) or ((Last_Spotify_Check + Check_Every) <= now): + print("Spotify hasn't been checked recently...") + song_spot = spotify.get_currently_playing() + if song_spot is not None: + # only override the currently playing if the received song is playing. if it is paused, return currently playing + if Kind == "spotify" or song_spot["is_playing"]: + Is_Playing = song_spot["is_playing"] + add_spotify_to_history(song_spot) + print("Spotify was playing something. It has Priority.") + Currently_Playing = song_spot + Kind = "spotify" + Last_Spotify_Check = now + PlayedAt = int(song_spot["timestamp"] / 1000) # Spotify gives us something that Datetime cant work with + print("played at: " + datetime.fromtimestamp(PlayedAt).strftime("%I:%M:%S")) + Progress_Ms = song_spot["progress_ms"] + Duration_Ms = song_spot["item"]["duration_ms"] + return { + "song": song_spot, + "kind": "spotify" + } + elif not song_spot["is_playing"]: + print("Got a spotify song, but it wasn't playing. Returning currently playing instead.") + + # Next, check if our currently playing song is still valid (i.e., a youtube video) + if Currently_Playing is not None: + dtPlayedat = datetime.fromtimestamp(PlayedAt) + tdelta = timedelta(milliseconds=(Duration_Ms)) + expiry = dtPlayedat + tdelta + if expiry >= now: # we may come into the video halfway through, so subtract our progress + # song is still valid + print("Currently Playing is still valid") + cp = Currently_Playing + if Kind != "spotify": + if Is_Playing: + cp["progress_ms"] = cp["progress_ms"] + int((datetime.now() - datetime.fromtimestamp(PlayedAt)).total_seconds()) + return { + "song": cp, + "kind": Kind, + } + else: + if Progress_Ms < Duration_Ms and Is_Playing: + print("Song should be expired, but user seems to have gone backwards on it.") + return { + "song": Currently_Playing, + "kind": Kind, + } + else: + print("datetime playedat: " + dtPlayedat.strftime("%I:%M:%S")) + print("timedelta (dms - progms): " + str(timedelta(milliseconds=(Duration_Ms - Progress_Ms)))) + print("Time to expiry: " + expiry.strftime("%I:%M:%S")) + print("Currently playing song has expired") + + print("Radio NF is offline - nothing from youtube, currently_playing, or Spotify") + return None + +# NF TODO what is up with signing shit? + +def get_history(previous=50): + hist = [] + skip = 0 + if Currently_Playing is not None: + skip = 1 + for history in hello.models.History.objects.all().order_by("-Timestamp")[skip:previous]: # skip most recent + h = { + "timestamp": int(time.mktime(history.Timestamp.timetuple())), + "song": { + "kind": history.Song.Kind, + "item": json.loads(history.Song.JsonData) + } + } + hist.append(h) + return hist \ No newline at end of file diff --git a/api/spotify.py b/api/spotify.py new file mode 100644 index 0000000..ee7f209 --- /dev/null +++ b/api/spotify.py @@ -0,0 +1,58 @@ +import spotipy +from spotipy.oauth2 import SpotifyOAuth + +scope = "user-library-read user-read-playback-state user-read-currently-playing user-read-recently-played user-top-read user-read-playback-position" + +sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + +__default_image_icon = "https://community.spotify.com/t5/image/serverpage/image-id/55829iC2AD64ADB887E2A5/image-size/large?v=1.0&px=999" +def get_currently_playing(): + song = sp.current_user_playing_track() + if song is None: + print("User is not currently playing any tracks") + return None + else: + si = song["item"] + item = { + "id": si["id"], + "name": si["name"], + "is_local": si["is_local"], + "href": si["href"], + "preview_url": si["preview_url"], + "duration_ms": si["duration_ms"], + "album": si["album"], + "artists": si["artists"], + "main_image": __default_image_icon, + "main_link": None + } + + + d = { + "timestamp": song["timestamp"], + "progress_ms": song["progress_ms"], + "is_playing": song["is_playing"], + "item": item, + } + + if not si["is_local"]: + a = si["album"] + item["main_image"] = a["images"][0]["url"] + item["main_link"] = si["external_urls"]["spotify"] + item["album"] = { + "id": a["id"], + "images": a["images"], + "name": a["name"], + } + item["artists"] = [ + {"id": x["id"], "name": x["name"], "href":x["href"]} for x in si["artists"] + ] + else: + item["id"] = f"{item['name']}{str(item['duration_ms'])}" # default is local id + + return d + + +# results = sp.current_user_saved_tracks() +# for idx, item in enumerate(results['items']): +# track = item['track'] +# print(idx, track['artists'][0]['name'], " – ", track['name']) diff --git a/app.json b/app.json new file mode 100644 index 0000000..6a6a710 --- /dev/null +++ b/app.json @@ -0,0 +1,22 @@ +{ + "name": "Start on Heroku: Python", + "description": "A barebones Python app, which can easily be deployed to Heroku.", + "image": "heroku/python", + "repository": "https://github.com/heroku/python-getting-started", + "keywords": ["python", "django" ], + "addons": [ "heroku-postgresql" ], + "env": { + "SECRET_KEY": { + "description": "The secret key for the Django application.", + "generator": "secret" + } + }, + "environments": { + "test": { + "scripts": { + "test-setup": "python manage.py collectstatic --noinput", + "test": "python manage.py test" + } + } + } +} diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..2344c1e --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,72175 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + NF RADIO + + + + diff --git a/firefox_extension/Youtube_Video_Title_Get.js b/firefox_extension/Youtube_Video_Title_Get.js new file mode 100644 index 0000000..c8af43f --- /dev/null +++ b/firefox_extension/Youtube_Video_Title_Get.js @@ -0,0 +1,185 @@ + +(function() { + 'use strict'; + + console.log("AYYYY"); + + // /* user modifable items */ + let sendUrl = "http://127.0.0.1:8000/api/send_song"; + let signingKeyB64 = "zphbG1sXK5Ebndyq5ey+IdYfM1CAQSGUR0WCBI52EKL6EBCdNcTmBpn+NFYS6qXDIeEBh8sBFUiLPCpZjgzhVY94SQStRYHJ7Y8pGtzGUdJFZpSuPA0GL87VKWM4YhgncC4hBY8+gIOq6KWQMAAlvUZBWg6sdo0qmsBxCPr0J0w=" + + let cryptoKey = null; + const encoder = new TextEncoder(); + async function makeCryptoKey(b64Key) { + const arrBuff = Base64Binary.base64ToArrayBuffer(b64Key); + console.log(arrBuff); + cryptoKey = await crypto.subtle.importKey("raw", arrBuff, {"name": "HMAC", hash: "SHA-512"}, true, ["sign", "verify"]); + } + + let permission = false; + let mutObserver = null; + const videoIdRegex = new RegExp("v=([a-zA-Z0-9]*?)($|&)"); + + /** Send message to Background Script */ + let myPort = browser.runtime.connect({name:"port-from-cs"}); + + myPort.onMessage.addListener(function(m) { + if (typeof m === 'object' && m.hasOwnProperty("permission")) { + console.log(m); + permission = m.permission; + console.log("Got permission: " + permission); + if (permission) { + setInterval(() => { + console.log("Sending update to server..."); + reload(false); + send(); + }, 10 * 1000); + mutObserver = new MutationObserver(function(mutations) { + reload(true); + }).observe( + document.querySelector('title'), + { subtree: true, characterData: true, childList: true } + ); + } + } + else { + console.log("got wrong data:"); + console.log(m); + } + }); + + + // Your code here... + let title = document.title; + let vid = null; + let reloaded_at = 0; + let vidId = null; + let sendObj = null; + /** Keep track of if our last udpate was a Paused update. If we have two pauses in a row, we don't have to send data */ + let lastSendWasPlaying = true; + + function getVideoId() { + const matches = videoIdRegex.exec(window.location); + if (matches.length > 1) { + return matches[1]; + } + return null; + } + + function getSendObj() { + vidId = getVideoId(); + let sendObj = { + data: { + item: { + id: vidId, + name: document.title, + main_link: window.location.toString(), + main_image: vidId ? `https://img.youtube.com/vi/${vidId}/0.jpg` : "", + duration_ms: Math.ceil(vid.duration*1000), /* duration is in ms to match with Spotify's `duration_ms` field */ + album: null, + artists: null, + is_local: false, + preview_url: false, + href: window.location.toString(), + }, + kind: "youtube", + timestamp: reloaded_at, + is_playing: isPlaying(), + progress_ms: Math.ceil(vid.currentTime * 1000), /* ms to match with Spotify's `progress_ms` */ + }, + signature: "", + }; + return sendObj; + } + + function reload(refresh_time) { + if (refresh_time) { + reloaded_at = Math.ceil(Date.now() / 1000); + } + const vids = document.getElementsByTagName("video"); + vid = null; + if (vids && vids.length > 0) { + vid = vids[0]; + } + + vidId = getVideoId(); + sendObj = getSendObj(); + + console.log("Is playing?: " + sendObj.data.is_playing); + + if (vid) { + vid.onplay = onPlay; + vid.onpause = onPause; + vid.onended = onEnd; + send(); + } + } + + function onPlay() { + sendObj.data.isPlaying = true; + console.log("ON PLAYING"); + send(); + } + + function onPause() { + sendObj.data.isPlaying = false; + console.log("ON PAUSING"); + send(); + } + + function onEnd() { + sendObj.data.isPlaying = false; + console.log("ON END"); + send(); + } + + function isPlaying() { + if (vid && vid.readyState >= vid.HAVE_FUTURE_DATA) { + return !vid.paused; + } + return false; + } + + async function send() { + if (permission) { + if (!lastSendWasPlaying && !sendObj.data.is_playing) { + /* don't send data if this send is paused, and last send was paused */ + console.log("skipping sending data because last one and this one were paused"); + return; + } + lastSendWasPlaying = sendObj.data.isPlaying; + + const signature_object = await crypto.subtle.sign("HMAC", cryptoKey, encoder.encode(sendObj.data)); + console.log(signature_object); + sendObj.signature = await Base64Binary.arrayBufferToBase64(signature_object); + console.log(sendObj); + const response = await fetch(sendUrl, { + method: 'POST', + mode: 'no-cors', // no-cors, *cors, same-origin + cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached + credentials: 'omit', // include, *same-origin, omit + headers: { + 'Content-Type': 'application/json' + }, + redirect: 'follow', // manual, *follow, error + referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url + body: JSON.stringify(sendObj) // body data type must match "Content-Type" header + }); + console.log(response); + } + } + + + async function main() { + reload(true); + console.log("making crypto key"); + await makeCryptoKey(signingKeyB64); /* needed for signing our requests */ + /* post the message, all other functions flow from the receive message function */ + console.log("checking tab permission"); + myPort.postMessage({function: "checkPermission"}); + } + + main(); + + +})(); diff --git a/firefox_extension/background.js b/firefox_extension/background.js new file mode 100644 index 0000000..d1d946f --- /dev/null +++ b/firefox_extension/background.js @@ -0,0 +1,52 @@ +console.log("background init"); +/** user modifable items */ +const ContainerTabName = "Music Youtube2"; +const ContainerId = "firefox-container-6"; +let portFromCS; + + +function connected(p) { + portFromCS = p; + portFromCS.onMessage.addListener(async function(m) { + console.log(m); + if (typeof m === 'object' && m.function === "checkPermission") { + const tab = (await browser.tabs.query({currentWindow: true, active: true}))[0]; + const cookieStoreId = tab.cookieStoreId; + console.log("getting for cookiestoreid of " + cookieStoreId); + const permission = await checkPermission(cookieStoreId); + console.log("got permission? " + permission); + portFromCS.postMessage({"permission": permission}); + } else { + portFromCS.postMessage({greeting: "In background script, received message from content script:" + m}); + } + }); +} + +async function checkPermission(cookieId) { + try{ + const identities = await browser.contextualIdentities.query({name: ContainerTabName}); + if(!identities || identities.length === 0) { + console.error(`No identity could be found by the name ${ContainerTabName}`); + return false; + } + const identity = identities[0]; + console.log("found identity."); + console.log(identity.cookieStoreId); + return cookieId === identity.cookieStoreId; /* given id vs white-listed identity id */ + } + catch (err) { + console.error("Failed to check container permission:") + console.log(err); + return false; + } +} + +console.log("functions generated"); + +browser.runtime.onConnect.addListener(connected); +console.log("browser runtime connection added"); + + + + + diff --git a/firefox_extension/manifest.json b/firefox_extension/manifest.json new file mode 100644 index 0000000..81e5b65 --- /dev/null +++ b/firefox_extension/manifest.json @@ -0,0 +1,44 @@ +{ + "manifest_version": 2, + "name": "Youtube Video Title Get", + "description": "try to take over the world!", + "version": "0.1", + "permissions": [ + "", + "activeTab", + "cookies", + "contextMenus", + "contextualIdentities", + "history", + "idle", + "management", + "storage", + "tabs", + "webRequestBlocking", + "webRequest" + ], + "applications": { + "gecko": { + "id": "radio_youtube@tampermonkey.net" + } + }, + "background": { + "scripts": [ + "background.js" + ] + }, + "content_scripts": [ + { + "js": [ + "utils.js", + "Youtube_Video_Title_Get.js" + ], + "run_at": "document_end", + "matches": [ + "https://www.youtube.com/watch?v=*" + ], + "all_frames": true, + "match_about_blank": true + } + ] +} \ No newline at end of file diff --git a/firefox_extension/utils.js b/firefox_extension/utils.js new file mode 100644 index 0000000..0385073 --- /dev/null +++ b/firefox_extension/utils.js @@ -0,0 +1,91 @@ +var NCrypto = { + /** returns a CryptoKey */ + newHmac: async function() { + return await crypto.subtle.generateKey({name: "HMAC", hash: {name: "SHA-512"}}, true, ["sign", "verify"]); + }, + + +} +var Base64Binary = { + _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + + arrayBufferToBase64: function(input) { + const p = new Promise((resolve, reject) => { + const blob = new Blob([input]) + const reader = new FileReader(); + reader.onload = function(event){ + var base64 = event.target.result + base64 = base64.split("data:application/octet-stream;base64,")[1] + resolve(base64); + }; + reader.readAsDataURL(blob); + }); + return p; + }, + + base64ToArrayBuffer: function(base64) { + var binary_string = window.atob(base64); + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes.buffer; + }, + + // /* will return a Uint8Array type */ + // decodeArrayBuffer: function(input) { + // var bytes = (input.length/4) * 3; + // var ab = new ArrayBuffer(bytes); + // this.decode(input, ab); + + // return ab; + // }, + + removePaddingChars: function(input){ + var lkey = this._keyStr.indexOf(input.charAt(input.length - 1)); + if(lkey == 64){ + return input.substring(0,input.length - 1); + } + return input; + }, + + decode: function (input, arrayBuffer) { + //get last chars to see if are valid + input = this.removePaddingChars(input); + input = this.removePaddingChars(input); + + var bytes = parseInt((input.length / 4) * 3, 10); + + var uarray; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + var j = 0; + + if (arrayBuffer) + uarray = new Uint8Array(arrayBuffer); + else + uarray = new Uint8Array(bytes); + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + for (i=0; i> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + uarray[i] = chr1; + if (enc3 != 64) uarray[i+1] = chr2; + if (enc4 != 64) uarray[i+2] = chr3; + } + + return uarray; + } +} \ No newline at end of file diff --git a/gettingstarted/settings.py b/gettingstarted/settings.py new file mode 100644 index 0000000..0fee2f3 --- /dev/null +++ b/gettingstarted/settings.py @@ -0,0 +1,119 @@ +""" +Django settings for gettingstarted project. + +Generated by 'django-admin startproject' using Django 2.0. + +For more information on this file, see +https://docs.djangoproject.com/en/2.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.0/ref/settings/ +""" + +import os +import django_heroku + + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "CHANGE_ME!!!! (P.S. the SECRET_KEY environment variable will be used, if set, instead)." + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + # "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "hello", +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "gettingstarted.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.jinja2.Jinja2", + "DIRS": ["hello/templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ] + }, + } +] + +WSGI_APPLICATION = "gettingstarted.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/2.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE" : "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3") + } +} + +# Password validation +# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, + {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, + {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, + {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, +] + + +# Internationalization +# https://docs.djangoproject.com/en/2.0/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_L10N = True + +USE_TZ = False + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.0/howto/static-files/ + +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') +STATIC_URL = "/static/" + +django_heroku.settings(locals()) diff --git a/gettingstarted/static/humans.txt b/gettingstarted/static/humans.txt new file mode 100644 index 0000000..e69de29 diff --git a/gettingstarted/urls.py b/gettingstarted/urls.py new file mode 100644 index 0000000..4ee9536 --- /dev/null +++ b/gettingstarted/urls.py @@ -0,0 +1,22 @@ +from django.urls import path, include + +# from django.contrib import admin + +# admin.autodiscover() + +import hello.views + +# To add a new path, first import the app: +# import blog +# +# Then add the new path: +# path('blog/', blog.urls, name="blog") +# +# Learn more here: https://docs.djangoproject.com/en/2.1/topics/http/urls/ + +urlpatterns = [ + path("", hello.views.index, name="index"), + path("api/currently_playing", hello.views.currently_playing, name="currently_playing"), + path("api/get_history", hello.views.get_history, name="get_history"), + path("api/send_song", hello.views.send_song, name="send_song"), +] diff --git a/gettingstarted/wsgi.py b/gettingstarted/wsgi.py new file mode 100644 index 0000000..7e8b8cc --- /dev/null +++ b/gettingstarted/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for gettingstarted project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ +""" + +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings") + +from django.core.wsgi import get_wsgi_application + +application = get_wsgi_application() diff --git a/hello/__init__.py b/hello/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hello/migrations/0001_initial.py b/hello/migrations/0001_initial.py new file mode 100644 index 0000000..61eb641 --- /dev/null +++ b/hello/migrations/0001_initial.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.1 on 2016-01-27 21:54 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Greeting', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('when', models.DateTimeField(auto_now_add=True, verbose_name=b'date created')), + ], + ), + ] diff --git a/hello/migrations/0002_add_songs.py b/hello/migrations/0002_add_songs.py new file mode 100644 index 0000000..6b1523c --- /dev/null +++ b/hello/migrations/0002_add_songs.py @@ -0,0 +1,37 @@ +# Generated by Django 3.1.5 on 2021-02-03 09:17 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('hello', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='History', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('Timestamp', models.DateTimeField(verbose_name='timestamp')), + ], + ), + migrations.CreateModel( + name='Song', + fields=[ + ('Id', models.TextField(primary_key=True, serialize=False)), + ('Kind', models.TextField(verbose_name='kind')), + ('JsonData', models.TextField(verbose_name='jsondata')), + ], + ), + migrations.DeleteModel( + name='Greeting', + ), + migrations.AddField( + model_name='history', + name='Song', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hello.song'), + ), + ] diff --git a/hello/migrations/0003_history_has_timestamp_as_id.py b/hello/migrations/0003_history_has_timestamp_as_id.py new file mode 100644 index 0000000..eeb8c08 --- /dev/null +++ b/hello/migrations/0003_history_has_timestamp_as_id.py @@ -0,0 +1,27 @@ +# Generated by Django 3.1.5 on 2021-02-03 14:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hello', '0002_add_songs'), + ] + + operations = [ + migrations.RemoveField( + model_name='history', + name='id', + ), + migrations.AlterField( + model_name='history', + name='Timestamp', + field=models.DateTimeField(primary_key=True, serialize=False, verbose_name='timestamp'), + ), + migrations.AlterField( + model_name='song', + name='Id', + field=models.TextField(primary_key=True, serialize=False, verbose_name='Id'), + ), + ] diff --git a/hello/migrations/0004_song_pk_both_id_and_kind.py b/hello/migrations/0004_song_pk_both_id_and_kind.py new file mode 100644 index 0000000..e272d7e --- /dev/null +++ b/hello/migrations/0004_song_pk_both_id_and_kind.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.5 on 2021-02-06 23:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hello', '0003_history_has_timestamp_as_id'), + ] + + operations = [ + migrations.AddConstraint( + model_name='song', + constraint=models.UniqueConstraint(fields=('Id', 'Kind'), name='unique_kind_id'), + ), + ] diff --git a/hello/migrations/__init__.py b/hello/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hello/models.py b/hello/models.py new file mode 100644 index 0000000..5abaddf --- /dev/null +++ b/hello/models.py @@ -0,0 +1,26 @@ +from django.db import models + + +class Song(models.Model): + Id = models.TextField("Id", primary_key=True) + Kind = models.TextField("kind") + JsonData = models.TextField("jsondata") + + @classmethod + def createSong(self, song_id, json_data): + song = self.create(Id = song_id, jsonData = json_data) + return song + + class Meta: + constraints = [ + models.UniqueConstraint(fields=['Id', 'Kind'], name='unique_kind_id') + ] + +class History(models.Model): + Timestamp = models.DateTimeField("timestamp", primary_key=True) + Song = models.ForeignKey(Song, on_delete=models.CASCADE) + + @classmethod + def createHistory(self, timestamp, song): + h = self.create(Timestamp = timestamp, Song = song) + return h \ No newline at end of file diff --git a/hello/static/Spotify_Icon_RGB_Green.png b/hello/static/Spotify_Icon_RGB_Green.png new file mode 100644 index 0000000000000000000000000000000000000000..26410e2fe2ec1e88d81aad43aebdb40691e4db3b GIT binary patch literal 16410 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 L-Tx}otRwzE3yc;) literal 0 HcmV?d00001 diff --git a/hello/static/lang-logo.png b/hello/static/lang-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f04aff1e38eeaeadba93390eb5cd356388b8a9f7 GIT binary patch literal 2217 zcmaJ@c~}!?8V{ES5J5Ras&x#4Sjb5@5(!5xzz~)VpeP8&WPm)7Og4-ru!tat1eHTn zltSYHA_!`w93BV~D@C_zU8Rby1Vxl08WH5yPAJ%Y_HjEi-+bTu&ii}c-+TNq%8+1x zGZQ-#6bfY)7{KHqyHK~#^N_dn*`Y9GTMDxx;7}+Qmh)vG%1;Pw1%W^@KMv%9d|~oG zIzTTJ%D_n!76C_agQx;XjN|KUa0;;$L8DM!J_;#ckO0EKRxnN^p<&)$ZovQ|Aq}&^ zjZ5H48DP99AVmg-rUZuxQW69dA;!lW@KR6_2VxNB0}64XB#Ek^VP^bNk+V*X#{e@X zZ~_hU2dM~d2*7}3AmD~`#|j8UGT=eM5#8K9C>|~V36b#xPdtf$B~Yktu2cdEn7uGa zG?_4#%44!;V<8d^6A!~uDjqMF%W-m793+dw6Dbr5oq!3gUTS60}VwK>87DKLmkb!&{l7&G~ z;#~Ja;vpDHiie~CgE7-Bz=_Kjh$K4Y8eM^B`GPXhc2LNcL1JL0LR8TgSg;u+7K!EI z%JQQSXEGoW=nOW6@2aP|oS1Q;s&z#P{JJq*ux-`bs~p_~-7+ zYD!+5s{VEjH2F#WiNE5*bmM5(KqPXLZ^hPSoB02X&hmBAUulu+i_XGW=pRQ!#gfm* z*)PnO7uCx(dwTXw589+YDDm~GGV?M_`})m%A0wZI@=NXRjXkbfQIn1L0w{Cms)F9? z?C#8%-OkGg-=n9zuYBj5>zv#7@T(0y{kG1Uj)olj0yfz=dQ_hhdra?KGa>CYUyAPdqmBD`~BUt_i4qwX765iYW=nKiAU_9J9Q0(BfV3V zV^?FYb{F8ZquO*UtG$cOu@`FRbI6?+HmSQS4B1ht)@C>T@rTUjG*PItqQM=w_mW2W zv8OGfsm>9w6c<+bHClECx5w)bT{uzMj9ZVzvrqnDm^~C5;Lqb25#AheDhs$hl3Muq z=0v_o!KgmeY9Zc*zlL|HxhMYxB|Ns+c4&KQ{M&2yvnFk8^a3CUU+?tMHt1joO&(o4 zx~NKSy6n12d)d7!ZC-R#+tq3^s=v3N-C2CTR_OFymPeba%ltyG=}rS5t9$B~203TE zqAn`WXtrsC$MF7>huqf$hL`mK>#OghuCuPbj{T~CMcu6f=SH#upZ+Uar0U~qouzC2 zf9+x$6!28NFZv{Pw<5LVroXjzpVVX=yr-;tN-sD)&QUNm)>$08^wQv_|G15DBVBeF znQsW$cJ_hAo@I!NKBhm_u-NuQ=2`ixlURs{b*E^Ectmrrg--%)^>abZ(@5_(; z+*?O$8wWUv=Q+j;mZ~3aW)wPP$ye2&he;{J_4#EJznMP@>76JR_I6} zcAeZD`|8mvQTNaXEQfLQ2(iCln3EXXG#I5Y&1h=LD>QDLb}2XQu~oMYA483|uU8wF zD;>2q{WZrn-xyo~ zjZbW-mOahOG~`9BUYE0aNR+F*l>MnFDAnDy!KEyyWe;pXFZJ|wv?|*8qHArJiuo?G zXF$8RPqO-mRd{C5eQOS|{}sjZMf~`>?F9|49b2BXZ|a<`y5ZfN;1!k$svfLtLywy& zIoS&W&K};E%B4;|W?6#tn-*F2D`RR-b;Ol7|F+Sx!oaQ;^COo9cC(uMOrLd!TcBBhA$<`#BgBvnSY=qCk>`Ij*84tM aZ$a%}dZnx*#!~kSf(m2>Gtbhu?D`$|L6nF9 literal 0 HcmV?d00001 diff --git a/hello/static/logo_web.png b/hello/static/logo_web.png new file mode 100644 index 0000000000000000000000000000000000000000..3cc03418739d66214207ea5a2ab2fe0da809bae8 GIT binary patch literal 98368 zcmeEud035Y`|fHWV@V~NQAmj>sWcc9O{4)$N}5P%kj7=Ekw{4s(yT#JN&^}YQW`ZX zG?z-LH0<+UE8h3}_TI;__y525JC0AX*7H2~eNE?iUf2Cx)6!5`IFDx@g+f`Vx@YGB z3T3Vdg~HS|XEuJrz2sN~{+MmLPh}@%n*1*+H})olB1BQ$x$U4!SWlzd^`LJaEI$NG z4g2mdDnEDi^nQuM``MQt=6Yl`u$c4Z0tU6-!gossevfA?O>MW39W@?L%IB=kImxJrR@q9!-sB zBZt2Il9F@m_;?S`ME|elh?r{jpTAJ3PZk$2{`uSM8T|M4hff&aI-2o*LY(WBMa z9_c0E!@b^r$-2Wk?`}SM->JL0JlQbEvL@N^)~(UZgR~ec+DQvM@7L*Nio7z7j@n5_ zGW%=};`-5I zKVC19Tf;>qH$FIZd|ZAw)0Q7MQ6K+CTamjMEqz?4PER&Z`@Oljy2LC%VF?Q>-|G*V zmgOso0|W)nG}x;=In_KR)|`o3q+ERL+}|`A^vp2F*}OgRgNNjFoke8Tw^9Yub%&qC zEqObBzgzdvp+k=SO$wcZw0q=jr|nwT$G*m#w!GhcKEM0(l}38%ZicTH6}=`n*`Xro z)K%H>Im0Hr@_;n`QG09CR`UKxh>Kg}@@Rej#OW}vsj*qpvb5_p>)wne`Hyq|``n{jZEN<0SqZ+LdXEII1AReeg|Io4>s2`%vks@A%x$tY1xTZGrnFRO22` zSk*l?C)Un(>^zXz9v>I?THvP3tA#R!^VdIL#LoWh+qbbb9OQCB{q*Z88+lC*XAM^$ zX$#Ubir?(@a_;KFGOwwjtdY+)5A55D=j!N%<;^*bJrK=y>b@Ob!$8aKYjo+Rv4Bzi za{98xzQ4cAeT9|(?T1X;MmgKOvF~fvt@FFR?#L?rqjFDdY9!>B&9!hoAcV#A;%+M9Dv1J9c-hM)=~S4TkvDP5%DR8DcN?()M6#BdzMhJHx4vg{b%H(pg-9e&Dx!otNlg^;TOzK%$Rf;s zw=bXUceA<_MY`0!yGJOdx++p?iAr$2AB=~rH`meWEXI&Qc= zTSS$ce6h&%#rawG-|tuyzrL|D@luNGa2HpA(v-_{_|{83r?_1{OUjcDrC+@omz3n| z@q0wXfSr7;K#v9|KDInE%9WGI>3N(r+UjFgI>;8gCguJ2OG6+F_` zw@iW--jtxh4COQqvawMwK0iO}V1TW&|7;aoQat%t|_H)6AY&SFL?9k6es;Ir(3ywek{{Sfn&Pq*S8t ztAT^qEu$nktJOPX^U1?ur{9Xs)hVfY)^dJ+>$hOzhV#F?6rYD9t68uBq z5#M?9WA5KyvH4UJ-(8tgimmM@Q5FCQzt|`tRV*&yKhvQ1Jph-mtc=@#(ufsTrf9Lz z{8>47q+;LtqLZ18OOVA9H+v1fSzWT;YpgVDyesjNwRi3PT|TDY-Ug+etbbaY=izpu zIZxrKZR6qIA#ZPQx%h{$@<6-Nw5;5jK7-XtY~;#&SZEQ`^>BJDa{5|DMTN_kOWX{)k%l8SKZKb8|k@*B2likK8FD|g8JE-tG9aIb1u-rC(a>TO!>B;j|H%>h|oZ+qe= zmviUp?dA!`p95d62=3lli2T=vq@bC#f;>=ENC!y;*t!y>DajA={m-LIg^Gx`^8Y?_ zf_$PNIEY@|IV-NMjtFs_OMXeIH2dEHbKJR=b7QgCdN!TwrUxz^1q-o3HCm0)Hy}>z0WK`K+>J12o#s+;`3dg?aWW_`KLoJiJ1iCS*Y zyc~bV>t!(MR<*SX3G!{5L;j(XhG=j*64gk=qO{G4HmX`VXW!n2u0Z3Nj3%8Xwh&L( z)k)p8e1?fgvy<-#4bz{Jvd5d2n&MaE6Z9ng_u{3;HrCmzUOPgAT9ht-Lo3|sfF_Ih zJXIDN!--l&zik9%$)yRX5-G|6iZ%kTzL_vO3)+3Jl_1-mJ8=RS-;j=0Ya9P-lQ;_Q|26o`cmKbh%!aUJO5C--Rxm85cj4%#{ntiSo@Sc!;;trN{j;^hCe(EnNn**9rg-2P*j`^hxNq)^=N&~F<2 z=Gf!5z{Q!_UxWYbacvN&y3nxWf4Ud3b2Jl;0snav@^mxo)tUw)l)KC~-s#DTE_@_G z+heDaWGVa*AItQA{O;oz@~OYu&Zu9>HM4~EG~X5)-grmN+2BB{Zt%q4UC61xccLTc zKJwQCh$Uto_|K!vHQB$Xnv>k&&-4D>I#Iqq_euXJL}bq|A|L+88uXNR;ICu;pFMw9 z#YkTx@26PJ04_0IVMCfljd%Q)Uq(&2OpUcaIMtkoN_nP`%D`j_Xq#qUdONz51aZ{7 zzsur0P^A^gs$UuO{;o`kj-DactIG?0{CH({7k(L*In&qBQI~F^7OAL!%*K&SauszB zy=pL!(1DShfv`hl9gdUQInX~n)n7M;%x+$iaX zXM2>QexCc;1w2w~2vDufbvv_@k2T1D*``&SZ5x)Z&l@%U+25@6dze?o)|Y+d?n2r2 zFphn<#Z?nX=BCar`^VM?ozzLv>1lYjX_Z>YB8x~5XYnIX#pRn*jPv!MSnhv!XVYqb zg^}8zk4&u_XsS@ADtxR zuk%xE3DBr%;Z^p!F$K4g!ds%+_rbL!Ek5wskSK{_oyiEsj(*p+H1N+JRE-O82Rph7 z#-@_*IZ04p-B??Il468Q>oph9zXwM$ZB-`R0W+_b2zqTbavvz_XwLU?_5_@lv~9>* zDrKo9e(14qN(za6YFE!*CJN=ctDMPxJx7lFn4o1;4QSoq}8TL&QG^_Tp`MyWSxF&^SEJDThD0h({ z@)wGJsyN>9V5z+Gi3Nbd@P?3Z!HviEB#L_~yKL_htw`mNiycLRH^ zY_$t6c;?Vv{AP6|-_6yU{`m0WX)k4e$SWZ^zaj z1x#snUtV_9XP#>Evi&{MYc~F~GtIgxVX36)PG`@u2n9*=x3@?%z?)Q}NbCw}(qolY zO@nV`Rf*&~7Odbd4PGCx?ZWJ$!fPC6z&GsnF6;c@)BsW(9IMpUjP@rAD7Y5F5CVUE zTs|LsX{n5@0SSiN;)f1=22z$Z7k>zsH+y+;u03p50{?qFG&w%(17KGa zChO1&j{E3SsKoOhFZI(*cfE^Hke74nx)pAm?P#??U@HwY9eH{p{!=Kqbk|IF*QCr} zGh1`(z|NmtRbm3}KVF=$$a~-~w|13!C?{a14*=Y1-6N{1s=oa4o5>1*+RLAx9lE-u zVVhlF!!vt=LchMb`2d_Jjfc2N1&!Abv_LXs>)j;7oXrw>qpeG2PagwkUR^hK^ws5} z`cwJ*#6rj4hl=QbnYMwJL6Qs-2iMBozOO&@*QKwHQM~dO;41OkN)-V zETDW-q=UJ-1m|2ApaYC1ZWWJRe2T~CM}4GuI2=Ol?&ftP{mp{#@VlG+h=(H-TOXH7 z?8|z&(qW*8yX45JT&{GBGJi-q=Iz`P21^N1U9fDUaD>Omp)Wgdc`DD}I!89HrdNGI}BsGzMl4)`=lREiX>US*|Z`)w$ z`hZUw^6LcLdeUk$PZ^&NBH5L5HN9xlE9Ht6t-#Xu)04kS;$tItkY0{CPlcHIUpth3 zyy)en`HB4Bf_FoVx_W1mMKM_sn0s>de!Hp!9sAyln%xAZg24DcI+D3cUlf;Dw*ME1 zu}S!n0KyocIKGBtj-?w+lp9W$u1jXxhO4Qpr zP{=`0=~5+6_Y8j{L9YpWwNNS1Z0BAcrLi}ft-YDe8mR}!X0?8#v;L^3%&Bo=awZS! z0p2-~ulxuJiH-COog8f)T3^=RnDfgfGS)cXbKq|C#H!hB0tO{1QMOJ{mJs}=Z*PeX zbUX;4X%vvoysy6c@Jwksysj$Y|I1N|LblkO`U)t>h02_Yu&cuTDE|U1KY}3?N_+q(4ST7FS{wjz zNdhT|1Cok&X0xZf?Xz#UXLIExB%u08T35!oOb*wWfj&yQkN&W}SEG}tTa-~_#M_wd zkKg+8W z<(zw#^2<9XZLYyOnG@IB?zp_*+VUNj3okF^y`PjMj)3JNmHp~fNC;a@Y*EV@gPtx@WVl4qY+0v~pc1ZKZsYhQin`1Fl*Z;tJy4fchv!x|+ ze^!KSG~c_~y$W^JZj(JE9$h#0fz~4Xv2VdD{Y|+K zu&%Xh*Dg*V=uK$)UjU3ErmzITJo)=qz^wU8jS<^PmV zITNnTaQQREY@R|V^8t6N-Sg_76c z+Wlw%8A=8E;ffWesGasjTzZAC*p$NToXGP&`xg%Gr0Rrye|Lw2z%W#H^LEd{n~{Zr z)1xKCE6)cFsDFUjT#%6Ns{{zJv)jX)MmsgVcn}nBFM~+U`MR5qf9d?lyKHoz%?z8F z28j^c3d!MJq>_?==jazpD48#-?1i(>^b7bbS?A5bH2YY4U+%9a+67tI1k_SD;(F9m zsEhc6R>YFxTZiD+<|V`nU?^f_j-;ywMAS3#9Q&5_HE`c!2R5Y%I|HXGo&Edw-!L&J zYi#zXS1ZDJ%#JPtnonx|0Ug}Dgp~b}HS!g)SnfcBLs?OXq}gK!XvmHW_~oP&Cx3oo z79*%=%V~N=GOD8J5^5Y*27b~58FmFLiv;p+$3?OGPeV7KSwG{5pup6 zfWcf{(gC$QMni2{DIL^Zc{+yLawa0De)ToheKbctyeQFqZMPp!5ej(Q3l_n5Q%Z)= z3w(K`*M6bt1$lS)*WwxnQmohPruevX6s(od2@r&roID?-HAkkwZpYTa*DLGFl%R0Y zRfH`Y>5m+-a*n7lLsIJss?Kz{^Jl9%dpH_L5>a$pUe6T5gxRT%1?R^fJ%7Gc-WFbi zYp&7BF_I>7#a?`n;_pk}LA?yI8?5?T`S6tK-sXIz84?mW+L$^OANu zonGpX#Qz_vA19VI%Uj`sVPX&A%@)nS?gP(6^?7AIZY9{-tPAF)4W z4--9JvHloBGRH)yItF-bqKBJ^aC*}iEcM9@VF#h(@lRk7S6Ni8Nf)mx{^ggB*gSus zq-i>9{PQnFNl2qC89T1d1tGCZiN+JDPiB&5g0sk4=mPt`bWnq~G9-U3e)1CzjIe-Yh?rO}uaRqZ~l%m-B^=1D2 zO8Q4&7X;W#*4jcglVE9#memOQ$Zin*-G=S1ORe^ zi~ejkN5T2a+bD@gKhk86=b8=xe)L&@KYK%vQw2k!3t*)@ETcQAlfgt($v?jPcVjsN zDY}mdD4ZTondU)@?RW!fe%)CZp&JocH}JFblNll1NJ7kFAeE)?(jf9ErM*ypPyE6M3;#G`ipOSIz*SUNO>S zx&zVh7cAW%gpUW)6PNM7m~}LhZsX{WS8Q#hsY7TBawRX?S9K+ML*e~}q-KM7frN$; zWPLv905`ymfVsK3Bv@;$_CaZ;eLfx~<0fmo$UQ4P7y=&M^MetTkR z_HRUj3qfCJD$A9>A|4TU1{0ySC+AO%XAQm;GXtq(w;$!1%E|woqn~QBEy>{7#^h(; zLkVSn859_ef~EiwU`eo{^C9QHhrvdqJ`@6Nb0jUmW4COehYwvOJ9;$faK>5!o<@gL zyu!n~(VKjZyU-H)E^fnHCQh7pL5oXpRsLTM4w^){UcoAO+y!uh~m&D$efyW*E_u`|ig62#?{4e1%F3bKWi%A)Tj`_|`j0)@L0Kvnk) z?U&;2lzaiu+dZipD>|US2k04{71_IQU%CU)MI1iJuAYJ}y^f|sQ!mqoQ>X_~uRk)U zTKAW$2>PMAM6yr=6&KOvw1lsvEjQS0Dli@mxAm>1oQ9N9E!o4fYP{y&*i?TGHP@OWrqTgFA`D%@k+d2)| zZ?}3HRt9WcjE1P^L0#Qd`pd8zT7vY9Yds^9-`zJg*Q6>UO1P-ymbS(<@G=F@(N}`U z+aa4QhODPb%a2itshdbIB4MtxGFEgzoQyQ&PfzwgfYs_`zmP6N)YBfK8eg|Q&#yIM z5X*Tt!R7$1>c_3iA;mvB6c`51UJWI>sJNN*;)EjqeuXoXqTBmSLv(YsFu8~(9rlFE zlrJ~LwV3F2-2E|`86f+*-x4J>qWhMqnK~&2V>27xY06lnY3FC!c8Y~|6=%}0-6L(N zwnmCS)w;}SZ(4lzs#&DLNd5fhTFzRQjQSbvat~_{_EODhm&>55XJob6SsJ3V>F8td zO&_^e{C9Q7c|bUyIc`PQ>SOqgqO4eVhe+;K&#!6RJEWJfI%{{@Kqf()uV?gw_jfxg zMYi2m)bdKBmT0SqiMPA)e z{2^4uEKim)Sn9O5BEhJHwoA&2wKM;QWWtd28TL_2a4vW(KyE;9%9HO!jm}NpuSV}d zeZ9+1!0dtdyq%n(toj+N*QiRS(LbL~H}u(+{N9n+-xXQJc7Hyvo_b;XCx*lkn1rL7 zbhTg0(4&%eA&Rc&GYwT-5C8D@fuG-CrJ3ZzD&#DyRPd(j+FA-ZQ&^A(tM%5Bz_j+dor?@e$7k=LiU!@2&&wNX+Tg$Rq zhd9@&>Xqa=r~Wush3J!n?!7EY4Ws?LCF!l3*D~^?HbtYPaw^q`78SaZ3Ok6q@f?=E1H(AWcsHN83O-UaKHN=^iG8C}P0>J! zV5Fnfb?ce?Ypmi7rS9&X`&>&cAz8&s26q^b1A0fhJ96P6kAXDX#%ux>@(0=85%3bS z;plcU!&Hv?a53SsBfZH2)5h(SGx=8Rv{y2ory)atfx4Z@)Za>jOF;PA-pe%ml7y9< z-IYLSaK%H0;Q|zRgLTJrq)%jk&7T@JfXL)WW=u%FIMa02!T{qlB&##(unym(J0wX? zvgbGC8^j8$x9_AxX_27=^bf8*+!tIND6)^%Eccq8>S@E!gO}%u)d_$J63_MOVO*J`YfT_U6T^fm~*E6=W`+hVzFezg>!Ydqq z$Y_0~#gsSF!F6j${YYHfCR_VwQ+}L;RJev{z+@9e_T4T-c3+aHm*NlRUOnmoJ)R&} z0vf{5U>N90FDvFf_56m%bGQg}c3!g05{B7@ar+;b{_H5XFJ5NBIWEHBMCRwJ*+mT>xtc;`cy&3595z?tWdR|fGZ9RNm*B}+3mZO9oWL0Fi$cQHVUw@az$(S znWk$uR;m<_wMPnK5bM+e48_DAzPFq<UT*Sgg`FniG1x5Znlm+wUWO_$v~D1)YLZEz+>x3t=Ryi9dp6o zP#6iSkaYO|t^@ut@#Bh;Z}|fis1*wH26@g+e1?Quop!r=1?Hasq8Ey-Vo;S;TnNPXgWNA%6WFO?r%kG+7tWHu^>TV zn<_08(_}UmOi-DP4SuU@W7bR3AMoS1;*qiCBke09buj70qDv>!6ztqxy$;~)0Y-6j zQ;hhDWzg6t0r-7vJOs(N7~Lfzo=Tb&P?v5xu0|vQ432~a*DUz@y>xjZwA>OR;gg7f z*7SYiIgybeD@wzWwAUF7dttI#U&pCwdOG;@!TmdTF{v`JFI==?R>s!rhjp!wZw?oa zy%T!;w5^5QJN-?~G0DXm$IrytJP}QF+w1V;-QdBSE5FN@F?z3Ab+uLYo6y=hulw0N zlSXd)oquU$(?98Mz#Uwg!ImfEwyx%L_t58lO-IKkDDjO~Q=&W%XIMW39or3oBo3yG zflPD+gd{K;38s6zJEbPYYtkkcoxphu7dp9mP<3d~mO{yrnq9%ry)tXI*mBems)g9v zwG|*m8P2_jSK8@lY1!44%$hxWt*EFfP~QXg?0NI%WhWdqH8UH=R8l9#_R5huiFh&j zyLq}AaMka3CG#tYc~*^%pVVDD?p={`?$OuYzKog!l3Rn$3O{@z-6CM`-o42kXFWVT zxRxyWo_aw?P0bfmqUEnsqU|wLX_S&X61qwwEH2pC^AHAZ?nxMAMR|MA^Z4Ges?K^hxJ3sFFoRNsEz%v%KMH6FrKaquO03gRpji>G-vFr)_5TTHWZlN`zDs=1F z$5WU`eB0dI{MDLaXl7`SSgX8pj)|edh_?P*0=MjpRs8wN;ljQJRj`B;I*z4^62ihe zJ;r~g-PQP*x`bGdHDW-wRM8Mkq6Ygb%!4BL~h%U+#q%O z>mITyRDw2lUaj7E#*2a(+$q(K&W3dc}$r4W83JK0cp763M10{O(Er zob8k-+zDpviZ-3J$G9UTeFxXCH&hJd>}DI#hi531;N7WA>abCZ(H7L@76E9nPfpfv zK3SW(4e9(Nl^`pD@@87R{bVR0Y_1d-G@k-NPudcAwAQ+@EJVuuD_RX6c!u(rZ zwDKo=Pf42_peSMAfBC$R5+1P4~r^ods!K-y#U9*puMLYs|TdSnhoTaIu;g7!H zeNpY04id{)nNzdJFHtF}%EGtjVus*J-H$SxtUsE$Bc22VY`K#X#x~(Lo}QlS2Oqg% zNA3Wccw)doqd$K-&&ah?gkQ!FtN3Dj_H^FwnP87b>wHWbZJ8qo4Ne*`u|6`+0IX zBupDPa3|Y{5)(JOE zO3ocQ98+SmGcPX>-KIc@*hg~*ig{g!-plA5IIu!>94oF$F;;3sr_B}pj4F&#;K4(e z(2yvFx^HFextL<-s;p6umnWFdFi`9Skq5GI3G%IlOE)On+uIM0jD&qDgMGzBM0Saa ziiRqBWMd?Q7hMjE!`Y7UC>0{A2NB!KR9?=M@Od$DaQ`29O_;xt9U3IDJZ*Z5&z(=A!H(jTZ_fuTJIQ=)N|0;Jy|8k!sVPQ zAk!foN;G0Vwb<>Tkx??xgC?2}N@~fAEam=Y({qke(lJ8MU5Pu>=H1TJJUw}263?WI z9bx6$5{0U;1M|>Nb2PVYJ4Y4@yI#6-#RhX6Z(qOO5O3P@wl<=SL-@&UOsu29rwIYR zVz|cmRMM}nQQ{4Pe;0qwv0!|T$&0_GlvQH81 zib_Zbx2|80GRk%BtkN^qF*1r!a$H-vtt(!L=Kpg5|^BTQ?@quG!B2nJEP%#rrP!vf>I_4YZSXn3IgpN(E^<->j43g~a|)zp-UH+7M#-@wKo z-ibW+=N5esEorL?;YpCDaUk5`R-g3=fQ`<-WL5K5F516W}%#vbzw~-bC{PKcj_iJnQCGNul6alIUODGRR zQeuhcJh7v0AfQ>Np|j{nm5DvYSIo068NtPr`2EkE{Tt~lL`357I>L|Ch zSzg^IcXluuq$?VYR!bn*wd>YplB(>0FqOqhz1)0kEUed*j%o#|Is@?D2yeaP} ze?X$w3@waaDZ3Wsh08YXyfAy=0X)7e17X4qi^A0?HQQTe9dFCRv)T=xVB)&C#$*Yj ze)5YE4>`LQDkdl-)x+g<)<6GoUcjY=A=~uD$?Lnft-Hb|SWOZXc^>3q=ha%l+DH%R z_S-;69tZ6Z(aB`@_4n7s&3ext+O}<*-+_K~%?Zp4-(vsLb`s?dKyC#Nz3d6B%yzPA zgs#aWWqBR6BI)bbV;ChM+h@7eapN|c5!-&v7W*>um?dmhR7!g7Y`4({E5rW0-^m1N zqIh;;$$`<>UMuKhYXV!jO+AMl>sHH!oHhDj~Y4z&Z>KBg?Baov3Kq@dsLY6vipP(KZj@+s?y6KZ_L|HX|JA=TI5Swicd`jKkjYH zJwmYZ+qWC1#Kpy>a-<9{iq1JY3n8-)n!Gf`VTGyDHuTjqe}2Dv3VO+&Ks0$`Fkra@ zz1~mYYmR^fcMaBkv|~=)S_>-n5IRTo;r`yRs6uPs+;;!8ytuN% z!u=MR{fvt#b|eaux0aY2V~w1~@uE)+&m7j*KT1Gzj*z^cC~m3=tZq0pa~Q3Ua?DlT zx^u_s%(g7V*|KHJfCWB+%!}vTS%a>A3wBL%TH`oSe~wMPlCXqLEv#Gorjl15w zc|*dAmP!<-Cmb3vLag!o7hn@X8pys16F*)BCa`%!Y?6+VXaI_Za1sLwQ8l&|hjc2C zC7gB{#v`5_G3L_+jU?!x#|GmZ=SM(c4-qwD>(;5mu+9Op9^+3MpIi#$T(Tqv`H=7% z+?~J$Mn*;+0~}JZ^O!Yj7J&s-G3vZUB_(33R_#VQ-H;<*(92%1{cqMx;}0Q;Q~A?) zee+Zd6tw83Ul{AW!2a0V&#%g<#xOP{WNF@lQ`^+GT}|8%1kRoGc;R6~>l32~<}hX_ zx3ri{Vstr$0Il4K!P0RQWT&Z#v#J$vEOL;~Pe9?Yc8uD7zl`YM-_C#{O4}8dT$7a%R1~Ppa&-|{URqO zCJqObmX+ywdgdW>38|_X&Y@6QNJ44y{C)C$nCvIZAaR{YZby{!fq?;1mkkWUTHD&V z*x9#b&Wd6uTdgyjl0fix7Ac?VMT*uZg)vKsbzp1#vj&06dG(hFvNu&^-16rCEMW_;TXjy?cZQ5QaiJC&UPT z(>4S>fueT+t<(TH5WeU8V7Yh-yq~aojALq;8Dd`a=9xPv(m|xsLFwS_COIEc*Rpd- zfR~k_n{UL=XQ2GxLqLRXJ{d|9OO12xZgca8kJHnG!owc{)bn;TF)|V-A02gpkM4tt zbpY5Meb)AOgAAE3NKs)GF#E#t^4S1y2R9*@bf9En57+%(hO-KVZz1xOB$d3-or3x=wCpu&c{ zx&u4?$jL}Z=gJ$K5Bw*b`Wg-a%!(kJ;0@j4upgtL0E0z*YltH=$q-i z05-;rfZ#qsDPM7oY`UEuVlPz5E02g{grH@6KyDo$ikwb@zPyyF6pi|~@7`7V^UFUm zD`7Q1cFYnEjk&;(S6*#Ub?^d%>o}n+Zx)`JnTgzg)bS1GBZ6C7TR8;;nuJq0>~=BB zw|oGq)-fq^uMgU(yVJc;9V(n%V9VpVf_an4m6$w zw1nmvM*LRMW4zKe39=JWCA*)39q^t@0-;&Ea^()#jHJ^??dVf#9X}qkanmNEZkTzP zm_(I}ls+}P-Fsz!f%b;${xRRyNNn4RMPf$=$ zk^BBOfD*rNIE<(YL^N;y{7q>q3M3izsT>=emQyIn?HH~k!H7eb$@tKlzNgT+y7cnL zgV3iJ-L-r7=Fw;J&OLD$t+v9PV{!J|w|jwu$~ppdI6ea3Wbg_n?LT-h8oa;?1ES8| zfXfLWjdf1%Apga1ZEfHoUiXyyveIY^6Ok5I={i{9Q4T*l{qQm?zqPZd^HP@!L5mt@ zQ409@&NTV}$72h+aol5?kZwOd*#i(-b8w2$)YK`JN5%LAV^?BQ(mVYRuU~8J+<6hr zdKz~JQ)_n>5{Is0!WbjLOex4lxs8PquRRSe?KskND5oAC7S#;daXfN*Ob`ds@9m#9 zT)%!j$xm`}hjH>RGi?eb6i#{&@(@mnS}~`i=ym=$i-Wn4&SR0FmUa^X2$|6FO~Tyc z2)JkajhRfA%&z$I0TU|81qI58H`Hcb>+<`TCMGAV0MF05xrwb=vj>_ewyX*RufnRB ztb6K6@tNd2zLJQ-LyMl+8FR~UZE+h(Lc`hA;3jc>9Bg!M^!(kM{pB)mNX()FuK5cW z>L5)Z=ZVM5QN}^?yCL!Gf;SN@2vEHA>skg_*PLeE@1Gx=`{4Yy6A*h;^{nXEulL}{ zjP^L@5gx+Kav8~}o1(I^hfo`xyV(R4Ph3pH!H0XqkvDD9Zimt_%!mKiJA6142T*#d zF&On>j#(9RIw(VD^4#DZkQ(2YJDc-Tu|EeOJ0L~G;>u+CgTuo*@c8Gsxm-(^u7NYo zVrH&f7G>R-o$;!qMurddZwca5H85{taG!dlq9LlUWo7fLDicCDZ3BovVkhu{sj(C* zOh(tE8-0N)wAY?klnLb2+sHlF1h>Nb0j@wlwmk4Kl~K;*i!~1R7@s|R_HdTny{WM> zueH+BRki+}69Xz_Fom*2{2bilC`qZxpX3QegX-mh#!H56H?RSTYz)~RO3pd7%j5Jx}fx@96)X4rk%4&3N*JlLGJO6LMoklH9Kb{HQz9M9$xA#jcu zBKUv_euDEp0M;gg9WsM-AMetomZlFW4d;*_QRidvtfJs2Wm|`Q^QOja(n}e8AYvQL z(dK5Pd>o}IQ+d|VCGjx#l%~hZZr{!8JWULO(g%*+h}qxbam+F0bk4WQJExBv)GeEk zkbvHRB4S+A*kd>-Ef3Sj-q)_hS4k$Kd#iEwWWmD?P%IDQ90Bp{^wO*(oL|x^Q}`7Y z-DNfB5of{UUEstI$N{_WEn7e462*XkH{fQ+@9&l=V2q>q-8us$M*h@~A@?6Va6*Dz zTyXvyd2$0oZEhS7Di6uKP6|p~Jto-vzJX=X&^Ai+H7@BqL>QsFL}~1;ZvXae*(dI5 z$9IG~VOG&bp#+NV6Q^$7la1L`wjL-jz1xX@1FfB`s9`ej{UE2DfrA#^r@VgOC5r_H zgHGG9k%`~H1-P;R0aQfgudS5;z4ERO$=FL{+3i06H?K-j`J?*YRb*I7Nmaxs>|ZV zivhb$GN;f`Ak+azfczvvQM}NIO3N`u#nXsX>|Lzw^ul9N55;o?ZD(tMrND&P<(M(4 zEGE?yS?h;^*F>8j7YG34j9QPheyC*?$f42>-_bbVtA z&&p6Vl_~RoXwd=@^lbQ3vZ4IL=;$>fB1QUoIyw&<8VmprIyz$`b@3piG4=DOBlzye z=cZrmJB~3<^gx%WhD%|b2WVrn6(+&Ez!>Yy*(v}=G=#TUlndYgnF&MLa%*c)Mt z?<19rjXlR68g8QEj8GR&N>zj7B>~eB98K~+4h$Yg{tnew2wnU_jnd~Wwt%ugTAMo$ zXW;=BE}=I^u!{#Irt$ZuJRbl-UI|aOj*$qHb4nmci6Agc9X%rPiKep^VmBk(j6yM) z1^G?K-abt@9xMw`@xdFeXSZ?aL3HEB1Ej@;G0bC0n$Y;t*1D`X&tFgm1ke+6dlKDl zwWRMBM3#K2LZO6RiJC>~%sD2OE(~Q>$gzntAb6xS80!*+8S|O-_N*o6REK2aN`G});+kBu!e$N1>cdl*sI z#vze+VcW~2lSY3!vvpbaPD%CxEHr$?T@}dq%bcEDMD0LcG z;{jXSWYBbr@yb*Z%QHp9@^Bc-eF=yMn~EW<_5}>~r3MV>%`<0cc zn~Yg01s7_a3rNc|ZE;O7bTODVJ|ST*R1l!JOV4x1vKZP;g!oh2ySo$dA`%tMpel*z zoO$v10L5p1|AxCKS;Xn~ZIh4?K`$8pp&;IX(0bBY)^a;7mUr)@NM(n{&$o$Le=B;E z#Rp4dVF;Hry7#`UOeSW1(%EEW_O>I7NXol*?M85Lu(mM=r9h#aA#s3t)~xt_!4gQ5 z+Gu1D2{$WiOYB5Fp0Sb?R-{6ZV$tQxUyMG>x}?y+!PKdI5-t+OUN8*KfJW1TT$Lbk;V5og+YG`~!2#YEx+-Mbg|+{4=}%O(c|nC$cb7(%|c#?KcKUA2&owd3EiBx*&LB&Rrh*~M zLa~Y5V!yrF^YO@g1SdwLg9r?0);YeHu8}&NYbQ~E z&Qb0Tr3y{%7+lE)a}P7=^B~cTsY7-GS1+61#S^SWP>PEn6Wq9QBXq;j^U>p)hAv-U zv(Ge+ZxmKuqEJi0=xb2jgjEqD2hrzKPkuctA}qYL6w{P?!v+x8N$1bry%~i$yxHHT z{^=u9`q8XOfJB5ihtNc@92Rcfn1BENc7XK?j8yhi<4AE`$8DVkllam;!TE=*d4 z6YoGN*|NZ}<|;bOI1?j{;T*rElJ`G|&H_fI3A~#&ecEyc2fH&3+kJTOTA~V6yeD{4 zvv5>4(7qnIldD#(S}P^^Xb==0jv_u3XE6*{|p z^*M~;=5^=GEZ00;MxiF6zf$n+;>C-W5QBNp+K=u^)zQ_xZ5W*N?wuNb`mB%~9laCr zM~?0JI>8x;@CcVCHvv7|5H*h?UWsyM zlO{mhGs4hozTJo9Iyf+3-(|x{ky4N|k9gykTZNVR9i=KS(&agi|si21f8*_5y?yX$tZ+_2aBlHb%OvFQq`9k%sO-q&=iz4PMS+up=_n zv2vxK#N9wL^MzC>x^CV3j*twngTvvQMdDLaQ*|@dm6VijLxz9h{DzuNkTM2qnrIr|631NWrX8p(I)fll*{O z;ouUPkg%30tV9Kj?$XeM>R67rtwMV-w(^iMX<5%SGt3&1WuPs`g9Y&3OY-$y0GF$A zbw70I4g^`i=FGw(1gm4_q#B zD=0G3xI4{1M#9(6Pg?Gn$m-P)V2d|0@lhyl=mvr&2OXUJ5=qf*Q&m%wy3LLD3vmB~ z^n>)_7}8B9^E?StljLw4~fX=lV%ZG$#91n8jK7Jb2@?rgs7DB@^HaVX642c`6i~{IWI1F{$lTmOxk<=wy;IkXbHMI z+j%`Np)_z|{vj3OyVyd3t@>z5ZLY35)AbU2MD#3-6$OT5FQO!g%gE^A%tT-`LNpO) z`&Q|FRRn1!ZOI8w%=P$*PVkL=ik$j-;7ejQ-lL-i@kASQX5=h~nFsp(6`ww#^#?ef z5o2^K8YJz}q4eF5{Uxg*CM1$pF0EmS-gCKVN~sRmQ`hkzR()Fc8YF>iK4nkX8Kxf~ z6_l2ZJPutiNqZEp5=z=s%0k&v@biLtNllF&8D_)$YD!pG*x`HTM=&(=v2=ZYPhnTs zdMFl<$o8tLN>&F22aAb`mBMal4FNh=ySf9^K-mg{m*AT3^z-f8cEgJDZ6aCBsCiE5 zrYzzT&tILOiN^%`?MQo{wfg)W`UYA?CEm$Sg^E-6jgi79M6G&q{9VXVaZ+eW$a`vp zZMg>@d|OgdQn>g1m$o(nw4u`1KLY;9oPP}AV}*k4e4$VpD(X&3>FjVdYIfc1R3OcR zX5iEXXXhLyvEIPZ-bmSsH;Pa!nS)WNaQgEK=39)UmK%PjkkOuP+-RL3XFk%s4;o@USI-~{^&9QqsF9-v+k`M(GKw=6G$N! zhLoi^>wVo;9AhaUXIiMM4s3Ed>gp;-+$DsLT$dz?3kfNcEyjCOK)#eIiL8LjPU&ws zFFGb%2-@JZjzanHiu?FStrMFl6ulxY(!6outEVi{Ui4B2ua!6gl^`%7^9zQ|Zi+o- zmH5Eul#coD<3vc(-7d6 zUUUF7yoDvcdQ->uX=rS|edqEI3ubv(z_|d0^IsO&qUWIbJeY0)EaevFSa?dy%ga~k zGD?M=q}ZUFx=Pn{o#RG^KleUq|An8{QYVCgS&01|b4y;i^kieqk|v2ZW- za{59Og3k;0CS5vJf^BH!yhyF1jl69QV`;UvOaA^Blwu5J%~SqVpw_CNJ$2eBH<&R~ za6O1Q7pZ3}Y=Fw+?)GwCJPtVq+7nFzZ~!zL7kbh@c z)(^Q0<1gK*xpt%rUFOZ73L&$O%+}ZmoL@o_CS+@NvKr=8=-&+QmAc5Bno#Gw@ymGu zld`8wn52rrASH#efu;Q%fgQhgZs4Hiw9@8Xw(drA5eMVesuCd$vy8BsWfq3Vz<_k6 z&+{Wu$(!7fopHer*U+h8+cux(f~^ih6wLy<@A#4p=e9@XS+{A?LaB>TS7GkjOJZA* z$D(X?d#JNQ{K&UMF0@I|{AOTm5j6)!BpZHIe$oU3u-AepdJ^K|YG~X9CgfzJU4F;l z#u#XL<@>eR*1a$HhLBedwJ*0k2RLi5>CVdBGIz#iIHhQ0_6)5ASlocWUP51O$DY+3 zG^s?llUn3CFFg&X7fe|Fb11^wohc36wDB^R1&sQ3+@L_kgXrKOLU}Oa(sjIu=9)9A z_kU0ix`oVYXQ$#(l6_hAN5CJP%;s&6+Dus03{zmEv?S0@{S=rTv#{VL<3(co_U_$? z9t2t`IPA3P*$Rg`qp*iJ=bDsZX(uFq%uc5rhiG4}b|LYF1 zvHlb17g0paWHA@%<7s!6tbOCBMN_^Wyr~wv1uHBW4-%o6VqzE;`D`@}1Q?u!Z&B+Z z@P86Zd48YQHj7M^ZmQliDb%p-^y$ZGJ)I2Vvn$SJA4+3dg5K{R$wrx^Vx=ZCO5fY( zVy9qd<&~sY54seKqXOMzjFQX{H?0Roe-p&u7eJ{l3)wp_?g&zT+KJn$%-9WO zCbAsKs_)tig~rt~?dnfvS^DO|FTg0f7F} znl)=)U+kjBd;z}(g+p%GPY4kXRNLnCZcZ=VIEz1(nte!;`d6N$v>4DlmF^MW>NHY- z#UJ9OMmAqx-{@-2&o`fa_gu_%;CZya_6DL`-jl{44o)Z0!7w7BxI6UHsV%Q&c(7wc zVU-DSeMRP$&Lt7lN`f%hLO!df_x+g#EwX_(Z~B>QvYJR`FWPvOQEd4lT33s0r^iSB zxo~fK*pV;cAa8^)+8P)i3XJAht+7T%rsk{nyKSjVad)|5g^m$jCX6QH#W2`OP8m~L zl4rh*nJ||GqF+EdD{fZEn7`x&Yn1K9TjxI0zJMOueZ^7V{)j)M9~|N=b85>Q3`bjt z;}}R?;of%`yg+)v8NLfXeW{FO+-(b6xGlxNcbc2>C!v00FF3!N#NTZh+XhQhk?;3z z&ef6;!^?eI<&rLw@yzcnSw1AC2>w$;vbJJ!?-+1(@gTrx&j^d=3mR-=(m(E0U@Ca2 z3ORu2P0F8E_y&;g(oq|22(o1mHQ=TpPWuwAOt=$cNI1P2`-V$a@C#O`8*=`-2dD0< z&2wpuLdFQ6NkN)0M9iRq?fmd`el;W{wWLD6r%atFT0MtO&f6}L{c0Y$BX#Iw=j??= z?JU1arso6a%-k|*L+)ae7@F;YFJOCCi3SFzbcNlAms`H1%uAwfQ^57RTPNNr)a9iZ zlrXd;TVgt7p|G8Z;S_2d!MHgv5Y%q-;og8MBLpWbkh4EPaL&a?Y!}b?AcI z3VoIWjtz1&&moVT3>$(^Z9KmO#B*lMRyZF08OXen>4mGz<%2l6e^T6ZI~J>EF4td3 zt`v5~VH<^eB|$O+TzNN4R~n{C7gCZK2<_dDT}RXA0>hcC6(?dluk@d`jAd9UPz%yI${%JLqNtW<6Wbk zJ$X|3b>3apFRTTUVvhNNwJJvyPT*+a7Pb;YDbB_l4TAlWNWLB9g(?O{n4n36n_tHW zDMqrBN#}{oFC9F5crEbFO)(oD*oZHEukxL3GXE?M5w?I*pksdtat1}BY%S9};7`l) zm-^1_R&$8H3ehNNi4`8=&Szi^vdz+p%KQUK=b^)Wu>_YHl#P<_=;j~9}t zoOm}fY8fOthe1q;*3`3;Ao|W94~${hugYQkXBGfcn(#&j|Fe5p#OpOy0S77p$`x^5 zEGQ$+ge7xF&Vr~$uWSevM!un2lqIx{0Z4?Pzk9&{3oaNDC@w7x`6O%r*iU{qLREh0w|IYu!Z3`spMdviiQj3ZX6-XvB z->OqNDotYoLw4lixYs|)hBDvo-BYG&wA!d+*Cf0ei`C@`F{EiqF_EOY7!mWpRlY!iS5 zR5RjD6sp6&;BhG?a<^2Yew*FFjmyjk2BzFzH?m)!fp+{uKr!VWp%Q|$E&dOCu<9Fx z&ElhBPcGVKP{MqMY~k#*>3)LSMQD1nS!!9AZcUZ||*3FBz5py(X!^dEWM?s?ev_ii=m`K%bTKvj4@^ zm4M}#zul)oMTy$q*L#npN=4{@BZ$rM|^vl+XzpDWZcD@WQ$l=DdH|VAlowV#BmZ z13ar=$7w#RXti2XNLs*!gRPJKEdAM%e75559&>IB-fI@5Cb1|uuBqe;l>$X{OF)nO=&m|%N;ciUdM;yb!NKZ_SSc7pM1Norx zeE_*)ypWJej&w0n=4dziX+BDGyr!l=3>BwNoM>}!ChG>0Gsv(jD_~8Z43&pihdc&e z_?P;`v}$OkFlST~*i-#|aA-*V{f1lHsm(n$?mJzBcW-4!UkTbmDp;PsiT?@5Io>@g zoNY!o&drl#R_9wlj-lxnytT5=OygQTj7#&grb;>ReQ-a`z<(tNcXxN1;)A$$^2CW) zknivfj1lRliHj!ygkKEZ1K3}=@Lrobb*f#zE=z0(4#`T8BhlZF-r!&sABh0_H1cuy ztUaT`k|a1z`%)p-mBVQY5|JO&adcdSC*3WC48KZna$0|91wkKO|&BL928JTA`H%)x>1UzKhSQ zGRty!Dk`z^h$;G}1%_jkFP^xH{iYGd=BQi2_nuJ7W_X^NqVT86O&n>9) zCVoX)UjBidCH4kfhTYdf8iT*-1TR->2Jw%L7bZ3}HI4f|eVa8U3G|R4QPupVL$V$O z?WPq5z1*wPG+hZe$QG?{A3jC}icr)9R=8sb62;gf%g%z<-d&Wu$5Q6~Hkd=)n$ z)4sg#o2L-f1Tb7~1=9h*20)uL?x?7mM=Z$A$+&zZha#{Q>_v~>58J5&FTOCV7Ss-) zSPJy3c--5;D$94ydzoSkz!iPjCexDhASUdAs~TNgeFFn$-zm|E7T!&N@G9+pyB^xE zyoY6<@QI+efRLefFCW7We2y_DPayg_dsd{LM;ppT9?CF2DI4AJ3NfgQSQ1&}a+2K(z+<3xJ7id9!~2LR}J zixH07e6YPuFc*-D1J8kEQlz@juCAPDrobAjH1+1^#$Q?EJ{L=jNZ4u?i55Bf7_)i4 z%ED;|%)6A^gqZEX%RhEC<7+_49E&Mk@Nkx{uI>_v8k!Y@UCr;jqZE&-4@agQdkqc^ zN^ab^v4hx>5ZpD~G58MJOB)2E)$rWiXtjG5r$Q0RoS=sW$uYRF ze)#)$r?F`+d5(xJxh|`3FGe_U`}kJKln9yfUL!0PGw(VWUX&6hRpqMQGdhshsaAiq zat9hg9CZw3ll({XhkgBUJLZC;N9~Z{RK|| zq7o1(T3TC0J3yD+%%BR{76VzuO`6bQ2xth>B7xJ%^5q3#skf@bZ063#GAF6 z+H*US4(!a(D{L&F%Sq>d+%P21HNcIoyMkv?EvNE;ks_) zr@45{$~ujLE41J!A&zpKG}?_vM}~z84KoLLG^o#F$=to+*A2OdLef#Z86u6B1FB93 z&Vwp#BRr3nvP;eQDw*sVBl6(HqTXR`purN(BA4Xc}_ulNA3kCsbz|E5!I$t#gxPnprLAwEC+qQK}|z=U_I>VS!_Bf zNY}RChjEmb2ayLGNP3n;vANSOXG%h`O6LUOV`Z_z1z&#l2owcmognap(s%#iYe0uE zFej-u5rhDZUxfDZvW$nYF~2jUD??6J{w?BA_su%eJt}>Kn{`$0Fb+s11p(WFF&NuD zIx*fd7+hSKEya;+0Tl{H!um8w#E^B;B-?{t(Xg>JJ%!mYF+f4UQW{J}2&Q;=eAaID zi_gYtQd3i`%g@KRG}l9=xA-zolbaHM%HXpSo zNskVGdpOjUmt6Bc9NJmPA6H{)fmEZfrR9%FRw0|?aLp0Jx|ua?68XQ z8KgqR;EHA<;b2!b5g{jl6fe0T_&k;4NfEDaeuT+xHRxTiIEY8>^ynu3A50G}7WSbi zp-XTk8LhB36=*oBqDQlC_@!uJkVnJeJ@~Km{nK@rvs;#rcHyJ#odWO;x!FsXmVcaF zK8Dy8s8*@a()ScefOkmEyLizqSZU<19Qvr3=LzbMfsW3fbY1X-%Z(z=;L(atz^GXCRYNSF{tu^ zOYV8Ev7x8wsg1U$yiE4>N2HD=a0doT)$eMDG1AAB{+IZQv)C2 z5eS^0wd&Q!Wg7k%z~EaE%?OE$)D1LC$Aly`HMPAiErx_xRuNl>s^@|}mr?o)xe5gZ>rfB-<6BPz6i zSRwJiDrO5l2j|TIQUydV65^!k^0LOMgC0TXkaqP=Pq}Fv%s;9T5s8bh8wk4>=QC)| zS0;1)MCT};FjLSHfl%qXbH3XKJYrGYZK9G87c6TfE(Ef~jh#Dpdcb;UW(j17_#xc& zi}Z?BSS>=yysHaQ?KV^@mT5#Hynus9N_EhVl=7sqFQF1bueV56_T!(D)@EjAyWQBg zZryse+T^MGQ$zjOPE63XLfUc0QDiCx31cRloV1IoPn0-~xv1r4L?nc*+O>0M71roP zd!t&eCIvb9T?C?Rxpn&VY28;NNNk`%Qh|*c!{M7!r$;WjJT zu~toVXqdssfT0bB0z_H|55Eo!oJ=$)*a>Bte}bM8VeqAA2?$`@A;AH()_gAb`69qd zhgIq)d~*<%gESO#ET~Sy0rSq+&V|W>vfbYk=UuFZH^XI_6AOC=25OaYMvDwsppey% zO?O&rPRtb)4rGI_mGnXsRvPB)UDc@b&$p1Hgy*5uTya&m)x1LDB83R~K(Kv#bLNsac zGHINC))$1oimJur(%Ozh6KZ*yi(`gScZPSLlXmbkPpnAz7=Ph&e}4^rm4u?&!O?Tl z4>4zN0iJXdvA6;HXTWs@mJ#$H@C0dtt!9kAzWzr|af@h}20K;UIRmc%=hPplbqQwQ zkd*)wTmoE;QZ>Bw=-I)Fw*XGQ8uXBD@&+9_$@?ZCF-J&hh?^-Dhi@3Y8d}bC*p%hi zvYmTT3CsoAn8g@>{futQ2$K~0>Nu96LAtKX_mnrqOUM@%7AixDS=ssh`;n;VXeV%0 z>9e8bAU2CL2wBr-wJv>d^zkrt$Ccl33c;Ly*!u}mC~EjV1dZiL<5JjvOL@E`tKs&= zix)qqTbXFO#0xv&G06EyK@+J z9OR@yFXHT8{IJ#VwY&o&`wK^p>@euELUY%JlstKI7X%>umc4a%H=q>`zO!uA{I1hT zOI_!2SUTc1F&*yIF{92@LfF>UM?r@$y=%PvhV|=bXy`EZIk3riB4`6V|7lfX{GDA_ zzjmgiEd4q(B(`z^&Ta zs-Qr;=>EjR@(Bf%%rR$frEn0|QpDg$CxCd?0ZWu`kgu^ZhA`cAdfHl2*k(^iLVbID z5crj0%oYi}3mp2=ozfE7ay?894sb7i1z07`j-3z>0A*CcX`SttTl};Jf-I%$a~2kYlSz467|Ds+1CPHw6!<_MR{k)d<%(dNK1Y$FD^3Rj6cSgI40B zhMF!oV?;Ftzo_UN`bN}Hq0vi8g9?67$@R4g^76^0j*W!{1+r^*z~}@&<0Yd9vzVlL zpaCQ921((eo3yXH5FQ>*-7J+J+7%cub&7J974teU0~psZT`aZ%(=>bKkHK9;bADCG zIu9}V>+~aE-f2T38&%~?;v!MecyPN6R?FkLQR<>RT>Y79Y|&MI_duGqNxhG$r#JlO zl^jZEtgP-hhCil9>%v}ujuC(!KL(NlPzQB@ro`iJh7KqTCmmQj%gv8CP(TL+l6`== zJVgjchZ!UVsLyoFU7FJt4)AA3LZKIrW>gJc5hx4kl6kgO6ul~pzk(HKi=?G>@BpTF zR904A1<@JjD{QR^^eQqvb9eq!3Qe6gOJ3U>Vy`}66EAiSG8U_~Sr&mr)kbPIYX6K? z981Thz~fxR7nsTP_dYIXZjF^bD_6@fyNjw9Gt9@o@9`Lqs;Z0KF3-o9!oYeY9LP?A?&o%`V|DvjH zx9$)3n`>7fk5845*!zC_%t*WVzu;*bT0 zA$m+CBS%x1gjai3Xh(1f+y%a$e}X$kjApO~%}yj^s@@CVcSnS|FxCBY-^hqy7{l~W z##2JI?*#r5QRVQvHrE5^rKKN40s;i?4MDZXV7IL{&XCD2HdE6=6f8na!G8s7^n815 zax&o)Acv8FGkX)0b?MqQHXy7v)M^H}HeLAxR`Ao+M(s}g0U5(x09vA3K%9PRw$76e zy*Vi~NC-V@?|@_(g?mP_W*F3`=bz%`@YB#9R;!n!P_R0~^!92Jezb@;g{Q8$2753W zyjJTX?jF7%%(xj-@)3KPcPJU$*JKupCG$!iSr|G15=3}3aky}zU+g)N!izZ|f?#gL z))(*Jy$gw!+XS`*j9iid3J{MLO)?Hvt%m=Dkss#hy=(DyWow4MeQUq8QSv#c5b>af zTKD)hi6bhfEQCIT{LF~<4`nBbCW#M@0H)Bm8_(Pu^MO8cQ8+sCLk*grqGm4DvV;MBJf4C;D)?k)rwohZi8?_~~bV^rt#wDEp|CgrSf zw4oM?Y&g0}Y157nz@lu6l129pa{oGc6vPElKj^{HnoTkmP1p!SfoPH=!cYEjXnuj_ ziCvf+5RK$Dohy+pAkJ~1+{v`0`79#2pr^1xO__GMvKh`0qzT)1@3TM3ljKe@Rwepx z&UO%Pb?IG?x(*@b5h6m*5R7VVec*F(-Afnta=p(2k$e7v1*0Bq%Ff0o)w@jV(RdKb zhOXPBB5HLFtUO)D+u?Nwyk6rbZ8F}{QX3f!b*81$lW$0X^c0XAs-bO;J$;%F|EdRG zGc`H{`a2&HgIEi=&yrjtBl~X;Cu6QeQc_Yx5KM}m2na*oxfu>o6VovP>pFH}91rU% zJU3QD0~}qCX-FkhQ`NY3NO)}kTn#|Ck=V$$dzWN3{3X_2b&>+16)bA{iy>QUTYnlQ z1C@nHD~^x>oJek%iaZvu2$X-S`spQNR}N{F?8nvduVRu=Zwiqw7lIe*GVs&KK|9ee z8FUgOnKq2Yo>MUd8_exgT>x$9JvuUQ6c%wZB4TeYmd1z(@bf=M&jp{jUT{qD5b^;t zQQRS^AW@T{S0J5cPDW)#MK53*M?eo09dOnhULN$a5oNYzg1t}8Y9Mm@_!2;(>gL;BJU8Gw%6hrWk4)dnF;aMFGIPe^JAnxn(>%E z81BDD5`J`&m1?+Ef)Z+mFpLkP6twOU|NEA6T(UjQbsD|nIemj)zY-%Isf?)01e=hp z5&gRqVt3Lblzd7{9D#OFd?wc=Q2ua#y@|#{p@Fw9TnXs)D?e?+B`*+R ziSY{xR>Ke@ii9Pw4EY8@9G@+>Tmmdbe*29e#2V4a==IT&y`OBaQpboJS_xDd>;3G0 zHTu*f0xsjTd+2md$TAdmiDz)`ZsV`6PEWdZYc=_!AmEdvk}58mcOc12k?<5F3w?~{ zlE3=!FeaWT$tn$tD>C#}nZETGbKQpLjBBXU^6uRpEQs^3N|b(9ck8aIgT<8E!k>y4 z8!Cbf@sMe#;RMV)3?e$J3bFO(rOzI>$+e;!V9m>xpoy*T<@ddHLUCM*&eGx8P2n1v zn#97CYv*$`uLZF~k%g(i~dw1X+1utBt^?+Ta{O)0we;lEJiotuzKzUQsIRTp+tB$_9sPHfY zzcD1Jr>Cb=HSkZwMTRw$i?{3v)?C}j@PiSO^|s-#^h@fW1gheQhi8^z^M_O%x{@gF z9Ugs!)o3~?mxn3t4gfvU#Pvfw@-V4JNj(ha;R}}|NVmCd(br%Qy1dTiCexHa1Z%VV z5GV++)nQmfzKXyOYM}d~nHY|_nDK~HX`#}XrEbdNApPuqG)s|L~Os#&RnR4Y_MUVH2!Z!OaO=g&ZW~A>^lHQw0 zT1gH#a94ccv&qOEe*j;3-!~{2aTJq6c<%xs{o7e$Q|{DU8XLq_8XY`%FmxbID@KN4 zd0vOn17K36#sIv6go8x$NB519oHmADl+Z}WUD(dEdP4|r`v>=NoKfpl-b!#fe1y4# zo}rf9vSmxutbMPz*!Q+>EX-d~KlKDcceFjtaGLI;n2#V*A$b?!9<2o3;HA%|+B@&o zx;!p=ftoiKgnPse<*|1UcQ#vPy42kUZ~k=oG-$`rNmueNnKy5qC)TjfFk6L4g*Gx! z3bl2;D*$3qu8Rl*ZkFNwB({kapBFP*igog?syPEs9f-hkP_Q_Gw+T{L%D^@OvM3=I zCJZ2rLA?d`mk5L1J&;cmN>b!JH#-`_2byC?6;S-5l7m!k;NEw@s(8+ku`eFuz9-^u zZHGBq6%^E+n&PULkX^!pFkf{%JdAp(q_U@C{zIZDpfd6Q6bZG!Hls2978A-AGKYZo zG0egPiChVgTvYN0BdqQ45ayODfvvgUeTj|w3Mdlc1&1mART%f+e!P0ME;S6r9Ld$l z&IvVXG_qA&jrqQ6A~hgIttjeHH4LEAJO|joi6n+M5S2ajhv+Oe;J(*Doe+gAMLbdT zd>I4XO-)pSLL;pkh}$j*Sa>~Pk}CMg0Gx;{1^(Xc%V^C`c`tc5oNH7;$Eb!n3)*-c zJ{*gJC{Ql{`Qm-;8i$i4NU-lCBL zNG(CDgC;B$wju9J`cd5=#Uq6+MGBaP?%ls8CnaSYS-hg|1#%UOJX*K^j+-4#-P;

=j0GZt(~;-5>nQ+cdgUv&k+=nKfS<*p1Q>MZr08AUC0- z{u5qxAJ8|Y4=nxo7UR@!nD&wra2!a~NZ3JOS;ml+By#Yai!CQgc}z8qvV190kaQOo zr+AX~-$Hx4yUQ&PHAdm|gvcq0h=@32g#HT=B+`%CQO>ciy~k@l_!-frFhHV#Qdpj? zgENx)@;)nmE*|WlIv?@mfUqvywVr{6#oy_m+XaI!1?o|p{8BDRvl5Kt~7;0|Yx&hNlg*}Gqe zFUb+Fk~o%s2cSd9WQmci;c^d!c@dje)Ctc7u9u!p1QT627j zCU+W2$7ioa9=eQd2Mp~F3k6I4VKE_X`t1MbGIZ% z-XslkU`x#e*sFl8wTdT;FUaJPE-$=*aB=-Vaak7O+#gPg})Kj+2Bz`;;QxpZqhe6?D`ipSJ8cXT)pZn%NAk+fxTFs48pqh`s8GpL1haG!7iBdbyhiSpUZj+kJ{q#o$?%>|xMQ(2$p!2BZ{gP^ou?$%xSt z1e^gtCh^0EJ(amM4ttefKlO?9*RV^MY;(855_F(QFj>eq)(<|_75lL zo#Xd_*OA*$Y`HgAjBd}ZxhULLGbIdM!N|Xlj583hK7e8H9Fad6tR^4fr{Mp(3;tWH zM$!;E{XPN%b#zkPrU9j=8Dsk~u#sQ7bQ=bq?5gIZsn3>Kuf)K{@hiS;OHDyWp4p;j z(*f#c=%!>}rEyeSlRckW^AsxM`-H*hVTD}JV!nBE=YCWTlwnhJ ztBQ;4?(QDH3LMU|sn163o8b*W&~RkPDImUkY@WYai3fp0l2&Jm*(N!-5+>i`x_q+4 zd1ll1?>uh877-X=Je~**P&|%%QI$CA4&|{aN&Sy?f4&$O&w>#w8LGe*MXIBXoNkgc zGBOYlB{j;G(A64Xv@>m^6P)aRm=oP%g8aQ(7{j+w?FDwq?oYNkQ`Ky8RC)$9$E1iG z05!sZbg?!(vT~8vcD|o9vjou<sqrC9a?JrCN*ZU9krPx13jIQUtr$=PTf z33>|r4En}0zK=P)C~Mq|etw4;lQ{Ie3H21e^mQ!#62r{1b8s-r@WVuihN(o8)48w@ z6C;|JqwdlUew2qn4|3fisI~FcJ^x&7j31A%X-db`PFVT&85#U7S?kXPIV&E0y^bkS z2tD)wHAZkuOpL_FU6xprp@0e3GXKbvI=F_i$8NSZM( z=Di9oJZt=%%T`^&F0FvSzaJZ2WyG44u%gHs-W}-x7o|@nKheh=fQ%u(y}P_M9p9N$ zwQ%bYRdhIqbSQ>M|vLbWX2U4rd_Mq8`Zefp2L4egO2{`fwPVq0wQ0U8YztW1sfuh!# z8ab;WCyWN;h>Amd9iWiC1I{CvS`bVQEur`q&*y}{;?JUHup+`<{;6gUd}eEM@EcJ+ zn-%wgxmUU)m`iNj>D$UB>wNH{he^Po?cb>KE8Q_!NXVSER)jUQOxWg2-cP#()DICn z(;NQyb^ch+Ku+Y?Rl_h25^tS*1e6b|l*w@hegK9zY2?XFuA#u~-DBGVFpr`zPT39d zm!8`#xc1ItwG5Wt6zLJp%$ciZGqdc-_yS_Nz;!DiGL3SA4WxsGaPa6{A;mcS*#C7PSmP) z5oQA<(4`2E=E|Df8faFiiM=d%@@WIzQrc*VjF3ZN_bLw?^#k}}3-MwRQ|tFjrHn&3 zF1ryPiN5h~-0eWx=gRiDiq724@O=zM^(;?swQ6J;Bc`1#~+7JGys@-2OE&k&~p4Hy3#- zz$E-olg4i7Nm+Mv_ZgB8?Q?$iU+_~<1|C9g1+)eMR?%cZMi?@-Vkn$Ur0oPEXK{gc zKOZOIHl}r9+S9G>!6!*XksXM#zmUfizd6zs8zt8{zXX}QvloWdP6+QbqM{lL_+Fi> zNG_;dBo1h&#uIh-$7SO-qUH`}f;#qRxm{3n&w78_k?%ZcU+SKnFRML+cOJ$fe5rC_!z+%d2i;vjgO|DNP5~>p!w|Y#_)NV3X_F2UQ{faB7h#$RnR_- zO{&F>A*XJLr}EHZhdrr#G2VxLNm}BmG0U}VpxiAT?NKJcQR^yg;vw6yz&p57PAGT2 zVX)GN^?pRf!1sufG+CxRr-_dOWd!)}@@FUL*%Q>pz_djyVLOo3fMqc}hc=L)ga*q% zb2hCS`JVOzn?Z2Z^i=9curaI}ix~96HONs_r9L?lwdPBgXYcLNeY_4~tCS&CryeU^sgU0rFp&e+kW7z- zE&n{Lo{6zsv#I*>X|hCZEti0VNaT4?Wu&#?dtHORU+<3uR0K+rkC4Ih1QaGOW5 z?%e0A1`nd7r^au>!5!_ubxJiQN+PkeQ0d&|d!Fu8tpgk<beR0@@B!2mk)&mM^6P{a+6RIm9<8wf(o)(!bYMN|OMaUi$)4H%%15K0cwc}U zNiuAr(b)yRgq~?{28c0JpGmic(WU~E55r+H`?HuD8XMw_S%FBm4SYhH7NJ!qk_p}> zW|8}Hik-lPqdFhG4q7KOmk9y_N_w`Y?k-nlYk`zbe;uZ08P|LneT?8neHEG}et5o) zD8q?E$TWh2HaGxRAAWxOQbR*ya~aN^LYV>+Tu5DMLkONOSsQ5za0*%$xqJtB_Zww+N| z_*I)cG=3x5Q%*%FT7oFx=~sP5P&AOoI=ba7(@*%XL`q;q-znLSSy{LWlF%ke8dW0&JLZpoMpSacitLA8;tfJNZQ*3TY15{-fF1JU}AXomN$3yE!Ax32F1{eqvRW=LJfl~Ztsd0^u8~7LMl9k z-sPL1iUD9Bi@8ux?g(<%=7$M^M?s9kP;PaOZ3&9RVf3!w(5UO~b;gQ<#n zxU}ajT#2QnrS2U#i!z|}VcfGwS+1x1oL4QjI6E1A$x9dFHhmNeTnd;R8%Xoxoxa2d z)LGZV8eQ-M#;EJzHiUE}Uqg^o25 z2V8Q&Pj=cH=P~n3kMdqwZnT6^Rm2nubw)&0!VUvW**)U=&{o~$vkR4UGofg_5(E!eg7N&Pxc1%h_NoA!0@~H`il(d!X>|Pp$F0H{MCh*6+2b6!c z{clhF_};ViY#%1^sB@OUm)1^a-Mn>cTPt1BS?{2t1nf2ZpTmol=O)jZl?>9Df3w)Z z4gb^-3=^~M%i=mTXjfhuqqat{tNSE<(Sv7!{N)k;b-`)Wq#3FAn^hhhYQ@SuPP7q;s-{8Ooro<1a8{5--NDNh#iLWjL zNh4xU)LOF^&8;YJUIMQ}^f7UIVu5>9nQB;}&|#LFI*eRSyKkt})~*1=JQW~2v=~Ki ztjy1euc&xC;sQ>M|A{jGDrV6HVjRt-Y|6NK&%bGfSbI@UZ&x}XfpyN09z8;VdIQ7* zwBw0n-P?;5m5>K``G494$enx+QJ}Ujt-Q*0)t2pc;VVp)rg5Y%AVtx+1zlv#@o_s` zh~XIWr2JmtcCV3HMESh+v<1b#-ou$aZpQ1^ufNJOpFj~DIgkf$=vR&rnKq5QA`Oel zc2okCtA@pbB!&gY%n9r&oSa1ST93^qPn|L!lkr47iN<3X!1;b_iy@bdE6C$WS|C}h zFl5--*)QH6DoEIoMhjZh1NgfBl<_DJ1 zG)zcoFaa07BJx&7ol{QlccPxRw|7pXB1Xf2I>tc|^l)cBP!!;IaYLb#w(B#@Pc8tk zO*(JjC78ZZn9OmP!wvjZ(4#JLPVEHmXZnr12$p(p9-#ZWYTg5$1rf8Mj527wUwYiH z)j$*2I!umqW9-+hWF?1$-`FksEmVgt789^n=987Ren>NolSj8B7VNwTM!)Q=& z5XH)NnggKUuzOyQ8_D}i5=@YTP-oHXnHJ6{VTp|<+E_%B*G4@1T95Kxe={P~f>#lS z%*94H0sT2NbVvLyW9?0Z$d`H(h51*2hlQw_3&!YxRskzYS$^}9cYfV(=eJo*p>sBK z<>bT#jLB$IOmAAQ=mP`jQ&a|O0Nf}ORBXziP8J>)AeA}soA=Kf6ZNe8E!B{zQ>{wT*N>*J=;Mr;y$3N!0wL_A{UWiV?&Z@ zD_26`d;X*t8gcw=xQf1k7+iV9zg2=V-I4%y36yzAL8I&X94+z3DWrV!H4OUti6?U1 zdk@Yiq)di?ZX2%uLEi#pa>*hL?ZM0vOw?vd)P9-tw+Dc7^Y+SCqf{(~(!`<|l+22p`zS7;6+ryG`u5S zS|5tRreLxrn5)ow)OF{wo|mo@1{NZHp#841y(IOLiudj-(yhdHw_THJ=wk@pjv*f+C~e;(HepdF$OmLENIx2u02-*DpU6@M zpg{-4zXs^EI{1==z0%wYf3UFK3es>wiJ)8ocXg+!C1+1-#3>YoI=M<21nwCE(gmir z37w#9k24O_yH4M}%3%+Vv^h|~wvl-lj^Qtj>S}IlTa2iR1|$xZIAt4NBgV&e{94uV z0U`qrdnRzE5iW**RPzy9hrjofdBc|-?8AQdPY~v-z=@Zvoe4G&+{nk7j-gf(Zo8Oq z8E`lV)f5vXlb+#Uu}}FqRQ`P^u0)NOqiiF~eoWpT6-lZl++Dj0A5Fj#x>`&I4qhEH zMYlrL50V<)A^g2q}V)2_Go zI7mqLFiA?eg<0(t^LG>gG7sN~E1*Vn%mKd8@`|cq6qc7f7PE|iZL=>3ri_L4+EfpY`(BNhe~)S< zjS-O#U+JupgS|5Gd1yZ{=7(mscFae}bRU*`Z(g-$6^@Ak7>{HUMD~0sxggcj&Oh7= zds98mBHEcr#=B=dQQVO%lBkb>rO9=HiaW$xyU%@?4NVtGl(}suttsbkHZCPe$tVsJ zD#yAbPgFQ{p}Z-j7Y@t=V6rXf$$eKYX7?y%1x;f*LTLQ=7YMYpiVH%@=is-rbUrn= zZ;t}5fY=*8E?Kf{2nkpi4P0fLXkf<3{#3Pz%pQd9D+H?G9 zN6gIdV&}KQrNW*&WqMCJw#(mo;+XwvMu*W9z zUGwGvF2-aOs={lkI>%?Djk6vIRy@tp*0pn`B#uIj3d6T{k*0;L=*5ha5e9HzW^j#X z0%dtjF?m@u;Me+as^3x0)ewN8YVevI_lIV!!;kA>t7@4h>0jl{^|0++vf2dPdt*Hk zrjav^r?C3|IRNLV#FtEJ#3}Q{gA_BC2eS<;Dl={S7*%=98sQTDB;OijCz_~P@FQ^3 zt@!sg7)$^wG2IHYWy(|ei1z+9V{J4Miz|Q+3$h70!@Nz*Sol%*moKylmPjgvPJXD) z;V-Z(L6UiIh|R^=u$=PYirKbpHhufKGIu@|LbBrCh82>SNd3wY28wrijL*=4rscel zR6xkR`>-$bXqor7hiGA9k<$HZPAJfYM|JwzzZx{1azL~;rkc#Nm|M3vQ{R&PFhY`U z<9pzG&moX?$kl{Ksu4Aqir74xy{!_B#97$0m)kT};QvQjW#=&|I-5aS#ou56Qf+lV zSJO-MNjtx-DOQ0C1C1j5tIg37AypnKZ0B;5BY+HtOA0e7Z}5ulzF3Lk3Y6oQ9(kBH zp*1s(8{&Fa8ip3+f6LJ8VahzFfn?-ECmu?G)OJ6{kbXFUL=iDD=RKM;_F?NSdFmv* zA{d%x1NcNq;3vzM41N9Dh8>pC^~9J!da@03O~GV?_Ru7E5<&I`K3JlsA#$|AjK)td&K{6o{fs;Ji zZTqNwrb}Qf%<93~fDp$OC<{rShDw6=KY;6U?bu=f@=APnB+d4P!PGq{~z>N3p zL0B=+Y!CAuX|QnvtL|t|A%+_|(6r)-Tx{CGV!l+knrbtdxrBbB*K^AJxb`A88SzRU zUX9TF-fm9Q>~lgk$Tu_0gln3C@}auacA4 zNE{7P4ZTGn(m#eD{o#eIwic@=sxU*L9o%uaz!aF9`prWAc7i9C+4`RQlqv?`d8?IOkt4UKs z^EHTg$q6d|)ELtnUwL%_ZsAIRzsWF%es9{XLVo#}`3aLv+R8}NllmFVAqOO9)H(Wq zOd^zReIdW7!TeBwJpgi8Tx{&$Dc*R|YM6XLT$BiQZyauAz`SF5pxC{HD3??HyQ)$4 z@#ILSV*L&se_{@Is4|D>I;`tJVC*5@i2yqT2@6)p2rdk>5h$=K=@J6rkwXW;3DiUX zss-EN4B9aEpI32+(G4U{vJHocPULohR9}ZS|3LxZUkxT)nE)H?uSi;fL}u71;yy)i zo=$pkU@!HEzq{q@VVIgqEry{Jc}83LeYM{r#jQg2m`LBi)#~fb3CT{7bomq)6TU2g zx)dV3yL_%2n@vhm%rF*&)g8sE+D8Y*|NHzhu*t8lbr`32$j2nOBKS&7T01`XNXncetuOQQ5R%!-zR2I}U!FC=P zw3{Z`R>f}juO?|0kOcuYFT+yDkWKpdwgBhmL*SYIYB`&F#rKL9Oa@`Z5QmOT!+eCt zx&b0xOqHc=A1qD@A}VZu=!XDBny$ij8d>;PWAGaa*tO1w4{n)W%-Ix)e-me~I1xti zvlC;SB)RmL&eYnv3ViX6r+#Q2dvb;t(j>gZmJ%1F0OooTD6Tqu6Ao_3lB$K@&A*|* z8*_qw$%1KU*xT{ODlp$D+aSPUw0KiO{K_)~fPaUFKf2LxC%TqlTt85%(>_zgq;)L4Fvppj|VLF4s3jj=mWwj zkjOja)R3JD%)-tzAMZ-k7!$0G{Sb9@6p2_XHU0o)pcl=lwSgW8nmXO;AQ=3<D+KE9VXMj9f!fXqS zp|)d`3O@MGG+*wd0>o_)!6p1e4GhCCp#mX-egr&h-3(EX5t4$%fU?>&RmPBxZ(d<5 z_NRIu-ollw_PZG{xyl%0hU6&CAzll>Csd${hwWO_j|`^J_oF3C^!=8qu`ohMLR9q! zCM+tNaQ4E5Dx!_#4 zA%b5;+au+OGw+Sl+^HeWJS){Wt^Gge&ZrHC7+ptdw#4Mgw^8@OO8>=aTcb@V8Yupg zItl2CO1*s3ITEYmrJ{wyBn75uN(qwUx_IWc89>?6VL><=UIefn@HR{b>OF=~@EajX z${LQbth5j-Tl}9J84oEgc!0O*38^1S!sH{zS;9E#`_Su=8nnAsts#uXPQ-FjZ2|WX zOyn;{bE6xG&d^~GU8OZR{(2?2epkI^CEz>AQXd^E6NIXT$o;0REe^=LAt}0Wzmx3u zT)m5n@A>JKCE`GO-Ab@^{;=Z1nN^bo0r&^aMQb$^B{0s84MbD1`A;uMM=o z1W?G{Ol!`h(HtO88Nu6a^YR9_;}L!IQ4Qz4coRT^Bvm1BxU}ZejH=9k0h-FRgZKc1 zNh&{(J1$9gCdZS?Ob}*#5C^F=$~SE~*Y*1@G^xO_?>AOJ7+^&UBw8FMAvP8qsq|9Mx zjCc|FEFNG^7q)wOd$&Vms)Czff)gN^cnF*mj1oo7rXY;ALUIGW9l2ITdt&r*P<#@z z+ul#8NW+DfNg8z&pvn-bk_y=fQysiUfB-0cCS?m&5A1^OUc-8XCT1*I-S*!Iz=-)KJ zkCSlKuQcNzM|wZtQnEfG*3XDy>jNj=OXtZ@s~?6ppjlngTZQFY^_cmpXXHyzu) zra>@QckRg^1wQFpmB$$@B&BV1J*HU)#RZw&>tluf&2{`h&0>3Zox@n+Hmo;EzW|1; z0DH$IymkZ3C_TURI$rA%NtqTIGYck}`6PkZqoM0Iv70h68u3jR0FPSmg@eLSUeIRV& zj%BJeOQrL+dmFk}vjq?i*qEs?EXCh>n%^jg;|Jm!aG#lKLc+qrz>a({Z`L^}r!!+d z23iOQ)o_ueFf;w!%4qO0W<{#oXnQ<_@#Mmu(Tx```8sn{3J(6;4C}@^othGvXLEJ1 zc-4;xY^L1NQgGA@ocF3^>s1g|R^y^1P#q7K3&n(RXeeo)A8M=>U=oX3^*|5nUyEz` z93@X!P#bIPt-FJo%s=%bp2fHuv=gp-(~lSo-^ikl28kKI7IIJxphUezWQvvB$H(kO znm~3o!2eO2*nM6|0y;*;dkc_(1B6UdRN#qxyl2{fess5VoJksMP%OmU#<;Pp1#CP` z5}RMb^H9M2;w&qwAqmcTmXRa9;9aC z>Q)cfyCPXqlLpe#A3zNfEqx1&1CBbB$gjWRgsyn@ZuD$S*u>eZlAZVRR?e&{TX?h)?LGAV8i9_ZF1W5;Ba>XvJRE@K+E( z$xwtcN%UiebAZ0a_UwgRoHPG?Ml};8A(rCm1%Qe~yOceG`sq;-DfaHev928eu?Vgm z?Ogb5T6T^}xd=EERvF*69>0N3(h2{d^q5^atZb#takYTp`Zol||NXl96em^e3{LA~Y zWEdyX9^Rn-VX$aH-Q7#WgP{JgKZJ^f3pP0%3E!%xr;G>p8CTK~r{+*^CMNFQ=!<%h z+`=@bF^3nRMt46}#lcgnEwI@?nFx|6Mk4sZH9W%kC#SQI%f%M&kh26VJgauZl zsM%#f)0}HFxf0+7I>TzpBN?lE*>F$m(BEWJaDt!4ap;0JhX^nlQ^c_AUQ+Q{VewS0 zonUbPh92h~{x&WlfhudlJGMov4eHwr_YC5?(}71_7}PiR$K~hs$)uT`wpjnK^0033 zINY;PH*~fA&TmnJ?)v3*4ORP#ObS}_9PeA6gmbv|?r%g~< z!qj`k@fdEVtZ6zklJ>3dpn>>D1y#bRZPY&#KZrIOLv*fC@Q3Wo^R8dhU$JZdE zQU$4o{o7H#TwuVSqaEKmmMS)0;TZckb~gcS%>yrqOb{_I9=CNY6F$FVT!K18OPrgw zyC%8+DQN1p@%QJvd7^NlE0?Py2w*=gMZ}*u9_2fLZU%Xl9A@sO%e!a6288CywrU3gyFXWLblzFshfuy86UM^p-KnrmCs8O4v^*bxAeGlTzGUA~< zb;8990_GW_pSAiA?&zwM)XFG9lmwWG6V)MaeLn%%rZZL+j-!w@CvW3K?iFiHi|hF6 z=fu2VjXm@m!ip>PRf0X8X`8_@KV^T}7XdFAduv1}{c0 zIlNIEl}$8^)2&^&U;$a4V3Hm7@G=)`sKk5B9I+I}PUI%Gm;Iig?#lL-sshtMF#InK z7+pNaT^qj9n!=O>P3IG2B?FfG?QmZvTV zjKpUq(rd+i2n9?~)MTK;)Ez3QQ}vsuHH3)e`Spvvfs=Xu9}`<=qKc=t5-AEDX)SFL z1{OS130nA=1hJGZDOS-q*>__u%zTeKaqh2X{w{c2QuyL1xK~m%ZYhZYcw;Poulrb( zFOhoy95}uyI2qJ`^1#e|T9r`x(r>;tjTjv>Y-wgjo*vS`&;#0OO%uj)G}l@~hvG4A z*p`6VxG;a~{XX^cq@@0e>d^4S4F}tuR1!*l-w%8Fm=8qyVPzw=qcpaxnexm73n|g- z|NYMkyRd^x76a&j*&ZP~i~c0y8@pe+O@uNxN^7u0t$ZHDi68`Nz4f3JS<{ma?K zp1M~S**dM}uW{AD;v~zCv~+om zo6osq17@v}rf}Rdp=*y_ ze`d0O6=7U}(+J!K2~$je3iI&_av!tWW*n>XpOZdXtgYCKLos&z)N*u}RNb1s901Lq zu*m!0zv$w;E272{GfUQw((ymJuqg-M-QEmSv1dSqWAK49%nrc32j$vj#8kn=35;<` zE*E(U(tW^WG#bO7ADtO4irgrCwBCLm^KUS8;e6YNZXE4I5YD^3<7@DssNE*hn<(Em zUbtuugNP=Z*_Ju(_LWYBnou=A><+{CH$=CG->O{b%)>IeJ1&J@%tP5v$l=P+X!tKo>mMjYi3x9F$ov@_zKK1Z2S_#b+|x@ zx%;*Up!x5nPe8?HID?Q>C=ra|Te756omls-4W_~J)|u(@4X@FKkFqYzE;G}?+S**t z>VvZgWKy+PUb@LU>{T0r@dYw6IapuQpT(4p5)T2!<#m=(X;rD@HaGJHll?z&`5b&I zfCJkN?9`$S_;ik@fUIl$8z5ycM|yU`vB3nk zRT-cbf;Rf9;=W0e#de$c$SMFKui1Gn zlNAil&96gfSi}~tab1mFSWS+<<7-hhQ}Z+3D^h!hLiQU8Sg=*q@zbGKUK=rbGX|{y zM_Urq0zpAB!`N+WD3btu38i5!4rZ8s9!fCs6~Yfuf=KCs+@|Xj01-Wa858*Sq5zz& zj*A9a+DLzAnqTt9ka35O6$`M`k=nB7{jU2Vx!>QG+mMY0kYph=5xsxpD~bY)E;`6Q z4u^e7=Y%2Lu+kK;94eh^!CpEq5Bw}~K zZ`O&D_nNU-*RHOH92y`s?y^H)6e#K2yM2lE{f4gX%<9Rg8kZEPJ<~$k`3EByFP3r+ z&Jk?T7oAYM1ik()2?tLsQ8`l|{_c+h>o;teX@(_LQlX;yULRA7H?su?CZeCKweoq| zrSL=d|HwKMu$=R@{oke;W=70r#=h_Sl3iiOjIAswE!K==PnJTY%vfeIq9Kw!!W0p* zB!!uYL`ag9jJ2XHr4sso&iiKGd5-@a$8#L-J44;~@Av&)%XyyHd9f!^1svm(=~f>b zn$cxHFPawj-YOvFvZ{mX`7Pb}-+nFRXpOk<&8}^!$<&xUrt$e2abqskomz8Eu}mJj zK9}-K0@`hzYIdGBX_D2v&GP03^$$&%!F0pq!?){5*hgOy9bdeKQL3v@>2lrh@_(=1 zy7Mpp`3cb@Cb8L2uyzcg{ag9a+T91S|53YyX?aH8n2Sn4iJV?gzjz{ZN6Rv6wRYUM zap1Z()19p5HL>u=)&Eq5;o(m0lXK22lG2<$@Nu0xGYE|XsmL*+-@qF^yOX=9>?%`1 z0@~Fz&F$t;L6vzg=cD1qmFF{MwY{Ss2%U;XSoUosn*M3wa-wLt5BU+&S3#u57t$;M7O8P^10OwfF z4``w`rDxvP)F}O}LSb;|k}p2JQ9AqS)2H6l{Ds%Y`^)uALk+_jrU4W9n#=F7?VF{< z_4=qZ&p`?@{BNg!!!gny82|T*0~6ePh8i|rOwB{P!9VQ+sD(PaWX!>3S7I%}+<+gC z>OAljG%lH^cFgdD4lbzWdWL6SsZzq4)*~GzB&=y4UdJ*STypw|$AEgM_ktbjz6j!P zNhuv2e|9z86_&>~s5ORCCB2$TXgE1~$Z40aT~-+Nep{F21qB6( zTM7jflKMCu&B4QEhca;BFbXp|WHMR^!`V)J+o<_Dv0e;J;!=G(s?zMVPF|0kq{qW) zsG~>ZqyGWkZtwH58w7MfWdT`&J}KXHop0DWlKMQB}7SHr9WT!%>nGVceQ<{qLwxv;UDo$?+z zHzVZKkFJ$$H!^2OB9|d11O0RE{9TFs#*kYd!olxzoGy1NlV%7pF%$BB&X0vWHU*EFCOV0d8{aeDp`i|LU;(`9H z_1UQeFnjM>B`1lrF|-MhN5Gwxh3O1e0rEIeJY?Zc&2 z$6Nxe;zAs|x;Os;!g%J4gO628VBHex+n~ie33Zbp)Q|XVSw-cD0tS9}a`BVfEr#v* zNpePF@gD%hbpE>==bs@=%&0h4!1PPBq0)s-2pdeIDEQ~swo|Y!4Uqh4gfie)D~x^e zyXxjdOw5;6s;qgu_SKaOcPegt<626p@914H$p`J{%41(+5gH-D5|m?Z;_6|8HTlx# z%p&f-Ed>H{v8025AsRa1me6Z+OJeBCHC@KUqn$(M3d)K(MQpT7CBNbq(IG5_zspa z63~}M)3k4rZAD27M~1w2b#4Q84F|=>;%Pam^4I}ge!P98+Ebr?UY}N8ZY=s-U)Miu zjQ{IfL1ORB-8VMY{Yj%2>C}mu;?N?jm(23l_O+WrOE284VXwf=ZLr6<Jq+6v4s0wp~0#0?2llvcnS*zclFGyoVJA z%7Fv-xP?~l8|qbn#15tF$N@(m%FSU$c}vM$uMhUq4$rc0Ib^eCQ0$Na1J2p*-RSW$ z<|D(gFW%M{caF}w>NjV$S)iS!(KMGsV=D#B`Ip{UP#}ZQJnICjGL8G&gAub`<8)MY zk7(U9FbYj?tc~U!4FOB+w09AQmwGeT)z$T3+Qcm>gp$^|&M+ggC`WM}$(`h8ICXW`+G z?(k=jKMr=!^wVSv8@sJ3J@+4qz!8~2#t2q-t0UC5B2}Jraq(BWxnp-e)}9X|J*ztD z3FTjH;ViVUvdY-+O;$Yl_}nLVd&(hh@?kSGOl4{ z(Rs(Mky;OxzvG;TL*=`2Z-nd~Fo46>pv7=}OZ&|(XIPa!Atu#@uR*5P*Eo^1smCtT zaMzKkO&d2pX4%Ka#^!$hNB?Qi;%5TFovW$o&@dXHT>dcMj8aD^BhFn4S3$mcXwVQR zjYI;19wcVgs}`djF&nZadR>wG1h|${X5F%QQu5oXJdjFF^B*1ezM=BmM@1IoQ1{w; z$_`P+*53CxXi!YUQF~U}JM!eh`K_Jy_of{Lw%Ec?yE|+X|5bjFMydXDeYNXf#*s|U zzVaFDUoWvn9NRt#SkbfWKiOZg=6~w=rd_7TsY(WH*~?LOzLARZdGzr)mzkB>M{+C6 zP8V#&b(V?T9E?yZHa(%0C>)V1LOa;EHQ!fr;}a%Xt*o1v0Rr35F1IKr<^0u`?QZ?> zK}C(JI9)-d-d{6KFg!N7m+4nwCx;;TOu-E<_;J%QAW~Cvu5~pSX8jsoRD-L#d43}= zQq}#`2k6u^YEAw-Yd#s#i0jE_*_>W*K-n@-JvAPHbAr~Ha;Er>O|tLX{z$VPFeiQH z>2CD8bL@86ewg^baM{Y_E-vz#BIwn?iR@m4Lm_*IB-o|+8~tSq`=cRKzv)fgOs0Ml=JTx`u}-3KWp+`}Qy6R8AOF6q!qe#B6M8d>x?{cSEm zwsXPtTRq|q%{h!o6iWemZrTuewVPHTT~;xnVVAy+-xBsXRmCFdT| zaY?I^4G#D!$-9qH;&uCyg1bbVzvT!tV$2?+VrQ5c^4{q)XClEJb^Kz6>3aee>3a&e zoje2LMZXWFdJ80tQ4wuNA3r2+nuj-q2lDqP^D5vMv4^!zIZP1PlH#Wa)$gM1rRJ5s zVc&q20A~7h=bo>g^g%JQ!J+KfgU!*8*Is?nN`wLxX6tS*I-^Y^7IE7S+vKkWCtE8q z&m?xiQ3+igdoluJ+pEYz4|6|wg9IE65$D>N1 zkPw~=A9>)=T!J-KZd=$F8-93#?OyK9WIVWxDbc^~j7v+>4g!$D;7y^{pL^m|#ctza zoZqrF@kF&wY(z-TdBE+G)NpUlL{FTGH5&T-dL4^xVlt3+pZuM()?roif{l3pVTu#(fKfm~%A(BmSil}ijfo+bZm)Alu zZHG`vu0?;=3o5W_ZOE3M-j5Hb+He2%qcb_)D9fmBQgO501;^REapS-C-cc>L9tU+bWu z5ZqGcI5V17`x?*KV?{UWGR0?oLxPjm9#5#*U>DszT=~c=xr4FR%BB?4QfzxF zFnY;s8O1+-ydL`S z`XgWV7zCVy0}yh%&Mx-SX*xF|d^{WjsmyHK3Os zjW2lL&Cli<@33Lzoqhd2#ce^ZzQgG@0b~TN2J2-e&h>U@OZI-1(Q~wM<@cnn_-z+5NCk2M4w6)#7 zWV6o;XCBx*3UXWOkya@82YyL#m`j1Me@9(?%DCC@c%+qKBR2t-$c^<$$1Yu_3Jh#v z7rH`IGa`O7?^4gbUbT;LntmKJt(;-2&LmR_#k zIcn^^o|>2gq!{#=)bsVxzkhth(y}3zPnXEuAb)tI>i}t!dBq|ph!&5={inITbM$yQ z>keKOuc7Uc!^7I+b9w^CT2p2mt9#|O8{tS;PE4Ts%b5&ngqZKn|y|3wo6k)6Bk-! z8c8;LSEmzN==76zP6goEeCJJU*_-GF4I0=-O>@?~`Le4g?0A8xNb5tH(0xd+J-6i6 zsoGUqISmB@9mbWK7JOUhflofj>b(m;3v`2TxqN8@1!IRpb#A8X?^0C+-xyE3EJKFF z6;{m5zS5ZZJaX2Y2pUoabuhu8Oz~5!o%@e2qyIklQwitFhl^R2jqNER2+Cw@xiz!kSI{j@@ouX#=XdbkP~0#h zf^#f#FH<~y+r|_Gh#$tNrWv-6J2Us~MyVo0aG-0Mevyn0haXuhO938i^sAW{_K=We z=%L`&`nA;sqP6*6f|U;vG zw_pt#|6iCi5_}yjUuca&83mC8k^*b1(N7s!nL=b1w$2ZqlJ3>4B@e}h%EyjcV|q5- z{CuHWa^cz;yQ{yA%~e(}nD2F_JLgmRi18ciQ@D1I6;-CRK6+peDdz**j&&apAqf(& zTwsCD+A53xBJbzm#5PTfQ?AqyA#vL}Vw8=Z6S7un=#{E$K~jIWoF-ed0TNn-(1 zHE#^=uz#m7DNVpF|MmXEqXU}~HS*1SEmHOB!G{LOOubr%s)U77+xJ+xtRUr0;THuK zXw07Ob;bbG+q1a0FIwAj41S}|tf=H9$6wkLl6qsG7ikkI$2~nyObf%no}}1=Kx)nZ zC=nMOyC7$7l-k)O)Wg%4G2-%2s{~5>RQK z19ugkXL``7O)F}2N_et?2-W#Slbh#xwH;}QlS^0Nz$rR3+b8Qd0F}nRBJbu-=No9s za9!+JeH@p%|9xb`26uMRVrzwEit|wP{&Zg%S=nz!(awBnGTw&bzs{!$=Pk-bLJUv3 zIagCV*`&=z)9_bRw?}k^J85NVj5z|Cxh!=_>CuHHk>XQu`>`u!BS$vTkYG0JKB%cE z4ax@c09e2BK;waH+8OhJq262^PxVnf8X=YfL$o6@9>V*?dhFL#DU+znCjm_Au}$#V z^bd|+dM@nMo04u$+aOmQ#W~Vx3l%%g;a{PL0qVH8=EirwRB6An&7*aJfuT^I4>?w$ zFP_qt5puoKTkg0$h99&GCcyf=aLm88b;q9MnY=(Rv|WY&cGBES2a1GKzrQ-nyVEWq zsX_PNuHUp7h$f1it(1f}y2lf<3TcUVqe_swc6PAO&96xUbJ#gyHznQkM5Dwm5IRh; z|6S0NG%3eAn|!lWeA?>DItxZV#RQioyxf5nLM~UgL%J%OnidCVo@I00& z5U#p~n}qc(kROrW!`UQhLtU0aK%AI$*B3F^m?2h$YkC%Enc0;#YSLuGh`QHGX&#O1 zLQC(SUpIt{Cqy$lW|a@S%{1Bpn>k}ZEIDtFs2tSC>0NP>zZ!ENE z1Avj{uaisTIJ=CRom`knI1pp zdja|qVbet6nbHi@7T2_k8{6VLPO~Ny7=~M8&B{qEuZaP}skEsyq88p+kz?AWBGbG| zNe|T-oEZlAp=lZ-*am#EhRQ-=ha&<6Ei<$>7XACn|IanNXb7Yr(lih~8qfb?R5uU1 zx0*+d=AmENzo1sK4;M-;^Pxqry*c!@(8q}m#fkCp@d1y&ohysamq2mGo7C*=VuGi* ziNGaAbQ0k*UI;B(JQdb`#<|bd1lS*R8|1@;P^~^6@npN2;|bDmMzj$KHN=^FE$Kx6 zUx)xbmz)95tX(M2kSnujLdeghLt^Q@}L5lO?;}D=%9C$!$~^12Kj( z1sNZid2}`@UM}mQgEzGxnncI9PXW#r{t+GDE)ih!q1UN)H-n^;=6|g1wuk||Sa-7c zpNi!8zY4~jg;seXCuGea#2D2`Aoh}l7Z@w4@c*r(8u-D=>=3hndRyJYz`$0My@%W# zwWX&|0gbYbiI@NPHCmo-!fAn<~nbNJ|@$jfl<9OL>F`=%^ zOXuk2KmHeDlW1*WH1s6j7j-TE1RJiQ%DvzJ_3?S{o;Z(*EylmFRqoF{e%E}+X77PA zwBB)xB?<+STwXDDBr*T(NSrvu-HxC1xP4j&P)~*$vjr7%`9bC9UO^Y2zRAn~b_Yr) zoULYeXBe7wX4`lO*R2AwWwJ$sVAQ@!F>>dwH{n}HN-zvH`iN^{D1>T{8#l6=X3SN4 z6A3BfiC1qw(rc4?GT|@a5UqC9wgvI;3yg+g?M4lL&xx8MnW6!Vd-a`qRd3$Hoyi`x zCNhApn1zgaa=K#oS$BUDJ~ZoI!h|=YuifgA!jHHLC<*F0eC)!fOX+MM*J zBDIZ%tWU%oyHH7=Y=6~WLB>Y8R?DXG!^m;fyMAQ3IC}XS5#AK1wR;{{X#EZ zvA=eNYV8ZiMvCm?F-Mn%8Wes1q$#=D-le>!CZ9C|laOWo;_rWCL92c;am71vH`Ux= z7Cr{Ppo%-B2aB`Qh#OVsx{-RdIJs4}C}eS*34rE}U+W_pid&w12TVH8ibRU;kT;tP z7u~OT3njgd3zO&@w<{*Neb9tD``U4V&@V+xtOgjK?9o_HfAiB^_6pU(fTiEYjb-R#)(OsMkp?Pg1B9-g11NdG^ z5_@LBh}I-wc$mwaySt#wV77Z0d(-ZA`cM`cOf34TPJOstuFcVhbAJesuB4 zbZrx?eP100!P9Va;IvKWxAcmo>nB2cbE^J`}V$n@23>L!P?GeK8I1 zE0NIJrbFsP$Ioeren?!kv{$1~E=-H+CYMc-uvC#z7yNo@U|QWdIlg0zwh9Hda^8+3 zPMj%I8C>5@n2$#%IkyE%T48>pE)Lz%|1(kbG-*kf$EP-cdqh3~ z6+b-x^hSxU=t8BD88D0w3e(uZ%$eVrczAI*`9|Yf@`d8PbQ(D^JN-yRs7+9Vv18rG z9}l6fV-{l=C%;q7I;vvDH@@UsEN6jH;4!z2@xZPGhx+H)VP>xUc?Fa4^p7fR>kz(P zaty1oSI?;cBB!s6wL=@FqL5o2FlTn|plb~)ep0Ke%kw4OzCio{zdD6pJYWZ-+KIiT zhT&(m?pN1&9_k(Xj=tb_$r7U>RvP(0%~0%{!nTCR_-oysJfMHxMxYv|+OY9!Ro5V- zr%c5q(>ibSt{$ZC0}wO~p0$qQ#O*=kI7o|>88&TgaravYsT5312u8L61xPz@dAZ(Z z-qZ5s@ZF>zyni;)MKv8jf*eY#t}Ct=&v66)Ix;_DWBRe#y95fM6Bysi`HH+`yfHIrm8}*s?lqt6Un%T?4_$6Yh?*6%L%wcplro6w0qmOf zt>1&d2H*YiP`iCVC7KUF1A1lp;&AC=LuUNaq)C$;K6okJs%NJ@SbSl6wtOjoLs2u%Rmf-0|;igg4Yi`?OeaEkW2tEsld7QzKs^)stLtqhg)KohZj6ve_}HCO^?(UPn_7n4-ZZ$S3R6 z^6$ToD)&^@&smk3ao0-q%>Q06E09GCYCg>`c2{Nt$5Gru}38|Q{*&SlNvMd8b& zu@bDDmF0ps8Gig>Y}A__p`kf+kwXCzz8^nc(L#*Hq7|XGCr+F&u6l>eSTfBrju)sW zj@wmGW*BS71bxzixtj{n&C5kPw2fv^ihjgl@Rm#dzy4|m%KCM3oIB0GEk*a5_3J0G z;R=nd@zc(E*xRpd&5yrowHuEyty>J(0eL&2e55@4n1k$BKGJ>Zo>{?C1X7&J1v4Wg zt8%Tb9=$0;qZ%z_u6pidj?a<^{nA&>SJqqd?~EHpN~?@cz!*?y)053(yO6$>C>&4> zdzBqN_Fae}L-9JU+B=H-=!+ zp%83>ubByBC6gME_Ipis z3`KN-lzE(K6C#t9_CF=Bw0-90_6X^$Q{yRyEI$hmKun-TBy_l*C3ni^k~35t0O~Ud z)*LhBo8B)bJBpFv0@G#*Sea>uRRwjny5&c^rPH3?nId%#y@Xf`I6U#bn{THrQsdbPIP3jhw;!8gu$RmP*e5Y+Fh zJdk6uapxh~HsI+)X{FG9^m~#ZFuOna(2*Uo8!i01=8U&>y#?d${|5NWe4)`N0}X)> zuE#7mLMy!s+`rnG9*FrMW9-GD9Uiv{UR0)Y@+EG>s;M_oy{~Zz``2q(LAMT7GU;PX z!p(2WCuy`$s}cgnP&!@VZA>wNTZY7UW3ZFDePlG}>H1OPs`cx4Gwq&D?jJ^@vh6Se zkG<%hcB64#c5Uf`4?q5R7`ay6{QxAE-?-IliT@Z*fc8N27wnG5g1gC^*ZcO;sxZfm zqvOA>Y^45yEg? zkw&ggC+5vmv8>kGR4h;YFH0W6D#eq`DLtfyyhdwr&}T2saQbP=xs(W<#&z%d9aV{@ zJH#dgC{l^Appi8uN+y}K9jfz?$>BUyC0=3Gn$rRBx?%OXjR!(=T^SjQWyf&j4$~hC zdNS3Q!u|hmR)LSxlh~yq18V%A+G8~^@*fcH=j2m+z>D76s#mJs;oAV!?n=Yj%`PyP za4dxV{($^ZBoWPrOYJS)E;2z=QT)TtZJ6BVpb1(GElS`FoGiItlS!d7Z;M{1cfyj( zVk1s=Hr5s{q4FWaNgkB0#nsv`?UGjfBmq%{QF<;zr3^Az!}Ti3}3af<9GE| z*Z8L5l17boB$md{zqczsF!7Pqf)3ALhj*&DbbemxKdn+%cXb3P7WkVTtsF4#B;7Hj z%-8^XD*9iO4Q1cq|Dzjo`DnTGJ&H?9sj}z{~uyR;_Sy z;;Xy|Gcu0vBp(46KAjtZt5?Q}`F1p&Xns>Tifb`_yY0hiPoOVSB1O!*8{Jk5oEX%& z^7Qs_jn!Y%1Fv|qw?V}L_$x?Ig!<^H>n)1O2oAzASCQY}b>2qyHth&7BsucIwdKYk z-mqx-dnN!k#5V3(9eR^g5bs^<*RL<_wXR{m%KDy!wyRhZxs2RccPPC-tP( zpaB{k$wtq?nl~98X?zEUmbNC3?|B_RcFLRpVnJu0%7CFggZp8341ObnmN+ax{7Y#NhAlgExRUiP8oEp}2I9va zQmUN{qprL`@4$1hxn(4k{CZ@i`|CIu>imY|fFaYJGa!WDI>AvMKm??ICE^whS;Lz# zmd!twHFyAiU1a1cY4M+bew#cOq;WEJehUN_rekODXj;YOy;kQ!(0kW-+G_&?-CSxw zGGlhom#do0l^t{oleeveApnMfq4~ygIWA-9+h=kJH;=BKn@93qc_wR3m;h_qeU2Msx?Cl^<29YS!T7BB2b-{*O4cpr{>GAJhN(zeqbQr(Y zwXs+9Xpr3$>aWp}ZAp|67qiZp`p=tRzJ2lWArNv;zLJ`UB*jZrngWI%_4cLC?fdqI zJ=GICaSC3IAaXlkw7xZxvUe|kZohYb4#?}ylQfcFwe`Hr*{yJ0RAF>Z9zL>Q)E7Eu zVqtF9e)lQvl;<@xO($1Sw1v_lB+r#BM5;p&%eU{hx5L-(eu+MeWr`p@mR1nuljl;* z^{0??T;1TifB*P5|MSN+)|tZgDc!Lacp*cTq8>Lwv=&i4G*ke z=)y~ZV(n!-bgRC6cT+4s2HqXA8oX6`gL;hj3jeGY{q1`_`^W$N_z%JvqBr}UXj zR(lVRC$F^|>aSR{tcY%QaTG(gm+&d#q4Zb`g*_D_*=Y`D{qD-znXatmP42XI z&*|lf(ra9O*8N0Hwe5jrRox&<<#XloJ(=+$ww~X1kc`13*gt){82lP@Pj{$upPP5H zy^lx=t;Sm0%K1vcXnhmIywCOO4Svf7D2pOtZI%0~Ec*($kw|w|o9u64E6$+}oE8lOss>fXST^Gw3&Mx1$oT1)$iK1yyqjxM^Yqh|O znc0oc)Q}hqmA4z2{CPhSGa(WNGC?B+{~98r=Z;wUSWy&xBk?p!HE9h!8_nBq41#Z% zNYM|^+QOj5AK+jnC&F=hqhom&sD?~9nEu!+tdG8f zhYbY{tbx?S^AqYm{uMQ$8aWX2sO}$I+E7cL@xPn6w&gm3W$4{%Zv5EbcWVJBLbHME z9tn=p&cbz%OyU0bnYfLi^Z8B)jcQ#;xt#X*S`MHJvqdO+bz7eb!U1YmsPpHoTeof> z1n{H>|9$afHeB){w=`!nCA^hGzY=S~3)EAH;$}#5(kA zKOBteu*dChsJ;KpY4*ebel#=Zvvouu!BvZYelvo(KD(vu4RQIr!%_53_VjS{Yg_5g z_Hf`F;$Lp!2ux*GwoRJG&{-h3Ik>j*4z~NSi!oa||CHgLs&N8@0rMAfghZmLG6k(G z*gf*3%WuFoyDqXdW?+TNwc0hiP*+2)N^Zz+NZk`})G<8i40^wb!qdC#ei$EPH^)_5 zN&Y(bCJ89JAm6tvy>Yb8DJY)ZNz-HPebac>Tt8#-P@5t_eZTjtV$FVDXWE=Q4)wY= z!U_nNj=@P3W&vo5LnxMOuF8ppgV}{qF#-HLVp>eua~jeeKv)0Xg_IuH7*O%vl)LwflSYCdS7*37l&G)p`lyd3w}@b#1q#*sfaoio#91%*QP9#t!4@Z~B8*FuEqJ|FoK?Os1AbY$JC7-bC)0?g(%JAG0<#aI`CKmF@K^fk7Drv7PSS`cXl_kQHl6x$Zf<9xBz_V|#8+OqT{w^#zA( z@5&!q)#IWv8Rigwwj-I2I$a0Zp_QC zbq|d|p?rK8>0|t*^BUF-GZw{yR%$?IZt2?D|O8Z(UIYRiMdk{Anztse00AHrYzL{`#{2TF~a_S}Q zClsXd5XJZLFe>*7xb~TH32$gr)F;O8HN#XtdNky`N=IBNdh)57uIB>>iGYUI2w(YL z7onqHwi$Ijr`lkR%A>grUs=xJd{NatL7Xg6qeDKH{KJ_86UjuX$(?aat|bT>vSpKl zw9`Coi><6Eh`P*TKDc5+4d=CddmHwrKbH7j@QLS|R!za=D0GKoW1^epMJR09DaW_7U6Q-&=ZV+4jhDiX^y>Fnj3<9EZs(JJgL4Wei%c)`GT@wV= zv>*TXZt^29z~Jve;zuSi3JXESdmv!#u|pSSobERc5}!LJWTK45r$0@8_q%yd8gJo;AL?#w`V3=!HrDqp+o(KS z;D#j@ae6l{3Yb~csS zy)c4Z&7Qp)!d7TM0d5!H9hq^(w$-hbon?)yUcv3{QG-o&S*hbEmIEdsVTA z7+XN{PWmu?VN+A;ae$d9p5P!g0np2uRAI31t-KsOuK~ zGeaQ5nS@^V=*I;E1`l?iUC^pw>)BWtNT?{W3+##O?TtbOc}>njnf&lakz71b?l zZkZLyP{8`UBaMaVR|#ymg0?5$^J}%0c`(qAiGj^Ka*|q}cQtZ+?mcra<_RaJ9BaFP?)f=)jr{8*-jyP)DiA(v%II z#?ghn3~}?hD)t=YIc!M_3wgDZWSdJN7}dSJOK={#3) zG0l;rFH4-=I67mWXq$+b7aI~^1>9vgg#DVGruV#Q%?D7BBk~=aGeZ{|;g0SB(}c6K z-3@+EmGdNLg}tP<{!x7|nEx=!LM8JyZQ2Ybu8I?}x4-(jZb(RoXed&^Alk%bj{w$G zU=Iho6L%uuPq`heyakB_!-3VnZuO0jT3m}o4o1D;iNCP)o8eR<_Zg$t6|+cZEgcW0 zO_M0i9*LW(cU5r{lK4T*T;~5wCY5o;&U-C^?v+6pFJv%^#XCgFOOg6>sTL&+V?<%KUx+6TqPhUOW? zqmFKQ^SX2@SFugn+W&3?uK<^)0-iOI4T&>u=!qs8FH8&(&1ge|s{*c~0( zvvaqGiYc;|+)ys>0Vo(0Z0_q+lH%T#t{W)7!?<*UZ)lg|##dBJbo5J8S#gea8r%4T zJ*;-IqvRz`U#0$cH`5O6&_m-pF1rZ6zmvhGsSj4OD;STjyPn(k}Pl)<2Ja+t&EtlFBy z7zv8Be`efs0i?7xH9CKCEqea*P`MeyDF%0l#p+K3N|MpJ+rdv?q^On$k%*L?3;MxF zaSx*BG!6G;#$ABpuT|R`H$9g$YfD}|wyQjKb z&N$*RIR_@va}s7ej~{&z220cemx)!*`!ji!YUW|SYxInU8}Me5SN18*@b6oeRKYNB z83$hVn(PYBdx0K0QJc(3>*>@G$XEkIVsQpKmWNpQK}Zk%rFTjyU&vqxH^H3kzUB(k z1nojsw0z>-#30c|N=D{3ft^Ix6D({AvGt!b**34rfUiKul)B-aO-HW{;|fw@0F$)< z6kB$&ykTCb$Zl%NHVay1ajAI^R_h-9Fjb8@Al6GfS=8_Wu#c#H?hdh|538XrS+|YZ z!97sU6=d};q5TYWvZ=*bYKLsdi8Xd!%50lV397MgEV@bz#x$y1+#PEj?M z>|!(&1(tBQdtfR}1$vXiG{rk$?`{87mFLpT6dFzuuA5BUTrirEElQiTxNn{9r0`=5 zw2vDYP_+&fuIU`xb@5~NwJ#1uml)scNSK1Ssky$gA?r7Uyc)YynH8G%Gb2l$JriZc zv2Kj_0O?LtIovW0)17)))p8R7#Qfi7nrn7#L&X0Kb+s}~n% z@0^MXRVd$y1~;1f<)bAbZj^%nJO8{&dBK&n9(KGvY1SQ;I> z`=>{#a)3Y-j4u22S3y@RO;3ybjuSSVx!VFlis{t!{>oH*w(E~=6do0iuda}a8p^pt zGuvzH_!w%yvb%Mek=e0crJJX8s z97UIvjG>PCmWp>MfK|Bb_baln#fLt}xpu`e7s{kRhVA@Cd+~rafZ%vWy}$a_ND;I< zOTo4A<-Tkn+td5|<;@S^&UCl>F}=KHJg2klso6tHl82N$S_EH+KqAPiCir++7*S4M zG{aH7^m#Cbf&qnG`#DWkz#;BKpE827b2vrE{P59V&B@QS()_cYFYY0?ua3W`usE-7 z@TQ0cdSkojbX8CwMXkIkX?4TpjDLkv8`RjCXaRg9e7*9P8F6g!hycu1kN+t1Yw&>XnAG&p)gGw`Hv zw}&xgc#Wm31<3y0uAJdX5qCF4T5O=gWr-C(`sgyR@LqoYjI)+q-FP*?LQ?+C@T_w5 zte$};z_A_5X{OI|v&!4gqC(=#y_R4-{MI$kQhL!%2LS2ae=`3~(S;kbbix6r>6!cp z$A~)jTEccJ$KzB~_7F!63)f68w=vgts2HT^$bhv2s=oK{wQMUy55%<(N%VlJQ|)4+ zwLMNF$m$5sw>+tcYLE-rzTN5v;!e*@eEsT`xy^fyFX_W|9GhENS)G|kJRW58zM=Ph z0W3&rQt5Ll1!*pp+>^M<`Rsa93F#q>(qDlqWv0t&v=M(0Q6=9&;{G-vUN9xZjqSj; zGfw)XZ#xJ~EQgn=9u1Nh$IE$=hE%Qk`uF!S=oi8bX-NrvX5!|B&jx5X?N57y!F4kw z48r4%WF*+*U2Z#B(FxMWJkRE@v!BdWxk=3j;Qd3{g|cNZJ_0&5cmx{ljkA!1GFHHp zOg`8`smc*U?m0bsIv0)qh*p5HVu^BO=b187@9OAhCo8Fw@VLZdV}`wMw}p!kK&a7J z{Ig}S#Ro=h{qJ#Kf^Df_Aa}dv)H*VjeNt(JLVL8fl3vn-R!-{1q=KAuU>IwxuN*6o z5r@S|93ennCc@L~nQ_-1X@sQSS&J*=#c~!xksmdubOL-o_r!*e$kXQOjpRNbXI_$O zyj6J3)dqt}3m{)d;jFucY`MmnvlxDQ?qPcIFxnKo8~T}Xp2i6VcRyp@l(kjYaAB#S z9~D18elb6a2iR?4)TGPX%Qsn^#;YKOx0Hs%?g0|0JuG@&zXs@Iynu2-eOil(iT=Cd`qu(nd_AAaAYvl#Q-u$D&!MYpquI2e07iz z9i3927v&e;1QEN;V~Ak2x|adwXoj}@u4mIgIvH;t24xwVba6u`YxKtL>wmc-5Fr+) zZ7KmjsAn{)PgKX3mvGvu||{j)q@EDc^VLL-_DU;&guUQ#S}A6g#=0vFn!>qrhcUIdPb_Ltnx0U zK_TPg?gLcF$6iRIor=bFWAR@^+m_V``-y@Zua~9svIFKHgeZGjdnKzsRhXvt(SS_MGSgeo_Dz zI^pF_lAp}4ziCjdG4%2D8;52Vn?2N&CUsGHHgv=-1n!h+8K3pulNEe16-a+CebxYv zH|9EHY904U-UQn@Oich#krb}TDx7Pdn*&$*k`X2i{Yv@eu&|&#HIIh)79P~RN!HtE z9MsY09 zt%4?Oz;+Z7)}t#KK;4Dz4KlwNB7q; z!mjnc(4+*C^{#WG0Q00aIrZ}iYn*69ldxnxwWN{9HQu^CrUu-_i+euVMKpf!N|f#Is*mlhd+SuUMNcgRmzBjTY_vO=S2C z3T54Q*}izLu?d6rVrXMK7l3Oyn8HyLDJcgc*YvA1|69J1fRvQOQyr6kby6>?nG8EN z#PVC}8cS+FbK!S@7k4kEQTNMhwS3cOJ%NgXdiE)I-s%yUHEq*S8FWAs_o;I(0FXqx zGX3;C*Xh2XuZ9>%EJ(w#S@<`v)uO)hH6no}jKEM*2Hebkgl7*m^+t;;-Ghdha0J@l z-62pIDt>rFDPSyKFZ)NeG}V6xPb2nJ)Z19qp500yhGZ6Cws^pasvm@hH>6;b_z;oB zA3`=j5yife`75Q%mZlDx|0fdfrg9bRk9yp;*HRE8Kge&~;q(AKe*)NkW)t!*(`b)kl zk{3m8P*gHR42`ZW%9ugv<=FDsl?G4sF9+ZCumk8+PS&D(Reu^lEu3XNFg0K=nP zM*j|XPq-z7QjKj-pO?+RS{>q_YJy6mRh#GEuP$g&Q$O3DV`3)(723ldbHeoH3`Hh= zL0m7niK+x!e)5as)Or%ftMTi9-$%7LUPblKAvBIKDq+gy<%!3-LF8=h?C*cpZglMz51a zW6NHylUH-q9kYgLDT3fCiU@mpuwv_m>J6@Ndrj_y>9haO#u z?Hg?ap@W_wNt8psQ)55;@WV^!D5bR!{Uf2!G|XP2b)rKk% zW1q6{db8!`vTj{2QLU*01ngST@+}dN$dYq`h&ZiE@YX^b!oG&ddG4p|hFBSWKt-)Hw5~HcJ^Sw>JqE_^JXggC) z4rs1~*F4o-WWqn_h^sI1B|1x8v%KgvwV^jnBy;=1dwmhl z3&f1!k z!WpU*tV|L&!lb-;^)u0l@?UfGK|O1tbCt$GSbF`SB00Xph#xYKk>x1$T??oEF3TPO zR18ve0x*|1>D%?wAW(Af{Xx87@C*LQ-(UIa5b%9ih-kPP9bA7B3=i-GVAMqQk46&v zxIq`m-EGXst-21DAH98R-}8s{H1<$#u8FXLuIS}j90NF-;8Bu8X3GJipi=&}B;hww z&j?zP10p0nzM#0uxqcvIY2K>21wh4rXl4mNV7K)u;;3HMQVx;+cC>A=+b36tPi( z{nXE&0s_JUPb_|2W*;XJzw)yT+*l}+Hm{vCk6MH9VdMD%UE0&b3$qM#lkJi?M3}D| zS8DCQ$i3N4ny=Bp$f%I?D+Q^`iK}6%a&7@{)?n+!nFqglSNUL3TMPfd=B!bmvn*K` zi)VzFKz!n2mj*RPxiFh43k2hrHG}q!D)>7M?Z{;AqINLD0J%6VsJiF7DNAJCb^X!95F6vgk{k7+a^^f-ghWaC-kp|5b&GkoTlBe`@zL?fRmUdsX|m z>p?n?q(C_Aa_YTx`Fp9GWhlo7IKHq;BqRT!lgOKclhXE&`;n+IrMD4x-1nzZQy5nk z|JX5aGR|k!0rhK)+yb?vgdF$Mca zIfRUqxKh=FuF6+fbi(qB4%`dGh~=A}j=)$e-8{DFh<{z1Aw$$G3X!%%^c}H!)L5}LY@TLI1xqFWs!Zc^ydSVT{2YB>ZTozUBKmm3B; zL%Bqqo1s`X7#z16JEMp$<4(U%LD+4M7mjie(7~sEeiBB}?Do)yCsXvRhiE0@;&``K z>%(y^&;mkZxLt}Q;h(Fm4+o{NFW_-z%t$EfnQ4RP?V}a!_PRI$;IzgX$u;~;_rT9F zde*&Pe|2z_b%P4C;s`Ea%kQW49&zD zaLC)F6_E$0@booBWBuaPb198gX_#Ic8rvGC*OvCSo^}#}fPk9w&x0sl_4l`+43u(H zmt~g1tg8G{RA=mE(BS*)fk>nzpxmdATJ!JNOIc}KI>6EhN>*)cKsf<41CX=&f?H|E zdG{k_*)5R|&t-L0L8&iZG#a1bO24@sPlS=$lcDO9WvQ_zM-`Tv#5GiTW>oj)>CtWDcIGEeY?5Tj}+RC8^6AtPi@a+@NT-j7OJ{)Q)9P) zTA>LVUpS*G1zIB@FMxOXAZAC4CInDjf3iZRPzWHcm@^N^bgKN|XcCSN)j_m5WegNg zM&N3-=ghq@Xf&GDOIhC*?*#$m7}Akl0*D*beC(I4N7xea>mnyv}dx()7_@%A5>P7I)2Q(7{XX8GLg2voA;OrLfdIH1d7=b@N-5 zDHRQI-Ay6H6Rmmy>YT0%GnF99{8su#QEMj8eXBOonNyG;<4QLZnor`0t1JB!D|*^_ z_QP_HXZJZx`K+8*P-c||>g2_>viw0a6Js9G>JOuSt=)4hliIwXvvIsGY82t@7=m?~ z-VdZiWBldo0Z%3>k|ZZM5_K-~LbM*!_>kPc2X+n(j4-mQpwDX} zT&hE`P=|J3nCX6GD)NT%O^nxwi86lplNKWS&_ZWjT>*np{fqLx!X1|-y(%>Gmj)PD z#10EJT2zZVs3`Ggyl>ow%6?EzKkx^NNVx_=fo;Sc+jnvl_mXUvB7 zusRb|Hfd$-5uDTLnEt*Lgp2JJ4GPhIykpS~ezSYNDISmW>V^*KNFCl*6@!94afM#& zCY8?eq%FOC#|WKiXN=(ujWo4iYB9g#Fh6_OgW}>R@skePZ0VVCX+9-SGVt3~ScyIl z_{MSb(Nn72ocx^jZM-;@LnXc4G#9kzIlrw_GeKsCkf-PL!%zGztGu%t!9c2as1Q5% z^-E854}b2TuhC`%UsY<=ns(iWKUi%dYGT!k%@39`LCuNU(4nS>Jr{gqiw`t2Mh8>X zn7ZdJ#WzME)v`n=`;M-a7tP>p5F0zYUelZ-B)L)PkVtFdcYs<;!UH=u)RBW|b1f!x z&T2LBm&ItRG!Ufe27dWcBaLz5G_77+ik`FKM8O&zDwM^$AF27G_!OZ_3$ZW;uyC!z zpI=dgnP@*G02T}P5#Hg8>e20-AVbXb9t^nOkzt;a;wL+qkMiqLD)WM%9`K*y64#{peI}6-zye2ackm|V z_-elnX{=xHRE>zrzV5TxeX{K0b1%GLXL|RQ-Vpo~mnR{)vlqnI&Sd#Vf%#Qn-c$V={hdl*G0823ZlDLS1|gh zRd<$CNX_*s7Lx;EmE9jElKL=E3=ST;y0Ic=<+6iQj-=xP;`ZYg`rIC0jr~n$C`5MR z=tudX08$iM(kK>Bn{nsSV@FNDft{)m|M7GFQd}#pHHLca7Ut2?3=g%be&)e@Zq4xj z!%e7m&ml$(!lRcdVjX}$E0kem=U&hQgg{XWlY3ZZAiGoDyUWc6xESK7y|I2tJj8?o z4cNI$K_EXgWox!slsjmJS8nAkJ58Fux~BW>gokA+h2Efy1DbMxB9%VQ(|?zYKfyg} z^}L01Q(<04dfc~s(RRlDUd4%oqG!#fxOP)_Tl`33W{OA60r4yXFSs8`-&@)EKB-t1 zuqPoLG0wvPAJ}ls#xPNEJHTgiJ(ws$MdfvOg*Y&5gpbErV@zw;2aS#XB^ihQ9IRG7 z&$K#OEd=2q>0qmQ)}<1DZ5S6&^ay9BnY(V2Uq9KhF~k!fyj<%Gxae)tgHkA@&hM$2 zz;1>C8c3~IF^%0e+l=%wfKm0%pLpyfl8XwgyyX^dBc>bF^;hE!vRsKklx}s@NtSbj z$)Lu+j@2CWitF-|29h4N_hos~T#Tc5lwFMBCozhc+vforM#u2AmtA~+)Hw!O5ja({ z(Z`K*Hoe%H(xH;u&qcl#d)(&}t9Mqbk+t$3q1(C2x2)Yg7<@!)z{@w)cTD53x?Yz< ziqR$ef?0T$O*t7P%1+R9-Y1&Qd;EONR`#ykicVBgJjDArCL}le{`E4x5JX$;o@KZ{ z?8bP~820_rq+djFdgi`9I7z47v^p*yO#IjhNtWEu-aeHdO;3e_c;w9-TXRj%AY|Ds zc`HL2#`&non;dpe6eJ7-f(9UU?Vw>mL!#T=$BqFVk>K}vP|iVxK9bajPfD0Ztg+r$ z5L=j{OUThPj~#vQ^HVfMf)|F=v4Bb`IsF5F{^=)=;zv~ZYnYHT9=o_NSG00rc4ef1 zvT@H@uQU7ibWSOZy`FY;)6;G*9)wpkvi6-B8E zsumyiU)AKp8Xuhc+PwdA^ZviDtY2NFdpP$|#kME5a@?xlR3y8&pG8S$B0-R+Ieq1FnD+68&kOqM@||^$vOX-YY<#xk zsKRW=SaxnS1^Qemxrg+eL5}^pK3mWc5EItlEZz8h^D<+?0JHl<(t+)Osz_bcD(=fC z@2f|wH`_%az|ZD32VQGI_U>El4h2uvu_yg#UKexGGdTl8OPCU5@Tp1kMdUBeG(6?I z==fR4Y;=D(-RSuEzmP`7qfJWEPJO_R8vI&R<|Ju)|ti(`|4g>Iei?$s+UsSdGxt)(4wi1V|^y1IgV3}*Ui3{GvchU8HTWig^6gz0YSAL8q}rtqJ*-G( zhe}%+f1F{InVF82s}q#N2CD^8DV;XvQHOJD*S$59CC7{$o&8BhtnXN=#KXDMC?N}} zzpI&!zIMy^nFVRoCisF||F5#9)T-_Rqk2A0rJ~`{Uqer-ckmSFTSPKLg-~B=N zCSQ8vaLB;2J17v7(a=8Xo{nwry`(L-c;)1yP=06ifak=yY5`_P8}!@!vh?BQhGxO~ z;rpwaK0AQ$0CCPKoko4bBh^F@n!qqRda@&;Y2;(%ZC=Fdfwd?Qm)BR#B!;J#r>*E3CU}xJmIuBmUX_L{tWZcJ&9fQMh z5DCJi_N0vLlQ(l25V|lS5vbsm1sG>1T)42ockTgdpXjm6FEfxuHJJGJ697y0*l3GZ z=gYQZZu)ih6JxT!^brre(llf6dv|H1IuW8hL0Tn^A>ft=n3fmfs-)TR>0z9>~imrKu2DKQ)yxkm{zqbN6~Uf(|s0pc3Ei^)Y{ z<&vlH+r73_V*26#m31CqS=R0Qzs-KU^?Ok($Lj`5Qe2U^2e=2~L{Z5>iVBV-l{6Pm zS=yVLgt!N4iW?0v6*MT##DxPyTwsaHa_0bq|L45#2m8J6pX2Dz@Okd>9oP4|&g;C+ zYp()-}$z5#!COoxhz%~51B4M7_JU}QR5wz?nv(pA#7rEqP0d_0QR5&}6IN9}SK zn%Aa~O4=j~dj0zKy%YCcLrw&IbpRTh+8CE#M(psc2;|JEcqQa1ES)&x*LM1gG715j zE+Y5~0%^+jFjX$#yjTkt;d}^4fg%^I*xBJZW1CsARJkzGSFH7h+hl``sY) z$Upml=7qd<%{cW@iT>?;8DD&F%E}$bmp!3X)vIb5IUik#NH>Y|iy=`= zme@wy&);u|AUL$E&BSQJi_`+s=l+52a9&aFOd%|29(b+;i>k-7(6n$;uVbe#K#3?m zne~|191?chX+J{{!r%{65mK!-$)>ppE@z!Ib&esy$(fbiMyhLP*0oLB+%0)I-k9JO zXyw?JGj18}0LoS9^ttee(t z5^--X0EPT%O3@l zswt+0dhdC8urg!V4I;x>@YHGRR)LP8RpC88z^P@+mKBZCQ3dOf~#=ggWFbrO2|h&Mtp0t6GvS;A0%+#UVITSA>=Y4n@udJ!*)OAE$) zGZHt*$Xg23yWlL@kn0=Xx8(VKJDYESfAx)T6iJJ#ZM zL)3FPy0OwO>Tm(oKQ=Brh}%i9Wak8~oY(~~ByY}{=3#FG)-oTcvSvEP@-IdcYxNDg zBD4r~TtLPLeLV*gtSWHox%;$41{c#3LpgCuy3H)B%Td^y@A*`azvC>m>GJFPf>*G} z{8XcliD(_sAJOM|S9FWuN~VQ6c$oNG!Yk&Ui4Cl?=FC&i$W<*S`9;-yJY&|Z2_Wrl zLW>V8i^4|1mwO9mM!fyh=3K=;hPsBf)7IDXud`3(zctUEXf)DE=iI6?mIbUT7n6b} zwH1Z4(zAB$+ToiyrFK9Nta8A8#n!D`ndvCyA(?n(hIU8a3X>y!a;rq~Gd+RLf7N0Q zlTvZ(wZBx9(`lqJ<@`~t59c?cvrXA}eWc-nu8L%eYlaL@YJyIR zuk5LWOCPYc>UMHW~v&H+?T_YESTK4OAUXuE%_ZBp5*SPC zH5$Ek{Y!_phE-PmAUbkE3)|GentN4L-HWKbJoym3AR zPNXio5Wp_i;e^Yjn$-HPu1V%agKh7X-9;RQw|GgULLR?d(jRY{Ix-VJHj$KoDI6Pv z5d{U7U6nE7*^0Mo(mGxcjjXZ+M(D(3UTkk?YMk;sX0bsrL)9)j>^%z?L*DO#sgmE& zNqf#rtMxa}J7efqcn<3Mg6P|e18FbEyiTeg25Ka+3C|@?T56EHG&6^)HM^cJ_X(Loi6(p>- z{c-Q`B*k5DxCTOOj!z~v@@rxXTXRBW$0XMwdpB^U2|dh2{GX=JW^BO!Qj<|x18GOF z(fl|J$QZ_wYXv*+kE5K*T<(tMEVFrLp70MKbRuM4d!I=13K`crL)kJ**VM?kqMb0T zT&R~$y9aAPDuM_c<7PbE#IoK3JUxUfgXBnsn*H4iqNoy*=0H3cDdFw-F z?=6=(4CQCIWIO5%g-EczPHQe|EE?0Rc~0M#`fJm5)YGfSl`0*GUUx+=9a~&nEM7gQ z+VixVe5Oezu%GlmuHOlTDf5)NxIT8No-r7hYrOYh?}%BSa9LGd|fpu~WBZXw&0sU)y__SfR#pGa*0Zu$eZo z4VMxLE7w#U7~FFolOpzWbvJ(-5K&-At&7mvr2h%O{8(twY^*IUMm7O%tQah*Wc8H) zj=H`HY3Z!iT%2oKr?fa&+5bE27v(QrYQ#}@54)`3j%P`beW^Wcna@ibd5=Q-`Y7*1 z;i~(wusi5mrh<>D$qQU4=|KAqZkh@!reqvdcMHnb8bE-ij)7{p!=l)~fi%vE@#t~p zc@*ACs;Cx$4nLJSjq~Yz^!VWL6g=;vF}hRLCH3UY8g9q18zQi%Z!^ZqH?3zy{1~K5 zI)d3sD>602QJr3Z0!9*^CKv63p+p>^{Aj&qOy|&5#Mc0J`E9O}S%-P>Yi2jwL)d^@ z`LD+E71&}?>VRchG!pD!`*B!Fhlg;NpqisKaQ^e#9f;TL9ZI_DAj7uo zjt=>|Y~s29c!PQ^zxoXi2{{Qm}zB zw3>My8}l2WvW~N+7KlOA;%Z%|E?e&k0U%@c)5^?9AP)St1RsCZ)7a z9Xk9@U)ol76c(1&vKgyLJ=9iRX6t2o!m=9*h4Db{L~>dt0T)%gOkdk*m8J23YU+26 z%H(G|U^LD*Np)_u_c+Uw&xA=;Th6yqF=#oAfD~|m5MeDj8u6{Mqs^&nYCq#aVvbir zLlgtR^Rnlz?n3=TPr*ZTGgNH!EFID@WC}(&co>S8Y=?4ABk?fTJ``&wtfPe?8q3oy z5r$ZN#hp7h55=gcg{qV&D0}%S?(AgFt+0EOyP;VgNPg=5=Iqetb3jr0tE0+;o1Np& z79t)>A&0|(*Ye;#f26iu53WIc5C}hCIXT0vwgoZyud+^hFOgT-e7CGqCNA{3UR%*5f^MO9L5Y)54mylXlL<8|NV}O<0lTA&#-m> zLewt@V>*9a>EdnoFYavn-101fhbqc}Rq65KR>k;)*5ke=I(J2&1wEfISUg$Z!K6}h z<+H_mI8Qd?EU&y&&S?52v{xw8X*tz)9da#507-?$mJ{BjUUAuOU zN#3|#Dr`fjF}*PB8WDhYQ|AIBoI0!4*x1CJ>fyzI`JH3vw^JYHJNVNe&L!z1nq0fx4FAB| zw$ppiAChW=Dl5`nupb0^s5#>=XKWeMfr`!A<;8mxzLM5o9bS&7OdR%!ucqIy#ZH+z z)dy3n?3h|6i(|JN=RpXhD)N94<**40!y8(ioDmn&OENk5*0neSF7TOKhy(R=$jp(0 zPuA`uJc}>~P=M)oi}28zrtIAD{ikAQz~#Nf+2b8QniTlq@iHGLHdxE=M3{Qjv8{T` zX=!`^@Ov#=rjUf@a+*ALOQ%0Z=^}87v{NKpD?K!`F!!(|Kxd;a5`)EAMBKP{~(+zAnnaW zL~A}1DI*2$)5S;T9$jccmd1&564F#%v8o2C8(04(9FZZzb5{Xl{{R-Djv#&F_u;GH zaC~-Uj%^ve@XSJ7p4NA88Kdam3=EStg3RH*wxdPMrC%(p&LDsH%#mokZ%~5|@PVl7 z-y{A&pQV+{&2o*|(ItJ4>1mwHacXYh>~RIx00Sf+a|o|%0MWe|l0^4?gt+bG?7Fal z2PuE#-PSHHUwht3tfc0mm8y7AObFOi`D=+HB*d!c#;dD zWM>mZaL61e*I(>)!3gU&k}ed1w&qC*!>b&)-+LX@%ThxLwz+a!sZ&6(_Y{hMTg!;1+dYMo^!3vQ1#<4WgVKc-JCI5o0(6MHL{?sF-W`vir!_`J;eAhbVt zkj4vk-c-Rzf<}_h9sG2()F^MRRS^oR8MbaG8kBeP*agy}QtUp5_E-RI@X6tNm$lY0 zWNQR4&`s?*r5&)7tvhA<^aF9>H{l`djy4W{1zdr@a3iNWia}MyPOkRse#T&o$df18 zK4q)d*;hy%jASj~gWPa^Mv}QV9?(G4CDu+cJ7nK6@eRZIlkiNh~quz5H1JOFWW(V7cxb%)bjNLiW1VM7@Wu~Ks~5)yoVpNSIRa;Pd7 z?`a`q*0e&G%o10^dcyG^AP@+srRI{{>l=L&UMs%H7M3i4xsreRW~+bC3yh&E0XoNo z9V)^kO7sxbm)w+D^S=C2{m8c75FV1)+Ol1Vp{{T=B;kiY>x$uFSMHA+5QkfSG;C{k zV^tDQXv*+tulxd638Maob$3#)BHhtCLr*-H`ydoYT>a<~M{-i)DMa568gIXo{g6&{ zI)T6}vrrktm5kd7$ZFuPRp?L}@;`|#M7F&^iT0WcO#U?$B(2si1#O2OaF^iHA+}RD z$mT7MJpW^%x(E=j`rL2A0gMjH8t=zDrfLzCEHtqJquo3@6sqwLwh;C20bDg0!<9l%x; zAW)6)kjJ-sYl(-KDZlIc)vI@qY1m0X=NC6^yGyNW*RF}!EPd4F*G&6qA4prR8#HBm ziNdZFbPx%2A<-D((oO;F}PHgWa2cv2|{2O7xAAioe9R1a@ zu6ZzU3FHefxc}Wnos(z{PTS7hKwwQ1adYth zX766Ni!tx94?rk&+8hUn+^-I@M<0n3iLZN?1wVhxuOY*Jo;?&Hfq@`oY8KEdei0BX z|FbVv>)p6xK~RRnHa3<5KfLEtsN9B^$Bi5WCe`Rr4Y$q=u38wb4qwNJaUiY?FDJGT zjNu};=f5KtzpHrn*If~Z-$ONhwdK<_#-NY*0L>d!yi`E;2{hPEbrzubTT(;h%t!zm zgTT+)Z>$AWRb|u~U&#!xrP}^=Py9(d{ys-4x?QE?t@o_o#^Ljj01EPIVI;P~hFv73 z>Ud@m4R)|kV$gSCyx}oc!5VMf+el&J9q#QrfNk(86Tf1ZK+9II9`EO2Bvz%xi4F+Ybb{7FP=jMCO?Sds z23zwyjPE2(t!h>TUv;E8+_s8vCiQYr0S91+K`Q;wrABaNJZxXiQ|}~?nNPO;T=b}y zPYi2$=ACuZrA+7(qhKB1Unfc&2dwLK=Q&F2NKj5hB=lb@ahQi}DS4YN5iHn;S32^3 z&I_&c&*<~c+iy!+yW091RL0MEKXbgQI;bUBx!e==T$Ec@<0ZMB#h?#F5Ax!p!C>2b zM9RbM>YRT~8GDL1pHM%h9wB}xJV4yu9sQRlhqQWPLJw+c${kzzC}XV)+g;`18#6Wp z(a*;9hbD<8jT)~#DxiD!?h;mx3MgwV0_EJO8bnm6qON~Rxrl`2;HanI!1j*+M@a%E zQN7dDzCtouXkU@Ws_^;DnQE~V)qb&twZm~M0y5SL)PhpqtkIIKBkMFwg1oP!x?eFN z&y(j5N1G?mWUGS3`4OMQp`Q%F{bXnu$gd$AUG2IepHA; z0Heu#%U-k^3M?QF#Db|a3M$8J!bO(L6qVJNJuebsV<*FZ7Z13mpyZz=_t2LSqlD#3 zq`HM;zfIPS)6QT>(vaYx2cZr^(nSqzs}cALzr_{_(6QgvZl+qTTCiXN(cayD-Ecoe z|0PROtrvVgG;GItJtZ)ceu|dzZ8pkY|5Z#coW<0i95eWpQt=A*_qrMYJ z=qHy^@i?|SP{6W4^wbN#joqi98lM>T!56!tWwaB!+HJ=_D>e2@+4vZ+Pf`~9%QUS5 z{I}T2^G0k@!pr>0)$Xl1YJ{cg98|C6wKK;-Op%SZ*$g1%KGgQaL1y)7dvLYDX3j49 zxamZbII5>|JX{8Dr6%?Ck9cB`@zYJKwuJ(>9=6iCT3qr<(}yB7Jk$ z7+fUf?|7g3hfy_|?nfF&)_3FFFd{pNn*zL2XwsjBByo7~n3FMmxymr7>jtz%L{+t-YT^&+7>Dok~0^emAcIZ-o-CWo>-)TDmBFQ(|ACl|4Gq*?`2_RXmCtFyr zX9LO#K?{FiFF!osgd25W^Ht(XiLNq?UL{3$JOy9Y@|Zn@hH?isFR9FuR%x!Q=}Vgr zRmQ%M>-9qW!Q0zAE*X@d7v72c&u@i&A=p~u!N5Bv_W{76&`fp5)z)KB(n{LD3Ej7c zq?OZN3}5lV$V&iDU=brCp(oTRS%aE4$qeC?^L@_ zBtX5AU;zjMat+m8=ztSRG6~5IP4HeJ^%gEC#cC^GYI9s9I-kZwc57eO? z_hb(p!gjzsUCeba+{;leAWxbE1ZsvBHx`zvMqEy?;q4MS=+v$%f$bIzWNi&yO zEJBf^dgJ}J`kk_YJqUo9Jj4cjIqbex;!QQoCKzmVezgGZ8>h~k>CJj`-(D`PH79a6 z2DMq^P{R4B!+*SGWVXW~t1v;Cw4FN>lgLnumLLikx*gB+Ll*1N{3}^VL1q_>SPMT)TPLlap1k}PEQEr~pchaf`y;j;^a9WN0iXnUB@M*e zh)S5##;qr2Mx94M$Cdl?O*1z^Qt24LTA3B+kwHT`)gio(J&%Mlr?HF3BMim%B!eB= z9^->~k*7@o^%@;gx#~6w0%_A887oOLXsDJcim?d4MrIcT#e1gR>D;+<@A0n%^kFSG z|0}d5aIE(;pFBuYJ0U`f!@FPo<0a_cCOA>x3*-c0WD>r$jveQP_E@3M6ml9MRt?WY zhSEzz%Im8xzj0!%GOYL#Yr^MH)&(4NQBNC!HUELS6a{p?gFCi47#}bFJvEtE-5h&7 z!%S@(G4<^;R~KA>r9NP_rxS7Ns2a|XPp)qtuM$bWVm0x_vdW*iRG*A52LsM?)Qi!Jx zzUJ=2Mg{N6QRh)nnn`@@j-D6lL(*BNBAGl;^(qOTT5rP~?2gcvm=i)({E%%Xpdn9&i(QVC_Hsm;bCVm=rT7Ff`Pt>UiX@h#3o)1|K|a(Jl`c|h29l-xE!^|Ayc(HI)F`<8CXwd>b+M=#r0xzUh*QaR-) zQYQilgPN7I`}H=?!%N?$OV_SJ?O5qy>XWt;8+qLT1PRKQkvv?vWI5@I$@uM7!My3y$HFL6|FU5JB;G9VWl$09J}h zg%(~dv+5$?-^43E&E<7sd}aJkv;yoP(c;4^_Z4Qw;z}X^2C;9*@H6iq6Vacff-q3_ zSMP+PM+;HEs2>^{D#}N$rqj03KFVGHPbyelR~9(U4GeK{z9@Dz{`^G0xum{=(kbHn zomf*9=N^T5?i6Au5qE(FuO4iicz(l^E8#~B#{5>o^-^&l4vyc?vk%D`9@9Ng?;KNp zef~f7mnzc#;>!R_0W@jEvQdq#|qWq@qDq*V*Jaw zVu+NnCqx(*a%Nf*;*Ug&rc^7Syih?j*CtupaId4a(Ty;d2xu-i`QSGDypu}q{;)(E zk!zmr=!}SC7~F0pW+`3`uS@+|4kv&zhMdYfu(@|ZB_w_b1+{U0PJVu4dQnny)ss~* z2-`h~N&@!gcWH0P!A(rC8(br15h#$NQV|f^!46m|yb37;$7Ba1USMvq7L3vCc35r?sf_?v ziYx}9FNTL!F8OB$Pp~YBH@Sg{p_C<`WZu};lPovo#D!}XWgaxw8{hvDUZeM^NWuZv zJ*|}I<|lKtwR8Fs({Tiq1#>lXi+pHUh0-_9n(_JPL3x*djLJ%0`C(@| zEVLl9G=FTl_87#7*$f!74c{#)fDXgiv=nN=Ibwat&hujN)}20mx*CVX7J5SKCUkQBrVH`7E}Y>LDNG@r2`%#1w_}W_s|XB~G5VD@O!{!Og(KKVv~?wDz)N z9!5;8Jo-sjQX=y3G8-T_N0i#s#VI<7i>M0%6$&@l4(b?dVPS@`;Gso%Fv7M-n4Mfz zoNKz$7+9ab$HS`9AeP8dC^&ZCs_-LhGoKNkigCt|ohi@XhN?lY_ngXC%(0i1xjD$}NnA{EwkPMRfljvui(}q!3XrTb3tjCoaS^wxf)oy8x2PHx=0slF) zQIIMiRjpIc{PC|y@P^H zS!MHQul;O?%;7^;kmGdCa!-m+$sHYwoo#)_IBVs=SW^j(D7{Hu$3^X*3OMp#JyYiF z($^|ph|4an+{H&nX_P=_R%eg-)2ej6*)q>@vAbF)%&lKFG^z9OkUcBgo z-E(j3Nt;LpvgxZuY0qZiJCr5(NTE#3-|HzdZq3O+3zqn=+j(Z*z8yucr^~TLigW}A zm99!RC;J|-d4h!XB1BA%$fHz_1MACMc)&PdmE=#8|6S@>$fl#+oABRc{wi3}8wCFTB5ZU0`wtx8`l&kdK0gL`H8 z985jPPpEuY^T+mM=|aC;hdgd|SOGyVD1|-`&fgnH&iwIrEL~Kesn$!7m)BE_zz$qg zEB(*M692v(9>_)sPb~LDkm~xuPmjKOx9>^^Dbps9Rw*FYbVAprA(>+8=`watoO*wM zng^nDbn(%@!26-d{=F0I0H0x-hoOpM&HNUThkyMatM1jU{B5tYA>a+KE^>K^6|Wh# zGOQIfq#=D_<@1F|S`YJK=@2?L{tL@g~?<*DJ zSKP|apXBvabv`t0f3GqbhtVPCxf+7obdEsR@XZ%zWej}v-M?<*IBSFsZR6e z{|^6V^`;)*Z|bov-MjauwX1(iX*PELhwjg6?(Nv3N=!_@&#Ij4b8>*sXI{RmC)TX8 zsoTAA58Gw6ZuM76^Rzk1_x~y=>oKRqHa*ScZQg&|U&g2|3jV8x;4_5hGZ+Vf8p9`P zdNQBAY0~E3p`c`hWBKy$Urm^j<#l-0vnJ`LWqB~+HJuE$uiCV2I~oV4=T8|4p-w~< zePYb{Evjv^G-!$-^^;8C7^vEOG@gqtkb+3}{`j%*^ z?p57AagTNPv57Pyiot81{5!Z+>@W8Swsp1Ej%n zPvYb^XirwxxXi-WMgBJ21Az8EB?_o}b(xn-K|w*dS)gio+ArNPYf9^!+}x!TJ!e06 zBNHATU~cK>9_C9WI{E?9PMbEZ?$!JG`MrO#UU-F>)bgKCk=bt~(D?40f@bi3!tCGu z!2aEjAd->dZ<9V3FJt!0g68%CU2J~ec^-+RA;4zg`P9Jv&g(6;9<8LV`PL`=K}F7A zzrJo_XmGGw)Yh%`K?!}woX&s?*RR)V=)0>&%u6=jL7+qXbk?w@<9$HcMWjFj3VB11 zxkW1{n$FZ))|aWb*gk}k!ti|D)nmBf_F*Z#ID!ys4^pHX^O7xeoLRAM-r>A8;!Sh! z-u;F=O5Jp}Xy-*smefl(cd0ez>8YuyzhP-&UQ(cVoEkm*m%q2Zydx35)27|K8z(*G z#YYDQ)=x4|o=WS?aoOOtxv0Sd@=>@I3j+!@iTwszOR&L@MD>>`0}RjqVC2uokovLS zxqegYohw&!a#}KAdqhAX!O27D3D!D!^>u8<@>Zmz!t=ehyu-cwS}VA#i#g!inle(= zt5*-7NZP7?ZO^%Dt@-@6hspEkH^%RykAB#<&po|ZtIXUx^{d-&T)k$^MXdR2Qw7)_TRq0c+sLRqeqXv z=dLSkcwoQRwk=y+aC*MC9-)3aYvdLaf^|9_>FN2bnm*kx&{{6lQ?FgCIehqV>nUuV zDw=CQWiLi#2tCZ~m)>i?^hBJ}^H;B~v0u88{nEIG!*&fj)YN|I9`;M8rKD7Xhjn_6 zx$Y~4oA2UZr4`;o>`y=0C;WfAn=8ldpUs*zJI3K+zhkg<$9>1BupLD{z4ZAkJAL|{ zEdyNt9{sPav0K>{eBxg`Oz9oxTX$T(YURokb7WzSN~OOFnlND@=T+%LY#g|KV1q+T x^bzxCTh|fhbeRA1Jkoj?`@h-$IK9i$X!CldwBwNnx9V3tyY}f4-O2yU{|DER7qb8W literal 0 HcmV?d00001 diff --git a/hello/static/logo_web.svg b/hello/static/logo_web.svg new file mode 100644 index 0000000..7d12e7d --- /dev/null +++ b/hello/static/logo_web.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/hello/static/yt_logo_rgb_dark.png b/hello/static/yt_logo_rgb_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..64d91a3e83fc4e9cb61c6fa227df7929044deea1 GIT binary patch literal 7438 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

YJ^~_01e24{O#Xkp>|4Ept|ql zJu)#kJw3>-Zc>F^?zvGX`c$hf9WzYv$CLoSp|eGupGlb~jD@OSnyBioMAJ{^l`=q{ z5C$sjx^5w78s@Q~tEER=gkjpTkvqQs@)T!yLjvwx84{BkK^H*}>Ed)xUS@p`0L{^> za8zSo=aJdo(|2bE-ACL<NgCYRt^H2oR z$9o(tfdkS}FB5H^BbOfdGPqLT1Au6&Xc9I@(G?>msyGE{eIXgD*45xlXJ z`QN0_bAtAJZr?})Kn@rZg?#&+T~56{rH`BP*Kb=I^s5!i;D4yR9`zhJLk97F{r^rdChzI- zPk)x94EpD5YP>;$1T%CPIN&dp894ypPDtmM92JZ!kN=rPQt2|DH7um~3PZ3@*E302 z8gjj5{=?iEi`Oy%5Q&vUoJi4Zsr5M7CKYA$t^H`X7Z(8V<4@`SuyDci{x1CBH87@6 zAjVf5Aaz-}ak}(zugd$Rqo$1&NHkzEB(HyXkOTLWW0XogrG`U)NK>UpNZ_40a>N}X zP}%GlbuxhFu*N@3#S>ByO5!D9Rbldc7n^n`KV=JVIoh1`djf`Yq9kcZ9|omOT8e0z{F68Xx@-G=y^SlIe}sUfbx<02mp^*yw9TC5GnLq@ojhzu|d_^`{BJ^ z8C3)wR2Nl2)sI(75COayhl^=Izd`cy z?`7^>%_yBJIr+U38a-`}UjM*saa|g~cXae%<;2L)s3rF`>8tw%WFa;2?ur;7=zI9Z z%RPk!@OtCO@%I~91`Sygna8wvZ*~CA%ue&0>(&C<7i=2MpXF&S>!#(Cr zVDnh=-GxaL4WtvXct_=y)iX3!u8d{E!!&{935}@?wE+h=h$c&W8M4vH_bG?Zmkml0 zZNQ-#b;pL?!`?S5pf_feGvX2L%e~XeDqSXsZif5`Q#xSSf4K9O{LPn6fWkZ zOU$)0=_{AudoK0Lepe%vH(guBuLzAF$Q=rc7SCCIk(#UJjXm`q9Y$F~?(;q&!vsD1 z0?uzOrpbbIFWib0F-`CguI=V(Ggs4c&Bv`y^Wvr7%qSty=Kxu7EaRCyGqWvk7+aV`-$-7sbjem6%Q#}o5WfE< zProH!9aC;4)WW^ObW7|6TW`HgBJQBQ!`=c}r7})YZTzt0$C!CKT>0s;9XH3XfT%;U zP2sZCF8XkCuh{PhiOG|^BZ_hX1wSd@_jYN?C_o_nV`6(8v-(1cn!YD~7tQu(ipMWR`6agP<;>g~OnFNB9gqEY z!b)#D`$In66t!~t$j0>5%n*-dWI?f*j6kK!J;9 zv{Vkhbx#~e!;HLI zZt!wEO8>qt@}-m9G$H9g*qvi!ft){_Hw2M(&Hh)y?M6Yd))A(7!b(1}m8{ba>8?np4yFL3@gc&j;^JH#&ccUCMDfgnynQ5Z^U4k5y(LL zffsohc{GwP9(5(3v9-Lmf60^N3tI)Pi#;qCm5HVsKR0ZOP@|eXkr`lvLP z_lXh7YQiXKD%;=h8^wnq2%=}2fn?9@4-W26Gc@5c!!_NG*$~%KroiG>{leD|}pW1NK%}+=R4X z17@YCfzMZ*Cg+jkrPO?XF56Z=Bn`AD^&SfO7D?-$yjJIb+H?}=viJSfv$r!W3Y0B%C(mhMll@S}*qM)<7bz?&#>t&FzlxkfmA6|#OcGl}{O38m0@t6E> z(Bn6*oSb+SSp5i|QlVYQD;zGU#-I&s_8$M$}l72C}d1MkEUe-hDT@wyx+%&9498u54ixKmY)-&X_{6yk>g+lR4iD zYt12%h + + + + + + + + + +

+ +{% block content %}{% endblock %} + +
+ See this project on GitHub +
+ + + diff --git a/hello/templates/index2.html b/hello/templates/index2.html new file mode 100644 index 0000000..2e00756 --- /dev/null +++ b/hello/templates/index2.html @@ -0,0 +1,555 @@ +{% extends "base.html" %} + +{% set cursong = current_song.song if current_song else none %} +{% set noSong = cursong is none %} + +{% block content %} + +
+ +

Currently Listening to:

+
+ + + + + + {% if current_song and current_song.song.item.href is not none %} + + {% else %} + + {% endif %} + + + + + + + + + + +
+

{{current_song.song.item.name if not noSong else ''}}

+
+ +
+ {% if not noSong and current_song.song.item.artists %} + {% for artist in current_song.song.item.artists %} + {% if artist.href %} + {{artist.name}} + {% else %} + {{artist.name}} + {% endif %} + {% endfor %} + {% endif %} +
+ + +
+ {% if not noSong and current_song.song.item.album %} + {% if current_song.song.item.album.href is not none %} + {{current_song.song.item.album.name}} + {% else %} + {{current_song.song.item.album.name}} + {% endif %} + {% else %} + album unknown + {% endif %} +
+ + + +
+
+ + 0:00 + 3:25 +
+
+
+ +
+ + +
+

Radio NF is currently offline

+

Come back later for some true bangers.

+ +

In the meantime, check out what sick beats were played recently:

+
+
+ +
+

History

+
+ +
+
+ + +
+ + + +{% endblock %} + diff --git a/hello/tests.py b/hello/tests.py new file mode 100644 index 0000000..10873f0 --- /dev/null +++ b/hello/tests.py @@ -0,0 +1,19 @@ +from django.contrib.auth.models import AnonymousUser, User +from django.test import TestCase, RequestFactory + +from .views import index + + +class SimpleTest(TestCase): + def setUp(self): + # Every test needs access to the request factory. + self.factory = RequestFactory() + + def test_details(self): + # Create an instance of a GET request. + request = self.factory.get("/") + request.user = AnonymousUser() + + # Test my_view() as if it were deployed at /customer/details + response = index(request) + self.assertEqual(response.status_code, 200) diff --git a/hello/verify.py b/hello/verify.py new file mode 100644 index 0000000..96c5e4e --- /dev/null +++ b/hello/verify.py @@ -0,0 +1,45 @@ +import hmac, base64, hashlib +import time +import json + + +signingKey = "zphbG1sXK5Ebndyq5ey+IdYfM1CAQSGUR0WCBI52EKL6EBCdNcTmBpn+NFYS6qXDIeEBh8sBFUiLPCpZjgzhVY94SQStRYHJ7Y8pGtzGUdJFZpSuPA0GL87VKWM4YhgncC4hBY8+gIOq6KWQMAAlvUZBWg6sdo0qmsBxCPr0J0w=" + +def verifySignature(string_to_verify, signature, shared_secret): + hm = hmac.new(shared_secret, string_to_verify, hashlib.sha512) + hmd = hm.digest() + return ct_compare(hmd, signature) + +def verifyTime(timestamp): + if int(time.time()) - timestamp > 30: + return False + return True + +def ct_compare(a, b): + if len(a) != len(b): + return False + + result = 0 + for ch_a, ch_b in zip(a, b): + # result |= ord(ch_a) ^ ord(ch_b) + result |= ch_a ^ ch_b + return result == 0 + + +def verify(data, signature): + decoded_data = bytes(json.dumps(data), encoding="utf-8") + decoded_signature = base64.urlsafe_b64decode(signature) + + b64Key = base64.urlsafe_b64decode(signingKey) + if verifySignature(decoded_data, decoded_signature, b64Key): + print('Valid signature') + # Verify timestamp + if not verifyTime(time.time()): # todo fetch real timestamp + print("Timestamp too far back.") + return False + print('Timestamp verified') + return True + print("invalid signature") + return False + + \ No newline at end of file diff --git a/hello/views.py b/hello/views.py new file mode 100644 index 0000000..7e4e55d --- /dev/null +++ b/hello/views.py @@ -0,0 +1,55 @@ +from django.shortcuts import render +from django.http import HttpResponse, HttpResponseForbidden, HttpResponseBadRequest, JsonResponse, HttpResponseServerError +from django.views.decorators.http import require_http_methods +from django.views.decorators.csrf import csrf_exempt +import api.spotify +import api.currently_playing +import spotipy +import json +from datetime import datetime + +from .verify import verify + +from .models import Song, History + + +# Create your views here. +def index(request): + res = { + "current_song": api.currently_playing.get_currently_playing(), + "history": api.currently_playing.get_history(50) + } + return render(request, "index2.html", res) + + +@require_http_methods(["GET"]) +def currently_playing(request): + res = { + "current_song": api.currently_playing.get_currently_playing(), + } + return JsonResponse(res) + +@require_http_methods(["GET"]) +def get_history(request): + res = api.currently_playing.get_history() + return JsonResponse(res, safe=False) + + +@csrf_exempt +@require_http_methods(["POST"]) +def send_song(request): + body = json.loads(request.body) + if "signature" in body and "data" in body: + signature = body["signature"] + data = body["data"] + else: + return HttpResponseBadRequest("Request was missing either a body object or a signature") + + if not verify(data, signature): + pass # nf todo verify is broken atm. come back later + #return HttpResponseBadRequest("Request was signed with an invalid key") + api.currently_playing.add_song(data) + return HttpResponse() + + + diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..85c6c7d --- /dev/null +++ b/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..74d8187 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +django +gunicorn +django-heroku +spotipy +jinja2 \ No newline at end of file diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 0000000..73e28e8 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-3.7.8