From b1f16ab6117bd7053cba97cb21e3b67a95875322 Mon Sep 17 00:00:00 2001 From: Mat <158223041@qq.com> Date: Mon, 31 Aug 2026 23:09:02 +0800 Subject: [PATCH 1/5] Prepare v0.1.1 downloadable macOS preview and release pipeline --- .github/workflows/ci.yml | 9 +- .github/workflows/release.yml | 42 +++++ CHANGELOG.md | 7 + CONTRIBUTING.md | 4 + README.md | 39 +++-- README.zh-CN.md | 30 +++- SECURITY.md | 4 +- bridge/codex.mjs | 5 +- bridge/server.mjs | 2 +- docs/INSTALL.md | 36 +++- docs/RELEASING.md | 55 ++++++ docs/images/setup-en.png | Bin 0 -> 126170 bytes docs/images/setup-zh.png | Bin 0 -> 132497 bytes docs/releases/v0.1.1.md | 33 ++++ native/CodexPulse.xcodeproj/project.pbxproj | 8 +- native/CodexPulse/CodexPulse.entitlements | 9 +- native/CodexPulse/CodexPulseApp.swift | 158 +++++++++++++++--- native/CodexPulse/Info.plist | 4 +- native/CodexPulseWidget/Info.plist | 4 +- package.json | 2 +- scripts/build.sh | 39 ++++- scripts/fetch-node-runtime.sh | 22 +++ scripts/installer.mjs | 176 ++++++++++++++++++++ scripts/manage.mjs | 128 ++------------ scripts/node-runtime.entitlements.plist | 6 + scripts/package-release.sh | 22 +++ scripts/sign-and-notarize.sh | 15 ++ scripts/test-native.sh | 5 + scripts/verify-release.sh | 38 +++++ tests/SetupPreview.swift | 19 +++ tests/installer.test.mjs | 157 +++++++++++++++++ 31 files changed, 877 insertions(+), 201 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 docs/RELEASING.md create mode 100644 docs/images/setup-en.png create mode 100644 docs/images/setup-zh.png create mode 100644 docs/releases/v0.1.1.md mode change 100644 => 100755 scripts/build.sh create mode 100755 scripts/fetch-node-runtime.sh create mode 100644 scripts/installer.mjs create mode 100644 scripts/node-runtime.entitlements.plist create mode 100755 scripts/package-release.sh create mode 100755 scripts/sign-and-notarize.sh create mode 100755 scripts/verify-release.sh create mode 100644 tests/SetupPreview.swift create mode 100644 tests/installer.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4799b9c..f55c7f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,8 +18,13 @@ jobs: - run: node scripts/check-release.mjs native: runs-on: macos-15 - timeout-minutes: 15 + timeout-minutes: 30 steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: '22' - run: bash scripts/test-native.sh - - run: bash scripts/build.sh + - run: bash scripts/package-release.sh + - name: Test the shipped Node runtime + run: '"build/Codex Pulse.app/Contents/Resources/runtime/node" --test tests/*.test.mjs' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a755f17 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Release preview + +on: + push: + tags: ['v*'] + workflow_dispatch: + +permissions: + contents: read + +jobs: + release: + runs-on: macos-15 + timeout-minutes: 30 + permissions: + contents: write + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + fetch-depth: 0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: '22' + - run: npm test + - run: bash scripts/test-native.sh + - run: node scripts/check-release.mjs + - name: Validate release tag + run: | + [ "$GITHUB_REF_TYPE" = tag ] || { echo 'Run this workflow from a tag.' >&2; exit 1; } + TAG="$GITHUB_REF_NAME" + VERSION="$(node -p "require('./package.json').version")" + [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Invalid release tag: $TAG" >&2; exit 1; } + [ "$TAG" = "v$VERSION" ] || { echo "Tag $TAG does not match package version $VERSION" >&2; exit 1; } + [ "$TAG" = "$(git describe --exact-match --tags HEAD)" ] || { echo 'Workflow ref does not point at the checked-out tag.' >&2; exit 1; } + - run: bash scripts/package-release.sh + - name: Create draft prerelease + env: + GH_TOKEN: ${{ github.token }} + run: | + TAG="$GITHUB_REF_NAME" + VERSION="$(node -p "require('./package.json').version")" + gh release create "$TAG" dist/Codex-Pulse-"$VERSION"-universal-unsigned.dmg dist/Codex-Pulse-"$VERSION"-universal-unsigned.zip dist/SHA256SUMS.txt --draft --prerelease --title "Codex Pulse $VERSION" --notes-file "docs/releases/v$VERSION.md" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fcc512..679889a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.1.1 — downloadable unnotarized prerelease + +- Universal macOS 14+ DMG and ZIP distribution with bundled Node.js and local bridge. +- GUI actions: **Enable/repair bridge**, **Remove local bridge**, and explicit reset radar enable/disable controls (radar off by default). +- Requires Codex CLI or desktop app already signed in with a ChatGPT account. +- AD HOC signed and unnotarized; prerelease only. Intel installation, clean-machine support, and full release verification remain pending. + ## 0.1.0 — source preview - Native small and medium macOS widgets, with English and Simplified Chinese. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d02045a..4520202 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,3 +15,7 @@ Before opening a pull request: Please preserve the read-only boundary, explicit missing/stale states, optional social feed, and small dependency surface. No credential scraping, automatic quota resets, account switching, or fake engagement features. Good first contributions: clean-machine setup feedback, Intel build/install verification, accessible text sizing, and additional languages. Contributions are licensed under the repository's MIT license. + +## Release changes + +For packaging, signing and draft prereleases, follow [RELEASING.md](docs/RELEASING.md). CI tests the bundled runtime and verifies ZIP/DMG contents as well as the native build. Keep unsigned preview limitations explicit; do not claim clean-Mac or Intel execution results without recording evidence. diff --git a/README.md b/README.md index ae40109..e831f53 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A native macOS desktop widget for **5-hour and weekly usage**, with separate reset countdowns — days included. -[English](README.md) · [简体中文](README.zh-CN.md) · [Install](#quick-start) · [Security](SECURITY.md) · [Contribute](CONTRIBUTING.md) +[Download v0.1.1](https://github.com/18637168668a-cpu/codex-pulse/releases/tag/v0.1.1) · [简体中文](README.zh-CN.md) · [Install](#quick-start) · [Security](SECURITY.md) · [Contribute](CONTRIBUTING.md) ![Codex Pulse native widget showing two usage percentages and separate reset countdowns](docs/images/hero-en.png) @@ -31,14 +31,23 @@ If this saves you a few trips to the usage page, a ⭐ helps other Codex users f ## Quick start -**v0.1 is a source-build preview, not a signed/notarized app download.** +**Download, open, enable the bridge, add your widget. No Xcode or Node installation needed.** -You need: +[Download v0.1.1 — DMG or ZIP](https://github.com/18637168668a-cpu/codex-pulse/releases/tag/v0.1.1) -- macOS 14 or later. Apple Silicon has been locally tested; Intel installation is not yet verified. -- Full **Xcode 15+**, selected as the active developer directory. Command Line Tools alone are insufficient. The release build was tested with Xcode 26.4. -- **Node.js 22+** on your PATH. -- **Codex CLI or desktop app**, already signed in with a ChatGPT account whose quota windows are available. API-key-only login is not the intended mode. +> **Unnotarized prerelease:** the `unsigned` downloads have an ad-hoc signature, not an Apple Developer ID signature. macOS may block first launch. Only approve this specific app if you trust the download; see [first-launch guidance](docs/INSTALL.md). Intel and clean-Mac installation still need validation. + +1. On **macOS 14+**, install Codex and sign in with your **ChatGPT account**. API-key-only login is not supported for quota display. +2. Download the DMG/ZIP and move **Codex Pulse.app** into **Applications** (or your user Applications folder). +3. Open Codex Pulse and click **Enable/repair bridge**. It registers a local service that starts at login; no sudo or API key is needed. +4. **Right-click desktop → Edit Widgets → Codex Pulse → add small or medium.** You can close the companion app afterwards. + +The app bundles the local bridge and Node runtime. Setup only runs when you click the button. The companion app runs outside App Sandbox for service setup; the widget remains sandboxed. [Security details](SECURITY.md). + +
+Build from source instead + +Requires full **Xcode 15+** (Command Line Tools alone are insufficient) and **Node.js 22+**. The local build uses an ad-hoc signature. ```bash git clone https://github.com/18637168668a-cpu/codex-pulse.git @@ -47,20 +56,16 @@ bash scripts/install.sh --dry-run bash scripts/install.sh ``` -The installer builds locally, uses an ad-hoc signature, installs into `~/Applications`, and registers a user LaunchAgent for the bridge. No sudo or Apple signing certificate is requested. It refuses to overwrite an unrelated app. +Source installs go to `~/Applications`. For a custom CLI location, set `CODEX_BIN=/absolute/path/to/codex`. Pull and rerun the installer to update a source installation. -Then **right-click the desktop → Edit Widgets → search “Codex Pulse” → add a small or medium widget**. macOS requires this final placement step. You can close the companion app afterwards. +
-If Codex is installed elsewhere, pass its executable path: - -```bash -CODEX_BIN="/path/to/codex" bash scripts/install.sh -``` - -To update, pull the repository and rerun the installer. Remove/re-add the widget if macOS keeps an old rendered view. See [installation and troubleshooting](docs/INSTALL.md) for paths, manual operation, and removal. +For downloads, close the app, replace it in the **same Applications folder**, reopen it, and click **Enable/repair bridge**. Use **Remove local bridge** before moving the app to Trash. [Installation, upgrades and troubleshooting](docs/INSTALL.md). ## Optional reset radar +In the app, choose **Enable reset radar** and confirm the third-party request notice. Choose **Disable reset radar** to turn it off. Source installs also support: + ```bash bash scripts/social.sh on # Later: @@ -105,7 +110,7 @@ bash scripts/build.sh # local native app build + signature verification ## Status & roadmap -This is an early, deliberately small release. The local bridge and native build are tested; installation still needs feedback across clean Macs and Codex versions. There is no App Store distribution or notarized binary yet. +This is an early, deliberately small prerelease. The native build architecture is prepared for universal distribution; Intel installation and clean-machine support remain pending validation. There is no App Store distribution or notarized binary. Next priorities: clean-machine/Intel testing, better installation diagnostics, accessible larger-text layouts, and additional languages. Feature requests and reproducible reports are welcome; please remove account data from screenshots and logs. diff --git a/README.zh-CN.md b/README.zh-CN.md index 68b6172..815f9b1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@ 原生 macOS 桌面小组件:并排展示 **5 小时已用量、本周已用量**,分别显示重置倒计时,超过一天明确显示天数。 -[English](README.md) · [安装与排查](docs/INSTALL.md) · [隐私与安全](SECURITY.md) +[下载 v0.1.1](https://github.com/18637168668a-cpu/codex-pulse/releases/tag/v0.1.1) · [English](README.md) · [安装与排查](docs/INSTALL.md) · [隐私与安全](SECURITY.md) ![中文原生组件,两个已用百分比及带天数的重置倒计时](docs/images/medium-zh.png) @@ -24,9 +24,23 @@ ## 安装 -**v0.1 是源码构建预览版,不是签名公证好的即装即用 App。** +**下载 → 打开 → 启用本机服务 → 添加组件。无需另装 Xcode 或 Node。** -需要 macOS 14+、完整 Xcode 15+、Node.js 22+,以及已通过 ChatGPT 账号登录的 Codex CLI 或桌面 App。只安装 Command Line Tools 不够。已在 Apple Silicon / Xcode 26.4 本机验证构建;Intel 和其他干净机器仍需要测试反馈。 +[下载 v0.1.1(DMG / ZIP)](https://github.com/18637168668a-cpu/codex-pulse/releases/tag/v0.1.1) + +> **这是未公证的预发布版。** 文件名中的 `unsigned` 表示没有 Apple Developer ID 签名,仅有临时签名。macOS 可能阻止首次打开;仅在信任下载来源时按[安装指南](docs/INSTALL.md)批准此应用。Intel 实机和全新 Mac 安装仍待验证。 + +1. 使用 **macOS 14+**,先在 Codex 中以 **ChatGPT 账号**登录;仅 API Key 登录无法用于本组件的额度显示。 +2. 下载 DMG/ZIP,将 **Codex Pulse.app** 放入“应用程序”(`/Applications` 或 `~/Applications`)。 +3. 打开 App,点击 **启用/修复本机服务**。服务会在登录时启动,无需 sudo 或额外 API Key。 +4. **右键桌面 → 编辑小组件 → Codex Pulse → 添加小号或中号**。之后可关闭主应用。 + +内置 Node 运行时和只读服务。仅在点击按钮后配置服务;主应用因需配置登录服务不使用沙盒,WidgetKit 扩展仍保留沙盒。[隐私与安全](SECURITY.md)。 + +
+从源码安装 + +需要完整 **Xcode 15+** 和 **Node.js 22+**;只有 Command Line Tools 不够。 ```bash git clone https://github.com/18637168668a-cpu/codex-pulse.git @@ -35,12 +49,16 @@ bash scripts/install.sh --dry-run bash scripts/install.sh ``` -脚本本机构建并临时签名,安装到 `~/Applications`,注册登录时启动的本机后台服务。无需 sudo,不要求你的 Apple 开发证书,也不会覆盖不同标识的同名 App。 +源码安装到 `~/Applications`,使用临时签名,不要求 Apple 开发证书。更新时拉取代码并重新运行安装脚本。 + +
-最后:**右键桌面 → 编辑小组件 → 搜索 Codex Pulse → 添加小号或中号**。位置需要通过系统界面添加,之后可以关闭主应用。 +下载版更新:先关闭 App,在**原应用目录**替换后重新打开并点击 **启用/修复本机服务**。卸载时先点击 **移除本机服务**,再将 App 移到废纸篓,最后手动移除桌面组件。 ### 可选雷达 +在 App 中点击 **开启重置雷达**并确认第三方请求提示,可随时点击 **关闭重置雷达**。源码版也支持: + ```bash bash scripts/social.sh on bash scripts/social.sh off @@ -48,7 +66,7 @@ bash scripts/social.sh off 开启后访问第三方公开源 [codex-reset.com](https://codex-reset.com),它会收到你的 IP 等普通 HTTPS 请求信息,但不会收到用量、登录凭证或聊天。只分析最近七天、链接指向 @thsottiaux 的动态。规则可能误判、漏报,第三方源也可能延迟或停止;所有判断均不应视为官方确认。 -### 卸载 +### 源码版卸载 ```bash bash scripts/uninstall.sh diff --git a/SECURITY.md b/SECURITY.md index f1b0943..b50bfa4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,7 +8,9 @@ The bridge binds to IPv4 loopback and checks Host, Origin and cross-site fetch m Optional social radar is off by default. When enabled, it contacts `https://codex-reset.com/api/feed`; that provider receives the usual network metadata. No account data is sent. Feed content is untrusted plain text, not executable instructions. Only recent HTTPS links to the intended X account are accepted. Classification is heuristic and may be incorrect. Clicking a source link opens X in your browser. -Local builds use ad-hoc signatures, not Apple notarization. The installer does not disable Gatekeeper, change global security settings, install system-wide services, or request sudo. Inspect scripts before running them. +The companion app runs outside App Sandbox so an explicit setup button can register a user LaunchAgent and launch the local bridge. The WidgetKit extension remains sandboxed with network-client access only. Setup does not run automatically on first launch. The bundled Node runtime is downloaded from nodejs.org at build time, checked against pinned SHA-256 digests, and shipped with its license; no runtime is downloaded during installation. + +Local builds and unsigned preview downloads use ad-hoc signatures, not Apple notarization. Downloaded artifacts include SHA-256 checksums for integrity, not proof of publisher identity. The installer does not disable Gatekeeper, change global security settings, install system-wide services, or request sudo. Inspect scripts before running them. ## Reporting diff --git a/bridge/codex.mjs b/bridge/codex.mjs index 5dffda0..eefeadc 100644 --- a/bridge/codex.mjs +++ b/bridge/codex.mjs @@ -1,12 +1,15 @@ import { spawn } from 'node:child_process'; import { createInterface } from 'node:readline'; import { existsSync } from 'node:fs'; +import { homedir } from 'node:os'; +import { join } from 'node:path'; export function codexBinary() { if (process.env.CODEX_BIN) return process.env.CODEX_BIN; return [ '/Applications/Codex.app/Contents/Resources/codex', '/Applications/ChatGPT.app/Contents/Resources/codex', + join(homedir(), 'Applications/Codex.app/Contents/Resources/codex'), ].find(existsSync) || 'codex'; } @@ -48,7 +51,7 @@ export class CodexBridge { child.once('error', failed); child.once('exit', failed); this.ready = this.send('initialize', { - clientInfo: { name: 'codex-pulse', title: 'Codex Pulse', version: '0.1.0' }, + clientInfo: { name: 'codex-pulse', title: 'Codex Pulse', version: '0.1.1' }, }).then(() => { child.stdin.write(JSON.stringify({ method: 'initialized' }) + '\n'); }).catch(error => { this.stop(); throw error; }); diff --git a/bridge/server.mjs b/bridge/server.mjs index 242c169..eb2b93f 100644 --- a/bridge/server.mjs +++ b/bridge/server.mjs @@ -37,7 +37,7 @@ export function createPulseServer({ bridge = new CodexBridge(), social = false, if (request.method !== 'GET') return json(405, { error: 'Read-only service.' }); let path; try { path = new URL(request.url, 'http://localhost').pathname; } catch { return json(400, { error: 'Invalid request.' }); } - if (path === '/' || path === '/health') return json(200, { app: 'codex-pulse', version: '0.1.0', readOnly: true, socialEnabled: social }); + if (path === '/' || path === '/health') return json(200, { app: 'codex-pulse', version: '0.1.1', readOnly: true, socialEnabled: social }); try { if (path === '/api/local/usage') return json(200, await cached('usage', 30000, async () => normalizeUsage(await bridge.rateLimits()))); if (path === '/api/local/tibo') return json(200, social diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 19a7107..0669690 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -1,17 +1,41 @@ # Installation & troubleshooting +## Downloaded prerelease (v0.1.1) + +[Download the v0.1.1 DMG or ZIP](https://github.com/18637168668a-cpu/codex-pulse/releases/tag/v0.1.1). This is an ad-hoc signed, unnotarized prerelease. The universal app bundles Node.js and the bridge. Intel installation and clean-machine support remain pending validation. + +Move the app to `/Applications` or `~/Applications` before opening it. On first launch, the non-sandboxed companion app asks you to click **Enable/repair bridge**. This user-triggered action installs or repairs the per-user LaunchAgent; the WidgetKit extension remains sandboxed. **Remove local bridge** removes that service while retaining the app. The radar is off by default; use **Enable reset radar** or **Disable reset radar**. + +If macOS says the developer cannot be verified, first confirm you downloaded from this repository and check the checksum. If you trust it, use **System Settings → Privacy & Security → Open Anyway** for this app, following [Apple’s unnotarized-app guidance](https://support.apple.com/en-us/102445). If macOS reports malware or that the app will damage your computer, **stop and do not override the warning**. Do not disable global protections or remove quarantine attributes. Managed Macs may prohibit exceptions. + +Codex must already be installed and signed in with ChatGPT. If it is not detected, click **Choose Codex…** to select its executable, then retry setup. The download includes Node; no developer tools are required. + +After setup, right-click your desktop → Edit Widgets → Codex Pulse. Placement is a macOS step, not automatic. + +## Update a download + +Close Codex Pulse, replace the app in the same Applications folder, reopen it and click **Enable/repair bridge**. Keep the install location unchanged so the login service can find its bundled runtime. When changing from a source install in `~/Applications` to `/Applications`, remove the old bridge and app first to avoid duplicate widgets. + +## Verify a download + +Download `SHA256SUMS.txt` alongside both assets. In that download folder run `shasum -a 256 -c SHA256SUMS.txt`. If you downloaded only one asset, the missing other file is expected; the downloaded file must say OK. Checksums detect corruption but do not authenticate the publisher. + +![Companion app setup screen](images/setup-en.png) + +*Rendered from the real SwiftUI setup view; this is not a clean-Mac installation test.* + ## What gets installed | Item | Location | | --- | --- | -| App and WidgetKit extension | `~/Applications/Codex Pulse.app` | +| App and WidgetKit extension | `/Applications/Codex Pulse.app` or `~/Applications/Codex Pulse.app` (source default) | | Bridge and install settings | `~/Library/Application Support/Codex Pulse OSS/` | | User LaunchAgent | `~/Library/LaunchAgents/io.github.codexpulse.bridge.plist` | | Local endpoint | `http://127.0.0.1:43187` | Only a logged-in user's service is installed. No root service, firewall rule or global security change is needed. `install.sh --dry-run` checks tools, existing app identity and port availability without installing. It does not verify your account login or claim full clean-machine compatibility. -## Prerequisites +## Source fallback prerequisites Install full Xcode from Apple, open it once and complete its first-run setup. Ensure `xcodebuild -version` resolves to that Xcode; selecting a different developer directory is a system setup choice you perform yourself. @@ -42,9 +66,9 @@ The second command prints personal usage values. Do not paste them publicly with **Port conflict:** stop the other service or choose another port in both the native source and bridge configuration, then rebuild. The packaged native app expects port 43187. `PULSE_PORT` by itself only changes the standalone bridge. -**Node or Codex moved after an upgrade:** rerun the installer to update the LaunchAgent's absolute executable paths. If another unrelated app already uses the install location, move it aside manually; the installer will not overwrite it. +**Node or Codex moved after an upgrade:** click Enable/repair bridge (download), or rerun the installer (source) to update the LaunchAgent's absolute executable paths. If another unrelated app already uses the install location, move it aside manually; the installer will not overwrite it. -**Signing warnings:** the source build uses a local ad-hoc signature. It is not a notarized downloadable app. If your managed Mac blocks local builds, follow your organization's policy; this project does not provide a security-bypass script. +**Signing warnings:** source builds and `unsigned` downloads use ad-hoc signatures, not Apple notarization. If your managed Mac blocks local builds, follow your organization's policy; this project does not provide a security-bypass script. ## Manual development mode @@ -58,10 +82,12 @@ This starts no LaunchAgent. `PULSE_SOCIAL=1 node bridge/server.mjs` explicitly e ## Remove +For downloads, click **Remove local bridge**, quit the app, move it to Trash, and remove the desktop widget. Codex login is untouched. Source installations can also run: + ```bash bash scripts/uninstall.sh ``` The managed app, bridge directory and LaunchAgent are moved to a timestamped folder in Trash. They can be recovered; reinstallation is the simplest way to start again. Codex credentials are not touched. Remove the desktop widget separately. macOS may retain the widget sandbox's last-known sanitized payload after removal. -Build scripts retain generated files under `build/` and temporary `codex-pulse-build.*` / `codex-pulse-preview.*` directories. These are not part of the repository or the running installation. +Build output and runtime cache live under `build/`; packages live under `dist/`. Build staging is cleaned automatically. Native preview renders use temporary `codex-pulse-preview.*` directories. These are not part of the repository or the running installation. diff --git a/docs/RELEASING.md b/docs/RELEASING.md new file mode 100644 index 0000000..2156daf --- /dev/null +++ b/docs/RELEASING.md @@ -0,0 +1,55 @@ +# Releasing Codex Pulse + +## Preview release contract + +The v0.1.1 preview is a universal macOS 14+ app bundle. Its downloadable files are named `Codex-Pulse-VERSION-universal-unsigned.dmg` and `.zip`. “Unsigned” means **not Developer ID signed**: the app is ad-hoc signed only so its nested code can be checked locally. It is published as a draft prerelease, and users may need to approve it in macOS security settings. + +The package includes the official Node.js v22.23.2 Darwin arm64 and x64 runtimes merged into one universal executable. The two official tarballs are pinned by SHA-256 in `scripts/fetch-node-runtime.sh`; that script verifies each checksum before merging them with `lipo`. The Node.js license is shipped as `Codex Pulse.app/Contents/Resources/runtime/NODE-LICENSE.txt`. + +No Xcode or external Node installation is required to run a packaged app. The app owns `Contents/Resources/bridge`, `scripts/manage.mjs`, `scripts/installer.mjs`, `package.json`, and `runtime/node`. The GUI invokes: + +```text +Contents/Resources/runtime/node Contents/Resources/scripts/manage.mjs install-prebuilt --app /actual/path/Codex Pulse.app +``` + +Source checkout behavior remains separate: `bash scripts/build.sh` does not download Node and still uses the developer's Node installation. + +## Build a preview locally + +Use a clean checkout on macOS with full Xcode and Node 22+. The first release build downloads the two pinned Node archives from nodejs.org into the ignored `build/node-runtime-cache/`; later builds reuse the verified cache. + +```bash +npm test +bash scripts/test-native.sh +node scripts/check-release.mjs +bash scripts/package-release.sh +``` + +This produces the DMG and ZIP in `dist/` and verifies the app, universal architectures, embedded resources, ZIP contents, and mounted DMG. Do not rename an artifact to remove `unsigned` unless Developer ID signing and notarization completed. + +To refresh a corrupt or intentionally replaced cache: + +```bash +bash scripts/fetch-node-runtime.sh --output /tmp/codex-pulse-runtime --refresh +``` + +## GitHub draft prerelease + +Push a tag in the exact form `vMAJOR.MINOR.PATCH` whose value equals `package.json` (for example `v0.1.1`). The workflow checks out that tagged commit, runs bridge and native tests, validates release hygiene, packages the artifacts, and creates a **draft prerelease**. It uses only pinned actions and the workflow token; it does not receive signing credentials. + +`workflow_dispatch` is safe only when run from the release tag itself. It repeats exact-tag validation before it can create a release. + +## Developer ID signing and notarization + +Do not publish a signed-looking build without a valid Developer ID Application certificate and Apple notarization credentials. The current project has only Apple Development credentials, which are insufficient. + +When those credentials exist, build the bundled app, then run `scripts/sign-and-notarize.sh` with these environment variables supplied by a secret manager or secure local shell: + +```text +DEVELOPER_ID_APPLICATION +APPLE_ID +APPLE_APP_SPECIFIC_PASSWORD +APPLE_TEAM_ID +``` + +The script fails before modifying the app if any value is absent. It signs the embedded Node binary, widget extension, and app with hardened runtime, submits a temporary ZIP to `notarytool`, waits for acceptance, staples the app, then verifies Gatekeeper assessment. It never prints credential values. Package only this stapled app and state that its release is Developer ID signed and notarized. diff --git a/docs/images/setup-en.png b/docs/images/setup-en.png new file mode 100644 index 0000000000000000000000000000000000000000..c6495fd67c0ca34c92e0b0732613f5d8f47b717e GIT binary patch literal 126170 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

;15Ga|aA^V{1PJQ%o@4F&wOyTqt=XRaQ-?nq znZ%q@`jVDRRX%5a?RN$e&IR!p){hRXsm9r%I@!c!f87E0Ouj%QISUQHho|o~Q1!rLJE zZ0<=}cB7@D#ehkwnOiL-sYWRRBnx&(n_?HbqOs>Dc}#whaS=u=8Z|e94cS|Hp4tx^ zux^?brFniGTRXLFA+Bq$c8z6gRkF;!QZS&eP-L zs?QC)GkbxWO5BbkHfhCEH`cv1tk@UEC4YWnzPKBWup(*FXzCd1Lm%&@l~FfHXbJUb zSAw+}A+Lq0C5pQ|RPxBlP8#2;In+>wALx&q!a`~48f%-U(u}i!&RaT92rtFU#h;cS zkqZ-f{-B}q!7H)x-t;#PK9DwvVIV>l>aN9l5M+``Xt3Zem%dq76swTe(RH--HaMV0 zXtLC_?tOpVO3E6)Hsh_CuW~h}^DRN~raoimF6h+VZ{0onNZ%PMUq*>zg7QR=>SknH zc=enQq3?;vg%JZ^x^L-eoFSy*2CvA(x?Ju@-ydCh3x4#oGo~&$>TyfPi*h9{%{=9b z!jk&&_IITZ>KxXBeUY^ryyN9Lav!6+k9P0))77xOGt0|#KKHOjX9UIgh&*^4w*P)m zmiBCFxev~)Z?HS^_(}8E`jUnc&Q<5Z7P&_b6Q$-d!VOQ;wpS+?RI5#W5~I|n!h}!9 z3_PW55?A`CJm&(4;`s+e#;Vb7$z~`Z5afw@++*UhlIATt^sD{8+v`K2kY)nLWN%+b z-*&n(c=pY#>B0(oeF>2Qy@dN%Z2YxQ?TO-xCUAX-Hr|WTZB^Q>cSw$HG{fRX1Ox!p z9D#rS_+$awSH9;XveiBP=frR=S7nLQPK!ezH-85*HCy{#@UOFfu}W%q6Jko@xc9(oV_6s~B$G`pP9v7_A>L?+2{Z(S1|Usn5#3{kiN@chV;9ZB$F&FG zF5-hOVMtAVbploX%O}%$xkSycdKTS#O?EBDeIDDyIj*d1ML&FXY}E}hK91@Rui4}2 z!So%7PgIgqZlr+{vf{cHhfv+q38zY^cBZ|}=m1dzq<(7MhBpWAS7M@P*dIaJ$nse5n8lKd>> znoA}$AKxD4+aP4gCx?Y@jdsm7_g9)!Zj|qbyG8S=QuhwQ)~j3wjBAo%uxu_ewrn!M zn{5L2obK~&ZlU@lpXar&%pHX^dCUO$VJh{xysMqz8_>VTZ#2QucX6*Z_~e$vwi#pk zBSnbCHHclbI@&P|t06s4hDKs!SLO>I^D5Hy4qdZ@-0hXumR9c9)$X8b;%ydlYGwsG z`)`UN;5vfn+SG4_X)I-N~yR zKTLN2v}s-m5%X66=1K60o4WGQLdJd62loKf?&CtCqIX5cbA;CZWPN~ zk)xP!N<%)eBJa+Gti;|${=mU2t#Aqj3&kenR*7jV>(%oSS1d^3ZEg~aE7;?=W#;ec z``vcmhgb(iAKxH+yIF;jpmcu+Nkis#1R~Z>bQq~)m5|>;)-62}-v{nGl-2p>EB5ee z=6+ChtTA?{a0+iD9%$Z)@;+HxIX~8;K1jJ9z{u_~Xq`#f;IVy18IUF{$LQj9>ry?= zRM;?x0?7X;i&D`Nh_M68sI}}b`m&u044HUthMDO_!YFLtX;^IAW@0$)W3Sl**M)mZ ztR)yhFwB(_2DMpL2jZ3e(+Bje;mpi0sxHn6?E%lXeRn?3dJlLDK``PYJ8U?RMg$%4 zYYLE!Zv(!GBs%#{qfSH;;NcpUxHwfbEPa!)S=Zs@cAzeI6=%m0m3x!<96DxNWa@Jq zYdg*xtL&{e#SZtP5ucD;m!;w{bSjhmlgO4_=0;DvDFrE9=jh$&=O98In)Un~3u&}v z_BoK}GqML1{$}Sx3gzo8-*maXolk7@CdUmO=}b>sLwV8Ga9{JE7a(Pn+}MywGps9{ zOAu@tA%5}!b$F6o-Lci+@qVW^eO>p0P>+a@>n<`qlcX^bnzjjGNyuHg3?2^x6i0I|bbcHEKV?70>%4x+P}& zriH>$S!*+R7{Wm$$sa`4j#^lek)hE1xwN&Q<=kxPX%yX(nfGNKrzL5iri!u~cuOcc|zKDim8;;CN3Osu(8zb`3G87CpZt%yDU z4z)deLafs2+%|X4boH+T1L@E9Rv5Fq^Yd&LzNgJm=9=!a-f-|)uZy{$^!GgFWTD;r zcHV@NcpWM0{1tM8`33pVkPvZIwKZCK+v2XvjN~$!;q-L~E#dS#*TO3|eZf+P5x$s$ zJn7>TEM#NF)Td05_t>H~e`aB;VUyl8*KFJyFG=NF{HWK$=N`k&6@{^^g4`9w%i_il zN5FFGdR89cd5c&!dM~e~v5RRErhHBHbk&KxPr_3o%Z7`AzpeF zsHIilrfC*+uUDNA^Ov410rlW^Z!nKw!{QzOrH2~w7oX0Tx#SQW2du%PUYeuGjPaDk%JFTL8$zgs*o_r?#6|M<)zyR3=8}v;smBZ_;%c16y3=4kK7W7< z&%I;4>y*vJW=;p(s;ft%dkQ#MhO<2J-|L73D8)rY-Z7o6q6) zs*-0$b!OpQ!7AP*Otj{F>@zK+h>=Fx4*vNb7DR;!$KCSDfUD+1gM7rAt}zW~)#5!kXFlhv^ol zf|%;-VvGux0uv+okB^1ECsQkjffJt#Mi0Dl3LcM@6W=(M49T%fF0LuBnmBA`dEPA( zz(m@Q=r7z8Q2&Kx`%SZbfoGS$X=h?K_Fz@GYN&qvY}k;sKAeauiL)S$m;2B+3Y4pt zms^(hu-?yU6D2)r@jL=?d*}sr%%v|qwje(~(yB|N)r$B775C6!VYh;akpkAHQ%B_N zooh0au(l ztSYd`%1x%lk)M_6I3R{E+A03fkt@L;9pc=`A@bCsz4rrt#CzA+mhYj5cb^h<92h?X zep$`XM8OPzD`rOmOqYh$5Rk?ibrDv=ly$08v)FQ{+3Fxbewd2PXxo@DJ?klp%6!yg z&YQSuH)NqC928!Cu~&FsI{gLMPzdv`&FrqOz(C){*&H~Hd3l^=CtDnpbX=$y5A~Vi1$CPI3=T3V_neU`o5umD=2WJzKT6;k+m%fl%e^+2nuRzRw4U$DU zW`dnsmxkn)Vn{<_lQstS)VM`?YMWq`VH0h196L!wtC#4!5Q3@dLW`i@6c-YrL^Y`X zSzbh7BOfR3ckrZ)MP*}l0RX3(z|+3ABZRvnvwHk* zz})Lre2%9)x$`GF?`^kN6yi$|1vUn2Aqod5SEto1KX%qZ<*G1PnN4lfUi!_@gQKZo z&oY5S3k}kMM`gNeXAHA7)oN#m5SUMXO=pdd>QkPlOE0`|t8Y7K<0OKcYDD64Tl;qi zmx*06WmlwR!h8(rvErkPoXmp#_U z@eVR}a(J@Y`=NBp>fS0&ZPxy&fvT~ug!PtD!%n6oE8ol^-1l1$F6GT>*%A?`OFC4Y z$>F7T%w0X1=$PzxhZ_o+J_sQd3;p1gHPX;1Hr}wCS!D6{9I?(T`C*dhB5Xzu%^p(A zmHhpru(gdPl;<^yNrALpU6kIanAMluv(5Ep6L@5{h>3I@Jl~P*HfL#eqljIbRWkYY z!=GhVuSJ+1Wf6grWEI=st*4?%U?q>x0jLYZ=TBI^fUXC~HZ#11|e zg;G&zh*mpf`+>#AH!>+L{Hi7!%F^WE%ydl#{1H>)18evEtc-6c+R!wGOB5I*LWrD` z#*Hi~w?+OSKmQij9$5Y{IJ(Vp-hyr7l^#h1f_Mvs_cMDJfzeL4NOr6)ACMqCXmS?d z%gp%Gw`pwb2AM_=c#xWHPqv`ntV>CVD;xyvy)@tvOr*)(vC_+znv z^U0Iy1#heD)gsNcapPH>z|D=q`)yuqdBy>590?6h71M-aGUZS6|Of*v1AoX)orQ8Qz=nP~ z_gQz4B_b~(rG}G{D|d<3EAnpdPEsuQuK7HFN0ZxMfS~8{?%gm{aqP_Hl<&$+x|#vPWDysVi#7s|%_Nq5TIee+t;{ zJckQ%C~*}va`h=*q1+``fLG#~{!nN&)DKTvbS&71Rj#}x?V$l23~)Aau86Sdbod*P zBQZpPA=amLVVLjn(#K=G?^dbHKm&(~95W>mM`;D9TbJpcrh2l9=<(O@b+EAynsC*G z9Zj#vq+CtPJa1h!p47~#v{4HM*$N-%`l4yJylma))|o%$AyYuo#tmBL^PJ4I=ekBd zwzp=2OWbG5lBX?Z+cP%E*9C} zSiD^_ps@^G+n3|7@s2Jo&Wn=`&eSC9j|gn>Q=J~IPy~~dY`RtyF*wB{QS2e^FA?R> zA(_bO?mRQq6Pc3f9NU79lv{-3eXBCADlhaf=5A7|{mcxPySCHESj-pm9Mqqq_6s>@ zJ=4r3Mdrp9XA&<77el_S_f6&r^9%P;y-#KYyr?}lRxf{G$8#FeY$<}FnQfs_o>{B4 zQCO}*OB}do8NeLJ=+9{n&B#jfyn8$!zlC0uS2B=}HGx|4;-2(bX3u|IcRW18SP46> zw4vR?$c2?+#n_9o0j#_h91(kC#{D87H$$9jwjNrw>N>HW^EB7>NTVl?XCn}c3}%<7 z5ZduQIet^v!Q{>HQi%X?PYs~AuLeQ2a3ZjSgd;BYls86$(Hu=*;2gL1Y2p5cU2kzN z0RDCr0@-ST)24YoJE~jR67x@E8`@M*=x*{_IdXWJv;~7wkyA$%hn#A~G;@HoxHhzJ zHzA>|OyV#T{h_y?n75h5dBeP`i|j98mUa7?S0}neqcWiqxKaMycr<+oaZp-eb(~`!EIPA z(Db~*|G%1~k?otlj$+wkXp^PWcjc$s!K7gcE54V&XR{w<1z{QHvcC9aL+ZYQgZ>OF zh-%2v<0)hV<;VPYuaeA?S0z^n+f8KRpLX8=MMUKZeT;3%T+0x2bOkM;x~v9{z@vX) zTu}LGQx!gUF2Z?7lwOcc-`flhXiH%y`y#G>LgHFgrEd#K?Y62ZC?NMe?c6}Mz4GJ6 z9UX7!Ra_jOkF~u7gM3!-Qr+`ed#APKOpnS~gD=i|0*uHuJ{_j9k%xHM9c`5*wpYgO z{V*a}I(QR5!5mL*d`~Nzh}c+a;oE*HXr)pV6dhidDgLyKM`x~i3N)}*eWc3VaB;uP z1?h6ywrd4B7A&xr0dn#;yb$C$J4YUsf|(0)>AD2Ork*;{@ze{^5>y}i^45(W7$}tl zO(2LzlNX@yDXyD~DPF_7hll9x>DFOH=XO0oq5&6|9PmZTR~1AU48X&f;>`ixwj;W_ zYStaiiXkkuMMwnWZ_1-;l6bTSV)2qkgDyE6HnJG(GIGMmwoN>-40adrz@SSSwq7f= z7iBVuY&Q~ocDxol)vLemZ*t^keE-%AIg{htup3^4JI+2a-dG*}5}|Ycy)9xvI?in2 z-gy@0kwtqr?!N9hv7tfJ(O%(>?at9h$_CKR`?DWC%YDhrizFeu`9Hdh@iUN%la4Uy zQbhut_^JfM4}e#0k5Gl1kP=k1#~ve_XnISa0PsTsDGayqta>xPF*V+g^jp*z*{2@o zcQnwiX<`D`qi5Y`nHGCIR#M$J^Ma%OU7DqvaRC+$JN_;K=?NttwSBhSr!3h=w3fNZ zw0ssP9{nb(PfL6DZy&Uau)iq{esS5te@7ks+X=Ijsq_=SOYmc#(tK?xr z4ys8`hLT-N8~8qn{r5^BS%UaE4`rGF|H#fG+>ScSbIGAh-0NG1UpfVRRrK)j=Y&RQ zQq*^p3zfk2Ah(a(K@myeXDRqL-6dw3JH#I|Wm+n8`{9RwF#5ZpC(6Wm$rNm1#}z^< zMK0q}*hgXYN3-QUvtWI7f^ZQO}vS- zO)lIvbjETM&Ff7z?RmUX!qdfmO`x)Fc-dQ&tQqy&(6l9Ry%CeW%Wd zal#7EMOm=V2(sL)g@^&b@ZC-jc~@luHHcX&({A%f5;ktY>Ze0sYtOGdGLJ|py`1E2 zpNMA}E-SDJ!IkQ&)~Z-WBsCGj#kPfr#kD~0>#s>Rwm%=gROjPOQWDwI**S2cB;zq{ zYNZf8y0ksJ`1xQsGfkPd@yI#SWmWRx+`3leTo0Ii9lmz!vLp~R3A(l6JHJ!zGl%nM z#);Dl9Q~pB=VGcmhO?GpDQiJNLWuZ~$?MIVNGh?Sc)4E`o%HJKqevd|z8bf{I>TYx z3IC|CRjm_Au>ciQBev9M>5;mWv@9hFj55$LD7nw*9(Tw^mRVa1G70>QtNJC%JhRQe z^+c;fohhYu-K9BL-fkl1V_AB~mAQ_>Fv(yixcK9!@C6pg1b8lXsghJ!OAK%!bBlrP zX^MsE1&#*;E+G^qo4QjfQ=Lf}&kfce)hFqgbkt{Un^vf4Yf(L~b^MSBd;dHXHhXXX zMNz!G>#-*&cjXn~=0F5yVxKT$UbE8EZ}{%s{NcQPswa?4sdWi(g4OyIbgX(5{KpLj zx~LD=YCZdA^6mVr8S={GV=hm~lQ3LT{e~vxr6&DqFF$;@{1bXmRo{q}G4nI@RG2%S zu;O&?HPV3+j%%oa7*&6qi)W7kfE7~e(Ro^PihDRMME>deh`1!dNMFig0PL=+hZ`A? zs3}C&^~Y=o)!7^tkubw1pVWS*y~oJ1c++Eu zI8s$F-U$;#elh)|b|>O++Wx#HJcd2(-Sm_5HddjNj;Az?uX40=RpI780q#`jxQCFX zoqnZZg}_Hg{YH^0G?1A1hs;>3#a|oM-FZXvn$f6^$XxCSnp7m@g%^VgApFCo zrsvp}jmK_|?#7|m78z{#c|7kPMwe`I_RT`y?l(lZv>zRLm)JpR)+RnL)zbI8XUVO8 z;I7*j=^*sQEELkpSF&iPsXP!*pPgYHZ{n7NI&V*Isnd~Q8ADzmR$<^VbXIy4j8rzX z`V13oWqR77xKY*t|J3x&<@Z7xzdmX|ooPJGqh4(5*&X<#{(K^)=f+!e%I!0?#rvYf zPBB5b^|D|CSXIbu%Hz7d#bZn9zt+d8OOP|{#)b*N*`vmetNrU5Po;^sFTn9AGw0_& zWhzhUqb@%R^eq#J;ySlC;&l_*9P0yBl`n+dG29>&K zFh=tH_|>S4d_*@f6?wLH<@Q*eIPHpP>Y;seJ&nMka$r3T)%U`Dj+*|@-mkV*objIB zTj~qRu5Q*#&!ejPmE%bkAhDiN{Z)ESS@*bYU>}+FuF1B=9(WWu=4cnjjW>A{zUO+* zx5^#@aSQshvZ5|A@AWJAILk`??{~E%X*mwp8`l@zDH5Br4%OJ3t5*}~RWJeh5WiTA zz4u<;O=Rz{HYJZ}Efe1bo{>))T}vqy1Emis@VrL6N!}aH@-3Bb&XUr29g&U<9<5lI z&&?aOPn4#%;&=>U{)<*E^yNgvf&@6VXY1cmx}ryfz|IGnBbi^u zJHJXU>gdP%%aQ3U+IM~PP+8Hdnp-!@>hV5Ptoe)hingyJvvj73DOoSV;m1VZSwk%A zxsQv6gNN)zt_zP&rQ>)UmXIGF2h=Z0^cjCWB(R7ex~W|ykJ4+M*V8UGe7Rjn5*^5= zooD05vBa%0^|oVkv%9cFkbFp^^f~`)#-Dycz)$$K@YJqz@MwRL9dKh5$f4Ks%Afu8 zy-@yEXB#3wj{~o z5H+g8+n;F;wbXg@r62AyE6&L!(#*bo+`>!j=SB7IN0;@F%Z#ikOs9k1)n7b2Pl1y6 z<3PaFZRd3kzkPruw!h1#qnLc4pZl8xJw?UQ*zjSA&UK(Omm8|h5vg*XLMFT%=1+5U zhPL7j=M{TS{6>IVtt+<8tbah_#L{yh_(1*mGovNLa!*B6Z*znWzBJM+Ba5+0#_V8~ zdGmz9X)lde!m6fH05aYSP(b2t^{O)^_mtFvjB->Y_Vi1l^HKv|{O6X(l1KD$LdH5g zB6NGv{e4U$^*i&F73^;E9`$)gHw2~Ip2VfVQhdgXQ=vjc5lRqlV@qdTD?|5@?N;*W zk_!Fi>azPf-3n39-4 z?``&Tr|^IM3{Vk^sX5LMoa~RLsp+bk)w2S}8};`;t(#d~y`{HLbc5!}&ZBwG+(W~C z<*Z-Cb~Qy}GN(@M0P~3B7|%9W$(&JpfsHMGD(ZvsP`m}@AT5xS|E6#sD^j@muDw)&t zo|anA#2i}TuxVPS3Tvr@Ot;WOP{1vL7za&1Z5`j`yN`X&$R3~X&ZcZ}7B%MQcP0tg zI*>C6mBZ%$WCHlXVK+EN>m8o0>`n1;ox|xC zovN)@Ix}B&#(0GaRU_F2e*AIyD%T%7CL%Z;59c2_H;OQ)2p!+kj`8pN1aB+UZmdI0 zL(MwDT{qy`HyxvyFTNo~O(aEF*`|T(hl~AbN!SvpO5YhS_(!K4Uv_T5?DAFcM|36j z6>OO>+!Oso48Wul{hITOUj3Vp z2ylmK0lV8dLm~B-D1U*}z?4(`j3>DjU+~9&dH-(|$Is|G5XSM53;LUh`R~s~seph6 z8KZ)~kAh#Q&wulvBTu`cv1K9fjU$LTU+ztZJ6?N9?sdb`q zgbPOEe*Ad#lMLptStW)(SmPhJX@DMWqN^&LW*hXq@kX^a>T%D@b(Nvhx~b3+TXW@p z?V1woNu4p8romEPULMq7{!jGxFDd#F0XY&E7e@N_0kFQb?;1sA)pSk8i!cT>&@wu^ zOA?*0p5^#ec#iF!PoWOa=GQynH{xd9(5XTISM&p3cO`Va(h}g2Zl(uNTu-WLd|gL= z0sFe{U{~k8Svf+nB{A4^;gbzMJc?ezn2y{i7-?EBO74FT3#fav~mf7NHnPv!E_Y=(v7 z#SUo4>S`JugUMwHCEKO$Sj_%>td>xf)zpNkuSHK>tX@~S<>5j?Syk>Vv@9c~u>Re+ zsMW7M`M1?WAR?w4T${=Y+AQx;@f$ayT%PgiFs|l^>akpnGEpuA{z`RuolrTsW+_BID zViO;8ag`?mJT<`m8dw%^R{aMdFb?$r@+S!lk&!| zKIg~rT-X~EsvQNEJv8GPG9>(}u>#O(0mD^^DQ-uUd%QC@k6!7QT&2XMXQt|-DBF?T z@tht|^{Znt24Nqsk1Jdb7G~R`E+Ol*#4_iV@B#&UN)0!FFt>c-p+mt+Ey~fUJG862 zVo+>%(HQaH)j{bAF&TgQNQEa$-Efcw`24FTY0EuS21}=}sb`yt7>`i~_}&D^VCU#jaN zaRA+a@;(Xks_?O~l6;bO<#}z{!UiG_Ui>Wh&4seiVaDqqeej%H>k+Bj+!acXOBOr; ze6{ai?{q?t1g}0D7~ho|6}5&Vx;HBZnoEnTXIj@i)7iKmzVNaD?#LQ{Mi~>AQivUx zq0{G1#=l%q;j&Avp0f$?886pytwiqKi@xG-%htbW7fcUFoPR z&FApgxg}^_53%)-LUI)3`D)c>$m8A7=Z-7Ut9$Dbkm>B;RM#K7)fkxfk7TaNy)|n% zny~GA*ObN`&k8VHQym+J0<9!YA?K&ZZVSp6FFi^s%ZNmSn4BXWYt1DoQv}J@4VPN# zcmdhHe8R~6^2GYA2|Fd>xov5Gd`#I>q+j7sWU6TBSY`R9x1K382Q*>lDwg)}Ut8km z(_*}ow2C37&SfLlr+XBUi+P3!@xNYkP7osCeVuBy#XTU-Q^QwS$d)-csHmDbw$hoGK@w8|M1Wh5oQS^OT=$DC7QZ!u z?w7zGd~cU9l01HEK`H*RB?W;ITYO5XgBV5Xy3qs2C9RnTr-tZJumX5 zThniYHUpq-zEr(KdwdBMua5W99qBW3&B7H>!zXQy!`@oFw{al`6P~P`kvY|?M`Hv; z1c|(g_`DwF>#zPV3o1Z5>)x*G+o~ZXE>w@m98gSs6gl{3JYd-2UnDNA;E+u_9IMi3tU1=LTpdsk8jHFKcoTC^&`Mo7#TJ;Wl zVs4m3tLHbHTIIQyl;q@wQ!e;fe-PUVEJAWOd#;wZGE8XZOSr`PU*BJNHGAX9U^ttc zE0mMGOm{twV|5+>qCB%(l>P*Ob6wSFr(_oW3Ye?cCdxXh=S9D^9Ci;#EwP3)Q0_{39R;e}CgY~It9nVwbLmn0|#&|oflQ$$CYJPzIxa1;71d|bH6p-3)V z?a5)o_8pj*Epuoi`(!i*tI*QMcRj{#&iL$vEPzk5QEtM*htc+>QN-5l?791Rsd`a| ziYxlc;T-SvMg++i|A08{hUw)p)Zxr5)hDGVV422g7&G_%G@*4rb&YcF+9BN%x>+;q^7(?Q z1o^lwCaE;vI=uT9bNRvXis`iT_T`E}7eXTdWC=M;zJV)v$HX3$FP0CzD7*9-=6kx> z;zzvAEKUvf3f&euqsxwxO)xkeQUfO-m8H8=`&FP|!Dw4p7n=LJL z7#Vg0fvki;w=UT_&nRSK@E!ISy2u?5k>_vPZ?YDqMVDeI{kgK`mujx1k52 zWj;+YS)2w1F2!7(FaL+>(+T+rA#q6YLAwR8n5+g)btmPX+myGS_h@X_MHx+3+A^9_ zU3>H6#sk$D`yBa4wR{727RM`XI&}+DBxA>P&-LPB4UOC2S~^8LjS}**(nNLR0vyAj zC^?R?vH^Tzg;vtLALck8yUn`5)+oEP9TX6mg8+^}k&(dyBkI1bSR*QNE#zHtd1~vfU-K9*1SP;w=z6}xEFw*+ z9s+nDGGxj*cfYop4^^Uv=*nA{)+Em9yNpNLJ?9<`oKjz7h{4K%;a0Hlq|$7Qs@ZDv z*8tJEKXzgBXiD6%{z(*% zM81$9u7cIr+|?9G0XR3wk1FLaQ?W8h039w;-Nr1r`2zVNh=XIbBdnxBTay<47LRLQ zUAy7)B-O;YD?$(*>rc#;gi;Jlq$0Lk?n`CRD(hmC*w@UqIWmxhvl%bNYYeO#*e1k= zSe*}7?g3O^%G-a~=Nnds1olI*G(CP)? z$AFj0A$eY!G4`i>^W|XCN`1fkjCq4uy8tRYZr!MG-mU&xD>l8{avCz(_Sh)mw+rYW zNMVMI>NRC5MBHz8IT>R0lkcAUbzEys2E0~k1<{BI+N?p3SMRQ+YXcGFI!`F&cV5t6 zD4p7BM9Rp@zg0cttb^mHl1B;8D;yYMozm6g2KL1KO0(}qB>mIFohKZsr=+$?M}!m3 zPl4mOB9N(f$}&FH;S5K(=E)s?GmkX6bT~+w^YboR;>swKgmQImuEa@ao8w?x#5G(X z)^aa@MyUH3s6Zr)ejOd==)GN>l_91~FHGV5^|eM#HRE>{0N+F2_5)x6)3@jpO}$$nFl{4I2U5u4TZ5>$a6gId#;}Rn;M+?pC`dI%5o)i$y{7XRq|bq z!jonJENWGGB<>h5tS@!3N%0bW+QDj;>Le#S{O+TpF|8?bMfdR9`3E5dIf*Q_id@Zhe@m5C~?;iuQq!)FL!L5z3CtwJ@{3C`F9!vyMK}y1O>YejS?~{#yOg!?Cenf zH$x%P#n1od>Pux5+cip`QHn`l)8;9>xl)dd#X%a8#6m{|C2Z8jMoTY_*YuAbj6psFzbUI6t2{H5K{3Q$&e;;UGlxQn|nft z3E6EEuyR)vfId=kdrR(-cz%NnwtZJEs9r@`HwJZ1S(jMaL-l&x_U2!~eGWZ}iqA0$ z7ej7btUa$bDW|d0K|qrNZrt-vKW=l%`{UOF)RdbuNPb${}E@-cF>+ZY0JRM!i=u(b&m3kczi2?}KMu9f8 zz;W#Dm$|Op-X1zg+iW5{Y58Q`qX5?OEjav0Q1-bwF;?E8tB4p-YJWJuh>+}|YVv~k2D zr~Mh;^Vx@7^B45-57r2TW&cbl^{qalDDABHGpf>I>Orl%4kRRpDM9`H1NxXQoh$*F z=-W$y70lY&NaseI_Dn5)4(%$(>bdP@nb^ZAYh?N~rNrr^&yl&77cJSn%_YCP)U3Wb zY3WLelV~~VC|3oL4w=6I1jBu|K0D>b&?R*c;iWa>(y993OK6@#b*c)Zc5&A8p6Li@ zN^RGh-7b}JD>Ld+dx_R?$`aABLNBHG(_>2M^5rs#;*)>?CY8Dd*OD%dC%B)<)u&JTKd@c*#) z)?aaKTi0-~;0_@KO(3{ya7Y3KcXubayAuL|;O+!>m&PH%-Mw*d+?}_`y(j0~?|HsI z;2rNBqkiZCUDZ{)_Fj9fx#pT{q1jypkT0t7{~#}uxjQtZ6e--`n__e8P(0x;=9{AV z0uF*>+G`|6Da$q;ElEofE&f!3lvp|eDF8foz(&&~?H6SN>Bv{8>tD{Z8|gID|A%Qu znD|D_UH^l&Ngdv0Y}KESL>A`IC`NO0IN2oJMLW|1&LIl2<#-Movm}BT<9>BiqxdiP z^(Y6aEnEEw!T*l{v_=8|i}$&8xU5S~wk)dkT6MoN>{}FU%_r_E*qOg5hWm^b-seg- zD@2;{+L*u!BsAhL{$cRUZF3-z!}WwQ?WHTU`2XjUaCCq|kBU5|0^G<-nnu{4YP&zMHIgFmFW)p(H01w*X#e-De-6oiN8`Vv@&CV4 zGC(6}PYMMAPM-+>bGv=A2!>QlmUCw)<~?PDJ3pdzw*065(@^|gVH}LCnCTC|L0d#$qNJ9Ml3%4F`R>!=N*4}X;!R{8f6)J5$az1*?Dwk^N z(JB{L1G?WgCpJ5~lcUbke=_Cww-gtA*~;5Rflo_RkpjcZK48h9Kc2B}qhF#p+tBq0 ztUO!W^p_H00KIJ4=MblrLnJu&?1mp>p)t^04T(=`Q(!DvCQ)A^Fv3o*sbkEO&KUrx zvzyLDv<>b)Ga*5kV1~LsQLeN|q*rg6XGY|2b-tD4H)J zgDdQALt9^L(OucxTdvmY&kLYPcFVa57%q>)iF5O?HBr)O=tag+Ag5#q@KOfPOY=$o zJv~k&GcxSAsUpVn4*U2rW??H-@#hgOh9q()Xkp zZ51u{XW+lYaeN!z%9cZ=st%`c$G*w8(yAwl&_1E{2 zbTXD7LdtaX6Ox*a7&XH%d@T^R8{ZIc^7r-r@=%_AM>gU63_1~MyYbVK*k6^mR31-o z*$7YG5u^Ik8Ayg}JXxTG6s=ia%83Br>xf6GF^MD^|4L=ZYQQ2fWGJ+HU6_;>&{IY` zz3~w|hpRkJjU3eEofLqsee&b5;I5>_&z7IW#h%lOJS@yy-d1qXj$G?bT@9k}RIaoPX4s0&o8#X>6X z?(8NA7`hanE#bdeI=`=2Bb{-SE3|w-w;`+wsAECScZdd_ahM$NCbJlc_np(I&r}$| zn@`u4l$_vpg%X$m$x6j)nto)}3;-3KDl!RQM(|E$?>8PuP`eH1KwiS{_+s{G6tROz zSpL{j3xsX6g|S6@o8F81Kq_#kx{tlmvnp3=|D^v>zq3=A!(rRTeRs!X+^l=|-Gk$l z+I(r#s=P*{y@~tTG3DM)Ub;k)<%&2Fk3%_tIJZ6Wm|h$-lFSfTx8SxY*@Syg;x15c z`1~v4`a~@YJZ(&1;(Y)N$Nu5CUoL0W;K@e+lT29EQjpn1zRu8m^=E903cE=f^le20 z1DzV-(-%_>ju71}K=cl4q<~nby%=1s=YQo`4(QUg{!sw*j?Z{wdBQ9Y5=w9qCty-q>Sf^13iT%NVcPjzX3th@Rz*JOLM{adc?o%*Xw3sRX z!G6Ai0+h?CcqnL_2)-Nn4%>3IT2#63i6RzQGp7;H0O@c?OLO^Y%WskE3kFJBj3CD- zzUp*GeMMzzfL-xl%(cEhB+}Sumin7LrS+six-zTce0V7O5TQqJ5eAsqY(}PT|DJeF zH{p8JxjJ(bJROG?%f|hwc6WFZ2OqwpWm1iLJEM9>H6KAsY}F>03RJJFin%F^xsbmi zsC7xeLmD!rEd_m!rf4rm+^Cd0Bt`|BEjHEHSd9K0V8!2!pK?9jOg_O=RIHW)3d{V6 zNkR$O(WbNjkqUbCYN~y!?Y_XVN~5A>#x(Kudc$6<+x@yF3*qOS-mjD=I>KeH1LET8 z>V&=MxVv^A-qxgDzB8RHjD6P>CS2>V!(u*FTu^gz@q&}87D#?Kj5fg%pZkn*gtC)& za%%2!X>YngoAN0uvwg`?t1=e4Z#dSfwuz+ItS;~471}wFfl!Z{BBw5mW!~3N4~oSM zwN$H}I4Wpr?roLjuwOPf&;vPpM#P~+O|n70a1s0A=YaOI=6$%@dc8OKE zE%S>YRC4Dv(?ANCxM7;xaqp$(xaTy)07z47g&EQxjS`yC)LH)0O3QQBXZcmiJKIcDeC~nGVI2&MqTxe|WDARC z_e&K1Dr^eL@<=k#*)#kNNZ3KKR%2~#;`D5LU>y6|VT6u%su55PQbpqR5?71fr6r9- zNJk_2D<@lXjKtt*Paioig-hm(?oT{4I3B*5$T^G^i>929c>Rl}nDK|7Sn zjCV=$e9ifa?TuA3hh+nhvXj*)CpA`4iv>zsn2EwYg6~?P47x+>Mzgv><7K#3xreK1 zX+2G%mj|^MbE*D^E{S2Mmgj&_Kd~*)F~zjr)eZ=#XF| z#e6ig{`|1@8|CRC_ImG=w3uJ^LjxLQx`-r&a-&^L>BcQB6>u$*pi^GuvQLFyCR?{k z)R@&9-IOkx714tW6-ItpR_dVZgkMqge9Jz~9aieKvtBEoa6MMOWLG+P_D99nQQXI8 z=+!$g-(5UJ*^8`{#q4Z*8BZAuD;o0k^Zh!fSbiLW#& z1?ZeCzoBcW_zv`5sLCWzxMv}vFY?f40OyBY67;QSCO2t&RsGPpi4Li~1u}(x>5A?7 zyL)B!Thg^dbLNzL@5L0(vseIedP|^M7JE_V{EZv zC)`DSlT789E;r(JY91GyOdKjKK|%tJ*SQ3KMvN_I!H)Y4Rv0M3rEKOG7L7yxVmCt# zca;(rS*V;rEkwK|Y*%swY#G3jxSx&(s59!T5hI{^W;?r~^46p530y1@4L^7& zo$d4nksD!cAAlQY1s-h;%7;?8?Dv*Ggd?RvNIV0zpQN}tTalytCq9qw6&97EUL@aX zOX-+j?tPcdFh^dDmwOB^#ZDzHV^e2 zx`F^LSHr4#kfCXL;madG-|_l*ntyT8{o0{7@|5fTIp_YS_d=9xv)}2oj&qG=#kDbF z|M}|tVM|^7-CSw$Udud#(`djJyzj`iTgd(00sv|fZ_mC-ySl+>jq^G+r%?x{ATF45 z_}|WDh7}UI2^-$Oa(n2eS`9zweEfmBcK zjv6fu61f9pj(x++(SO>cdGT125qA<(tCX1Po);m4CL!zmOrmyi+Kru>JI<7evOdgl zdS4$Yi5%X(It^L?>C7~By|RKQ7isg$JoWNqmZ)>HB-P|%I{YjRtx{8}ox*)*b7oX8 z`xC%kG?ge}86geI^T5#tMW zej_`woQ)mMsA2*V^d&vt6JrqX@z`fqfrE-s1O&spqYmAdJTJr-Cjc^!A*KHRpLw<8(mWmMqUn20<6+0~Bpz3`cdh{PxZl;PmCTZm6$?}> ztsm-`s524>F9~_K?%c!xDr04bL#)yQlNU?Y=`oEwohA<4KvN6aGdb&gpiYtxVImMW z-?`u0>fWReP#YU{zBh`0=)IVCKD3E0=F|3^e5`UNekPBjM#5-^7KIt3m!+H@tWgO&Ibl0#Z6s-v`dxXOy(p9+^_Lk zH%nN3goHXD=HQV;Q#*MqYMm}t z>tF9zF;eo{d!xhc?X-Y;w4ngU02|UVXbd#Nti_(owl(0%@A4Y>iap#6b+scl_tWO z=bz4;cPfpHLqW1?c%)(^e$s3>j5Jr3Xm!j~V#{ehzWA`+7OJi7ZExYAC9qIszcWr& zZ4E@8K9rva(u()L2uNvnX!i?PoB;K%!%L(a^{c$hE;16H2g(`rHR1qP&HPgNV_T|a zz3PWHBl9AZId*CB%ITgVec^R9U1nswTjn zmTFds9hUCV6M^pE!2x<2_7C1eHR9g@ce95zKMX``#c?TcRPJc+t1$t$^*I0BLgWqL ze}wxw1|SvNN%Q5**a6a1i_Gbs4*`x#KS^(aNngdlpIwZiPf9$ z)S;+{53q$LN|B2&Nlxkfoxy3xcD%3*iPPaNb8HOqQ_Bxt2iJJ0#fvAWrvudf@M>^2 zWQnV<#M8Y~-CLX=*Y3)pA@5aV1y|sN+4Z)%D~Q%R4g`2oX3FBPrOm(Bf1fW{ z4>v`_;S}ES{QUyLC&0(%3y{9gykehek;D;})fCK#c>l^q%P$AHqvlSGLI6}@5exOr zPAKW+k$yx}u@AkUEqsl2T{bZe9nNOebGz_0J27aG zG^Wb)K3tTe*Rt}`Deq=^uGXVv&f+km*H=V|FM$?w52Clc_?iv_KLXKE6t|b%T2A^R zjWa>lf=tU@93a7h?+q8vPXWdtq!6FxK;9tTrK8k2;)erpK(?Ug*M>j@4)5&U_;$yRqdh1=FoKFTsB+Qt@}l{W;f zaI`_US#icT*aSeHR^~cX^~0y9J}2ekY6uV1$Mp;(+za*< zAH7IIaxiiDWry0{BOwv0{ID-pl`POT&V!V;im6ztVJ-=SBbHelfc`%(x|-A*ry3Sl z)a=LU4Vp{{=O7y2FwYjM3@p85dtM)?HLUHl5$yt$kc+;X&Ul^Ps)+=sKpYy!Fy52$ zd?cbK(Gdn0nYT2hj@USgg)={|1@75;z3yzvIx z=-|9A9fO|d6u%>+s$v59Enk%*5uvd8#c-9Q$p=hR6f_nMR3!Ea1bu)NhMUWXTPv+F zg1q4CkoHAJex=gx2bG~C-#eVHTnK3m##M}9f#0F95A{K(D8ea}g4O-6siFsd8H#H`y^JUCw@efsvFUAPM}L3%L4G=5M;%hyxf0>h>6 z>sQ0U{zNaox8CfUZ$3$ych@Xgau$uW_wndE!n{S#mPv;p!{LVSZRoplrrgd{a@*-6 z%N#k;V0kb1MU~@`dyC|Pi9m6#B5J}O`(D^piP&=wQ6@2K{>Xxa{l@LIPhwcj$jx1J zW#a@&KxH;(i!9?rNpc8a~J5zA9&EeXDtA1=0gD-T4 z(xz#HLD$0Piv#dHjZB8cFZOR+p*ldopCj8xNR_RNiX?PbmjN*avdWu2_m}6zKNfhk zHqm*ng7OAN4Kj*boX$`;uT9d&q%d1$vkPN7*>hZvN*(RW6zikft*fsn-H5$Lxk4}4U&L|Kl;?k= ztTD&!t~PyR3=!G_8PV{1sWlmrU6e&a=|||sF_!xZy2hrbQ%bxQ#x*O)Dg>$pP;8KK zb==5f-UlK2dFW2U)G^Q%VU=8g)=$UT#?C{8?0FIGL-X}fKCc#mbY}BhUoV*=5%Ez- zwz!2oP{=d#aZGz_h0q8fqdbs!Y>y&LQ*=;{nIH`bOGc26nnU&Bsn*cr8RgLmu^QJ8 zGgCR;U!o1^P%GP%8WGmkd>)^p(Wu}x-`vYDl`0L81RS&hp0%Y;>P-V%z6L?MsAU?r zHmKXg`9sirzsA~D23@&@T>CW*z;i&a=KduqPjjHFRTpsW7z-y5qNEieh>5N;36zq~ zsKp#vbaSX8?3^NtyC@A^kNcR*v-v_k*Oh9O{Di5Ro_%(jxqya5NJt-AKA$J~Ek#Ol zIM9!z%KY^e^DZzzc=Gdpf0WkqeiAyEy~a6}=N>}D}3iL`SS4PcT9rMl@Tmk*_;O@z+L z-uOCpKSq4Vpp~i2h%-k(^+m37f}yn%~@D_r>WR=}G}UTc~KE+=|`9eN`{ zychyw8ILP2Z2rC0(TWh37> zRHv!|`_VA`2#G@+4-mzkzCrVM#_ia>Ijdqs(G1Nn-J7ckDdEhG7a1Tz(9B=p23h$B zk@>f(`r$XrN7h;f_Y?FZJ$L-_9)3&&deva}U`jgqb*aS5_9~a{jrau5ivyy~>S{uQ zqGD5%)Ik~n0o5NcoiZP;d?$H;h7dR3cwV#gEuPX^;&LoUSY;V|K-eTcvT1Ve0EiVQ< zYw!}PKUR9Fb37do^le$DyS2sAJ$tOb2FoVAbKu=Or)J>E6F$tKJ9DbCkS3UZuzl-S zDGFCgo3L9KmJ;HErW0#7%l?SKqvHR(k&>XO5%%5@2wHTgGI$S4n1AJzWjs;JZ6%uU+LrRt}Q+`Q+REbccc}CV?!8{jzUBl~zF`E{@27!$!|D zs3~??Zs;u$d;ehdga{tl?l|FNt&>xY-YRlcvAFbf6NRs^!U!`yFg$!(I~?UK!fluf>!#d0 zJUrfs)p~v1IVFD}O?ALj!j&Ben};U9-A0eh3W5^@JOd%4WsbilweJGC?6yN%vg0sF zeHwei56Rf*{gJ2&H4Fq1rFczDSZ?#9{p?tQV`LY%NdyVK)bwhuSM$$A$Gh%K%`28r zfobR-Z_OD;b4i%hPnP+wdvYbpx6h#F;hiYgv5A4SF_yz1X}{|Tt&e-r-=nw78sx7$t&AFy}&Bp??OO8b83HDw3aU(&%Jq`OMy%TbBQjQK7I%GM)JY z-acc@JT}leli}C?E>+@J9syvZ_r5#M(~i(>6naQxsCrRw7Srw?v7G2j+IWR*fR7y$ zm#iau_addLk!tmP*1Y6vFp$cT)%NfCbuaGU-+1ja93jELQn%pIT(3W4bg{TURZ`^K zLz(Vn%=9a!XrR5S3__gRY%tdBbAja6Rbw&xlQa$+cAwbtqPu*#0IcWeSAM%?0?$j5IK3Rb^THbEGcpiR=BmYx9l+`w({N(& zNHg&kUhkY6C4ZEz(g-?eaC=2Ji)6g~BJm3LyPxVC3NiYM1Ejy+7UdDZI-R5Lh=gA4 z0V!~0g_^uj^Jp8>J*y#WChbjHJ6N@1KPc!P09Ax1=B0T|3{~dcim%}rjkU8GtNqHD zb?g;N%R?bHbh|v*F*-y`b6mSR?zB>R0`RRk4*Td-y=>_{hImgM%zM{~{Y`o|Sm1bG zE+59UQ`R?rU^JLB$L*k(hr9+Ww|eo}pDU^Cntl1%dqT}kVwJJH*46k^Y}vnH2(zcY zk;+bY1!(DA(WwO#n>STg_}rk@ufH!^51WbX!UgT`(CH=7(Q%dGb1fu)vy4-n%<$U5 zm~b6Rspp`kIxMSKKf%mNp+$fu9_&Mmvv_q0ADo_S1)4%>J+ZUD5O^@Q;p4M;1Y;hG zaB9)T|BpSIbSC??v+I{qF7EDQVU|#qEjqN`9u46nPb@QV)Ytv{Smg9-g(-Di%i9Kj*ibhEO|iMY|&xn zlX-w-e6n;RB{LJZ1d}S0k0Taz%9|F1-7ioWC!$=W2`|)e+21|yBi;iN(Os${iFN(n zp|3bj=n~4qP8FjD(YMSsQRsd-B97B%NvV{o;yb#z5)z2W*Nb43;|4P@wby)UUm@`> zj&n@3(w;KV(kWOc$o1mo;DA!4X}Z5~k%_dQ(ivtt1XKZqj&yqfd16B=0{dv90W#ug zgK&P+md6Kpb9&#M4$Kgdl5PI$GyCD)*G{Dc`^}HOfrI;XV2gC@gg19Ug%wLeFv0Ze z7bBZ7* z)f)$rT4;RO?4Ago!?h3Yp$nx=Fm8#iCR*rjt1uZRc6!ce2xb0B5EuA0t@$$8K4Zw$Md#< z%3?#=ARSrZ=M)LA`x@-UuB*RWz0$>?C(U=)OfZ6dpXTeU83-$`4U{~uzAdAyn=PK%@Y5KLTg@@M!<1Zj5 zP~1%@$Z(+Z-6im$DTI-w_2tW{;8U?;%nPqIf)EFz+|SVxp_}MnUvQF%YMYl5c-AOU zyuRok6(y2;13A{W%sQv4P~d12?^fE@Ej%Gb#;_pp1WPG@gU+GBX?4FmFnU~Yuw9@x zI5?u?T=3M3iyS)VT(F4kD98E&_h}?%#YU*XV%ugd-RSesLcMWEkoiEUKD(bi0lS$g zxbM!$Cu$4mIaHUtHIQiDa&tpaCT*6Jzm*|b&O2ceX(cnwh!Y~q-#&)!?Nu*TT2deY zFN1y{z%hFMjRi6f26V{)44&5=sgw+~RG+zFSGRMr`c{JO@$}KYRLO70>24^EwR^$y z@_rLQ-_RZAp@%D*au+IX|M{LrHfVY;0$0i9j%6B4ScUYyQaQl-8=A}Ayqf+PE_5W~ zz>A!+95)l#7C)XV6Mp5kA7`5kx;51{H(KU5+Ep}<%-q>!q_g*mR7=%eSq+BBujPgq zl!w{TYt#-@`PdF?H8(J|8uiCFCL1u&k`b9T9E1 z&taZXIUQ|G;!eQZ(&qNz-3qrp>>gD1_pS$GM>5Rl=i<}d&ewhvX+iBHpK|n9h-wzG zVQ>*FSTpg1K>7bjtO~~Ud@v`U^}sH{>x+kEGTYd+iblukZyc{ml({s*qii428$cZ^ zmcHWZdk!Bq^P09?(;Y~h4Z`8wO&4Q^u;UKmL4;h_TysjljmFfvX^%XVwO&tYa;=)V z@0+FFAVbP3WcUm)+TO)AJ+=p8Ub;jy#-@csZi83I2F=S_cRF#$JVBhyMptln+WL!b z5F#+)r3xf)tJpj=5c`<$75|;t>F%TUrT+7JL@xlwH}1*#H9#j929Masy4P1EP9-F( z4C^48jM}(LBcm6_qI(~Jr&Fu!W0e#_&M+J+|AMNC^b?G@7w*7J_T|M_)X_3lK5an! zU&nLMRD;4>gUsc8KXU+awXoYNu6Fc}-SQqz#WVb~R|9(MvimgnQdkw}Js4vo`#h}W zfudM_^v;2(Rh9t|fI}Y4XwOSVW_YE~(6Y{Af3nOvu=HqKT61A1kg@zBls3m!s($Bh zqBGl|(!ejovK$xqL(vqU*`%w}(#nM$ znEFD<^<7tze%&ME6^(g(U0w`)`>NCxluWNphh(1~#hEG@L9!coOL93QZ;Og7FCyBH z?SXM<@#_Y4N}n}yOUXX5zU&CURm~WdcBk?MeVJk%nM{Y2{|U@+{YF1>>})|U!J)@` z2#2uyd#EoQO2V=u^*~1e4$oUcQ)l{UmKKI!{#G`NnYJ!PzYPM-K$%w#Nsk!T&BbNZ zj0Pr9M2$;?&Uz+zcw&DcxRpVIQ}vo+OH$n#Y7>&}O2^)CX#6x6$_|y|1+s#9Tzks` zPKdwu>8WPk_*c-cNJnKwZ$wylEyom|&_#*^q1ud7jF4AlltoMLW_+Kki}8A4n;V+< zhS>5=U~47T!tG9yC3PeVnE=(xs93`*ASuE&yC=_$9t;Wy8C#Qnl}p;gDVcgq$G<<( zu3Ql4fpJG9P87;FDY9CuN5M>GPa1TLBLT!q!AdU<$o`5=d#s?UX}1R zGO|sD!S>NYfyi4E%8mWq z7qWX5nhg5apchD2N%SgWruujGI~ zu|&54;FY2Jr-&nEtO0yKFIeb%0}-)(1=5Gvh}Rzmhp~`LnvjcQGCVT>72-YJ52tT& z)kuMQO>ih;GbwnXyB6)24S*Hsv`A?2NtQX14dgFRbnsHSS088AHaZ016nO_r2QGHg7V*I zj{SJ{RX$&rwe@TF+Ti`~AAUBR=|EK|(V9Kr`)9LPdO8&fqobp3fF0*4TniF;HXNkr z|GM#W*;2VsvBTAZZK4gZX=GR+F5`bO!3_9wDkp+r&iigJdd5%mJ)f=E1kA;t>m@P- z(=d1Lf}0&7%2fadVF9i$Df$`Wo(;6i^A)v^f4^*0Xtjb7q46IdK9HO&fP&N{un;7k z4SyYbd1kQy5^D)lD8R1ebKymd5Zr}5+G}SG`aO70VM+uKERBi1(mAq6ERB+6XE1JM zePJ;H@I`3YW#fRY_n)ck*=_;xqB#&RyZICw?z#Zd(`$;MfPxsmjpI_>jG-{fmHIbk zy%8;_OzYr72*U}>SE5-DfR6>41+qYswi8$CN=0&6H&`}RH$9J%G4!M`U)*9Jv#ET& zLd6pC8tEN&dIbvKl()JjRZ-7+f)W*y#CKER27-a7eR`#W&oT04tE7LWd|O2{k_PUw zL_bfzQ@qwSW3hspn8uA|+0F=4j1&z@Zn5uC+jJEmiS!AYB!|XEhs_qRt`ma@hEr&i zXhP)cgO%tY_6YC_&4fYU2>|Os2t6nEVStghJ0oGSGN+9ubQ~Xkpf@VyX>5KU`0q*c zaJccuDCj8unxB8c9sina9pn);LXiejNj!gy(bJ6mbCCK!d4TPq-I@P>nEyQeH)dj2 z1y(cvE4=?}2|vw9Ula<#0O{wP#36t30)O4u@3)r>Ai=$ZP9`P)>u<9p0BJ4!1s6K* z|LxWVt*`)ajB`GrkjtW^6W9OdU)(w`_Pf*@tAv=euv*sMhM$JPWc_D42>J4v_Ec?_m8Rs0Oyi_w(;0 z|7$6e`hF*im}F34H&evxPf5a`rlMm)T&IDe(l(zgHUhuqw3tz)d3mKtg*brrLTSM8@kI=*CbVqFDzS9kQGJ9}rX(W)Ld?{C9IAyX z{NE>04Z~K-|1dBx2uj8U_Bm2}#5N_YOS^_I!vPMFhTOBCNWnl;U>5zm63uChjkW)9o&CF=LkVpvL|vnsfEB((FmobBg2k4wr)VvPDTFxGWuYAixsvNOEq(NZH(}NTOa#KN_6SK zJ@!e#F#!cJ#vHmyrO)xS+~#j%i6KOajLTi%Js3{ffeYAlBJm8njfuk@hwO?EubJ$z zsK}nqL13%;v!RpvvSIXa2S^7XF}=zIrj;SGufxLl&L=Vr7eJ95Bjnj(tf~Vj{2zCP z_jFg;WIkrsW^dxY!rCPZavuOc5IJAcHn)WYwMbh(Hdaje*ES%?@%!=|Y)FuQZYTfv zT!D~HobpC_mq&Lg%mHKuR2_T!SRRMOsc1hCb7JK`7Vx>Yw<|^YMj*xgdF}@WXg?E61oNGSKU@X!8!hSFx zGSDTJEHBA?DZaD7V0ZTLe^(2K~_mj47m36rBS4B2t{9OqPRa1J!f#`Yk7c5|vF2 zYfc@{bEz@*S-IgkqFC#(43{^5y|O1Ss0$;bUkOPnU{wZ*e9lWM^K?`a7v4;H^?^bYc-xq2TM z+3#}x(jkNHhu)+IP!dwn6jG8V_@El|>8XQm(u4NfLyoP7+xJx#*LH`54B3H# z1ac|hH~#B|tJ*m%u6>H9;7fs-$=VW)5~J?26%|d^T&&6)@D}k z$9r`9^T{j;Dtnu@{<6E_yLzu?e7D)R7gqoeMsaoLJ9{#x^~I1g-qD5^Cw{fV&RDNv ziTb2uI>)cOyHiFE)XR5|EDN}9d$V9R%pAC4#iIcC+>Twrfdm)mfKLG3T&hU9F$pNV zNH`~$nkUT$1jamdQy0#Xg5P5G%{NH3%+ehT0a;NKsD ze`W)Sr}5!p^WYGDl7<8d?63QsJh9EoCGSfUY*1L!Xk5vO6Fbj0cKBkP7j&AYPvCEr z)GAAXVwpDB0h|@0MNdV=Bye{XeQ@Hn0u3v{+++6bHJjxPiZuz|m_&x7S4%wU9AtJ& z`)JB>#kpdl-e_Rocn>>VwJx){6Aq&^S?IV1t63D|OS2Tj1JajsT^%bp(Cm&&^J(F> z!t)kf40(++tgum!MNYJy;I^8EAe?u5*Au<<0VrMw)i!rgKHnY%uWxPOYnt?Tp4hB* z^ct^Z3Jdjift9n|*bftMX;s|%WrIp?Ph}dzK-?hf@z=fl=Ge^wYq6O7EqSV_$`Oy7 zL&=nP$_c4}${5g<-9r77;3W{|^?0`Sbm<~D@UP|!KZUt}j#(MN-6x-W8ArS;9?;&E zZ(hbp`_|NiEs<%(lRy-nnSFP%#QXxgE(CxRKpiWMJrBv&4MPovARgwR*8Pjd0icWL zhE;9bPxQlQeNjaqQhu+x_5EdeG5q z+9|r)pOxxl74d}Fbut!9(s>IjkO5Pr1(U3_BA9#c3-rNPi0C)|Vn047(BAD?)iBwR zzsB%NX0;zF#+mD5J(a$I%9v;y>T090ltWROj<=QtL%la%$01}>4FS+54D26)Sw!FX*m9BF7=_J z4-re%=k9c`b>3si<<#;Jg9_uI#r(S}T=hk5Ju<>`&ncZDri2>gU@Db|llXC?5xbPe zUX3nS1k)zB^Hc#rO?Q;9rCkRh~i|A#mYn5&mPFwG)VUEG09q(5yT~iER^X4+%H}0VM0QRLGom*~HG@lH1oLQtihYI{Si z9kHI*#fMGNo8L`wT8!%MEi%ZfD_U&g65SO#2qah%z0>T|uJ`LYitnH+mnr^sU`c)H z$e&(LD3Jd(I4lMVxLo@yUSJ?_Me6oc84okBrFl(BTYhKU*-CW}6S6=Z{z-ww%Vh9JM$E^1(RKyT28l=P!)i#`fYUYl6fAfCbrF^4=5RX6Hb>6ZF5|+B zYP6ZSPws7neU5KOtL63lK*Z%1vPNir;Fhz#qE!aY!P+HE{kK_D@JZ>n8d}Bz4PIxH zX)GoH;d{!?^eN{%LQluEO!2%Qk;?PotvHdY6YtrP0f!ZGv19pRy2)dDO&Ar*okxpF zv%gaUr*%v6+xT%w-EUN8dcts>1P3Y|j<1+9TCbP=!w2GZJX0fh^jIztG*On^+?%+v zAKRZ_qQM4do1}RzGL&Im_B$ZQaJ7CzUIA(n^?@eJ7R$s=J+JQvTd*`x?4Hu9tj0qq z?1S&p!Y>zYeU!AxP+=LI;f6b>wY|r|F=KWKCYF_#CNt1pKuc$1KiH|j)m#k~*RSag zel@#aqArt)L=%u1nmT|8k=>$_H|-yO6{*A%sPysIYEebsLcP5s^M($U(pMCGGYk`$ zO4(IPlzYc7t|!NVmUJ&vecHI6BO&(4Wsb=C@=TQ&9E>Qj8uclDi#)EXKaV5W-(!-c zSpTLkic1VIXZ3Jl-$7N`Yw+nX%`+Kih}ofTiTs3n9Ev^ zbFZ(~WNedsu~zlu2zA>kMB{(XFvNab$+SD^rQFSIk9Q(0I=R0TP>=U-7w#r>+iv@U z!_Bj=s1sd&J(S+srh(oVffb#`_Yrfd!}!|_-iOXXseb4U%$H#2VWLI4j}Mjm)Xer1 zq1Kbut%EWwN?2s=qSZ6c2FgATT0Oe?ZIz7 zGlcQnkKEwV(!i>cb?WuY`&4HzfrI#frCxeX?_xSL^2+@6HOpB za_@zLR8;{6lJe{!Pi)bjJr?-DC7z)lHpP=;HeIUK&*Qx_wki};$J`rmytZ^2!<7X4 z+-Tfnpt>li{>S*uPx>E@UTI)7I6>J3eArc>Ms9kK`6}<;su7Ms;ARFpjYSl_Ekl1| z8`Avp-TpjYI%H_QCLGrByn9KgI3eW0z2JUau&w;1(2*j7AGW~BHn!93{T9HV;()yM zVavX^vIJ|%#RH*Qm{OJ5q_uCmQC8aC{K^Sp|HoM7Pgsr$Mq$RjLYz2^qp-d?O1e^O zb(?}$G$+) z>*=tTQG>iKk6Z91rj@(w=I^Y+AGlHw5hqz@`^7`o+YE7dLIf3mhi?S_zof8z1sw}5 zsq9FB)Ksl9k7^pby_2HwSBUyVizmE+cl|)$e$QO`vyNeYx1Y=O{0_(5iUw0`CQtKb4WFZkX!67RQ;mf8y2+$-?j% z4x|Lk;}DUUfmCK01ACnF6}5Rn5nF`^B>vupF}90OA6w>BK%tYJ^;3qT7ERoH8=haD zX+1b=<#dhbn-D%^cB*I{j~!e{CPL@imteYEOn4Ne0}7U^v_5%TTM3b$fUDtEcxlqa z@*ZlBrVqS!%jUN&?(u2dpGH(Kw6&@mX zhW%m3VQ+Ivs2miTgzeaT31X0PIg~%sj(;y22wBPfataV!NfB6}1r0co0PU`M&7*X0 zjSvjgfVLb7gN`<^!Cm8FFN)e)u>{7DV}FQaXuSW1DRle~7bK#NW7&4ym$t@Hp}5gV z(RX*NvtF4S;l8`?KNkV45L)Z%J_a?bIq5>oQU z$hR&M*+}GBAL>BHSAhkxgvorJR{q8B4mMdrq~;5>HhMHA?%8ZKyxu|%(_L`LFVq6i zPJm~tV(?ZCqX?>j6NZC5NY5&39Q8QfP;sI;yjT>DTX#GW}1a-!2*e_{FMkgJV0D$x1Y~-bTLP&1)O`AY9_) z0KPAw(Wz772!{CeeGTpGM_3O5F$&4osQ(bgxTxO(So07Lw4OGozyyAHB3+or-D?|q zq4Lcz7N6$56WS8_?y{I93R^wD><@t#SP~{xiDad;-v+k*9G>ux5VbLN9E(vL8lmg@ zd3n9n%5R-j>XWM%Hm3{`)FDcn;zz4e(zm-#sw8^L$WE*u)z-BjIbd(^ zkydfC!v9aNY46RG*R+2Pb{23ksfl@s));~X?Q3p;XzaN|YK0e(m+m^$K+(y~zsT<_ zm<}+!&uyGZpe+iQ@8am4YKzJlzHw|%pRRPl#=llse(+Icy_y%(%yv6J_)Krj)`DCt z3G}Qn!`K_AKjd8UqJ*iTUC5SK7jZY`#k%u4S`lR)H=nHx0C}XEhpWA=a^7)REMQ7x zH?RF%VgFi&>bm8zWybCkG7R#Ybt3Wv%ufcGV2^%F79Qnt35k*VnXfO&6O?*m-75E6 z@zSkJ3B76>6Z>;MKAUc+J#55YyeuBSn-y~Pf3|je&{zis_~|CN+@J@=G0$+*h8yHM z0aa9?(RHMluR(IyGAEsL=*ND38H78gAs%Rw(lzZH z8)lyPyeQZ7Ak@vP!As#OgoNSE`eq)>s<2>A{m-q7JOlP6j+)q)E3N8n6;_$t$**me z`T!I&r;0fm-Qw+BQ`)a@mcpGK#hBo9&h(K$((jW=Hjc==s#ac%YDU6eIvb34%~ z>bK_zmIQNGTa(z9I+xS2VL{SfWSSxshP$UU-p!imxD>r4Pv^~d;h?t;tU9`UscKv?B6<3A8WpKUUP*Idvt z{A%xtFowRKtOV=DyFy8Uaem;`yRF+4U9~%PeDz_WP->5NOua|anJ=q%`*Pf%9FxH!MgbEvfje2gj$7~^ z2(DPOzRyb372uANPLybL4|QZi>7IX7g^eJWn$B;vV9y$^3q z}qRs@7a{{+?$#rzEqC(Gq>q`LheVajh)*OOkH3<{65j%%_0dB20s+rb{qIUSw1P zLcmyv-^jqmZsXz!HxOtWP8gUxp658rBAtBwfX2-Jz*Q{ZjtpTw>&+o`e=!IofsvFA z4U8V$X476^-7mY;`Q8Fi>P49cAZVOVUl<3;z3W*QKn#4~2gp3$VtysyrRui>^sI=Q!=gP2U+-(T&$#tTHw z8MZ9RJ{;RBSv+l1O580goIa{Sl9RkG94tA@7=B2T?z~|SF!uoLTkEdY+ou!-2QKF7 z+EV&QNd~|q_B2HQT`L2SoRY=v6>IsU=-dX@XP=Lts;919r#UL7Hm&%5GW)7y^_qL` zvl+FOHTHW$f7QqF*)_4FAlP%~TaTm&6!Q z|J^HAXw^>Y=5Sm7^aL4uijh16VCkZra2o7}Ivw%&pu6q?gdnOx#Tat)6d3rg+{s+E z*ARUQQv&Zf-}j>p0#DsXVcE`fFj^?QB#m{qU;GJ(N#n`CIk zNN%XjKiF^YGVI47t3Ku|{&Bo!>;i{1fo@;lX~|x^w5D=TrXkxLj^%Wo`$Xw)Ovu%2 zkc)(5?obIRppd47hg1=%o^dW%dHaZx}j zC<=8kj8fzerbvs@yO5qIMNYvq#@B3Z7sd&YGWH>^jZ;033ET`#=y(=2%6(0@2Uyv7 zF4*aYQtO-H6)(d`diW&HHpv<=1_&+EQ7lOTyM(@eT94h@n+M@0QE#zK|J?gPV^j#% zG5-=M)e<}CJs(vN|A@(((_Pq^*dVab6ri@=_m^^?+ftA%vBV@si?DiT-U z7Z46%I{hwSD`IqJ&#EC1D|!`|bw+Xhejh5*2lCtYH-mkrHTu3)`_EUow!&X&(rb?` zo`SI7rHq3!RhX_J0 z;~S-ekH|%{2peSqT~y-V5*F>cn2d=C?0$3hv=mfztSqqwPXHn>t?Ul3W5Re5M8)a^ zvFd2jq|AK^Xl&;(UAbhRjnP^p0_US%k7HB#8Tu5N#MkirkIU8~gb*&s1LmdoVLWO@ z5&ps}$S)xFumoE(pmS@o4>U5mEcq%C|5zi|#Jx{fk$ZOJy|=BITK*MebjsY#6CSXB zgYg{@gb$DJZXL^RQw07*QJt3HcqU$BdM}=LdxLLs)Y!C2VNY0+6`9!aAc+tqO4!UJ zE>5PHI~v@J5UG9Nf+)p$?A$*mBe~Wq;M32uGt9(VH(YafxvxEvnCsj_{B0Vsx>_iV zoh$iQ54r$7`QrBuQT#FQ2)VA9TyXO>Hk(Rw3-m*t3%CQPIip$bzj<8XHW#ZTS@C=_ z!w*aEoTDz%=F|G>b2Bk$HnzZn!pb91<96Qvi~>O+OrN8dk#Wga>v*D|EieiL1(U7) zB2rtGK(S94I~aDw$sYWD>z2rX^EK-8LBl`X&a=$r#FksC1l>~W0By-}y>gu^43Wnl zk;XxP*5BW=HhO}1*`XD_!m|94N6kLKop!Ti>qE zWq-=WVKYY>{&+s{I#Gc5Pq|zs_q-Uw98k}h^+NY7sH!6TKBl`gh?`-dSzA-4(xSB* z=}SDl?9j(z?5Re~Ra)6E$bX&bKgXQw(WXaWf1@6l)bFM}(PQ6 zlR98CS@;g`mDbwykE!F?vpt}CSU)wrNydQT75N=~mQ1Ttv5H9#!}JaDPzm)hPr8f% zY+S$7C$!^OSGwkc4w!(=B@QBUo1J7dRgM`L=rV894uug1u$WiM)T`+rAX#gUFz;ux zn)ur|Kc!-NgjbzXlJkWs?90@dvR$!et$?ZB4)HwgO zkGC()4t9mJnuGtcAAEU5PW`WpDlwvFIuO`_xaCNB0Wqm7DT@pYn&baDQEjpPz>BX| zA(P8JyJYKIvSt~0q2{_InMS8mX^qTn_nG(H4Gh0xvJ!Ck;q7kEj)Ec?8^2My`-(;C z>ipxW*sCka3n2~RpYaE+Ql44XSK@Qi=x)~%4`O|{nclSy`HWdNc2KQ~l&bQq`4Eva z(nWtjAu|#exp>b{<<6f(Lt=QW8pI)QsgtBU1DrXY^%Jzp4p5^`q0mzgHMt$>@Ma^U zm_^JIJ?CS{%SGzdyt3f3rBy+B;s}Sv)62vcb6V(hJt{_Y)#?yf)l~|9f10y6_`x2i zQv7-ImsvtT{)d%_pVL37?EB4nT|*JLs%Yvh1(0pAWU1VTUFAWj)8d}JMQ9MM{G$p> zI(SqY{fyX#;6_V8W8bK$QoDF=_<)TCAgHZ9h`3KU6b?E-y>>*lG|}@Gw+%ge)6ILe zPOMi_yVa;`&$--2^lOJ7NTk^K#^F>P;&!19f9@YeA7;{Mee`9}WKtg5XhBS28m&U* z>pgqB*DPu@AMGE(`5!NU!K0=*EAa`hYvJof(|)#cpmy-Xpt9Aqwzoqg`Fjk!l6hpL z{l5_bRSJ-{c(%nE$~{dUOpG~u+EjovD=hv>Bq9+N6qLs;{qg%4(ep+2;6--RU?&E3 zWMxJgVZOI`Wn5(m4g!VM1`Y0k5p1I*@M;BGSpXW*)J^m)D}4Ay^$a| zz!rEIH7Z>V$3hvf{K> zJkn{X>sZzjeK|yec<`u4A6Um%q6QKnQt2H`a1IBkiYBt&fwJ%ap`5z0Y5!gfGP3TW z+L&M>BNtFVk;XuHue6b^pnjt#okRr&BO~s$t~v!09!URtykdykfnu}oTyX!?iWP&4 z{vsYC2umY-Xp_Ux4?7@?3h_OBfLhVGqcz3;=Wk2(mvm9HdiaWET-3KVWGMb7P>wdh zoB00=Rx>_ZsXGQF$VN!5lfwWW2MJ-RuQ_Fk)`zt)>h09;kBEDnt3TuM4kZ6^ka|Kpp zG%kg981;Ru^M$*q0unk^@y7ySq>1*3vquul&N32d1w2q^@z1Axkbf~p2j8^)|GQUb zkVn+!v-QNSkV#@pOXsmlWmGR$sl-PLUz9dP#jmM5kbd^1zvXjDhI)k+tOYj;``VN% zkleA$luL0o`oB3QH-f-SrCo+4pnY39fPiKIR+>W~Q`Ni=$icR_3nvV;kKe`i@ct-m zr@ErgIs+Nt_%1|29!~+YI+@}vAJ(@L(axBryh0E+1|fM0HXsjHj( z=l%cBahe*Zp)>X+yCv-12g|tmK1me znf}f7{^wi&9>o3r%bae_n#}(*6ZN0(cKQyar1<9#E4cr$F8pWQ|8LO$oFf1G`2XGM z|1rP*1s(kVbb9AH(GhhDrF1xL5C7eo7k>yvH=D=@jYTFgjW|03n9G~)gR15?e~HpY zyJemBK-srS=tu%?OUr8IIx`h_M|=P=*Q+x0=JxHakaV_wJ=bsU*J(@3F@6RBG@szL zx+XN#XuCL!)%}XajTdMv!;7rjmjETD#2`6EYRX8 z2m$=lbVN$Lb7(Z1i*GN+uX(ax^sZi2ftPS=AywGB(Q|8pej`We>!&aK=ed}8q2rNq z5;P;j_^-Jw46l|;nk-lS_*6kFJV{&24So+^b%2TNIgo`;&7o6>EL-~l>dM}8{u5{h z&2r}jN?9C)OltMuMxgr63;0{5X}35Hc1kEUDxCR+d~3g3P&s0Pv&GmgU$KW>h|byl z5_Da;M}Cxesq^=il?J?^s5if^0)7jxxq`g+WbkP&N3a}GUo%P4=5q(o#`576M8Q@fX00%&Ppo_Z8VWU}}_9YL_L@FjhNAM!U!~_c)Ki)=73rqP6kGPCD&x zIG_Xcf=lAhovOD~g+u8Zp1#xW{H|5Zm?_tUyVJJ&bw9$>eXr&hhb+KC%;cU7Q4B?j zxsjNqPtGe{higwMpyD*hsz><+mnn9U%(KW$R-h^?RHk13NYu=;;ft`_f^g{%vW%)YaM^1;{uX5f6pKPVcbh%U;5 z2-9C>OQlZ3Pk*4!$9s3|5DPdmaFq;;)oE1f9Ggw)iF{bAmQ7LE0emt!yW}z`YIB%c zJ{vyVVHpf8o7$W3>oTxy<^yCPERkQgf7tpl2>B!2ZyQtlBY}B`kL1kbncdMsx+UPY zN_>v}zOaj|uB{Th)N)=r`ff9MOeQpDq(-c>1`H@n)ylMfr?059c_HxGuPj}NHdlKB znT6#(2^L5>XmvV8R66?gj6~K*Z~}cmk2jE!wn4<|PyGJjZ%fMvrJd1qo)N$8kUdBE z^1^S_VDu}~>2j#S&J)3dm z$ZtImL@-<6F<74V{XC7(oSt_W=34Je!Kjf_-QiiEyJ z8UCJb*XD|{3f3B1_Bc=FY~W-%u}ze_HB16v27;*;XLIXlkN)-NG!+AD8*?V$V_r)w z)vl{M(%)bDoK>jeF44)g*2VIk2aX`2=mN-2slGiu=r9-wwBc?!|3ObMUF&>4^yPE& zsGFDNYeuzoKA$aXRP#7d7j+vgj5fEs)!YEy*{k$AD$G%~@SWf9@RHzW0b=G~_=zN* z;u;lNmJbyise!+bCyPc#jUDMDc-Q**mEJdugSj#!Yk58`5v-MM5Rs|2xv`XYe7wzw zL`Je32e8-q@vq)OX9GkGm^FqJ-#Dd4C|&Iu4yua9`?5x>yI32m>>f>m_e-Gnk8nye zpkRV0bTCuSgqh(XRi;}~wT%u*-5$~OSe*D8Ew%UDI;PBcqR!{msZMQ)C;t|lFK-JU zN@)`H1KBS7#eD?8YTI;%uCBwmcr*};8qmRabUa_Wg2^?2lxo3VKj5W!?DbO+{X%h? zR@NI{%q7L-C{Oo__Z&vmf~R8%SD}bsfPSw#v7*#0a}F%|W3!cT)vJef!rC88z=EVv zd;Ma+CHVvCp@)E|GH)oTVVIuLC_@tbqz=tc@R~JE;(C(^sZ~fY9S7r z9|maW0^f92Z4#rsZv)e6@$y`egEA%7RobuQFCITwHEd%zPnpRNh;{^O)3ch(_V44F zDwebZ^-hDf++*+K`7ttQZaJ^$-(YLn;2bO3&eqTt`o38N(2Q==c#}q&!?tXRx>1_+j|Pu4jhq-QV3n?^X!LxPM5Vn)Ns@856@+drO$W9-p2O&(dgA3`>z>QD}MD7 zR}Oj9$Ev;9qtYmfz+CIQ!e|!>ym0l?y=*%gM83qZ4UBs1@fK3dZo+NPSVJe2?_H8; z?)(F>V>X?*HmG+Y<+U+PvZzskiMqp9o{L_T-1{b5>=}8t!==DjBU<3TY7s@%J+3`r z%4t-rKBbXR=iV##%?74PN&UWWQT0N{b?lGCZ?95OEN4>unDwaMG*cKVhrwRmjXpv# zhmS-yXDhVJ2YwnnyYq|Y{W=kx(DKnC#x@LTFx1qs!^$_vZ`H@T-G^#f{_ak_l2##u zw{l>n-NDCq3omTZ@%cFXY^0jSnlD;%WwppLw#{_tYP&*nw;3xO0WZiHz?O6_t&Z)= z8xeR^P7wLyP z1><9&^JWZEP+AMx;k~%kVE4FL)b_8{Em6o~)cDv&?DIyY2jg&zZWvy3i23CRubDe5I)nlm~_)%`BF8My%K?A`| zH8viAN2cv3)uv4Zl777Ovll1+hMjl&q{7qKG4+0;Pxp26Kq?OHiUIn!hac8{oSh*5 zM`XHT=;J|-#t#mk{uwte0m;%f9oTNIuGBkJ{N2w9CA)O+#WqbvuC=&eTY4Gy`#0pt zw48<-_1x2W}|H^7?q0`?eQk84DJ9`oPS;67?gor^mwqo5CgE#m@Ru zVPMQy9k|1gFa%HV3+y9KShKrOT1}CmHu_F5pV5IZb1AFwMZl@7Edy-+zBw*?vaDF2Ad1~^@ z7frlP(dig&Ancvmhs~s>0kBM)D^afo=_Whhv&O?QvT&E!087fz61Jw!i1Ew+fEvy&(^m|JWs?CDjhMnV{`n{wR)52Cww+* z9TqLJQ%7m^m&|dOAhv~~#>=Co!po4DjB9R3KHyDMscyA6x}5{^yB+X(9MHTHM$^Z)YiSV?O$4p zhVKKPN>M48@Bh4X46vu2fFqZL8Xb<%vG~&Ys0qO-pUe}kV%d5*C8>?zZ4r&ubB^&N zGC85d)>5RwZx_tyWkpE_%XWzo4v1;CpiobfvRrersw2sRZ`^Nw>(S)hLErpx{+(D< z^9uGP^>hoA&Uw*Tp7EcB_l@eiuhMG>W(n;OCv?(p3MH|hoVcuPru(x#>`d2h@AlJ# zXAR%qVz^E`8vj`?7|g~)M?UNx!O3E5$8;>Pk0T5Z)$90X(Jlm{` zaknuS)a+8~vOoRqLt5}rgK2<&?~B2OYPc7f!87xrwLbM7L&{<7fw466OtY?w1K7_& z*8J>Uv>!Hni$}&>x9G9XfPCk$f@Zj=?&*;aZ1rq0M&RsJEaqn4f-Wjxq4NvCBf1b7+dR`T^5JLrIK7@B6|rq5sj3G-|&w&Io*mxm8F-Y$0 z62gfJT{Dz)pz%f=%x*^=;bIOeP`G?pmm#^w zpv8H6C`?j}T}q!#>UrxK@0xrB^dg8{GLucX5j9#s`O$imK6K7m`gW>#?3CA?`OF=H zl_l_MFfl0BM}Ri%XV^Br+KOb=9{Wi}u22ojAy4TwQ+C$T0-=AQn9eR+rt54Pppcpi z>m14+9}Hx_{bjP=7~ioHl?@xxq_8RGt|sR@!G6hvb@Ea(m*ENilx3=Cihb25_2M{% z(Fp#`=#Gz=`G;JFh<=3@(XLfLo5*BoJ??>Rl4;B(BZ|0ERco!wD^|TPtEx&>-RV@x zAxA_O-}o=i?sG8&YMuRymZvBi8@JeDuK znHwOrT5+QTwBdAF<-*>UsULsOJ8%7V;?Xm;m0tJNG>!5t;M7>5LO4kC@#qnLWMXbK zb-wBe)d%nM9l`}SbRbAkeo>1ov&x+bPBuITEH2|hn`+j}forY~Q7T+QLKdqYb?;N{ zGG;5W46JaMZmQew(i>!k@UQWGW_mq|6Z=|CT3uYKNnEq|0gv>`4MeCAfTmty#IO30 z!>LxIOmWTTE#K6=CZh&5!Crp)gk<;XrYx&;Z7x>iPO>vy9k*`9@5&mFBFN)ej}MVC zYPb|g*zX=j&$ZrhUAbZLCxU)1*PHm;^>Kq{e~R`PC8+IJtUow?9WX((@IsT)nQD0#}I(njy{|w$x&{grR%E8 z*}th_y<4@mmmaLi*CM!JQ+xaQ(V-#u@;TDd1;*R`t2cAQ9H`evCOU#yeBKTdqDHs* z=g$MxXN9kY4E2vsjYB7~WbkTkx2C{RDr~pU2VM>%-5$4{95uW+-%$M$7mBKVqTaa)Pl$*WF0-ku&=7#cIwy9 z!6<3La&`!te9uMkYjz^gms6<&#aoqU&hATG&Bey=60wQ=*Qng{NSx$-&gG5mR7)w3 z{Zl75WtsOo6Pis?iprUD*DAEQ9ki*$;Vb@6G;QV8F3A%{vSA^Xs~*=x!@(rnRLua% z^C&e!1TtbT{h*&a-E%H}^4Z(r^<$41)^lxjwZ2FMFp~6~H>VuA!_&H7=vt=-{K);# z6~pdN^qsWz1&N7ss~Z4zwqiqVgx7X~o6D#d)s2eB;hI*k58K>w36^9XXqH$t*7Tss!2>eCCfGL z$VJl%1!zM!BCXAU;9zPj1EY}K%Zu{04iqYDMY+Ize%`k%aqNvFQ;Q>VGgLfP4Wc}e z?OIkse+mI!2JA5!Y8SpT1>i)?zM6;S`}_VyLf@X6&3q~|ag#W9+be)NC=%6O#_YIP z$+$lRq^Lkv!2U!Ok}r3DCAxWbj$h4nJf&6@FL?(w+Rv8JPW;pkx;S8;4fbZ(`Xhnr zRkCLAII+i9xcP8IJ09AM^wR(+*MZ2tyf*1#PEKV=WmGXu(U0uP7emO;qQ(4mO1O?z z`!k@s0yhh@|F^i_YeI(bQ=+%wt7m6SPjzgTH%7)(6*4&e5_9_CI;=^_|5K+ zxOf3a(3(d2hv9_r zuR!at@7Sa$_TeN!#LpR#jq`s9)!6=QhA`hXC}}@m)qV&9obM>TlEtG3K!hs#!+|%H zaWlr^LE}}7TfbQSe(8BUc3~m5w;)m&-2}-tP#+L7(-h;#{cywrkWFHe8x7tJsTa7i z7d~XqX%XsAOG)*X*%^Yn2`1Sh^xR7oqh9qKMfKc;5@kZ)O*6_0f)i5;4BC|3HfUEq z61)eVS=}4LDIRYY+t6{zH0nmXtOc{®iupestQTpwj(wa0|vAA&*)u{f9eTV#kX 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 Lfm|xP=o0xKnq@Gy literal 0 HcmV?d00001 diff --git a/docs/images/setup-zh.png b/docs/images/setup-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..2a4a19d04ff5daf0176f0243e08810934f776304 GIT binary patch literal 132497 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|7vxjeW=f5#LmfV5 znh3`pLNPOFJX*0(M{+Nwt_VuIALGwO*MHhgz7D8qVIlGgQWBD@bp}jxDCor_tS{X z?4!7UR=Z_6uqtoVs}8<8{45L%@__Bu7t*@Ez9LLH|4b#oyl}t`7RK z4OE8$02|+F*H*6IT0R`!G^w!Ub<+vz9akevR^P9j*5E5?I31sat4}t9%-BfIJ=Zsb zpj^g)4}9IE-?MZhpN_d~we2n}O$RMx*Pli{8e5;TrvIk&dLF~alXRTX>`S;7+!3wlgGs4t5;Lg2Y z`BK1**D)9+zoResN$GtH%3|N%sNPZDuqkKWAa|`#6K`S2p=(#>T4%qd_LTbf zC`Ocy$-ohr=Rx|+D3ioOxA`^Sk+KmLwE+C2U##1M7*I^${{F>Rj6Ox*;Lv>6b2R_t zzIvu!hwDJYL2Dz^cB>5PX9z$4vd;s#m2$-WF|*kWCXH4M!3cT`O3XHeTh+S{aj#Ay zB5gQO_cD*s^})R@iVsRcv8;d-1*%W+`9{}!Zj=0*H@ZSfnb~g3GFbXt+%?OkjofY}Y;?d&F2e;tkkG(ArW~jCgcyA_?=F8}hQsIvV3Y zq^#{aPQW1*p$+{(4xK~K6L(&IyP*r6H9ctRZSqbg;Hd7OGC1kwYLnVLSDc(H+|~hvAA{I-3N-aLJj@a-0NG(dBSbH#mE5>N+cIjxb&ag;x zKd|7J2M_S5~=rx^x(iTZZrl)&s$%1=@k*+`0OxA}tJs?0g zyeDts(C?nYmj~*Q&*qYll_R}xiyuuNC-vS9j+WF0@2$MVD6H0h4ZP_TF#webFU2ci zMBS6O;r(S&u6@^V;GhB)z?dVD!92{<2i*=*A@dS2zURhave!C+oCsQib?`n|!Pm5? zT%s}FG%!67A^|Y=aQL^Q%bTBnryOgRkx*xDDyL8+r4{tIUFj9KonsJ8R3o7xA(vmO zccUpAy}|}fryo^3+o1Au9KB}L3ocnXcU$uddd7?c(w%woOgu5QYB|G)qVfynM zX5}DM-m{oWYY}>qHe16zi(Dyso$W`>jU#3?*v0*FT6Oru z$^NZCsmKlc14x7ITOSVVODQj9qBmwY{)}nS@bKv=wi0zLq+F6U$DxzH-<8`+C{kZ| zL2v2kIbQ1FgZF8D!9F#24{}X6f?sU1N`(aH5d?oW%k8%?bl#et_4vc>7vdI9TI%#S zJs>4Hb4r0a99rJ5bhWfMe$Co6WfHGI!3hE)`Up*F0HR#B#PVjyt5GFMB5EH3^_uL7Mu^L zbq{KUJe|Q*75N2-u#MvHA6_6!QxztA&P52hOre^}RBMssa^t$1)&$hPl^X~~nYB~i z(*4-+$=SVi#S;RAuc#>F2tMkbemV%5kS^&4O4JHlit#xVTw^BfoTC(fH!uHPptH|4 zp6O;ie)p2-?oVu8_Ggc44rrwIc&xw9V~-G`D}lJ z4EtUmO{Bkfc4lv?O)%SD+TxJBf zKZh9smY`p#k4wJZ>lJP58M+H!kfiVPfMC;`L`u^7K6R1Huhs*>YaVs&74O@*Ozlxg z<38y0FB`??0)i%$dyHEnjw|)sqpmP%ctG-@E`8;h&*u251@lLldYpfBmit4&Hl5P; zT?bIHG>4Lp-OOB7u2dS6NS@~f(l>l++FI7 zjvUJwewjREZ5gi%YL>!V*vhK+|IG$o{{eZ^A)W_+Ie)j*29`5W=CcX>6mEoA()G!Z zNPFg1?=d2Phi;F!+|xHtd|wS7V23n$*r@M<()}LLIs<;*HAbH;6ebIJJA6)Xg&~YZ z8W*^S%wvf&E2C>2t0xFCb1i!Y(kVgG^{2tz^gd27+ih^?M|KGXg*zMh**Ke$Ol;nx z5vQk67tr}>d3xCywrXNs$PRFOWikKJ0@QaJ4wCBK3c7wkbfdCmA%Til%(HLWII>wc zXqOHD;!WGyPGqa3rJmcwrgl>$d*tn2Se($b=R02hQyW0yML!6G(shmQfpH_a-oefeJutm=^yI+I~vj##i z+ocKCI5EGsUN{xjVE22Nof!WTsk<;EZ@Z;NKWLq*Fv6whmCbW`ykP|k7CNEl9%0?u z5kW^nw8AB>GfhG$6MnbIUYN7MKqS~1ufUftkP&zhsVVj`}!U2jq_kG`>JeviNwmZaW-UO%&EW6pB<+E zk0oo}_a)bft1>t9-2Y~sOijnp-^@C(%jIq-@vdOHVc|e|T~k8Mbj%)8w1S8sKAPvh5uymn-?`(D3s4~HEopHe3=vPO*vLbs~SpEh7yJhRV3 zHh64Sb?f)K{+9drxDNFWKctGa8Y3%hBiEoXeTJswYC5NmJNG028$9CjCMPiZ1iW(Q zyJ+jLYkTCF_;|jTDLB%Z{wz9KqkuTh*BGbrPNP<}?Qq}ga`nb%VG?C`zk`*bP=g1| zz^8+$zM+|D&V3o)aPgDbzwBmJrfaADhQIEcjTWNzGdc&-M1ENPK45yMZ0vR4t7~Ev zl_ZbJL3(X2U;68PpPf}M9eI(l3;j!E7qGVB(?J9q3+!>DPcB&pabqwu3oOYZPJvGx zOL+_rJI&sFZap~W$8zGDcs6T46h6AxfejX;Rj-=#Kx^c7V)EAW+>%{KlGCis6~D0o zTO6qrvNRHTIeT&^Wm7xjUdr>o2(j$v$riru+}Xt|zp;5qemLXl{E-qmvs1FV_N!Rx ziv3ger=}Gb{!}h*u9ZX>r(>62@Z~3sHQl2>-z}!GIyo&y&NJ4e!Yt~#Un6rq9J@I5 zIxj4Sl`pVbE(~uERcg*;Py+4{IhNiA`>`DN!JSbMwu@Sg2t4QI=uCbyeA9tl?#7aP}~h;4dl z(pNx#5nKWmX-LrTO={{_GrBBq6rOF<_=IvHI{!@?%EeO@|4_nMYI(40dJI)n`~AK0 zdXD_4aG8nfV!4^rHzb0KG}hL5I_{^dnLL?;>EEO1kL@yPw)S{8-7uEj)6MmG=pNUe z#r%#uDOhprE1Zg!s4I9TJb8YS*7Vb|pgc-+qReV)r!2|Vg~>OUa`UZGucZ#d;C-|Y z<(o=?gWY_(Ed0a9IWu=4l3mnBT3Rhm#jw#4z#zdW3y0rw%T!IKrniqNg|vPpHLtdzFLx8R+1QOTq#i9UcOT5 z&EHf$GGTo4b8f*ofqIWY;NceceKPA&RMr={vz2?zZid#(r^5!+u^@YtxS5Utyai?% zim?vwXXXs^dG*hFCz%-;74#&jCKCsBC*u#og>DPD(&HQE8z_;S1%X%0173r((9^|h zw#Uw;>ra#Yj~OT)zwD=;R)96YQ`%Q)@d2>vsw{6)^^9_ z)n}&nq9!XgR5EAjm3b}u4IZK1!o3Yc01j((s)I{JhS@Yt_{X=@8;G% z<6K=i3a(~)?7APgE7?vNa<4Q~fO6_}u397TS;bnkmwV4VxtQ5mR`y-dt*TaH$)$HH zTF=;7-B4tWeZt|#dEH*x1!szU!FP!cxttw*pjOuOm{A;H{~{RY8!5LOrTx9yO>fmm z_hz{MK)~1;9%&u%Jd>&Sp@-mJ_g)}S?1n;t)Pj%GH*D;Wz#WpNM@cx)^D%(dI^F@7 z!VsXpML&+3Kbp=TdE{Fm+8xvT+==YLd)j2UeXT|bqmx;fi9?ej`L1HA7mC$x?pG1n z6H^rn+O^1w_!9tc(j#vio<%>8&-_8>`t`iGTZD0PGMkKO_ZTVT|7sZ>(DI6FbT# zZ3stjO~B#HU83Gl(bQJi9G1@F#}7@}8kD$;i#5ij;W*sgw(P7WYKeHB_ol3O&T!{~ z{+drjN2X6dT_@5zba54?iIAzn3GZqw6$H2~BZ$Vhrn8M)X0lZWk~bM$wCdcdoyWnZ zrD*j_H?y_U5?UW%TXmA}K zqSRcNKHc(~^UM?Wd?8*6$KmI0Rezl@q@;^MP_S?1fm&}drzjTTCfOf}OIL3>=TMPg zPa$wORG4{3TdLQY;r!&J%K9|rxsp7U3*B%+655izX4z0`a%T4BqO|hG^hC*@3-?R@ zUqns-$r32JQHAed3~4zj#4PMoq_RMVrG@GY=GrU8#GNmTUy!xNZ!AE4;5yz0YuP5C zn3yT1+*x+inzv_EcBIhJcd(4svkmaX)z9ojw&q9SbWG*hlN|{v5-HYiT)>(n%@i?i zZF|QNY>wu^BQbd0%`K>k4PP(loZJvwXAZoLJ7MUVHJjSh1^Zjvj69mYnhwvuDfBk8 zC9Q0K4*K}jGbS?(lWjh0!pG5O$sEAnZ4_=y3NS}Xl_+kJHD=@vo&Af8rymkh^XlCd z77FTBGkh$vFwh=O8Z~leaxJq4Y&7E}Y9*X9@0DuBoI96#kA3_qQ^r^f7Q^Nl>j`6E z5HV@giGTAs^oEp%dveJfcNooUvpe>fUEtwcI3Cre3DbIRC7Y8~>Z09|`!6_45I37; zkQhyLu@f&z9s={npG^?#Tg@5zX}9`yD{oxaxzFk$K7d(2s8y69`G7w*=UKXzc6>)E zpYh~Sp2^xg=5&07ASu@(YMTeM`KIc7u2wdQy&dzp^3k$pT1u;}B_}5zl4aMmolBo4 zarTovA~`5C1|ZE9&3XV@oFWNY2JCFIOt0IF>$Ma9kpzOW7~@LngCfa1!Ovr}mdkb3 z7~!*gxbJfQdz4Z3Kh&Y@B^wdW7q(rbusS!-FHV~GTtlSa_b1M#i=4l9 z`!!T3`)Q}!Q zUk;D}r|SOiQExo8uk>|I?LDSuE2{muQsC{^n)gCroGhS?^owduVz%pmWjxsEAc_qz z`b&zLjT+yO4Ge18cA9>Db*Aa}-c;YRRo+II6|sN(i~Xr70BZrEhR?dSBlG22^y3;8 z&v&L3`*pwkWP`cP3CPD>rgFM(ctKT2lll@A9|~k^(_KuC>(+ernY!yvV{1(d~_PswbX$5R36hJx^Q6_5c3?_X7 z1f0Yn^R`3gGi4;e%}SMiZZe65p^Zz--U{E{Z0$TB{SlBTi;cv(^YK3QdimmZt84*- zT5TAxWRE>V7IMa1S1-TFB(u!pie2vM`D(ppJ}DDyVltK*nN!oXVd8y`5hwB$;(OlE z>C~vK%Y+GGQ3qdN*^VBIt`Dg)D@$1BnUSn9Pw=c#^=nlNL7yC2a!G%OAxM*j^a4J; zNP6o1!b}q`wY~eNOo~@;7FiGho8K2f`}m>kbs@iY5E2SLD5+9@18>a8V*rV9rT~Zf zNEV#jP+HO4?J@Ua_GQ;Fu01v-!2)Cc`8k-V{BxL2((-B1>)4%<%D6ollSr6c7*w3Y zQvbXaGh~YE=gr{EGNG-`$BR^z)}b|By@ANo&nAbhkx`5e!?6K0W z4&{gW3ixwFj2v@CV7RjwX}RHLcQ8>a%FeVt6W32ke<43+{B*0s8mr}|Au2ZSRaUj3 zkA)dl$f+r|HIijS%mEgSxeN|jH82(yb0y};O0_|j$(Qpqg}{n`=}c<^fo~{=%#4FG zR%Wa@Q#63FAQc4vxUDin9LLNp>W^<>2&;X?aX5KY;O~c(Uh%lJr)T$M6UBR91+V^& zRrsh6x1!N(>X%h!frcq}F zaBGd#lEZ`HpjvuFdC5@O%yG8F*W#4dg|!0*^{#9LhmDI+rYzC>^K}dt)+XvZ8Ykmb zK!j9RCJdN`dcr;ZXM-`$AH1Z(B%szo&`jIH;Cfvi#q=~HUw%0qd`n%?rdmhwhSmp~ zDulkV=+YjK*Bq7mh-L+0nEgIyPv#f>vyIw_TH-G>oc>?m5hp1{FXJQr z6-;&@6$p}(n_c`%SoXgk|1;msSoR-)-oG9?0O`FcVa=?*0_Nl2)LbIJv)i&fi18PnL&}0zgD%cIasJf2ap6P!ESM{S<$179as*fri@`QOY#@FQL>c z2u>hFdK@GR+h6hIf4w*7w;Uto9v|<&>oMpD)B``O8veh#3QZR1s;Sw%#s5P+Pyl7$ z_NxflKa9kG{JNhRke)ZRfN$WxSr8@J=&1dJW-3OHqdb;CWM>4-LB^vFf5Aq$ZHzRcMSK&xYEzYG!&u`Ju^PNi* z6m!L#hnQYgsttoJ`7ucqlAyj79>3tJ*IQs*>P(NG>3QfI>}vmK zw*FH1XEYbb;~Mlue3Xs-cNuKH?4I`o!&JNT@lA>kjgAOe2IqNtUxHO3%J2S)+>#z&X?NrfR(M$U={fIcuCK>7Q83859Fo(hCxkXy^=*w|I6jcL=G@6gb`5fGDY?yA=-5oTdO1%I%_*e8)WF(yg77#`So4{)Zl0oefyz1ec>_PP^*s<{(aR%ve;k zX$FDS6UwS}$HXsk>GCr`n(^9vzO1wW^GsgoBb=TS4gl=YnrlK6z zfrv)a=NK99BkLu=(rN#u_CJf59|xAix68B4O1;jl=3v6B&f8z5Uc3p8dq7s@aWZ<8l(e)otk(0BT+2P_ zvKxz9uN|rNi#9jMzBgmrQ$DDgtq9kXDd}6<>z5{X*NyA7wUP?!X+Lwxr4znWX1dA5 z#>N`;kLnpsZ>xO;Yb9a6`=}^VqE<;USE3p}oi9Cfu|sXNne)Tvb##wYM@+`ZCvmn! zLC6QK)mEKl@@*3WF5M573l;Ix6wH*$GnRLNYb*-M=DOycS*B4tUw;&z=$d%Rm0?)U z4Nl6{0rFC)&luH-zMTa0BOTc;`m~uW`r#N=Q|nKFd#?Fq0#PWqJ1&1&*T zf_Cd2-qX#Ns7npjS{=HIPyA0O6BecfhFb-)Of!$<+?}b<*Z0HJ9)r+;?(Wx*um=J; zW=WIOU_Zt!ioxINyT*zvKIIa1K{+;G^Z5pcIg8MpFLJsm@pL+x%k|v7%R5wCik&t( z&2=N)uc9tF$Yp{eR{#vFE?$g><=AF$@B@(YE294jm(!8CgTBZ%r_a-aBvV`zYr7uz+oeE%4GyNY*1PhDYI?S*B|; zx3Y5R!nOTstIldJQZD0OMeR=eSLt=qr{4Gme7g zs&w4P^Re9-7u9LGcAB04Di_Aa)9NCf@}9BVFjpnaWHwt#t;cyLf#H+T4r5Luq()CJ zJsMx3_75t;6nWdWXI#%Rs5mBF(xO?CcD1q(f`&*ge!T7l6G`Rs?N80_N0>YGXfi$? zmcd+ZZ;C+_ddSU$B3qke{F601rDm)5^yP$P!Km3eq6oz&fnkZjH{3as#(7z69v4(1 z(|IYli-gS)AkYFnTZtRb>=f9dkRgq>bs0%-{L(&n_+e(eiwIc1xp+wmy;>?ztSN$p)zGDsC;1$36QYeEf&KS9X;>(CrWkO-b2G#6?97{C__kfDKr)+Za7~%{=?8+b`OVsfrK!u;Ae0`RI?j5* z)gRJ{PH_w)x#GU6_Y@|92d`h9pg$fbut>i3{3NjQa_#vJD!d~jsn7Ca4(jz;N^@;t zDTqqPC#~JI!RFyxg?6(PJUT^|>qVz*Wk;-_%GOi0(G*W6p+9%$T6yr6DGyheLE$e$ z$&yn7o(ZxfCxyImHE!irfG>_wWD?YGv|6gs?Av6-yl6mtx8C_8@J1Evv({j*3v^R9 zFaT3E#?7|M1K4a1AD&Cv9@d4;te!l>xNL-;@W~d6PaFRxglOUn-8XHr` z#kWR_Vst2|*Mb6QX#c#p1-)^jf=`#i7*R?bCy2x z(JkPtXFNJNO03k*-oj7VjM~KayxzBn;Y>1fIbHT=TV(MB{qS9k_LKUFzD3Gn+5Png zsm;+VhkK-hGDY6dMg)9SulnlX)g)oB(Ho1DS^Cl(e;W1hQI*;y$XEQWKfYZ~+MHsCaXn!vInY*e%grLc}9OQUANeVt>7|OKYqAW%u3$gJ35@<*76p=>p zj19Y~N~>8vC#)$AcP@klzpdaz0Vg2jgCVppkhCC~=K8o8GdzRf?{qY^QaB%0&rC$^ zY_Xu6!2r6_+ye2jwEBNJ9MxpSKz@t94c}(?$QVt*;p$7HMDen$UuM11paec%dY8~d zXuCIZ^oEWdQ2vd?9nuA}ve`}rsnQ_M+er-vsCuFhcm}sGIwk$2ABdWn-k~NyML+X5 z4(sJxkBrDy_;+9btII)OyObpNjdqTyQ%08tewDAfUod&?6A!15*J6Eus9dgdN8B{k zv;u$qsJySU(`=u4?J?{q(UZ(l3 zBOE6#vv;eaXVVSEz#(K;`ZzQnIXeOS1zf%|@14$U>O$4E#=b02M5A3NV(UTE`Ljy$ z8nzpuRJ)n9`v_9RuM>tojqQYM`dfY&$LJn3-^-Ph7e^b;=;P{HZk<0Gc=RBSmY&(I z{pyH+k*seh^BimJh9G5Ug2N?2 z`vPITQfjIu-3h_PN|Eeejb<^~V(iFjRgEe&MdZt)iLgu>h*(?=GF@kXFlWlFO%+7* zIIK&?|2D72`ud~(#5<^1qis-kBrb8%m+Y6c=5f75MovOzi=^CVM4_&PR zw_5oE1>Z>cd@upmj66P5Ub#k`SXv~v`g`CQmePf?Bl~it+C9YSeoOBZiZM-lm%OTM z84sR^x0_7fI*Mb$b{O~gpe#E}NO@`*i1a~dG&N$Y4V~X@rqE(G$~uc0DbX z7&GUu{Ms%K@T`+fMN#Fi%Ve~U<*d^b|7Kyml! zGEEYVpD$QsSJ}K{jICo{u;$rzot-L>V;ok$0Pf6Vy5P*V-D!pY5IrbFKi!1#7=B?@6vBu=-EHG-uUxWd&CAQRNiRpqq{uyBV*pBT`#(3 zzMO2ple<94ziGt^dwLb!p%y1Y>?Y&S@IevO5(r09E1jx3c5r`vRA+HbX`)siiH63W zy>@)e8km{dZE5f`DJFp~u$_QKu-|@AB0}@}JHyArU?e<2PnVFN63G&tx909`(cX3*LH${zd+RcC2x4Y;s0E!SW^yTD)&r z4g)WlVsnJ;`Xe9dQpcD&k6u)I*n5*4j+w{fXOLfrs5@@Y2T{O>~tN=H{dH0;yD;pkX>s#fkN(faum=Xo?0}m zlX{Zn&E#oPB>-M~IdOb9BDSd9d+$7E<5Moa&1ZMH3`!Zc6s@TrPSw4>F)-6rQup=E#vDykc>e4-308Qk+v;DYr_pyBLFt)6sM6YvLZnTs=K#nnRBL$z%tTQ^z;SXr* zRXbofA5Di!*-Kp($)K_7JHQzVzw86zMCHKVLj`cre1kJ$k38O5ZTkbtWNOX3KdqX6 zwBJ?@r8jc+)K>)(0zQBE-8eY!$z=u(y?~^29(Ssrg&EXpD55E!Uzza$9zurP(|su} z>eu|#Mk^Iv)H{w7P70cx;e>NyC#vuCh9`I#LMGVL>}7^d_g6S!Zq>L!W!vu5SnUan zxywRgAKd63F=KTQ9{TgVo_{7&vFxy-jP%IIDQ0>W&Q;wb;I&~#8Ys>N;d z9Y)k3usG)GM&dF@?$%Z{HdJp>DniVA3E{e7*QK#!L-r_E3MZO%_e}aU@o)8q3ZoST z?F`2Vzu{6}Xpv#JU9E#7aBJG^n1)IJc=7{sl_ubj7yhBifb*K>vmOWz>h*nPiXVI= zoY$lmGlh|AP#i`6FjQ~0Du?8&@?AatT z9{VQ*imGhe0ESZk;GWoZupyPkBV-_dh#FeXYKxQdUJ{ciLXD^3@&n%?8{hj7`2YBJ zz^2F33I~^c8L~h~@=A$P9%MHcj0Ht8#9E?~&0)XgcAT9-Qnr+%VR*kPC~VpvzC@T! zN(hOKXKxT3iA+oA+rtxnN?4k#>$|#~(RVP)nw*QcxinL+MZa8gj_7P-Qh?(YxnFne z`|Q3ng$L6o9YY#OLr=s@mw-k$&jzS}!$zl!_r}vrS2LhzD`cfr0>CMgf`Xl|h1Ee^ zVN!_ciS2&G?@DV^XmuJ$6$3Rl-EMpzcroj|eo$q+^4XHu-*2{WYqF;$C9z3sDj|B_ z==f&&QwtOj8jcxrQ{?Ug%3u`Db6yQX#-kO2%~o69u=meQ^=@!U7v0a3iSH>-Hgw0Q z@UQa=aq>VZt)7<`Mj5eZHdCV2XyK7zh4PS%dS}${!KosZ?`U)gK7RB_oUj{V@E2DQ z98F@x7yn9;K;h^FDZBf5MSH*{wy)dZTzvrwXP#_XfX*_N%{$@kNbv1_-;ffg2z5|= zJHi>ulkUvPY63CTxg1onV~Awdc=~ejQL)fX6S{;=$S`05MwFT#hE~Z%8-K!m~;;~N?|fa zNa;61NhsJXwMrPZ)zl?5Ne2#jsg>beYP$=2Bz4-5%%#=;3Y11IU&Z+8z*H zq5eet-V!(RHK8Ef%GYi~2$)TkXv?{R{TkU{W`T6j7(nQ4T((T$REg;Uz& zR?1ldRYkQkdHeZhyOm6b}RFq?Z(qV9CFkd!uU3ST8|et74O6%#s}aM`TRXBvyF z`8%H0#I{I*_i4A{M-N+GttT-|J+Ba(wYtw=>a(nzE z*z?Djj68*BYWxW1QW#GIFnI{BO%*TKncVohZB|WINqRd>V&RvXh@Z+HkxBnffCAl=>nxQ*MNaHo4lnQ^fJNaaq&u)EX$@Hv~$Br z396ER6hp!*YlC;J!NR@@XgFImXHz1n;H)uKA}I$IFqaEIuqCK_??h26P-B8H|Kz0H)_wy1a6%fLIw%4=hGk|Ee+z=_sb3z_ zRqC3s0d+A!mw(Dk?B%WZ9?DR633t{Jq2+cx$>uTlickxYw4l70EY9?4+~ULG_Glta z6FlxQs8U5A#8*$5Eyh?X5*D>&c1Mho$F6ud=DeJ1d3^Kd#`N!w)+N>K!-D9sE4H1> zNoK|EsMz%^tg0_pBL?ApG9NixZLOR(Iii25thzOIgHK;+6qbA+EytxSK-8#98ehxC z%P9!PwYKRQC}Mv&1go!g5~YOh--e>|a3b?!uF`4N6-k-Grf~6}_f6V>&;Tr@Se%i` z#`{6X&Mi*-hwo>@i|^(v7JUl1?D}tg>rv<1-1pKOX)Dt(O6MnmJ+_Q_Xz0Cqm4fqP z6{(r~qZY83?dJl5FNB>U*f9507>HjJBZ(^W4Yz4r+UW5nc)kmp$O(62G9{c)-Z#fj znc@q8>x}MG(5;j&bD&rz_CxOV+6`gL3C0CW$mE)SYDonlc|3B=G`i?#S~SIk67 z1MANb5&Or~$09uF40}g6xG7dyHR9tamwB>U`aZ4od99r`GHmb%jW~m<1Qq!Pk|)9Ohyug^Tfmm_Md>fhEHV)w{aPg#D>Ie1iJovDHKk)vz6#UllHjmi7^(>rdWbo)W_|==r=d(q6Tz= zker8vLzI1)UAn1ZCon}usZ~Fe3ZXu^i)BUS)4IMo(=uZBj9;Hw%Xq_E(QMV5hv@Uh z8f_cqoX?^UEuZYlWLHKx2D$>B5@8Olhi|jI7CfUee`-(fbT$?IJkT>@@He;k6&jk* z-kVc@I-0jg6KIsQQR3KaSruB1HjQxUU(Y&(C5R%wuiL=HlDw?kDPLn9b=IYjyoVzB zSVfu^IAlKk1-?`+E)qTzJj&^Q_#GiiV3)!uODcwxGo9bJ8yAlnj?yhLYGTOec9YVh zQ~i?)bR{mO5Ue4kWQs`rT^zH1GNA~Ldu9Y4tAg_fy@^fion)_&ei7)N>=M;d3<|H_ z0}dygIv+wlx4})~)}FLr8^~;v4L`|*CvE4{6Yh=zvqy|)qGx)v-Y2KD-kBQHu^dnu zlRFQq&9YEn$-X_rkXZt0pD-*5z1-45-SeCNwVEC30XB{T&|9uI&VWaT>J;jU`f;=# z8ISRs&&v~PdvQY3*&}O!mEUJ(S&3==L zJ_45)W$cNm+wlHqjj z!fDGI1UKk4MLaf}hSRA}k4Q*_Tta~cDJNAZ24$u$3$b<_2e*Ei86%VBxv$&ULnpE5Sj$%`9IHaza&Gl% zW|}P(SDS;u6@Oj?5W?>j5dcOtS)BS-&GiuR!e+Bg|-Q8o&-ShnOyP+P=#DuVDg^Ueb*!(9m0 zsC(n}lZ0tC#?O2TwrgyQ*=oDM+eUHCDs zpV|N#s;?wo8vY@B?P%-Yxd6HXPFUB(l2i3BYW#-C+zzsMdwju6B+eUMf;*dE4W&{k z)ZuXAI-HN#)rDCtr$e#`pnCHxrhesH7;t=HOy=~ixk&nw^x;bSS=xh(ozq{V7PH)Z z`FrTFw0ImR$AnI+mnU-;L7CG*EL9l#{6rdO*bnr^kQVV?&kbVy8;7KC^CUQnov7B! zHSy6MxHsdlUcT-#K0Q90f%(F3J#P*x+Qv`_xJHZj)U<-3+jGA{BNkO>l}@*svQs^M zlDyA2+d{u)tNx+feN7G8Hz5zPo5Tw z!a2KE7I;O1INu7r_9;66L=(P0S+gCqQ5OfQnR!jcxZ9eIs~f>F=QXx`O=~Msiz=jD z@A{S{S|)bV%Cur23@s(yzj6csZtZ89G3f^@j6W`yOKWc+PXMVyn4Adr#$o{dD@oZA1S*af zXaBZ}{O6N_4gk$zu>&bY8ORV5cflJR(W1QW68Z5F2|9xW0P2;{l^wr4J#^-7l8Grb z(h;aI_DE7C&|9*R7X=b|E?D(1S62*Z6q;SDnIs7`I@#09!l_8fkD3i;Qe;+n zD`7I)^)?tZU!!LC$be{VE*3s~WrMec@R{5-+2+C~d;zaoLJjD(I%0h`?RWwr3uKao zR@G{giq^&mWt9r#Os5~B38fPL++`<-AtsQr9m9InKciiWCSY3=f7qDwgC{)1q|+=Z z?P>Sgx?V6J%zBP|l9iADfw;#JMBa7M$=}J_6f zd_s7fv#>cWgAFk9Xap^a;b;DdO8JU9?6yk9Hbxt~Nh^_s$*+Lu+OUR}M+oI%#1tny+coWC(%Xc`}PEC$HRVUQ6^tRuYKdy+mKvt1Z zAC&g6lZY-Abr6AO0DZ<6@_1OLK%7Y_lOmMPRj1N78E~FkteOr}k)jOVnp|;{7mdJ- zm&{8of!oZ6%l78h)2;XZdR^3pBQbGx@RcWpM|?tK1qAY^i@jT$SsI#zo5)3pm` z=_sI)Y`@Cp2GS;}#J%x#R;!|yQDo5fPlTP0@c+=I=IV>&U1clth0#4=?<)n)<3W@+ z88jzP1VcaPJPX2^^SP<-ra5E}O7>?sf{)r)y&$CQ`*()&(CPXm4)vPH?FxFbA}1sQ zpj`oM4FK3u!IrPdlO(ut&lCn_dC!)6+NSW>m+cq_R*%6KFX1d4t$24sbbv~dINVD} z?Et>pl1=G|ID(H#iBZNq3;K+ShXajpI#>WOEN} zCZpI1n7C~pT5A__R*6qn8)T))lOnkShFlKjXVzpI{$>=sfy%%^CD2=7CWVI#p(bN> za6>-uJ&Zlk|!yrg2o4D-E!U!?XkfdOEjFr~TRZ-SG^u>Lqlm z<+@~5PhT}3qZ68PTO&%xhAOki9P$zEV2Ia77NJXcq?Sa-fbV_WjZG6y!0W-{BbKSQ z(|GoCmnIl>uH_C^gi9#Dt{al(S(^T%)#we?RX&rc&&&n(%*jow*)~3pTgc(OrAQ!W zUW3%mHx?j@dR6rAp9?X>uWWQdECQSis_&@t;ey!Rxo@f7IH@y@8VY5(l;eJ97H7*h zhO|ur;r1w8c{6+OT3zQ8t`OG=l-!c`Gx*64uW?OM^w1-}%vb1`=KBP*OR}Jd`z0nM z5u?3<>nf$OnEi0I6C@ki>v!z8hIp!PHt=psVE`{}*ZYR>Mn)Ab?rURsYC`x{q!2P()$ssW@2!vk z9DyF3WcxqK&VMU>{(2XKSf#c8J>Cd}Uz}wi0jF|n4PUx?{0u)C3_}j5p z)Wzid@E^IuzbN?sx%>pm3=rTI|LM#8&tt#}B32|N4v@=hqj6C9vj%^?Ya$~Kh~#Ed zB>P)?|5H1GJP`r7bP0Ej?X16t;TOVOd|9P8duCk&7k0) zDEfci^o4jM5-4-JC=v0u9{H!7>L34%dHb5giFC&}#{cafXvkk%-bDbE`B@!<`@eS| zDLI7DzR2(hDJ=Q_+VU^lK$#{(GSfo&Nr2rO{kf*_$H`GrlUkXTix0@AL=;OV;+WzQ36*!j8?Ye)u z+FG$iF7-WR&A0M{@pxM3Z@^-~MGoVm;`_qe^R1cdBlfhCObHwY>RX%FREkZ+Pq$n0 zPA|_-lr`%E^>O=Cxk>;%`VEVn4zO)cVq7kNI!;V!+3pm~(s#-<+N|cRG@kKHyTuec z0tD{o&YAH9Ok2$0j(hF;h(ewp(6e7$v|f>?`r{uN|e&CsbAODQc@D4%)0 zR1UxeSKY8@#V@cx{QnK#iZtY(^X&{y_qYD@B^v3=_2$Jcb5-_^%Qs`sc4ut*Jy3NHOQher z`!pXSb<6;sw!*O9d@fBYo~EK=Dl)y*-Qn=1uf}!4=6f)_zvJGx($Mq{FZi_qsqnoM zp|KpEy;}_wx5F*ms?juw0`>Fe!)%+m;oQk^eCcKfERgc5jAEZS0OhZ?C6c5;tbr&PLlTt1%?`hpu?brKA0$ZN|@%4(Y~>y62II3Tv{K z9QRrZad2TLC}@#ds-}`U{qe-#d05W>d*!q6K(+%`QjI(d(>N zTx`ek<^EU-x?q3%CUIXnwM~4O(Rnu{r?Q2EUsxwXKTPl@e`s8+HhgHhS}Prh!V`6O z*t=NX=X_=gAA&mO^L+Kxn<3DF6gLg<)dfHnh+Z|N(&s&Z!8|%ysV@NHn}bu~JfH9O zFp>?C_l=DoBGbQ3cK5Xcg#HwO;J4SIlz&5~MA_L6qj1#33R;xIbf+coXe%wY4(VB36AEcZ@+rm{^Y_3oQLG2+2r<7XNSv|#`oFl znZ?n{@n(%zv-MP3G|!I%x`RUSU~xzlZel8d)|)>O76m^iB9%?6oe1~LD|~arWFlQ0 zgX(*J(_`du*V%} zWe}I^b#_zvPE#k%K3q&{JpAy`tg<_g<6{}_)0;HBJx6u&{+zNnwE}?Uq6h(#OSLz? zS3mCQi~E9!CM|i)`?g{AvdN~I81<*JdC#2LL=Z_zt1{<#iUS6M8VrEr^Ttve z&Gtbt!&^d$h8i2`jUP2S!+-O-m1FOKUk zJ(TBr;*nvF=45aq9L->jkbCi1&Xv^$Z&PW5bOO(s&f_32gf6fp*dWBZ7HVx#ZVk$? z#$*Sae_F1#I)jU}7;F;;8dk)%OlZx|*1T=zeBv9;)&fA|fwD;~bM>e~0_i<3SMA>- z*=>Gi8IPz@*`ljqQB;Iv^OmAD^%Muyh;BG?ZsZ0}(u&hQ@ca z8f-38C(rkftKN`_IpMMzUO5nw`h) zv@~mq?YVkKSg7y}r?Kh!(&oZuU*7a~fqvAdGQ0BCTTF#3=F3R#jKt@Y1839yFz;0S z)9l*_|E&xD%*1CVKr}D#5p#ER)7~%iVdJ&;M|j_f@P-jK?-52-ak>UV9Wh?s;j`cxS@P?;ARwf#>rCK2epS0NX-sOHawB+9Rp(7h$jt>f0 zg5j|j%e5NInI5F9QN(A0;8WRq-=p(WLTUgp4MLRxC{C8RtmbbDJP|2m*J(kKRKYjj z@8)#bbvb++O2xx%&~Xwmr~`kc0$RkwKAWqiH%F;5{H`KH!+2QDfVa?7 zzhAf0C4$Pc3zvEg$wPkYt~mr(sL0LoNICI5UX3txQgC1P*~@)y5@dDf*Y5KZNo3vy z+;qTi7b5Dmfs;J3jUF<|U1oU=K>JBoZKXU8x(4Yu)@~VEjVBTVkxxBmov4fcr@}j& zuoLvHV`;3xAjCcaj}~4su)R#rf-ct7N~Q5=(I9>}VhsVm?Jk(^iwj;|?r{K08}%E) z!x5LIo_)e+0$iAom&$v?5w)@cAUp$&$AhmzT@H@GS0Ikz7sPp;i(G2hfG@4kC|+)p!(LZOt# z`aWMtU$P%28QWM{c{|XSKH06NtQW+GJ`nN$vG-R|ajenbF1mud27=Q-kU$6y!QC}D zA-KD{1!z22aCf)h?gS?^?v1;)W|f8So~Kh8dv=jx2n7pa>LR25b4JLm6trurC- zV#*0uj!{$^lN}lT*Zdf*tvQ}hkY0oR1Wp8mkjoU@0{w7b_NyVbH>CJiN|x_KiYT9m zG_Hz07rhbUBz)@I!cRe&#*4HN$lk;j!cCwO`_vTy7S?Y}1FpsFU8A3dNxrWcKi?~i z2DIl46fW^F_EM3dvZ(kS?@eS4q4`ZcN0ITHW?X*3h<3UN7ZPlgrW^c@aDAx!mK?VS zpm7wBaR_erXLL@XF3kp;rqRC$zl{K4%`emDUp|OmKrUZm!X^k<0^74Y*nqv0{MpDk zB&OM&Dd=Z-B`IoFadvW8l2V?e(*arpe+E@p>rreIkjqH7_CY~8C9o&DRF4t8R@JR>DxL1XcVsqIa79B`dJhj2k%K<^aFN} zBP?ZZ5SYibm#pTh(&V%Dc*OV=vm9tDJi6p#)E@l+?;8Lu+ zvS`qjB{W@cRzn01!@oqxQA_B31@)C3GXpCj8z|3czV_T>E1Wb&;LTV=l}K;i(K7`r z`WRV^7f9PwAxrLE@+gW-ngqvlg7hB?HdF1DwJ<~`A)j`KXCY7ZQcb95rsNNjW2qhe z7@A08O`i(kEQpLDjS+{z=J=BEdur#@Mr%>M)5Xp47&03Ht@iZEeBXtyM|%Ik*TEAO5qo6oku^5up_gz5-X>{enfr z^oZf6dyJqxW}CGu9;AzTtK^4L`^X4qehj(Ab4MA z!}Z(E1x335$QY1&k%N@JNl|IB7H>55O*neh83=B1o+P{`watpAoQ_K$oc;7RDT}myUbwIjFV99#a>t!h}6!yJLD%?F(MW znK~eObw<6>jW$`;onrit(@!X!#P!DpVZY_4MqvcP*+(EP}2t`0N}HuhOfa`bV!Rn-z2a z9ETt!?Gv#s0f^igY2;YDL$os2>EQ6p+%r3?GZ>AhOylGEqWABbAl<_Z`lJd?@jGt9 zo~YUCs2>;(wT*-vp6PSeDyEM!M~nq3?o8UOda-21fFKCw)|vIzs4_5~ zn8g}+(YUnJn#oV5B?K+Xr19 zw@Orw-Zb{tli>l;)I3a?_?yN4@^pTuRLReoTD#*suS^3qut(BcvS*E`R;&~@+|Gfe zs;It*TCh#!Vn*ZTXZ(i~IudB*?x;rLM;6R`#TKU@jju&CY2-q#xP$a^$<~7eFL-fo z_ZZ4ouMEpI!M~VT{(bG?{JXHu{5apuH@#X~R3V_k?17{nvq7LI%T4ExB=GfmYt5b?H)Sw0i&M&kD%YzH4_ zDlY+;qL^uuvaVe9p(%jUDO>#N`4$mLjJPK{>g9<|xC)Mf13(-Q4@2R1H2{&&U0oZcCW%8Kk>~|!4mVCGFSH-FAQOj zzxaRBZOfN><1Wot+RdxDgh`^XJ@)g`s{$xMs1Ac{u`KUy1^uRUX0^{vX_LF|x91&7 zwTlWZ5uOvoQFoN)Y}@yeW3N8|1WPIAI5`&TuWXQ_9s4pd(z{EO(IS3VVqQyk@Cob| zWbaGw6PXhrgG?B&^$qbEsQOR*=-H_|5r+7~f_pF_ZSKVMH*(B28< zto=&C7M)@t-B`^e9ALA0Zl3?oi$fF|1NpDD?Q$(AweW9pGQCENqO??Tc*&q9LYlC1 z&AYdKs5Pr_mXM+DzO8wtZXcFRj7RsbZ6rUTloe1Wn&Uqd-oK#bGj#^N5 z+QZ2dyuVxak40n}*nPy>czuCxT)etvG^J4qn+J)Z^h4ZL>^o7M4^!*%rlbsicmCr>G z!lmmM$!hjzO9pi4>v6e7^R!k1i`fs<;B;eC1{BjlNWzGgG#@O&rP4OLoGRoG6IG+? zqwPl*T~D9MT}~$Xv!5x6m%sbAt7$U!9mfjWbYeo`l9Dibmc78Pj1qG) zPi@3h=ICut*H|iNF2EvA+RrxIqxv}U>bleJ|M(ys_r7olcc6u%eptKFS|KRh*StWa zf&QC%Oh+S1L?5L}M9HQBr)2Oimn<*LL!k!~a8(ybJ={pr98-!E$uFSzgKkZEX-K66 z?Vm379PcyE!S|ZZ{l4RsRnt5#dyeH^RL+J$?r*b6d!k|L0SXLA=K6|AFi(wiTab8v zaYHHLc0cW{9#lCb)6^jP&IhB&aKK8&Jfig0(d$Ua#n~8<-bn0$`%3q z>=j@JEycnpsy;GN_>dud!EUo0L!*#Mw8-bKK-5AS#Sv<46-m_YOk{d`ava`te<;Ds zUA$z@`0KZ9;sj(p&zXh8S}EzY;&#U8aAydSDV=H7uOu{znD6BA6t4g$T@9JC_t(4} zhG^*A+s*btkqsb-rt;`GMN@-8X-q9FW&WPCN~hJfN_`25qOUf4hy>ghAVjZR46<2m ziJh%{oUG2$3f&CWpvtURye4wIDf<+j9Ns-1bF;&?B)P@I=N97%4TE(10%hLh%@bBr zZ?#y(;v;B%98R{Y^JVUoQM0)m=(Fqp8E~QK(pg^Y5jduRaQNf*1y{xYac|{QmCATSmW15 z1(=_xoY&TJ$ktI}pC6!Y9wTMn%LQJh`Oe=E{-wE8JZD_)A5Z<7X75Y8wlH5ItD_Gn zE|xPOW07t#R9$={$>?lS5`4BFwE1SqLYD(;WBQ87CyIiX=^2Zn_UhUu7`y%+vd9%n zp4yb!(H2brF*29QtI0)sc}CBIOuRBzg60Ahsr*T+SlJS|oZP4%OLidGSw5Uk-BYGt zYdY?N#(gkgV2AY_bUP5!{j3$3-!N{4th`>a+{||-jPx!v4%mP}{6#~`j|^|M4yoIA z#=)}!oRxl~SS)T{D-oO-OzsQ?Tz$n8WLp#Ky^@;gPgt)QbU&?5j`md>UFF4-fgoa9 zc5R>=Y)u;8Csm<>$l3R({r`BR0#Uk7k$DIi0uu)TUsL)Z-?YI6G>I*g!)_M57IXzj z=%yguuu27^?-QI;mT>0mAu$Hi<>FQ@wn+D1Yn)SN+SFHqE&06~%E7mxDeFpHo(ygZ zmfZs|#B8>d{!Pq`muV@*Mvt8AN#cd)3V|6LF-%;d4a~_jBhI{7LP(o(BPmyFCU+De z6hH+`SmUvsoga=C*Z@nFKM;)`KY#z#8XTEga>8OLR#cU&9~d$j9GOE(GQ(qZ zrp{jF6B-yb_lR^`#_5B(Z=;3spO?v9NEe&<9_UB^TO{$|g7)?rQsoaxjy6GjCY{QfoE%CFMFs3XITbdKe`Ho+m(FM)P|_^lj@i_` zjF;;=+dsOn8H`MDEBGJsA8#-+305}GYHdh@8$(3p^&z+u2+MWC)~bpab}V7L#$9X< zx!_WnI7x+LvU)kM?|qTPNgMr`S!w=<8c=ADYa&5 z^O==wNf7gZM&Z9fq~wYDiQW>MR)xxq($B$B$4jLYYbiyw8IeS63fSn73Zm&wCQ^P^ zx%zX7{FH(9x=K+>h8o&L8kY6-^^vu0eNUx5_QSJZEa)(GRgT3oW7=G5!)ES^q`PMy zos=VQN|Xy!S8^p$sadgaxLg*|u6y~xA5G}J-g?CqW6|8qqVx%|_6kX@YdN*N6eF_a z4q;oTAzXANEwt;~SF)uX)e`?2?1S=wP95aV^*p76+EeoB`H<>AjI*8Op`R*XP5%1I zQCi}b!ex_8fFx69UMhmk~&uTG0 zN2a#zb!p9->*Yq2H-BU%N84yXQB@BDyMJ27*da4#H?JCmU%w-bCW24H#sfu*|Eq4c~JY_J!?It$eLu<#mM>N5-MV=@ph z531T~*SI0I8iG}EtJ~?Mhx{}LYh$pJw*6N_(`_ci0g%cSpc_@d=b$8z_Pc~b3&tA} zgGdDE0Obh2JjLMz8r0cGCOlfl8F3cgPAx)2Pw0tfQ`vQ#h%{R& zk2nWeY+U_gh3+4XNT}zN0Dwg0!yt*sBlATp2}C=l`JuR?Y30`mT|FpL#%BkSAp^E2 znP>{x|7H;{=qNo%X;*pVdBXxQyctxDTGx*sWVZL&$ev~r8}!XPfJkyMUaBPY4V zY?iC{A7v9qNiw;XQ6z~!yAy<9z;Es}_$?b9^El^}#0@Zf(GT^bx@PZjkYl+>=dRVh zeN>c;o;>02CR6tOW=<}j#iG4ZmJI2&t;Vu-NAC;ftYCyWrRG`!vf<);@3-YFlJBSv zzwSrNl=pkQ!i4Cw+|YHgC2q+ zmmm6v>N52zd8}56P@|UYI`CO-s>=cH)z4IROMP_si4FN9j?11)CZ!~WO0gsC{}N_}CGspky}p0|d){doeRmZftjMjPR> zbzgC{I$lo|77Bu5cFQ%9*0v{n3-*KT4e*1JQCDlCX{IgpDJot-Fy4y~zs;fGKQnD| z*bFA?aVc@JTqeqw!Y-c(^mK>$__dB*ZVG>ln1K;r6-W?`Il%CFZb6uzM`1$6j94qq zHM=RNusUaQWX;Ri{0uA-H&dxZXTT152^y$ir`=IQI*1d163v{P$)S^S4li@y zMt7%SiS^H?x_67sCQ;aUjuNm~Z0<1T_c~^a=1Pmkz4y7tPt0?Nw{ zLSPeJb3Ixv7``HZCRyzyPt>2YiAg~ZzC8@XEt>wH$P^Nqe^DyLpR5mDo%d1xpM0#7 zg)%#WjIb`y9c5NEa+Bc?;uN(&eGu(YE=$9wrPJxK z$I@AXzSi4TwRx|dPj={7Jp_m@bv(X&50OOTrO{0M!7o=wD(L&Is^wFy$yg~XBRqUT z0p~GKsVfgJG3U{o8i)OzQ}iiAjK3(t4b}2HQ`7o_5e=Rzq)eoDkJ<4?q7Jz6nFq1G#z= zN)5@&L4pQGy@sIV1|0>mNx3#p3carpPxbFownBFCj|Rx2J)O1t7RK4TH@+Aw{gYGc zwX3dOvP;94pznU_TWuSt76xIkQKMH=&Brz9}yTWF^iF=)afu>RR z-MEI{zSH)waQy-MStQtK8lzkRv+ zc8^3R!kEUT7DpEoaA%Rm>Jm)tST@qrI?Y46XP0%CW)Y74V!|bt>@0=R(~m`V{`uo3 zLzQN4Ca+uf*XZJeToPU5pWGl;3iS^2?xXK+{$B86vp+22)DViB$|qu(^vJ~bx_S!` zB3fQvBsG2B9p?m+rV{?jHrg6-Hb=htT9=|V4qWj@hp&{6Ulu0GKLkk4iC)6@{YvBJ zCx_5jD0Mc>6xhA`gJbw;WsQwzP?&O@!a3|?wvjyfk!*T-Az8OaO~`Ta4d~DWBvG(w zLfX1dNv-nrv0x~F;?t!koWnm=1m>C+{1om0^W4%y*~Ux;_V$xyWS>u?oF33&o9h8D4Y~j1K0x08tMBvT z5MEB{nTu%-7;{zPYons#)+4sgV)GI*QEEES$grLgNNn;XBPv5dMZO9qzquJ1Y3P{q zv4Z_Ukdn#RlpP@N@qrY-qV`MuFwlbXr$v6r`SB}aj@9&iXcGn@r*h=^$0uR>?Y|Ng z6?kETU?vY+{8X1w6k9(;9(z&d^hyl$+8n z<9gG`(o*F92?|vOALo=CG3NGt=nk66;!7JzqR^y^f~;}Y@Cdku6Fm3XBV*t5k=5tH zncY~)PgaRA^UE2t6Pt?L{=tlu?O0nPEW=SAUr6YBM#NCd{>=I;;dmL%r&x4MN{F7l zRQZa~@ZQ_q`FElCMP@xvCLrZ8-C<)@kd=3+?l6ygLYm=&x!w8VnJN=cFNxb9t$eEE zo(>E{l0<%|n8rE9EaWQGI%$Y9`^Do&@O_@-^*k5}GGmAU78a*am zjN@Y3SVkvM8ypPB37I0ca>9+7zTUy9JReKr_#%F{$REMB-}TaH*ZFk=bJ8IY0@wq~ zDIM0Zm163@{vzKSz0zL^Hj%}r8>b9a>Zz3~YHC36K+yp8FLdfL9gaSrcWK;pmfJMq z<a!T^DTDAl z9Wd^@l3bTD2h-y~@6&J|=EY-O24`&W9U6#3Ljd`a)^Dqn?={-XpB;|Hfq8iwEseeT zvLS#f5wkxA5YEQm)G<3(_V0QgW-tk7knU_a}@fZ~r z53_sko#R>ruGS; z8bR?xei5S9p>fk}{UIl%@%unCluQ*c<;J%iCQUin&vpBSvU^nh+N0OZF&+^6i@6w+ z(KHI)JYR%c`@Oj5Oz^v}-!@-0Y>j?{#U>S$8+ANq4yj_`f9FM z=l(&>kjp23RCf;qa~Mpse4}FTj)$ff;F1i>=W~5)lDVz7TBNAV4lfo zwO9wql%cYU7G<3*w4tYv2U2^t>5=I?NzKTZa3T2AmKn@^gUwtsqTOx$*- z484T=@}_qSNh>5BjSL&~#(qp_nIc|3gen>Qy`6~$8>=j+A(ZpS8_|31Bej39jlr(T znL5P-V59C_YI+k^nnWxB4ooE>PoV#^Um46L*M~q6=TH(v3sc6KoAoWYTS(SC~;Oo$F3NaL+`dt<~ z<;`!dnZD*@85pAXFgWdSsWnj`G@W4KBTn`%)uWmZP((gcz#eZNT#7g2=3Je1iEX?3=80`|FhwXjCXPm_>k-K*YV{X+uSPagX!tGwW~fbH1zN6;X{cYWCndEhAx_?k@cs^pl;qp-m=NgfNl!Xo&w%lm>8hMYuW>PbVXce{ru|ZgsRy~U90j2OMq3?XQ37@w=0E1SicgLpS; z;=QR{Baum@`;(bRJJarTwno9zCFpGoxuK2ItupaW04$Pu;opz5DX3IiJi&OqRG-vJ z<5ii&?9d{84MYZQ@BA28343DTzxiVuMqSzt5F}nC1ewyTQv~EIFS)EyzO_EZYSfM$z@J&IvQ-Gh}*+WSW^tz<^ znP`wFl;ses&N4kxc4_Ow)U_q}lW7FJb-0NWZ=jHjSVr_MVyQ1} zMs*a<7=4v#6gG_u(29)43!uz71)wtV`0{|Es`&MLH`$n;-!q4}fX7=N>+ji)Y>a(Y zvqh#Cs%EjgE&y*dqvZ208iyLo!p6*RZu3L`=jByJQi? zaGk@>qFB(4`!t@clZjZpZcp+WQQvZ=X&o9#Vrm$!s{2<57}aYl+++?9QnWA|H}-h# zIS@jd-8`4H^=$RNS7ZB4(3|DdtEpT@|sFA=vqO?M(&?G!x7&{uESo(J~ zi*M}jZKfdhjoB}Zq`fLT8`LfX`uNjl0gF{4= zXOt6}B6k~UT#95IDN-Z2__T*pcA%nEbo3N^%T0BJ8l)WY*9HnSamDXu<0*g`G261hdl9UN4G#X%u^2imH0`_BCWl#*1J&_>_d-@`l?h{*Q#*TVhv zr+{6&N=9GE2ju=M2CrK`7h*BOLC%<8QcTfjpVO=2W|5)D&zeGwUuTB#DeO~E+w1kp z^I#DJkV(JYcG^N!=N_=UhPu}9@`gyP{d(i{!I3G2VLI+#pd;YRzp;6@EK589LnG2 zE!Tm~b$xjfhf`K1hD(>nq|%9^Mly?;JA2#X0zrr*)km~@$5t*sXM~(yw|)szkhc?-JBELDp!>rawh`YS@y6bEUcg=5zTX0-(I|>K{&wg-h;$FT;k1^WLq;Z0EP~HdLCWR247Lw(NPYb2^6wg7rU_hT1Rkw{ z{qj)l4-vQwUe-!ud>I&Oeg+Ni;A^>OYT3LkAb4d9Nj3K;M z1+a&ubLRwIp~Rtr;pb@w6pTP{2ir+1*i)$VR)jRr#bGCW!f7Ls2OvQ3oI2kHiwK6N z(E(X!)(M+G?oAkxWwM>kn$Ol%qj2qy=jYNOwv!Tze9eyV$D(fihwBfE_{G*66OYS= zD#?n+VpU|%%@C|8yiY0bjL?=NM%7v z2+k}(l^N;fF9O&BPa%vRBk_)G^#_!=K@c;R z;SDnRW}fN5k|x##sA5o477NfZaJKXR!G2|4Io7;Byh{r9&35Eu>x0D--4A#kMo z_p|fg-vYpGfx!RulKtN1{|lic_Loo!`xHzP{@-8g-$ySX045WplP3Q6U(J8NlM?$c zca3Z%{w*bk2!wy~VbMYXDa!n>ky;bzfkLD98 z`v2a1z|mTY#9Fha1J28>ne%I`ECIi#^MmCGLXX%fu%=fnQwX#t_oy#TC{YP%DD^9u z#M?V+cJhs`H<{uIACFT$dWEc0`QAEN&R1B`ma10sWjtJK&}(38Uo}L6-^ja3jsij_k>0Qts|ttHve7nwASU2 z*>usW(15FLP|E74*yZjY)tQXen`~fRdSU(mkZxZlD1-KZ>92Xf%f+>ii5A!WonNa| zmS6R!Z~0rqc5MnyrV470$6Wf%J{_(Z11xYY)z(8Wp4SOz&KJ{Fs!`Qb__PWnf9W}D zspPKMqc9>46l(dO;7XQic3M__w*$Ym)Q}YhEq)UNlGgpVF(g3RUntMY672Nk6@_w&82Ar)s{q4D6*&*LAppsL0g z{eMw5Ng`Is8|%{7Z3d0K<$K7G-;K4_enq2WS&OQ7N3+vz{*X#xS(w+)_hD)t0e9y! ztX8uhj|$G;QSV3}2cf>(8%?P#<>T|4ER+^)b+x`;sCTSSC3_@fvHlelHvZ=gXR&4p z&$Hu``}g*jj2-w@AIampsx+>BE*jb8BWU~M6&tRaR;_U%r8o*UQf%kz%Tk3$@&({G z*EAXMMUIelNc<#nQ10x?%;v_)g`k)xH-)AJ>NBsfUW>JVHpz|mZ zZs#feGna*t(K1murrpL_rdgftvYf=Er*31VT2;z-@+X~N76>wZF*#fF_zK{LfI%z& z?T4Ri_!Ij@S-u#da=zc1rmM8m9Ct?lfcIcwzU)V&dwmI`x;e@7 zxO^uuE1IzRU)mMvAOE6Eh;XRNaq0}R?i(hS6xd$4ySIujH>acaSqBJ?g+Tel@>wy{xF3*C1C6sa7UKn0@-Nl7K?!r;wI*_O zta>nA0W4}b?o_9iXU)Z(%%e8s$0I*9I++&cOlf!^Q|1?=c4uw~Ciz$NU<|S@DC=)? zfIj=N;-iMaiin@Yuf$pY`lI9ZC3{gJj)sHcy?Jlp*fh}CS2KN$W3*CNa}EsS!%B1Q zea<_k3}JpgA0YQsVXTgx=i~lC=cOuAig{=JP(ukr`co6`uj zGC{RNAbMVcM2)4L3h|hB@&xyKTk8m~O>f+q6AI{o4^v#X57c-@Gkw`i$8um1F;dhN ztx1hB+Me~@F~ucBiU6hJ-)u%4xT!2GQjMY2%rk`@*Hlt8E_ zfX%u&#tclNtGA>s1=t?wRm;=<-j`Hg)<2R0IB%3ap5#X=HyD zVYJ2Cdv}J&{lTq$0S0c=WDe(jt;M%#!+6s(1gMzmC2Rr)f|=5oZP~kfQPgvkIUbfk z{L2rinXlewE{@JX zM0}P|T(w-vz$uQ$(VVPjLm%le(7^9?sa>byP;ir0;T&XN3RttNBV9qx0$TNQZXR3P zdFFTT-VufgnhV7HqrUd;%sg8f3;VDwyqEW=rlt3eK+8aq3uaQ z-|duu$pKeTFLAtyH~}4=gQX(G8N2yuOX5sCcdcY_WED&JTl&4SFtuo=KQuWi#Y)Ar z=rqwq5tlpdl6YoKHJichTB7 zXUo6J48>9BWko-WXhbrN0FyBaLJD~5tuzlk;jaO8YYLz^7HV}po%lUFNk(I&M!Hfj@Y-{&Wr*;4C99QBvPA7xeHy(vsI8;7RVyp*Cb)7qPk~~3q1xujOZq=8X6}@`% z?=S{3K6jyslplfjlc^unYMLw&73rqdSaQQiYL|5rW9m)iqDjF1DNB2(IPYsT^MbD# zt#|&QVo-z)<$QA;4|dvRf@tU+BRS2NsB|82<){=~45+{UmJL8=4E49NOBY4RG2-y< zVTj&@dSB0Im=EVWs239|?6<-qN_!EQdUL>rxa=syQJfTIuCyxE7)x7h?>1Ophhqq z1O}sN1k|=*1ytT0kVJ+Nm=6gFaX_rUcz*o&dcSMO(}QczHPT0+SLk77)zJG;IF_@> zo-A|#iPlrh%3<9Wp-nXvJbn&5!-|pj@eB%HGmoZ@?{-2&=$^wkUeYw6+R;4Qdy@h? zSY?)fv`{;tfWJ|%U7}3A_gk}Cm8EAp`*Op$ zB*j`Po-POHa%F@EJG$3-erlvdc>?Hok)=#``-IqkCOAU99MIf4-@JTV~!sMffDZp+!uVtILkD6swQL}x-io29# zS=I*S!>|~aTQ25PFlsi5S->}62XUc@XzIHsa@sAFhAswOnohvaf{1v$0Z``qNQB>= z|AnXM06?#sBCA{Vyxl(jd{nJgwxg*whaszfKla)K9rw{1e5f7o6pBNt5AEPuADRbj zYZ0SwJkWfIu=)zuQ_+c8Aw5VrTEGBRb;BuBUM);<{WA!5o%2FC1V$H@Pzx{=Sxz?j zQ=-J8v%D^Os1X!OiZ1+{h55VF5c#XCCY5_ZZM$sX5yv9xmH2T3a#E^}6E$6X6H9%W zW(gAvVJND)qxgLPO`kOg3y(H1WbC0nt274Qd@%m5*qdM+@o(qrjtGPGO@rgMWf2W{ zsFH@i;|^d6ofRY@6V=3__*3D2XB|{IMh(K6BXg}io{Pygqu0P(@8q#m;XS)FJ^j_8X~Eh0 zwUR!JLyJLtVSf59^BA~<4xMcPlYOXUI+~6fJSw~$gxdK9;AkwiFT@XCdY-=ouW~8y zFoMF?7Qm0Nr&-!hz5?T9s;%>0lkajWp@-gbe}jA!1w{%Oxpta}=w#nt2yW0P2_F?= zKpist(JZdDnJFJWMtLE<3VvVNz2)i2I>JvA#jgeQ0O3`-?GlnvPx^K^XPkT^g$h~H z=lAn}O^gpzc_hyD`a1&AB=-}&D#{#df=Ce~qpymAqyoqUsF#CQlaND2sN{E`r zg3Fh}#X<#%zxDDFAO;!w+(3ojVB@KZ6@*G9>57+53VWV@+|D>PJ+-DuTgX`G**I}~ z8hhW|+&uIYN7}rap8HCNt~N28aR@V$sXT1EH_Z~`w;}m#0wwOp8S>yAcyIcfMXS~% zfw(h8IW~!Q;>YBI#gQ?Hmc~OJx zAhir1Igc~*)=OOntXl0!$L^c^t-RYY{-9!5e_EDYjJ{Zb#%uOLto~r-b+_e{(179q zgzgENY;ljfLtL!ZQnd=h{$UcTrlwPPaM**(VRE5feX2_IiHG{A>M$0;hlL#|Cz<Wa{KFi_2$L; zKvq+l_ngCthMw;ipgqL0yn;;O@#=Bqpw(_#Vev`3;YZu;4Y9v{i==ZFp4yRv6pfv@ z=D8BlHtFUs@PZB-o90omx$ewsXeF z*C%)m&38-=S=1%{WF;g2_Z^=5{28`1kNo~*bsWU&w1dsO{KHh?2t!rJhqH(81|o}j zl3a1TNGH#93mCNlf0*KE((FGX@f4e1*&s!eJ1LDWaYR<(w<-59msq)0#3Akwjj@2G zdCFI=x%R5gyvAC59$lw3BtG7K=>@+Ot)u?(hkX!_9~g|n+sDD})b)874moYNX_Nj@ z^rwi(*JXeo+vA|?vCuw8WasKmd^sa~Zbxo-t>rVrd{e5o#`8}(JvW_^E;yHsK4}LW zN73}Vm!&G$gf(x(8w;@J;??5eMrfgi-U=PWtADh~K+?5HTU9)F{T!Dj)e4Z5!F}xP zd>0BcOQgFfbmq8pSk-w9Wk0l4jQh+h%Iu_?88!cF>%M;NT{!(0Q(q4P^8nvr?m$mvU%vKbh$Lik5 zF=XL5Ub6w>?fB|-&V5Psef3W2>3KVJoTKelV$;FwQEYgIY=HWI-xR>zA#{N)6&Dco z4ik*N6+4v75(w;b`mzsaW_K;ga)*HVWd@VS*`gQ zJMrCBy(h>5^qP!c>%@kW7;vTDMmT}M$P`ilJ07L-VJL%&T2Dao2zj>!7-Wp2z%^B* z`$I$OGa|{H-qLvl@93xM6WamKqdN!MWyEJ|J+NImQ=o=SG_-L9k^UfFgDC;$cf`mV zk~nERap%ysfk~Cm*kUIPa{jtaqWEugB-=bbZZ2!TR-l3>!XE6+In4QPfLs{K)SO;RKiP|KMyORE{6Rha4!@8}r_sivEl5rY1fzThbFBnwV+;HTo#Fs=OK?2^d$6fA7+xIff&pF)be}`aV5m!hp zpOy@8Ox*nu(lmqed2Eew=^}@6Yd6}&#p*@kxKkxgSo)p8)sO{4FAa&2XI4E9>%S)l z?qVAXiiFV@D^0Y{RnW+x_0WrDX?xwUtT&&wJ^By%t5#YQUOuB&@87@En>AaJezMNe zb`PL&`*{;ibYsl;^PAO8vQ$zAuMRnulWzu}IMn-5hr8Io7%;H2<6U6&p!(yjsv*sQ zsS~a8=lWmX3&H%K&pEEtyMRCPsnKg;1BMK`TJMv=7*l@BRCdBL1f^fDXWu8y0?|7B ztFlHLHzqdo;@?Grzm`s$HaQnsY3D@|XNG=GoiSWj z5Cwyk>ZOi;lzF${xwI@#^GmHEaX^8=OmaW9mXpHq=m{|4uf!{HtT?xTa(_r*l9(ad zxc_z#+#H?LYUy^pDIF5g*;^iui~PDdxTUino_F1kqa91Oog?lao5sW7nzDS4TkZ6wl{X$SR8xDEZhcWxlUf?zjLd5OaDSDM(H1dVUDKfkpO?9KUQBM$|9M#08J z_An^M3I0V|MUij1#y0Me2Cr7>OTxyZz)O_M(Ml78=03T#nje(N*l1c7x(@U;v1@$d zj8cfkX?jk}DLSWsnH0ySeIr1Hk!S)AF<{{t^NAMJ@?6qv76SoVA<&;AGquRbOT4

-lcGEs8a6PoM6D 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

?^I3I z#bh{W+;shmreWsepe;~u`_^N#qI0L)c@NFr;kvJI$hJAmkPYEJ{v5962IYI14JVg- z$4zgR@BMY=1Yfw`DM2ruN8GwSlXv66)MW}0%ra1t8Cx6O9d5;F#ky~mk?|yo@G)Bk z>FI#u5r$MBgejix{X4S7J^?!(-QfRd%ecIL`^2s5B$RnHF6{g5)vw9=*rk<{rc<1A zA#4vcfbu~p78VWC86(QiMStFL6rI-ufP}ux8N8y})j4H44<0Yn)h&!GQr}GqW?_GG z<&`3dkEtLqOgwU>^fWEB{qXMYw5V8~37%7i=ogW`H<=j3+2r{7;58{S^q2cG+BzLI z2kuNcI>9+#QCGcl%kd_C*(h4uyf0DYCU~nUQf8O-8=13cx+4(KyjC_j7;Ati>Sq}K zBJg4A-7_=wK`1_)b1uy4xn`E2+e6xd{c2p^?YOYkP!IYt3x?dGJJS^vwfo&gx@4)l z7I9CzbjweC!awKN8P@Ol#kx+mpNsai1YupMQmzfm`W`_>`{{H`(Br(yed`fjh`sPM zb{2V(l|gii%zCl$(Nq)jD@@NO?4TFhX`7m}l*o)IeXPPK0xW3ie@QvZxH!-QoY%Y$4QL5!S_q1 z`tSD#qJzvnOA~&aU;rVe9PZj@5mTqhdxsF+^DglwVL+etq|FDWhS=wbSdtYTFT=Kt(1r5!|-k*ANTmYm8Gx4OGF*W(z7H%W-t9gg( zeqJih;GE7lYPagp>klN|PBw6b_cPXAL@_(dSNwDdg{hMmpZqKGHm=hXDo|HZV}%!1 zgC&!h^fY^pBQpeKN+S_4;k%{4p%B@VJ#U4+w;q(>C=pUBk4@?e2w2?nWL*l**j(aL zd(*nR<-v3;0EH=1gVTzjgLk0=RXlzYP8M7q+RO&c|KF^p5DqZcDF_$23I4E zVi-Ay851r(;;}Uq$FfNl*x9Jj@l27?<%fT-mNneH>hdU86E$r|gaQ8E;LXwlD>K73 z3#5?8x+skbt`Nja{S$p0lpPx>7z_C`$G&5LpYhZaytU-L6VU21478PzzOlf z@*0Df`mz0FYGX0-%-pasr6h|mu8SF@hSV&DW=W?dg`NpHU0+sjcxDM&RC~==v5q&p z3p+J?oC|y2-`M5~I&;zM)EMPntiVr>AX!A1L)E^Z@QPsbIbKiJ?rEVwD}w8}uE710 zuzxNRwffoEw6~{-rW(`VgY=J3PMI{hSj-Y!;0BlKsmavOGR&{A-2U@Bz>;!c4>mG5 zR*fZ`2g15x$%(x#F`i-?Eb{NMhctqW`q#H$V$(*_3r1LGfr`|~t$gurbulEKNtmp|a;^V*&-J(};-DX`G&K{=eV+e*=NR3x&iN&#{5|-*3m2!_w~-GWz9Y{R7kd2bTpJ zlytz;o!$uq{`cFe$uHot)%(U16aRdv|FlImfv1a)MM?cb4fxMJpdnI@m6w-Te&gx% z-`_nv3wZiK`YGtY-gleSV{2@G~$ox7muBnht11DD*E4Vm&twzR4o6wGx#SI z{m;9TI{{CpwD?B#&!vCk)xWQhYXHL{qwyfX`^VAn$IFQ;0#Dx@@qqpBw+k78VJVBu zrK9`LNdDRQ-=P0*(Es1{4y<&HG|5RA&NQQOP~s zomW@M~yXP5bg zLO>I=f6pLRu8*ta)sC3uoPDyiQ17IfJ2_o4zRRThsX%F1$F|_F{Yxa2xCOcS`7n(( zBCC2z_LClJk~7@U$FZ2HO^eMiN+>Mp*U&rE8%G_~R$%`KU4EJt_-OYm`E+)ftAhn< zxs*!qB(0(PFF(4cFyFly833jZ&f;~ZT|Os&@y}Y99*3QR&c0N-e|JCPag9b zFQ7d3iG}?}Joc$4l3V|I&Ks^xK79QYmB+uwyJx;oT*C9hnDooH@KW z&I#GpUW6Dz2D}#p-Sy&Be=Klmf7q$Qyr3*zQ2nRh9V_C5!J}63F-uW00H4>{X>*NQ zfcFTsUs**emqtMC%|CrY9&jN+u7Jcx3&mcpHTkcNhyavFXy~$Uk!Vb95l*}i&q1f) z_ee`bg@z*pB_QWf{Ql3K|JO&6j7*ihH!WrFlG~4{gqeZwM#ApA9%}jYJ;CRtT84mJ z3UzD`lys*8dA*RDN8{h04im|^pEGhUUhTZL3zEtFYJ$fc?vJ!4c)FZ4z^fv zjZ|803hWqFz=+JV-(X(8-Wx1wL};Hz)j-C6>i>*I05X6eV7n+sZ-YO}^I2G{Np1?e zO7JDMVpP-L)=<=JySCMSI={u@kf?HtA262?GtzQvOCFVtd^01okf0pjB>p=7302&# zlw6hd*ZJuL-a$RxM??2ZXv*aC`-7;@h*4by5)AR(yp#er(8qp`it(9Dyw`j?aK!OR z#H%dN-+CMRB5{*LQ@P@%iZ0iYjp;L&fBtyq)PLACn5<<;`bn#M6b?y0=`G?Bptq5W z-uq5n1Q%taQ!g8Iclm}}VK)rRkgZ5IIY~B|QMS>hOfT|j^~Q$gLHskqA199pJv3hE z9p>I1*0f)M`t3la>H>F_1S{{dpSszDWc+S@#H|RW77n(hmgZ&>sj$7&&u{d_*xSTj zO*_Z(5BMt_*HeMQ_6CPv40(0UuH5WnZ<i$e6{ve7JPoMrU&EId_sJ>cLlJO3a7b+T@2B z-+|6E&YC5cfiq{VoIm87GrvN4iS)5@iH_YgbKqC~kzoE@SObP-wF&M)N(7}*jq5B+ z^ELA3Jq__|8d;oFNi72k&-3kM8o87{Z|UW)4dy+e3UvPIn zJzaTwJ_p76_6L4God~*?i6Q1So2y=Cw_kzg^}YLIZ)9&eh(%NAm?$}QvnQ!q3-)wI z%VJ7uyXhupFsjb7S%FA+U3?XsU=IZJEI0 z+&I1k6G`DDqZZqvLq-_lRG9|j2$jRBp#Mv5XiFu&ByYgqqK}0zX^h#)d&Kpp)o|H~ zqkq+au&~f7G;R-N1LfeZ3=9iRIImym_>H)4hhVL(tv?Py6Pw#&>(x(O%4m&BM01Sg z$bH{?a9^rJM4Ut zwf)w4c(zK^z^?rl{I8Y6l)Oe|A{Ycg7U1kdY0x7_Yp|JIItYtHR6#JA>LkATU4ruX+cVWy!OcKz@Y}EAVi9k}E)jm!?_^y%ta@vH zk6L1L&O=W{APZ5ha3}0<+#393D3EQ^v}}Fi=OwWaQs;+iG9Dx}TR^Y=tbC|6u8@_7 zZ3XeSzHb2?Ioq|_BN7C+q1PZDaUK`19V+Y1#bBmGXl4u>=~6m56{=I79&=d3nk*Mp zVo3RE^N;T9gK|>#zF)*H^dGhDD0U4KLR_EDSLpzNGp9kpF$GZJr0CSY8wO(MKM(3r z=PH!V4m0iB8!FzVv*hl}alcpEB&yPD00k>YKb~6f0?98B`75-VVhC)0u|NLQrPK|4 z>c()Ud=CE0r&wG4Z7*XTy(PKC`H%)vQDaQ&(Px2S|4><|XcbRHLm`T=&OYk%2_vUt z>GVbS{AK$~-VN;Sy0vW}X|Ug1lJcT0TQ1zWw{SjV{)Tto2-LHR=r(e1WjD`A+^XbL!B$wUaONeStI6`c=C@$Y?8J#VYqXz# zhU8u#7GeOd#31NpzEr$!+0r^$fB^llfT0Kv;UVZ(AoKJkhtN4PacbP!W>nk>zrcID zvV)7vPhhE1ea3uAE0@~vOG82kcoXxnt2Gb_A-4=+`d&eN?`trd$C^lC9az44gwok= z#)q8^lYF)EQW)8(E6R$5=_N`=Ne=m4&{r~|4$L@v5UF@;Oa$?{42&vmZ1~)LzdbSa zT?oYm5^n%jor-_NLmfk-R#K?8>noN(n(qEe3Swrx5u;;y)Pnj(BelS0XH?vQch}UA znON(C4>19FHXV`S`6%P9S`&_RZ-lT&_N3!=;UxUtGeO79vaVDyQd6ME&6Qh`=8YTh zB1_HvI~TyiRq1P1^;|sNZdf#80eYaECep&Gi^~bj5gh;5*&ST#Yjvrh0Rr zXmCU?IU&l|S6AUmmk3vVO+3(}myG(_`QNTS;Pn$lzcCs&!>km8{p=f8u)Ek{J3dbX zn}51@8_!~Gv)CC*=^ZSca9qm>)j zD?fn@CyqL4c}Mm>c-7Ey1ZYs%PI$xU~BtFf3+~vWyrm0N#)zb*9uVbfAVpsYBk0 zR63js24282fm&-qynh$DJ}_n>e66YwNeUDc*p+DUElNjKvck^yX1%peE)lomd<6kB z>g87^M&0G_*HvM2d?V!1@Nq5y+-)UQH9@eU7ob+u5 zR;^$oX@o%-Pq3_<^uyvIUc3%B4<#Bzzp~`xA!=;FeepuoJPqS3h5c91N~HMO)Le!A z1YOT0q?8p`x5r`?tG;z@TKln&`QnKRq*6%xA*QjHuPNdv&=s71pfchtu<``!)0j2G zgIGYR-m^5bw}^bHcp3o*Q}dXZLsvju9dASv49I|{3!bNUnOgFG2$P93=Q@3`w&;nY z)_NpKv~@mcrdoqzrkc8mMZa15>S&P;?)6vcA5GTS7%qU0g$i%Wz1@RWenNN`zdkVD z;Kx;Pim%;1E{4*I_pumu#`h8>`@!m>ZWTpAQ+QucV%Je~TT>E~78mQ(9V*d?SJ;&z zC}ny5rIQU&%E}cu1gXW{Is3o#C>U`(NEtW$CqG;a^4wZ}ohn`H>B5=a>7l}%kVo8` z7)&$C>Ifny>{SAX#~MT2#h%d1`InpeqA}zik#E~to>*fB+vb$Pt?`n2#Aq>ftjiAi zDQTW0-7U)5Rt_8%!LmJ^Pz|A%!KVGk(H(f*O_0H?Lrf4qm^58^T`_hns^doz3BqvK zUYD7i2g^RAiQrq(%pwZuimV(d&h9?ugyvYK5x(wGNh7?c_*{A;cN#YDLjH^4#{8il z4sCY9@m=SL-KaOK)D6$i(SpgRzq-mzU*523@My?a8@6R!?0Hs@x15^B z3K8SeTF+Ka)onGL0m6^;vz2+r?;2V|>pia}xF;5M0;GQPPeC=3 z05woW?$J&Ck@UTRelAk&i+o2`Zdj#_c^*bEy|`bCjUUYPr#DC)Ck}vI37`p5Ax*J> zsUV744gvPJ@u7NcbJRR2L-yTdRe|!Ofs}`r2xply9R1^Q{s^~@-)v_l7=80c8aO?U zE^ZZ^>)+p?$-ZmFRvAC~sg6_ct7hdnP7{+BG|s+H)=!1F!Z_eMQ}<rhSX z!*vpnw_$P4Ibu~2>6p%8nV?IO`%)+%n=t00+UrZR?aUk%Y*C-^%`P?p=N`Z3V{{Wt z>mw|Qa4fsWr)CKvevz6SM~(UW@P*E5r zESF!9Rcky1;x~;I0p{NslVSGPEA!-U|HVMzSx}=VwWy1>lcf@O>8cdpkFtL28JI zl(R!^r`~p5OjV7MZkHe5cUzlJDobR^GEVhbj9%V;L(bs?Ap|MIi#mj~$AL0lriz57 zVNiE4%InmXgVRt#RX1mC>P%W~QwP#b+tkmtClMGi8_kDbG8m2R#ESG2J|14znGetM z6x`A1OOoag?n!J~pbL8BVzxl;Pg*MH(8^t+ANGjs@$CM>mqp4k0Nfb%pvA!XlT4<> zN#smiEPTFHtTm4en9Cvz8@zeQZQ)&+7vw7J_&z_9MW)K>I~XqM=UD8_S$Zgkgb9hs zwh8}?nt71djK1NkqsfW=P#vcLCP$f(BOGI*#rv>;}@Y*JL~x3 zk<5JWc({JuIe5WcPs+VnHvqMO%`53FK0Gn3sZB~m%0HXG))nWP+&x!76zS+<+1V&yZ3 zGKXoJX5g};Ogl)I4V3_ck>MkiYU@sQyQ&rwx54a*YW?FtL2PEx^(f0Gl8NFukP5+I ztE6^S7Ko2*EgpXx@ILm(`9fx_8!Pbe!IJ1~f%VpN3AX;}>^Xf(NRBvx4dL zQmn_*ege*2x=wBkJ8G4j<8BTvelenB#x!?=_s- zvt^G$_cgxUa^bpWYF8j5KElQ zw%8;|&lzQ@9x`jp6BH*tI~;@}5yImX=V6a|tO%8UGs70@_|hr73CfooK!#N+sL{2I zxT+D4gP{`=1Me1(EwN9aQs`qS-Z2n?d@=am`q6Y`3nF&tu??hzE8T#Yv#USpHsV9| zFRmIU+J*t?LnvFfUZI!wj|#LsEi6j-J@;d_U=Utw3u3CX?N?tDc)BSgR#!ywV8B=G z;~y=lVGz_n(o7Utbx@~=_dR-u1zZL;8*A^YJT{u5VcRYA4Y?bYoS1E!alZxOn+^vY zuex_;nXI-y25?>T#;18auAvtH;?=tOPGsL+;Q1lpNeY$alkl@X#ny0YV!*fnT~H1I z29IEHkp+AkIr@@+EMgPVLAcH!1_*q4w9fShFa)>{uK@Q!W^Ml^kW*KIp?(Dg&m4EK zhNZ@!kTRUJ@;*fWmc$|!(IP^1{R9;7_}S2G712U)>AKcyWQ>f2rC2!-t(xdo<8A6o zM~EIqV2IfeYw#>N0jqe{{!loi^wXdg->=y5B~qfQ%d{kR>RaCpD~k))I~bwviU$-= z^R?(pKWw^@-F`R4`6Q!23*y-OE6tH+Y53>|(a%!JFyO-zl$iGnbv8}Ye$-Ho1HZPO z(N0ljn?gZjaL6S?xH)jtuNvPaDtjjyilvol49L7gg+f>{W4h`?C8*zVp(A*ftFf36 z*a>k1i8Z*sf>_}wOUfNAw0wa*>kZ~65%7>kdZ{kW#s#R=i^T35-P9n90VKwip%-AIAfUnPLS5Pjr~Oa+V=W_wgSGbk`|E%&&6< z-8eo6@4BEw6j=U!G)DokGis=JmOBUz9MIj0en5Va;dBykoOn8;j8_7Zk*|Gs zp2LYpBoTKbjy_Dp5k**0nT>Pdr4W0M19^vGcy%i)mDWP7$sJdg(*YHpL(hw5`1!%B zz2ddo>>)qI%f^*8$+XG$(C?KBB?*x3asOuB%c3P#iDe(4wHK1|X-?eUWlo+=_6I3& z(gzzX6b>-!y-Bsved1RY)1Yt4TNhkuJ63o3g5wxL)_UDr8dn`Oc57}Fvw%LiosV$D zsYjnEQTkQ%!Wy&GdMsZK_31t99^CvBC>PYGkNnoc9qlZv|agBUY<~+rQG4D1gU_e3W*o z-)6OJ|`3EqjI4p<^gQ;>pbR%AA=gXomLiB5~wac)U0K-RYtlNww{cS&k<`@j-bo>u}KD>D#p0OmeU{9nY{i*KN7l>fNcI51Eo| z!M^tC_z+4Vsn=l`iNk<3 z-{kGCuawfMI4)bI%V|E*>6akkyx57P?-CC=dEn5F=2ZHWn`-F6t#y!wG*Ffq_Klo*zg}FXJk|C!O{XCb`A%7m(>mlhvaLl3}Ww{~9 z_+YC~)vfzh%v69at7_9<3h}_MBOGTIqh^wEp8N~^CwPHir(S`o6AbXpXp*90;3j&i zwUZXE>H~_&;EA>A?Yxj!#$v<7@YPqQ%pB|%p9hqDnbJCQ!BnB!X-vEW*Pr-HrmZeb zVzA;N<)@6jofUArCVt01!}*4<`TEs|j$gUHCQj1FuX-OuLBT#|9FnRKmVI@zl54r^ z^E%vIIt5iM&{9uyggHS(L~nK2CE}dR^P?96i8E}!dnQkd!=1YOSBfk~njVb9zUK5F zT(3!>8$aQIt5t`7=OP$>(tb@Zm&0kTNx<>0l32)Ro?3$RyeC$*)lH$S!u(sV=eDQL z=eO}L5K@1Qn8O9^^SniPgHWUvtGO$_!BnMZX#qEY^1e~VVLtTcH(cc;6P<=IG0jqz zNhRq+v(aDSwQHIRDAskGtcoYU|-md7O+0-`0NiwU^!S8_* zK5tiKB|uxA4qxk8+TG=QW0y#bVzpy&F2L#5Nj6uyZQ$BKI0$V*>rirbp_sVHdj;7= zA6(_H6+8XJxIC50ATPOTl~On{tuP! z$JS)^q=gPRK|IHtFI&XmNUYb;?6V85=Tp{bda*iuo61TsWYffEM62@%_R6NOr22;~ zW_07{YMc^a3gnykQ53RCp||a%7>49%vPf?;+=gy|{C$g=xSK;{e z$JawOErw2M=(!1`d_1Cn=Cv?-yD{ML>E5QqudSL2%Be^em*(Sk^RJ~_uXI5RyG}8L zhzzA10m~S~9oxZ#qHO_u>&uJ=+JMukBL4vs+a{XH<&C_v`B zLUP@ZI)IW12TS7d3aEg@sIJxcx4m5Vn`a@Nl{P|Ufi&X9%cD1VZ&>m6z~jgvYkoG# zAP51r{8iVQtBX)Il#Ht_^t&v)!36)MHR^VWrzDz;$WLZbX7Q7oT1|F&j{Rc>0hh{5 zemQKVN1Jph9{ulKz9$zWKJJX^t@UbI%6-`$A>g+AwDjZgWm$Tytbv?r&@ow*297w_Fm!Z(7U~}G2VK%$LGs@WST&!Mh?K>tuq5N04_CMiC5nT#^ zAA{+RrQt?een+(D*Bk;~Srzi$ciO|Senp$DC04f?3Poub?Z(e#R zb7ak#ICDO%lNqo#O1{55W8deNaH@k=Ua|3I$Y}d)1UGB6t+AQklV77Snu@yI*A=Oe zAg`OsY2XCnUyP}e=#8H*ZFLoOt(#v?T+C0X0Az$=w=^YoPC{+3)ZzmOk=avXeVCp!?AiWo{PF{@h^ zZZF zA8s61G045ekMvuLbf#%(^^t7vuZ}n(0&+c^J{`{MNhC@!=^9`r`gp8&_XVD} z*e=~5N=}IC0Tf*s+tCo1MTqA|ozQ#u+V?evL@0xq`*Stc5EJD9i-hd7+C#Rjumw(wh(Uqw>L-2o2Ui2K0 zYwJx9gY(nYp0)~naxb}`fX?b5?{slgqWXfb0Bj%><5cH9ZIWo^hd37*(b0{KjMO{N zqC8n_fh_WbUT)f){LsB7hE&46b;LZ@mfm-!lEvP&Q;44QOIy@O zOGm_+njMebSGo}Dfr7q8>=h2tVxyPdUnsE+?S|9Xw$~lG_q^t+xe>sv#p7we7AnR! zVzTS3E(yzYi|XFA6+6CtRuYazt_-VJt+vr=*(+y)1#2{vYsi;5T{~ig1Mu~$RDIQ+ zIprm|z%_R_sK*fa*DHz#MDN9^$7Eke>C?VZ)WI z7v*4GuA~wSQj!3tmwe;Ob2!|a--;p!R zs=>BR*ZGbKE=gpC#|P@!6L`ni9U=JrmdmBN6eld$f}bzD{Tjr7=rL1oJJib&pBY*b%I+Y{ZuIi+~wvCC(= z?PK)uv%4Ukgl$^oVwWn_glC*_W%f zB-r(91gj)K03AlLFgUCD{S*G?Xl-)o2%7Kx(|xT|A1>-v25n4UJ%B6f)VOgy~V+NZjnN!=Go0gtSk`LR6tK+etxJ|(r?TDjzxH7 zZadNWRD3oI5M#~9h+R4U=I(TML;+AZ$Q~a8V`G?!dq;J}&FE4XEE+5tLN_0~FVQ_1 z{qw?Y#i(5sHZW?A^0cm&rk+hwHbl>}1|1se47)`l)%l0z6m5Uc)(+~EOz!fA&(aKL z@LI%A#jE`zY%3CIF)7^m6DOjCTS|&IPObX%q14@);Q{!tlcUxrnqX^r``Z8>OV6D}n`OU&ZKB{|u&TxyO_0Ug_WiB3dB zMn0~>_TpO)WSjP7##42~dmp!`Id7_?1=}wa_ID^gDZmvJK#A_O9{Yb53vLs?!80u*UvwjT#SBXaV;A&BHttz ztsb5HxvJKNgI3lwplMO_i12u$z$jE|fkYc~Qm$QbP8!Z@h#sYE`fkQlnF1+vvkL=0 zVG&Za!X^Y^1A_fy7%Dsp?Kku$W-$O>)m47xvg`Vsm&L);Qf*o~x{)(}}?eR@&_p+dS)|1<(Lw~JN zS1gO%=U}yIHCSNXsmUh#Ht!h?y zr6A)$z%DTA?p?5clCb|8id;%57|+ysdn|FaSe}DI4UlbFWp2Cz5(hkOr4AM!+ya5x zt;%u14+BB_A7{pL1gWNr$HOl^=RH}B>)(uvPrx|`{Sg`=AH^7mqjHC;fGUhYcYR3r z-_%dCo=te`avoIHGI(fw-$&#KKI1~bY+*3o-gKTVlRp1z@5 z)~@C#2|l-RRAz-}k3;;&iZX#~#Q{jeF#bjN5D=hkSF431#rNZN!r~)?NMlUF)EbW? z_VdG1qVaqc6!}Sna4@`sTUK}tKc}t@C!jz6<1IqiO(^TVS1G-wmZ0ex4aZx%z~zm@ z7c4}ZSlv4}nl*5tCk!5{Z4i3L$}AP)8V;W^nY)ATH4=CzX|^=>ZBSTu+XtyQRJvYH zk&6sSA2HSrDsLW!9bDG{VK-1Wo=Z12rNirWGwwdLbuf=HS6N9Ae z+ff64)O*J=;2rI~v}nlOo-Wg_4WyM6qD`cId`VY{B=gaEdxXKye8#?IOR`M49Ws)2 z>zx3X!h@F*9(uHFmjXns5CsyxJ>57%s6MDLRecFzKUFJHNcCkbEK12%son1k0Cg0q z?wfcT{&BbkP-9Db2P!_hI=#*u>-`rf6E_0OPAp8nU__r=sB*qN%A~@UoSyIo1DzHM zJz#pz(e)&cvHdTWo{Ol6|FxoC%KC@?Q5suc0Y5^3$*oQuxBeC&yv3!4NFx_H{ik>lB#gECWN2kx>VI|) z{Z81ath_|e+IMDx{nW{LCmj89Q~~~U0nR(r=Rf0R+OGgPO+qnNDor{FK^hI(qxi(; zU&O(Gv*xDIe^chn=38Xh557lz{nu+qOG4im4u0-QL=?o_D3DdVU>HqMpb9Xf{$Mdw z1Fg-T6Dam4A5{PC@81B^o=%6BfMRhgw*_}qdFmv+W+eAwl`fr5AlqinAIQ6PIh9Xm zTnDAF1GBEv%^~p@A=2nKAria6>yw!-AEWQGj32;<55S>{vs`!|q07Or@J+bjdpN-9 zjJMfv%)3x{F^-kP@Rus*jxvrGj%2C()v7RgdV(W#N;@g??}tDEzky1py>-=&cJZt? z0((!xG3wSOA^QCt5y;c|1Z7?4FO$Ad7}`>EqN{4;PC_eUin*9kmf91?WN9wJfux$5e5JT^1GV66*bdeE8uchD5XR9ECcwK}G_w zs|i0MJ=6pG{Y+V+OQ&Hs>?vG!ua)Agi+flpR8XRnJE`@BL1D~FbLTPTB>0bsD~ctp6*vax ziQu8~&(%Mu_|zB_P+yD1K~c+pGHCz7c>WLjKjiN`|I2ax$IlA>EhPBg$N%ZEf3IHY z|8?E}rp-U6!9PM9k^i4B8FurrjE!_qtnoEI^ql^*wv~Df?L9hioN0fIL~oIDSD;hh z7AlQO(EOuZpk?!&9O{4jEjzPv7J8HlTnH_H(ZW<4n3cuH_*4N?nJ7^~6^|}DJyfXZg zNd4~}2^J&{H#;>UoAOF$b5Bx>_73}ZMe}!$LUbz|AMrZ0t8G_CE_A-Umx1^`y1jg* zuAITuCJAI1q8d(l#4M2;m9vsgW=vMNALVw9Z(8*=0*p$c5+g7wvz|Va`A|x{Db(k(l{>5YXzx{m&&=KIc)V&+E>J91z z3zU*_BO>yp-SoH}{-9ZOKaf5s^NH=bY_go@`&^^E4xZXAXEM8s(h1;d#lpp<@jc!( zvjF@)#CA>V%zhd2lT&H06f4kTA1g&H^Y$5%Taw}yv}9ilB~1b>RwZ+-!jC7 zkV3>|hg8X3YNV7=t`!MnY8a;lD6kv~0Pi@Z|M@=L+db>Dhw$~~!cGs||Hs~2w#C&o zZG#Dcpa}#C!65+}CwOoR?(XjH(rEDD9^BpC8%S_>*Wm6Je0J{Vz3y<$lOHg1%zW#k zd-vY8Ypqpl)mdj%rE;$*2b(1&j1W5~6sy%~?yg}cGDmWMEBlxVI;11~7(*tru!wGZ zuX{mpT7|)dba#`ZKR=?Q6~97j=4|qvfqddR^Wwo!k+wLT>*n)N{HMpbFbljB6@@*Plbee-nv- zq#U3`2d`xuJQ~PPUmmDFPo71@gH|KOr~49OaJt!#X-l;)Z0tFt&Z_XNPZt``7rLgt zwn4sBy*EUq!Pda*Y9Mzo$zXS4$M)Lb)gU5!cW9b1bV?9LUy|MV_L2e@4x9SfG%j=Z z>cRQW_-UBGo=ShdCM(d1^%Z$ga#+|@c@}{WBxr%vg7EcX;g*+E__Xc%0G4s%L2W82 z^nS<58ZbX9ZN^ElPBx|utL*ajNWu|5U{JDV$SV}eM=srfk@4BGp(fLEho?%^3=UL5 z>l8p^TB5SWFsnGV6`O4DA!ZF#-mQIB5S4|Gzg~l1gB#t|@peT$s|`(ojD~fJ%DJYR zTDf+H_=81ZaxlD|PrY51%Mm)cYKMISx2M>4re>r6E^|Z-Dh86( zp*voN1P8hU?!CQ)_(Kvr8tw|2UT%o@ah@Ia7`i*f+udvjNTd($Mfe^>l$o5g!yEo9fZ5r;kJt!BKvvpQ!I{|0B%00mOZ=zH~&JI?? zz;+?s{q7gMY_lp8TH?7+(5K^bFYWOLJ0X=u`vjodyfRQh*1U8UDc7o#wq?dmunBJ& zbv06Ly~3SA$e^|;3KSm1N(Z(v&%$tGwp!9nLam`HZg3;qMxTnP{)MC|&P*^G`QeAR ziyo_qmA`_A_{@q!;vCIp~Ly|^tjg<4aqp}>f`_28O-C!ojU zv=aM96AM)S5=K^X9zLdRL3a*Rrh^TLp;i<8O@AxK?$6eJL-i;l55JN&YGT~x?J?->}q*0B;9B2wK3EhP&$RGM6E8SpT>d^plZ>T-BTd(RwuGp zdEriqYKX~itJJu>dJP}%Vcu|C+Cnk34qrVRE5(JExjN?2Wb*AWNUK#c^?lXW03w1B zHnW@W4(up7oxe3@yhJ{(X-IOS*;Z-O;m1r_pw|qYtDf&i*8#y-W%F6RnZwDfSyyN5 za$b9E2KJp8abhYZ_I|?_uTo|7x*yQ#>%tHIRS5Z?Z6uq~i;;R89Vlfd-ZNcLPPcxh zW1}oc0V1TMgP3T;byx5q*S=B22;)_sYklOAR{F}%oIuMLep+Y^WtFU+pvS3U{r%Fj zwqF3|RE*{VwNT{@^~3gpv)&d@l;$}v-xeJO8{vMjelKdG8EI9rLPe(Z52#HS85y&^ zZzW@j(KPK%FQH_{%@X5B7~t4?xP9a1O?MgyH@@#My#GIw3x)i*UXAX(ZQbF(#8`H7>_c%XNK4w_!7W0Uh~`I_2X>`G7*{49FXM!{G!< zJhtjs)f&@23Tj%*vz1?=GIE?>7aY$dSbBh36^<+d)t1rkTh9(*H$M>zl>VlK4-;Yy zRK{wa0Szvhs;O#;IX*K~Kc;(Q7E5P%%L2u4&yxagaa zVfyxzV8!7xn#R#Y)MgJiv{XSyOljTL|BdDRKmNgc5}_eEXOqWv= zgn?o&-E0PANFB;Smwd27+W%FtMz0n9C>e{zd%K7eT4t&58w#$Ujl!!4bF_k7=-UQ#`~Fkw(y(l<18r!{ots%8q@u<# zTH3NJldHo;bo&LAhX0*594>3Z>J}Z%6tIvR8FM+E5%g72;mzA5Vam4Ok#&rN*Pu|&|AGL+6oLs?XoWX5HV3ER z%}eN=ZdVZ`)r03_wwyJ6U}U8CIm~3-sOQibh}q`y#0dBNbRP$bMT{TBX?cW32f($V zmEyGZS~R;Rj_s4x95SzG^%i7kz}@!cXDA9^hIEVx)XXV$haE^LIZe`BRe0>7)S7c8 z|EB-h|8P*{kB^;?_=Sa0wres(xZc70@ZJoi?K_4zi^bA=;W4C@KGi%)yx(cKyBX0E zKtZnz?vTlx<~%?nOmSMGId*Fhi%T<8aZnq=(G(PJL860Q`Xt=rwz-dWZ8?BU zS~q%mz#dv}K=}pSeKjwbieqL8)QnAGwVNxpoUNQ(M``O?B@u%Gf6?xbEBh!0;qCe1 zP-8VMNMj+r4A~!AXt2YggPou8bRo{!yomPKmFy5)$079Vw zSPY(V*Jqfb)ufAlJrOKr(J`2OutOSroiE@xKRPG*0=~}BZmD>s#eA(Zf2ny(g7g}r z`3%pT$q=6N1mPP73d0`^Fa3SHKANxj70U1jxD&Zg@WVpQq&S^N>ZsNrPG;>+6d2qL zCAEG(XTZ6swV3BVJ*6xY>wi0lhHjr|Jc9+D$+SEB;yJm{(9FlWNG*3g|9xBj?l03} zoIpR9(vRM+p>u#?6a~M+Xg^`*7`*hkk|2LoK&k%eQ(V+yxWUfYLvPXw=fAMM|8xHI znji#X<@mcs!>O@4?X8S_&wRgSV?zX`N!{kEvAiovbj;=By#Z&9NCn7e9lI!z1xP~V zaP@iIf1PugZp!4Wgs;*@-Xx z`kTH)rX-Hrh2Tw9^QHIlG(N^J_P=c*`0e>0pGK!>-kyS^DWuGrIRPf2KJokDx&_|t3rP5I0 z4QVjBM2pfHtV%_nyIU$pLyo-oy96bDo2x2(-b*fJsl*SvoUsx2Kw#vJy?JXa_S~kC z@TNH$+ty%`kfrI4Z)eKXNNq;Dps{3@_7C_>jDaJ&3~v<{iC;*hKViLIgI&JANi$fV z&RVy^$U;D`7e1`NXO^RIKX=lDT8&x0s0e)$A^8Wqf&i$Vb6_^m3rBMyR}!1oKWb+~ z0iB0@A8@StiojHH6UwxUb> zGn*9sL6yHhqW-!&tqW^qrx}^6vT5*iCE$<+K9>8@t^TfLW4?qa8K5|@_0a0Ij~=t$ zA&KM=S>sNgE;B!`uG3=1kc?=B(^KPx%~{Y{TJK-dt4N_%n@ZorW-`q`uBMVE8fZpa zqCejJotj%PkOPVpQSI!f-255emMD+y__^5?;usj_mEBuzs!)_T>~A1B*z}^^12|Ph z`&zTTJH1u5`Y`_e-voyLSs21!ekY)R6lqzzTw+TYHY}uEIm==Mx8~s^r}IpbD6>$% z@L=>k_A1Yj$!bN!UDGU(ukdDsRC_h``U+$`2P@nZZu!lJnJ5(7tbw2*JPWt`E-$EE zHCxuNKZozqX)?fRHD2e^*oyPJ=bFyE?Re=+_~Qdejuh1W>NB3QV41AG zY6?q|&?ZoeQsTww;tX@lURQr2hACv;`09|KKt8yQlB>PB;e6~S7x8pYx#Hz3NAVb; z)(SDB@$MjsW5UW1#S+adupPbF!`<~nFgf$1#7i4=`h_$=A@OSmI2>vCF2`KIiE71~ zRa1-~v}Am49CA`gYib*UB@4=d7JNr9CX0SbM3dOP9VeJ9N$j?sZ!n9)V*}{1hG-wl zH1?8T^!L+R8J8kWzf!xpajyLAq(}Q0_!;l{T91vO8>bcT$!i7ga7ljBMKCc3>)M1rE9mXt$t=zZ+3LNAymG z7gYQrY6hMU@pLtL6s5YsPLI-CXGQ|s@Fjo4F-0N{Y^?|kNZAHs^ZPR*)#F{>S=;^> zw@wFh)D#RlOe0|}T4wQbmKZl|8p}(>mWQQ$OW%2i#R5?~bIM3<{GDDSv04F}qXCDV z8L23ui=6azRtKFX~=vo{z}GNPWTnW^{Dy&atZM*4-Yg9`e!Oe z86JN4jWnk=D%Yf@ev$_EsAIQ>xW$x|lttG=N6*dXviQB1$e}x!c)=EMJkOv|zC42_ zeD?f*KJvVWQji>xSzXCsSxDZ#&s{id=3B)(?mVU){Q4$q^&n_ovAq2IKt+Ro8?)Ue zmC}J}Ura%%iilquqETM4|5u5B^x5;?D^t8tg@Y*1 z`_Gq8^i4+a96IInWX<@m4{(5jV^a|tf+zZCbe`OU=NgW1J0_e!i2wgKg1@ivDn{cO z>1DH(g!@0k`s9z#p!t8mEe`e{Q zd-SjY3M~Gx<@+~@(%k@w`ntoj{;I$!c*1RcJXVnJpS%4TnT-!$(&e~3a9{mRft8Za zctLwTtVDm4=>H$m|ETQ$OGC=4!mZ~oRsV1!LGSj`Kj44Qr}WA<@pO8I22JbP)4>6f zvK;$=opc!CJT(xPP(^u2|7y@*tO+nZQQv&$2fe|X`|FH`Aps^WFZVkd#J{a0;`hKJ z`-*h%*OlUp$}>`sPJk2#^S23)3M^ic&;E{owF$hyI+7nj_V53zi3#BEAB@zNfGL zt93>Y1q`sa$4B+If76QaXTZAre|U)h8HxWF4l7}vx2BRHO%VVX=DJ+$<^o;r9aY*> zvJ&sjl9V2LdrYv(>7ky@W`w)fdbVFqhBeW z#Lo{a&3LL*V}5;OvV!mRm8!taUBkEiH{~t1x#{WOff&XoSI~y|6G_deycFnA6i~c; zlL1w|-<1C`{H-pA&C67AV8T89mPn4YEExjf=tvfSZnz-I%cHxg3N~YNgWdP4hcyvF4+@sn!o|rf#b|0mI5tRI7==F+k@Xu>($9@(* zF}d`-gzgMY;_4b$-SSZSwwp0;@BG>b) zN5}wOxX{XY5x!+FuE^k%Btukw^ZTFO#B!|Qo}{W9ZmH7rRn(FDj9X}*Cz}utDV#hj zFYHmWxSPbgs=_zI-R@D*{HcY7m(4%#v(uhkiQFX6zkj0EH(nH=ZTYg)2MR7X6+-Dr zxa>795hI$^!mhZh7tf`>+;&83!~Zd-5thGw1`!s*F5s!FXoS^tT$rjvD5T%rQFDK= zJ-II%ynMsY2PWz~p@X@a!MTgw1l1a|1n!4l<5X(3R4L2hvY{KEftro>CIw+?(QJEF zs_aShtc-yE9A7k7gK7}1F4+d#mW_#Gt%sb^*-e4vc{x$$3Em_%F5=R z0v0IKFJJ8@)l6&7-(5^=8UFD0>~|=jRy8-DvRIg*C;PYtx|1%gpqTr?ZoWLKF?PPw z3dnF*m8p^1lp186CNKO^9sP;a4e;`uydXS=Nn5?arDs6@1bQ5c`V4j*ofTOIz*C`5 zTLAS>LVqp;V1#0~SqGfHZ+g+Lo12@7>PhSZfn1A?i$gXR%)F&Qy9ehJU54HHQTQ@m zJ!Xr>mV%}!Rl~z&&m_PMfcBG&g?w&aEv(x=c*ATidj?B6I%p(*&+RuHN;dh{*)XI? zeI}6t;b1Ts)34I+jY5^0)^ENL2m048x;_|o^w2k7p-M&R!rsa#h|Z^*$c@)7*5l(lRfH;iH{-T+W#xk3X)qlv)hT91UD!s-stNH;&SCFISsX72sH{ zW{X%ll_b`P_kW`v7?#UTENjKrK`24NtX*_EvZQG}*PUh@^?-Fraj;b78aEtd{@8BW zJj$qUglBg~U6-Jw<@&*GPPUA|VO_^Ct@*0*NH2)BM5yei^I{ngO<_^9tnj!dByVxKNUhlw&Nv~@_J6WG{-n=;$i~bk()xx#IjlJEf z2xpXo5y77keFj~K`+J7ZcrF@k@T<0ppp9qux|py}BT-@xB(oMxto5?%v~LbBW*fS@ zavEURPpRa2%|axSWYf4^cuG`j7CQD@A0L7bZRby=PoU%hA9d|gq{e1ye|9r3EeMgV zrlc+kf;wh0s`WUnQCD$)msBrj-ZVJ1Da5{`p$(I(uQ>kg<2Mm1%HW7t^L^PPv3B>U zPp09BV5Xp~c)%%9U1!Uv* z1cfgRaa0A&w&=mOs+fa+MRq3ujV+*oVqHsJ=XqJrQg=vT2r)2K~2c+0Tq*~M_g!TaxOHb^JBlsNWJt7`8HV` zzhdEaQF@X}ooEfdH9J(VqoBo?SkOnnJUOCVm_7)(`yEbCVDa?GW^$}*xu7~$lwEe# zF$bu=43Da#qSIvI>C|-#ZQ_;DT3|eq%H-ttwI^L-_5+Da9_KPb@ppG`ZRkSkQVI0B z!WguaZMx=jOIYZ9%9`e^8aHN}heKwkx=ui;rXIHkSLw}?DQrJn7GkA^mGt)R9S$ay zuxUrGAB1o{@-g0dG6M}(TdZ^wh@dzn*;xe%*|xvmhia0{evQl;5V)tIF2K2cveghu zlmB+~PxL61m9@{*(BY9i;Qa8MgAdOR0&l1^EBn;GUtRPY;xJwm88$miznWSrnW)15 z=+em`@!7Ku?1=srqZV6HA0R4KVBIc$0&P=iwG0G(>QBM!4T{YWOgy&K=|s>D(Z3*MQNt0+Uk9jLYvmVb%I*=~0szU2M5nGr+8dnIcC-jfnYn zgLl+HSUAwgh1RT0W0gs#modl?L-DYw1$z`93d_Sq} z*fhL;xIM|O!9XGYxWj2xJDY1bww|WGgtklzDc130njM>r-y(D4jMZ^ZHc+qA)Bris zsMh!R!R<6!H6Oe_JMAxnvEt3#d?SQwD#?8i^V9B?W0#7^d9(bsWNR?3oluXfLHnyD z_DC8Oti35FpHjSc&ItEM8%l$}O}*VPYd@ZyPTJXkJtewCzJ7zLrso><*{T>VY_??s zINwCuZ#`;YX@xhA!R4|RY#zkNMccgozG_@D#oOIu1E>Z=f3ON@Qkr?I%BV>QOqg5~Pd3+S`Kzr)}fH*+#88L-stF;H78{q&VYgm`QQLIbFdTxz z!nLqI<-nafTNQxeSBG%9$hIG*o$@bmPu>ym7ESJ;mF^W&x_J5dO)Ae9>yP-U3rbAe zilk%AlhVXN>}8m?Q5Pq-neNTqVao&>Z|4FpWpSY14!038_jbWw1+#?Bp&MqI$-$+z zImeLIn&8rzq{M<{*735FDP`n@6Cj)rYmCKVM>nYHSJ=j_%K{t)36u^MDfl<-A~5v?7+ACWY2{_$BGiX(;>FBcWahl{J7BI z39I>f<-u&XvCaB!3so}HeMTqX(+@#)kH>pt(46?M6`{Ci*TtGf??|XyH#YYM7oC=^ zN+GMVnErV!2-l-q8c_$0do-oN91?6t5V?vws=j$N3{{WhPjqnb<3BW->}#PuQ`(t^ zGx*S7^yzHyp{}Waf##((@0hj7mAGZntU`oIW-cKUA9aezj~TG{%$;}Knd=lLiz+x( z5Fri6nSIOr!+yFnW$|Vi-d6geGOYm9j@a!rj$_`e+u7j4R;JAmYg62gC3h9jcBd=w z6GHFl+8#cEOZ(tvRyeoA)=%Vron;UJkb==8O3|<<-$Zv0RF}gViN+I!n=TCxJm{oy zIB5k9<+goyhJ${IQAIIxv)u2hNZek2VAP?1?}t=nTQ{kyQcp0ltH^}VLA2*hZ~mOp zgy~%6_=+`RtJbx2n~qfCXIEt8Wug9FW&%kS@l+A6^9}-9UaDkkw#MZvHAxS=@HT4K zE3R=eTG)1KR zef3ONtQv_zQV_m<8+_gz^!nsL?i3o8dhc#Je^6WO+c~$-JLT3rv297RObXPl+g`3v z;ULfCQ@hTp-#xh(nD2lm1uH?nO4d48=- zEDQExZN6u8DYH-f;4eHR05BZgg1D zJb@I?DcZa~Mmb{(si6*KK`ZIdkXid-8hwx># zJbHMe*|))Z-pp=o?wY-XC6ZlnAH7I%+(&nQbTjUJzu|^uy^MCMOebra@+C$x@1-mf^#4@^|7dRpYt6?UTodgj{yAO z)HVyV?YiY97){4WVXpBBNnnb z+iS=1Bj>wfooo(O!lyzPVB!mY&Vq5|s}H*uZ$}fCkbk^)@+wh|HG8PS7cVq@TdSy; z9LXX)qiPPRKtv0UV;6RVl;}m@zTbAn?u~OjaOW9W@!Lv6;OG$y$2X&CtS6%lO`8}Y75q@jkY-F$O=FsIZyGps9}NPHS(5#K)gz9K~hy` zLk9=8#w4eQK`ak6kt2D}neU2^1n&D|f+?4Nt<*-BT#cIJkdilbC^qblf%A?J<1Yl5 z_fJ9?hM8%EVqdA;%`Xj$3Z@JY&u!Z+*pEvr$l|m1`Wl3ilo2(rTY%{HjrK+v9CjJi z4vvtw1Y-By_Wy-52moOmIe#g#Wdxkws11q<-6{zd3ARc;jMWPnk8tC9*-!F9nuIw_ zfpn+|55LZ&2}Jlj z+OmuJTIRPe?6e<4E|;Y-8-{Yc8sCD*g)6NwS2I7guNMu|YSle z^@ksOisPT-2&Om3o2&X41R>kw!vwtwkLjEPi^*Jil1_Vt_QK0O`eJXX7)t=2%6+CqoeE`)<@YE@J9ZZrA<_-qcmZ!{W)MJUu? zao(b(#P|>2AJk>}NPw~ZK*2x4VkuFriBJ6`GGj_t^3puQdMi*5+ixhKVDXiSor_KB za>GlAYkD@l!Mg=UgE{xNtl`C0Lg6;OR=-Ia)K>2GkzalubQ6HENctDe$`(VTq>v$| z(u5D!T&i3^+uBk{9kj2UB-g0Rx|?Asfm=y|hLHk3`9-w!u0-bOYj*qdq#w55znc}u zO)qG(H_Dc2YK)gz5p3b*?y4hm-sMNaYR|OPiF9arY%s;u3HAD4%{y70btPE^G@+|a zUme_?4TYH~@!5hwOx3H0U!KQx!twi2_WO6^Mzjfj3K$B)2;@g^*OWnxP3D2fng^zK zA?BFI)dPU!@tL4rug|e7PGkOYr%aY$65taW_WU$c7oOVTbZsK;Ddect%R4C9nkqHi zE2#^C?;pE%7%nwCvnSgA%J}jRUM7tN-!Vi_xyG*iYMNuopV#@MJxz0o)Pi|_z(Vrz zpzbH8Ve2yOe4UkLtre)T9Suh zvY80f({G|Mc~PQ0+M+QZuSe|bY&JO--~O6&hU4;AbPKt%X^0TMYg_VoQ=G{XBwn*Z`d*48y0=x47EQlByrpZu2Eb`NFUgK!6LH25+PR z3w?d6V?J1@ua!hFH5!7>GMk;_USm7#pPYMn?`ga`TN*6^On~8`sKOTZROxTZ~h8fGPR31cgE*1TJ$|5)~OWAr0;x zNKx6G-Wk_x6d5^zS5#0TRjpNDLG3e9k3;;CCrl@S^890M1Ewt;Kh_druiPM4$g!{Bq#(CrwKP-;luUEL% z4Uw>YW@W7^#Z8~{(WE{N)%5!aTvbBjC2+WR2rYAawidasWcsPb%(Z3sqDG3+$A&Hs zx(xIXPeB^S#`B{uEThsHW|v@PysrE(AGe~!`->#r9)T;amRuX%Z>mxyl<{8=pRt=N zKhNX6f4SLw#l1!_v0mM^lomla*8Seo5o^lo`@v9vohnC!17+`N zcJ&}ifv36}u8R@xyhxTD0MGgz1K^Zxu6kgy@ou+qZLwOV8q;qg(te_KmgF$-3m!^w zLh>JX5PLUg)#|Q}x~kFmmgI}%Tg`X4xJD#Y&O>Qh@+RVo#MPZu2@FP9vD%o^{I6L@ zAQzWS%q)@`<0b(I8cu#voeW?la3sajgZ2C?{xU?Xw`y_U9RPSWsAl{rL&d94@b_?} z#Y=6IkLDCdXF12AzO_FOcHDRLdeyFqeN-OL>}f$4YQxOfd$ATrJQ7pQJ#-A8ggsX% zRiLcWf$Nv+Ohn@LTA^EIIEebDc=ezxL2W#Hckm7VbQz_%Fp-uf@$F;~(`orB>F7}a zfrotqXNN5S*bbuZHDi?EZ{C&#ih*^{4_v)m_p;1~GJ!NJVify{eCb4Bw{6>RI?|Lx zmrH^UKI(F}+En8;?3*YMTr#BhtG#GG<^XLP-(n=WDT}m4C!ErXI2&8o)%Or{a9nP` zVD>$-vb)7|YC29kKG9%1GN);-PP?Ap+>+_cb53OCG zw$rpD0d{RmvgmcTOo3h>dzu7_ceP>2J*x^Rz>Op?WO8Mw_D9u+}7%` zd3*JG;f~V>e!EtJA;*jKwZ$4{7|S6kzFtqk#0Z$*@Wz+qxHwEWBCdeX*!~XuzC|Vl zK_Qsx)pmEj@HWw8Lc=8pJX}&j_FB$rXgXj*Al6tBJ=%6mqc&MoTY@jgSaEOH6;jXY z&G<&4O(*s>ZRk#N0zH_-!Vt6}BL}aaz}2LGo7J6DNj#w|z;(;3IP-CRLf!3bZ%F433ihgCpl^FdN z7}z*dgh%mF;@9+~^YEq=Q}r@>RVQ6Vd^xhLg6taOOllz{hqF5JBcjeK#uu3QX;oR2~=NxN{XA5Vv4TXY%91Zd% z`!^XZu#D)5jMFZo`HAEBO-@dd20S9x;Z-_jw zQv9mkc2vI1l6ya*+1M|~2bt@8%9SzYgRt^RgX@GuhOFj*3|G;^ec8voIqRkm;h(4& zMSF`12Xbu>3eiC;qQI#OPklQ9@=McWLjlB0a>g^p*?OU<)}XghvDWOW&Y#TPP}^G9 z3G`}BD%HBY>eKIO;hdFih_I~C9k*z=4BEMbY{YG|5qs=lFoBL*9k1am80T1VCT~F7h zQsq=c-ApHFu#@l#tyP=NGv~+!^ke1OfA5nd+2|oR@vOA#Z6a$G2u|+@f(cA=dEySy z;(k&&QJ6wRTBrlqYQv$Y@)HO&nL)*5NZYmShxAsh7nTJ}ksO@McihQ|>& z-ZXWK9&rsGJvB5PWy>UStQA7uxluR)7FnUp_89dOmuE5Lo0Ce*a7WB~-5y)DS{~O- z(Q+TUT|gI%{N|Q;fvohLln*z1ICZJp!-q`{EPWy*a>gnmo6Ai%)SB`!AH*%@E#-(2 zVikM7v1m_p5g!i)UXIuDZHKXL3fs+*gJ7Bn+_ocqb;H=mTO-Yv?%sz}*8L#(*KF4X zY}LlEWAx3D_lybCpXri8Ik@~y{OvljRTiDe`33uy6uDY!(Fvsu#6-N_{8h23pi_v* zw>^Q@%Hf1FrAoQ3{j=8OZpN-zI9K@2S-d)tX>3{{$zE1_TZ`8zxi;PBp?y19xRg5M zPJC_AqVwHnWN=rn$|&ioeZPu>b^L}E5~fI0W4h#{T#lMAKf>bIdk*LT5!AJ)=K-9C zx@^S@5hKStd1*}@-8W0()hhxZT+a{;np#KBnD5HhPWqGP&WaQA1)`Iw%#|2*>v-qq z&McxCS?udsdW*5_D%uK?n?n14vzGdgQQSS1)Cq$BL$KK#|u7(j*(-;R$G; z11DEx*w%S!l6vB*7v>44`LCKiA{usgd1*{+ z?bDX0YWi_@&hhi0Q(5P(&KZUiXj|{*oG5E!wo}uV+iHe^5IXhsi$7k;Gp{~L!fWx? z%GM?%&BvFHm8~|xnIExI1c}glKZlKJit;C|=iDsu!Wmn zpKkC*DNdu@WZ|*_;arLQ9AgJ+SBUr;@x0bV(=RO&o5car{)_43TLRDeJBq|l6yQ=( zh}js;ON2PN)7=ebbP3%!%|=_NVs~U09Mx$t-3SgU6vrTj@agxok(USajUpa-lJh{u zs=L-=91yWd2X8H2xyy~^MBR%LpX83Tp-FKpSy0FukEHKuI20``+|=Go8nz_e4+KGr zyVpu_U5CiDymkMU!hVDf$F^H+U2d;t(t(?zmh2V=0#Ajg?3|#rlo~J>i{%D6QsA`q z(+EtK6L0>iTxCC)>AiRpN874OlDmD|T5&-iMebECzHF0l7+zG?*k*q)){swht|ZcP z1hI=>yP8>(>RN|Y>sAcen<^<{UH|zalp`Lp!_{!~5D?^Uh#GUQGF7NB&dG2N&R=NS z?+zq!CB8mUc}lZQe~*^$;vJSE4O10>6dAYYftWNhp7c3TUd-xNPgK=X8^p4dJMYGr zK!1OF7>$?b^4d=%7Tq?dLSA()mK%?EBG&IZF#pUdWYqN3sdvgm{OvVD`}wkFP6~jj38nmiF_?&#j40YF&x2N_;3z z&Wp3lt|WLELmZxQlN4B0caABTQac2I$ZCvOE_-iPXDyQ{j4t~Nrs)I*N$yF=N!L7$ z?_myRnhl?}Gj1&F)#U>$0qcrR{lz;O`sEce6ok8k+IfG1#a6eFQz}3tK7H_oG*JICOTMZC2|=9gao&n z)nHnF>I5z7$CPi^X6r~#_Ji1Ho>(;d%Ji)n-@>znvhKtYN_{?^cc-W#c?GgD9nbub zND#Efz_Eli#AZ5Z@UACBb4n1|f}701CXb8S2NLFDs+ue8AqApgzmFdPD9>-+T@7OJ z>)pXscjuWV0)f`s3Tp0FzodBo?m(5g)lh(YfS{fqGj)L<`|O$)$C4D8QbN>B6*(#y zwN1+2eCF+46Cora(!u>Ob}+`A-SnvC%7gGze&WpWiq@>{W?GU=)>xdfDv`)aIWah2 z`0IIYp~`YN!4Zqb%tnGy3XZu_3`VSAoJ9O_R?%g4GN06JM7i^2SJF|v@8IdjD3(OX zK+DZ8&e^^lE%YMO(2Yc5{ppEmOg`G{nken8;rFS%McZ?G{_!?zLG>Ce&iOcx-iSjs zsg`M;bR3_|4;NaKN3ve}8F^e@Tc7P$4a3IPdWSg*3`289$D**Co=#!YuM5_3H-`T! zIYC|!YVvfKiGoY4Fyu&ogNZT*r0PzJW+jyIE-^nqAXt9rL!@Avuc(h0lCU9ynk)hM z8F+kMlnC|)MxD;EUiO{P<7U8936TDLEJaW9UgS0?Ko;}3$#ZKpf^Eylob{Q7kj<( z33QQ&F@ng40i32P70-K8!;Y^qk{r>-zuQOA6pN7j?C+D%q{O}gQr8`>!=p6%zp0s9 zV$ZwEEqnPXI^$g&Y}HRXRd{@&oS+}w1me9gAlWywLLQT#H#PLb;PaPnG{1e|dlVuB> zII~Flgr5beqNzDq^nOFE`q8KrsZqy=;qX~3i$1W~MzFDqFNs>>~E zMyHOp-d{G!941$KaJQ|+Icl^`ap&YiDbAhjAphAg$~OVdu!(Vv0I3b>QSQKB} z)UEL=!67v*et4=Hk*$r%z^Acr!bNDs&gN{_^-0F1(+!dU!jfFEwQ7|7kI-W_X=DWO z07OO%`tBZ;jO_ZvXX%qn?}KM6*mNRirw{Yx*#Jd^-Rkd*we=x;J3aG4Li@?p`%(J| z>Duh$Z*C7+-oS28boooq0O!5fkS~Yf^0u_G=d}okadYUi?||fuuU`(47eT#y$7vat8vHNm| zzj3W=Z9YjXt*jic817|I>n+90d)=3&BryglVoKrR<@LIFOCs`^_`vz|{=c+hFLBiT zDDSW@I|O6vG(GD|0Tq-u&liys;PRk{<^FNM4rxi2>!T@48x{{F;x z0rbe^!jK=XAJzfF8qicqVWY0k)rW@g#fSER&4h(h>XSyW- z*rbtP5UVOvS--NHt>z88{>kZ>1xe??;H^v$E5d8r+1iSSVoyrcn2Ix3JuVyMrSC0?omog4#ix%0keOO8Pg)k46O?7B?9@x;tYzel!pzi+@dsN)hc) zRQpQ!Z+1_o@jp~`FY!0Z7t!F{q3`ui75c|fFahZJ(Td4PPoUo?lT8Z1NX|l7Up$?G z|4c?QIF&l6F;@TdZD_-qW2&tD}T_?;HSp*QqL zj3@UP16b*xl22Iwa(4cCGyPP6&%TLe_wwlp{l5|^{zer#d$s?$`kxAX zs?r223t?=0vQD!Tcw#Z_O{Yr@PESvZBYco06IZ^z)`~<0~5ziUuhQDZ8S zOZkbv8;%o~HW;vfGs5}PW1zg%Kz|osc)EuE^&exzGYcmVbX+-%v+GE%bf^4;0Hxsj z1zLj>am<24YfK{Mgr1kjqd?$_=Rh23IR3wD>lsuL@D}Ly>XL{!hW}y0MZ|fh!tccU6lFQM`Vq8SapAZVHxW#c zuHLuL)rLp?wQ`Q|d!`)h@c&pLuXX6cPQO z5v8u$4jSBBPqurq{~SnISsOZ+NvKi2e8-j|#2fav52@(#M0uuc0sZTtl=(dQ-G3n? zeP137bo;(XN;g4a1~O>Ea#i^C^_a)mh%h=uN@&RzLA0N@O@f|x5b!^5RY>?B0)7!` zx9x9Z%tPg6&w(>WC%CUr0pqp*=I3n^=TtKMp9lExgf6IpUsTy-ny2uS1W^`dkL#|5 ziUa*Q6M*V2Nic|SV-R|~E@w#hO3XGN?wtz4vg|g9(zS+x`ukP@zdoiWxKypKbk;U_ zaM1B!KA`~MVgogNhvyoq+}}$WV$!H9myRpOZ1oG`SQxXJPcQ9P>w(VNk-2jZ?8cp} zvtA|Pa9SZCB2t&FE_c@KGt}}2T;?hieKQ=|XD!t#lvXe?iI!ldOPbMpyg$;q)zC`b z%`n)l;~meAXHSn*|_zItHU5`eBYMZ}3*i z)c_FlGre54A~;*?5ZN5i+(Kt3RcZf1Ny9{~wwaW{vZTA@c6N|%7EQXB05C1R4?a`k zn2$^pR}HZl0tC7Sc|glFe%0-zeRMroV}*$uHk zO`7mQpyOST#tf!y(Qss_7aa17~w`dP#WW<4v(4 zlo3FlGGDInX$oTXyx&Nr&1oi9*pDiwH#wF1k+G*T`YSTv$Z4Kskz)XId6V>mtF;nv z6=t@UNi5ISObl^6ht`S`9! zR4jGNHg(|J6em4@(>Z(h-=tRY6d)Hvid!OZ7WBHY>o=$iWKAr@yBo|J&s(Z7Y$tjd z_C}Fx0w4w5?_$jTA94Q$8om3S`_b#~H1z!T$m}=I%?ol{s5*4{I$sc!26eN`-=h=PiU6qO=fsnTso z2k9LIq?br1KtMo1R6u$s2m;bOks2w2ln{DoNkB^I0TKw10C#h~d*0XcedqqW|Mrux z*Is*PvDchqjxpxBdW&Hl7Te;|x(AHJ_SS1YbH8b%4#Wb}OJTz4wG$(KX_8Zbonx`K5>d1@7w?{ngndwhqBp5S-q6-bm%^$pe<_{_~^FAr8 zmzhbQC(Du7JWwQnk4WXRrN4+sx5FIIOOQig%G?FgQ;a$)M-D-E+{P9h$Cj@&d^nBi35W|F#9Tdc+ zws&W#8sFky??wH|2QArmLPJ<=r<1$9>tvH`)^HPiD%{0~d}-5rJ~krVB43@5-XFgf zg~AGd{2gF1T3Fev*xX%x-z*6LMb~O^MRu-DZa!663Yd8w2HV-G+}`l0TQAbBvLFCG zqh>r%Otkikx#dTkB_js;AH0B`r+}vO(#U*B&;}TSxSnib<&AMrtlpj6alYBQ6a1|@ zY^UP$_}qG#wChf>YhmQ>T#Ve!Vet*})?$VSxuYhp%580nJ6+JsTb!ml?r?AJxyQyn z#5z!H!+&PqU*#xm1eIkU(mY%&E+lO!z!Oi z=f=gzAA8oTG%2<+$@+J_Yk7xV#gJLAp~wycwP(;Ip=pWXRr;NZKKftPthdek22+93 z(>T0a9hm?ST9l=0of=&}y}yHOV=c&ZZde~0T{@Co_{z}d&YX2k9DI-W_Ji26sF%S|2%ek=)5X>XH5xJiyeQ&fU`rl{0 zJNZYL-t+k6DGzwQr$?Df&fF52=}}cj31((~^Z0R!oND6QEc;7YJMGIV%A(Pbbd+rR zdRyOb=6+DL8vH3)Ts^I&mX)RF*_Q_?`K#ri$#IL-M8<_335@$;jQml`I1Ih4U6iYhr@ATKDn%ssySht0JMu06u1<1*}5V+h>?Ce5?lf++AeR_dE0_bZ9}m*6@5)c)>1R8Pe7iqC)AsR0 z+=qi=DM zYxwH05|5tX68A!)@wqsq7}n-KTk(Kz#yf^|B~H#mq;K7-LK)Zgla-Dt?2k9S$DiTy zj+^N*dPO^_BGzHtECB<-vllOB*!?&$dWl|*A*ia$NMHj*hQ~j=@W36p@QqNMTbN1B zShL^SIWNfGE*}FCFqE)IC%=ea-%W#9{(wy`K%0m8_-aK6o?=w}f%`hfb9n4U)?Zay z;_}Keg0l}v7$?o-8Y358$#wPXrNri!srGtf)agyWH#&K2So^8zH=xdD=G2Pgj!t>C zfS$o%5wGchR5+feA~tV9zidx&FnGqr)Hs6HrE1kl)?L=E|MmjdXuQekf&99RiRZBx zae-kI$8-b?H$i=}D<0?fO1o4#=h0$OOj?KGF{?|P1a6O^F%(~CUE8#E;nz65JDn1fd0)XaWCm_XT0W=;6~jC*FJqNozp zl?4OeYATUObP92ugB-(}q9zk~OS)Cd&4yAHBH-N=%CJNhe)Yqqbr)a)IC}^+Uv;jI zGdex&d?CJxoFI?GK?^!EoB{e;BQD|=w?>+Cd!=0D1RMJE5BJIC<`V8{Dchm1&=9nW zX8^#y`A&sy(aH(wc|#tWYB5Vh=C}l6(LU%!1GKi4!d)aY=NW@-+f*vr<4az&oRlpq z&z#SLtL1F36X0C2Xm`RuiWytbwvk$hJ)BSv6a=#*cQWq_3>t-?06Ou852K03p-q~R zCBTgdC=+p6m0X14J|^>v+fBSQOx-952?=vO{QT^)s0yYj0Gz=*z4M=P74Kib2 zq#Sjzy@-cX&jnT3#HObJVj?jmj9=?nT$)j}ok_6MSGJ+sUh}gLXW8i`_GUwC` zIHOvc`SP+#K9O9}jc51yMZfjS2J9IK!eietEF8yXIx9dO>Mm7pCjoNg-f8bHvnLlO zc(|dj!YYJJ!+66qz`G4&6?QSq_geweJjpiQ>f?p^#gt@oLrx6O`Jv6k9F<^*Ce6a? zRC!Q{)`zrq>ZEvYwF;e_D4D_pZaW|aGOY)9{T>L-goSew%!w-krpnaOTxFVz{kjsib#t#m z4SbrnWXQyeY?@SRSgCRiFwpytk~RkbDsx`_P<>3o9$yG_aK$)>rm!AQTG+HpzO1W; zze5$9pmwxuzFobi*dW|`l>G)vlHdC!!ENeD?_DJz6i|T}y*KzICuF-=>C)b2yQZ`2 zhpT0iqhX9$xV8_vG|l?!#^QGBCb=^A*Qa1&Cy5c|Rd0HM)#|uKOtZRrYi<`QN^q(U z&6TqBzMT_b9|1YiV#BiWeC*v;MXUHGo82iN{LLrarkD4kB(UN|f^#l?Dfm7>Da(36 zs71C(X60LZD1tjHVDd=iNU5SU;Du_^wX|G=-3h?3E#!F(zKM{v?0gmqg#6wZ1IR&! zQ(5i)d%qniG>cGq_?KrO!G}K4@~MHf$zJP|6B6|coQxLs(bBWma`8!R)BVx~utH1j z&B96i?xCXWy_GS69{AUX^O@Ic0cvSihJ$Pl2mPZ&P zcQyU%MO!@-NoqO`OGTN==Mg9BNp@^Xhd21NABbJg_oE*LkuHIxPCZH}H33=mFQa?) zbBipYQ1t*0waYcxm6!NvZ(WPDlL9?zD)QU8tBHJL!W53X@^91&uq_iyc)TLgDR%8; z6AaQ*s8B|jgpoJU0LEi}+jID}a^BnK!l7Y6hPW>7zbiF$KcZVi6J)FFO;Tp&^*BC5 zw_m25%|0$FsC>aB9u;cWvo4DqZxn7W9AfDN+=%~ zkfW)0+Lusj+gn=q=F3$YJ@8Vif9Q%eFAG#fBQ53BdS@Vcjm5=1L?6WLc<<@}Zi8ox z=Sh2qvI0ZrrYrt>wz%8JG@0y#_s09Oe!FW|o49wFg^64p8TTvrU1DzTm&Tqq8P^r- z#|}FlgL|&!lI5MZCs*rKQP~dL^U%KX;ezv1#<7a&FcVjS4RrPEtvL3HhK{USR2i-@ z{ltL*-=%q>PPH*-mG)v~p5#$Z3*+~VZLSY?82^{ZC_q^RXg_%i1BVgq8I0P*N8o&L z{I4}=WsCZ(E`4ZRYSZa!pTr-tg@BPr~Fs(zpNdk>XNcr*Via z)Gbp1Ox|f?Cj$uL;xQ`R>G$lqtds-9jC6)L=zD_4cR4Pio z>QPeuGJd=DOSEM$S1c;x9rr^=KxE)=Q6!uzzTl^InKqSPUdX75Lv*`nbj!PH0*w33 znYIx8JE%07)GKL6GWL3DkHE2OTj?%5-qv&Tq)mHYG?}1gepxtDn>5j+oF@i;;<@zQ ztg?MX&VE2|v9c>mR0~w9Uixbuu9_AQxIc<|*cG((b2G)oMYJN)tl8l%c&b$50AZ!7 zcd-~0CI@PFt#1vmYp-Z>sTP)xjMFc6XG)Shy|sbl1A=Ezq>8Dk>265$(=+8aUlJiZ zU17-$Y|)YjzuxFn9Ie9?z*X0(3J2stJ$ZzI_LvhbG&)_Vh3Ia2O2OO$MA`SAo>Osb zsz8D_m_92FIHW>B^RlqfBonGJ!@;ZgfnK${J{{ZB_Dgnhng_kz#fO<2% z@mUZoOLEr2UG)|SDeI$o^XUjat~cZj2j@2J#Ycl~jra!DnnK+Wz)4wQ)KFBZB~vtU zRNSFMNsAj6^obsXjPtSTLu8MxL%(qhjYn!Pu3WMsDk>qN{tWnV8nfQ zt6TS&={1|ObIkz0VeQ3>Q+ZCw*#*zDD(rMCa^EFZyVyrSf9;o*x9o=RT$w~VTPnyT z#^@UwjEmRaxufDN(74-hXTz_JJXcD-%`;h$!DF5fiIOlkX*%K+i?K<53?wa~6s_$? zvEOcpQUB;-^YI*@jEEr5u5Rh;)~*25+)pq*2NT||rIr&MH$GZtGShrOony&f2KwCy z>?lXsv`!vYyQ@9!XdILFf|j{~i&{LMOWk{wUK#2qwKM;F_MxhA@`H7SnI!^W7mbs! z`%=R5*u%e*X~60SFmve0jmxjo$gGnny2%kw4!o;#VdTdtg}YHj)Q5J2Ov-E7H%$)o zFxR2(FxhPa# zWB!u1O+dxLJH1!gviDmx*I@i| zMHVaLq>5Hm3!|CU*-SmKNZX;d5t{=6?CS&+2GTPU6J8pPW>3~Q%v~NX$5^jZ>A>HS zsfPCVna?X59*zg50{;-Dj@k>V;+jXxcBp*${e6Ko>|WBZ&|k+i<+&}D0c5iPBg(0` z8dfL1Z6!b`QAE7YRI4IeU`7A#U}t@ zXwY!dX{ZVe&7$6|j02z6in$4PTem;^Bj4oPGLJtBn5A0sJMtX{&l_=?q;XwE#USYa!LME+*Z~qjFw)3U-@w#6 z(qXb@$-wn6_n3_DVwBcFq$zCd0u3){cK0nlC35I=hsLMMn2GYdH%8ZPhj3A=0$$>D zb%!4Uzo1^10%XTEMw3nx_|YnAH~5U8L;=(-DHZqdo5xeY_< z(ri0C0oRFJzCf3g@kH+SQ&#n(?zY?Ir!Js}+lEEHHPpw(qRZMTl z(p!wMO;2s8TS@5=QB-eB;|<{fg~xIG>j=iipO961s+R!!5pPRZE9`OH$38%H$lbR( z*EQgt>}qBjXLOhogfko(y_YdHu`w1SFa?*YdlyjZ7i$b3UAFn&NH~B z=h`sSRDDM4d1Sht7a#x9yPqkqX091<==QWlrXE-7<)~QC%Dj{kMyNMk3G{7)J*< zc)z|u#S{R#roSMt?f9LXMW(pIOdD#Hlw$qiT!8LrZEbQ?LhHVE-(P$ZWzBw%9~ixd zS-2qO$*-r)W@TjDq~G0Q^IzlfSh#*@_OXp=Ucr4o(ct<;n>cn4qvOCQr{`uZ0opyU0070=s<#JQN{ z3egEaVf(85?%8ao^Tx=$@z;ek7wbp4PA4&ja2b$U-h5-0?+Slz>ZrghV534)+@pU2 z7ih^bHET%kaBzEnzpQ+8iR~zHd6eLpTOp-K*$S~}dZw!)Wh!jWu)yMdzsQvVs!q5BIm^?T0N825-7sdgP23sg(*BujpX}s5WvI1#9T&5@wRU`{I z$GLHRtW|cE?(_H^&D-dURd!imjAzZAa22VN2io|vb7a*AEHd-w2mta*=7I%mkgM~Q;KZsXO|Y>BIst+=o9Xd^F@Q(SBi*(!>zFPYEgvlTZGE@jIi+voHC|4H zrF$giu+VNNB~}ebRoiXB`h~?W8dtPkqaxTEke{lQwGu79eNm5V07RVU?oJm#Ay?lk z(15pcIy;o(&Bo*6Op32#tw;Y=hKd`jg5mobn3BaBjS>6v$mutYVHeT5|c&z@rIMd1Ah=Szilz!zNm8Qp!3#}_088}U%3 zZYxmd%c=<2U6XuKzHR74cHR=dr*Xsz7h+MBwV+SU65AIL_r_?qAeqaLk>xi`cwt5o zt2^`S@tX1^pq_@ymk4`q^+%v}<-S00$FZNlx{{M&(4n#HOwai3Ytr76t%*&E1KX9E zYO;>Knq7qNvB_Px`HY>L7m_-4tEnHZmk%;D3voq8&lvG-mVNVHer#={>FW1!$bJ*ufC}amp-ju$);&l&eqe zbWC8YMOV_0ei?h1Ql#YwM}_J1@rRTFsvRxXtbZlypl33#RoaT0SS;fo%=Dg#n5r#n zlK-Dt3*s+sDIRDHa+zU+d}2~kVd?Xo3w+PF@~Ne^#Kg34i*{;9x&$U*D$Lv=$0zb| z^mv5Tu2bERnbjiFq}sA2pz(XqfzjG?;ZcG-dHUjpAtZtUd}Z&7q`YnJ3)(YJxSKR* zoiQWa&NQQ~DqQTRW-6Z10R{)(p%EiFpdyk2C@bnZ3}uGtMDgQOk?~ee|3mB0(}K%F#a`YkZQ%@q+HC7 zHl`X_(H+z|lR|VqzZIAQW`~Dg#Hp@5;eOjn^9NU{=LDvIQCnm^*BNDYAubRx`dm5E z3N~$Z5qJGg>(lt4L+eA}-rP?kPp6mLq|#Pv8-6lRd#sj41T>xmUEKAYbwKc)pH3U} za{NQNRqj@zoucK7?Kkh!;?9vfT4y0U>m1(zQcKygh;*uuruJ+3GOnFubGaY412#`B zRy?~benJ+((^O_Fi^8vA0?0 ztri2A5s}ZdG*5+@f_1d#-&{zaOg5@}X5gp%%jp}TU%FwV$UW&p#JlpGU3|#+^wYu5 z*MevR_s6F24RMn|9|%hdiDCNr7=G9;=M8_V%!{V(MkSQc)mKRfW@794!Z7Onx#9zD zaCzDUUPp&K`D1a`(ednc2>hDxQoB#bV^(RQL%bdt9W=>b0i6O+vj<%){+{f0_vwcJ z;%j5IgEE|C_n!<<0L1-@=EjZjfiAZV!zjj!^hDody-!&;sW+n@FkVei<}P z7g>@{3}ScQ)UA-kE|`|@VA}60WU1x6)>Y-ME|JJadQH7i4ZLz9G~w7mbt=C}&ivag zSwCkLF#LDsJ)`vP^N~8^ww+snl-VveGyxOQz|%DV&~(i9mVD+qf4(1}PtugBypK@a51~h%$@_Xy=lhsbdGl<;PUE*22D!E_H7Kjeu6UCWP?*m( z57@Hd4p6EXdS31qwUXZe!P83MJQuw z#a$%F!uD0ZOrZdbE1IP8Vb&u(+qnE-2PICwI1k>&2Ay>)b~SVTS@1evnRq9HC9y=c zki;Vq!v*6^-A;L~{^d1|e{4iJ$!~u|qav3}^Ia>-%w?=9#5nl+3dhZZp`l)b65iI^ zvVxf16AwM>Xz6Zh+Lpd1Joi;aXfprpmRw~rU?%Cd@55o9M9kcpOY~t{&DE|OtlA1# zw&v4cA8R&gyO{8Jv%e9a8o>sh?n@JsULqkR?v-|7l#<847eH?8Upw5!UjnX?gBWw#0h3Ls&)D`V0!9U zEYQbOP)4Ib8*>$822M(77e zJp8_cM_((Sgy5s&jK=}~M`6jI`tMv-J3hW57WT`b&)HCFBiPxL8~5*uI6y&GiaL?} zX!}nstm-vtxJbNhy2NTE`DEy;F4*`QCcB9`6DTH?G`h}NncwHk+&{mnH7j5o>5!HA z_!1jy`Xv+zv8avLGZ&4NanP>60bYIn?25Le21N9WK)1)&ua%;b1U*lcm2||R)izM~ zNnTE9Y4|MT&arl1QKjh(U!?)3xZdH1$u71oF4w4y7+5Lt9`E8_pyiz|*uIU75HB30 zZZ3B)&LBwjt!!r`mS@C1O+Dw3kWeTn`TeOMai6Pda7?ufWrS-ea__0louAsK55S}8 z=vjWtSUc**l%{aUq*KeQ)m&eGA&r*=p9%jd5qV8kL%tWht(2gZC>dGOgJ#%B-u%kv z^9d&D`#ZHox&f)TLI&hr!X7%`#`2vuAiMjnk1QTOz>Lp|M_T#gJ+couv(pHFsqAJ# zeun4gSz(@Og%mt>w%N+^acp$`MO%1D`9IX3*Y3R(C^ygL-O0_Qr$tqmv!&Kd?xNPr z#S4ph4-z;W?L+R-T?o@%n4j-RxB?@bm)?qO*5;(zjlZ){WYfbqxC`+3bE$^5 zoRzw6GC|@mT@K~|c&=Q*?Sg+NVlSzwb)P&bsGtwLWGV~@Y#dIjCMW%iR9X@sN3vC6qzfu1?AZBOz zpUyT5@raRcTJ7_rh1Tv)W6#HwyI|oD*Z>|8eWi(jHyoe_`BTI%d&~OtTCV?LTqVBuSTubn^koL`Rsme8kri&X!0M$N#ChI-=%|0uTnefYTZMACBmA@?7n{d2f{ zqEa%?`t;vbN++Fe=H5%5`foE*5&~vK+6k(#y>Bnw~zf!R7%OX z?aIjfTa_3Pih?dRp* zJ@v^~rNES@{fwFa&x1+4cwwo;-3s)- zXM82a1ekLDPR;*MKTO4#)T+xSs+eN75e%wWOmh+s+G}Ua52)HFz+8c{_TgfFx@%Td z0I{`s!>io38X@lDTECFAFc#b7R9dTFeds+U=2TMug3yRPbR{lWv*BB&$`EbqH$)|- z-&lJ9!M{d#_3;r|tWm}nx7f)Haz54syQiIZDye)Sa=-*&fH2#Lbr?txPGKBwa@;Ws zz|)G`?*^^4AkO$qR~mV4{VZM!mHBgJt#FKNEDI|V|q7QnE9 zAQ#e2dT_T~v- z_ekd`-i(K&7XyAnJw9@)CRMMyKds&(%>%QXUaOlDM2s3(3{#FsaJJ+HSF<|6_+KIh z4T9RnS7jO;tr+yW^qTvx58kGHKa)O{JdFtqUl9JpZ)lh4m3Dre_+xk4cTQa*N=Eu< zHd=aZV6A32dR-EqWRjo7&;@TBs;B=|3AOgD!?xA?!tZ40cm%lC48G_+-0lB~Yb-{^ zVh_m}pLkoKS0KW8;RqptG|fuwU7xZC^db>*o}|Sdz96v$86&K9ap?wjt+J~F4`E(NZhF7J+2lS?(xOv-bLknGg7l2XPSTSk|(#vIxge#+dkw z=per~5DdL^q~(I3g8glS=!bOfBAgL-|ySgOjLpe$=T^+ zrhJ+GJx46mxA>=BEz{SdKnDfd-G(hszgzMsvA)cR16YPli@0Pn3o?(EfU4b8|6qYD~; zmQIl;bIYfCMO|d%w|C_YJD7_m_qc=Eb_XIvk-nY7s(F-^#b;~>_8y2@R2_JmrTd}5 zuw?}6w6pfsk5C05q_w@r!!p z0Y=rX`{n`j_t=~S_b2kyd2a$H`iAi|XsOi_SvM0opKWjXAhT|%)w1CLygwlCaW#nU zW^9=OBT|3P5iIt!nIA(C#TJ9krqT5xEytk;akhB(z5r4q)~RJLPe@a+@i>X(l(joj zAW9NCl`9lAAr#MKu-$*^yi6UH`DI5EDCB1@5A@Em#nBEn9ZOk+0eItgs?T(Cdv1t* zz|v%{xPS63xr!@1D^LaKJ-wTOy2rvLCG<4pW0(z1VY=%zoyCZn_m`_;Z0WV zs7w19X@C8?m_^F4Jvvk8Do36WQj^3C{~#Cy?T7DrP)ag{;vdB}*_)*ZW-Jle zd)8Be9~UjrG>e=BNab={(g`yvLqe*X>^8}3>16Ej(Zcs5msLGz&@owl#MF0C!3DDc zokxQCjtPw|8-BeTI8y*_vR%h(yGl%X4tIN?mPi7vT*d{Oy`&6POGkdMb<+0g)ad zyLJcd98V%hL;u<@EXWdfsRs#r)W;Jx;-SP2Z|QzMsLgbJWjY*rNOo;duAV#N<6IqB zkbx(k`=GA?{)XJ`d3LfLwqG^WpS#sBUOJNGT#Yz0IkuT-tPI{dmpAZ0FgyO~&sasd zQr#;OncFu|W){Z5Do<<(0^%T6!jhtRLE{3NrDsODBTxXA`XTx1lq=kuP+N_Uy)x0&iX>nV;6FeeY~ zsPY-nj`Y=)9Z-VvLX7!-@H}qWQxLMh!9QLniOaAFj!K48@(>D)<|8-CT$^UYZQJSJ zrSRlc4bm=s9fFVQn;?jBb%_rJqUMIWFHW@>Ll@===4~nFd6K)&~CLpH|rwi90zvH2-2=Rg# zlJDNLbQaZB+=qPKtcFvWO>)@a3}*AaHk<@h=>beP$?2uF=i%~IABY1>%f`WKkE8?6 z{kVZAj404kf4A$EjQI2>2EkL1F{xivl||*&u&fp1_nLYmuoT=%fKFxX&#_6M1ZZD= z<%HxRTt1rdT8u7!G`j9{e?IA0pAl=S8S=AvIGY?3pl7MMW+&|UG?DT(GSkSe?1 z-76_7YR0H87HK%&lb^1fLG=rQ%4Izg*MA{u4UKI>F$cwa|>?K&{h!j7fx9AGps8{EwFy5%@hMKP?+IJICWx z6_24Y6OinjtMZQ-^Hr>qO4b*sj>LD;ImDz>`LH9|!3PZTV> z$01u|8@zrFv*rQ{!nsF1rItCG=f(kX!~DIp!(DWvB;cizrYdx}Ki@liML$&1?r5*1 zdtq)P!*>YPBN;@t&2{gST~^k#mpiD`6kRT)3=IACP-n87$a~vhgBhZJtJZPi70k@X z1#XZF&iBt?ZBV@JX1^aL?^AV(1Kdd70$#b`c;o{?Gn3OJxN8Mzi$yZJC|uG>Jg6@p z>~H!QSJf-%BuAW$(P-q(^5`2}_ecit=T8DMwSS2;Le7Pnkw_k`DdHr99Zx*uON9Y@Fu~FB*=@vr{`Q1?O$I3_K$A+6FW> z?@m@j0M z>uF7ljR|ZzWR)dJB3)yO=@P6Tocf@yx+#%3ulpJQ9WwEz8i)!$ahZ{Z&u}&C(cdrP zk$vmv=Uu7Z^B~EYz+z)R1=EmjmV+cu=Pw*g4|%wV$~F_}Cv&JS$9ZERDDRXPyqj~{ zr^lDwLV#pa`8a>eeB6Sc9M{{engY4{^}NkhEXB5`XxRGU za;!~?wZvxPoG_UKS0g>_Vbha-Y3)h4vrLZe%|@OlVdNxa`UiKvk>=HLk|5*F-YfM) zXNci)ElOSTc)dpFNWOxFCJx&)c&8ansfRvZl*Vjr4D}Kw*71sdk1#Kj^4hWvclv!; zrpoTg-rq&z9_G;pnR^_-xLZPnz*`rm@EuE15dj(qoFA$YJ9T6(X!t#wcuD%Z0NdB| z%6{vk3G6Slc{hY0%O6*NGl8&hqR-lBxt~J15H5joWGfFkNdu70Y?Mt!L~c(Dx|(Y1 z;OnZ&XRc>gKs>E`YrUeora|pdE-%Go`GN`h@JhUIe^>FE9=*F9Bv+TNUPqXgRaq(TtxA- z;uEghsqi>Ot1>1$Hjv2HA(S|Szm;_foa9|4fv0;_n2WJ>G3eivfr9j7PoDNz;W~K% zd&UHnwhv$X*s4j^tfMXS3EKyQA2tm%9~HU;Yix3~$IBh2BBKPZmHzVgCgeAIhI{9^ z$KQESok#p@98gbkRp%uJnf7d!xjyCwTcsd9eD`njTwx(C%yBnbBK5QJEnR@XTw))7 zm*;Hv;cohczCL0DF>7g~oobeTpdQG@^7)Zc!bHAPnaeLGAcdFgx^GJ*C(U&7U}b9S zN#{te=9?k7q{lz>5bHkE7;m(zzoh^=yQxdx#Knkr&7kIb%7!<_xM7HUbOT?g*3wY( zU4ZBMRuH8iXx-L@FPG5i*<9ksX?Ybl=U^a|4iMlf-{CFHVYPLy%Ume3C)yc0Z zl)P5$p<=TyaW6PJ)m#GYv6}S7sy4!0LNomHj=IHBkHOR(orvT+j!d@RLnsYbixU!n zSVSVLH8nBM2MOsNXrh|NnDKVQd9mP$2}EW#M}ooi_((T6(Cy` zTsp&3j*xj7b3eFOuC;?A*Ia(-7_3aanScJtVu*?M>8txLl+p4s#|?wP^u@#(43Mm1 zFIy-JeeUyew_$oJU4~j1Ko(NVwU7?koU=&NcFAu$cH^5TZU`CZvn4p}1h;u$c(P9x z@MY4d8*{8yWcKC8zS7Wc@RI+2?IpJkPlc<=ww;V8P}txhM14Iga(3#{&%FZ)4JO2p z{uMSJiF_tO|8LaAaFD9ZRTk!m#9Ebo|(LC zO1!X4J{pq;%GhXhn84=~Zz+AW@@YvWo_{>$nU5lbX%hN;R{qE zx6im+MBVlt==jJY{%jt9&ki_<2hP2a{fFjF39j;HmEL3~l{}J6IBg^EPI>-H_>iDqh;#B<` zVK#;E9~_y6;c8wwyp`0ZUqdpoR0{X2bZ$u@?`|gHsb7{2 zyu^9M#4TePqP={G9{R#e$B+AfOxV{OI%ruP>M`Z|q+wGUK#bG{*%>;(+%r^6B}TtM zBoc0HUy=ZJ*}q;y6pi3I(Oe)u#DZZxAh%U{VD)kF)KnkHgdifMk{Mr|C0!Lwgikoqdj_O-?`+40!jk@g9BC?+UR14Ko5M&+HbLE?bM!%CjA^$vLE{RpzDCykC z@=VH3_hSdS_FnVtHru&?q@m)Ol-%QQK;DQow~$+aZC%XRSC3E6n~I5{&&WbaZ~471F?BZ4Y=X4LC~LAE zV8DPzrrgm*dq7UNQoCB1axG%(h(DAEzN8PmiuLr`FU#=3oQ>BkHCXHb`!X4)g{PL> z!xk4h{O+w8n{-lVIwvlMB*s*=xW;5=K)2DoRf7vgy&tHS2+hmqoEuCkgZ9mCtMizQ zCUm|7wvfwWHjP8%M^hMqP!|ioO@3g@W>NX>yT$3Ud%(2fVy0-GZZ2!H__M)&yKYyl zFQi!Iv%9Gy&ha)lr=KO^MHQ8$V-Nlb*SnTHBK<7^ZX2lW)C*X7i#W_fk9DPN7;*x% z8p={7jfNYip^{#-^_6KdJMAu{K606?r8tP5X^9Zv7S28}EEHSD7a*=+#grq$4Ze_(V$m9$jzX3TSM zHln69W5-Q8*gn;t3lHtF8Y)nc*e~(%yg4D3=j25rj&8G{IZNH=sRNsdTL4nO`$1g= zHA}WjN)2dKP3t+5V^>wVl2agLT@A*w7R9%jH?$24A{dA?*FXfJWEPtX>eAON9qv3N zyz`8S@&pHIEqBKzfaMy3(~T=k%WDRrRF~mi2m6aMj34K*!SJH za)j3wyiNV$tDL&@sGa+$nQEIpWq(;SXi{I!XWX)J*AP+pnUbDx7&rT9IZqf=4R-m9 zqnu4vu-aL#KuUAe)9l#J|CmTDz8;B94)InO;(xX+%zr0-6JuKD4GeHzB02e$0dK8K zSn;rl0K;9JblR+cVSuJOgTL)WT7jJOaIR^pEh0}VcJRldT6y|%{iTPc&&u4JKt`wO zC4+z#!`TocpQrQQtts-$oZ7e--EZKR)KxzhXe^~!TO(!JF#SK{lkxRk?FAXDE4+-! zDyGJ;#^tt)LXKyiqisx*!6o$9dOMoLzCm#wXImMYm-aaydzi5Hr)BN*-J8O@`K3@w zE{(4DcO^tl$nS1x)&@s!RJ4_d%0|oWEF(4a+p2_y82AYH7JTy3ZzO+Mi0FOLxZ!gL zn_7^JEkt`y+0?%!lHkXo-f?TjZkSw=fP0A@RGW>7aH8Md8z%a_s^pe$W~jqnknZWA z9o`Qn3G906jAov0%~Kd#^LS9gxli**H+dbEO<`GZ+>ps#f-C16RDK?tWN@R}cIFRP zIcsg!QVHa><6 z(fL$RZzJP3ETjM$E@Z%>$Yk=UO6QW)hF-%Iu86HVZ&JsmE&wcdsw{0N^Z#k@JHwJ- z+rJyuou<{3EpxO~ZWr#o+oDL}O2t)@skv98NLgu9OHsrDR^rH2Zg6GG1ou`PnF69B zr6{5(FFpU`f4ukee0;yY`N_kB0}wB-^ZbqTcQ)rQE~(C&IW5nG6*ygxX!nke_aOS& zK@n%+9z#z&aFowwqSqQXOxY?)jU6(Y!@Pr9T;nOC6CcJf`0Okh&Oi$}MUcd=lNknQD*ehPaJ>~RNG}#|Y)k0mOXOMqB6*r&HI+#6cd&CUU`TT|=yR;>#=kcrg z4f(p@-l2;-Jy%8?LX1Q5+Z}31E!hor2%DR?=yhmzEW)OL;yCf3S6P!b5I&LYBe%k# z?>xc(Hq$pvuPTBpIv{Q;uHhy#^H{Z$WoFedjRLcm?%~+-eB4tyW-{N1uh?u{ee_4A zbx^iClBdGrUs$PqRUWlNLUg7dJ^2ilQz~6Z4j!09--RLMXU4LYz2iOlaxTq(XkzUA z-z)%9sBu-8-;S*Dsg{vs(IxK;m*e3n(5-JK`nq3qoJf>`$6DK$F49l|v28Cp`8SiT zvjRvX-Unhs49fyl82FH))oo0(+M7&prIylmrm$|oQ!|&S4t8@qo%Q!N(nu1t7fl$?sR=hEq(&Y0*e75j)5*{NH+Z!PGIC zI>hV^XvjX zzy#rT2~SN0sc`gd4I{Mt=@M<;sYM$67~iW4`RDdWkD;GL;jH22n7GCK-iQJYl6YODo;{#?QWUZ+3^1y7sTc?Z9B8 z{#JU(wbz&r&V=>qj*o^#FD0TaJY9Z7jd^WEZY9~wVsFs?1%Ex7SJ{QDKXr#CW{f)M z9Xqj{gcUy!j>`&X?EA z1##9fS>_Ro4@lpq@oV8>-dK6V)~~PNNso%|l|DZCvFEGhTY<`7w3~*s$~LQ?``UR6)4>6>%X(4)o(Lq}@Q{j4xK{Qh`% zTkw;->=R+|+AmMleG_^4Jtq$@itL28QI?I-Y-aHhR zQE>Epyn^l?+>j$>wd3N}=Q7+=Et#s_;Xhn3QsOyI#PX=<@R1UT)t}NiE?}=ypwvaSVdTkTZHU@Qb-#eqDj)VADsIHhrO*nKm z#HVa#79T1H)&MYTaE(loe^+op59_jFVb)S?T%Z5jmYMZC4r7DJ9vs_x8(@3B&Y_uF zjYg+1!*$uHu~)n;E^4?5DKV%xJTCF}c_5XXo_KMHq4{qv#cT(~Z>qRUZ<64eIR#aU z1-gWX{97?Oj9}O7u%icF_R?`mItG>!Uj4#T!2@C-}-Qi%n;a0DZaGdX{76kwXV2%y*tYq^0LYXkelW>*J{4? zNDqbZrER<*V(F)6yUW5e&CS89y_7sek+S z9qe{aAG~#6HsFFc^W$-TVRV^V+Tigz3Q1c=p=Dx)0?#aO@;hDlvLW^GQ)W^n;c$-d zI7hg;j%iO03#F;d!17F!PC=eftA5*XI| z(2~cprWr7*m`Rx1PKvJ<^Nq@{AxJZ8#YK)U6d`w49?R8Aopne&7sq~fqN=fdsRBk& zvP{mKh8Tos<@Pm_91+^^>l?!GIxWL+-|Mdj_l~yBhfP@L8caSPy>VvV`XO=m!`}PT z?p&AV_P(WVlYyE=K(Mo&;s+d)@2b8Z&tFO55K)d;A>Sb#Ff8MOI61fi=IBw0tXG*T z!i0Z_r*HmBLCBeTkkRXge4NkdE^C2z(mRh$Ki;$gu&+Z(w?E9!EGWnB?{ghmMbS`1 zY03MqnF0Ir0{3?lMC<~gU%$o4f+LQ>62iBdM8M^LThc_RDNA>B#$$Zh89g*!KxYHk zYDir|<~f~MFV}@P*W_)~aVHV;kGnD%TCj+=6lyEnUpn|=;@=846lsh3(aU=N?wfBh zwGw|j$K7VavpnI@gf_tQ4Y#grXRgwx*B9;R+pR&}dfPL4&=ZY@onbg3Q}E3S#QQOJ zuz|vVRG$_t46PROJ|WWG&Q}mlgLiEee?naBk0;9i+r6S;`(5rtx78^_$<5C6MLU-V zt%P=Ds-Xz<8*->VDW^T<7r8pL&kZNOl9I=K9^4_mJ*zFPG~QV0799m8c@}7epJQ%T zPBz8Vs*#Ee`U8ij#WcskprJK2>++|0V_gl~hzFS~`Y;d0itNJvsGUY{c4d&ty5fXe z&P_yDe&sZlvR7V=M+KF!4n62Q2M}(Si>4hU*Mpsrh$qkT?c2AeP6(=_EqqVO3G>Ah zpba(lqvm!l+qa_JM9&61t>NkVd&%FraDqL7W1D;1GmLj^1TUeGJfjKxyOe!`(e-_bAc8 zn;x<;3mc>4vtT#50Umt8Wa@Yjzyz44az=Fm>JT$ zgxX2>3@B80Kqabi3)L7YTtLmaUHD0BK4y?#Ii6%&<#wcG_N6F5TGi^V#uk zO4vBhn?#|yD~_0-v8?5Myi8MVJhte8s3tgpSHplx?sgK#y4Wyf;_7f=^wK6-kQr*$ z9@1Z0H^jIYRKKCJQIQoIXjCbaCA2+!{yEB7Z-0@Sr%PsgG@X$m^WQ^a-)>aMaREsK z>!!RwsXz_}^@~vop;JfK%%p3>WZ}5^_+DePg z{y?+*OIBlEne=J&qP9<5VaWEJz@}JzoI}Ec0{w+2`PoDM>Mcz7jd-o7(K^l$YME-Zw^twcu;n z*x7$KUuq(YzqaQrJTw#<=EFo@uE z_afC)-GUc-KyYnCmcEmPbcsi7N1bk+pDZoN0eBQVjGRnImHNRCHbAj(8l z>*|zSS%)cF|m(t$mLuhSK9}aqtVnwk4TJ)Tpps0s7tF$lmRlDPW$Stt#b+>uu^t* z?~*AZtytU`^Z|JRnl!-d3>bg>zOwUyhGNnSIQ!=ez|@NvU65{Syy9Ma&r2^cyBXz> zfS~zZ6+I8QWxovjDiaBxjY?2egin-- zuiOSmtEa7Fp~tUijs5J*N2tR0mCH0Ue>vJojPs>J2I7nQ3Yn&Vc3J2sgz!td1;8!XS$!8753cebJv%g`$)2sLr<0` zrlCuU1Pao{L0isD$<%Rf^EbIP?#R=GbTMCxCzIp49N=0y3hW%~#XD8kZ7>?HwXIGBg>@s_MyVz7dAbLwxQh@?aO%{Dp&X^WiHHcKYe)1((owE zeiaNBjg-#~+eo3#zjlbrdgUY}fO4L4zaio~Hl+)SZr@MLGm-b%nJ`V?&g_X}>EUqTJBqVkV)FzoRY12lG z`@$Fkr}t&^vW*=<9gFo~&I_CUFZpo_G-N2e+!SP?d#*9xx|m{E9f)cY+TxdH3Aeqy>%iU6TV7~KYl(;J>>2Br%t1HSH%yebJT-zq+~N?T zK-3!>cXOa=3Hs>Vfsv4|A$a{F$)8xVS++7&LG8Ikukgtqqi9}9u3eN|A$yI(nT_df zL??NRoUixaP~<12j>lZ$HEwt-)mJSax9vMqzY(_*2fX-F@TMpxt=Mc?hrSXq>sprK z)D?u)SH0IETQgbKPT)S*`<8k)HYt@eW<{!KFHMyjobLUt^OR0%{Vop2nm(AC<)(gI zZcd{pb*1NL9g5~eDDmZBiYyzl2==M9S7{dM@cY1BrCC1kMaC0lQPr7)JxZ|vLasaG zsli;~86nLmzR>1jPRNN}y-K)rR#6HJQqVqJz{U_S%ncy@T3&Z(ECCMpjh?mNixS;E zGp9_P@e`9{wk%UT+((+0=xMjCWTNMxyy2pp`zISk{44+uXZ(bca&r_}{@%FNOKnSE zeS*U6s_z@qT0@_9!OaqfnimHGzGyi$kOhI{?%a0m)VsE&;tCmkYW9O(2cz9`xF@5v z@LvQQ^UW%z8v8O9zWhupm+_#dVfX047qKFr=NPiA>a1j8 zJKRTm@~mtqX5wIUHrlhZ4*mV-SHc&QwCAuILk!E-KOmt#Z^i8J)-~0m3o2A|H*)O$ zk)u|=E8y~m9`aatISUB6qJ4NRcGVm$dXaIOMQoJ|_&{%1PG13ii`Bp$xPxDEZjSoO zrPg9goyf4;6gOfL=lfgcSXdXn0Ud=X>-W5aG^-WO=qEa9F(bLL>0Va*QP=2)oS{HW z?CqF+HWrM3b-1&XLw6Cg0SE7vD>b`zk%>2b+0R78<{Q+cQc|sN7XYp!LT0#H^FnyT zQE&D|0;>YILP= zc%+ZdTc*}m?ke)z3aK?@%OGYyzj$YZ-h6oQCu%D!*_Y8nj=d&jX68Dg+!_NsgMZa8 zHHw`IB+hUNn5_nh*=I46_1B#xn!;o1^PPNl7-6G;+jH72(z>pj~$^*a>e> z-Ow?AyR~vP6Mgi@pAAd*WBRW`f>coBd?_QeMc+#Z%1?UFx3D6a{8|g(eiv87Tnu<9 zbyjF8`#h5d(HgRh`sVB+7v@W~S<42l6MulA%DG`_e(Kmj%kZiAT>%syr5@d8C43kh zD)z9bVF7kDB1LsolatB={n|Rg%Lo_+%JZ7viiy z*r)c^v=FMfJ|_yO34?pfC7($$Xn=J_*4CU(jgJ(|V(!MN$f-4X`vq&T(=4X@aO*Q| zMAfpoA5Z8)KiAMR$y9noB|+q1s1z;F{&oFEO_QF}73(W!c69*Kt*ZN^39eQpyg61w z^zvxE(xaPomf+-J|E{*Xwn?9~yG)9$Gy-6+_!&NetHy2KWw;a-)N_j6Q2py#-r^u7 ziR&u`Q7}2j2G)I#S8Bxc`j_s$rN*!<<>MAW=VPIP62il)#9=GXFHSC(J z2&w&dk=ocx9{7H6Pw8^?Og(bccM^D1{!TmEJ(Df?o=Ba%w@zXPHajYQDRVj?gDKd@ zmf^yv#(vz#ayoqyBT`&a6Xjxg=m0mOk7j*xD!MCr)w_F>;=%Ky?$wvPUvNszDbD)9 z^izdzc7Ul9wPiLY*^?!)s8Cyk;4d@Sjtt48`PXiA;Kqg3<&FY|7L$Q)`{hp(N~5fh zD_xbuP&epO{;yM$L+t^&zz%ry-}4YDj?fYO%bWcH*2wEUk9sGC)FNO)nMK3zJFU{ILDazJlCLcGn-uv zSrrpi4_KsmAnQjs7yQ9XXP|h+I~r)66YfxCVS^z#IbeYhH{ADu`*J#(Cb{+F8?4%> zEQPc|EaJ$(NCnlsyMRHBcb4#TucNK z8Q7;iOC)^JPD_G`MUbZKr9yuRJ$0|!xBp6sEJH`$8F!t~lR8kscDSFxnqHEE7>=fHO*k)yBKR243vkcjq>>GLNeLDl6#1VnIDJ zfxGZ-dLN5Yro3$S+a85+{gQcR*CxX7`(ms-ucSPdW)1Mz_;Iv3H+DjjN__J}nBMV} z3ObKSgS%&BQ9fg=h#F*qXb`3 zxADb|Uq=7Bv6YQnHDtX{PiF>dc-aj49vxtF9v%fMr}aJl0M=i&v(9~=&$+hoJ<$w$ z!dAo$Z~{Em#*=S(+FqIFWn!q866YL`9syt_i{(_tPeCQial9aU<>hUpEWeYdwpVbT z6e^u-TAT~_#V+VzwnKKQG5E26-2`D1=bm~Pl|?V5;)ZWpA1K%zIyY}?x>D8V)yON0 zTYGaN$la07CwcJV02vxanz2Z?1cM~oD*lQVhi(Y}=15-#QTTRbp3qSeicwKtwGz5~ zCL#lr84r%%Z6}&AS~BNit)jD|NuhDG`Tqu3om@jD#=X2zNlnWqG{kTkLtka`VR3oW zO;AwR>ccZA(mBUVxXhKQbD;gnGJAb>3K<#B9{p#|?btA+_fErW>`@**WQ^C_7*_SA zn2D~3s-b4W7RF3JI{W4xuOy0yzNCn7{Dw7Zwa{hC<}0<@A(M4fk>#AfJ7jcDYz_mc zY%2tje&=nYqW{ELSz|apf^u`5!T1q3*!X(@$0^OzAIyBt%}1><)`OR7gmgmPwF1Ui zoz4*L6^Bo`(k0#sYgqFk9Ob?lRpHUZqQ=>*x`6l3etT*c&F;m-3cI%Zf(-`Bs5rPW zlv4Lh3iNUU7-4%K_W0y@l$|fNq@58OqcmLN0c15$1M6)Z$L9DV(}PZXM~S6e|E5C* zbK#jW=o3SnBUV$2lv;Pz_y37Cp3#}l4=qNSzAZ4g03p(SdWToM^OV_9}W(; zebo@8Xlsl40s9459?Q$xv{AyuJdX~bb(!c{VY{^tkL3lWw-x$Wi)MQd4;sPCa!E)m zz(=Qp8e19JBjEK3Old{2Us*?hxAz$@d~f^Uobbf^R{vA?pAC_nPu?UMRkUw}gi-5- z>ydT^yfXX5KWIAnZTPc$K+>I z$~Ks#sl=@7cYJml6%9ANgS|YHmVDbs`QDq2ntCKNaI+^F`8s+)#beO18yDTLoyl$B zZrX`O8LLV-&KPV8t;JUmsj$J_=GuqK7eDO$?*y+D?Ghc=0-`@Bv+>qXPqM#Oek5 z0V}ehQsWNEU|Uk7%`x0mECkUjIogW#c)id1_E8RhIS*jl5T_HP7~Cc3u?OJf+|1V3 zYN&w$N1xli9z&XpQZ(_WmQT~5V^)S=CwOIC9ihbjk~LF8+uOfe{opp6@-%y>=7 zwhCF6DROmh!b*_@4ixJyoM9=X*}ZIRydkze-`%BAFZ9`bW7Z@`Bt-HK*(A)0=LXsdmA&aUY24~@{8`1g z=o2}&&M!=4Dlb5*NHEK=J_7<{_XyhHh1bEnGQufE2FK=LV~inJF+zPFR{>SDoAA8< zIQrL||9n7PV(RE}01&4EHkx0kq_W2b6+B%S+D6TsbsKe3;C&dECY9hEbBCar>zc56 z{=HSugu_)i5K%>`F>={>Md&#xl*prPMEgkZCgCanW0}(3!Ckv+JA6}Yu>C7Z=oG0< z8*v$43-K-bb_H$kBJ{UcD((~?U&&KgEg=ZAV`(c}v)Q6j0G!2TdYE&=T1t(BFJ8+q zh~9hI5~Y)~#bVn4Gm9#+;^Czw`FB@Goti_JphXe8Mg{{9DDGk-1`5OhzsW}5Ia=+! zf9OVDZ%(w(YmE5WPh&dkxa^^XiK-IdYP(jMVj2;$Z)%B4b_hlJfnpF0xiS#2>y8e4 zcKXndrKa(4ODQA0%+OtL7bdH&yQ9V>Xdun`+EyDedv&0xh9B8rHQd}*3 zGePY$;L5w;src1nC8Z;xNn<1E?^hEr1dEOL$*8wOv|h;<##?KWRN#W>8r(K{QU0Z< zJ7K8%66ibN;dfz&Ij^X%zP&lsb{!#=&SmNCLF29q^IhMFNNA%~E;g%fCy%PAsoUV} z6Z-6EA3{xl%4+D9V;QiJWMk1;S*V!6O7xv~XEx{Jan?xMAiWXv1>j_9wT+MkB^t2# z%hU_RnaCXmJeyXzjiwr^(AUxy{HgurO92v^P&X4=9b*!E+7tc#f*3<|pCZkmT|Nt2 zET3A~^aHN$JIVc4U|wq9JCq@=3J6Njf1WP_Ip}HiZh>zcT_V4hbvHs0(8OQzs51Q) zT3snEL_igZBMfuF7p+6zOIBeS0e9M-y1&b|jL)%>n!pMq4;QIq3AmV`TRWXb)TKTO zc?J4(0i7sB6KtiL|JoQoWl00+Z=E`JK2=NQE8k=j? zbcXp0J>jwv7B|<2cLSo1$giacitZ?GOPjd2qC4&WBAqYdDGAHc52~zrjUQ6fz*~@Q z@P+z5Xxy)=q-#Il#PP?oFDrz}y{M8la`11F^AmWvBzlljN{50IeYvO+2cN za@Y}E4I44j{DcpbT5ZY-?A5`PWG-Dv_-K}Iqln*oYv#vx=HWE2iFiZp1sRBN_}p{b z4({;XPBujz$7``A%$RR2H~SDKO2z-WJVbW|!5g!drUe~AxWUyVUS!dMNEMt?mEz@> z=#Ll0sJ?ABv^-F z%=2bkY-qZ%(l?)dIrcI`?#1m?sLKm=rBaik7ZEWkzbBYR(@P{F{LyD=Ez4a3-=aeS zy^#*Kugn{@ntrX=eGR;zEFxHg2u3?oHT${?7N2TEz=(_Cd#_1FqRE!B(7_J;M$x;O zipiB_RqB3!o!YdIs}Ic^3yH56@I7eau23G$rXu^hgBVeC5We{MP`~zhrRh;gSdmg` z`HA(Pm#kH&Jsn4z4SEi)<*;MRJ7R7Yy}0R)t4hlE%>3wGHuKW4Z?VbMo=&&2UQ6fJ zd!+I}y?qM1J}m}660VXjGUWd}M|D45n|4E6=<9|C`}A>9Yi}a878WM4VjtejcR3V7 zw}DUTw|eR;-1@m6F8FGi*2+0q_o|LCpwp7oBX%o^Yo8KEoJWGDG~GHc^$k(pqfZHg z5+XV-E_ZMYEOVEwHEwoPoDhziI8mo>z_#w7NcM%(csX5N_=$XmjcjO|#aMjrIpyt% z_Hn7be%YXTTlhD~j)Pc>Sk_Wbho*gu;mlY!Sl1xpEU!$+dVQh}c5}|JI~z6ysvKsB zNGuyD<)7G^ZOz1_ANej4dO`ygS3eS$k1$45|HZ)tT1;uB$f|5(0Q{7#qMpIYl_0Z;W00t>n zY`_Ia2heffd^)|0kWl4I*n;WB%mM%vCRD9hU>wKn80(%!pMTf{k;$MqJ@G++k-!Zd z%Z4;7-^{$0R|Qk6b!1e~mcWBt`=xsinf$0b`hd`0;}^Gq#$ zTkQCCey_aTK z+Kd!ysMO5=p+njlaZhFV`!Cv*@{xmm`Vd6sjNpmA_ePm(Q$6HltH%yh5hr;y{dlc| zKL&R?8oV^=&^l4adUt!}(6?xR2fUrrMa9<0-W)?fdHV)}<);3Qv@o9?ru|;H$|Gu1 z^M|a^_ZjRXA`-s%EOY1|Ark)+1hIJW9(;Q5;@9Ut2Y>juwu(G^x%KL`tDQ0h>b_%o@f5!rGLNqKflPIzsUbR zcz=%8pZ}5nxS;;rT7RzJe^i-2b>vTF|7Q#Fr$zbGYyIOq{ONxGwDJFh9)Ix2AB6ai z^Y91i{=w}3L74m@AO4UJf5?a5pTHkr^#@q}qme%O2Uz`o0IVLaf3DfKO$2In-qQXL vGye~n;}7fjhjskJI{y9y{+}2X!HGNI=8N`M0w=c#zpO6Uo-aG=8UKF(`jLeN literal 0 HcmV?d00001 diff --git a/docs/releases/v0.1.1.md b/docs/releases/v0.1.1.md new file mode 100644 index 0000000..aa49cae --- /dev/null +++ b/docs/releases/v0.1.1.md @@ -0,0 +1,33 @@ +# Codex Pulse v0.1.1 + +v0.1.1 is a downloadable macOS 14+ prerelease. + +[Download the DMG or ZIP](https://github.com/18637168668a-cpu/codex-pulse/releases/tag/v0.1.1) + +The app bundles Node.js and the read-only local bridge. End users do not need Node.js or Xcode. The companion app is non-sandboxed so an explicit user action can install or repair its per-user LaunchAgent; the WidgetKit extension remains sandboxed. + +## Install + +1. Download the DMG or ZIP and move **Codex Pulse.app** to `/Applications` or `~/Applications`. +2. Open the app and click **Enable/repair bridge**. +3. Add the widget from the macOS widget gallery. + +Codex CLI or the Codex desktop app must already be signed in with a ChatGPT account. API-key-only login is not the intended mode. **Remove local bridge** removes the local service but keeps the app. The reset radar is off by default; use **Enable reset radar** or **Disable reset radar** when needed. + +This build is AD HOC signed and unnotarized. It remains a prerelease; clean-Mac and Intel execution tests are pending. If Gatekeeper blocks it, follow Apple's app-specific approval guidance: [Apple Support 102445](https://support.apple.com/en-us/102445). Do not disable global security protections or remove quarantine attributes. + +## Downloads and verification + +- `Codex-Pulse-0.1.1-universal-unsigned.dmg` — app plus Applications shortcut. +- `Codex-Pulse-0.1.1-universal-unsigned.zip` — the same self-contained app. +- `SHA256SUMS.txt` — integrity checksums, not a substitute for publisher signing. + +Both Apple Silicon and Intel code are included. Intel execution and clean-Mac Gatekeeper/widget registration remain unverified. + +## Source fallback + +Source installation remains available for developers and troubleshooting. It requires full Xcode 15+ and Node.js 22+; see [installation guide](https://github.com/18637168668a-cpu/codex-pulse/blob/v0.1.1/docs/INSTALL.md). The source path retains the existing scripts and local-only setup. + +## Privacy and limits + +The bridge is read-only and local. It does not read chats, start model turns, redeem resets, or request purchases. The optional third-party reset radar makes public HTTPS requests only when enabled. Screenshots and rendered previews use synthetic demo values and are not live account data. Widget refresh timing remains controlled by macOS. diff --git a/native/CodexPulse.xcodeproj/project.pbxproj b/native/CodexPulse.xcodeproj/project.pbxproj index 57c1660..bbe76f3 100644 --- a/native/CodexPulse.xcodeproj/project.pbxproj +++ b/native/CodexPulse.xcodeproj/project.pbxproj @@ -146,10 +146,10 @@ /* Begin XCBuildConfiguration section */ H10000000000000000000001 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = {CLANG_ENABLE_MODULES = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_TESTABILITY = YES; GCC_OPTIMIZATION_LEVEL = 0; MACOSX_DEPLOYMENT_TARGET = 14.0; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; H10000000000000000000002 /* Release */ = {isa = XCBuildConfiguration; buildSettings = {CLANG_ENABLE_MODULES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; MACOSX_DEPLOYMENT_TARGET = 14.0; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; - H11000000000000000000001 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = {CODE_SIGN_ENTITLEMENTS = CodexPulse/CodexPulse.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulse/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.0; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app; PRODUCT_NAME = "Codex Pulse"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Debug; }; - H11000000000000000000002 /* Release */ = {isa = XCBuildConfiguration; buildSettings = {CODE_SIGN_ENTITLEMENTS = CodexPulse/CodexPulse.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulse/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.0; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app; PRODUCT_NAME = "Codex Pulse"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Release; }; - H12000000000000000000001 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = {APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = CodexPulseWidget/CodexPulseWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulseWidget/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../../../../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.0; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app.widget; PRODUCT_NAME = CodexPulseWidgetExtension; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Debug; }; - H12000000000000000000002 /* Release */ = {isa = XCBuildConfiguration; buildSettings = {APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = CodexPulseWidget/CodexPulseWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulseWidget/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../../../../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.0; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app.widget; PRODUCT_NAME = CodexPulseWidgetExtension; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Release; }; + H11000000000000000000001 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = {CODE_SIGN_ENTITLEMENTS = CodexPulse/CodexPulse.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulse/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app; PRODUCT_NAME = "Codex Pulse"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Debug; }; + H11000000000000000000002 /* Release */ = {isa = XCBuildConfiguration; buildSettings = {CODE_SIGN_ENTITLEMENTS = CodexPulse/CodexPulse.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulse/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app; PRODUCT_NAME = "Codex Pulse"; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Release; }; + H12000000000000000000001 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = {APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = CodexPulseWidget/CodexPulseWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulseWidget/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../../../../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app.widget; PRODUCT_NAME = CodexPulseWidgetExtension; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Debug; }; + H12000000000000000000002 /* Release */ = {isa = XCBuildConfiguration; buildSettings = {APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = CodexPulseWidget/CodexPulseWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = CodexPulseWidget/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../../../../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = io.github.codexpulse.app.widget; PRODUCT_NAME = CodexPulseWidgetExtension; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ diff --git a/native/CodexPulse/CodexPulse.entitlements b/native/CodexPulse/CodexPulse.entitlements index a8c1072..899d535 100644 --- a/native/CodexPulse/CodexPulse.entitlements +++ b/native/CodexPulse/CodexPulse.entitlements @@ -1,10 +1,3 @@ - - - com.apple.security.app-sandbox - - com.apple.security.network.client - - - + diff --git a/native/CodexPulse/CodexPulseApp.swift b/native/CodexPulse/CodexPulseApp.swift index 70dcf4b..ff6a50b 100644 --- a/native/CodexPulse/CodexPulseApp.swift +++ b/native/CodexPulse/CodexPulseApp.swift @@ -6,64 +6,172 @@ private func tr(_ en: String, _ zh: String) -> String { Locale.preferredLanguages.first?.hasPrefix("zh") == true ? zh : en } +#if !SETUP_PREVIEW @main struct CodexPulseApp: App { var body: some Scene { WindowGroup { ContentView() - .frame(width: 480, height: 340) + .frame(width: 570, height: 510) .onAppear { WidgetCenter.shared.reloadAllTimelines() } .onOpenURL { _ in WidgetCenter.shared.reloadAllTimelines() } } .windowResizability(.contentSize) } } +#endif struct ContentView: View { @State private var status = tr("Checking local bridge…", "正在检查本机服务…") + @State private var result = "" + @State private var busy = false + @State private var connected = false + @State private var socialEnabled = false + @State private var confirmRemoval = false + @State private var confirmRadar = false + @AppStorage("customCodexBinary") private var customCodexBinary = "" var body: some View { - VStack(alignment: .leading, spacing: 20) { + VStack(alignment: .leading, spacing: 16) { Label("Codex Pulse", systemImage: "gauge.with.dots.needle.33percent") - .font(.system(size: 28, weight: .bold, design: .rounded)) - .foregroundStyle(.cyan) + .font(.system(size: 28, weight: .bold, design: .rounded)).foregroundStyle(.cyan) Text(tr("Your Codex quota. A glance away.", "Codex 额度,抬眼即见。")) .font(.headline) - VStack(alignment: .leading, spacing: 8) { - Text(tr("1. Right-click your desktop → Edit Widgets", "1. 右键桌面 → 编辑小组件")) - Text(tr("2. Search Codex Pulse → add small or medium", "2. 搜索 Codex Pulse → 添加小号或中号")) - Text(tr("3. Both percentages mean USED, not remaining", "3. 两组百分比都是已用量,不是剩余量")) + VStack(alignment: .leading, spacing: 7) { + Text(tr("1. Sign into Codex with your ChatGPT account", "1. 在 Codex 中使用 ChatGPT 账号登录")) + Text(tr("2. Enable the local bridge below (starts at login)", "2. 点击下方按钮启用本机服务(登录时启动)")) + Text(tr("3. Right-click desktop → Edit Widgets → Codex Pulse", "3. 右键桌面 → 编辑小组件 → Codex Pulse")) }.font(.system(size: 13)) - Text(status).font(.caption).foregroundStyle(.secondary) HStack { + Button(tr("Enable/repair bridge", "启用/修复本机服务")) { + perform(["install-prebuilt", "--app", Bundle.main.bundlePath]) + }.buttonStyle(.borderedProminent) Button(tr("Refresh widgets", "刷新组件")) { WidgetCenter.shared.reloadAllTimelines() Task { await checkBridge() } - }.buttonStyle(.borderedProminent) - Button(tr("Setup & help", "安装与帮助")) { - NSWorkspace.shared.open(URL(string: "https://github.com/18637168668a-cpu/codex-pulse#quick-start")!) }.buttonStyle(.bordered) + if busy { ProgressView().controlSize(.small) } + }.disabled(busy) + Text(status).font(.caption).foregroundStyle(connected ? .green : .secondary) + if !result.isEmpty { + ScrollView { Text(result).font(.caption).frame(maxWidth: .infinity, alignment: .leading).textSelection(.enabled) } + .frame(height: 56) + } + Divider() + HStack { + Button(tr(socialEnabled ? "Disable reset radar" : "Enable reset radar", socialEnabled ? "关闭重置雷达" : "开启重置雷达")) { + if socialEnabled { perform(["social", "off"]) } else { confirmRadar = true } + }.disabled(busy || !connected) + Button(tr("Remove local bridge", "移除本机服务")) { confirmRemoval = true }.disabled(busy) + } + HStack { + Button(tr("Choose Codex…", "选择 Codex 程序…")) { chooseCodex() }.disabled(busy) + Button(tr("Setup & help", "安装与帮助")) { + NSWorkspace.shared.open(URL(string: "https://github.com/18637168668a-cpu/codex-pulse/blob/main/docs/INSTALL.md")!) + } } - Text(tr("Read-only · local bridge · macOS schedules widget refreshes", "只读 · 本机服务 · 小组件刷新由 macOS 调度")) + Text(tr("Both percentages show USED quota. Read-only · no telemetry. macOS schedules widget refreshes. You can close this app after setup.", "百分比均为已用额度。只读、无遥测;刷新由 macOS 调度。设置后可关闭主应用。")) .font(.caption2).foregroundStyle(.secondary) } - .padding(28) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - .background(Color(red: 0.04, green: 0.05, blue: 0.075)) - .preferredColorScheme(.dark) + .padding(26).frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background(Color(red: 0.04, green: 0.05, blue: 0.075)).preferredColorScheme(.dark) .task { await checkBridge() } + .alert(tr("Enable third-party reset radar?", "开启第三方重置雷达?"), isPresented: $confirmRadar) { + Button(tr("Enable", "开启")) { perform(["social", "on"]) } + Button(tr("Cancel", "取消"), role: .cancel) {} + } message: { + Text(tr("codex-reset.com receives normal HTTPS metadata, including your IP. Codex credentials and quota data are never sent. Posts are heuristic signals, not official reset confirmation.", "codex-reset.com 会收到 IP 等普通 HTTPS 请求信息,不会收到 Codex 凭证或用量。动态判断仅供参考,不是官方重置确认。")) + } + .alert(tr("Remove local bridge?", "移除本机服务?"), isPresented: $confirmRemoval) { + Button(tr("Remove", "移除"), role: .destructive) { perform(["remove-bridge"]) } + Button(tr("Cancel", "取消"), role: .cancel) {} + } message: { + Text(tr("Stops the login service and moves its files to Trash. The app and Codex login remain untouched. Remove the desktop widget separately.", "停止登录服务并将其文件移到废纸篓,保留应用和 Codex 登录资料。桌面小组件需另行移除。")) + } + } + + @MainActor private func chooseCodex() { + let panel = NSOpenPanel() + panel.title = tr("Choose the Codex executable (not the .app)", "选择 Codex 可执行文件(不是 .app)") + panel.canChooseDirectories = false + panel.allowsMultipleSelection = false + if panel.runModal() == .OK, let url = panel.url { + customCodexBinary = url.path + result = tr("Codex path selected. Click Enable/repair bridge to apply.", "已选择 Codex 路径,点击启用/修复本机服务后生效。") + } + } + + @MainActor private func perform(_ arguments: [String]) { + guard !busy, let resources = Bundle.main.resourceURL else { return } + busy = true + result = tr("Working…", "正在处理…") + let selectedCodex = customCodexBinary + Task { + let outcome = await Task.detached(priority: .userInitiated) { + SetupRunner.run(resources: resources, arguments: arguments, codex: selectedCodex) + }.value + result = outcome + busy = false + WidgetCenter.shared.reloadAllTimelines() + await checkBridge() + } + } + + @MainActor private func checkBridge() async { + do { + var health = URLRequest(url: URL(string: "http://127.0.0.1:43187/health")!) + health.timeoutInterval = 3 + let (data, response) = try await URLSession.shared.data(for: health) + let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] + guard (response as? HTTPURLResponse)?.statusCode == 200, json?["app"] as? String == "codex-pulse" else { throw URLError(.badServerResponse) } + connected = true + socialEnabled = json?["socialEnabled"] as? Bool ?? false + status = tr("Local bridge connected. Checking Codex login…", "本机服务已连接,正在检查 Codex 登录…") + var usage = URLRequest(url: URL(string: "http://127.0.0.1:43187/api/local/usage")!) + usage.timeoutInterval = 20 + let (payload, usageResponse) = try await URLSession.shared.data(for: usage) + let value = try? JSONSerialization.jsonObject(with: payload) as? [String: Any] + if (usageResponse as? HTTPURLResponse)?.statusCode == 200 { + status = value?["stale"] as? Bool == true + ? tr("Bridge connected. Showing cached quota; check Codex login/network.", "服务已连接,当前为缓存额度;请检查 Codex 登录和网络。") + : tr("Bridge connected. Quota data is available.", "服务已连接,额度数据可用。") + } else { + status = tr("Bridge connected. Open Codex and check your ChatGPT login.", "服务已连接,请打开 Codex 检查 ChatGPT 登录。") + } + } catch { + connected = false + status = tr("Bridge offline. Use Enable/repair bridge to set up.", "服务离线,请点击启用/修复本机服务。") + } } +} - private func checkBridge() async { +private enum SetupRunner { + static func run(resources: URL, arguments: [String], codex: String) -> String { + let candidates = [resources.appendingPathComponent("runtime/node").path, "/opt/homebrew/bin/node", "/usr/local/bin/node"] + guard let node = candidates.first(where: { FileManager.default.isExecutableFile(atPath: $0) }) else { + return tr("Node runtime missing. Download the complete release or install Node.js 22+ for a source build.", "未找到 Node 运行时。请下载完整发行版;源码版需安装 Node.js 22+。") + } + let process = Process() + process.executableURL = URL(fileURLWithPath: node) + process.arguments = [resources.appendingPathComponent("scripts/manage.mjs").path] + arguments + var environment = ProcessInfo.processInfo.environment + environment["PATH"] = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:" + (environment["PATH"] ?? "") + // Avoid user-injected Node options in the bundled installer/runtime. + environment.removeValue(forKey: "NODE_OPTIONS") + environment.removeValue(forKey: "NODE_PATH") + if !codex.isEmpty { environment["CODEX_BIN"] = codex } + process.environment = environment + let pipe = Pipe() + process.standardOutput = pipe + process.standardError = pipe do { - var request = URLRequest(url: URL(string: "http://localhost:43187/api/local/usage")!) - request.timeoutInterval = 20 - let (_, response) = try await URLSession.shared.data(for: request) - status = (response as? HTTPURLResponse)?.statusCode == 200 - ? tr("Bridge connected. Quota data is available.", "服务已连接,额度数据可用。") - : tr("Bridge is running. Check your Codex ChatGPT login.", "服务运行中,请检查 Codex 的 ChatGPT 登录。") + try process.run() + let output = pipe.fileHandleForReading.readDataToEndOfFile() + process.waitUntilExit() + let text = String(data: output, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" + return text.isEmpty ? tr("Setup finished. Check the bridge status above.", "操作结束,请查看上方服务状态。") : String(text.prefix(1800)) } catch { - status = tr("Bridge offline. Run bash scripts/install.sh from the repository.", "服务离线,请在项目目录运行 bash scripts/install.sh。") + return tr("Could not start setup. Re-download the app and check the installation guide.", "无法启动设置。请重新下载应用并查看安装说明。") } } } diff --git a/native/CodexPulse/Info.plist b/native/CodexPulse/Info.plist index be494a8..52299b6 100644 --- a/native/CodexPulse/Info.plist +++ b/native/CodexPulse/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1.0 + $(MARKETING_VERSION) CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) CFBundleURLTypes CFBundleURLSchemescodexpulse LSMinimumSystemVersion diff --git a/native/CodexPulseWidget/Info.plist b/native/CodexPulseWidget/Info.plist index ae9ec53..76ec0ab 100644 --- a/native/CodexPulseWidget/Info.plist +++ b/native/CodexPulseWidget/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 0.1.0 + $(MARKETING_VERSION) CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionPointIdentifier diff --git a/package.json b/package.json index 619ad34..8813aae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codex-pulse", - "version": "0.1.0", + "version": "0.1.1", "private": true, "description": "Native macOS widgets for Codex usage and reset countdowns, with a local read-only bridge.", "type": "module", diff --git a/scripts/build.sh b/scripts/build.sh old mode 100644 new mode 100755 index caa6316..79fd274 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,21 +1,44 @@ #!/bin/bash set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" +BUNDLE_RUNTIME=0 +if [ "${1:-}" = '--bundle-runtime' ]; then BUNDLE_RUNTIME=1; shift; fi +if [ "$#" -ne 0 ]; then echo 'Usage: bash scripts/build.sh [--bundle-runtime]' >&2; exit 2; fi if [ "$(uname -s)" != Darwin ]; then echo 'Native widgets require macOS.' >&2; exit 1; fi xcrun --find swiftc >/dev/null xcodebuild -version >/dev/null +VERSION="$(cd "$ROOT" && node -p "require('./package.json').version")" +for file in "$ROOT/native/CodexPulse/Info.plist" "$ROOT/native/CodexPulseWidget/Info.plist"; do + [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$file")" = '$(MARKETING_VERSION)' ] || { echo "Expected MARKETING_VERSION template in $file." >&2; exit 1; } +done +grep -Fq "MARKETING_VERSION = $VERSION;" "$ROOT/native/CodexPulse.xcodeproj/project.pbxproj" || { echo "Version mismatch in Xcode project (expected $VERSION)." >&2; exit 1; } STAGE="$(mktemp -d "${TMPDIR:-/tmp}/codex-pulse-build.XXXXXX")" +trap 'rm -rf "$STAGE"' EXIT xcodebuild -quiet -project "$ROOT/native/CodexPulse.xcodeproj" -scheme CodexPulse \ - -configuration Release -derivedDataPath "$STAGE" CODE_SIGNING_ALLOWED=NO build + -configuration Release -derivedDataPath "$STAGE" CODE_SIGNING_ALLOWED=NO ARCHS='arm64 x86_64' ONLY_ACTIVE_ARCH=NO build APP="$STAGE/Build/Products/Release/Codex Pulse.app" +[ -d "$APP" ] || { echo 'Xcode did not produce the app bundle.' >&2; exit 1; } +RESOURCES="$APP/Contents/Resources" +mkdir -p "$RESOURCES/scripts" "$RESOURCES/runtime" +ditto --norsrc --noextattr "$ROOT/bridge" "$RESOURCES/bridge" +ditto --norsrc --noextattr "$ROOT/scripts/manage.mjs" "$RESOURCES/scripts/manage.mjs" +ditto --norsrc --noextattr "$ROOT/scripts/installer.mjs" "$RESOURCES/scripts/installer.mjs" +ditto --norsrc --noextattr "$ROOT/package.json" "$RESOURCES/package.json" +ditto --norsrc --noextattr "$ROOT/LICENSE" "$RESOURCES/LICENSE.txt" +if [ "$BUNDLE_RUNTIME" -eq 1 ]; then "$ROOT/scripts/fetch-node-runtime.sh" --output "$RESOURCES/runtime"; fi xattr -cr "$APP" -codesign --force --timestamp=none --options runtime --sign - \ - --entitlements "$ROOT/native/CodexPulseWidget/CodexPulseWidget.entitlements" \ - "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex" -codesign --force --timestamp=none --options runtime --sign - \ - --entitlements "$ROOT/native/CodexPulse/CodexPulse.entitlements" "$APP" +if [ -f "$APP/Contents/Resources/runtime/node" ]; then codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/scripts/node-runtime.entitlements.plist" "$APP/Contents/Resources/runtime/node"; fi +codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/native/CodexPulseWidget/CodexPulseWidget.entitlements" "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex" +codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/native/CodexPulse/CodexPulse.entitlements" "$APP" codesign --verify --deep --strict "$APP" +lipo -verify_arch arm64 x86_64 "$APP/Contents/MacOS/Codex Pulse" +WIDGET_EXECUTABLE="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/Info.plist")" +lipo -verify_arch arm64 x86_64 "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/MacOS/$WIDGET_EXECUTABLE" +[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist")" = "$VERSION" ] +[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/Info.plist")" = "$VERSION" ] +[ "$BUNDLE_RUNTIME" -eq 0 ] || lipo -verify_arch arm64 x86_64 "$APP/Contents/Resources/runtime/node" mkdir -p "$ROOT/build" +rm -rf "$ROOT/build/Codex Pulse.app" ditto --norsrc --noextattr "$APP" "$ROOT/build/Codex Pulse.app" -echo "Built for $(uname -m): $ROOT/build/Codex Pulse.app" -echo 'Local ad-hoc signature only; this is not a notarized download.' +if [ "$BUNDLE_RUNTIME" -eq 1 ]; then echo "Built universal ad-hoc preview with bundled Node: $ROOT/build/Codex Pulse.app"; else echo "Built universal ad-hoc source preview: $ROOT/build/Codex Pulse.app"; fi +echo 'This build is not Developer ID signed or notarized.' diff --git a/scripts/fetch-node-runtime.sh b/scripts/fetch-node-runtime.sh new file mode 100755 index 0000000..2d1d4e0 --- /dev/null +++ b/scripts/fetch-node-runtime.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +NODE_VERSION='22.23.2' +ARM64_SHA256='61130f394c1630d211dd50aecc4353d379480f36d3ac913cd85dbba1aed585c6' +X64_SHA256='58e99022c2ff89395576cc7fd4d98cea24bb68081475d5f88b801ee8729fb026' +OUTPUT=''; REFRESH=0 +while [ "$#" -gt 0 ]; do case "$1" in --output) OUTPUT="${2:-}"; shift 2 ;; --refresh) REFRESH=1; shift ;; *) echo 'Usage: bash scripts/fetch-node-runtime.sh --output DIR [--refresh]' >&2; exit 2 ;; esac; done +[ -n "$OUTPUT" ] || { echo '--output is required.' >&2; exit 2; } +[ "$(uname -s)" = Darwin ] || { echo 'The bundled runtime is only built on macOS.' >&2; exit 1; } +CACHE="$ROOT/build/node-runtime-cache/v$NODE_VERSION"; mkdir -p "$CACHE" +fetch() { local arch sha archive; arch="$1"; sha="$2"; archive="$CACHE/node-v$NODE_VERSION-darwin-$arch.tar.gz"; if [ "$REFRESH" -eq 1 ] || [ ! -f "$archive" ]; then curl --fail --location --proto '=https' --tlsv1.2 --silent --show-error "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-darwin-$arch.tar.gz" -o "$archive"; fi; printf '%s %s\n' "$sha" "$archive" | shasum -a 256 -c -; } +fetch arm64 "$ARM64_SHA256"; fetch x64 "$X64_SHA256" +WORK="$(mktemp -d "${TMPDIR:-/tmp}/codex-pulse-node.XXXXXX")"; trap 'rm -rf "$WORK"' EXIT +tar -xzf "$CACHE/node-v$NODE_VERSION-darwin-arm64.tar.gz" -C "$WORK"; tar -xzf "$CACHE/node-v$NODE_VERSION-darwin-x64.tar.gz" -C "$WORK" +mkdir -p "$OUTPUT" +lipo -create "$WORK/node-v$NODE_VERSION-darwin-arm64/bin/node" "$WORK/node-v$NODE_VERSION-darwin-x64/bin/node" -output "$OUTPUT/node" +chmod 755 "$OUTPUT/node"; cp "$WORK/node-v$NODE_VERSION-darwin-arm64/LICENSE" "$OUTPUT/NODE-LICENSE.txt" +lipo -verify_arch arm64 x86_64 "$OUTPUT/node" +codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/scripts/node-runtime.entitlements.plist" "$OUTPUT/node" +[ "$("$OUTPUT/node" --version)" = "v$NODE_VERSION" ] +echo "Bundled official Node.js v$NODE_VERSION runtime at $OUTPUT/node" diff --git a/scripts/installer.mjs b/scripts/installer.mjs new file mode 100644 index 0000000..e57b044 --- /dev/null +++ b/scripts/installer.mjs @@ -0,0 +1,176 @@ +import { cpSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import { homedir } from 'node:os'; +import { dirname, isAbsolute, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; +import { codexBinary } from '../bridge/codex.mjs'; + +const defaultRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const label = 'io.github.codexpulse.bridge'; +const appId = 'io.github.codexpulse.app'; +export const xml = value => String(value).replace(/[<>&"']/g, c => ({ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[c])); +function systemRun(command, args, optional = false) { + const result = spawnSync(command, args, { encoding: 'utf8', timeout: 30000 }); + // Never surface arbitrary subprocess diagnostics: Codex can include account details. + if (result.status !== 0 && !optional) throw new Error(`${command.split('/').at(-1)} failed. Check installation, permissions and the setup guide.`); + return result.stdout?.trim() || ''; +} + +// Dependency injection isolates installer tests from real user applications and services. +export function createInstaller({ root = defaultRoot, homeDir = homedir(), run = systemRun, + fetcher = fetch, platform = process.platform, env = process.env, + node = process.execPath, uid = process.getuid?.(), codex = () => codexBinary() } = {}) { + const support = join(homeDir, 'Library/Application Support/Codex Pulse OSS'); + const defaultApp = join(homeDir, 'Applications/Codex Pulse.app'); + const plist = join(homeDir, 'Library/LaunchAgents', `${label}.plist`); + const marker = join(support, 'install.json'); + const domain = `gui/${uid}`; + const version = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')).version; + const allowedApp = app => [defaultApp, '/Applications/Codex Pulse.app'].includes(app); + function assertApp(app) { + if (!allowedApp(app)) throw new Error('Move Codex Pulse.app into Applications (or your user Applications folder), then reopen it before setup.'); + if (existsSync(app) && run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleIdentifier', join(app, 'Contents/Info.plist')]) !== appId) { + throw new Error('A different app occupies the install location. Move it aside yourself; nothing was overwritten.'); + } + } + function settings() { + if (!existsSync(marker)) { + if (existsSync(plist)) throw new Error('Unmanaged launch agent exists; refusing to change it.'); + return null; + } + const value = JSON.parse(readFileSync(marker, 'utf8')); + if (value.appId !== appId || !allowedApp(value.app) || !isAbsolute(value.node || '') || !isAbsolute(value.codex || '')) { + throw new Error('Unknown installation. Nothing changed.'); + } + if (existsSync(plist)) { + const installed = readFileSync(plist, 'utf8'); + if (!installed.includes(`${label}`) || !installed.includes(`${xml(join(support, 'bridge/server.mjs'))}`) || !installed.includes(`${xml(value.node)}`)) { + throw new Error('Launch agent does not match the managed installation. Nothing changed.'); + } + } + return value; + } + async function preflight(prebuiltApp) { + if (platform !== 'darwin') throw new Error('macOS is required.'); + if (Number(process.versions.node.split('.')[0]) < 22) throw new Error('Node.js 22+ is required.'); + const app = prebuiltApp ? resolve(prebuiltApp) : defaultApp; + assertApp(app); + const previous = settings(); + if (previous && previous.app !== app && existsSync(previous.app)) throw new Error('Another Codex Pulse installation exists. Remove its local bridge and app before changing install locations.'); + if (prebuiltApp) { + if (!existsSync(app)) throw new Error('The downloaded app was not found.'); + if (resolve(root) !== join(app, 'Contents/Resources')) throw new Error('Run setup from the downloaded app itself.'); + run('/usr/bin/codesign', ['--verify', '--deep', '--strict', app]); + } else run('xcodebuild', ['-version']); + let binary = env.CODEX_BIN || codex(); + if (!isAbsolute(binary)) binary = run('/usr/bin/which', [binary]); + if (!isAbsolute(binary)) throw new Error('Codex was not found. Install Codex and sign in with ChatGPT first.'); + run(binary, ['--version']); + try { + const response = await fetcher('http://127.0.0.1:43187/health', { signal: AbortSignal.timeout(1500) }); + const data = await response.json(); + if (!response.ok || data.app !== 'codex-pulse' || !previous) throw new Error('Unmanaged service.'); + } catch (error) { + if (error.cause?.code !== 'ECONNREFUSED') throw new Error('Cannot safely use local port 43187. Stop any conflicting service and retry.'); + } + console.log('Preflight passed. No changes made.'); + return { app, previous, binary }; + } + function agentText(value) { + const variables = { + PATH: env.PATH || '/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin', + CODEX_BIN: value.codex, PULSE_SOCIAL: value.social ? '1' : '0', + ...(value.codexHome ? { CODEX_HOME: value.codexHome } : {}), + }; + return ` + + +Label${label} +ProgramArguments${xml(value.node)}${xml(join(support, 'bridge/server.mjs'))} +WorkingDirectory${xml(support)} +EnvironmentVariables${Object.entries(variables).map(([k, v]) => `${xml(k)}${xml(v)}`).join('')} +RunAtLoadKeepAliveThrottleInterval30 +\n`; + } + function saveAgent(value, beforeReload = () => {}) { + const oldPlist = existsSync(plist) ? readFileSync(plist) : null; + const oldMarker = existsSync(marker) ? readFileSync(marker) : null; + mkdirSync(dirname(plist), { recursive: true }); + mkdirSync(support, { recursive: true, mode: 0o700 }); + try { + run('/bin/launchctl', ['bootout', `${domain}/${label}`], true); + writeFileSync(plist, agentText(value), { mode: 0o600 }); + writeFileSync(marker, JSON.stringify(value, null, 2) + '\n', { mode: 0o600 }); + run('/bin/launchctl', ['bootstrap', domain, plist]); + } catch (error) { + beforeReload(); + if (oldPlist) writeFileSync(plist, oldPlist); else rmSync(plist, { force: true }); + if (oldMarker) writeFileSync(marker, oldMarker); else rmSync(marker, { force: true }); + if (oldPlist) run('/bin/launchctl', ['bootstrap', domain, plist], true); + throw error; + } + } + async function install(prebuiltApp) { + const { app, previous, binary } = await preflight(prebuiltApp); + const built = join(root, 'build/Codex Pulse.app'); + if (!prebuiltApp && !existsSync(built)) throw new Error('Run bash scripts/build.sh first.'); + mkdirSync(support, { recursive: true, mode: 0o700 }); + const backup = join(support, 'backups', `${Date.now()}-${process.pid}`); + mkdirSync(backup, { recursive: true }); + const bridge = join(support, 'bridge'); + const hadBridge = existsSync(bridge); + const hadApp = existsSync(app); + if (hadBridge) cpSync(bridge, join(backup, 'bridge'), { recursive: true }); + if (!prebuiltApp && hadApp) run('/usr/bin/ditto', [app, join(backup, 'Codex Pulse.app')]); + let rolledBack = false; + const rollback = () => { + if (rolledBack) return; + rolledBack = true; + rmSync(bridge, { recursive: true, force: true }); + if (hadBridge) cpSync(join(backup, 'bridge'), bridge, { recursive: true }); + if (!prebuiltApp) { + rmSync(app, { recursive: true, force: true }); + if (hadApp) run('/usr/bin/ditto', [join(backup, 'Codex Pulse.app'), app]); + } + }; + try { + if (!prebuiltApp) { + mkdirSync(dirname(app), { recursive: true }); + rmSync(app, { recursive: true, force: true }); + run('/usr/bin/ditto', ['--norsrc', '--noextattr', built, app]); + run('/usr/bin/codesign', ['--verify', '--deep', '--strict', app]); + } + rmSync(bridge, { recursive: true, force: true }); + cpSync(join(root, 'bridge'), bridge, { recursive: true }); + saveAgent({ version, appId, app, node, codex: binary, + codexHome: env.CODEX_HOME || previous?.codexHome, + social: previous?.social ?? (env.PULSE_SOCIAL === '1') }, rollback); + } catch (error) { rollback(); throw error; } + run('/usr/bin/pluginkit', ['-a', join(app, 'Contents/PlugIns/CodexPulseWidgetExtension.appex')], true); + if (!prebuiltApp) run('/usr/bin/open', [app], true); + console.log('Local bridge enabled at login. Add Codex Pulse using Edit Widgets.'); + } + function social(value) { + if (!['on', 'off'].includes(value)) throw new Error('Expected social on|off.'); + const previous = settings(); + if (!previous) throw new Error('Enable the local bridge first.'); + saveAgent({ ...previous, social: value === 'on' }); + console.log(value === 'on' ? 'Reset radar enabled. codex-reset.com receives normal HTTPS request metadata, never Codex credentials or quota data.' : 'Reset radar disabled.'); + } + function uninstall(removeApp) { + const previous = settings(); + if (!previous) throw new Error('No managed local bridge found. Nothing removed.'); + if (removeApp) assertApp(previous.app); + run('/bin/launchctl', ['bootout', `${domain}/${label}`], true); + const recovery = join(homeDir, '.Trash', `Codex-Pulse-${Date.now()}-${process.pid}`); + mkdirSync(recovery, { recursive: true }); + if (removeApp && existsSync(previous.app)) { + run('/usr/bin/pluginkit', ['-r', join(previous.app, 'Contents/PlugIns/CodexPulseWidgetExtension.appex')], true); + renameSync(previous.app, join(recovery, 'Codex Pulse.app')); + } + if (existsSync(plist)) renameSync(plist, join(recovery, `${label}.plist`)); + renameSync(support, join(recovery, 'Support')); + console.log('Managed local bridge moved to Trash. Codex login was not touched.' + (removeApp ? ' Remove the desktop widget separately.' : ' You can now move the app to Trash separately.')); + } + return { preflight, install, social, uninstall }; +} diff --git a/scripts/manage.mjs b/scripts/manage.mjs index 2d9b3f2..3adda56 100644 --- a/scripts/manage.mjs +++ b/scripts/manage.mjs @@ -1,120 +1,12 @@ -import { cpSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'; -import { homedir } from 'node:os'; -import { dirname, join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { spawnSync } from 'node:child_process'; -import { codexBinary } from '../bridge/codex.mjs'; - -const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const label = 'io.github.codexpulse.bridge'; -const appId = 'io.github.codexpulse.app'; -const homeDir = homedir(); -const support = join(homeDir, 'Library/Application Support/Codex Pulse OSS'); -const app = join(homeDir, 'Applications/Codex Pulse.app'); -const plist = join(homeDir, 'Library/LaunchAgents', `${label}.plist`); -const marker = join(support, 'install.json'); -const domain = `gui/${process.getuid?.()}`; -const xml = value => String(value).replace(/[<>&"']/g, c => ({ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[c])); -const run = (command, args, optional = false) => { - const result = spawnSync(command, args, { encoding: 'utf8' }); - if (result.status !== 0 && !optional) throw new Error(`${command} failed: ${result.stderr || result.error?.message || result.status}`); - return result.stdout?.trim(); -}; -function assertOwnedApp() { - if (!existsSync(app)) return; - if (run('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleIdentifier', join(app, 'Contents/Info.plist')]) !== appId) { - throw new Error('A different app already exists at ~/Applications/Codex Pulse.app. Move it aside yourself before installing.'); - } -} -async function preflight() { - if (process.platform !== 'darwin') throw new Error('macOS is required.'); - if (Number(process.versions.node.split('.')[0]) < 22) throw new Error('Node.js 22+ is required.'); - run('xcodebuild', ['-version']); - run(codexBinary(), ['--version']); - assertOwnedApp(); - if (existsSync(plist) && !existsSync(marker)) throw new Error('Unmanaged launch agent exists; refusing to overwrite it.'); - try { - const response = await fetch('http://127.0.0.1:43187/health', { signal: AbortSignal.timeout(1000) }); - const data = await response.json(); - if (data.app !== 'codex-pulse' || !existsSync(marker)) throw new Error('Port 43187 is already in use. Stop that service first.'); - } catch (error) { - if (error.cause?.code !== 'ECONNREFUSED') throw error; - } - console.log('Preflight passed: macOS, Xcode, Node and Codex detected. No changes made.'); -} -function saveAgent(settings) { - mkdirSync(dirname(plist), { recursive: true }); - const env = { - PATH: process.env.PATH || '/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin', - CODEX_BIN: settings.codex, - PULSE_SOCIAL: settings.social ? '1' : '0', - ...(settings.codexHome ? { CODEX_HOME: settings.codexHome } : {}), - }; - writeFileSync(plist, ` - - -Label${label} -ProgramArguments${xml(settings.node)}${xml(join(support, 'bridge/server.mjs'))} -WorkingDirectory${xml(support)} -EnvironmentVariables${Object.entries(env).map(([k, v]) => `${xml(k)}${xml(v)}`).join('')} -RunAtLoadKeepAliveThrottleInterval30 -`, { mode: 0o600 }); - writeFileSync(marker, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 }); - run('launchctl', ['bootout', `${domain}/${label}`], true); - run('launchctl', ['bootstrap', domain, plist]); -} -async function install() { - await preflight(); - const built = join(root, 'build/Codex Pulse.app'); - if (!existsSync(built)) throw new Error('Run bash scripts/build.sh first.'); - mkdirSync(support, { recursive: true, mode: 0o700 }); - mkdirSync(dirname(app), { recursive: true }); - const previous = existsSync(marker) ? JSON.parse(readFileSync(marker, 'utf8')) : null; - if (existsSync(app)) { - const backup = join(support, 'backups', String(Date.now())); - mkdirSync(backup, { recursive: true }); - run('ditto', ['--norsrc', '--noextattr', app, join(backup, 'Codex Pulse.app')]); - } - run('ditto', ['--norsrc', '--noextattr', built, app]); - // iCloud source folders can attach Finder metadata. Strip only our installed build's metadata. - run('xattr', ['-cr', app]); - run('codesign', ['--verify', '--deep', '--strict', app]); - cpSync(join(root, 'bridge'), join(support, 'bridge'), { recursive: true }); - const binary = codexBinary(); - const resolved = binary === 'codex' ? run('/usr/bin/which', ['codex']) : binary; - saveAgent({ version: '0.1.0', appId, app, node: process.execPath, codex: resolved, codexHome: process.env.CODEX_HOME || previous?.codexHome, social: previous?.social ?? (process.env.PULSE_SOCIAL === '1') }); - run('pluginkit', ['-a', join(app, 'Contents/PlugIns/CodexPulseWidgetExtension.appex')]); - run('open', [app]); - console.log('Installed. Right-click desktop → Edit Widgets → Codex Pulse. The bridge starts at login.'); -} -function social(value) { - if (!['on', 'off'].includes(value)) throw new Error('Usage: bash scripts/social.sh on|off'); - if (!existsSync(marker)) throw new Error('Install first.'); - const settings = JSON.parse(readFileSync(marker, 'utf8')); - if (settings.appId !== appId) throw new Error('Unknown installation.'); - saveAgent({ ...settings, social: value === 'on' }); - run('open', ['codexpulse://refresh']); - console.log(`Optional third-party feed ${value}. ${value === 'on' ? 'codex-reset.com receives normal HTTPS requests (including your IP), never your quota or Codex credentials.' : ''}`); -} -function uninstall() { - if (!existsSync(marker)) throw new Error('No managed installation found. Nothing removed.'); - const settings = JSON.parse(readFileSync(marker, 'utf8')); - if (settings.appId !== appId) throw new Error('Unknown installation. Nothing removed.'); - assertOwnedApp(); - run('launchctl', ['bootout', `${domain}/${label}`], true); - if (existsSync(app)) run('pluginkit', ['-r', join(app, 'Contents/PlugIns/CodexPulseWidgetExtension.appex')], true); - const recovery = join(homeDir, '.Trash', `Codex-Pulse-${Date.now()}`); - mkdirSync(recovery, { recursive: true }); - if (existsSync(app)) renameSync(app, join(recovery, 'Codex Pulse.app')); - if (existsSync(plist)) renameSync(plist, join(recovery, `${label}.plist`)); - renameSync(support, join(recovery, 'Support')); - console.log(`App, bridge and launch agent moved to Trash: ${recovery}. Codex credentials were not touched. Remove the widget from your desktop separately.`); -} +import { createInstaller } from './installer.mjs'; try { - const action = process.argv[2]; - if (action === 'preflight') await preflight(); - else if (action === 'install') await install(); - else if (action === 'social') social(process.argv[3]); - else if (action === 'uninstall') uninstall(); - else throw new Error('Expected preflight, install, social or uninstall.'); + const installer = createInstaller(); + const [action, ...args] = process.argv.slice(2); + if (action === 'preflight' && !args.length) await installer.preflight(); + else if (action === 'install' && !args.length) await installer.install(); + else if (action === 'install-prebuilt' && args.length === 2 && args[0] === '--app') await installer.install(args[1]); + else if (action === 'social' && args.length === 1) installer.social(args[0]); + else if (action === 'uninstall' && !args.length) installer.uninstall(true); + else if (action === 'remove-bridge' && !args.length) installer.uninstall(false); + else throw new Error('Expected preflight, install, install-prebuilt --app , social on|off, remove-bridge or uninstall.'); } catch (error) { console.error(error.message); process.exitCode = 1; } diff --git a/scripts/node-runtime.entitlements.plist b/scripts/node-runtime.entitlements.plist new file mode 100644 index 0000000..e8d5435 --- /dev/null +++ b/scripts/node-runtime.entitlements.plist @@ -0,0 +1,6 @@ + + + + com.apple.security.cs.allow-jit + com.apple.security.cs.allow-unsigned-executable-memory + diff --git a/scripts/package-release.sh b/scripts/package-release.sh new file mode 100755 index 0000000..757bcb7 --- /dev/null +++ b/scripts/package-release.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)"; SIGNED=0 +if [ "${1:-}" = '--signed' ]; then SIGNED=1; shift; fi +[ "$#" -eq 0 ] || { echo 'Usage: bash scripts/package-release.sh [--signed]' >&2; exit 2; } +VERSION="$(cd "$ROOT" && node -p "require('./package.json').version")" +[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Invalid package version: $VERSION" >&2; exit 1; } +SUFFIX='unsigned'; [ "$SIGNED" -eq 0 ] || SUFFIX='signed-notarized' +NAME="Codex-Pulse-$VERSION-universal-$SUFFIX"; DIST="$ROOT/dist"; APP="$ROOT/build/Codex Pulse.app" +ZIP="$DIST/$NAME.zip"; DMG="$DIST/$NAME.dmg" +[ "$SIGNED" -eq 0 ] && bash "$ROOT/scripts/build.sh" --bundle-runtime +bash "$ROOT/scripts/verify-release.sh" --app "$APP" +[ "$SIGNED" -eq 0 ] && "$APP/Contents/Resources/runtime/node" --test "$ROOT"/tests/*.test.mjs +if [ "$SIGNED" -eq 1 ]; then spctl --assess --type execute --verbose=4 "$APP"; xcrun stapler validate "$APP"; fi +mkdir -p "$DIST"; rm -f "$ZIP" "$DMG" +STAGE="$(mktemp -d "${TMPDIR:-/tmp}/codex-pulse-dmg-stage.XXXXXX")"; trap 'rm -rf "$STAGE"' EXIT +ditto --norsrc --noextattr "$APP" "$STAGE/Codex Pulse.app"; ln -s /Applications "$STAGE/Applications" +ditto -c -k --sequesterRsrc --keepParent "$APP" "$ZIP" +hdiutil create -quiet -volname "Codex Pulse $VERSION" -srcfolder "$STAGE" -format UDZO -ov "$DMG" +bash "$ROOT/scripts/verify-release.sh" --app "$APP" --zip "$ZIP" --dmg "$DMG" +(cd "$DIST" && shasum -a 256 "$NAME.dmg" "$NAME.zip" > SHA256SUMS.txt) +echo "Packaged $SUFFIX artifacts: $ZIP and $DMG" diff --git a/scripts/sign-and-notarize.sh b/scripts/sign-and-notarize.sh new file mode 100755 index 0000000..1dbace0 --- /dev/null +++ b/scripts/sign-and-notarize.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)"; APP="${1:-$ROOT/build/Codex Pulse.app}" +for key in DEVELOPER_ID_APPLICATION APPLE_ID APPLE_APP_SPECIFIC_PASSWORD APPLE_TEAM_ID; do [ -n "${!key:-}" ] || { echo "Missing required environment variable: $key" >&2; exit 1; }; done +[[ "$DEVELOPER_ID_APPLICATION" == 'Developer ID Application:'* ]] || { echo 'DEVELOPER_ID_APPLICATION must name a Developer ID Application identity.' >&2; exit 1; } +[ -d "$APP" ] || { echo "Missing app: $APP" >&2; exit 1; } +codesign --force --options runtime --timestamp --sign "$DEVELOPER_ID_APPLICATION" --entitlements "$ROOT/scripts/node-runtime.entitlements.plist" "$APP/Contents/Resources/runtime/node" +codesign --force --options runtime --timestamp --sign "$DEVELOPER_ID_APPLICATION" --entitlements "$ROOT/native/CodexPulseWidget/CodexPulseWidget.entitlements" "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex" +codesign --force --options runtime --timestamp --sign "$DEVELOPER_ID_APPLICATION" --entitlements "$ROOT/native/CodexPulse/CodexPulse.entitlements" "$APP" +codesign --verify --deep --strict --verbose=2 "$APP" +WORK="$(mktemp -d "${TMPDIR:-/tmp}/codex-pulse-notarize.XXXXXX")"; ARCHIVE="$WORK/archive.zip"; trap 'rm -rf "$WORK"' EXIT +ditto -c -k --sequesterRsrc --keepParent "$APP" "$ARCHIVE" +xcrun notarytool submit "$ARCHIVE" --apple-id "$APPLE_ID" --password "$APPLE_APP_SPECIFIC_PASSWORD" --team-id "$APPLE_TEAM_ID" --wait +xcrun stapler staple "$APP"; codesign --verify --deep --strict "$APP"; spctl --assess --type execute --verbose=4 "$APP" +echo 'Developer ID signing and notarization passed. Run bash scripts/package-release.sh --signed to package this stapled app without rebuilding it.' diff --git a/scripts/test-native.sh b/scripts/test-native.sh index 6b92e7c..089a776 100644 --- a/scripts/test-native.sh +++ b/scripts/test-native.sh @@ -8,4 +8,9 @@ xcrun swiftc -D LAYOUT_PREVIEW -parse-as-library \ export PULSE_PREVIEW_DIR="${PULSE_PREVIEW_DIR:-$STAGE}" "$STAGE/preview" -AppleLanguages '(en)' "$STAGE/preview" -AppleLanguages '(zh-Hans)' +xcrun swiftc -D SETUP_PREVIEW -parse-as-library \ + "$ROOT/native/CodexPulse/CodexPulseApp.swift" "$ROOT/tests/SetupPreview.swift" \ + -o "$STAGE/setup-preview" +PULSE_SETUP_PREVIEW="$PULSE_PREVIEW_DIR/setup-en.png" "$STAGE/setup-preview" -AppleLanguages '(en)' +PULSE_SETUP_PREVIEW="$PULSE_PREVIEW_DIR/setup-zh.png" "$STAGE/setup-preview" -AppleLanguages '(zh-Hans)' echo "Preview output: $PULSE_PREVIEW_DIR" diff --git a/scripts/verify-release.sh b/scripts/verify-release.sh new file mode 100755 index 0000000..92fc6d5 --- /dev/null +++ b/scripts/verify-release.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)"; APP="$ROOT/build/Codex Pulse.app"; ZIP=''; DMG='' +while [ "$#" -gt 0 ]; do case "$1" in --app) APP="${2:-}"; shift 2 ;; --zip) ZIP="${2:-}"; shift 2 ;; --dmg) DMG="${2:-}"; shift 2 ;; *) echo 'Usage: bash scripts/verify-release.sh [--app APP] [--zip ZIP] [--dmg DMG]' >&2; exit 2 ;; esac; done +VERSION="$(cd "$ROOT" && node -p "require('./package.json').version")" +entitlement_is_true() { + local binary="$1" key="$2" plist value + plist="$(mktemp "${TMPDIR:-/tmp}/codex-pulse-entitlements.XXXXXX")" + codesign -d --entitlements :- "$binary" > "$plist" 2>/dev/null + value="$(/usr/libexec/PlistBuddy -c "Print :$key" "$plist")" + rm -f "$plist" + [ "$value" = true ] +} +verify_app() { + local candidate="$1" plist="$1/Contents/Info.plist" runtime="$1/Contents/Resources/runtime/node" widget widget_executable + [ -d "$candidate" ] || { echo "Missing app: $candidate" >&2; return 1; } + [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$plist")" = "$VERSION" ] + widget="$candidate/Contents/PlugIns/CodexPulseWidgetExtension.appex" + [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$widget/Contents/Info.plist")" = "$VERSION" ] + codesign --verify --deep --strict "$candidate"; lipo -verify_arch arm64 x86_64 "$candidate/Contents/MacOS/Codex Pulse" + widget_executable="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$widget/Contents/Info.plist")" + lipo -verify_arch arm64 x86_64 "$widget/Contents/MacOS/$widget_executable" + for path in "$candidate/Contents/Resources/bridge" "$candidate/Contents/Resources/scripts/manage.mjs" "$candidate/Contents/Resources/scripts/installer.mjs" "$candidate/Contents/Resources/package.json" "$candidate/Contents/Resources/LICENSE.txt" "$runtime" "$candidate/Contents/Resources/runtime/NODE-LICENSE.txt"; do [ -e "$path" ] || { echo "Missing bundled resource: $path" >&2; return 1; }; done + lipo -verify_arch arm64 x86_64 "$runtime"; "$runtime" --version | grep -qx 'v22.23.2' + entitlement_is_true "$runtime" 'com.apple.security.cs.allow-jit' + entitlement_is_true "$widget" 'com.apple.security.app-sandbox' + entitlement_is_true "$widget" 'com.apple.security.network.client' +} +verify_app "$APP" +if [ -n "$ZIP" ]; then + ZIP_STAGE="$(mktemp -d "${TMPDIR:-/tmp}/codex-pulse-zip.XXXXXX")"; trap 'rm -rf "$ZIP_STAGE"' EXIT + ditto -x -k "$ZIP" "$ZIP_STAGE"; verify_app "$ZIP_STAGE/Codex Pulse.app"; rm -rf "$ZIP_STAGE"; trap - EXIT +fi +if [ -n "$DMG" ]; then + MOUNT="$(mktemp -d "${TMPDIR:-/tmp}/codex-pulse-dmg.XXXXXX")"; trap 'hdiutil detach "$MOUNT" -quiet 2>/dev/null || true; rmdir "$MOUNT" 2>/dev/null || true' EXIT + hdiutil attach -quiet -readonly -nobrowse -mountpoint "$MOUNT" "$DMG"; verify_app "$MOUNT/Codex Pulse.app"; [ "$(readlink "$MOUNT/Applications")" = '/Applications' ]; hdiutil detach "$MOUNT" -quiet; rmdir "$MOUNT"; trap - EXIT +fi +echo 'Release verification passed.' diff --git a/tests/SetupPreview.swift b/tests/SetupPreview.swift new file mode 100644 index 0000000..28cfd6d --- /dev/null +++ b/tests/SetupPreview.swift @@ -0,0 +1,19 @@ +import AppKit +import SwiftUI + +@main +struct SetupPreview { + @MainActor static func main() throws { + let renderer = ImageRenderer(content: ContentView().frame(width: 570, height: 510).environment(\.colorScheme, .dark)) + renderer.scale = 2 + guard let image = renderer.nsImage, + let tiff = image.tiffRepresentation, + let bitmap = NSBitmapImageRep(data: tiff), + let data = bitmap.representation(using: .png, properties: [:]) else { + fatalError("Setup preview rendering failed") + } + let file = ProcessInfo.processInfo.environment["PULSE_SETUP_PREVIEW"] ?? "/tmp/codex-pulse-setup.png" + try data.write(to: URL(fileURLWithPath: file)) + print("Setup preview rendered") + } +} diff --git a/tests/installer.test.mjs b/tests/installer.test.mjs new file mode 100644 index 0000000..b7e7fc5 --- /dev/null +++ b/tests/installer.test.mjs @@ -0,0 +1,157 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync, rmSync, cpSync, readdirSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { createInstaller, xml } from '../scripts/installer.mjs'; + +function fixture(t, overrides = {}) { + const homeDir = mkdtempSync(join(tmpdir(), 'pulse-installer-')); + t.after(() => rmSync(homeDir, { recursive: true, force: true })); + const app = join(homeDir, 'Applications/Codex Pulse.app'); + const root = join(app, 'Contents/Resources'); + const support = join(homeDir, 'Library/Application Support/Codex Pulse OSS'); + const plist = join(homeDir, 'Library/LaunchAgents/io.github.codexpulse.bridge.plist'); + const marker = join(support, 'install.json'); + mkdirSync(join(root, 'bridge'), { recursive: true }); + writeFileSync(join(root, 'bridge/server.mjs'), 'fixture-new'); + writeFileSync(join(root, 'package.json'), '{"version":"0.1.1"}'); + const calls = []; + const state = { failBootstrap: false, appId: 'io.github.codexpulse.app', busy: false }; + const run = (command, args, optional) => { + calls.push([command, args, optional]); + if (command.endsWith('PlistBuddy')) return state.appId; + if (command.endsWith('which')) return '/fixture/codex'; + if (command.endsWith('ditto')) { cpSync(args.at(-2), args.at(-1), { recursive: true }); return ''; } + if (command.endsWith('launchctl') && args[0] === 'bootstrap' && state.failBootstrap && !optional) throw new Error('bootstrap failed'); + return ''; + }; + const fetcher = async () => { + if (state.busy) return { ok: true, json: async () => ({ app: 'codex-pulse' }) }; + throw Object.assign(new Error('offline'), { cause: { code: 'ECONNREFUSED' } }); + }; + const config = { root, homeDir, run, fetcher, platform: 'darwin', env: { PATH: '/fixture/bin', CODEX_BIN: '/fixture/codex' }, node: join(root, 'runtime/node'), uid: 501, ...overrides }; + return { app, root, support, plist, marker, calls, state, config, installer: createInstaller(config) }; +} + +test('prebuilt installation needs neither Xcode nor a source checkout and defaults radar off', async t => { + const f = fixture(t); + await f.installer.install(f.app); + assert.ok(!f.calls.some(([command]) => command === 'xcodebuild')); + assert.ok(f.calls.some(([command]) => command.endsWith('codesign'))); + const value = JSON.parse(readFileSync(f.marker, 'utf8')); + assert.equal(value.app, f.app); + assert.equal(value.version, '0.1.1'); + assert.equal(value.social, false); + assert.equal(value.node, join(f.root, 'runtime/node')); + assert.equal(readFileSync(join(f.support, 'bridge/server.mjs'), 'utf8'), 'fixture-new'); + assert.ok(readFileSync(f.plist, 'utf8').includes('RunAtLoad')); +}); + +test('source preflight still checks Xcode but creates no files', async t => { + const f = fixture(t); + await f.installer.preflight(); + assert.ok(f.calls.some(([command]) => command === 'xcodebuild')); + assert.ok(!existsSync(f.support)); + assert.ok(!existsSync(f.plist)); +}); + +test('refuses setup from mounted disk images or downloads', async t => { + const f = fixture(t); + await assert.rejects(f.installer.install('/Volumes/Codex Pulse/Codex Pulse.app'), /Move Codex Pulse/); + assert.ok(!existsSync(f.plist)); +}); + +test('refuses unrelated same-name applications without changes', async t => { + const f = fixture(t); + f.state.appId = 'org.someone.else'; + await assert.rejects(f.installer.install(f.app), /different app/); + assert.ok(!existsSync(f.support)); +}); + +test('refuses existing unmanaged LaunchAgents', async t => { + const f = fixture(t); + mkdirSync(join(f.config.homeDir, 'Library/LaunchAgents'), { recursive: true }); + writeFileSync(f.plist, 'unmanaged'); + await assert.rejects(f.installer.install(f.app), /Unmanaged launch agent/); + assert.equal(readFileSync(f.plist, 'utf8'), 'unmanaged'); +}); + +test('refuses an unmanaged server even if it claims the correct application name', async t => { + const f = fixture(t); + f.state.busy = true; + await assert.rejects(f.installer.install(f.app), /port 43187/); + assert.ok(!existsSync(f.support)); +}); + +test('repair preserves custom Codex home and explicit radar choice', async t => { + const f = fixture(t, { env: { CODEX_BIN: '/fixture/codex', CODEX_HOME: '/custom/codex & data' } }); + await f.installer.install(f.app); + f.installer.social('on'); + const next = createInstaller({ ...f.config, env: { CODEX_BIN: '/fixture/codex' } }); + await next.install(f.app); + const value = JSON.parse(readFileSync(f.marker, 'utf8')); + assert.equal(value.codexHome, '/custom/codex & data'); + assert.equal(value.social, true); + assert.ok(readFileSync(f.plist, 'utf8').includes('/custom/codex & data')); +}); + +test('failed first bootstrap removes new settings and bridge', async t => { + const f = fixture(t); + f.state.failBootstrap = true; + await assert.rejects(f.installer.install(f.app), /bootstrap failed/); + assert.ok(!existsSync(f.marker)); + assert.ok(!existsSync(f.plist)); + assert.ok(!existsSync(join(f.support, 'bridge'))); + assert.ok(existsSync(f.app)); +}); + +test('failed repair restores previous bridge and settings before restarting it', async t => { + const f = fixture(t); + await f.installer.install(f.app); + const previousPlist = readFileSync(f.plist, 'utf8'); + const previousMarker = readFileSync(f.marker, 'utf8'); + writeFileSync(join(f.root, 'bridge/server.mjs'), 'fixture-update'); + f.state.failBootstrap = true; + await assert.rejects(f.installer.install(f.app), /bootstrap failed/); + assert.equal(readFileSync(join(f.support, 'bridge/server.mjs'), 'utf8'), 'fixture-new'); + assert.equal(readFileSync(f.plist, 'utf8'), previousPlist); + assert.equal(readFileSync(f.marker, 'utf8'), previousMarker); + assert.ok(f.calls.some(([command, args, optional]) => command.endsWith('launchctl') && args[0] === 'bootstrap' && optional)); +}); + +test('failed radar change rolls back the old option', async t => { + const f = fixture(t); + await f.installer.install(f.app); + f.state.failBootstrap = true; + assert.throws(() => f.installer.social('on'), /bootstrap failed/); + assert.equal(JSON.parse(readFileSync(f.marker, 'utf8')).social, false); +}); + +test('bridge removal retains app and Codex login, moves only managed files to Trash', async t => { + const f = fixture(t); + const login = join(f.config.homeDir, '.codex/auth.json'); + mkdirSync(join(f.config.homeDir, '.codex')); + writeFileSync(login, 'synthetic-login'); + await f.installer.install(f.app); + f.installer.uninstall(false); + assert.ok(existsSync(f.app)); + assert.equal(readFileSync(login, 'utf8'), 'synthetic-login'); + assert.ok(!existsSync(f.plist)); + assert.ok(!existsSync(f.support)); + const trash = join(f.config.homeDir, '.Trash'); + assert.ok(existsSync(join(trash, readdirSync(trash)[0], 'Support/install.json'))); +}); + +test('modified managed plist is protected from radar or removal actions', async t => { + const f = fixture(t); + await f.installer.install(f.app); + writeFileSync(f.plist, 'another service'); + assert.throws(() => f.installer.uninstall(false), /does not match/); + assert.throws(() => f.installer.social('on'), /does not match/); + assert.equal(readFileSync(f.plist, 'utf8'), 'another service'); +}); + +test('paths are safely XML escaped without invoking a shell', () => { + assert.equal(xml('A<&>"\''), 'A<&>"''); +}); From 519c297630b7288d2c26c18a6c36f08a41680c67 Mon Sep 17 00:00:00 2001 From: Mat <158223041@qq.com> Date: Mon, 31 Aug 2026 23:11:24 +0800 Subject: [PATCH 2/5] Fix lipo architecture verification argument order --- scripts/build.sh | 6 +++--- scripts/fetch-node-runtime.sh | 2 +- scripts/verify-release.sh | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 79fd274..10cc639 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -31,12 +31,12 @@ if [ -f "$APP/Contents/Resources/runtime/node" ]; then codesign --force --timest codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/native/CodexPulseWidget/CodexPulseWidget.entitlements" "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex" codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/native/CodexPulse/CodexPulse.entitlements" "$APP" codesign --verify --deep --strict "$APP" -lipo -verify_arch arm64 x86_64 "$APP/Contents/MacOS/Codex Pulse" +lipo "$APP/Contents/MacOS/Codex Pulse" -verify_arch arm64 x86_64 WIDGET_EXECUTABLE="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/Info.plist")" -lipo -verify_arch arm64 x86_64 "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/MacOS/$WIDGET_EXECUTABLE" +lipo "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/MacOS/$WIDGET_EXECUTABLE" -verify_arch arm64 x86_64 [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist")" = "$VERSION" ] [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/Info.plist")" = "$VERSION" ] -[ "$BUNDLE_RUNTIME" -eq 0 ] || lipo -verify_arch arm64 x86_64 "$APP/Contents/Resources/runtime/node" +[ "$BUNDLE_RUNTIME" -eq 0 ] || lipo "$APP/Contents/Resources/runtime/node" -verify_arch arm64 x86_64 mkdir -p "$ROOT/build" rm -rf "$ROOT/build/Codex Pulse.app" ditto --norsrc --noextattr "$APP" "$ROOT/build/Codex Pulse.app" diff --git a/scripts/fetch-node-runtime.sh b/scripts/fetch-node-runtime.sh index 2d1d4e0..24c14a1 100755 --- a/scripts/fetch-node-runtime.sh +++ b/scripts/fetch-node-runtime.sh @@ -16,7 +16,7 @@ tar -xzf "$CACHE/node-v$NODE_VERSION-darwin-arm64.tar.gz" -C "$WORK"; tar -xzf " mkdir -p "$OUTPUT" lipo -create "$WORK/node-v$NODE_VERSION-darwin-arm64/bin/node" "$WORK/node-v$NODE_VERSION-darwin-x64/bin/node" -output "$OUTPUT/node" chmod 755 "$OUTPUT/node"; cp "$WORK/node-v$NODE_VERSION-darwin-arm64/LICENSE" "$OUTPUT/NODE-LICENSE.txt" -lipo -verify_arch arm64 x86_64 "$OUTPUT/node" +lipo "$OUTPUT/node" -verify_arch arm64 x86_64 codesign --force --timestamp=none --options runtime --sign - --entitlements "$ROOT/scripts/node-runtime.entitlements.plist" "$OUTPUT/node" [ "$("$OUTPUT/node" --version)" = "v$NODE_VERSION" ] echo "Bundled official Node.js v$NODE_VERSION runtime at $OUTPUT/node" diff --git a/scripts/verify-release.sh b/scripts/verify-release.sh index 92fc6d5..2272637 100755 --- a/scripts/verify-release.sh +++ b/scripts/verify-release.sh @@ -17,11 +17,11 @@ verify_app() { [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$plist")" = "$VERSION" ] widget="$candidate/Contents/PlugIns/CodexPulseWidgetExtension.appex" [ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$widget/Contents/Info.plist")" = "$VERSION" ] - codesign --verify --deep --strict "$candidate"; lipo -verify_arch arm64 x86_64 "$candidate/Contents/MacOS/Codex Pulse" + codesign --verify --deep --strict "$candidate"; lipo "$candidate/Contents/MacOS/Codex Pulse" -verify_arch arm64 x86_64 widget_executable="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$widget/Contents/Info.plist")" - lipo -verify_arch arm64 x86_64 "$widget/Contents/MacOS/$widget_executable" + lipo "$widget/Contents/MacOS/$widget_executable" -verify_arch arm64 x86_64 for path in "$candidate/Contents/Resources/bridge" "$candidate/Contents/Resources/scripts/manage.mjs" "$candidate/Contents/Resources/scripts/installer.mjs" "$candidate/Contents/Resources/package.json" "$candidate/Contents/Resources/LICENSE.txt" "$runtime" "$candidate/Contents/Resources/runtime/NODE-LICENSE.txt"; do [ -e "$path" ] || { echo "Missing bundled resource: $path" >&2; return 1; }; done - lipo -verify_arch arm64 x86_64 "$runtime"; "$runtime" --version | grep -qx 'v22.23.2' + lipo "$runtime" -verify_arch arm64 x86_64; "$runtime" --version | grep -qx 'v22.23.2' entitlement_is_true "$runtime" 'com.apple.security.cs.allow-jit' entitlement_is_true "$widget" 'com.apple.security.app-sandbox' entitlement_is_true "$widget" 'com.apple.security.network.client' From e97f5595d177edc1214a8211a4a1ba7f41c55024 Mon Sep 17 00:00:00 2001 From: Mat <158223041@qq.com> Date: Mon, 31 Aug 2026 23:16:12 +0800 Subject: [PATCH 3/5] Align download guidance and stabilize subprocess test startup --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/release.yml | 2 ++ CHANGELOG.md | 2 +- bridge/social.mjs | 2 +- .../CodexPulseWidget/CodexPulseWidget.swift | 2 +- tests/bridge.test.mjs | 19 ++++++++++++++++--- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 82126ee..13f4775 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -9,7 +9,7 @@ body: id: environment attributes: label: Environment - description: macOS, Apple Silicon/Intel, Xcode, Node and Codex versions + description: macOS, Apple Silicon/Intel, app version, download or source install, Codex version (Xcode/Node versions only for source installs) validations: required: true - type: textarea diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a755f17..47aefaa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,8 @@ jobs: [ "$TAG" = "v$VERSION" ] || { echo "Tag $TAG does not match package version $VERSION" >&2; exit 1; } [ "$TAG" = "$(git describe --exact-match --tags HEAD)" ] || { echo 'Workflow ref does not point at the checked-out tag.' >&2; exit 1; } - run: bash scripts/package-release.sh + - name: Test the shipped Node runtime + run: '"build/Codex Pulse.app/Contents/Resources/runtime/node" --test tests/*.test.mjs' - name: Create draft prerelease env: GH_TOKEN: ${{ github.token }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 679889a..038c4ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - Universal macOS 14+ DMG and ZIP distribution with bundled Node.js and local bridge. - GUI actions: **Enable/repair bridge**, **Remove local bridge**, and explicit reset radar enable/disable controls (radar off by default). - Requires Codex CLI or desktop app already signed in with a ChatGPT account. -- AD HOC signed and unnotarized; prerelease only. Intel installation, clean-machine support, and full release verification remain pending. +- Ad-hoc signed and unnotarized; prerelease only. Intel execution and clean-machine installation remain unverified. ## 0.1.0 — source preview diff --git a/bridge/social.mjs b/bridge/social.mjs index 4b48462..24756cc 100644 --- a/bridge/social.mjs +++ b/bridge/social.mjs @@ -30,7 +30,7 @@ export function filterSignals(data, now = Date.now()) { export async function fetchSocial() { const response = await fetch(FEED_URL, { - headers: { Accept: 'application/json', 'User-Agent': 'Codex-Pulse/0.1.0' }, + headers: { Accept: 'application/json', 'User-Agent': 'Codex-Pulse/0.1.1' }, signal: AbortSignal.timeout(10000), redirect: 'error', }); if (!response.ok) throw new Error('Public feed unavailable.'); diff --git a/native/CodexPulseWidget/CodexPulseWidget.swift b/native/CodexPulseWidget/CodexPulseWidget.swift index 73651f5..ec5f3c3 100644 --- a/native/CodexPulseWidget/CodexPulseWidget.swift +++ b/native/CodexPulseWidget/CodexPulseWidget.swift @@ -107,7 +107,7 @@ enum PulseLoader { if !feed.enabled { payload.signalLabel = PulseText.t("Radar off", "雷达已关闭") payload.signalText = PulseText.t("Optional reset radar. Your quota monitor works without it.", "可选重置信号雷达。不影响额度监控。") - payload.signalReason = PulseText.t("Enable with: bash scripts/social.sh on", "启用:bash scripts/social.sh on") + payload.signalReason = PulseText.t("Enable reset radar in the Codex Pulse app.", "在 Codex Pulse 应用中开启重置雷达。") } else if let signal = feed.signals?.first { payload.signalLabel = feed.stale ? PulseText.t("Radar cached", "雷达缓存") : (signal.resetAnalysis.level == "reported" ? PulseText.t("Reset reported", "动态称已重置") : PulseText.t("Possible reset", "可能涉及重置")) payload.signalText = signal.text diff --git a/tests/bridge.test.mjs b/tests/bridge.test.mjs index f8f7cf7..cb301e5 100644 --- a/tests/bridge.test.mjs +++ b/tests/bridge.test.mjs @@ -2,7 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { once } from 'node:events'; import { request as httpRequest } from 'node:http'; -import { mkdtempSync, writeFileSync } from 'node:fs'; +import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { CodexBridge, normalizeUsage } from '../bridge/codex.mjs'; @@ -112,8 +112,9 @@ test('bridge permits only initialization and read, and handles a real stdio hand const rl = require('node:readline').createInterface({input:process.stdin}); rl.on('line', line => { const m=JSON.parse(line); if(m.id) process.stdout.write(JSON.stringify({id:m.id,result:m.method==='initialize'?{}:{rateLimits:{primary:{usedPercent:7,windowDurationMins:300,resetsAt:1900000000}}}})+'\\n'); }); `, { mode: 0o700 }); - const bridge = new CodexBridge({ binary: fixture, timeout: 1000 }); - t.after(() => bridge.stop()); + // Allow cold process startup under concurrent builds; timeout behavior is tested separately. + const bridge = new CodexBridge({ binary: fixture, timeout: 5000 }); + t.after(() => { bridge.stop(); rmSync(folder, { recursive: true, force: true }); }); await assert.rejects(bridge.send('thread/start'), /not allowed/); assert.equal((await bridge.rateLimits()).rateLimits.primary.usedPercent, 7); }); @@ -123,3 +124,15 @@ test('missing Codex binary rejects cleanly and allows a later retry', async () = await assert.rejects(bridge.rateLimits()); bridge.stop(); }); + +test('a silent Codex process times out, stops and can be retried', async t => { + const folder = mkdtempSync(join(tmpdir(), 'pulse-timeout-')); + const fixture = join(folder, 'silent-codex'); + writeFileSync(fixture, '#!/usr/bin/env node\nprocess.stdin.resume();\n', { mode: 0o700 }); + const bridge = new CodexBridge({ binary: fixture, timeout: 100 }); + t.after(() => { bridge.stop(); rmSync(folder, { recursive: true, force: true }); }); + await assert.rejects(bridge.rateLimits(), /timed out/); + assert.equal(bridge.child, null); + await assert.rejects(bridge.rateLimits(), /timed out/); + assert.equal(bridge.child, null); +}); From 908bfefb9a25789f15641c08b7f2aea6ef7dab63 Mon Sep 17 00:00:00 2001 From: Mat <158223041@qq.com> Date: Mon, 31 Aug 2026 23:18:40 +0800 Subject: [PATCH 4/5] Validate clean signatures after copying local build output --- scripts/build.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/build.sh b/scripts/build.sh index 10cc639..5cf2292 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -40,5 +40,9 @@ lipo "$APP/Contents/PlugIns/CodexPulseWidgetExtension.appex/Contents/MacOS/$WIDG mkdir -p "$ROOT/build" rm -rf "$ROOT/build/Codex Pulse.app" ditto --norsrc --noextattr "$APP" "$ROOT/build/Codex Pulse.app" +# File-provider folders can add Finder metadata during copy. This is only our +# freshly generated build output, never a downloaded app or a user's installation. +xattr -cr "$ROOT/build/Codex Pulse.app" +codesign --verify --deep --strict "$ROOT/build/Codex Pulse.app" if [ "$BUNDLE_RUNTIME" -eq 1 ]; then echo "Built universal ad-hoc preview with bundled Node: $ROOT/build/Codex Pulse.app"; else echo "Built universal ad-hoc source preview: $ROOT/build/Codex Pulse.app"; fi echo 'This build is not Developer ID signed or notarized.' From 9452e60ff7887c63393c2c40a46c4262b800251e Mon Sep 17 00:00:00 2001 From: Mat <158223041@qq.com> Date: Tue, 1 Sep 2026 22:13:08 +0800 Subject: [PATCH 5/5] Add CP menu usage meter --- README.md | 1 + README.zh-CN.md | 1 + docs/INSTALL.md | 2 + native/CodexPulse/CodexPulseApp.swift | 122 +++++++++++++++++++++++++- tests/SetupPreview.swift | 13 +++ 5 files changed, 138 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e831f53..009acab 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ I wanted to glance at my desktop and know two things: **how much have I used, an Codex Pulse keeps the answer small, readable, and on the desktop. - **Used, not remaining:** 5-hour and weekly percentages side by side. +- **CP menu meter:** C represents 5-hour usage and P represents weekly usage; each shifts from green at 0% through yellow to red at 100%. Missing or cached values are gray. - **Two reset clocks:** each quota has its own countdown, including days. - **Native SwiftUI + WidgetKit:** small and medium widgets; English and Simplified Chinese follow your system language. - **Read-only local bridge:** Node.js built-ins only. No Electron, web development server, telemetry, or extra API key. diff --git a/README.zh-CN.md b/README.zh-CN.md index 815f9b1..dbd2762 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -15,6 +15,7 @@ 想知道额度用了多少、什么时候恢复,不应该每次打开一个网页。这个项目来自一个很具体的日常需求:在桌面留一小块地方,把两组额度和两个重置时间说清楚。 - 百分比统一表示**已用量**,不是剩余量。 +- 菜单栏的 **C/P** 分别代表 5 小时和本周已用量:0% 为绿色,中间过渡为黄色,100% 为红色;无数据或缓存数据显示灰色。 - 原生 WidgetKit,小号和中号,跟随系统显示中英文。 - 本机只读服务,Node 内置模块即可,不需要 Electron、网页开发服务器或额外 API Key。 - 无数据显示 `—`,旧数据显示“缓存”,不使用演示数字冒充实时数据。 diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 0669690..2644646 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -12,6 +12,8 @@ Codex must already be installed and signed in with ChatGPT. If it is not detecte After setup, right-click your desktop → Edit Widgets → Codex Pulse. Placement is a macOS step, not automatic. +When Codex Pulse is running, its menu-bar **C/P** meter shows 5-hour and weekly used quota. Each letter changes from green at 0% through yellow to red at 100%; gray means missing or cached data. This menu has no floating quota window. + ## Update a download Close Codex Pulse, replace the app in the same Applications folder, reopen it and click **Enable/repair bridge**. Keep the install location unchanged so the login service can find its bundled runtime. When changing from a source install in `~/Applications` to `/Applications`, remove the old bridge and app first to avoid duplicate widgets. diff --git a/native/CodexPulse/CodexPulseApp.swift b/native/CodexPulse/CodexPulseApp.swift index ff6a50b..ca19128 100644 --- a/native/CodexPulse/CodexPulseApp.swift +++ b/native/CodexPulse/CodexPulseApp.swift @@ -9,6 +9,7 @@ private func tr(_ en: String, _ zh: String) -> String { #if !SETUP_PREVIEW @main struct CodexPulseApp: App { + @NSApplicationDelegateAdaptor(PulseMenuDelegate.self) private var menuDelegate var body: some Scene { WindowGroup { ContentView() @@ -70,7 +71,7 @@ struct ContentView: View { NSWorkspace.shared.open(URL(string: "https://github.com/18637168668a-cpu/codex-pulse/blob/main/docs/INSTALL.md")!) } } - Text(tr("Both percentages show USED quota. Read-only · no telemetry. macOS schedules widget refreshes. You can close this app after setup.", "百分比均为已用额度。只读、无遥测;刷新由 macOS 调度。设置后可关闭主应用。")) + Text(tr("Both percentages show USED quota. Read-only · no telemetry. macOS schedules widget refreshes. You may close this setup window; keep the app running to show the CP menu meter.", "百分比均为已用额度。只读、无遥测;刷新由 macOS 调度。可关闭设置窗口;保持 App 运行即可显示 CP 菜单栏用量。")) .font(.caption2).foregroundStyle(.secondary) } .padding(26).frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) @@ -175,3 +176,122 @@ private enum SetupRunner { } } } + + +struct QuotaMeterState { + var fiveHour: Double? + var weekly: Double? + var stale = false + + static func decode(_ data: Data) throws -> QuotaMeterState { + let response = try JSONSerialization.jsonObject(with: data) as? [String: Any] ?? [:] + let byID = response["rateLimitsByLimitId"] as? [String: [String: Any]] + let bucket = byID?["codex"] ?? response["rateLimits"] as? [String: Any] ?? [:] + let windows = [bucket["primary"], bucket["secondary"]].compactMap { $0 as? [String: Any] } + func used(_ duration: Int) -> Double? { + guard let window = windows.first(where: { ($0["windowDurationMins"] as? Int) == duration }), + let value = window["usedPercent"] as? Double, value.isFinite, + (0...100).contains(value) else { return nil } + return value + } + let updatedAt = (response["updatedAt"] as? Double).map { Date(timeIntervalSince1970: $0 / 1000) } + let stale = response["stale"] as? Bool == true || updatedAt.map { Date().timeIntervalSince($0) > 900 } == true + return QuotaMeterState(fiveHour: used(300), weekly: used(10080), stale: stale) + } +} + +enum QuotaMeterColor { + // Green at 0%, yellow at 50%, red at 100%. Missing data has no usage color. + static func components(_ used: Double?) -> [Double]? { + guard let used, used.isFinite else { return nil } + let value = max(0, min(100, used)) + let green = [0.12, 0.75, 0.32], yellow = [1.0, 0.80, 0.10], red = [0.95, 0.18, 0.18] + let start = value <= 50 ? green : yellow + let end = value <= 50 ? yellow : red + let progress = value <= 50 ? value / 50 : (value - 50) / 50 + return zip(start, end).map { $0 + ($1 - $0) * progress } + } + + static func color(_ used: Double?) -> NSColor { + guard let rgb = components(used) else { return .secondaryLabelColor } + return NSColor(srgbRed: rgb[0], green: rgb[1], blue: rgb[2], alpha: 1) + } + + @MainActor static func image(_ state: QuotaMeterState) -> NSImage { + let image = NSImage(size: NSSize(width: 28, height: 20)) + image.lockFocus() + for (letter, value, x) in [("C", state.fiveHour, 1.0), ("P", state.weekly, 15.0)] { + (letter as NSString).draw(at: NSPoint(x: x, y: 2), withAttributes: [ + .font: NSFont.monospacedSystemFont(ofSize: 14, weight: .bold), + .foregroundColor: color(state.stale ? nil : value) + ]) + } + image.unlockFocus() + image.isTemplate = false + return image + } +} + +@MainActor final class PulseMenuDelegate: NSObject, NSApplicationDelegate { + private var item: NSStatusItem? + private var timer: Timer? + private var fetching = false + private var fiveHourItem: NSMenuItem? + private var weeklyItem: NSMenuItem? + + func applicationDidFinishLaunching(_ notification: Notification) { + item = NSStatusBar.system.statusItem(withLength: 32) + let menu = NSMenu() + fiveHourItem = NSMenuItem(title: "", action: nil, keyEquivalent: "") + weeklyItem = NSMenuItem(title: "", action: nil, keyEquivalent: "") + menu.addItem(fiveHourItem!) + menu.addItem(weeklyItem!) + menu.addItem(.separator()) + for entry in [ + NSMenuItem(title: tr("Refresh usage", "刷新用量"), action: #selector(refreshFromMenu), keyEquivalent: ""), + NSMenuItem(title: tr("Setup & help", "安装与帮助"), action: #selector(openHelp), keyEquivalent: ""), + NSMenuItem(title: tr("Quit Codex Pulse", "退出 Codex Pulse"), action: #selector(quit), keyEquivalent: "q") + ] { entry.target = self; menu.addItem(entry) } + item?.menu = menu + update(QuotaMeterState()) + Task { await refreshUsage() } + timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] _ in + Task { @MainActor in await self?.refreshUsage() } + } + } + + func applicationWillTerminate(_ notification: Notification) { timer?.invalidate() } + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { false } + + private func update(_ state: QuotaMeterState) { + func value(_ used: Double?) -> String { used.map { String(format: "%.0f%%", $0) } ?? "—" } + let suffix = state.stale ? tr(" (cached)", "(缓存)") : "" + let short = tr("C · 5h used: ", "C · 5 小时已用:") + value(state.fiveHour) + suffix + let week = tr("P · Week used: ", "P · 本周已用:") + value(state.weekly) + suffix + item?.button?.image = QuotaMeterColor.image(state) + item?.button?.toolTip = "Codex Pulse\n" + short + "\n" + week + item?.button?.setAccessibilityLabel("Codex Pulse. " + short + ". " + week) + fiveHourItem?.title = short + weeklyItem?.title = week + } + + private func refreshUsage() async { + guard !fetching else { return } + fetching = true + defer { fetching = false } + do { + var request = URLRequest(url: URL(string: "http://127.0.0.1:43187/api/local/usage")!) + request.timeoutInterval = 10 + request.cachePolicy = .reloadIgnoringLocalCacheData + let (data, response) = try await URLSession.shared.data(for: request) + guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw URLError(.badServerResponse) } + update(try QuotaMeterState.decode(data)) + } catch { update(QuotaMeterState()) } + } + + @objc private func refreshFromMenu() { Task { await refreshUsage() } } + @objc private func openHelp() { + NSWorkspace.shared.open(URL(string: "https://github.com/18637168668a-cpu/codex-pulse/blob/main/docs/INSTALL.md")!) + } + @objc private func quit() { NSApp.terminate(nil) } +} diff --git a/tests/SetupPreview.swift b/tests/SetupPreview.swift index 28cfd6d..5c76936 100644 --- a/tests/SetupPreview.swift +++ b/tests/SetupPreview.swift @@ -4,6 +4,19 @@ import SwiftUI @main struct SetupPreview { @MainActor static func main() throws { + precondition(QuotaMeterColor.components(0) == [0.12, 0.75, 0.32]) + precondition(QuotaMeterColor.components(50) == [1.0, 0.80, 0.10]) + let red = QuotaMeterColor.components(100)! + precondition(abs(red[0] - 0.95) < 0.00001 && abs(red[1] - 0.18) < 0.00001) + precondition(QuotaMeterColor.components(nil) == nil && QuotaMeterColor.components(.nan) == nil) + precondition(QuotaMeterColor.components(-10) == QuotaMeterColor.components(0)) + precondition(QuotaMeterColor.components(120) == QuotaMeterColor.components(100)) + let fixture = Data(#"{"rateLimits":{"primary":{"usedPercent":0,"windowDurationMins":300},"secondary":{"usedPercent":100,"windowDurationMins":10080}},"stale":false}"#.utf8) + let meter = try QuotaMeterState.decode(fixture) + precondition(meter.fiveHour == 0 && meter.weekly == 100 && !meter.stale) + let missing = try QuotaMeterState.decode(Data(#"{"rateLimits":{"primary":{"usedPercent":30,"windowDurationMins":60}},"stale":true}"#.utf8)) + precondition(missing.fiveHour == nil && missing.weekly == nil && missing.stale) + print("Menu CP color boundaries and quota mapping passed") let renderer = ImageRenderer(content: ContentView().frame(width: 570, height: 510).environment(\.colorScheme, .dark)) renderer.scale = 2 guard let image = renderer.nsImage,