From c499106f85fa64c5f9c30d06c51035cc1f3d8501 Mon Sep 17 00:00:00 2001 From: Karishma Chadha Date: Mon, 22 Jul 2019 12:59:48 -0400 Subject: [PATCH] Revert "Raise params to the next frame when pushing" --- src/blocks/scratch3_procedures.js | 57 ++-- src/engine/block-utility.js | 6 +- src/engine/execute.js | 17 +- src/engine/runtime.js | 19 +- src/engine/sequencer.js | 20 +- src/engine/thread.js | 247 ++++++++---------- .../procedures-stop-this-script-ends.sb2 | Bin 54737 -> 0 bytes test/unit/engine_sequencer.js | 28 +- test/unit/engine_thread.js | 37 +-- 9 files changed, 163 insertions(+), 268 deletions(-) delete mode 100644 test/fixtures/execute/procedures-stop-this-script-ends.sb2 diff --git a/src/blocks/scratch3_procedures.js b/src/blocks/scratch3_procedures.js index 3eec20b64..56d3f3e7c 100644 --- a/src/blocks/scratch3_procedures.js +++ b/src/blocks/scratch3_procedures.js @@ -13,43 +13,46 @@ class Scratch3ProcedureBlocks { */ getPrimitives () { return { - // procedures_definition is the top block of a procedure but has no - // effect of its own. - procedures_definition: null, - + procedures_definition: this.definition, procedures_call: this.call, argument_reporter_string_number: this.argumentReporterStringNumber, argument_reporter_boolean: this.argumentReporterBoolean }; } + definition () { + // No-op: execute the blocks. + } + call (args, util) { - const procedureCode = args.mutation.proccode; - const paramNamesIdsAndDefaults = util.getProcedureParamNamesIdsAndDefaults(procedureCode); + if (!util.stackFrame.executed) { + const procedureCode = args.mutation.proccode; + const paramNamesIdsAndDefaults = util.getProcedureParamNamesIdsAndDefaults(procedureCode); - // If null, procedure could not be found, which can happen if custom - // block is dragged between sprites without the definition. - // Match Scratch 2.0 behavior and noop. - if (paramNamesIdsAndDefaults === null) { - return; - } - - const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; - - util.startProcedure(procedureCode); - - // Initialize params for the current stackFrame to {}, even if the procedure does - // not take any arguments. This is so that `getParam` down the line does not look - // at earlier stack frames for the values of a given parameter (#1729) - util.initParams(); - for (let i = 0; i < paramIds.length; i++) { - if (args.hasOwnProperty(paramIds[i])) { - util.pushParam(paramNames[i], args[paramIds[i]]); - } else { - util.pushParam(paramNames[i], paramDefaults[i]); + // If null, procedure could not be found, which can happen if custom + // block is dragged between sprites without the definition. + // Match Scratch 2.0 behavior and noop. + if (paramNamesIdsAndDefaults === null) { + return; } - } + const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults; + + // Initialize params for the current stackFrame to {}, even if the procedure does + // not take any arguments. This is so that `getParam` down the line does not look + // at earlier stack frames for the values of a given parameter (#1729) + util.initParams(); + for (let i = 0; i < paramIds.length; i++) { + if (args.hasOwnProperty(paramIds[i])) { + util.pushParam(paramNames[i], args[paramIds[i]]); + } else { + util.pushParam(paramNames[i], paramDefaults[i]); + } + } + + util.stackFrame.executed = true; + util.startProcedure(procedureCode); + } } argumentReporterStringNumber (args, util) { diff --git a/src/engine/block-utility.js b/src/engine/block-utility.js index d7f9ef17b..cfe18a227 100644 --- a/src/engine/block-utility.js +++ b/src/engine/block-utility.js @@ -60,7 +60,11 @@ class BlockUtility { * @type {object} */ get stackFrame () { - return this.thread.getExecutionContext(); + const frame = this.thread.peekStackFrame(); + if (frame.executionContext === null) { + frame.executionContext = {}; + } + return frame.executionContext; } /** diff --git a/src/engine/execute.js b/src/engine/execute.js index 4825ad6ab..c8638d01a 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -279,7 +279,7 @@ class BlockCached { // Assign opcode isHat and blockFunction data to avoid dynamic lookups. this._isHat = runtime.getIsHat(opcode); this._blockFunction = runtime.getOpcodeFunction(opcode); - this._definedBlockFunction = typeof this._blockFunction === 'function'; + this._definedBlockFunction = typeof this._blockFunction !== 'undefined'; // Store the current shadow value if there is a shadow value. const fieldKeys = Object.keys(fields); @@ -385,6 +385,7 @@ const execute = function (sequencer, thread) { // Current block to execute is the one on the top of the stack. const currentBlockId = thread.peekStack(); + const currentStackFrame = thread.peekStackFrame(); let blockContainer = thread.blockContainer; let blockCached = BlocksExecuteCache.getCached(blockContainer, currentBlockId, BlockCached); @@ -403,8 +404,8 @@ const execute = function (sequencer, thread) { const length = ops.length; let i = 0; - if (thread.reported !== null) { - const reported = thread.reported; + if (currentStackFrame.reported !== null) { + const reported = currentStackFrame.reported; // Reinstate all the previous values. for (; i < reported.length; i++) { const {opCached: oldOpCached, inputValue} = reported[i]; @@ -440,7 +441,7 @@ const execute = function (sequencer, thread) { } // The reporting block must exist and must be the next one in the sequence of operations. - if (thread.justReported !== null && ops[i] && ops[i].id === thread.reportingBlockId) { + if (thread.justReported !== null && ops[i] && ops[i].id === currentStackFrame.reporting) { const opCached = ops[i]; const inputValue = thread.justReported; @@ -461,8 +462,8 @@ const execute = function (sequencer, thread) { i += 1; } - thread.reportingBlockId = null; - thread.reported = null; + currentStackFrame.reporting = null; + currentStackFrame.reported = null; } for (; i < length; i++) { @@ -517,8 +518,8 @@ const execute = function (sequencer, thread) { // operation if it is promise waiting will set its parent value at // that time. thread.justReported = null; - thread.reportingBlockId = ops[i].id; - thread.reported = ops.slice(0, i).map(reportedCached => { + currentStackFrame.reporting = ops[i].id; + currentStackFrame.reported = ops.slice(0, i).map(reportedCached => { const inputName = reportedCached._parentKey; const reportedValues = reportedCached._parentValues; diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 57961940e..a3976e0e3 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -724,7 +724,7 @@ class Runtime extends EventEmitter { if (packageObject.getPrimitives) { const packagePrimitives = packageObject.getPrimitives(); for (const op in packagePrimitives) { - if (typeof packagePrimitives[op] === 'function') { + if (packagePrimitives.hasOwnProperty(op)) { this._primitives[op] = packagePrimitives[op].bind(packageObject); } @@ -1567,7 +1567,7 @@ class Runtime extends EventEmitter { isActiveThread (thread) { return ( ( - thread.stackFrame !== null && + thread.stack.length > 0 && thread.status !== Thread.STATUS_DONE) && this.threads.indexOf(thread) > -1); } @@ -1744,20 +1744,11 @@ class Runtime extends EventEmitter { // Start the thread with this top block. newThreads.push(this._pushThread(topBlockId, target)); }, optTarget); - // For compatibility with Scratch 2, edge triggered hats need to be - // processed before threads are stepped. See ScratchRuntime.as for - // original implementation. - // - // TODO: Move the execute call to sequencer. Maybe in a method call - // stepHat or stepOne. + // For compatibility with Scratch 2, edge triggered hats need to be processed before + // threads are stepped. See ScratchRuntime.as for original implementation newThreads.forEach(thread => { execute(this.sequencer, thread); - if (thread.status !== Thread.STATUS_DONE) { - thread.goToNextBlock(); - if (thread.stackFrame === null) { - this.sequencer.retireThread(thread); - } - } + thread.goToNextBlock(); }); return newThreads; } diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 00e67302f..54d4870a5 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -103,7 +103,7 @@ class Sequencer { for (let i = 0; i < threads.length; i++) { const activeThread = this.activeThread = threads[i]; // Check if the thread is done so it is not executed. - if (activeThread.stackFrame === null || + if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. stoppedThread = true; @@ -137,7 +137,7 @@ class Sequencer { } // Check if the thread completed while it just stepped to make // sure we remove it before the next iteration of all threads. - if (activeThread.stackFrame === null || + if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. stoppedThread = true; @@ -156,7 +156,7 @@ class Sequencer { let nextActiveThread = 0; for (let i = 0; i < this.runtime.threads.length; i++) { const thread = this.runtime.threads[i]; - if (thread.stackFrame !== null && + if (thread.stack.length !== 0 && thread.status !== Thread.STATUS_DONE) { this.runtime.threads[nextActiveThread] = thread; nextActiveThread++; @@ -184,7 +184,7 @@ class Sequencer { thread.popStack(); // Did the null follow a hat block? - if (thread.peekStackFrame() === null) { + if (thread.stack.length === 0) { thread.status = Thread.STATUS_DONE; return; } @@ -248,7 +248,7 @@ class Sequencer { while (!thread.peekStack()) { thread.popStack(); - if (thread.stackFrame === null) { + if (thread.stack.length === 0) { // No more stack to run! thread.status = Thread.STATUS_DONE; return; @@ -299,11 +299,7 @@ class Sequencer { currentBlockId, branchNum ); - if (isLoop) { - const stackFrame = thread.peekStackFrame(); - stackFrame.needsReset = true; - stackFrame.isLoop = true; - } + thread.peekStackFrame().isLoop = isLoop; if (branchId) { // Push branch ID to the thread's stack. thread.pushStack(branchId); @@ -365,9 +361,7 @@ class Sequencer { */ retireThread (thread) { thread.stack = []; - thread.pointer = null; - thread.stackFrames = []; - thread.stackFrame = null; + thread.stackFrame = []; thread.requestScriptGlowInFrame = false; thread.status = Thread.STATUS_DONE; } diff --git a/src/engine/thread.js b/src/engine/thread.js index 3c275d192..e381dd9bf 100644 --- a/src/engine/thread.js +++ b/src/engine/thread.js @@ -5,23 +5,14 @@ const _stackFrameFreeList = []; /** - * Default params object for stack frames outside of a procedure. - * - * StackFrame.params uses a null prototype object. It does not have Object - * methods like hasOwnProperty. With a null prototype - * `typeof params[key] !== 'undefined'` has similar behaviour to hasOwnProperty. - * @type {object} - */ -const defaultParams = Object.create(null); - -/** - * A frame used for each level of the stack. A general purpose place to store a - * bunch of execution contexts and parameters. + * A frame used for each level of the stack. A general purpose + * place to store a bunch of execution context and parameters + * @param {boolean} warpMode Whether this level of the stack is warping * @constructor * @private */ class _StackFrame { - constructor () { + constructor (warpMode) { /** * Whether this level of the stack is a loop. * @type {boolean} @@ -29,62 +20,90 @@ class _StackFrame { this.isLoop = false; /** - * Whether this level is in warp mode. Set to true by the sequencer for - * some procedures. - * - * After being set to true at the beginning of a procedure a thread - * will be in warpMode until it pops a stack frame to reveal one that - * is not in warpMode. Either this value is always false for a stack - * frame or always true after a procedure sets it. + * Whether this level is in warp mode. Is set by some legacy blocks and + * "turbo mode" * @type {boolean} */ - this.warpMode = false; + this.warpMode = warpMode; + + /** + * Reported value from just executed block. + * @type {Any} + */ + this.justReported = null; + + /** + * The active block that is waiting on a promise. + * @type {string} + */ + this.reporting = ''; + + /** + * Persists reported inputs during async block. + * @type {Object} + */ + this.reported = null; + + /** + * Name of waiting reporter. + * @type {string} + */ + this.waitingReporter = null; /** * Procedure parameters. - * - * After being set by a procedure these values do not change and they - * will be copied to deeper stack frames. * @type {Object} */ - this.params = defaultParams; + this.params = null; /** * A context passed to block implementations. * @type {Object} */ - this.executionContext = {}; - - /** - * Has this frame changed and need a reset? - * @type {boolean} - */ - this.needsReset = false; + this.executionContext = null; } /** - * Reset some properties of the frame to default values. Used to recycle. + * Reset all properties of the frame to pristine null and false states. + * Used to recycle. * @return {_StackFrame} this */ reset () { + this.isLoop = false; - this.executionContext = {}; - this.needsReset = false; + this.warpMode = false; + this.justReported = null; + this.reported = null; + this.waitingReporter = null; + this.params = null; + this.executionContext = null; return this; } /** - * Create or recycle a stack frame object. - * @param {_StackFrame} parent Parent frame to copy "immutable" values. - * @returns {_StackFrame} The clean stack frame with correct warpMode - * setting. + * Reuse an active stack frame in the stack. + * @param {?boolean} warpMode defaults to current warpMode + * @returns {_StackFrame} this */ - static create (parent) { - const stackFrame = _stackFrameFreeList.pop() || new _StackFrame(); - stackFrame.warpMode = parent.warpMode; - stackFrame.params = parent.params; - return stackFrame; + reuse (warpMode = this.warpMode) { + this.reset(); + this.warpMode = Boolean(warpMode); + return this; + } + + /** + * Create or recycle a stack frame object. + * @param {boolean} warpMode Enable warpMode on this frame. + * @returns {_StackFrame} The clean stack frame with correct warpMode setting. + */ + static create (warpMode) { + const stackFrame = _stackFrameFreeList.pop(); + if (typeof stackFrame !== 'undefined') { + stackFrame.warpMode = Boolean(warpMode); + return stackFrame; + } + return new _StackFrame(warpMode); } /** @@ -92,22 +111,12 @@ class _StackFrame { * @param {_StackFrame} stackFrame The frame to reset and recycle. */ static release (stackFrame) { - if (stackFrame !== null) { - _stackFrameFreeList.push( - stackFrame.needsReset ? stackFrame.reset() : stackFrame - ); + if (typeof stackFrame !== 'undefined') { + _stackFrameFreeList.push(stackFrame.reset()); } } } -/** - * The initial stack frame for all threads. A call to pushStack will create the - * first to be used frame for a thread. That first frame will use the initial - * values from initialStackFrame. - * @type {_StackFrame} - */ -const initialStackFrame = new _StackFrame(); - /** * A thread is a running stack context and all the metadata needed. * @param {?string} firstBlock First block to execute in the thread. @@ -128,25 +137,12 @@ class Thread { */ this.stack = []; - /** - * The "instruction" pointer the thread is currently at. This - * determines what block is executed. - * @type {string} - */ - this.pointer = null; - /** * Stack frames for the thread. Store metadata for the executing blocks. * @type {Array.<_StackFrame>} */ this.stackFrames = []; - /** - * The current stack frame that goes along with the pointer. - * @type {_StackFrame} - */ - this.stackFrame = null; - /** * Status of the thread, one of three states (below) * @type {number} @@ -190,25 +186,7 @@ class Thread { */ this.warpTimer = null; - /** - * The value just reported by a promise. - * @type {*} - */ this.justReported = null; - - /** - * The id of the block that we will report the promise resolved value - * for. - * @type {string} - */ - this.reportingBlockId = null; - - /** - * The already reported values in a sequence of blocks to restore when - * the awaited promise resolves. - * @type {Array.<*>} - */ - this.reported = null; } /** @@ -261,16 +239,12 @@ class Thread { * @param {string} blockId Block ID to push to stack. */ pushStack (blockId) { - if (this.stackFrame === null) { - this.pointer = blockId; - this.stackFrame = _StackFrame.create(initialStackFrame); - } else { - this.stack.push(this.pointer); - this.pointer = blockId; - - const parent = this.stackFrame; - this.stackFrames.push(parent); - this.stackFrame = _StackFrame.create(parent); + this.stack.push(blockId); + // Push an empty stack frame, if we need one. + // Might not, if we just popped the stack. + if (this.stack.length > this.stackFrames.length) { + const parent = this.stackFrames[this.stackFrames.length - 1]; + this.stackFrames.push(_StackFrame.create(typeof parent !== 'undefined' && parent.warpMode)); } } @@ -280,47 +254,34 @@ class Thread { * @param {string} blockId Block ID to push to stack. */ reuseStackForNextBlock (blockId) { - this.pointer = blockId; - if (this.stackFrame.needsReset) this.stackFrame.reset(); + this.stack[this.stack.length - 1] = blockId; + this.stackFrames[this.stackFrames.length - 1].reuse(); } /** - * Move the instruction pointer to the last value before this stack of - * blocks was pushed and executed. - * @return {?string} Block ID popped from the stack. + * Pop last block on the stack and its stack frame. + * @return {string} Block ID popped from the stack. */ popStack () { - const lastPointer = this.pointer; - this.pointer = this.stack.pop() || null; - _StackFrame.release(this.stackFrame); - this.stackFrame = this.stackFrames.pop() || null; - return lastPointer; + _StackFrame.release(this.stackFrames.pop()); + return this.stack.pop(); } /** - * Move the instruction pointer to the last procedure call block and resume - * execution there or to the end of this thread and stop executing this - * thread. + * Pop back down the stack frame until we hit a procedure call or the stack frame is emptied */ stopThisScript () { let blockID = this.peekStack(); while (blockID !== null) { const block = this.target.blocks.getBlock(blockID); if (typeof block !== 'undefined' && block.opcode === 'procedures_call') { - // If we do not push this null, Sequencer will not step to the - // next block and will erroneously call the procedure a second - // time. - // - // By pushing null, Sequencer will treat it as the end of a - // substack, pop the stack and step to the next block. - this.pushStack(null); break; } this.popStack(); blockID = this.peekStack(); } - if (this.stackFrame === null) { + if (this.stack.length === 0) { // Clean up! this.requestScriptGlowInFrame = false; this.status = Thread.STATUS_DONE; @@ -332,7 +293,7 @@ class Thread { * @return {?string} Block ID on top of stack. */ peekStack () { - return this.pointer; + return this.stack.length > 0 ? this.stack[this.stack.length - 1] : null; } @@ -341,7 +302,7 @@ class Thread { * @return {?object} Last stack frame stored on this thread. */ peekStackFrame () { - return this.stackFrame; + return this.stackFrames.length > 0 ? this.stackFrames[this.stackFrames.length - 1] : null; } /** @@ -349,7 +310,7 @@ class Thread { * @return {?object} Second to last stack frame stored on this thread. */ peekParentStackFrame () { - return this.stackFrames.length > 0 ? this.stackFrames[this.stackFrames.length - 1] : null; + return this.stackFrames.length > 1 ? this.stackFrames[this.stackFrames.length - 2] : null; } /** @@ -360,22 +321,14 @@ class Thread { this.justReported = typeof value === 'undefined' ? null : value; } - /** - * Return an execution context for a block to use. - * @returns {object} the execution context - */ - getExecutionContext () { - const frame = this.stackFrame; - frame.needsReset = true; - return frame.executionContext; - } - /** * Initialize procedure parameters on this stack frame. */ initParams () { - const stackFrame = this.stackFrame; - stackFrame.params = Object.create(null); + const stackFrame = this.peekStackFrame(); + if (stackFrame.params === null) { + stackFrame.params = {}; + } } /** @@ -385,7 +338,7 @@ class Thread { * @param {*} value Value to set for parameter. */ pushParam (paramName, value) { - const stackFrame = this.stackFrame; + const stackFrame = this.peekStackFrame(); stackFrame.params[paramName] = value; } @@ -395,9 +348,15 @@ class Thread { * @return {*} value Value for parameter. */ getParam (paramName) { - const stackFrame = this.stackFrame; - if (typeof stackFrame.params[paramName] !== 'undefined') { - return stackFrame.params[paramName]; + for (let i = this.stackFrames.length - 1; i >= 0; i--) { + const frame = this.stackFrames[i]; + if (frame.params === null) { + continue; + } + if (frame.params.hasOwnProperty(paramName)) { + return frame.params[paramName]; + } + return null; } return null; } @@ -417,26 +376,26 @@ class Thread { * where execution proceeds from one block to the next. */ goToNextBlock () { - const nextBlockId = this.target.blocks.getNextBlock(this.pointer); + const nextBlockId = this.target.blocks.getNextBlock(this.peekStack()); this.reuseStackForNextBlock(nextBlockId); } /** - * Attempt to determine whether a procedure call is recursive, by examining - * the stack. + * Attempt to determine whether a procedure call is recursive, + * by examining the stack. * @param {!string} procedureCode Procedure code of procedure being called. * @return {boolean} True if the call appears recursive. */ isRecursiveCall (procedureCode) { - const stackHeight = this.stack.length; - // Limit the number of stack levels that are examined for procedures. - const stackBottom = Math.max(stackHeight - 5, 0); - for (let i = stackHeight - 1; i >= stackBottom; i--) { + let callCount = 5; // Max number of enclosing procedure calls to examine. + const sp = this.stack.length - 1; + for (let i = sp - 1; i >= 0; i--) { const block = this.target.blocks.getBlock(this.stack[i]); if (block.opcode === 'procedures_call' && block.mutation.proccode === procedureCode) { return true; } + if (--callCount < 0) return false; } return false; } diff --git a/test/fixtures/execute/procedures-stop-this-script-ends.sb2 b/test/fixtures/execute/procedures-stop-this-script-ends.sb2 deleted file mode 100644 index 8bf7a0cdee5f0eacd7c975f8efcbcc5157a8f8ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54737 zcmeEu2Ut_-wsz>f_a1r+A-&L)qM(4iV*xuhRIrYH>|Mv+!3GE_2!aJ{^xi=M0qHd% zAt9mu>kFf!bDVR|z4zSmJm*&lU-nM+Uf(M3de>Ts(|jc)fVH$Ielgnz2rO$MvYyo!Mc_FC3gZVSeO7`3J{rbl;iHo&0Ojgemjl zb~X&|Q25MOsu7-&zI`m1`RQiAO!FCBd>Z30h+dQc@K)#qy2+F5M&n^rJqchc4VM@KI8 z@7+(%-w^4)%|&jlw42$sBBj7Lr$2GJ7PM7gnYq&2-+Ars`VH!wB3nTrIioD$NKe94 zJKr?9plc^)U>uUq>qTwPj>CF!*7R`C>UbTwDZTm^Ztm?fd-BDfKGC{T{h*F>E#3+II$H8?N^;rM1_N ziZ32_-*+@d|FdP=0&}-W7g%a1*H{%r zt&PEq%iLG#K4-SYImIXJV^`vi{Ze$~eD3mLm)+D5!yzxvTISxe%GnDy*9HzOud2Xb zE$Bblxom20+3p;@wG|tK8-2}_0vDGw2RE@jv{!AobTEpvZ1S8d^&YdPE#HxDd-uFt z?3oRFT35}AkH6trT&laOZ`zld@?wb-_62)b-N{}@N?Kbcvg%hGEZSr--Tfj)ah6z< z6h1ggGh1`1M@-G0&>F7!uS*iQFJ5@&l<~tbbp~=59MHegDM;#}rSz zpXv}nxqDLQg4)2iwbvZGKNM3>$+~5AS8mHnnt71E@kV&`bL_Gs<>~BQ`imu~-5EM% zY0O!#e#xa9;5~5LiP9M>jb9cfKCMYL_U&3bcWTqS9<$0r#r&e+#)gg4LyojBG%05E zDeqmhZ1c;|z!19X*}h=)EA_K4?J9m5wYE^;fG*`#qvCqKJB0tlr3y#9+{m6hssOzj4E= zW7DR1E6MAlxKo=R>q|93fO ziTNQQzTf=sC%y&Czu~#RhY}rP1|Oxu^+K{Q0UkMoO_&!pGh}7hwxG=`FiUsfm#zy5 zS-yM+e%a<78^c2I!Rv!ot-u4Kkth>3EDKq_VsoVQ-X3@(X3~TyUXMKj5B!LTbssG2 z-|Jy8=m#Mp5g)pBl?(h}x31V68XU60)r^QInqh;NyP7Qv3NyoQcQqqy+-`>5@%!&> z!OO!|yP7en=-}!V!K+q>!CQz#^mJ?RiftYt=p9%BmPy6JVKeNC4M9uSt#DWxv~2CF z%^_Phz=b!g*ak27<0aeIuX76B7_@AKtJ%iQD?(Rn-ns&Aynfw=P*=0nVPPAc938i9 z+lJpp#)oWPr1vM0@Dv&eM`z** zWacslct)f;5bzW#(SeF56DSTucw{=z@pKBwfsCgT$X4dty`15}9X&9|9z25e3Z970;K@uPT#U(Nh}JY5k%%Y2Avi%K{Y;Ey1U!RC1n~(ZD!h?Sq{Es< zrQnEgh|YANz$0ZD2~VaG;qDX?jsUMghe>o2dKX&KDHKmK2~T3e6{vUynSmq0FFI_F z2|JGsiJIfF*uV`9$<*Ov7+>GH8PW7ojf$but-DxG#-J1`!B!Dvp9S2#P1r zX`lrPg95uiTLuA{peY)ef}_HQNN|8bBjaeG6~<3DPXx6iO%ccp*bM9lj7bow5w;5| zrNYkPh9Cm$5w1xmli_tt;t%Ukco!2CK?XVL@GdId0o{@Ivpagy@J!eMjS8=2Ai=0i zv`?~VQ-5swo041{zj^J?wf4KCBEKXv@FXG~$DrZqRN68Ej^MxmV}K*!Ne)Ch?1PAu zMI@~QvoUC(P!jBqh$m6#paBL6?TJALAD}Ri50F8LOj!SP8_STVlfn5!4ukv=Zb8Nq zk@JH?k%$g(j7cDY`e-B?QXi2FR%0-c&yc93@7JMVH986!0v$vp5Qv~oGKKmx?SYq* z31m1=q!E!d7!>4_5Cq??Ls2A9zzk#pxDbjRWJogIlMH%bKyWbdOd5_t#M5X@90P?X z1^0vIzUlr)2i*{|0Z{21Adtw!i6j7ou>%gj!y;(&cZ`4)sGbRGVvzq;N+y$-NXujj zXbbtQ1CfR&Qjm}Sp=2-xXb>!n6!dlZor;k=eAV&KW8$CC@y|o}Kc=A{bT0B%@EjtE z3=T*n&>e{2yI>i3Br?C=?vG&j0XY7Q)&IaWROCK@xZsWqD!MUvF$qu??hc?TLNgHp z|Jm`EAzxv_DJlU)E&=cwT?s^F5{d9`Itk$tRH%>bSO zq{0&bc>r|qNpO2exfB|lrW2`fO$y=9&X1A+m56W&f(eifzzJRkV1xXd0T(1O;JR=> z1`|Cp!80HT7$~Ng;4&Z@dZZFW+l5y!>BvRsC@`52B_uqZ`KNI6q{0;-3DHq@BjKn> zIq(dk4MhAwgWtmChrCK!LR|7srq+L8E((G(GL8X2Oe8@hp?x6;CV|*wK&mms2JD6O z3&tbwZgA%EbpT4b776h1w^h-jyl1Zk3YN@{~hyz>@uKKrnAU+U=m1R3?f{XE=pZg5(x}W1-ypDNhTv2K_@bh z`$77E6M#*SVgX0-1jzmn=u{e6#hVfgC8seg7;JqKygG27iXE1dIY$2$GkHpo=Mz6gEpl*Fio9{{F+0KlzU6)}f#w z8i9(EBIHciHHivJrvp<#kWEKahCqdDf2n?PGx&-zB>>B1*JI=M2SEMK@^}bLJ8O(695@Ph>F4-atsb6 zA)!5GpCEzRryp8z%+7Id}22=r56pHKMb`)Tq5PbxS-w)RLmcsrH)X*V=Lp_0# zFKr$8ECo~w5K5!0LtZ7y+cX+cgh2#^4x$=~OrwK;!XrxhWIEUpWhwAI5+Eoj6>){{ zp8Rb4e!x^IBEAY9J;v!NV^;!AjKLRh5e5+zU<3*SM}=d+n;>fvaWs&F&P3osf#MFH z(SeJiT4jvvK&gP71-T-WY+z53Jm8`~_eCfn=u}kDlAtmGm!P7pfa^h!f~Cpu1mz*> zkA{X)6tEsB9c16{)_&is^Dor@AET2ftMj!JPh!hd>(nXntfifaG@-t5W z%K<+GA(`Na=zXXVqC!UhZvC$i5==`54+Fo0qE_T`Z~!VQfKXBPM_3Pz^>dyDeoh4P z1o{MrfRF(O0PluU<-7I2LP(&4AO|ux>XD3PemX!Ez&dz8uscz4N@o0-NsoaWXcBn_ z3DP#O6bLV{Jjx_rm;aQ6Ut2=ISAfukTCpr>qpO*y$@Q%;Tpt{^V)MFS_yujU-y28( zJ_w@$eE*^+1F(g>l@36{053!cfC`Uq>+j@4xBb0q^(SBaD&KaZs~H*I%w#|p57rQ~ zGzJB_XCycdG=NHjZ>nR|mY{<(0AN6Br_m7lKn|mb za0wV7SP5}mR6ap+K2d5sLI6=(oa#G(=1gzJm) zJd|H>c~MbB8Y`ON@}AIdAt64D&=W^P@jbdgb@M5rA(1_5z;= zHw5;B(m6xaLjujBK!Ag=Lgg6~Hb6j!ARbV`fht9`7QNu7yGE~uJPa=ec!kTLi+z0u z!xMUkQ261GU!RF2`};qDtehj0y=IR3&17C~;FojsR^qlog@+0z(lPh#?}%BQh#novGU48Tf2Nf#*=70jS{kuk^Y zCMp!EqPm;OgudwS#zcli#Q3Y3{>+@m5a>I@j#*aJgZteV=$;fR>>v74D9a*{6Nv+$ z3)Sn_XCmSL*0A3f1=I-?cZldenpR&S0l6*}+6^=)TOccwXi(+>(}(&At_o}p`4x&% z8WX`Jl?G`5F<0b=a265)5L;v$lz|Wz1ak8?4LcDJV4(L9f%c&;h$t060S#-Ws4yf# zO#~Z-4g^R+hMfX=A;7OOnQ%Wy_|0xVv>7Nrb=^M!;n#rui&h;dln%N^DhKu=>IVU` zK<$PqRN&hPrbS51{JALsTA_~*szCsTG=v-j5cY>Bp@{v63KJ3qGzi-TT92wE3bHk- zA3+nSR}IfVmpBRlGwKO{FWVm~7;6fPAle0uLfn2F^7PIR4Z-VTFz5#jc}V}}LmtLY zz2t9)JpaH^pt_-hLjd)lLTv@E&k*%zU|=9Bu0)g`m2==RsF?xOg!vb_4EpLokD#7| z>I~cm5DgeK9s0$P^PxCHPoTtsJUupee>8KN%Idq928%0eHzR{0A~PtpqPS33Q%EyA*d1|Zvy(G zWDm$gK}jBV4mkorBtm5-6nzkP6yO4YLkL0<=l^-Eiij)1B;cj63Dj&xrh+^H+Jg(C zhA^yAdLF|&GBhI4tr0~89E3HMf%+wA*azti(k>VP#vPzMplG1Zv3?2Tr)36={Lmx| zhCc)}t3xalI>{*RMSX%l)bLGjf3UFcas6+mlmEbRfp0>!fTMx>=wnSpSOLxg4Mmvs zwHZVEbJ+p=BtT0X5^_gq7()pP zQ41u8@wXcVX`xYq41xM1sAfXc2`Q2w>Yva+g{baEU1kELOQ1qf&;tNLYo_OHQn3UqM*1ECc`B124z*bf6J5w!N9qsV}X2Q)}wk3VJRNY#iUQK44= zA%M^q!Wue_-#-aOJQlhoQ2ZjYESgahi6Y0Qj+J#lB_S$co`V7bHNwAt7K$u_K1e`8 zQ~=gv!Sgqo9HW#-oe&4$571EnryBz{6p$bVnl3?}5e!0Z)6mS{ZNzh;e?hU98br&?4s1$G-BG5jtv&a(= zPeK3;3IHKR35Lu>gJ?8XM_7xdYc!E#K#2qwq5=Ja5FV@Z;WFSBfF5XjfJ`7FgbeNH zMnZdl2t@r0)Y3*27cwQJTQD&a5lWb^4)%946dHcP?qL*0Bad}$z)g{_(xJ*kOBA&f zG}%BCSEO7z*6UymbQ(p- zS9F1V4LhWYEJGK~&B3ak6f`-7_yZ4xjQxY~KR)}q^?yy0fnp0L0w|p!YXWFPNQ{{o zAwB9i!q^2Y3oTP*W#*rojNm26KhVoiV{$CPB2zQ{gZyqU(RbFtT|Mrmr00fK_Km}C# zI@J9awM+izM+%^Sgp2=|Mhf6RA}@lGf*%!P3^^;*e16bn7tMP_#`#7l{tm35sU<`^ zz~a}50xGBf`zH!$5CWf^0pn8s(MSPgLn8&K70^fl&<$}Z7~UcrK@0>{=zlp<0DS*r zr0}zRvFy8v0gw~4~<>+b~oCnpMU#jg_uh?H*w1!$*# z8z`U;I{kMH6i}~C1QGv30|nGr_`3rIR27K^I;i~uZjKlOd^8KBgckibS^ol+ejF$O zZ9%M?@xL-qpg~It1_~tfX(N&BB3TfV1^WBFWMAFo59;`RefFOkD1g3Djf7~`|A~PD zWOdZ`LKO^T0n}gvG6G?Z=-&6T{xepE)G6xVL-*)^YoGx27<6NhUqLB3CJuZCNHkFR zUbw$C?Drj!zdulbc^VohpalNEI8cC%qJaXUu0T*wK@06skxZh`Mtqa-o8A8P0|h8L z&_Dsz{$tDmfcbxNpa4V#4HST>qJaW%R5VaPAAu14`a`xqRPYZ53ft{BMzi5Nbm#{S z6v+60@_Tf9zJ8C6DF)wiO(PuUhFr~*oM{&BTlxsIZ|?v9BHiEnqTs*Bm*rrWW8aDU z%kPW*|1Z*g_s!CO!!OJIy)O#>y)V)gV7St9H$&?`9tX(!SAUVty|?)W?mPyAeh?%Q z@Y{m6&X_cDq6Hk7>po|~%JpGbRX8CAf6eA#FkUejj5tOWvpgs)2m`Na#!MCS5?duk z5pxx*!K}r!kA{sZj@}sw8u?}9(8#WlF!;M;Byyy6OiM(>AbK<{VU2Wh+9TRkJL|hX z^~m?i_HFA=7{rVJDtAD2yv{O1Z(|jsWIaR8@hZu3+oYn!#*LgEh~}^41oRkms6Y%~3bd=#hzsalZZyty`+T3Tvc)6?YkJ931I4;hM7a zI{RDAS{>R{I-I(0_po{o@hSzZk>#@E)cSSjn(Q!LjJ<8RN9T)rrV?KEokZd2{=xVB zvfj1btJ@=+HJbvOwl$AyyV$ADzSXx&aDHUFEK@yKf7GWN1#Sl zjFx6$t_;fY*R$7jK4{5pkgGfK*{5EjiO_zfyOUGfe`KUkj;2*^eA_b1s^9z_HqS6b zcbZnMYKYuAOsMb+H@2t0Be=EY%k$3}HT+u725JkX>oI4vf92>6g%vsqrUz|S+ugOw zGD|lxGPKoQq_IjtU5qA>=?(3?)Y{k>Scj?RRIxtheJ*P<>RQOn5-i8aDxJ}@vY3b) zkN2<}vXn9#HEh$_pe`qWdDNd@)}z&K+!SAz{mG!>Y}uQNjWy33%{yZ`YXz!e{mR9L zhisM-oQd=7sg`M`gT}`UqO}W^HiZuY8X)?#&$@ZvqtyRCpd}D7_*AcCreGOqB zcb1MTnouCfwaELmu%II6^Q|_;K1GRB8YbqO3Eqrt^znqxb|l-UHj8XNSbi}Gljrk8 zS{7EHE!$9Zq5zZMp7S(Uzvyb^lZJ`i(nF7x42|>cXH&%(+evHfOKfayhipe}rkE|& za2h?(Il1=N@}otM3VQNOa>H^r<@=XLRJ*kL@Wf=+>+Q0cO(xOx$rkoPt7z*`J4c5r zwjo9jWxctT^)2O&#p?^}3dHjZbGGGt$bVjDQ~$Z=8iuH8Yf<4iLam`hIka1^v$3|@ z>HwOx3fH}yP@;4M(mz&h>VJ(oHujgc2P70*0BrUTO zvz}m!v%inqZhy|yQl(hF> zj#8fCFW3-m*Vt#-OWB{dI;zi-t>JxXd{nk3M=f(!R!Q#Og4V*5MV+NZHLJTrq`ZwD z;jhv+(R&D2Y|5?7?Dyk$I#TQnv8R;}5BRmmeVSXSoV_(uA^T>obpGwa)1`*h2JI(D zEp_hM%27>V5~horV6)bqjUVSY7x%(^o5rS5Ot(dCdeP3Txb(1$uB?4IJMu;fH7m(Y z20|J2SgRN0V+`wZsXwOvAlWj~qcdBmHbfX{JjKwt!F` z+AzY^P{3oK;ybAm=vAaG4%rTJ#0x|_$7EXy)}L8dCoqry#X`>Rum;`yWvEFm4HM>4{wX$}b{3W_AbudNXuZxxcVPp41# z(EV=e`?hqsLSn6U?^)SZM$-1;Bm;^x>5(Iyltj;mFS7jVaLTw>?h$W%b79rE!qDu6 z8D8(T-ub>C%`_;{|1zJ?P$WM@G7L=GT&5>zPZj2gxwO1hm;Z;@nKZ|s-Q3fY2! ztR-nfZhwJ~T(2XmJQ%OHQV|AY?n{k>Am#(1M9~EbTR#hEqGsYaf<` z<}S_DNy~Yw|4uz!rC?jluAXsHPWleE>xt@ACyD|gl2A;Epe2yi9nKi(%S<$`wCjXF6C>9#UTsorxyHaX2{``;c;d7kQ>eyS+0?hGeh#z;TVYMNstrI!*%z0NFkNp!kOZnRF<3KYA; zTKa`hX_)^Yo&9F%YxCDm@3r!CtG&7|jV{o@nVz;EM?OHaqDeAWxn#L?)6O{Xjqb=^ z;i-{1Y&SEvhRh-R9NL73$7DJ55O5B`bR_(>PB5R^gx3IIHhxaB0I4zu*?%(a3 zJ3a(=LgUUzde6}>TPpLZw+H*X==FuA4e1M#PRHDin*Bs6l~!`Ct#xETb)%t=*&?e?wm~HJI14}B zsn5M<(dHX>%gFSv={Wb9SG?dud&1F2s*iLMR%Yy~(eK+S_gH6^v4YuYi$2>uH0nhD zRJ$o#+n-VlH3}>i_XmYkg~ZMQppXmzr-*SZ8KwP*7uE*x7VAA-DAGrBF1_SX_7m~ z*TB!kJqSn8(Qy_>jS*EESF&0u3oGmOPj%V=B;Gj1Y# z@)@rP%CE+9auovqE^2*R3FE`-1lO39*hMdn=O1mV92ipa)>~kljkPnU*tk=sdR(8J z10yx7dX>eiG`O*uPWMnATGbUA+OhbNyDIGxg!TI&sCjHy^{i=%i8H^yY4 z??aEZgk-$}>EnWN-R1SNB_VI0#7RXf#Kyn0E!x|bKDt(2#|VSnVybQ)Wv9l}^>LeW z%V!3|$!xPCf3TD#Y}{JDCQUby^r$_$H6b}O;Il3NqrwgSkJvqCvF6XL=aHK|Huz8Q zvm9S$zgnwW%$_&1{am#m=jh9-*yT~Ur!(HUSH`g(OPlN5HA*vfHZeDAvQKuQ`kGBi z@mfU^GYF8f?cd$Czy54d%A1iVYa)lDRbM?V-rTuVf}(ZZFxKd>5d-_)hQ{pk$(Z8f zbDe$%J4aq?@Cd7@(Xt$yMt|lOkh3Wv^_Ot9q5$`~2A>wP=lmQ&~3~Mh0f7r0M4xbsEnx$+gfTzxGt}i<~sc z4T6bX@%048OV=f-t2H-K&O)Mk`DvTSSr;dCL3M_~^MT zwWg_8iIwpVcl6d!bANpy6B`oc6Guvq`pgjIC?3_@U>IjqZtP--A;0rH<=gE&WjV>Esu$n<@m}u&sKQV}Q73-(C ze#DITv|~f{wk+vH_lNcO=f?YIZ*8s~wbj^Xpks(Nz!`N~uX0NARhrK5$)-peIm=EO zT*{4aCw@xIm=!4k$G zoWspA#l^3VM_#`@c<=Pm9slv%2S*T1iwq+X>(w8Xfi_vi0*SjS7MZ2;SMvn{B? z_wDrRoNny-4R^aR=}*?QY_eKnobH|dAs_j|paD(Rc-w9Y&g{->}N!ttEPjT;Jf zCS~963}63vTXtM~tkj5BmF_Lgo2r(YE6sN}v;CW=wR+(l-L(BA<_o2GZJqb3&!)#b zZMkdraKp>eDkZ^I6$`zcI&0JeRlW3d@yQcZXAJr!IiE4Bmb)>~$yH_rG+ijEOA(7X zec$%!`>g7=5y^?#wtB}j`&Ek74b0y?!TDKAuSX(nfCEYuFj&yl~O8%x!i8NbA9j=S3_6Jx11z8&{&Pklp0-p#~Y_xR!Nacu>= z*`D%`w0hN#$a~9hl($$1Ps|VKS-8Vjhd|W$JbJTVf@|5XP$l<1AXe(GMpWvXz4aGH znVQWyt|}9y<)jvCU7)nhlv`Rbzjpjq>;WlGe@owZ_T|Pe1&pMsd&Uvr@ukJ5`lc!y z>N=_G$~+buC%@ftp7+j0mlhrHrQ)ZkHVjwyujt#?aj7cyonegg-RIHk)84f_lT_BO z(5g^K61R|u(Tb)O&KzB2H*I1s( zRK`gRj_~B(TRr!d3(%PN#dD_Bbp@RvTfs)&^sZSSCEvHiK6|hwzNsLUeN&OGi_waZ z9UNUFzFRkzAv42#uGr)($4Cv%=qBOEewE&?dc&MA@k<^|j?u`N-{vY4qPtQjN#P+z zI8vo-jkoa4pL4-qkzT6*P$EL8Bh2L~wBIc|`07C9_y>EEO+MWjuF!Hf{H&fXnLgAk zxd1!Y!+Y+l*=IcX=1DSp`t^9pJf$AXT1HxO%=WvPPkalUxrM5uh6{C)_b~se} z)z0sp_ABG4Zo#N3&ztvwyP|DPiEpyU{Rj7?UT**VPJ(7&Zmg>|BsPAaS0cjnx!1*c z7iOOwuWx!q(ub$ox1vwjb^KHFJLgBYB91)GE==b&YT&S1x))^RhdPFSRZAgtOW1L}{zb9J*g~)P1?>41 zUMDOb%c%BW;}&s~yWMJH)2Ok6h_#Q4@=x}KXegUL(>o)>6SN4Gl!%TgQxX=I&5UPu z>uw#%?JZ>dus$i$MM&G!9HR<8U7o)fIv#}|fN5szdM-NHqJaX2Xdvzh*f45_x zinm~pb*1M`2ea;Q-sp2dBsO+qdU2bH{B5JRhFg>hpa+&9Yhx!q#b)vC*>j!m>pPF! zX1De1=vm*aUQ+OCa&%o}%d6>iz2egPr;XmLiet=$A!0b=&hZlSf17uH!V>E~xv2g| z&Qh)_>p(+yPDT8Zdt0NzKkRRRtkh}hgT1DlH?)wSEADFc+k{IC4Ch68gkhhFJz|&k zDE6-C5pQ^qvnRgk-kcbxtZ6+?s&1xsMpT9CgLM9F$qb7{K4A+b=YMveZ+vp3zB`JQ z#@o#kwj3&05^o>=<>7)1UDi7FIpz$bTG_??iyRlpZtD+zHA}(*qC6^%Loi1;JD^|H z(>JcAK5y~UJGbvXc#%fzJg2OLou*He4&=FVR3KYf93GP(s3^OZi6vhv)B`b*9A$f z5;>b6UAh_*{`7qiD^{c5?6LlQsR*tQr&>0O$ez1-b>^Zzw^KU3{l9iGd#4Bnc*mNX zvpz+qUmLyqD2>}At`TfjrROABz}4zItniw$FCcS`&myJ^PyJ=zwvG?I2M3FWs(WS> zV;;}DH0xSdvP#Q()e5V%W{(tR_21;2m!{!)b25WHmUxV_)DiUm()CO4gF*eF=8pUv z>cjN&a@TTR&*>s-MOvOQ%#@zP7waFdoI!gRP`>(NK$f$Vwxuwm$C$fK=+}>L_0QfO z`Q^f_8?CRSJI-pDTPIF;Cxtpd!I+AAy<5eEgWurmYI4t z@yzP0vr{X2Cg~d4#hWI|hZqm&gH7Z!D_X$UyPtWz80al6m*>W23VdCewi&3AU3 zHoSWH4Yl{Sew5ufthTHIf0RF>Qp4<7yk+g@06Auu`bIvb=SAO(fiJwEhP1a@x1&xU zzwY{eE7#iKgl)F5hl~NACOD%m?YbezbKTSc7JX2)x$k}VBi^Lp41QuA>$UAQixX|v zrer)Aus5SQTr{c^6Jz&rk7?A6k69tT;r6_I(gb<2UX^Zsf9iu}nx$~zjqj!EX zSDayc!RD0Oo&GOfZUZeQ*eN^LX|6jxooL%6KDoz-)jTk6)Qr2Wd~a;&>E|a3qvqDG zQ!T`G+Fn(O;9luiJhOLYBOv+n)X7iGjHD22drw%Uaw&XYs-WF!Ib!3^`>pZdOoagi6c7L7O zxIA;bTsmhHd!>vGNpf-Y=4q>6PfRoXENtwM>-j}+ePCPHm3;2Q$Wu4Z$i^$S)M#CI z7_~}JJjlDqmX<2R9}XDZ)VA8lXTT_GK)PdZ_X2_Y;G^z@VuA5+~RP&Q;rJ6l^qkv#H5&XQyrtRwy5a937$C(paWIdSTif9|`{G|PTR zJL3rPJH7M!H)t>L%wM%7L_VOB;-;X>8rOD!eO0iI*Yf4=d%HX4r_wKprB37S!p4yB zR#>^+oO)J`>{Ti?&~npn%i6|CY58$wTjRTH1*t;yPLuqFk#VP=pYe#_)Vfg5jl2No zs%qQU(=lPV%=*ln9UCjxob*jH;R;>bJUTb^Hw?=5mX)hM4LB!u!t3Ecb)(ucQWvp9 zyRzS<{Uxu&C}xWNMzKwcXY*_eFdy0%cWChChbQnpRo{9(_qRDm$Ttrb+Q^=Fd`b;4 zo;!T7oyk&C-{~o}RyOR}qD5q~%>2%QmPF31A#OjZq4ssz<$7p_{^CJzgxO+7EbfwG zF;+bWjjijlci+dIym0E-lZVX(dM9Wu#4^oh zepQFW0M7jU%xjyzY|xuN(Q?UfSX)p#kK5kg+WEZbVa%J;Cy%o4N`LfJZ70vAUNi_F zIM^P^mDWG!S08dBbaZYdZmD>Fdr9jn&IuuoJ)tu1S>gEyhZC;9&R-^N>sUm0H@6kn z=%%wbs_q=0wt7w2#lRbkU`5Fu#g@>X=lzrV9@TwLNxs^0*y@7kyV8MV8zH^fDn)1`Ty66O^mn#5<)^VT zyVgs6B;$i-Z@IEM%4<~jF@Jlz8p~c7Cg^P`&Nvocb(C>x!m~wPhfOBIcM0|=C9+?% z`(lFem5X>=o~)hgldgY{U*CGI=iY$xP;%$~oZ!1TM~sgfKe^C0Xw=G(BPywpIKgdM zLov2R3odO*S|2sp)W}SLZ+qSCKk#~RRcBpJ`#ptYjmLUp3Y((zVyG&FvueQ{POHY? zH0zvsFSm>fk@BxJjuRxbvbuT)^hS5FP8WDSXgeZt_;uu&FEjKH)5S@->RUP9t@wdE z*7EcDTOvbZ{VPopgs0kg-RlNlj`*;A3Z_5kJ%Twb6KT`1NB0G79VtNbeV==K)WA%u zw{up8Z4LQ6CC1cfu%#`g>zWWh63J32+8%lASn8p!`=rlLwcTlF$a}N{_uoCsoUJtG z28GUEKf{-4T-a~YD$~_5P(Qk=cYo2#hp&(J9W;KpzTuQ!4t*slN@F7TQ0oIB#WH5r z&5e3%j!eQE5d<6CCiXZErC>}s{Y4g$Cyw!O7{SK|+UD&}E%sg&l$%&|rW7iK?L{gdt44s?>5An9N@Vcr7F__Q2D#dFfKOCz#x-4d4n-_MM%QA=$vM!yqWNkv=Qny!H z@%-S<>D#2$}_Y-IIEH$0L&~*q_TEV8ZpBz4G(>tqaO?P0(_}jV# zg2`Qty(fn?MwhW1i_S#T&z?Kilz6mfG1ib?YoDg*!#>?k8ztHCXYC62`?#|RBeZ)mOKsJ`fL~n5I(~!K z*+Kl(!>0${wjIg+EqdEU#`{&EeeO zuO49z_jEZH=Eq1}ynab4X={hKeh_hkZM@Qrz6jP`u?v=Mlam&E&70;n(IiMRkvFZc zUhobu?nYf;=CdfmC7oNRKG^gJn!lp^J783C{hv8{GOz8YPaRkiG)Ks+(n%R!#W~3} z=}+z*s9TuMiQI7c@h!ji>|S$&aC=2F1NjWTEI&|giha4?@IwFD&Ccr#uZipPL;1`B zO#!?8V3Fg~`e;Y*JjiTRRT^#uBc--|yKaDbnc>5C?*CDgd7|k_)9-MV z>AqGmC#mH6?cWwgZYuATv9y;a)*ASY8naD>GCFr%g65xIv~qH$eTq`G(3G3TuNLm% z7B?7X)jq1Ya^yz!tGKSIdOnUdHayjNgR}eR%3ikN`lQceP0w}mGxn3N=pW=t@!s_| zwVkM3pOO|a>vHt{>3O=t6D%*1hs?LgzTl4vKBzn;6-?h5@Y%0{n5wmVG?63C4reEK zF09{IxH~!gZsx6X@jaiOOYgGW<LSb4vAtqMK`?CG!~r=Zr&fE@m}~zQZlU=T!Y23;brz3z#}c|ERxDOonr)$BezP zdt;M&sliKLgxSr;I94@T-qXIDw9PD6u19DwVyZ)RlAYVI@QbgtgOTFRzJ*<{*@nC_ z)}dOr_W=*8uCVSgb9)9G%^Zmymf}j9gT#SJO8PkNVHI`Q7qtClgs$}0I-Jd18?6(cu^e@yU2HG{HvX8FQ`DfYwRnb~RB>&GqV z2&_EvYHqmf)y9~+A0H_MI6kM#Sl*L)+h-wIua-^ApR+M2Zu%|aMI}RyQ)_HzY+pKW zWyir1azfPgW7o`+8{6+1^fG)HuEx_b49LKb?ENyoC(8b)&yogK3qL~pq4iz8;H9%_0W>QSz1(a)vH``TUyt0zEQtp zhe@&Hvl}-)UN1^YY>m+NB;6s{=z0x1a0^CHo5Xp=FSJ^aJN~%wj!~JO!(9n|n!@tl zFLmoO4nDHEk#he;_Gw|Y8G*XmK3ipru#Ue={)>b3bg4kf%zNa;s-O5#-M6_XhqejN zw@%7aekyiLKD;9}x9fxUd7QsZn(Cne8U8MrG;7<*uNNiGz2VZQpFaAEqtq8UG(1A$ zo~%w!ZMu)Sq4p@SWUqLR)l8CtnWl6Z*GzC#?G;UO?%BXcQ|ug`DXisn_RQp~kCqKO zv`@`H_eA4*?RBpgy=`Z-BM5IC{4^H`+3Yao!$r&IXStOb5JnHO$gG$B2Zk72 z<=Tq3We+Y~vwg_QuN%H#E=JsBF)UvySUGS|#li8p@0&THzSoIHnyo_@dojK1c^A01 zT5cDWKM#m#yL~34MUEr8qqkAYLTJaU=j!xK zt>2o@O1>94?_qq(#HLva7tBMgjCC`lw}}}lUNkdv8u0d>%Evtxx{dr_E2`Mz>j@-XYE&G9EG;kYYR4 z?#evz?8Ad4QMT{I+BPU1H-BZ(r8QM*7iNNDj)k4u3BRR2b7)p37V`6k0|ZC<2e`d$ zK9%9`v>(^s<-}adThuRS_}T7)*%hVBL-9jes)deod>v*{yx}8OYBPtPaGQBq!t;EC zHnZYQ&vnA(ZoN(HX~00kJPBinT)x*@BMqz;ILSnU*jnYMdp`cyyK3?B%&m8o_I^ldOPVFalKajNC)=~_bAV^m(V0A zWIw0f{TM#_BDX0;CByDC&O(2w1Zkj6;-S$vm&&QzrbIZ;G_{hOAe_)w-`Bvo-0twv zH*N9bw-Nheju%)CJ~y#+^t1j=O&Y@(QC6|Rg-?v1cEHJp7WQpmr8nLw z34UD=`SIT27ZVyv6+YQW;=7EbWc7w~B%<_JFoyi{{3~5z&9BK13eq?lTz0Qj$DQhk z%o%a3?rw;pXVLnG4Z0m)*e%vd5DOe?lq<0$c`8oto^+G^M8|FPMeicE5$7hWy@^q# zpXw3S6w#l+`P3qMY*suwytlWbxK=&) zWJ1=xy2u%6@jX+tlN<(dd-M&Zu_J65jH$F+z|`ly7wO3c*5ZYn9jr~9YIazwN5zh} zg^xbnyOTirG)?NHr2?VSJW)9xGbkRSy@OKjdtqA2`0>^(1xew0?mJ!$?{#-ktwpw4 z!jlKfAJwN@bnj3f5PZu9&plGhB|4?bUELOGMRE6H?742C<88nShYnQw~5&f8s#?7BNJ z=6Sx|p5Xbk>Giy-{R0=Z1r|xzZ5pKt%T;oWPLj5IKJ>asbF#Rs5h%kOu@T;8Uu$%% zpykrvS|sYl=e-H6SvtH%x8EWFyHazPGC`xtw3X8DetO&+!c7wmH8+_o%&mcGtk^p1 z;=uHXmkIGp6ZA4ZG+Ifv8N`@Z8;+{ADId_Pwp`EH>XGNV4S(J^T~$MR{RoEN*}k%R zU*V}tMyl%bqt91nMl_w2EH^r39d63iKB~S?yVqQUqT#m6sn9_k>!5y3>fk^MYrz-q z^6hyZ8Shg963vq6*-u*4W!tdVY)+UqX@6FKq#JGZjJDiOgBgxHW}KkrD`hyK(qmcg zTQ(tYVaDpzq2~rK%5$%_OUk`7QLuhu`cU_*cCuldts#x<+(gl^^EF9k7jal-tR}J~cI+rU*na{GdHaFK7YHJvV*%;9RTn^L29bRMStDVCb_ik#O zTxniZlAoHL^yYbDT+-oOb_ZXPWO>m37xVdgg<3NV(LaIlI01edb%WKd8;tZM5bx_~SiX6bQFXrYdR*X&q-i z=U2=wJyIf*mzc64t}x+pE}8XMGaY9`7&MpB9nPsL&_=d|FWpgD zKT!3dOuX1R^HlPa9Ljlt~sPru8IFe!MaHLb=UQiitk41oy<~rYcjFY7|Dy8o%6~PJL~@Uv=l`KCVK? zs`}q57nLl_=e~dQe0BVp)PYYFOrhyk;uqXoBfi>dH5X%bQtS8~?VC1fmqRBD!rpS(0aC<|n!roCz9WLtK z*7~;gQaQKCBS-5EKfy9lBBQ(coxHxyaZ;_FxX}fTwOSa9XsYt~3}*qp&ZtA4IFQiI zXte$KxTLM%N%rYC^3S&^Z>rK+M+i&rFPz#m{zH>AZquWl7W`OJwz( zZ=3LWMR{6bU#@ui%h%jj8rc?&ZDNW>m3BpZH1>lDUx+&!ai1@53K z+qK1@=1z$)Z+zyqH^#5T-fyn(;~1;7m=o--S==++sb6Pu1Q*Lxaa&GLvh~vE%Q_E8 zv5qvY`Pfk;$Q@3POEr5Hk+%Kg0B@p3q17upH*=N&Pj5VS3ckj9ftww*-fFe>E=eqZ zPnX@7NtL;UuXCTL&rEGh$;b|^-!!y9cb&~H+he9e{dERT<}Znzui+P(^@57Y!GQ3W2J18ZLr74!TKJ>-t`3|!9LWeRq^hy z45zNm>ht{4+4(kEkKcB^{P@PKq^nC#o?*JfmTIYC^g)ki{L1z`z1Vdcoo5@bZ!JG% za5Y=1CFK*NcrcHhwdlQWDlILj!jU~+kz}^aw#UNL__IM7_KLk9BhaOQoMmaLqb#d5 zsM1^4Qt~OW=xA4OS9av%O=gVU%y;m$4t)A*h$EAaomD6Rj-oR zFPO{P-NdQH7i`a7oo1Vwlwz0dR(E6|S2N!7wM~_&he5AFso7S%D}5C$7&pVDK)qDT zYCwf`@XO`0*?AALwxq9rd*$u6JpBf%L0K&c%lp;>te4>{qt_Pm92dd=>osUgF)C8M zAVCn+cUyi@DW9H~lDX&o)Ra%DBYC?UiK9z&f3rGktz^2zaH)~5g(Y5_DntHaTWS3N zIQr_is{t5Ndk;)Kp=k23Fcx}WsF$V`?bG{9P1UwzqaMvNuMM z9M*ndoGYq(Ojg3M)U)Y{9ls>>i5S6ThSr%~vi^-HKHvJ7U3vO_Nl{b@Qb*AZK+m>W znc_~K5x*sdXfrxtOX}BjTSrA=W~77J5=O?KW->pR227aL(Lb>A#`%= zoerrT&L>dYw8n%b%uGF)9@$Znus_1fcpLoBd{8cL>{~Otn)PvL>6xPM@3Lw;Xa}R! zZAPR{OkJ529@i_jLqbM}lC&!wbn!34yE03IZ_Gw{deg!h^QY>{K*_Aa-tT7A7Hemt zl-Sv+5gpm>Uc}9fO-)#lvL$Uq>e~b?avC!(xWY78R?#rG##xPg{Pli$VaeOoH5Scg zbY5&y$MI>Nc5~axW9P+hP43+BUCPe*!x4{}&x1Y84`g1_-uiq-KV^LQTy*x`#F{0V zZs?>qb*EJsPf|kh&tntYwr_th^?k~V_^?PBb9bq?*F&wIALTd5Y&& zzfxAxO5^rs49J|G8k1mYGa^o!G^c~Ky(tb0*AP*Ge6vXLvq@hktljwe<%cdsMa4%y z{ZdS)Es0x`(LeKlsgeXi?5env?b16OXx}$(c$krB4IH+7R2qMb{(7c1`Sbk`nMJ>f z-hZSig3znj@976J?~vy>DXu9lE9q!*kEFS6ri+V-s^C29MAf#ROTONzIq>PvQf}e@ z3RhH(mv4doianTdJZoZ_IcZHC94ARowW~_dM|T$=V!Q}N*#~KU{8~}pzjjLX?GIlH z>4jw#bm?X4_LyR_OHgYkb-NpFSH^8iP$hBWCr7;#jv-!#*4WwFGtJ-YWeAC_`B;aJ?octv8UZQJOM;wvl(@YvYXq(_ndzl7osrtUMHudBF zl1s0j7ft`XMl}VQ5dS$VBkxG|gEX=TJ}y1Z(k3_RoA@1XEKyD^a*=f+GG8O*YfW`= z>DM=5g@Y@*wDt?;M;*(UlD8vgM|yR8S=&9a8)KO82fhny z+E?@~Zg^Gvc1&%v_8kT$p3g4KJDfGKV_jlx8+%MkOl$;KkjlA0=YZrrsqL^T)YPta zbLHE&hhH6d6IVH=WxM}-xS`XQ+{`WuJJq%G#TG`ZqeBtj1#z5{j27Cc&?)yeP;Ut?{f@_*I&Ye;n39guos9WJX1vHL_xdcBBE)0~} zR>&WGQ&+WrFMG534Xt!T{TICt-5PhE{9VKGEK6Ey`yO$3qwhox7T@EZVwW;HBNr$m z+_yA^jqN{;Djii+@%q@?lhu8tYyJB~9Xljv8_8yS|E6Mzk+DfJrz5Tj?sD@uCx{L3 zw%{F0&sK4*w7kbV#hXz@2g~O-CYt2fytqy2!Y*;y%hG-AHpCu`dKP{~u#xNG{ATUN zB)}GTNM--N;bVO1ouc`LZQpmRVag)>%YvpcZUp@QdlhWC5{cpFFAF8X9w*;<;o+mr9;&QKMmZe;e+Zs6`?1r!}|0u74 zQ$fEC{pags`1Px%CaIEm|K#n9Qf~FJpGu2{E|2Y;ekx~Sm$#kXC32%3;xyqOyo21M zTo!918b%%NU@HROP1UQ)-6eJJr&Pw)KUHoEeG%jy`wUwAzkmKnWMux_0AiXPsZK%QH}peRZR=(23HOEkWnhBcv=5ZT~GCdnLGT*d6GY%>%`9Y z+hH-4!p%$_+Lv|(=o#qayTrAe}y_SFa~x|Wud(m!SXG+IjW6|p@szIN@~y)>^& z`hvv!k^6bs_%Qe|P#plh+uRSWk(z6*a3k<}Tv_FNN!f{-*V0(;bS{?Ekj2gybkE7v zb)>}8B8Ia8x#%xI0noUcMRHtfkZsc$2 z9+{Jr8q@Zcs1ZvB`h~{%LauuEMf+;qE2-e;k=k*UgUiGfXA zzUX-|XMYE0EXKb~TT5{T%QL53{0K7*BC z(mSJ7gD<+y_g5oKhK!t0Gvxn1c!qi(OpPGukoT~^ct0?bUi%Ti4=}c$a!pu`W z(7yKzIN52*&ZxPp{!lI@(%->#*r{<$HO*GnNku=%=ZBR$KddRAS!Uk~mNxOFuZXzBy8aU;CVw+&UXM@PH;ZO2$zvQ)}tA2hMP@$`PBtPp*;SWsK z<~H_r^y}G^m3bm*e)x1eDKyOU+&0{N)AHF`W8A21lwbOJwb<)wWE$DgwX6GYIcT>D|rHya?sO2e6|FC|}FMIKRTE)?C=QO!g zdic1GL-S+%^&UVJXfyY<%L{vkl=-$e^Q^DTR6FX(H;>Wg$Tl=||M>p>mXfB5Lk)}d ztD!5AzD~v6SN2~wU{TLmoq@y|f=S?O_fPvJ%M{CI$7x54>9S^x1pVf!aF@I*8CUi2 z$3asAvOH#d=aW6}4){4>e~+u_>)RG{R#OhT%IzO5`>bWoiHTw(oz&5!Mq$t&15U{-%sH+RQlZ3>y6f^S?xM~rp1&Ey_@n0K_YrsBXn>%=NCB1g^S)1Q0V_@P`;YE0`zriW8^fukF^d~D*jLIF7 zzZ(Aj?5N8A__4OG<&3omVMo<=T-)_Q@50{Sx|%x;ji>WAf}g#o>=%s_ja|)5<3vrV zqPivdd+L{}PYXYv{60eQ)b*HXZS%g9qnoGqvR?XJJk8Z+JBvYm=Qdfc>0=E)3_G=t zm3?H|Ur*}$d?~HoQuDK^L_O4}WOZ&kAtSeYR3An`{~T)Sr>ITDyihmSU~^ynU;|>< zqdBa^Wb&Wu>wkQ)e|}lFpt)493_aziCgo?R6h!sy*0VKxTrwlP8P)mU*_#Zbbbsm> z>Q<;HDtk()KabTbYW}EM@y*ft&Kw0z7i-$vx?Cza+WS*}yG$U-Cin#xduLc%b-CIs z-3CpXszf1{bo>$XZBH$uZfD~YIq3Ks#UhW8@p(+I>|Ui^FQiwu9m!>b58Pi&wVKr$ zx;9ZQSLP{xwG3^VTz{aJ@-^%yq3+<}GS0_jr0wiV?X{vOKNn7e+LSYIQzXs@2CnA1 zX18XDYPQlVTiQIJ0sQ*8=6HRN-;MgTP!V?>`PyNBeoMi+?&q^BQuarj#t#MV*$TCY zx~FD~x>;#cj+Lo?t!a4o^?042Q6p`!+y+MrX^FJX+q#YH5#RN7=UeSoiqp|c{!Ui0 zR-!&mJ|}sm{Gxc=I^f6sZ%^v}`+A#P-y@d-yB~48{jRK0`G))(Ikry4@xysNpm@(i z<0^HMrmbeQ%A_>NZ~eaA*i=8RuK3%bmJ0pgz$}(E=356K$DRMP8?#Gw$Kh?3F@ID3 zbj;AztGa4Bs}CtJDlbbbem?o$`|H@co{ev0<(4zREdJoOxoOLCiTp!(Co+>#;E0`g zMlfU@p0pEsx*D@T)lFVQ4e zi)``dTUO|jbqBOnsvOl8`GV$m4V?N-b%o#0N%k270VlIh?B`S7@xmK@YDc_H*j8E@53e=Ctoz)m{^( zz*mHp+8gwHb?bDK)#Frs6wxh;#)tKf>z04J_1mlM?U7?{F)eXs`pn#Ud4_CNr=s{< z{BYzC|07Geev`glOH&_HNo75osf`!vtH0(ny_YRD=Z8kIHbwo_{zc}{yc@Z-Sy3Gg zF-O?1p$g9#bAmD2K+~#J6O|8I+x$>}6MWrN-|%a(`lrJTj}!baj@j`+ml1jKIcGZO zwTHr~L|1Bp^Rj8VahU$R`o2mmuWRnyxV65tPWC-aBGq5@-Jl!83<*2Zx8xAH^Rp*( zDrq~1KbpMXXtEwKvJGD}3gsl_Hc9Qzf(B9j)OyR0XeG^d9_YtC8q+uBYL+v%DrZ`j zufyi(&Fs!_m1mk|g>i~LLVZNJPj2`vZi@SMvhH5}rsgY}XRev(dQnRJinK#rdgs<< zqZ$7sS;PkkHc;o>Z60L&u9YjZls~1y=Dv-=`dMGUH@uK!8a@8?j6WhaCebs3T{td}5=XHJ*T z*?l^L9jwvIxV1<(f3oeU3DI{{k5?^LJZXLNb3?<)`eENcH5=4_IDfzk_#fJMQ&wkw z&EAuBD}8ahlM&hMQ}7CJr0uoonQn-BkSbmN__wx+_C2;9Ykbw})8%@vqlbmDacfeS zXa1Spm^rsobwXO$C}s*c$=%cX(io@xN7YLylsbOBZ;byo;M>96SID$KTo;RW+DF}mQH1PZ#fS-66{Z{^UeMB0_DFgnLk!FO#3lUvRL2Sy9eDP zD37_ASl#Y=!rK@|*jn~VY!7sjnjCr+WCqK974Gi#T;pL?cS+i>lRpZZ{qpNZ*#8yf z@;5}5$1aSU9bFvOo!^F;hwY+Wgnj@6fGp~nV50A+v(g-{t&<6V|MAQ8`R-mWcb|d{I5m$NE8cA&cNCU^dVLP*X#pO8%-C+X{Efr{8|bf9i9#P$-Ok zj5jCje-UfK!$ko95^FYom-ZZT0Dl1}BnDqorUah3?xd3s>?L^o zsIb}LZZSjHz|CNF$Js~%>;kp|Ab5kS4w`*uUG)}|Zh_J%`PiBy-=r&cv`}vmm-$U$ zog>o1YlNk|2P_x90@(^L0p9}~0S5JKV1d`~s5AvMdGd_b!!4I&1-kyuctB2E;tvQ5 zg#Q&*ExbiaLxbN&M#Hnf&A={llqT@m%Xf}7Kh%tqdt1_4cgb(*quoYu6!V!NI(%{j zE4-WN34ae8Bna#?%>WV5Q}6(FX|T}Cbyk=TXmqj;t(#g|ihw@R{TMvM5D7wI!y|r& z6^KCo5Y`=h1~MET4Im0-nS6T}Fdyw{%v^_ts|$wQ-tvB`uL{5k*G6h&&TM zQuLS?!-VjmNPjp0R)al3E9HIQr6<<@!Z2GECT(r`L()#w*8JYr8(G4>A{rL4Gon{m zfiQ(zz|f#8Xt_`>*ad6`-cp_gyq+cY5k|Y}KWUd%w`7p2pV{UUBE8t%Mc2cf;Ty%5 z1amlH!~(P!J`T+Xsn8m*6O|TB^tQ8S8XHu@rCF`tC1Mq3?&p)h1glE$Fw7KY5QX># z_73_XWD9%^j0MMmL7<3~Mi1{f`$^+Vbx+v@NsIK7>ZtjrcQH&bfAN*#^I_XWjr>LI zzVs1DKT;N7ff-;c;H7jAZuPd>#U_{fwQRoRp>#M|GyKd0KyeH=@2+@#*h^6*e+Ao( z$0BbbKG+So1FQ!gQZ#{h?-V=Ll&)zj&yzA_&s4ol6Fq-{D~L_Jt>P8rlkq_U9w(dt z(e-c|m;kf~ep3yh!+|2t8~eYeN7`)VW7%>{TI$f>OFZ(UKOV(57H~~ryc9u;DL2uSRi^<#OVjH%qHn`rMI?1fxoy%E4+7saDRe%?oB4!(~z z7TiN!O8tj=mC`$u;WxYc+1;jH+966nFPPl7Ko2!5D&oH$XmfnUb@iH}Aa zK_yj2Wy)7Ehlw%mHBdqyi$F}T<94J2I+fvt3?aMJwzY)jjS&89E1b0 zfQ7(QU_Wq|+COCQjc~RG5VX`muy-?J2hRgS3X|#*)ZKjr^ez(IE})eqJ<(CzkriN2+?~`DXltB~2|fa@0R7-{ zs1vjuNDQs>p0-CDWva8XB-wVwT3wD~cc>M;$}ST)M2KjJ;3{VlqZNGsH-a5O2y#HB z&`7X7Wv5T(=xnm9o8)6;XBC+4g#BTVgEH7V1-C`fqO*b#Tq)xbHj|bPO$D`JB0L%H z3GJX(`oA~}%u_YbgNmRva98LJ z^-N%sE8UW%r7CVq<+45MFJ`NE0u;vJ^7z8#!XW}1cQ@++{V{r;Rt4RF!r_DP1?VC$ zA-KieYWYi>r^u3mvIDB+rm>!m;0*dS?sLIf;ReAUyz8tg`eJkf%>v~>GH4yV3Tgp5 zgc3X^>tDLNirvzaQbcv#IL)01Y)heGSD-$ z&hyI~KlunawRemsJyQWc7a26+5kRVJEMDh->PS7W#Y}ycLB3KT(!LDEwP#GNW zIca^SqbsIJ`blub06pw9gwCUcI-&Y3P>MXwNb(RK1o; zCHG_tHPO}`zT?m~Vm`N?|A}wlt>O%2%)l#<74TN*Unm=j0u9u$p@-fzjs|18dZp}+ zq_d2tE;hs7Z15mm#rep0^4s&DbJPqvy&Cx!?gKq0b>0hTsUt(veUZ*N=7pMWa!{%z z5m;^N>-i6uPOs*)7aSKP3U+bXq;{~et27Qg0)7r12aVLlp|QS>&c5a}O?$aOYLzyt z`kGU{+rW)P2KSwyO3;_osgbNq;uy9Pc?lnbJmhD7gSAr5JmxS6j>ke`s=mkm?rn4f#@ z0*CRboQM38!ZU(K-YoVzLXV{*L*XR&1au!f3Jj#w`yM)vnr~?8<-etve3d%WeAaUw zP~h)5BL&BVIYK)B0{c5rg6%?DU@g2Eegq8zTPPF!v96_-joN<|Ei#?lubyl!_WTQE z(w}gy2+j+6!iT)QY?P6X8<9b@4z%a+5y%NVrHt?oaM>-(bSIVR@@9FSdcA3mdoOi3 z-iy;ykSRPW_?vfty__Mz8&NZjPa6m4LC1lGltupUu0m^?zOCx4yhwgrwaA$2noa3| z&16^cX~G?Xm%I>L%@{%FVqr)Co&f8>YTyEeA2{w_YLn@Es*>duvU5tU{$B?tBt?#~ zaDKJmj9@N5lG~oOilF0{kwn@;cmj!Sd#U|`r@XTqEyh&MT*WQF)f#Q ziFZtpDC{f9;$^WNgaw<0?1Jw?10Wj^570tozPrv_=Jndq%ENN0;<~oCwXJV5^cS&) zTO@cbTqQit-@)m`e2L@eVps#wp$_0Ez!!S%zv*hQp{Yu}RgOsa$b9N}i@>)S`aw{6tpZHc zOW2WbVJ~6GF#-uff0C%P06YN1QG7mutB<*hW~ls;WT{lIEHOsAJ=DMP0UWlVLfBVW z$Y0L+%ou{FAfw>$(?UB^!p^%0E_ zPUNj*mD87@F|;SpA5a@;C)i3I5p4Cmv%S@8lu@$&())6q7PGMf7Py=-iMLKTNVG$k z#$UjGMRdaoX#YU1;6d;TP)vOtT;#2_^NqJu!)1LXu&j?-Zd&Mh23YY?oH)To;X>hV zzKuPXaTb%%u0d|_G5CRGNH0P+e7Bue(=biCe2GLZVJq7hW{^B*7pi5g za}P5KdM&aOJ_I?y31BTi)*1!0u3MJlTARE~k|!yYpVA$*PYFIn#<9NgCy73bI*4$7 z8haNp5&KD-1OI~dK`+2DfH&CR+uttH7b`bN<0ai?yEGEZTb~j#6W_Qx0bBH3IF0{; zw6jy#Npg(lUmRofQ2iz`1>y zf8dLeTF3;#B%dt>)>5MUSDgDz$?8nmf2}hm)06?jJ=c8dJFEleFF}#WD7qlbZA-6t%alPvXuE&`a_9d9G3B59+zHldVk2RmDjI(-lu`!aVFpfs{{9GhnR18w}l5pKZO7AhjBJC*5gV9 zr#&K(rxNN4QYg>7yX;@|A;o#ggw}P^*J?BQ+7yI%L|?8}FhkTOW$BRCsgm8w&c=hTwNwwLWp5K~5fzGd3ET5NvnCLOup|Vc zJ%Go<0_X$vPcru_F|X7ZWDTu(606*=JK`t`K1Xs{4E`Nqx~M>SmyG^K5;53TS}eQ- z>IQWI`%xDK^4&Wu2F(vycI!Va>!kP8nDwwP9wrzmyp=+YsG~?AsN_(Y!|@#?9}7b1 z&=pV!go4*S*KJDOU`33ixP_38RQXK*^K=KV(IdITgi+!Mu|W8Z>tc?hgJ>LWCFx@* z@OChcs_;S15yn(ioHV7CAxTww3?bKh>Sf%;nIN1j{zLqaa3}8|D?swGp|q_q0h^#t z;2Y}dK$+{H8PohLD{l>xe3y68|8SfQnb7_0r-F{+a&exh8-E`A2r(5KO-q1pKvSU= zU=39lIOl$E>8>@%#Zvb&y@+`u!OJbauQp_*(LlgzCuQhC-@iH>j^Qrv*Dz-XhR}o zCO9T!@bt5t(#=!cmway($!}_nBp=(1++l4Oj235ySw#)}2KE(#i}j)%hWbMDph1uv zkcHNG``KUWsmc$Mjjea3H`IG9<9tzYGh+!~E&3_$Bwi<2!VxgWVMl2Tp)iu63P~21 zLE4$me%UZWd0BF@Wsu~GGTzj|lLMv`y?7a-zsZw+C{S`@m>uz4qyU}*P56JafkUYq z{VSc*OqHtJQb8*qp(>pQn@daWL*LG&i7tzKh$jo*aZfSD^zX=1_zrXydIyOi4b>Q+ zyS3)=nrX7BtrJ@Z$zSS@If_HS(d+E9f>O~%QBY7tGP3dX?&x@!4mE=h$o{D>sBrL_ z`>Z8JTPd5-`m7}&eAYw$GSN2CU||~RD=yM|qD$ee;9zhViTX#WhCnaR zerpfiV|iKYo)(HULp{g>`5aJh#t2@G&?yQDuaUB!PTWLq!pA`m5Ch%GH2y%!kWX)@`c)h5Zzlsw{;_z+S2lp^D6*K6uq{0%2v_)+vp^j0vOdzyIx{}&kmGfCa>f-KNR(fK>O#+jL< zO>0|wNPfwC>32J3g!Z6879sdg^hk70*o(K3l}fiFOJFs42;2c)1;VLw1M%)=%SA0) zu~HH%87q(05%%oh73450TyR!YAnqo*#DBs*MW|3OJPY~)+Q5mRnyL?W@ZPrR^#_z6 zrDG(sWz#intS$(^m%S;-zUX~*X zlb%)1GHP56R1coRy)K+7ULh_OPUdxEiRq;X0pA7hfm=Z(@QyMsQ0JOr$<>Ok`NRvvp9CeGzZiK~1$+~=Si}>r=dBirf4ZIB`NZJ1aW>YT&_j_cvllpn8=Q4?Ojq z1c!G?xLiyVcNM1avPn-dhIS3yLUuP^4#0pb)X#t488VI6beEeXZ={n|nCY0?L_LkC za;^(Di++px2%~sAm?!ZAv>+L4t_5BK`J@!d)`>2@WrMb@qP_IEbei&;!Rj19k)vsB z13#bC#tLCJe>B@n?|~-3|9~lA4k?pSR6I!Y?6aQM;mW(xNNE_EZT-(aDwu}+V50nX zq81TPbdUdy{ebv_{slLHTyQOz1~yacgJQ3n%ssPIonVrr7!|hU4NTDXfhRtq-|w|D%6zheouXm{lz}TuM*mX zI|bLd=a@_JRmd;s1b72{0S*F7sYo!(Gr;;n_eD8Z)NNi%pI3qly`Vp@3r3R}rI zYY6WYS=l5*jF1oDf&!AqoucjuuJlf~R~l?8uWX(4vD~KVX5H=E1mzQA?oh#fAzAgy z7m*pf?$}%S5h+C@AO}L!i=k3q4`+_ap`IYer9mm8zG2GtY$h`qPdIMDKG72qTWIBK znJxG-q&*BkZ6Ogf8N5R^2cEm{Se#m|;)AqSI$F8Fkn4OI8ih`0{mCyE?h&mJmXH~c zLOOx|fM$Yu;8Son*cRv->gV;^tonhfKV&PUW|CXovVHff-~$XLH%^!#DiL1fqns2* z8tDTkkjQwQ%so8@3F>P9pH8;vx4JVa{UfqEwZfd@?Fkmqe{xKM>!KT?8-gP4FlHH^ zj%2`{p*xTQQiFBW{UrM~ncHcHDlSUXWII(ijrU!@DPytD>`(kUVSiCL=_`7%uG6DX zI;|1Pgdf5f+zXr#dg5ud%5+?14_Sq@r_!gtdXjdV5oL`E+)QF-e^vM`Y_2({#sdoIo{cXKbEAAQl}J&f~{&XpB0nh&Bj* z2_?c2@IWY)s`PuDsQIF1qN1H_xICb)HaB@rlW{nkGgeR{ghX8hJ-8*z&G>dCmSj6k z&~P%kSOc60@;#V!vTnKZx(t(FQr$AvyLM5U&_k@Ryn(_Q!m)w|Za3CUx{~x2DdZY2 zL(`xQKvJl;_q?r&%)0)RWyy*a<+?n3_dpFC!&!RPxQlb$usK&J%!51 zT-S6eLT2O2%mcKq6w_tLWWQDSj1ewH$byV#)^ZE^(*=9^6FAjmuAqg6!nx2xC;%;k zW&m@8vpt`zeEn19V%a3=Boe>h*%pv3rbiHDEex-{U^qXOTgrTkUqL3r;m}Mnlca+< zU?7y_Q`jNnZgrmg4{2w4vZl&>)Ds4jVXs&g?gIWE{wwZ0))%rj`EN2OGzT(6y=WD_JQnXa`x~Pheiurxg^nbK}p*Z*%jM56=O5j;A z%`@71gv{_PlMRrWl^-v-JRjaI*~U-Z=lUEo92hP&@9S9 z-*>yqFh;#Z-dDCq5v5D8J@w^5hv@g&Z+SZYWd2w#!D7?M^EKE_)~*?a%DSwekA%Rou1g_rxkPA9@4c4QJ8*r6thrlMz~p zw}8AQ8mA`fz2$Yv*ZRYDJTMdPLVRQUxnFrT+)M1~jOpZklp4;1m%@#3Gdu|@pg!{d z=bS^9n;ueB$$BfgX%AS^yfR=MUd#Hx?Zm&%%jCwheDsl67V-ye1x<)_MP}2cf@?x& zJU^}7^?OuL<Jg@`u5BR^`k3*AbB`zGwQ{es`!ROl$>=xQ9$FEtGjfpT12<4k z`kL*lj8*C=MT~ravO#yoX7JsG=F!!x``mfFTU-gdnXw-qh*HQnmwf+3bHgUEEtL^? z?CNJx=^9nN6@3*S)r866JR9nSd?XgIbGVndZ#hp{dg2#Wh_s`r;kUHW$PL;6sEH!* zO|=&pYSgC{6vY?S7DEq5&%iy{LnrUMxk2uH?nm|!h8^F9qR1i|g481|2#@wJKm=*7 zJ!ZMKKy_8oMU|#!+BW*efyeMTRxG!L`!BaUN6x%KpM&j2R?uG39v};m>9jNu3pKh+ zEe~}4Rlnrp6?Dxr(^Z$4G7w2(q_cyZmz-MmXXX$3RqQ76i}p8d2U38>Aa&3?O0Cyr z%QU2@$s1gGtg4$~rrqto0}1IvS!+2zIEOeFSqh>B1JHb05MEEah|EN0z}*2Xz;R`p zKWQ73pkko1SbN+O@{~{`u{359XEL`lH<$B)*`GL1{!<|g8Ht=i*P#88+t5JD81F#a zZ~Zv+PQ`sim6~qq=jt2!OuI~UW7|0+xK}w;b}lKAz33bymXt;<`T}vnbl@LP!=_8@8Kb@UPXnwA0P1S?$OmbYygSx5Uy+k;F({(}zzJaUZ|bE0mXDprxE zWN2mPlkQm*9<26!^D+G_)*0=I+(r7L*U)vyBWMq$)r;A$86ZuQ;-X@% zdb}~+SrJHti}C(UH|q_1FuR_)i$L)*vfCOArcGDvQCwGU z)%CObJvCG|`i-2eBYP_QI7`YnKx$+cG?E;(2;GV9LV7_=%4<)mEz3}$?xpl9hG-&9 z+0OF7cqkR`%9zM1V0C1bF+R}?u_zQr{4^;t5PgIkh27Ly{;tj;rrp{z%8QCLRj&Su z^}e^7%0ZVAPnb&9XO@=vl{kwhV*emRkYmVXbSlb06re8H!?VTuME^ittSD2y)Lb=% zyXFUP!qf4Sj0jdet3Qj)yiTvg#-ND^7x^1`i`Zxnp?j2|&+XV|TA+Qayrr0;nxQvY ze|ZxCF*=b5GKa9GEH$%R7|Jy8YHm zo;nIadxei+%wT4)q|5+Wr@RddAvclZNFMqp(v~&}PzN@+gOBzrG60!kqq8<(OcJr(v!z9gHrCq7fv@uCan@9+J*8qOJF1IkjTIMD(7ZB!#| z4_-&mm@F2=6fwHfcVP3-dc=(MK=#lYK!9TPU2^7Ga>@US7*rNDUEjkZa1RZ(f)~*g z`c}p~riO_yzYqre5OxzyLwV?CWD}eNbPE3AvDo~^GVN1US5=N?r6Jyq`ht{2Gyva5 zd}iDv_m<5_CYInAF&P1o>^J?xM#nmUKJ62DIj zVm@bOvyL(o8Sm&9@DJD$>=U{gkw8BwlS!`I-SSiKQU9yjrB2iDu#9t81*bwf^cmgG z=*9ZYaxuR!wi9k#fM3OiV29B$GzM4}tnmD@0jB#}u3D)Ys*N&bIRySfs-I@Z-9#2k z&3eHCSkoDF;uoHbcfikLE+h*cPaWm2ak|Vd{aDQ`^-j$yLr>dz4}&rS{*JvOjxv3$ zA?$vvAY(rfMjwJF;MXxK_CH!Puq61!onkvho?C+&)eO?-Tb{bi0Uvk`b|WWQ(_doCvL!;m>a!;)PNDb~|P*)*#ybpuTYGA!& z%_GnI4*fL#3Zvtfu(s$sIF2eM%{1q`E(FGaL(x)tIb$ztFk8YZ zX0jQt=<9GXF2vVhmys+eoWk&hJDjFgU6s0rIz_w4c+Nh_H=cTs_9w0;ikMy4-PkFt zKN;PLWjKgiv42TS`39S)eFH~b8PpsB^D>K9GrA$MYE9nG48K#mp4O z8u}c(1WU$)*i!ToJe7LIzs0%5@?F1Ib6Xv&MU4U5dGDW;3-AhTHi0tVuuhX_-J5Zp z-Va|#O1}Zi#QvsT1O5n}bt|ly#@=LgZIni&A8SF~yMs5u!DuF(%J|CM%VMzZFw%*2 zcq>+k>9HE@8AASyfKuq4WKT3j==f^#cTJi&)BhaJzC!91+IMU}p<>iCuQB^DR?sb& z6|F^u*d#27u;EII%~$UjW}dB!R@W*Gs?qw%)<*Y?keQUoL;3>7b7moP2jdG}jlD#x zkzwcp)Qa4J)5-1w2w4l5Z}5;+xwBNSwSCM*&dC80xDFYM-y}LPE0_Rt2XP!9hNYsj z&?=OTMIk}*?&H4qzCFog|NpjjO7q?L#JU7xCpzC)R3HM z7@CTVhjvlqzH&!z^97wi{hxAxdV_wXwUb91TmeO%cL^Dk#@EXYa;Pjg8WAM zAY6D4)#e}V+GV+=-=&_XoTNIb9c;EbV*-^xKGFt1M)(*PnLQaF=*#e%sDWe_N$40d za!v+~!AqVJTe-2LHc3TQ_0tS7I_(d=Cn)RTM`#>9flUu}#2a?owt8lUCP1gq0G`R1#l)Bff}odR3(46~G!>nPgdi!k zN1((t(>lg5S+hdbRXtZnw@_U#{oR0Nv^m%(`Uu7*##;iU-^C(P62VCiwHaa1Y5{R* zm4|14Y+S1iS6^2R()KgOIqcqY${#R_^`%c>SQzDu>4Y4YU?pfN8bF)TlSnm`LfzwE z=A3D{uHT}WtVXnRjcyy$s|&q?R-sw+M88&<5Hlz;Vs&)9upq z)MV*{=2qtfe=YSryaoF~U&83koXzMh2A;bBxUg2XX;B7PoQj&;TQVq?)rGG^!;`sUebe`eaNyQtZ# z-EH_}?d9GUI19*VDr`J~FsCqQFa{GgybPmZ4QPLCCaR((LRFN*zL`!MSy^49d9UfH zM=Ud(O}-}-A9Np`K;K6)i({~M?#t88t>zkgp=W6IEjb!75HVWAC`u7AbGimtgTEAVcv!IZR8qvXs&2?86H`u zxc>>{01IgIuoC)GhJk@H{PY3%7IGdL%EK0r^+$Se1!aeCr1Pe^KtElRp}DWSYj!zC z`PxyILHCh+_z_|ZV+HXiolmlgGvuj}eNfRgNDLec>4kOVHnF|e|{P10NF0kYn9&2}NkLv%l6gc1esFXBl z2;#%~5z&m##3}j?JRQ4+ZbUnfmNNoLgP%|rkW8z}7>EdQ%&ES?3?;@>yC9e4RxrGIX<89Lc`2&}|S#c3=nS z#l%14xL^29Y%TT=iTi6X7`*^5131AHl2xRc0R3exU0-iHYCrAC51t3=;UcscUqq}T zO6W3NN6s}6%faHYL^O&v02~^+?Y-i7WA0{Hs>|2MnV#E@y3+#JsZG!~q!D{U??{9Z zFnuGwo3xj;SUG9eO|)@P9Yy79cGg(N8ko9nx-*7qOSQAN&l56&ep(6km_CjeLd>DB z$1UXg2)qmVr#~@z5ncjB1$mycwj@)Io@CaBzs&0$v%Jg@0CuOnK$~!Yh$8-=AHsiP z=dozKJIR^8kug{ict7;pd(rXLyvHEZ`SjUjr@g73=%9^y8=iu`$EOgph#&MD_%Qqd zb`$H58%Z5uBO{={DP=yj^Pz=iY|?etYm9AdfP0?*9c3-F4!MhI=}U=ZVm19NKAIen zhmXQLVaE^`^op7uSm?%VQKp{yNIlQUx9)Sc_2q=V139$W=ppq9|v8C7p>B40{LE&Yvebz}6MOnYq4T^xT|XdyU=)`;5h-SoC}G5!bk4E;=^qa3x6 zqkfQelBt0np3e61=81+y`gr3Z%TY&XFCNrV>F^mO9%s;x(68W+F(-)yEhy5*Ns8S)JWH~l9B4MZ?$pe7AIHm1{Gu{^2^2i zcmwW(Q@{%xj}<%)9}!>i8`u=^ASYVQw2sjgX*1I@M)xb4KGAl)31~3WmR~7u0`G5v z)C?qRqBKIvEmgygFo`=r?+mIso%9tkDl#YSS!94x#$fGPUOV!H`hnfSUl+>Zde{M} z$}6P@?|3NAAja_}nB{;3FE*wtvm^P^^t6@HQ)OAr*P(Je$UtP?Bd*WKSGR!fp za3vg%k+_G)>`K(s>u7dRFGlFJL1|5+b<{OR)ZXXMK@*uyJQCyaO9Ynu1Sp)6x z!q#tU*XYKy)oJ6RgVb^c?QHdFN@EW3LqtisC{>ng$YHqcN@Ev zlabW4)sf|~zS}%O9n|k|z>=1Ymp@y(i`_b$j$x zT9-(JSRSpFIoJ6v7)`BXAMxA7RNPCtAl;EZ!^@UBNmFq@As@%nH~i-IIjvr-NF--u zW;CXhHM-g7y^o|EbCA0wB;#h1C*_fw$%Eyr@+wJ^62*ReBD0%R0Po<0ax)@EjzP~f zEsr(KeHomfU~MGdRh)r&s7;bH$)@xk__;}Z#y4kA10T~{^VJtoH%*K@imp_DHA*_; z{d$znw-&%n?fefb4 zv2}$7;-9zy@S=j;ME)Qhlm5Vc#oc@Xc0H=)T{9cP34c;_VYH$0P9g#{&G;S+wXU9>)eZhXKt&HW0evF)p4bZBXDNd818dZSZz}FM! z;ACmP^hqivmy^GeQ>81ovUq~KK_3m8IALR;(jvMm@;drLxumCAVXrwUNS|as@@>Qp z_%~c#S_3?JFU^!(Tvn{bw`6vZYHn4toLVDVC^9@XF@+ z5Z;5cNqYb}$RKoNw?PK5wq01?6I&k{8(A8CtNgC-w;s76vX+{{ZsTLZS9m_YgtJPm z!1`2{#zIv18`l)Im9JI$=CXSm7V|FjPHljt203XMg`<#T}Gy2SY!v{i6oKq?b`m$152cz&D*AtiU z8QAAY^3$x(+UnS|$kT`sovBtclI{22Lo$=j$Ps?9*ap{z&19(%IjiG0W#8M&4y~bX!Z!4 zQW$Nk_Aut!nP9$HOfTW$g+}63yb`~{pTSDL#C7pYAq70#OjJRCiS=IV6*~spZxo%P ze65eLp1akEOpj!L;sKDwV{uW51?eay9l^82i+o46DYe-D7L;;(tYzdyTJ6Y+SX8ZR zb^<;c=sv^n$Axe3Vf>Z!1Mskkq~kZ@PRNY*r{@MKPAQ|WQZzaYxPLO%Qj^SC&L#g1 z+RNPHHULt;3}(Z;QZ6YBcDw{$CT!!5(p$(dcbr*A4Wff1b0bc)vPv6k?bBXPbe7J- z-QvfJ>9CC}O4X!6;9*V0B}I#y&%~o5-YxU78jFsL7-^%TYm}P$ZtI3yixi@NV5jpJ zg;(Nqd=}rqxA5<{G~mZ``DJWR>X^UK9-kC!=!X?yDc=J|`o90tKBE_bry*Er^CRnHsp?~+m2=uRkj7Nz&k9e)pK%TF z4g@HBaUncQ7|Fe*TaZK-nPb(}(ZtB&$nMxxl{M=+Ct$Xi$E@eh2)g(XyI2K%SpZ&^ zB`y}Garr@pKe->w^jg8#`N(B>I`jlpG^*K`y)$GxP1sv}cCiH@JfE?LKj7226t-Xu z^&O@Wn(E!KDro&;8zaji^P?rzmpZnmdYi~Jx-+*_L09&4waGmbfH{G2ckZso^_NO~((kyl9Pq!eik_;na(6e_b7s6@Y)y;4tB3dbT* zN%>k!G)1ubwW%mGhc74g0Ujnvou%4<1zy7Ka0l@(z7Ly=D(u$-yHi`47A+qYV%5}Q z#v`i>XyEpUlo_NL4{^bWSe-1&^R#g;Iy z6qc_8N8aITpwXR#)ey&QB)k`A714()%VR0AfyyWCq8WBa2Q2-J%_UUDW274L6gf$@ zz~lJ{vDRy0I)8*&i=KHQyRTkHJrg?_d#DW23YfW_e*O&f8_b=pMHy^BcKH_Q=Fj*b z?jn8?3i2(OMQEdU%Q~)iR2wP}Vn>vC#+3@wl`q#H6bi{ut^iXO?=2XTi^zN0kV8 z_lz0VyQ-a(Y)W6{sQOvYWFPh_qik#?L6#-~#?}`wrB|U2urxv5oA8I;YE!u4CAc=S!CWU5H~3p@}}_h~_U^HZ@5p ztn^b}tE};rJ>RQ^HZu$Pq4+FNT@B9-?+Ue%Q}Hn&kt;<{4{p1et(E#^b+S@aDWTj| zqS{z0Vqr@sPANbUu7DyaOHsnFt3 zzEFDkCB7uI;&RZ$&+3dfj;L#6N_0*%J{FCY*L0)0LkBsj_H2T%4&MbVG%@@vlml{M z2{@~e#GXSdy`QWS`Xwb-Yg-puU45?_i*1ONiq%uz!5Jkd?T-FZG!5dgKg1VOlhEW46Y3@xk*eeNFpJRi*XFptK-hXD|OEv7=CgAdJQeYg5ONJL(xrJBij zZmsk#l54cb-4eIT8N!>x4?~F|L;3*tXH$MIa{^W=wz7XV7Hc`w0!l_@tI|TtYtD8K z`f*eycA-#9Y7@E`{xf_bv{ar2*w#W=rCXG~6s&h$tBEmD>!mJHS}MHSP`_o4a+8C% z)Lr(SuvY33svVviDiwMm{f&o-NBH9GW3G$)GnrrylV%?<*Xud7@6~0Bp_I_J8@231ULN!wVz#4L zm%j-Y4)+eVlnYAR#Y_Bt)}cNI{oO0p8H3h!wXu3ksjCjst{F@1uYDDbVNVF%rJbSO z;U(dJzoo>N<6ST2QZQW^oStm8b|v(m*L^hzait zO$Bs{hN$ZRm%aoJB^k}EU)(TRMt|gvh;M-Jn?rL#7v#gzJF%j$ zg)7PYf=>HQ+J z1UX#ADr3eO?etyRNbRyV%P48hc6SBy=|x;FF{6}IJ}R$}pTbPq6=q+LWthXLX>bRg z-Sx;k0?+gKRZr5d>YI&yRv)mmGTo5tCv?P*BrI2w_egJWV^~v>k2}Kjr)m?*U+R2- z+EyFsj9YrDKHrG5);W9p=2Rs%l|LwZ-{-eXcEYj=E0f_(egYCYVc& zNBZCTkGiF2Hk;Y+-9N}idNJ2bc<@h@S5P_%c~?fTxYcYukp7p)?J3L`z zfzi%rZ0@u2xm|Ch*79G6v4g}=m#fNEQ!FFfU^a^JC^=~@&b$)4a0vXFVySZDMzE*KTe zOIC5WQZSQh%y#2X3wr@E>yP{51L91f6F-=H$c&<&qs~DCFNd=Q&cUx?<~8$}1I5ZXI(v z`6(zym*Y0WDvU0W!Mh?>6L$zb_$chD%feKr7*fUy?2^_^q1;HAAtoc^24F znjOWz5jKk_@I>4V&k#?*x}uzX0^t3fs2)L6&$7#bEI-h{*9Yr04Fm8B!7qSr&^fr{ z{3PJya{L3}OO=3b1HXx@!y;NGx&5uqK3Oc(lEXnMuAJmXmPHV3##z=dFmzP|p0;WALL3ZXao{kIS zgJN~DhLDM$#J;6gkjLH#r?8b|Jk~O3V^vq}qE9e0I-Yl#ECAmyi@@W3ka?X98HO!l zMX|Tgf-ldeqX&|WUPb4Tc~)5~rV<(wC^v~)W@S_sc8QNXrqD}c2J5eG<#avQmWd{$}zbtZ~!g*a{- zO(WgAX6H2r=r`2t>R-xGwLFYNe*3LEmE5G0xf8-@JY6ave*=hE1Bm#}i<1S+Z)LWi zqQOSz2kRT-s|e#s(+|YwWCHsyRB!DT+D0kq0ko>lKuoAy{FU`SAp2*EbI#DL+d2j z-{t&hl{a2#oOVL}PMf0L)7P1moW=evWH7n-bpnGIPAqmN1HyFdm_#B|MUBt>lasC@F1ACD!4jRA2 z`_Wl%jWO36T@2bxGP_u->(sZego`< znM_YXOM}+l5T~UX9dx0pX9jDdXe89?lp z3cL9bzl}xAFzN&umkeSzNXQy}fd+&pvQ6Kshvy%H0@V-CA z$~YrvX>PH$kidUtdoydO6f(xI>E5tPnW=hB{k}fQAZCJ{+evlH_#{|^zM_vYE{yX6 zp(11*t3Z}5FRU!P&Mji|G83rFq*XA_JLD|0_5io<7*)ZpKea~M)16Q5d4CESLG7p8 zviGkQCJ~T?3cgzdBxalWHt|)ldb&r zXFI`NjSdYGT0#x}E) z)yw|YIq5F*tD)u8eC7E`gg3yP)=UGKIlz2w7Pk6YE$nB`7Oyo)pl;I^GmtCDCkh7zA6Dhn6h86``Gedwb_PSyrO~`# zgLl|DW$iN?nYyvoJZ&agqpfD3C%U%~^yDwP92?Ii@U$>SXf6EB59d?4Q7~^!W75$& zDopPA?Y(x+4eO1W&&+R5HLshkEZgefWcF_RXGscGn90em=Dy*}3R#5W!k>J0K8>5m z&1EMuh_=vCvOdV?Uvu}`@2qTA9qWwM-rjFFcG|kzy|MvD9jGPr3no8zi)+KD^85H@ zd~?1I-{_d%;cgW_#WIoWX(MDftVHq&m_JlNI&?O=6ld6&R0hMZc%|QR`46G?-iungpl) z<^Bf$u)o$n>Yw!U1|5Q3K?|~xgwPo@iJC+e1B!lhJ9+}$ldeeTqt8&OR1%eqx`>9L z=Oi0CN8XW}FoQcmdU7|&N6L_HBsV!k{w8VUYs8}h zC>tt^3ZWBdKYD@?)rxwL1nMeUga)7-=oz_1`jJ*72wn!|NF}nK+#vPQEOZoEC?i#n z3Q;oEnCeK)pjJ_%;Zq`&59rULp-4a<$X3#aFeHwA1GSDI(}+Sol0IlWI*A-~3@t$I z(OfhZ?M1`kj^CqiQE5~L`3XNRmvBlPyp_lRD^Us5d{<))eZ=Pu+(0 zE=GM(ap=JnXyxNmaO0TQmW6f_^6;86lJh=!&9-@T~-t6?ilr^@NsoM%~~F1Ds0-?-2sW zw?VCOz`;_`eh#i5Ca=gn;sJjP0uQnvhlr>as*GBrYS71gaIa!;#{~2h(B}oJvQWxE zUD;6<1P~}tABWdovXe}Ov783|*$nrypp}*3dqYuE)DB)#P;cNz7gPl(dGv_fA%~&I zi{X70IR+d!K@O0+1YI+k5W)Fng)IEj>@A-P@jZ6@*a4!g)Ae}fqE6$ z4ic0KynIdqBB7GNxz<402hD)j6f_cQ?1&npL})oeHuU@&*$s7WCOhEwZfNV@1%;SN24i!D$~R1qaXU%vwG5@M4NP{$n@v-9LKlpFBr0eMJXz(~J_|9S)} zfFBNtz$XdbLkI)U1$ZIk!nj#PgPLMQCkFBV`P&0JnD7Ys7cD~IqQi^&=T6i=zyIg+ zKNtSjTeF4?EB(*6hMaD)E|#(`O05sMi>c}V?!VPvP;g$_@(PFEJ$?~dlT@qQ z(2E!2uY*&0WgO z?zf=n9{ql&5USLyYh*~aer=ja1%@f@Q~PW@ylC_aYk%Jd8}a<_2DB~OdqdaX>*(?4 z73PAz`^tv+ou$skKAeo(S)oYtSer8Sn-pi*5)V%t`?M|H_UpgTef&FLDPeNMxb}rx zbgr-~bFL4=Qg`nzy7kzBoY(dlo4+1g^?dUS%?DJS5dYS`d1uOr_`|JF?7IECUhJ!> zrSU5I;S~-|5FwuavTH!_Q|tAN#J4_6uDiL)RP`;^*e>lC`o7fRJ+G z!_v3Y-#?4k)-76;8)R6R@qW5;I6FPYU1KcO9_x4QcrqWBIcAf76kD_1gJumWS^~jE zAi5L?)t=iOx)*^BOD{owL;r}{|9%@fd`SOZJ(Cmqj~Fue-;^L>K)LUFrk4>Gp)ci& zIR5*m1>7$&Vd&sK|4s7rOu=WTv%~HvDE~?Fz4%3*M~wXcNMh|r3`zJ3p)ch>N$TfA zsMP;OGP?NC9Z_i1m-3$^E0Yi^{eLyAdhGS;5(^RfQvQ=8&q+{Xaw-tug=r diff --git a/test/unit/engine_sequencer.js b/test/unit/engine_sequencer.js index b2cd26139..a383001fe 100644 --- a/test/unit/engine_sequencer.js +++ b/test/unit/engine_sequencer.js @@ -120,40 +120,16 @@ test('stepToBranch', t => { const r = new Runtime(); const s = new Sequencer(r); const th = generateThread(r); - - // Push substack 2 (null). s.stepToBranch(th, 2, false); t.strictEquals(th.peekStack(), null); th.popStack(); - t.strictEquals(th.peekStackFrame().isLoop, false); - // Push substack 1 (null). s.stepToBranch(th, 1, false); t.strictEquals(th.peekStack(), null); th.popStack(); - t.strictEquals(th.peekStackFrame().isLoop, false); - // Push loop substack (null). - s.stepToBranch(th, 1, true); - t.strictEquals(th.peekStack(), null); th.popStack(); - t.strictEquals(th.peekStackFrame().isLoop, true); - // isLoop resets when thread goes to next block. - th.goToNextBlock(); - t.strictEquals(th.peekStackFrame().isLoop, false); - th.popStack(); - // Push substack 1 (not null). s.stepToBranch(th, 1, false); t.notEquals(th.peekStack(), null); - th.popStack(); - t.strictEquals(th.peekStackFrame().isLoop, false); - // Push loop substack (not null). - s.stepToBranch(th, 1, true); - t.notEquals(th.peekStack(), null); - th.popStack(); - t.strictEquals(th.peekStackFrame().isLoop, true); - // isLoop resets when thread goes to next block. - th.goToNextBlock(); - t.strictEquals(th.peekStackFrame().isLoop, false); - + t.end(); }); @@ -161,7 +137,7 @@ test('retireThread', t => { const r = new Runtime(); const s = new Sequencer(r); const th = generateThread(r); - t.strictEquals(th.stack.length, 11); + t.strictEquals(th.stack.length, 12); s.retireThread(th); t.strictEquals(th.stack.length, 0); t.strictEquals(th.status, Thread.STATUS_DONE); diff --git a/test/unit/engine_thread.js b/test/unit/engine_thread.js index 047ac60f1..36206eb99 100644 --- a/test/unit/engine_thread.js +++ b/test/unit/engine_thread.js @@ -40,7 +40,7 @@ test('popStack', t => { const th = new Thread('arbitraryString'); th.pushStack('arbitraryString'); t.strictEquals(th.popStack(), 'arbitraryString'); - t.strictEquals(th.popStack(), null); + t.strictEquals(th.popStack(), undefined); t.end(); }); @@ -209,54 +209,21 @@ test('stopThisScript', t => { x: 0, y: 0 }; - const block3 = {fields: Object, - id: 'thirdString', - inputs: Object, - STEPS: Object, - block: 'fakeBlock', - name: 'STEPS', - next: null, - opcode: 'procedures_definition', - mutation: {proccode: 'fakeCode'}, - parent: null, - shadow: false, - topLevel: true, - x: 0, - y: 0 - }; rt.blocks.createBlock(block1); rt.blocks.createBlock(block2); - rt.blocks.createBlock(block3); th.target = rt; th.stopThisScript(); t.strictEquals(th.peekStack(), null); - t.strictEquals(th.peekStackFrame(), null); - th.pushStack('arbitraryString'); t.strictEquals(th.peekStack(), 'arbitraryString'); - t.notEqual(th.peekStackFrame(), null); th.stopThisScript(); t.strictEquals(th.peekStack(), null); - t.strictEquals(th.peekStackFrame(), null); - th.pushStack('arbitraryString'); th.pushStack('secondString'); th.stopThisScript(); - t.strictEquals(th.peekStack(), null); - t.same(th.stack, ['arbitraryString', 'secondString']); - t.notEqual(th.peekStackFrame(), null); - - while (th.peekStackFrame()) th.popStack(); - - th.pushStack('arbitraryString'); - th.pushStack('secondString'); - th.pushStack('thirdString'); - th.stopThisScript(); - t.strictEquals(th.peekStack(), null); - t.same(th.stack, ['arbitraryString', 'secondString']); - t.notEqual(th.peekStackFrame(), null); + t.strictEquals(th.peekStack(), 'secondString'); t.end(); });