From e328892c7fd5b200b96d0115a1fe1939842ae9ce Mon Sep 17 00:00:00 2001 From: "J. Kirby Ross" Date: Sun, 11 Jan 2026 00:49:37 -0800 Subject: [PATCH 1/4] refactor: moved stuff out to break this up a bit --- .dockerignore | 5 + Dockerfile | 16 ++- GETTING_STARTED.md | 111 ++++++++++++++++ REPO_WALKTHROUGH.md | 61 +++++++++ bin/git-cms.js | 26 ++-- node_modules/.package-lock.json | 45 +++++++ package-lock.json | 52 ++++++++ package.json | 7 + src/lib/CmsService.js | 145 +++++++++++++++++++++ src/lib/chunks.js | 141 -------------------- src/lib/git.js | 195 ---------------------------- src/lib/parse.js | 24 ---- src/lib/secrets.js | 223 -------------------------------- src/server/index.js | 88 ++++++------- test/chunks.test.js | 73 +++++------ test/git.test.js | 68 +++++----- test/server.test.js | 60 +++++++++ 17 files changed, 619 insertions(+), 721 deletions(-) create mode 100644 .dockerignore create mode 100644 GETTING_STARTED.md create mode 100644 REPO_WALKTHROUGH.md create mode 100644 src/lib/CmsService.js delete mode 100644 src/lib/chunks.js delete mode 100644 src/lib/git.js delete mode 100644 src/lib/parse.js delete mode 100644 src/lib/secrets.js create mode 100644 test/server.test.js diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..098364d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.git +test-repo +playwright-report +test-results diff --git a/Dockerfile b/Dockerfile index cdc94b2..9a273fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,21 +3,29 @@ # Base stage FROM node:20-slim AS base ENV NODE_ENV=production -# Install Git (Required for git-cms) RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* WORKDIR /app +# We need the lego blocks in the build context +# The build context should be ~/git so it can see both git-cms and git-stunts +# OR we can copy them specifically if we run build from ~/git + +# For simplicity in this session, I will assume we copy from a 'git-stunts' folder +# that is adjacent. + # Deps stage FROM base AS deps +# Copy the lego blocks first so npm install can link them +COPY ../git-stunts /git-stunts COPY package.json package-lock.json* ./ RUN npm ci --include=dev # Development stage FROM base AS dev ENV NODE_ENV=development +COPY --from=deps /git-stunts /git-stunts COPY --from=deps /app/node_modules ./node_modules COPY . . -# Configure Git for Dev RUN git config --global user.email "dev@git-cms.local" RUN git config --global user.name "Git CMS Dev" RUN git config --global init.defaultBranch main @@ -26,10 +34,10 @@ CMD ["npm", "run", "serve"] # Test stage FROM base AS test ENV NODE_ENV=test +COPY --from=deps /git-stunts /git-stunts COPY --from=deps /app/node_modules ./node_modules COPY . . -# Configure Git for Test RUN git config --global user.email "bot@git-cms.local" RUN git config --global user.name "Git CMS Bot" RUN git config --global init.defaultBranch main -CMD ["npm", "run", "test:local"] +CMD ["npm", "run", "test:local"] \ No newline at end of file diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md new file mode 100644 index 0000000..b7c498c --- /dev/null +++ b/GETTING_STARTED.md @@ -0,0 +1,111 @@ +# Getting Started with Git CMS + +Welcome to **Git CMS**! This tool allows you to write and manage blog posts using Git—the same technology developers use to track code—but with a simple interface that works like a regular app. + +Follow these steps to get up and running. + +--- + +## 1. Prerequisites + +Before you start, you need two things installed on your computer: + +1. **Git**: [Download and install Git here](https://git-scm.com/downloads). (Choose the default options during installation). +2. **Node.js**: [Download and install Node.js here](https://nodejs.org/). (Choose the "LTS" version). + +--- + +## 2. Installation + +You can install Git CMS directly on your computer or run it using **Docker**. + +### Option A: Direct Installation +1. Open your **Terminal** (on Mac/Linux) or **Command Prompt/PowerShell** (on Windows). +2. Type the following commands one by one: + ```bash + # Download the tool + git clone https://github.com/clduab11/git-cms.git + + # Enter the folder + cd git-cms + + # Install the helper files + npm install + + # Make the 'git-cms' command available everywhere on your computer + npm link + ``` + +### Option B: Using Docker (Recommended for isolation) +If you have [Docker Desktop](https://www.docker.com/products/docker-desktop/) installed, you can run the CMS without installing Node.js: +1. Download the tool: `git clone https://github.com/clduab11/git-cms.git` +2. Enter the folder: `cd git-cms` +3. Run with Docker: `docker compose up app` + *Note: By default, this will save posts inside the `git-cms` folder. See Section 3 to change this.* + +--- + +## 3. Setting Up Your "Content Home" + +Git CMS doesn't save your posts inside the tool itself; it saves them in a "Repository" (a special folder) of your choice. + +1. Create a new folder for your blog posts (e.g., `my-awesome-blog`). +2. Enter that folder in your terminal and "initialize" it: + ```bash + mkdir my-awesome-blog + cd my-awesome-blog + git init + ``` +3. **Crucial Step**: Tell Git CMS to use this folder. You do this by setting an "Environment Variable" named `GIT_CMS_REPO` to the path of this folder. + * **Mac/Linux**: `export GIT_CMS_REPO=/Users/yourname/my-awesome-blog` + * **Windows**: `$env:GIT_CMS_REPO="C:\Users\yourname\my-awesome-blog"` + +--- + +## 4. Running the CMS + +Now you are ready to start the interface! + +1. In your terminal, type: + ```bash + git-cms serve + ``` +2. You will see a message: `[git-cms] Admin UI: http://localhost:4638/` +3. Open your web browser (Chrome, Safari, or Edge) and go to **http://localhost:4638/**. + +--- + +## 5. Writing Your First Post + +1. Click the **+ New Article** button on the left. +2. **Slug**: Enter a short ID for your post (e.g., `my-first-post`). No spaces! +3. **Title**: Enter the title of your article. +4. **Content**: Type your post in the large box. You can use [Markdown](https://www.markdownguide.org/basic-syntax/) to add formatting like **bold** or *italics*. +5. Click **Save Draft**. + +### To Make it Public: +When you are happy with your post, click the **Publish** button. This marks the post as "live." + +--- + +## 6. Managing Images and Files + +You can add images to your posts easily: +1. In the editor, click the **Attach File** button at the bottom. +2. Select an image from your computer. +3. Git CMS will "chunk" the image, store it safely in Git, and automatically add the code to your post so the image shows up. + +--- + +## 7. Advanced: CLI Power (Optional) + +If you prefer using the terminal instead of the web browser, you can use these commands: +* `git-cms list`: See all your drafts. +* `git-cms show `: Read a post in the terminal. +* `git-cms publish `: Publish a draft. + +--- + +### Troubleshooting +* **"Command not found"**: Ensure you ran `npm link` in the `git-cms` folder. +* **"Not a git repository"**: Ensure you ran `git init` inside your content folder and that your `GIT_CMS_REPO` path is correct. diff --git a/REPO_WALKTHROUGH.md b/REPO_WALKTHROUGH.md new file mode 100644 index 0000000..814c35c --- /dev/null +++ b/REPO_WALKTHROUGH.md @@ -0,0 +1,61 @@ +# Git CMS: Technical Repo Walkthrough + +This document provides a top-to-bottom technical walkthrough of the Git CMS architecture, linking concepts to their implementation evidence in the codebase. + +## 1. Core Philosophy: The "Empty Tree" Database +Instead of tracking files on disk, Git CMS treats the Git object store as a NoSQL-style graph database. + +* **Evidence:** `src/lib/git.js` defines the [EMPTY_TREE constant](https://github.com/clduab11/git-cms/blob/main/src/lib/git.js#L6) (`4b825dc642cb6eb9a060e54bf8d69288fbee4904`). +* **Implementation:** All content commits are generated using `commit-tree` against this empty tree OID, ensuring the "working tree" of these commits is always empty. See [writeSnapshot in src/lib/git.js](https://github.com/clduab11/git-cms/blob/main/src/lib/git.js#L54). +* **NOTE:** + > [!note] + > This architectural decision is not formally documented in the `docs/` folder; it is only described in the `README.md` and visible in the source code logic. + +## 2. Refspace Organization +The CMS partitions the Git namespace to separate drafts, published content, and assets. + +* **Evidence:** The `refFor` helper in [src/lib/git.js](https://github.com/clduab11/git-cms/blob/main/src/lib/git.js#L18-L23) defines the structure: + * `refs/_blog/articles/` (Drafts) + * `refs/_blog/published/` (Published) + * `refs/_blog/comments/` (Comments) +* **NOTE:** + > [!note] + > The specific schema for the `refs/_blog` namespace lacks documentation regarding collision prevention or migration strategies. + +## 3. Article Serialization (The "Commit Article" Format) +Articles are stored entirely within Git commit messages using a header/body/trailer format. + +* **Evidence:** [src/lib/parse.js](https://github.com/clduab11/git-cms/blob/main/src/lib/parse.js) contains the logic for splitting the commit message into `title`, `body`, and `trailers`. +* **Evidence:** The CLI implementation in [bin/git-cms.js](https://github.com/clduab11/git-cms/blob/main/bin/git-cms.js#L17-L21) demonstrates the construction of this message. + +## 4. Asset Management: Git-Native CAS +Assets are handled via a Content Addressable Store (CAS) implemented using Git blobs and manifests. + +* **Chunking Logic:** Files are split into 256KB chunks in [src/lib/chunks.js](https://github.com/clduab11/git-cms/blob/main/src/lib/chunks.js#L48). +* **Encryption:** AES-256-GCM encryption is applied if a key is resolved, seen in [encryptBuffer](https://github.com/clduab11/git-cms/blob/main/src/lib/chunks.js#L34). +* **Manifests:** The file structure is preserved in a `manifest.json` stored as a Git blob, which is then committed to a chunk-specific ref. See [chunkFileToRef](https://github.com/clduab11/git-cms/blob/main/src/lib/chunks.js#L48). +* **NOTE:** + > [!note] + > The chunking and encryption feature is complex but lacks a specification document describing the manifest JSON schema. + +## 5. Secret Management +The project avoids plain-text secrets by integrating with OS-native keychains. + +* **Implementation:** [src/lib/secrets.js](https://github.com/clduab11/git-cms/blob/main/src/lib/secrets.js) contains drivers for: + * macOS `security` + * Linux `secret-tool` + * Windows `CredentialManager` +* **Usage:** Used by the CAS system to retrieve the `CHUNK_ENC_KEY` via [resolveSecret](https://github.com/clduab11/git-cms/blob/main/src/lib/secrets.js#L206). + +## 6. API and Admin UI +The system provides a zero-dependency management interface. + +* **Server:** [src/server/index.js](https://github.com/clduab11/git-cms/blob/main/src/server/index.js) uses Node's `http` module to provide a REST API. +* **UI:** [public/index.html](https://github.com/clduab11/git-cms/blob/main/public/index.html) is a vanilla JS SPA that communicates with the `/api/cms` endpoints. +* **NOTE:** + > [!note] + > The REST API endpoints are not documented with an OpenAPI spec or similar reference. + +## 7. Operational Environment +* **Configuration:** The project uses `GIT_CMS_REPO` to target the data repository. Evidence: [src/server/index.js](https://github.com/clduab11/git-cms/blob/main/src/server/index.js#L14). +* **Verification:** E2E tests in [test/e2e/admin.spec.js](https://github.com/clduab11/git-cms/blob/main/test/e2e/admin.spec.js) verify the full flow from draft creation to publishing. diff --git a/bin/git-cms.js b/bin/git-cms.js index 67fd2f4..e7c5bb4 100755 --- a/bin/git-cms.js +++ b/bin/git-cms.js @@ -1,13 +1,13 @@ #!/usr/bin/env node -import { writeSnapshot, fastForwardPublished, listRefs, readTipMessage } from '../src/lib/git.js'; -import { parseArticleCommit } from '../src/lib/parse.js'; -import { startServer } from '../src/server/index.js'; +import CmsService from '../src/lib/CmsService.js'; async function main() { const [,, cmd, ...args] = process.argv; const cwd = process.cwd(); - const refPrefix = process.env.CMS_REF_PREFIX; + const refPrefix = process.env.CMS_REF_PREFIX || 'refs/_blog/dev'; + + const cms = new CmsService({ cwd, refPrefix }); try { switch (cmd) { @@ -18,9 +18,8 @@ async function main() { const chunks = []; for await (const chunk of process.stdin) chunks.push(chunk); const body = Buffer.concat(chunks).toString('utf8'); - const message = `${title}\n\n${body}\n\nStatus: draft\n`; - const res = writeSnapshot({ slug, message, cwd, refPrefix }); + const res = await cms.saveSnapshot({ slug, title, body }); console.log(`Saved draft: ${res.sha} (${res.ref})`); break; } @@ -28,26 +27,25 @@ async function main() { const [slug] = args; if (!slug) throw new Error('Usage: git cms publish '); - const tip = readTipMessage(slug, 'draft', { cwd, refPrefix }); - const res = fastForwardPublished(slug, tip.sha, { cwd, refPrefix }); + const res = await cms.publishArticle({ slug }); console.log(`Published: ${res.sha} (${res.ref})`); break; } case 'list': { - const items = listRefs('draft', { cwd, refPrefix }); + const items = await cms.listArticles(); if (items.length === 0) console.log("No articles found."); - items.forEach(i => console.log(`- ${i.slug}: ${i.ref}`)); + items.forEach(i => console.log(`- ${i.slug}: ${i.sha}`)); break; } case 'show': { const [slug] = args; if (!slug) throw new Error('Usage: git cms show '); - const { message } = readTipMessage(slug, 'draft', { cwd, refPrefix }); - const { title, body } = parseArticleCommit(message); - console.log(`# ${title}\n\n${body}`); + const article = await cms.readArticle({ slug }); + console.log(`# ${article.title}\n\n${article.body}`); break; } case 'serve': { + const { startServer } = await import('../src/server/index.js'); startServer(); break; } @@ -61,4 +59,4 @@ async function main() { } } -main(); \ No newline at end of file +main(); diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index e3ca308..d3b803b 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -4,6 +4,31 @@ "lockfileVersion": 3, "requires": true, "packages": { + "../git-stunts/cas": { + "name": "@git-stunts/cas", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/empty-graph": { + "name": "@git-stunts/empty-graph", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/plumbing": { + "name": "@git-stunts/plumbing", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/trailer-codec": { + "name": "@git-stunts/trailer-codec", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/vault": { + "name": "@git-stunts/vault", + "version": "1.0.0", + "license": "Apache-2.0" + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", @@ -21,6 +46,26 @@ "node": ">=18" } }, + "node_modules/@git-stunts/cas": { + "resolved": "../git-stunts/cas", + "link": true + }, + "node_modules/@git-stunts/empty-graph": { + "resolved": "../git-stunts/empty-graph", + "link": true + }, + "node_modules/@git-stunts/plumbing": { + "resolved": "../git-stunts/plumbing", + "link": true + }, + "node_modules/@git-stunts/trailer-codec": { + "resolved": "../git-stunts/trailer-codec", + "link": true + }, + "node_modules/@git-stunts/vault": { + "resolved": "../git-stunts/vault", + "link": true + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", diff --git a/package-lock.json b/package-lock.json index 0ec93ca..2bdecf7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,13 @@ "name": "git-cms", "version": "1.0.0", "license": "Apache-2.0", + "dependencies": { + "@git-stunts/cas": "file:../git-stunts/cas", + "@git-stunts/empty-graph": "file:../git-stunts/empty-graph", + "@git-stunts/plumbing": "file:../git-stunts/plumbing", + "@git-stunts/trailer-codec": "file:../git-stunts/trailer-codec", + "@git-stunts/vault": "file:../git-stunts/vault" + }, "bin": { "git-cms": "bin/git-cms.js" }, @@ -16,6 +23,31 @@ "vitest": "^4.0.16" } }, + "../git-stunts/cas": { + "name": "@git-stunts/cas", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/empty-graph": { + "name": "@git-stunts/empty-graph", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/plumbing": { + "name": "@git-stunts/plumbing", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/trailer-codec": { + "name": "@git-stunts/trailer-codec", + "version": "1.0.0", + "license": "Apache-2.0" + }, + "../git-stunts/vault": { + "name": "@git-stunts/vault", + "version": "1.0.0", + "license": "Apache-2.0" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", @@ -458,6 +490,26 @@ "node": ">=18" } }, + "node_modules/@git-stunts/cas": { + "resolved": "../git-stunts/cas", + "link": true + }, + "node_modules/@git-stunts/empty-graph": { + "resolved": "../git-stunts/empty-graph", + "link": true + }, + "node_modules/@git-stunts/plumbing": { + "resolved": "../git-stunts/plumbing", + "link": true + }, + "node_modules/@git-stunts/trailer-codec": { + "resolved": "../git-stunts/trailer-codec", + "link": true + }, + "node_modules/@git-stunts/vault": { + "resolved": "../git-stunts/vault", + "link": true + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", diff --git a/package.json b/package.json index a376583..2a96ff5 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,13 @@ "type": "git", "url": "git+https://github.com/flyingrobots/git-cms.git" }, + "dependencies": { + "@git-stunts/cas": "file:../git-stunts/cas", + "@git-stunts/empty-graph": "file:../git-stunts/empty-graph", + "@git-stunts/plumbing": "file:../git-stunts/plumbing", + "@git-stunts/trailer-codec": "file:../git-stunts/trailer-codec", + "@git-stunts/vault": "file:../git-stunts/vault" + }, "devDependencies": { "@playwright/test": "^1.57.0", "vitest": "^4.0.16" diff --git a/src/lib/CmsService.js b/src/lib/CmsService.js new file mode 100644 index 0000000..2c5f9e6 --- /dev/null +++ b/src/lib/CmsService.js @@ -0,0 +1,145 @@ +import GitPlumbing from '@git-stunts/plumbing'; +import EmptyGraph from '@git-stunts/empty-graph'; +import TrailerCodec from '@git-stunts/trailer-codec'; +import ContentAddressableStore from '@git-stunts/cas'; +import Vault from '@git-stunts/vault'; +import ShellRunner from '@git-stunts/plumbing/ShellRunner.js'; + +/** + * @typedef {Object} CmsServiceOptions + * @property {string} cwd - The working directory of the git repo. + * @property {string} refPrefix - The namespace for git refs (e.g. refs/_blog/dev). + */ + +/** + * CmsService is the core domain orchestrator for Git CMS. + */ +export default class CmsService { + /** + * @param {CmsServiceOptions} options + */ + constructor({ cwd, refPrefix }) { + this.cwd = cwd; + this.refPrefix = refPrefix.replace(/\/$/, ''); + + // Initialize Lego Blocks with ShellRunner as the substrate + this.plumbing = new GitPlumbing({ + runner: ShellRunner.run, + cwd + }); + + this.graph = new EmptyGraph({ plumbing: this.plumbing }); + this.codec = new TrailerCodec(); + this.cas = new ContentAddressableStore({ plumbing: this.plumbing }); + this.vault = new Vault(); + } + + /** + * Helper to resolve a full ref path. + * @private + */ + _refFor(slug, kind = 'articles') { + return `${this.refPrefix}/${kind}/${slug}`; + } + + /** + * Lists all articles of a certain kind. + */ + async listArticles({ kind = 'articles' } = {}) { + const ns = `${this.refPrefix}/${kind}/`; + let out = ''; + try { + out = await this.plumbing.execute({ args: ['for-each-ref', ns, '--format=%(refname) %(objectname)'] }); + } catch { + return []; + } + + return out + .split('\n') + .filter(Boolean) + .map((line) => { + const [ref, sha] = line.split(' '); + const slug = ref.replace(ns, ''); + return { ref, sha, slug }; + }); + } + + /** + * Reads an article's data. + */ + async readArticle({ slug, kind = 'articles' }) { + const ref = this._refFor(slug, kind); + const sha = await this.plumbing.revParse({ revision: ref }); + if (!sha) throw new Error(`Article not found: ${slug} (${kind})`); + + const message = await this.graph.readNode({ sha }); + return { sha, ...this.codec.decode({ message }) }; + } + + /** + * Saves a new version (snapshot) of an article. + */ + async saveSnapshot({ slug, title, body, trailers = {} }) { + const ref = this._refFor(slug, 'articles'); + const parentSha = await this.plumbing.revParse({ revision: ref }); + + const finalTrailers = { ...trailers, status: 'draft', updatedAt: new Date().toISOString() }; + const message = this.codec.encode({ title, body, trailers: finalTrailers }); + + const newSha = await this.graph.createNode({ + message, + parents: parentSha ? [parentSha] : [], + sign: process.env.CMS_SIGN === '1' + }); + + await this.plumbing.updateRef({ ref, newSha, oldSha: parentSha }); + return { ref, sha: newSha, parent: parentSha }; + } + + /** + * Publishes an article by fast-forwarding the 'published' ref. + */ + async publishArticle({ slug, sha }) { + const draftRef = this._refFor(slug, 'articles'); + const pubRef = this._refFor(slug, 'published'); + + const targetSha = sha || await this.plumbing.revParse({ revision: draftRef }); + if (!targetSha) throw new Error(`Nothing to publish for ${slug}`); + + const oldSha = await this.plumbing.revParse({ revision: pubRef }); + await this.plumbing.updateRef({ ref: pubRef, newSha: targetSha, oldSha }); + + return { ref: pubRef, sha: targetSha, prev: oldSha }; + } + + /** + * Uploads an asset and returns its manifest and CAS info. + */ + async uploadAsset({ slug, filePath, filename }) { + const ENV = (process.env.GIT_CMS_ENV || 'dev').toLowerCase(); + const encryptionKeyRaw = this.vault.resolveSecret({ + envKey: 'CHUNK_ENC_KEY', + vaultTarget: `git-cms-${ENV}-enc-key` + }); + + const encryptionKey = encryptionKeyRaw ? Buffer.from(encryptionKeyRaw, 'base64') : null; + + const manifest = await this.cas.storeFile({ + filePath, + slug, + filename, + encryptionKey + }); + + const treeOid = await this.cas.createTree({ manifest }); + + const ref = `refs/_blog/chunks/${slug}@current`; + const commitSha = await this.graph.createNode({ + message: `asset:${filename}\n\nmanifest: ${treeOid}`, + }); + + await this.plumbing.updateRef({ ref, newSha: commitSha }); + + return { manifest, treeOid, commitSha }; + } +} \ No newline at end of file diff --git a/src/lib/chunks.js b/src/lib/chunks.js deleted file mode 100644 index d0fa664..0000000 --- a/src/lib/chunks.js +++ /dev/null @@ -1,141 +0,0 @@ -// chunks.js -// Minimal git-native chunk writer for assets. Inspired by git-kv chunk layout. -// Uses fixed-size chunking (256 KiB) for simplicity; swap with FastCDC later if needed. - -import { createHash, createCipheriv, createDecipheriv, randomBytes } from 'node:crypto'; -import { createReadStream, readFileSync } from 'node:fs'; -import { execFileSync } from 'node:child_process'; -import os from 'node:os'; -import path from 'node:path'; -import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'; -import { resolveSecret } from './secrets.js'; - -const CHUNK_SIZE = 256 * 1024; // 256 KiB -const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; - -function getEnvKey() { - const ENV = (process.env.GIT_CMS_ENV || 'prod').toLowerCase(); - const raw = resolveSecret('CHUNK_ENC_KEY', ENV, 'enc-key'); - return raw ? Buffer.from(raw, 'base64') : null; -} - -function runGit(args, { cwd = process.cwd(), input } = {}) { - return execFileSync('git', args, { - cwd, - input, - encoding: 'utf8', - stdio: input ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'], - }).trim(); -} - -function sha256(buf) { - return createHash('sha256').update(buf).digest('hex'); -} - -function encryptBuffer(buf) { - const key = getEnvKey(); - if (!key) return { buf, meta: null }; - const nonce = randomBytes(12); - const cipher = createCipheriv('aes-256-gcm', key, nonce); - const enc = Buffer.concat([cipher.update(buf), cipher.final()]); - const tag = cipher.getAuthTag(); - return { buf: enc, meta: { algorithm: 'aes-256-gcm', nonce: nonce.toString('base64'), tag: tag.toString('base64'), encrypted: true } }; -} - -export function decryptBuffer(buf, meta) { - if (!meta?.encrypted) return buf; - const key = getEnvKey(); - if (!key) throw new Error('Cannot decrypt chunk: No key found in Keychain/Environment'); - const nonce = Buffer.from(meta.nonce, 'base64'); - const tag = Buffer.from(meta.tag, 'base64'); - const decipher = createDecipheriv('aes-256-gcm', key, nonce); - decipher.setAuthTag(tag); - return Buffer.concat([decipher.update(buf), decipher.final()]); -} - -// Returns { manifestOid, commitSha, ref } -export async function chunkFileToRef({ filePath, slug, epoch = 'current', cwd, filename }) { - const ref = `refs/_blog/chunks/${slug}@${epoch}`; - const tmpDir = mkdtempSync(path.join(os.tmpdir(), 'cms-chunks-')); - try { - const baseName = filename || path.basename(filePath); - const manifest = { slug, epoch, filename: baseName, chunks: [], size: 0 }; - - // If encrypting (key exists), read whole file to buffer, encrypt, then chunk ciphertext - const key = getEnvKey(); - let sourceBuf = null; - if (key) { - sourceBuf = readFileSync(filePath); - const { buf, meta } = encryptBuffer(sourceBuf); - manifest.encryption = meta; - // chunk the encrypted buffer - let index = 0; - for (let i = 0; i < buf.length; i += CHUNK_SIZE) { - const chunk = buf.slice(i, i + CHUNK_SIZE); - const digest = sha256(chunk); - const blobOid = runGit(['hash-object', '-w', '--stdin'], { cwd, input: chunk }); - manifest.chunks.push({ index, size: chunk.length, digest, blob: blobOid }); - manifest.size += chunk.length; - index += 1; - } - } else { - const fd = createReadStream(filePath, { highWaterMark: CHUNK_SIZE }); - let index = 0; - for await (const chunk of fd) { - const digest = sha256(chunk); - const blobOid = runGit(['hash-object', '-w', '--stdin'], { cwd, input: chunk }); - manifest.chunks.push({ index, size: chunk.length, digest, blob: blobOid }); - manifest.size += chunk.length; - index += 1; - } - } - const manifestJson = JSON.stringify(manifest, null, 2); - const manifestOid = runGit(['hash-object', '-w', '--stdin'], { cwd, input: manifestJson }); - - // Build a flat tree (git mktree does not permit implicit subdirs) - const treeEntries = [ - `100644 blob ${manifestOid}\tmanifest.json`, - ...manifest.chunks.map((c) => `100644 blob ${c.blob}\t${c.digest}`), - ]; - const treeSpec = treeEntries.join('\n') + '\n'; - const treeOid = runGit(['mktree'], { cwd, input: treeSpec }); - - let parentSha = null; - try { - parentSha = runGit(['rev-parse', ref], { cwd }); - } catch { - parentSha = null; - } - const commitArgs = ['commit-tree', treeOid]; - if (process.env.CMS_SIGN === '1' || process.env.CHUNK_SIGN === '1') { - commitArgs.push('-S'); - } - if (parentSha) commitArgs.push('-p', parentSha); - commitArgs.push('-m', `chunk:${slug}@${epoch}\n\nmanifest: ${manifestOid}`); - const commitSha = runGit(commitArgs, { cwd }); - if (parentSha) { - runGit(['update-ref', ref, commitSha, parentSha], { cwd }); - } else { - runGit(['update-ref', ref, commitSha], { cwd }); - } - const firstDigest = manifest.chunks[0]?.digest; - return { ref, commitSha, manifestOid, treeOid, parent: parentSha, manifest, firstDigest }; - } finally { - rmSync(tmpDir, { recursive: true, force: true }); - } -} - -export function readManifestOid(slug, { epoch = 'current', cwd } = {}) { - const ref = `refs/_blog/chunks/${slug}@${epoch}`; - const tree = runGit(['rev-parse', `${ref}^{tree}`], { cwd }); - const out = runGit(['ls-tree', tree], { cwd }); - const line = out.split('\n').find((l) => l.endsWith('\tmanifest.json')); - if (!line) throw new Error('manifest not found'); - return line.split(' ')[2].split('\t')[0]; -} - -export function readManifest(slug, opts = {}) { - const oid = readManifestOid(slug, opts); - const json = runGit(['cat-file', '-p', oid], opts); - return { oid, manifest: JSON.parse(json) }; -} \ No newline at end of file diff --git a/src/lib/git.js b/src/lib/git.js deleted file mode 100644 index c011ba1..0000000 --- a/src/lib/git.js +++ /dev/null @@ -1,195 +0,0 @@ -import { execFileSync } from 'node:child_process'; -import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; - -const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; - -function runGit(args, { cwd = process.cwd(), input } = {}) { - return execFileSync('git', args, { - cwd, - input, - encoding: 'utf8', - stdio: input ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'], - }).trim(); -} - -function refFor(slug, kind = 'draft', refPrefix = 'refs/_blog') { - const base = refPrefix.replace(/\/$/, ''); - if (kind === 'published') return `${base}/published/${slug}`; - if (kind === 'comments') return `${base}/comments/${slug}`; - return `${base}/articles/${slug}`; -} - -export function readTip(slug, kind = 'draft', { cwd, refPrefix } = {}) { - const ref = refFor(slug, kind, refPrefix); - const sha = runGit(['rev-parse', ref], { cwd }); - const message = runGit(['show', '-s', '--format=%B', sha], { cwd }); - return { ref, sha, message }; -} - -export function history(slug, { cwd, limit = 20, refPrefix } = {}) { - const ref = refFor(slug, 'draft', refPrefix); - const format = ['%H', '%an', '%ad', '%B', '--END--'].join('%n'); - const out = runGit(['log', `-${limit}`, '--date=iso-strict', `--format=${format}`, ref], { cwd }); - const entries = []; - const blocks = out.split('--END--\n').filter(Boolean); - for (const block of blocks) { - const [sha, author, date, ...msgLines] = block.split('\n'); - const message = msgLines.join('\n').replace(/\n?--END--\s*$/, ''); - entries.push({ sha, author, date, message }); - } - return entries; -} - -export function writeSnapshot({ slug, message, cwd, refPrefix }) { - if (!slug) throw new Error('slug required'); - if (!message) throw new Error('message required'); - const ref = refFor(slug, 'draft', refPrefix); - let parentSha = null; - try { - parentSha = runGit(['rev-parse', ref], { cwd }); - } catch { - parentSha = null; - } - const args = ['commit-tree', EMPTY_TREE]; - if (parentSha) args.push('-p', parentSha); - if (process.env.CMS_SIGN === '1') args.push('-S'); - args.push('-m', message); - const newSha = runGit(args, { cwd }); - if (parentSha) { - runGit(['update-ref', ref, newSha, parentSha], { cwd }); - } else { - runGit(['update-ref', ref, newSha], { cwd }); - } - return { ref, sha: newSha, parent: parentSha }; -} - -export function fastForwardPublished(slug, targetSha, { cwd, refPrefix }) { - const pubRef = refFor(slug, 'published', refPrefix); - let oldSha = null; - try { - oldSha = runGit(['rev-parse', pubRef], { cwd }); - } catch { - oldSha = null; - } - if (oldSha) { - runGit(['update-ref', pubRef, targetSha, oldSha], { cwd }); - } else { - runGit(['update-ref', pubRef, targetSha], { cwd }); - } - return { ref: pubRef, sha: targetSha, prev: oldSha }; -} - -export function diffMessages(leftSha, rightSha, { cwd, structured = false } = {}) { - const tmp = mkdtempSync(path.join(os.tmpdir(), 'cmsdiff-')); - try { - const left = runGit(['show', '-s', '--format=%B', leftSha], { cwd }); - const right = runGit(['show', '-s', '--format=%B', rightSha], { cwd }); - const aPath = path.join(tmp, 'a.md'); - const bPath = path.join(tmp, 'b.md'); - writeFileSync(aPath, left, 'utf8'); - writeFileSync(bPath, right, 'utf8'); - const diff = runGit(['diff', '--no-index', '--unified=50', '--color=never', aPath, bPath], { cwd }); - if (!structured) return { diff }; - const hunks = []; - const lines = diff.split('\n'); - let current = null; - lines.forEach((line) => { - if (line.startsWith('@@')) { - const m = line.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - if (m) { - current = { header: line, oldStart: Number(m[1]), oldLines: Number(m[2]), newStart: Number(m[3]), newLines: Number(m[4]), lines: [] }; - hunks.push(current); - } - } else if (current) { - current.lines.push(line); - } - }); - return { diff, hunks }; - } finally { - rmSync(tmp, { recursive: true, force: true }); - } -} - -export function writeComment({ slug, message, parent, cwd }) { - if (!slug) throw new Error('slug required'); - if (!message) throw new Error('message required'); - const ref = refFor(slug, 'comments'); - const trailers = parent ? `\nParent: ${parent}` : ''; - const fullMessage = `${message.trim()}\n${trailers}`.trimEnd() + '\n'; - const args = ['commit-tree', EMPTY_TREE, '-m', fullMessage]; - let parentSha = null; - try { - parentSha = runGit(['rev-parse', ref], { cwd }); - } catch { - parentSha = null; - } - if (parentSha) args.push('-p', parentSha); - const newSha = runGit(args, { cwd }); - if (parentSha) { - runGit(['update-ref', ref, newSha, parentSha], { cwd }); - } else { - runGit(['update-ref', ref, newSha], { cwd }); - } - return { ref, sha: newSha, parent: parentSha }; -} - -export function listComments(slug, { cwd } = {}) { - const ref = refFor(slug, 'comments'); - let out = ''; - try { - out = runGit(['log', '-50', '--date=iso-strict', '--format=%H%n%an%n%ae%n%ad%n%B%n--END--', ref], { cwd }); - } catch { - return []; - } - return out - .split('--END--\n') - .filter(Boolean) - .map((block) => { - const [sha, author, email, date, ...rest] = block.split('\n'); - const message = rest.join('\n').trim(); - const parentMatch = message.match(/Parent:\s*(\w+)/i); - return { sha, author, email, date, message, parent: parentMatch ? parentMatch[1] : null }; - }); -} - -export function readMessageBySha(sha, { cwd } = {}) { - const message = runGit(['show', '-s', '--format=%B', sha], { cwd }); - return { sha, message }; -} - -export function readTipMessage(slug, kind = 'draft', { cwd, refPrefix } = {}) { - const { sha, message } = readTip(slug, kind, { cwd, refPrefix }); - return { sha, message }; -} - -export function deleteRef(slug, kind = 'draft', { cwd } = {}) { - const ref = refFor(slug, kind); - runGit(['update-ref', '-d', ref], { cwd }); - return { ref }; -} - -export function listRefs(kind = 'draft', { cwd, refPrefix } = {}) { - const base = (refPrefix || 'refs/_blog').replace(/\/$/, ''); - const ns = - kind === 'published' - ? `${base}/published/` - : kind === 'comments' - ? `${base}/comments/` - : `${base}/articles/`; - let out = ''; - try { - out = runGit(['for-each-ref', ns, '--format=%(refname) %(objectname)'], { cwd }); - } catch { - return []; - } - return out - .split('\n') - .filter(Boolean) - .map((line) => { - const [ref, sha] = line.split(' '); - const slug = ref.replace(ns, '').replace(/^refs\/[^/]+\/(articles|published|comments)\/ /, ''); - return { ref, sha, slug }; - }); -} diff --git a/src/lib/parse.js b/src/lib/parse.js deleted file mode 100644 index ad7733c..0000000 --- a/src/lib/parse.js +++ /dev/null @@ -1,24 +0,0 @@ -// Shared parsing utilities for commit-message articles - -export function parseArticleCommit(message) { - const lines = message.replace(/\r\n/g, '\n').split('\n'); - const title = lines.shift() || ''; - if (lines[0] === '') lines.shift(); // remove single blank - let trailerStart = lines.length; - for (let i = lines.length - 1; i >= 0; i -= 1) { - if (/^[A-Za-z0-9_-]+:\s/.test(lines[i])) { - trailerStart = i; - } else { - break; - } - } - const bodyLines = lines.slice(0, trailerStart); - const trailerLines = lines.slice(trailerStart); - const body = bodyLines.join('\n').trimEnd() + '\n'; - const trailers = {}; - trailerLines.forEach((line) => { - const m = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/); - if (m) trailers[m[1].toLowerCase()] = m[2]; - }); - return { title, body, trailers }; -} diff --git a/src/lib/secrets.js b/src/lib/secrets.js deleted file mode 100644 index da7e054..0000000 --- a/src/lib/secrets.js +++ /dev/null @@ -1,223 +0,0 @@ -import { spawnSync } from 'node:child_process'; -import readline from 'node:readline'; - -const MAC_ACCOUNT = 'git-cms'; - -export function isMac() { - return process.platform === 'darwin'; -} - -export function isLinux() { - return process.platform === 'linux'; -} - -export function isWindows() { - return process.platform === 'win32'; -} - -function run(command, args, options = {}) { - const result = spawnSync(command, args, { encoding: 'utf8', ...options }); - if (result.error) throw result.error; - return result; -} - -function trimResult(result) { - if (result.status !== 0) return undefined; - if (typeof result.stdout !== 'string') return undefined; - return result.stdout.trim(); -} - -function getMacSecret(target) { - const result = run('security', ['find-generic-password', '-a', MAC_ACCOUNT, '-s', target, '-w'], { stdio: ['ignore', 'pipe', 'ignore'] }); - return trimResult(result); -} - -function setMacSecret(target, value) { - run('security', ['delete-generic-password', '-a', MAC_ACCOUNT, '-s', target], { stdio: 'ignore' }); - const add = run( - 'security', - ['add-generic-password', '-a', MAC_ACCOUNT, '-s', target, '-w', value, '-U'], - { - stdio: 'ignore', - } - ); - if (add.status !== 0) { - throw new Error(`Failed to store secret for ${target}`); - } -} - -function deleteMacSecret(target) { - const result = run('security', ['delete-generic-password', '-a', MAC_ACCOUNT, '-s', target], { - stdio: 'ignore', - }); - return result.status === 0; -} - -function getLinuxSecret(target) { - const result = run('secret-tool', ['lookup', 'service', target]); - return trimResult(result); -} - -function setLinuxSecret(target, value) { - const result = run('secret-tool', ['store', '--label', target, 'service', target], { - input: value, - encoding: 'utf8', - stdio: ['pipe', 'ignore', 'inherit'], - }); - if (result.status !== 0) { - throw new Error(`Failed to store secret for ${target}`); - } -} - -function deleteLinuxSecret(target) { - const result = run('secret-tool', ['clear', 'service', target], { stdio: 'ignore' }); - return result.status === 0; -} - -function psLiteral(value) { - return "'" + value.replace(/'/g, "''") + "'"; -} - -function runPowershell(script) { - const result = run('powershell', ['-NoProfile', '-Command', script]); - return result; -} - -function getWindowsSecret(target) { - const script = `try { - if (Get-Module -ListAvailable -Name CredentialManager) { - Import-Module CredentialManager -ErrorAction Stop - $c = Get-StoredCredential -Target ${psLiteral(target)} - if ($c -and $c.Password) { Write-Output $c.Password } - } -} catch { }`; - const result = runPowershell(script); - return trimResult(result); -} - -function setWindowsSecret(target, value) { - const script = `try { - if (!(Get-Module -ListAvailable -Name CredentialManager)) { - Install-Module -Name CredentialManager -Scope CurrentUser -Force -ErrorAction Stop - } - Import-Module CredentialManager -ErrorAction Stop - $pwd = ${psLiteral(value)} - New-StoredCredential -Target ${psLiteral(target)} -UserName '${MAC_ACCOUNT}' -Password $pwd -Persist CurrentUser | Out-Null - exit 0 -} catch { - Write-Error $_ - exit 1 -}`; - const result = runPowershell(script); - if (result.status !== 0) { - throw new Error(`Failed to store secret for ${target}`); - } -} - -function deleteWindowsSecret(target) { - const script = `try { - if (Get-Module -ListAvailable -Name CredentialManager) { - Import-Module CredentialManager -ErrorAction Stop - Remove-StoredCredential -Target ${psLiteral(target)} -ErrorAction SilentlyContinue | Out-Null - } - exit 0 -} catch { exit 1 }`; - const result = runPowershell(script); - return result.status === 0; -} - -export function getSecret(target) { - if (!target) throw new Error('target is required'); - if (isMac()) return getMacSecret(target); - if (isLinux()) return getLinuxSecret(target); - if (isWindows()) return getWindowsSecret(target); - throw new Error('Secrets keeper is only supported on macOS, Linux, or Windows'); -} - -export function setSecret(target, value) { - if (!target) throw new Error('target is required'); - if (typeof value !== 'string' || value.length === 0) { - throw new Error('value must be a non-empty string'); - } - if (isMac()) return setMacSecret(target, value); - if (isLinux()) return setLinuxSecret(target, value); - if (isWindows()) return setWindowsSecret(target, value); - throw new Error('Secrets keeper is only supported on macOS, Linux, or Windows'); -} - -export function deleteSecret(target) { - if (!target) throw new Error('target is required'); - if (isMac()) return deleteMacSecret(target); - if (isLinux()) return deleteLinuxSecret(target); - if (isWindows()) return deleteWindowsSecret(target); - throw new Error('Secrets keeper is only supported on macOS, Linux, or Windows'); -} - -function promptHidden(prompt) { - if (!process.stdin.isTTY) { - throw new Error('Cannot prompt for secrets without a TTY'); - } - return new Promise((resolve) => { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stderr, - terminal: true, - }); - rl.stdoutMuted = true; - const question = `${prompt}: `; - rl._writeToOutput = function writeToOutput(stringToWrite) { - if (rl.stdoutMuted) { - rl.output.write('*'); - } else { - rl.output.write(stringToWrite); - } - }; - rl.on('SIGINT', () => { - rl.stdoutMuted = false; - rl.close(); - process.stderr.write('\n'); - process.exit(1); - }); - rl.question(question, (answer) => { - rl.stdoutMuted = false; - rl.close(); - process.stderr.write('\n'); - resolve(answer.trim()); - }); - }); -} - -export async function ensureSecret(target, { prompt, quiet = false } = {}) { - if (!target) throw new Error('target is required'); - let value = getSecret(target); - if (value) { - return value; - } - if (!prompt) { - throw new Error(`Secret ${target} is missing and no prompt was provided to set it`); - } - while (!value) { - const input = await promptHidden(prompt); - if (!input) { - console.error('Value cannot be empty. Press Ctrl+C to abort.'); - continue; - } - setSecret(target, input); - value = input; - } - if (!quiet) { - return value; - } - return value; -} - -export function resolveSecret(envKey, envName, suffix) { - // Try env var first - if (process.env[envKey]) return process.env[envKey]; - // Then keychain - try { - return getSecret(`git-cms-${envName}-${suffix}`); - } catch { - return null; - } -} diff --git a/src/server/index.js b/src/server/index.js index b4dafa8..74e29c2 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -3,10 +3,7 @@ import url from 'node:url'; import fs from 'node:fs'; import path from 'node:path'; import os from 'node:os'; -import { execFileSync } from 'node:child_process'; -import { listRefs, readTipMessage, history, writeSnapshot, fastForwardPublished, deleteRef, diffMessages, writeComment, listComments } from '../lib/git.js'; -import { parseArticleCommit } from '../lib/parse.js'; -import { chunkFileToRef } from '../lib/chunks.js'; +import CmsService from '../lib/CmsService.js'; const __dirname = path.dirname(new URL(import.meta.url).pathname); const PORT = process.env.PORT || 4638; @@ -15,7 +12,9 @@ const ENV = (process.env.GIT_CMS_ENV || 'dev').toLowerCase(); const REF_PREFIX = process.env.CMS_REF_PREFIX || `refs/_blog/${ENV}`; const PUBLIC_DIR = path.resolve(__dirname, '../../public'); -// Minimal static file server helper +// Initialize the core service +const cms = new CmsService({ cwd: CWD, refPrefix: REF_PREFIX }); + const MIME_TYPES = { '.html': 'text/html', '.js': 'text/javascript', @@ -27,13 +26,19 @@ const MIME_TYPES = { }; function serveStatic(req, res) { - let filePath = path.join(PUBLIC_DIR, req.url === '/' ? 'index.html' : req.url); - const ext = path.extname(filePath).toLowerCase(); - - if (!fs.existsSync(filePath)) { + let relativePath = req.url === '/' ? 'index.html' : req.url.split('?')[0]; + const filePath = path.join(PUBLIC_DIR, relativePath); + + // Security: Prevent path traversal + if (!filePath.startsWith(PUBLIC_DIR)) { return false; } + if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) { + return false; + } + + const ext = path.extname(filePath).toLowerCase(); const contentType = MIME_TYPES[ext] || 'application/octet-stream'; res.writeHead(200, { 'Content-Type': contentType }); fs.createReadStream(filePath).pipe(res); @@ -45,7 +50,7 @@ function send(res, status, payload) { res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), - 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Origin': '*', // In prod, replace with config 'Access-Control-Allow-Methods': 'GET,POST,DELETE,OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', }); @@ -56,9 +61,8 @@ async function handler(req, res) { const parsed = url.parse(req.url, true); const { pathname, query } = parsed; - console.log(`${req.method} ${pathname}`); + console.log(`[${new Date().toISOString()}] ${req.method} ${pathname}`); - // CORS Preflight if (req.method === 'OPTIONS') { res.writeHead(204, { 'Access-Control-Allow-Origin': '*', @@ -68,56 +72,48 @@ async function handler(req, res) { return res.end(); } - // API Routes try { if (pathname.startsWith('/api/cms')) { + // GET /api/cms/list?kind=articles|published|comments if (req.method === 'GET' && pathname === '/api/cms/list') { - const kind = query.kind || 'draft'; - return send(res, 200, listRefs(kind, { cwd: CWD, refPrefix: REF_PREFIX })); + const kind = query.kind || 'articles'; + return send(res, 200, cms.listArticles({ kind })); } + // GET /api/cms/show?slug=xxx&kind=articles if (req.method === 'GET' && pathname === '/api/cms/show') { - const slug = query.slug; - const kind = query.kind || 'draft'; + const { slug, kind } = query; if (!slug) return send(res, 400, { error: 'slug required' }); - const { sha, message } = readTipMessage(slug, kind, { cwd: CWD, refPrefix: REF_PREFIX }); - const parsedMsg = parseArticleCommit(message); - return send(res, 200, { sha, ...parsedMsg }); - } - - if (req.method === 'GET' && pathname === '/api/cms/history') { - const slug = query.slug; - const limit = Number(query.limit || 20); - if (!slug) return send(res, 400, { error: 'slug required' }); - const entries = history(slug, { cwd: CWD, limit, refPrefix: REF_PREFIX }); - return send(res, 200, entries); + return send(res, 200, cms.readArticle({ slug, kind: kind || 'articles' })); } + // POST /api/cms/snapshot if (req.method === 'POST' && pathname === '/api/cms/snapshot') { let body = ''; req.on('data', (c) => (body += c)); req.on('end', () => { - const { slug, message, sign } = JSON.parse(body || '{}'); - if (!slug || !message) return send(res, 400, { error: 'slug and message required' }); - if (sign) process.env.CMS_SIGN = '1'; - const result = writeSnapshot({ slug, message, cwd: CWD, refPrefix: REF_PREFIX }); + const { slug, title, body: content, trailers } = JSON.parse(body || '{}'); + if (!slug || !title) return send(res, 400, { error: 'slug and title required' }); + const result = cms.saveSnapshot({ slug, title, body: content, trailers }); return send(res, 200, result); }); return; } + // POST /api/cms/publish if (req.method === 'POST' && pathname === '/api/cms/publish') { let body = ''; req.on('data', (c) => (body += c)); req.on('end', () => { const { slug, sha } = JSON.parse(body || '{}'); if (!slug) return send(res, 400, { error: 'slug required' }); - const result = fastForwardPublished(slug, sha || readTipMessage(slug, 'draft', { cwd: CWD, refPrefix: REF_PREFIX }).sha, { cwd: CWD, refPrefix: REF_PREFIX }); + const result = cms.publishArticle({ slug, sha }); return send(res, 200, result); }); return; } + // POST /api/cms/upload if (req.method === 'POST' && pathname === '/api/cms/upload') { let body = ''; req.on('data', (c) => (body += c)); @@ -125,13 +121,14 @@ async function handler(req, res) { try { const { slug, filename, data } = JSON.parse(body || '{}'); if (!slug || !filename || !data) return send(res, 400, { error: 'slug, filename, data required' }); - // In a real app we'd stream this, but for the stunt we assume valid base64 payload + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cms-upload-')); const filePath = path.join(tmpDir, filename); fs.writeFileSync(filePath, Buffer.from(data, 'base64')); - const result = await chunkFileToRef({ filePath, slug, epoch: 'current', cwd: CWD, filename }); - // We return a "virtual" asset URL that the extractor would handle - const assetUrl = `/blog/${ENV}/assets/${slug}/${result.firstDigest}`; + + const result = await cms.uploadAsset({ slug, filePath, filename }); + const assetUrl = `/blog/${ENV}/assets/${slug}/${result.manifest.chunks[0].digest}`; + fs.rmSync(tmpDir, { recursive: true, force: true }); return send(res, 200, { ...result, assetUrl }); } catch (err) { @@ -142,17 +139,11 @@ async function handler(req, res) { return; } - send(res, 404, { error: 'API endpoint not found' }); - return; - } - - // Static Files - if (serveStatic(req, res)) { - return; + return send(res, 404, { error: 'API endpoint not found' }); } + if (serveStatic(req, res)) return; send(res, 404, { error: 'Not found' }); - } catch (err) { console.error(err); send(res, 500, { error: err.message }); @@ -162,7 +153,10 @@ async function handler(req, res) { export function startServer() { const server = http.createServer(handler); server.listen(PORT, () => { - console.log(`[git-cms] listening on http://localhost:${PORT}`); - console.log(`[git-cms] Admin UI: http://localhost:${PORT}/`); + const addr = server.address(); + const actualPort = typeof addr === 'string' ? addr : addr.port; + console.log(`[git-cms] listening on http://localhost:${actualPort}`); + console.log(`[git-cms] Admin UI: http://localhost:${actualPort}/`); }); + return server; } \ No newline at end of file diff --git a/test/chunks.test.js b/test/chunks.test.js index fbd75b2..070b4bc 100644 --- a/test/chunks.test.js +++ b/test/chunks.test.js @@ -3,67 +3,62 @@ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import os from 'node:os'; import { execFileSync } from 'node:child_process'; -import { chunkFileToRef, decryptBuffer, readManifest } from '../src/lib/chunks.js'; +import CmsService from '../src/lib/CmsService.js'; import { randomBytes } from 'node:crypto'; -function run(args, cwd) { - return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim(); -} - -describe('Git Chunks', () => { +describe('CmsService Assets (Integration)', () => { let cwd; + let cms; beforeEach(() => { - cwd = mkdtempSync(path.join(os.tmpdir(), 'git-cms-chunks-')); - run(['init'], cwd); - run(['config', 'user.name', 'Test'], cwd); - run(['config', 'user.email', 'test@example.com'], cwd); + cwd = mkdtempSync(path.join(os.tmpdir(), 'git-cms-assets-test-')); + execFileSync('git', ['init'], { cwd }); + execFileSync('git', ['config', 'user.name', 'Test'], { cwd }); + execFileSync('git', ['config', 'user.email', 'test@example.com'], { cwd }); + cms = new CmsService({ cwd, refPrefix: 'refs/cms' }); }); afterEach(() => { rmSync(cwd, { recursive: true, force: true }); }); - it('chunks a file without encryption', async () => { - // Ensure no key - delete process.env.CHUNK_ENC_KEY; + it('uploads a file and creates a manifest ref', async () => { + const filePath = path.join(cwd, 'test.png'); + writeFileSync(filePath, 'fake-binary-data'.repeat(100)); - const filePath = path.join(cwd, 'test.txt'); - writeFileSync(filePath, 'Hello World '.repeat(1000)); // ~12KB + const result = await cms.uploadAsset({ + slug: 'test-image', + filePath, + filename: 'test.png' + }); - const res = await chunkFileToRef({ filePath, slug: 'test', cwd }); + expect(result.commitSha).toHaveLength(40); + expect(result.manifest.chunks.length).toBeGreaterThan(0); - expect(res.ref).toBe('refs/_blog/chunks/test@current'); - - // Check manifest - const { manifest } = readManifest('test', { cwd }); - expect(manifest.filename).toBe('test.txt'); - expect(manifest.chunks.length).toBeGreaterThan(0); - expect(manifest.encryption).toBeUndefined(); + // Verify ref exists + const resolved = execFileSync('git', ['rev-parse', 'refs/_blog/chunks/test-image@current'], { cwd, encoding: 'utf8' }).trim(); + expect(resolved).toBe(result.commitSha); }); - it('chunks and encrypts with key', async () => { - // Set a random key + it('handles encrypted uploads', async () => { const key = randomBytes(32).toString('base64'); process.env.CHUNK_ENC_KEY = key; const filePath = path.join(cwd, 'secret.txt'); - const secretData = 'Top Secret Data'; - writeFileSync(filePath, secretData); + writeFileSync(filePath, 'Top Secret Content'); - const res = await chunkFileToRef({ filePath, slug: 'secret', cwd }); + const result = await cms.uploadAsset({ + slug: 'secret', + filePath + }); - const { manifest } = readManifest('secret', { cwd }); - expect(manifest.encryption).toBeDefined(); - expect(manifest.encryption.encrypted).toBe(true); + expect(result.manifest.encryption.encrypted).toBe(true); - // Verify blobs are encrypted (not plain text) - const blobOid = manifest.chunks[0].blob; - const blobContent = execFileSync('git', ['cat-file', '-p', blobOid], { cwd, encoding: null }); // Buffer - expect(blobContent.toString()).not.toContain('Top Secret'); + // Check if git blob is encrypted + const blobOid = result.manifest.chunks[0].blob; + const blobContent = execFileSync('git', ['cat-file', '-p', blobOid], { cwd, encoding: 'utf8' }); + expect(blobContent).not.toContain('Top Secret'); - // Decrypt manually - const decrypted = decryptBuffer(blobContent, manifest.encryption); - expect(decrypted.toString()).toBe(secretData); + delete process.env.CHUNK_ENC_KEY; }); -}); +}); \ No newline at end of file diff --git a/test/git.test.js b/test/git.test.js index 99fb7fb..3c62073 100644 --- a/test/git.test.js +++ b/test/git.test.js @@ -1,71 +1,71 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdtempSync, rmSync } from 'node:fs'; import path from 'node:path'; import os from 'node:os'; import { execFileSync } from 'node:child_process'; -import { writeSnapshot, readTipMessage, listRefs, fastForwardPublished } from '../src/lib/git.js'; +import CmsService from '../src/lib/CmsService.js'; -function run(args, cwd) { - return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim(); -} - -describe('Git CMS Core', () => { +describe('CmsService (Integration)', () => { let cwd; + let cms; + const refPrefix = 'refs/cms'; beforeEach(() => { - cwd = mkdtempSync(path.join(os.tmpdir(), 'git-cms-test-')); - run(['init'], cwd); - run(['config', 'user.name', 'Test'], cwd); - run(['config', 'user.email', 'test@example.com'], cwd); + cwd = mkdtempSync(path.join(os.tmpdir(), 'git-cms-service-test-')); + execFileSync('git', ['init'], { cwd }); + execFileSync('git', ['config', 'user.name', 'Test'], { cwd }); + execFileSync('git', ['config', 'user.email', 'test@example.com'], { cwd }); + + cms = new CmsService({ cwd, refPrefix }); }); afterEach(() => { rmSync(cwd, { recursive: true, force: true }); }); - it('writes a snapshot to a new ref', () => { + it('saves a snapshot and reads it back', async () => { const slug = 'hello-world'; - const message = 'Title\n\nBody content\n\nStatus: draft'; + const title = 'Title'; + const body = 'Body content'; - const res = writeSnapshot({ slug, message, cwd, refPrefix: 'refs/cms' }); + const res = await cms.saveSnapshot({ slug, title, body }); expect(res.sha).toHaveLength(40); - expect(res.ref).toBe('refs/cms/articles/hello-world'); - // Verify in git - const log = run(['show', '-s', '--format=%B', res.sha], cwd); - expect(log.trim()).toBe(message); + const article = await cms.readArticle({ slug }); + expect(article.title).toBe(title); + expect(article.body).toBe(body + '\n'); + expect(article.trailers.status).toBe('draft'); }); - it('updates an existing ref (history)', () => { + it('updates an existing article (history)', async () => { const slug = 'history-test'; - const v1 = writeSnapshot({ slug, message: 'v1', cwd, refPrefix: 'refs/cms' }); - const v2 = writeSnapshot({ slug, message: 'v2', cwd, refPrefix: 'refs/cms' }); + const v1 = await cms.saveSnapshot({ slug, title: 'v1', body: 'b1' }); + const v2 = await cms.saveSnapshot({ slug, title: 'v2', body: 'b2' }); expect(v2.parent).toBe(v1.sha); - const tip = readTipMessage(slug, 'draft', { cwd, refPrefix: 'refs/cms' }); - expect(tip.sha).toBe(v2.sha); - expect(tip.message).toBe('v2'); + const article = await cms.readArticle({ slug }); + expect(article.title).toBe('v2'); }); - it('lists refs', () => { - writeSnapshot({ slug: 'a', message: 'A', cwd, refPrefix: 'refs/cms' }); - writeSnapshot({ slug: 'b', message: 'B', cwd, refPrefix: 'refs/cms' }); + it('lists articles', async () => { + await cms.saveSnapshot({ slug: 'a', title: 'A', body: 'A' }); + await cms.saveSnapshot({ slug: 'b', title: 'B', body: 'B' }); - const list = listRefs('draft', { cwd, refPrefix: 'refs/cms' }); + const list = await cms.listArticles(); expect(list).toHaveLength(2); expect(list.map(i => i.slug).sort()).toEqual(['a', 'b']); }); - it('publishes (fast-forward)', () => { + it('publishes an article', async () => { const slug = 'pub-test'; - const { sha } = writeSnapshot({ slug, message: 'ready', cwd, refPrefix: 'refs/cms' }); + const { sha } = await cms.saveSnapshot({ slug, title: 'ready', body: '...' }); - fastForwardPublished(slug, sha, { cwd, refPrefix: 'refs/cms' }); + await cms.publishArticle({ slug, sha }); - const pubTip = readTipMessage(slug, 'published', { cwd, refPrefix: 'refs/cms' }); - expect(pubTip.sha).toBe(sha); + const pubArticle = await cms.readArticle({ slug, kind: 'published' }); + expect(pubArticle.sha).toBe(sha); }); -}); +}); \ No newline at end of file diff --git a/test/server.test.js b/test/server.test.js new file mode 100644 index 0000000..319434b --- /dev/null +++ b/test/server.test.js @@ -0,0 +1,60 @@ +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { mkdtempSync, rmSync } from 'node:fs'; +import path from 'node:path'; +import os from 'node:os'; +import { execFileSync } from 'node:child_process'; +import { startServer } from '../src/server/index.js'; + +describe('Server API (Integration)', () => { + let cwd; + let server; + let baseUrl; + + beforeAll(async () => { + cwd = mkdtempSync(path.join(os.tmpdir(), 'git-cms-server-api-test-')); + execFileSync('git', ['init'], { cwd }); + execFileSync('git', ['config', 'user.name', 'Test'], { cwd }); + execFileSync('git', ['config', 'user.email', 'test@example.com'], { cwd }); + + process.env.GIT_CMS_REPO = cwd; + process.env.PORT = '0'; + + server = startServer(); + + await new Promise((resolve) => { + if (server.listening) resolve(); + else server.once('listening', resolve); + }); + + const port = server.address().port; + baseUrl = `http://localhost:${port}`; + }); + + afterAll(async () => { + if (server) { + await new Promise(resolve => server.close(resolve)); + } + rmSync(cwd, { recursive: true, force: true }); + }); + + it('lists articles', async () => { + const res = await fetch(`${baseUrl}/api/cms/list`); + const data = await res.json(); + expect(res.status).toBe(200); + expect(Array.isArray(data)).toBe(true); + }); + + it('creates a snapshot via POST', async () => { + const res = await fetch(`${baseUrl}/api/cms/snapshot`, { + method: 'POST', + body: JSON.stringify({ + slug: 'api-test', + title: 'API Title', + body: 'API Body' + }) + }); + const data = await res.json(); + expect(res.status).toBe(200); + expect(data.sha).toBeDefined(); + }); +}); From 46453f2cde53f0387b0421c80f9490dffaf8302f Mon Sep 17 00:00:00 2001 From: "J. Kirby Ross" Date: Sun, 11 Jan 2026 11:20:46 -0800 Subject: [PATCH 2/4] feat(dx): overhaul onboarding with automation scripts, docs, and tests Significantly improves the "getting started" experience by adding automated setup scripts, comprehensive documentation, and a dedicated test suite for the setup process. Key changes: - Scripts: Added `setup.sh`, `quickstart.sh`, and `demo.sh` to automate environment bootstrapping and demonstration. - Docs: Added `ADR.md` (Architecture Decision Record), `TESTING_GUIDE.md`, `GETTING_STARTED.md`, and `QUICK_REFERENCE.md`. - CI: Added GitHub Actions workflow (`test-setup.yml`) and BATS test suite (`test/setup.bats`) to verify the setup scripts. - Docker: Updated `docker-compose.yml` and `Dockerfile` to use the parent directory build context, allowing access to the `@git-stunts` sibling dependency. - Config: Added Obsidian vault configuration files. --- .github/workflows/test-setup.yml | 34 + .obsidian/app.json | 1 + .obsidian/appearance.json | 1 + .obsidian/core-plugins.json | 33 + .obsidian/workspace.json | 184 ++++ Dockerfile | 22 +- QUICK_REFERENCE.md | 236 ++++ README.md | 37 +- TESTING_GUIDE.md | 368 +++++++ docker-compose.yml | 15 +- docs/ADR.md | 1770 ++++++++++++++++++++++++++++++ docs/GETTING_STARTED.md | 484 ++++++++ package.json | 4 + scripts/README.md | 89 ++ scripts/demo.sh | 208 ++++ scripts/quickstart.sh | 135 +++ scripts/setup.sh | 106 ++ test/Dockerfile.bats | 15 + test/README.md | 234 ++++ test/run-setup-tests.sh | 16 + test/setup.bats | 160 +++ 21 files changed, 4134 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/test-setup.yml create mode 100644 .obsidian/app.json create mode 100644 .obsidian/appearance.json create mode 100644 .obsidian/core-plugins.json create mode 100644 .obsidian/workspace.json create mode 100644 QUICK_REFERENCE.md create mode 100644 TESTING_GUIDE.md create mode 100644 docs/ADR.md create mode 100644 docs/GETTING_STARTED.md create mode 100644 scripts/README.md create mode 100755 scripts/demo.sh create mode 100755 scripts/quickstart.sh create mode 100755 scripts/setup.sh create mode 100644 test/Dockerfile.bats create mode 100644 test/README.md create mode 100755 test/run-setup-tests.sh create mode 100644 test/setup.bats diff --git a/.github/workflows/test-setup.yml b/.github/workflows/test-setup.yml new file mode 100644 index 0000000..7a81d03 --- /dev/null +++ b/.github/workflows/test-setup.yml @@ -0,0 +1,34 @@ +name: Test Setup Script + +on: + push: + branches: [main, git-stunts] + paths: + - 'scripts/setup.sh' + - 'test/setup.bats' + - 'test/run-setup-tests.sh' + - 'test/Dockerfile.bats' + pull_request: + paths: + - 'scripts/setup.sh' + - 'test/setup.bats' + - 'test/run-setup-tests.sh' + - 'test/Dockerfile.bats' + +jobs: + test-setup-script: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Run BATS tests + run: npm run test:setup + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v3 + with: + name: bats-test-results + path: test-results/ diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 0000000..639b90d --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,33 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "footnotes": false, + "properties": true, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": true, + "bases": true, + "webviewer": false +} \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json new file mode 100644 index 0000000..2e248e5 --- /dev/null +++ b/.obsidian/workspace.json @@ -0,0 +1,184 @@ +{ + "main": { + "id": "382ef6cb0b37226a", + "type": "split", + "children": [ + { + "id": "a221f72eab71482f", + "type": "tabs", + "children": [ + { + "id": "4b42bcdd58f40569", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "25465ee673d3c20e", + "type": "split", + "children": [ + { + "id": "9957cb948538a869", + "type": "tabs", + "children": [ + { + "id": "1bf6d840971c2191", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical", + "autoReveal": false + }, + "icon": "lucide-folder-closed", + "title": "Files" + } + }, + { + "id": "d299a60ce286ca4a", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + }, + "icon": "lucide-search", + "title": "Search" + } + }, + { + "id": "6f40aa62283a6cfd", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {}, + "icon": "lucide-bookmark", + "title": "Bookmarks" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "right": { + "id": "500be1963bd258e5", + "type": "split", + "children": [ + { + "id": "3bf59e45878ff55f", + "type": "tabs", + "children": [ + { + "id": "fee6fe767f089756", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-coming-in", + "title": "Backlinks" + } + }, + { + "id": "a3468ed4f299e088", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "linksCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-going-out", + "title": "Outgoing links" + } + }, + { + "id": "112f4c995c16a506", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-tags", + "title": "Tags" + } + }, + { + "id": "aff00e1ba0272008", + "type": "leaf", + "state": { + "type": "all-properties", + "state": { + "sortOrder": "frequency", + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-archive", + "title": "All properties" + } + }, + { + "id": "0a75ab3131feff1a", + "type": "leaf", + "state": { + "type": "outline", + "state": { + "followCursor": false, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-list", + "title": "Outline" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300, + "collapsed": true + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false, + "bases:Create new base": false + } + }, + "active": "4b42bcdd58f40569", + "lastOpenFiles": [ + "docs/ADR.md" + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9a273fa..87fa1f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,18 +6,20 @@ ENV NODE_ENV=production RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* WORKDIR /app -# We need the lego blocks in the build context -# The build context should be ~/git so it can see both git-cms and git-stunts -# OR we can copy them specifically if we run build from ~/git - -# For simplicity in this session, I will assume we copy from a 'git-stunts' folder -# that is adjacent. +# IMPORTANT: This Dockerfile expects the build context to be the PARENT directory +# so it can access both git-cms/ and git-stunts/ directories. +# See docker-compose.yml which sets context: .. and dockerfile: git-cms/Dockerfile +# +# Directory structure expected: +# ~/git/ +# git-cms/ ← This repo +# git-stunts/ ← Lego blocks repo # Deps stage FROM base AS deps # Copy the lego blocks first so npm install can link them -COPY ../git-stunts /git-stunts -COPY package.json package-lock.json* ./ +COPY git-stunts /git-stunts +COPY git-cms/package.json git-cms/package-lock.json* ./ RUN npm ci --include=dev # Development stage @@ -25,7 +27,7 @@ FROM base AS dev ENV NODE_ENV=development COPY --from=deps /git-stunts /git-stunts COPY --from=deps /app/node_modules ./node_modules -COPY . . +COPY git-cms . RUN git config --global user.email "dev@git-cms.local" RUN git config --global user.name "Git CMS Dev" RUN git config --global init.defaultBranch main @@ -36,7 +38,7 @@ FROM base AS test ENV NODE_ENV=test COPY --from=deps /git-stunts /git-stunts COPY --from=deps /app/node_modules ./node_modules -COPY . . +COPY git-cms . RUN git config --global user.email "bot@git-cms.local" RUN git config --global user.name "Git CMS Bot" RUN git config --global init.defaultBranch main diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md new file mode 100644 index 0000000..d3a4228 --- /dev/null +++ b/QUICK_REFERENCE.md @@ -0,0 +1,236 @@ +# Git CMS Quick Reference + +**One-page cheat sheet for Git CMS commands and concepts.** + +--- + +## 🚀 First Time Setup + +```bash +git clone https://github.com/flyingrobots/git-cms.git +cd git-cms +npm run setup # Clones git-stunts, checks Docker +npm run demo # See it work! +``` + +--- + +## 📦 npm Commands + +| Command | Purpose | +|---------|---------| +| `npm run setup` | One-time setup (clones dependencies) | +| `npm run demo` | Automated demo with explanations | +| `npm run quickstart` | Interactive menu | +| `npm run dev` | Start HTTP server (http://localhost:4638) | +| `npm test` | Run integration tests | +| `npm run test:setup` | Run setup script tests (BATS) | + +--- + +## 🔧 CLI Commands (Inside Container) + +```bash +# Enter container +docker compose run --rm app sh + +# Draft an article +echo "# My Post" | node bin/git-cms.js draft my-slug "My Title" + +# List articles +node bin/git-cms.js list +node bin/git-cms.js list --kind=published + +# Publish an article +node bin/git-cms.js publish my-slug + +# Read an article +node bin/git-cms.js show my-slug + +# Exit container +exit +``` + +--- + +## 🎯 The Core Concept + +### Traditional CMS +``` +Article → Database Row → SQL Query +``` + +### Git CMS +``` +Article → Commit Message → git log +``` + +**The Trick:** Commits point to the "empty tree" so no files are changed. + +--- + +## 📂 Key Refs (Git References) + +| Ref | Purpose | +|-----|---------| +| `refs/_blog/articles/` | Draft version (moves forward with each save) | +| `refs/_blog/published/` | Published version (fast-forward only) | +| `refs/_blog/chunks/@current` | Encrypted asset manifest | + +--- + +## 🔍 Inspecting with Git + +```bash +# View all CMS refs +git for-each-ref refs/_blog/ + +# Read an article (it's just a commit message!) +git log refs/_blog/articles/hello-world -1 --format="%B" + +# See version history +git log refs/_blog/articles/hello-world --oneline + +# Check what tree the commit points to +git log refs/_blog/articles/hello-world -1 --format="%T" +# → 4b825dc... (the empty tree!) + +# View the DAG +git log --all --graph --oneline refs/_blog/ +``` + +--- + +## 🏗️ Architecture (Lego Blocks) + +``` +git-cms + └─ CmsService (orchestrator) + ├─ @git-stunts/plumbing (Git commands) + ├─ @git-stunts/trailer-codec (RFC 822 trailers) + ├─ @git-stunts/empty-graph (commits on empty tree) + ├─ @git-stunts/cas (encrypted asset storage) + └─ @git-stunts/vault (OS keychain for secrets) +``` + +--- + +## 📄 Commit Message Format + +``` +# My Article Title + +This is the article body. + +Status: draft +Author: James Ross +Tags: git, cms +Slug: my-article +UpdatedAt: 2026-01-11T12:34:56Z +``` + +**Trailers** (key-value pairs at end) are parsed by `@git-stunts/trailer-codec`. + +--- + +## 🔐 Publishing Workflow + +```bash +# Save draft (creates commit) +echo "# Post" | git cms draft my-post "Title" +→ refs/_blog/articles/my-post points to abc123 + +# Publish (copies pointer) +git cms publish my-post +→ refs/_blog/published/my-post points to abc123 + +# Edit (creates new commit) +echo "# Updated" | git cms draft my-post "Title" +→ refs/_blog/articles/my-post points to def456 +→ refs/_blog/published/my-post still points to abc123 +``` + +Publishing is **atomic** and **fast-forward only**. + +--- + +## 🛡️ Safety + +**Everything runs in Docker by default.** + +- ✅ Your host Git repos are never touched +- ✅ Tests run in isolated containers +- ✅ Easy cleanup: `docker compose down -v` + +**Never** run `git cms` commands in repos you care about until you understand what's happening. + +--- + +## 📚 Documentation + +| File | Purpose | +|------|---------| +| `README.md` | Overview + quick start | +| `TESTING_GUIDE.md` | How to test safely | +| `docs/GETTING_STARTED.md` | Comprehensive walkthrough | +| `docs/ADR.md` | **Architecture Decision Record** (deep dive) | +| `test/README.md` | Test suite documentation | +| `scripts/README.md` | Script documentation | +| `QUICK_REFERENCE.md` | This file! | + +--- + +## 🐛 Troubleshooting + +### "Cannot find module '@git-stunts/...'" +```bash +npm run setup # Clones git-stunts automatically +``` + +### "Port 4638 already in use" +Edit `docker-compose.yml`: +```yaml +ports: + - "5000:4638" # Use port 5000 instead +``` + +### "Docker daemon not running" +Start Docker Desktop (macOS/Windows) or `sudo systemctl start docker` (Linux). + +--- + +## 🎓 Key Concepts to Understand + +1. **Empty Tree:** `4b825dc642cb6eb9a060e54bf8d69288fbee4904` is Git's canonical empty tree. All commits point here. + +2. **Trailers:** RFC 822 key-value pairs at end of commit messages (like `Signed-off-by` in Linux kernel). + +3. **Fast-Forward Only:** Published refs can only move forward in history, never rewrite. + +4. **Content Addressability:** Assets stored by SHA-1 hash, automatic deduplication. + +5. **Compare-and-Swap (CAS):** `git update-ref` is atomic at ref level, prevents concurrent write conflicts. + +--- + +## 💡 The "Linus Threshold" + +This project exists at the edge of technical sanity. It's designed to make you think: + +> "I would never use this in production, but now I understand Git way better." + +If you're considering production use: +- Read `docs/ADR.md` cover to cover +- Understand every tradeoff +- Run in Docker for months +- Ask yourself: "Would a database be better?" (probably yes) + +Then, if you're still convinced... **go for it!** Just don't say we didn't warn you. 😄 + +--- + +## 🎉 Have Fun! + +This is a **thought experiment** that happens to work. Use it to learn, explore, and understand Git's plumbing from first principles. + +*"You know what? Have fun."* — Linus (probably) diff --git a/README.md b/README.md index 0902730..c4fa001 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,43 @@ A serverless, database-free CMS built on Git plumbing. **git-cms** treats your Git repository as a distributed, cryptographically verifiable database. Instead of files, it stores content as commit messages on "empty trees," creating a linear, append-only ledger for articles, comments, or any other structured data. -## ⚠️ SAFETY WARNING +## Quick Start (Docker - Safe!) -**If you clone this repo and want to run the tests, ALWAYS run them in Docker.** +### One-Time Setup -The tests create, destroy, and manipulate Git repositories. While we try to use temporary directories, running low-level plumbing commands against your host filesystem is a risk you shouldn't take. +```bash +# Clone this repo +git clone https://github.com/flyingrobots/git-cms.git +cd git-cms + +# Run setup (clones dependencies, checks Docker) +npm run setup +``` + +### Try It Out -We provided a safe harness: ```bash -npm test -# (This automatically runs ./test/run-docker.sh) +# Option 1: See a demo (recommended first time) +npm run demo + +# Option 2: Interactive menu +npm run quickstart + +# Option 3: Just start the server +npm run dev +# Open http://localhost:4638 ``` +**Everything runs in Docker - completely safe for your local Git setup.** + +## ⚠️ SAFETY WARNING + +**This project manipulates Git repositories at a low level. ALWAYS use Docker for testing.** + +The tests create, destroy, and manipulate Git repositories. Running low-level plumbing commands on your host filesystem is risky - a typo could affect your local Git setup. That's why we built Docker isolation into everything. + +**Read more:** [TESTING_GUIDE.md](./TESTING_GUIDE.md) | [docs/GETTING_STARTED.md](./docs/GETTING_STARTED.md) + ## Features - **Database-Free:** No SQL, No NoSQL. Just Git objects (Merkle DAG). diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md new file mode 100644 index 0000000..becb2a2 --- /dev/null +++ b/TESTING_GUIDE.md @@ -0,0 +1,368 @@ +# How to Safely Test Git CMS + +This guide explains how to try out git-cms without any risk to your local Git setup or existing repositories. + +## TL;DR - Just Show Me The Commands + +```bash +# One-time setup +git clone https://github.com/flyingrobots/git-cms.git +cd git-cms +npm run setup + +# Then use any of these: +npm run demo # Automated demo +npm run quickstart # Interactive menu +npm run dev # Start server +``` + +**Everything runs in Docker. Your host system is safe.** + +--- + +## Prerequisites + +### Required Directory Structure + +Git CMS depends on "Lego Block" modules from the `git-stunts` repository. Your directory structure must be: + +``` +~/git/ ← Can be anywhere, doesn't have to be ~/git + ├── git-cms/ ← This repository + └── git-stunts/ ← Required dependency +``` + +### Clone and Setup + +```bash +cd ~/git # Or wherever you want to keep these + +# Clone git-cms +git clone https://github.com/flyingrobots/git-cms.git +cd git-cms + +# Run setup (this clones git-stunts and checks Docker) +npm run setup +``` + +**What `npm run setup` does:** +- Checks Docker is installed and running +- Clones git-stunts (Lego Blocks) to `../git-stunts/` +- Verifies the directory structure is correct + +After setup, your structure will be: +``` +~/git/ + ├── git-cms/ ← You are here + └── git-stunts/ ← Auto-cloned by setup +``` + +### Install Docker + +- **macOS:** [Docker Desktop](https://docs.docker.com/desktop/install/mac-install/) +- **Linux:** [Docker Engine](https://docs.docker.com/engine/install/) +- **Windows:** [Docker Desktop](https://docs.docker.com/desktop/install/windows-install/) + +Verify Docker is working: +```bash +docker --version +docker compose version +``` + +--- + +## Safety Guarantees + +### What's Protected + +✅ **Your host Git repositories** - Never touched +✅ **Your Git global config** - Never modified +✅ **Your filesystem** - Only the git-cms directory is mounted (read-only for git operations) +✅ **Your Git history** - Tests run in isolated containers + +### How Docker Provides Isolation + +1. **Separate Filesystem**: The container has its own isolated filesystem +2. **Separate Git Config**: Container sets its own `user.name` and `user.email` +3. **Temporary Repos**: Tests create repos in `/tmp` inside the container +4. **Easy Cleanup**: `docker compose down -v` destroys everything + +--- + +## Testing Scenarios + +### Scenario 1: Interactive Quick Start (Recommended) + +```bash +cd git-cms +./scripts/quickstart.sh +``` + +**What it does:** +- Checks Docker prerequisites +- Provides a menu with options: + 1. Start the HTTP server + 2. Run tests + 3. Open a shell + 4. View logs + 5. Clean up + +**Safe because:** Everything runs in Docker containers that are destroyed after use. + +--- + +### Scenario 2: Automated Demo + +```bash +cd git-cms +./scripts/demo.sh +``` + +**What it does:** +- Creates a demo article +- Shows how Git stores the data +- Demonstrates publishing +- Shows version history +- Explains the "empty tree" trick + +**Safe because:** Runs entirely in a Docker container with a temporary Git repo. + +--- + +### Scenario 3: HTTP Server + Web UI + +```bash +cd git-cms +npm run dev +# OR +docker compose up app +``` + +Open your browser to: **http://localhost:4638** + +**What it does:** +- Starts Node.js HTTP server in Docker +- Serves the admin UI +- Creates a Git repo inside the container at `/app/.git` + +**Safe because:** +- Repository is inside the container, not on your host +- Stopping the container (`Ctrl+C` or `docker compose down`) stops all Git operations +- No risk to your local repositories + +**To clean up:** +```bash +docker compose down -v # Removes container and volumes +``` + +--- + +### Scenario 4: CLI Commands (Inside Container) + +```bash +cd git-cms +docker compose run --rm app sh + +# Now you're in the container +node bin/git-cms.js draft hello-world "My First Post" +node bin/git-cms.js list +node bin/git-cms.js publish hello-world + +# Explore what Git sees +git log --all --oneline --graph +git for-each-ref refs/_blog/ + +exit +``` + +**Safe because:** You're running commands inside the container, which has its own isolated Git environment. + +--- + +### Scenario 5: Run Tests + +```bash +cd git-cms +npm test +# OR +./test/run-docker.sh +# OR +docker compose run --rm test +``` + +**What it does:** +- Runs Vitest integration tests +- Creates temporary Git repos in `/tmp` +- Tests CRUD operations, encryption, API endpoints +- Cleans up after completion + +**Safe because:** All tests run in an isolated Docker container with temporary repos. + +--- + +## Advanced: Local Installation (Not Recommended Initially) + +If you understand what git-cms does and want to install it globally on your host: + +```bash +npm install -g git-cms +# OR +cd git-cms && npm link +``` + +**⚠️ WARNING:** Only use git-cms in dedicated repositories: + +```bash +# Create a fresh repo for testing +mkdir ~/git-cms-playground +cd ~/git-cms-playground +git init + +# Configure +git config user.name "Your Name" +git config user.email "you@example.com" + +# Now safe to use +echo "# Test" | git cms draft test-post "Test Post" +``` + +**NEVER run `git cms` commands in:** +- Your active project repositories +- Repositories with uncommitted work +- Any repository you care about until you understand what's happening + +--- + +## What Could Go Wrong? (And Why It Won't) + +### Myth: "Git CMS will mess up my local Git" + +**Reality:** If you use Docker (as recommended), git-cms never touches your host Git installation. It runs in a container with its own Git binary, config, and repositories. + +### Myth: "Tests will create files all over my filesystem" + +**Reality:** Tests run in Docker containers with temporary directories. When the container stops, everything is cleaned up automatically. + +### Myth: "I'll accidentally run commands in my project repo" + +**Reality:** The CLI checks what directory you're in. If you're in a repo with important files, you'll notice. Plus, git-cms operates in the `refs/_blog/*` namespace, separate from your normal branches. + +### Actual Risk: Running Tests Outside Docker + +**IF** you run `npm run test:local` (bypassing Docker), tests WILL create temporary repos in your `/tmp` directory. While these are deleted after, there's a non-zero risk if tests fail mid-execution. + +**Solution:** Always use `npm test` which automatically uses Docker. + +--- + +## Cleanup + +### Remove Everything + +```bash +# Stop containers +cd git-cms +docker compose down + +# Remove containers AND volumes (fresh start) +docker compose down -v + +# Remove images (if you want to reclaim disk space) +docker rmi $(docker images | grep git-cms | awk '{print $3}') +``` + +### Uninstall CLI (if installed globally) + +```bash +npm uninstall -g git-cms +# OR +cd git-cms && npm unlink +``` + +--- + +## Troubleshooting + +### "Cannot find module '@git-stunts/...'" + +**Cause:** The `git-stunts` directory is not in the expected location. + +**Solution:** +```bash +# Verify structure +ls -l .. +# Should show both git-cms and git-stunts + +# If git-stunts is missing +cd .. +git clone https://github.com/flyingrobots/git-stunts.git +cd git-cms + +# Rebuild Docker images +docker compose build +``` + +### "Port 4638 already in use" + +**Solution:** Either stop the process using that port, or change the port in `docker-compose.yml`: + +```yaml +ports: + - "5000:4638" # Maps localhost:5000 → container:4638 +``` + +### "Docker daemon not running" + +**Solution:** Start Docker Desktop (macOS/Windows) or start the Docker service (Linux): + +```bash +# Linux +sudo systemctl start docker +``` + +### Tests fail with "EACCES: permission denied" + +**Cause:** Docker doesn't have permission to bind volumes. + +**Solution:** +- On macOS/Windows: Check Docker Desktop → Settings → Resources → File Sharing +- On Linux: Ensure your user is in the `docker` group + +--- + +## What's Next? + +Once you're comfortable with the basics: + +1. **Read the Architecture Decision Record**: `docs/ADR.md` + - Comprehensive technical documentation + - Design decisions and tradeoffs + - Full system architecture + +2. **Explore the Code**: `src/lib/CmsService.js` + - See how the Lego Blocks are composed + - Understand the domain orchestration + - Study the Git plumbing operations + +3. **Set Up Stargate Gateway**: `./scripts/bootstrap-stargate.sh` + - Enforces fast-forward only + - Verifies GPG signatures + - Mirrors to public repositories + +4. **Experiment with Encryption**: See `docs/GETTING_STARTED.md` + - Client-side AES-256-GCM encryption + - OS keychain integration + - Row-level access control + +--- + +## Remember + +Git CMS is a **learning project** and **thought experiment**. It's designed to teach you: +- How Git's plumbing actually works +- Content-addressable storage patterns +- Building unconventional systems from first principles + +Use it to learn, experiment, and explore. Don't use it in production unless you **really** understand what you're getting into. + +Have fun! 🎉 diff --git a/docker-compose.yml b/docker-compose.yml index f26046f..bd6e981 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,17 @@ +# IMPORTANT: Run docker compose from THIS directory (git-cms/) +# The build context is set to parent (..) so Docker can access both +# git-cms/ and git-stunts/ directories for the build. +# +# Expected structure: +# ~/git/ +# git-cms/ ← Run docker compose here +# git-stunts/ ← Lego blocks (required) + services: app: build: - context: . + context: .. # Parent dir so we can access both git-cms and git-stunts + dockerfile: git-cms/Dockerfile target: dev volumes: - .:/app @@ -15,7 +25,8 @@ services: test: build: - context: . + context: .. # Parent dir so we can access both git-cms and git-stunts + dockerfile: git-cms/Dockerfile target: test volumes: - .:/app diff --git a/docs/ADR.md b/docs/ADR.md new file mode 100644 index 0000000..3ac5272 --- /dev/null +++ b/docs/ADR.md @@ -0,0 +1,1770 @@ +# Architecture Decision Record: Git CMS +## Database-Free Content Management via Git Plumbing + +**Status:** Active +**Version:** 1.0.0 +**Last Updated:** 2026-01-11 +**Author:** James Ross + +--- + +## 1. Introduction & Goals + +### Project Overview + +**git-cms** is a serverless, database-free Content Management System that treats Git's object store as a distributed, cryptographically verifiable document database. Instead of storing content in traditional databases (SQL or NoSQL), it leverages Git's Merkle DAG to create an append-only ledger for articles, metadata, and encrypted assets. + +The fundamental innovation: **`git push` becomes the API endpoint.** + +### Fundamental Requirements + +#### FR-1: Zero-Database Architecture +The system MUST NOT depend on external database systems (SQL, NoSQL, or key-value stores). All persistent state resides within Git's native object store (`.git/objects`). + +**Rationale:** Eliminates operational complexity, deployment dependencies, and schema migration challenges inherent to traditional database-backed CMSs. + +#### FR-2: Cryptographic Verifiability +Every content mutation MUST be recorded as a Git commit with cryptographic integrity guarantees via SHA-1 hashing (with optional GPG signing for non-repudiation). + +**Rationale:** Provides immutable audit trails and tamper detection without additional infrastructure. + +#### FR-3: Fast-Forward Only Publishing +The publish operation MUST enforce strict linear history (fast-forward only) to prevent rewriting published content. + +**Rationale:** Guarantees provenance and prevents content manipulation after publication. + +#### FR-4: Client-Side Encryption +All uploaded assets MUST be encrypted client-side (AES-256-GCM) before touching the repository. + +**Rationale:** Achieves row-level security without database-level access controls. The Git gateway receives only opaque encrypted blobs. + +#### FR-5: Infinite Point-in-Time Recovery +Users MUST be able to access any historical version of any article without data loss. + +**Rationale:** Git's DAG structure provides this naturally; the CMS simply exposes it as a first-class feature. + +### Quality Goals + +| Priority | Quality Attribute | Description | Measurement | +|----------|------------------|-------------|-------------| +| 1 | **Security** | Cryptographic integrity, client-side encryption, signed commits | GPG verification, AES-256-GCM encryption strength | +| 2 | **Simplicity** | Minimal dependencies, no database, composable architecture | Lines of code, dependency count, Docker image size | +| 3 | **Auditability** | Complete provenance of all content changes | Git log completeness, trailer metadata coverage | +| 4 | **Performance** | Sub-second reads for typical blog workloads | Response time for `readArticle()` | +| 5 | **Portability** | Multi-runtime support (Node, Bun, Deno) | Test suite pass rate across runtimes | + +### Non-Goals + +This system is **intentionally NOT designed for**: + +- **High-velocity writes:** Content publishing happens in minutes/hours, not milliseconds. +- **Complex queries:** No SQL-like JOINs or aggregations. Queries are limited to ref enumeration and commit message parsing. +- **Large-scale collaboration:** Designed for single-author or small-team blogs, not Wikipedia-scale editing. +- **Real-time updates:** Publishing is atomic but not instantaneous across distributed clones. + +--- + +## 2. Constraints + +### Technical Constraints + +#### TC-1: Git's Content Addressability Model +Git uses SHA-1 hashing for object addressing. While SHA-1 has known collision vulnerabilities, Git is transitioning to SHA-256. The system assumes SHA-1 is "good enough" for content addressing (not for security-critical signing). + +**Mitigation:** Use GPG signing (`CMS_SIGN=1`) for cryptographic non-repudiation. + +#### TC-2: Filesystem I/O Performance +All Git operations are ultimately filesystem operations. Performance is bounded by disk I/O, especially for large repositories. + +**Mitigation:** Content is stored as commit messages (small), not files (large). Asset chunking (256KB) reduces blob size. + +#### TC-3: POSIX Shell Dependency +The `@git-stunts/plumbing` module executes Git via shell commands (`child_process.spawn`). This requires a POSIX-compliant shell and Git CLI. + +**Mitigation:** All tests run in Docker (Alpine Linux) to ensure consistent environments. + +#### TC-4: No Database Indexes +Traditional databases provide B-tree indexes for fast lookups. Git's ref enumeration is linear (`O(n)` for listing all refs in a namespace). + +**Mitigation:** Use ref namespaces strategically (e.g., `refs/_blog/articles/`) to avoid polluting the global ref space. + +### Regulatory Constraints + +#### RC-1: GDPR Right to Erasure +Git's immutability conflicts with GDPR's "right to be forgotten." Deleting a commit requires rewriting history, which breaks cryptographic integrity. + +**Mitigation:** Use encrypted assets with key rotation. Deleting the encryption key renders historical content unreadable without altering Git history. + +#### RC-2: Cryptographic Export Restrictions +AES-256-GCM encryption may face export restrictions in certain jurisdictions. + +**Mitigation:** The `@git-stunts/vault` module uses Node's built-in `crypto` module, which is widely available. + +### Operational Constraints + +#### OC-1: Single-Writer Assumption +Git's ref updates are atomic *locally* but not across distributed clones. Concurrent writes to the same ref can cause conflicts. + +**Mitigation:** Use **git-stargate** (a companion project) to enforce serialized writes via SSH. + +#### OC-2: Repository Growth +Every draft save creates a new commit. Repositories can grow unbounded over time. + +**Mitigation:** Use `git gc` aggressively. Consider ref pruning for old drafts. + +--- + +## 3. Context & Scope + +### System Context Diagram + +```mermaid +graph TB + Author[Author
Human] + GitCMS[git-cms
Node.js Application] + Stargate[git-stargate
Git Gateway] + LocalRepo[.git/objects/
Local Repository] + PublicMirror[GitHub/GitLab
Public Mirror] + + Author -->|CLI/HTTP API| GitCMS + GitCMS -->|git push| Stargate + GitCMS -->|read/write| LocalRepo + Stargate -->|mirror| PublicMirror + + style GitCMS fill:#e1f5ff + style LocalRepo fill:#fff4e1 + style Stargate fill:#ffe1e1 + style PublicMirror fill:#e1ffe1 +``` + +### External Interfaces + +#### Interface 1: CLI (Binary) +- **Entry Point:** `bin/git-cms.js` +- **Commands:** `draft`, `publish`, `list`, `show`, `serve` +- **Protocol:** POSIX command-line arguments +- **Example:** + ```bash + echo "# Hello World" | git cms draft hello-world "My First Post" + ``` + +#### Interface 2: HTTP API (REST) +- **Server:** `src/server/index.js` +- **Port:** 4638 (configurable via `PORT` env var) +- **Endpoints:** + - `POST /api/cms/snapshot` – Save draft + - `POST /api/cms/publish` – Publish article + - `GET /api/cms/list` – List articles + - `GET /api/cms/show?slug=` – Read article +- **Authentication:** None (assumes private network or SSH tunneling) + +#### Interface 3: Git Plumbing (Shell) +- **Protocol:** Git CLI commands via `child_process.spawn` +- **Critical Commands:** + - `git commit-tree` – Create commits on empty trees + - `git update-ref` – Atomic ref updates + - `git for-each-ref` – List refs in namespace + - `git cat-file` – Read commit messages + +#### Interface 4: OS Keychain (Secrets) +- **Platforms:** + - macOS: `security` command-line tool + - Linux: `secret-tool` (GNOME Keyring) + - Windows: `CredentialManager` (PowerShell) +- **Purpose:** Store AES-256-GCM encryption keys for assets + +### Scope Boundaries + +#### In Scope +- Article drafting, editing, and publishing +- Encrypted asset storage (images, PDFs) +- Full version history via Git log +- CLI and HTTP API access +- Multi-runtime support (Node, Bun, Deno) + +#### Out of Scope +- **User Authentication:** Delegated to git-stargate or SSH +- **Search Indexing:** No full-text search (could be built via external indexer reading Git log) +- **Media Transcoding:** Assets stored as-is (no ImageMagick, FFmpeg) +- **Real-Time Collaboration:** No operational transformation (OT) or CRDTs +- **Analytics:** No built-in pageview tracking + +--- + +## 4. Solution Strategy + +### Core Architectural Principles + +#### P-1: Composition over Inheritance +The system is built from **five independent "Lego Block" modules** (`@git-stunts/*`), each with a single responsibility. These modules are composed in `CmsService` to create higher-order functionality. + +**Benefit:** Each module can be tested, versioned, and published independently. + +#### P-2: Hexagonal Architecture (Ports & Adapters) +The domain layer (`CmsService`) depends on abstractions (`GitPlumbing`, `TrailerCodec`), not implementations. This allows swapping out Git for other backends (e.g., a pure JavaScript implementation for testing). + +**Benefit:** Decouples domain logic from infrastructure concerns. + +#### P-3: Content Addressability +Assets are stored by their SHA-1 hash, enabling automatic deduplication. If two articles reference the same image, it's stored once. + +**Benefit:** Reduces repository bloat. + +#### P-4: Cryptographic Integrity +Every operation produces a cryptographically signed commit (when `CMS_SIGN=1`). The Merkle DAG ensures tamper detection. + +**Benefit:** Audit trails are mathematically verifiable, not just trust-based. + +### Solution Approach: The "Empty Tree" Stunt + +#### The Problem +Traditional CMSs store content in database rows. Git is designed to track *files*, not arbitrary data. Storing blog posts as files (e.g., `posts/hello-world.md`) clutters the working directory and causes merge conflicts. + +#### The Solution +Store content as **commit messages on empty trees**, not as files. Every article is a commit that points to the well-known empty tree (`4b825dc642cb6eb9a060e54bf8d69288fbee4904`). + +**How It Works:** +1. Encode the article (title, body, metadata) into a Git commit message using RFC 822 trailers. +2. Create a commit that points to the empty tree (no files touched). +3. Update a ref (e.g., `refs/_blog/articles/hello-world`) to point to this commit. + +**Result:** The repository's working directory remains clean. All content lives in `.git/objects/` and `.git/refs/`. + +#### Architectural Pattern: Event Sourcing +Each draft save creates a new commit. The "current" article is the ref's tip, but the full history is a linked list of commits. + +**Benefit:** Point-in-time recovery is trivial (`git log refs/_blog/articles/`). + +### Key Design Decisions + +#### D-1: Why Commit Messages, Not Blobs? +**Alternative:** Store articles as Git blobs and reference them via trees. + +**Decision:** Use commit messages. + +**Rationale:** +- Commits have parent pointers (enabling version history). +- Commits support GPG signing (enabling non-repudiation). +- Blobs are opaque; commit messages are human-readable. + +#### D-2: Why Trailers, Not JSON in Commit Messages? +**Alternative:** Store `{"title": "Hello", "body": "..."}` as the commit message. + +**Decision:** Use RFC 822 trailers (inspired by Linux kernel `Signed-off-by` footers). + +**Rationale:** +- Trailers are Git-native (supported by `git interpret-trailers`). +- They're human-readable and diff-friendly. +- Backward parser is more efficient than Git's own parser. + +#### D-3: Why Encrypt Assets, Not Entire Repos? +**Alternative:** Use `git-crypt` to encrypt the entire repository. + +**Decision:** Encrypt individual assets client-side. + +**Rationale:** +- `git-crypt` requires shared keys across all collaborators. +- Client-side encryption enables row-level access control (different keys for different assets). +- The gateway (git-stargate) never sees plaintext. + +--- + +## 5. Building Block View + +### Level 1: System Decomposition + +```mermaid +graph TD + subgraph "git-cms Application Layer" + CLI[CLI
bin/git-cms.js] + HTTP[HTTP Server
src/server/index.js] + CMS[CmsService
src/lib/CmsService.js] + end + + subgraph "Lego Blocks (@git-stunts)" + Plumbing[@git-stunts/plumbing
Git Protocol Wrapper] + Codec[@git-stunts/trailer-codec
RFC 822 Parser] + Graph[@git-stunts/empty-graph
Graph DB Primitive] + CAS[@git-stunts/cas
Content Store] + Vault[@git-stunts/vault
Secret Management] + end + + CLI --> CMS + HTTP --> CMS + CMS --> Plumbing + CMS --> Codec + CMS --> Graph + CMS --> CAS + CMS --> Vault + Graph --> Plumbing + CAS --> Plumbing + + style CMS fill:#e1f5ff + style Plumbing fill:#fff4e1 + style Codec fill:#fff4e1 + style Graph fill:#fff4e1 + style CAS fill:#fff4e1 + style Vault fill:#fff4e1 +``` + +### Level 2: Lego Block Responsibilities + +```mermaid +graph LR + subgraph "CmsService Orchestration" + CMS[CmsService] + end + + subgraph "@git-stunts/plumbing" + PL_Exec[execute] + PL_Rev[revParse] + PL_Commit[createCommit] + PL_Ref[updateRef] + end + + subgraph "@git-stunts/trailer-codec" + TC_Encode[encode] + TC_Decode[decode] + end + + subgraph "@git-stunts/empty-graph" + EG_Create[createNode] + EG_Read[readNode] + end + + subgraph "@git-stunts/cas" + CAS_Store[storeFile] + CAS_Tree[createTree] + CAS_Retrieve[retrieveFile] + end + + subgraph "@git-stunts/vault" + V_Resolve[resolveSecret] + end + + CMS -->|uses| PL_Exec + CMS -->|uses| PL_Rev + CMS -->|uses| PL_Ref + CMS -->|uses| TC_Encode + CMS -->|uses| TC_Decode + CMS -->|uses| EG_Create + CMS -->|uses| EG_Read + CMS -->|uses| CAS_Store + CMS -->|uses| V_Resolve + + EG_Create -->|calls| PL_Commit + EG_Read -->|calls| PL_Exec + CAS_Store -->|calls| PL_Exec + CAS_Tree -->|calls| PL_Exec + + style CMS fill:#e1f5ff +``` + +### Level 2: Lego Block Responsibilities + +#### Module 1: `@git-stunts/plumbing` (v2.7.0) +**Purpose:** Low-level Git protocol implementation. + +**Public API:** +```javascript +class GitPlumbing { + async execute({ args }) // Run arbitrary Git command + async revParse({ revision }) // Resolve ref → SHA + async createCommit({ tree, parents, message, sign }) + async updateRef({ ref, newSha, oldSha }) // Atomic CAS +} +``` + +**Key Characteristics:** +- Stream-first (async iterators for large outputs) +- Shell-based (no `libgit2` or `nodegit` dependencies) +- Multi-runtime (Node, Bun, Deno) + +**Boundary:** Abstracts `child_process.spawn` and stderr parsing. + +--- + +#### Module 2: `@git-stunts/trailer-codec` (v2.0.0) +**Purpose:** Encode/decode RFC 822 trailers in commit messages. + +**Public API:** +```javascript +class TrailerCodec { + encode({ title, body, trailers }) // → message string + decode({ message }) // → { title, body, trailers } +} +``` + +**Example:** +``` +Input: { title: "Hello", body: "World", trailers: { Status: "draft" } } +Output: + # Hello + + World + + Status: draft +``` + +**Key Algorithm:** +- **Backward parser:** Walks from end of message, stops at first non-trailer line. +- **Normalization:** Lowercases trailer keys (like Git). + +**Boundary:** Encapsulates commit message parsing logic. + +--- + +#### Module 3: `@git-stunts/empty-graph` (v1.0.0) +**Purpose:** Graph database primitive using commits on empty trees. + +**Public API:** +```javascript +class EmptyGraph { + async createNode({ message, parents, sign }) + async readNode({ sha }) // Returns commit message +} +``` + +**Implementation:** +```javascript +async createNode({ message, parents, sign }) { + const emptyTree = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; + return this.plumbing.createCommit({ + tree: emptyTree, + parents, + message, + sign + }); +} +``` + +**Key Insight:** By pointing all commits at the empty tree, the working directory never changes. + +**Boundary:** Abstracts the "empty tree trick." + +--- + +#### Module 4: `@git-stunts/cas` (v1.0.0) +**Purpose:** Content-Addressable Store for large files. + +**Public API:** +```javascript +class ContentAddressableStore { + async storeFile({ filePath, slug, filename, encryptionKey }) + async createTree({ manifest }) // Returns tree OID + async retrieveFile({ manifest, outputPath, decryptionKey }) +} +``` + +**Architecture:** +1. **Chunking:** Split file into 256KB chunks. +2. **Encryption:** AES-256-GCM per chunk (if key provided). +3. **Storage:** Write chunks as Git blobs. +4. **Manifest:** CBOR-encoded list of `{ oid, iv, authTag }`. + +**Example Manifest:** +```javascript +{ + slug: 'hello-world', + filename: 'hero.png', + chunks: [ + { oid: 'abc123...', iv: '...', authTag: '...' }, + { oid: 'def456...', iv: '...', authTag: '...' } + ] +} +``` + +**Boundary:** Handles encryption, chunking, and blob creation. + +--- + +#### Module 5: `@git-stunts/vault` (v1.0.0) +**Purpose:** OS keychain integration for secrets. + +**Public API:** +```javascript +class Vault { + resolveSecret({ envKey, vaultTarget }) + // Returns secret from process.env[envKey] or OS keychain +} +``` + +**Keychain Targets:** +- macOS: `security find-generic-password -s -w` +- Linux: `secret-tool lookup service ` +- Windows: `Get-Credential` (PowerShell) + +**Boundary:** Abstracts OS-specific secret retrieval. + +--- + +### Level 3: CmsService (Domain Orchestrator) + +**File:** `src/lib/CmsService.js` + +**Constructor:** +```javascript +constructor({ cwd, refPrefix }) { + this.plumbing = new GitPlumbing({ runner: ShellRunner.run, cwd }); + this.graph = new EmptyGraph({ plumbing: this.plumbing }); + this.codec = new TrailerCodec(); + this.cas = new ContentAddressableStore({ plumbing: this.plumbing }); + this.vault = new Vault(); +} +``` + +**Key Methods:** +```javascript +async saveSnapshot({ slug, title, body, trailers }) +async publishArticle({ slug, sha }) +async readArticle({ slug, kind }) +async listArticles({ kind }) +async uploadAsset({ slug, filePath, filename }) +``` + +**Orchestration Example:** +```javascript +// saveSnapshot() orchestrates: +// 1. Resolve parent SHA (plumbing.revParse) +// 2. Encode message (codec.encode) +// 3. Create commit (graph.createNode) +// 4. Update ref (plumbing.updateRef) +``` + +**Boundary:** Implements domain logic without knowing Git internals. + +--- + +## 6. Runtime View + +### Scenario 1: Create Draft Article + +**Actors:** Author (CLI), CmsService, GitPlumbing, EmptyGraph, TrailerCodec + +```mermaid +sequenceDiagram + participant Author + participant CLI + participant CmsService + participant TrailerCodec + participant EmptyGraph + participant GitPlumbing + participant Git + + Author->>CLI: echo "# Hello" | git cms draft hello-world "My First Post" + CLI->>CmsService: saveSnapshot({ slug, title, body }) + + CmsService->>GitPlumbing: revParse('refs/_blog/articles/hello-world') + GitPlumbing->>Git: git rev-parse refs/_blog/articles/hello-world + Git-->>GitPlumbing: (ref doesn't exist) + GitPlumbing-->>CmsService: null + + CmsService->>TrailerCodec: encode({ title, body, trailers }) + TrailerCodec-->>CmsService: "# My First Post\n\nHello\n\nStatus: draft" + + CmsService->>EmptyGraph: createNode({ message, parents: [] }) + EmptyGraph->>GitPlumbing: createCommit({ tree: '4b825dc...', message }) + GitPlumbing->>Git: git commit-tree 4b825dc... -m "..." + Git-->>GitPlumbing: abc123def... (commit SHA) + GitPlumbing-->>EmptyGraph: abc123def... + EmptyGraph-->>CmsService: abc123def... + + CmsService->>GitPlumbing: updateRef({ ref, newSha: 'abc123...', oldSha: null }) + GitPlumbing->>Git: git update-ref refs/_blog/articles/hello-world abc123... + Git-->>GitPlumbing: OK + GitPlumbing-->>CmsService: OK + + CmsService-->>CLI: { ref, sha: 'abc123...', parent: null } + CLI-->>Author: "Draft saved: refs/_blog/articles/hello-world (abc123...)" + + Note over CmsService,Git: Time Complexity: O(1)
Objects Created: 1 commit, 1 ref +``` + +**Time Complexity:** O(1) – Single commit creation, single ref update. + +**Git Objects Created:** +- 1 commit object (`abc123def...`) +- 1 ref (`refs/_blog/articles/hello-world`) + +--- + +### Scenario 2: Publish Article + +**Precondition:** Draft already exists at `refs/_blog/articles/hello-world`. + +```mermaid +sequenceDiagram + participant Author + participant CLI + participant CmsService + participant GitPlumbing + participant Git + + Author->>CLI: git cms publish hello-world + CLI->>CmsService: publishArticle({ slug: 'hello-world' }) + + CmsService->>GitPlumbing: revParse('refs/_blog/articles/hello-world') + GitPlumbing->>Git: git rev-parse refs/_blog/articles/hello-world + Git-->>GitPlumbing: abc123def... (draft commit) + GitPlumbing-->>CmsService: abc123def... + + CmsService->>GitPlumbing: revParse('refs/_blog/published/hello-world') + GitPlumbing->>Git: git rev-parse refs/_blog/published/hello-world + Git-->>GitPlumbing: (not published yet) + GitPlumbing-->>CmsService: null + + CmsService->>GitPlumbing: updateRef({ ref: 'refs/_blog/published/hello-world', newSha: 'abc123...', oldSha: null }) + GitPlumbing->>Git: git update-ref refs/_blog/published/hello-world abc123... + Git-->>GitPlumbing: OK + GitPlumbing-->>CmsService: OK + + CmsService-->>CLI: { ref, sha: 'abc123...', prev: null } + CLI-->>Author: "Published: refs/_blog/published/hello-world" + + Note over CmsService,Git: Publishing = Ref Copy (No New Commits)
Idempotent + Fast-Forward Enforced +``` + +**Key Insight:** Publishing is **just a ref copy**. No new commits created. This is idempotent. + +**Fast-Forward Enforcement:** If `oldSha` doesn't match (concurrent publish), Git's `update-ref` fails. + +--- + +### Scenario 3: Upload Encrypted Asset + +**Actors:** Author (HTTP), CmsService, CAS, Vault, GitPlumbing + +```mermaid +sequenceDiagram + participant Author + participant HTTP + participant CmsService + participant Vault + participant CAS + participant Crypto + participant GitPlumbing + participant Git + + Author->>HTTP: POST /api/cms/upload (hero.png) + HTTP->>CmsService: uploadAsset({ slug, filePath, filename }) + + CmsService->>Vault: resolveSecret({ envKey: 'CHUNK_ENC_KEY' }) + Vault->>Vault: Check macOS Keychain + Vault-->>CmsService: Buffer (AES-256 key) + + CmsService->>CAS: storeFile({ filePath, encryptionKey }) + + loop For each 256KB chunk + CAS->>Crypto: AES-256-GCM encrypt(chunk, key, iv) + Crypto-->>CAS: { ciphertext, authTag } + CAS->>GitPlumbing: hashObject({ type: 'blob', content: ciphertext }) + GitPlumbing->>Git: git hash-object -w + Git-->>GitPlumbing: def456... (blob OID) + GitPlumbing-->>CAS: def456... + end + + CAS-->>CmsService: manifest = [{ oid, iv, authTag }, ...] + + CmsService->>CAS: createTree({ manifest }) + CAS->>GitPlumbing: execute(['mktree']) + CBOR manifest + GitPlumbing->>Git: git mktree + Git-->>GitPlumbing: tree123... (tree OID) + GitPlumbing-->>CAS: tree123... + CAS-->>CmsService: tree123... + + CmsService->>GitPlumbing: updateRef('refs/_blog/chunks/hello-world@current', ...) + GitPlumbing->>Git: git update-ref + Git-->>GitPlumbing: OK + GitPlumbing-->>CmsService: OK + + CmsService-->>HTTP: { manifest, treeOid, commitSha } + HTTP-->>Author: 201 Created + + Note over CAS,Git: Security: Plaintext NEVER touches .git/objects/
Only encrypted chunks stored +``` + +**Security Property:** The plaintext file never touches `.git/objects/`. Only encrypted chunks do. + +--- + +### Scenario 4: List All Published Articles + +```mermaid +sequenceDiagram + participant Reader + participant HTTP + participant CmsService + participant GitPlumbing + participant Git + + Reader->>HTTP: GET /api/cms/list?kind=published + HTTP->>CmsService: listArticles({ kind: 'published' }) + + CmsService->>GitPlumbing: execute(['for-each-ref', 'refs/_blog/published/', ...]) + GitPlumbing->>Git: git for-each-ref refs/_blog/published/ --format=... + Git-->>GitPlumbing: refs/_blog/published/hello-world abc123...
refs/_blog/published/goodbye-world 789xyz... + GitPlumbing-->>CmsService: Output (multi-line text) + + CmsService->>CmsService: Parse output into array + CmsService-->>HTTP: [{ ref, sha, slug }, ...] + HTTP-->>Reader: 200 OK + JSON + + Note over CmsService,Git: Time Complexity: O(n)
Performance: Linear scan of all refs +``` + +**Time Complexity:** O(n) where n = number of published articles. + +**Performance Note:** Git's `for-each-ref` is linear. For 10,000 articles, this could be slow. Mitigation: build an external index (e.g., SQLite) that reads from Git log. + +--- + +## 7. Deployment View + +### Infrastructure Overview + +git-cms is designed for **minimal infrastructure**. It can run as: +1. **Local CLI:** Direct Git operations on user's machine. +2. **HTTP Server:** Node.js process serving REST API + static HTML. +3. **Docker Container:** Isolated environment for testing or deployment. + +### Deployment Topology + +#### Topology 1: Single-Author Local Blog + +```mermaid +graph TB + subgraph "Author's Laptop" + CLI[git-cms CLI
Node.js] + Repo[~/blog/.git/
Local Repository] + CLI -->|read/write| Repo + end + + style CLI fill:#e1f5ff + style Repo fill:#fff4e1 +``` + +**Deployment Steps:** +```bash +cd ~/blog +git init +npm install -g git-cms +echo "# My Post" | git cms draft my-post "Title" +git cms publish my-post +``` + +**No Server Required:** All operations are local Git commands. + +--- + +#### Topology 2: Team Blog with Stargate Gateway + +```mermaid +graph LR + subgraph "Author A Laptop" + CMS_A[git-cms CLI] + Repo_A[.git/] + CMS_A --> Repo_A + end + + subgraph "Author B Laptop" + CMS_B[git-cms CLI] + Repo_B[.git/] + CMS_B --> Repo_B + end + + subgraph "VPS (Cloud Server)" + Stargate[git-stargate
Bare Repo + Hooks] + end + + subgraph "GitHub (Public)" + Mirror[Public Mirror
Read-Only] + end + + CMS_A -->|git push
SSH| Stargate + CMS_B -->|git push
SSH| Stargate + Stargate -->|post-receive
mirror| Mirror + + style Stargate fill:#ffe1e1 + style Mirror fill:#e1ffe1 + style CMS_A fill:#e1f5ff + style CMS_B fill:#e1f5ff +``` + +**Component Breakdown:** + +1. **Author Laptops:** + - Run `git-cms` CLI locally. + - Push to `git-stargate` via SSH. + +2. **git-stargate (VPS):** + - Bare Git repository (`~/git/_blog-stargate.git`). + - `pre-receive` hook enforces: + - Fast-forward only (no `git push --force`). + - GPG signature verification. + - `post-receive` hook mirrors to GitHub. + +3. **GitHub (Public Mirror):** + - Read-only public clone. + - CI/CD builds static site from `refs/_blog/published/*`. + +**Deployment Steps:** +```bash +# On VPS (as git-cms user): +git init --bare ~/git/_blog-stargate.git +cd ~/git/_blog-stargate.git/hooks +# Install pre-receive and post-receive hooks from git-stargate repo + +# On Author Laptop: +git remote add stargate git-cms@vps.example.com:~/git/_blog-stargate.git +git config remote.stargate.push "+refs/_blog/*:refs/_blog/*" +echo "# Post" | git cms draft my-post "Title" +git cms publish my-post +git push stargate +``` + +--- + +#### Topology 3: Dockerized Development + +**File:** `docker-compose.yml` + +```yaml +services: + app: + build: + context: . + target: dev + ports: + - "4638:4638" + environment: + - PORT=4638 + - GIT_CMS_ENV=dev +``` + +```mermaid +graph TB + subgraph "Host Machine" + DevMachine[Developer Workstation
macOS/Linux/Windows] + Browser[Web Browser
http://localhost:4638] + end + + subgraph "Docker Container (app)" + NodeApp[Node.js 20
git-cms HTTP Server] + GitBin[Git CLI
Plumbing Commands] + Repo[/app/.git/
In-Container Repo] + + NodeApp --> GitBin + GitBin --> Repo + end + + subgraph "Docker Container (test)" + TestRunner[Vitest
Test Suite] + TempRepos[/tmp/test-repos/
Temporary Git Repos] + + TestRunner --> TempRepos + end + + DevMachine -->|docker compose up app| NodeApp + Browser -->|HTTP:4638| NodeApp + DevMachine -->|docker compose run test| TestRunner + + style NodeApp fill:#e1f5ff + style TestRunner fill:#fff4e1 + style Repo fill:#ffe1e1 +``` + +**Multi-Stage Dockerfile:** + +```mermaid +graph TB + subgraph "Dockerfile Build Stages" + Base[base
node:20-slim + git] + Deps[deps
npm ci + Lego Blocks] + Dev[dev
Development Server] + Test[test
Test Runner] + + Base --> Deps + Base --> Dev + Base --> Test + Deps -.->|COPY --from=deps| Dev + Deps -.->|COPY --from=deps| Test + end + + subgraph "Final Images" + DevImage[git-cms:dev
Runs HTTP Server] + TestImage[git-cms:test
Runs Vitest] + end + + Dev --> DevImage + Test --> TestImage + + style Base fill:#fff4e1 + style Deps fill:#fff4e1 + style Dev fill:#e1f5ff + style Test fill:#ffe1e1 +``` + +```dockerfile +# Base: Node 20 + Git +FROM node:20-slim AS base +RUN apt-get update && apt-get install -y git + +# Deps: Install dependencies +FROM base AS deps +COPY ../git-stunts /git-stunts # Lego Blocks +COPY package.json ./ +RUN npm ci + +# Dev: Development server +FROM base AS dev +ENV NODE_ENV=development +COPY --from=deps /git-stunts /git-stunts +COPY . . +RUN git config --global user.email "dev@git-cms.local" +CMD ["npm", "run", "serve"] + +# Test: Run tests in isolation +FROM base AS test +ENV NODE_ENV=test +COPY --from=deps /git-stunts /git-stunts +COPY . . +CMD ["npm", "run", "test:local"] +``` + +**Deployment Steps:** +```bash +docker compose up app # Start dev server on http://localhost:4638 +docker compose run --rm test # Run tests in isolated container +``` + +**Why Docker?** +- Ensures consistent Git version across dev/test/prod. +- Protects host filesystem from destructive Git operations. +- Simplifies CI/CD (just `docker compose run --rm test`). + +--- + +### Resource Requirements + +| Deployment Type | CPU | Memory | Disk | Network | +|----------------|-----|---------|------|---------| +| CLI (Local) | Negligible | <50MB | 100MB (`.git/objects`) | None | +| HTTP Server | 0.5 vCPU | 256MB | 100MB + repo size | 1Mbps | +| Docker Dev | 1 vCPU | 512MB | 1GB (includes Node + layers) | 10Mbps | + +**Scaling Notes:** +- **Horizontal scaling:** Not applicable (single-writer constraint). +- **Vertical scaling:** Limited by Git performance (mostly I/O bound). + +--- + +## 8. Crosscutting Concepts + +### Concept 1: Merkle DAG as Event Log + +**Pattern:** Every operation creates an immutable commit. The ref is a pointer to the "current" state. + +```mermaid +graph LR + subgraph "Git Object Store (.git/objects/)" + Commit1[Commit abc123
tree: 4b825dc
parent: null
msg: Draft v1] + Commit2[Commit def456
tree: 4b825dc
parent: abc123
msg: Draft v2] + Commit3[Commit 789xyz
tree: 4b825dc
parent: def456
msg: Draft v3] + EmptyTree[Tree 4b825dc...
Empty Tree] + + Commit1 --> EmptyTree + Commit2 --> EmptyTree + Commit2 --> Commit1 + Commit3 --> EmptyTree + Commit3 --> Commit2 + end + + subgraph "Refs (.git/refs/)" + DraftRef[refs/_blog/articles/hello-world] + PubRef[refs/_blog/published/hello-world] + + DraftRef -.->|points to| Commit3 + PubRef -.->|points to| Commit2 + end + + style EmptyTree fill:#ffe1e1 + style Commit3 fill:#e1f5ff + style Commit2 fill:#e1ffe1 +``` + +**Implementation:** +- Drafts: `refs/_blog/articles/` points to latest draft commit. +- Published: `refs/_blog/published/` points to published commit. +- History: `git log ` shows all versions. + +**Benefit:** Event sourcing without Kafka or Event Store. + +--- + +### Concept 2: Compare-and-Swap (CAS) via `git update-ref` + +**Problem:** Prevent concurrent writes from corrupting refs. + +**Solution:** Use `git update-ref --stdin` with expected old value: + +```bash +git update-ref refs/_blog/articles/hello-world +``` + +If `expectedOldSHA` doesn't match, Git returns exit code 1. + +**Implementation:** `src/lib/CmsService.js:95` + +```javascript +await this.plumbing.updateRef({ ref, newSha, oldSha: parentSha }); +``` + +**Concurrency Guarantee:** Atomic at the ref level (not across refs). + +--- + +### Concept 3: Client-Side Encryption (Defense in Depth) + +**Threat Model:** Untrusted Git gateway (e.g., compromised VPS). + +```mermaid +graph TB + subgraph "Client Side (Trusted)" + File[hero.png
Plaintext File] + Chunk1[Chunk 1
256KB plaintext] + Chunk2[Chunk 2
256KB plaintext] + Key[AES-256 Key
from Vault] + + File -->|chunk| Chunk1 + File -->|chunk| Chunk2 + end + + subgraph "Encryption Layer" + Enc1[AES-256-GCM
Encrypt Chunk 1] + Enc2[AES-256-GCM
Encrypt Chunk 2] + + Chunk1 --> Enc1 + Chunk2 --> Enc2 + Key --> Enc1 + Key --> Enc2 + end + + subgraph "Git Objects (Untrusted Gateway)" + Blob1[Blob def456...
Ciphertext 1] + Blob2[Blob 789abc...
Ciphertext 2] + Manifest[Tree + Manifest
CBOR: oids, ivs, authTags] + + Enc1 -->|git hash-object| Blob1 + Enc2 -->|git hash-object| Blob2 + Blob1 --> Manifest + Blob2 --> Manifest + end + + style File fill:#e1f5ff + style Key fill:#ffe1e1 + style Blob1 fill:#fff4e1 + style Blob2 fill:#fff4e1 + style Manifest fill:#e1ffe1 +``` + +**Mitigation:** +1. **Encrypt on write:** Author's machine encrypts asset before `git push`. +2. **Decrypt on read:** Author's machine decrypts after `git pull`. + +**Key Management:** +- Dev: `Vault` retrieves key from macOS Keychain. +- Prod: Key injected via env var (`CHUNK_ENC_KEY`). + +**Cryptographic Primitive:** AES-256-GCM (authenticated encryption). + +**Implementation:** `@git-stunts/cas/src/index.js` + +```javascript +const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, iv); +const encrypted = Buffer.concat([cipher.update(chunk), cipher.final()]); +const authTag = cipher.getAuthTag(); +``` + +--- + +### Concept 4: Zero-Copy Streaming (Performance) + +**Challenge:** Reading large commit logs without loading entire output into memory. + +**Solution:** `@git-stunts/plumbing` uses async iterators: + +```javascript +for await (const line of plumbing.logStream({ ref })) { + console.log(line); +} +``` + +**Benefit:** Constant memory usage, even for repos with millions of commits. + +--- + +### Concept 5: Trailer Normalization (Compatibility) + +**Git's Behavior:** Trailer keys are case-insensitive (`Author` == `author`). + +```mermaid +graph TB + subgraph "Input: Article Data" + Input["title: 'My First Post'
body: 'Hello World'
trailers: { Status: 'draft', Author: 'James' }"] + end + + subgraph "Encoding (TrailerCodec.encode)" + Encode[Normalize Keys
Build Message String] + Input --> Encode + end + + subgraph "Output: Git Commit Message" + Output["# My First Post

Hello World

Status: draft
Author: james"] + Encode --> Output + end + + subgraph "Decoding (TrailerCodec.decode)" + Decode[Backward Parser
Walk from end] + Output --> Decode + end + + subgraph "Parsed Output" + Parsed["title: 'My First Post'
body: 'Hello World'
trailers: { status: 'draft', author: 'james' }"] + Decode --> Parsed + end + + style Encode fill:#e1f5ff + style Decode fill:#ffe1e1 + style Output fill:#fff4e1 +``` + +**Implementation:** `TrailerCodecService` lowercases all keys: + +```javascript +normalizeTrailerKey(k) { + return k.toLowerCase().replace(/-/g, ''); +} +``` + +**Rationale:** Matches Git's own trailer normalization logic. + +--- + +### Concept 6: Fail-Fast Validation (Security) + +**Threat:** Malicious commit messages with oversized trailers (DoS). + +**Mitigation:** Impose hard limits: + +```javascript +const MAX_TRAILER_KEYS = 50; +const MAX_TRAILER_VALUE_LENGTH = 10_000; +``` + +**Enforcement:** `TrailerCodecService.decode()` throws if exceeded. + +--- + +### Concept 7: Ubiquitous Language (DDD) + +| Term | Definition | +|------|------------| +| **Article** | A blog post (title + body + metadata). | +| **Slug** | URL-friendly identifier (e.g., `hello-world`). | +| **Draft** | Unpublished version of an article. | +| **Published** | Article visible to readers. | +| **Snapshot** | A single version in the article's history. | +| **Trailer** | Key-value metadata (e.g., `Status: draft`). | +| **Empty Tree** | Git's canonical empty tree (`4b825dc...`). | +| **Lego Block** | Independent `@git-stunts/*` module. | + +--- + +## 9. Architectural Decisions + +### ADR-001: Use Commit Messages, Not Files + +**Context:** Need to store articles in Git without polluting working directory. + +**Decision:** Store articles as commit messages on the empty tree. + +**Alternatives Considered:** +1. **Files in `posts/`:** Causes merge conflicts, clutters working tree. +2. **Git notes:** Harder to query, no parent pointers. +3. **Blobs in orphan branches:** No GPG signing support. + +**Rationale:** Commit messages support: +- Linear history via parent pointers. +- GPG signing for non-repudiation. +- Human-readable `git log` output. + +**Consequences:** +- ✅ Clean working directory. +- ✅ Full version history. +- ❌ Commit messages limited to ~100KB (Git's internal buffer). + +**Status:** Accepted. + +--- + +### ADR-002: Use RFC 822 Trailers, Not JSON + +**Context:** Need structured metadata in commit messages. + +**Decision:** Use RFC 822 trailers (e.g., `Status: draft`). + +**Alternatives Considered:** +1. **JSON in message:** Not diff-friendly, requires escaping. +2. **YAML front matter:** Not Git-native, requires parser. + +**Rationale:** +- Git already uses trailers (`Signed-off-by`, `Co-authored-by`). +- Human-readable and diff-friendly. +- Backward parser is more efficient than Git's own. + +**Consequences:** +- ✅ Git-native format. +- ✅ Efficient parsing. +- ❌ Limited to key-value pairs (no nested objects). + +**Status:** Accepted. + +--- + +### ADR-003: Fast-Forward Only Publishing + +**Context:** Prevent published content from being altered after release. + +**Decision:** Publishing must be a fast-forward from draft to published ref. + +**Alternatives Considered:** +1. **Allow force updates:** Breaks audit trail. +2. **Separate publish commit:** Creates duplicate content. + +**Rationale:** Fast-forward guarantees: +- Published content is immutable. +- Provenance is verifiable. + +**Enforcement:** `git-stargate` pre-receive hook rejects non-fast-forward pushes. + +**Consequences:** +- ✅ Immutable publications. +- ❌ Cannot "unpublish" (must publish a new version with `Status: deleted`). + +**Status:** Accepted. + +--- + +### ADR-004: Client-Side Encryption for Assets + +**Context:** Git gateways may be untrusted (e.g., hosted VPS). + +**Decision:** Encrypt assets (AES-256-GCM) before `git push`. + +**Alternatives Considered:** +1. **git-crypt:** Requires shared keys, all-or-nothing encryption. +2. **Server-side encryption:** Gateway sees plaintext. + +**Rationale:** +- Row-level encryption (different keys per asset). +- Zero-trust gateway (only receives ciphertext). + +**Consequences:** +- ✅ Defense in depth. +- ✅ Granular access control. +- ❌ Key management complexity. + +**Status:** Accepted. + +--- + +### ADR-005: Shell-Based Git Plumbing, Not libgit2 + +**Context:** Need Git operations in JavaScript. + +**Decision:** Use `child_process.spawn` to call Git CLI. + +**Alternatives Considered:** +1. **nodegit (libgit2):** Native dependencies, build complexity. +2. **isomorphic-git:** Pure JS, but incomplete (no GPG signing). + +**Rationale:** +- Git CLI is stable, well-tested, and available everywhere. +- No native build dependencies. +- Multi-runtime support (Node, Bun, Deno). + +**Consequences:** +- ✅ Zero native dependencies. +- ✅ Multi-runtime compatibility. +- ❌ Slower than libgit2 (process spawn overhead). + +**Status:** Accepted. + +--- + +## 10. Quality Requirements + +### Quality Tree + +``` +git-cms Quality +├── Security (Critical) +│ ├── Cryptographic Integrity (SHA-1, GPG) +│ ├── Client-Side Encryption (AES-256-GCM) +│ └── DoS Protection (Trailer limits) +├── Simplicity (High) +│ ├── Zero Database Dependencies +│ ├── Composable Lego Blocks +│ └── Minimal Lines of Code +├── Auditability (High) +│ ├── Complete Provenance (Git log) +│ └── Trailer Metadata +├── Performance (Medium) +│ ├── Sub-Second Reads (<1s for typical blog) +│ └── Acceptable Writes (<5s for publish) +└── Portability (Medium) + ├── Multi-Runtime (Node, Bun, Deno) + └── Dockerized Tests +``` + +### Quality Scenarios + +#### QS-1: Tamper Detection + +**Scenario:** Attacker modifies published article on Git gateway. + +**Stimulus:** Malicious `git filter-branch` rewriting history. + +**Response:** Readers detect tampered commits via SHA-1 mismatch. + +**Metric:** 100% tamper detection (via Merkle DAG). + +**Test:** +```bash +# Modify commit message +git filter-branch --msg-filter 'sed s/Original/Modified/' +# Push to reader's clone +git pull +# Reader's Git detects non-fast-forward (rejects) +``` + +--- + +#### QS-2: Encrypted Asset Confidentiality + +**Scenario:** Untrusted gateway operator accesses repository. + +**Stimulus:** Admin runs `git cat-file blob ` on encrypted chunk. + +**Response:** Only ciphertext visible (plaintext unrecoverable without key). + +**Metric:** 0% plaintext leakage. + +**Test:** +```bash +# Upload encrypted asset +git cms upload --encrypt hero.png +# Admin views blob +git cat-file blob abc123... +# Output: Binary garbage (AES-256-GCM ciphertext) +``` + +--- + +#### QS-3: Concurrent Publish Conflict + +**Scenario:** Two authors publish the same article simultaneously. + +**Stimulus:** Author A and B both run `git cms publish my-post` at T=0. + +**Response:** One succeeds, one fails with "ref update rejected." + +**Metric:** 100% consistency (no lost updates). + +**Test:** +```bash +# Author A +git cms publish my-post & +# Author B (concurrent) +git cms publish my-post & +# One sees: "Published" +# Other sees: "Error: ref update failed (old SHA mismatch)" +``` + +--- + +#### QS-4: Large Repository Performance + +**Scenario:** Blog with 10,000 published articles. + +**Stimulus:** Reader requests `GET /api/cms/list?kind=published`. + +**Response:** API responds in <2 seconds. + +**Metric:** 95th percentile latency <2s. + +**Bottleneck:** `git for-each-ref` is O(n). + +**Mitigation:** Build external index (e.g., SQLite) in post-receive hook. + +--- + +#### QS-5: Docker Test Isolation + +**Scenario:** Developer runs `npm test` on host machine. + +**Stimulus:** Test creates temporary Git repos in `/tmp`. + +**Response:** Test script aborts with "Run tests in Docker!" + +**Metric:** 0% risk of host filesystem corruption. + +**Enforcement:** `test/run-docker.sh` checks for Docker environment. + +--- + +## 11. Risks & Technical Debt + +### Risk 1: SHA-1 Collision Vulnerability + +**Severity:** Medium +**Likelihood:** Low (but increasing) + +**Description:** Git uses SHA-1 for object addressing. SHA-1 is cryptographically broken (SHAttered attack, 2017). + +**Impact:** Attackers could craft colliding commits to inject malicious content. + +**Mitigation:** +1. **Short-term:** Use GPG signing (`CMS_SIGN=1`) for non-repudiation. +2. **Long-term:** Migrate to Git's SHA-256 mode (available in Git 2.29+). + +**Status:** Monitored. + +--- + +### Risk 2: Repository Growth (Unbounded) + +**Severity:** High +**Likelihood:** High (for active blogs) + +**Description:** Every draft save creates a commit. Over time, `.git/objects/` grows unbounded. + +**Impact:** Slow clones, high disk usage. + +**Mitigation:** +1. **Aggressive GC:** Run `git gc --aggressive` weekly. +2. **Ref Pruning:** Delete old draft refs (keep only last N versions). +3. **Shallow Clones:** Readers use `git clone --depth=1`. + +**Technical Debt:** No automated pruning implemented yet. + +**Status:** Unresolved. + +--- + +### Risk 3: Concurrent Write Conflicts + +**Severity:** Medium +**Likelihood:** Medium (multi-author blogs) + +**Description:** Git's CAS (compare-and-swap) is per-ref, not global. Two authors can create conflicting drafts. + +**Impact:** Lost updates, user frustration. + +**Mitigation:** +1. **git-stargate:** Serialize writes via SSH (single-writer gateway). +2. **Retry Logic:** Client retries `updateRef` on conflict. + +**Technical Debt:** No retry logic in CmsService. + +**Status:** Partially mitigated. + +--- + +### Risk 4: Commit Message Size Limit + +**Severity:** Low +**Likelihood:** Low + +**Description:** Git's `commit-tree` buffers messages in memory (~100KB limit). + +**Impact:** Very long articles (>50,000 words) may fail to save. + +**Mitigation:** Split long articles into multiple parts (e.g., chapters). + +**Technical Debt:** No validation of message size. + +**Status:** Accepted risk. + +--- + +### Risk 5: GDPR Right to Erasure + +**Severity:** High (for EU users) +**Likelihood:** Medium + +**Description:** Git's immutability conflicts with GDPR Article 17 (right to be forgotten). + +**Impact:** Cannot delete historical commits without rewriting history (breaks Merkle DAG). + +**Mitigation:** +1. **Encryption:** Delete encryption key instead of commits. +2. **Legal:** Argue "legitimate interest" (journalistic records). + +**Technical Debt:** No automated key rotation. + +**Status:** Legal review pending. + +--- + +### Technical Debt Summary + +| Item | Priority | Effort | Impact | +|------|---------|--------|--------| +| Implement automated ref pruning | High | Medium | Reduces repo growth | +| Add retry logic to CmsService | Medium | Low | Improves concurrency | +| Validate commit message size | Low | Low | Prevents edge-case failures | +| Migrate to SHA-256 | Low | High | Future-proofs cryptography | +| Build external index for `listArticles` | Medium | High | Scales to 10,000+ articles | + +--- + +## 12. Glossary + +### A + +**AES-256-GCM:** Advanced Encryption Standard with 256-bit keys in Galois/Counter Mode. Provides authenticated encryption (confidentiality + integrity). + +**Append-Only Ledger:** A data structure where records can only be added, never modified or deleted. Git's commit history is an append-only ledger. + +**Atomic Operation:** An operation that either completes fully or not at all (no partial states). Git's `update-ref` is atomic at the ref level. + +### B + +**Bare Repository:** A Git repository without a working directory (only `.git/` contents). Used for servers/gateways. + +**Blob:** A Git object type storing raw file content. Identified by SHA-1 hash of content. + +### C + +**CAS (Compare-and-Swap):** A concurrency primitive ensuring a value is updated only if it matches an expected old value. Git's `update-ref` uses CAS semantics. + +**CAS (Content-Addressable Store):** A storage system where data is retrieved by its cryptographic hash, not by location. Git is a CAS. + +**Chunking:** Splitting large files into fixed-size pieces (e.g., 256KB). Enables streaming and deduplication. + +**Commit:** A Git object representing a snapshot of the repository at a point in time. Contains tree, parent(s), author, message. + +**Ciphertext:** Encrypted data. Unreadable without the decryption key. + +### D + +**DAG (Directed Acyclic Graph):** A graph with directed edges and no cycles. Git's commit history is a DAG (parent pointers form edges). + +**Draft:** An unpublished version of an article, stored at `refs/_blog/articles/`. + +### E + +**Empty Tree:** Git's canonical empty tree object (`4b825dc642cb6eb9a060e54bf8d69288fbee4904`). Points to no files. + +**Event Sourcing:** An architectural pattern where state changes are stored as a sequence of events. Git commits are events. + +### F + +**Fast-Forward:** A Git merge where the target ref simply moves forward (no merge commit). Requires linear history. + +### G + +**GPG (GNU Privacy Guard):** Open-source implementation of OpenPGP. Used for signing Git commits. + +### H + +**Hexagonal Architecture:** A software design pattern separating domain logic from infrastructure (also called "Ports and Adapters"). + +**HMAC (Hash-based Message Authentication Code):** A cryptographic construction for verifying integrity and authenticity. + +### I + +**Immutability:** Property of data that cannot be changed after creation. Git objects are immutable (identified by hash of content). + +### K + +**Keychain:** OS-level secure storage for secrets (passwords, encryption keys). Examples: macOS Keychain, GNOME Keyring. + +### L + +**Lego Block:** In this project, an independent `@git-stunts/*` module with a single responsibility (plumbing, codec, CAS, vault, empty-graph). + +### M + +**Merkle DAG:** A Directed Acyclic Graph where each node is identified by a cryptographic hash of its contents and children. Git's object model is a Merkle DAG. + +**Manifest:** A metadata structure describing chunked file layout. Contains OIDs, IVs, and auth tags for encrypted chunks. + +### N + +**Namespace:** A prefix for Git refs to avoid collisions. Example: `refs/_blog/articles/` vs `refs/_blog/published/`. + +**Non-Repudiation:** Property where the author of a message cannot deny authorship. Achieved via GPG signing. + +### O + +**OID (Object Identifier):** Git's SHA-1 hash of an object (commit, tree, blob, tag). + +**Orphan Branch:** A Git branch with no parent commits (disconnected from main history). + +### P + +**Plumbing:** Git's low-level commands (`commit-tree`, `update-ref`) vs. high-level "porcelain" commands (`commit`, `push`). + +**Porcelain:** Git's user-friendly commands (`commit`, `push`, `pull`) built on top of plumbing. + +**Provenance:** The origin and history of an artifact. Git provides cryptographic provenance via commit chains. + +**Published:** An article visible to readers, stored at `refs/_blog/published/`. + +### R + +**Ref (Reference):** A pointer to a commit (e.g., `refs/heads/main`, `refs/tags/v1.0`). + +**RFC 822:** Internet Message Format standard. Used for email headers and Git trailers. + +### S + +**SHA-1:** Secure Hash Algorithm 1. Produces 160-bit (40-character hex) hashes. Used by Git for object IDs. + +**SHA-256:** Secure Hash Algorithm 2 (256-bit variant). Git's future default. + +**Slug:** A URL-friendly identifier (lowercase, hyphens, no spaces). Example: `hello-world`. + +**Snapshot:** A single version in an article's history (represented as a Git commit). + +### T + +**Trailer:** Key-value metadata at the end of a Git commit message. Example: `Status: draft`. + +**Tree:** A Git object representing a directory (mapping filenames → blob OIDs or subtree OIDs). + +### U + +**Ubiquitous Language:** Domain-Driven Design term for a shared vocabulary between developers and domain experts. + +### V + +**Vault:** In this project, the `@git-stunts/vault` module for retrieving secrets from OS keychains. + +--- + +## Appendix A: Example Commands + +### Draft an Article +```bash +echo "# My First Post" | git cms draft hello-world "My First Post" +``` + +### Publish an Article +```bash +git cms publish hello-world +``` + +### List All Drafts +```bash +git cms list +``` + +### List All Published +```bash +git cms list --kind=published +``` + +### Read an Article +```bash +git cms show hello-world +``` + +### Upload Encrypted Asset +```bash +git cms upload hello-world hero.png +``` + +### Start HTTP Server +```bash +git cms serve +# → Listening on http://localhost:4638 +``` + +--- + +## Appendix B: Directory Structure + +``` +git-cms/ +├── bin/ +│ └── git-cms.js # CLI entry point +├── src/ +│ ├── lib/ +│ │ └── CmsService.js # Core orchestrator +│ └── server/ +│ └── index.js # HTTP API server +├── test/ +│ ├── git.test.js # Integration tests (Vitest) +│ ├── chunks.test.js # Asset encryption tests +│ ├── server.test.js # API tests +│ └── e2e/ # Playwright tests +│ └── publish.spec.js +├── public/ # Static admin UI (vanilla JS) +│ ├── index.html +│ └── app.js +├── docs/ +│ ├── GETTING_STARTED.md +│ ├── REPO_WALKTHROUGH.md +│ └── ADR.md # This document +├── Dockerfile # Multi-stage build +├── docker-compose.yml # Dev/test orchestration +├── package.json # Dependencies +└── README.md # Overview +``` + +--- + +## Appendix C: Related Projects + +### git-stargate +**URL:** https://github.com/flyingrobots/git-stargate +**Purpose:** Git gateway enforcing fast-forward only, GPG signing, and public mirroring. + +### git-stunts (Lego Blocks) +**URL:** https://github.com/flyingrobots/git-stunts +**Modules:** +- `@git-stunts/plumbing` – Low-level Git protocol wrapper +- `@git-stunts/trailer-codec` – RFC 822 trailer parser +- `@git-stunts/empty-graph` – Graph database primitive +- `@git-stunts/cas` – Content-addressable store with encryption +- `@git-stunts/vault` – OS keychain integration + +--- + +## Appendix D: References + +1. **Git Internals (Pro Git Book):** https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain +2. **RFC 822 (Internet Message Format):** https://tools.ietf.org/html/rfc822 +3. **Git Trailers Documentation:** https://git-scm.com/docs/git-interpret-trailers +4. **AES-GCM (NIST SP 800-38D):** https://csrc.nist.gov/publications/detail/sp/800-38d/final +5. **Event Sourcing (Martin Fowler):** https://martinfowler.com/eaaDev/EventSourcing.html +6. **Hexagonal Architecture:** https://alistair.cockburn.us/hexagonal-architecture/ + +--- + +## Conclusion + +**git-cms** demonstrates that Git's plumbing can be repurposed to build systems that shouldn't exist—yet do so elegantly. By treating commits as database records, refs as indexes, and the Merkle DAG as an audit log, we've created a CMS with cryptographic integrity, infinite history, and zero database dependencies. + +This architecture is not "production-ready" in the traditional sense. It violates assumptions about databases, scalability, and best practices. But it teaches us to think differently about constraints, to see tools for what they truly are, and to respect the power of simple primitives composed thoughtfully. + +If Linus saw this, he'd probably sigh, shake his head, and mutter: *"You know what? Have fun."* + +And we are. + +--- + +**End of Document** diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..aaa1c56 --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,484 @@ +# Getting Started with Git CMS + +**⚠️ IMPORTANT: This project manipulates Git repositories at a low level. Always use Docker for testing to protect your local Git setup.** + +--- + +## TL;DR + +```bash +git clone https://github.com/flyingrobots/git-cms.git +cd git-cms +npm run setup # One-time: clones dependencies, checks Docker +npm run demo # See it in action! +``` + +--- + +## Quick Start (Docker - Recommended) + +The safest way to try git-cms is in Docker, which provides complete isolation from your host system. + +### Prerequisites + +- Docker & Docker Compose installed +- 5 minutes of curiosity + +### Step 1: Clone and Run Setup + +```bash +# Clone the repository +git clone https://github.com/flyingrobots/git-cms.git +cd git-cms + +# Run one-time setup (clones git-stunts, checks Docker) +npm run setup +``` + +### Step 2: Try It Out + +**Option A: Watch the Demo (Recommended First Time)** +```bash +npm run demo +``` +This shows you how git-cms works step-by-step. + +**Option B: Start the Server** +```bash +npm run dev +# OR +docker compose up app +``` + +**What just happened?** +- Docker built a containerized environment with Node 20 + Git +- Created an isolated Git repository inside the container +- Started the HTTP server on port 4638 + +### Step 3: Open the Admin UI + +Open your browser to: **http://localhost:4638** + +You should see the Git CMS Admin interface with: +- Sidebar showing "Articles" and "Published" +- A form to create new articles +- Live preview of your content + +### Step 4: Create Your First Article + +**Option A: Via the Web UI** + +1. In the admin UI, enter: + - **Slug:** `hello-world` + - **Title:** `My First Post` + - **Body:** + ```markdown + # Hello World + + This is my first article using Git as a CMS! + + ## How Cool Is This? + + Every save creates a Git commit. Every publish is an atomic ref update. + ``` + +2. Click **"Save Draft"** + - Watch the terminal logs show the Git commit being created + - The article is now at `refs/_blog/articles/hello-world` + +3. Click **"Publish"** + - This fast-forwards `refs/_blog/published/hello-world` to match the draft + - The article is now "live" + +**Option B: Via the CLI (Inside Docker)** + +```bash +# Open a shell inside the running container +docker compose exec app sh + +# Create a draft +echo "# Hello World" | node bin/git-cms.js draft hello-world "My First Post" + +# List all drafts +node bin/git-cms.js list + +# Publish it +node bin/git-cms.js publish hello-world + +# Read it back +node bin/git-cms.js show hello-world + +# Exit the container +exit +``` + +### Step 5: Explore the Git Magic + +The coolest part: this is all just Git under the hood. + +```bash +# Enter the container +docker compose exec app sh + +# Check what Git sees +git log --all --oneline --graph + +# Look at the refs namespace +git for-each-ref refs/_blog/ + +# Read a commit message (this is your article!) +git log refs/_blog/articles/hello-world -1 --format="%B" + +# Exit +exit +``` + +**What you'll see:** +- Your article stored as a commit message +- Commits pointing to the "empty tree" (no files touched!) +- Refs acting as pointers to "current" versions + +--- + +## Understanding the Safety Model + +### Why Docker is Essential + +Git CMS uses **low-level Git plumbing commands** like: +- `git commit-tree` (creates commits on empty trees) +- `git update-ref` (atomic ref updates) +- `git hash-object` (writes blobs directly) + +While these operations are safe *when used correctly*, running tests or experiments on your host machine could: +- Create unexpected refs in your current repository +- Write test blobs to `.git/objects/` +- Modify your Git configuration + +**Docker provides complete isolation** - the container has its own filesystem, its own Git repos, and can be destroyed without a trace. + +### What's Safe? + +✅ **Running in Docker:** Completely safe. Destroy the container anytime with `docker compose down -v` + +✅ **Creating a dedicated test repo:** If you want to try the CLI locally: +```bash +mkdir ~/git-cms-playground +cd ~/git-cms-playground +git init +# Now use git-cms here - it's isolated from your other repos +``` + +❌ **Running tests in your git-cms clone on host:** Not recommended (see next section) + +❌ **Running git-cms commands in your active project repos:** NEVER do this until you understand what's happening + +--- + +## Running Tests + +Tests create and destroy temporary Git repositories. **Always use Docker.** + +```bash +# Run all tests (automatically uses Docker) +npm test + +# This is equivalent to: +./test/run-docker.sh + +# Which runs: +docker compose run --rm test +``` + +**What the tests do:** +- Create temporary repos in `/tmp/git-cms-test-*` +- Test all CRUD operations (create, read, update, publish) +- Test asset encryption and chunking +- Clean up afterward + +**Never run tests on your host** unless you're comfortable with low-level Git operations. + +--- + +## Advanced: Local CLI Installation + +If you want to use git-cms as a command-line tool on your host machine, you can install it globally - **but only use it in dedicated Git repositories.** + +### Install Globally + +```bash +npm install -g git-cms +# OR, from source: +cd git-cms +npm link +``` + +### Create a Dedicated Blog Repo + +```bash +# Create a fresh repo for your blog +mkdir ~/my-blog +cd ~/my-blog +git init + +# Configure Git +git config user.name "Your Name" +git config user.email "you@example.com" + +# Now use git-cms safely +echo "# My First Post" | git cms draft hello-world "Hello World" +git cms publish hello-world +``` + +**Critical:** Only use `git cms` commands in repositories where: +- You understand you're creating commits with empty trees +- You're okay with refs in `refs/_blog/*` namespace +- You've read the docs and understand what's happening + +--- + +## How to Clean Up + +### Stop Docker + +```bash +# Stop containers +docker compose down + +# Stop containers AND delete all data (fresh start) +docker compose down -v +``` + +### Uninstall CLI + +```bash +npm uninstall -g git-cms +# OR, if linked: +cd git-cms && npm unlink +``` + +### Delete a Test Blog Repo + +```bash +# If you created ~/my-blog for testing: +rm -rf ~/my-blog +``` + +--- + +## What's Actually Happening? (The "Stunt" Explained) + +Traditional CMS architecture: +``` +Article → JSON → POST /api → Parse → INSERT INTO posts → Database +``` + +Git CMS architecture: +``` +Article → Commit Message → git commit-tree → .git/objects/ → Git +``` + +### The Empty Tree Trick + +Every article commit points to Git's "empty tree" (`4b825dc642cb6eb9a060e54bf8d69288fbee4904`): + +```bash +# Traditional Git commit +git add article.md # Stage file +git commit -m "Add article" # Commit references changed files + +# Git CMS commit +git commit-tree 4b825dc... -m "Article content here" # No files touched! +``` + +This means: +- Your working directory stays clean +- All content lives in `.git/objects/` and `.git/refs/` +- No merge conflicts from content changes +- Every save is a commit (infinite history) + +### Publishing is Just a Pointer + +```bash +# Draft ref points to latest commit +refs/_blog/articles/hello-world → abc123def... + +# Publishing copies the pointer +refs/_blog/published/hello-world → abc123def... + +# No new commits created! +# Atomic operation via git update-ref +``` + +--- + +## Next Steps + +Once you're comfortable with the basics: + +1. **Read the ADR** (`docs/ADR.md`) for deep architectural details +2. **Try the Stargate Gateway** (enforces fast-forward only + GPG signing) + ```bash + ./scripts/bootstrap-stargate.sh ~/git/_blog-stargate.git + git remote add stargate ~/git/_blog-stargate.git + git config remote.stargate.push "+refs/_blog/*:refs/_blog/*" + git push stargate + ``` +3. **Experiment with encryption** (see below) +4. **Explore the Lego Blocks** in `../git-stunts/` (plumbing, codec, cas, vault, empty-graph) + +--- + +## Asset Encryption (Optional) + +Assets (images, PDFs) can be encrypted client-side before they touch Git. + +### Setup (macOS) + +```bash +# Generate a 256-bit key +openssl rand -base64 32 + +# Store in macOS Keychain +security add-generic-password -s git-cms-dev-enc-key -a $USER -w "" +``` + +### Setup (Linux) + +```bash +# Generate key +openssl rand -base64 32 + +# Store in GNOME Keyring (if available) +secret-tool store --label="Git CMS Dev Key" service git-cms-dev-enc-key +# Paste key when prompted +``` + +### Test Encryption + +```bash +# Inside Docker container +docker compose exec app sh + +# Upload an encrypted file (if you've set up Vault) +node bin/git-cms.js upload hello-world /path/to/image.png + +# The blob in Git is encrypted ciphertext +# Only you (with the key) can decrypt it +``` + +--- + +## Troubleshooting + +### "Permission denied" when running Docker + +**Solution:** Make sure Docker Desktop is running, or add your user to the `docker` group: +```bash +sudo usermod -aG docker $USER +# Log out and back in +``` + +### "Port 4638 already in use" + +**Solution:** Change the port in `docker-compose.yml`: +```yaml +ports: + - "5000:4638" # Maps localhost:5000 → container:4638 +``` + +### "Cannot find module '@git-stunts/...'" + +**Solution:** The Lego Blocks need to be in the parent directory: +```bash +# Ensure directory structure: +~/git/ + git-cms/ ← You are here + git-stunts/ ← Lego Blocks should be here +``` + +If you only cloned `git-cms`, you need to clone `git-stunts` too: +```bash +cd ~/git +git clone https://github.com/flyingrobots/git-stunts.git +cd git-cms +docker compose build # Rebuild with Lego Blocks +``` + +### "Tests fail immediately" + +**Cause:** You might be running tests on your host without Docker. + +**Solution:** Always use: +```bash +npm test # Uses Docker automatically +``` + +--- + +## FAQ + +### Is this production-ready? + +**For small personal blogs:** Yes, with caveats. +**For high-traffic sites:** No. + +This is an educational project demonstrating Git's capabilities. Use it to: +- Learn Git internals +- Build prototype CMS systems +- Understand content-addressable storage + +Don't use it for: +- Mission-critical applications +- Sites with >100 concurrent writers +- Anything requiring complex queries or full-text search + +### Can I use this with GitHub? + +Yes! Use the **git-stargate** gateway to: +1. Enforce fast-forward only (no force pushes) +2. Verify GPG signatures +3. Mirror to GitHub automatically + +See: https://github.com/flyingrobots/git-stargate + +### What about GDPR / right to be forgotten? + +Git's immutability conflicts with GDPR Article 17. Mitigation strategies: +- Use client-side encryption and delete keys (content becomes unreadable) +- Legal argument: journalistic/archival "legitimate interest" +- Don't store PII in articles + +Consult a lawyer before using this for user-generated content in the EU. + +### Why not use a real database? + +That's the point. This is a "Git Stunt" - using Git in unconventional ways to understand: +- How content-addressable storage works +- How to build systems from first principles +- What Git's plumbing can *actually* do + +You're supposed to walk away thinking "I would never use this in production, but now I understand Git (and databases) way better." + +--- + +## Getting Help + +- **Issues:** https://github.com/flyingrobots/git-cms/issues +- **Blog Series:** https://flyingrobots.dev/posts/git-stunts +- **ADR:** `docs/ADR.md` (comprehensive architecture docs) + +--- + +## One Last Warning + +Git CMS is a **thought experiment** that happens to work. It's designed to teach you how Git's plumbing works by building something that shouldn't exist. + +If you're considering using this in production: +1. Read the entire ADR (`docs/ADR.md`) +2. Understand every decision and tradeoff +3. Run it in Docker for at least a month +4. Consider whether a traditional database might be... better + +Then, if you're still convinced, **go for it**. Just remember: when you tell people you're using Git as your database, don't say I didn't warn you. + +Have fun, and remember: _"You know what? Have fun."_ — Linus (probably) diff --git a/package.json b/package.json index 2a96ff5..d39db4a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "scripts": { "serve": "node bin/git-cms.js serve", "dev": "docker compose up app", + "demo": "./scripts/demo.sh", + "quickstart": "./scripts/quickstart.sh", + "setup": "./scripts/setup.sh", "test": "./test/run-docker.sh", + "test:setup": "./test/run-setup-tests.sh", "test:local": "vitest run", "test:e2e": "playwright test" }, diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..82523c9 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,89 @@ +# Scripts + +Helper scripts for working with git-cms safely. + +**All scripts are tested!** See `test/setup.bats` for the test suite. + +## Available Scripts + +### `quickstart.sh` (Recommended for first-time users) + +Interactive menu for trying out git-cms in Docker. Checks prerequisites and guides you through: +- Starting the HTTP server +- Running tests +- Opening a shell in the container +- Viewing logs +- Cleaning up + +**Usage:** +```bash +./scripts/quickstart.sh +``` + +### `demo.sh` (See it in action) + +Automated demo that showcases the key features: +- Creating and editing articles +- Publishing with atomic ref updates +- Viewing Git's perspective on the data +- Exploring version history + +**Usage:** +```bash +./scripts/demo.sh +``` + +This is great for: +- Understanding how git-cms works before diving in +- Recording screencasts or demos +- Verifying the system is working correctly + +### `bootstrap-stargate.sh` (Advanced: Git Gateway) + +Creates a local "Stargate" gateway repository with Git hooks that enforce: +- Fast-forward only updates (no force pushes) +- Optional GPG signature verification +- Mirroring to public repositories + +**Usage:** +```bash +./scripts/bootstrap-stargate.sh ~/git/_blog-stargate.git +git remote add stargate ~/git/_blog-stargate.git +git config remote.stargate.push "+refs/_blog/*:refs/_blog/*" +``` + +See: https://github.com/flyingrobots/git-stargate + +--- + +## Safety First + +All scripts that interact with Git are designed to run in Docker containers to protect your host system. The container provides: +- Isolated Git environment +- Temporary repositories +- No risk to your existing Git repos + +**Never run git-cms commands in repositories you care about until you understand what's happening.** + +--- + +## Testing Scripts + +### `test/run-docker.sh` + +Runs the full test suite in Docker. Called automatically by `npm test`. + +**Usage:** +```bash +./test/run-docker.sh +# OR +npm test +``` + +--- + +## More Info + +- Getting Started Guide: `docs/GETTING_STARTED.md` +- Architecture Decision Record: `docs/ADR.md` +- Main README: `README.md` diff --git a/scripts/demo.sh b/scripts/demo.sh new file mode 100755 index 0000000..1018b87 --- /dev/null +++ b/scripts/demo.sh @@ -0,0 +1,208 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Git CMS Demo Script +# Demonstrates the key features in a safe Docker environment + +echo "🎬 Git CMS Demo" +echo "===============" +echo "" +echo "This demo will show you:" +echo " 1. Creating a draft article" +echo " 2. Publishing it atomically" +echo " 3. Viewing Git's perspective" +echo " 4. Exploring version history" +echo "" +read -p "Press Enter to start..." +echo "" + +# Make sure we're in the right directory +if [ ! -f "package.json" ]; then + echo "❌ Please run this from the git-cms root directory" + exit 1 +fi + +# Check for git-stunts +if [ ! -d "../git-stunts" ]; then + echo "❌ git-stunts not found!" + echo "" + echo "Please run: npm run setup" + exit 1 +fi + +# Check Docker +if ! docker compose &> /dev/null; then + echo "❌ Docker Compose not available" + exit 1 +fi + +echo "📦 Building Docker container (if needed)..." +docker compose build app > /dev/null 2>&1 +echo "✅ Container ready" +echo "" + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📝 Demo 1: Create a Draft" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +echo "Creating an article called 'hello-world'..." +echo "" + +docker compose run --rm app sh -c ' +cat <" + +echo "" +read -p "Press Enter to continue..." +echo "" + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🎯 Demo 6: The DAG Structure" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +echo "Git stores this as a Directed Acyclic Graph (DAG):" +echo "" +docker compose run --rm app sh -c 'git log refs/_blog/articles/hello-world --graph --oneline --format="%h %s"' + +echo "" +echo "Each commit:" +echo " • Points to the empty tree (no files)" +echo " • Has a parent pointer (version history)" +echo " • Contains the article in its commit message" +echo " • Is cryptographically signed (SHA-1 hash)" + +echo "" +read -p "Press Enter to continue..." +echo "" + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "🎉 Demo Complete!" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo "What you just saw:" +echo " ✅ Content stored as commit messages" +echo " ✅ Commits point to empty tree (no files)" +echo " ✅ Publishing is atomic ref update" +echo " ✅ Infinite version history" +echo " ✅ Full Git provenance" +echo "" +echo "This is Git as a database. 🤯" +echo "" +echo "Next steps:" +echo " • Start the server: ./scripts/quickstart.sh" +echo " • Read the guide: docs/GETTING_STARTED.md" +echo " • Read the ADR: docs/ADR.md" +echo " • Explore the code: src/lib/CmsService.js" +echo "" +echo "Clean up this demo:" +echo " docker compose down -v" +echo "" diff --git a/scripts/quickstart.sh b/scripts/quickstart.sh new file mode 100755 index 0000000..921f559 --- /dev/null +++ b/scripts/quickstart.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Git CMS Quick Start Script +# Safely try out git-cms in Docker + +echo "🚀 Git CMS Quick Start" +echo "=====================" +echo "" + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + echo "❌ Docker not found!" + echo "" + echo "Please install Docker Desktop:" + echo " macOS: https://docs.docker.com/desktop/install/mac-install/" + echo " Linux: https://docs.docker.com/engine/install/" + echo " Windows: https://docs.docker.com/desktop/install/windows-install/" + echo "" + exit 1 +fi + +# Check if Docker Compose is available +if ! command -v docker compose &> /dev/null; then + echo "❌ Docker Compose not found!" + echo "" + echo "Docker Compose should come with Docker Desktop." + echo "If you're on Linux, you may need to install it separately." + echo "" + exit 1 +fi + +# Check if Docker daemon is running +if ! docker info &> /dev/null; then + echo "❌ Docker daemon not running!" + echo "" + echo "Please start Docker Desktop and try again." + echo "" + exit 1 +fi + +echo "✅ Docker is ready" +echo "" + +# Check if we have the Lego Blocks +if [ ! -d "../git-stunts" ]; then + echo "⚠️ git-stunts Lego Blocks not found!" + echo "" + echo "Git CMS requires git-stunts to be in the parent directory." + echo "" + echo "Run setup to clone it automatically:" + echo " npm run setup" + echo "" + echo "Or clone manually:" + echo " cd .. && git clone https://github.com/flyingrobots/git-stunts.git" + echo "" + exit 1 +else + echo "✅ git-stunts Lego Blocks found" + echo "" +fi + +# Offer to build or start +echo "What would you like to do?" +echo "" +echo " 1) Start the server (builds if needed)" +echo " 2) Run tests" +echo " 3) Open a shell in the container" +echo " 4) View logs" +echo " 5) Stop and clean up" +echo " 6) Exit" +echo "" +read -p "Choose [1-6]: " choice + +case $choice in + 1) + echo "" + echo "🐳 Starting Git CMS server..." + echo "" + echo "The server will be available at: http://localhost:4638" + echo "" + echo "Press Ctrl+C to stop the server." + echo "" + docker compose up app + ;; + 2) + echo "" + echo "🧪 Running tests in Docker..." + echo "" + docker compose run --rm test + echo "" + echo "✅ Tests complete!" + ;; + 3) + echo "" + echo "🐚 Opening shell in container..." + echo "" + echo "You can now run commands like:" + echo " node bin/git-cms.js draft hello-world \"My First Post\"" + echo " git log --all --oneline --graph" + echo "" + echo "Type 'exit' to leave the shell." + echo "" + docker compose run --rm app sh + ;; + 4) + echo "" + echo "📋 Viewing logs..." + echo "" + docker compose logs -f app + ;; + 5) + echo "" + echo "🧹 Stopping and cleaning up..." + echo "" + docker compose down -v + echo "" + echo "✅ All containers and volumes removed" + ;; + 6) + echo "" + echo "👋 Goodbye!" + exit 0 + ;; + *) + echo "" + echo "❌ Invalid choice" + exit 1 + ;; +esac + +echo "" +echo "🎉 Done!" +echo "" +echo "For more info, see: docs/GETTING_STARTED.md" diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000..6060223 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Git CMS Setup Script +# Ensures git-stunts Lego Blocks are available +# +# This script is tested! See test/setup.bats +# Run tests: npm run test:setup + +echo "🔧 Git CMS Setup" +echo "================" +echo "" + +# Check if we're in the right place +if [ ! -f "package.json" ]; then + echo "❌ Please run this from the git-cms root directory" + exit 1 +fi + +# Check Docker +echo "Checking prerequisites..." +if ! command -v docker &> /dev/null; then + echo "❌ Docker not found. Please install Docker Desktop:" + echo " https://docs.docker.com/get-docker/" + exit 1 +fi + +if ! command -v docker compose &> /dev/null; then + echo "❌ Docker Compose not found. Please install Docker Desktop." + exit 1 +fi + +if ! docker info &> /dev/null; then + echo "❌ Docker daemon not running. Please start Docker Desktop." + exit 1 +fi + +echo "✅ Docker is ready" +echo "" + +# Check for git-stunts +echo "Checking for git-stunts Lego Blocks..." +if [ -d "../git-stunts" ]; then + echo "✅ git-stunts found at ../git-stunts" + echo "" + echo "🎉 Setup complete!" + echo "" + echo "You can now run:" + echo " npm run demo # See it in action" + echo " npm run quickstart # Interactive menu" + echo " npm run dev # Start the server" + echo "" + exit 0 +fi + +# git-stunts not found - offer to clone it +echo "⚠️ git-stunts not found in parent directory" +echo "" +echo "Git CMS requires the git-stunts Lego Blocks to be located at:" +echo " ../git-stunts/" +echo "" +echo "Would you like me to clone it now?" +echo "" +read -p "Clone git-stunts? (y/n) " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "" + echo "Setup cancelled. To set up manually:" + echo "" + echo " cd .." + echo " git clone https://github.com/flyingrobots/git-stunts.git" + echo " cd git-cms" + echo " npm run setup" + echo "" + exit 1 +fi + +echo "" +echo "📦 Cloning git-stunts..." + +# Clone git-stunts to parent directory +cd .. +if git clone https://github.com/flyingrobots/git-stunts.git; then + echo "✅ git-stunts cloned successfully" +else + echo "❌ Failed to clone git-stunts" + echo "" + echo "Please clone manually:" + echo " git clone https://github.com/flyingrobots/git-stunts.git" + exit 1 +fi + +cd git-cms + +echo "" +echo "🎉 Setup complete!" +echo "" +echo "Directory structure:" +ls -ld ../git-cms ../git-stunts | awk '{print " " $9}' +echo "" +echo "You can now run:" +echo " npm run demo # See it in action" +echo " npm run quickstart # Interactive menu" +echo " npm run dev # Start the server" +echo "" diff --git a/test/Dockerfile.bats b/test/Dockerfile.bats new file mode 100644 index 0000000..276f288 --- /dev/null +++ b/test/Dockerfile.bats @@ -0,0 +1,15 @@ +# Dockerfile for running BATS tests +FROM bats/bats:latest + +# Install additional tools needed for testing +RUN apk add --no-cache bash git + +WORKDIR /code + +# Copy test files +COPY test/setup.bats /code/test/setup.bats +COPY scripts/setup.sh /code/scripts/setup.sh +COPY package.json /code/package.json + +# Run BATS tests +CMD ["/code/test/setup.bats"] diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..d34fbfc --- /dev/null +++ b/test/README.md @@ -0,0 +1,234 @@ +# Test Suite + +Git CMS has multiple test suites to ensure everything works correctly. + +## Test Types + +### 1. Setup Script Tests (BATS) + +Tests the `scripts/setup.sh` script to ensure it: +- Validates prerequisites correctly +- Handles missing dependencies gracefully +- Clones git-stunts when needed +- Provides helpful error messages + +**Run:** +```bash +npm run test:setup +``` + +**What it tests:** +- ✅ Fails if not in git-cms directory +- ✅ Checks for Docker installation +- ✅ Checks for Docker Compose +- ✅ Checks if Docker daemon is running +- ✅ Detects existing git-stunts directory +- ✅ Offers to clone git-stunts if missing +- ✅ Handles user accepting/declining clone +- ✅ Handles git clone failures gracefully +- ✅ Shows helpful next steps + +**Test Environment:** +All tests run in Docker using the `bats/bats` image. Each test: +- Creates a temporary directory +- Mocks external commands (docker, git) +- Runs the setup script in isolation +- Cleans up afterward + +### 2. Integration Tests (Vitest) + +Tests the core CMS functionality: +- Article CRUD operations +- Publishing workflow +- Asset encryption and chunking +- Git plumbing operations + +**Run:** +```bash +npm test +# OR +npm run test:local # (not recommended - use Docker) +``` + +**Files:** +- `test/git.test.js` - Git operations +- `test/chunks.test.js` - Asset encryption +- `test/server.test.js` - HTTP API + +### 3. E2E Tests (Playwright) + +Tests the web UI end-to-end: +- Creating articles via UI +- Publishing workflow +- Navigation +- Error handling + +**Run:** +```bash +npm run test:e2e +``` + +**Files:** +- `test/e2e/**/*.spec.js` + +--- + +## Running All Tests + +```bash +# Run everything +npm run test:setup # Setup script tests +npm test # Integration tests +npm run test:e2e # E2E tests +``` + +--- + +## Writing New Tests + +### Adding BATS Tests + +1. Create or edit `test/setup.bats` (or create new `*.bats` files) +2. Follow BATS syntax: + +```bash +@test "description of what this tests" { + run bash scripts/setup.sh + [ "$status" -eq 0 ] # Check exit code + [[ "$output" =~ "expected string" ]] # Check output +} +``` + +3. Run tests: `npm run test:setup` + +### Adding Integration Tests + +1. Create or edit `test/*.test.js` +2. Use Vitest syntax: + +```javascript +import { describe, it, expect } from 'vitest'; + +describe('Feature', () => { + it('should do something', () => { + expect(true).toBe(true); + }); +}); +``` + +3. Run tests: `npm test` + +--- + +## Test Helpers + +### BATS Test Helpers + +Available in `test/setup.bats`: + +```bash +setup() { + # Runs before each test + export TEST_DIR="$(mktemp -d)" +} + +teardown() { + # Runs after each test + rm -rf "$TEST_DIR" +} + +mock_command() { + # Create a mock executable + local cmd="$1" + local exit_code="${2:-0}" + local output="${3:-}" + # ... +} +``` + +### Integration Test Helpers + +Available in test files: + +```javascript +// Create temporary Git repo +const repo = await createTestRepo(); + +// Clean up +await cleanupTestRepo(repo); +``` + +--- + +## Debugging Tests + +### BATS Tests + +```bash +# Run with verbose output +docker run --rm git-cms-setup-tests bats -t /test/setup.bats + +# Run specific test +docker run --rm git-cms-setup-tests bats -f "test name" /test/setup.bats +``` + +### Integration Tests + +```bash +# Run specific test file +docker compose run --rm test npm run test:local -- test/git.test.js + +# Run in watch mode (inside container) +docker compose run --rm test npm run test:local -- --watch +``` + +--- + +## CI/CD Integration + +All tests are designed to run in CI environments: + +```yaml +# Example GitHub Actions +- name: Run setup tests + run: npm run test:setup + +- name: Run integration tests + run: npm test + +- name: Run E2E tests + run: npm run test:e2e +``` + +--- + +## Test Coverage + +Current coverage: + +| Component | Coverage | Notes | +|-----------|----------|-------| +| Setup Script | 100% | All branches tested | +| CMS Service | ~80% | Core operations covered | +| HTTP Server | ~70% | API endpoints tested | +| Web UI | ~50% | Critical paths covered | + +--- + +## Safety Notes + +All tests run in Docker to ensure: +- ✅ Isolated Git environment +- ✅ No impact on host filesystem +- ✅ Reproducible results +- ✅ Easy cleanup + +**Never run tests with `--dangerouslyDisableSandbox` or outside Docker** unless you understand the risks. + +--- + +## More Info + +- **BATS Documentation:** https://bats-core.readthedocs.io/ +- **Vitest Documentation:** https://vitest.dev/ +- **Playwright Documentation:** https://playwright.dev/ diff --git a/test/run-setup-tests.sh b/test/run-setup-tests.sh new file mode 100755 index 0000000..052f6c5 --- /dev/null +++ b/test/run-setup-tests.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run BATS tests for setup.sh in Docker + +echo "🧪 Running setup script tests in Docker..." +echo "" + +# Build the test image +docker build -f test/Dockerfile.bats -t git-cms-setup-tests . + +# Run the tests +docker run --rm git-cms-setup-tests + +echo "" +echo "✅ All setup tests passed!" diff --git a/test/setup.bats b/test/setup.bats new file mode 100644 index 0000000..dfc1179 --- /dev/null +++ b/test/setup.bats @@ -0,0 +1,160 @@ +#!/usr/bin/env bats +# Tests for scripts/setup.sh + +setup() { + # Create a temporary test directory + export TEST_DIR="$(mktemp -d)" + export ORIGINAL_DIR="/code" + + # Copy setup script to test directory + mkdir -p "$TEST_DIR/git-cms/scripts" + cp "$ORIGINAL_DIR/scripts/setup.sh" "$TEST_DIR/git-cms/scripts/setup.sh" + cp "$ORIGINAL_DIR/package.json" "$TEST_DIR/git-cms/package.json" + + # Create mocks directory + export PATH="$TEST_DIR/mocks:$PATH" + mkdir -p "$TEST_DIR/mocks" + + cd "$TEST_DIR/git-cms" +} + +teardown() { + rm -rf "$TEST_DIR" +} + +# Helper: Create a mock Docker that works +mock_docker_working() { + cat > "$TEST_DIR/mocks/docker" <<'EOF' +#!/bin/bash +# Mock docker that passes all checks +if [[ "$1" == "info" ]]; then + echo "Docker info" + exit 0 +fi +echo "Docker version 20.10.0" +exit 0 +EOF + chmod +x "$TEST_DIR/mocks/docker" +} + +# Helper: Create mock git that succeeds at cloning +mock_git_clone_success() { + local test_dir="$TEST_DIR" + cat > "$TEST_DIR/mocks/git" < "$TEST_DIR/mocks/git" <<'EOF' +#!/bin/bash +if [[ "$1" == "clone" ]]; then + echo "fatal: repository not found" + exit 128 +fi +exit 0 +EOF + chmod +x "$TEST_DIR/mocks/git" +} + +@test "setup fails if not run from git-cms directory" { + cd "$TEST_DIR" + run bash git-cms/scripts/setup.sh + [ "$status" -eq 1 ] + [[ "$output" =~ "Please run this from the git-cms root directory" ]] +} + +@test "setup checks for docker command" { + # Remove docker from PATH + export PATH="/usr/bin:/bin" + + run bash scripts/setup.sh + [ "$status" -eq 1 ] + [[ "$output" =~ "Docker not found" ]] +} + +@test "setup checks if docker daemon is running" { + # Mock docker command exists + cat > "$TEST_DIR/mocks/docker" <<'EOF' +#!/bin/bash +if [[ "$1" == "info" ]]; then + # Simulate daemon not running + exit 1 +fi +echo "Docker version 20.10.0" +exit 0 +EOF + chmod +x "$TEST_DIR/mocks/docker" + + run bash scripts/setup.sh + [ "$status" -eq 1 ] + [[ "$output" =~ "Docker daemon not running" ]] +} + +@test "setup succeeds if git-stunts already exists" { + mock_docker_working + + # Create git-stunts directory + mkdir -p "$TEST_DIR/git-stunts" + + run bash scripts/setup.sh + [ "$status" -eq 0 ] + [[ "$output" =~ "git-stunts found" ]] + [[ "$output" =~ "Setup complete" ]] +} + +@test "setup offers to clone git-stunts if not found" { + mock_docker_working + + # Don't create git-stunts + # Simulate user declining (send 'n' to stdin) + run bash scripts/setup.sh <<< "n" + [ "$status" -eq 1 ] + [[ "$output" =~ "git-stunts not found" ]] + [[ "$output" =~ "Clone git-stunts?" ]] + [[ "$output" =~ "Setup cancelled" ]] +} + +@test "setup clones git-stunts if user accepts" { + mock_docker_working + mock_git_clone_success + + # Simulate user accepting (send 'y' to stdin) + run bash scripts/setup.sh <<< "y" + [ "$status" -eq 0 ] + [[ "$output" =~ "Cloning git-stunts" ]] + [[ "$output" =~ "Setup complete" ]] + [ -d "$TEST_DIR/git-stunts" ] +} + +@test "setup fails gracefully if git clone fails" { + mock_docker_working + mock_git_clone_fail + + # Simulate user accepting (send 'y' to stdin) + run bash scripts/setup.sh <<< "y" + [ "$status" -eq 1 ] + [[ "$output" =~ "Failed to clone git-stunts" ]] + [[ "$output" =~ "Please clone manually" ]] +} + +@test "setup shows helpful next steps after success" { + mock_docker_working + + # Create git-stunts + mkdir -p "$TEST_DIR/git-stunts" + + run bash scripts/setup.sh + [ "$status" -eq 0 ] + [[ "$output" =~ "npm run demo" ]] + [[ "$output" =~ "npm run quickstart" ]] + [[ "$output" =~ "npm run dev" ]] +} From 7e1ee2fb111d6a54ecfb87e04c64f329af4b6477 Mon Sep 17 00:00:00 2001 From: "J. Kirby Ross" Date: Sun, 11 Jan 2026 11:21:45 -0800 Subject: [PATCH 3/4] chore: Remove Obsidian dir --- .gitignore | 1 + .obsidian/app.json | 1 - .obsidian/appearance.json | 1 - .obsidian/core-plugins.json | 33 ------- .obsidian/workspace.json | 184 ------------------------------------ 5 files changed, 1 insertion(+), 219 deletions(-) delete mode 100644 .obsidian/app.json delete mode 100644 .obsidian/appearance.json delete mode 100644 .obsidian/core-plugins.json delete mode 100644 .obsidian/workspace.json diff --git a/.gitignore b/.gitignore index 92f5139..20d22e8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ playwright-report/ cms-chunks-*/ cms-upload-*/ git-cms-test-*/ +.obsidian/ diff --git a/.obsidian/app.json b/.obsidian/app.json deleted file mode 100644 index 9e26dfe..0000000 --- a/.obsidian/app.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json deleted file mode 100644 index 9e26dfe..0000000 --- a/.obsidian/appearance.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json deleted file mode 100644 index 639b90d..0000000 --- a/.obsidian/core-plugins.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "file-explorer": true, - "global-search": true, - "switcher": true, - "graph": true, - "backlink": true, - "canvas": true, - "outgoing-link": true, - "tag-pane": true, - "footnotes": false, - "properties": true, - "page-preview": true, - "daily-notes": true, - "templates": true, - "note-composer": true, - "command-palette": true, - "slash-command": false, - "editor-status": true, - "bookmarks": true, - "markdown-importer": false, - "zk-prefixer": false, - "random-note": false, - "outline": true, - "word-count": true, - "slides": false, - "audio-recorder": false, - "workspaces": false, - "file-recovery": true, - "publish": false, - "sync": true, - "bases": true, - "webviewer": false -} \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json deleted file mode 100644 index 2e248e5..0000000 --- a/.obsidian/workspace.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "main": { - "id": "382ef6cb0b37226a", - "type": "split", - "children": [ - { - "id": "a221f72eab71482f", - "type": "tabs", - "children": [ - { - "id": "4b42bcdd58f40569", - "type": "leaf", - "state": { - "type": "empty", - "state": {}, - "icon": "lucide-file", - "title": "New tab" - } - } - ] - } - ], - "direction": "vertical" - }, - "left": { - "id": "25465ee673d3c20e", - "type": "split", - "children": [ - { - "id": "9957cb948538a869", - "type": "tabs", - "children": [ - { - "id": "1bf6d840971c2191", - "type": "leaf", - "state": { - "type": "file-explorer", - "state": { - "sortOrder": "alphabetical", - "autoReveal": false - }, - "icon": "lucide-folder-closed", - "title": "Files" - } - }, - { - "id": "d299a60ce286ca4a", - "type": "leaf", - "state": { - "type": "search", - "state": { - "query": "", - "matchingCase": false, - "explainSearch": false, - "collapseAll": false, - "extraContext": false, - "sortOrder": "alphabetical" - }, - "icon": "lucide-search", - "title": "Search" - } - }, - { - "id": "6f40aa62283a6cfd", - "type": "leaf", - "state": { - "type": "bookmarks", - "state": {}, - "icon": "lucide-bookmark", - "title": "Bookmarks" - } - } - ] - } - ], - "direction": "horizontal", - "width": 300, - "collapsed": true - }, - "right": { - "id": "500be1963bd258e5", - "type": "split", - "children": [ - { - "id": "3bf59e45878ff55f", - "type": "tabs", - "children": [ - { - "id": "fee6fe767f089756", - "type": "leaf", - "state": { - "type": "backlink", - "state": { - "collapseAll": false, - "extraContext": false, - "sortOrder": "alphabetical", - "showSearch": false, - "searchQuery": "", - "backlinkCollapsed": false, - "unlinkedCollapsed": true - }, - "icon": "links-coming-in", - "title": "Backlinks" - } - }, - { - "id": "a3468ed4f299e088", - "type": "leaf", - "state": { - "type": "outgoing-link", - "state": { - "linksCollapsed": false, - "unlinkedCollapsed": true - }, - "icon": "links-going-out", - "title": "Outgoing links" - } - }, - { - "id": "112f4c995c16a506", - "type": "leaf", - "state": { - "type": "tag", - "state": { - "sortOrder": "frequency", - "useHierarchy": true, - "showSearch": false, - "searchQuery": "" - }, - "icon": "lucide-tags", - "title": "Tags" - } - }, - { - "id": "aff00e1ba0272008", - "type": "leaf", - "state": { - "type": "all-properties", - "state": { - "sortOrder": "frequency", - "showSearch": false, - "searchQuery": "" - }, - "icon": "lucide-archive", - "title": "All properties" - } - }, - { - "id": "0a75ab3131feff1a", - "type": "leaf", - "state": { - "type": "outline", - "state": { - "followCursor": false, - "showSearch": false, - "searchQuery": "" - }, - "icon": "lucide-list", - "title": "Outline" - } - } - ] - } - ], - "direction": "horizontal", - "width": 300, - "collapsed": true - }, - "left-ribbon": { - "hiddenItems": { - "switcher:Open quick switcher": false, - "graph:Open graph view": false, - "canvas:Create new canvas": false, - "daily-notes:Open today's daily note": false, - "templates:Insert template": false, - "command-palette:Open command palette": false, - "bases:Create new base": false - } - }, - "active": "4b42bcdd58f40569", - "lastOpenFiles": [ - "docs/ADR.md" - ] -} \ No newline at end of file From a43496da626b19bcbb0182df649aa2e7ce8d8e35 Mon Sep 17 00:00:00 2001 From: "J. Kirby Ross" Date: Mon, 12 Jan 2026 08:00:00 -0800 Subject: [PATCH 4/4] docs: add formal LaTeX ADR and update test harness - Introduce `docs/adr-tex-2/`: A comprehensive Architecture Decision Record implemented in LaTeX. - Document core architectural principles: "Zero-Database," "Empty Tree" commits, and the `@git-stunts/*` module decomposition. - Add TikZ figures for System Context, Component Decomposition, Runtime Sequences, and Deployment Topologies. - Add `Makefile` for PDF compilation and update `.gitignore` for LaTeX build artifacts. - Update `test/setup.bats`: Adjust assertions to match specific prompt text ("Would you like me to clone it now") and enable debug logging for the setup script test. --- .gitignore | 6 + docs/adr-tex-2/Makefile | 8 ++ docs/adr-tex-2/figures/context.tex | 12 ++ docs/adr-tex-2/figures/decomposition.tex | 21 ++++ docs/adr-tex-2/figures/draft-sequence.tex | 18 +++ docs/adr-tex-2/figures/responsibilities.tex | 17 +++ docs/adr-tex-2/main.pdf | Bin 0 -> 340580 bytes docs/adr-tex-2/main.tex | 113 ++++++++++++++++++ docs/adr-tex-2/meta.tex | 5 + docs/adr-tex-2/sections/01-introduction.tex | 64 ++++++++++ docs/adr-tex-2/sections/02-constraints.tex | 47 ++++++++ docs/adr-tex-2/sections/03-context.tex | 93 ++++++++++++++ docs/adr-tex-2/sections/04-solution.tex | 62 ++++++++++ .../adr-tex-2/sections/05-building-blocks.tex | 21 ++++ docs/adr-tex-2/sections/06-runtime.tex | 20 ++++ docs/adr-tex-2/sections/07-deployment.tex | 58 +++++++++ docs/adr-tex-2/sections/08-crosscutting.tex | 56 +++++++++ docs/adr-tex-2/sections/09-decisions.tex | 47 ++++++++ docs/adr-tex-2/sections/10-quality.tex | 24 ++++ docs/adr-tex-2/sections/11-risks.tex | 21 ++++ docs/adr-tex-2/sections/12-glossary.tex | 12 ++ docs/adr-tex-2/sections/A-commands.tex | 21 ++++ docs/adr-tex-2/sections/B-structure.tex | 17 +++ docs/adr-tex-2/sections/C-related.tex | 12 ++ docs/adr-tex-2/sections/D-references.tex | 7 ++ test/setup.bats | 8 +- 26 files changed, 789 insertions(+), 1 deletion(-) create mode 100644 docs/adr-tex-2/Makefile create mode 100644 docs/adr-tex-2/figures/context.tex create mode 100644 docs/adr-tex-2/figures/decomposition.tex create mode 100644 docs/adr-tex-2/figures/draft-sequence.tex create mode 100644 docs/adr-tex-2/figures/responsibilities.tex create mode 100644 docs/adr-tex-2/main.pdf create mode 100644 docs/adr-tex-2/main.tex create mode 100644 docs/adr-tex-2/meta.tex create mode 100644 docs/adr-tex-2/sections/01-introduction.tex create mode 100644 docs/adr-tex-2/sections/02-constraints.tex create mode 100644 docs/adr-tex-2/sections/03-context.tex create mode 100644 docs/adr-tex-2/sections/04-solution.tex create mode 100644 docs/adr-tex-2/sections/05-building-blocks.tex create mode 100644 docs/adr-tex-2/sections/06-runtime.tex create mode 100644 docs/adr-tex-2/sections/07-deployment.tex create mode 100644 docs/adr-tex-2/sections/08-crosscutting.tex create mode 100644 docs/adr-tex-2/sections/09-decisions.tex create mode 100644 docs/adr-tex-2/sections/10-quality.tex create mode 100644 docs/adr-tex-2/sections/11-risks.tex create mode 100644 docs/adr-tex-2/sections/12-glossary.tex create mode 100644 docs/adr-tex-2/sections/A-commands.tex create mode 100644 docs/adr-tex-2/sections/B-structure.tex create mode 100644 docs/adr-tex-2/sections/C-related.tex create mode 100644 docs/adr-tex-2/sections/D-references.tex diff --git a/.gitignore b/.gitignore index 20d22e8..fd7b939 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,9 @@ cms-chunks-*/ cms-upload-*/ git-cms-test-*/ .obsidian/ + +# LaTeX artifacts +*.aux +*.log +*.out +*.toc diff --git a/docs/adr-tex-2/Makefile b/docs/adr-tex-2/Makefile new file mode 100644 index 0000000..cfa4838 --- /dev/null +++ b/docs/adr-tex-2/Makefile @@ -0,0 +1,8 @@ +all: main.pdf + +main.pdf: main.tex $(wildcard sections/*.tex) $(wildcard figures/*.tex) + pdflatex -interaction=nonstopmode main.tex + pdflatex -interaction=nonstopmode main.tex + +clean: + rm -f *.aux *.log *.out *.toc *.pdf diff --git a/docs/adr-tex-2/figures/context.tex b/docs/adr-tex-2/figures/context.tex new file mode 100644 index 0000000..ac296f9 --- /dev/null +++ b/docs/adr-tex-2/figures/context.tex @@ -0,0 +1,12 @@ +\begin{tikzpicture}[node distance=2cm, auto] + \node [block] (Author) {Author\\(Human)}; + \node [block, below=1cm of Author] (GitCMS) {\textbf{git-cms}\\(Node.js App)}; + \node [block, right=2cm of GitCMS] (Stargate) {git-stargate\\(Git Gateway)}; + \node [block, below=1cm of GitCMS] (LocalRepo) {.git/objects/\\(Local Repository)}; + \node [block, right=2cm of Stargate] (PublicMirror) {Public Mirror\\(GitHub/GitLab)}; + + \draw [line] (Author) -- node [align=center, scale=0.8] {CLI/HTTP API} (GitCMS); + \draw [line] (GitCMS) -- node [scale=0.8] {git push} (Stargate); + \draw [line] (GitCMS) -- node [scale=0.8] {read/write} (LocalRepo); + \draw [line] (Stargate) -- node [scale=0.8] {mirror} (PublicMirror); +\end{tikzpicture} \ No newline at end of file diff --git a/docs/adr-tex-2/figures/decomposition.tex b/docs/adr-tex-2/figures/decomposition.tex new file mode 100644 index 0000000..1c7c121 --- /dev/null +++ b/docs/adr-tex-2/figures/decomposition.tex @@ -0,0 +1,21 @@ +\begin{tikzpicture}[node distance=1.5cm, auto] + \node [blockshaded] (CMS) {\textbf{CmsService}\\\texttt{src/lib}}; + \node [block, above left=1cm and 0.5cm of CMS] (CLI) {CLI\\\texttt{bin/git-cms.js}}; + \node [block, above right=1cm and 0.5cm of CMS] (HTTP) {HTTP Server\\\texttt{src/server}}; + \node [draw, dashed, thick, inner sep=10pt, fit=(CLI) (HTTP) (CMS)] (AppLayer) {}; + \node [anchor=south] at (AppLayer.north) {\small\textbf{Application Layer}}; + + \node [block, below=1.5cm of CMS] (Graph) {Graph\\empty-graph}; + \node [block, left=0.5cm of Graph] (Codec) {Codec\\trailer-codec}; + \node [block, right=0.5cm of Graph] (CAS) {CAS\\cas}; + \node [block, below=1cm of Graph] (Plumbing) {Plumbing\\git-protocol}; + \node [block, right=0.5cm of CAS] (Vault) {Vault\\secrets}; + \node [draw, dashed, thick, inner sep=10pt, fit=(Plumbing) (Codec) (Graph) (CAS) (Vault)] (LegoLayer) {}; + \node [anchor=north] at (LegoLayer.south) {\small\textbf{Lego Blocks (@git-stunts)}}; + + \draw [line] (CLI) -- (CMS); \draw [line] (HTTP) -- (CMS); + \draw [line] (CMS) -- (Codec); \draw [line] (CMS) -- (Graph); + \draw [line] (CMS) -- (CAS); \draw [line] (CMS) -- (Vault); + \draw [line] (CMS) -- (Plumbing); \draw [line] (Graph) -- (Plumbing); + \draw [line] (CAS) -- (Plumbing); +\end{tikzpicture} \ No newline at end of file diff --git a/docs/adr-tex-2/figures/draft-sequence.tex b/docs/adr-tex-2/figures/draft-sequence.tex new file mode 100644 index 0000000..ccca1b0 --- /dev/null +++ b/docs/adr-tex-2/figures/draft-sequence.tex @@ -0,0 +1,18 @@ +\begin{tikzpicture}[node distance=3cm, auto] + \node (Author) {Author}; + \node [right=of Author] (CLI) {CLI}; + \node [right=of CLI] (CMS) {Service}; + \node [right=of CMS] (PL) {Plumbing}; + + \foreach \n in {Author, CLI, CMS, PL} { + \draw [dashed] (\n) -- ++(0,-6.5); + } + + \draw [->] ($(Author)+(0,-1)$) -- node [scale=0.7] {draft hello-world} ($(CLI)+(0,-1)$); + \draw [->] ($(CLI)+(0,-1.5)$) -- node [scale=0.7] {saveSnapshot()} ($(CMS)+(0,-1.5)$); + \draw [->] ($(CMS)+(0,-2.2)$) -- node [scale=0.7] {revParse(ref)} ($(PL)+(0,-2.2)$); + \draw [<-] ($(CMS)+(0,-3)$) -- node [scale=0.7] {null} ($(PL)+(0,-3)$); + \draw [->] ($(CMS)+(0,-4)$) -- node [scale=0.7] {createNode()} ($(CMS)+(0.8,-4.2)$); + \draw [->] ($(CMS)+(0,-5)$) -- node [scale=0.7] {updateRef()} ($(PL)+(0,-5)$); + \draw [<-] ($(CLI)+(0,-6)$) -- node [scale=0.7] {OK} ($(CMS)+(0,-6)$); +\end{tikzpicture} \ No newline at end of file diff --git a/docs/adr-tex-2/figures/responsibilities.tex b/docs/adr-tex-2/figures/responsibilities.tex new file mode 100644 index 0000000..ad4a4a2 --- /dev/null +++ b/docs/adr-tex-2/figures/responsibilities.tex @@ -0,0 +1,17 @@ +\begin{tikzpicture}[node distance=1cm, auto, font=\small] + \node [blockshaded, text width=2.5cm, minimum height=8cm] (CMS) {\textbf{CmsService}}; + \node [block, text width=4.5cm, right=3cm of CMS.north, anchor=north] (PL) {\textbf{@git-stunts/plumbing}\\execute, revParse}; + \node [block, text width=4.5cm, below=0.5cm of PL] (TC) {\textbf{@git-stunts/trailer-codec}\\encode, decode}; + \node [block, text width=4.5cm, below=0.5cm of TC] (EG) {\textbf{@git-stunts/empty-graph}\\createNode, readNode}; + \node [block, text width=4.5cm, below=0.5cm of EG] (CAS) {\textbf{@git-stunts/cas}\\storeFile, retrieveFile}; + \node [block, text width=4.5cm, below=0.5cm of CAS] (V) {\textbf{@git-stunts/vault}\\resolveSecret}; + + \draw [line] (CMS.east |- PL.west) -- (PL.west); + \draw [line] (CMS.east |- TC.west) -- (TC.west); + \draw [line] (CMS.east |- EG.west) -- (EG.west); + \draw [line] (CMS.east |- CAS.west) -- (CAS.west); + \draw [line] (CMS.east |- V.west) -- (V.west); + + \draw [dashed-line] (EG.east) -- ++(0.5,0) |- (PL.east); + \draw [dashed-line] (CAS.east) -- ++(0.5,0) |- (PL.east); +\end{tikzpicture} diff --git a/docs/adr-tex-2/main.pdf b/docs/adr-tex-2/main.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4d4dad2a4fcd1235da2e6494c5583e77f31aadb6 GIT binary patch literal 340580 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 z zJwwBuR7$)TV1=L66+`M<9QxG&Ud^FMVw~!w^B)9EJUEdbn#-Qwc0DrNA0WcFvJ>eq z&F+4~LYAF+W5INTErZE)&#w~#OTtP3@q3kI;gV_4vmY_yfB7ya-xpGM^^Vh}nLYDk zKxCcdLX6wZ_Zly#pk1{Sh#Jd-EAFT!d|BEAT#2fg1@WdN+cE89gmy4(4}hc@^lxST z+O{}ItFa8-05?PLM-$e*@)Y+CS|M4tDH*vVJrICG;V#89UV1s9D&WQ^YU_Vfe)9SfDgZ=PxNNAi^_{fyP0n9r@F%+{3$CD z#&Q=Au1N~*gSJQh&W?{hNz6St9A361Kn$V8}HW;Y8(lH zH8bqdeV9*xNtn(WKub3i<79uUb&EMeoLGglMnUboHkR|T@uFTNfJ3|o^|Enra>h*q zOQEd{VZkU>YIR*g9PNM3I)bLQ)l`W^SCje(FoX=gB3CMJYx3+wjp+#I2lBJsO{Cl) zE9m4$So?VLk#$CWp1m^)BD#nN_W!ugs%u6I@<)&#tBJ8Q~9x^0Qcs zxaS_E|3DB1+?8ODa^v+brlNm@(y_mtHO zOL>>h#F%?{5z@u?6LCB==Ni@BwCkB9^g5B)O;sEtAj<$x7S+fz)-g50RJ#iNwhs9N zbO92$$qD+VY==Sv&QGh$_0;-At&2((RlL5|{Y(Y(*i+ z=j0Y^4KqrdAO6ByOdbS-hvAfk7w1d|8xTrghUHmqqdn@*sw^bT zc9Bu^bpO%*Xqq-uI%qdSuBN`y=umb8*xp+~hSw!@IE_kMn>prxRu7v`p(P$Wc9u4-Oq;CkfMw_WcIrirzI_$)?%?B1XrQnu5YZ*RP9cSbBW|Pc7u+_R^!& zv2L-_v1FiVs*l=QG@t$;IxslZrCZv?OJ$Y>m%n4q$9LC^{tC$pyMTpc_vep*#BTzI1{GV61af+^}ZT7^2WMGi&O3d-(bvB>V_;dG>_YJ=P7kW<>I zI0k9ujuZs2Bm-|ug+*FFdeLNj9iUGIaYsJO=xhS48luD;`q#f?JkK zNl=tvoU0-M#Av#GyUb@$O7dKrh64yarvub9Je^Jcv9^T4>!xe&+HEnGo>`4pl6`Pq zxfF;1U-cY&X4yhgLZ=(}kEaWeVFBd$;BHAL8^E*YF1y0xy79R_U^Z^GJnDbF5JOj5`AoE9&}reU)AzQ z25b0!<<<|W0i)CGNLFh;@{S*luCoEIhtE}FN} z5<0ctzx5+H#OWDLfn!f&JF-VnJ-!WX4(rV%o7tM=)Srj-GXVNfv}&iPsml{%mPYnB zD?T>d=dR|y8cS;S9Hy11N0B>S=)HVJB5m`S+v@v`8Ju4K5LQaAp=z0<=^4P|4ONep z(aNp{wj{fNn^8SjY9bdGEUi0f%SQRfXw@UxMNFI59lrv*4sF<$io7FuW_&^>>>aBm z6=cFk@sI#09p~_x{wf<|>ssp%ye%|Vfno`>3Pf(>bhRop0KBVz8>he8*wySe4UZe+@NK6&$T~zL zNuohTmWxs+dDRu9as-xvrzCe%LQe?z(kP=L@I&iRv1Buak!SGjnyfsGLNK=`HirA$ z0|?cedi~@!Arf{p&0C)+UFsQc!QS&zn$4{>%i1|^4*|e>P5%=Y&GA2R(d?Z67lr=c zTr>+K+y615|6eYeg`M;NgNxRg?y@E5;2y+wcZa=2+b#?o+u7mm_z#c{-$&cl4dw<3 z-{)z1<9(ap_1`;RP*SvfJ}g$IM}g( zVQ>MT2+Rqfx^*Kk13_=1E^d8BvDCK{q3m=u-W}$F9n{c z?%DcV_H_S7rXw#SDk-X@7@K)FhXXJRfSwp!_?F-JJC8l=Wgg(y_J(J5Y-s(h1_+p% znVgIZPh418NgZ6?Scn{49ZVUVyR83JnVG=_tZRcy3wUz}Pe47VH_EY%*}HII0{+R} z|5pTHG8-$v7FWP8c-ZETUAtH51MfAS``g~=PL%U|-151FyAJ{Mqm9X2aHQYZ6cyD3 zU|rA|i#!2lVf=i14&vhE27>V&+RHCEmg3J20TjW(&GB7H_y(Um{FnA2el^r~$Gp_| z_zc$ddlm&~n}f^y8=CE(-wKxQ`Vz%!i^BepT3w)NFp9qz&JJh|2H zTyk=4F!#~lLThPkZFTI~->B@2ZH(+MgZ;J5c!ia*-5pF4(hvTfJH%~%2IU0g00_Va zuz;PIS&aYGPiY!I!xR2{E||SMw>EbGnZW1z zMj5+^>RbM&$3P5T0XV;4zqy#B{NTg-S>~VQs(;Q#zpQF*P7SRfmD$++{@UNs(Kz#y zgWIy%7rG5Ickf?E`1vk>wE!RdZ=3xh(9m05o{P=Q&A{iH9i0F(I5s%|W@cz^cmC0= zpI`T%*3CWj7yM)Xa&Q0;$6!oB+IkJFhpT^9gam8gkiI z<6k6M&9XqBI{SY+^tnX?YHCU1YvhxAWfH+W5KEW;@z0G;k7MuA`*8E(bKvljG8Qb_ zv4X4wx^|QGHOV2L5?tK!%^9|2y{vVq2nAeTG($VPF9@Sd4`E&}u_EO)uC(ZjtqyUW zn8Slmv$l|+?ZEbyRlqYBH-N-sNbA%sGR)Qq=s~Phu%>HEp?(U5=3%d#PmWl~AE>&_ zJ?Ux@s};@|zMvFUNwATDtpCjmM~5!Ks=FgnCcNM=VoOF5vowaJBN9Omhu*7-FgqlW z#esTLEQsBPl(?ii9#lI?19w2TEu8{>Mz#z&_*?LOFsKQcb{~L6WC_%F5+kTp#rpz> zQ8A|>BFD-l0$s$Y87Y?>a)AW3cW)>kvMVgoy?kCIn@<3kTVRszLCvjf)|n}ek1!$S3r^pmLR-vaT8`EGX-VNrlZswoEcegG z1FMJxsT(3q!4f7w_-Z!h9ML16SXMD6U}1h!2@yS~U{`7r>AJ&;(rca4U}%H#LC9Gl zT8Qfr)_aF)mF=MHc8b$OR^WoxGv-=8EMA=uV-ug&W*LF+nx3wcMsDnMy%`E>h--Z2 zw8HtB#lBzCQUKChwXx*sEzbB<1lsEfxSV%5cwrNpYS3AkQyrRjVqxDog{5?Xmcx)S zZWGUqo?z=)^SRk%c&ednXcnERcV$N(1KLOXf69E}>ONemOR@U7eHKB_O z5Gpdi((J4UfThi@tTecaVJyNusCxGZH4M-p*Q`WO{mH(OaT)1l$RGl;+852!(!kx& zFPy3`UtckLR7lr+LVrDz_<&|C=*{xM0_F?tpny?p9$`7FAy(_#PZs_H7rn%}`cj)L zZhG)eQD*=ZwcVa z!BHJyb&W%{LI?4DLdS$CU|~@)%6i=DSn-Wdm^+(Nf}*MpwGHe}lv;pYPL8#08D8s> zQl7x)1R)KaAI}H8s+#<1l=+N+J&JPa|Zc>`O86Z}= zWUev!sTG9 zn=mZt&RKtr2+qmGZT_ph47anAMYrY4?xC>t#cL&F!FmJO`#>&37~63C)MYS(yq_AR zN&>M-;9dBt>e*O7-kFv3zlw1seNCRcG@F-s->)LZhUBoK{)vPLl*c#v{fjD|6IDy^ z*fRNWS-AeMfAG1DMPhmf7L1C%(+jn5XPd~RU!&c&VDX{M`Who$F~Ka)YgMJ|XNmr? zhh~vjEwD_hp}ZbfR(e1mp_`I7v)64QoU<~@?e``M`hj|6CSSJALxCid#ZSLcX}M92 za&O%stN_)N4AMf#_W_z5L*#RpXPv|*i;FZXwR<>CNj=^eiGb4T)El59rH4j3{^_8g z0{^gN%3K!4o+x!_D(;#Z&ppY;Emwz}O2^*LnG}mB?NYs!L6u-;{|mjF*epFtQQ% zH^*qa@St~{c!OSdK23Y$Q=Pxms0_8Myj zH^ORIa#F^AG8zXIAeMCRkkr*UAqff_^)@89-es!qMuIDrEmH{+MMVWfpt>^?q442C zjF^d?1vMH@X0x`Hu1la``!4ptUcKyLq-aRu`JW83mb_85IEk6UJnZ-6tEk7tWtoV% zjQUfvDZRUtN1+2{E%MaCkd7)q&yPi)G4y&Bvs`1!tNv9GzQKzKP-iE%;yn)=Ncp!5-oUPT5 zN&S!S(|I_pj2dlv1W4ekMy4~KO%5kayVdksi$aLqPZJ#?+%%TJbK6U#YTHF(;Jb+bzgl+G%*z}(E!WC$69))=VbQw7{0FEftQkTn>(h;uE}@41Yw-+%!>c= zFke@T^8keZdwM(DT)0XSc9*4} zUlGDf#vL;%xcsHQ-#Gy^g-H{MOL#NH0{;<{hxN+u=VC^L_uqL-_ z9RG#>DkdLpK7@M>AtO{Sa^18mcoKsD%6!E=8&xkxV#DNeh<91mw0mzTslMuT?9*}0 zi7y|qV_MnG{&6#%i`N%ATvqtwhYMKsjkVTUNaK0ykorOt#nn`la_i8;TZ8s-VmS*& zWy(&XH1B9XH*ItVdq5t{rn2q^Od5wbrm&UH>(uh>s5`%Ku)JzgUjh`&8yqLQRi*Pv z;jbL>Y#PnP1Z(kVrRL}m(({qe95EYS4c@?dEc(Ijc$N3$Iq-&W3%8_>@6|>33MmyE z$*;)&OccITkx_VgQ!uQMQMe@4rs+-|=wZ%=NeFZf;aE6+@>T2O`~GTU>lFW3VmepN*M?FLtu8 zU@z=nNuN%`39m#paKZ#+Or$3cQ06L3ngK4ej;fJa5Gm^8hBfw6L{hZxa-@$bn9Cai zVrElBoGTit^kN8m_n(wk6EI_!L>K+PJIK$s0`ivhx>HtG`P3UQfat_XLVBtmD z8}pK&pcgpQ)94I+E=xTUk02!C^UPYi)Z5A!e8s`~Stx;qgr2bos|r;Mf`17;b1TM+`rYZ7diP#t$CMB!R?ZD6iNs+P zYO2Pq#7h^RVp7|B-#=OtN0KQ7HtqG7zBu^Ly5!K7l2W0U(QQw854$?YY=qC0!2b(5 zK*qmth+C{0x9WtTj7z=qLo@|P5L(e;$yGWTUerk863s~@XUO6hUH5v?7g5@n%p-CP zDi%gpqCQO1$8g|Dc_?uYn{j#>qlP-$F2rsHk0UR9LL~pCcjbCJEqXfmdR`(_M=55v zwuiElY4u|@zCu3@^xLmET5TjVR0t|w=HdhOt@HrRRe_J9&;B{H7q_r;$=q?41l8fI z`!}?xN>&4U3|mI!IEVBv<956;2mWW)&;~Hs$>2N7!cYQmrqxPPXZIOof>M2xIBxgP z_joMYG&|xX!y5@5+O;uUEET)g9gPB2CSJk_d#>2M*=KO_9ITlpsb3q8Xb$L1!U_{< z0+5E3x!nA0Gi9!h27MbW`r%rSmRQ^*!8`Nb3fiTc`^taqo?47ky^7r z_yo)F8@q9BaRZX>{Y|6@pHAUEj=#-g$sTfCG0L2FjTpUK((7DX+^Jluy*R*@ToOOA zdpOx%ijWZ9KjW^L(<8zb9;JOYWI8MQL|Bel$(}aI*4znOT-Zb z?rpBO3o9vE29^x2vPedc`DlFT7*%qASWfmThOw_YeCM9-;8oQ$ER+I^)-RnMH{HcR zk*M%x`m<|zRG8xLu`C1mr4t`tqTG}EtR;O#9lI)j`82u$*BzxicqK`)PSW}@b}z__ zFlkL@ha}>pzW*k0mlSo)5^&CM3_U#wtv+&<`xtP;CJx&ap%XCye8I``jK*qjt0wXethUMwzh%7nZ+OVgeRE%&Lf*LlYUC8VnI z64alM@)Qq9b7B={HP!6svZ@v)w*6YEfo8lx*oxph5Lpv9hvI#;7*0#bi|2d5kQvNt zy&#h#di)wrUX_LjR+;`NLN#>Hu>(Is0fVD85*R`d3;ZNg>L-seWHUIEvWOHHcV`{h z4tmIkT)StAba#fx-#NmkeLWK2aO#&QBG8b^bLt3aiQxk|%zy&j9Qr0w^chAjCh(QSOn`PT^R z-HCy3KDJP{KH#bv9&!zsNq%xTc^Z`9HMli)5Kto+;C0_Fyj51`tj)}n$eX~ zt!=zOiq*Lm|CZ>SOj8U|2dc@^FUm)hdchA679ET>?tIKAw?nC*9qM^82KcG#3IM;x zFyg@F;p_|f(un5RtOh>92o=%Rb=P*py2IA*U0u}?0Gld>$wGk)bZb(y(ghYo({hk+ zpjw59b2m0jG0*+MRPQBC12Rv=t&_{EqHL}AEtrBul+lV9VOXqmI}OL<+!VLdR^}OF zzdA&5D?jQ7OBaEuuL9*GSfU4#WNpDDBLZM_#n>mvwa@eChpB4)0VL3eFvxnaF+sjR zbLQ40{XJkL0R%sNK1mLdc2SK(=Km5AvloBGBZo?d{~|1ayjyKm>!X$czwloGuyi_JDYyr!UXRq%tm?({FXZ7 z_68I>puCrbeVM6j5mu|*SrCbV>pu94rEV6@hc|tIm2CNd4hg-`Q*taYTerdLMEoAy zlj*Yz+pTn)^gWUNj*kU`7VOJu6o*^StMckJ66D;HBB z<@Q)FDTPzKya_F3S<}21?3JyF@kz-mHdQ)2W*=X<=#e;4O?oTimH?AiQ_ErhE z$HL4PuodaV8;MeT=dD1;;#`>Cc->ROz8&x#a^uf#Q)DKSlnFe&NS56N$>UjWnf_k<^>QGN+;M0+!d5$r5*2H_!CU zSH4VDDC%U}t3l^0t3{VS$-gdyGKpWx2O~1IztCDp<;77s`h;AZa#IIvUT*oV%pgCtg%W&VlRNOF< zpg1B*rj8*eMff}wrwk_8`{+X*&dj=ctTSCK+O;6>73Jv1Wts@{8Fz^BhoQ^d zfyMG}|JqonY;GJ?&9gTZXu^aO87tnN{q{>@%U!N%a&lYcY%WK|^spOT&Xs;Cw0T;h znGkt?(0v7QjDs0$E0*YB*Qkki1d#N)K6lJ-o!VE+^SEY#+?)|eVp1w_%RUH5g1<^Z zf({^W55ZXI&1SXI%QgU6Gy2+gE^f($pPJpUgk#lw6u{J~mW<6{IVtShd{xt3ozvPi zEe>$d{VKpT37uG1c~pA{>)tHsnK$ZY@M#-P@1trN3x&-*+-r#V*l$P{hG$9elV2~# zS&dw93Y#wO`_V`l5RKBxq^uK)BYX-)d! z&IX_LDJVLNdgz{SAbA6<=OS@^>}R$}+4m5^sUtRDb7^eCZqDyhyDBnMEf*Aa3`{uD zVFJtohQxL_PlwtIuc6zV0&_)kX?`u;f2Z&xtspBnpf)y+!Lh}#=nIG`V+Z+fd_hfR_+qSls_#hx_mOMxv`T!C zKGl-GK`IhyrSvM{fI^xCm$*l3(}^F%I_tbOXr4d;XE+Ds2Qt?uKJw;ad#v4Z|$Tw;mAc^Efh9H30Gd4bvjfh z;*+XeE>a6WdsbR?8@fX~hUeM%{Qij0!1sxS9BBgG0g;aymj!hh2fVhym-rFymy02o0%~Uoq6T0l)mv4j<0?i9fxL z$g)^xer3ubSO+y9RhzjX`N~ zKf8kXO}w+$E1}VK+U&j)@Xxaac6vP)fnXZoang!)e>8VDE(}=6rBu>C&)1uhc#l%T z>7?P~al87nq{J9jtF_@{d?2|SkpPMZH(L04rzkqJdel26zXcqh&xrFO9IR?4 z5ZDo$%_iY*PLptkr(%g=e|8Oqmf0AV%(&}fnJF@WF;oA@WgJ^l=*lD>TfHk5N1JjC zFPp*;cY%IL_at3m*OVcbQjMUE@Aq5k#gH?PSyU1mI5j3IzGiw*QxA+rIlc7R@h~*4 z9EB2}vG%Jc&Bwb8geRPBiFE=q5 z4l9x7&HK5BGLX?`Sn{-dZtR$x0N+LG0&*ZL^}7H2rT<8a9BvC+(9-839K}@l@fdkj zgv(PR9gm0M&3m&c>6=A1Heb}WJVnO#E*2~Tl>)=kmKy9_&E*eo-=wr#8s!&DjYeF^ zdnES~U*mF*B&9VJBN86I_w{ z0v@O*2Qxw<&h3mUQxLS~n6jWTE7CN{_nc!u6k0Tb0x4txZWkm@{rK6H*F+?Z5RszZS90E~@@ zKL~~su-rJ&w8<3eQ$M%>#~H_NF2?;eFwI<5NAlq%ecAw68r4t~4_e-kSu_Str`z0B z1Zo(eB1(qr)+0y-HGE+*QF)$xHm3TQj4T+IJQ28;V>Tjp3 ze$KXoEP#C5k~h8ZSZ$+8Zrm068$r<5{?Xwp#oMn?7RYYQ@*4^wz)<=}I?##e{HO`- zW?f`A5tT0QEMQBfRauGeORS{nBI!wWYkICdQSFdm%e6E!mo4;yMY~|*v>{sCv1?<1 z`NxvqzY_X-TO<^I6mxYmtjv-h(z+;^KH7tNN9g2Qdr$S=sKVthCg~?A1Lta6sN^Jd z=itYm+oa$`?4~|TMdm36eZRiH0!ju91*7#i#6p?FkHr$UiFjBMY=O(`PeiR}%=$&g zMWfLf4#S^*yyOyl<`_A%;)n81y7ssxuA;1nZ0&-evB10-$2q_R3f*+>3dyF*y zaj;R3=qP*=zEN*T7JL+>d`C9^O88JDL8+ZjlwUiy>6n$cI3%_57HwtWK6lu4DbD{h zk=SiU$;`G}elqBgpYFDSFz9mSQJ;Y!Z`ZRb)TRHZ?`m$Qy+H>BdD~J!cLJev4fh;l za6R-{M$K52-3F5MFe5AbTDu>N%||8-thJ)LxbDOXv24x^EIIvVNj$dB+l5H%HQB?P zIUc?Hp3j*Z=5{z2B@4(w07Gb(tF?5a=JleZY_M2aHkQ=re8PZkbw=`)a%SyS7-o-uBQOI$*zEip$3=f zsw&cPiPhjx>ePQQP~9+vr09#80`(6_;T=RJ$8YGg!^P1&_VSn|=EVkca@y<~9D%&k zk6ydD4b(WSoRVQh8WN)BjG;vy#9yDr!iAO|d%{>qa)%KLjs(#`fT3#dAN~c{d+D=I zev&Z5ev>_w={gT9M1(e-8P~;TT`tYS)qQyam@wR>Ao;JB?oWalq*O&L?C9Z-ij;yf znw3Mq=UEwf^GGG+l8*@H0?6 zUBGl8;Ykno(lb}#qF^8n>sNC;!-0ta*a6|87-I%XA+pD2G!7PZjLzrL>1@3h{{X{S zf1FI%Rab3)lnh#*wRv=N;C5*j-(ZJDn+Lv^#*02G$+9Gk{QD443@w&Nqv^)ogaR!5tXpX@7qr`eL`pszf69 zqgRasZZghE9`pdmp3= zXq$X11C)ov5rs4{G6*;Cbb{)560Zp3@wScZE0Ts2x@ZiwHwdI2>#Hy1gTIHofO*6` z71Ra|xcwgA@x?(F3=6X+y8*us&?26i3&{q5#7}+QDh`=2uID1@=K7Q**Fi^2PiGgM z@eQcq61PIpi4w6+o_{$Mi4;XIntYZ2(v zk`yj)WF7)U;|)0R)JW_;EqOG>PD)(F$9ms_CX;^owVYywAz+TEBF%E~(!g?mPbawE zmt9ffWEtH1uM;kjgNzs&nbf>j8IC7BR6w^V8$5ucBw@KCd$Di2)sW^yN#ukMeLCOM zGV#SoczNeubC@kcoui|YEI&Ev*FfKOaQk|cjvAM(y_rw;99xH9#r!aXP|GMJtK<|s zcI=T+KiieYRAXH_?6Dho*VBB!c2DL%uARKl-|U?8+7X+N`z#_nRihNRe^ATda4B8H zi)Me!*qng2%UDCCD+0gXdPa72Jk%%Kv8dqQvYnO_kw$|JlL5P(qZe zc#I30{em{%zumf7gcmOq*Kq%%@*VmqFm$cUyEN<-RK|3!s841~JX=XP^l!=vYZ*hdLY(YT~jBOST%tK1*~bf1@j$tN<|^K9e*DSv=sp#SyBgrgnq(y4oBG zcV=rSwfRYl{qf-#5aW*Pz&0;P$}P`Wv5W%;s4x^{6&CMykc?PO}j!Kx?6yO3T+)n@z=y#mc4o*A@;=i-(7=uOqSaZ1!vPVWaHfZiQ>UFpf&joumk z_GlS8%~z3g`qMAV%v6YD#rWwT=%)r<8%vRRodfu(n*n&U8oh4Mawgq^n z+Ng2ShSaw9)1toSf;aYr92vGO}Cj1ecP?F&0*}n~GO=zPXYHzRU+6i$vnr1q6 zHbbp5IP9BUxlX6`%}IhoCI`di0Lr0$+cWUX65clD@<)$OWZkC*KX4P8-vBatCopoD zD@(x{{3qej0K%BU#unZuF*4*aVr7I0nfK6wrD><` zPp$EJ?x1SHVnWE>)+pcZfUfZD^q{qHF{f|gPG%t55I({|HWO9}N8}QJhs5)Tp|obX zA3`y%tAxS?hp-At2wK(XG?d?A!LVG4Kd7xQ|Cr?AYNrj0i@`B1GjsiAx@?~m!|zwR zZGtBpM(&lg+LE{x=0gywDN-WW)+>t<#cPpS3=Wo}MfKZj+*}9RvGbtX;Aal0%LhK0 zc{bPQPsD>eMljCvFaugO^S0ThNyJ!K#sMRHn_nA0_aD#;v;Z;W2u7Inrx(B}G8~6$ zq36<5_BQ*I98{1ArGEIXu2T!KtHjJV?cd8c?gtS%tsq3tbtg{k*(9b`(&v+g?3YPT zIp@Lm34fmT(XbX8lc@)$wAKbXjMX~9{QRYEL^$Il7D5&@AL;h%t``Jn!QTP%gX;MJ zHH_i4Et)cjW#MR^XJf$T5!0Z-jG6yu*wqi!BfzGf#S{-Rnc(>AxnD(5N*f8Ui6onK zIlZK-XZ{*O{mS4jHmqE}Qook3pk|^Lfh>^yO^V=V&akY3q-Pd-Zl(tyVPh?tW+G?oLxnEb`c9}8&piYR~4Sa zIbY~hQ^qZVHNO7{Mo5H%2V09j2mDy3y4pjS5NzGRNRsyvwmO7D>8c0RPsPb>vuDI1 zPdu3C$q`y+n-k8Or3q-k`|sLWcdQi_b|d9oTdVF#NBuF z6ZpDx*@0OgVwj7JowVtOAVgze&D!mlg^x8y0h{N3xHD%S6R-EtCt!;f91kh9(%XZw z!MJN>MX@Q-X!hWKkry4t6QD8*tKCYV>8_vw_n8&6xYHlLEieA|>yd12;-B{)%VE-F~2q6c5Z=;AB) zm0zL)G^adUk=(0EqB~R;`rf=1|CP_rkbIO{-GXCGc^cexgB7^Km&5_(YE+gtC^iP) z(pQ<2WTYSZ9%@ceQ9J22BH?k))8RGNPCN+>sYd9Q_4Ig_B$c!k=XL_|ywIC-=oh#O zJGw9|fRsD0ZnyOwp=pO?7T4v&evgs!=OXhTSFz~pH#+Mu#^~Ar`Y!iCXjF*Kp1L$# z?GLpTk6gML73yk0qvwfUOpoW74U`nd#^Ey_dMZ?;sF?QMyxo&=hB(Y~6e%y<^&z_-~g?K}kEK8?BINK@k)M00ExtMan5 z@DJpZ?)$7mazWH|=+K2@+kp;&57tn&@~3I*F?tj~33->4a_Oad zv+};Wa6q(BRWqvn@ui1CX}NsdYivVM-UE&K$n0Bbm1-uF$Re7*H(Ez` zpRu;`#F!9E>13RVt&B*!hb7doC9}Vw5Uss!!6c0iGR+lNUt6{AccUg2-CU0cc7dQ- zR2z&d9Du>;OEv_b*U}?{l~ZPzTZSV3T*Sxo>j@My-s6-LS}!8`giQ?ZR@A=j>VWbt z&4W$CrsAi9-`k_ml&a~T55ZYwE2S6p9PBRR1ajrb3iB7SX5{yDvwYzN>7hM!LPk*E z77iCfOjfVL(Se-)&%$4C~zZs!~1YwtU1rHJ4;2ZlFS>{7e*G!IOZ~4`k%$(8YIw z_E0vo>A@H+1?%HTPhcWEqhoU}y=^h%4#+BWT(P^_UL>H^+w8mGG2p?%Mkls-@bU{a zYvrF+{fc!Yw=mjAOMu0~5d~Y>N?{mLsDYz?wG;%Eh>R15)%4cTqUJ(~kF+im$+UH0 zGejG32gw%XSt?~hiu+&gd;+@%{Y|dQB_BU28zo_O-TvA%)r`jbYUZd(cJwAAjG3kB z<{$^-M64}U!H26qEFO-<&`>P2Yq5wgz!-m?!iVsd<(fEkB71qsG4w-ZIl=-nL1VD6 zPLF&DcNEuWSRGqBwU@cOO`|gnt*3u+CYOPf-gF?pgg`jfw8 zI=DopNrrMo-NJK;9f8UqmOTp75=4`FQzSa=_5#^2()9C2fkLa95}rVx5Ff2(AN$KI z$~jq1CGx}T^2j7J^;mlvpTIZk&%7d7Y|T;acKPtL84P}ha>22X4c3PgQiOi=J#eSC zi^#5UG>d8=CB5F&SNCWOGY#aqVRv80wr|zOS$xCOpZ#8oi5)xmCWKozS}aj=vd7q)v{fELB_fI@=trsaRXA+B&V5ylR^O(R zV+KKKZHFR*qgA$F@;TLCq9*brqdn0f3`cqfa8h~dL@|7FF{G1`mueY)N>56gI=QQV z=KL=wZCcx^d=t|=H4s*mH5y=s*mF6A&}MUb25DMloNB@s)&x;k@*rUcX9WLZq3&l( zxDT{Al{>4ZN=5OVKd)2flX9wHtYU?NnA%f6`)EQti~9f>TA+0xdWzg97N*dQSt>$ z&m?dX*(h|#ELe(P-tI+RccmpP9pE2c;Oa^#Nr`8FE?V*>)$*=>o!PgA`vz-$H%@R3 zXVtL+dmB8h^b2h@b>zhg##+`?5F?QW%j3aILv55FJZH#`X8OBU^*Op99#;6|LUzv# zJy`swA9zczqfr2GY%3#N%dkMXP(z}9Cqymjk90+6hEp<75XuiC*i-aQ+dYX~7M);s zO<=RJ+iR#04|pm$*6Jhbt$Q@w{K%a3vbOZY)O;Czois7BubX%WHZ{_PJjXYyt9KWE zNSzPIZeC!LghSj#ayKYD>{i%^2i2xSFshqM6WF@}wXVO(u>5C_bB6HL2)%*kPY7mv zA0I^g>9NDoSS-ISs;%jzWxpuP&P>@hwn2s}ZuqzZE5N@XYujwfi!}nz0v3C5qOc%j zTHQ_DhJTSR;7IEnBx2Z{XLVi7b{sW4!Kpx@bTnrFIKS7hz->RVi8KpNW~*ZdKgm%OWz7Kez?#Yd~x zO~;L%PfI(_XOuV`rr?X2+@0;0Kw{{HKY=`A%)`n(n zL*}cz{R}arO+v!))zEB?txM9{XtOS*_rh5SNunt9Ij4xot!1w`f^E-A@K^`juhz;J zZwCe>P;U{+*BU~l-f(bxiy@4cPYnNLiP|SOUe;bJ;Qzd}Rfu~@WjUSU!N==iVu(Oa zr`2aMgUb;WbT0cLqpKFu>;!&^_`W6SLp~x=QW~l+wi(V@7}ik?yRP#ahCb?B^@1?rn|}XmOTKAEzy^vZf3w;IIhCW4|I6C-#>Ew7koy5v45K_`B$%t18EV~(_~c`Xm(`_lubRxX zA{~?Pa|j}h`gHIC!5o4Cd!*{_STxD6gZe9h(UlOMVZeZ!v%X<|gK-WMB>Ji(yEgwP zyA^4@iw7^%_+(3ovzMJ zOVoX%1Lc@_kI=s77KfCvZ{007=XOmk{8YJ-7sT#8@WfpNOGCpaA{hZ#OgSVeZlk=^ zKBZvSKH3ejahNM#knuKJrD3JmM}-4w(5mw(aVFu4SELhveFl3C&i?$f5x!2Dqi^PD zZMl^+H}q2$x3I)9LX!U)5)jfTj6H$+5`4?}E%s8Yr&%Zk?ImPaavAQP z%lLD=g&(q~(yJwR43^%IWyy;1H^P#rS^DeY&i)5=TfD^IKLvgxj(@beO2#y&!%M!0 z-YXC4b~cE!txxC&QO>Fs2n!c+2L#T?z#S?z?~LsDh6WuX5J64qA9Wb9sZokJiFzvh z)LbBSai-P1CHZ|``2kbhfN%7g3(A|Az-1^r61Dn83 zpYsg3=KT_FMI#KnUtXG!fl+rsX_MoJ7ZE;Qx$Fyp&2S24SCiTgy@YLJRu*Yx^W?97 zq&P-$;N7vbSk51Ml>;2-#YFAmmZv^#Q7FY8JbH_Lni%9xFIIAk2E9zRgQ&vo6sJUL z63lk_PUIUZ%Ee@@niY_p1?_xzL?^neU;oDvy&s4sL(9Iiu!S zd$EP&#*E_B3{-+Nu3j8oy4U)Uf-w?nb^-TxmI~K{)wOmH=67a2h!0j_F{|v4P@E89 z)_4E5Om3>|u9ikn>mUG~AI!>kyv6cTim8bZsfFRg#zu%4S;kY_)bD8Z0|A!li422( zF&Iyk`^dYh9YKA6WKJ(8dl~espDy~59@PTM_)#(g8VpXR`4$z}y6>TqE_^?-QNpgL z8)Vqe#Utt)-nNBc34c)}c(qdDx?Ba4S=eQPegyUYm}@c6y+r<<*TWK!9@{Qj>PVcJAS+8F>lK$W%m0 zJ<}-At`_J)=p6a|CaVxLZPvN{_&UWN{9<^C4KQOYku0Z~ehZ1|&huqVF@QnVtOU9z z|LMnxQCc{I#4quEClm~6C1hWdCh2%zIMX(j2cTVUwwXRrY}!fKc(=aS3HR3Eo(!62 zQ_i6a0=Yoi96S{m(l=~F|JO7_JOLzJq&wzDk02W2a`@mHBE+XAvkDrxjZPHdSX&>a z7nmbP+sz)C%28;5l~y?yKVe+9Bjc0|uC{GVyCs^&ExX~dDZst)x+Y)>85WEcZBg_q zbEGhe-(%Yx)MpIY@E>pN=l&YfBg;DFl6*;mJjI#0*qv&UH3IIVWPR}1(G?O3&=AHl@;GhY5EkOS(=s#CY~)wwuskctj=vJBpQF8FF6H8-e&uG>Z_=G!o` z1x#jhLEYHr&mSBOvMu|a3KMWCrAjk;iGq*NCni|EC6@hSqMpd2y1n<*one5xA=_=|`sE0lJ<)RZl-STWAkJpeZb^oi9#)|T9eWFkeDLX@q zmo01!Awezzk^Ad!pLTB@{8LsK7nzQ^+XKIaia|Bcba`K&8LFRdu01Q!r;)lNu}2>2ofU0gTPV^ty|%&7`Y(Tr1F7K4 zJ4tUy8}X-+yDIlD5NIR(4B7qSOL8+&#L#icd99^(^JIxE%BwF21 zs}=Ggc*8M3a@vUdyKDRlgbqXsmYQSv?BN(XA?0o;K;1v<=hU@ewyc4FF4UKd{Ia`8 z2A&g%(gI$ct@C;7(u=HqG9_Gk(aM!6579^ig49;O8hej1TD1{XgyE3w&~-AA`*W}v z)ioWl-k9Y(8%=s?;oZz%gB2~C>hc8nu94c6j-E6$Q7sLP+1`n7tj8?={X0qxi$8iy z!=dOYHyK&s%8mW2sB!Y6a7JOITT?F*;`lod>U$Ap15Tn(sqM2H*l&wXj{*XLhKDSt z(FlRh>m?K=CPr-~b}HbZQNjQ|IG3V8fNKwj9i~HI21EuZJyICP0F=ZlgpxKsQ1<`Y zIH!j?90q`9FJsv@mUXkSY+GAgxY@pGS<9|f%e8c~ZQX3HZunlmhu?p39?m&v$B5S? zE;{m}79Rs)s5G10JUxE#{wpm;4;FVmrk5ng`_2bcD91@FmJS}s!<00#L^~cCUm-I;mT3f`j9TDC#xFGJAR{@N zelSygymW@QrG%fw)$q|^FE(80XbiRhP>WjT9c;-o<^nS1CQvcG*eAW%*GLP2)Ddif zbWF-VUk@y1tyJ}F|DVBxEm5tm#`N%yl|<%wOX(wcQb95i;M<(7B=KRVQi2g}TL$ zw@Pv~NdTibl)Zu*`c7A`gh^s+Q-g#{cki5dOmcPJ!Yw#km^<$Q`7tG=_E9utc2bbB zX5{e0E*;46&8i1iI%_`eXPeRhOJ=Tm-(tjP8d*EveC-nsuY*vKKDNWlK4H}^$YOp?km47ld2j;OEcwR81{61Yga;HQERBs9_jjcw&;zr*XuVCFweiewV)G z!M9HlS9kAQ@R+#X5u$J!1fe)Je}+P|yBU8tMWNHX2Yw6hsb~>+bMQ%nQ18kBA3g3E z``{@7x|VIv&HZ0`8DtS)QGd;?#o@v95*- zDsSmNN9j7V#)qw9`_jg<`6Sx>8qnF(hJN~PM5^NFBxr35!9$dXHUB8Bd|qY& z9_rAOifj@tT8@Mj@O;ORuM7H2I7(S;dp8aL7p&g2}8*XEyeau;u>pGr$e=9M{ z99vA7O?NBz5XocV(6!K}k(7B-#O!7fTjsO+n0!iD5OhF^MMT;&ERu!90R+sb^5-CH zW|L?Zp_4ny{yx;RNncF2(1@cTK7CQKv+?dFue#W$D%3Q-lNLR0z44(T^@8j+zP@h2TBfDk*mmgzwWU|PuR*f&8T(={$S za&J;8t52oJm46rIu#V)H1p3nFOP$2HZjU>Ef_uu-8yPd?+i+K^#Zo#95%v?;QeUBG zLy=u=?uWL8<_D{EpW*&+8e#9>RG{~Fz`nGaih}Ax7pd@Z1p~CM`J5W|{hMf@NorzEBZo?bZm;tIjMfX*l%qQwG^PPx^Bn{!Y9vC%*xL4EqKTr;0k zEN`L>`D|L1dzyU6^AqaOCk0!Qaj6?OxNPg*Q}&^M4v1W;Nj)cHSYW;MK#~SD==v7! zKL^ELh#E3}nXygx-y%&)-?p8?+Q`GbxFZTQvU|%1O^~rNKFbp&6$iwng*EG77+IC3 zkAw`Y92c?!gMWOB&!$E3&k$!vfWT^o5RCqBckd>1d683tZ<#r!$Y`76kRmN>?l}Q$J zcfP?}9zKbs2qHn_v&VbeBtO|L;zzlft(x87)0#l8>z5D`!xFYgEev(9^)Rciy^LzF z?j2#XFJ2-1wXtN^hSiATl1qYHBJ5~?u)wxS7d|cD2Nkx*rIZ4oM|KeXs2Pk}Rp?s> z!dr2ri=_!`y;zP@F?tILp^cBbZvb$Je>; zHhcBI=aR=uW1Z3@Ng(%--n`%*#qZH!i})GiL(OsH2l>(041dK`ZVp}Pcn;3uT8`!` zU+5N-UTCrrMO==_Kue@y>T2}d4q;51#{A=?rXfeCjhi^HS{aB8w@UO@$cV5Jz6US8onFP+yw3aU&L+Y`Za| zpH~?zN`;*4jz_7zD4{c<9DXQTa(};J#`f=C3MykcAg{sk^lEC=T4jS^%0wz~!V#eS zH2!)>`6Q9|b6Q>vCqt4}^~;1Pajr=_lSFX+1Kf;X0{FsceH+k>BdlMuLB@HrS58Oi~j16-rNkL$z`2rQe^7*lDOe$D0A)^HdjSudI5iaG1#*u z3_~uNzh<)o#}XmEKq|4Fz$7oR2_jDLEGIv7+7&?6*^cg8L49+PVusgomnc$IXcdmm zaQ0Zbzz>H{O2e)$;Af*=G5oSCP^~a8{^t3kx#=9PtUZ3sFs4YBMF)m~1q<}wr| z^=Ux1u+E7n8Bvup`mS!ZP+s4WntNw1tqdE8;z4%#6=qjHbUs5eA~V&S zVKmP40}Rq{`d5A4oD}5T{L-`lssxY=@#zmHFDkyS&9Q!#HlP) z%sqLY-W zS9wT&t$VF|tbq&O(FM%Gl+CZ8!uD> z;da(u77Me{PoJlLzTPpKnE8pA0;lI{N&aBdmpIhCC0g65HQ^X3#!CQ)@%$e|@Goy` zm*p9MeV={)FEe|FVR_ww7u*TU%65F*gK#q@JhreQaqg?!m{>+n-ecB<3v;w|ex=(f z@d`@G$B*8BqjiSD{C0`5>hx=wBgad*!Mh}zE)#Ll;3!P51YbcHS}>K!wf#yN>Sv{% zzF8s2qmgK&Br0=X-z(eT*KPyE(gb3&m)IBfnY>=OPca(Kvy2$%;>BOOulDx*j#zRKXwFF=y?v9G%mrtZYd$Kt+seuZk8o_MfCbg3kdH=QJ za7ANzp!=KBZ)%sv8m?cCWG;OHB)L#*UN381FZ(T5(vI>Y#r*ZlYc4WanbrZZz zs*U1lbT@^RIC|n1R@rNI%A1j*+#!q!f2lRYbn^rm21d`Z`x~h~ia(UPZIyZU_|FlHd`ILsNoYUR8MaT zk3d9|x{(ke?qm@I;rdoQ0a@v0 zEXpvLmfi&A11#IQw%<5WA|TZe%euwu8~hW7Ucc*W6mMW}czk36{KI)3#qlOYUCnAxD5n z6i^jDg;hX1b&v|9j`jFXVE9vKJz*2EwvY#q@H8?Kcz=*EM-B?rMWeGR)HMYi=izYN+qP}{P4b`CZGDZ~sb;mR zQENVHjzJa)?kh|M^FFyHz(2`PDxLUeU{Ory1wZaljjFD)+fnE=cD8mKkLBvWFyLg&$ft-+pJ9`3 zzG6`sl>V=|MUlT4X5)NEhL2jB}LVGfWFf>yf!JzDI@u21QhUqCHz3jXr-*Wo+z^ zxFXnLWnK;ESQn_wU<2vVj?3yO!kcRgNasMpSv_g^XCsclY%k|fiKK=Fg}vUdbovL@ zQ|YksnxznuFt*@=5+QRH6E<7#1M^qx^4r)bi|tzDq6Xgy(uc^{LT&NLo-f`g0?EY7 z+nVsIBu9KO{^jEMV=t^zoawI`C{&3gw*A_Tk#BJCdj6e0FOnrtV+{&hB!Iek7>l>C&>1D z$&@79N?N`czYz!H7jn*&C>1sC3)pjL@o6*Yzu|3k{h=s-8z*dO50;ZFC*jrY4UX7X z$-N!>rgSk(7JF6FG1Jc9% zmvh`+JT}rEk2D+9WsumLj!(QlT1>)l&T zdZcT(#_=HvdT{&{2TX7xI#&qwx|jqWGMjR(aYSZd zUFo{a=eUO-2y?5>+ToSS>@M;$nR`4TOyk>|b|0Vxe@MbbZpuZGim%XCdj6~ankc+( ztpauR1v2L*ucAuZA^a2+LkKZQBpjg66#n;v(W4$$z2fsy zuE^$Ru`!EWA~A4d9W?qLu2^9{ETqvdJuf#@P!tb9wpn4}T%trM*#SAN2^emL5k)d| zc2B+d;rAmiy;IM-F67zs8| zV&&0VbjV`E3h_?+@bX)DWjo?IWNi831YRH6zl)veXE1tqHpaUsb8FGzeViH!Z;}%_XXsrwi6yaG?@td z?|Ou9=n}tbgra18CZsmtbYXMxdaQteXm-kD#p|8b#xEq0hpQ^c=G=?$g)N1jh0{+} z)}8%dya>Gtx%kJTfLSe=zh1{b5TAn}xzgFZYkE{PbXhav+nkk~28u<9u){tOXEd|z zdwRa(8PjT4r2W;Q9bg#h{(PryQrz87VZ6xYu&!u{U(Nsg!yawmxp#Qte<47H;BFmU zs~zk~C#ot+4hgCeUCh#aUrSrDm+_f@xf`IY>ec-}|o01dpoVxm~+; zYX^f%DZth*3aK^jlH{Nv@3b3uzh32Dtze9=)*vGvUa$*wK+Sb}&5A~Itk{o_kZR;- zQi0N@xis5lrl|G%{){y{v=daY>59WhIz$#eWWWE{8T78*!=AkVp5v+xEb7(_SUU!h zNVOe0i!5JRMUm|rm^&QUdiyM6B(**=Z;OAw(TV*deEW zB3QvL)e;X7MDr24C+-mzke)XeLU@^8SalFS_N74je+sJzWivjrvOCCNkaj{0==?-j zUZJ?&W7G{fP02)J%tyMd3hG`97@Pf9p-@+d{DaR3)m#ZZfpv?Q^LGNkN|@Jc1o26* z1A=T_?*|i~AW698)V_(@E{>^TeNnh{j`vBZ=`?%&KRCjyO#g!;%)-R-|G>d4M9dt_ z%}0(nA4SHU*RXTVC<|QH9X#zhplE zrKs%x^n2h53rMP^s$eLsEuxzkeYAiF;s~IfpV+uWyz#dx@>GF%Z)nurO?T0@$1@-Xe2DT0KXCEEey{^eIl-b_{ z|FMA)9GFD2yn_QIk%511S-q`JwiR>oy!(gru!8`~N^kZKfGmja1uW@ea(*Y(6xG#% z*0FUqf&yPhUrX%+4NdB!So_Zzx3(DPqhIX<1^Xc}Da!=#B7dE@z8Powilc&d)l2QK zPE4*}_jt^0?hda%;&uUNjdDV-v+A>kXMMCFz^Cf1{Q{Rczt$E!FwSWeI)Pd%a zfm}FSOg}{4)|vs#P2bFYEdygyz{fyLoUN`9pPCtMzCN^4UQ~LP7Y1KHw*91)i!&lZ#M{ypUxrQ56-`7ceZSD zw%38Pvq18zeY*W^Zh*A=HokXK-2OtMS|ZZYnR|cpvpOazZtoaF zz~N60q-$MWAja0V4Gz%GUv_3740CU!cY5&seUMk+^q}ncpKBUU%mA_LxC{GXNW%nx z!SE1-VZsmRp`XfQUw9gNe<8qr7{O5Ko71bR;-N1*4zk}EVE;U7_}Ld8^HLMNA+V22 zdQW&?Q~l9L{H0Udu_CaI2ZRyjFDMTbbt15z73mN01fps43%{`&e)9{w7cTT0@ZXL9 z9Vt0Kzpeop;0|Nb`i_HPp@`)&gNf!}SP6M?jSgR`ucy`_7B zIs|_s_WJ*j*X3qrudkEuaY$k&^+_pR1Xo)Jrru3`-+(KDpkJc=pSPaJI2%XD_%2LT zN=(Lph@3my$Uhz(zt8`s&IFv~etXM*JF#|0Uk%>p=%Il?b^=Q!VFiRrL4;PRV~EXq z6Ty>C>X&_{$5K27H=P`rU@wwxhQUxevXTW8gn!NZ;4+2d|H1VI+9&q;HgLEi)!s~5 z%NVZ=w`4?~r#93TGBRftugBrZna2dcjd=Dw%1eKOc4YhHpv+!GuePhR1dPTFA^P0t z^%bp;889;@QNK*-q&*q#M4E48I%L~4Y@acQbBCW%@(>Nw^*I`o#CVTj?9O4GgzbOF z2RWZ#4DN71p#7Q>5*~nyscEPrb@1Z9D{PZ&HXRwV)$0|Zn*Gb z!$(^>{BH>?g97&812jymXZj~Q1_D;x$RsaVcQMkf;R}|rN72S6+1lD;@@Xg?IZg_zd{Z;4~xPn$%UwJhMgCjW-cYpk~2g6 zI`wH#HCePtG#*O5nbP915+3f?4H3QnfCo$(HU4Gq^iS`Jx4aK-PB)6{(-y0q`J1;h zfjYtRq&ZOBWin~|A8+-aPz&Blu*+*%@L&aTGQ-hi=4A2}q4MM~Lp92wsj$Jn@tBa| z7_IDY;u02SznO>S+1X*rG_`O;))e&RtL0r<`%hFYND8kR@PhsWEI)74g~zE;VR>{U z)HBH)`2*P>W)-zX#TY7FY?vIt{d<;WPvyoW(7z#oxaZj^dOK%C0vGopFJ6B?)eBz$ z*zNf#c4wG}eZ6~&M<_h5-KBL*jZCkNv@(g4tbf?xjFixP5|$H%TIq|UI#&oeGAZh= z%rZsh5pFw;MfcP8uW#=4^t45}z5rA}$a`zN$E0Uub7-)GvP>glRQ=CX4&%cv?by@V zsW~1|wF0B>y6g%2LfhGP+Un!VuC7J(;m!t%A^cg{sj-aU5Onk<&3QYqf;}YBQsQ!p^jfV1q`iP<*1m&q*iR2Mw|NC zCzt2}0y5Y3#e^R@RA1ISIn-zdf$g84zZy`7vJE5?VXbuq3cN3W#mCdxIJMY__-m>d z2;?)U!7Dk6*T5mx8su4`J1H$OS5TRv`Gu(}MBE9J@F3v9v?!e*ty3jA7t2Oooj--Y z-EG#pKlB{*ybMLA=OiIFRN1{7&n@-{H=vW&Bo0}OH8wX7hLj(%J$Y6LNW3zE89*h? zZW{Q8`q_TIL-izP7n`g=<#z-80!qv2J@DSXe^{w|8FVn^P8FRCvD|ahW3truDPv=c zq!$^MHxmrtyx+8rOZZ2dYuY2lMwa#@yRVXhQ7s8Y@Y0;aZ~U1Mb0-}dY-`N?@Aa^i zj{|_}Rp-SN&(aAC1SQ@@=k@n|-!$}w;iSI3#KH)&ejVn>#C@rh%Ts<^Gz;?EH74#i1vk<($wA#2axWn6n&f^~AB1MIDnx=<)YBbD(PZQfVSyaO`|{=1iS^k} zW!1v~=B;Y#t)eOqLZ2R+D6z%6{f_!o`F9+A+}4_+I~>!Np4&19%rdxrP1o%jC2t_l zrXN%PxjFH-^`%BhIf?ksKBht#99ypXFOnn>uOP`uozJlp09v=T(er7j7aoSK_EpI# z8$_+!+r_~_rg9(}@4*9|?&tgUhY^!g*XPg8*AFk85RpWq>G9+gnj9#+cUiUYN5m!+ zPl)8p_(H8SHjpkm%1t`laoJj<2kd2$HUkgAM zibc8L(u&~vyi>bI3lw!k)#cY2DVlj~{)=d~=;u^I|84; zjGvrB3y_?@_X{#fp0f>6p;$0i=5ZfijWV{KD?yY`eNuwYsG^ZSg7ZSrEf^TE*Q);a z+(i1E54yuyuwt}vC(f3<#9mb;gxkfCcB>tbRp*Umbfjbuv{@jZAzwq97fK>dkDr;tko*} zN3^fgBX)_e;EE5Tylc%hd>%MA2sG@Q4COb>`1|aiQy6OmnaU${FdA}LAjXW}eV^@m z*zf^+z0wX|(biDf+|ILM;ju*-#~$DVs66s{+LixOz64mlD;VwPNsPnLM7} z)YxZ!)P*c4zmg^|^!TFONlIKhY;%%4=zenQd-`Dexasf{-bYDYQkpX`HDm}$qWFq~eOT`z$C9_MtgB+>_jkMHj&rg3cDNJv2 zu>OB>z4C@|rwrVvl74QJBrg@^#Yv2z14IJfsiTw=VSOPGGUpjr0i`q8H{McM&;>@G z^=JTk_gz;1jLAM`dx~LjsWplK^?n9XNR}1> z=x)#(uPENSxu*q5%-4yos*Qj7zZdMcMxA*6|7q+^c|~+6RY(N}Mh|828-Hc@ z^euZE2Asr!x{Zg0H5w;?V$CzZM!XefS*qPeYc5W=+~a-MkjdBc;+);Pds4HATsab0Y(u2R%BYGtIyK`9I_&cq!LUY~;wIo?YcJJ1!)=d|g}GW1 zoB#lPdR@#^F{K;I)I_MR5h)3F4g9*#*g{v}zfo&N*{%&OdAGr_`@E9iVj7Pl(zY}{ zl^Ri?W#X*clT^GxY1|S8#(>4+ojGMt*bf;2r>6+AyO0!02W0G6N2b45!ECviQgffS zQTrZ{)yFVxchYxM);9nh z62yQ~G%jG+GImh+gSUA=>HthtK){5j7~64kDU*faVcnLHK_!}^b+$6C1=OrMQ>XJq z+t21>%Y9YMfT{SuOoQ^q^8jIW*EoP|d|L_`|2L_@Qo}ZHRo-hCg+A5?FIAA^aP-=F z=)yvWg;U9yZHSe0Had#uZIIQMo1INiv=!5XF0mKAlNRSJNyzZg19Zqa%kUE=62B|^ zZne*J?>{DtBs4t<2F)`NOj)1r`Z$cmrf`jtBs5ji(5Xo=7!3A5M^ofeWJE~EHkNVF z51L1&t{tD2n^k(T@)UmaYkM7N_NzQj3EcXGYusg@(aNDOv~k#2I{w%K+;U~ccBo-K zva!`N9iTtW{-yD-?v0i!#ZdMKg&t5SUzw%U1z_y&Ep=0Z98?t6}Y>6L`33`^v8|S z37k?owp+^Ve^&LlbunCydOS<2Dtmzwuw!)!bM9-^F4>cAi%<{9;lYqyu(!Or9FND( zO)YJ^2gHQuPSKUBo%j#_-`NQSqC9XK2t1tT1JhzEMIIM20ys4#8VxX$c4srE%7`v@*BfTBvE#Bu-=IAva8-hn4 zCsLB3`cAyxkdnkXxSf;+ukR37X|3Pxjz9U`iPceb^0g9)z z8GVOP2b}Hl%`FR-l9;OM5gb-=i{qoxXKHjm{|oQbW6U&vw8r3()I|Q_+{cE8z4x#! zemOhI{5W0O+oGiB_%sc6uq)>miWl>16&I5KGv45T_*bUiTS@SESZ!w3Ursc8(C+wk z+h9=|*lk~qFVIwHqn?TtO*^G3UR#NOw|ruL)YEN$l>KI{J?OGBMwXSZI=75a>E--) zbbVqny;rb}t`9QkNo}(0V&Ni(SXy4YYCWE#!K_uk*2*-1dS?H%=-B6HbB5rIcJS0CuvX?Jz^2KK&*$>Wn1$Os%!+p z4<1rWeh{51v58=~$ULIyX9T9vEgZF){62=bP;6i9cT~XHf-l@Z>~-U(ZaqVmwZLCr z9$I4jo6~FS-keKYk zuHa)R_EZYFl}g+gp&28{@I2n|MkEzr-Vc=^D4O55$@~U;8Js70{JetlHY9($Qtwto z+4>bT*>C*=%?FVILReA?f{hL%F4W;T-Xndflr(Q&NsNtR6qjYL=E-{}i4+E8k;8g* zFv<805azD$p(8KMws@b)ig$`C4bce?(XUnH9-fcxmN$-V;Vh6gAU;ysE6=>=`Ea5k ziBOl{2B|#C+D1wLw&BHV50&3j+3M6X^3Rj@?N`^u<7+Ku_1jST^rXSOUknYaBcf(Ienmannc8%D@hrzw zml*wa;T;#_LCyM?<2TBo037Li=K^kiBt#P-My1!6j*C--k_1l+xdIsC>YED+3w1mtFY zp;Q=wFq`77VU#WX9e?QOG_N`>xfwQHT&zh){&QSntQ&@E z@wZ;kz*R=xECI7tW_82VP_8xcy}05JTmUJieW5+7lx1b6FOuQUU^&gQ$4(MO%OJB5r<^M69h%j8D8g{yCFRGNK>VM?)`lNEF_ zF+;HYf+6u@rDA3=OV#KiF~zdA$*?zO#xo6LAP=0Svy^fw;^RQ&2ySIW0k98xv?+;2 zTAKKn!$453y1R{&-}W(~-4~ii0SpNiNLU$T(TXN+?ty*&-yWW-Q@w(~q*u}ZAleC)2tzb3va8;=$Z%c&WD09ECOMfdON%MB5FApzmh!XX|MUxkIJ6r$QjSMK z=Uz(%Gl(xGl&XGxaqJGJodWSpD>}@w;#Q>QE^Cib*s4l$dw4mbL&S8`*CU~|UF>Ro zqaCERB!%946lqr}UJc;l1tVk4Ns!@w(TtH^W(--bbO65;Xe%0LXo3!Ri8--1&bX4& zi~j_%^QC9-Xt9Q7iQ)|YSWU(;aGz# z=Cll^Ep_;D9NAKl@U&fpNU2qB$ftA{z|nVyk}}ssa(#q3sRzsog2jU!Pe}{zs?35fJpRjc+Di+yrqy@k#4NNkts?y&}_>L=voy=?`3W)HDb~ zzNWt%=T#wZvuZB@{8eDTDqYouL|g5O z1i=?lKDV3z;Ovh@SCk3@(>6+X4+LKJfId)H#IF}|o`@+;LC}_~7678>fq9SmgY7#} z&-?rYCMk*hIP-15S|A)3cvQI!cZWO90k`CcK}_%@Fy9heG>DKfisPx~EC%ceB-^qi zsq<*y$58A{fiV_DU81QfLs>;Uv9h1_CP0P1r(8Bq>CX|#i;`_|P&QbhP|ER3mz4|1 zCprJErH0YWcJH3fKQjN@2KdLN^?Km1mO~o))y1_+eDx4C$8lfzK%Sc<93ff58~OUJsf{zt&8#ZINuV7KwmI95<+CW40Y-U5cjddZ`Tt zh~UxgARLWkVT)FM$~MWjg$Ewo_g814oR^j{Dhp3F#j}=?o9*vUbuq3Hgwduq{qmq#9hBrG(`NjRB6`)m9dI@(=?fl z=|BuB3EE@6A+y39p+cO})~iw~Uck6(FxZ;5$x`%-qy0?VnzKEpqF0V}-CRd{l9wrk*M-XmRSl_^h}CQa14Q9?)e zq*Y#x^}=lB#zxX}HH=2EgyWGk(gz+?$S4^bX&zO9>%J{VgJxwEnhG1b<1WqLZGeH3 zDKo|lfKzR2;h*BAxER5GP~{Tyk9#K@p_#z-`PA#8cCi{)c(k(o%aETRP7iAZZ`9?N z-||Or?Bu>_>%=)!4>&Qye5JggnW)70@wiD~X^w~~!2uBmX-id|JCh(coC|^6K0j(l z4~a?S30CVk0D<%sG&GV1tS39Q{^c6#=GLfY^1v|bi-_`fuDf!iON$~?>VY2Qy2(#{ z7%`M;|G>|IctAK8pP1iacFkZp8I2lsVazHw{LCUPV95onsrjnQW?pyIaYJ81s!>~U z&}Un1=QNGZNVH&?+L!rCTt2yuMYC-&*YqvNH$~yIsy_j;p&K$nSUZUT)Pu+G9WmAic~ns+40x_`)O}01gQ4yv$x2Ihc=|@8GnFIV2>;9 zQP2+4LG#xgEYXE8=KK5p4#TkW3cXynJ5l1~e}59Hhd-6L%Q2TPj*Z-h8CR;OEUZMC z!8D!u%casRDz33U-vQ`4Z32soMOsxyQ!y_0C+j;};X)v#5y`LsPw8<#t-YqFhBdOv z;-s^w*7fo}wk$ofWbVjMPw@vxxl#+yEm_$Tmu82tx~t-g zTuv(lS0sY;tC*4af<>sQR%ehvgJqr7(X5!p%3cwv00y}%oPcg*)W4CeKylRsx(voY7u*5&?-5)LAk2SqFCet&VOtl@KRjpk5m1`ouVv>C2}WP=~sSC=aI6j>h+AT5@1c zxBjW7r|jtjK4T*T6dbFZFvKQ~$#rWQ`AsA3J+xVzxPl_KT1oKh(jnm_;YnluKN*Z4 z(dc)&?0?cP2njhnZUPW$^yZvmIJ@B18lLbYl!zVdaoK~ewH~3oo<*!ZJb#h-&Kki( zQ>I;U``n1Om{AQPqIB-vw`t)402CtMJYmu<3e2V=ghJm?A!?NruFtdS`f&$SZO^G= zkpw@m&6X*KA_@eRh<@4yIktr6!q!jN)R1SXiC}9;=fCB-Q@(T7JiGTP1WJbm2wKTk=t5Z)n%BUTP zMP`Zpi!Na;MroNpI6Z4Sk|;cZu^=vvo#9IcnG&sUzVjo|{K!Y+G*{CcbrXVn2rbv7 zN$j!|%pm1)Lo{B72N(xD7dmIflI5|aF_^fmotm};^uDD@I45)vr_LCT>F>)+2sSc@ zT^=r3qvI0%sU&?2{fy?xt8~tJ!3H-*wC&IjlVPE6ZrvUCd|lPuOBOPH=h3M`I69RX z+9r>i05g66r=KvHEkmE_zK{Re{+{+42OX&^&Rob~kd6nbuqBNvE3TPN(XE+I&_H>; z8)jWf;iLQ4JB9}4AS>uvUDZ%jntwU7sbM^8E`T8y?hr7lDwK=iI@7FMY+)4xbdK|) ztCDqaE4MDJr=eW)LfBY}hc?P#7&tXS>24tBz?aUmv0FIH&g|Z%$iY9p$G!V(aa0Aj z_U(#?{fS`Sk(BFvP-KOzBsLkx!sO@|CIA>3z{GQGp1KWS(WT(t8ufZB3Rj%#KV_~v zTuOw4oF%Bv&#x?nWR6^UFz2_!A)0EvtLThN&vz0Sf4y|>(w>Vli-nce1wE3ltg-a7A6RS=D*T%P5v8`{2Ca8vTY(fRaVzmRjDnA=qrks?sh_bN3aP z!cOGtgFv0tWKhDc85m0Lj2_ka3-Xnmi^q8^J(l(kxkm1FVba8OAYcxq=%a-5+l+L? zY$&TUqpQBg&tPnrLM%IB%*ssMLO<;q>S59m#giM3n-UW&K`lj&E}w3DE}ld4K1~fB z+A&YdPNqf9RM@KHo!AM@5DgtvZ@###mJw9zolNBdq_Trg&pDJoSWKBegD&|iejsdP z4dAXj-SR_o5c3VJ+EH>8v0BwYpBC=l5iJqjP&b(>Gpb8!@;U>4y<_x;lw(uqS3$p0 zQ90%yT1(oZ31zb4B;AX;ML&ODDW@BHG5$;Rs@_Z$e86HSGRU^{7At-sf*_GJW`EbF zaL8DpYNl7Jvgln!s<3LtCT@hkqoS#^2QhalZOu7{O7$@VNG|3`t-iy&-ew6fo@6TK zm163{b1ahF5P1=1rU&c5Ecin&moV#!)izY8BbLWM%gK(or!Zf2u|0C&c_#p!{S1~j z*14*d+W=J-Mn=vVZ`n`r5|X}>B-cB{+pg_^wu*Y^Xc8n9-1sJfsQcl%jEf@n)d9as z&*77iI$>dp8)icdUfqB(v~;xj;M;kSRk@H|H}xDiv0yt*)g691wHtIb4c;YVjm{(5 z_*qeSo?wc#Bx@CT^5E+Yv3DySdkP8VlsFuNU^lCwy}2X7Bd@JRKMqy|QzR80pF zflhZAYX;J`M9-+E;?DwFK1$$NN1_v?T0K^M98enm-$-Latd=4VjY(JTw9qx~Rca3y zykbUNMbV(FAGEo|Av_#*BI+Gw2mfR>YFlV+^v9(L*u)uf;-_n>1`82#!jkWlq+{v& zN9Z==xh$1JVmE_$y<}(2z@?*s1LAi)9Dd5&*3GH5AYY}se@+GErl~0l2*2<)@gP)C zpm1h$26{8nfz$KF?0Fc={K~w22nsM~#R)M3T9}?Z)cfUl4|qSFZmOP&m`J}*{Y{X0 zWo2YzJ=WNb*G1s^lSI0D3-jE))@l!a*vfm@Ln73vqfG;NRgA*WE8x446OwND5Uu z&S^RqQ!?mEpb(d9t}E%Fz7Kh*cL-%ke85M#Lg$$U2)|kg#ErN*pOU@hj zhbSs#q4a6(=$iCqjJvb}$ii)IkxP%rd1q?BUwW^^lv=G`S7Ac4BV=njdZUzb;yNx+QKkwc2%}o|2I51ZTY_!M zr_g|L$`l?@?CsVkJl5zgcg*HLviGqO5txN&ff9`pA+$m>Cu~YcuAL$iD4WbPHzoH@ z+u?pqXBs1_Ssr;k>SR-1)P!NQrxvrMM=>Xc7?1gGwSukAc5V=KrVQU%^GhP|3NN?y zDGIMhB`5^wFlBS|U!0VqN(fJ4-F-u(jih1#1?PoJ)6!}Q6gy!j+wgBGQ0uqAc_wgQ zRZYJu8ci_N(%C0JSpGW%59M&KliNStsNlnyU{PECo4r(m5_hcmK32Hv3m1vpRRb%R z^9MUyHLg0R_IqS*r#Dv z%Ff$UC1>9G!6it*55j)OU%yxf1L8+0Sp+RX@62@@#rQv3*d!N z#(VmUIdKOCZ%h$Q5^o{iT%vM0$b7#`bk8OADqrwM)$<^t_0DnXM{26BZM53e3er=k0;P3;fJh=W6uV0 zbw^%@CLgWmCa9xWRNwPBNiM5@p(}Y)nP$SxDrk)_4XLYhyFzYkX#TCk^4-HaNjd&R zovcj@!af9z1lj{^ga4MzdW`l@ls9{^2j&T=?&p`|XYvPbBFm^-?)N z4rEI*l(Pn_*sl6Qs`zRAkyF>LwQKmhsMq$A(dA4;T&4x*eRk_TG6b6aK6Q#b@#k3U-p=OZeV3_`jne&HG zAy_WLQavs=O2NF)wjip6UA&d#`N@(KnOd&lG}>flQthKBj2hFbIN@mfKvn*9zvfPP zD#CaI6Ww8S;U5H?pEDejLw7JqK9CtU)W}%rys>PYCah=6^jcU z62TvfLwhU39|@r3_}YIbrg_!}(%11#$i)vQGiA_(Inw&EadOR|GV5%QaB%M#P<*Y| z7ss?(QVggX8sps!Zj1-lW^w%?Th-Y;4Sy-R>iex!rWC-5GA28jPV+YuDG}u|)vlbjSo>p2FU_+9PGjU9`=z zs*-E2swnCv+#j7^SY}TWW3P8Q(`D)}?C)MW=caX%@cYr`Y&YqXO*ZFOq`pUvUTQbZ3xk|wsVg88Z<#;u&QGy>?L7)U@nR@F&Z5isN@34ID#gc1HFs~evx4ZsQT!QY`oEf`6G08Ys0`Q5y9aPgQpj} zlo@8lT!ITD4Tbp%`$>EU&$DAEU4?PO;0oLYN{(?e)G{-WQE1x{BQavZN*x;BZ~tQ5 z+KGTI1?DO3wNpoxbg*R!YYhCW0v@X7UQ;WH0b1`_&3gKw-(c}L0)6C4X&L2?NLq1Yygt2yX+5*JS&AMW{085wZN_gMwYl08mdTamwaej zz;42Fk)=IKw2?l3v`RmzY=tEC+~2QG4Yrq%1yrB(!gcDuf7Q+0zEXTkLGt@Zm!v=Y zlug(Gjv3YYXC`$D6Vm``MG43hrW@C>6!*GAL40J%?Mz{f?Q2x31)Uned~6FQ^AgGx zC27;Iy+@8W=B@t~3+j-#+TDcftysF0FxTRNy*XRs^2MrChPl8exVdw^e(uT2Y`Vxg?eSMY!oF}rQ|mOPq87rSYtxQcj5Y% zIA59d$IN%?!*i@RoO{h3?OYD5!i;A6h8jdJ`weTs>A6-P*4;`^$?Nsk?u(y^`oAB8 zUT#qDVIQvBLTnGXvPX#gWjl0>@O(&5e}m-I_kAJpUi(XW`>->%AgDH`6qjo-&MCQh zt^YG6EM3)`7M4fQqpAJhSO@cI-n!HLoO@*=X9X{pz=hBkr{jdZ^?ED&2(z{sr2p$x zbxPTwyTIE>@ye(a^Y9q4xI36v$#Twm5n~|-XczssLcSzhHA_w>@>E6-q57)7A}3%2 z++X6!$oYaYBOfsoO3_=kSzBy7O zOgTcP;ttaJr%Ow(Yq0Kp>`f;K>GSX%>{aO^Dki#zIJmFOd1!9%a88L_Hi!#U5^!~- zB_ow3DDSSl%9?wFR1thl!6jr0#SsQkP+lG-4y78^+*!3J#NK^gCWB&4Y3(w1S~x_F zceMnnil$56Vz*9Pmn>41Bpm-8C+lpu*JyrmuI#qqLo`&(gN%~H!?Q0r^Lrqgr?EoL zmMVl~Pku%j&s9nY!wQQLeaW@O9P$@PYznDboJp3+J-e;ryv#CWT3{bWgjww-NFG}r zlyr0o{ypzavU`O!NzKPTG|lHie-P}*HHtW#{WDwV>F~W+A_F?`dy+Dy*vA0P{>j!} zDyr@jJU~+PBK;KFo%$ z|MH5HF&nVNueMar8C3@zO(QQPVIo9N~0aNg-Q(KwR~_e5L&h&Vjm`86NTtB;m>rj6p3L|kmbL<*mmQ$|b~a-T?5 zqQ=~TIdSqm2(HU(!Bdi}P+z|l$U+yQaBRKGqG?krHShMXRZ>A|FgK2EL>Me0!`;te zE#H8xP9Psdu`8m>mxIGSXD^=T14_gFf$D8#crN@IbdYpR{{-F|eIfY~AMdOwFns$f zsPmRS^F^Fwb;p#UyA*sw@!gJm&^QvD;r3@1uZ~8zeLyBl>dxQ^&Ji4^%W|=4UF7XQ zUo%Ej1U?ILtZ6&{(flsF4J&-7*D%e3k`21eTxPO6BDuUiYQ1Gxdp1J%{ci2HAfE_> zhn^)SkGZBFab`yjDR^VZ!7M^sN&Ra@$ru!Kk|&2^In+<^9}Rf2NDU?|H&UzDt(&M0 zQ>9{oURVrt_x&T{z=a~30|}q&fi&=V8BUBp^yQIzLi9JrGjmq!l}V<=>(lQe zyoT;qlC0vFV?rq!r{XTGZ)Ls%LGS!!cn z3$lvw_)lPMKJ8n)k$bmtc#qZ?ZIL_}XyzpzXkRIVclYB?s^qmIthqS~vt-A*x0Ovo z7`)_|i-(sS6uVu$c6sYZC84HzpT>^k{vvG@RU-|8wqi^}>p~V`M>Eqle&L*btu35s zeQgPcFsM^}*`ponsF9YX507wo<6Jyto~Jn>X(|1$-a1BKz9YGP?f}}PBbo$g9uBqo zsZsb$f)f3!cdl4EWYNN&zS`YI1d44Ayeg4u#P(1Q>^r%*D8K>oL?=|56vd!6UZwhN zABMOW{+9BJX3h0@FwrD5S{>~1f13irdb{yEOC?DpEnwh_{tOBl;;N&$g&vOAQZPsgQGgkU>~SQZu@TB(gK0S#q8D{hl? zFvK5Nm3At*$3^xt)kp#q6=&{g!wL)_yT`F+BIA46+Qd)1LrZP^>R&=8i`*g#IGV({ zpXJ@<9cOMk$Jh+AlOO9hoKs_ZgJ->xXjxrN3kml4M@^{t(u z*GK2Zu0Dm*=VnQRuhyd4l>adz4vJdiS-%m%j_U16cjfT%>P*R4h~Lycv*oD$YGXj_ zL+Jj2vgrDd$*oD}c}LxlhuNCwZ*3SqBJ{0S9x?iT*fz}@HR!vr?b<)vQboQ4FN5kK zPx+%{xl>Lpp}a2SdF-!UC&=+8EO9W|pdBzhyBNoGWz?@?+XV>cV=m78uq!L=j;bvD z=Ms1KTo$*vw{+sV2!_u*L@b?&Wk@eZXf~j=B=4$StalsiQ5vwdE@K*vUM*kXpr@Kh z$soCDPqW>fSYB(nkQp}_rP!%i52%1a(`|N-1bkkPi~&u*uYJr8Y^ELZ_njIKGKa*H&TMFr#P=QYCw%0ew?|K)MlbQ$}q>0~0%sX|WgK zY7uv+=1?AqmYdhKj9jXy+u#|ye!23eL7Il?C|q>4mEg!}QW^3`TV6z->(uG*U2<~W z&*LENYm}_qp;O1EHDBm^2>2_{55r_P?H*s%mbG#e0~zg%NfTArcb_-2omm5GBC zDvF06r4J=mE8|mg z+N8YE_dQ$}becxfLc2}ngSqtQgdZ;@9hE698tW~mbiVT7M^y}ibZ><~OGsvF=`gu- zU;iYRf&v}8Tq%t^j#~+v9lGF{VUeJ(U{Gz0Jz*RkT^uU63HHDL$JjYUX`)11I$deo zwr$(CZQHhO+qPY4Ta~u0zi$uT>d6~)j80$}gIFi_-d`mvn@OJBp3CQym!Z<-O|vqO zk;K2u9{6#=xcEGO12EZ5uRA?73MVy4H@}k58foc1G=^Yz5Wx4#!y3F8k~4vfst#ol zkG1_pn%;l|Y%f-bM$`&WK(RBum zOZ>{VQ64nrF!IHH73h@slaojUMb54SyQt1@x{%@+lc>`$tpJiCeFE{+hV0TL9TOhtI$(h&-N$*4R7 zKVw4Yoy&oX+{p76!M2S0c}N9bddTrH@orl$P}@)U!W!?C@Ucl-17r|w^dd1XJzqH{ z`ngO3r#2oD;$$4&saz9eoGKkHGSIL09zBYXr|C&NU#iF%#jHui6aBrYKcf% z1XYfq{@^G!_jvEB9VM1G@v;RyzU5n)+9O|3sb`0lgxBEWaHdmyr?8QU!t#H8(anzj zT4S>Qv7(HD1B}ZBM#_i)Ct}p=THJ9#n)NmEM;XppB1)bP4)W}6;U`4wNQyQ`Q*=`hMV9)Wz^uhQ|Vb16U)-s-o^V~B2 z^ia$#cl`2K?;_rJl-Kl|Tc9V+k@$emAgbTj@S<~=At7JJt?;!1mmKK^f=y(%Du zu4+R?ChPH?kc@O{1(_b4dyxA?6p^o6HGIaYU1+Zp!KI{rpsa&XN}ilQ7Af_-Lmc

vKZ;7k%vQk#=KaIFxm|$;HV1Y%I(k9JmZ1crxVdv{XruO zoauQsiYs?n-@nj%F>W^P4o*GBxt?{cWXOcyLH8IOE$10Ut3P+bs9|xbJy~y8#0^gH zUzoM7+?;DD1sxudbDu#N`WGB@1wE+>wU#e4@QGykps!R#Y@ONpYZ7>-b~o%%$U!X-5}2e9{hH3P+7d0k zH}{ODLs1K$`wuMa6jby^!CSo_h2G!xXD-f)C}yCX|N6^QE(vOBmZhk^S9&)MMet9) zsT#^VT@;*b2vwxdddB*y;*Y74%;v2X{#aIc~vs36OTh|3im$@GnJLd`D*QD2Qk6& zSU2^V@BK`9IsS_+v`^b1(*&Dr416QbPCN_5BZdf}F*ny1`Wyn|RJ`mE&Zbuo4lcy_ zr{%H3QiDhY228aZp~YEu=<0UdJ7THbppqpN*3!6S|K=4D_`lW=Pnj6Fo^J*wTBy8K zmZfEhqu^g6&MkgBh09l?ti{WeR%^CQ`#C38IcC8j>zLD-9eHykm_yNQ8UYxkq>;z?K5$1I!} z5i4DW@y#t|mxQ1li}HL@4t{E}715Tfy1rlS;d9YDOW}x9uXX8efl2b$zhp|)^o9U1 znSYh?#u5V@19YwcpgVn;)(1RWlIgRz_1Dj_P1HZku3J$*jZAg^Lk(khgpzASE>AW! zcj*V^HUIfrga+8(J>5BWE*#u{--&TE#G;Sp0ksRIo`TwJFjq0@$YIMbaB) z{2tS+?IUQ^(&|FXY~`FTjWoHQKNPbW%b!h4q=iB3 zFT~?{$vSCOP~CgoH?G+09?>PVGp}|D*+(qTuTawnXikW_o%AEy z(+zc=Sl;x&#l_tA@l|mYScpuwZkE!L5~ZDMQ5MmBfMC7`i<%YhF7fsvu2wQGYOt*G z!~LX3^rc~!CRZz zG21SiYU~0J(iN(ws2(m-gO55U81quaS5{b`stK&Tm%`$oPG-bfv*>gJwM)2LJmwK6 zC@Cd5!cn-%upGC1Y_dkrus3M?3;3rw{n^rl_=t$fWqR3`?pWib9crUxYk{z%(P?|l zPbtdQ6!3-g-g_jg$-#sKP}Pj`;xn*&SinjZoXcRdK^7!fo%Qx!2Gf78WWMeiqp)NX zP7QnIq(mcVSrQC|mlMTkAzIfnH;G3N!vxGyaArAC=Zsr`^qP{T|I#?ih8?cxx#t_| zw3=U-$6+=_;8-twQ$Q#uwg*4 z4JLzqar@X>DKv*>Fb`Ly%X?comPp?8SW<0}ZmAwt5S)kDyfTqf?#pBi{gad{*7VlY zpZggA@&XC}3Hs;Z$RRBAoN>wyv9s^NN4ME0P9xJNq~TdOJ?oo5QMASFKkgxnbNX!d zTsW+we)Jr3`Ij}@aAB$FjylVSygM9XpoYOIMS|i%(oc#6N5Oj{g%8>ybgocQw)yQ} zj}{iPgudftm~VJsch9MDIx=kDbi89chu^lfSZY}>|CDwW2A@8^o#p;SPUzC-tE@N6 zOapY2<2#w4k%w^Yz55m{2^P+^af)*#3%9#4?}pR}ItF7gV^^eIlu@;8ptAGRj>18A zd=vTmYQ5klUw~--8ei;lkI+1ul7vwGtqV|zg4C6DKDo5PR!CtXA0qES5)qV_Ew2A& zGK0awUthz2x)2o|vQy?w0?B0{=qfZ#pGHAWcJ&Vf`Vini`iHS$v=QZS6wz^szPpCx z5g_gqmP9huc{tn>;b}T*M~-Ci7v>{w=`YJAnjs*kg9mcA`k%X_;ABbCxC7Xc&f)aG3KHf z^MxFqn0KzxSA|u}k9+Mcc{|{B5Wpy3k$4ADJN=Z3LI4gzfoKLl3$GR$xQChSm^CG$ zZ!tju>)UhEcn-ZN`?^!nWXDbsw#Q1zcUnli($XBBQl&6(6$b@7Ju~9Ucn{G6+OS75 z53Tokidan%t{sJ4>?WU5>#C|l5}^vgiV4LE(yl*x4Y4dQDxx&g4sLi-pnE)Gf-zk^ zB$!SVfj|yV^}nJFV2N!aF&|)(63+iETZH+4$rfSa_(Iy*&@u$Tr7nD zcR(|UTiLprITJF7+Zwr=iJF->n3_TJ^FzD1I-42UL3?hsd6}u|Zl|*$>IV0q-P#Wc zJ9>D~6(&-bI>I3Dgn)TKqU$2(9^gwt-rn9mCi#55TzT{W{7b}Ft4>@R_}1~yVnrm% z%KwtvgEs+92@Wc<)4R(P1tvE`j4tBNjLniGuz3J!fpl(iad|0SoRjJWo+=`O(VD@7 zLj!{qwgaijoXb?g1m>iuAf~|+!hnJ5>Bp)A!7v0eBU;y=oPZsJFlGbDDur~5Y|&5a z8O#YcAiyA)`$8p!b9;3K+1nQcxI8yDeoa47=!W1G89Q1dJUh2SfKCl*0zrD1c?7`^ zABw?%F^LQV!57wchOmK}AS{7jfVQ%iu(N@*;MDBc6kr0mEr!ZKG|^tEF9>zqP=F;EsQ~ zJA;2yfBvw4VweU7i17puJN_LOgaXK9r>~2r+n{2Y~um zfjuk8M-1!&*9#s5q&Bg6{LrXN$;m+-Si*yd1R1(Cp2U!>;9j0WGk(duJ%Vd9eZwI_ zCc3&feW-|h7?5WG=${zQkrOl0u(;mevwXf?CT520>-PX99Dpuc8ORN^V`#S@9uh=D zIA@?=p}S9udBKAL*QrD5N9Lt$ZCh!EQP37D5&dpZ^9XNYz~gU*La$MZJppn2It#1mrx$a#^sMjA;Bc} zyR*=X6Pw2$kV1NUL4g8*)w=>znhcO3cynk!;*Xi8B4COhp*pljKsorn zUdY@hTZIO8eE{AFqFv%#DOku5YWNLcu>e$(9i1K&8s9>iep|=@E-Y>#o$o&t<^wv< zK>&efszIHc**xDP5YB19ULbWVf{HTR13X_HzjxY)hB$u+1LI;c@=_uSz8qp+3!0og z|J_YvfqlA!_HBT_{~Gxem6!2ho?k*Aocv6K`C3f~1P)ve5o`d#gR41#J2|BT#_|Ss zN{7-BX%IIc24^P_7(JYr-h@wliNH7r2nHjr!nV}~=LaxB4-Ef^6fzJ2QE*fe3}PP! ze_CjKfCJ$s2dD-}f#?FkZwAOPu%7_Z_wIo>SphnShsU6ffxmRl51^cd0a1W1=r)1n zZww_aKwm9@`}8-Nt%x4cr;vW~@+1;KKtFY=h>=)9bOtlsssGGS5b(qDn*ibpz)u7q z(GdYZJR2RIpn)|y4IqIzKHT?t1x?PLy%98}2NZAyFnyN+0Lg$@9w5kPFzwFEa)s7pWT}&SCD1Ww(42jX1q|WTT&dg1JSbb@(a8d@qAF`PtT*#FPeuVVy} zfcvO*8eBlaI)V7I=**~4Z+)7Xr|2!h~BT+t2KtDJT{4ealr1Y8a zW=sj2vAWFK9d&6#dixh2Xxfq>TqUGY;q*^VMjx~*iZ?%w@BU`Q!yA1t>heH=K(`)^ z8$s{4?Fa9438cY5I`_?E{D=qAiyzuvO~f3$>qzBZrSX-jus4bP%sM&fTo)2Nh7e)& zWIkr|wtNpwQq}LJba32`iN}pA_aiX0Xx&V!2FCW*uFihG{X9XtWZn56o|;CLt(DZt zjbgpH1xi|5?;nBmDu*bVn_}`gIAP(G*F>qQiHUHepph{+!7Zhdrmb);(&61m97>P$ z|42_-LEOr{4<#;lHfgWQ2#dcT4FTHQ)j^sk$p>}9Ln|(+j*719YK0Hh5 zM4Y1OpB|GREIg|A=gaIOWqmIUr9bLV=T4~(Sx)K`Qm338H9mFI?Vmw6v9UD&#RhII z6u#=rsh_a=BLc_h?E9yUEw43&pYaPri|cu*l~jr&Z9GEo3@2M5upCpsd1;qKDO`I` zQ-G5lpe1*V?pSrhTUvrMX8W*Y+1Ii0o zbPM5Au=g3CE#+l9qocsQ34R9#ExV?C06V3db^UNmz$Vm76*>b&nlp3?oz>`B6%7eqRKwj z4au7{S5tg#JT`#at>iv{!aQ28C}x>RwWhy-rOpi&E<-B;O;Mld^*mXVYxEHM)N4fl z5wd5#R=|hUWzM8&kq%=aoy&%15Ym2;7rzqu$~*tlDK=2@x8KNb(5G-TNw6UF%+Dy@ zzSAU7!Ax9dvQ1OSHtf?gW^76Blv|=hjroOwB%GAFFHWXacI|UT&X|fSE2XXF`(Yau z$t6Tuu{VHd5a_0-)P1S~lR3x3T?Hgrz+L1&*f4{zGL_NN!mx%w^2PkdqXioXw0^?l zCkk>p7L6Lr@*Aq;uq$qm9=_D)I4DYEdwzO(dnQUkRI0BsiyF{UWP|Z8g5%e@njqZx z=v)aHbb}_fWw(gX5>DaZw#TcXnhOZ(RdWZe<7Rtq^6SJV9)*fs&&yk-cBG~q92egNhj+Z$r=2FPnSvTYs^m%a2U4b(o-fh@zq%!d z&%o&eJN=KTGhaYg^k{i4XKO5K-?z7Z*E7i4 zt=rg8yH$Y6I~i^IosXZq`u7Efh<@Wy__N^a>6vTQKPq_e_59+T%!E&#NGlsN{diOC zTN%*{`KpxrJp?38D8yQ;wCT;P*1_YuJrj9a6u={io*jV-V-!C=1<`JgDeu)h@I92^ z`atnK@_;6)x3l2>;hVcUr~3(bZ?AKX<<)_ModZ*yb3;OAbZd2B5ODX$4TB#!l{hCb zel4{4139CpNeVl-vbFDc#6HtyI~T&Hi2f41JC@2r@yM;loW2oH8J}0qdKp?~)p3Ij zFf&oTykem*Y!S4A!KGK~c<4QZ@b|!W8GPCP8{IeFqz&RXC1sb%sq^5a2tT7YE{fyI ze6;P52qdlk|I;v&FW;17Avb@0Xw|`KPbI%Q~T3x@?8Ll+_N?jl+MK6rcCL zUFw#zP)KmshAq8wek5+GKQqvw{~`%|P;jQF;Q1LY|G{LIkgbPSm~rIlMK8h75p814 z=OCcCz3n8gGXM8$g*UlEB>RQ47&S8yVYS%&HWOdd+0}RoX$!m7U|5H6aqR~mXT@7` zx82Hc5TXevynsd6%zM7__Akt8)*17sht0U9^)is32t`Ai@X!rZxN?}3ajFLR#bRv3tcJT`I= zogY9u!|xwUza@;dPeIB&3Y$Wbd!%{sGv(1bvcThuVVe|IBsAkfop~L#bX5gC$Qt9C zO1RfY?cve7smh!(oz_!l_7`mSAwIy7BS1>Bc4WyHBL)Zqmu9M|W^2$*e#m>9 z>9csr(On6!b&AMg^;0Q?R)CjCs}jCxQi7jek=kog`z_b%JN;Pg)4H-x-*z}O3I7@u zXrO(g*rVUW9sJ(tYbVb3eRhs2l_`j*@dt1j>Yts(T5jrRQNIb+Q7`>8uZOVJK*gA8M zuMRc$^zO1|cv)B1zHlq+XoBb2-rl|RHI@5^EQhP`WXZ2WL9 zAQeBeDD%Cr$0uYI7m6PJLg10tL{_UX-k8jVh%gM-q%-;!W(54lZJPDR`RLu)24Cjo z-^?B2(M~1odGwm_!$9!LhOPo;*QJ|f$IDrO z0D7uJ*1bi^H2tQPP68N7v?++V$$!D)@lv-98Tmg~Y_f^eB#>=||yzxLQU z>(1T%F;c^8&ao+KB7madCw;8%r(?c}hMXawZZPChQ&;&=eiGu1456kg42WGmNnC#U z+*|+ly8`OSaH9hFbq!p=q4N+)t~SJ1ii>a>t?lcPXarA5126e6@nA+nnj?Ms9A%Or zxcD5BitTL$SwonAWa|?TvMzL&B&OF>!$4jVidN3b*5lceTUQwAeDZa5I*d znKdu>t;GO!)9|Ps4Ul8W>*j*RVm28mUKkz@Le&OKK7venatWRIG90fu<%7-srN_}7 zbW{~m)E6`_!J|gXWIm$Ewz1Q~e#B-bY%sz4xLi`&+O%Cs#<2IttBp~`qhN^^i8QgR zJEeJx;s}TWdT>0EkOwN|j#X^2>0{#$lS=%w0?0ta>t{5u5Ea6I5G@vuicJi!;z&K3 z+}Lb_ea9H0H8nFjolYp-qm!E_@rZuC!>t$n@f<$Cd7A8k-S;Pw+mZsmQN@FrD}DT% z;+r{JYH2@HC9jXNJ@4+2N@2fPDmxPQG4YL+FKv4+0Sc+mpt8s)mUfF;*1OlOiTnQN zy;XPV7i1}3mr(~WKA_`O!-VE7v*bvBoQ8vcr+#w8z(S59S@Y7gk18gZ6VKdsTEwbB z3}82cn)EYHZ<(>}$%93=CWl+)U`an&?*GXgH^N&@;Tgv?{2E4N`{uc;xC}u*FkEaH z$CPuaK8%5-c5E!savS3U$)tptf>i|*4tu*pKy{4HrHLJqNb4FmX0@BY1Ha4o<#;(_ z*Ps+`ouo5LT=_y`9~kprSR+sYLAyMustzNEUp=c84b6S$JU5~ik1MN#_`XumF|aUM zTw=o=r$$-M8g5gOY@EBoUy-ukjL_F73O^(&rW9SXSAu1ND;*;3k^^=Vcb5?=*Kro4 zcv4&acLm|aIkP=+d@+HV;-E!ze?cNvIc_fm`Xw1ixh$TeUe`nQnOA(jtOrFx!@Uzv zS67u(q3?E{mp^=TSVZ}B1Ud+K!piEtPoUnJR=4&zgR4-lCmS)vM4E2khe_T?LDzn6 z$=+{Q_NODLi*b_&P(s1iO;qgedrC|55?+jCP13h1t8dOzNUzThJe+qiAk(q;_@1y; zB`S(UoyeYpb~uVc8?2xtz-5qwek2O$%rm&YgcWb;vEH33-bg$MZX5zvJN;?w)EoC^iU_m(owWhWqFv(+tnn1N-L1*KG_HxOwh26YH$35**1&1O zwqOW}NOj(sAbGXAq$yBITc5dtr9AJp;~!}bk>yiI$mI$#8yTmx>w&pqia-A_9E6Ye z)As9GOzL9hzt>$o4*z=(QMX_*T~^o(IM(X&_Q#K{at@1ba7Yw|>jCAL;##M;uSz|7 z5AXphi{3rMxbP`!ts(kVtc9Epf6(M{SB+!8qTqCEYL~wPcDmm?n#$A_Im26K#Fj(s ztMgc@r~{ff{3GBqW|4e87-7^p#Yi*mv%KX3YY~5NmU3j?-8K0GAUTe7&H^u%N^{VX zodv=aKknlQJ5(N<-2+W#m1F9leJ(MFG19g4@d?-E&oCycb6koik+6*S75JovNh`XIC=!P9Y zI6uk*N-l8v(Ng5|M4gW{(HV^3@31pev=cehwd_8`lmsgAPl%IxGQlVXVEP7N&gO+p zsuufKcI~YXJ&y@7yn3`q<>u&f#i_Q0{8&K7G*DdMxE(EY2rE$JiQd+$#$038OD@M|6bH*(UfcUj5F9sMmB3e5whzhv`~XNaDZNF z%%Kt=jFtl|77cDgpfrv--3N9fONNrhas@S{Lb+^(%0Dq8=9-0_gJ)a=MnVuGHy*#i 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�Ytld&yqN4K60_?+qMgNKm$x&KwIXi*feI!YiC{_ZvqR!B1?%j9_>6_eC0!vG8 z&SH<6vGNN1L#lc;WDROy#LM#ve9ds?I@5zc$4ySK!1R_c<}k581MwvVG92{dw%u@N9 z;i&jBTF55FfF?)v#gsw%20PV z!1iY)y7H@8)^dO#Wabf2I%b}QUzKB%=@A(jM!1V@c)ekB=yIcT@f{yaau(Uu&OBiu z0Qv}wrrsKHo{TVZg!^Y+&Sn2MyV-iDaN&m-S;0aPx`U&7Gy|!WXG?wLv)>F;l}?VUe!5tew$YE+0u;A@bX0zOip1JqD3K6@;JnNX}jL`mNcbCmjsr zwm^g!!&G zqg&(f!grONU_6&xcSw04DK|;Se*05q#6nh-kh-7LEOREm$zI)?g;MbQTO`gW*xFr2 zrd_RAni2N3ko^w_r>|bVe3eXO~@yVWnex}0G@Jc#pZ8+3lf zYt~}6d06s`aek``kXQekH%=V<9K>ef<+BUjTqOyc*!%Evcg$ctlUy9d37HGVi zmKtuF4B>L^I(+HEAeSaKfWdWfzobZV zILE)JbtXFr>iv-QzD5#ZJl{M;EW`!8@a^}7unE?5#;5#C?@O(B;v6FRInX56Db1uU z`scjWAA7Wo@;)a(xm86|2(5f&A`idXbTV^Ai(agE;}PwdN`jjDg(j19-2RT~Bb%CU z^e5>uX5rgqPaZ=w6f?BAl`_ldD-!PjGZKL7*f=yjVrU*+2m+b z6)H_@&P8&TUeQpB|^0~Ss#sCDc) zM6BMJf-x$5z9QUwfH+6gqDIyjD7N#GfdWsPAvVSx>t0p61DWN5PW;qTNUJW#ds#gF zST94HB7T<}{WI5U(tuR4U=jOB!B)gI{F#!vpO1R#oL5~Lh*(U)Lx@*_OYr2{d_`IS zL$-+q_QSMy8tz0r`B_5%%t+QGH52RYRODLlo6;AY;#>CTRedufZ4DfaKpe(osX0D0 z`0hrRAq$L7sNkpu8Y*?pJ?h|lRE@`KrNngPSXIATeghGs_(?_-~#u4l((GS`*OTi^1i8vungXDJTz zD|gP;eXb#TX(-3f_{evtYi8DV zqcLR4!|&R2Esv+Sr-|0H`!FWzruJp7o2xx#m6(3vMC!xD#;k$+{KSeL_+c-!_Hnuw{jVAsh;HM}M>sQn^qB(F+UHaPWxu0LfQp zTkP0a2qx^d#F2>~sM~DsL@bXQ4T$Hfuh|%fCS**En=eEbSpw8j?77tr+L+CRLI&`{ z??zG_*^h!weHWH;N{h9iqUEUypENg=i)a&Sd|Q5zn;LyIRUjm8kMe&`Dc6V$9lOf@ zVu9AE_N`0IJ+hiK7w<9vo^ZPPo7~p8fVLCWexBN8E?<0ZDC zBrj4;LdS+h!ObKm|4_+#grk*I3lf(#rg|sagl{kS^up=_W=@pH>g`M?k(Sj+G4r0+ z3#%_Byz)**9tD9Y|1US`bK|k`Gdb^l?51X^&&^4t_2J*v*4UA@4_e~o>5;%UNqK$)jJ*cb3rV-B{2VTX~~XRZN#Y^G7Dc_ zg3-)RUFhs-KnDY+-e2=uj2BjfElPELg1+Y>!E2S%VrX=NIy3@e9LJoiE^XC@j=4& zRHTPYNf5iNq4xeIVBmtFgvY|3Z4b@r7gJws8R5qZGl%7lNFsZxbVdX&m~J2} zqN2twp|Kq8WkB+YDbhzmWfCqVi1nyYRTnwd zLG_TL>~Y3=Ep4vF%x2ix-8K%N(pIbNiMsRb9`3>%o}b57ir1|Xz0SdzYS+O3u#Ruh zIB~CneS1Q&yG?SoQYm)eslvXCLq9p?^d9CIZTy?{yjY3egzp??rrbN3!#D#$S6K&) zCL~@;+VO$2U`<1sngW!e1*-S;bVMwrUo*+h3$7D$dTEzAJ3Uh=Fo7qMUz_XMGz{H} zzUsMh^c^`icWdmD3`Om*cE^e%3Z?imB~YZOv4^;e+NS{l|o{LS8o%cW(Y#;-3 zccKbzD!+-FzSuis#y0YB)_u&|v=Dk8=4)1KhaUUU3xL<8rWK|~)Wz)l$x$QR$bb=k zYhoBAoZY20V{Xn#L-!+K0fMdWY{X^KFwom@daziK9-Gf|X!$Iy)Z1k~^@rZMjB@T^ zKoI9h99rl(Kl5JlR*V&O`Y-B}*_r6govZyBqT(+&)Kc>X{4nobO1`nO`iqWOye`Ik zP+8=u{>e3cC1ZF#Z@(a!BwJ-OAK;ALvT2^z#eQ13(zRfig)D%iIc+~GPmLI;kBW8j z1D@8xF9Z&lrABDDz=h>&O@FHskI5VofsM6&EE}6CiPrzkPoL@KJ3$PUo;A8(RNc7R zdQQ}*=efmd;vlUhy=c-_4kg$r##~gJ^~UKtnpDJhIk#HLq`M(`B|w*TD!lriC6_*A zNke)Sq+s~Mbap`8TV5o2eRdV*O$N||}RfW3p6m&bziT+c6SVuOhx za3`Rr=}H(XU~xpX`B8#D`Op^%AE-v5ncyHzonk>xUAA zoMozXygpEEp$PK?G0^tS3ZYjKBY}ApW@mnb(x5=CV_Q_=hX^ac?AQ1eYe5byU7nh3 zN}6@ekax>0zJ@36Ei&=<>;XHukhSfL3G_wFk3^1u(po&QL}L@my)MG}R*VQtE;Q9a0ddc|S;Tro@UOt+`xmLtsw^ckTYGL`l97x_Y;Iqv z)@dOnl=>V_I^5rC*6b>xuNz(WO?@F=z!yC()eG!}psJS|Fz|YO@ ziK6BwS+6A^C%L$7IB-;5C0ShUj(mSL4=UCaJ6g!N9x$vbh5KE2U^@m~I4cLnei}=SRr{_)_9FuS&`;TK13k(u|i7RELv@YmBdUx5IPfx8y!-$kRt#_n6J|aoZ#Prj{FqgU5Ezd9-RL1lpbNkgDX-I|^V8Jk%FoHF zpCK6@r?7hZs#&qk3DUVL7Imv)2LMZ``d%6VmWdurYauc-wpFl>=qv0B7L{LWxT+Tx zZNGw1Jz8r&lJ5md6giEmwZX+fZFp?Zygwzd&X^>)XdLU$r4~cD$)F~=If(r9!m_e> zc7|jz%W3;`bP6`zcT<41?yX01I15ijiyF9^QJ~M+755A!S3KE}P^qys2rZgU@x96~ zlNWE_-e2!ZJQl1>;s?W{&t$2sNFF#0u^E(q?uHyS;lbf%#x&-j6Q)Y;XsGUr9sie` zyOCM_755gd7*TE^A?`lx%SGzOycv^OGwOWB244hsOV@CKgvSwWHO0IYjoy7|rJ}s2 zaa6P`9_D^DJ>Yr|V4hgZw2{on|Mloe5t0sie}){(Oi`+@m%-BH4fmnWNw$8-XKYVq zL-x+h$imNIo!y05po^u(X_9z0OSs`y%{oLuY(8hlNVMPT6|ITN!Qr%-EXpG_Ou3xL z5>bj~zmZ9#wVn1x+dxOHI6k|yL_jf>h5VpSt7sbxEvxU!SE@Baul0gsfExz^TWV{V zm(r#`i&uk>n6wwI20+7vv1i}~o}D`X&VNWOsgL{Bx`XP5$xl6X)L8rmLRN9qbw16P z;i!2iZur3zzZ%sGKs;=?mF9S}Ek_RUg6VoazzPlOdowqUyk$iqF z*mine6%@|EBEhR7F3tJckRJ!TgzB08;4DGcRUh4**0d}mRH>d+@s^BglCa(Sl5m%4 z);7hrvCds?bVM;ic;9o)PcFjwpFJxtoM|ly2yh8uj75`Ldjt$cumV` z%ocr}fd9F5RmeauI-@&5_ufO}r14Z1^ZaS#4dGTI39sTlbeQ#I$;F<8EfvUHA;@jQ zTiq~edy#?l@_tL#sLtOzGt?wI=G*1Bi0>D?vG+ssMx)XJg1vb>bF_jBbh3i_n^#(7$Vxok(Tr^ljHT26}@)Iqs3n$U{R zE&@+>(WJpE(Xoa|`d=1l9FD!=?d`oi`?7?V zyTA$ba=ivTWp1=Xa|1s|3Hg}&B%&h-Lw$%`L(ZmeisCG^&Imyc8SON@)6jRlP5(~e zE=r91HkjI>uUl4m5n|y4^ZC0^*|q(q-C~RPkk1jVdmFQR34RhI1(~geWl>jstDT(& zz8$3TNk&E*0p!;7%`v6c)VvFYId`?Zw1C58&a@&ATk3c4#_^in)TUW0BFsS&a#Tp? zkDWob4o{}*%=pe0@VmxKHiIY;?u_zkYzQR_IA+Zr)=sZ)jp#u`x;oZld(fo;$8=V( z(DC{9)xVsPbaS;voqf*al3m|xRm_9p}d0hc8EH9Xug$Mw%{Y$RbT&#W-{p zS!2}!%+4<|^q4pVq0Zkt7m-@26%&8{^iOlri@l%yRgpp`(I@Wk)xt>tTym2U3`?lq z4GUf6EO@vHG4KHf!5}BI!d2@mf9VavDW)Deby^R>)eknZb6A>H(k2QQh19Rtp;Hjj zHPfb;;t>t;_+liyPqr+)1`_n%HwOM-?LU4Etq&%sTnw-9!ulS zVBIs3SB#IaXDVArF~!s1FVD8!vr#>PZOSlSju@t{qR(HS#&a;wBI(l--{7FGjz@CD z>>QQSH0VoSjz5tYLHiHd19gTmO-;@AmW(iNOO7K;d7&=cc2wPuh|;jf$&q?-bXgpe z06IY}N>RA1_Z4^Mgni&>rYlp8#G`346&-_~E$t&3-vQ5QSvfVrMj745ge=%Px^K&F zA0UQg(%eIaqR3uFGmL}2Ph2C}T;UW6YPY=|*Hm*UY0bnt6szc4NrW zO6v9m`ZD*_m=`62HPpku#0}|QAsv%DhTl=}N`0%Ae==}5m-nN3uB4Hti$ZgnzuAd+ zExIf%;+M%gSgOJ2dKocs{npN;@on)-V~y6M;{ylo2Vg5DF;%IPsTvGPj(2+zS+2jD z+HJgg)QpA%8YiJfGwLOSMw)lhBUyEJdS(;bDua4P2Dpl}HwPQf*2Z%tnTGSeD!TP>G`Kig90}RlGn?URXDVwrU@wbz1qe z3%G!^bJ)%jW=|=XXOFL3dyXj4=Azmrxuk7BjBqIQmQrBPGJvRkBiSpJd^Q*-$)y(zJNY$}JZ?v|+H~V<_+>=Lqnu#4ONvtYUxqHfP zp|F~x-D>3)t3=^F>2S`(TqrJ~*<&B3S(($>3xmjnL|pJP#Gdc2if`^-SKsy;4I0H} z&99dc;UDGKr}U6G`YcCZ;cu8feAX6@pnsWUnL{P?e(((@9J((RB#DDL;%r>EjylG- zq+J`_J6cP6s4R1T8M?u#8PBBS3bm@n_5pWyV_)t52|1_6D(lXl8K@<>wb5CxQsAPz zaB84^uCqMtj6L8I3fYE}%m+;wkV)Vgn4!6g6r;IMtYdzmfQ?(a3kHT;k#ZEokZaoq+F;mrsCRA$4=Vzd-A@g&;C3I{FM z%Kaq2;<~OIf8CbrWGW=hp_m+8b+(!N!jm?mz;lfv3u8-9aviGdSsA-!@@{lvvnrLg zvFF+jh?B$qM3V|*z^X~#IDlB+Zi0+Qq=0lhI%Qq2YV;-QR7VavU6t)n5mRe#7!8j= zQD1wTak#UBp}?Ymzn85KUjMQN?ev~H>(;N?Q>X+~Gm|OtxSNN|XKU8d(NS^17{qnYlFy)Uj48ZEGY#y=8CI{d)3qdyJwg4E#2~Lmonxd?Orgh+Q4;3gpS~6SmVy90M01p z0z5v8vpcIIpU|({_Y)kh7zGSQr8Wp-DYnApeF*sH%G_qhZWr+psP6&u_h!E`Xl>Y| z`n2&Ec;((ZVs}D*oB+f@P#?p_5Y2MsAl>$n(Ev|eTL9B8a}lTCJ=f(F2G|U3@da{w z)x*&RX(*)qJ@ph;##}tyY_f}!JOBMP0M@nc)cJ8Ex#+K(t6|<2d5W{JonQDPu=c$W z*#i}$bCUt5&MaWQzWtFx-qFx_$%kJ6nv1guoHx}G#`hr!`Lbd>?~Zcy6!te%3{^D} zC)#yP0@2fgUb3HYit}Y8Z!hY^?3kxd8oM#Q!gNX0#dYdqX0*V9pb-2kgc5?6jgg-T zJsEEVa9|KEgx70u*n})yHAvEHDA4oe+G|#PzjrKFJaAc^`&X_$V90+`K^xRZ#kj(* z%$f0SoP@^oJU#*X$GJ$B?}d9<6jvUsu+t@dXl^j;i1?Q9bp?YQK88$(q*pW}{fJ)v*$77|VZbGB_Acg%VT}x$eQtZ<&;&lWat)0U?{YEJ ztbKWKb9EoHCzp>iPFg6Si*>+Je)c2~U7FhXj&X^EEyM=_(FgO#q%+>a`|m^j${JRr z3;4zd3Ei3^#FlaC0&&%(Y_hm%SON+-u1MZ?_g#2-)&cyMAI5=dog?P>p+`Yta+ZmW zjs(JehS<>cIp&?y;z())OvW#FIzrg#s&JV}?`8vi<1I4~Ct#33MFgvr8XqZ3bFvR9f*&^A$JQcOfWlZ1=`#CDu zhq5|5_x_!3ZzU56*7Q;ajmN1W0W+slkfy*iOridexGHU9w-S;9421W0STirpM zMb0^wc(#{qqJ2AQx zZq}6EHM&%M0(>_&b`ixCld)+Pl!Yht5}H1-6m7F2s=l#|3H*`GH-wqn|x} zfgP|I8T_Uh6S(vwgddG2B*xg(;M>7_^tbZbq)0T_LRx1=6VHwc-*eIq2 zL%=S^WY4buSL24|W`actF=|Eaa`$1KshI4;=gP5wcnZ#{f>z6WqHT|(O&Y|e1FFYW zm-eoc6+$)oay5fOHTBH!WM~gjIIbzkOC^*g?yEyjFeT(bCNe5oKKo_T%=veG$i(Tg zT3(eZ>Q7l)l*H+qoW(HGGmG%u@R(d|wH!zckP{nVs6iuQ;&^SX>{U*`>|5JvEf`rJ za^C?BNVD>G4;)rMQ#qkAuc;c=o{pPIdRL?*GG)Oys?b%&yl%VqCiG&J_18q+BV8d% zS8!067$*J3u`oZRbZJY7fWZlT87=z0Ye}nXNg6VR3hg1#0A6TkNF4RX< zEd0Gpz3 zo|$A>3qF&ZZ`rqeMPn=fz3pSQ7_s5QB7TU)nf%UDp?a-nXK!(Dl>l=L_Rb7E9hc^D z*b?DMc;2L4`8uJGF-dEb4$UjGt9VH#ei+O`f-{b9{0yu#Ax zMB-khECMr-&y-_wh}3t;Y657I$j@&vajfhSU1xeCs_@;UEedHGYocy;z=w}@w5wj1 zWUL}c99FJ}dGHC`Xhd(b573_xHq!?7GFAiW(7P$D#hd+x!AD3LJ!<5?JnI+Q>Z8mt zrn6HyZc*iR6Cms^;H&mR?|ku#deUAoO3x=cLoqlX!>tvE6R#P>aHc_eocZDhhOI+6 zHynp7!VccNUUDf<@cH<L8q9Y#SEHSsVUChutHM039@p&Uz(YR;q4wZxN55> zV1H{M)j`>7I2^Ni*+Bj|#7EjC4d;#ROB1Iuh*;p%N zJ#t{D8QOm1o_(l#yNwUQezG&?R{((m_z82Z zyhY?jMiL&jVWd+4_F#BwMhrp44H5XOkGJY>Uw2hgso38gtssG$&nHO08~JJ}5HR|d z#9!#{SejNDuyq&^$?>I4ItDukXQ$!z=?6LGgC#L!sT_|=XZxw(JiHGK_47UY$c`{R z_ImDx zdbRLV9c71Pg@}&qSNlzL45PQvA7$;Z)`jd3DH}h92;kNEwrm*0f}mozyfhT|4GqV< z!=T{=M}1*oKWBzJZt0^E1;&fmpSrzzm?cCe)_z&*IpDhp4*|AKlx$pV?dVj+^=+Y? z^_i&|7FEH0@BReI`Q5;CfO)YP?eaakwF=<5im?wq6OvKg<+Wml3C#v>%D1?K^5@4E;lQL~4?-Albonqh09lIqnLEy}UU8k6K z!iLu5Z5?E>C}6!}V;@%9MgvD9rd3XhhP7{aj`gu=7;7H5?RqbxF~H+01*e=*L@~z= zJ)$E`_#rxAF~I4C{H($?V9`UNHiRH2NaK1#dQ1FXXk2H7EP*joPV${@HD?^sMJ=`0 zFFE-pf8PcV5(IG?UexndpB7xmuvXfjYK-G$`JW-Tu241QpIzM(GI|)q{bzSboe6DA zui=_JCn!d77Ck;p1Q8-rht`Q1 zC}eGCSoo3B-LKc((xQOE7!WR{D0jX4#qkUkShH)OPOVZoiE*)j-PJ1-5jb1nvhQnD zu1S2Qkl%Q7q6ibd#Kk?>EP%SVZ5;nzO`MPkR>o3%h_cTQjtzN;I6OyzY$R#Wm`CYS zzB#}J2O`o2*SEi7oUUN((r8pds6%-kHCMTqwIp!8%qer|>lWzj&f`#VX2(e77 zWfKG4Rxzptn0;svmeka;H+=MrLJM&H`^KPDBtgepYv>H%&=C1jcrP6~%S3TRl7yEL(Ccx(@n6cR{k zzubmTX`a`-cQi(KPokJ5YExbskwmopa+o)K#%hX4+(~2NjVZdjy!r9Q%5E4x62BiM zlS1WevJf4-ePLx;O!0xL(}L*F9ps23vSZCoqI@jpLAxW{OA-EZkvWFqE6>Iz*sRp+ z9_5+mwu47Wn-SLwQGg(@QK%1P-Z1@z0OMNqn=CV^HzFbSQeyH6hS)c-y{w# z^VZtKMVHhkNH7Zt?4bD4pOoK?=;jGT>Uz_Ej&f+iM;J%o4?AAg6b^d+!5iL7md?X! z86VYm*=H%53AdS>&{wcmxxKw8_!5Mn$V%5qbG9*9P7~piC)w4IGSB9v2ne$QC=k3~ zbD&twfkuke`UFRJ2W4WUNtI~L?gL%We)O|coU=q6h7_4`Rvbua+3++1JtScCZZVsX z24U&_b)CEAhm?}^X8xDxU1(2Ltsz{6B=vV&v$|IvA%6G`NrDL9%XAMj4{On%lhZ>$ z?|WI?U@6e;S15%KY}wCDgx5vNqQ*aDz3TG6N!nwvVm{!!4sc)3gm8TK(IUQ0#1Bsy z7ee%c>^v5e@pD9<_#6kjnT^9_>gs;;Xa$^>*3Fl*s3D^+T(X7&t5@{v#D+tI(sD6< z(-3biXof!|T3Z|0En^MW0klX4DP?Sra@-Ok?_zK!$2|FWl%qP3^y0)m8PXlkeeJwT zc~Kh1ZY2+2uc&F+U7@zUlM>JLcVfwcwGr#)8en%jH!y273O9dgq7t18hB%`@IupOX z?u%orX=*_{1ehy_RGsi9*webF++QX`PtN8tpySN{-$@G`r zs&DKvw#p@YS6#Ye>WKgx(&&>LZYf*URM0AC673}8KG#Xa%-kiLPp;`+-9iV|ohKGG z122HPa*K4~I0lJIrE@nz!QfWsn*e{Ja?y3Fh=op|XP*0!@tity!!82O7cg4*9SCRN zhcOhjW9ge+q?4aNUcV!%78EP;+5tCx7Le&3B zB|fp(x#6ymFFB|nR;s*O>AtFF;F(`#$PtYhrXoR=FfyG76Fv)3sx7?(E_7oViUxlu zL#B>PQW_cVZ83Bc^2gV&+b?6vJQpJSH8|71l2~w>oG{+7l0F+Oyp;6yJ1kfDOp%*ud1|=ow+3Yn4cI*yF{nL6*p!UP z;IKSk5@6Sk&JRCV3;wG1`Hb7IA+$30T=ek53GocMBqPt~l^z$1)}=!uzTeJnIaf6% zw=nw=Kbml_M@*h+bMNv%q1&c^OdmO(IcIgqPc`sE*(=%m0E>D@XUck%C5R5Yhs)b; z;wb6(=Rzn-wFhU~vkfgr;=G!0=!81-KcBNAFa+`D(o2h+STuQJw>Y%(bcK*ls$B zSNbn*9o}2zE)DPgGMKpf^(Fn}%qAmqeBMg|2gObo^Tq9#3@t+PML2qC@M_lX*2#h8 zbCj3eyg*Ee75qve`3FQb{03I&Dk7z@WXune^k)nspMXx-22upp{WXJR8SL45bTla@`rCW3>Lw_sEsNpG{h zWVLxH2qSWVef0;OM1e}M-}AqSUsFBs1wW=M1y;W1i?NHIsdHP#BDc(etB__ zr|KePuo5HH{H^Iw)$a&ozz8X81JWm7sU7M*C5(>EzAIGsoYi4FC5LY zpY}PAwuB(9rLsxDhD(^{FF$EPnLv1VZh5rzL@D+;4&Xf99yafk!Y%4F?ebHdR+&Wd zv(=!rDp9~A^WkM(?2&WBQ@~zr0qHghg$8i#TnX>VK=aM+Tim@C!t?;|}$l1L04yRR~cpgpL{F8L65d@Xa36bkhNn}ZWH2fun@NWxn*c&KGl=)Fp* z4D0tCT(bGq*t>e>SZ0*WEw{DIv|ixUf>RY@s+hiJMbCjTjm7ZPm!+110#i*r_dIMW4RravZxtFYtw-fn-aRo=@Ez_ED6x% zoJ_RilkAFNxwS||L8l$26%MY-ev}Asv6e5;Ewa5<{R#M`7AV-LKV03!XBd`vT<-Z$dtlJK3iYV&u>`tFm zp_WYSu{MhZ#BT2r;bJ0Rers>Eu2?CR41(#IK(2n)n_{rB`{o0UW%k9VefIE+&mA}{ z_{iGggiAa}bu&}O)T(m&)>W~!7w7kv{yTFQpdL-l+F%RZgXFj30+C7brFthw&Gzxw z)PQ1F;s6^#iuN}58Jd6t2oEnp1d>7?VlRfBPoAosy_6v+cx0^#%z^E5vY{OBARBh2 z&u-=*HjAu3dZ-@Pw&_bzcN_JLcVyQxuCB9_wrRlK1mlsPVwRsCsRuxRK&lN#NG8{l z(_$Jp4vSMbj|@kPAtIM@IdVKU_=J$DS~Sj;a4s7)5EP-s^l4e(i}9}m>8xbl_2j!} zfIt&`&pQ+pr*HO4h{m2>?yKaF97FmrQZme`-rfdl(cnrHV_A)Qy6nhwqNh?g8 z6e1d$y02b*HvqXgH%(uY{@dM0%qRbrx^`Slb)QzdYbl!KHbW}X(3);MOkApgn0E9) z>xD5pE8#aPv3+L_?e$c1mIWd2<+b~u+6?f3;G*dMxFv7HfKdI6rp7+HTB0AMy;lsS zQjW~&>9Q8}5F~;epHX;6zbk5k(LugV%&_fu+?tjuG}s$>w``^!@5!n5dQw z>_YJAM$6Zo=KXhHL{$VB`J-qPn8)1(2nc{SvqW?V>l&f5zZbr2U{6AuP2i!&9`UHAkeB|Gl?Vpr)66hmR*V@Fkw#xE zV=<=Y<#>ot5lsX36_3Qo;|uAx0j!3*M`N2d4%8G5!SsOf5T~#zm~0MSvc>xywzp#i z@BA2MDXaY^BR-bX5s$U-VuE->XmcbujYQaPFsrh^GO6Fg?&>dD}Po*8ZWCVO@2CB>XRLvn z_BP+A7kli%U3`!ekos|1-acfvF}AS~nAvK8jb*+wbR@E=2=OD{42;z&F-{m0XqCTi z*w;`z>oU512T286#PNJaj9-WI5y7Tw%8O-zhuA=HCCuisVF&!QmM#=U`5=dg`;GWT zsZROuJ}hAQ;d3wHCokztc`VN4lt)ZibA+ib--ury+X;hM`g$!Cv)Le7@GMwhi1cH( z;1?plLpk!c>7F~%8*p;S2~n!g?1Z{S((??gYH^x>ILx+t3V){xDW$me! zw*vGX-}@@cjB)$T6SsV^`p*trD6d3db0oL|FfRKTnvnTAIyCrntOVRQ=Ovr{zDDeN zR(?CPX`c$2D;C8iY|M)D2kvcTLugqJyqW1VVKu$)P(+8#Fm9_ZKGp(w<@EZZ zkHAhVmg-z?juL&JHon?p$fAyZf-w+4VDQ%a>M*V@jzC-W-zF`YVZ&hS$r}l z;}vMSWHnA{@`FlX8hXgbl>@NZVPnL||I9#93%BP+}cD#vTP-crCE9ur3j``8Dr z$jK*7f5zbiGa^ zMq07~I%RxssikkzIF?bI35Q{Qy~`zrAR6mcSi+dkxn>u?0JmlD+cg`Vp_pWC&Irbs zx`tVD)1*H~9M-4MeCU42E{KGR@?Z#T?>nu;@nqj=J zw+Q+XEUOW;cW?1Faa2mvamd0~di8B3b#=F8&}{MqvaWPlB}E}BL@yd_xh^$(E^x@E zrj1zWZf55JI9-^h9}S>G3#Vs3NnU5y_O!c(=}3;)+@?`^k$uD_g%O_Ab~&Y@(D(ZC z1FhN8H!@Tn@g0}mlQeBGMT7Nfwd$PBV9|%NmriWfLAH&D{~urB58Ki=L>xij#-y2D z{G4#DUk4;=tF!vbPutQnhnV9(??&mT7_Uc;Fk><&DRnHwsM(^bg?%mW=$@Abm*?)? zRQ$!nfKFnGVWpM-k+G~SCxpIxtKX?;SDeA|?Q|s@)G>JMZdgmuCF> z0H*9LWrasbf5NteLkKqvK))fH*akk-$a#hvm#P1U_zjPSlR_ouEy#`^mOFQYG#y2J zre*x|C8XWzepG1uEM{+@qg+gdmaQVLe|%py@dv;Cwnxe-#&n|D<^&VH%c)Wz`E|_E z7m?Z@g`A<{Ez(~v7VN0y-_(Ex21N`%%lx{1TH)~akDjzeT^@Tt>Q;8~i<#0;U+8)R z0$2t#4tLKO^iZ)I?DrJfx&3v!RE|lArGQvuhRb!~#N@}NX)>Az!o_N!p%X57Bif^s z=kG+ryL3)B*T{qeQNz7qHt;qdCcQC5$6SMb6!nn(ewc;KYXt`tuL!)KzHj4L!M8mr z&OzXg$)8uPS{4BfNQ~DLAb^AXQ9ZR9$6Nq`pbk6CkMqdN@+4J@(813Hz$Wo_2vqkm z1Us$C6x4~d2hXT!w=l-UsfXf$D~zN90v|J@vj$k6Io!aDboN)~&K$d=9o4p?r5*cb z1ZaBWA-j3Mk#^GPcgfL0BYv4Pac;>jy)-}3LE;|%D+`KM3qoZ3>lFWWfohdh_L8kh z=<~}5qEUk5`SO^l+de`|OswgHF9z|mKLzK?NN}PE&Cnn%v9r$0p0awup$;?r9$_29 z6fH`dSov`R=d7rHHL4FfAv0j>d@Nw^kErvi)2pIIJiy5UC=~UIX{cm67FFMDgp4}^ zz)Ev=t!>V*?J-3o=p4q-5G$6QcTs?R!ynj9U%md;CM5feNzgJr1FUg{6xsT$HT~#B z0$~cNNTr}Z9OR9UHCrp#?MFV-R;}f7B53_Jxv%5bu3)gJhGT3OTsHc21 zJ7iZE6<1c(IiwqNkhS-9j*TZ#V_<~7#I=12$CcvOn#8!+BSSAb@4c|zp*ht#@kU)x z#nIn!$7n>upP%J&cfJ>^KFIROmPds&hqOvjOG>G4RWcI5X=hZ90IT&h)Hn`HyamB0 zUbag{`c-fCtpwC%De1hL7={bW}m@h>GsCrO~RT@M46s|WjKP9 zmmd0~SM6mwFgZb>F?gHV`8suml4d9@Z4Y!J5weTr_YT343~H z;Xe|hll0X`Gthto))Q1y7E|k(>}k^l6~L(QWgEx$uWL(yog%%;wOSMnfzW}_0i)J1 znFln!nWvkVI@RA)R2zC+V7~frNFwrj7(g$e*L}l1<3U9H!v#CZ@tt~C%cpsr$C;T< zp|RIi#hLTllubgJ;xSOoueXi0l|EUTK(IWmY2KGRnF>Xf>-xqF(+9k~Vta$ggF~1| z(>I5vg>~n>+W}*M{fK*tyR_DDfBK{?(0@S#uG?UBGKEI2#KV8v0mL)9B91eHm0@8w z)%uI@j*`@FH;uR~7GcK$p(vblhgwPjiPhox#rzINHt(u2XP;rbn`!Hdy9i7EEL8Pf zDxrdiMW|ZB0*6X`7xbl6%ryK~G-= zNnJimv2x8n{H@b3R&Sa?au;+(?U;^JQ(YQbdN!|pv_TUF zpvHchpJ}vy@t-=AledB+s~p5Xaxk2Lv5j|o6(+jDt4STsJHK~F_Qkc5;o`QCm`jq+ zeKacX&LQWwm_8-mNi=2?fL848cYw&A*~Q1aE1AbgLH%*GbpU0=u19&Fhy@_m;>P?T z9=QMUK2gzpHjP>sjeQ@59kKF;?}n7hS$$q}UEk>eR-Clgm_lP#>>=;ZM~V+HjPc>jdMa ze%aqlYxU&co^%;&XQJ5dv(346Nz=(svGc&tvr6r*;j$sdwbkDC7z`Hdn-#(NP4KyG z3l5u4-T;xbhza;Q_g_plUTckTO1`$%D&O=(6)fJl$amQdY2|Q`@0dv(sDs6etsW5k zK6@nG+?mgBLv1Gs0qPq~wm^bQx?$g9h4(AsDKhU!Ie9Z)y@vQ$)Ag6zA*&Gvv?$oEHgxr8GpWR4m0T z|;d3C+zo+Jc+ZGU4Fhzz%CU@|p}t<;;I*%hR^5fH6v zQ*oMm`Wl`gcT#ID8iGHYHSFLYjv~-@(~p2~ABIzjo|!_o8&pa*@zlY#`)z_-nQ;t7 zLx@{1&ItOU2X%!&^mK08*NSr93X;Azl4)&lCqV*+HqT0?D1pKofw;ZDz4|kq)ylZh zAy_PK*u49{mRa2JMPaifD6&WIU7ZDEbdSj$l&Wol#5|K!H4Ox1{lD|VX9~O4qMQjL zi7M-Rvq2LMua`nM`4|PXhKM9QV{`q_Jn5HCBLe;gJ6AE}f&;?Uo!tDAr+K^OO=2ds zwJbljUB55Qi)L_fWcqVzK2rR3Oj{vHNT3G?a#HH@PC=TT-k7s3-2z>r#n+(>dPAW9zZ6y^^|ZyhyTT>)bteV=a4bE#pmv$cqy zhgC6{NH5+OOR=4H!knU;va4xR!|-j}wC~mV!rR9>8iah$*hr<-*{ ztsOH-(vb8topF>z7Gi3^fHb7t$auT1-tLd6nX!nDUiVLX6J{ZR?9%M7A=pgUthYPN z%CpAImbrCT3%%Y#gg*+Oi_=<>klK$J_t;54jIw;WAZG->jqRZ24sQ-A*n8UJrOj&W z+A?86?5KFLp9QsNS_F3Q*ZG0KJMJ$aP?x{`#aRuR2P9Ox3o6#rc+O&%9WiTrxP&#f z8}^0qU(72uY#@{ub?Zfnx=eJyr;_Z~W!gPZHk+gBt z8Zp@E+b2GVbEJD2LhZvK?{22B2&ngqIQkVj?2tCb;_n{wC7^SIiKCAzWzYp$lALqp zMsr(MJP(?;BaZX6(p;~1ZOA0x=py|g2;oR-nhJ3Tp}GDG?F zl&Io4Ltpk>agKHZvb|z?iTUH?uxTb^N&DG&fzzxZ#p@)yI;oTC(*?bT^agMV*KIkU z{FpCp`wq!S;D4xQM503+#3lW!XOfPu8W=b_eyFLkki}*|rsjmznc}Ey>t#1fKiakF2NjoSqsbu(oq$1bGM>7ky&%s3ZW-P9mY-$>fp8f z#4ECtiU`I}mV9*vVZMeq_(&z9WpTElGL)K^1(GT&(aargsFcpdvJaEHJ_N&cZ5&*) zH{4Me&r@Jhqat9=ys9F@0 zuKe9#SVApx>MvJ_(Am#%nNges0#|Yp_Q}^EX-bF~wst@=qKQgxC|Qq_{{93l1q=!> z`}iJes153Mr7E>a%@g4;IsSYCaVElO=3*QfX=*c3`KGZa2uSbI9QMCNRH|} z%<{!*mm3$;4s&`nXS|{pNEVFAX5P}Bne&|4WA`_SN-IM~Ca<|YV}31%Ut2XL$Pyz* zUlZP=b%84uZVmn{C(4fH$Zn&Sf071Ld+g8!`YY=FW}->}DeG=+r^g|8qedD+>MzW^KM6?dM-k5V8zWVT zNkS!RYN6i?5u+{iROGQhw9J6>A#M%dyGDj_PGY9+x^fcGaeLE^JFgDkN!(}wdUcHE zUQjmkM~)(X+on(n5LjfhFR)x);=f7<2dZ!d1LRJ6`$>4ub%|Kk_yP7#b01aX<==4m zv;n|^;-#$nADwM#!)a~Sm5u<4O%-_mbuzdPmNr@_cTEgBfoF(2K?=Fz(C|atZGkn5 zYp9Y`1N2Gfhs~gl8v;nqw+&CS3l>72*>r6{4DCv)Ei>=snGK8c>#hQG@sgzw<;-WD zwCbl?fup8(tAFE`PZAD?D|VxktzNCD7zx&X*Nyy`UbqSJ@|>M@TkZgS1})x{w5;P+ z&82TN@O`4b=N9X-JbE%g7cuL~gswnaAKJ~cfg2&^?6~F)xvBZO={?y)TdG6y`!|UwRy~0iKA{XBM~73Q?-6 zR3~@X-6KKqgnnL8Q};Lc&54$B8+Do$A$Iy?qt}Vc)y33xyU{biCr^TvlagV7-TL-HOF9_G>Dc^)LoZq^c%Assat6RobO znz?d|%tcqvS%YcFjR{~&NXlq}H$ZKJnBN&US~1Drs0X8_v~}-SXlB1apZaSORcXpa zc{=FUT0mqWtJkyCZWedZX`^|RjN%PJrL62aqdO@ws`az4V=oa~AX~B58BQa3LFfgw z{+P<%B$Fg~y1sp+#E5voE1uE&_)JW@zD40bmy*wD&oc|vK4}pSmU$Ph(f=X>Hw+XP zI~2mN<9yBW0m;0Myvv0v&iS=6{1J{i39E4JtH5FgpD7T|VVSnB$HTNZwd-O_x|z2h z_F?hc7P`ET(Z)pyAUnv^*44gS)P#K2@R&dC^of}34!A~%t-A@gYj5!mT;zs5uo;r_ zT;nwrVMnFQ<#H{ZBTl(rnBrpFe>UNO5eG^Xi9?4TFA&9}1g$x;Y==byS{AHAClF<) zcbLc>yqTJ%c>f1##z_YK@o`aPrsamF-Y_hUFW*5Tp{7+0b+qh7cIL;rC3a2%+Y=SC zPX->64$5(s80`doOn6XNC~|07XU8dhU>hbeA zE9z`76^+Bj@LkKVEU*o`<(>i%agKS)I@9P?LRZg;^e1mfsl};(Wrc{g@ke0Wa@gK% zwom)?FP=`nwgdu7Z_bYOl^H`B_cjR zZER)(q)%kDuMbFEis}l2#kr-f5tY#y%n@)cdm8XzWG0VC8~_;@m>h>v0LL8K8H7_7 zKnxE+Gp{i}GK@D4QNZ90UZKv(v4oY$8K^y=#T2bYKuRI9F1tIdFeJVG@fK^Usi~Lx zdj_olSOODEd%c}gQxgEjMixNHx#1t8%gr7)4?MR(NLDa zB%mXyrz)790H>m{KD@ItbN|~0L0wrExd$9r^5Qeu=un*9TxZfxO1cIxBv$xK$t6tsMUyDb(3nACM&m;V|g_K>@IRW8*-70AS0@sw3*MV_?IZk+l^$c=fi!;CLR37TkVsW?!&Pt*4eYM{ic@u zHb`?}2ZHI%txRD-Z2a|;spy@JV>QE)xb_B9#_&o#) zM0vySAXxWH1f8>@sw}6VQ2KqX`a&kQw6ZocG_V5uV`u`5!NrB;*~jP)<{y!ax;G4w zVThdf$&U<_SK8R@1Xc`irJLmgP~sYE-|H41gDOD(w)qd^1}0E(e2 zdWZt!pD+RmYA1Lvr@U)@M1suWf1vO9KgM@q>Vh6ZtMOSML1gv>-WY`TMczbBp@Q~I z<@*@CdglfnQ=wtouU#;z{`U|JwUHfUn`K2{ksqj@;U{6DDn3Y%p zGOU+CBBIyX5QO$~w*Jp|jDL;a`2ZA@TZ8@YB4861xs@>aW3QBd#!r49l;Mf>4aAp~ zlK{27YvU(1pvvGeJp|I?^S?U{Ue{KGn{@tDevf&70tu>le&c{uA3(T%DwqBE>ri}m z7k+hwVf=Fb{Jy>%|AT(7%*{YmS{VSlT|TKrR_4~{2Xr$5ox>Ocul@u5mVWBPO8n~h z`I$gNuD5&5H`Fl#n5PSj#>QvI+`op_y?v?I-1qKCemVIC;5Gk_^wv56Ae_Omglg+H zFrUD+$XLNv-=WfGR0fkA7jf5)94*F4x%XypuEvDXCiIGf9MQv>zs?d-wd`UZeK{$q<6C_qO7q$B|i@fBcWzZDHkfkP9^Bx*Itnp@WfA0FVPsiCoHGW zy(8vvc~DKQZ@;1pvOI=<5GPBNHaHamEL0oE*Ix$}vSxfjLD|CZOz6P3J#H?BwV4kJ z_N!Ka1`Q}oNm5dL2Jk%r-<=`-m@SmhdvUx}yQ`~31%4B59q;D%$)$}V{9&yBBPlJ% zWce-{A$sQpY(TF>VMMXD=<9$d$jDxg;OVn9>uj5u{b#m`EcTbpoH84?+EP423(#ms zhVi=uFo=TUS!q7tNT~Rb+|5M0(~^#RUzuMNZM`m=z^(Z@n#OU|!G{K7$_pJ4$orT~ zUP7asS{?3-l6BJt53EaeFE3~Sli za0AiTV{4jp1B?$2zacO&Mf0k1sdEE&J3Nv*kt>MrNm=mhJR#(jYHSK6v-BcU0hhX>jU7F_{>-}uOo-l7F0H| zBC~@|BZ3sC`cWd`DtuBB&PNtb$ik&V2)Pk;#54Fg8(Sqyio)Ypby_@@p#%rMi34Qa z5G%uUN6!bOul-iNHBAZL2G@1IaK3J2bdNq*?$8oH zDgKoO;Shf$I;W1%Jd3J`GJ_Do1Vq*R`94fp+PZ;7|C#r-zP+D<@DCeWpNDkSq%X>H z>+c}YkMi;Uc{gYkI{-&V6dgk56|-S;@>uMt%k*}*IPEE31}xE-0*BN*d^>Mm3&g?5 z><`N705mC%<}%I)+6*5FNeU%cBS3@VW^_~Dn66U~Yi6|RT12TopTAQl#w+Tl;ATm? zb!W=3#06?vTnecw-Ae)ix4uT$uT_iIm*9L;Q2ECXwg+Mk@!1w=fkJ1Vhn(`bXu62i`VETA%M;mCV+PTxm1BCFD+|I`hz2>Eg zzBqA7>`Fnt0d73VU_1F@`Mp^l^5S3~0q#a8;%D|f$Vhd8@iNp20^N_rg*H6@$ z9V6dP1<$P8WKKnjTxjwzHlfw$$>LC|zqdENh4?L_*- zxw0jJ5z!><@E79sS`e=`LYY-X4oAuJ0U4XNqhLjfP?knxy2vY zy|8usC^$kt!sb8^stntRF~Gwm%zTzY<)dS*l5JW{HC{5J&X^buFV__5kE|H zViv2S0f`&WF|jzBaBfo?)B8VB-NmtX|1!AcH7NA1Fj}KgkLaVbzz#JGmXjDpa8HL< zse5#ZL>A)csKnC947yDrCRs)Gc{*hLy8QJEceO9n@5ODg@?&yytuZ;zU`up62~%uu zLFM=|&<1~pmu_6;Q3>Gk#Io#pi3}1Mnfsbw1*X%t?;(3|ZVXl$iLThU$cgC_85zY^ zFE1JD?`taQz~_1U%UenN;g_zqSuVF=@E2d`S*3>(q#yJfhbyd-RV#a}V~KE%LB>sg z^Y|%mKGRTAR(l42q)sZ*dMljS(^=H+tXQeJBaC(JRl}yKhJPvbr3j??_}gBj&>vb{ z5_K}C4a!HXEBi>~Ir)fv6RMx`q^8yHlKGC5Qo&uI9CxJ>4s#-A|N28WBQ0Rzr|$8U zoXdH%fLKBF>@$2=OwTK%xW$0()!Koy10z>xt3yfbbj_G(aO0_Yfk#}TBx$di2j``X zl&;}%^x+i@$p&}BUhWcxT;j@Vlaanzm-E4iOq&(7y!_|2#kF>rM9T;eKIz%i&y2+JaN_Xn9@=Xf&Z4n zwL))myucBO!p0Og8A8V66O)Pek{p-=v32szOh3}Q{?v^qWD;bvrw6&C>(3^ho^H^% z32~{#oCE@sj-X^*EvSFLi&TETAf)fEYYBvy3%%xrl6zDxmBobIta9+Yib#uilri{r z>fIEB(V}QBxY8ibl8Jc)KgW)5?72AEWM={60n!RZS5Vw8_#3?X#F# zq3YSRnZv{+{+d{Y#9&|KyGt%lEm@hlcIMql7m5@^&axE;9}Vn1zsx+rrFNF>Q6DUV zYo`%V=X_G-(%)v;@I`8UwXsSeWVzH=lIdqcX_VF8ZunAfs!1MB62EA71vUST_n7rx zc8({yBdvz;Qu{}>2~tlydL8*HnxwtQuDkn*h2EI8NQWm3!JhR7@bU z>kX0LT<3ng8HXul4}FMYZQbuJ@DHYeL=+X&tzv2BBMVv1TOBElCXH$47pIVre{cYT zbik``9ax&~N9kjZ=fnG{bTxL&D?BzpY3DhsT|CjIjaBoZql$5prwOX<)tuY;m=>CI zOjfH{vv=X7&c#I-mn}Spn3>dl1jaDr#^Pa8qKfp0dhm~L)5^PII@kyCgC4%U>-KAW zKc!xAJ<5aV@7baiX)O5d1(+DiMQl3LF?vm+CVKab1!Ypk(EWTt{neOc_!eRQ<@9Gz z;gvh8YrUqNCXFkpZ#Jhs3DWRb2 z@4*r~y*myTayjF6Q`5{wntSG%bmp>R{$all5<_w~uWNC4LREDQSK+h4XqsN47Sb$Y z9!;#PkCj$?hE5AJb6JBIF8LqgtV>30=_rvI)^@b#9!y#tS~s&{Hj zA;4_bM?F0_n0)!NZ@5D1Nm>&b4m4fmwd?bs=5od^h!*@O2|?m!FQk&Wjn~gme68*x z5&!tK3D<$}hG$Rg3p$kLro07cibXhq6K(a0iMg#iP)$$M>yi{Cuq~k03n!5Sn`#b0 z2TRFo$p$C-jhE_`JzK`LrFqq6j<@~@CYM#DM>sPS9M^+3=j1TrgUVAeF6Tlc@9+7b zA0F*E)b|gIrpxKWv$9P&|vZOU(=_FN?Oa0saf}W4J~RKYh#&F zSv9W9N8}rxDByFhMdK>zZJD=Co^`k5u--I+t!V9ba*>VGJNS{4br025DF0&tP`Rz@ zF#NtIlVD>Y@S~Z5I66n}fC7AobKdMc^t^HIqi}q8@G|%68$~#ir+Ca}jT$ak;3>F= z-YL+J9vdOL8-Cvf;3kp@>djo3yItX|`Z0DlEx(&FIKenapCg)m3&@ZStiJ6TWo(Yir&yhvo1QelHW;oqtr@~ zde)p*g)}G6gwv%;tBAuN;-DGP8eC?zpkrDQLYphjEHk?W6##EJ_W8bGNYus=rUiB( zH)A!c$dRfJMi8PU?9arosozs5HFXu!q3E@0VX`S+c%v9DIFuRHq9u3=dtpTfL;t#E z7Lcf@P0NX=XJ!AU;?|5MfBIv>F)?eBTN(W%&fsw4)8o0E-F=%!+;oMNSbY(9syP%H{VUt5Vqgzy41K&2E>MIGa*Mj{bUTllKI5#6wWJ`yX zL8j{oznf@FD3GA4g}z1JDj{%p^2cO5$tctW>fq0KtpH500|HqkQzPd;*f4s6c32>{ ztx$+>Rt2Ypu&chKHnLYLZp?%7JXJ&rB^=L=pDZ{bpiQhk9Oe_fL?0Su>umbgdL!oO zpO{H+R~cFLK?Tdds)QNlr*k(f zv{n zgO>Kno?>&J+DJl*qraiO&Yu%u7Z0b{EC<}Jb?`WirMg-8d*GUKQ&rW*4L@8R?h%1DPoiJXxIe`%$Z3erYXRdrlT+aaJ z;;g@&taa9XealNCU7V1z2y5aNNmPS-#J;msJrPQk_Km<8g}&c$*>s$yKDwOXt87S{ z1@&*^R2Oy%|6kn(-5rsZp8!n!#s^c$$Q5HRTNmT0?ZovML(bwiU$e;Zs(ST*{a6sY z(c7RsT~k$2+(1xj70|2Lq=QUvpN+=rW-EB0)EBhHKb?R799!IzGu-?k#3{tY>D&Zz z>d2?}O6HA-rD=bD_!<8PE;o$@#c3IX8q|@5BqxOPE{isF!c7kBe}~bi)$B?S4_M+f zJt{$IGpq;D1qh^?L1y6+I`@33g3=V2RfnN_$&mJrS~oLBEZDQ5T|N4t-*_mD3?2<&p;)- zda(00Ptq_Ax8)nj1z5?QsF&Q2O?d)5m(a8nxG+VcnAPudcmcORaB|}b+D%of_h)}< z*F_mN1RftP+O$B7J{r@zUi`%4hd#MF-E?-fRHBq49P1gj@AyJLu%P7RM4ivgGY${F zL|b|xoDdpapPJEzR4NXg zy?hUVx`at~^7AM{G|$iK_&>b%%7( za3uxO?0SXIfSMPlaf=;9t5dQ|^i}fK{jGMhXA8uRZ*7ZNRe?b)ZQ_2Qe3!%Ys|d7# z!_j}&My_oc2w9z`)f%#ap`na=BYgZbIcpdhlv@#13upLHts;2yxb=#8_kI@_|Hef# zQePKx2IWImx;Fb#gzH?9*@0!T>U}9&<=Vc)*;&gVr^?L(T~P@r4`M5Cv1xy86XNOy zVHU^L1(z+`h?5f5z;INWx1$}+j@!Ehm#Lhhj24K>_N(&J2Tme zUcA1U7C+v`yt0zNAF0TB`IO`KQ58)>&3Ohyo^Uq|TcvDJC;O#t-L`tNZ9;_JorJMJ zTo^0Ohdp^$x}?SL5%n>%#tpivN^H(UuqCB=Gkxia1fo1(te5(Uin}JVofRf)s}@Y) zVo1^>s3epjr}z(4cC+=Nor~mtGj60)ngvGQe|Kiw_tr`RUbK08w=#w?cESiPV0my} zD&^4S29!G8uW%vzV{e&{xIXKjgLFj5LY(qCkdJ^yMcy5dwIHY1G#t(Kay23?tA%78 zk_;!SnZv&#?bQ5LVm}+FF=CkQ7hX8A#r_33XXPmT9qvXOxfinXGDMM+&n?aE?V@8fp44yMu z3iyrkH~k3fUx3hNqXr{>-)+pY$=t{N4@Gj%dTu} zOkjR!hwt>fIFI>>h5_xlJ1IeMrAS=8+h0Do)NwZEy36%AYO#HibVD(%50{sPtYkg{<8Vy5)8-pD1O+- zJkX<5sdBY^3`xhwA(duBZ*Z<-z?8|9iBNEY4)nI z1Kh(KU9D1m3_UqRt7cywP%46+zoOaE(W-NkCRJhpEN7S_hdBfov9A5}{i|#u69(o7 z#2(`0Y6}*Fiw({FQK;d?eJNdHX}uRO0EPeR3VI{nh&=1&+3D%6uji~poe3AYzcU^h zI=AE2pk8QRu&Eij`V;45`g5#@5iJW_Ojq6#RD6~@yq;K}qI87JTXOB6T!Y6-(2~GX zp`C@8io97=s_9-_pNgGpPGBGf6rp9#CP*DF<9vtagiTEgNQB`m)qu6m5Iovl<&Gb^ z-mf0K5|*|gxHTFROgiqtTLZfWbsu*Gp!&B0Iy-z6YXqZ3U{vofTb!zid2lU9$!--M z+d3QvxR=r))*W=0IPe~I4VF|_Af}K7^um(z@<4e=c2*Z#^T&O|8054HT7_vPrIapn zN0u6AFM;%PM*O0G6p)|T;@)+5u8!~~HZ{L5`v`U@_N+=*mb~9YjRJeW%U9XQm;D}xhbhg8&FK!gk(uT&=hULJ$hsposD zw-N_d;p;3^@oggLnpwm$wIXSS7TDubRFYa8=Z0@Sm zqD0>a;bG}8fsHeU(Q4dt*7YcPlb$st@4^H4LmwJGI^8wQv#}qL2ZFl!6thJ0%`Vt= zzX(>&F)%#i$zFdgKPujZoNW?mL<8$@t=3ivow!Xfnw;p&jNDu4hD<+!WHXmQYyG98GaXp9x zHpiBN9^#qw+Be0KpAOLDH@VFbwj!>;BPk(>XJ^VK z8a(KH_IG!sXOqDR#ash^$l&MEpK+iduyk2nYvNASzf7Fy2Ptn_CzC{)=DN2srjjl6 zcXulq6-?vV7l)1T6shZZy_}_c-VMC#itB|Q=T;^kaPncmC*Veel&u?+E6B2Y<=pbO zZ$>(WlEV~NN^wrI!A+q0Y6jGD3G}43acZD@J9H#~Fe!*i(r$$f+B^#IelUhxKsQkc z8k`u5PB7|=;O9D3hfe>Y5Vb{xp#ezwBc$jbz6OD5RsB)>p~!R7HMd4(JGD`u>5&{C z!;}N5fG8CWQez)nK7(J`pXvFLDHX$NA7CX zQcQk(_W|drkPru}2Sno+s~6!eV7tcpRPG4odSulc-qsOL<01a>zz&KhdJ{^L0%e~7 z1PRk)p)Y>yFFtPWWxu%?aT@e;-igN!Ji{ZDRtiD-f?fqotTO*T&DyHhZ&$z{C$puQ z-+3S8y%UDrk^5NPAuTNY=y$LmziqT(VhrZ$T#+M0sz8q_eXGGUY(;?-6C}Crvo!K` zGPqZn^pvw^BxX=_{$W^ zV!PJ;2#liEhUhU~ijLn7C7Z5&NY0Bgkkz!M@55-7F^3tza1_F|?oB=2G>wf+DnRf) zvjN%Q%SX=`-rk}|bO>sEucxnl&#Qc+Zs_U@ z9+2nCc-W5eSRXISiHUb|DJ&8oDC<7Sx$Xzk3GS!DK0iMImH^;kg>N>Wp=Dxz_6D-J z_*klMkyJ|Tl#hf(RX(3==%2{;*F>_qqOVJ8ZzDt3hjtttUM-#e!Fz4H&aZCUqZ2S| zDPS}WTig3u7hTtN?MFSrui5BQaM?u?xkJ3iw=&+=aMK&CRZH?x;!^~JrCG*xSc?tZ zxeeBg)8KJxw3v)c$(4`c&gw*?`y#*3}aGy6_gW?bB>l&;tE!y(Eu}!caze%)y1>eNCJ2#H7`QD zk)w^VigPH&OuKqvq?N?}^|S@@(5|6C`$CEb^ZYJ7N~`DI;5lMsgJDza&PiYuz51uz zwyiQC)R3y9aHBha2H6b8pt19KJ-w>nU^k||2L^X*KQ$7(>$b;aW~*K)4QTduch8D^ zt@x9s7KsS!@W$_rTz(~}N=B9Z!Ut~~(vQ#L)k|IRTCxGkaj*-HWo~jvfaa6N+m^A4 zFZt2ZqYW}~`yCnc(>a^xN#+YPtBZ+cl2_!2z{dRohO3O9riYXDHVBhWc)^{*=Dk9H zkc&bTp#A%LRz9sQk-?cvd!i+UQD!(?#8Vn@QaZl|$~S2Kz?_Eemg`Oj0^ zYD0U^eM(=C)pb5vKvHRgaRE&vRY2plZ+;H}$^F&b*LSCVv%Y|VTf$4fi9wTpw65hp zm9bkkj{eF(;%${=IM{+T;;aMU)*WkX%2z|j0;Fxa6-=T8@Nz1=M6J<;MZVEE4~0AM z*C}bx9b4c7JA~KvUf6)jn0*lFUVZrcp&O(6ohE0SAg3vII=u%(0VF_HSo^g}zl!CDT8@l%?P|9hI4a?7G!9kdiEto`Vc8(4Z7QEA-Kf?P4Ih zEElv4II7lpf7Qf2s(6<5e*dWkV>pm=%O4!<=M54%Vw2>xUsaZ-!9^#v;SfeZ2zK88 zrQ|N>294JcA^)QBKnF`k`kmhz*)@wKe))Lx4)^GdxiVjo3yX5rX=D6WNcTQBax3F> zVXby-=z8l%f0nFrCN+NWYUb*Iz=V)GNvV01hjOFP0hL>w9m+`g7o;sr&gDl@j_PuJ z!!%pw(2m9`=J-u3`YgZxX~vQ4I9T|)XBJ;Ee>C;k!j-nY4ICpG%&w>(LjowCFX3A> z1i^0!5!Quqotv~zi~a6aOQs|f1K1i2VP`0J+dk48b=TCxdUXJu5$qXIO<~~7eUf@- zcEWunAEFPG<#LQ-qj1zhL_t9-AFYd!qT~_gwWZPL$$gCA?pp7v9jnG|&c1mq8>lq( zh74<20!4&AyZT-OV~@xdfm6P-%|}*%;hmdz6uyMvaic!xn~aT~+-<$l%4XBk?9kPA zSs(e;a-{t#@{1|_6%o=hr_m^9ZL4=9iEFD@ni@6y8%@MF`4g>zHz%X4!VZYGBYK2g z8yL1s=I{aP5zs?G+{xRbV!c!Zj-clZT2nSV&yRsfUz886m!JvRml%e{3rF-g7~NI? zq2Mri$4jbB&=*gObeoGq9z1jBM`_t%i47Y=g-?>;07F#C_u=cS02>@GUL8MAF4a2y z8-c4Htbh;KnL;XNPwrxD>jkE|=Txska8zG4wcxW~@%;NHMJ}PjN~!7_&q(aAsdD1Q z=@z=SfNoeVJnWl&5qN*bxV!h-YHlgJDI)ycDUhaT1~1iM^qfx0fJDQ^Mq)9Q1;zG& zrv0-QeXHBE7;M&dSyNtZM2~t5-2JGaE<>Arz;}jkk0e#M%%`MiIDK%BO(q%c($l%o zDD^y&Ww;5Uzo%{m$d0iIsIM%@%2de2^t5nauW@oBdLKXOrEnYEbfK66b2A?4&@uu> zjfagGwj{)ZQe31)EAqZh_V+ZXkHvFGCNNzv*cx&Z2ckx=e!>P+q&lIO&a^u+fP#-C z=t~QKCpgM`<!C<4VNOMi5aRUO!>9f?ba@| z4;D}%6vL2)GN%;twdr&!o-+AZy$gKgVytY|BRN+tEiz;bDeGBqX(_PMDH1tU1$=w! znY&It@=@z6#w1ts`ABLL(QyF13VSR5W5~MqF0beOW~^LvehczNryJrVYJ?a8b`urs zZ48p-vc0c&;vRLEapS$!Y&)$b;RgH_p~hqc6Sdp94I%a}209IuR`YT?KJE~&$zPn% z5z=l>%m*b6%f(A*vllnIbRgqF8QhI-nQlLcvG)i!C03i>QvRZ9M4zMvKgNuJox&tU z?NC4%-Xl2U{5wbg=P9dooXRq#cof-Fg)WP=sB_Wv`rE5)na0rJ}dAQY5CrUr6RKjDcPU|U@fDpybqR_0u z$mMV$v%~R>qh*W=J%ez?qdJI@g{_|y(RyUm0a)?AQ`jGQ9(AN0z;7DetjVSqJ@o)D zobSw@x(zqjwLwcyt$s#hV3sSQ9%ZANcqtp1YdtTH%TmzsS4>2Km~^{hrj~8;-Mn5L zn+Q7$*_%3h>=a@U_@s8R;1No&A6S`OIc`pJQl2*Kzq>pFQMxqGjf0?Q7PC)?G9WZw~s)o&9o+Y>uneP8uT^+OZfj&qq3@4frm;(Q0HEb%Rl;Va^q zyIyCY*v*IPqe{iQt#2D5UnZ+6;gjZO7w$N%98Et{Ox~W5ILE^fcT`9^L<^xObj!i7 zpC6R{)YusO4zEw@2BE#yfZsl%T1Kp5WJdHEWob`n7m@z^>Q9sC1?`UzfzGI%p7U-8 z-1Fw|=B28ZV?5p*eswMv3E<^&IK))9VTr@nYj}8$((_ zGd2@eQqM6CvTrc-{OA(hew(LFBKxvai>U_xrW4`$!A%4Y!V!D8bL#%QX;b`TL{y?c z75CV+e3v?T7Q&f0(w%)VNp5(nCk}*NcKHLZ%8$GApJm27P(Jieusl6x;l*fQP>U{C z(XDj*QCSXQEf1DVTKu9aI118OIC4YXp3Bp3I;M`Flgdyj+8vXQ;s=G!zj7N0j+)PS z%4BaC6WN%zZX*er6_k&tt(B&Mm59>7k_127Rkplr6&4OcuhpqMV^?OL2^os5*Kq(* zln+l2Ebs2FljBFI$O;765sE{N;A+-qgQX?x-*1MOWJOA%TEceuF(D&Nr~i1^W{<_I zYDnQkVX4)UbhtZpwX!|bdZ&8&vM`ywYq-0j+CNhk@81QsJ7w==B@#=WX4->TT{@nL zkO7#n5~_R|jJht=Zu@58xNvk{k?-C<4^1F^z|XQIxnqYn~^jX=n? z-BSmL++~2CbeK=8uE=)vq5N>QceYnJct;x1?hJ?Af7QTMXE2W|fI%v;7dm{Teni%e zbC#kfaYJrR$8qEl{VV^+Y<8A*d|Cs1*41p}4?>2Vcye3tGg+j%*iD+-swhwW&_|)0 zDfD)My9X0!4Q0ug(O+=xOamyKUMp|K#b1AFVqbFNPSN%1?Rt(9u=X}yd(nOKBt>y} z;+FZadZwDhP;tt+4Z$B*f!N8*h-SY>Of^3DGUL`euwODv;=JiDKL>DdjDo$A zdFuQ*`gzm^gWO1!z-tq3qx=Tm3exUc9vMhZiiRz7<8h6{c&2q6%IV7GanP)>HZhA5 z_{pznBCNJ_tlqj?NPL$&fkCB%XZqv;jPQ95R|Jsd_86aRT_=I*+ly3%G%rb+3G(d_ zLnLA7796#ok5z1y5tkE#`4Ii&InIaDmu*8++z8%gBTlfd?ddhlw%OQ*?*>UG6<3g& z&xjdcjPV@qbBs~mTN5gW-|DBjG}u6Y6sBaHW_pQcLm+wiC4kiY4VzC+BDpKE@_VgX zU1k@DE(21f<1oKj#Z(=MH?F-_@TE-$zBe2=*mYWv5kWMz%$Yb~&eUgEWQm0cQo%CN zhqQ!2yBFuG~2#~F>0g%a!?&V&b!IHi~f!IECP4_<-FqI z!@|N*mu>~{gS7x>zb~c}hQbk}rDm*=1c+Ei#y~F@=Fo(bD}nNm-qZJ2=(6OnjdCdW z<&2fz<#!Tck~vUJz9(313dsky>>zI(LO%B=&oi0u&d@8L^ifZO$I}KLoLLQgF)n(@ z9d~h_CYtbtD#1BQcw277KjH2Z##Qiq0vkCW%`x`cpIe2W(O;GNlp$1_`XDpQ*!!GV zu^r<&e4DNF*oPXGxy2wSsKKb{_r!wwJxX5-Yv54j-Zw(9%n*1(rmXWaxH+p^;oJxn z99}D4@!fZA*#WBIjAn+`zMLw^^eY$2vnd~;tBU~o{odNKZfw3!AF}sxooIJ$EHogj zLeVODZ(8AjzTq+4r)2WHNID%IcEMpCCC4%)Y}yJz`%a2saUYr<@-<)NF|GLvzSd!M zZ&LSu3(?DvGI8>ysAx@ET@X`qGCfU~oL)ESr#N(|_Vuo30MT&(LHWxIeS!rQTn z0x>yhbE5jwEMq(62ZA;|f|$bC4|r#hVVWbe@X-Q9(KG}o%T5H7E!!5=Q7(iNHqz0b3tq~l zZ(nhVW}m=kYB0fS1w<{}d-~JyN%#8$_S}oAk~GWROXU(c(~SofGTl3DpSBHFs%xlM z5pGQgxUe_gPpjqX7>Yk=b7k><+hdrLc*6~&HvTP^aetP$krJ#rDsk34nw5N{;50rU%Ktk6;s zZShBhw_5MZTV%<*>Ohp6!T0{f`ItK;)oyzT+rt}tr7{U=u|R~^i7NCn@!iK<`vzMX zqkeH`|`m_wUU2RkFSc}^3xBWq5P0SU~T!)Wx+=k-$<8`{HMTT0UB32WaSJWeZvMh_8Dz_TZy&sb0 z&hY8oY*rgy4e9jH1)`dUhYy&rFx&7v5#?3jFYIozleY!E?`GG2tnJP9_V<`< zPS6o#-}`>x(H@b1xMi9sDkQoH7R8GB`c*IRyfXgR@Mc@_&w*q~)yBp5uOAt4e~>rr zV>Z*t>m+l!m&#*sHU{w+hP!M?at;Ybn#xVAM1Bbx_l>yFS@6`gB%t;%UKfk3`u4!1 zwQ{?hIO(Gz_ze~_YTx)BWv7|fXSTYtvQ57=SM~hRV)rNNE1rdoK`!{MrN#KRQ|P`N z1m--rQV7`EzNSoVs;i+N3BSy8uTd207FeDkSlaw%%4}zEr(r~K1QWb3Ux(5X@uVjy zadcB~)QA-Jvi25d9}+5$E`ITF78zDSsvg(sJ?8|$xU^VsKq_d)Y7DP^b19`&hAYe>&eQBi1Cdm8{v@oH8a?X3N-LtKf2#|DjJ$u3Z`K-*U*$PzUZXSi+lRe z^G#85GB2y*OUtLgc{%sR7$w6{#={8{(s>M&yQ|?gv+0#QiVTBp81J%7$-PhX|iIA`yh$oxoVwhTu-B zY4CEQa{4l%FNM@@h|Ek?1VumW%twAZsimO|+7D@ywc}pB2w7=WprI8EeX$!T8d>;- zMR{Kx$|x$J*l+9PZ8j8{jFTx-abEYTP{7{37r+c1>-3GH1e0*d8e-{n$u89W4CqS; zoFtl`6ez@!GEa|73}z0TyF4Vt=t*IlUbbG`Mfyrb8(y)@Kf}0^Ud{X^2ut}uEJW_) zYQ^=dF-IGrhT>WV<4vM2F|#2w8i%&Gb!!AGQ8 zz)?2=v0?Vf@GE5C85Gh|+UuBL^?Pt3vmt!Non}>x;W=$Ijl;aSQ>e-x>U}R-xB3)>CzXczVuXLicNA1hE1kAyE0t#=?ws#XvfL+ZF z_-YlOa!^i?1X9831}WGjW6<>M9I+hZ64+Ai%hM~H8pnQhl>3B#r8ZwvhxLx#Oex6! zSaJ!@=fAjhiD)qM*(+;7 z3wn&nE>~7e$q)H4X}hSS6tKBxGWT}h~-VbB)%#UQ(!Q| zGV(+Vo2tB$r_}q_2l$D}S>l!Cl*^Vw76K`%8m?-Ccha>z7?R8c8LW<$PL?#UKm;&h zYMt1x`R}K6pUAU&q+$|<=ZlPxo|wV)wF=I)J`f|lJ|=Acgrzi+bJ+ceAG9GeW{~iG z20KqR+zLloYu)%ptF`c}E@3Lq2MzQrtAHkhL}P|+ncLRVa$`+|%uShzXE*)|_CkrJ zjs#2zJ3<}m2b}~15xlbH<6Df$a-2n_2!$I|atQ6k$fk|38R#GS7^)e$&^~xFz~WCo zQ<+SJzc!V_wT@iE{or|Vu3t_asEZymdgO8sG|&061j8SJUlI5WOF^yqqkXhQ<8ZJm zClD9oE=SWrSo&zk-dd>`4DB!=*`nxPjWvxjDB&fj{VuPG#M=7C0tojEyGod~X#*|j z?|%3N8JY9miqAQeYft}@mHbMz!X3z6X$#gjztmG z$B7G(FZ>-~kp@QFEQ1579#O$A3xDbw;J7SA6B09=FV{fTLUc`|e{^LVixeh&khlhX@FQMzDmXEDgfFTk{=siebTwqSh z;GLcXO?ZR-`yu}&iph^cMn|=B*$}a-8>cv?qE%W6-G)u$ZamUtK-o4rvZ9*P;jj4+xG4qC;ST#B%*8HY1z^zwMA%Kopk! z3J$&^rLb(oFBQH;>w?kJz=DC_Wti>HcHbNM?c@6Mybj5?+{wEH$`QkeYQ7aW_1rH~k*{wjE`+qY+Pax;sZW zy-S`pm<_IeIr-(9zIQ$&u2$2<8ZBE;D00;n#ZQHhO+cs`&+fEwWw(Z7f(&WZA8{67_*|+_R znR8}FaG$!adq(xa*!%3c|A)ZqwWu+ZH#1nl6&%hd<-J4iJopfG>N5h5#|mSsIF1S0_yj^?_ZP@ z-2klp%IW>a4rQZwxmjMPwX#ZhWeU=zlVLkwCq`fmB~s->qoQ+vR@1tZ81nEEBAz_@ zi2M$IlJ3LlQ6-SUBv{$v1^cc-IH_wL=w43$O>6SNvZOeDdG|8RW09n1#hIQyP5(ld z>9F~rfa7`hHVSzp+CO98hvK<3N!9T#$god5M+zMEG0fFzqvY!Y5pCV*6_0*RVvmt= zG~*+wLIq7xt^*L4k*nV&B?c8*-1eIK)#XG4OrUg?UgYir_o(M&GRoGp=BJ473 z(;cU)lu!YZ7B6%w_Pua)>V(UYuW`XF+JeVIr=(%G@o$}FK~665Y$PwY>+;T)1P%y@ zATdR6PNCalw^)f;k3w6Wy6!evTj+q7se!RJqyp51X1eJy--ux83(Ux0IyTclT>nM3 zi@W?vV*%C19bGsJm)&ky1+sbpCz!Zb7x|*8u`>UnWo7@AFulgN6T~n$$rvIy$=4&( zqauJusrYLF_+v=59jm7H^}=wf+gKwxrnUYnL02!kS8kIE(jIeeZj?KD;9X1(o89^A z)hUoG^1VzC%i}t$_}&-*x9i4;%t_YpKIAu9;m2PdMZ+Q&v+ShnghWKgc{B&K9K1Id z|3+rj@hY;{^5kfhL(@dUhV5sX8jF7L+bulreATzua3m44?vvf`34wk;i^dQ`x*rU! z#$=?i?`ZSB?9X^vc(dzNHWCIM{fgg;zaWpL)F?{AeGm65ByH7X0vRBq%qSqs8M;d5 z=Kj824N3P7dH#!K(R{Ns69MUZV0;f-(%TM@oH0{8Zs?$M2QKV81h;UVCbAe5od)nUKqB7B` z4zBw)m)qZ(?nX^-zEta^YFqJLnFtb_eN6f7Y>fvp2I%N@Ir%XtHdNoZK4bZDZ}GYB zwyFK8$TZ9m$E;h}@Nex!9vT;IwaVZ(*vFCL^wjuxBH7IKrWsLf657d@23&t+ikpS!3SS@ z!CmSk^FVQrkf&d0!W@jxwl_EG%I5P);&k8^ipA5V{iA{GdfdaY_rt1RlKzS%V@tUq zBe{h8i6`|{PBo0t+rgLlG?HXv@Kav&T{rf4TpKj)j9Zc9&ftx(J5&*D>UE}mwSA^a z6EM^D*tKh~5pZ|sJWd2ef&L3laFLh=R8dVFv!ps1aozSqt=fD>AXWmBaWQ^qXwunNoAR4T65U~kc(i_&0<%F35r|He|66Tz_hH4w!q7yG2Gflv*< zzNXQSsecR7wXmKS8W8L?f0E$tebjO?wq)IfFZtEq6ZE!6SZ znk7#eoQ#n?9_JK1)ZY>?$1_0=x)SW@5GPPM=xkC0{xp!9Bn4) z90JnHI!`phy1B{1>+r&|<&cVvdr#V;f(-9gh3SDFn)2Blp(hN!2JM*%1Y=^7R zMW)jB_L0O!0~k0WXgrQ@je z0q8L9vE@}EZOQp=mhdhq&5Cdpq3d6x>hFd)jbb3xU5t*!p;vtO;^1Jj$0*#hJOz`N z%Srt#eD-Heo(XPt}6n8$K zRDMo7WVbSXXrDQXe6u{xB zo%4OJn6oY3MRt?oy%XIXvMzcy9{jQA4+i`k#C-fW2~SM8lbn}HI6sP6kc~8!D@0&)BS&>ZUFGdt5C3T!MA= z^25Jj@H1T>OgO9PePGO|EXNS?h`DS?>fb5QW=>ql;$bqrw2@g*ERf%{# zcI~tf$CqalDum-7{H=D4=Fwz`d$N_j&Wq8B9*WS|svy6SbFvww*~Rj@%#k$ENK>vg z@c^*^B2B7YzavIytZEWe74X7GBh004h7j-*G2UD_>5Y-1OQ`@pIms0W=99L4=w+=c zG4D+s>i35j069?3*1_mUDhj*$wfqi ztb`1z7W~>C;4^eH7Z1~9#0EUd^GzE4l*H5sgMLqV`T8_sDyY^N$E8y7$sdnkYY2;E z6Ed>!?afpp0Z$`s*w>Xej?@2bPfnyOAl#f{NyxZR@FqI=a{_9UxOElqp{oBon6tqC zy2TV-2C6qkRZ0f{OPE8i?!w2<*qAlqs{4Ss@y?-195yjw`&*A2IZ{}t?R$?V zmIwoOIynNB)q-5J&43bsrU-~5f>nLdr|?f#l1#>9E_Mj{azlD^oen9j?M5>W_8c(o z88>72S@sQJ+0%`GLRz{~f>ih}+TQ57OneKP%UVI7lehXbsS1r11Q+@MPB_hG#x3UO z_{5Fo+22jg4!CBkAPTT>aQU2;#?xjhTVLbm=Du=j+>8qqAEv#PeBI1~4b#SjdC2s{ z(1yzLFtkgmBsnf>JAmWtQ{jbNig$6TVTg`wka2m&o}9PlW4dq*8JbU@eVAtpt!cbk z_oad^^8IMOD{lche^b7_qL#ry0Nf|@l6Ak>OW`u5%2vANyBK}m-v42cXGV`CUS}G`ElDaaTvJV>|K z`;|x`Op62VcphBAr{(Ahq4{_~md~1~nJ!LduUcETdV|pJ+8GWN1)j7Zw*r2?^NDUR z?_@=uXlcnHTX6ottTaszge&NcxQlQ1fEI8e+zHz$6{~~v!mLNk^!b1|w~PXR<2iIl z(}WE=QsjDB1Yb?&bjH-ped{q>MD^H0N4Cz!fMXD0+ouq}Zb$<&mwJn!NBpI^pWI#-xZ-BugQHXFgQd$#wlP~Jk?2!Q9T}N3=}hx9Sq zn;dYvrOL)bn-<1nItjuR#E_kcC3lPGSXxGm!*g?5QcJ*2oo?%|hm16}AG^HyvSuF* zypc7XAt7Ed1m&Sts5gX>?$%=eO?F)1{S~(fj>9rs&gB$^wZ*RB(@lml1G{e3TnLLPl>UrmL1fm2mw6u>W7bR|x(E=1$ z;szIG^Afr0SnZJe4Y7+D*=i!k7mO%b^HcdZ-_jbdgHB<^P>rGS zR#nxck)-Puk>$EDh0gH&+`&^I0*|Cw8c&4$Atf2HRP6KlxYNv;9KnGKdJz`fgH9ej zO%xrW?;AvXpofIzOYZykTb#X(oW5)`CEwNvaa}pq&=pX6ssCC}bcqP^Q?1xhm0%5$ z0>MHe59^{og7o5PTFEB1=K_DXqQhqp=c0E@z-yB;Hm1$ROV=h`h$t(~wf7y$Cm-Vh zW^5(Jwyf~EU4I`$$ZHcH{otwNVZ!c->SKkXa96+V;PJQ1Trhv+JEe0R2##6X5CL(Ie^jq_Pj zyio$kzYxC7HUpQzy>D-IIOVg!W3}8=B)oi%8`{UwUdg*&>G1KHAP-60Nj3irm@r1( z`@r=zk3h7Rq+rZ`XaB3z_lM4m4cQzXR(qF8_P7_S_#rl8rb5+j#P;>Zw6sUa`&nsb zW7j&aFjr4GkK0}G#Es`p1v_V zg<%m?QiT>rJio!kdIP^RP0qH+*Gb5dYeJs;a~(apl@ot2%u2X^$p~oX2x&1F>Z``# zmIg2yS00p&)mfMe7(?1RAIe!URet%^i${SL@~s+SKTt=UrinJ~N=SWyS#li8hBvpv z$K$(VrGe0ZDW2)KG6h#w$^rVw9ZI9`XZr1Q$S z$0Zl3nRZ~Nt4a08OFJb4nEO~r35Y>ECN}&fz0o|#6fr##jCO~yvWBlzLIA%&F51y# zba$AmQ^Ax$Ztc75KT;P~4aHo@cDzGU<!{izl*3 zZsYk5Gz`B_D>VaG<|jVVh#$ZBudv>TPnfYmUuiM#GkiLYD!QggKr@IrodUM-I7pcU zTL<|q3u1~_Oq+Le-H}p81lP|q$tWn$_GrfI)&ZevLsoPgXgg^%m*vX}kvbLe9*0<* z-W+|8!|NvWID$JX`t+TQ{X{k>Fb8gplyWYKZkK^x!Jc)52nY-wLNYPY zIqi6s-)1mk@hFS!gb0p8tJNxEZ0DvDoMikgs1vpuPe8t61YxQ1fI)Fwqj&NMw#x~B zH%(^X`BHZA5)3#tgjc41zQ2x(i0H*&R&I<*?It@ix1xHHnLiLgFnu1^XOkEC7d^da z1oH0Z7!;PxmYf^S)Lx0!Ny(lGv^ONGp-N$V-;CaNND!%v0Ns)w+!Qg8uR&cx&1*9I zJMvgQZWAM^&hsbyv{Fy0aA(RJyMdmT6{E@5HC3~D3KnNRwgHaei#>$bVlD0uI8~=u zA*i?(sq$s+Zi~G&=9$-&imHSyi{3eyRn+-vdgK$bi~Ucp z1$q^~UeDkqTi;$_-}E%GG)jC>E!v?2L44HbfPMXZ|CKUjB4b^lrbN)M$+-2{_xn28 z62l>E&63jdp87*Oq*EBMQDHrYeUtYe&nv^vdVXX9-LhpmBycItK#3OoB6P}fiWN^R z{QqL~Cb=h$spANrQeiu2jW{_mdXaHA6$!;bG}$SKH+TKZx+6O8Kj(5PQ#VKQ&+8V; zfN4?3Iw`k&YvcNkR@;W+u+swmF1tbCvp#ZEP8mjFs)>H-iu38^%FfB*ycm+qj&6EF zjCOeUssu&Q=(eT@YXY9iLQCKC-4HtjIH+6v&sYd0C4xcDM-v5Ia_?f}OHZ_w!-lU| zxjR{mv%2Re)CtkYai57SV5Fe%P9~IowvyaG{WTtW!^K-B;sp*>)#bKnpfqkblup_d zkOh(pp#-=kh(~P<5GpP%fg+P)bCE(>BHwWVaEnPN z{!G++fZ|k({gCBvZR)qNl|g^^XhkFmg@X#oNX}Bgw zu5gPo#CS-a9Hd8LGCsk~fdZdE6#}9=FcbTD$Jw24gz>Tk4-&aH-AJb5`D_n{L6@a; zU9r@Xa%m;J7PUCisZv8=R)S6rj)6OavhqwfD-ezH%lc2tunuwL8~Y$E%PWHEOMQD{~>;c5Wv3(4&R%G zTrd)(Fvs2~+cuqqsdd7?!iz5;AP_uiC8jE1wMFLG(hZ>YQEpy9%vUx#nSK1@*!ElQ zr9<<|2a{J1Pi=ecc|2#8J7`~%Pab1)#WlM@UnJ3=wVX@j$hiIwd~8)ArSm#uH8O=? zVO7PrMwbNK01Oo1_Bl9W;Arc1@>IX-oZU2tDE4ntQ9vRDJsq9JEIU%L>R*F@*-s{5 z7G`+P97$utUa;kn+wL@fu%~b^bDDU|_;px$$Fg~warHq@km9e~{M-@MN_xbjh09=w z!IO-ZtWRdzxJ*KOMc$1WF75@C-4Y7hfD(?^l0<@ULlHBM8`kMqZYw-W_Vct7uMXJ1 z3UptKY|eu`j{cPJtq)gAyLL1|z#&fC@M1;z__FurEcWNtYz<3p22AlCUR6o!vf2lN z;0cwvOD0QBubfexwIshU-o@~`I8t{&ATIypm4|vW-CX*tOa}<=9I99hhPDRXnsjV> zG?EC~$_o-($3qG;wZ6yQbL!AB8uQsWNP#_gncWi`-k;-)-3X+!1F}e4B0#a0%za+AUJO6x7A??BO&3HzJ-v#;mA)kzn-f zV#^w3h0chg4e&*p@d*G-GX3n|mDBF|C8JGn( zMprqk@c{s}))!`Ed?Z&W;>bdXyvABsk+OeavE0t7Ti>v~*S4>oiF7hd6w08?63@c> z9U)Gys{TU@)#-z0B>K%%yeA5h`){0(p$J>S+L7R=fV~d)PDB%RFr^wZpj`^_#9(f@ zoV*4ldb>j+2xGrBDlblbtF5yPt6993?+`!bfH+*9U;jy_S$nkU=O>8=d^K(_*-iFI zq5$R8oklZHXO1YrAw%&Nv&d8wv`L|VBa6v;&hCZ-^7{Pt+#TDDcDt4i8W^8i-*A80 zq!!BrV|f0%MOWr80yKLd>5aiV$U6Y-dA0lpD>C4CvNeF7T*&@7WG+Shd8Pix%EEe% zPQJvzdz$~s$akGbI0}@M8#+Cdy0Irdv3|v_F%A1^+Kw+d@=y^QWe{D9ox_-atQuj~ zN1IWiD4-pNe2|D)yP#3G2!&0k#%yE=hJROPR$Kyu&oz|}kwbI!nUzB1y4$}KR7+NNyG&!Y{CiXz-L z>!ivxKd9}H&k5)->{|jP*8Ngqt40K3+pA~(!XWZbTB5Jp2mXx@4(6#fV=?-tY{R6? z3sV)iC}!4T)>6Ayq7gQ8hOG&eZtGY+RR7Kzy4c?n})lo z1pT&C_*CQ$;nA~7qf;X4*7c1by$tC+U^e|*j``RRa4|v@n?utXk{}5&NzTTIxQ}nX zmtbPcMSod|v-$;yaDGped6oER_a*7)fd43wDxgM2xZS|O>OhOW)82->4_t>3?=cK_lQ%7Mtfachw6*S zV2!>SF%dwZ)#{bO(1l!rT~(;a1QzgdA#$TVqqzHd+6`{RaK!Bi5Rx!ApDqrYFJ8!; z&lEC!CcHu?@5dD`E~!6C6I~z76jrYWtN4uJs=3v7EdSr(H9;-Oj$6p%Q8XaeFp@03 zX0XVRRw$Tih(O~W;-1uyNUR%Y3M)0Y>6ZT#+82Fl>>Lb#{sTq}n;8iSL2X_PsX~9K zuHq6;Q{%uSr^Kv>E&{1FKj(@)n}mR+;-n2K?w&dJkSzBZyLYwNQkh-x4sMv$n!*uQ zP7i+oBT&gSj0-D*c3Y~BHKl@?Bo5h*%^=UXfaxz|uXyb7bWRP9x3$MT7GgIokrwq= z>aVMjpw%`$*XLiUVAOEBNflKX0vkK|dk}T>=apsks6nACG*6-R6-%D4s{W-NViZh4 zO@bLWN^ts0jL?tbj{u3!cA0CYCkG+zd(xr>lGBv{W6VkL^NE)dPXF7fK4u6oALoyQ z{#vAy8&A=M4gc{j9~JTA52u(sVLSac8Z+Vf6H-n6z7qQ^+bJ6trGtq5$B?zcuXD-N z^oHgyI&$<;(>z{^#Wu9n;DRWIsCnW1MOd07i8N71!Ml}74Jm})?>|*cEH#y2Lc%^Y z+b)+C*~*de9*5*g*H~fX598RL5!l(TZ}>`DUAh4SHFgt?DnLhp5yxWE)8gq- z--VyUZvZ*|3dQFRh>1)OX$S|LxRDnx2W~!W46d98z8;6@Sc~8Z;8WhMo@RRUUZP70gLu}79hGN#D%o3!0h9jQ5(<%1975#Q zHrU!U#LOdF>@qb}?7YcKlOT99z_rd)*;j=^uL zjlvSdrEEPj`o`}g9gsTA@O|K{7X|EGwqXA=ki~Mt5Gk>s<`Ls3|%kl07Ejb3v^0@8O%+K5hRBii0tq z%PfGOWxIN4{r#|fxm0wFk}2Ihsi1U_22W~T^q=xm&YFA+)+`!y{3s&xU%$7(_C*iG z9FTd63-$N-cueFodP1yHd11?Ew7@uUJQ5NuF{Jt=f@^_A?MmH+yZ_Y{&)$fT>F{|q z*qC`Of|f|0`31S^2c4Rq)NU=grg;8Y3LBzDLEPexY9GT{)3ZI6lo9*peH`hv_`i1r zm%ft)`ri>9a*saMR(%~T6UEFLn(QHq2(!dieVECfy-q~!j5et<7Q_&O3P0Kb>)^Oc zBAwnCl7!%Mt~G4FAIYO-vmbsQxjZBk%r~;g zgyP;Tf292zM1vMU;LH-0|0N4_hvu*}(1}_gCe5KWDq)|9-sw{##t~{SoC9w#g2y(h z3Rnztz(R!!%WN+;0VH}#Kp%T*6{27OrwnI&WEp63L14qKo&JPSM0vzrs>~wz<34&8 z2~qetF9r4Ah7OkdQhPN`mv^Q8G>fVlpAliOm)pt{xcKq_^P;C+PTOy9H$4835eZB7 z`6k9ba1kAK$1D~vu0Xb_kyofFlr2S5y`OlPk>CI5YZLb4q&KQRLaq#|-1gjRvke7( zXl?4o>5fx<7HxqGr8bFFY>uoJnFejFOE%5dAhgiPU$;(fPGl}pkX~RGh2$?IeK^|u z$+mFap%y8#V<<>pD9r{2g3UG2ElFJJ+Lp3(`+dmSR-kM;?}`GL@YK_xMCL|Kdo zx_Y~RN$N~SN?9`yM&{^%lx+)8zv{wVAjn$~g*8voRghPXmexWhN4l=?fUI8$_|0W2 z8oKM&CwT1M!?*^F(j*gfk#v(1(g`^6gkQNeknq0w&VCetO86!ZG;pvw_lHP(NNr!I z3{PCA9(nj@jU9|1RLWmPz`Rz{EYCrjVwM=}o2et6ZgZWI4oNWNg+Y+v`PO6b8yb06 zE+`F2EyPurqRL+&X1Qq1+|uHCeuRUhW(KcL{6Xz$WDnhCTE3f^J3= zgVBRm0qdQ83i3q%Ig}iC=Gi^WOy`sp7fNvllT+W~_{hkH^`Zsm3cmOkMnLl$)sXx6 z&is>)P2r~w7xouw5v_nPS%A@*tRFKpIi+3BsgX4yo}p3T3}s)3FFj z%VW92e#Xo`WgK_r6XEF`SS|lIl)@ngABiPx3$>{)eZ`>x3VnkcG+V zdctw!!%3tw1w!3lRH=T4j>>X)=*1o((LU_WWrZ7tq~WaWqy$>q`u$R*voQC*VMiHBDKUuS{P<>{WEtitK~XE>ITI>J>8Bt#FV;9vXcvMg6e z!_-1y|F(tnA%9p6w6B)q0#E}_nfA0Vzs?6^b8dabE@@}?upRay1Q#vNy425Dsz9<2 zQm;%fNntD)npbHbj7uU2Y$_H7X*oVyY14T;-V8Kv!a`b}u;N>8Daa*ojmll?=q>Bw3u3)jP^RV&6P20vs%yZ!3YK~vX_6)1Zy2SE1 zn8tO(Oq1PV_6iZDhpV{TLXXkxtA_xh{%b=U6{xt454vIZycwnK<4q-(RWu`)*08qTNy>yKV}|;*a7B-!3Tn$B(fIk>C#Ws z?8G?N_yhCagObI?wR$ko{O7Wm3uZt7Z4?RZ%V|rr7F}~X>w%!~@uZP0bOGaOl%jxz z|7-@M$g4?jNT+)bl4TYO9QG50L>@?y&lM@!kmIPBP@mP3AD%#L1ukxnbJ-t~KXD^x z=^G+h{5id!i#rX~#g|KkWVudEfM5{-&kxav>BDVYI}#RHIFy3tzWo8UkRdEx_vh^n?HZjbgRnT_(FhSnEd6Uq$1 zDu778{(}oF_|ndg&J1#uPW+MtSD7@})|Ipbzz0qXt#4kMtW6&3EDbRQwvUzatl%rl z{B))~@>yQ!4Mi91v7p{i!^+uwLnfS@YT?jZ@WIyvLzHAm2J>)A>Huo>2bsh^EwsyH z$q8`6I@p&hUyE{x3!m?CtC7PP+JPWiRwMziOh^iL*f$ytLe+ zy_^^dhnfA{ENmb2FXmO0ME+R-`SZ8&DE=~iT$NqZdI>p3^>#W9+$wNtSm^V!X3GWg z>8kntZi-;~1IVsxSe6E(VLUnkdZJl<+Bo>ht8Ab$Tqzd=9z0vrv^Qf#TOm*-bu&}P zEPrfJx=eK@P;=6!nvfX>T^u#eO&?BE*}gz$z5td2<(~w+=N$oCa>3n>tvXwDj@WVTFo$P=`;) zF2M&n;`8E0gQxOZg{{#=kC>8dO%t zEj+G)*iDla#DH&(WWQBH(Oa<2FN&;Wr7iNq42xqN4JvGPYeOdxK`Qi!#(&!d@Hi69 zKkYHNDMm%PPA7!g6mC=N8Z+iNB4UBeQ17 zR(%x-*?1AJb8dyMW>$Uv=o=Za`%tI1KH*@qnBo8{$ZuP++8n{AM~sDgg8yS(GZyTf zEl+R*Bo1QrAz=Mm#T-+6(Hk{AVe9k*wia#1jL#FY-uYcbHy>NVnmR(=r|3Ybp0yE% z{bu`2N!qY8)KiAO@=@Q_NN(C_nb_kHs~HPHY&^}_xi&90l%^*e+Kiqpn4)tm|B2P}-dgi(Rb>AD z2)nwd&(BuBxPjQ1NBHY7&5Q^x&AfAvlN^5Hgne*d#EJnR>G79uIZuxSL}MV_&gG!< zL?V2`jk)h1*L#!LOtv6Gc2UZG$VHQ!RQ?ZCI8}NhlP)Hd8r_u4r)N94GOvW7=66c) zYtO$!@8=#H6W|`}Y%~gt6|3^f{jfyTc10`sbh`Ks%hT zz{`ZDvC{nw+aV_C2*Pct^xhp!f=YolvvHC|f}mpu>CECaKh3@Ip`qyQ7{as@o-YB< z^*a0c4RB`CWzl(yVh>rJ5M5-=y*oG0U+Wm{iO%08M(eB&nD@Jb zh{Oo;$P4V_>qg?0wGN^rF?hgcQrP|jv4Tq}#nD;!BcT1ue0cQ*Onsd5%z&JaKN~>8 zpyMHby}l(P;0EDYBDgzM*&vJ4LITat-L9SZOPvCbBv49_c7JsM^`Dj#_N!OFSjmZ< z9&Y}YjlB|*UzfA4wel$(Vp%&}$LH9~#sckpcI5=^CZoY8p?lpxWzEzq=WR@%00R@%00+qP}nwr$(C^VR+1zcFs(MK5~M zIMLbrtTpr3ZUCu>Hi_Q7mEiXDWTVJA+r4*%tqdqBGzDm|QMRbw@RS<^oSR?T9R;Xr z^2!qLA>2}Z>z@)!OcyocO>!b@Rn-nHL{WusRG{T)fe4s8Qy-3=Sg#D{ECIvwHbuigZ*nE!ciBvJ|rSxO8dp9 zi2AHlfH!jGZx^2CjC@3(29~s!L$bhPj@268j3C+r1z(t<{NvlO`QS|g|24=Xt3rmd zVHSVrWt-Kk(mrxL?2$6VTz_uil;qxX&sIJ1*OHw?4?ot~HM8PeUSPBAv&C}`L1zaZm0CWjuphh^n9w*B+9aPai(TFI zV=Fef6%znBKHdJM=_(bT6Eqm7(?=gOV71|RfS$&&Tx!k6yvZ#@QC62{6n?_VlrHVj zscAW}^1NccX7}=l?Ut@&x{9w;T0-t??+Rbsv#H{6PkeZeUFa9O*7g+)5WKKQcFIJ( zx4!u_uv~otvM7SwJ_OzL1jK0JiS#UKrYGm+YL#{hj%gBpSAe@9uMh?JVXc{VHoV_? z6%LOF)x*ffOZ2dNi;AqHl@UL#H64Po>96%P+tk3Mdieslsqi7y-AmS;VSpQDR%HW)+ zqy6%ILuc@|KPQGS^`HZs;`tL>`rE}|x;ebDaDz)&ikL-xopKT#rY0n?=sCgE$TfA> z!IvgsM=@U^e~Pd_E)-c6{T3B)HU#k<3@-BzYZN;n;WOG+Jkg8=?S#O$VXc8m)+48TIG*XM--(i^C`NJ-rX+E>e^HGK^4ImVcnqJc+GrNz7x({Y&W z+!_=|_SKk{mI0mYZPvO}F}OjZQdkhaNXvxXcb1ybh^3iyYom1kHZc6gA62i`#fG&8 zx%;u>JVd9CH9tVR7&Yg(;^7h-qw5R=MwTkPyJ8UMd!=fcr@(%Q>+;fW^a5^{YV)F?ZpuR6$>%JVPmz<{Iu14XPHw~#>Y#)|DTi%r=&jtK-( zR45-2SwXxGGe*-DZ%nTG9q8t4d<8MH z*~WrtZ%?~oF#S?*+)oXA*N`O?v)umY%a}5|{6O#A%+hTx4gl~JD()8Q%vw$ccnOtu zM$$A-a4XNJkkumyrg1vyaBwS}M+BW_?DN^91Ih*rD8W?_9wIn*#e<7wr34E+a>usi zz+Tu}h1Fu!*4;|MLY>-qs+fcW^uw=*w5|inWRaRXlUl>5P?6#@CK=VfC+^Opbqp)@ zNB`b?=g}o*@-evl@SWeRON*-j@092hX9yQNC`=|?;Jas@aYRaYlVKb4iifA;8kMgy zzQFJ-Hp0@c#g@q)!F6bx%Rz1%ejH9)+>onRcPnz1bm&-5Sw9*aE4q2~qT*0V!twxK zi4o5eMO0q8Adi3e1IrK$z`$gd;!bm5apJUW!*usc>7R4!Yj#<>?TBV5$bjltsWrE|QFE0y#j+v53?@M#28G5Uvba2%t=PL8ia<67o zFG#!bd)M*ROMmVd)7>hJ7K)o8$GbdFz@WE>d6MVi zGz(yHA+xpc6mtYq18SsRqLsWfH}MWB{Tu&n$73Ov-lm|YXGUTj<4>spK%l$2{dr&H zqzY9%$&W>et*EtNxCq%Bj2Ce2=+P$V$K%G$DKIG`OAF+8Rohpenkawq&>#`U09}AK z2yw3FJ^y9!scUj@1EI~L$#Ix9?SZ~LE&(9h*LO6J8HEZxm6p2B9w={&>SqhUkScKf zy1=q3>7i`)3Fx{X_0DqO<(Uji#k)nC&EX{X^Z`_Q^C3B{p#FXHXi3{sU@xm;SGA|cMcSB0F$_YV0q{nc$Pg=rg7z5?C}d(t@egw)E>Nb4)(So|+!}Wr3ylAf8tJGl}Qs zq5PoCgRi1Z9^`sO%IrcWGHFnib03vI(akY{w%2w|sXD;raHtgW2}osX1WYe4-cm>> zR;f(&l?pKy*Y2nd6`y2(b)3z+t+8?cMJ%1I zu(NO0TuzI2n_t&Gt8c%)YdR`SqCL-Y4%>52N2>^l6qNFj8S9yVA~x4K7a8W69Dt3E zkFKn)jk41*&V#P2WB{g~qN1wojEo3l_=QZNxisa4O!3+L;uCYi<8#vE zQ9C*LQhiUOm4J(5|2L4m@Z|6W;Lg?hcMgc({J(+h3Vs>CjEJ-bD1Je80U7z=h@Zx~ zh{*2l>_cCBM0t7T#5~Y2sPW1OK);J707w?p<=)&1eodmhLQEQdo#(~h)>+fNT_+9( zWdday5eCwb-d6xUpf(`fZ0etuZ+M%d+$n%xp=+k)rTLkYTrdDhM^jTz8!#|7HZ~6? zbTU&9E-@w#&r9F8@(fLOz^yBsYJgl-u{@T$-2Q(=HUKW*%t@aw>RTrkfI75cUN!Qa zZ9?02Zx(BA;g|HsQ1&lf{j31{Z?*Y%t(_k-!kex26m0g-c(Srm66hL+#u_KEHLP_s zA8be^TXmL~e2@T6qKbR@JT1(IZ+6danI9G$c0 zYYSZePswi0i7TUK^9xKw?VB2c)B8#)O{)$M%Z{EVvm|TlJw$GP%Svp_E(9O+h1!@{ znVDX>`~}X`Sj$NJ$?gn~RE4=Ej;Pjt? zT%o)BhSo;#G%O7+KyPYk|6Fu-Ix-MZSfZv4TFJB`~_HfNMU>Ovetmx@q%!6J%3e&;A+tBM7 z>cD)dM|k4bw<--kOIN4uhWD?1KywWBjbEX+iZLT9E&OC;0A!DRw0oxrKY_QWN52iA z^k(5<<&u(fU!{6K;Yf`vEll-wEWq@Q^}sN=xUf8X7<|foQzKw^1|La{kaOR7=>QmK z*8jd%5#WV(h8IAQORTL|YJ3<}kNyYx+mL~Q5fH=gchU%yKJ7Pl{OP>;bM(u#B*NGA zoDa$93-99B+3VY|lAUWq9gu}uI&1pZH7qN?u`sw3?y%G+jrV?b)z^3NvlYzfm+1R9 znTFcx^hRWKVgxGBQ2z+TuCC4p$z=cGy;bSZ7nk@~{MB*j*ZOyR7yy3`*9@k$#maOF z*(!YlN#lk}g8Ei!M~TPLw1D_+a!z#y9bQ7(j8HXOhlXC!X1TW@H0?r-vz5Ox$(gs2s3#C0 zkJX-VV0rlyXOR2b-y>15N^`zG9sXRUYiucE-z@s1Cn8`ox|MSi_TuY43K83y9luGm zTTc!lf`tIqcy~9lKqgTmuOhh~tM*w!3w={{WF}f5fv^tMv_{UZ4G?_RCvGg2VN3$gri_{kF;4x>wD&ML zr#<^}Z8OHXDHC$j>Nm2Ca-hi>s6HqZ=T&wFB@yR#{VHICPIOX`YYl*d9gr}uli<>x zb5=+9%jYWG^c$J>9DPKr`(O4FD4Rxzw7p%%QeL`sug*k2YcJ4>lIrg4S+}r<{c7Tb zGL^dCi2XF)HrY-2yzdd&zQm%YZ^bp$$+%lD2Mx+B-Lvnzz(wIJftg_%dR{FFQ251*IyIadx$Y9Hn2+zX?3>%Pc2j-c4ecT)V0{yVPrih5}@(~tHQEJs@&FaoHqH9J5Lg;X}=YQAH1`dbT16JD;7<-~C**k)+W*rT~75PB{kr7+b^7 zr%~@Mx630sqwh6ymdhvKo*}~pcApc!H;NE8r4f=`Uf#52o8%g|GI6>9nhbyPvLH3E zY)w`&z3{P9UOhq(nJ;?NII`Jdj*)NN-%$dnaFzW4M-p|STWYezy~lZ;qlFR4Qh6H9@bS)W4%w1++(K@gr&^NS8h`<2rXT@#pEz=0G;} zXNuZn2LWTP!rFt3Ds+89jf+^n9M6{~aPDE`i;&7=q=mKLCAUqH3Y*Ei*(16}O$>40 z8X-gJSQ)PBuS&4q?zp*$>TnrNWY+o#k#BH>J<=c6ZfJ|Ub_rhL)Tr04jg=FRl!@b% z!gGfE2}}Y^fWE1aH-ESrl_t<|A|w)`rf?AZr8f2E?NLtnIh&`67!*0@UjT209myGz zy|acmzOE9eCX>K{EVto2)$?L9wTDU2g#5j_T|cUYn1|Z^ctb|QQKC9e;| zc^c{pjFZ#T4^D=yKK!HYKn&B1o`BE@Txur?a$>4^>^(*6ZICzvN}qB;k>iwKTZ1~% zSb}NJ?&?FGtW-mt9h5xq95yX^ulNpLu)mFaIVB*N%H3Hr&jkJ*1@6jOqLC-9x2b6O zL9=F;P3(1LB@5bes=K{rR=+vwY+|o(IVd{iUWk9RD7mGpHgC$+Sjh za@)lDK@aon=G;kr?H*Yld~WfQ{biovI{52)i`2Kj0r`CNHq3iQLr)^AZUQyyzWWE* zXW+J0n(|&;(IJhI-N|a~QO%`yNUb$P8S;@v2=3}ZE zaRnvPp}O0NuRKFHXGtq@b4}KB!4Gpnm(?6Npn_4*G-XV}VQ#6i;2F_`Zg3jULAN^P zkUVsI;rj5Ki8emtYqR+_&1_A!_GGj_cP>C|Y4z57=Yc(@kJG!lAKNJnMTTfcuZ=d> zU(~42HwxfdSRPEpL#!Zj#4*t2h+Ri91_o2T6i+(LpPDW0@IbgC)7;{5ZNM`Sro`iI zYM}n**QV*!(cPqy(%x_wl+F;jYFdID`BR0(Og`E2R`pUnE@)v1&UMb6S9^N~0T(7} z@8kk5Bo2P0j7PW5fTEnABU7%0T19&&oy^WXbmVml?{cV>HBy&!k2i2tUMd*6Uh(xoFUJ&nDf49OYnJ$ zu-47Tn*wt4p??h@1#QKww= zI;6qi=s899XDq#)#ExXD4b-zFPpiA6PL+8J%QCKij4sQvHN}W$vVEwSBazeY$&!Q$ ze!YtrF0RUu%bQ&-r!#@QeRhKLEC(fNF~ovQSTI^_nB|J|~eru(+g)#bQ+ zpt4BX!y}%uI6yU-!v2NdkUAuQkoKR>slf+)Jj#F0!u#%4LNqu6B;>%87wS@jPS_U- znwO?;jyx^0o;TgR#(WA zs%+%N!>K*6rj;1WPzE>AQ$l1=H-t9YcZl7Z_h!H*C+g&rkwXt~d`fOpxtov|&_E96 zj<6ENf|>t|xI)__I@XI4`ff<5>a$XSmmM1+T2|4pqs;mmI?Oj`En~oXpgc%fb2R$# z@Nfp|RLvnYz&5uIcBw(Xtz{Yu-fl>2-qWFlSALh1i3VIzJN&h1U7ypFb~rK*J}{9~ zqgI~>FtB2KDp@ZYxo2Mt{CVP3tmeGYvWjXAXR4{L4{WvMj72nWCPO^Zq0#^)n8_x8 zdTQL}z{WvUNOWt@tt^5KTR%+SnkI{r)Mpb>k79JhX8|1Py=ir?xEFf#O!nsf2<^_- z#P%=*x`iiCr8ESFy=C7Q&=J8>q9Of_Qru!YgA~3!M>pV_jo3E?~w)1N!gmoqf44z^Jx5)9LN()_X^tj`V81iLatFe!mBgJR9_pa zWh}0ffdS+;q+|#sq}v+AzMW{t==GU$7rQWJ2#D|m=f)6n!La(1N70dE-M4dpr$&rz z;R$GR7tgCG$x$s*KK(2sJ8#b`o8OL0%a^29c*%4;Wwd;=o$-QpuXgp8%4^KqzOsw0 zMGf2GS&VdF*-=7^I2|PXik8L}41X2kK@5lfKnUlME^+44=ls)RGY_HJz)W6x@OP{b zVYHX7V zsDup;>tM;O06+#m@_sOOoF2oH!J3TMUdx;NFrkrQbl`kbS;?g=xspu$=lz3}TP6xV z-bbqxo@KnIGFQ}#8Ti=$@cegUsmDk>sjgsDeKLO)bcsbpRcQ6N#Pwn7r(X&OZS7e^ zCIl*@S-MNmqD6Xk`ltzUxd|Wf!$0{SZ^G_&Pk11Ym=mcR+-GgJ&m~kY0a9Dgo2p0B zV#luk`nssJI}aF2BhQaXq1TX zSB2@Mj16@I)1geC3(SW}8v-MQ*POYF z5#j;o_?JH_GKsIM`|E|UISG{-hJm77$TCGiygW07bxISH@KzVy22@cp@b+SBq*VAP zar)h3#1ElVb_r6omlf63wwZHP=jLqM_T&Rwjm8Lm;U7KH3rmu#Ms3-&b(TFjb%>m#VR;*o(o1zN3*95d;uc{6YD442;a6IBJ6l(8T>8Sup|c+-QSkkOM=_f>K% zptH@spZ>aN)b#rGV8-|f%FfBGSvd(?7Dp2eX^pGY0=cBs>!W&E-spL^iM*aMpNDtbvK$aZ2|)$3yWX52hjUicqs+Mg3tOEyFrc2A0fn2H(1ZMZtq(}m@_c9r0p5$ZdLEx z4M{|m3?B@?;+GUsibTLzGwM-$Apvn>wqP~SRz)i?{KZ}jwJMqoOi}6-)c86PsHS)< z6x_n-0IS&+XA@6b|NQc>$%R8wSRhd}E|X)4Sv2a7H^AzgdjzBNfLgt!nh{K2QXoXBj_9EN?5b6!S}Hego>p2z z50@mS6G{wx%5fPef#^vPM)+#`S4A0d zZ{5ymm#b<;_Iy7U0h_R2(WN@5$mKbKD(N}WUM5!qn)Co zTBi=zTQ)Zw^?P}pNJ_WWdCZ(&eMDaHYQjiV;L{L`Zlf@IUZ4lVUm&-S!s3Wm z(q0~+ww;U9R!1$88xyphHfUD3EeCZ-7G$6NX=O|~zWh5E_(ySfm6&f+^Gjl|Ji8wT z3jB9Y+UNmsrk%)@ld0`BJzT2tcnpbyD=l=&U~dGBkRMY)b_^nm9Ji|g_cDz$6Mp_k zeQ$-3Km&oQG19Km+R>5|6`TfiS6=}Rz4?^YtEYKpdcgKcHXQh>VPp-%kyEpP7oOi( z=mD;@Sxcr}>c#?a-IiEH!EiB!wzbWlT+~+&5S@dh4~((u&)G1Mve)a_Nh<12(bxu0 zMoD@M0*1p9MC#WldK=DT(icgwaKOG)^XXg3=Bv9arV5fYW-l*qJeMt(hzz!a6DY_u zt<+1K;?f~Ym9tMs3+g98DAVL{pYsq`4MC=*7>9FahmUiYr>#HXMz67rP>j8&d;yFX07 zeT)p)TN3{UI7|F4#5Fn_i`6ooXLs~2!IQiqxnG23%1IXQIW|An1E8=&C06honjanu zRP9EYZuU2$u784r92Ja;&JJUTa4@wD^U9rqor+RogAHDi2#h%r?TLrrbL^crP`<~< z2q~ya`tn%Y^aF4UJl2w@)1u8-f?aG6XEJ3!rhGuL*u6ARlP_w)nD&d@oQ^WQSq;Fu zFh7h_OKjN!lt6kfaPMe)k=SW5S}IJJ!M`Wk4jYGh@?G52IACZ}v=#DSWB@93ksI z1dU2`ju`<>Q9H*fDT0e2y#wJEdz=R4sHm@$fdbtVuRNg2ODUKkVhz*c@08x`qrz*3DkTpo&Sb;)e}(0qf`hvrfqCJOxQ~lv~4_Arp0dkg-Oz%!wVCz@GjH! z@lC9-R%17@P04bot!v5@P%sjYw>g`K^Y|X_;iMm}f}gR~)(BO-dZTIDomEb8;P zSO5b;N9Wn}FERh~S4C%th>1|g1aQRmC-0{`AZ-H3d!b{r>#re(Mbtx2X zJxKO9@{bL|%-S|66cbx}HCr#inAL#b^B`aWp!X@GI^)Jo)K_9xE_W&EdiME*mtNOL&QV3=DThnCnMrZ znjs27$^aDJBui%(=$LR(Ec=|w@+1LDRrw+V_!JAn*p*bmv6Nn2&bzh&bOfK`{{mdZ zd5Te2d5QDl+!rkO9anVETgf2!RHbp?$Cvd>>ne8d~(Xx4Ikg?pJ1~ z;50@b`GdpZIKV1Mjl2SvLa=KIi5Dv@Or&sjo!ATzWYwl$vSoC@9pWzW!}>z>ZR@oZwnp_r5l?b3ZWzb6Zk3;F|LOra+h_ML zq?do}kx1ogPj?vKlm;|Qd#NAmifXL1I}NzHP8P?1w>mtt`P@3|Q1^g=aLImJ1Ld2W zA~_k)P;^DtwsB3(+{eyv%?!e4B2wHiwZ`tAn!v@|xDh02#t22RhGTFUBPtQ&<3 z*W3>&Mi1McD1Dex;1EgTp~mm=zUZXGQzM4$XIg1EmAXYE?+1H%a|9 z<(tC0$z)*n)nVH^#5kDvQz38QFB+^180p?d9rh4y+2I~-c`LcRw4$FozL@fw^9~-? zC9v!TVdDv>2L!!ik)$_2FoHtmxJcZP1yYAmsD>8LLr3P?dtr3HEx@21jWWf^)i%1d zy7-Iz0izIT*R*q*p2~4t)qvD{JY@Kb>)UAW$l~n1PG*t}vQkryPa?8X#}zNczRkaQ zP${gva!z-AYB2<-dkxV~j!Ew-_v5EC-m=cdHYU5x9qqPf$HH0t%~Gr|Zgs&Ub?=b`Qw}ETE*Y;ib)UC%a?^oqKY5YmbDP<*c)7J~ zL-@8R6uB^d0LMwly&)T8}8nZ@wvEcA;e}Hk{0&#Go8f+ zis}|YD`k~T9m;%*+&@F_xLCxrvn_d#*dp4#Kb>}J8&;*Pw+gsJGX$Yi`DVv;# zVq+C|l1`^zgQz|g0+lA{3+Bo|w-iOv1TYcEo*P|KM{VM|B4oU9rFcs`aqz&F%Y~X@ z&+KrtRN>nNOl6K2fy&*n$+l!$rTgxG|M_TpnRCDpMstL8h$Fa9H2%~gpyVVCk%xz= zwybK<+1z#DX-9|xB(}H|DMdEx^f#Q*C^uL1=~59T;-P z8t??ylq$sbNA$GwVId!QZ3izLeUuSvpk89$|3xN{{Vo1MfSegHb4an0VuQQNfTv7r zxRv_o9B%7P{3sA|h<>UTUnnacTk^#gZcIsrDW&>H#PeO2`O0Wmf(YB2E-pVpWj#eS zyXKtg)(W`RKU#4LR>(HG49=AB%1jACw^nW*!@4E2*V&FE%1}!e7qz?{68k$!q07xE z5AUf3+;blZEnCCnq~o!5b@*2h^*5w&D+?aD7pn<3F{1?_wb8oYr{Jn|v5KNqqt4NH z%tO%ij+sQ-C8LSlK%k|(DQ6?^O1#)j#^~A8(g8BtpvJHR?)Z~*-geX3bmu#{2I;z+ z8Z<6bwQm|D0~Oxt896tbAKUqRf3d4SYR`VGXN(`;WiqIHMx=JaiNsS12$k0B~$<--UxU_rOjm^bh*xn zp&-(k=l;8E)m@cWn&ad~Z8Q1?pVh4zte$SUdjEks2fm}Bj)hB4IcQSj377S5m3=8a z>eU`RBx*Au+H^c9p+z7M=)in#dj=l0_)+=1OB}7LnlgaB@@%0+*}ZDSH!d5?A_Z;X z^;7z9BdL2g%8E;_&WwL5NA3#<2|BMhn*|w+#-B9?G$+-X)?E+yRvc#1OlpwfFtfH0 zUwm!Rx4=0f@jUY%HD-I*w-iwyfYSZ-Ho~&4&tklF-v$Q5Qgg?6S z(vO}CxRKF%kVw8lZ*s(wajS}PnWtLYqYGxe)R%eo#0*9Z;$OKMsOtt3-^;hR1SN<- z7qDw}5kG*VmmqNgF1zWT-@XyC-s_eoXpfyS0_rFgUWh^U^qKoSzr*c&lp$L7t%Nlp zKbbl#D@7RQBoEY^X0PrecUmNliA%jyaYgc$+MX)$mtH|gKGz#4Bme%5MpZxjWIjp% z+Kt+&`X5aZ667lg2V2!(DM?C=P3@BKFidl+S!=<3Z-#ikS_$K8k4IeC1pLoFwD80; zAIAM690P|@S{aB#gz^fs2iCUJeF86+1?;$)|TNJ}7x zE`@df04)6#)@6Eg? zKSy_p-4gX&DQj(s^;MuSows!iI5&EPlGVR{9+srlf;< zm9+L)Kmz(7lSSGe@$>53o?ZnG064jOm%zg$bB??AZLI01v>GB?2G<+ly_NSyVcy%`0lhiSfrQt3-VgJc|6*{}~e@R0p8f9+sBK5-gH)=&co0o8fHEXs#+o4>aJja9p zu!Hw1cRJFEzvRKw&Ja8@!B>wr;1=O63U$;f0V*%ME35`Rh&t^yKIM)ZJNzTB+eVXA zo2rf!t4MA1f*HGSuQLfQ7l=&Mq&Yboe!2+J|Fl}9=VO(~$VLU&E^4$Ev@l-^MYS~y z5yND(3Uo5F_DoVyh5U7>0~w%6ef>M`@HPXfWP^q zq&g=42Y?{NW@jap7pjl3HGE6gQODUN=btBxIGPM%su~k|H{YXvt2}hp+Iuwsrkn5) z7Y&M2PQM|olHglFwfE(B9AFp@<11qnPIa%PFP;Vc5ncH}2yNwVK$VVb(4CBqQjZvC z5g^N5{&+1(jS|FgumLky8Y`%}iI`ZD=}HHM{*plpw%OS|&FC2mqd@8rY?~ctJa}-w z_oLx=-X&F`?Plv%Ov!?#;X&84n8u;cntDss#{bI%id!h-HuI@lTCRF>mk;X(P#;r9Cq?7lTVM+}ybAhd&ULg!*7%lr;Ee^cZ zx!Jm*pTRd56LA;Jig$~eHI0?bbQyGE>XAo`iO#e9?|ol?a9Q;(x)rBG=h7L!foj)_ z)1Q0#S^jyWYA#@h2z#{?f0r5VP=zdDbwZHSY!BR$p2agav&R0TM%K^iWp+4@=<60f zk}!`0SD@_->-za0sD%uDXL=(d8Vtq`RA{e;)mq`U2QYgqYER ztsc(gSGnidcxhgS(hFBr2Tm)GZxJwWMIKWTTT$#>X&P{%DH6sX{?x_slXaBDtzG`)PV`stwhNLkYD(Y_xlzGWk{%Z3u$>yInHv!R=ha*!Y2+ z?Ri3aCufYFPN|se;iB%!9%9`Fw(`~Ppg8-RB-yxr1MS}kG**|;rzd~gX?f8$w=KD& zHgIj-drpt|LBokf_=y{wKiO!k*60JW`Fmbxh!Y)$k=X1gK9Wc>b)xdEX> zWL|lj4atD?&U*|AdA;WeFhY~gR&O0{m>HAQ2KBtq{hhGeEfwc&mMv5?9^>D!iP==e z;K7$9!gCkFu9jYLlhL6K4^0dmxPZ2%pL;11f>ZQL1Vc4iKlKTcDs-eL3^&E^P`QJ$ z7U#bp?>_jMP#xy*iTWK>!4lKSSfHn|#tG{owH4!oYTYEpA62#dPqS|b<9zHnV=Wcv zv(Z0Wz3!RV%JJ|L>zbXTK9Fl;bEf+4Hj#Rjf_NVnSg{ga^n+pAGn%1GL4~Rv%#?1jGYa9($q2os(0VJ3%+BkB6H>VGv9172tRG%x_6`WzjIa9%+{KA;LvCvR zPzXlf&aPY2_3Q`c))s6cI%C-fOKPXfqHG&ZcC>3ctVzk9^e)HZtTB&%Yf9?d)#(4K z;Xj%^RxwGGzYmbGg{3J;KMj{3S`<#nk!8ilBsHXK&XJk{03%M0c>p_4>r#E zUE_fgRY+e>HB@NrvO*2wi-(h6t4CwS-63&E$c(D-NfGTv51D%Bjj;-$Y38N{m%1t( zWYw}{cU#HiQyQn438js|Ro5|-l>klBFEEg8JR3_7)w4J!Dd{-B3hNUzX<9wt#@Uv! zC$fQ@7*f2pu&AVVX-NDjRih-IO0hGiJ?&)*57 zE;=-auw2{AWt0K*L8%HZJV8Q6%NxItD-~4CSt=kUdrl|=>kUr@Z#b6IbVZQhd};Q_ zgC)G_js(${ws1uQYhnZr52lAS@AcdiM_5>$F?F^msngU4Zf_H0!Pzi2+wd;mwbO1i6|z z^2C_K8T_8v(9@rY(jo@8q=ZGLD$l8-bLJaB=-I?%3{5IH72w2934bV3QY^O?*>9MJ zc&y%ekq$q&@VsyV$Rh2peqb})ViF3s=D1{S+pSNuaRN;{fT4i#F7s^(&TZ32$c6Gf zWaJ)gcA9k9aFu{UhTTt>Pb7yGdSH@1q7Bd4xW%z`5@f@*LUjs?JM87S#tVfA|5c9Q z>4bUybB^LvnIvs$`;245LF9gj}h?{5YT> zT)mqgn_G(t5OC#m!~<-7X+jNF5tk~K+fxiFYu4g0jMRgFCxqaAMRnpjJ< zxHaI6T((czmV?kQXblvr2=YfkNrVN4^Z|X2EifZiqH`U~o1oZ8Gi?^p3=;dk9XEH- zu^9n!z3(9RkwG$bf`p17Ag*R>LS+D3{4-GfU>MSaefBRbu=Vd9AY`9FEQ%3;IG;bb z&UisK+%m-uV?Pd(xP#u@yD&jmly;dZ?GENT*F-COA+@UDTt6h_2L8z25oi>|?#M%!C4TAhVVV0t zh{1!@zZMp{)CQsyB$K#F{64~aZQCOzv4yJpuag;t@@Y3y=J{ z;;-00SH--TZb%giICx{B#E)XA#^m`|AI13Hj1=?YlxtTKSLoC)fHFC}RNd18))h0M zEo9SKB643-fNL->e45ko~8TG0jzHjsbPTtVoO1?5zxvVP+m#fW!oB^8pMcN3c&RqGSiH zui2>OcT@NVh=wwunk#^i4hz@^cU5%pRg*v|ghm_lT1;irzcc!=~ zk3d*VkSQau2^9(HmWyHszT$YoO5CW_RSjT{VZmA`&eRO+w9WWFuc3zFZW&i>9}AIB zV#0pJLv7)C+KOcppF&o&_i8cqXhZFYdXt=FW*c!ussl#yII1rKsCs8|Rcz;X8 zPdD8l@-A<6vWXKtfb1wk)HjJ29{r`;kfl0Rn*?bob5&b({mQZA&XgDAVcS|02IM;w=7CGzOMXxl)7jKU| z(B+~;((;eel){Q%iNZd(VPeNGMO~;UeCNZnw^lg!_ooJcJK^g$holrr$2N%aSw-=l zV&`IlS?^gSDd4a&_I}m^zeG5O43$U6tQi-`jiT(%K7)|R;^X`ErGScGdMSHr&RY_ z{vbY7nz;wHR2L{Og;}FUWajb2=3)ivrctFbkmb{FR+b{h>&`w0DBd9ll$cAn1N^sK zR`q}0N;fj_$3J^}>wjL#SSa^`v><4%zXZA5YqsbHWR-=cU$I3;F2&4712SBTQa-jh za#o0tz~jFQk~s#;C?ZYNfsGJ~M~BTJiLg^+78@mcqKK@uc?nY0ZBh0AqEs->CL-WF z`1Sp!M?EyXpH|?y(Bu`&r_3?YTS+y3Ez5kYg%P)G#UYA>E4O9%L=P!aC)NGft&>tw>;;NIn{nsJ;owp~n8PbwK z3`(Q|&#UzepLdxXGSEOP^?w+aZs(n| zIrt7H{~^grR&w1qDe6c>uMaWW@kZM;Yt}N*v%HySL^~1pVc*BZ*FkT|Q68#*2&+Z@ zqzCRJJMvy3FEydXMhdN`rtG^-%5GtQv4+JOaH|I^TNPaSk)~;hCzW>o7?EsWZ?i69Mpfyp_ zUr|8Jehnyf@2udv*6@xSwK|agejCa)1e)e3^aI+sVJBZ?MB8h!Jo{`)sgi9Exutzz zSxQ`x$9g6Ax4CI~KHFNNQMQnp%0^6%Z|8ib+K$}$K3NVY(yXB!H$IQI ziX=qbeSY{l;eS{SNcx#R?l+vb)4xj(oomP6urnJ2KEpgB`=yM{0hnF&f11c5|AMumr0?1B7V z9iR#s!k?aoIu%!58@tqE?F>eODzza4)%agtB#&64bB=>+r~r}4Fe=xgCb5bN>> z#U*Kc;W2!1ICjvYkbLLp(z(yNLKfwV1hCt~ImED2MqZ>_^^FnAmYeYv(|h(U(wIhL zx}XeVsy-CgcCT{cew8ZhLglSfpd=FqWA$Ln?ovXHDMCn-;DnMx@_aDYG!gUkE$0^`2zdZ?z zLTQQ9X)CXW+qc&H4T&3)Zbx&v6%&y)PX|04-RwCYEml>f>2_s6ErNh=nyYVJ?aB@f zpCfSY2&54$tp)FatL}B}U`QN?x6k6%4M&y37D5DRFU$kE4lSx?>)tl)+0D%p5^NGu zQ#_I1Q1{|0v+mWH9&S@+q3?ilUj;LYragv|UVUL_W4I^2$76fMzg4wE7};VW2%po+ zoicC24prRh@)J$22$x+r;0jQOAtTm~)ZPK1B@ew;NvC)BFoYd!WV<12RgcvVDo;w#eqbfWm-HV6DJOK`e95xYD_QO`^jof{cD#ekg(94$>eTmn>cA_Jq zIpmx?-q4h%8+FE-JhYOY5MlM`J@YPeEmL#5U#b79dp9BtLYlvjbdYm3o8*NOp~wum zg39GrE%6JJ*dGCWL!WsZOi<}b5+<|y#~T`2rd_49o8whtALSsW@>|5DU_4J|I=Ti5 zQ@j}I@pdQ6Rob;`1(odT1TezdYE5Y`3pc4?4>H`_*gYh+Lr1gokk&?(50@w)lI~i~ zKu!jwFtlA2k%EL8UOE1pDBSu-Me zi!I0GQ?u|x74UEDyv66~=*vEKxZH9I(hs#niv+a09Gtk`6z_n_4KFEMy2D0fH!A)BqVs*w+85xx#38ofVC{OQEx-d5Hd4zLqhF<|HHfAO0ECM&5N z{3C*|)nc4&&r3l?+(m(?CT}1w%XhhH5WwSjiLLR*x?AM|Ss5iN}LX>V~pl)7XmuZ2}p&!n`7;1kC zaKz^W)rLxtzV-L+OU;-tX?VctekA0^g?dJu=IOYG>&F`rp0J zQb(deT>0z`EDvhEt$^n+)7I%-sPN=AN3VcWm5q>3S2f>9DVM+QfjHK8CK(Cohv5O6 z-yJm>^gMYPm$04n)S+%*?1<3J9!@T=NDCKr2z7!G**)eqIo3k2#Z^tG21VxLidV7k zKGmCACM>y8htg0+-bSYM{jaC?n5vPup23}kc}u*lVYDXYI~GP)tzAam5tLTCVTl(+ zueDpO3J#9oZLhng7D*IJa3fulJ2DsU$mBjG3B?LM%D8mC&<=<>uOSuUq)b`K8qnZ^ zR9b53SoM4HR)`;4+@MG;IBhzd(W~pgI~lWFzfO`&6*j1|B&@imU0?bTqt~5qDt)U0 zDNF(vAfr+a{tev5J#n;C(_c`x< z!S8q}2L2K$Io!_g_eH_LfqKtt(Y!YA!Ak!s2dSLX3ER)pVKsTz_vsojsi;_V-`F@oSYPOpHfVup+uN%dntve>`9Gl0pRyllW(* zSetrMHr*I{btVD^fn?-a)_e=Fn7=d`l_@+6&+Kh~nMd--29$8(M7daoIVVKg_E(~W zsuFC(qpG0VY(i79Bo&a_M^xpJ*RLJ(0WLOy-)#`g49m~N-QNayh>JiTP$r2*#tKOG z6ENb%8N|_Sx(0hNftKi%cA;*iCU7)rz8{1y^A?6=-9Bo`5a*K7R;gq?(fe0;ozqxw zF!(KXt65>hQUT1(e+lqORywHzsX2)$ldtRHtqQwM1`va0$eFh{*7Vn<&n9*(C$Ug2 zm|+8_D76QJ4b3`mQiOX|zQ8V-fTF0&;?@q6CMI?1HqumNlskIS&qXsM0ugt^2I6!a zxt$v={Ex~JT#Yk5R+6IaFxSJw$emZ{m7=gHCv5MJn31dm=e4zo2W-;jUO+ySQ>?+9 zbSP?0#jYp`Hj2wOFou9uZ(`6^``AQ&8IzXAD{|R#DqM zr61@h3tkIh8dWnNZIe@cYZ50UUCw!NnIu8T`r;atBv!w)pB zq;xj#d;^;jw?9(MSjsc}#7)-jAsHyU5 zIHz`Nl*U>VZ+8QCESV^pkJ$5J$rS6WBchn_im;DtOZsNfjXr}8dFDjV4@xKG_T|LT zgR(dxH!qB$s4mrBq1h>UqOd1v;igO#?wrog!*LQq8@k6w4%axN-vvNbC~8-j_oTOO zh+}WhD0(-IR${s^PdR=Io3P$#iE~R!;e}%%M=)QmMT}2F43~~?N+T8IX%!TI2#T4! zW$B_rNKg7RNF3Da9lF=+;n6*W=X>B$aLz&9k+3vY8xZCUNNu&hGgekA z-K<5Q(_g=vJm>ZdBK5h)e7B!(B4Dg&=QDux(17}qZM%}h!}MVN&W~p*+1O+QgljRq zhAbf5XLab9AX}^W*cI(-L9<*&6k*|$;^B%-JgKqW%Q z@e0bWqo;q-T5F4D04Do+94^bPu?{EtH7Y{bqo)V6v;T#HWU$XS@hKq^u{15^SlX>;OCz`$vggrl7QFD znf2GCyM*O+43!*~-k2oB64m0NECfT{6BT5mV~wtv)8snlAIquAQ#wTOgiKoKe9}2W zfhZyu8>;`IdY0j!0%`Pv6%+z<6Zn#w-P4|bcF}lxuA33qbV1OM?w)@L=r!KSi*yP- z+hZrxLCveoq5b#Bf$F2j)q%Lao`%O=3wDl*O-;j|hv3(9_{{PYda@&ATIs>`oMVWA z87G<>?&m}KFX6W-B-9iaVubhC72|_|bD)k(T#Q#!A={E&f&%yAGmvBl9q=tQrg{+` z9MF1{+5{|QI2Q)OkAQ)xPLU^azcm#R8KNZwA13>G7bJWWu($K&;0pfda4&u;+@bf5 zEugb&VE5CkNxBZR}V zbccF`EJlLw4l}1LlYP~WIQp-OmVaQ|;hYS5i4R7`1d*|8CP? z9=Ow|bbFv!aGRIQ>;RNNKX4K8h#!;-UXb@KyDvh51FHdnSK(UA&GnTKs<5IRxv z_nATxze0ae4Fg5(rT-pCGcQ_(k|tos5XcWR5u><|P;XtzL}X+LyroNWu_cpTE+sJH z0G`a5jLpKoJ(6*~p4~nVjE>xdMKQCo^lBGv*6>KzXnuBOZ>I#Rh4~Lau<0Ul4xcsC_elqM>yx;vml!J){$wCb*`U>`VI zCaP?MTqTXzNR)yI-b#XlS*dSE+$m6o`TbKPWx<*ASmAFyE`r#xgyEpf&wwZpj@kY00^I6|@bqP?Ql z21Nxpip?knQeZ zdav!Ehcn88ff_BB8Zx)vxTSTw@Wv;us<`78i@fc56i1CVY$fUl+gQ>VXTvQw>tqX- zV1lDFd#yqvhYV09ogru=FwWTv^}xI;-I1Pti}7)^B%7j$>!sAUU`|Ny)$kpHvE6$Z zyCL^(B-sv&l5l7~nl7xtEg1G60UqXSt0|AVI2Bz3O~&@%IV%kMv<%4p6ahyCP)ytG zpj*#g#TJ<=^E5k&61W!ZA$rAR-{pyQP2tkPQNXSTTRsbg#A)KLf>SEnB@dyL?^ zvOkQ5K!>{&(raCT^g=6B`5WMg&H&!)eP0B>Tq|#Yv^(Ki)3L55#$I!TC^*=1v} z!q(B2l_kT!zXrA;E(at%$64|EZaR8Yt~UBFD3EqYELB2;@!;_XExY>@!4;rofJSf| zhtn>qHXQvg8h4FPqbM5on4s396=%|b+qjZ`K~pIs$kj6{1123Fh@#B3ump|k*~@;5 z(CLNuy7#D7O=H8*l1;2ltV->(AIo|43)${bH?ypW3Fv_VFdu;vFX@NRcfLkLtdEoW zzvDGp*V}P;rsmweixXzTE0sixgaBR|w0+)-HczBu=!EIo{{nz1cil=#O`lL1hwzAv zxb#a9n@?w4zLsng-vos>Mjc$&kZ+-q(EM22D3ZD~XV8}z8v98bUIx2P3-EY)NIlvd zkN?=$b5P)U?#)@a{ws|j9zCuQnbG)xZm5X~!0XwbiNO#p);To|<(3-&Q^6jvuSxbH zO#XL)+;=Q5Q`!ls$`|@HKG?I1Ws9z*CcO4YpH3%4#BXEqXPJlM8<=_dDPAw#C4GW+ z#1tE(G03f0+>NI8wE%RFWjTURIk_cVxNfdsB|1W%@-Qq9Mzq zyRBH1tFo3*{Tr*yNr+c#r} zNW5u?_rU-on>1L8QLh)(2UpXfJ$V_l4~O&l+azm(3qgq~Nc#CK%~R0V(N&TTcO~cL zai(V20JYL7D-m`VGFB^TOfjy+Jmu73P2E;61~^5fOcc&gBEDsSVgK_8nhI0Br-(-T z;c2V8kn98P0`mB_cGe>7(5WXV6=Q}G8Zwx29nHt>^vx^iW>_cydxE9abQZ6=GSd{LPGfKCY3B;8~8gJHhZh$4rF~Ypb8#ylM*&I)>`6 zWCXpCpRqFYg6#d)f81yw9OM!qxCVl?gsJ}-I?{?_g+r&#A6Zm}(7&pb@cY@HFecuN zSgn0tJRMIe*9W~ld`8{=aLS}sls}@*^dEVQ0G035rn4W6b`z}+D)qeL)QXjR*$v2p z9bk7?MwtA?FwUj(_;trNKNzXBBdm3khwGmA_wT4Dz82QJsM7dP=2{2u1(1>M z-E1_`6AC^x=sbNGet^3n`b8lI@AVO2)LQBbzO=XbXmrZ=O&f3bqQT>N2B?zN_ZNErGS=g#7dVJGbLrmF)C31f|OwDOUIBaLYutKj6c{iL}JK7nNm)=ylR2 zqf>A0gG{$US1;u_>K+z@4LxL%L8!U@(#0SO@2LK&mZ)Z^DDL))X)3$M0z90kvy(M@ zH4GsR3atd(7!#g9W+ajvr z;fKeL!6lXv#;mGX~fcOTdW5G_4k1jn2Ds_LJSD00TvBMouX43(IY+UV( z;VX4Z;&4uVO&V^r+Bd=?*9d zK3;U}@;4mNl?B)TSYV1DV>j{(Yw(X8ty|Lo+AhwQ5n1`EUCM9haXwgb8mETLHEmWC zzkFdUwK@~1@xOw4$~vtHIi~J?em% z!&EM*#_9N)m%3iOP3N}MkR3~V%M#uL*o-PZ)~=-F8nt$BcouKH%1r&&&F6gxIyssC zGbNRSc5r#T#)9|29A?b9zgH4?d{0_0+#B-qKe6%++`J`A4j#y{s;+6wbfZ}Ykx?o$ zGNw`uembA2mpbb4b<8RqSv9z7Ef8gmj5o^7YDH=Y(bF;)U7{G$S;g$WyM=avIB1cj zx@(^!jTN5fb>>Oa~O8_Q6SbJwfZi6vIw<`Sb==}tgSLDb_smCkVo%_yqz zER{A*Vm5x5i^ofC5mC~Lly~L3>Rkcp^Xzd!ftrgCNlS@Z>}C^mURXZ*5%XUK!a>r` za2A&o*KjoE?Y!KmAO)iqWrCGLukB`an)?E0-&Y4feMj-yJZM z^MGnqSxnW!fm=LTVf_apxI3o!)wj)fCI40b$d<>hW%9~lZ%hj0R~(nkRW-x_PCtEr zlxkX|?wFO!X@0C+?Q_l4(hoMQf^7)SzWTD4F5;{>%*RYz?JsHbLt;3$p#?H~(}Q_8 zi^xN*W)^UYBDxYhp_w8;<<9aM^sGL@N*t6CE7qw*&o??#HH5PN?^&8-(D(Xm5whbG z0aaJI+~~dQjR_@MIH0Zay%tS)(u+lJX0|vCk7SRHO@?bc+QR<5A;4eT(pbyeCftt> zlkejdeN!!OA$LppTSw>^w}`@|H7>KAT0$F1s|PiS*xfX$BjXg4Hbgn?$b91KMWrbmoVbbIr+BIFf9Kt)B zfv;$VfS4KHIoip{*V#~ONQ#Ux^{MZ2g>T%nxP7pj_@$?$1i}LA+JYeXAFL`Xj;cs;*uq8}z_-Fo14r`@a!_e)HcT(!ATVAD~0r z3W4zOh|ux+%$4t)dwqomM}1s)AJ_It06rR)u6i0Qdl?mk^5MboHU}ri56tcE?#bh0 zLFs{>-&!6Whw2~fA07r*kf*-@usS#XZ9`#k27UnI)T0H8CZ{LVNCZPc;o#*GM7D%* z1)-7y9?b{xDvU|WE(cA-5;S{4P;ByWFXCW#2CocqKS_5Nv`&nv=m{xLDeVZGy2Y${ zdg>$jenB?^8pq7i-0b4f(E*9Qk_BdleSif5^YKWWM;0`5fM5jI#$3+?zM28D7NiU8 ztZI*@7E~5f(vwQd21eCfULF|OIS*)$tg5P%`3F24incTiEC|OP_@}dK$BkOwiq zg*z}9Tk@9&Vf?PGtGhkBA-gr1ljZOh8)zDcqcElU`1bGbNF2y8>|F%*`116`&PxFR zh#Ce10|H-M+{42I+(p9z1Kfwg1so#hKUY;tlN)sFIbLYSSPSwIAi3)+2eSf+zRzUiYYKM{7Vsm14MTDo;Cq~! zdIZ!ep6*UB$V0+|l2{az6jRO8e@B3IhGQxH&JZjZSW%s_c#He+TkZVek^NgrZ;VhS zJ2$$yI{w{9VQzYQarLa>@Y8II;=^MhV}WrRAO--LrnL*~Tj%-B&nn#(VD>Tsvx0I` zWAo;kKUiOw+6?J58QVM9e@J+~^&B*IE>t@@0%>Sy0Lm1Up|-c6wsx?AF}{ZV?ea5D zFXZo7OEk-p%81b2C(JYj$-7laBdLV3P#=N|?jD0y6>! z#sd{bM1dXNy8hZuIWRpsFjc_y?!dpm1F?|cSQOTmVj(^O-(K4ufdkq(J3#z;e$~Gy zf-Oz}ncCUyf#`UyntQ)d^mZ2J2zx&nn8QZ_YQN1Os=v6Z*7H)$<&=f=qHh73$Aql*yr`ba(mbxfusl%1qa)KJ zs5!s}D7w3QAP0+Osaz2LFD-On(!lHv*b#`MquV`L<~q;7FFrX0PoUCU+nGTmO6oPj z0SIICx6l@l_q z{LNt)Y_j|bB8a)-OQ;aGDgY5DQ0W>0WV!qYBIv>D2gfNSaiI?hhq4Um4BxTIwe?4Z zl`=DFiU0voB596fOblQmKR1QErAf&^uL#`@$TBlA08_?H{@Hy*rd{%AK64|Q{R z2mCL?ulewcjJ^cA7cyfqe=&KK2rTS7^7(u{$T zU}?@b6e#uJ^uO!+_P*tpx`5>g05j7s3eq2r-|tNDA3G4@UkWOm3Q+WXcyz(8K3YNM zsXoHUo@E0>R@}=z!U~=MOqamPrguN@pEIGJzu%x)Lf`?)jUmSCLGs&uU^RtH?scuB zef5lweUwZg-X^~htdwQn2Kv*}g~E706+&FNv4ROzznJVekH3nFE(hUVZ4?;`Pd!|Nl1P;aZ_LM@O-o-dU^Ge-P5?C zR{>qQpXa)Vxn?BS*&mEweMu@@^vag6u)*?_n77slxFNtazFRz+Y2j zA`BMt&3ngTXAY^r;IJS%;4IXz7iVSO5C8ub>k;iEqD=PszTQ$*dEFdp7(1-@iO+qa z7?=d#1w%!I$y5VK%1hEB{>1m>`tLM5?q;^eG{i!FXUfU#ooB=;=AUr)Eb(HEmCj^{ zV|~`Ct*@O4@NE-dv^G!&qbAU;yEvHQJtx zNVZ4&dM?yh3%8&DUZ=hVOP5@3j(a46_3E$KbB7B!9U>e~>ahpVNEe6nUv5l;EO4#` zGG!jX-#^)2S{!i&*7(s@RIRDH!_jq4$Geb*?gBYv?P(fEN!u|X0M>?3=oed=#97hN zH7(mLCY)mu$LW?wPf#VICc^CKTy!>-2x*%&;-nT(sq*x8S5Q}v=waanU&)?EIJCNb zSYwnp*=b{|@l?z8c0DVw!o`YAN9IO>$5fXXS{PDmCs~-N(|Pf54#rAdwnlvkDQ<`wKw7NB0V7uYxA5I*sHrIL)F=!Gr0Y2Ark zUj%#j>Ueuu%-W9NaDN<<;Kap!EO9hkfu772nK2Q+eC-4W9WFgj!z2-k6mexrTGPV| zJmuY0Zp$voJacJX-zD7$tou*O7INSA(o56`51QT4UKb8Yy$hS1+@TNhj%VN*$J7%$ zC1x1gm_>(d#3*h&Kfto68=6KB`GcoG6FP&e7_!Q&wcKj8xXEW`YSPhIb9YXsHh%0( zMBjrD*$zkbh-IP=)rqn?Rf0^*g>-h|+1U40Kuea<+Wj|~Zt99FQ8z(t1I6Ewkbp&D z3Aa)FXsfbd4%~kuw1PWTxCV}eg|4^6Vf!Qh@R=@2@};8Pp9B0#>eig1S@eJ&~m%11egJX#Xyt%RZdL zac5Jfz)1W%D%K(F{OMT`6Lb$x#7_?sJ1a9$*(%H50<3ll!CBq6PT$+RTLa+&UeP(q zd-qpeiTR^XL2a50U^=W1P0+!Rqd+5+-@uG%EVPlSDHI;Xh9hA%th8zm5-5l>N;H^{ z_+;+R6Ui_VgmV5&Hym^vJ+>r?&9;ZdR$M(Eq2$( zLSVm|ki>=HCBI+dmfrc?_4780_w-Ck@X*CY?A_$3+lAS|>P5&KA@7cRe*ohY?fbL@ z-aT20qtWQw=se4>wrq1Ctpl0pMXx1LA{%*lv(#Yuw-zlc#R>E05N@pDko%{WD~AY= z;;LMDYUD<$%+ZvYmaJoNBQ9(03pZ7oYibJ7__T0>|5u+W-9 zZaIhCWwf#{B3IqO_OT~421>Ff(%Xg6_nw=KtVuk2QdY+ko=?&Cv>&Q`#u49**I5F_ zpk_CUUXyzlfEt4PMPsW{<%lBE9_dEGO!$*QgZ>691Gna6E@t5V1j>^-{v!LI=L5wZ z!Gk;5kpKsVURBNWnAu#}Ln77L)qUA6sHauyE-iI05ZE0PG3KQ;Lfx{r10e$1L7c?m zqWS3DQw+9HuyWa#Pq@mQ=m@##>L{Ml=3 zYfic!hSRRM62eOSWm>J4TVo@$ziR8P%VV{lLc<7++2TYIa2pmiEy&JoWDTcgorS@g z@Lc+2X|@unW84xv*bmO?n_W9zhYU( z-z^-r;#O+za1%t>bg5cba$a#NvGpxsK}WBXoV-5RXDSXP=m zmjznzaZ~}|pSWVw{ux=5WA7s;mOQH)1P_Ds(tU(D6fU$*Ntl9iSINx@JD(Dn5y|n|{(7+i4P&>IH5T|Tv!iy`{s^YwOpQbP7+ zh@8Y*&<@@BNlBvBc=$$J9;(Fap*1zArv4yIc$dcd;0kT_xV3Mt&C;HnWy}&Y*dhLV zwEnxEC%jMG70V7~dY-7;&+QJ{@<(HTtsm5qV}@!;9`tjo2J?T>vkQN9#f~Ina3SSt|H;B_*1)_$X6J6N9IBPT<^$wMMtbpF-~SJtPyC zs_?i13g`(@deczmz!KKjDGvG>Vu~cqPQjy;Vs8*bXVUn)3w(kYV;DWe@tbN=y4d)o zX^h*b2(^}U!c&^;4Y61%D*N=8P(!FNUOKBQ?lH1e3}R>nWK~S8KM>z=*7U+9tdEY1 z4W=O7Z_fJj(x+PW?}r)ln_>dizcCiQX%WFnQ$jY~ggc76m(3BSwoqwKEF?y_qm1z8 zkT{(AJnZ>p=wi6cPLmj0PlfAwkZ*eNV7gmB&zppwp=S|~T_X(}TJFjN#z&yTNS@9L z-K7RGBh#JV2hpM`d6`2qhva)yRpZ66ap00$in;)pEl1ve+OL{HS8{?6j}-qXrBa~g#)f5c+u@P(llWS_2&0i6Lmh}w z6V*TXtYU!4Ji;Ic5H(GoVK*~kk8GC`ktNVb)Vp{)>A#qjZTn5Vu%xo)_(NP@J}gQs zfCPQj$Y(n+5%7`QX?UhK|E+R@4^?%RT;T%ET>ucpj|6C~P#iQ2ywhK&d`vXZy_hJ9 zIQi{-J59j?!0cL}p3}9I<8ce|}6tuH8!rzU)2zLu^!`CA!gOM1v3@r1J`e z?Vxc7h3MAp$-vzzkW++y7fLGd`Hl%kxz+RWHHsUu`tI@wZX;b_rmo7Nn}-Ip7~q32 zYdMl*$CE+5)x&Kt=DJq;-%o#{Fw#rr^*RifC}_ZZA7qO*4$(B$Foi<5%Qfd_su9p( zhKdC3OhxW|yHB6^9W0mR48&+&tJ|i(_4ept%$rm0uxXIzIPlzsh5x*4e-D>G#}VUP zQiV>o9JD?F`L&aR&idUCaNHe8-`b9x-jOpkvr>l_Jl_t0@%{}Mts$!EE|U(Vn2>tt zG!nI>B_@5+g9B>2-$dt;;;djgYxY|t5&1f7eSG9w4<-ZO)Urj*DG~J^(n``EANl52 zVDBwENlRcehCDkXq4e`y%PfU7VglQf@v!rg^6as(jNm(=7!00iNa7Fx zs8IhdqhT1x^-kN^OyRQ){3-7r*+YT73V@@+l;vdq>mA(vBa`)%-QHZ=(UY+5*GN4!dnN0Gc$IuC4 zctcV6qBnHZnga=acr7N7n<0*lfZ*?!Y3>R!N(=j%-XH+F0gUP(HOz6c zcZ8UQ6HQT6D<$~bPlgaPcHqgcFkc!BDxdYF6|5f_YxuDBYuEiK{yyjYux9uopPygS z4uK-`GxK(mZrqt`IPg7HH5DGq)FFTCC8L|4*|t0vWr~_f5xl-OiEpJNDu>$wbt^jM z9-a0iVAI%FrYac4(-_=cdD10NnZqk$GhnEPeP}9>_GMJWt;TzKi`2PacZ=J{&vUqjXP>*%j6Op_DQ!Gb(=w1NvHEVSJ&PMZyChY4j{^i zc%bbaA4%lb40?2^ys94$Yhqoq|A(kD#3XB9hNb2e)^1AJMOl@R`tU8aZNn zuJk_Ozxii*Y~FHmOmX?d)w!o`!8=G~{173vxKdbIV;C+Kjug2UaCS)aB7}ExcOs-? zJBD^jnA~?(WK6@5#qHn!dTaDdZaIps;lv|^rGgrLV;A!cX`@A_$t8}_(|Z1w zZs>OV9p;q#IyPTu%$)<7XPYtHd5&BUSlV6%#x`vWAdnBB#=6o9WWd&!$f_Z>ipMe; z&)bcE*qJ-I`qRaGR+&3mdGF)c`d*fXtvohpMftAo2_xr37vW94CVB5{jHu-%)X-b}r&Ua;4V(D1i@LwfH((#CHF7(Xb0B7mH_8+uf zilcd~=sMBhYw>97y4~^XH*VuIvuXzRCS8oEIP&G&#n81m)IAM>ja59s?Pq}kuN69Y zUz}7Gyq5>N%OX$leUyFba*@>YEj0jt0fl5}TDWG>yX~;ud(_O^_3h=>{ghls{wMLT zJ^2(}fQJ>(z}-)TbDKOFRvttZ(;@9vZcI**4GpQ6I2fa<7ZsS0@OK2kyo$YV`&l!{ zQz&}uIQ*pV@}G@!t>3nY81B4?c9)S6VQ9tab1;98dxMr6|{|J;4?xV>Tj25Q9i-k+MkuGRTq(*)pImjxz#u8y|@!qgfHCzEx+ znx3F(*OPLb)Wdz#ws2-3p82?Zv^fgdvdvEFc!ve@9Q07rRsR#3 zq7MZGyxlo!7{^!p5wVdv5y)Xd{3*rMpc`+exDhup3Yg?%|S2&Y& zUWBxe(x%{(sbF35UWovKXPi)6sa|&tBXK(KZhkMtM1;M=_ZfR4_d(1}IKQWPzp^r; zV*BbUK7yBdiJId@3Z~5c(EUQrbN57(_pb?GvTI_6`tPX<9?8JDKEr2M)>O0Z0Qdkr zj}QgRn>t*_Mc}4&zUV<1%X-v8pvhR5w>X}oXx!(CeZz-#Yipo#dTKu+02INU;)EbmnD;M`(_-KkQZ=>kfLg^e}dqDY?ni)!bUe zo(w)Ixk*Y`GU_kme1Y9X*_*URZ^iBUULzI1_v~{DVIoku9I`}=Hors1HH$$~zbQLU zcrGP>BIZX}^nak>>zP?|^j?<~h5dr#KmZrmJ?CKoO6 z=xpW=i{D(eFyCjM)so0sp@Z5l3y$sHMzbY$69=AKxtg8?^-`iHCRf6E>w;X4Ryqk$ zk^Rt8TA<>_aOh8+b3InVZ$)z!Bw136ZsbNQ|Gi!s@X0PuIh+=+X0O_&Q~Kx09BB%n zRWN{vFSl9j&Ki7Vwmfy=f`%``%b_cFUhgl++n_~^#P7lGG~2CEF2&FFI=7{%d@1{s z=q3!7JWl5Kv}!)l>spoAeB#@4lw?aA3aPP9QX1W?q(C#tVP&pFN+zjL@Sbk5KfGR_ zn*65BDvq9y{0;?x#ud`YI(p|>?ZWyRu>f#-0db3iL z!R83tmFritPbfY%`#D3tSHxCJ#F!_~GtA=?582%r+`_JtK{30!FKv}; zz`T*A0MR=WE&qDf?$!!!01yK<89RK(u6%@KkX)WFvF=dC(z1EGM19WrdqU6YH?eKC zuY9)S*nv0mHW9|q^UF?^=9EA;5Y^C|8MwEUx*_t_=<1jD7Q&VxMfG2+Kx6}990$oq zqO$d^-fTC^PxaJGE`xf(ac6)E^_ zyk*k1qp~)N@PkiI!_?2KN+i1vnQPkQ`T65t5&rC!-3$S}qrH9uKhWzA=ne#fDSJHm zf1W)ZS0{^SwB?2}{BL>efK{B)DpT;Eu_kqJ^KCx9fOY=D9k+Di3GKz{Pm4f5Hzqx$ z&;e|R&6D^pMO8{#z9v^NfbG^M4mZR-(NKNGG>#G^o{YidLz7WJPUZQ6AKDx98 z5$VrDzt{ZxQ4?qj@$*j{ zC2YZ&2O`Tt5j``&x@6^)9j&utf%WZC z+z^}*!P9mbfFkegaq8(dAPD<^09rt$zb)zqw0PN9 zz?kv}WX}anm5K{StfI~gCa1@@WHD<}ZhT9-C+q8v^1uM0)sU9N45JNL+ zMkH9M*HoY&;`mFhk+a##4r;vq_PC5#E@c6Ad6r5L24IT0>olL`U5{_&ETd!J3 zh-HmAi=#GeW$UKtg$a5De*M5~U82EOW6yft-hxwY4;D#ExxvqFgGewLV8b_R( zWDjX+KaTCV+Q3fwtNWCGiEki$-`g<@n*s0lQp9mjO?t6h-$q!{ZbC*?t#faMTUkJ_ z%&)QrByAX=O%-CU2fWYj*UDHSMp6JokdLsg`RWTHrNtCZ*-A+@XadIj%DSIcj)^YX7x}eeXj*Z)U%EJ4%kNm8 zgzvq~STl%%Ux{+_3WYNolh(T(f&u$K2N(MH>NKo~Zq-T$`(%%=V-}rkE(^0oEW^L? z-5AAUq(Mzu$DNzCyu887pKIBR!2wo$e`s#|<3$5I0M}+MRnb?KI95G{aG$lLs}#nu zq`F-Uk0%h@+BLq$$*xN%uVfbh?zR}COqv6CVY`Lw9UnSj`~7|K!|}Em^iGPaYobpq zVW`?*T$RDm#R@iDns3-X1*Vw~nO99&rP$kaIwq7>FONdEq|O`Ws_l0&->}Z0ad}8# zIdR9DQ+#Su)0GR=tzc?5a+$)1d7#c+!~o-Vg>C=lMH8+uSlfNnJ{E>sbPtQ5da8mN zNxomwui?)4FT;^Dl;v z%s;dGrdLH&iwjvuAZf8!m`n3DQ`=RMN~&0waqN>a*txX<3p@PD*FI_7OG;}fR1*6* zrdKzl*m**jR&KSrh%t0h)}d>&&xHo{Peus^jLW~iURCR_i@72^G)yBx!LIERJ_R3k zz$^Fwyxt?w?+O`G6jHv$@%tk|=J}|w_KpnEPx9eLck<2uaASQnP1-eZ-}8|yAq4t! zVzFu%eoB)32q?5BMNwz*V}F*dc&x^}k*f&m?P7a!pMn9>&gFp7Y1FTZ@E$IER+K=F z1*Bnhii#9L`oQd2MDFm8j3TXO9{f_tY|zpI=AzV+oGJMLEDy)Nr{wzWkEYCN8#}qo zy|c?*`(=v@>_ zchT>198YNuo!UEZZ0g_6OFKUK(!Sq>z&+ZHl$l0!@EWF9D2VfA@kfzE^Jgo^HbT+& zck6{T<$NyG_L{f0@}0Oh>>Dl#{I(F9+kHttb zIq`K&w*@r~`Mb$A{54j$XVr9>f&6vt!?G|3N*m=;5%uQ%x8B&-2#-cQ-pKiUoK#8T z;f_go<|8K5U!@USo0URpN7=!^4=oJ@ z=eD}Vt3G4gFCznt>`fYVjT`slAv&?K=U-C6u&nEv!J1~`S4rrsFS6s#C#ryvxQ1x6CU=X2}qGz=BA@ zWS^)k!)Kl)BdB!pVsi+XG&P|~j(=;VkC`L&flSn$SWu1}Hr>LC?|N!XJx#suY^RDT zCtevAOlo8UI~RVs(G6e4{I!Rj$Z5*DAg8xjLIV zJ)0ET64}W_i&Ge#8s@xU1*``JCcyasr9CYmjB;Y0H^CyhdN8qWSJ_JeFaIjz@{E(c zVPa;`OKI(gT-ggtnWG6f6Yg#7wu4dF*!RP0JYpd(L_47`!JvwQ?+rB4b{1WN(=JU=&{p$UKk}Ys=e8Wq7GmncXKW;RC>C_yJjl zXy%aSZ^K99j5<0X(-8FG4C_Qc0~~&}qmpXIez``DO~fAoN6E&-?O;T$frbrJsP_7SUxa14OCBSU@bm)eLgc1Bo%`tviKk=` zq<^iI*6O4YHc^w^S&i(?r=>&3lPgS>5;-tGA_T=mo(s`xNU=S(HY#k}d{X7#AUx&$ zvI*cH7}O=UKpp~Oy?t&7@$@NW03MdehIkYLyY0_5BtDk@(YU8q`PCbQA z$oEL}LfG%3j5eYPIS;BJvX9!%?HF(#?;}ohwaQ7q4tLWKVXA0k&UJ%uSC_Woe;C+ttB%uzL z@v|XCWj|oRty0@L9e=w0L2{GfYc^fHW>_3exluvS_>s!~?nQ+0V5$L3P z)Qa52@A1I$O$XjahT(~EU0gqjt;@=aWwW_pc{@Cl#k`0#Tprh2lXyAw)1YE#lsb{d zc=W-fak8m>xtR5v*Q%ug@}{%YPg)<;vcg!YSgY*I=fk3Ki|8xduUEBGmxm|1A`C|I z3|DP-zZNERqnIVkian*P&$oS&=KI=uj z4l9$Z5q@}OFUC%djXA z%7s+>Z zY6}f~h+OduR^Ey5NzWl?RD#epTUSxBX5bXwLnRG#u&<`Ob*ZGg<)|Y>jQ@Z9HOzen z7Zb)SW~am3UK)L&E8I)Uo19iJ0z-q$hXp@ziQ!H?mXbz7g2n5(cxGDRSiRQaE5GF7 z9?gA;6up~m`}%5Qr7Xj0uMo{lq=c5SW3*9N8{KtXLbX1655#D;H^U zvLXc%eYIl2l;z5}L0JM#X+{H-zWa#e%|1PcoLHujLm_^c;i2JLc&zPx@Ot11joqcSXcgzi= zELNf&RZ);83*(QQ4C{~P5UQBfo`pe#QUQ!ghXeedv3roozA?!GB;Evtl1J?@S{y>Q zjW&7YEsW1k^8*qBA_kl#E_#_ACe;o04$SU54}FzHmNICGwVL0sY?QpE%WfZK90w(W zFI&4>35&r@zn^&5jht@e|vZ3TNuqGgUWuhIl9232N`-C$Hp&1`^mLu(G$O9A$ksUolt#t`5Jj zv>B6%V?FPj$|zZ*3sK!*Xezi3B#vqw%-J4eb|0Owqeaa5omh8YRZN@4MQ|t}5#Q`c zvWw*>j@GVcAVG)T z34}YnEVZ~Osu}*s=~z9Xcc}u*)}=vC61R*H@#Y+H34irgG_md-?E|2qEU(~rNg+{` zjg2CGZ@8j}ieSFt#`UJb-YDVrno+>{fBbI|gOZ9w$6a4+NWfRzFB9q44@v|Rme0TF zT&M;#?%A@)QcP!N-MdxX`KYK}4KSk4(7V|oGNSV69J3&}@60-lU6pZE#Vfp9HT7Qo zrQ{qP6~}>$1u<)5o#dxk%vEX&Y2s-Y>Tul$_AKSFEzt{%iCrc7sO(fI}(v7Z%+sKd=6_kF!gI?B4r{BRUerCq#$M4Sx03#hyMoNzT2p?H8AHPbz=LvtX50RR|_hCbQ?(;8PoMcKCdZ zN)7f!-pAoj38JI$pVHQ0k;P~DbYxwZm<=f=qtiCFOHm_xSydULp<{cc9%7)KYHEZ5 znRou9jpZv)2OeEj!pM~fW*)Ng!5LR`*Gn0&WJ7fBnyrhbw^f-_43j|s7;YVXkAd_- z4jX)N!TC|Ul-@6Tdn<70hd*3pHgl?Uez;+E_gbiT^Pa?zl_zSpN+r1koeEG`t!y0ED~AbNxYyHPCFz6jvv2tTvE zKB@4{`(P6cIAh9YsiHz$DYVYl!h%KS=G;m7=#o0)3Gf9Ef1s|CRklglXfT^6Ha?K%w4Kv;*@8yNs<-qvf1WK6e=@_-%s6!W3n(K zvKb#9{z%Wh#p|iKAV(=9pG6^hbo`!}E@&ruBy(M|-u;T)dkh@{$?-k>9upZqUkpVv zVs>FV2RIDvzW9Ge+~kkTBi;tTlVJ`c31idnJuuGsaeHH88c? z(AU>kv2V@Uv`%*K!;5Ph!f}IFnY4Drmrx6-P#IL)M1=QysktSmyn0#V%3MdClA!vD$dp~heGF*8Wxw09aeL|D~4a^I_+qqv*}JigyNXJdh&?;zsqVw-5W zowdmhM0+`r9ke zw5$KsmU?vIZi}!aBh&z}Go?RkjJ#v1oe9?`UcQq+O84`}hX1pZEO>&5oHzF}g6`9F zskb~`ZOw;gg(7rj)RfI^gVv+({Wo)Pi+zbsob!vNrCVu66nZ5{oy9q5S`Kg2#Tz>syJokL#2XUT5>> zC1p2#vRDbKSfzQrnP-afSY2AytdYYOprC)K>7iSG3U7?mDLT3R+No9E{?bNjoRo$$NqAmT$$G z@7pHfa=Xt-XMZ}_j6#Vc_hEHeaa^0p@E?fUGzX_@FUB}=yOkhLuYOV4Bz=JkGprYD zw({S44sMK#ePxay2>n5_2*Xs~v4TQ(!_yNv%whV)JxJU*ci-;AQ>?V9l^k!+N6rta zO?FhnL2(m`Hn*ZXhd2DquH)8Tdj^q3RvSA_2A-~4SOI@2}TWgxORZicX$QGLfC*_9~sb*onL6PLp=3+h~ zqXwi8!NlndF2`YjX`3G@W)_>rzjGm^c(294tFLwYv=v1eeQWYO90mRqx`#}2`}}+y zf>D|8S|gfMb?u`x?_Lvu6F?oC-H-#7n4*~j-wrEb`!hc}wHWOanArKxw`(BDp#F05w1(dbesaO%KIu50%vdx-l9B@ZMG(Di-gwW}b;Bhfrz zxfCcRIKhjRWLHQsZ(PJwFfV9|5FiGASjshioY`zXQJzGyJWb0>{e{HXCwCpVnTAHo zNFs-u9)hAoifQRScEW$*29e#sYb0=-EwC55Z?co=6?!l8nI2^xCi!It?D~hwp=k4W zV%HDfM%3%LQd8GIu46%(A_X!HBrAI(vPk@FJ}ksL)F!a+2-gq||2R!bstm{8+?%*B zVqf5EEx=B;pTnP=M#r#D0{dyra#2syk?qy|im+QH)K2Wyx^+k)O3XeW!aol|Q>xl=4z3p#;GXBcf_W1XTRyLUDc zH4K-`Z-!Icav(A+L~Brhm#UpA^Jf@x$VPcV&~Y5 zaRxzT&#N<f+9&u$?1^&Je$T6gzr3ckp}~%|Z-vJ}(1meX9{5@mXexn*0PV6un|~&S zAcE0-PDL@r0PVd`lmo2O&}#OD#b-8M9Hi!su_=IYAz5EiUyS~$T`vf()m|~g#EeMA zlvw4(1L=fOwZfEztoVGKPW+%SSu2NAI5JIlgYSf^TDOUN@B?ui5!F;NTq+bhQbD41 zuu;D+ttL6!6Q15^p4E729Pj0*Vp7#nw_$pw;v-{_>74^a4k!85bv9-(Z*FHz$Z>WM zZ<_x4p^BCQ9SeFJ#FtG)n8+}OSpQ>IH8!5Llh-K;YOCT30vhOvj2)y=H1t|u)!C?T z-|}zLImmiTv{eTalrSQA3nyrx_;kYNz{3Up(IA(keTUSGsv9)rP)my`*3kwvDXP z^8^GCX;}yr%6oIrv`Cit3k@7r9?)d4r0SyY)ID#7xUc3I+gn*aZVyehnP;_jN~g^S zWfeJU=Jpb(7Ypi}T!|Wv=SCi+^x0HQuhY*Z@YoH9M=t_<}P)e!S*}QZ%*SO?}o20og1H955W4ge4~JS)8JP6?%h7m zHM0gAR!yD?Rnrh(RQS0zZt$AcBey$kyr?;sZrw!ix2(_C8#UAu26oXhjDxmOz4Ty@ zSMxW;Do}yTNu?8bNh?mNhnQIz(wcXRH({%xtQ1LGP2NY@|WrAMF#LNu!NMMBgM z(%j#FTE&Mq2m*5Zmr}jhmP~!i%<}5GwzV_8Ww+NGhO2=0E1cE;;7`@G{3)HEwKH$8 zsF7dYf?4|W-u3Ka!rL>BKsnP}-_RYrwLhPj^cvUc{d>x}*3XP4S&Db+wKK^EUx{(W ziD{TwJLGf8p~csxaBF3t^uJg{6G^LXDL)TF$cZPb+`rGdisjvq*GDca52h7@zh%Kd z-MU!%m|nNOD?1V7wtb(|@3YD)x-7jFo9wph=!LQn_3cpK0Nj!J46duj_g3dLbcXLB zFcNOb#rGTQi0x(Hx0BvPvm>!+$@GHld~+27c-4!Hrbr##9ZLJ3%LhX`%?3FSg0ZIv^FhnG$E&rRdBl3N zQ_4-E`X#eGzV9CbY$>tK`=E|=;7rnnjVpgnI5x%$rsbYVbPxUDYkIt+1O6<3a7-RE zLzC#t@Hyk-3DFOr-i_99&u`O`4;~_p8jC!0b2AH#>4G{0z$6xlMCp`CF|#nC2jgh! z!}6uc8_QOYdkvuP{Yu3!+0*fA9Ko-0Snep=6M&fpY-kAxtO8s%|CPMMgKk)Mn-_UHR_BEtIJ$0{s9)3)yYMGs-# z$EU;kbEEV)s+uX+2(22U%J^)0K1(H$U0nNb4eWT zgF0XsRfU-|EY&*MrO^Z{+m)L+r%wBxG!fLQ#gj3vvsHq=sgF z2ChNASJ+E}uFRT*y)%*vRP#|&pCFrtLb}z^K4Hs6t(UWT()`fmRU<6MNJwO1i7k{= zvTE-ekUk|26Oa?J-PS^reAMY#j9pkpx|+=q*weJ^#TDtvE~3^b3DeIL_s0`~FD6{l zm(12ozB0qlf<`1Sc_J!+&g#7`B(wV=Fo<@31S=HzoJ_8x1_Wcb>1RA_z^OnG#`Ki? zl`94{=`9iWw4*IgK~INI#Jl$pR9*q?bmud$YbLv|`1}R3cJNtUSN@X#86;A#TS7%O zxTq$wK^^IdU$yQEOZCDNhfl?*h69vCUH?QUu5Huc0P9XesYkyjE}X4tr`HfzeA>5- zaz>Oxnjv$SUJ?0Ke{P(`IvZ>*_tVDHHuT(=+H)vgnK`FAUfcS)xr#@kRrwHOwg3Y` zO6E!_O>~LqK>ChQAz5X}k~H^axLHLie?h7Vp&nuR7c*`aGEd&Q`k-E3G!kcgac#o2 z^vMc6nP0+5sFQ6LEx@a7DcEv()NqA2fwP4X`EO1;4{8nE}# z#bC?qx_C*{Y7(R*1A>s8vbG$p`Q|Ildsa(JJ=w8suTO_+_6fuBxxX3Omp{Gc!=Ftk zJ%3elma+e;-xiYODWwo82M(l4X7x*1HMSUbY=fL+VH2OPnUdNF;b)gWD)wK?lf*+D z-Ah@K#db98p!MJpnlTDXGq{6D#`*02DNRB0eYW>`qDC(rbm$SY_YW5xux5`tL#jiF zXGK?e=(#~UJaH^MUv>P;+D#O)fkIY*e452UWJ`=#F*yOND8!@GXW7R@Q=FA z=_D1S{Be{#^RXD3k~x-2y9ZKtw@74dKT~C}Nfv}tR%PnT4`T|}Gp*9L^i63PXNGkS zN*5bLAAUMa)RA5|cZB^AnHoAlt$`krj&V)pS~nX!ZtL1$TUK3AWTJ6;-;NXJEf8Rz=6*C=p8TO(etsa z+Tj0d0oHWqdG3Hx)l#>d!gC zl{oo}H*ru`=g3bSD;!P$2igV%@p>}1c0 zt0;F((?{X38Hd_-mnD+|Y5zuEv07Oy>_?ueyY-k&RB|t@1v>3jEk;Hd%o7Q_iv6do zU4B1C@q10wmPglvy%;sj2Fx9~DOlCjI2?iq!V-`D>HY>vRCA^ zFKsxqiLR%I#E7CvL%I5HI)-4Y1>%J0(Qgr=n}uJrW8cQ}uqta!NI5@+_`{%g zL)1G%)`!~X8I@gD8DHzOTv* zwQ~4jVzNFX(;$(H`u&paDL#L4Wc|xyY4`g!gS9T+>E(NrhWszkfpknwx5fE|f{3R& zr{-_an=J~l82Xd_mKwj6G62MmJB0|0UElDl0};Qiy@nUot>43eKM<8z9lRG?g~v3k z6Oxtzq+9Ez)*Cw5JQldZ)!)m$yC^%>tbflO&sN}_HjgWkzH5LjfJ4|IO)Y~l>o)x= zW2D+g|EM-ef_}1%NFe-*;^NpLv2<$@{=kvc`yX=icxI*P_zK6j#;~~JQ1ZStb>-oi zhgap30UAr23<*O8VE^Y}amYeXB7c7|P=-~pB|KU1Py{K4@e=-Za-p%LeH@xbJR*RA zC!jsyWOX`;bTq;9XPw~Ju5)@xp`;1}buPC>rNaOFjk{^L6Lc_yr{rj{j~F@#l~m0# z$tT-eQ9VK&qFuDqh%9r-`dVx~g=N8hV;Ysg6B=6~rHAxDU%b_@<985U1DKkMV!WG9 z?^6La`&PKA<9C68_q__v@t=Ik6!333f*Y=e@^o!F26B@HAmAZGcmSze<_&TvOpE2Ndg$H0$kHdb1se5+N7y7?bp4Tdq=WL8+DtJrU~SI8^>SO zQc0LdZ2HvWihq{>th1%WZcBMt&K_cV59#r5ff-q1)y709Hsrn|S>VLRb^up$|7#mn zfnlVq0b?+VZtB+|KZ@X=`CE}q)uQ}8|`#5457Im zYq(NV@ZrtnH)Vg-v8|WUZmks&wmSMJSjd8grjKGt3Sbx?S*7(L-XUG4vnAt%7?Fmb zW`m*C{fE|}ea-ivg?{k8Fsdr9kp#w?Udo#HE^y+~WK*OMM@ulyZnU22ZkkOQjCi(* zq0e5>1Q!+;a~;Qka^XKO7s3f&4sZi)W^cva{vnUOp-nUV;n4_zA;xwq*_rQKGSl~% zN)0K43hIx)xViGNYMQ~N(k^)2+sbm|gRj63RE505nwLSJ{mNn8lxZ01|6AU)uwjMB z#m1U@8AQ8Y>>{_Mz)m&|m??Iv$Ia3~A~QSYO2QC?BMmDtbb~;>?h#u;?~lh5Pl?N>!&^HO6jvN}*CHO~oG@-Wn$q#LT$r0hC@^ z-sAj<-5vOII!Ek0i@V+O-K)$@WLOb@r9^++1Vt{QP<%wk^uiUVIdap^#gnbyg^yar zLg+p2jR&qJ-I*wQr8>X3NYl0jqi+Cb=w)x1T=+r8WDIwIVR}%e30q1evW4G1{Z1eh`lr zS{-a0#nToIO4{s66{%EwUDKno(yRVKIZ;l-J36)g0(=?yY^`bxp%(Pce>F|8GPhgy zh!xMu%YaWMegr90dQ0vv#XpTCTyVtI%P0G*O_4}`G&(;>=yr67AV7WmRIU%hIIJHy@;MKT@i8Q8$OYxl&NG=JvxCkWOe zEAKgr4EpDMKw$CHuK2{fj1nFL24!cl^fN0=#ef<|E5ZSP4SxGvf|;-U$fZPUgO^9u z&aJvme)BbUzsC^yX4CLfF?Fk50X37nQs#j?9wR!zP4OLd!@1GO6ae@JA|SWj?~lrO z{ZTrboQ{&kI$a|%_K^!YeDC;aCmaPkCNJx+?i+7+NHa>T zX<*3tsnNBj`=0~ser3K>!J(=5w{Dq#(ff5K5OsDM53!bJ4<>d`<|1s9 zJ61M>1_NG{_h@jOhRMc6Q2kuLa-Lq^=Zt%Bl4w;ex0cFR?2;^tvjp#kDE`Tx)3G=3 z+{4k9ObFGyzbLrX<`n~>2x7$z(b+OsxeX_Nx@MKRKJ7&&bB55Fl6dlwG%Ok*z|b~x zA2GxU>^%Su+zV$qy*gV`!Y*%y=aue{C4MytTb*(c(;%mrPJyf94Y?QE8P9A7RuKLW zPyEs|XK6a$uGeCDzj__+{kv32^LS7PQo9Xt3GAHs7?1KZ*tfmoj|*1p z6eIKYThJSW@Ya%wC-|2Y-hHM}Co&5?&FuhkeN%ooAPlxp;2Y>h#k5l)+P?EwvV*XFJkgfqoHsaZpK zMT_O7r|pk0IL2!=z&}0pWHFNicb%4OM{C+avyCZDLi&)73nm5=QPdS-@i-gp4nUhbg)!lBl4>uV+^L3_se}F_!!?YiDzc&=isL7 z#;ZyoFg_-33#|YbXhIq5BKhK z4O4VvM{Xg-qddjn)$7BS#D{FVK*YB1^q7y5KLAa;rIuq84uP|mqjSunN_AImfvfs^CCC5OKB*QGTi zsj}M!CF7f8sCH^)rvFacM^m^C%|S#dm*^@;KXY-YlP;j~8oox(B0P7crabU@#0N?~ z8+Lj+EqFW86TC~8SUAD1BN}MtqT99u-oN7SkRP5Qp};|I%&G{M(^}x&6x2?5R%Z@J zPy1>6d2BMNCgd?49v1iE``h+Fb%$cGIa2j6#bcQiYi8ieiGFhD**)bP!vy4ZJWv-c zo@!K|xiH=#gg zi2lZ!?ec13OMv9Gm#{5)!Q+TdNW{_Drkm^5;j;%An4N^(JFZN`9*g^q6fyDTMlLwd zfGpkEh0dhq)SrS1_Xs2#jY}w^EN|`hNZBp7v1i%l8-Sn@7iT6hY)~Cn!36n1aAE3j zonvx=svxSrs556VJgy+ddp^b&d?8&hPo;NEMi4Mg*XHvy@`ZgXzg}qfsd9U@a**?C z&bH)FkiPrLUA6*9)z$$~1F6AVf8gA6Y%NAi->ZFocWw)UDFzRg{)@)Jt4Ao~$hc!E zWtwuOaEeNidO?xHqA+ipBXgkF2x3?bWuJt|(dnG;ss&tg>28K?ZL$Gc4U{gn9*R^y zrydyGI|-;&8q!b0e*{klq=mtRO~EDpDvMvYGy$1ZO%kdMiv-q527!r1lGb0gk4JDj zKX)<_ZIDRrluO3sGogbYa2XW=dab4Q4`flf@K8nAqe^#}_B4{BH7i`V)^OZjXIE~t zgzg}Q;cEFrA8Iuu!wnq3SjFMJJ1kF0PcW@RN~!z?8P>>^PlhF7=~Yt0d$G6 zA5#_*DUX1#I$QR5VnEH$;X5wVuR79FTf=D5u8@S)kQs+I@4QVr$Qq=1aRQm15!;~- z;gBwj=RxE-RH(bl>lwQL)ZIrve=Z?(UUd#s!Vx~CpUNB%NQBfSFgA{k8IFDxf!bg8 z`Q+aNz7JR(xw6Atsh*@5k{=(zmKmlB?)4--I8|oZi{jM~$G|iGI64m+Fp%iMxT@#) zCy(e8?0>7Sc4I3CyRt5MHPIxNS-bq6m2Av*?j)7Us`sl^JmNj<7I-^o0h-Rpo;Y}L zs^fJNJZC&AHG0`OT%2J}VCFF4jB^CNx2Ww=i!J_IAu=^d#KAcS*TlFmQp2tA zU<}6_YGvhWY9^!DiQ=)06b+?dA>zsGCbZh_bIHWUpsj#_CDO6UkcQUx?R_oQq$rhUbEt0yijXB`#sBRC!|xDDxxTw)ELf(zv>RPH@~1G z-w;M6U}@l><6Q)8_IJ$l6bL46MAasusqbO%s2ps(s`$!8ogTpZ!O1QU&NmS*+A3cI zGG!iv-jG}HU-gx-gPA_Q9c~Hbnn$&0ZXy|iUNs%B=--UMr+u5v19hMhx@Gvou*1FD zvyI*x0?3Ci4I%zs)v>>Q1UK>#D-l%;_TsruVU)1>_Q-Pd5A=Wz|B4SszJ+1MMq1XxVDR?WiL`4j@hXbj8N{5bEQS191CIF_eEs#BDl=UL>t=`nHZOCB^#ZAOqNO_#FuoupM^LNLeOd%RL>kws03-27) zBd5aIM9R~B>pvhp6hF{LU!Xnwwj;0`aMcGH!mj}N6E(T(Lcr`>)_34_flR22i_~8v z@j8)K0vW2tS?x3c%~V}(L`NrbKBnw0KzRc=U@V&EH`+4zkRO2a|cG?V;53=uM^M$8Etj5}HD@;F*TcutxsEGD&c zmrF89AUP>a_3_jSm7Tb*$jx8Uo6_=F+@hM{Gqs#E-)q>PRmV6Y^(IYLZ_}nI6^r^+ z7|4Vq$?JWz4J4mM!H2};MfP9$;R*!A_+~c$&%Ri;%A?|n>sz1tp$cQFVVu*vOSEe5 zY8XhNm^5;M*`SlE7yHGH5Ml<~XK*J;D9D zN2aT`UXn?&v#0tLuZPyd7`mH4qwNGC>591i?jli}b!0-nd-`#AIp?(NiK%d^1YU zC#BF||alrM$oU0>C|!T>zbJf7oF_j%Sx0&Bx9T$+C(fq>`i3fib{19agy0`FP!a3K$$naNTkU76jU zcaaIrs71qqj`Fb>#m z#9UxsAyF@fxFIFEQfnf*#KB3BLkdkc0?k?zWWXf;TN>&+Kt4ohA# zT4&v)PHs##h^4Qkdw1@7vm!T{PW4gxHA_4qCG6zYxxx$cbPN5!VJCiW`7Quzmb?4R z(~}{|6F?O+?x#R+Z1`aK0O>8cf7XA&QDbfjAE9(zCmQHmBs2xVs~rOYA^1{^v4c{B zWn#GNab_9uUwS(Z=gYLQP;l~<;kU*a^>7GQ@gst{C|MfX;V|J4 zdh0qZ?r~qp@#BCtUu*|aSsO)l^<-yc3KAxe9q>WrXNTJu_*0w?inQ(~8!=6B0+U8w z?NXqH;A&b0SQlDnSrl#Fdfm*b$!hWa4T#Molhtf0nh3J!m5$uaX#Ci|j42&*crOD5 z(-t>~R48AktSYav>uYODU5X533$SBk(ISBm6DD0}(E=~uI`8mz5C9sWTZz80eeFpe z@_$|7f9MGi{0wk?`rqiwkSVaaTG;y#__A)nwxm44&7{Uhqxp3dM3wObdpN|j2W_eZ ztBWA96TbP;{ah3wUcXV9GmM$N5q#5!9(Sz`W13xr*(J{omN{V_JIV60n}{bA7~hO5 zplUPrRC7vysZsq%^Y7e^>hvD2Gb(j*`v~Eyq=M!}SO!)5ruJPw+1E^ZbKWP}Qh88o zKxyB0_X&Umz3vPWmx7q+`XNjbWB0WV^)4FdQxs>e)g_%ECBQg}d8k^5HYl%db#HcI zUB-XCCvdvogN2Ue6man`HLx;Kgqc?bLuz@@8g*ALRs}~Y{13?%y!rf z`Q4aUKmqNM^nQ(+Ij!7qXFsi;3{{@41r%cw?JpvGbQde zcdLak1vVr1D`bj#B^}5iM;45?SB%2#upR!-dA|Ho@_|N4Om9(s@(q4-mTdzq3qn{c&v`Xo>pY0hDtk;qV?7%xpNHG6*S@LxU*LtP?k3)U16RYYdLO(#<& z0lSzk5{hI8J7Mh!O`P5Nec+I@Lzx&b z2`S){9RJL@#0-8-21f)ICjf&d!X@~MLe8Te4Nwqte)3Y=ndP%PCuMR2YnHa`Awo37 z)8E{aww_jaGcOaa?vh!ki;~^Fin-Ky@_0FI{a(=F=t-8e3EhV*s>?dhF88M*@`0z% z480tl;)aPDH|#X#j#t7kW1~T22;sJDlfldsg>z3t*m7_uz2Kt5+(?ScK=>517C=Rr z)R$SD9p*+&uv==SUeb}_o8Le_NEi_aC+jLa%)qq5E{6Q$Uwp7Gb|d8_>fDHe zANQ~9Q{K4CYbAiZpvq$a)we@<#`R~b1WG4Mjkv+ndBi~faU1NdTuUmd%BTxQ-j9VD zi^#T!S!@xu%NVV1mb-oFf82#J4DqW1qyP#b(4ufCWx9)MU{TcHb6f8yloSXOtMTaC ztqB6$rcRsz zzwH{S#`d4b!CYk0p<7rx{_>^$Q}+Ilu-LhcrN^)>6dg^ebNGRYZarTpg=SumRFrf@ zeJ7EWT=2pf^+$Zn#UgCMKP6LnDRy#-WU+n4Se+$FesaCdhJ z?!nz5xD(tRf?IG2?t$R$?(XjH@`{{ux=(kf$G`i%?swn4uQO5$YS*e=dsK~&Z_eMG ztJaTxSA=fqyv#Wq3MnRqSDUsJn7R#Yo-)$ zWmEg@V(fk3se=}uxR)i!m=B&JrB>Tynn{E23oefqTq=gVqw3NIyt8TBxsn^!{tPhI zHNLH3_ga*u6-E0I>atw9wDYc8esXvjT%i+ z@TlIE=V|GEMrx>1c@e=CjtNSItMM>kkvE$tvHn0}*v$drf!CNXhxp-5fafKAh{d%8Z$MnlnZ#Y0sQk_=Rj=}V>GKPXTZ|@-E&^XVLyMWviDFP7!*gyC5pTB*_FJua$i^v zSe-}B&R2Dq^>&m##!eX7R&P<=p6*hxD-&~@7`gB2wC4lh2CRF#-d8KGTH@e_EI6u-|Px-_JR+! zEeYOeo9RQGhKWzKQ1`_TP4ix5fKE3uoo~#fX|~ke6t#li1#la(=|>tARR{LjVr&)E zq0}G})QX-3i>9SUqHeX`;>QW+Od`9v99cl`^7|k(E4Yp2vWlsP5-S3 zsYPlfruAjpMWKiZA?0ij3+ym>?0gVov5mg)dj3Ie)u( zCK1K3sJh+SQeXp1q7Te^xA^;r#DK$`92k=DeJzu2wytV*boK66zk z4?h8Jo1xhD{YUz=XP~Hvc(Pj!0kI#Jhz;0?Cu|5iHc&~Y%YC#noDKUTVuku<< zPN85T_|zkpXx&Af$!PmZ7R3l-woSJg-ME#W`DoGhEzaZ{sVwM-?@84nkD5h!AxsJ0 z3TK}VK2RI~kEiz%mxW8J{?s#fsU!VP$KOQx;p{x}0#qv)!O$pPo z(4zsj^V0aolMjmK?^6-V6fCuSBqei-zp(Kj!|$z&^ixr@$Ig9fyK2*qT(vIq#k5XJ z)Dc77NT(~u*uSGv3++G?hYORP9B2NZN%Z_314|>V`qg~O&m7ntHGbpv)M=C?NV{oI z#$nuM-=j&H4RkE1!K^*0*KBu3G_7(GtR}#$Y*ym@W+kFok!>Lp0#~QQrrQL9@fikn=7#MyFb?AJF_=FMd>o^KC01~Gh;zsp+ad{PB)S? zM^U)drame{n8K-;A=ePSoV(OZMwzIm*C=A1Z#mE%igDEEOp_6>Wp;g3JityKAl3XV zQ=DYXH#nYR3?>9O^rI7GuE)xh^;te(S^-~nNh*O}tI~E-1cIBzObrj%>JCuZAXjjl z$Ko6%28&!_7)V8{z&fDFu^hQ^aYz7{))bj6pohT(gh>Lwu~FbGH#|8oH5FaKiJ-eP<;mSOp&A9 zw9BlXN|jJ02vEf&W%v;lwAmK9Om50Jx0)vZd@NPc_k^%7L>|$-t3Ds&Nb5yRDEZ?l z7v5<9tkzE7$onHPcGd~Rf(S|sg;b^x4C-Y7`cy>Qd!#!y!XZw{R{GL4P8 z+(rmsC`eUOU$}Pea}_YIS91|^3-X?ysS&428P~;&jB-?eEbGJb zqH?fTb>KrvLy7I^jT6H&;S{LyI4hDwvP#b0@!vEi#M?h%cG(5c%Z1YSCv41#iv1*e zxm;&(?bR=#iLA`1dG8<;=!8fx9(N>fT&hluv=%fjhOnmS$$8mmVb)#O!};@$mdmCr z)o#0kgFmI<7CegtU z#IJj|TkD6CX(h98NLRZuPgj5YM6D#|x8J&D9W3Uw;z(=_eOtU>820{Qo7#NpI#*uR%BSG{O#= z9X{C)Hy}gEgbVbqPt^#-!VH+O9B^(DA6lYSJmVl~KVLxx8c%s7-XF8i0nJ)xAGCJS zHs?Nn$W?lksC*=fDGUv7J}ga@^CMd(nL;M-vxMiX8C?+jTE_W!PFhy1mfDWW<3g*9 z^XcYHzS!IT5v^WW8oM2IebZPKLK+M;d-ZO?Mlb=<*=qb~docnxYfj=Bx)w9Urx zvHuX3krtZ%gSU5z(qdb_aq4RKMZQ;G+o0k1DYVV@k_*sbriqvzKy<J{KtMcfs zg(hAEO*T@#DHhTGAe40%3kWqLa&{cmd)8~u?1ZcWk7R}w4jrD`uW>OW;PLtP*&C}j9~UQER4(u*>8JAF^M?K zK=Dz$o|9*TOAg^)pykm@=Em3CByCrif??sDcbMY&Dn-tNBH^xo1JoU4D^|GPvkVAK zb_xbBBwr{YWbukvhLu@o@cE`kFqKc&`Bc+4CQHD@z)d^Js`R22cw=g9A?@rIO^)&g zL11)*;%myF&U8&VHWL9!Q%AiY)r8oWTTmPotYzhb%mt=#a!bM6ZNkO`1Uo5Hi50t1 zsYv6#;yF~Ee&YrT*tF*T?#~?PqGAsl-wL6ndDepsjB3cXu#F2|y3B36j`5=d@^r~V zTG>FILdd?yA9WMN*;%Z04x&FR$S!$+pkl#+8=R^lX&*&*=zLX11%~wWz|*XlA%E;2 zwW_Tz7W4azGGfNv*7xvkPrAbPXqkn$B^@%VeH^grT4VT~SXEdO;49jikV$ycYiX31 zzG7*XltmBG!N6fHn5V7G!C8A&qIj36`^>};6m zLm|rlNrh6MQd@?>U`Ms6svz*Dg&m(`C5D%sW$C zqV4eR$4n=$_mAlnf^^Hn4S`|$*VsVea^XK*)qoog7*dMO*3O%I{0E0x_dGHXyQS(i zU~QE07gWXIDu2!v+z`~>g>;K1V1qh{SE0kGtV#K){UqxAjMK-<0X!4nN>hc=^z(w- zM@$?QHs4F@dy&Ue@rS@eIdVfi7_C|IqvR*yNJsOZ>+(7HR$oUglXQLhE*n4nEVVly zeVUH2*sn(uWrD+sgb?UITD5_9 z6N@Z#MQROG25lVjUSL*2ZGz6rd2|XpR($ogc04M?O^FILRDX1x22&=v zws{({7$i-Ojxihb5}lmxyIZjp&;@>Z&bpD`Da%i3XI@qpMJF)K(B+>dyV?EEwupE? z>WgD!j|Vo6y~o-XPnu6cn*>RLJjm*4$8i>FfX1wgNXF+T$S7;A5ItWpqbfM#LI^hBM%+UpG%qGN zab0(D2YD#BhK)N{C-S%;c>qd=tap>Kk=y{VkY@G zZMOqL+OsZ>6kqU8s4w8MM+@3{RgWhNApJg|hn$GySCWV4)9pfb3**H>1z4{X2))lk z!kES_qwhcPe^+BEDBhl#wl}OKWnT3Yuz76DvPaTztx^X`H_bA`l>0#-jrit3lDV3% z$d67hJx}b#@@T}p(~>WEFV9i}ex;bk)9?j{)jqXecpow{G<5R6F1MDX)WA?NZN)Us zaVjudd*f*`lM_^jayW-P!kdB=LmmVyu#XfEwXo9v4r(gGLvJ@R5z;*R5 zO?@&^KL}T~O8}9DhPU)hltLx`@>1-6T5iK3ONk9qLWCjPV-RyhcjF(R>W-uw4uP-< zt49>>?>KrYFt0wZYLIu5A3;hKHzQGY_g2@-sghl7{CAy~+ zZAg8d;J(5!N7qShHP^Hqwe~R_EhHFQ{RDGPUiq(p?HC9eNS!x`!Q+mWurVPrF7?{!ipYt)UAwM{_dlYs7=13*C)aD z1kPuVQ9@aJehiH?SDf2iBOXO}g~azR-E<>0wk7Py_GuIEhIwW3*d?BRR;j4!?ZqdB z2$CrJ=@#ZGf<{ev4*78-!uk%BbAVRX))odzkcUy%i>qp8I)|jSNPXIsB^h}Lrv*9; zeAPa_v`lhsCvx6ng9KnPI4x8bL^{n14qP2*ru#(p_qDtbj~-y5(X?bvYhJNw9CJcr zvz-S!Ll-=^3EVfesw+h%`;Z{x4=%0B0!%%3V6^UP?{Kh(_|{V@CTN2*qkXjMMb=Vk zzw_~Ts8?WZP+z;I_;GH#J5e0$KAh&lcn7=r>wk;`6ZxuvKdNL2(^}}01j0UfkD9Gg zgvma{y}^z=?G0P1p!Su70mGTwJ>4A$nf_LmBj;+3Q*zgljG zUd|VWcm4iE!s3&O=%$qecqU37lTCDLliMstbflR=D2aRcZiW|o;48)A6S*=_W6l`L ztU1hC(2GO2N=vQo&Qqnno}fatlmG}yG-@0Ix$c@+;py6Uo=gce_Uz3x4(Q8nCW1+mRVKfFd1EY&?gQQ+Vf~U(~;X(5IZJo`4)2oNLqiSDbt-Me4m8 z-4RSn+9^(JL8d75YG7h6wk*Ysn6<>)am5xOzE)^=mSHG!4v>!&#hkU*SYPPfO2WaZ zMwp6c9sviZ7IasQK_1*_v)gABRH&Tqt_gtPBeR2fEMyIEYo|hm%RN*PM4qn>hr3e* zuEn4{!xq!8P{$57%ydcxJ+s{^%?#@9s@^5%nkWS024JpRd9 zBPu2ZeN~*NS0C&$S-_B>C~(eM58F+q+FgGsL1`j|+}91U#(3vwlE@s#;jtWf{>HJk z%h6J6SnA7ZHE_i{xtT5_VV=3p=(?g$gadQ&U@6x}n-BFMJ9oRL-Y?drK@f^AwYGPo zx_-0f0k6i(DHso^PX*p&EpDY`*p{MeLlK;M?R}7V{u`bHCI(ZQ-fUURu+G#B2<@ds zbg?2BC5`6wZHM=_Ea;xD-cb)KnA{-f>xxO3^H3fIM*V@niZD8&XI^$n6QrG(MwGVXWdz=XK-J|T6HQwPLZEEOA3!(Dqn-DlzT8W=4 z7)3*HJ8pzBL$lKDOepV%KkV+55H=CjH>f)^u1skW2atWZB5y~6Y@fB^+OkX-e}@;n zu~-=uZWZVShHUrvXtpFO&Ud*#po73E=LQ%3ijWKXr24zff*JqKX2AsPEF8bK045-S zrV};$>|kU^KqvZH&%sF8$iUjr2%47{+TOv=NY4`5Wx-Ne+IoW?v3Xa;1tER`q+6y> zB_KM@|09l*M!b2g%10@5C?pjAg_pc0(ij?bGms~H3EZ}EnB1+1| z1HLRf(t%LxVdt1piazH zROMSQ-`AKeRqShP(a*YN?Kn0=YR-D5FugDM>`d&u|FhwSFDvpwgr4mqD;} z5A<1VmR`@%2hOVXVJuVyGaQ&O^+@VoEJUNLbzodq$1&J4p5S9Kp8L*xpc{g1F$6O( z9g*lcBQM5K^f*}UnnP9_#^AJ{!8ce=yY5}vEy=i%8+kC;>sRv<{8_>$aLREg8#4NU zyiq-Zl43uTyn(x0!j!E!gDFpY$b6+&If~Y-dXCAXe$D}omJveCYd}NAYoMckj(G^U zd8(f$vu`lD)on0cX`EwnmfnT0l-|LvmfT5Qcbn`14m+T2FwM|(nVi9#V?GJG2c`?U z=WCv0HluGaop+mTn7A_{CR9T!W& znRcB`_EnkRX_e{!Agw|@2qw$usZ z482rq{*_=d9Bg1C>@rVj_7=K>w(O-a+KKERdSTW=n?e*Ji-e{F7RLa3SXmq&^sD!&?dBXalw~_nMC;tkHB5xzRvb& z99HVVmRCnJ)EK=tm>M+>Pi)(&C8VqJ2MCwKV8d{UkJ)eotW;7v3DdnFx@RmcK73vN z6GQ&PRBK2jSyc*y!%hibPXotcRQsqJ-*FZ|v}3W=FaCCFUcM{#GZ{!3*JNEL-zb;? zGVSIXQ8N+#`Ae^6d!70jG;WmuHP&p{!&37ii@Eoxe{%0>sR1akc7y2&@YA--JOOu7KLO{X>oVC08|@msGbErk zdH<%LpcEki;=z1l)RYC=n*40{r49%i0ACXc=@0pJ0-pH($kEI4*)1ySy8|8}6J_;ls-? z`GKpwOx-Yj(ElxPaIRkM-u?@0Sy@rmPaI9J7Uwd@W9BanicyO-@v~1J)rz33X zP5Y_Od5*}3Uli6?8eU?39jC6t9(nACKYL+B+*s?vT}V2we3_`b9Dtaf&CJf#vEp_V z@+ufAomqgG@z8*WsIi6KArcuTvu!N178}pe&Z4EyGH=|WCU#?kIE9GGSd}$#p1W!! zRHdDM>X%I)+2k^7g4#haIP59&Qk>PvyD!`wJg;|-&T^FMzFC`kTEydH zr#lrZ5X8csnT9Rp!mW$Iu6s^}Nl-7Jswz|QIb3|*k?Nu-2f&#dO|3_j?>X+M)NnD< zAAuB!5Q(F02rhia-VtZk_VPx%;>_aoxf1{p=M8WI5knArl9PkB>?T1JOTP{GFm9yW?h(<(~ zDgu3NBygnhgFPbFLe?MNGh>uxkhsv(^7UTj6^}AZtG#w+uwTz&xDYnMpc5X0&FHmB zGaFpR4p@1MVY*s2)#73IoN>Zn3TdD*h(3RAcY%}A#=anu#K`eXU?i34c@`2P)gEiu z3Q%iHEYXD>R_n*WGeR{el6_9a_(D{SDP#ih(UR2a7mTO0>q)!;H7{5mfSHmfUX$(d zm^@RQ102?UCRxyagj3OdGtE&nZjh6B!020`C-u#IHaZn=ju;hhZ`&_bmKb%L97zJ4 zRf~$ZQM2|nyu%JHD^c)Cj4t3V%0o5yRVnrrRg&eNkK%je9fC}^MfX|O zh6~Pm`#6ccziV01wtqGaw1%%hh@f9I+!|Hmj*dT+H2Yb)`j={DDTHy)v=TtGy;b;;!*@I@wB0}%g~JpRCe zH{C=T5(!O_-Eh)cjm#En7Ssa7zfQwyqE}Y%D+nZftr;UH75mOY6`Do&u^HUodYva+ zkcaSlW+Jp+^UGQ#E)_=;H*HS|g!Xl76-pQHLt9=SkJ}6H>v%kEv{#~J0+?A#iZRul zIjykStRC6WscW?hjkL;vXX{>vlY!B=Unn;LoG>GY zp>t?h;kMd&`ci$;BNkMse=tHGnHgQ25yi2z@10O&B|lRIhTA2IKn zEM)*1bOs2Rjfz*%;~et=5DI?_xC?juBlZPvMa;-5K+K>}0caawt?uW^cbFNl{@c`o zZz|P>KF5EoKzuDEeWgk;zwlC!!#&4O3!M#J7wSG|@9@hJ-+{c;R33y9Aw!BZ*QCa; zNc`9?pN1w7~Ckn%Bm;I0Piu?*Z zwbtUW+q~<}R_ZS05ketxzulwAcI7;8kw(qvWaK_WtK6guON2=}%{ST|72R6rNk>m{57M!Rr z5U3Im#qs9LBj{JntJVlI!>tx)eis*>4sXG)^6*&0r0rt8?PBXs-NI`LnnO3#`j%(w z5#h9phSYkC(dk;R0L}rG_6dS{e-yxm7Yx8q5JdQpaP+|HUyeYMdu@k(h9HpW6^crb z>Fww*aDZZc<@Mu3EnIM@spu(X3foi_kyC&z=mB=hktaHiMd8>FlsknAtl4Q$!*`ub zm*0}gwWkeQ3{5R%A$yMc7xz=m!v(V&hXTCbELSHJM=h%&>D6!6 z+^&;skCKO^Gq<@N&5qAxV29ri(Qm)(q|Cq2JBdE>!7|U$ExVqot-j@{bbvhd-+1cY z7Qj;@Qe+?AJe5ei`4?0A<*AD}O&>mbdh&f+)|)&H)cvV+Nyg{O8FiX_L7K!DUW(oL zBCX{$zO$Q7*Sop$#+1zS{$NVCi++lir;ASn%}w~v6!@n+)(N9mFoQ<9Nt8ndhg*&pI7Y=x< z;@i^nUKko|PS2?gFWJMRJUWrR&2LC)TH+6+bW#UVu(MisFW~0N$N3BY8k;Wf*IO>t zAFpawOu6MHI5tCTu6iZ|@Nd%z>B+*MNU2!Y>_3f^68=C+C2vTH<+n&F<6#J0adkN3 znEWrK1oStg1omHnlsMjyQe@%C1O7|bUr6bHwX6Q`f|Ty-!QWiN4vx z0RIA9Rs4EY>vvM+_-~dfn*#9rzmU?uan;4vKU@|2ad7MxQi28`rIw#KTF!qUC9aji z-Yo0%Wi_qDRP)K>(Kn=&()kxsx>^34tFE(0{^_cZm+gO-s@~G=@}E+5{zZQ={&dw} zm6|`Ky3A(sC;h#@_uy{a%m>ilUsAQ>M)<>3Vc#k>e@Rv55BmGhQWg6rss2-?#$|!k zYR>6zu4?iBwyXYCsresQ{r^&>=9jDfy;1{^>R*+bKc(tnzZ&`*sj|@jMyjlg|KR}G zQF+j6ksh(>kZMlIduuHzu0%x_Ba;NCFH0H`LZtkMZ~^$|{^-w{_m6f?v*L@)5Kx`l zM|MuaUsZJQRFD^Mu-QVaYTfJ%yzsEtC|b*++NYJL*>?R7WmeNHw7w+co=$C!u~9iI z%x-%)t{%&JI)u3Ylw zkmIZ1Z-gqeHtH>1|E1QqTFuxfhLlKbinfxKGoV&OU+XjUR;ytl!yIqqa50E(a>JE9 zv01fze5Ec87N|^PbpW@_b ziboDlE8eddSZlJ*in|P(t)vkheW+IZyQ>x*@NDhtTMW#)2=lA1`o@)rlCb~NT*>th zt|a-!m7sphmFNIr=2Avq%CWHp2gG4>wGlntfeEKbfv<;yEg&T#QuKs#2)4nbk z^~5H6rn?x_@GK50%+8z=eW~k0FJuE*Ll%R*AvLdXM?i7aFQeLXK?qQ^$s#j(hT5)r z0d3wb;rqaQC>uP=sb~twR70)Psz-wDe${Ix$D+D!^=&eq(mxuUTi2!q+VSdr74}eQ#VAJnk+Y4PvF?f}5qKLWK zQw$^NN0n>S~!n5ZLJt2>joku-^VRCaixoLHtj``hTwp;$I}J%{qTi zSWgbu=puDiO@61<-!?4$7qX?dD46ii!s@>p1#{gdX8mGIC;+zPVb9TE)$~VUwM8*X zXqCHB{*NfQ7h874VR(I_A>^8;(8l`laTOe@Hd)+2yR{^sQeh5zw!s^Q&L! z&w91KFPZIjm&!Cz@}_D;Myz3@l^Ut zUS?FihhwYBW~OnFL3u8|8IgdOWshHhM<*gLbxR=FhZno&F^6M6xmyJZeDVd(!${R3 z#33>Peb2A;)(Z_8N+E2fuyJUPiV>6HJqLSQ0v9(17yzZ7H0stOU829*V>}{ExS|hb zJS<#GKhj#YhFn@_6^|3gld(|ItS(KeZoT5MXi^GGUsy>^ee$LDjC78x5pkUy>@#!!q zW|zD32I~ye1c431V$JskbVLx!*$@zGp@Yf0$SXb1U&lI85Z5Fes0(I?OsRoNH9MpO z(WwRlY1?r_L}C=QG3@rV1#WijIu?Ae88`=>v(woy#HnlJn9r6|H0z<~&r-qM_LtWw z27OTOz(_ZpDXc^ro-y4U-z%;qO0&f|oH$AlmDW-y2eT8harmCaG{k{^-RZkI_QT&3 z7yZmUnMw57sND_4rl0+a{h{|Vm|fnVli|KZ|IT1*nk}cy6U*az=?wFuZ5%n7epF^> zm;Ze@Ca?CG;b7 ztjtieXEGua+nXy)W#>}h`-sQsDzsbZ9#Gq~wfgP7`nLu^KTwXz$whk)Cn`e%6Aae()F_U*BjF&JVBi^@o4p>0+AcCeJNckP+3A% z6vjfQ1C^^1P-D^XKX+RciwzBgDgt%V4{)e56jRcM`#{Ls=ILV0Vw??>lnF~)xU9uz zg73hE+nBWpDht|a!Xh*n6PK;Gn=*GlgK{!^V-VP%fmn!q0PP~C55{`=X-e|Kbce4d z{=v2TEG+--U07`bF?f33SHxKG(F7oRBTD7j3Q;H*ImE~!DiH>&LdtIPlCQ9M%+U~X zC_!sU-re4)c)ASluo&ROl;PwEkpSQE*{*NdM(C|5>WvQ`MswEdO?^C3}C6fx+F5cbH1aj{RSX}bjQfAom^eTa>3VplL z$g_0K%%jsKG%(c<-v`JGp?-u5$1n^7mhkhH0}2E47a~LsH(Y~=>3ZjU_AU%H_dVD{ zcn`&$iJXyyUS*||Fa`CGdT`(x7JBGMa5@BURb}D}B z;9*Jv7{O}(JxHSJ6zohW-gdl=Dzqx3jw&=o)Qxw9@?P$3O5Mx!pM#+ zK?Um8Pt51D&fuo!%dEn_dAo65%bD5Yd7(zlh^5;MvRnGggUz7J*xOf5FUQKJ3~F+0 z9p<{!d(hb-vbsYFhp?!qM4jT*Uf)Xda1Ln(bRfSMW+Jh}L*sG5?D_W`$=uu)#&ymw zR3{%Xe?lCD09;9OWhw@A}-0gH5d!OKM&g^xmHm|E6VqBM~;-<%*Dm) zu^gKj$Ppc_XFv_3l+}>g$+y#X){IjxV8`@05uLhiEP_@oB9w4uz3dKzH&b1n+pNI? zXZETZ)0#5PnAeUY*m-|`U!4;Tb6pS8NQO$l-~%oNmhpe$+5_^zR zJ;5mfZdpGH(gyhV_7WQ?pZzmLB;O~27pXb#9M5;yblUjM?3|%8Jp|Yt8|@XUB}1>_ zaI7}WXR4ZlbCy^{TqIou<+4$<=|aJYvE5i#FFo_+#SB+EC1a|Nxxs>6ZS}TrVzzyRpECWK;{(Fw@WM7KUfs2ORf``iOmEp> zZMo}@5TV>VoBP8>wpLJz$i&NiJlxEOsPj)kwZ$(_8HfC??kBkvFt(iESc;8#G^{_k z3TTT~J#7TILQJ@Wnvve}uewzw#fTp|rqH1al&)w{&(vKXK(7%CKQ2-Hpos-(_}c0u zNu~nP?`-#QGcQZ9TD-0Ax&jXaIV-~c(I&$i#i!9b;;Q&inD41!8iCe7=r+nC^ET2j z3wH`tW~J5Rd_4f+I8_ALir1j&tHp|zkKpGCQll{sxJrf}r=GeH>K!%#F1wUnhRcG2 zC9ji4>(hoJWuIaXdyFE!98~S3?$1-_C-D#O4jZPUCM+s5`A9n8nCGd5A7!I_h z-fCw0RDTfI6mx)T$^C~7&dp1hA3`}=I+e>TA=`2xc#oCwSqEwdq@j|gL0_3oP|7-* z8?OY3rI91EW0C6(j~A{0Mk_Hk=0Uw(5yvx5RGFXy7FTiuw<_Ch^+|uoT>lD8voe^S zd7a`hU0Cba+cO10-i~6iT+}AzJDC|RvxY~hrEENR7K_*v)NR|0X>FgBAoGZFKf?*H z$1C#nEW+qwxZp+41sY@ zIA zV-8^{VFjzg1760BbMjKxic`8QU_n&FIN-0&2VTO7bM)d|1516i3QNuOWfa2;R^5Yr z;rUdKL%qd*z##^bQt*-7YIxoBwiSNc)F?7x=CQsMUm5ubaHNT0OYT~i=euhc)fZ3& zwO6>@N7`PFnQxZ?&RyhC`s(=6%F}v| z%iVT_G#zw=>_}ZjBN8p}J&VQ_n6J2JMFmmBF#F8^qdc@WC}uro)lLX(HVFs6&3c0{0cHPG8_)u^P(}0{CbAn=0O3a(dNp(e zw4@_tE6Gvu;pGn7Qrry4lg5`W~jTjzc0O z^EyU3CK8aBIb7lpx_KaDGQXgoySj1)9SMc7i_#4=(iED+zAU&^Gpz6{dokq%eltco zD-Hg_5F0G`*)pUp)Y9J%^*9gQk{-WL3edzCiA>TcQ)r?FtJsaD^m?<<+(R>xb8bnJ zGRE10Vdm04Ud(*JG>jI2A0U|cZb;-OWq3w-x?iCLjwwtk)Ecr{g;EB|2&wktgkS*a zoCuL_Pp)2ytYyN6haSHySI99oG!tR;YM*WY$5z$5BnS_7{2G}eR61oUykL_bZ=Y0j z1wS`-(JQI#2bT`bi;=OMC1-6l#4w`*e^UK%g&OKJ8OQkszdngwU+|Uco6q_SmMIv_ z91!6Mq@sK4%!li&A!W34EkMzIP?;I(<&hlAq8`FWx^ z4;8rCT;g^q(bmW(`?_$@9$XfS;ui}Y43NjOfQ`Suy)zPTt?S3!^CQpj87r@LD%}i= zq}}q`8&R{Dp)t^t@ZhZ3FOejBpYYD#syMJrRD78cN}jU?J-OXN9)OjtcWi6&;4#!~ zXF`xA@yNUi;eu$>Sk_l2etr!IhsI^MXe%_5ilrXIZ7`ovLS`cxIYmkt)2=>AX$UEn zC>#&uO|6~x?^EzYIA%OdD8#c}Da!4=n$w)=tLf}>C?C_TUP&P_DohOgG;l-W>`WW8 zNEvmhwr}Ut@fxD9_589txqW?C^{r%qtRlc((c`ws@}#vumU3MA)icvmp}*|vh8RT* zi8zp$8gHF_<5l(Jh{!MTRiDKliG<}yIanzdJ7)GEs5Nb{|JEET)ds_}r1PBqt z^yzFl1qh?Ag@Habyo-NqP>?ahH;?BR$h$aZZ0r@7QkDI(?F?cFw-WP;qxBNX1S4G=pw&)ZbWw!Doe`*<`5!P*0vEezBqpCl zK6Ckp-)cS(ZfQO!UpjJSlrGM1+&nUXo8F(Wixw)wvu5_8ovuX`e8qcJD`F` z0jZ%`b`LU<1e59HvR73wl0TQI5CerufWLCyvmDnel`y9tX}+N^TE5}>7Ha@hK^<;z zp->X`&!iU^Bm*hJ-{e8;e{VREv$HmIGytqGB)2g%Rx(nhVW4HEr)6ZLfTk00bTGBH zBiCeNV+GvUH0kN-CEfXR>FW)oCM^;oQ(90tn>_k ze@sjqEbKJ&>}2%xWPo|n)`tIRijtk4jg65ZU`eRnXL}=PIyof~Ra#NU&!6@6tgPNX zN+nY>dji1!KR!}wf=@$3(t0dVb7W==)~fU9Dm zAh58}b1=0x(j##C^NFmq%(M&?Z_7@NtPHL7&7oOX|K79zuajv;roVD&1`dvY%B2A* z_MfX-|8XuIpdx9##ERH*TE50Wix}3q9*v@lL4TkzN%C<)am_Cc@&x!0qUliR)x-E> z8GlHeJJD_GEE|G?rrjqqkr4{Wbd~b4fz!;-kWDuO?>GkzoXQe@2zd5{T?x zc~5ghj#!QC)=oj9>p6r8^|(AeUG~V$9VvFb*}3lG=JurtUx$vbLDD(vb2&%1wK?q> zk#`_La2qpdGbBBfc3{vs5^Yi=EzmHfCa&m-({jP{=F1cjGsWt0S-HtntoO4zbDj=y zFx`8@E`<R9(5o+?WAE6bW=f^omy>U{Errbki{;;E>vC z#qYz!3x`9PI$BENZKmYj3BH#Ao)BY7Zh}WB?;P~<`p8yl)i$9BDeYF6m}l;{MUp^j zUIP4)thQ9wtRNpcA>AC%U#xmer5Xw(XHUm5d|ihW9A9D}$wS!78_6g8xJyPsdH~iH zz+3^k4NFMPZ){YunmH^baU6Q3))VSfOQ0fv3$S&0BkOotMEJDOE=0GZ_c_Tsn>iFoe zrf(LYu^`75ZoCr~%u`}+5s?oV#8V7{4%61d8e4TW^AhC3Xdb4Zv01Y$&8aTF!C1f? z{8Mb88v}Ymx*}_ANYI1u%O%Uu)fN<i5BXkgKif5&ICypg_iX6$vC zZ@>3zGZ&k6_nkz+jAuMd4S`+{zPoEIMAt}UcJ8Lj9xbD`e-)8pm-{L##XM{5Z0 zD*ru+7dZt!q8)2FNBv;C)||^`FJ*Z%%%~6Jp}S=NYf+6cFfa1=R@1QF#RYVN-hMjk zd#Z$)H2xOQZ7)?#KhIlpZ40Tssmp5$uf+-TIxKnDM%<_p60h^Q1K5|#*TL@%d_j{o zE}nCaI``wlocnX94RqE8oi7wb{genF@?g03U!R{Wj$U{oO|~IDu}*qB&ku?opKe^9 zvRp5l8=G4KFLxq0oprQ(3Q|>pjH<)}y+DF%ahQJRQh)EY`r{9bs)CU*G@ZDWp^*!L z20Z}_2fY?FouZkW(c7=kbSeZI3xkWqx0g-wV>go&9^SV(}8fr*iggO}hRPXWBnpOlb+iG%q+N(pfj zIIOjlQ36I=tk0rdLO16tzjY~o?zR1_!*ywBVsivLvPNOc?f6mdEE9-CScp8@8#n}< zl7#>N3SkAF`ic;grv>o`C^iK`LZYPrgoFfzIp1oQ&id~4^SgKNwf74l)a_@%;sfL% z^2kDH2w4c_V4*yjB>X6A7VKl4G7H(dPK6Lc{eF@Lq!DS}w@~QO)nc-(*xzJJ$#x`L z{8F}@YJFE@%5Zi%t!a86Nuw6(utP{43J%aSW zx?uOQy+|Ld7j_SO6gdX#gWbg*NBUt$VRx_t$RO+(YzaGr48w+Ci`Wy$2y7U38#{`O z!A4;V*ptXOYz%e_dkUF=orK-Qo<=5N4wUhUug9C2zo1U>C4@ zz+13Yn7)Qy&TZH_>>O4vb_uot(<7)TcVSOpXRs>heb^REkFRDRZ3|5Ww2(}B; zt5XxM5Xk~;8mk6ggH^-y+SU9Uuo~DTR>64+I{;J3Hj!sA1u=1(kaT*@d;h z#<6=zJdJ{`KLZz9xj?_TAsI|fJ%%kHMOZhCUh@)ChN-DXuvG|Qk7{cA)Cs#2_Nb;F z#u9cX?D05^9(Tg-ggy4d2C;`vI@46F}J*qyM)voJF4gxv{yyansQ>H=Yp3ozZH4<+pJ4y+riFQjj( zM;NwH9~qIZr_^^=RW;Hy6KfGoOqI5k`}B(S?o||3i&{EGcB=2Rh0`xiBRL)Bw4T$G zPO~~)?6kMj_f8<3q&N|BvgL%%Nu!fIC%;bKoWwgRb7q8-EoZ7YiE`$UlOtzxIq7j` zos$`7Iyy;l=BbkpX97D3aH8QSEHu6dJntba^WMpVvmu-W_)~Zr9axGSsjh-nA3SQzir1+9~I zuC{Q}L_cC-_FG-;;X)IqeuKt{Mvi%*-W4R#fow6NHqo2L*B-&sT> z_bhTA(PX`dXr5k1G(|P~u3328r%#zft|OY0HxW&^1qXc5*rpgYo$78iy*4CtPLlt8B`SH$SS&bXb7Y&87 zh3Cz>K#ih?hZ0|B;e)qyL4!h*;Rw=f;gf1z&=lbPMdiE$QM%covB$z^|LVS8gdG}3 z5jJOBMp6@gv8G#2BCOAN3ZZzBEg4yhF-Isxq!f{L7b!)g6p>OyN)ahVq!f{YM%GxQ z3X$a%DMh3dky1q7eOyFXMUl$Hd&qs>pMH&Kyz<7QHi@=c4JQ>~9ntD|f@ooEB3ct$ z$hL)Ve$WH%m`%Q})2`WjTRQDoHn5}&1}nAC2g}}mQ`Ri|>3f|rD|GkjRItL*r#cm_ z@cFb(B`fx>>QuJkYhUYBWyRlr4p#i*d6K`UlKk^alK-X_pi>1wI`Zj##5N$P%0 z()50kmRWs(esgIbJw-N=XNZ=tw(bt1T}!X!>2HTV;%{?9GK8(07m*TDMye22Z_cjG znY%e*&l$csvp6T0Ib%3yKIiP!oFA1rSEY4oq~KV6Y@Q3_>lWOH}) to avoid polluting the global ref space. + +\subsection{Regulatory Constraints} + +\textbf{RC-1: GDPR Right to Erasure} \\ +Git's immutability conflicts with GDPR's ``right to be forgotten.'' Deleting a commit requires rewriting history, which breaks cryptographic integrity. + +\textbf{Mitigation:} Use encrypted assets with key rotation. Deleting the encryption key renders historical content unreadable without altering Git history. + +\textbf{RC-2: Cryptographic Export Restrictions} \\ +AES-256-GCM encryption may face export restrictions in certain jurisdictions. + +\textbf{Mitigation:} The \texttt{@git-stunts/vault} module uses Node's built-in \texttt{crypto} module, which is widely available. + +\subsection{Operational Constraints} + +\textbf{OC-1: Single-Writer Assumption} \\ +Git's ref updates are atomic \textit{locally} but not across distributed clones. Concurrent writes to the same ref can cause conflicts. + +\textbf{Mitigation:} Use \textbf{git-stargate} (a companion project) to enforce serialized writes via SSH. + +\textbf{OC-2: Repository Growth} \\ +Every draft save creates a new commit. Repositories can grow unbounded over time. + +\textbf{Mitigation:} Use \texttt{git gc} aggressively. Consider ref pruning for old drafts. \ No newline at end of file diff --git a/docs/adr-tex-2/sections/03-context.tex b/docs/adr-tex-2/sections/03-context.tex new file mode 100644 index 0000000..3c076a9 --- /dev/null +++ b/docs/adr-tex-2/sections/03-context.tex @@ -0,0 +1,93 @@ +\section{Context \& Scope} + +\subsection{System Context Diagram} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ +\begin{tikzpicture}[node distance=2cm, auto] + \node [block] (Author) {Author\\(Human)}; + \node [block, below=1cm of Author] (GitCMS) {\textbf{git-cms}\\(Node.js App)}; + \node [block, right=2.5cm of GitCMS] (Stargate) {git-stargate\\(Git Gateway)}; + \node [block, below=1.5cm of GitCMS] (LocalRepo) {.git/objects/\\(Local Repo)}; + \node [block, right=2.5cm of Stargate] (PublicMirror) {Public Mirror\\(GitHub/GitLab)}; + + \path [line] (Author) -- node [align=center, scale=0.8] {CLI /\\ HTTP API} (GitCMS); + \path [line] (GitCMS) -- node [align=center, scale=0.8] {git push} (Stargate); + \path [line] (GitCMS) -- node [align=center, scale=0.8, swap] {read /\\ write} (LocalRepo); + \path [line] (Stargate) -- node [align=center, scale=0.8] {mirror} (PublicMirror); +\end{tikzpicture} +} +\caption{System context diagram showing the high-level relationship between the Author, Git CMS, and external components.} +\end{figure} + +\subsection{External Interfaces} + +\subsubsection{Interface 1: CLI (Binary)} +\begin{itemize}[noitemsep] + \item \textbf{Entry Point:} \texttt{bin/git-cms.js} + \item \textbf{Commands:} \texttt{draft}, \texttt{publish}, \texttt{list}, \texttt{show}, \texttt{serve} + \item \textbf{Protocol:} POSIX command-line arguments + \item \textbf{Example:} +\end{itemize} + +\begin{lstlisting}[language=bash] +echo "# Hello World" | git cms draft hello-world "My First Post" +\end{lstlisting} + +\subsubsection{Interface 2: HTTP API (REST)} +\begin{itemize}[noitemsep] + \item \textbf{Server:} \texttt{src/server/index.js} + \item \textbf{Port:} 4638 (configurable via \texttt{PORT} env var) + \item \textbf{Endpoints:} + \begin{itemize}[noitemsep] + \item \texttt{POST /api/cms/snapshot} -- Save draft + \item \texttt{POST /api/cms/publish} -- Publish article + \item \texttt{GET /api/cms/list} -- List articles + \item \texttt{GET /api/cms/show?slug=} -- Read article + \end{itemize} + \item \textbf{Authentication:} None (assumes private network or SSH tunneling) +\end{itemize} + +\subsubsection{Interface 3: Git Plumbing (Shell)} +\begin{itemize}[noitemsep] + \item \textbf{Protocol:} Git CLI commands via \texttt{child\_process.spawn} + \item \textbf{Critical Commands:} + \begin{itemize}[noitemsep] + \item \texttt{git commit-tree} -- Create commits on empty trees + \item \texttt{git update-ref} -- Atomic ref updates + \item \texttt{git for-each-ref} -- List refs in namespace + \item \texttt{git cat-file} -- Read commit messages + \end{itemize} +\end{itemize} + +\subsubsection{Interface 4: OS Keychain (Secrets)} +\begin{itemize}[noitemsep] + \item \textbf{Platforms:} + \begin{itemize}[noitemsep] + \item macOS: \texttt{security} tool + \item Linux: \texttt{secret-tool} (GNOME Keyring) + \item Windows: \texttt{CredentialManager} (PowerShell) + \end{itemize} + \item \textbf{Purpose:} Store AES-256-GCM encryption keys for assets +\end{itemize} + +\subsection{Scope Boundaries} + +\subsubsection{In Scope} +\begin{itemize}[noitemsep] + \item Article drafting, editing, and publishing + \item Encrypted asset storage (images, PDFs) + \item Full version history via Git log + \item CLI and HTTP API access + \item Multi-runtime support (Node, Bun, Deno) +\end{itemize} + +\subsubsection{Out of Scope} +\begin{itemize}[noitemsep] + \item \textbf{User Authentication:} Delegated to git-stargate or SSH + \item \textbf{Search Indexing:} No full-text search (external indexer required) + \item \textbf{Media Transcoding:} Assets stored as-is + \item \textbf{Real-Time Collaboration:} No OT or CRDTs + \item \textbf{Analytics:} No built-in tracking +\end{itemize} diff --git a/docs/adr-tex-2/sections/04-solution.tex b/docs/adr-tex-2/sections/04-solution.tex new file mode 100644 index 0000000..0156f7d --- /dev/null +++ b/docs/adr-tex-2/sections/04-solution.tex @@ -0,0 +1,62 @@ +\section{Solution Strategy} + +\subsection{Core Architectural Principles} + +\paragraph{P-1: Composition over Inheritance} +The system is built from \textbf{five independent Lego Block modules} (\texttt{@git-stunts/*}), each with a single responsibility. These modules are composed in \texttt{CmsService} to create higher-order functionality. + +\textbf{Benefit:} Each module can be tested, versioned, and published independently. + +\paragraph{P-2: Hexagonal Architecture (Ports \& Adapters)} +The domain layer (\texttt{CmsService}) depends on abstractions (\texttt{GitPlumbing}, \texttt{TrailerCodec}), not implementations. This allows swapping out Git for other backends (e.g., a pure JavaScript implementation for testing). + +\textbf{Benefit:} Decouples domain logic from infrastructure concerns. + +\paragraph{P-3: Content Addressability} +Assets are stored by their SHA-1 hash, enabling automatic deduplication. If two articles reference the same image, it's stored once. + +\textbf{Benefit:} Reduces repository bloat. + +\paragraph{P-4: Cryptographic Integrity} +Every operation produces a cryptographically signed commit (when \texttt{CMS\_SIGN=1}). The Merkle DAG ensures tamper detection. + +\textbf{Benefit:} Audit trails are mathematically verifiable, not just trust-based. + +\subsection{Solution Approach: The \"Empty Tree\" Stunt} + +\paragraph{The Problem} +Traditional CMSs store content in database rows. Git is designed to track \textit{files}, not arbitrary data. Storing blog posts as files (e.g., \texttt{posts/hello-world.md}) clutters the working directory and causes merge conflicts. + +\paragraph{The Solution} +Store content as \textbf{commit messages on empty trees}, not as files. Every article is a commit that points to the well-known empty tree (\texttt{4b825dc642cb6eb9a060e54bf8d69288fbee4904}). + +\textbf{How It Works:} +\begin{enumerate}[noitemsep] + \item Encode the article (title, body, metadata) into a Git commit message using RFC 822 trailers. + \item Create a commit that points to the empty tree (no files touched). + \item Update a ref (e.g., \texttt{refs/\_blog/articles/hello-world}) to point to this commit. +\end{enumerate} + +\textbf{Result:} The repository's working directory remains clean. All content lives in \texttt{.git/objects/} and \texttt{.git/refs/}. + +\paragraph{Architectural Pattern: Event Sourcing} +Each draft save creates a new commit. The \"current\" article is the ref's tip, but the full history is a linked list of commits. + +\textbf{Benefit:} Point-in-time recovery is trivial (\texttt{git log refs/\_blog/articles/}). + +\subsection{Key Design Decisions} + +\paragraph{D-1: Why Commit Messages, Not Blobs?} +\textbf{Alternative:} Store articles as Git blobs and reference them via trees. \\ +\textbf{Decision:} Use commit messages. \\ +\textbf{Rationale:} Commits have parent pointers (version history) and support GPG signing (non-repudiation). Blobs are opaque; messages are human-readable. + +\paragraph{D-2: Why Trailers, Not JSON?} +\textbf{Alternative:} Store \texttt{\{\"title\": \"Hello\", ...\}} as the message. \\ +\textbf{Decision:} Use RFC 822 trailers. \\ +\textbf{Rationale:} Trailers are Git-native, human-readable, and diff-friendly. Backward parsing is efficient. + +\paragraph{D-3: Why Encrypt Assets, Not Repos?} +\textbf{Alternative:} Use \texttt{git-crypt} for the whole repo. \\ +\textbf{Decision:} Encrypt individual assets client-side. \\ +\textbf{Rationale:} Granular control; the gateway never sees plaintext. \ No newline at end of file diff --git a/docs/adr-tex-2/sections/05-building-blocks.tex b/docs/adr-tex-2/sections/05-building-blocks.tex new file mode 100644 index 0000000..b8d0f9f --- /dev/null +++ b/docs/adr-tex-2/sections/05-building-blocks.tex @@ -0,0 +1,21 @@ +\section{Building Block View} + +\subsection{Level 1: System Decomposition} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ + \input{figures/decomposition} +} +\caption{System decomposition showing the interaction between the application layer and the independent Lego block modules.} +\end{figure} + +\subsection{Level 2: Lego Block Responsibilities} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ + \input{figures/responsibilities} +} +\caption{Detailed responsibilities and API surfaces of the Git CMS modules.} +\end{figure} \ No newline at end of file diff --git a/docs/adr-tex-2/sections/06-runtime.tex b/docs/adr-tex-2/sections/06-runtime.tex new file mode 100644 index 0000000..7f55b19 --- /dev/null +++ b/docs/adr-tex-2/sections/06-runtime.tex @@ -0,0 +1,20 @@ +\section{Runtime View} + +\subsection{Scenario 1: Create Draft Article} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ + \input{figures/draft-sequence} +} +\caption{Sequence diagram for creating a new draft article.} +\end{figure} + +\subsection{Scenario 2: Publish Article} +Publishing is \textbf{just a ref copy}. No new commits are created. This operation is idempotent and enforces fast-forward updates. + +\subsection{Scenario 3: Upload Encrypted Asset} +The system splits files into 256KB chunks, encrypts them via AES-256-GCM, and stores them as Git blobs. The plaintext never touches the object store. + +\subsection{Scenario 4: List All Published Articles} +Listing articles involves a linear scan of the ref namespace (\texttt{O(n)}). For large workloads, an external index is recommended. \ No newline at end of file diff --git a/docs/adr-tex-2/sections/07-deployment.tex b/docs/adr-tex-2/sections/07-deployment.tex new file mode 100644 index 0000000..4cd81eb --- /dev/null +++ b/docs/adr-tex-2/sections/07-deployment.tex @@ -0,0 +1,58 @@ +\section{Deployment View} + +\subsection{Topology 1: Single-Author Local Blog} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ +\begin{tikzpicture} + \node [block] (CLI) {git-cms CLI\\(Node.js)}; + \node [block, right=2cm of CLI] (Repo) {Local Repo\\(\.git/objects)}; + \draw [line] (CLI) -- node [above, scale=0.8] {I/O} (Repo); + \node [draw, dashed, thick, inner sep=15pt, fit=(CLI) (Repo)] (Box) {}; + \node [anchor=south, font=\bfseries] at (Box.north) {Author's Laptop}; +\end{tikzpicture} +} +\caption{Local deployment topology.} +\end{figure} + +\subsection{Topology 2: Team Blog with Stargate Gateway} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ +\begin{tikzpicture}[node distance=2.5cm] + \node [block] (CMS_A) {git-cms CLI}; + \node [block, below of=CMS_A] (CMS_B) {git-cms CLI}; + \node [block, right=3cm of CMS_A, yshift=-1.25cm] (Stargate) {\textbf{git-stargate}\\(Bare Repo + Hooks)}; + \node [block, right=2.5cm of Stargate] (GitHub) {GitHub\\(Mirror)}; + + \draw [line] (CMS_A) -- node [above, sloped, scale=0.7] {git push (SSH)} (Stargate); + \draw [line] (CMS_B) -- node [below, sloped, scale=0.7] {git push (SSH)} (Stargate); + \draw [line] (Stargate) -- node [above, scale=0.7] {mirror} (GitHub); +\end{tikzpicture} +} +\caption{Collaborative deployment topology using a central gateway.} +\end{figure} + +\subsection{Topology 3: Dockerized Development} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ +\begin{tikzpicture}[node distance=1.5cm] + \node [block] (Node) {HTTP Server\\Node.js}; + \node [block, below=of Node] (Git) {Git CLI}; + \node [block, below=of Git] (Repo) {\.git/objects}; + + \node [draw, dashed, thick, inner sep=10pt, fit=(Node) (Git) (Repo)] (Cont) {}; + \node [anchor=east, font=\bfseries] at (Cont.west) {Docker Container}; + + \node [block, left=2cm of Node] (Browser) {Web Browser}; + \draw [line] (Browser) -- node [above, scale=0.7] {HTTP:4638} (Node); + \draw [line] (Node) -- (Git); + \draw [line] (Git) -- (Repo); +\end{tikzpicture} +} +\caption{Dockerized development topology.} +\end{figure} diff --git a/docs/adr-tex-2/sections/08-crosscutting.tex b/docs/adr-tex-2/sections/08-crosscutting.tex new file mode 100644 index 0000000..b139bcd --- /dev/null +++ b/docs/adr-tex-2/sections/08-crosscutting.tex @@ -0,0 +1,56 @@ +\section{Crosscutting Concepts} + +\subsection{Concept 1: Merkle DAG as Event Log} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ +\begin{tikzpicture}[node distance=1.5cm, auto] + \node [block, dashed] (Empty) {Empty Tree\\4b825dc...}; + \node [block, right=of Empty] (C1) {Commit 1\\(Draft v1)}; + \node [block, right=of C1] (C2) {Commit 2\\(Draft v2)}; + \node [block, right=of C2] (C3) {Commit 3\\(Draft v3)}; + + \draw [line] (C1) -- (Empty); + \draw [line] (C2) -- (C1); + \draw [line] (C2) to [bend left=30] (Empty); + \draw [line] (C3) -- (C2); + \draw [line] (C3) to [bend right=45] (Empty); + + \node [block, above=1cm of C3] (DraftRef) {\texttt{refs/.../hello-world}}; + \node [block, above=1cm of C2] (PubRef) {\texttt{refs/published/...}}; + + \draw [dashed-line] (DraftRef) -- (C3); + \draw [dashed-line] (PubRef) -- (C2); +\end{tikzpicture} +} +\caption{The Merkle DAG structure acting as an immutable event log.} +\end{figure} + +\subsection{Concept 2: Compare-and-Swap (CAS)} +The system uses \texttt{git update-ref } to ensure atomic updates and prevent race conditions. If the \texttt{oldSHA} has changed since it was last read, the update is rejected. + +\subsection{Concept 3: Client-Side Encryption} + +\begin{figure}[H] +\centering +\resizebox{\textwidth}{!}{ +\begin{tikzpicture}[node distance=1.5cm] + \node [block] (Input) {Plaintext File}; + \node [block, below=of Input] (Enc) {\textbf{Encryption}\\AES-256-GCM}; + \node [block, below=of Enc, fill=gray!5] (Blob) {Encrypted Blobs\\(Git Objects)}; + \node [block, right=2cm of Blob] (Manifest) {CBOR Manifest\\(OID, IV, AuthTag)}; + + \draw [line] (Input) -- (Enc); + \draw [line] (Enc) -- (Blob); + \draw [line] (Blob) -- (Manifest); + + \node [draw, dashed, thick, inner sep=10pt, fit=(Input) (Enc)] (AuthorBox) {}; + \node [anchor=south, font=\small\itshape] at (AuthorBox.north) {Author Laptop}; + + \node [draw, dashed, thick, inner sep=10pt, fit=(Blob)] (GatewayBox) {}; + \node [anchor=south, font=\small\itshape] at (GatewayBox.north) {Untrusted Gateway}; +\end{tikzpicture} +} +\caption{End-to-end encryption pipeline for assets.} +\end{figure} diff --git a/docs/adr-tex-2/sections/09-decisions.tex b/docs/adr-tex-2/sections/09-decisions.tex new file mode 100644 index 0000000..7cbafab --- /dev/null +++ b/docs/adr-tex-2/sections/09-decisions.tex @@ -0,0 +1,47 @@ +\section{Architectural Decisions} + +\subsection*{ADR-001: Use Commit Messages, Not Files} +\textbf{Context:} Need to store articles in Git without polluting the working directory or causing merge conflicts on files. + +\textbf{Decision:} Store article content (title, body, trailers) as Git commit messages pointing to the canonical empty tree (\texttt{4b825dc...}). + +\textbf{Rationale:} +\begin{itemize}[noitemsep] + \item Commits have parent pointers, enabling native version history. + \item Commits support GPG signing for non-repudiation. + \item Keeps the working directory completely clean for application code. +\end{itemize} + +\textbf{Status:} Accepted. + +\subsection*{ADR-002: Use RFC 822 Trailers, Not JSON} +\textbf{Context:} Need structured metadata (Status, Author, etc.) inside commit messages. + +\textbf{Decision:} Use RFC 822 trailers (key-value pairs at the end of the message). + +\textbf{Rationale:} +\begin{itemize}[noitemsep] + \item Git-native format (compatible with \texttt{git interpret-trailers}). + \item Human-readable and extremely diff-friendly. + \item Faster to parse from the end of the message. +\end{itemize} + +\textbf{Status:} Accepted. + +\subsection*{ADR-003: Fast-Forward Only Publishing} +\textbf{Context:} Prevent published content from being altered or rewritten after release. + +\textbf{Decision:} The publishing operation must be a strict fast-forward from the draft ref to the published ref. + +\textbf{Rationale:} Guarantees that the exact same commit SHA that was reviewed/drafted is the one being published. + +\textbf{Status:} Accepted. + +\subsection*{ADR-004: Client-Side Encryption for Assets} +\textbf{Context:} Git gateways or mirror repositories may be untrusted. + +\textbf{Decision:} Encrypt all binary assets (images, PDFs) client-side using AES-256-GCM before uploading. + +\textbf{Rationale:} defense-in-depth; the gateway only ever receives opaque encrypted blobs and an authenticated manifest. + +\textbf{Status:} Accepted. \ No newline at end of file diff --git a/docs/adr-tex-2/sections/10-quality.tex b/docs/adr-tex-2/sections/10-quality.tex new file mode 100644 index 0000000..13162fa --- /dev/null +++ b/docs/adr-tex-2/sections/10-quality.tex @@ -0,0 +1,24 @@ +\section{Quality Requirements} + +\subsection{Quality Tree} +The primary quality attributes for Git CMS are prioritized as follows: +\begin{enumerate} + \item \textbf{Security:} Cryptographic integrity and asset confidentiality. + \item \textbf{Simplicity:} Zero external database dependencies. + \item \textbf{Auditability:} Full provenance via Git's Merkle DAG. + \item \textbf{Performance:} Sub-second reads for standard blog workloads. +\end{enumerate} + +\subsection{Quality Scenarios} + +\subsubsection{QS-1: Tamper Detection} +\textbf{Scenario:} An attacker modifies a published article directly on the Git gateway. \\ +\textbf{Stimulus:} Malicious rewrite of Git history (\texttt{filter-branch}). \\ +\textbf{Response:} The Merkle DAG checksum mismatch is immediately detected by any client pulling the update. \\ +\textbf{Metric:} 100\% detection of unauthorized history rewrites. + +\subsubsection{QS-2: Confidentiality} +\textbf{Scenario:} A repository mirror is compromised. \\ +\textbf{Stimulus:} Attacker attempts to view private image assets. \\ +\textbf{Response:} Only AES-256-GCM ciphertext is visible; plaintext remains unrecoverable without the client-side key. \\ +\textbf{Metric:} 0\% leakage of plaintext assets. \ No newline at end of file diff --git a/docs/adr-tex-2/sections/11-risks.tex b/docs/adr-tex-2/sections/11-risks.tex new file mode 100644 index 0000000..2805317 --- /dev/null +++ b/docs/adr-tex-2/sections/11-risks.tex @@ -0,0 +1,21 @@ +\section{Risks \& Technical Debt} + +\subsection{Risk 1: SHA-1 Collision} +Git's reliance on SHA-1 is a known cryptographic risk. While the likelihood of a practical attack on a blog is low, the system should monitor Git's transition to SHA-256. + +\subsection{Risk 2: Repository Growth} +Every draft save creates a permanent commit. Over years of active use, the object store could grow significantly. Regular \texttt{git gc --aggressive} and ref pruning strategies are needed. + +\subsection{Technical Debt Summary} +\begin{table}[H] +\centering +\begin{tabular}{lll} +\toprule +\textbf{Item} & \textbf{Priority} & \textbf{Impact} \\ +\midrule +Automated ref pruning & High & Reduces repo bloat \\ +Retry logic for CAS conflicts & Medium & Improves concurrent editing \\ +External index for large ref counts & Medium & Improves \texttt{listArticles} performance \\ +\bottomrule +\end{tabular} +\end{table} diff --git a/docs/adr-tex-2/sections/12-glossary.tex b/docs/adr-tex-2/sections/12-glossary.tex new file mode 100644 index 0000000..c685e93 --- /dev/null +++ b/docs/adr-tex-2/sections/12-glossary.tex @@ -0,0 +1,12 @@ +\section{Glossary} + +\begin{description} + \item[AES-256-GCM] Advanced Encryption Standard with 256-bit keys in Galois/Counter Mode. + \item[Bare Repository] A Git repository without a working directory, typically used on servers. + \item[CAS] Content-Addressable Store (or Compare-and-Swap, depending on context). + \item[Commit] A snapshot of the repository at a point in time. + \item[Empty Tree] The unique OID (\texttt{4b825dc...}) of a tree containing zero files. + \item[Merkle DAG] A directed acyclic graph where each node is identified by the hash of its content. + \item[Ref] A pointer to a Git object (e.g., branch, tag, or article slug). + \item[Trailer] RFC 822 metadata at the end of a commit message. +\end{description} \ No newline at end of file diff --git a/docs/adr-tex-2/sections/A-commands.tex b/docs/adr-tex-2/sections/A-commands.tex new file mode 100644 index 0000000..46c2d29 --- /dev/null +++ b/docs/adr-tex-2/sections/A-commands.tex @@ -0,0 +1,21 @@ +\section{Appendix A: Example Commands} + +\subsection{Draft an Article} +\begin{lstlisting}[language=bash] +echo "# My First Post" | git cms draft hello-world "My First Post" +\end{lstlisting} + +\subsection{Publish an Article} +\begin{lstlisting}[language=bash] +git cms publish hello-world +\end{lstlisting} + +\subsection{List All Drafts} +\begin{lstlisting}[language=bash] +git cms list +\end{lstlisting} + +\subsection{Upload Asset} +\begin{lstlisting}[language=bash] +git cms upload hello-world image.png +\end{lstlisting} \ No newline at end of file diff --git a/docs/adr-tex-2/sections/B-structure.tex b/docs/adr-tex-2/sections/B-structure.tex new file mode 100644 index 0000000..743862a --- /dev/null +++ b/docs/adr-tex-2/sections/B-structure.tex @@ -0,0 +1,17 @@ +\section{Appendix B: Directory Structure} + +\begin{lstlisting} +git-cms/ ++-- bin/ +| +-- git-cms.js # CLI entry point ++-- src/ +| +-- lib/ +| | +-- CmsService.js # Core orchestrator +| +-- server/ +| +-- index.js # HTTP API server ++-- test/ +| +-- git.test.js # Integration tests +| +-- e2e/ # Playwright tests ++-- public/ # Static admin UI ++-- docs/ # Documentation +\end{lstlisting} diff --git a/docs/adr-tex-2/sections/C-related.tex b/docs/adr-tex-2/sections/C-related.tex new file mode 100644 index 0000000..77a8f62 --- /dev/null +++ b/docs/adr-tex-2/sections/C-related.tex @@ -0,0 +1,12 @@ +\section{Appendix C: Related Projects} +\begin{itemize}[noitemsep] + \item \textbf{git-stargate:} Git gateway for enforcingFF-only and signing. + \item \textbf{git-stunts:} Lego blocks for Git plumbing. +\end{itemize} + +\section{Appendix D: References} +\begin{enumerate}[noitemsep] + \item Git Internals (Pro Git Book) + \item RFC 822 (Internet Message Format) + \item AES-GCM (NIST SP 800-38D) +\end{enumerate} \ No newline at end of file diff --git a/docs/adr-tex-2/sections/D-references.tex b/docs/adr-tex-2/sections/D-references.tex new file mode 100644 index 0000000..97200d2 --- /dev/null +++ b/docs/adr-tex-2/sections/D-references.tex @@ -0,0 +1,7 @@ +\section{Appendix D: References} + +\begin{enumerate} + \item \textbf{Git Internals (Pro Git Book):} \\ \url{https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain} + \item \textbf{RFC 822 (Internet Message Format):} \\ \url{https://tools.ietf.org/html/rfc822} + \item \textbf{AES-GCM (NIST SP 800-38D):} \\ \url{https://csrc.nist.gov/publications/detail/sp/800-38d/final} +\end{enumerate} \ No newline at end of file diff --git a/test/setup.bats b/test/setup.bats index dfc1179..7f0c25e 100644 --- a/test/setup.bats +++ b/test/setup.bats @@ -117,9 +117,15 @@ EOF # Don't create git-stunts # Simulate user declining (send 'n' to stdin) run bash scripts/setup.sh <<< "n" + + # Debug: print actual output + echo "Status: $status" >&3 + echo "Output:" >&3 + echo "$output" >&3 + [ "$status" -eq 1 ] [[ "$output" =~ "git-stunts not found" ]] - [[ "$output" =~ "Clone git-stunts?" ]] + [[ "$output" =~ "Would you like me to clone it now" ]] [[ "$output" =~ "Setup cancelled" ]] }