From 8c2c4b3f0084e6a7e5d14e88750737b0a10227e7 Mon Sep 17 00:00:00 2001 From: Nadia Nujovich Date: Fri, 17 Jul 2026 15:24:15 +0200 Subject: [PATCH 1/7] chore: add playwright devDependency and exclude worktrees from vitest --- package-lock.json | 48 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + vitest.config.ts | 3 ++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index f2cabc3..ef41946 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "husky": "^9.1.0", "lint-staged": "^15.5.0", "next": "^15.1.0", + "playwright": "^1.61.1", "prettier": "^3.8.4", "react": "^18.3.0", "react-dom": "^18.3.0", @@ -9023,6 +9024,53 @@ "pathe": "^2.0.3" } }, + "node_modules/playwright": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", + "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.61.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", + "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", diff --git a/package.json b/package.json index 50e54dc..80d7f65 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "husky": "^9.1.0", "lint-staged": "^15.5.0", "next": "^15.1.0", + "playwright": "^1.61.1", "prettier": "^3.8.4", "react": "^18.3.0", "react-dom": "^18.3.0", diff --git a/vitest.config.ts b/vitest.config.ts index 830588f..9ed709e 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,8 +1,9 @@ -import { defineConfig } from 'vitest/config' +import { defineConfig, configDefaults } from 'vitest/config' export default defineConfig({ test: { environment: 'node', + exclude: [...configDefaults.exclude, '.claude/worktrees/**'], coverage: { provider: 'v8', include: ['lib/**/*.mjs', 'lib/**/*.ts'], From 940fec32f8d380b937a4b2ac60f3d1e717edb3ca Mon Sep 17 00:00:00 2001 From: Nadia Nujovich Date: Fri, 17 Jul 2026 15:31:03 +0200 Subject: [PATCH 2/7] feat: add release-infographic HTML-to-PNG renderer --- .claude/skills/release-infographic/render.mjs | 55 +++++++++++++ .../release-infographic/render.test.mjs | 80 +++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 .claude/skills/release-infographic/render.mjs create mode 100644 .claude/skills/release-infographic/render.test.mjs diff --git a/.claude/skills/release-infographic/render.mjs b/.claude/skills/release-infographic/render.mjs new file mode 100644 index 0000000..b9964df --- /dev/null +++ b/.claude/skills/release-infographic/render.mjs @@ -0,0 +1,55 @@ +// Deterministic HTML→PNG renderer for the release-infographic skill. +// +// node render.mjs [width] +// +// Rendering is done by a headless browser so the mint-branded HTML (exact +// brand tokens + accurate technical text) is reproduced pixel-perfect. The +// `launch` parameter is injectable so unit tests run without a real browser. + +import { readFileSync, writeFileSync } from 'node:fs' +import { argv } from 'node:process' +import { fileURLToPath } from 'node:url' + +// Lazily import Playwright only when actually rendering, so tests that inject +// their own `launch` never load the browser package. +async function defaultLaunch() { + const { chromium } = await import('playwright') + return chromium.launch() +} + +export async function renderHtmlToPng({ + htmlPath, + outPath, + width = 1200, + launch = defaultLaunch, +}) { + const browser = await launch() + try { + const page = await browser.newPage() + // Height is a seed; fullPage screenshot captures the real content height. + page.setViewportSize({ width, height: 100 }) + const html = readFileSync(htmlPath, 'utf8') + await page.setContent(html, { waitUntil: 'networkidle' }) + const buffer = await page.screenshot({ fullPage: true, type: 'png' }) + writeFileSync(outPath, buffer) + return outPath + } finally { + await browser.close() + } +} + +// CLI entry point. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const [, , htmlPath, outPath, widthArg] = argv + if (!htmlPath || !outPath) { + console.error('Usage: node render.mjs [width]') + process.exit(1) + } + const width = widthArg ? Number(widthArg) : 1200 + renderHtmlToPng({ htmlPath, outPath, width }) + .then((p) => console.log(`Wrote ${p}`)) + .catch((err) => { + console.error(err) + process.exit(1) + }) +} diff --git a/.claude/skills/release-infographic/render.test.mjs b/.claude/skills/release-infographic/render.test.mjs new file mode 100644 index 0000000..0272854 --- /dev/null +++ b/.claude/skills/release-infographic/render.test.mjs @@ -0,0 +1,80 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest' +import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { renderHtmlToPng } from './render.mjs' + +// Minimal valid PNG signature — stand-in for real screenshot bytes. +const FAKE_PNG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]) + +function makeFakeBrowser() { + const calls = { + viewport: null, + screenshotOpts: null, + contentSet: false, + closed: false, + } + const page = { + setViewportSize(vp) { + calls.viewport = vp + }, + async setContent() { + calls.contentSet = true + }, + async screenshot(opts) { + calls.screenshotOpts = opts + return FAKE_PNG + }, + } + const browser = { + async newPage() { + return page + }, + async close() { + calls.closed = true + }, + } + return { browser, calls } +} + +describe('renderHtmlToPng', () => { + let dir + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'render-')) + }) + afterEach(() => { + rmSync(dir, { recursive: true, force: true }) + }) + + it('renders an HTML file to a PNG at the given width via the injected browser', async () => { + const htmlPath = join(dir, 'in.html') + const outPath = join(dir, 'out.png') + writeFileSync(htmlPath, 'hi') + const { browser, calls } = makeFakeBrowser() + + const result = await renderHtmlToPng({ + htmlPath, + outPath, + width: 1200, + launch: async () => browser, + }) + + expect(result).toBe(outPath) + expect(calls.viewport.width).toBe(1200) + expect(calls.contentSet).toBe(true) + expect(calls.screenshotOpts.fullPage).toBe(true) + expect(calls.closed).toBe(true) + expect(readFileSync(outPath)).toEqual(FAKE_PNG) + }) + + it('defaults width to 1200 when not provided', async () => { + const htmlPath = join(dir, 'in.html') + const outPath = join(dir, 'out.png') + writeFileSync(htmlPath, '') + const { browser, calls } = makeFakeBrowser() + + await renderHtmlToPng({ htmlPath, outPath, launch: async () => browser }) + + expect(calls.viewport.width).toBe(1200) + }) +}) From 1057479f97a83b9e3847531d3cf7d2e48f83be95 Mon Sep 17 00:00:00 2001 From: Nadia Nujovich Date: Fri, 17 Jul 2026 15:33:24 +0200 Subject: [PATCH 3/7] feat: add mint-branded release infographic template --- .../skills/release-infographic/template.html | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 .claude/skills/release-infographic/template.html diff --git a/.claude/skills/release-infographic/template.html b/.claude/skills/release-infographic/template.html new file mode 100644 index 0000000..7b7beaa --- /dev/null +++ b/.claude/skills/release-infographic/template.html @@ -0,0 +1,195 @@ + + + + + + + +
+
+
mint.
+
+
{{version}}
+
{{date}}
+
+
+

{{tagline}}

+
{{body}}
+
+ github.com/nujovich/mint + {{stats}} +
+
+ + From 4f1470404d57954da81dca2db4ea5b6403334571 Mon Sep 17 00:00:00 2001 From: Nadia Nujovich Date: Fri, 17 Jul 2026 15:35:25 +0200 Subject: [PATCH 4/7] feat: add release-infographic skill definition --- .claude/skills/release-infographic/SKILL.md | 109 ++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 .claude/skills/release-infographic/SKILL.md diff --git a/.claude/skills/release-infographic/SKILL.md b/.claude/skills/release-infographic/SKILL.md new file mode 100644 index 0000000..a737d6f --- /dev/null +++ b/.claude/skills/release-infographic/SKILL.md @@ -0,0 +1,109 @@ +--- +name: release-infographic +description: Use when the user wants to generate a visual summary / infographic / release card of what ships in a mint release. Reads CHANGELOG.md, editorializes the changes, and renders a mint-branded PNG. Trigger on "release infographic", "release card", "infografía del release", or before publishing a version. +--- + +# Release Infographic + +Generate a mint-branded PNG summarizing what ships in a release, from `CHANGELOG.md`. + +This is a skill (invoked by Claude), NOT an automatic hook. It does not fire on `npm run release`. Claude applies editorial judgment: picking highlights, writing punchy copy, choosing a layout. + +## Files in this skill + +- `template.html` — mint-branded shell with `{{version}}`, `{{date}}`, `{{tagline}}`, `{{body}}`, `{{stats}}` placeholders. +- `render.mjs` — HTML→PNG renderer. Run: `node /render.mjs [width]`. +- `EXTEND.md` — optional pinned preferences (read it first if present). + +## Workflow + +1. **Load preferences.** If `EXTEND.md` exists in this skill dir, read it for `layout`, `language`, `tagline`, `width` defaults. +2. **Resolve the target version.** Default: the topmost released version section in `CHANGELOG.md`. If preparing a release, use the `## [Unreleased]` section. Accept an explicit version if the user names one. +3. **Parse the changelog section** into buckets: Features, Bug Fixes, Performance, Refactoring, Documentation (mirrors `.release-it.json` sections). +4. **Editorialize:** + - Write a one-line `tagline` capturing the release's theme (or use the pinned one). + - Rewrite each changelog item as a short, punchy line (≈ 6–12 words). Wrap identifiers/commands in `` (e.g. `mint-ds lint`). + - Compute `stats`, e.g. `3 features · 1 fix`. + - Pick a layout preset (see below) based on the release shape. +5. **Build `{{body}}`** using the chosen preset's markup (below). +6. **Fill the template.** Read `template.html`, replace every placeholder, write the filled HTML to `release-assets/v.html`. +7. **Render.** Run `node .claude/skills/release-infographic/render.mjs release-assets/v.html release-assets/v.png `. +8. **Report.** Show the user the PNG path and a one-line summary. Confirm no content was clipped. + +## Layout presets (for `{{body}}`) + +Pick by release shape. All markup goes inside `{{body}}`. + +### `bento` (default) — mixed release with several categories + +```html +
+
+

Features

+
    +
  • Short punchy line with identifier
  • +
+
+
+

Bug Fixes

+
    +
  • ...
  • +
+
+
+``` + +Use `card wide` (full-width) for the most important category, plain `card` for the rest. + +### `linear` — a few sequential highlights that tell a story + +```html +
+
+ 01 +
First highlight line.
+
+
+ 02 +
Second highlight line.
+
+
+``` + +### `dashboard` — "by the numbers" maintenance release + +```html +
+
+
3
+
Features
+
+
+
1
+
Fixes
+
+
+
12
+
Commits
+
+
+
+
+

Highlights

+
    +
  • ...
  • +
+
+
+``` + +## Output + +- PNG: `release-assets/v.png` (versioned in git; auto-excluded from the npm tarball because `package.json#files` is an explicit allowlist). +- HTML record: `release-assets/v.html` (reproducibility — regenerate without re-editorializing). + +## Guardrails + +- Never let an image model render this — text accuracy and exact brand tokens matter. Always use `render.mjs`. +- Keep technical identifiers exact (`mint-ds lint`, `gap-rule-color`, `--no-semantic`). Do not paraphrase them. +- Artifact copy is English by default (repo convention), unless `EXTEND.md` sets another language. From f3ae766d0e9ea2882cce64bf3b214f83c869d687 Mon Sep 17 00:00:00 2001 From: Nadia Nujovich Date: Fri, 17 Jul 2026 15:38:06 +0200 Subject: [PATCH 5/7] feat: add release-infographic preferences and output directory --- .claude/skills/release-infographic/EXTEND.md | 8 + release-assets/.gitkeep | 0 release-assets/unreleased.html | 217 +++++++++++++++++++ release-assets/unreleased.png | Bin 0 -> 43880 bytes 4 files changed, 225 insertions(+) create mode 100644 .claude/skills/release-infographic/EXTEND.md create mode 100644 release-assets/.gitkeep create mode 100644 release-assets/unreleased.html create mode 100644 release-assets/unreleased.png diff --git a/.claude/skills/release-infographic/EXTEND.md b/.claude/skills/release-infographic/EXTEND.md new file mode 100644 index 0000000..4c722b6 --- /dev/null +++ b/.claude/skills/release-infographic/EXTEND.md @@ -0,0 +1,8 @@ +# Preferences — release-infographic + +Pinned defaults so the skill doesn't re-ask each release. Edit freely. + +- **layout:** bento # bento | linear | dashboard +- **language:** English +- **tagline:** auto # "auto" = Claude writes one from the changelog +- **width:** 1200 # PNG width in px; height is automatic diff --git a/release-assets/.gitkeep b/release-assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/release-assets/unreleased.html b/release-assets/unreleased.html new file mode 100644 index 0000000..ca732bf --- /dev/null +++ b/release-assets/unreleased.html @@ -0,0 +1,217 @@ + + + + + + + +
+
+
mint.
+
+
Unreleased
+
2026-07-17
+
+
+

+ Static CSS linting learns a new trick: catching gap-decoration hacks before they ship. +

+
+
+
+

Features

+
    +
  • + New mint-ds lint command flags hand-rolled + gap-decoration hacks — borders on children, + ::before/::after pseudo-elements, or + backgrounds beside gap — with zero LLM calls. +
  • +
  • + Suggests the native gap-rule-color, + gap-rule-style, and gap-rule-width + properties, wrapped up in a "Modern CSS Opportunities" + adoption report. +
  • +
+
+
+
+
+ github.com/nujovich/mint + 1 feature +
+
+ + diff --git a/release-assets/unreleased.png b/release-assets/unreleased.png new file mode 100644 index 0000000000000000000000000000000000000000..6730f19b3e020976be4f537462df405c8f13b1d6 GIT binary patch literal 43880 zcmeFYRa9J2vo1;m3zh_j03if-*ABsgLulMXaCeu6;1b+5xVtv)1b26*vBsV5Ly~{* zbD!?ZdAN6svw50hu4bA`CRNl_ssm(;^$R4t`Tm>^7^)&8^5SG;G>I>-%z5Z>URSI{f{SVd@Jnq4aUqH!h5 zp1>vxce^w;RbR-euj#4LI-_$!Jm#)=Y5g4W!$#27FSZbGZw5Yg26o@aQS?xT>Qutd zKId*aWZXt0SL&m@(A!jhb}g3VCkp=j-3v(lTX@I4e*K3m1cVBl=feN?;)Oq>{9UyJ zQBa=!U8%i#M*i=iH2M3Ne^=jVU;6#qV(|BV{deV^`#*>MkIWDd{@+a_cK+Le-b;dN zJ2Gs5r$$YLz$M-B<T zJ+(^~KG9p@2cLzwxzYbKK|dQ57K3emP)|v`Nu&|k-QC7-UEK&~U}QSSoHNXwOxDr# zeo5_QJByH?>FV&yzkfnGCN~JLdMj{jwE|1&h`7Zdllk}H?#Z-eXmJcF>-jwGk5I5nx*;s@J^j9lu8&di~X3 z&OXEay~k*(vJ~%E_{IJmhlHTT_9sXnAhZKt==(+55pwRFW-2Wjn?icdK}xhV`D?p* z0B)U|#LzU}!bVTovjaGZG@pG-mnSH8d2^E@{}X%fBP+jqRzb72Mr@qZUf-k`uvc?D z0imfcBRKVThyXufCJvr#w+CnAFHN<(BDrqR9_;jeTxju&G_u;>xIUb8V#F$sir?N2 zw%!z0{!7dr>Wht@i`bKGPxsY}Hn?2S0Q^B;WF~P|wcE|vl~HuFwg!vaiZ@jj*)Dc) zvfN_+WP|6PiQa|SRG`xgRUyh(aM(30HCP?bdn?Lew_cg@jho;GX^5yeV_xyfchcUa4 zn)3B3vuP!fHC_`|o<`QDx&%M}!~!L+0UeXUJ>>2`p7(Xm9%F}l?WT2!=+3u(n9{kI z83DQ8W{-EQGI@C#&sct!dfr=pvk%T(&;^<>1;P5P@DsT4p}$#8m;W$6*7o(myVQCl zf zVorVUULpY{DE&d{m$qiTZL(0V2eNdjP91rdn;TI~`sydZ=v zJtRe(OP1TDH*VlwqA~oHJ_2dOn73vvZ&UNPF?kff$9iTuxxqdM+z^{ z254kUi{i&x+lVeNvxCb$c&H^kZKHNqI9w8%(dL;h*A6!{dQ=btMJ?Yqx9vLIGb}wvz>keBk7=c_av2S`)7gnS=A>Uw4*x?P8 zf=k@o=7Y40lL-OwQ{oZV!Uv&P6 z?P}A4j;-WobqN}bTwqyqU(L9{0!7-KJihN9mFNdneP0lia;S)7&)x+&0i)}n@NN>7 z(uVY!gGJiSRa3z`W5b?&RjY{;ia$cB@Bz!N^|lSC8!VoU4+y>f0zbd@a=vcOj?>5x z?5cG?Oe#J9-dDH0#%)qjEk3tkNb%UZa$DB$_&IPo@nl{T-gggEw(v!2a(~Hud4dLS zV^+!0F8{D>uyl7sno@O;i>kBaq&rTV59f_Q$EIRfg-gqc1m4o7td*7zg;!W!<0hoL zo@^Da=r6bGJTOP)q(E%bDr{k~6?Lke7*&^Nzu>O-X}C#m$u87iu)i;1Xi=M(gYfq( zzm=4{ujB?Qe^r{k6@M#cs-S?2Y9$yhJ_I4+w(~nau1ys@c7g$IHB(iE7m)pum0$c} z*M!?dbjd={Sgv25`Yq;;cAF)q-CcJg@2Bt`6))RO@jOzvi1d)rcD;ksiJF}2U6L*) zOvMK56`7!_wgi_UFyH3kbpq~}fpTm8l;5>g-15VWb8r>#(gb0q3uIYDxz#DoQ!%4s z2V|Fm=d&t@TAqcC#0iCjV6X7OLpZ9kxbI~&HZ@2RPnv1g9&v<1Q$;mE|2jpl!6_k_PF{C?&rWNu4S>0S<9<-W2+{ko()rYZXRZ`Cz~?o=1)QSE+h zJPd7$3I4>d2IPX4*6R4CE^DRof|MKyDc;`@|#*$G-n<{1Wdn-oTA|ll*bDk zY_Dk;7z4IWB||zXYkN^X|9!TYFcT*)iZMAii~PEn~J?_-(rxNYmE4G z?qrtK2bU)=Ejyyw?NFM3y!|PICB6r@h;_SkR>bmZ<|}sv>_-c@XB*sS&0hy%AR`DE z;{4I=uTeTadk^dT`i$aZod%UM(&;tynbT&s?d{dKFy)zbe@Io;WJWLip`2aaSkp>n z1BDdrf>^Xq7ttL=7g>{`tep064ndO=PHmw$l=Uk08$VE$DEGJ<#vgPBom%Pi=}E>( zX_SY%4Wp_a#FyOoE{Yq63{0NSGNQS-4-b+AU_VjX=TtI^;)audx-YN0tE$Sse`y) zM)DRf^&&P7>{+u&z5zDpl(ViTMTe11mLRq}b)sc;`1?$jZ+D69l{ys57!k5FyE!Be zQ+gempX!dY^|^nB=ML^WLE@?t#QJ%`gmGybYMT=x7*$nOU#+uhzDNr&l$JM?ejL$a z`~3d>VVlM6%=02iJ8_L=(LZYY_8$1gw?mt{stHIH%7XHugaK(h+l;Ce)H!!)|1J-H zG+moLeSO5KB0a&Z8ar?tzkEaSXjVHrRnK*6g7%tN3iEi?q0`8~5A@k@^mnCIxJX(H z^*H>4QS1(xE@;akkof&isfd9&Vd&`V*H_|G?-ORz!&4zcilDE`RB3W6wxxCXE4Y87 z13-G5XgbNhVL`Y=$SIYS*!ug`m}st&hI~Y@`v{&C4bN<%b^Cl$y=u#j9GBCmgtb?Cw%-+g~^w+gxJ|F(bW{kUV-`c$M6~8-j z6VnT}*tpX6FOPv)nL2mg0eSnOR!WnZ*>RH+%%Nq9(^1L|HhyD25(nlkvCiIxS7hmz zo9AQc?B9gDjC}Kni)UpB5wyF?p@nwK1yz}*XfU_NH(l#Csbm-@c}bGw^3+dkTN8)hk-xVR`N z8r{)VMUK=N?FQ&gdwC7?GFvsH5lTGiRm5n=D6K7vhW&5Z?5X6qFFD+V(eNW-htcIR zINnxxpp#s{0~TJmvX4(KAtruK*LeEDW%Kud9ad_-{*;iOBAx}hyOv3&Q<2Uy+H&Jr$9Q*z5~)rt`RxzWopd$uloGmHgkfXAj#=-+e`n zN)K-^GxhTh-3-0DKf9rlcL4kzBePn!4Ak|1ncoX_4y=~VuKkT2-k+pZt_Jt5ku1}$ z4{0=^2|Mm>Q>IllYm=UEDVJZn_S5~S$cVm1ZCl&RJ%m>Og$1ygo)yPXIVU>Z+jR!q zFh~YMOTO>6Om43;)y3djnrbV#u6NfZOfG)c$et;0Ouasr-`tU}BH_3K#XszV7Ft#D z(f~J^91i+^?E~h$SWr2hit|mZl+}TPBAzIlrBSb|kD7gw?D6u+7eb^3jyr2H^gPS$xoGrxS|)@LM?mwu1(F&73Zy}E}Vgc(u@bIhEFsf!b%H|MSRN`nh|3v?92V~S>E1~32MYs}0LRp@ z!s9O-Lr>G~xTzRaU9F-$FB`L|J6ujM@u$Myi3HfY%r>fm1O6N;`0r$S?@qY}^RnK@hP+C63Hk^9tlx92qoQ|&EC~2W)w=-Cl!YVDgx!Axe7nM!r z*bR<)u6g-F0y4mN3WDEpWMJ33JSSxN`&Ic1o>`D7A8vD6tEA1`WZNhlvM%(85d;>Z z|HeK#MgCR62>+iz9z6fBm0z=JY7sX0;qS~cqvNz`X&6i!1pT|nxF*h7@mq`Tc53N+ z>T~J7NEhP2+Xs-3)xv;ZdS#PfKb@Cf_AS^87vwYMYk$lEPA3G*?czxc=gxq9n-rVD7JXJWd>dl5*r*23MD_zj18DMSL?LXitcrQ?d>JJ?eM=rsl8b~i$~Vxf>LG6~GR6Z{WsI2Ov& zMK$EIuC6){CTkT077$h`N=lmr*K-1tRHwLp_tp{_4Vp$y)rCVG)kF0440{ThnHgFa zt3*X4_2!omsFCScw4v>vM`zH4lsT7D@I`w9xLHlqzMa^7;I%E(dYtdfJdmnE^dm{w zhyRzwTd%7j%cSx5w2&XP*NeZ>c)_526qmIaBmDeFptghssqv6D*eds=Y`D#f^`l)o;H5#^#ODk-OcbK0X_V)gz zc=SbRfyyYbN8P`wz1{SjSS}Y|3ViG{>W5xB0NPWI$@n}NuyPj5nO&F zn2g^a{BP#g(BXrzU#XeMnL0+9QLG;8*gSX3;960*@8+G?j%#-HbqR7|Ky}yS)q7Z+ zXR!_x2zuBJq)6S>7s<#VE7Hk(=xn=&=YK6SKX2p~vhMC+cgg8Fa@ZtA*Ixj7E>d(M zW~2VKmUfZ$bu7oN;v(zW8TPi9Fj| zQpFXD$4IJ2iW0^kExI=2Z(J|t4ODQn?tk&xvcd+45$pHw41+O(7`(l-%ro{(qjauA zLg|R_%;}Hd>MlGDBb(InDc@AxYa3J~+flHp`Y)&I+$e{&+*c!i7gifRGO`WnvfStd z=j2$wqq$rA^sI>%;c6q&$LD~J&ut}j55bwZXq)(UxMXwnNb>FxrtX)^;@1CTZNV?i zeN-vg#w^p&HvPRvM=DFSL!*IRlYu-hge? zGq%=7OO&Tj_NQR^NL(TB{%|L2jw0Tg9!r@$;UX8!{kVc+7HU6V+$w(7bH%HVGF2z- zjWVE4dsjNXUeyo0aVunlTbaiMWZ%jmg_f5d$&7&f))uRDtO%Md+_D!(btqC<_(nDIlTaRi(* zBfjo!;#QiR@2x$O9R@L%=qJhsh-I=f=IsxNuwPO3Tm;YTOp>$E%ai$+@OZBA7$(Z*uqynGUuZsd_I|Jyu`&O18(sIhS z2V*4rfSvmOwcr*WlN<)g)mkx#$XT__Dx)1@mOyy?&-p<$YsrI(>f@|Fc5u?%#~)H zk|4y@q>HmWtN<-}g+x$;QTmm^!dt`3hK4CYI@S*Swo-aj=mio%B$Dvwf>_llx}f~_ z*$y^UV7?(zSxb2YTErmsf<0;v@iDtwsxMGTTsGQ?dqv$n9PMr6xrC%1Osq0T*c5V1 zQ4?>zGhWRDklg!B*NxAQ*=oy}=J~?I1F=~{a=pjHHY&XM6g-oy58oG2&hc{IYF^hQ zLN|(87r1jAP&nutjMGAvC)3Rg_02l_?seQVF|(?kgdg6aT-#NBjZSd1ITC|kSe#uG zuhxWyIK%n9l>J~Rq!I7A2jbGgTSaQ&?_^8u(1N;5B@Z0HH!XJn`P zcgBAjZ~%VBN}P>uOUpEH7BNa*)QuFzE`6ZSx5)IKKJze7{o= z0evUn3@Ag)tnPn<s)<+1gP zdq|u%OR+JO15cX@Ng*(VlQHxl z?~1eUDw&;q#tRGETbqEubADaIer(a!Myr97czG^)X19A&;Vm$~YDBIicE^AOWF@1dKunnWo=cn9d^e27D1Z&EdR2{N-Mg=;V)hqJqmB!jmY463dmg z@@~OE-T4_JaFNl4Yk!Vv`~zSvSKARMjW5y)pkJm63*RQoQDx~5$X$bg%Nc@j&K5jX zV`{In(~itKzP2RP}s5&fmUdC;2(X8qssPH z*G*)mE%+HiZhU%bId{^&(y03Q%-4*|Emr6Kb<*A?o<=3=xJoq#X;_ns$&rr@sxz$+ z#kTbOg zl0>Ual4n_ptNFHta@DMm<$(Pk2M-Qf34~Rc9xc?A^>s%OWax*hJbb<(WK>A*3;AX4^j|z8N5St~!2gKJ%zX19dtg zw(?n5(X#z7EWlEIeDZB_oBmg!J1%jsz~ew;eq1o|tVhbC)q&Q1g(^4GDPtx!1Ed*w zOq;|{D7prk*SPxlY;B$BHCCJgUheVZg7GvQ30Y?G=JuoQe&r^u@d$q1BOMj9K!w5G zGdE^}lYv0uPV?(FFnR0IJYD>cLTl^P-LBH#vN95qf~sng;4o4_R=0^I@WqI#m5HrR zzF&bg%2LDo&n!Y3 z)c!*84Xc8!ec{YLi;Om!IX;TH{L#vTVrxzgu%p@;|I348M=UQ|o&*<{pl-NOOZ_?+ z&1}S@ZM(0={w-MKYlF2m7YUC7de!D@7Q@QpPQe z9_X8^kOJEG=xL}peRgFk#^`8#gv+(yQ?>4Y&y!Q1ifMP`nSNCnwF`1D+q4fx=R#P{ zoh=-=a7>l+rwr3+r5efSGVBXW$NhjBdQxhJhEHC1+4F1R* zV9WH9J$Q;lY+35SE{e^7*&umO(AsRt!`qDw;&-IDB&?7l$L4EpkL2OCgu?iIp*qXr zc{9Y4QiOnsjgkzX89k{NfKqujFu1o#4L=+ zS-C06Xh9dncQ|iw31Lc~yPNANcA}C8X;-}}xwWC5qgn}TyptUDCzcELt=pn>N~=J45JS%Pp7FXDAG`z0T4xj9aNg8q2s@ZCqzAtnH=lxcTy$q^agP zDrqhhg4*CV;?Zi=E=RXHqta%sP)0KRH^=E`M`9G^($h_JjeJHjZ-Ly{+~xOmwFuSn zA=TB)tyQ+NIcU|49J9|IU7=-lf!_zE&*?E^U*BKH2gqN@4hSlm8?@k4dRFfC?WD#V zWLRKE(jd*Rt83azZf`SGQoS#yANW*3d+&Y4;harEL<8)~Rd8ozJTMa7QtV*rPu>K~ zF6=_aF<;%~>+2uUtBHx_u*&Zpp&d3#AsSDYd#dpl*`rg$=YQY~YK1WbkoNx$veR!)S32m7s#3dznv z!*9#ytM&@PVC5z?GPB6-G$>RnQ& zW6I`-U9tSo#ol9yS)?IHRNbYg*hKMm6748Z64$vpkZl#aj%_SHk>kY#1!7t4mF#kj z)AEYXEN<>c?J%vkuL(H>iZAJ~%rhkQj&t^0e#961T__`u+C)1TWNR*yA>4V3_j?OL zXQNwPu1i(ptzdkV*Lh35^mey9%Gk@7fbAqw)Hi21xA|}R({^UGWh9$^Tg;UmEJS1T zKYl5Qoi%OA)ut_vqu*;`k6_!8oRX>SzvVuV`5j&*oT{5; z5}e7AvVe(!U+6RO-p=+8D%MTOFti+P@?Fp^DNE5kh6#Ipvg2xBrK=X}9rIdTD)+jl zx|>uv?s>RA35)S^GI%86+G=G2l5o@b(3P^f)Uck$D5(MJ;%W%CI)0UC)Zte)g{B>_ z4(yGSlvNpkk^~yX|w}iBUk4Ai{<1i|w9^ z>wf7`>O)?*;`g};$H9zOL9QB+FvrYr?1>%S0W;~w6~gio#=-*1-p9GYZLrCVQw)T+ zy6THCbld+pok^*2e0TmyGolK6*uqb%dlQ?BX7(EjYx%Yecw+we z8S^*DZeYBbwD(WW7TWB6?aau*I4Xm{PnvWBXAshZT-!I3E12n2%;3bhyUEj7c5SlU zu~H|KUlJGz0dA=MNj05wyd9g%5xO{<_Y>4I(VO{IRZA2f@cj^*@*mVT-agb&UmF37 z=Js~7^Di`5k9ej|ep6bXH6*mHo+tqIW((wXX!}b!9I=;|a9M_bplTQ5H==jthS6dB zX9)v=ldjSODH~E^e(V5?K}yG1>Fyu(`3`cx;Uq?DPc3rmd6nQg%ebi(`L{8D3PQ(` z_vJK2O0SLGFTdGan)mW?t|2>3jU^|pm8@#X#Ubm7x7--VI&$HHO zN}uyF_u{5~mBP<7L7mCc)Cpvvod{Hoj*rZJ)Q}aK*7IQ3AA9@>=z8XjY`KQ$HyoR* zek!?PYx~^UhqM0c?1)5W&b7}>{C-LiKS>IQd@)zFuxHS^nPv*6o#aeUa!~${t`}Y$ zcYHBMGFAO0G8~|?RImrgta8d*1!M_s2fe_gcGB@;QMzZ zT(oR0NhZMnqCa|0z!3npFJ=`T0JRG)YGVcI3+`{nFOs3>UX3UKPe zq~;WVT&((bX$5WBH0C&yVzt+7Ds34nyL`EkOCpYgdo|k%S`sXYau>JnwXTZD{LOKB zGBm=4%-&FsI*C(`wlJFMReH+4dIs6tg7E(6*$E%yb-F1E*$a(Y%TQ;KW|&)jN8=3O zg`s7kmui~U>gUxL{AMhYGTf{~(%0@ZT>!oFJd8TZfF{l(^<$$WXZ=a4Z;ia*kB|8e zv~c2ggf?3qW$)dZo6a^?M3=c8_DV3n6CwSHPmMlLNh~w8s^FX=Jnl?mI9+%2$G}1g zWn8zo=W-8po&>KR@1@K9>ks5#e$7%9eiUBk@wtTV68^lQH6NvZNEBpZ`o0r(5$ayk z=K90fw9v#Wfhoo!SqsP0r>d?Xs4Uz&-!~N`IKRG+O)M129|4h?s(t_Dh6}{Z0{C<@+0`;k+O;P^l zu?i*3b0iFqCRC-04gLJ+s~9+`S0??r!aEutPuavv^6O089uZDfy>gDHrT{)!LY*b+ z;WE;JMjyIB!gwoFtblF_lvWFCzo3JLb-9~`889t^ag3@-U?wev*tMK|#o%0hCA(6C znrJPje(MgLsX^dtN83StVL?~bD#xr$q~SWd&%*nGW9jkPuZRQq^=pj?cf(C&XzAnX z`+Ll1ShKwEmtw@}dhS;I6{%HL**8y=mO|xgb(85`%%l=uu;R7U#fI7i=IcOexXg7k zcJ2)tfgy@lq$3Gf5n8QABPIzW=W2If$`?*=<8$>c_7e@N`NhWZr?lnx&dd>+S*&ga z$o>>wsa^QpKkN0HqeC4SY5XhgJN-$dJ9_&1TDElp(o3DS8;(Dgk{)DZJ}4d$hul;+Hc2g-bS3lGf%n?joW8<-HTka(+cK>nxl>i?Xfd449)r!_1|4lw?K^( zq@!EsD74xP9wx3W{KSEKo&~j`qYXhPpWSm&XCc2SX)~a2O4LcmtLmh9pI{vV-fh#& zjcbx4UC2y0FuFoNaJXo@QgP-egaMqG0s^zN6^P2gh54D-?r1YH6oN(zK~DP7!;Qx{ zV!FRdWZ>TeTe=#-mBejsjiMglf_S@YoW>KnksO^JF_y-_ui9Bp@53o^bstC02!lf! z8u3s@SGXCd=;m@i*mgBqPbc(TShScM)1m~Wv&s_ym?$AiOxoF6$QguAb&ehl<>rnkFY(N-`?LVrG(iD8W;!2nz1&0A?7d(b=Hunt z1o>X%$&!!6hc%eW_D>NiroVcP6rP}p6FhqO$?m4PtN7U)(T)=bY4zw9+% zMCO%p#72%$lGW4YsC%r|gK@XnyfPNAbEI4P&|R@!M$6KP6yqze)0P?b@D*vSmoWjoOI4hMCAoGlq$bJa5~s_eZReR41>Tru4)><7nlcY81`@d}JNS@@dJl1CVl`DHD2rtl9VgY_&i3oMa7b1Fmh-j^*uispmV0JODkVAj-@T=G;n2_!!w{`~sE|mB#9PE>j1Om=}Q%p}!=fH_ku;Mal%;s3~HS6hKWBeug zb9t68Cf^0Y&X!Cd`JbOWTR&MZtF3ibrdwkAM`cSmCcw=6cuWrk0>AV8Y+`C^YSi1| z>HC+QllHM^C?o-69Vn39r-wWyk(62gx?Wt`kEIM9ScLDuUSzM&ZUu6I{~1gmeV+>q ze$yEkfjMx>K=}6*m-ao|!e>t%T=%nbHsB>e_(RM;D;4;BeY{MJfJH=tB2S3;Zx8$Z z|IcQGLPUQ3oY(Ja$s)NSX|tefb)_xL(kb+$i&}0y+x)qo?6hj*%B1+E@x-j`9aw?U z`nu(3?Y%Bp^{)B6)j3si^YSCr91X0&>DHih16I_m^=_N84^7%?s1Q`n%F6ROHR>DgR?0O~%fE)D`#$Z^krkq-Qk#k-0pQu~k2*`@5Pa(bb_~2#| zb8wVZqu~!c2Y@P`s3bF`ryz9rTmX3H9PI^zpgEp7nk{JNIEbkj=qtce8aj!#y3YL(WC`>FSWfXlYQD9q~h zV_#$qy>o1-eSE^U#l!7e!!I;w34|T;E{V&Mg9E&!n7w2*)e??RkFSRs<3wyMyTb*_3bK_O@7(auv}B{xi+~zXK%*2n+$7ek80FK zh7YBZ3Ob6erH-#71^7Nr*%M^^p0Kmq^1{vv3{N$&zm1?ngy6;oZnB8qwP8$ezoMco zVJ?q)W2`ybM}1TUzVHm+Gq7xl{%7l<nMKAhK+rS zGv54UTR;d_w5uu+HB}@5baQo2!X%U>c_ET%F$ua3wVS?r4mlNtYrq}uhf{lT^h!sM z?+|-=2IVC_*s9{H63uJ8zd_*7a2_L0)yCZnJ#U=z04~XKmEzPAk2aGz2`EOpVUbIK z+axx>iJrWNyZj+jDe^!}m8|}f;FvQ+)eb1<_SC7Ej!q={2B@7{%@4KfT^@OpR)#|t z7biXuK^?4Rbn`QqRBtdpK-QJ*CL)$SpZH%~sd)3evn&Kno_TQ66-&>xa1YH=5!@W# z*U$5b3%0o~>M58>_y}Se<*fzPgjroD8|=4FhDj&YdWzc)Psvj%bJglLKe+9@sb-}I z1kNqY0cB;SdTA}F+BB=UTekWH)77xw2!uen#`V7TVrcRI9hPaAa$)tvVzqZXBPw>y zf5~YQbnyC)O!vHhXmN5lMS*s9wb@fVGkw*(#D6DL+>+X*ag5x^b-48G3g4e=Is*XO z30#!*gSOKAKCsPG<}nF_Pm;ZCM4uhfRaA7X74KvG8-0JlJ5Vw!wE)x}0?n5nfNpB# zUoO;D#yQyxe&hqhaPZmWOBka$u^Mb$kBMQ%ooXpj*a14NU-eGL*<|sV3`xoOP7(X4 zxnxMxz4Frs$-YZt;jMrldTvLY$?0O_R^joG)1jNn5q*{LG9AZbm7ke7@mQp{(Ge-g zw)gw2mxz@PQ~MIgB~?4B4FB>Hy`JBg363s1Lcy)E{()sSDQXQNAKOxI7>!jLLriUt zsub^IWqKqzdBi+Fn|gJX9TWt*yU@rD`x-8?XHrqv%wvAUoRqY1e5$z8ayDU4jWZ<^HL^S2|;yX9{#yJHt@Q|gn8hml@p9AkZiej7kUMwTKXMuC ztJoSFeXtRTeD#u={N(FXk9|4pA?EAU`;aP^ttfGni+988TjN4_?{c$zRw%L^o+12- z_%@xH(ZBAphKnL6yq3vAYyk+nFb)q7=d5)`xwjd5Y5=?mLUKpduDDIC^wIVuSz-=(Aq(BZG#$f&3Fy7!q zq4kb2W#3>R4-+JK;ddF^np&qbwkdo1to8`G4(zo^niwAj(|Pz@J-Tkgz%b{yXZ`8j zYE!-$h$k<#xAo)Cs_43VrY(4xwle#4T z0$g+YkcD58ioa5IpZl(Bx22M8A-fMa`@~a6%^#jxmsBn%71@q7qn`Ns_QY4!>6koO zIKNTq0jKTC0V~YuXUH?H_u6)kUoTg!Fo)Kn$J2!|9M4FJkJ~Eud!x0Di#0%knM1eF z*Chl8W>PO$s>O#T;O(^+IpBxuPH??FRD9sxm2*=vpq!`O+ACdcY01E{T!8Hq(;xZ&Qh!cAFOooxib^?o2iEw^SBD?tlq^D%Kk&c40731DmL=Ny<}K zS4pI9Wa9p=>6ZMeYaSgZJpAn#A9J;w-Uk5WaDJah?)M+UuAlSZuWq{+s%Al3RcIvnZ0umD$C6uWrbkGo55 z?cCLXDJ|#BY{dOT*}ODYHj`bfT?;%nqAw`!u{AeqS2riqXu7(9^D|A|T_xuvA1J`` zQd62@xr8HwNctS}_~x5)-Up9IV@;6(K@Z2v4q-QVr(<%%@gVMlue7G%m-5B>4&CO< zOWf0*MrTm`mAuuRrgxQ$5p=)PygBO3-l%l6S}_3I*6D2IkXZEfJ6%Fv_=%8>CQ@CD%(g}Ue0 zmAdI6mMI@BQ^e$-PvJvPLy@?Ko>M zCVXU}T=}IUZ%cmQd9qb&-wDDF9V)Zx*;gd(b0eDvyFszlccBxpSn(EZd`AA^M6)6X zr0u``AdJdLl!|dSHAC)p(gTKKw7RA9$uu+kiAL`&8`%xrKoGTsLFf3u(((90vC|)* z!xe%F4@K$jE0B2P#1=07WS8Iqj>6UGt#$Y03zY7)ItPxp5&v((im?zHpPDQBomW&$ zi{MWo242nI6&sfa1Ni+-X$JHc?wD(4-Rp~e72L-bBDf6s8M$J&NehLRaWh+tIL)n0 z#nPmJ^3G$eWJE{S-lnKj(zyd!)aFvTtQdBRM6rAjr>`*Hi@N@bBI+4Bo|1}sSpFUUs_Ga*OHK8 zBLnEij-}-{s;9bdC9p%1PdP{yCwgZ1=?oH;9BwRCZ<%h+&efG325$M!rlh&aPLF{2 zZ8eP53u{)o&gFhE)Mx9SMk4yz8K7i?Bbm3_oUTJ{3aKY6PEY``QA>5sxBi*1qN~ZN zzRjQJU4>}0fk3v<;P*66W}-{`vmeW?MkI!ql3(KzvYmy1UX+UwNv{tuSzfuF1-N-i!%tk zNDtn>%fYd)ryWh))%pDhW9yp*d5F5)^rW1cIunPEP(BIG=q?3MgAG2Bc$Pnc#Smfl7iXJl2y=?YjnhPIoEu z@ERVT?G%?H-HMs^Il-N3qo5>ju&GXJDmR+Gl&(&!-xn%Oa$Dr!(65@exXfw2-ik|l zfXsX^ZvPF5QXp;%&T{@mjR{x$co~#T^rq6FH0$sZqjzNJ`d57whhJ8`yG-?RL1A^) zUiE9qrnj#HZnr-kuDHdy1oZU299Dl!mT2Y`+n;gl=qJHfQXJcrIiQrYQV7)zWgCS# zxc}I>Sb+E7PA;Vwk7XcSz963I`I*U-Pa0QPpU2VJBmKJ{ z$RH>iTz8Xif5+XXd^wS9Js5Cl)mzKzd_|TV^8iV31^NWK>hv^BYp%>_ZZye0(a@c5Ql`A6bYit;+r!BlSBLruy&){Z{Bk6;V5rRNTA$XrGM@3rVO#z< zY_UUZHtcw;w&BdIw{+#EF8#UQ%!3=Ua}Z0fc&Z)MZ9~ZJfgl$ZpN8$;+B3drR_B!a zhx0dEU(AfEa{6cb`mB%71#Zdj_U4srDUTkT=3|qzU0fR64HvHQi}rE`pasn7TbNgx z9FEZyUt&|QG*N9)Fwr$Q=7qgz3OV1hJD()6h$yF}q{S8_HGXWY-1u$n|4w^xBFcnc zPpu$E=E6`%84H&Ne=|40qLT_=br zWqqoN)SAi9VK1B76B}$6v-FEqTR|%JPi<|uF`m$Xo`42Q>bxB7h-4DNeO%r5Rp$|x z%J8)#PVyys*uG)@FB)Ah2xRLWk~oU8vdUFbP72-tHIYYh73epk(yOIB7mW3{?1uV| zt$w7H9I7s1P$C|Mcgm7Z6C-HT7gQswwdYBPhu^KfBuFeTPn`_nTC$2URkdc@0$#m5U`C68H4YlsswxzQ4|( z`_NP`9*wQZ{jlkP0ieCr;(Vk}(+vuo?mwf`H?q3;nMBgrwrthZpVYJ1=4xqiFPcEr z+;kNqbNS8DuJ^L^Ugbs{aUs2QziJJ9mX^W%ZaUXxkSU!JdlqGfJ`1N_G>MRRUr3Nn zMTn!#6T5Zg<=kzr3|UuxsG->6RA?2mU=pQC88N*$eF%rtL<}~hFc{f+kLF?oa!qhx z?A}>c&nBnPjG3SP%3mh)uu8ZS%R@gSlZcvcAz}vbxzSJWCjpJ}rx+@QIM|A23U*oX zd0b>P~!}3GVJ1Jh;0{L!faD zkcL2TXbA2QXk3Fk1eeA&cyMW)#u^&_&ik&lzO}x+#(%Jn_Bo>lUG-GeQ};EmIX7#1 zuks6l(eKtnZ1Xid{LhR{D1e@aS#I2@UH>Q{I}CM?sU69d<$Kf%Cf9~+#E+CrXnyl& zzWnf#xbV3>j}N<&55wLOR<45coJi5K4m%T0>u_{TlR?4CFW;ugqy!xm=0#tLzE_?T zld%`_Q-r&@EAa-SV2leFVPm~P5>dgQiY+%|Vcbg0NiLhcr+RU{*c7q8yHQo;Yb}9y z4_n8pD?9Rd_16n=X5}rV&{PhNsG!G3BNs=h z>yqBKJ^20z(kbK7x|+OSy=85%6F_cF{ zR9n_+MeK9=Q9q zxIQcOGHAB86#7&z7TAa=f3eG|ahhk~`ck_fW29LuG3OifxemRX>)};v4l|n`Gv+xN z!;kfFZn4KqxtnE|zZr@Li%Cd|it9!v%n?b-LgBUx{+wwkz|B%+mEPTex`V;;Z9pi2 zul6M#3rn;9j0?~ADtVWZ@J|MMdJ8F@daCIew3*ug=}5+J*@#!~36n~i8kDzc7vy{A zs%!$b+G%WLxgaw#-)PUU<{NKnGt(+p2peWTm$!P=AI zBnRR{{8Y@|`PmrWs;Sxt?acjH--C09_5G=XJ<}<2(lT|yvT(USpF1x#1M5pqo8TI zU{dPj+1En&wcLb&-jC5Mnl3UUy92`=?tV7h$rK^f%AI*+_I_5>FmbY$Z)t4u(Y4@X ziN{Ne?<;ZxYAED5+sbRkjLc=(l?7a(x9V#2~`RhuI_BCyo)^F z9&5+G(`KfTx3RJvfmTR&2jbFUyExx>NOG2Z1FUkGX?Mm*wTMYCE<_)53PQnrzM=QD zjiAT2@g)_v`-sSm{Cp1~hwE#u6_$qIq`z0mF0QUNRitO{V&J}2A11)!5=in5^3aKE zaWTk5;nIbZSrZdzru{@PB(gXbFRCqKU=T0zf5KV4sl&QlJ;ep_#$PxVZGdMDOK zR`w!<*nvfm6Y$%=2BDymefF4xRwJ@5&r#!5hc==ew_-j7fi0R`Dt8tUJGUd&(MVgnIYj0><`puQ5?C{zvW@$ zgT)R`h*}=fPbhg;=U2a1%**3zMK;nB=^K2HY_Kti$m#NfkB>9GB$dmKMui+$ebe`i z1P}r1s0@BH#IY&UT#v=k!Rbn)V5n%u#O;Fu=7dFhn!8+X(B)0p1LzvcYyqs>Xkva>;O#Rc;hEF_E7kYfOiXNPC~}Wj@Gs8Ur8aXNbWc%d1039y@K9PEEkxN3@s+s|9^vmj2>Z1MHP*pLO>j^nM z#y0i&og==Em0dU3OPy3=W&)E~ZbZmPsBwkbx&LLTJrsUXZ}z=RY^%t~P@+ew(qf^ndFQl_(OqL0~93=0Ebu zZBJet2`l31Nx#c4bd4Tw5lWI*zpG^P*=(+!aWKgLwEkEL{ALe7ocN^i1qVk^ly?O~ zf=9dHn_4t;STTzcqI!{v=i_(E$ZWBjd0u-rf8h^?nUGP_Gq~V+b}Df9w}pZ&o96Ub z0W(1BlAiPu&_1PHmd~wlhE@(J9oM`{ILlI-q)cxIR zuRc|s^juWNj-ys$CgV&J4qi&L*dd)J!G5TtF9#&00QqUKP-A1H08a)m{6_F{Ro^>q zJ4@ER?!9dwVs-Tq-FZ;{-m?Ku{9kHd&J;zn!Zg@Xf+FfQSC86Pjz%6?soiL(_l`qr zMO+vH)YGp{Li{Q0!K5>{dLFEIrux6;ZD1a$M`FodkQkSUWFDRx4zC^(laiIpQuP|CKR#C^mVv#D@ww@S;@jePR|DY>-)$%@sh-K zGNMcNe|$m0AQ3fOYgOOWE9 zm`m+vB6+zY$?|4v|GO{tDo%N0Sc7+ggsJyZw z0fTUkl?*!dyRTn6Z+hAF*L^VqokQQQ))( z=l<_qTlqKKAltwsf$FDtUG*xH%%4tWAQ_h%Uez*0T)#W1A96bH)rYMbjlPUP|>TPGLxa929AyW5oFP9LOwxio8q~uA4g-;UklQo^?S*aIzCxSjNL{g z)2zBsy^@c0ngpV^eBxWZ(jk8E`1#!-W3yxi%*bQuYLC54j^llU!n1eTS z&3~7Fd$qNY zlYR@iy~?xMjSTq-X23~k(Jv?6B)tpds}JV?1O{KYtl~yR$JyUa+kSP-n)Mb`GneP! z%mz^?*IeYEuAI5m{j3u9{%vM))d`L$f^1uk;B89_K&2KYcW|Ev`8$-?>qy)OemQQ- zpNFq#OvquY#~0Y&Ulp2aXhQqeEYfChdQcy;n0&p3?cd}lE)Ny$U}9Q?lj=RVxNC_K z>$}kdYoYYcE-Hphqplcw%Lwmh61T?Q%hAj4*E*0sjzr6R3_z)s`@K49%G>ikbeo0~ zWHv?A>`p}b9;2%#Ew}&u!@MMTA(UnfjZ&wA^Q-a>Ej3pSFq$eLyy5Q=cbg zjV|)UKT@bC(kK7}K~{?0xi+|g_(;SsVjpAg;Z}rp+}UQ`OAivh-X}^XxZFl(%AqQk z)(ZG81LZslgNd!x{N{*P?!CD=8!rv+Q&fLJ2@#C8ob8Jj*^`O2F_?TZ6IlSlSJ*Tq z6kemI9YzbHuFI!Z(12-p03CicEgsdb%7dl56%zqieM&_;DS=>byL^1xCDg7tNyjFi zkw#zuT>!H{#fQZ$6>)ZuZb5Rf&C!anlWm>e@2Xhn4DxxwNizn=Kuz00SzcOmRQNRPrJ69a- zC)e-HQ>pPLr+FF7Oc}TEHSsri!1ueX?U<=FyVbsEcf%u_kTrvp1wrsm8I$6a=4tq1 zZki-zmX|*&PVKMgxff!ny-uMA^R=nSuSv^FOG(KVTJq84WQb)AaJs2#%@FvyQl^lQ zoll%Sgv&}xA0Fb_Y`-KACvuE{3Db5)`@y;g0*uiGQ>l|CqkI%INKS6~n>z6G4#Ehf zWmLj3um%0N=A4#mGnJDyBZGJMpz}U)5=B0QM(HitB6GJwVo9 zykjFiUhNpzU4I%0$oXw;^X=)6znsW&IuOpnnRf=vVoCw>J;@amV6qgT`1g)Yo=3(; zMzdMZQ1Py27~7w&9((vIZ`~lp4xv!;4F@%(l`fq;Yoo5J)uO4ySpZLLgbuWc2P2#7 zA%2#u}s~2KY*}!4U*;^84A=i#5cvs5n2K{cB!vwWYps z*~Q5%-zxjizl%JH)99g>&Q(7Hlo6N3$G9~=5ZD>KUtn>2A7o4QX3mtjDjHT-m7kj7FfTez$18sZSigF zYtL3w-Mmuk)oc?GzqYLy>EsIb)E8Bi@`v7}k2>%6jN{acK7JoU!`&gn07y=@I*8dP z4&(PQq!}wM>~dH|-s`^8Vr1J7)a$m`v>R6!qmIqwL<;X7vm5G8HxwxOV4%u@uDe9W#^th?hC#W zys%V*_X_&ps=P1Y9ZMLsTt-Xfv3Ql=vFbE5j3#pWUV_`3$#5`WnR1s3p;rPEnm>9` zX@M%O*}+5AYKbmqK#ERDSQ?I~tPOnUhC^uajC>fnaRy-wF<*CYF5q_ zh8X(^n3s-CW0;Yk4)`F*=lMfjac2>)u96-}0v##N2`cYh22PM=gov>rDAT?h$|X4p zO4rVBxhLBsK0h6*bbG-}gF4CVs%C*d3eMcwF< zvB}=wY&ZBTYHxOqws-rjMW4Svfde$SrX2&9o4@XW5#Aq1<1^)0m@X+GCGVR?%8k=X zmTTP=i|eeQL&DbU@e;mF# z98Vkwb)ABp-5wnJZ3!wR*V8Y~{8Vp3K<@JM+?8neLs9?j_XT!|U#?fnliKaI+!JNj zsa3rbEnkI1e}S3|JDhkI#{524GswqezB`XP*2oH!`wyt)>OEsnWa8j+(Bb_L zX4SQ``9W*hzl`E@qFheh!5S8@%3`+Teu zs@j}rELM>9^gT73&^o6aPNVfo3cIJbKJWgEN6E*y8InnRDH`1OY$WpZhpV^gSM#Wq z5`|>jA*~%h0o6ij=W_o8q?MrAPU-os-{q4yQXl=gaL~VTcYTVNbYMs!%_(MF$)IM= z<1voVa<)JjmH&&GUC+lhA@`CA=Bs-zjgB|Bs|&9Z&OA4YG~~TnuCA>W{-!Q*JM>OU z93I0lfwn>mS}VqPpia%s1+&hZ?8Zp0c61s1tr#4?9Mz?IM=_h78->Y^?jn4Kte!&S-OM0%B ztNqSpBi~TYn-qZ8cvoHaZj+*|31OP8PIjhfc)5vj*O6C70hv8m_|3MAK!kJ8Ca!ri zEgdbfl34?qyaC$c5uzz`Wq z^=^7=SEqvFB^gqBq;T+scqkptfv*O(o)qC$r(g!OaK@n;0N4?{5fI_DUFTDS53GcB z-Q&xN0DJ#@RidK5?@yyeVjpOsrkK&8e|y_G_N+zl=&I<^grd$XA}W#<5sCZjIbY zy2gqjIaL^s*+&PM4qTM24+({q7?C>{Qk4Nmd>mHZ8&wBV7pM6(oP%GDrzdd2jjuU| z2O;?*;W?vWGzSsoOZgU^PcnJ6iR_v3(YTElszk#FZ$Ay>OL3g|IwPAJI8ceM1^O^B zjfbT(id(x@LGC7ZODoc#b<>_qk1F^hgVV_tev!c}sglDmE)OMhl=v!)nKh^SB{iNT zaLZ>$F1bzH+sN;ml?}y@jm8t!gq(G;rEh7?K~JAupK3M^*K%EjH5B5Q0S-^HMyH%e zAIUr&`lL-O>L%D8mf4?8+EU9u^jNMmn^nGZ7+{bYnxPl1vpSgF8%Nn2xO1%{vFX2>Rw)XAJ8}ct z#k=B+?Ks#>f}$J^jT3>Mv%axUo>=iIp{e=s zVIa}&W@i{(10s`4Q5*3$!r1&L!f4I`w(nYmw6EbcMp6`~D9=3|@d1HKmm2+wA>u@p zKAcvFH=-i<;dQk}@u2GgX7QW&8U;qNV=$yoC89mDI9QNk!&<;nyq zNaw7YA-ad)!h3|YJ+RK5<`Sl6(h0AffO*U24F!ol?CcF7lN-=;hxY|63NFizJFwts z{UdB2Y*GmEGDmkte@<+!6#cwto7#|aR9<13N)1h8mv3{%6+#Ij)fkPRiOJM<=b$<8 zp4#tMt+;v=li^od;k`2olxWboorWrltF_%uOb!SD_d`btOqxjt^Gz*Za+Xer=_Or<}$OT_~u0%jM>eVcG{-kY*3%CgdVE!8Y%&j z#n^A4v^mRuGH_ zGF~P8)4Bs)bjlSk&)n%Azj8y8ipKQV%oQz>`+=J?Xg85HG#`DwV8d7arRA{c`@*uH zWd}pe8z25k?WaGV(^YrQY8etK3oiVm3Pa2ek?obznRy#9H0tLy;|wty?t7gM0;S8$ z4DEYrbDnJ{nin<4xGBHh=kgtJk|i_{A`E#ae4SS(op5@(XzK-Ap=snPCbSFrg@b&U zy|p(uFe1gKw>K}%v=DtVSWZp%ddQgc^;cF1*YHd2LC(WNFaS+aGaWo&lG6iPj8W8D&Zp;o`k#^{;0+umMAJ~kUf zFk5vAzQg?1)HFroBWsaXT{qH)^#> zo2=RZRh9H<_k_`Q_YOyra?vu6jIKZ(Hp9D~9Vz9w`Hr;4OzP6|*qykUW2E=w(6ZOR*0!u;3a$rMbZNTbXp##HRBsG`2w@YDJTKz%r*# zd=9_Y_G%%UF{T#Xr*=dbq}OpE-gxmb=ucg%V&In_vh)fxe5k5D2Bj6GuMG6~QICen zSm8&%BJ!>|Z(CPIr~e+ZN@ZI#uPMaJ+>fQ;`lg`NL#=8|R1HACBmTBradM`RK6+QL zU|!uKxYv_JsH4kJ|J%EwMxz9yzmnpGT{o|@<3}cMhy?>E0mEr+IVpQbZh~ci<7@$F zs#soZyx%_5`1-K4b|H~r`Ra@DwY{^knuY4l)SGriZ(SK=3(nsmFr`LS{##D(TxR zAt_gzzP-2QV5~Y0wXE29w)$m)-`2Y+LAx6B$gh zU2gQ_>#(oZ@)a~D>X&I0fBV zR|koWj^DmePD~i62mMFV=U>|8f$jI{m*358kWbr*3aSu?;E7V!n+;~@os(<;0u@O= z-ZS_W)Oz+OLj2!RBq!tbVpv^)(M%dJh5vf8`}kmzTR_kYGCtyS z+M)*;IwureUt^q{es-ZiRa>57p2*%>rr`HuioWd|(+Ng&gzb-!_IKO-GLe@aZyA-| z7sl#96CmkbS;t#5IA|4>(KLB0?hHjvn+#yQy2uNS+--lR zZ>6JMuExf8W;+{8TwzV2*kWrs0dhGR=%T=V>~_(ogz&D!YC=4699m;pu(qAUMct0? zu~D=~62GU9x9nXw7-;d@AyUonT|(~BQpzs@MRR@w75k9~dDL_Q@2pqhHWfk28h&jV zu6A8_EsULX_$z~pGd5DQ9c*4B{}Ua?zCHJl9w4c^CpVfoqqAXU$*|i-7!!=c(mhEPVwx z)ifAKb^Dsgi|KIpsgdDIgSr9jmUFH78zyTc@7Z}0M56CXCv4)Z>2Pot1Y|A#l~u6 z|6Z=9LLgMH6JE#q_}>H9Py_?#^;2nM2aJSpa*=pLWuZe3cZcq?^_@S8FdkcYWF|fV zx!c{=s9Seo3zhN+-8#fLS^g-N*n#?vjv;TGf@5BJx~E3dSt^j9N7mJk7RjMUic6zB z!T{^w;7jAEwhAtGd|g9EKs42R9VwD`L79g^0Xy{`pN0X+hQLL!1D$P4>FA>pU{M*IVA>y*EO z#Drkp4yvk~=+C(_QV#c42__?GT(f!cyI~t}E2Rv(hYSRSIz$}brqUtA13e{1^$WGf z?i4M2pU!2*J#J$IFXLF`ovd#^?gY;fdR%RcqLXt$9Gp zM5`^%y&x8GPY=JW_;PF3`BtCHy*=B3pJtZ#2Ob5mr++^9jY~7?UPG&0b8-PZ4Q{9r z35e3Z#U-g6%v>>4A6X;SsF;%aZXVy-+=FKYzM-d)b9cKE1?kA61NrYEAbNxQU6PqL zA_;ZAa>F>y$TR36SN)GQmj<%->KclhdnC)EzROmK!lt{GhuOQ;4r-sXcI9nY1pEzJ zpnO7AWyi1WdDI*20Xzrg_N~RL?MSF)o@_pgscE>E`O4jM-h!7>KhxWC0oVYRtqib| zB7S$pp@f5AdA(7NbzzjYc+gf-GPIPj)o?p^JWHYDSIRK5j66%Zm6>>qk`YwABmUC7 zyzyn8o4tkDiS$OEP%xo3Xio(MlBlOe?lon2Aq`*Y&%`(UKWa`f5&Si8?7L&f^LOvF z@(bHiy<+cVzw^<@pUZ1eNx$@-iUiJF`*voIyB#gJ(&kC1-EU`I{^cscx&NeWf~b~& zcKbr3{D0{u>+r#7#GhY>+Ra@4KQgwA^wEPda-Q{Mjj!Zh-TULRCk6vue|`+AZrE0H zY6YmykwQT*EBnU48T-M!48=Iw0;>9(8?_L=Uu$^4{ICxoMT$NS(fKj=1^>$Lx?*ohEXN%Z>ZPMc!d3s@O(eCE?_0o0@`TXRiYYB>lNE0RA$*jGfaXid|^i zGF5j57y-|W3d>Fpuo{gfGsycOg!EFbpR~FtB-#yO7SULcVs^9D7Tebg)GlQ&@w@_w#(19Jn5CuUNbdb5Y?;M1 zs8pU2m}_gPo}!tpT6mweOwBVj;A7X&2NQS-XI`jTLM`eMvqx;_@?*$$JsGv*fB;}GU?fLY&}+lC1OOs3~`6f^5-5B33MUl z;^~Yq6gb{XjUJgUYHFQqHdNf>;x7V-gY(VSiId4UBaym5TN>PwddqWoJ0`~UW z(q$4HqXfNP@thai`Kao=+Z|OQrZ7}8VHqaMmeKlo`B%hKY0g&bGX87;jUnf}20iL~ zGKtbFr3T=cM=#{#B>UMaC3d{?vut)n2^nBeQ{r#6M3_b4DdNUU@RUI^&5AuO@u|I0 zkUm@OYz#To%=eLskc?G0Jrv_iYIZa5T`xLJg_x#3yoy?S8+u4ju|+RIAtxg?ajCHH zpEsuJcXSbz)9!U_FPZ2=dv{NRq_rY_c|j{OEq}5DYFK$rK7B$0@^J?NCqYs>P1#sA zWZq4lZ+WF>rHJ=&5!UQwrQXFP#JbTJU9BS-UvYuj(KzxY_!EpNn)*};gO&iYugcqn zv)k7TOZP+WsqBtw4P~gVqmE!ioY`mKRFdalLX?GU$_jszN0-=|L5_Hi02|U{dV=QW zj9XyJb!NT{Pk*NX6)j8RPrq{JAzHsj1kXBDAQ|(P93qaIe?v#D)lQhUkH*|22G@H= z#SCndny&KfQ>OP;j9!!o|P-0Sf3(1ZJ^w|N6h#)x8P-@ZBC z)|(V>=a+*V9t(%yjMsW8<(cLLH9K)Bs}{jUgr$Q*KhD=jm4W4yV=0*)c9Qoe!};`j z-lmA;G;8w}%-v0BEbu>94$wSbKUu7Mpw=%_|*`biFg!?VQfC z&rk*Z1}9Kt09n1towjD!bQ&_38q`6RXmNoy04uiV;h5;h?!=u5NtPMSW@I}Bc8wng zhk7h-(@nE0TFIjO9TExhkOBcU@Go2EX3Ss`hlb_JyfkM&^7%z_{!DCuMXmmzJO7{*zAC4eT^$ zii0eT9b|&D69T72#~=L9oHC1Z8rV-}YwGg$L%_c8s7-51AmBaaaV3t{&Z$9}uS`>o z@rTTDhvpVNbJ!F@eAGYt21bHMbezp5QflJm5l>bY={_&#|4f`rNqXIO9*bz-3|l!^ zF_07fYIW}iIoua@qij`1vdm7nqMC|@xT4*gIJg_J<^JHxKqB)-rQ@B2FwlFh0^^PB zyXL99q17$jl6~r$(Jc2jHO|F`-f!4fT=w&c9!ksIL_1|7or<%-R?5x9 zmw(?CN*1pnzy}o<&wa~$Jzd4lqx**N)H3;J3>}-?s3Kx3)_-ft+pticUw=zPz$Mp8 zmW4_F+IDzG>bwkNSVL|ZuqHOBCsM|}`ITm&B1%vEXgbY0KdmnhA|!UrzFXY+dp`6~ zQfu}l^0tTLZgDni%6Z3&%Gi9$zX6F`hc`&;@^6w;p5R{ce{q~_%8%R_z?(wQu9=+! zc?5JOu*!V#<$1;I0E9P#srxk#0t)hxL-ml6%MNM{Ff~PCOy3;gr9Z)uhA+ZEO9+}Wg`pO?O1Nl8r z6ni}7jgmT)YfU49Rxu)Z@BX0Y#d);ZEuDFRw?=H>*OVTNrKi(8W@LKvXv|&?Eed%% z|E`ymTfOo;#&cGC*EzVjE|yia%Ks!1Bl)CM@$-&bThpc!J=zgNI?#HAnnLH~GqO)P zgVe}pM^_!(p$$0v&1Du`EXXIs5X1ij?HNm$Ln;5M0Xj!mU56d zmYCPsxo)l7-oc3znVX%5L4kIq{C}L9U^MRVwrDZ!Zrrxxp{vH#&9$qu*!YV}h*>`%WBweLOtss7azKZ1{7#QE9_i}7* zWr4T*lPpK$dO%ZUnSFnW0^^5oP*be>@sVD|ytk5uL&MaPq-9!KYt7)(-XXG+q)*+Q zT)$HaqoN;Fk@EV=xrMsxIV1&4%;ronlTvl|ZT(SxF#e_d49y2On(Vukz#$8GJs52( z-O0N#&^o+1XxhYJYJuPl_ORR?94cJ&vrD+bd~uJ(G30EQ_lLpcGs=9K@v;E*($7bh z(3Hx<+Fen~56yP;+w~e+u{lr3LdeZG{B=i1Ux%lrckkz*tHr#dQo(=SUub4wahq{a z*pE{W3DO~$`Z4z5K3mI+qPSwt^&q`pfk&mBV=4ijRE7@Fn$B?OFI`4?pe3N~G2iDA z9pt_2L8tqxNN}gtq)C*LFYJeIF9{dWtaK6#fxRMN3yIl6y4*-ZoBIkzbfs^d*xat7%ISGY zhNpbS>~9K!k3MybRvypqJqEXE?5~HJm+yvw7Uy&_k{%obBhPpDUqK)X3-*Kot z3i{|1UYPnz#741mo{JFiE>ER&830iJBH0FdIgbmnnawW zFW=wIz(?JOsaT{k6B1iwa~!1p9YhfGk8bJmA0OJ?mka1J_A{0wQ?j>4%wtoKnbPK? z`Au*eC^foRT$jqNhhWRK=U%4ZC_juTSJI>VBRO_8%l~Eoa2I?I=GfnWU$S5Ke>wylhRuu-mI5}~l0u+pr5NGqS1ZA9n z&f%BZFFf(L2R(h;obcnys>!$!}}?1>kBsqLgBxCKEiC+Ufng|YNX=g^3SXX02@_`@ZenSY&+3F*O-sdl?y4mm#S?f%NB;@p&UN09|fn5^+OL<;BdA zbcfy}4VI;!6D(HAoxVI9;*Td97}b_IdMMKgTp&lpjy zY^DvB=DcRy&$vdF5=n(M^C)}c6nrE6j_R*eWCMH4j0sR6F|C?2F>8j0YgYNUt!(im z%4|TsqQ$dLXGxT zvsoUNuVkv-X;_-)y}_-23ltjhd6{tCm=dkv8B+kj-dedLTX5a219@va3dLc%Eq#+K zrt_Xo7v+KV%(UyvEVG{aeww&s#!H7)$!DlRImp%y6 zVO|imTQ)!<$}%Fla58Vz7jopiyc}v<&W~ajiBWU%B<()fWHjEyHnK^*u&Gbj8#-U% z!4@CWAcbKZ-+43r(53CsX(yzvzWz1LBcHRCZpCb)&&AUFW^eG+R2Y$f*{# zmU4g*Yk#aE6yWmGdNSkeI*%>TCz||oQ9uLO)ArT<=du7ds-QrILsjc8WX5ik#9y$g z$5ghXvu^y8tl`qeI(PToAr7Ec*N*(R1Ju>&$2XlMShJv(qxf#Y#|A1^Ai636V*)OA z_P6lK(K@h8zeBnRsMa~MB#A5QqsQb#)!Iz&PxseN0+VQclb6_0;Z-e`mCRF~xj&1!ZN~!?y`jSDS;ZkhHDidkoaMSW6cpY%3p$j*UT`b>3f@zq$9H*}P2YwPjGYm> zq(4h6!Fi!*pP8qbo-}!w`h^sc1X&5st6H-tS(CyuU$>HpBEoyUy?q3zcj;MWg_u>9 zL|SpZH{%zHoE`I;#0LOIc0yS7wUpP?)Ve3aVsOppxJ~vtSEYtIf)~Jn?lV(U9>Mni z1#mfpn8;{JO*<6TwUapB;@m5_+!)W&CoPJxXbfzEgG2HKNQ3JY7&g|Z#I_R`P5e+Y zMPs`7i*6b?Dj`sTu2JY|}q|s$m4#_j$g>MP*1BI&&hg(~xRTG`> zmLDpQbav$Ow$C>pY;{zF@#MUvXQ$N##op*AL{SBlM7>O@;SEMz{`lCTsq`e1h){GY zW%7-+yRRXZ+V7y97M-PmRAHa|!W%#d?z&2zSQ)_|M>7_qyf}7+pY91@$gHFqGKa5i zWQ0K4KCx)hD=amcAiLG(z+;kmDie&U(cao$SWqtpB$Fqo z!KOM_4Df&Q&`gL_=YCr|aw}cHV=b_<>udbMFX<9UF_z!w<3(hf?2#ui34oI*hB5S~ z9Oyi>iRy&xsYg5lh=Sw%|87q_<^6{}v8Q1CLXqWv#1SHvc4Bp5(HJ0tF=}_=)dMPN}N1Y&TBOsXt9f4LLfoTQX$kPfhb1 zTB5kbE5`8XrUMkwrFhLp7tEj2u#T#I1ZHX%WcJp&y%9;)G;D)hS5_BQ<#*>>oDbkmxsD9IMb4QS~Gq&S!8P=@l)D3 z%nGb?ce-?w1Rwx-hW;GRNHQvHlo)dP@wGXxI9L5%D}XUBagUr=n^YvtCpXDxb8`{C zI00WYDGiaePZ8!Fx`@q1vVThqBd7<}pt6ykUiPsw+=e%UzT z7a-q?{r(edR~zx*T-cYuD$UPw6FU@wT%BxZPG^(i`;RR0(N0Nvykd(Jv>X2=&w|kMplLXqGj^xu?%|7x_pxvQSPonrd>7z zyut7zXblN(`;5v01J1aC#u8~Lrx!LPqm=!+t4tHM@w5obFzzmB=b2fWsc)ZH@Qri; zAH@04c=@54y{ReiRj8NVT>b8u0dWD=`JDIO=nZyE_DEgo!9*4+D=NlBi&TU|-*}@v z>bx1ca(G=UMgt&iH3Y)viWAuBxv4vu7R5MOL=NgpPy=*7Sq3Ium*LT2IxKzP0U`cR z>NhUr8N`3S(0$A@X$890nA%J)0V^*<(x>ZRa(fD-+!bxFVdn>xWz;zoT;F|7;Ui|K z57pCc9y>lTX9Iad4^6;$4K!1HVEL zhv0p1`uZD=C7#^Sd1+x1no)d$ z;ww>qyhr?bE89sVqLVWT6}>|4q|GNP;H30s+HG`;fDEtPgTZ&M9qiU<=SsNGI10c!oLIR`>I3tmu|r(C1%E!-%#I@;60-kb5aB2k*qlc*Qy#f_TA1-8r# zO!j1ernoFW$&*{WbvZ2;Td!uIs1I$BAk)akUAZwk$LAaF;Q%^E?s+ejOgnVwP?nK{MVZxMJ$wv-002HBH1=aPVDX|BU$L61DsdbjGb3%={? zlvGQn46*KK*q7{IS*H$)*TAzp_A?yxqh%* zpC*vZc$nem(_>kEzT9@6Jr;Vn1evD>s0;C1^=bs*bIx z?MbB)Fw}f~J~@cQV#?$LsvEK=ZMda;Y+U-cY9~a^tOU=f+CN}1D<71BCeq46(b_w? zBAfOMYEL0(uSe48WI>J8^LTfnT7`Hw9;sy_A3B;QoJAVpn1nltCnGB>6c@rAhM~vJ zDTVwQb{jy+#utPFunw{RLtvj5G5jZig$u-;M)3<|MMis@F)nrdgTVH}U1?^N}4u7<-b9o(iAM$yJ7 z2nZURRdQ=vdi7N};miQia7Taxj5}b!-Hf@EAFxzQWs|e1CSEa$rS9iIFNfUR=JFJx z-nubaN|Xw0ziSW#u23LWKLKYLp;FsN!niZ^@{Sbxa9s>{t@Ht8hOyIZ-DrA!%UqQy zPwQ{=p3;Fpbly5}Z*i=Q@|U@c*d|(lhD{!0e|9-)l+@xVgQXV?Nca52XV*&%(Vy_i z>3-P&OomaMeS5iIqgnA57Ns{foufEKj|vhu$?DBC&XkO$!_rnJuVK-`*0ZTJ0O+zF zDF-O5sYl@-Y+u#klf8G;^SbVjG8CcL2v5L2J*O$sVS7|@o~5%?JimbKDAVsZZhy9> z@_M+vOR8$6XZWGw^NO=bE{uG5oec7(B-0*zFut%8tBP zNnhf_BNpzvB~HAgXdQ0?h;bW{XiO*KT3>%*D$$ACmtYv5uqr7qOnOR%oiX_%~o3 z6~W}){Wr0`_Q&)nzZ})8->Q!Cl={Bb1Qz<`bG?#dH&sDV%I?*#fQclS9o)EEZZQRK ztZ5lx=GepahV9qywiD}zK*IOnZuP-w=xhud(@10g@BO$n^gsvAX)snFn+yfC z?ru_t`9*E9vPc=BQxdEimCa$cm107+?}8B&4#TQ`C#sAU zptk;aNTI!5e>!gbEr+Iand0G5Frn1KPW6<%B-*+EX}x*pHwjQqg=5o5t^2)d&qw== z=pVs8fdeltpQF~Cx*pNEUvuUojsRO^)hah{;L>x}rCT=CHW! z!zfaB7FQmjk*kfp*4z=t2gs?teu9XVk#1Et`@I;mhL!Wj4pKNp-{>mVMehMk1i{wze&R| zeqp8F!9d7A7r8PQekh$Nk}@n>OgE3JBY5z@;9qSSS&0tB4LiE)FF@_*!!~BVn*U#W z*BR8*x9w3BRGNzPrqToj1O%jsbO=p)2kAoSy$K>9(xvxMLkYcwUZsZKf^?;mAcz4W zp}heAcgveQ@7tX_Z|3FGo}829?6cQC*?X;DaZ}c7EDYNvyH9qwV-*5bI#`Jd`3K&P zqKx3pArOPGm0uo(@qm!93SXFn7IOk00Qk3>^gfwr@=$BhUq7{PjHP7t{t`7?(xqEd zwr6r!_+xJxph!CPOE!p0uhP-G4|uNQi%g)SI`z0K^ABvE+yZKYLpz~cFUk`kjFR1U zDa|9~YKK*q&cmY{Z-XjA-bCHw8leTcA-nR4Xf8^esoUPOvOodfL`IkB6aoD{WHXk+ zvxzj3-O?!l6+KY-j^uD%-ja*(hAiCzm67p^&otfR3OJe{QRXhtFiT&NugbB$V-TLo_@&ouh*yJ<%k#8)703(hz zK5Z9Kgwy_Eug|gL-FPM%9oeYm8Yp5r`MK}sQVBKV*~W>$a<`#O{WeQ;t%H92{wOTT zW3~UPkXZ-`%C%UGW0bWin~Wm^`_@_lbCQXJ_f^1qqWKp^)d4062q)bFx<5o-duqW%W^U)g(oN5+H)@%%Dgw`oJv^3anD^IYzYnwYVl zuHQQj(+=JHGUX&h4ak3MIbh!-43E5>T8-h0@pJ*0Ad`&Sxnu|xe#&p7`FBgXW(TK8cVsvfIl=JH-K4tc3%Rw$F>f>?zX zJqWx%VKlq-sjC0&ke))7;!H#PoVKpfQ2i9m5?sss_PCJ)P5lFMZ18=s!veMmU546Z zawdhfo4yyYpSINTvl?iRWd5@V5@2aESL^Tm2^@sW$v^Waq=$fB`dIG?j{&Oib*-DNpy<*t@Is+(IA60G(-7ATLL;yd_@ zN09={>T;b5UbN-WtA@uaB6uFpmch0`SiPsHaRueEq*;1vEEfaLezhH=bQO)2im@H-3Sw=LRnt3v_N8!xU>u@m!pou* zsT#k=9Bz@_%6QY=Aja~Byq=Z;yv2#$dS(jF_oSGq4)VD!feck(mI%{Dqrv^OpDCBMFL_|#7v^d-y9K6g( zyDE}d6@+ehS?3E8P{k*gH9jdBi({7o!i{1x7!>ErVEYLm%`nj9t1Rf{e-SR>^-hp@ zrticfn9fq+=)I!Y&Zw23_@U&`v*A^E=u(+h488c)NtQeT_iH3pN1VfAmQjohyxg4b zo;0#PnyZcl>|1pION_oYk$oH@?5HYgKcj{Xw+KYHENwXJ+}`%va6p`zEbcgK(}ybg-vzuW`a=xO#kD z_Y64l%#XA=Lpe!+#D6b1JDc%|T0YR`P5l?1X+;h)8cyz0w`|_DW%@#b6~G8QVc&V~ zqK7z8@z>wXV9NdnJFljHqP{Mk^oa5E@-d=p5;8nCgFe5xCJj&*uvNNSN5Z|`xi|xb z*&9QoOpp}3y!M2GO)mcI?-L!09U$A7A0#Bl4w-F^BLZi)LubGrv$jYB(=BEgcI4jl z;y@#?LJO8GSZF(;alI3_+kX0>*K+d{tCV*>vlczTQI-EiBIFnx^G^WvyN1tya^+4n zNI3m2*!wYORXVHuiB7~&>2_egO5`sd2LZmz1j1yT0QJvi){!(mh#f)@k2$}XlhC{x zAJLgSek>HSsbHs4L$sLOjeUaCvdq?+9Q?R$pnoC2-j0WzP;Zph%lJ^;sKnuDO49pC zvK(~T9z3|~XrxuKZ|lgmUq-cajD5GBC@ppA?wj~}bc=hz_r?O4i+icA8gx6O``$#- zjj>GdU-Ao21RkegGr4pOw+54jK()5p&vN`!zE(yrg}2R`X_K;tMce5~KA@TIc{Wd( zdnUmyztqI5%A_8fz8aJsJWE~IpNdL^?!)f%Ct8i!tkl4L+jA`R-fW6z#7eeryv zdpa8mFKU9mUvFL;N-Ub%pCk>_jngORH!#H@CF($h1RN<-n%*4Zh7M37z)<=~ujAv3 z;Rk*f4QdIjx_4`#5b|`ninCyagKPiT^Nc1G9ABJN&SMuGY8jId!_y+Fu+J!?w8w0%A91-e14M5sSaeKC{MH= zih|!a)0xE_NEy0jm+sR`&3&H{R2{FPo(EolSle$bO5PHBve}o{^UI*hbj+bUUs1Dg zwJW6rK4V@c^6;98q$IAi)8)DYrybW^S@qH$1&fV_PwT2uY`Jv=UM2PaysX-gbEwGxkdfa%A<*mPtJ+!qeO-t4A z*j;44Jifcoq-|gz;#onK6fS%Lf5-B@r^m8G63EVbB9U1A1=g(%yiOo1H8nNNVZqsz zHZ1v4tslpmjLwzNrKSM)OHYr?_<0HulwJnYhQTz7?Jm%)zu3O_Tkh+JLdwf)-2|3| z5Yh`x{?XFaRZ`-kx_jkXb4N&r;njSCg6hEmQ6y31{`o?aNAy+al3`fCo6dBey61H@ zw0ZArpK-Qks}=RV=FYm_X^DmE1EqgNUd6#E(Vbw4GF5F>2Fj#RXzwH3D2Xw-bDHO7 z^;h52V*XG><8se|B}`!@CNAIozaKpRCPM=!IWd9puNhajPJ~dqj6CM71RJNPEmw05 zhn^hkF?D&kUF{Mik8SJxn=a-*3YA~}D^gwsY|#EWtZ$1#In`y$DIwO^nue$EZz|#X z1bs0xu>)rFt*;#`f!bCD9iDc6sYD&(h2IgH0S1K@jk)Bdf%>)f2R z-gTGGM5jd4ivqrT!|yYn(b-uKn*Lc?Z#}9}__-_V?vFWJkB$mo%hNBB)1h~I;|i)qjGvXN-`}*rMQ`i5VbSXlAj#42@y5`-=lY+JJWdNy(yug7tcM)< zrjzHTf~d3K(bd4I=@>kv4DPieoB&*HKVC6mbT6aW+BAC_1z{?;1E8Y3Jy_Ppo*X20 za2gOK;T;R!4cF)It$$JO&`}UVUU;q_U$LH1PLLpyNwH+ShC2S_(Hd7c-GTDmJ9R5% z;CN4NYp@RbgEhEa9^8EE0s3v}2m2u^JFH=|KA946X8Zj{5ILL^o{p7Om^uu}(;&O4 zONL2W*7-(UTcx<& z;*(!P{&sp2F=94t$2~-MF|GDFV2wE^C~4Otro)t?2hR=iAN%Yk0)S!2->&nt9{mBQ zY|O4%%;lp7JT_aX!@49frQa%aOZrS6zanp)AM*gw!otd$>o&Qw%eFo2%Eweaf$(cAOJSu0#$##hUO`u=y0N&yX7IH^KQLL#BSG({zG!TT%J2OJjwL z2h1%h(LBDswZaxM!GPcPQm2qgvc@s9>Yd-~nab$s2hkcyMzE+rT{3b*UN>={Yy3&F z8)M?4@Mk1el>Tn;cUOizBt%e!5LGk(Aj(ABU(Ft
~KIALZjQyrYkzS#s!!_4>0h=@cVmS*d09{)@EyxVG`ZVe3TQTu2c7+Q?AKvJn~;@Rdp$ z(RITI@);)d_IElPh{M=99hCgypuvl)&)x66cpP5B>XPyHGbYCK-}6f!SqB|k{-9dv zsQCD=#fE+)RF7eKN)6=_Vsg@n~AbD{TyXZd*opM^W*os zDs!FlHWDQwfw(0O8}v_0SjfG3rE4g%Sd@{mdVyZsZ-(`p50R~WGZ{9QPxEi>;~f(V z9UT@IKH<<~sKjQwLUBo{Xr^PcsXwHC9~JzeQGtM^^*TmDfh7 zGkP|V;}TlX+`<}tht|Cz-N?!b&ehO8#UAU1m|R(OxpA|=kFD8I#Xj>@0@)@N!qiNB z@>=#mAC9(Kx+~a1q)Gu6Y!7Wnz_v8Z%_ZF4R>8Q0^TAJl zf5U2DVDI>*)Au?r%=+ z{<*cr65zp8lb0w?PgHi1io(&6*JWgjQ5P`^Jvu~fZ24~h>aUH(T;rFLf41=TaS&{u zi+>lx$#Hy$LJNd4PaRa|KhU1bRc139m^Q!+Zs>?Gx6HSf#8;Jvus-SaEU=hprVpT|zZ{X2`lTwfTz80NWRvWvZy!xYA&N9-H0L zbq%5f51MDT8Mb(#J7Ol_fu!_~KYs#0m*~M92gA*fTN^p-XWEs6tML=5`%IEru0q9w zyId;0vvc1TF}oc(#56YJiA6j4m)-hs&q7{nJY}EaTQxU<3ZF3a-S<^{5=K+}cE(-sIbHn@B}?Io7Oqcg zF9sinaB6LLsWQCoB%xq~(@Rg)1?4+i&=h@MM%)!IU9`kN(_*tYzqWF#s9*G~yQxTZ zfLtjoEjF!9ffrX5pw=eLSjfRmN#_ z&*fiDJ0}$abkz;)$zJ-0dfzE(a6Ne)D@XUo(bn+v1mx)aOj)JP3kfUQCD9wqxQA)> zDD+0h5}YSM%(azI9lx9}Zzpo~8#;|ovr0`N@aHIds4!CP6`ww;cdJdPFA4?zF@HBn zewMD!->L4~D3@GB*6<5NLMr!6JVJ2jpdF|x5 zJmXCYh;RtfWC>|1x?DSzL^#ytJ}ZnZ( Date: Fri, 17 Jul 2026 15:44:55 +0200 Subject: [PATCH 6/7] fix: address review findings in release-infographic renderer --- .claude/skills/release-infographic/render.mjs | 10 +++++-- .../release-infographic/render.test.mjs | 26 +++++++++++++++++++ .../skills/release-infographic/template.html | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/.claude/skills/release-infographic/render.mjs b/.claude/skills/release-infographic/render.mjs index b9964df..5911c1a 100644 --- a/.claude/skills/release-infographic/render.mjs +++ b/.claude/skills/release-infographic/render.mjs @@ -3,7 +3,8 @@ // node render.mjs [width] // // Rendering is done by a headless browser so the mint-branded HTML (exact -// brand tokens + accurate technical text) is reproduced pixel-perfect. The +// brand tokens + accurate technical text) renders faithfully. Fonts load from +// Google Fonts over the network; offline runs fall back to system fonts. The // `launch` parameter is injectable so unit tests run without a real browser. import { readFileSync, writeFileSync } from 'node:fs' @@ -27,7 +28,7 @@ export async function renderHtmlToPng({ try { const page = await browser.newPage() // Height is a seed; fullPage screenshot captures the real content height. - page.setViewportSize({ width, height: 100 }) + await page.setViewportSize({ width, height: 100 }) const html = readFileSync(htmlPath, 'utf8') await page.setContent(html, { waitUntil: 'networkidle' }) const buffer = await page.screenshot({ fullPage: true, type: 'png' }) @@ -46,6 +47,11 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) { process.exit(1) } const width = widthArg ? Number(widthArg) : 1200 + if (Number.isNaN(width) || width <= 0) { + console.error('Usage: node render.mjs [width]') + console.error(`Invalid width: ${widthArg}`) + process.exit(1) + } renderHtmlToPng({ htmlPath, outPath, width }) .then((p) => console.log(`Wrote ${p}`)) .catch((err) => { diff --git a/.claude/skills/release-infographic/render.test.mjs b/.claude/skills/release-infographic/render.test.mjs index 0272854..17e7646 100644 --- a/.claude/skills/release-infographic/render.test.mjs +++ b/.claude/skills/release-infographic/render.test.mjs @@ -77,4 +77,30 @@ describe('renderHtmlToPng', () => { expect(calls.viewport.width).toBe(1200) }) + + it('closes the browser even when screenshot fails', async () => { + const htmlPath = join(dir, 'in.html') + const outPath = join(dir, 'out.png') + writeFileSync(htmlPath, '') + let closed = false + const browser = { + async newPage() { + return { + setViewportSize() {}, + async setContent() {}, + async screenshot() { + throw new Error('boom') + }, + } + }, + async close() { + closed = true + }, + } + + await expect( + renderHtmlToPng({ htmlPath, outPath, launch: async () => browser }) + ).rejects.toThrow('boom') + expect(closed).toBe(true) + }) }) diff --git a/.claude/skills/release-infographic/template.html b/.claude/skills/release-infographic/template.html index 7b7beaa..3b27070 100644 --- a/.claude/skills/release-infographic/template.html +++ b/.claude/skills/release-infographic/template.html @@ -26,7 +26,7 @@ padding: 0; } body { - width: 1200px; + width: 100%; background: var(--bg); color: var(--text); font-family: var(--font); From b9fd33067e97ac343d31ec8ee014bd675c735024 Mon Sep 17 00:00:00 2001 From: Nadia Nujovich Date: Mon, 20 Jul 2026 17:43:15 +0200 Subject: [PATCH 7/7] ci: exclude generated release-assets from prettier check --- .prettierignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.prettierignore b/.prettierignore index d838da9..980ad78 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,4 @@ examples/ + +# Generated release infographic artifacts (HTML records + rendered PNGs) +release-assets/