From 3cb1faf1c6f39ee341eb2dfad0d8bd9633c901a4 Mon Sep 17 00:00:00 2001 From: zipg Date: Sun, 20 Sep 2026 00:51:06 +0800 Subject: [PATCH] fix(editor): skip INSERT hints duplicating projection aliases --- .../editor/codemirrorInsertValueHints.spec.ts | 8 ++ .../lib/editor/codemirrorInsertValueHints.ts | 2 +- apps/desktop/src/lib/sql/insertValueHints.ts | 73 ++++++++++++++---- docs/screenshots/issue-9277-after.png | Bin 0 -> 35490 bytes docs/screenshots/issue-9277-before.png | Bin 0 -> 29887 bytes packages/app-tests/insertValueHints.test.ts | 46 +++++++++++ 6 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 docs/screenshots/issue-9277-after.png create mode 100644 docs/screenshots/issue-9277-before.png diff --git a/apps/desktop/src/lib/__tests__/editor/codemirrorInsertValueHints.spec.ts b/apps/desktop/src/lib/__tests__/editor/codemirrorInsertValueHints.spec.ts index 64a714cda7..7c42489b5a 100644 --- a/apps/desktop/src/lib/__tests__/editor/codemirrorInsertValueHints.spec.ts +++ b/apps/desktop/src/lib/__tests__/editor/codemirrorInsertValueHints.spec.ts @@ -1,6 +1,7 @@ import { strict as assert } from "node:assert"; import { test } from "vitest"; import { buildInsertValueHintDecorations, insertValueHintsRefreshDispatchSpec, isInsertValueHintDecorationAt } from "@/lib/editor/codemirrorInsertValueHints"; +import { parseInsertValueHints } from "@/lib/sql/insertValueHints"; test("insertValueHintsRefreshDispatchSpec disables scrollIntoView", () => { assert.equal(insertValueHintsRefreshDispatchSpec.scrollIntoView, false); @@ -18,3 +19,10 @@ test("isInsertValueHintDecorationAt detects widget anchors", () => { assert.equal(isInsertValueHintDecorationAt(decorations, valueTwo), true); assert.equal(isInsertValueHintDecorationAt(decorations, sql.indexOf("INSERT")), false); }); + +test("a projection that already aliases its target column renders no hint widget", () => { + const sql = ["INSERT INTO t (operation_apply_id, pacu_status)", "SELECT", " noprid.ruid as operation_apply_id,", " noprid.flag", "FROM noprid"].join("\n"); + const decorations = buildInsertValueHintDecorations(parseInsertValueHints(sql)); + assert.equal(isInsertValueHintDecorationAt(decorations, sql.indexOf("noprid.ruid")), false); + assert.equal(isInsertValueHintDecorationAt(decorations, sql.indexOf("noprid.flag")), true); +}); diff --git a/apps/desktop/src/lib/editor/codemirrorInsertValueHints.ts b/apps/desktop/src/lib/editor/codemirrorInsertValueHints.ts index 2318d4739b..2b9e097ae5 100644 --- a/apps/desktop/src/lib/editor/codemirrorInsertValueHints.ts +++ b/apps/desktop/src/lib/editor/codemirrorInsertValueHints.ts @@ -99,7 +99,7 @@ function shiftClause(clause: InsertValuesClause, offset: number): InsertValuesCl return { ...clause, span: { start: clause.span.start + offset, end: clause.span.end + offset }, - rows: clause.rows.map((row) => row.map((from) => from + offset)), + rows: clause.rows.map((row) => row.map((source) => ({ ...source, from: source.from + offset }))), }; } diff --git a/apps/desktop/src/lib/sql/insertValueHints.ts b/apps/desktop/src/lib/sql/insertValueHints.ts index 03d0393b67..0549de7a75 100644 --- a/apps/desktop/src/lib/sql/insertValueHints.ts +++ b/apps/desktop/src/lib/sql/insertValueHints.ts @@ -14,11 +14,25 @@ export interface InsertValuesClause { database?: string; /** Explicit column list, or null when `INSERT INTO t VALUES` has no column list. */ columns: string[] | null; - /** For each VALUES row or SELECT projection list, start offsets of top-level expressions. */ - rows: number[][]; + /** For each VALUES row or SELECT projection list, the top-level source expressions. */ + rows: InsertValueSource[][]; span: SqlSemanticSpan; } +/** One source expression of an INSERT, positioned for its inlay hint. */ +export interface InsertValueSource { + /** Document offset where the inlay widget is inserted (before the value expression). */ + from: number; + /** + * Explicit alias of a SELECT projection item (`expr AS alias`, `expr alias`), unquoted. + * + * The positional hint maps a source expression to its target column; when the projection + * already names that same column itself, the hint would only duplicate the alias the user + * typed, so `buildInsertValueHints` drops it. + */ + alias?: string; +} + export interface ParseInsertValueHintsOptions { /** Resolve table columns when the INSERT has no explicit column list. */ resolveTableColumns?: (table: string, schema?: string, database?: string) => string[] | undefined; @@ -115,11 +129,11 @@ function parseColumnList(tokens: readonly SqlSemanticToken[], openIndex: number) return { columns, nextIndex: index }; } -function valueStartsInRow(tokens: readonly SqlSemanticToken[], openIndex: number): { starts: number[]; nextIndex: number } | null { +function valueStartsInRow(tokens: readonly SqlSemanticToken[], openIndex: number): { starts: InsertValueSource[]; nextIndex: number } | null { const open = tokens[openIndex]; if (!open || open.text !== "(") return null; const contentDepth = open.depth + 1; - const starts: number[] = []; + const starts: InsertValueSource[] = []; let expectValue = true; let index = openIndex + 1; @@ -130,7 +144,7 @@ function valueStartsInRow(tokens: readonly SqlSemanticToken[], openIndex: number return { starts, nextIndex: index + 1 }; } if (expectValue && item.depth === contentDepth) { - starts.push(item.span.start); + starts.push({ from: item.span.start }); expectValue = false; } if (item.text === "," && item.depth === contentDepth) { @@ -141,8 +155,8 @@ function valueStartsInRow(tokens: readonly SqlSemanticToken[], openIndex: number return { starts, nextIndex: index }; } -function parseValuesRows(tokens: readonly SqlSemanticToken[], valuesIndex: number): number[][] { - const rows: number[][] = []; +function parseValuesRows(tokens: readonly SqlSemanticToken[], valuesIndex: number): InsertValueSource[][] { + const rows: InsertValueSource[][] = []; let index = valuesIndex + 1; while (index < tokens.length) { const item = tokens[index]; @@ -205,7 +219,7 @@ function isWildcardProjection(tokens: readonly SqlSemanticToken[], from: number, return topLevel.length % 2 === 1 && topLevel.every((item, index) => (index % 2 === 0 ? (index === topLevel.length - 1 ? item.text === "*" : tokenIsIdentifier(item)) : item.text === ".")); } -function selectProjectionStarts(tokens: readonly SqlSemanticToken[], selectIndex: number): number[] { +function selectProjectionStarts(tokens: readonly SqlSemanticToken[], selectIndex: number): InsertValueSource[] { const select = tokens[selectIndex]; if (!select) return []; const depth = select.depth; @@ -239,7 +253,7 @@ function selectProjectionStarts(tokens: readonly SqlSemanticToken[], selectIndex if (tokens[index]?.depth === depth && tokens[index]?.normalized === "with" && tokens[index + 1]?.depth === depth && tokens[index + 1]?.normalized === "ties") index += 2; } - const starts: number[] = []; + const starts: InsertValueSource[] = []; let expressionStart = index; for (; index < tokens.length; index += 1) { const item = tokens[index]; @@ -247,15 +261,37 @@ function selectProjectionStarts(tokens: readonly SqlSemanticToken[], selectIndex if (isSelectClauseBoundary(item, depth)) break; if (item.text !== "," || item.depth !== depth) continue; if (index <= expressionStart || isWildcardProjection(tokens, expressionStart, index, depth)) return []; - starts.push(tokens[expressionStart]!.span.start); + starts.push(selectProjectionSource(tokens, expressionStart, index, depth)); expressionStart = index + 1; } if (index <= expressionStart || isWildcardProjection(tokens, expressionStart, index, depth)) return []; - starts.push(tokens[expressionStart]!.span.start); + starts.push(selectProjectionSource(tokens, expressionStart, index, depth)); return starts; } +/** + * Projection source expression start, plus the alias that ends the projection when it has one. + * Only the *trailing name* of a projection is an alias, so the token in front of it decides: + * `AS` or another identifier (`x total`, `f(x) total`) introduces an alias, while a dotted name + * (`t.col`), an operator (`x::text`) or an open expression does not. + */ +function selectProjectionSource(tokens: readonly SqlSemanticToken[], from: number, to: number, depth: number): InsertValueSource { + const source: InsertValueSource = { from: tokens[from]!.span.start }; + const alias = selectProjectionAlias(tokens, to, depth); + if (alias !== undefined) source.alias = alias; + return source; +} + +function selectProjectionAlias(tokens: readonly SqlSemanticToken[], to: number, depth: number): string | undefined { + const last = tokens[to - 1]; + if (!tokenIsIdentifier(last) || last.depth !== depth) return undefined; + const previous = tokens[to - 2]; + if (!previous) return undefined; + const introducesAlias = previous.kind === "word" || previous.kind === "quoted_identifier" || previous.text === ")"; + return introducesAlias ? unquoteSqlSemanticIdentifier(last) : undefined; +} + function parseInsertClause(tokens: readonly SqlSemanticToken[], span: SqlSemanticSpan): InsertValuesClause | null { const insertIndex = findWordIndex(tokens, "insert"); if (insertIndex < 0) return null; @@ -316,7 +352,7 @@ function shiftClause(clause: InsertValuesClause, offset: number): InsertValuesCl return { ...clause, span: { start: clause.span.start + offset, end: clause.span.end + offset }, - rows: clause.rows.map((row) => row.map((from) => from + offset)), + rows: clause.rows.map((row) => row.map((source) => ({ ...source, from: source.from + offset }))), }; } @@ -671,16 +707,23 @@ export function buildInsertValueHints(clauses: readonly InsertValuesClause[], op for (const row of clause.rows) { const count = Math.min(row.length, columns.length); for (let index = 0; index < count; index += 1) { - const from = row[index]; + const source = row[index]; const column = columns[index]; - if (from === undefined || !column) continue; - hints.push({ from, column }); + if (source === undefined || !column) continue; + // A projection that already ends with the target column name states the mapping by + // itself; repeating it as an inlay pill only duplicates the alias the user typed. + if (source.alias !== undefined && sameSqlIdentifier(source.alias, column)) continue; + hints.push({ from: source.from, column }); } } } return hints; } +function sameSqlIdentifier(left: string, right: string): boolean { + return left.toLowerCase() === right.toLowerCase(); +} + /** Parse SQL and return insert-value inlay hints. */ export function parseInsertValueHints(sql: string, options: ParseInsertValueHintsOptions = {}): InsertValueHint[] { return buildInsertValueHints(parseInsertValuesClauses(sql), options); diff --git a/docs/screenshots/issue-9277-after.png b/docs/screenshots/issue-9277-after.png new file mode 100644 index 0000000000000000000000000000000000000000..bc5f20c5c23d8accf2668d493f15216ef4d49e4f GIT binary patch literal 35490 zcmdSBV|*psw>BD^9d?Y4t&Z)EZQHihu{zF*ZQD*dwrxA{*2fE%!Q4k!pXa1Z*|cR67H{0e@X1OCr3 z$n0Mi$}8alYZU;I6cJQ*2R+w;)oq2mS4;5mAmuziHnoTx9?3LcthU`vLjtD0!FX?| zHj_K8kxi>9%EGE%j&JAqXv$1O!+KBby90^WyUTZXMl>AJq=p8#tg?@9WVJ~69Pz6jR~7vn0+G98 z6V|3hY%IQl?R+Bg8WcFXVi-EYN{TTz;p}eCZ%T%;e79%%IIFK6X<$tB=36##my$A` zIhZxuyWo10Dyq-qx;nS+mZX4|?j0^^6(5beQ}yKYz02{^r;5VUiveXTLulZzF< zxR%PgG-}U@%}*~PERZxKMCc~S1jn)eFbytm4KSWd3T`wr)U&heoMX_CQresQm^{XU z@ooKeEoVOz)DXB+$)VhdAN|wQAtJb36K+UN;pyE@Vu-)@M5~Hy;&k!^kd$j|%1$3( zwYi0iv?<9ly@-&y6)?5pMq@HFBVp#GvsH55%(a>YKb4r2Xakt;NJwz7HTXR&PWlJB zATgPlvj3-ot!@*PcV*cprV67k)&#hCRpb)Ed?7?rfH= zsm1ePifQA9FR8~$c*)jqYxnxRbI%aBLFw#-5g@lgkxBREadC)gA~+YqQ^EZ%;s^N^ zTqjOabnW+^x!q6&+c*?bRL!#LN?1^&4M`mbW}JmwDWg@*?AB~pVj~v#T#74~My>f_ z$shpkK=sB4Rb;H_3kU9=!#FQG0ZMjrLH1q8W^{c)ov1hoGISxRy+n(x`&_c?dYoET zd|d%q(Dw}s>mn~wuIBps+N`F-q>=LlVeKO4CJZ~p%0QPbdv3n=k`%xRgVDzG>BjeU zdMY}pajL$n_{z#AZ5hw}po!S(*4ze7UJQ&wSMSZ^tt;7MeKdf|K5p8DVQI6We!};I z1i*0=1o=)WBnxt|o_8GNwHG@}e_U`0@Kmt&o&OYM-P32Pv$1-@CbU$tLBUwaE7!|G zLsXJe)IB|cd(DuxJk3iq1Qq{>{FiLI_e{F`$F2hpS`MGZfa^uqpKr#Lt0mO1DhErW zae{K?+(9?DJip^O-6>o)w@}@EtO?FymX1s41nU%kHe)zzIeRLHfZVEd!X!3g4U}zm zm*EWJI(=-R_DViuD^;E&KsVN;9vYRK%3|6mJHNdQAH;0nL_L3MD$6R1?G(sHGs-SF zJDu9vu6~^vg}YMfumMeM&SyFnH7khy@bo|FTb00d8u`?18U`S-4E0jc>GPDFQf=KI z*V_5s?^H}?c0fuFL02X>TZFu&ld&!+2T^sq&5GBYbo0HkOM82a{;E@aUelEB_wRN( zLb6*AqWjWPN$;nAS8rA?$L~|2yVXU@80T{h%IzFRM(&u*W$pP9=+WuP=Jn}gOJ=_d zVK#TC=K4J{(&+PJj1ITWW$$*i!Qc|Z$qo`R8G^0d^L`s=wfj@S#>{N7bS_`3K-VKA zEv*(Ft0ma};cS>*HyDG?n3CLCx}qVPw!sn$3u3h|cFArG~!zBbv9JboV$GDq34Rbn0i)mYI>cpk_r@tIkoO zpLphS6g6^;H{tu0osHQCm}l$~)|MteFWqsVHaE%d{ryC%rFTzfKMl(M5$}Uy{}|b! z-pG#Xaa(vJpZlv`$_>^b-tXo18!PJSj#4k2y$zXuPoTGc-O2Y0ezn6}7D+XIM@KUg zL+_~Gq~y@gH9L&sU3|E1WXwk+_sNW-fHnK?aI_l?KU+lTFPtCWzt^y_z#EUSPA>+! zAX#m0Di8mbUYe0s6E7EH(dU95Kijs>1<)N(KA!=cY60{VZ%mt{zOBfcVRn}-Zr^Fq z7H&2NS-IMxRrY^Px)WY?Cf(Nje9}`e5b=ToM<1G=1pH2Y@^zoE(e?s-_1g@Up`FC4 zw?qzYLi%a6roo+d)~0n9Yiku9Q&M}zoSMU1 z@xafC6TSqSg~}L84C5_7xG3T^1;`4g@z$T~?>b7;=Nsfglw&kmkYdqo;>XHL%FtS0 z9|93mcNQZyPkwajBO&II8J&y#7&3(Vi6y-gR+xF|bFL$=&E=s6L%HSqyQ;Ks^C0XT zo@H$pwy%sHD_8^fL>=b`f=go#$P?8JiuLrCwR({#17 zgzImJ02@gt4aAaq3E%uK2;XrkY|*(=J3}OQxq%GG zVoCKy)MP7x9U|S|@}z^c5_(oepRI1L-(>%NXDk8b?D#IhzO{1kl2lDWVT&v|PS5q} z3z(MUdURkvyE6j8%*bQ;qHM0qAdcX{6P7wI1hgY<}jC^Ya<*~p6c0S52e7Q1narZ7E3x5u-}g$=Z- z@SPyF$5FwOEuTXI&d-Y-NJ~de!-gPdcqr9=3v|4CKL@iaYhyk;9tR6eI2B!1!!Q~X zS~s85Y%Xc9e=dP%fiWtu{E2`gY_MBJtS(QYr zwDDCs$$bHbxw@$i=g{P)F4DqHO{oQB`_a<0Fczb|>_kB&-%=N1bQPXF?@CW4x{sVd z^|G#ayxt~o_+Z3(+)-b#k{H}`=4NfO*W8g}&8JzBJ=*2ZYt6>TTB#cvC$EBwK_^ZY zb%<&x!zIMjWQv)g$B&t>78f-|?)5!+{_x0E4dqU&8rTx_qCM&;ey=dmt{10H=Y$Ks z8Ua;Bu#$xs2J3sn4lB-(p+1EeR$?IaA4zJuoGz#6didXYZR0g`Z0))yxLl0|1!GUY zesySWcdeBHVE+h3Gy<@zC7zzvsaA5xwI(l;Y7v_Fef*ZqHud$*$oB1nh`~nk4S`>` z^zLQiwRf!*Knwy^O3#?O2GssiY_Bv?Q@AM1{5GfwM;uNaaVP_nZ8&jkwjbti( zj|2d(_hLPC)7d;-hM7utOYb`x(A)kgsy-MU!EZk+Y@^SiUk&xmA8C_Z{fj+X9+xVN zdfyK8vq34O`ZLJyx7{y1sJapXRxTLQC6w9ztx=7;f3S8jQiGr}!OmmPu$bAdk$xiD zRM33goQ2EUR?1C_vss$hx8QSCf6O5vuyT||#jI7ii64W{|IteXTcQ4x9r)$Wpk^1k zQGeFJe&eZzcQdBt-8GoT+u|(+y=1R1T3n*lF!LWWPL-tmf5*h5`1tZF5`YGhK2abA)eTM-C z=yH6}ga9SNqxyE*P~~kDL`qzHBWT8)d{!i?yxO-civ6QTA#)+lnZd#RM!H`2boE6;IfQnyod2>Z`IeNwo2#nd&4&dV6iim; zkLEYyO3jO@SyHLv%h-&2Ae<}!jlNsa&LLH{Ehxyv*lqcyp6E7e6OjTMULHuJS9-Ma zqDRIpc5o405WqhM&(v;Q6jhCtC2{_75BsSnW5Pt$!!s;yN|C98He* z_?NR8iG>XEn80BL*Xx6>bpm9vCuNKqy*N2*XYyCn^i=v5`hy}Dp0E4im<#anRaWmY zL~w8l>+*g)C1YV7nVqC+!u!m9XJw%MAtD*hs<*ZbcIlB79$=$H>NP2n+|AnP!p7S8 z6dk0fkvp)h5EVMmBa%+QAXkwwIWo@7bT|&VL!Fp}b7F3=xaWl6($LVzYH)GWe0UJR zBw-{IHNN{xvEv(K@^wF2kI}H!+M5kpq`0jDpV{c8{L^U-f21I{y^(%+Mp6WMq;Up# z=`6euiK;kJ5Hu?H*jr@{bhMAhCNW(c6~#PE{<@MfG;`ngz>t9Nw74c&LP+OA<4Ixm z{wHs$#bN@|lx3b^SuSg##O&^va6=8snyCp1MuvtJktPl%Dbu7xMmhPA!@6Q!)_spC zE#pfFJ00RNV?L-_f#ve5P!f>79X_#Ih=_md`MbtitqG#)d-0Fh`2W8kHos{t-sdOqq zUafu_?lMPyk8%#;Y~NS^Hn7d9KM^I5cdmioof2Tfq|3+{a6uyt7KVRIxs|T8K$(rK zrBQPd4<6lD5wy&ci+S!_Lgp+s5jB8jL<*&(TIdv75(qm{`r|qXshsv$ppaKaN@{6- zo|TW9Lx z3NK0RR1*ev77lKjr?81mU_0E83Wv{$F-gv|!l}ynj3^sHp$(#>E#Nb&b0FR~Ec=qe z&cv!`5&w)Z%QN*GbQ1p1U)&MdLV7ym=QlLFQhNYP^PL zNhelJ(8=#lH+xprb9cY)PY0!CRvykU952>}$>mJzZuQ|(ooZe$S{`=t$3`Pq&IF54 zXu2&iQtrO#K8xE>7S@;wPlpsIauS7vw0?D^Pn39vEa#%2uBoVK zsA%}Mm&HJ`tumwK*@ZCr1n;#|Kjmpp^Vn^}Q|Pj$7H79OzV>l2d`rtab#$HdfRZ0_FDG&xQucti&zFre+lnU$8M`4(F* z&c~7V3t%v8O3d6^&&>(p+f&9R`2i_9vIA9hQ#aw%cneIi5?4)&ps@(=pL3>!!w z7UTD?-?hVVXZwT#iu>rmhP!#OLOVlRd2wjaRcif-!n$z$*P2m;K}yP_nmv|AwFrW+O%i=Ql@^MSsXgfJ2FkgI)ts;{2|NY6GUa zpvcHZ((4xlf~;$X(hnk6k7GDPvYZ2x-}iWLWm7Rj+LEa_CM@D^DDd)vn?TXU)>%^W zBhteJQW%Bb^>k;hFC5iZ7$oDSE#$fJ))<`t&ldHP-*QZ+OSHpBZfgpnKz^(nTxBTe zW}wWsJP@nj$(=@uV-hv8PMkg!aq$9r1K+m;J@$cmJ&s4qy2XI7yS^S)zjyI#6fEBl z5taPBXL-?z_%05NARQNHIOJnnMFR4#4=leZX;jkk;EE#DS@nG6NJ;X4BH(s9F5t|x z!KH;64O~Jj(j8N|a@2m!vlI(l%snn1yQu*LARLNSRJhw>{|bu`!@*;eqGZjrk5qp% za+^a%4d7MBGi^cbmuY${O+~t=XoM=4(3QIsG}baIBcA0+^2AncuXu8Yfd{SVMD{P znh;alcx5SAZX6h(H)F}Qh`89+ZUsh$%k!nyhtgH%BPcOJ6T)#0tlyb`*=&p^GaP9z z+ZXoB`MrKWn#^VibxQkuW6^4@%bTgvA%u@nyF`-R%_9Lboer*~TY8Dcr6mqX=x9le z#_sj~%+!+Tkq#|svEA6s3!0s4oogc+s>~%$iM{K}5xn+MMnBrttN$rE-=-%OS?H@L zGw!(^JMED_G{H+z(O^E4Wc1B-Fmny#Y0UZ_6ZJWnPFME&z5D_iV2~(|_e|{k2hPWe z;%NibanAZ4%;+dN1@n2}mGH;C<_7NN^F zuM>@|$j&;&x+4sAPoe`K&)GFA!?O2wY`v=8B@8Gp-fs@YaQC1F?-i-77vZ3}TVwUh zGYM9GhrXb&3}mF>PX}IDXkG_6=(Y6a?xC{*s|iHBp?Aj;_?S(@Ef%(F?A-lj2=un1 zIC-)tb2*2f*c8n`Ppv<=?+oKL2<9XxDaeQ`n;7LRFOI43F9^J>3rlT$#Xc!lz(DJZELMBU($*?dF6W~M#U)Jd?0l~>bnUs(nx-FT z1=UrU=QWYx+kl0gTsDu#EJUuT3akQT9C>VNy9!1sK{X79vCC%Fl zRt$j{LWM%bi>~+gj{7K?=6?hk}vb{0j7m90oK(^8vjR;ob*dVW&#w*gqHrU1jbE z40g|$I60v7>-R_JC!4U7;3i<3^WdOJP3!Hz7{$A5j&dqXJuJm&C_(zZfw-_(y|?;> z=so9b>>8oE?{d&o6czhj@;6+bA@YCT>i`z%Lc~PTVCV$cnNA&IP@+lpL6k5lRVF0V zcV$;G0w1z!vmkm`rWHk?0|;Vak9e;mLVf%wh>_*8v++c5eeAY;DyDOeo_g`%)p&=n z`l+x*SbW{_g9#6IR~PeT>!9lH)P5ia-^xCI z8U%H~`_)UceSDv+Ub}}F`1R@hbG0O*zn2DFAtzPSt@DI)KSdyTr*m$Qp!iV4?Aue8 zz3-I?R)U_Mn_cIk-JZEy3%|W3q#cvBBvrQ$gg*c4E=_pyV&HQuLcuC8^O*i3JpYET zuIKiq%NtQ|aR^C>NLK~S)q`j2<F>5#x=HC00=5{X{)IA zv=0Wog#)a1F|!J@N&vWoNCdA62P|)utQYtB1RhPI@jG{Y{rh<<_JLTwQ@r zV_bORvD;Q$lq`fgBx+rxEO_;J$vs_sg#v*=i4wUPL5(d3J1+V_sQIl-0xn3oq4fug z=#D6~CjX$HxZnRu( zloiU-;+0iUFG{7!&-m>{j^7!dH5ckE4rn5ZcGzdo`K*E@a6cm1C1A2!(N(d9z*O!V zsdu?U#-RX=J9td%kgqlV@6-ssVzKus{#`BC~8xE}eC!Kb9|x@xvv=U*CQAAZ>fiGPSB%SB`Zi>3UM= zS&?HZF}7_KZKQZ?<8hbRcsV0rOCd{L1}D;2rAv~n5j`R?L}5Y6I}C~#FRUa0yxOYO zNg*KVjqVNeb7P9jfnlS6h)7G5gs_!TPIZuVy>>KlhKb1@&eeR%<8ncd<1~~5(K`?= zO9$cytU-)7or>V6znUPlyJyJhDL{-$J1A*(1g$5D-fyh9yik91Ap{S?vY(V}eUTQ_ zj@=jibZB5;ho)BSiB`ZQg&K12EZi`LM1{J5R?_4mGBL6bzB-TEKx7#ItsRCGb4PcA z_S_j3pmVFD0!u2Vl+;iXs8X0G0Q7yBYHRCFyC~vHf9M0iZtPMq8PlAtEc^V1l!;Wc z;)6-NZ^R_vVaLvhhnejBAE%{(~Oq==;1ZKZ;(%t$42;V}3- zucW&()?(e@(iAaB>}H#HNHg^iEfrYo`=<=qG%9ui0Q;;Ov5!N~koK`w~nyJdACql>3jH*d(@!CnYS{6*uk31SC=qf~^WNm7Oz zYC7xmEK{jky>3_~mPnq63Q8Qtej@K%PB2gBK#zKU46?u&`yZh~1M?d*L<~{XOl7TQf@{SU%qn27<*%3B=YJC^m}@j@2~~FU|Jahjr7cc+BQj zRgAGsiM%m1_WfL;x^NPr8MPxMtV*FYxiFA%H8hNwm7|p2=k6$N)sJ3 zzLaZKc-Cbbt{*dk3%l}>0}mw9ovfOXIlP=S!4uewgA%C}X0IKN=JE+ck@=ldK5{gM ztOgZQtgKGP9ADLL(l|o`g55m_Hn+h!;GUhOU{JtnGZ(MKYl-QD&w>%Ur{qd=MdTj4~jl1+a!TQrTIepaI8{5+7iJ05z=ld&z z+BfZ(80#T~otQ8GdMp86B6+pV7l1-|cJz6p&r4Y5oZkDP-qu^5V^CWY_tPlN`66AD zJJZ=r(EB4UJgkAHW`&2-V?Xlv(9hOZ2Y#X!?=+SRRn8MQk2k~TjZ4cF8s}HtD~A)>hgCYXG?Anq?{21seL!=sit3E|@3xK< z(D67kyT3i;HmxXDQq)Y&Qq#}L*J;<0kuw7YJ%95kDjx%8U{_bie}`M`JS?q16V}}9 zaen$Zvr0*9e_{L+?{xCTY9T@<<4FPq9{#%_gxRQE=4d4xE#1oH23|ij^71dT^4!SoZRHc&jj5h89n8J%Z>7!P%i>qZ|G3*dkc&4#Ya^3f^P>jIk9|( z6Y0Fk-4=63&CbIAdNCd!h|}qc&okALKgHFbToxs10lGTQ2nx4um-e+xUVj{!SRNm( zhhxMq?k~nnCykws9DUvVKE!N)N%@qps%ZIy+Ez1IjVw)V0_h8J|5)w?`aGb zAfPk2Xvg71$3<7Zw95aad+Fnr*qP>V@rXUFb)%3TgWu}@XIXu*3jb^?yI0+AE%~mF zGy%E$_oV4svy)hNGkav@o}q<)#a`bq{mx7%sox07#$Il${wCIohN~GBN2;y<^n&+B1npZ z$YefA(@xfxZ(vFrN8kZ^K4@+m(zZ1|ocQVCsG(bO^ttI-n^6;@G{0L16Q{A;&ivTK zeM;>m7-nr+NMwxIdc@dW&5WIq-M9Tn@;*iQpKo7EdRb+s%z5twuy>(7*;sfPSH_OC z{LJ7xJMBCO;AOL2h&mcGcLJ#B+>zuqOG>^aYDB`|aSbHX8c05UX+uVI;t$I45xV1I^Kzj#A|jE<=Y~XRRrq$Y;&{XZ3O6KC~xZxjc4g8 zm3k%DS6~Y+&rQ%)mnb*Tn|%3ag_R2v(1F~!HneGV#;tm(*1IaE@faF^aYYhK;9j|G zPinKMXx|FGc-)fh1dN2Vk}|#nlbMma4pCZ{^+z&OydPBA@3_%#GDho0^>9m>(K^$^ z4wC%E;Gm^<$ov8yXBQQJWNrsOJ}AUVmtvjoGB>L9oSX>omUjU|tO>|cJ)Swkf12qK z8{A~9H>djFfc#FL!m=$})fcxzul{-L#)Hem$tFQ~?(y?O5UcZM2Lj^X84W=^bg~_D z%#1e*@&gI%Wk0Y-tLY%DZC0{)X_?~dPYky1mL>q_^Hi>f2=EBTcZapJqqP0uYrfW z8t7cRM4`5^6wSU?G5nP-`02Atw=ing}Y@l)F? z{W5R>!E?{>kc5{la?*ERa}lqIL7wETAT9OtjAM(E{FOLl>=C!@+5cV)rtrXA4l0iV zuxA#*W!nowCkfuRu%$@f&EWCrWT1o#qIt1oK}cT>MKHZX*X+I_Kh$Bbq(^3)Y@0)L zb7$O0y>j=bipd$YxH<0fM4G<*5(I!PA-WCfhQuTng=g(om+C@s#nR<%Z_g+2Bs-CO z(^1uYoPbfY53*xpB-W!YAMgf8YiM`r2yJJBt_~`t_f4^j+h%Y(vEpyaDN7Rbn7nU~ zL5cgZ5`#a!l=2manVc-zFt|RxndNdm(qyf$9YkC|JSc>&31{5hdEp2xD(BXO7uo4dd2 zrW3*3=l)^}&~~F_g+P8w{0h)aA+0w+>|Usi5A>!Cx%^!%ri@5t&d@}fjA;LTb^$E= z2Uc@lUyjR6mZ3XvD#3x>HQRL?H$O_B1Ib$S^yI+&k^y%NuAL>rLDq*Sn?qR2;OoY@ z!qr_bJ&+M)N~@E0Dk6gCCi-_qeYNU3 z!61$Vw>#6t>TE95>uCc#+!H>W4Rv)mDG@=b+yy8uP0rabsfWowe-$NrzD?~nlqmE0&2kHW1erj%AYm!-;XgI+`$(RuOxtu&|JdssI8}NXPu10_HlsRx&uP zM^Ku)IgiSa;f*}XE(9R@i3r{!m6#w03mID-5blBbH1uCrU|`m7hK{J--M7Zh8X6kn z6h;}uf;kdqW(f`#HbYJI7KXXFzs3=DRhC+7Dt0PqYcWu=G;5AjBY4tEyORCzD87=6 z0=dSKlaz@JNpj_cKW-CG=PZL2E~%!GOmOFpi>nQff+*WLCd6HqQxei%@^vVX#IVLD-D+y z)-p7l?;2G7#nM2!F|uH1O*oJ{(*J$+8~}pb8Ct#~AQw3W)#|L{S6-WT8KiuY>bj_h z#gmT+v}>k{ZCg&fNQm>Dfjy?)XkpI$J4VD$!}kb_QWMVT-h9c^T(e& z57N_A2U5u1PSEj>7v~oSz-+tfZOq4;3v8D-pY)NUa@=YKiG@`C)oIh^SXT34_2-ch z9L=36Sa*-6H4nAmPUqNn*W14K>8^ut^djODjc&h=_A_%`rF`fR$ZE(xGv))4M+B1$ z=;(^ik-{YsJijw@Fn1P)XQ?u<*JFSK8Z^$1tgCQSRD%8K@y?+NsV_v8r?_8*%-%c* z*EC4Av_8D4Kwm{!+8m|+{ApVzeH%A9V6#PU0eEn?5!Y``xdGWs_C=UhQQ7pvMhgx` zwq7d2u;QjnyFi+3$C-@W+t9AZP__Yo*U$}W=YMfVvVv|o4*Iu<3Hg;#6`Oqmp<|i@ z32KF}Tx(w`IKU~x;fS)SR_9>xaW=w!U%W;0BM~&%Sa(8Drb zj)@(kZumZ%j2y$R;ZAiIS#|4h!DfY1^|GH~=rt$a{s=~xCJi;F+oF;!5C=|B*%54c zyueykgo&|$3U+cbJ`#2^QYs(`i)9=eiVWE74XD2@cQi?XUhav)3=6eE5}NkDG9|&J zhN89h94Nd7Wfa1gfpDfFYc7e`whrgf5bHva)<+pLizpHe{Y6=rF0Ejo{Llckhn}7M z;%Gj1Syg0dT+#p&FAKBW?*Sw{N_T@p$KtU$KHXa+?B7wz{Eb_$1Bn><%w6bK8&n!m ztw88wDmb$hQ=203?6betj z^M;jUfE5%eu;nQ#;1lZ`rmjY;;- z!4y6IF3f(?D7vyWuLY5zMZV$k-kg1E zga+>0)xd0jej|z^*xiXtwkM!TeLz&ThI!oVdVRXG9{o~9crqGVM~Pl~YSB1k;p_0b zvj9xwQ2M&5*Nx}qfTkZ2XQ}LPC)!2+pCJQE264&=BVJm$`r8~v zkfU)9ZC41`xGKURGa~CddWG z;&&QGIu0tmhK2yMEQH@2c!}gR7|+x0;3*jcUV~ zR1?Cjl`NoYw59HmP6Kq-s+d-&S_wk4J&g_g zLjt%^J6}ouBacqpAeBFe&3pBco~>yg%!@j4oZsv1XJ*2*96SiVzu25d2Yai)rk=nf ziRUDXNbPl2xkkQl^rmLDao<}iKZdEQ0)Ik{{mO!?3frp=}GUiV7l{T z@AcUXr$qkPR+K#(dt7iKCc-nBe2_&(){N(2K+RlkT4#D1LB?+3k1zY5r+}6NO+yFC zl_#X{LT@s<3cvStGI&f(to@4zk@MF<#ya=kIzOl^JO=f$quCZxBv{!@UF+HBjv5pi z#4T}rJ|d9t4W*K6644J&N0aGI-e1+69c~O=pP8j(P1DoIC!+B=a_Y_iK4@y$G0z3n zd%gY*BhICAXbDr$?6u7EVj=$*G27IEviZ1$CR0hsATYblxAnrUb$sD7 zcBgLtQUShGd4Yf|ZIN52f)P<*N%@ZZ>qgGrQ>^QJZcky`!h|wyrBW!BkbX#*i7|#2 zfh-%@6-eLx0s#Zy#7q1Tbn_zBsdV`qBtJyI%3jY4EiWzM0glh9wNm(45rI#I&PLwi z&sW<*S}vRu>#8%{q<2+uAfG0!?pK`+S~?Ioi3xl~is6GcIuWhUOPZX1i7PAkJZUxLFL>tK=@2Wy+e`I9)As@(g1PQ}*8af7a5Du}{r4a4fmgPPo!faLz1= z2?J1oTCV^|wAzNb&e%@)2q}syIKeJJ(nsd=CY8rve$)D3m*8|CQs6>};=$R`7_8Og z!1&1wb`i4l-Ss?JmY9;TQC_pmG}x6_Bp06q%@aE-_%qb1CQ?yb&EbWNi@Sky1BZ(8 z0_nkF)*hagR+AaBl=Qx}=klL7mpgK9mxxTxelYNr4i9M`ZCq6V!QzWNC-wk;tZlLe z5pKz;Pox z)+2J`&!j7)^4CC0JC?*7cdq^R6Kos$rRVPXU2|6LbCAHVSfvk+5QhIUb{m&zJrJ#Y z;puhz*V(pG=fcA`Mc?^uPZbLasiJ{_61$~FC!o7?LL&vVD(f>$4HOaYKCV`W+;{9#JNg*`rFpho*-_qE?f*?H- zT3R5cUcrR}IPE*$xyT~N^bEZ$==+Qi+nLt+-t*OWqM7UaZVI$Hycbf8E4o2Bxt^#92+|hq3%zD#Z57P?3)kIDSEHJoQ_iXwxM_DG?Ti5#I-s|*XO&< z?PLu@s$QcQZ4vR6!(_d}?`YJZW{$fQzbqSmWo*i9tZ&Wg5m$+Y2*e^LPO8J_2BuwD zSdD#s5t=CGT0Q^C4;7#N>37!WP zjc^#}qnYcb^yQhshbDLrQEapz`)7*j|F{F@M1Q3Sx3(CQ)yNJmDQS$xo4KxkHGjds2{$pwR#oNHlw|#v}{`&wyCZS4pCv>n3upH@ZiNrZ^)pi$*626*8HwX9Yca8z`T=kYIW3*N~*20&@d-eWeWhC6bghsW^tY5^8w?m2~5p zqIGqer#UG(q&iSJwD2Ml)%Hjca- zs^8ajPkB_Ycf4wD{}MK1*odtXJ$x8}6TGwEz9CHLO<~=J5r=6fnxYscF=B>Coj}0y z1=50h8!%wzDcacC5W}WI&d{6Ck(z8h-dJ~Lj3}TG2^x?0Ou*2dG*J0wR#uFG!oAuH zYyF$xZ)(9^FsyK}yJ1n%|NIw#k`LV{2Yn(KC_iwL^~(Ll%`M7oN+wU;F3wM2+NF0F zZx_;eXy(|9T!v*7Nd)T>0NaZy=Eq8A>qsJd%YhkNxtoR@!!ig6?y)LJaEjc?4+(97 z;#Fi=U{O2$Z}`9NJ2n(e`?&)x`{&Zc>9B@ac=`4qqnwX6>Yy|-Z0999jJ7*CQE(c z3WxF+5M>&=Dkvf~yM~++bR&%DCETK}Bind4Hex`b4kea}EgaF%q&jzw z?(3RQE>0BN-_Fw4E}nRT3;K;hw;_T7c8@at9y9$5);Yz4Wa(Q@Bu`YJ@n!KV0;*} z|0~9?3v7faJN^gcADQ1!#r}=3L+5;fies3hUJq^g-4R-2G5OmncHSG@vDmMEKi{9y zaU(X*3}cUpQj(T9h&LuW@Hc8|ua62aOKxZMkf-$^?6!~T)*HHYWVCPPj6Hp8$41Lb zo(!gjoV*+t89}M#{qxw>LL{5zfX1V!XvW&+Sfqy+%kqmm$#4u4 zGV&#Kv4vX2wvh9@UcaWM>rHB%X{iT-NQ%o^~-Vq*B3-{U*$G*WGN2rs_8arQDA@=Wfn>$ zU`U7nf&Tp3dpT06CRWcOn9QbqpxJ{IJY(&0W88W|9xDUhynPWlQp}pcx-$!67f7is zafX)G=&kYhKGE_!FDN|tt^0mK{}STQWsZ+DwLQ()1c}1Oekbt6t#dvZVrH;!>(g(v z8-oHMQ^S*XvG4J*);e2STf4>|{_%TiYHO{%Qw?4YlJYqDA46P%1;KjlSl0e?r|9XC?bf|7&BHpzJnsXC;wuhLXn-*~_TLlf6x40;$q+mZMzs`hNZpUxCo zPN3&Ktf6>t%AAIf+$qGzQ(ALkpnRji4p*4h{PYGBc0g+L|FriG-j%Fxw`lBil8()e z&5n%@JGO1xR>$gC9ox2T+qQjI@80|S?e9D1+SjZApM7dBUl#nqN5s?)A zR2lo3mJ|{JpS8^&)OfF?!v+kk>aH?0VW?8p|4W0%EWC{WKzy{OiFHm%C(ahzPvTug z&Ex_PX-8D(7UspRt}uZNXliSht20T5?6~WvIjL|;6~|;9)krBgC}Q5`o*rV-R`#aA(?-&*h{D%2x^+)tY`Wa(`vykdm$N*MUM4%sHJKO%$DrD*v zWGRQ@kNUaSd2`}78^K6rITkbiKVA|;p7gsz<`X6q=(8V*Jjg^d@{LTX9pkA$Xk}CJ z;wuRf&_A;r#@OXfI79|ce^!ww>E_;0SxfvTTyWJfirDDq4HNW;*;@r=d*)&Llp{g% z{3+_&t%8H2{!np=n2Hu96^RnkwQ-U8E3+_aY4hr4_d!QHr8WZxX};7+qQT6FzJTeU zT+jDeILm76`T1;R#^TM(tP7GG2NB=mm;4Zs&b&HF z5DOpB7SY!{pRh+A^3_ooBTsmYVP#hUvvtawsNU-r717Kt#R*3QU-gl@(EA*2cZ8RB zPj0#T#axa11m4AA~6qQ?ZbpKV{cbo%(cl+t}A<>OI2*~?ZsdU%$psP?RGQxFP;Jf=js05!sKOaeN zeb=Cf-~WUv0{9XDL^Ha!D zu^0gd*mes9tN$m_MNt62Hlpkj68h(o{-#Co35oy?1idI2(7df@0NM2P}|apmN>IBHnGR8RYjcz_VjT;ijA6Z_rkJ8Q!DG?VXI${|=kb_dWT zyt*gMdC%OHwuG&dvwJRY?!mDx_l%-qDsy?3JtqyOI9 z_5*qaV8en^a&a^qHx)?t`dN%yh=o>ag05eF(S=?2>8cQm$#tHpShli6mc7U|;qahl z-7_}x&s3C!2cR!}Fs5oNa5ZF3v~Y9I>Th6q&EzhtY>6t2E3b~l*@aC68;2&sB+GkR zT-l5EE%On$pChMWS*%^=FV=N><0*Puw#3{j4TwnZHy;lb)~q zH6@3jSt(iazCLG#vObLz{No56&!85=)UchGwWuXc1OOiT|5Nt%Bl%y- z-pXuOJ$;WA6a508VFiZ{{569bYQchAb7F^D1S&)fiK)&0AQS{!00`ZCU3zX|zLmM; zESs|kP^j_0zUh+cudU;;=e6(Jf(jv-ns%uuS>UjylB(a|s2XXtMrpN;hK3~NbPKp_?CgD`$hb!?h)4ysEg0!Q?fuZ|n*@!j9;J+>+tbJ1lL>%H)RV4}Q(_Z7`VdLbd5B5M#@>$mQ z?#$=65#A!cqw^{++oknQfnV_PBUbUF<Yxs+G0ZLN*ddRqG%e?i|mDp}lVj?C@4N7J{S)dK^l_Zz|Hr?c%hvgTU|QmI>|%^K;M5n zuHZ+IgRRc1W+}+EMAMcYrx>Otw`v`AUb+$^spP|Y5VfheV8>zA{&x6b4+K!TG`^p& zfB#s-xo~7ttXEco;4ED-UU+X!@H=4iuqR0Mq~$3=yv^Z`5Kr>s1@plW1NyQFw2gJE z5FsX`<*+BN`WG4e3z7vP^NHyWX%0`IZW&z?xPpZSHB+RYWonV6pkJp`~3SayU2a!x4LI)KW<@| z(T*CNRt5XwSBaoL=DZmu@p&?h^Ilti)mrpc_(ngi*jF7=*W#ioMr;63Kjx2Dj@_7q zc)U-Npc(+GyboODhzBsbNbtERdbd2R$UB+?NeDJe&Tm$G=o7y)A(wn1r>^^D7_zJj zk&7Il*w@a9{xYS#MP6nl10EFrH($zSAF)s~wZ6RdF1L+);H4IT1;?U|xK*sN=Ig^M zo8K6l@BPXfB6VB2YKvGF9Wh+9BYFnrw08Oaxk#_)HvM#G7jSH>8n!2* z&0R}DM2|NRmM|J@tEgRs9BL_~Zm}KtZkUH$PO-olcK={F+sN&bHvZc5^n@Kokh(|^ zK+gN?>J(g?mmPS};tx*DK@!;GY5_b0#;9GHo`hWH(FNek&xOi6nY3S8m#So?b%(k* zi+o`lCyM}M4mDqGF7Ho@DoHAv#nsK23Gp{IlG2={N?G-Ry)xKj=@2?p|po*gOH4t zI5ThqaE~`jIo!gV@F0ovX`z@ap_cYt0{evbgVdhd_^lA9;Ow zoUhxS!~jh_bJbyBy}l6KU3HrGW0$vXa$9P$Wpk{L6sQSoZ_w+E$7xoZ4oDnsxS)xV z3>%Xo5x=*mbYZ7EO)<23-c(Kh-QP1F+-a zQnuMLsMe{OLg&fmPf^P6lVhCdS>GLjWZwY&m4`E2UUVwQCJN$|KOp$u=< zy+Q?`ON5S4FVj!M$Dm3?3ZoIHWWNI7Oe`c2sLrombovh1R1PppI(nw$NIx6Zj)-YP z3Y2fuvkQD+=TW!011MFtfG~eLh;XP?9zA&o;?h{sNCmR|C{HAX`Z}qo%{My#OJJrm zKoono*e#5RS(U{7hxwRWv05P+<z14MbZm@lIy!{|;J$hhB!_=+)C5 z3+jzu%LW+ph)}~@>;aIaDs^8;>5>tAj)|%=LE&3;1tcZXOw}FxejoInfw5u%>}*+p zpN$`g!R`pD1;Uel>p%*j)YTzw(#tisaIU>OYtYj=z}ljrBoyGP6Aa{H05H+9ntz5G z+}c}uOC(b&_D~zMrWW0kP>j&d^C)X99SFj!P*Wk}>J`j5(Kj^&cP|B)kCY36W?QM4 zC@#wv)zXuZ4fOV^C?|~v7xKkb|5ed;kwtPbu%4p@8Crr;-BQWl-OWS@y{|>)#ZYUB z-~qRSN(o*-?1DCd#joRw2NZy!n(qNX+|SYOK?e$rN6)n}aH^UxKSygbEW}LM1qura zuykT^q4w?n08!V;Ii`)K7XS@Amm2_zQdU>zhZ6%Iw%1kdQCIEe46*U!M(}(Z46eH7 zcMis<>mw%ec0!;%$45_VgrYbXnp>E6T53>nDj`Y6Yz`LGeYxJO5zaUmG|T5Vxd0PcVMe^9D{fF4wp znRktI(hB|#4))|t3jHMr;cgiKmE~(|jDG>p-Qkwm@ZGH)$ha@mXqBx4J0rF~Y|4*7 zqU$Qk^Z8j6TcL`&DhTA$jJ$ocoyDNyr`ss}F=hG2g;{KpO-tQB^;(v1%wD`c75d##^*Rf2&mGwmQrK#Oln=_f!XXk6ZBtSso`qf8jK%LqzyZjqh@(E_N&Bo2 zm1pZq=wZ!^ff)1C*9Q{NCBe<3hh|YYAyW=}EI68LtnKU*I32&e4v-_h&OuIm$nGgda!vi;kl6dF>bN?BI{tx4fs}q?;%JXQ zrxd3vV=BA6=166zFMA^G*Bf|nb=FST9A{z$KKh4e*sDcSfXf&dC`zUp2iF*EKI^#u zb^tkRNM*l2@Y@_9E3*Z8D~_AmNROI{G1)A#Y{_6QFxKBXZM3`5xjwoY6u@*A2aCeC z`X_Uc(9TUh|Qq?^=OCK#H{ah+4i0-e zWK&m0C^&kgzJ-x7I5(5x3P(?A_q6jqqStgljJy6jy7R_f zQ+K)=p>7bz;#^l)j+jqM5DA~nQ(H%lIFew1%i5kpK&P} z-C4bAP_SgKW2I#o#hE!+Xbmc^^x%SUO<B|o;sXWutig?r6TNI-bKikmbx;c5nZ)VZ@*|iiod41_weRGXOV&b^UDgjWoU2-sF z`~W~-mOgT1ftP5?nNM;SdaPw)u1>j*aZecc_{tq*7!J{+f`C=VA9WL%7Nkqm_4Rsm zN`6WOM;2UOTewM~wg4bYwNz^$N!7xn9VYyPC;@>un#^~6e_WTLdCUq1&6%+M ze9M0R*mPNX(ffWyLlk~F6vJ`s0?_7(db)C0=uYlXi5TW<{B*eydCs}Fjrj5#wR_EF z-a7__(L{_=>>bkf$HG6|Oyh&Alqb%)-5pBg#X{Nt;2@nf;e5CdTeC>y@PtqWkEbxh#qIO%)+5pw6$VN8N0Zo8aEV%56~cbP+s;Iz{Y% z=b{DvolM99Hx8RwN*SaeA-?mjk4O^*^Hu=;#jM-IC<_Ueq@s3PA-e8y-qf?e&*d+F z?$;#<5fQq|Gw2tY>_2?BziDs40zgpFsxoH(5)u9dp>f>+c7KfW3LO78f#L6CM%+jL zbKm7CF`v;J(+5-$=>GuV09wCa|8rj_Qxwn}CuKquJ-{V{j!p*jgW>wAZFqPX4jx`g zQZi$MR&L^-TJ>Lo8A8ND`x>5#N^(}>f}*QxQpNGc8*QbwM)wbM3T#BedtfeWI;1 zlU<$X+K;0mJ8kk{L?93V3IQp}b>wH| zo0eUqSP{ruv^L1cgYjZTd#Lss`UrYp!M6`+>5tpYK>%X|HRLD}v5*c-&MrJVTHZNW zNf^km>^^*m+l|fhIb(8i*RR-y0P7!Q0@=6udVZ&4L}vZkS-GK~R}$kFm22YbZ7Uu# zBCn^5OJhlid0sIlD(c?mCPB>Xr77T==)5PDYPJ6$d)|=widb(b8EQV6(NUbkH%D7$ zVVM9g-d!dDO>mYD1i&fJgtwZ03HA~1L!3JXxb{6ZA%B28VNrsILH+%R;*koo2@6NX z2oHq5ySQm}1;1%e>r7Z$aDdE&hle{lIPAXA#trFwF`pyfF08CXTyN-5 zHu5xm`eNM+2??2+l9G~~JS0Jsvft+)Ab>n+eND~n%hsCv(CCazO{uxlhYTzhXy=RK#3`I!3aEL|j&>}#N?LkW1-F2&T>lpE z=+ghMm>2;S&BO!;Pw_P)mbE0}w)76FMbNx)|TXaZqEA3i@HJ`>796-4fVojG@~ ziZ>PCa6Enl9ZsiTC*UZ++zO_jp}3)aqoV_EwTxnuSFIN-F^!zCM!_ID-Y((H=ie99 zKHMJmx70u07c$-n%OfeD)_+_(UqB1eVxICYr{ApK!_KL-CDmM?G3f5JxaU^qOGja& z0!&iohB2$&BRD+wgv>9FmDw^s?!S8_h&YQDo_s`}EDjBPI}CNcL(O?j1rzfDd)ELf z{c;jzpml3+AE|zs5Z7jQAH9z3Cb~qv@cR0i>HW@5O?}!O2y0fy!NH+6xg;8e$L;xC z8yAOsYbziC5@2U&xcC0{0t*XEn9i^iLoB*In=h5x{{s^=p~LY+Nn3j(TQFGMjt^_} z{%obn9knOBWGIe|xXJrsy$ux=HI>a;ByK#Nvj-BT-eQT!Viz6`?sTJr*UanXjIDOL z&OAvx@A~HEWUa+nTpWfgncaRrnaTJQ&R0ZiY-~)-&^Zu~&g$&aQffN7i|k-LM%Cz$ zNKZzV>8Gc)I>+bRq-W1oHs>yDbS3UZaARYSI6s4jbnnnBTUna5IHp%^(Wr?C&)Z0! zJ5gBe)%YtB5AxY*UT32yEia1?rnYX+v`B7z?8oEwZy!8Q(}SPF$(+QSVtJ!6cH$=c z%vX&EM$F-}0`!+In!XEP{D6kNcW`kxC)G<-9vAy~)8Y00HQv#&(=Fi~+zBEmv7%W7 zZzErpwgg^+VnTiB&Od*UXr8I&Zq&6{38hU&EiHFl67||Pk%0EvQUvLOY2L6 z`$0w}aJH2g>PZv*QMT7RZX50g9(pTB6TwN{``ZTZk6;1yj1VsiLo5Ssv;Z;C9_3ZB zmhnX0+jQ@UuFqFns1z6|5`j6#9MqI4*Dupe^XqdenxmK~hX;Be!xNYzS2B(kq7FSR z&8p+f1i+sOd{+{D>I^)!Totuc_m0^^>m2XmlFFK>7<*Ut>_~>{zYCBPcL*2ENTqYs z)z>@q1i|z3^MAitYjz9|2_dJUk&>2fcex@GVug8sfA0xK2)+W$epk@Afc^$4blcX} zCi(-z_HZ)0e?O8M3m-pItIbUp7)bUL)2S{lqru?w-AQ1A4|&%VZ!ORE^Y@#{lS+Ip zm&iqqSE0@P>?_74P%ni;m=U=KGIxnM zoDa=(g`z~Ufj7LAB)ern#~ZIGt6mYj+0z4TQhn6+rgLA>8!}cPPVbDz29T(yQ?n@6 zdo)p#i3Sb6m1`y$zGd+TnQ$xcpw)+?4Y`RMTWj7eYY{rzE4)97v8@^j(BxcG#a`pL z5hEgGeb1d?+f_EHT5>aKggnU($oSnqBr7{|#W6R}LHs-gKtAGP zV-^Pxuj-~i1u!`hw}C-Wc=2F6M;GNRh|r?*{O_PM zxH@&|=;$Q*xxT3S=!tMM!e{w@?<_GTaE*y3z!GHV$AQ)6PN&@vt5ja0qBN_3P!Mb@ zf2ONvp(7~7+;n13A6nAdvN=29sTA>Bp`{I4IpT?K?_Nf^rOF7Iy8V1sv2Sd6AebVUMB7WlxPI8-`(PCb;(UhKwg5H0cYxQrBvc!5FMLC7TlcuSr>oHJ7L+l~ zU1)E8A7>43<~rt*5cv*f{G|Piv!i7hge@=|n=&M1JK3;YlHXf25Oj2BnZRbTculFO zAV=_POiXUkg6WAPnLW%)5LSly%DJxv8cCH&-SX(DWQac45fVrgAdCqOMY3Pbe#|}% zWY;Sx$+{zKK_V6XLi8*piT~z&wv37ZmM@tco0teOM2nG2(7QZ^4ReT=<2{+hkGLmR ziOv~-AO_s6ya-EI8qkYw)@vIc7PdJW0F8X!a>27`EXY^459Lr34CiL7jy4^bZ8MKg z#g(k==)AiJ=V-vPX^1Ps0(PsuWsC9jQVXq}Ikvq!eE+E~fKx4FAdHA(CLKSBbio!55d) zU}peZ;QHvOI)SRHY)6zBUw3pat=0K=5Whj*i@+q0(SXRMr6f@ zU3;ri@I!ff3r)$9w3@q{hv4@LiL5(=_@besKsHlv-& z$f>Jd*)JRwvQd|u-C9lLIpP^FM`kmrQ3pDvusklQwPYDD{Ol zRe8}}c>eMRVw}%VNx%1${aP7|u;y!MOE3)+0Pw>_&G zQChweIX8P%KY8l-);H&<5~iaM4G%c{QAFH!fZgQKHJ48Fi03;@&0N4bUkaj-T zNB(gF<4*5OKa01|Cu}%)Zy_e;0PGy6VBbp^T#ppy0g6G-D%}}yawBqVunu9SLAOE} zG0dv{X4pYg5r|0J=YU02JS7Z4#1nO`&U>Iz%xHANrClAPzMnFY2OSK2*VI%iK|px? zy4s~f!{|{hmz;xz18ZmNuNCYpdlb9xc`XasUsB006$+#)oSj>rWh#ow4H>DGZYXPg ztv-=Hs5m8)cA|D`J@=b8PZ&+;30WjtQtwRcmP^a-gISTdsD-vvUB0)=u6`?x2Tz(oPau$ z%gNFP6$bv-j5P*Td+Xh}VzE3X4M~^d3(p8ZxcncKbEw5{j8<56zkmPk(=hoHgFq9{ z^@%jW@&?r$&csc(dV!7T8Z#hCm?#R|b`m@OZsDLOqE_G)&)vI9b2F|8$#x6PWz&Xu zyz(s5w=-?d)a5DvN%HEmN~^#?>pO=TR!hlF&^n95VEV!oVe0R74hVV?4ETg}O9hmF zg=9;m$Nv7??~W;^&veSc##z}~E1eO!Bv$%6z6H#)hER)gpT}uHBO?D=BWd_MzXqQr z+Js2|In^pHm|6_GTZ?4!&7Tka{p!0C0c7}g<|NFH|NAum?Byi{9)9NC5RR z#cgV2WaP?T;n8+pgvMptiNt1ycgm4dZY%A-PHg1}qV!{ahfKMbw}AtK=_Bi?q@<+i zXsmPf9kubW@wO3|nq>|!3G?F7aU>{PPU}twiq9S>i@$CbhJNXY{j2?c-#T9nSSf0m z_g?VX2|@umZD2FYUGqah1kPHUe9ihQ2ZSYl!Gc-c&vx;=W(xDr=Vv#eB8Fxg=vy~W zBO@adlft`lF>E+n;_)2_8+-ef7`)zkK<^B9HgdkUeRdHKPzmjRzuCh-9rZF)81!s= z`*EWBpH}caA<&^wVzFXLZ%ui5xqQAPQU?~g?SOmX?;_;9y(cSV5iVue;ag zc0E2QT&Z(QCLy*`m7AC$SKxl|W;i%FlB*(uaLc`jch5oX7r38p>=Y+=$SoSr^y z{j$L~?&*n`^-EEul4A^Gq5X7C1_8m%w0m8ADp0f^D0L8NpzL^W9|moQbkKgF@sz60 zXg|y%*u!01>sGbiI@z10sJ7NaC5Ln|@W$92z91Uctq9Y?nM87O3y)4!`L*XvD6`Lg!*cER9Jmh6xL6LE2I*|Af)59e!vivU++^#HK!&dyE% z&Or?R8jSB{%}!|FDEBA5Q)nmE-pU2RAbD5=5e@Cky%hsu-o`^ZL23(LR=gK z1cbm9Jk|bS9GBe=Y)3kU`CB2o?KYU(`AmU~nHit2}pgLxU!1DG^PUU4~fv5f5pkv_P zl002tI64S5c-(HC+!&qQa1laS5h6@_y-*G>J5jvdkb`atMD9F9L?BE8z!P8S!3aPp z%p^I`+bQ>)CI>)yzg8c2(Pm0Vc9@F6{6xBQ7hxy4i_d7M=Sh)w1V}G7LJ%UtFCXu}uW$c)ty*g(5fw5-_Sb`E zB%Z&xF^wVr@pAe&KN}lBtEDX&6%agd&_BN7VzsbTJ&XR*Pb;3n%SzoM$@E@>Y>syv zHYa9edN!ChFiRQO_-bO|Fdz5NB(jJGd@}3?)rTMTtJK9K$C97n9!>5uG|6PRe1UY} z<4UEj;P>x{vmOmrYgw=o5)#?1bXu)Y!XbVg9UqrlJ-V&7J0cze1I~w&z`nZH*4E@B zfM<{Suxf$Hhz^2_g(B_%KpMKbx>WG8KElFa#1u{D7Z+91aG6cMi-{+gyJ3aC>4=8GZO;$9rLrjT~I5HW% zy~#WYbVNK(C+c|x6(JTZh`r8rCgGIXW$v--Al* zmMR#vtn29_gNAlmcjM&S }q1fmsb}frK3qwh>?99)9@_9*53Gt!uR7OOS0lcfX z11b?=*Y{YtAI}dLX8~C*4}1qZO>=d35GI*t9WF9#6&dmRV+@uo;k8wpwvstBPM7iJeHIbok1?wypLn+gS5ablJ_jtp$wor8I+ zDK8<{g5B8PZAzo7-_@pHMg9u$_&``?I-9HCqkiDvqdWS%%)xv*3$~%6P(Hc8nNB!XNj4b`V199gpPu8y56QvFOv94#P?T! zGl&FKDOIJKPvZb6Sik`S9#;rs&fR1e20ES|c(v<|QFa-5zEnRAEv-nfmR67ngAtgo zxt`87>M`bhVSrhZ1Hv>H7Z;APE|X3tP{4$&&kqrJl`Zyq^kwG)utJ>?nN_ z?@{Dy#ixQl^eTLfTu*w^zoEVM`w{V$ic&*@$T8WCSxLv9keaP zhLKScaa9-!(^uERIs%Zi3p1hc#!JBe3c--U@!(%x_ zv$cxP?haJ>`W%oZ?17bnw~TUE=o^e!5mK5<$P?I#elwMwfb@v|8c>V|Ue%Q68u7~= z%5kU3cM@URw3hag3$q~&UD!^x#S2;iIujGfMdO% zgBztT&e-abv?VqGV6-^$NkUZx{nXgsz0?F~0C?KX4uZQv|U|#19mMG~(`vNjf+JK_nq`GXnB# zZ6rGpF$~>1Zuk2vLXOd~u|W9kb3iuT9_fLBvAesg1MTa>kO4=~hf_rT7-W4 zAp3$@GLn#lPL+N=P;)!T7YAL}K<22USg@2NTRKJhJV=Nl>Z7=sKK_beezz`Kz#xr$ z7`QH1p{6-(TU!vMfg@ltm1%s^pN1>JXf+7<5QFI3<-Tt@({Z~|H!P3IA{~|By&Q!S zFC}#0ee&dNG&{Lt>X1;aeG?F|wUp#c>I1ljI@pPB!`o@@m-5tXE|h+7YH=}l>(6cZ zl>?6tt~Y(p_w+D4c3-Kf5of{W!tLNx@X_f=%_X$RbRc18VWFY55;F+UWmsLz!suJ* z^BPa7eW=$~aj(5xH@Pr$w_8h(udw9FOq0(mvNkz5zucc6b=u$0A~nsa5A zbG2_px2J689q;ukt@&eCm(&Ur3Kf&kp9P`=EZa{|T2)K4%AW4Uyej?P2@jOX5b(_twj-s5jHH18d8jcM zEfRzRK_afc|E;$8hif(!GHEP#=jXfr1t=@NZ3(PYWj%lDX`NNNZ}vMiP;&>$v*1ms z)xtkI>ZLC{kAyk;@5y&4q90!ecH@VXNq|um%wi<1YNckP+JeW?DGp8bXnY-*rXl;<}}Ro5OH1*##h$7ACCO3fWi%3sU%QAnBzI{JPQ zUh_rk=*yWdRj`?BjEsXsQA8&gOq0~Gm5TdR zx68I7I{DT2VAEi;nC(IDdZ;V;*W0|NvRJ{cnKvcZE%4Gj1SI~xj6a)=1XA=MPGjC{ zF4KQ@{&i^Vb5^M}8WMa8q0SsAj|6kX_2f`-cQ~fS-SVi+skN9g0tbPV7eX&;% z{-P)yNm&>7M#G@IVoPMb0MpbKXZ_(mrdiJAEvX*6vs@K5JT~xJnqbB(yrif)fcwT- z3`+bX7%`2ZTsQeYEiAT~k64*lx?pyK?|T1ojAbchskxDXtM%dD+E>uvT4VR|ZvJ{P z`z`Zlp=Rx1Rr@-9N^WkcCg)q*!+cXCGgPjz(Qpz?4X?M>dT#K0Q2}$IjEu6!O+>M? z_1a>UVE+_bb&I~=FJBf)fWX_x z`fYTGj`_6QLTSuu!hq zQzRc2kK#HI>Glc@H|zbF?cdf`>U{Cs7mn+8Kg&O3y;>+PsQ@cjkUuOMVHdQ=G+|<9 zWt9jdKT-b}p)1zyIcC91mRmwZ&9fd|3FmAddN)kA?znn-nIAdb zCEUrpY5UAV$KL+-`uvo#jT4v)D`e9$Wk31t8XNjJ3#y#BU}j*+;`MrXV%ieZlS!}cHuPn&M}cjtAoW?8R&o%tYdGl`qk zT!`bk1<)G)3eIbh)?67#&ZeB(UD~K~L5{VL#Nj?zK?01-`=^>ZVO1E&gU)Ow|8p+| z3}yM))T;fn;!@;eADe^Cax@2#(?3wuKY&a)Vx>~8mx!Ll^HaC#N1a}G=|oQV8)Scw zTCe7fG@`lphiC9oO*#&aLC3oq1(rrDxhR46mEKD--Ou* z%Xr?ZyaaUItH-0<^;Y}&e>m&T=s_J`Cc{<&6^=`txO}Mdy!B^3JqPCWr0Q%C=Q?Na7kZicL!e=^Lyn7 z?yllte&u)N+X+Ln)jjOqFN zi?81((I*O*B)FT`6596kyB3MYYgaAR{(}Gk7RrFXs=r>s-%K490(hC7q1cHse$bPdH`aXXzRvzy0|3@1*9hYwiH|z9J^IoJtq0Q#@(7TZR z+Vp&nt(@VsX@~Eoc{G$hfF{k;WPqkbk#G>1)qdOSl-!Otg5cOPt}?2Vr|Ux=m&`fi zCc5bNuj#L|8>}2k7uK2T#qA7VU(^Zkqo=wTuM^xn>*MN9Y4x{INiX3)EHGGLj@T6Y z-$wS}u~`+)7G-^Zz8%d30qQN?RoPAhp9EFEI-M&71!LPCB9)15kHyKDz1)>JJ6rS3 zY7f?Q=#gKsO`8U&iP?}eWR+GdP|jK96v>?xSG2^J(Zx~Vq-Spi%EQzJm){qcMDld$ z#gW25WpcVahC)ypBUDkN03Z+v33$SLBZMh?&b+ow_LN^<@1?_I4I}cIBD@_UxG14~ zJd_ND({t*h1Dmjs zloN`xRaFs~;(A&Z0H#m83dRLl?d1T=Q5LN>5m?s2dQqeB^7`s+3%T=(O!vMY^rkDP z%2DOcdvERej6383E?e1BhNdqOsc93VDPA9?!WT3Q}gdTwJb3JYkyA>2r ze;DM9w)Tf3f(t`e-M>(!m}NVY92v;_@~>6V2OL@>?o_wSi!Ac!Y9w+dH=l0CBwm+%FwglSbpP(V=K7;!)c}_hU|3(eoKYZ**?X$sdyQ#K8#^viWpbkwsTvEfRP5 z{cY|3ti)v#*itD`)1p*DMWv_7-sz%UeWfJnQ#t`SzV#r$=6-shKzE+n(I|h7II6J0 zq6tf$?Vihe!P&6DyQ0aZ{(;wPWc?XB;NmDx=GM)!#MnV&FraDZ;)nAkTq(`hsMotn z3OZ=`n7CYuR+~d_2;z=D@5x=K+zh_0OLJ%QaQm#EH}|EnD z#1;QAvwB{*i61{-EQSreSknL5#KgE%5dlB!_OF1(x1LZZ_!RymA^?4J^Puo@z)$d( zG3w}o=ZEc~c14AZ(6+tZ?xJW(V@j00C-=8nKdpsCErljGVs_E55ntJ~+-CI8IiOFJ zln6`97tBUCj6eF-VTVU3(P&+A6W%oSBjKyzpE>eo=D3Kqn9)ET_W~EiY$8}-@|$W!t^Dpn(ldpWHk3UvLFp7)_W7rs%o>r2eowg>>=~VZ1!)$3 zK(o}$W#F21R#t7`xTq}xR-PHgTWrD~Mb`AEF?;_#aAXw)N_hvqX!NDkq~2?i8h)1U zYEMkzeff7?0+3q!_)M?8T~EL*4I8AvP+5)}tLsYe{--g0z%1f@95({=bH5+5{_Ela zRT?zlVYiiLt=oSE>HzeZ1W^Bw;L}C@zwiCO?eKey{NMiYr=;?K+u{GU9eh6^M|mcK UNHJFFfB=8rgr$Yb1$6xWA18mlZvX%Q literal 0 HcmV?d00001 diff --git a/docs/screenshots/issue-9277-before.png b/docs/screenshots/issue-9277-before.png new file mode 100644 index 0000000000000000000000000000000000000000..de24784409e18891cc89a677429c4f8c2762f927 GIT binary patch literal 29887 zcmZsjbwC_J()O_cK|=@-+}(q_>*5leCAho0Yk=VH?!n#N-7UEL;`VLs-h1Wl`(xRG znVy~Qt*);AJynD$$Vnh0;2=OiKp;y=iYh@sKwpE8XW*g0KaE8#`@nCI4oVWj5S0^n zN8n#Xjnt)#Wo02~z{l_qkRfIeFn=!rzi_}WaPw?P2x#y-y zIv+5Y4;1j|*evFG5!wC8*jTZFi#t4t_$nUfGc0|(*f+E^z9!Bh!TkE1X~2xlb@B5& z&sCNAW~tg>x6xuz&MP6^7z>r_z|nCgg!~38xV?}a9y#HARU#C$#kafjgbjCqv`oAt zCl3G`R`UHhYpyh*PCp2=`7XWMFrV!8R05g-#8y{3KGm^$w>ciif5E11Zj!uTBYnLJ z+1;mTf37q%rf7dG9C=Gn%U{zro4_+$VKp21V%7&Qr9&#_7D=Jof3~ z!GM}Xcx32TgSG0Oo14_|@Ql2Gl*xo-tqDM$H>bvD7fp4i^F?W;L+9yA;^^Tjb*8GF z0-vAGYOUD0Fe7yH1>oLSm^+tjtRrDRo?|pE=;gYTz za!jK6u|HG)M)@HKcn74aD(|SOeO}~=bKzg#nBCAWE8m)R+rr{sj=kL1;iru<8Zb@( zT{gZ?!uw#SBn+~cyrHM*Ds0TmU!Qe*i)eBUS2kh2ak*S}x-`PfGvCPZugu=` zdyj8w5H?;ato$S(s6qiTE8ISg#U6YYB@CS$gq;LNSsfW#al6=zoK}P>b2q=*QH}R4 z9cB=FgAfAKLVqdr+cJKouqv4P%ZjwnhPUg{-&tmc;7-z zLGy87WvMf&KuuK&DcEKJF4#?dwBYzn%g%Q=Iu^8@5TeHdV5zt?>PpP)2mra0#+Alxmdq3 z7scCMi!x3w!ad=X@Z-iu_oE%zR79L@nGBw}{xAYn@Ajkwyy_B6@iyjf-?CMg$s0p) z(!Y4hM6hR;O6cCBQ#a<@KdkMHJSij&VT%2XPMVYgJUbAKEf zjf;)VmrYZd4c=&1bvs)HbhBl(v$4y3tUNzlRa2b?`sgs69Z))*I6ubEWedgT<<&V9 z(d6*Mq9!_@`HPjY)S>U+RT?);P+%^6uN;45ZgiP$nBuIWqhEQxQ*huph?;yoUhvi% zJGR-4_#mYSXCjNxd~hZtka_aBRoG{RXt3}$*`gsh$~@V94L1=+Ga*ywczybIw`qsF zueke?YO}-fy0&#hSdE%;y%1AnVwkyB0`@%L=;^)Q{Y1Q;*Gf7DI8L%JqMdH*d0yR< z+9#cS%jI8gS=A2Y5ah<_Up=)*WUTk~fW>FDWs`C5CvS6;Z?f9&>Z|eh9xqJHhnbu5 zgfc^vgednuF795{^kz1eZ>iW;M0*u$s(2p?pRa~|ml|8GJWBbrS&EwcWh_|Gm$)o9 zM!VM*r+Wscd)D%e4Fxlz+t-#Smr1Hbji?EM*7E7ClzaEj!m*ntS8q)3&sdqu&I}>j zo)?vznatJg7N=w9o`j5ivEC(t*TDV(s=F^x2-r_Mwkt<-xfc{L8?(c&!vd2%VF|C_ z%8pLfyH}0vB{+bT5qcbDVfbr@p^$RXg#DRszbTCt76K2R*+YbSD05lDZ|6;k-eU*| zh^@cdR7M(I_wqqGgc3a{^!0974!`DLZCpSWg=~(>C1)|o@1PX=xDLj-xLZX}$kI~T z>{%m!jF@ET-#_c_kola;0xZfwnP%LCZC&5J~kRC|I@CNUWjJ@l`g z`Pcn;;LAFeJ`ImAto0Af4fF&;c164Mf8T^GT>9z(P_~gkw9Y+E?=ECdV=MgteQNn+ zq}QzB@~|otBi}Y-G?BU6cz$g})_Y5RJqJA4t_4JOtZ{9vpOf~a`=RAlIjar^ZbQV4 z_9(dU&GH|$6Z{}xcepDYN{MC&3zwmNdXD-1;L-x89f;Cb=xld!Xcecc9yNX}u>vyN zf?%#NfMy*Bb&tk-YhvBURXKCrxU21JrsdX9-(H16zyacto;eyDS(`g8YPWJGkmx!2 zX0MqAGG1((1SUz(-mQFS9E8U;>t>X>Tj)KQ91RTF4X#h@{I({Y@I3AKxvYeCgW78F zKJlWc+*u|11a# zV#Km~3Z6e+xw!;?@7k~}DeFL}AY?V2+8<9dLbY|58!oTvl^{%LaZZrSY}1}t`0mtV z8pG;R**8C(SKxMIUa6@rX|-BPvPVIY)Xcy5_M*H}BgXA0iBXirt!gCW3q0vsRV9Sk z4?$M$f7=s@YaQjXY0G&^izB@~BsMAb=CEN%h%fdoSCLWOx;$hrEv;*6DeW=&1C5YW zH6|@k)7(;%dmB(oMoP-Fx$yY0sB}bSm)hvU9)NYRcG&x3Yksz$)Z*jRHS`Wmgj*%3 zOsj=ENp#Q9d+OPX5SPa!`Qieph997M^Z9U{)g!>Sc2iE+ruIv)2yK*W6&p9MG17yeEI*-b+A9ApJZ{>cets zoQ9643j02VIN0cJyrfn(mt!~a`sVhk9JcjT=jWfdufuk>J>5}JA82`(CQAmC8V(xk zo0-W(yriKRgp)f%viOc-eoVyiw7h#0ArpwFmEdTK^IHZ`oyN7du_BrmVBm_VhV%7v zb?>_=`_s!tmT2JKCDSYbs?gXhYaqoCgT!H4~0a`@?gSc zo~&x?I=N+Au$3Dwc3r;0%k9|t+xe|G6 z{;6-wPo$xuJB%NLTXLrfo}CQEDZUIWYA?RqoNlekuG;V>>ZM%2c${_6-`2?l>M=j3F)Ev$lhWfq`nIhpL}-7v&5*4qFCt{A5jeowsvOMG$&_ zaZnx8_4;&!f}pf_sjObCH2tZ~W>(y3eL}9kqSYm-yh61g)3YX+S>WZjbl}Z#+01tT z%unn~-TK;KsfQwlp0c<5)@M%)@G}qs%UQRrLptF+zJ?* zP;OS9HZd_=->5wO;Z{*o(a6FY>MGX3a!hti=I0NO>ylZqA4p~<7Ruj7Y0Dl)DD4NL zEd~4Jj90HqI&b!V7pLD`Zd2(yg{nR@5U?MJ7Qg}uMrsgVX^HF~BRb8)6uK_f*5j2Gip=5^q7KVuDg_9mz zrT|W9+EPE2Gx`1dbR2B#oTy(n%^%F6`(dC1!l865U|~sj&l@T)DVHCvt-iH;rhS1E z^ny#)H`tXij)ko}ZZ-T-N-{1Zgq^;pI`3!woxquGq_Q71aD+v@neN`7XM20QhgBtu z!>QxRxtNe#)Eamp`Sh6iNgSot!tE+QeVCDke>Anb7mf(he);23%O;9byXHr)%ZWD* zV(OyPG&{ek<&+bBvtaFCTr5g>3*`%0!^Rpi)?elRbR45X)`<{fCGFQ8&u|CPmT~bV zeO2rVW|y~uy)aS#W{l)XGCV-ncNwF4ViK|qp{!QKNG#wuR`V6Q{%&q!ft`gEkVPBA z_~{e;8VbDj+n3oh`aptuK7r!1df{8s6Q?s=COBiCO|N?$wxT4hnaQsi()Kxwpw?W_toJ3JDJMijTCV&DVik&`RFO?rwW~5hm~V zJ~QX*Gt0H5aohT4-B1bfLzj?c6VW`1Iy$O4swrL+cpuvMJ(8w)s%18sBnp*mQ@ANLcDK}0ga348 z|4jq){Y(0%i)Wid0fFp&*uF$>%QTFL8MZ3T6VJ5?=^ z!y!Z9Q1)zu^6@Wyl}}>>cs)!PuH$dDgODl5fJKCBFZmM;bW z#5K|R{b;7s*N0kNGm=vT$m`e!chQ>}inZ$7V`H!e-@CyqJZD6 z(kqV*{YPDzm^JZn={%V?kh`gL5rSok%#jqHcb7Tfdzxe|q(MKxR>4pu)Rv;oB~QX~ zW2lJ=Ehf^>aikqp)Y-(vpxV%C_e`hEK-z(@*G9X7cpfSz0n} zdG0qQHy6=oi=7Fbm4v-q!Sx)T4>eWs>&0efGZ`+WU%66K?p($EmefP8)$FIi^f+-}W*)J~r20SGO|N{^h9*wBeCt z_7p=(D9h$F*#kLEsJm3L>pr! zq9WNp-RjQIbmIni5^)o-^lGuyipw$+4WX^0jFtDEiu_Xazp}ON8I#aGMxrJ0J8Zk9 zgtH4R)^o&73c(Vq@Fqi=2q|+3d0Oveid84_Gi*@VSRKaq_8C+|`}t?AC%n~%-^kh= zW{1rGVS}mDBuV1Avok9)({8!I^fhL!>jTzEYhTC=Yss5x5Y-hAuNUMb3P)e*Tw3A|WI#jz?b>xK+*u1%-p|wuh3( zKA%&!;+qnCR;Og79Pn)QdJ>kA&LH7Z3>^`x%=`OA>X5tTz zZ>|qki0bxdss&;{QK+!qPQq!)1Mz}NVVd9zYvN)Dv76rb(xCeVuFSFac?XpdDBqoN zf2ndQC!V!$(rW*KS{#7YLVF$0EN6Vxi7mFV#@7|N33| ztukX2wN?4o!cc4j_G#3EoewBj5K1C8ndrV8ezG$ zLpn?A(=3AI#ad5#hax_rZXNg&`yM!B4>2FOTCya^*q60O>5_&q?hjKi4whiMbT<|k z`+hq~0O!M@e_D;)^eA_wNAs*07+bbI4mWsyswVLR2@H)Nzed_A^KclX-PY3PF4I~z z6~!nX`1@-fTloId-yp)cqDMUy-J{wt3OM)@ezw>2lA={qQ5?8`Lgtdo0JPor4LVhE zb2JXHljd=AHFLAoKY@-~k~-uPxdPkGd1$~CAhUvjWMBOtFE>9sH~%-ozADCEf68!6 zqG|$$*wNKq|A&^OFAg-L(&01cR0Xc89C4u+Hl6P|X+FeNtgXe`ESu-^I-ZL(1pRvn z)f)YMb{JLWM#4T0;Z>LA?1FZ`6cq+8TJXsC62_=#K=maI4C<0jGo+Q`X z7Swav@7y@FfhH&C2m*D=qi<`?H+=3WoUT;Dw7@IJxoFA;Q6pMi{n$d+9p5D8Y^}id z(c2zguEuze(h~`woRC?NwaE!v7s!pGvpkokOu_9Go2tMm?0|&1NYrADUZ=tHj}Gbd zmMJ!ECJhSH^5-#(L4iC;J0df_{P6kt)Dn0`d=)$h*PZ4acC%(9l|G|{-vT1EogGDV z-M=NvW5_Z1x1=%a&K>3d`NZ9P`$ERHNM(rI`^97>9L`0vOO3;X`^~=30 zkfm`SBRR$0n_+a|27HTGT%uwIx`{dR8)2Dy-g|XSAq~u%q&G-u5SLB)e~Zp%-G}8DPyg z<<5$r*>8l#I;EG{!%t6D`)GS??KICiB?J62M*|oN-M{`OD{BC4)>HYU9|tRKrZZ#p zvm^7G1V?{~${haBZOd2fIr{=PoFtv=i{&+BlN#Z*iW_N~`4v;yw3ecegU2|7lw@@_ zi-iu9s=FJP-QNWqaoYUjzETQP*H`K=6v%^6+cXUX8y0D-o6IX0?w!&DXPmqiEPRhJ z)eeZ}DxLO3t;!jNT$2ea%07OSY9n7rT!fl)2Je>axx~hr^KIad8uA;SFe+(#MxVku z2B`R5=!S}S?h%~kxFVd$+^PX(fgJ;;Df8~7oL%Ph1!mb*MXL=Lr)$jy3fZ9x7P;gz zP=2c@kjgyD5$V@BG>hI-BV)TD;=C}Wb@lq#!uOB zq_(^M^77n^y-r%yVEt~rWXoe@((Lccg~kj<-uEwC1ugMPczRCM>Sf5%Iq%l;Gi)N; zJ-C*RH@IvE!L0kiDy6|OQtP-?M{OmtUK(UDP~g5oLy~qNA<&E>(15I2=X$zV`qtip zXWZ9)Bnsw*?Mg!h#q7Lq3$Ub3agsGxvF96c#=1a>0Ro`k<_7m-LI zZ#u9%4F~%`?Key1KAVH4mxz4y-N1~x)@+Fph1>@yC`d2_5(H1VPvD5_@4%cycNwLk z7&WqT&{xti?p08=oxPBBhK%1Z01ypk(@djJZ{ZZ@sQz{RznV8y!)q7b+Vf;z_;+tE zX_1)!jo`rd``7tT@N-y@dmOLxixI#7;}kg7BZBf@*c7}JoBv-e{`o+`LV{CI!QG0k zX#al4H9;7dicY^j5vBjp599zr(i!(RSs6=lIX5Gt-a3{4Yz_|tBFcWHz~eK%oj?)D zdRWQQO5<4u4$->)HhC^_sjFy=;Qlf+ne@H<7g)Q)!zTv-j>b92IXI32Q1g`{-&00A z!`yb!hG&(Z9t=uewmVZe*b_571Caq7U+&5Ir2ZE=bL24yuE3qa>yq%o5sYam3@1= zRU6*Wy}nl)C+Q>p|9si3-|OCn-*k4PmNin#l-yd z<0N|j{auG;RtmM7tM;Av2xuGWuplWvJDc|UV4{6nCH>zf4?Ikz092&pi5h;`i}R>o z76IO#snzmVd=YY=mnLc4TE`M;mYqFvdTrO{%+~YROm9v1tq-bed?efU9o$aW`Jn4j zHj|+fBOTdJ@0o)vK!5+|TK{$r)ik62|M+%IpWs*(kOQTPSKB4k7EAtx6Ps#WnwEbX zbXy)0BGcD1*F~|cfAgKz%zvF~zjg6p)c<{guCq|z?Ayj29V{=*|LcjH`agZDd&6wa z$>sUCv1}y$>(--ObU+&acdmjv^M~S%u{P3+^7{H30TD6s=TDqgk}X1*(y}ruOUu)< zvky4`b~80U!5#6FIEQP%2yJDq21grwdPi}wr0vs*GpR35m)~p4d~xMr(IsL8N>PbC z8@k;xd6}GHrX2munB^}Ja!H+#CPVt#96WF5wV?!)7BMnAWxJoFOGvaF1i zE;VY?!l~_X9|ZT;Anru7t3^2r2L^7y?%>QcDN&6RG%7&hf>>M6)EP$9@n-kb)Wm6H zW23Bm#`Bqg;QaX5+`_^GdO9HHVy&5lg{9W#{f+gSM$`Uyt^_Rhz`??rCkFM|tkexp zPgeswz3ty_Lo(b22xom_*5+WllfNRC&<$W?SnTbhBX(=hgXM?yQ6k!5hPjvwS(0FQP z0m_9k(<8)&6FKu=?Ta;MbG}o1-O{9*8GS4H%5J%o$>&ilcA|tYKi{V_OTg?^rQ0r- z$y<_Ak`g6Jll-!JL|l=6H@G)wl*GSOu}nz{Z5VKCQe#{h0ahuiYgxVWLk34*)8aO7 zBSQZ_IU2jQc%4s%3$|G?;Kac-j6`k`t#KpV)in_A=E+IvVuj}r$3@PPWp03 zCl&@#WEjCsTJ`s(M#A-+B(D`t)qF3fnMXUXJtKz(!$B-?&ynUkyv7^D5+3dyOI43N zCp(w~(rMGZJM(`0D$_&>rD-&uBLlm5E+i4Lr0G_`QH0lB%3MuBDFJ4>@z^i0%s!_Q zCh?dPl8*&sRq-*@yoxBxMWw{N3}a%QGg}yfz{0J?2IM+tOnUevZ#K5ZMvRmWG&s2# z`9`ON9XnjN>I?%d0c5kw10VrXsDU~=V&%<4db%=CQ^mQCCSHP(oSccxNYuXJl)Bsk zw4;=uy$8GB-`LpL-CG)y@)C|6-X`;~t17~BaA19S7;&4|<6q4sX6{?#93p7j@aZ3**6T25iI|X z1C{BU^W-+T_t4#$(`ovyo zfdu#uKf{U)gA=hZ+Wu^GKYh_a@Ss1Uhd7&-yg*4wNyz8^1rwzN84(c?9-ipV^YV{S z&m=W9b>Iw-)A8>9elV-&``aryIXMOfMrLMa29FDDpw((ahJcTEmoMZJ`V9fMV{u5x z;6Nnq-gr~8)5QjUZG~1Ni83(>%7u%I%OG*evc_7;CIkJp+Vem{a$2;=coYB@i{+Ng~N zRHvHZt0fZ=KMWY*>A(dGpr_WHn{snQlHAa{hObc0}}u^=u!U74O0^uP&& z{^=&c>B)sR5!C7!4uWQY*RaJGSF)H6F z+V4_TtQGoVw3L_+pABTNu;eTf)Rcw=Qy)%_D&7~Z&-3-37hQZh=wr~d6g6Hqf;m-~ zk*0z7Mc#Kd+hCm>wpjzLgO7%;Tse9S)pbmds{8;;_gO_SabI6&!(tLo-&oi-rJ#0 zvyOId7pIX343YTp&IN9=mav|V_drWjcc2hHY8fYf0<=FnhF4j#SJT*~CjS+rfLG0I zJG0j%6k?c=4c%s|{&!jXYE`t7v@2gLR6_o>i3t?qhb*7Bqn#aSr{F@7DYSz8!b0oK z4zHfTkAu;K64{@>d=Vv7tI*uLxVYHf7LMoU;o+gCHhX!vVzS}tMs3*v zNMfL%pm5o6I{+^XKW;=%=Fwct@pzn1M-ph~neC0?>wb(SGppD=T>hYP9gM=K7F!;U zqh!fYuhtKO)T~lv%uk0!-zlQ2jhQb~^Kf&cc9y-b{2|ru=m+@Y+agX_H0UcS(3Zs& zb{ayB%;GnlCowzg^Zu%~4qVq9@{8-zSpgz3prF{TV8kI-0BxD9RFZF+oJ%D=O$b+$ z;8-bjQKbC)I5pBH(mo?Ko^P3Cr2=6|W0rlJ!_d+V&dKK2{nX1&dSbsG6cm=!aEKaL zC!sL(<9Ol9r=e4ek-Hm?m{T%Qg40MIe$_wj-KIy3s?eZoewb9kjWhiv&4wTD7(n_f zlc60H+b8|GhO_=#rHQ;*4~!~2Avumbv7aY&NZZ9tMXM(^1WIDz5CEJlfR&{a&K@i; zX6(D}sd{B|cyZZG$xk@@c@N1#77(33%AdxgSq+rn2VLtI;g=Rg;3{uHnysMj|qobkWZc7B5imF41X*2=f z?|3dgm9N*bajJ4lLj!B!OKm`~p341h3BPU8H7-2ZYrX2E0QygQ?SaR}p&QE6eZSc2o zj`U7=KK52L^3C&)^@`UrxA3XDExe~6FZ7f@RCIS-*!)}t=X{|;IJX_H%%%2{?*9PR zc1C#Qu+35&{>sc$RG3oPh*z+13H19%2(JK+6HQ+;5BtWT=4mK9<%JC00p zornb)I&(f?M%e}lvW@RsKqvwH^>`mIy@5cW@Os}ZSLinBgyJcF!Bl%TwaNEv6g`8I z%#VMN`J(kT5C;1ChLR)&qcFz5u-wi^5CjiHc>RoyPHOBuc9xwcMh;%CRp^R`i2q{s zg(Zf7oQ&+Zv|#&jN?2||hYZwZTkLgT|2?SsP@W16?YCw6FXgAey{wyGjd~FD%-iiS$V+8f)pwr*?21XcseycZ*fQNuS3G! zaWH0ba&o}lpGX(A;$pd$(%R)>BO^02 zipFa^l?|rhqUD4^_!f&nTW~9YL%SMYPzZ*eYP~w21QU4)c8Y*M*Ws`X>vN~$k-LdYy`2SG*0N(;dL%=ZlbZa9%UATY!v9IURj-g|ln9TN!M%;Dt-C zA}3w5z?Tw;$fI)$!atVFFY8`&L2nXgyEHWIfgukb8K08*b#SN z%w}F5%ey2mIvHOd@^+7g7qHCkEJe|mNr$E69?>mXn(xvv#(#v(| z${4QsDyhC0K|{Kpxh;CnMILvyPwKnFcjsd^kt*|{YYvWaZJesTXvl$B41fT?IQninj%fw*&+!x?1+8C~fyayr(l=>KMM&JkXuQ7H;$cs-g|E|b&qcna; z%S{~D53}?;iSMa?g?9cRuzi0|Rh4R+75R&YyVImubQK9d{(P?ds5>2!d4s525mr3Q z$LX2Tt7;a@zNV|4fic%zp>+}tn+Y#U0kc!aku)s4X?wq}itsKB!fxbMsSe^7?aCw4 zrXQ=yj5hFqx_G8k8GIqc8Mg+H&#nvZSgnOAemG8Cd;?Q!np}Lwfyc}-$5?0hn zGvyqlq|mZxRSQCleG@v%GlGkAm6G6XRgF^j?%?ur3Zt0jgbj);?#!-(snJML_}JGa zj7SWYA4L37YBG@xnd5$+s}X;>gk3@*_bWM##cz`5nwBrwivhmP<3fY5P4{t&Rc2-K zt5Bg@`g8~~E$f<_77HsYrgGO?Ck}GMAJ4izcpxgf!4(yf?iaUc>98TQ&hkQOPRy&h zow}wJKF!(sYlJN187}Ew9g9_Z_DjTdWG3KPL(l=f%FCh|E;GjUjFU^z{s88Q;i# zXGecq=#=hImx&CSeIh4C6F0Dptm}wMKw$9`^g`oIQ+%-m+US~1HcUSywpZWD)A5XI zX*;c6-Zmu;Z8_dxcxY}O)D^c~%a}8dq?hQdO`2fd?9Gvb{%*IyT z09T1c;2Bq)zYk)z#UM^lB7)@N{@pMdN&4!6ZbT*m%p82EX*&+We=8a7@ShMDJ=-d@nle3`#%*TvcF_BZjEaCZ?5zIlDWV@)f=WS%@(8|my}d=(SGYby0(E; z`MQ47$l;xP|9{A1B>^N_h1vj$+@wzm#(TCXHa=f-*9TL*jFZY$rMW%ts;H{=4-Dw)_}IWZeq1gXj7_jvUIuMfxsZ7^^BohysJ4r*#y(M(0H z_}-0QA|juI8OplGT;3}xI=+Wp=2Cv^*wesSyLu!jz!>P>-4E(Kq6Eh%i?E~Yzjhr{Q ztV=jeqw(&yt~XupM9*%?#s>OIYplHE%m3zjrusKvtk=#fsG2{?ArW^o@&w2I!pWt6 zH+IpNKC`$ufG0(RWY=hZVN^D;nDk(+c8#_A8BFEUtz_O=Nc3cIvFM5zqgJqzI2tNW z()p-aKgO>24_0Q^U8iLXhkU-Cy&eVEQDm>l(5$$x==t#1?lxmg!)@P4&F(P{HaOO> z^Ccz1l*;WtG15MB5vi%Ws&WW4}UoCG-M$!0nh}KDk>ZD+5D~HkDLLYU;+8bxQ zvA!i};*&ryoE*ED@w)>zZENv%#;sj?%Stl;`l^<5C1+{OcsYN{ttBC&7Gm7wyKLJp z;M<}|#dCwBf@QQH{z$626p=msNRIoS3Wj2DA=egT#S~%J<2v zmD04T;}SOmt5e|Mj7IAo!w*b`iWAyE`)H1rrrejRt zfxnrV+55|lyr7`qf5Shc&z`4C)hs3x>KYnCeIclXC}#{*R7;IEKyh){z9exJ0^VeR z#bPBsvp$Ta>ujMccv8GR-6~rO#5(5gfWc+_EeHfo>|i-cpjBI0TKeT%gZh=JYkmE7 zD26m9CT0$UkkH25oEyw~W?GC!M@GQFT#%ZOFze=E(tye7SVhM;8s7V2qaBPfPZq0+ zREdd+9pgl0WRNg~w!si-(o9=>Eso2ef!@9Z zyBVoTxv7G*)`?WJtYrgJx?}my#;wL=wJpay@#$@QKmnWZ#KDt%{PhmC1*pL!VQ!AY z%ORLzmFWbShvrT%2@IJRf#Ag0IjsP%PJ+d6-zwB~>aDlI*v=LdEdleusqtc>?CB^T z$&B7%rnBag`B_FEBu~jMW`v6B)WFVi<@_6heh z^oYsZiXR>=2^+Co1Ozj&p4ld5iyjR4+2K^Q2#gGMo+r{Se?eIKC7vqWHB1oo8?+U~lgy!rA z`v1~Xk^Kb?rk~cfXUO5?7~Cvh%6;xwB}HuF(TD098#%tXUGEMvo&FOtcJKH0^!WSx zPxT5~F={tKU{Ow&Yp@iv4_GXeZ*lN~(*%=T8zLe`vxNds@VWD=u)yYAgo&sB+kBpe z>YJFbh{%g)DxTg+T3n58?E{5wndXU23l0Xl?V4{ zt1kWF7}tg(?WYjUMUdciCNARP@v-|T1OMwA7 z?9*6GAM;=6O%Xf?^TNw$xEA&RD+58DaxNyVLkvCn!W9gmr-xG|{}WNc;e0HZ^{}Q{ zUT=8wH)o*a@3e3Mp}zS7NA%4LId3OlR9Xma{n*+&70fL+6m78rtXk_|>008u-X@L= z`6G+N`u~ex)~I-BIg{lz2lRIbdU_9mTpG09cz2xhZpq1KdV*+RZ45}SF73?Cs6W5~ zq@-p*N3lssbMqCQ5Ulur{};e4x`Ft`)8LBjq9n_&xsU`6dhLZS!CdC@@616v61wpE zqE7de07H&;uNizKMo^vU6WUCXO(g#pn4fyeL@QI zQ=+nSZ>IA$Eh=opDdP4ijxV*cvZAM>lLi1ZAhWw$ozG&Chv8tTI^>#Dk+?F)!wOQE zfyZQ_CZsrut32wdJ#o9rS`O%3yJOT_hc7eI^(n0tDVRlSz!{lOSab3DBECx3Bb7`; z<4%rE<=npHV5+$*(eMZ^V@#K^VjTQ3PoH$N^^K0P*h=ybOq$>#4y9{rYXxnfu9ZQu zK*_jiTZmU=O#~aH@YQv}@;e3DUc46z!zZr6F{kQ19G+=L_I;B3&fTDarlsUkkGYxo z@cJkKmQ6(G^771F$;?G3pw_qqzC9Y%pH+3RqN2d-IltYb0Gwasc9W0F{|g1L_`|0n z0Cd8$g_U(IP$_KN=-6L!A=Nn25;EuBjZxdV5@$X!Nx}*40_PTMPVJRDPm_ZKmq0R! zkbE{(Ldx1pV-F)QMy59pT)Q{5ri6&L4q0fF?P~tRyl)0G>)i-rzP#c?i-z0M{NX*O zz^9Qq4W00WuGm;5{+eX+VivK#sj7c7w~iyaFqkKvFxmAwPqbfJeQYkSyW9Go<;S#} zt?rjyp$BB&XPO-j;N#E}#b1ThGl;lH;@)1L8*MfTYG@k?2T*I1W)-YbPV!b`fDe+Q zn}Qr4kI^+G#(Mp<)YMe-zhC+4-e3%ouaHt6>wcdmj`&z(9tu19QH-TR=IKKir6yxz zvs#tzuIchuesTzT2zl=mB%2wcPf>w746*;hs*KAI#wIgE3lqUQN4jUTJzMJbkU7f# zuf4Mhi(_fqbs%Wapdn}=K=9xe+=2uNu9HA;4;o;Q;1VPRcXxMpcLoM`2<{9nyR))Z zzV+|_WS{Tvqz|U*y1Ki%y85l>z29eQ@rboO>OOO?%sLSJg*|(?CO*tZ!!+G+qpw0C z;>h;{)Xw%yQ}641{r0y0mz2`fuf>kM2jh9b+#uKXovjZx?F#CkhTcj_-qGSM5fF{5 zn-anbHZPksg;!!<^lyb!lmt(6_`56`+6gty+r5tzNotDnA<-zT@z@A27Vh>;`_@Ab zYMdoXyPpQv3_E1GMhv~R6%lN&+?a>GsXrlM*KFA06 z_P@?oXAR$DddIvTRaWV1Y;_j2M)a~+UuD-k_TUl3I4^cYrO^ou*>OzH_Y@0=1&!3gfBfhS`P$b}@36~5tv4*^ z`Nh{tb4!q^Z+KWTDNN5Kz@;G7s_VN?JPIkMI`(ub#n+??@<;9|2?-3rH=23NF#f$l z>X!;qsV4znV+-bOdq}lwtg@;yH5EQ^r6;eLKD`{_55-#ZiWA9eMRe7%=h>?K2aY)}9A_w3mj-9@RJZVGZ9 z|DM4kwV}e96+VhyTWD8zsbMtN(&^2%#D)J!!gdc3AKona2=9Q?bEbe?8@%B3h~uPJ zTd1xZJdlVPD_366Qr$G=bwTCI$H~6?vV>SUr75uiN4}S_9DEnwGOADoQD1_?jCAM! z##(@I;rO{{KXXZb-zB?);jtT;HbIxskA)@O+H5Tz9)VIAMp)`EEyxLI9JVRjV0Bcx(6UHz zSclc@#ge+TJvzC?gR`^kCpjZj8K%xH8Hl8^Z{-MD+7Z&=ivO6@6bR_fL3IoU(?bM&$bA8k)Lyb6zSTVT}`Y zQ2f^maNP(efHJI+*UMN~d$Xy0h9*Kxc^#~4vX$~zRmsTySlyetmIY!q%a55i zgH4N=KP_xh=G!b~XeZr4p|P>kg@t=k#&15EYK9>q)D`{-7r;R}x78)Z zwGtAT6K$PRU7HMwgP3?plg>W&-THnkq0_U>l^a^V2C~jG9Z!^}K4T*KKQRxqq_|d; zT#)N1362m@juzKtbSNlx)hyDp>F0Xn=S4|3#R={I*aAmkvhDV1KRh~XmF^`KUCqQ0 zRE{Z>wsv^n({x$B38+L4P->4!@yo5~elpeH`DS1ro>kU(`fL*@4T^-oWsIxLevs55 zz_Q3yWqjWwcm7W3K{#L z(R8~Tf~soy9K3~PZQD&vs*FoVZ3G&Xu)#C?p>pO$@WNQTrA!|Kth{FQbLg#~v!_e$ zF5g6d-l4F5lpj8s5njAIund_KsOR7#$6lL};>rzZb}m1KOw2Og*mWh=36 zALR(!!OxND?Y>pSXHwFs8?Q!-72x6bIphshqT4Gt6maQ4ZJG*Ex73t+NOX0Zt&lNl zSLc!z+~biNqn}z0$-Z%>!*G4i$uh~!)Iu&<_JcX62faC~Zdau&RV|yq_j?KD$S7Mw zka9L(eU_(e1jGQ={qsf6T0|xBVF;Jb~M(7f{hdC#-B48tnS(gXTsDMLUt9y34>1IT^EAL_P1FpqcHI&t8jUz z5aHG-PZAi2!hPbZOzt?jRss!;@gD-8l?Y43Ier`7RV8^b6GEMTcddo|IpdeY+HY|L zAx!qj*DLcxvi7w3jmcXPAv{<2fjoPyOa2s-Ns4Wl`8{vw;xp1ZnA^z$dJgxIV4`-( zfcgRzm*!4$J%V+kiG=!u?POKJ*LOr-jX2q5v*u15u{E`3W-7&EgeJZ&j|+?(#J4y> zdl_G(GZO^iMSUP=hY==e!l`XfvBzAR!bKGj#U_J8Yi%r1DB^3PpYIB&OhGx6uK8XF zGv4w|s%UeLI_X-YS)e&3+fGHUK6!-jpwb1wj9O=7*=l~?t|5+jME06-3U=niEf2)E2(QM;M z;8zi2T&x3~t(){rtmYAq&2EYPn{xlfm3q;96Q+{fy;5K}2^;s&F&$4G<>3){FjTu` z$pdJm?o$V`_>`r=B% zC28cXAraLsWKb^vS9jm^lRVuP?OC`~BwC5b{=1g$zvSGfy&QMM)LOruvyRuVeX7Kb ze5K2&N0G7n$cWEjjIPq=kWKqTOw;fXV}tX&;DdNmem*@H*ZGcc^SzV5Bh9B6GKiSx zI9mS$Upy<=_Q%QriOeevS9Mcw0n8Q>bMwK#Eiak(yt(!^q+P3f^WBoi*k9~$G(aGW^GFzOu%I6tJGTsT z)9Fv~%7YXYOYJs?2L}g%Xw=o!btyA-+uTt{ha`!Ovq`^HWa#2>2>^vkN`83V?z%ax zM~7G+_J`>g!0RvyJzo)8ZZHT^pNxaJIv?5TjLZvLIu6i=e9Ii^sr)ec)x*l{a@vI} zr!YPLTh6zS?6xp^Y?A|%=3OKKpM z4I;#Bx>`*|l~h6Q)XAZ;g2P&4+7o~TPe>O+-q7%qT3RHVpGk*$vR6CCBV~(+PrF(0nfx%blIgk z=8uaO@-4*Ak8kKX(XzgQWTV^ERU;4*fEyTy=-Q{NnM=@*SlL-Axo)BL(`4?BBWK6% z9}PLmu6{c|kqCjCdE*n+p+ci8J$-FENO&>oO)W1l_16JMts+@=2X`>;(!R{SzBVP3 zZ8huNNPs7+rOuJ!A0sN0Y2e%*+=Af*fc4Mu$r9`6>X%6G?cPg}JdRl>S+v_9RhW)H zGYS%8pgm3xW*VD<%zqC83MTW{S)(TR8!c=Yl+C(s7newi3iF%8LEVS8`#K&oz^i6_ z0VI1T)akB-d_k9n556b;J2!j{<~!Dle>s9_{SSMs;_ZJ6)5{Nod9!-!7qFc?uWpXs zKhkiXq3rg44FK_*H8#VdD~-c`MAICjBO=KR#OxMfU<`JG6yELcCC6$LkR|ls9p8Pt z-)~Z3kIOw<1*(Vv3$t0RXF`jR-MVH@Tz8}^29KUZd8V)N-hF^B3~bGvU9Rc?Td}7s z4nK`x4{Dqp^ADm@{K3~?Y$X};Musrs;al2h-@NGJXltx-TkGHOts7w(zfN-b$#JQW?A5u6ZcP_LP0oQmh2OV^< zJ)WU?UV`d`Ln+9Fe|WXb`0W7mS)g; z9+9l6F`Tja!O+ai;>_NfMT%jP>h!nHtT+U4#6RgMkmUgR5px!K4XyqLsIMV9{5Ev+ z=~HXRfJC zE6B>;0B9*ZJUk9AZc$MYz?RN^XR(pybKIMbV>d1=EKIHF@W=A+$F*JhEiey~dAE5Z z+nEA*DwSl2=f*D>d}yc$fWaLO-TDJ`MvrPd59L85b!Ts{ftY@o+q+o^iCBZDNL5dI;}^Vo@8YuiP?f+>H+>IVNU@f6 za}6M0x;wNCFsLFWdy|!+9ndftP9B=`Gv<#Ped#(7xgS3KU~JcDw2#FUG)Pzc;Yoz1 z%6<2&#*nOo!b80ftil7ATX2!9cPNNH7u*Bc2l!`JtT<@b-6mbzOUVa&ePxyNBgM^z zx%z{U;UT)>J;=BheeB~~06Bg0tW2=dz--eCKTxk9^~77ZCQcK1{iOZ6kTigUtk(NSVisV2wP-PYsg+jJ*(_{4%K` zrwx9v2nrjnEfoJsFEBO$S%BW|d+2ZOy}PnkK{GN*KK}`L8x88Yk*c<-%vge5^Rc}A z`Y(>cqZuQ#YN7#;w`12hC^=vgxyb12UqBxx1iId35vyujHa^E*1qLYA~*&iO3U66lJ@b*KE(UH7SLdIs&t-i&8H0gZ$cyRZiWR98Hvbq>bL0_V4fJ)(+&vRE$d#Ro>=E#zI-OkFW7wU zj$8iHA~r7I3@uPoL-KYjNtDP9;J`-eQigkK!!L{LSRr@0advp&8)CKgnIrEgf?A1j z;b?GY0J;7Hx49r3ywGgR2QvmEih`J_+tfZf48f&DRZl987a@$Mm=;qyf+kIipG3X${wBQ3!SRTDHl7|{tcz${3<7*bwq6{ zks@Ztjr@KR1Xr=CurphqmB3bEkr~SQLp$~rJWlWKdS9fhjEq`|-u}i0VgeQ#nzzf( z_4U@qUz&Cw4WMaPcs)keZ!{Wu?%uHm27^(#Izo^!o+IEFs~5z+6dp~h3t!k6h`G7E zd@ax_^s=F{60d$fOO~+sd}k6Zf=}cCTBI%315oL~cY(OH2hBHDxnJJD$8lfY4N_eb z;^!wO-r}4fas7$@BkA==cvB77Vw0;>C<)Qiry~1jgv2!TXM~RK2lI8dYu!Z}WnYmf zDqbinDcNl%Iaw_>61k?scJPt1rJu2ASIb%92jlY~Q%4KNGGTZ1FjeY3h3g7EDniFk zo^JbAFq(wl!=47yPXEjU-em?A^8u11&)r`zZGSv}8c#sOZ4{R3bHR(wO#>|)kg-&Vpg)d<~ok_w%7*uVS@zTra-`v*#16-_R*4<2X;TXOaV!0i&)n zM1KVH2tnFk9#Q^7Vw|O4imgx2E3odIbY!0qAMeF^gCokZGjl+lEkY06Pl?+TJG+jB zD`1>rH949R_?_D$jf+v9tXUdut$ji{6_S2+uYO)wt&9#1lZ-30P6PgQ3(&!lnG*{a z)-vrbnK)X&gG-8lZ72?}lj||e$mQ9zY{76!qawo4s{d*#M(_e|!W2U*S)9-8is~6a z6S3m_OB;8y>!0W1(U6h(o~;nm*qB+Yn+0;u%QCuL2MlejG0wY+fjq&5%h(FXkugzF zQ`av)J`tZhb~EcqaKQDoHmTt%RRqnp~Uw`#B&1g^5 zM4?31(BL*;#n38YNkO%V_2_Qy;+%zaF&a{R=Z;oos>b({V z6&Vf=d{%W?+41SAcYC$jWKb?|n`!!TS69~wraa{+F0Fhg*#PiW0%hDM1UR_3To>y$ ztRo4#RdB{D_$fV};M9X?!mI)H6t%y{0D5Fh*f=m~y1DrK^e@ipHx? z3>rU z9y&RRV93C^R!blxA>rB6&B#*+d=_6{3HzSG!e}Y_pYQV_aAg)I1yFgHAe#ex4Us5{JZ!brT@_{tq+ z9Q7&XcUTy)!^6?p@=@*&y78Q{5?f%mmsiZ1+Ojw2(ykZf*|b9mwBREz`(SqAAhjXXgPQ5#q_)m5*F0PC*}35z%qcmh zw_5{K_Evy8|252O>=iMH3jOD@g5A7q?tdm!KCM=={7M zwYstlL8#cBeDg%~V_BkU8Iqo*H;P0UMF5#7oIy{n)J~|5{SNfx~m+% zRDO^ZS_MJ7e#I~KMl68T65SkA4*%#8ilW=BqLg(x5%!CU7enZ9<$68kK`0Ytg%(hu zURLUokZCfpr}Rev{~S<4qSLcHPHLMfk|6O2GC38hn11_c2b#-*Jcd?)KyEGnVdRnF*l~&s z69N(V>iTwTfE;hnXFfm`(f+j23qkOuHl??uvJU}uP3_l7)S*>OHJYc=`A+Z4jvrZa z8xm*c#H;Ga@==POoc*{yS4G|09E_L{bKQQweYKetL6vo}sO-Blk`!qME+ZJXi5CAb z*gE_fW5w)fg-MuEnAPFaYi!r(1itDbhVECryj^~lsGWx!vZRfc;R})7k2U(@VAn-h zivgMNesHU}stOmGHvAJ-V?_>U)xMAlMRt0*DkdMXrQGNe=rMPKo<>zT$kzuwkbaBb z5VkQjR+LQyL8_O;>~~*1IH~u~7Ae|B+BPk!LV5g`6rw1F5JF+*z)=)4Q!-}_hg_7bC_ zd_9w8A_`l7*2&-jNZ{hM9jdCp%LENhGK!hbI)?;gQ^~D%fPCdf?j(i7GIK}R@+t1~ z*JBS(1;l-5TgCCCgdQCK%sx=1$imj+;j!G-Kb``>;`K?3e|=#p760l zp@SsYm8Gc)y;l!&4a8fo3i!j;*dzPo^j^cAAc-Ti2lq0gtf+R<2LuZ%PZ%x`93x7= zF`2~(NHxr=&O?+_4OI!SNRH25Y1v0bSyka>YGBjB=TIIxPa-Qnq;h~f-NAxW^dGtL#*ns#WAMyE9sjc#^CGnDD^67vNgJh_Z{5GdV_gJUUvlSv%REl7Hg)sTDW zLF=(_&$ch1&_ATI7-1wXJ!y7(BkL$F*%$y(RAjZ{H@bWy4?3q&^yeyIKZCfU1c6hgVjIra_6RW{~><2;o1GkhpT-wr>$uGJG!H!;xbjzYW64dJuEYM zIY~79Fw#&5=cylIWZP>6bv7M+glc5tndFRlbsoZgRwPraW7=sO{c0{-+^+VdwJ_Q` zt+;ymWUj`w07TG((P!(sV^mi?{Nh2D$s7)|1^=Ut`H-oDZTI?F@PPT;2s3ZZ{TA<@ znjsurnR{=+oWoPty*D@0l2Ri~qpNrm$?)C+Vj#wEQr>=lWw{p;Q*rC1Yo~ulxUoTk zxheX{>n(ylK6H29cxT>sBT5%CoBZw|Ad~&+WZj#OV4!Mz)d=K|2W8N~Y}!@%Shnim z!3i>yD1NdgiUuxo7N=?~{XTALPvE<7ub(tUzHp6Jg;re3QyRbc{%iOXZ@#sMw-Ds# zZxvHIFpIV&Zx46gOOa0r-%>}A`#j0zG^CVR6jhQaTE$v2V0KG+uK_v_)*i{)6kmKF z8&BJ>TQ5D9va?o__J;DEl+Wc8s)@c(I(h2zOKrt<6&=ljT?~)F2jMBQ>ww{1mSfVy zrtZ=mE=cMLLDR$qR?vq^e&Vyd?tbrl&b#-fXZ@|H@9f5p90vC4gzN|_)6lUI?L>Gb zl!&$wbLyrEv$6)CWA(xcF!*y@E9eTReCP!PN=Kav!L}P9M5Bev z{wl5~%?=JSwn&`Cmp9rm{FUw|1MgydHYOJc;{#f$cdW%Pyw2nl(0AmfRrep>`XE2g zyARkV2u)4Ue$Eh9s_DTQxc$8x{N7D*^A4YqH=zG56|Yk84mPwVAh;hzhZKI(jw3@b zxzpLT=B!%D`uv0=m+2FzKEUxuRB*a0Hv|Hyav*g+ADz}ZMDlHKzP=aj%D6_g5bp`P zjYql1i$R{ma@ET!L{NpuW-Z@5VOedw7raTpU^;He^3GOBgVWQID~T3ES}T)qwPv!6$fz#HM>*59vb>S#zqrc4Z5fZPun?oam{G zB+nKsFXU#HHh5Wk5=T|!Nz?Nz$@~&h(E?62GOdbjoIu@G!_wKX{~vey{zMx58Daecq`gKB!D-ojwCqWmR;ln+JU(hl|X`|x?Usn4(a z-F4vZV0rQi`4S5650j#v;Xy(AOJ{E#s3(26PCAb;oh~rzNKlIiC%+Ss??W;S#1eFD zKu%dRKG9NH>p_Ve^a43g5wL}qDG~Hzee9k#1+G)Y(4x|QPgX?sf-)*V2@?5}1TKkaox{i|e z+n9#dETc3J6Mlvuyt>z;2AF!=OEv_Ac9d7hvrmuQT3>VOE80uQKlirPp?*j2Puqt> zh7>yM+zY=mcxXU1c1FrSa--md7ibCt?fF~#vz=;1o zR64>nB%3eJ-Z+1JI2)C8YMQIH0`Z{ez4)sKwiw*q9L22!kr*gmGFA0SsrC|mj<5Xh z#=m-u;=r|EN1G@S{^vYiYIMRH|8M=UPfMH2`>R|*fV(TWfW)0)UuDeiBAEMu%VLv0 z?6&A^chX@g+6NpX`sXgZ%#|tp9!OM8HDT;RHpt_qPZ&bFTS52(pfj9Re2%rK14pi~zNT}o{r2SClhJcr^TnOSi^#!` z7k)*;Fa91$3eQ%~SJ(v$E@3^Vt&xX|6YRUE8wx{UR+b&srfhotxyTgq8sjh~+8mJ< zK1U0U+R<$rjn8%qXaqbr7bWU)58FA%xU@7^KOGMB=3-g<@~`$PirI}BGo)(rimNNl zr%G)N<|{^MpcBsKLrDp#lJyP^?MqDdH=8khVIH$n`>9L(^T&!ZBWY^pgZE{y)YD^} zKM$o9!3)i?A!B+aDrGa}K6~eiJSYBWGjvVDwZznU`dQ2~L*(RICe?M({W?(y<8JW_wO)umC ziIjbB-Pq-DJw1FC`6k(KcrCfV-tv13@zTMP%U~VyE_Sin^sN zn_ek7SaGEf3n|Hq%`z}Mcb*2oVpYD-y<)YsT5zN>BUZ3X3@eHs!iN=m*E6VnKc?!~ zzvP|2cJ**^-LZfD?EuzET#s(TxW5QWdHk;z<{gDv1I#z4nTfIZa$!!{T*pDk`Lc-L z??TQxg#>LrB*ae;yb~GOG;=zee{sjbp+WBP#&)WhXJe&MZ~q%ifJ|1xw@NwZbnd8s z0b?)}5nQ1X@9Gu#aE`D=o`uISN(_F_* zCd^BKEIG$O;`E+9H=A?#ph4>he+P5c@$O(kzD18_>Ed>~Wa?E<-@oq^4q+IveJuLf z=*9IR#_l33L)ILIsrSuNsbj~YNy#LsM?)!4Fd~-+&&(TbtH(DEVxiFzPSQOkQWCNDq)Uy;4kN!^nO<*rpxwG#HBy%wxBkx;%V-hy*`1J&SW^|Q^5DF26i z*?{jYx6N)#KaGS$5&t!fWGK|6d3bfltwY?J7&89Py1jn=t{?&#k8WsVUxq|)SN%&yQ`gopuR}+FwzRl=M&l5 z+#_jXP+mJTB=lT$Dw(z^+|SU$JUNAnH`gZPV;RsMGTH0Bic{AeF9DX>(n7b3lo33# zLGZ>Yu6gvUUGPQv_G3LgNbzAW^Mzo|8X<1tJ|7g1T$(&_YX6=POs*myTCjczy0`Q> zF)O#a%h_XvIF#OPG?>XM(95yRUZxF2WD=|<2IjZy3VEnF=qof8Xqk%n?nd*yXTN#4 z$p;pBRkFphwaqnE<)W-}5|_)4nLKVxNFDr5H|xKaeufWB3=F{w%d#>BB*(UNQ`F+e zc*vpnBSjC(L&fYY#qahzQ{I?Dz?HU}r?$++S+7&xH|lAtJ@e3w|8D1Iy$cE(7qh+= zxUh|#WnvtEZ1dbq_nW{-v+p-0(qF6ivKfK%>XC=;8R&<41)71_ay~)8q*W6ZlVnYw zUVq5eQto)hE=!g#ji7neOyWL2qS~v0B@J~woyy}D2W?B4ur@F2sxu93*!ASNf)e?k z55uw+c7UqYUDb!Fy=PGdkmY=t0aDlOW#M;y$40x#aDVze@(RWc*tfdtg5}L9%oN$? z%p1m?L+^#33Dn&Cp;p9`V&eafGXl~*?}H{lKa?!Ov$2I+QQ)XLuKP@>K!Rn1`^Sq^ z16Y5L8N!oS*;Ak&UeqL1o~>0B*mK%O1}}28jT)SW10)721OEw7fOR_!ejQ58XKPRV zud6wQKcASGI4zOmkzvf^C?27y9hdquSK+)7r;E6qPqz5}JfKJLf^h9FYViO1p&Jbw zN-X4y{!euD>-yVWp#M4XBl!Pz`Fn8wJ1+m741e|!|D6o~oecj!O@>>cpxX$~i|g6a RUw&nEc)T={{aCG8dm@S literal 0 HcmV?d00001 diff --git a/packages/app-tests/insertValueHints.test.ts b/packages/app-tests/insertValueHints.test.ts index 77a646271e..0bbe5b6f24 100644 --- a/packages/app-tests/insertValueHints.test.ts +++ b/packages/app-tests/insertValueHints.test.ts @@ -233,6 +233,52 @@ test("returns no positional hints for wildcard INSERT ... SELECT projections", ( } }); +test("skips the hint when the SELECT projection already aliases its target column", () => { + // Reported as duplicated aliases that cannot be selected or deleted: the inlay pill repeated + // the `AS ` name the statement already spells out. + const sql = ["INSERT INTO t_demo (operation_apply_id, pacu_enter_time, pacu_status)", "SELECT", " noprid.ruid as operation_apply_id,", " noprid.enter_date as pacu_enter_time,", " noprid.flag as unrelated_alias", "FROM noprid"].join("\n"); + const hints = parseInsertValueHints(sql); + assert.deepEqual( + hints.map((hint) => ({ column: hint.column, text: sql.slice(hint.from).split(/[ ,]/u, 1)[0] })), + [{ column: "pacu_status", text: "noprid.flag" }], + ); +}); + +test("keeps positional mapping when only some projections repeat their target column", () => { + const sql = "INSERT INTO t (a, b, c) SELECT x AS a, y, z AS c FROM s"; + const hints = parseInsertValueHints(sql); + assert.deepEqual( + hints.map((hint) => ({ column: hint.column, text: sql.slice(hint.from).split(/[ ,]/u, 1)[0] })), + [{ column: "b", text: "y" }], + ); +}); + +test("matches projection aliases to target columns regardless of case or quoting", () => { + assert.deepEqual(parseInsertValueHints("INSERT INTO t (operation_apply_id) SELECT noprid.ruid AS Operation_Apply_ID FROM noprid"), []); + assert.deepEqual(parseInsertValueHints("INSERT INTO t (`pacu_status`) SELECT noprid.flag AS `pacu_status` FROM noprid"), []); + assert.deepEqual(parseInsertValueHints('INSERT INTO t (total) SELECT npl.additive AS "TOTAL" FROM npl'), []); +}); + +test("recognises implicit projection aliases without the AS keyword", () => { + assert.deepEqual(parseInsertValueHints("INSERT INTO t (cnt, name) SELECT COUNT(*) cnt, src.name name FROM s"), []); + assert.deepEqual( + parseInsertValueHints("INSERT INTO t (name) SELECT src.name FROM s").map((hint) => hint.column), + ["name"], + ); + assert.deepEqual( + parseInsertValueHints("INSERT INTO t (cnt) SELECT COUNT(*) FROM s").map((hint) => hint.column), + ["cnt"], + ); +}); + +test("keeps the hint for a projection whose alias names a different column", () => { + const sql = "INSERT INTO dbo.users (id, name) SELECT source_id AS old_id, source_name AS display_name FROM staging"; + assert.deepEqual( + parseInsertValueHints(sql).map((hint) => hint.column), + ["id", "name"], + ); +}); + test("caps INSERT ... SELECT hints to the smaller target or projection count", () => { assert.deepEqual( parseInsertValueHints("INSERT INTO t (a, b) SELECT x, y, z FROM source").map((hint) => hint.column),