From 3026370ff79f8754ca1a1ede96445e4c23b63d65 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Thu, 13 Aug 2026 16:49:53 -0400 Subject: [PATCH 1/4] Dress Klokkentales dubs in pop chrome, invite collaborators reel-chrome.mjs takes an English-dubbed laerklokken reel and gives it the side-stamp treatment: pals stamps + laklok columns hugging the edges, a drippy melt-feedback layer under chroma fringe and scanlines, and karaoke subtitles that tint the word being spoken. Word timings come from scribe, so the highlight lands on the syllable rather than the line. This machine's ffmpeg carries no libass, so the type is composited through canvas rather than burned by a subtitle filter. The haze layers were eating the blacks, hence the eq+unsharp pass on the way into x264. ig.mjs post gains --collaborators: the invite has to ride along with the container, and for a dub it doubles as the speaker's sign-off. --- marketing/klokkentales/bin/reel-chrome.mjs | 466 +++++++++++++++++++++ toolchain/instagram/ig.mjs | 23 +- 2 files changed, 486 insertions(+), 3 deletions(-) create mode 100644 marketing/klokkentales/bin/reel-chrome.mjs diff --git a/marketing/klokkentales/bin/reel-chrome.mjs b/marketing/klokkentales/bin/reel-chrome.mjs new file mode 100644 index 0000000000..9e1b7309b2 --- /dev/null +++ b/marketing/klokkentales/bin/reel-chrome.mjs @@ -0,0 +1,466 @@ +#!/usr/bin/env node +// reel-chrome.mjs — dress a dubbed Klokkentales reel in AC's pop chrome: +// two pals watermarks hugging the edges (VHS chroma ghosts, pulsing with the +// speech envelope), a drippy melt-feedback layer + chroma fringe + scanlines +// over the footage, and karaoke subtitles in YWFT where the word being spoken +// pops lime-green. Ported from marketing/kidlisp-reels/bin/render-reel.mjs / +// pop/menuband/bin/chrome-reel.mjs. +// +// Inputs (in --dir): reel-en-dub.mp4, dub-audio.mp3, words-en.json +// Output: /-chrome.mp4 (voice + --music bed mixed under it) +// +// Usage: +// node marketing/klokkentales/bin/reel-chrome.mjs \ +// --dir marketing/klokkentales/out/reels/1000-lyttere \ +// --music pop/marimba/out/marimbaba.mp3 --name 1000-lyttere + +import { spawn, spawnSync } from "node:child_process"; +import { readFileSync, existsSync, mkdirSync } from "node:fs"; +import { resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { once } from "node:events"; +import { createCanvas, loadImage } from "canvas"; +import { + decodeAudioMono, computeRmsEnvelope, + magickMeasureWidth, magickRenderText, + setPreviewFont, prerenderTitleChars, +} from "../../../pop/lib/preview-shared.mjs"; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const REPO = resolve(HERE, "..", "..", ".."); + +const argv = process.argv.slice(2); +const flags = {}; +for (let i = 0; i < argv.length; i++) { + if (argv[i].startsWith("--")) { flags[argv[i].slice(2)] = argv[i + 1]; i++; } +} +const DIR = resolve(flags.dir || "."); +const NAME = flags.name || "reel"; +const MUSIC = flags.music ? resolve(flags.music) : null; +const MUSIC_VOL = parseFloat(flags["music-vol"] || "0.15"); + +const VIDEO = `${DIR}/reel-en-dub.mp4`; +const VOICE = `${DIR}/dub-audio.mp3`; +const WORDS_JSON = `${DIR}/words-en.json`; +const OUTFILE = `${DIR}/${NAME}-chrome.mp4`; +const assetsDir = `${DIR}/chrome-assets`; +mkdirSync(assetsDir, { recursive: true }); + +// ── source probe ───────────────────────────────────────────────────────────── +function probe(args) { + const r = spawnSync("ffprobe", ["-v", "error", ...args], { encoding: "utf8" }); + return r.stdout.trim(); +} +const [SRC_W, SRC_H] = probe(["-select_streams", "v", "-show_entries", + "stream=width,height", "-of", "csv=p=0", VIDEO]).split(",").map(Number); +const DUR = parseFloat(probe(["-show_entries", "format=duration", "-of", + "default=noprint_wrappers=1:nokey=1", VIDEO])); +const FPS = 30; +const FRAMES = Math.round(DUR * FPS); +const W = 1080, H = 1920; + +// ── karaoke lines from word timestamps ─────────────────────────────────────── +// Greedy-wrap words into short lines, pair lines into 2-line blocks. The block +// on screen follows the voice; the word being spoken tints lime + pops. +// MacPal's playful register: Comic Sans MS Bold for subs + the laklok columns +// (same face MacPal titles and the macneopolitan visuals use). +setPreviewFont("/System/Library/Fonts/Supplemental/Comic Sans MS Bold.ttf"); + +const PT = 58; +const MAX_LINE_W = 680; +const SPACE_W = Math.round(PT * 0.34); +const rawWords = JSON.parse(readFileSync(WORDS_JSON, "utf8")).words + .filter((w) => w.type === "word"); + +const widthCache = new Map(); +function wordWidth(text) { + if (!widthCache.has(text)) widthCache.set(text, magickMeasureWidth(text, PT)); + return widthCache.get(text); +} + +const lines = []; +{ + let line = null; + for (const w of rawWords) { + const ww = wordWidth(w.text); + const gap = line ? w.start - line.words[line.words.length - 1].end : 0; + if (!line || line.w + SPACE_W + ww > MAX_LINE_W || gap > 0.7 || line.words.length >= 5) { + line = { words: [], w: -SPACE_W }; + lines.push(line); + } + line.words.push(w); + line.w += SPACE_W + ww; + } +} +const blocks = []; +for (let i = 0; i < lines.length; i += 2) { + const pair = lines.slice(i, i + 2); + blocks.push({ + lines: pair, + t0: pair[0].words[0].start, + t1: pair[pair.length - 1].words[pair[pair.length - 1].words.length - 1].end, + }); +} +for (let i = 0; i < blocks.length; i++) { + blocks[i].show = Math.max(0, blocks[i].t0 - 0.15); + blocks[i].hide = i + 1 < blocks.length + ? Math.min(blocks[i].t1 + 0.6, blocks[i + 1].t0 - 0.04) + : Math.min(DUR, blocks[i].t1 + 0.8); +} +console.log(`▸ ${rawWords.length} words → ${lines.length} lines → ${blocks.length} blocks`); + +// ── prerender word glyphs (YWFT, white; tinted per frame) ──────────────────── +// three variants per word — MacPal comic treatment: white/ink-stroked for +// inactive, lime/ink-stroked for the word being spoken, plain for ghost splits. +const LIME = "#B4F046", INK = "rgb(18,18,18)"; +const wordImgs = new Map(); +for (const w of rawWords) { + if (wordImgs.has(w.text)) continue; + const safe = w.text.replace(/[^a-z0-9]/gi, "_") + "_" + wordImgs.size; + wordImgs.set(w.text, { + plain: await magickRenderText(w.text, { + ptSize: PT, fill: "#FFFFFF", outPath: `${assetsDir}/w_${safe}.png`, + }), + stroked: await magickRenderText(w.text, { + ptSize: PT, fill: "#FFFFFF", stroke: INK, strokeWidth: 3, + outPath: `${assetsDir}/ws_${safe}.png`, + }), + lime: await magickRenderText(w.text, { + ptSize: PT, fill: LIME, stroke: INK, strokeWidth: 3, + outPath: `${assetsDir}/wl_${safe}.png`, + }), + }); +} +rawWords.forEach((w, i) => { w.idx = i; }); + +// MacPal's per-glyph jitter (PalCore.swift): deterministic tiny dy + rotation, +// scaled up per word for reel distance. +function jitter(i) { + let h = 2166136261 >>> 0; + for (const b of Buffer.from("word" + i)) { h = (h ^ b) >>> 0; h = Math.imul(h, 16777619) >>> 0; } + const dy = ((h % 7) / 2 - 1.5) * 2; + const rot = ((((h >>> 8) % 9)) - 4) * 0.6 * Math.PI / 180; + return { dy, rot }; +} +console.log(`▸ ${wordImgs.size} distinct word glyphs prerendered`); + +// ── pals watermark raster ──────────────────────────────────────────────────── +const PALS_S = 150, PALS_EDGE_X = 105; +const LEFT_PALS_CY = H * 0.14, RIGHT_PALS_CY = H * 0.86; +const PALS_SPEED = 0.18; +let palsImg = null, palsBlur = null; +{ + const svg = `${REPO}/system/public/purple-pals.svg`; + const png = `${assetsDir}/pals-watermark.png`; + const blurPng = `${assetsDir}/pals-watermark-blur.png`; + const r = spawnSync("rsvg-convert", ["-w", "424", "-h", "424", "-o", png, svg]); + if (r.status === 0 && existsSync(png)) { + palsImg = await loadImage(png); + const rb = spawnSync("magick", [png, "-channel", "A", "-blur", "0x1.5", "+channel", blurPng]); + palsBlur = (rb.status === 0 && existsSync(blurPng)) ? await loadImage(blurPng) : palsImg; + } +} +if (!palsImg) throw new Error("pals watermark failed to rasterize (need rsvg-convert)"); + +// 'laklok' climbing char columns next to each stamp, like the kidlisp reels' +// $code columns — set in YWFT (the brand face), NOT the comic subtitle face. +const TITLE = "laklok"; +setPreviewFont("ywft"); +const { chars: titleChars, totalWidth: titleTotalW } = await prerenderTitleChars({ + text: TITLE, ptSize: 72, palette: ["#FFFFFF"], shadowColor: null, assetsDir, +}); +setPreviewFont("/System/Library/Fonts/Supplemental/Comic Sans MS Bold.ttf"); +const CHAR_SCALE = 0.8, KERN = 2, CHAR_BUF = 34; +const CHAR_SPAN = (titleTotalW + (titleChars.length - 1) * KERN) * CHAR_SCALE; +const CHARS_EDGE_X = PALS_EDGE_X + 6; + + +// ── speech envelope drives the pals pulse ──────────────────────────────────── +const { audio, sr } = decodeAudioMono(VOICE); +const env = computeRmsEnvelope(audio, sr, FPS, DUR); + +// ── canvases ───────────────────────────────────────────────────────────────── +const canvas = createCanvas(W, H); +const ctx = canvas.getContext("2d"); +const stage = createCanvas(W, H); // current video frame at reel size +const stageCtx = stage.getContext("2d"); +const tintCanvas = createCanvas(W, H); // full-frame chroma-fringe tints +const tintCtx = tintCanvas.getContext("2d"); +const dripA = createCanvas(W, H), dripB = createCanvas(W, H); +let dripFront = dripA, dripBack = dripB; +const wmCanvas = createCanvas(8, 8); +const wmCtx = wmCanvas.getContext("2d"); +const glyphTint = createCanvas(2, 2); +const glyphTintCtx = glyphTint.getContext("2d"); + +// scanlines pattern (1px dark line every 4px) +const scan = createCanvas(W, H + 8); +{ + const sctx = scan.getContext("2d"); + sctx.fillStyle = "rgba(0,0,0,1)"; + for (let y = 0; y < H + 8; y += 4) sctx.fillRect(0, y, W, 1); +} +// vignette so the subs + stamps pop +const vig = createCanvas(W, H); +{ + const vctx = vig.getContext("2d"); + const g = vctx.createRadialGradient(W / 2, H / 2, H * 0.32, W / 2, H / 2, H * 0.72); + g.addColorStop(0, "rgba(0,0,0,0)"); + g.addColorStop(1, "rgba(0,0,0,0.42)"); + vctx.fillStyle = g; + vctx.fillRect(0, 0, W, H); +} + +// KidLisp-reel VHS palette: lime core, magenta/cyan ghosts. +const CORE = [180, 240, 70], CORE_HI = [225, 255, 150]; +const CHROMA_R = [255, 60, 120], CHROMA_B = [70, 170, 255], CHROMA_PX = 3; + +function tinted(src, c, cnv, cctx) { + cnv.width = src.width; cnv.height = src.height; + cctx.globalCompositeOperation = "source-over"; + cctx.clearRect(0, 0, src.width, src.height); + cctx.drawImage(src, 0, 0); + cctx.globalCompositeOperation = "source-in"; + cctx.fillStyle = `rgb(${c[0]},${c[1]},${c[2]})`; + cctx.fillRect(0, 0, src.width, src.height); + cctx.globalCompositeOperation = "source-over"; + return cnv; +} + +// one glyph/stamp as a VHS sandwich: shadow + split ghosts + core + env glow +function drawChroma(sharp, soft, dx, dy, dw, dh, e, core = CORE, coreAlpha = 0.62, tintCnv = wmCanvas, tintCtx2 = wmCtx) { + ctx.globalCompositeOperation = "source-over"; ctx.globalAlpha = 0.22; + ctx.drawImage(tinted(sharp, [8, 10, 6], tintCnv, tintCtx2), dx + 2.5, dy + 3, dw, dh); + ctx.globalCompositeOperation = "screen"; + ctx.globalAlpha = 0.30; ctx.drawImage(tinted(soft, CHROMA_R, tintCnv, tintCtx2), dx - CHROMA_PX, dy, dw, dh); + ctx.globalAlpha = 0.30; ctx.drawImage(tinted(soft, CHROMA_B, tintCnv, tintCtx2), dx + CHROMA_PX, dy, dw, dh); + ctx.globalAlpha = coreAlpha; ctx.drawImage(tinted(sharp, core, tintCnv, tintCtx2), dx, dy, dw, dh); + if (e > 0.02) { ctx.globalAlpha = 0.08 + 0.20 * e; ctx.drawImage(tinted(soft, CORE_HI, tintCnv, tintCtx2), dx, dy, dw, dh); } + ctx.globalCompositeOperation = "source-over"; ctx.globalAlpha = 1; +} + +function drawPals(t, e) { + const TAU = Math.PI * 2, u = t / DUR, sp = PALS_SPEED, s = PALS_S; + const wig = 13 * Math.sin(TAU * 24 * sp * u + 0.7) + 4 * Math.sin(TAU * 9 * sp * u); + const bob = 3 * Math.sin(TAU * 17 * sp * u + 2.1) + 1.5 * Math.sin(TAU * 31 * sp * u); + const swiv = 0.05 * Math.sin(TAU * 19 * sp * u) + 0.025 * Math.sin(TAU * 38 * sp * u + 1.4); + const spots = [ + { cx: PALS_EDGE_X - wig, cy: LEFT_PALS_CY + bob, rot: Math.PI / 2 + swiv }, + { cx: W - PALS_EDGE_X + wig, cy: RIGHT_PALS_CY - bob, rot: -Math.PI / 2 - swiv }, + ]; + for (const spot of spots) { + ctx.save(); + ctx.translate(spot.cx, spot.cy); + ctx.rotate(spot.rot); + drawChroma(palsImg, palsBlur, -s / 2, -s / 2, s, s, e, CORE, 0.62); + ctx.restore(); + } + drawTitleChars(t, e); +} + +// laklok columns: below the left stamp, above the right stamp, climbing the +// same edges, each char bouncing gently with the speech envelope. +function drawTitleChars(t, e) { + const TAU = Math.PI * 2, u = t / DUR; + const wig = 11 * Math.sin(TAU * 30 * PALS_SPEED * u + 3.6) + 4 * Math.sin(TAU * 12 * PALS_SPEED * u + 1.1); + const leftCy = LEFT_PALS_CY + PALS_S / 2 + CHAR_BUF + CHAR_SPAN / 2; + const rightCy = RIGHT_PALS_CY - PALS_S / 2 - CHAR_BUF - CHAR_SPAN / 2; + const spots = [ + { cx: CHARS_EDGE_X - wig, cy: leftCy, rot: Math.PI / 2 }, + { cx: W - CHARS_EDGE_X + wig, cy: rightCy, rot: -Math.PI / 2 }, + ]; + const startX = -CHAR_SPAN / 2; + for (const sp of spots) { + ctx.save(); + ctx.translate(sp.cx, sp.cy); + ctx.rotate(sp.rot); + for (let i = 0; i < titleChars.length; i++) { + const ch = titleChars[i]; + if (!ch.img) continue; + const x = startX + (ch.prefixWidth + i * KERN) * CHAR_SCALE; + const dw = ch.img.width * CHAR_SCALE, dh = ch.img.height * CHAR_SCALE; + const lift = 3.5 * Math.sin(t * 1.5 + i * 0.8) * (0.6 + 0.25 * e); + const yy = -dh / 2 + lift; + const rot2 = 0.03 * Math.sin(t * 1.2 + i * 1.15); + ctx.save(); + ctx.translate(x + dw / 2, yy + dh / 2); + ctx.rotate(rot2); + ctx.translate(-(x + dw / 2), -(yy + dh / 2)); + drawChroma(ch.img, ch.img, x, yy, dw, dh, e, CORE, 0.78, glyphTint, glyphTintCtx); + ctx.restore(); + } + ctx.restore(); + } +} + +// karaoke block: lines centered in the frame; the active word tints lime, +// pops in scale, and gets the full ghost sandwich. Passed words solid white, +// upcoming words dimmed. +const LINE_H = Math.round(PT * 1.42); +function drawSubs(t, e) { + const block = blocks.find((b) => t >= b.show && t < b.hide); + if (!block) return; + const blockH = block.lines.length * LINE_H; + let y = (H - blockH) / 2; + for (const line of block.lines) { + let x = (W - line.w) / 2; + for (const w of line.words) { + const pair = wordImgs.get(w.text); + if (!pair) { x += wordWidth(w.text) + SPACE_W; continue; } + const active = t >= w.start && t < w.end; + const passed = t >= w.end; + const img = pair.plain; + const dw = img.width, dh = img.height; + const dy = y + (LINE_H - dh) / 2; + // MacPal comic treatment: per-word jitter, ink stroke, hard accent + // shadow. Active word flips to lime with a magenta shadow + scale pop. + const j = jitter(w.idx); + const cx = x + dw / 2, cy = dy + dh / 2; + ctx.save(); + ctx.translate(cx, cy + j.dy); + ctx.rotate(j.rot); + if (active) { + const pop = Math.exp(-(t - w.start) * 5); + const sc = 1 + 0.14 * pop; + ctx.scale(sc, sc); + } + ctx.translate(-cx, -cy); + const s = active ? pair.lime : pair.stroked; + const sx = x - (s.width - dw) / 2, sy = dy - (s.height - dh) / 2; + const shadowColor = active ? CHROMA_R : CORE; + ctx.globalAlpha = active ? 0.95 : 0.85; + ctx.drawImage(tinted(s, shadowColor, glyphTint, glyphTintCtx), sx + 4, sy + 4.5, s.width, s.height); + if (active) { + ctx.globalCompositeOperation = "screen"; + ctx.globalAlpha = 0.35; + ctx.drawImage(tinted(img, CHROMA_R, glyphTint, glyphTintCtx), x - 3, dy, dw, dh); + ctx.drawImage(tinted(img, CHROMA_B, glyphTint, glyphTintCtx), x + 3, dy, dw, dh); + ctx.globalCompositeOperation = "source-over"; + } + ctx.globalAlpha = active || passed ? 1 : 0.8; + ctx.drawImage(s, sx, sy, s.width, s.height); + ctx.globalAlpha = 1; + ctx.restore(); + x += dw + SPACE_W; + } + y += LINE_H; + } +} + +// ── decoder (rawvideo in) + encoder (rawvideo out) ─────────────────────────── +const dec = spawn("ffmpeg", [ + "-hide_banner", "-loglevel", "error", + "-i", VIDEO, "-f", "rawvideo", "-pix_fmt", "rgba", + "-s", `${SRC_W}x${SRC_H}`, "-r", String(FPS), "-", +], { stdio: ["ignore", "pipe", "inherit"] }); +const SILENT = `${DIR}/${NAME}-chrome-silent.mp4`; +const enc = spawn("ffmpeg", [ + "-hide_banner", "-loglevel", "error", "-y", + "-f", "rawvideo", "-pix_fmt", "bgra", "-s", `${W}x${H}`, "-r", String(FPS), "-i", "-", + // punch pass: crush blacks + saturate + sharpen the composited frame + "-vf", "eq=contrast=1.15:brightness=-0.02:saturation=1.12,unsharp=5:5:0.6", + "-c:v", "libx264", "-preset", "faster", "-crf", "18", "-threads", "0", + "-pix_fmt", "yuv420p", "-movflags", "+faststart", SILENT, +], { stdio: ["pipe", "inherit", "inherit"] }); + +const FRAME_BYTES = SRC_W * SRC_H * 4; +const srcCanvas = createCanvas(SRC_W, SRC_H); +const srcCtx = srcCanvas.getContext("2d"); +const srcImageData = srcCtx.createImageData(SRC_W, SRC_H); + +let leftover = Buffer.alloc(0); +async function* frames() { + for await (const chunk of dec.stdout) { + leftover = leftover.length ? Buffer.concat([leftover, chunk]) : chunk; + while (leftover.length >= FRAME_BYTES) { + yield leftover.subarray(0, FRAME_BYTES); + leftover = leftover.subarray(FRAME_BYTES); + } + } +} + +console.log(`▸ klokkentales chrome · ${FRAMES} frames @ ${FPS}fps · drippy VHS + pals + karaoke`); +const t0ms = Date.now(); +let i = 0; +for await (const raw of frames()) { + const t = i / FPS; + const e = env[Math.min(env.length - 1, i)]; + + srcImageData.data.set(raw); + srcCtx.putImageData(srcImageData, 0, 0); + + // stage = full-bleed video frame at reel size + stageCtx.drawImage(srcCanvas, 0, 0, W, H); + + ctx.globalCompositeOperation = "source-over"; + ctx.globalAlpha = 1; + ctx.drawImage(stage, 0, 0); + + // chroma fringe: magenta/cyan multiply-tinted copies split ±4px (screen) + tintCtx.globalCompositeOperation = "source-over"; + tintCtx.drawImage(stage, 0, 0); + tintCtx.globalCompositeOperation = "multiply"; + tintCtx.fillStyle = "rgb(255,60,120)"; tintCtx.fillRect(0, 0, W, H); + ctx.globalCompositeOperation = "screen"; ctx.globalAlpha = 0.09; + ctx.drawImage(tintCanvas, -4, 0); + tintCtx.globalCompositeOperation = "source-over"; + tintCtx.drawImage(stage, 0, 0); + tintCtx.globalCompositeOperation = "multiply"; + tintCtx.fillStyle = "rgb(70,170,255)"; tintCtx.fillRect(0, 0, W, H); + ctx.drawImage(tintCanvas, 4, 0); + ctx.globalCompositeOperation = "source-over"; ctx.globalAlpha = 1; + + // drippy melt: feedback buffer falls + fades each frame, reseeded by the + // current frame; screen-composited so highlights leave falling trails. + const bc = dripBack.getContext("2d"); + bc.globalCompositeOperation = "copy"; + bc.globalAlpha = 0.90; + bc.drawImage(dripFront, 0, 6); + bc.globalCompositeOperation = "lighten"; + bc.globalAlpha = 0.45; + bc.drawImage(stage, 0, 0); + bc.globalCompositeOperation = "source-over"; + bc.globalAlpha = 1; + ctx.globalCompositeOperation = "screen"; + ctx.globalAlpha = 0.17; + ctx.drawImage(dripBack, 0, 0); + ctx.globalCompositeOperation = "source-over"; + ctx.globalAlpha = 1; + [dripFront, dripBack] = [dripBack, dripFront]; + + // scanlines (slow roll) + vignette + ctx.globalAlpha = 0.055; + ctx.drawImage(scan, 0, -(Math.floor(t * 18) % 4)); + ctx.globalAlpha = 1; + ctx.drawImage(vig, 0, 0); + + drawPals(t, e); + drawSubs(t, e); + + if (!enc.stdin.write(canvas.toBuffer("raw"))) await once(enc.stdin, "drain"); + i++; + if (i % 90 === 0) console.log(` ${i}/${FRAMES} · ${((Date.now() - t0ms) / 1000).toFixed(0)}s`); +} +enc.stdin.end(); +await new Promise((res, rej) => { enc.on("close", (c) => (c === 0 ? res() : rej(new Error(`encode exit ${c}`)))); }); +console.log(`✓ silent chrome: ${SILENT} (${i} frames)`); + +// ── mux: voice + music bed (music low, faded out at the end) ───────────────── +const mixArgs = [ + "-hide_banner", "-loglevel", "error", "-y", + "-i", SILENT, "-i", VOICE, +]; +if (MUSIC) { + // atrim clamps the mix to the video's exact length — otherwise the audio + // track outlives the last frame by ~50ms and players flash black at the end. + mixArgs.push("-i", MUSIC, "-filter_complex", + `[2:a]volume=${MUSIC_VOL},afade=t=in:st=0:d=0.8,afade=t=out:st=${(DUR - 1.4).toFixed(2)}:d=1.4[m];` + + `[1:a][m]amix=inputs=2:duration=first:normalize=0,atrim=end=${DUR.toFixed(3)}[a]`, + "-map", "0:v", "-map", "[a]"); +} else { + mixArgs.push("-map", "0:v", "-map", "1:a", "-af", `atrim=end=${DUR.toFixed(3)}`); +} +mixArgs.push("-c:v", "copy", "-c:a", "aac", "-b:a", "192k", "-shortest", OUTFILE); +const mix = spawnSync("ffmpeg", mixArgs, { stdio: "inherit" }); +if (mix.status !== 0) throw new Error("audio mux failed"); +console.log(`✓ ${OUTFILE}`); diff --git a/toolchain/instagram/ig.mjs b/toolchain/instagram/ig.mjs index 1549207fcd..14cc5e2337 100644 --- a/toolchain/instagram/ig.mjs +++ b/toolchain/instagram/ig.mjs @@ -22,7 +22,7 @@ // node toolchain/instagram/ig.mjs --as oskiewar refresh // node toolchain/instagram/ig.mjs refresh --all # monthly cron // node toolchain/instagram/ig.mjs --as oskiewar post reel.mp4 \ -// --caption "..." [--cover cover.jpg] +// --caption "..." [--cover cover.jpg] [--audio-name "..."] // node toolchain/instagram/ig.mjs --as oskiewar insights // node toolchain/instagram/ig.mjs --as oskiewar snapshot // @@ -263,7 +263,7 @@ async function uploadPublic(creds, files) { async function doPost(creds) { const file = positional[0]; - if (!file) die(`usage: ig.mjs --as post --caption "..." [--cover img.jpg]`); + if (!file) die(`usage: ig.mjs --as post --caption "..." [--cover img.jpg] [--audio-name "..."] [--collaborators user1,user2]`); const videoPath = resolve(process.cwd(), file); if (!existsSync(videoPath)) die(`video not found: ${videoPath}`); if (!flags.caption || flags.caption === true) die(`--caption is required`); @@ -274,6 +274,19 @@ async function doPost(creds) { coverPath = resolve(process.cwd(), String(flags.cover)); if (!existsSync(coverPath)) die(`cover not found: ${coverPath}`); } + // Renames the reel's original audio track — the name other users see when + // they tap the audio. Meta only honors it on the first reel that mints the + // audio; it cannot be edited after publish. + const audioName = typeof flags["audio-name"] === "string" ? flags["audio-name"] : null; + if (flags["audio-name"] === true) die(`--audio-name needs a value`); + + // Invite accounts as collaborators (comma-separated usernames, max 3). + // Each invitee must accept before the reel appears on their profile. + if (flags.collaborators === true) die(`--collaborators needs a value`); + const collaborators = typeof flags.collaborators === "string" + ? flags.collaborators.split(",").map((s) => s.trim().replace(/^@/, "")).filter(Boolean) + : null; + if (collaborators && collaborators.length > 3) die(`Instagram allows at most 3 collaborators`); // Quota first — a spent budget should stop us before any bytes move. const quota = await fetchQuota(creds); @@ -293,6 +306,8 @@ async function doPost(creds) { share_to_feed: true, // a reel that only lives in the Reels tab is invisible to followers }; if (urls.cover) body.cover_url = urls.cover; + if (audioName) body.audio_name = audioName; + if (collaborators?.length) body.collaborators = collaborators; const created = await call(api(`${creds.igUserId}/media?access_token=${creds.token}`), { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), @@ -323,6 +338,8 @@ async function doPost(creds) { videoUrl: urls.reel, coverUrl: urls.cover || null, caption, + audioName, + collaborators, file: videoPath, }; const sidecar = videoPath.replace(/\.[^.]+$/, "") + ".instagram.json"; @@ -396,7 +413,7 @@ commands: quota content_publishing_limit — posts used/allowed per 24h refresh refresh the 60-day token, rewrite the vault env file in place refresh --all refresh every provisioned account (monthly cron; no --as needed) - post --caption "..." [--cover img.jpg] + post --caption "..." [--cover img.jpg] [--audio-name "..."] publish a reel: Spaces upload → container → poll → publish insights per-reel metrics (views, reach, skip rate, …) snapshot print a social/accounts.json snapshots entry (does not write it) -- 2.51.2 From a061ceaff1a8ad40deb539b33ffd5442bcf44d49 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Thu, 13 Aug 2026 18:07:04 -0400 Subject: [PATCH 2/4] menuband: polyrhythm trainer as separate side-by-side circles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each rhythm gets its own circle instead of stacked concentric rings, so a finger can own a rhythm. Taps route by the contact's normalized x — equal vertical bands mirroring the left-to-right layout — and score against that circle's grid only, replacing the nearest-grid guess that let a sloppy 3-circle tap be excused by a nearby 2-circle beat. The clock now holds N counts (3:2, 4:3, 5:4, 3:4:5) with per-circle click voices. --render-polyrhythm gains --pattern/--phase/--bpm/--light/--scale so the reel lane can sweep phase deterministically; pop/menuband gains the polyrhythm jingle + sim that light each circle from its own audio lane. --- pop/menuband/bin/render-polyrhythm-jingle.mjs | 129 +++++ pop/menuband/bin/sim-polyrhythm.mjs | 283 +++++++++++ .../Sources/MenuBand/AppDelegate.swift | 183 ++++++- .../Sources/MenuBand/MenuBandController.swift | 32 +- .../MenuBand/MenuBandRewindVoice.swift | 139 +++++- .../MenuBand/MenuBandSampleVoice.swift | 66 ++- .../Sources/MenuBand/MenuBandSynth.swift | 44 +- .../Sources/MenuBand/PitchBendCursor.swift | 61 ++- .../Sources/MenuBand/PolyrhythmTrainer.swift | 458 ++++++++++++++++++ .../Sources/MenuBand/ReverseWaveformHUD.swift | 110 +++++ .../Sources/MenuBand/WaveformStripView.swift | 187 +++++-- slab/menuband/Sources/MenuBand/main.swift | 5 + .../Tests/MenuBandTests/ShapedownTests.swift | 140 ++++++ 13 files changed, 1733 insertions(+), 104 deletions(-) create mode 100644 pop/menuband/bin/render-polyrhythm-jingle.mjs create mode 100644 pop/menuband/bin/sim-polyrhythm.mjs create mode 100644 slab/menuband/Sources/MenuBand/PolyrhythmTrainer.swift create mode 100644 slab/menuband/Sources/MenuBand/ReverseWaveformHUD.swift diff --git a/pop/menuband/bin/render-polyrhythm-jingle.mjs b/pop/menuband/bin/render-polyrhythm-jingle.mjs new file mode 100644 index 0000000000..39c3f74515 --- /dev/null +++ b/pop/menuband/bin/render-polyrhythm-jingle.mjs @@ -0,0 +1,129 @@ +#!/usr/bin/env node +// render-polyrhythm-jingle.mjs — the Menu Band POLYRHYTHM reel's jingle, +// on the same /pop lullaby engine as render-waltz.mjs / render-jingles.mjs. +// +// The rhythmic identity IS the content: every rhythm is its own lane with +// its own timbre, and the sim lights one side-by-side circle per lane from +// that lane's notes — so the circles and the audio agree to the sample. +// +// solo 0.0– 4.8 "3" three (vibraphone) establishes the pulse +// duo 4.8–12.0 "3:2" two (gamelan) lands against it +// trio 12.0–19.2 "3:4" four (kalimba) swaps in — same 3, new grid +// full 19.2–26.4 "3:4:5" five (glockenspiel) on top — three grids +// end 26.4 every grid coincides: one unison C, ringing out +// +// The shared cycle is 2.4s — exactly the app's PolyrhythmTrainerClock +// default (75 BPM on the outer 3: 60/75*3 = 2.4). Every pitch is a WHITE +// KEY so the strip rig's real captured menu-bar piano lights pixel-real. +// +// Writes: out/menuband-polyrhythm.mp3 +// out/menuband-polyrhythm.notes.json (lanes preserved) +// out/menuband-polyrhythm.score.json (sections + rhythms per lane) +// +// Run: node pop/menuband/bin/render-polyrhythm-jingle.mjs (from repo root) + +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { writeFileSync } from "node:fs"; +import { renderLullaby, m } from "../../marimba/lullabies/lib/core.mjs"; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const OUT_DIR = resolve(HERE, "..", "out"); + +const CYCLE = 2.4; // one full polyrhythm cycle (75 BPM · 3) +const BPM = 75; // the app's trainer default + +// Chord tone tables — one pitch cell per lane per chord, all white keys. +// Each cell has exactly `count` pitches: hit i of a cycle plays cell[i]. +const CHORDS = { + C: { three: ["C5", "E5", "G5"], two: ["C3", "G3"], four: ["C4", "E4", "G4", "C5"], five: ["C6", "D6", "E6", "G6", "A6"], bass: "C2" }, + G: { three: ["B4", "D5", "G5"], two: ["G2", "D3"], four: ["G3", "B3", "D4", "G4"], five: ["G5", "A5", "B5", "D6", "G6"], bass: "G2" }, + Am: { three: ["A4", "C5", "E5"], two: ["A2", "E3"], four: ["A3", "C4", "E4", "A4"], five: ["A5", "B5", "C6", "E6", "A6"], bass: "A2" }, + F: { three: ["A4", "C5", "F5"], two: ["F2", "C3"], four: ["F3", "A3", "C4", "F4"], five: ["F5", "G5", "A5", "C6", "F6"], bass: "F2" }, +}; + +// One lane per rhythm: count, timbre, and the icon-palette color the sim's +// circle wears (reel-lib KEY_COLORS — brand-consistent, per-rhythm). +const RHYTHMS = { + three: { count: 3, preset: "vibraphone", gain: 0.42, ring: 1.15, decayMul: 1.25, color: [255, 77, 107] }, + two: { count: 2, preset: "gamelan", gain: 0.30, ring: 0.95, decayMul: 1.10, color: [97, 158, 255] }, + four: { count: 4, preset: "kalimba", gain: 0.24, ring: 0.90, decayMul: 1.00, color: [255, 153, 46] }, + five: { count: 5, preset: "glockenspiel", gain: 0.14, ring: 1.30, decayMul: 1.30, color: [51, 209, 179] }, +}; + +// The escalation: which lanes sound, over which chords, per section. +const SECTIONS = [ + { name: "solo", label: "3", lanes: ["three"], chords: ["C", "C"] }, + { name: "duo", label: "3:2", lanes: ["three", "two"], chords: ["C", "C", "G"] }, + { name: "trio", label: "3:4", lanes: ["three", "four"], chords: ["Am", "F", "Am"] }, + { name: "full", label: "3:4:5", lanes: ["three", "four", "five"], chords: ["F", "G", "C"] }, +]; + +const events = []; +const push = (lane, preset, startSec, note, durSec, gain, pan = 0, decayMul = 1.2) => { + events.push({ lane, preset, startSec: +startSec.toFixed(4), midi: m(note), durSec: +durSec.toFixed(4), gain, pan, decayMul }); +}; + +// Pan each lane toward where its circle sits in that section's row. +const lanePan = (lanes, lane) => { + if (lanes.length < 2) return 0; + const i = lanes.indexOf(lane); + return +(((i / (lanes.length - 1)) - 0.5) * 0.44).toFixed(3); +}; + +let t = 0; +const sections = []; +for (const S of SECTIONS) { + const t0 = t; + S.chords.forEach((chordName, c) => { + const chord = CHORDS[chordName]; + const ct = t0 + c * CYCLE; + // the bed: a bass root each cycle + a soft woodblock tick on the downbeat + push("bed", "bass", ct, chord.bass, 2.0, 0.26, 0, 1.1); + if (S.name !== "solo") push("tick", "woodblock", ct, "E5", 0.12, 0.055, 0.1, 0.9); + // the rhythms: lane k plays `count` evenly spaced hits per cycle + for (const lane of S.lanes) { + const R = RHYTHMS[lane]; + const step = CYCLE / R.count; + for (let i = 0; i < R.count; i++) { + push(lane, R.preset, ct + i * step, chord[lane][i], step * R.ring, R.gain, lanePan(S.lanes, lane), R.decayMul); + } + } + }); + t = t0 + S.chords.length * CYCLE; + sections.push({ + name: S.name, label: S.label, t0: +t0.toFixed(4), t1: +t.toFixed(4), + cycles: S.chords.length, + rhythms: S.lanes.map((lane) => ({ lane, ...RHYTHMS[lane], preset: RHYTHMS[lane].preset })), + }); +} + +// ── the unison — every grid's dot 0, at once: one spread C, ringing out ──── +const END = t; // 26.4 +push("bed", "bass", END, "C2", 3.4, 0.32, 0, 1.5); +for (const [i, n] of ["C5", "E5", "G5"].entries()) push("three", "vibraphone", END + i * 0.05, n, 3.0, 0.36, -0.12 + i * 0.12, 1.6); +for (const [i, n] of ["C4", "E4", "G4"].entries()) push("four", "kalimba", END + i * 0.04, n, 2.4, 0.20, 0.1, 1.4); +push("five", "glockenspiel", END, "C6", 3.2, 0.15, 0.26, 1.6); +push("five", "glockenspiel", END + 0.08, "G6", 2.8, 0.09, 0.34, 1.6); + +// ── master + scores ──────────────────────────────────────────────────────── +const NAME = "menuband-polyrhythm"; +const { mp3, durationSec } = renderLullaby(events, { + name: NAME, here: HERE, out: resolve(OUT_DIR, `${NAME}.mp3`), + healing: false, reverb: { wet: 0.24, decay: 0.8, damp: 0.4 }, + fadeIn: 0.3, fadeOut: 2.0, tailSec: 2.4, + title: "Menu Band Polyrhythm Trainer", +}); +console.log(`✓ ${mp3} · ${durationSec.toFixed(1)}s`); + +const notes = events + .map((e) => ({ t: e.startSec, dur: e.durSec, midi: e.midi, vel: +e.gain.toFixed(3), lane: e.lane })) + .sort((a, b) => a.t - b.t || a.midi - b.midi); +writeFileSync(resolve(OUT_DIR, `${NAME}.notes.json`), JSON.stringify({ + bpm: BPM, cycleSec: CYCLE, durationSec: +durationSec.toFixed(4), notes, +}, null, 2)); +writeFileSync(resolve(OUT_DIR, `${NAME}.score.json`), JSON.stringify({ + bpm: BPM, cycleSec: CYCLE, durationSec: +durationSec.toFixed(4), + end: +END.toFixed(4), sections, +}, null, 2)); +console.log(` ${sections.length} sections · unison @ ${END.toFixed(1)}s · ${notes.length} notes`); diff --git a/pop/menuband/bin/sim-polyrhythm.mjs b/pop/menuband/bin/sim-polyrhythm.mjs new file mode 100644 index 0000000000..4d9afeb0ca --- /dev/null +++ b/pop/menuband/bin/sim-polyrhythm.mjs @@ -0,0 +1,283 @@ +#!/usr/bin/env node +// sim-polyrhythm.mjs — the Menu Band POLYRHYTHM reel base. +// +// The visual centerpiece is the app's reworked polyrhythm trainer: N +// SEPARATE circles side by side — one circle per rhythm (3 next to 2), NOT +// concentric rings — each circle's beat dots lighting on its own grid, its +// own sweep hand, over the polyrhythm jingle +// (render-polyrhythm-jingle.mjs). Every circle lights from ITS OWN lane in +// menuband-polyrhythm.notes.json, so the picture and the audio agree to +// the sample — the lane's founding determinism. +// +// Acts (scene times come straight from the score's sections): +// 1 · intro — the real menu-bar strip falls in, icon + identity, and the +// first circle ("3") already keeping time below; +// 2 · duo — 3:2, two circles side by side; +// 3 · trio — 3:4, same three, new grid; +// 4 · full — 3:4:5, three circles, then every hand reaches the top at +// once for the unison ring-out; +// 5 · end tag — icon · "free on the Mac App Store" · menuband.app. +// +// CIRCLE RENDER — one swappable function (drawPolyCircle). Today it draws +// in node-canvas with geometry lifted from the app's own +// PolyrhythmTrainer.swift (face r=56 → ring r=45, dots 6/10, hand 52, +// hub 5, needle flash 0.12s — all scaled by u = R/56). When the Swift +// side-by-side rework + `--render-polyrhythm --pattern/--phase` CLI lands, +// pre-render per-phase captures to out/polyrhythm-frames/ (the sim.mjs +// menubar-frames pattern) and swap the body of drawPolyCircle for a blit. +// +// Output: out/base-menuband-polyrhythm.mp4 + meta-menuband-polyrhythm.json +// Then: node pop/menuband/bin/chrome-reel.mjs menuband-polyrhythm +// +// Usage: node pop/menuband/bin/sim-polyrhythm.mjs +// (render-polyrhythm-jingle.mjs first) + +import { readFileSync, existsSync } from "node:fs"; +import { + W, H, FPS, OUT, INK, easeOut, clamp01, rgb, + makeStage, roundRect, text, drawDesktop, vignette, drawIcon, + makeParticles, loadStripRig, drawStrip, stripKeyX, stripKeyColor, + loadScore, litAt, makeOnsets, + renderVideo, writeMeta, makeScenes, +} from "./reel-lib.mjs"; + +const SLUG = "menuband-polyrhythm"; +const score = loadScore(SLUG); +const POLY = JSON.parse(readFileSync(`${OUT}/${SLUG}.score.json`, "utf8")); +const TOTAL = score.durationSec; +const CYCLE = POLY.cycleSec; +const END = POLY.end; // the unison downbeat + +const { canvas, ctx } = makeStage(); +const rig = await loadStripRig(); +const particles = makeParticles(ctx); + +// ── lanes ────────────────────────────────────────────────────────────────── +const RHYTHM_LANES = ["three", "two", "four", "five"]; +const laneNotes = new Map(RHYTHM_LANES.map((l) => [l, score.notes.filter((n) => n.lane === l)])); +const stripNotes = score.notes.filter((n) => RHYTHM_LANES.includes(n.lane)); +const stripOnsets = makeOnsets(stripNotes); +const laneOnsets = new Map(RHYTHM_LANES.map((l) => [l, makeOnsets(laneNotes.get(l))])); + +const sectionAt = (t) => { + let s = POLY.sections[0]; + for (const sect of POLY.sections) if (t >= sect.t0) s = sect; + return s; +}; + +// ── scenes — boundaries ride the score's sections; `full` holds past the +// unison so the hands-at-the-top ring-out reads before the end card. ─────── +const HOLD = 1.6; +const { scenes: SCENES, sceneAt } = makeScenes([ + { name: "intro", from: 0, to: POLY.sections[1].t0 / TOTAL, tint: [255, 77, 107] }, + { name: "duo", from: POLY.sections[1].t0 / TOTAL, to: POLY.sections[2].t0 / TOTAL, tint: [97, 158, 255] }, + { name: "trio", from: POLY.sections[2].t0 / TOTAL, to: POLY.sections[3].t0 / TOTAL, tint: [255, 153, 46] }, + { name: "full", from: POLY.sections[3].t0 / TOTAL, to: (END + HOLD) / TOTAL, tint: [51, 209, 179] }, + { name: "end", from: (END + HOLD) / TOTAL, to: 1, tint: [255, 77, 107] }, +], TOTAL); + +// ── the hero strip (features-sim geometry): the real menu-bar piano parks +// at the very top, falls in during the first second, lit from every rhythm +// lane — the app tie-in over the trainer. ────────────────────────────────── +const HERO_W = W * 0.96, HERO_X = (W - HERO_W) / 2, HERO_TOP = 54; +function heroRect(t) { + const h = HERO_W / rig.aspect; + const enter = easeOut(clamp01(t / 1.0)); + const bob = Math.sin((t / CYCLE) * Math.PI * 2) * 6 * enter; + return { x: HERO_X, y: (-h - 40) + (HERO_TOP - (-h - 40)) * enter + bob, w: HERO_W, h }; +} + +// ── circle state: per-rhythm phase / grid step / strike glow, all derived +// from the score clock + that rhythm's OWN lane onsets. ──────────────────── +const FLASH_SEC = 0.30; // needle/dot pop (app: 0.12s — widened for 30fps) +function circleStates(t) { + const sect = sectionAt(t); + const frozen = t >= END; // after the unison the hands hold the top + const local = frozen ? 0 : Math.max(0, t - sect.t0); + const phase = frozen ? 0 : (local / CYCLE) % 1; + return { + sect, + specs: sect.rhythms.map((r) => { + const notes = laneNotes.get(r.lane) ?? []; + let flash = 0, litStep = -1, sustain = 0; + for (const n of notes) { + if (n.t > t) break; + const step = Math.round((((n.t - sect.t0) % CYCLE) / CYCLE) * r.count) % r.count; + if (t - n.t < FLASH_SEC) { flash = Math.max(flash, 1 - (t - n.t) / FLASH_SEC); litStep = step; } + if (t < n.t + n.dur) { sustain = Math.max(sustain, 0.55); litStep = litStep < 0 ? step : litStep; } + } + return { + lane: r.lane, count: r.count, color: r.color, phase, + activeStep: Math.floor(phase * r.count) % r.count, + litStep, flash, glow: Math.max(flash, sustain), + }; + }), + }; +} + +// ── THE SWAPPABLE CIRCLE RENDER ──────────────────────────────────────────── +// Geometry from PolyrhythmTrainer.swift, scaled by u = R/56: +// face r 56 (white, near-opaque, hairline quiet stroke) · beat ring r 45 +// dots ∅6 idle / ∅10 active at the ring · hand length 52, lw 1.5+2.5·flash +// hub ∅5 · center label (the count) + small bpm figure below. +// Light mode; the active dot wears the rhythm's own icon-palette color +// (in-app it's the one system accent — per-circle color is the reel's read). +// Replace this body with an out/polyrhythm-frames/ blit once the Swift +// side-by-side CLI (--pattern/--phase/--light) exists. +function drawPolyCircle(c, { cx, cy, R, count, color, phase, activeStep, litStep, flash, glow, alpha = 1 }) { + const u = R / 56; + const TAU = Math.PI * 2; + const quiet = "rgba(0,0,0,0.18)"; + c.save(); + c.globalAlpha = alpha; + + // face + c.beginPath(); c.arc(cx, cy, R, 0, TAU); + c.fillStyle = "rgba(255,255,255,0.93)"; c.fill(); + c.lineWidth = Math.max(2, 1.2 * u); c.strokeStyle = quiet; c.stroke(); + + // beat ring + c.beginPath(); c.arc(cx, cy, 45 * u, 0, TAU); + c.lineWidth = 1.5 * u; c.strokeStyle = quiet; c.stroke(); + + // dots — clockwise from the top, one per beat of this rhythm's grid + for (let i = 0; i < count; i++) { + const a = -Math.PI / 2 + (i / count) * TAU; + const px = cx + Math.cos(a) * 45 * u, py = cy + Math.sin(a) * 45 * u; + const active = i === activeStep; + const struck = i === litStep && glow > 0; + const dia = (active ? 10 : 6) * u + (struck ? 4 * u * flash : 0); + if (struck) { + c.save(); + c.shadowColor = rgb(color, 0.9 * glow); c.shadowBlur = 22 * u * glow; + c.beginPath(); c.arc(px, py, dia / 2, 0, TAU); + c.fillStyle = rgb(color); c.fill(); + c.restore(); + } else { + c.beginPath(); c.arc(px, py, dia / 2, 0, TAU); + c.fillStyle = active ? rgb(color) : quiet; c.fill(); + } + } + + // hand — one revolution per shared cycle; strikes brighten + thicken it + const ha = -Math.PI / 2 + phase * TAU; + c.beginPath(); c.moveTo(cx, cy); + c.lineTo(cx + Math.cos(ha) * 52 * u, cy + Math.sin(ha) * 52 * u); + c.lineWidth = (1.5 + 2.5 * flash) * u; + c.lineCap = "round"; + c.strokeStyle = flash > 0.01 ? rgb(color, 0.78 + 0.22 * flash) : "rgba(20,18,28,0.78)"; + c.stroke(); + + // hub + c.beginPath(); c.arc(cx, cy, 2.5 * u, 0, TAU); + c.fillStyle = INK; c.fill(); + + // the count + the app's bpm figure (75 — the trainer default the jingle rides) + text(c, String(count), cx, cy - 13 * u, 15 * u, "rgba(20,18,28,0.88)", 800); + text(c, String(POLY.bpm), cx, cy + 14 * u, 8 * u, "rgba(20,18,28,0.58)", 600); + + c.restore(); +} + +// ── row layout: N circles side by side, sized to the frame ──────────────── +const GAP = 44; +function rowSpecs(specs, cy, maxR = 210) { + const n = specs.length; + const R = Math.min(maxR, (W * 0.92 - (n - 1) * GAP) / (2 * n)); + const total = n * 2 * R + (n - 1) * GAP; + const x0 = (W - total) / 2 + R; + return specs.map((s, i) => ({ ...s, R, cx: x0 + i * (2 * R + GAP), cy })); +} + +// ── captions ─────────────────────────────────────────────────────────────── +const CAPTIONS = { + intro: ["meet the polyrhythm trainer", "one circle per rhythm · press / to start"], + duo: ["three against two", "each circle keeps its own grid"], + trio: ["same three · new grid", "the left circle never changes"], + full: ["three grids at once", "3 · 4 · 5 — one shared clock"], +}; + +function drawFrame(t) { + drawDesktop(ctx); + const sc = sceneAt(t); + const local = (sc.to - sc.from) > 0 ? (t - sc.from) / (sc.to - sc.from) : 1; + const dt = 1 / FPS; + + // the real strip up top, lit by every rhythm lane + const hero = heroRect(t); + const hRect = drawStrip(ctx, rig, litAt(stripNotes, t), hero.x, hero.y, hero.w); + for (const n of stripOnsets(t - dt, t)) { + particles.spawnNote(stripKeyX(rig, n.midi, hRect), hRect.y + hRect.h + 6, stripKeyColor(rig, n.midi), true); + } + + if (sc.name === "end") { + const e = easeOut(Math.min(1, local * 5)); + ctx.save(); ctx.globalAlpha = e; + const ipx = 300; + drawIcon(ctx, W / 2 - ipx / 2, H * 0.28, ipx, new Set(litAt(stripNotes, t).map((mm) => ((mm % 12) + 12) % 12 % 5))); + text(ctx, "Menu Band", W / 2, H * 0.50, 110, INK, 800); + text(ctx, "the polyrhythm trainer — in your menu bar", W / 2, H * 0.50 + 96, 44, "rgba(60,50,80,0.9)", 600); + text(ctx, "free on the Mac App Store", W / 2, H * 0.50 + 182, 50, "rgba(60,50,80,0.9)", 700); + text(ctx, "menuband.app", W / 2, H * 0.50 + 262, 58, INK, 800); + ctx.restore(); + } else { + const { sect, specs } = circleStates(t); + // section-entry pop + const enter = easeOut(clamp01((t - sect.t0) / 0.5)); + const alpha = 0.25 + 0.75 * enter; + + if (sc.name === "intro") { + const e = easeOut(clamp01(t / 0.8)); + ctx.save(); ctx.globalAlpha = e; + const ipx = 250; + drawIcon(ctx, W / 2 - ipx / 2, H * 0.135, ipx, new Set(litAt(stripNotes, t).map((mm) => ((mm % 12) + 12) % 12 % 5))); + text(ctx, "Menu Band", W / 2, H * 0.135 + ipx + 66, 100, INK, 800); + ctx.restore(); + const row = rowSpecs(specs, H * 0.60, 205); + for (const s of row) drawPolyCircle(ctx, { ...s, alpha }); + spawnDotParticles(row, t, dt); + } else { + // big pattern label + ctx.save(); ctx.globalAlpha = alpha; + text(ctx, sect.label, W / 2, H * 0.185, 148, INK, 800); + ctx.restore(); + const row = rowSpecs(specs, H * 0.465); + for (const s of row) { + const grow = 0.9 + 0.1 * enter; + drawPolyCircle(ctx, { ...s, R: s.R * grow, alpha }); + } + spawnDotParticles(row, t, dt); + } + + const cap = CAPTIONS[sc.name]; + if (cap) { + const a = easeOut(clamp01(local * 4)) * (1 - easeOut(clamp01((local - 0.86) / 0.14))); + if (a > 0) { + ctx.save(); ctx.globalAlpha = a; + text(ctx, cap[0], W / 2, H * 0.80, 82, INK, 800); + text(ctx, cap[1], W / 2, H * 0.80 + 82, 42, "rgba(60,50,80,0.88)", 600); + ctx.restore(); + } + } + } + + particles.stepAndDraw(dt); + vignette(ctx); +} + +// a note leaves the struck dot itself — each circle sprays its own color +function spawnDotParticles(row, t, dt) { + for (const s of row) { + for (const n of laneOnsets.get(s.lane)(t - dt, t)) { + const step = Math.round((((n.t - sectionAt(n.t).t0) % CYCLE) / CYCLE) * s.count) % s.count; + const a = -Math.PI / 2 + (step / s.count) * (Math.PI * 2); + particles.spawnNote(s.cx + Math.cos(a) * (s.R / 56) * 45, s.cy + Math.sin(a) * (s.R / 56) * 45, s.color, false); + } + } +} + +await renderVideo({ + canvas, audioPath: `${OUT}/${SLUG}.mp3`, outPath: `${OUT}/base-${SLUG}.mp4`, + total: TOTAL, drawFrame, label: "menuband polyrhythm sim", +}); +writeMeta(SLUG, TOTAL, SCENES); diff --git a/slab/menuband/Sources/MenuBand/AppDelegate.swift b/slab/menuband/Sources/MenuBand/AppDelegate.swift index 34ab637487..4fe4aec089 100644 --- a/slab/menuband/Sources/MenuBand/AppDelegate.swift +++ b/slab/menuband/Sources/MenuBand/AppDelegate.swift @@ -119,6 +119,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { private var isPopoverPanelShown: Bool { popoverPanel?.isVisible == true } private lazy var pianoWaveformWindowDelegate = PianoWaveformWindowDelegate(menuBand: menuBand) + private lazy var reverseWaveformHUD = ReverseWaveformHUD(menuBand: menuBand) private var appBeforePopover: NSRunningApplication? private var appBeforeFocusCapture: NSRunningApplication? private var keyboardPerformanceFocusActive = false @@ -448,6 +449,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } private var trackpadSurfaceEnergy = TrackpadSurfaceEnergy() private var trackpadMembrane = TrackpadMembraneSimulation() + private var polyrhythmTrainer = PolyrhythmTrainerClock() private var trackpadEnergyTimer: Timer? private var trackpadOverlayLastDraw: Double = 0 /// Keep the last percussion surface readable after the final lift, like @@ -516,6 +518,33 @@ final class AppDelegate: NSObject, NSApplicationDelegate { guard self.pitchBendCursorPushed || self.keyboardPerformanceFocusActive else { return false } + let slashAction = Self.trackDrumSlashAction( + keyCode: keyCode, + flags: NSEvent.ModifierFlags(rawValue: UInt(flags.rawValue)) + ) + if let slashAction, isDown, self.trackpadPadMode == .skin { + if !isRepeat { + DispatchQueue.main.async { + switch slashAction { + case .trainer: self.togglePolyrhythmTrainer() + case .help: Self.openTips() + } + } + } + return true + } + let rateDelta = Self.trackDrumRateDelta( + keyCode: keyCode, + flags: NSEvent.ModifierFlags(rawValue: UInt(flags.rawValue)) + ) + if let rateDelta, self.trackpadPadMode == .skin, + self.polyrhythmTrainer.isActive { + if isDown && !isRepeat { + DispatchQueue.main.async { self.changePolyrhythmRate(by: rateDelta) } + } + return true + } + // These two ⌥⌘ chords are claimed globally outside Menu Band: // D toggles the Dock and X enters Slab's prox-keyboard focus. While // Menu Band owns performance focus they are musical sus chords. Sink @@ -1098,6 +1127,21 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } button.addSubview(dropTarget) } + menuBand.onRewindChanged = { [weak self] reversing, levels in + guard let self else { return } + if reversing { + let screen = self.pitchBendOverlay?.screen + ?? self.statusItem?.button?.window?.screen + ?? NSScreen.main + self.reverseWaveformHUD.show( + levels: levels, + above: self.pitchBendOverlay?.frame, + on: screen + ) + } else { + self.reverseWaveformHUD.hide() + } + } updateIcon() // Pre-build the waveform strip panel so the first note press @@ -1432,6 +1476,24 @@ final class AppDelegate: NSObject, NSApplicationDelegate { self.exitPerformanceFocusFromEscape() return true } + let slashAction = Self.trackDrumSlashAction( + keyCode: keyCode, flags: flags + ) + if let slashAction, self.trackpadPadMode == .skin, + (self.pitchBendCursorPushed || self.keyboardPerformanceFocusActive) { + if isDown && !isRepeat { + switch slashAction { + case .trainer: self.togglePolyrhythmTrainer() + case .help: Self.openTips() + } + } + return true + } + if let rateDelta = Self.trackDrumRateDelta(keyCode: keyCode, flags: flags), + self.trackpadPadMode == .skin, self.polyrhythmTrainer.isActive { + if isDown && !isRepeat { self.changePolyrhythmRate(by: rateDelta) } + return true + } if isDown && MenuBandShortcutPreferences.layoutShortcut.matches( keyCode: UInt32(keyCode), modifiers: MenuBandShortcut.carbonModifiers(from: flags) @@ -3934,6 +3996,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { /// Closes with a short fade-out (~140 ms) so the popover dissolves /// the way standard macOS menu pop-ups do, instead of cutting away. private func closePopover(dismissFloatingPanel: Bool = true) { + menuBand.closeInputInterface() // Tear down monitors immediately so a stray click during the // fade can't re-trigger close. if let m = clickAwayMonitor { NSEvent.removeMonitor(m); clickAwayMonitor = nil } @@ -4982,6 +5045,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate { + "lifted=\(changes.lifted.count) active=\(changes.active.count)" ) } + if polyrhythmTrainer.isActive { + for point in changes.began { + // Score from the hardware callback clock, not from whenever + // the main thread gets around to drawing the result. The + // contact's normalized x picks the circle: equal vertical + // bands left to right, so each finger individuates a rhythm. + polyrhythmTrainer.registerTap( + at: callbackTime, normalizedX: Double(point.x) + ) + } + } let touches = changes.active.map(\.point) let priorTouchCount = mtTouches.count mtTouches = touches @@ -5046,19 +5120,22 @@ final class AppDelegate: NSObject, NSApplicationDelegate { if pitchBendOverlay?.isVisible != true { showPitchBendOverlay() } - updateTrackpadOverlayIfDue( - force: touches.count != priorTouchCount - ) + // Audio already staged off-main. Let the display clock pick up + // contact changes instead of forcing a WindowServer commit for + // every rapid down/up edge. + updateTrackpadOverlayIfDue() } else if priorTouchCount > 0, Self.shouldFadeTrackpadOverlayAfterLift( performanceSessionActive: trackpadPerformanceSessionActive ) { // Preserve the final contact/energy state long enough to read, // then ease it away on the same rhythm as the key-label ghost. - pitchBendOverlay?.fadeOut( - after: Self.trackpadOverlayIdleHold, - duration: Self.trackpadOverlayFadeDuration - ) + if !polyrhythmTrainer.isActive { + pitchBendOverlay?.fadeOut( + after: Self.trackpadOverlayIdleHold, + duration: Self.trackpadOverlayFadeDuration + ) + } } } } @@ -5427,13 +5504,24 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } self.trackpadSurfaceEnergy.decay(to: CACurrentMediaTime()) if self.trackpadPadMode == .skin || self.trackpadPadMode == .synth { + let now = CACurrentMediaTime() + // Quiet reference cues: distinct enough to follow, but well + // below a played TrackDrum strike. The guide is a clock, not + // an accompaniment. + for rhythm in self.polyrhythmTrainer.tick(at: now) { + switch rhythm { + case 0: self.menuBand.engineDrum(.block, velocity: 18) + case 1: self.menuBand.engineDrum(.snap, velocity: 14) + default: self.menuBand.engineDrum(.cowbell, velocity: 12) + } + } self.trackpadMembrane.advance( - to: CACurrentMediaTime(), touches: self.mtTouches + to: now, touches: self.mtTouches ) self.updateTrackpadOverlayIfDue() } } - timer.tolerance = 1.0 / 120.0 + timer.tolerance = 1.0 / 240.0 RunLoop.main.add(timer, forMode: .common) trackpadEnergyTimer = timer } @@ -5511,6 +5599,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { setTrackpadFighterSuppressed(true) #endif trackpadPadMode = useTrackDrum ? .skin : .fx + polyrhythmTrainer.stop() #if MAC_APP_STORE trackpadPluginCaptureActive = useTrackDrum trackpadPlugin.setCaptureEnabled(useTrackDrum) @@ -5646,14 +5735,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } activateDefaultTrackpadDrum() showPitchBendOverlay() - pitchBendOverlay?.fadeOut( - after: Self.trackpadOverlayIdleHold, - duration: Self.trackpadOverlayFadeDuration - ) + if !polyrhythmTrainer.isActive { + pitchBendOverlay?.fadeOut( + after: Self.trackpadOverlayIdleHold, + duration: Self.trackpadOverlayFadeDuration + ) + } debugLog("trackpad pad mode = skin (Tab handoff)") return #endif trackpadFXPrimaryContact.reset() + polyrhythmTrainer.stop() trackpadPadMode = Self.trackpadPadModeAfterTab(trackpadPadMode) if trackpadPadMode != .fx { pitchBendEndTimer?.invalidate() @@ -6160,6 +6252,47 @@ final class AppDelegate: NSObject, NSApplicationDelegate { && !NSEvent.modifierFlags.contains(.shift) } + private func togglePolyrhythmTrainer() { + guard trackpadPadMode == .skin, + pitchBendCursorPushed || keyboardPerformanceFocusActive else { return } + polyrhythmTrainer.cyclePattern(at: CACurrentMediaTime()) + if trackpadEnergyTimer == nil { startTrackpadEnergyDisplay() } + showPitchBendOverlay() + debugLog(polyrhythmTrainer.isActive + ? "TrackDrum polyrhythm trainer = \(polyrhythmTrainer.pattern.label)" + : "TrackDrum polyrhythm trainer = off") + } + + private func changePolyrhythmRate(by delta: Int) { + polyrhythmTrainer.changeRate(by: delta, at: CACurrentMediaTime()) + updateTrackpadOverlayIfDue(force: true) + debugLog("TrackDrum polyrhythm rate = \(polyrhythmTrainer.bpm) bpm") + } + + enum TrackDrumSlashAction: Equatable { case trainer, help } + + static func trackDrumSlashAction( + keyCode: UInt16, + flags: NSEvent.ModifierFlags + ) -> TrackDrumSlashAction? { + guard keyCode == UInt16(kVK_ANSI_Slash), + !flags.contains(.command), !flags.contains(.option), + !flags.contains(.control) else { return nil } + return flags.contains(.shift) ? .help : .trainer + } + + static func trackDrumRateDelta( + keyCode: UInt16, + flags: NSEvent.ModifierFlags + ) -> Int? { + guard !flags.contains(.command), !flags.contains(.option), + !flags.contains(.control) else { return nil } + if keyCode == UInt16(kVK_ANSI_Minus) { return -5 } + // The same physical key produces = or shifted +; both increase rate. + if keyCode == UInt16(kVK_ANSI_Equal) { return 5 } + return nil + } + private func showPitchBendOverlay() { #if MAC_APP_STORE guard !trackDrumInstallPromptActive else { return } @@ -6172,11 +6305,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } let overlay = ensurePitchBendOverlay() if showingTracktrampSkin { + let rhythm = polyrhythmTrainer.snapshot(at: CACurrentMediaTime()) overlay.showTracktramp( trackpadMembrane.snapshot(), touches: mtTouches, + polyrhythm: rhythm, atScreenPoint: trackpadOverlayAnchor( - imageSize: TracktrampMetalView.logicalSize, + imageSize: PitchBendCursorOverlayWindow.tracktrampSurfaceSize( + polyrhythm: rhythm), fallback: pitchBendLockScreenPoint ) ) @@ -6310,11 +6446,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate { guard let overlay = pitchBendOverlay, overlay.isVisible else { return } trackpadOverlayLastDraw = CACurrentMediaTime() if showingTracktrampSkin { + let rhythm = polyrhythmTrainer.snapshot(at: CACurrentMediaTime()) overlay.updateTracktramp( trackpadMembrane.snapshot(), touches: mtTouches, + polyrhythm: rhythm, atScreenPoint: trackpadOverlayAnchor( - imageSize: TracktrampMetalView.logicalSize, + imageSize: PitchBendCursorOverlayWindow.tracktrampSurfaceSize( + polyrhythm: rhythm), fallback: pitchBendLockScreenPoint ) ) @@ -6331,10 +6470,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate { /// from delaying the next input callback by a complete 8 ms touch frame. private func updateTrackpadOverlayIfDue(force: Bool = false) { let now = CACurrentMediaTime() - // Touch and sound stay at the hardware's 125 Hz cadence, but this - // decorative thumbnail must not compete with notation/UI animation. - // The Metal skin submits at most once per display frame and reuses its - // cached texture; input and sound continue independently at 125 Hz. + // Keep WindowServer work at a stable 60 Hz even though input and audio + // remain at 125 Hz. Motion is elapsed-time based and tap scoring uses + // callback timestamps, so this changes neither speed nor accuracy. guard force || now - trackpadOverlayLastDraw >= 1.0 / 60.0 else { return } updatePitchBendOverlayImage() } @@ -6488,6 +6626,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate { if keyboardPerformanceFocusActive, trackpadPadMode == .skin { releaseTrackpadPercussion() trackpadSkinTouches.removeAll() + // The guide owns a continuous clock even when the player's hands + // lift. Keep its display timer and panel alive between strikes. + if polyrhythmTrainer.isActive { + showPitchBendOverlay() + return + } trackpadEnergyTimer?.invalidate() trackpadEnergyTimer = nil startFxRelease() @@ -6510,6 +6654,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { // somehow already cleared. pitchBendModeLatched = false trackpadPerformanceSessionActive = false + polyrhythmTrainer.stop() #if !MAC_APP_STORE setTrackpadFighterSuppressed(pianoWaveformWindowDelegate.isShown) #endif diff --git a/slab/menuband/Sources/MenuBand/MenuBandController.swift b/slab/menuband/Sources/MenuBand/MenuBandController.swift index 1f00e3bb3b..3e60949630 100644 --- a/slab/menuband/Sources/MenuBand/MenuBandController.swift +++ b/slab/menuband/Sources/MenuBand/MenuBandController.swift @@ -71,6 +71,15 @@ final class MenuBandController { func setAudioInputDevice(uid: String?) { synth.setPreferredInputDevice(uid: uid) } func setAudioOutputDevice(uid: String?) { synth.setPreferredOutputDevice(uid: uid) } func setAudioMonitorChannel(_ channel: Int) { synth.setMonitorInputChannel(channel) } + /// Closing the input UI is an ownership boundary: monitoring is no longer + /// visible, so revoke its persistent preference/pin and release CoreAudio + /// input immediately. Tape/sample recording pins still prevent shutdown. + func closeInputInterface() { + if inputMonitoringEnabled { + inputMonitoringEnabled = false + } + synth.stopUnpinnedHotMicNow() + } private var keyTap: KeyEventTap? private var heldNotes: [UInt16: UInt8] = [:] /// Chord EXTENSION voices for a held key, keyed by interval (semitones @@ -1236,21 +1245,29 @@ final class MenuBandController { /// True while the spacebar reverse-replay is sounding — drives the /// popover waveform strip's direction indicator (◀ reverse vs ▶ live). private(set) var isRewinding = false + /// Momentary reverse UI follows the actual controller gesture regardless + /// of whether the event arrived through local or global key capture. + var onRewindChanged: ((Bool, [Float]) -> Void)? func rewind() { isRewinding = true DispatchQueue.main.async { [weak self] in - self?.synth.playReverse() + guard let self else { return } + let didPlay = self.synth.playReverse() + self.isRewinding = didPlay + self.onRewindChanged?(didPlay, self.synth.rewindPreviewLevels()) } } - /// Spacebar released — stop reverse playback, banking the playhead so - /// the next press resumes from the same reverse point (deeper into the - /// tape). Playing a note resets that cursor to the live head. + /// Spacebar released — stop reverse playback and lift the needle back to + /// the session anchor. Quick presses therefore repeat the same phrase; + /// playing a real note drops the anchor so the next dive starts at now. func rewindRelease() { isRewinding = false DispatchQueue.main.async { [weak self] in - self?.synth.releaseReverse() + guard let self else { return } + self.synth.releaseReverse() + self.onRewindChanged?(false, []) } } @@ -1259,6 +1276,11 @@ final class MenuBandController { /// Reverse playback progress (0…1) or nil — for the strip's playhead. func rewindProgress() -> Double? { synth.rewindProgress() } + func rewindClipProgress() -> Double? { synth.rewindClipProgress() } + /// Live-input peak since last read — what's being played NOW, clean of + /// the reverse playback itself (the tape tap sits upstream of the reverse + /// player). Drives the HUD's dub bar. + func rewindLiveInputPeak() -> Float { synth.rewindLiveInputPeak() } func setBend(amount: Float, allChannels: Bool = false) { // No clamp here — the trackpad accumulator can swing past diff --git a/slab/menuband/Sources/MenuBand/MenuBandRewindVoice.swift b/slab/menuband/Sources/MenuBand/MenuBandRewindVoice.swift index c5e76ad07d..d9ead19b10 100644 --- a/slab/menuband/Sources/MenuBand/MenuBandRewindVoice.swift +++ b/slab/menuband/Sources/MenuBand/MenuBandRewindVoice.swift @@ -45,10 +45,9 @@ final class MenuBandRewindVoice { /// (~37 MB at 96 kHz mono float — fine.) Ring must exceed the reverse /// window (`captureSeconds`) with headroom. private let bufferSeconds: Double = 96.0 - /// Reverse window: a session (first press → next real note) can rewind - /// at most this far behind its anchor. Presses within a session RESUME - /// from where the last one stopped (see `sessionAnchor`/`consumedFrames`) - /// — they never re-add time. A new note re-anchors at the live head. + /// Reverse window: each held-space dive can reach this far behind the + /// session anchor. Releasing lifts the needle back to the anchor, making + /// rapid taps repeatable; a real note re-anchors at the live head. let captureSeconds: Double = 90.0 /// Generation token for the in-flight reverse one-shot. Bumped on every /// `playReverse` and `release` so a deferred release-fade can tell whether @@ -103,7 +102,7 @@ final class MenuBandRewindVoice { private var ringSampleRate: Double = 0 private let ringLock = NSLock() - // MARK: Reverse session (persistent cursor across presses) + // MARK: Reverse session (fixed anchor across presses) /// Absolute frame count (`framesWritten`) at the FIRST press of the /// current reverse session — the fixed "now" edge the whole session @@ -111,15 +110,11 @@ final class MenuBandRewindVoice { /// live head. Guarded by `ringLock` (reset can arrive from any thread /// via `resetReverseAnchor`). private var sessionAnchor: Int? = nil - /// Frames already reverse-played this session, banked on release (and - /// folded in by `settleInFlightLocked`). Each press resumes - /// `consumedFrames` behind the anchor — the same reverse point the last - /// press stopped at — never the top of the window again. + /// Frames traversed by the current dive. This is folded in if a duplicate + /// press arrives without release, then reset to zero when the needle lifts. private var consumedFrames = 0 /// The session's fixed window length in frames (`captureSeconds` at the - /// anchor's sample rate). Presses never re-add time: once a session has - /// consumed this much tape, further presses are silent until a note - /// resets the anchor. + /// anchor's sample rate). private var sessionWantFrames = 0 /// Frame length of the in-flight one-shot, for the settle accounting. private var lastClipFrames = 0 @@ -139,6 +134,15 @@ final class MenuBandRewindVoice { /// (exact, drift-free) instead of a free-running per-frame counter. private var playStart: Double = 0 private var clipDuration: Double = 0 + /// Display envelope of the exact scheduled reverse clip, ordered as tape + /// time (oldest → newest) so the HUD can put now at its right edge. + private var latestPreviewLevels: [Float] = [] + /// Seconds of tape the preview envelope covers — the recent audible span, + /// not the whole scheduled clip. The HUD's head clock runs against this. + private var previewDuration: Double = 0 + /// Max-held peak of the live input since the HUD's dub bar last read it. + /// Guarded by `ringLock` (written on the IO thread in `feed`). + private var liveInputPeakHold: Float = 0 // MARK: Attach @@ -247,6 +251,11 @@ final class MenuBandRewindVoice { // // Mixed in, not overwritten, so the dub sits ON the existing music // instead of erasing it. Clamped because two full-scale signals sum. + // Peak of THIS buffer — the live input alone, since this tap sits + // upstream of where reverse playback joins. Max-held until the HUD's + // dub bar takes it, so a transient can't fall between two UI frames. + var livePeak: Float = 0 + if reverseActive, let head = reverseReadHeadLocked() { // Absolute frame `a` lives at ring index writeIdx-1-(framesWritten-a). var idx = (writeIdx - 1 - (framesWritten - head)) % cap @@ -255,18 +264,22 @@ final class MenuBandRewindVoice { let l = ch[0] let r = ch[1] for i in 0..= cap { idx = 0 } } } else { let m = ch[0] for i in 0..= cap { idx = 0 } } } + liveInputPeakHold = Swift.max(liveInputPeakHold, livePeak) writeIdx = idx framesWritten += frames ringLock.unlock() } + /// Max-held live-input peak since the last take — read-and-clear, so the + /// HUD's dub bar sees every transient exactly once regardless of how the + /// UI frame rate and the audio buffer cadence interleave. + func takeLiveInputPeak() -> Float { + ringLock.lock() + let p = liveInputPeakHold + liveInputPeakHold = 0 + ringLock.unlock() + return p + } + /// Absolute frame the reverse pass is reading right now — the needle. The /// in-flight clip was snapshotted at press time, so there is no live read /// pointer to ask; the position comes from the clip's wall-clock progress @@ -337,9 +365,9 @@ final class MenuBandRewindVoice { // Fold any still-in-flight press into the cursor first, so a press // that arrives without an intervening release can't lose position. settleInFlightLocked() - // Session cursor: the first press anchors "now"; every later press - // resumes from the same reverse point the last one stopped at - // (anchor − consumed). Re-anchor only when there is no session (a + // Session cursor: the first press anchors "now". Duplicate downs can + // continue an in-flight dive; ordinary release resets consumed to 0, + // making the next press repeat from the anchor. Re-anchor only when there is no session (a // note reset it — see `resetReverseAnchor`), the ring was // reallocated under us (anchor > total), or the tape behind the // cursor has been fully overwritten. @@ -352,8 +380,7 @@ final class MenuBandRewindVoice { sessionWantFrames = Int(captureSeconds * rate) } let cursorAbs = (sessionAnchor ?? total) - consumedFrames - // What's left to reverse: bounded by the session window (no re-added - // time — the window is fixed at the first press) and by how much + // What's left to reverse: bounded by the fixed session window and by how much // tape behind the cursor still survives in the ring. let count = Swift.min(sessionWantFrames - consumedFrames, cursorAbs - oldest) guard count >= 256 else { ringLock.unlock(); return false } @@ -371,13 +398,27 @@ final class MenuBandRewindVoice { } ringLock.unlock() + // Normalize the snapshot to conservative headroom. The captured tape + // has already crossed the master limiter, but reverse joins the live + // signal downstream of that limiter; 0.68 leaves room for the two to + // overlap. Cap upward gain so a nearly-silent tape never turns its + // noise floor into a loud reverse wash. + var peak: Float = 0 + for sample in reversed { peak = max(peak, abs(sample)) } + if peak > 0.0005 { + let gain = min(2.5, 0.68 / peak) + if abs(gain - 1) > 0.001 { + for i in reversed.indices { reversed[i] *= gain } + } + } + // Declick: the window begins and ends on an arbitrary mid-waveform // sample, so jumping straight from silence to that value (on press) // and back (at the tail) snaps a click. A short raised-cosine fade at // both ends ramps those discontinuities away — the "very slight fade // in when reverse starts" that kills the spacebar pop, plus a matching // tail fade so the one-shot lands in silence cleanly. - let fade = Swift.min(count / 2, Swift.max(1, Int(rate * 0.006))) + let fade = Swift.min(count / 2, Swift.max(1, Int(rate * 0.008))) if fade > 1 { for i in 0..= 0 { + if abs(reversed[scan]) > 0.004 { audibleFrames = scan + 1; break } + scan -= 1 + } + // A beat of older silence pads the left edge so the phrase's tail-out + // is visible; a silent tape still shows a believable short window. + let visibleFrames = audibleFrames > 0 + ? Swift.min(count, audibleFrames + Int(rate * 0.25)) + : Swift.min(count, Int(rate * 1.5)) + let previewColumns = 192 + var preview = [Float](repeating: 0, count: previewColumns) + for column in 0.. Double? { guard clipDuration > 0, sessionWantFrames > 0 else { return nil } @@ -483,6 +556,20 @@ final class MenuBandRewindVoice { return Swift.min(1, frames / Double(sessionWantFrames)) } + /// Audio-clock position through the HUD's visible span — the recent + /// audible tape its envelope covers, not the full scheduled clip. The + /// head therefore crosses the strip in exactly the time the audible + /// reverse takes, then rests at the far edge while any trailing + /// (older, silent) tape plays out. + func currentClipProgress() -> Double? { + guard playStart > 0 else { return nil } + let span = previewDuration > 0 ? previewDuration : clipDuration + guard span > 0 else { return nil } + return Swift.min(1, Swift.max(0, (CACurrentMediaTime() - playStart) / span)) + } + + func reversePreviewLevels() -> [Float] { latestPreviewLevels } + /// Space released — the needle snaps back to NOW, and the reverse voice /// stops. Space is a momentary excursion: while it's held you dive back /// through the tape, and letting go drops you at the live record head @@ -516,7 +603,7 @@ final class MenuBandRewindVoice { DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) { [weak self] in guard let self = self, self.playGeneration == gen else { return } if self.player.isPlaying { self.player.stop() } - self.mixer.outputVolume = 1.0 + self.mixer.outputVolume = 0.88 } } diff --git a/slab/menuband/Sources/MenuBand/MenuBandSampleVoice.swift b/slab/menuband/Sources/MenuBand/MenuBandSampleVoice.swift index db6a2e6dbf..397c9bc8f2 100644 --- a/slab/menuband/Sources/MenuBand/MenuBandSampleVoice.swift +++ b/slab/menuband/Sources/MenuBand/MenuBandSampleVoice.swift @@ -289,9 +289,10 @@ final class MenuBandSampleVoice { } // No launch-time hot-mic prewarm: opening the input device here made // macOS surface the mic-mode HUD (Standard / Voice Isolation) at - // EVERY launch, even when the user never monitors or records. The - // mic now opens only when something actually needs it — monitoring - // toggled on, or the first record-key press (which pays the + // EVERY launch — and lit the orange privacy indicator on an instrument + // with no visible input interface — even when the user never monitors + // or records. The mic now opens only when something actually needs it: + // monitoring toggled on, or the first record-key press (which pays the // documented ~50–200 ms cold start once; the mic then stays hot for // `hotMicIdleSeconds` so subsequent takes are instant). } @@ -761,6 +762,65 @@ final class MenuBandSampleVoice { } } + /// Stop capture now when no recording consumer still owns it. UI close + /// uses this instead of the normal 30-second re-recording grace period. + func stopUnpinnedHotMicNow() { + guard !recording, hotMicPinReasons.isEmpty else { return } + hotMicStopWork?.cancel() + hotMicStopWork = nil + if inputTapInstalled { + recordEngine.inputNode.removeTap(onBus: 0) + inputTapInstalled = false + } + if monitorOutputTapInstalled { + recordEngine.mainMixerNode.removeTap(onBus: 0) + monitorOutputTapInstalled = false + } + inputMonitorPlayer.stop() + inputMonitorQueueLock.withLock { inputMonitorQueuedBuffers = 0 } + recordEngine.stop() + inputConverter = nil + inputFormat = nil + boundInputDeviceID = 0 + NSLog("MenuBand SampleVoice: unpinned microphone stopped") + } + + /// Release microphone ownership immediately during app termination. + /// The normal idle path deliberately lingers for fast re-recording, but + /// shutdown must not leave that timer, the input tap, or the dedicated + /// record engine alive while AppKit is tearing down the process. + func shutdown() { + hotMicStopWork?.cancel() + hotMicStopWork = nil + monitorConfigRecovery?.cancel() + monitorConfigRecovery = nil + hotMicPinReasons.removeAll() + recordingRequested = false + recording = false + onInputBuffer = nil + onLevel = nil + inputMonitoringEnabled = false + inputMonitorPlayer.stop() + inputMonitorQueueLock.withLock { inputMonitorQueuedBuffers = 0 } + if inputTapInstalled { + recordEngine.inputNode.removeTap(onBus: 0) + inputTapInstalled = false + } + if monitorOutputTapInstalled { + recordEngine.mainMixerNode.removeTap(onBus: 0) + monitorOutputTapInstalled = false + } + recordEngine.stop() + inputConverter = nil + inputFormat = nil + boundInputDeviceID = 0 + if let observer = monitorConfigObserver { + NotificationCenter.default.removeObserver(observer) + monitorConfigObserver = nil + } + NSLog("MenuBand SampleVoice: microphone shutdown complete") + } + /// Replace the global Piano Sampler recording with audio supplied by an /// in-process source such as CDJ Radio. Unlike microphone recording this /// is an instantaneous, explicit handoff: no input permission, no key diff --git a/slab/menuband/Sources/MenuBand/MenuBandSynth.swift b/slab/menuband/Sources/MenuBand/MenuBandSynth.swift index df5ccba9e5..72feb9b50f 100644 --- a/slab/menuband/Sources/MenuBand/MenuBandSynth.swift +++ b/slab/menuband/Sources/MenuBand/MenuBandSynth.swift @@ -191,16 +191,16 @@ final class MenuBandSynth { /// else holds the device at 512). When Menu Band IS the sole client the /// device drops to this size. /// - /// 512 @ 96 kHz ≈ 5.3 ms — a deliberately conservative budget. The full + /// 256 @ 96 kHz ≈ 2.7 ms (5.8 ms at 44.1 kHz). The full /// synth stack (GM C core + DLS MIDISynth + per-note sample voices + /// percussion + fx + limiter) must finish WITHIN this window every cycle /// or CoreAudio underruns and you hear a click/pop, in any playback. On a /// memory-constrained / few-core machine an ultra-low buffer (we used to /// dive to the device minimum, 32 frames / 0.33 ms) can't survive normal - /// scheduling jitter, so it popped constantly. 5.3 ms is still well below - /// the perceptual threshold for a keyboard instrument; bump it back down - /// only on a machine with headroom to spare. - private static let targetIOBufferFrames: UInt32 = 512 + /// scheduling jitter, so it popped constantly. TrackDrum stages sound + /// off-main; 256 keeps useful scheduler headroom without accepting the + /// 11.6 ms buffer delay of 512 frames at 44.1 kHz. + private static let targetIOBufferFrames: UInt32 = 256 /// True once we've successfully taken hog mode on the active /// output device. Tracks the device ID alongside so we can /// release the right one on shutdown / device switch. @@ -433,6 +433,9 @@ final class MenuBandSynth { func unpinHotMic(reason: String) { sampleVoice.removeHotMicPin(reason) } + func stopUnpinnedHotMicNow() { + sampleVoice.stopUnpinnedHotMicNow() + } // Tap-driven ring buffer for the popover's live waveform display. private static let waveformRingSize = 4096 @@ -501,7 +504,9 @@ final class MenuBandSynth { // Duplex monitor: attached only when monitoring is actually wanted // AND the input/output resolve to the same interface — see // `duplexMonitorEligible` for why an unconditional attach kills - // the whole engine when they differ. + // the whole engine when they differ. Attaching unconditionally also + // made CoreAudio hold audio-in (orange privacy indicator) on a + // menu-bar instrument that was never monitoring. syncInputMonitorGraph() // Speech easter egg: same pre-limiter sum bus, so spoken language // names ride the bend/space/echo fx. Idle (no player) until `speak`. @@ -994,17 +999,17 @@ final class MenuBandSynth { } /// Spacebar reverse-replay: play the master-output tape backwards from - /// the session's reverse cursor (first press anchors "now"; later - /// presses resume where the last one stopped). Returns false if there + /// the session anchor (first press anchors "now"; repeated presses dive + /// from that same point until a real note re-anchors it). Returns false if there /// wasn't enough captured audio to rewind (caller can cue a fallback). @discardableResult func playReverse() -> Bool { return rewindVoice.playReverse() } - /// Spacebar released — bank the reverse playhead into the session - /// cursor and stop the voice; the next press resumes from that same - /// reverse point. Playing a note resets the cursor to the live head + /// Spacebar released — fade and stop the voice, lifting the playhead back + /// to the session anchor so the next press repeats the dive. Playing a + /// note resets that anchor to the live head /// (see the `resetReverseAnchor` call in `noteOn`). func releaseReverse() { rewindVoice.release() @@ -1017,6 +1022,9 @@ final class MenuBandSynth { /// Reverse playback progress (0…1), or nil if not reversing — for the /// strip's exact, drift-free playhead. func rewindProgress() -> Double? { rewindVoice.reverseProgress() } + func rewindClipProgress() -> Double? { rewindVoice.currentClipProgress() } + func rewindPreviewLevels() -> [Float] { rewindVoice.reversePreviewLevels() } + func rewindLiveInputPeak() -> Float { rewindVoice.takeLiveInputPeak() } /// Route the trackpad pitch-bend / echo onto the spacebar tape playback /// (its own DRY inserts — see MenuBandRewindVoice), so moving the mouse @@ -2217,6 +2225,11 @@ final class MenuBandSynth { func stop() { engineLock.lock(); defer { engineLock.unlock() } + // The microphone uses SampleVoice's separate input-only engine, so it + // must be torn down even if the synth output engine never started or + // has already stopped. This is synchronous: application termination + // returns only after CoreAudio input ownership has been released. + sampleVoice.shutdown() guard started else { return } if let obs = configChangeObserver { NotificationCenter.default.removeObserver(obs) @@ -2260,6 +2273,11 @@ final class MenuBandSynth { // would otherwise leave the engine paused and the hit silent. Wake // it (and cancel any pending suspend) before staging the voices. _ = resumeAudioEngineIfNeeded() + // Percussion prints to the same tape as melodic notes (it joins the + // pre-limiter sum), so it re-syncs the reverse clock the same way — + // a Space press after drumming dives into the drums just played, + // not whatever tape an older session anchored. + rewindVoice.resetReverseAnchor() let p = max(-1.0, min(1.0, (Double(pan) - 64.0) / 63.0)) let depth: Float let hold: TimeInterval @@ -2282,6 +2300,7 @@ final class MenuBandSynth { func playReverseKick(velocity: UInt8, pan: UInt8) { guard started else { return } _ = resumeAudioEngineIfNeeded() + rewindVoice.resetReverseAnchor() let p = max(-1.0, min(1.0, (Double(pan) - 64.0) / 63.0)) triggerMelodicDuck(depth: 0.38, velocity: velocity, hold: 0.12) percussion.playReverseKick(velocity: velocity, pan: p) @@ -2291,6 +2310,7 @@ final class MenuBandSynth { func playDrumSkin(strike: CGPoint, anchors: [CGPoint], velocity: UInt8) { guard started else { return } _ = resumeAudioEngineIfNeeded() + rewindVoice.resetReverseAnchor() let zone = MenuBandPercussion.drumSkinZone(at: strike) let depth: Float = zone == .kick ? 0.40 : (zone == .tom ? 0.30 : (zone == .snare ? 0.22 : 0.10)) @@ -2303,6 +2323,7 @@ final class MenuBandSynth { func playSynthSurface(strike: CGPoint, anchors: [CGPoint], velocity: UInt8) { guard started else { return } _ = resumeAudioEngineIfNeeded() + rewindVoice.resetReverseAnchor() let zone = MenuBandPercussion.drumSkinZone(at: strike) triggerMelodicDuck(depth: zone == .kick ? 0.34 : 0.16, velocity: velocity, hold: 0.07) @@ -2314,6 +2335,7 @@ final class MenuBandSynth { velocity: UInt8, synthetic: Bool) { guard started else { return } _ = resumeAudioEngineIfNeeded() + rewindVoice.resetReverseAnchor() triggerMelodicDuck(depth: 0.10, velocity: velocity, hold: 0.04) percussion.playSurfaceLift(at: point, anchors: anchors, velocity: velocity, synthetic: synthetic) diff --git a/slab/menuband/Sources/MenuBand/PitchBendCursor.swift b/slab/menuband/Sources/MenuBand/PitchBendCursor.swift index 8680422e53..bc40c56825 100644 --- a/slab/menuband/Sources/MenuBand/PitchBendCursor.swift +++ b/slab/menuband/Sources/MenuBand/PitchBendCursor.swift @@ -1058,9 +1058,11 @@ private final class TrackDrumInstallCard: NSVisualEffectView { /// cursor so the chart visibly replaces it. final class PitchBendCursorOverlayWindow: NSPanel { static let trackDrumInstallSize = NSSize(width: 260, height: 126) + static let polyrhythmGap: CGFloat = 12 private let imageView = NSImageView() private let tracktrampView = TracktrampMetalView() + private let polyrhythmView = PolyrhythmTrainerView() private let installCard = TrackDrumInstallCard() private let installIcon = NSImageView() private let installTagline = NSTextField( @@ -1096,6 +1098,8 @@ final class PitchBendCursorOverlayWindow: NSPanel { tracktrampView.frame = frame tracktrampView.isHidden = true contentView?.addSubview(tracktrampView) + polyrhythmView.isHidden = true + contentView?.addSubview(polyrhythmView) installCard.material = .popover installCard.blendingMode = .behindWindow @@ -1142,6 +1146,7 @@ final class PitchBendCursorOverlayWindow: NSPanel { installAction = nil installCard.isHidden = true tracktrampView.isHidden = true + polyrhythmView.isHidden = true imageView.isHidden = false } @@ -1174,6 +1179,7 @@ final class PitchBendCursorOverlayWindow: NSPanel { /// small height field changes between frames; no NSImage is constructed. func showTracktramp(_ membrane: TrackpadMembraneSimulation.Snapshot, touches: [CGPoint], + polyrhythm: PolyrhythmTrainerSnapshot? = nil, atScreenPoint screenPoint: NSPoint) { fadeTimer?.invalidate() fadeTimer = nil @@ -1181,25 +1187,28 @@ final class PitchBendCursorOverlayWindow: NSPanel { ignoresMouseEvents = true installAction = nil installCard.isHidden = true - applyTracktrampFrame() + applyTracktrampFrame(polyrhythm: polyrhythm) imageView.isHidden = true tracktrampView.isHidden = false tracktrampView.update(membrane, touches: touches) + polyrhythmView.snapshot = polyrhythm alphaValue = 1 if !isVisible { orderFrontRegardless() } } func updateTracktramp(_ membrane: TrackpadMembraneSimulation.Snapshot, touches: [CGPoint], + polyrhythm: PolyrhythmTrainerSnapshot? = nil, atScreenPoint screenPoint: NSPoint) { anchorScreenPoint = screenPoint ignoresMouseEvents = true installAction = nil installCard.isHidden = true - applyTracktrampFrame() + applyTracktrampFrame(polyrhythm: polyrhythm) imageView.isHidden = true tracktrampView.isHidden = false tracktrampView.update(membrane, touches: touches) + polyrhythmView.snapshot = polyrhythm } /// Missing-helper state for the Tab-selected percussion surface. This is @@ -1213,6 +1222,7 @@ final class PitchBendCursorOverlayWindow: NSPanel { installAction = onInstall imageView.isHidden = true tracktrampView.isHidden = true + polyrhythmView.isHidden = true installCard.isHidden = false ignoresMouseEvents = false @@ -1238,12 +1248,46 @@ final class PitchBendCursorOverlayWindow: NSPanel { if !isVisible { orderFrontRegardless() } } - private func applyTracktrampFrame() { - let size = TracktrampMetalView.logicalSize - setFrame(NSRect(x: anchorScreenPoint.x - size.width / 2, - y: anchorScreenPoint.y - size.height / 2, - width: size.width, height: size.height), display: false) - tracktrampView.frame = NSRect(origin: .zero, size: size) + private func applyTracktrampFrame(polyrhythm: PolyrhythmTrainerSnapshot?) { + let size = Self.tracktrampSurfaceSize(polyrhythm: polyrhythm) + let panelFrame = NSRect(x: anchorScreenPoint.x - size.width / 2, + y: anchorScreenPoint.y - size.height / 2, + width: size.width, height: size.height) + if frame != panelFrame { setFrame(panelFrame, display: false) } + let tracktrampFrame = NSRect( + x: (size.width - TracktrampMetalView.logicalSize.width) / 2, + y: 0, + width: TracktrampMetalView.logicalSize.width, + height: TracktrampMetalView.logicalSize.height + ) + if tracktrampView.frame != tracktrampFrame { tracktrampView.frame = tracktrampFrame } + let trainerSize = PolyrhythmTrainerView.logicalSize( + rhythmCount: polyrhythm?.rhythms.count ?? 1 + ) + let polyrhythmFrame = NSRect( + x: (size.width - trainerSize.width) / 2, + y: TracktrampMetalView.logicalSize.height + Self.polyrhythmGap, + width: trainerSize.width, + height: trainerSize.height + ) + if polyrhythmView.frame != polyrhythmFrame { polyrhythmView.frame = polyrhythmFrame } + polyrhythmView.isHidden = polyrhythm == nil + } + + static func tracktrampSurfaceSize(polyrhythm: PolyrhythmTrainerSnapshot?) -> NSSize { + guard let polyrhythm else { return TracktrampMetalView.logicalSize } + return tracktrampSurfaceSize(rhythmCount: polyrhythm.rhythms.count) + } + + /// The surface grows sideways with the circle count so the trainer never + /// clips, while TrackDrum's own artwork stays centered at its fixed size. + static func tracktrampSurfaceSize(rhythmCount: Int) -> NSSize { + let trainer = PolyrhythmTrainerView.logicalSize(rhythmCount: rhythmCount) + return NSSize(width: max(TracktrampMetalView.logicalSize.width, + trainer.width), + height: TracktrampMetalView.logicalSize.height + + Self.polyrhythmGap + + trainer.height) } /// A new hardware contact reclaims a surface that is still visible but @@ -1302,6 +1346,7 @@ final class PitchBendCursorOverlayWindow: NSPanel { ignoresMouseEvents = true installAction = nil installCard.isHidden = true + polyrhythmView.isHidden = true tracktrampView.pause() orderOut(nil) } diff --git a/slab/menuband/Sources/MenuBand/PolyrhythmTrainer.swift b/slab/menuband/Sources/MenuBand/PolyrhythmTrainer.swift new file mode 100644 index 0000000000..541887b4a7 --- /dev/null +++ b/slab/menuband/Sources/MenuBand/PolyrhythmTrainer.swift @@ -0,0 +1,458 @@ +import AppKit + +/// One shared cycle rendered as N side-by-side clocks — one circle per +/// rhythm, so each finger can individuate a rhythm on the trackpad (left +/// band strikes the left circle, and so on). Keeping the clock pure makes +/// its boundary behavior testable without audio or AppKit timers. +struct PolyrhythmTrainerClock { + struct Pattern: Equatable { + let counts: [Int] + var label: String { counts.map(String.init).joined(separator: ":") } + init(_ counts: [Int]) { self.counts = counts } + } + + static let patterns = [ + Pattern([3, 2]), + Pattern([4, 3]), + Pattern([5, 4]), + Pattern([3, 4, 5]), + ] + + private(set) var isActive = false + private(set) var startedAt: CFTimeInterval = 0 + private(set) var patternIndex = 0 + private(set) var bpm = 75 + private var lastOrdinals: [Int] = [] + private var lastPulseAt: CFTimeInterval = -.infinity + private struct RecordedTap { + let at: CFTimeInterval + let phase: Double + let rhythmIndex: Int + let accuracy: Double + } + private var recordedTaps: [RecordedTap] = [] + var pattern: Pattern { Self.patterns[patternIndex] } + var cycleDuration: TimeInterval { + 60.0 / Double(bpm) * Double(pattern.counts[0]) + } + + mutating func start(at now: CFTimeInterval) { + isActive = true + startedAt = now + lastOrdinals = Array(repeating: -1, count: pattern.counts.count) + lastPulseAt = -.infinity + recordedTaps.removeAll(keepingCapacity: true) + } + + mutating func stop() { + isActive = false + lastOrdinals = [] + lastPulseAt = -.infinity + recordedTaps.removeAll(keepingCapacity: true) + } + + /// `/` walks a finite loop so the feature remains easy to dismiss: + /// off → 3:2 → 4:3 → 5:4 → 3:4:5 → off. + mutating func cyclePattern(at now: CFTimeInterval) { + if !isActive { + patternIndex = 0 + start(at: now) + } else if patternIndex + 1 < Self.patterns.count { + patternIndex += 1 + start(at: now) + } else { + stop() + } + } + + mutating func changeRate(by delta: Int, at now: CFTimeInterval) { + guard isActive, delta != 0 else { return } + let oldDuration = cycleDuration + let oldPhase = (max(0, now - startedAt) / oldDuration) + .truncatingRemainder(dividingBy: 1) + bpm = min(300, max(30, bpm + delta)) + startedAt = now - oldPhase * cycleDuration + lastOrdinals = Array(repeating: -1, count: pattern.counts.count) + } + + /// The trackpad splits into equal vertical bands, one per circle, + /// mirroring the on-screen left-to-right layout: for 3:2 the left half + /// strikes the 3-circle and the right half the 2-circle. + static func rhythmIndex(forNormalizedX x: Double, rhythmCount: Int) -> Int { + guard rhythmCount > 0 else { return 0 } + let clamped = min(max(x, 0), 1) + return min(rhythmCount - 1, Int(clamped * Double(rhythmCount))) + } + + private func phase(at now: CFTimeInterval) -> Double { + let cycle = max(0, now - startedAt) / cycleDuration + return cycle - floor(cycle) + } + + /// 0 on a grid line, 1 exactly between two grid lines of that rhythm. + private static func gridError(phase: Double, count: Int) -> Double { + abs(phase * Double(count) - (phase * Double(count)).rounded()) * 2 + } + + /// Route a strike to the circle under the finger's horizontal band and + /// score it against that circle's own grid ONLY — a tap on the 3-circle + /// is never excused by landing near a 2-circle beat. + mutating func registerTap(at now: CFTimeInterval, normalizedX: Double) { + record(at: now, rhythmIndex: Self.rhythmIndex( + forNormalizedX: normalizedX, rhythmCount: pattern.counts.count + )) + } + + /// Positionless fallback (no touch coordinate at the call site): place + /// the strike on the rhythm whose grid it most closely fits, ties going + /// to the leftmost circle. + mutating func registerTap(at now: CFTimeInterval) { + guard isActive else { return } + let phase = phase(at: now) + let index = pattern.counts.indices.min(by: { + Self.gridError(phase: phase, count: pattern.counts[$0]) + < Self.gridError(phase: phase, count: pattern.counts[$1]) + }) ?? 0 + record(at: now, rhythmIndex: index) + } + + /// Accuracy is normalized within half of the chosen rhythm's beat + /// interval. + private mutating func record(at now: CFTimeInterval, rhythmIndex: Int) { + guard isActive, pattern.counts.indices.contains(rhythmIndex) else { + return + } + let phase = phase(at: now) + let error = Self.gridError(phase: phase, count: pattern.counts[rhythmIndex]) + recordedTaps.append(RecordedTap( + at: now, phase: phase, rhythmIndex: rhythmIndex, + accuracy: 1 - min(1, error) + )) + recordedTaps = recordedTaps.filter { now - $0.at < 0.65 } + if recordedTaps.count > 12 { recordedTaps.removeFirst(recordedTaps.count - 12) } + } + + /// Indices of the rhythms whose beat boundary passed since the last + /// tick, left to right. Each index maps to its own click voice so the + /// circles stay audibly distinct. + mutating func tick(at now: CFTimeInterval) -> [Int] { + guard isActive else { return [] } + if lastOrdinals.count != pattern.counts.count { + lastOrdinals = Array(repeating: -1, count: pattern.counts.count) + } + let elapsed = max(0, now - startedAt) + var fired: [Int] = [] + for (index, count) in pattern.counts.enumerated() { + let ordinal = Int(floor(elapsed / cycleDuration * Double(count))) + if ordinal != lastOrdinals[index] { + fired.append(index) + lastOrdinals[index] = ordinal + } + } + if !fired.isEmpty { lastPulseAt = now } + return fired + } + + func snapshot(at now: CFTimeInterval) -> PolyrhythmTrainerSnapshot? { + guard isActive else { return nil } + let elapsed = max(0, now - startedAt) + let cycle = elapsed / cycleDuration + return PolyrhythmTrainerSnapshot( + phase: cycle - floor(cycle), + rhythms: pattern.counts.map { + PolyrhythmRhythmSnapshot( + count: $0, + step: Int(floor(cycle * Double($0))) % $0 + ) + }, + label: pattern.label, + bpm: bpm, + needleFlash: max(0, 1 - (now - lastPulseAt) / 0.12), + tapFeedback: recordedTaps.compactMap { tap in + let age = now - tap.at + guard age >= 0, age < 0.6 else { return nil } + return PolyrhythmTapFeedback( + phase: tap.phase, + rhythmIndex: tap.rhythmIndex, + accuracy: tap.accuracy, + opacity: 1 - age / 0.6 + ) + } + ) + } +} + +struct PolyrhythmRhythmSnapshot { + let count: Int + let step: Int +} + +struct PolyrhythmTrainerSnapshot { + let phase: Double + let rhythms: [PolyrhythmRhythmSnapshot] + let label: String + let bpm: Int + let needleFlash: Double + let tapFeedback: [PolyrhythmTapFeedback] +} + +struct PolyrhythmTapFeedback { + let phase: Double + let rhythmIndex: Int + let accuracy: Double + let opacity: Double +} + +/// Compact, distance-readable polyrhythm notation: one clock per rhythm, +/// laid side by side so each circle sits above the trackpad band that +/// strikes it. Dots are beats, the radial hand is shared time, and each +/// circle's center digit is its subdivision count. +final class PolyrhythmTrainerView: NSView { + static let circleSlotWidth: CGFloat = 100 + static let circleGap: CGFloat = 8 + static let sideMargin: CGFloat = 6 + static let fixedHeight: CGFloat = 116 + private static let faceRadius: CGFloat = 44 + private static let dotRadius: CGFloat = 34 + private static let handLength: CGFloat = 38 + private static let circleCenterY: CGFloat = 64 + + static func logicalSize(rhythmCount: Int) -> NSSize { + let circles = CGFloat(max(1, rhythmCount)) + return NSSize( + width: sideMargin * 2 + circles * circleSlotWidth + + (circles - 1) * circleGap, + height: fixedHeight + ) + } + + /// Left to right: accent, ink, then a blend for a third rhythm — three + /// voices that stay apart without adding loud new hues. + static func circleColors(accent: NSColor, ink: NSColor, + count: Int) -> [NSColor] { + let blend = accent.blended(withFraction: 0.55, of: ink) ?? accent + let palette = [accent, ink, blend] + return (0.. 0 ? color : ink).withAlphaComponent(0.78 + flash * 0.22).setStroke() + hand.lineWidth = 1.5 + flash * 2.5 + hand.stroke() + let hub = NSBezierPath(ovalIn: NSRect(x: center.x - 2.5, y: center.y - 2.5, + width: 5, height: 5)) + ink.setFill(); hub.fill() + + let label = "\(rhythm.count)" + let attrs: [NSAttributedString.Key: Any] = [ + .font: NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .bold), + .foregroundColor: ink.withAlphaComponent(0.88) + ] + let size = label.size(withAttributes: attrs) + label.draw(at: CGPoint(x: center.x - size.width / 2, + y: center.y - size.height - 3), + withAttributes: attrs) + } + + private func drawTapFeedback(_ feedback: [PolyrhythmTapFeedback], + center: CGPoint, accent: NSColor) { + for tap in feedback { + let angle = CGFloat.pi / 2 - CGFloat(tap.phase) * 2 * .pi + let point = CGPoint(x: center.x + cos(angle) * Self.dotRadius, + y: center.y + sin(angle) * Self.dotRadius) + let color: NSColor = tap.accuracy >= 0.7 + ? accent : (tap.accuracy >= 0.4 ? .systemOrange : .systemRed) + let mark = NSBezierPath(ovalIn: NSRect(x: point.x - 6, y: point.y - 6, + width: 12, height: 12)) + color.withAlphaComponent(CGFloat(tap.opacity) * 0.9).setStroke() + mark.lineWidth = 2 + mark.stroke() + } + } +} + +/// Headless render of the real guide stacked over TrackDrum artwork. This is +/// intentionally a QA door, not another product surface — reel tooling +/// composites these PNGs. +/// +/// Flags after `--render-polyrhythm`: +/// --pattern 3:2 colon-separated subdivision counts (e.g. 3:4:5) +/// --phase 0.25 cycle phase 0…1 (wraps; default 0.18) +/// --bpm 85 tempo readout + needle-flash timing (default 85) +/// --light | --dark appearance (light is the default; reels use light) +/// --scale 4 pixel scale (default 4) +/// --out /path.png output PNG (default /tmp/menuband-polyrhythm.png) +enum PolyrhythmTrainerCLI { + static func runIfRequested(_ args: [String]) -> Bool { + guard args.contains("--render-polyrhythm") else { return false } + func value(_ flag: String) -> String? { + guard let index = args.firstIndex(of: flag), index + 1 < args.count else { + return nil + } + return args[index + 1] + } + let output = value("--out") ?? "/tmp/menuband-polyrhythm.png" + let scale = max(1, Double(value("--scale") ?? "4") ?? 4) + let counts = (value("--pattern") ?? "3:2").split(separator: ":") + .compactMap { Int($0) }.filter { $0 >= 1 } + guard !counts.isEmpty else { + FileHandle.standardError.write(Data( + "polyrhythm: --pattern wants colon-separated counts like 3:2 or 3:4:5\n" + .utf8 + )) + exit(1) + } + let rawPhase = Double(value("--phase") ?? "0.18") ?? 0.18 + let phase = rawPhase - floor(rawPhase) + let bpm = min(300, max(30, Int(value("--bpm") ?? "85") ?? 85)) + let app = NSApplication.shared + app.setActivationPolicy(.prohibited) + let dark = args.contains("--dark") && !args.contains("--light") + app.appearance = NSAppearance(named: dark ? .darkAqua : .aqua) + + // Deterministic: the same flags always yield the same pixels, so a + // reel can sweep --phase frame by frame. The needle flash re-derives + // the clock's 0.12 s decay from phase distance to the nearest beat. + let cycleDuration = 60.0 / Double(bpm) * Double(counts[0]) + let sinceBeat = counts.map { count -> Double in + let beats = phase * Double(count) + return (beats - floor(beats)) / Double(count) * cycleDuration + }.min() ?? .infinity + let snapshot = PolyrhythmTrainerSnapshot( + phase: phase, + rhythms: counts.map { + PolyrhythmRhythmSnapshot( + count: $0, step: Int(floor(phase * Double($0))) % $0 + ) + }, + label: counts.map(String.init).joined(separator: ":"), + bpm: bpm, + needleFlash: max(0, 1 - sinceBeat / 0.12), + tapFeedback: [] + ) + + let size = PitchBendCursorOverlayWindow.tracktrampSurfaceSize( + rhythmCount: counts.count + ) + let root = NSView(frame: NSRect(origin: .zero, size: size)) + root.appearance = app.appearance + let skin = NSImageView(frame: NSRect( + x: (size.width - TracktrampMetalView.logicalSize.width) / 2, + y: 0, + width: TracktrampMetalView.logicalSize.width, + height: TracktrampMetalView.logicalSize.height + )) + skin.image = TrackpadDrumSkinPad.image(touches: [], energy: [], membrane: nil, + appearance: app.appearance) + root.addSubview(skin) + let trainerSize = PolyrhythmTrainerView.logicalSize(rhythmCount: counts.count) + let circles = PolyrhythmTrainerView(frame: NSRect( + x: (size.width - trainerSize.width) / 2, + y: TracktrampMetalView.logicalSize.height + + PitchBendCursorOverlayWindow.polyrhythmGap, + width: trainerSize.width, + height: trainerSize.height + )) + circles.appearance = app.appearance + circles.snapshot = snapshot + root.addSubview(circles) + root.displayIfNeeded() + + let pixelWidth = Int((size.width * scale).rounded()) + let pixelHeight = Int((size.height * scale).rounded()) + guard let bitmap = NSBitmapImageRep( + bitmapDataPlanes: nil, pixelsWide: pixelWidth, pixelsHigh: pixelHeight, + bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, + colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0 + ) else { return true } + bitmap.size = size + root.cacheDisplay(in: root.bounds, to: bitmap) + guard let png = bitmap.representation(using: .png, properties: [:]) else { + return true + } + do { try png.write(to: URL(fileURLWithPath: output)) } + catch { + FileHandle.standardError.write(Data("polyrhythm write failed: \(error)\n".utf8)) + exit(1) + } + print("polyrhythm \(pixelWidth)x\(pixelHeight) → \(output)") + return true + } +} diff --git a/slab/menuband/Sources/MenuBand/ReverseWaveformHUD.swift b/slab/menuband/Sources/MenuBand/ReverseWaveformHUD.swift new file mode 100644 index 0000000000..6797495db3 --- /dev/null +++ b/slab/menuband/Sources/MenuBand/ReverseWaveformHUD.swift @@ -0,0 +1,110 @@ +import AppKit + +/// A momentary, non-activating tape monitor. Space owns its visibility: the +/// panel appears for the reverse dive and dissolves after release without +/// moving focus away from the app being played. +/// +/// Two stacked displays, one story: the TOP strip is the tape — the exact +/// reversed clip, frozen, with the orange needle diving right→left across +/// it. The BOTTOM strip is the record meter — a live red sweep of what you +/// are playing RIGHT NOW, which `feed` is printing backwards onto the tape +/// under that same needle (the reverse dub). Sound in the bottom bar while +/// the needle moves above it = new material landing on the tape. +final class ReverseWaveformHUD { + private let panel: NSPanel + private let waveform: WaveformStripView + private let dubMeter: WaveformStripView + private weak var menuBand: MenuBandController? + private var hideGeneration: UInt64 = 0 + + init(menuBand: MenuBandController) { + self.menuBand = menuBand + + waveform = WaveformStripView(frame: NSRect(x: 7, y: 33, width: 346, height: 44)) + waveform.menuBand = menuBand + waveform.tintColor = NSColor.systemOrange + waveform.hoverColorFeedbackEnabled = false + waveform.usesReverseClipProgress = true + waveform.usesDisplayLink = true + waveform.isLive = false + + dubMeter = WaveformStripView(frame: NSRect(x: 7, y: 7, width: 346, height: 22)) + dubMeter.menuBand = menuBand + dubMeter.tintColor = NSColor.systemRed + dubMeter.hoverColorFeedbackEnabled = false + dubMeter.usesDisplayLink = true + dubMeter.isLive = false + // The live input alone — the tape tap sits upstream of the reverse + // player, so the dive's own sound can't paint itself into this meter. + dubMeter.externalLevelSource = { [weak menuBand] in + menuBand?.rewindLiveInputPeak() ?? 0 + } + + panel = NSPanel( + contentRect: NSRect(x: 0, y: 0, width: 360, height: 84), + styleMask: [.borderless, .nonactivatingPanel], + backing: .buffered, + defer: true + ) + panel.level = .floating + panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .transient] + panel.isOpaque = false + panel.backgroundColor = .clear + panel.hasShadow = true + panel.ignoresMouseEvents = true + panel.hidesOnDeactivate = false + panel.isReleasedWhenClosed = false + panel.alphaValue = 0 + + let plate = NSView(frame: NSRect(origin: .zero, size: panel.frame.size)) + plate.wantsLayer = true + plate.layer?.cornerRadius = 9 + plate.layer?.masksToBounds = true + plate.layer?.backgroundColor = NSColor(srgbRed: 0.025, green: 0.03, blue: 0.03, alpha: 0.94).cgColor + plate.addSubview(waveform) + plate.addSubview(dubMeter) + panel.contentView = plate + } + + func show(levels: [Float], above trackDrumFrame: NSRect?, on screen: NSScreen?) { + hideGeneration &+= 1 + position(above: trackDrumFrame, on: screen) + waveform.seedWaveform(levels: levels, cursorAt: 1) + waveform.isLive = true + // Fresh sweep each dive, and drop any peak that accumulated between + // dives so old sound can't flash into the first meter column. + dubMeter.resetRaster() + _ = menuBand?.rewindLiveInputPeak() + dubMeter.isLive = true + panel.orderFrontRegardless() + NSAnimationContext.runAnimationGroup { context in + context.duration = 0.07 + context.timingFunction = CAMediaTimingFunction(name: .easeOut) + panel.animator().alphaValue = 1 + } + } + + func hide() { + hideGeneration &+= 1 + let generation = hideGeneration + NSAnimationContext.runAnimationGroup({ context in + context.duration = 0.12 + context.timingFunction = CAMediaTimingFunction(name: .easeIn) + panel.animator().alphaValue = 0 + }, completionHandler: { [weak self] in + guard let self, self.hideGeneration == generation else { return } + self.panel.orderOut(nil) + self.waveform.isLive = false + self.dubMeter.isLive = false + }) + } + + private func position(above trackDrumFrame: NSRect?, on screen: NSScreen?) { + let size = panel.frame.size + let visible = (screen ?? NSScreen.main)?.visibleFrame ?? .zero + let x = visible.midX - size.width / 2 + let trackTop = trackDrumFrame?.maxY ?? (visible.minY + 126) + let y = min(visible.maxY - size.height - 8, trackTop + 12) + panel.setFrameOrigin(NSPoint(x: x, y: y)) + } +} diff --git a/slab/menuband/Sources/MenuBand/WaveformStripView.swift b/slab/menuband/Sources/MenuBand/WaveformStripView.swift index 728d98b97f..a1f8567b53 100644 --- a/slab/menuband/Sources/MenuBand/WaveformStripView.swift +++ b/slab/menuband/Sources/MenuBand/WaveformStripView.swift @@ -48,6 +48,27 @@ final class WaveformStripView: NSView { didSet { needsDisplay = true } } + /// Momentary reverse HUDs show one exact scheduled clip, so their head + /// should cross the whole strip using clip time rather than the broader + /// persistent tape-session clock. + var usesReverseClipProgress = false + + /// Drive repaints from the display's own clock instead of the 30 fps + /// timer. The momentary HUD opts in so its head glides at native refresh + /// (120 Hz on ProMotion); the always-on popover strip stays at 30 fps. + var usesDisplayLink = false + + /// When set, the strip sweeps THIS signal instead of the synth's + /// visualizer capture: a read-and-clear peak per call. Also bypasses the + /// reverse freeze — an input meter keeps sweeping while the tape + /// reverses, which is the whole point of the HUD's dub bar. + var externalLevelSource: (() -> Float)? + + /// Tape speed of the live sweep, in columns per second — independent of + /// the repaint rate, so a display-link strip doesn't sweep 4× faster + /// than a timer strip. + var columnRate: Double = 30 + /// Fired when the display is clicked. The popover wires this to open the /// full keymap view — same action as the "Keymap" button — so the live /// scope doubles as a keymap affordance. @@ -144,6 +165,23 @@ final class WaveformStripView: NSView { /// draw loop allocates nothing. private var columnRects: [CGRect] = [] private var timer: Timer? + /// The display-link drive when `usesDisplayLink` is on (macOS 14+). Typed + /// `Any` because `CADisplayLink` postdates the deployment target. + private var displayLinkObj: Any? + /// Wall-clock of the previous tick — every per-tick rate (tape advance, + /// head easing) derives from real elapsed time, not from an assumed + /// frame interval. + private var lastTickTime: Double = 0 + /// Time accumulated toward the next column advance (see `columnRate`). + private var columnAccum: Double = 0 + /// The in-progress column's running min/max — transients land on screen + /// the tick they sound, then the column seals when the tape advances. + private var pendingMin: Float = 0 + private var pendingMax: Float = 0 + /// Silence does not need a 30 fps Core Graphics repaint. Keep sampling so + /// the first transient is caught, but coalesce the empty-grid animation to + /// 6 fps until audio becomes visible again. + private var quietTicks = 0 /// While reversing: eased column offset of the playhead back from the /// cursor, driven by the audio's actual reverse progress. private var scrubOffset: CGFloat = 0 @@ -194,32 +232,69 @@ final class WaveformStripView: NSView { } private func start() { - guard timer == nil else { return } - menuBand?.setWaveformCaptureEnabled(true) - let t = Timer(timeInterval: 1.0 / 30.0, repeats: true) { [weak self] _ in - self?.tick() + guard timer == nil, displayLinkObj == nil else { return } + // An externally-fed strip never touches the shared visualizer + // capture, so it can't steal the pin from the scope that owns it. + if externalLevelSource == nil { menuBand?.setWaveformCaptureEnabled(true) } + lastTickTime = CACurrentMediaTime() + columnAccum = 0 + if usesDisplayLink, #available(macOS 14.0, *) { + let link = displayLink(target: self, selector: #selector(displayTick(_:))) + link.add(to: .main, forMode: .common) + displayLinkObj = link + } else { + // Display-link opt-in on an older OS still gets a faster clock. + let interval = usesDisplayLink ? 1.0 / 60.0 : 1.0 / 30.0 + let t = Timer(timeInterval: interval, repeats: true) { [weak self] _ in + self?.tick() + } + t.tolerance = interval / 3 + RunLoop.main.add(t, forMode: .common) + timer = t } - t.tolerance = 1.0 / 90.0 - RunLoop.main.add(t, forMode: .common) - timer = t } private func stop() { + // Only release capture ownership if this view actually acquired it. + // Hidden pre-warmed views receive viewDidMoveToWindow too; treating + // that as a release could steal the pin from another visible scope. + guard timer != nil || displayLinkObj != nil else { return } timer?.invalidate(); timer = nil - menuBand?.setWaveformCaptureEnabled(false) + if #available(macOS 14.0, *), let link = displayLinkObj as? CADisplayLink { + link.invalidate() + } + displayLinkObj = nil + if externalLevelSource == nil { menuBand?.setWaveformCaptureEnabled(false) } } + @available(macOS 14.0, *) + @objc private func displayTick(_ link: CADisplayLink) { tick() } + /// Stop capturing and clear the raster so the display shows the empty /// off-grid (used when `isLive` is switched off). private func freezeToBaseline() { stop() + resetRaster() + } + + /// Clear the raster and rewind the write cursor — a fresh sweep for a + /// momentary panel that just reappeared. + func resetRaster() { for i in 0.. 1 ? Double(c) / Double(fillEnd - 1) : 0 - let level = levels[min(levels.count - 1, Int(f * Double(levels.count - 1)))] + // Max-pool the level range this raster column covers. Nearest + // sampling could land between two envelope columns and drop a + // short transient — a single drum hit — from the display. + let lo = levels.count * c / fillEnd + let hi = max(lo + 1, levels.count * (c + 1) / fillEnd) + var level: Float = 0 + for l in lo.. 0 else { updateGridGeometry(); return } - let reversing = menuBand?.isRewinding ?? false + let now = CACurrentMediaTime() + let dt = min(0.25, max(0.0005, now - lastTickTime)) + lastTickTime = now + let reversing = externalLevelSource == nil && (menuBand?.isRewinding ?? false) if reversing { // Freeze the sweep; position the playhead from the ACTUAL reverse - // playback progress (exact, drift-free). The player's progress is - // polled at 30 fps and can land unevenly, so ease toward the - // audio-derived offset (snap on the first reverse frame) — the - // indicator glides while the lit columns stay put. - let windowCols = CGFloat(menuBand?.rewindWindowSeconds ?? 1.5) * 30.0 - let progress = menuBand?.rewindProgress() ?? 0 + // playback progress (exact, drift-free). Progress lands unevenly + // against the repaint clock, so ease toward the audio-derived + // offset (snap on the first reverse frame) with a rate-scaled + // factor — the glide looks the same at 30 and at 120 Hz. + let windowCols = usesReverseClipProgress + ? CGFloat(max(1, cols - 1)) + : CGFloat(menuBand?.rewindWindowSeconds ?? 1.5) * CGFloat(columnRate) + let progress = usesReverseClipProgress + ? (menuBand?.rewindClipProgress() ?? 0) + : (menuBand?.rewindProgress() ?? 0) let target = CGFloat(progress) * windowCols - scrubOffset = wasReversing ? scrubOffset + (target - scrubOffset) * 0.4 : target + let ease = CGFloat(1 - pow(0.6, dt * 30)) + scrubOffset = wasReversing ? scrubOffset + (target - scrubOffset) * ease : target + quietTicks = 0 } else { - // Live sweep: reduce this frame to one min/max column, write it at - // the cursor, advance, wrap (overwriting the oldest column). - menuBand?.synthSnapshotWaveform(into: &samples) + // Live sweep: fold this tick's signal into the column under the + // cursor immediately — a transient lights up the frame it sounds + // — and advance the cursor on the tape clock (`columnRate` + // columns/second) however often the repaint runs. var mn: Float = 0, mx: Float = 0 - for s in samples { - if s < mn { mn = s } - if s > mx { mx = s } + if let source = externalLevelSource { + let peak = source() + mx = peak + mn = -peak * 0.85 + } else { + menuBand?.synthSnapshotWaveform(into: &samples) + for s in samples { + if s < mn { mn = s } + if s > mx { mx = s } + } } - gridMin[cursor] = min(-0.012, mn) - gridMax[cursor] = max(0.012, mx) + pendingMin = min(pendingMin, mn) + pendingMax = max(pendingMax, mx) + gridMin[cursor] = min(-0.012, pendingMin) + gridMax[cursor] = max(0.012, pendingMax) written[cursor] = true - cursor = (cursor + 1) % cols + columnAccum += dt + let columnInterval = 1.0 / max(1, columnRate) + if columnAccum >= columnInterval { + // One advance per crossing; cap the carry so a hitch can't + // machine-gun the cursor across the strip. + columnAccum = min(columnAccum - columnInterval, columnInterval) + cursor = (cursor + 1) % cols + pendingMin = 0 + pendingMax = 0 + } scrubOffset = 0 + if max(abs(mn), abs(mx)) < 0.002 { + quietTicks += 1 + } else { + quietTicks = 0 + } } wasReversing = reversing - needsDisplay = true + if reversing || quietTicks == 0 || quietTicks % 5 == 0 { + needsDisplay = true + } } // ── Drawing ───────────────────────────────────────────────────────────── @@ -357,9 +472,17 @@ final class WaveformStripView: NSView { guard bounds.width > 6, bounds.height > 6 else { return } if cols == 0 { updateGridGeometry() } guard cols > 0, let ctx = NSGraphicsContext.current?.cgContext else { return } - let reversing = menuBand?.isRewinding ?? false - let accent = NSColor.controlAccentColor - let tint = tintColor ?? accent + // An externally-fed meter is always a live sweep — while the tape + // strip above it freezes into reverse styling, this one keeps its + // ordinary comet-tail look. + let reversing = externalLevelSource == nil && (menuBand?.isRewinding ?? false) + // Resolve dynamic AppKit colors once per frame. Calling + // `colorWithAlphaComponent` on a dynamic system color inside the + // column loop repeatedly enters CoreUI's theme catalog. + let accent = NSColor.controlAccentColor.usingColorSpace(.sRGB) + ?? NSColor.controlAccentColor + let rawTint = tintColor ?? accent + let tint = rawTint.usingColorSpace(.sRGB) ?? rawTint // The compact and Global Keys graphs opt into this color treatment. // The full-screen visualizer uses the same view but opts out; shifting // the entire wall as the pointer crosses it would be distracting. diff --git a/slab/menuband/Sources/MenuBand/main.swift b/slab/menuband/Sources/MenuBand/main.swift index d8f3999e58..803d64f3dc 100644 --- a/slab/menuband/Sources/MenuBand/main.swift +++ b/slab/menuband/Sources/MenuBand/main.swift @@ -47,6 +47,11 @@ if VisualizerCLI.runIfRequested(CommandLine.arguments) { exit(0) } +// Headless capture of TrackDrum's circle-per-rhythm polyrhythm trainer. +if PolyrhythmTrainerCLI.runIfRequested(CommandLine.arguments) { + exit(0) +} + // Singleton guard: when MenuBand is spawned by both launchd's // KeepAlive (after crash / sleep wake) AND MenuBandLauncher's // double-tap path at the same time, we get two instances fighting diff --git a/slab/menuband/Tests/MenuBandTests/ShapedownTests.swift b/slab/menuband/Tests/MenuBandTests/ShapedownTests.swift index 7716495a5d..96a490232f 100644 --- a/slab/menuband/Tests/MenuBandTests/ShapedownTests.swift +++ b/slab/menuband/Tests/MenuBandTests/ShapedownTests.swift @@ -468,6 +468,146 @@ final class ShapedownTests: XCTestCase { ) } + func testPolyrhythmClockStartsTogetherAndDividesOneCycleThreeAgainstTwo() { + var clock = PolyrhythmTrainerClock() + clock.start(at: 10) + XCTAssertEqual(clock.tick(at: 10), [0, 1]) + XCTAssertEqual(clock.snapshot(at: 10)!.needleFlash, 1) + XCTAssertEqual(clock.snapshot(at: 10.12)!.needleFlash, 0, accuracy: 0.000_001) + XCTAssertEqual(clock.tick(at: 10.79), []) + XCTAssertEqual(clock.tick(at: 10.81), [0]) + XCTAssertEqual(clock.tick(at: 11.21), [1]) + XCTAssertEqual(clock.tick(at: 11.61), [0]) + XCTAssertEqual(clock.tick(at: 12.41), [0, 1]) + } + + func testSlashCyclesFourPatternsThenTurnsTrainerOff() { + var clock = PolyrhythmTrainerClock() + clock.cyclePattern(at: 1) + XCTAssertEqual(clock.pattern, .init([3, 2])) + clock.cyclePattern(at: 2) + XCTAssertEqual(clock.pattern, .init([4, 3])) + clock.cyclePattern(at: 3) + XCTAssertEqual(clock.pattern, .init([5, 4])) + clock.cyclePattern(at: 4) + XCTAssertEqual(clock.pattern, .init([3, 4, 5])) + clock.cyclePattern(at: 5) + XCTAssertFalse(clock.isActive) + } + + func testThreeRhythmPatternTicksEveryCircleAtCycleStart() { + var clock = PolyrhythmTrainerClock() + for step in 1...4 { clock.cyclePattern(at: CFTimeInterval(step)) } + XCTAssertEqual(clock.pattern.label, "3:4:5") + XCTAssertEqual(clock.tick(at: 4), [0, 1, 2]) + // 75 bpm × 3 primary beats = 2.4 s cycle; the 5-circle subdivides + // it every 0.48 s. + XCTAssertEqual(clock.tick(at: 4.47), []) + XCTAssertEqual(clock.tick(at: 4.49), [2]) + } + + func testPolyrhythmRateStepsByFiveAndKeepsPhase() { + var clock = PolyrhythmTrainerClock() + clock.start(at: 10) + let before = clock.snapshot(at: 10.6)!.phase + clock.changeRate(by: 5, at: 10.6) + XCTAssertEqual(clock.bpm, 80) + XCTAssertEqual(clock.snapshot(at: 10.6)!.phase, before, accuracy: 0.000_001) + clock.changeRate(by: 500, at: 10.6) + XCTAssertEqual(clock.bpm, 300) + } + + func testTrackpadBandRoutesTapToItsOwnCircle() { + // 75 bpm 3:2 → 2.4 s cycle. 10.8 is exactly the 3-circle's second + // beat but lands a third of the way between the 2-circle's beats. + var clock = PolyrhythmTrainerClock() + clock.start(at: 10) + clock.registerTap(at: 10.8, normalizedX: 0.1) + clock.registerTap(at: 10.8, normalizedX: 0.9) + let feedback = clock.snapshot(at: 10.8)!.tapFeedback + XCTAssertEqual(feedback.count, 2) + XCTAssertEqual(feedback[0].rhythmIndex, 0) + XCTAssertGreaterThan(feedback[0].accuracy, 0.95) + XCTAssertEqual(feedback[1].rhythmIndex, 1) + XCTAssertEqual(feedback[1].accuracy, 1.0 / 3.0, accuracy: 0.000_001) + XCTAssertEqual(clock.snapshot(at: 11.5)!.tapFeedback.count, 0) + } + + func testTrackpadBandMathSplitsEvenlyAndClamps() { + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: 0.2, rhythmCount: 3), 0) + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: 0.5, rhythmCount: 3), 1) + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: 0.9, rhythmCount: 3), 2) + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: 1.0, rhythmCount: 3), 2) + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: -0.5, rhythmCount: 2), 0) + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: 0.49, rhythmCount: 2), 0) + XCTAssertEqual(PolyrhythmTrainerClock.rhythmIndex( + forNormalizedX: 0.51, rhythmCount: 2), 1) + } + + func testPositionlessTapFallsBackToNearestGrid() { + var clock = PolyrhythmTrainerClock() + clock.start(at: 10) + clock.registerTap(at: 10.82) + let feedback = clock.snapshot(at: 10.82)!.tapFeedback + XCTAssertEqual(feedback.count, 1) + XCTAssertEqual(feedback[0].rhythmIndex, 0) + XCTAssertGreaterThan(feedback[0].accuracy, 0.9) + } + + func testPolyrhythmOverlayGrowsAboveTrackDrumWithoutClippingCircles() { + XCTAssertEqual( + PitchBendCursorOverlayWindow.tracktrampSurfaceSize(polyrhythm: nil), + TracktrampMetalView.logicalSize + ) + for circles in 2...3 { + let surface = PitchBendCursorOverlayWindow.tracktrampSurfaceSize( + rhythmCount: circles + ) + let trainer = PolyrhythmTrainerView.logicalSize(rhythmCount: circles) + XCTAssertEqual(surface.width, + max(TracktrampMetalView.logicalSize.width, + trainer.width)) + XCTAssertEqual( + surface.height, + TracktrampMetalView.logicalSize.height + + PitchBendCursorOverlayWindow.polyrhythmGap + + trainer.height + ) + } + // Side-by-side circles: three circles are wider than two. + XCTAssertGreaterThan( + PolyrhythmTrainerView.logicalSize(rhythmCount: 3).width, + PolyrhythmTrainerView.logicalSize(rhythmCount: 2).width + ) + } + + func testTrackDrumSlashAndHelpRemainDistinct() { + XCTAssertEqual( + AppDelegate.trackDrumSlashAction(keyCode: 44, flags: []), + .trainer + ) + XCTAssertEqual( + AppDelegate.trackDrumSlashAction(keyCode: 44, flags: [.shift]), + .help + ) + XCTAssertNil( + AppDelegate.trackDrumSlashAction(keyCode: 44, flags: [.command]) + ) + XCTAssertNil( + AppDelegate.trackDrumSlashAction(keyCode: 12, flags: []) + ) + XCTAssertEqual(AppDelegate.trackDrumRateDelta(keyCode: 27, flags: []), -5) + XCTAssertEqual(AppDelegate.trackDrumRateDelta(keyCode: 24, flags: []), 5) + XCTAssertEqual(AppDelegate.trackDrumRateDelta(keyCode: 24, flags: [.shift]), 5) + XCTAssertNil(AppDelegate.trackDrumRateDelta(keyCode: 24, flags: [.command])) + } + func testTrackDrumClearsVisibleAndRevealedDock() { let screen = NSRect(x: 0, y: 0, width: 1200, height: 800) let size = NSSize(width: 240, height: 160) -- 2.51.2 From da086f80a98862bd1c1b708e8dc9e1038ffebb1a Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Thu, 13 Aug 2026 18:10:51 -0400 Subject: [PATCH 3/4] menuband: add the polyrhythm App Store shot, bump to 1.6.11 (171) The trainer's three-circle pattern is the new store portrait: 3:4:5 frozen off-beat so each hand sits at its own angle. The capture is transparent around the circles, so it lands on the desktop as the overlay panel it is rather than in a fake window. --- slab/menuband/bin/app-store-real.mjs | 27 ++++++++++++++++++ .../en-US/00-keyboard-menu-1440x900.png | Bin 173230 -> 172490 bytes .../screenshots/en-US/01-reel-1440x900.png | Bin 834429 -> 824858 bytes .../screenshots/en-US/02-midi-1440x900.png | Bin 632900 -> 633752 bytes .../en-US/03-polyrhythm-1440x900.png | Bin 0 -> 1100844 bytes slab/menuband/project.yml | 4 +-- 6 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 slab/menuband/fastlane/screenshots/en-US/03-polyrhythm-1440x900.png diff --git a/slab/menuband/bin/app-store-real.mjs b/slab/menuband/bin/app-store-real.mjs index df8a5b2549..b51350d5d9 100644 --- a/slab/menuband/bin/app-store-real.mjs +++ b/slab/menuband/bin/app-store-real.mjs @@ -58,6 +58,11 @@ console.log("rendering real UI surfaces…"); render(["--render-menubar", "--light"], "menubar.png"); // keys at rest, light theme render(["--render-popover", "--lang", "en", "--program", "0"], "popover.png"); render(["--render-keymap", "--lang", "en", "--program", "0", "--keymap", "milkyTracker"], "keymap.png"); // fullscreen expanded view +// The polyrhythm trainer at its widest pattern: three separate circles, one +// per rhythm. Phase is chosen off-beat so every hand sits at a distinct angle +// — a frozen unison downbeat reads as three identical clocks. +render(["--render-polyrhythm", "--pattern", "3:4:5", "--phase", "0.41", + "--bpm", "75", "--light"], "polyrhythm.png"); // The ♪ status glyph at the strip's right end renders in the system accent // (green). For a clean light-mode bar, recolor it to INK. That right slice @@ -95,6 +100,7 @@ const SHOTS = [ { file: "00-keyboard-menu", kind: "literal" }, { file: "01-reel", kind: "reel" }, { file: "02-midi", kind: "midi" }, + { file: "03-polyrhythm", kind: "poly" }, ]; const FILL = "#ffffff"; // solid light-theme backing behind the panels @@ -156,6 +162,18 @@ const screenCSS = (s) => { return windowEl({ screen: "keymap", scale, left: Math.round((W - w) / 2), top: 104, z: 3 }); } + // The trainer capture is transparent around the circles, so it gets no + // window chrome or white backing — it sits on the desktop as the overlay + // panel it actually is, sized to dominate the frame. + if (s.kind === "poly") { + const d = pngDims("polyrhythm"); + const h = Math.round((H - BAR_H) * 0.78); + const w = Math.round(h * d.w / d.h); + const img = uri("polyrhythm.png"); + return ``; + } if (s.kind === "midi") { const d = pngDims("popover"); const scale = 1.62; @@ -248,6 +266,13 @@ const literalStrip = () => { const scene = (s) => { if (s.kind === "literal") return `${literalStrip()}${screenCSS(s)}`; + if (s.kind === "poly") return `
+ POLYRHYTHM + One circle per rhythm. + Three against four against five — each finger keeps its own grid. +
+ + ${screenCSS(s)}`; if (s.kind === "midi") return `
VIRTUAL MIDI OUT

Your menu bar
plays the studio.

@@ -294,6 +319,8 @@ const html = (s) => ` ${scene(s)}`; diff --git a/slab/menuband/fastlane/screenshots/en-US/00-keyboard-menu-1440x900.png b/slab/menuband/fastlane/screenshots/en-US/00-keyboard-menu-1440x900.png index 2af40e97654dd004cb222713faf81172d1ec0342..7de385860edec70e664fdf87b4366494253ccb1f 100644 GIT binary patch delta 169385 zcmZ2?lIzrAt_hXm7P^MUAx1`429{Q)M%o4jRt5&uzogYCPLRST#kG9#?1=|u>ydRC zLv;N<+WCQjp@G5E#WAGf)|n4vj2ph~ZP=@rH) zlLQuBQDk6X5Rp$_17!528IWMlVlkf7&aWxX<<3;^GWJNCj-L)r=W;cPXDtzOxPJ17|vvW zwmvv9yozZj4+BHQhn)X6D$mr%D4YeE^Z8bdZ$ZVGurmrP8*?}q7^ZBtxg@Y`f7?4v zo+XwH3=9eLW=-epo0G}SU&;GKpMfDE?(?ViGj^U6e`>#+bkt!M$Xn0mR!)0Ra6V>7 z-`80e9bCm27-r}fJ(c&VzjP+}`I#gR#R-oY7#JFUCfTW4#C#IxTO6}Yzy9knkjrNL zo^R}(rDSY+I<6yn7PBQE14#2T-=@QwyB`{EefWu^VD--KfEIysg>v+StM^9`0S0)CADPHH=jC0h_^=v#{lCl)0E=x|u!Y19kB{Afk zs)%{z#Ny2Q&3|JeJ~5nX|GjQT^WOlz7Pc#hYaMTsM|AP2V5i zwx`X2cMI6GIbB5x$3dZ%y6%p!%)KJvZ!39U?}=+W^R(^E(n;(AYNrzIr`WVjVh^zM z+NbR$=P*;F{cpf0i7rtGt8T>@HYsD-o0)wwu9jUh>K}jDvDafIC|t^)&U>)o)1Kwt#}5Vdrs)%}dN!ZZ5Y>vpqiX{r#A1P7zT0QBR%w;KK(Al}o|5&LsUVK9^?A zz`*cK|8l%#aGA38)`?S}89cE#5fQso!?JHtjrWP0D|Hzd7<7uB&VKMA!1Ac!?uA*m zE}Z!Aao)Z9hZh4wLp7f-p1PfV{lt$O3v?zGZ`#=D={j+>mR6D9&4}v(f*jAbMzguQ zCwFF?i#0d16#T%h)nqAlu4Ai-+3%^3=CgVFzJB>SJ1b)aS8Lb40;N~-ay~0Ozh??% z71bnd+P3W0`X6_ef6?A|?bx##^MZnuh{vmbr+jot(vn%Zer^3k70qy-#%srp?Md=j z@#?^b1t+F1>~=~1n6hWxF16>;ju+&!)~!FU&DPK6=4N^Q)~s1+$q$7euKc*N^Uh>n z--!!my;?OV_*zKV^{~+AqK8lXsIU+_XL<9-lO-zNS4F2atxb&ke^1$@Vs38oGsW_}MA3bjNvo{vEF+^s-+q3& z$c< zLv`Q2%E`{-`oWxXB21!4CPn9z;b9r~i`|}!GzAzK7z%>+aq?+Tf77I zbm?@34x{w+~sx9vM+KKOV=V9P|>^E zM_6WO)Tx3qc^Px;zdrJA_nWih;jYzs^|v$-gpKttl(wjO{8~0a>O?<6)mG8bY z@3(dCJKiTgvsUc=GimMfd9`8RIJ_s^yg7a1$BCC~t)H~rVf8FJzQD-rUe({L;d=4g zjs)|h+*J1~Hnb|-^!%&&x7eD8&wQn?S-U07k1pysXwh}?_3!xpkhfErZk_qg-0!XX zaM}00_0MJJC3&#hSlR7Met&w8?V*}I9EL4Z^WvZXzL(qCc*n1E@o|5f?XM#*$|ZUU zCS7pT3froCUYYIkyp411_FnFjvknXtth%rJenX^GatW&1ui z%~tGXWZ9l?zn1mBUcc*&&}`jBG2vC~W;^@;U%BwZ>Y&m-Cz-epOG0L@*zvRNbyUi{l1@Gn|?BU7JvLqV6t^(^*d>i zn}2T_310rcZ|DC5&i!^j%^nE*?|a_%nz^oi*|DzJQqk=yP2PRUe7Ckc1%fIt1I^1U z?VaB@NjD!p{F`ro>0i_E_)VqUn^$lOG1hPX)$?rGvj2a+mB-)O`T3J>G|x)j+pn}z zWK!dD%M!aR^R`QassIK9t>Y~1uOCm0E_3E6{1f6I8hVxW`TW)P`_c`P^v*BW*}Y~* zWlq)Fm*077WBKG~pI!R)uG-}t0jB=*B_$`uHO%H-xZJHvfcd%46WQjMoi{nJn|MuM z`EgTyK|f>1mxDq|Q{NfBW4}Dz`*Piex}Sc$&n5{xsa1brm@#Mhsi)kIE;GY7tnt4! zP5HrxyWtZ~sJE2_{tMw*6k*7rXEUFtElMx$UV4ya$D_GCDHRJZ#oNt%y6D8OTe+PV zAKnslX{z3@u_^gOS>m&|Ei0Mgz`($; z;Eu42+P0g$XFUFf|2@5YWvZ#7%dWc(J~I=&`hCsS4EE|2|IYu_6T@-NGvEB2h2u9F zlfPa|-LrokIv=!^+v5c*`x(hOFFAE{4L5yZdnVYtFM7>V9tlDJ(E4JJ;|VpZwjG&J zSDAA2Y=OkBqY96mzC^vaCM0uaohbk7H`@$fq#Cj;O?xhtzR6&ZMO6K)y0b=ew2u83 zN_NUvxl8TZHt!zkjIKs*KbII`pHu2=?*y2|=LE6-Uc3IqHT~7U_32`}ESJwV_!qwf)3tgiXzf97J zWY_!c;3Loa`|pI4KX$~;Sb0osnYd+b+0rBfU!R}%WmrTDiVfbKc@uB!?UBE*_~V2_ zdOk*X7ntaquQ>Bi;M(NgOX95xmu&7Y_%e4j|3j(tJGN~3=Ipj7Cy6$n^*gPjQkq>a z6eI9bSKxVRbJCfTZjblumQ#(k9eYsHY-Bp~h*9O_H{6#4KD#bi#hQA5X?k4X(Y;sN z1Rk}D$5(vYncgpNFV=f((MAuOc^+z$ojNLP%04`BJhxNl^s-2BfDJg$N883^yJ+(usgly zUdpZ73p>(gsqa?Y^|HT9C-_X9h?w)Y^;Mol*CjOm9-CAd?YsBCgwv@mMO&}?;Y}>+ z3k%;}@?_X-trwYn{>TK$*_Gnw-x(zRa#foDSApem)m5Iop&^(5Z9g{QoZdyX8~smS)&$k#AMD%!9$Wlo%gpHQ;2%)9WdU$qR5 zPKf+b(yafhZo^MMKNXw(6FR>V_&21dc)3#)zA)BJg_SwyEr)F?<_FPUkpEjlTqR;dP1^!|cKB^Y~1^s#Z zk1e{t`}b~VXXjO`W-WUjbL4U1ZB>PdpeC;0DeZ#~{~4s{?wk16S?l`(@weYDU2bo! zHvan3?Xl6@W0KSJ>#OE%yB3%3Qk7e5Tjw|F`YXjq`7ajB*L?fD=lF!W`=&<}Y{CN# zYdyt!3=`wkZA=^g{dym==g#ko8)qAR4V+jUccacD^wWI1<`hMbuTtq*%$Dj#M-puB z#Pzi*vI*^JkYEukoTqnCF-Pr`Hru>%o|hX}PCi)W!^>EB+wTyfdQlbE~E8-nzFUWr@4y^sbEe z;jIy?YZhwqR%wYk!0RO-&U#N~({y!~>0c#gEbZ$0-D){mdWt2R;?v@{GyFK0SAQ+x z( zHTBya*mNmZ&*Hd3hlZ$g+TA;5Z6zxO*w^h=`tH5bL%d)^UFf!RdAs$pYsHo)AMD|- zpMQ_Pr=m=|GKRx#ruwrp*Ta)<=DaqGO7=KEwd-Jo!kqqA!zC{*XUxm-IzJ_z=hw*t zZ;}k&X}YZxR``7Mx{&j#h>6ZT@7C|zw)hP9LK{D}>3hDiZ++FaSJ50ZE(s$l2BlRaG zD`%EW+*6Yu(Bv}Da7m>8nJJdRPXeV@y< zMk&72IcL;+E5(N0NuD$FC`aPEoyzV!PsEykJEtGK$@|*a_UWVA*p*ybHm@U6{!R%! zeK%;9+SUUlrJQ<_-NhCCzV-rgNekXc^iif!U6o@E`s@0d8oiKp!|d{R5vVZWuN5U{ZaC>m)Sp!ytU4_o?Cf#p6Qv2gR)D4 zma)6+zB?tH$N1Nxv|rP*ayyVl@Y7j5tcl+(bMH+w9G))|f43jioxXt~Q zypVHJS3&WDJG|F-xF%)g-s>ylspS=IvgQ;%fP@?B{Wyjc4_WusV9GC zyx5q?r|7av-6Q++?_Vj)LQ{Or_D1YwXxOfPeN95kJ;8O(JS)vued1;3CJ89To>ID> z{4nIuQL76pD_LL1Y`c15F8ibl6~CBQ-rbns!l&y#gT3Br`_2bpn_~mC*naE(>oHPy zK6g%Qlegl|;|X?>U-*ws(QaGQ*w-q)qCw)5g``aRrnf!!k_D>NwN?trY}4O5PybBG zJf-`8CuprT`EA}VDcAinOf06q^+Uzmi0{n`=U8{%S-^60%fX!8CVs7V7qkd8eJ;6n z{^PR;PY?OXbLZVvtY5d=DMkGKrp|*8pC!moJ}y1wa=h*1c^mT-Qs;j-*4Z7%cgS#e zVvL>gww#xnUa#Bxt?8^dOS7VDpor_VRMpEVJ(<=4fvgM+40EOgHXUC2Xx-W1nM;4T zom=`eH0AKlFYJ={n$Hy8YMphp_(_R%Q`PAy_kQ(nP$`*{EKt^b`TT}$^@bwf5?(A^ zRex{ubIX7w`-><4-B_U2uh5ckv;R!Ygp~ce?#%Y|TfXq&o~?cpBHxto+*!G);q>}n zw``9l$Y?Cvef3P=!H?egar>V=Dg0Iwu65#N#glvdZESYI@*BB37gm_Jmt^c*-?8U> z#QXH{gW{R@%vY@0n|y;`>9?;Lf7^ck`aW~^eDP%pZYk4c%I}M=+`XlkhtHfnQMh^G z|0#R)yP8hbayWa-OquI=VzWSd^iAG#J5@Yq+NWn1j?f*HWdV+s~Kl2u9vscbVNUxs2KPurXuNDU+qszvpc{matpz z_@kmGN~ueBDoTNY@&i+OM0ym`ybgx%-o zwk=Oi*wYZ#%lo_WQ?KKVBMP5v<#`QXc%KNJrSSYs<$Al=e{C(#lPCT?m%7iuHBjHj z-*7@M&rdn-?@gkX-`D=0{(n!Bz@7+mjop>D@7g7g)hFz+^r)QAU-kd2WzvVbVga51 zzk}zAr#(~JRXPowi>1p{y?QMBWL}Djyar{HEvHNlK0K0K z$*%u&b#ZNd@sCw!jF(<8=DzxWvR>)i2p-k!DlhxZVxOX-BY5uE)c*RraDtZBvb|Go zZaj8NIOV%YcKw{Xw6A|Ui|1X{Q#<|Vb)|j4swEYSZ{sVv4rWfACUK@(Uw%&dcCqZW z8{f$}?>c=cM0~lig~qa=FVkFi&gC(VH+_C{x9Rh`3-J?mekZQe_qjd0`SZI|+4C*l zMt|qtyy2|*8+N5}XU4<_R2m zD7-==jHgPoAqtw|_nagA zGyAu5^oysxlVDjMV_1>He`v}VPhYdu;>!e9rdbrdW#<=H6P!7@KQ2k&=w3^YLsN1- z-QekZaA=$NygkVe?#z0t^=6)@*=w))nJafyUwgaZ%%t7hIxH$zrDtRq*w%*G)w}** zxNB9_%S%h`=JyvBu26Vv!OH*|-AkSKprCT4$8;|9EB+^KC!cQGU;RY=N&w%vp(PCpP8j~`E0}! zS?6V{9%+0Bes4T+Z;ad0E}DeRoQuc-pl`+2rR< z&-{PC73aQ~eXwrEK7+Tfv_+q~&6S-l{qVxxU9pOMjxO{6-kI;VNN_r64Bg=~)h#+=?)S*ddvNxC!rWahC(GC9oL0HS+IIGQ*fNib zWhZw3J2mN@yuswwM3*xwlf|d66HxI~n-|VAvv8V(g`t|IY00eJKWo49HRcL+KiMkX2TuymTQVIUrHHY14!h{(r7Mx-A5j>I7UQ(Wu=H&CZ^t?2j zu;2`5db!D^sfH2H#Ai!XBpO=CIR;->xwg~j`TpZeEsrXA3UR7g2ns75uTwbOs%a!D z#-D%0;D^lPT)j#X-`aVnF%Vj%zwr|TQI?S7I zUH4~)H{1R9{B!E>{q(c6czw{75tK?kWXP#l>=AC;B)IKpQf_;N{O*#MLif2%Iq%Jv znmY5C!TN`qK1=HTr%yHz^YzmTZQS+i*RPuW;pL@er`BIz@o!^IQo`h8@=Enpt5;NA z`Lg!v55p_(A|e(GnS@^5v*u`7uO1`&pMPz)mI?0_4KYmYI{41vNk?OA_N}PfpL!Rr zTD580raGN>%N>qLG{o|}oOmXnO10XyXwSCQn~m>FoY=W+($DbIJ(Y9$^@O)?+t%`A zmxR4%&aQ(I6Mr9C;uFl##yyWUGPb(9dSAU^NqISIMQ+pgS!UN>pFL=?R4e>fmbA1q zx5k-Cn`bKCPJXyoWcJ%evsW3f6Mkpy5Hee*v7Xy_^0S2*EB384l;GImlC*m1O5Zsv z7R{R2lsrRDbY0e~oV3bsix&N;=`B6$-WMM5v|^q)dv>IrWAN5o=}-GCeb%3t^!(H> z=5&b@9rY}ie}6hV>zZ@XL78L6|9?nc##`8Ru#7v#NJ>uY1Zc8mQCJ@*pZ?Uto7Dnz3n}79iUyuKIYBuAiqr9%S&MHk@vFJqI{`-~OOBaNc z-%Y)~eVfVcyji*Z3x6Hhd@aA?^8wZ0eS7`94pp)TsYrdS|6P-3I%j8yY|hSyr=+v8 zvp@AV+SI%hos#Kx;N|JWcjx>43^^3_Zf^QoQt$u&hvB5qtnmSyOOO+reC+eijZe0H!Jg`h0P4cSGO<8{`#!= z+-dW+TeD_KuiN#n+`nE;O_=%D?!9XxbktZ_n;Ex@i(cJdcJ*fZ+WQaWoDaGhtWjrv zT4}fA$c81mU!T&wZu8eDGib()$C;A7ZmN-dJ7Q<}TymN|um0+%rQV-<6ThySDxSOR z)6!V4SI-_O2=!`pJu2U6&?=H(8XjL%TOGanwB2$i{WD)Sp163TBlssra6KnqHqY~U zwcidN7MFc__jytCqdD%$hWqco51#X%p>XHERexulUbkw+iWBAbId}IwJ+kug-emWf zJib+{jz0Q0$Gm;oG1cjLdsU2kk8@vMt`QznbMwTF3jsft+&-%~(?@Oc!h{QNpDp-l zbvr!IGJo^sU3c1Vt1a2YxBY2~p8A3J`WU*2-b%2{u9w$0rMYLxFt zt}c74U&`as*Q&-d-~2NFyP2oXR&CCh^Vz4#nd8^r%eR?Ar<%u<`!f29R>@dfS>3vP zJw0#l`3WC>oNeY`8?!Ix@2{<9+=^-*EH(e$tvlD%#r59z;LKxue0*Pdd3@d*CSNW% zB6RXdeSZD-56gOAhp&ryDB^rUK4RArYXJ@s8RngKar583{rm2&{l2fZ@2!fzYU!WW zRA4*zbLG5wA3Hsl|1EfPr1N?Fjk>>E!%fZ1EM(X0dNu3aJH2BOiH0hZPfk|%Z(SUi z&9KY1`upCm*B-uJzjxK5O@}fweR+9hUn()*OHJxH{`k0m{hS_kAwR=CKQ8rs{P^+p zx}9E=-rirVlBBD9R`=}LxNUd;S}aT2aOU6L-Sr|oZ1xqm*T#uWdOvmb>{+v{Dp$E* zHF;fkq5p?7zx}lf0sEgeea=l%Q1keavUKy}y~~!Vt)F}_qo(H1m6!Le~t$FAL0+V$Gn=|zb`J5|~Df9w6f=gXtD(Ps0f7hAF(zi|D!y@kyj z$<$l?!jpyh?SDO)cJ{e$F7@73YZsqr$e~zO<=5ZWZ+-Ma@vkr2(&KkL zJ9TGuF^Q%B<}W-y_p5i+%qQno{%8|;bfojK zzs=Vp@9yq)cXLnLSfL`5*0cBV+x-1cZMR>$em(lI+21UwImK0=23p9ejV#A`B!d;V zCEtC1wSGfw&6V~mS5rfE4aGiQXt(+K#8~!i{afklYn89F`_7%N^z_;<1z+D@U*BH8 z{sko$d7qJ)dI|l@?;Z zrYtjASMWCRxW%5WTbJs_G9BF|@8;&VJ-0gX<|NhE*Vk@bx2rzFe8stQee2fwEth2e zcfebJ@1~-opO$*>vOV_T>9d48nVWRpmE~Fi%VuL2~oB%JMFR(R9$Kuu<>- z$qQwYG~V2bp%Wl7dtC$rR@=k)b!P@0^3A8()2?>iGtx-WYggl4ep-b^_`4myz7hO)UJID zuGwe%^qdpV(p&tIThqL@$a{UgDrgw+bM6Gyo`c&g94z0o7ws@Ot=P8niO}JkHyq3D zkGl8ESyp~pl3TWT*Q%(bl~yJDcf1#`{{BueY4$m**S7EXEmf)J0Zk^a{5k!>he=0I zY)^3yJSL?k@XqkeuX!i4)}$03ov_ua-Z53c+42p0;+m-evm|W3xLJxDc3e8H@Jx$s z`Xh#=`z)uZwH56#@cwvQDcy47O=CMdxjvUQhb0&DN}IJf9TZmgulXzezv{&W#oCHx zospoTv;SFq(_!V?TCcBtGwS*K|Ecx09UtaQot(RR{qx)1EswR{oBuRtermc< zbG^6n;->=4Gk0_8e*c@myRtz-#_sNO!RFJ`>-*I|_#}O}x48YcU$KS5ysp}(x9|F& zO#V<;yn#2tEU93xhF5*!q-M+gmQVT)uH4wql%$cgbKap>ogty2?M@2|Do&Z~*|~G) z>eaWOf4=*>yP8kdO2^aadDJ~`&>D&v{hWOIwo>&K`TEIfps|)?w`!)Gwp6+QN!f4e z7T>_i`{6&2JqUWb+a~G5mIIN!ihsB6nxMaw^?1V1NPA1}OzA~844>30*qnQ6SGX)A zG|})$^_!w?^9*jQFKL&snJP8o>1^kd$seMs7Hu(apR+tT&TvNkyxT%D&*zu_Yiwqp zSN$(C^z4ucgpbemlPB8 zTeolj|DY^i`~Ua7^{ZCtc#4XOnwoB%q;j@k1_p+b&pHPmwtipq!)m$Ix%yuY z*}`&`&r7o|7(VCTQ|R?NLVvy9%dfZJu4&lip3?G zqyJVuw@r}LcF9ck*njbyP1~Nh)U&6zgm`Lr@#rzubIIU)6rQ*?aJ- z^G5GyD;`Mr%xslB7T{3G`T0i8H|Mz5r^@X)uHU?S|3a6b^E=Kpnn(9c3ya{{)+Ozn znD+XRPyP9asWbi35B22pO)36%bHC*oleVNgGC6v_**y2SwZsIPJ*Kv9nRzC0!SXpw z$*y^Km|0C27#I#LF7hmpu(UmI$)~O+VfZ{s#kJ?)?5%*5{ey~Q(@QHN9 zE|&Iao;bUoRX-=Z7Hggn$Rqc?W@FL^BeVOfn=h3vyTe`2_vGWr?F%HnSnQGU>Yuse zP|zZ|?sDB82^n`zf5RJMQ%`MQ)Bbna($m6cKRlZ-IXkN%O``eu+H5>RzC~p*<5JR6}Cd<`^~79 z+Sl6z%q~mVKJDu3dOtsMb^TPWwuBiIFa25Y z>+~v@1tEq$YL7j+?rh(zTd`wzh+&V6twOJNew}@o;%_g}!v{LFoDQz6-Yv2+#ZaZc zJu375%>N&IgIFD0rXGIGyU;dW?r$t-@(PcT?Jf6gHh-HZbZmjfSO1m#?|pK#Lm5sk zF>`&iaPQgkywlzs;^FtrT=nT%z3s<~4qHMD=gjb$@S$Bkho2?NOQ=DiaMk;%3A5uT z-kry?<|nH@C;MahcYCjMjW zTo#2GPT;t5`PgT+_D@5BWhX1^z~XR~NWHaWZ0GL~-n zcw*m7{Z$G7ZY}F_$$xxATD9lkasBlnex_{v(+$`>cl}%P!dBC(tX)Mf{PL`1XVE3o z-W{5=BI8lcmj!N7C-u&F%BRbARV~rdoSMdI@AKhd@S79MiYH&z)2O$9zlUA@aO1>% z-B&73-h1BgY*F8tKOKw=KBpcY(rK6Q+WOMzOGf@)H-6JK)6U=CU>9tER3W?SZ+W{- zQ{e*5)`u&G{Fj~hbX7e5kA=8>Me1?q#mcKEan64* zPdr{mS>>%%4$o@U)w32BnN6Kgzx{otrENs)Dv4uie>+(`^TPuCPkv+OJw0djr4PX- zAG1y-amagh-RQiKy-6c-TW-ud@1pzNf5L-a-nt|C^soBNKg|Ir{XCRjO;53l`rEvB zwYS9Kf+PQrE&O#P-&^wVktv7zT5hDgytLoYQ)P$AKcl04)3jKoNr=SQ%HFWn>6==w z)mE6<@cD(`*NqI^XP;KFK33k7Z*$}F7L$U{rQz*Oj?3q!%vL)gmzKBru(!~Q zpraE!RM^_uW~sk^-P}0o?t(=hUwpVx5uH5weE61>$*P(Qrtk6i@72?x;<;)Khi>ep z&GLq_tZc8<7Ck=hH`&Q7sebje(voe$6IC`IZtvqf*DApJ+~UH`n>8lv<^4PN*gl#m zz_1`^YJSsU=gouK0p-jemn`v0g>WwcxN2+aDbE?kb zc?`$G=jI`yvAgq1gNqm2ty;YK?)&fW>pv?93Ua!BG(4u_`Dst#k8DumHn0B1yx8B~ zvdz-B-#aa1YzzE$S)%^y1_y?QOS7A!g9C4c9Mj!$XU7)HSHCtVGV*<{l00Ymd`|YP zSsp4TzR|lMo@r~VsttJ-A}J|(cl+}Oozr#u*+ixbg$%>B<80`k({?+f`bNxN|M9QU02J9Ki3Z!9y*P`k-H@tvV-=v5ab zMUOT2cP!hs?N}LSa`NNq`!~){K5K4OU-Io&fa?j>Lm4W&UVq)@Yxy+Kq+hJoQh zlAMZ#M!yXE%`NMn90B7C$>j*&AWRcTGUrX zs7q;n>9=1A8Z(TyMVM^+{dMoERWB|1BBxD!93k=SpTfC6yJqx9^D;1meO5l``17en z$BC$VQPuaV%nWB{F1p{bM}I@h>b6CnZ_LbQ^e#A?SK#YC^)3g?UupBTpMU?AWA;-K z%70U3Ea$zXSVkz>_?4a5v&D<#3*U3=JY2=dkYILZHVgYsJCkakVu@w?Uym^`2n24t z%qTbA?DJG5T_gP`U)P036dk#+D#J*EE9cG@ziChRG{syodD|PCe{50V{`=22o(QvF}>+AJ&%nw@L-~K&ea)PBR*FD?G=2nVFHZE45yx#I}{hN0g zd6@?ee@QZ%ytv<(T})B&h{OMaeE;<-ns)Qgm(8-wel5blkd~pSVqr94Eki?*S@q4{ z2%T#eBCg-OyG-Nr))=`dV)ynXObibFdZlyU#)}^v6cVf%i)0uWJ|Aj&)!Dmrs+9mk zgOc!}eY(8oDpjO1Gjn5h?cu)3dxG0oqqJU!L3NqNsZFA>zPh{@Go}>h%{}l^jfa6D zH8s(WclNxiAJ{n=yz(Xq`Y7?Pemqm8-?>|-R0WIE3&2Zd$kdYxEEN%UpHUX#5tD>u?O{o%QWDr~MRC{{H ztXKEmu~mI!X3%if9c>g)KK4u1nEeQ)A?*%Y4u&&#*Dd@7v>w+g1 z3=F5lKnAH!%b%I9x8r>OFHHu9&8MG-?|86nam=dKQ>?NW8eDln4qK%8;G)_6$QA*W zmh`V*}7ZpJX zWWmgEX-$RQjd~#r49})Tubq6;BYi==pAv(^K~Qka;Fi-)Q{K(U5Kz}O;jzOxCWZt) zg@cR?2Cr@GuJ5ulzSY z_#8|&WH=CW>Ri0f{}(2`zl9hW62d_86WHHRU6lSu_PpV4#S4)-3zKbJ?aqy!wGJodKm@=)yE4Ptv(;AxWvjZ!~0tG`nS0|8je{oFf4cha)!pf8vARO zraG?*%NQ7DcgVnrTIO~+p`%O zb}pY{#lX z;^+FGP3iB%uWh?MCGwT>Hv6JiQybIE_v}l4{(AlK$Ax`w*ci^RPg42$_n&Y2+^tXd zaG%e-bt`h~nis1DRA#7FCVC_WSjA7A`nVuEp{(z)_bKQ9&JAZc7##dSCCHhTF{WF% z=M<{(^}VZ1`u|?8{!Qm!eK|>MvA#Z)D;7dB3@ zY}ptli0htP{wpcCcH_mx!OhLiUmRE63Ar1(bs zK}M0-rh1JXKiuN7Kl(jAY2H?D^Y4XlyWC4|{$tORU(##=YR3oab-6P!vc#l9rn0FL6c zo2thjT39nMoDmHPWMt6jbCORf{{Bbn#IK1PEZUT6H%92#NGL1Cx8_K#K4!Xb;#-Y* zPojbZCJIfNG3Bl>=OVQ)W?nPTOmPU4iscAOp0&?(@`7;9df_=8EB@ZGy1b%ua^T(> zKF^<3U0(5`pyr83OUJA5kT5fLAMQ7|ZP#6Y{k>HtJbiO1=ebZv7cUPZ(c0%)*M*uo zROBbu-elL{1N!e0P)<1A}V=3p<0u$4bAlimdu*6XSI+ z3fqK(XDxfFFS_Y|%(8ycq>h zT(U|xo&Uo(EmC&!j8Zq#brYX$urmGrYR&tEn8zZ;F>}SPe`yZczU7jMmf5r`!ZKe^ zpINNZ`Gv(jwRl0D>(s)K8l{{6kL?gRqEbKGVk?XIojT!`V>@TvD#*6(SZVHabPs0} zx9K_032!FPx_))WG|QTdApe3LbNDyipHrC7v!%t&Mbx)(n{Vl{z)sDtPd*=xn&WMh zZGU{ucS$RQh3Xccto}w!$}Ut|)b-5aIxFw7z>_P=zMN#_%67R@n>e|$^tbv~7Wa*Q z_K$DI)n84^<5#i+Ir8V+y4HDboqWIk$=ST?D|J-_bU>dkKqbxVI4 zhCR6H=aMz2_}p@#$sr}j{v~|Q%)L@N5i~|5BDrb>1H&2C-*Z~qBj0r8i|Af%d~}&% z!vPM(uB!CSTPC{v3>DRR@Qj~b24n$ z0V>uXxGi})=h%o4xD3)Vnh~^N#ktoiuA& ze(dyWgCD{S3=fz<^=eR&=03yf+-@cYhka{ALoXc;>|kbC5VK%nAVb5=r@!9n9oJdb znfCSe+zT@Ghl}M?rIvp$S>T^M%kcG7h4oiIzLY<6`bpc;=ron*sgtI!eSBz-)!D+= zJ;rKkla~eBOyn}jlbqVK%x$HiuH8gaGfBVgb7wri=KJ2zcgAh2lG`&^Iv?5D(WiE1 z_5_i6Vd^LLocVIiwe9h-z^stV$GQ9_F5HnhGpefpY2~lZGlve>GjCjT^=M^UVDMkV z%SKmcOsjtV$?|WHwUT6@@98JAKA$VG{5wZquXbwOw;7+WSa=t*>?J+TWD-+w1G<&fDJJw=?@)*^5U9a;lDb>|MCCN6GD)`23gQFD&n| z+?4Tp_IL9I)k!=1Ll0N4S!o|~DVV`ER#q_8N?7;bt2@aX<-Q2XUOW2Wk$v3%#@l(j zKd^3;SLBXKR|#|3U}HYdKQWG>U}?Q!0-#D0PjBSS$`J*X6X zs+#_hcS^lpz25rudHLHG_3*7btNvxCUZK_ggr`PXb!*PqiY+mIw$|sd`;>G=J_ZI2 zPEe(rrjkCpU|aKE{o_9>Y*)|7iQM|krc3&i@{DL{| z`&H3Boaa^tJ8hctcjf%zi9FdZM^c{EuQxeAlOww-P9fm6ac|J#S#i&mG9;I(RvIl5 zoVea;+TY0CJ_UmF1HN8m%{o)RNqF+Ae~aX@KFoGgRbD0a*hOU3_nBR-8JzQG1a+PW z*VJ~rxnQD=q`g*M ze8=lq)ssT5N}1>yo6QP%Jf~yTt+R_K1!vU+T~(e~8@W38v5nQ73*q8xzNfGEYhi!% zi*eOUo|)4mWqn_`FI;xoM$2&Nv15~5LT(Bfyfrjk*2@0q*DI~)O^-#A9+iZwzy5f= z(R{6}p4Z3M)tvjbNB_pB=({rXr$k}lQ`?+iR8bNYYmm6KA-cuykeg0VdiSJju&UPmuobx zF+X&1ad5l5yuzYwn_u5HyDI6fsy4a$o$bn_JNE}!zW%m!S?at0zUOb$Z{!f1Tf4mS z%FDOP$LC2aE&95>j6HkvC9cEm>i7RV)l|y58L<1+uWf6t`mS7muT;fwsTSkQrvF<{ zZ8>9JS65STUqvwX$4lcgzklvL*u4L}@*-dPm@KbQ9{D*nPuD5`dUbABt>-nt{;c!$ zUmZ$R99^dWy=ryYsQg~-mh|Hsg0Ua#x4-sX+-GaM;rDX&ju&_O_44C_CvV-wJo)y% zJ^t}`Q|otLv+(l%&~E?#*O8SPf~9lrCqzB_@Xzz_jh%Dqyga7W@}=)S^e41(&f6@P z(7ETnwM^?NQ2Nw*=BMepk4KiwJGXhJq2bIYeyh7zW!W5mHDy7Hm2s=uqu^EZ;x|X$ z4bhrg|9sP~n+xt2NhUwr(=2dghQdLO>?sS^@*YpKU|>l2wm@8zp<$6=nP%rq-3=C} z85tU8YKPe#T=ah<0|NuNx3~G+tvxGFvsiZJpYaXMVPH^D+M6rmZGO*X)5h9Zcw+q_)yjUt@XM`606nS&6pVy-hqmJgXu*g-eTvT zS_jlHGb~V%;VxWqd{+Am^}}nW84~(HsWd?0`!_pY`HwQQ#Y<;3q^(vAWMI(XQ_SJY zydidE^V|b}&$ItyV_*_rujMV6@oIU>U-P>R?#t@BD%S`+ zEckIsFk4R-QW8Q7!tTl8-uvqFJX)J94you2G_?8pV{`q~sZ)9^8WQOPoysWXCvgZ&)4J|x`9JocgC^9sk~ zSC6WP+D0a;nk+0&%F2GU+IR+z>6_JHN;3tVNm9Ba^I6+ZS9Fd>Q-g zmXzfi3$OF37Hjif99VMs#*da{71nugTjyO$-D2gq=*HnsxaMCtNBrqDMuun81P-m$>N>3Pe(8S(h6Nn~P0S1ne#FS<7W?O~J^ZMC zq57ejSvLccrHtxq7S%t@w_bhCM9W5C_M2|uz{fMMK6CmV{OZF(O(ibVU$3X9PyHqy z!?VwF;V}!r(%1_LQO{01Jb9vEQpdEMT$A2eZ@T;BdIbVcAG?*18@9LkN6M!9>k@*Y zCO@OiW<0j}d&(opOL>uK`1ToYyzgeuu#r_>G`0Tv_L<@3T1Fenn>wt{tzDgUdR3p` zd=I($yomd|RK?9_rrCUavmkCw^4s0kzKegA^}bxnW_IUR>b>*oht#+C3k6=E*7i#@ zblKItUjx=Z5LxqmZe?+M<}u~|udko#ocnpA2vJ($+TD$7DtHDbR_f9-R+=JE66?B9KbE}F*Q%D8v_Jg?lJT6w|T zzi+aFk4|{lJbC?{QkVF z@`_}C{x|<#aw_fmqJPa~{mETEZTvoYzdza4mQMfsH0rU2?m_u~e_jhOU*xjoO;_4w zqxSFqua2J!$!+i0vSV6LkAm;M;2N zjFTMdp#ICM`uB%T=gqj%(Q#5_h1vNTGkl7cUv&*NotIqde6yz)%D4e^Y*e7tqMr8wq;;A!{SxIz%Zrf=S4{d zhG)wyJ)D`LUDqkX-hV}s9W!i9K)w28UD4aKi&rwU)H5`QfLj>e=lGIx)s3(ED}HWw zwDD$UI3svj*Sy%=Y>B1MW$xRp5p56b_!tbdK^^TGniFHU9eQ~3>RSIu{nr{_!wd3%XxHmtXv@$b32ykBB)y7?!rhg)lH| zs;I2j(tUICYSi~5nNqW@?!DZ&`TGT%tJ222fsbSUCw?lqVxlE@^^3d`vti`PQ&U%; zyb^PAgH@qXQdhk9vPbgvf@b>0b7mF3`7tFkq{hpeU9z|L$mX!=0xxe~o#;H-Z??go zX_X;4HZ!G46Ata!oTqYMLfR z&Ani~D&X;-Bb%F-rM~*xFL1Fl_gUcMmsjW3WJYkN%;ldcYf)%a^yK5eHCI)4N?q^p z@a}T%|1!&bq5alf&h`8=-FxSH&7Gh=Pu8SVO~`Y7-XE7I2i8~jEZ(6tY2uY_?|)y_ z{H(U*{8jV%%1e88eOa;CpYO|lyJ>rOxulh@zh7&TT^e)bSkS>9IivZPHlDnqVY+IT zTcPe>=Q-R{rQJKfq=*x*tsiGsYM}a+uo%w>?>ZXA5E3I{&iBWx%M)9mKR;D3<}NgYGxvnkc{7cskYa9 z_on$K%+U#MQl9+4pj1HHVtGlEvJ78*@!zMeH*d^;^Y_~M_dC;Xo0p&c8pp;kLstC% z$6x$+%5Kk1uU)0#UHxZb?&OZ3HT9r!hdWKTK&kT2&O}g2H$CP~%B+t^HaA!G_H2Fs z&ZPI%ZBw%<6(1MrythWZQucy&J8P$O?Am5>W&H}HweQxpSFtWn*!%v>Y-=B5xym*5 zoAljWp4X)8%nUi-_ps4c*rnv#T<@t3IWnfu!e>c~%4Lm%t~Eibj*VIMM|Yk1yZ@!6 zwV2|fZoB=rOkREYHZl1;ui(XJ{_A+I{pwxZ#_zxH=jmXVE0vCiSG~U7vsftj)#`Ft zPoI@u0lVJlU!OVc=dtts{O@L~EXv-u<>H?C^QCQm{I=U<`*)I!;I%JT=a&ASv_@I( z>b(E2822tZd-i|nyv&)_@9l1FPCoLtrhW&wlv#Q57IJIIEPEYG{g2P<{pWNEUEHKS z%lEX*J^PjN*3+;4)JnbiykML5nGo~#nDb?(i&puiS37yTSqT2rO1U|IuT`(QnyFHf z5$me6pq|{F%+kQn-scf>&%RvV`D2P#(+rnJsnf5Ph3x$|<@BpG|7G>dJYR(i>BI^g zP8DHbIAc2nJZinCNWjv%!<5hWYMi1X$Nj$y49}dNP0L)&IcdG84~UtTr176;0(BRbDQgR(b0Vc>v(It zF57*>p|TaFYjTV;Jm4$Gke~)GY`AZ(&AO3d_(uA{ zhPe{``xzLDozLgpSZ2Jbe(t_@Yo8u#bA|&l4xmvh2bU$PCYJ@y&2?YO{y|0jrn2#V zuCr;!&M5CYt18)G*W=3U5jm_56 z$NJlszL{sS?APO!whOp=XY$3Z`mtwO*Tn5=XIFDCSCg~MkTW%%67}rFM9uoL>y}mV ziodS$zMXB*7nCd&ZYfykThH@G);Rx=OO`O(w;Arf-q#JEnQe z71(R-?tA)5b-3d7%lR4qQ<8#A`)1k5o;_3dsdeF-ofSrtqC!#>-j%$G@v~pZ$CHB zY|@baJ$di_Uq5ZX=lp)QF6d1rL&KxpKl-oNKiGEroz3fD*T`GR{Pv-NktZcCTh~uj zadYW0OzP=SQG2=nmF-cZW&h`Y>AcJwxlI1%nf)`LrY|#Gcjd?G%qhD1ml+szgjOtK zVlY@O^LqA#rBiv2yNWDNwPs*A;h*@{mixMOz5OjoR)!h2AVmRsEwRCipK+$??q1k( zMl)Y`o|b!(?9s_htD8EWH2mYdEU-lF%Pc9Mv`zNEcP~;fJ@+-ediGV-psT!V7Pn|^ zS)!nHQ{T|CT0~vpY+CMN=Mf8un?19y^F6%$loz{Z0eXObmloj>NY)%i7yqFZ1?+Q=y_7^xMy$i z-wkEp*4Kf1oO|Wm6Q4W3oz%6=^y)I@x=*c%x(8KT*X~(%b<3H1a~D_T&T0z3UKm$< z?bW0|FD5frZJk)Uy=3OJo12qU{7>+Hu@Hh22cx&;m`oYErTBtP#bBLjmMH>k(4sL;>n z$qe1+LMMs~`L{JE7Hs2CvCcaaL1{yUY{oA%nRgLsCr4?b=&I8 zGGXpf&!+kZseG<~^~lA=C(X=Q%_8&LYVWM3qP2dXJd4Vh#bUhI`)!Jp^?#lr6&5Kc@Hw8VsoWT>y*~0Tdca>^i_LPT93a<`!|0MN1sidlhs=bEF84NW4xC$Y`VYO zWZFF|$S~hQ&k2vF-#Wk2T(|g7iptan1$OdN8jdV^^I37GRlWSGTTQXiQk%b>oKp2` zYM|}Gi+i`8+;V2)@rnx_P?n#}#FtS`%##ZhWLwY?u1SMP=%P6W_mh zuYY%DdwI&)sSn)ey|^wcV;U>EELCm!7O+y2-DwtK{n_=VR@{!5*uwvM3=9pz zpyt@KkaNc)Z*#Kvmg_|ydHztu!oV;?^+y&v!-RGr`&DAqZ%=2Pvv@z}bJ_ks&mQcXd^u`P{YBxEw_;zFT$el9 zv6I(lo#lI<>6g#{e5CZL%xib<+{ZWl7F|e}?O#b<1JE2$iIeDL&Zu+l$ z=;4X4=5e8GdTZBxpI9Gn`|q@R-Pbo4m$P~8el9MQy;;p^i68s)z#}>L7A`ZkDBi=l z$#Tk>-{}jzRf7A~kA06QZr@tPwP3|+nJm|DPG;tn>eDy^i(Q$%ShQ zJ0?~)F~8(zXy5@?bmGh2oRpa&me@1*e$mY%u8${Ao_r+!ePynSq2=$px_V5ok-DnH z4L@7#F01-I7he)#)B6%NwUi!R#xr)=lKg^AZ^-LUs@&$7wY;w4LrcYa6t0&>3>@BzS*wJ<+>RePD#GI#K4fs0aE@*<4L0U`Qr=>-2VT*mo4#TVCVvcEoc!m1H+8(;4oQs zXx|}D#ScIE7!v+z{V?mBZO`B!2yTtce-J3akf8T)9XEqPe?4e$#lSo5gU_3PHoePp z85(vPc9$pLImyV-<*!-Fz`$Veo>OsB=Z?#lcj=t&dbF9(|46dmW`kpY{xxKZc2>-} z@kPM(D8MmQc>8q{&>8?dL@|B<4%=8dg?4V#_&3NRl)pe04 zpMNfql({1$)TA!NDOCT2pG6{hUGOabOkuY(@*FeRjwKr=^<5VMt?%8QF#jF{!>NNl zcJDb2^Sj)*71@4OwLaLEti3v0N^17n!|cC*TU^gc53Kq3?Ofhtfpb3{;`<9doP)hn zLrV`Ds!#4bxbL!G^^SE5SMFL?miPV99mzNEpUw%te(ma2^ILusI*zl||E^Z`d=;~) z#*9fqQmWvjo?u{daJFk`=*sWGiXov_&#&%Vw{+8@9ey)S=3Y|kI)DA%&Lb8r#lG{G zZd$c!;mWO7Zttq#RP4C(IsDz`;Deu;7#gfWarVsV;7Tq>rxz>xihRrdTo&Iy!$Ql@9E=F7b<+Mb2ap8dCiNmP~UIg=Vj$( zPEWCv>aBYn{Xah|%SdYGrR6twrJlBYKF4;lcuW1C_IeLB;cf44WM5yi^HbMpb@gLP z6IV{V)^{jA>C~m^`~RedhR&9LmA~gBTUvOEg_h)*j%sKUZe(kkL@z^a}ul!!=@c)bd|0OGLnTE&TyLb-Uf%+_F|_Gb>!H1;GH@HLuv=S+a&nirm1jErdR#n@WT#&!)I??`G3-aE9))EniSNqq!h(S&QnIqLvHNORpMOg=U$sgrzUtx6gahiHLFwO(Jg0?* z%1TIBe82O#t-U=r{p0W2-}mmUR(oVO|I)pkE+2pX`u+R7-S0UI7cM+wQvYkE{l7Qq zc6V=F37S}6&)Ihp1U#qDIB)-d&-;5{->y2v5{@xANUzn}E~x4vDj>O|@$>-T#e z*T37%7Jrh>iDm^VLn|L?o+ z*TwEWry1a@I zwky@RJATUldnkW5x$f=Ox#97}e~%nFGUxrdooUfaPdxV)eJdj`Eh{Oh^XOHdto63C zx4YcsYp>L9a9xiEc;_Fd!sJLV)?u3WY2;~L-n|NkDIsW|g{ns0D>`>(_G!QB7< z=x7`7|2{2O(1xLbl?~LmSl}>ua_~eC6%nqzAKqMc>R9<px%L7;(nTH8eU}y4zJd^s4-c zYSGlAD?OzapRa#sEdT4l+ld}7r}KKAZPH%X>7w+|qveum<*Qe(=2gGD8DU~(XeZO{ zmYP`~x9tEI1B1bBaG}k(vB8RCipt7u+uAx_z1kG@bj|wJ=WnGP>^;h+t)-onot>S1 zSL)M~80Albf$r|@%QBUlYmaJ8(?7XMuDG^#Zec}eYS`gv*ZS8bDF?#6yrApUse~1WtWLl9FhO9?rd4VJXI|Z@SDD%2ZzXQIa@D$v){ke*l3Blk z!`E-wr+|+YIVl>ed)z{O*WQ00zbVDDBC9ARtlR~2JPuRSrMnPiD z+O-$I?-vf1X8)CU<$HvQRA1Zj&+%R7!-J!z|1=frbvg8nH`?G>)~i>(w(nh(A7-dH zooiay)pg42^@sY67Zcab>|djEdS%Hx^Mzdj=VA|T4SBbC?ONZ|ao>q6DJEI-1rvHguV1Tr6SsZc z!i}p|9m}*l7OU3M(X!mc_iO#nnu7@%Vx1D^W&%7?_YXhbIOFoVgdWzWgANKAZ|)pP z{q@E1VvXJW^YcrmsR@5v*~ytL*?VY~Q$}8{dFk=jC89p&Hxs_!l9@NF#OkJr@7JGy zj;*~AVrpahQfR7<_QI~NHJ^hohnTLM-*WG}Cc!`C8}o_4V`T%=vXgzV3;#{Jz5$ zd$w=?-YmZ-w(Lf``Q3`gzwdpIJGP|1=81B>zs<*#^785Tex1B${=N2%@O+bfz5BoK z-M;7Vv)L+YZ}08>{cQIAxbW!T^Y8!JK2 z|2=EE^ZdwD?e>4z&*$7OdpM2z-_!Z~w>-WYzW?Xh|7U!H!^6M#*Z;3~eyPOlZ~OI% z{GWsFQqs~=_0q4_a{qbZ{_nx0Zha}aH|tld$;!!7U9|iCzk~Pxy}iF}i^=utH^r5s z_SgNL|NmzC;)w+&Lf2-WxY{0H@v!x3=(ndLlTJF_YEASxRVnJCG;#ahx5p-{`^S}^ z4UPY?dcVQjr(3hHw;q0I9JY3fj{1kLr>Flv%ikx^?e=TY#J+c_o9cD;f4vqR9$)LL zArZ4_$?39KUS8h+-@dMwJnvuoLo_^2^22TO*}JlyuG0T=_5a3qt6iNYC>YMY=cK=Z zfk73tV3466o?jkQ z`80HT>?TtYuT&p3H8sEacD^q4>-T({^;Rc;Z>a~z$7i$irP%jR^WpXK?Y6JCO#k;lSw1)O{e-T&W=A@O)&0JHvHA02@%B5P-lfm0Jy$Q` z;Ol!f{NK(^8&|siFU`tYwS9Z|{ob(9t6M`uLua46HAAxK$A`qnb{lW~{Pm98EPvmR zMcl?Kt^S_a_wSe9a%Jo4M<0Kz3|{Ux&*tYHZvBYka+XCc#d*7R_4jT0JIPyb@0&~A zM$r>*zEXDYzqQVL+SAqRc0F6PcJ}K_rYEYZs_N>0-)4`m%G`Z<=C?=Q`tdaY@W|4ws@WuWLxsXKrl2se0}_WJ)usYrMDkP>?>Jm zml`JV@|yFp%g7k<$;->j%SrzH;QsGJYx?}W z?Ch)TcE8^g|C(r+06}!&Psy*DwCGovpY1gp#J{> zcl&Q2pKr6hdGTUi)QL||PuJgyigtH%^JVq#ld=7^(!c)K{eNHM@BQrC{@S_j$6@)u zZ}0!pP0o4UDsJ_5b$`v53U>OU=hZ|ytB5_Z^Me0>mu~_|Jh`IuOhjoBqgcl%9btO>v!y0etchwyQ^#KTd~^r@8oMf z&fjPBxB6S+uQTa(rH^^9M?W``yBV44HFIzMuUFbGC9i%6UjE=NU;Srt{h!RkZYjA( z&Y}M4MQ!i#5dHy{;>gk!Bx##3LBEC0o z3=Tc_HhcPvXGXaT9?a3nzbhIVDs(#U@X>;l=W(IFYc+q0u3BNzcEt4TEbA33)|kke zKGs<^YsvaQmA~y1I15 z*2n&pu7Vv$)yflNT;r z_`d&t?d6|;9$MR{_!h7*HGV#4+kWY(g_ic})w;GbUWv@t_Yl3-XxVI-J8|WojKtxjo1rL?sC|K0olFIw4rJHX(_M*BY*$;r<7=TGixTNdEzy0Ck`>*}zzRc|)B z9}b=@{5aXAv9#=hf)Gssp_U`WQ`Tsx4&sr8WS@|zB^U`}^)%`Y~Zk(LF ze9hsjDU&)vLRFPK&&_@C<4wA~bhq1=m%V;-Uuk|-t6G$K>-xTLThBCF7d<(#di}m# zsi&vS)D>l55K{(qf)g%wsteiwc-ZePd(HpGIf-CQU6G!2nA0N}_RX*E&|M$Nd%?%4~e>}C? zIr#uU))) z?PBN$p^(tMkNd3uzd3JbzkidoUP|Pzll<@ZeVetq*zf1%`TxHB`D}jv^&2+9zc1(i z%e0ttRqEX8_4|H3Xx^_~8pFU~@P7d~g;3(o)S67hG7j|6#k9&fPLSJ|8dHu;A^c_in$O zle|gica7ct`}w!Gbv*hU8hX9zR)O2L=fw&F8oB4U##v0ga${d@wTTpW>!;TbSs56_ zEWyd*p!(%G9v>+57-Zq zoyQ+1Cns0s)<6D`Ve<9UnVoJadf^6UW@5c=YvtE{U4L-au}+Q8tLkkG4QKisQ+{Z` zskA7?Xyty+-+${oCs{l%p77wooc`Y4+sAY~C*6O){7su&i-6zd*S-m_-a5`wl9!g| zZa;kOp5e||YpIP9I#RuUem*O*u6dX0%$m9_VbV_4E)NwWOG`-}zwmC4_ny5my}iBu zzP>lZWIp`gtyi+R(U z6PwOh{y$}3|5p3|AJf~BDUoVIQ`WsVu&~&XdHH5@bMws1eP7@12H}nu@9N**ExkH5 z{M65M^OgrsqUJXhuM3w|P@3;QF*Wk?7W+Rx)N|G2_SM|nrY?WpBw&@s%9r+^ciNZV z(%q!PJ*)2X6cx|&d~a@jJ$7vK`EnlXum9$7{Z^L$`9i<`r}y&Elqz+@yk+N~3p>5J z^|$TigxY`S?S9YnulJf}^ENz42HzlL^Sx#ul= zQ~%G|`?U}A|DDSe>&7CjBS3oc7vzwj`g;CmE2fkUotQ- zs0J>3Ti?aZ;PCVJhxYe1uU4wZ-kZqOcwoK!j{Qq3cRe~>`F!s0E5ZI@p`n&%l}>+3 z?zgQv`gD3~Tfw=x_nd@RWxRc{X8$i~d)gR2ARtzh2{%GQWMvwPU?A73a>K>u>w@32(jmod0RkN@D_xAPmFTU~5XtV$MMEHIE|KDpazpqQq&vp+tnDVO5^>T&L%ri1KU%h%& z{qE<_`F~E%-*H4uvvJxtzv;2NN?u-CKCkN2ByYWw8+#ub2znM>yC*Ftr}+HwQjJsP z`##Urulp!}cQWg&WvW7+YB%er7#DF?r<6?T__9hPdRtDR{ib6X#eQxs4?SEsCWdz< zXJpLim{M|J``vGK-?I%&uYcf(G^)CoaV7Qb;>C+++6Et($_Hv9Y8+%_U|`M41A%`J z-fmYHD)il4d6SQ&>GicWX_Hhoh8TApOelDLZEg9Tj|(3zR17}KHCIXdbp0;t4v%S~ zwbNFuT6H^bcWzCMjnF(3-#ZcUmx~`|xPK3d{Pyeln@y+nyw!v|EAEuNd3JWT{hx={ zizj;2*2bnKq^3T-wl>=S%R>I6$$__L)Y{db?_6A0zhLX)?hY+2t!;UCtB%W-A6X>$ zJ2#|8ds^x8ZGn?IPCWmddw18@*!NZ8^`)UpSFLjS#yNMhd9KmFs<&IOhlGb8UnH1) zRcQYC?U{#nE%l!6F)61;|L&g3&%5vc&0Ci_r}%M<^tJWxEep47+*$hd)m8a_ALg!F zWoB-gdhFDunsb)VdHDJHzkJV}wQPF5;mTDUU*=fcy0|r@$V2SM-+ybPx8Ex|U2S#i zcFeZI)Ag+467_puE|Z?FA3v|d{iI}a&fi~OPo@-oUl%)TSy6jlVfL!ky?a;0RXl73 zS+k9IpTNaiTeCr7kbH5)$ECI+Ts!3>@6Iv~pS=3qxpVyWKm2?zUt1gNe2=C1V03=% z`vV6Q7Oz>Gosn^4SLti^{Qb5weRi~5xo38Fu2*^a_WFI_LRW{~^853U|NhFAx7xnG zHge|LaS1fL+k`ZJtn~WW#%-~j5^S&b`}Lpg5pr6xN_|OtCy&uTznlL(|4Q@u?|u6$ z+k5Z)O$F!t=i5Bn@>*+kmei~qySLxwSUkJ(qIt~^t6kG1+B0UA{d!_}yYu$$X&PR2 zYd!etzkYXJoah>OYxlIM<9uJf9!WM-^OTMC_PzfwHYuzIG}Un0Os=%*{Sze{PlknzC|Y;9;$rw{!1qo62_VxSQHBH(zGySK&*V`pV#X!pv<(KU7I#?MzaPJDQ>(=c+Huk4yvZS235A8IPSdJ~uCb!U!U zrBA-=QP1kvIZ%B_1Zx4%}qrd2E&5*B6}v8%zh^iRj{x2qRdM=o3A zr6l+Mz3tO2Wxk>Q_4BRr?sA>``Ev5{T;rH0HA~ND^V|N2NKFmhbxM5py1%IsPA}IL zL|E-VEFszcx;yF2kK$MN&uDCVd8PB_zns=3LJSUUpp|zAd^{&zxp3vtm!hYif9JMe zH#f69o21LSVEv)8r1wY7jaFr4J5QZD$yuAzbnDlssmsi@AK0ed&f=@*?bW^WF!#br zE@$7^*w$AOt?eExOp1@+mwx5-%fB^A#nQA>VAYB(X{}8!Rev-8Yg;CEd;79euUtIUPLl(w((8l0WEmJ3 zrnGrnHt`J&4GnD-aGD?x^S`m92_bC$y-m18RN z{a3D7aln^{At4a7{VhRI(8*V|1?M_< zEL+*>q9nl4;-m<=qDc(Ay+W)z#mLgo&{IX@?^olA9#gC|7#i+;^4;+3Z(Z%W3=^r| zV_DhRBCPy-85p?b-+g6Z=yo!Z>UCRORi-@Cr_0A!nt_44Z{FUiDkq_Rl zaKNbz6r4=r{l}FjatOZMyL5_`3`4`t#n*EKLFW+v^^@Rg^^yfG(h~c!kdgq5qh z-mo#~6jk}(a1rTsD^zD;sE;@RYI;R%Xb}(=o?KNdU9pV4;i%90x#}$v^79?IT^Ja+ z!Q212!))Zln}h?6X6lscFfgc2JNLP(!Y1xj1Zcl0Xo_@$0jJ}|j42%8w`#n1@7H0;(OUkmYcyL^1}PBIiKq*Y{EchEcgL-MuU;O z79+y}El{wsFfeG?fttf&YJZ(or}nznV-%RFWCotyu*EP`@Ko+?V9rvmiE;=6m)s=IrD32r|4;A@%SkbyHxrs zTNRXiFQ-K6ftIE@7=pdT@N%!>v#ED)nE(9sxcU1^r>~w}XHw)pPp?vDI2G8_exK{T zrO@5&E1wh~=Gny|AI{c(z5i1$ICP=LlVA-2hx)+An~F~!KJ2=;@51TzJ^TM( zJ8?}nE?v0EaGHm|csxAd|uG;pq0`2~UDr z%LNZv|Gqc#Zv6Z8gIh>*x=CFAtYh_WD(>>v>#WR5`CQrg^mL_$hfo&Fc`h}U?xR!g z?dy6Tzhd`)#`?9})b{1A{eJV}VG)J{hnn~AU|`@5h)XqpWbAO)4zK^^r(0}?MBFB2usndgO!oDA#@A0reZu9fv`78_#m5lWzj0|E+Y>Y%|>pun;3g+_byyVc+ zExp0;+1X>2&E{8cW{A~Re$jkfP?>Y*`u+9WwjR4aC-Rkq_{1ZZR6kB#{UpPr;6=g8 zWJZRDAaDV|_{gSz(e=fhj=kBwjo*UYc@5^5v`zE$v6HnvcJ#~BXVNk$7iZkM74+(b z*xVGTJ-O2S_ zzM_|X@100a?&)ZEIvU0OJSI9tJu9*0zQ4*7j#Vod7<95SQbZUM7?XPT*ze*Na;fy$ z&v55^bNv2&wdE#4*{^eIf3x2!d)8*m6>-A2f1iPwjhjofp7s9vt(Tv5|9!2$zwprq zPo=2pYctc=#Ltxc_dDKZ)v8y=K3~&~-|Hj4>GRUN>izRh`6!$&stvw7Y3kirZ|gPP zvTvlTKCYbJ`C`rI>-yHpc>P{Cmsnlh z>+{Ozl{W30II(?OzWSnNw{C5hp7vq!ak<}DH=kek=1t7@6iz|Su1i<%)SPVNwNrgv zFS)5a<;lahw>w`P`uh61-p2PErxyRaEgmm3bH)bQ-|M{f*REeR>!P2s+NYCml@2m8 zZ1?~!Y#1KyynFJav-G{?b z$Ls%IS($9>Qu64;N&ni1{XWT8m;5@=Utd@K=!B+{ki5t-mgDQ|{zUs;{li$VcJSjT z&qry`9Dv7OV4_3e7M^G+sp2?YgQTPetU9JuJ(#+c)F1?ej zjtP@pRnMV2iRE~X#N1iGKKa-GIyBFA<|gUCix=n1+5bE9?rweQ@3&`5OP9T5y%=8i zZS&mxy{<0td!NtizP3Jp)ml^E;txkU-~V}6?jpj)axQY~DXW9}+j4)u6!sUm_-dVA za?|7by6?MNR(z1feGulI9&&h4@v zUovlR6wkk5aG1sY--TI53U>;GT8abkyx=jv9BkT62Lmp=|897!s&D?k zi}nBieBWQQWrGsq?(#SFe=pYm%}L4$nzZEAtyf!TpL-K?YvB)(b3e~bFT4Nuth{)P z=W+QD%bnJ8{HpP)TA*(naMC!M#qGPz&nKIAmuJrjXKS8)-sbZs-`THLuaZdC-~02K z`oFjLADvv1`K$3_pzUr)msQL57CmS!glF{PLOkZ@$j?ua?cfRY1ieq^eo@jq%02$|se3J&u;X z-}h^8{RcnKN$Yle+_eAqm+4oQ?0Wk!ef^$~K}W+M%s;AL_xsCl`?BuB?e{<1@4vFe zW>%HzqOMaHuGf9=cUiLP)|DSu`ku$t);~DD|M8sv|HS*(*}gs#`a0~%)-4}Go*cjb z%kp{5w5PZKzqr=D?w$|_TZ_PQ|1bZ}@BjDU$HU3h9{kmyw9=pL&{>A6tT(>7XxcI-hY>(~E(XP)0;Zf10B*`ka4 zf4wU&e{;Xy-o)(NvyYFTuZc>XQ}=zMvda;P?ED-XTaz!3X6N54ILNAZy1wfAI{ui_ zsYxChdrDtjxfr*-=8o+3*zXsm^8{QTM!Y$?w|f7N$MUOZeY4;H`|eU{^RV!cC%YSa zO-;Z5yZ=91O5)2|)PNMrnju|yZoB>GRsZTgt6q=M@Dvg(E!iIXyHC4w#s4o4o*W4| z$bElz@&09g%Z=OE+sbXW8{cm==wxkbbT9~r483^kX3^*0_rLA4uQ5;7k?Xdvcz^h( z+}Y{d_ZnH5xVcQfTkvtJd8`-*TStfCwVhiYAD+K2HY`Q)$mRX@W@5df8}@ejUv%bW zVZN+tQU7P(8Hd{MPKj=6>YW*t)z#I(lm7|DiE`EcyB2L<_xY^+-jBzQ&62wO#sBRc zPZ#NF`t|>xPB%Wb?fva^-KU8qJC>&x)YyF1e*Q=L``zdFrmQ?NL&bBG%GHpNnC+FH zk3BuznPDR|v&V(&hC}2er@H+w>x*aRMda}EFf-`LRs3V9XNcGk5<2&%lUR?7j-i#s zs{ePc+?pb}@8_lBPLJTN=4Eem6E+?U*syKivoD?Z{#|CC*;pNS+uvoatZuI^uW@JP z>8G>*GTIBywYnzE>Av^;3CsIa^OPUI;WnFftW5v?rO&b#J#tj``Y)(ilaZ~wX!`f} z|Ian^r^OwezHM9Gmp18oyQ05ey`wfoZJFEUHox{UuhOoh%gc(x*MHMKRblbxws`!O z*iA~O-}3T)O!>5X|Nq*w2PY36oZHSPc=1~4>pd;UJ9f>Q-RW`Jq_i%L>yvIQD+9x4 zR#0x)ppgM;vMR00Uh$QE8TVoHt!6Ke^0NJI=ZeTlEj`+G^>mAX{oil(duL8F0#!=K zZcH_g)jIoTafxrNZ?d{QpDthZcBL7}E{-Qwl; zhtI@ruQV1cJomot$HVP^kH**hvj6uu`}@7$H&(CrbIqL;^WFaUnpK%DCD*z{WqW%~ zr%rYGa{0LYcHJY2hGm~!#RV@a*ISqI^!2`EE|;-TXo=XJa`M+&i*H)Qd_370(9qEn z+gqXTdFg8Y{wBk1`PUELn^&jw>b2yJ{l6EiIq~{@r1jw$l8f7xRViHxFwWeomPit-t@z;{58__cpw6QTcSLk@>sr=QH=~{{NQ$ zb!mFv_wUl$+Nz;nPtLXO)OhfD?VC4iIN0>>?wHuorl!{S{rhdbKc_aI&s(`V*fjU| zzrQXjEkFKx>kD2y8@+v3%HuY5wZ1RkWSZ>j!Q~2(Hb@&tI`lFM;{- z$tRE3?@jx2|C{-Jov(513=ORey**3}2No%u-1KO2=ZPziIj>jPNU1M+b&F~DikQur zUoVB;J$}#X<1y{(Th`I?KR)KS3cS6W`}S_GF@JSQN>4|MYv2@{e<`Ooz4^R+nY{em z3%|=ut$tlARGL(uvhqP$Xku9Hn`6@VOFtex{_EGgyPKaM-COO?%O@20|HTXW+P|;= z|6A!l_vYQT{$_G~^JQdI7I9x+D=jInzDV0F_tNQ-Jw*==yjrLCdXnm~yuFXQ{#QL{ zJRV>B^%=K*&EF3X|El{7U94OkZvXYyYrl_o{=eD0zw#lg(j|-Q#yYd>!`A)zbliTO z$d#|2t_D9o&dxL9+gKLO&A<@AU~`QDWM0T#nr)epnXQ*| za*|5yzir-q^1p6+`@g?Y^^`ULt?e0!>ihEh(x36>_VxSneC-toRCsWHb-a-0G_BP^ zwb4A^__vm&ZN0T%<*kX#?wuZi^&)!>`IM4^Uj5#?_2$J7Po`u_&B*Q9_-xm%XS;Tt z&A!(0ec$&BD}(Rvc)#!Zy{c>_A3=I<7PM{hz``}kHzY&A6zn5g4vI(2IHuHE(( zXX{P3PMzAC8(XSTa(im{v?_UKh67CCMH4z){~Gph+qZ0gdP7IsulC!!qdGfS_U@}S z7xbJ|@@-l#tA5SfW5%_1Pj5u4Z?paL=f;VO>hRaUHeWwukf3ZB^qUtV;p){K#qmt zHx-n6Kkt^WZ0S((syBZ|JkY@cd1_Dg>21} zaDRcoZ1>_7TKzmtp25+NyG&1azG#%U*J!!1qw+A%;@;zr_WykOzP{|beyc#2f93hP z@0Zwc`{(Se*&O%s*~|O(pN};Ar&~Ricq9Gm-~Rs*@2`B@^je>U%;?CwvFGQ%{r`WT`Ty^iv-~CXA9ua=Z+_F$@w}9N@3Wjz z)z=3H7k>O0I(M#RcRuJ!Xl{*z^^6P*-A6;s?ReE=K7{2)a-miAT`oKV|CQRHe=9%S=t@N=Yd#;=X=vi)qZ_`F0IbiMO`PDyZwvSq){p0++N zEOVvB<*jQTGtb{Kwd35Kini*ONh))zFW&tBAwIq$`S`ub?$v7Q%WCSDZroY;*E0Ls z+|6#=zSJvfe`^1C{rC2mvVYR+-@dgr73e?Kv@jt${PnKlYjZZ{ExoK4wY98O&cFWp zr*oE8UEHzZ#h>&4znnks{_gJ)@%K0G+ZUk}7#z8??Bt|w^PCqsS(lazy1d`_CFopb zdhzBQOOx&K#lG3j%z{USIcrbMTIy|IeOh;uPP$cD?fa+G%T3M0Tb=H{~`SU()!Y0{F_wn7QWq@92~rD^44Xm?}2Wq z??DXX-`0A)E!j8t)qW}XI6jBa%=t#io7=e+HGbQ#tUvs4<@UQZYk!CF@be1?+Q@z1 zbW*>^W>@W(lb>Jf<#U!ysrt@*M%|z9@2&GqcueE#|2Op=hDu)i ziB(0D4UPD&i%*rDJ*z?E^0fS_b!&oBj>X@d-B2pe&9Gs`0??^KN6+cAc1nmxtz>4L zksh+ptLJ3SE*&2J))oPuP;c2=iw@UYs4MQcAOFgMfnmWEP@^j1O;*jb$xHcI z66_?y-AyO1344`d7W*(fJ5Oo8Qh(1ht6i?{a&n22j$E8<$Z+6M8w)$bfu!qCvQwR` zge(^<6ku;KkNI%-vA*FXv#TjvFRV1Zvf6a(zsKqvtrpKFt!gWKFSbc0e%F#K3mF*d z9W=oMc{fadM4wx`yM_DTr5BG4b%S0NFr1ou>Z5PPTKZ$#0LfQs|M&iiA- z3f&g(cTL+jQ(r8h@!^r>lZ1~iVo$b-d7fRrYt2iww3l%epI&J%{nvPE`nK@Dugp7* z!&lFh&5%f%=CMla``6Zccl292*2bIvJhxqV)@>Gsh&!O5Vo+N2Iyx^``h8vIm(Ir* zosTQ$3&sgEyfK(0vGM9u>Gc^^?yWJY)@OhG&hylZkNUj&J`2CB82kN0M@_t01Pza+ zR=)aGpS^tDE+>tOHLMH~Z$3dUrts`yW_QfkdoUbk*6ea+b#rpj3k<$3Z-X1A9QHRf3reXNVEb zOJZaYTmNs~;-!2CFJ9VqDyaQ|M#%m(R}^ndb}@38ytMC-+~@Gq2it<&A1c_nM6J2v zXu(k`pnd&(;KbmieFrYqcLv6Qn*@vE2KRA*oa0H3wVpk%u>a8kMYU(uM$63Hr_-|~+-sVF69Db@Qmbz9cdCLNif z@|#I?U&7SOt7XNVypLHvH`(6FcT6JLCrrfio8{gcoa?%th!mEtyWb_LtTuW5q?2{W zGg}lEPSxpDNI70!s@S3K(LL$HGZU-7qOqSQ#yC!TV>4Ibp!b&hDoW1}v?%C$Ma}6r z|Fdqg2j2vlQ**a7F*LODaq=Ab$?Ld$!mv!wdnkD2O9u2{1@kMDVuk)UvsN@QAbY`;T+ueX{|my*bQ(|(1P zX(AsBmE1Pn|Jqt9R^Vr&_~`MWcwJ4#+5WHR2xq#u_{{noUh3#1u+n8y>{Wip`lu;a zI1Fblc@QJcC7_kb`N;EA=;V~}!%f*Pb2_GG>@O6WGb3rbyTFt=D)SVUo%vZOd?YkT z`N-ras~!8884@Of=SwyUw~4S8YdI&Hi*pJ!6`wObm+E;<{LqXeDxMsAo|BHtw9iZQ z)DNDK*6H6{=*xS}ST++6aJP@XP=3vo4KyY zatfX7leB5hS38{+flkgOA?|C{t8|0j%yn~7vUBX@JoqZIEJuZ9qT7*#qvC7p;jJ~w&w&suRf&MEf2JjrwI=IWE1 zo~Hj`Zal-XYF5qDrOzj29a^sOE2x-V(eu!{Y3kZ^$Kbf6#Tim zLdP%b%A^MuPUoFi`t!!TsFglW$_Ilzr}5~z`KT>jl(Nxq=AWxmW+>?TefnZL^;E6E z?AM1ZB7fKSP84vdvgA8lc{DWW@sbvglkb&u({j8TJXB4+iaJzm?l3Xv#Ql(FVA$|t zX)%{&{1xNUAQRu<(5uh+^DL@^V`H03D=$X)6!<1hTJ$8##PIH%mSZ~&CFV}+F;vt1 z*R{v2qxj$A`F~&CzW;k>;e*xI-)%k}*&P3O`TjdQ-kquWUO(Z{`hdrQ2TdQpRt-1x zoTOs;e*cm=pTpy8-^TC%_kMD4@UIC820xb1|M$3iTilD!Pp^MvPWB0`Ihk_E#;JSa z8}oFrPa?fXzbtn4d@S`^9I=X2xddy~-6wTDw9r#<~sth(*D z?~0WhxRqKwR3>?be%0){|6Y5~mWd(?U6TSn7H~6cnDG$Qloy!TUZ>jOq0h4}^JL1V z)zwEQJ=K=I_sB&@ELr7G-Tdg)E!P-y-ZpTYEB>yX`0+#X`9J6R-(9W$_Org`Y%lNf z-@iIDl9FDn|MxC?|G%HxKkF7x)MB3~E2n;L#RT(*zu(nAP`CeEX*5$sDRQD|X!p^i z|DU$5um8Zj{qDcU@6Y#I>}FQCn4eg-_<70w>;FGjSD8IL_IllpXQ#TkBe{ZGHk9qx z;>uo}n5Fe+{{O$awfj?JHvIgv{cb_+!sz-;--3>&&C>4ubMJinbNZpj6hZDbrs?rD z2Twiq=Hm77O65&^^W&qizs=7rr9UFmb9W?s{>iF$rGz2)x~t;xkjp;~_vgQUEA68; zxyyg$+I9P0wrOi?b7f_@?-%g8eVT`XVM^4_Z)^A%7*ahs)@4QMh^=3yy5onRI@2u+hvt&-byL`YJE-*1z@V_wRk*PtX5z{rbKy;lFM?e0VYUeBS)4 z3`JF6HXfgR^2w#8-upi0$JajCSN;F-?D+UgcU_z6em{8Mb)Elo&$P)NYWx3B{>{eL z&ff0E*6z0K(8Hv>`h^cwC!f4{@#3pjucm5GOaFKM&YhSyH@NBxS1o_vc;D7ev~Nws zt-UpoRoX;mup1c*6%sfYF zWtPwU#B=+XyCr|j&{?J)pI2Y|{kE32vrEavX~nm1&#L~-*7@SYMd9$ceOp6*PbjuC zvyW++~pPq)t);_&k{y(Fr$Y`Pm3sa-y`jlng-c`Roa8Q}|YpL?$ zt(tJ9qoO@6*n#pSA36@q7Kn7jN90eNHPk!9|46osF&C+B)j~_j%Ht9mW3+&$qo` zZgAzg{f%o;VwKtq3^U3>jiH7;9KG2mT_zR#xd;mjf4}$n^5J&A+Mo0HPcs#K?lfiD z{$r=QF6^&+xjw{Kc~RfCu-XSlo?Q8GqJGA|&(A)aP0f2hQN^>o{=2nPM^{(KVWl~r z&F|lFchL@CqtX86*nn*{rFp7+spTC-*7EG{p!kK+rNLAPfyq9Zhf}xc&har zZp9t;vGoEyhGHLncWB7@pUK$Cz_6hM)Es4~6ma6uW9h80+4j6Q_WS+s-4iEHJf$^z zouqfDXxy}?@7D1JpRxaOvbNJ@Qb*J*Y4bJFv5PJQX=!VN@^R63>3knQKiltrKCj=u z&sv15_C@pd>1GCZo%?gUT^6O!-}>&-+UL_lo03y<>U%o)WNKc|tFE^cowsW3%AF6I zxYzA@WVC<(foHniOSjhta9q53@z<&B{5}7U?aMH^cJErzw_~Q+Ve56i+MO2aKQ3SO zL-5#*Yux%8?N7W*L!Vw!jXm!FWzUAcTfc3acJE%}zQ%>BcV)eIS*PtQU|@)t1CFad z9+Q@6oZ>#8D_t)y|NVFE)~#DxOOg%S>waAR{eI_r$G^{S-}_w_srPratl->NFMoat z-?!?2Onm(R|9{_~&%Lu@;T6Zg{|`P)z8%NI@@MD1$L^)^zy`(Dq@*UwFO=+V-_CvRK$<3;DvyL0DctNVSmyJKIkar)ED^fek^ z^JbTQSnK?-Am#G1UR_->Z84p+5fK)%$U^SEtVZ{bsrMk23M@_Q+hOK|L0@b zVQXW&T=L)9f4Pu+yX?JXfE_2F@8!74r=gM4%;%Pd%}fzcQ(N|K=l}AD9$)?xn_ann zm7lL4bR*1v_3!_lO)HPNKl$}swfg=4?mmwH{eAbB6Z*S8-0}Z^ajsqb&OZ;cb94Vb zQMX(6|Igj`e;@pdxBYNrvj5!DYsa$J?b{Th`1W@Fj~^%JJzLgxJHOUCS?99Tnqxax zWo^=#`t9hCrn9s4Z|sRYuO<-a?Oj}2diB7819(JBwdG`6d(wj$Dh9$4o(w9)Kb4G>(dk#nhr_5xkoA3YecTJa)`qdPhz+ZamYvt&njKJ$~FJZZjaz0$@_zq3DGNWT5=q4xcrpYvQ)vK2K z%iCFszI*xhdNlMiFJ63ldivBq!TayOzg_fC zO{wZx{m<#uzuBvQv(2llV;5W-y?ND>jW56L`}yojNX6S*TUGNXT+Mhn$xo>&`Tf6S z^(r^FKhJPmcVs;6Qcc}-pMfFap62v?&~W;{FWdQ!d2n=gv5d%*_6M|NmoY`QFd6 z;yHHt&)41E|Kn(_i^}Osyyh|Chho30%l{9sF}&-XZZq%4ZT)}Jg0baSmtK!4EesBJ z=1f*z)U9`G*Y952{CBs%KigOPYr?BnuWsM_zVDLTQtRJqO4<43EI(Yk$eb^GwcW(* zO8lm;e}ay?x|mp6*8hC7`MmM5bN27&1RbB0diIs5dUe%zS&N$c>*cSt8yvf~Ca&=5 zQt@e4CJYQS)`N?-Jxh&cH_yLu;kv@77Z;Rg`qaI5-+$uIt=slLuIArKowH!~>c8{k z|G3vBimX2$eeA~b|8F+O|Gl-}*T=`^!|VGX{Nk{x=db_&{+ypyQeQ4!di?3~jSJ8H zSRHr1sbke@?OV~ayQMr8AO8IN&%fpmf4_|7t>Rx>mSx@b-Zj0XJXAdHS*z&B9bqj^ zgrQ_buzS+$SAMkv;x@JP^&tI$c?`}za`{T!v z7e8EbeM@~yL!+}7`nF72m7K-EP_Lm5D&-gi1vvu`u?e;csN}>2%vi#4khO4H_}o)T z`(G8T6B0~)FVlH)PPPim)18;k**SjIQr>n z>l=%8k^NGWMTB1Q@UPJE%nn&B&?%ew&&cBWq$%b8l2zBWrY)?T@*cEa(74;UFX+!g zmlPX8N&Ya?s+d{lpZ|V#{ondktNeuPMJ_ycGcr4>;(031I4Dd+cipO}pukUg*B2~a z{CNHUSNcMoEYIh7PP+eGd(BcG$0eCkoA+EXR8$+~YnCilbF{$Ea`X9OXTv&hkjf9H4 z;KX{VrI*Y;EOhNy(b1{Mz%Zl#LplRP!p7uDDqp@Sw?3F-e10b9!B&ALLBpiTR#q0n zB%N42=YsA2yOnnTXnScJKS?xxg_Y#o9`EFT38s^a_LmtQo7H_is%4p)@WsM)YRy-B zm)SIZ`M>%5{fiS*(~};x}+Xi69v{hY_<%ahzLyWKTPv7Y1_wz2D|R#@mX-}evpx-&d{+x`6AU3(>A zPL>Is4rz}RPwv?tyqxdR(Zk*P`7R7Q;_v*fo$=V>o{=xZ1B-`pLe7&^?)vAn+*p-P99{!)~Cg6azb4D46fk{BP&k=v4#GlfCGVaJz?f@~L= z-Pn3~K4?w(s8)M`gHfCP2+P5}vuA3yB}zO~JRl^)bJ(EYswH6K$$HfTXM43$-+fSM zVPNgq7fZQsZq#+~DEV1YIC-hS9)%z;oy%K%gcIN7h&IgjpQ7Paad?W5BFm)ySDpq&BAZ04 zt;5yL8hAULiv)7#6ezJAVBT7v_sn9&;o`54CbyXR3n$3A=u1c%1Sb^wna|dK*LRSK zW47*n2Z;tIRR`VU>~F8_P~7r!MgnJrv<@$itiby>w`91kFflw3J@9?1VTwdsVjbTG z7WTsiJj@))ECt_}ip@SG(cQFQRoD4XMKbx((-c1B^+$(_Hj3|fn^WN^k^gIFy@``Y z8Efv%4JEx1YD>Rwy81t^y;WFMT>sP$zSs8zotiX)lWrfm=a==O@km?cnZ&-`m*=sz z7JvQ@@9{YaX{%gfTTI zO0?aqkA3r9;IIKtv9Qx^OuD3W}nc#i^y&H2JT8_s$g@f3ZkB zJq_M1d-U0)MOg*>TPD70zRVzV?`WBE`PK)SH{S}pdr|+nv-K`tBgiSN5U<~H(cH?h zk)v?SG!`eDV}HV~T4^k0Q@r+Vb<3Uf9HwJ7PSMBGgp#Z+G8h^dSbBD@opoBsi}zJY zj>Lox!|hj3$vUmvxvlx!IcElm2^+2ob1|4LJs0+Xf#m?Bkf6eiM@QWlbPBdD&}Cph za9C{h#;*FScCvkIBhI$A>mKV(lxVATfhHgZ2acJ(YRNlg3d@Xm7$g=hSY^h}^n>qm zY4@dzDM~9}vm7}1(m$8}LyjEfO zeB>NM1;b9k1or5*fCa2vo?gdS-0j)0=ix-o0}2y#99SFJCrsXbI;TPB0*3?N2{{Lw z=;H?scs^$&LsF&e(h?n^lP{~%Q&Sy6xBq^-Ep=v_qoycJqi{?0%yql&GKR{=MoRX( z?bg=59@iLTRX@o`Vq5KkMTeAgVq=>GoN}cX+^9(Xe82F>HeTP&y4=Nc6g>A-Y(IT% zXN-1KoytrZZ`Iv3|F&)v^h)0>*%Q!juTZo*z;KCI;NhKjob1#;*L?k@er`dD*Xh+W zZomI#F>_tiRfW^ZJMY9eelDtU5V&@4>SoUyCVyn^>u8^2XJfcpzsO|WQ*qwdr#mKX z71G`&sJ{~w;OayXHJ3Y_wQQS4$py0>U@LhiM zcX`Jx^9l@Z6TE10*m;R*XHUh#gd5-TQqA*@EnDSzxZ`!}B$nfo;x=fMtXfwedooYN zRNL#wmFc{DRSpW8^Rfh}zf1dk%gs~nVo~Ac6_c-hZR!<>W(_&c`Mv7lZ&igWx*gYj zZF6pyW*e25T`*Z%cVp_CW4=aCz9MHC&N6&l=b7@PL5)$WTyuBe6ZShSDQp>hD`x9H zN|0!)Y}p8^9L_BE+pfd#LG$)+i@g)-&;S4M|JUSy{`PxgMU+JW1r-bKcu=vmbc8*mdahs(@=LH?Dkb z^tantSO3k~%j5OGzy39ESI?d|t?#Ja--G;zFJErBu=)OwHoS3_rHb3^Oq86;RSRb!_>WZEIq5+;qH)s#E%3A79m9NiDjK22$|8x6U@-lmVf93V9e((Q(&y2eT zKmYDMZ)g1F;7uPBFV4#M{{Pox#;@PM?VI0y?Sww2313@feUrF%tl@F0H=Folb^X`< zYSRuMoxO0^E?o{r^#S_59jhb6BPwN<6KhYn2(OmHYhYveeD?KR^GU z;j7ZLb*uirZ~0U2RDWClKP|E3%d^9k^)~u{zvZ9K3%8suDtIbS!d%+n*16vb(!FuN zZtvgByE)DO`@QG$?^iHwe9L|RU*9yZdQX@~ZQ{|J?t5wn(p=F^4Pr{zS8Y8)-QYA5J{D zy^g1)UgrO`^*gk+uHBm&*%|Zi_5O_|dn-2Q{oiM+Zxesc^yAxv8(iS(UfjC?RQ-QX z`tj)KBk{e<{c8Vh|2OYZQEPhIzQ6kaL$$;%fBxzH{@<6K@xR)PCq}dh%E_}c1ctue zwQJe>xVvAr+O1_5J@c3M*I`&eeXe*8g+w{X3Vv zr#rK+-~V@d{|VLLJqip?(-L!R+66vcoB#jkiJ#n41g^e5yZrJwp4f|*KAe~;|HokG zjx8_uo=$!&|Nm*dUW(DbUsjHjk~VKPzgKnI=nJ#{{wEGO%Foa9*L*2doPD=qdTylr zzq9xC`g*T!*&1qQR)1vrA@0SCCe`Gzui_j{c_l`V_Qp( zHC9~HN-0);e(o$UkI?B`75a)tG+u1FExTs-+>4X9#n(K)mvQpR4|nR?r-n^zwzbsYzmhb|GNJ-v(Vi4{NsN1 z*RL2HCM>6!Dkna}3ExButFi7{HSH*fqn`~SH8$NLYNYm#m^&#&nccx6@e z#Jm2(@7pykzl}Z}Y=8gv_x}l8`t`rFvdwH0fBfa=n(6a>vj3hx{r`7A|2O--{fASh zk8EPUSEoMR<4sA<%ZN9ZqV2_8KK^)azyISsCq41_m^FF1wa>!qD*sRRpZD`sxT|aA z%z0(cTE*winX|9J^W)E5^J*UXJ(rke_U)qk9t{>LX<3fUt1o_jzI=V%@9b5#`(^H_ ztg5e((^#9CZ~g6Oc-a5f)z327nHIP3{CzU_#19wO>gW|qmwt)!I)1)x#nK?r+}vur z?@q5zPFCOdb@jeow_iFGzw|{^9TU)z3KEUhw@#D9@ zzb{vi@Dqsp)&4*C@IBk|m+eW>*X|r}`1tzU<9he-{@;05ozET>KC)@yo>xM*n+)nc zWyjlocoMuw>Hbd@70p-T{~vsp+O_MExA*NGziPYBpI=>fKY9PZ>}l)ve}Dh)e6M=S zBEz^zyX5Ve88{ZMGwzT5dGNKv%6VsZGBwWSTmSn=XKnv{%_l|D?(q4d-@j!!GDY>f+T*J> zuG^ga>(fTcSjpCb;P?k#_q}Xy}Z`9l6X0F4VVnyU(j-WAHh=!;R_tkK~3%O?v+G z{%`aDx2G+C+tT*;H{YI5lU{w-@AuECI;8#ouzg&$@x~n?F&vA3?0FjVzpkR`;9-56 zet}Eo-US6V?^mx-Xwm8Gua90PId6`U$=csP4C~l8g-C~%l^l@e+9dWgY2%9{DJz!V z3=e)=(3E^WdHH*x2*vsA47Tg%{#}3HPjCGRx$@HN*Zb7x7bqCE7`&_fdDJ@B%<$8! z+*w`Mcbga(RKF}zoIB0t-KoC5Z^r$WGn+surEVFx4ZyQGcaOrA?c2}S_x3Rz=>PZU zeDKDI-0at1`R!$F%JaU;#GZa%He>tD?O9?>4ZD@L{MuTuy1XYha>K$WPnZMKZY70p zl4iJYWBXC9*;|XfZ*S78|If~F;qQ^hUFFAxWuE$E>mL5`;P!pZZ}pk4-oCXhPFucM zOWiE#_Vv0SRvX`*QS8?QSvUXa1x0+tus+`O``=X4zij-fsz8-n>NcjGrrA4#$ z+{w==m*c%{q`CBFM#-1I{7k*P3$IOkI`QI9?eMKBtKNIZYizdXJ8Z!7xdYt#m3S7n z=S%keU#I{7^jM`|b;rN1 z-#PoLc4Z*TH_eZ+H>Z6)S^rP};>(o|wXyfL{X!&k+4Z~p|DVzic6#LPef|D_1uOgi zf7busmHj+?`kmN{iiqcw2PFRFyQnZ}nc(U$nm zwbuRk`oI1Ew=CQoT(;BT_|BSr&upvfKG*+xzWTL7Ox*pv;}x@4tXeHlIU8wcgYYPg@^z^5~-}6P6xaICbO4yL`M_Qqp`j-*bGUqd&6hYkC!4 zo_2U|wV6=L&K)gF{yk`XRK*(@8oO}8LeZSdd+x6`1`VjNZEFJcsdu_>)z#hq^Zft# zX_-M@hR0;i&u*L8-%-r&p<)e27$8z2Kdg^{@GVtvCUhnw*<>jM~H|}hGBtEZe zg7Hz!da*#S_51!E`%o>PFt7g8_PWE-TW8Pzygo`o`uCUL>)%?IX8m7lr*<@M`B5q1 z-KTY4Ou2N^d-`>`Is5CJPp7Q1vMw{<_V2s>40*ZAH{$!Y-MZ|4I*s8#<6q5k^%F+= zo^E#YW8*mQ{Cb&~#oA)%U2g~K*QX}cpE2Y)Z1DZj?)pE+fBJ|q`0e?T^!y+*L&D5w z@&8}f2kTsoyngN3>J>NMN?gDB|4;Gb=jVlQ&)Zv=T$iw5;dXP`&Y1e&Zy)XbYFk}a z+w}c{)bAIMCvKKsY4`r|{*SN!?b>yh@AU)^IBZ!WodhW@#Fb>-9(Cw3M$)CZj2 zSG!wQO6JcaagL4Q`F=HjJc|-HKHr&MV`}=n@GAS_b*qbi{p$T}U$OW5$Kx?|{~z7> z@#w`21<&2P?O7QFj#bCkeY{luZ`XhK{4%?rEpI-zwYLR(d(S)N^)T_)`(p+?hi%S8 zK;lLGW=hthU!@EYGiU#PCI6@K)kmKA`aK4vkJ&_|7uP*Ky<0Y6<*dGMtF~?Xa6^Kj z=0E@c>8Gw;JMpEY@a67TU*-OvnjW#d&DS?}Pszvk``8(5{q2u(I(-TY4>5fZAAK_= zJ@?y{6?X3*iqG5s>D+Gd`!%a8TEveY*0+hjeQlfc<1Knl;Tk)>sp+3?n4m2XP;>6x zZKv5s>cehcxl;S;$c>-f;`b{ySGaurdG61n>#5UEe{|G-x_V`%U0u$%Lq{9s?{?`5 zy!d@d+``@JF{mMC&kpw0v%vNTacbZE>%MAVZf@R|x^&S+``^$1&v{&VdsA1r>Gv;N zzJJaA-t;BSKy~B6=B(U9oQF>T|M36Y-TIIJef3&%>rZQ?Surqt{&V{O3;9!d-(&Yp z&$*Vs%D9MMXIHhmc{eY!62Hcljs5nTb%Af@Z+f*c|F75Qh0W#vZ> z`B(q%x%}y8iUgf<+4-+++4}VI%O|J0)Fnb{?aFUTvM`lAel5o+uxs!3=Jo5o-O&I0 z=7E@@2&%ec8#|CaY&v?F#mO=w$VF9mh{;sclo;lRdpagHtl# z)~d}b7CvT&gPX2Ir&^r8c<1ux@BcsW*ME@zclgf@36a}tm^dcYUnzff=JfuLum60r zFErKZ4$@ku-?H#S)6z^a#hS|5ADn%A+2gAO8EmA@PAIh4EWB|2-%b17|GwRR*y(9I zU0Bre%7qR8e?D*i8lAKIM6{S&hx_ZK09M7+7cD_C-!ApvyS&`!ql<6$>DY6Dd+!}S zZ`&^LLwohMJqk-rvZD^Q9sF4Tq2}7Q?V_`_1zyyBDs1u6zgqJlA!Boq*1S`?+Y|!5 z9xq#%bK{3{@|=yHyi1?z&wN;6SI~Y|cGdOOReMEwc~j$7bp*`X-r41yEXk8cQ?ZHMVUetA8EdJw2jfgf$>1>zg7m7(5YtGc1?!gSeoZ06j+OE*B@gu zYuHkk!{WdY!hYi#m%!22t!Ld>6W?&L#oq4sWnW+pD$)|=VxdC`!K{MHTV{Cu6kYn~ zrvXEVx#_=e`+xk`Ie)G%c5m2;=c}cqclFEc-2QGu%cY+oT#8R(|G!m?oaeFp*yWY? z95&4PSx_1s{WZ2+V+Yf};Qc?iZ`b$c8qOCsnD(=@_?(t&r`VRAIonRY)hk|C_ojIM z?N2gSA6Gt`zArE>M@`Xl@q>F4X0DpN%eHq%OVYtYL}4D!belf*Sb%QE*1EiE}_R@z|u zr+$}+BEJWVM}QE^p0(yLn|pI71~EN|zTbSFnS*&Q`z!VXyQjn}I6QAqVmQCf#s*Z` zUPyorHJvZK8yb38Tl?_o(`y$_*mU-&_*GxutG>S9g&Xo_1%IqKcfneFb<0=zAE#xm zKm6La{Ic^&m-g%GR&nemxe~%JLk@2H-BjvQc?)u;;s4s%b3K9icvuCem< z=bbvND}uf4t-pVEY7l?MJ&X5(#>qLGgOj{6Zx}q|s$_iliudGn27MRbQ(^NpALC+c`T&oTCSqjhHG>vmS<70foi zCq-0E>lw?J+#SC{Fpq)TSwla7y z_31N*1jDJj_U+L4xMy;4>Ffzjshl#`U-17hkNz9Dco&x$=kw3=*Xpd6>6e|ef5wzo z+jI+Krk{T=y0lmQ%I+Am3p3(6#7t)1KDMvE?RR=$l7LciO#AiqIT2iqg0G5p9{c?B zXVbP2jT16u>!LWA<_dHN=^roO9rLK|x=??>@-=?1TV0*w&3M&~Wke3B9AW!VRI^wk z_snk%j_;oy&B*PGSjMpIMUI@~Vi5+X8QBlbJdLzCt}^ol8~JuR96T8!&w7E;qCvsQ z@y3((`eyzB?hBO-*$$}-{EnqDi!iV>q%rJo?mrExIp%=N*fvIn6-B$9^}>~=`-_@% z3mlgVfA%wKz5a_J%NDb_uaa7#Z0EU6&tAGBvd-;E!WQf9JzaPIuiLcQN7Ra9&N^R6D!zOp zg>S3ItH1GC>Pf*C>+XHDbx&nsTujN zgcKVu9<6E5pI5@Y-u}o&+b#QT1ckQUe0s%@>HmlNV`@TQF4Xh7v(}~WmwJybypbh;sc^GzPKw;68zSb;>Nu!uVleJoAt$hJA!d`t`+%8mzQ_Pbg}IIUPIe7h*` zh5%E~M1|zO+euM=99w<7I+IiN7z7SU{4f%8y&<-h=T(BPltY67e-lge-Wv@<8*~dk z)CSb}F@BELDPAa&Bb;;j?V3#V5TpQPq3$ruE~V zw;7L~hGj5ZJ-f-g;`p?~QP=#|SVZ;|`Q~sqnJ!w9Gf#Sv$fdwZ9Kz2p>17u%t;#&y zwB@I;m*x}U`UR=wiUteVJ9(k@f|JK|aBKj>-jFxv-&IC<~ynuusbIXLA zA6G1lKB(2dh|4eU*K!uFSra=_(vO8n-PW$ySF+qeG5>6jipJ8by?LGw=l+>9P2j}R zFBLAAxx=d(_4c4atjl_S8@8cvgCM)vD5|HmOrCr5x$e zd)d^XwaO)~pyZi*&a5t}hc}z1ZCx$p{aJsClU3T2OD@BCDroUZ{u&kBOXJH#XOBs^sK^rH*U3~%$uZ@E(^?UJr%Ysyfsnc z*~DYe>EgW!S&@r3U5idDYYv)qPDOL6M6ulWU6%EF^G(lM=c#=B-BiBIyVP@P>Aj~v zr%W@yVw#u|T&0-5^^47eH*J}(8YUc=9{Tyx>*>v*X-bP`vI#D|y|Ue>K4`nor5n%m zjdwe0+SdQf(V7|%`hDi)^SL$;m&@-fO#Uz_b!O<)t?l3Dzjj zJe!myFLE}{QmYiVE?~)C>T<^C=$T0@?smz_EcXuN{bPN!{=xM0-k4*bykEyL{}d4v zeZu?p)`CR7P}5>=JJUG+CERx*KYE9y?pZJgmrrTjtv&f45ABPO=59368-=B{r{VP z9+iAd)0!(WUq))a%&$Ms>l&ZGpLWxcW9OYDo2aOIOV#O{Lixk}a;)1QPq0@>5ehq5 zxYt3%y#4g;3(lHnQ-U`h>C#!b(BbJV@!L^RiutqJbhH-*giY#uym8GVr+r&&I#)Jt z-*ji+nkkoj^d_D<5_xouZ3i$ z@iE-?(2m$P)63n|_I)9%O`iR}!);<~Cv5HP6)4l3SEQ%Cl7T~KE+lRslcAqiD7P>j zn6_3!_q5b(i9hGQ{|mYPKB6OJVn}G=RGBNiO}V!-R@cvBJj&2@@J`>^WfJ+eKNn3= zyL@qf<=^}IYtM-FdrS%{^3$9DZ}a;6fG`HAp(PnV{>ZS1Lt2N)ZoYsmvazwAUSKz^^->(m=efur{KO-k;K}E2@ z5&bOFj?kR`4cmBCiviQTl^!xR`OY)X| zzO(B6%;Wpkt&2RoKy=glx&?A?#&)YonN8)dr<>*lvv4?i7SDWiwkT=w zlx4*q%k6$?-`!#PMVGg_@4M~(j|)GyzIk2${@={h*?L#MAAMf8dQH6<6U&2?$I{?s zDo4QOj!)#edluif+y6NI=umHpR@&{^UwD6h&Hu+3X@7V_&gcIBPx^~~`Z&jaK6lj2 z&iKQv==y1wjcoKe<}7&mv-f$-zK@Ao((W9!4_o8k=iKCHIQ%#~uKv5d)g-v>m!QtZ3Jh|kz{OmKL6jNmC63h4$;Np$6g$Ju(Uhe z&aUi7;le#RhxU3dQCh$MxA@7DFV{3`FWkKJeW!YTrs?WMnLDrF`?=X8XQRbQIjP+j zZteJfbosuMQ^Pf$)YX){Q%@FdHVx%%|Lu2H*YB>xp86lhZr6W3yZ&$U)l{jrmGvJ^ zMo+$c*w2h#&#L~ddgm3d;M(%+!}Ct=Y}|QtY zWp#hJ7ZeLeSGi9H6k=I7@AJ{jDV-kge_w%6LXOae52m$_!4*kJ>n;Au_k3T5mnzpT9fe{Fry@>imH z+poX=y8dr|!jG(vlb=jJKJVVn8<%EQ?3<9g=Jk)S>;FIQ3V6Hh`I;kQjP(bebIRSR zzO}R}X4P|#`@(kq0t`YcU-a?C#`=CX-~Y|}yzNic>AO6qHbp1}&6$7w`n@xZANLd# z+~;KQSoV0e{O0#8vv0hw`C`7(r{@2>;QN0b*;hTC86PZq{>GQDD}OG$T6`|PUR@}9 z1<%#mzf&E7*p{1;` z(Ol=(&MW@;Yk9EoVqM?Zy|(RTR`a%J)=3laI=$$b8L*w#6Ae>R;L)_SosMJ>!m zabj0S)w;DSzaN-qTpGIe=$>PDF5T#}o9()@Moo&F{jcb8e%p&zF8tfMeE+K;+mj_V zr5BH!xl=E(@X47@alW_qS8rVj^{MeW#}j?6PhDiw&J?xjIqTlP%e21~a{cR#iRVAh z5$M#PGH092%-GIzrdLbfme_y?P30k@j+)))rGL2Z|85`3vU=Os%%3~G(-{{ih1|Vf zo$@^CFo%8Rr>p9IHUIQ>TS{f${_TD)z4&F*yy>d-q70XArdZ8pXqa`XO;&bS{J&rK z_n+Rosb+JUgWddC+Z|hM_!*|9rft%U)XI)OY-`|aJK6i!-i6EkY6Kaa8edJlv61_F zos~h=!nK9@ALn$=WaKM8Z~yP>g#By`eQ)Yt?e*XH`?CMO>zC_hXct=_w{?`L|F|?> zki}8Jg~5SiXK4L-cX#GQNg?)3Hbn~Epqv{=5Ic{zT%%T5a>4n@x(Md8I? zo_$i?zx~n8<8=oge-h94YT{womb-Xve%I;ZL)z#6FH+jwy|=>PSd+r5UE8d3et(m> zyZ!l#S3gBG6kP<4$kv*5r+C)>J7a!l)&3uLPc8V8*FE7hJ#*+L_xk!mnfe{ySKd5& zaV}qHqD0$I%frxO=iB?cWo?i4^55?{Hmx%5$5H+NX){B4-k)vUyL|ha2NfH>Z)|&o1-FC#S~Pz5U!`v(Dk;iFw}+ z%g?L7yQwFlXs1@l{^G-jifeqYzJ1-U%pJUW@v29wR_>eIYgPDzGbAmxi`_bJPlV)} z=)IP^Eu=biS9BeJ&L`S`Vv^SSm8F(OrK}85Qr{lT?GKyu9R~8AO5FX-#j_9LgnOn`;SXyYuoQhiA~?L%;x2bC!&XSLRhcw?P7B~AL!*L zqqAO(1Jr$4a~vF0XZk!;7Tf=O`JG|G#(hh-?J9JaUp?oaNRxtH*_WdwW`?%rMiyno z?XJ$bw;vym4=mrfUzOoJ_xgQ5df(T4ulE-^c_Y5|y?+-w^S^+F3o={xM8xUeu0EW& zZr7u-eF_u1dVJ!ZRVLP-U-@WaM$$@)lGUXS7Jc8Vnm)QjXg`sWUbJVL_3x9>3?FWE zKEJ*${pQp+Zk-`&RWFZK%RDW+gT9>{&ueVp- z^Hj2W{k-QpN=<{gc9p&R#C~KOr|MqYc3Zjqhd1{6#!JuI@giuit?c&clb?Kgx$$K- zV|-|A>FZ-fdq7L!HZQ&V|8xT=$?PoocC61TSLJ=r_a>Zq z``&Wj{^u;`IX`<(uKzXHe$EWZ8+UJ5-TwCP-1dLFm$lWKwQTS%wJ&>g^ZuWw^${_< z-hXDF+v#Y|wSNEa>AM17ytWkm6fVyHY%34LimvKht%GYT7!GXdsjixntNr3ucK+Y# z6-q&CBp;q>o~Ak3d(Y>O_g}P?6}*4kxHUI6zw?N=-M$ZOZa+>wjxSnir=Hw>Y})<5 zAKF_csQd4IQaIgii+BCknzvW)|G6bzw|V{d9|t}>eZTjk_^!YLoo!2}zC8W+z4xL| zUrw&q+MT5 zO|u@K$c$tVkeS)^%I#sZ|2?0jkE(a`%UOTf!Q3CQuW8=@H>Yk-Oa1n?a?RqU>z~AV zW!mig^YW>==7h=Zai1#ZR>*~?ZdzIY-L7tK(61va#id_GU2{vFVWsLaX-d+`+sW+m z{ceZ5PjBA%!zv z_&pylpL@p4$FBeyCp7L_`yc_drqjUdWq;kL@>$cE8;sTG-+o)b!0_ng(;PcihTg69 zvPa*rF@&&WSKZ=gbWjrQR1YuHHaorP-`n~B9{&IK{@>4={`d9P-8zxI^Z&2y{}~yy zoK5*^rsUqf#((eU=a)YpuIf4_KJUlTt7>Z)1ipkaHe|k-zj+W#{i?WSExfcjnHCOigum&}9A3n@7XI zOG)@6wB}0G&y`?k*fwq6vbMYN`xqHkvvMb&e0sIHWkTzRl#khkwVZD1oJ|F$N@CInCnWZ}%<9@~P{)%k9tO=SR!ruX$bZurq&(3Bx*$E33NH zmoE*zS>d{XjlpgCx>?Km48^~MzRw70xdAfj%9#$8lZ_5X>#zPh-*sGDJ4-q%x~$6Q z-MMXR{q^_HJgIg^Z@)zn8qXSpRw+B z;mUcky=S+aDYvUQYw)EjVQcE_>+O0B3`|$9Uei9U<+Nkz%4|cM-;2xtWyPNt+pB=*-yFZVPHO=CmmiJ<@@Lz@nuUoyt?c;3s<)5E;R!F8V zPyZ6v&ZSc`8BRQ#biFr&G+$+*}qjggL9r1th~2=&yU@+kCbUQ z>{@lr*I%RjuwZL-+z#On;eSqDudjdn@#=J8rxzz0joGXGQ;JsRn1x0Ls&grApSw_7 za%r@^!?yZ=$5sVAz8-f=;`XyCWV@R#rqi;?#}(aU9>GRVoH<7y4?$wd^qWGa2v<*>DCXe zOMm>_JJv?{^Gq ziMh3)MJeXplCI~iSI-)$3OIEwDl7j|R-Ti5m2GLr>Dkik?q!8h=hRvr?LMaV;Zdja z`TRHSN*{#wO?3}QxvszG7yIGI(~~<5oK`H`v~u&-^>cn2EH#;I;WfZa_DTt!w(#Pq`d^@7^yytuQP;w3cYkyDFiX8D_Cw37SYVTMs_>Ny4!1sX zt(v`f$}us`jR(Vb>Y1Hk)OS$i-X#6bw7BU0M!^$D7#NOx<>U)wJmXlEYM!iYw&YO5 z&e-Zlpbla?%j-pl40t}Tcx-X!Mp)*nYj<3hESPzYJwfEm&XX$^&i<;aSl<_K?kwc8 zZrjn>=VxqQ?0NadM?HS&)ZkxN9PVuLNM6og{Mv}M=|m-Sklxz$I?r;t@4QyN6Q1L} zInzO4g~s0(F@=SC`tu_U!=G_&ds~t-<IgV;+)-S>0vZT> z?#!IzXvLMr7{jQsa`oYl0aw|k@o7)qEj)YW;Zq_JRw3KoM76boM#w!jh=R7%@SNxh zxGd45w>2}1FIy(fK-&B6g?X~S?pWajV^=_=4w|_2ET3tV} z(RW3vfagQ$+qIMSoXq#BZ)IY5xx~(T;uBWByY(9u}ZD;vA4Wba!8>5vPEHLna?ko9k-O4og3)o__g4k z!v4a1LHz}@`1I`jlekrO`pC@H4c_3xz;e&4{>}P(PeRXqe6X^mhUt>v0U3**YOGw_ zSS6ZI^IuB)>%$`1#5*CX?P=iy7Wd@EEIGmzf=pi(a<;mIrgwhsgrsX8hKB3wD{6|& zVo#)(UM|a9%W^*Ps%mx3r@3W83N22i>l~)e>Js15^YTd*OWc8Z4R1bily~tai>wLy zTd$}(`{LIOZInD1^s62i8;qr5eC6vgr#ThO7fvix++in@TB1*s0_n{qA1rH|J)KVdq0`cyY)6$}G-vg+^}CyvUR zuH)Yg>Ug>gxk5CgzbD!77_{%Hll-$=_IR3w9P6s`ZS!B-K4yKxYqumi)s>Z9{@8UX z1(qhB+nW1cX5_3AzmmJvFA0j?k?X$zQ#lWxodj$ zLPq+Y9=ra(e#7F|5Ua5>P)>CB>HN!&H#EfDcq{O(>2K$01D?+sN%nsw+Y;qswdC%; z6?o?n7_?jV(A?z5t3bPL5_7!Xoyl|GXz3T^da(Te^_!ec+D8Q+|69LVIAtTBWq3te z^{Zy@-Li*d&mIylw`KuNiHUCjt%T<(7Or1vp5KimUl!GEOP6+JTHIXE@|kJ< z4}<+jlZ3LOw@q9;?PUTdUyDWK(lAiN+A9vGaz0Gj> zqB)aOJx7IL%i3Ft!CY>9I=nJ}7?~uP*EhXLas>^tOMqwEC6=8q;re(~Q+KiphqYDc zf+;~tyK5Hy3X8k5B--b~y)!Bv9ULR@;Oh{nWP(S5u4@-}Z`pAxiq!bu%p zq0vv*#4t)MmxYESyr`bl97LgOOqBDpx*}oL#>ff|Ak} zRV6VpSla3@Wnp*{VEmpd$0~ODwp7)$w^x`HSRTCD5h!gDx8l{YQ*)DyJ*zmmJll`= ziXHErzHz_c$4}4rbHxnv;HYU&ZkwUrA=GjmUa7kp;M--Pw?p@%hoBkF#A?lc$Qim3_RhoS$p%e zb)h9P$E59|^p_;hoT{ngaqpI&-;_Dt`3wxIQC6!|!+m18uar-JBB-&n^~D^q*$-W& z2VL!|ym+v1@st~_H}-5Z%6)qIUE5w&eRZ!)MXTheljqbw65V?>T5nm!frB@fO^nex zlI9vL{I_&zB}E;mcM1S7*YuTRUV<6*s|Vx4`TdY!`X8n>QG7nAUEP)~^5$ zYags*2Q4jl)#G&ULQ!M=tYx4bFrHo7A-9t1b6YmA^Y$*WthcwPzBzXG#+|xy z*XD`7x7zl7tFYVYlvBNZleBsAXBO6@i_?WwkAJl?4K#U7ldif3M*d^+iI zni^Y!YyI0iRyKyB6@m;sU%XBhT8lex>i!(^J}iObbJE#3g=tfxVyfo|)ptutE@3HG z-yPV~D;~H)R%forHE{;BO$jLn?{5K5fAJm+Gbl<(Dc5BKJO2Q<^Jeo(Czzcfuxx5^ zk)!#sWzU6I_S}D*wPG#T4;$6)KaWptNt~g2UzMXqV}mO@uVWaaV(@j5{`#*A7N%}c zD5}|c`dsepHAjNC`L3$hu3_4rnaU;Qofdp^&-uk|HF+WT`f44&203-)GHI-4KU>o^ z{YvbaJO&0Qk0SP>i#sPhPP03=n(@fgt%sX}W}VCA*7lrtxO6Jx_Nb^GQvzoBJXboo zCVJwkrnpA^*PA$!PlhjE?ky~{ZKANvK_g@RDVI{Lr2EuDU03n3rmWmjP`@(F;Mw%W z%Tn3*zI(-0Kht01kj(mu+`T16KEA#DCQ~Z~89J61Z%n!NI;hF+`msbq-E6ZtC&YUe zoDYqEssDLahwz3ssyiiEW?#2qHxp=DvgzKEqlMinmrj=GJt$?Zk(+nBX3ON4b9_6l zubuXLPLa)17lW-||NHSWIOv#vPP&;=uR8JMv#%4*i+)&9;Vc~EYc8(jd3Q^;^SuUl z&F?P-LKs+{d<1g`1e)&~)Wny){Dd$)?Fva&I7Fvi|jS^8t2hH|p2W^9K_{fCDQ%VuwHJNp08 zN!z&VZ@KpUo$PJ@FQ?+`vyHaB%YR4xED9<;`s&1$ozFlmjx)~n9pE})#-=q#gzA5V z=f7xMsTGu;{`!nlh3d4L=a0R&<=R(%y6`HqwTY2|>G;~YzMO~p#ItS6YyZ6UUso*i z?rp|~Tq~o!KhCB9U6yKJofQ9(pIi3tT^KYqf8FDX-no*fd;>)BiR?a}sqf7YmQFibd^nO|R1 zaM9q*Aft_TgZAtLm51`tu`wzv=26uPgZ$2?eCq9>$vv+{`BF_ ziivnT7%zZY$zIO)W`;yM?R9n<~ai(0&^mXFzOVDh~5B>Qfuckd^H$6{E)g9`?! zGv~x!;k~@{ME!g5c+OvYcP0K?zP~!V&eFYjaEXTiIoH?~(m)48lbJyD{bL~mJoj+%9Rc65_ zcKf|QZpYV8yM5AamHeFj)6PEU|6Vr7WwQFi%$ks&XIX#GexHHG&XSUR?~ikq zdR%%PG|%ReZnsnF0ptBL`^~J(4YzOFUYqXSBGqPTDIS*ka;bXX2O04%yTqqI=GNYL z^l3%5vnfN*d7W2nJNK`C>XGkWD6zQn%9}^0YAkl`I+fhMq&P}v=GwI%?25NYCx?iB zQMvT<<4+Hpx!P(L&!!2p*56&lS$SS2zS+po159*EDg{S$wGpUFl6>kE~3gs?eXPcsCl^Z@OryS4u%hYY32+H^G^M+ zd3T)eJ6nw$gT`SF?SWbhrN6 z1>yB?GuFt=jOV+&ri z@z#I#`0ARk%Mzo^7QUKwJt*Ei*55mH>i@KjK_8!;(%-e#JrOkIoeHk04o`XdWZ}KZ z?N#CVVkM7%U9ezSvsNzZ0`G0L2q)*qm(APMKi9Ly3bi^{TldSoIB5NoaZU8p{}h@A~>~T{yR|_i;h$hi~55g{o$|MG9AY<%VvkShCK@ z!fdZZ=knXq*^CF&QdFn0G(>0>>-U%Y|56tVj?Ar7mGn*X|Gu>~Z|}58k-Ul%uD^N2 zSrN+Mk@D#rOPX*|ZHm>@ljmC(pY(axdb$1DwRGF!l=FIe9VhCuejPXxq!m7cS6%0} z-ObyZs=_Z+?~a_57j@shT9)CL)s0WQZHW@gVjuyUBfa#?+s)5|XUd!}ROfpaX*=&! z3ZugMm-cqmj#E|d8a$r1RmfX`#r=0xS;@3b-yS{8_;k1UFGInrg!GRcVFnBg$zPhk z>z~(i-J7Sn{$=;XBlSflKTprMf2_M+=cz4sMZUTq*RH~i^*zr&bTZGLlDvVl^7R|m z!zS|fyY9a)-J+Ob7GLrBaQ3V`yV5Q06Z7gs7_T2l+idrx!ga)GXfabvui7ZqTbUQ+Djos6V{rO@lk{ znwfK+o5(Ug`gxl>v1@PUrk_p5%5EHc4XtLMd!~CkZv|iFo!4;>chA;8A>QMy{JAaj zcFPx&@Rgs`j>hCTor|04k;YXWwaQvryWB7e)J#q1h7`)Toi%G8@AcQ`?@?^o_vw*v z>DBGqnU@$ z8Mp1)(!FoZx7W>>#>>!hVQR#y|No@d?+Ue?eEHuG>wJCJ$@L#^vDbg_o?o1HDt*?q z{r|s7zsy;;dg;EEWs@_bwdT&95&Nn7uK#?S2M#vbd;dNBder07hk4JE_ihjGn=!5a zZ~6PUEjpiC)%i z99ZiivLf^Dy}eVz_f%w+F53NTz zpIl;g{qC(FPsPvW==^ci{Co2Fbl=lfd$u2LtO%1__Vw=kxLMrCziqo}TbXjV=F_PU zJ$Vsx&t8o^dzC|RyVCxGEO~~SiqxJUbuHx#*1v1{^)p%jzS!5tY+Jvyx@^|#Rr|g! zP2d0FOy_y~+CS3z_IWeJ7+RRDcqjxo|qWIFJU*p6=-17sjq~e@W(HL}I?`x- z{Fm3P{u^e2BA%g3uAXVSy;S6P=d5L0FF$;_?Cag~bM1>yZfje$-mbhRm+j!|pf1MN zKijqAuY|K2I!y^G_MLl0HYw^F|NXx?1xeeqUQ|DQ`FQrX2-(?j5;JFor`Eqbv2Wen zzVxZNllk@g{m!f{*?whT$+GoJl-A@$9Q`kTS#rvyraY#G#2I`?(r$j+JwGnKQsTd3u^y_^Z{k@dCv+nN818U-n>VF>F*}u+jLUi%h zq_A{oszu)bCp5G%>WXv2|b4rda zeZAkGll*qlv*Psj&EZfywpQihs_e(z^6|4jRZj^&|K*hR{jM3H*>}ss+g5-!L_OVQ zX!LV(zaGZbS-vel@xtDE*}?=`tyDLXYRb|ObnAZd+$nQYPi06bFlT{E&m>W zw~wfg=)4}zzW?K+my>v!l)C4hHC=4{@WiZnQ?9$Eb1b!aHf8R7_q~4~E|p#!TpGGC zzxLo@ta*b)9mlT%RXadL}Ca-{bOgykh;;v8PV{&1EP^@&A1E z;LDdsU-a9*eV?($Z%OfU_GJtYt~B<|y~ma${OMQq^Xc_UoSq^)r>&|B7gX$7Xm#aY z2scCA_FW>K=UbI;&IuF!^0oi$6Yi?w*wD}u`!7Gfb}is!td!)OC>@Ek=-Ld!Nm4T- z*&5nb&E~%wAuPgLr#Y+c`ymhi;CUnd;3k;8013# zt*KvDaY42Fc=hbczFM{820VvzdZGQ69^doz@7Hb?ad@zE>C_w9_CHrt#5~v;KEHa+ zkFSk;W#8A9nNB`k|GfQu*>>|+ZKb6JJPcaR|E?XI`#0uq@8kA4680Wls9Uz+No?QL^&Q@>cWQGet z@wK%TMPGj$w0-+$t>};7&kuJNs5~g$ZhG}?hC%ktmNw;+kFGaQ=3ae#wRX)>miAR1 z@s;0B{1$I#R~P$zT%6&+QjdCnnU{9k%8y&`kyy4>#FL>RZ-%pQ@#^E2J>8sq+qLXV zYyK|}Z`bGTVPBfLe|`1%yE?z(+!xp5YR_zXJGJ82 z>-tG|Z$~yeZvQV+>*+Ul3peJGRJ5x_piHl+gJbL zVOq+PtI^EF!Fbcki~&?pJ>03hEY)@L&Ib3`+bvr)9)#}yc<5q*&eXH7MH&0=@15&s zJB2|@(wwDX!Jb{}Yk9A(<-N*!*Jp{bDC7DA_dnM6@71@jFOm+t+rw*?Q*dl``5jrO z72DTt+rHK;-XQ3vQ|N)SYyG45R1}@>R{x$;IoI0FP4jlmS@@>w8Sb*`9SjMtW-Yms zEAHuE9bDkc*d3~R)TsK_?7Gk5aeVHNx=#nrp785c*S2N5bT>;gBuKI@m?D1t?0nXn zQ@iVRg-##2BevUP-_J`gebplr|DR1;&9N|;-75OE_HuFM(;KH~dFy_idUmU50Gsn^ zr885HC}`Ys(sJtP{U}x{5MT2sBXRR0(M1KHn_4dD+to`cUfFo|sq~Z}<@twdUOxEH zb^cP&lpM46{pvQyuZI5GE-7tzNzhNLHn4C}((_4I;_JIFFn91OihQYTvOB+RUw2TF zxRG?S^B$iq7GJMTo2emKv2WX<^6A1^PIfoa-YaR0M; zZk>9tTH?}fMKb~BmaqR+;+Pl=J}XSSeIsJ3>(|EjhmA}bs*EK-t+K$Q(1G8;vX4zO zV&+YbjjNB_@pz5$i|=fIqrWeA;0O(8S*_i)x;Nxh;!HOso70?&p2U3@m}K5^XmaPx zg#p?3k7fRevd#Va)F!~Ub^o$M``3Ql*yChpb>5pxecfzp&3~($vQ+n)yj-2TzglkL z(uL37@hf^K`A0wAwrH1Rv|{>`piRq5c z=@++^M}5}LX%~Vfp19$f6n${ozDak*_9(1uj8dNNq0@6?TH*Tsg7=?JK0WeBK;g|Q z4d1>GUEyCsM1;6+{$xzDzU$H)G%0@G8Qor`IHB6BOE>QP6EWe-j~Ye0@MraM^Vub( zH*P&KWn$d3RDJd7er-P!gcI(?yxBg9`+LdH-%dJ*Bcv2=ay(z_`sdeL2M*mE~EpBTsR{F+xlmav!3#izyLX36WmY`1he z5qi7Tb*aE?@4nhL%Y!GICQX?!<;J4@ZfmpdM>I1lt_drDeUjB!*mQH@lQ%t6gt+T9 z1ovKDw7%-GoMa2@#(xc>v$rHo4of=r^5&*ghGR7wT0iG*3g#@d;oCOpi;(9z$1K5Z zwWBv|4U8-1l233`+FR1tDD# z28OQV`nzjeV^&Q#EpWT&O`+j&&sFaAg}>j0Ok`AC@+(^;KU7iJ__JhC9PbJCrpK%o zg#|?4&n>G|=!yL&bu@Zq`s8Wz*pFXRR&a=zaHq~O=zRs(vn!{>RBtR;u6*P~a8Ow7 zDRx2WLrp4`+8YXv7cJ>{{3KxVi}f3eJhLRX^!%E_pLZkW-qZcwVXWMnA~sK#u(XzD zPpY>Nm11yn@aRG_1JhOMr*ztWB^={T6iAt{w_JPnA{K{lj*6^RQXR$i z4h)|asvJIA&zc6B%8?6$v{~=82n5}!JNowiTL-gl-sGduwU|? zwfx%V=+va`De0$Iz1gk(YTNbxjzrL+Ug(U|x{0pGuiej|ooTn{u0YJX_AlG(m**xQ z{&4qyX<3s-QP(ExxAxnXWG>3JU*f4f-~ZSTMc;xYLHzk*56%7Gm$85*@$xD>{<|cD zX0hBgebtO-`dr&I=k~qxpXVHZ{ORYO^7%(^nt7@i-CXl5B8Nk9-t#|o+pn*__gA^( z_BP?p9J}}pbE8-r1cX@Z1PWHKs`+kQuiNdiSkl+HBiPhJz-iKvcBi~Zv3GUL5+goV z_+8g6Si{Edv`MGMNw4p=(%gyXXK$R5Hfvk+#>DB~9IYaKyQ6hEy)y0cmj&&boFCM) z@w95r%&dh|mIb+4<=)y>JTth@S+4)V=T81yDNr~R3c-@%%aXE`6s?&)pX+VfHx@tr z#j$W&>d%^a@7{&2zrNRSs)J_lQ6pz(#|Q{Q;+ms|9i+ny-VR>%hNcfzb|OTC#HzI=GN*KYo0R~e(3 zZ|b*ZAD*tqJIAWj<7U7zMX}Q{`)riD4!ykmJLKw1CBBCRH3bE~4z)f!F8^M*<+qa>8>h%_H7A{fsHyZ#Pe!s@Jam zskO<}L_|_1=H<(kT&-S{YnOTI#rFkrwez#r+AY7&F|()gZPcSrPj9RYp1SGGzfGwU zZIw$l#xsNVHCo-S-*$ff{&S!2JUqNt@4DWUZ#*nD$NS}X)a?9!X=&qR_1_i$zP(qw zyye$#_0UkevNh3@$`&>`J3B8u|9n?P;ge5KFD4(~b^Y8`-otZdM)I-P{QkZ@Zqx-HDi^sUo<$-cwv{ARtqt%o0m`1YQEAAh|srN}5yBZ8g(T1e@UcrT+yVnHc+~oZ+y+nZ6-M49y0ng_HjeVeL+e(|P;NViLxtC39-+tV=lS8p& z`zC4EgA3FJJ{)=ca?)dCW5bpU^K46Z??~FeP*KD4&!ePGPkwwV@)Fq5)^;~X?bfyW zu%m?)g@%DeHbN(V|Mg0Jy3RE5sl}f9deNl@#*<^J@0h&xaa+Ht=sjqHS7fJc^(vpq zE{lI|J$^aUc>ea=w{3Sv)P#rrT&I_Bm%se-v%I4RK$FWn(Ea*z*GV%xD4TA*^7Qk~ z6Fn@ZpRU;3cCt@W|hVHFn!`g%59t&9=MluVR$9JqWZf zG)tn@Maio}lp{pz)Gj&0WtkaKWrrIow#itv1ZX_DJL5se(V~M3R{yyx-|A#Hw=dyL zedS)!MG?PRg1j!j%uo}4UU~5S`bkeWN!>~4$;$rw`SViGmXciov2S(vpYzt6?xm(Y zY00k|(WZjxs(cC7*z@@|@snZ}?Km2y)_1sWzxGU>zh%D0uV3$dn%-(Ov%*X|P-Omb z;YT|zsh{4q)<FAVKHvL1DbM-fw;3=2(vQ0d3=)nU^ua&2t+Lpcf zS=83?yjyTh_t{Nvd{PiW!?eC$uwS2_Cr0Dvx@LBH zZno8@J9?w{zPWYdRLqL}$YWnh>UGTaS1nn#Z12j<_pcU6yCoKViqhH|v&Yi7IV;;* zN_zL{mEW|w{v11J)H0#>s*hQ!MC-zZ+$%$tR0u2HxpgZ#{(fLjZe?X!R#w8}^3oES z6|1xFe|pr^kh^<}Ag5x8K>aDH?J;_WX5TUwPT2cZr{nC|b}g-0T^j?v!orrNrLVvJ z?JO(nq$gR~*3UjqHI034krKJ|yynu>y`GE;a`7@!zpj|%>sd@nEf2rG(cwYbK|!ZC zCr@U7{(Sgo_44HlSFPH){CSG!w1<8MZmPaP96Kxb%*of^q?26mAvg9s(}9D{_3;5B z|6j#+cQ+dwPw#ra_2su!^Tc;#FN?JH!?aG&H*54QIJ$Lp@%*+`U z&%cIwP2ytsSyPntN{Hdr8yiuMD`(Hd#K*}=OaFfI;-bE#!0i_=TrXd_eTy$Fe7lZb z-}y6N`g>z7s=h3JBsDpyj9Kx{_3v9WPBAkp#qRo4&%n^Y;OXKRBENRc8IMV;_x@eL zyiv5bw|2?vNCut_dWs8Q@0>Z)TjKG&dFd>UdkY`;K7A?}`t|yilKZcnLHn`$#lo6F zXIN;4o6Vl2vUKa#+fP3+EO_;*Dl+Wz&)e17NgGqQ->!aefHN}8@YwI~@=q%l23!aW z4}CMI#OmB$$^Zx#xA0)ES_v3+)VR!TD)1O~_^=ev--qy<-CEXOKdso^VtiN|Jc+!%PP}3{d z%NZQBM78HVDEpn29UcDva|Kh|!fKnwQ>T8-?eo2C)Hd<^&#YOq`MH{6qHjxbnKCvk zyL(4_%4t=`1^f1?i)0;{k)3I&;i-4p$Y|ybzvI(R9?7}AW>r>R&K+gXtnBRh*P|0> zwPi{%ICRYQ(MvufZ~H4qA>eI&(N8|PnlOPUJ9jGjo_|Nh={#tWxT?O?Wd01sF5=dgl~S`XISZ(s82it*9)noDO*+pKf> z?YA}aE?m5L`{KpjRZdz{H|PXUYffEPw_m=uH@3GocD1>wEWsMb5lV|VWDT^^n< zHCL{GuaW-#Ol^?J`HPF=WAY?S>WdB}k0@E;j) zbs&*eUu~jmZ)Ub2b7zfRyFf|l+uH?Bc_mxy=bwM}*>d~s-TC(uk5^Tu7PZ#DXR~MLug}?@Tb=Vp>pV9*zg^z#X`dg9^{;nP>YnLiG~2hzrg7JEp{{2GsPaLinU(~1xpH370S)(Shioc#M|DENjG*ESO{eJy636*0p zuCC7B-t&{szkKv4#ca0E(nYhT<>uXc{59`VjM>~ief{%Yi-H0JpZkQka&sS^HO*_e za@)eKTV+G1%;q%Rzkl1t!vBB%9N3y|FXrlc*@)xexpTss-UQT(IlY-Vv$4i*uFtxN zX&dYR3m=_pEs-2pA9CsCjCI*ZLnfw59*tUiROdF|;_mLhJ7du0jEtjr)18WminuPF;+jvMsc!dtF=bOC_Pea>6T5K=B?4Rl<3w?+kCRE&2OG~nd-rb^{1DHhdt|lYGxz%|JIGJ zV()(S3-|Wj-*jf@&W#x*g_)VV_U$`6^Twu|E;jp8BGsHcCWSb8Y-IK}Tq)RluGOjZ zV8Y&1$?ooCZSBo*`K}sU9$PzhO*-kJC2Hu~{M@zgv8F1=+TRBAgN&@LdjxK6em>*y z{LjmSym!W&+Q#cy6zEm2xpey{yD34Z3Y!w2=$=+NG9}eqaa;1yc#WkSZ!|4S&AnZ+ zyE)ry@1m}*VkEt5qwkk8kRE`m}Jmc0}aOZHA6%x5bvW zJihkTLGzfK=4#nf20VwSv_gjJ-xlt?v)tdFo#AB4n^RNI|N5)RVkzJ^IBPu!~8+j4`Md47=B z>{+{HZ(mG~Y+IHZHr-}NOyja;e;FqD-G7rY+oz2&Ap3P>nkURg@$jxv2E+ETych3v%kw)e>?T?@O~zklBIYrn-AN$Sr_xIJy%YYs(ryI1nk zyQ}{F>3{t3=_B9Mm%8hNOL{691XwOU=G5roX1M!{Uw|q7THc)tm~ni#}b-%I$DcWM)|Xxxh=4!L+C5qnhH93Z}a+w+I}#bm_;>&+Gkt zW25gfht|C7%4hLGl^$*#_aoDc}G{V<<7eaw`H9; z6j`$4?98VJD7Ngqm&IUZTDovXU(eCBdhXUO8ml0KcvCua13{~IPF=lr&C=Z5(#~$m z*)$uu`=?GNsZE}wvU1lhIR=AczP@jpo5S_u{%qK{FLK({n>RfVU$B*Xe~VYgddae7 zmSWMb-v8gSaG|rnl7b2@hMIj7R_$V3uxL?U?oUtO({ruAPg}I3U#9X{V<9(-*7Ile z$MoX=E!enm^5Y*ncN#LRShFTRmnAy(u7$C2(bre*XV1pAEflZ5X=bwJeMy3hx<;4! z)UKGFpZsED+f!#g{Gh@R5^_a+dQL)*w)Si>@#Adl_Ul%^zEGN5S;?h%=T=q1^5o*( zwKD2Uf-at(ULO^HectJ%haP4!aIj@xe-`%a`SE%ICtqJ%YuWQr2NRf&#psx2OGIg0 znc~$d+{w!D;peLSxdGF?TGiFgJumX?R~PB@QJtK~uwq5Vy_Ywnq`&+4e?NboKRe1y zU`6NAXF{E+^TccSaWOb>tXx%|m-pgOtNhmO@{cSMi#};BU9$P}4vlv??c#wU-{04# zzMc5*pSkhOdXMt&!d;K_^C`cPgy&VWTf+RZ>*4 z#a?C}fBSPmr-KQp<=_8Z6@K-4Hp7c2Pd@zlW5Q4%6CQv6&b@u@kIQQ6gt)GL`yw-U zmeict(yR5U99cGojbb) zsuL57Ql4lrbS%1awRFR#O=ZiOojFQNWMX4vVk2kHoGq=m_^moESCU~_V^_~VbQ5jk=UKWjo|W!+U?rZG={^(yT4HZ}G2em*gb z3_U-uUE8;77oR%&2eB>B{xdMhsF#%5+F4fS)%}xVP-uyc>Z@mK?%gdY4eI0>cY^Cl zxl##bh7E7mil0|*aay=4c=shIiN2|KZts(5`p#cOV`IKFvl z>Be#L`Q=3#`7ucWHOEf#ENjWUCH*;1Liw`JYs*lP^Y`}p-`p0ek)l$6GBoGVu5b4x zxJ=uedY7$yUF8?J=eE|v%-bOX*LtH1{oQA-H=n=$(~FDKbxvQ|(z9xsoyoBs3m5L* zw@-U+pI}m@&A~|z-Zuq#aXhuy@~?@3p(UsK``LZ9`gt}I942yBA@k3=X)MhvpYZrp z?^=n5;M53E-=SUPx9tJY#=yz-shkX(ZsuOOCBky>_1C+ZcP*Seriu0+-@R5v9oeZ&Au*&1n#c1F1yn)>p#zbf0Urk1w( z=AXQy6HaF?UL349{nhvNt4ksxUrtZ`cxvj$+@}_DYf7xlt#`lqzFRc)ZprF}3x$$v z{{9M?nXOvpq%+M=Wz)id%*qqbo(V9>N<|ecSoL)7nRCZ@4zF9Seb*)^`0;j~>O8%D z(T$At2aX)!Qe3ib-IldEsY|t|YU${|uSlM2y)n1w?JcfjJ9ggO|80jtLEQR1d*+-? z**5WU#Ri_kQW6n@Ec;Y`KKjg=XKrse@myN@p2$mcpAjs>JbUUv2Jm z{r;M7HxuIHcb`_Z46|Tn&{%rJzczd7y@#D`@@8s%lCSH?X zcz92{y-`=^$g<^!S7~kEI@L^|aQD-;wgYE;bmp6Xd$(5H)xG|%u+y>Q)2B}hvYQ_i z96YOrv-M76Lw1!_{j9UEa&xE3Jb#g{yDYQ6ukCW?+HKd~f1S3DD>IjO&6+3c;^Y06 ze_f_Ff3m*@!;4*}1_Ec(zV`J^P+428oY1ptms9w9z1ZDidAYnHAuGh1b4pGrW zvOh1KB9L`^$)-#9FJD&SnEmGX%Ju6fq!y;6e0y~C;-o7*%#YnTR<7mUy8U|I8r4RD zS8vvo?S8s&;nDMU($6ie!nfBB| zeHX`ixAfaA45ejZ*RT9A-#5*IPu4cd+)i%(Jil}2md%-?8_YG$m8J3Z>(%Sl+*#sm zaQ<=a?^Vl}Jqix)oH=vJl9BpUmU#dweJF>hsTcG>aPrxLEEi z_kZuJvT0|`!auiozxO}4oPYjlnKo!kX-MQtZno;+l{t3n?>o;uTHP%0!RGzvogtyS zE?Y`G{`Jejw^v{6v>4a2=8cMhPnsOJ*Q?z9n9tKwSX}HHJJ){V3F)?{H_W739HzB8 z94MWhs=VmL+q=;>Z@uzY*T1KX#8x%h9=jL=NX>=9*zh3!3z-g7% zs#k|2GMN;geC}Ms#dg?$XLC3Bl-g$(uPVKXI(SGoG5fmKygbjR^2cNZ7!+I%RwSI& zk<$_MR$6}Ne`y(uk*39Vg{0^^d;Twso$XM+V%u%SJ4Yw)mSq4L#SJwo^z{3v>&?2F z8oO^R-mx@GKb<>;zgg9G&EsQ4|Ok+;W}w| z|E|50`n07-AG?`(%dX)+)VWBAt5fg#U4P|ip&adNbFS^I+sN^8lTK*(=Tl;@O*_`T z-Z*3J>%OCH0*^#o`C2DzIQmW4diK_^u#Sf@#Yrs!&p#G~hR)c3`+nM#ph>51o>VFQ z;M*l|D9?QR)!8B(ik&Q;YAavHY~!f^X!GrNp#cYfHrfp7&I%hV%a!Sy=O`$g+bPO5 zWx|g$Juiwvw`|+xw6J$2ig%^*&7ChLWm#Md7J(&t^=4kCr@i`nG`@bl z_bzWwq*h}@SYFyP0Y2qE=RKQsb9{}hEmvNOg>8RwOM^5vRxX{oA;XHuw0uHBG0o8llM zd)8DS$=_FT`|Q_mj?DhckSI~#mMEtQj43gS2o{ll{TNo z#y-1GZmQXttDi5v@T%Ycpvctj-;ZU+KV_%J#`S&st{=PaPRTPK^{Lx*JkOt9nwGA* z-u%kt!`_!{Z4d1|t)r)=rvCNy_1AqenkSV5yn>ybTaUV~+;nMwz5TtcgNK^yT{%zo z^gc~X`%o%ckSw>M<4zbKeEZ_@#CLAE4Al;FDsvJV`X~w z%+BJ3Sw-dBuiSZ)lEC1=qg?;DDlw;L#^|pw9z(;EGILowofDt_TwVR`*U`7r5?y}%R_$N@?nmMC&C(1H)~#D- zUpwpZ&!wlQpZs;#aN4@%;$l+*RutX0152-5z53nj#Vsn!mwUf63SQ}CvBu1ll~1k z9Xi5tV_Vgej?XuF84fIZVO0~cVx{4;XC8I26JxzP?5wyXv}u3xmf z_hsg;y61eRzK{P@s(3!iOEG6)*nRiW$HyLlJ>Jvj)ZdW>*VHYLj31c(q-a`VOH@?L z-5E>8KTZm{crQ=7ZJO6w+j;Sk3%AAIynfu$&O2UJqig%hlV_glef-w-(I=8%U4BN#1!q>u<6jrO);^1qZ=6; zZe3_#b*zt$(z47unpC53Ab*?eNlA|6o!i9|V`j{Zte!J#+1&Hop`j7e%5}}=P2ass zLorNeo8Gn(sgk+b+0MHqW~+RhJ9okB66Z@@iJ(dC4Z2$3N$ue4j1G66{pwh=Oq7S2 zfho^?`%NDEX@0?8?@QjhHR&j~^nCSXQJ(zJWuoxW`cKS@r>K3dJiU!k;Yr!!uh}e@ ze*W>%X%ooeV5{v4diE#&Q`O4c$zSF9#3y+ke0u1%rlO-}tmksZhT|45%BI^?8BLGw zI?md+nw#zFr)OOpik1>*jz3mC{?)~ai*0-8vc`a2lTI=;D0S^SD;K+cjf)*WgI?g5 zDS~o`B37E2QQlQwWlM#c3#DKeGw_cmBDW%`oCGVOcg zs%wQ9bEG*Q-npIaJlVX*MUR~!RIdNPX9fq&-ZZ0QX;Z6K?}3#V!#f+Qbyu95TP5sg)0j3r&>4^eN9J$$t zB+oy+Coi>$ld+-xyu8(tdtQAJ+iDYwir$6kC1fNn+_~vfK=9-Mx3;9qK8&gVEq6!Ny8Cvyy2GTXM8N*Cz>o`uE_0j|vlm z`|Vr5uGxH1U%dF?*VW-Fjz69nr=QxXb7)51oae#2)_%2Emb>51LgM68h6g*(o!b_W z@pWBm$g95}KhDWyIuKz}l~?vHA~`wV*EjNU+s3VSW?T$Y@>V}unHRY}c3+H7LCwz- z6QlOaGjJ?@&(H5}G_&`4{ofxS>%IDy_cUtPPG0or?Atx}OfLU<_aMRW;74tCezttm zJBGQx@18t)F=I=`=f^j1TJ=A_`R&_*Fxkqk#=Cr=6F4eEAPuI?wk;Eiot@hSqz_afrtdfl8? z{VEEde&n*D|Gf?PJh_t!?R+Gkca@)-^T#ch>Ix+~~-U zJ7fIo5a_n3G)1WQqxNJEKR-4(wG-1 zo|blJQpv8hXJ<|bi`@42;RgfO7ui`_JG%vvgda^>GOd2qs;mE{WOWW?-ugDRm36v8 zNnXW;nJ!HXCE=l8uU_MlxgHw%(<%IV=Q6e8&3hHC71zH$?Cot@SD$RKQ6i$-6E5b_swcjC1b!zgoeO^Ys`jmBH1s6(W8J6U}Gu)ZJ(I?GLYAt_jmU;A)k2?>yhwtCU*}3F0 z$ARY|hfm+EuvwY8ck9-L);5n$d@2gN?!RSAPUPZ;jl0c^Cu@ty)xUmu^T!1<#g?Fn z&y#1K@v`a_KHGsgm3ktmO)kAChsP$-)B z{ok#q^dw{5*Jq{8HJ0|5mff2%d-v&?tcN8cql!*{>fC0Qes9yR)LIi`<$^m4Z{3>j z=Qr)n?H8Y2i*`=T*mCLVAr9YT^^bR@hVG1!iQab*G*!|L?u5@M3iN7EOEa2PR&-wO zy6h<*GpntSlaq7i_w@_Sx$ zbu8Su^Jz$y>dY-UyZ0_zHYaK3_w#B`KHZUV%JBE?-B`EZAy8-f?rj?cigxa*U%gt{ zPq#vIQ%-e8qT-9P?V+J(r;6NVQJ8Y8<;don*Y)CJ?(&yz+Fa~kyO+86tB0QXY@f1_ zkSo7yq=jWH4?A$g&Y2y3F0Ff`VuSka+t%7zG99@UnVG6{?e1L*E4{w%{FF=oT3hF= zlh4X4OUve8`epOapDoL3_wBB}?6fU?*6jMy)4SyO_}8r|ka#^U^!?X;SMI+3a84Q2 zCruZJj6XiT0oj61bv18iWk#y+-u2^bSl^8n0Vjrq%d4vYu9|h~`FTFx*cmfceEaG2 zROIv?eltaRUq7Y;2SL|$Zs1Uy;#RzK`K{a9G3z|cem}f&<>pDx^*Yzz6y!|Hjh{Jl zVnyA1*`#RE^H24B{ZBU)6de9GUv^RCH4l}b=O0b#fB&65KVg<;EIWgf<{}Y>lG9x& zn|b?GeoKH3IA(^ljHk2;6lLa|*|6r^ud3MsvnM1OvtHh$bNiX>{XH9|`JU+AX~}gV zC@@gR)l-v|;qWGxzG&&$X%g@Gc~iMt=k3}x=@X0fkxg$e9(4_!B&Ds@CCS3&pkb=R zt+?ge;`*15V`Gng*6-={)z#mf^78`U^*tvfkCo_zJuC~av}sEf)pohj@?u)3j_~d& zUT4*XO6&G}Pr5cYVV2VQ_b-xKT3wPXr)I5R$G0P9HGl5SZ?BwBH+}dq&$de=tZFZV zK*?^?!#{Fza;$`IzGOLm;8Rh|wl_SfpptuGrV`0TrQ|9?*TcK^V2=gtQ=O!axjzTJ~-iu=>sP`6PsJQm#5XUMlh7_(=S>7`n*1XIRVbJsOi<>d0 zB|5*QoQ*AuxpDgMUt#BU#MVq?UAT2s*7Ek%8tJnxpHyMkV{RE)^Eh)FE5mwz{_+;5 z^INv2me@vWRH(lE`0UxE>f-#+s|6~XCirDlE9J}$pOx!+jd(Q8-tHT)|TunYM;@K4aH~7fh`4>+%1#C~d<8!+&WwX+G z_K>YRwk$dHHZJ;Z@b)#2lvw94dh>@vN!c5Wr<@@a%miMkLv)WX{%uvzeUA9ao z)u=6(UF4{;XFWrMfD^;4Of~M-hD8hwnYS%3yKq>3%L6TLue%0mTm_3oipaly8(aP4 zZ}#;^GtVqM=l4FZq$T#W@@fAsU)I=udMs@o^z%<=U*FZAw+|dT6l253P#OFG$u%eb z{j0vcEnsYFxc&FbzrWf2HSaI`t2$OJ+P-~9xtmDKvQww(PZs=84_|K<8YVT(RFY4* z#cKPig$4g#)$H5K+2>;SfAPP6QtQ8e?CX0pG5PG-?DO$nOY4km?#S@S#n#uTmt4PE zx?Zxe^XXH5Hul|F*}wB_w`h6Rh4QLTw%<{)aq+S=&51L*kKWm|XZym$<;m9j{+Sl% zm3_PQ=+VPpzqSRes8~|3D)Hs?ry8xVhZ`H;ty;A)qeOM~SC63YeA6F@R{m?P{e4ZY z^7XOalT)W2x3bQ@t|G4V@{5yF;KMTcJ3pTnPSxUwzq2|0?Zo|W-^ZUxnU|Z-uf@gi zBW35c$1^?E_SgRXweVKd#K-Ge4p$ytQMg-lTMc;Lmj8DvsJ6Yc_-;l$YjjzTbl(x9 znUBODhGczBC_LYKd1J1`_QP-AZqn$})!{jJma!o^kZ=3etCm4ZPvVsB?|okT_QFS* z?=|uFcW&Hxa_ZF2j~{a^IP|!(=zSb}*uE)lTc7=Rl~@>FU2Q*e-n@>Zi!NVg2zdO_ z=I+Ifi)UAvwVEGcV+eo#jAJSLoK?E@QF$vk_FlSMTU+__)1ybNt*i_JmhS>$?_S(x z_58OmXyvB;VrbvE-GGfD>-O!x$JDRqyuANnrgQtYQd2LEfUfK3Qv}Xmj=t)%{b}ph zZZ(DnFZWizuk7f^WO7m!u0HcQ<##h1L%dbxrY9XIKC?$h^KaRb!p$m|oa*adf4eBj zS$bARlB2@1op%o~t@?HPc>n#UEmG^hN2~iysdwBR;2?d8cgEw6#2oW&-(J1?_UhH7 z<}MAptGBCn?Y5qIx>CedtmV_>ydx$bkCiYVzuC6&uF8>*%a%Qsp2XUvU~~Is<*ucw z6VI<+^y0qXez~N`jKAjuSr|C(9-jTB_3!Wa`Wpowj`F_m%T-{Rx(}(n z7#a8;J8#{}o}IO+Eiw4j{d4!WKjIfiSSiq!IKy4~we~sCSKL0!= zsPJ!|_{rB>c@JOudbfA&1h2%t$JfqVPEELQChfgqe}OuOV*jEX?cI)=R~H559p2s{ zDq5xEW>%m5`;~;3M_pp${Q$w{?-g7VPuQNh`rhTqPp$d>f=54XmcFv-i;L3@0qL;N z?8=#TJ4$W46t4WNxqUis#)bL+qab~b9=zy1-tsLmnXS(F)@5Oc(hI6 zlgFiPo1_^SX7U7d$z=XH16mrr1sa*^yY6l}Ebd}Y%W-l;BAUS(z7-nnz1Ur_iZ${iM0M zcZ*7FUGrzEwnx3dldo3|Cn$Wdo4<8a()ybTPYo8mZe6ITbNbJ(>(Za9CZ134?VlXm zqdV8k-F@Qq?y`MHbPgNvd^Sjq4v}a}lq;2Z{HvKgT|Z{V{<5`;*7|;|nya(UQBya? z=wc`5na^KqYgMB|49x)5O`5AP z%aZ`ZQb|glyL2S^_r^omhaOT z_NG_HubSkw?P}K7lJ95kytK|=yZu`9`~N$Oudn%Cwd?9-KdqTsQ$zMeOuN_6^4(1M zW$lm8bsl0I?napc3yyq_4C#~I2J4!rXyjE^(SS%mpmANp%&qu&f zpkGEYr;F>b!I{aBJ~Foj^D+SzFt~`^?|%Z!S=1W^(Q$L_wBR0_+J0qnHMvAE^oYP#_^G#$K&CLZ`Zp& z?0Nnour$qW{#?_rusM0lvu;mNIsftTpJz`)@*h@S-&gzVP}9auNo&?w&2eE^I_LIU z9==Jk>3#JaO%_E zm2Ow>%QC&b0xtdTJBl;e6kR&qq~oeQ&p*vcpFN{qAaKf`x_9Rm`#N>3-Wa%UwXuAr z@Z?$RW~+3@y^nqOS$JOg*RLmYbHf%o$mS$DaVT~j`dw4r?JKhMUEao}N7seOEm-;7 znN|JtoZGe2d6Xxnemo%ckesb8or~?LVr9+ z-gSs|y58bV)3wjt(cSip;i25+TP%Gk->pC=an`rpYytN<=f%jC7p!;Qp&Xuiewy0O z@|=0cO%E=-z3JNwzAK&4&usfMo0z9^eV7qvzGH7ijId0=k@kAX5D;YOwryu?P}UQz zw2eu#{rna_cUkYvv+Mo6g_Cb>o2hg2XIHM(_IH}lO|VPW}8`;|%9lDe5Ct(`kA7u?+>sJ$?!LH)bLdHbSN(U)9%gkIgXp1&(8 zL9f1j663_?1D54?bGp`aO=VKj+w!ZdZ|xH0$hJJ^2Qs>^7l^RRzU2DDrBv>rs&YC) z(`mcHM**3hvqlqFIXt@X#C7iMrIr$HiSr5|S>?d07f+v>=yUG7r*`n^m!R%xSyRL& zKfTJc-lHk~^(KY1RZH|!E%raMx^U>E-~Ss%o9k0^%~txU#;~i_Mel5xsuMMn>-pqX zHhFc6Sq~Tzo@qUc3XDH1@BLu0Pi|GFa-7pLrbdMwYma6gJ>bN*so`(wj_}ZniW#Iw$4Z*qk}9k-9py1Na8pQj$YefdRA88gHBj(hLe;>5a(v!m0F-`KVCteVCC zM^YIjcDorJICkA-kLozGQn+x}&JXimO`ECtxz06*&tm>vhI$2-n4oG7k+elSO5+2a z{ZxD7E(w-c>}G5bIAr?MBb{SeZ%StS4Ib%0bEWFS{d1L9d{=nmbo0PBJAG}}8xHXm z{F|g1Sma_IUG8{HS(x{ZGwE{l&EB&Aaw+Bv95S=^6mWWkZb;>totdn|8hOAW1*BZ$ zPi}ADsJJ3vx`Xl5 zwYNW8smSfK-FsOsM4{+JUi8Z43ltR&?=Anjwq?Ox{zm7V;!E|XHYMKRIN^8x#mx@o zj4wYd8G;Eix<^biPa|ywqN`GF-l?@CZKK;F0<@@Z? zQZGq|;@HI+cm8E2MO}-@DOB92)E$(boE^Mm-s3E(Zyy#hIOWs^3mshd!sUr4FSGjP zZPS7az0AL^{<8CqV0?YX--W5SPrv-(lH>QFW#6&BWdT!G=l(fgt#YHpo3%akTIZST zm$)2_d!9adHLbVw--P>*Z+~$Lh`M;CLha?GC&xT$ef60Y=R|M%^lIAKEh_}~J7w+o zBpMriZe8xp8zL({pV%I5bI~{1Zl}@Y2)6<-V1|P8{MzH$UcHRjuFE+7RRY z)@@@@U#d{F*|uw@T9@8d`m9=~s}?q0X!X~FyUraG+g`K2Z$qd|qqjq5G;4d_!h^xy zIWLp!Vo&AXydjr4rNwu?ve(Nf#n=^7ES;j9zHW+ej%rsf;EtZmVbNk%&OA>BiZsHolzy zY}(Xk2_=W^ubi9OeO>IhchyqkOP6GG3q4QS&X;6Jkz>_30&zn=d*HQLzs+*zLaZ>$QIJx}nh zWSMt6@vB%=c8;*O@%)(IX{V3P-~Z$9v|Vkl?z@XGv)}v8H*$4Nwb{R)&CC08_pK`5 zmzT2qM#HU7h2dhy*6H=--uw|i|7YTn-7Cx8wgvsz&i(%NGR1;F=l%CzRB+4c?Y%U2 z`}GH>XHS3j$Xj}Q{g0S?|Nq?TuY7qe`tSDm+Kh=AD7oGHS-5qP4aQmD5xmvOFDz{(Ho^Mrfrhe1g^Xuow$3*Y7 zs{H)JA@}ja_JjzvrCZjoOkS`uxpuL8+4}#rR{JdG$8`QWeBb(4jO+D#yMG-`$=PQq zBAfO0=3DKsizW=}zxd7ErLUQ{nfJ7KPyO`%e67%F6=u2lX%n)1!UD&boI$*2lcMn>{~1evZXOOAW5w_i`13&oEcK{^Gr9etU$>jpiu0*Nt)m`k%Ud=l2Ie%_lrER79hd;kwFO_afoSA#^Suk_^wf!l{ z^@7*lEu11X?dAi1`^(iOe}6Z6@A-Qy+UvOf+1?#0KiS>m)_i7NukTl5S^D;K=jpW% z*(Rp%-(uIx+u^j!uRyTT+@lZvack4o?Vg_mPuVZN%PsAu1~j4K3}DLX8XLV zr}OP9sG-sK(N9O$^3;l}kVrOSCjl;(fa zeD_z^c9O!jR%z)!rJq+$-4k^$Xw?SkO-F4QU*^BPXJ{6Bou%*f`#17A?-?&#zx48Z z#pa_m>tZu1 z+IVpVdbaEDfQwi1^WvttzH})6zdYQ`SAM~irXbglYwzb5*UO|wPD=|uy=lYg@4tOd zFPZX5#(a~_T)k&Zdhyvy6rX$y|Nd&(#Pw5L;xfALcp0|rW%Ly2&U$&!Khik#dPU#j zDRJ{9y`OKsn6PB;zMIeY)o#E4{^Q>#JI!Y)fBjkXQSsbo1+OeuA(yik^4Ix@UoCQ0 zxFnc)>&Djy_O@SRnS%D#*XISVlA3kkqqKF&n|U!SAB4r+45~{i3^VUtRp#r*+RJZSG8E&|UcJo5$s2)AW|5)|!@{ zU0xA)|Noce$>K5`nRBx;9Q*6-_U)MxBWkg5?Y@;u-<74Uo%MjD>Tfdl<&8dv>Ysnw zcHP{)`60V~{8^2Jh-KbE$C8S(e{OLPx~1&<^-gBThCUC9I z5zFkQucVfK=@&m2wat}7a-Qt>owoLs?|Ap$j9V% zm9M_^%igLlFMBs9^IZP(_PYG4U1I0eR2^&H{@Bc?Bjc>8`$}}W#{XBB++`GZrPdfH z&wq30f64oaS-T~@US4h8m}2-j=Dy+ewrMN)7EH<775Btz|LAbwO#gCs`KkxtlYx1vv8=EqfW(!r^+oI!DzV~aq>vaYf=7;IO z`iol5s7>21v%mh+%@eKj?fxNS)Fqwe?1fyf-Lr4^eV12hiJ7;< z(8l`TzoX~tfBl)wH|MXO#?rRbncGU2J$~R2JUum9zIR@{&rv%$+yBoNrf-+Ak(~Yi z!L#dmo|UODwlMqZ@toeWa;@~S?Bny_=44#;{aYSiZ)0R1`J8|5o%#zlO+mACpRJaS zU^sJp`t8@V%dO3>UeH)78vFa;MRDmr6T24v`}S$M__I7S*4MwJtQeMb-8`?p-h_Se zaclN+>lwOTQ;k@!^87u1zE1tc$LUv3>F@t>__?`Wndvsxy>&ISA3U)5G(YZNqs}Sr z?9=soe*D~D_wC&M{U43jXP0lzxmtfrRnPO^>BH+i_eh*xURVG3bN_L@5Mdd!t(vZ@ zX7KLVQ(ybb*LBMCN!s##HGhvw$NxP$^S#&Z`=7yw2^m8Zzpu{eUoS3+w`Iz`ky~MQ zXiJW?gKO~JE^jearxW|W$=%+T9`?+*b&t}?_G~pKFEq(`Q+i2>!$U!|9@}` z=C7za{Kp~s{nnoweKg}&OsUc9_b+6=VZnH0i%<8hb3R)wZtbq$uy(nf$jY>cdDbOG zS*dlVTf;7fOpm!OG-G$Oz^6+OJWp?na@roY^zX%u)Bmma|Cg*OYpzqgcdhc$61%Ox zF21O2e7wK@OY4E{t?IkI9{iYZ_kEd)mv8;US5k}S$=iLtWxwbD>8T-imYKQdrADX( z{`qZQ&!!N4X8+%(zn>ppZ`!(eukPI4QnOV$>}@~J@}9E#vUW|^@1+MP@89>yQ)l`r zH4DA7{Xt&+Tlurv7$uhF1}<2$Qq;M)b9eNGhm)RyY`gxn?}sx(P2Ty3?+)f4Tc=X= zGOKBE{q~*8kNC~n7Hv{tym9}g{r+u6y9}mkJ}b9A_^`aPuIka&3Adk@S29+JmV2*A zwA(sK@9Cj=4LTh%#}6L*&c8ok?}qkUzudypAN`z?_6nLIn!p|U8MCHr_0pNk^5OXB zbo0FW@2~rJ&%PaJ`A=u*l}&5^ZCkhS+`d1q{RA}d}j(l&FFtNZ>l=M zO}FQcB1amxz3Z(P@npMj^Tw^1>l_D`eXG7-^X;_%{qFQhSM??5N&1U#Qk;LkargSm zACK1mf7X9pOl=ka=BJ0etPU2(9Fb;m;CR`!jbVq0aggnUUx#*NMnAk8pT~T_d~x`{ zr;qRZuD=uIo~$Y9{jA=I>HKe5&DI^VKY(|8Ez0CTx4p+H=peRb3}tGv@vn z^J==d{UzVWyW8iN>g;AbV9;Ct=fm6hnlH0sRtDTPvawz#x$FMhwbSySocj6y$Dh6Y z`t^}_v!kBfc*Mi7|MvFV8$)^C%I~jwKL7mQ@N4;Nl}vV7IcxG(=k1;Q&9uHuF5_kF zf8l~kP7nVrYd`aO|FLm8>h)6IzUKFRyWf9*RUMwJUCfffbzkd}WbBN8@$&or{`}DT zYRSAwQ8OcEu|9ARpAn+@yFY&K=ZhySX9qE?T6k79+~Uwyme-6OdkikzV0>_SWB1ip z8=9h`PO8N$()qZ1H=8hMI4r$6w7`I;{;+{*pvupm%FE63e!dl#U$Lt!>HfkA`V0-v ze;n+axB2?H{lBjs|C<}TE7M2+y!ND;q7NIGb)|19_3C-r*_+PMN)Zj5<-ab-tG|SA z-S!HbyVV(nqWgE6xN7RYepOO)QCIVKd3|pL!{4>Bn>QZ)u0LmPw=SoR{Z^avpYL$D z`+L_vk_*54S*Cu$+V`6;cK`qK)S5l2y7cml9{pV|KabX`|IAMpt+lDzwE|U7OX4|PcA-rYGvbLarL(Pj~DaVZdY$UddDZ{;`47ZudM^#noE9SlRA8H z=8Z%4d;YIp=25FOy=$p(V*G=Q`xo-!w>O-&zH-NQlTrQW_0Rv`h`la!T79}vw&M2s z1s|`OR@OcEaqRK^on_mWgwA_qd*wm@o3fnJ#)9hF&xdZEs-IK4-ty9hIXy==pWK!a z?7U%J)qw!__g`mT^qzcpWsTY+em}kQqFPH2ev@Mt3(DlW;##|K+PKs z?#&)mwc7Y7hvNBf^0VuG_4?PG5xH7);jwh=TvMOV70)LqL8l#sAtPpT0i}Uwdb_2+ zY$@Te`Tz0hdiUqc8Fr}r?7ggi&2ke{>WRnyZwBZ8`SwWt@<&$&CH*-stxI+!-~YuJ zcl7Vw#pn0d|2_Tis3!yC_V2%s$A3BH=M(rcC+F|U&G~zNpFLjxxZ9W^X49ub3orl8 zjlJDpQn#?9S$D6T=g+@e_1mT|WB3s}@4ZaLF4LOboo}ipI_XT0x*u_AZba>~o6PDl zn?4=w?Vi3ok6{JB+rIi|Q?ryg88&JBefs(S-zTrk4{uIBSu^YLj&p6-%>DO1C|k1r zRQB)rLKY8?eR^{Ar%b~)kIVe^eET;PI-Pan+rP%X=GE5kdNo#iHwm0pVc^;NeQ({L z$bYwQM%zt)zCP~9z4iNQ>h<=Sh{p?AJp6KC;_~nE#R)To<~^=2`((X;-=C8)MU{LH zILkL>|KGgV{W`yZ#lLj*{hz-*?SFoG_2-wN4ElU?Y_4tW*Ifu&6n3TK&JMF}*A44I zb3$(K_T4*vY;Sbm8oN6iHvanX?cUeeDM4Jj{%!xdclP#RuZ=(LxBuH8qP6emwe0f$ z;Y)%v8E)-WyL$PvHp7>gom(b+C^hGr=YIL$g>7%0cDiuv(er=1RXWX8-)H?Usl#4# z`5UxT87_!jN?Y{6?uyruS-UC%ytH>^MJx;d_@UlZ(^2aM{D@x z1i#8LMCdR$Z0gx5^Ud|aT2r&D7ebvsYtED1{W-wPJId9#bo-O~UHz_Qr`g;lzu;JK zjyK`q)CYI@r>9Cfs1)^|e_#E+=E27bPQ{i7*Z!ORk2gK~`>mMMwafdYw}sEos@2bX z-kSeD>i_#)z5MV0txVxmXiJN~0q6 zazfAdQ^&lnt$NWEaXGir=|uhA{0H1N@}GXZH#gIcXFM*LcsZfx^QmW1jjz-uX8lU^ z;;4L*%crq4%<;D3Z{dIm8o`HElGbiyl`DPCm36ahlMmDFT`RPhx~yKsJjg!v>4S{? zx4UaYxsDg^`~5a8>6V7{hy3cp+Dt}LQhOd`Nf~xE2~_4G%hU6ncJ&H4<+TSpVqTBfHhB zy{ukr2hE@x_-kEDnF98&_M!)YTG^3{SG)`5aq|ofH*Sg+yED7Zw&udwovEctc~igc z?K*pAN^eCR$F9yjnQxA;$GSZEy0l)$^zGiRv!}w|bRGP?txwdmS=?r!ab(tI_Nqtj z4eLZWSXbUQ^WiFgtp|@zm>(?9Z1O^@tVvG}%+crz*u)!JO-lsby+Y;xM z)VB!ar*AQk)jqdYv$XD@?$wIlzbm?5m8ShHYTjp!qVl`fn2P#1zQ!e+u0OlHWkUN2Kb_XyA9qDoUe(K(6E3C{ z&F$QA4~y;8rke8qzTPL5M2vM%VbJe7KFA(xnQ zVugW@OU#6AbFE%EUObQ_=gOOCUcqk9F~w=Kfd0V^7a!iQ%5oAYJ-lHd2PPqcBrrS;gbR&lTSM$;cp`%d&Fo84P3;A$df^eigT zKS}u2o|+?j4=?BwSa;CdR%otIlHP9iP#KmN9EGLUXN?qC0{KN4KMEy1lZ!F!TX2+p z`i{@*-YGm%)e)a?v%89=^Kii3bDwoqC90o3k#*vIy=zWagV_CZC%O9$@3T6Sx-p8$ zt6Cu1!!7;9#TF4zJ0SuxZN|pHaeU|PS5w@&rJmijUTgR0vyc-@@SAO@qjN+U> z7I7vFEsr16E#a=QagwR5iFV?O>D4u!>&C&t^l)SSn}u#1DUAKgLJdK)dNv)$zlw9W zB}yD)jGh0sl%@RIX7Sc{rl0P8x6<+3c;Id3=X1LssCt|_Y=3s0!RZa(lQ#M2y4-&p zJ^RA!`>#3PJ=*`almWEQOAdUz%MA4yKX&l7$$!2fcUnoDK|!tM_}5*9Y%JO9n|ClT zC0BMb@im7)6wTS1qYA)TDw<3GlyluIMH-0XfbHZEE zbEW#6n&W0NQ*M#0Irue+lm8t5Lcuvr*6WTt zCuSQYZwOj&u9lfm@L;>5N#o>)ccL6Yo=Jw>e<;Cl!HYX9bJ{Jo^ScjPUVnASsB71* zWnyU}`StB@Uf!__TYlvlw{qJyo~*(>-_Je16x(t3%&c2oag$Wf+g-f6>o0?s?_!fA zX-|fh?+kpUZY%T>vR@h=+Uas$K+wrrCi(T2BGE9R2L~%8a%4o$#ytAJ41e3(Fl!1^Or7cSy)INWQRKq15qB zWzFhX(CNnRkSi6LoqfZ&f}3QDet-Yi^!wrb5BnmfMV;&o<+?2Mep(D~bn@ymlCSnC zZ1=iXEAzgDx!&3PeAd#ywFS)|^c=f#Zf1w69M9CjA^pt&y_fpn6uL;jPdE`2Pqor3T8GBH05l}m~WZ%M6Reee_*w%bp6~`Gq!Ww zKN)^3xV-VERZr#&?FS+qvC-dWWnVaUzx4k#kVPU?~I*?y6xhB%m8gnvRPko*qy~N;8fgp-Q3`uG*|t;PeFTyEZ%@73iVm< zE?jPLZ>{LMOJ{2}>Q{zt*&^zgCwdpWYw1JM+$Yv<2PCJyT>JZs$QqW3zb%$tfB1%t z!HGkCtI+kt0NG!cw%vHNKx+wOhpu0`IfH;)68n<88<7z!*H(YkY&cX}1e)RN;7FA} zqBlc(gZcOOOT?}O3P`RKuAXq0;eh7^_Jghq&mXvV=Xq<^iWr9H_3gi}faVGd^mh0+ za69egS!MeNv;oYZeivk+kY~CiD?``z*9+&rT&S^6u3<)1Rd7xfkIRHw_HSlp7w>xN z&b{@tSK7C9^7Fm&Zr-@{r2ksw_2g)8 zF?V&Ln>k0{hwr-OESsy?w|e1h21OT+fZWvA+Nn=F1yr|Qb)TYr?1@iWo}qukwY2>B z@*B_ZUYVmbH#EOTO=xA;aozeiue-Nw|B>C zxn9F5+Izu%>opqD-Kjj6XU#h+;$2nUz2END+NYWMrC&_0Z_8UQ^&>!cW1!dN$kGy} zy;Ax=Ym=(G_iwjW;kt8-SuC7u^XHuvo9^6t^7b8vnakZJ)9Oth9;n>Tdqwxas``y~ zhnAU4)amV07kXKw@#0k$f7v!x^Ew9J%TZA$_4S^AX5G5;;{AJ%)^}fts65!{abwQQ z=Cw>K47F2kmt=0WFq?Tw{7c4>tCuBn^1kHNTi-O>YdP_fN$|9m=H}9^t;-nTkp>wQ z$_jdL&sqQWvhaMJ^i8w5uGB}*X1>bOo){s%UT@W{YoUI7-LA&6_DEO$|2il0yr*lAEjK>SZ*Eh( zY3a6&R{Mi!O|^|sp7nNi8nozw5tl?PqU*R828wy780DfIhiKU>PrYx!aEaS=NURKse0 z#iw(NuRnUfX6Nel)*+`SGvB#(O){{Q%V^Hq9cqGtKuv^C3(|6F_h_x1dP z_BAG^hPByM=YE8EP5L3fZ{zyCrUAEIZ~v=X{Z*P{>6g{q+T!c(?b7+|{qywU?B#tX zcEwfMsi(e9JW}sIU!Q^F$C4;v8S6S`(CIhO`P{=-x`MJK%4)Ct{&I5N*N1C0?nMPT zPHTO?&&c&7X``=lHGgo~nYmKW~*86;?_w{7)bw}*1tp6W2 z|F!D-)%`oSERz0aygaH;ZiW9c?fpLwU-{ti=tU!2e|7oozKCgm<@ZaU6yK8EK5L%c z&1KTp#Gi|~9TT3uZmmsq{jR;U;%3hC-v9sPmQ|7uCs}nR`2GIdE?mrg(`D72i1(}p*7Il1@Y`zgE3SIu@#jeVO9 z*O`6(w>GgwigX>jIy+m>wc_>GcWqVYv-W&B_xtj7HzD;tlT)AGPK`Vz z`uWe((Dm**(_~`urhzu?ZiWtnuhnSHjFOwK9`$_bl)Rno=L=PYzU5fVnD;lUElB3p z{TSz;#||6u&JL2|)4FJN{@V?PGy3(<8F+YITqlaVzInY`TGl_M*iU53>Q$TzHr|Wg zf4MX|>g3B^SFb#fezTrkpqIm)-}L{-$DOm2H{SItc(H5ihB@V$hoaYi6=3puxp{e1 zv~;b)_IJ&}Ug3{j*Sp(TNQk=b+j#Ht&1dp+ee`vnv;QvJ-sxr)+__eix$fuDbSqB9 zN%cqee{(wT;GgnXWa`taOvfkg|M~La&7Wt)pNo~5&g&JM#{F_lRQz+hvK5RA9QXe@ zc6zS%#-IcGwbFaEy6!AIxa*gdc|)^v>HNB_Gdw~=u7+gI7X5m_O-<ps6VREJ5Tm9;tF>#l9y(gBNZ+m#LWm#l< zpG)+t8iw5bkAI(3*B+g;(NNn<^Y5=mUJFz9{P4NGJYMfzmJO(BH(wqyJeB3DX{s9? zc0@XP^~Z{Xk0)B)KHU5DpDce|=hNVsLEga&Hru{&$Z1Or<~me3ecf8MNlODxT)ix~ zs{78oI-?u);pR4*%4${qy?I%7c}srJx=6FN{Z<=aG_RUvAU%NB~Cx(7QNYianc^Y*nwPg?~Q0IJ>?rar@RE?7tUFvp@X( z>s6m@)~Bi^H-DbVi(lP4Eu5RdPd0njoRdChmT-Dhug?GPaJP!pCEWeN{{L?k1NTh5 z?!8o-VUJv4^4vpuGiP`)R{To2{UM{K&QSeBOt|}sS#MTY74La_=Hs?k_cfP>=N~CK z{O%pc$xG{wn;A`Hx^P|Cs=Pkabe_)6*d+h-4coPMe4Nqx^w8GX*?;dYT=>rb(yRFn zIT&U})J-!}-|9R&TWfdMiTe7l4lA$Lx4C=ye)RsQ9$qiMP84Nm|7L#u%9@7@CEHjZ z9GaTS^ufk_`;5IcxnHZ-e_dNHW>LH+H1zDliCZsrs%%~9`|=?(uR347xwXLTRg&9! z?dxm~er!=rsWUA8oA##tzHC>^9fqjc%q%nJ`loMt8gL<3B1|WaVS@Gwv!!?P;%qN( z(d~Zr>6ZPU*Sy=k6bxV9W$uKSaGk@W&SsAl9 z6HMcF6r|pKJ<;d#yg8n|zH0mb&#h-%|2%A=OYPk_9WSmar_>r&-aK=p^HPE1req_Ik@PEj5Y1!obsi?6}%wx$PnAB$S0a zk50YgeZGWKx@y6+Q@`H-vxw7qxpU98dqO`R&i-9yZFYOv&nCVHt3RLiUhTSFX^Pgd zuk{m;d`^$@m&=Xm|9|IcXyAi+mU~}c2kj^Sx%r5Y49{T$pS518vJKajYrk(*oTt9B zt;z>v}=4&OiPAyW}`DmQIS(y|G*I(4jyVz{O)$nb$F{IB@iZ?49=(gz+D{aY!#R=t1QjVb&7zI*X0 z>)~wg?)5g;_inFWd_SxI%*K;n%HvCcW+76loW-euab zD@`|G&I>(~;$yr`G>H`(wKJw0`-#6=M5&`qjkir*o_KnY1u% zVt#K3T2^@e{5t=xG>Nvve>p#DPxbGs{$Q>DesZd#z>i-mw(m3y2<#2nwdJG1SS+9R{`|Y;Y*Sl^v*MIzb@cH~Kao0GJAN$@F9MBi%irRYGZDr1$&;OPrM%}O7 z`hEZZw;%WapRKHKd)qVj*HcUNtOxb}a@l`>_VdrRyQkN+N8?j^-}XwIAfwn-YCRl^ z=jXh$sNAyE?$uS3)poCHAI{Wc=u&#~&ETFYw~fC=-=3dd+f_bII#K_8sa}7y&a~d5 zqbwJ$Jz}14^4`0UpuL>;@4UGEw)y!^{bTG8lN_))V$wX=lNvP%1^%nD%V%o zD%CT1KKlOE)uk~w<>ArvTO0?y_U!m*aC_POx~*HbM7?>(QTP9A9(&Z=BAJiBQyAj< zuiSbf?iv?(B)NT-#?fh!HgWx5>i;ZX{Qv#`$4~D6`!Yf0)B9SJowsA7SQ|fAt1{%C zwd;=-ab36X+}+EPTXd`}XERRF&WN8E|E+rIVdslUC+k;~No>uTbvE<1_r_pxhSCref?)|L6NTc&&M8mXsUfwFf)lZ$sA ziHXw=?MZO(Oh2_N&-L{k*<444mV&u&59aIXE!`}7dXdfk-IXm~M=z9W|HxH$b?Q*! zTsmo8*0STek@eHozP@&F;W19(i{OJ1I4xbJs{9cGg@Xs*g$781KhY=4PvT>SHYH~ZOQcJC=V<#wFU{G-gwS)R{7 zZGV;Lc3hajYG1CKvDM5!cjeXB@f=^p@2$GGepbNbrLp{(Y2QvIU>XAK4WGnJr#RcBufz5^{wlyj%_qJ2M?p0R#^ z|I4nW6^kO)NwBxiGSka3wA&gM*t_ptMs3M;ZUM8b?2py9mzHL){^;U4?Z?#$L6PNs zrs4JNxfiXzKX53iG5UGi-e-&1Z{6E*QRi-(*%mFh*qF!H{P*i-?wS4P{Cv+Zt(X@b zbIMEU|0(Xhiw-acq%7QTUQ}A~^=)~+ndy&9Ge1Rbx)SjI?pxC&#sZnjcRsIgzxS=H zD67jd^X7Oq{ga++#n+#GU-wBL=exH5|I0i1{|#`;q1!)zh-~@s{iL)_uSsEyKhUFJ_zQM&)8E_`}KZZ@#d8W zr~6C~ep%$6yLqokl(HDouhl1X1UjIyO+2pwOTei#zH!Y5jk997&zPjkup>^}t zJ$T~tZ2rGw6```DkCr+G+FOK(b7?U!)&1OQy!JJFxYn_&vpJ_9+W(>Cb{_jN(BalM z!K0rN%ff8V*S`O{kl%iGMDO$9m6H?-)cd!|Ti)38amLJ@OHQlG)wR?=mEL;Ro#V&U z`Tw6Bcz67XHI;!ga9j^WV?e@o~SD9F2x<1t34c{F-J1>6P!hcqQPwcI%?JZ|3vao--JY_ZLhA7~J`;?2bLe zKL4!$*;K|YCRO#n{{H)#>Q!<$D!z29)&E7SqIL$HZmphiBd%(jwoFm&zq5b7#LQw~ z-djI$dz^g4{b>2G|Nb0j|M%fzNX^+H^)xaS;}Wh?$IO~3X2!y1=q6)*RRUrWti51Pol2pO~Lbgy8TGHa{M>Cbmw>%TSj zIc?zMD)=*3*rx8ovxDs2O+nlXT5|p!JmT39TK~AhUu1{;{+<4peNS(S?b?wl;Kw2P zYQ6NE?u=bW1(iI%8x}0O!oYE2S-p;XidV1Hd_|FhzhC2J!b~r3TX|YFFY?b+fud&> zzds(^OceB(*>z~=TF2KDz z{<7{o^>x4Nvud-ZbKDGj?dWnL>UZQelb`?N|37uvnbUCK@uYWCA}s56{QU8E-4E~3 z3Aw`Z9Sl(`KXU%6K6F?1U{{t<-wx5l)=fX_IrI1a&HBa0^kAp) z+U5P`*|Su;<`g~u)9Nkw?!8oy@Pga++@Ri$Fys*Jc_lXQ*%qw!bmY2LWTUuZ-HwkL zhYhZ%I8+v1UbMDJ!tB)LW%ER)&T3oVlJK}@=3G97a{C1LWn%1t9NRN(&Up5^RbDaM zG$-P5sq)ohV&zI)d+J~8-oM&wW$Mf9mfP2)gEHFeeAhBP%+?B2Y^k_Y-t9Z-$8RrA z#s%B5q))qK+}YL4f4Il_4de1FpKNT7|J>8Ri?unnX=>w*U8UB~n>TW8_$rG^!K0NmgJ`~E!f@!9ta6pb5aAe&8<(^W>L`kscBzN-HJQ9V72E~3*A!}bvgO` zRy{s4VcPyI$(wt-&aTjz`D)PulZj`Ui~O>b=6LJJE;qgIWmB|lS3-29dP3PIK# z9@^oWcQ=1EU1{c*Ae$Sn~vFPj$Da7{C}Q(+dfC$N%>2r#75ihvoXzfj0@%F{C_yV2Q(OP z`KXo!XhTj(i-7+J2gBN}Q}(V~{k2I#fp1!6aMsMUdn?v(CLIvIh5CLCtUODwzN;gwal7#Z2Y}9#QeyzgB=I;9PhdRIC1Uo9{D8wp3Eux8w2>2 zEN_@MHmx#9UZA$5HhOs@gFuvm*h2rqKJ|_(*ac;K&*~kDVa++=zI|U@i^HqdwT|+w zlI;Rz-@+}V%LJcEb?{^swBMMbydtKdiZzY-$AZlpXKpAmNPf^9&}Z?(E*-QJ)E%<= ztU=(OwB0JPWu>NRS(?8JZ28{5zoO70oKn8}^nLdee4I>u-zyHC&pax0o+#;oSCLob0Lc74ly) zUl^a;caz~z^Jgc^Ju0<#=SmkY~0aC|2x&AyR2>Gj&SS$;}31>dX0u(hVcok2L zv5`K%y7F|Ho>`#4;dupD#J`@HXMHs7cGMBL0MW$mzH>!uX(8FZn6GB@2*AljG71TFRbNU8nX3D&%BebD-WB^;anp%+x>&f zlaBB`x7)X*Oug2#b+@ynUbNZGo7_k_Ps z{qg0$rG8tzvf3t}5cTZCqk?^t)LSY<_1|9++9tAP&D7x5D>C-xH*6%nwUzJKu&l1~ zYmuWi$D9XK_xSl0uSg4xX?pE)n$z`8qE&y^3iC(iA;F@R7gcx6k(s{i^vkV}X1RZQ zv;Mw5r}dVSlaf1MzkI!G?e5C$XHL%v-n!20&D2w;>Vqmz>i_C@>Fc<|H~*k%Y3@3U z^x)`+q7#KXgJa`$vW{wPj8GMu!1TBApX~kT#;?va?MgWK=~LXrgJv>PSJSTEtSsFZ zn)kN&>qZ&&!v<%B`&2=NpTwGFVb33b=3Uq}@0pxy(XN9nX&J`a#@(H++u!7MZp*o8 zz1vLs^f9Z&bL;P3%u_ek4|UyYAvu3e#M}UvrHUI$FJA7v;o_)Ua<$x)eKza8m+~ur z7S&l9))xPKws4y>V|l`3y~}3nkFHzUW))(8BiFm*=jU0! z6*J#@FTnR})f=nxADh26Cx+j6D7e!1ZHlJl^qJC;(l_sKh<{?fw|?=bs()Uuy23xm zamjL>a#Uw#PPp~Vt1@+$f$bzoOBu^OsrhcF&xoZl2Q9dJ`JJF`wb1RN%F2~nt~|Uu z>rM34@aI={x~<&k{xY!Q`2NNlw@Om00;5YlzYE)W_2Fh?&~bpG*Fg6JJ@Z^H{p-XZ zj}y|j?(e++^9>tA

&mw!`)NKHPXTW7TTu@~K-ceYsUqyrObJ<^hoW`bW063a>2x z;TGn`lYMzfLsL}5>GfM(Z{1RU3p!u%$K8L-YuQ=+B0O|+Zcf!v-<-A0{L<}5`Gw%U zi$Tv<-j3gYf6LjYe?Cpy+nMCF{mZ-p|0A-6|LUyWcU0xqrmxt%LOl5CmHKIWi;r6N z6|f&>pL;%!LBL|+-P`w`zV*uJoHOtCj?T=V+Q;R7sw9lsW{ZrzajJE`oV z`tPVey8K_(^tZ)-Y`^=^#c*S4^`bc+PXB8Vs#uU-YqDtG3inS(x;E%&yL_+xV6? zH-vyzaU{-*fbOe5XTZy_Ddh5kbKBmA=uGWeTH;$?8M81$owNV68H2Xcf zKD%e_4BcaCNv$P~;y)Z>7i?S}Sa!E=@vUiltv1h!@rqjZl(XWM^{efB9+h{V)vlbp z^vSfhyOy#aIbb_qardONN6REU+M}HRRsCQ4I_>h68ZFD|SG0FozgYKv<@c+tCMkzL`{G<)@h|nNj#NX6qgq znTIZZA!mJO+Rc5%AQI%9bA5X6scrXGu*j-gUt8Z3cTG6Bv&JU><+Szp#NT%BYBpV~ zrz1QQ9)*xr2!n$zFSq8>&5Jj0Y>i(0(P`U;ZF{cWxOl_(%I3N=m(B=nHP^KXydDzn zUEh>^d}DkmZ+BGE=G^KpuP-Joi>Qq_BO?5{^V{FIzIT1E>Q2k-t+QPG!ZKHHY+LV?6ukQwPg81yx&7Xi)AM<`KWG1}|55ViLw0-W`?WTQKE3#K>Fn)? zYtODbn*Qi_{H^_lt4q~oj^Es{J!i?3Yd3aYzH)Z8e5~o$=*p#EvZ@MeK3*yJ_taZi z^*6t+)Oc&j>RAf&&xFTcn6_`$t1ylZ-|a`)qE45dKK@x-S^M^OZ@o<0gBxp-D?k29 z`ucupiKgXznVL+4`U?@kcTau0u}Z&CSH5NI&8=U&s(yd_weD9hXWx&QnkR2OOvNQL zJFm=ma6{tEvF zr6?<}LeETkwd%o-6U5ZTuP&0x;`l22R#??==Omf^7It-+e|~5muWbC@{`Yvi^}dfk zo}PSqBj$|!$M*n}1uejQIRs{g~((yDUt9{7EovojAw;lhXbF zCHwUs8J8A6dfl0{E8=9R&BD8HSrQ|!J>}P%z3XP>hRwMP&Td-Mda-rs#-%?m{=Bz% zZ_9))Syo%;d}`a{?9YEv&vN>SyFVTs`*Zf^ufAWeb{Bp(;WcxuHhcO;ZT}3NrQY>k z53X74nWCo~7yqOp?|=4h+r;y)e!Tj#^yka`W&L|fTZGHX%RXG#?7VE}$}2Bk{SNoN zJLSo3?_)jn#`{cmJ>jgP=f3kF4{Y3PxyA7J%IRM&es@>hzGYsBmyaq}cI&Qr zyWTC|&FTJ3|IBf>q|?`@SI>J{c_0|HgVJAO+Jkz~6+u~Bt@dX{hIyBFAAipHfVYBw zj!lBZv0p!2w6huZ)U7}Lc+r++vmf?*Wm&Q=Si0TyqsEnGjTs65i+|_74pVH-y{R3n z-J<-q`RyW=Ag|ZAUd7l=H-4RymLwVX!1{anDZQK9-u~KFb#!sS>uX;hR-AjgH?}4J zgC(e9eq`r^BJ>}ir=ijfmyg3f=G69|}X_TBvVA-fz6u?t$WmU!ITF#Yk)S0YoB zRz-M-mRTPRJU8|9&rRkp-rl(H$nlV6-S2?%EvBcsw|`1~In_jCR@JOk!dZvTK6Egd z(3zTadE>T&cXKtAwHB?ob8g`h@k>ifP6~fwk#4@Kdo)DQ;jzQw`t9eq7i`>bXeM{L zD@rr^)7774re-&lPw%kpPOq$q)Lq4Umv__iZ^w$(-MMhp;KP*zz31~RWjQAabmUMCpFO50* zwAl6bqKVHuO7oWnEHwMdV!JK1zs7daRMYqy*YDhZ^X;n1-v5eIxl?bdHa|KRZhq?L zCjB?rukyIuns4_nnc^2e-^^t3?}Y73Jiga1`<*g#+Cr(uHV4h{S-Xvv*N1;`a9*%+ zePJ>`U;d3~AJJg%mA}qaElyf8{nDHRu2IUnWuuoyFbZV$E(r@NHh-3LxzEJ?7TfJ> z`rOBh8O+X2(M;=p{lBy)HLCk?cZ)i+KF=EdLt7WI9k~A>p5OG2Se$I^+7#{Gb06IB z(9RAPUtTd$-oki;;cbgAcP2cUG$+3PP}<_6U3-dZT}wKBoqb){&wpGAdiCtN`Q_CwL6c%SmpAD~U;pw@zy0*jO$wYVr(QX6UHRnHC*PW{ZkpAZ zddIH3*ne%Vh5V~sGtIVUT87L0OSlohduZa;nOiq*PHw&OmT&sr>XKzlt`{`bqIfD+re(;5N%XeM(E@CLKIsP%mblaV*yoZ09UI^Xp-}=6C3uruP zK3CX5&ZKAF@uPm0OWZmRs>tdhc%`TeT;s$@o{r6rk3Cr!?5 ztIa*v^CIUq+k)v|m;GDT=PWBy^6=N8S4UobX?=P4zNHVx!YO)pW3*Jbnshw$PG0ee zz50CJIoXPz2c{W*){EVqwCqOtp7lG|OCC5eUAgn}LTv+zYLqrhEUt8=IPO?95e3Cy%eM zY{R~E&70$=Ri}DG?9RUFL90Z!e&j!{nQ?xz?d!jJ;Hxv{ML@2h6z+SxYPG=+r+u&9 zFx*samp-(><5-@k@|Lpga<$(wOm{OXi17YwvWvZ}d-~SZ8x@V~{ciPdaj9Q*_07Hw z=fyt;&VDw@lHqEpIl~s-JFm_O$WC{i(z{a{s~o3nef`h$gHx=+2N z`_C-@wDISRCzEDb&6fL+^4)WaYu|GYcPqZqh6aI4bt_^&c`QqlTE)0vf{w~F;jVbg zFTWN#ua~p>^laj@+OtuCvv-9$s7 zjir~TFZaFs#_n3|Zy^=FqiL5n@*m4Noo9b--^QBcxeKL~-}la#b@P8x{f^q})eNA{ zQN3S1H1xFNFD#!Hy8U{rtb>r#s`9nh#Xp@{TGW>4GJDbMpP#ct8<@?n#>P!wDD|3G z>RR$JQ_8E@m~)W+0={Yajx%KmlD2t_g$B5Rc_PoZ>TUbXoIH|L17%ZQt(w=jl<|t`y{Pw#XK4G~pD}OtjMaSor(25@ zqXkqiHcm}ioEyl{*?MHH$EKq-O8iXqbLAQIKk&}wWtgTueKq?NAxmfTn7HZ8hxZ56 zo-kTFb>`GphmRC3nxWft;PL*w0-a&kE`8kcD9GvS!n^f->2no0-!(+*zt(=dJt*w8dqok|GBlswB1$H_ni91g-U7PD-OrSJ?Vb==+>X8($jBxBZJLj?ZQn< zLp4M6_SaYb`BPDvuNfURH}Wa#zLm!p{+j-D_UWlLsy9SJ{zQAL+)*@dSo&~jmZDFU zVXW8miizLd=49;Pu21-NX-nKS>D|(+kB0S6U7GEEW!YKw@_81~-Ec>U#Bck%ih*la5~KowiQwW@+}Mn&R~0EM3vr{i2&) z;~sF|WNPU9$H(p^)WqxPe_?WG>bm->*eOSg_VFyJT@gD;m7%_6!nA$U-b9(%iR-6z z$s8Bm?CRw4dS4j(x@hlwZ>wp2XOD5cY*OF^caQ!({`=Zgc3SG)AFtRntlF%unOijo zT&i4B{N>GyLtk6J6iGQ4#!iU|x<7N@s{=dsZMNGy>Eyb!c6*tyny#hMM|}c|JpcNC zeP5Q;@%-muec65gUVg3LSe&eVS$kQYn6Yd5fxD#}R##>DUwGX8Bk1%>?)R}1Vv7`G z7nr@Zy7biNZ+F-==NY1e_`*UxD^$R@}E}8SC^WT-J-JKA9 zTDM>Sbl%R#3CACY?VC8yKV8ho%i(6>yOW1nTkjO{9eCAy^+&{>U4h?DHrKD`eP=Nf zw3$0`Tg97Czd&_Ea<{;x`W5?=7c@WK;kEJ*XH0c`_49q_zB0Q+-lF z2CvS@n_vCk_;>c4a~p~otj|{7oLK)TtZ!e5$t9tUKC6S)?AWueQJA^(Z0T$E5H8U} z6L(G9^=sQN_oBkA`6Z7(?QV;c`s8BMmi0pPuJETX_ILN+3v4P#c`&o_+TXQJDl1s8 z8m;xnPWgZOx2>YTuD{>QbC>J0DjgYrDF1WTm;1zGb2TJtgJQ*xqlaI6-{4wQ@Z_oT z+4{X_x1~-mQa!2q)_U*y(goLgM2|ZAZq!UaHOW2e)^(L#Wf|MNI9}S^yIHkiszA`G zDK6V@d=Bwnl6?L8wY8^?7~R{j{dvWCTj_(lYTsooJ@a>N!tv8#hrPWtef5{vCi?&P z{%bvdO0)W#k1e)~ls+--|95=mYw#SUWP&JYY`NawYTjeU8Pg&kf7FfDJu7>5T56%p z_P>2w-b`Ze=f5@0SMw?BzHf$0GG~f}JTU*8Fsb6?rnR@CD@x>EY|*{FEqC7Y?Z?$T zobGqp-QKj)*Rt{Uj;51$UoP|Gcz9yjW6{8iJZq1o3%DeHc=BLw(r324$K&k69tYdtkBv3to*wXK*SXBZs{dhj7&9Y>;#%jmy3M-VQic1j)Lmql@@3MI z+_`6zID?L^Dcu@Uf297+*5qZGVe21G+b;aj<16b{-RkNm-*@CKQ{#+I7PeTJGcEh) zr+{pYD^=T1y0j?gw%?xBJ}dY3GuD6mvdm4Qi#ccSDlKSvd_ZzrVEyUo<#Mmy*j$M` zJ(1a;_lle-16NjH_UUXb2Zn?P_cjVTRn33B_cY_%aYev~qE;XocC`>*gebLu; zUiWo5Y5fn2RPJTkRBD@f*6&!~SY;zFZs90szBMX?!(_^rpj9)fLN?kmoZfbgD_brz z+tzjRe$D8UY1%h$B@4SaPH3@y%CYL;{p+r)C8kCwik0QBoyfVoTq4Twa{$ew?Ci!$tv5b zdPk}I)3MmE|El_*NXE+PW^Drv?uOVZ!1HhX^YnAy}>LKO=SUf+* z*|x68ofCIH6uaa5&UbB)tKXXPtLb0P6lGSfPdfej=gUJS4qPlx9~_H~J9t~gR5z=; zUi;Rmd9}$?O;*mXrRk?{PO1-kwdQpWPmXUv$DAGe>;8Ye@pb*P z{arhh^G@!)?fo#1qc>~WG`;1f-nZlT+b>|*Ci7sTO>JrI<&`f_pPtUVu0ctIzhoYJ zkFV*K993_}->-kA#@#D&XkP8O_3Fz%C2r?io^Eg{tKB%GccbXpq$uy=7HKZNT>Aw_ z?=Fh|<&>$ow0>#LB7cRZV0}%ErK+2!T>s3qyyW+;?eYdMBu#RXx7h4jwDt$|2Q>3x9*rDckj>pfP2FHT));@O~0n=z038^n@4i? zO*+5&r&M*H-K-lHeu7gMPFuJlzg=!!%Y+TqHLJc}Ny#!=|I~P@Pj9WQJmgL`M|o>}K_NIqXD)#$*o{?S{mvYo2m`!<$VSlwx=Ub$mRfUw^+ zF9Cr@;YD6suHWBn`g>Ti+{W=9=2ZoyDzS=hjm8T!@98jrB{M{wO_pxwAz1N5L6^oH~5C7fSQt!iMMC|_mZphLG^i|#L_KG zB#(Bjo4M?=Efed(=aXzURV?q6Gh2GIYvy&Hvm0{RlOJ2wpHnSzbp3MbPi#`Pz;X`; zh6V;t7sn9oS7Apt_;y>}VwkGD=|H7w+@qb=XZsCvXI*`>i1Bclo{5u!z#}oiDHf4C zlHWFFF3xeRsUD1|estu}!&Dv2Kq3 z>K2EIF2}=?SQBn*tcqH==x0n(@`cT|{RuZq)ME8siurd$KdO9m=fTMh6IV*C+;s85 zRO#AF-){Kaj?;ay%(c=fWn!_O3DadaN7K)%B)@jZdEO9`T6&>A*J}1=AFj^kGs2Iq z6wF|1>rH807P9*EdF|Ul&LRf6Dq0H~4mc_lY|3wTT=-H$vP0{^&b8^wL|BDSt1?We z^stdRtrXDI)!EcJrO!|QNbY<`E)m`*r2-C56fG()YAlFcF+)SDL(AG{=0cIxqA8^X z4N4AW24>tE5+@`%JTl7aA@gRFq4Q=br=#|*VYBtR@mgq(Pd)>K&TT*Ot3Df*x@&Ii z-n#c_mZSE|u*v@GK6~tWe3zr-a-aCtt&7w+V~*(N-JGp8bDHaGn?=v{N=0^y&rV%_ z+HF%xh_>cD@!{QF+mn>mAJ#pf?o?3I zw$V4xY~tmKmj!QKd#1Wpaka9}Lcg2MH*~s|bWLHK>3sL`?OpAO5^aS{uR)^?pO+Zx zYERUz6j^EapwMnNW5e?u^(*eb4PBD5Z_Vu4vuwk7v?DLQwh3zXFSFat=peLX+k(@| zoU1FZZZW@mHk@~LPK4t27n4~*H=3!;>#kCnr)+uk#wP9c7rR>B_@7U=c%H1>vcvV# zo2R)KdUlmMUY^A0B{)Ihb9KS~xdIwCOhP`=Q`b)C&6Krq?5^hDB+X#a)KK42#i}a2 z^z6o)B9*dA?GyH}OSWX?#0km?rV9Uh*0yF>?+&i{4Q}7>9XTd!vg3jH#$`_BRexhZ zUAK>izyo{!R%bUbu-I1Dyf%Ik$`Ddg{P@_OtWPqTAH1riqmSrDnVGKfZC<`7uhZt^ z>FS*c>h2GwR^Gj3waR<-Hg5-q`dg=~YFpd=m0W9I%kW=qJL7!oa=e3xoKX9xZBv7_ z)c!n@y8Gj{F%!(*8YC^Jbq)*m)EB`b(|=^{Ym;l z&W|J2$CqWldeN$%ll|HuJ}Aa{`Ml`=pF-+$GRvM+Y0iJhdQrabn~cS)kL>S%u2*Z> zQMqo%+iAN}4~IJ2p9oR1tNZ)u+uMuFrrkT(+%npU$}C)K&fdcJ1E5wr%I4{ZpkbAD+JX)5?Qfy->YX+xp$Tn{r={>eBQ@jf3EI-ZuD~Y^z-RKoK7AJB61cLYmV`2 zGFlwCGiUQEyEPljoL5gt&x<>`eDbcSk3X8f=FZi<%Pf6=#nYs^svkjC+mdc?vzK{k zU2{r)-Rh?^E15Rwnt>9GC*+bUv=KdS~(-W-lJZVCziS3(aYznqjgUIdbHSH zq$o17P|ztT`{T})AJgOO7Vq2n)N%2u(mj)6VuQ4o@@@?DmZ6b>QV9MI`yx=CCs`tEmIVJdlzPeMVJxepo+o*Hd$hYAOpBziTiL~u92`{9UZdteRz4|*&#T+n zR&Q0%K5fI+nC&S!s{1x=dAUi#YU|tD_P&G9*#mT**#9}ZKm3&I(Wh!M(>+zi(w6P} zfBk={?ca^nI+y=^np=N9ebT1WXFt~HO^ukbBl66$@3Qr~sv2@{Pq+J5tF=vM_nnr4 z?#bEN-ki!yd z-mCxW>AdOm*FXIKs~&s&fA;hI^ySB+tG=y0ZdUhH+Udka@wogqFE;8{Kl$_g^W($8 z*Y$blRaAv1XXoVBzkdEd_3c07G;zh|!ZTGm4sUmbq(DoAnmy8O5GHvcZop7cm7?ehFTujJF+ z*L{_>d->@{ndvrT{k?g)dMAHA*8jgf^VO!)ya%?u{XD-mLQ|Z7ZcWzxg~>9<&-?b) ze?BP>ik@u_{+}zUQ^=W%DYYRyS#+PX4(5{_m%kuKcKKO8)ljYDmsa zX&(Fk&GU=*82q_<{B!+d^Sqj`Cp*LM-Flm^02+Om&kk8_m8GgZdzyu$^uDB7Zt3?A z{1Th@{8u~QJL`faRn_|!?rbfXllWrFrMq(TPptFZxb~bM;|n>PJ%x)?XFU!-Uo3Nf z^Z$;?oP0;$-uqEdnHM$XNwfO7HTi+ssSI)R;|q5(T9{2!ZVA3Kul{TM(Bp&`ZhCFpaGSGFw_g6z>~Os)T|e(FY|iT!XW05S$!_(IJI(HX9gA2N zlz%vI_VjbEojGPxS7c}0x_YDNBuj&XN|f)tpG=8?Q?}-Fuh&@GJz1Hd&+hxIB|8{o zs-8`~`txOsRp!h#=6p*~p>v)Ayb8mBUum-6IiDV_uGPEi3u=?UAGq-AzV7K?^`8#g z2i(rfd>=Ev@?p=`sjW92tvUU;d)t=WJ9d^en$x{xs$Q|?D{KkBo?BOCG}&ug>DMs! zIiahf7$^9xsr~zsy)|ds;_d%GoLruI^yRko+>gzDVqe=Abv@26^^2W5f6){-spx0N z^ZjCM^Iv2|zrS!`qp{xky~}xQq8?w@7k2WixA}aj@4c$m%ctwlGrh1c__1&PuZJ_* z3@e|?oabI1_t);H*)|Vn?uL`u;!@VToG%`mDLvi$=NfeZo~!Tk*b=*oHWvIn6h293 ze$~6M?cxFgee8@k4VEsRaQe}0o!jfO-ru(`dwKfk$%*fpkBdxCuY2USb4Gr~`+wiO zUS;jn@CbTRf7?b-pCd1RLC~4#X{sIkb#b6TJ9!XXwV!F8vB%Pf!?Ntz&bQ3xe2U)A zK5u_9^r}hk!o$a_+4*fQNXkvfe33l;T%k?mk=v=;_CCV^;|34dvm7jn7F@9XHtj%4lzvp9fz>;O(y82xd zC(n}Fr*m@MwtcrFR~0GpE9^6f))Zx)xMHCvx3GE8#-+>m{|;6!mdRdy+Pm1eu^`ss z)`nXBrC*LMEuI>*vHt(Wgj`-t`Gq(Blo(FWeD&t8#nKbvU3k9rIzW?{*{D1m=&vQ>_WxTcdbZ7O|y}P0|>UbAcn$>lxX#XrZWOnnB z2G3ywA74n%bZ7q2n!L)yYvLT&Oy3o_M@@M0tL>QA(n+V6xUY|&mQufScm0Kp3uCqR z1)W&>I{KFRw9J6pa(lmQU6OsQiJ9zK?PzpRo==6rR{zu@zGFI~99 z^x)Uge7ALRb0qgy{&^`b)1CY27VGV8d~+&GPs^|~MC~m3^;Q1b_ASA;_Z5BnyY%J8 zm9NG5?Y=HDZk*Xx`0g@4L)ELF;b!&cJa1MU_;Q2y=u^92SBm-41xmISz3t}bJkBdq z-Ia6Vi)iso{d<4SFB>?0_03zaKi@A+XyfX1dy9{!zGr2g`{gmEyLI;T^BbZl>Ed|pu<9@uD`{U4= zLqB@wHTx~OQLnKy{CsVu)UlJ#;|lZ7En_`gn*Zl${CU3~-7|i>?z}tbtUm48vQ00S z?D*}gr&srBUX-3()vu@P79LhOa^>sh{Xd@{U3u}{Uw5akzMD=T{d{QJE3Md2*T{!5 zKU+YP@AYgq_<2A%`kzXYc5BVLeH(Y~T$}v3?DQtLb#a?=Utg&2G;R@a>QK?{x*egRh0S;8|NJ;RYU!O@#sc^5yjc*W#pH2x+WCE--@leVee}=t_kTa#eE-*E!|%^h z8e7-L{_whf<>2AtwT%y^?Ntufi`Z8B4^UNDGSrcww`#b-+BiUfYjibF9TZNN z(YtTJTbuV~mxAZq=JsuKc1`dUa$Jr;YS${s}g`%|Gpadea%78dirTJGVx?RXVlFUPiY* z<#OlK)__`J{SLkL{;}G}#M7m3?P8Fa6{Yn=WcuxyA}XMhR?-h#T$c~7oULweJKnZF z$gBGM+xwfkpZ|2yvog`84yPsFS?Y&u&_2}5vr8hI3ub2AH zmXl?>uwke3t9PEq!-6(0bx^sr^ZkQqv3lFhFI@>b_dJQ)xNTi_R_c>O(;2LOeY2kI zJ415!L|;{@XzN*K>6fqh_VWd2$y-#NdYf}U*z4tqR{c{)YrMZV9GAbd>H6Ex!CvBO z?j@n7y!DHxocFuGhv~p$ehZ=5wI4tCn})u6mizBrl9?a^iAxN?%-7h~TxcIvdZ@kvi&1dKC)%$*Je*#9zGs6{n`22e-m#%Ub-z-Pjs){|9{Hrb31dheh4+}J8V5a z@4<_i#qa7xApPnSvv}S1(pV%-@oVay`q&Cb&sX= zIp)^#?d{v{AA3UAuSX;AeWS5{-u>J4UwpK-8QGi3#Lp2`jntjae#UVYm7Io_}Tu0o6Uv*Nt<@2|@LneygekbAxV-j9#h z*Zn{J^P_a<(n>#pEnYV-Tse2}@Yl6-uQFTx`hNV`^5oB#)9?RFKUBE1=9+kqOvNkL z_UvNN3RC-7$k1EJ#cFxSm8-(6cK!avFZ1lDY?slUxc8ga?=v(uj5?8;dpj>HGynBF z-s`UNN~@yS&8DShPW8(Ee&E2x;QH?}t2mo(+_GJ8rRMzncO|(Vy3=_W5?)woynS`M ze7UR7>)BEFetbNy?zT?+b7kCv+q-|W^UK%HSf|=@MQZlCRhv%Vy=K0}?!=u%>sEek zmH&J8$yV;GqM@^P|N7NGZ{5aVwY|;)rpLlGrysi5_HCZs`)xv6wtwZl8rA7g zUU&a`-Q8X6-^#!7zPT~wh&ac-f0O6m-&3MD|Ll!zvG?y7Rs7gt{8eAB{=-iBKUd$J z*y^N~JF9BRLd#2cu3f9%&20E^N3woR`m0|@zud|yt$kEqdwl++*mt+qffn!|Zn(1p zbSNcgVA)M$sp-4BMJZn&w)I|Z-~N5w`$bbOy~=-lKX38t4Id57{y)F=f4bLE^ZQkA z-~I0j(PDMDyk)n%*`#fZBB8aau^DSW?^a!2ZIZV{>Y0<$b%8HzcZ?c%LK%*5MQvL0 zzPpOGPCx%)n)b8$nq_yyzwU6AbBMmcst|X@hg+AiUF_%%?;OjkFF1BGyqI!2Q1U>? zwI>|An5%1~lQ(9B^4yXaV)&6__eO}}h_(QSlHZp(duO+B&0chnmBEvD6)VGIOO~b4 z(%&zX$T79^=`)z@J|H;5?3xzGi4SjHdS?Y6(JtWT@L<>w!qzaSul}i#mCc7YPrvhr z_?!{D_-LQ#Z9%L0?~hX>*#tW8BqyCiJp)pngYm;#u^``T0!_WQSNm_>_x&2%G2Wcc(N(;a!BO; z+c%6v=hi>(IFT#m`a{KW`46 zU2WfK`>#i7^?lHm>bA-x=*Y95$d3uvr|M_FOgdV>?fZfYx0jg&hZLupz6eYyyeym5 ze}p~uQI_NBDW$XDIp$3BO|CRuJ}aQ`Rm#qaM&oBa9he&f0Sfhx?;wO*8vqLW>4lY>fg|^rg6$H z^Nlw}GDRh26*IGQctD%N+P*$WkZ4N`cwRhn+1xYJi&aA>x~ea4ju2UuCNb^p#HCjM z`6j=O{<|sd7I$Q*-mAQc&t-bfZV5E=xx1)TZson*&VOs?y7!3Ie~EAuuk;hMeDt8= z?ve{Uw-=eb5xeu~TA-}I$L#6zPe)(2Jgq7))BUWkrJNY6VeS-PFU?!Ed$MoO_Iw}^ zI3Z|bSmTky4|lq&wI((SxQOKBUwtHe@rm1-o=KeI{09%-c9`N|yfEqkXH;31)kD$5 zU=iLBpN>73%UAG7xA8VQ7t}A;jO5juAyOzRDciMq{Yu}!jSFsn=&ZKi-jOKLcC#2# zz%>Y5lK8YkJ89#h%v~>2*0Q*FXnasyZ~b6e*&I*34>9p`ts{*-%?iAv`zpcMu}@(7 z3G<&v7I@zOQga5<;W-E|e@0q_+-0mW1*UQxZLF%9WFoi#z}qaJ9VHwPCuZ?-R?o*+{!|o z{nrKW+&uKZe7!O#X?;8N`1fjEkc&a{ETAq;FJ!F_GsBf-RX*mA+G01Zd>S*^;gIkm zft7KSW~mk}R}IRMC~n)C7Bn@8U3`%W(?gp%7gRWU56ykY5zrjPJ#FsBmCx=ptzltd zvfw{%S{yT@Ub#GDorm_6b3rK#cTfIX-oWs~(Taof-p+3e7<3p}4;*xxr_jLhqtWa@ zZF{oD1SYXYrUx1KBODl=9K;Kj`-zEoFcdCeiST1(YhX@MVA{e|zDi(IV`_rv3JYmz z{v8c&3#Q)P20G0V(i>ycSo(B!s_nAkJiiazE+y;K>gP#aIWzm|#!VAVY}jp6ZgWlE zmbdzOsC9mETpxE~K@nRUpLX_4!{8SpPZTSwt*)B7JrBpjd)lpLKYFQRKzsU90b_Za;N9m}hryR7mtSt;bVO zr5xRx|GKyI@3Oq-IX_qEm~fTre7v#u2G6SVuZ}G_c(Q)ZmEEO2nSHaaEO`_-k-OmB zakUpshPg8)t4-v%zauljo!4u90Ea?4#~y`q>*jlEwsKkd6f%Cv+_klDF-r{lp92C4 z*7p*cm_#2~6);Yn1i#K56JaVESNYZnbzL>jL47ajO0dwm0Q}-hc|X$1S3uGXQN~uGzHoY4t;- zf;X2#Y5oFxp!4u$$m;7E}Mms_8gZ1y%|Sh@4sq;jv7snN@FZ(Z5veVudm zt#bPW?wyfrjWci8Z<*CPbwh{Ck!?}!CDO^egF}|(-ZTE8dqixa)Ri!E+vR(6iskyU z*Su8MTskFaSKX`KN78PFy=@e12H_GvlXXVREXNQ92Ebe?6t4hDIFTJwpT5NsXrdQf|5y$T8 zzX|hgke_jXPau2Af{oXnNBmdF>CFA>dgtHrWgO8Ak{)@xGp@#dm%KgKZ`a4kMe^6z ziYnY^1CgKh9K1V!Z`15`(XB%DYd89)sI614UpKu+ z$iJfhMdhleE7klje>=QvQ}Fbp=?rhW-&hCLFIl$yTl2B)ya8K(ORR{G*=aF%o}Q#? z=X9o`2S?Y5|J_ty`~Lao`Rhf(%;fYxfAVju3wm67_*r@}cSzax>TlV%fMaXv*9nb>p6QBg$X=_h zDgD$x-Tv$f$*Uo;O{{Dy+`kov~u; zI+gWL?W2F`tWM=UUC{mRox}IeW5Uw=8+F8|?~nVrD`iSfR<+CdiNBQpF8nuZUKGoT zdDT?77XvR|EcUT@CcnLBpYIfR|vXaBWs(HxEw zjN4ztoznkX^k(|XqE*Y%?;C~(6z2r5TzUV_pR-wYSCuPk>Nn-D-SO?;k>96(KJ8`S zWBxC0)uc}zaxYWg z_n%u4t)}Q;dR2egz6jm5>!yW$j{0}ce{bF07qZ)~3*2@$mY+M-M)i6BH}?MC?Zsbp_ulN<_pfe+UJX)S*WvqCdZqOL*U$d1 znlbeiquEybIsZS@yxHShysk>&KNZ7mgmvZ;_m>x-sIJV#a&+m{juO~+q2tadu!0ThG(8f!5ivlM6G=i{wZsp_NA{y z_fNAdSs_|)`{(t}FL!31Gk$%%#^PV%rYUc_N>WeF%u#(Ek@NXx6XZ^*pAqWy`R5+J*=@*{%rk}tDDkiovYdW>ug^9x>cJ3 z_et&6Dtc63Z}(@usN=?!e=nYKKb(E|@yd^n&mL#IaphXB?GvuQXBX}-R9jM-X=*!j z?v%=(`RxD0p191u_5REr7RWs^{PHUTdSnuA~^5%N=kCR;2*316CKK0Ql zm$W1eqb;j9t`!Rl?_OPZ^8a=A|4|QEx}*MA|EOOt64q5^xPqmg^Mv%?{2Uv*K)*ka ze(8(Eb?zwp+q@wl;zZWXe*yo?cke&lc>49v_?~}BTGn5aZg*d0KDTz>Wu3Q2w~6;( zlUG$xUHrv<-T(gAov)oIDmEtXN4cAAtJVruhPa#2x|-8jJRh*$y<{%;SSa>r4wr)NcOjOkx68f?eSGq*$$DCD?bZ*X?mOi9{!MsZR@-`Y&ph@A)BjwRNQo1( z3^dL^U$K%c{`soabpkev-0Pnl{rx%tw713PCZvhBGBke6`&*~Bp4@u!oyT_XlHT>b z)3*eb$9_MS9C!cwuW8d{&b{FL+M|A4e_dS94rM0wn5dmB2?|CV>JFTIHu-h^_La6X z=dlQswaRv^)xNWJQvA=9XOpj2$3M6HxBBOLi$im>Y`4}OXl!FQvXnCrEVPFDH$kk3?+VUukE(e?n|Wg_2xm`!gj=)9n+Y zGrpN_{}o+sZNSj{@Zjgw&)tKR|30kie;Ib{-mlma;I;cutbe)P z-j6eEPv$XXd@|d6>FcTX&GP?VpRHF_5GkoI`M+^lvb9`|YFVn9v2dxod74An`Gd!r zMZTQgsb63CRh&WNMetkyukPEo`Po>PmzmkFj-2IR|7q{m_iLr37ufMQohZ&d|FLDi z#Qq=r=KmU-f-acvx_86kj;tTw@zWpEqvx$HzrJ29T>eqcciG$i?RCG-9kITibiM8I zVY98Set$0RlXtbf_=-_%YfhH_6R|Mv)o&ZWMHrS9K7Evx_;va3`dzm#OIjTIyW{)u z{d0aiP4}K(yYWwJy{qp2C;vVF`>!gMVbDrDy6ju^=J$myuerbJicUMXc3$)u{eMgT zs~hd#t$m@W<@dt_{Qr}m*x#F5GhKO(@7uKa&(VMLPaeAV`PP-X{8zT!QCBtX`6g8U zT>EZ&o$c4x^>TloXXX4|_;32{_&ECo+84e?9naoB|L-ao>O8x!rX)_=J&^O2Lp3z#|kq!K+Iw{~kQTZnkx|^4+c#OT1s+{IZ7k_tk&l-?i3n%u}=eeDDjq z-o>lJuO3>~t=&>)TsT?aQ_k(p(&>5uUdxRyPY=`knfhOPZ+^(>ALX~7K0O_;U-NeQ z-?fclPA8JeKHhm`*(l6sE_+WRy1shBUEN*XQH6@zKiuAUzpnoN_h=^5^?QFh=w#Jy z`*CyY*6h-CyVCMECrWR=d6WOS-4n}w`ZwG;409fP{ppJTB;O%d@W3f|$;?~U!tc+d zKA*M6*LUBtNpZ8z`TVbXbKPFWu%+UNS4^`&ReZi*x49K701x=@SRq@q_w@u<5`2M)wkKf^1 zep2Ia(WB|wOQ+6!b0#6BAUyf>s+;$F{x8d!vfKHtqw0*6DbI>O@0a>}_58R0Ypiaj z-;GGp3G3O)eyiHacDK}}T`sC0Z@;{M>xvu)?+%vmMU(1hobb7E zuAlRJv3Ef!>n<0+7%iRJy}!05N}u0qxBdBjQ2%;{Jtw$jfB4F)$t(RsoNE_;Z_WDJ z==*m2`u(=^=f!KUG5wVt_p`XXX73ME*4n+lzpBLxGh8$X+6NHsLG-c=(k3G zTm6LS9~Iw{`wH^E?tMD_FMr9Z-^*r39bMBgXNO(dWY(MNzZpWVN9(>^dcXJIyXKSp z*Q_fg6-Ewj?QUGV#)i)VMB^p*o1oh&2 zmTPJD6pBH}l(9Ev-jCuRS+k=Q4SP%DJ`kUUQYa?SB(qks6-7`r5W0)#Fu%_bRHU+&H## zX>nWbkCgbWMJ?)og6c9Y_uqMu`{ne%rnny|--MYq-F_;~uu6MX-R4ieE}cJA=BH&& ze>`0?BVy;(&D+dx{JwfBy#9IEdDC6e%IiEfP5M*x)0^p%9Fd(bTwg>%u_&W`plXgk?Z?vUGw@34t|N3TeknzFQb>a24|6ZS7Jw1QTU4@pA{GWE0 zzn%H@_R)H={j0=eYs~)N{1tBcd)EHz-}m0_d%JYr^g8=*zt5-H{f_!Et07~V+NVd~ z+4gOp7hSpU_5btt>h~U>7|Xfn{jEgfOTX)VD&D{J-RLpRJScSgl}S}sChdBDX7A^_ zzwa(D{x|2d)$?qfZfEI4pq`+?|%y@a4cawpftg=^Y{0u zt6Dl7jya{M9Ne4qerw$CvtRP<;(p9XuV8X94cVQr|4!x49n71Hu3f(s|2yUByu*-M+I>0yYp#NWyAGHwYxvR^$)ZEdA2XQ$@lL-o zsnz;Raor~E8Fx3zDj6_v++eD&ev~hMxjWKwweVd{E9Y$&{7k(VB);&qy`9=AvAkf% zOKH<&i;|qZ_wMbt{#>p-bE=PJGv_ytd1c|%2gGi4u04JEYxm{-5x(owp70#6FNj-R ze!)KC?zcxLlASr`^33_-{qO6aDz}pc9Ur6i*uIn7{$gF_9`BO9cYYPEUiv~I3YeZL^TV0n<5(~FWHTW&v!JExQWbd7UK%bSIY z_b(()Uoqjmob>U6_a%ETzkTI5McC3b{rOwF`tJN2)@O{~Oy+)V|59X5_syegCQY?i zdHbsE138PFtCMDJJh(7PIO3uEVf$JB=a!#ZxhSlJqpv~N;Dz*^+DM7Eop%Z=%TGOi zxgaWDPRUF=|L@TY`p+&EYg#Uq=n5`rTl-KhykAn^(dLio>#y!U&&U{^u$=ML zdK(W?Zc6-kbXUS8MGKm+Mcj)gL~mt=KYw$8p*!1|0@VizlV8 zzm=3%@A_`J;Pl0NkHg1~8Q$4YzMqBBX~pfUe`BvL5oj=SaAl17 z{LMP%rtm~z|CVpBtBRF=#8y8_VBlS#^f^sW-ZEw?Pv>+$cK`Rq4aXlDau?f}@;2D; zwJp-gYq$Rfd zO>Xi{o6@l{&BV}Pk+5=}LUm}`@u`)26KJS?Gq|l&V#5M3rcbA$4C=N<` zS|_%t=q{X^<{fdgm!Bbfhe`M)Gt-svNo%W@c^dGwy??ef)wgzu(BA@Xr#`c7Leq|? zDyMQdGYNfrA}GOs_=jY!<7M-bBopOrOxM&*7YVFeon@ECaeyM!{&O1nTOYXw7j&MZ34>-_6?!DR~Q#aJFrXS2mL$BaD!n6;|Jyt zk>d{-su({p1T!p6JF<*<4bvK?EleS6UT&Zv zEEApLkka&7f}zE+@%@9<{11;;d|kH6|K+bW=PYJA>wL7_bi;uy=14<>{Ym3}r;dwu zxEBbXxZZL{O@X0s(lOhM3Jk0bMhxsPOk383zMn4ofa!p4gEfN~LpJmLZ3zub4O|Kg zbJlO2bMU*xw)G4-4AH2V6upQ-C)qbw1Gi@bpvw;Z;vng2_^vsc89Z{ zHrX<`HmEkJGK621nwGqjDTRSy!QQM}+^&HlUmq>xwK#u|HM*1d~*Uz(!>(aOWR9qmrZ6m`1IJ(V;^|#pDtGH`+CJMRzZ$)dOgdY z*4`zIstQre>M9%uSS{5~gsk_!+2`x>LCb;Xgjl1I!(lyXrVY#`j9k}G<;_^bpwF1Y zxP;*f+quUM41Nsq4h#M%++qK~N1j7@<-fQ5tcLuubjmIC{@_{%4D3h_8_ zC@?%&KfhOsnS=QVLs9!$(IOLz2EPV_hWh?6iKQA{i!z#;7in}cF)*|UynkA$|No7C z=@*FyPBP+Ea`owod>eIjZeQAPQrcg5cEbYUfak@QZzeNXF{`Nx+Hx)y1yG7QRJGE3GeHYhHujHCW* za(2C6a)Ef2ZIx2-xOQfb2yyfT=UE3+(AZ$b(5XX6kD>hGhCZ3%itO);`-KA zSO%17%$!b~+b?}mXK&zUhU4>Y%(}25r8@Ng!HtfGrJH1w3^HDoT8HHLa=kr}#CvvU zUVEkg?BcWETq+!Le0Sw-VPFTPPm_a=^?@R;GdUDna~$yW<6R(e|f&+)4%waE`!&f7hdN)krJSm(s;aF%I zYdr(Y0R|y~9SntE*bv zwM#^kSof~6j*_`L-8KBH(n4_mJdNjgv1*-oNsEB8L5Cyn=>i3ZBMNO<5~~hcS4>OS zZa>0OAUBzZQEmb&#le2NeD?r zeot>~=5OAksw{T%R?Y#LJyB0iFbj8ToAPF=#fJG^~G^zFebg(L8mNi@t#(Ul&~t-8)D7c8uBT%eQ_w z$}%Xltl_I)eK%MC`RP@Q-rZX|EoAG8TZhXIs+s7Ttq(2fDhe|zS*&E{Y`jKJ`}F3s zUA{#gI>)tKmnKc0cDcjvNJB@&l^-_*oH`sA`Li(St`B`G%V^2TVcnN7Y^lC`Ugah0*;mKz^mSuOXQfP6B ztLeHiM@)5n0`KPfJCmQk%JNLL44cq$cn_1JOK7O?bpfYE8bvzc?+s$F3p%y;@EUq- z;3|q+_s8(Fl=jBoQx2@KSh?oJu7#U*vITXnu5RH_oV9M{tW!p76gYH>SF|bfod3WV zryttW#<+Th=#8$G!e0}5QeCf=&V61PD3E=8S>~*Dg*xgS?Pr?|W$F)q=uwoOQ+i%i zNz0M1q$TnkRA6n&nd)85_kX+D zVFRzC&IBcnCXEi!>8_WzbVZqQEOcJG@eyMPLv6lFn%}{y59Rst>#{c~F*hi1Foi$X zJuET(iI7^v1J;S+{Ihd5F+HhgG--IgC7ja+2Pq;s|-3ec1&BHzMgIG!Mp5hj$hCByQ8C>+A<+_)BeJbyvy%a&ZrM}(_sp_ z`ITAv$ArZt3^V4}3vc-=Q>yO@_wa0X?Nv;Ij=}msKKi{2xe{1x2ont%Ai}R~8qb`a}OT5eX{kwks zeI+@qr$;{cl-33}amwsceXSl}yGbh2w4SH=@s0q6FXyt~cO05`)FQs__tQ_eHZ9AP zIlgnwy6^XE?k8D>Ksw#cy%upI0Bgn|Ctg({}m)+ak1toLJ&4iXWXhYAjwZ z|Ka@qkM-wMckZd~zWnUZ&HlQw72)oorY^n9J93k=ANODXA2G?h!9i$A__=*XH!OGj zZV1u)di-_$nJ2~)$&KR2ejQskXIIgU17%I%R!<1D)x*#(H9uq5w~No^mtNA`fBpW= zdnXI;T)A`QY_)kgUqn>wuW#qJcdgmd7Jay}U}1g4k00IrlUF|3%u-O`?a#mv(Yv;; z?6a|J=&hz)-NtE~g8n@?&2MIAUdDGqv^f6W&rKTQyQ6kR{n1?+^Qu|j{=^gGcJ8+` z)9(5E_}3J_mX5t{eaq@lV}aW2pAQ!Ea~(Z&j#1+A)UQ+H|3AF`x%=}@r*$D(wntYl zUVdjE_pu+pe$;=pzFaQR_A>MJ$6b3qhWyzc|2NEhp3m+b=Ed)i9hSB^{(bBB%Gi6o zYkTk4f39Yh&y)GdGu`*ydm>i`n7!B&xhsqPZ!R-*?S`GNNPE686Vf44+;Mcve)0Q3ApQ-Zn$ZO zSo~?RO*fssZ4iHZb6vFF{NHEY_j@i8VvJv~f4RKkm#5p~>ni`Ao~t8q%wnHtxarlW z1#kZ(Z@<0&wtM9)9ZPTzmhwewp-wSRX1s+IpgKCSoB@p&VYkk_fUNHIQRL2*Ok zjMtB^+wc79x!H;F@7}ku z?&Td-hJcW#-}c^aOWgDO*zSc691KbqPb`nGt@{1%ZTbC*?Y|y=ySU4?Qd+p?>6xkX zw#hL>bg!-b^Y%D@n*0`)s56{u+tu^6R~cQh{`6_(bjAm>tM8v#d&XDSFV?bl$MeJI z6Y6WS<~;xLe*f3M3-mb{zRTa+U;6)A?{4#ZRZn$|xBUqFbNIadlZba;ZoFK1bLHc{ zboWS2e_g*w)z|m;ecvu~TF}XE@6VTaUfp@S^7eGU7^CFq9v!bmU#74Bx72r&R7o@udDbp@fx}N=j*=|PfImC_P_q$?)v!tb?5D7$x2E%a!mDF zy7fhr_ll>>?SE)8yx8^c{=bL&*RETywJON)^y3q@HD3%iNoMkI`@ekqKjFg$ZHa#l z%l}VI%uUQK22C~<&sdf{|L#8?#w_k_M<;De=FL1Veto~k(qLv=X8Vfo>^z5G?D|*# z_wj#IL*v3{MCaCmPjf6xG5fi{ z?*IOGXYN>DEN4=5;rRLNpn0dyBIP?DC!5zL-K+cm_WJ)^%}pxvC#eQz6>I@D4d*La zf!m%|IPVT8(1;`m9&ww$B&7Xq$I7 zopFKgjkG+@--j6lypN@XvN8A+sK_xk1UD}~!|Yb&9x=^y|LcgAv!b-7=a}6-H*3nn ze~AncF_BlcsEZ2jzO}pV({y{o_IJl+FY&pChWPUSK9uGw&@y4>-pb#Y~MVs zJyBv>qTqt`IeEnrCv$`t*3H?KwCrufG+WyWDF(A`^Ug>pwbWF8KRqet*TZc4k_g%3 zvXeNIWo~yd9*_>-e*JWT%=N4HRJDtY_S#Nd6`{q{aQmrQfBuap9ES~(IwctD=SbQl z-+Pj``*vcnit$OOoeT`K)}38{?z7DQ>FfWfI-Qu~_NDy(|K0I5|HY5b-3V&U|I4`` z32uQWel7WW#(q|OOyrjxwqh4I?b;VL?X>e>=Vx(!k0sgyMX#=T#=y{)c%tjfrX1JQ zUghIPYgD{am#$gSb%2{;!{nfoPmF@<9kiyO-nHdq;rmgY?IebQfhKr?bl7x$!-X$%Wu^pblbr#-FQw|FgcvW))` z-oy0~-D^&E*<7(#;b_wJ8GYj1x-(^MR=cBjJr8@< zXRRXabRx0*$)}wzMjM0UkLhfm=%HF=Rn2f<&vV0L|3At9-y|1XZW-hJ*I9pl_02zL zDloB^OE9&fjW}K5wfZ~m%N;Hy8c~M|N8jq0^O*xuj&2MwNUZ*( zF!y;yTVlP})8#A6KE@`0-eL1I>EF8}u{|5}Uc}%3bL&p1UcPu$&b1%C&ns4^+`VyU z#*Fy~Skk#~_V52I!LXq*bZ^n6-c>92|9TUCw5V`N`jR;D8OkYshBIc&i-?F(XmLrJ zcz)kc9)=Xxd$unfE^m$hcU=Gf+vfV+mG9H){r|6?9+!KdG`pUE8}otX+wJe(xTVl? zX5E=t-)C3OW@J$N5gz}?>*5r1y*-6@x;K|ObMSuWWj^rU?q{slv$w!Mm-nPE~@6-1EYxER~o^0&>*28q*xVe3p>D2?rwhP}+Q;=Y+Y~s@59^cE#BSG0F6#cm#~4l9;Fc*&)yKfzAr)I z*_Y1CViz~fyb%)-bK=>i_xt|o9X8-txIM1+_2>2W_d9a`d|v-wk|APR>Fzr>bH446 z=VLyw^I~zQPf}%a<=5@285BMxWiKdA&OV$Y7HznenSm!qz=`j^=C{b0eFgPD51+T6 zGiUCc$QcJEtY!W7U!U)xDpe5qP5r~6*U#hrzc}U|fB*llXNPCcTF1KAao%Im(3KL? zq;LFqb1i*mQr?>KH+N3#WLvZNV`a_zec#@tU$^`HH+}#1n9V1;?ug~x-j}i4?_A-X z+w1rB8s78D^Y!sp3F@4`=fCjmt7U68mToVpkGHG*dAt4ozsv6bQv`K3X>D)6r96A$ z+;c}ZpWgg3=GUc8@3`gPZ~A?`;@3N`EBB~cy88d$_W#Nq1w=w$X1tE*Uh{U%rwtv` z?wz~$Z{EL+3k};6_2%#YvtIts>#7plsh&Ugwr79(6uZ~tTab=q^u36G_WytWHz`h; z`|#Y=8>?J5)H5)g-jJr+*S%PL{k)y0jNYtHkNbO^|9_$FwskAIEEl(fGQu}^NSA-1 zfK%R`y$dsMy$+9ipYxuj;orP}HH!OpZk6ml9u*zMcpz_c{rk1=T^CL4ebILLrHrJ+ z&o8U}Bl~g>IOnuq{rK3tevedaZ1;N0HGPfi8vXNXm>BBQjt76fztgEtAc^mssq;lt|B zrC?yq)G2mRM% z2WXTe^nCtl!*C<#cK>n7HbeK4lO>zBE)6yRa`dUI(}{rp6L#K;54~EVrW?6ruKMlc z>3OMsm$&>o_ix@eIffI@HovToi4t+yf197d=J@Tk-<(!%*tj+En(v7xMzhvMs%A6m z-Mw;0qyRlWp!cgM%yd@?oItJ^&xE5rk!sty_$6X@$QOekIE#z=V$MF_W8#dQQL_TPiD`q zzu&{#J6GoBI-y4;R*Vl`&U#a)E*&j>F=dPGjeoCZz7;i0)4n{ReD|KbNWJ8y{d>MY zefR#?w};zpb8U~$eJ~?_*7>JJdt>+J@BK7w=hM~F@rFE??_J8Pt9<;fcj?uo-|toB zFMpNmsmJKRoc7d5*Kg|7PYKr(@}u<`rc5m|5qxS{zfbuJBZJsQr4LP!&zBy(pH$bq zNQ*=9h{?K7dY~~z^({PN6_9PMKY%T(_$G3Xp# z=X%X7N&2T#-GY1u=^xMT&R(^Q?+c$vf~tqw^qDm#Gqs<&Rl6HL=)B44bRyyU0?SGk z#gd{2PrlZ(Uw?o8PI-jvtaW$i?eXQfsVP*sChS_c*&^xGop)|u&6YT}_V;!HC-L)f zIVq)WRci9S&$=s%3*t1y*WKNJ%;3z@;OS*;yT7NsyE}U?JA?9F<=HEJix;1MXQX~q zX7&2~I$e%K*6a5Qe_-1-Df<4sztd80UOX6RY_|OF%(JQQ{qEG4TFpsIJ^S%wA;XKT z_f^+~=sM9g>)v2OR)+joBdoBI8%n!>W#lg$@*zQ}$am(9Dy zOkvyk_4Rf2um1hc-KTV!tb#H}-1 zCFecvul~ix@S^SC&$;KPFFw7#etz}b#2M|}{KZG_1YDo6GpsxH#&*4ZUss>6`?@>7 z?)%>9`_m`qcu!o~yOy{Avh(g00V1w}?JkhSpSbtusoDGgKlwf}Lq(|fO^!|Vr!|%) zP8@rSUQXq=`;}0YS5=jF>y9*E+xfY6*Bfpe`*rNu^=IkR($c1-ozWFLxaqP;y%+v!1)R(?NT z{O9WB@cQpx-`nl``0?B^W9Rf+O#Ywj_~mU){-1X@x4U(-;^~#Cmz|gQo0?6({PkS+ z`Pw9zMcIA>w-Ji*P34V zb?Jt;xmy08Pm|+kMN72(e0kfx^wu`%=^-lT`l??lz8&}SGn4;`t1w? zPEQObGTvCTZT`N`m#^N)(weN)QgQd*yK8xyx4oGBK)=2|-*nrqnYU6T%^vWUY%h^7 ziu(6%o2-BJMFxcj{D1zq+sEIJ@Lx8W=Wq+t!oF>Nv!?3kEPDFNJ6w0s(+%Re^CkGi zquqBrPQU;AW>t;tRA0`f3t~C9=iX&#&|bbi#QY#<6~B4FdP!y`miAq54*xx@w_IDQ zdzq2u?z8u9UX$c&n_s_&$LYEM{QT@(?`4x_#vDs5u85J_EOsVwp>xj4$CpleuWh_m zp*8Ph`W?P<|7`yQ!Yj%@yllL@ckN#5m;KJM+tVW^f4mp{o|m5|KQC9z+jaYC+Y81I z%665@e|R?4yxOYTOnCOuBtsF7tu0aWG&>d;6mTa^)-3-9iBJb zEG|EOTm1gJ?AP6Di;fmud|SX@!nfniy2l)#sj^?2TjcC!WR~%WxCWk|xXbzGs=cD_ zv*O>~%BcI9^8TEj(}`~j{(dyu#9UU-Tm66Q-}^}$Km6mrclZBt54Fh*3p7qKw%d9! zHpEN{zBpz3(d>b7Dz7``xg1QHCXZSQwV3tel}yRlQf|{+TxABDZr# zi|*y=r$1zH$ePZuV20MKRquE#r33aXkaO~|j1D`!YWGoIhMr>`tbz<)6NL^Qxs{ij zms1pS%xYWdEry2D4SS}uGpMdrVB_>#I5Rnr$t%pUfn_@bgOguEs2D>}N25xM&5E7Z z>v`P`l?_hxGc>$@BGAmhEW+r*@NlO8hn(xYTntPNmWz{Q85mA6a5C6C6rXN5#Sra( zD1vw0oBACZT?`LC|NLhE=KKD?C(<@6w+J-7{r~nazXA(G|Mr~wmK+D)y?y5W_RU>8 zh6Hu_&p&p5yHmP*|DFGBIgj3Y1&Vy#llkveeAl9Sja54<8rd71mR-1GaE5^;^E`v! z25y$gkJ2{o+&J};YFna2-FbcAi)u;Cr!9AOHVXP&*%USRuV4&Q*v4s>_g!8s$GawB z@0#Lmr*4@H@nY#wYhzRKcVJ&JBe0P{z`^*wKLdk7 z{l@|tYX>Qqx%f9WXUV`Xi5OUy5Oc^0z9h(7hO zoVfXCZjqnf5$+oqhbBaXe|b|C7GC1s-JJOS&!s0WeiK-BDx9vAe4KV<*{jwNMh=g@ zQ|`~#Oik5YGb`xo9Ip=##a7G6I(5WddFm@E@nG&$<$Axcghs}-D?>9{lW@PY7SY%>lz@RYWfsI;ZlS)g=-t$ic8#o#my)Ml8!_5}JP{Oe9 zm43fYgSZ2u2h)rDZ?DepWt_k?fzhVqttn_~weO$Y0*$Uk2eP(HtqMFLa;nuxy(mrk z+_3{Jueuaz{O`4Ud=tq zruY2R)0&x&cet(Fd4TO0n;Xxj%G@~-KX1zzo)Fq}!Z7k?(3B;IIL;`Zj+61tky2wz zv^aJxZ}p6CObi{aP2LxZW=*>+&@51W!$|u)AEOeR;tU18kAC}p)yFw8IWf8ju^cxn zVBn1tU&fkC9<(qm59-juWtH;#7)Yu#WlX<%|#8OHWx2lHhHfd<(F zuyOj##n73^1MfCQ=ZNi8(N0}D@%$gjw!#V-vDvM{J7#I06l|We)-U$j)H#bZqm+}A zS+70X)=@UGUNoz}M6mfy-R^ZSX04Hoa(=G7!AAR*>p>-jZQnemKa^M*YILeC>`KSA z4Khp&4B3g6(#JuwSaL6obd-0ntVwh>?YMa0gn)wFN2Pv?5dGj|96X$YO2R>TZ=yt5 zPP851@>n4)&A}kkz_&ntTgRKgqijqJyWhu4$1;R97&ZK=w~)Rhq0_*6fa}0zuEip* zfg-*IpemMup+Vr0>pbzw_Tv}dL}VRR`?%+ejox~9j*nvVw%bhKXxOp2@M@^RJoXO9 zH77PD8D}5A*2yE#K0&r|@6Cxvt^xPXYbf)tN#7+ta`uXV1vn*j;7boeVm}LSiU$rN+xU(OHuHuWI3nT zQYIVToVgr%-qgD3*T3%xo0UOHYgQwqiI&?Ua8{uzIXYT_MW(w#?5fUzjn-za>Q-%T zZ0!O<7DtQ=0&*5e9XW8}gp)XrlMVMB$K-gQ`i@1-_io7P^DuF*9qQ0!(6!1s6({SwfgiczFLYx1{s+ z^@8Tj9HH}O3=M{rTSEPwgf4y<>l(@S^Nmw|K+>z8w zgX?SC+*N()W?v_@N!Q#IU^u;?%>4GFgx62wi@0{mt8U_3ve4A6(ec1$10jXP>bp}n zyfm`$YR)q;G5EaeqYlrn1A*zwxD_`{Yi5l&tDmd5Pl7G?MFnuaH~GB3PH8ETJfF9Ur)fj;)QV*j&rc}jSvhIrj4Rz*FF$`2T`0&TU1_tE(}vqt zZo{V)^@$s2evUNzRAA4wSMJXH79MIX*;&EaxfvFeDXn!)Ub5Xn74J5&>-Z~PEv zo)U6H=g?hV3Eqaat0t{ze3-_viEE41f#l4LMF$T|2vn$_)VzjA{I)}dU$`SEY4SRO zo0j@kPA7b}%+P+lc&*v~#hkGMQ4U{j{ygbXXci@tz4@(Nx3H63-ib|KaqlMHxu(_= zYqj@JRn+Vo0n3t4MRZ39-cAZ~=J4CzrF6aJ=f|~vWx8wErtr)@u*K?ojLcO9^A|VlHo6d7N|2r0M%+SCm-g7+Bl39;C;@dx4 zjY-W{b-q+4p13~eM%A4UXSICPwI=Jg9PnZbN`3MD+KF0|Cf+8q3V~+#Obf|1J#QUl zjEv^wHWnBsy=LIJ`QRK|&+&&f+_9^j0!6+$EuQ=nROOVY){ClhN41CNc$FP~vYGpC zo%gC0Pg9e>e@hWu?)@WV_l+rU+E(5@yuErygkSg<+u--++!5DKdIV&6l^wqF?9m&g z&5EF;uYB_(CWaT^n;I2ot-m98ve~)8 z&i^u#aD>Herc~Z*->$u{zhbE3^ylp?5m$7Qm6fOpZh&6jMZqB^oz;V%ZsoO-J z7K=EWg5H+v$JVPnX-cwKs=j}AkZbId3HQrx+z*=-6ZBLmN#bDA<9ZhFuZ(TWvb;DM zK8k4{E^3e2DOgf4af{yTBb!!R910VRt~{1$d1Wz^Q%8_qM$yc~$cwKYR4n|(uye-M zkg1PZ12=7ysh=@DRpQC^jjtuwCRLm8$7x#}{aa_{e0{@0L!J0qJ?HSLNz)RPJj(7R ztu39~y(-3qqti_M^woXEIx<=H#Rkz!PyJTZZobd;XkY%yb(%K}EaDPwoO*1sR7d=C z!-1sI4@qy!%x)Nz_&Rc2wLWmFIl3uCvg+G2qfcC4DjIHo*S&hxNU`OqYuienT`Qk1 zQWF8#g^FTA|7g=$vI!BKxMlSvPBW*lE{L&CiQm1=g-O=VdURLy22ba?kE{*>Q{v9Jl!T zcpD0uSQqZyn7Bq{bK9~FO&YgiM61hZY}aNe*t0aP!cqE+y5jnV&z5hMT>?d1O_{(I z%H9_|%nW?*jwgEM=lRtA7CdIfV4!oo{#AX^j_eC}mahDC_k7(_&7z~*Bi4M|oc~Ak zxV*ue1j!bG7suv(+|bqN*gm&-Ud-(Hx(}=e*%T5i7k)pqd!57Yb8$`{e=atkc$3>? z$gn}?e)YTD@D-m8*6VEOa7ew+<$7GH`o>Se)t9%2FFPBo9Jggo%~y85^ONnS-MAoM z^K*8Mkz2iiBS&QHzRmgnmQ=OGOg?cfW0KPABf4+JXKRT+-}ftg=?v~~b6;BgJoPTN zHKgR^Z(9Xc7pl&{hYVt5E=c~2Ch3}vE@96HWPOAQrQ2WR`=S9PW zgwnn}AG`1FRP5<}dRu;(@@E$528r&wwtt@KzpB+>5i2@1Pq&3Zkv%0YYYo^l4YWz1{AgbHgA^zGhm?%%q6CFK_?*Zn6A+r0g~S%M&sJOdL1&u4P{T zXGhwpHy3;FKQq71knrSee8gSTsso!i1hPsFD}YARE1jo9`tVcz^ZoAssc#XGc_)+g z-u~prLvQBlD{=Fm-OF>hswsD0!Si?Z9A+C54;Wu@w#g|=uC4ocPo3v9TeTm{Zhr=+ z;_LsEg`?|=4%~Y4>k4n5cr^RD*57`@PS5uJjZG?jHgnyHhe^@%_UttIsH-1wi~anT zFMU$GzCHLHKb8CDT;^r@b(8M)+=$s%e{Lf8zi<1Tsy^So|M$Mv&JR8tuQu}5CjYwK zY5%AG^iCBslcw)IVWpvUC6CM7ma**eZ(%zxoV4c7@09PUXY$tR-1}pD(5>P_&4TAk z7Os5uajU-n+}FYHH@%!?Rsa2S^#0%TiwyH$NGVpktv;Gl^z1f2?`dK$Z?2EdD=vN3U4JX8rh)gY!IrzWjhx52xBr_EHGA5eeb+W> zm*sogZQNG$eex^uPW?Nl-NZL8Om@!B5YGn1wLdSotag>Xc4zN;)6jReg&S)hm^f+N zF|Bz2Io@4tdDQRvV**Yx`aE;1bH9K5c=hMn6N^rZ+dXOOPTy!)%+2xA?sMDnrR)qb z3(xI*z5nivy^py{XTA1CklD_kO$WlXLUFWzC(9u42b5<1Buj z;(s%bfgwV6UTbyyx%w*KhmxAv=9Tb7F*3 zLC!NXvoGt6^I3oU2{%nmGLw#un)_qZ^EZJG8ry*t01 zu1{IFae9^i{w9GW%e>T2X(|5>epvdxekS{rPcLuImXCh3ZejQPGxvV|$XI{-(p>)H zjj823rVA)bN3XgeJ@=;=N2YYO>V;w^1|DBu_h*|vE_FDs$zV`Yn*EXSG^g|We^Z{e zUO2F`UH%`x<$SHw?XP_6Dz%L7|1+F_FH72DuK%&(lNm?v^|ltarTXvr70&0+ApPrY zjoRM&opEQD$;@M5&{*nZv`NMC&hmRdHtu}!?ArVP>6+8SyjWL%=IENJbNAokg<84E z>s7*+Pq{Sjlv0-E{F@O8teH=G_orH%yKQIk_vU@|>&tHY?NN%7wQkounv?QL`sB;! zs?~b?YPRHSgN9Pm+s-`zwb%JrrQH-KvouV5Cup2npRm!AwR>&MiCLI{9={ z%66;0&!!c8H(*#|Hm%f`v7shQn89f-^P$J0yngi(3_{Y~#|8PFR+N5ux^ese&1Yp- z-EieNc{H4H!T0({)oGe73GX$#53kl%E$(AG7%}y8)76)+rC1qSW~?*LXLPXIR1mU} zH@4#S8|(cW-ozedU}$+zQX)1G{Ysd)dM?fm}8z3W(#o%K>w+mAo{#Ke$vW7@qy1r^Dg`*vG6?)V}8|LGlT z`};pL40xIaoZPQWxcM+&y7Kq?sJ8f3dg~Uh-n3Bj-nP27#|#czcGk!)cJOc&Q#LBS zdtu79jjOlVgBAyuDuCzc>$|K(ju=e38>*MWy>rU#`%DZG=FjIi>+Mb5XsOkAKc>2c zcX9TQEeR9%9ez2F>vYkcqsvaZZjG5BBgb&z$=f|`bNso*q!~))R^`5Yx7?fGj{obN z18suwGU99d63*Y)c>Eam90jRe%d)!;L@_Rya$jz;_EIMOh&6ip3{NgcOC-0|Co(wb zJz+>Vf8p>Lj`3!%4-T`n%l=_8cf`+LJBWarLF-t{;3(9^p?9&w01< zOI*$Vd!^dXg&Z~=UDd)xKq#PeV#9r}u2&88wCuv+X}sold;V?$mcsl;r)Ab3N{)i}+;i$@9J`mS^98cIn4LKhHoB z*S!Z`@YI7=Fuw{oW2(tuQ2t$eXUqkW%8w6yi{H6@4Y+e*>(!aR88oh#UYPOV&O$$i zi0TU8@KdvbqH2Hi?sTt=d3ESzey;2;h3A*GAIGotjk_GW^YamHzxvaox(+dY`1yZ+Z+FMK4!mnY`&- z{%>-nbGU)oj=j0T7LG>R)(i{>Bf?Yrgv zIURaN&T8LIr{6K#gUlEi#I8@yVO94^P_tW=a5!SmU-qWL^GCmDm94P6bz@T}FT(_x zcXM^cW^*%aik232KUaU}$A^dE|2J+l5PTu?!uogC-aIvb+33IJM|=uqd_P~7!>7+6 za=AZ!pTH)=(z(KGW7F?jy^Bl$uQFi=r{FHDHQ)YC{`n;=Df#EI_x~9Ubq*WsD@Zrm zcB;EtYLk$Yn0nreS(j{!?j@DhT;FUvciY41TrVriiogDo|6k8ge;|6zx`1%AeTTS| z7zBFc@BXydyYa=B?X6Y*NllOYk3G--qj#ft(d#R#kIUXZu+#k5{y(KPnN`K9eF-_` zzvuib&=WNFo~+PvY~3FFe@EBL-~C^e`6xQ)#k_)at8HBoVpruq$g{US6iC{z?%lnN z7gC2e_0Rur%yT?>4Rd8s?xmRey+P|E-vk=&u3K?x@-cOm2Rv=j^+ZOB-X%S2Hv4{Pk>&^3`N&$hd3w{@SGqL)m=U+MhSo*+Ko?dVP*r zkW#rj@#e+p_s*$3e)&U6J>pO9-ELuXh6CHSODxoyzRhf!PMG`k6Fb|E9*bVHc>RBq z?OW&hyRe>omicn#?thF7Gi)_a{|u>0o+!Swar*zJL`#MZJDVrZ|6i=N=|bhFsgLU{ za*8YU_kAya`6EhiXXZxhX4${n?f%@l^zIur{Z+wirzmiD$~ADyz1|h zjmxjr`{>n6GfXMUbn2+Ip87eH;e*Y(uw)4ncBU!HrZA^j)@^u@9Ct%KJl1;^|o^r!qVSmcHObExpm@(S=##-tL_+8T$6pp z)DUDAcy75x;HF(nA1WAG4|ArKF*8U^bM3eoD#^iCvPW2Tnp|DCz-7A%wF~$78KNh; zE}gOYhD@5~*&;>hNQvjHE3>~G`c^t`FFV7%Y3JPH92gP=k~dag39_@R-=6wHi9zFN zj$!>~&8WGzg-s;d#Fqx8dFwvcE#qf6BKD3+F)Y8s^4Uo>o#Wno<(AX^*66cXvokK3 zaPQKSNw@FcdaydA_pz&E(Tb-vijt*2ZZjzC-^s-gR-W)&BIiYaUfqOVy0at+)h?DR-`Gs6SEJavn(<@xLV>hHa=|6XUar&lwLSjrzjbGivU^R04ENoFY?-jq={~#h#|Jkv z$@h}govAm!y7PxFm3b$1$M&Ma{Cl?|W(lfBNB{41JLbmGr{AZ&G{*aXq)$P~J2Qrs zD*ss<>pk`44}bD9+->x4>H6f3gyihhsBqDfFS8FAO-M4E+M#o5X-)R~84EMLA75u! z_^){V?2Vma)mpovPA%mSi1!ZHoE%@}`>^`N6LVSh_~6q&e=PpZVYsef{Z9GhwPw#U)&3qJ^cLB%dmSDMO;__aR(rkt@#{$Vy}pGdDRH__Rl*PW6nt1z z`sMBaO}~FUwU(b|^zq*Ge}~FM_LhS85qg_|Mq*rLr>$SAec|5h4xRq`zl;nF3cF8V zuYPptU9y>+FVlp18@p?gyOmjXAKx^4^~@h$YTI}iI1J7FHLmQw+wHia{)Sup@7Jx- z^*5sC-HMrI!oT50?B3^6A9eOVKe9B*Ofq^-m#!Zp!{JR2-zDbnIDO}|LC*i1;mh~` zEvS5S`)OxBW5d(dd%@vz?p@eC=S#xYY5Q;N)qS{-d*e>)&)4g6^9r|r+14LtXkDVz z64j)B$CIaJp#*lfS?--~zd|2Y^s5~F_mx9)Q1 z`@LB!AaXk=u_-^dsLH&AoB){-QKBhUD5-EnNIHLABh{OAME{!hZbdeb&>wmnr@9zNks zyH0QBu>e8oZa(SRXP;XCKX<-sXNs9%vcxsfjIBHOoLP5Hd|tru*7yGxP4IjcWOy;D znEmz|zVi#?q!{e$*uNh+CL=R@`PTE#_==KJ-}YRaIDPM1=bb;e6mPuC-ny%Kw||4c z<=>ZnA1&E4;ZD5+&ugBt8FTfsj<+?g?BZ24;QO`k7Tb9?D>m&aeq$Z$s;Bx~E6<*J zW|brnzTxac&TBfsNgFNo_Wh6l_EL9K?cG)1jN2>xt^N03G^>i-@^eC|S3woA+t*`e^&q;p&XZow@k94<2Zxmw6Su1k3ar^BPPwU@H&q})+Eqpww zIHuygefp!^7CCpSE>(ZQ1tq_ZY9OddJhgBx8nvz)#y|ztsm;uwCRiw3(eh zMq=9L>ZWgd{cFn=S}Fn`xt{#><@_0Lt~7yyYWCM<6Md)h_B2|$*!%hk#QwWhb@`v5 z)1nk{)!pltzFx_s%<{=daMdObKf%=011$z$*=yz~T+Q)2Xt3t$)BDf040Y*|jTH}W{yw*XX9I_qR)x;*+WftH zB=jSgWdAny{hL)S=rrlB>dn}94;bICtZ#HQKCnxDDW?)UL%^j2JKxXIUFoOPv;D@O z*!ES|H~&Av8_Djpt$876v^v85@{>7>G`fCWP8E)1i10pnmN!{dk-6dauJi_>qD^dV zD`$L?jsLPD$ve}gT_y4SitR^FuCj{sdhN^Ob6h3TC@1M@!JgaAT~ce7%$AT^a(co< z#hCi9Hg*ZEOqY6K77-F z1H3l#N_Q`GQaAm1HPfXiuYG%`OlFyu{lKbhu0y1$g;?oN)&0%u?G{`d+v5cwd6d(x_DD>!uKa2@_4rn4kLmHW{~^Nly1 zuQ?unu<5`A{vE5TPbwZdY9`Tta4zqJ9c}B%6>c-v||Xz<4CG{?~@8H0%u=daO?&$ zFyzV^J`kBysT+LBWN#t=wY4@`rJQx`3I!|D+8R<|EE?FC0)k^pwwIs$v+! z(uo^4UPx{gW53a|YvWJVg6;_u6+_v0&GpQtG0x{^G84GD>#FCjyB8icR4`6Ty&z@5 ze@4k+x$vR-zQ2&w2QrY#oN-2}p5>KSg3%UF6 zD&leS6P(ldyzs_xqX#1V8s0ZWI2g}6o#0#eJm0E8GWq};S*fGr)lj0(=TUaEj?a)b9Q}T;bQ}ro(=b&G_Co1!{S<^&GP!!7kHgB zAFNrr{E^9xwso~tQgVNP{+$pc;u@&G?D?1VQlN=r=0BeBYRdM#*(#m;%OZ!}{7`-O%=D3==MQ)W~VepY_vt=D)S1-2DE#m+g zBU}%eu-)1#&=fi~Ln|{xmy^Mv!_nqE$D@D!D>)Ti^n`s?d9`gA8YI{{#g1^Z+c>F9 ztk!xF#hmQikvKs?;a$U0Lzd(Trx#@RYTsyJh~U!^O5*=z&1U8h$dKG{EY>_BQs78) zFxxJ+qMa8vezb{Dark}AjYGmJL(61?1aG|piw=8Jg~L>CCx=jn&;^b44Gc*R0{r0W zzRD2dI#vb;1HH9+D`!5l`TsmtE;^k*>2=8!gObX!LnqQ_3rBBoeIvEPT;hXVqTIx;bZ$Nxe2EoO15$~GBP+_xW|0Ws@~L$ zqw$B8OPJJjpZS|j{DI(mT z-dHHQym*nk<{I<7e0klR7c-}96RkJ(QqBAkQu^=ciPSA8xHiaKztq=qOzg~&8z)k~ zoYl~q-tz6;sXyF`6~)ZgraKBO-1~5&q}9!?L!WH)p3GRc@6`6532y^;rLb<_f3Z0z zw)u+K8vRCnp1As_$@M*nnPQhXKm0f#-Q;Gbs>a|Y`ABfaF80{J54gkR8VuLyJMQGr ztJl9F(;K_p$stf-D{Hs$g=@@{wrZKlrX6$CbM|JxF^BgrGmEgsQ$?}Hm%j~agmygN zC}IfOD+pVxqs$^M_MFFc<9EIfW$BNZAI!}=_fW@fmcHKk+tuwC)=iW?7!f%~k;Pj% zJu+K3%Dq5t|GRG|xhJ1`wC0BWrs{Pp^#>#RT?LMF+cLB3iCXflxxCif%vS8;L_ zd#c3)Q*K1C?iS|lS(p}5;Bb#2F1jV6WyhWqk8f{YAJX8%6cfj>-Q3QAfnmD%wdo35 zInAn{#&oXLSTgy-MdpRejyz+`7kG9|aT814{drgT6$SbmVw$e$73`QLFpKxVyOyi0 z9c$~I!~f6w!gb8Ro^=xsbMk`%b49c5;&bw5%x`JUl(6~vXPOSE?(LKRE9(H-LTj87 zssChYL3HpYX|;RLHf-7Uy0s}z>s_brmrr9N;0iJyD?xH-4V%=L;buUAh<(~DUb zu3n$=rmgeqFUi$sPo!yWn|zk{0NX1`(4=#HOO!QdvxiaKPUYE5EeZK<%Pt;z>rl|U zRc@v3hA71gx3(Ox;QQt7csZds`Fxpkdy?Foch6GHeVRDl+AcU1aN_OFI4uV|?%cU& zPv*^dqnGi%(TUHib=gseKoM74_7^;SU5i$T%Z7m;dziQw#~4JI>rQ+}!vv zOf5Prq~24cDKGr!y-8~%s#hx-@oefc_3HX$RxPQxIOfsYK6U-L6N>Zh+wXSdIC+|@ zdqU`%HEgS-E#{p*x$4;j9mnO1e^rOxy>aTPXl%Kc*!sK2u4twm+;u0aW^RU7$29fp zYbT`YT>7`#zT~jRNv`u7Cq-1wSoZp2h}+fD{=3g^OGobusb3el{z~TR7^wz9k}gD(g6sd{*CS|r(~!sT>z($bifTc(~=Y+=${zF5ob?tzUZ zyOyjl>y{|my`$=NyoFp&J)g$2)p}l%QMbO&XPPiww5K!l$B(YlU2VeFQQ`I zud++Lb2LP_yB=-yl3P7><@SF^pE0yJ=sABD+6pSBFJA<0N58_|pTOYo)m!nzs;b(e zv_$1oMrZEtsk@q3YjoyX$=}7+-<3Pxsy~ctfBbj)xoBPgV^`(x@0IsYFWW!s{>wkB zS5Lq3Dx}F$W%Uc*g|817FqBUJ@;tTv>Ew3fi$3SlxBp!}{oI?n$k6Ncwdpn!@6Qvu z^su=8{gV^t8fFSi(w%C*!+xfA{&#j>i#PA*ORl!mbJbyQVYoNBM4_$imHrR)mK3g| z_wVnTe&+e_=)>>hZMIkE8%_WJJ=^@$sj|#Vm-pUXKd)lbzo+x}{a6;WI_u^CkKymH zuTVc#UwGA5yJMMR_1#L<857plJT(8V#@$u4Zu8r(5C7e*p1y6;|HAr96>}0ROBZ~v zDgS-0vh?tdjXSD}UwYPF*xvTrzjVtry%Mc1m+RW*uh_24|D2StXWP_2Z_n=TTDG_N z*^`&|*4>@{<=~}L>HKPjiVO!fp5c$Px-ZT5ZcfzIul2v5)u*ZKjMWGiYMsBg=;r&P zD|W)C9ZPd=Fzm|<^Dyr@+56*o@Mne(i#I3#b*w+iI5X&HGyCO@G5Zd`{&(}}<=y2g zcl~Q`-~9RGTd6s5v%lu+&Dj+FYEJj#gO7I6lK!%Pd_Lb_j~koMc}$}NI>O^xU4PhVZ0*i&!6^S8nzk8Qv9 zs8{V0TfDK=)eCq^L8cv z`Sk2>&dNLDpZK@7yj#C!y{fUf{MtQ6TWpK8HD2Yv^P3{_wIn>c`}S6W+fg0)wPvQ@ zn>VY^vo$+>z&!1lT3A@9@A`YIGwN^Uue-0M{c7gEd1mv!zdkwh<5JP(SF4t-zism% z#ee#)Y@W!lD>uJ#l)D_Y2)+BGCM{7-$~?YdAV~8P1o6~R2%f*n0h3s4H<;TPqZJZ?>VYYdv ze!bcus-feeKsE_XF$oo zRqajAu(cMx`zI^UP+i;fyVkCM7oXgTsaYL&dRF}X*&!u=r#8y1_uaK~i<$WSB*`!T zPCiurY230%qwCjaXYk^!D|LD2&LsE5TU!1q$TW@DdV4Q)!qW(=-0czfs$bfiHgMc- zJ-PHE>cGxbuk~iXeL8WWvit;*)ThrDi_X@Fk$mwtt!`sdzRu*+(@x3F z{`z*K;zD6K?K86s-dLWMx>w<}Zru5+8xz?S8=u#ezI|ps`EtFoZ0@21%mvZfR?j}fl zdDnSx!Qp$)N{<(}x-8tWWvUbp`@FxqYV8a|HBPVZ)Xx8H{Y)Qsmk=>UgyGS@9dk$H!m%_6A?4F zU;P(z-D(Y+h}AKfQ*}?DOv*G6saUz3S@FuFqJQ7>^YWi@v8l;;gHu5W@0Jr9u7M(3 z=YMN>Z@;&!bjRYozr@=XWzEVfX=8fURNsAof7{l2MhBCxDL^Gag{p$0BEg~s9pRM*?zwWk6 z;fB8%TJcIPaq{)Aey`q~92edDNa`6+>vs2FXL}AfXgt__J0b_rDdKQ!~Z{=BW8)4F13O!%6@#c=NH_Zb^`w{MMNu?xOa=ghsyhoS1w?Q&(O z7q4C@Ft|+8jLEM$a9P0eUAnmce#0x_@7ry!%KiJf)Hv48|7+7Km->Ys48NKi8}70( z$Q+J&`JSzzWF?RL!RK54@8AFZ+0ldhX1S&aG-)qxuCIN%biwYj#-Mr0|1V$lem~bf zce6~b^+Ub+zyB9L{gaWsBCU^;vF87g3;gGLtg`0LN}jRbuKd&0gKx{{q)PN98ps^n z4Vv`)yK|8-=uDFpfAWKmD5v$4{BEj@+f)Oa1mw z7npQLoH0Rp?%&5hN&*92=W$!SS%&*PoBVT;PO;AJ;NyadPd3%x zRO$=~4AWZGE97J+Jzq!jl=orgOUCE54d=eiSsm^jda?AZ!5XIho0l;wrU!qVyUKg z#`8i-4|t3^X-oN2Vgl`&53vQ0 zVTpW|o#|^O`nKM)_xvQC!|U>vNhGYn}E}D>)Zc6{+b(MHedH--fcmjM>pCJe0JNo zrTT8mnkXlzS zykF#m&u;vfewll|-+6uYOZGO#Rcj9W6*GBzR!$N$FfcRN#&P?lM7zr0v#a(0e-6LC z-uL|78L=kHZ%{l54_=KLmm%lb=| zXX;Bpi~H*@K~lymYp(hob3XjIxa;H^J;ACwi-I2P;BIE#t9$$Od&xG=su-3NZbn~a z{l16Tm}xUinWFA|%4Oe%&9aIqX@+~sW=qaKP?#HM&fsEv^L^32<%yd+X03alw_%d@ zyU2j#Tc@6>O%GRfl*q`nd^f>|>G&s|=%A}zMu)Ldz1&Vj`G^7^V@_zfI`sSLOa`m$eiN68w1>7#bKnT^vJNjE-LNTh4#iz~pYhn0-O8bThPY??A@RiaZ&$(lNji$3qd zzsni%{5l@wWEiH#xgd|B$*pI=Y> z|M6jRHFx(j#+C^_3pp6XKHiXznY}jXS@P^>D^IU7+bqb;@c!{lRmJJT3}22fPWADy zncaNcn6+=}?KEYE?a$<9ZhY#s^y*m_h8yL&i3%+>*0$Z8mA~J3zWkv-y)#u}{@u2E z&Ye5ABpsWkGsWyPYvbdJY0L~)4S0IW#T^pl&+Fd2d;Ocm2bt%^H+Xx}ubG{>v1nyU zWN5kA+9jV_`QO`Ai1hMqX*>V*d&!U5c-uK)rM6GXWJBBUzCV+^mFYla@-P0*bB|LHg8s|Neb&2E&7%&pSsT2#NnJ|A*!&R5x+s@=Eq{GS!Y_xbac zZdrT8yt_-LVE3QA<&_Tg(XY?W{Mmk5Tj_kY>^Bdit=o2{PS>#xw(0Y~@$^Zg+N5)F z^W$G}|CC?j!r|b5VSBLimlXHcH94>UeX{DFa6PYDB?DeKSPdT9OahMU#x_j)?# z*17-DbFaVg_+MI48-wN5+k34iPSg~+F08r#@=ZybCbLED-(Mx1&oU}4SADegrc2-7 ziYz$>zb&nm(-;|6AK0yOI&9yMi%;%&czYZ_c6VyWn%8EI2FE`ff3;Ou`G4KtYuk;B z!vX_J|6XS2XH0leSS;x&^2|IbID4YcLX!*EgglqM)6wCSsjsd~*)UOjgWCGLx5Pi# z-tzkQ@!^@L`_{FdeUhc6Tom(u9oMW7(@^t&f8VvFJ>Xk!9jkLcCW@7TZK3hp+?dVj zPeJ+VygGD}pZ)Dmeue^_-{*E-mcO^pe7oGt=zfNV!&Ll{ zr=8LDTm9wN%gOcDzE*wxt`GkIdNlLC{fw#&Qk5H|7#kW6*Ofl-taR!>TUEK>_qj{A zw*FKt?)Kiar#NW`<7vq`VK09_KVMT-|7i9}$#vu5|^`nlIXW;kHzv;F?> ze)W z8zPTv_v^LnU!;4^I7y%?y~Lqzfo|SXvF$+&54LpJTNvM3A|+FABx*JJXws?(wuY@C zX}VJl%{Ot(&Bo2 zD6*V5_y6|I-R0JbEZ_cR|K5Kz>EU1bJ-h$=PxMh^bO_{oanWI2EfYhQRb)(L319EV zOLhDYLu1ujIAp>DHwBvaoGnoc*4XuC+k)FiH@@2B zQexA_uH@Hmc4{*;MoBylJX_PD)YU>MIXRi+O_0xBYBaI9>3GiNRrms05pcv z7F`%nDx0iSAQQZL;;P1t%cOMm*ajnhv3l(-B@7Hlt}!xfTeM*l z!{YRVS@-SDoE#ox?N{E_SlVOR_ONX4;~4^>>vNcT7o6)pp*mv^_uSfNx3~ZL=ARh9 zNQ0^2{PWxYH{AdKO?md&yniP*{@uU#KVu8SgOAhR+9wJ$-MzhC*?sr_|L6QS@8w=) zb?(hSA=~K1GN55W_POBmC%-Oo-owDqru2UPgB9j)o04ya?O%U2zIslBz#~h&7lrKn zQPYxEa0wjZsOHKwnlv>h)8+a%&jN*(Z=Gu|@4v6b(3l);yDqH%b;AuW)&z+o?<~2q zw@U8hN#OY^uV&06B)P9@cV*-+`SW%w?rDFrkzrHZF~dFP>A@54TAcb4>U&-tKW4PG z{RM}j=L7dB=il|o%g+}lWLRu%U6rrZ&C)9K<8VNI$gzz%XARAoC!9{R&3t|5x%6MZ z<@aCOJlK`Uvs5YMxLU^q@AvZ3=Qq{-y{W~q@Kv70vof)T8%|4>$x6&-T&lF=TU=Zl zV;k$vE%i;w|91xJ9Nxh6S%;m$%;9>y!<}fWBY)0lJ^d>z^ZWR*jnzTYx9v@w#Qt5V z4-QRHU};(WG6FQY`L}bC@E_1DY{?uI#lES@(l;#bSxx+XpiR$Rxg*u`_q>nNuRk(2 z?6Gj>d2GG!i?Q;oWk;_~R9Lw8vDGzk6}D?;VVno=f89D?G%Q7Ve(EZ=X&P7fW^qZ^ zul{}B!zym3h}QH2!J!hDUb2NY#w^QhWOT^lHW9rO8fn?iy-89-be5Qe;)Y!uySCZ7 zCb6GxRB%vZJsxwW)L!E7F)0Ct<<;lQW;0uenO&PDIeVdV3TuQ|4*S!7P$Sqr8$7Y~ zb&<2q^B2;FAv+E17f<)@|N?C!4_q8&>$gIj%#Pyk!6l4lBZZXwm2N^QS5797`$Lg;y1=A zvnNVV@;0z$d@97#bMWK!@1Vi?dFfxSgN|lpU88c-s_N9n-al_t4s%~P!BoeR9Gc2< z@z%w&QMp%tTjn=ptP+dWzPrEAh1;Mv>!&9JPj7vOmh#ObjTdLVF2CWx&1ewBS(+#G z(aCwW`71WVl4Dtqqi&sbb=$4j);P~`(>9h)3(vfXZ0B!ZH@#3=P#t*Q;p->Kgvb}K z+9Oyd&7R=LblPm)8&#zRFC7ea*a&2-Eu8;ZiD!P(RMv=j?O#(LSY$+$GW$4$GBC14 zFWkEN7-JJheQxXq(bf}28)6>YaWF8jn21L3{ZTBq9yLql=E7^RSQ1W7F>gHF*tnqQL#PzblR61KIz`s{RcM4q?dovE8m+X*pb*WjnD4N zGWEw6^AGdJtUmO?=J`iszw*6ObsdR60;J#bzrJZQrM_FjJj;%W=?LeV(`P-l?P}j3 z^GZ(P?cEKc>Q9+W^vqgZIR7Z7th~Rk<>`X8+$O9>nHNG1^hUWKRw#%%@RoJkzx(w% zVG>rXOPN$2FUU;W`k*bwoGoYV1MYX?v(GYySx@PnaK34sxsJ&Li480VU*6JR{fM{W zIQvbLl;8^|Je_sw+5Px;>}`0lCIxg%FJxugaRH~M+sZp^&;JW@mzO^Lp>f*Z+tDVx zr;Fn38~)#ne|bW&uYKCL=Ua|4={qU>d81#fv*z1h?=&-Br}Kq5JUePlwPpu^M$H$4 zXXmbTXM1NlJ?(IwbmH@Go3Kl>!a_^xdl;33K+~hD^=1zu{>({>k_cn@SJ~SuDDZjD zF*VD1e_b`Y7HPcVfQ-9$zh3R~d6%oq5hX9sEUU{Y^Yzh3_DQt39Q^%eeX&f$1D3A^ zd-J9JCN!;iYw5cpQpfDd1}g=B>FDYWHx;jZ{p02qDB>y$Z6s|Ibn<$-DMnAacTMp@ zgZfD-k!!F0buVn0khF1y7FS-v{orYdDyu_9j{Z$PEHT|n)%UW;;a4#X8)VcyCn?An z#4{(yXo;1^=11(0NI90awTS)eW&@tZIrnmStNjHZS@=y-dA7i4*RExno9^sbq{Yx6 zaK5nV=%)Id7J=C7rlGkhIUI_8k6W7UI9dc^FPGH&W~USXOjG9S4)`i)(IQy7!Ks zC2QU+fl2kA%NJkNU@%eL_N|Yv{czytD-w@GlqUMA%o375Uik1^S+~kno2`iwD^oU2 zIB%|M<|xp#P#|1=YQl>utC>^0m$DsC+qY26^V5&NJf|<2u)79c;qC*cB8>~BwKX*{ zm$&TOXV-rDq)Ay#(23{b)2GSVR22OBk{P%rCnHKnB&~kga>=%r@-kCi@%-u2H1hGV zntLxIUVo~Wy5GDt=aiRBI{9>}XrREaU%y-eb5fd`1t$5ZJo;F%F+xU0W=+K#e~z0y zN6nHAFD7MXWiYSx`wU2E3-IGnhB`KD|7$1JvO zT)1l0>9^Z%O6|&PWyn}H%S+8%X<~wfj_1_V#|@6nzNlfwGyQz|gP!HeeZ2yqp_^A; zNi&gJGx-g8?>S^)!`DTJCH!q_R!AQ^DXcEzm;RV}!|k_ayZ_cdeDdVUl`AiUmzVJe z@*J+%vf+TinHM)^xMn$p^6kF+uE;7qJx%P{bM|k~1WRJ$`(0E#rDSAm3M`KmZn&9a zw!5~n(o(8-+t#gb?=98vN-Dnmu%ztkH?yZRx1G)FcU?UDVuso5wGykvxmsh)UVr}S z^zhl1fQ`4`zJC4sWyqa${z(cZavR&&nX zm1lACNXquUyrsa~+w}}@m#>Ixx9YBq6Yt#0%FVz3*HNKGCCRX9qrHrn?zCga)jAd_ zaCAoKNcOWwMZHh~&wk!4jtc4qod`Z7X=B8R=eu|BnlG1dWn5gbfEZP;LyLRo)oUqWVcW-aswv8uNUP>wpv_bf5m26qH+T@it=5-u5 zRFu7Y*H`8ZtFz*?)U#XVcBfv-Y)fQ1m=@NUlbfsBvgGp1uD7i<_mVbR+yj0r~b;P{SeyrIUV`i|eBk8P9OXTBvXLBBg z4c9o&=WS2!DfMlRb>5Lc3ue>SQ_VGuJD0AuOw*@<6eow!oGrj)wtaaXE-0|s!zWV|k`rpr->m92%eRX$q zkxuqnFD?U~C>;vsP8Ty25+2HqzkOHLK7N-oqNxyiEPQI8HwQJTvE7+UA`x zdh5>ZKD=p->m;wAHY`lm(uT)w81VUge)_r6r{iwg>YvwEuZo(M8Yr;py_@f4vqgci z*JJgj*I$3U^7}gjozsPL7HRChefZTZHU{=f3$nahHzu+;a{0mx)@`+HbDkDeKD@X%#ptBL znWNm|T44{Q+a`LbiHnJu_`ZJm?%k_bxAvOPKI>QS=eKHBTHVV63paPStTZKwHb;)o zFKriinGJca$QL~O{PX3^nK5?x+i%D3Dp>d^wKTThZE-O-cguv07cWkW%2q0g-Cz5C zoz7{7g0G)aS6-8t^wh%1!GI|2IVnqi$~Y3BDU>YZzB*7+^Jd_QJ? z+}|d<`R}J{hp&2X-uHObZq~$}oxdU#Lqp|t_5A$&nGZ~z9-o(+xza*mrq|uQ<@&Qv zvobYakFQ*+^k(+<{PazcpS>Lg^kVl&teNbSDCu_7I`%}4$>#IzA=93I?Cdzx>_8ZP%`GKRDIX5=+MyjwiOf3 zKmT4o_vA{=$Y~e-vL`K0kT`bbONoip+Uuu{XP>>dyZ-)}RUyXf%M2t+cE(ss?{yCm zb-MiZ_xJbtdAV1mx$;~V3-ilo^%n<;D%DF%2VcIdb9$a-sh7af&UXIruy8>q^<&58 z*_wrh=HJ;fbIq(TiApUxIyz_0oxi?EI@j#>i+eu4X0v;9atho-N;d^))O>!s{cE0j z&&MB!+r3YpHhu5rbYlAb8s*bP>F&p0obb>Q+ih?6@9fvt`FlUMRbP+(GuQR;$Ncs2 z>(6xB)GvGe>umJ)YuB!4?|Zy5Q0_Kd15bb`lqI`YXV)br<|RISwl?~H{r9_blh@tf5vVuaf4;@V zYuCyie|tOiYAD-6ZT?ohv9#q(*=&U+jFuRO77&#rB0+i#wmV-;Fl_27nxI^Uq^$?%91u(w;x#iIta>`}Vf> zQr@K!S%#=X5BJ@>H@Cjt#(m0zh}hV>cWz~6XG=>+tf)Nj=a0?t!u0cVR_;@icszBg zXv>A8+~QGDQ8jVzpL$P^ijEHTT|GUmN{e4z-S}ose187-dzB7qp`p*^Z8zP{nXVtZ zYM=Dlu-6X`95`ohd-v|kl39)!B`Hrl*beinshxWIsnhCngVD`5i;udlzg}Pc^3l;( zu3|5J+@_`OK3n$ij^*yN*Y008H!)~1TsQqx<*V0bhK!+~8_L$KUB7@u;W#zd3=UcVISsXi#K6WqK4BnVE z4P5DIWZ5rF*sywacjAnvQ>VV#Yjb?Ag!JdCy{{*Fe2r^A{PEP))z83l*nz%cUNyZXLz6Y^d{%#=DTN@zQ=v5{;QthC|ehs-k*;Mw=}*=(KDv$W@F708r7{PXkPJh|et z7xP*sB&}p&Xl`zPwtP~e#QgjFr+TDpip*d8=Jw@RZ(mteK4Lj+@csC4?XpOnY327S zlGUwGDx~PS-QHP$Re2%@!4b@u2QcrCYr%D9ikQd2hS0 zySw}G#+zKemls{kh@56TvuD*R=D&a4Cp{2w-I#v=1{*uux0~J^Gvgyph;u1BJ6{Ui zp7F85<~KiI`LW5SGrbL_O`GWa*TDa{{651di{#J9Es%5FMst$ zZ{KuN=h%$rKO64Xzk732d1v15^V=R&)>UM@Ffiv=Oerf9V_4-~QIo#hZ_bV9SNxV= zepzzO`as_H`S#V{4jwsje17e-!rk3VgVZL!eDh+(xa<&CkI zL=;mtN11baE(>xmeF+{-F*X73`FWfE|KpQHx7o9nt#w!0wJy1*Hg0{u^7P{u*~%U; z9!)A#mMYyHlbf5%yDx)XF5y~AXz14U>-$q@oH*vDG;_|pnUN_v&W88G}O0nX_k~a<^`~c5U&jeII)^Dz>P2Zi-ra zGbe0X>R|&H#~aHPJq{;1bCi~q>FMg*OUNIWu%3JFt4B(4u`olHpR47k8$K-)GIYv5 zf6MJl_3!C>mviP>5re|pS6xX{RTwy02Dy6OU6G;rnPrl_^ydhu)xYuB!QIdkTn zBS%h8*OR^4)croEF!Q8A&#bL-v(CN#$iv6CZR@sKca@@|qwW7ane3qwv_8`F@CTcI z0i~8bMPFC#+_Yfx;>Z2+wIaPoO?<641ZE^_bZy$P=S=aP*3Zx9PY#;W2`=pG85_LC z^~<(wfByOB`Tf6Mo!eW@cI@xoy=QxMAAH~c<&yXHb+NN6eq6Y7>HhWYA6`tnaiBbS z+SB#xW0hO>{Js`#o$4asBsX1qqSw^ZPv;)fURor{(6_`0vfsWF+!0*ycv0r8b*~p` z%<^CLw{HLS*S;!3H)GzdsA{S)Um8@OS)9$ya7{^YbCt)&2$qJEFJBgDT&d$Jwwl*< z`Q?_|Z>?=JBBzyF&ApkkEkZ{w*YL{nRso~Mw`NuyFz7j(cKT`2CLMcq&c3NvLtO)_ zcI}!s`3)O`%i=%=30cXP8TsrC?S~70E}g#b$FJ8FHut`;urriw+4}cIyZsqZ3-e`3 z{knB)7#gy}*I!GX>b2bd_apAR2J2#Wg>2lQEy1G}q`CR69z%jt*HI;>6XhaD9l>eP zdrLQX2YZa1uHL;JmBw=Y@4qas@w+82;N;>cz`Ah4{WP{Pt*KM2)<#QbW@WwFeBR!F z`Q>NRXDyp~*K_tf#{`LENgE~F7HV|uJX)XA!pLym^WyQMoi@hSr;U8#>+3fsS00MF zwK)6MId(_$p1E(&Zr!q{=IyVqE=H0(Y=;+4a1{v;3zuxm^x+Dc_Vl%R-ib|rF12#s z4YkzVoOpKeQP&@pvaAAI4@t1VdB8@I9y}h=!8zbIae6(ndMwqA9 z(xCd8K5h?w&Rx}bHfd{={@yQ_-szUVzpE|Mo$fbx)lJ^*2mdr4a5J&8v%7cw{`rk> zPMzX9wqxs3SDQtjRPWEcdHl)2A3w~mub+L_M@&qN=Ws@LuI(qMwfD~+I>e-yQju~b zZ?mcOH1$IZFDyQKwDqX#U4vWE(Z)C5ytyNzs3O5*W^Gc>!NO#ofA?00o4dQ)p1AjC z-sD(K{Jy)#X}V6jHmqIuDf9A(?PeC9WOjzbqNT=?|q)2YW|o6C0BE`OOUob1LC zdZx|bddv*oNa=d1=(QY&7Y3|cpI@1pT2yqYM^}cgzpqd3_^j^c_`>U+f=+L9bHSYn z<;^L~PAgV#{_L@8zFlaDDgOnNTwNhS*NZWnpZ;WUw(H05GO@JXyJb&~+5N2%I?0O{ zH=mu67F781joIy`-Qw@>?cX2VtSrN|_s^%(ygw#rt;+KAJyb7o{><68Ip6K_oQ^1z zeEjos_V#@LvuAwHo|&=zzV~_GOi@rpUXk>#M7;dN~#zY;0`&_b`9bZ@k-X6<6(1{R&Ngo zyeU4g`~9Bay%V4R++XqD)+W(yT5)CUWj`M$4to^-q`?s67uig69J^$~Ts_Jquu$p`BS&`lR^B;FC zN;frb==#n3_SV*Z`91&Zj*7M4{r7qPzmos&x!RrVEB^m=F^bfhzW4WeZNp?{P*AqI zfeTuFtKxvF*M) z&qu}JnETZ?o0*(W)CMecck;ESk9J^U^Yt!oE%RMJ8 zsj-viX`S^$MlLx~oG2%?t*03oD zIM|w7CM-RAl=-=r%>1N{GtSmOU6noS$Kgch>x(CzXgq(l-(PKRn8?xKs~-+MEn2y1 zSFqDo&28JZ@f=>!cQ$SF)b682E3d3MzyTWcQe3iVKF8_8MG8-fE!S4cvm7=sOEzR% z*yXcAp-boZ)5|Z_uKAdj*v|IaC{ym^DF$-3KPz|*?A{j^eb%+Vwk*>4UjP37`R7Hw z{0ky9?$m#9nD}(Ex?jkdNe?RbZC}4WLc_<`@6_27`W#pT*HuAeoJlP{a{PL$ZS?zU{-x^?SjdFLE@XmHx#Vnj|-Qq%Jt zZAaZ0K=&9Qep*yoQWCQMz9Yxh@)C}w4Wj-2zCH!LbGPS9u$l4npTB@5ojd)LxqjrbnV$^pKXf#yFhA!dq-;I^2;yF zcE7IYRTFgj=WyWl=cSilCM`@b`7qP|e4*a<+j-lsOK&jb5$0-VKA2!NS8w`h_G{;C zv^W&|p5N7*9KxdNFJ3qF);$RXlTYr=~_ue(F}|5!v?8^`esJmaU)$04t=Td7B{d%%GKR zw&?8h&p-dHIm@>sFXwFEBD227HSD3xxnlF4&%b?xCGd;w^s6#wY&s%BcYUpF5SXNr z`Jc@YbpNPG=^F5W|Er^|d(OWPaM@;(_w>+Zp(W1?UvM+9F?W5KV|QH4l8^iR%llSd zG83L}Eor`e%4U19@Fl0m%c^YGCTwN~9cwh}k>%gjY@oeC3_d@0{5oW}yXnf7YbxxU zY}cP(QQ9VQ^m)k{&5bsK^DZ9=n0MV|Tjtv|zJ$bj$uD!#;>}cd-c-C&x{EV33AD5R z8RR(GENMlRcs;QxlP=znk}(S`^7!_*TP>-_xM<&sY0@#xhc$1#J;ZqWH*ZgI(Z)5} zysL{DISP56Z;4R-*D$5Av3JTOeQB@9uVNU4BJL?$xqNFlwM^<-ahB)ds>eyr9toAx z6H+fS)_-n3)i%qpODgXUJEP(TqeZi~Zu}i)rrL7CMO&)NQA%98S%Ujf?wZv9{F;nG z2Z|astTGdL`HtL}_##1vW8URTJrUQy5M}T@kq9e8z=ZDZ*%SA~BuH*s$ScKhabx24 z8&%A?W!-D7raEwVPA}#@xph(4Gf6%v^B%<+0?iWjaVKv+f4zmZMJrO6|FR0mnxAE(IQp3Kl8|ghPM-)81F?In@O$? zG@WdIibr8tWBubwrUV8tf$LgTGCpr>;u%kSR~h-A(lO}m;bk^txIJ-c`{&yef85b~ z4jRFdY6dr{H7@Yh7S%Q~^lbZTts32YK5l}yv9$N(iSFsU+m5c%vj;+1|O2&7Uh^qgnL58T$De5wEwf zXeqPriMV&=V21FXy!v$)<%2|DYoEHdY0uSMPK%qT?%7&N1m9v~lz18~v*IH6jxLvZ z7n6c-9g|$>+|pL&vJBM3GY99quZxTg>NZ%NHhL3Ly^}=R~C0IO(bX5@7Pzc zt9ZuktA~P(zq~x_+PQg7o}`H7!jBubTKwhfe(P9LresyWtF+*IeMXGw7LUBss<+sg zWpk33d(5~M<2XBEuJ@XCsgLi@n|60MSCnO(U#sf-1*`XdJijHf!7;qOcd}T~#0tyH zNnhXHn;ppI8k@KE=b`HD<{DToHm_RP%laEU>B745uH>oJu94y8`S;H(H&A4*_dS(2BSviY z>7>)|_GT~$XsQYADV}{P6ZANBm zGtyP{-)Dp+=p?Z%4P)A{@XgLVD?_igM-Sinp3Iw3ailD|iOq0RRp$3^OcPTVm2Lpf ztBAF|f40ZyBG;3jYpcCLTh{9t=7Ku(Ul#?Jh%)3nViZ2jebYwq$g?fR)#1(w%;~`| zW2~|_-?nwsKYjJz*&w}XCBBn$%=*^XHiT|aXgM|O(aqYRr5YP*&PoYeb0{9onU^SW zGBEPc;S0TY!nEd}v#iMrKX5qYYV(Bm^3Mi*20Ocxu1b|M|Wq zW(()Ezo(;L%nCa-y`pjYo6ya_LUko?Ydzz-H{t%%;>D|OghZaqSz6*-&b}wi{jDk| zhvN1p5fhU|Z(sI0sC(=C`8_LABXu?RsC0#SU)59HyK$xFEbBL$E9aQ%b1N>Haf*>a zyC7)o2Z+mCE^UzNpr+q8kS$oj%4nb$hDeTyOVn z5%a!p`KcTF-hv@zQD=^c<_(>9V*8IKuB}w+OO#zRkJ>PDsyD(ou4 zvJ7ipG`w+3)OKdbiBmuP?k}^8`KFC2X45wPo-=QoLiE=($yxJy)tpkTPoBsHW^>o4CPfpZmSr@;Z7j&y`k+x-ya`^ekxwoAQn?63v`f~BE=9>KS z#UHk@{L-Iu!}i0SGFN<{85U#*>W+r$6<(T#VjuP+x9&-Z^@Bl#xx_5PAgR=T3I>*MGCFJoe; zkzKgaT>qMl;Q0+~A!b($IG(*S=ej6Tnp^hq;$KN;^JDAgyp?!&_hu_^^0#Y;r>xHH@C|^IP4Qi&6}GK3#slyV>8a`Dx9^f6L7$O?(?% z%vAqu?R00`+-JwLzCHW#>rK&D?tOp4^MBr6yp=a-RX*MQ?-y&jXj|P8^zjxkk zGSBh2`d{boPml4xl-Qb5_KDxT>*U*&CVN~hK28s}$@Tx&abrfztly9Bool}$SHQow z@SNngu>Ug?{uwqttjzuH4Jtrbe8K0%|Bjp+UG=44*)u)o>+1XVM(a(hI^GslZFNmN zeA@D7;%dwE_m!4DpOItq`N8bjZFOICbvci9^QSGY|Ez8LebuH<4<5f}xKRJFWxw*D z7w?{2^D23H@XU?X&(AV@?R>QO_T-LK|GmY5TRM!dzhAy6dgIZp=QjRJ?>~Ft>&N_e zDsudq+Ea>JKd#SbJ}~pT{?3|tyXVLIAKmusy>EYy4?1{Gdqq=&G6rn?X|Q);3%I_snYjNZD^)v8xtk zt$M}#b9Y-+W#jud@5OYI3};_A&3!)O>QC1r28W;fw^`rrGc#DaCP&Zxj^h25+x0$9 zJ5~Sk)aw_l6xxmPE^4Q*<(qx_ zz3tCetPCe|>>`wciK@42)*Hv{HQy=4-0<(T zy6ftrw*|B8FS;Al>!ofpHvQ?6mR;C9{m8}bdLP6NUY4@>JU#sOu_{ixSufeR%hg<0 zKRxt&eU;O{S9^E5xNVAV*PAP(vN3nV>Dy8hx>J|#vE6*~w$vM$xA%V@zbvGa^2u!a z;g`koo;edcS*s7!zFVGuYtPh~YFpQ2q#nI3`fiuOnQo`+KNAn8X{v0l-?eG3YnPv{ zu+Jgqx%bu?sDHAZer%1LyJhqdwz^l~jauT&;3k6W+vR)Lzy5#!Uj6aorE|+4{VzVZ zHuz$->cM-io*~n9cAn^asx;lAa86Fna;wg{yY?Tsx8-l1(DFBGg_F)&mEC!?9_x+4)moFMJ{HWZYBe)~?++GQuXLZjkpPOviT5xXj z?oNqig+JCsPns((RQkGSSk`vEf_)^ zzukJZY}ck&T+_>!1=wHYZ`HQ3+;QNWbM-d)Ta)kDnaC` z>R{izH(PzHZ@nttvco&gEn-5Svr9~%#?#~WrY2_Bj6?P=UASrIw%1pVie`p3Ex%HJ z_;$Yj>UBFR{^WeS738x(f4ksiaewJ^jWah(uO}+DtWHs5nNw+X_Ft9{Uyo4W;d^UcOiV4*WD+Z4 zZ|7Ma_;HGdG5YqkJx>qtxdyJAb0RRO^sx22ggKdQZZ1X_&D^rqz4JRHxO{$HsKvQ? zx7VNEc~Hni_RhWff&}UCqLM_zJI}t#?{PQXva?&Q({NdavG<*)aY;Hxq9T0{xcXa_ z{O*MDuI+Gs&ctxQs=a}kfq^UY&b3+Z%bK*ij@yS{Gqf_0=|86RIy-24{;B=HjWXNf zwy&LO=(f}DY^Z6d?#%4y|4a3hR^7fgDW@k-s>;i~?OpNorBj~r)?eKs^hb25>eSSq z*QE4}CD(8$>dDwUyI8NkKfiFHTALgD?%&PAmoE!XmfOEQv-)+{mbIIft~=m=n$NTHayk3^)}-AYn)>qA>PvI%Hq^S_nw)idpDgRGXPR@RZy1U7ZQEZosUs_R zSA`3cqEgjUcmMX~%|RZn!L!Tix4fJ6_Qz(Qv)4tlW?L`Ko%r&?fuE~mLidOoKaM@t zB&byM=-Wp2d0r(&fhJq)zE9gW`}k0}zJu%*= z-_M7yKiuS6i1~Vl<1<^1Ip6-guVF>k@}zZZl79r{+X$__b!)ca2R^h4r-%4v-`$$KargST z!$P^zFJ8Rcf92_?U9XFK6BS$c)GVqkD%i4S+on}3%M_2ttlY+_Xyv!HpT9TkO6c|6 z%rgnH?|lv;90P_vUT>_nIr`NcvtblsR6Ob9!Cgy4#hH|5d15D|{65 z{3hS!*Lin$Gew?Zx-G`r;&1&#V37 zKTY|aU2d{I@^<|(cDJ~{7mZ^=%kCFxRCn-dy8PB&zCsMxfDB8Y#Ps;b)`u6awgrlt6)~^0r z6#hGP`}xiPx4qtMo^j{itsQ%(cIe62U#@-VRiIVyBzOCI-@<(Yj}Cb+ceDC!`}AL~ z`?F^eg*vT9Ozh*bXFDBk*5rtWs`)LzS`J&mXLCf7QvhCaQz zR@)}#+@4(SUjO;^uPnlUKKy?7<=R==wXf>_9-2D+e1(=b-`?MRca!}}`1gK1ar&)) zz0B9^p)>AHm5gF#U@(*9G2&uiIBjHWSNUjXxXkgJ#g85RJM(|C$2ca}9u|+cJSuU& z_IBybmu!N(B_;8;r3Ygl-L8FInms44Bz{NH(=)7x-&)mtKP&lpznjy;0)-iK{*?Y+ zc(-enPrt8=lXi^Z#Pzx1{oDJ?zD>UtCR6o$?aKPY9e%w1$DJlts8sz@Uq7ej%hBTV zGUYkdSs8zhDC@Ho^_p#x%C-Ld=VRx?jlZ@%V=ljYB6wLz>XB8mUunI5ZY8;L*Rt7d zqT6NCpQ?X6d2`!lf0uEywI4aegPW7r*T2tv*|9f&|4n1-mpp==idON~?k>CE z?>zWnmqc>vS<|bxrDRXbS>50Iq@9_e;VdsBI|GAGY=+g1x;I;rt#_}t4~PukyN>NY zx1UdZ-Cvo_ zCX;LO^37@WxL+SH2PYc`?{YbO@rcdtIctx`zny11{r9c)zqGu|?-p7twq^(yiFaLj z`gv;4MwjQzo<};2&t+V#|8l7C+`b>b64K*Slh3}J&7ZbKSFYFg`(F3>suw3KOr}K` z8JdW7yP3v%pLGoDl-+!<;!FM0lm90EvW=d_pLd?)^q;Fwdp5raF_@X*!`sJw+b}Gn zZTcalgC8!o&*%1KExTW|qVV~&IpN7WR@WyLY}vCet5KI_wBxd zsU54Nvcj^CU1n<2`(8HB!r!H5V_*1v51kO+`rOyN)uFz+t5@q(KYx3&SGn=RYx}Bw zTb3ogziYm(>~P16Q!l&sidzfkT7N$D@rYA=Kyx5zvlnPx#sV< z{n*y+E1cL7^(`m5`PQ7%>*qH7Rs)F6_Jz}nOyq!ovzE1wHldsu3szO_4o+? zy!%Cm->qC&zp?R~pVF$E*S4@-fBR&zzJG6z@Wmq!UVL?|=+Um|<8qbr zIL)0FF+Tk~OOgux*TX`B0|7SYo$mSj|CI*UHv^L87v_Wv2s-3=G^;ehThQzP&9~c;b|zCG`gNJNInbw~V9LJ3rP& z#d} z_KvTf(xSH9wLKqKr|Xx_+w0=8YMtrZ8=Kxfc-LzGph;@#M}0v-U%o!IeKVxw{PnKf zeKzei%i1$r7J8f88O-^Sv?RU$-O040YoABlUDbr*~og; z7#5`FB|X@*>r_hmyvEaaojQ)iM*oRy_0!g0+Uj>_Q?i(#r=q*wch%|PxwAdvr1Cf&5X#D8=eJ|>V&aq?1IyA((Men^ixcR)$#f*eU zhYnnAKD&F*ve{kgGTn3D*xir184w@l>*6?FVNreG#&-`N9O>_rj4h) zBTmlh`SrWir=z+nE_S@|N=Q&JDT{t`C{qH&$?-)%^Rb>x|f}qB{%oMoZqWY@0eun zTdjN})${p=d~Lz2vzE^JxS}Jzi)YJ>(7L5F_Ahbj>Ym8BKFLICs*A~+E}@GPjB9Vo z*)1@w`kD3hb65M~j{!$wWjYjY!$UzR-Y*05)v2~Sh3l? z?#qtjk5f_?yzwAnjN{iUsq@+TS-0XNpI0nU8XM5 ze=A9peM3p*oqIv?jl0D)pQhBSBxuZ(&zLTG?_|V<$g|tddV3g($bHY6c{l6MDoa6b zj-645H8fTQ#f67j+$~r#qmO-WR@!Z!b^Vc-TZ7L%4d7k7XW_0b>oz&;O5|35;BqP? z|CXoV^CQiEIscAF_-+%Kwk6i)?er@tT7s>qHDBez%V*zPwdv5^bS07LD#E>t4D}7! zVoZDt4cT*V7tEY>)7VU))4ls@TZYXw(_86TZRh8f#fLxCx+wbg&4;Hm_I7ReZ)JTv zao>Rr=ReF?HE-9RTjA# zV}4>MBg48CI=3|XkKXxD{W~=dX8fr6AL{vO*R)tI|KBOm!B_5H zjrQk{tJqur|IfZxxq5daP6y?9nh4F=VR3DxQEC0#Z#|wqC9c^Y!b^Sm=E?5bwRcfq zxM|einJz)m<`NRGXG)oc?p>);tiiti*{Z^+-`m}l{c^%HHy;a2&zWe$a&mQJW8;S% z(WO^YS~-^Py1sbU--R1HWb?m-tvh?gz_YKwirLvwJ1FnRp8BX~XA33=T1w5&>;Gcb zd5Udu67RA$Pf_t}tseCkI!&ZQt^8M?O6)P6JyqQ4@AO5?yj7JecU{}Rq%g7ksN17U zd8Vtcd|5vE(2u&kAHPOi&s<%;JnV6DwxOxdstG;wwzH{TRNU(sd3(7qD2O;L7#JEt zT<_lA@%B`~{hj;xTD9wIc&kgiHFFa* z?9bPChCcRM@PF&W&z92rt7H^aI^Fz3S8q47-v6K{S36gNtDnDBeOc1Mt$g(sOB5#Y z&O4XZ?(3XVRjC4YWm{E8)SF1}iSEBW~v#?~KE+k7XKcvQ^X>ALpH$8BN^ z4`#LRXJKG)aCu^C`+N2_cBO?0I&Unpuh&0!3KZ#o_-W^!pFyI>B6jY6!gkqQlDFlN zp!=F@H+XNFxPF{%xBlHJb1t^@J(q%mo_+E?>J+H0c7085k7id;QiV~Q&dH4E=H;8N zg__B6yUe*U>uYG@krG#3<3Bf*n^iP>u2*ZVj#+y7;|A3?TeGE;cP*OwB2Ts6v-{lD zx9@(r)h{o)#1~ogwoXt&+1%Vq)W0ldYD&@Gt1G&^w4WTAW11tKekNs?yCJvB{J6Y# zmtQw4Nlh?JzseSIa+$%q)VBWF*)e&{3=FS@nfMqOW*n6GynAom_VS;-EVZM@;j(9rZI$vmNX z8!rRHI!}pgDTaCmFfg-WkpVLp7&bfvSqbJe@bZHiw_tWo1t|4`nF)uTK}`uTTUu^e zCo4mPm4jN@pf}GL7#u!=U9Gf8zIE;Xxjhj< zRhH$3pFU*oJ>ow>X2X%IJ3c?&@O63Wy6PCqcUH=i{v~RC^0*-s^sCa$fcJ%2{|$n?7Q9e-o5 zQM$9(wm+`t)_h6+=%871c1o7VfA%*!nQ=(4Kl0pV!Pk@PKG*f1TmRLYiJ@REILJzL z(*8dV2@$G2u{t+Ubn@oxzx92SJp^2r)F?l*5!(2_$|!2-hrf~Xg8yHKJUO1Yddg*X zo2spgGI|QCQ-xVuYIJ1mvrop$asG{7x;x0T+RWGDk@>MhvDNb2jt9~2jq8Ur_PXEiRKk@In z!-Jtr6zsK zS680+MUF9c+vkECMwY)^Ikcb|}knM@vfENN@d}voZR) z{I^$6JZL&z%qxg(KFsuih?u23BSyNgh zw$B&7U`@x!8ohj@sWX+SiUJDr+1g{yDJ6uyZkC6gA`SOm5n zQoXpsxcu%h8O5bK!54V7^jl9H_3-Fg#^S8JZGwy4pGnWsjntOT+4n4c8Y9DwV-I=R z7!GXpd$cUmu2XwT)pHe9Pfbg!NRcT!>{j|4%-kgNY39y6&GQzHlR7S}T;6bGsUX-X zxf~X-{GV{x`FtV+Lqwue$G7QmTsN&XD`Rtgy;r~dx@y)mn=2oW*B5Xx`0cEP^1Gg&J-UzQv-HciFKZtAe2T6=Yw&7&?&oRKcGcQ>{ah30Woc?u z^z+KebLRH~N^4&qbdLW1zI^%=75nq^r6l)Ny!mmb&}Z?YZR^%-yA~TXscPXdwqNV# z*eredYoYn_*f|%TJb9Tu|E*QInSotgT=@3q*P^$}S!C>p+2Z($Rpz$c*E5&rX#ak< zL;34TV^gcDk1qo2x1Zns`&zW+^S{%rf9b`Ys$@BKllS{R+mBlX7QKIT)O)@Bdz;U0 znW0~=HMehzuitz8z5i~hpgw-SILlfuuATqSS^M@czi~a`qMl4`ZdJ*eRV!DfzQ6ZG z_~f=V=JTr0^&Kz2U$c4p8XYOFy&vxs|LnW4C%xR)JGQz7^6RzxzrF5kaOV1W;Q!D2ci%qOl9sCb=l|bkq}aZGYk7#}nfJ&p!QnmQ^NbUd5-*<@-MNUbyn)j9Iwe z{OXrS>$`sa`u_jkd-eSI>z2p2&Hr&LJo#b4_nn*H|LeW)qb7KG?%e*GkN2~pqRM3~ z50(DCv@!X7-SgW&`6h8#tciGYeE$DGH^t|d=gjV?(vPwD{fPVCrcdR6f2nViwVQM2 z$4~Zs-%s(^3vjY^uBbdeuUDdA&!-E{v2UOI^gmCo|9bOOTm7*kPTEqnuk82B&6>3) zGxOuLsjO#|C{^lZgp3!Dg#48FgVgyYs>Z8ees|F zI?w+3r=R!!@817@^$L&r*xjl3|E+E3yE)DDO6Au_7Z)#|UpuY%=|2BIZkxU|6xW?U z|98*n=iO~ho&KHrvi5Z^Z*2TqemC@uakS*Dyge_|>!)=n9ei;0^77x-dbYog>c83Z z(QW&Ef0v5^FJ|V~UhX^2f9LBm>H8n~tmW!oN#B2AdH>&m|NnOT*Z$+4H)+z7`a+S= zy-#i5t9m|eW?sB^@8Z3-%jeaqiFNLIUtX`jb)DkXfbi>&<9}zFh-j@}Yy0Qg_NiB| zd@GHy`gvvY;@aB#KWFd%cO$;e?CX!$bEbTHa@jxEx~Ag%+U-y8EU0{c@Am!wjYqB@ zum3dJ!(hYjY0+A*q=U9w{=4DtXa9T4q7~-*U)SG_=9lB~^O324v+-Y__xalQ)}0N? zQe3t_cGmAG`LkousyUyJ=>9z>%G+A^=jZwVZ=d1aD3a{TZW)5GUGpoV*>euLdf9D;kzy9#|y{|v-|G#_S z#*LZc^XxwbzgJmwP&@q5#TCn!e9^W4&)u2*=~@4uKjHt5FV8(KB`@K@t6*|?$MeJX z(|_FB`1bvuv+1C8@o#JR`Z+c`A0Lx0w)=88{*RN1NYU@V`~UIJ4>sxTD7#DI3A zb)P2R|Iz(ll()63_SosGrQgmN-~W~NsU~>m-+xbxUma!tzxwr?$k6NWf4!W4(!;q* zuYQjDqUig-?;W{Z@%o_i+3K?Tm;L`Xe1CNG2;1f4s|NMVuMAD3P>;Ko+ z%klXfKa>b+tZryBIHAG7ux8P9xw;=W^J{~>e!jc^)-Qm?#TM@DK-)zpq9Q^Nh`DJY#aIQ9C~ zCt3HvtH15PT6Y@qS)HGAa_89}4-(%0EK}O`FZa8armEcUcY8Kho{v*{m1!UT=Jm!I z-pgO#+qCJ!moMAxeuszYY}?YjV^5sYtM@yu6hCxI@^sC;TmS!7{hyEJ@*W~rGTI8C zv)BK6Jpb?Ovxar`E$bIK1zr{Qx4C%#;>IV<6<*$*EB;QMzPznn*js8_?tl6FKkupk z`#4|d{TB=wdBRS2 zJ~r~d+x@ujkTkdAx;a*!E?ujZ-TP*-?eD4nx{MvR8w*|>TD_i4UHx`FpWLnT-!|^I zBZQRgEVkV(e;HIzG|BMVmg@4PsSnHcKNbIX8;3th|Ih99zS?Mh*{r+U*Y8^m+At9j~@+Q?(QJ zt9sgQ?@_l_V^x||n9jCLt=o$iKCu6LY`ySA5hW?E$c+)c-me>X-t&wv!-MVFc z@BhE!`@dav-~Xfa&E%+#x7Y7~Fs}bHll|ZM`>o5D|F*XJWo%Z@d|NS-A z{BF#f&(W1Jf%pE--fwxOvNUJG|CRZFp5Oj=TVL;?f_vSoxvQ4hf1MxS?|Nvu|J*$_ zua>OJytnC7|DTif^V7s7j~;rMU;9n}@x_e0*S1yLfBV>L6wJ@SkRt+WCMJl!-S>1F z_xgQSmo9()Q@+3WdrtkokmvEWPyei5ud@Gc>E*NE>tAh;JeAA;{Eu_}kIekYmB}}S zotyP-zdZOE9-rD%|AGHs^+x}^qc;k>I~E;m5LlG>yYGA5r{I%@VfEGeF%>W7+ovB* zGQactTkdt)ZMm

Zv_RX#dB|KH*GAM^jmKkW2ttFFq}cH4E^lTRNHHl8|m>`G|u zbn6Ze|M|~~op*d(e(z@OzQ2dE*V}%Zs(<(EW&6!H?n)*{e|!J`uKu6u@apRN<4gaY zmJRot%jNI?|3Un}ou&8x^;$%q+EZV0x#sx#Kc}w$|8w5Y{&PucE%U^fH-aLedq2v) zzfu2uZfyE_zS6k2I}84uS{Xd~u=D?~{r^9FJpZrs)wGKNFQV(ePCtD2ZtB*p?|;v| z9~*U$gMq<;5fp4@y2m0G@jGqYv1cFuzkBjF-=?nL^Xswvz8~@T@0b1fwQR1nvEAmi zdG&egvTwV&h?bUC=kMOTW}De(9gFpunVvjGw{{dS&)c={_xAeQk1w*frLLSM*6+4d zVAVQxHRq{LYJPh<()UIzJO2B3{68+i+SlvVjsXb>)H8t%__xQiGPuBcQ z?^ewg51!8tzva)+44D+-Tm5|fpQw8G;{oZ<%l|#w+)28^0bnc>7)be{cS}|0ni<1^U(8(hR)oGF1H*;_ zi4+lrgv&u!m6qQqum5rQ$c?w}>-X>9sGx({#JP?aSv?T5T*_vV3;Osn@T%s~>q6U#_oxue2yb z_GN1G|D9jI|Mzygl{&B9IbE7+?zg+PPVDe)4r;HRm@ery>)X8w|#Dt?y7y|y)pIwzrW@8z8)(+4{EN@eqSB_h=u=N?f1*~ z{~Y^q-~jji-}km1ZeJ>(|NjH~#DobQuWoN!`Y!MIt9}+{Pp&&M;C8wbeHdJJ=}JB@7rC6 zkJ@bvJz`P+`?&o-`TB3myXXG6RXk+Kc<@^4XD!P<< zdoQX{7VE6}z5d^(&u=7^vhHrL-~al~&UMAlJ35L}zn?W1-#BIQ4%R#dh7D4nHeZg@ zYsI@BS2xriU;DoDJtzcbipQ_W%G>w%uYAOheSOLQKg9pD{8;*^?a0%wdp}>Vv)%aQ z*Y>-=KRNTeH8r;X`#E1odP>;!nC(j>O|CWXw)?WM+r8h9m*4*5*7bWIPp_ZZQJ=T> zf9=7OC$G!>`}mo^=KInAzxGXW@;Yf*f7{)D+wW`9!QZ#)zP?!hKk3z^=JNZ+_t*cm zIvsyH;O2!7_x$T#RoDOC-uQ9jmF_p+e%t@C|7UUkfvohQx$-|AbgIk6zj^!XcHPIt zkD344K0j~&Q9j=H%Y9Fqr}sWb@1JV;;q9~F?Wy&zt?R#D-}nFf|MZR9|GxkGB)|UW z<$4QClP?dR|1+$-c&F}vwf)bPpw`&pzthu~E%fEH@o`zT%=GQ8$RiEOd-wV=F&y{= z8hg7j<%SR&cZ_D&vb$yf|2}-_kah9*#PWTY3wAD@GEZo~KvQwu@!$3md@NGsZ!`*4 zRM)*zF0+|e|0k?`=c%mhtmy43`CVSCSKI$wKi~fE8)N0Ydsi*Hx@Frto1)3pWkKgl z*A-r0S8f06;}y$7@739Lucp_l%5Z4RdUazPsE<%>|7+vh>-PBTIun@0I^s@kt>j^p0J;@9Sx&zRV1Jb!%IyjZAWV&huXPy07p5KRk5t z`mx`?7Cqc>`~CX++iIWpn&(Z)_HgN1b?^Qf-+pRIOU?fNX64;Ys>$A$U+;bX-0o4t zw*8Ct+z?OD?A!BsU#$84NoMt@Ig_pPY(53=|CC*3GtV~f^tHe2SNiK>E?!zz;I|?# z@86Z@`!D=Eb$W5_-r&Q^|4yA+b?jJf`}*%w&&NpSXTF?m|B3rhp;1}NoJudR?kY)e zsx^CaX65J8_FN1HmIeN}eEP~($!N8GzL7J2l;!0XO`Q^?cB%bls!?aq{^eil|DX9I z&Bc1Z@V<>G*W<^+L0pP0sga-OecJEqzF(%}@1FBF7A7VvyVG}kPP@~``?{v~4`$As zZKm-=pNIXh%l`OHo@uLNdE+^bu;+YSs&(GX*HdR_mi7N!jflmc;=exL_4MoaU_-^1 zx3|Xq&uRNwaO79_#}Bvf-qKaGn{{gKX|eeFS$(x9vTHUSnNyzZd)eZ7&&N-nHXVw# z`?UDDt(<;xkKwGJ^}p;p^DH)dM<|u0^aM>;=bIX1y_qr4C~@XpZQTOTzuO8na(V?a zFiiRo2O7J4{&0@q%@=+1=BuhIe_HzGYk*{-lJ|o}qC#SmmVD7HzJB(!WwK7o>#zVH z54R=D>SI*&m6f_4PdBlT780DaG@aKZ&?rGus9~&Hd6;$WR$nZd_rGc3tLHJRPU_Ik;zNxE&_6Z3K-YI@2H0@LG zjt|DGynoNueE)rg*2VA6(>7mG&d+yAr%b_CFDs`swD1#e#1mee8EHJ*&#Y!0=i!?j|FH*+SRQ0+W@0 zl;aLh`*ffABj*+6CH1d2&;4&MJKe?p`Bm+yTkL1$7rtySNjj_>Sl_qKS zQrk-1-hWT)+gi9k`ny4uR?>c<%^!2TMW=syxZ!GYXKh>2`jt!9eJcKzxL$GTpZ$#$ z=6cb)7EFleJd*1v|LH~UEhQ}rgA!JT1J9Zlu3}&?Q#>cS=x4jQ@2?s6>tB=}c`W!^ zep%9W>8#DizP7&KiCTb<0NbH|Rx#eR(cynQC$#TmN& z$KPst>T3OeD>OO%ZuS1_i@)D^WWDgm{(AODzfJBfTm8)Re@eIatBprD&NwSkJ=y#B z4<+|?Pi6i_GBB7)gSwluCoEgJ@y4UFpCv1^*RT8YI^@fer!xJEe=`V9JhYAA@{O)8^EyAj zuf1C4V!g22a&9H1a}v`_cCV~mc17pp<)d$eRiD+x{=6T2vCMnU#z);XEoVIw&m_E= z{`VRC-d{=guV`^`&18hTYt^bA!*iC&K6-1ux14(MSMIN0@ZOA0L&b~F4<&>g{i!#1 zy4af)@1MTWKXo^D+l~~=%T9|vH?(hNYkhxd>Y;j9hg_}yMN_{wJ^gY+spPEvO^b>B zn{&192W@C?b^4+&{Xr04$uT^Tn$A&E8hczs zi-BRbP~06x1~c8uCY>F{^IjD5F%;-tHmTPY{IRHpnIT~_XnD+r%$2KNmF@2AFl@W` zjG>^{dzo~nViyBL!e`JB-iDbwW7fI+Y+LvG#cC#o>uTrHcfEPJYhFh!BSS*)q1mwv z4Zi1Ie^s+vcg2KvsSHEG+Qc4JwKHL%S6_b>+il6fu%QcFIv4dA?!Q03qJI5rtE|oS zj1O)td|kDu%lER${PXQC;tUDJ;PCvZYQ%Thq%&es$n4@iIcZl~9Yov{cdEr3?(Gm#)f6Qo5mXZs+~? z=OZ{67-oxtf+xFUk;c-cOF!-q?RCq!UGJyk!?!G*uf2^sgxpKvd2Qu=H85v@VA)$J}O=&4l`{C#3 z=DvRQYSxSyJgrXKa=kT0T?=>mtiOK!LcslN*REZ;(lUdY;lZq?24;}yW|Q{q+b68< zS5{wIT6pf&Yw2%qZoVzsZTWm-L{3djO-9C#CntkrWA9#%udleiE_T;C@!fkF7&f>; zZ9MkC;@p!bR~GmGOUcU0y1#F4_4jwW+S#) zj~{QpSEX$PT4%!o3EdkKO$Q%*K5t(y-`Vp0{r&RCz3yJ#-V(_tx6Ub^e)?(APM^zb zR;;M`bW;7+?c1+ky()WmC-O}jGsA%>hy5-fAKYMQ5peI9v#$U5XP#~Ky+6;)r%#=_ zY?<`RJ9*!y>8>rmSGhdbTHSAsgq)mS*=n<%R$(XgR{(qfoec-dZ z`}XboccAgFva)h>bMw(WYX*ijte`4~fnmcv%f8~TudWtY?8(1>Z`G<*t#2NEttx+W zV_{}gczC&igw8if28IKxKqUqP1Hs35C?|VsrpCwLpJ|+)b9>&LIVy{e9doO{Tq63L zhk+sCY9bFG$h{HoC6Yr!LtRvsswgQQ`SIh&ks~hOrUjjvH&5>NHsN@0&04$p#~*8= zgwku-=XmXf&cI;8-lYPMPEFN5nJ?9CP~)2Tgb@C%b%Yi=gMJdXeh|RGTD1iTz+cm(p8J%%@__mgNCyi!(oGOZ*I<= z!+&(!+ldn=e*F0HN^Z{WeKkLe7S(eJ8XkM~`n8mlRM*`y28IZ3Xe=`)^yJ>%Wm;;| z>!Bjm>lVCyVvwJopW3mP3QDopU%!6+x9&^5KO@5qHE7c8UASn`qj$UC=VfFR?7o|~ zefOe8hhBeOmUqB%{o1u(D{R^lr%a#z{`U6r>+51qF5+ikxN+x#tRN`V%-9Yae0zUC zJUqPm)fG*pTbtAUGcz+^vCUfc_V#vt5iVYS{`YrxmmlwwJ(_34z_3OZn!YF2hlGXQ zD?V@QGR118*Q8aew%@DD-nW&3VM8Z0taz6dR5WHVGd#G}VrT)fih+RvQl@P<_+YXp zL&Mg_>(LAiy{v>+s-y)nGVFLZ$67AO-ptnYi z%Vy8h%)I$9>R;n|Umv?mH}8vfu{@rp+d9D|=v31DcfXEwbQqrVc)rKwdik_p@AI?Q z7@ak(c=4h8In(*M+t}4pP4sfxRRrt2W=kX==~&5ST(b1k^S!zAzt3wvng?112KM^V zBRB5c6-(|>srQUpyLK_`E_^^QHy%j19S(NVkYyv{-sr}Qo9C{QX(F_5XOOW1KPci-Nf59b}5b+y8! zIwkAX{WMt^#U}R@FV4Ao>|JUO6yzYl*?+8g2T$EV&YwCfk-%jkV-?(c_Q2dX+$s2#n zm#5Yqi7nN#6(YG1&U`?syFm=DI^**bOo3*W>yuO7U(Z?D1hFloN3$o!t$6Bmmo zKi{QY|9r1obnV93%nS^xxswa(85l$u7n}a=$*;Qe?_v1Fyc8~FaLFjOYVZ)OsT)S*(c;VXbE=p{ki-7v8{6U&js0ktoRuiz&)zV#WFu% zY;Q{zTq14BqBd8)F4v>u=kGTjp7ELcF9{#X{meDl<+%H?^F6-n&Ron%e-mF@$s z<`t;A<(Dq|klf^yQouSd?KH<6;oaiDwHO$3;=m5KY^+JP3(NT@7~%Y4{-#q(+D5;U zH?~bkSu&;S>ouvkM|ytD35hIq6B!xIOu@~E8*3yk{wXega&zj$DXrJ^+G4V_jU@EW zNeXVPh_NWU?9zEC9==xRCC6ZZPZMx0v_q*O=;f$JogBv|WG1 z)?--oTjcUm4#nl_Iq8y|EmJi z{%+v&LcxniPrj6odnwr+cX{#BH6B9h;(v0&wf_98=9{^Dw&?oqm0c>H(;l-ZFI+6% ztUp(@+e@Qk%Pgbwy46>V)`vxlRqeDDEYMgg_pWr}ly4`d^gP#;d2naz_N8C`-JWsi z?aF{3H;z82FV0WNTfF+}{0i~!yCsvqg=9R5uTx0=T)rwQ_gUYvP5gIHmh?V}$x_HY zK9A#w-WRs`Oz}oh3DdGTpX)K~+kd^gp)adm^JS56&$-V&QGYJ;B&RblB>&ovtZhQUNCLovl?EJd$;QRM3 zRqR-GXsOoXi#I$hq&md^PuqGT?8(pl8|F{mxAfZoZLed0M~UvAZK$`@=g#3(L0YMC zdzV%{x_#bi^1)X7HNsuD>XU=J&ZqYJbVkhS@OY?dUwY)mHHSXqkMa6$=S!bwZ+KKJ z8J#tARfb`Aj$qYNTV-CuS*y>^?LCufaBRxQ%w-?G2D~}EciF|L({9#v)>c_dD7PB>D*7D}4-nm$mBVynO00Tpq04Q&ttyX|D@&zyy~_aCt?i~Mj=a`sNyv->ul-D|Bptw?;$iZ!dwt;jTb zYD0lhm$bYI)|8!G7nYlfEQ=7XsKW~+>h+N^E`6XZfE?IrvFVlARP9~qU*0___ zijf71-an^Z_F1kzv8-mA$CXXzwLc~+)*lm^8GVlJ#LmYPVphK6&@P(2y4s(60kgT3vN zDLdwNPB0c#QCe28cIB-*Vfwl5nqS4iU~KE4JM%sSNQ{X?-%M zvc}7`w{Gd&qQ036vi9tWTAyvU^N<^R@?+NwN-E3w|YM9TLxS1=9$}1~ew=UdWQE*C5vg4=s)>~%Sh$Dh>};y4x}5 z?X0>drr8N|BrZ#9dB5L(_D0Zgk)wC+y|B6}m{EjFJ1t7OQ|uDo`m z*IJE<+j9B+ZY&Nyb7jk_ptwhgt6sGzciqq4a&1NGy(2E?)1vos9DnoBb9Mcig3luJ zZ{G--E>)nBYFC>r`*`QO$CAmj>K9#|_FC8UPIgpn@;gSHZI=yMAlqtt*KAwmRp~8PPb@XJyo@;wlyl)YffbI$cbT`yoYdZgwvA?-&2wB)X`mE;#q9fByZTMcI8**7Nk$ynb}`E=l{{T-`Tv(Czbj1qT-p}> z`Lu5?uiW(%n|~?iA3VNWo1eR`-aA-UFm@)NS;gJ9MJm5?W9H1L+LZoaZ|>Prx$-2> zGi7pnF8z(U{~+W}k_)@`>H9mE8ctk$rmjZs_VML%doGpMC3Oi_*I%D@?C@1luH@Lp zgx1Vyv)vw91m3RPv-^MNynkQqdpN$&x@Y~pc)H%wp4d0Dt6n^Padh61<-fkYn9^}< zwf)byccm+**4>x=t-O4F(e{VcpB4Y#ZTC2_u>MEg6CZU!!EmqlyKmN3%;s=oI=|2G z=LPSm+{&Bh@1$VMF`@SC?&+DJXE`7hNRZ_|@Y1O0Z&!zWv^Rdjgwf!dVf9A5y z^t^XjJo5Wf`hA214WI2Uo*xxC>2X`+!*#a0s^9OXY`JRas^}KvA=uLrXKDZQLAR33 z2Bo`fpxXIZrQwsNwbVDUou+%zVGk9 z>ih?Kwig*DU7E?~Z(o`8>*MuQ6F;u+`+rV&|IXP(oMC=9~^s_lVlXCchoBc_!AgFdVRI$xLEoxEA$r`%#_vlcf{y z`ADm+&n?pA>Ta9so$mBlS)+=lwUgy{60TGPhgcj8#UVvwtfewFnjgRr5lRr!Kj= z&tqqn@{Bbr>a(W*d^k5c`_3{Iss3a2C0osB<_TOB+y8y-*{{5D+t+FIP3fDW_1w<4 z+B^8~!&O|GPd!wuM7y)QExy>yU*>@BVLuUu(2d#%94Wg5S= zPv5%|@cgQYQjp|ji}Ka4)@{0^HGO7<+p3;Q)35WE?fNU4`ucw?t9fa$yRxC%G~vBh zr1##izMk$F^rfhN&Eokv?K5{>jB@5mKQd#Hfv>8s?{C=<(Pdgbp&p4Q#g3uNRxT+@ z>Pe}(&!y>k;^+KDK|;wjgWvx6YJ$?3JXycdJ|e znyBvOe)GZ;!Zu9iaS~u?Fm2=FV`wNG17~3O~{-ZMLfkBE(-|)8GI<9_o z%08aS8-FOr?hW4fW46@mvMIkp&n=y@-2HgGw3Md#S?gD;vu)oMU0zYT`&^Ijl^rp2 zHZ}&ND2Z8HnOKSRz0=jN4GzxjT$iu;@u!Jy%FWI8scK7YOzW-cs!9%pOnJTP)NQXC z)m>%f$!}j??EHA+m)@fQ(XEHhcieoq!q#TyP4_c`8&@|!TbH(O<&u?M*Ilm#rJd)r zt5+*aUGV7e_ZPlbFBLA6vz4-|JSsU~Z%hA#kBx>)udKd0ZT9YHrSx4XDrxUBLSCQp zd^qv5?XzuFX4W3M#wPF2?ykSvzFm0ni=Xo@oPPdhq3893YxkMQA1^ukf7|QFvC8L; z#OxOm>|%?zNapR4j?TJk{w`pT-n#5#=Z;mJKk;e(im>>&zpuX=x`v+Gla*^}ZYsE) z>HM6&ZRL|yf@W;odQNJtn&O(q&IjD-JC1+3TYBKmbD--@V?pQdMs6O0TsaI#*8Exc6fDcgJ-rgE~IETs_fv?wzH(`L;@~-D+%j z`PFI3bcLe~3=#I=>UZwZGMkffi<5irdliz6=vBH}<5km<+4cYcBsy zef7fOR?h~f6Yu&yaP#*cTXg7gcu4PCyEp0eJ*QTG$!os7ZOxji!tSpvgl+!4X_;bj zNBr}zE8A-2LX$;J-3m^{c^qyE-j;jP^_B_Be>eU+xAgp?O=&f|ru}F#4x1!l zR`iWMCQmB0ZDE0&_@f^mBJvGJLd4FWF-x+F{i<{rulldsC}_5#jY`3YE59-jlyP{CVK<%07Tm7ZfFRJ&ktx3O69n|BT!#%UUV0zxZ0*G-q2weHMUrU^l9xxe>Y?b7%0 z)9mSWUHtUfG_UEAPmOp}_g*h32z|KBuP5bBSySZa8D2&8$C!-_H8_*cTzE2xi7(yg z1&i{x5Rd#xDye(2Ey@-y|DYG-m0fU1Zf=q6jaBBMS*1@uo^vdAS2i{&a{2K?b??ro znY^nt7--wLN~n$le>;kGFk(Re4@_x9Hu~6){!br7EfqI!eFz+E!hW-y83iQ*UURLob(vP`~g%$&|4S@W&r$rVwhO~;qbeQ9u6 zBsqKS&fT3InN#c1UQFS!Xz7WUmHB_JSV`d8EA1;m>#J7uN(6iFnYQee?^K`grBjq- zX8$>OdZTykl7ecR1$7Vjww~D@bbdn4&GoywYh~S-m>4#sfs#&+M7DjsfqQOqWNf~H z-yy|wH>b^=H;KzuuGl1YZKjEKcF)Cw6&#S{6lA2de%ZeI=4YPdS)MIZjP4mLF(oQ(I?nvdY4PE z@LZYvw|x5tSL;jOeO&4CLx%yJJDBdfu+x%m)t^EV=hu&$w4?zWdWVOIJ-3_`C3fL%qgkImLGtozKIJ z3MWjG(bN#!y5xKHs>0p(_OE^F;JS0AR?w*o0%cc&C=X#-` z64BQg+uz=}oVfPTd7s#|9|Q$6yTT$5@yuPa#eMmfV_rcPo|?JtEy*^ftR9tY>yGiR z=WtD)+x+dsl(_hX+plUbjoZ4czQ<6k@^M$svZ-E%p%3+JFDh-lV;|goP{P~iopfJn z$;}BDca+E|DS7%COe(Jm-8RK|OPl)feV-%*C$7o}Rh<|8{l~qM0Nt;<^6yxFeBiAl z^m*^g1>e8zt%_w8oP21a;p|VT+Cg0>e8kl=Zx+XfcL*lmNft_1Y2k342?Y;1GCLJU_)2$|zkbS(o+Gzoz*Pzs-I7FBRqgQ*{2-H|FYcJ^!ucb^qd}4|BceCf??|S$3sN zB~T&H_OkU14_gc6{p%u~{Ej8bPG(f%I;b}IX$h>kg>G2G8F3j!SmO{H?{Zn)Qw9IMYb-~?onOkbZ6D97gfpJf}7Tq z+C{GEiLU>6PI2p<^S)txR#y})YgLs~+T^}`&6|g=&+=6?<0gx^_091V7CT+GroQpxjiYwo7n*IoviirJ zuJcDruKvGv*lT6D%j1o!n=g9TDhU{to9^V#KP|iIN$%DXwWcQ?%Zj$1apzj@vgVoD zj_QxTu}4Br<~;fH@-SPaB@@GqDc7pwBN-Zc_3l^SH9f64ZOyKOAAW_pCVpH|@w0QI z`ab(9Kkj??_xAC)bgtNRtX^a7mEdf>9Zu2TE4;K#l(be~nYC>v&*aHVHa@JdQ9Gnq zU3F;Eq#aIccc(3y+!eKV-OVRjo{JXl%g}k`qU@K%#C2}vvXd%qdFzAjChWMg)4B58 z%;Vv6DwV`tJuC&d+-0B7yw_;_cygbBo$v0Y>wfK8Rpe$O)#-cmvC7gz87e}R^_!N1 zx|-A3+Kw+SoN7FM)iIg&4wZ}2i-nsXatOZF)V>+@=(5G^p5t+nGLdQPHXMEbw1-pk ze7}F~??+eVOTTUF_qS3y9vFHo%XVFJ=+mAPYgbikdqvmEDb4CT+FV#|J3U`uqHtGR zT&B9B#PetC((XsE3-;QhBz66jb`1NrY4vxio5Mm+S%^1!ytv^i<($7S z>1%&lo>*6u@?@7I7TevIJFlO|Z&PaY;ZA0?jYm+Cv;Pr!ZpGZ_Gt=5%=$hWi6;fWj z^;mtzswgK}#_zj&)^5$(ng8sBq4!#?r*e}GpZT;dm$Nnddck|)^z)XD9~RXYIUTER zTbet0)r!)m?`qc`ktmm5XR90adDfXln>>ETJ)Bs_z_3OOv=L>Exa3hO*O${Kty*|> zt%i@6rJ0O%d5)FkpXI05R(NkY6%}k8QM)=j$3QKu-aa<1$8_t?_j~$Tm&NZsik%zk*{XW`(*7bOJ0 zvN+Wqyl^gP|NRS{9v+pIMg~HW?{26j-k#<%XT`m-zXX6>r) z+fC)y=#;NKCANS25tAiT_8u$9X|Gg!9y*+&%&Qsn! zbDitCvZH$6&Rw=se7slrICrp}vPR@k4(+Y{|9d@iCvtlq)pQIe60>_L&dcbR(sZ|jzrjpB)G67eXW1V6a8)j~73n?`dcytCxf2d1Qr~9f?W>)?{c}x5R!&}B z*yXib-hEjzMgkCU_5E^U08;J>9lbMfWcR3&Va(i?6e}bMtl3l-aLVMc2%WDqpSKx=@2Fnep^K6H8lx zSwAmWKeBlHIN1Dp*zXcQmp*~@yt>&z- z#4Fj}ZRN9f&ziC7$ZxmD;p{1A7JX@Ojw<``v~2CFE7ia4)~>u%A0MsuSnRUtI?bRH z5$^S0g6=!L-ytjbTDtdppM$fdVbhl9HSaxiUcKzFf zCk;<;TPixAvnj`WUcGI>OCJM+RP{E^*o6K@neYt8dYYSn z{K^;pbzgW|l($XbN)J44XK7Sdm~=`=Da(4La<)tE^Cu^MbWZ#@I1*Tgg=Ry-f_(J&b*fglv;YCFKtRav+PKMhErRdrF_-TIi^;sy3tW#`zD&U zrh1>AHcj`Dnc&GCvacn#u^nHU>aPE#qd@0lv)IHPJ-3yzRO=Y$bRPI}S$+9@yG-7` z$;vxc8oOQl@Z`(m_5SviPHvBbJS4ZL-kDhFeeCVc4WXy%XQ)2z+md5x-P?E7RHWir z$e#R=Bac;DMT}}575(U4t(4|@dfLZ33#ZP>HM8U^oc3aa@}Z3t*9$&O{q`~6PS&n+ zri$ljx%vmKCthkR$tWw%JhZlPrtsq)uhSE!>9$TO zR4@AV>Wi}b;_2)uXO!x17pgTMoPOT*T$$RsJzI`uJw0@^`lkLTd0B>r-nO}xrTcE= zGB8BAi(S%IDV_ah{pJ1%5tFv17HyuHsk6i93EjCBAIW642_wl^e`4|8H zoxD!9q%^TdWUA`33mwNdm8CB^w{EMBChN*uXSQ$C6>XKwYc=k2ceT-LJyAbnee({d zu2ZGWuh}*yDM<JKN(owQ9uD_G>w98V=}y(5#B zeNCBD`{;Z$SN`XT$Kxk$IZ~}Y_xu#6Bds2?i=3Xu%-vhMvBjf>L+UwKvZ!9OVE2u( z6Ptp+Kk5lN_C0*s-&6PIE?p*9KF59culjwJAG6LKR_j06@#Ut}j1|Vky&=a!&IOwX zOI)`2{&JO*&6^v6w-uGn%~0vG=1YGg{JT6ZK3H=}O=7}}+2ZT6=1hN4bz>WI;c21n zSNRhT^IjF*UtDngQ=g-){O{kccOI=;74+y@)~OvUh11WK+_-Zw;Mct9nX8WMZacp3 zpUaxX^Xt>rTVD=YdgO44Z;O(WjH;vY^GaPxrar;Sp7q^x({q!-C0|$|fD|HgaBkL`C!Blp~H0J5NT=Tz7KDQNQzX&umz|^3H`F(dv$V z20F4QEtHR)*d)AAXyu%hKW9sAepa`JE4}N`UbSFR!M>9bF+zr}ib|5*=l@%uinu(z zF8$&8702Z&Pd)y4<`_>;n)+(bpY=tFkGf}?sFa3&YPuK`GAZ)c#92vCep~&wRAgji zn9-=G#lWDgbN_~dxPa9PeAxdX7JKQ91f%aav){%Ns7dbpv+K)S4Xan$w^q#i>6Pcl^~~A`PmyAy&GOM+*7daum6txY z*w}HnN_v?+Y>c|Up-SxIi|Crv;Fi9uV-)mJ?41HQC%{t z!t3y*YsZS;PTE@VjOB8lGWU1$Ns(vu>JMycP3``0rb1@QU+HY_O#L-0`zG`isO2QN zY+gBQ%QTT(y?c{RYexLL7ngmxh@l}Hw0^U}w@m#kDqM5qc#7_ zGQGD6T2<-H3^{3_H4a_+w< zx94p9nDOT1yvFCh*si~G*M1tIVkXk(;raODjjsFkFMnSZt?)l|ch`)ld;KR5>Yq+K z=9~MI-Sdm@$*p^CEN5pZI15_cxgqIOxu50@PnFctMy6`FoJ{%1X;)u7)IL4exuiJz z#;aN7vuD3rwaa=}_uZhXEvx^ZoY#0HVxjg`^OQ!Gi{;i<@;mOhx~%?qp<3H}dcDBf zbxLNUafeqkN!Ry;#qQf88~N|ytjoJ*itt!|TI=F2%Fr;i$;y_Y;j2=z&aOMsI{#`5 zYP$p97)M{1SiE-kbAF3=D^`b1xA8rFs?*Z%!lvZDf@@}XJtlM(T7^AaSUan1!=jv@ z#|_KO*8B`@>~*;vw);ixC;mN#@4L+y7}gkqn}1qwWAl&APN?6uK{Cepo~8b`xnK4v z*Y%12{=+jp=(P}FQOmyX@0zy=C08C;c0}ap|8LS_+r5u< ze>)Uc8+kDNpX#~0ybKK74WLz1M*}UE�{5BP7qiYwxMK?^iwGx)=0(LDrjl{GnOD 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 delta 170161 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