From c58e6dc839615fe5b9b0a7de26b123f000398e55 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Mon, 20 Mar 2017 16:44:25 -0400 Subject: [PATCH 01/11] Refactored Updated dependencies --- .editorconfig | 13 +++ .eslintrc | 13 +++ .gitignore | 5 +- app/main.js | 74 ++++++++--------- app/package.json | 14 ---- app/renderers/index.js | 178 ++++++++++++++++++++--------------------- app/renderers/pause.js | 6 +- app/renderers/setup.js | 31 +++---- app/styles/index.css | 2 +- package.json | 28 ++++++- 10 files changed, 191 insertions(+), 173 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc delete mode 100644 app/package.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c408a22 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# http://EditorConfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..35b8d86 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,13 @@ +{ + "root": true, + "extends": "airbnb-base", + "env": { + "browser": true, + "node": true + }, + "rules": { + "import/extensions": 0, + "import/no-extraneous-dependencies": 0, + "import/no-unresolved": [2, { "ignore": ["electron"] }] + } +} diff --git a/.gitignore b/.gitignore index 2909082..34a9938 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -dist node_modules -npm-debug.log -debug.log +*.log .DS_Store +dist diff --git a/app/main.js b/app/main.js index aa9ddd0..a21234d 100644 --- a/app/main.js +++ b/app/main.js @@ -1,27 +1,40 @@ -const {app, BrowserWindow, ipcMain} = require('electron'); +const { app, BrowserWindow, ipcMain } = require('electron'); -let mainWindow, setupWindow, pauseWindow; +let mainWindow = null; +let setupWindow = null; +let pauseWindow = null; -function createMainWindow () { +const exitApp = () => { + // Do not exit the program on macOS (standard OS-specific behaviour). + // Instead, lose app focus and close all open windows. + if (process.platform === 'darwin') { + app.hide(); + BrowserWindow.getAllWindows().forEach(win => win.close()); + } else { + app.quit(); + } +}; + +const createMainWindow = () => { mainWindow = new BrowserWindow({ fullscreen: true, - frame: false + frame: false, }); mainWindow.loadURL(`file://${__dirname}/views/index.html`); mainWindow.setMenu(null); mainWindow.once('ready-to-show', mainWindow.show); - mainWindow.on('closed', () => mainWindow = null); -} + mainWindow.on('closed', () => (mainWindow = null)); +}; -function createSetupModalWindow () { +const createSetupModalWindow = () => { setupWindow = new BrowserWindow({ parent: mainWindow, modal: true, minWidth: 400, minHeight: 300, - frame: false + frame: false, }); setupWindow.loadURL(`file://${__dirname}/views/setup.html`); setupWindow.setMenu(null); @@ -30,13 +43,11 @@ function createSetupModalWindow () { setupWindow.on('close', exitApp); - setupWindow.on('closed', () => setupWindow = null); -} + setupWindow.on('closed', () => (setupWindow = null)); +}; -function createPauseModalWindow () { - mainWindow.webContents.executeJavaScript( - 'document.body.classList.add(\'dim\')' - ); +const createPauseModalWindow = () => { + mainWindow.webContents.executeJavaScript('document.body.classList.add(\'dim\')'); pauseWindow = new BrowserWindow({ parent: mainWindow, @@ -45,7 +56,7 @@ function createPauseModalWindow () { height: 250, resizable: false, closable: false, - frame: false + frame: false, }); pauseWindow.loadURL(`file://${__dirname}/views/pause.html`); pauseWindow.setMenu(null); @@ -55,28 +66,15 @@ function createPauseModalWindow () { pauseWindow.on('close', exitApp); pauseWindow.on('closed', () => { - mainWindow.webContents.executeJavaScript( - 'document.body.classList.remove(\'dim\')' - ); + mainWindow.webContents.executeJavaScript('document.body.classList.remove(\'dim\')'); pauseWindow = null; }); -} +}; -function createStartWindows () { +const createStartWindows = () => { createMainWindow(); createSetupModalWindow(); -} - -function exitApp () { - // Do not exit the program on macOS (standard OS-specific behaviour). - // Instead, lose app focus and close all open windows. - if (process.platform === 'darwin') { - app.hide(); - BrowserWindow.getAllWindows().forEach(win => win.close()); - } else { - app.quit(); - } -} +}; app.on('ready', createStartWindows); @@ -84,9 +82,7 @@ app.on('window-all-closed', exitApp); app.on('activate', createStartWindows); -ipcMain.on('setup-timer', (evt, settings) => - mainWindow.webContents.send('start-timer', settings) -); +ipcMain.on('setup-timer', (evt, settings) => mainWindow.webContents.send('start-timer', settings)); ipcMain.on('pause', createPauseModalWindow); @@ -94,15 +90,15 @@ ipcMain.on('pause', createPauseModalWindow); * Called after the pause window has been opened and it is safe to wait for a * synchronous reply before continuing the counter. * There is undoubtedly a better way of handling pause, but this works for now. - * + * * @return the false boolean value for the paused flag in mainWindow */ -ipcMain.on('pause-wait', evt => { +ipcMain.on('pause-wait', (evt) => { // If it has already been closed before this channel, then return immediately - if (pauseWindow == null) { + if (pauseWindow === null) { evt.returnValue = false; } else { - pauseWindow.on('closed', () => evt.returnValue = false); + pauseWindow.on('closed', () => (evt.returnValue = false)); } }); diff --git a/app/package.json b/app/package.json deleted file mode 100644 index 04101f3..0000000 --- a/app/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "station-timer", - "productName": "Station Timer", - "version": "1.0.0", - "description": "A simple timer application that repeatedly counts down for a given amount of times", - "author": "Ahmad Ouerfelli ", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/aouerfelli/station-timer" - }, - "bugs": "https://github.com/aouerfelli/station-timer/issues", - "main": "./main.js" -} \ No newline at end of file diff --git a/app/renderers/index.js b/app/renderers/index.js index e6d2532..6cd1ed6 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -1,27 +1,30 @@ -const {ipcRenderer, remote} = require('electron'); +const { ipcRenderer, remote } = require('electron'); + const webContents = remote.getCurrentWebContents(); -const counterTextView = document.getElementById('counter'); -const secondProgressBar = document.getElementById('progress'); -const infoTextView = document.getElementById('info'); -const pauseButton = document.getElementById('pause'); -const restartButton = document.getElementById('restart'); -const muteOnButton = document.getElementById('mute-on'); -const muteOffButton = document.getElementById('mute-off'); -const exitButton = document.getElementById('exit'); +const domElements = { + counterTextView: document.getElementById('counter'), + secondProgressBar: document.getElementById('progress'), + infoTextView: document.getElementById('info'), + pauseButton: document.getElementById('pause'), + restartButton: document.getElementById('restart'), + muteOnButton: document.getElementById('mute-on'), + muteOffButton: document.getElementById('mute-off'), + exitButton: document.getElementById('exit'), +}; const beepAudio = new Audio('../assets/audio/beep.wav'); // Object containing strings used in the counter const text = { counterText: { - end: '0' + end: '0', }, infoText: { active: 'Complete your activity', coolDown: 'Go to your next station', - complete: 'Return to your original station' - } + complete: 'Return to your original station', + }, }; // Object containing values for duration, break duration and number of repeats @@ -30,37 +33,31 @@ let settings; // Flag indicating whether or not the program is currently in a paused state let paused = false; -pauseButton.addEventListener('click', () => { +domElements.pauseButton.addEventListener('click', () => { paused = true; ipcRenderer.send('pause'); }); -restartButton.addEventListener('click', () => - webContents.send('start-timer', settings) -); +domElements.restartButton.addEventListener('click', () => webContents.send('start-timer', settings)); -muteOnButton.addEventListener('click', () => { +domElements.muteOnButton.addEventListener('click', () => { webContents.setAudioMuted(true); - muteOnButton.parentElement.style.display = 'none'; - muteOffButton.parentElement.style.display = ''; + domElements.muteOnButton.parentElement.style.display = 'none'; + domElements.muteOffButton.parentElement.style.display = ''; }); -muteOffButton.addEventListener('click', () => { +domElements.muteOffButton.addEventListener('click', () => { webContents.setAudioMuted(false); - muteOffButton.parentElement.style.display = 'none'; - muteOnButton.parentElement.style.display = ''; + domElements.muteOffButton.parentElement.style.display = 'none'; + domElements.muteOnButton.parentElement.style.display = ''; }); -exitButton.addEventListener('click', () => - ipcRenderer.send('exit') -); +domElements.exitButton.addEventListener('click', () => ipcRenderer.send('exit')); -counterTextView.addEventListener('click', () => { - // Since the counter has no pointer events when counting, this will only - // trigger at the end when the end class is added to the counter, which - // enables pointer events. - ipcRenderer.send('exit'); -}); +// Since the counter has no pointer events when counting, this will only +// trigger at the end when the end class is added to the counter, which +// enables pointer events. +domElements.counterTextView.addEventListener('click', () => ipcRenderer.send('exit')); /** * This function allows us to use Promises with generator functions, much like @@ -71,8 +68,8 @@ counterTextView.addEventListener('click', () => { * * @param generatorFn the generator function that will yield Promises. */ -function async (generatorFn) { - function continuer(verb, arg) { +const async = (generatorFn) => { + const continuer = (verb, arg) => { let result; try { result = generator[verb](arg); @@ -82,15 +79,15 @@ function async (generatorFn) { return result.done ? result.value : Promise.resolve(result.value).then(onResolved, onRejected); - } + }; let generator = generatorFn(); let onResolved = continuer.bind(continuer, 'next'); let onRejected = continuer.bind(continuer, 'throw'); return onResolved(); -} +}; -function skipTransition (elements, action) { +const skipTransition = (elements, action) => { // If a single element is given, place it in an array if (elements.constructor !== Array) { elements = [elements]; @@ -104,15 +101,15 @@ function skipTransition (elements, action) { element.offsetHeight; // Trigger CSS reflow to flush changes element.classList.remove('skip-transition'); }); -} +}; -function setProgressBar () { - skipTransition(secondProgressBar, () => - secondProgressBar.classList.remove('expand')); - secondProgressBar.classList.add('expand'); -} +const setProgressBar = () => { + skipTransition(domElements.secondProgressBar, () => + domElements.secondProgressBar.classList.remove('expand')); + domElements.secondProgressBar.classList.add('expand'); +}; -function getFormattedTime (seconds) { +const getFormattedTime = (seconds) => { // Get units of time (from seconds up to hours) let hh = parseInt(seconds / 3600, 10); let mm = parseInt((seconds % 3600) / 60, 10); @@ -126,27 +123,23 @@ function getFormattedTime (seconds) { ss < 10 ? '0' + ss : ss; return hh + mm + ss; -} +}; -function sleep (ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} +const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); -function pauseWait () { - // The pause-wait channel will return a value of false when the pause modal is - // closed, which we can set to the paused flag. When the flag is set, the - // Promise will be resolved. - return Promise.resolve(paused = ipcRenderer.sendSync('pause-wait')); -} +// The pause-wait channel will return a value of false when the pause modal is +// closed, which we can set to the paused flag. When the flag is set, the +// Promise will be resolved. +const pauseWait = () => Promise.resolve(paused = ipcRenderer.sendSync('pause-wait')); -function countdown (duration, view, onEachSecond) { - function action () { +const countdown = (duration, view, onEachSecond) => { + const action = () => { // Run the onEachSecond function if it is given if (typeof onEachSecond === 'function') { onEachSecond(); } view.textContent = getFormattedTime(duration--); - } + }; return Promise.resolve(async(function* () { // We'll be decrementing duration each second in action() @@ -163,59 +156,60 @@ function countdown (duration, view, onEachSecond) { yield pauseWait(); } })); -} +}; ipcRenderer.on('start-timer', (evt, userSettings) => { - let {duration, breakDuration, numRepeats} = settings = userSettings; + const { duration, breakDuration, numRepeats } = userSettings; + settings = userSettings; - function resetTimer () { + const resetTimer = () => { // Reset elements to their intended initial visibility - restartButton.parentElement.style.display = 'none'; - pauseButton.parentElement.style.display = ''; + domElements.restartButton.parentElement.style.display = 'none'; + domElements.pauseButton.parentElement.style.display = ''; // Remove all classes from the views document.body.classList = ''; - counterTextView.classList = ''; - secondProgressBar.classList = ''; - infoTextView.classList = ''; - } - - function durationCountdown () { - counterTextView.classList.remove('red'); - counterTextView.classList.add('primary'); - secondProgressBar.classList.remove('red'); - infoTextView.textContent = text.infoText.active; - return countdown(duration, counterTextView, setProgressBar); - } - - function breakDurationCountdown () { - counterTextView.classList.remove('primary'); - counterTextView.classList.add('red'); - secondProgressBar.classList.add('red'); - infoTextView.textContent = text.infoText.coolDown; - return countdown(breakDuration, counterTextView, () => { + domElements.counterTextView.classList = ''; + domElements.secondProgressBar.classList = ''; + domElements.infoTextView.classList = ''; + }; + + const durationCountdown = () => { + domElements.counterTextView.classList.remove('red'); + domElements.counterTextView.classList.add('primary'); + domElements.secondProgressBar.classList.remove('red'); + domElements.infoTextView.textContent = text.infoText.active; + return countdown(duration, domElements.counterTextView, setProgressBar); + }; + + const breakDurationCountdown = () => { + domElements.counterTextView.classList.remove('primary'); + domElements.counterTextView.classList.add('red'); + domElements.secondProgressBar.classList.add('red'); + domElements.infoTextView.textContent = text.infoText.coolDown; + return countdown(breakDuration, domElements.counterTextView, () => { beepAudio.play(); setProgressBar(); }); - } + }; - function endTimer () { + const endTimer = () => { // Setting end classes - secondProgressBar.classList.add('remove'); - skipTransition(counterTextView, () => - counterTextView.classList.remove('red')); - counterTextView.classList.add('end'); + domElements.secondProgressBar.classList.add('remove'); + skipTransition(domElements.counterTextView, () => + domElements.counterTextView.classList.remove('red')); + domElements.counterTextView.classList.add('end'); // Setting end text to views - counterTextView.textContent = text.counterText.end; - infoTextView.textContent = text.infoText.complete; + domElements.counterTextView.textContent = text.counterText.end; + domElements.infoTextView.textContent = text.infoText.complete; // Setting end visibility for Action Buttons - pauseButton.parentElement.style.display = 'none'; - restartButton.parentElement.style.display = ''; - } + domElements.pauseButton.parentElement.style.display = 'none'; + domElements.restartButton.parentElement.style.display = ''; + }; async(function* () { resetTimer(); // Start the timer: repeat for however many stations there are - for (let i = 0; i < numRepeats; i++) { + for (let i = 0; i < numRepeats; i += 1) { yield durationCountdown(); yield breakDurationCountdown(); } diff --git a/app/renderers/pause.js b/app/renderers/pause.js index bccf204..a1ae7e4 100644 --- a/app/renderers/pause.js +++ b/app/renderers/pause.js @@ -1,11 +1,11 @@ -const {remote} = require('electron'); +const { remote } = require('electron'); const resumeButton = document.getElementById('resume'); resumeButton.addEventListener('click', () => { - let win = remote.getCurrentWindow(); + const win = remote.getCurrentWindow(); // Lose focus before closing setup modal to prevent screen flash win.blur(); // Destroy it directly since this is a non-closeable window win.destroy(); -}); \ No newline at end of file +}); diff --git a/app/renderers/setup.js b/app/renderers/setup.js index bc0abff..ee2d176 100644 --- a/app/renderers/setup.js +++ b/app/renderers/setup.js @@ -1,34 +1,31 @@ -const {ipcRenderer, remote} = require('electron'); +const { ipcRenderer, remote } = require('electron'); const setupForm = document.forms.namedItem('setup'); -const setupFormInputs = Array.from( - setupForm.querySelectorAll('input[type="number"]') -); +const setupFormInputs = Array.from(setupForm.querySelectorAll('input[type="number"]')); const exitButton = document.getElementById('exit'); -function checkValidInput (value, min, max) { +const checkValidInput = (value, min, max) => // The handling of empty inputs is done in CSS. If the input is not empty and // the value is an empty string, that means the input is invalid. - return value !== '' && + value !== '' && (Number.isSafeInteger(Number(value)) && (min === '' || parseInt(value, 10) >= parseInt(min, 10)) && (max === '' || parseInt(value, 10) <= parseInt(max, 10))); -} -setupFormInputs.forEach(input => { +setupFormInputs.forEach((input) => { input.addEventListener('input', () => { - let valid = checkValidInput(input.value, input.min, input.max); + const valid = checkValidInput(input.value, input.min, input.max); input.classList.toggle('error', !valid); }); }); -setupForm.addEventListener('submit', evt => { +setupForm.addEventListener('submit', (evt) => { evt.preventDefault(); - let valid = setupFormInputs.every(input => { - let invalid = input.classList.contains('error'); + const valid = setupFormInputs.every((input) => { + const invalid = input.classList.contains('error'); if (invalid) { // If any of the form inputs contain errors, focus on it input.focus(); @@ -40,17 +37,15 @@ setupForm.addEventListener('submit', evt => { return; } - ipcRenderer.send( - 'setup-timer', + ipcRenderer.send('setup-timer', Object.assign(...Array.from(new FormData(setupForm)) - .map(([k, v]) => ({ [k]: v }))) - ); + .map(([k, v]) => ({ [k]: v })))); - let win = remote.getCurrentWindow(); + const win = remote.getCurrentWindow(); // Lose focus before closing setup modal to prevent screen flash win.blur(); // Destroy it directly to bypass close event if not closed win.destroy(); }); -exitButton.addEventListener('click', () => ipcRenderer.send('exit')); \ No newline at end of file +exitButton.addEventListener('click', () => ipcRenderer.send('exit')); diff --git a/app/styles/index.css b/app/styles/index.css index 0e534c7..217dc7a 100644 --- a/app/styles/index.css +++ b/app/styles/index.css @@ -65,7 +65,7 @@ body.dim::after { --color-progress: var(--color-primary); background-color: var(--color-progress); width: 0; - height: 0.25rem; + height: 0.3rem; margin: auto; margin-bottom: 1.5rem; border-radius: var(--corner-radius); diff --git a/package.json b/package.json index 2e6bf02..7ea03c7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,26 @@ { + "name": "station-timer", + "productName": "Station Timer", + "version": "1.1.0", + "description": "A simple timer application that repeatedly counts down for a given amount of times", + "author": "Ahmad Ouerfelli ", + "license": "MIT", + "keywords": [ + "station", + "timer" + ], + "homepage": "https://github.com/aouerfelli/station-timer#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/aouerfelli/station-timer.git" + }, + "bugs": { + "url": "https://github.com/aouerfelli/station-timer/issues" + }, + "main": "./app/main.js", "scripts": { - "start": "electron ./app", - "dev": "nodemon --exec \"npm start\" -e \"js css html\"", + "start": "electron .", + "watch": "nodemon --exec \"npm start\" -e \"js css html\"", "pack": "build --dir", "dist": "build", "postinstall": "install-app-deps" @@ -28,8 +47,11 @@ } }, "devDependencies": { - "electron": "^1.4.13", + "electron": "^1.6.3", "electron-builder": "^10.17.3", + "eslint": "^3.18.0", + "eslint-config-airbnb-base": "^11.1.1", + "eslint-plugin-import": "^2.2.0", "nodemon": "^1.11.0" } } From 1f028bc4f4c61b848d0c0cb92c6180c8f1a35524 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Mon, 20 Mar 2017 19:37:11 -0400 Subject: [PATCH 02/11] More refactoring Using native async/await Simplified some logic --- app/renderers/index.js | 221 ++++++++++++++++++----------------------- app/renderers/pause.js | 4 +- app/renderers/setup.js | 18 ++-- 3 files changed, 105 insertions(+), 138 deletions(-) diff --git a/app/renderers/index.js b/app/renderers/index.js index 6cd1ed6..1c6a59c 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -1,26 +1,26 @@ const { ipcRenderer, remote } = require('electron'); -const webContents = remote.getCurrentWebContents(); - const domElements = { - counterTextView: document.getElementById('counter'), - secondProgressBar: document.getElementById('progress'), - infoTextView: document.getElementById('info'), - pauseButton: document.getElementById('pause'), - restartButton: document.getElementById('restart'), - muteOnButton: document.getElementById('mute-on'), - muteOffButton: document.getElementById('mute-off'), - exitButton: document.getElementById('exit'), + counter: document.getElementById('counter'), + progress: document.getElementById('progress'), + info: document.getElementById('info'), + buttons: { + pause: document.getElementById('pause'), + restart: document.getElementById('restart'), + muteOn: document.getElementById('mute-on'), + muteOff: document.getElementById('mute-off'), + exit: document.getElementById('exit'), + }, }; const beepAudio = new Audio('../assets/audio/beep.wav'); // Object containing strings used in the counter const text = { - counterText: { + counter: { end: '0', }, - infoText: { + info: { active: 'Complete your activity', coolDown: 'Go to your next station', complete: 'Return to your original station', @@ -28,85 +28,30 @@ const text = { }; // Object containing values for duration, break duration and number of repeats -let settings; +let settings = null; // Flag indicating whether or not the program is currently in a paused state let paused = false; -domElements.pauseButton.addEventListener('click', () => { - paused = true; - ipcRenderer.send('pause'); -}); - -domElements.restartButton.addEventListener('click', () => webContents.send('start-timer', settings)); - -domElements.muteOnButton.addEventListener('click', () => { - webContents.setAudioMuted(true); - domElements.muteOnButton.parentElement.style.display = 'none'; - domElements.muteOffButton.parentElement.style.display = ''; -}); - -domElements.muteOffButton.addEventListener('click', () => { - webContents.setAudioMuted(false); - domElements.muteOffButton.parentElement.style.display = 'none'; - domElements.muteOnButton.parentElement.style.display = ''; -}); - -domElements.exitButton.addEventListener('click', () => ipcRenderer.send('exit')); +// If a single element is given, place it in an array +const ensureArray = arr => (Array.isArray(arr) ? arr : [arr]); -// Since the counter has no pointer events when counting, this will only -// trigger at the end when the end class is added to the counter, which -// enables pointer events. -domElements.counterTextView.addEventListener('click', () => ipcRenderer.send('exit')); - -/** - * This function allows us to use Promises with generator functions, much like - * the async/await feature in ES7 (not supported in Electron v1.4.13). This - * allows us to write asyncronous code that looks similar to syncronous code. - * The basis for this function was derived from Jake Archibald's - * [JavaScript Promises: an Introduction]{@link https://developers.google.com/web/fundamentals/getting-started/primers/promises#bonus_round_promises_and_generators}. - * - * @param generatorFn the generator function that will yield Promises. - */ -const async = (generatorFn) => { - const continuer = (verb, arg) => { - let result; - try { - result = generator[verb](arg); - } catch (err) { - return Promise.reject(err); - } - return result.done ? - result.value : - Promise.resolve(result.value).then(onResolved, onRejected); - }; - - let generator = generatorFn(); - let onResolved = continuer.bind(continuer, 'next'); - let onRejected = continuer.bind(continuer, 'throw'); - return onResolved(); -}; +// Executes a function if it is given (bad design is used to make this a one-liner) +const optionalCallback = func => typeof func !== 'function' || func(); const skipTransition = (elements, action) => { - // If a single element is given, place it in an array - if (elements.constructor !== Array) { - elements = [elements]; - } - // Run the action function if it is given - if (typeof action === 'function') { - action(); - } - elements.forEach(element => { - element.classList.add('skip-transition'); - element.offsetHeight; // Trigger CSS reflow to flush changes - element.classList.remove('skip-transition'); + optionalCallback(action); + ensureArray(elements).forEach((el) => { + el.classList.add('skip-transition'); + el.offsetHeight; // Trigger CSS reflow to flush changes + el.classList.remove('skip-transition'); }); }; const setProgressBar = () => { - skipTransition(domElements.secondProgressBar, () => - domElements.secondProgressBar.classList.remove('expand')); - domElements.secondProgressBar.classList.add('expand'); + skipTransition(domElements.progress, () => + domElements.progress.classList.remove('expand')); + domElements.progress.classList.add('expand'); }; const getFormattedTime = (seconds) => { @@ -116,13 +61,17 @@ const getFormattedTime = (seconds) => { let ss = parseInt(seconds % 60, 10); // Displaying or hiding units based on length of time (up to hours) - hh = hh > 0 ? hh + ':' : ''; - mm = hh === '' && mm <= 0 ? '' : - hh !== '' && mm < 10 ? '0' + mm + ':' : mm + ':'; - ss = mm === '' ? ss : - ss < 10 ? '0' + ss : ss; - - return hh + mm + ss; + // Hours + if (hh > 0) hh = `${hh}:`; + else hh = ''; + // Minutes + if (hh === '' && mm <= 0) mm = ''; + else if (hh !== '' && mm < 10) mm = `0${mm}:`; + else mm = `${mm}:`; + // Seconds + if (mm !== '' && ss < 10) ss = `0${ss}`; + + return `${hh}${mm}${ss}`; }; const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); @@ -134,59 +83,83 @@ const pauseWait = () => Promise.resolve(paused = ipcRenderer.sendSync('pause-wai const countdown = (duration, view, onEachSecond) => { const action = () => { - // Run the onEachSecond function if it is given - if (typeof onEachSecond === 'function') { - onEachSecond(); - } + optionalCallback(onEachSecond); view.textContent = getFormattedTime(duration--); }; - return Promise.resolve(async(function* () { + return Promise.resolve((async () => { // We'll be decrementing duration each second in action() while (duration > 0) { if (paused) { - yield pauseWait(); + await pauseWait(); } else { action(); - yield sleep(1000); + await sleep(1000); } } + // Check for pause before ending countdown if (paused) { - yield pauseWait(); + await pauseWait(); } - })); + })()); }; +domElements.buttons.pause.addEventListener('click', () => { + paused = true; + ipcRenderer.send('pause'); +}); + +domElements.buttons.restart.addEventListener('click', () => remote.getCurrentWebContents().send('start-timer', settings)); + +domElements.buttons.muteOn.addEventListener('click', () => { + remote.getCurrentWebContents().setAudioMuted(true); + domElements.buttons.muteOn.parentElement.style.display = 'none'; + domElements.buttons.muteOff.parentElement.style.display = ''; +}); + +domElements.buttons.muteOff.addEventListener('click', () => { + remote.getCurrentWebContents().setAudioMuted(false); + domElements.buttons.muteOff.parentElement.style.display = 'none'; + domElements.buttons.muteOn.parentElement.style.display = ''; +}); + +domElements.buttons.exit.addEventListener('click', () => ipcRenderer.send('exit')); + +// Since the counter has no pointer events when counting, this will only +// trigger at the end when the end class is added to the counter, which +// enables pointer events. +domElements.counter.addEventListener('click', () => ipcRenderer.send('exit')); + ipcRenderer.on('start-timer', (evt, userSettings) => { const { duration, breakDuration, numRepeats } = userSettings; settings = userSettings; const resetTimer = () => { // Reset elements to their intended initial visibility - domElements.restartButton.parentElement.style.display = 'none'; - domElements.pauseButton.parentElement.style.display = ''; + domElements.buttons.restart.parentElement.style.display = 'none'; + domElements.buttons.pause.parentElement.style.display = ''; // Remove all classes from the views document.body.classList = ''; - domElements.counterTextView.classList = ''; - domElements.secondProgressBar.classList = ''; - domElements.infoTextView.classList = ''; + domElements.counter.classList = ''; + domElements.progress.classList = ''; + domElements.info.classList = ''; }; const durationCountdown = () => { - domElements.counterTextView.classList.remove('red'); - domElements.counterTextView.classList.add('primary'); - domElements.secondProgressBar.classList.remove('red'); - domElements.infoTextView.textContent = text.infoText.active; - return countdown(duration, domElements.counterTextView, setProgressBar); + domElements.counter.classList.remove('red'); + domElements.counter.classList.add('primary'); + domElements.progress.classList.remove('red'); + domElements.info.textContent = text.info.active; + return countdown(duration, domElements.counter, setProgressBar); }; const breakDurationCountdown = () => { - domElements.counterTextView.classList.remove('primary'); - domElements.counterTextView.classList.add('red'); - domElements.secondProgressBar.classList.add('red'); - domElements.infoTextView.textContent = text.infoText.coolDown; - return countdown(breakDuration, domElements.counterTextView, () => { + domElements.counter.classList.remove('primary'); + domElements.counter.classList.add('red'); + domElements.progress.classList.add('red'); + domElements.info.textContent = text.info.coolDown; + return countdown(breakDuration, domElements.counter, () => { beepAudio.play(); setProgressBar(); }); @@ -194,25 +167,25 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { const endTimer = () => { // Setting end classes - domElements.secondProgressBar.classList.add('remove'); - skipTransition(domElements.counterTextView, () => - domElements.counterTextView.classList.remove('red')); - domElements.counterTextView.classList.add('end'); + domElements.progress.classList.add('remove'); + skipTransition(domElements.counter, () => + domElements.counter.classList.remove('red')); + domElements.counter.classList.add('end'); // Setting end text to views - domElements.counterTextView.textContent = text.counterText.end; - domElements.infoTextView.textContent = text.infoText.complete; + domElements.counter.textContent = text.counter.end; + domElements.info.textContent = text.info.complete; // Setting end visibility for Action Buttons - domElements.pauseButton.parentElement.style.display = 'none'; - domElements.restartButton.parentElement.style.display = ''; + domElements.buttons.pause.parentElement.style.display = 'none'; + domElements.buttons.restart.parentElement.style.display = ''; }; - async(function* () { + (async () => { resetTimer(); // Start the timer: repeat for however many stations there are - for (let i = 0; i < numRepeats; i += 1) { - yield durationCountdown(); - yield breakDurationCountdown(); + for (let i = 0; i < numRepeats; i++) { + await durationCountdown(); + await breakDurationCountdown(); } endTimer(); - }); + })(); }); diff --git a/app/renderers/pause.js b/app/renderers/pause.js index a1ae7e4..622f71c 100644 --- a/app/renderers/pause.js +++ b/app/renderers/pause.js @@ -1,8 +1,6 @@ const { remote } = require('electron'); -const resumeButton = document.getElementById('resume'); - -resumeButton.addEventListener('click', () => { +document.getElementById('resume').addEventListener('click', () => { const win = remote.getCurrentWindow(); // Lose focus before closing setup modal to prevent screen flash win.blur(); diff --git a/app/renderers/setup.js b/app/renderers/setup.js index ee2d176..6ce2b67 100644 --- a/app/renderers/setup.js +++ b/app/renderers/setup.js @@ -2,7 +2,6 @@ const { ipcRenderer, remote } = require('electron'); const setupForm = document.forms.namedItem('setup'); const setupFormInputs = Array.from(setupForm.querySelectorAll('input[type="number"]')); -const exitButton = document.getElementById('exit'); const checkValidInput = (value, min, max) => // The handling of empty inputs is done in CSS. If the input is not empty and @@ -24,16 +23,13 @@ setupFormInputs.forEach((input) => { setupForm.addEventListener('submit', (evt) => { evt.preventDefault(); - const valid = setupFormInputs.every((input) => { - const invalid = input.classList.contains('error'); - if (invalid) { - // If any of the form inputs contain errors, focus on it - input.focus(); - } - return !invalid; - }); // Return early (don't finish submitting the form) if not all inputs are valid - if (!valid) { + if (setupFormInputs.every((input) => { + const invalid = input.classList.contains('error'); + // If any of the form inputs contain errors, focus on it + if (invalid) input.focus(); + return invalid; + })) { return; } @@ -48,4 +44,4 @@ setupForm.addEventListener('submit', (evt) => { win.destroy(); }); -exitButton.addEventListener('click', () => ipcRenderer.send('exit')); +document.getElementById('exit').addEventListener('click', () => ipcRenderer.send('exit')); From 9d8b6692c4c2e60beb10ee7012cd39145b625aa0 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Mon, 20 Mar 2017 19:44:50 -0400 Subject: [PATCH 03/11] Adjusted height of progress bar --- app/styles/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/styles/index.css b/app/styles/index.css index 217dc7a..716284d 100644 --- a/app/styles/index.css +++ b/app/styles/index.css @@ -65,7 +65,7 @@ body.dim::after { --color-progress: var(--color-primary); background-color: var(--color-progress); width: 0; - height: 0.3rem; + height: 0.3125rem; margin: auto; margin-bottom: 1.5rem; border-radius: var(--corner-radius); From eed9481c9bbaefdc4dda851b22e2c048a03408e7 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Sat, 25 Mar 2017 12:12:11 -0400 Subject: [PATCH 04/11] Some more refactoring --- app/renderers/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/renderers/index.js b/app/renderers/index.js index 1c6a59c..53e0bf8 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -36,14 +36,14 @@ let paused = false; // If a single element is given, place it in an array const ensureArray = arr => (Array.isArray(arr) ? arr : [arr]); -// Executes a function if it is given (bad design is used to make this a one-liner) -const optionalCallback = func => typeof func !== 'function' || func(); +// Executes a function if it is given and if not then a noop function is executed +const optionalCallback = func => (typeof func === 'function' ? func : () => {})(); const skipTransition = (elements, action) => { optionalCallback(action); ensureArray(elements).forEach((el) => { el.classList.add('skip-transition'); - el.offsetHeight; // Trigger CSS reflow to flush changes + (() => el.offsetHeight)(); // Trigger CSS reflow to flush changes el.classList.remove('skip-transition'); }); }; @@ -179,13 +179,13 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { domElements.buttons.restart.parentElement.style.display = ''; }; + const countdownAction = () => Promise.resolve(durationCountdown().then(breakDurationCountdown)); + (async () => { resetTimer(); - // Start the timer: repeat for however many stations there are - for (let i = 0; i < numRepeats; i++) { - await durationCountdown(); - await breakDurationCountdown(); - } + await Promise.all( + Array(numRepeats).fill(countdownAction) + .map(action => Promise.resolve().then(action))); endTimer(); })(); }); From db4b9cda07b7edd832a46b35ca5ec1d145d72df9 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Sun, 25 Jun 2017 15:22:36 -0400 Subject: [PATCH 05/11] Miscellaneous refactoring More consistency --- .eslintrc | 3 +- app/main.js | 25 +++++++-------- app/renderers/index.js | 70 +++++++++++++++++++++++++++--------------- app/views/index.html | 3 ++ app/views/setup.html | 2 +- package.json | 2 +- 6 files changed, 66 insertions(+), 39 deletions(-) diff --git a/.eslintrc b/.eslintrc index 35b8d86..30680eb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,6 +8,7 @@ "rules": { "import/extensions": 0, "import/no-extraneous-dependencies": 0, - "import/no-unresolved": [2, { "ignore": ["electron"] }] + "import/no-unresolved": [2, { "ignore": ["electron"] }], + "no-param-reassign": ["error", { "props": false }] } } diff --git a/app/main.js b/app/main.js index a21234d..fbb737e 100644 --- a/app/main.js +++ b/app/main.js @@ -1,9 +1,19 @@ const { app, BrowserWindow, ipcMain } = require('electron'); +const DEVELOPMENT = true; + let mainWindow = null; let setupWindow = null; let pauseWindow = null; +const initializeWindow = (windowType, windowName) => { + windowType.loadURL(`file://${__dirname}/views/${windowName}.html`); + windowType.setMenu(null); + windowType.webContents.openDevTools(DEVELOPMENT); + + windowType.once('ready-to-show', windowType.show); +}; + const exitApp = () => { // Do not exit the program on macOS (standard OS-specific behaviour). // Instead, lose app focus and close all open windows. @@ -20,10 +30,7 @@ const createMainWindow = () => { fullscreen: true, frame: false, }); - mainWindow.loadURL(`file://${__dirname}/views/index.html`); - mainWindow.setMenu(null); - - mainWindow.once('ready-to-show', mainWindow.show); + initializeWindow(mainWindow, 'index'); mainWindow.on('closed', () => (mainWindow = null)); }; @@ -36,10 +43,7 @@ const createSetupModalWindow = () => { minHeight: 300, frame: false, }); - setupWindow.loadURL(`file://${__dirname}/views/setup.html`); - setupWindow.setMenu(null); - - setupWindow.once('ready-to-show', setupWindow.show); + initializeWindow(setupWindow, 'setup'); setupWindow.on('close', exitApp); @@ -58,10 +62,7 @@ const createPauseModalWindow = () => { closable: false, frame: false, }); - pauseWindow.loadURL(`file://${__dirname}/views/pause.html`); - pauseWindow.setMenu(null); - - pauseWindow.once('ready-to-show', pauseWindow.show); + initializeWindow(pauseWindow, 'pause'); pauseWindow.on('close', exitApp); diff --git a/app/renderers/index.js b/app/renderers/index.js index 53e0bf8..6247822 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -11,10 +11,11 @@ const domElements = { muteOff: document.getElementById('mute-off'), exit: document.getElementById('exit'), }, + audio: { + beep: document.getElementById('beep'), + }, }; -const beepAudio = new Audio('../assets/audio/beep.wav'); - // Object containing strings used in the counter const text = { counter: { @@ -34,10 +35,12 @@ let settings = null; let paused = false; // If a single element is given, place it in an array -const ensureArray = arr => (Array.isArray(arr) ? arr : [arr]); +const ensureArray = arr => + (Array.isArray(arr) ? arr : [arr]); // Executes a function if it is given and if not then a noop function is executed -const optionalCallback = func => (typeof func === 'function' ? func : () => {})(); +const optionalCallback = func => + (typeof func === 'function' ? func : () => {})(); const skipTransition = (elements, action) => { optionalCallback(action); @@ -55,41 +58,56 @@ const setProgressBar = () => { }; const getFormattedTime = (seconds) => { - // Get units of time (from seconds up to hours) + // --- Get units of time (from seconds up to hours) --- let hh = parseInt(seconds / 3600, 10); let mm = parseInt((seconds % 3600) / 60, 10); let ss = parseInt(seconds % 60, 10); - // Displaying or hiding units based on length of time (up to hours) + // --- Displaying or hiding units based on length of time (up to hours) --- // Hours - if (hh > 0) hh = `${hh}:`; - else hh = ''; + if (hh > 0) { + hh = `${hh}:`; + } else { + hh = ''; + } // Minutes - if (hh === '' && mm <= 0) mm = ''; - else if (hh !== '' && mm < 10) mm = `0${mm}:`; - else mm = `${mm}:`; + if (hh === '' && mm <= 0) { + mm = ''; + } else if (hh !== '' && mm < 10) { + mm = `0${mm}:`; + } else { + mm = `${mm}:`; + } // Seconds - if (mm !== '' && ss < 10) ss = `0${ss}`; + if (mm !== '' && ss < 10) { + ss = `0${ss}`; + } return `${hh}${mm}${ss}`; }; -const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); +const sleep = ms => + new Promise(resolve => setTimeout(resolve, ms)); // The pause-wait channel will return a value of false when the pause modal is // closed, which we can set to the paused flag. When the flag is set, the // Promise will be resolved. -const pauseWait = () => Promise.resolve(paused = ipcRenderer.sendSync('pause-wait')); +const pauseWait = () => + Promise.resolve(paused = ipcRenderer.sendSync('pause-wait')); + +const countdown = (duration, counterView, onEachSecond) => { + let currentSecond = duration; -const countdown = (duration, view, onEachSecond) => { const action = () => { optionalCallback(onEachSecond); - view.textContent = getFormattedTime(duration--); + counterView.textContent = getFormattedTime(currentSecond); + currentSecond -= 1; }; + return Promise.resolve((async () => { - // We'll be decrementing duration each second in action() - while (duration > 0) { + // The current second will be decremented each second in the action function + while (currentSecond > 0) { if (paused) { await pauseWait(); } else { @@ -98,7 +116,7 @@ const countdown = (duration, view, onEachSecond) => { } } - // Check for pause before ending countdown + // Check for pause before ending the countdown if (paused) { await pauseWait(); } @@ -160,7 +178,7 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { domElements.progress.classList.add('red'); domElements.info.textContent = text.info.coolDown; return countdown(breakDuration, domElements.counter, () => { - beepAudio.play(); + domElements.audio.beep.play(); setProgressBar(); }); }; @@ -179,13 +197,17 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { domElements.buttons.restart.parentElement.style.display = ''; }; - const countdownAction = () => Promise.resolve(durationCountdown().then(breakDurationCountdown)); + const countdownAction = async () => { + await durationCountdown(); + await breakDurationCountdown(); + }; (async () => { resetTimer(); - await Promise.all( - Array(numRepeats).fill(countdownAction) - .map(action => Promise.resolve().then(action))); + for (let stationsLeft = numRepeats - 1; stationsLeft >= 0; stationsLeft -= 1) { + // TODO: display the stations left value on the view + await countdownAction(); + } endTimer(); })(); }); diff --git a/app/views/index.html b/app/views/index.html index a64c6ea..2dc9f82 100644 --- a/app/views/index.html +++ b/app/views/index.html @@ -10,6 +10,8 @@ + +

@@ -18,6 +20,7 @@

+
diff --git a/app/views/setup.html b/app/views/setup.html index 6ad5529..efb1ec4 100644 --- a/app/views/setup.html +++ b/app/views/setup.html @@ -11,7 +11,7 @@
- Set Up Your Timer + Set up your timer
diff --git a/package.json b/package.json index 7ea03c7..f85cedc 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "devDependencies": { "electron": "^1.6.3", "electron-builder": "^10.17.3", - "eslint": "^3.18.0", + "eslint": "^3.19.0", "eslint-config-airbnb-base": "^11.1.1", "eslint-plugin-import": "^2.2.0", "nodemon": "^1.11.0" From 221836c10933e2e59efd164fa2e41747c4993a57 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Sun, 25 Jun 2017 17:21:28 -0400 Subject: [PATCH 06/11] Added counter for stations remaining Updated dependencies --- app/renderers/index.js | 36 ++++++++++++++++++++++++++++++++++-- app/styles/index.css | 5 +++++ app/views/index.html | 1 + package.json | 9 ++++++--- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/app/renderers/index.js b/app/renderers/index.js index 6247822..2ea8666 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -1,6 +1,8 @@ const { ipcRenderer, remote } = require('electron'); +const numberToWords = require('number-to-words'); const domElements = { + remaining: document.getElementById('remaining'), counter: document.getElementById('counter'), progress: document.getElementById('progress'), info: document.getElementById('info'), @@ -18,6 +20,11 @@ const domElements = { // Object containing strings used in the counter const text = { + remaining: { + multiple: ' stations remaining', + single: 'Last station', + none: 'No more stations', + }, counter: { end: '0', }, @@ -34,6 +41,12 @@ let settings = null; // Flag indicating whether or not the program is currently in a paused state let paused = false; +// If a string is given and it is not empty, convert it to a "Sentence case" string +const toSentenceCase = str => + ((typeof str === 'string' && str.length > 0) ? + str.charAt(0).toUpperCase() + str.substring(1).toLowerCase() : + ''); + // If a single element is given, place it in an array const ensureArray = arr => (Array.isArray(arr) ? arr : [arr]); @@ -197,6 +210,23 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { domElements.buttons.restart.parentElement.style.display = ''; }; + const setRemainingText = (stationsLeft) => { + let stationsLeftText = ''; + // Determine text to be displayed on the stations remaining counter + // The text is based on the number of stations left + if (stationsLeft === 0) { + stationsLeftText = text.remaining.none; + } else if (stationsLeft === 1) { + stationsLeftText = text.remaining.single; + } else { + // Concatenate the word form of the number of stations left with the text + stationsLeftText = toSentenceCase(numberToWords.toWords(stationsLeft)); + stationsLeftText += text.remaining.multiple; + } + // Set the calculated text to the stations remaining counter view + domElements.remaining.textContent = stationsLeftText; + }; + const countdownAction = async () => { await durationCountdown(); await breakDurationCountdown(); @@ -204,9 +234,11 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { (async () => { resetTimer(); - for (let stationsLeft = numRepeats - 1; stationsLeft >= 0; stationsLeft -= 1) { - // TODO: display the stations left value on the view + for (let stationsLeft = numRepeats; stationsLeft > 0; stationsLeft -= 1) { + setRemainingText(stationsLeft); await countdownAction(); + // This is called here to update the counter text before the loop is broken + setRemainingText(stationsLeft - 1); } endTimer(); })(); diff --git a/app/styles/index.css b/app/styles/index.css index 716284d..2ee23f2 100644 --- a/app/styles/index.css +++ b/app/styles/index.css @@ -23,6 +23,11 @@ body.dim::after { background-color: rgba(0, 0, 0, 0.5); } +#remaining { + font-size: 1.25em; + opacity: 0.75; +} + #counter { --color-counter: var(--color-grey); color: var(--color-counter); diff --git a/app/views/index.html b/app/views/index.html index 2dc9f82..c1b7312 100644 --- a/app/views/index.html +++ b/app/views/index.html @@ -13,6 +13,7 @@
+

diff --git a/package.json b/package.json index f85cedc..d714bba 100644 --- a/package.json +++ b/package.json @@ -46,12 +46,15 @@ "category": "Utility" } }, + "dependencies": { + "number-to-words": "^1.2.3" + }, "devDependencies": { - "electron": "^1.6.3", + "electron": "^1.6.11", "electron-builder": "^10.17.3", "eslint": "^3.19.0", - "eslint-config-airbnb-base": "^11.1.1", - "eslint-plugin-import": "^2.2.0", + "eslint-config-airbnb-base": "^11.2.0", + "eslint-plugin-import": "^2.6.0", "nodemon": "^1.11.0" } } From 8f756317cf9dc58c27656992e29b3a8e3c0768e4 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Sun, 25 Jun 2017 20:58:13 -0400 Subject: [PATCH 07/11] Added basic action button custom element --- app/elements/action-button/action-button.html | 90 +++++++++++++++++++ app/elements/action-button/action-button.js | 72 +++++++++++++++ app/main.js | 12 ++- app/styles/base.css | 79 +--------------- app/views/index.html | 58 ++---------- app/views/pause.html | 2 +- app/views/setup.html | 13 +-- 7 files changed, 184 insertions(+), 142 deletions(-) create mode 100644 app/elements/action-button/action-button.html create mode 100644 app/elements/action-button/action-button.js diff --git a/app/elements/action-button/action-button.html b/app/elements/action-button/action-button.html new file mode 100644 index 0000000..54f82e4 --- /dev/null +++ b/app/elements/action-button/action-button.html @@ -0,0 +1,90 @@ + + + diff --git a/app/elements/action-button/action-button.js b/app/elements/action-button/action-button.js new file mode 100644 index 0000000..9f00499 --- /dev/null +++ b/app/elements/action-button/action-button.js @@ -0,0 +1,72 @@ +/* eslint-disable no-underscore-dangle */ + +class ActionButton extends HTMLElement { + + static get observedAttributes() { + return ['label', 'icon']; + } + + constructor() { + super(); + + const ownerDocument = document.currentScript.ownerDocument; + const template = ownerDocument.querySelector('#action-button-template'); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(template.content.cloneNode(true)); + + this._components = { + label: { + name: 'label', + element: shadowRoot.querySelector('.label'), + }, + icon: { + name: 'icon', + element: shadowRoot.querySelector('.icon'), + }, + }; + } + + getAttributeValue(attributeName) { + return this.hasAttribute(attributeName) ? this.getAttribute(attributeName) : ''; + } + + get label() { + return this.getAttributeValue(this._components.label.name); + } + + set label(label) { + if (!label) { + return; + } + + this._components.label.element.textContent = label; + } + + get icon() { + return this.getAttributeValue(this._components.icon.name); + } + + set icon(icon) { + if (!icon) { + return; + } + + this._components.icon.element.setAttribute('d', icon); + } + + // connectedCallback() { + // } + + // disconnectedCallback() { + // } + + attributeChangedCallback(attributeName, oldValue, newValue) { + if (attributeName === this._components.label.name) { + this.label = newValue; + } else if (attributeName === this._components.icon.name) { + this.icon = newValue; + } + } +} + +window.customElements.define('action-button', ActionButton); diff --git a/app/main.js b/app/main.js index fbb737e..f593771 100644 --- a/app/main.js +++ b/app/main.js @@ -1,6 +1,12 @@ const { app, BrowserWindow, ipcMain } = require('electron'); -const DEVELOPMENT = true; +/** @constant { boolean } + * + * Checks if the current environment is in development by looking for the asar package. + * If the package exists, then the app is in production mode. + * Otherwise (if it is not found), then the program is in development mode. + */ +const DEVELOPMENT = process.mainModule.filename.indexOf('app.asar') === -1; let mainWindow = null; let setupWindow = null; @@ -9,7 +15,9 @@ let pauseWindow = null; const initializeWindow = (windowType, windowName) => { windowType.loadURL(`file://${__dirname}/views/${windowName}.html`); windowType.setMenu(null); - windowType.webContents.openDevTools(DEVELOPMENT); + if (DEVELOPMENT) { + windowType.webContents.openDevTools(); + } windowType.once('ready-to-show', windowType.show); }; diff --git a/app/styles/base.css b/app/styles/base.css index 704694e..e8f59cb 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -177,86 +177,9 @@ button[type='submit'] svg { margin-left: 0.5rem; } -/* Action Button styles for all pages (would preferably be a Custom Element, but v1 of the API is not currently supported (Electron v1.4.13)) */ - +/* Action Button container positioning */ .action-buttons { position: fixed; bottom: 0; right: 0; } - -.action-buttons div { - display: inline-flex; - flex-direction: column-reverse; - align-items: center; - justify-content: center; -} - -.action-buttons div button { - position: relative; - display: flex; - align-items: center; - justify-content: center; - padding: 0.375rem; - margin: 0.75rem; - margin-top: 0; - outline: none; - border: none; - background-color: transparent; -} - -.action-buttons div button::before { - content: ''; - position: absolute; - z-index: -1; - width: 0; - height: 0; - border-radius: 50%; - background-color: var(--color-grey); - opacity: 0; - transition: all 0.3s var(--curve-standard); - transition-property: width, height, opacity; - /* Since there are not that many buttons on each page, it's fine to give each of them a layer initially instead of dynamically */ - will-change: width, height, opacity; -} - -.action-buttons div button:active::before { - width: 3rem; - height: 3rem; - opacity: 0.3; -} - -.action-buttons div button svg { - width: 2.25rem; - height: 2.25rem; - fill: var(--color-grey); - transition: fill 0.3s var(--curve-standard); - will-change: fill; -} - -.action-buttons div button:focus svg { - fill: var(--color-primary-light); -} - -.action-buttons div button:hover svg { - fill: var(--color-primary); -} - -.action-buttons div button:active svg { - fill: var(--color-primary-dark); -} - -.action-buttons div p { - display: inline-block; - padding: 0.25rem 0.5rem; - font-size: 0.8em; - border-radius: var(--corner-radius); - color: var(--font-color-light); - background-color: var(--font-color-dark); - opacity: 0; - transition: opacity 0.3s var(--curve-sharp); -} - -.action-buttons div button:hover ~ p { - opacity: 0.7; -} diff --git a/app/views/index.html b/app/views/index.html index c1b7312..6d6af63 100644 --- a/app/views/index.html +++ b/app/views/index.html @@ -1,10 +1,11 @@ - + Station Timer + @@ -19,57 +20,12 @@

- - -
- -
- -

Pause

-
- - -
- -

Restart

-
- -
- -

Mute

-
- -
- -

Unmute

-
- -
- -

Exit

-
- + + + + +
diff --git a/app/elements/action-button/action-button.js b/app/elements/action-button/action-button.js index 9f00499..d8a0b9b 100644 --- a/app/elements/action-button/action-button.js +++ b/app/elements/action-button/action-button.js @@ -15,14 +15,10 @@ class ActionButton extends HTMLElement { shadowRoot.appendChild(template.content.cloneNode(true)); this._components = { - label: { - name: 'label', - element: shadowRoot.querySelector('.label'), - }, - icon: { - name: 'icon', - element: shadowRoot.querySelector('.icon'), - }, + container: shadowRoot.querySelector('.container'), + button: shadowRoot.querySelector('.button'), + label: shadowRoot.querySelector('.label'), + icon: shadowRoot.querySelector('.icon'), }; } @@ -31,7 +27,7 @@ class ActionButton extends HTMLElement { } get label() { - return this.getAttributeValue(this._components.label.name); + return this.getAttributeValue(this._components.label.className); } set label(label) { @@ -39,11 +35,11 @@ class ActionButton extends HTMLElement { return; } - this._components.label.element.textContent = label; + this._components.label.textContent = label; } get icon() { - return this.getAttributeValue(this._components.icon.name); + return this.getAttributeValue(this._components.icon.className); } set icon(icon) { @@ -51,22 +47,58 @@ class ActionButton extends HTMLElement { return; } - this._components.icon.element.setAttribute('d', icon); + this._components.icon.setAttribute('d', icon); } - // connectedCallback() { - // } + connectedCallback() { + // Action is a noop function by default + this.setAction(() => {}); + } - // disconnectedCallback() { - // } + disconnectedCallback() { + // Remove action from element on callback + this.removeAction(); + } attributeChangedCallback(attributeName, oldValue, newValue) { - if (attributeName === this._components.label.name) { + if (attributeName === this._components.label.className) { this.label = newValue; - } else if (attributeName === this._components.icon.name) { + // Must check with baseVal property for icon because the className is a SVGAnimatedString object + } else if (attributeName === this._components.icon.className.baseVal) { this.icon = newValue; } } + + setAction(action) { + if (typeof action !== 'function') { + return; + } + + // Remove the current action and replace it with the new one + this.removeAction(); + this._action = action; + this._components.button.addEventListener('click', this._action); + } + + removeAction() { + this._components.button.removeEventListener('click', this._action); + } + + hideButton() { + this.setHidden(true); + } + + showButton() { + this.setHidden(false); + } + + setHidden(hidden) { + if (typeof hidden !== 'boolean') { + return; + } + + this._components.container.style.display = hidden ? 'none' : ''; + } } window.customElements.define('action-button', ActionButton); diff --git a/app/renderers/index.js b/app/renderers/index.js index 2ea8666..32e866f 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -2,19 +2,19 @@ const { ipcRenderer, remote } = require('electron'); const numberToWords = require('number-to-words'); const domElements = { - remaining: document.getElementById('remaining'), - counter: document.getElementById('counter'), - progress: document.getElementById('progress'), - info: document.getElementById('info'), + remaining: document.querySelector('#remaining'), + counter: document.querySelector('#counter'), + progress: document.querySelector('#progress'), + info: document.querySelector('#info'), buttons: { - pause: document.getElementById('pause'), - restart: document.getElementById('restart'), - muteOn: document.getElementById('mute-on'), - muteOff: document.getElementById('mute-off'), - exit: document.getElementById('exit'), + pause: document.querySelector('#pause'), + restart: document.querySelector('#restart'), + muteOn: document.querySelector('#mute-on'), + muteOff: document.querySelector('#mute-off'), + exit: document.querySelector('#exit'), }, audio: { - beep: document.getElementById('beep'), + beep: document.querySelector('#beep'), }, }; @@ -64,6 +64,18 @@ const skipTransition = (elements, action) => { }); }; +const mute = () => { + remote.getCurrentWebContents().setAudioMuted(true); + domElements.buttons.muteOn.hideButton(); + domElements.buttons.muteOff.showButton(); +}; + +const unmute = () => { + remote.getCurrentWebContents().setAudioMuted(false); + domElements.buttons.muteOff.hideButton(); + domElements.buttons.muteOn.showButton(); +}; + const setProgressBar = () => { skipTransition(domElements.progress, () => domElements.progress.classList.remove('expand')); @@ -117,7 +129,6 @@ const countdown = (duration, counterView, onEachSecond) => { currentSecond -= 1; }; - return Promise.resolve((async () => { // The current second will be decremented each second in the action function while (currentSecond > 0) { @@ -136,26 +147,22 @@ const countdown = (duration, counterView, onEachSecond) => { })()); }; -domElements.buttons.pause.addEventListener('click', () => { +domElements.buttons.pause.setAction(() => { paused = true; ipcRenderer.send('pause'); }); -domElements.buttons.restart.addEventListener('click', () => remote.getCurrentWebContents().send('start-timer', settings)); +domElements.buttons.restart.setAction(() => remote.getCurrentWebContents().send('start-timer', settings)); -domElements.buttons.muteOn.addEventListener('click', () => { - remote.getCurrentWebContents().setAudioMuted(true); - domElements.buttons.muteOn.parentElement.style.display = 'none'; - domElements.buttons.muteOff.parentElement.style.display = ''; +domElements.buttons.muteOn.setAction(() => { + mute(); }); -domElements.buttons.muteOff.addEventListener('click', () => { - remote.getCurrentWebContents().setAudioMuted(false); - domElements.buttons.muteOff.parentElement.style.display = 'none'; - domElements.buttons.muteOn.parentElement.style.display = ''; +domElements.buttons.muteOff.setAction(() => { + unmute(); }); -domElements.buttons.exit.addEventListener('click', () => ipcRenderer.send('exit')); +domElements.buttons.exit.setAction(() => ipcRenderer.send('exit')); // Since the counter has no pointer events when counting, this will only // trigger at the end when the end class is added to the counter, which @@ -167,9 +174,15 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { settings = userSettings; const resetTimer = () => { + // Set muted button based on whether or not the audio is mutedd + if (remote.getCurrentWebContents().isAudioMuted()) { + mute(); + } else { + unmute(); + } // Reset elements to their intended initial visibility - domElements.buttons.restart.parentElement.style.display = 'none'; - domElements.buttons.pause.parentElement.style.display = ''; + domElements.buttons.restart.hideButton(); + domElements.buttons.pause.showButton(); // Remove all classes from the views document.body.classList = ''; domElements.counter.classList = ''; @@ -206,8 +219,8 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { domElements.counter.textContent = text.counter.end; domElements.info.textContent = text.info.complete; // Setting end visibility for Action Buttons - domElements.buttons.pause.parentElement.style.display = 'none'; - domElements.buttons.restart.parentElement.style.display = ''; + domElements.buttons.pause.hideButton(); + domElements.buttons.restart.showButton(); }; const setRemainingText = (stationsLeft) => { diff --git a/app/renderers/pause.js b/app/renderers/pause.js index 622f71c..1ee9e07 100644 --- a/app/renderers/pause.js +++ b/app/renderers/pause.js @@ -1,6 +1,6 @@ const { remote } = require('electron'); -document.getElementById('resume').addEventListener('click', () => { +document.querySelector('#resume').addEventListener('click', () => { const win = remote.getCurrentWindow(); // Lose focus before closing setup modal to prevent screen flash win.blur(); diff --git a/app/renderers/setup.js b/app/renderers/setup.js index 6ce2b67..2b0adb4 100644 --- a/app/renderers/setup.js +++ b/app/renderers/setup.js @@ -44,4 +44,4 @@ setupForm.addEventListener('submit', (evt) => { win.destroy(); }); -document.getElementById('exit').addEventListener('click', () => ipcRenderer.send('exit')); +document.querySelector('#exit').setAction(() => ipcRenderer.send('exit')); diff --git a/app/views/index.html b/app/views/index.html index 6d6af63..f8d5b8d 100644 --- a/app/views/index.html +++ b/app/views/index.html @@ -22,9 +22,9 @@

- + - +
From 865848c4ad05443f5e25da926a79b48c35ea7b98 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Mon, 26 Jun 2017 13:16:27 -0400 Subject: [PATCH 09/11] Addressed a few linting errors Added documentation --- app/renderers/index.js | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/renderers/index.js b/app/renderers/index.js index 32e866f..21e481e 100644 --- a/app/renderers/index.js +++ b/app/renderers/index.js @@ -1,6 +1,7 @@ const { ipcRenderer, remote } = require('electron'); const numberToWords = require('number-to-words'); +// Object that caches all the DOM elements used const domElements = { remaining: document.querySelector('#remaining'), counter: document.querySelector('#counter'), @@ -41,18 +42,18 @@ let settings = null; // Flag indicating whether or not the program is currently in a paused state let paused = false; -// If a string is given and it is not empty, convert it to a "Sentence case" string const toSentenceCase = str => + // If a string is given and it is not empty, convert it to a "Sentence case" string ((typeof str === 'string' && str.length > 0) ? str.charAt(0).toUpperCase() + str.substring(1).toLowerCase() : ''); -// If a single element is given, place it in an array const ensureArray = arr => + // If a single element is given, place it in an array (Array.isArray(arr) ? arr : [arr]); -// Executes a function if it is given and if not then a noop function is executed const optionalCallback = func => + // Executes a function if it is given and if not then a noop function is executed (typeof func === 'function' ? func : () => {})(); const skipTransition = (elements, action) => { @@ -114,10 +115,10 @@ const getFormattedTime = (seconds) => { const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); -// The pause-wait channel will return a value of false when the pause modal is -// closed, which we can set to the paused flag. When the flag is set, the -// Promise will be resolved. const pauseWait = () => + // The pause-wait channel will return a value of false when the pause modal is + // closed, which we can set to the paused flag. When the flag is set, the + // Promise will be resolved. Promise.resolve(paused = ipcRenderer.sendSync('pause-wait')); const countdown = (duration, counterView, onEachSecond) => { @@ -132,15 +133,21 @@ const countdown = (duration, counterView, onEachSecond) => { return Promise.resolve((async () => { // The current second will be decremented each second in the action function while (currentSecond > 0) { + /* eslint-disable no-await-in-loop */ if (paused) { + // Since the loop should not continue when in a paused state, + // the loop is blocked until the pause promise is resolved await pauseWait(); } else { action(); + // After completing the countdown decrementing action, + // the loop must be blocked for a second (1000ms) before resuming the countdown await sleep(1000); } + /* eslint-enable no-await-in-loop */ } - // Check for pause before ending the countdown + // Check for pause request before ending the countdown if (paused) { await pauseWait(); } @@ -249,7 +256,9 @@ ipcRenderer.on('start-timer', (evt, userSettings) => { resetTimer(); for (let stationsLeft = numRepeats; stationsLeft > 0; stationsLeft -= 1) { setRemainingText(stationsLeft); - await countdownAction(); + // Since we do not want the loop to continue until the cooldown promise is resolved, + // we wait for the asynchronous code to complete before moving on to the next iteration + await countdownAction(); // eslint-disable-line no-await-in-loop // This is called here to update the counter text before the loop is broken setRemainingText(stationsLeft - 1); } From 5a4e8a52e0b833a62a5cb42caed60aca34db10f6 Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Mon, 26 Jun 2017 19:23:24 -0400 Subject: [PATCH 10/11] Updated dependecies Fixed bug with settings not being parsed as integers Updated screenshots --- app/elements/action-button/action-button.js | 1 + app/renderers/setup.js | 5 ++++- package.json | 13 ++++++++----- screenshots.gif | Bin 37941 -> 62373 bytes 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/elements/action-button/action-button.js b/app/elements/action-button/action-button.js index d8a0b9b..8595ae5 100644 --- a/app/elements/action-button/action-button.js +++ b/app/elements/action-button/action-button.js @@ -20,6 +20,7 @@ class ActionButton extends HTMLElement { label: shadowRoot.querySelector('.label'), icon: shadowRoot.querySelector('.icon'), }; + this._action = undefined; } getAttributeValue(attributeName) { diff --git a/app/renderers/setup.js b/app/renderers/setup.js index 2b0adb4..fae1d42 100644 --- a/app/renderers/setup.js +++ b/app/renderers/setup.js @@ -34,8 +34,11 @@ setupForm.addEventListener('submit', (evt) => { } ipcRenderer.send('setup-timer', + // An object is created from the form data + // The names of the form fields are used as keys + // The values of the fields are parsed from the supplied string to an integer Object.assign(...Array.from(new FormData(setupForm)) - .map(([k, v]) => ({ [k]: v })))); + .map(([k, v]) => ({ [k]: parseInt(v, 10) })))); const win = remote.getCurrentWindow(); // Lose focus before closing setup modal to prevent screen flash diff --git a/package.json b/package.json index d714bba..4aee547 100644 --- a/package.json +++ b/package.json @@ -25,14 +25,17 @@ "dist": "build", "postinstall": "install-app-deps" }, - "directories": { - "app": "./app" - }, "build": { + "directories": { + "buildResources": "./build/", + "output": "./dist/" + }, "appId": "com.aouerfelli.station-timer", "win": { "target": [ "nsis", + "nsis-web", + "portable", "zip" ] }, @@ -51,8 +54,8 @@ }, "devDependencies": { "electron": "^1.6.11", - "electron-builder": "^10.17.3", - "eslint": "^3.19.0", + "electron-builder": "^19.8.0", + "eslint": "^4.1.1", "eslint-config-airbnb-base": "^11.2.0", "eslint-plugin-import": "^2.6.0", "nodemon": "^1.11.0" diff --git a/screenshots.gif b/screenshots.gif index 96b1cbc51752f229583e40ef19518df559fc5b21..5b926ed3a5259484a4204f5af78ff258165bd865 100644 GIT binary patch literal 62373 zcmagEcU)7?+UUDd2@oJ62vRhHA|NFc=|~{-8hV$|J4C5cLlIDlSiynd#{ z2uKkyA_5|6kd8nuzx|&5o^w8TzxU>!tTlPsto6)1lbNrMp0+0%u>#LqWe_q#0jf*3NgoHeMHECgCvGX7;JaJ%TWJFG{ z=56nXsi~>Qj~{O;i^s;slF4KZ4UO&VUKj;u|A=>6Tf1-HzFk~goS&bkP$&}<6Z!f1 zg@uJuQc{YFinFt`t3NhHMMb@QLZ)Ybxd-=b*%(?o1ivi%L?Xpfsni=cZtPL#$HvAM z7S~fBjehv>p|*JnEn+`N`R?!UUs^Ng<>l4U{dH()C^+ z;GLpjtp~9%C^%wrdg=T3@AsdLGchrZPW(_YuCw!bv%Io_)AO2`{y8%7`_yANOQ?H_LHC=qvFTXB)j*X3piH?ql2>s9e}ySsaT|Nh0Oy->r~@9pnzYRVrT9tw&%9335Q zZ0_#t>@6-*ui$I<4-R&AHZ;r|Lc=1DqjYj|nwy(@^1Lzk)v;On{{Alg=%PCrLyHrBE*$EoABq$MyA z5C8zjO*Te&w5D^g^YOQeS~$_!)z>{3?c(m~9iS@kyY-C#+S^T4!1}Tg#)yb>_wv?_ zxbAKqVQk?V;p?jCCZKi&trD&j?oaf04|Ya}`}+k1DTS*FIJ*V9xGNoB|I;iffc}?A zu&=6s`aeIQ|M7_nyzY*^EFmZEDkY7B`6Ql4kBffg#sj-H*iu z|8YfB!d-WF4i3C-5g6$A@280O3JeYm@(LuPakzh;nmk(A+B?84Ff2&qUphucN_qi7 z!Oj7$?s}T40>@S)yuIC&G&B`4+S1av%j$|aDJd;^MU1*EPFr46K}JDSUPfN)-@2NC zt|9*J0m1*)b^G7Cn*XEjKk494Joc>Ve%(9N-A(&?pg;Ow-B$AcpJP$~AMO1wUAO-^ z7LET=SMoR*$$wt%|M9Z_-E^Em|6Kle>K@wdFk8Y*M%?C&+~J$pJt|~CO=M$k9`=WydN1J8XV~F>wWjOr@O0@ z{HCM5t+l1Osj;EHuC}JSs`7P3d0A;maZ%x`f|vPuxi6mQJbU`&ady_DhY#-GyPJ6@ zBRwtk_N|oUq??He@o}WsnCPg;h#TQyp&`LR*RK%+1N{AbeZ0LqJ>1<~U7QI{R~;Sf z?QCtVtt>6f%}nto#zuw)`g*!L+FF`84Rx&A6;%~wB}D~!xy!OL(oz^n330JYq9Vc< zg)W>I6gY=IdxoEnm*+G$*C|eplk6u@Y^*FuW+p}i0~`j0fR87Lb9+#jG(ZQ$j^_&C zpE3#{=)fT(pKeudX9D7+s6$^>UUxD|Q2&{3b^hB_ZW*81zUr5~chI=oe0ntn{r82< zOC9=aUJYhpTnC=%)fNsvRR~(0?XN9*{{ox9#IIjhJo-}izNq6sUCCGx{-u77etqdg znN6+F+(3QVWF?{dHorkb`E;$GK1bAyeQpWl!m%x4Un zs=jomoV;{(sHysEZ>FHZbHnDEZ-dz~zVk!Pwaf2waj9pFTI#-!6`Pk`9d4=rF+#bbWlK4Vbz9gfQgcnlIKk{0*C0tm%a9gZlWg!*wPWWq@ z>_@M!=?Y85Uo%v;SH9lC!bKJ{HBWgj-qjTt#oi;yI;lS|flJG$tP^16>cKPsA*N_|t?HdlXClHr%us(McOu2uI5m95nb$^BTXrD$LJSvPLw z`?IF?BdlCYV6#+ zH1q~w5TlWyTz<4p#Km%27gBzW){W8;Tkqkp_FI3;Ek7HGnLT<^Y5RAdedrBY_$3l1 zTvYyNK&)}?&mg8(Y-31v(r;r}VYz%`L}h1f<2{zasJ5RB2pYcW*xi@1ZNIHj(=W^> zgOs+g_TQSY@vPYT=n(dEYm$&GzCGoZ<-a}cRaCJ(O*L1M7gjZ`q!&_Z9}l#()XoOF_YN zVF_=U8@qsnKc7cX-7rX1uf*TAy2*gQKbw|c|NYgr^Xu<#GK1s+t%ob{V7>3+du1*M zg|9bOUhdenSQn`osY8&$sBR^N2h_tIYO>_f?qXKp(cVf?<lCj8q6g^qD zM}TKNMb|K&J*%%rNNN2RJ}sZ4XsRc&hr}$-m$Y(EsQdK32KPl@K*|L`iauFS^D=zN zGuih}u4O&lfAI_?r5fqhhDma48~C2s*$7?8O(P-;&XPv+eJoSE6+AA?nJp+>w zEL;i?oVr`BrSjZNv`zQh)-zDT>9(3jeTIe7S^Y!jS8-4U$_1G16&A*IgvB|w$dHSJWz@Um3GCiaok70=l`3J)u8(+fMc|la{C2S*C|6?>6$$EG4=!k4-=#_8N+=^r@qOQM!_!t}@UdFqQU9(o%k zh*F;NY?a_SMa(=)$6rp#mf8&aXceteO4+}a+Od?`eDAlc6oQqz8kN~Sw6&_WdsxCA zvTC=iZ*AN#QK6;o>$o#ujhpAJ#EtqoF&Nm$9dTBvpYU_$8k`b7bE;a+)X(*z!L;C& zQ#Go0{oLgTr_WqHRjWMe=c!{q{XSmqV*Z5+A1>dSvHA1$W$EHh_CIEx(8*Q}O^%oR zeU*dn8m)Xvx z`$tDRA!iL2g>LR?VzSP`JGO)=0Rf@v z+Y??3C(X~ly_6xvX}{)ji)`~wAx0qG7kQU=dAC=8R_YG_f-9Q0IYr})H12lPq7X!? zU*8IGKgaM}B7CaABK>;w7o~C0$kT<^kG!qxk@rMmoBQ!XwdzAr9)d--^kJxT(9_rh z4+Un;k)U_ia(<>QtMrDyC;qB^VTts*%p5@xl#qSQmhQ!R$!;($AXrTp4|3+)9W~7e z)-uOHqc}(a6G;@*hEFg^o-PVqlFYK!w{gdO0p!U#;DX!)fcq{0@xrP@XmKHHG#Dg1 zu4GGuDpnNHRrbi&=`0ZdBXP+ZyCe=xe2?7) zngF(T(?lksbF!4KIw+U~Iw6*u+?yGP%&5kB6p&9JD!^s`#-%a!k+`ruoy=nG-63La zpE*$=>F_4t1R^pS8Q$3glSqgW&IOak&q2(HAQ4I~Sdl)o`%bIM-#rCjIw#r9oJhkl zrC_1*;yBoTXBv}OLUp!PO(9EZ8gDUqRvDVa=vUFrbe;-arKod6jk0m@VVTSnNK8T_ zxY$`L{AkJ<(4Awe3@QIXo=lWKVDKSA+RFeYq%bi4iUcnGo%tu?jrwd(E~M^$PW_zR zcB71Ra02TWfQ`J!riH!wP5GqWzDx9H;nG+x}kU&ZW%#n@EP~x?loWZz{5il*}St?AP1_)1v zoFzgWCfOQtA)}LQtprHR67C2a^=^`_&pK2z7a|)L#ejmT$pT8WfI}=W_K{68H&SI0 zYL?4(UoPfb7_gibuS5w|D@gcMh}%w1#8ly4zJn@5!&eCb7;Ln14>MyX;2Z{GK!stm zB3v6HxYXld-V#detp+%Cc? zaYx?>k59i4r;?Ne|HdYb1s=)+m5Cs`EMS+CDoTY}kdh;IanVij;x=h&UXZg*xE=ze zp28+YidHIMl_#1z5FoACTUz0_Vi1~7`feT45?_T!<#VSvXGJV1i3*kTk>cu!%F8Fy7 zZiJdP<8^C^Tk~`AU3h=|x0JMMeB|m>>MGUum#%GY_+js!JN(QO+AY~cT?R2jxKS&;;;h0Hm^5`h^-hGtF;RW}GZBxswQqZ^T(pZ=LmiXa>YBOr;;9ZeL4IYvE2KPO~{P-eJD! z~Ucq;>WBnohCt(^9ZKYz)L~8FEtpPB3JO?R8QLHj&ws z>%LMC%!%RFAsV8T3G`Ypn-OCU(O`Kr>?YS^RW~pLKHR4HE`x36D_u}6T_~rM#B4~p z|Ke7}y0FK~<`W)@CdgdYDj{F*EY{~mNC@SQ-xP>ckSeQ~rFx!iZR)06CO}F_?D5RH zied==j^jkbV5DH9-i(@eu~Zw75-B#gH)(P&i*s35W>!lbKmon&a?SV z-JB=^9e5-_Psh1VKQAaTGP-O#PXh~+*v^ue^^0-SB#?0?&`Qox3PyrRY^}L|3MhtM zJhKP}a+a7A&j^9iK&vPq_B#%l3whR$LuS5$5x_tTZl40uW`ar5K>S%OTttvMqvjtu zATJ4YmIOTnimtcdL^1*0fuf)pfG3xAmkdIs_`XIwc}thOBe#$GZEGE!qIsDXe(#<6 z<^5t|t0(+PIqJb|^3<%X+is6bOC;Zw@Ok8)WzxjZKuWm~Elg=a%kzBiQn{qkQ$od> zJunEK86{k%QFl+`R0-M6u`9x*$F6)Nq#XUId?3PM=!x^lemR-5f?cj+{E7X?7Q)n% zikkWg=*Nor7CUN-(}L3L0?XH%A+J|vY*%NluFbrDy7hXAv+_^ry;nYEC!8yHL?6|y z`tQ%UHqBIC)vo;fwi0Ual3p4CYDFQQRwcMsO>I@7lp4(IJ_TtjNw9@dERI&h^{vnp3fmU&9iFV!-BskxkLDQ0i4)LPpYQmYV& zQe&>uxlo6*M``)iX-?F>uCFsJGdGU3!`qwAqa)21*@(O4=FE1MWqP`lXh8+dN~p5t zdB_f+B}2X4iT56#sn6c3fBXQvg9RbT00#=$OF~YQRHw;ECMpXH34|d7zn73qRY1IN zlX4wWl88LY1(>}XREhvqJlVuy-#dEGH<_SYRtUQcxw}EngS8P zgF3Uo3CyqyG_YhNk~#TYM|C<>Aq91UxQ6O=pVmP-JCh!OPsn#jkpKY_s1G0B#|&f21}mT;7bvZivi57? z*R=5PdCV&jiVGwILJtz#&!@EDM=*vH>5$C4gK5T~LQ^7}AAe$FsRE{Hetl$M zunIV$^#5SaC~ECVaOm5%fI2B^`418YN;|`~2DcVjG*4^UJ*{Y4v+CfhKV>=O5i-5!S=#xo(d9B`dLG1m}!Fzz80zQ1dIb=J3U``zxcH0`#drDzaHD)j} zXFa5R;TRRZJj#*dgjB8L&KVtY8|9lAJu_^@n_erR`k@c{fi2{Nu#ti2p^4bs2S%$8 z(sbT2X%+*?VPm=Iu|>@>?$$9Cf9orARapM*zxN+l)j0dAnG{t%7yZ<|zKWV7Mb?8<#+oY=3l$fAJlkmK#!6?2zuwZWIOA@Eab=OHQl z$p``&p`v-A3fWC~reOi{{;TNX7Bs23*ohz`wP=AmnP6!u3x)>fq%t>% zLAm51)ujNY&0hwCtRDvUvE6L8v-2dVxhRn#C1L$XyCfAkO(Y?S$iWJ>c{(bPGm}Mn z2dwJQiXcI{DbYQ|ckzdw9{y!js+y9-NRcW)q>A-}0cbdK_LOxi8&@*FJkp^pXfg*Z zMMcU0$l$aar@0`K0Ma`Rm=Vm8!umHbo9L3D)?z_jgf0#=WFK|SdI*-~2vR^@bL~m^ zx$N=VzjR$(QhUCUfe;r0i*y;>4Z+u z1w5231NlLO4K&g=|D$!N?3q+mPzG<8N(ux|VVi>>hnR^~pJv2gmq?z`4F1vEqk1{m z5Sh@56u?9Gi3@_ehMhF8Ur4ptH{Dg#14xu43K>j~>&CKI^oRCjj;)gf-JHkerE4{=Bc#sUG_h}Sc@eqLQ?QfBTfQa!WL(E-7wns^-3gNh&q-H*u_IVPr z$7D$3^K&*Q5Q21l^irk_9xjjxwxjz^BdZSmT9(Jl+V$3YKUL0h6AclW;M2)%376Vh z+*$=FfR|sRG3v5Ogw9-yr4p`jH zw8jv+c~It<1P!$ZB9^b+rayc$$d+;+DX=}c#LO+ZXle5(--(e=np+G@t4%?`56xC^ zWVF^@t}eW2_~;#Vn2Y6KeuKL#I_A&|rB|clIB*bdBnG(O2|FFnJ(4k9U_bfGvF*mz zui;3JURC%A4<5CYYOT|Ai&N5Lc52pzK zA#2n1fmz?Vst8?4;&(1O%^%#@{610XDT%7py(iTCzUYN@_!}nfnpc@|AchYUZIAO( zn9N8EHwjm>)sx%VY7E!JN8zP-uL~ zZ!K=u2PZE42J@CzbW8lxvqmwFkDd`UVOT)d;0GBs~0ey6$WnDGsYzF)r@QG z-0q}v{V!s|n{_1IPU-d=T#Qy1dWCtxkq;sy3c_Ex{{j`Bb>a3RfMU66g>jMPxIZRX zNJWV@jmYr_uX)mv9&D=3+m1ZHD|a&3OkbH9eoJ3wB6#c(qTN(Q2gey=VPMH$1jX^bWvH#kQ?1J~PN@$= z?R?5OH*N4a6QTA2t(^7NdKH{u4%Y`Km_OOITZTD?e!9%&AUOOm>}td}tx3nIjfpU) zbn0RKRTAVB_s7V+%e#ccliOj`)6va3pcKJJ;V!o?HSD^i$$SiV%~0OnJtM*WyqcP5 zAh);Z&vojwcCu>do_n_IqZ>;p>Q@!D@0otQ;rU$8a?c|-;S^8nvq-spuY$;f8(xJ^ zL!T7p-+vV0Qz~Ll-}f%BjZs=HZQb7gk@osygkO!;5|3Zqm=*82>cP;z{z31rMh3LB z2k-{8ZAe)CYWcg}y4<>TDvD;ccl4Lo!^ZlI_>PxtoYo_l6*c#kzwzMDKKeye&`4GV zUl0XHH{2L8ke?fWuVo#*)uO9*7&66aloK-J8`i%ybzDPwr~P;4LTAIcVs^vK)3?JG z?>mWvFFXx9Q#1cCYySGui^ijfjQkfde>=;1k0NOoK0J^7^JV)=)aIDyr(NP;82!)2 zM3&Rx`sc=2-xEhQcR%j^-FcI@KW9SHNc~JlPPGB7_&ATj&tX>{zJ_R5#WDsvi45f? zopQq`@GcSs3d$MpGEh{QwqiKUu?GQZg~g7Hdh#;T%a-q&Mf}nIKCx(vhv~= z7PUM$@flGF=I4Auc}L@qsxvf=;Bqo&S5sKq^tO3{3uj(7{IVuCWlqmIuf|;yW5;%D zHd2G9JX~A0&@|n!XF;HW`=mgUX+|vX*X;*Q+A4)7n7wsz7ilS4;vJ(lj!{%T7R5Ft zOibT0x#@_vc{j^nNQOk1zv^es20ZYi~*3ddx#|O0ua)0R`9H{ zslNGZ_S=Cp5`+(xBu`LJC$*gy+FI5^TsO;px>4}w)QxxE!5XMge79^DAsIQN4qnD5 zK&_e$z35C>FvTxUwrIUaHZhNxcZ$S&o|52bRg;x7u*j6WXWY*zb0fD-;M8mtD8i2n zVfX4hDMtav-0p+~qDYXI+$15{xEDvz;5pT5L+J#VH6$@jI1YO4%ER0D6)a8sDaRu0MgB?)1W&u ziAAkLDTGGU4%yV$Kj}au9!c2btm2?{0paz350eiI>^9p~;pQM|8QX1xCN45AYeK?Oi< zd5mXJ{)l;0k|d%F6u+x!R(bbB!bO54oKEL~FcoJL{&Oe^~3b z-RIMfZa1%V2E?IL90*?!OBTYH%hm1K5}l#!Q>%y!0^Bj6A%83vewj>z%hSg5tW^A+ z=&O#(AmcLDA z^r&t)<)FMSS96zu0#F@P(gm^3p6_)9ah9K4(7)H-*7;VYon}nBOfzQz(-oxR%-6pD z^pWl}KP6T-vpmkt+kCef^^J77)R>c=J>V)gm1%43CSIhN6PH*6d1dIK&^kC&HdyoI z=i1^K<&d}6mV#a`mA71M`!bU7(Ti=W+*4}Dc64^XcI6Q^)Wuf(Ih4L$9~ z9>(Ahe;hujO4^NMeS%k#IvGL>>?X=QLdqNueQbK|K9*Z)D)W3vUrUM@Z=E+SQEvo- z&@VyVLZQ{^(SB|h?WYGl8mg1mGtfzj1HTqS>ixg{So4TfZfOW@O!aiX=VLz`X;9ZV z%rEM9$9^vA%Xae||Ks3F`}r{Moz|bj+2QZ)KMOzG*7s(n%8SoKjzvTn|gADT*2bK=|8PBm*D^71odNAK!u+dl=wwxYgD?D&ke z|6*=ao)4?oX=khY9m92*3W zBYyfjH84>~r^$p4No-e?a~laB#MJS$#OR=sm%i(2(2C9^|U6Zd~|L+j20bR`FHsnkz8j z+J1zI1Gtm+%G4ljZ=lfDLsx9!T@VYkou?QiiUIKzlfiBmzYLPs?6Isv5`k3M5(Msy zW;sbo2GwCXRImr;>RF%2r;t2w3IkQ}Hjg1ASnLhQqWY$5=h@&=CJL}Rn8cL{dZ?iB z7b0}Qp)1?B%kQPy)$m*E%Ic3Y+r`pE&n{}*JpmHcZU5-2N=N2`)cVztV%>SlI9Wb! z7X&c>2{%_pYHrf_mEZlewp*Da+pq5)x1r|J*ZlJwJz0W18nS0Mf;978yL6u^NEc{2 z$M+bBJvAKfFrOkRK| zDK5QCE80FY1P@3M;BMhE4w?#%ns5&Si9J(|z^8Bn8_!JwN!TPgz`b3(zH zuu1MzFkecy*SI`iHi%*19f1Z5INuUzk))fKE}fZt8Vf$%rxQJ^6SJlhd!R!?>c;Wu z#*67DsOTmd>fUtFP4d%Cj?zs@)4j!~d!CYfS{OplMQghj00cx5e^hVKhIS^R_gY(W zuqJpC$NJDg?~$KgR+L_Ln%?7QdQZyrp0?>d8`8^})qB3C_u@b=7pb3Dpf_S>M z<5}kLtUvK=hj4A%C-r(PqNwW+MC_c-u|6{B^p?Bis`sP?jVD z3hs>8l;Ss+7B`nsHJ3FqzwBsEm-9E5k2Y6GH&@ItSE?{qZXZ*InM=Mhg-(1B|5kq` z$CPKwOheoPr)r^TWTE9~q3v&>6K$cJZlRZBp=Bkz!MwXV2mRA0j*3p(W>6W%RmUb1E_U)Dq!4O>UgS;zdejy<#{vDn1%+Z>-rB&gaX8rj@* zv`O-}NshKjNw>L`V{^O0hMwAPlQwLVK4+8h)8@{hO(u)&U4Gkp;tcz@_XVR0Pgcl;pkIHu}2Zsa)O==jm!aWdL*D&289$8n~@ z@l(6w?6Bk9oa6jY$Ipk3a4O5ya3;k6MuVP!hJiG|2lxjK`uh(WM0f+6N3yCE8s_2R zISv>XIoI<33k_00>BCNUoDoGYrA>E-Xeh99sQcxo+!j4XgS(A3BSi)#IUrVs2WhK0an|&gk#j*D(VdxX3QvMXEa99ejIdcA2>--uY`}pgz>O*7 z&`&9*N+z{&T_8}iP2;kV!qVB6E6av(`)G%&LugUS>`bm0kbJl)C_AP1505M=uc3DN ziM;E|$?EbHM05v7QFb0da<1837#S+m#hZ2-f0g5SA(JEtmptfvbg0420YhrKEgdvB zZ^Rh7)4=x5j%hGyP4pK5LAX?bd&(RgVznUR*uf+xuWc6RyBpa>#D~3`e~jXLzwslh z`PWsuH|Ks{q>|XAHqRPD{}UP{q|gn4ijA?szmI3KaIvY7Z(>2ztS`5D_;Cp`BID>g zj2%$o9Y&cx>`S<4A9>-<>1%PR2oNzPPSSK&1H{BKgav}I+9fE6EEG$EGowhL<8x+= zrk07m$P#w`!RULb@03gpHB0v6Eof6Qib=NX?eFP~Jopm;7Zi$u$sn?^02r(aXyv$` zx!*-N#3aPYfTb>@kR0g$HyXsffBg>lKcPXY4%t3GUbk)kg9a7ezEtub(4d$h#OOWT z(GW2W+nbV{rq$`zZAdbI!f{`PeM=?{{3IfQgyJmFF_dFMjKYh7anBoX$pxO>K*N{n97!9^{_nN$( zA&r62kb3PTsL7x5XYnX4i)bWx?dP`;CWPNpp7+mg;WbVlt!%_26%=0HK|0IO-y$L3 z9uiIDF7#Egf}>vHzh9+Tk_}y+spmB!yHH;R3q6_7ft`AL_#jT4Dd_m|`Q0BUZT=MC zH5fAoRcBOnQ_&CzQ{r4O=H;!c8YV@ZR}$9hJad$WC5a&1)MM#{GWmxRxq!?(vE1+# z%lXBMJ|;0iBxXlC7b)3;>~8Dsq8$@thuq6|WH1k6-Z%2?e63dd_IJT5Vw#v%GcZ=# zLu!__wWh;$$zUED31RW52ax~*BrtJ4wg8LIXa&PK6~sb30XtWG>V!=v)1h!TWPcst z=J=BEX#s85)`@i3gm5=C0Zif7(oPlPZ^}B8m`~)!`DGJ~l-ka*(%r!c3Y&s>TRZa; zHx)D=ViMqr%vcmSGhKU>bjxTc|5Rh&TZxGER02|vTLgfOKK{SZAY$4}zGY!>Udnn# z_|VHUJAJ)Z_Sf%__{N0v@1C&EJjZ9dN#@^Qhw3RTvhw!zv6D!;87g`AhGr6YGti9a z%rDGdMDj@zka+wDlfjWjW~WdRS!UHA9wKy3st^(-g4NmQfi8Flka!`p6LJRCEt!R9 za=e!ZV4GEj1|`J?`5h4qs398tCQC}*gQv72h~eX5?<-%PfN#V@dMJr*@9y2x z!LPs{RgFjpZ$5G4_7a(AOiVoggPWJTfI&{m;AVgeqawQdyecqY1$KE>{mfmzpK`}Y zrIWwyARc1&*bE&7LKU zugH$SPc%cKFGs?3LeS@b{;v$3-=K!qM=C`A2L*EoGi{vAtQ^? z;I=a+`BVWL>_wvZM`aEbHuFAb7> z=CzM;_{)_n*d$D19I{&f$^`GU4Jm*tljV;7RwJ3^HBp9rz>R08sn6*3^{m0!C8eEa zO8V>IqNj$^fCfsn?{#S7;M}i>omMJKWq7Z_{GTT~ZSe{k*#Cn(wE|p$tB?xN{~vkE zs`9bYwbzeFFb4Tp%3dc?Q13sHr;0L9!KbnALnyeJU~fMBjsz(_PWXM?bo{yEDl+v$ zq3(VwAN0*;o?T8r`{omy2 zTGfjrHjzz6&ZS{jwOFCgN!!coKe6wb_a}DAxi9qY2w67>vbp&+3nja;=KOd-C-MrhW{o{Gfq~tz=uSj^pp*((;K)chVN_qCD=^{kQYIB z%}D#fIZ$FdH!Tmx7>l5?YckERO`c`tMq$;}cCs;0mYz*>5QB&cIS$b)h6hPl5dcF= z^k}YnJTp=KZNkuILMKE-Q=NoD*yMqv=kcUCPE&#|2n6E8K{&a4)Za??La~6P0N(3d z(%}$Fivy%-8t*-8`ET;nF3%FnB+~~Zs6nYGVJBf6qgap-W>=ksgH~kB63GA31jJUZ zjb*H@>c;}RcvBB11>~3Is{=1HtQ(hAef z>^GD88)Cf6PG*qV+yGw@Y0D%tZ^r{XRYzz>NEQqW^ zipJ1MIJwJ6JeJQq-eX-t$gzR>WGgZ*0S>{8{g61qQ=t;f1!T=nX9+07lKUH7gAz?c zJVd5lT6!mg6qfbOsey!yHF7sE*k_KnO6*83!JvpB{Hv?-u zuANFt`7DrX5S!SYM8sLY%~f~A-5*E@4Z@?_ggKYizKanB2U$;HoKu`n|eL58fC(3`G7R77j*@7 zll45-@la{FlUjQzP;-D$Aa???m`Rdr$0V)lJ~)ZD0vv?}%|^i%NP3DkQ1>`j5q&G+ zWMcJmwkzaQ2eg}vOxQG6;q{pKJd(t?I*Iuig{xHw-Va@Y#_+jHb^!V9>?8=h7~<}p z>Ihrb?Nypt&)`&q!--!`#f^KZunBibwVg;{pn^fBx^dDUa2L8$s8>KG znun?rFPq82L?Iyd5oE}z@!WG>$MhU2p0jW>K3JH_EtwL}hrxnSdpHObp)L1uLk~QJ zy<_S{k|*{vyQ`4ky?6k`dW#uJ17Bgz?YtX)S0pfnU9T+BT}-wqg8@aA9_@Om(5p9c z-Iyi}l^W4IIQJ~3?QITxJ1s;m^oJuT52X*&DS_li@88#LEY@P8^VD@K(OlY{fyEj#VB^vbAZgU|ajlg0BX+OnnVsh$T5Z;qmqVss*Ox>w}M z^q+yTWnWmp_d`JY74KvYn5j+{uH+r}Rj}|us*4JQ#icLqL^yzu7K=lYsGa=RGa+2( zci&8qO2+cn7hJ@0InH%JZoMHca6mMWiKyPx*b^+L4MMsZCEiJPol6qBKh-0=6nEk} zI*Ayp(D|N-xlybB#gp5%n0Yr)O7mLsh2#D6055g!^JI_XLrD6GK!xO|FtUd_r5kx> zip<_q1zezO3{K})-!tfhFv#XHpIhmCaslIsX^T4%^a#tnmbQE`>Kwxaz9#D>&l2lK z{*VccblMJ$kdv_kmQ!R(jl@$Cbuh6}zPz2%c|j;r5l8&P~N?hKzZ#0`;r@1(1^qnaRt0T9oB zo|qxq6bT)Q39Wx+^wVb<%sg!+$9FR1c`HTr17tUb@y6mWsOJB5{~YxnnD&Yzjg zZm7@63G_H#FnUY@Y!u9|d+Y~XF4VX_M$lTG_Dk-!bQF$#jq0HYSvZYj36esrL*)~{ z@C_7dU*zuGc>ecb8M|{s;sYjLCpnMVfVwNG|2*fuS~tQdHyO&8la$PGxN7s_9p#HS za5W3z`cI&U917fh2hH`N zqiyx`^CWpg9O_I{ckKGru`8ZmnH>?hrI3#O`Hi-d_p^Wx-DlFT-D~H*qo%?A;E-nA z2BPVxb}*wQL1DFrJ7Ajw6BFYUA%x49W?DOaH}(pPm{$kPgecWqyWxb@oZtU?M@_Ks z?hQ~=Cur6t!sIVs21~IsPap~Qhbwl80Ul3*hFV936!=bK;b+i@3?b4Lc`!xCqNM>~ z<%Tz-Na~Y})4k!!TQ}w|f<8TpfC$HqQ3ISwq_^bY^gLe@0S>0Yzl6m@5OAL&I4jmw zX~I*Y3KS0n3V9_g=)?x1L1IlYsKwwg3e+dlXB?BLsuLH-W$}0$83sUo2rPl9n>NdF zGmYjllTdbYoThH#V=lM}?Z(6j4{ZueCOq0RCEn7L!HwW7yTzOjBz}@hmTMyFdby)E zZ@kTf6v!udqm!{ZH`TVTxzMXXVmoke{0)DGB($!%>=NLNO^8uQ9>=nT?lSAIa2qfj zCo4QhH*pLDUZ%iaQQ}1=Je_jk(b>1EX-(!4y|hG*RAnk!N4G^l2%S==&6p*P(#8=gji#W%_J zUSxI3je2aIP->kfJCQM--oG6@a?QqxS`jL^V}LZ+uK zi#HKEp=&mcN2*Z3T`QS$yYS|e%&C0eQ8EMz#QDg_Y;v0;S4f}3BB1?g(pp4pW<1aL z3SNt5&w>?1DRcY{#z#~ruu-x~%-yS$&@gY8XiG)nJV=^_g~9rdFsY`P}y!Uo_b4zJzdH6J1e@K7JbfnAr$mmEcxC>%kz1e%Lh~=}-)JAwHSxbbm`?X)20T`Tm46#q{TH#+1mN zy6^Xd=pg~X^fOH_7C{1o7v{0ODUy}Q%I@`CJ{ykBjSc5uk-)MwiM)X9!d0<|HNDel zMugxE77wq~%3C_l>zkt=|Z zcSb2Dkif8j%Dr>#`Wph27kKE{_iV;HePQu|5&GrTmCO^RrZLs`FZv_|65ykx`BNE1FPyu}%-cYDeOF>8DQ)cpm)KTwOG-%TF6Q0Mp9CcaI-r-l3?yKH5wHAG4 zp+qWM0d4o6TvP=6ipDmh0jErJcFoW;RnLNyVjQMmm%ed-SO$JGJRvX^q8>ac+sg`~ z-zem=L`Lerj9v}R$z(R(=Wu!X;yzF8?5Ug}3nVW&^66?Mz@49}p2LzIxy0~X=T>nY zF6ZOp$aUc-8Ft1G`w>oxrR~Wub^`Q+_sLA9S1l1Y0#RUQLV?i+vkE1zdnS^A2EuGk zp&#E=B|YC0e)4)%7GjsnpkKD|*mM+&h{v)Fi^hDvQLbc)G$14LY+tMIzzapy=TWSx z=%QaO5#DIT7t$+}Yu7~@ucru?s6MXH|C*22VYBgmUN36wcJY<>jY@Od7m6odw=h(f z?Uax5sK2Gayu7PRci=j-LOZGO%e|TIGtZ!@;&yg5X%TtMsXDzhsPby{BL?^~J+u0< zGq(r2T$VR@?>4;ew(Og#*FR@!$Kdd+eU1-0(X{0}5d-lAyJD@>$CAD}^O+EKTCR3# zh+r;U4pPpFskKiH38aEdj;ReQIG&Q}ni?{Wg1;hHN?(gR-4tgRnP*aV!C~8Tvbi+K zu0Eu$TIEy2$)?AbtAT~8hQ!vi4j*MI08MCZB6>6^T)Szs8!Mw!bb~jdRky-HxWR&{ zDJbzK7<)@ck!9kPf6!jTD{{V=DN>J6>GQb7+&2~N`>bvQ=|T+)y4A8Fm-Sv0{<@Vt z192A8QMX(3DM&d3@B3D}d;ERD){!s$d-K%(5 zwEd)P-P*v*0U;oi0*ly&UD<{ug+j$K39CjFD4 z695{3MvR0tBJ|l-N-Ic2);`}_i2*_m!4p$FtHp^f#C%d^5@raPi~$UmHaP3VZpj$eB&I%~VL= zZQU@{Kt2lYXaCyb8Nby~>#vr#s7+=k0RGUBWJ86!0c~+K57=_?a>WxFo>*Ka8PAKp=x;v;TNZ}K^xAJS$ z-~Oo+1GaqapOuW0_?k8L(~m-);m7>%*<`DR>h200gwgswaBV&j)~-#spGSd6HgkK(6BRTlUuk5;wz7$!RULJ7DN zCF=0O-gFxjJQ3Z<1u7M+VnN-8Ia1jYktbT{4WMQ0pr=9sF-?3F|NpRemTysbag?8c zVTK%f=nj$YX6Q~yrMp8ynxVT}LQ+DIE=3u-q`Ol}KoAg6__6Nu?6doNU+><(;NDmF z`JV4NpM(8kIN1pfv7IK64T6(8VK|H?w?7cANzRk2fV`FtiqIj0{ z)6aD$XF3aJN@j`pmZn@1*}gQWUg6mCy0sfutrQY|`cMJIPHB32Tq2=a{@z}83rp8}{9Bp^ zj-6u5>6x5U2&Ow>GtDMpF-yBtT{M@(UH#TCk&1^8ghrI0ADU739N5_#@CA5#dnX=K zTI+LNJnOWr_BG6(6D-7Um#;Jl@P>%+TqZAbafqfrg-%S66bq7n{6KLo_-SH|4twb_ zgs{i6AD=d?+GU;L66bO)o(b8{hEM2ywzo&V@hyZ!J~2>L5>MllXa?1GBZ+d_-sRxi z(dOD*c)ef#c7N0v!o*!6h)+CHv{05zc(s0@j}M8&{TlUz+6z@#$0+9NnZ^tXjbH-o zU~jC`0uFX_A#mw^t+P=dEiS*WHU3`(uhx$pmV32R2&VwhGL6iLZID?p+^%@+ZWR>% zhsc}eIAu+*IT~^mPI1E)YL0r6dN2nCfw^NTtt__kh!@a@qWtq3Oi9Fk!v~ z5(6e4)|viuzVQuz6JPA?#r^Rd(OE4b_0TeLA%!^Tuf;AB$^iKh>Nn1Od6c&qG!Syc zSGu+?y)_8iU8aYQaEBuC*XY7VLYH9)xhD*SmpxA?Jd$_d9i4PuzY3rFbD`o(3roBg z?ips&17Pia)-P^&4d(~uEZEv<^-HjbY0Q?9eJ+X^m7GuG?5i5Wr;=Gh~fXZ z^E^D)w*IFT{3pNHa>DsrhQ@1{?5FRVNy^h#6g?PS(`P~)#8&NqHy0R)Z#TZbZ_Ks< zHJZPNrOtO&I{9Q*_36SgH4%zDr#RY?M4n;F$a`Vv!otk;SEF3Xb+82+_TV(Zb;*y* z+Y5mihbRDsRGQz~qU*Af&zj%;InFKN%sI7thBES+-)f|q?tq=^Cr;CTdmcnWl(u8YYV-Ot?mRsRN0`4CWff%CWx zOr;Ae)TSv83&433pK<;7QVwrlJuj(R?5=Xwe#}B!X<*;P^KBcCkcZ*Jf}MkQMHln_h46fh zf~S27<9AifG@LALH{o@9$0+5zxyEkb-0oyc6*N~7mAtQLJfXgFXd{@Z5v9x z>evO5N0^=qL0KoLfX!6MNWm_n|7$m|z~?Lo2BfLPSG zlZjlt5zdKT3O&uEssI8T?8y{rxw;>@@W2Y!D6(!Zyy4hp6C~b+BemndNmc(DB_H#h zrdqfXpigbRxT{}*n<{k5g;y2_5HPOnfagI(GW2S?c*j-N3Xz$RdTa;zHsj`OC70JGj7t;HY@aA5bih=&TMWx79&B5Z zyTG-?w0-Oa!wW6F$`T2!m0}$d_d&9-dzQs3Mzfq*_q~mi77f{qG`T?TZ}8=8mG86q z0Ui;<;ZEq1OFSXd=}dvC$(r0D!Rgj48JQimYka@hKb7$bHP}Y;YGKFTCV|M!Q*wR` zByTq%#%L+!dgHv_tjNKMp|L6szVkY|f-7mxJJ7hUX;}Y6M^6cf>wkQFr0Ce%zznsT zQF_(#G;Z+>Xun$Kpl2`CEAlPwVCGw>mt}?CRMXjf44qcmTbuENHVx-Mbc_XS<_|=T z#8o#JB~#zB#CwrbIMz>wQO^%cEQL}A2iYDQC5U1M1r@o0Q^$xT*AyVuW%fGPi{pCr zH_$msRWNu%Z+>FgvF=|m={m0YGKRLbvd-hz8hXcA?@)~|Up2o+8nMZ6Oi{?jk^a4o z5-TV5m=eglxR9jn=pOOw(I+D-@Q1b;l6t(0x)*%-g7FP~Q<-0+^YF;mexU!o~;UjAVzfvccWW4oQr~(_yhr2U-#g~Rqjl0}p76squfpR|KS4AP5G9H=sZH2VNmv2s9$8n|PZG&wzaGA5KT69ZRRJl=$Z zQY>!;v~U0@_uC)NP(+XhU=0bN~2XvU|@zIg3`X`{QPXcl;KDnW4RezVGe zdU`3b-m7`%PzD)#IbA87fQ?1t3}gi#BcAgG7Hg55A_4a}IOVem`9~F|4{_FM&+kEG zn|+nmXLYYWHtja2T#U>mA18h3o9jE-tuRlSOcZhHdro}Kw+>*%P10ec$h*U_dHQsb znoYsTto=QiT2dCb$1^JqgZ`HhwGF#qkQfHRh zkx3|8^fi{KFz+zGW;yYv>v76{%WjOK)DrCgrR%T5P=1Yhh86fA@%eW0U4CW};n{l; zu1co7@0yv*st(7^y~(tItO9g*B3G^=abRGBh6h8xggo1ei1iwh72JINKo+R1Gb^Pa zuHEdka@mPOic*f%_nPyJ+yZA3F~c8wDkg?{nK44f&+W9-JCtaExWrE1K=y*1Z*`LX z%u5QHxvWRn>3@RB)qY40{+VlwxOr;IjHc1S zvNnA0dq%y8IQ4f7)bYVCky6CK$p3a5Rl6EpV@k;)sYq4{{KhfgkSQ zr-Gl{*r_tRo!^?j<&|x}GG*ba(9K`7-$XABDJPzWCe@F%+{Z*?7GN zDy-z|dH3q@TbxAl-|f!mHN_6)jQqc8$MY5<^mq0rN z^W)FjpWpv!t#ymzW4^1HWIyXceKfoRGS+7uk|?0i`iwvGw&@ zw1Jz-p#on$LR!T(MO2?@-3jV`HI1vHkqi}iBR8=0tm9E=T>L3aVC4$q-K`YCfycw2 z1Xt;@9wT)=xTAB8fW$pirgm9Z#_Wr&&s=!y__o#4&+Wf)zu!Nv_`ThfA2a&p6!+bE z;NoB8Uc+PJJRQwdo3+IKbRAAgSnv%)XkkVhL#POFEc53&# zp7*`Nlk#76oq8~t6Ylmza0;Q{y~Smh1?d0aj~pt&~}C6EM&NP8v57zHJ@#V7lQdpJjDoB=@Q zRkI07{b=DJ*APHxh*4DZ_6f+PA^YlQ2npzMatHyLop?{auX;xN(LJwl&dafXu4QtP zba7oL>YI?V*vS9q!v1G3gMD8P=qhJcBVW-e&)5A9qXJi8{VnDNggy->>_y5CRp5X9 z_K&>6KD~TY+yJ0Jbb@MtajoBGmjGzoms^q}{6O_0s&YxOx=M_UbK>J&-7b) zkC!NGV^GRJH8L+oummCi#Ucpm#}@o-jv=>?Ry>#)+#Bf+C>Z=UjmHni*z)Wogoaa3 zE66fSm?#WN!O$<)zw)jtW(F$s!3U{1qq(;UopofQmPwp-BH8>Q#|7jJ*HW*daCIc1 z{z*f=g)*;$sa!D_1up=wMgrQxdO^p0Ja+u!My03NS0mo1eGY&7>N1D&EEW8&E5a-A zs0B+Lm%)4&D5t>4hLRZ5I8{zj#=mfYggcGV0PxTHCFmSp1F= z@FSpX8lV#wEbAD~1g~A|CwoHVJsz7>yr>)sh*x>Ol+{?dRwGBps_ z%p4bS&B_)Z<6I5#NJFcKYl<>=opjf=L}f*ulI_=FCkv+j&zNj5b>F(?&vk->R`Ekl z$u$y!^}KbSwvJ~kNX##D@ii|1cJuJFStg2EZy$Z)n>p2{K{=r~`J0Y^i!UuqG)0@d zh?}wo4KLn;F0CRqUG)4UeC7+YE^Uy0nW%wS+c(naK6c+((}h0S1KWF zN_OLg7bbW@FQvHo49d;jrl%hC#n%>uXciPX7mk_@kW!0dfl3}U36f`{Qbh~uA%;5% zi!OpM%voNT*)6%?8S+vudL~Qp)-S2x>GhWDXMZwE-Z9iPSW1do$|+wAhc3_zE_O~Y z+RGaSZxGmoEYr^~o$oC@S>G((1DExDj4X-_!xhzB6z6^RHDa@uDF=)*2j^^Amh39q z?WGu!?LMcTjiuep=MR2+OKK4CIFg~c(j;f{PO2!IW%{+TjI#9^ z9`!u&UQ`UqHyUWSBnvl(y!?~&^5N8^^Ko&7+O#x#Eu?a-ukBR>%?pUxl7-#JucWW4 zX-qgsP5aNtOYm0fZf47TS3XWi<{P{mxiOxlSstMwYQ&Fij3vYd>38H87R7 zGo3Nhc@o$dRy3;yuRr1ZbETT$tbBR7TC_IxeN}qU)KtnWZDXxzVhvik-qU8P=(fJY zvc5*MzNfjqzws%TRPA6x?KoQZBxL%R-Ru=+*#gVhqOZcv#HPe^^V+k`gf=s8v(3*e z#n;h#M|Lfvk6R~hbNYBWciCGwb+688UQTViyujPoTU*`?*_;>p2>7`D+{FSGXt64$ z$EvV>UurRFx4rtf*^jfOJFr<%WcilV^4fQkY-k&6c6)5w5<}7w&fPb0WAe96KJiSO z@T&l|^yGhvaVM`Q{Oqg>eXV|Dnp4qOz|9v{9gv>J%7yD|q`%J{EXA&b*5zl?8K$o{7wCv4KJn4u8*Ua>tT`)zMC%;Y z=Jy=~o6B-*kNWRA_yn!}@$c5!wrfdF8u617ZK<6;@w3<`^Vw$(>>J_l8%vkcYnkZ3 zl-!qUPtGKQ@V8^t+F!|vwDYyfn-5sfj$%R~xYl+rlNwFQ3`wOAg$usN-q_cZ3ZzMJ zSj{22QD0?S6rY}_;G|Ni+Y4{0;nQ17bX6WH-x=61PaH8R*sGi!hC$k6+exC`Eo~Lo z&s!YSyV`?O5`Vtc;#F%;_1iWk#t4|)j}Ugu;Fiyf(U&aX?pa8(w0G#GVnTjMF~=Vb zX|Lr0fQdghxwsEx*eG`99drjc#OZ=vVdEvzho$&~W%l~%GskwBfnT#LZC+{=#e@*C-EfwCKUg%VB4%y4M49CgUGcfR*m>#DcTT^=BFKlab zzIu)YI3|g5-Ua={r`_$>I?Te1?JlnU(oW)U?9td{HFCipyylcq?vd*LC?JnjI+eti?<&|*xf=G8)hYlx}>x9dy%inJYUdy zX$fC^prNx$ss1cI++|gdtxfHMa?c3>c~Pf>0@w}4PRy?HSGDXu{Bl(d7i=c;0x7#@ z>bpL9V8*7HOK(VMHKwpv8768QUgoE;SqG!tg?PQV zM4z1z&V>agpzRo#Rv0tECQfDb=XkG5r7)lWDvmLR>C7a!xN=|0i>%wRX)CfBTI`kC zh>Wf65%q*NF@$?j&fr*yjEUSznR*Nu&=#@$)DG58bLor;IW+0t-1n84_ItBn`Tpz) zE_&Pb*0bsd&?3&1WY&j-rB5i~G>yc)@cfpvl}g3}<}t@vGFg`Dsbgd#FkMu<{-3yk-7E@j6^SI|Z*jT&yZphwIDCB!@ z`!ln!+q(Erh!3;soYxnKpZftU4&&qU|0&A10W`O{7B_N`sKm9l+IMfB0pStWXN4x! z_yax7A{IaX(`fy4#YEwM*)^Jw>7#U8aDEPVsTo~3wd(wyu2cPeH~_jqnCL^ z00bqx>8~COpc%}``gqR^js13*WbOF+nG;`-!=J%7fgKLMiAGZ8JuuFE->Z15>1TEq`+0gsq>A(@XpZ)ZGNpT*d}d@gP@E2&-` z{U=!TCC8s%HhV^&YZxDBSpK%1crCNJGs-wJ#lC9q4D^J7qkGeh{?gun;w=7y5OF$Q zY|DCTZt^-GT`&y95z(ZG>ftgBB~fBYe`YF~8%SfMu_k18?;XnGFlu(KnSF&1>r$G{ zic^$JapZpUC-J~uVWI@T-pY$UjcvAqDl7oNp??&Ir<|=%D$RZw8(Bo#SIA z#+cTrUz{_o$H{1CAHQCyJ-hm80dEgXnr6)jQ{lQ8=NXjTlf$=;3y1Iw(i$Yp5mRw`36W8jk=r~| z7lx}AjI|;l_;UVWzQc)^u|>E^5!rUA?#mTQ)CrzHi~0-+6F$9WXX#T6Jy9No5`mx3 z4hjLqhf!EKV~#+DN*7cXK{(6lbk1Gh{HrWzDNKrlJn}Bb3qmOvfCz8H3TCIxhrV$d zsytbHgah`h9Jw}vaDwMRF-KD{X!1Ur5F;bIkRmv=-P+3ZSJb<5z0trArY3$JEFTf7 zFV%=63I*gSopituM3<%P1av@cdx!|D*$~&$oBvmgV!WY&2Jy$x-%8}P)}$Lg-sYK! zV76TfO{m8@DZP+Vb~}>K(RDf!Fp+}9BkN)xcWnVhT|~(YI=))uq4IZGfig%kofr&C z0+nL)V@li`xMtKU>nVbQw+w;5{#+t^N_N6A{^E0_3w3n^pJHg#CBcp#$v<+gcWEP? z7kE%mbWz}vF>$fUMFq40LkSsA(&5zop*U#=`B2KP8KrwVLFn7uK&dTB?BcgJA%-WU znsJkau+p*N67o#%o*h#5dl266jICoat_>{IYM3V;x_am}p;GrIO}+=u_D zeTF^zCGBlat&IgHGjR;aLEzUJFlAiFd@6X&mTQd)8TYjwaSh=1Z&HqG`4eJ~Ha26k zlmvEJaJO!s7wXQL-pYE7i-=r~GF3c356CRU6V=}Tj6iry&)M4&y=X~p6XCM*G|2eS z)Mz(PuWiVuyl!4}6E*#ja0~yz^-Ks92mBq2uhRGwsx#NkFha8#O9J=RlKSUfn#6z4 zC)hgva*4m-7q4~qiT<+)GR~C^zwh0tLT+wb8At#_3&86dCGK4Y0VRg_{cA|Nt(5F? zSI{NgH#Qd>jPK>8*v`|Yop@qBjYWrVQMz?#c`K^QJ%-e6lpb?j74yUp&D&`ZZ_>8YqBBCA z=4Epb(xc((?0Z&VSdQ%0i zW_mGo#?z#vMd3Lv0;vEIR2MgpDk)OtERyG(x&lKjp`7(OCN5cIaD3T1!5n+Dc!>@>60rkH}J)4Ty1mj&s_)) zzqz!2#=xt(-p6mA@dbQ)+>kEJKZ8V#mdRtJY(@GMRs`#xH(&z0td%MUu_N>-6}`@W zh5&E~bzN49Wp$7h68seNK~5JIoO4T z)a^5v^*4>e_?bf^8bLd9Y5rf2R~ybG*_oGAf(Ut73@V9`McR z6QB9(Z*;6)d1_qAxDL#oOL9|}qdmTw@PP5-D!skr`1c7SP~fV;?B3Xx0{FYqml>C% z$#DzwRs_}AQEbkA5>?iMfP1H<*jn!b6>QhaPHK3b;&1!~vbMQ?ft?>+K9xx1_U4)q zpYVmEwdJx$E7wzG{eReqZ{dVjAL}uk+ErGiq32#kaW7u(qa&wx3{!79`Ie+Vh)>;; zb)2YN;l2z1E5I*zS?z~=7&iP0?s(*o?T!0b-=nNrqTNcp5Pn{U#yd>^{>_jE)xAKi3Y=_WXDfEh0fA2#X0)Nq z%fFO1NAJ9!+A+SIxmW#F;N7Hxo0)ai`%Un@MJ7kk(GC!b`nvedp~n&{h>Mm13&XR7 zN;?Md<&kcKKbKKX`fq>31LUEdz`w5|rG;E?gQGV;E_S|h+SYtc5@Ool@jmP8&qW;N z{h$|kf)A5-M8^sz=wZq;$G~hZ$KPt5(U^-ik9f{V`NY{T_aA*||IB!NUDUC7-L%MI zknRRA{^MgYZ$d!nX%;3a|Lh_8UP__a2Y9d&BQgyJgc@(J4E_EBd~8~Oa@AWq+j?>R z?#U|tnkE+@Jx}ObqF@W9KyRt}gGGE~DM>80?o+7*w^8xoWSaC;*_s5&wAnRSx}3nF zq*xKalWa4z^wCNiR!f7DvcTqF#3nPwAyW|)1>h%8)(}{4mmn-+$&?x-te0qK39a5#3!TV*hKgzX(Zx4~v z0T&a*h2RxFQ|<~`^0cwFBMkf#`tf8WwpW1(I!j{$*3Maq^}Z0GzuV)rKv=y)ueXyl zv(0d>z=$1vRD{(Lyc4K`47$MD;*>>nTg_L716$+96u(gSwq5VPu*;-J3~Go|>dr>#(pK79+E#E? zhNWS9w%X}X6A=us7)bUDh@xoL$qgq7SKxERD%hS~Xh__;vDWhTegsX_Q>=dT0;D2b zbEp8oUR;M7BacE0qv)%A^%1TpotL&2DFYTD`+X?uXTtYkaC2gvUF$n-f+(E^=2#J= z{SEzl-m^q{K_G3s^~Q9feZo3)xzdxfibfPE#A|QBJPf&;@g$lfkHg`fQG}W%Qb;cd zRrE4Yydb3g?#8dAc=CSp@?h}(z~lWo@5d?yTznzwaJ5j4*FL3GP_(-ho4GzK({w*E zb&3%O!I!9hNGnNRY~w!#o7Y&Nfg_wOq0Zwe!rq0A@7tOgKNe5W(lm#Mmc|QL)*j@Z0Z3zJF^pESCa0eq!_-?1C-SwU ziR0v7F5BeqEzdd~RHyYH~ciZ2|^Vj$pd~Z7_BL>y(U?JU%B79)(0a;QBeS2;Hf3@28CT zefX-eSR05YUY8Z728;UCptxQLBf`NxvN$RLmXpM$LJsD1&f51tKZ-r`06>BMLhtMN z+zSxBaRTKvs=o{-MIBy64gI#MCi)0s2$m)GJdFvdGfb$P;#RK>{2``-qV!21yqMro zI3kTu>-~DR*35;Tbkn0&NjZ%}>?1|1-O{MthB~bH8mx?OBu2M@>e-$qyLgL@!1n z6`&DNn3pPcL{ubUa4#`Hc8AtIKQI2sIf1@9d{4NS=mLe9PW(R0btU}MWJgIzLEacf z^Y8YeC~!nv1WuHEBmzi}2#?%H;dG)GK%+ghj5Tpt5lK7@qH%<2;e>)Ckr!vDhHe;y z=GR(0gIp*y2qv7=@bC+8mjGl)^0;SI5xlFv`qwHXa^b(P>aHJYqa^>|>d*DB^2Pr0 z*SjN2`wbw8#^HU~wVEfEO)+L9FLqTUb^|X?Mw89X}&mGb0Z_lSng@3_r7SGqW~7i%~O+1wX4pGph$b+nZ*#Fn;#fX7*J6 zXSvPK-tlu(HFGrZKksOM-owv1+{`(}&$ZOdwZ+eU*v$QtpXauj=ZT*etA&?9fRDU| zk4}J}t%aXQKtQBLKt@1NxkXT0K**>?$U;Eap+(q3K;%t}NSJ_VY>Q~BfLLye*t>t$ z;ui4+0f~+li5>yT;TFlMCjqIY7O5=(>BAQ3pI5wd>U<9ZNUT;QfuJmTt1O+M99yd# zkD$CrtGtY$f^w^ZwxFU>tD=RVl0&PKhoJI{);Go8!tg$_Btg~OR@HZcYE`Xj4T9<& zt?E638pEv`Q-YdHt(secT8FJ#KLxdKTeY7Abq)o&E?U$`z|7rpWXx@PJVGx-+Fr;A z=_|MCYYQ0|wHa6l89KBXdI%Z4X)_8FGLCICP8BlAZ8HgLBTQn|rNWS`2I;*MG97L+ zof0xzYBSpsGCyoH|9NB7(?`b4EFIa;g#=rXw_DK(TeG!W^9b9BwA;uC+bXx)Y75&L zwcA+;+dH(|dk8zcd1`kE6LyUCv;P2MhWEk71tfi1og0K*I@(=&gk6W*U8jWImV}kU zE?yqCyZ;pSxNY}%686OE@FWoNBJc2`6M4GI?xhT6vi`W1LYp{~&>Y%v&cWMPbo?oC*|Z`}aqhe*P@L zrqclEP7Wpr2rnfj3S{%;ctT>*Yd%sTG-v45Dihel4$7)00~B9G#wkb z0*TFw6uy3ngsOy-2P4Cn20$3{ApdZZZ%7${JZ1$Fh7piJ=PfgU!lp(8Rl@O6_du1- z91jJV^*i8xXV_nPpnor(Xk@@U1DSagxxXx4MF&qF64;F{Bp%?aKmzjsJlBz+Wz;{! zeWXX1$kQz#N(`I67uOP<`vV2Nm<%%V|B@jRQ||v>`>x6*@a>-H&!ji+%P|9FK4D{k ztHZ?Qx^KN&;Q=0j@3-RL{{_d$D1G$)^Wk%#Y}6+iYB31vKB*4CkpMM<< z^Z`^|1vZw8mTP;YumI|MFs>h=Y;hSwSUxk%>Q$AUL{bydO-02IK+2 zN1`vcLDIM=5OqJ_KaBLYJe)+F#}bJZ3?Rk;U{>7nt$!wlgNLgC(%bUb{$L0*8ZZFB z3kHDV)NvSO2gs2mXo;89VnhnEz-lm%9VtWK&s~ioQ3=P!1%L%n#DWiel1Pv!klgb@ zszL%-7Yv#Q@lPW`M<|kI)Z`pMIv53|jug>BVle}Vq5f^k-ZF4x-qanEI#NJCgoHW( zdl?Y5)fJoi26luZXMZT7L*u~#yFtLDzd!dFrC*Lw_0Q6HprWYnHkw9`e7r zpk6@Q8@#0ZqM&eWo%;r2!2V%?4DM%gN%X8l_#quY8VU@M2q#}g%`V*+9d^M~?y-=a zQGYW<^3Z!*UHBNtz@_^{p8xRT0GRZDj?{tpp1?Af&p+q@ptLstq$u7s_~#lx05?2K zS%$O%5Ty(Z7)NC+^>r^i^3&bJ(f(b;QFXbuQh8_IlFpApW5r@g z!x8k~QN$jPel%%iyWylX;O{r;;kxoNRwt7D45+C+9BZiMCbXo%B0629%(GE8JwhZ* zp8P-C*@msOaDhLi7u6{!;-r&cFG){%;4A=2>U<$O{S?zz`rm8Xi(f!lRHO*vI1jaJ8Q(5PS3c zfx^derd%~wIE2#IdEtXehuG_zJHJ^u`f(BV&6u1 z)p^g~3nV3}TSbTKgOxz6y02y6n9q1g&Bf_y=%tKhJTxG?ryT}kiCh0QbBTu8P&7xL zbZ`6>L)C?f$JNmNb{9RB`uOKk4V%@|5*6V(^b!fh&_h6;aX>Pr62gPazu`RNIKl!) z@gmj2zw$oc1_b--9?&Oacb_yuFgOUFndY3tJ}Hvsh_QCiM^k5vFeXb9jWTDOW{k2H zk+^l>NEUjCRCIgoa#;UaaYItY#qY57rZ{bv0LdpoC>*_rCz`Y)8bi%5Q&a7~W&^mW2-}^IfH24>YUsmSVzA9e@*Qwe$%f zqR!q@l9X`OXv=BW?P!wLb&k1EOC8-8G$icS6+7a6YKGw{t7n*5op4*Cz2hNMAN=KDod6Q zJPNgzF3~GPWLT4XICq^4v*YZ6zJVi-4)g4Ozgl{C1=wtxsM|X|2c{Mx$|CVykLeSv zx(Ow88X7Xn&+ub90bu&!=07nA-623ZC2RH^hH#r+nrw2ojXpMLJ=p|1`BuZA+BK`x zvN=2GOa7ee15F={Cr{KKs4nxAT^Cc{uS`*zR$TOZ)vbr-c0F8r$ez?1$wAe3a9XAH zEarJinQMkX?hhXVfDU`um-_Q3@k&0m!p%^)r=vv0pWenf_wXH(ajLNk>FVUs)lH_o z^p~M1j_g{)+&;B`DvAb`QO`S3$fs6+%By#HwkVQ+ln)^0b>W2PZ(f>xXLSMbw7SsO zz=||G2vaY#&u2-NAQT?OK(Ygk&*-6=F9YA9RX}-ONeJiw1XFATs5Jnu_nL4qN0~3r z+h(Uq(nFb=WL2B1l0Z>VMgsIO-hK;!^B4uAG)Ch@<^78<^g`MYN>%)GLZp^aT*D(P z4<(G*;A$qR>~uL0)DuW!iD8qy_l`1%ELvnt7lR21<95B^aY!3sg82jRJ4?zo>dG06 zb|Mf4Mk9R~r5-y^S1KO!%5v)FM49>jWGsuhXQ1`x7IdBXCVCgd5sL0isLKe_&VwW> z|5AXZ1Y@ZG+;D^{P>+>Qeb;%2F(RNB^1d&N+@1F;ASud{!X)ODq_P~Gr7UODr^kQE zfbo&fQqn#>g{0e3l$hj{zu*!A{+-1WK2Qr0zhfa@kWX?AWWfA(WW&||&;B3K8?myi zdF+}->ftlO`JDj=kM|eQf;Tf0W^g1&v8qGx9v?=aqYT_dp)Qjv?a7`2xJ%H_Hu30z zl zcu}%@z|%hxvcRO{6vMyJGoOEWIDRk+21LVkEiX|2{vV(~rxSK}I53z5i4l4=&#zH} z&t_=}IZ*-NB{Wfm_#4o$LOD#V(cuK9+q8I|AgVzXvX)S^{fkm5Vw|#lj_k$OOr}D~R5!0^<-p7@VU_bi@-?%;-MOF4yn0*ZSD;Hn{I6#IJ8M@U zd$E>J_vCHE$gf0Z(~)ok5ujQ7(k#bm#>sV|n^9n5QM)(-TC;4{CjHM5_g zx5l4W3=C74O9AuNk#9*$Mc~un>5luY+u1*Zk6&5*O|gH6W^PCqk4}xKK?0ozD^M3t zipZNy@?MzXMFg?hiy?7CwEV1tf@hP3CM^@-uCebCv2H~Wh8Uo`HV;nCdZqPNbl{oc zWrE4NHF*zWh%e_d$;s4)Y6~$ews@Hmux>;5gcy+}`;``NYRg1NF{*0#D-UF&u{VHDr2$gc86P3;BVQA{`)UcFsew-@Q5nDolIDm*rI zkl3P_3Rt`AT`^EX@_WT;kWa(=hgn7O%FP_3;j{%-HuaPtVGTHhhN?Ho08 z_kKsUacp?|X=TIxO%K)PWzKE)v6)BE7S-1M;_cV_4Ue!Vs%;?o9U5lt8A(UI12eko zquBI}m7(5+SpedFy>SyQsP`zU{0GE}KWi~CNl}Gq3P**51F`_$pBV+f_QSzeaou}- zG80Oip)cQ-adx%O9P*~5M*v2^t}Vx1FeuWeoSf!ZiS5I;{NlHmb>$!(I1rPp5rF-# zM2gfHi`=WFpzd?@5j3s9wRtBI;JA%x9NV|L^3{(JQ41N{4xBrtr98`jLSs;FM~HOy zV&cK2n#_L2;%evs`S<}~3^bDWVDoJ=77DWW*?)|+2QcE%be@kjF)f4yTVE6*1n+{j zeWm?5@&MSw%W*t#B#M0BR4BCyxM24@DoAJaw8f+QAV6k;WPjtTg!~Ikg@-DUNfDxd z7o@Dd&5b>e!VZd^Xq!w4$Vdq7X&w&#+4VDMJ8YAxlrAL7EECVX0suZ*Qkz|gRKYG=M}|M}$41L)O$h)aE-o;uC)cqE%Q2_5~1z(irE@WNmKwnAAjFB+x`MzC8Vc0Cd700ajL+*0<`*@z=?j-%cP z7*D3JLyH zc7^$z;Z!dyA(sD4 zjn)dM)0mNRxC{g^!$}&45{UCQWmD6hIdOh-XDgk zp^5y1pqsIadh!qJ{2zN4HN4012xh_uIF(IbQ$OFM_Wt-4U*o90bK548o0{zc$gNdP zKg`KNf=cARTSujG_X&5agUkuMdhx`UOHw*HY-ys1g^xTVn>kDyeU~h}r)3xKY@aqR zm(AZG`LHpWOSC}k#+SW#FkaaU+RH zu#w*)2ej_Ggqqp1A5*rXybq6kn@N$2+>sNj2WyMozn^Bgqz_AY-BT7MUagb(k2Gz8 z=H@s`Lu3Bt=fk)dU3(plH#B?}#Wlnf7D?IzDGmDdX+*0Xj|LZY-aBg4AP1*2p6V87 zr%salPo#Pi?}Dv4DViX3ALkv(e0swYOf5usS+N0|_wz}JCE()4@Rzc*rW)TQ*y0){ zv2%LL%XJ)bas-l#HxHF|#)$oUH5yWcmZc#n@xP0UfZ>!R!ui8tM?VnKPybp0iC(6{ zesiEZA@Jx2v2#lr6$av==v4Z3ZW^tmh|_(zJaH`(Hf3EjBtMT2BCey;RA6?JXBjyd zg2c4lL(Peoh)^*jjhl3^R^1z$_;({ij?nHO{c=5ivyR_tJVM6<$F%Su^F+$xtjI#dyR&spS@KeBo!tnx19MjZ|EDt!Vy!v&Ck!hQD-g5I}> z$&de8ha1nGaij9TTf$ zM6%hWAxs!uHsaaa?RQ>AhU0V4jeaAMJepA)%t(FQC?;NQrRB-K{dUPw1Wv*m?rM=} z3~YYiNkzg9^s25UR&o%j+%3-xT3g0^d8=G~V(t0j%u&3KcVY3%86-u5<3D}gMEq;F z+PiHmX`(dcS)c}{Av?#7;4wyL8E@dd0F%z+eq;G#Z4)~hlUq*-o}(-5%MMtv4S2ue zBg)yFnY>)DP{2Rlr(q3VS^3ELce&!G)~YvyQ`qRoYVeclcv~kD_^N37t6_{=6S`>h zWq#H4Hf0CvaUPk6%bWFsu>qSZ-+z$9|62;x?bo}BhS1ybt^fYq_5ko3QCJ$=AgVhw zRI4$9{M$A};;t8-(ip|2v4j2Ut`9NU7$fp+2S4bppB}#{PFZ7@sNimZU8^a<=-V#Y z=et4Pl%^yHjXlb>yP=<&A5-3Z+oSz^H;lw@PK(vpXQUFNX%^LNjA;AVQ(-gObks=t zUgJB*tNStI$>yAnZ{N9t?#C?;79Fj3o(JXaetQi~;*_+H7AWX@qNPfSCi{hs5MR5W z^q*`gzWvvK`}ckdg)dmLb`iPtI_4YobRWU5i)4ekGNSjqKIW1+_%F7@F_R5JI1zDH zVn!fP34U9(vgV0i!JqkRt+raD31`DS+1cDu3UN4JjJA9Ux!Tbn2jdrVeymltuoj-PIKn( z{ipAGvtxiw>oS4-^Hw&4Hz#T$!b-km6_T4cyi4y+##^}c>*>6eEXVCK=kvpNyu)@| zc)g<%@!wU3H;F@B8(tAE65rt#0bi`NuFHN+-?O zbdjULr`PK*6pyL%eCri|{@Swn@2r37zpsfFpaXDo&pl+(X6q49?Pj4&?sVvWH2goSe}bV@@=Vvd{igm9YFHyINPJ{iQ3yZVfOl^+&Q(M(hYibjC*M41iCF4`}G& z_vK?An8!E;#kgd}JZy?_ABb^dfxdCV-`xstWkGlZ#kx^4{OAwztq9YgwAUJl-h+c~ zkwMrBR8Ur2d{bPac}(3o3R>TYYsW=*o5dytJsFD-+5JM0JBp=aiHndAZJ(g1MmbWc z#$YqzUpB>8xxikd5NeW-He{dFnE$XsI1EaDlKuFM5B;R5r)B)!EEDYJ>x%|zrpk@lE~ zVo!w+LVs>jCgYOXvQs&pxZRLMFdV1S=_I`YQcTe?boB7GxmfM26y)2KlP$ahIqJSP z@r`8C+X;~Td3Ks&bDGk8n(}d)3VZtPCuwhMA${1?#_iLm$hO&sSoVzj^AG=IdEFp-%2*JceyZ^sBZhxu;Mg;L6f*rRG6NoE z4n?SE)n>^UTboMMZd(nmRE**O)>IWLbP1+Lj0nQ-%dItvY=+%W(p=C(BFw$0~u z9OshR^STuB+Suu89_0;W=M6RIjm+nb9p{a*)AcCi_gsaiuxFdTKyd=O5>#F`3if&| z1#9OD1?v_CUmg`~Wf!bvi!@16WM*H$Hk8a+8EROBJ{o#TEd1O2pL(gYs6)y1@Q>5Rocn{t4>Sae=jY5sNOvo=%B-KZUdo@z+%ezL&+f6-(7EOEn*o=vJVt z2P8FA3PP%camQUYxP*7rRbn&65=DfiX2?;MYW;nVdBs;;>IAuCD&{FbkBFY&)grkU2new} zOR=)vvhtrrS#EsU)X@tn-txN--RZPmUad0~*bMpcBrcUh1ETWc?Z>LIm*q{tW%(aV z)2@~jeatTru43&3#o=F?_Jh?Ut4t3{YK1GuFJ2cdODA7ePU}{@3-*qESzG1FKx^fP zU{uFW8AV9#C3?gom0IvX6eRUknq{3(?(4Hhb$iq=`7Q-X{HyNVspF-G-Z)qB6U%zV zQ2AOZ_qC`lutP1R8ZTnG)0iRmhEPdgVET4eGw!k; zN)geRXw_1`)6_0pKciXy2oJx3f~Q5hXAKA7Tbm6kTmH$$s~yzd%dHZ0YazS6sJK!4 zyX@IB;O)CP={JLPZ`{1}+*&D$Ds&Ldf^o0B+-f>=+Z`0!R4Yr0Vj6?bzq$?IK#jV+ z%|Wy?+rNww@i?O-3U0T?SGNB^lr6M2H0eElnoIp`7}QpY+7Nm3IiZ8LF1uH;ya@3k z?i1+7jd#eZnjGP3Hmk<5vS-U=aE%)*Ly!LaUvq;9S^8tOdSC`hwc+1KvOs9@uYVE@ z58E`|s9%%XSnE1(1$JlJNtx$EfkQZn;dsVEgb|{y1H^lypIvn(8sQcbYUyL>Bwm#~?d0C%STR-trfB1sb zov%LT9DV*5WO?X7PTOm9(S8}JJ|V5{)I8Kfgf9w}7JJk|b<&!QkY1FLBD1 z_wd5-Xd=V-Zho=SklzCJl!*6tmKsLYuKCc?YZnl*%Ef}~sNm$N5y$96Wk;FPz-DOs zX$$Sn0SI<54m$wpW5I0;ueMiUwq&|*$YHTdj6d{?4%?c0S~@0YYBSv12labLg~3KR zfIAGZJ(x7YBRVm4O)Ha4wG-Z)!?b$?>ztE>;c6xW0?RpJ^h6l4`BdrT{Up~S2%%CZ z7zSKje07jlA>JM)Ia+`Cw`WE+df=p_DzQdh3}%D}4X+@PXt1Hm2RI&3NqR3#(@8_a zNJsN(897E*Qd_1(QMH4T&9Av929u~QWSY1GmxP`?K}uinn`Fev6NtnCSdvtDL1sz- zuq)Mt{k62QqW~}jFk?WGdxf272(t?E6a~W?Oe3p%#qQ3KhX%rtuVrXFbmwMb5g&#^ zYrJpH{u`v@z6tz&0eqU894!Ie$}eodPtcJHIrm_Sc*tLNKy7`Jk{^6x0dBxTxRNAg z$b}&6tQ;0xD>iMP-|IWVK(ZNzBL*bTXA!npL&u4O9-<#M*FOGjMsV*zk1fD*2a^X} zu!~Ga%gQ8_RCvz=B1J3|IG9{tn^eRvNnjxd9t#8cg&^|O+2W+y&BpxvMUlEioxQq9 zx1ngErCI9%xiE3&+CsL2<@P-q2^CCBABvdzw7kkpI!#?QIZ?&yj?@jXVP0A6$r`yPo zQ?OeNNc8N>DSk?-W7(RtzIOs1CKv9s-$)IcOZ42KLw)-9Vm@hqC1rp9W7zadvyJNu z&1Qd7EIT%+7dFN@W)-=#sZg-wy;UaYds~b+9J_OhS%%}5afag3OLQRMGf$Ev*Am^l z$`%*Rd%iHBeG$Yx3i`)BjY+OCGGus~JhRw3(_giFcW=Yk@Pc(ztqQz(N)1nf*L`%vMR7sNhmiL>}SV(hxiPcd$sGVu}7R-haS`S z@Zig%_d54jGEQ1L8w7Nhz8q(NpAX-mD=d@&_Wv2oN~=Kr`T@eIEyI<`Z4z?q;BbV5 z9999H62HR9OMeHy{tB=8qs(wz^Gz-EWm#J{N9r~%Yzd^e3CBTTJjj6Ry@PN-pH#@E z@3 z;}TiXd*MJ%xMb_MvbB{&q0A-hQBeu}u#LTR(*#92ppT4Cm&MV`uS6H>)Y|uEgi7KE zVK!Vb$T|kCHLE7?4b8;o&kZD^9{r+?B6sPwG!tNS0@iZ}_W!4U`opo0(`a?^(>(T- zuH}8zG8g*K(ICgZ8Yd4Ui)dD6Vzi9_Sob_Kyyt$xfQ4TlqWJVd8=hhJvlJ(@uq1jO zdxW&(3uCre@|sIvy>02WxnH+CU+?zmKDYIs8t22%Q?S7D(rL)i_l@y#yXCX66QaU8 zfv9{lN{WrIy7=PMtl|cg(HN&namjDu#+wPF1hK{+GAT0WieJCJI#E14P(!IPd8;$% zB}&9`Ngs}c49~?MTD4QGaj6Xwb~ccx&?|T>GJYInCHeoVIU^ zPP-jFz)v}-D}v!q#!dU^iMJy4`VWM55441Sek8VEnKJe@kp1NMb2K)h*7=!qiMqN9 zD|m>ms5f z@4#^OF;pWaeH_ggfFi@{fBL6RIc{%{o$`EREI<^mo4xPb(>(umKRMw){we%3kV@1r zykh%^t7ekN>*d??zYnY4%mlmDT==JMwcRYaUme1eB}cse&@|dPq+R%@O>!AmxXyYE zgi_=myx9GClmGWWuUb4s<66;a(uIG@c*j(x$aQZ6UQwcq!VQVUqLfsBHKf=j(3qWE z_@|F$;#zv2nI=Ef3$ODUw)$g*YoKDC_nmZWJPlyDTiC=s5*I9Yp7({H+BB4>{F`rQ zeH{MxYivTKbKo*zz5RuAei#ru6!w!~_dL$&7E}NeTK6yy^pn_f)~+1}DkWu72o-|4 zckt8~{;5ao`MXWm1H<*zOYOozU7q=3zD#Z;3fE0lwmy_+9WinjdDJERoGwUcotI>+ z{gO2A5h;E7KE0f2Eox@abnj}>uiztfxQ(PTyD=YaQjmsd&aeaejnyHVty5$V74Kk7 zWLj10m8OwOaC`8%G9#ns8ilsk<-{}7_RfhY1v`Lp*B=PpJl4U)7^Rn7cDyQQ(eV1iFmYe?GLdOs z+q}<5CsD+XdrT`^z~?L5l2D&S!FN3@#l5WV%T7{BkMti1FlO}vTEdMDL%-{dG+w1U zUaz(&K0PN(rQQh{|Mq%A#OvffL=5e$F#5>Quk2p_*9Xow7A*{~XB9DxuCrVlsas9=_X&M(ZK6lYz|4Ri|>b~^r#J-kd zwo7>ERU!Ws*PnUD9ns|e+)vUK3c*AQ%^u@2ndhzs9>MqWz8II^c(zShK)UPvd#E6* zv;6U)g;A*hv$W6OzWq`Sv1c=rPg)fQ8Gb-70yN$%HxO4|)LyHnwN4-f3=5tPEOVuG`a&-&v%9o-!^ z87iAz3Z2`hmww*a4VrD+|Me<&qsp*Tajxs_cva4)g6}PYnEo=;1_p1_2S3@-$5qBw zK_A>qA1NkXThHK_B71mFO;BlKd1+c{#Bt?yRuA#KWms~TcUYx$E_n780p?*L1@B3r z_O7eksIi*;5VLr-i1h`@-SL;-yv?NP8^!z>AQ%h3Q9+>J#6Uv#(4dEuU9@8IvDcxz zcsI(GcM(JtK}BAIWK$;h!87tTcVS@d$FDb04g1MT95;w%-mQxpl12&#kXerFbSGK- zHr+0>hfXtZ6-PDL1}^5SN}WiCAaBGj8qfBrh)U%`tDQcGkrY)$=>>Hu)J{O*QL6~2 z^IC6$TktwR-oDrRxp?#&IZKv@fz@1Jq;(qE*3MPN=<1&Byq&(`nD=%L1U`yn&q0IW z7y3JY5CkQQr4hY+M0JZc5(51mB@qQ0yR-EsZwj!IBX(C#jQsrVke7j`)dlWY?KYoW; zcPVFL>k0sxVNj{pXEva`w!k|>{NnmdkmjYX*_ZbPgNJ3+qkYY)?`?dqym2hIe8^m= zIN-VRi;}u}!MC(?;UdrnEkIME8UIpg&8aXhOl)1=1ef=-Ksb6(;A|MGlTPGkdLjX!K?e3`t?igQ{c0|>0JoF{4TQJj&GFKd)egS9wN;h~@1XQ1$?xU$f9!iifd^_Rervc}`Kia+i5pMmvM^T9E`r{M0 zQ*P&nRNod`WDFV!IRE#v{56(Je0tM)cE8N*@wuAwsW>&wj9dF&$j#%DTTrH^ovxb& z!>>>8$)6{X$BTHE?(vnrp*#A-92kd(=&R6Gy`a~Qpgf@X&PY1xmJ}OSrn2trK9(%e zqq~QD_s939-TW2ml_)uL2-kut_pU0>i7Fa-o0s!8-*o4-EDDASj%4bai$9yGMQ>6* zP`#?2;}-`JXDGfpn1a-opvHp(;-Hd9H7QOtX;C#9CADk%YS)o!ckrO|$3m)%54sBY zNrkONLV359l=#Znl|8%Yo>z8aS0bbbptnWU)s)oL_0=`3)ivGKwJ!IB;-e|HlA624 znL<^VN7M{@*eoXAj&(ALDJgqe;IV8m6y`A$+8QR-8m8_VW}zD9i5eE^8pfr7ExucR zq+Owhq-b2Jzo3rQXC2*Yy+Yj!p1#sHMB!+y>Ey2I9IEM(sOg%g`EVo#HYXIqduveg zozUt#>`9;Fpun9-VFx8CX~lkN#m-4RRh)Z2UX@<)Dv#$+H4b&H5GH2-g`4kvuXy=s zJvL_k@F{=r2T`m|D{>??)UPWnuPppTE7m&Qyf)U$e880>@`rTCxr35+lDf8nA9*W8 zo2bMBFcmBB5+fG0)2I6eRy1W?2Z*7ASL}6UI&&FB`qNZ(@{m-|qLA52l!uWzBqfH+ z)UWzeJ3VFkFFaB^9c{(X+u?29q(oi*WAS2l$TTSRmhn*1!eIZFj>G`QiwPqrj6)H ze;n@H(u+76B!`Y1k#bqpQ{J@>2dj^S80+_8NA4eM44jM{;p9a*$^Yc_M?(2Vt&w9@ z%(YO1*;3^Dq5)T7<>8TmDfRwo9nTt zGrSo4v0enn#3n~|eEzQgd*M!J9L%o*IzNKaX&HD^Re7wWwX1~O+ch|I$2?&hvXmZr z-!=kyK2Es}G!P>N+=qbP`aM6)St*(JH03Gh_y=#WQRM`+aDq(}fNX%#ENUFO4~PE6 zpd9bKh6-UsQ{NLIiCchR9EiDn3`9g(u|=@`8aQdYE5MxCoTpEdZOHh7QbCAlsZC%Q zc+WtDi|@T>z=Ihm@BKgiDZ^Z>*q+h<%RiMrHM-V*Pl@?n80nt!#*|nRSP(Z!EC2p- z@A%Y1BlV<&&fQ{HUW17G2;q%%%L||v1J@J7gE4S@lUOHt*qu{j42{WME)%1h(ZLhO z2BQ}Mr-_Nj2jegk(`Xa3BooVg6RT(wL$M40^uwJ~z~c0SC2Yp3VH#8sZKIulyii~r z`_(;6m#-kc$M22cn{%`-(7z_6Nul{MYnHOx<_rgEr zGV`C9d9-)Ip~3{P5iDVMFPoUY<(!O~y5np!Zok_~5M>ayK_EXwBWh>P@$Ke>E774B z{;5AysmV0)fBUENX^XI=J@X9aSrA~6o;3e-F`7lg^tK0rJ^yah&0Cjj=En77)A;mV z#U_Ngz{u*Ec!Q5NTX-cGi*l}6Fg~^Pzxt=`A8F0!%QxnXNpsa)R@E9asx}F?P2Q{h znpdYW{LZKQL-FZ*{B*<7;mvyI@b(cR>y*9e-zxt=q z)>aed-R%qAy$j?$nBYL%;HmY%P0I`IHU5YQGckXAI=WTgN?)nNm;I@@ow7A-(&C8F zu?PEK{^{akG;r=P7d_8xvnFQy`KIl*0KT#~MpzBu@?BD@die#H#j<7Q! zEPbC%^Z^8>Y|mu4dIGaQ;<7*fb>p9jJ#1-dZ*k=(P3lxW7PV-w#BNEiupB>!<-O=b z0_yS?5fioWaJKsbp7#aA?+Yd0zskL4PH8`tT6(46zF5Y6G)pSy%qm6nL~KISb9<=+nb>Cv1tuZFCdNn#I-i$&%$aFjLDG~-)C`wRF-Wk z9f9r-n(A_N&7aSjiW-!UR}M1ug=(**Uqjjk)nZ z+BDz#`g+EVOzVDeZr&yC-mUE3W9Z&%>)z+--XHEhknBEK;67C2KHT9xGUh(IJt;dX~$85OAT(ZY}fyc)hk53&Q3u7LOOCC%69_Pzv z9xJq-7XiaHanH}np6iC58@8TbJUutVJ-3oQw+lRXYCOMocT?>+m`m^EzGfI@|X;Kl1|Ua3CHW zSON#Rg@fL~!R&ApUO4z;9KR}vst`y03Ws=yLyqHUmT|P-aCGN56rDFck2iyaH{&gD zraRuucHS&r-mLEq-o+gB5-nd>dtZ9z%{lJPwd~FP&70@k8%^iK%j3f*;lnTIvzz99 zq(Y!2$3laAgi?I27WxRk@)3FGBRcLQw(KMR%}3(gN0QE0ipN)4!dK>&@AAv#Qd*`P=?q{&W9Bu_XxD()L7vSU-;QTniB_+VM zFyP^<0JnDm?t!CzWSF(QKS7nynvoFp`?veJ8`H{f+_x-R(lnyUUrQBag^eI3#|b|G zTcQ8>yxKyOqy6O&;pFHEV|cDMfOlrFMsHnK_~W?=7q~;sjN10Y5Y8bJ1X>k>M?b7# zEU<6`u!*D2%{l^W2mV+A{I{q>g^rpkVE#DpUGb-W6LFx4=&%5A?gS|Opj|i}EFq7# zTmeKXj0JFkN#DlMbFlp7;~KW3#K*{|a*xt8DajKc31UQiAd~eGkb4B+QzD_Y1Q7X8 ztO@}%L4d|ZqMPtFwV)`T;4>)lQY{rT4lE!9 zpU#AUT!SU#k7F=Fp8X-#K_ORb!Rd4-(J66l&M66YSqZcM?!7zd-TWJh#&8K%x z=6NFMYQve?@L^`Lr5LK$JT$Zi;g@O&P#}($^N4;uGr5qOOIDnuQZyVx%WN9aa}}r7 zpG5a2;y^7`#U9SYIlVnmB(4jJ)<4KzH<#ps3ksuO;?|zpjbzI*Sg%N~$D~7SOXs$* zi2D)dR0*5cRC~PU$juU{TBUL|8VxT$JgIt3r#+o z@2lPZh%dDT|M{`^^^e2~IRefYKFmvCm4M;S>D4C*0=KLoQ38f}Di6epOhoi_ROW{X zAWqBza5}FSf##21>t=qCnLI>dRPW5pdQJ0z$58Kue;Utp4-d{;h-eP0;gx+5GFg`Z ziQRy+t^GwSQLjPj?#hU7eLp17aYpWDi1j|i>t*|L~?#7n37|dbrr8Ze`XncwJiH#%hmD_9jcrdM=pww zxU1svUE<%oQN6I7QHE${ciQjUpjLH|fX9tsLSc=t5-PeF6Wo-?WV&*j!=*v}JKnoU zBgas&=ObTiTyw+A=doaVdR-saT>~5jxBz8?|PCq(2 z=Jy$D^ukO&LUTqQYLm2%=ZHqN?TD@pjAoHY`23ZX9sqLU7Cmf4$yCL3lMZ9+c7Hw) zuZWAWz+)Wwo>($j2U7{e@6)1S^$s5{EMmpD0Y6lo4n4eH?Qj7!(;p)*DZX#Ja)^U{ zix~bShw~F~YayL{?;{|T2R~Vyy=dDMS4JT3}(xl`2QV`#yKv zz2Kbz%V#6rvQY!KeTn7U8U9)rlvgD&zj`@?opHz{cX!W!|Gk!}*@=#n(q~oC_y8^L zAK`0tty?+=X|Opb$}*N%q^We(3jhRCHAW?7F`rW#8-kPX+Mm4N9Vhs&?$+!EdDqdEFbM>=BUh@@}plwXw=4 z_I(d$uFyU2)@2(RyRZL&6Lnf0p4VN-gq3}66((XNs1zDd zz5L*6a&T7vEf#+vr=rP4P{m~doIg=i6`1ba>b(|3*fE7Q#kX}ldzG^-Ce6z_yc&pzfse5%e%6?DD%=JQPM+miwzdoGHcJBba*5`k7MzO62+#ha3b2r$ zsm4c4S-LX6y)MG{IcJq4uza9s!Na#$l#KWee;MccI)6V@Q0eoFZa)$^=k+9rvCp@2 zh;v1nQ}X#27XMpsbSAHzoB)1j-TCOP`!`OEwNT`1Od_OI1=(5+S`j&PCR9~n#G6)J zu0OkC(oK2UH&HE?k8?IXR;Jkd{{5&!?qo7fVZQr`pE#MG|F$dIdkXnu{pxfPLqmmT zyK(G;+i76^9(`7PDvhxu-h5)}>R8Xl9e4FRQ9=(W3w^t^JS71p@&wft0u!zZOCKFd zHsCxL283r#KAZwC(5?CfAIe|l#BX)vFl&Y)@dJtEo<;E|O#w)e-U z5Z2XsmF6+1EF$sJ?wZgTQqNoWM{BbBbBJrDh~jL2Ny+QC4K-n6?tj*J*QNzy>7!}A zZNd4uK|)5q*tI(sraxs0r8K>{nc*3WXkD5yH4aVWyFt@sy)KX`&&O`?qbVpuVl<<5 zH*w4TF~oL{L94Czm!a?TuSMVEt|rGPiG_X^Sw4QxDiM&dPgse6trJfN+rc||N?R_2 z7@Nox$sT?x-9+efe%ep2jN#o{B}LO~A@B~#7?~=2-C*ctdTwOBaxpl+AVrDIyX!nw zu4;|>O;ay{@ks!yG0#p$P`h}CRI+c?XRe=3{mN%j#7NO~UdHADO=an)X;tf2WSR#J z!==+pL^rP9YaTM~kj{8hwISx)JZyU=oz*S+MJla%#7S8uXR7MU^*7C^OUw?V8ddK8V%ZHlq>s1b7UoECuX5MyOuko$^YV)&Y zw&U!2ZKT+)J!9)!pR(-hwCY_)nb!HSaM}72u|3y&tsiGPWZ%B2-t+Kn{j_u@+tht7 zw(p(Ry6{C=u4Srv-=C2~VB(Qn+h?(FkKWzr-R)?6F(m~JB~~n-oyn0QOW#0ktjiQU z*WnNEGQ>$*^U`|B_wa~+k30CY!UFg2V*W9g$S^0r`XXf!~ zZ5#Qr$9=a*v=_CBtAfk&LvrFinLjzFBp+8Pa_ar87*ogJr9nTrU6b~VzkJj1)#11Y zDLI8ng^TARH-F&me+h{OLC7uC)Oi1jn1!x8w_1x!3Tj?1ifB)%H!0%>`evd71{`$?r z_X0t`>7=u{x0Ng3PBmK$pN@Ucf86owadJz)Z-H;}u=2N>cc%sRuYN4PD)`=Xelt(z z;wLjcK4Nsfd5|XI9QM;{W$dx?6Uv&CZHdCAnRm)$i@1YI1VL3)B(lJrS+`NQ$!tfqwj|PQ>iGwlyDbRH zY)dB5t{JICA^){wXsPdAJdm&A0Mzd;VU#^8t4ml2#2~zCBe^=(10FS2XWW4?``9b) zc13t=bGq}MJmTdsMY7$-GbGy67ua+B)nJJ*S(}G4&fV7H1)_UNZY?8WvBKQto4^5<3|!uuoIp(>m`QM1`A)_!<#5>0(6gzxDb=RU9C zK3`c-F*<{nH+jvLj0Ioj78Y2`zN`{`-4sIO5ZMd5R-D90DmL8UldyFtKjIUjDBcPN~z#t22dI~%`dscfAvcdG@?W}U{QKaO=c&Wd4M2>BxvPeX2Zzh zZJ68Ar8=f@YBBeDX&pGtZEnPT7JkcTZbP!2ix6W|7kh7W<-M^^LFt{_+PXd^cIy1M z&}(B4Sg-~#Wu-M6bN(xq#n;bDjit3Qw@dA&`7T|M*M}yYUwT#1+*}`dZ)j{7XKWBo z>@S*WC7`Qpaf3EfdGtVu~uGsc;(ItZHAA%?!g6xw! z>6$jIe(0m{AFPXM_4o=Hj|v@UBDle2PSl#BDE)W10ncNsqpj!)d^!R``+3@g^w4m{ z#-q$lfcA8L*>39+<21=*iG-9^Rq7D%qBZh6i*+mq1@gX1=Bz=F>)Q6t*LSYNOH=pd3oqAQtCkhMz(9K1m6gCR3jj* z4`m?A*H?u1T3POXg^JJ7`hBfN9F=@+?+0Yakc%ay(e_4J44$fqK?#SX!cNdhND8Hm zcJ%&L!`(XWs`OU<@&0SIoV1dpI>01~LQBlS*okhCZ{ zYWeMD6u#BcZN&fWJnpV4y|i`hFj<j90ckT7!Z>|31^e4E-<>C=HC{2*7dJtq;>? zvX5r$TKGxmz7mSZgPs3Ok>9oL@@d@~I{6g*<-l`a5y>fOpPLJwS<(VlgBH@&F7`t5Buk zo&fByWa_3M!mVUpI%^c^K@Gp=D5WICi&Kq4NK#c2g@wIbjQ}la6F4PF08<-@N8i_y zzE~5W2~uOHqa=g3%=;~EMnYMqSUX?)OGI!+V!_R`bpft*R$K^6CSS8&VbftJ#h=*| ziDlQybw(dr{>+&hDU)p+9Q6$TnY)54m+#jZ^U3*{x20dMI6F8N(DF0?AhBF&Q)fK* z`^Fmuo_x;nH!%`uG7rJIc?=xBspGzja(0A6I%K3O$Chv$<2pF0w_E@o-R}T^#YUh(zsmr!%NFwFAYCL8Ce+9@)@sIVreSP`*mkt z=lrU2F{rfc+=)c8VJn5D$;^f-vwC^tnxOVd+n+hI=bIlt>G462>(U?|O^eydYV zsJWWxefoI*@%QU0*q)o#13dG{@3&+c&xaOYKQ1Nhri4;we3aHiBB%< zSjxTbiLQx5szj+_{mhD=_C-np^#JD{TOd;Y6% znPJ<1J_7)H;9EFcfBx@ZGqpMm2?DG2$_)3>yAH>T(3#r`+^T{zN83|QU}W{oa_%+- zK=xBuSRD^%Q(O2Y{zPzhmGRC%8?~(zL1cH0vfYdhAf&~yJ%T{E|tOsU15Vf z>bSw}6M6sNXMQ`g0bN^+SMKimj)1}t)leVPQ>%^B+w8+|>hE!_i4WkB&8i`_`1rvp z2gbtebJZ`;r62C;&i>cXSs}X4%ZVtm(z@W8hlR0g*B4)$4r|`{J4sBgFO|U(e4v&? zrH-DSG~{i=kiS#^D|E*C=RFm;HqRgg+*sVAqd!xB#qZw^zhgIG?X=JDV)K>nnZvN) z91bVpP04rAGOOkT17?)mc@9_S256sxL?x*V%m}PHNwUQCmWN~993MZP(T88B0qe!K zYAesw=Z@dJY~rQ}DR*kD=NDZP!CNgU3~4I7#6I{G&@g z)1Tb8nH613Bcli0&n@PvA-fih^-A~^Xnpw+l z7!I8N6g%}B+FJ0a<23cF{hh8k#r{-KsoT$K+b%c|7dWA}v{+nX`kB!#xSMBkLG7OP z&J}obkVf(^j%=mRLf={v7sPDM62f+0Kl?QR_xWlR_;<%yP`W)jL}q=p88FvNpw)5`vdp@LgfJv_-Lf$P|Z*zP(jMtt{Vj8JWLH#n}ZnF$Ymn zd&7YGMc|3qN%)ZJ;Rg5Vy!*FnfHdw{ZTeS@;k&5)J!CNI0eLRZv>neWzU1bN__i=g zrVhn8mwRQ531&fy33P$0oAACITLS1{KSiX9{5udPac)Cb2iD`X-JWS2PZ~V^iacoj zl>E+(S^8l2Vyi-V11H)nBWZKw_7|#*p^VK8{!`BV;Ll^Wer$jV?DyLMmMSZCA(HJ1yV#DcDa>M7M$S^!BTl5k= z!Pq=n1m$l&z%?%!Xk{MFr-irM;(VtW;oxFboe||+!MSkV$!#mB_e+dd5a*OE)x{E1 zuD{C}5D_@XxzHEu=p0Ls=lrS_*BwA<78Eye-We6&WNW<{m%@hq3kwS{^$02pp^~@D zJn)Ute$rk<*w%24MFmF_UCeMW7ReyIR>-g%$nUyCno#_3D$P8}el5^17)zy&rt<7} z4a0(>Yr$!#@B+&Ci%8nN6)XQ<>wph5A~@K+g8bwl6XlzJ`d9;0F;@~9wSvg!8 zoiJc-mGT_k`ZkPtG9aurNxj073Ldw@##t}}Pr*LgI7%#Uz|*+I&~&=0uUIX{C5xG* z3=%@sGE>%FlE=zJf-y-vbz#w@5Y@NfUlBx?IoG3#lrLF!T=H&3Td1H+P(HKmv|}I# z6&LlBl=@9bzkEVW0OfBA;@+G&&;-Vw;;j_3|H7w%9y=# zR8nrvb5gUXv*Xe)d%I<@*{U3+&v)KavY_7}BOVU;*t~f5!`?POE6hPBgFP!?=2x)m zi;VqFo8X{~Zp~*ncC_V@r`My*U3=TLa=77O=CQr2{a`ewU={@Yq$buc+T&B?JrKIfm5$DOjUig})%S!?=OkLqR~ zXka$Gpf^DwcRw{o_lbqpY+Q>gPofzy?^kXbd)}gId~^n`|4H7bqP&q`zRlZt6hbk> z*QvC%^LL!{yQ1^6O7a~C^Bd2jaYK{^N167WrZ#g_(O;-|_~&vne+7-s7ff|Vd~nP= zq~du+m6VuW_)W^gZ#&2Y6?rzuPR*W3`7lW|HO|C26gI>@#S$zcS;S;n#1dS@rdVWx z1r=K`lxXBh$QROmWL@~;ERf@zpUvxQmbP; zOy7d1=IMD&Bc%k36?0gBQ{|31l~R4Tm3wL7&swUL!L5SDv&XAp0eA(0Q{vVz_6R0a@&jiWpl*fXyO@Alx zOO<-(SOjdBr=*tZQs?oVgL3>fA+~W9X`nK{#x(90_vm;lU*Q)|EK_GSY=ZuZSjA`O zDYCnkrHPQdl7e9@^BIX*&!1DXnh1xZSE!As>D8QbdEu3H)T|{hJu5cpDGq4YEK1uI zUrfh5&0H}J8$x+CWP5D8HwIS`2noHqfoTU8A+A6hQ0*vOF}=fv{QH90{4on55aRkg z_XCX$M@{l~x0a9AF<&4VD|EYT^g)?4?AVYUe=vT&YM+BGIk+&^iR#0E>xb||3I*ZeU>b#l zOv*Yw5%xEV*sSvk=WIo5-WzXHS2I&xtbPo>Noy&)_0La1xIU>fINGAV$pq#cU+*6b z6CA7`m!pcMZb*` z6sch$hq@vxrX9WfL)cwo8t+$zT>aRXF6DtAuAlC$ib`N#XsCAxqFN+1B@8!(sSs1y zp8ip6PPC#$PrUS{#QRk?rx5}($e{|A_*hL+aV7g-3gESW3xp*snjBX7mA#_>@n#bN z(d6b~)tcn(76yQ0Oe46=DH*m~i#uIeNbmp+r@-g%zM0m6OYCz;l))+lg&4Cbw$Ldz z4i9G#`h4Os*9;*T2WzCLT?}DI0O>>hk7V`COfZz{#8=y&I0oPyCaAPpJ&TDz%8iiP zUzaXfhOxjf4HlR6q3lHU*_r{^yCDdFcQSGu-K zw~kE#EGPr}h$H?{b|7UTJlL)Q9J~@@rUD(GaoxJqRpT98P)2oc0uIy$-a-QU(SiKC zWcfVe4cNmQ{@q#&J%%Se7|vcJrCwv}UenNC^SoZmwqEOnUfYviEN9<+rM?H&eNLf$ zE_rLFWZKy z7KUn0hH9&Z!pJ?vCnzOFy7$E4mbT%xh2f5qVKV1Pm(oa&^+<;jwT;#AB`J>*?8w;3 z$OPx;`_K_zawV}1_$Ckk*fzSbFuHUyy23fOrZl#0J@y4TW>!lzq{NU*Oe#DXJK!Au zp){V3?D`ryev~))u{Pmx~l-J6DRtggxiF8Kq%7s00duw8Id4TVE{}L zNwTkf!J< z2nKWo1KL4NxhILSLS{Rs>8Ms{ZvlSbeJJ?79f}$dW#B zhKX2XAw(J^f+WI>N9;I&se##kjJjntQwH^Karr75qCN%UTM>t(fxS`7 zAT$!B4x<7T8eiY;>!yag1PEG2+|Bmg5xv-u)>R-hSgXtkq&sj1#m6d*+-38@1#h+t-v%+kTd#}5~YrgC-E zsS03T4KZ5;ovx^u8EhP(q094hY`71oX*y{%%oc-KLL*tpUyN(O{QI}f7uTxxV8A_y z`Nakbp!!?-Q;XOp{9@>@tS5Ai-n7L55b`7+31TY=T%?!efcf;~4_1q7?wd3Mq%B(# z1hhi;OdOWIM0cIMfl2z%tOiLi+(})c6R6!%U!uE;TX-Q3qmz`RCNBt+7pj$4Z1XnY z7uWRsq@}zod;oZpH{@`1eC-$P3rG&L!G@;m$AhI$r43P2J1C@uFOr4?hU4iNJi*ci z>rlyE9u+_zHFcx{5;xvLEYYQe0{|l+ZL=jyyz%?TR;ez^k~j1Zz?70RifAYw>N{NWI}--%z9h*;1mIZ6A2Q6&cmo7n zhrK&EJ;%{a)j;eo@AoXxN#Y<dvv$2Q*LLZTOvSYa4wByQ9RUUiFl}O)48#?|>w63n7n1 zttI#LYgNGXGb#CiYYM2|L+UE}m-!i3sv0yL25_!iw;oeuiG*6yN_x`$nSHzqKVOl2 z#ijpiOi>{6hwuuG26@8}1CqdiIMLr4@1ID8LByg?M!goVoo~Yq012FE3mA2^lyhQY z-0odCA2$=Z{5}?lgwR%C1F8yRAVx-qmHsOfb>Z`W{pGQdh|EiH@k6VLJDFNAiqp|j zi>WULc?$mf>+@5acSsj?`&TTdx9*neJQH{PIK6$Z;_h?9=awIKObS`)P`jH3&?Jtl zCK$5)XFxo%pQA#aG`0-RK?q%zCj#d0IIMWN(~CZnA=xtRu#&HrRr**@QAp7sT)qX< zDJACwFSv;E-Nk=;&P~SNDPxEsNCzhxolLMb_PSa7ovrQ?1YWBoMErU_8g*1!Wm;EP zxEFy4Dw=z!rr|zD-(F$vL|@Vuz9S$j|KFOs^LMEGKVIOU&uq5A*fO>ZAtc6=naY1dXG20BI)j6H2}v%diHL(PCaDBS z3cdrL;8NWjGo(oba`ps{APp@01zmMyKr4xSTc@@9k+f1bt}z3J^H$_Ghbf(-9z$iS zI13s-CJ|99119ON*i&SicpsTpE8ZJYz{z6o$D%w+@1<6hNrcsa?R{GAwe!Oqdvp?ndDa6Hm1Md0iD|MyY%)Br=SQEFy%~yd zvjjsqCc^B!TsCyuJWEHW6fefgMeiFewB3nIPqweWbR^|+V1~Hd*`3fS)^a%uL74UHAQ{H;HO30ZS9g zvMn25p-=NYg^a{V+9^q79eSToYzMdqX$!K|JANlA=O^&y<8Mg4pmhl98S9NxHu*w# zpo{tNV(*V^GRFx3ICLcBsUidkAX>cfW=6_$TzpGTa_cB~5Ug;O*{JP}>b8D&R%dIG zsBGZ&mRi&7oj4$1&ytEzxVk*bqTq+x^rQFi$3|@otHo;Pv{uf=aU#MoaQNnr3Wy^s znwoGeKo&~^btrlg&O{1Sl&BBLsXpS~O=KmDi9nL*;K^wUsAQSWvc?Y()WtxMZp2C_ zAKl`mrArM+lQmVBGI38$`MU>=e#@c~A-ptD?CUvRZY&8+fPtb^Cc~^Ek~9vF5Z~%o zbjIt3Y6JH0Jr~pilsGHO2LP#E05>rX?#>0hxJzRBw=R|9$z%zD2t443BTLpzU_j$A zBt(MB(uK+CEZICT=~Cgm zgqOw#72}Zq89MuOF}(lM!_88!vp;THL@i!=wExXZ_wbJe31LlvN_y+DN8l5rtc(7S z(Ant-%M4HJ5}^g}^Jn)gvy-e#8KE;1^9ZZk<<@1VJbX-@_N?;z|M$?@f{#V?-X#jc zrqV$2s%2(`b*YriV^fc-mmcg{R~p$=T`Ie3QxjqH#M9>A&{^l6O?{Hh6E{g;`_~b+ z&E+;VzKqb>r#;)&ew*5mGGC`35q2GmHg%EzgwFQts0iEocu7AO_DDjnlx;&gBXlOR zPZ%_^J!;G=^Yb_zX+Pp=+jM`y&+F{I{dkgXbBUzCk9p+fX~em|sy+OD?R|%*`|s2m zW$63+M>>35w0+io22`SnJJ9<1E{UeN1Z74t(1hJ{(fls8_B%@S{ zza2iF98$FZss6&-wiQaP=3w=wwR?8$jK|IJPs29r95@jJDiuH~CqOEDVip-qT?@X> z8$)w1|2&nC{1QoQ=(iJTMUi08qyHa+RMTS`gQjCH25DE}x`CV`o63BxCp_29I z;8%%p{DgO1(>BV*j99|%(6eKf;Uu0y>Mig(j$ee1)h!Gpiy?76%PD6Pt7phOclV}y zbgot{e7N%GZ@W%FDj;TujR>)`o9!)c!DnVV`*{iV{iwO|EI`w7LDuf&D927v!LWZo zg+qDsry74z>I%zz98}Qrcl!q?2ObsLvz5iLi%#jrM7el2BoR15GGEMap@04IbSPp;>yB4gzpiGxjSNs64LSA>6c_S69-{8 zl&a7aLAbT>=5(%c8I`zPPfJkU1(MUhxQR%hnND(pY3M?yCEo0P3o|zegyg(cbh2~l z%dzljp%8Gj65ut&k>#v#FnlFdGx*wVKcw4o!A^pz@Db;q(7myh#$3@tWZs4y{ba7*KsS*?ku}#G?sc>LRu(!_0);^QphcU8hR* z6yzQudi4UbajYGsMT1HC2JJ>P7)v<(=t6k+iG+9@CBe`erjAbdGu07_iu+58HEuo; zKA0qz3-VAvMY5j2f&MwzBWwayaa!+q?^*fTvtrWV!G63hy;C>E0IwdeM}l(iLRo0K zc_-RRm<_KmCs}VL!ck=X3>JAa>bb&m^*+7Aay_MZ-3xvRhJ%J*rg~5K0S1E*`PM{t zW7y5W_KZ#4>PFi{A!X!b^Qu4*HZ+40K3v zwqzB3&49#0n&_hWBMtjqJD1XZ!Jx5_-vnT4e_9N|bm*!mBF>P;X<% zt}kGb{}Pw2U!|4C2-F?BOjMiA|5~83@w*?={Hx!st`n$>lOr>0dS1KFDVN%Dv;=nmzCV@3HKMN5JN$s~U}AN2 zlI<*vF#1*4qDjvbqpk7Ep}i#@&dr=y>A>VZKKg*Uojd!*O1p)0Hj}4>#osDIZ9H+C z+8UKTtxY}TPu6MhSxxwxwy`w}rqg%pq2u36pRZ+)F?Ei+vGT$xtt_4D=~E_beR!^g zGCvyJ3kBhTw`G19TxeE+5GF7K(&F zSxPKe<~U4Bnp>TWwvx`Yl6hbyTVr*q(@O63&f-7zB^qf9a>_xjTdi(bFAf;#Z)z$OBFN*_W!b-v43@ za~!j7Mp8HgmhQY091QG#PE?gwlHOv=#`Vs<8O%HJqk@Qo$R>%ZH~7!e{bL_i`|8$y z+Hmb*Ydm=*HQV_p117V_SL=*6h(jOVmZ2~FBK&r{`z&N8>&o+^BRNGiDifS{;@0)S ztrKI=U>IXaJ}}60j#UZ<_90uf@%@TiN=rmtJT12yD!Cg^7UmqBx)QyLVtfO`RLU?D z6hnK>*4j(Psfr^BY}{h9S(f{4`Obiu$N5t6m-AFhxUMpHfCI}{Cu zRp!N;@``HL7chKMk0I|$6c#2gy40Pnz$9L?`f(G zk~kq!Q6?l!M`YNF%V7%EM;A?VD`bHOHu%qn7n zyz6=qSZk~Sd_{Yl6Cz4Y?qb@(kSySbyoxf4aCfa9CN!2>^K658%Hau&e+?D#XWM`Z zh+xS`rgn;tZ-h7N{m<>{TP0*oeHwSe&0WTOxK39L4aQ^Uh@u94#?%ipnU#7q#2Gje zhs%0n@J6FM)7gHy!$_0|cxLMo;^pcK;mz9!wI3?3th|6z2+JB|q_%hWDzQ%#lO4ix zh_?iwg#EoI4TrsfkJUb7aiA9)6$62@2I2uFo*jk)c_DnH41gM52iH2hKcs{FhC7!a zFGoh4!WvKMoPOR_6HSbB>5Udx%=dW6;tFwAJ7u9O6-6a!hu%r`f^2!7@X;*0CgK80 z!|t;fIC6EK7w4*?BQ1{X z*Mp*y0+oRkOoAi<>{C=I4H;8J($SFZbxix^rvFYpUnuCt;y z#d;_vNKQGKl=9pnX0PbwkF{)nh2~o>NAwW=wJ4(`1GysZyMw(_n(L|fjAGsj<38ET z>uH3M;$zPS`{X0m(}~Cu^nh`{(!KQzZ?h7?w}btvZR?qV870EsjR!Q}uV;milpNm~ z9MIWYzePfpVwg+@^#wPwQ_M=m`CknhX>R0XXOv1X`0|Cz8@c%-rBZ6IUR{jX$fF?3 zq|ciSS>4;XU1?S(Yxio%wr%6D`iwF;FO%WR?>FwWj+DuVy&87j+qg?bmSdAmMqC9q z^9Rk!mF~V8@oWoL5l&;+kL64_a-`t?h>^;hk_->VPpzJPo`rFKbKP!&ZKQzElnK&{ zb$sk>X{qXu6G-{Nc{no_2YBO-;5@qw`|pO z0=xl=^*HHY`*D@TddTa|j>Us;=^mZgkV*{yJSW1MS`7JJY33z6m2D*kFjL7&S(R2e zc_TGbB|Re_hW)sqQVNFafwzKQKm5F2p+F()W-{!@wdO~HIO^Hvw9qs8otJF3kii_Y@hGFsgkNB>oj($blh1-caXZz z9Ssqxw|Ss9&d3Sw&t)J~w;M?{VAMTXdxc|0;2G>G&-1?18EKSz58!St7wDFgZ8Mcp z#^4RB59hj%hJez#*QYJrv>e`hTHY5&)m%$Hb%_UqK_~w9=iOI?wsP-07d~@M)vC%- zdK=0#{<`+OIUN!Z*wSX^&Y}C%)H(AW4weH|;OU$o393Kqcvl9An*Px1=ibvuKdr!6 zt%TW=S0r@5R=AnzYkrhVkAobmXKC@Iy*iCSN0|r4FkQ&_ri!-3u+}Fqb(FAay%rio z|4KU9ku@KlPh6YAUN=aa*wNW3@7VpBden1vV>^U`=mQ{(;6}x29f@`N zc+V1)aJ$30#J6Rj)rF<#c+I6Mg+&vo*D;(k3K>o6y$q z@l2CZt=7lc^01jWjo@nmf=F|_gvn=~a34aw%_4x-Uvjyvt+Ax9n{Z(u;K%(2{=L9NmWUsh7{E-nK?9|V zruu}|FK#?F*I!|NIV14%M#N?M>)^>rVD%(dOGOYaq~?+2a*t=kfJSfzP3mT}=dIz_ zu^bK@#qK{>TOvPxnY_`){|3e-gyb6lDEbI{8WLH?%S#=DgeL!F)j3%;a}zz84j_ZZyok&|&k@ z&zf6*J&ga-vGDT+Wb|kP5Po>zCh%fn;AM{d{=+J@H%bS6uKN-tc9IEderLvk+s|U{ zav}oG#|qA|_hKSz&q4V-NiJZ>-xVZ*E)vJmWh9ZzJU^=44ETWe72L7(dMzk>;I5 z$Bb8Uz4dlxln>(?GWq|?6acf*mogid(iEh#ekEmT&Soyo@_ehz;@8XixtpcMb?b#R z*H-?m?IrGAbo^S1@9)`L>g%`8tH=KsyajvCjd&Lh-b`jR4>J`cw4S_mc{iJ+p3QB- z!!D4>ER)UkJjXgYCkdU)-f&A?fLBB#SCl13=1-=?%^P9~T(70`snxV%+P&VN@_wKd^`F7~;?GTS7Yx`^h%XP~? z=}s&T60LtZKE5r7ps8tTbmKB#ZA z5fLUl>c%nJCKq;kQASXh&lG*@q&E5`wNe`mR0W=(;w1JP$fJ08Sn_HpqnO$ghLh*`^mUV zVchRfdU?y16=9UHfrosp1?=>zcWt1*rHaBTIOktI>I{1@_NqwxZ#0%f%Awk2tHMAEl@*LRdZZW&vBwC? z9{Bi4n|DM+@e5KlQ6k)J$s*JyN3Sq@GAB6w3z4hgOY<%>8qt?!B7L zi8pS4N-ciE-N*S-7Vb5m$w6y&)^ghxtsZVS(i+7r^H1ElB6WnTRq`!Uq&A#scLGsv z8d}_^n;Oq*T}l^d7Mo*tywH43C}u0JSz>}ypW1YG-=~B01aHb^_r7@*K^{$O>V5`>By7=&mPs{fU$eF5^>aZu*BDtv-o*@#coXi;H)Jl_3v-KYju3LuGxCyKsG(dlI?k zqGm0EF61{!hQiBH2~RmHkLxeJFNy6UhSUE0e;Eb(Bj;=s@IDGlKNwngkNzDs*2pyu zJv$gK2hn7V-SLQxac}-;XnKdp$8`w*q4u1mh(@o-UXbV~7gUlWz(j#`2MUuN3HnFZ zg;%)@)chx9xAcu}qsho?%F&Z?j#K(IBKt0r`qopi$jSYnah4yCFsE_i(SStfRP#qp zdG;x4@su&|kXG-sZ0INxh3)+W$b^AotkG;6f&$Z=-Q%Ea_NXj{LlFgCp%3qE&ajMw zFKBEc*?<%Z%02~1)xUMbL7@~5L2O+}5~nI<^rNe&)Fg=A6oUsL&yYChi*;XQbL?UP zV|||+%77F`Ld8&cC0qCDjkh35Y=y)rlMS)&wuX^K(YSYJbg}n_01FnzN|n+lz75Zm zQpZU>rMzUJ!FmB*#sq(9;W(58Wv0SJQSkDbnRY9nbzBqi;C0~9q5vOJ%^srK1-uP@ z@P1p2^IhksM?t4=)j)Hc}GKi~#L^eUYOuYb--nbVAcE(c-wE-F0ln0wwaƥ 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 literal 37941 zcmeF%Ra6{6|Dfq^ToVWo+`VxK?hssq2M8A2Jvfa+S>?(V_eU4v^Nxb%Minc3Ny z*{i+Zi>kW)-PEZ%=Y3@4r1|)bd*Mmo1_6Nk`+GBUtEtJ!A#1D2G`ZqE9$o+BcmJHcLfB1hbN9{`Js=$`~RgUoS$F#Moh%TCq3O>K5cC@waspA zZOO>0tZ!ZY{d?o<>kEUyo}Zs7Vd%)2?>g9@SSqSFqkZM_Fc~*pVXVQCorBnKD=TD&3luO84;# zub!P+4@K6@>ElMPN&AlN>sBA-n)R#4PQU4^7Z^AoFeo@AG%P#<5*Za86B`$wkeHO5 zlA4yDk(rg9lbe@cP*_x4Qd(AC0j;d6uBol7Z)j|4ZfR|6@96C6?&>ZLLygRG@8hu4y(`~ ztuG!=W&b&rCD%|gnaSsJx-r^NI-M&PghndgSTuAYs#++YE#FkJ2-Rt@ z-W+R!F4q_hKu8suD_0vV=PQ1UH&?B~c9wkA7TuC{xF(8-lMTmSBlBr+LJb++9e%@iu+DtEQtovk$3Y)|=efv5niR{u2!@j5d{0a&i5v*~5W{}dmnF;nXuiX6 zYEPEWoLj*-2#kN?zJ9j)6E90w{wG0^=j2bKsx;$4l7^PmL9&i{Ic?IXnB_tWQD^o( zfa!<0zI4ly^1}?<=99xr$05d}EY~Hgqim1E@}nG|`;((w@YMH11Z=OT19H(A!sCJ{ zp3~#PIBC#HQIfm>AfJT5%aVLAf*)W@sE?NKk?BlC7Hsa7cUn=|e0mD49Ri(IHZED8 zRka>goK<(;pPtq9A~BuUcIPl!mtdq+$dr<#Jpt=xq?s-n7qo0HU`;FLHW$cn!9+Cm z+l-mR1NXavM&TCu`^H{n=Fy0J*ZNbL*3CO_y7o zO-UOZ@A>rrmJ9}a%VvU=V=D?hhFBYh!uj7}iZEu*YTRjWry=*O3d>>Ymh+o&_7}bS z-y;Q;9K$a|mA6wu4V67T%kr1sk4rM3mV#+&hy-&q%sT4 zdKY)gMz@hoGrA3ZceBQ&RrhOiG0{$|c3G468?MWf&~?Wi%9c%^hl_^_k0a8DA*RB& zhuv^*($*cD^X$j{IJPdneJeh)r-QTsA^rmkot&qmJcUkv*pZnB+4D)+IJ4Mq@g60w zlVIZP=kvxM!RIrRG=rDRP8Dy#OQYkhm+QfoXTfU&6vNk>iFq%f8-0fD*MAGpXQ6+( zvW9Q>zYSxBKd-s4yVijNjoA1Y-;R8`WJ{Fh9cAOGxw~+A(;U zU{w~LYv^xGPX;xqnURdp^EYj;4Qh<%$6<*jP+XuZkP>rLR)>-^o>|9~njV#p+Yc*2 zCXR-d{z+D`L@Y7W)RbP>6HYa>KCY0)3{}xnUbI9lncB#V>FQBlCvZ5rVZyA&8dc%@ z=}lCpMlqW|>X1=_bK2lU0f%tJgsHSsdYWy?9Bv*EiCqjH4ND77!0`(ZK@8AVK*y&? z3$Rr?gD0I411zluxFLzblU@S=3!@U25^5Q;=m2=EnSc)zVBp_MJR|{jfX>^kC7w|) z(3uu&(|($}Z>tBu$^&A)CKi0g1S9k9%;2rTxZ)qrSAhg^04;v8{3ZdbuX<*)h0$L! z+XNUDHH!fW)@Q{EuVoaHV-42rV;O%m#Kbib!9Z6q5G@U`rn?5p@-l)0tS}&Hoq_=8 ziJHh}crEO`0a}O=no`lH>V*OTVECP;^5SU)q@n`D$f!)M__P9nLZj+KlU~#O37Kbm zgLO`F2{NBH(z}&Xw3kuQ%Z3G#{%;K}e$DLg%~E~sgN1n3r23^sb1_ZLZ(57EC3s2< z@O03M#tLgV40c3o+yPXn?>r2*qG+C-TqtSS<(YA@78WBRYHWv2H;J2%`DveW%{C2lVZw|19o_H6b_ z=F^H{0o~lWA9qmR2{l~xweiNl#x#pH%W2(~g;MD|u)?W1xxWBPzWsNk?ok~ijI`w{ zwWh@BOyenmj73fNe{wcLW_k+gvk_Dj_aj&hmQUK(qezrZKd_Sdv@7T}MZa_1RR%TE|CxxEFYLPOZr*5pHMkzc`p{1Q`6~AKWqMTjafV0)D>AnYjfCW>pSO9=f86yL+3<Y%!GG9bk5m4A|Dd_v=V5s-+lF0_^p5ZUa&z7g!(p#n z4zQPb|Mz8K*c`8~AO#qnPY56@ijoGFd5{n_2lLE;KeXyyrnr6@ky+FZ$kG54wz~2S z1e7*{FC+t~T1Chn1GtR>>1Dkc%L2K216dyVX)HxJ`GV5agSK6Q_z3s~!i9xaf}U;z z*$Lpq8G^%agJxWUWgmIv!-W)Af_-m;dvQY4EO|A;1+_dvkiP~?J;LdYgxDsA)Zl~) z4`_K7X_83$o5~89m$6QU0AG=qez?&!25R>NhE)`Voi2xF-G-jj3*dnDcj~^8$FTw8 zfIDA+$Z_({OKqx2|oO|UVuzht89e@ zZH5H~ZHSQ2XtOY_U zP?W0~R3PE@%}oM`caRBgWoMmeLUs!XN)+N9P(3*s?ix7Qssoo7Nr3e#LXL?$CdPZA%)@pjr zQ+nQLx{ZfZ%u^Z-R=WEMr-v0+S$YO_Lk7cqMl~U4Z8}Fie7wL5H3>=LtEP^*QHlQh(%9t_gFG_j1D2a_`ew9-nBR+j5uZa$&+Zxd2@j zxHT#S-8`$L>@`BUjqQovLk4)V$$TPgU1pzO>C z7~ux&9~U*I#eB_(R-x61!~;zhhdZMr5r`#WTg9`V7M06tFMC885`~fP6pfha-5-SW zWN0Kc7Q6=(RZ3{1f$bZ^^{XuDstCf~rCgwr<^e>-lZ){d{SeTJmPLY#{8~}3PN9BC znQwa8>;XinBF@RW$WXS_#Vj_HFC3D_MwkwKmMYw#iTU~*O+3#6BbbT*85q6o5e`OE z7RZQE#{+SJ;z=X4Ypt~)9?=c>GR|wHSrwrB-$jI|Nv3f;EZz4ph!3i=mu_Lcgm&6m0LEIL;Zt6DAtcg`@u#&`Pg)FoZ_Knw z)ka0td8M)e!zB4ZS9qmUokmUesV>!&+T~5HXtw zQ-HxsQw(l15?{0F8Av~q)H1VK*Q|Mdx!InnNb#&O7oo`o3U-9LIt#YgM3VZRHT!#$ z24pq|*^q`PG>7StM!YmdDv(BxH^d5(#(Os;GLa@THKY=grmxp$qLXGv*5|&E`LB zvch9b>1qM}-X!EqfYcVtU@DdE{BYv25_8Rnlh$vW<6X-h0F#h}W=+*5FWq%Lt?l@@ z9)f~{ht47FE@DQu!1gjW>z;VD7*mi6?r15Adnv5qQ47B@K`8(|1m)= z@%NaT$4DELs2>6eE_X&Xvi&1wRrXTa5sz9m9-SC%y~Fo)R5PFlqN1;e+B`mq)}J-) zY=z~PG)HKEP?2a(I7fhjlm+)M@qTIx`B@^6P2AorC#4 z+0`4w9n9HX6U03mS$&)RYV={%?KJR2quNp?$AA4|HvOU+43U%CKDMgUwf04~-_pxrD|EdUF! z5~>8iG+M!}1+Y}j8Ak&@Qmh1FE_|Pq)UzY<6P{1)0;FE7;KZ$b&7Q+#2gbhv2*lPR zSXNoy0K{0Um|}B`RjXc;t3I0wN)uv2mTb zI9+UjlxDFUSLcN1Gwmd^e-P#VSS%0*^#9moyx7331>$!B1Kt3bVq2?9fCfxp`R3M9 z_Og_3f5^mO*oI`!#XKxQX?gm`2IJ(~QTEC?%epq{CQBFKxNBv9at9N<{(u?q%lmKMOD1vFw`LEx5mIa=fjC{g`dcUJc#^ z#ItNiWbeBuZQ9u_U;S8Yo80VRQN%Y8BUGMuR@zWj-mtw`VrN-z>;lr*Z?na0#+uP z!yEC$atS4Vr?9e|(~9oX%B|CCztgJlA=)oTg-$a{vS$UxXR_gE`T1uOBWHQLXTm7w zxs>O8vgbL*=Un0E+4<)X{o`5JW6$-m89$Xdk&C>6^Q_%-`m&46z6+}3iwxi;3BzT& z_~n$|1%=zi3ajX8xBB_kW$Mq%w1CSGvRA3bSE%7vDfw6MBUj10SMSKzNtD-el?Ul$ zS2rK{5w1wldafhpuM>=~=@fS@>_jTirWHT*Yj_pk5crT5)6(N!=_t`VL8 zje6RRWAhDjYzS+v6Fd3s4}#Nk&`rn}i(hNEBL1b9FU@@0c>*vQv^an$>{j+;vt&)S z)RoLH5EJa1e<9cOFK&lh)>}`TrY=T0&*X)F=lH%R=b8 zzZ~4T+WfWHy8qQ^DCd9g#r&{=e!s|g|C5~4(gz&bGC}BSblaN#ZQL_wvhUfyeHQMyYT?QjYLluXB%`7Ov2yYVh|smi zr{xvB{xC7Ows&^-@;gKn5XVl*$SEkPsIG5r@9rNOo0?l%+uA!ky}a2{&KU_n`-p>2 zOioST5gwCpFCrgupQ07QE5cNn&wo5@6(6ZLQmnP?yeqchED0-Xx1 zK(XA}Y&58ktUrp;g>KULcuvl=+=YHRN5mfv6XaSpX5Wjoq*&p~IA0=RU&0P@11(l) z)tF3HxG^nP8}tNXGPyIa)|*ckkfPsZ&Ntg{_iMJhvu?J#U+qmof3a<{f}P{c5MavqGOu>G8>qS zAKCnbo^B4O3sq|TgkSD2w+CX`{6*fL@2~c!Yy3rF@9!{pf;=$%C!M?iWU4e+ULZQ> zN?y=M34;7!95tQ%5PXxg{7_=&mHaUBK!SpB>I9vF2>ODw0ti$6N*PKpa zH1A$oVT|C-N@1)h9AQzMT2JMleJCKi&ONRSBp~( z0|`sgekOb`Nw+9SFUhc}UoFXW=qD`Aa+&*Hn*D1py)?)BX0#aKx3h1E2IN>xQW^E9=KO*DD*QC5WpU=hgJgs+yKfGOL=` zo!6^cwgZW)TlW+6s@skVGOOFq>es6~uKI~TpP6mA0we?^%&HqAcG;*KCJ!R1AE6E+fct;SOEPd0kOIgA z{HMI+A!8(3;{jPf<_2P@ePoK%Ss|h$|9Fc3L+tojIFH`%dmB^C6RP$R&XNm1w(DygIt_)TpTj0 z>nA4p71+Du<-gizcf;$Gt6D4IRI@9PtgJx@+3Xai&dzJyqpNi;ZvUB*U*G-j<$Qb@qd#IjF2qU7}k z1${u}bH(cWCLRLM5tM@MDAorA63S^g0=|iZi6jaS0agtKVYy$UOvZg3IB;^f(8PK8Px(s6O;7kA`Z1Yvun^UaXNUposq|FN2?L z&MnlKQ&#IIc+SonX10#b{%3iCUNmpaF~*iLD%OgBBo~??s>UVQ0V3_^)b^q65zVlo z{&nN12I3lF4|S+Cj$a|sj+}{ibP&$;0zML41CT!&8TAgJiN1gKX^w5RRn9 zCouo)I(|Rbt#l-#KQfje!&I0IXn)k&tR4Jdh`~ABk$%?Kk2;Lei=<|+df)zW&?j(U zJ?f>ewYALm2K#(ZEoIH-*SdQP7@75PCz$vvQwvk$r)@q4glonfeW6+8eRXzK^&LP| zUcf>3?_Xly0xe<|U@9ad>a*YTd1an*SVJyRb&-=;mk#1=rrOFhO$^}Jlki#l`5vMg zvaSa49bW&A+};8aCwQ-3Z)arK-u^9UJG|YkSk!dgt=nC_J?wrhS_ zaJw2q5~yw_SPY{8D{MrZbkB^fo1+&ld}NT0(+PMA7h@1}4Wt$L3!$a~f6hda0#RWD zKG#xx9zO1aL5#tXNVQmVXlUXW8(A-d#of640KXh+3;B5V|C zjts{LW*f0dvXT)ls!t}6;IuxGm0@I^Ipa{FA_`A}L>}|{U{o712F4vk{*1toq9QQE zwCos{nlq4?01S!^<+`{_gxycXDPJ&{zonem0uW>wYml(S>^{Dk!cVP= zyW0QRNfisWU=`+^j=P^Q3Xl3j{5NDS(Fx12Q@LJs*rWq`dboO0ce5nJXS&~j{CDVKhhe2@Q60THff(*U3ETY3>MMI`s zv_SAsQU*ei3D^mA6!PuXn~>&2Rsa;|D;=`kWM^nbLAq#|pRp(a`Ts=@kl8H7C@(`l z{*VdCR&3+cQcn3FFefbdzh_nN@96#6mn zzmWr{ePT6>o8ITv|C=0mIDgeaPU8VTFC8G)d{iGfg)%)N*4aS~4T*oj!;kv14XdVg z`MzKg#r6Ez6@PpA@8qBYIRH3@Sx*E*!rjm!_^*Nl@Pc9U7zDN(H3a}MceHlGTClIT z05_WbB*qkQY1@7&9%6?7MGgw>kWG$qTo>jpT<38nmKoef)y87e&4#Bksc^ z?Tm*gKqXfgm*!z4mZbI{a^Q!xbxa+iGd5Jnq@x55h{tP|p=IrLBREV!IBlhgRDMRb zh;vmlImrBV&v=mL<=T{==>u6U2BGt$l?2!yaMT_B1OQGwLA3r3H2+ieL;!Z2LI+t(2%B$5;bsh)5fA! zTcrTHwjbIR5?tAD^^1zy|3`CIX`T{qR7evGiVOQZ(L=HJ2iD6it*DEZGATnJO)Jom zZL{fn@r8#sf~;KwtTczItL-4y@58SH9n<068LtKrH?3ji>W7nY_iBM%ggAom=Hko` ztt&l9J>H`R2-#1k+)T2j4MRcE9rUC!{zAs+Gq1?qOC5qf&EzzGzPWL{yKWByW8K0X zrsy4fj98JPe(jh#8^aq5-LR3#Tbl|I9FK<0>h~7pWtNGb&*+E`&oZqin6~hGE<2P0 zLt;1B*C+{+xpS!O$qNG-A9|d=t(&V`fmH_uudclP1rdz5lQ&OvA|d27cy z#de!cItY)Hq|XDxG)}Xg<$^T3H+(@{WYe)?lIb%k;R7-TV=)O)^HrY-yQNFU6ML8p z80b-lNd{Hpf(A?pY}0s=J~>;I*y5Qu%Q4RO8Ao?EQi1HW#xy@wCG*Vuxv~Av!)J-^ z)whs^3oVj=kSYhRAYkwy4~*Jl-r9$L-Qjik0{mI8hVs^CjBb|RxhI8VzfZG=@(U5T zX|w~x!2(($%@Da=js?R*4+rf%*-$dLd`Bux8Mn(@&E0_^hBU{;5V>h2p*+@1#^_Av zlHA}aSVA;>G(9mFaYUemxa^OJW_X6}q5=1H((}yXTBgN}xzhQ?T#X z8*Kr%ml-$hVN~5l$+z;F95rII*qur1^|gPBhq5A+eSoaUY?l}}t8iUL19occ86O;B zy+0}(YryM;%{xM4pn9&|;xGI*b-n`)@zvrpcWN1Zz3N}yNEiEX=MV7H z&vNl*y@sw=ddxX}R#iQi4lp&QWm(qb-UrFc+$>^*Lwi&>T%@%hf>vAGh$)UQ2h5Ck z8v{={E#2s$j==1-s+bSJ0#*$t|L+@ICtFtooM+c08*4h)E%SYqi%ynn>-yw9z5RM{ z*UU~?deqyp{g}A*ZF?QcIO+kN_sKUA*-`K`FvdYC*-0g-fgO_(|0AB~Hd_V9z8p*V3cX3W!?}*SYN*3DFaUG1wh(lRHD_$7$VBQ$-8buKc1IXsO ze-FX$?_Iz2=2yG#HRN}h@^(_H-vsrc9XTD?yjp%r{6V>C`?v#qNK0rLUQql!E8~hsD8Ss z;@F;+q#S_EzA3HdKrm)TTw^WH9kH15ZT3NNQ$$&>$(a0lDWW}qqoo3fGNsTvk9dfn zS0mCt#E@M-MO!E%eE3E8q1MV8uDj5B{R_Jg@36ujbSTk~?laUH)!^r#r1USN$f{i8 zHmV-@$-S}+-d*&M9*G&ye;c@O4RRly#R|LbN`;zJ1^ukXQfF?xqV6x5H?=01s(!WN z*Lp0I8O_Wi@pk0@Qu@XwzX8vF7+P04gj3-mjcpj)znxdvpkjU$3uw=j@@_{QOp|x$ z@Y*C2>^63IMkU%7zo+rkfT~cJ9kq4O);uqcPWpIz_at!BgScAEVdu!yxM9le7A`P+ z_y&3xppL;7vh`fEdt9k+zOj?XFsawD*1u)4dkc|}lWVGB>06uXmQ!yhT` zi)wo4;e6)5d?SW|8Fzu0$6lGsGVrbXSNQbJ?lu}Uf!T*Y=}0>+jD5zAbD z{q#nml{PEowI~hV$ERms`TiD0UPc*GcjWV3!|D#l^`MznxK+5fn5L7%i`y|cG$EMa ztAIura9-Q;2a2xqqtybQ;+?5pbrRSgC&-h40-3<=W7^LRULO;bPPU=N8wsYp)f#EU;>JwFU`;6Vm9p+ zbIDZN(+9o4{D9PB`TUh%ZneN%6!&z3P<@Xm)fF=rUS{!d+sU$sxaM$m+32CqKJjU$ zf~i3RYN3%c_+Gyp$1J5PPy!ctV(57xUlAkmwSIXGLaO#4a=6i#B{3V))<*j#O9W

|awmoFh#JV~pSvb18Yv zP!rAqQ-!ROX8)#PNWNTZWD zb}CPr9XuTHXK)>0k^4*JEWrbff7H{@+O`z`FPXz9+1p16zI#az4C?uEc3u1whx|Wx z+Nhg{(nko)MLeVBzUCNFr?Ml7yKbpB!c1l*bkqd@eB4T8m#VFJ%^hinePTWF(n{ z$NEbE1{w7N(>?jV0^U;!9NG(F<>N-53+zIZ@sTP^TcN5M<\KOdo~Pgx5PdXtd~ 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 From 2544eccd6ce3df7eb053fe71b8edbff3a679f6af Mon Sep 17 00:00:00 2001 From: aouerfelli Date: Tue, 27 Jun 2017 20:28:49 -0400 Subject: [PATCH 11/11] Modified build properties --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 4aee547..f425010 100644 --- a/package.json +++ b/package.json @@ -26,17 +26,17 @@ "postinstall": "install-app-deps" }, "build": { - "directories": { - "buildResources": "./build/", - "output": "./dist/" - }, "appId": "com.aouerfelli.station-timer", "win": { "target": [ - "nsis", - "nsis-web", - "portable", - "zip" + { + "target": "nsis", + "arch": "ia32" + }, + { + "target": "portable", + "arch": "ia32" + } ] }, "mac": {