From 2fad8aca13426461fc937b26708079672ea718f8 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 18 Jan 2024 21:56:03 +0800 Subject: [PATCH] Check `Array.from` --- rules/no-array-method-this-argument.js | 50 +-- test/no-array-method-this-argument.mjs | 2 +- .../no-array-method-this-argument.mjs.md | 295 +++++++++++++++--- .../no-array-method-this-argument.mjs.snap | Bin 1299 -> 1780 bytes 4 files changed, 279 insertions(+), 68 deletions(-) diff --git a/rules/no-array-method-this-argument.js b/rules/no-array-method-this-argument.js index 8d907edb6c..ee0be686d7 100644 --- a/rules/no-array-method-this-argument.js +++ b/rules/no-array-method-this-argument.js @@ -13,7 +13,7 @@ const SUGGESTION_BIND = 'suggestion-bind'; const SUGGESTION_REMOVE = 'suggestion-remove'; const messages = { [ERROR_PROTOTYPE_METHOD]: 'Do not use the `this` argument in `Array#{{method}}()`.', - [ERROR_STATIC_METHOD]: 'Do not use the `this` argument in `Array.from()`.', + [ERROR_STATIC_METHOD]: 'Do not use the `this` argument in `Array.{{method}}()`.', [SUGGESTION_REMOVE]: 'Remove the second argument.', [SUGGESTION_BIND]: 'Use a bound function.', }; @@ -72,30 +72,28 @@ const ignored = [ 'underscore.some', ]; -function removeThisArgument(callExpression, sourceCode) { - return fixer => removeArgument(fixer, callExpression.arguments[1], sourceCode); +function removeThisArgument(thisArgumentNode, sourceCode) { + return fixer => removeArgument(fixer, thisArgumentNode, sourceCode); } -function useBoundFunction(callExpression, sourceCode) { +function useBoundFunction(callbackNode, thisArgumentNode, sourceCode) { return function * (fixer) { - yield removeThisArgument(callExpression, sourceCode)(fixer); + yield removeThisArgument(thisArgumentNode, sourceCode)(fixer); - const [callback, thisArgument] = callExpression.arguments; - - const callbackParentheses = getParentheses(callback, sourceCode); + const callbackParentheses = getParentheses(callbackNode, sourceCode); const isParenthesized = callbackParentheses.length > 0; const callbackLastToken = isParenthesized ? callbackParentheses.at(-1) - : callback; + : callbackNode; if ( !isParenthesized - && shouldAddParenthesesToMemberExpressionObject(callback, sourceCode) + && shouldAddParenthesesToMemberExpressionObject(callbackNode, sourceCode) ) { yield fixer.insertTextBefore(callbackLastToken, '('); yield fixer.insertTextAfter(callbackLastToken, ')'); } - const thisArgumentText = getParenthesizedText(thisArgument, sourceCode); + const thisArgumentText = getParenthesizedText(thisArgumentNode, sourceCode); // `thisArgument` was a argument, no need add extra parentheses yield fixer.insertTextAfter(callbackLastToken, `.bind(${thisArgumentText})`); }; @@ -108,28 +106,26 @@ function getProblem({ thisArgumentNode, messageId, }) { - const {callee} = callExpression; - const method = callee.property.name; - const problem = { node: thisArgumentNode, messageId, - data: {method}, + data: { + method: callExpression.callee.property.name, + }, }; - const thisArgumentHasSideEffect = hasSideEffect(thisArgumentNode, sourceCode); const isArrowCallback = callbackNode.type === 'ArrowFunctionExpression'; - if (isArrowCallback) { + const thisArgumentHasSideEffect = hasSideEffect(thisArgumentNode, sourceCode); if (thisArgumentHasSideEffect) { problem.suggest = [ { messageId: SUGGESTION_REMOVE, - fix: removeThisArgument(callExpression, sourceCode), + fix: removeThisArgument(thisArgumentNode, sourceCode), }, ]; } else { - problem.fix = removeThisArgument(callExpression, sourceCode); + problem.fix = removeThisArgument(thisArgumentNode, sourceCode); } return problem; @@ -138,11 +134,11 @@ function getProblem({ problem.suggest = [ { messageId: SUGGESTION_REMOVE, - fix: removeThisArgument(callExpression, sourceCode), + fix: removeThisArgument(thisArgumentNode, sourceCode), }, { messageId: SUGGESTION_BIND, - fix: useBoundFunction(callExpression, sourceCode), + fix: useBoundFunction(callbackNode, thisArgumentNode, sourceCode), }, ]; @@ -154,7 +150,7 @@ const create = context => { const {sourceCode} = context; // Prototype methods - context.on('CallExpression', (callExpression) => { + context.on('CallExpression', callExpression => { if ( !( isMethodCall(callExpression, { @@ -201,11 +197,19 @@ const create = context => { optionalCall: false, optionalMember: false, }) - && !isNodeValueNotFunction(callExpression.arguments[0]) + && !isNodeValueNotFunction(callExpression.arguments[1]) ) ) { return; } + + return getProblem({ + sourceCode, + callExpression, + callbackNode: callExpression.arguments[1], + thisArgumentNode: callExpression.arguments[2], + messageId: ERROR_STATIC_METHOD, + }); }); }; diff --git a/test/no-array-method-this-argument.mjs b/test/no-array-method-this-argument.mjs index e5a43b9bee..6cb708b5c9 100644 --- a/test/no-array-method-this-argument.mjs +++ b/test/no-array-method-this-argument.mjs @@ -27,7 +27,7 @@ test.snapshot({ 'Array.from(iterableOrArrayLike, () => {}, ...thisArgument)', 'Array.from(iterableOrArrayLike, ...() => {}, thisArgument)', 'Array.from(...iterableOrArrayLike, () => {}, thisArgument)', - 'Array.from(iterableOrArrayLike, () => {}, thisArgument,extraArgument)', + 'Array.from(iterableOrArrayLike, () => {}, thisArgument, extraArgument)', // Ignored 'lodash.every(array, () => {})', diff --git a/test/snapshots/no-array-method-this-argument.mjs.md b/test/snapshots/no-array-method-this-argument.mjs.md index 85dacdd156..9d9e3c3993 100644 --- a/test/snapshots/no-array-method-this-argument.mjs.md +++ b/test/snapshots/no-array-method-this-argument.mjs.md @@ -193,6 +193,27 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ ` +## invalid(10): Array.from(iterableOrArrayLike, () => {}, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument)␊ + ` + +> Output + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {})␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ` + ## invalid(11): array.map(() => {}, thisArgument,) > Input @@ -235,6 +256,27 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ ` +## invalid(13): Array.from(iterableOrArrayLike, () => {}, thisArgument,) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument,)␊ + ` + +> Output + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {},)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument,)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ` + ## invalid(14): array.map(() => {}, thisArgumentHasSideEffect()) > Input @@ -254,6 +296,25 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(() => {})␊ ` +## invalid(15): Array.from(iterableOrArrayLike, () => {}, thisArgumentHasSideEffect()) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {}, thisArgumentHasSideEffect())␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, () => {}, thisArgumentHasSideEffect())␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, () => {})␊ + ` + ## invalid(1): array.map(callback, thisArgument) > Input @@ -277,7 +338,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(callback.bind(thisArgument))␊ ` -## invalid(2): array.map(callback, (0, thisArgument)) +## invalid(2): Array.from(iterableOrArrayLike, callback, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, callback, thisArgument)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, callback, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, callback)␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(thisArgument))␊ + ` + +## invalid(3): array.map(callback, (0, thisArgument)) > Input @@ -300,7 +384,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(callback.bind((0, thisArgument)))␊ ` -## invalid(3): array.map(function () {}, thisArgument) +## invalid(4): Array.from(iterableOrArrayLike, callback, (0, thisArgument)) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, callback, (0, thisArgument))␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, callback, (0, thisArgument))␊ + | ^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, callback)␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind((0, thisArgument)))␊ + ` + +## invalid(5): array.map(function () {}, thisArgument) > Input @@ -323,7 +430,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(function () {}.bind(thisArgument))␊ ` -## invalid(4): array.map(function callback () {}, thisArgument) +## invalid(6): Array.from(iterableOrArrayLike, function () {}, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, function () {}, thisArgument)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, function () {}, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, function () {})␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, function () {}.bind(thisArgument))␊ + ` + +## invalid(7): array.map(function callback () {}, thisArgument) > Input @@ -346,7 +476,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(function callback () {}.bind(thisArgument))␊ ` -## invalid(5): array.map( foo as bar, (( thisArgument )),) +## invalid(8): Array.from(iterableOrArrayLike, function callback () {}, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, function callback () {}, thisArgument)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, function callback () {}, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, function callback () {})␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, function callback () {}.bind(thisArgument))␊ + ` + +## invalid(9): array.map( foo as bar, (( thisArgument )),) > Input @@ -369,7 +522,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map( (foo as bar).bind((( thisArgument ))),)␊ ` -## invalid(6): array.map( (( foo as bar )), (( thisArgument )),) +## invalid(10): Array.from(iterableOrArrayLike, foo as bar, (( thisArgument )),) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, foo as bar, (( thisArgument )),)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, foo as bar, (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, foo as bar,)␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, (foo as bar).bind((( thisArgument ))),)␊ + ` + +## invalid(11): array.map( (( foo as bar )), (( thisArgument )),) > Input @@ -392,132 +568,163 @@ Generated by [AVA](https://avajs.dev). 1 | array.map( (( foo as bar )).bind((( thisArgument ))),)␊ ` -## invalid(7): array.map( (( 0, callback )), (( thisArgument )),) +## invalid(12): Array.from(iterableOrArrayLike, (( foo as bar )), (( thisArgument )),) > Input `␊ - 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ + 1 | Array.from(iterableOrArrayLike, (( foo as bar )), (( thisArgument )),)␊ ` > Error 1/1 `␊ - > 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | Array.from(iterableOrArrayLike, (( foo as bar )), (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/2: Remove the second argument.␊ - 1 | array.map( (( 0, callback )),)␊ + 1 | Array.from(iterableOrArrayLike, (( foo as bar )),)␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 2/2: Use a bound function.␊ - 1 | array.map( (( 0, callback )).bind((( thisArgument ))),)␊ + 1 | Array.from(iterableOrArrayLike, (( foo as bar )).bind((( thisArgument ))),)␊ ` -## invalid(8): array.map((0, () => {}), thisArgument) +## invalid(13): array.map( (( 0, callback )), (( thisArgument )),) > Input `␊ - 1 | array.map((0, () => {}), thisArgument)␊ + 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ ` > Error 1/1 `␊ - > 1 | array.map((0, () => {}), thisArgument)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/2: Remove the second argument.␊ - 1 | array.map((0, () => {}))␊ + 1 | array.map( (( 0, callback )),)␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 2/2: Use a bound function.␊ - 1 | array.map((0, () => {}).bind(thisArgument))␊ + 1 | array.map( (( 0, callback )).bind((( thisArgument ))),)␊ ` -## invalid(9): array.map(callback.bind(foo), thisArgument) +## invalid(14): Array.from(iterableOrArrayLike, (( 0, callback )), (( thisArgument )),) > Input `␊ - 1 | array.map(callback.bind(foo), thisArgument)␊ + 1 | Array.from(iterableOrArrayLike, (( 0, callback )), (( thisArgument )),)␊ ` > Error 1/1 `␊ - > 1 | array.map(callback.bind(foo), thisArgument)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | Array.from(iterableOrArrayLike, (( 0, callback )), (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/2: Remove the second argument.␊ - 1 | array.map(callback.bind(foo))␊ + 1 | Array.from(iterableOrArrayLike, (( 0, callback )),)␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 2/2: Use a bound function.␊ - 1 | array.map(callback.bind(foo).bind(thisArgument))␊ + 1 | Array.from(iterableOrArrayLike, (( 0, callback )).bind((( thisArgument ))),)␊ ` -## invalid(10): array.map(() => {}, thisArgument,) +## invalid(15): array.map((0, () => {}), thisArgument) > Input `␊ - 1 | array.map(() => {}, thisArgument,)␊ + 1 | array.map((0, () => {}), thisArgument)␊ ` -> Output +> Error 1/1 `␊ - 1 | array.map(() => {},)␊ + > 1 | array.map((0, () => {}), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | array.map((0, () => {}))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | array.map((0, () => {}).bind(thisArgument))␊ ` -> Error 1/1 +## invalid(16): Array.from(iterableOrArrayLike, (0, () => {}), thisArgument) + +> Input `␊ - > 1 | array.map(() => {}, thisArgument,)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + 1 | Array.from(iterableOrArrayLike, (0, () => {}), thisArgument)␊ ` -## invalid(11): array.map(() => {}, (0, thisArgument),) - -> Input +> Error 1/1 `␊ - 1 | array.map(() => {}, (0, thisArgument),)␊ + > 1 | Array.from(iterableOrArrayLike, (0, () => {}), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, (0, () => {}))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, (0, () => {}).bind(thisArgument))␊ ` -> Output +## invalid(17): array.map(callback.bind(foo), thisArgument) + +> Input `␊ - 1 | array.map(() => {},)␊ + 1 | array.map(callback.bind(foo), thisArgument)␊ ` > Error 1/1 `␊ - > 1 | array.map(() => {}, (0, thisArgument),)␊ - | ^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | array.map(callback.bind(foo), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | array.map(callback.bind(foo))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | array.map(callback.bind(foo).bind(thisArgument))␊ ` -## invalid(12): array.map(() => {}, thisArgumentHasSideEffect()) +## invalid(18): Array.from(iterableOrArrayLike, callback.bind(foo), thisArgument) > Input `␊ - 1 | array.map(() => {}, thisArgumentHasSideEffect())␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(foo), thisArgument)␊ ` > Error 1/1 `␊ - > 1 | array.map(() => {}, thisArgumentHasSideEffect())␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | Array.from(iterableOrArrayLike, callback.bind(foo), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ ␊ --------------------------------------------------------------------------------␊ - Suggestion 1/1: Remove the second argument.␊ - 1 | array.map(() => {})␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(foo))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(foo).bind(thisArgument))␊ ` diff --git a/test/snapshots/no-array-method-this-argument.mjs.snap b/test/snapshots/no-array-method-this-argument.mjs.snap index fc008f271170e0883c780137040da43db2eb4da9..cace8729956bab82ebd965bcd51961415aff9198 100644 GIT binary patch literal 1780 zcmV(Wuv_NsVzy9 zP9_9~=O2p*00000000B+TuW~oRTNI9LKWGuV!`WHsK{;{C$>|ZgeGYqfkbK&Ddtfm zs4}+4$tccDG&7D`C<_7-0)$jl2?0W?$PXyLfc^s5uwa9P!~%BgKtin0)E;||=ght5 z-f?Q<)XPNv?#cI>$Gz>hwQ}9A?73f_J2pJis~guRP3usvo7Ge>HMsHeE|UaCdFb{ouG-)jj>{?3t0XBmQUfk&(wn$Hy4U zv6~dAF{7@Rjk>XB9W=Za*f;=tiUSsWy|&r#I^X{y{C(}Ck+B8xG>kEJli{Chp$}WO znPq#d;Tp`_HQ2Tfv(5At5Hl^dz2vX=Y;(QzcD6ODx#Bps!*Y|kfc>d}{d}AKnpyV@ zhfe<-U@QX|<6~j`X8_vMJTzQ@uYdrbKmi2v@Dxy#ptT}TgKVHdA*6v-r7JK4IJ?lr zSv(TP{{?{cWIPtm{%yeihu!RRX5nzJ%Dh$O@?Hpdp9Z|ISykgYo&0$~*kpt-E*z%7 zBmg`o0K{cD1~S}^%D|tBn}bAxG}q;+k`Gk52voVEyB=MXOMt^{ghL)0rb!myF+LtH z$sHict*9j2nFNZc3vz!|o*u@Bv~Q-sIlSp*B@Bp1L%`yPmPHxNyAYRW|>vB1r_cnWu(+H-_ZWh5V3cu2AjEdUFb z=yM>^5j9tt2Oq5IHtqQs+EY_qj={L+J+lbmPC$UKfdHTK1i%L3Wa1k9^iGMDwh{&9 zio>MY08Cy^)N#00m%$2o*%fdF?*RqBOV)CHNgrg*&9_yaCe+-j?v~7|u~MrU6)%+z zse9C->1DwE46*dOaS>JD90kx?agwj^72B$|$H@xsyP{4gwViNLIqzbByaoKRktqEn*L)0I^Ui3Z+)8+f)Yb_@JqQ+) zy?5k1y}%o-ie9gm^~zrCP4f})=_LjTb<2;yE%%}w69+~sm4R!Kyj+U}e|`F7=gRwY zz2+KBXJxx#RavcJRs7$?Pn0eDFT;T*@s4{byeA|wFxiJ{4{s9g)Sd(Gd|V@TnY?FD z$v_0-*nK%@pJHmdxf&u({ zXwJ*yBjP(RE*x6TzXOy19Ia+Pq{z?1)XtEJep@weE~(pvweY^U$o!ICEdj5t5ECZt zU~K_7c#>Mv$$Z^IxBtJIdayzuH?34OE=3O^fUpIZ0%96OFHLEm9agZ}3>2S5zz6pF^2EH#z7k`h^@bFSFSkX}&TPjdR{4@@$ z**4Q%R@R*iOQnFLSQ_kN2dUwmCnQ0lclCdQX#5(zB#2=}{vW1`K$wkw+cz{-sxwx) z^~4!bs^fsDOV_1NFv)xOb>Q7qYW@@qt-S~gT_AUTQkS3FZXcXL2zMV7req=J6qs+A z4zzC9?~vv#A)l1kTk7W25M9#nTg)kXWM&m)W)6)%1sTo9S&)x^@Jj*- zotTATyC`&V({GFOhEuWgtKj%2AwX&#e;aswlb%;)>$iZnIqQL6IRQQ00emgd1EVV7%9Aytz z&ZcSyZDh@>f&Y9%8z&ce0!yFX+8!kTOARZPikWsQis(VeCRok3#UT*Ap%+4;h5a}1 z{2%d0BI98x79XbSjxy43|MF&&vg=0Mu9O{G1rxskOuVLa+>K~$4gBjrZBh2zWHQ5_ W+F~EPbjVLk%FKU*wv*<5O#lE!pkj{z literal 1299 zcmV+u1?>7kRzVGqa(^`rs-Eicl#O6``0vz(2viKwo_DMG$<@H{TS*Cz)nvchBB4=iZs@ zmSxSnF8jS_zn||td*|G5J1sA0-;Ta~=2*sV?8!STu74yv*Rg8$28b{ecPsKphIcK? zhRrQ_|AR8b`);%y?sX5OAKPx^i^FI?h@+2=9Y@6C-Su+|7Z#Fd@%+Nmi@pI2o)JsG-g&DV55NC#^!rPnER?p4s{sJG2lR7mApfSS0cgzW_AW|M9r{Of8J}MVN^_0pLMCA<;#pY11ArC8xhnyP4q=NK-*Q1dyeh||new=*@W{DSwvmYq(!|`mrGZ3WHV~!pe24HnqVb$=*PI@de)rT;TFoIX zPsDGELvv2AAWN6ArMwtLXc@`9$jZ@dzCmn0A7i7bh^JDJM}JKt5^F;eLAWE@`x7F; zi{&OUCRc=nrlP5k= %4J%Xgyx8OD8;F{rf7}q7( zytjy?mzs-)@m93W!hUMUOUn~}N;kWEdoqgMz)uKnz}xa5I65gOlI_5E2IW+={hImn z!JV)zJg+6%w=@5IdWL^K8A2rL9}(*BRn%Ex(`sZ>hFQ-CGyV1UbnB`ob-fcw5YP&` zz5|`E-%dWsuBg&VW*LY{cH-*lNDs4Bnj{fB?gd(>MrQ99l)WFg>=BC7?BQo2%o9Qt zPIeL->R>YwOqT-7=8oSz!{Z1mM`rPNl*OObEb@{}80W4hVkc%Nl(?>3{qdSQ_C<{EE6YuFSe{5jCkQ}9&=O%8EDOZ} zZ1mFCGZ@YqNs^uRPn6(a)dcHh|4-d^)Q#B*Dpt#!3k}{ ztiF!2x=s{qBuw_)b11QY5s5VvH*30cm0rb}S<3KOZAEgtrCzS2+ST%~jhhGgItuaz zS+$8WndA#7$^XzvHc~e{Kg?T}$Gn-XFyrEiq`9tMP(2=LRm(6KYiUovx;X)-MxGdc zL#h3V7)Nr7nxxKCLXi)%lTB1sv9s(tIk!5|>I8v4l)AI5R+3ES-zb@XWKXcNWlb9C zJY`gMWOjn8)|M-+!z<3}*%jyHbF9DO%(_`VyW-5mFr_Qbtjp%JE6$nh;S;;!{0};| JbDhjD0090ZgC_t0