From ff9a345b0924d85269c8fdf365040a433ca976cb Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sat, 29 Aug 2026 05:35:18 +0000 Subject: [PATCH] test: apply post-merge review feedback from #22, #24, and #27 - close the fixture-server listener before destroying held connections so a reconnecting browser cannot slip a new request past teardown (#24) - honor AGENT_BUNDLE_PACKAGE_PREBUILT in public-api.test.ts so the parallel integration pool never rewrites the shared dist directories (#27) - move packed-release.e2e into the packed suite so `pnpm test` and `check:release` stop running the same long packed-browser suite twice, retiring the now-empty serial integration pool (#22) - reconcile the fidelity ledger with the desktop-only capture interface and drop the retired mobile.png evidence (#22) --- .../rsc-runtime-workbench/fidelity-ledger.md | 34 ++++++------- docs/assets/rsc-runtime-workbench/mobile.png | Bin 53199 -> 0 bytes package.json | 2 +- .../agent-bundle/tests/public-api.test.ts | 4 ++ packages/workbench/tests/support/http.ts | 12 +++-- rstest.integration-serial.config.ts | 16 ------- rstest.integration-tests.ts | 45 +++++------------- rstest.integration.config.ts | 10 ++-- 8 files changed, 47 insertions(+), 76 deletions(-) delete mode 100644 docs/assets/rsc-runtime-workbench/mobile.png delete mode 100644 rstest.integration-serial.config.ts diff --git a/docs/assets/rsc-runtime-workbench/fidelity-ledger.md b/docs/assets/rsc-runtime-workbench/fidelity-ledger.md index 0233513a8..5cbb70533 100644 --- a/docs/assets/rsc-runtime-workbench/fidelity-ledger.md +++ b/docs/assets/rsc-runtime-workbench/fidelity-ledger.md @@ -6,21 +6,23 @@ Workbench evidence. It is not a claim that every concept detail shipped. The concept image is not a 1536×1024 capture requirement. The approved, committed capture boundary is exactly 1440×900 for `desktop.png`, -`hmr-before.png`, `hmr-after.png`, `compile-error.png`, and `recovered.png`, -and exactly 390×844 for `mobile.png`. The capture contract pins those PNG -dimensions in `packages/workbench/tests/runtime-playground-capture.test.ts` and -writes per-run identity/layout JSON only beneath `/tmp`. +`hmr-before.png`, `hmr-after.png`, `compile-error.png`, and `recovered.png`. +The Workbench is a desktop-only application (see `AGENTS.md`), so the capture +interface is desktop-only; the previously committed 390×844 `mobile.png` was +retired with it. The capture contract pins those PNG dimensions in +`packages/workbench/tests/runtime-playground-capture.test.ts` and writes +per-run identity/layout JSON only beneath `/tmp`. ## Current captured authority -`packages/workbench/scripts/capture-runtime-playground.mjs` creates all six +`packages/workbench/scripts/capture-runtime-playground.mjs` creates all five captures from one disposable Runtime fixture. Its readiness authority is a selected immutable run, a visible binding-scoped Runtime preview iframe, and the opaque child heading `Runtime edit timeline`; the stale plan selector `data-app-status="ready"` is not used. The contract proves HMR/recovery -identities, no outer Workbench document reload during App refresh, opaque App -origin, and the mobile zero-scroll/bounds assertions. It restores every source -byte and keeps its per-run JSON untracked under `/tmp`. +identities, no outer Workbench document reload during App refresh, and opaque +App origin. It restores every source byte and keeps its per-run JSON untracked +under `/tmp`. `Verified` means a cited raster and/or committed test directly establishes the acceptance fact. `Intentional deviation` records a deliberate as-built change @@ -31,39 +33,39 @@ not a pass. | Region | Concept evidence | Acceptance | Render evidence | Disposition | | --- | --- | --- | --- | --- | | Header | `Agent Bundle Workbench`, separator, `Runtime Playground`, `Documentation ↗`, settings gear | Existing Workbench header remains recognizable; Runtime is a sibling route, with real landmarks and keyboard focus | `runtime-playground.e2e.test.ts` proves Runtime navigation and its heading, but all six approved crops begin below the shell header. | Not visually evidenced — shell-header composition is outside the final crops. | -| Identity strip | Twelve separately labelled runtime/provider/HMR/session/generation/state/target fields; simulated Portable MCP Apps profile | Labels and values stay separate, ordered, readable, and provider-declared; browser HMR clients are not inferred from endpoint readiness | `mobile.png` shows only the Portable profile/evidence portion; `runtime-playground.e2e.test.ts` verifies authoritative identity attributes and the distinct HMR-client count, but not the full twelve-field visual order/readability. | Not visually evidenced — the full identity-strip composition is outside the final crops. | +| Identity strip | Twelve separately labelled runtime/provider/HMR/session/generation/state/target fields; simulated Portable MCP Apps profile | Labels and values stay separate, ordered, readable, and provider-declared; browser HMR clients are not inferred from endpoint readiness | `runtime-playground.e2e.test.ts` verifies authoritative identity attributes and the distinct HMR-client count, but not the full twelve-field visual order/readability. | Not visually evidenced — the full identity-strip composition is outside the final crops. | | Provider/HMR status | Green-dot `Yes` values for `Provider active` and `HMR endpoint ready`; `Browser HMR clients: 1` is distinct | Expose phase text plus color; HMR readiness and connected-client events remain separate | The capture contract proves a generation/run advance without document reload, and `runtime-playground-hmr.e2e.test.ts` verifies HMR client count; neither captures the full phase/color presentation. | Not visually evidenced — HMR behavior is tested, but this status treatment is not directly rendered in the approved crops. | | Generation identity | Cobalt chip `gen_00012345 (current)`; source revision, artifact epoch, and `Last good: gen_00012344` | Active and last-good identities are immutable and never crossed between generations | `compile-error.png` retains the last-good generation/run and `recovered.png` shows a later recovered generation; the capture contract asserts those identities differ as required. | Verified | | Left operation groups | `Hooks (1)`, `MCP Tools (3)`, `MCP Resources (2)`, `MCP Apps (2)` | Operation groups are visible, count-bearing, keyboard accessible, and provider-surface driven | The as-built Runtime UI uses one provider-declared `Runtime surface` selector and output stage; `runtime-playground.e2e.test.ts` drives those surfaces. It has no concept-style left operation-group rail. | Intentional deviation — avoids a second provider-surface navigation model. | | Fixture selectors | `Fixtures`, `customer_lookup_success`, `Target`, `simulated-host` | Fixture and target choices are explicit; browser sends provider-declared opaque target IDs only; `simulated-host` is concept evidence, not an implementation value | `desktop.png`/`recovered.png` show Surface, Fixture, Target, and Profile selectors; `runtime-playground.e2e.test.ts` selects provider-declared fixture/target values. | Intentional deviation — concept-only `simulated-host` is replaced by the authoritative target ID. | | Input tabs | `Form` selected beside `Raw JSON`; `customer_id`, `include_orders`, `limit` fields | Form and raw draft share one validated model; tab selection has accessible selected state | `compile-error.png` shows Raw JSON and the detached draft; `runtime-playground.e2e.test.ts` switches Schema form → Raw JSON and verifies the retained draft. | Verified | -| Run controls | Full-width cobalt `Run`; neutral `Reset fixture state` | Read-only run affordance is immediate; reset/mutating actions have confirmation and at least 40px controls | `compile-error.png` retains Run and Reset while source build fails; `runtime-playground.e2e.test.ts` verifies confirmation and every visible Runtime control’s 40px mobile hit target. | Verified | +| Run controls | Full-width cobalt `Run`; neutral `Reset fixture state` | Read-only run affordance is immediate; reset/mutating actions have confirmation and at least 40px controls | `compile-error.png` retains Run and Reset while source build fails; `runtime-playground.e2e.test.ts` verifies the mutable-surface confirmation flow. The per-control 40px hit-target measurement was retired with the desktop-only pruning; the 40px minimum now rests on the committed `styles.css` control sizing. | Not visually evidenced — the confirmation flow is directly tested, but the 40px control acceptance now rests on source inspection alone. | | Run history | `Run history (2)`, `Clear`, two green-success entries with generation chips | History is newest-first, immutable, provider-session scoped, capped at 50, and never relabels old evidence | `compile-error.png` retains prior successful records; `runtime-model.test.ts` pins newest-first 50-item history and `runtime-playground-hmr.e2e.test.ts` proves failed source builds add no run. | Verified | | Durable state identity | Concept displays `State store` → `memory` and `State version` → `17` | Keep the separate label/version treatment, but render the provider's opaque durable `stateStoreId`; never imply module memory or browser-owned state | `desktop.png` displays `State store ID` and `State version`; `runtime-playground.e2e.test.ts` compares them with `/api/runtime/status`. | Intentional deviation — concept-only `memory` is replaced by the provider-owned durable identity. | | Last-good banner | Green banner: `All outputs are from the current runtime generation (gen_00012345). No stale views.` plus `View history` | Failed/stale output leaves last-good evidence visible with its exact generation and a phase diagnostic | `compile-error.png` shows the retained last-good identity with AB8206; the capture contract and `runtime-playground-hmr.e2e.test.ts` verify exact run/generation retention. | Verified | | Agent-visible output | `SUCCESS`, `Hook: pre_tool_call`, JSON policy result, `56 ms` | Hook output presents raw bounded evidence, status, operation, duration, and copy affordance | `runtime-playground-hmr.e2e.test.ts` verifies a real hook result remains in the agent-visible stage across failure/recovery. The approved captures use a timeline App run and do not show the concept’s policy/duration/copy composition. | Not visually evidenced — the full concept presentation is not captured. | | Native response | `SUCCESS`, `MCP Tool: get_customer`, expandable `JSON`, customer/orders object | Native response preserves the provider result and does not get replaced by model prose | The approved captures explicitly show `No native response was returned for this run`; no cited capture test renders the concept’s customer response. | Not visually evidenced — no customer/native-response raster proves this composition. | | Model-visible output | `For model consumption` plus four-line customer/order summary | Model-visible fallback is shown beside the App only when declared and remains distinguishable from native output | `desktop.png` shows a separate Model-visible output panel for the selected timeline run, but no cited capture/test proves the declaration-only condition. | Not visually evidenced — the conditional availability claim is not established by this evidence set. | -| MCP App sibling | `MCP App preview`, `Customer Lookup`, status, five-row orders table, open/refresh icons | App preview is a sibling stage surface; no iframe or App node is inserted into the decoded React tree | `mobile.png` shows a separate Runtime App stage and the capture contract proves an opaque child/stable outer frame; no approved crop or cited test proves the decoded-tree exclusion. | Not visually evidenced — sibling rendering is shown, but the complete tree-boundary claim is not. | -| App result copy | `Acme Corporation`, `cust_12345`, `ACTIVE`, `SHIPPED`, `PROCESSING`, order totals/dates | App fixture values are readable, stable, and sourced from the selected run; sandbox/profile evidence is visible but non-marketing | The captured App is the provider’s `Runtime edit timeline`, not Customer Lookup; `mobile.png` visibly labels its simulated profile and non-certified host parity. | Intentional deviation — the capture fixture exercises the timeline App, not the concept’s customer/orders sample. | +| MCP App sibling | `MCP App preview`, `Customer Lookup`, status, five-row orders table, open/refresh icons | App preview is a sibling stage surface; no iframe or App node is inserted into the decoded React tree | The capture contract proves an opaque child/stable outer frame; the raster showing a separate Runtime App stage was the retired mobile capture, and no approved crop or cited test proves the decoded-tree exclusion. | Not visually evidenced — sibling rendering is shown, but the complete tree-boundary claim is not. | +| App result copy | `Acme Corporation`, `cust_12345`, `ACTIVE`, `SHIPPED`, `PROCESSING`, order totals/dates | App fixture values are readable, stable, and sourced from the selected run; sandbox/profile evidence is visible but non-marketing | The captured App is the provider’s `Runtime edit timeline`, not Customer Lookup; the simulated-profile and non-certified host-parity labelling was rastered by the retired mobile capture. | Intentional deviation — the capture fixture exercises the timeline App, not the concept’s customer/orders sample. | | Inspector tabs | `Tree`, `Result`, `Flight`, `Protocol`, `State`, `Diagnostics`; `Tree` active | Six tabs are present in order, with active semantics, keyboard reachability, and bounded artifact views | `compile-error.png` visibly shows all six tabs; `runtime-playground.e2e.test.ts` asserts the six-tab set and selects State, but does not establish keyboard reachability or bounded views. | Not visually evidenced — the complete tab acceptance remains unproven. | | Decoded tree | `Decoded React tree`; `Show component props`, `Expand all`, `Collapse all`; CustomerLookupApp/OrdersTable tree | Tree is derived from decoded React output; props toggle and expansion state are explicit; no JSX/source editor appears | None of the approved final crops shows the Tree tab or the concept’s customer component tree, and the capture contract does not assert its controls. | Not visually evidenced — no final capture proves the full Tree composition. | | Protocol/state diagnostics | Tabs are visible even though Tree is selected in the concept | Result/Flight/Protocol/State/Diagnostics retain the same panel geometry and phase-labelled error surface | `compile-error.png` records `source/build error AB8206` in Diagnostics and `runtime-playground-hmr.e2e.test.ts` verifies the diagnostic while Result remains selected, but neither proves the same geometry for every tab. | Not visually evidenced — only the Diagnostics phase surface is directly shown. | | Trace table | `Trace (2 events)` with ordered hook/tool rows, generation chips, status, duration, details | Run-local spans remain ordered by sequence, bounded, generation-labelled, and exportable without becoming a second durable trace store | The approved final crops do not show a Trace table, and the capture contract does not assert its rows or export behavior. | Not visually evidenced — trace-table acceptance remains outside this evidence set. | | Trace controls | `Auto-scroll`, `Show details`, `Export trace (JSON)`, `Copy trace ID`, opaque trace ID | Controls are keyboard accessible; raw export/copy are bounded and do not leak credentials | No approved crop or cited Runtime capture/E2E test exercises the concept’s trace export/copy controls. | Not visually evidenced — no evidence establishes these controls. | | Footer disclaimer | `Simulated host environment. No external systems are contacted.` | Disclaimer is visible but subordinate; no fake certification or external-host claim is implied | `desktop.png`/`recovered.png` show `Simulated locally — not host certification`; `runtime-playground.test.ts` asserts that exact text, but no evidence measures its visual subordination. | Not visually evidenced — non-certification wording is shown, not the complete layout claim. | -| Typography | Compact sans-serif labels; monospace JSON/IDs/trace; small uppercase status tokens | Type hierarchy remains legible at native and mobile widths; code never depends on color alone | `desktop.png` and `mobile.png` visibly show labels and monospace values, but no committed contrast or color-independence audit establishes the entire acceptance statement. | Not visually evidenced — visual hierarchy is shown; formal accessibility evidence is not. | +| Typography | Compact sans-serif labels; monospace JSON/IDs/trace; small uppercase status tokens | Type hierarchy remains legible at the desktop width; code never depends on color alone | `desktop.png` visibly shows labels and monospace values, but no committed contrast or color-independence audit establishes the entire acceptance statement. | Not visually evidenced — visual hierarchy is shown; formal accessibility evidence is not. | | Palette | White canvas, near-black text, cool gray rules, cobalt active controls, green success, neutral disclaimer | Preserve contrast and restrained developer-tool palette; no gradients or marketing cards | The approved raster set visibly uses the restrained palette, but no committed contrast measurement establishes every stated accessibility property. | Not visually evidenced — visual appearance alone is insufficient for the contrast claim. | -| Container model | 1px outlined panels, 4–6px corners, dense 4px rhythm, 10–16px padding/gutters | Panels align to one grid and retain accessible hit areas without card bloat | `desktop.png` and `mobile.png` show outlined panels, and `runtime-playground.e2e.test.ts` verifies 40px control targets, but no cited evidence establishes the complete grid/padding/no-bloat claim. | Not visually evidenced — only portions of the container acceptance are observed. | +| Container model | 1px outlined panels, 4–6px corners, dense 4px rhythm, 10–16px padding/gutters | Panels align to one grid and retain accessible hit areas without card bloat | `desktop.png` shows outlined panels and the committed `styles.css` sizes Runtime controls at a 40px minimum, but no cited evidence establishes the complete grid/padding/no-bloat claim. | Not visually evidenced — only portions of the container acceptance are observed. | | Focus/selected states | Cobalt outline/tab underline/current chip; selected Form, Tree, history, generation | Focus is visible, selected semantics are announced, and pointer-only state is not used | Keyboard focus restoration and selected states are exercised by `runtime-playground.e2e.test.ts` and `runtime-playground.browser.test.tsx`, but neither captures computed focus appearance or proves color-independent presentation. | Not visually evidenced — implementation behavior exists, but visual focus treatment is not verified. | | Success/error states | Green dots/checks and `SUCCESS`; no error shown in the raster | Implement success and phase-labelled pale-red diagnostics; absence of an error in the concept is not evidence that error UI may be omitted | `compile-error.png` visibly records the phase-labelled AB8206 diagnostic and `recovered.png` shows its cleared text; `runtime-playground-hmr.e2e.test.ts` verifies the failure/recovery behavior. Neither cited raster nor test observes computed pale-red diagnostic styling. | Not visually evidenced — diagnostic phase/text behavior is directly observed, but the compound color-treatment acceptance is not. | | Stale/last-good states | Explicit no-stale message plus prior-generation `Last good` identity | Preserve last-good output through compile/run/App failure and distinguish stale from current | `compile-error.png` and `recovered.png`, backed by the capture contract and `runtime-playground-hmr.e2e.test.ts`, prove retention then recovery. | Verified | | 1100px continuation | Concept is native desktop only; approved continuation moves Inspector below stage | No unreadable third column; bounded trace scroll; identity labels remain separate | No approved 1100px raster or cited contract run covers this breakpoint. | Not visually evidenced — responsive evidence is limited to 1440×900 and 390×844. | -| 390×844 continuation | Concept is native desktop only; approved continuation stacks rail, stage, App, Inspector, trace | No horizontal document overflow; controls remain reachable at 40px minimum; reduced motion and focus retained | `mobile.png` is exactly 390×844 and the capture contract records zero scroll plus host/outer-frame/opaque-child bounds; `runtime-playground.e2e.test.ts` verifies visible controls, schema inputs, and associated radio/checkbox labels are ≥40px and horizontally contained. No cited evidence exercises reduced motion or computed focus visibility. | Not visually evidenced — the geometry is directly tested, but the complete mobile acceptance is not. | +| 390×844 continuation | Concept is native desktop only; approved continuation stacks rail, stage, App, Inspector, trace | Retired — the Workbench is desktop-only (`AGENTS.md`), so no mobile boundary is part of the acceptance set | The desktop-only capture interface produces no 390×844 raster and the capture contract asserts no mobile bounds; no cited test exercises a mobile viewport. | Retired — mobile evidence was withdrawn with the desktop-only capture interface; a mobile-only layout defect is not a release blocker. | ## Update protocol -Retain the approved 1440×900 desktop and 390×844 mobile boundaries. A new row +Retain the approved 1440×900 desktop boundary. A new row may be marked `Verified` only with a direct capture observation and/or a named committed test; source inspection alone is insufficient. Use `Intentional deviation` only for an explicitly stated as-built constraint, and leave any diff --git a/docs/assets/rsc-runtime-workbench/mobile.png b/docs/assets/rsc-runtime-workbench/mobile.png deleted file mode 100644 index a97cfc0bdbb501be0a150dcb2817325100825dd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53199 zcmdSAcT`i~7VjHGDI%btC^aI@1}MEpK|xT8ARt|&Ne#UxQIV$fDlLeBi1Zq206}{1 zH32E1Ce#E-d;IPhcZ@sUd-sfU-u>(SyY|jnd(AyF_ji8gT#1mX3b|$ z^Z@{xFaUt|1;e?sktvoeO#t9BK=aAtSN@sX%}l}UhNo26F@!OTgP-=Q!uzbFw`X6ojTn51GS{;tpU?edHw>ctPcUs?I6fqVJGY8Ua-MmzD)p#Q7S){|d~o2C(u6B-JbIr)oEGHKUfgK^AWJLTxf`)PSz`OBX(AK%Iq^ZYL6)7mk=XQCEFcy#?4ea57K#Y1w; z9g_`<9m<`Hk;#V!9JcCKK9D-c(Gbb7+R;BEgkZAHYS$bd9&zgyB*JArD%f6Cy)Tvr zZDwii^}tN=VWnd`J|teULbtAwwM9Z23=WTS&#qNf7FOfIyJCD)$bq z>+?EXJ^E{B|D9Hon&N(#C1eC@`#bYay!Mup(1q9q5aip+3c+lu$++1SSD`R}F+j#k zmy-9PqElTpyOij@j8_i-)DYd>J76#fW~BP)V=wAMgTpB)Y+E0h2)+F2Gp0pq%U^pW z9<14gsZ7_2WChr6d_tD^&i2eow^aF881kCBnTv=YkA1YnA&*fbJ+Vq=59IKVdC*44 zzlOe~s@S1zYV)$=^EdasidMEZ2YhB?Ibx4p>@vt>mY^rTWsok)%%DvK*F%rf5&^S{ zH#!i++N#5R*KU#Y5a&+&LFzK{*Icu;_C)9Gv~fQA{lj`mT(kCLt?zBImaw)3Kg-AH z0dAy&W=^AtM!gt3$2mYL=KJ*K|L^|__<6E6QCj<`C_m(H_^Ki=z-lI7-h`rO6 z6~DLPEw(OELm9~0)r~f0?k0`FlX6{Xi({zWf@~oo>1%cX`6PgSOm$G!WeZ=usd~`Z z@(ZsC7QF-cv0Y(Cq*s9jwezt6RT{`yQ`uiCD^l zM!G;8Sd-CfFN zGX_1)H(*aW+?TX_?#Ao=&g;aP#VT(>CxV2@nnIz&Byf=J$jYvZo(5|8eIF}e^hF!T z_KbTnd^}QHZI!9nx6>XjHu`{zk5^hZ><2cUIZ#|v}ISM!o^v>gTjv7qsRT}*gCA<7!4I5^H z;&55JV)uJn7J6R^J6{avYWd*O-;;^&1(h@IbpP;B-8kMzvqCn&Sg#w#ZKN>)Vc*3{ zjHyyfeL>5YtBHSDD+Z(?Z_qMMW6s;>(`=(*T{&}(ZBB~Fpgwqm_i6`!p$Kh;4Bc=v z(^r$U<5^_=3ktRw>~`u+h`Q2pbErr7?tr-*m@7-Ti8M$)iD}5`SC;HzOu2%bqaN;j z$p+6;42`U8}48`ffz8HwUO? zlYJX(bd66t?)B?krZ)R{oiwXOs;|%X_^yoNfu$DEKWOJylCkF&HGx?*H?iW^y4S;0dih#+AP}#er9}2X-WjjOcj?7%PLE%1 zFfeC+2Z~X#mlJBY%cl_!XZ<>ry?!t?UnRR)aA*C%eo;7X{!ImWso%;j6pt{u72oa( z)x1TiJ+)pL*~y-O$1iYH6~9Dp^zSs%)@oz!ojzOa(({z~3X)i=d_687_fpx(CF{dg9>q!bt3mNvnCKKa1S!?^Yw2CX3;`P(zW+hfd| zNX%jmdqFs2hEe&>pW7R$8NF5@d23P!<9_iHr?<<`%=s-e#5`^>FYib1N{HZ`hn#?d zOi2YS=u%Q_JhVAzNVi}W!b--aX#-xs%qRJ2nq))FhyTU%l|JY7UXEKKOP35y^EYRH7;bBb z4Ebbw>BjRTRo)`lX`D*r>2v+DQN3!N2&fEH#?du6v{a|#YH6zN3(`d15aqarT(rm9 zmq?$h6y7pI*5?KRH2w5Pl>;|lZLzZ@2#ac2dR5}vuYq0Emznr1;^f)7cw^lllo`U1 zWHvwV2MEHii4uZf7A8zV4P@Umc8xoAF7_lYT|KbX}Q! zfjYAMMa3!oRtb==^z;1R{1xMD@bvMjqFGCaF*6UyVdM8+2-}?qx|u&R40z|wnCv#` zpI>}&GmRDb%I=R7B!(PN|UZ9^joo(P9 zjbwrav8E`o@lNmly~q95n2(zOr~j`T~};}lx6*OX?vG}_@#y$I#db|?1m!-VfwLN;r$DA*#y7u&JW zISE7y2R9e{brhU?D!qZ7zM@pfRzsC#0B)G6?2OVyPq?AWmzG(3i`11>z~%}K5p|B=FpUV^X8Ww<2FL$WN2Hq_y4XI%oQvPKUYIumdZfKxwCc)^b`XBK_9I(|*@>rQl~CF2G)P zmoyM(dHemrD?wVRm)Ld2$ZEgX?hmdt;bT=*8&XQ|u8pOsjF9ii@SGO1FeY66^I;`- z(Ham)2 zq(ZTC*pi|xNe}-~`VIK(8!pceB`PjjdUYR11U}4y<6LgV{K-4wm9|b-+1bTWNMyfw zgXK{J@w_oT)r17y=x4j(K@aZEBidI?@8J&_)8UnPKK!exD^wvo1XWBpR$Ob<^4cw{zcJB0ly&FXfZLjN%x|k=dyTAf0IvdYqm@= z6y1yw!LEOB1(pOX^%xgh)qKrXNF9GzZ_qjJ3JDtc0cPRFAPKP3!L2^H#lZ}rK<}_T zXdy`aH4pZETn;WVRtEbg#Qo9VprEzI2H9gEYB zco(R|g@?SAEn|EVZmY|UvV0i7Ip>@U_k}eqErWBL?aq=&p0D!GsyOh} z%#N9=#w`#8vD%)R4LJ!2+Nn3lp6=$lLv|c94jPWT5;FQWOfb|JW*GE9TSnLy@oY=> zCrF`b2X6oH#s6dhV>@VGW*A|DSmq|j&wUobNxPccA1|oDFhgaju*2-dk!20MOU-ia zGx}(4-R4#ucI?B2k+gQSTM3yi95H(OCR(K$QiU5X9E*>e!%q8N^-1A#C8))I_#CPB z@?Conu1-}WCQPLUR$YQ6apH%X?0VzaGp1fGmG#Ce&!HhZ$|7^l=6_L>eA*e4{5ECe zvf+s^1|T_UIMG4JtIV@9lAx^dBIvM!CL40PIyYowou!p4k@lB#hgK2Fo^+V~K%<39 z_LD6&t@UXA%80lhd|UD~nLGh2HZ>{;a$Aa+-&Ua#jx_G!v3H>6bEMy>-%S|^83iT9 zqMSOZ8T0m#T=NW>QfPhV(+xFSlM75YjusC#ZDMl_-j+;Puf+nxHudcU)cfxaX7j&* z+M&%ziAPznz0})JX!6D*A_+=z&Ju%qU)Pf_aauhfwJP*Icm8z4cdd!uz7tNHa7iD1 zV1ByBoE?1JwD;zG7mHins`Z+$wNu%S$l_k{KszC`Vs@%|_ekMW#E1PCYlwicmAZ3< zCjH+^;F;Zp| z!&~L{GjL6lhua8MzX*TX1%lO(4!W|Hk5+65S2a*U7+~#yTwKzugY8;Ltk~Bi9~Cvk zj*gmgcx<*r2eGXHmyB&*p6U9bZPv;YfNS@I2ks9=#A&CSJXq>b49d+qL51C*Jl?a7~%v0fG6jlu>kfoelRpuM%BF|rC2(Q5Dc3`wg3x_O znJqYJ#pnwF;C-RAE_wVdQ)jJ^{9K5Go4SkR~NTmURO zJ-!-a7R=PCnHJK6PtlDkG~8U|ykJmChZm;5>nYMB7$1`Jtbp+SjCxf^s3veB-Y5at zti9Um+%!i=^@TD`o^ux3|X-Wk{>DMmmkZ->25J{~xI9n!Kh)~Z{u1wCC$yc@Jrcz_KGmFGMjCjI5+ z#%HRYfwzGOSH<_^FD1W*#uKKx4#=wklwz3M;M%D;T}FPqrXN1iZMP%Wh z$r@^|5v;nd;(fXsuB%KUP2S#=&#C_Xbc{<)M3Z3Yco#Jb+LQ4t5>7ZYE)W5o`i?A#aEoblIb|h-A?2&+pt>-NOsz$`H3!jr(=II+l)gN>UxuS(1dRDGkY5pd zWM3}nk>;YpCk;ANYbSHy)lQq`ThQ6nJ&0X^_mrQm3U$1MmhC!$NBLlKM48f9=G!-@ z?fhIB6@=dY*H8AV+HUB`;8Uj4%@bTNI4~-}{4A73??T-%DLXmett&iyT&9c_ zVX7;KP29J=<*;N0*kcnPZS47Wi^^uLl zaO4cqajQ#lhA-F3>}vqrsoLm7c)W@l2<`c-+rHkwFZ-e;jfBHy!ArKDW6^|h=gzd9 z;`KWlW$B9CJF(xXl=8yapl1^PpM`_ou#SVD`GR^%UvFs)jYlD|hZVD;X1>s)p#mgm z0lX?ME+{)J@a^C%js)5sYJhgUaVi0cm6#lG?Y2UeOu6nt&UB#~^;fX7vqkK~hslx5 zgFr;n!MD9^AkswM;$&BQZ!25}PSEQ|X|5aR|B<)O7xvXs9lCGoZ+5U}0)uL*-cb{o zm#Or`U`44EN@}hK{t@T`=*aWu(0G~+QR<}>RuN6}>9pt~^yr>YEw3BWar+&CkT5b; zld$w?RU8=nOzeg^$Q4GRU_hjeaJ7P$_Qa6dnqJwZm6oZ}wm_+0i}h2$&zxVU>xf$i ztjJZ!&VZ<_@>4{XD>breP5Y|Tewi9|pKtSFpzp})2s6xBZ!#Uk1wCjt)Y}IKXq=IhOSGUnjGHv*2}#h(11%6rQf`wP(ie!vgCe{ zMQ6^ql*i{*(g}Fy?Vn(>gR5rA15121U`n#ENTQROqdP72=%gh!hfko&ZYn4H4~*bC z>v>*NeF*90UDlBUPeV}jC)mj=M%2KHzUl!H9frLzhp;UXL1emBO8x z_mfcA2s?V!zHx;xZAF}DmHD-|oWhDCZvv2|U2&NwRh9HQUjq$>vZ$0__~Bw2&=U1K zCDb6a%?h1YJ>nI0FQ~~Tz^kvo*$>jd0ptfa9PqW15iu$v2g40^^;-$x)7zm^A5Fq% zbI)ELU5ie(690Jewx0$2g(jAkKXiRPRCv_)?4FIpM#@p_(R3tM^7IFPA?OyMjweDO zW!$D!+aUbN-<23XLGMdReWjgWX2uN?+wjTyrt;8Q>({6wN#^eQxKGIqfdXm}AbWen z@6oL|{v4*~YpcTGqu1qhwT^9>Dl5dg{SeyUef-J}PL;%$Gm^=Ua8WZ#Gw~Ext}L;V ziiqA0a2pUAe5jKd;+oQ4WA+POa*X-GN+FSaLeS}R64vM*CM_(_B-2xvtux4^5mmWT z2z;Imdnf1=i@%4?br5eu{DpRG&dCO-`rl(1^HC1!%&&TRsFSU71?GjiJcKCX9N1jR zphyDK3pT%~G%d~pzDY(1Hi>fnYzpv>-Pe`jIR>K({a5JOyMkhRxh9v3vfw_{Us=0F z{r>lRh~!V1Q!|UQ1P(Ug1sfB9 zxb^m7i4!ThMIh>)NYBsjg}J6T?5ND7+_%k`LuP`qH)ef{&K9MBD@2N5K&N}L_X$?x z`b~i^a}C+wRtS2x->&YnnW^6>0>Sa6HeAlpWD#@bu2vyOWZt}g5VZp30A)t_c#%>)TasD z7oh>{EL$By8^p57Cf}8YvG7pN?>4VBh5K9BhvvI()r>5LU&D>dXfetMI-w5vdWuj= z2}%O-(L)*X){nFfOpmyOwmPE9REjAV!(A@1(-l+~djpmFYB%n=sP8ms%YW(ma>)s5w`%@a?d+l9N)gJ$Q zm0#Zj43Kxw)!38YqOw2L6R2cpfdgy!@Z!t`dD@`ErqVZ?KVc<=*KqL@84cfsp5Yec zvEM7t_RQBUHM&-(bawU!T>_``-v2Vp7eU4)+wDe3(D9E#DZCq3td&T%RfDRLbxjlQ zDEP`%Hv8L{1rV50($3YcAmRr(e*EHnobC9^Z+hVA>Jy$f6flVgQ%ET&c&OOJ%*pQd zQn<_%QMA<2IyQsIIzvUc^)&WV*l}AtpN&XS7+wxBh!71pynGk7RV2Da=tzkDy1SSV zWRF$?5Isak;iv<{Rd|@+iuQ#+tPAt>St`R?LK@Fr$vWi9+yyDy=XGpIOW;mq>C3Dl z@0A~nkt;6RE>MQap&m1v(!TK36ZpM*zm%uFKWm+`)LXBGgt89yY=??{`jWv7sD6s5 zav1V`uu%$e>5?tqdG!_mC>0aS;%a5p`ZuEdKbBAblKdW_*G2YlOacHv$EUZi=^8xE zPmU78E^UXOEkRFYwOF#7Z1bQ!%OU=QeBeJ=x?_T0Gk7tYGjFBgRnKmKVR)st98?8c22TJdjzrio{y$=;_3BdKH=nllBWOB7a-WNOr-(1PmD<0XqvY+ z3#fKWFq{Xp8a_=;6f9la;ORNqG(NVXF6HpJ&z-H3+o#Evc3?gbPb~_5KfT*aPvegI zXZX2-TVAj#D*DMgXNDhCnzNBFVF<=^S0d;I&axDlhRrB$t;c6c2*i7&01;n%y-zyoXHUk4u#w$eLD{*6>j*otln+kOaWtk{&|)Q#peP4Y1X%4%1_#B zmR(gk?)ekomPFjI@Q_`wx~4v*u*BR_e+M%nt~g!PL|C2EkZ}IU@Qyo95FbL6EKo6F zFAWHG8f?xk*B<@<5)47PuuwKL^ose zLqo-S?V)Sb$mX4B*B~bpQuI)N4>*5QYl`cpW=Y#blMHxvyb*qEJC!oUR~O)fUEyRk z4*UCq4g;fBq{+Ta*y@g#ZIXQY^aD9wv1;Mbcl+7{kI zqAex)kXObysLgHe%V(ZBWuI@A8n`e$AB1LuvUNir=$7-;+gt3fcNC+8Ti?>}zI4UP zW%f+}h{EKY__u0)y$gd0rT+uCUVf}WOov}ERwTGuPaK%3>VyQ z8Q{O-)5o-hbZ==niRTyb z`6~`z;uZqX0xe02oa}u5yYS*V?qm-e?0PpE4&B}($X+n(=4$C{zNY-9XvUr>eY)6# zp>iG^)}B(1s)?<}n8NN7?}tDWY_wo+9VE1!>^Rfp z^&&423;K|RZaSG+ONXJ_oA(ccK6dqm-{nA4#Tvj1)DsZI?P80~^(o6Lf8QxFox39K zFj&)ZPwxZ%)O`vs2FHK}0beD`m zY9B67pvlAm)oQyw!rsN&y@iOQ)_d`a)O{EdCYF2w>C!?Eh!a#QUPXZ1hpvA9=83BZ z>7q*S{iau;^l^9&Ch89Lr@S+;?VZV3EO(0l& z2W@ahHX|P$xko#*5;braD)0bW!B< ztI8B5>}xHR)el`5O$22@^hSLqPTW~lmV#$xT`29pS;!3*Z@~DbziX!d$XvgiL9Zfo zDEhd^18csRs5{M#3)+P9n1)GGcRtZn2-h4fTn>Ey^=KV@up+UVDFQ!T)jNm(`3@MD zr_-wOaj6`4)I^!e*V=8_Ij z#Ybt!ic<`JU*nIs;5~d^~_Ex{&vj-j!xtdpefQTc$@RWXK%ho2?{j)`I2Ee75=&;!Yir0SmHMF zSkA5}J761p$G}YkW_8-%g^9gk!ND+-biz9DU7(Q^-|@j~EYAPI{*vDBti|7ra#HVa zG3cvU8nrBk{1Ux$0BmN4oIE~?i6EuufX5@HBLwT-$dyL;KS1DW-e~vT{EgIWs*R5m z&s6Q{W{I+{49MXeA7+e&KyS|;Kdgtr1P0Z$mTI9ur-w8%>a0=&6#+t$Z$0_IY(qk& z&dZIDFDkcIX&SIPOP!mg7c6wmJMOzaQ&F_X{i54}Y_EE}bNw!R;#elEPZ)L|#TiVk z$j|PE*ETnnk|LvY`OHqCw*#(F=$5T(1s?V*v<@+Y50IZzsjv2g_}-ek_o1xtv$)5ludI+0Y-$dEO057~kMrG#@dGg~u26JQ2bvDb4=lnIzHHZ?Aa=Qp ziVGvd6HfF7QjyczANx-SlmZq@j8!5b3c=mvHevG$nZR$N&rVzsc8l;UNLup&E0h;7 zM!K*Br`|-5x_Fx4)+5e(=hZ{EFh@4;9vXL~! zh(BrF7z*b3&C(kq&8pliP;eM~uqx=W+%yHxSPVL?@Jm#bc{zs5)}@eB1>6Ij)`D^l zp!|yLD7S0pc1{-~IX_c2Xf+;+kK2;);1{2J-> zdT0J}KNbGa63UlB-!-@c>nE>#=x;M2Km+=mV=xC|w)a%-wrqpNW6}G=PxNx~p7c%m63fy8T2R|AHwST-YuFhILV~tQc!FyHSwHWNKsE@_P-K7&$LK?Mj zSMd2CmF@z6paqA$W5`L{6FLN#H~0(8~r z>V@}3iDFJdSH?vTpdd`=n(k^%#hMG|9mLh-Ox3ek9Muat{cfTczIm3-NR-muEA-k5 zzu1zOot`M4*@TQ-p2VkD1@9(;$o9X=_X}4Poc3{lDoYsv=D87;2@1_;|A;=^BxDJS z%V8WyadL4UFe!Ex0(*L)=JD-?>o0M0giHd4rKCiZ3DEjSbvwrFEqT~48!k{Rt%W8w zn&3br1g{Hfefl)Vu4N$6;2EXE02oXfzTnp0HnmI*{k;?j7ryf+8bhx4ba6FV3N7AM zIaA3`)whjC^DRMA%Xm-{DE^3?eNp`|{;=AJruEvB!vyauQ>?D8114g6RYDvOL{?2?JB>-s{SoAqiXPbo)Y49} zJdRj~Je>S-v)J|`;Cj@0`&^beD2erz7+m^Hb1IiXI8RqDSbIhXR4T~xPW7f&9a$5; zRDH73E!#Tyl3*bp3yMceweni4HTs4s)|pBGQTuox+@Bos;H<`D{-At#=c&M%d^Z3x zpv;bzM(@AQzf@=XA=It$(tN2diL-@5ZvLhL*p+;5C?w9YA_^mIGM#OG=v?uCTPOOz ziGC@IR}!y!Y_*~FYY8M<(dr+IKjzR3pMHJu5~f1OLQ8Fi*HjltDI#49Qe_fRP`(m8 zpjd^)T)u|^)r~1Thqnn z1^f<|ZPrgxthD-N>u%K6mod%q+WhzIk|Z|Ju`kqACxj53V{I~VHy8}@IEXuF{yy+o^bty(70{Yb2VGYGAA*%lqVPTrMLf>gv%C8*y?WW# z%)VKI5rFy(YM6tBtsE$+0sNt@239Y&V0I z=!BeC^?nzbIIX(al-VDrvit1?pB00-jB}_Bhwr@GWH_H!@g0|AZ9lW*crKk=`ntL5dfH!8TMmROo&)&WY5aYP1`H6(5U-`|n2`3I^7(FCU?N3oCd!@u= z*?lAd#1Mw_TF*}bQ9I0tJ}+YtLh@I zkFB)Pm2aWx(m!f$?OV)9WN7P5iK|gq!@-FK`lFCMaf_0~mH}_1L<4 zmX9^MT{3RQE!XiTXSDBvnEFZ;&+ zjaPd8LBWm5{8es^79145=oU$1I_DyQ@zuDz!N=YEYx6fwR>+&WRAeEgv(e4@M%z(5 zZflt~GxpO~WYndE4r-1%nlJ?9GGYc@BNK}11sm8d?-;JX6)4UIN-EC0^yFNo z$XV3;7Ym5amVMr^k$(-?WxU+^_!c4Mfb}?=8>KUDkJ*acF ze$@TZXk-BpD%*-c(*oQXX*8X`Z<+l@cG+xorDVWq44CUYfX$N zS+OLxX3woh=GddB+|x4m+Ue0Smkp6hv>7x*jqNZKge3LtJ`V#;x$of55QD;-ot?pU zBD!HK6;{6|zGc-Nsi+eC^J6_Z+KhtdEN);n-)WtlGX^ecgPVBcsP>kV$&nXn9;MO= z7D~EH>tdd%uYkLccgDO{-dv_>{X-9bzIn-Z&`Wv*GbsO}`!mmnTmQryx_=vUyyZ37 z);7k7BWbfDMKEmo=d%a%ZO9a4JUDD@f!b*uExVoG*t0IjP(zG$(fH6EUr%rnVaWh-DexQ2xQ zbx!NwW4LkD#i5LDG{p;p^RyErsc-;Fxf*^ZcU-6qi?Eu9)1FOfeBA>7QuC_|?fatm zQl(|}ynnuNVhul%J9a#Ae-tk>e)G<=ie7ai(%?&Dt6Bp zobiS7vugZ*RF01*dYs^o>#I-L(ifVtQ$7~DFLe%Jk$yJHu&VFpt-DGZ*?k}b@b+o_ z@9NeMW~G6pY(d5fuf9)LQ^RgUWx2u^(PFJ6_-sJ(*n094VxA|9Pv$lgS&xun(MY(Kkp3BYGzJwM2fElU z<|qeuw?5C)O4UjzhkQDExA-2)0C-<|PDcDM2OZyH>N{_%U$5Cx^j#MD&rHqZ|8AKk zMvOVNSL^ql!0r^_+w+g%_vf#*Jr2C{M&HhE#U%{Hnhi;`@2ixZN^V8NVz zrWS;egDCO&hj}^YL|RVz5-_s7>YOcsZX2TL64Oe1pjP(&#}nB!WwVV6+j`mikouop zjpFyw!R8Wc*yPUntTL0Zs(M*Bq{K;dr(}>;qSGd3r%G?=d?G{;19nQtQ__LS$ULw z{1M>jlkoP=gr_E>F(U86s?l#GYBUbVmqI|E^aKdf{txn550h6o!6hE>RM!i{7r}!@ z*o@t4gej5dZwAr__3 zHAeYQVx>!L)q$E^@+k=}DtyXyTaPSWBb+|uooa{if+ zN3rj}ynijo$SRIi#32)VRelc_E0+6Qzpi*gTUhR7fxfKc@R`KB`Q`&$KWAE?M0Jt< zGCkgP36f1-4w)Z0&=Atc_cv^X<}cgy>LYNu2)KFG!3qMqIouJXk)>$=Jse_2czR(= zolV(iKcl2ZqZ2*a@-%%5Rx|$k5z{hN%9w~hC^G_*_N;(A_q)@_4}ux#sz-;hXPgDvMRUnB4=Y-@fAV^nw{ja`EZ3F0xWL$1(uS^OF`femzEUY{kl~`#_J6uY81y3)QuBN4D3)_kBC_HPM z#O#M(YURE0)&|(SZtZ&e0l@oWd`H45b7KDY+{W7Q%};(JGwER16UQmpla#3)FXE>q zK~4xRS3#R&qM+dLwBoE|8@l3G)w!VHY-*pLSK~4k77dg&z5E>rlY2eYdol)cLpOmw zH^jm{Frw2oMRP}GxR~#?8;@C9r0=QyTpS^H=~zDdxK>!$KR=Q;TnA)zA2CWiOp0y{ z$a9~QikTUOw|WGK zEaUubd6I(+kfuiw2{d8AjKK^Mg}Sx{9^`^Y)sNkW4aC?R373>m8|DrfNf_U0XK zC?rJE>+~2o{c~O3{;#$+>H4^UvICYJ+dtsyTYk;->`37^g4cG9X4t&M!>zSqC?mS$ z;KWFi^~#3T3*FaC!|sYd6mI0m$YrSC!WlM=jy<|e3zRRyGu)^FGU5ox|%%{fxv=B z*Ihgz?NLY>rc8#vezxeA`s1qF~e`_}c;7rS^#zvhL*1Z=zg)dfYdW)tq%FoLwtL!r?` z&8J(E7m03j6dx%)uW~nUDnz<*@6+s&tgg$H^A|qQWd+n>>&B<-dz=rPjsb`5O9DZx z?o&7g|BFRK>yOFh+JZB+xbOuKpIQ(rgYfi&04kF-E6q3gxAA#!w!7>a)~Z3&nt+1y ziUuKW-8^TCTTXOC`Oz#duTnd2Tf6^pz;})Ty4Ni(Ygmo_RZRN*0#+=^{K2DP)@-Cn zrAb5{kex2z-hrET7fg4iBM6Axnp}ha4PciN_=p)vD9dlhHW82k%Nae|V|V0>O+p-$ z_J5N&j#{9o{mJ&Zb1UU$op{RBn){9ne)k#po6hd68`n78_K?R9oo&VhW-9npcl4uO zuDqET4w0)}pq^UWngRo#0jqKDyWx;`RLwR)9%aBe&DN)?Qmi!31g9K&=v}6-9tX02 z{??Z0R%iKsi3^iR^U9@gS~J zgF!avr1++j3AN;7+wI#k%>BYGI z2E1a+kX7?kKcbM0wLZN?In>0(>_u(cv+R1fb_vnyVjvDOVNFIK^> z@UdCOTFx3FwzuMU$LF$hsDEm{LS2N6l~zK zlKhntcsviLQQ6?n0TBXSXB0Tc==Yqe``sWc&j{NoW-P2&ULC$Hf_l}7;<4GQhRx|iz46d{# zAV~+Vgpz0yZIwx@Ok~OMrmc6Byv~HmMmsBtG)3d+X%k|#j@p*;st4vOc<(l=RKc1W zM@xZEk4W2HPi`{K%PjsK**QBg&ikUl8K@X|W1_8N&JUUj`9~l>GR`xgZ88|8xp&qc z`d?Jt|ECv84~{Y<_(WB;3J-RV)Lw}wUb=`*=c)C*3(?!7SiBNHB)Bi{EK)6A05h%`vO zd@*YvU+oc_ma~V`Q1vIEJ#vB-Xsm#xHB{HmAj*?OH<1~U&lQ&bu2krEvVt;#DhMR;dGxGC49=Y4O zeM#6yEUjT^yzBi~**{8ctMp3s-Z)e2zXW=~p9tOV3u)6c&dYO58EoOlxX!j-F1no6AC^>t|Es=K(p8I$oqtJ?qD&v!>1c9GnU!&|IF z*cZYPH@TFQV^&EzA(m!m!ijyeJtw`_&J=|4PMZ*Hcy+l)>rG_E`X##w>!s*2&q$Vd zqkO~0`!93i8ecf*1@K%F&0|)GiYhG@9{s8dky~u1&L^)0G+IXh*_>^Chor zzok##RzFgjs^=DY9LJo{LBAsm2^f%X|A}&VICG=mvF7FK&hktKIx>ry;oH_9w%0bL zqiOEz=eV)e3*WAR21KTR!C)&5Wv<2j5Tx_(u&KK8$_;tz^(xB}fj_)w@oi6Lun_JS zo^dKn*;iNZ`B+oe?+4MdY4M5S%!`eEn@zGu7gG*BBSq5krsXzK7}Laa8-FtFSRqn#&xqCR#ZS3dlUz%qvColD z?sA4CXpWC>)-<-e&b-XRIz1wJAMMHvoq7m9Ef|qO{g50tH53VdBPnsQgoQsrEg?zO z<^iXtKAXs92x`$T?R`q2^hLHwV@uW8yX`VVeZi-_dt?_cT^{z04b zCaT9NoM%!dSHblIL`I`hQLS4jsvy8XOof?LX4A|I8P z$Paj@bG;@(bye~-3E``nZuSY3g0 zl-`T>=ZL?vSFC243VIUAwPO&fHPN9dXc(n#WXY!r;%0c`$6tD-OZ!o}!8?hx z)p=s>UmN-G#xHZJ+{%(9mk0hghUf*+KjNfjn)oj&TnN3{#4NQm8z83n)QOGZhIj>|cBqC>yVH@^@gbtJ?IBGj=`%@PwUT zv&W>K{3=8KK#cs;GJ0aM-X31^%~dIaarplt?k$|!exq&g3QnQLofd~+E$*(NI0Ojp z?k`C}^iHHcb~NCXaGlJv6cDI5xovqYq}|PdG5>0TbWr1+0HX$MF;5*f z?wVgLzem*}f<5K5LD9mmxN2kKgs^l1*Cz?@>BE3xz%!F=m%@ghTr+DJ6N2oIm?2x# z>-|a<`WRbs(q{U3CA1cu_RmAMd!-WN0GxC$EQdw@5$iFx*$%PUJdu2>eIH^xTP3v7 zGbi}*p7lZ4X;eITgisQWDeY081pHpIs@_tZFly66`U|d-q4A1$uN=`U3&{$7i_XoN zgeY7|&61YtEKNapDzQQHNrukoA9*`DiD~c=l+Cg4tv(fGKTxST&%Nk z&v2BBlqSThQJM^T?bIMH8ngJK1sv@J^q`nF@>a+QZVkx-*Z>+DUqB*1Mp&SOT}9^I z5MeJy_+_$h)xslH5Fa1KGxmCMV~A zPT=FaJG(EFqNomoo~|G-yUr>PZW0kiU{jQ18rwgOz_IA*D$@f9T% z@=Mq`ef~F1JWr_c1txi0$)!Z9h%`EFS4mv3{^Cq0y_QN|BALc#Fv8mCKnN~Twj?dqyZ(+a_HA2dKV`U8i|w;LCgt>=a0c1fcfuP$4I zJpu0Am(&_~jJnP4y5kGi$u>YkXB(YXuKErAld!a$8M$U*an9a0_rH5$>*C`xe|oZs zGD=SLCbggDC%SkZqt0&A*NoS`qP%@Gj&m^m<}A($HhlR17HIl+)r##0wJhFdxbTM}Q*q(?_C|~3U*&1jE~breGl;z&5XKTR>&aW&%qC2y!fj=R zW-el%JU2)7FNK=NB>6%(vAntpI%n^M60_)mm}jnwTIrgTy6Th{ zot%GOk`(~yia0*OKfb9M%Oa}fQDgI@$^^a1qMv}L3clmDstB#g6MXX~F_{Tl1{fHu zT$4CMi93z1HcUFtX0XiQFv5dh0M@tjrq6tmae+QZS@ z;N|I1NkV=Jif$t9yiATd6L)kC%xA45K-h!qCv_`5Ad{2nqWx9V)`v3HEsTI4G5frK zQ>SWQ5%+nNd6*~~hLdOiZ1(yUD9+^R5QHhP|CObwx*)sk(e6*sYa{(o`2+n4hu@({ z9r~M}a^nG%bQshosS>|;9(usyU0=z~ow3Ni;DkZ^BWy$a-A{IAvN_5MDnX_>sjM*=s4lm})6D<(@0|3fV?eO7#Na zb-+;0>Apqx9!E6=~Vca(*rq!N!|n>ELps-ojK`sl!S=DfIqEDRiA z#b*znrTi5xEoxx96xDU;-)i(r2B?;1FPa#Vhs!QzE){~Ap}&b7^2e}FCo0d+Gc5zb zGE_)7a%je>%L9Fb*kJEHseF_gJ#!>cT#iBQpoBFg4nQ0z&Q&0M!xu^+t5b-_u99-) zsbv*gYM&phex(3cxaGt)4>Pj7?_46G3HU7-A;spOh(!LNV(eEvO`=Z}{#p0Imte=* zxbHC_F45E}7JKFTLEe`#mK-ZL1I+==mV9Q&M6Es^1MkBofv6h;R)f*cty$!hVST9V z56N;iKD0n4JWA(Ltb>tNS2s0XE9Hyz#EF>@j{U2W5HUOG0c{HH#1zzTUSP|IBFNFZ-<6H((G6O}e|g4j5~t52R!7@u~k z=s8S6*r81D_iLXbLi1D+IalS1h3(~g=FubTq()P1Q0zorjPaLROnK}QX_j|esO9kPANAI)a#RrNt?+(oUECLL;6F6vOJkT z{?(whbfR?AuR`zAx!abL=y?F2LvDB)Bf5bTN0MALwZtuzhClEMGcN{uQvEz{+oK_hzeMH?eGRe*H~kVVq)^( zAoAtoA#v^O;j+|$Q~v3^9{QY$>MR>SGqaX)JxlrDeza72>e!X$JRY+5WUk`Lyxtg@ z?){$hRChVOlhFJafHkoL}=;Qg2<2|Ez4cu$e+eY?MUjiCE-C zKL2|!prO`j;GCnFgQt~94Hs{Br=OKjgq4oqGRo3U&oNzO>bCZ;>X+Yj|$i zj6bUXe7Sft$PomSGF&f9a|zp~(i6skDu-4&uXv@vkW0rJBgm#Qi;+fS099%GJl?fB z(}R4#+c(a^%>gHnn>Ft~It9?LB_fvWO?X%D86#qlzT9tG=SZPClLj31lf^4gK zcJ4_F5>NYf&l;Yw_R10y0=;+qOKC{f@7uZE*8EuI*TSbNcvZX|N4N@?Zk~Hza+E%e8tK)kGlI8iX^2DU{ z*9E#7grf-brq{CVTj4?tkEs1MJvwfz5b~GuNqL;Mdm-Gt3Ohui2-HlqHS?jt&zV1_*4=0r zXzv^b+B960+rOa>mN)D@p?n@p;w5zr890AGDuWkEg#q_#)RH3q3${z5fDRR-$4RJ< z4-}AD&+Oh$IEU_QqVu|+{&0zHej0it@bt|3eAcz&j&^6Mqs$DUSSrp%ielZ2YAYIj)bydJLqdezkSKSo7O;O5;-KmQvN zz={jHc%;UL^Kt(9vl`KHqeyvkLk&`ZZf))uwH}sE)1h)-z;j zJwFPbLw$aLsZKyG)^Q#BtcX4;e=4iR(^P3gb&-ZXH<^l69IGHEB3e6m!xf7P3 z%IN>PlhJh`mgp3df7W;%`RFO=sd&Jwd2UAads066Mb;nmwqRxy2h*3zRjaJC7Bc;dWOl>E!bQ zizjkBqCiWC0io51zQmDIKE~!asmj$hji6weX$BodCH}_i_`{yVoU8peYRWob+2Plt z$C(F6({{0Ocg@W2t}TrAJ#NY&R=)FV2gY!PY;do;kE%AwcC8aje|!!tK!ezlD&ME6 z=rRI$jA0Iu6jMM^mBS5CmHEngFv`^gCmk)8HyEJv{4APVqQMq^r(?z%knjj7^;0=T zi5HRHp=UIXXR1?}b0f$Gc!MLGNquyvGNw@=r7X4!@p&0dEbWPm{NYY#E$tQ z#UlE34ypT!OP6eVM{@AF#V9H?OO=~#&-JPC%4pz;zv4@=iYXN|It$8Np`)5s1(b^S zp5gt*AJUp@gl!|$03oA``!0+zP}9&sOw@#Q(#;KI|M+zfcj5)rmOAi8h08Cl=~I22 z!tRKY1G{>5N}YcKO(=!2L&&;_m1u>MRRfhAX54p)OZ{m0fuFbg;0PjgTc7&{$;!0= zlJb_FqgkfW6FaH6elr)WR(w|#-ze%UvXn?rMCf^RO5f{UlM(S@lQi?gA@^;|`=C8h zxAkZOYt_h)JVUt49$kOf$d+nff8RzJ=Sm`9Vq7MDMpXz3_x&&UjMOKB}>9IlpOj2;>t62FEe1l;EKn%L0UrXh#dPd|Ly8JQ{AkjWm*GUX(hh zG#H#5Jpj@Y>#YvUnb~DJYQiO=^{S9@$qpGr_Ad6OOXF8t)=f6QYUT5)eD=PJ=s4pb z{r-?TrCX-ZTix0FdF~v;V4!1H;k)(2{1VdK`9trpQcO$J=dp&m{g@4Fpz>ucg0tN)zh8NS?BWkQ4=UBJefdDrwHH87A9TM z-(34{PQ4@_dHh{2J5o}G-=fY=QNJiFeO?$u zO7>mJEAWn4YqHB;*tp@5!Q;P|_&rFk!Y-C?w;vqlw#Ham)?04J10Wd)cJ}R6EX=B@ z4(zeMR$=h0U{R0c>4fKq{n!LpX=$;uSM>HvFh}vxEhBGHof&8=zl&RK&MI3xDhJn{ zPn3KuAF#d50%$__PbE)CD@&g{;Ee@Dw2Kg=n>=9h?Cqz)9Kn4@^{1^d%1d>H0m@LL=(;_$q`#-Kz10CS_`2V4EPi?~Bo~b* z5F0soM(R2>yvMh#O~2|68Mq3{^SGD_h^x2S_?|89DyVZHV@8lo3x<{?xvcRQ?K%5- z-yi_IQlha)4x3Res6UrgoSzToG^fa}ZE$%jqHnxtZqhNBN3>BUGN!vvz2d6-I!zqe z3g+5K$@a6gGmqLaC-I%mB9=x!-dU<)cUmo}iv7>5@bSJrNjRSE+Jp8jTJEPWxLk8F z1FXyLM1s26ZG-RW%eGFB1F~br1X*dv6bV-?+nm9T&*>w`{f$v&b)Az17=Eq!G>ZgnlOb- zH(ugVO$GN0&cH2~JzDV6Nb+i(T?}vR7T!vSbRqJ;6)1I^DZx`c_oRK(;NV2o$EeQj z$#omp;w@?J)!OlTC-~ZY{9MX~aMFHw_xhLSC4y7rrcI6dMy70)-_8aW)X#)i<1P*ey*>-&qw}T#f&xU_Wi`OD~u}sugosZyFaR8crld67SU<-&lim!+dB6C zdfx{~d-;_E@-7qSenm4~*}o1TEdW{&`5$1oquU zr=}?rZMmI?AF=Sn2rf+wz`+qyP=SV)d$tRy&o3EH>&gil^d`><{fC^_qbY+e{+2ID zmQuA{xA`%euT%5lzSZ^ltiP?x$JnMx4MCVqd-DRNf(G$TPRw| z)vvs*+0l@PhQ?a5p~PgxE%wmk^!pqUbt?Uafse*H=DMer@Y+JQ#`+Ubil!gZ)SQ}#&TJ03DX4jVTVBB@1aji z(Jun_H)eS1X)u75-22ejH*f4@-~6A^to~mOo<+K0*BC}XjwWaRL|1O+fcS8Ud4*0W zPsY*M@<8)YCn5<#xbN|7xWbG5%V#11UzscWH`?zpq%e;l1hoM8fc88%=~A|^i4DBA z61e=yRA2%T8(R|}+zB{ja?x+!v~!W5B=u+Ky2Yo`ELoXebil}Jx6pPAho6LWY{SNi z6u5XoGp%EuZZyBJnH}C0)v(sH(Iu2(8r0qp$h8Me87z4(W&@G-8JgE*Ix9rh%6F1f z!yPr8ElHf2Hr?L-*2DJsnyZxFvZVDHk2Ewz+RR#{Op8Q`>lV=i0Q9)xQizh}0lic7h~8Q|29#5l38UNc$KWlc%cag( zxHhHHhhC!2uvyrwUg^}J5TROxPDSv)4N&jf^c4(g5BbdfL)1uE9@MmsbR&GwMLPcX&bxGP4PIL!Y`0 zXNm(v?05pecw>xabF?NZ{+~irMo8wD?JXDJmh%UbqQBD-)P%zKG!-;<#)w5>*S%Nx zW9-=7ex5g|=Qv-Ez&=Ax_De~j+i*7Z<+qr=u4*x;++=fiLe z3f^Rj8i9(J^TNB{eIsOWF8v@ToM=K&>jx@=T9!lj9UY}+uNeo%4Z76Q30`$Fj+{Bh zQk3&*t#Fh^tGbj&j-l*00QV)Yw(kc!ox;!&1q1lsnO!2}v=Fv6BLi%sXZ+%6-se8K zjeG0`7W%SaLgNrU=X1tD`Y{9Xkh~)NFeUJrb&fQIw6v10<{k&3hAa}Lap(pi)h^|e z1x5+mQuM45)8OX&c$sTznx&j(_;)xac*U&ACBu>04)0z>N&;?IvFba*AJKKiMv}&=}}DP&{Xw8VOB#8oWki!tztEY_#rlM zD4v1i+*dW81hFkeMcS^l7x;xANMun)RrCDTt2D^*0~_79Dv%FPbi~%!tMdVz!d5a) z$Gd|RO4hU*Hqew09xrl$uN^q=jLEQnIY;_232}kpD_`H@VzRoFZ z@0*=vMs%o?xc3M@6CasgAnP7<3(VUeu|lvv@-X3l2=eni-@r7S{3SZ60$ies29|?$ zB4_$TUq4f-fN^FTzsiqPAFF729sUVM9fYT;oX=C{7=n4M?EF#aF=h4m=SuR_IgUrz z=!!ikWeuH+OkW0U2LHt4jp~_7N0ZeiS@*DIn~9g@!K&<1W5(+hBEg3(DJ{Lb5H+{>I9Tv zSD#;ik#0Y_T*g_1v6$dsP)6jT2BJqu^p(NSo}tawt7Rrpi!bls2>9zxgr9WErQ;$7 zk*iYIQ0U8@3pf9o_&x$+K|?U$YdN`SAm*rP%O^!n->dSp69N>P*-MA@^tjKrUUH`h zFn&^QRd0qjqz=f5Z6!kYFswrwLm}~{4Y3jLnb%t`+4O@X#Gr)m6^5g9Jfpbt2Rl5I z`oQJum6k9nTG?|mQf|9jZEr+?dX9B`8`L|IwF0y>=%s&?()}JRxmesq41W5GgdR*#R? zvYIthJi5u_n>q1P}?<<|fGw@~vzeiR` zA*KnO6Dj=VB7MM@By`gVUkI!EyPLESBW(^c>^%Lraxm61Nyx(C;pLlBauGoZNV|xMo?8_mlK3xP}3`jmtYKlUYF6 z55c1sO)`d0w+x(?DGFB#qY^DM#A`NqwN4c@NA+1E<&PTB4GtiwCK6il85(VODz>@* z0_O_QQ*AP(52>o!<@ z2&amJ%;WA2xa|HG>)!G*N!ha#N&4 zXv?6a2~I_I@^m>4{nS2tOKw>U5A6_R-NJ|RgAXp!Cl#vVfK_99`kJSKmKdm9X@Ufa z|D<{vk<8^mmi559*r3VE8>a@;pG?yK6*vk&QTk#xViFX|xOl4z(=4yy_ow{0C){$0- z`gyX50t=u9*83FFzpE`Uty1AOlLl`1Hoc;=H2>K`RM5}o}tv7jz){YQFlXv z?YA48(dfEF58hX|UCu9YsA$8}!)XCBxcnMPbn#z=u>VnFFog@VL+)i$B>+r{g9jN_L&=L*)6Kb##;S1kBLca=X!(qS$%eP`H*lF=ZCC z1T@(mtbA-ge@;0;Jo?1*cylGc=$h7%=(Yx#Z!ao$H{B`016Wc_>^?|}5Dn?-_Z@&v&m3al@@M` z(oA`3=Olu7-w*?B!gn)XO)TmD;CMj~-^PYh)%f;3iJ zo|vz0+QN(K$-wZ^UMZraW$AE2EGsJ)JPe|Ed^XB3XzE*D4|~U@on$HEO?S4pjRx{=HiTqV7v7;6-dv>* z`(44n;*X;`&Jd(#;)*<;D$*eO3}W*3FV+(d$8OVvTa68i#oo{|Iu^9) zO>(*4jjKU}6e@#1u&VK!&$e(+(P9_BcxY0_lM4LqUZf)70}7}wf{l)^?^b0!$E3FF zS2e#HKU&wze-05@s?-;i{vu=R=*~xK8^v4qL)9Chj-21cQ~|#N`)||y$hyW|$ z{pVVgUE~quV*%NMt$*LC^A>L6rpe{zNQ;;i>lJt~=N8ksbdyPYmU`El9jt_A{P4P| z8&4L%N>1jaZr6Q5M3?IF$ti5uDzqD>YjtG+VsjRZo=YB%rg6eRbISA7Aqbn|Eil?M z0XFx+gd5|8I#-@8QM5DlqW#q ze%KzDP|I4$6hn#K72su16@mRyg+c$iZq}L;SUd{sNZE$<+{p8{i{e#8<=3 z(Nal(x<~3pp?>7o?B{#5u}kQK{+(&5~EqCVz0GVbGk8$h^dOvzpz44S+Lf6 zr*-@$KmBaT8nUTtIKqgbi^D$qrn!Q_7njJJE`bvqj+X0TP%QtIfvu^#Ujk4wRgsHK z#_{9)@FQ473TQ{x;} z2Kss8I1yp?=9nzn9H`E^M&*=&%ewg*b^vffqzX>_5;ox{T#5kZMJL9)AEURg7For_ zv&|XRtTzx=l0TP-+gRB@-aOXH(BsS^8HQ9U&ZU2GtrgG z0kWNc#A+(Ih?hI25VL&xklIxA&QrHqq()lS;G<-NGJS1I1DWt7AYgrZqf5Hxi+C{z zDo{ZuJk`SSk~D3zqSVLGVH2z8z?Oui1QzeB=<+5?$4m@2K|sd4M!3jS=n4A;N$F|n ze54lVg!kkHm$OhE+q<=>CsvW0L+4RN(kYbKU6T|*hkuS2@=vSuK*>&wFwD#1Ndu!p zIPM*C@w7#?!jJHk)#b6AIQt6%i60u&24-5@u-j40BId+dG6lzWeTHi<$AEnn zBtM6TISC(InooyZb(X@E5W|uyQgzQm|B@shCmIdA>AeLjL-lV`<;bdG$F<3~r7jcm z&xUotSAU355!*b~gx=QAkG*41&T3>|N-+Nz&xb{L95Ps&>jr@eqm~FS?kS~kofjKv ztY6ohovjH3w-S;{B?PFFN=k4icG*VGr@d)-dmHG89l(qN@fIE;QZe7A)r90{iop|175pnNK!q?} zCt$?D(alfTM|B~lgvIa_7&(=7Tvp;D4I?<;;D2*`&}7x*r8p3L_!TlR5@{r-nZjLe z+<7f6uR%kl^D+H4jXgTc2Xau^Gr%?(&FbCkgz#qQw#ou2z_V4j4ec$q1<_pIVD+aun<{b)*-hU0(V^;lFLvBqS;M(Lv2asuY6;E5 zi2e``kFtvd)D3Gy(cC(HehwOrSr&)TB!Bzg&Lc1bIoI)g@eHMQdD4Bcv@f2HUVbjz z&~M8p?9l*GV0w@KC!HtjFc0DQxdY>yy|aDGU!}dkcTDWCe#US;b5RM$SDs43W_@(4 zgY^rW$<1g?J{s=2q$)&Q2Yj@=zo+l07{z}@4V~J3S=D!Op!5B}txY=9?Pf7+JbjeT zhE9N-k)!3;$7KPKR+n^g-%UBR$Q}K26fc}wJRE)rY9tQfFkn!R#g8xU)y~Z6lpy`p zB1>dYo5Gi3e0nIpfFgs-Nb5U?hZ$G(39+rHzmQ3+32zeMbP*dVtYg&ZoUNk9@ zah_DmAJPINJVU^t!P1Ac&K>k-Y4N%YbxXGGf&7gWl++)#%;6JB^y1lr;xziMGtDF_p?$_^F zXVKll2WfG;A87}m2#gMK@v4tee3jicmP!(qg|y*4kS6sW5JL*T^WpS@3}AtnczVun zE+Ol`aEwM#t^RFX@y1D;EAj0ZD#CVX`?)&UKVgx3hJF8Ee4Rhz|6@0SkQ>n(rcX-N z7nx9}TkLTGJs42`|JTrxy*L#e;p)A?z{*|gxywoMcDC|b8C~mBTg;vya;5}c?}haa zb=qF@FJ)Nfzcid4ARW`D5o?6$G+h7kXW%}%2^KvJQgmJD9&Y0w518;AE`ygB;IQqD zQi1!8HQS-E(u4sBO_WT8TeVcgSZSKzK_ps2)to5Tm5m|Ip@$AYg(}tY(8X-b2r^B z9$CtrLi;Gk-DW-#Xx(=9QF00)Y?zqSayG8)T6xVzz16_db;M9+Z%A4G^JC=7--&|s zpraqs>3Gnzpa+GWoBTCDSe=2r$ojVd^}Og6)HH)Q=8wq}q3Tlcj7-&?!UJ zSfn>R!|@SR`9p>M$lZ_iCw<nu(?Bn(69$S8?A@T=LHQ_);p=R0aF>r$(xNv`!f`A&$;2`&;qrBg)w0rZM$`PSbl8bKWS$|E725Roz!T> z34c3da^(%M)`xP}p4PG~Sy2>r2t3B;+7fu%?`P*+VPGopPqjePo2rWzw^?J8xCe;l9j!Um=U5cCCHu6E4b*6dljY7G2q= z?C{F{Q%#ThiHM!z)B9jEEjFd62wlRf=oz{#J-bpl}-osgjcj0pUF97;!u+P33e@L%JLPRSb`)gBU^fry=6t zbZvZ^vaUZ2B}K?{Lk{eK?Qf~XWMurppVV=VJx+WtEfP#X72t~e=lG#o9!mxk%Cz#k zBxeuJs2p>0%p#^Kf)inXNh|vZY#ONnfR@!{u~ZIpaC%NX9QUIK z?i-Jn(x-wj(tVZfedK5H=z>DvI21*`$cc*bZ{&Z`%?A)(2!io;rOSdd8(H_Sf&|3P zM7VSgFS!)kIt^#GO;vwgC>+h*(M|Ao9GF`)i&DK%hdq~X+j--et>KNOd-zAo*nxQy z20Bqo`$Yo6B?1%K+iJqZl^&Mi2O{B;a=FyN%@^Eohv22Ni|UpT#|15Ye}@EKZ3!H* z?y>k9`mVjYwX>>!6X|BOdCKP{#l~{Y^!>Eh*oLMAo-F#C%=r+ma>8wvb*EoQ+0bUf z)d!fo2{K6c+wO5m`=B;Z(sw!h=-0yH-TIFb-^URvTf%KLd?`@Dgz=2O@g>FqQscPK zhc`wvKT6Q`#BI10d?$~OY=>}$9HWs0=QQO)i8#Dk%zcKWU#5cEyc@TJ^DUnxbBp%= zbSRavnHQUf@7W)FZ8og#kE?yQo!`9saRd4Bggnjc*wn(@WRi^y4C&LE|2Kt=!GNsu z6SexjHzQ|UZw`&7ixh)VR;v^7MVQzmRD}^gkR;lsc%f7E=3dX?F$6?wzCj)Xnxy06 zcRg(Zjq8sW#k~U@FT!Ix`xt2KttEYbjvL|oX1yO9XB^7V=@r_C1MZfAh2oJM zc~WCc-et|xeq-8!d&?qxJmB zWz1CRDZR5#aWP`6-A7m2Lsw;Us#~G%O5PzmyxYy^!LKN z3ylf9Q@`e^^!+nYLTJ@w=43&LL3|q#wWMY}P2?VE2Tmig-$eqJE6c3RG{k&YkiGIw zEL2qvQ!sP>U&wRypo_3n2ODE9(+8JC#b6!;VN0~I{HB)PysjOkvLVn;X(A2*#0M|2 z`!^ovL?!lU1I7IGv^lmOW;)`1_!9IzsgQ(W1$F=cZ^Xn(%GOmq)RE;K4s|G&`S5Lg zfCfR?(8eVNOl8v~NnK2cvV!&wH?;Hfd*DOS zVOJSNf)5t6Iv^dKFEy8Hi;P^8jBu4`v+?5G1ZmAy(G#LXvSAFn?a;GR43u6A=7Cr& z@4~4rz_m#(4?NT%`qPPh8N)D{#b6@CSDq-79X!&Yzoz|g0lZAJ+^RbbWCAR%7vMtG zr7wRR%7sITjg8|4D97j_OHNr*d-?xKVt+013;v&dYw#bk(=VZ0Ya;tecPXk1LtX^p zN39&zl7jYGbXs0uxwd=M$b1=rw$Kdx^HYQe#QDKdox%!(Zx^GKK7K2EKh8o`3r9y@2vb zDp_=^VD;;PXERl+u`D<43t2yG1Yt(?$dwIIDcDz*fL7gc6F`6juf-%7WNBC)@x>j| zwc`NuN;oPj{IPLHa38hAo8^nespvb}DB_9%Eya30gTAla?Ch!sv`?!CbynRUiTxl zeM3gLw_mNv$ibXFZD#*1OBxSZ9eEv`Q!X33-|gNwYQehotzRL{Lc;xz`BfF6?50-4 zgb6!9I*(doW*L~-wZUFu4w{ejSFs=n%tn^TopJn~<3Ax?bn#ojRr~F~#L-H=#^4ax ze+_a(L6xJPYokUA`82z-n^G=9XGKs<|1mqv%THL`4y4ZE#Ud5b^rZ$Oh!F``szDtQ@mRWEgn3$!S% z1Z#z$4`AWwU_LW!&8kevIACc^j@{0(e(?%zey`aT!V>zm0nJ#E;s{e|@mRm6dA*Yn z+!k#$h}}7vmtlksq8R{h{%}7_#i!lkaaF%Gm$(g7?6!t9`Ff|yrO$^*S-RL4P1QCf zDlR!!&`b|;dOw}um7+l8393@{X_i9ar6$?Mtfum+E##mMFL=6ETH0v=-qijgd*|K| z3wwPX8(e}iCS49!i@L@6lrMV9qLs;thv@r{Z|aSpYI|Jpw0x) zLn>7=N@lGCrxZh8luwj&^LliE)?bQrabQ1TKSMsNulUGMt*3;ULg7^lM$O#y5(dn< z>In1bn-6tI#IYvHvsrVrc3h)HLl_)pSDkrF;_oOA7PA)$q%Cm5!RR?s<5-zon|`Zb zNIS7txB>&he;Fus_2#hs&V#pJ=T7JowkI~deO&l)6lyeYaPBsm{9}_3H@$-VXYOPv zA5$t*V8dLl%Lkkt_Ks8>sXc-myNSZi9V3T&p*WNnvWraVh1@K za5FfnH}MI^dR=~_dY(|{Cg!Px$t^h%(XOtUq(d!QnfeqDIll3<$2cyOLWWJvYeOm; z_Fv=Qz`g~tI`f#3nqlomvpR~>ehb$xsU7M%`qkgPnd_zsRLbY3&xLaYtC51fZeN=hLFu{HCUsFhdVOpr)d%Jow7VaX8+k>VO|WF=GDN?J)e z0*!~E5nKlLy?I*eZ3aG4JI)&p9zN?R0;N@a8Krp4*lmNDFs74y~O z-^Ixxhd4$5l#TtF#F(SXR3zbE+BzC|P`}Mxsgd4VCIPBlea}n#R+?$0K>Cx+KWjJt zH6Q#X0S-x#Iz4s@YA#e7r#_cA?`urIDI>5eCjWCQ`n%w~RxZfFBrqh9 zqs>rvkDvI2(*S64M=KKiAxH3mqvf@N-fmyz&gr510o5czMiNommdTTu&7pT#_}3Wc z34c6?*K-T}Lo5Q&zdKWtl=lvzEy&m)9rpk2VkIC(fGfFVXV3+cmr2YPMSy z=YC%CmYI~U>|6wpO96(I0IFa=#mWL?F#x_H@(8`k^v=q6LYeFk0CrE7I_VJ zdQ#t*wrlCTui*(V-`}fP|8XMDQ zNYg(#4qHuCc#>);IFPTZrkj#TTKjaUh?vA8+FAaN|_EQaPrPhBID^C6( zP|*g}>-@Q&QNDyu1t*@8TwkR(xa|J$ni_IA?Y3GjwZ#0*ux4^k!P#eT)!&3@3ZDMkaOdRYr1x-G|F9qhM+F?-fbZ1b1%of z@Q>h`Z+-oz)dVo}u!`9=hwZqbaUAwUc$Uh2`g(*t6MuL*YyP*>W9XLrg?DqbBC47z zg*lF)3&O+w&U;hTCHtDdA+xkc9m}L;1XL=7V!RVp%>&TFGad?`;yG|a1Y`78CM&iaIKQQUXmY! zDI7XEsf;yIxQ~op$gTQhx-}_C6LSk&N%H+!RlY>+dm|-(!1Tm^@s=d{{iY7Tp`>TQ zP;UXM_Zp|jqhY2-#xsKk*q`5-aLERiIs8JGB1XFnT}mU21qmB;{f2NQbsy{kL_W=j zqHu?Kw2KI1MyDKJ!jnoONYljw>zWD*mi1Kr2W@X16xZKwdq!}F;2MHk<1PsfjY~I9 zaCg__7u?<5t+B@4-Q8V+OV9+J&N=s;d)_*8r)F-={Ml7qO|f@Z@8|oh&swXD^dX8^ zT@&KcGDG~Sc&RPSO)Cimm_>*kw9Kgw5{rh;Xt0hm%y2dV%V%>k^~k&IlSvXqTbtW# z0RHsJlH>e0V>PhZ#cbcwV#Bfl{up}-9y^#?7BM=G386kjvp711p6;c}?Zn&;S3rD? z&l4`oNO0W&9G4a}yO_C?=LfIueglX9$uLTB2GV(H-j{i8Hx865pbjp`%dbdeI%1)Y z%HU(z!``>zH4e6)E3m0?XZ-fs83;d%H~^=lJlvttN{*~-m2V2w&;YCPc+00ce57KE zW=~Uyh_g9CiR`zW|ClVwUC)d~S?8wFE7(alk-CYm*e$w$m>nE9azch?;ln6MMkK>idp}GNV@4T+l zQ0W|u)1kGp6}s$CU5pWMmmQV|>!~km_^vuykB0;#!;)(|@Q>7Kv|WC>ODn_F-ONt7 zA?D}jB+EpCkJ>(onzL)DS|u$L*L&x;pso8dZmj`e)zVGKrrPzHH+8OMDC}N-=mVit z^f}u5q{a=buz*UcO#_jDqJ;*D+XC#dQZqpKp33wx%)7xLmXd)1hRN##xEPNGioWKB zMdo3}eq^;>hGm0GHW)bxflY}YLZ2+)TqI%CPUge6_{T@u3q+ZO*9FMJGt8wI{4kqm`eddn`xi>o8?!QO@BndKrAqNKY!#>sJLxBEUn3G zfk*xcyTIrTCN$qVfQeaFSZYl7Wnqj*N$&fv%dlh$yR>hIbqD3Mapuw!+E;t!LC)~k zIIPsZwJ78s%{f|%&vc)a*_$bK0y}O@eRmX?LLKq_X~#URdPwK$kyc!_{WC!+nHb`0 zpx$m8luo34)XYm*J4}coR1}|t7kAQ2xEriW6D0>)vhV%zF#=G|LGz()nO4 z(db#Su9p~jh{i0Er%ExUMZGHc7!^c(!v*uMOs#j#HV#Z83a!pVP&-iJY_@lg^Bon`0yEv%@VlD4QTTeo-3&d(h7@`^ zV$n4C#ROcibJyZZVB@u@Pu_zSoy;B?;(67oWX=FZyFg0+2GC_1E_YnFo{~uYO}YN` zpIBV=|6R%W{|aY=*+>3As4)LueY%EboZ`hFhh<;6i*Jsz-4;(@ZbJS-X-OhAX7{pl zvU%IK*)}U~^kD$vX{xX7KbUGy^WPUcf}$TjKbu%rW57!Pjt&LDGsEp)J6bDO+Fx;7 zEMy8&|0szxlz8;~Lr(AIFdA&VV7pG%91@3EhkU?6-{N{w#MZ>O&2m!1#+Y^po2pVf zpPH6Sqp<5N&n@-o|FsJkvRjvlWbrs}E=u+Gbm`w(Ev3HThB)L~X2Q0L8Rs%{q_5}k zW!xmz?i8P?U`6*kXlFw8<#aC{3*Q>ddU-bQgYzxlOPNKbb6fA^ba{8`kabx(-b9)c z*e~8ehzHvc+wll`UT8@GC0CIeJ>FlVvg_}6fEY4cvIY^F+CVQnL z(zyD)#thScp3Pa?eydnmyj%?yp~Zbv>0PN0YX)H_#I?@sa?vAi6JFF?sLQQ|#f<}M z!)z|BV7#8Cu2u118SQj`@O{d>6{_w1N&m8VIhQ4S$_Y($6e#o*6^8dWjp zwUcxfrxAud>JY`Z!)dLrs~SEn=b)p14pQE3u59Y~&mR0_mA|f9)vSMatF52G5W9uJ zU;7AIsav(n&gQ4TwRpP93M2Y6d)IkSBxtbW=SP(4iy0*H*jeG-04=U5SdT_{m&>^> ztr%Avt{a`Ee8H1`s@+3FxIC2|#b#+`n9)5_pNqnfJ;U(BdF5fw54fE&@`@ z;*z_i;mUU5V^w&tT@hYcam?Z0$KLUy!Z~YZ_RjZoUU)@nj0Li#y8TDk%%&CdSzOq3 z!>=uNebVP-gIFLcPX#xUbd5}wOwhV}wCct1j}SZq8MT~JKME6>h|yfvoHNSD0r^gD zYm0%Dqg`n?>EL%isHQh|!xX;zLT;Kp)ryp|`5IvA2qu~AK}?~npViti}777S1k5m$+&wmHO_fEBfT@yL8t3RNlt zSAU1XsO&BT0v0}?6hsU1u~abmRaC)@6;dj_J+l11m0?`Jq1zF4ss5%TP0Pt(~Cg2-{SCw>9mHAI`_+w&(iwUP=8RLCiAo(XzY)b1i&4-`5d+m=Iyq~a`ZU}*-qDDlmvTtWA%F0lP3h#N+M zYoUNU zv?TX%-|P0DqLoQc<_I^f!enIquuHuruA^JWOvM|0jmLtg` zWa2(a_zFHUeoBd?S+7D_YLgPP`kj08x|8L!Y_8!-whX+I^LL(cAgShJqgEJNQW zs#rJ+oVf+hYG)*iJAeC3;{d@L`O*%JDh62#`!-jZvP$(S!Yyd+R`M;fWI zU}?J>p!n<6c1c82Vc`9Y9r(~E(vd* zU#~#lO~Y_FnmG!XKAZyzVMw7ik_D0onf53Tmv#lY>NL*33^s3HubYRkH}4`!{=4q# zcN?F?NXT6(_K~Zuec}H3mvaQ|%c|06H~ZJgBJ^~(Y|)xA`I^?PXG-LqyO)Dmbc&0v zSr^w}_Y2{LJC`(xxD~QY{s!CD&-5i}5vN_s#TgpDt*H5dbsC+f% z;b|9k7PZHEjfK<$8MEYb3x4rZP}tdbU6z04V+C0mZ94gxl`BS%8mfN~UDNU)&$a4i z>&}-M*Z14c7df;aQYe~vDktHZgn#y%+-6E&lBPG@It{CyLi-Mj_zz@M8EI;loMO~o z`GF=l_5N(J`IpTn$Y0JNxF)e3 zDG{Ts{1;guLtXGLUzUB<1Z->Eqwn=!w#I^|RQe2kLc2)PdSWVhg_h?D4iMoTVFW!;FT=_frr$n$(SpklqWr5Med0v@n_PKd|Hs9 zyzzyrixagDukMxaz-uKHVye zN@o^IcDVh~Sz*?$pr>sLEu0&~-0q^!R3*aj5*F2uG!KIQp<4S#?b1-_(+b*;omCEz zul`lNxz@~RurofVXUvGnJkw>n5Z1OVun@fc;3Ymk={qyv>v*iasm?gC6?_r^3M&66W%8ljfeuj2-QC^sS^#@rHK{dmtk28$zF;k zBg#d}R~Xk>!LSP*TeeVhtO;$B&1-!ZQP-dRHi?$wZoW@iDD7Tul3i5P1s^orD^-%; z{}vq%bhw&2ulii(a%mRU3z#NpiUGJqv}hYE5o-0;bi~)B~o_qFcLvHpS$TK zR@Zz6S*a2WF4SL`GI-jct~u@KLm>~Lg9Np5k@*e6`~3Mt&>|dip`WUS3o+?KDf@O# z=(w55-0}x*1anB``w2ay)Zk1r|L$WnH{}$W!l-VVV5VCy|9P`+XYUWi$8ev6RoRJ& z#C|wsD$}%2>>W=Ps6Gl$F(3tklj$U5t@1Gto69}Kn7tW|og5|B4p5p;F@k%I*aZ03 zAlRL=`-Ugefm4c^p3$O%1^aCr(X% z1rs(iW_{v32iUD{UODkFKg>9^hAp^+;cHFT;g__;uO6gcq}mI_kA87H#%8aZzJW82IMRVVH~6Kkh(*F5v%MoBwZGqQ1~s+S^mS`P~d#t7is$ zOcYR)4V5MMni6rZ!%gjZjsQEDiH7)4@O}x10S@Gt;Mo7p8Qc!NWQ2P|0AC$fNu$}C z)B{LfvEa7C(Ydo2M?Wcq0wDSyRy~7ri0{|2@8pgbD$-T$>kkuf3mfL(h)H=DCZ>$> z)uokvZ}SXGZ~PXMkz`4Dw`EVY^=@o&|XEb`>Y)+yh)^>1=x4ER~ zY@)Vnyp0H8$?Kf|#ORKeROSkk{K!V+vs?T~q+L7SGZmteXYfCeDYQ@XK{zy}W-i2O z8VGtHM&FSqXV22=agYL>mh04++cL*Olr7LB*1>pN2@%r;#mM@(YUyk9>U~MSsTklhe^k&eOrksn(aS7Y8U_`*oh+E=Rrg|AwJ_Si za3G=AmVe+XrmZ=YWu~YnE}R~efq?g6a4xX)kT3t-uez?ln70DG`d{I!Je7-Fo9EjX%18!{;dC!D{{`aqi(CGO)0BRKvRIo&gD-c>uh%?h@ z`Qanq&x$6GZ+CsLG>gt*D_=aiVGOEI*I4r^yVs0BP&CK7bD~WY$Q-HZ)5DV@3KUSL z&T;-H(d8^QZ|*3uyuG}Q@e9mWSce*GXUNIs3kJ4V`E=W~`*W?3K~QRuzNQYh>`Jtz z#xnXt>FM%CltFgR1Ma1?78Qytr#tks$La*tt5^;S?_n1dsgQ$T%Q@VbI6S$Li{Ie> z`0STP?F4Z;DV+sOE8=dWN%TsWwzp2hqqsqU5~TG0^XY9S0yT0|h&rx!<-c|T4*IS0 z=Pt`k?_|IhbG^GVu&5Txno}v3}3(s_%t0!)@4ucBkiYi3hw{ z{Itrry!iSAcAm}HcPk5sGEga8Qixph1|7a`nPtx!cbi4&v>9??bJ{0r`wO45!y-3; z^mE5OL}dZ^7HCmSJM!-}Nb(|Ru!mo(75&WyY8Vwuzc#B@?J*`>*5P*-8fQwG$riH8 zo0QHMY+AVm7!zGRUyC6RORd# zpyCRf_nThIl{=FI2FZ}lz0akMWZEP zYAWn+CiC63P%XV?gx;Nm)_x=7I}O{-HY>lN|x ze|&<=AaImXU4pThM)Y`LrKTbQd)hwErowL0Z%p^nZSnoPjW`L+=Df-LDt7BzFPD;8 z-I_Aoibsp`b%x_nTb{5b7ziU^3C$1pf6iK%wJUn1(8*^}GN*@1VixTnrAouxTCgJ* zK#ETMEggml&0yxtp2JGTl9FXREez_pp<&u_;ExzdaAxYM1&}0_C9Ea#v9|WYp6MW* z?vErlOQb#h{TRukcJ9rj{T#TCtEVp}N3iHu7yb-IL6IMR`mCdBR+;*8yBrqv-6m5} z$J3fJZL~yzcWzcQ0tG9_4lB$(3v~qpnl&?4>_lj^@rnT4%bib`+dT*CKB^h>R`m1ejt7cJR&E~vvjblc4dtj=%V<)Z1r~R>+^dSLeHr?6 z+8p&B@HRTz>pqXYv?)M@a|AjAg{m6U!-z_8F}UK}G@nV7WI0PyX1u$0+_`4FZLRNY zejo{=(Qsvh&hgzE4z3FVz=X0@0yJDE5NLq_5LOw-C2oy}-Z508%sVqLM(y_YTl;ZR ztyaoHWbi^!wjc>8HVi}{Uk43&mR>Xb$wnQsDUxz&24JLitVKtR3L!6(XRI>1Pgp@h zo%*39xi0UPPY6|8rb^RBIGw9U6)0bS4}*sQ({jTp9lCuUF^C>W%2H_$Gp$)xRI;k$ zLwa}by&2`!6AQ2Uzj`oN^wq05;jhZC6u{ac@dN#!yKu{6*Zjq_@1J<)R8}r?LmGUU zK6zI9-b2JMeN-{DN8X82k94ta`Jx3Q;)rai4naiG32d&=t9;EQn_*$K9v)Y{?+GV#5zLwRF2=;iRthwX~HKvy2D^RuN z*`{a6QkWfq>X^>#{*IKaQc;{E3`nID+70yO*yB98LGafPHXoiCmqlu43_|ZEPwzc) z5+DNz;mD?af<_@3i|o`8qJs&lOzQaDPHItNsUf0}G(OPgigA+dT!69#7atI(`q-G; zvi=iP%ULR_T_it7X7F&d%$iSCbk`$>k|5c3nl8$?N~MUKV+56GYB+6ahr65eE4n#- zq3R(sB~s9PGg^(NNM@X}pN>msZsF|sW>uIix>+BsR*Y?CIf&jk`) zU}Xkng2$Zix|&1m1|k;-BRy3~-*cquk;3S9-lV-*(bYJ3TFgRNRQ~`e9niReWipux zCd=%Dy!;>5G~=*pp{$eAQ8cyY@|o<7b!kIP(6o9Nn~$)C+T0_fEe5G9I5lG;5q36d zw)rs~nlhiR#~0>mSHDt%T*{-ZfoB#g3gc8u(P){44|Sd2X)Hn;sH3k|M@JZ~L)Q9F z&dj(&BgNX+>&s;NTWw5D-9D#k)GS!G|6>j{;;KNFJ3-Udnz7HDqqUaJ%D4nEvwPzq zNcy<|(jkqpUah{S9T^Y~9bM-2y1_L4P+#MNhqx!r-VwcwGK<1l!+*@_ ze`JgQo4C~e*6u%zWK%TaNPN4pj@{B*?Pm2>T9HnFnP5-!Rf2fzusroz z{o!R6z^V8VQMD$_%>_}5qpw(Qh+8CKN*=51vsbGLD+jN0SI8_maxR0N5ybmznn69@ zo-d5yD)3=&y0*F%f3qJnV&o2*y1o8?m9hSdNYCDYO2o%@SL?P6Xz(U?62 zeF`_J@1yHH%A*^Go^1ho3e;da9&=r!2%Y_m-QlT+COnIIEWwXFl<;3{kb_=B)yIoQ z5-t>+WZ)6$XZO)-Ko?$8LHy^S4#B9IAf+_d)!(uoXveiZCVTI3+2RrVgKYn=(jP9N z*=ygKn{{5V1}^e@_UoyS<+ZzafGcwa@L|JWUed=NhLYCr6VD_-Q&_g%P=`SZQWc~%4Gs{h`JKUU~i8J-ct-ySM#yYhWIt?{T(kPxX82?R^?=k}xCg^H4Zs^ZB?-)`o^` zRhzsLMU2AcNTNOxOV+| zRF2wEScG{$AxRBR8Dx?Es1G?jST4Z;v@1TYOe}mbpSj>HE(FVxORK|P{OzMvKQA?5 z%$@{73~7s-Uw{{0DA8W1(c#rTIBiq?r9av~a?IfzNYuh%qn3#)!YHT>U}D^n4NFWMC0GYPx353ZOrS6z(Y+o;E`l&|bG zM|2Io4}Xf#DKLmT41n=z4I6bv%~JuKh`he*?khK|!&RR*+FaKK#Z8np*qabrWE=og zoULQQ%D^CIf7Cg3K>8VarMp&r!Df+p5=dHgui3M%v!%%Atv|it=2xFUDYawBAl(%x z1JdG@nnWX{D84GF4#n_yvx7fJE0vcDdUqa1W5@a!I9g8I2F`Q~6~ti`Qda}?^TVlH$&esNV;Anx8CS1Kdqs66b-Td8DObKC?T24#HX(Ke+5}vS#9FHi- zpz8?3Olhgdx@=&O-S=!3ktHv?gv~qjWTCt)pZZRA!-1&EDk|61);27T{(bNW5rSKwO{Bxr>)0vZszJj8}!&+ zF7jTu*-QLPsd(D49QD6veXLG%o|!HB?nS(l%FLt@hI&4B|0TQ36g4J&enX|RbVI24 z20Q=Q-Ud=1p>E1rw6jm`EZ+ih3G%zOmIr0-r` zu+OMrEZdd}<<}?pQH15K2eI;(x5=ZEj{52K0)Bgcr`98<$}t7ex2N`PVQ>M;A%D{=MGZt9|MX24 zp&_$8ifx2m_vC78r4knXXBa&Hqk=2z13+HoIN~SuKmgw_(O~wUe1=rY)^ZaVvAAa4z>Y9@8=ir%27tY+ zs3Fp(fYHC}_S8;4Lbl>>8|Heh?adGT{uI@+Ta0y_z9GnyLIX>(X{Ac~>~tJa-ah7q zPQ0R1&5$=3y*0^Sp)t8MFFb2%JPTiZk*?;kMDaLwwP!wz`suWEmTziSDEZ|*VgYh$ zMyWN6aN5UgzPiWr3+qmPu8+8U5nj>hFs(!}N&XWNm*+%VSNes==daLf=e6D=UioJC z?J;)rW@#nI3Z9B{`S07lj0_5R8172_#V2`Zat;SMTnk%T);s9Y*e`Lop@<#4A_> zbRhbm;qXnV{ED&OZ>tR;%7kl$XNM@dEzSV4E2kj+#E)^HGih`SZCVrkB$v;rBfliS z13eo^XgN`lQtTksVK6hFS?T9*j7`@s1(~aZ;9(^m(vBGEbP>u)#G}M+nDEB&lZ+fy zsvZ?ZVKd9$^q1h;BeN*jfQ4UAxsyS`%2IYv#qe5--_@GM!^-3_KPx$`0x;nPjRf>8 z(PPzY^d(!FN2{BOCCH0aLWOL7up)zOM$4bTnPw`k5=osNg+UHl%y@EyQ8sShLlnJyiHb;U#vZJJE{JnN#J&z9^Z5#{o4nzH8IZFhmKi3N$ zZ@?t5-u?lry(wfH2`+Scx^isUi59tBO#>RGwFEgMm6{sj-;l}z&Qh>7Mi zW)GUVmY|_@_8<2FqpKl5DhNo(5q?{ryBy=eop2q?12)1DJ3k$@T`m#L5&trnoFS6FO{dDbUA6lrOuvB-iv^q2bMlwvEw_ST~inHT^Urk)ehw%eE6s$z5w(#t)3F z3xA7LJPfO42UJr@Fa%yM;Xm?e_|Gao=3@oY>S@Ww72HZ8zOPSrCr66Z7%C_^pUN8l z!5K#x#(w1cs5C*^hqB(5ZmN zZdPeYKQhrWJIbXT=D@4t#{-0@C(y%G8qm_!FwFRJi|)U*rcH?fQ7V}Bpu+V^m)mS} z8zB{X5;Oc7I4#3)N{ixcft1Nv8R7xo$#zLy(Wn0rUrwq$hw-1YbQ*!qDU2|1Uj`p3 zWPpkvAgdX_G8Boqf+n`R_a_{km{gZTL!D(N6?e%iKM`fdj>9sUC4|dGa!i?e#lo0` z0y`^!^KYas2?;gHqVA7V+I*|!wFikZ-0n4_)z^>O!(pf>U>aEO9HHiP3gB>16*VqE zuME5KbK7Nt>-bOmM!OeqiDEW;Gdz6lKy*)(8tr+%$VKJjRpug3{@h#RqLZHlPkEhi zx2y&!Fqo`EzcJ4(z^uh->vMyo&M!Mv>2d8#daqZ#WZys%*$2~|5D);vxcGpC;){J1 zMBi{*<^HW&iZ?BWf^D&viP_1KcL7ro8ePZwFcqWoP7FT(%|LgKmTR_sP1Va5UnL>C zlK|)ER#t&Ip;d62+Y^TjPKWFXcP-O9dK#G1qxLWXTE&3P8H4iz_cD5Qi@X^MO9TbX z{Jg9t#SkcoiPXZ{VUTQ1XV}HAnnij6OPw1*#@9^tpn!a^TA2OuRZk+1b$;NSSH%P( ztmZ}tK{rD(Uwfw^O80rb5ODs?pe4TQj9C z3=8f?ug-Zt9Xh6(zHv0tZ7{%Tl{qSq`tct(E%Xtsww1C%&uFd2asfYqP1r7Qfe;;&wn9?Y^F7CjjU zv}2aH>aSy#a-7BWLd<0RCyg|<#2Xvzyf5y$f0K6cHMR;)# z5!BLNq9=y!OHXj;N&j^K zUyAeMZDP&*JE8ZGFcRm_v(Wbqp1*-^{YKkXMJlz+n(YOQr;V1?OP&GVQYcA4vFZ!$ z*N*`m_B2f08+j_GDF?`bSl>UC)7r-nOscOXV%on?M(s}LXbxQEi8?ywZuqSNQzo^z z1bnkxRa{fS`x>zuR;Lc8M`*;vm^2H9+RFGcvCDOgJttT@)q!45rgX97-Y(%~Ot)y; zs-LRzd&q#p^Ncc8fehEkyOM+fR&s4UBx@t~vLx4R5tX=T~ zs-C=<;v$bVXr|l1_*EFAdyOwmHBPs%$}3jYu%F#jsGSTu;7xL6&W(0>YmJ`@{Jcx` z3QK?unzpVUzLKA0*?YWNP`8h+Ua?LJ-W<`K=4}dTd{q%FPxKE6_rw(;{u_2>M#KCX zeV;|`$fys@aGk4yQ$7lSbG{1l zqn1j746VDf-5f=LS^nTC_I7qz{)gczX*ZBB(*N%!9He1xDp)c3+RqUL zbT7PIpI~Uv9&cG%)XS}1;m@B|)%wvnEfc244(ZRK)?H|VSE0C?=i&~d_U$f zL%C&r!|%b(L$gwb7ZsCo28r!9fiT`9FYf^wG{={s#HE6RdD2-h%p+M7;$jmA4q)SQ9;B79p}k1&e*z)nNo3VWJfOKNxKpbFDpwPcOAYO=d&)JRt~ELLoy%0pF?>S2twcXhkm@0`EXEHXnF zctw82?Hd4KlbEoETe8d}WqY0*U}P=NfnsP+5eCh+mwf2Mw`Q?u*d@Mbv@Eq#sI~SM zr1cpXD%o9qL(hdE-3Er46Kz!9fWoG;yv(L{gf!_5N6zYEI5W2(qEJ?-SNaKk6fU8_59{ywo*aSy}9o%(tVS;}Kq|ts)CjxK|+FQ|&Je zvwCUp^V=R()lC{n&3Z4lR}s#X4h-)~=moB8R`Es~3(cFj~j$8jp-u2@Q2} z$AuHH4%|Ir%;pDJlMagN%FQ9G?AXBe@x(RwAyZxyxp$^V<1KxvkB*`{&Q~?WHGePm zgmLY{Tz&>lakX4RJ~it6;!*`Ue!oWTxbm?=(!h9Pnw=Kb%?ez6Kv(2q-#yC?|MwW> zpFde&cd!W1YBnozRu1nUjE^^uiwm5>cX>uZmuQYb7X?|aN{n_@Z>Jv{|j zFwL>reDaFiSeK9ZURexg_jXynId(pu(6u4Rff*N+@$jvN3`~z~>L(V)s<3Wmm5D~^ zZ8Ud905bHGHb%smqf21PzZUYJz}d5u-v&1IlBpaGa@b&Sp?pbOvI2AUIO3TXr4Oym z#i~to?E|cHd1u=)&@Tk8ESVj_J0|)f<);&2V7+%Bo+Z2^xD2kAs^LiO-}82`1=D)+ zp2?#*8z|p&^z08xMd>DLN=7=TR)^8w6#Z;%{JkrDAwKdXhCU8XWKp(uG&m8fvFeP} zAck4~kwiMmO`3|z1VWH-k>_FRBpYAY$J38QUAz-w>9dxNf*A`tZKP?}kFkE(`0G-B z--~&PT!EF2on-zSHnm39^vtJ?y|dckww~lF?ewim*{99>umFf=bjoMD$Dpk)c@pl8(jhMV@6rhMXdg08U>C#_H$oahKIug+t@3n^tDEuYt4!M03qGaWJp`ohxM+t}?=sjtBn+XE^iE+H z6wFTXuLj@YCCh9vz7DZ6hcJSy)S>I4#CDG?k$-3(&yYl?{}SLm$1_XP*msyZU^3W` zwtlmfsiU3LQoDSx_(14MK&JOx89d&Pha_+MOmXYhH~r=R1X=T8l3Tu|UL;EGbE@QX z&*uclR5VfeV5R?4wru(<5(!5KuO6HD6RvhR>iyK6uNWrTY8!_}7zFYYijz{WJjwMI^1u6J*5AcEYZX!a@>LSh(D12Fn{cXJ9;F|hVD9u zX3!s2r^&q79p{;vPC-_!^66pCrYmn-c?C$fbLNtk(6JHK19XJ4YKhq-DA8054>Fe) z<6Mck7!wD!Y={g)&Kjxs{^|K9NLc8QT8&IP>2#}rA_lFF+(Q1<)28i%Sy&G!-hcAK z-GrAxqC(tN0VHcdz@@i$5^N0QtkPO5L1ZSo`kDnrHRW}6b+C}{24vBkvN4>2?a1R@-sxDPyQD`rDNMRa z>PFhhK5);2fFgmG0lviaT#JVowuMeX>r8zD=) z@vnLHR2PA&usxxu6^)kdm#! z28%b%(Met$&)1JA8mRm!jNd*1`RJ#pgU&<1Enq14$;LUM#dn`Gp^_N|BK46u z!%&?g&BAq-4qlQfusTp}U$<~k{zJwlLD*S~OFH=Va#P8c8ZgNnXygR#aY8LPIRNhzawKvFO%b!r_R%x^Os1|6nIMMcbUb$^9m-WR?7PcKx zd#WXZPE$Uu1tDfL-V=wv1;%5+d9u+fh+&y9bjgTe6?`$ErbJTx$QFkM$ACpBi{yuk z6hRFqiUKEvLrPrmzfZP2BT+ZNR$x0&3k z@Ub}_7i=}Gm4f1&;3k^%Qr%7EH|c08DHf z#Ttp2AlX|J5!uXh@E#27|KnuiTIBrqydnr-xgc}p#ElaXZ9^NRV z6=L*;F0Wo3eEoDW+A`==Q#2xk?(F-E?e4lw>9Rk*yeiDAlF*=RM)FcmgK=GI#hqJH zkW`_vEvxIHPNf9M`Xtw2dliA@i9BF)gSB^6!*TcBV zn))-gIyi(lIj@FU*9@6@$)E((prfE??6In_k0cF}4?MK8DA!H2M@98ZxM*R;$5QDx zYE&L57If83yo*IjKni>W02f%552Rw=CbQyX(l}@1Kt|DYQ?%KZJAK zi|A$b&ni~X=yNllc^T-_Cq87NmTJALvI<%hmK}A~ik}Tvr9XcZSN!bs`^z}9%k^S# z0pi_A%f2V0wD|I{z1zU^w+s{)r`fKMbknlTyq2mgAETGM=&#RA|2)p~h17iT2&;BH zUH(Bi(K1!&pu;lm+>Z4khdT;AXlJwU2#ChiZDOG-DDGHKp96_k&iq-))*9x#=H);e zt&AbBV}m#3&KnXO^wplb->~#qS>H@>{hU>wNpqkvbdFpu?-IQvd4BYjnA5L}mr?w)KYEa5VM6<@dRG})*K%{S+v~^7vn(ay6n;(KZ zfj`jxVXGw6!If*}afq8LX}q z95E#e3f|W3aym{A;-xKmk>tm!^wlMF*)O-wbNs=#ogQv|Y_KyVko=&@uJpCnGT`euo*`V0OK{390pkpaM_h zhpd;v0N8f;L!m>B9Z~1w6{KIh@amfM;sdvWlGU80G_qb=2F6M&YtdP+a{|x-Swg6J z<>u2+(npkt2ftko=_84!q>0fLkJtWPX{D?SmpByNH!4(n$fblTvv}VE=j_7_k2|qN zs&KkZ4O+Jy2wU)DK`I5ZfBx`ZN?{>nQAh!x5*Y8YxqzLsD7V-@V(Wamcxo+OCVholEl-| zgLes_$`OuPrhWdVWwxOk45m40gmW4eGUZRpA~xn+^^oVJD$DQG8f9hrLrvds>8cSv z&}%FU$%ZBwKZK5q`dfydqYZIInOTUIXJyBF41({ai?!gL)rx1WUuaYvlpAAqeSxZJ zRVX&D-^f+Ul2(dkg&tNZ?(D#f&&SDg{-NTlK`WIF=>3$qu_#LDpI6TW+zMJ$H@Zqj z8G1qrv>HghcscuZNj`+Hza3pKN2HV!3VWEe1=GLekJ6XNB}FdBS%VS|IO&IHUka+< zk|L;#b!m_K^@E9}iZ2gk_C`(Ztip<(;!^j^_j!IDM-rU2iuLpat1_u9roIF5xq7&X z`TLNLLIBfKu~-xyu-QKN850F|J0iFy8VoIi^yp>y@}4~#>-F;o{JZ(~kH^pQyC|dG z2&ZrE((sllMMTac4j&dow@jG0rPzdDZS#}dw5xc=V^lCZqI3hP(zregd90UAKl9jd zIa}*^e+`au@x3y6DRdtfSYQ2KYxz6j=G=GB+TC`;Y@;~;%q)}0-GC~!ly|coQ;$Ox zT;qT5t#gvd<;SWBIjM@y>uOO@l&U=2GHuV0_{LUXqFK_@u}ID2Gs9QoE~79*izBdO z5`bcg=+;NLd>6gJ6UgPH(`uJ+2PwsU3# zrMl+-SdNpE)!M^(L2 | undefined; const buildPackage = async (): Promise => { + // The integration pool runs this file on parallel workers that share the + // built dist directories, so a root rebuild here would race every reader. + // `test:integration:run` builds once up front and sets the prebuilt seam. + if (process.env['AGENT_BUNDLE_PACKAGE_PREBUILT'] === '1') return; buildPromise ??= execFile('pnpm', ['build'], { cwd: workspaceRoot, }).then(() => undefined); diff --git a/packages/workbench/tests/support/http.ts b/packages/workbench/tests/support/http.ts index 1f3c70071..20c0a9115 100644 --- a/packages/workbench/tests/support/http.ts +++ b/packages/workbench/tests/support/http.ts @@ -4,12 +4,16 @@ import type { Server } from 'node:http'; * Teardown must not wait for the browser to release its connections: Node's * `server.close()` blocks while any connection still has a request in flight, * which hangs test teardown on two-core CI runners where the page can hold a - * request open at close time. Destroying connections first keeps `close()` - * deterministic regardless of browser state. + * request open at close time. Start `close()` first so the listener stops + * accepting new connections (a reconnecting browser could otherwise slip in a + * fresh request after the sweep), then destroy the held connections while the + * close completion is pending — the order Node's HTTP docs prescribe for + * `closeAllConnections()`. */ export const closeServer = async (server: Server): Promise => { - server.closeAllConnections(); - await new Promise((resolve, reject) => { + const closed = new Promise((resolve, reject) => { server.close((error) => error === undefined ? resolve() : reject(error)); }); + server.closeAllConnections(); + await closed; }; diff --git a/rstest.integration-serial.config.ts b/rstest.integration-serial.config.ts deleted file mode 100644 index 448277c11..000000000 --- a/rstest.integration-serial.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from '@rstest/core'; - -import { serialIntegrationTestFiles } from './rstest.integration-tests.ts'; -import { withAgentBundleRslibConfig } from './rstest.rslib.ts'; - -/** - * Integration files that rewrite workspace-shared artifacts (see the - * serialIntegrationTestFiles doc in rstest.integration-tests.ts). One worker - * only: they rebuild or repack shared package dist directories that every - * other file in this group also reads. - */ -export default defineConfig({ - extends: withAgentBundleRslibConfig(), - include: [...serialIntegrationTestFiles], - pool: { maxWorkers: 1 }, -}); diff --git a/rstest.integration-tests.ts b/rstest.integration-tests.ts index 27a5a6ee3..cdcf6cb86 100644 --- a/rstest.integration-tests.ts +++ b/rstest.integration-tests.ts @@ -1,13 +1,15 @@ /** - * Test files that run real builds (Rslib/Rsbuild), pack and install the - * package, spawn child processes, or drive a browser. These share - * process-wide build caches and output paths, so they run serialized on one - * worker while every other file runs on the parallel unit pool. + * Test files that run real builds (Rslib/Rsbuild), spawn child processes, or + * drive a browser. They run through rstest.integration.config.ts: per-test + * fixtures via `mkdtemp`, servers on ephemeral ports, and only READS of the + * prebuilt shared artifacts (`packages/{agent-bundle,workbench}/dist`), so + * the pool can use multiple workers. * * A new test file belongs here the moment it runs `build()` from src/api or * src/build (directly or via tests/support/build.ts), imports - * tests/support/workbench-e2e.ts or packed-release-harness.ts, spawns a - * process, or launches a browser; otherwise it defaults to the unit pool. + * tests/support/workbench-e2e.ts, spawns a process, or launches a browser; + * otherwise it defaults to the unit pool. Files that `npm pack` the package + * or import packed-release-harness.ts belong in packedTestFiles below. */ export const integrationTestFiles: readonly string[] = [ 'packages/agent-bundle/tests/agent-api.test.ts', @@ -50,7 +52,6 @@ export const integrationTestFiles: readonly string[] = [ 'packages/workbench/tests/mcp-page-app-browser.test.ts', 'packages/workbench/tests/mcp-session-timeout.e2e.test.ts', 'packages/workbench/tests/overview.e2e.test.ts', - 'packages/workbench/tests/packed-release.e2e.test.ts', 'packages/workbench/tests/playground-real.e2e.test.ts', 'packages/workbench/tests/rsbuild-closure.test.ts', 'packages/workbench/tests/rsbuild-workbench.test.ts', @@ -62,38 +63,15 @@ export const integrationTestFiles: readonly string[] = [ 'packages/workbench/tests/workbench-dev-command.test.ts', ]; -/** - * Integration files that WRITE to workspace-shared locations and therefore - * cannot run alongside other integration files: - * - * - packed-release.e2e can run a root `pnpm build` (rewriting - * `packages/{agent-bundle,rsc-runtime,workbench}/dist`) when - * AGENT_BUNDLE_PACKAGE_PREBUILT is unset, and always runs `npm pack` - * plus a packed dev server on a pre-reserved (not ephemeral) port. - * - * They run on one worker via rstest.integration-serial.config.ts after the - * parallel pool finishes. - */ -export const serialIntegrationTestFiles: readonly string[] = [ - 'packages/workbench/tests/packed-release.e2e.test.ts', -]; - -/** - * Integration files safe on parallel workers: they create per-test fixtures - * with `mkdtemp`, bind servers on ephemeral ports (`port: 0` or rsbuild's - * silent free-port fallback), and only READ the prebuilt shared artifacts - * (`packages/workbench/dist`, `packages/agent-bundle/dist`). - */ -export const parallelIntegrationTestFiles: readonly string[] = - integrationTestFiles.filter((file) => !serialIntegrationTestFiles.includes(file)); - /** * Pack-and-install tests: each one runs `npm pack` (and usually a clean * `npm install` of the tarball), which dominates the serialized integration * pool. They run through the root `test:packed` / `test:packed:native` * scripts instead — CI's release-gates job (`check:release`) and the * native-host-smoke workflow keep them covered — and stay excluded from the - * parallel unit pool. + * parallel unit pool. packed-release.e2e lives here (not in the integration + * pool) so `pnpm test` and `check:release` don't each run the same long + * packed-browser suite; `rstest.config.ts` keeps `test:packed` on one worker. */ export const packedTestFiles: readonly string[] = [ 'packages/agent-bundle/tests/dev-workbench-packaging.test.ts', @@ -102,4 +80,5 @@ export const packedTestFiles: readonly string[] = [ 'packages/agent-bundle/tests/public-api-packed.test.ts', 'packages/agent-bundle/tests/release-audit.test.ts', 'packages/agent-bundle/tests/rsc-runtime-optional-packaging.test.ts', + 'packages/workbench/tests/packed-release.e2e.test.ts', ]; diff --git a/rstest.integration.config.ts b/rstest.integration.config.ts index 9b3728ad2..2180d36f0 100644 --- a/rstest.integration.config.ts +++ b/rstest.integration.config.ts @@ -2,7 +2,7 @@ import { availableParallelism } from 'node:os'; import { defineConfig } from '@rstest/core'; -import { parallelIntegrationTestFiles } from './rstest.integration-tests.ts'; +import { integrationTestFiles } from './rstest.integration-tests.ts'; import { withAgentBundleRslibConfig } from './rstest.rslib.ts'; /** @@ -25,14 +25,12 @@ const maxWorkers = Number.isSafeInteger(overrideWorkers) && overrideWorkers >= 1 /** * Build- and process-running tests that only read workspace-shared artifacts; - * files that WRITE shared locations run serialized afterwards through - * rstest.integration-serial.config.ts (rstest has no per-project pool or - * isolate settings, so the split lives in two configs chained by - * `test:integration:run`). + * files that WRITE shared locations (root builds, `npm pack`) run through the + * single-worker `test:packed` script instead (see rstest.integration-tests.ts). */ export default defineConfig({ extends: withAgentBundleRslibConfig(), - include: [...parallelIntegrationTestFiles], + include: [...integrationTestFiles], pool: { maxWorkers }, // Concurrent Chrome + dev-server + rsbuild pairs contend for cores, so // parallel runs double the polling budgets (see tests/support/time-scale.ts)