From 58eaf2a44a035605ea9717540de8195e51eafafe Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Wed, 5 Jun 2024 13:00:00 -0400 Subject: [PATCH 01/13] adding version support --- .../src/common/extension/decorators/blocks.ts | 50 +++++++++++-------- .../common/extension/decorators/newBlocks.ts | 31 +++++++++--- .../mixins/base/scratchInfo/index.ts | 18 +++++-- .../src/common/types/framework/blocks.ts | 10 +++- extensions/src/common/types/legacy.ts | 3 ++ 5 files changed, 78 insertions(+), 34 deletions(-) diff --git a/extensions/src/common/extension/decorators/blocks.ts b/extensions/src/common/extension/decorators/blocks.ts index deb608fb9..0cafcd24c 100644 --- a/extensions/src/common/extension/decorators/blocks.ts +++ b/extensions/src/common/extension/decorators/blocks.ts @@ -1,7 +1,7 @@ import type BlockUtility from "$scratch-vm/engine/block-utility"; import { TypedClassDecorator, TypedGetterDecorator, TypedMethodDecorator, TypedSetterDecorator } from "."; import { BlockType } from "$common/types/enums"; -import { BlockMetadata, ScratchArgument, Argument, NoArgsBlock } from "$common/types"; +import { BlockMetadata, ScratchArgument, Argument, NoArgsBlock, Config } from "$common/types"; import { getImplementationName } from "../mixins/base/scratchInfo/index"; import { ExtensionInstance } from ".."; import { isFunction, isString, tryCreateBundleTimeEvent } from "$common/utils"; @@ -55,36 +55,44 @@ export const setAccessorPrefix = "__setter__"; * @returns A manipulated version of the original method that is */ + export function block< const This extends ExtensionInstance, const Args extends any[], const Return, const Fn extends (...args: Args) => Return, - const TRemoveUtil extends any[] = Args extends [...infer R extends any[], BlockUtility] ? R : Args, + const TRemoveUtil extends any[] = Args extends [...infer R extends any[], BlockUtility] ? R : Args > ( blockInfoOrGetter: (BlockMetadata<(...args: TRemoveUtil) => Return> | ((this: This, self: This) => BlockMetadata<(...args: TRemoveUtil) => Return>)) - ): TypedMethodDecorator Return> { + , versions?: Config): TypedMethodDecorator Return> { return function (this: This, target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext) { - const opcode = target.name; - const internalFuncName = getImplementationName(opcode); - // could add check for if this block is meant for scratch - context.addInitializer(function () { this.pushBlock(opcode, blockInfoOrGetter, target) }); - - const isProbableAtBundleTime = !isFunction(blockInfoOrGetter); - if (isProbableAtBundleTime) { - const { type } = blockInfoOrGetter; - blockBundleEvent?.fire({ - methodName: opcode, - args: extractArgs(blockInfoOrGetter).map(a => isString(a) ? a : a.type), - // is 'any' an issue? Likely! - returns: type === "command" ? "void" : type === "Boolean" ? "bool" : "any", - scratchType: blockInfoOrGetter.type - }); - } - - return (function () { return this[internalFuncName].call(this, ...arguments) }); + var opcode = target.name; + const internalFuncName = getImplementationName(opcode); + // could add check for if this block is meant for scratch + if (versions) { + context.addInitializer(function () { this.pushBlock(opcode, blockInfoOrGetter, target, versions) }); + } else { + context.addInitializer(function () { this.pushBlock(opcode, blockInfoOrGetter, target) }); + } + + + const isProbableAtBundleTime = !isFunction(blockInfoOrGetter); + if (isProbableAtBundleTime) { + const { type } = blockInfoOrGetter; + blockBundleEvent?.fire({ + methodName: opcode, + args: extractArgs(blockInfoOrGetter).map(a => isString(a) ? a : a.type), + // is 'any' an issue? Likely! + returns: type === "command" ? "void" : type === "Boolean" ? "bool" : "any", + scratchType: blockInfoOrGetter.type + }); + } + return (function () { return this[internalFuncName].call(this, ...arguments) }); + + + }; } diff --git a/extensions/src/common/extension/decorators/newBlocks.ts b/extensions/src/common/extension/decorators/newBlocks.ts index e4069f657..fca4c6734 100644 --- a/extensions/src/common/extension/decorators/newBlocks.ts +++ b/extensions/src/common/extension/decorators/newBlocks.ts @@ -1,15 +1,20 @@ -import { BlockMetadata, Argument, ReturnTypeByBlockType, ScratchBlockType, ToArguments } from "$common/types"; +import { BlockMetadata, Config, Argument, ReturnTypeByBlockType, ScratchBlockType, ToArguments } from "$common/types"; import { block } from "$common/extension/decorators/blocks"; import { ExtensionInstance } from ".."; import { TypedMethodDecorator } from "."; import type BlockUtilityWithID from "$scratch-vm/engine/block-utility"; +export const scratch = { + reporter: makeDecorator("reporter"), + command: makeDecorator("command"), +} + const process = (type: ScratchBlockType, strings: TemplateStringsArray, ...args: any[]) => { if (args.length === 0) return { type, text: strings[0], }; const text = (...placeholders: any[]) => strings.map((str, i) => `${str}${placeholders[i] ?? ""}`).join(""); if (args.length === 1) return { type, text, arg: args[0] }; - return { type, text, args }; + return { type, text, args }; } export function makeDecorator(type: T): TemplateEngine["execute"] { @@ -20,11 +25,26 @@ export function makeDecorator(type: T): TemplateEngi const input: any = typeof builderOrStrings == "function" ? (instance) => builderOrStrings(instance, process.bind(null, type)) : process(type, builderOrStrings, ...args); - return block(input)(target, context); + if (target.config) { + return block(input, target.config)(target, context); + } else { + return block(input)(target, context); + } + } } } +export function scratchVersions(config: Config) { + return function( + target, + context + ) { + target.config = config; + return target; + } + }; + namespace Utility { export type TaggedTemplate = (strings: TemplateStringsArray, ...args: Args) => Return; } @@ -68,7 +88,4 @@ interface TemplateEngine { } -export const scratch = { - reporter: makeDecorator("reporter"), - command: makeDecorator("command"), -} \ No newline at end of file + diff --git a/extensions/src/common/extension/mixins/base/scratchInfo/index.ts b/extensions/src/common/extension/mixins/base/scratchInfo/index.ts index d95de0f7c..b95c9952f 100644 --- a/extensions/src/common/extension/mixins/base/scratchInfo/index.ts +++ b/extensions/src/common/extension/mixins/base/scratchInfo/index.ts @@ -1,6 +1,7 @@ import { castToType } from "$common/cast"; import CustomArgumentManager from "$common/extension/mixins/configurable/customArguments/CustomArgumentManager"; import { ArgumentType, BlockType } from "$common/types/enums"; +import { Config } from "$common/types" import { BlockOperation, ValueOf, Menu, ExtensionMetadata, ExtensionBlockMetadata, ExtensionMenuMetadata, DynamicMenu, BlockMetadata, BlockUtilityWithID, } from "$common/types"; import { registerButtonCallback } from "$common/ui"; import { isString, typesafeCall, } from "$common/utils"; @@ -23,6 +24,7 @@ const nonBlockContextError = "Block method was not given a block utility, and th const checkForBlockContext = (blockUtility: BlockUtilityWithID) => isBlockUtilityWithID(blockUtility) ? void 0 : console.error(nonBlockContextError); + /** * Wraps a blocks operation so that the arguments passed from Scratch are first extracted and then passed as indices in a parameter array. * @param _this What will be bound to the 'this' context of the underlying operation @@ -70,7 +72,7 @@ export const wrapOperation = ( * @see https://www.typescriptlang.org/docs/handbook/mixins.html */ export default function (Ctor: CustomizableExtensionConstructor) { - type BlockEntry = { definition: BlockDefinition, operation: BlockOperation }; + type BlockEntry = { definition: BlockDefinition, operation: BlockOperation, versions: Config }; type BlockMap = Map; abstract class ScratchExtension extends Ctor { private readonly blockMap: BlockMap = new Map(); @@ -84,9 +86,15 @@ export default function (Ctor: CustomizableExtensionConstructor) { * @param definition * @param operation */ - pushBlock(opcode: string, definition: BlockDefinition, operation: BlockOperation) { + // add functions parameter here + pushBlock(opcode: string, definition: BlockDefinition, operation: BlockOperation, versions?: Config) { if (this.blockMap.has(opcode)) throw new Error(`Attempt to push block with opcode ${opcode}, but it was already set. This is assumed to be a mistake.`) - this.blockMap.set(opcode, { definition, operation } as BlockEntry); + if (versions) { + this.blockMap.set(opcode, { definition, operation, versions} as BlockEntry); + } else { + this.blockMap.set(opcode, { definition, operation, versions: [] } as BlockEntry); + } + } protected getInfo(): ExtensionMetadata { @@ -103,7 +111,7 @@ export default function (Ctor: CustomizableExtensionConstructor) { private convertToInfo(details: [opcode: string, entry: BlockEntry]) { const [opcode, entry] = details; - const { definition, operation } = entry; + const { definition, operation, versions } = entry; // Utilize explicit casting to appease test framework's typechecker const block = isBlockGetter(definition) @@ -119,7 +127,7 @@ export default function (Ctor: CustomizableExtensionConstructor) { const displayText = convertToDisplayText(opcode, text, args); const argumentsInfo = convertToArgumentInfo(opcode, args, menus); - const info: ExtensionBlockMetadata = { opcode, text: displayText, blockType: type, arguments: argumentsInfo }; + const info: ExtensionBlockMetadata = { opcode, text: displayText, blockType: type, arguments: argumentsInfo, versions }; if (type === BlockType.Button) { const buttonID = getButtonID(id, opcode); diff --git a/extensions/src/common/types/framework/blocks.ts b/extensions/src/common/types/framework/blocks.ts index 3dbfa3d6b..c9ec87169 100644 --- a/extensions/src/common/types/framework/blocks.ts +++ b/extensions/src/common/types/framework/blocks.ts @@ -9,8 +9,16 @@ export type ButtonBlock = () => InternalButtonKey; export type BlockMetadata< Fn extends BlockOperation, + TFunctions extends Array<(...args: any[]) => any> = [], TParameters extends any[] = Parameters extends [...infer R, BlockUtility] ? R : Parameters -> = Type> & Text & Arguments; +> = Type> & Text & Arguments & { + optionalFunctions?: TFunctions; +}; + +export type ArgTransformer = (...args: any[]) => any[]; +export type Config = { + [index: number]: ArgTransformer; +}; export type Block = BlockMetadata & Operation; diff --git a/extensions/src/common/types/legacy.ts b/extensions/src/common/types/legacy.ts index fb36aba20..05758a686 100644 --- a/extensions/src/common/types/legacy.ts +++ b/extensions/src/common/types/legacy.ts @@ -1,5 +1,6 @@ import { ArgumentType, BlockType } from "./enums"; import { ValueOf } from "./utils"; +import { Config } from "." // Type definitions for scratch-vm (extension environment) 3.0 // Project: https://github.com/LLK/scratch-vm#readme @@ -131,6 +132,8 @@ export interface ExtensionBlockMetadata { /** Map of argument placeholder to metadata about each arg. */ arguments?: Record | undefined; + + versions?: Config; } /** All the metadata needed to register an argument for an extension block. */ From ad66885d82f02332bc1c0f6bbece9479f1552bb6 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Fri, 7 Jun 2024 00:37:50 -0400 Subject: [PATCH 02/13] integration testing scripts --- .../downloads/allBlocks.sb3 | Bin 0 -> 121323 bytes .../downloads/comboBlocks.sb3 | Bin 0 -> 121352 bytes .../integration_testing/playwright_load.ts | 208 ++++++++++ .../playwright_load_old.ts | 289 +++++++++++++ .../playwright_save copy.ts | 380 ++++++++++++++++++ .../playwright_save_all.ts | 165 ++++++++ .../playwright_save_combo.ts | 349 ++++++++++++++++ extensions/integration_testing/test_fn.ts | 21 + 8 files changed, 1412 insertions(+) create mode 100644 extensions/integration_testing/downloads/allBlocks.sb3 create mode 100644 extensions/integration_testing/downloads/comboBlocks.sb3 create mode 100644 extensions/integration_testing/playwright_load.ts create mode 100644 extensions/integration_testing/playwright_load_old.ts create mode 100644 extensions/integration_testing/playwright_save copy.ts create mode 100644 extensions/integration_testing/playwright_save_all.ts create mode 100644 extensions/integration_testing/playwright_save_combo.ts create mode 100644 extensions/integration_testing/test_fn.ts diff --git a/extensions/integration_testing/downloads/allBlocks.sb3 b/extensions/integration_testing/downloads/allBlocks.sb3 new file mode 100644 index 0000000000000000000000000000000000000000..1119335785d13422fb41c1012149e8990c2b2880 GIT binary patch literal 121323 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

g6p2{5X>>!Y+{K%X9U4y3=qNr{q86o8on`0o3IK z=XoSJ*LCc*?2FB%<~8;P3-1$N)34~G>QVI}_86Os&&6>RL!q{22cx4go0vt^bJll$ z`M85u@7v?A)YxGie|H?88Y>gNJ%;Gf{D;Qh$`$kgHQ`f6dQ?3+SimfPC5KBp=rKQ|r4*J|}EZA5OiH4$sxWU{F{g%$*JpPP&LS>QJ zWDcH-m$sI$LR}%;g}TO*6Uf$TYgGnG>?V7Yy)WOF8ybxa+#rk_>U9pilcT`%!xd5EM@0ZkmLyhXfyEqyE$;2#I%19D}xih3CP9n-9u z^^oN^%U$dq)(P!|R>mr06NpI!)NAWy?O|mIju24^g_;j4rBVAG`yBc1e7DVK^)(AL z4?K-Ljr1zqt8l%-bql`lws*E1^ec*MnD$BjB+pakDQRk&x<}cm zq-*IKywB}Kb|lA9X_tbA%;1I4rBL^9_we-K^kBdpaG$15QmyfJxE-~kcEfH&<%CS} zBoFn`OY>#<)1bbdLC>SmZ~Gd04Sl8mqwmyr>u|5G3Dy{EiL^pmh|R?&i6)7@iQb8( zY*V(E&`W^3mCKSVlK!|a?%*6;SP$wgL2l(R7F(t**M{&z_`$+ZA)zPq6f!`T0>OY9 z)&}H+AmE>Hwy2lhTmKz9inYeS!=blJH>0aD8XJSz9CioP>UrRN;5W?zBA8R)LqM&pX$fk{U=YomncANn_J)r`$|Qvt`(5fV>vT3uJg#4E`UoMun6e#2*6ATN=yHzO*X@=5q4K;4b`=zNfI2BQs?hDw0(Gu^-mZVIs4 z4a+sl0%9Ry*PL2!winwx(L6ygB*Tcb*jeqQLT}#g-1i*8lI%tKFB$H+^mg}l?{V*Q ze}}e0i}EFSozu8w+ER_h7%T|z%42}9j~IuITG}_-w`d)-2;dbDosXTf9WxzKGD@B? z&zgC9uI|Nsc*2ozbnv$I{^XnPn;n=P*qXX2wN!eU^b2W!rCC!fDLcts3*85o@HoWaawD&@czbUp7zUJjqlm)9%kYqd2RAye|V zavk}galmMcb-+rP#m%4;l+JR0a971^VmiPCC6MCCSaqyAkQ>Coe$b8Ntt8Z(oTyLK zp=X^SiBc)Cq_|pLt&XL}P(%I0{EtFULzA5ooR_tWT8IfV1iZVK)=My#{0eHuYI%)3 zE;%+CW+F^|t%0`Kvd}UR@T_&zDhmF&3#5h8MtO_ez^H4Sz)#?(0lO^XF62HDI1#X? zInw5*&r81-z8glpn71FO4b1@3c!)p38k zmBb37Cg4Xin4g)ylIN2lK=Pr#&0Fcc1pC@o*vl-+A>2xC1=kIn84rjx^eQ?S55>F3 zdc>~8F2xo{mqdS#&WK)4TuuDJo#bk$wbd!eBn0mK!ammub_E-aN1+{HbZcT;ViC81 zTL(V-XnB;p2}CEYlLmd|ZvZ}V#BtcM$hpXg+Av!=stg6Sx~Bkab-=REQqEh}do1-> z>R*|cGLIKJQfOYG5hJN8=kTPkAZu`}u!wH4o-_wqje zFXMs{v4w4dLvj=V6G8001N`PEW13-+3E8cCbQ3r59U$PGz-8_#_m#EC5#vA+%J{_NdYnq~kr8H@z zI8ywF|A(JT&!wSG**1D7eN^~e5I}_r6Q#jd3zaqOLt567~g0g z>PFpAYoQujmAw$X6s?)8m8>n-lsjYHusQf_{AY89*}-UM9L5jhogEz=ol-ia^bZXR z{q23~{XqUpP6Fo}Vwh>jG-R`5v!g?>Q*d)+LnJ4h8~&W~B?W4+G0vp3h^2@n1qmRP zl}ZZK_p6+&oE%#)uHf<4r(fHBZSxiGQ2wg?sx%=Q5r2|@k}k}JZ8o=<5j2AC!}efH zk!1*+UmPQj7OP6tr9NsOb%nM<^C^C%FjttPqlswO{OWp>9+=Po*V4Y`O=~?3u!hCp8=HSedg~}BAlKv^( zo9a)U#N83Q~XW-8b3{+roXYhv6V|Ho09GO;@gMs#|^+Yp;q{AW*0Nu7-^iP{-DO= zK&glA?01*Z6G_46@Z@SKf9;9uiCEKc2m2lB%Z)aASDqvf0+*QVs5M;wvJiDyw~1q zWA@&f-C z|Au}`cZ9QS0CzofK61jno^P>w7}P58OMYntcm_ML9oSdns{#Aq5G&3Dv4`2sT&6G4 zyOX<<%@R!$*FnIZY*M17W^yxmow!~M2tna6c*jLu)=L5oIng=E8K-`Ra?Fd|5yC4 zc&WTndGm7@=AMtAkK+<1aSE&45N-;im{E+6^Kqgq%WaW1NDPgmSMJRAR_fvPany#|cG$Mt@+}3HS|Dy&Z&_(4?SvW}=RD^; zD2b8(2>%FI<5%ObKK7M+%Y*R2_z%?osNVr+JE9&_%jl)`^Tavgmg|ly3*@9MZ;tn! z<*fy3@Q%<&>O;_BsMSu|Jt_W_NvY#gvm;rNHmU7WD+enCcX)St=i27lAPx^HsR}BX z{4QoE(=y&V{wViR?&R#r*{$16N zCHIzkNn@4qN6RO zG6H+ud)?4;_pR-%ZHZ-><&+76JHfRoXk7rPd#)Z;qi)$FAH|M=T<9U@01WU5d4haE z-=dI`~d17VL@W4@?A`Xv8pz7XZ3Dx)w^Be%EF$525ndn>#b zATMkpH<6DKM~H8{-+0TXR7ioId3j>47>b2rtKzHUP@m=jd7s>F*=~V5?>oe8BJ{+& zt=-m!Sch0Ic+YvKd4KYrwV$&ehI%x5Z5`?*&m?{(R@+zG=eXy(bG%=@pM9TwNBl?q zZBp8#z}@&$u9L1Fw%)df#C_tHdCRN@aMwI`AzK5~rfP{A3AkHQ0k42pwpX&d?H)Vy z5&5cr)vGJjlq@+*hUa^axJ!h7v4awW5;^&K`D(6`8_$pD&xp;6WyiDP&yp{aW7$z` zCB7oxgm1==;zn@-FYt4l*rtFZj|DimMWRJwbbLg7b!-jD z-oM9s(B0`iVqX!?zif~<%3Fmk!YBRJ4?GG~qu_?^PhTo=u!f zR4%Aoa05h?j?;0#p_i$P)n&pjLVug7%PpHHp!di znZgWVHa&-~lB|;aMOZF;z}{nx-HqLkwl0*wi%a2h>>4z>@nPjXClq*4(I zYTrEoweB11H`bqBvs{Fq^p_2l3e`-nlfJCzFGbH5J6)_zdYkkF01OKN=Y1)>6kt!W zkI+Z>hkM0^00$`YweVN-GxFt0!IOf79@np1Z&GWJ9Ce^F1ulUT+r<=W}(^aB#vbu=3u($BR$ZwGjDIHTf zcshBSI2t=@Q*|hKcRQW@nQVc!KpV&nW$1s~llh+cNt`AgM1MnrmVo6Jb`xu*eW#t( z&*`uq`q=fvRozp~vksj13(5uM41X3Ns%!iZVUVzjU(HtsxMO2{V;uTx6w!<7pR8Z3 zdG0)SZFem-6ZHA1vL&D3rz&*hnR=QaNVIh`g{9$KL$PqDn=?s zvcoyyE#8gZKd3Vl^e%fLy^#9J{pAh-*DMj12xnq{#7g9r%sn6dE9%nhS|58qdm(^h z@8kFJ_8@<>1047z|B{awA>$@`6Ac@w#!hjE_=f+P|zC}JbTXPk;hD_C`=vDMe`bGVcK2x44k6=bJN8(50rRh?1 zmY5^9!dhZ+kP}PdW$;<@4EYuJ&wqP=IRJBQAUBckiFd>}W1P`gYAF5A9fhkd9ORsS zzz!RUjl>bsC~1wnO0KQd(cr$>0dyZ)5-Ww7Am>6KJijf)_JivOmulDS8;SMA6Z4rl z#29QO0Aa6gulCF}v=Nq;Fn#PqPoI9-{p%;08ni{gvo+jF+% zwD{EWQ~8hOKUUAHng{>hE%6rk5^^ay9Qz+&noF=w0GB}Q1be}c)FJa)*=y`ZVWUt{si;hqr^s-A65{t|!csxRM686Xr0XBgOV4fFU0VsGm{FWB z&YxsXGwa2*;x2QidERo~($3q?+a|SDD)e?g9X=WE;_Bw|8-8OVGm-gUazyeS^O`9` zm!?An!2+mJvG&XQFOOpnV=K(nrpx7U(Qd}Qj#@{(R$r<0g?a+4W7m}HN;9powp?Bz z2l)_Rm#N1zr5n*h=%Ms=z#-Oy*q=O@ypz0}?9O&&{}lcbbV-w-_w5jUunx5%s@ZGU zUwHraRs&JRQrWUvU86SS8gNC#q9TfdSD4bMkN9W&oPJuzRZ_(f5;<-^YKK0Z>wO!2 zpX{IPzZ1U`9q{%zoLRKF>@LEG`wph;Pni;$8rl@u7>TAu(>8~}JAV-&Ok+dwFYFYgOtOG354k)gPl32-ranW5TI^8s=1=*8 zyxLr4ek4DVa5r@fJ{G^H-_^G%+m!p-eXS$b0fSyQHm}9|AoMuYH@$Cqnanbo|3=@hFUt@?mP<3-&&Wsw-UHN- z4Uk4?BemLi9egM?l=?_~A~MZ%^Qd$}sv%SndI`OS|KsQ?prbn4=yO@$Y?6&9xLc9p z?oL}MuEi#4vg&4Rba} z`9}GEOst(~PjRG7Pnw?8G_Gk}ZLl{kWR@_K$qD2!z^#+e6cnDZ4&(-KSM#psO~{#$ zlNLx1q$+8O19#wy@kMw)wZGap+9;X}>b7=Un}yH8VW!_n5Zs>?RaSqsx>#U};hpiH@dM}~vZhX=5BIB@8bAe;H}^{iq;t`; zQJBxRCA>BKf%}hxeQr<(*~n;OAc$qPL))R{v5ElECt+XFEVKg{gYZ7M4cnT9`rA3| zJa&RP-aIXy5+Cx9`5EAyF2j~!lj*7Sf5ck?W_ii}L+&O2v`@1OF+$AQr1MFK(~hLwPQIBu#5c$XHAFBY58j#f#(UsCz?+vT zOO+Gh6X9n0&GH}TKF+NYsS?>}Y%&6PA)byDMW$*~v^k)bqDxWe4RH?ewp=U+OHxvl z)6svTkGMx%W3I_}T}@m#F1$9lI@lKAmMh{_alSrJj~HQNhqgnTtISbwoz$Uz`JCsR z2cAm}b`Eq-L8csJd)^6@urMR8k00Uc0_D(M+rv`{uSp;!At_! zsWzxKT3ZczqfZS?4cH6Vg5Hrn5vUvbVE<@e?Oy3_z&2pZAr%0gKBdE+#6&WIgjp7- zim6F}|3IG01lYhCuwI=EoCs{o-S+*Q!IA68g?i-(&+!+fi_$1zqyT-nyDD83n8`Ai zoyGpn{=t5|x=O7 z#$+QB-WxyU+I zjD0vUoPc>~luXG3q<#`6l47^$uTkiG1#^#0)lmOM{zamgh+$w(!rqMw$VDVda->e{ zbWySx=|CLFUVXn_SF59u;CF_-JFCO1!~X(|J~=o!XhktTQB6>Pu&P=D;9vLA+bF#I zuR&F(pz&!fn5pJ{=-m(I;Rto4+E8pDwgqFZJJFq3#w=st`VKSbUdYeoU$ySqMeDrP z5^shFu`u=zc*h6S{c1&k(}rk+w035D6Y6kbpZ#p#Y~OGG-~9a&`zNNwr^Smd-jzrv z(Y*o3KVzIX{xVmY)%5E6M?RD9ALtiID@ZM{N1Ty(Bi2|>tRO05m9g$xS1l+8#RMrq zg1KofKv=TWZ)yn4Gw9oTK|Uw%7Y~R_BTFNj3bzyv%pa8BB-kW4L7X5$A4mWb3_;-) zQ#3?FK*TIHOC3p!B<@l7DX1OV%5USVhiZflM)pUbE|#Z6%Eh>t1J*(7mH1jb%b(_D zMN?j3FR_01zV<%ue(o~PvQCZ-vD4V;Y#+dXiaSd>&-zaL(v#AYdZzYCy##7d(!ivD zd?$R59nTz%=|*%2kKmt(OyUo6B>4;S3(`mGCEW&lGUWID0KbZ-;;E+gX7DWaND z&48ZLaG%Lw)7Z84wf6sr{|KM%)1k**rtn!fBc2u|iI@DKAf|W`eIA8}6ZO@)>N<0c zImw!8!OXpiN;w7UVBcFGt##-c^pbhmJfQ4T<_n7jsLhA{EB_Jih#A;S?5uu9zbW66 zSF3B(E$C)+IlG*NnX{00+#s$K$zYFdh&9F}TA=H=>bhomXL+l5D|_d9=6j}kr+I&j z`7!3Y`>K07crp{wN$3Q9qW*(cMT0t5s39l_6@*F_mMTmQrUw6%W=Syf<|ciehJGK# z%wi_g(nC+=jn)S1FnSCP4 zbpZ7l`;1*juc9)hV30RYw@^i= zsSnjJN|v(4++;dQH#rZiBW>t5^geVCN~omTf$zw_2)_tJ-Pl@CH6uSp^r#+vF1!$+ zhY;)yIA$HUU@ipo-wUt>>;(G+`*>;+)!b}u`b3|2k-NyjUhX;OY_lQS5dFcbX2D)d zMOD;PBh46&55teKM_Jh}+M##Q9rO-ecX(9%eVA zs}YODA^nKH#8dnU-plB1Kre=)pq_#C#UprxK%gKnEoXX8-`w80%Yw^-cF7^t2iyam zCp-tdRxP(O&3SVXTk?z6NCdmQ^f}5olsGH!_)z z%m8`-z0TNR)D&xoLBOSYgLj_m&UZsCNH?S_avO~0SHf$dgVsTdSeymVx(-T*CD`XT zO`0wZHijBKke-NBV>L)Tu^=8i9r-8HL+_dWwPY=M3i$k$W6HRV-xv5-Es33IZx^ers zz1%_Z;CD^=Aa#g3S{tjK(@twJ%c{NA)@oz5vsxO>jOI#91$yiviY4!`cETf3q>@q5 zI4zx&Qn^$v5DtcYQjByC?14}t2G2v6p-a##^P3rq#-ShSOnSI$sH>f$y#xL^^ss0X zX&Zt5iK_v}sgE{5^Q=4z>e|OhW2B|(a&rV3Mp-=ia= za{*6$25NS6cJzJZePn!SVrYG6ZRn54s7Sov7X*b<;8{vLxvi{-is)2a%02y_Uel^! zK~J6+!b<^Wr9TZn4yOvKLOrdaR-otUp8*EAC*PM3%SYsO`Wl@iX)OUP6AtP0wvl5hk61c@JJa zM$Zv)1=s-eI`>WPr*EIWEiPD6a85g;LA_{8M=Qq?Vli=4JFaz6x+uSZc|Qa2*ge>8 zEJaJx#_?l$B8o=$fth)y&9a73FW!Xsw z$#_Zc82>o`^_Uwm1$Z8QUAQ4M=bCe!w4b$=_(~k=;f`BJtqtOO5puel;%yOXaSt&^ zm_AG|W;fUueX3WT4S3lJfe}wn!|QKqZJtLelHB*J+E3EG=?3{Z9Iq_|Ne} zY(s6=!T5*ShkXIIxFKDa?uPG%`{wk?nf_(QmrL1~vSB7Y^sVlR_CQCOW6joTOMsLU zRhYvK&&{C5HbO=pJ4 zw80t&0f#!}KJ6Brl5+>OgIZ<%W!ZIBe{H@tS&E@LyE?lZagMlK3AYl`{ptRwC+c}@ ze{65SHe`cjkjz9sp=$wNf!=wa_$jr!sZWy{zN-8ap zJi&hvvV^_T-tV}@&e^!Sp$4I?!Og+-p>?5^p%oz{hy|XQ~ z;NcM0U5{Ri4$%5(CCO6cJKKLY2H>x6);CK~gzve=y}-T|PxuL*j?&O)riazj+HLGH zRwJvCqu{w+b6s_fagTNv+5`3qOhx7`^_E&rFQm#zmPwZ7>&^pB22u~-f15qA0n@UFM?V8H$DdOBJG&=Oc5%B8fA<& z=8N;hc0vcCJix{!VLlyl4T< z(SkS?P+sO=_5wSZnarFc&ypg>V~^1%=x%H;_J(*#G+~-DaGoEIJr-LhxlVHBv`T69 zlIkVZ_tf{mJj0*NPA0r#fIanVthE-Q;L6s}w$RIhmj$mQuOsEma^`dD3H2{|iCm?x z(8mbl1efR$;XEjdmPLO=Y9fV7p<)wk!YBR{zggTQt_17PM1B%~KYTw7HU4YDYr=ns zqr@UwF)h_dF`&;c%*N_#^|4-&uSlr7yh+?7HfkHSr_ra;o7^>SraD`_f?dWok(7rq5GQ2I@}j91pl>#)M){I{$HYq&iU*(TeDPQ0r|QY>#6f#=cH^ zowPe;cgj!6KPMOU7xOpqHT0GCl=iso9=jWN;qZLDkJML!8J{D#q1@2$@bE8@pCfaH zc|tLxsKH|b2D2SsYp=CL@N7m|qb=wKx}I1^3_=DW)6{8dJFqX626a=qAypPDi6^;J zTxujG(l^>C3ia#1nqABSJb)J`i;{~027zY;8CV+jjmcr+9r2F;(SOrnBV-&F4~u_^ ztHg8Wc@yRzPogK$W6?3_ullcghL*0u%;;)(HT+ldR}w%f^r(7FJqUPt8>x+S7NDfF z_!)dXz}9Y`%Lg_3VuF}3$v?rL9+MH%($?DcANmHJs!h|j0c2PX)LL7L&eY6H&4WP7# zJk+k<0yRzeQ<%a};Y)}m#2RW1b(i_K*$!=sZnQR9u%~z_sLE&+)Im518e_2kw71`V zg4XhD`IcG>Z8SCtTZ6B~=bCfP1IhuVl2S$KW%ah^(F==bmX@GN7Kr5lp zYpA}XzT=ALvZq)~(U{BLtKJGR6=FVvYU^$5J#0T@58+`PdPxt|25KGE4(d(uhUkmL zM%ov)FC+_z!pG5P(F@i&t0mo%-b3yow*d~93Gm(nP`%9V=4f;rI^UXSbpiPPj(AtB zFV+>eirYn~^{N6eIlKe@s%Pm0N}!O}P6bsQloNA4h{= z952G2>Xw1#fi?wg3-*Tgg#vO=&ceQ8_vkzHPsC3|tPyKWR3<9F=$-Y;*cI#<{gfWd zjAaa5$JgoW^#Y*~@assVTBu5>WUy2)HJlu-9IXk%;EY9| zwV$>B0{C%jq7_lqtZKF~+8SBN7X)DtX0&&-cXq<8gz|~y689$TO{nCr>>uG7?m0uB zp*tg8kWK0))h)Z^v7nxd&qXwfMUjXZhHET5tA}T`Bwxis~`9`mu_L&2l0M_F5Qx9856=1FtNxnvQxC_5FMj5d>7 z$ShcU4`GL~)y}ofI<8tS*jMsGd8t$d@A0$zNnUSmG~b)=%w5VZr5nH;Z-sY&1J%`z zTF0!l##-Yx;0S|4gF_8N^+MmIY^f&xBmRZ@LbWhknXn%>ArK#cexoom?gyeOG25JJ zKH;8ny9#y{z_au#fO~bPx>AR1M{IEK8Uyx@QTiAi=J_l}79-`zvSbssDf`Cx*10Nf zRou(u7s=a`cO;*VJr&y)jHkiaV9YX2bDTBa+F)!pKJ%IU*!=PN4YKQJYXLO?z5VO5 z_1NF+zu6yR4>9QfR7x$QE<=_e@XqxU{uy6lEHTE3V?_n5<4u%iN>#O*+8kgos7e3G zf8h7Xd*y0KHDm@oi#}vKXmha+wgJ_Us?F44%D79pp-0oVn4FlG)N{(FIFu~z3kUmH zS0SsAOu(V%5etaf+H4K3Gyh1Zq^ZahTC2iK1rXYgYqHyo%PP5 z8HV``IECL8=W60@;+5mo_$A4Uk|!ojNm?DdDi&s{uEbVhWz@22O|jfN>94CrBg-@I?$RqiU8 z(T~xW;g{j{{5l?HgRTOYI1Nw5S7WO&n8CWzT4B*7L$-3XbPRC~b`7G2P`HYy&mzww z6}XBVJUgq3R6*c5Oe4LqK27>lx+tHQyIVah=nb<0v*>DMEn>&) z*k>Y>z!;P{=eX#Ay%!e~FD5QZUYtBPeqOxd5FPCRRuv51IH#T0I)Q4aHd5P&?Zon2 zSq^%OX3JT!2r%t$_+Y#kl7ZAvsw?{ehe?xCrAyjn4c?!_eAlty9XojsZ{t|5dgO;l z4wuLM%U$H4CuxUJ$I!O$*6`5iuqfoxUd^L*R5~h6q$Uz36LN2@x3^Nw@8bDXn^{RjI8 z`XgPGDZ7T)z-%0*Ww#C|DK{H@B#hPF+ zLuGsX&UkoEvw_{fhLw=AfLp*_ldehq(E(^>vLZPI8wN0$sVwD|aL|Vyp0V|%`ceDX zz3hJCAhAfFulJIBeD~FRO~0kxF|HWs%lJ0&P2!Z)KU3dj{FfnS@ZYm=;C&bLt%5%G z*=nu|dvjv>SpH`Ijr_@3ld{fcozEH`7#fHwQDq7`1ywE0TBt45ssIF3+$dpOCN2{W zunyg)AJFfJH$*F|mDNaTq*Rp3OA&z+{)wK7jub`;HMLsW8T1rdo~}SIp_Wn4k>^Nt zP-~bqOj>M8?EjMYB)5!j8DE6VATRTm`D=mefimIJVVI!{y^q3rSidda6c6)9`HxDb z0=+dFxEi|Zx@)`PIUdZ2$kD&)ye{bpcsxGLKEh7=2w#Ce-(NZ5hlCcs=Dya>md1XK{nVc*faRE@Uw6ZtW(fmq6_j1QVq;wnB|HK zgz%TNM*1v%6#GX9L<6D1(B|N_Ak+|KgW4C|8!R8F5U3TX9herH8iLvEGx^!P7!e{c z5B&=G8H3~j@@Mo58fAIFc+azYv3=M=ZPE7($`mz8ZHu-;U9^Y3L0%`%Am#yQ4202T5~c20B-V~4Q?RFEo87XkCQI0HR9bh~M96w^57TEf+YMJWqYAXnb$ z+wL1=8*H0S&LA%k=ZT5b1Zn^%Ct^eD2z3QKgomm{szr8cyR`09H!8|R7zNP~cz2P) zr}7uUoGN3KHcp|ZQRo{5?@en1oY^kgCQ5P?H#RypdW=8DcN97bHKgj&Md^aHLD($Z z1mhm&!tB=nr^Ec0lk7=$F}s8{aT6b;57FNWuY}|LNuE(irHR?t9Doi+=c02^m@79F z9focJoEe_ck7dR%Fn4JxJ_R2N@ESbVu8q~iU=KIE=b!DF?J1I2Bym{!2r!c)=`;Pa z{7r4mY*VaB)_voV0evP{1Kh5evRR5R!|%`Amp46sM*d=9kx&P(i%+B{($LfYH(`(f zdxU?Ievu3?#y8*_@g88mfPIVbuI-ETMS?w+v_dIRw+ltlwva7!D|#ckNL`?2n>l7T ztE<&V@25lVuo2ye#<703qOGiL1HJ)=eWS21cBC*`_zxhNfnsBZ^!|JD0X6 zc5iGh;HEJDSCv(Hhq6tXsn613-+CIK#@_(*$jr5Je+v8*fSQOU#4>^=D5AOERBy$% z;Xg+|N8wd)J-Qx!m^sXB#kOLAooYMf9ddOr?r(w`uS`&`idV(6+-Yu9bW9X_fI%G| z)RsR6IJJuTgV_oB2`SH(V-=6$sqCoa&`sS;0^F;*SXJC_?lZUBcGzGB!%o1TXIe9? zUS?183~`1S;~wL70b&gsLg(4$+18-z&Zc>G&RkYAt5Y`P<~h7e1~}~s{!}>TihxBs&~_m z5=V*0%oAobF^brw{ZFeZRh7OeUzJ=W7nwuMA+90UkX7VnD~eq*E*S%jK}L71D+c}Ah7f~^26{t%I6s_+e5;|@Slouv08;)L@V=94=~7ugf=1Zdn<%vTg( ztqX}AQ#+;JO}UeDD&bVZNAE{3Z{uxH6Iv80ft=A#>#%1OYRpz}E4X37A;C`JpTqFp zV>SL4KAxGtK>a;#VrHtEs_vF|$#tdr63tUQ)K0C;UzvZr;8=kYkONeR4ULElihTjZ?Vy$cOK~=X71MZjMC8T*I@tdO;f|C`?p-fKaAZvMmQ<0#a1 zKGGg*4*>2c87dWm9#Ci1GwK{_Hg(T_*KXJho1L*U&6uW4PiHUZUiUutet;!PnkCI9 z(ZLZMGl5|K=tqE1q<*B0g+u5_+)k~B)MM%SS59_W$v$buQP z>m2JGGrTjrH{)-{UrxT9+$W=N#@-@(i!@7Vp7KA>PES#+7zX#%DdB11MqC4K6Ssxi z8Q2*RvxV%ZU!Q&bA^1aZ4B%k_B0yBbe!zNZJ+)KPS?QhrMz2RUBy-v9@A}UQWO;G| zHUYbgTtVuB>SgvacS*aXU^o~SLqf>pO}?q#L~n(+!iy8d2{#&pvN(!eLP~+FWa{K_B<~#62PdDS~VP^Ffs~sUpBWC(Pp}^w9W1ej+d7 zm+?Mk9~0&qrN~Kg4XcJ#-B!c4KW=~Ao8;HYd5MLIue`6k4VbzNi#pNE$R%Vyv7fj} z-J)RM(T`#cv0YyKyye-;v)hH*hk6)2jM7YLW9f=NN>5nfg+r@`Q170mJX$bSgDv&cqs(Mm)`;tQy< zcp02TX|PglMDy@`9CFv|0IR?={9E>0_R*eEo(8cEVvoigi-8{0I7VW{jiSazZ8Kn= zv$V!q6K$!yNUk2O8NC|55>Dk)cvf?0y^-Ds%r~E9&NhG7e%Ig~5bVF1rcc*lZ{{2B z4Yw+~GI~-vF11uzDC>m{LLGp#M&*pjVe+Z`-P~?2sD{;r<{}e%%FLAK$iJ&YRSQAT zAK0qwPS+0CP}^|ZJN>O*jw{Du5h7Act|>1EhxY)b%~Iw*Dr(kvQ}Wj=6AGrNl~!6*4MhoX9wxaXjT{$`A2X;_G=Ec%k-t z7CV#uf@Y!9<(YD3;CVRg_Sjgkj&9esX=BZCCd@7D zYX8Ol16h?Uuas5h2ImKB6xJw=iTEO0#4Tb8p`>svbS0EmP*6}ZR5Daot|!BMHF!oh z9iM?W!Wv-+g-}1ZsnlmwOuY0_Atk>ppxLT0S$ltAz)OOeizCFa6q16V&U5Fv@i`N7_GKQ(oR#%wmOJbXuTfSjVJ)J; z-r^;o0%ph@NcE?hFpU|gMIEXCp~Hdq8^BNjBWSc&+p51tyG08E`GMZSKEdCm5mH&A z48hnK+au-?Qx;T1M}0?HT+z7qsqa&_r)*1s+#dE1dU!YgS^6lgL|3EZ=?Qd%jF3=+ z0q=^&5#xz3?l10Gf4u)=?EBbW_TKgf$UWqu`mYM#?^iqvhd#?|d~1DdB9rJ#i%Ywf zb|o!4;akE^_up=K2Wgpz1;4+o)JFOo$_ioGX!f;FS3ap<)Gt34{#ckG`K4GR-gu}y zQWk;zH=Rr6j!Va+>Be*e-dp|w<|fo**H;^;mStM7x9}eR0B>WoGCE6Lq#@E!369ku z7Q{9)TbW{PF*cLPB!0#_YEMC2k1R?DmjIOd)jVhFLRbUPwl04Q%}ifWGazF^dNhZADEBKYUgTa&=>N} zNSK-MEdFWy8P6HdW%e?ghZSJZn-rd{Wb*I%E#Xb!T7`8B|IGU{??V3h{6Hue$_DEW z^t9No?bnjERP7AdV~*%Y_4Z~vvy;)$fLe*VMjZosJ)c(3sZXS*QuAoj==1Qa@Fac$ z-%f3(&a&oO*U@X}Tx1TCVy2i7E3d^@;|=VM?D3v>&tvdjYT(uJsLHDli)RCD9K|EJ zhG`h|NSqp;8g>R9!Q5z0bc8wF97+E{N7*Rb6pZN-NO5EdvJ}}&ZKl?_*0{dK<-{c< z#wS+tSM*PbnHqE4dCW<$6zd0j>mS%i>=&!E^;UhO!hF@U;yH1sI7}QNj1bC*WklHb za}YU*FgSw`w?iuLZ4G!;qMRW6u|#aHV~*or_Z9bb@*2s=tlS_} z4~(?0A*j3QVRkp48PAO^(l#j+2}MeACAcMkpCnL8)Nk&7?h2lAopEc7`&1#nsd z;zvUEi2acNp#OE+%d|}yn=;mZW>P6B@c-XjzXQO zt$-~^$WO@c41GS3`G_50o2l$n7WT5k+$q4ZMhl3iNMt>(@FyajW1mV}pv zABUfWA-;XaJ>x2X?`;m&Zr%`#9%c^{=KBt}hFN#$JM_4iaWPwywj~Aqh5llW5{{YH zEWpic=rGS}JTs0V9E77LQ zj`zSB7vriJUnxE>DK7~&1~kfOl<_*{WlGohZt>;pW$i-%PKG(EN1}(K&=YcV_U7z4 zpXPlUpE)*jefGv|s6j#io-_fMX{WW(N~k5&6Z#3gBvJ~=0``igF z>@L+%jHk+Dr90jo-xjkY22Vj!_(UNQbz|;r)HVv}>} ztE<%@7&8sN*8A#s>wL?-iM)}srR+bH(aI!pBKd-NPRuf98@IKa8pJkn_Bi_kP-y`F zJ5+~yi@U}BC%hMGYBjYXfYXdK#v4Pmp;~dJ#P>{t6fH#?0oLl;TrKWe@Op4oXl5u? zN|kDvwamNb1M`7=Pp%oM8G)Mh7NKULib6#pN6ZzWcI-*uaiC(bauDZn{)To<8;6a@ z+=PqhhxSLI#vk@Lf!Cp*N6sS$$b+Q9$V`T#sH3{Ky0>#emjpe{Ok0+^EVW5&qgcy^ z*r$LsuQ}EfyMf+Dp|8zf!e2ty@ULO$@eTb6YBRN%(e_dHmGlalLpc=sS0$4v)XPX^qyv!yk>lJE4p3g@ll9qpf7+FPy#8Ct?aGrW9iZKHSN0gd+?87{hYcv#S4lTz)Z+f+Uf6WWVVzm?GyKiZ_tpE=`@8*j zJM`i6kufAZt0|!s*Pe0DIRMe}=VZ^xZd};3@L&0Y%n&w0p%wZi_5wSg@7G}-0E^kN zv*a1l#4PNZa#ex3Slt8N0*!-BgT=x{!@fvd>+E zsXr#yO1>C(A+D9HwW~V7Vdc^C=n3_NS_AAEyR!e6o%TNYz5iX(yIEgmeyJU*6(Uqz zg&x*WU+&esS_YPZ{mWcpHd7lZmhDL;j7Y;966J8tcEA$fv z3cm?uqh+JNfGR2!6(}$vpr74S^NE?Qd{g>M10*L{=W3WW%-@lb$VKyHK369M*S zjWfrX@GN04_~diNIU)kUQj8U24F))|B3cd&m_aks`e03_rcf}u2xj6A!-io?q@_~- zP~T9SP}|TzX`u9r*~R>9WEz@cC~f67a#OXjngZVEbLuIT!4_qquR83leyhG!6Li1c z25XH${ZRXub}^OWE5|3qCB*$1^JmQ807I9xm$Sp%u?#%pdlqE~aJS!uk;44YoKU^O zdWGwQ>w_(YR)PaOH>iLA4`AV2${nSN)>Ip4^|$U~_c0N0;kn8@#m#xSj8J-LVQ^va z7f`PQuLBpC5GvB;q{%h94YGVh<1LP6>2!36^uEV~g za5Nk}FI*6ywsDd;L0rx)moJL&7h{=}x5speD}lr}|!eg*H@_bk+~FCgcUPTYYn!&l-C#=$goG<7Vn&9_k$ zO|3@%LX)gys{&Yu8qket&KY%XjNK61IJrr3T6${wziF4!vJ$@}Zujo+)@Ez6qp`7A zGoz^ia}v50b}g*>soJM??>4?$mANvrYhjnd)=Dd7qqW(pZPYfFt4q~s<}`B``8U~; zZcRfU-5ug~aYJ}xIKTxs*r)VAY!_Aut%TN5YpX+qAwqenf&_cb8?lYq?#^CL+D6)v z=p=fYW18cb|CoPn#=MM2sSi?zx<|NSUVBHilX@MwfvAki%wlJ=(ATH9Tud%6m6zai z&vxcIyT){ldFy)Zx<}okS|e?d{{V+}QEuuydyYNnIO)jpeD!3+r^nAonVynfq(~8n zH?GHCjV)#`Vc&`Gz;{?Xtn=DM4N%U==C7N+e*XC7dheq;^3hCWZ8C0|2reWZRQSP&{`7^olE!R_SWIsU`QgUF7^-w}8>K0}%< zRfHb6m=jxTt~F!8p7mb+Po+%SyoOvyAT}DU{h>i0{z2S84rYr%j#wM7i9=rnLMQZV z(iN$sR9b>w7Ilq!#%^n;m8E~v$0=i#QUJ&G(0XaxtgY5j>L>+!P51cr_(J}$-<{w| zcfZEVcno1$E=S)!u3ct`ql1`1kN~VTJGq;PlY*3L4H=23RW2 z@EaYmcGx#Mhi(P-yII66q9j@xeG691x=1|)p2_nTXZ;R-f7mN-mu)hu)4FI%-?OHg zf!c0vGn1_(YX&)s-0s-w=-~XxxsTdMEimRAISyQs5hFe#Mu!u#B-uo`Q#U%<`Q#=`Q{>1mo@o+(jE!+KkblqNSC9RqrZjvhmyjH;p>1G z!@1vy=t%qz%=;i3Ko5Y=xrSIx9JC#=!R(8vu4%6NL_MMatc{Pwhhjaoo;nSihV5o{ zGn43v^jdTsI>Z^&Wj(-q6fZj3g8T&!C!P;VdncmDg=X&Q)zMp(x zX-sw%a~1QKOe}e@$o?WX{5Sn$9Ag}H@w&Lpa#)K2&W9dzD|1%mFdu0cm6h2czeE0E z^`Lr>xJyjNr{ezrF1SQpu4aQ>7-lw>2Gz~zVJs7uh%30|+$TPhhx*F8T7B(9^nG+) zU~S;XQ0>qbWsB09Zbe^r-*894`k6|n(~YSn)IRqf_sWD731#BT#CK#mF!!Vf(v0AY z;1l7o0DViO7$N4M_psLv-sU$W+xSO6t~Vo^6GZ|4foB&r=vs6~t-S{IDHr7P@~>!D zbhd4dZAr|+7%5(g?~>FdsdIYg^o@Y~_e|)SP}^S1-rMYLvS5yl6-S9>qZOjf@|)+c z{`A+Usqd%0r*o*BW6Dtl`eCmEHPf1D4F))%rPx+XF_Mfj;PXB~o+7Y6a)>Zghz-Yt z?*{J$xd%ZyHQ|A-lTYIg&)&t@J0oQw&PrE&|J@ilbpK!MNRsE0rK#m0bsG6;sZ9c%N zZq2O)l&}(y#33u`<@6UvmSeMfv-`B?tY@%ykauY8;Mg1fTmDAz4dU0j*0}0Z4X8NN zXEqd@fW2jH7%!v>-{!r|gFb+TdVxNa8cHpo7Xyy;92;Z6)ZWnsKuj~M3ATth` zfLsJz>biJM%u>E8F?x&+b;dD#49^6a;Kx8_0N%kA(KGb-$a~}regb zyomW6`ziLU^Sm>RL=a1`gw|YZP7`Gjo)=XB>v|ovu1X1%&=}NmbD0S<_kMKNbbbRr z{|b5;Jq0);%!WLK9z~(ojpZ_3BYmTMc0cRyo76X{V`9g|jWHWyLTrfLh;78CTeB>9 z548ZFk2lgA=^ewJ!b5Wh=hFF9esQ^ke2u(8E~FRGGxQny(8%ye$zX|KAz#Q3F!~#9 z!2Wkdy{6vaZg7Kx1A|wCH^9FK1ZNe@E@+wCD)+zaH`%+v+SM}BDxyicv`}6or-S{f z3|EGmA;l(3*9H1tTESGTDpD2k>+yPbp@*<6usjgW3Fj0EWCTj7rB#^6<09SUQNVp;!8@xa z))3p9ZB5AW9-~ju-g+=WJO7WB<{-geuOmk+nvPOZunXvbq)fpXTL3YqOYMJr} zd5k_zKSmrOcCb6x59~*FE476>jh;aVn*+_C%%4qoJ~UJxqCeH2>D%xv_!;+UcZZZt zDVK^~E{dj`X>Gjiz4ZVV&I4RRO-Gz<5Hu!ol>u}b+@V&4bb74-K z$5xf7N_^G6XfdKsydYi_7wb!O!_>?waupf+9_#~EJX#{!D%v~>b9M`bfKXqmFLl;_ z(GFUNte4gctD0UzU#YBAVAhHojG2a>#vYhA_K)whuRYxk%$b>buAT$_EQb6avy+*C zPr%_F{bYU;zgk!=z8jxs%M&~C)<;a>Y@%cpC2OcBT%>(OT-eZ zz&d_XJ*`fNPK@4(+=-A9EkU2HQbZ{NW=f0&wG>~BhpdPN^R^*Af&MeaoW-2Y;+w@& ziB#f(*hR5Ur^|VVzD=vNMi*m?u#d^dE^3mTDEqh=Zc+ZC{Fm9U zvajS{&L7AP;wDQIrMhYz^{bMtPSA!MEWdB!qaC80AptaHv#%sr-F` zy@4arG3llG(%c9zcNw+3`b>N(u9a8IUC|yW^kyCo=HpTOQTu1&6LHPBVQf*isCSGz zMmMrM*~Zn%)xqDvkEh@%|0JGDT;f~eJLfp-fW2Owi1x&7P%A*ezT2n5b76Afq{3Zb zT}_H4MPQEs^eGz53}TjAOD(t`E(N^7Z92_fcpp3u%|jc5Io+IV!JUX6i&hn?3$4JY zhW_hlAyW8n?xoya;s1rZTHUSt%zdT_+mM~iOkvX4boP|%9~Zpq>6_9o1^OmJuW`Q^ zFLn?*37hmy`cFhB0{T}BLx-c~_40ZPt+`eguY>P&{q6eKcgfeq*V*TAIbF?(rbLEW z)EtNoMAO(*Hp~0PD<>+66H_Ln3{D)Bc-(i~w+QV0rP$)^OY$Y@MPiUU@@=_#xO%wa zw<_QIedzn4&F40slLN^Cm}5L2;P#ndjdUrl@3~hm_1F3v^bJZOBvM=|A&m`<31vjm zBh921(r#n-cU@9@y`%m{cq8OQbE3F}N{_)xl7XZn{jGi$ywCg}@jqg}!0P}2!cbK``7HKDY-arD_>S?N;%~-Wj~QqmWQX1v)zKR0Gvlf8 zK)tVeK;=pWQX8%%_bB)zm>bEBI2ES?{kys_U6=>NBch4cSSv4-6|VC)_&h03I-(!a zYa_J*OTU41)PL6DJZ{M~=N|G8`BqA6Wr4NOk_m-?`42Dy3d2xr5|A18jqU@wi3X^#6{o0z8VN4bSfF-R`+tE`kSZDfSnN z6sNemy9Fpvq_{f;iWYZ@dvFQ`in|7h=iL4FZg>6}@;;CpB$wTtnNMcE?|qYb+$U}* zH;n7Vc3?|m))>RmEastVm~5C7qcLw8YY~eDBf%=3YMv_2iq7)RO3p!^fu4uR4%Us< zk3I`M4_)(L{RVx=5Go(75XE^Hi{|Tj;ym#)vR|Ls&n(slzZ$+CJ`+D3$Gn5-B8%u6 zb)7l|&VcHCH8isWe0M<)!8pkni9kUq{+1k(RG=zRC7=}G+QZMHFQVGWFL}~jY2DI$ zq$>?_!xZIIB`G6iBc#Kn3YkLoM*LcQp14S0Zp~4lv7s+07tRmmhi*l0MJKb9+1yla z%ETGC>B#R7P7X<~O0G->xd0afaqxloKr{hOK^v|O*CWwAQ9E2Gyu-W0`-7{tYmsY- ztG%zCuR^$77}vD$3BVrZ5AiagT)0ZQTsmGkQJI5)Yp|P(n~Mig11QX!_9*c<(IwtB zelm74_9^};j`f`InKjnRFba*r!{Vdj4bnfP6HxB3SF}gef^W{}#&f^*&VS@T@w+5D zBu@>`429`M=}R(}WOPaEp7yu?sD8L+xaNf7gaY@=j%G)*&-~B)7u@IF&)qNG9lY(m zE&VP0XF}&fSUWz3d?e=csEO8}h!^qgz%QT=*@tXEG$6jh0yq`fA*{2rjoZpSh(CP1o;q1N8AZWa(wmZ7l8`hg6{sjxcU>3VZp|LeEBX~( zAyGb&9!d|5NsLZ(6m$_hVE$viV`?#L;2O9xx*W@F#J-SU$eWVulDX1(QjgFlbfz3B zMNA&6l&YK((iEMgD6jArbf;Arx268HDv z-cT->3jX8z$2Gz>+?MIibl;5Jhy?i%uOU>#yTrRhVX!19jmn}px5D``?s-MiGI1$* zA-K@L=vy7uM{k}t$2H#dwCs7Au0&f>&0fu3;4ku5W2><{;C5I8VG**e&yfHBsQjRO zrF*5jC;wOel7GS14%Q3iMlMA#KS@_)bp&ZdS`ST6&15=<7LyWknQ*DFx2m6NzhR$& z)Bug0aWI%`!_7PRzsMbAIds2fW14ZGd7$~I`G~o|RA@Si#&^HwpeCsBD{${xJEA>N z4O9hK*9j)M$_;?|ta)9qt~+K8U19 z^gmhD4&?W7F1*6C(!=>UpFAiJ9*iD}zF;xK%`+C)&Cj7`Qx8zQBNQ>BI>PUTOX+1a zj)C@S_G+f9r>oo1ZRrK^MezdPSKrOhtMuXAea0DD7 z86`QVJfoZkD;53fRa z5PTGz6dWI16>lj&)aXp*Q8>p`rCiu-6vd?mgX z!RA4{Z(SfQlpav+Q~AUJ@l50&bD}xX`my>k%-e*y_5Wx5pYfpyLH|Ji4$UJ*&d9%$ z*Od2`_LbIQYBM^KPE<~iB~U^QoXSpR=ZEKoC!*XJpFuFZn9mn{5#SouJIOoAdy)Sl zaTE~av;Vomc|xqeinWXuB^M^^Me0TJLLWnoBTXWh|06qCC3xKTx9^(&n*U1VN+ds( zpTc!nB8sB6(%WgBTrI~sYvYs?l#j%Z#5dU+Eao%9JUzH)x4x*J=$7=h^rGmTr~}`D zr#PCMD9RDtQQlGJsB_d0C66WNP~QIoTbu32_GR%teLHzO`C-)&)hPslMxc3*{j#yp z*uvDpxI_~SGZTYuk+V<%(wK8cuyn( ziNJWcm%4w$i$@e%@?Q5D{W79|(88aODSY1M&_`-f+2eSj&ijm5Z((3A{;q+p%4|h; zJUy1CrD7@8&D!nT>1$;F$$s1WuNT*Ec%c`rORY=cKKMDFxt=V4ray}O^1ARJVOdxj z#=M`G{1^SD{xbh(?`Q9io(7&K-p1b6n7<>{Ej3p%Tk@0kCvCo}K=m1X1nEADPwmh- zj)V_~hY3drYpZLik0_2RS_xYUu?FC9W+` zYC&{iw3nl&qmQ$nvvs0%VwiZC7;8(75RVk&-Ywn_{f+%i{7Mv)S$R8Om@G=_P`=zN z*ejUkN%K6kKd@JERdL~(fFqGZk*q{kVnSkkqGzOMWN~n5a8CI5FxH?vAU-U9uYac> zYaVN!s-C9C+B+wLCxa^^t0HEhS=dk0Ph->Cw8fHAi2}$#cB*QMKpzif4`lld`we*S z>MzAk#UkM%A=dWBef5=5^!Z7iCm*OBq`acMq^zO&UNc-fOj}>|KUFDH!rTHkLBC|b zq=*%~c7mmFIs6cN7b^|gfy#ehc1VVzz8IAiM*ET2UU)AyfjKiNz8SX1}xx;_?kGSPN>`H+v@FFyLOg(hPs)i znI==0rNevHGc+?b?bRLBLu5l`Q-#xnDo({=o;$)vpe*&2?^k41S0>gZFz3Nc(M(ZS z*adEmZ;VffPmGtQ%2G?HMHJ3ou8>zqT~rq}1x>-l(Z$hau_dvF;f7(H*QY$ZXP9HS z!|Et=yzoBrz6!hvScBGJ&1j9N3dK^HR3-&QP_#z0T9k`ozp3%x;!h$^BHg*}+#ta~ zL3^?jDM9w)ee!McyJW2-?!UP&xhpBJDzECH?4k5Be&!$I7O{oj#&;#U5a)zvg*?ME zxYoaeyn}p=dX?H`bQ|Yc=3Dw1`x<*I`zRYrnn*r~-icOGtEk_pSyWfh6;umV4XrI( zS5{VFEx23uZ`s#yez;grC|D+1A!@`o~n_}bGaqRi%`RLBj?$A1f@!@gdCFq&#jqi=?ivJ~YM8)O@0^_BIN>8f&)(P1T_y=)RY0S7@)NUr)cEc`x&n`K0-*`n>uGeTc>!rnQJ4 zh-zduxh%0P@t^CVE4v`OVCuWy-o5(p;=>KcO~;kwrQ~^V0n|;@P5kG6;ND#JXIYuM z%)JBU8k9gJSOZtV+}Nd9178DQTW1?*J@=39rNQOFE3w>|i8Zht;vM7qs4<#|$K!6^ z!!IHilk0_l2)B#>5+9WxlJ`aH7OJ5-lgVPRhRCVZ>C_(KPT^?n7;S!fLHZW+W^;+W zO#Ul9nSLaGAa1N~qMo6jt{12UYBkEozC&^FGHxk{Yvo%iS}V?IPiprW_ZxAHJv4oA z`g?tzKB0&!?u+h;urJBuKl2yiMTm8J={Oy)9;gwxR(7>)Ou^WKOlyV}@0U*^CKErw z#_+xWt$%9i)Y9IieM>9*D*8spN5_}Om&CDM`sn%K`Q1I+jq9ZEhVF*0B42zed@793 z_m?2tj@*uHKsoeMb_F|x8^R5w2hvGH%8*;(Qib*vI#x((SPj-Ny5!CEW`@(lIPThP z++rM-IXv?(!xlp`X-jE}PSBM!RWxU^PG>c$+OVp>QlOH~q%|!^v7C?h^S8i1pf+8L zekyw+YoKnR{#o5rogvAR;Qf@^%nyuGrjlV!vpi{@G*@&0F3~;}J{ICQX9=1Ib=7s$71JuFy*GU{;rQbseV#rmIVZtdddn&=uiUam^BVmt z52!rMIKqf^CKY0}xSTvwzEi(b|1#}O+G4{(!)E0sWjARzX*F3jnM37NHPJWL|E`~- zU#VTD{Y$w+DMQ8(*UDyuGs0(z&ld0gyzBE8WVhQQKZ^C44u|gW-p+2QI#pD=jT6Dcj}V?SAEd>92_90zT8};q2xF2%8XCSKM{M zchT1<)+h!EK$0>b+oIa88iiu#(W#NCt-fu(7yjq|9sEun$az_Lb@^|#@Gt2X^l`xn z!5(@SJybJPvomdHTKn`4=}%2hO+TuBROO4liiDJqa!6g$A-bWu9K!^|G3390(AClv zYfH5nty=p;^F$L?N7QFjXH=Mjzn$V2#b@CcA>PX=Lw43)Y%e}*J!1`{_yTL}tVVgV z!|(LBwYRmK?H2nx-&^1A`0lurm9Uw?^x#)Vfupyrr)`pBvIFZ-jSh_pVVxtXPvRSD zA7USG%dxF=u5`BcwDH^t+zH_R>s{ndvXQvqH~xX{R1a!gd~CdKv~IK&Yz;BrP(&G0 zdKDhUS5dxbJe&aEAhZ^@6x%fp&3WTR<5>L|J(ctIeygq6TAbsY;KV({RZ)!4DA6d<*4Ngjv8(M{9orlgJ>@;^ zQO-TjJJ%a=g+bwi?%yucOz|SkG##bgWdW6YCDA9ZIW{RyWP0F=^&Y=1ZnX zrb|1pGt`u_T#42=vk%`?r*(wC&~w(PZBH(WOi(G1oMR}NEdmTi{R zl+=(kq#95-*0|xi<}%vSY-MP$Pk0f+C&Lq>$64K7)&1K0+B@1a z%CpR|+|k3@!&<4Va@lG7X?soIcfS3BeSw4CL*5csscW5Utt-#<+11_C)r0#(@OfeR zMEOJ^EQD*3cdjY^Uff08Njw~3Bt4SGJtb?IH4NU%_ZU6KPnJ)(rO)CvxD5An_jHF4 zMj@NNTfJL7Q8h_*RdH4ELHb?_P~z}b_(6y{S6V4sDStLLF}}!nneim+aaMavI}6YY z^cjkD#TajpMNbVD=6C*+8$cXu4J($`!f_< z?6&TeuLu*4D-5cFIY`biGZF_72H|1^?Xd1x!-VzuYm}VTLAFNN8r^_>inZmW?I1|O4vr@fMjX7nzQk|))L{;J{agA6FSHoS&JxR1q8Hw-9O zwuI6{>X0^cICL=dQ?yYO^K0RrG<=N{RTEYAjIxZ;<;Rw7DhxN(OKz5>F=^xG9AK9@l5eRz8^n6kP|RCjE>7i zmy1Sz8TF-JalPUKf4+ZIVpQUE_;lE8HCjO)kyq(Mr4Mb2+Z5~lT7ScEqwp9Mqc<&R zR&XKzLjD}Z5H|-4U40zB-wylcoblK^$*Up#Dl0ZpdB=YI;R3wG#9Wf81)~GVB zwyd@6Fl;v@#0l|cZVPt|9)tJf_v8VyALWAiX}2|ZG?-UlC&F-KlMhrpP*Gh|UGqrQ zzpEax9I-4=E>QND43M~x&8~s06k3*Pev{v{M730f`}Qs}=b2UVRq`j=r&_ncZOArM zH8j`!ta&1RDwR?U^(p!}YAbP;l;joW9W6LoP{CW-+nR03I#c$PASehX3%SC~yo|gN zMI(yLfwaJa#Qenf(eI*bk z=^N@>>DuTpN5XpDdff!%!x$rD{LMJcC^N_mCl#j@oj@lr$3M%zrEF{2L+e9p%Fp>% zAU}n3^6yZL*1oJmS>2MlCHI{7otcr0$l&;(_}1XI;6uj)hsA2KitGY=D^FX`sNl$8 zr%I-sn3k8;4%wyp`g(fI)y+#d z$tLwy^&#B>U7q%{ww|G`p|-iUd2HI)G=)WOX>D#}9-<$rSL-$UtHvwF=H}*RpU$hB z%1mW2uk_#6%5QiWA>-jQ#KYOTRArI{nRWZ|3C9&3j>cVZ(e%(*n~2 zm7JBFo+4M#{(?gVl}aj>tg@}N30*>0HD?Xyh_Vr7IVCwI-<8!YyH$3(jIaXhpY~1m z3cgCdo~iCB5ACI~7Q#BX4hB-e)I!00!9C@F%1db%(`IMQ&bn#&$1+Udb#*wqu`Vk7bN`j5*zyVceHS+^9u?K3f~vKD~jaD^7S9JAHRQH>vis%+&70m9sabhU~j>x;#0+S%j%VND(z6Z zzHoh^Bj1s)E>IP$&R>hZa^+JcWC?>}(#x@{G2EN@Guh%B_X*}N7|o1f!n%;Ij-`&J ztEsc8ouQp!Rod#bq2-2@Yg4gx#kZB-R%%zdL*>d9Dpgo!Sz(DHU);>p%;d5-EP3g9 z={M7Eq%||NFpScT*5#&MPFq@ONu^a))>cWBkCt~?JeH5fkH+K3cTY0>YN)BHuG!A) zU@#|qDC&>?$!=mZxD4)HE>Pi>nkL zDn3%Yvv5aY_-o|r@vq0e2EPQqj6(ngWWm6qfkiEgS{2nU`k|<6akt`;wvo0mzR^C+ zl~EEZ4h@bBinNKgj!ubBiLc>SbGX+g6pO}iFJUoP!c`Sk6RM>uDXvxeMb%C!R$UTq0X6!@83wxRu;t{$;RU@hoa4)raUqSbzn{fC9`;%}zZI zKMt>VZFG&Yj^HqF7Ls>!GJob3g!hq2U1?n>vp+af4R214m%G!O~{B=D5+2~ zv~WmaxG-AypY4GS$L*G|CEPmLDv0$LmZ8@h(C2Z1QGvaoeId-bpB<|d>&f`I+gNsaRL6YochXSjsG6ZqqmDHIj9b+Va}+)sj_`V}j#? zFUhY-XVek>GrB2?wRdJ9oQ88 z>8rw5g}KESi>q0y<83qh7RP2sB}Wy2TJNHEQ&DkL{8au(zDK!NiEGMlC~hi> zrG-+9%pw!1#HtWlC+$sbOq>at`WgEh1G=EDwzifws1B&#tKQ?IP}K?LNo7irQgo4b zmE#_#-I84ryie6!+FZIyvR2ZTZcQ&ISCISo{rrUFxMY)f(>RV{rbeelo5UK&FfY#X z$kIp}ibMQfpZA{guCtk=x#KU#c1J~Yw+rkG?LNET{>1Uv@ss;U_wRu@fs>IFk;>u9 z;ZMHLzE$2;-g*AH{%66bK~KaN>Be?t`=ZiB{1M&&3;^qe%%kR0HH9^Vm=n3Su$Hh7-H&EuwCuI=jWVW+sn#ghDDnQmOX+K= zUFMKIQan&t)amNlnjbX(Q#Mcvq@=V6VS!?y0{25rMRR&Jy@tLb$Q8`OJA=$j21p61 zSL_ylN7tfp-I0Wl5%0l!u#ebF2ndR($=Bd_C-x*ZM>a=Zhu(zRgxiF%o`omq3yOS{ zufMaOvyQEv?UL=Ht)A;g*E#PQZ+gHSm>T>o_*Zaya3})iA~+v97aAHK9L`3-uLUS> zFALg&=fY>gi=vC7H)A(qIf)60#(X1w3N@9QNzb5f3vUTAw`BtaiAXG(CH-Bx0p-yr z6vq?+xnDk0K1;q)`KNM%Hb?tH_d+*GJy~5to-IEkIWJMml(G)0j;dqYlUkF;sCl5c zuPBif%ic>rN!Ll%NU9^~#X9kK!taG5LP(55IXu=qIl>?2vHl%w>81(1T}h;l@0K}$gy zWu=Y_{}%QU^b-6F??9d)$Vn)+?Ir6aE02&awMd_epNY|+NoYAE=aoQp3_Y9e(yh{$ zl9v)zmXeh!N)&xmeN=tbebqHpHB^Q2V);dct@15$th0TdIme7cxjfc=_!%?@b%;8| z25KFJ`#_y&#Vv)4AnxtiiLi;=%sojyNuG|KjC}}w49yMA3t?@8-qBvsl1O1hhqAD( zfh_@{rPJ$nr0`?!AR8(#!F zpM8^jlbpoo@JEQF#A(4P0oI;gLM|iwfnFfQM|l;YB(4gt3RPmI*pGlUzVM#;X6Y8` zQR!i6XN2D+GbK*O#q2@2AigMWB*DAljU{18MAB2*Q@TU4Ln4<*B-g~(#dDas%tzrz z;dpW!Sr^m?SgTk>(j?ZX?aJVlTbNz{-1ReqhL6T(2`_w%uM#ZVBg6e{L zXv~fh$A|>_mt*uX`Ze>0dCojzFgN2!dK5hk!AP5EWIAYwa{bGa%aXm~z27(r&r#>7 z+0+~=LWQY!qW7Y6;xpoiI4s5-;>C0c-HYkX;JzqYC=&iF_*Wnj(1IJ}Rq`hJ4|#?- zNwkG+VI%%$egqr}aSiA#?gqCdwLR6GYsxi7$Vg?SFqcWWRAy=``u8meUs7MuJ=Wzg zCq3S$Z4mn@);H2WG9^4Y+&kPWjQ2hI2m1vl2PXz+glC4wMaM?x#OB1hCAuW`qzN`I3~li)qS zmXa2dKg8?A^Xd8Yd+IIK2hEPR$WCKE{Ka4~I0a8Z5)hz1(SR_MMshu|f!GK3f^A?s zI1SE%F0d1{qMWyWvTpJ%`<8vfzGD4}Kw?*Hcg!AghW_xc^$+n6^{)sm54DZ8jrB_m zOngmzN>B-5qFKCoT!=pBvX@ye!u!PA#Hz&F1jSOUE8$9*5FW)J$DMI&{6_p%JU4L( z&95t|&HNU=6W4+3ne3U|lH8m;&Yj@465EN6qV}TU%rNGl=%}bC)t%xIdNX~Qi^z7? zm(-JBUV6+K*GutvB>_?UUZoD!cBzh&Oy(g3Cp-IpFg52NQW^O(-!j$*ujcA3d# zjxooX3gRl_ZOm3?p=hDVLYXOCBUuqvfcRq=IgGqQTp=vHh2NUop422&Nh7XT07n4s zC(;5vza9P_$7N(fbqF(r!8RAyiaALqnL(rzxbLWqu&wZ<=(K1j=JiMRe5_!+ zU@^6nS}a_Mo|IjP&t^XfJ`3)V_sENa3xdbOheE9XSy@z3g!@O25Qm7{;12kiXhJ+E zUJzKr2m8pqU^j@t1T=#*@E>vSn|6_kRFe1%&4!*^ZLSVSB7fQec7#|5F~&u?k?8t= zLs-f!=N=^=CNcj)30umZPo7VnM(BfJNSRVQxosTg3!BRQ#?9cSbH0=(g}JTAq{gIh zjX_@OL+WAjzoa6iOr1+zz%&YcC(s@Q5#GTMusi}j*X@kfyb7qmeefUXNOUGX5$_0y z{P+X}yTB%BCj42b7aE0eK}>*qu3W$g4j`-pe*k>;JqnBfSQq>a`G(w&Fat~nC;8(% z?w4LfE+JP4mZ6z?0gc3GL2E%P0p>%SL`|mf9K`*4zY>#)AK{NM#>KcFxLRBeXXI0|23eiF2rhy=bnRIn6W}`9d;ERghwSS5)P~e@b_M%8JB!Uv z79??x;wWw;S06Tje;{n<|3Xi68jtOtfzT6JlQWI55O>j-orb63Xl^WrLa5|F$$yjh ztfmwJbFFURH}d1*c-RWG215~Uz+3Q7xE|I4bwNJ-g64mS+lS`G{V2A+M<;GzWzUANWzrkscB1jay?j!JgsZab!R41wtJm3K4!t9NZ zMwp2#1kA~@fS5<9Ni|s;VF7xjMVLV35SWkBK2%h5(!=n)MCSWZhj^s(Rz$7?J zo+q)U>l%bw?c*s!r4(1`z`Y%%{7SSckm+38E5Fh1i4E zUpD$YlpOwT9uA|1BdhQa1t=(JO|~H?fN=oF2aEVc{9bM^cO-Q*|H#YHDDWK5HRBueI%qV2EhA0v%v2t5)1+}nnSe_ zauIH#Xy~NixZr@`pr8kd0D6G=a3TB*^Dvznc#7f=%tev~$^j*zARdzs$;pCW1*JqO zf#-b)2GDnYMyshlOmZCeEcGNcEj2y$tq+{H@$cdLZ|m$&xDjH_mIuTG;v#X5Z~+(k z*(mzC1}JYl%x59oMDf?p2)LG?;0UfW*O8mU&E@9szoYm004tztcn)7e0RUh<*a)yj zZxga9iF-swlcPu+bK}0)m*53>jIMhnzl<;B3b~sI2Hwoqgf-zJun1t@|1xy_v_LEv zP7R}8Qm-f!unKmOyV1PaL^#p4Z3G*D6v)6M{vqFy>%?Vo<+!fMk1s~g2J6gD2QvWX zRJQ{MsDsuY-qRV35F|oGf6xyshD#uh;|ll!z8b;^ZWz}SSup&8Yo5mP8*l&OKg8cyVgdPQlK?I>6(T`Y6EJ0SJ4H^p@xDD>1 zNbfJu0Q?UGVG!0pb^+T!ym!(BVI*2VEr?b`KFCKaXE&OAqX6dbbs<}O6aMq19@fzdIoMD>mb*GKfwRs12_T<142STTt=ut)+D)}o!pNBP!an3je;R3h>zJf1kMmqtnXX%Y{*0<>D#-Q)T zecvPmFo5zB0C^stxk@1Ot%m0;0=^%t88;gN^G-eFAMpyPhGWrB|A&D4b$cT$LF;cd zScR^3Bq)!b>qqzz?nl^*fa~GYP&~8_0gqfmAJ}2u(l}umIsSvY+q3 zTi`|a96;~_AA0rS+chfDGoKD;z*4>xS)kwfU--7jgEi){&hKD;D6-;H(9HdV$GWmg zD2I#CXgZ-C%76rvp!J9~?JFSs!{7e)O!n~y(O0*4%)x?d-^aqy@Cv*NzXvq|);;(H zJ_4*i;zn2T3gHAej%M;!fPK|9WWz6l^T-mc0sjY3O9KQ7000080DUCKScuLL0h0g# z0LlOW03-ka0Apk_F*PwXWH2=|F=k|DW@0ijGB7k{FlA#kWn?%sVJ>raXKhVO4uc>R z+8`l9=6Qc98LdhjUay?mv6@oQx zu(Z?FnRM}4A(OD7f=$cQI7fw+XlaB%x~%enq!7TOFuI4ys`|4mAqM|Z@Z3;;ms|0gLFOd0~lKp-${DJe;)l!T-;R0@Rx zqb;HMEG^;if0Eik&NJnYC7AoYbO7KHcU(Ca#OpNPW<#ktex4cn9cRo z3Qpr&KtpJ_lv&*UnpC>A?b>&{pEt#8cLO*8YguO5eQwxEDO~vJ#Z{(pW<^6mM$kI}{nI&w6s0*&O+%qK{@rOfK7`KE&@O<_*rdsl9bz->tYf{`}g;5qjWt ze1bc$gLiOJDG5A}kTV@>g*JHoYcL-pH7ipZaN)jOPds+ay{?Tna$Dh`fun63`hE7;BY|o&nO>HiNZujN!9#LV*sXzZT;1h`J$sf@ zKmF=tLqY$yA6c&k6kI+#rqFz{k!5|tF8BsyDJFh12|AIl7y<6WCdD05-S2iO=wutU zza3h)I&frXpspx=pYhoP6|3lmFo>_rwQjs&?fEiEy9V0B;~Lhx44l)6z1$t^0D`!`sEAwOf> zl|pQ$%BP1chI07X*yZ0Rf#U6OQ-{6>EWoYA40yn+=&+QDZ;VV2s-wFDKLp+Yz3zX{ z?IfM|#D9;-K}FSohq7lNFwh<7Dro&4DE%m;Lu8brLW_xEn9(xCfD5Qf)}AamNWv2l zs86mjRVnzKdc+3A9Nk1t^+|`FXU|kxjQaSF=kSZROp1Ge$+q7ib?^F36QBFQ+x_ep z=BJ&;6&l~>xsQ-CS3!V`iuZds#9B83GPc}Z!M^QpMV_a+$KDA;7qw;Y%uixvv= z&*uH2Tuq$|r9m%%VAZ#le}+3}kQ_InrpcMZ68U1^3CtwUtT?%W=@$_<`$k~%gzq@i zfIlqMG?hCdWh{!%bNC%p3%Zb#>OZSU?(j#cB zgK`(2yoCopq7EnJ3(~w=8t;S_Qd8t*GBzD8eV0FVJ7HmZS=zbdIY#|H>)L#bHKpte z|2%K{-WA3(c<_~lc4~-+3&Z$;1-$L@rc1&fu0_A9HQL!0iCMDyds!!O;j(R{HGTHy zYm4odCn_H=TcJn%DvjyGer8oTPu8Z0j3C?<{+awK_o69lvBHJ6r;$}u(w-kx6SY~l z?rZOBHM%T0}ryZ=ZDA{+R}|{0Jo|O_4W(RJodaZmr6^)-FI_}7bNWt(iCAVrmQ-Ef<71xN z@y3DVb}nC*;{i;xTcYF>$SKCDy;%96?nn**2iaNB&J(YeF3JfTEC1vSkG%b z)Y_?XgnJlPhJQ6=Cq{CA^IiuyamrMUBu83awo>#z>zSNZ{25hRO;g>P@+2Wu=1j)9 z!alC!9r1$f<~peza-qwR?wV+j^wKJTGZV=Byx(f$s};)@k>OZv_vPBUgm3<`>{>aj-zu4FVCnMEBwHeYHw$0L zC#SqJx18u`sWu4z;lV;$9R2?^#+JCoOyU2zRQc4X+s1p~l!3C4=hZxqVRy3PwiMUo z;G4bbl6lOX1;<38Yvamlw5FKqlV*{ruNe&^>SyS`%uQY94n(FYZ*-o-VEwks#8(5{ zBp4f&kOn0>_ppkDO==o|s=HC?ZGKU-+-6L^?c2DwBhJAT+p_yZ8##4Mlre2Q2af8X zUTu68UfEErfw;tDBK4{3M8fl+7!95poEqb?N{Y6JHhnKhX)nDGd+%X>#^?lEgE95I zWtk)f@`hCZSiHpy%H*SNF0$*R8*^!1Sm&ayCZN(6)fFhn6StpUMo;@12rGs?Ay8`N zIft{&;*H8D$v<|NRHq&{);REKz}tnyD|o(`KU!1yKo#mA?^UiN&-s+9U~Nz*4MLId z6{^LbEje{1LGK2TEv|~5Lc}X+gE$`ndUNka6Bi>xn>mT;@oKbW=1h@Zm4w=ija6(_ z4!@w_{j_PIsVtW2p@9h(`ZR1i1`Z$PBRT&$z$UE;qr+^#+`Ozv^sVo$OV?g75 zW`h$^)YCCDAQ2Noudp7`&wzL);+a%#* zGpNfsh1mkOVg9&YVcV^I!}W)(&%zw{yu$d8dl1BSmH7|hO@%M#?Eja*#bI5eM zx{UuJa3Bl{jZZ%>7Wc`?lcwSnKQaG4F8|N^98=Xb@}L;@ES1MTL!`&Hb*W zxkxX6k4Aaq&_vJ5Wl`7i{(ialpE)Q0N*CV+@j$Cwk<$4EryA#bUAE6kD29dxRxmG+ z=0k-$_8D5{Dgt8CCN>y(2d9aiuSq*r8!rbYkSc4lje~n9m%lI9ig&rxl#h73k`WTV z8{Su^i7{V!4G%}w*JHe?&O0!*aYV9ObY`r-6DB*>w*Bt01YI^-9-pyyBQM+)VE3qI zEL-G$AD0e%a}HiPnpT~>e^?r;Qg{t@2alX4%)P9e5viSQ9LIQ%n(qFlzhMf_aPMHg z=s&E3&r_9_dIYa@%q_}zmk-mVnNkLCO&XnBda*o4Rjo9n&6u zb3)R2PKbc}HDuz2SaPha^JncH2dVO~a)*Vue5{r!kKx<44{a2OND?&F=s}Ec0(x3) zk6yS4x#;=9)yPFP-Z!voM(nHBdr{=hOR;JTGG!UfCCQB7u> zj;qBy*97*VqY%rzi@l6p8s$h8F7GTTTHX6;5h#W@>zO=Blh|#HH6r+02dS@9{n;`T@U}D@+Jp)`->)T!qKkdUom$G-D z(o~2iv+S-kzE3pu|Hzr#!4G}AZ@su=(wQbX27#_Tgb`sjQZC<4Z5 z*gn1XJ6;ukV88)t>=7wQZx^C})QaS$W#l?cqPOIkR#4Q*`n1C<^O3iwdH~hYx6)m7{q?1%hGg7{28ZEqU z`e@ZVc3#s+1LLY%97eMrztQNKzFSaYD+_W!$#Uz$fh@=wrG-zwd%+^=fiVb;%N6el z*7O#0-vLh0{P83C^k47>)#JQSzZM zOS15&@*Li`ea>_@xQvO2jj$xsBpfxOt_E%pMib+g6_XWtlA_AvUu5{4%$xS3ze2oL z@&20g+Mu4JGNdmXJ$Iqcc!V%XB2ZCEPx|9WsaR!4aR9Y#M1XweeCyqx714K%6uMj+5g;&xVLP5+#X@sk9d{5NL=Is&jm$MivV zd(~Hhfu<8Sa+xr9O_#hy6z38D!)zvlYoq$3W|6~;aa-xs>TZHENgDP$pUPi_O;@9_ zBKGbNAJjd`k2GsBX554045NI=W^K= z**3Q`wzo@uKLWVzWaoi<1ZI9yb%Y0OGxeBLNovj78P(D1Xfr@UK)~3R&`FWf44qk8 z$0DxRvEs|xXEn?AU2F zgvH=(_)CHmnh|X$RSzWYR1b1d9CeWFm!-*dFJ5-YD`@*TW_x2OV~YpQ21^ZEp9d4h z(H*AwWozt9g$YNwMcWrW;HHiPr%pWEEogMBlKO%@ND@^@bI2(1-SFMbhy*_l^xVSmnTU$LBvv+rP`a3dX z|Ltc8ApiivpZ~~J|Bg3!JZZ2c93~AzOIe|y7%&P31xuo&&}fV`3Ime@Lt$bbme{`$ zS${wa5X}St+Y^Gn5YO-g1P-M8l872VyH*`x+ikyuT%IydQX_KQ40Ts^rL;*31#5>6A6fi(6KyFAx-x2utZnyWz_!->( zwb!d|mWNxl%hHGFu`ul<#sjlOMQx205C*B7Y9wA=MiKVVb2+45Z}RTZC?fH+#p^RB zN_Cp@z6?l}9kTa4>PeU`@_Lxj1d32G;%JYu2yxMn4mzR=r77WuSd=}iK@%ESHFfA? z-*+`lQw^dL&m_2PAkjI(CK>WI`j+y+8RduvG_H#{3A+Xr%~0oSzkv!YtK*geQreI4 zi`WyIya=(ZBgZb=*zjD-*InDvHP^t{C$4WBx@FHJKA?f9@~1@^5#nNC!+@#?Bt=mY zlDe2yv_e(aW(ZeJRgz=Ns0TF6(w~hOqDR6S3=@{=!AX=*P_e}8Ai#v4GZd!@60&)Z zpkhv|g_C4dfW|<6Gvw#AnGoW2Pf*cJVK`Q1tmvaKo$+GA0#4wZ8`pFefQP*w zTzUWf=5AnpZC-sn9ToRvJxx4{sWs+cp*Q&z0j?w!L% za<==}y|L-;$ozCHS~FgrBPbwI@Fa@R=Xo6CCeuhB0WYw)rO=~ckHbrgp3Br#PFE@580$!A2v;cy=E zfsj|={Jz&i%aL13W%Ira@4X@|s&`kOa?O9LZ^X+*eKnrYMW1Dx==7x9yr6$T459eo z^r%`HZo!Q+B?zzBj{d8)vCgLP;$Lz8K$ly0o^wrO$~3G5UixQT1K*VNpO4A7g1=WU z_wO&OZml}JIl*htBaHWg0a+jVSzNe4+&5@wWDxfFtw;GuoiwK#@CYSmBo(Jmd6pLE z&lSge*Djm7Z<;nS49zm2Ml8d1b&M==hDVMwd%R!OciHhCYUM@8d&87R*Ow65n;=x* zbzGv8vhLWPQ`U98?723?URm5lT+N(?Sk?FS5DV`pXVj(qMUal}=@u@l7WN!X*KF4z zwrV)Yv`o)(eg98xDY~ZFa0YVKT&u4sP+mgPAiJABc{N{da`NB@k=7L<2aI^RO0vXI zr;}f3Cyt+HtjQl`Ef70u0Wq1bZ2pMG0jEr+t|bkhavC+!fcz~o@eg6ULr&r}8-28R z{mKR}Pl75}5Se}jG5U&}`dVg<2x!y&~>$z_(4^ zF6mZb^Z4NW^h7CyL5~#niPxiBg?g9Kh-^dQLRCJ6Ci2C_ZSn~ikN*QuO9KQ700008 z0GK4lSfBBQt~CMx05Ado03-ka05~&YIX5^rWHe)9HfA$oH#RdeVl-rAW@Tb#H#9Rg zH!gQ!b^$N~&;3$KMn)(C0037(Rz+rQbRZA_000310RRyz001IZ000625CCLhbYTPn z007kh0|UJWat-elQyn}bnsYW;xK((-+APJH*u*=wj8PFPq>Vh1Bq#oPp)yT{)~19O`k!t*t4iy0aV5u=b@MdOyff%28`SeIMuf z)7F8$AGTG#tkt~rDj0$@^+AL{EH4ZbSMs0Lv%~ejbjzIMdIEYNi8h8m(l|OK!v>P) z8_tHm2*4H3QR!<4ekC9}2tl@`XwS_wz) z8`yWt4a;WMZ|boEk{L59crdCfJRS51Wb?n_xYzd9tltpt%>gMBTpy?-NFS>cuLDx^ zaOS$-+u$?l%=RP(+Y|B}N*{z8$q#%1g1k1 zIoZt2c2~c;@80)bZS#7yYj@QkXj83qt=@x1W{m;>KtO?-2LOmVN&yB$fu7w)cB@EU zgE0g-K@Q*oZr~$G#((e={0s+h5DS0L@)`|Bd85(lCL^o0KqYWuAnpcjKAPl_%(ivAK^FnEoR7Pzs4`|XM(n% z4SDB8un!yrH^5C`U=0t%gE7K3{trw8Dc}!i23x?p;0}0>U*MLw1ujCcko@!qXe!D?5QpQi1~l*p-iJTnZ#V{y zguB3AAVC3^r^-=)qN(fPDwu|+;{#|vVla!p|HBWw9q%A_d>DIx2PD7*IGP|DM1#(# zGs;RJU=epEcm0r{IcNr2f)-#gTml=?4d}P@8@d3MpQ-|?fHin6W-y1Bprxn-?trV2 z?`;L!z-NO0k^B5;f3j7AlAr|0KxLp#5iF&aQFq`yI1mg3vE&|Fpr&Xm+JYA2rFbA& z@A+T>NX37#Le`@;s)gR#Z|!yV2AfAb;>bN5C76Y0<630R`V-UxbwLBz2sVc;;bCwX zLya&GlZ$Nq~J#`P<1(WT`b`h(HmD|p1pFt;)6F(4A z@GLkFZowPSPx;B+E~O5D{U8&{jMmy~?Fa~i26RK3AOMn ziS4mnHJfqU^@+|TY~_eTTJGO!dBq6$+P=}dG3ssZ&8f502j zX5?IJN7xaLqsCHWsBu(IDhJh+YDU$hYEb>jv*nS9me@<|MPMPw%w}Mh^2_;$^dowp zJ=o?A-ne01x2jQ9sU~bw_7pq?pW07tY$N*uxkR ztQXc9gE9UyrDM9rmUQ%}HCa10)U=?R<|Z3G$uXFt@iYFS}DpjS4ln3YJ} z`~tr~4W>FXftpCQv|3tcwKG}{GrNfZ26gD#^m4Ea%(E6)InCT=U(^c?VTLh~1aTTn zg*ELub}_Sv$yuzm4y{KDL4qA`*R|{08^A`8jm^rcjKUnU58Hpjf5P|u5B*z0TS7OD zTgE+bA1uK0@qP2I`9Jf8d6}$FQ>Fz|Q>-r55o?P-xF6hi<~uW*8buYL3Q?!&Gju*G z548ZzMJ=t?R$a56ImjGfwzOJV|DkC}qy(xmRfSqgo@*JZ4D}g)__y{J!6kGB#h5YX z3W87I6KF~|p=EMi_qqGrJN7;MmU+WWU?wv6>3j4#W<7I-x=i)6``JlmlG#P?s!OV< z*05?=!|CDlDdsfOh;6{GJzmVtOeQa>~^x1Y_-JA@qOk#(^zUO zE%7YzeDQqu{1JbO+n8<4W%?SukJ-b_V-_$|=*jdK_zfnKeVmETLN6on7_>sxP;4xMeBlfRz5G! zF=iY6U_ZD9u7!Kez2>vvli;nY76%_8UN^Yj<@SNAGul@y=@bYrRs^_awcEE~s8 zWu`EdP-Rp*QZq6xJT_d-tY)sG)>6rI8eN}oTgV6-JI(FpPP_|uBAMWnebNpa5hJKa z^o!^mI>(%2o)Yu|eL+X7y>(Z=t2ecpSQTJd_yNDi6|_p)t?;ezYI&7B%o=9BW#6%j zTnk-4g`dJQdMP~`j)Lc?^VC)58nc()O>ecg+HJJ9+E#t5z5=a4r>N6ZFS;k46KBVJ z^}YHUeXZWqZfZ})lkjE2i?7W$=0)wIw$0dLTmToqedZz4l%PA^h0aeGpdZsu=+10s zc0NHHx-IRcJXBVg84kfia7)k%e5JloFR2%l!-w1PRy<4}p+8feDN~He#wYX%U7;`0 zS;TB&N1>yTOefQ|2$yfOwpky{kLEFw3)aH*@H6}Zd6r?b3fTmOV3aUY*val-_tE=l zCmt-yrY2jHEw>^miQ&ZXQhAB&MjjMm!>k~%!Y}$KT^JQ1{8GZsN@b;FR$*oGe>s?( zjI$pO5T3kG-=*E0hnvJsVPjx4EM}FkmKsZptJYO(G#*3r00b_}XI)V)EA!=raxNo> zaofISA2JV{wv1#Hw!%A=oysV4w7Hh#&3R}(Dx?+Cz7WiyW>Edb0b*^bh7{sLoJ_c& zmR?&o3Eq(P{bGHw4xxQ$BA$wW<6rnE$>RBN0XzXtfMe*k#xLu)#gg|W;}oJ_T7$dx1Di6Salkxa z?nQf%6X)B|Hnfr6ObY~cU|ranZbO%5N-_n>b6pQNK^4mIK6{TXM^~UL7!{4{`gMH< z(K`(ZA}B=i!Av~Gm}X2;C#r|hA@q^{O!uSuP!bYQZZn_xzK?L(23~BJ@y{ElvT=Vf}7xFa5-5!h3vdh z(2d+^rantArK&pEQ-wewAP|l8$bM|UCOS1glaDa-d*&1Vi0hhl&F|VzZKys>w`|jX z2A{%3a4B>&Xj7{x`Q#(kSMU`?(LVYidd-uDuGE+5h3q2sEqDuhSufj>@5FCp zHZm6o?{u^}Sw+mE<~ifMalyW1JGrAMEC!!YkEzOZRr&*b54TZUDV;K?d>|j_h5Di$ z)(&gEwoX%2RZVXtScmZ;d=8$4O9>C1rp{4CLE(Qoy({bna}(uW7MI1-NIaDWWx!t& z_vNXI)LZxlWpulnpSP=A<=BZtl?H)Y5-M;tbZHO z7WnNn+tKwhB~#98cTu~jlZ3-(kbJ?LyqTWF{}yT!wUz9((Z*=wgYnULf*zrwY*98S z1cfc^c6KNpgr8f_t=H%^N~6-KOl)ShDbtKW(1wL@A^h5YWmmSV*q!vwdZS2#$e8fB za5uS|oT4Rb`A~jz2i}3D=rXjy>TG|pzxab71DBD@2C{=q=0@|BeoC)t)HK!*ecB%n zz=g>(-=c5UkH|-4BWMJ(%30+us1y3d{o=;B#=0)Kue#%0aju=>4so6|NBW=Zl`A9! zgj_Hu?5KCtpR3Q*$J!&UpV8kaK{Q*6_19XWFV-LFPxLf1#cXS}vD`$dx^1t`63+Rh z{nkoZC9RYAB=JKJ@Me39-NI~X<|JrKuuI>iUs5h9t0QY7xs;qrv=w8$BOa_5>W$J7 z&D5D-mOaNVgG=M_1VrHJ)s$+=Qe&xsAtoAe4R=g9D#VKkVuBPewe__1IA-cd+_AW$ z(MO^y3KfNnL|<-D)+>J_zau5hQl?E?w1@EhB4#m@%>H5HT(Pc+F_U6$C*4gdnYl#f zGf8KY&c&XK-R0itUc;^A7SfC9qs&nzjZUSDprYuAeoXIVb~0sZG=*DzBfx{b3v_{%4d5=6Q zGAiN?x`M%!P|7lbtEtygr}!uP7e$stzU$xg7Iq7J1+{{D#y%(B;3+kTpbT4v{Rlt8 zil`Er4yVBv%u9w?9i})_jDf^SZ?-mDKkV=JTs#NAhOglT_5xw_d#uE{xWnRMqA072 zj`=#|I^aXb^rhQ2Kkm1AS zA6I@{@?Y>DRu8EmJ*0OhYhKtaXf7k`(uM2H<>7L3n5LNb_#M7%UNHw7gN({X6{D6` zTPqkT6gd()6e_F~ReG7-&AeovOO!}CdC%dO@61=`nea?F;X2`3<67%-^xS-cs|1Zb zO+6o@K1Hqbt@V|cDoQ{2AAD(oP22{qjnG<%5`AKMt|IrD`NZ^Od$C&yc5{0;hf@x6 z2e}Q*24)A`1#c6-`3ydT?LZsQ!|rA8GSlG5T3fCok5on|DN361Jn|%>$g131?XC7wdMPK=lj>3Zu%3zdo}yM!E74AG zk2FV_xvU&kRa66oQ4l@GPw+Cd996TbT8b^(E8!|wnD~d?U?=!!e}$d+eZ_X}w(jblnx0Ia%$_Dd$ zm{=5tX6Q5Y2ikqDqtVGowo46@21RjNszHdPAo@m*Us0?ag z*Rv-Rzcyc6pq(dhbZ2FPmU>J5xN=g-7t9yTn3j}Q-Cx5$DKIg>hlJ4P@TPEqNWn-u zvQEuWOVpF;$;1h<#3l9>RMudFbdY2|FI|(WMa>}&&~dNbNDkr&M&Z$TwY}2bNBnOt zIyYU9`017GN_HK)o-M={WFL!<#QVN`zG>0ZqTk27kGU0lJN9wR(-Ij%aob$Y>C??A7bNfaJ!-cEh zD)?^xFr$rV!^wd;$aAPlRikDw)0w~QU$zt9mCq;Tm7o`TbHwC`c^~^Own1$D*d&7M zu{UEI#WjwLP8XdnD%Ka<(c8&uN~Tmzs4BE$IxxkkV$?1Y-_>AsI0a6IkL*XbshCRZ zNUKN_xv88<&7y8Mwi#vBvg(fHUCDQU-u^iwZD!gdbFzXZS$~bc zMmxKmJ%AvKl0~`y_x|6tVOgWKoY=UPY5Ol&Uh z7Iq7r#Ezn$AP1kFA5IOYE)gGdRllN-AbZEuH0`DKTAL%!l{07=wI)O#6~+Z|K0Y5m z#W&UWEb3|0WzS{La@Pu1f2p68UCJuCM3-2MFU~v9X(P3fItGpcil*t&>}d8ddyw77 z>|?G|*Qu#+Ds(uw8}5wr82OER;k)4^f1>|W;B(*!$(iS@)7Ex-r;~cDk;X`)EozM( zFb|j%CY8~UhQ?`Qw1S}mp|C&VFA^yl=|=qZC+o9y30wlrsAg0JR323~svB*rc2*;* zG36&7lA}1vrfpi|G;S0-g8fOn4$UykM!XJhB74WMbSnub;cj|&eWS8P$zY~8x8WW5 z6?_4GOcb-3-NNqTc5>f@FTym>bWg?TO3@*2*jrG@FBIoX@#oxU-0Py&MNNnrA7!~M zw~J`-Bq6;J?@jMr9=$ZWhOf3Smy}C7#h&gp;=zn~dlBbNyT7Yh+W}=CsRyuKX$TyXfy($up8O2Qmj@195>p zDZ5hs{7L@PIJr^ss^IcqNxhUl56wd%5CoR3+a-)rMtc$~2bqJ+LT)kVW;_f7Xdn~+ zTt%)X|5kn}yY!vTV;cz#1xXSm&ds{x-HGmG z*I(Cl&oz(a^Y|>UK~^K|)jb-?0L?uWy%oI|+~?g`K*9`eHrIe|K)1(j@qD}l(~yG8 z(NeVBT5i?EHF06O5Z#gM#LW}t2}_0LLUpb($Iv|82lN4h&>%F-7-lq)8_BD}tHMPH z9;ZD_Q-5o}xBlAl>-OJ!fA0kE1veWTjn1G8(2$Pu8wHFr>M1o~2F%UWW~v+0l{tql zpm;4-`xE{hJ{mb5$zo(Nd?*Sn))(rFBiZLMbR4Y%ji}lL z@PX(KiIJEBFh87bPB*XW*YqpqRntoXrLEDy7^9EYp}`nE?C$nw`UC9~q6MAS=E-B;py^pxq?yNIBFlYuMp4D6t}=>WOqFm|0n*GeoEim z-`y9y7rf97+-s$^QX_XmcR8WFa1Go5RZ$hx6g5W+tOeFyYZviiL(y0K4PRldFpG)i zspzTb$tC6x=h5@&N9ZwHW2`X@*^qmM`h>;>#|B3RMh0@EWlziI&+caxPMMG9B8e5* z5&S4Vo=IRRgox_hVpoP$q0`5RHlxk{YCpAmxO=#ZzpKAVTH~~`Y30&h`Cs{WDBG1B zc6NKay~93e?YH7_0`}7(dbBV~$jWEsPkkYX=F29f}EZ~jF{O7a}p{)CMO9CI#LoZxoCGE^n4I&jro|_9Y)kj-*A>-Vz=z z&6HtQGwYaZ)-~&panSHmK5Cb1yQ^eenYdpGzY@%JM!GXG=VGqLUW>h%a3kSE{JZ!c zuJ5jM-~yOUe043khAeA}HkuwyUt}+_bzmJBB#4r{QlFTbn>ZhI9+kW=GnCAXA0jo0204?NxVpDWtu^9>V6h>rg*ky)*?ZQ^cB zltnLhAy^plGAC~j?FjWF8Zlyptv-5ReG&QGMrM8U0rQZF_C|ZN#AS=S7ke*uk7u{% znfOd>E;X0Ry2`n(i`T@DM5E6jd;bFg!|_}Lt{#^~$SOdIl7@=I#P(c!t|4pyt6J5q zT6!J50KqNerm@^uX1rD3sPhSW5cS?0^aj_6&gXfC4-ie2ALTypp>D1VR_hn9r$1@Z;_c`aGn9!J(~D)j<-DhTCww(LwLSI4`eFyZ4gZK} zx{HJd3i*ooRthTxCtnRQhnSqs>OA>+YP>K8n}f_V#%Uv~oz>n>?WFQ>xrmzI%Q$mhZ@;Z5DWM*WvJW_rWejC0PxDhCrRv@ijO5K!q{&)V*#usBPwT?=p z5~%)YAUbXxw>sdC_zv-4Ex8t4c9a8sR6Z)p2v^@AxF2~KIT=1da4K9_Eu;b)TZO42 zR1dZ{3j~YbAZ?VExtF`w5IFVqMqEQ~6UpHzLW;1!wZOGdS|B+dCQ9%L5mshr(z9qc zBQmSmwd`@`1hWt90Wo&0y~tW*S5ir?pU>nUx|+-L{}%{RE)|#B^X+-3=XDevLoLkarc=L8Oi4`HN#K=z z@-=)N=jZeD1&9`H;%era?VjTvN)Y3UcJ&eaiC5SwECXpM0|h`1{Hqxb=7;c4=qEHq z(bOJ#AH9-f+&|JEX(&6CeXGCMgMmOGUoe00xB6XuL;ihBxuF!$3TT({1su<(=QDaU zc-uv_kIEoq5UN`>EkP5BqtC6CREw)F*(1LTzYk}Tv&yrT*-C$PfO^I}YaYReF+>n; zFgKXh&6;MSkz{nXJKCv?pE<{$4YRMX@7?O8L}p1PDpkoyF^N&+T-?kBk_?= zJ@hKL32LHh=poVBpUlsu5Bgw;5A#m{whGZ!kK`wEC%J>1-bioULN}3RVzaB(S!->y zHGbmXxS7~gT;g5i{m6b~=jjXdosk`pjp2>q)^cn467gNfh}YtSY_NNr?PoXyH+twgKQCGDcd1estF ze_?-7wU|1enn$f>*RUL7(E;s%)(Le)2ZcjI#;8nDh$P+~Qcr0xJ%n~@o8y@A|1_tq zV)c32^R#il$NzS6zz}_i-kIsbyyRc;UAZoVcN=gyq?}SdcL8^AS8vxF;gyh{PEX%P zchGQpC|y7*CYLVQGw%ukt{@;2>l+QQJn&^~3qa>O`n zBoXfu34{ZI)L?3Pe_8)KlB?oEv7zGrV*WO%ZBy5!u21dc@8ln=j#IzGA27^>nND;k z+UZkwr@B(J@f>^_okSO`iJTWmvgP;aUym6LF_!5e%Vx)nXeoNCTc zW+UM3X)>v(*?h73ZoeZ1|e3d`TF?O6?kt$EUVqda5*iSS zujKaxJo%;kl59up=(L!$@4vqPI_N*>KWZE^isKTvK5BrRx=CSJ0P+$qjffr={nq`? z?P&0>!5%?2M1`&ySB(esBl;!(lHbH_=A0T`tPmq)bZ2zuBFIU6sxu#QN;$3Ei`NDhpLym0at*YrI)~Ieku@ z_yzMnW&}T+A0dsD?(z5d#>AhN#3k`Pd>@A?g<8w3VSJ32`AK3aua(C#WK;I4J~c}B z={1#_O4V?+@a^E8VC!J3;5Y4uwuxEKw3j+b@q8@5mFS}>Xc}^IzL$K;A^ISlK*dvj z4g;Qigk@6 zSm#>n8X^o8oW5$D6=xl@j#@3L*3@P0BDa~}#BX7?Fc<*}L&@Q6b#?N)XVt-I#ZU3xkY2Yz#ZxOc7(E}z%yJV*h#iU7|A@cD2JQy#bJ97f z7+;Kcdcp~G0$qS9z|<$6X%aJqc|*OS29iDD_}+!oe5wi4jCn`BqbA~sxC`onoS8BY z?WXrp`>FBvcsry7l^q1Ttv%L6dK|r#-Olc#_tKN_WqFNB2T#x8~k@!`|UmoX4%q^E?(W^Bgki@(7C!_(;*w4+0Nfu0}-%n2V7uG)_dpfA)Hsyb7XS&o*WQTiDD zfVx-BL)2h#vzXb^Y-OI+PHXM-_Ihc%jQxZ9L50Myct|)XEWise){wSbU7_Al?kmZ} z`{X06&%6JV zCQAdwLERtP;?Qqsid6wKX&^RzMG%DoGAmwB8v2*A-bPKbY2~24Apu5v2-6!3-qH{!l^M3c5 zoXLHpK2x=rT1-2-E&a-RZS{=wh%8B7lsxRuh(AYyhl2f3U(}py$xY%X@%Pv}>^1%d zKiM_OmCc>Qy-V6DX`I150QW#1kQYqnrgL9hpIx8apWP8+PTq^}#DYRWp%34icm5tP zjgy9nL&Z7tJQ_d<>(O=S#mrL1>8EA3GuhviZ_41v;7B>8obti^WIFQ`eayaQ)j-ui zd}>_koWT5mM0C{+?YdUQtY-F=`^W|S1^i!9zoga-R1fqH^$oQnd8}eurL>-@y;Gm3 zK1)p_oL|Z+Ze1q+xidj;x)*(sK2H~eC15;xHcsz9qnW`Bs6q9q{#YN2$Kw&q2xcj_ zl*`Oz;Y5z(yu6pMFEkRCNlT<7?j!E8=k{F zzDqwOI_xF)KQ58v#dF#@?Wg>Mc%WHItQM<{&_-(04rq>9$*eIgNR0+!B6J{?tnY5C$FagSD!njo>sg5?e_Q8pI3hxMCwJ-+v)A>I2YbT zuB#~`ApGihgDX*&qqg$fctX3{!NC3ikSTdJT8TapUHOOq%^zU*vrccyEBU0G?wjs$ zL?1U{nliJ^+2$B|v^-IsEKkxVYBls4`a)%)@-6fwG$7JH;^e0sFgq;8mSQ{co%pTH zRwfntVH%Y}-3NEUWBsY#Fw!^@4243q<(e|qf#K36{bKk+cwl%y*w78#iJJrbKE9XK zM_Mhc7Cs6egpN@iqVxnkp+#b|#9(wJdMZDacWROC)ix?a{A6`p4G*P;P#f?jycKW3 zrP*@qByp11%iZ1Gka*(>o(Y~fK87F7j$#{$O~jT`D`^?Kgk1qvg74@Da(ZSg!!qlL z2OL9>q{|UL9;J`eU5Zzks7=;3Y3sFTk!O*~p~;~P!Ng#faM$n=`>@?z=pk65DfVak zvCf{Jj;G_lLTSan7X4b|U9ESSKV|u3{j`5Z z0&-xCJ=%7(Uv_U+@5Jbd(GBAp#otc6lQ<}0P{N0p4>6R7@=T?t($~!E=1>A3@B)GG zPk*K#V{#T3Bs`hTmC5DQ*jl^Wx^K9yx}LDl+2i(c`?`KjUqE>M0sWA!&o|`Pa~rtl z)C+0?7z+emHJBs4q8=%LmE_qWn?*M}bFyy5Txur+?nuXkt8t&)^yH zteDN0&G+8(!E=G=vZwet?qYYg^An7+N7!}kdiDZ+p*|}-JNzf~JCs$;s)qH5{+~Wo zFH3UD75Svdjj&5f24J zKvT9UJAt3f+b+|!&9}{$o=@OkSTC%8R$uFd{nB=3!a2Z!dR9FP%UE7Rw2d>j!$_P| zFuFi=-k7{G+oi3NGlRDZu7*$1W0XV7rTq&34u>P5h>vLPreY#?i&lD#fe>dKZyR+TdEA(ahmHo;-t{>MY$P?rSq57d|B%f8& zs%Ybk2}WzHwN(fg#^34hv?W@i&*Ss7bG37oxGN695S&BLrMDA(zk}qm3*a1R!?a<(abLMTL@&)F`DT7(PGkzv2nkmFzdl`Q z67x+6y5eqlEnb70z{c=9`iVr1*Sbf#MXt-&?S_%fN{{MZ#FPzSkoybu@nM7PLH0th z02t7MVX}T1i4NWFDTGLPp&t2k~&WPMak$bK|N5P+;3&-Hpx?xAPKR=!+haB zbB^W;3$pN+`b(9w%2^>jsQ)y7ng7{S?d9eQ^DN=T)yi7sym8)W0b9cMOgm;4oB_iq zjK1QpxIC-~Z&A0Ycs7A`=I6eV?|rqtTFbQM+L7?#@b}=4pi`e85*{3$q)pKhtn^lW z66=3)GA>P=Vm>x6+uqgQ<#J2zpY(4!gPCMbC2PA-UM&C7ergIKfT`AhRw+~xIrD3G ziI4L|d80bVc8N{$rT2~JC-9gA%rx{L>WaJL@~8p=7B&Z%gUv+*jvvd*<>f92=Y`qq zEcOsM1Xh?U|IHsswq*Ap@2P?+qozhPV|#d8xI(Z}@P>LrJ%di62v7(!wE{$**~mbK zGxrptL-haX7xZy_3@;-4wX$4M?xXfqyII|=0eApz2AY9YMDK4lH<|@e0rZM{!#Nu2 zh3A!**5G=26PP!h755#yr9luT3 zF0}Wx_ce@b5ceqNam)eNe%D#%EYl3M0G$a6(uMxboA#u7P|wkGbj7-6&9-OS>(K_Z z%wB4rF;APXjW@1syYv88yvXW>2Gskwwp< zLj+K3vTu)2hp2PlJa~m(pf*|?EffxhTN`Z*g_uX4(~dq@Dw-+s?t^I zN^BMO1Ad2pnZM2SR-zTF#;Ea;^bw?6`bul1AA!RjKGsW6WK{@5 zLFhx!lFVk0>097g;Ato}630-Z zsljkClzD~!>H6iW$W~-O>7R5Mff1($yTV>>FJKn_(}}Sl9gs}XoD3(z{o;PHg}a&i zlki#i0e?WJzjnpGY|jDnz-i_*Q&K1?Okl^e4lm9iKIkv;qo32q+2iawc5Qor)!%Z?ZTuF0i%osae0QZ=(o~{r zb`hVyIj}iUoy1~REsM6&UTNR3Zdw`iBpv8jJ8T`YoOpVQ{)hJ1yX{mn%^YYCu;0RW zFcX!D8i9tPj8;Y~ot0oYTJ#3E1|lTkUbC;0SM|3a+7IlZcsOnbo4~4|D(FR?*#vT} zwqYCV^!555cja&;MkhtLh-nd{Mk~?nqdP=*h-n|Q z)wk7GldZ`*XIN&z+3*m3h;}}wTujB7X)%*yoF3myI1{EracHbH-ugi_q;uxrsrAe% zua;Mj`j7ad{jvVN>K=6&;e^lTXLFso!CYsoH5_f9&W^L4*%lWou|ME1cn}}LdF{M* zIirkmT0gCqAvw%8Ez_;K)j!H#+@s$aPTCV}Y)IuW~P!BkhWt3!Op_)PH` z<7G*ee%U|lCFT~IzNoo*1h;}&ZHg}UN<|*l!>YnVL%gy6PqTy(2WLo5Z{^$Pp;Sb?s z+EHyE@$bb#B||mSs;6BK+z2#O8>oZrp>_wlJ-wHB2!>*)+{Aw@u;yFkjS9wR`?KAW zWTX4~UEP_ji&x{+)8Vt>DFi#^9dg+~*}(YJiK#8ZEy7ck$;u7orcy<(s{gcpTFt1Y z6lQIrdupVqzsjJjXY$Xar?{)HY^eDvNku3wO+tuwZdS`u@IozxY zs(=spBd(6BBiT@mLTVv3rK3iX` z55_yAexy+(cO+-zfBFlZwirvXBX%)R6r3Vlmlx)P57~!o6!BV*J&!#Fy#>6ii*b<) z5(aSnxf9$e&Y6WQ28x3#`c?gf`NHfE`@*68P~Ptic>hNIiTdUF?K$l^=^5r7?j7r% z;La*$7I!c^nF(+lY){|<5-5$!;H&WRzd5R}=sR+1N`2Vg>>h%S1Ys`3eIpSzk(xw# zkPkVY{o z@yLnDo$#G-4Yj(;+ML}Jbw^DIoLQ2*az6Q7=v-)zx?4>#lg)Z|eLGA%(3!}&$h6?p z;8E?kmYdDZz9i~uFF|XmrL>eF#q0NGjn5n}WfC)SNnFwq?-6eqzBJ#EYs6LJ%kzz0 z&0H>@+gIFE#B*FcDgG9I2?d1w!dLD)_mp|YI5UaPz_N2jw+3B{b~L&(m&mI;*>h*Y z&b^doN-#^v&zizd;m5(Ta0-|Nmctcr1HFNsMYP=@JQ!CBR|x0y=k^~89t=Jv`oozG zj>qZnb)uJ($dUZ&|yH z?bNrO`jf`$Yzz~{RA#HPV~L-y&o$s?vvb+iBtGZk`8Ws234jHy+-5FwHkyN6ltjH0 zUy6^S9!FjBUh(+>V)qw7F zC%^&opt)b$s}+`u%GW|yLs#W%@xf5ncy^tzR;c5xybxXp$x@2cQ|KWmJ@$5#(X?VtMD|JmO$(j{W3x_ZUB zY;Cc(+9k}AW?id})dhFPx8Ys*o&Uz4^PKa{cFl5CVyZBs@ThEyN%3Nw7FLgT}qd(i9JwczKYqGUiKbJ=S_dD008bCSs z;q*mYS}m*#_#*yJyjmH%tW6uxxM*B5+?0!Y#y#gQlKg(#x|*98o!=GJ7+7 zKZ~El%xo4mFO!#XY6}`!yCdPF;faJt2B`zpJXRhnGtP|DS+Q1gxw%}_U(}x%NDQn} z)+nW{5|(qG`66?Har{mxTmZ&EIlqeR#%y>z8iz6vT{Ov_XdBqVeF!q5Oekmu&FsX( z93aoVq*7XGAlH|F$-m_x;UVF5{x$vvf%<_K!4|=efzE-QGmuiz29k+CSVc921HT9S@ugq@*UNKJ-8K&kxNFEetLUehGgIkI+Zz-OMiL zDeJV=19pdv=qB`A;w7B3wG9YoeFUGtCH6Awk-X9>!qk`f%e*t=?#wB+7TO4n2&M@$ zgfe0ou@%>X8^I0Zdb;|${GL?LR`*tSGohJ~h6DJDdC6Ri7vY)gboQ8dLL4TJ6l)Rv z=G2g`;43&6lbc!2EM;io3$AN7wFX*!tvl|9ojL!<>=QN%mz8TvJY5P(K~3zY_GYvh z9RLS_ljncXzv#MD9jY$TVmUzef9KXQg(!~Um=1JD+Q|nWiB3!>#0#+`CNAk$^s&Y$ zqb|u&U72poW8skih;rP=?c+Z4pZS)Ai|dK?#Xam^;<*oi&Zra05AuOdR7a{A(}GD9 z5``!!TB=X7F zfp(&r@fFUw-of->I**V?SRl=poOL`y zpP?P!`p5gn+bX_ge5=GZiM5hyB{fdpH2wP6b+Ju-O?>ZM?_AM*6kh}v#$A-|%Bsk! z$ZDcVqNym#IU`dIRYR`{uZ<0i3498C3{;C$jl3qv7t9+Ro-!h(LR$H>vP8??r|wf1 zq>EA(S4LMysslAco2_M4GAq5*zUmx#mOLvoD>UCf-`_5^UFreQK_rd z(GFM#t;_aByQSIOoUY7NUIktR{tNyWbmqjjncK{IMtvjRNN2Prp8TEqPAyF$_&D)I zWtftT#o63IqD39=zf@nU|4_fH2g3)$Mnoh2$JG2rit!nJLeJp;AVXqhAnuPlfi7Sc znu&^`qNq2~NHyqcv~yl>58i=ygS{X>m!G>TU6T^r32wzDyAXNWm#9lrGET;2VHtRt za7IJ65t}Of6)K38#n;SBrYtBAuGv@ZQD_Wu>XXilhBKVB5AK1x>D~Wo@GHfYVm`5e zxQ?K&*hiegPGt|$2k2T{ZEiX{jdjjTZ)dhKgN32O6B5Ih$p z?3?&H_D~)w7n_G|!8Bu7ilzF~1L%%i2dP@27 z@~UU;3$}BPqX=D??umQiIp%D0hB`wHDj{W!x!QEj3S>938LFzOZwZE|L)9XBA^m~* z$V_i1*z@rMd=XxRy{SG_9pagy_-Nj#P0O}yH#3?V&Uvzk8c}TT|8;j8DZ>%H#2?)FPT$t`-sYJ4@`Ia}kL1I|Qerd38`2Jr*O(Yc4lUO zpZQXF(^@lju3j9A=Z#Hzm5ji@eBh1PrJCJj&MR9xuNP{V&849q#nG zm(okwTIa02_Iu!{_1? z$jM}WJRd#@;88g2rK}5>$9Qf6*O%@~HzXQ@O5T>JN7tpBG0m6=9j0q=HMvB77hi-g%BQ+g zU84bKSjsQw>$qyU5?py*DO3uz5M79xwq^fBejs(IdekOrBUKlzi$cz|!dPbX(+BFX zFIyut;sJUe9gU1ZAg_7@VgtVMF9(44J5Q8HfA>@yxviWCYT|8B2W;E1dm6nB3FOTf z5P$UF`em{d8Gu2(kKnUMRU2m%!WOHwbfecrSR2o)kx(?2f2e>U9F)y zx~=E5a#>@|G3FL$tFwq$KqO($Fz87G?~lI7pXFV`Zeg>sNrC4q>y-@()b4iEx@w8~ zUcH0e-rfQ4knltt>Yk=DQKFT)?FaTmN&XS1_8*qm&85T8N( z=Kt`oU9VjA*m~?LfF*mQJprQai~b;f68EXQR6&5@Sg`-#o%KPGw+92P@R9yV&tYe? ziS$l-B*3nzbSgatVADa&K;|^4n<641`|Q1T6M%&a*@bP`(;!nawFbm6au}ITW{@1g z6F)#Ls-{=fAIJ~nXHt>`Iqw93G4rbh)NWFD>9Bl6E^n2$wt=+(dC)oMoO8)MZ_co0 zT9=V4$O8Od+`tTMhBMPCU>C6A8EFs?;suxj%uIF$n@**JPq`4anqAEv_a5{1i|HHF zJ$v`;tz+B8wuo*K{loj+JCq;BUuSMId&xwyoKwzur@hy%=$G|r$PDBfah=!$un2r+ zzd?Q)BaRk}2!(|FVnNX>y2PQ8VG-CLl_6$`|1+zYC5e(mYo-mel3Y&yXZ>eQkSEEf zgfl|JNP|d;aLI7LaG!9#aKW%E%!h@D7!kogP_G-ZvaC!r3x#*L$Muu?d*O`$dE$O~ zzueYnZ(P@|YP3qL)8!fRKIwooU!SLUMmwYRi26i6DuFsrTqGLX4eeAT-PmvLHIJ&t z)G|^T3HIs|G9i!G#%oz1|Lt^kJN4{3c5}NKs8ipqNA?5z40aAfNQAtIU&I-dMh74R zkrG4+Vgx&!P3BU#&D>UQDZ7+~{nQJ5G+h3G=`LXZc`@n!jc!S|9}39dL@oNkIY!5<;A?%8{`cF>#{%!iTFh%6EBG8L=yT8{nwgjEz_6jUc+lZUfYmq$W-O3 zaWbZ2&-Eld3d9I|g#7}0fz1P)i^Dm*rcu)vCJ&Wc=q>e~U?0a4F+>cS4J~FBvtX}A zBe{{>QERX5v=Xg|5ixeE+f@Sa{Z-0prLtOH)xlRH*tb3H-uC~{Drixx81@POh&QF1 z&{N6jr0S>+Yci&&NXl4wjGSohHg^+=#4Y*;y_{Y}=fdOhwboioG9+UOh{f6>EuWfS z9V3mAmI*6`DoQ1#lu^o$J6^R|9NpJ+@lGOeIB%bsCJ z9Krd9enZ=$ZP4M!2qe25Yr}JN=mpc?8fdLVRv>+`-WWW~e_|)u(4Wh85Tu>m7Ob#_ zb_Khl4LzkodY0bK>S)n6X$PI4lNZg0wzgZ^TdYmib^E5h#n@_~8mj%P&C^!NYvenT zyOEpX4RO7?QT@lrWwZzR5}ubrud{K^B&UVb%;}E~Ky%=6IP@lZi@ZZ7f&U(jL?f?= z*Tg>dKTtu}vFE`$eQCY0x*A=K8|F3hjq}F23)X?eO6*C1iCi9+r+_!V_nGIpXQ+FK z`!;`zf6P8%^Duds)8r{~FSZ}6j@7^_5*3M9Dw?{?US=1%7Pxk@yV%LZWTG}&8~tv5 zvvQfaOsECQW975b)eLoxG+Sy6_R|b?hFaJvV&z2=kZeeHWTZXZhWB4kbFt7~WOpz- znuD}~TB?*H?GSbdou$qaCo^(Wv56R~#;FyYiVoCFbR|IW-S~8Oiu)b&ff+&%q5rUd z*v0fhdLGDYZSi(^8kUNcKue+dhw-;3$V)F5k+n~}{( zX`>`y02hrUC&>XHJIVum-xowQ?#H8vY{V1dF#+$fqmTgd(fDY<{)IorA7ijJz-o_l zKnz^Nx0Bn+M5y%V_wu7XBR$J~%YB6cg#yETBYYb@8$1U+hdn>oZ)}>KVULcCjBNe6 z<>%ZFb3cGm@iTWgPq>@dO^lJEB?Hvb>Gm|6b695xIv9Otf3Pcy6~!j$P18SRe9R~< zloIkOdBMu9sPtBPDWB9&>T~0zaTf4dsJU+jF#1$&s#YdaI&wxlC(hO9>Na8{`Kf{c zu??pnKRALOK~I4wiWSA`OJ%fEDL+fzGkm+S2=jEF_<1iZvz-|1_=0CimlpTjW5PLfY&S8mF#NZbA~;b z3a4?$=_54MN(6RfqmByZ-|3`W%sxeU49S`_=kKhP;<*- zWw58#bL$Rr8%f5JvDYBiwRhS(b(~txA3Mc9jvPgxwtOkEgm5D+q?g&tya)JA1QpOQ zsG)PwxoDh|-5IY>)K4iVl@dmAgE3h%RZf-x(-&W>Z&g@#nj#Gm-f=l3z&+!Iae^F? zA{kPqlwFBco{34~s_@!yLMU&jb+}b{vOG;bVIDIDM|7H?jnSd#Ff;{V(htN(BFsnl zRIon(1AA{Zzy@8gZkR#nL_ffj-cfI;GE6xpk=@OL!ogf-FR@`)#I=Rr!sm76cO3z% z#o#Os=IClzRct&q4ugG7Tlww$1acf1wnZD>?@u+R8%5Eg=w0?Mdx$pd%?jx0)1SjlGDh>Rs%~DO#m-!@Qg|AfP6^aCGHY&5I@D=VqPP`I0bn34e~Zg z(gdB4$;XspOR{;`yzG1M9y)*;j;g2%{b|Nnqb;b1hBfajb{?A#_IgRW1U;FaM1Lc` z6OacCG6otq)Env%^N1;-BDx*fj#ShtX{dk;Uxm-YaC5jRk}?TBG6p#V9O%t5Br-U% zL*Jp_MeZPiC0cuwJqj(b0woYab*q-e@jU<5`wGh4Jq105Je7SFe9NO(MCZ$%KRX}o zj$XnpW($K#3iZZau&x-yX@+AtP;V6%${t!ASrW-KG7RV`lEfyl-%$tPfTaM0>IW33+gFcM11u*9uo@yezKBlKejW zK70mXy07XN72eZbGj14z)j{fI?Xou8nr-bwcc5MIuJ|GIpqVR_E3_|Ve+r+)!ABtMm5U&$JCz;ENPUd1DT=a4 zSS-{I)(VC*Lz%zDWHH@IbB@6nc#E68``8}b&Yzmp?VB6E`G zCU;Bema;RvD_mSHu5JgPTOYNz>Xm#_HM6?;50{IZ;+^81&d=f@@7RYO#6&!TPh(~> zTbV7)2x0^Qd(ejC!| z(l~XTsv5d69iNJ)fj7Uxv&yr>ztdkewn}W9Y^}0w@NV#qVa76}@X>e&u(tzLfSQO* zLf~4v8N3#JExZ;~%dnd9P5JqO1%Y$E)4oL49@iug)A?yUyaT>x-?bmAkJNMFbKwS= z4KptXuLM1kU;3qdSDLBK)fhQihW!V{)e>qCv%7iEzGp*T=ePa#B4@F)liW#S494h$ zLHJQ08q!00F}aw0K|U`R)rx94L2k-G)6oIgAgm-_63<8GC5zcb?Kk3UF+oTWD2bNx z!}Be?C!UMQMU=KmTX(d(+F|RU)dXO>hrY+YSMHbY<$w#k2mHO2(cGA2&Na6HY}3+d z?(|dpt2yKx@+xtacvL;A4j}uJ??6?@+=Tmv@0zcjudQ#FC(*Mxuq80TJJ$OSdxw2C zJ{u|4A1ldu?#w}Fqqjhmv&ve9m7>aEb)Y&D9ffin&8>2+a%H)LZrLrm6F?4HMl2`d zpcVq}hQmAN7s^YeX1H3oPN-g}qF70U{-Eh}I=#=m-+h8SPCnEgX&I4>$d2&NaF&v( zyhLAspL832CBKk6Wp>Qevb3yK`da-GeUYx{uH-JsmSCsYQ|*<~3TcusQFtl8ln()} zctAU-J(eCyl_C`**M#c=#3;}YvL4rftH;;pd(u7V@&Je3C-0HVK=edo?z|H2Jia;bDx>zn(2!3=J3w*&GDuAGyFxO3P+Xlm+(L4 zpYTxA`qlbsm9UCh{Q#y^3594uHKUr7ElKE$`wRUAFy42IQ#hrFSXfMx)8#e#8oeLD z3RwW#e9=Ga@clurs+IIIx*OA-sY%o#HW{0YOd(TXMPAHO(v^+cW^ISOO@``U4u4eHox+BI#OrP#PYe4s+0T)+n~1nixe&%jQM`AjO6N}UGzbGklFA1n+8 z72&f0`>yIBb&y=-Kjc$@_7boJ4Dv4&$8ZI_|HeckVyn5?tSnR!atZ$k<3MhKTBon% zSMmyVh04xmXFqwrc;`jWi*D*~=I_RL=r1cL`k+dJAs+R6d{TbVLhym7Xab_+@!D8Un?$^knE5Zni-lFdKr2h!X!+ZWzDq+ z48wLJJCWR0yan&>p#F83Gt60ytVNn&O|iC4Yo|Eai#tNQLj?e1J}4X#VE&qJ&M<46 zHO+^{6T|DcopMB3;v{{NZbCFA27vwaE8|bbmDEeA)3T;z&6gL*kIjeXZotbfn3v6W z&Rb^!HGvw%kLG1oWDy+4JDXk1;zm&edcxEIHS)H8>#tq~dcibTnkmn<7g|NRqI@-S zEpi3q_ZT{gZsKd^`{DoLFYGGhDvTGw-`H>L1IT^^_AT9`?o*$MFT`4WEe>cmF^!%| zk9Uo89r7Lap&s1xj($t;rgl*a*ahqd&j-(wsHCX%{tf=UOd``Ag5VddZSn3GIvh%^pS$CqGc{sk4CN{gi*nheJm~$>BfYYsxi6HdS+M5wx&A?}KO}(OCO}(1B{_Fa$xxWANeSXTnDK)Zc!7Ikl-O!y-y!^LiUPG=StGQ~pR)RX%mTp7CbIV3(6BPQG7AK35 ziR6D|C9ER$6n~5#bsckcis=$FA=~(D2~l~XOtg;Y(&yszEYP8w&78OAhYtF}dhK7mlPTL;8wkW-3- zI)9o!$tSszT+_Iz+)?T{HHDl)LXH1;b{zYhd&Z^EDReKiCwktzXu`AUS@Il!I+x2! z0S7OH7Dg+8_feUv!rk@W@%D=98FeE1RP@2XfxvP07z;UIo^V2VX>e)qz3@&rq8wF@ zsE5@$dR;wiMXZhZCLH=EEOO0vJs=;FP?t4O8YE2>r-;Wu6ampA(lfF@yf55VY9o~e zIdLJmh;*?$I|d(zch|e=T>xGx0`k5~b*p`~J{t6xgZ;=b=VAzsK>w6}o_?O1?%HmN z7HE`2$ftA?eZzgj-7e5R(8$-&SC6VsWjC@LP>*1!mg)e!R}5g$;#_eK_EAzC!S!(U zbUpVz^NtOS59AEw2t>Ss_o(}b8}=?WCt47F(Y|O)q%~rqIy#=5NEV>;(iHd{F&d%g z68{qA(Q;@Fv?e+b)X{T*-zD3>Y}iLkM2N`R$hycS>7rCesr`4aoitCGWzaGx#Z!EA zASy74pTze<`Xc*{y#~~9jzPzu5h_Hrq1)1sKea~Npf+vLm!qym&CWS1=K~O3vUkdU z-+$k~fnHD7vFcj4_Rp?*O)?2q5t#k z@%0Jx4nWVAry!q=5ylAHBU>XEl}ifk&`xu#IkwhXXB}6LDYf-Fx<#18NcTv0Q4qKB zn|M=zai)RwA{r5cC3!L@lao129wgJzH1sX<9_dc@Adj+#+5Pk(x;k17g?P+TOy!7l zR4S$vSDqP3#%1IZ5+I_8AQ2*(Va>2H_Go*MIl!E3PqrUpkFoYt2dX*Ul!m=sHHkVz zek2bv2pNowCPovd@H2QZyO_OI-K?&Y*UL?`rdoa{zY~wg0|Y7IA`(Wnm|M(aAb*@8 z&Jirhkd5%hxQS|LE%02L7>$hW&UR-8ItyKbEJmIJE}aw2g+3>q675|bT_rpq_!4{{ zrZEV!GXZe5RrX5zo_WU{BafBWM>a;8NmA_+O+-BwolNKwpWGpmvSM$KY?! z_bBvA*{Ez(s>wCv73wmzpjt=`$WgK^NP;)$2kWSR#y^ofk@dzpqb=4J`%V0YTY-2( zy`vfcT$J6F%@uJAZq=o_V4oxG<%P2Xa?!cyS?<~H`<{Cq=qU($#kv#SiMp;ju7`m~ zfho~bqTPO%zp<;4OXgL6j%Tjtjr*;84ZDi1L|3AlgIc~F-G&mN?)6~%uzT1<7WS?| zpUx`y|L`tmClmIt_Yr%Fw?WL3=15SZ$mxuJR==PNYDgVy53!rGE!a=YC#Hr|%jqI_ zl%Hk2$ZDV7A-!azLrl`br%Q*3<#?0D1vEkM2ej!5*86?__o` z4ZQWecYODJ`#t+SB|$U*A%XXu=-%tD#a3raV`VYP7VHzwNoOuL4}-l}(0q6nGnZ-Y zYU$eU-Qk_$pW-hQC>7K1ewzsjbV>kLY`lGmLt_o9? zkvN&F>aF6P?4RoY<@)N%M;0JIVIMG=(1^RlZQ>F75FKI-wHkxh!c|NSY9S5QkQwGQ z^PX~7sUNBz;?ueGGHGSgE@oWJz`{;wp|D6u5mJTG(nu+%mQ#ziqwJA@PjLiG+_COh z-^8zCTrf7cCAcG)EdCZR18h0Znr{V>2m)tiK>c%?m2N=~?wRIH6P|~E!9HP00DD6} zJO=Ra-f|x~r;*Eu!{V`T_&2;Y+6sjpTG0EhCcwGfot_SyTk*ntX--q8t3##X(i`cm z6feiiRY5R1r9*$y^~ibz_Umjhx0;UtCWE@I`Jgty`=@SfSGFz4q06*o8uU1MY(26{ z5v7T_^jumXBV-5-qYsb=2v0FoE_W{XboWem3>`z8wr%fFcc@?FPcrnoEeLY!Vq_5# z52B1y+IfgPM#iCIQP^i#1TBjC2rp3%sep{v#{wLCSpFvb5WJF0;th|HjQl~~;qUSO z*g(u}yX{t1YwMH!{x4sIYj+en5?ybuGg*T-R+!7p?pAjTuBBth5#+h`%z``&_J8(f zd$AYs%lI~Dhtt5WYfk}deX3`wXJPb$=(GN_{scCGEru1rpjSgNsu;C^{FiKxbV7P+ z-L)=aXK@60mc7j0=Ks+Dp;zon_DSWGaz(r>!h38Vh$tyqQURxhK6U$r!-A^H>Hw>s zHPjqtmNP0Ei2&>VhwMda;ni{IA>WzkMC5Y{I8Y<$H@)T?E$SBaf_O%3!MEZY zu?<)or>(Qy+HQTZKilx`=qh;s)0vq}RlYJ0c?-l6P%|^o9%O&hzv++UN3tTS;zVh( z^c}3x9nyB`fO{*h$;fm3Ie_mb+STr6L%)Y)Ek*OI0TrG}KtGZ>)@*BmG2dumx3r-KX+Ow$ zOPEE>BF`d^<Jmic5A4@eT30y>4&3JKi1TigD#|$GR`OFS$FpySnRvywQSh$`=OD8v3uE zbWS@YMqnzbki(hbe?3rPuTuX||Io|u^Kf~of+R|U^c&#$E18!vH>Yn+U!Aok>y!RT zAIFSmx^vyRclbLTdh3r6h6|HJQ$w(C^s)Lth5ikt)za#1;kE$vi_q`-EA|De&(vdf zF}s{6u=^j`QkYUSVN2o(oQ?5C;h+D|bCFhfM>{|9Q z5J#9J3>8I0eTexKv&y&9*NkpPA3zQvP@fgy!rW!=6>k=o!NIu=+raa`pr6wxpp(%~ z?vCzbzT-X$@Yj$Xw7V+Zl;`quxh|-waApey_A$(PKb`LmiBO0I>Q7C&It?{?(9^7> zS;`!#jnbYNj}6XB7w-`@S||6P}|U}tY=v_!Z*W%|Z(D`P6w-c#E3Z6CmgXhMf2h|?qKjWHyMNdQ1QP@wukKRvLz$#&i zAsfTxVW6^KmZ3M!Mu7RIg=dD7G9PDN&$^aX2Ym9lK^aj0a#lT~-c{}?ZS{7#2>1@v z_1si%s7c|Z@V)eV=|no2o+p$LA|yg;1|nJfBd%0e{?#s=Voo!N5AlWkVgCevJP&iI z0U|$JkiG4`=`Q9k?tkTbnGjNY>BsY*=!cUZB zOS16HyRWymcdB=qcPqb*9}akS5vPdr#Cht-sDx%GW62hD3;Gy!lxj*eCt!bkDwcw^ z!`tHJ?F#lZX{vM}v_JGX_&C@k+%#N8tSpw1N=Ze<;$mH}@}RHyI%hSM<=e2&r)jux zcwlf)aD8Z9Xntg2q?yn}*b&(g*(huh{!{m=vZFZ9sU+$h_m1o2>f}mtKXrfheD(-# z+5OY?!<7cGOJ(+d>?`U8^@e&)wFG>p1gIB7u))}8^NV@dIP}*$ASWBoLQl|H+-z8FmWzy&G|jxeBiGuCh!yrVv^Ph2HpM?6EfVa;U^r;;wTyxRK;g5(oPa_GLkT z_`G^PJxxxNcMCg&#PHtm{>Z*abMS1wOFyJ};=iIP>f&g9oDMx`;Q3Ntygxq4ncy7N zkLt_S%8}z7xpQ>TE3m0cTHjMZ2I8C*rgLJn_17&4E6VfTrr3 z76-|4OPUOQ?X zw(eo~u>ccbhH^u=Tg**n2tAC3Cv&;j+-y;%D3eV7Azz`d0j3*dK`)tTGhilL$<{o3 zo_*E2VkKC4tsUleGlvmxd{@7!k}SxuXB>KjEmRk%jkLzvRAs8NL)s=S5toR`k(9`} z@agatzz=hZxx~}rNwJOGN}jJR(3Ts^3^J>RVfFCZIK);3ok9-mKYDL`GzzPQRZ1b0A<7`7o!aql zkI*ZC?>1XotZZPd3`0gB?ePvcoL6zvzHSfF2kY6CSY@rWPFkicQx58fb=b$%RqLu9 z*G_1k!D~W|;eYyGeV95#jZ&jk*cY=BaIhix5M0A`9NxQCH)7ZB#j2iao=2|7E;#20@}f)XMfIchQ5yg_t7wS;(f+nNSe>j1&N$}` z;HP7VF~oX&JuU!#1vSRHZP-_gD@GBmhz9-aPl4ZWq&3EZeLt4tIOXhewrZ+o54)FL z&#CQXIGN5Ta(Z|N4qPlxn_pkB4rFBq4M*T`!GYGChj zcR7Y-SugFOp=R$Ab(t#46lP}ev-#KD8}0&iff_;#A&%omaX;?EcVWA+ub_r6HWvX_ zo%z=nfya34GFGZJE48{we>Fhk_LrujEjw zYc;eMMoZ(ien*GimGEx9oK{xbEN&5{pcot+92y)I85J2S4UyVv?X=zIP7|I5RkEwt z5-On3^BsDt7cdK&)4*r3PF)LD*)a7V;~!&^HOX?ByjjkyU{*t`q2Gz`#A0eOmB=UZ zZlBw?*}K`>+}G0AIi_RGinvvAZ{ps@6^|_vTQ#O?j4#?Bebal#`;+_5J!76R|D&o> zA|VhA$8tlwgS;=jue|B*bax+DU)KWHeAgxSMfW5S&~$8rd%e39RhlYf7qI)-{cHjy zP^cA+WwJAGh&RMYZMZfwJSY4q^gi?h@Q_k+N%^(#M#vq^9c-M@G-G_mxQxnT1u+kv z2S36c<7(11=}%KK#K1yxEfrBf0meTRHT_v(F+zDQN7GF6%_ z!ww+&6VNm8nUmy90&8?6JDg2ok{IYiPzWu8&L(CNacmAY7oU^Q%j9K_At#V)=4BIN zh^gKwUNRezZD`c6sA7Ck{uFi=gS{ir6BYMj-hJ+U?gmr?>bLXD8EK3$c#E^zFs+zg zz8*f8+vBc+SHTnXJo-)PrZhksph2BeA+jLpp*+-U^cA|%-ehmXwqwUZ&HYS$qFNJe zh&%ReyNA|I>!Nqn>i~?^4}5lgtX|eefMekE&nxAVMuSKI-|NV=WL|M8d*r?HK)Jts zN4g`G1QC#;Bu?Okj9_Xodnh&p&rwSVC4?T49uYEvM=FP_hPwp21brb-Xrs7MgmYw8 zs4M=S&3-YznUm~Ec15SW6Yu2wt0~-T?lqzBZwsr1wb$9_Kz$g@1=~QpGM}4pPMWPD zdI2M!vBBJA*0O3^UdQLaeUeJ0Q}Y3)rU{z(M1BO=e<)KK)G)?J`_{WQxW1u3P^jbG zWNtK}7d}Q}WOgb$b&=}_nj0gFziQZU0svXmcScRlx->L=;FR9USGN(iEE z09b|!lED|5&olEz@a#&|D+ zXy|F+`G?L;7eR_4J}2N9h>lzWeDxB@ZLoi!BiWuLaRQ%(&BmSqUO5e&jyBhtYghz{ zTnwHM_74pV#RySC3#qxZPFyE06_<&h)z7NW_Wbqx`+N2)tP?5*D+Nb^7$2S(E+v$N zwxvR>kWCmZkCtm%wXGGz3ZfiWmK)$2_&0BK@pkoo^?dboba!@-agBCO=B9EOavQ)Qa9-R4^`V*|<&jo|mxs-e z6`Cu|6H0*nR9-AAP822z(8I8_S;kZ`8G}t?g@{6g8vu3a``cgdtFtEi_l|u9x*W~G zGx5e`1M)a^k~+d1X2x^lxYh18?k@iB{?dVx0oX4X0rA-T$orH3$#>*C@T8COZHnF$ zeK6`^6ntiV0k4E-K{>%b%%IY!Lhgd@nXWmmifjcoI~U7cb6BcedmEQ6`6`aEi~*kfp>=6(d{VI4L}c)AJh+OyL+qqUEp2de&Al9si%o& zIlGdrPF5$kAX^aF#|!nI)wODW&vcZq7IwmRIH!!-%mQ+`%s~pph=%<|1P7kUNRRPp==u^={ z>!I}$dyAqV3N4jZ3e+O(M)n{VtP55LrK7S=S}P4#hpOK|jFiSmx578VZ9=U>%fl%KsoCpKAIt!!pC^SXJ}Tw|;;3hMdw3)&S8`X@-Zgm2?Eb3eIX+$ZKEL(wE%k|;ss z#qwi~(S|6TJ^a{wWWu?o4fTe4FRiZz`v$g~JIq{mybX1NF(Ag<6KvQ^Fu>{Ww6$7W zyTNm9;52exVlS``00Vc!x?y*)yBNIhhi9al@J)CwGM+q-U%-13J&6&3hpMollv1f0 zU@d*8f6@#?F{9~`H1s>^1h5(OZy%@+)Sn?wkz#yt{-^Jk?|7JCXr|BaAKId>3ejB}so^nn( z3(*BA>~p7iiZ>XOiNT_vBQ`V%yHr*u?g9L z)G=xs!{ib2W$Cg6`*X*NW5ohOL1B%!M&uM;nXk>)8W;_YS=w~1m{d%P7vhDf;#6^q zvPFSj;~&)z>KW;*WPr6?9AK;2>MRxd`z=A2qAiJ*L>0O!4QG(d1^dEJ_y~BPn4OQ| zTYKAiFM&GIoNLbUG)Kd}ft%blt`xxTD?MvGL2s592XEw$=eOrg)a$5KaVz7NN-Kv;n%_UTZgTnmCn+iiF4r%me;0f6{f#wG!l9=y(6!_uU8mM{~#JiK`G> zKK76Im$#(5wA+XuJW<0BU#szuO|;p z8J4m?_+N0TyiC?~U5~Q-)=X=*^}u=P!1}Zq>=`&WWS_QAyCPkbNPuO_fZXsEGsYUnjg!WE{k;z7C>2(VsVDX0dTFP$6OZM;k0yGVy!UP zuL3nG$K?}pAF+>E%qV6Ai6F6>Tg}~P@3C;5=RyBLW5Jq&etq-A`QqI0>~OM>D!@5{ zo187qc48aR65wGM`0DKK?41r`k$ZuAIlq#JUg{_CV|aEv9^Z%W!PkM1a2bDzy~5y3 z8#uSNJ<=Y5p2(l=k9KFftG(J;kVOdOb>q$PX1txthV!w<+GFf_ z`oH>5`L}#ZI3?r{6$mjPPKw9G#-Qq~HP@O~k?Y7Dd=3tMOrSTk8+`o>Fd>`|9Z-Bq zCs4EC{^^2rLIhmI7Z3{w=x^{)f2gwxtDIDhEBmDV((K6WNR>#nNUlik$eGCL$Tnq% z0)383p`}sCaW>K$Xy}^@=S)9^y%nlog|E>Q>5WvuE8-uq&sbh84^|&UHM|x+h!{Z3 z1F;-miNkX@IB)neeTjztqE%hhUESSX+_Fn?E#Ve(lbMN3SEd`&80zeZdqj3Jjue_-o@|Y zD^lgDUFI$`kD5n?zG<|<7`=^N#u9O{crpD#x|ktnOp+!`v39Ht^FSN$9!Fxsv1fD= z4QQLUNOaNYw}H0-ozuDYR(p$*DH-zMCQf6g4fxXzjuOzf0M6SxWE?Q|x%RupWFMP7 zJvJ>CYV-f0a#O>IVFbqETql2Le;Kfc>w6n|cQQMfv*a0aBB=Rr7T|1dHh0Z+%>{kt z;N1EST3c;tWLac&*2=7B!Iwcx(1j*yQ+2ntQ*)_ab&0${KBk?}V9#t3S7Fy__ZhdJ z@>6B3QWiXOC}ie0=c4n_hGb)MGqxFE3EPA-oN1L*FB?~k?o3YxdfDZV%NJJ<#I@LK zv6Eva#=MXD81pOkXY8cd$+3r`4o4OB74fNF&D+G^#DCdy)iaP81bAu;@e})wu>?aL zWsWj$T_0SnnHJ0?^O6bs0**DvR2nUbYl065Rg_NR7QQO!ZY;(F9 zeZ)L!@|kRAp5J+YFHc#X(m&icTpD1N4b)m{7(If%fM5DML!lB?iF(ex;O@BZy1y}B z8QZd~0&)TQR^(=6k~B$rsNL5Xum>Il9|li`PKThkcLRVYpr-FAdyHL(FTkH7PmscR zVY~uf9`9mzv71XRq}S=M(pMy}Om3IjK6QQ8`mEu?aG`FbZX}o8=t0z?OlmAMj=4kKqM-Jw238A${)+vz z{@PLbxLimmByauFCZfC1iRdJB0x}*c zXce^J9p$F*=J1NlWtlazYGthv)(F3}U)pAn11DpXF*s)zVt5YW5U8t$_gJ~8TvP+9 z4s{m2fVyqY{$zi(6VTjf8lH~BbNK(!RcJUv`4D;lb%UP^y-XnA^_U*>ymDUIEANx5 z10MRqcxAwui8q}a&MW(s4K*Ine|seeIG5}XmWn|SC+Hiu)7WlIRi~>9l?6}^sdSV( z%Z_M?odBk~0iJJuC7)7KFQuO~P8*#8E~^d#dKugUd;ogREdsbQVhF}QZNHYNCaRD( z!Tt{!WbU?1YX_~QGGC7Hao*w^# z+R$0(Ec6k3i8;VC8R{D1qGG97KF%FCKYD)jI^TNVaQ`s>t-!57{iym;aNgcI`aBK& zRaeO?<@?HAWw<^1@BD^kQ>q9``go9a10ja&_C*{R6M$hFLCnb2QqxHweItL9S=%KPQcpoaC9 z`^s;$ml~Y!{)zZP+$Haj!^sikef}PQ)PD?)zzocYo)H}z6Bh%0gA=0ui4tSvm?PN^ zWg8S25E#yn;tP-kNjSsVp&V+8XR0SUHY%2ir{a6X^^N-w_z;-HPGYO!)$vInw}NHN z9rPaZ!ut(4+aj8drorNMqfuB?V}C<`WsqB{NL8eT$%~Wq-|FuY>BZA4g)4>o$i3vN z`gOfDQWiM}@-*ZOt@&2`AkPqw!#N!EY1J&vnh%~`Yps$d!}z<*9VW_(wlb{@3wk#q2#Ubo+KR#Q!Q($q{;dA9 z+RyqK^)f_J5_jr5^^4X;s}!h56ngxFl?owo9$mmg+vR*Wo;?))}oc zDuaN&(&dtP!pm&MW2-d#im_=#7wtrlUbDjOEAkcf7ZqyS*FgLhIx8aER;2nPbgpHAc-NB}jwhfimRv&-Ldz?3+GGoud9@_AnKh z%1ksBO~E@1cwYd$Qoyou|8o6u&86m1@T?T_>b>HA5uQnP5Ic$wrN`1u`G&k)S*Acg z#s6tlwNYTdLf!Ci_i*m3adIxp!+pwKj z9l*<{n^Vk;aAx>R>etjf$+?r0(w?Q23zrS=kakFw)Jp2V=6nA%E)pZaUWS?; z=yA6VgqQS@7?1L%*YXzj7xEY9N^(i&V-wCOM-^1*ulN7khr1r|%T>f`;$LbGm6y&> zL(O0XqrBk`yTXH02d75=iTRTSVo}QCls0K?(y$;JggW+T;Q3s~u4A?NI{ZV|LsuE9 zG80i`5DZ&-yHq)Ev)#NI2B0Yf~&5z;X{Md)&1F}B|f+DE(4A!r|ygz(J;#J9N*g0%Cp(M#U1a?>3+sN=hgy_ zam+Ys98wM`{e}L5m2RcyNzRje^7o0~Uw?o5oh?0EI_%%Ppk7oTX^*vBRxS(9H-o*F zN%&J7>b-f8dA9Ism*z!*IiJzevAGN4106m}pGo@#OXN4D<*j#XOIh5;rMs zLHzvqLAi$H;&b!4`^5K&9~e6*wrzBq=ple>=JVwDH0N9Ja0XXCK0ja3o!`y+SwGa> z#DhSh(5Q`pO@W$$8i57A1-|_5eD2fqDH>|-q36dIXR~wFykX7;Y!d2Q_L=)k*jwi{ zy=GPQ0n?W>;7C$zMA|s?Q`15$f(Fk{e=F-_-eG(TkEht`MvedS`RqOT!44F z>pk^P;%9L{uwU>&@KNw|d@J|ee~ zT1m&`qw>GXJY~OnP;I5P);7!Q<;{T4Crhc)3;mgX&^~Cl!P;U_BOC%evLI1_ScEUe zr=Zi&c21kWo@{rNJ4)qnmGFhE^I22FQ^K%EXErhi8AFeui}S_#KAygw%ic@gS^P}C z3Emw4WPCL8DG3Vnp>HpDl#i-MRIlkX@1gh6u534Uf^UMaTvYj}dH#9+DXz(`x>P+1 z&Unmi=e8kk=T%-^qpVR1gIKSv)i8uWD&Upy)#xg871*!PlVqc_(Mhlq>^u5xyB>YUViB?!DPfng zo0?6`i^h2aYTl;mll6<*CGC%%tZ#)qaNt?jv+7ynoC!_{$wK;(1Ihof|6?JBTh1-z zPVuMsZQOPao(t{8_F?O+wN_=Lis3e0<}7=*oe#-}tU^})orf%uBI(cwbCf;~P-|s6 zH=TSi zpBPV#4eBPfo!VA?ue?)Ilr%+@C0P;#;ihm)xToFI;M@l2>9@nZ%bmj;=Pm0g>-pjR z=EVX;V7PCDuRLFYFG-c4pceQLb^t3*lq9NCH7MuzL8+HCDi_)IuHD@WG;;K5*fxr5x=Y+=@PYCF5_-G4oox*0u;H_kg}2f7V~=OJb7 zvNo;L`gUczqJb~i=TS^4rgQ~ZJ}ijB#PG!M2yvtc*Y-30>0ck1R%jb^ygkNFvC^zE zcu71jUx450+3NYgz2{N^KiF&RHK2xI5w-{$;u-82_V0mCu?8exO zIj`i*5f>K+JtHZEM1C8;jZ7!Yp}^WpbnkR;0(rIv*ONOzouF3Zt8o@((bM)RTL*-y zjo3zA8mSjrtb`Co)mKSS{x5lBj3!II$nqEU!237wa`H&oj4nrFt z^$-o!(JkZ_@+fzVyYIT^QaG7A!JcFbfPDGE^WIZCP%E(4cfdE7ox^TIH>1zZB=eGS z$ru2T%1`^JJq1L9k`i5d?ts&ZuWpIEUiB{oaQD^GU`NLsNBile9(3CPhna zK)y30X5>-mK`0!Ggy8w)Vs)_!`!}xh*ZBM1``%CdN4`7O9SbOaB{L&4WAmTQe`frd z^(UMfO1+$QIcvN$UK(Nzv$Ducva!3dyRyHsUk)gNJRp|vOZg?}67-&WPkk497do4M zHoZfzeef+lTubEkTMTH8r&uMSiOE1W_rc|k;LG1@QVmqA##1+@S(>{)g(ySSZYfY36u!P-C# z(FVyP?oPfgzGt2!&llz!QvolF_dt7~<(%@)LSw%1Rr{{B2fMSNR6trLE*Di< zlcxaox5?aO4nzhcAuJPvIOH5g(wfi=03QeFvYQJT;3I0LDHR1K~c2k$!{TTiW$a!DEbY#!DR z>07bQ*d~BA;4GhxWM?u5m4kwNe-F9`eE{}Uws35CTH3TUC)rBwkk%n>ZE#%>p0&74 zx0!?_Ay2W#*al)f(Tnawf1$om(7(NeUQF*P^^)Kn67-w7Y+bV8%uhI@0O||@opTBk zg@_hh3l6TKUxD9&qy9twY3^xm%!Rs^xmUO+c_(@gdJlLH@ca2B;yGaL_dI~X(_=J8&8|V%6mf@D+S!uJ=a-?KWd71JmkPkq7@I(F~x6oQ>t?btJE#fw@ zfSu27;Mei6Ken-_iRY#Jg?ov2iT7RLZ6H@5cVL`*oEy&8s!UcQD}%Z_m>Nt)*f4tu z@FO^H$fg|{YSO-f&o>(v%ULelHJTgAHN+ZY`?S5F)70SeC^h zK#<@pZovcj1c%^|h2S0nA-Dv03&9Bx+${umceiDIq-UmG{;SfUX!0rEh(r`5yS#B5@w2vdY@{C0kiV^@Kedj|Q1yobK``|3S)sQk0MIs9ihniI{* z&kAG>&K{KAC9iAV#K?rmXC*^ftS(XGbiWRI`@iAS@FHYU@-hAhKaMz0FTJ~dPCc(C zN(s`!$RCkWk&%%KQblR2wb}Zc+sF0u_VEVd^5ZHbRYz%P+eWmZ{RVfEv$2|bzktE_f7Fn^;hy%^j7!O@C^10 z@{D$ma*uY7ae`KADw#@VV>ws}tQZE`T?bI~wtLvnS2NR`VXi{~GgCYBcjvFoT%Gw{ zW{1p0S&Om;<`2j(Dy2%$lQ2=AgqY=g9s1NeSnVy)^~{28ep ztRDOr{1hA(9TuHy%r>r5x2X5r2QCkB$=zr#Oma_jmto7WkgxYE`;>bq{~V1SiA|S( zmnR`yL)oPLl72~pZ_|ALe1Fs*^9S7l_fy9+2k0e0KON{oZB_nKU=Fb|3h+sTIiyZezDG5k+t4A4L36He}<1bY6<&MskaOD)#CA$9o^I=U&f++2k~o6T2fU_ego7 ztc$LVZjd+1?_rP9V`%U`2koHI2#3S{>OTkr7?epJCyo-o8dHr&(MQo@Vyc)Se~~NT zmGI^4681iSpI11QV_Ak>Ppzk>;ZyN=Bf)qsy_B{VJkyluS17B1AK88E5e9u|JSTA1 z99JDQ;zV&o0#VWa+Gb3~e4yXgHC@%)>h1I|>SuMjHeE~BQ}oVSXAQI~-di87npjP& zDcO{CI$Vy++(i!OF}|nJQ}{vXB*Yw1M<$g;ow85aC-mcbYxJ82m;=ot_Cb3hHW}-L zcfo(AhEmf}KF&kYo$bk%WJ|CuQA}p1u+yk%)OS`#>x24U?Vz{UAEEafW20=AGt=q! z#Cejug}gCW%mp*FU9Ha6;Mh;G9|AuF9_BpEIh}PnYh%Wr87niEW?VtfdbPMp^e7(X zuzAQlji13mg8+27T9Dt8jnVpn^TCPABqdQvQ0~Zg(GEB(|A=bA;K-23GwG=mFoP!C z73~mq2(>(QJ)7N|-A~<5+7VKG%sA#f z{ecGUQOG%~ysNx(fC0|6Ykh*bn6qVV>3TRa)O zOG%#G#I9#6a22`PC_sk|2F=b#&qbdGUIn@aItN-uT1DV2ua(ux`qpk~M-k}A(y}zo z)Xekvzc^?z^s)Qd#f{=d8>NlHs}A+7c24W3^jEGUzCANGBi2vsD?USUOS&tqR#&Oh z&1vQcd?b!xw%yh2VS=1S`Ig#9g{e^+|!d~hh3TBY!xaK0rj=4VbpZPWXD*k};ALldAb58?reQ#Yp zjqixKM+>u=d0oGu|7i3w&{t($wXRtm%>S9CwNly`d5k<+nk2c=8med1E9hB;v$Flh zUIXsohDkq5aHn1Y#c=UwaZ+efsAZ^iC=w2b8HtvvT2-xUjvJ1N-tpd3-qYUC>}QrV z2;+F@c&Kz%nXIuH<1(CCLRP7~Qh9K8V#$Ou74g}T!U*A&?~TtF=Z!Och7a_QDq)qe z0aAYn=AmH@eRIyH9B0%Wr7Xq*t%l)_k&ecEBfd0Oh8u_0ADmbJOJAT5kp~OzIgg+K zZK4!A)!uAvv0B@$Y|v%f5L+MH72Of-Blnf-s`b=$+8XVOaT(#kcOZD^RBaoyQcezoo2pDxKp#OjbmNuv+DgU>Vc;Wb5f-tKUBvEo?sop@>g@up%_?kVb}TiH0=>95 z#w)`mdt{gB61Ro6hkOxlBt!Zv)l_S#=jHS0H7ZD;5wOT!WM8B&(cQVO+$3fqbJRL! zC8PJe9|in-SEdV-DP#(7oo}6Rh5(!yGzCuCC+&@>X0-@43-!+Kl|BB;gfHn?=~=}> z#X^!QtF7>sIQU^sMUhEo&@dN{IdBKe>*mPWa+PqEaQjf(&|rCx{KR@@4aNuJ!>pgJ zN?IkYs``z3$U111U`w$lJ;yzF{CEAA+?U+rx$)d9_67Ti$zZCoRoFv_J98vUN}#l= zNT?h*)all5mf}zxZCq_#gSbIlEw&chmTS#{w-FOh$InZclW@R&(0v2d%Q@CuE8oho z1ky>u-17_S6?K=mMSw2)6l@wc4DH*$slC)~^R~Gvx-zQdDS31bne!_5O>Wmv=THyC zAIoTEwXRAxRL8eQK{tE6GG2)qQKL213X?3^8ljF>!L$3Oc3nG&xWXoDqm_W_)H&^6 zt*Oz-0M*R3+*+=Kuf4B9V*SKziQ5x%;&b9R#BYq>n6M#XYTR#eFz5P`dBvQtPFSV& zGCFXC>D=$!VAlW_?Ds*!U}30Zh@(1Rolo};_5L3JTRaHX6nB<%HewnxtBG~QUnq|} zCLR+7UU#^KryJ=8qfiQXFbvQJY6*tlfPHnvxM~cMhDdQ@f>=9NCstA~uGg?@7WB2g z(O>Ha)q`p~t)14%=v1ID3)&%NwQ}0B=#uF9*!fr^rLhuHLn_>_Zbbq9bsMn_SkMu2 zl=GGIh5SK(im#}zm@mb*-Mh{Et*fO=6e2=%R}0rV=Nji)6b;<<-EW=moNf5FyjSoD zEu1Z#CAi|;PJ4&#mfiAz*uYp&3Q6Ff3wRr}0{v3FbT@K4(oSkCz0*EurSM|-7bcT| z+I*ZoLFbzJ<~K@pEq$hy3^XoiaLQ?E0|lL(xygKP?F?4m`9TS_jdpiqK*D zcVZ^-C%K6Xp!Yq}Ino*7qFh<53|2H+ELtT{rJxS|rEk%b(0=sVUOOLQrF-gK^`-Vg zgE^g$BkVZrKIGmmY!_1KqI74X3juTLudwG>0+C3-jN5Q&xKv+kC=QMO6df;3luF3O znXvNi%>J(#&aR@(z zPot;O0_$P{KaNM-XRWoynxakBV$o<6^o|Ol03Fbk*h;KD-;N*S8RvQEedwL-ndM1y zr@5yK(+jkujv7adW^xO;i`Ye+B2E@f*^c<`PyP8rZw4s$Nktf^K_wWj)~v`K>V z#7V{^<39cX)o>pU=l>6thYI+uHa40Vb&0yfN@@jlggQpu#INJy%<<+vRFg*N!}Si* z_Y!!fT@){fLqj7%mS~DSwC-Bi2pi9|XIeG2h6-9+1_B8s5ic7{kETJhv8&zH&PUIB zrMbqOLH$mZ;7W02`EvY2<{`7*T5BDY56KJU`7-oOf;J_1UxNqT*4Xw~DXFA%N;|1_ zCb|)g9gPY+87iZk^qzW0L0x!`KA%b1)HrrLJCNzmfJP$BNG#@-aPRr|{4#DiSCmen zZ`d~qxIWBo&)4Q_<<0VDf#(@>ky+_j?Px(Yr!-yBnW!T=Cp0ItJM?!bE)o|R9vdFJ z8@(MZ9Vrt@l~ZL{gJY>Nl)yNd87ROP4)mBy+QscP`dS?{o+rrT<-z)39qznCX2hJL zPu4;EWv{*0zDQgmpx*<|%Htey4mb-|1x1LsBkpy+wZ5soUw!9Y|G6+8=a0~b=pXQ| z_zq$_agn{qrgKBN1N=dLn)_Gx6YmpmSARGE)A+~nLcBA+oVSd(ma~?#A$mqI$1<22 zNR3Bvf&Pz9=8AB$`Puv{?iB|;MW6{-h)HBH^n=T!><+jB>vGoR9LPVI9}{C@no>`J z`T#v5&torRo#jsQXYG>)y4DEtU>}Y5#yV-ev?Q`5QbH~vPp~Fipc}Q9-bXK`mQefc zf9yI&EdxAJ>QN1-PL58FMkv=reX{SG_pQBng%1m*l2zoj&b9y0qJ_;JFF2==N?2Rf`&inu7VFD+(nkP%OgJ5%?jyZ{hV>e=xBGaVQ${b_?UCTIbkWkl)p+` zCfcZN)S=;@!++%dk(-y3mjh?jn@}z(W0$m@2-iX{CFnI~(^>R&?gkg*BYbOwk8hJV z$>G*Wi`5yOFi4{uUKalvapGZ!M-?Md377?$h0j4*?;sBP?xm^H6nLR#;a_l={ThZM zp9m1E$h9QQ8vjLYrp}S)$^IyMIC?q2UnSlV@2ExBpl^}4$b0rf8@$Y&mVi*!E9(cV zi?!d}Yi1eQMuM4Ou0i=gw8M5=ybTVT$AB09M(AK0+5?--&89c%iDqPHW$PJQ#-}eI zzog~X&4vE=nnrD-ELnz};+X2F>#XfOg935@=y-z{GKrHo_~FhD&k6@cQ3Or5zE(f$ z77lS6uaDKkZXupMoE$;cVrnvX=(}_^{2Tl(;Jj*LFet6})*x3P(b_Qpn5=snL*fB zFn76)-^m~54s*lUbapKhkl%qzuaoc+-i7{!{)4`QzO%wv0nT-w#h%3`0 zh%!iNU^FxiVh6DpAreJUG{hQWpf7bnx*+KYxHpP6iH7x%9>PT&`skK$i@4qF-z;d- z78g>56Yi7lKb(I!*Kn)31MC6z3-g)j$M@yCdwY7txNzJl-)Y|k?jm=|zGQ|E+>z|?29;G6LSD0c#%?jGwAs~>6*YM=LA-m1W|!0_m(s7rHdBt~FM zsHN0%>IF4~7(&2|u4URLcmx3MS{_{y{a*ZDEF+bbz|-JQ#A|ChYC4uU7CC^cf(PA+ zxRY_I#Z!x4EO)V7sC=;eo)UXYfR0pqtUU&r?WZEAB16LIVLFe>Tl->%FlV=p-azLO z*~Db?7xSQT$moJ{eb5Y=;B5=K(pw^bMM~wD&2N$4EPuVYPVAs|RKX+n1^u)@kL)6T z5ubwng5{GzavQb1K&NV=J=unt3DBVGPV^+42xBcnd-xQ4iY-N!CZWd`yfEq`zC21B zqxIK*)b_~#$Z#)GL#e4e*PrTZ&Glv+7LT>So8tjH--dI95=JRwiMiNphquS!ES$DT zE62z&7V3ZKpY@M=QG^#|N~N|^TM#O%M}dA?X|!j+Bd{0N3rnNwQVW?y%sJ)^Gm)N5 zmqd8$rg_VJWxO=Dn17kzuLwHawb8y=iE7w${e@oNO0&KtTawlJZ}_U7svg=&Ip5%K z@!m=wrER!ncvos+(sBb8<)&$<`m->W4Jy-?`ifh0bjnQ-cq1( zQV-?U(t2qfwEH&5>*Y7F|`lzBLN;G=k4=0_|p6y z{XKeIIwnoQe#OQ*#yZ*}t^&QLKH5j`CU=qJ9pfDB-0j?;Q#6Dd!VSfK#)c~CC^wIg z+Ny2UUHUHcjz;Ns)LUvdt%t_hY{6OR24SO+>&f-h@znMl=TGq90iQ?alJijh`=q{C zF$6NYMmt5FF=woi+CT+wF7Ug#Yu+)7Xhk&8`WNM}Tn76J1HFz}>>L(6kDzDpOC%!# z8gamp4#`L4YDzU_Z**U@j#x+BDeaJ8ZV@!^_X+<9;1#)+UQN@e=0}Mbaf~^_l;TQr zF-BsbH<~3KBxvQH_x|g3CwLNmaDVTHb6mi7F3!cpd*i)h5=SStjr%UH2j879N0+1j zqyD4nF=&3i<`_*mvwe^u9Y0|0ABEn2gpB)K1VDhkMAL1gInTD!7Ln zZH_aa8&45xI%|}+OWFOYeqbF=b;G;k<+1Vwo-T{=#rRxu7TJz!M}fv%JL@}ZwY|E) z)5x?9+he#4=qs5Bw-kssfsPI6zr8izm_5y2W^eS*%2pL?E4CHuZg;mIX!kYH*6gkH zQegJtVCYb2Sa?`?MsP;Z2$%soYDITze``C*l=sze7$&gm6%hg6& z6U~b_WFx(az7yYpzoFmJbJ*D^lb&Wl8xFASKzo1CnMd{1XDXIn=*M}Wv9hTuc+wg_>b)KBUo zj1fjPtOf?(1!xGv%nkS-rjo_U4fuNed;5Dk+sraYnPbd9>_6;QR4eLF_AmB6bC3Co zE?c0t3Nud7gY%MpMwenrF#{2{1i$w|=3o!D?{~keTlk6jY?5zy}DlIY|j3bnnI;H)124*H~iK8HT-qF zb-eYx^}Mq@b3BLKhuqM+Q51#X5?qVeh3t5IJYE##ja)nr4^X*OPrf%_-c{Z;iJi!T zN61y{venXTjWTR&vl><%V`z$g$9>@T3;P7n@rM4QvSc}O40>9(v>TeBI#rl$Z5D1C zo)rEiTq{x|(g?l(!;zyA&_Z0K{GmX<5A;RPA!mSeDh_jajSvd4MqGVALd`{P+TGfzjO#Wv7W~Z1b zW+xP7P(0Qj>2DAVI76H&z`h5t16WtQCtk!(whx&5&7X{P1J*O(p0C3d!$l%RBe#@W zN=dVXc?Inh8pU767GpW8oz3ZQY4DUih#kg$Ri~=Oqs5|b(JL0wk~PrPeBgTEdMZ2- zx=~#z&}RqD0Wf%9h%h1HC;WBYb=<$xzthdh7UYj?Zx*z%G{5FA7hf)(5@-P$F<#YEF_vyq_iJuZaCmit}_0Dn5a;|1qvhAqvs1@XLG8@arKz|SJ4F)>~JKzqD z5-8yxZhyf&8tA;#L2-}1LzkvXQh(Ts?2q~f-LJ;0ZI!kKoN^1ZnQ6th;nTUFIMDWf zYrnNI-PXG3U3G`WT6OHY_C9N`1>Og>5dLo|x0Yd^6?*U2E9*ddOu7@f9l3(|?j982 zKMmgQU9oN$?EC%3exs?gz7~(qr5TEoMdi6@dILUa32JoZTUoyIE>ihLiCxAqdd|I1$cwGQGl-v zWaoqQe%e8E^jYFG0s68~uW}u^4(PcY$`9o?FdLZvuz#^QGY%n%9%h!EZOk4LvF^i5J8Ilw)8n z64ngpLVYklnsCMs`Z&-lHq)AEfzNIsv`^9yZi8OR<;-#hzON3u>cL z#0;V|U6M{D3K2Jqn}%2S>X}A{;le#QoVlGQ&Jxwk>gF6{mXT#=+5PeUIGlT?o9X6{ zYH#(K@=UpD-LOhBC7I{!3w9(mk}7AHwcqM*^mayDqqd!9SI4X2bFkUiVe^OyII9Sj zjKP_9SO^NAof*!4j{c5cv8fnvxfv*LwwK$;v(>rk*IE^=j9OYPj>4%6`XFa1x)e&lu=C#t`<3Aa41I_)K&l zJCYYsd?G)R;Llnbz5aXbBi7b#X?Hbx7$E*RKQb=@y$RD}(+m9Bz|*0OUE2QDnqs}O zU)$iR0R3yZR-Sc9yQpnewkUJ8+1g?2sKw(v{vLaaUBRyu+`q5m)^XRImz~h#SD&s= z!|bWcL?p{J~VLUmWT!1)BqM2xJW41C&oQs@~_{aPa`Urj4K4L?C zT*546-n!np{2sq2(V5_UPCuvNEa?@BCTO2rU@kC)*d%r>wT3E7enpO@MpL(_J5(>K zCv}iIK!LB}NAy{<5&n6AKg5gKsRcczkbl6_><)2 zH=;M9%|p#YJA*rdWdmgccCMYfHLxY{Jn|wkTb?bi)K+R0P|gWzL9K>b10fra>eAer zh&X>mv%J~e=x!|6mTQO9Lu!(isFgHI8;wy822EA)Rjq^7!rmG0jbX|#Wl3ylY({Km z3{@^Uszo&d?fnbtCB$}1s=JLHhKbv_pN(V7@n7+am_L|#*gUMfRo>c)^34tuP3@-k zaqF1X!{}wOD2|wi&3XtgkJZQO|ElNJdP;o+RcURLz0n4(g~`kW<^p?>y+mK6R}rg; z;zTjx1NI(UY%W2Jt&BOu{>d(ir{JIq2p*6_sKFFQ+5~vKqta`iHP4#R7YDwh^$|ZU z&sJcsF*le7Xsr~bQmLwBRq_RjT1<5Y_A1Q(bVl_Q?iG)j$IQQst;RZijh=*}1Y-5j zyFn;q!F|*_6lKiP<{SJy-j-~Ia@rB>vU$aPXgoCTAdK|A`9HI_)!V9xB1wHgwQb{BRRbCq<>a?Nz%Zp@wPEap7JoMy&iZHlP^WCM5;zBMYGWNAJJoa9lN#-USbc4`@~I@mm6pewROgNgR>bs7t6=e zh`I#yNyBXO8|Ag~-uh%s<)(0rJWV{cT(w-#r*ND-%J!mvqytots!7+Ncj3G7?bgf<4~8i0V3Myh3mB4e^#(He4pWNL(zwmfy;7 zrd-HKFkrU3Ct9x&D`E|x`cv20+w2Sc84h|*=cE5dZ-;M(XDV}*Wy~^Wr)#^bi?h3P z2fdB1W`1LW?ilDz|0+xohWUp17I@})<}ve``ec3bE_0XZB>W(V==&|2P%L4cbAuD| z<_F?Ek;oKgmb;d@1|;@NoSrx%ag1+_ue__Q3pm3rYB%+ed`J#PpP{GS%RWdPB%ZL3 z*p>V$K1C=ZggKE*XVcle)IO>(l}PQTchlfqn1-cc9gOdc(duZmno_;s4)`p6mIh4& z;IyllmCQBl2G&+@qhly`n%m5Jc0>D;b-`+e0(^xr1ylZrE{Uc|X%hI)|4;s(+%(!E z3cmMKL(@XLW4mK;A5j_m8rx^@v%fYgnmJ02@^!Rw^smsS(1_ru;Fj=~aAqVcVn+1H ziRiKDP3fleUj8VTR?Dd1RkB(8Qv*DA0L4@NiJoo_1@%|6n)OYA$2Wpm1Vz$h4#Gdc zQ$VY-G|E}YX0n-t;x&q6_z`>%J(%u9|Bv>NUh)b41pk_HJ6PD1rN-i$ZbqrFdCj0O6gEvP0G=)4aye=^~H*3r{+ z=tnI@mLz{9`;c&EmSh$-=M>yq{G*RDN1D&Ar&fP^u+1PI4&EQ&bNsiyOMhrSHa}n= zu;K`hY~nZYK{m|xBl-~O*ifu9-U;tcbR*KqVPt>^5Ph&dm}bbv4t1wmNGYVeRo|)L zsXfXXVO2o6?R)KeZFp=%Y%Ypn`cVA>@h{PZ>CE&-?+ScI^3cASVN5rE!hXhvQ9n`O zp;^o$Q6`7U;%7zZT>c6YarjuIjEe5VV*bJ$TlD~fcH}x+H-s9Jv7WQ zpNO4^jSG$s0#<6GH`P1X9c-AVU1zPgVyLdc-51Q`bAHaB8ec3vl z+jBRyhw6+Xg)BmL$GT%9Oi=6_Yo4%HOkMaK*Wr zJ6bwY(d)wOq)IAe&>3Aj4EmpCjHe)jh>sS*RqOpiWWuth-hY z%IoKZGs4Wo*@^p;_9sE#9l=s;d%K-|3}G~rG)V9s?&9p~JjNbl1x>T?~1 z{|V(?U%Afmr};(*QyB=?+NKHZRK_j+mR{Z}V=cy);ys8SL|4QQrYOHC&(){uUUQ!b zzOT)RZwZ(aZ4ql8(?vr}LTmUMbCo&kKIa}BHz+O=C&rcYm-kQfPVlzyHut_kfw^pF zI`uOJ_w}2kO;TJaKJ+l}e%^)L|8hf_fy_l2i!+35K6`Zjn0zr54t)uK4y!>u_%ir9 zxFfPHatr0BdD?vKmU+|sSs$jal2^-_s4hXDE9lp3L~EuC))lK}*Rat`*?p`&mRI)` z=uLvQub>GUoLkO9>oO1V{f^T2Qol&w2A-8lr2eP9*@nKt zCDdXn1N(%fX=&PN>8x}{KdawHxa+3-mivwHR=9-yhgpiHG(~H*oL$BS{os0h1O5tq zg@!Z47DfvLJV)USQqxoo`UeuFL@6Rmay+aRgr!02=^$}{Xic;tpvGNyTz8BU#tZ$q z{#+NLGw}f7F!1JHpwHLuSr05t*Y!BjCmOkCE)}2xH^l4W7;U_E+B#*u(cWnP#10f_ zRc}*vD4>g1U9YBtr`RVHKbs@WW<)arX1r;dq=8Sbq*u}Vn0-tP7jdWN(c;2!;Td_e z^InEugv+UA)p6>0^`FT8$ot&axu>(wWEU4ph-0+khn z5I1W=H>ShrcR?@L1M{A_gVAB;4ko-qyk4I9D@;sE^5;Aikl?WOigW3{o_ z`qMg#pTlb){9BK&$EQ1oIs-yLsK8g`?>KHb9Ow)Ff_U91#C3j0Sn?-?u;&}|4an)W z@@wZG4IT|Xlpo5Uv=7=H<-Sr`sifRAubTt;LHrK?c7MD(!Tk<@hxd_wl%58k1eb|R z#0T;d`Kok98X8HDv_vs1HY`>Ty~{3iXL>d_j{_g5sm!lTDW(il&soQLDE?4^)C08@s#oOboF%garJdQaNc*;5$Xu7 zxNo_~)FUc@)_+8o3bd}l-(`$*tW)!8zPsN0-cS5Tegn0hk}(M@N~92HsI$~!Y!S9S zx+B^@Ye3eLkBdJp%UG7tF3>hGH99TY1l63-+ewLvQEd@t1D)hndTae7 zdLB#kB|6NuuSEF*W*H|)6Qp~`p5N;d!G0#@ww-z zXB0V-Y;LwNfoDH)J$3a>{4sH3;-87-y%oG2gmywxXH(}0-$>u2#7T+63jJK@tpAMP z?QlEbd>CezVRi`a91iP;^{?fMGWY^~G(H;OlXjcA&G;A(vz%N>t|C?uwaD7!ar`(A zJ-+**`=j%M^Mb#NGsIikZS5C(lKsK@Y;D)JYH6|hu@B;VF*lYS%T%(IrSekwb>vlK zx41*R6TKg8s5DS&8nuiyX#aw4>1b`N)-BdKMu*tYhun9$2T^Bx~Ng(p7UlTeo0)MxF~U{e}(_O`<)y5^?vhD^FK~_ zlCaFX#5<9iOwCp2s}rU165LCD%~j?`xJS76I}bWnu*+FEcYjO2p>J?ExwnWXb)&jd zHfCdQ?e}&E{5w1caeTnf6C>jz4RRahR?PY;Yf$cx+(n^L+vuV9(%)Kd5l`-q z?J{;76P0mF4Y`hNOQrA zlRVv=ZgwHNqm|Z^yrBK3g~NgHJj5dznU+UcqpZ2qJSs>ANWds?H_@Hz!TH=icOOr0 z&t`rrzm?oVw!_=u)ltAqJ9tJ+Bqx%W9G4t-ym!27;#bEvMp#7@LIU_r83;ejF=v~# z)H-URV43iqSCms?~b?63MX{dDYf z?1A)9`lNr-L6;9^XdX+CCD1GzA&-eZ>evI zPv&JF`rzOm9y~S9B5s=MOmTMMx^po1=EA-B0&*@{m9NU*cHMD-hlGvWcr2#G-idF; ziONI;w0!1c^RVmeHI{Ib?z3@c<8CJ3NgkInCS^eUfOyabpFm6?5HK^YNSCC&fqw#z zGaqF#8Ei(g%x0O-gD--hby!=ktshbjD*fgDay6x<0{0Fpw3S+Sy_wtPNPd?5 zeNv~SBmSfQ_TF~hao$nhv)=RGUf!PGCGMqeAMfK+m=wm#xS4_M0Jb(?hyTqx-8(EU zJucUi@1X@sctky<0GC5=-x_=^p6(dr*yGyk>gwy}8{!}AujZ@fqui9cA3u=Kc4Rts z(z|HrpQ98)Aw*J~ls_rIU$}qxn0j2jYu&c`qczJA3;~+kg%P)*P@cG@-_}9H2=p7_ zti=jgf&KaW^PA;1&21HE6KEoj`(+Vk*;HlL? z@2JxzZLYW1*lilf^(VFL*>fqC##5O$j*D*=BAxEzQ&>;FECBA`&g|7H-9BiCS~1xl}`{CjG9>(C#7*16&M2e0^u^ z@7VC*u;5^Eun3;FmFX(`<;kWSM5BL$`$lEzL zbJo9I_jcgRAum6F`1Ap|9q4#}hj+j$k(Ef$kZMJ?BsIjz8d8m@(pD*}qFhNHCJm7y zYD~>Hat)a6$U%R;lHN%FME6D8Xl*n&duWfh$G4;B^-Ot=U}ac2jW}U7Z#8e_!c_~W zCDcp!likREi?9j2UVsTQpb@mP$f_brl9J?d39b+wrrR;?7@ae?RA*7=FZ^Vlrf5nt zG$TvfR3)wg*U;6-)yUu2pOu)EcqZ{|;&9(^ANmyn=o+u4SJU8GPzkSu zr$$qwwKMBxuK&F5bE(`CxtGLCBFqxb3eN~%58Vtsk3NkKF@_r8XSR%5K{dsiV5xR- z8+y9R8fA@|QcWo*lpiXUQ!;1emla`hqjUGJ4S zg@ZH5*Zf<)y0^NQ^x|I7GVh6M>7m$>*u2Q>NPDTBv`}B9uQApdos5o#8`Xdl^l`c! z3h)HJtKL<&#kR!?tI6uW2ro%k40~t3HK$9{rTKvcffsqt@|Fiz1RsSThWiHx2D3A> zGfTZI@$UJXmv5}k_UCKy(dOsS;$RC}&z zimIGcPAGuqDw|czE!I{GX2m2us)Oc$s_7cs1%r@ z#$+Os$jqW=(l?14#9`tnaf$wyZtQ64Xi7Js3z_NP^ zO|)&)9T6g+dorFHOI6^@^Xs_{ToJk`T@vl5bIMuex^h(kzX#sMxxP-Sm~^-BgTikT zUM0-)%=0uAnh6brGy(kFYdLB;67d9lhVr}eEc`6&M)4r_AXdrz+9XMejHeUmo>UKN zGxZmBhrUT4rVdlPu)nbz+I0>5F2P5pG~#`OB7-B<#TsJ2VDI3sdB5e+xomF3{CfEl zB9kId5g*EtvZa&aX)zj%1mB0=hIoZnR${BMC&UwCpT0*2%;*Vw!fT?dqxojO`2nrZ z!OlU>!l<6Wy&(8}JR}|v@T}*v3)l!5Awk!9lfF^MEZbz!K0YEG6`seviu)^hQ*tat zPU%skTaoLDw-VhRr>6W%ecb}@S{!YBK& z16U)XF|m|hOmAj3GjkBGnPtv0Rm9EbNed;=$cySRy_MEd1BqZYszi@U$0WF~fpeV) zG5iO`=afOwk*-A#JwW-iu~o->VY%KSM)1-K0BYi&)jFgpMF(vRd99o+U$eD ze}Yr=Uv>>q6K&FEzO&vy0wriHFgtvqjw7wKw(dUWt#J|JSZ-g%~vZb zUn{UDr(?fil2dY?N;s8(pnajQ;>yMi;s^67R0_o+Ob9)55j$ch>&ZIkMrK96M9S+G zbhz_-=y>R;>qv8)B2E#<&7+6~-Yw`Qy=mRFK(oIiia`h)!CF3~9n?~l;!0vPKDso# zJnV^hA}gg8k|CRNhLj<#6W59Vyz3yl}y5uhVbb;^kBb?zKre(?hP)=UX(rlEfk zdApq5p8SrCVG{O2f1yk0GlRZV7ld|wJ`^8%6nhc_z3J0vzeBHEO})Ba0@cfQu6C|kg=-Yxm1r8kXTJ@V)fkG-#UL^WXK~_dN8#to{J4zh)?w0{z->Pc+Lt z)4eWkUEJD)H3>TtcPF+=Y@PVR|IGhXcq*urO5MXB;5Y4?_Gk5@%7=w;UUq(VURHiq zKZFxN7bBfaCp#gYL7SwxNMEd{*hTH{(C1Gk5{a|MIU}Y>N=v1c0-t%QvCK%(i|D1K z($cW-(D1{+gFtd9IRtas%VJAncg1@m==Feh;92>se9^vS-=pu-IYbr#x~cJzxX5I2 zlK2GG>55ndY#XZekMQR>Xdn|RrdGASv3w4nL+}WmXYQx&rR)+`HWXu?JV#!uZP4!F zcX8e!I99k{}6kG zdWN2$?*#PA0*-t~HKB^I(ebBa5Xz@Vs6!O!DSe_p(p`wI1n6sUilDTS+sF%*Kfsbk zxhLI|#)+fFVS%3ms{*S7%_2=Bvz6J(26ep(+PibaS>m_RR#DIq`i-1M!u|gv{gGZP zTr1oy&^2%~dNX<$<;88p79thJ24lU!stz?B;dPM=krfaR7{ia{os7UVwwhSAlp4w` zb(UHRanS!Et`>7g-QDB6$J2$VLasvYLbnobCBRw9CVnH|lxjkOr>4u`jc6niCa`ps^o6fOo~ZVj0F4Bi@R)KA?AZ!EvF$@8Ft!-5wwhkc%R2@ssqE)I@2l zfVR_agok_O_sCxySQ>ztj4$YOjj_g9pjEWUT4Z%X@q&0xEOsn$G)6HIkne7w zcxFAbpkEw(ijQ+AxFGtBC$SUQPHHFhf&0Mq7y1jc=s9%0mZPjiKy%KvT)=I9Kd>O@z#2JY--L>7&GtkOtZNPa%RxC62RrsrLLQXH6UoIck;t~8fzK&RfYW6v6GRp9|;PfTr3f&TVCQOf;9ygRr=e}5(7R(41 zCySBS5$<~6dgPkN&F8+N%1}?qr{r309ki}!oSD+w-@rQ=`bBH*jFsY(VXs3 z9S0qU9G`{HLbteXac_&fEi$O&pps&$mx6l_*C>DPFm@P2P(aUc8NM{X#@ zy4XqSq--^}nV<kaj~YF%|v zY*7rfu=a|3#77nvK>81T=8=~X4uu|+VZ_fw$PU`gu@=}< z`-u(xZg8(P!ad5pEMZB)&7?a?FXEoZrMQw^F4o2FBlnUwQ0@Uu06*(z-Ixozq25rF zq$FvQI!QfEo+9BKz7gG+27L_hQ8P44gWl7q88M5Q#ZBDQD-ug5l}&0G-zfgF`;xnuBh`_L7sH!t&9tkLtC6>X zH-WKv^8bgdC&f4c}=&c9O`wQj;GaVa-RVS(u@pv5WvfS1HW1s1ifqR*pc&C(|HpRAx(P`}cXY3Nh^;QZul>}lvpbEUaN zN7OL_ap3KUD?ra?GU71}91R?>{&t|XcV0iQXQBOm!+p*DBI!la__zsi;E#SpIi%bO z-U$8^-WRTDR5E}Elo!4d?s@KcmLx4pdYF1IbxyJQ#oiZwS2)+5>z<9z!Mn-bb8$&@K!OU#){?H)xB%Y~yBavj#diY?upQ4O|V>6YGg*I)I_Q$)18@s)=V@khX>~l&MhjYh^Z(uT)@xcpeegq{!p*;Lc-BW-i0h_z)4P&g$vx~IHbjLe;KhCAALWOUClS!l*oW`I>ri#6a%4HO9+rl!v{qW6 znfM6RM$k4a;VACtN^~K%X*;w@sQ&NJcj^m?g~Vv*DCZsj9e;)R3i10A_a=@{o|yc9 zlCCmLilghc%}n>W&#bcx1b24`u0dWP5G1&}y9aj-o}j@KT!Tx1puwH>9qnn?uZnN) zA0A+LXL_pYo>TYUb3P`0PP*y2?m0jmq#*daCEb!nOCzO$;vmt+SeYT=A>ke%b}~B{ z*i#4nY>W6JzBXNlZpXA`9su@xnD~QOjQ@iFr@U0G084%l-;2<9w=IZVF-QE3-a`*6 z8dy{%R4K%>0=q-qp^nzZXl>-y@^kJP2k&}dJ#mF?m93$xp)1ppX)$9Ywol!!F2ojK z*DO~pq=RxiC7+Q!kROp1>I(HXb_XjC{$GE`Ku4ja(DH$BEoP4Q3hcQSP`p*pI=d9y9}X8aU-8oiXblt|4^$tFLO zpNB<Fboizy&kyq?X_6wau z!`Z0E*b^+r_|;gIs6jyAo*wFtD)gp?UM#2)HNw8S0mJ|z1IxhR?DQ+`t@f9GTwj4M zN3R&J7~a|5*#-p$1$L+HN~@kyJ>|ITs0(UjPeP}_Z%1KGqLf@pJ{CC=*_69EcY4wE zqNV^dQKXfGz5TFvyiqt;a0Q7+|b^@4&QS_q5<(#d7``&-Uv_!xFymW z0r1d}0dOVsi+Lry6re8y^pb^|S5L?%WEn$g1MHD*A~lh6eeVG;}}6mwn~F@*BW|OJKz@IM4QP;!&biVavkf zxyK+J&N~x66Fvg+V`@A-ekpn>+9K8>2K|YlH?V;5*mQk{9_Azbi1@Jh-00ls&s;yQ ziQYu_ATFex++KznuO~skd~nxz*9dh!V^oY9Y8Yy8B2Hw!JYQx-R(vcylW3Jz0i`3# zTg!tay#{B?mlMl~@!+f^WlC-VaseWs!c=Y=2YZxZAKUEstoWPg z>u59{i^KZ%SMjSDl|s^K`K;VXX`(##D8(vDM}GvG7ZZT}hTk3sGDD0p6QmJ!bD(H6$C z+Oftl%QMrnCAc}*HnnZ)jij4N^IY>?Q%#dh*?OLSNP5!wj>I!M1RcvWD`HRU29 zBvexPP8f^~L@30Jc-X7nI@UVI zg@n*z5X0!9bW6FFTwkxNqu}c&>?dqGIs;u{SY{KlMW=^^Znz4UYKhD{~T!;Z8(k{$Lgqc)XnT>_I2cC zq*SDA1g>q!<;$bxQRtBc&5dt}*Tg}}VC9~CPkzWf=?>@0n(wX%A37stwhO8t0hcSnglupBbDPjJTuj+U8njs8O^P z@Qym*d8)XCk1>ujPBBk0Z+C8WHuN>|^$PY5b`Nw5kWR|Ek=#haKJ53{2W*SJNpC5& zk$S{?#@83FFB}~i85trB7pCh|^j3NceFxwvFpu;Sdx>+@`RZVGkUEAR!>5Axw=udo zn!{u>PsQirCE%Yn@a#P%kLd@hBlW=auL<76PD?MuQfw$s#I^fSM*6f+=F_KQb(x^`b8aj zb>0wfiW`J=!Y$@Db0mH^K8>BuuGiP=UMfH>vHW6bZft6tqs`NLDL*NY3&J^U=#N`m zEG{-=>w#?YiiNcks1I+6TjO59>pn+6M9qwaK?PiZei)^=Qr!QT9t<6gME6GyM$R#3 z8M8{M&>wSwvOsx7zozFD%`Za2T4)uwnk&@v^_$pj%r4vI{;`3v3gL3$WIlx-X&PaA z<$3M-pR212&e6C;r}&Zo%y-keXj924WOHXr=XUotcgPiXt#q$+CwY^+Z$0lk@0{

(5Ju;5~EVPVS!Bk9CNK_Ilh@-L5*b(X&^@e&&K|P9F$_>S<`czr} z{}>^UlK;tFT6)lq=B9oWOZPuM4XL_Q#} zo-{UTT+*wgmr1AXr|lKMo*M~JQ$l8Bg20K_*0>>3=kYt4olGj9??HYKS*!}sRrO-E#wyR zA>pt9HHu*0!~|*_)!6>M{f70r^^W1L;UIDV8H0F zzD)TqrDm{JaE5)l9cnCa5-0T+`U^OZ@$cgw;%y7t6;{r#oWCggOY~Q9qqq&(iA=+$ zVqf$xdND0igY$4Wjv33;=Iii$f=iT(mWy_Zc8prVnqDog z75`E0C?Ta#DKAx&ZVERAs1ee})Xr2Ld=jL~=z+MPn4BsxeRgfL|8mX*Q zRp88EaYIQ1tbt6D#!J6}IIo@4>gaX!Iov$%cKB8p_8&QTH-B5bt!~q{YOuEZDDo&W zqG&`>QM54njDNvbkju*=FYvSIS@b0ktpVn4?`r4To4h9(dbVd!85HahD5sWFHIrrn z%+3?{#=YI_-R$R$7mWtofHx1cT|LMj;=4*+q-t^vxox6t;$H5( zT>EF&=W#`&i^gf=wXxJ#YM5b&;cw}RWM^DVd%gp|60F~+`ZIl>ctAXtIG4B(J0F9( z4bvi1B7YS9QS^OY)4al*qMWjYWeRW6cj-scBPmTw*0QA>X&b+Tzb;>sp$|hZe;P1jahdY zeltK#Cpa^3LjF^RGm=TBB-2sz(Qm$Y6FlQRunxR5b6Mub7aEv7%O9gE~?x6KfKq!5LIp zt)@;^CM#z_P7-5c>_hBh49?)p1hI%-K>w3?kVs=w*la$BhjU=C2IbLQS_!SB2DM1K z5nYMf=G*2s*4I`z$CeNnfs7mDF*e55G1N9xb60Z@aSnF2HnlZv*M0@3T7PW`xtNr^ zlGp3=_*z(6SeEL`^~nJ5^-=mNyn!{m1?Ti`fICk+PC8VN?0J&>EV)s!hQ%yt)-q=Tb?C%6gmnSd@;U4qI{xpsBs8l|Jem|3n1r#b8maFJs7MLyp!L{ivR|DhCD@} zj#Yg_1H(z_l;osc^w-$eSg&~R_|@p&(bnNM;bukO7o~+VLfJnUfNkHn_fhS*W*h}6N{$^46Zp?iXTg8epr4-bOx zYi4L>5S@~gee0;yoNV9N3k- zE!mmuNv`XvH-wE>GSY^C2JUlWy`RnAbeF}aq$dSHE$4tje ze}ZrTOz09F0C8lAjLzy%>)Vbvkj7jC?r`WxsCRC!+>Mpe&2%Sa}+j6(%4){9gYlTp`&`bG+ z481csz`G+_SUV@26X0A4)NS!2ek2nwhNs}E_}|E7#1768IG4DPS;QP;kFtoM^H4_s z&PS(#paoi3A*>Wy%dO?@`gVOjv4E&ZRiu6+cau;%-y}zBiy?eE3l?k4|@6`{gW>5?xt)r~TwiH`wTPfQ` z`z8BF_h)y5K!d<=|8Rd(M-#_I@*?@W;dcY{5M2&9@Bo07?*Xn>hAYqg!T-TuP|hmF zkSqjhJzQ1(Rw8Oh&DL}E!Pp?Io1wcw0cWW!DN;U@#|#I&7J3M`$ZwV30L0V0=Xq`N zTIH1vl?`oUwlalMf%KpHTy3I#ul107$k+J4d8l=HLi$rWBc2t%uwPg>Hzh^os6Am% zz!~CC=x6jT`Wl7x!nNF5ZZtQR>!7vQ0+gSE+^CeLwB@+rxS=dw8h=VWBkGX#NW0l) zzGA*)_Sw9)$*yUx>R=Bz0=%#o}ykfX)I6xjETOq9wcwXWR!JOsK@z6JCrZhv^#qH*bGsT(dfE%|LJBV(O zn@7b*#rK4M4_U+3@bC2Rv{P_F%T}>GUzT6WE@KA?gM^dlX|$xRxGl+(?9m;XBZkq~ zNOmOqJpMGkRoW_<4Hm%GSzO9jk%Cxz{RaRrD?K zhJcz&@DBa%m)l>iyubQh%~$hL1yNv+TOOH5!n)riej*QNL`R~-(ecDMVwbvG-On6g z`p5dk%0|mV2oS9us}xpWA2Of z#^7ucoYkJL&D4tG1@Q%6fB7oE7vER>TIuWR=&ERzR9sSJP4);Lp(FU57YK_4Ns^`a z(mM%yYpzjND^TaS71A1kUdR`P3&J{j0}X4<&l1lP1GoWP3!$a(i?|T1-)z=NgW#Op zBJd1KgXdY!S=M>VdddoYHsQ?R@zC+m9_DwZG|1a^s5;bU<0d0~&ap@|l1~@V2k-;< zFYd+eG5*p13XY17ap(jT-g6adA#EMGj=bc!=tO^>S!(itHP2E#b>ICC3&Tl)^@c4sed zFYk5#HUAFJ4$n>NE$d#G%kU~VMi9h6yg$A{-XxEWjg9Rp*j0cO>ILbE^u!hIn${9( zTwzeh7 zLyqak^v(PR{#N1L!tcL)|0U&X>eqil_d{@2k_7o^Ffs_4z>nug$41AX9}w)x#dK89 z!n5#a`hWToVX*+~H?Y^>JFFBo+&av<-*LcE+gjWD0sDZhkeAE>XZ%8ZCGN?0(6X4Tj0!kFR`ci6zqjK zALUPDXR%Gz&DJTl$+j7WX@*P66$Q>N!2Z3kC2VO8&ZC*sEb3>hF9vnhf58{v7L(N! zGKEcB%v;TZgL6y@Ob9GZUy)wASm|P&f}Mgbt*xwZwz;@eLfR+p72&)^^=OT#JI9^V z{X_Q;?LM{pR08nk=4x~GXS5Fru^05TRCt+hqqbFFVQ;Wu$WWw|@SSi9tmQ@GBC${{ zRGTWzl;hk{?mB&g?#^~&<7!-OW@u^n1z&_8mySv^nb{1S6^A-M-M!ttbJAy|hm*s} z18jqB1d5?|)q83;yc_<^`pi1lHP4l9OS84b+v01qRoWMDMs>3OU~TJZ?V0PD<7s1V zXMUhR&@GBZIS061J*)xN!_?ih+P>1Bei2bwU^PShXU;p}P>n9s+q2YXUKjmlTN47gVEj}Zj#-_4!mDx%y zz#W&!i{)ADEOumURBS_dW4K1BMhI%Vb`5t8_e%6iJd_{GyYXFko-x-r$vD~QHv|n5 z#$iyec%5af#TN($tf}VINFWjz1I}ltHMO1J&g+`0RkBpJjB<~3M;$Ro6+;!nN#!r) zq<%{8W$k6nO3q9!N-IiR=3VB6ckZ~3=>xSvS{b|)UW_bGKB1mcA1xm&X1B$i9!v}N z1F^=l+EWQIj>4WjD$GGjTkz9odP@B4!Zq ze)C7QrwV6Apw`SWadq|ggin{6;s91Tp14LSu1blBSKWrBu&~T zZI`NWl{x6~5#^#>NDu4x&G*gYoa3F)V>krX$T9jj{UZ7@dWJvE|A)Q6mY5csx}iU! zC%Hd4IvS7WFuBYd^bNYew$L`&G1>7yvNJhFo1#6I9!qdGks>U_ZR>4od2c!I#lWRN z{iJ$H?j%=Iao=~oh$HMc339`K=I7?}R0V1jF@i8iCTV75X2f1#D_}xw=$d#{tZS%a zV2!M?584-n+GDVv@NevIY%npDc!E4apbpP<_9{D! z$3Mn1#B_0~x?FY0c6kKY+q2l2>;P$y^csJKcd)hxEU%Uoda}dyevCdsL(Tq$`eJ>O zae{GxVSoYZ*^f_vpvTj&-t)xx%xH2L9hdDF?SC3i8fWOU^xa^6oIsDE%gJTrdHZ?$ zZP#5F?nS+ye4l*tymP&Moqe4ZEEOzkjq8mNr#B;-5Ku?>4gZ#J6>Sk!iS~tF^NP1_I$xP;@nVfs8~ER zF7Q0Strx#(?qnx&5^D?B7oGq-ZAHD?7ZF*~bYlM14FNBu@^j^G#|Bb%`fA1oh2GpxTs^)%zf;+v1dYkYL)L@Vm()vY5wZ~J$@kzl zv76bi$`@q_Ih<7Ovc0smv=wTUR0OyI);s?uuajMEoo($wKwhyQJ%Bz!AEH+bR}KA5 zKbv-uzmu;32XEtP<*A-hEu}=UlEqr5wN2aP+2APy@>jZ=uC^1~h?T_3BAnq#E=(#c z_PN++=X>}24_`ihIRrSY9kC*t^o=^~<4EEIJfIWOK4d?#4c~@CPr__Am)*f_=T-w8 z)?XW-t(8_w4%W?@7$fsRd?)t8``}-V*~Xp74g~7z!v5C5$`EA@IKPUgWTsd%&6%}= zb%GnIjno_cwO$q}k3h}Z)vmR!o9=7wqvm5~c;8$Jsep_&jWKm|c6GYEPVXf9Bsk_;xXJSmO7l=vRM6M~wUHNLBdP}@1 zu1%~<+=<+YR0rpE)xs);?LfSaypB*j$zMh;AsJ)_Ig^?}{b=fGiW70-0(Kt5O@!%& z`?}kg>Q7ysx-2#B0|7vKj+7^z5RZz*iIT)NfS;-dss-x0>bW3Ss;|}2YUB0r-p=06 zVriLao>Wij4f{3wE_62vwHB@^mlX{|aOi#TkbFR1x7@Ila2I!b0^UH^V3%N$JH@@h zxYl?_y`@eDpH)Ef0W5e(s8v*}X#R(JA5OhJ_4aiBsr=q@UpYu6QLyF%HDIB>GR*zs z@$qxslDZ%@@#o7IHjC2^pnfwzw$vbNvtn7kaLwhrG%U%$Jsdh zkp7p38Z&>PC(wXB$$r4K&ozgdLnRbOxliAR5*%?xVkPKrRDkE<8`MqeZgv+tF*YH# zFtIQ}={DU)St!{14r`$6)%EIJVXjb8EG5D-;2-OK>r&5RPuLgn{ptV9KgcuCkNZgT7LTim5fV z8XDBJHY$X2Li$VU3?eSZMc8AzIr?k#b-{~*1Nn#YClyXCjECc4B#y*4$F{_lMwdjp z#Ja?m0fhEidL@m(N8)iq+%OIsk3p__H+(1DIIl@wwNTa2LT)~{S3jUfu_y*L6iRbt zx#{c-wyD}og|k*KZU5Pzo&m(;u#XOU_d#8!q4uHnrrxGr&9C}5`Zs-hzq!r==TgTK z2h?DhMb0M68p;~>pnFh*1_Hdf#fb$8_(G3xhq*u0Kh%W)H{Hko!8@T{(DmqQbRIbK z?iucV`+Q-Ybw9hGt;kelLR^@u#ns>r$B)KGhDL+sW=$y`p zfcxf1IZ{o$2437;%Dlt2)ixUNx-H0N1f)hbBaxAiMMCdEQ z!REo2t`{yBWv6-|J(2&ZUDWO1Yze7hH5@OB&(4{XGxgK7Pjzx?w!a=!%b2sO2 z&VLlA!+j8}uFeM0uh_rMR>O--4HOm34hg`jpfe#6#NyTW7tC4rhT684nth zeJQ@CY2T;00GdE-i0w1}8Hak~H!RmJZokKW6162v>)aojwlImIPH1?PA zwDBM8E(Sf*G+L)WCq5YXG)k*8D!THInroT-&Xde1W z{w&YoW^twCW#U&Oe@A`@cMd-&ykA%{R5ElqemR~EICT!6!$Z#wjMurr!cald1g*NE zrUB0Qk3@zed2As&Bs?g5Hhelf2cX!g>NK??S`lpmF#SdGq6qutCh(JZ*lSo5uZiz4 z>@eKN9$>JCb-uJfdZ<0rtl<3?TJxO!e2KV3{F}H!v@o?Y$%u+Hks3>3k^H|H+?eN`jCcv2|*gsiVr#Kop8p+Qq$P@Cpe3Zs%r{>hI;#cu&$W>$+__?;!b9i$&niI{LmNO&geB^B8Klz1x0{;_d!1{l} zKjyFTSNURkrfxUb4XXe~uc}qkev*EYrpwdi&PqqcFZx7;*5eNg9u+hJIcHRObhsVg zp1+}8(^jD?QK)aVRoE&FlZH!Yjc1Hyyyd-j1GfXS?X&DLG=>(6Ara0D?=tN&ksh;W zvTL%djj65af_h%PCS8@FrxesFY?ItF`L6Gt?=ks=gxdctwN~00@bij0iaR8)>|Kt z+^?hJqvLy!y~qU9c+)!L1|!rEPLc!iVd=00HALqF?7@Mrsq8cs_Tf!prZV$mb7Oyp zuZC?AO9Z4cdY-&MUQR9{qqdl>s->!Bl4-K(B7PA+fgD3x5-o_K=Aq_QSchU(yV)b-T$98Ef&bS~voiZ#`qIwoaIO0z)IK(aH%dCYXwG+H04L;aNt@;UjS zcu>rtbLi|)PH1OncW61il5VUvR6$xK!bB0V9odQ)z-h6TUCVAwY)^b+X+_j7~jZ2s%%&^>{xwpRF`Ra_>W7%4^X2gy7J>{;_ifPRZhz*P_W0$bK zkiJNWEFw3UH<&RaV*C?)7Vzh7N46s;@Dun+^J()S_W<|s!0>=G*`C}j*dxd}8Rt3j z0y&kKN?5`9KEyE0uo>Torzz>mq4=Tr{lbTZKZd)8JII~nMpOgpvHhtX=0vDVTp6v3 z!kH4<7&q3z>)_4B=3-a6E8Q^OC_XnaCqXhKQzc$GemV4asCZFU5jch;2LNV~1y$ex zr`*YIV;6(>HkY5nL;nIe3khdFI%{3DOW_OQ)?eCuiRZ*~p3~3hGx}+LCO9{sw=X4| zWu6!Ll1fR%g*)&Hri!MQ#@EK_V1Gi-a;VLH0_^$c)PK}H+dsB3&e6^_-qqfTfr)|6 zfi8iuzHz=^oQs_2sq<7FX%Y{AMc3mh?R(zh_>WfaYF%j?1FYe zXDV})Py8o-lej_L37#kPV1m7+r-U=YcXUY_p4VNNu1upugGAj>-HWs)*aovZp#Kl%ZEkD3*;GM`z*s4+RVgWgVC64pesSo7HR z@Qv_~k#3P~^j3Pe^t*(CukQ^_4RBq-89Jyf*B9hD#UVQ`C0$8M3I>BO%`eQ*!{j~S zm{12RXic^Uie(Irww1S4Pi_hv^T}-+JGB2UCM6I1m2{eTnv0`>E}j z4otPYDtXP`HGjA8{et&fz!_d77s)g9sd`k7$yaAHw( zK@`rul;z9va9@`ZN()=Txi}#)F;QMBCq;=UQDhF8=U8T0u9>cyB6tknYuaNv!a1 zlAmhNH0WIm{jq8!Y9ubiF2vlllYYcJVeSZbggSB^dB1o-T+XlHrveNig9Lg@y78@l z7V7Gza7i4T3G&H)xfD@~$f8P6g;)Uwbrhr=Ax8#5CQOMn=o%E>W%kkg>Tm|5Y@$r! zgY-!%V=8S5Is;DFJ1~!!M_dvwi6BMu1CfCU^sdTD%1t_-dLi{u;NL(4PeTvsHF|#n z=h(ueUy_P@i+d+f<0&&@MqVo~m6h6R4bBrgcqdP)xuT7fp{Qp zXKgIZlO>#|pi!p>9sYXoKiZaGpSY9)*yId*nTGFS-w{ z!`J2;CmJWN^4EFj4F|EIZqiMKdZ7-_#@+mHya_QO^~`n6ja-dfJ-j`=42Wj_=KjaQ z$HATco&IIE6@aIF#M>(ElsbH!Z#{1-Vk=^c3Kkah%I%d~yRc?qF~I2>sg2d2@SpG& zNXu_tn+UIQXN9vu3xJVRv}DaFo8&J1|M;csQubl|L3~VTTnN^C+84Adm|QTeU{le$ zqA%euVLl>8ZqqmDbHaJSBe|uI!e^nq+Ckj|_)QgSCF@1YWy^o~f4DAag34)J1PLSM z9AzEzy$igH?Z4P_uv`rG)3w!FYdK^-IoCDEmE;P#K9KLpvPfA3dWKxYE@GQ(8*N*I z+k)FOwr4!ae4IHmYkJnG%u$(YvX)%vEOO2UpB1e$dWxJZXA3#PTjm`@N9ahSP{Yv7 z=&a});jQ2yJVc?fzzAmz7qE-i#qnR_u=ndVIMdpJ=RHImBJPjvj};4Lg=U3jhaSZK ziG7NHj+clOk8}$C5Na509ECj)9kdP_iIaG1v^6?Z8>-DlXQSOM-7QeFu3b{QqzrGG zS0H8bwsu|Xrgm2+15BB1&$cHyL70=x_0W1K>_2a7Xlq#QSm8)=C%ZdXJ6I>;6Y;O| z7kRKeREE6kh~==Qx~H1wVc=097p(D$$rX}&CG|>r6?hroy}WmaW2d8qsksUIy(bBN zp*h=r1ga?MFGSiq<%1Q-li}*#qIF*~q9TtuVm*mUxGxfRpotmZ2 z6lM!Ym?I4AKR*ue_I>UycTTtf`a)4P{V3IIuAW$JY1N(vfy=ZsQ_AfiW)X%P$eKK+~@>F~#W@*K=b<%pNKRbXm zaU{18@EGWc@d0^{%+u%T%>l;m3j+E&WinYz?`WSWtVh;K)JY5#hl(H64=U8}g|*s) zv4gRG^gtT=#J0D#v)1+3^N(|kcl@BY*QZ5iM0&0@h3bA*2Z}Yllcge1rUp@aYeT2RWa?>Tl zWdrmaA1_W6^Z0yzygEjGjlIQOxEmiXkC3}3x+h?N^2Ef1#Bba#&JWhjZ1C)p$a#4WzbElqqG!BU9L{Y!j4ops?6Z5`yI!c94)1@bL?=bZMaM?nVBhZs zTw{)9p5+h2AwwCp)Hf}0ct;2Q35VN<*~8W%>s{kN#+rIfJuF3}7J762GI@pkz?`g|Et=l}<_fl>-XYkA>Rnlwwo{qr=dC<^krzwm)pO$vPyX&`MDvoEXQ9 zXBHw0kX&o774|s!K(eiXlt-XeULKl*Zl|_UD{ZT6AE{5&Q|uWAHGkn9)(&llwiVxs zpSGN_O!Q9jZcF_&wMtf%tdp6iGn112$;F+;o$&XJBgPZY@n?7#a5<>UI3zkGdNBJy z_Qx+DzYK^Bj6e;s>*nib3Vgiqf{*%5-+$}a?zh^(u zAL&Re5?d5o7=wSd@HQSmE*a{j{EzR#_htGqk{}5EiT=cN=S=6v;QQc1-vi%P>Q@Tp zgKg}uEac%ZrwjvJU=g{9tOu}tS*3!4Nr;rLWoT_oZA@DoTOGrk!<-Gt`s7jdgt~>_ z#IKjv%QK8KjHnB9&Gygoj}49q_73(9vH?1f7AO{Y;C|pI$`~ z)?7=IQ)Q^R>xeiarJ^OH6@~J`Rs06tlx$97IEo(uToUSUo#s#T&*kSbq2emR6a1F& z*6^+TTlp&rmKTf*j|*R>uh9Ddzeoa62E=3T5jPp2l#AR2ZY(>Fr5T!84E7&NV8nUw zxxg9wv*c+Ku7ySHLKfZ~9|zq19N;(aR zQ#Y8_n|cwwh$X@b;bzg*qCt5>@?ICcDjE;gnp^d#+tlsqGyW-Tqhu>_mAHreKRomS zE2orI!d!$a9se#q6s(ixk(QCE;c4NG;q~EHq1PcH#D^>~Yiuk%mL5-!qv5RU`uK+U zS2l-*vwoAElbxx7A2JG)3zN_I zPW#roHo9PcZg+Ecb5pVjxfJk}AJOjUMd6~bGP*MQH7`4FNAAwtQ}Msza25>(gmx9a z0w1f6Rci^g1vtmzH~GGuGbW?K7*V3i5P-q)C?2gDuM-b5MNB=eE?0^z&HhI3p#Ml5 zN=y_c3!1FSF(t0R`EobvLg$$lny%UYwka0Xa#}yByJ-*orto#)0(w3@6zqAHVyJ8) zn}B^&tD>u--D2Hhu$Q)?xuUtQqpkz7>Xuj7D=es_C;;6+BEQeH$J#y9UDICsetR?b z_wE+nmfl0YL%v`ATl~5g_4Ri2cHAIuk=uxE#7=An_6&KBG|(DqrKM65^j#$4hWLN6 zXEB{cxe|H_{VH*p2w`E&sXA52H%P%OK;4fY^`3e=wVgUf7$qFy4uN%lhCeC(C3cd! zNcZ@A{C)NT3+KExC>s@6XK5xilkfzVfNNk!WP9W%vA1}HJWOV~Gu`9tW9?n_uKHd2 z9z7s7AT~rA2F~xDCOF6Vn`yV{jr>}sV|0v&8l&ZfazbfG$Z;G$V>MDKI}#AJ30N49qHm;w4-}HkN~lk|LF7%dzFbIRk6cZJq6$t$l5L1DySx z2_s{K{z8lKC3tg7GfORZO}FfoyxqM$yxHzA?)u(_-h=)>{5`Vke8 zIf87*x8Zd`%$DXznUTy0fVlYuq5Kf^_kpv41*Rg?YGfq>`#@W8ExA|H3urB*{vjWh z$FQT>O_2?eXi=i5eY9<~Dbs|h%2ngagZ=-7`NHJT*>v4Rg9OyoYa%z1brsbnAY+lH zL^GnKxup5L?YzxmF|gDD$X;X_q6`6jcwqm6=Fl7$9TyyzZC7lI>^&cxG_UH#_k)5$3`i z><@=J%>CG(*)!Z3u9Q|rgB+l(t&Q!S`JMR+`Zv0V+r!PEr_r53jw?X(QGt@ES=4L_ z*3DjsFGQPY6>Fe1(D&B2)|IYRE~t|-9i4{ei3MU~v7tBxnT`N(NKJE1b!`vq3_MSJ zo>o1xTIRU)@#$Cn*Zt$IT_EjSFpkm1H*MmT2-{j(tceojB9VZriJ{7O8NE=EtMr_#_{ zEFc5~*iUB%=YmUj=|5sWV)e;-WWF=s`7-c2&?D)`q{{B9?y|-*#=Xiug$FSZ8-T%k ztTpDNec$`cE{kh2HHCsR@zDFAk@UTk;N!d@PQ=gVUdZk7x%=lKIfHZH z9X*^iabQjiat(<6uLDjGAe%G}8IN2`+%R#UHUe?CAu}rMB4Ehvt9W_uK)e-`T*>&;a|4SBNV`LO1A8A2DnV zSyNrSD_Tgk2Dugq6QDiVvT=2p%9 zsi1d3^+e4CtgAqd+ei6Xf$#Y$U{!0xHR4_Up57d5j=k4E=v(FOGSvCZ0qEQmsm@$rD4zOHf@XcyLqp9IrJr>mQwB1w(1Ic zCEYXDBbF>BNl*)Vp?jhGj_aO_pit_G{#0)W^2{aEMbiNHAh+yOd;-d z{6Y96&{|9zY93)8sv=gK`k{VZIIS4eoW$b)`c(W>9L^l6Ce>8OUB}(P z)4+3*Iz{c1_DSpGYvYv@l@q1Go*zq%p{fDC_zUq1aYQ+!bPzj=us1M|Dxfrn;`k5X zIXE9<*3J5F^6&Bi^Z@$G{Mrof$7&_jPFk6~EE(2y2D=8jD684p!_?CRIY$TM4@QQd z38-%cHPMPkv!Yk?Zsausd%9b+dlc%k9n+3!s;G(^0G^^FiHI#>Nx;9qrQTAZAMbi@ z9akw{IsSX}w`iMK+gLuGPtRs&vrzlzH)c1pkYCKdl%7kIm8r@IWu%fRr-RjgPKJ6< zA1z-jW$b0`^Ne$h(9;a|lK;t_;L^drt+21KZvyd`@uabv_CIZ+I#KO{cfyk`NtSlD zj{unWexLe^K8}q)&0hFWBSXimszKaoh}v*gaXCwCF~{> zX@VY;Ak*SGNG>u>m?k_8Jqz{u+WYJ3?A6&YXTq7Tx|X_@1pq(6IXI||l9k9xSQVS% z!0gyaY!p^StEkNp<_a5_jm&6zG`%~vD|Re)Ja#s5CZPdN2KynMvRkgjRp%Nr-!mQL zcCy)IF~M2Jv%z!0E1thS%Z!VS%cSKJ$(q>uTtjY%HdxCx<`^fE6Uim$QnZ9zQVvK# ziPuGa3^j^^-Z61|!p<8w!y);I4E4MxtCLlQ)X5RtKJHpfnu*YosOYV)m?jT86$@`z-q`|5;vG zRuapJOg&3K2-fc*>JMt8bBojLHo6~L9$G#UpNRSBeDn}@7^_LvAiLYU*^4_%I1jo1 zaGwsG30wZM2 zJS)5_v@5hKydr!xb}e?EK2J9S(J$UNelvb6{*%yKxMKL*km=xknjoF55bGez^iR?m7cTIDpxYOL*EZZ!1ushgk z<&^R>@-uSIe9nBschmQK+U~THncrn*Wfaf2lyo`iviFkrw)3`=u;I3|)EO#nikU7L zE*b6soN}GJ$(;+I4{y!glnad*0<4$qf_1|*gKijv4aDF~FPtYS)bh1*RC(&T`GvU- zQImKleUR+5jfV9gAMK~Rv)$S10GFL+PBR{Nb^_K!x2ii*~=>)AcTUZM@vl6rzY!|L&Mcq(d%rqU_&ANoQ4 zl;xDAsiV1LA2|PMghq~l=idTpflQ_*Qv1P~{@DH4z23Xg8}~(hn*r~DdP3Q@9NT8o zCR0h`I|9}d`+{dQ1LP*y<7{Fm<^WjR?c#0XSNWU#OXNQU_7^_}SP<&9l@N*x+dx3h zv`^pv&Ew}b_O6>1g6}l?jQ|+O)GPg2^K;G?R=xrz~mKE73 z8pFlfp}$)jv?Y4Ydff_AQ1DK%TgB*%L`FeUK~k1C)0^r{ zaee|=<}vx0>`ZnfRg-2)H>Mh)W_v54mGDpaet2NvfI`T57RyWI@4&P91oB}wrKi#$ zQ7;h%q-UkFLa~}`rWe#p3i`}8WtuYMLgPY5L&rkbqt`*M+7m}&Sgcx6)uLK?HS&fP zj4b#ywk2i|aAA|YL596ge`zPRLB=7*1@;B@Tt}Xx4#=Meg+l`DOM*2!H^6TegW1p+ zZGzSoYl+`<)1)m@c~e=_IQMw>4)0FyQu|UnLnMeIB!tjl&!RTMMtBHMF<*uc^?s8o z^StuD_CE1H@n3acaR?3(5U>8`9+a%gi@a2+vxHtuLvz1cLJdKdRe6>+Q*)wDw56fdw>tV+z&oIx!xQug3TNEc@@x6y>IwCL z;eY|^5kkM#W5@}l2{=0^=o9osi3F^=6CHIjrTh!Lf+0>cj z2s#)mV@+|SI97UBeyiK=@$B|Me}d+CbNqiucjOmrF_w%aVK?|&JYE3e6Z)w_c7^Pb ziIE9`kcg1E&^!Pih@a!n^XKVv^kMc8dq=seB#;C$NFS&_lAcQ2xg8wTLV!JiJtI9L zqrxM?Z)5LbCAbpYW#O_=S|}rw;YxGunKsNr{t*xT&0!x14PNJI@(kHg?WlGIoF);E z$29>JJL8>ko)pLoV}`M>+FPB&&*eLdoy4Xf*Je3NI-0t^cg+Xy-=#UV?fedYh&Whm zgSJIe%*p2J&T7t^fM@vA{pl-B|vXI?|T?Xh~R}L?S50{6^)urlEeegQ{WRP^aoUUiyXI|22 za&93vlfCfX_zB_!0ecZB7v);wUF`kh`{+C3JL*gGW%`DBhI%&Jw%8sL4~bSX|#lPmE*Ut#~e{vVG zn`jqo0@N>pGgMxO&yk)INm=1v;h#)SC6Dt*`HXma{1p2K3w5FF4u@m6W2d7j!1-^) z*Wz|zhpkkF5G8fOsE1Q+gbU96Sac*umzngES zHdSqi70JPJ{__m@sDIEqshw5mkLk3zY)jmW-Q_%GJ)P}c?2Yjz_%>uaGL{%aK#jP? z{)K)f$OWNk@2<%1$g{|kNTJk>)TSv-QZCpo+omHwBfIpSI*E|TUF04zNFA)!PS#GY z%vqlEA@AS3k$`K%-sC6p6IlzKJnB5=#Jq^NhOY*+-|_K2&i5?%G}t_~d1|ddjX+UnQ76>8g}Tn&^lo}3rIIp< zoy^WIm|ajTt7z8N>>b(H>8tcAZI!l2TdWlUwYUq{g-ZufRxT?Wx~4-O0e8u^i`&J< zazlBzGE%t-@?mkd2n+j|4U&!j^OAwOCr|iC`~Z3oJuUfTGR7D1b~gywISkA@hHIWXZ5rCG~-7D&XGufS3ahn&@aTl#X-nmWE3@qf@T_Up$Y2N{p|kP zT`R3d+K?hci)5r{q$@7f1$X0HD9x1<+6iqaIh3sHstc+w>4KhuC5;lsFY0pj9&!tT zy@ygDhu?MHagL-$Q&yBhSpfLc@KhX7EDCyhE%z<=LEj2ED+xL00mnf{Q?e-;0x`@w z)JlQaYHTssB$rgPwQO&eH*0)!Tomf37Nv?)KGIJX*NSKj*~VRjiX1Tad#6?EkTY_d(>CPVBnhn!1x@V58v4ekx9K_&QWU_$`zuD$iX^|ti3 z^7>ppR~t)POE;_=c0xa)FOiqXTgA=dZcwLoFuRyk5Kh40FV~mrL4egOCMqSq#L7WcCI*gP(eJFT8lXJE6jUx?*|4{+IO z#&n~d)?RyIJ~x+HmRlSEm!!MWT#cz_|IIOP1e`Gp{(j$Ex?8>gti9X6!+$t*B(yiO zC$c!aIGp3n@piU%viBqU5^v1+Cft#}tXcrO zOmU?AnR+30RK|#mdKvXIs-#v=t>vlVi4f^TL{HNPDFc8N%@TOqC#Z%cQjZTc4d0J0wewAq}hPuE{4&y|Q2mRj>| zc{rl-OKE0VmN`f0Gw(HJ(*4i_@Sa$MTFik9;e&6 z&br=uPrIu@AF%qdy0N@iK`hLM*j{o^dAGJ(3xhLp5xt1QeWYX939JN&B$mKVSWj9T z`0M%M9r_dyi$UG3jedicP>Lxf^x`_yT87W8maUfUp7ub~L9W=sZQ^7@HNJJ%cFzvY z37znr@QIW}CCuc1{)8!dx$**yeGcETx5#H3dg>W^^Q$SOiC~@I`&t=g@OU`f$^8@OZH#sgS1p# zst%F|%6qxJoKtj&a4+*a&!!_A2%&)`t0xfj(=3owKh782CH0mAQ%8 zz+6mRNW_t#ni9^3b=$HBr_7W?Lltw zzN^qH8{V;%mnuro-};jEvbCtAkOTH~LwZn$n*Pg`rOGbLF3Xv~nLx?(66v6{WbRAf zm);`WJUrV!$A8d$!2Q*hV>?frB_3l>u)FvjydGK){Y73Oe+GE6Y_xn7-t9av9vYC# zqi)PS8oUERKFnVN&orclRLJMLgIw9k=wKY656~O(Hs-wqQ5ocLIHNE~8Z0dk=ZO%b zskBDlVehbugoVOFX_3@L>!v{+`qkhWKk+~H@AU2Tr2-z2R1@k>VYl!_{v^Y``oGvm zY!|W%*(vXoJMta)%jzYym93@iK+1s>sKv6#yU6P$yu@|whQ^t!39)!zZy#?c6bV&} zREcD!r>D=!n3pj-ZB|;dK+`~~Bh|48TZln_^dCU9P@Ag=i?S1PC*;2S_~xVSi~S3% zTQ#xjSP7~GHP#$&E)^Gxzp;nedBS|5q2540W*jpr$`$34+-WX@&0q(B=M5-I)EXtD zj)W^=6)XaryZ-|}jrSmW5PzW;&}?vSJK^o|QXm(F0+B#^T6&rpHp0*Bf7=&o^R>8; z5N>I=wNchl)_?sU{k#1;{ZNM(`XHGSCf7o%qYE7i9Gsu?mr5y<($wC>J{ld3Le2d~ zR1>PBy}cd!Hoo+}^fm%mI}%O}w~MrkTn}6iba#I5yhGd};Jqc(6BvvQ!M+Mv!kgT; zxgS3K`(fPFAOaT zy^p+)4EK%jjYY?xpSdqw7p4;fb%?fEwp;4C>bW|R9mu!xTX`Y3m^&$*lHOvkv3<@x z&SLIj?l9ob5U-6OMi8B;&eTl%4EtvHM)w{6UH`JsFQL8Rz2R6W8VUwNfrsvg?xBvM zj;@Ywj)#s%j;;1>c8=u9rg~Ey&aUp|_Ha;7h`>o4YBHR(oV2_Jd8eXQQF|yqkbRn0 zb0QA#NroX4jd8|b>O~d$D1S|4C(@(o(UAqC3NFO{iuL7t^WOjr)eq^7KuiMX^z-Ok zdagKEg!3m=Tvc6#Y#`Khb!`5G{Ja0&`FC>Gq^#lmNIp(P2?>DQ3?f26-I(?CuXIbP zxdgrVhPj5ha4+s1Ya3%Lf)qwzJ}w370%K?FMN*2S+zH+ezVW~F&vnmn7r63VT|Her zZjaaVuj60G1nVU08S*R%`$c2Xv8Wy7mG*2qwi;cPZUyqr3G=vF%Tn8Njl4p_IZd3$ z_>tl$@i+63>7%^VPxuU+ln5yni^m$}*Ut|Xq!v7iJ&yHC^i05YzPYh^vBimniCUm` zdl)aXm)XsnWKJ;6*_JHSK%68_6eDt~JWp64Gz2-YbF^!;N4$IdJohIDXATEY{i&D4 z3!dxN|~8X)zN8?%;G%WNb zkQE4mA8W`KdgOoX-(%lxhhCja(WNN#%j-yVBcsV8j5Z3nyuytUl5+<)MI;4PJwN^9*qZ2~osYUgd^tre~n z2FEqBI(1EIr*Nk*)G@l`zv7R(60Y9>pG_bPa!tFY!G6q9`MA7=+sILIYy4pBK8Ee?K;u4)%Gs>aoSF zDfr{d=`W3Q8s+o_?`RvM6;a>P2%MqU2=s`FN>K@V6sMsP^o;taI*1v-tc$OYmrs^Y z-eGUEP)KbtyNIQdWb#$=b@HZgQ+S9xLQ309+V?s3J6=#Ps4yPEVg7t)eP;#G*K^5t z$yWq$dy_DTepr93I#r#5KDvO8q(FYy#@5z$9MlO`WJDXtn^0%+SAd7Ao7GJY=^ ze=_A{N-ujK`vGIW;SgLx2A{#h9sl>nJHxHJ^eiDqm_yH{#iWp|$JgZzRaJK*dy%S0 z7383PNPn%r(P7UA^2(|9DfVKnqORla6Ye#>)xMU2R)OxpZb7(LI@UVYikPTb0py1Q zBhMIvj72icbkizP(x}AfLO^*6 zJF%PN8{>b*|BB;DBB>;`WJ$U>T_sUD!9>~UfO!9SI#Yn+LQ5+C*{!S;SG;A=o8*MY1dzGQ;K)5VgqKWF2QM zXE$#TFXGaj>3BN6Ui(#htG&@8SUP5a`c~MV>7Nvy5?-9XDE&*JtU?_#+h=|o`ZmIeEg-Q;WIuYEuD`}BQI&z#~yF#*MK9OBe9+B$7Dw~CV) znVBk16>ICY03(g)Cxl}HoK5+a-axw;H#3YK%AVp+@dt$iLQ$!xbWS~|`i+2LH>}1Y zz~!LV6Koc}M?aux)^zJm$4wAzwLOJGT3_`JfLv^poyNb)%-?KjH_8gT!B!KP~TV?`_a8e1>C&qpz=@&l~YX zo@6}Dco}{Xe&l@O+=J{!-Yf4F*i&tY#E1-wD8+wbuo z@bB{%4HONu2)77#i*$~RNgbE^L*Rdbh&$|_Vw+<7$vWLS2H=?%))v+c*d`46#cpM{ zvK!eA><#cL9g|cltZMq*_uPAcGM43wN1& z%!=fSB=l&7y18)1)QZ~B)7mKw_K)szx4HI82W1DjgIwrd=V4L9)o?+Lnc`+KbB;Dw zgBr&zZ7po9m-C(o91Sc_S();kx0QE=d!@UzyOsMp*LN;Bo3@esm3)pqM|YUp&A1lV z?2=Pz#kOK$f9J9IL>y_3G#}y*@GnRg`)Fzubp$<%s;Gp{w=S@T{2~97@T2fLz@@K;Z-t#8CWR)4rUoYm887SoVEtfy ziT#5ah=xo=C!w{ln%FPqGPAYRTH41RV4?o9g2`Avdq2C|>apg6{Jvk>FKv=H$iJDt znIu6FP;>Xbd{2JQz2n|6@0gkNOu8Wm=*M-MJ;fFh3JFfhCH0Z}%A=H#$_QnY(oyZG z9ygDg0WyVrVtZ;E;TY+7Mm{5V0sL~F|MS0Cpe|6MCR9B~eaB(zA*+rUNK2`Ow3*+` zdkvpa%wEKP%5&0l)_Km^0&j`uftu;n-MT;t)IINg@9OZ%@aVL$X~QBzBOk*b!$!~y zdi`F1(n&jCQLm_($SmYrt&Y|U?u$vor7!Fkc1nCo{8Rj6{0;w#hgyb}@hbQ=^Qu`^ ztRQM2k13qW?UnXOAvIN9sjg7h%4=naS1U7B7%s-df{9R~B3qF?FP!_&&-w+xVhy#1 z+6;My4E2MLD902Ep%BF`+k^hFUw51C?qqjT6a{fxd|P~Ja%r-I)=pbZt)UnY_qB)G zE@nGGK!X@3$cR&&Q=KCMBLl^KC44OS^;5=4BiAf2w@{m@O3up89o`+@tAT5QIsk{V z5k4|0eL_0y2R{YhF}!1qfc*Pdf1*Pl`mNFyDLtAN&HD1?%Z;x$z8>R`@h|Xy@adKr z7N}?WPI;%mU1_M*XGiTQ)c-id9Ax&y_r%GhCAo{;&Bpl{5AWV0$#C*Ah#|sYp%36z zPi)U^e>?tmK+U_Fcujl)J{DgE>i=QSAy2+9&o|CF&e@D?O18$@U^K~)JzU*gvS0CE z@m=lpS$3`;O^k>;QuwSHV_R)gVn<| z!~dlJlU}-L*`n^k&cgeH`-8Wvx2>DCjT+QfUZ5?~;EeHJY#)}Vs{*sn{D8N-a})waT?qShPz7tfXGrlE92GiDyHJ6#)dAw8^rF|v%8%HPUXb{h-N9)H9X(k$R)NQM&M5`Fu4`eF3=bYH|$;{dY0| zml|F$yug!m11y%{mr6^dl6*;?pmF*xbDv3({jy*8>72nCM?n7CZ|*gr59E61I_Gik zDKGRVg&t&!)J1ADv6%?{{Faj|$xDul4#^=qrc+a?G$b8)Zaz165Zj5mj(U!ro*kYC z&il@`czgV~c1)Y3P1GEy3;kgI*V@6?!RHTq!=uv2q=yR!3V+S~n)!F=MF{qUn^>A! z*5Ipg5BR-sk0{6lnU-H$eeM3K$EUM7XL9-p0|gnAu=T`xqPNytE6inbSD35J1aXpB zTrZ;MXgOLRp|>!V{*kUt*P=TyotP8c2@dXR&6DPXEVoN?sUG!D?fid#C-`1Kt;IfS zZ?%Ql(tJ!jA`Vy%S^(9g;Er8Oy@ftQpRUJ{7;+x}6Bh`cfPT@B%%`Rg^I`YE`v`pr zpr&aze^-AQM;V8Ww3A^XOk5!^leMjNtk9E=u_mq4Z9m&OdfR)KMt+H;6!I5>+CU>* zqg+$XiRM`F&K4DmiIu@K&SAf@WR#5F%et4fJ$rk06}mD#02zo}pe|B2(n5|zN1;#; z^n0ua2DM5?Aj6U7YD*RN6MmLvNMR{e3b7%!NPf}$9$DXKWo3WKE|MsesH@afRw65r zNycP@lQ?Mwzm#vPG*j9W9f|d}b+*6pzwsRTtE|%oU4f~{yiosEv#8J19_v2q9sCyV z2K5R0D6KM98E~fXmg|PAx3{-k>@KF#Cg7<^p1iua54c`r~ zOLo9m#j(Tj{>XS@%+Y7*oz1T1d~^;9u{!JvSR|_?2$E1MY z^d))`{R@R&96jWo@C%9m_YCqVA$@ zYYLh2U7&SfuYZsKkmrbpbF$70_DgoC3;P2)423$PQ1_nU8D3>H<_+_T*#zqU9%Z+( z&|GL$TJj3`?<2WUoFQn!B5|<@aYq@xG(R1j4nwP5mLAFsX6{JanPv@G0>vD~98a-lSR1po33V?Q8B2_d>P5AzSVpYJe9IKD zQTBv>N(iBqIJ*@A7x8k3DlFX~5M%dchVxw;qGi#Y8rdv$LO?+foU?@QY&+XLhQ@<@B6 zL0`hd#P5XaQe0w42vHf<45<6?q44{{`!e=t{24eKm}j47zl>f+=WFw{xAGeqdNal1 z@%Z!H=ee75H|H*-=hNrRKh0drSIczEG|T_+;rLu+9&!LVhq#6SKzTh1t)Ta9m8IlZc_~w*lsOE4~)Hsa@2z zS_iF|Qdp@2p22bPm}uwhTnV-W3%OG*{u};0h%wR_skmBH9j}eo;2rd2W0Fx8DTgd4 zmy^9*y(+nu{7w?{$ug5C5kdZDmLCJ*!eyr94P`m^QQU?85yr`((Zf zz7Br0f3R;wx1;bb^B#H!?FsS+^k1E*PE`M8J~Qd@w0KpvGMi;&8!rH6gdVdG$p_?A zWE%1mgqQS^Yiw(5P}B zTWkro6x#{@zn!U$R3~p&FPqAyE=ZrB{@MS<-wp4MKNX$`a8GfbK3}g5IL1F9I-8wL zxW}}DTh0wthA3U|u6Qe3YuggrLYss-~n)x4X6 z8-gbze?)!=3=3ShUAH|nADSUKEJOdLuo_VtN)4m|@d5EgSxd4$fBF0+GoBHjq)t*( zumBc7{0J!1QWU)7H>BIr6l013cWD=h3&ii3)=b}IpX5Yl0@Io4!c2%yjPEYkTacHZ zpYMx$qCe3;(dj~l0QJP;Y@B_@J>m9=2gQm;d1DSak6b~mprEhFKyCmBy{lfu-o(fO9|8 zJJkDQ+D~bq+!uRN>~XO_GS6go33dubT_W&QqaL(Q)b+6?a4(WkHO_$Kf>r zM*kGgil0xOOAY}!pg+~08tNGAfV(^2lJ&?Z#1mqmZIErhd#}5)x3U*^;Ewue0~F$N zsM9*bm~Md7XL;bi?^hyPWJBh!nd=L0DBQYmo5F+A`ll`OF7^(g22m%B69(K@n;?ys zpl6s66JnpUK4o>z?v%Yfu`7|QW~+UPJ_O7qr?o${dCGicyRp^aF#)sSR=k>4P5YaB z#+{|l(ZOUOIV}D|+)S8>=iGCywo*&^3HcE@O`aiNTK=)*fOu|wX8p_Ym!q7gf@iI7 zoiCCSPMPbS?IkFRViZP!=eo7rR_>4VM=nzrDCnOD`AI+uNuL3i`GSAJe|G%rfExCV zt&OdR0gi>c=c52GhrO<8W7=VNCiTA{E;B39kev{oOr(q7fTWX9nLB8Nw_ip`E)$+?uXDQ9!ep!`AkLt{f@bexHo1_8Z*KQf;fm*^5JNadvU;;-Ul zd4g;+9cFo|9Q8lPa0m4Km`}~4hU+7A=q;imDgtx!BKuZ3pyeT_dg$hj2qV=m`dA*am3>HRvI9TfQatR(dHtwC}ZP<`lCX z+5yEe46vkISU$j4sg{ss8hBn%LkP~9Kuw!b+DHv*7L`CtpsmQ3WHymSd_{B6ljte* z58@A^p|z3qyzQ(_24`49HPowm)sgaW8R|^!!gu2XtOKm~T=!iIQx>MIOIw@vZ}AVs zTbFKEx^1CWh4P&FPN)gEP1qttq;v`1MZjLb>iF7tt*qKv@@MJu{lwkGO;As(5mkw% zNOJ`GPN`Bq1cLljK3(ZEqmwHI!=yCMD|mKd8qK7VauZGwH2%Q(k4M-@*M&(^@^!05=h z$o$Bh$b;ac;7spK?`!K@YgxQ34n2t=*Pg6Q{LjODWNc)tLP3RsrSwwz2lWSaA-Vu< zjsWO1Lt`pIM;RTwd{+{rRFvE1`F>KUemAW zqv}!hA@&%Xi_gVz6hoo5W(T9AF`Jl0)N|H%e&ea*Dd#BXXpXnU3mF+kIkY0`wYV*7 z0XMDUuj=OlY~Y{ZtKj{}{m9hxsp&NMcem5!oJvk1HzJ#m6eGoms!_Fo&*S0TeO5tM z!Bl1%b5=X21@R!>9B&4WB!PX!zF_^R0n|Y2Kr8I?uT$5nP*biHTZ*kHRuD@`rKP3Z zVh;M;Z7kSW5Q&DOgSf%m4gHqR;XM9~dO~H9*<=o$iRutHrS+=aTvlM~3+YHL*n zN$e(jlf5tBmm3<54BQ}$8|rlx>MM6JJDL;miFjkGA$8e$#ahi)&9>XJ%Ys@kO9~aB zqIf?30sDyE#&6?9h7xYiMa;$#dtrRj2Cg zhYmy=3H5}->`@l>LZDCkG5b+_2@n)c;^U3+#&mPK*`4Z6{pLC7*%RCw^rrYy_B-}E zEP&tEAZil*to^LF+&A28fDhb_+>X%cY&!hRdPol~@+|V)q3%+Pk%h=oW0?VayFJWa z|9NK4iO-3U*jxS{Y?!K|U{@6+zn2%3|fPL&#y|XXz)Y z5?hIdd^w*fU=9JESB0)ZuZ^vXC1T0gRQ^Z)o_a?uZ&WZ`rrSJj90yOYq46uW0Tb<# z-Rh_Og}g<)eJy<~6yP5RvD!Vt1{Z_LqK6?;v-SD{vLL?pzOUjxtvnhm1o=kOw*& zosIW^%Zvw{^gj(_EsTniEG>*Lh#$x~m~%Pra^4m83j5l4ZNQo9TjEXeUi@BM ziptT8+(m9GG8w5%R3TuG<(2T}Kb}918^gig+*s=vE1W%mJ=C5lJyY(b+=X^Kfop;5 z0R<%Zx3+h-9P}%SYnb*){v^*+<|%1vnz~2XsibS^8obZ#M0O;{QRApQ@cu0@78rxn zAu9C$8Lv;!hiSt!=y410uGebov;rkx`OJUf8_`YZW*{bU6SzUrFlnqdN)t3r8wTf4=GA=KE#@XuK3+cFG}$~^Q>Y<4(Vl3B!FO^=zoJ9` zp&#`r`d5%qirR|WGCi3ds3|zrGR0EXENw2-7HL5=fL5@9@Kp4)O=*{chRooF(4|oK zaQE=^;Pha?9dMtfPExJ$cDNn2qISb>MCF7`@gxuR(M$7X`O~1jo;E!T$dL-@hMP$8iw^b|5cmIA?m8rBBngdpIbaJHzI-dq12JBqc&zr&%o zOE;sdF&Z0#*&KEU)arTQeBeAo{y`$BiKJl}*k#KlOTIJDS=3$JUBy+!HP1WOo01wx zEuC2^lSyOKZl~N#Nwa0xXn?#H$qQt7R}B4MU{4v&X6;SvOPpp;vwp*8Tp%xzus0(r zobpNdBtYGb`RII*aR#Fem4-@y@iX1P32q9o+6~J!%K~B{Vb`2mZ?+fPJkdNsFeJl> zwAfkgq(X1r?%ekr!IJDn`7asnx%77TcJFcTbAN}nLW}Yxc%9R@W!h4W#TYCI@XBL= zua6jqjau3_+P7#OvDYaC3ne+>3f2CPdEGaw5UF05lpWKFP1z2ehZojZkxX4}N?#1rJHs@{2n+aWEd{wUUoX&UghpoDXWL%}{t47ctCLnLwPY&p!98!uHzeH4 zxjsae!M-#(uZ7Q%CbbAwQe=(OdGrLwh>b%lMo zJz`I_D^}GS2cMnyv;M!+U#3?tTCHf|!bJ*O!uIeF?!oS6mX;QHAKAm`X`GeM$QjAB zWc}>=+3!BR`*c0;MqUn|&6n3J=xen#8X;5iw{ji%pmD%xi*>+Cn8nSY6qL?#e{fgD zYhpUU1SOE-$XIo(I*=R0!G6$<zs+0e zy#)K(SJ=xe$|2lJZUxs3oEZ;@HS{Vv7!Sp}$9lxB#4g1aN0&r@j?Rc)PFzj=!JXu4 zsI}E8$Rq^r{K7uh3U&n>jYpv!V03F@TVfHnfLjMX`)GNTya_}nt&;|Q=kPoBTJ~EiV&$KU~a-<r=f+-LMscc zDg+ly+IZV|c?)k@ge}5chy#JMKed#a3c_H_r@T*jud@Hi-kiHN_Y?DxDX&&gH^}Q{ z3E-GSk_VUgfAT*e#x4L%*8foqzgg{3rUq&QOihyRD4OV6dDPT4kkCw)}-T@XNp z3gfBxE%Nq%yFNOh6X})=OL==4drNmq_ZZ)3AL>TkP-~$YTa~>Ky%epPtd*=S*OWVB z-LN_MZ2V_)hS|YrXB@^4it0eOHKmk8)BGg$TVcLW3!_} zuv2hzWJ4q;oE!d}@+Adou`$l1vxudLB?So}m6b{g)c32LtehNMFs|V7*Qa0GeQom< z?oj@!{Hin|8WDezf08cDg>5#sm=QFB?!)$AOOa&=oL?Lxjuxv*)uldaA9aPcLh~tp zr7%~Rqoavv*Zl7JZ{ly_@cpf1Rx}6V1Mvm;LVPqiiUePqt6`);q;_WQ%(lVyL6wk* zk5IoTniXB2Sf7A9ObING1#mxp(D)6Ywg$!({3;%B1zZyX;{z>%t%4cuOm|@_lj@9h z#@vL9SYVxJUFlil5yE_UQ0Cywl7-3?`jY-B-J9x9o#dbBf9-tdJYd^zYiMm~h5k@i zmCH(>M6X0vPIk`9oE14xcchk9Q@e^?!=NU}ar3x28X1AK#oA$0v1u5b_Z}~d7y2jr zC({#|i9yLhNjHequ~jiR)B7_1G7f9b7Im9C!5C{aQ0uG5_*48%{u)0`pQgXDy|I-` zDVvh*`{LV&@5c?mH=$PeZe|xV+!$$`rT(DC306$9qJvQG9l$%;B6o~kQIQQ=RdoryRX`= z+ICaBsU)7jOCTi?IDeTA@?vhRAhwQK!@SqtYvZW#R8?DLTaZj4ujp6x<IUAJq1eAmI0QlfFUMV5&2x=s)NpOeS-O zzr*j)c4_wketw2O#Wx@uk!|W0^^R~yr~~-SCT=sgL|iJiR9mXO^X@9jTxuouW?v*BeP-1=s`fA$i+*+c`EkHaH{W=M31}-Il&JT~9Gn zRy&tFIq)tYrVdl5EvGCVi`Oz0pMp;SIPwDj7ypKSOLv5`YyfvXbUt#zy`FEedKlCy z@JoJa1b7BJupQV}4PQ-PaS%Nm-#gk9?TIQ#WuzX`0BJ?FqLzD>d0@}}P{yH*)|ss{cSg2H ztSPpXM$U%LedK;}Dl!Ebp^wnv4pm#e4gXjCuXw4vQhD=p7v`RipO51bCUFX@+z@UG zqnJ^QkMnV&EX!??Hb@MOqgV9HdOvBPR9mbm{v=Kpq1Q+Ux;;HFIY0TBea!x$oL1`L z^>NgO+IHBs+wv_1mRcZgS#McsC+&n99OpdeJSd5g{|NsGSL0XXus-&cd&`6H!T1l< z|ES*qXFH-EQ_JY3_4C9z;+E@cq5^KaM8GA{HKeLpTz&ho?-cxJj+D?WPgdYVriM7LZSPXdlvYPG>SHk zzKgz%hQ)};pfp;9C_?lz`5+vm9Fx^ui=y`O!beMkI9{cTd(q`=+yQ?8S)9=6`Lhs1s2mU+vp z25{Frb|G5>)TU~Q8VR^tQUR}kSGHHOyX_u3^bz^0f7Poi)s!qbONQrrkGM;OezAiR zgAzIUdHHItk{i#D=g)}Eie<;M;?I&Vl4IFXY$d)T--K_*kK#sg0x$4$wYgdkya%2n zlO)uz^P?%~0IjbEcdBSWtV`A*)3J1H z1-=SDLjF!xAj%V^0Pkc3Mu0w49@fiVHLsb69KShqm+o3m{YpXq(pmf*9_H-MW=FF( z(if?&R9Bv`PuQk_Baa0*xJ9BxVsv~&e06LM$lkxldeGhJK4M=H&cAGsH_BUuEy5@M z3tv~Qr#futJ)UHZ1jr)M|k$ zflJ;?Ufe-AR$wc!Yw8VkqBP+@Pw!PAx1LR$OH?kXTyO(Kl#bJJz@e9^i`8YqFG7E& z9|Q9f^d;S>Z_wvxbF?keW@(NvR~Rdel{U$n<(a|^VKzO7u9B>h{6$zUe8Apgjoppi zs$cc@^7iu1w9m0uu~e}o?Y)U9((-pY)dvl?v5N zuamy4=r2Xj7CT+6O?sR31ON;R0Ox%vycA$hv5(M4_=kJNg#ZUA^0n|+^E2}0Nx_qX zgdW$gTW?seQCF#|W>pj3lRVe{)l?xIhI)Bx@HIHh)lcF?Sf9?r|?(f*Ww+Sj!YxHk?tg&&9e@i_Y2AeYuD%taMzX^>;Vs^c-an`_6!b28A-$0L$^GRH z0M{%LmI!BJf5b}UmdrgL{VVFy>{=gtKYJm7WAEel@%A8pv;!RYCI6C-7$M^(dJ_#B zsm4xmhxm$l$#hTlO46}-EWeAo4t^K^mi(4vOxlFnu(g$Mlyoy< zLNDyq#44f~Rs@6E%O8|~73c%`7=45uvHotI=AG{SJ@k8MS7b+Iaq8mK1-?Z-I9qcS zxrR*Dr|4DmO8Q0pl0H+ODUV=AGDqS^nhiZ6G(1?}>NBIAfgASZXN!&K-rTE*#{Xe!vbJiH*b&(kN+-yh^UE)zRR-*#UGP zS`sUTnIPvvA3VP;#rA{i2bXHs>>G*o#1r$GIm8%jBmiNrZm;&=OnnZXgBMbZs51c0 z*`jUH&RWk}uLQ0JazZ&FXixYOeSvn=I&0O=d40917(jcut+R4bt z$m#H@a7lkDKg9H~$2eV?uFT+Oa*N`N;@fk!<+S+J@>BVbtC|P@-YxMK_!4p{ zIUM^RV46#?P5_rc>;!wkkJKmXc4iyXF4-;#^#@=t8hTHx12F*v{1Ot@q&3x*>RRGl z;;dk;Xnl>n#(u*NVY=P0mk1UM?uhJ+JV|++GJ%{xo)S-sSJ`XqMq#5+QK_g*m8ZyX zeiGvMWx`TH#6+xwtEB56&r8p3+g)1;qnJ^gFV3H2PBZJpwc;*wr+MCT-qOz7&f6xn zRVws$KOH_9?&9j^@*93*A~TWsUvfn99rKzgLzkvQ1;GNSQL*;R`Y(@T4`VCL)uzkk zaM5nYy^dN(y;fhT^@Vx@tYg=d>q;}Nv9?@ZAqV*oUze%JG^HESL+GLOb-*FkgV>)u zn7os`o9xbZW&afZ5_CzEp!e+%eXtI-BC6SI*k5@6_ErN?#ZuX_T3w?y)T*sE_z({G5JT$5m3r5fV9WKWc|Qo$GxYeV^=~?7tJg6CLpOIGkCux$G{&hx-nu z>`$2zni|>^*%*nYMbkEiw}tC_>UzFVU#KcrHLNmT5ibNao5%qmZ$8y6JjpLiE>3>t zvw7&-`it!s8`P+1i?lG2SxHatu9+!dd0sMqguyI#6|U zUe1gf(Ovm_^5ITmO}(ZL_2-&9TR5SX6}+1qC=HNCXd|`ScpZEwHI({Dd?GT@S;bn{D?U_Z$@*6&=}B4#k<8v%Ejsa%z>$S_YG z`o=$ZJ#+PR_jEV6wXm%qSCHq4^TaTEC=GKqNBKtieoU;LXissZOi!Ag)HJSXTy3y7 zE@YN4lgSC>F~F^p&=eG&u@2-0a98uL=1s_%kdqcj52Pw-iUW7xi}6KxKefNwINB(h z3+lFZTbqT?!C|J~N#q0qJ$B{;Y`!J5In*c6JFu_tK;ePV!4TY^6;)P$wYpefis7B{ zpYa3eA+!tluP_~^ea={C4KRl#y8d%uov2Ef@fdE%CImLN8i)$>5uLY?q%^y<7Xt!PF$6^ zA`$wLl>qqe9{qr(Ey9BM@GF?J$Ayyu^uDPPtR8&v_089tUv7NS^5neQ;Ad4LDiN2- z%j9NjixmXpGFeKIhUvrf02)9AlQ;KE2c&b+vr(AOwk5nZ{DJ$AgMDsL2ieGIVjzfR zwL{yX<*|wY(I;VF(JZtB7=!RWxDDHyh5Fk$>^ydYIo>=io)RDOkNFwkoi4+cV3X;o z^nb)#0%m;yx{Y4Jui@Y5EP9=7y{#$RjD@`wzo1=E$OYg$+e7Xp|FloD3o$~>*`)JH zhtrOv-A=xlJj6H12Q@@6BM;u0_QreQKERuoDNB_T;S=Fz`OWel=RVG@5~&i|Xlyb9 zcp;vS6h)?LQ?xmtmZD2h=nZiW@U~nm2TM{?l+)3FqK~*oTw|`ucU?_fI4-<4xH{Mt z;Fc@mRdK#PPmdU3V~4gwo2$%GaGlhle)*i|oClsu4R#K6PC=$3(BoN?B&m#5&e}?C zqW+>*QLvY$Knh5rEXvD~WymtyGF!4Y$-B_A*dy5_8_a>~NA@Q#(f`s*oJ*a9V+Y3` zNj#G1PVuIUOB$0jJa$BEaYqS94*nJAOuF5QkWzrDdLOzj@ggfzhYl7m}3jieb~xN7=J&$eqy~uSE4uZKmS|*(b%K0F#D^ly^MW0F`R&TXp~IJ1EhWuCX!;e=&w=e zdj)fkP1R8UMgB#in22FuPQu=e3&=$zN^+!5>vU1F80kP9$XGcRy*sPJ ztHb{Sj6OLyIcP;OK2c3jf3T`r0^ncw(c37z`>#P&r=am^Etsk1edyf}=HUo+q}oty zAhrc#t~=44SjH@4;Q9_T=w8Ur)p2eB~r4|vB1)ctBjfYXL(gS2*L zdlTw#VW0hM-)!G+{@?ul68k5n#izxKF5Z<$C(*qD$3J77H~unLnbq{_`bR#K?;q$F zNGnJ!ut%Jccq7(WPOKm*W0kS)T30P72E_y^L4vtyEy`LgJj1-dse~LRxI?wt}`_hxrlX|B1NxcMWP}0Dpe|#r=j~&k(jp;^o2#?^Oh)m)SawPc+ z@(a>O>LuLi zU8e9^I3u1GC5e~(pdhAr5q%zohZFVHy6QS}jXBAhYQfCCib^>J>R{hnAFXxh8uXHR z**u`^Q|1ec1*px3{VV?w?}!=LOzf{bUC}6g_*OEcibSZ6UktY zZHP6-BwC>BxazuQd1ra6cq@D7dggnkdZ&4RjQKIo9r@Jz^d(q36O5 zuy0lXbyvJ2c9*-!ua$R7Yps>G%v^5v#JXb;D|G<%8T*V~N3WtXreKgaPq$CEuVdCS zldZ{CH@+JWH3w&+r=npqV(tX^2kzm$0Nz8uhS*c+DZJ2M=qt%(WEZv@yM$OotXBV0 z4bI~B@q76-;F+FtoOd`ATnTrR?i#+ z>NFfiikWIw1bhMNspiJci{%o+37Me!fr^WZjjQjh@B9L=qTft3X@yn{$&g_G_)1~5 z5Q+pMwzM1F<%VaF zoo$_MTga{C3F0^b^|%`y8yvhh>MifD=r5X7G--SCw&b2ky^}@*47$+1$ljE0Ok)&E z^(6a{z0qFiSYfP?1HJ}i{gzcMkP&ENG&eGtkIVpi0KLxGVAK?Ah(W-mdV_bK>&|yW zEl4+{D{>o*M=Q)4wqJh31iJRSKb z(nIg1Lp}a7Vi|E&xvJC&)ebceHVgI<`-mxM8fsw{_Oseab%flZ0fqewt3|6ui(193 zwagkO$(Cq~Ct?ZOWX<37fjaCTsE*aZu25Gf=rz6=;FM_zQxlG+98VdRI3#hEccnLv z&ZjRTmyoa-Heu!))cJi2=Z3``KBq=*jokU%e6BCr7cFToZ9f6H1!+;%L-~nZOfRM{ zz~*8ZWCr;M_6PO=jP>opcEJ=akprA(yRuUm2kzp4iK-K(=du(`H8 z8|=$&L^Y%+8)5s`3o7n%oYUj*Y(=-CCxjEiEN(itN!h0SN^~I>Gm9AL^XXH3N+YqM z*jeqOiiAk4a4mNg0DQd<+xK0g3VR*at7}ymQ?ZTgM)r{7paXZK?s~okzVeCX6SZV5 zc?$Uam1D}s%w%VDQKXVl(Ks!glv24=E)WieeNv2c4(x$YBL>ey zm!V70Ec2Tgi^icJ=}daKYpAQ8qrC(EIrOk-6KNZP{)wvr$ElAtK=Z6T3+md(NMod> z>T-27c*Z`v&;GOP7grx!AKNcPXCfQP0kiKGV#Dot9+^${XMbbsyBoNFjqehVB%{gY zlgcH{^Ud>hVmq;^Xgc~>f2a@9hG{Sdp}Epr+0F0bGq?=yA^(UUp!L_TqSw$)_)j?W zdz&atl12c$_?NswE@_lB7?b|a>81)(gx{khqjLdId|^ z$f!uX;1>jiQ{Y)jJGrf_h>GY`T*^KDo?g?cVL?xx7s5*cW~Dz3KMtn~sX{%ip;n;h z>7M}xxF_G256eg7b^02eBxy2Y58K1eh!gf$XR%+{@^m?RC_9XW{;aLyTE%Tk*pYAm z)VbI*vAsOKJ#bvycRX~AwT-s@%zz?0k>}70=zHUX(O>Q-KL%VT3ij58=6tgw_`LIo zIYcY06*dwXi9pRvH>w*2wYBh!u&P{Do+3^bVU~G@m zjBhoz7!Qm`Msu^7samSl0IiS04DlDv7fzdsTX8}Z2X#0A&r zW@*jS24wt}F)wX)T3$ka!cEU@PZ1`afq4&JJx0$Fas}7`^g8!V?x$~`zAY|TQgBW? zqd~oBOGhim5@IoNR6DM9QMxF6$|Mi#~F$H)YeqFdBH0PRg zowT2|mH0{=>fw%CN39LwdJ%HEo8oN|YH<%SN0>fLFJ?E`7k#Q%oeg-|3FJ8P(f-L^ zEVf82nLs6oNkY==wAX2ii!3d2H~mifm-x@|Lu^BB*TMLQ*@t}rwzwf(m+pq|hWqC9 z$(jCT#+OUkm$G3dJ@l>aiS|H8nPbh?YD<8W6IGbQ4bRP>#x_DlsVaD7{4N-uPr*L& z7T`kYui8D@Gg@1!B`q`-8a9F^4%3I}9z+kqVL7cC*q<2e&9f!g5}e770>(EJ)u+Myg}9naiKYxl9FUmcN$?0XPhTOf5WkQ=lNgQB5h6^y z)81(xA|E2Jf-izu{5L)Z@gnV*_Dm5fgBoRwHs*`-#CAdlp*+CGC1E}tat(><5xpr` z>jhrqf8siFXIwBPd5K)5uh7Q`;{=!J5#c;2ixqMPum;8xtq6Z9zx{r*=_E2!VC->qr-G`*r#(Gndc-D)gv&Og#vAc^j#XbQYkbv-lZ&J;2s(pUVd|`eK5ZFv&l`pB|GD z)6&-3_86t)fy<*)DCDR)Wz?@+1%aXZb>*a8|*r0wjP0AXYskpO&Gw(0pxy zwifW*Wy&(;o_1dwfDOQ49@AWGHioFE3MC)MxZ_+gwV0YsS3_jdgVl;t+ubudI9Qyi=RmLd{SbJgb^(p=g{{(r6jABQzC+L6Z09brq zYp*oj(2VE!b3C2Spts}O@KFGR!hN&`Uk#wNhdk7--U2mE_*0m|PvJ|5CBzzP4Rx3K zx7iMDi*B?wTCk^hDX7Y571TjE2pVIs|FpN?eS+5VYx$O13vDzu3R{D(#pjxH%>&8- zrIJ!b>1Fk{=Ftmic!%e-JM0*RP-%d3R6r}C&}*o^qrT&c=d!0*OwpLj-mBgUF%@Dy zgKFz->pg5gWDntC9C}F))COuD)eh=S@rLMKc|wl5?LiNeRxXVDARIjbezlHNn^ zA-4ezmkIFR15mxp?&fH896H~cXLSMi{*HK8tS{CTw~E_EsP(D>Fgd&f{;Fr`1WKTg z*G>gh9F!AtgROzUY?Om4V$ZNIwk@$G*95BHNT2qq%2W3VVki1%syr%y^;^ol;n7Owgj*bLoXNQ5-MAp6Zr?=7BZ^Z435>_Jsm+P|m`> zV)y7f^iRZ3M63~OOjIT+zv!Ly%h(m{8U2(V%Zz0VT*uex>-7Sm5b*0rq*|y-sARBI zFg2VUt{klrts+zvAQvdDmDcW=_e?wLK#$|c@D5A|roFwLJ(tO42BAaH_wqaW7I&M2 zeL~N*7g`&%HQEYkgFvqln1}L2d#Z_ugy4)tpS7R0{{r}NYoZlV)vRi^G1?kg$QJ}* z5N5P@w0CyGtc3E3`kcTuk0V;8SXhlpP@S=U64)cCe){#O~X9r|UkV7||% z=2HP%(Du>&(LFA1Y+S>{hKaBbrbTk|IQj>gt;{J!5;Im z;6uTqtVdZ}bGPTtm*z=x$hl+@wkSIlos2eZGHsA<@LW4sML-j)6q-?1s z{v-Z{`a-oZTbZyQHz5!ofPSMeGwuhXDlyxfX+Ghea=Qw46~MFfD}Z}-r@B&yY)5Qx z?-~R4j#2s;9p?EgMiwLG$g*S;wki9@`PR8AZdKgN>+z-r8VnHa_#2{Mh{Q`3C?7!I`Vh=Is|5QpXqb@_1An?xh z6aE=rVk|MniDN|ttm93TW=d7Hn%W#-FsMoY$baDX$b02#NHt^zJ&QhMJ7{yU4z>Z+ zkgCnpVam8mxuHkXx0sxmm(+90rZ|)=?h6O|SXUvdkW9d#=Mf8t+1hLkt~38gr=+RK z6y&=7rhS`ho2xoigX(MaHaW`nK*m^ckj#aCmi zF_^)+(pq8BBty1xv~&z{4R#HphETYQsLvwLBNe!c96UR#ic~@1IZPwHu|7@uQ@SXh zm%Cd%Ea(xM;!1YaaMW;=q)Jlf(6i`jWG!OH?AT`_lfW31Ip?_OfV~$N6E7w%N?x2i zH-28c;t(C}09F+Y-Z-b7*E)e}s5VmDi0#DkTv-l!i)PDNvIsEkZ}?!m7?Oe1P^v5Y z0f$MGQl(4UWewh+!+h7V;2k@84{zgGu6pE$NDi0B{mWhCpeJdEP{+`=@Ye9q=&&f{ z(q7G@byPYkO{69gCKGaRt+%$qTxuRSP8dGfCvW67a*e_bzvsQc`#c|5FW-QDakMf< zX(~67=c;qnr|5IEldYrew)2j2ymOqhiv0)s2l^vjlqtf@cFu9G_igm;^8e32Dsgn; zJn&i1de3?hx8+*wT|$yW1v8wXUSXa(Uxk?dF{oHQRu7^<^el0K7=ZW3 zcO$!ymFOyTFgX~Y+YTi3oZ^w72lI@H}%qb&eo^C!yx-x%^CiqCL}MFb|e)FKS;Dw=xyl>rdd*p5vwh1$+ zKdFO`Lyjx-WxA4C(fmpINy*dm^nLgNoFP~O>h;Qr z@df-{;hvDLr|F-;oZm_QO}53_U_morHpQA?FhgZ~{LXlIPP2jCz=oBOvVdE_U6Za! z{m}tvWwIhU1RDl0nW-%0mT=IA9-guFrTS6(*uCt2;vlg|pRf0ldwloRdriNk-7&5h z=*##v@lE2C)IU?-W&D>RX7Jy$aNvCx^sRzE_StH#3VU;6`B?sD{*C;}S(CEPW}VL( z9vB*kDp6$$It5iN&044})T#gkRNN?GTqZ6P4zLd0rytPoh&MzltCiJAX{1z?%1aS} z6aI;wijEXU3N^J_+8Oi|TAr>zFQJxE&ynXybx>=VHB4G;O6>oV_awKBZy8^N%pfoG zm-%af>wz-i(qWjP3%!rRdRV_L-V_h>NBNIRrUJb+8n_y|>bh&Y;W-}6h{(~u>AWuK z33xm{%s#?S`UqcvKi^+D;fI74zUIEx&X&%2TY_x_J)DL*%PZCutCs$w{#pDYUW#0a zut7H1E7&vmv+%QU4y;qqU!n{03sMctW0>WN3xx2Ov_|?YeiZvh2Sfv*!qDd6wjk6H zWP{ol+#4((s1T?Xs2!LVni_)H>@)eD%rbWE*UoPR<}N5a)@B)C6h(C?{e= z>IiiOJcNg;MXE)1YP+=VR5vQhL>L9p5O{Zy!l&{V!JH~%lr~PGr%~t|1@BF31Dx3| z+9pbJ6gM_HHhPRd#&;At3N@ta(naZlv_aS`+yvtu=ECgO|EI(Jmy_&Cb}_qzHE|Ok zqz}>G3a^CY{7IfsNTrF{*c^ZkM(3h)P?#$>6di_c0h}40(T`=uFfey%Dn11t3h){{ z*RGA##9$9Myyu_one8c(SR`>+`Uo(SBk42!v;0kM&1_SwN!ESikpX=sR|DLxnX*}m zFT?N8+m|;ze@6adVUbV=uZvHlC(_W<|2JWf0DFXgl75j4Fvd6F8}S}szkq#<@UHEP z^hJU_mb5}CP`3+3(YBB+bSruzx=3B1W}7)?H><1FNAIUY?ywQvh{mygwxX@9Z3Dgm zhkc{4FLtCbTKEqjnSo?~vMZ=V)fSqbP z!}*Z|*a<+jiJs2E$IkpJ!S#tX^hM^9*r@7~>w}b^&4y8$##V=GoSu z>(B^TKW7lr37^;JMUv2@S7~q3^fWcimE=rHjmwA|nY`dnQdp0vk1H|e#O7# zm53Or6{-`0X8p6mv%|DZ$qK5V6Yz2PP<@2HLR=>1$$9cXbD((}yNSi3v1qEAqOOgu zkG|#Jav>osj8J}8;CzR9EUN+c`&-;8{;GG=j}k|T$IKIEG%-Q=hNL!+yPe`Fr!@^Zoe+1%ZOtU|g_ixJh_FcYuTE;ak* zP!n1dDS@2PPwTK}6l%;?a4WcB!6Cs;;h)3s-eWcX7e1buz(D;yZenJtnyT)Wcgc07 z`V!4kJk(CD%wL&*yx>@Y5|9H_hz*U142zWFOY-opZJn}KVGtH65B64(7HHUSewaQ; zKVcp-`&|cIw|qBz|G58g!?k)ybYS#S;nl(`;Y;CJ%4`K{!KWBgjK)e+FjKB6{m_0W zV`FW-9K9THUcx(qcg8ydY94nIe-roEyKGBW3)if;*>P+NlhQb?aoXeLN6Bkq*T#0U zb+$bwO!w;?^1Rv^P+R3-ST?o{q<$lmyGO;Y>iX6_sECuzT^2up)ph#BJ30P z3Pr$P{2BX*1+0*@i~pP74c==(es2E5=;J8Vbw1J_YYzbKC>bghf*w$3)idfGYBqJx ze%Ef;44a*?GtHQ$OiyPo=U(?d_kMsSN}46jCeg;xhJaN~7p4h*Gv0iLzCxi-Q4*0% zoT5%ru-6vm9IkY(a*{MkuSVCP@E+)q^~i!5wCfz}95cK#yf@=-#$QgpoZKg)Z^qst zdy6znX`b>w&rVNKtQZFO)hXd=;YM5oZWFhK+Zosy5VM8sr(d6a{UP{6a17vK0U|(D z!+yYeX+5=5(pl-9{zk7yHY9V|?C<)|3S@b50yY7=j9fwLg6d`VGIvS4q+mE07DGbF zHiu0bF7 z`@}sW11W-R0rNqXG^rxMJ}1oMCiKwwLVhAI;g|6~W*-yg8>Preat*77Rozy@wm)uv z+?(Xr$$5!|iLbn`ybYMT42wF^%g7~UKe3;5`H+;M}P8=o;lUj%^ z#4O>fP)qtz8m*1ePU5FZ*;n)nx)ITYxT0QCD}}3sQ-VoB z=n-C4E2qKWVHM2r_sD+;ytBwgbJ0pfMdAynvUnMsL}{>6ZAA0%d>nGu>j103GyGfj zTlUeOQJw~|4PuYR9E*V-)Hp_B#f_rIMr|`-p0l*ZS`%%lyhyGdtr@)z^U>`vDX*HGJV+dKWOUXClrVG$xy zORgy|LYJV2sY4X(ABXn%ALXC#d+T%j8IHMd zSEa;Ci4`&`WSq!2opC(nXvz=qRpRS;8+f7idloyB{eotp)8(0RX5f9`^tV&rI%IXs zs+3zPcPY1=gC4@|u=dzku#RrmwrOL{aVE?y>}vnT{sUQ+EU%PR<_6~nYZTTfjEVRn zTf{A538AELEp#Q6S5Qz;GE_2DSFR_+d^LDRHyxjWH^LfW2!&8TxT?5{#1@Mk=^E*J zkGw<1@MHL!;hW)A{A&Jhz{O9PCrnbO^iRr11>Vs&W12HDZm)a1cdXaua=2QM&B))a zk=8<7~3P}5mOdaLq~l_T3pe%_o?qw zx2J4Nf!rSU4|;ev|5^GdtwdL&gp80-g8}b~#u4L*FYYhySbx0#W9<9bUiRMh z2gp6-qWZ52-|tsE3x__-YkX^cY$B8BON&dpmUbmAJK{c{WqOU<&I0or0K?V1KwNy0p=#u zW7k(3sFr0~u($9Y{s3=dv@$wNU8Et>PzjFJAQr?nGh3NrY%w;I$RvKoJLBM2Vp=(x zJ1{5Vg!>iDrj3z(a!?5>RR9`;cOYHSU(w589bT@j(CV8F%?Ic`bSgQ8gnQa*9n}-!((3=#V ztz`1=`7Pm1;aY`t3;)dfGw(wF`TRgA7|I6g4)nCxukF{8wN&j4*kg|9NA>n*JF}C~ z(STZsx<(xXdOe?3zOr&9B1)9CZ?tMDX#0^d$;r_QqGTG!EQ=v-tDl47Qq5G$|6 zSK|%rjqLHBc+X?-UTWag@uldviJ2O6+YI#e)F8liPx6a>SPG&9cN3My`T$mi4 z7;O!BRid0A`>{l9u49hlU-uRFb@Cd?$gJETR1b`_uOX0x#^pBc}MEz&kA6bVI2 zaV5AVfS)8#Nz`xde(nmMa-Kif(Jb^iJq2)D0^&zP_K5wE|DgYM+RL;}8JjZJq^?W7 z;J@hqGiF-MJI7l`Ik1P`G;SJB*(DE&4vs>dsjYx5NXSpf?+krDkokxmV4JDzR2KHK z!`ykOvy~-9>Y?;f?2=tt%dO_l0lWosc9w*fh98HYgdx6t#y#UIfbVS%)^6Sqj2>nW z6XyF4w}x4F=sWbdm~k;%leQ%V{e}KwjuMWU)-1ryYv?e~YCJQJAsmFGCR3AvzP9}U zk6C4|G7%CZ*VxwBUW6?~eDt85iTK7+)zqFDWkxHU>1xXq53f z}Bmk08WNEsz;)SqR1fmuaW9 z(MqT#)D!v%y(Cf!$pZDjxNAU-IrM883HGe7`d8fv_OgmfWhDjhitiR_W2HOZ9p4tSBL+`FQust6 z5p`qkZPYdj-Z8Flu5dE3Z0y9?39&8g&Fp^~e;VVs30!vgTi7W(k>|^QC^fm3e_IvP; zVEvrBImHW#7r;!&Q`+h8Yh<>REA12ah;Nm5N)fCG1_MCh`4!BgorlfEhJa^V5mcd7 zV3nsU(Stk#Jg4GM$2ash@{f%h6Zh5o)%&~scRTdq^N}$mJgX_871y3|&p80m^5;GT;yK(Zg^jKZ@62ed*l!P4?bB-(xC4G%(RTbVz58aKhcx;N&E_Rm1<45q{pFS z(UgdjqVC!r*rq$DJDYo(d*{c^k8>xw6SESs60$wtJhzD3#2fXsT0$r-3=H=V*UYb( zKQC*3*58>sGvR^F&fv}<%u2Tr4DmmF7k(JvI;cZ|eK$?1rc^_$0X9pWsqO)M8urJi zf+~2_81<9%MOq(S6Kx-9ABp9B+*$do40EXf<3Jq0lh`EoXHad~_UsP(cKbl@KySW3 z&tD?0L>%nNIcyv;iYY}E*#D=J8rjp<%eI1D!Tw4ANgpGRlCuHdYH#mocY&`{_EUD) zmj~}+VJ;l(5op1*WG1-ByQ{`mi~lWoKyt~{QmH>C*Gj$^cOkBotF@~-z+vUl^5_Zm zgjxga8N0Iom!0-L`Mv*L(z{t-W`3z1sudzsT!kLiP+#uVyjlj9f&I%|Vm4D7DVPg5 zkDJS_4XqDpf+j$3O&Wk}J%MJJ_9PWjpKlY_Qs>x=QlC;;3H@>(bDpkYo~JF$&;N;#t}qn1;pyd}L- zj2JV{Io_E~WD}`K8d43bhCv|$q>jy<&7BouD#p}GsGV>u?P%KAjBy#ol8YycUeO!R z#<8cdQ&?xKizy@5AFW?kZYo37A*$1G8gQPRXD%=sTpL_}`~LPp&GGw$4+&@E z&csc0PjbUv!{gL(DvSI=LSNtA$Q~pF@HE^*k426}l9Xg+Ffs`F4}Xs*VaXW0!~AAu zn>( z1qXFOKda|~J@zVdnSpsCGmII=0r`;JPHCg;vi4XznH@}1PZQ7h*h#T({crs_N!dxe zl6NOV0F@q-9@CU*$_%mwS&3?*+FR@^b_xF!zL|R~H}Pxy*OK4Le!CL55(p}VN^7(= z+6CbEd^6v?Wd3W`!fIm&$phpO{0M$szplf+qi{4FJuh4kptf<6I6+*_E#*!{PDQpw zw?%(ZIx8rKVkvYoy@vXWT0||O2$oj4#vSWbu@J>u+6to6iuy0|3Z_jWUB&LhZ@k0Y0epSZj9X! z+c>#Na$0(7`oC$H(y|i2ByRWa@YZH)vZJxFSTm!k0do?%6?QGG`l;Hdb?-L5Ta~#o zvuk0O!q!SFWuvv(s%_LZma9wEY34L@7x_2Yl5R~yAKe||c5y>^V>rMCIM}E3KWrCP z39W?IQERJ1gdswCse%N1%^R_e+3wC>PTEG=lISFQnq!*dnE#l6ZpOTfN2w1|hq_0& zVP1PjwUc@sxq+yR%FJSCv(VS4xLiywFO`?zbI*3>I=jYnjd|;O?Yc+Zqgo?vk^caP zc2REXJbR8k={V`g@_hAV#HYv4NSU6JUZhA7h&QgsUX3kgFJa$_@4$ChJFN5CMGa8S z$mXw`zJC7r<>Q*Hzp`3{TZXrqTTB$gup)XNA|Cb2R%0t5GHe`z*ErP6c)2 zz17}o2d)$MNBH;fa$$w=2jKM3^9mZyR|Z%r&hQ%@v3A%uI)`or_PbfcETSY@8hr~^ z%(_TD1fI$B7H9nqet+02ZkKH`tJAt@O5d}lnt|GGZZnguBx?pai`?$m>geG7$+?f( zM=dbs8#=G^pCTV4Edej@WA(M>0nSoSucKF1Dk{IKUDYe*Wiu7vyN*mJW*xDf$k+4r zBqdRK1D^Y8>@Tdmy}Z4Tub;1jzrFuR?BUoPPo4*Nk*@u=y*7aospkMU#hbBaakaR* zL);~PK|G z!VSV3LTf{p!JOY;aG+ps-tN4Pd7bj|3UdpyBRP>Cd=GwHbbPcHSDP!&7w5B;9OWQ# z2x&q#CTrrgai}9J#uwwMC>{Nu__qi#ac#6V3eP=<%Om9aQeA1CwpN4wOp}?Z49ieV zDwd9|G1eH3&Bi9wbKbMxu@8?M5l5x6saA%Okx(qLn7gR6XfP?1^uqhxtFRh-9IQF_ zp+_;`C-6=vC7c|7lJ_j{Q(k7C8PY=>;JvVCcsAe*ZviL1qFvIU@9I^6E9Me&i23Fs zQ}BymrN{qu*m)*H~csKV;o}~ zb@95m&2m_a0nUdWb1QRJT^MFI zmIl?$=wU1qmxwF4<=iJelZX1sx>|khL-c)gU0`kC$58Fi7G;alnr=m3ci(VF!TOm> zr_+t8Ce%Ln9{0+G6$xeH%fxqNIxzR72hxn-jNlXDu>gHbq!=OQp!cxX4<BBir~# zKdv_;niE9<|AA*0HRxJ&N3FdE^(hzR^YX7~S9G>*j%`WI!Wb!Ditm!tC8=|I=k$$$ z`}a)fnNZta%ii1UZL(mFjTJ|UWuq0M&GMV)um1Gcr>XC!zNd4joMXyS1^QvH0yWc` zX$=NAprzPWOfiy-GT`$*L7pP8KXQmLREQ17gzpCL1-S?xsl(UdV+Eh!2HdDW;BLFw zJ#2SZch^$qQfCa~WtL&fv9I_yysoXTEyt1L*iLPw`s=^x&{O9V;9GmGz19Qb0Rh*0 zm`}Ssv_14s_@8jL`c?gp{6LNb{HU6(nr%M7s&37#1(dK7kHjG>>E-knN0wu=d$aqr z=d5S2caV2z?BLiN{#*V=@eShFy4JYrQw^v%(`Pmmn}EG#Z5S`43g70v&4WIGg?fQL zlp0Dcpcey<^c)*wz|`K+2IQb$*{|#XW*{>TnSfjbTeT_b&? ze0D$U@0-*&sbgZt#EmfK`x{h&@=QI`q0SmNXcM{U?E?~4>0;0ZNUC_MZKop;BIh(g9C$CgEzpx2Lxvo z%r0n|+bZ|J>^IrF!P?a_(kh}!y0lPUB&UP@sti|#n<3AX^YL69`Vd2po@RV=J|@ST zvpRcCcKLAma2chn0{h`pg%sgt_*NL^*T$i7Xqr9U-qzE`Q|JgfZs9j@8)8FX-ouYz zd_T0`wBBED!_Y zuSypM`WHaoIa4&n`eH+|i}H&Cy;BEb12Ncdw8z|IP6zyVC_9ve{k=py5#Q0?$zE5f zqu?PT^dFGd)h(0`!_rbhds7=;M2m~ zZ$@V1u39%OPK(uGzdG#eXsxzZdtyDYqPF6;CeEhLyUbnYE%}PCrH*A$G7k*bnSSb}O}oI*pz| z2b%-UpUj_4cs?{#AEH0ipXuB1E%+JtX?KT|PAQj)UM`BJn`v#l?Y;E?7S01)aG|^a zwl1k%#V+FR!rg_9zBc%JFzayEz3{!T8*^b!o5xm_s7id*zGyL`PrM*r6c_7Dbi>rl zDsmMW`X1~9RXkcE+A7*S3UhV~g@90BsxNice$ftEhpd;@3#*!5Ltm+^RAAPM8;qHT zp2i-SH};S3w68tg4$PUEdaj-W{w#+4AG4F0fKR~T9sOi}62DqlEx>+Ik(Jnn&W28y z>0N`V&MYMtk!OhW#3X70H3#78>fWl}nn|^jCKR1e^ltIH#RsPiNn7n*?fr*3NtMRR zVikz;1k9Y30SVE-UJ5hbpX5KvhxxZ%&2Hu=DwAr6H^5lS0 zVl}y%T;Hl^ZNazUAtZ!&l^Eqv=y0f1eyRL@fxUqv(lP0!`O@47Fn1ZXy!uRhDz24R z%U#hPDD-9?4(8)g`%(L6;uCSrxM6Hjx2SiFJ4QFMJK4t7%GJT&!H=ilDgPv%N?hVw z;ydR!>wvvporw0tZBQ#f!M@w4!gFDA;iSS{U|mg$Bt>A40rV*v%nV|dT1zdsA1(#F z!EHLtUU(lo56wdxgE`%tYr&m}9*b5Lstc{asD}RQXdzPgZ|mL`q>*<@)F9rH0La%YZ7%z4ZItiQfP5MtnCj$Cc3`2*b<@NG< z3$3|U7q5fwbp7r6*LTU+#n;*Aa5-JgiKaw`S=1be4n)(~R5r`|#VaQ&i4#*Mqzq0R zlz7~C+_wnq{iWFA>`U?`=|y6YJMwM0dboPH;Q?wRFi|@Vs@GJ}V zNWr{!&WxDQ_vIqkQ(icpJK*;Rm;mzxeT>dF=a{+HHw*S9Yyk6YhYCf%;TuvSx9TQz!xVErg_HWsHvvz0A%bAz6o!iD$ z)+_55%yZ^R?WA^CJ|xo$qf|F)7t0R0#^s=f%omtbqlohV?H~2g$PdcI>(rY8N0ZYGubku*=;XH21HRm4k5BXL~ zYh{78(2@y-fcXzF0}8`XY!W^hhv#2mci7!9p?-oV$(MBBciXp~UB|9NHXx86*}#63 z1~6GV_y_vyKLogXoHSM%WDGW7p9j>-{R{Tm_GCM9gSo-v6&^5-fbu|lpy3FPYykhS zf!@L1E1pZ9GtRS4m&@bA0SW)aX0ovF=^64Ic`LpXpGKZW=0_Gpj)abcJ_J4lZUbzC zfbqCR+w}jAt^z!YqYcmQ?cMIVTP}hJYbo{@iWH}~ySoJ_P^7p!1&S7TihFPh1&X@{ ziRaw?_HK9n8S*}m93+?BotaN&zVCgLdE6&%C^wAj#CBjyW7ZhM(k$koYM5-86r(Y3 z8EX-X1tY;Ko@$;d&Wg_R&PvWfo`If+$PU(x){j05Jr7;;U;PGs$Pg+Ytq{d|7mMcW zdEz|rGqPWw+0QK22frG=9zGL49ml+b=^~5h8g-pI1PhZ zDgKrmkyM~6Q6-=h;M&8_qA#M_$S--)Txs3Xd!#E3a>EqmR3#}RWh11+r3#rs_D1|# ze4e;SU~bJ(p|PPaC>PET<%e!XZ$&4wliA!kPpH|fNQXui<^rFQ3EKE%$}kFz!o%XD z;tkS2q!Uo?uvfH4)Pir$=f-ot_0E6fKk>UHJ0wpH&kTj>Md?d2mSl8E>z?+v{-}Pq zX1L~r;)DYC%Z_G8v(Nm`{1@Ek-Ot@G-5tE`y)FGM{AWVvLRdRKhI}OE^Qei|pNJRn z?Z7Xf57~!oKr|q}!U8xI*&(d6vyI!zJ%~Sy*ACVSUiMz|PWAul&qQPS2tI^EP@Xzj zIvGX5S<;)5Tau78C>5wERd-z%-EPeu%`5s9T_I6EkseA9jY*77bQE+EJYfD~zGG@J zYv3BVGP)egY{b5hU&x!1>yo+Bc~XziCv>J9DMd^ktCXso64Df%r6{lPD}Bm4>VMT& zwO6z;T|)Oi!~YB+lxJ2GXN#+X8sKR1a1!_T;oeX#mXZIJd(2G46Rq(=u@>cpX)<Fh5CG zWOW2-L|P9`Pt9aHhZd6(a+z?cu(zt8YQJHhfz$wvopCUjYs1Yu_`k>0l~8?mefI@dt}8F} zF4PzHg;`WNY6L%muN$fzy6=7H?H%qO#y*IoNc2Bh)DGnLaW1^Vv(m%)IG;Qy4<3vj zioRem!_6}m*UitNW>XJPydxAbqB_Fwg-hvWG>(DxYW8ZTtEa2m(QWAk@kQ|h-&fzw z(5=t}I1VloEf?)XF*EL;?w9D7h(?3a;cx^TAsHn(r#z#aBAp^_h~}9+>WDHCI&zFV z&drofm)$cwL~#~r9%2}3=%wzX?l0>nn=73o?JMgeYb$9d@zGxTlJKGs&(~3bQGt!N zO|~D(YL)4{S})!gcZ=QPStwq};M4ijp)(-`x*vSzIS`%Toqdt!`cU!L-0TF5MZ9I zTlU*_bD6m;%aiG8l4z2s59>j!hl=}XN_-{07QyC0yl-6~EtDQm?Nj;00r5=aA9JEP z(fYCaG0fY9x%K~N{Gaim2|@or{|?O~M$X8;lh>5@miCp_VQMovkxo=jkR?z;4V=nO zW#@qY8C z@ z%qpO~r*Ubc((8rS3s<;Ty07!sc+9u-j(ATb0*SzQ+c=xnrE~3z?u#-|0++(Y@P7P$ ze6Vk*@2uyn2Xo^!mEaoM}94L5?`nK%0Y^-s- zv7NDv@q1M*)otM&VJI0$Vh)(GlJOGU16@r~Ly<{j5hJ3*qL}OY7JBY7kyPZ7dZo9S zJIp0`3C>T>OU5~t8%zzMDk~}}o*SMU7&C3oPb)|}nsFo}KkaLpU1QTo85uJi`B+^- zpZLOlVF$AV*@}_Mk>l=T?(5bY*8Z-6uF7mhc04_nrln#j*3H`O+v#g$|H*#a`>z+* zZ+M{>u1l>;;Xe2|p1GbZf2Kc*{PMc+A7NQo8pgbzm;4v~rT#MiXYXh4kDdmeCf>&0 z)|kH|)h#twGF$SK_9tz=szCJ_d<5w}i%;#)IgW%6hldGA2y3frsgEd*Dq0C!3b6*@ zaAqi@P%G3E3^|6sbw_pI$!f{I5TA$*+y)M7D$%rv9)o7hWmB%HZH2ZK{>ueVYHW{r=yRvpR;wMbz+!!m>6qI zjS!C%QKJiE7&WT=1KEBv_G&{aaD2Qnt&sbLy@dR zR$@Y8e4=NhXJm13X>d;X_b}F=JRm+Sey@M0A8Q_Ko~oXv#@ah4f+vG3Bda22p;_2Z z(@$g5+O)-zQi%e{Kz6EXia;L^We;Tg4f_pv@9HnbPQ@bOA|clH#(njbQS|vqo+lru z9HhLWyrit5`Ccc9Q^MQ=H$lH-zodv2u{RSp6IiQdq;r%rP!KFg|C0V? zYst0}QCJw>1$Kg^a5?-CdlxGW+JZxaLxO+D{*H}DHnlcij}L}|p{nj`?xxNrPS(LX zI(s^KW<;h(3KIDVc~l;4>Tl{l=|APa6ZtptD)};r^|hTcr|h6+pN7$k_04t7beANT zB%4y3Qtcz{B6E{-llue*1%Fe=sP0@3&KvfIulug~E{86MjKByaa*4c_>IYShbi6c5 zMoG+dl?E)}iujs1rB0~Z=-cY;TDx|ZdWO20rkN&Fm!-pd)-yCSHSN_M)I(%LWmARI zgep$OVV*m}N1!bAl zNL^GHH3dz<#nHvlWw9l(hT(=`oY$v3yl0qWxWnowbG-0A^S%na30Q;HV9jWas0zhW znN%hPMNqUxv|5ylV!x^J-{MaqPa@s9?%W{3KtX%56DdLV;(hXM^1EcMB<{btFS#oz zuPU$Vq3ogbGJfVC;uf)m-^O<(x)A4tXN5e&Gq~2jgS>-$je3>ZWpo?oS>{{%8T%T0 zEBh!LOPWYNh~9}-QLCumsaaH4&=ph*RSm5zTUS?_HWtOaDKR0P$*a?S|Mu0 zH{@@Gu7~yq_6Ig6wj_oS0|_m!;jx`gI1|o|_CM|IyluT3W1C{**m3On==tc*(C*MW zgz@2V;U(yq?2Ye@>*KmOUNZ$m0WnTCPPQ8Pl@lm`+$`K8#Cwaq*j_9vNC<+;uu^W6 z8C#oMnb+yo=&}^$6dPn4W%ZTymFcQ<)k4Jrg6Y z@Z!S_$4$qT7e&F6*_Gej{yUe`<lUh^ zI+Mv_u!hK~)ale7;ZEUb?HFx-dO`XY^Ja62yiEQpJ(+$aejskFZla!{pRO0E1!^_Q z$G$^x@G@>Ghim0qDq1VfXisYQ8TT7;j6F1caQb_Fo<5<7EAET#iLfup<3IBk;YEmb zdg(YFuO6roxK?(xY)rw}f=p|M74Mf%A|?|*!N%~t|E+&&>D1ERrF}~)`zrcI$4AGP z#+SsgUHa(x;Q8G>+l}j_?}qM%t|DK2Dts!8&-a%g+>YFiY(P2mQg#J9gd4&QqzBST zL&}g_;ZlY66*^W(YFG`{FuLT;^=5|C!#M8RY}{fTmN`80FT)l?Gigg{icZj#G*vWb zvQB3;s@kxszfz!*&ZIRhN3oob_w%>FKcF^Ui+(D5B5R;-p#E9iRGlHolHmQ6+RP7( zQl^q&PP05|o-|i1lxHVRd^{w@t z^_u&#`)TM!=yu{(!oxYZe$*f;2gM;x&5g{L)2^p2(Js+G6+RZ?IA;l(2X)nT)D_bz zroA_PG~xK;B7L4dD>)~@T6)VWFR$FPM)Ml|D-WnV%s9e`btV;JwYZ!-Q@&HbQ~xsU zP1<6^Lc?a|CS^BiH)%ClHJL-@R5j5z*8i@bqhG0Aru|E~Ln%YX5ZB6Pgfqftiq97B z{=Dn+7G$^EB0q}tnGYc>^)L17iu6VIzuf!sqpg9hTBLfUJKK#7hJ)dUt_Lo@lq)SQ zD=FLM-tB(nf9bD?<^n#`>EZ0=1PGfDSXbP2!FSQuDAp(j2|$uEAlstat{R16=h3N= zsja?kz8C)I{vG^I9>{rFd3E`3weT}(jmH`x*WpCei8m(IUMDs)wR!7ulRA*F}gTI~P z7sY4c7a`uuDMNPFUTiNuYdvEPqxb@A?5sw4vcvE6x3#ymo9!0+JKtO1?)dJwl$EfV z!Svu)M}ecat*330W3mJ5P>l|a3SpfisZZh?Y9C@BZ_BZ*bgp!^_O$Wb3ET;Wz$)?oJSL-%vyuQhF60#aB_jXgr(%-ypOWw-nno4$XPv zMdMig7(LFz9t)ocr_fXB^@{Zhlh&yHL$^-%qv1!xdBZtF9b;W%HB)udYQsu{N~h7) z&{fk7(~Z=fQ=d_PmVB1{#5dq)`{($#*|*x;IXXB5Au5D*I&pX!}afMxao8C6UI>Oq?(Zx~I zRozv`UC(XxmU#z82Sqy)9f)pBcc!bThiDtv0!%4$3g6&yURV7t5b+#JUldq%K z(OA!FtaPkYsuSxDryWYGlU6s)q%mpcOXf?aNTy0gDMu(f={oE1-v2R#f%^XXpA3x* zGtD#2%hH#m@3!o+K zfqj94-b3CJSE*~AYppBK_1V?k)769fL-2WF`9%3dAuNPzk$0{s{$AWg+(|qfVI)10 z#yur#nKcaF%l8;P#!r?{xTVkHHnv2|lOFIkD3-lR^bj2Kc9u0&*h-=e~DP!ts;BnxP z8 z8{He-J8Zjbdu@Ac0ypJu7HAs4`rn&FTSJQjivs0C6+;@7f8spQ54-^Da_y)0(^FCY zt5s+e9EvBjPzxur6WPfi2Mm@Ckrf&XjB2yS4Ag{rsd%Zlv!tWsxax!|-I!(^q#vwL zm#51!g_**&uhU7lsD}R>m4xW0uC}bT>@aLMB*Y2vW^N023?75`TLD+NWB#!EMMkR5di${H%E*eJYhw4D~7cIch6$mXzcb z<{d3KT2R4T+1r|J$vRW^lprVwCJVX3%)E@e5k(`4%z?DPg2ep9_tEd8&)v`6vQla3 zmf~&2qn%@%D+0>{^Zg6_|GNHl4YCim%WMi;F+!Q6)Y0G5-_s`CI^2qH^G%ams*os@ zQl<0+f0SPwSQZd^DKFN|ImjGhvQ*_%CZ$PvLUK~FSGZd^fgVo}P!CkgEegx2jFTC6 zEq5)$^~3cQr4^+Lk>Z<9NKhBnO*G}0ju?&@8tEJATj|>9Fh|0A-Fn>whdn->{(YV5d;0&>qijPr5bTI;v!B$%e9xWsPk= z*=jnfJMQ})`0#oABjO=ZnXW>&BioXlqg|tiLWe?g_}Tn9={adrT@#(iNE>ZxtNIc1 zkco?uB8@_&m|z%h_?VWL)(+XF`uci$%+<|HILRjUR`ns>0bQQ!0>b_6ojAzMiS>DG%+Xu@=HQxDEzV!PG** ze8D~Cf67Z~7t>~E&Ca@M`NuL_H%r%7JwPorhz++h?qp1>W?soGMz&+0WshZyd5k&Tm|@(h z{Y$$@vQPq(Fsb&d{Ds~^FV=|Ty}Z|KGuh$=v4T&py1sCIp(EdsuP#s(tj=GHzH;SLC1eSM zV$#d8t1;Z0_%qq!8}|w3FBr{?VZyqQu8yUSrK_p4shy#nVO84dw4vpOlxtJ5b;Y-p z-d1W?xkKg36)II&W?5m0B46Ch)Xe0vI4pVTdFeOPZlpCcv@nd)jn?I+T~1qCX-TD3 zRn}HXl#iBoSv;1H#*fD1$ahaN{A#GFsjk`1>|ih_d?@OV{>g4)Gq?=yUF3bFx2Lyf zo#PM3e+XKa2DcwNtJ|yF+0uCF;^M`{Rg0?>A1Xdlyt8meVfbt0>+!G0z6QSpzl=iw z1!Td%qJc#%i&_=cF8ZOUYjL;Yk+zYxF}~40%#~3RDh>^f42ragwvJATPl>PLR&%)5 zCKQXta4%soSHe{lRuihFDk-j2`bE`FHBB>B^Vsm%@HG8ddUm<&a^Gjv%IIME#WF5q zY{nlM8#AhARLhu}H7P5ek;s^9nr)Kn75W;w@4od3;arP1@g}Fvq3fdTqFf?dEW^5! zD7cl}Vg6;XUhynyCe?@NLs)&g*u$U4OZ@yAC@KJ59)lRw$`ZGPH0=VYo0__@C{84ae=4uqE6&*eZzi z7nY&d8_?%*fl-0Ip?x9Dxt|@Y6zj?MWwSwL(1vNtlqidp&(zP<)0EScJLS9N9~JKu zd$jwtdb8Gi&~VUz`_plb5)cN3KABG@Hc3n?GFN0W8Fa=EXk8C64K@kPl=+$InWcr^qfpfeMVrJL$1pF>^2pLi8j3^wUZ3}#^RBa*qq*ZR$96|W zbhiua3++C;-~Pn$*zuG5NB8f6If0Xr6Oqc{%HdDG&%RaORo;32x&CLtr$JA|7wN`! zW&5WFrn)3MCR?L8ra9k?$C|DIVOThU8P9MuM>~ZM;Q`Tp(GtlLNi9WfMNL(873L3E ztNBB-Rl8MtUw>aOHOtIVbIe@Xm~Gsx-J$KP>94t=xvm+m9ii=^?XDfI9;0q2Z!7OD z?kf(6e4;L*t|IJ9FuzF!rXrI^eWc7p8qpnggTL|9`F>nKZgp~X64%Yv3V#5?q}{NZmd0U7UkE)-eT_)&r?rTU$!qNI3WnbFuXr< zAaVv_T6B7}e!O0MIy;@sOMXh?KHT2PKFQVGN)Gppb|$-$Zqh>rsUY;_jO7~d*SdZ6qRc*FbsaC1mDt}QmW;tlj2vxm%<{VfWUQhjbRgr_ooNPhsNhe=SJH^ z+eQ@;Sp>({g`t8_uSm}b)|J5eT!}Cn{x$GxV1aj`_loC|$AN4>j&GuGw0E?(uD6a? z;*7458aPuWVGzH@{Ka4imBEp*C_G+!At3Dsa@ufJyJYSSk&q2+L|9U|5G+l3Z$g8 z2w{O@p#t|qO+|BhHNA$uBFGiY!aIY^Oa@2^saNb4e@EA%aov%GkP+{}d$5n#O9%*x zsL9vhcPI8FHb*u`UWeX<+JxJLv7Ut|=nIN`l&`!OGVg7BF28Jv7aAZ5M2{q6RsMp z5~TgKzn%9Nui2CCDe@F}M)^ni#{@?QBY|)L>!!U4ya`kdR}KGwurIJTK>A5P^z(iu zEDmpv{S`~HDRwe9k?X>D;RTR_<%n`bYe7pv8D*u83;!1O5%d!L3-3UlAjnB5w(TYB zB`c4RF11LXil2$mph;*sBj=Ssbqqb5?b5B%my(wfR+f^LDoPZ6RDD!^)qT}9RW($F z@?!Z#gst)|a;&p`o;k;iL%BTGefSwP2X%-##0F{|h5JCAXvHmsiy-dp*@>`;+sr*l zK1rUAos4}5eGJVF%?n{|gWl0z(UM4EM2E7lt${58nP2MP=HKqeeXrHS)x+UXIE0BW zhDU}+x<|W3k0YCh=g=Yq%sqPy<@>mP=Nn%HJD+`%e3P8S=kP~}qr_>!DFN1=UP3M- z`+;5{#7B7*p(L&fuL@OSrPz;vHNNnk`DW=B=~3xnX=jArB{L;X#>MPGxFEhLZY06G z;*BL?Nkr09+EcnivO^-5NF>+9*Tr*~xy(o5N8xyK99b9C2Ux3EMA9VIsP8N2C%_!d zm`5Z7LBT8eGPam~jeOD2*zi~jwgvl3s#VI8%uEhQ^h*pvar}iCX5Ba!s}Qdc$6Oqr zBcCJX!{x%Q5Y|N2M9Re~#IUB&mDKgrYHkI05P{}Jd^4^E*Cf?ARfnt1h0%Qq(4f5J zUU0ZC8gu=Lp#&ZR2SJi#$@|njDn`Yrs)Fi*dT7j!632)H`j=z$G5R(0hI!6BV=y=4 zNO}}K4Z%p8Xk2wzfP(LL7XFeg3Ur)?1XDb_dAKQbjeIovzkD~$I& z`Um?3CkH16XM|^l$3@3R=fvj3x+S_K_M{G^@EP}0{y87u0^HBYCr(6j#mjlPTTr%0bjA4^+FTS|YEOq1X}zm}2~l0U@j#PjL-^n2Yy3w1Ry;Rx3C*u7sm=Trz7yAh>zVAC+>+d!JkFiq zwi4Tkj-vLW;mk1Rpy;TmC)J(e5qdLynTyDF)|b?iU|xF68P`qFRj@|5M);U{!kiMH z62E2M;?e-758am@K@X$nF!Pws;*Mgxe|DM4WsWh&nF``6;%&@UW}#@I$U>PZTq9W# zR)F|p7&(l*LR=v%yoKMI+@91VRY@bRR{%!g65azJcgtbepmbbstXtPr7Pv{e-Az;_9C4#h(8P-(OzdO4AsP@wl+j(~ZY6-i}s zExU$A;eH|&PsIl(h9xcl_sDiaaS`tC!)Fm#>j&4~o)jGyK_L{b7OfGr6}1xO3-g6`6q9vBkcwoYrOZaY4?S zvZnT;Ie&}0&h>_U;4%0&yvyI^hj2r=8_63r)e_I#{hykIf4lv*rYh@O;Ph|gv}2|f$%k@v`p zf(wGj!iPev|5;g7QH1+Pj}V85+u#oPnP@^hCteU(!w37wySo==`no<`_{ zU`Ux#JGpHf<_nw3{l?AUrgOfOCxyAK$E3!jaE(D;>O<;b^1q}arA(bmUBEO7d?(Nz z1QFiB53oD}KG*Gx*1QU+z3An4N~F;b?9wheD|2KgoZS_^hTB0duWx;5YK);ds~zv<5>FZopgc zPq-e|0d+w>{DS6xh}(ze{#tGgCjb-(5n%$?!D7CfT4XJR3-5L^(1-`e%#rb z9pzvOrkrU;(n4#T4m^Cn;|B97!qv%n-cOP(jOrt2DnTI6@6PM{Ig64VjQAg7a? ziOmG=FRD(|AO;Zw2+XIumRN_p{t2QIQH9up)?YUIJd_;%Z5|Gzh9j%+4+SVFXic^u zCxCGP#|Mk}Mf_fFFLxw$H04kFlTA}iQ#h}93*W$>K{Id_TmyHByF@p#JDDKjgovPt zX=of(yn@HQ(4$hLQ#F${zuE9^$?i!!cc<`E`67gIa2&+KGELC?Tu1MNbC-&s0>Hew z$N3Xz)&I!L(J1g7&o$#4^Ezlkmi8IMIaYVj6^sUB!5K8h`-%NT1M+{!vYAM%X@>jx zhm#}7N#sN_Mns7l;0D0^J+r{?C=v_;GnzxS5pof3qG;%(;JDy`;Gm!fi2!p&%ZU56Q`bUj?N^DS_vG2nNu1enzXQK1^~P_bl}!H7zwg z^{o$_xAE`c`)}*)Pq-0c&6Wqm1L7iaj&K1N`q?P@xdte2Jj`by+(hx$&j`4dpWq0t zGuM%u!_DR9@V}$?`2Z`RYj_S{LID6^J=h4aMsE|cDT#YTMw6pR9CPEo*q7i1c#N)l zCBKX>2dIPAAKud$j1VM3M1Rl^EQU)U zj^hgW0=^o;2yPhH6In3)foq<|^5gjP+*uCuc4?s==71dV9HA5F49>%Ia5LNlEhuI` zied}Q&9)Ejfw)KFE0@oG=01JXC|rxyjS(8*as(T+qW72po*-NWSHLo`0^s;90oZSU z_JaKY^MoD+hd~6PAJLCkOe{fGqzxJi8@LVbp-As9&;a}o1Yr=?Kz0G!K)iR-1Ysmv zKP`w>L_WwzD`z*Fd!qp6?{y(tdlUZi?RqiC&KkHHS;E`!H5#YAC>LFYUgNl+6~bE- z+ur1FAWQd>|AcJJKL~%KymdXg58Qw8EBqB=8?*q_!?+DcOXd6Na1I`1OaotYy(@t1LU>B09Vh(z*?{dVD8;}DE8>acjxEw zbNEb{3G>mrwn4UV4zhr_-#Q5Vpg+-&ZuBc?(@X z?g6fk=KE|o7Z%|VXO6Zwpj?1ipeVXhu5$u4n0ua@M!#>c*h&#eLr-1TcW|5&(G~pSemP^R0&GECRkC ztQj{O0rO5h?+KjKDL@e1JtIF4rWR)BrgHDtpt zg7e4{tO5TAP)h>@3IG5A2mqKQ$5@EY5CM|_007DW001Na003iTGBGtVG-NO}Gcjgl zW@chCGBPkUWiVx9HDzQtG+{1tc4uu(OAdn|6x@4?*S816t~A1;Nl(xdv`U0j#lWl3 z+t*r`O=dBfZyVPERuiK0vqH%wLUKJ>g%yG|Zm_h|)tPkhSs|0Kp@L1z(>Ox7(!)$*5_Q-WPyxQ2A4F!U&A5xx3IhD!q{Ml3 zM}o)z0F?fJl0w0xAz(BF0<)Epl7vc0NZLZBP$;mC6%?PP6&(IgQoG1G*BR+sLHib5 zb>dGlRF5w@SiE1VU|XB#cbC|yBXfDDrxBb&I+a0}l(z5UoZ;>PWutd0^?B2%jU zdKsZj=erKg!zGLySJ)M&DZAHPd*FrO8(yS`e%X?zQAh=`IhPrP4~LBFs zmU!)cFehLw$2_;s12ZXwi~9ZN>VxTr%7)B>KDj5h+okqfa3vds?XGxpxuVLtz80GY z_2$X<=NuVME?&AN&inlA=~4gHYs!U+PPLXPkRpsI3=~T{6Ph-DEfHIUh(2WXX{!{^9b4Q;CWCtPiKT-AO=( z&B^S@lgl=#cS#2+1%q=QYOkF*_ACFKetK!=3_bEaJ;NP2z&p68lmxw^<;;d!p$)#9 z4Uf*&C6@0TzLyMjUdhLl-lF6CrZib0cxqhc>9Ujys-*H~r#@+0 z87XO-m*~~+pSVFfIf1_Ad$uR_ej#t@!^^+k0NI?5#Fu}!A)qqv8SL?ATR>x6u1Khw z({RzEOY6TCwpr$+p4g_R-l3e7dc0xma8=H4QFdh|n@W6~sdkJ`Jn1a)g`E%8{BEr) zsRw@v(EOaQgcBSU$eyq*K4^$$J zf+b~$rn*@9^*~&{kjZ0u#t9-256h4s&UB63l**Lnkp}q4@{#E%RcCf?ZAx!#3iO8g=8*s8c+zdk~NJ~PN z6En-ANw`iHn$qf({Ue6%*P3|=8}*pbz1Al^y1!+v?`mBXZCwNu3TwO{5e^(Grox(a z&h`wN+0{m|u{3^tjN}{Q8ayT^h0zQ|;p#5`ICA8;^fRnZHWc-L`;qfvK*8;kb2{xu zJ6X0z973-^R$}5eQ=t=uiqYUMOlsl@)%|X_qE7Zv$6FC~s{k%4c$K|rz>!IR1HV= zflxpP;RMvd-S4V;+COi=Bx;*ET;VqZTYjHT8qM0Ys8;lH4v?-}snX;PC);rN=Kz}; zR*A$Azy}|ICSY}70YZqTXG-0qg@lHR_5KakFvw=Sr&74x6n1*Zawt!LokRX@Dk#YT zH+39v#0uO_$%Y5Nh>J|0_{PNipgOKQ});5kCdQUw7rDc1A;3Xv(Z(@bPd&prulfQ}C;Bu+$l!3wv>?g-uO&cdd0hN*S!Cf+D?T z+Uleain%Ma$VW=6Tu8-DelWr0LBTF_vF*eHS+rD`e>xu+>u%;+EDd@F1gpNb`Ze4+ zgXFvsJ5A0KnZlp&MsOx&X2rz=%&>^K**5~4Cw#-H2K-^Erm5T!BV$>5ktg7!TGWM{ zRNt&3xh)W@Qb1FepQ%^D<8(L~OPGdfZV0VamjF)NhvqLndJPXVq>dux57oR{8t;S_ zQ&SXtU}`#9`Y!+5AZj9pt zmhiUAn{LU!xEBMf*63ziBxcF(ALN`RM#;93*7P}EtSz=*o~gXQY=xc(s5E8`2bx#m zeAt?zvqN!L_-FFJc^1vsN)`TS`%R26_HbKr`NP#ZBu=M^$MP zgDJP}Ev}bZ!aWl5Onzp(%{ZVp;%(;wfrDI~p8{!4ot#wid42&*5UtVhYL4kcgSF_pTn%W^fWS zl4d!FI3KgGTtYONxI^6Pj!QqgpK$gSiJ5)aHc4n~4t2YrFkiql%%9dP?08@|+<(aW zFU;}GD~$iR2SMyqS^T)WrSRo~=v*f9%7v@Qa-=nQsa8B%l>H@#n8~e3i=t+VyJl6FMO8i$oqvMhF^>{z3iw<;c zB9W{Xy*b-n@?^)_PT)P((91@v({qk){-Ns|jJUshvO)k;I=teJ>(9ukKB+>miu)x^A>)3H>y&`eKU)3^%)x45{tZd`;t zVP=}AoSAckj2aa@n`~Smu*>ci0Dm-$uOHoUudkP9Nlv}U3m5dfhDoVF+f1t+Fx)LcF8aK4H*r%<3JB?%5&Nq3 zRusAWT&&uXOj$;ANpfgtsw;m~j85s=E~^x0wlFiF=WaRAJ%M@XEX;cE&q4M+t#XVC zw_lz4yv5LIW7zJN(^>5tS~eDML9M)r?IKmOp_Gc<{O;?^-%GY+Ag&o9&lzxJ1{L<- ziPUejg^*x0AE?QzzuHNyn;)G`Ecw&NQQ5}q3kfL7WfdYd5L9mKmgw)UjxggVZ;cCo zH{L4fTgh~#Q2Dc7M~nexSFTHP#BPPi*c6qKsjJ~s^w*W_Sfb4@a^zRvHp0HcvYRGw z<6q28W*R6Y>ak=rw;`1FCgiQs2CX8&9Yz8FB<$vxHt7I6t>#E{o-+l1X5?D*=u|0+ zNxf&ivjU?{5b+}(l*RJ+Tp6E*aN}k*5@UJ%;Tx$JBsA5?dWlLUl6e1QuVb5aU zV^8S$CZ8dxopkH|jGomiV06Y?eE;m+Pmk433wa5WDslF5aQz2Ql@~YxOWQ;il@<0H zkp--A5_E-?YSMr7-%-ToOwh)cpxuLx3JXxg#7a5rA72KZu8Kb}-~=`Hh!kbD3o{tD zB6;YTxQ|mAtazst6m@bw?()gJ=j*8+!1py_*Rgv`D{-P~o*9!IDnp!fH-Ryql1K5Z zXoY{33FCGJ6P1qRge1R+6I3_RN&QSaf?YI=yL)J6xayZMuW6!zc2_Npq&-a9X!Ob2 zFDkQ_1v#N)d351GR^*J*!pFT{u!wp{JVN7g#czTwtHmN-iUvp6#+H+EY3}9#ADfS;7{7jZBA+crAHJl41>O1nU~7cbyD@C#{I!G|x~K&iKfIu( zDT_c@Wy;)wJxBghvwV(pT}3osdmeq!Zp~-k9}eOzo&NrG3)%qGaSnS(3}tw7tpnr- z`8F#`{C-dnDr1!M#yO??!?6Cyt4&_O1j6V-F4r>G?pF5BPT8Izz+*SJ0Nf)uvq#kt z6}-dTV?iaUHS1tfN2jCB2nh!P6IvoBMar{vX6c+uxL+oSFKeIIEIW3wE8P4>ewxZ( zRPj*>ZaHU5|9Lusw+v;!NE_62L|99gV5^f5{_HF=9&f{65~9$IZab@bAaT2TkelM9 zgXFLxQ?7gQvO``$+uu3Y4^5d+I&eN%ZqVu#Mwm!{oEey_aVQmeH`XK0vE%^{bs{)p z;^}@-qeqq07tB$rs6wVwc3Hqiz~lZc%i71I?Xiq9^0+RYp=6BTqJXBkw0!y3UQ|J`#OL(54;&5_ zko%Pg=j!j9=-$50#q%WY*>PJ8ZA^LQpS9V*QyE|QyO_ll!fV}wb8kH@0>ayXe?_Mi zAG<{iF#zzA27q^;{5{+}Tpew#y~G?nU0wc;%szbm2|@?}fbi!(a@D`%JswXQYz2o& z!)&CiQBX7(1%rYmQBpQGXj>E-CIyDV#JsIAe|wI1b-nik^%s5ur(NJ zBMpMuSi>d3l6X^zEes?Dw}L<+)=(50{r@5UEvfyx$C56B|4Lx{dyjwXS^pxw=q3RC oH|o~kh<_8Te-V|22>|~M-O|${Ciy3d1b>VX008V$_zU2F094!gp#T5? literal 0 HcmV?d00001 diff --git a/extensions/integration_testing/playwright_load.ts b/extensions/integration_testing/playwright_load.ts new file mode 100644 index 000000000..851111737 --- /dev/null +++ b/extensions/integration_testing/playwright_load.ts @@ -0,0 +1,208 @@ +import { chromium, Browser, BrowserContext, Page, ElementHandle } from 'playwright'; +import * as path from 'path'; + +(async () => { + // Launch a browser instance + const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions + const context = await browser.newContext({ + permissions: ['camera'], + acceptDownloads: true + }); + const page = await context.newPage(); + + // Navigate to 'Create' page + await page.goto('http://localhost:8602/'); + await page.click('text=File'); + + // UPLOAD ALL THE BLOCKS + const [fileChooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('text=Load from your computer'), + ]); + + const filePath = path.resolve(__dirname, 'downloads', 'allBlocks.sb3'); + await fileChooser.setFiles(filePath); + + // TEST 1: PROJECT CANNOT LOAD + page.on('dialog', async dialog => { + console.log(`Dialog message: ${dialog.message()}`); + if (dialog.message().includes("The project file that was selected failed to load.")) { + console.log("Invalid opcode found.") + console.log("TEST FAILED"); + } + await dialog.accept(); + }); + + // TEST 2: RUNTIME ERRORS + page.on('pageerror', (error) => { + console.log(`Uncaught runtime error: ${error.message}`); + console.log + }); + + // TEST 3: INCOMPATIBLE FUNCTION TYPES + let incompatibleTypes = false; + page.on('console', (message) => { + if (message.type() === 'error') { + if (message.text().includes('gui Attempt to connect incompatible types.')) { + console.log("Incompatible function types detected.") + console.log("TEST FAILED"); + incompatibleTypes = true; + } + } + }); + + await page.waitForSelector('.blocklyBlockCanvas'); + await page.click('text=File'); + const [fileChooser2] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('text=Load from your computer'), + ]); + + await fileChooser2.setFiles(filePath); + await page.waitForSelector('.blocklyBlockCanvas'); + + + // Wait until blockly canvas has children + await page.$eval('.blocklyBlockCanvas', (element) => { + return element.children.length > 0; + }); + + // Zoom all the way out + const blocklyZoomElement = await page.waitForSelector('.blocklyZoom', { timeout: 5000 }); + const boundingBox = await blocklyZoomElement.boundingBox(); + if (boundingBox) { + const x = boundingBox.x + boundingBox.width / 2; + const y = boundingBox.y + boundingBox.height / 2; + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + console.log('Successfully clicked in the middle of the blocklyZoom element.'); + } + + // Collect all IDs that aren't arguments + var dataIds = await page.$eval('.blocklyBlockCanvas', (blockCanvas) => { + const elements = blockCanvas.querySelectorAll('[data-id]'); + const ids: any[] = []; + elements.forEach((element: any) => { + const opcode = element.getAttribute('data-opcode'); + if (opcode && opcode !== "math_number" && opcode !== "text" && !opcode.includes("_menu_")) { + const dataId = element.getAttribute('data-id'); + if (dataId) { + const shape = element.getAttribute('data-shapes'); + const opcode = element.getAttribute('data-opcode'); + ids.push({ id: dataId, shape, opcode }); + } + } + }); + return ids; + }); + + // Collect all the arguments from the IDs + const blocks: any[] = []; + for (const id of dataIds) { + + var block = await page.$eval('.blocklyBlockCanvas', (blockCanvas: any, id: any) => { + const element = blockCanvas.querySelector(`[data-id="${id}"]`); + const argumentElements = (element as any).querySelectorAll('[data-argument-type]'); + + const argumentList = Array.from(argumentElements).map(argElement => { + const argumentType = (argElement as any).getAttribute('data-argument-type'); + const transform = (argElement as any).getAttribute('transform'); + const match = transform.match(/translate\(([\d.]+),\s*([\d.]+)\)/); + let xValue = 0.0; + if (match && match.length > 1) { + xValue = parseFloat(match[1]); + } + return { + type: argumentType, + xValue: String(xValue) + } + }); + const filteredArgumentList = argumentList.filter((arg, index, self) => { + // TEST 4: NEW ARGUMENTS ADDED + if (arg.type == 'round') { + // Checking to see if the "round" argument type has another value in it + const otherValueIncluded = self.some((otherArg: any, otherIndex: any) => otherIndex !== index && otherArg.xValue === arg.xValue); + if (!otherValueIncluded) { + console.log("New argument detected."); + console.log("TEST FAILED"); + return true; + } else { + return false; + } + } + return true; + }); + // Sorting the argument types to get them in order + const sortedArgumentList = filteredArgumentList.sort((a: any, b: any) => a.xValue - b.xValue).map(element => element.type); + + return { + id: (element as any).getAttribute('data-id'), + arguments: sortedArgumentList, + opcode: (element as any).getAttribute('data-opcode'), + }; + }, id.id); + blocks.push(block); + } + + // Helper function: checking if arrays match + function arraysMatch(arr1: string[], arr2: string[]): boolean { + if (arr1.length !== arr2.length) return false; + return arr1.every((value, index) => value === arr2[index]); + } + + // Now collect the argument order for the new version block values + for (const block of blocks) { + const selector = `[data-id="${block.opcode}"]`; + const elementHandle = await page.$(selector); + + if (elementHandle) { + const argumentElements = await elementHandle.$$('[data-argument-type]'); + + const argumentList: any[] = await Promise.all(argumentElements.map(async argHandle => { + const argumentType = await argHandle.getAttribute('data-argument-type'); + const transform = await argHandle.getAttribute('transform'); + let xValue = 0.0; + + if (transform) { + const match = transform.match(/translate\(([\d.]+),\s*([\d.]+)\)/); + if (match && match.length > 1) { + xValue = parseFloat(match[1]); // Adjusted to get the y value instead of x value + } + } + return { + type: argumentType, + xValue: xValue + }; + })); + // TEST 5: CHECKING ARGUMENT ORDER + const sortedArgumentList = argumentList.sort((a: any, b: any) => a.xValue - b.xValue).map(element => element.type); + if (!arraysMatch(block.arguments, sortedArgumentList)) { + console.log(block.arguments); + console.log(sortedArgumentList); + console.log("Argument order does not match.") + console.log("TEST FAILED") + } + } + } + + await page.waitForTimeout(2000); + await page.reload(); + + // TEST 6: CHECKING WITH CONNECTED BLOCKS + await page.click('text=File'); + const [fileChooser3] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('text=Load from your computer'), + ]); + + const filePath2 = path.resolve(__dirname, 'downloads', 'comboBlocks.sb3'); + console.log(`Uploading file from: ${filePath2}`); + await fileChooser3.setFiles(filePath2); + await page.waitForTimeout(5000); + await browser.close(); +})(); + \ No newline at end of file diff --git a/extensions/integration_testing/playwright_load_old.ts b/extensions/integration_testing/playwright_load_old.ts new file mode 100644 index 000000000..6b728baf2 --- /dev/null +++ b/extensions/integration_testing/playwright_load_old.ts @@ -0,0 +1,289 @@ +import { chromium, Browser, BrowserContext, Page, ElementHandle } from 'playwright'; +import * as path from 'path'; + +(async () => { + // Launch a browser instance + const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions + const context = await browser.newContext({ + permissions: ['camera'], + acceptDownloads: true + }); + const page = await context.newPage(); + + // Navigate to 'Create' page + await page.goto('http://localhost:8602/'); + await page.click('text=File'); + //await page.click('text=Load from your computer'); + const [fileChooser] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('text=Load from your computer'), + ]); + + const filePath = path.resolve(__dirname, 'downloads', 'My Project.sb3'); + console.log(`Uploading file from: ${filePath}`); + + // Set the files to upload + await fileChooser.setFiles(filePath); + + page.on('dialog', async dialog => { + console.log(`Dialog message: ${dialog.message()}`); + if (dialog.message().includes("The project file that was selected failed to load.")) { + console.log("Invalid opcode found.") + console.log("TEST FAILED"); + } + // Optionally accept the dialog + await dialog.accept(); + }); + + let incompatibleTypes = false; + page.on('console', (message) => { + // Check if the message is an error + if (message.type() === 'error') { + // Check if the specific error message is logged + if (message.text().includes('gui Attempt to connect incompatible types.')) { + console.log("Incompatible function types detected.") + console.log("TEST FAILED"); + incompatibleTypes = true; + } + } + }); + await page.waitForSelector('.blocklyBlockCanvas'); + // Upload the file again for data-opcode to show up + await page.click('text=File'); + const [fileChooser2] = await Promise.all([ + page.waitForEvent('filechooser'), + page.click('text=Load from your computer'), + ]); + + await fileChooser2.setFiles(filePath); + await page.waitForSelector('.blocklyBlockCanvas'); + + + // Wait until blockly canvas has children + await page.$eval('.blocklyBlockCanvas', (element) => { + return element.children.length > 0; + }); + + const blocklyZoomElement = await page.waitForSelector('.blocklyZoom', { timeout: 5000 }); + const boundingBox = await blocklyZoomElement.boundingBox(); + if (boundingBox) { + // Calculate the middle of the element + const x = boundingBox.x + boundingBox.width / 2; + const y = boundingBox.y + boundingBox.height / 2; + + // Click the middle of the element + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + console.log('Successfully clicked in the middle of the blocklyZoom element.'); + } + + // WE WON'T NEED THIS except for defining the elements and removing priitive opcodes + var dataIds = await page.$eval('.blocklyBlockCanvas', (blockCanvas) => { + const elements = blockCanvas.querySelectorAll('[data-id]'); + const ids: any = []; + + const calculateDepth = (element: any) => { + let depth = 0; + let currentElement = element.parentElement; + while (currentElement) { + depth++; + currentElement = currentElement.parentElement; + } + return depth; + }; + + elements.forEach((element: any) => { + const opcode = element.getAttribute('data-opcode'); + if (opcode && opcode !== "math_number" && opcode !== "text" && !opcode.includes("_menu_")) { + const dataId = element.getAttribute('data-id'); + if (dataId) { + const shape = element.getAttribute('data-shapes'); + const opcode = element.getAttribute('data-opcode'); + const depth = calculateDepth(element); + ids.push({ id: dataId, shape, depth, opcode }); + } + } + }); + + // Sort the ids array based on depth in descending order + ids.sort((a: any, b: any) => b.depth - a.depth); + return ids; + }); + + // const seenOpcodes: any[] = []; + // for (const block of dataIds) { + // if (seenOpcodes.includes(block.opcode)) { + // console.log("HERE"); + // const elementHandle = await page.$(`[data-id="${block.id}"]`); + // const box = await elementHandle?.boundingBox(); + // if (box) { + // const x = box.x + box.width / 2; + // const y = box.y + box.height / 2; + // await page.mouse.click(x, y, { button: 'right' }); + // try { + // await page.click('text=Delete Block', { timeout: 500 }); + // } catch(e) { + + // } + // await page.waitForTimeout(500); + // } + + // } else { + // seenOpcodes.push(block.opcode); + // } + // } + + + const minDepthNode = dataIds.reduce((minObj: any, currentObj: any) => { + return currentObj.depth < minObj.depth ? currentObj : minObj; + }, dataIds[0]); + const minDepth = minDepthNode.depth; + + let moveX = 600; + let moveY = 100; + let alternate = false; + for (const dataId of dataIds) { + const elementHandle = await page.$(`[data-id="${dataId.id}"]`); + if (elementHandle && dataId.depth > minDepth) { + const box = await elementHandle.boundingBox(); + if (box) { + const startX = box.x + box.width / 2; + const startY = box.y + box.height / 2; + + + await page.mouse.move(startX, startY); + await page.mouse.down(); + await page.mouse.move(moveX, moveY); + await page.mouse.up(); + moveY = moveY + 20; + if (alternate) { + moveX = moveX + 20; + alternate = false; + } else { + moveX = moveX - 20; + alternate = true; + } + await page.waitForTimeout(1000); + } + } + } + // END WE WON'T NEED THIS + + var blocks = await page.$eval('.blocklyBlockCanvas', blockCanvas => { + const elements = blockCanvas.querySelectorAll('[data-id]'); + return Array.from(elements).map(element => { + const argumentElements = (element as any).querySelectorAll('[data-argument-type]'); + + const argumentList = Array.from(argumentElements).map(argElement => { + const argumentType = (argElement as any).getAttribute('data-argument-type'); + const transform = (argElement as any).getAttribute('transform'); + const match = transform.match(/translate\(([\d.]+),\s*([\d.]+)\)/); + let yValue = 0.0; + if (match && match.length > 1) { + yValue = parseFloat(match[1]); + } + return { + type: argumentType, + xValue: String(yValue) + } + }); + const filteredArgumentList = argumentList.filter((arg, index, self) => { + console.log(arg.type); + if (arg.type == 'round') { + const otherValueIncluded = self.some((otherArg: any, otherIndex: any) => otherIndex !== index && otherArg.xValue === arg.xValue); + if (!otherValueIncluded) { + console.log("New argument detected."); + console.log("TEST FAILED"); + return true; + } else { + return false; + } + } + return true; + }); + const sortedArgumentList = filteredArgumentList.sort((a: any, b: any) => a.xValue - b.xValue).map(element => element.type); + + return { + id: (element as any).getAttribute('data-id'), + arguments: sortedArgumentList, + opcode: (element as any).getAttribute('data-opcode'), + }; + }); + }); + + blocks = blocks.filter((block: any) => { + return block.opcode && block.opcode != "math_number" && block.opcode != "text" && !block.opcode.includes("_menu_"); + }) + + + function arraysMatch(arr1: string[], arr2: string[]): boolean { + if (arr1.length !== arr2.length) return false; + return arr1.every((value, index) => value === arr2[index]); + } + + + + for (const block of blocks) { + const selector = `[data-id="${block.opcode}"]`; + const elementHandle = await page.$(selector); + + if (elementHandle) { + const argumentElements = await elementHandle.$$('[data-argument-type]'); + + const argumentList = await Promise.all(argumentElements.map(async argHandle => { + const argumentType = await argHandle.getAttribute('data-argument-type'); + const transform = await argHandle.getAttribute('transform'); + let xValue = 0.0; + + if (transform) { + const match = transform.match(/translate\(([\d.]+),\s*([\d.]+)\)/); + if (match && match.length > 1) { + xValue = parseFloat(match[1]); // Adjusted to get the y value instead of x value + } + } + return { + type: argumentType, + xValue: xValue + }; + })); + const filteredArgumentList = argumentList.filter((arg, index, self) => { + if (arg.type == 'round') { + const otherValueIncluded = self.some((otherArg: any, otherIndex: any) => otherIndex !== index && otherArg.xValue === arg.xValue); + if (!otherValueIncluded) { + console.log("New argument detected.") + console.log("TEST FAILED"); + return true; + } else { + return false; + } + } + return true; + }); + const sortedArgumentList: any[] = filteredArgumentList.sort((a: any, b: any) => a.xValue - b.xValue).map(element => element.type); + if (!arraysMatch(block.arguments, sortedArgumentList)) { + + console.log(block.arguments); + console.log(sortedArgumentList); + console.log("Argument order does not match.") + console.log("TEST FAILED") + } + + + } + + } + + + + + + await page.waitForTimeout(20000); + + // Close the browser + await browser.close(); +})(); + \ No newline at end of file diff --git a/extensions/integration_testing/playwright_save copy.ts b/extensions/integration_testing/playwright_save copy.ts new file mode 100644 index 000000000..e43adf9df --- /dev/null +++ b/extensions/integration_testing/playwright_save copy.ts @@ -0,0 +1,380 @@ +import { chromium } from 'playwright'; +import { expect } from 'playwright/test'; +import * as path from 'path'; + +(async () => { + // Launch a browser instance + const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions + const context = await browser.newContext({ + permissions: ['camera'], + acceptDownloads: true + }); + const page = await context.newPage(); + + const wheelDelta = 20; + + // Navigate to 'Create' page + await page.goto('http://localhost:8602/'); + + const includedExtensions = [ + "PRG Microbit Robot", + "PRG Gizmo Robot", + "PRG Arduino Robot", + "Music", + "Pen", + "Video Sensing", + "Text to Speech", + "Translate", + "Makey Makey", + "micro:bit", + "LEGO MINDSTORMS EV3", + "LEGO BOOST", + "LEGO Education WeDo 2.0", + "Go Direct Force & Acceleration" + ]; + + // Wait for the editor to load + await page.waitForSelector('.blocklyWorkspace'); + + const addExtension = await page.$('[title="Add Extension"]'); + if (addExtension) { + await addExtension.click(); + const parentElement = await page.$('.library_library-scroll-grid_1jyXm.library_withFilterBar_26Opm'); + + if (parentElement) { + // Get the last child element of the parent element + // library-item_library-item_1DcMO + const childElements = await parentElement.$$('.library-item_library-item_1DcMO.library-item_featured-item_3V2-t.library-item_library-item-extension_3xus9'); // Adjust the selector to match the child element type + const elementsWithSpan: any = []; + + for (const child of childElements) { + const spanElement = await child.$('span:first-of-type'); + if (spanElement) { + const textContent = await child.textContent(); + if (includedExtensions.some(phrase => textContent?.includes(phrase))) { + elementsWithSpan.push(child); + } + } + } + var chosenElements: any = []; + for (const child of childElements) { + if (!elementsWithSpan.includes(child)) { + chosenElements.push(child); + } + } + + if (chosenElements[0]) { + console.log("Last child element found"); + const firstSpan = await chosenElements[0].$('span:first-of-type'); + + + // Perform actions with the last child element if needed + // Example: Click the last child element + + if (firstSpan) { + const spanText = await firstSpan.textContent(); + //const spanText = "Face Sensing"; + await chosenElements[0].click(); + + const elementLocator = page.locator(`.blocklyFlyoutLabelText:has-text("${spanText}")`); + await elementLocator.waitFor(); + // await page.waitForFunction(() => { + // const elements = Array.from(document.querySelectorAll('[transform^="translate("]')); + // for (const element of elements) { + // const transformValue = (element as any).getAttribute('transform'); + // if (transformValue && transformValue.includes(',8688)')) { + // return true; + // } + // } + // return false; + // }); + await page.waitForTimeout(1000); + + const hatElements = await page.$$(`[data-category="${spanText}"][data-shapes="hat"]`); + const stackElements = await page.$$(`[data-category="${spanText}"][data-shapes="stack"]`); + const elements = await page.$$(`[data-category="${spanText}"]:not([data-shapes="stack"]):not([data-shapes="hat"])`); + + const viewport = page.viewportSize(); + console.log("viewport"); + console.log(viewport); + + let scrollMax = 0; + let stackMax = 0; + + if (hatElements.length > 0) { + let xOffset = 300; + let scroll = 0; + for (const hatElement of hatElements) { + await hatElement.scrollIntoViewIfNeeded(); + const hatBoundingBox = await hatElement.boundingBox(); + if (hatBoundingBox) { + // scroll back up if needed + let yOffset = 450; + if (scroll > 0) { + scroll = 0; + await page.mouse.move(500, 300); + await page.mouse.wheel(-1*scroll, 0); + } + // move the block + await page.mouse.move(hatBoundingBox.x + hatBoundingBox.width / 2, hatBoundingBox.y + hatBoundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(xOffset+hatBoundingBox.width/2, yOffset); + await page.mouse.up(); + // add to the offset + yOffset += hatBoundingBox.height * 0.8; + + // loop through stack elements + for (const stackElement of stackElements) { + await stackElement.scrollIntoViewIfNeeded(); + const stackBoundingBox = await stackElement.boundingBox(); + if (stackBoundingBox) { + await page.mouse.move(stackBoundingBox.x + stackBoundingBox.width / 2, stackBoundingBox.y + stackBoundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(xOffset+stackBoundingBox.width / 2, yOffset); + await page.mouse.up(); + // add to the offset + yOffset += stackBoundingBox.height * 0.8; + + if (yOffset > 500) { // if you need to scroll + scroll = scroll + wheelDelta; + if (scroll > scrollMax) { + scrollMax = scroll; // record the max scroll + } + yOffset -= wheelDelta; // take away from offset + if (yOffset > stackMax) { + stackMax = yOffset; + } + await page.mouse.move(500, 300); + await page.mouse.wheel(0, wheelDelta); + } else { + if (yOffset > stackMax) { + stackMax = yOffset; + } + } + } + } + xOffset = xOffset + 50; + // move back to the original position + if (scroll > 0) { + await page.mouse.move(500, 300); + await page.mouse.wheel(0, -1*scroll); + scroll = 0; + } + } else { + console.log("Failed to get bounding box for the hat element"); + } + } + + } else { + let yOffset = 450; + let scroll = 0; + let tempScroll = 0; + // make one stack of stack elements + for (const element of stackElements) { + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + tempScroll = 0; + } + const boundingBox1 = await element.boundingBox(); + // check if we have to scroll down to find the element + if (boundingBox1) { + let found = false; + + while (!found) { + try { + await element.hover({ timeout: 1000 }); + found = true; + console.log('Successfully hovered over the element.'); + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + + } + const boundingBox = await element.boundingBox(); + if (boundingBox) { + await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(400+boundingBox.width / 2, yOffset); + await page.mouse.up(); + + yOffset += boundingBox.height*0.8; + console.log("getting y offset ", yOffset); + if (yOffset > 500) { + scroll = scroll + boundingBox.height*0.8; + if (scroll > scrollMax) { + scrollMax = scroll; + } + + yOffset -= boundingBox.height*0.8; + if (yOffset > stackMax) { + console.log("new y offset ", yOffset); + stackMax = yOffset; + } + await page.mouse.move(500, 300); + await page.mouse.wheel(0, boundingBox.height*0.8); + } else { + if (yOffset > stackMax) { + stackMax = yOffset; + } + } + await page.waitForTimeout(1000); + } else { + console.log("Failed to get bounding box for the element"); + } + + } + //move the mouse back to the original scroll position + if (scroll > 0) { + await page.mouse.move(500, 300); + await page.mouse.wheel(0, -1*scroll); + scroll = 0; + } + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + tempScroll = 0; + } + } + // find where all the input elements are + const firstBlocklyBlockCanvas = await page.$('.blocklyBlockCanvas'); + const inputElements = firstBlocklyBlockCanvas + ? await firstBlocklyBlockCanvas.$$('.blocklyEditableText:not([data-argument-type="dropdown"]):not(:has(.blocklyDropdownText))') + : []; + + // Find out where we can place in the input elements in the stacks + var maxX = 400; + var maxY = stackMax; // stack max holds where the last position is with scroll + console.log("max y is", maxY); + var inputBoxes: any = []; + if (inputElements.length > 0) { + for (const element of inputElements) { + const boundingBox = await element.boundingBox(); + if (boundingBox) { + inputBoxes.push(boundingBox); + } + } + } else { + inputBoxes = [{ + x: 400, + y: stackMax, + width: 5, + height: 5 + }] + } + + let inputIndex = 0; + let inputOffset = 0; + let scrollDown = false; + + // Now loop through the rest of the elements + let tempScroll = 0; + for (const element of elements) { + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + tempScroll = 0; + } + const boundingBox1 = await element.boundingBox(); + // check if we have to scroll down to find the element + if (boundingBox1) { + let found = false; + let tempScroll = 0; + while (!found) { + try { + await element.hover({ timeout: 1000 }); + found = true; + console.log('Successfully hovered over the element.'); + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + + } + + const boundingBox = await element.boundingBox(); + if (boundingBox) { + var moveX; + var moveY; + let tempScroll2 = 0; + // If we still have input elements to go through + if (inputIndex >= inputBoxes.length) { + if (!scrollDown) { + await page.mouse.move(500, 300); + await page.mouse.wheel(0, scrollMax); + console.log("scrolled down by, ", scrollMax); + scrollDown = true; + } + inputOffset = inputOffset + boundingBox.height*0.8; + moveX = maxX; + moveY = maxY + inputOffset; + if (moveY > 500) { + await page.mouse.move(500, 300); + await page.mouse.wheel(0, wheelDelta); + inputOffset = inputOffset - wheelDelta; + moveY = moveY - wheelDelta; + } + } else { + moveX = inputBoxes[inputIndex].x + boundingBox.width / 2; + moveY = inputBoxes[inputIndex].y + if (moveY > 500) { + await page.mouse.move(500, 300); + tempScroll2 = moveY-500 + await page.mouse.wheel(0, tempScroll2); + maxY = maxY - tempScroll2; + } + } + + await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(moveX, moveY); + await page.mouse.up(); + console.log(`Element dragged to the same spot: ${await element.textContent()}`); + + console.log(moveX); + console.log(moveY); + inputIndex = inputIndex + 1; + await page.waitForTimeout(1000); + if (tempScroll2 > 0) { + await page.mouse.move(500, 300); + await page.mouse.wheel(0, -1*tempScroll2); + } + + // Increment the yOffset for the next element + } else { + console.log("Failed to get bounding box for the element"); + } + } + } else { + console.log("No span elements found within the last child element"); + } + } else { + console.log("No child elements found"); + } + } else { + console.log("Parent element not found"); + } + } + + // Save the project (if you want to) + const downloadPath = path.resolve(__dirname, 'downloads'); + await page.click('text=File'); + await page.click('text=Save to your computer'); + const [download] = await Promise.all([ + page.waitForEvent('download'), // Wait for the download to start + ]); + + // Save the download to the specified path + await download.saveAs(path.join(downloadPath, await download.suggestedFilename())); + console.log(`File downloaded to: ${path.join(downloadPath, await download.suggestedFilename())}`); + await page.waitForTimeout(5000); + + + // Close the browser + await browser.close(); +})(); diff --git a/extensions/integration_testing/playwright_save_all.ts b/extensions/integration_testing/playwright_save_all.ts new file mode 100644 index 000000000..e04244ce0 --- /dev/null +++ b/extensions/integration_testing/playwright_save_all.ts @@ -0,0 +1,165 @@ +import { chromium } from 'playwright'; +import { expect } from 'playwright/test'; +import * as path from 'path'; + +(async () => { + // Launch a browser instance + const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions + const context = await browser.newContext({ + permissions: ['camera'], + acceptDownloads: true + }); + const page = await context.newPage(); + await page.goto('http://localhost:8602/'); + + // All the extensions that have been included + const includedExtensions = [ + "PRG Microbit Robot", + "PRG Gizmo Robot", + "PRG Arduino Robot", + "Music", + "Pen", + "Video Sensing", + "Text to Speech", + "Translate", + "Makey Makey", + "micro:bit", + "LEGO MINDSTORMS EV3", + "LEGO BOOST", + "LEGO Education WeDo 2.0", + "Go Direct Force & Acceleration" + ]; + + // Declaring constants + const startX = 400; + const startY = 130; + + // Wait for the editor to load + await page.waitForSelector('.blocklyWorkspace'); + + // Add the extension + const addExtension = await page.$('[title="Add Extension"]'); + if (addExtension) { + await addExtension.click(); + const parentElement = await page.$('.library_library-scroll-grid_1jyXm.library_withFilterBar_26Opm'); + if (parentElement) { + const childElements = await parentElement.$$('.library-item_library-item_1DcMO.library-item_featured-item_3V2-t.library-item_library-item-extension_3xus9'); // Adjust the selector to match the child element type + const elementsWithSpan: any = []; + + // Collect the extensions that are already included + for (const child of childElements) { + const spanElement = await child.$('span:first-of-type'); + if (spanElement) { + const textContent = await child.textContent(); + if (includedExtensions.some(phrase => textContent?.includes(phrase))) { + elementsWithSpan.push(child); + } + } + } + // Find the extension that was added + var chosenElements: any = []; + for (const child of childElements) { + if (!elementsWithSpan.includes(child)) { + chosenElements.push(child); + } + } + + if (chosenElements[0]) { // The added extension + const firstSpan = await chosenElements[0].$('span:first-of-type'); + // Collect the title of the added extension + if (firstSpan) { + const spanText = await firstSpan.textContent(); + await chosenElements[0].click(); + const elementLocator = page.locator(`.blocklyFlyoutLabelText:has-text("${spanText}")`); + await elementLocator.waitFor(); + await page.waitForTimeout(1000); + // Find all the blocks under the added extension + const elements = await page.$$(`[data-category="${spanText}"]`); + + // Zoom all the way out + const blocklyZoomElement = await page.waitForSelector('.blocklyZoom', { timeout: 5000 }); + const boundingBox = await blocklyZoomElement.boundingBox(); + if (boundingBox) { + const x = boundingBox.x + boundingBox.width / 2; + const y = boundingBox.y + boundingBox.height / 2; + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + } + + // Starting values + let tempScroll = 0; + let yOffset = startY; + let xOffset = startX; + // Add each element + for (const element of elements) { + // Reset the scroll if needed + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + const boundingBox1 = await element.boundingBox(); + // Check if we have to scroll down to find the element + if (boundingBox1) { + let found = false; + while (!found) { + try { + await element.hover({ timeout: 100 }); + found = true; + await page.waitForTimeout(500); + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + } + + const boundingBox = await element.boundingBox(); + if (boundingBox) { + // Move the mouse to the center of the element + yOffset += 15; + await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); + await page.mouse.down(); + let x = xOffset + boundingBox.width / 2; + await page.mouse.move(x, yOffset); + await page.mouse.up(); + + // If we've gone all the way to the right, start again + xOffset = xOffset + 20; + if (xOffset > 600) { + xOffset = startX; + yOffset = yOffset - 30; + } + // Scroll if we've reached the bottom of the workspace + if (yOffset > 600) { + await page.mouse.move(500, 300); + await page.mouse.wheel(0, 10); + yOffset = yOffset - 15; + } + } + } + } + } + } + } + + // Save the project + const downloadPath = path.resolve(__dirname, 'downloads'); + await page.click('text=File'); + await page.click('text=Save to your computer'); + const [download] = await Promise.all([ + page.waitForEvent('download'), + ]); + + // Save the download to allBlocks.sb3 + await download.saveAs(path.join(downloadPath, "allBlocks.sb3")); + console.log(`File downloaded to: ${path.join(downloadPath, "allBlocks.sb3")}`); + await page.waitForTimeout(5000); + await browser.close(); +})(); diff --git a/extensions/integration_testing/playwright_save_combo.ts b/extensions/integration_testing/playwright_save_combo.ts new file mode 100644 index 000000000..5b34d63d9 --- /dev/null +++ b/extensions/integration_testing/playwright_save_combo.ts @@ -0,0 +1,349 @@ +import { chromium } from 'playwright'; +import { expect } from 'playwright/test'; +import * as path from 'path'; + +(async () => { + // Launch a browser instance + const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions + const context = await browser.newContext({ + permissions: ['camera'], + acceptDownloads: true + }); + const page = await context.newPage(); + await page.goto('http://localhost:8602/'); + + // All the extensions that are already there + const includedExtensions = [ + "PRG Microbit Robot", + "PRG Gizmo Robot", + "PRG Arduino Robot", + "Music", + "Pen", + "Video Sensing", + "Text to Speech", + "Translate", + "Makey Makey", + "micro:bit", + "LEGO MINDSTORMS EV3", + "LEGO BOOST", + "LEGO Education WeDo 2.0", + "Go Direct Force & Acceleration" + ]; + + + await page.waitForSelector('.blocklyWorkspace'); + + // Make sure no blocks are dragged out of the workspace + function boundY(y: any) { + if (y > 600) { + return 600; + } + return y; + } + + // Declaring constants + const startX = 400; + const startY = 130; + const scale = 0.35; + + // Add the extension + const addExtension = await page.$('[title="Add Extension"]'); + if (addExtension) { + await addExtension.click(); + const parentElement = await page.$('.library_library-scroll-grid_1jyXm.library_withFilterBar_26Opm'); + + if (parentElement) { + const childElements = await parentElement.$$('.library-item_library-item_1DcMO.library-item_featured-item_3V2-t.library-item_library-item-extension_3xus9'); // Adjust the selector to match the child element type + const elementsWithSpan: any = []; + // Collect all the elements that haven't been added + for (const child of childElements) { + const spanElement = await child.$('span:first-of-type'); + if (spanElement) { + const textContent = await child.textContent(); + if (includedExtensions.some(phrase => textContent?.includes(phrase))) { + elementsWithSpan.push(child); + } + } + } + // Now find the elements that HAVE been added + var chosenElements: any = []; + for (const child of childElements) { + if (!elementsWithSpan.includes(child)) { + chosenElements.push(child); + } + } + + // This element has been added + if (chosenElements[0]) { + // Collect the title of the added extension + const firstSpan = await chosenElements[0].$('span:first-of-type'); + if (firstSpan) { + const spanText = await firstSpan.textContent(); + await chosenElements[0].click(); + + const elementLocator = page.locator(`.blocklyFlyoutLabelText:has-text("${spanText}")`); + await elementLocator.waitFor(); + await page.waitForTimeout(1000); + + // Now collect the element types + const hatElements = await page.$$(`[data-category="${spanText}"][data-shapes="hat"]`); + const stackElements = await page.$$(`[data-category="${spanText}"][data-shapes="stack"]`); + const elements = await page.$$(`[data-category="${spanText}"]:not([data-shapes="stack"]):not([data-shapes="hat"])`); + + const blocklyZoomElement = await page.waitForSelector('.blocklyZoom', { timeout: 5000 }); + + // Zoom all the way out + const boundingBox = await blocklyZoomElement.boundingBox(); + if (boundingBox) { + const x = boundingBox.x + boundingBox.width / 2; + const y = boundingBox.y + boundingBox.height / 2; + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + await page.mouse.click(x, y); + } + + let stackMax = 0; + // If there are hat elements + if (hatElements.length > 0) { + let tempScroll = 0; + + let xOffset = startX; + for (const hatElement of hatElements) { + + let yOffset = startY; + + // Reset the scroll position + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + + // Check if we have to scroll down to find the element + const boundingBox1 = await hatElement.boundingBox(); + if (boundingBox1) { + let found = false; + while (!found) { + try { + await hatElement.hover({ timeout: 100 }); + found = true; + await page.waitForTimeout(500); + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + } + + // Move the hat element + const hatBoundingBox = await hatElement.boundingBox(); + if (hatBoundingBox) { + await page.mouse.move(hatBoundingBox.x + hatBoundingBox.width / 2, hatBoundingBox.y + hatBoundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(xOffset+hatBoundingBox.width/2, boundY(yOffset)); + await page.mouse.up(); + yOffset += hatBoundingBox.height * scale; + // Add each stack element underneath the hat element + for (const stackElement of stackElements) { + // Reset the scroll if needed + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + const boundingBox1 = await stackElement.boundingBox(); + // Check if we have to scroll down to find the element + if (boundingBox1) { + let found = false; + while (!found) { + try { + await stackElement.hover({ timeout: 100 }); + found = true; + await page.waitForTimeout(500); + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + + } + // Move the stack element under the hat element + const stackBoundingBox = await stackElement.boundingBox(); + if (stackBoundingBox) { + await page.mouse.move(stackBoundingBox.x + stackBoundingBox.width / 2, stackBoundingBox.y + stackBoundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(xOffset+stackBoundingBox.width / 2, boundY(yOffset)); + await page.mouse.up(); + // Set the max Y value for the remaining blocks + if (yOffset > stackMax) { + stackMax = yOffset; + } + yOffset += stackBoundingBox.height * scale; + } + } + // Move to the right for each stack + xOffset = xOffset + 50; + // Reset the scroll if needed + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + } + } + } else { + // If there are no hat elements, create one stack + let tempScroll = 0; + let yOffset = startY; + for (const element of stackElements) { + // Reset the scroll if needed + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + const boundingBox1 = await element.boundingBox(); + // Check if we have to scroll down to find the element + if (boundingBox1) { + let found = false; + while (!found) { + try { + await element.hover({ timeout: 100 }); + found = true; + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + } + const boundingBox = await element.boundingBox(); + // Move the stack element to the right + if (boundingBox) { + yOffset += boundingBox.height * scale; + await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); + await page.mouse.down(); + await page.mouse.move(startX+boundingBox.width / 2, boundY(yOffset)); + await page.mouse.up(); + // Set the max Y value for the remaining blocks + if (yOffset > stackMax) { + stackMax = yOffset; + } + } + } + // Reset the scroll if needed + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + } + + // Collect all the input elements + const firstBlocklyBlockCanvas = await page.$('.blocklyBlockCanvas'); + const inputElements = firstBlocklyBlockCanvas + ? await firstBlocklyBlockCanvas.$$('.blocklyEditableText:not([data-argument-type="dropdown"]):not(:has(.blocklyDropdownText))') + : []; + + // Set the starting y value for the input elements + var maxY = stackMax+5; + + // Store all the bounding boxes for the input elements + var inputBoxes: any = []; + if (inputElements.length > 0) { + for (const element of inputElements) { + const boundingBox = await element.boundingBox(); + if (boundingBox) { + inputBoxes.push(boundingBox); + } + } + } else { + inputBoxes = [{ + x: startX, + y: stackMax, + width: 5, + height: 5 + }] + } + + let inputIndex = 0; + let inputOffset = 0; + let tempScroll = 0; + + for (const element of elements) { + // Reset the scroll if needed + if (tempScroll > 0) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, -1*tempScroll); + await page.waitForTimeout(500); + tempScroll = 0; + } + // Check if we need to scroll down to find the block + const boundingBox1 = await element.boundingBox(); + if (boundingBox1) { + let found = false; + while (!found) { + try { + await element.hover({ timeout: 100 }); + found = true; + } catch (error) { + await page.mouse.move(100, 100); + await page.mouse.wheel(0, boundingBox1.height); + tempScroll = tempScroll + boundingBox1.height; + } + } + } + // Move the input element + const boundingBox = await element.boundingBox(); + if (boundingBox) { + await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); + await page.mouse.down(); + var moveX; + var moveY; + + if (inputIndex >= inputBoxes.length) { // If there are input boxes left to move to + inputOffset = inputOffset + boundingBox.height / 2; + moveX = startX + (boundingBox.width / 2); + moveY = maxY + inputOffset; + } else { // Otherwise, move below the stacks + moveX = inputBoxes[inputIndex].x + (boundingBox.width / 2); + moveY = inputBoxes[inputIndex].y + (boundingBox.height / 2); + } + + await page.mouse.move(moveX, boundY(moveY)); + await page.mouse.up(); + inputIndex = inputIndex + 1; + await page.waitForTimeout(1000); + + // Increment the yOffset for the next element + } + } + } + } + } + } + + // Save the project + const downloadPath = path.resolve(__dirname, 'downloads'); + await page.click('text=File'); + await page.click('text=Save to your computer'); + const [download] = await Promise.all([ + page.waitForEvent('download'), + ]); + + // Save the download to comboBlocks + await download.saveAs(path.join(downloadPath, "comboBlocks.sb3")); + console.log(`File downloaded to: ${path.join(downloadPath, "comboBlocks.sb3")}`); + await page.waitForTimeout(5000); + await browser.close(); +})(); diff --git a/extensions/integration_testing/test_fn.ts b/extensions/integration_testing/test_fn.ts new file mode 100644 index 000000000..e406a822f --- /dev/null +++ b/extensions/integration_testing/test_fn.ts @@ -0,0 +1,21 @@ +type InputTuple = [number, string]; +type OutputTuple = [number, string]; + +function transformFunction(func: (x: number, y: number) => number[]): (inputs: InputTuple[]) => OutputTuple[] { + return (inputs: InputTuple[]) => { + return inputs.map(([value, name]) => { + const [x, y] = func(value, value); + return name === "input1" ? [y, name] : [x, name]; + }); + }; +} + +// Example usage: +const originalFunction = (x: number, y: number) => [y * 2, x * 2]; +const inputTuples: InputTuple[] = [ + [5, "input1"], + [10, "input2"] +]; + +const transformedFunction = transformFunction(originalFunction); +console.log(transformedFunction(inputTuples)); // Output: [[20, "input2"], [10, "input1"]] From d90e9eacca09f02392b03ce1102bb4973301382b Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Fri, 7 Jun 2024 00:43:09 -0400 Subject: [PATCH 03/13] cleaning folder --- .../playwright_load_old.ts | 289 ------------- .../playwright_save copy.ts | 380 ------------------ extensions/integration_testing/test_fn.ts | 21 - 3 files changed, 690 deletions(-) delete mode 100644 extensions/integration_testing/playwright_load_old.ts delete mode 100644 extensions/integration_testing/playwright_save copy.ts delete mode 100644 extensions/integration_testing/test_fn.ts diff --git a/extensions/integration_testing/playwright_load_old.ts b/extensions/integration_testing/playwright_load_old.ts deleted file mode 100644 index 6b728baf2..000000000 --- a/extensions/integration_testing/playwright_load_old.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { chromium, Browser, BrowserContext, Page, ElementHandle } from 'playwright'; -import * as path from 'path'; - -(async () => { - // Launch a browser instance - const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions - const context = await browser.newContext({ - permissions: ['camera'], - acceptDownloads: true - }); - const page = await context.newPage(); - - // Navigate to 'Create' page - await page.goto('http://localhost:8602/'); - await page.click('text=File'); - //await page.click('text=Load from your computer'); - const [fileChooser] = await Promise.all([ - page.waitForEvent('filechooser'), - page.click('text=Load from your computer'), - ]); - - const filePath = path.resolve(__dirname, 'downloads', 'My Project.sb3'); - console.log(`Uploading file from: ${filePath}`); - - // Set the files to upload - await fileChooser.setFiles(filePath); - - page.on('dialog', async dialog => { - console.log(`Dialog message: ${dialog.message()}`); - if (dialog.message().includes("The project file that was selected failed to load.")) { - console.log("Invalid opcode found.") - console.log("TEST FAILED"); - } - // Optionally accept the dialog - await dialog.accept(); - }); - - let incompatibleTypes = false; - page.on('console', (message) => { - // Check if the message is an error - if (message.type() === 'error') { - // Check if the specific error message is logged - if (message.text().includes('gui Attempt to connect incompatible types.')) { - console.log("Incompatible function types detected.") - console.log("TEST FAILED"); - incompatibleTypes = true; - } - } - }); - await page.waitForSelector('.blocklyBlockCanvas'); - // Upload the file again for data-opcode to show up - await page.click('text=File'); - const [fileChooser2] = await Promise.all([ - page.waitForEvent('filechooser'), - page.click('text=Load from your computer'), - ]); - - await fileChooser2.setFiles(filePath); - await page.waitForSelector('.blocklyBlockCanvas'); - - - // Wait until blockly canvas has children - await page.$eval('.blocklyBlockCanvas', (element) => { - return element.children.length > 0; - }); - - const blocklyZoomElement = await page.waitForSelector('.blocklyZoom', { timeout: 5000 }); - const boundingBox = await blocklyZoomElement.boundingBox(); - if (boundingBox) { - // Calculate the middle of the element - const x = boundingBox.x + boundingBox.width / 2; - const y = boundingBox.y + boundingBox.height / 2; - - // Click the middle of the element - await page.mouse.click(x, y); - await page.mouse.click(x, y); - await page.mouse.click(x, y); - await page.mouse.click(x, y); - await page.mouse.click(x, y); - await page.mouse.click(x, y); - console.log('Successfully clicked in the middle of the blocklyZoom element.'); - } - - // WE WON'T NEED THIS except for defining the elements and removing priitive opcodes - var dataIds = await page.$eval('.blocklyBlockCanvas', (blockCanvas) => { - const elements = blockCanvas.querySelectorAll('[data-id]'); - const ids: any = []; - - const calculateDepth = (element: any) => { - let depth = 0; - let currentElement = element.parentElement; - while (currentElement) { - depth++; - currentElement = currentElement.parentElement; - } - return depth; - }; - - elements.forEach((element: any) => { - const opcode = element.getAttribute('data-opcode'); - if (opcode && opcode !== "math_number" && opcode !== "text" && !opcode.includes("_menu_")) { - const dataId = element.getAttribute('data-id'); - if (dataId) { - const shape = element.getAttribute('data-shapes'); - const opcode = element.getAttribute('data-opcode'); - const depth = calculateDepth(element); - ids.push({ id: dataId, shape, depth, opcode }); - } - } - }); - - // Sort the ids array based on depth in descending order - ids.sort((a: any, b: any) => b.depth - a.depth); - return ids; - }); - - // const seenOpcodes: any[] = []; - // for (const block of dataIds) { - // if (seenOpcodes.includes(block.opcode)) { - // console.log("HERE"); - // const elementHandle = await page.$(`[data-id="${block.id}"]`); - // const box = await elementHandle?.boundingBox(); - // if (box) { - // const x = box.x + box.width / 2; - // const y = box.y + box.height / 2; - // await page.mouse.click(x, y, { button: 'right' }); - // try { - // await page.click('text=Delete Block', { timeout: 500 }); - // } catch(e) { - - // } - // await page.waitForTimeout(500); - // } - - // } else { - // seenOpcodes.push(block.opcode); - // } - // } - - - const minDepthNode = dataIds.reduce((minObj: any, currentObj: any) => { - return currentObj.depth < minObj.depth ? currentObj : minObj; - }, dataIds[0]); - const minDepth = minDepthNode.depth; - - let moveX = 600; - let moveY = 100; - let alternate = false; - for (const dataId of dataIds) { - const elementHandle = await page.$(`[data-id="${dataId.id}"]`); - if (elementHandle && dataId.depth > minDepth) { - const box = await elementHandle.boundingBox(); - if (box) { - const startX = box.x + box.width / 2; - const startY = box.y + box.height / 2; - - - await page.mouse.move(startX, startY); - await page.mouse.down(); - await page.mouse.move(moveX, moveY); - await page.mouse.up(); - moveY = moveY + 20; - if (alternate) { - moveX = moveX + 20; - alternate = false; - } else { - moveX = moveX - 20; - alternate = true; - } - await page.waitForTimeout(1000); - } - } - } - // END WE WON'T NEED THIS - - var blocks = await page.$eval('.blocklyBlockCanvas', blockCanvas => { - const elements = blockCanvas.querySelectorAll('[data-id]'); - return Array.from(elements).map(element => { - const argumentElements = (element as any).querySelectorAll('[data-argument-type]'); - - const argumentList = Array.from(argumentElements).map(argElement => { - const argumentType = (argElement as any).getAttribute('data-argument-type'); - const transform = (argElement as any).getAttribute('transform'); - const match = transform.match(/translate\(([\d.]+),\s*([\d.]+)\)/); - let yValue = 0.0; - if (match && match.length > 1) { - yValue = parseFloat(match[1]); - } - return { - type: argumentType, - xValue: String(yValue) - } - }); - const filteredArgumentList = argumentList.filter((arg, index, self) => { - console.log(arg.type); - if (arg.type == 'round') { - const otherValueIncluded = self.some((otherArg: any, otherIndex: any) => otherIndex !== index && otherArg.xValue === arg.xValue); - if (!otherValueIncluded) { - console.log("New argument detected."); - console.log("TEST FAILED"); - return true; - } else { - return false; - } - } - return true; - }); - const sortedArgumentList = filteredArgumentList.sort((a: any, b: any) => a.xValue - b.xValue).map(element => element.type); - - return { - id: (element as any).getAttribute('data-id'), - arguments: sortedArgumentList, - opcode: (element as any).getAttribute('data-opcode'), - }; - }); - }); - - blocks = blocks.filter((block: any) => { - return block.opcode && block.opcode != "math_number" && block.opcode != "text" && !block.opcode.includes("_menu_"); - }) - - - function arraysMatch(arr1: string[], arr2: string[]): boolean { - if (arr1.length !== arr2.length) return false; - return arr1.every((value, index) => value === arr2[index]); - } - - - - for (const block of blocks) { - const selector = `[data-id="${block.opcode}"]`; - const elementHandle = await page.$(selector); - - if (elementHandle) { - const argumentElements = await elementHandle.$$('[data-argument-type]'); - - const argumentList = await Promise.all(argumentElements.map(async argHandle => { - const argumentType = await argHandle.getAttribute('data-argument-type'); - const transform = await argHandle.getAttribute('transform'); - let xValue = 0.0; - - if (transform) { - const match = transform.match(/translate\(([\d.]+),\s*([\d.]+)\)/); - if (match && match.length > 1) { - xValue = parseFloat(match[1]); // Adjusted to get the y value instead of x value - } - } - return { - type: argumentType, - xValue: xValue - }; - })); - const filteredArgumentList = argumentList.filter((arg, index, self) => { - if (arg.type == 'round') { - const otherValueIncluded = self.some((otherArg: any, otherIndex: any) => otherIndex !== index && otherArg.xValue === arg.xValue); - if (!otherValueIncluded) { - console.log("New argument detected.") - console.log("TEST FAILED"); - return true; - } else { - return false; - } - } - return true; - }); - const sortedArgumentList: any[] = filteredArgumentList.sort((a: any, b: any) => a.xValue - b.xValue).map(element => element.type); - if (!arraysMatch(block.arguments, sortedArgumentList)) { - - console.log(block.arguments); - console.log(sortedArgumentList); - console.log("Argument order does not match.") - console.log("TEST FAILED") - } - - - } - - } - - - - - - await page.waitForTimeout(20000); - - // Close the browser - await browser.close(); -})(); - \ No newline at end of file diff --git a/extensions/integration_testing/playwright_save copy.ts b/extensions/integration_testing/playwright_save copy.ts deleted file mode 100644 index e43adf9df..000000000 --- a/extensions/integration_testing/playwright_save copy.ts +++ /dev/null @@ -1,380 +0,0 @@ -import { chromium } from 'playwright'; -import { expect } from 'playwright/test'; -import * as path from 'path'; - -(async () => { - // Launch a browser instance - const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions - const context = await browser.newContext({ - permissions: ['camera'], - acceptDownloads: true - }); - const page = await context.newPage(); - - const wheelDelta = 20; - - // Navigate to 'Create' page - await page.goto('http://localhost:8602/'); - - const includedExtensions = [ - "PRG Microbit Robot", - "PRG Gizmo Robot", - "PRG Arduino Robot", - "Music", - "Pen", - "Video Sensing", - "Text to Speech", - "Translate", - "Makey Makey", - "micro:bit", - "LEGO MINDSTORMS EV3", - "LEGO BOOST", - "LEGO Education WeDo 2.0", - "Go Direct Force & Acceleration" - ]; - - // Wait for the editor to load - await page.waitForSelector('.blocklyWorkspace'); - - const addExtension = await page.$('[title="Add Extension"]'); - if (addExtension) { - await addExtension.click(); - const parentElement = await page.$('.library_library-scroll-grid_1jyXm.library_withFilterBar_26Opm'); - - if (parentElement) { - // Get the last child element of the parent element - // library-item_library-item_1DcMO - const childElements = await parentElement.$$('.library-item_library-item_1DcMO.library-item_featured-item_3V2-t.library-item_library-item-extension_3xus9'); // Adjust the selector to match the child element type - const elementsWithSpan: any = []; - - for (const child of childElements) { - const spanElement = await child.$('span:first-of-type'); - if (spanElement) { - const textContent = await child.textContent(); - if (includedExtensions.some(phrase => textContent?.includes(phrase))) { - elementsWithSpan.push(child); - } - } - } - var chosenElements: any = []; - for (const child of childElements) { - if (!elementsWithSpan.includes(child)) { - chosenElements.push(child); - } - } - - if (chosenElements[0]) { - console.log("Last child element found"); - const firstSpan = await chosenElements[0].$('span:first-of-type'); - - - // Perform actions with the last child element if needed - // Example: Click the last child element - - if (firstSpan) { - const spanText = await firstSpan.textContent(); - //const spanText = "Face Sensing"; - await chosenElements[0].click(); - - const elementLocator = page.locator(`.blocklyFlyoutLabelText:has-text("${spanText}")`); - await elementLocator.waitFor(); - // await page.waitForFunction(() => { - // const elements = Array.from(document.querySelectorAll('[transform^="translate("]')); - // for (const element of elements) { - // const transformValue = (element as any).getAttribute('transform'); - // if (transformValue && transformValue.includes(',8688)')) { - // return true; - // } - // } - // return false; - // }); - await page.waitForTimeout(1000); - - const hatElements = await page.$$(`[data-category="${spanText}"][data-shapes="hat"]`); - const stackElements = await page.$$(`[data-category="${spanText}"][data-shapes="stack"]`); - const elements = await page.$$(`[data-category="${spanText}"]:not([data-shapes="stack"]):not([data-shapes="hat"])`); - - const viewport = page.viewportSize(); - console.log("viewport"); - console.log(viewport); - - let scrollMax = 0; - let stackMax = 0; - - if (hatElements.length > 0) { - let xOffset = 300; - let scroll = 0; - for (const hatElement of hatElements) { - await hatElement.scrollIntoViewIfNeeded(); - const hatBoundingBox = await hatElement.boundingBox(); - if (hatBoundingBox) { - // scroll back up if needed - let yOffset = 450; - if (scroll > 0) { - scroll = 0; - await page.mouse.move(500, 300); - await page.mouse.wheel(-1*scroll, 0); - } - // move the block - await page.mouse.move(hatBoundingBox.x + hatBoundingBox.width / 2, hatBoundingBox.y + hatBoundingBox.height / 2); - await page.mouse.down(); - await page.mouse.move(xOffset+hatBoundingBox.width/2, yOffset); - await page.mouse.up(); - // add to the offset - yOffset += hatBoundingBox.height * 0.8; - - // loop through stack elements - for (const stackElement of stackElements) { - await stackElement.scrollIntoViewIfNeeded(); - const stackBoundingBox = await stackElement.boundingBox(); - if (stackBoundingBox) { - await page.mouse.move(stackBoundingBox.x + stackBoundingBox.width / 2, stackBoundingBox.y + stackBoundingBox.height / 2); - await page.mouse.down(); - await page.mouse.move(xOffset+stackBoundingBox.width / 2, yOffset); - await page.mouse.up(); - // add to the offset - yOffset += stackBoundingBox.height * 0.8; - - if (yOffset > 500) { // if you need to scroll - scroll = scroll + wheelDelta; - if (scroll > scrollMax) { - scrollMax = scroll; // record the max scroll - } - yOffset -= wheelDelta; // take away from offset - if (yOffset > stackMax) { - stackMax = yOffset; - } - await page.mouse.move(500, 300); - await page.mouse.wheel(0, wheelDelta); - } else { - if (yOffset > stackMax) { - stackMax = yOffset; - } - } - } - } - xOffset = xOffset + 50; - // move back to the original position - if (scroll > 0) { - await page.mouse.move(500, 300); - await page.mouse.wheel(0, -1*scroll); - scroll = 0; - } - } else { - console.log("Failed to get bounding box for the hat element"); - } - } - - } else { - let yOffset = 450; - let scroll = 0; - let tempScroll = 0; - // make one stack of stack elements - for (const element of stackElements) { - if (tempScroll > 0) { - await page.mouse.move(100, 100); - await page.mouse.wheel(0, -1*tempScroll); - tempScroll = 0; - } - const boundingBox1 = await element.boundingBox(); - // check if we have to scroll down to find the element - if (boundingBox1) { - let found = false; - - while (!found) { - try { - await element.hover({ timeout: 1000 }); - found = true; - console.log('Successfully hovered over the element.'); - } catch (error) { - await page.mouse.move(100, 100); - await page.mouse.wheel(0, boundingBox1.height); - tempScroll = tempScroll + boundingBox1.height; - } - } - - } - const boundingBox = await element.boundingBox(); - if (boundingBox) { - await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); - await page.mouse.down(); - await page.mouse.move(400+boundingBox.width / 2, yOffset); - await page.mouse.up(); - - yOffset += boundingBox.height*0.8; - console.log("getting y offset ", yOffset); - if (yOffset > 500) { - scroll = scroll + boundingBox.height*0.8; - if (scroll > scrollMax) { - scrollMax = scroll; - } - - yOffset -= boundingBox.height*0.8; - if (yOffset > stackMax) { - console.log("new y offset ", yOffset); - stackMax = yOffset; - } - await page.mouse.move(500, 300); - await page.mouse.wheel(0, boundingBox.height*0.8); - } else { - if (yOffset > stackMax) { - stackMax = yOffset; - } - } - await page.waitForTimeout(1000); - } else { - console.log("Failed to get bounding box for the element"); - } - - } - //move the mouse back to the original scroll position - if (scroll > 0) { - await page.mouse.move(500, 300); - await page.mouse.wheel(0, -1*scroll); - scroll = 0; - } - if (tempScroll > 0) { - await page.mouse.move(100, 100); - await page.mouse.wheel(0, -1*tempScroll); - tempScroll = 0; - } - } - // find where all the input elements are - const firstBlocklyBlockCanvas = await page.$('.blocklyBlockCanvas'); - const inputElements = firstBlocklyBlockCanvas - ? await firstBlocklyBlockCanvas.$$('.blocklyEditableText:not([data-argument-type="dropdown"]):not(:has(.blocklyDropdownText))') - : []; - - // Find out where we can place in the input elements in the stacks - var maxX = 400; - var maxY = stackMax; // stack max holds where the last position is with scroll - console.log("max y is", maxY); - var inputBoxes: any = []; - if (inputElements.length > 0) { - for (const element of inputElements) { - const boundingBox = await element.boundingBox(); - if (boundingBox) { - inputBoxes.push(boundingBox); - } - } - } else { - inputBoxes = [{ - x: 400, - y: stackMax, - width: 5, - height: 5 - }] - } - - let inputIndex = 0; - let inputOffset = 0; - let scrollDown = false; - - // Now loop through the rest of the elements - let tempScroll = 0; - for (const element of elements) { - if (tempScroll > 0) { - await page.mouse.move(100, 100); - await page.mouse.wheel(0, -1*tempScroll); - tempScroll = 0; - } - const boundingBox1 = await element.boundingBox(); - // check if we have to scroll down to find the element - if (boundingBox1) { - let found = false; - let tempScroll = 0; - while (!found) { - try { - await element.hover({ timeout: 1000 }); - found = true; - console.log('Successfully hovered over the element.'); - } catch (error) { - await page.mouse.move(100, 100); - await page.mouse.wheel(0, boundingBox1.height); - tempScroll = tempScroll + boundingBox1.height; - } - } - - } - - const boundingBox = await element.boundingBox(); - if (boundingBox) { - var moveX; - var moveY; - let tempScroll2 = 0; - // If we still have input elements to go through - if (inputIndex >= inputBoxes.length) { - if (!scrollDown) { - await page.mouse.move(500, 300); - await page.mouse.wheel(0, scrollMax); - console.log("scrolled down by, ", scrollMax); - scrollDown = true; - } - inputOffset = inputOffset + boundingBox.height*0.8; - moveX = maxX; - moveY = maxY + inputOffset; - if (moveY > 500) { - await page.mouse.move(500, 300); - await page.mouse.wheel(0, wheelDelta); - inputOffset = inputOffset - wheelDelta; - moveY = moveY - wheelDelta; - } - } else { - moveX = inputBoxes[inputIndex].x + boundingBox.width / 2; - moveY = inputBoxes[inputIndex].y - if (moveY > 500) { - await page.mouse.move(500, 300); - tempScroll2 = moveY-500 - await page.mouse.wheel(0, tempScroll2); - maxY = maxY - tempScroll2; - } - } - - await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); - await page.mouse.down(); - await page.mouse.move(moveX, moveY); - await page.mouse.up(); - console.log(`Element dragged to the same spot: ${await element.textContent()}`); - - console.log(moveX); - console.log(moveY); - inputIndex = inputIndex + 1; - await page.waitForTimeout(1000); - if (tempScroll2 > 0) { - await page.mouse.move(500, 300); - await page.mouse.wheel(0, -1*tempScroll2); - } - - // Increment the yOffset for the next element - } else { - console.log("Failed to get bounding box for the element"); - } - } - } else { - console.log("No span elements found within the last child element"); - } - } else { - console.log("No child elements found"); - } - } else { - console.log("Parent element not found"); - } - } - - // Save the project (if you want to) - const downloadPath = path.resolve(__dirname, 'downloads'); - await page.click('text=File'); - await page.click('text=Save to your computer'); - const [download] = await Promise.all([ - page.waitForEvent('download'), // Wait for the download to start - ]); - - // Save the download to the specified path - await download.saveAs(path.join(downloadPath, await download.suggestedFilename())); - console.log(`File downloaded to: ${path.join(downloadPath, await download.suggestedFilename())}`); - await page.waitForTimeout(5000); - - - // Close the browser - await browser.close(); -})(); diff --git a/extensions/integration_testing/test_fn.ts b/extensions/integration_testing/test_fn.ts deleted file mode 100644 index e406a822f..000000000 --- a/extensions/integration_testing/test_fn.ts +++ /dev/null @@ -1,21 +0,0 @@ -type InputTuple = [number, string]; -type OutputTuple = [number, string]; - -function transformFunction(func: (x: number, y: number) => number[]): (inputs: InputTuple[]) => OutputTuple[] { - return (inputs: InputTuple[]) => { - return inputs.map(([value, name]) => { - const [x, y] = func(value, value); - return name === "input1" ? [y, name] : [x, name]; - }); - }; -} - -// Example usage: -const originalFunction = (x: number, y: number) => [y * 2, x * 2]; -const inputTuples: InputTuple[] = [ - [5, "input1"], - [10, "input2"] -]; - -const transformedFunction = transformFunction(originalFunction); -console.log(transformedFunction(inputTuples)); // Output: [[20, "input2"], [10, "input1"]] From 1a8bfe400bc7c1f9b73e3528b2cf371dc84d544e Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Mon, 10 Jun 2024 14:00:36 -0400 Subject: [PATCH 04/13] script improvements --- .../playwright_save_all.ts | 3 +- .../playwright_save_combo.ts | 31 +++++-------------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/extensions/integration_testing/playwright_save_all.ts b/extensions/integration_testing/playwright_save_all.ts index e04244ce0..cafaa5245 100644 --- a/extensions/integration_testing/playwright_save_all.ts +++ b/extensions/integration_testing/playwright_save_all.ts @@ -123,7 +123,7 @@ import * as path from 'path'; const boundingBox = await element.boundingBox(); if (boundingBox) { // Move the mouse to the center of the element - yOffset += 15; + yOffset += 20; await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); await page.mouse.down(); let x = xOffset + boundingBox.width / 2; @@ -134,7 +134,6 @@ import * as path from 'path'; xOffset = xOffset + 20; if (xOffset > 600) { xOffset = startX; - yOffset = yOffset - 30; } // Scroll if we've reached the bottom of the workspace if (yOffset > 600) { diff --git a/extensions/integration_testing/playwright_save_combo.ts b/extensions/integration_testing/playwright_save_combo.ts index 5b34d63d9..2c0375065 100644 --- a/extensions/integration_testing/playwright_save_combo.ts +++ b/extensions/integration_testing/playwright_save_combo.ts @@ -258,24 +258,6 @@ import * as path from 'path'; // Set the starting y value for the input elements var maxY = stackMax+5; - // Store all the bounding boxes for the input elements - var inputBoxes: any = []; - if (inputElements.length > 0) { - for (const element of inputElements) { - const boundingBox = await element.boundingBox(); - if (boundingBox) { - inputBoxes.push(boundingBox); - } - } - } else { - inputBoxes = [{ - x: startX, - y: stackMax, - width: 5, - height: 5 - }] - } - let inputIndex = 0; let inputOffset = 0; let tempScroll = 0; @@ -308,16 +290,19 @@ import * as path from 'path'; if (boundingBox) { await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2); await page.mouse.down(); - var moveX; - var moveY; + var moveX: any; + var moveY: any; - if (inputIndex >= inputBoxes.length) { // If there are input boxes left to move to + if (inputIndex >= inputElements.length) { // If there are input boxes left to move to inputOffset = inputOffset + boundingBox.height / 2; moveX = startX + (boundingBox.width / 2); moveY = maxY + inputOffset; } else { // Otherwise, move below the stacks - moveX = inputBoxes[inputIndex].x + (boundingBox.width / 2); - moveY = inputBoxes[inputIndex].y + (boundingBox.height / 2); + const inputBoundingBox = await inputElements[inputIndex].boundingBox(); + if (inputBoundingBox) { + moveX = inputBoundingBox.x + (boundingBox.width / 2); + moveY = inputBoundingBox.y + (boundingBox.height / 2); + } } await page.mouse.move(moveX, boundY(moveY)); From d70573ce5068e95fd8f427803774c251abbe23a7 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Sun, 16 Jun 2024 22:53:29 -0400 Subject: [PATCH 05/13] types --- extensions/src/common/types/framework/blocks.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extensions/src/common/types/framework/blocks.ts b/extensions/src/common/types/framework/blocks.ts index c9ec87169..7b07b6c22 100644 --- a/extensions/src/common/types/framework/blocks.ts +++ b/extensions/src/common/types/framework/blocks.ts @@ -16,8 +16,15 @@ export type BlockMetadata< }; export type ArgTransformer = (...args: any[]) => any[]; + +export type BlockOptions = { + transform?: ArgTransformer; + type?: { [key: string]: string }; + name?: { [key: string]: string }; +}; + export type Config = { - [index: number]: ArgTransformer; + [index: number]: ArgTransformer | BlockOptions; }; export type Block = BlockMetadata & Operation; From 49140d74bf72ea884026af6d87d2dd11787d41e2 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Sun, 16 Jun 2024 23:22:42 -0400 Subject: [PATCH 06/13] adding node script --- extensions/integration_testing/node_script.ts | 84 +++++++++++++++++++ .../integration_testing/playwright_load.ts | 21 ++++- .../playwright_save_all.ts | 18 +++- .../playwright_save_combo.ts | 3 +- 4 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 extensions/integration_testing/node_script.ts diff --git a/extensions/integration_testing/node_script.ts b/extensions/integration_testing/node_script.ts new file mode 100644 index 000000000..d5c2fc130 --- /dev/null +++ b/extensions/integration_testing/node_script.ts @@ -0,0 +1,84 @@ +const { exec } = require('child_process'); + +let devProcess: any; + +async function runDevScript(param: string): Promise { + return new Promise((resolve, reject) => { + devProcess = exec(`cd ../.. && pnpm dev -i ${param}`, (error: any, stdout: any, stderr: any) => { + if (error) { + console.error(`Error running dev script: ${error}`); + reject(error); + } else { + console.log(`Dev script output: ${stdout}`); + resolve(); + } + }); + + devProcess.stdout.on('data', (data: any) => { + console.log(`stdout: ${data}`); + }); + + devProcess.stderr.on('data', (data: any) => { + console.error(`stderr: ${data}`); + }); + }); + } + + async function runPlaywrightScript(scriptName: string) { + return new Promise((resolve, reject) => { + const command = `npx ts-node ${scriptName}`; + const playwrightProcess = exec(command, (error: any, stdout: any, stderr: any) => { + if (error) { + console.error(`Error running script: ${error.message}`); + reject(error); + } + if (stderr) { + console.error(`Error output: ${stderr}`); + reject(stderr); + } + console.log(`Script output: ${stdout}`); + resolve(stdout); + }); + + playwrightProcess.stdout.on('data', (data: any) => { + console.log(`stdout: ${data}`); + }); + + playwrightProcess.stderr.on('data', (data: any) => { + console.error(`stderr: ${data}`); + }); + }); +} + + +async function runPlaywrightTasks() { + try { + await runPlaywrightScript('playwright_save_all.ts'); + await runPlaywrightScript('playwright_save_combo.ts'); + await runPlaywrightScript('playwright_load.ts'); + devProcess.kill(); + } catch (error) { + console.error('Error during Playwright tasks:', error); + } + } + +async function main() { + const args = process.argv.slice(2); + + if (args.length === 0) { + console.error('Please provide a parameter.'); + return; + } + + const param = args[0]; + + try { + runDevScript(param); + console.log('Dev script started successfully'); + runPlaywrightTasks(); + } catch (error) { + console.error('Error running script:', error); + } + } + + main(); diff --git a/extensions/integration_testing/playwright_load.ts b/extensions/integration_testing/playwright_load.ts index 851111737..dd09b1bac 100644 --- a/extensions/integration_testing/playwright_load.ts +++ b/extensions/integration_testing/playwright_load.ts @@ -1,6 +1,8 @@ import { chromium, Browser, BrowserContext, Page, ElementHandle } from 'playwright'; import * as path from 'path'; +const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + (async () => { // Launch a browser instance const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions @@ -11,6 +13,19 @@ import * as path from 'path'; const page = await context.newPage(); // Navigate to 'Create' page + + // Try connecting to the server in a loop with delay +// let connected = false; +// for (let i = 0; i < 120; i++) { // Retry up to 10 times +// try { +// await page.goto('http://localhost:8602/', { waitUntil: 'networkidle', timeout: 6000 }); +// connected = true; +// break; +// } catch (e) { +// console.log('Connection failed, retrying...'); +// await delay(5000); // Wait for 5 seconds before retrying +// } +// } await page.goto('http://localhost:8602/'); await page.click('text=File'); @@ -51,7 +66,8 @@ import * as path from 'path'; } }); - await page.waitForSelector('.blocklyBlockCanvas'); + //await page.waitForSelector('.blocklyBlockCanvas', { timeout: 120000 }); + await page.waitForTimeout(2000); await page.click('text=File'); const [fileChooser2] = await Promise.all([ page.waitForEvent('filechooser'), @@ -59,7 +75,8 @@ import * as path from 'path'; ]); await fileChooser2.setFiles(filePath); - await page.waitForSelector('.blocklyBlockCanvas'); + //await page.waitForSelector('.blocklyBlockCanvas', { timeout: 120000 }); + await page.waitForTimeout(2000); // Wait until blockly canvas has children diff --git a/extensions/integration_testing/playwright_save_all.ts b/extensions/integration_testing/playwright_save_all.ts index cafaa5245..2dcdb5280 100644 --- a/extensions/integration_testing/playwright_save_all.ts +++ b/extensions/integration_testing/playwright_save_all.ts @@ -2,6 +2,8 @@ import { chromium } from 'playwright'; import { expect } from 'playwright/test'; import * as path from 'path'; +const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + (async () => { // Launch a browser instance const browser = await chromium.launch({ headless: false }); // Set headless: false to see the browser actions @@ -10,7 +12,17 @@ import * as path from 'path'; acceptDownloads: true }); const page = await context.newPage(); - await page.goto('http://localhost:8602/'); + let connected = false; + for (let i = 0; i < 120; i++) { // Retry up to 10 times + try { + await page.goto('http://localhost:8602/', { waitUntil: 'networkidle', timeout: 6000 }); + connected = true; + break; + } catch (e) { + console.log('Connection failed, retrying...'); + await delay(5000); // Wait for 5 seconds before retrying + } + } // All the extensions that have been included const includedExtensions = [ @@ -35,8 +47,8 @@ import * as path from 'path'; const startY = 130; // Wait for the editor to load - await page.waitForSelector('.blocklyWorkspace'); - + //await page.waitForSelector('.blocklyBlockCanvas'); + await page.waitForTimeout(2000); // Add the extension const addExtension = await page.$('[title="Add Extension"]'); if (addExtension) { diff --git a/extensions/integration_testing/playwright_save_combo.ts b/extensions/integration_testing/playwright_save_combo.ts index 2c0375065..0df824b89 100644 --- a/extensions/integration_testing/playwright_save_combo.ts +++ b/extensions/integration_testing/playwright_save_combo.ts @@ -31,7 +31,8 @@ import * as path from 'path'; ]; - await page.waitForSelector('.blocklyWorkspace'); + //await page.waitForSelector('.blocklyWorkspace'); + await page.waitForTimeout(2000); // Make sure no blocks are dragged out of the workspace function boundY(y: any) { From 1fc46dcc3669faef52fea61628568048040cc3e3 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Sun, 16 Jun 2024 23:33:25 -0400 Subject: [PATCH 07/13] clean up and exit --- extensions/integration_testing/node_script.ts | 2 +- extensions/integration_testing/playwright_load.ts | 14 -------------- .../integration_testing/playwright_save_all.ts | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/extensions/integration_testing/node_script.ts b/extensions/integration_testing/node_script.ts index d5c2fc130..4971158c7 100644 --- a/extensions/integration_testing/node_script.ts +++ b/extensions/integration_testing/node_script.ts @@ -56,7 +56,7 @@ async function runPlaywrightTasks() { await runPlaywrightScript('playwright_save_all.ts'); await runPlaywrightScript('playwright_save_combo.ts'); await runPlaywrightScript('playwright_load.ts'); - devProcess.kill(); + process.exit(0); } catch (error) { console.error('Error during Playwright tasks:', error); } diff --git a/extensions/integration_testing/playwright_load.ts b/extensions/integration_testing/playwright_load.ts index dd09b1bac..6656391be 100644 --- a/extensions/integration_testing/playwright_load.ts +++ b/extensions/integration_testing/playwright_load.ts @@ -12,20 +12,6 @@ const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); }); const page = await context.newPage(); - // Navigate to 'Create' page - - // Try connecting to the server in a loop with delay -// let connected = false; -// for (let i = 0; i < 120; i++) { // Retry up to 10 times -// try { -// await page.goto('http://localhost:8602/', { waitUntil: 'networkidle', timeout: 6000 }); -// connected = true; -// break; -// } catch (e) { -// console.log('Connection failed, retrying...'); -// await delay(5000); // Wait for 5 seconds before retrying -// } -// } await page.goto('http://localhost:8602/'); await page.click('text=File'); diff --git a/extensions/integration_testing/playwright_save_all.ts b/extensions/integration_testing/playwright_save_all.ts index 2dcdb5280..a5057f228 100644 --- a/extensions/integration_testing/playwright_save_all.ts +++ b/extensions/integration_testing/playwright_save_all.ts @@ -48,7 +48,7 @@ const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); // Wait for the editor to load //await page.waitForSelector('.blocklyBlockCanvas'); - await page.waitForTimeout(2000); + await page.waitForTimeout(3000); // Add the extension const addExtension = await page.$('[title="Add Extension"]'); if (addExtension) { From 05d1e774611109559b20a7819209df350f1e01f4 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Mon, 17 Jun 2024 21:29:27 -0400 Subject: [PATCH 08/13] saving downloads for reference --- .../downloads/allBlocks.sb3 | Bin 121323 -> 122243 bytes .../downloads/comboBlocks.sb3 | Bin 121352 -> 122525 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/extensions/integration_testing/downloads/allBlocks.sb3 b/extensions/integration_testing/downloads/allBlocks.sb3 index 1119335785d13422fb41c1012149e8990c2b2880..8ac598478a35a1f5fdad80447b6927b561988805 100644 GIT binary patch delta 2572 zcmY+Gc{J1u8^`B|Lf4kDMb^U0*cy?2XvkjK_iR~`jAba?{4nAovW-cTNFjwRWx|Xs zrBNnhpTQVe!VOtMmdRV4_q_Mq=dbVc`JU&T=g-fVMovsCCwS4Co#O}u0^x#?<@#Oe z+>UB%ToA~`QxFKxPZ}PH3JLH>tA#|N!j?U*I!s$Zf560E9yzL!A79rbw3eD7SK4q@ zR^L)Vz!rW=R84troLK~Etu=oyGe7i&^C{x4&F6s&+nSn&hTnTrs9#Gpe2x(MZVL|~ zX(l$Z-%b>O0iFvvL4lry0dZ79Y2XR_?V_DnaJ3FbbR|4X5z*P`cE(wQS!%AjynBSE<8P7KLXX# zdV&x$+Je{(C(0VUX=6vO%PvG)9OYpXD&$?Sl{gLxB>B|I@!NEr*2yKPoq?IzD(?^lK2CpAwNHUQakQROoZt{L_S;{&!+W(oIYNHL$>Nb8Zt{-hN zc(&DRn|jrq)K8;7Z85$O5H-18JuKhyeeU-D*;NUv?|-LDl6 zEZW&Gi_pM`G*%NEVsSC%9W^SO@4swqc?HPp*@VrNjn^M#uB30MYJUZL2TW736&v=m z7OcFMxEl=_{dG^HN%x$`LK(}7c8thq>3)Hk*B(Q2J&x=KReYq+ZOwzas`@VX+$N)I zePQ{*tSD8^vH8ni@p!V!8N}Jx0DnW~>p4njF5}g1;GfCl^%U|EG0K7_z~i_0gwi*? z-P&FB7L{;55+S?2>j4JFM|~w9{IE}VAJI@(B zk9GLSod}J}@M+L>_~dxHV#8yZGQKZ6}=>`(P!n{TOM2orOD&?R%3s z!)opC80n&BHNZR)&v zgp{uMI%iZ#Xcf$nO-|pi&cQSHs?1OcCol!??$^De7ud%^g0gB4}w6hUS5`wd<_6#=z~ z5^fM8t@(!Jq!IZ=NSr??uSrpKz?XUa{=hL#l2w7KMumOJ$H-i{%SBB3*i+ef&u~2-{>A>%VS=*v|#8`7bMVhLcBQt z0peBB&}Fk(Tf2f>nQ%dFLhea0SR7?+ISV)rkDkew9xjg7ckb>4zJlUc1(!zB=;_Hz5{#vx#&x9A!j%mJEQC7 zklTAiSxDXvcY4rsHW@pwbBxHg)9)(HtYeD<#a-84?xI?QShxRfL^W=pk(d#-oCJ*;Qw*m`v~RMZ7_l|@YwCIKSjsD+Ut*WTD1(P z?i>J#pU;6t5$wG=5B6mZS=*(O4|`CZGfQb%b(}Xb$Fkf{SEW{1a@-5Ji!}?*@^Gm$ zfuc|EeU^FpNfRnlX|5^9Qxdds+L{(c&dd?rFm?=1tvjm?*2GJAV}Q4EDLqe} zDQzuQhQeq{_Bkz2D(@+^Hzm;u&)A#YxgC#r;Q-T{5RBFBv#$EK81X2w(3U>JZY3$p z0#J{wyrlJmGhLJTF6`DKp}QlGxjVii{v}I|Ifu|}>_4pu!^uV95GHtyf)6cw1@A&?7V5Xi}&BKOY_2LYT3 R6_Cdb(*c3QMdQHF>c2F~-g5u| delta 1697 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 Date: Mon, 24 Jun 2024 00:01:44 -0400 Subject: [PATCH 09/13] template documentation --- extensions/src/.templates/default.ts | 19 ++++++++----------- extensions/src/common/templateDocs.ts | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/extensions/src/.templates/default.ts b/extensions/src/.templates/default.ts index 5ef20010a..0ef976460 100644 --- a/extensions/src/.templates/default.ts +++ b/extensions/src/.templates/default.ts @@ -1,4 +1,4 @@ -import { ArgumentType, BlockType, Environment, ExtensionMenuDisplayDetails, extension, block } from "$common"; +import { ArgumentType, BlockType, Environment, ExtensionMenuDisplayDetails, extension, block, scratch } from "$common"; import BlockUtility from "$scratch-vm/engine/block-utility"; /** 👋 Hi! @@ -44,20 +44,16 @@ export default class ExtensionNameGoesHere extends extension(details) { exampleField: number; /** @see {ExplanationOfReporterBlock} */ - @block({ type: "reporter", text: "This increments an internal field and then reports it's value" }) + @(scratch.reporter`This increments an internal field and then reports it's value`) exampleReporter() { return ++this.exampleField; } - + /** @see {ExplanationOfCommandBlock} */ - @block((self) => ({ - /** @see {ExplanationOfBlockType} */ - type: BlockType.Command, - /** @see {ExplanationOfBlockTextFunction} */ - text: (exampleString, exampleNumber) => `This is the block's display text with inputs here --> ${exampleString} and here --> ${exampleNumber}`, - /** @see {ExplanationOfBlockArgs} */ - args: [ArgumentType.String, { type: ArgumentType.Number, defaultValue: self.exampleField }], - })) + @scratch.command( + (instance, $) => + $`This is the block's display text with inputs here --> ${"string"} and here --> ${{type: "number", defaultValue: instance.exampleField}}` + ) exampleCommand(exampleString: string, exampleNumber: number) { alert(`This is a command! Here's what it received: ${exampleString} and ${exampleNumber}`); // Replace with what the block should do! } @@ -65,6 +61,7 @@ export default class ExtensionNameGoesHere extends extension(details) { /** @see {ExplanationOfHatBlock} */ /** @see {ExplanationOfBlockUtility} */ @block({ + /** @see {ExplanationOfBlockType} */ type: "hat", text: (condition) => `Should the below block execute: ${condition}`, /** @see {ExplanationOfBlockArg} */ diff --git a/extensions/src/common/templateDocs.ts b/extensions/src/common/templateDocs.ts index a4284d250..b3864d7c9 100644 --- a/extensions/src/common/templateDocs.ts +++ b/extensions/src/common/templateDocs.ts @@ -107,32 +107,33 @@ type ExplanationOfInitMethod = Documentation; * Hover over `exampleReporter` below to observe it's type signature and that it returns a `number` * (which is _inferred_ by Typescript, but you could also be [explicitly stated](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#return-type-annotations)). * - * As described in the definiton of Block above (hover over it if you need a refresher), we turn the `exampleReporter` method into a method tied to a Block by "decorating" it with the `block` decorator function + * As described in the definiton of Block above (hover over it if you need a refresher), we turn the `exampleReporter` method into a method tied to a Block by "decorating" it with the `scratch.reporter` decorator function * (the use of the `@` tell us that it is a [decorator](https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators)). * - * As mentioned above, the `block` function takes a single argument as input, which provides all the necessary information - * for the Block Programming Environment to create a Block tied to our method. + * In this scenario, `scratch.reporter` serves as a [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). This means we can use the passed-in [Template String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to provide + * all the necessary information for the Block Programming Environment to create a Reporter Block + * tied to our method, with input fields at the positions of the templated arguments. * - * In this case, all we need is the block type (`type`) and the display text of the block (`text`). */ type ExplanationOfReporterBlock = Documentation; /** - * Below, we define a method `exampleCommand` and decorate it with the `@block` function (similiar to above). + * Below, we define a method `exampleCommand` and decorate it with the `@scratch.command` function (similiar to above). * This is an example of a "command" block, as the underlying method takes 0 or more arguments, and returns nothing ([void](https://www.typescriptlang.org/docs/handbook/basic-types.html#void)). * * Hover over `exampleCommand` below to observe it's type signature and how it returns `void`. * - * **NOTE:** Here, instead of passing an object to the `@block` decorator function (as above), we pass another function to it. - * This function must take a single parameter, which will be a reference to our specific Extension (hover over `self` if you don't believe me). + * **NOTE:** Here, instead of using a tagged template literal (as above), we pass another function to the `scratch` decorator. + * This function takes two parameters, the first of which is a reference to our specific Extension. * As you can see in the definition of the `defaultValue` of our second argument, * this allows us to pull values off of our extension when defining our block. + * The second argument references the tagged template literal we use to create the text and arguments of the block. */ type ExplanationOfCommandBlock = Documentation; /** - * We can either use the string to define our blockType, like above, - * or refernce a specific entry on the `BlockType` object, like below. + * We can either use `scratch.reporter` or `scratch.command` to define a Reporter or Command block, like above, + * or reference a specific entry on the `BlockType` object, like below. * * Make sure to hover over the `type` field to get more comprehensive documentation. */ From 1baaa47c6451b1cee93c1231a4acf61807dfe57c Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Tue, 25 Jun 2024 00:08:55 -0400 Subject: [PATCH 10/13] changing extension READMEs --- .../documentation/src/anatomy/README.md | 6 ++-- .../documentation/src/blockUtility/index.ts | 8 ++--- .../src/customArguments/README.md | 10 +++--- .../src/customArguments/index.ts | 35 ++++++++----------- .../documentation/src/inlineImages/README.md | 2 +- .../documentation/src/inlineImages/index.ts | 27 +++++++------- .../documentation/src/porting/README.md | 4 +-- .../documentation/src/porting/example.ts | 26 +++++--------- .../documentation/src/reference/README.md | 2 +- extensions/documentation/src/testing/index.ts | 16 +++------ .../documentation/src/tutorial/README.md | 20 ++++------- .../documentation/src/tutorial/complete.ts | 8 ++--- .../documentation/src/tutorial/index.ts | 20 +++-------- extensions/documentation/src/ui/README.md | 4 +-- extensions/documentation/src/ui/index.ts | 13 ++----- extensions/src/appinventor_example/index.ts | 8 ++--- 16 files changed, 74 insertions(+), 135 deletions(-) diff --git a/extensions/documentation/src/anatomy/README.md b/extensions/documentation/src/anatomy/README.md index d08b3377c..90a674d05 100644 --- a/extensions/documentation/src/anatomy/README.md +++ b/extensions/documentation/src/anatomy/README.md @@ -3,7 +3,7 @@ Extensions are defined by all the files that appear in their associated directory, located within `/extensions/src/`. -This directory is created when you run the command `npm run new:extension ` from the root of the project, where the value you provide for `` is used to name this new directory. +This directory is created when you run the command `pnpm new:extension ` from the root of the project, where the value you provide for `` is used to name this new directory. > **NOTE:** It is important to keep in mind that the name of an extension's associated directory is internally used to identify it, so it is best to avoid changing the directory's name (as this could affect previously saved `.sb3` projects that reference the extension). @@ -24,11 +24,11 @@ Below are the files you should always find within an extension's directory: - For example, if your extension folder is `myExtension`, you can do the following: ``` cd extensions/myExtension # only do this once - npm run dev + pnpm dev ``` - Instead of running the following from the root of the project every time: ``` - npm run dev -- --include myExtension + pnpm dev -i myExtension ``` - Inspect the `package.json` file to see all augmented scripts. diff --git a/extensions/documentation/src/blockUtility/index.ts b/extensions/documentation/src/blockUtility/index.ts index b815a9819..6bc171c56 100644 --- a/extensions/documentation/src/blockUtility/index.ts +++ b/extensions/documentation/src/blockUtility/index.ts @@ -1,13 +1,9 @@ -import { BlockUtilityWithID, Environment, block, extension } from "$common"; +import { BlockUtilityWithID, Environment, extension, scratch } from "$common"; export default class extends extension({ name: "Block Utility example" }) { override init(env: Environment) { } - @block({ - type: "command", - text: (someArgument) => `Block text with ${someArgument}`, - arg: "number" - }) + @(scratch.command`Block text with ${"number"}`) exampleBlockMethod(someArgument: number, util: BlockUtilityWithID) { const { blockID } = util; console.log(`My ID is: ${blockID}`) diff --git a/extensions/documentation/src/customArguments/README.md b/extensions/documentation/src/customArguments/README.md index c929034e4..7d3b77d18 100644 --- a/extensions/documentation/src/customArguments/README.md +++ b/extensions/documentation/src/customArguments/README.md @@ -6,7 +6,7 @@ One of the coolest is the ability to define custom arguments, which means both: - Introducing an arbitrary new type of argument - It could be an alias for a `number` the same way the built-in `Angle` argument is. Or it could be something new entirely, like an object with some specific keys, or an array of a certain length -- whatever you want! - Defining the UI the allows a user to set / interact with that argument type - - Imagine being able to create argument-specifc UI like is done for the built-in `Note`, `Angle`, `Color`, and `Matrix` arguments + - Imagine being able to create argument-specific UI like is done for the built-in `Note`, `Angle`, `Color`, and `Matrix` arguments Here's how: @@ -17,7 +17,7 @@ For a quick breakdown of how we handle UI generally in the Extension Framework, Then run the following command: ```bash -npm run add:arg +pnpm add:arg # For example: npm run add:arg myExtension ``` @@ -31,7 +31,7 @@ Assume we have the following extension: [](./extension.ts?export=x) -When invoking the `@block` decorator function on our method that uses a custom argument, we can define the `arg` field like so: +When invoking the `@scratch` decorator function on our method that uses a custom argument, we can define the placeholder like so (note the use of the `instance` parameter in invoking the `makeCustomArgument` function): [](./index.ts?export=x) @@ -63,10 +63,10 @@ At the heart of this implementation is co-opting the usage of block argument's d > In the extension framework, an argument with a dynamic menu looks like: >```ts ->arg: { +>@(scratch.command`placholder text ${{ > type: "number", > options: () => ["option A", "option B"] // for example ->} +>}}`) >``` This is the perfect setup for our solution, as: diff --git a/extensions/documentation/src/customArguments/index.ts b/extensions/documentation/src/customArguments/index.ts index d9a3cfde0..474f28649 100644 --- a/extensions/documentation/src/customArguments/index.ts +++ b/extensions/documentation/src/customArguments/index.ts @@ -1,5 +1,5 @@ import { codeSnippet, notRelevantToExample } from "documentation"; -import { block, extension } from "$common"; +import { extension, scratch } from "$common"; import { MyCustomArgument, details } from "./extension"; export const x = codeSnippet(); @@ -10,25 +10,20 @@ import MyArgUI from "./MyArgUI.svelte"; export default class ExtensionWithCustomArgument extends extension(details, "customArguments") { init = notRelevantToExample; - @block((self) => ({ - type: "command", - text: (arg) => `Set custom argument ${arg}`, - - /** Invoke the member function `makeCustomArgument` of `self` parameter - * (which is an instance of our `ExtensionWithCustomArgument` class). - * The `makeCustomArgument` function accepts an object with the following fields: - * - component: The `svelte` component that should be displayed when this argument is clicked on. - * - initial: The value that the argument should default to. NOTE that this item has both a 'text' and 'value' field. - * - This is because the value of the custom argument must be able to be represented as a string - * and displayed directly in the block once the UI closes. - * Thus, whenever you set a custom argument, you'll need to provide both a 'value' and a 'text' - * representation of that value. - */ - arg: self.makeCustomArgument({ - component: MyArgUI, - initial: { value: { a: 10, b: "Hello world", c: false }, text: "[10, Hello world, false]", } - }), - })) + /** Invoke the member function `makeCustomArgument` of `self` parameter + * (which is an instance of our `ExtensionWithCustomArgument` class). + * The `makeCustomArgument` function accepts an object with the following fields: + * - component: The `svelte` component that should be displayed when this argument is clicked on. + * - initial: The value that the argument should default to. NOTE that this item has both a 'text' and 'value' field. + * - This is because the value of the custom argument must be able to be represented as a string + * and displayed directly in the block once the UI closes. + * Thus, whenever you set a custom argument, you'll need to provide both a 'value' and a 'text' + * representation of that value. + */ + @(scratch.command((instance, $) => $`Set custom argument ${instance.makeCustomArgument({ + component: MyArgUI, + initial: { value: { a: 10, b: "Hello world", c: false }, text: "[10, Hello world, false]", } + })}`)) /** Our operation should expect an input that matches our custom argument type */ blockWithCustomArgument(custom: MyCustomArgument) { const { a, b, c } = custom; diff --git a/extensions/documentation/src/inlineImages/README.md b/extensions/documentation/src/inlineImages/README.md index bd66a13e4..e660bc4e1 100644 --- a/extensions/documentation/src/inlineImages/README.md +++ b/extensions/documentation/src/inlineImages/README.md @@ -2,7 +2,7 @@ As noted in [Scratch's extension documentation](https://github.com/scratchfoundation/scratch-vm/blob/develop/docs/extensions.md#adding-an-inline-image), Blocks support arguments that can display images inline within their text display. -We can make use of this feature within the framework by adding an extra argument of type `"inline image"` to our extension's method, and then seperately add an `arg` (or `args`) entry within the associated `@block` decorator invocation. +We can make use of this feature within the framework by adding an extra argument of type `"inline image"` to our extension's method, and then seperately add a placeholder within the associated `@scratch` decorator invocation. See the below example (which assumes that a file `myPic.png` is located in the same directory as our code): diff --git a/extensions/documentation/src/inlineImages/index.ts b/extensions/documentation/src/inlineImages/index.ts index 47ee5095b..86d7c1910 100644 --- a/extensions/documentation/src/inlineImages/index.ts +++ b/extensions/documentation/src/inlineImages/index.ts @@ -2,7 +2,7 @@ import { codeSnippet } from "documentation"; export const x = codeSnippet(); -import { Environment, block, extension } from "$common"; +import { Environment, extension, scratch } from "$common"; // We import our image as if it was a code file import myPic from "./myPic.png"; @@ -11,29 +11,26 @@ export default class ExampleExtensionWithInlineImages extends extension({ }) { override init(env: Environment) { } - @block({ - type: "command", - text: (image) => `Here's an inline image: ${image}`, - arg: { + @(scratch.command`Here's an inline image: ${ + { type: "image", uri: myPic, alt: "this is a test image", // description of the image for screen readers flipRTL: true, } - }) + }`) methodWithOnlyInlineImage(image: "inline image") { // NOTE: The `image` argument should not be used } - @block({ - type: "command", - text: (someNumber, image, someString) => `Here's a number ${someNumber} and picture ${image} and string ${someString}}`, - args: [ - { type: "number" }, - { type: "image", uri: myPic, alt: "this is a test image", flipRTL: true }, - "string" - ] - }) + @(scratch.command`Here's a number ${{ type: "number" }} and picture ${ + { + type: "image", + uri: myPic, + alt: "this is a test image", + flipRTL: true + } + } and string ${"string"}}`) methodWithInlineImageAndOtherArguments(someNumber: number, image: "inline image", someString: string) { // NOTE: The `image` argument should not be used } diff --git a/extensions/documentation/src/porting/README.md b/extensions/documentation/src/porting/README.md index 9b9877fda..503c00f92 100644 --- a/extensions/documentation/src/porting/README.md +++ b/extensions/documentation/src/porting/README.md @@ -19,7 +19,7 @@ Here's how: 2. Create your "new" framework-based extension using the command outlined in [Making an Extension](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main#-making-an-extension) and use the ***Extension ID*** you found in step 1 as the value of `` - For example, if your "old" extension's ***Extension ID*** is `prgRocks` you'll run the following command: ```bash - npm run new:extension prgRocks + pnpm new:extension prgRocks ``` - The reason this is necessary is two-fold: First, in the new extension framework, the name of the folder that contains an extension is automatically used as its ***Extension ID***. Second, because already saved `.sb3` / Scratch projects that use your extension refernce the specific ***Extension ID***, we need to make sure our updated, typescript-based extension has the same ID. 3. Once you have created an extension with a folder name matching the ***Extension ID*** found in step 1, you can actually delete the corresponding entry inside of the `builtinExtensions` object of [scratch-packages/scratch-vm/src/extension-support/extension-manager.js](https://github.com/mitmedialab/prg-extension-boilerplate/blob/main/scratch-packages/scratch-vm/src/extension-support/extension-manager.js) @@ -32,7 +32,7 @@ Here's how: - You can do this as the extension framework will automatically handle adding your extension (and its Extension Menu Display Details) to the [Extension Menu](https://en.scratch-wiki.info/wiki/Extension#Adding_Extensions) 6. Now you can start coding! See the below comparison of a vanilla JS extension class and a typescript / framework based one. - NOTE: If there's a chance anyone has saved projects with the extension you're porting over, you need to make sure to follow the [Legacy Support](#legacy-support) instructions so those saved projects will continue to load correctly. -7. Once you have migrated all of the "old" ***Impementation*** to your new extension folder & typescript code, you can go ahead and delete the ***Implementation*** folder inside of [pacakges/scratch-vm/src/extensions/](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-vm/src/extensions). +7. Once you have migrated all of the "old" ***Impementation*** to your new extension folder & typescript code, you can go ahead and delete the ***Implementation*** folder inside of [scratch-packages/scratch-vm/src/extensions/](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-vm/src/extensions). 8. Now, there should be no remnants of the "old" extension inside of either [scratch-packages/scratch-vm](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-vm) or [scratch-packages/scratch-gui](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-gui) folders, and instead everything lives neatly inside its own directory within [extensions/src](https://github.com/mitmedialab/prg-extension-boilerplate/tree/dev/extensions/src) 9. Test out the project you saved in step 0 to verify that your port worked as expected. diff --git a/extensions/documentation/src/porting/example.ts b/extensions/documentation/src/porting/example.ts index 5d03cdc2d..1398b10da 100644 --- a/extensions/documentation/src/porting/example.ts +++ b/extensions/documentation/src/porting/example.ts @@ -1,4 +1,4 @@ -import { ArgumentType, BlockType, Environment, block, extension } from "$common"; +import { ArgumentType, BlockType, Environment, extension, scratch } from "$common"; import BlockUtility from "$root/scratch-packages/scratch-vm/src/engine/block-utility"; import formatMessage from './format-message'; // This should actually be an npm package and thus be 'format-message' @@ -13,22 +13,14 @@ export default class SomeBlocks extends extension(details) { init(env: Environment) { } - @block({ - type: BlockType.Reporter, - args: [ - { - type: ArgumentType.String, - defaultValue: 'text', - options: [ - { text: 'Item One', value: 'itemId1' }, - 'itemId2' - ] - }, - { type: ArgumentType.Number, defaultValue: 1 } - ], - text: (text, letterNum) => `letter ${letterNum} of ${text}'`, - }) - myReporter(text: string, letterNum: number, util: BlockUtility) { + @(scratch.reporter`letter ${ + { + type: "string", + defaultValue: 'text', + options: [{ text: 'Item One', value: 'itemId1' },'itemId2'] + } + } of ${{ type: "number", defaultValue: 1 }}`) + myReporter(text: string, letterNum: number) { const message = formatMessage({ id: 'myReporter.result', default: 'Letter {letterNum} of {text} is {result}.', diff --git a/extensions/documentation/src/reference/README.md b/extensions/documentation/src/reference/README.md index b5809c2fc..604f7963e 100644 --- a/extensions/documentation/src/reference/README.md +++ b/extensions/documentation/src/reference/README.md @@ -8,7 +8,7 @@ sequenceDiagram participant B as /scratch-packages/scratch-gui/ participant C as /scratch-packages/scratch-vm/ Note over root,C: INITIALIZATION - C-->>B: Lerna utility forces scratch-gui
to use /scratch-packages/scratch-vm for its dependency
instead of using the external npm package + C-->>B: PNPM tells scratch-gui
to use /scratch-packages/scratch-vm for its dependency
instead of using the external npm package Note over root,C: BUILD Note over root: /scripts/build.ts activate root diff --git a/extensions/documentation/src/testing/index.ts b/extensions/documentation/src/testing/index.ts index 957e79a11..5f0e54904 100644 --- a/extensions/documentation/src/testing/index.ts +++ b/extensions/documentation/src/testing/index.ts @@ -3,7 +3,7 @@ import { codeSnippet } from "../../"; export const defineExtension = codeSnippet(); -import { block, buttonBlock, extension, Environment } from "$common"; +import { extension, Environment, scratch } from "$common"; const name = "Extension Under Test"; @@ -11,23 +11,15 @@ export default class ExtensionUnderTest extends extension({ name }, "ui") { init(env: Environment): void { } - @block({ - type: "command", - args: ["number", "number"], - text: (x, y) => "placeholder", - }) + @(scratch.command`placeholder: ${"number"} and ${"number"}`) exampleCommand(a: number, b: number) { /* Do something */ } - @block({ - type: "reporter", - text: (x) => "placeholder", - arg: "string", - }) + @(scratch.reporter`placeholder: ${"string"}`) exampleReporter(input: string) { return "Whatever you expect to be the output, given the input" } - @buttonBlock("placeholder") + @(scratch.button`placeholder`) exampleButtonThatOpensUI() { this.openUI("Test"); } diff --git a/extensions/documentation/src/tutorial/README.md b/extensions/documentation/src/tutorial/README.md index fd7e2961d..4545da159 100644 --- a/extensions/documentation/src/tutorial/README.md +++ b/extensions/documentation/src/tutorial/README.md @@ -5,7 +5,7 @@ Below is our starter piece of code, where we import the following items from the `$common` package: - `extension`: A factory function that returns a base class that our extension should [extend](https://www.typescriptlang.org/docs/handbook/2/classes.html#extends-clauses). This function allows for you to configure the capability of your Extension (as you'll see [later](#configuring-your-extensions-functionality)). -- `block`: A [method decorator](https://www.typescriptlang.org/docs/handbook/decorators.html#:~:text=Method%20Decorators,or%20replace%20a%20method%20definition.) function that will be [used below](#decorating-our-method-with-block) to mark our class method as something that should be turned into a Block. The argument provided to the `block` function contains all the information necessary to create a Block representation of our method in the Block Programming Environment. +- `scratch`: An object with two [method decorator](https://www.typescriptlang.org/docs/handbook/decorators.html#:~:text=Method%20Decorators,or%20replace%20a%20method%20definition.) functions -- `scratch.reporter`, `scratch.command`, `scratch.hat`, and `scratch.button` -- that will be [used below](#decorating-our-method-with-block) to mark our class method as something that should be turned into either a Reporter or Command Block. The [template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) argument provided to the `scratch` functions contains all the information necessary to create a Block representation of our method in the Block Programming Environment. - `ExtensionMenuDisplayDetails`: A type imported to add typesafety to how we define the `details` object which we use when configuring our Extension's base class through the `extension` function. As the name suggests, the contents of this object determine how our Extension displays to the user, especially through the [Extensions Menu](https://en.scratch-wiki.info/wiki/Library#Extensions_Library). - `Environment`: A type imported to add typesafety to the argument of the `init` function (which all Extensions are required to implement -- it is used in place of a [constructor](https://www.typescriptlang.org/docs/handbook/2/classes.html#constructors)) @@ -29,17 +29,15 @@ Next, let's define a [method](https://www.typescriptlang.org/docs/handbook/2/cla [](./index.ts?export=method) -### Decorating our method with `block` +### Decorating our method with `scratch` -In order for this method to become a Block in the Block Programming Environment, we need to mark it (or [decorate](https://www.typescriptlang.org/docs/handbook/decorators.html#:~:text=Method%20Decorators,or%20replace%20a%20method%20definition.) it) with the `block` function. +In order for this method to become a Block in the Block Programming Environment, we need to mark it (or [decorate](https://www.typescriptlang.org/docs/handbook/decorators.html#:~:text=Method%20Decorators,or%20replace%20a%20method%20definition.) it) with the `scratch` functions (for example, `scratch.reporter`). [](./index.ts?export=blockify) -> **NOTE:** We preceed in the invocation of `block` with an `@` symbol which signifies the `block` function is [decorating](https://www.typescriptlang.org/docs/handbook/decorators.html#introduction) our method. +> **NOTE:** We preceed in the invocation of `scratch` with an `@` symbol which signifies the `scratch` function is [decorating](https://www.typescriptlang.org/docs/handbook/decorators.html#introduction) our method. -The argument that `block` takes provides all the information the Block Programming Environment needs in order to create a Block tied to your method. - -Your code editor and typescript will help ensure you provide all the necessary information, as well as give you a sense of the choices you have when defining this information. Make sure to hover over the fields of the object argument (i.g. `type`, `text`, `arg`, and/or `args`) to see thorough documentation on what those fields are and what values they can take on. +The template literal that the `scratch` decorator takes provides all the information the Block Programming Environment needs in order to create a Block tied to your method (i.g. the block's type, text, and args). #### Need to access properties of your Extension when define a Block?

@@ -47,13 +45,9 @@ Your code editor and typescript will help ensure you provide all the necessary i Open this -If you need to access some information on your extension when invoking `block`, you can do so by passing a function (instead of an object) as an argument. - -This function will accept one argument, which will be a reference to your Extension (the name `self` is used as a convention). You can then pull values off of it (like `defaultValue` below) when defining your return object. The returned object is the same type as the object argument of the `block` function. - -[](./index.ts?export=functionArg) +If you need to access some information on your extension when invoking `scratch` decorators, you can do so by passing a function (instead of an object) as an argument. -> **NOTE:** As you can see above, we need to make use of the `as const` [const assertion](https://dev.to/typescripttv/best-practices-with-const-assertions-in-typescript-4l10#:~:text=TypeScript%203.4%20introduced%20const%20assertions,pushed%20into%20an%20existing%20array.) when specifying the `args` field. This is only necessary because we are using a string value to define the `type` of our Arguments. Without `as const`, when typescript infers the return type of our function, it thinks our Arguments' `type`s are simply [strings](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#the-primitives-string-number-and-boolean), which causes errors since a `string` is not a valid Argument type. By using `as const`, we ensure it infers our Argument types as [literals](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types). +This function will accept two arguments: the first is a reference to your Extension, and the second is a tagged template literal you can use to define your block, just like the previous `scratch` functions. You can then pull values off of the Extension reference (like `defaultValue` below) in the placeholders of the template literal. [](./index.ts?export=functionArg) diff --git a/extensions/documentation/src/tutorial/complete.ts b/extensions/documentation/src/tutorial/complete.ts index 34ac1c2c7..9289c9a0f 100644 --- a/extensions/documentation/src/tutorial/complete.ts +++ b/extensions/documentation/src/tutorial/complete.ts @@ -1,4 +1,4 @@ -import { extension, block, type ExtensionMenuDisplayDetails, type Environment } from "$common"; +import { extension, type ExtensionMenuDisplayDetails, type Environment, scratch } from "$common"; const details: ExtensionMenuDisplayDetails = { name: "An Exciting Extension", @@ -11,11 +11,7 @@ const BaseClass = extension(details, "ui"); export default class Example extends BaseClass { init(env: Environment): void { } - @block({ - type: "command", - text: (name, age) => `What's your ${name} and ${age}?`, - args: [{ type: "string", defaultValue: "name" }, "number"] - }) + @(scratch.command`What's your ${{ type: "string", defaultValue: "name" }} and ${"number"}?`) someMethodToBlockify(name: string, age: number) { this.openUI("someComponent"); } diff --git a/extensions/documentation/src/tutorial/index.ts b/extensions/documentation/src/tutorial/index.ts index 8f3da355c..3f7567691 100644 --- a/extensions/documentation/src/tutorial/index.ts +++ b/extensions/documentation/src/tutorial/index.ts @@ -2,7 +2,7 @@ import { codeSnippet } from "documentation"; export const base = codeSnippet(); -import { extension, block, type ExtensionMenuDisplayDetails, type Environment } from "$common"; +import { extension, type ExtensionMenuDisplayDetails, type Environment, scratch } from "$common"; const details: ExtensionMenuDisplayDetails = { name: "" }; @@ -55,11 +55,7 @@ export const blockify = codeSnippet(); { class Example extends BaseClass { init(env: Environment): void { } - @block({ - type: "command", - text: (name, age) => `What's your ${name} and ${age}?`, - args: [{ type: "string", defaultValue: "name" }, "number"] - }) + @(scratch.command`What's your ${{ type: "string", defaultValue: "name" }} and ${"number"}?`) someMethodToBlockify(name: string, age: number) { console.log(`Hello, ${name}! ${age} is the new ${Math.random() * age * 2}`); } @@ -76,11 +72,7 @@ export const functionArg = codeSnippet(); { class Example extends _BaseClass { defaultValue = ""; - @block((self) => ({ - type: "command", - text: (name, age) => `What's your ${name} and ${age}?`, - args: [{ type: "string", defaultValue: self.defaultValue }, "number"] as const - })) + @(scratch.command((instance, $) => $`What's your ${{ type: "string", defaultValue: instance.defaultValue }} and ${"number"}?`)) someMethodToBlockify(name: string, age: number) { // ... functionArg.end; } @@ -96,11 +88,7 @@ export const ui = codeSnippet(); { class Example extends BaseClass { init(env: Environment): void { } - @block({ - type: "command", - text: (name, age) => `What's your ${name} and ${age}?`, - args: [{ type: "string", defaultValue: "name" }, "number"] - }) + @(scratch.command`What's your ${{ type: "string", defaultValue: "name" }} and ${"number"}?`) someMethodToBlockify(name: string, age: number) { this.openUI("someComponent"); } diff --git a/extensions/documentation/src/ui/README.md b/extensions/documentation/src/ui/README.md index d991705df..49773a515 100644 --- a/extensions/documentation/src/ui/README.md +++ b/extensions/documentation/src/ui/README.md @@ -10,7 +10,7 @@ Please first make sure you've satisfied [Svelte Dependency](https://github.com/m To generate a new svelte file, run the following command from the root of the project: ```bash -npm run add:ui +pnpm add:ui # For example: npm run add:ui myExtension ``` @@ -34,7 +34,7 @@ The first argument of the `openUI` method is the name of the `.svelte` file in w The second argument is the title that will display at the top of the modal window. If omitted, this will default to the name of your extension. -Below are two examples of declaring buttons (one using the standard `@block` decorator, and the other using the `@buttonBlock` decorator short-hand): +Here is an example of how to declare a button block: [](./index.ts?export=x) diff --git a/extensions/documentation/src/ui/index.ts b/extensions/documentation/src/ui/index.ts index ba256a5bb..2246a8826 100644 --- a/extensions/documentation/src/ui/index.ts +++ b/extensions/documentation/src/ui/index.ts @@ -4,23 +4,16 @@ const name = ""; export const x = codeSnippet(); -import { block, buttonBlock, extension } from "$common"; +import { extension, scratch } from "$common"; export default class ExampleExtension extends extension({ name }, "ui") { init = notRelevantToExample; - @block({ - type: "button", - text: `Button Text Goes Here` - }) - verboseButton() { + @(scratch.button`Button Text Goes Here`) + buttonBlock() { this.openUI("SvelteFileName", "Title of Window"); } - @buttonBlock(`Button Text Goes Here`) - shortHandButton() { - this.openUI("SvelteFileName", "Title of Window"); - } } x.end; \ No newline at end of file diff --git a/extensions/src/appinventor_example/index.ts b/extensions/src/appinventor_example/index.ts index 38db52e19..a9b2ee1d2 100644 --- a/extensions/src/appinventor_example/index.ts +++ b/extensions/src/appinventor_example/index.ts @@ -1,4 +1,4 @@ -import { Environment, extension, block, getterBlock, PropertyBlockDetails, setterBlock, Matrix } from "$common"; +import { Environment, extension, getterBlock, PropertyBlockDetails, setterBlock, Matrix, scratch } from "$common"; const heightProperty: PropertyBlockDetails = { name: "Height", type: "number" }; @@ -18,11 +18,7 @@ export default class extends extension({ name: "App Inventor Example", tags: ["P this.field = value; } - @block({ - text: (x, y, z) => `${x} ${y} ${z}`, - args: ["number", "string", "matrix"], - type: "reporter" - }) + @(scratch.reporter`${"number"} ${"string"} ${"matrix"}`) dummy(x: number, y: string, z: Matrix): number { return 0; } From 161645b24f0cca380bf6a4fac0c39434789e1f22 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Tue, 25 Jun 2024 00:27:35 -0400 Subject: [PATCH 11/13] changing template, docs, adding hat --- extensions/src/.templates/default.ts | 16 +++---- .../extension/decorators/taggedTemplate.ts | 1 + extensions/src/common/templateDocs.ts | 45 ++++++------------- 3 files changed, 21 insertions(+), 41 deletions(-) diff --git a/extensions/src/.templates/default.ts b/extensions/src/.templates/default.ts index 0ef976460..b5a453b66 100644 --- a/extensions/src/.templates/default.ts +++ b/extensions/src/.templates/default.ts @@ -1,4 +1,4 @@ -import { ArgumentType, BlockType, Environment, ExtensionMenuDisplayDetails, extension, block, scratch } from "$common"; +import { ArgumentType, BlockType, Environment, ExtensionMenuDisplayDetails, extension, scratch } from "$common"; import BlockUtility from "$scratch-vm/engine/block-utility"; /** 👋 Hi! @@ -43,6 +43,7 @@ export default class ExtensionNameGoesHere extends extension(details) { /** @see {ExplanationOfField} */ exampleField: number; + /** @see {ExplanationOfBlockType} */ /** @see {ExplanationOfReporterBlock} */ @(scratch.reporter`This increments an internal field and then reports it's value`) exampleReporter() { @@ -50,23 +51,18 @@ export default class ExtensionNameGoesHere extends extension(details) { } /** @see {ExplanationOfCommandBlock} */ - @scratch.command( + @(scratch.command( (instance, $) => + /** @see {ExplanationOfBlockArg} */ $`This is the block's display text with inputs here --> ${"string"} and here --> ${{type: "number", defaultValue: instance.exampleField}}` - ) + )) exampleCommand(exampleString: string, exampleNumber: number) { alert(`This is a command! Here's what it received: ${exampleString} and ${exampleNumber}`); // Replace with what the block should do! } /** @see {ExplanationOfHatBlock} */ + @(scratch.hat`Should the below block execute: ${"Boolean"}`) /** @see {ExplanationOfBlockUtility} */ - @block({ - /** @see {ExplanationOfBlockType} */ - type: "hat", - text: (condition) => `Should the below block execute: ${condition}`, - /** @see {ExplanationOfBlockArg} */ - arg: "Boolean" - }) async exampleHat(condition: boolean, util: BlockUtility) { return util.stackFrame.isLoop === condition; } diff --git a/extensions/src/common/extension/decorators/taggedTemplate.ts b/extensions/src/common/extension/decorators/taggedTemplate.ts index 7d896a44f..748e323fc 100644 --- a/extensions/src/common/extension/decorators/taggedTemplate.ts +++ b/extensions/src/common/extension/decorators/taggedTemplate.ts @@ -83,4 +83,5 @@ export const scratch = { reporter: makeDecorator("reporter"), command: makeDecorator("command"), button: makeDecorator("button"), + hat: makeDecorator("hat") } \ No newline at end of file diff --git a/extensions/src/common/templateDocs.ts b/extensions/src/common/templateDocs.ts index b3864d7c9..e469d6d8d 100644 --- a/extensions/src/common/templateDocs.ts +++ b/extensions/src/common/templateDocs.ts @@ -25,23 +25,19 @@ type Extension = Documentation; * - [string](https://www.typescriptlang.org/docs/handbook/basic-types.html#string), [number](https://www.typescriptlang.org/docs/handbook/basic-types.html#number), or [boolean](https://www.typescriptlang.org/docs/handbook/basic-types.html#boolean) * - If none of the above types fit your needs, please contact a more experienced developer who can walk you through things like [Custom Arguments](https://github.com/mitmedialab/prg-extension-boilerplate/tree/dev/extensions#adding-custom-arguments) * 2. Once you have your method (_what the Block does_), you'll need to add some extra info to it to tell the Block Programming Environment how to present it to the user. - * - This requires you to [decorate](https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators) your method with the `block` function, - * which we do by putting an '@' symbol in front of `block` and invoking it. - * - The `block` function accepts one argument which provides all the information + * - This requires you to [decorate](https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators) your method with a `scratch` function, + * which we do by putting an '@' symbol in front of `scratch` and invoking either `scratch.command`, `scratch.reporter`, `scratch.button`, or `scratch.hat`. + * - Using a template literal, the `scratch` function provides all the information * the Block Programming Environment will need, like: - * - `type`: What type of block is it / how should it be used? - * - `text`: What text is displayed on the block? - * - `arg` or `args`: How should the method's arguments map to input fields on the block? + * - type: What type of block is it / how should it be used? + * - text: What text is displayed on the block? + * - args: How should the method's arguments map to input fields on the block? * - See [Scratch's documentation](https://github.com/LLK/scratch-vm/blob/develop/docs/extensions.md#block-arguments) to get a sense of how your method's argument types map to the input fields the Block Programming Environment supports * * @example * **NOTE:** Ignore the `.` in front of the `@` symbol -- this is just so JSDoc doesn't mess with the formatting. * ```ts - * .@block({ - * type: "command", - * text: "This is the text that will display on the block", - * args: ["string", "note"] - * }) + * .@(scratch.command`This is the text that will display on the block`) * exampleMethod(someText: string, noteValue: number) { * ... * } @@ -110,7 +106,7 @@ type ExplanationOfInitMethod = Documentation; * As described in the definiton of Block above (hover over it if you need a refresher), we turn the `exampleReporter` method into a method tied to a Block by "decorating" it with the `scratch.reporter` decorator function * (the use of the `@` tell us that it is a [decorator](https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators)). * - * In this scenario, `scratch.reporter` serves as a [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). This means we can use the passed-in [Template String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to provide + * In this scenario, `scratch.reporter` serves as a [Tagged Template Literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates). This means we can use the passed-in [Template String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to provide * all the necessary information for the Block Programming Environment to create a Reporter Block * tied to our method, with input fields at the positions of the templated arguments. * @@ -132,33 +128,20 @@ type ExplanationOfReporterBlock = Documentation; type ExplanationOfCommandBlock = Documentation; /** - * We can either use `scratch.reporter` or `scratch.command` to define a Reporter or Command block, like above, - * or reference a specific entry on the `BlockType` object, like below. - * - * Make sure to hover over the `type` field to get more comprehensive documentation. + * We can use the `scratch` decorator functions to define four types of blocks: a command block, + * a reporter block, a button block, or a hat block. */ type ExplanationOfBlockType = Documentation; /** - * Because the underlying `exampleCommand` method takes arguments, - * our `text` field must implement a function which accepts the same arguments as the method - * (instead of just providing a `string` as is done above). - * - * In the implementation of this function, we should create a [Template String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) that references our arguments, + * Because the underlying `exampleCommand` method takes arguments, we use a [Template String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) with placeholders that match the arguments of the method, * which will auto-magically cause the resulting Blocks to have input fields at the positions of the templated arguments. - * - * Make sure to hover over the `text` field to get more comprehensive documentation. */ type ExplanationOfBlockTextFunction = Documentation; /** - * Because our method accepts 2 arguments, we must define an `args` field - * (necessary whenever your Block's method accepts 2 or more arguments). - * - * This will accept an array of _Arguments_ that correspond to the types of the method's arguments. - * - * As you can see below, how you define _Arguments_ can vary, so make sure to hover over the `args` field to get more comprehensive documentation - * and leverage the examples to understand the different forms in which you can define _Arguments_. + * Because our method accepts two arguments, we must define a template literal with two placeholders. + * Each placeholder will correspond to the types of the method's arguments. */ type ExplanationOfBlockArgs = Documentation; @@ -193,6 +176,6 @@ type ExplanationOfBlockArg = Documentation; * as an Argument for your Block. * * Thus, if your method **_only_** accepts a `BlockUtility` argument, then the `block` function will **not** - * require (or allow) you to define an `arg` nor `args` field -- similiar to the `exampleReporter` method / Block above. + * require (or allow) you to add a placeholder in the template literal -- similiar to the `exampleReporter` method / Block above. */ type ExplanationOfBlockUtility = Documentation; \ No newline at end of file From 4de54dedf0cce16ef586269b9d10d83da7b19170 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Tue, 25 Jun 2024 11:50:53 -0400 Subject: [PATCH 12/13] adding id --- extensions/src/.templates/default.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/src/.templates/default.ts b/extensions/src/.templates/default.ts index b5a453b66..272490155 100644 --- a/extensions/src/.templates/default.ts +++ b/extensions/src/.templates/default.ts @@ -1,4 +1,4 @@ -import { ArgumentType, BlockType, Environment, ExtensionMenuDisplayDetails, extension, scratch } from "$common"; +import { ArgumentType, BlockType, BlockUtilityWithID, Environment, ExtensionMenuDisplayDetails, extension, scratch } from "$common"; import BlockUtility from "$scratch-vm/engine/block-utility"; /** 👋 Hi! @@ -63,7 +63,7 @@ export default class ExtensionNameGoesHere extends extension(details) { /** @see {ExplanationOfHatBlock} */ @(scratch.hat`Should the below block execute: ${"Boolean"}`) /** @see {ExplanationOfBlockUtility} */ - async exampleHat(condition: boolean, util: BlockUtility) { + async exampleHat(condition: boolean, util: BlockUtilityWithID) { return util.stackFrame.isLoop === condition; } } \ No newline at end of file From a711fe32bbdd445292a7a9095955e90cf403b794 Mon Sep 17 00:00:00 2001 From: ymayarajan3 Date: Tue, 25 Jun 2024 12:01:30 -0400 Subject: [PATCH 13/13] changing to ID utility --- extensions/documentation/src/porting/example.ts | 5 ++--- extensions/src/.templates/default.ts | 2 +- extensions/src/common/templateDocs.ts | 10 +++++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/extensions/documentation/src/porting/example.ts b/extensions/documentation/src/porting/example.ts index 1398b10da..0a70de99f 100644 --- a/extensions/documentation/src/porting/example.ts +++ b/extensions/documentation/src/porting/example.ts @@ -1,5 +1,4 @@ -import { ArgumentType, BlockType, Environment, extension, scratch } from "$common"; -import BlockUtility from "$root/scratch-packages/scratch-vm/src/engine/block-utility"; +import { ArgumentType, BlockType, BlockUtilityWithID, Environment, extension, scratch } from "$common"; import formatMessage from './format-message'; // This should actually be an npm package and thus be 'format-message' const details = { @@ -20,7 +19,7 @@ export default class SomeBlocks extends extension(details) { options: [{ text: 'Item One', value: 'itemId1' },'itemId2'] } } of ${{ type: "number", defaultValue: 1 }}`) - myReporter(text: string, letterNum: number) { + myReporter(text: string, letterNum: number, util: BlockUtilityWithID) { const message = formatMessage({ id: 'myReporter.result', default: 'Letter {letterNum} of {text} is {result}.', diff --git a/extensions/src/.templates/default.ts b/extensions/src/.templates/default.ts index 272490155..8b6294c05 100644 --- a/extensions/src/.templates/default.ts +++ b/extensions/src/.templates/default.ts @@ -62,7 +62,7 @@ export default class ExtensionNameGoesHere extends extension(details) { /** @see {ExplanationOfHatBlock} */ @(scratch.hat`Should the below block execute: ${"Boolean"}`) - /** @see {ExplanationOfBlockUtility} */ + /** @see {ExplanationOfBlockUtilityWithID} */ async exampleHat(condition: boolean, util: BlockUtilityWithID) { return util.stackFrame.isLoop === condition; } diff --git a/extensions/src/common/templateDocs.ts b/extensions/src/common/templateDocs.ts index e469d6d8d..5aad4c213 100644 --- a/extensions/src/common/templateDocs.ts +++ b/extensions/src/common/templateDocs.ts @@ -166,16 +166,16 @@ type ExplanationOfHatBlock = Documentation; type ExplanationOfBlockArg = Documentation; /** - * You should notice that the final argument of our method is of type `BlockUtility`. + * You should notice that the final argument of our method is of type `BlockUtilityWithID`. * - * For every Block method, you can optionally add a final parameter of type `BlockUtility` + * For every Block method, you can optionally add a final parameter of type `BlockUtilityWithID` * which can be used to accomplish more [advanced behaviours](https://github.com/mitmedialab/prg-extension-boilerplate/tree/dev/extensions#making-use-of-the-block-utility). * No need to worry too much about when you're first starting out, though! * - * As is the case here, note that the inclusion of a `BlockUtility` argument does not "count" + * As is the case here, note that the inclusion of a `BlockUtilityWithID` argument does not "count" * as an Argument for your Block. * - * Thus, if your method **_only_** accepts a `BlockUtility` argument, then the `block` function will **not** + * Thus, if your method **_only_** accepts a `BlockUtilityWithID` argument, then the `block` function will **not** * require (or allow) you to add a placeholder in the template literal -- similiar to the `exampleReporter` method / Block above. */ -type ExplanationOfBlockUtility = Documentation; \ No newline at end of file +type ExplanationOfBlockUtilityWithID = Documentation; \ No newline at end of file