From ed66b6bdbafc2866c2b64b8260d0cab4f928ac81 Mon Sep 17 00:00:00 2001 From: t Date: Tue, 8 Sep 2026 23:05:12 +0900 Subject: [PATCH] docs(devlog): record the provider runtime stack landing Roadmap, measured conflict map, mark sourcing decision, two audit rounds, secondary PR dispositions, and the delivery record for #4026-#4031: six layers merged bottom-up into dev at e2bf1672c after a green lane=all run (34231255231) on the top head 16d49ceab. Local suite/typecheck/build were deliberately NOT RUN; hosted CI is the only execution proof. Closed as _fin because every outcome it records is already in public history. --- .../260908_provider_runtime_stack/000_plan.md | 65 ++++++++++++++++++ .../010_layer_plan.md | 34 +++++++++ .../011_conflict_map.md | 24 +++++++ .../012_mark_sourcing.md | 23 +++++++ .../013_secondary_dispositions.md | 23 +++++++ .../020_wp2_carry.md | 23 +++++++ .../030_wp3_marks_docs.md | 15 ++++ .../040_wp4_publish_merge.md | 16 +++++ .../050_delivery_record.md | 58 ++++++++++++++++ .../060_ledger.md | 17 +++++ .../assets/031_l4_provider_marks.png | Bin 0 -> 30266 bytes 11 files changed, 298 insertions(+) create mode 100644 devlog/_fin/260908_provider_runtime_stack/000_plan.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/060_ledger.md create mode 100644 devlog/_fin/260908_provider_runtime_stack/assets/031_l4_provider_marks.png diff --git a/devlog/_fin/260908_provider_runtime_stack/000_plan.md b/devlog/_fin/260908_provider_runtime_stack/000_plan.md new file mode 100644 index 0000000000..c8da992329 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/000_plan.md @@ -0,0 +1,65 @@ +# 000 — Plan and live manifest + +Unit: `devlog/_plan/260908_provider_runtime_stack`. Session `01a080e2-1dfc-7082-bff8-5043215bdd35`. +Snapshot: 2026-09-08T12:00Z (fetch), `origin/dev` = `29bb221c3` +(`Merge pull request #4021 from lidge-jun/codex/release-248-record`). +Carry worktree: `/private/tmp/ocx-prs-stack-01a080e2` (linked worktree of the main checkout; +`core.worktree` unset, toplevel verified). + +## Objective + +Land the open provider-runtime contributor PRs on `dev` as one ordinary manual dependent PR +stack, integrated with the repository's provider discipline (test layout, provider marks, +docs-site sections, contributor attribution), and merge the stack bottom-up into `dev` +after a single green final-head CI run. Constraints given by the maintainer: + +- Never run the local product suite, typecheck, build, or install. Every one of those is + labelled NOT RUN in the delivery record. Hosted CI on the final head is the only proof. +- Every mutating Git command runs as `git -c core.hooksPath=/dev/null` (the repository + `postmerge` hook can otherwise install dependencies and typecheck). Push with + `--no-verify`. +- CI runs once, on the top of the stack. Merge only if that head is green. +- Ordinary dependent PR bases, no GitHub native stack registration (DEV-STACK-OPT-IN-01). +- Cherry-pick, reimplement, squash, or rebase are all permitted. Original authors stay + as commit authors (`cherry-pick -x`) or in a `Co-authored-by` trailer. +- Subagents: `anthropic/claude-opus-5` unlimited; Aside browser delegation unlimited. +- Out of scope: release/publish, `main`/`preview` promotion, unrelated subsystems. + +## Work-phase map (one PABCD cycle each) + +| WP | Scope | Doc | +|----|-------|-----| +| wp1 | Docs-only roadmap: this manifest, layer plan (010), conflict map (011), mark sourcing (012), secondary dispositions (013) | 000-013 | +| wp2 | Carry L1-L3 (CodeBuddy #3340, Qoder Global #3349, Qoder CN #3350) onto `dev` with layout registration | 020 | +| wp3 | L4 marks + display names + docs-site sections + attribution; accepted secondary layers | 030 | +| wp4 | Publish, final-head CI, bottom-up admin merge, ancestry proof, closeouts, delivery record | 040, 060 | + +## Manifest (exact head at snapshot) + +| PR | Author | Head | Base | Mergeable vs dev | +/- | Files | Commits | Draft | +|----|--------|------|------|------------------|-----|-------|---------|-------| +| #3340 | Flowershangfromthebranches | `4b705e92d` | dev | clean (merge-tree) | 2108/6 | 17 | 4 | yes | +| #3349 | Flowershangfromthebranches | `4ac98bd4d` | dev | CONFLICTING (`tests/providers/provider-connection-test.test.ts`, import-path only) | 2683/14 | 30 | 4 (3 shared with #3340) | yes | +| #3350 | Flowershangfromthebranches | `a4e805084` | dev | conflicts inherited from #3349 | 2834/16 | 30 | 5 (4 shared) | yes | +| #3010 | Liang-Psych | `2e3582328` | dev | CONFLICTING; OAuth/private-protocol design the maintainer review rejected | 1474/2 | 11 | 18 | yes | + +The three Flowershangfromthebranches PRs are already a contributor-declared chain +(#3340 → #3349 → #3350); #3349 and #3350 GitHub diffs include the lower layers because +each targets `dev`. The carry keeps that chain shape but rebases each layer onto its +parent so every PR diff is layer-only (DEV-STACK-03). + +## Maintainer review state carried into this unit + +The prior maintainer reviews (grok-bot, 2026-09-03) on all three PRs left these open items, +now dispositioned here: + +| Item | Disposition | +|------|-------------| +| AUP / terms acceptance for headless CLI proxy routing (CodeBuddy, Qoder) | Maintainer decided in this session by authorizing the landing. Recorded in 040. | +| Provider marks missing in `gui/src/provider-icons.ts` | wp3, per the Meta precedent `81a1fc1cc` (#3338): first-party SVG with source notes, or documented initials tile when terms forbid. See 012. | +| docs-site guide lacks a Qoder Global/CN section | wp3. CodeBuddy section already exists at `guides/providers.md:620`. | +| Shared `coding-agent/protocol.ts` error classification broadened in the Qoder commit | Kept in L2 where the contributor put it; audit (wp2 A-phase) checks CodeBuddy fixture coverage. | +| `qoder` promoted from free-directory reference id to runtime seed with `preserveCustomDestination` | Kept; parity test in the carried commits asserts the flag. | +| #3010 relationship | Superseded by #3350 once landed; close with credit to Liang-Psych. | +| Tests at `tests/` root | Blocker on current `dev`: layout guard. Fixed per layer in wp2. | +| Draft readiness checklist (contributor-side) | Not applicable; maintainer carries the PRs under admin authority. Originals close as superseded. | diff --git a/devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md b/devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md new file mode 100644 index 0000000000..7735d51f34 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/010_layer_plan.md @@ -0,0 +1,34 @@ +# 010 — Layer plan + +Stack shape (merge bottom-up, ordinary dependent bases): + +| # | Branch | Base | Thesis | Source commits | +|---|--------|------|--------|----------------| +| 1 | `codex/prs-l1-codebuddy` | `dev` | CodeBuddy Global/CN headless CLI providers + shared `coding-agent` runtime | #3340: `7e56b6399`, `f651611f1`, `18530f8e8`, `4b705e92d` (cherry-pick -x) + layout fix commit | +| 2 | `codex/prs-l2-qoder-global` | L1 | Qoder Global PAT provider, account-scoped live model discovery | #3349: `4ac98bd4d` (cherry-pick -x, import-path conflict resolved) + layout fix commit | +| 3 | `codex/prs-l3-qoder-cn` | L2 | Qoder CN PAT profile | #3350: `a4e805084` (cherry-pick -x) | +| 4 | `codex/prs-l4-marks-docs` | L3 | Provider marks, display names, docs-site Qoder section, CREDITS | new maintainer commits | +| 5+ | `codex/prs-l5-*` | L4 | Secondary PRs accepted by 013 triage, one layer each | cherry-pick -x | + +Layer rules: + +- Each layer builds at its own tip. The layout-guard fix for a layer's tests lives in + that layer, not deferred upward. +- Original author preserved by `cherry-pick -x` (author field + `(cherry picked from + commit …)` line). Maintainer-authored repair commits carry no trailer because they + are not the contributor's work; the PR body names the source PR. +- PR bodies use the repository template and carry the stack map (DEV-STACK-03). +- Only the top layer's head gets CI. Lower PRs are opened for review navigation and + merge order; their own PR CI may run (`pull_request` trigger) but is not the gate. + +Verification plan (hosted only): + +1. Push all layers with `--no-verify`. +2. If the top PR's `pull_request` CI skips platform lanes, dispatch + `gh workflow run ci.yml -R lidge-jun/opencodex --ref -f lane=all`. +3. Record run id, every job conclusion; skipped/cancelled are not passing. +4. Merge bottom-up with `--admin`, retarget the next child to `dev` after each parent + lands, keep parent branches until no open child targets them. +5. After the top merge: `git fetch origin dev`; every merge SHA must satisfy + `git merge-base --is-ancestor origin/dev`; `git rev-parse origin/dev^{tree}` + must equal the certified head's tree (or a diff limited to merge-commit metadata). diff --git a/devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md b/devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md new file mode 100644 index 0000000000..9c69195360 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/011_conflict_map.md @@ -0,0 +1,24 @@ +# 011 — Conflict map (measured) + +Method: `git merge-tree --write-tree origin/dev refs/pr/` and the actual cherry-picks in +the carry worktree. + +| Layer | Conflicting file | Nature | Resolution | +|-------|------------------|--------|------------| +| L1 | none | `tests/providers/provider-registry-parity.test.ts` auto-merged | — | +| L1 | `tests/codebuddy-adapter.test.ts`, `tests/codebuddy-protocol.test.ts` | Not a git conflict; layout guard (`tests/test-layout.test.ts`) rejects root test files since `260905_test_modularization_and_windows` | Move to `tests/providers/`, rewrite `../src` → `../../src`, `./helpers` → `../helpers`; register in `scripts/test-layout/layout.json` `explicit` and `tests/fixtures/test-layout-expected.json`. Commit `769e4208f`. | +| L2 | `tests/providers/provider-connection-test.test.ts` | Import block: dev moved the file into `tests/providers/`; the PR adds one `setFetchQoderModelsForTests` import against the old path | Keep dev's `../../src` paths, add the Qoder import at the same depth. | +| L2 | `tests/qoder-adapter.test.ts`, `tests/qoder-live-models.test.ts` | Layout guard, as L1 | Same move + registration. Commit `094cb93d0`. | +| L3 | `tests/providers/qoder-adapter.test.ts`, `tests/providers/qoder-live-models.test.ts` | The CN commit edits the same import lines the L2 layout commit moved | Take the CN import set (adds `QODER_CN_PROFILE`, `resolveQoderProfile`) at the new depth. | + +Auto-merged without conflict (git content merge, needs the wp2 audit to confirm semantics): +`README.md`, `docs-site/.../guides/providers.md`, `docs-site/.../reference/configuration/providers.md`, +`src/codex/catalog/provider-fetch.ts`, `src/providers/registry.ts`, +`src/server/management/provider-routes.ts`, `tests/adapters/adapter-*-conformance.test.ts`, +`tests/adapters/adapter-registry-authority.test.ts`, `tests/providers/provider-registry-parity.test.ts`. + +Known dev-side drift since the PR base (`81a1fc1cc`, 2026-09-03) that touches carried files: +provider namespace ownership (`bbea77a48`), Nous catalog limits (`5cd71ec91`), OrcaRouter +PKCE (`c41232aa5`), keychain restore ownership (`924b65799`), BigModel repairs. The wp2 audit +reads each of these against the carried edits in `provider-fetch.ts`, `model-cache.ts`, and +`registry.ts`. diff --git a/devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md b/devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md new file mode 100644 index 0000000000..519fca9072 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/012_mark_sourcing.md @@ -0,0 +1,23 @@ +# 012 — Mark sourcing decision + +Research agent (claude-opus-5) verified on the public web, 2026-09-08. Assets held outside the +repo at `/tmp/ocx-marks/` until wp3 commits them. + +| id | Decision | File | Source | Terms basis | +|----|----------|------|--------|-------------| +| `qoder` | ship | `qoder.svg` | `https://qoder.com/favIcon.svg` (declared site icon; 73,379 B; viewBox `0 0 206 206`; byte-identical on `qoder.cn`, `qoder.com.cn`, and the schema.org Organization logo URL) | Qoder ToS (BRIGHT ZENITH, 2026-04-29) reserves rights generally, no mark-use prohibition; same posture as `meta.svg` | +| `qoder-cn` | ship, shared asset | `qoder.svg` | same file | CN agreement (通义云启(杭州)信息技术有限公司 + Alibaba Cloud, 2026-05-20) §五(a) reserves 商标 rights without restricting third-party use | +| `codebuddy` | initials tile, documented | none | mark exists (`…/web/ide/logo.svg`) | CodeBuddy service agreement §9.3 "Tencent Logo": no use of Tencent brand features "under any circumstances" without written consent | +| `codebuddy-cn` | initials tile, documented | none | same | same clause on `codebuddy.cn/document/term` | + +Wiring consequences: + +- `gui/tests/provider-icons.test.ts` derives the asset stem from `providerId.split("-")[0]`, + so committing `qoder.svg` fails the unwired-asset check for both `qoder` and `qoder-cn` + until each has its own alias row (the Meta commit pinned both ids for the same reason). +- Do not mask `qoder.svg`: light plate + dark glyph, both neutral inks, 94.5% opaque; a + mask collapses it into a filled box (README "plate problem"). +- Display names: `qoder` → "Qoder", `qoder-cn` → "Qoder CN", `codebuddy` → "CodeBuddy", + `codebuddy-cn` → "CodeBuddy CN". +- The CodeBuddy refusal goes into `gui/public/provider-icons/README.md` because no test + can detect an absent mark; without the note a later pass would re-fetch the logo. diff --git a/devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md b/devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md new file mode 100644 index 0000000000..07f7937551 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/013_secondary_dispositions.md @@ -0,0 +1,23 @@ +# 013 — Secondary PR dispositions (bounded triage, read-only) + +Method: `gh pr view`, `git merge-tree --write-tree` against `origin/dev` and against the L3 +head `85ad0a29a`, blob reads. No bun command run. Triage agent: claude-opus-5. + +| PR | Author | Size | Conflicts vs dev / vs stack | C4 surface | Maintainer state | Layout | Verdict | +|---|---|---|---|---|---|---|---| +| #3990 Hermes source-preserving YAML | rrmlima | 5 files +106/−44 | none / none | no | approved ("머지하세요") | already mapped | INCLUDE → L5 | +| #3988 Gemini model-tail continue nudge | rrmlima | 2 files +51/−14 | none / none | no | approved after CI | already mapped | INCLUDE → L6 | +| #3833 Command Code native integration | rrmlima | 9 files +256/−4 | none / none | no | stale review mostly fixed | layout trap: `command-code-client.test.ts` seeds to `providers` (`layout.json:14`), explicit `clients` entry would trip the seed-mismatch check (`test-layout-tooling.test.ts:282`); needs rename or `pinnedOverrides` — design call | DEFER | +| #3952 openai-chat freeform + Moonshot Responses | yxr1995-maker | 9 files +467/−11 | none / none | no | "지금 형태로는 merge하지 마세요"; bundles three changes; `apply-patch-envelope.ts:51-59` fence stripping can truncate legit bodies; flips `moonshot` adapter default | DEFER (split required) | +| #3639 EntraID for Azure Foundry | chrisoro | 39 files +590/−62 | none / none | yes (new `@azure/identity` dep, new credential path) | hygiene-blocked, security review required | — | REJECT for this stack | +| #3283 Antigravity pool + Gemini 3.8 | vanch007 | 14 files +960/−53 | 2 / 2 (`responses/parser.ts`, `server/responses/core.ts`) | yes | "merge 비추천"; competes with #2562 | — | REJECT | +| #3282 Copilot context tier | Simon-Opopeee | 39 files +521/−14 | 8 / 8 | yes | provider guard missing, screenshot missing, hygiene-blocked | root test file | REJECT | +| #2230 Gemini OAuth accounts | ppvia | 33 files +1637/−61 | 16 / 16 | yes (embedded OAuth client secret) | maintainer-sponsored security review mandatory | unregistered tests | REJECT | + +#3990 and #3988 are pairwise clean with each other and with every other candidate +(`merge-tree` exit 0 for all combinations). Both are runtime-scope, no auth/credential/workflow +surface, and the maintainer already approved their content. They become L5 and L6 above the +marks layer, each cherry-picked with `-x` to keep rrmlima as author. + +DEFER/REJECT items are not closed by this unit; their disposition is recorded here for the +next triage pass. diff --git a/devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md b/devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md new file mode 100644 index 0000000000..32677407ec --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/020_wp2_carry.md @@ -0,0 +1,23 @@ +# 020 — wp2: carry L1–L3 with layout registration + +Status at write time: carried in the worktree, unpublished. Heads: L1 `769e4208f`, +L2 `094cb93d0`, L3 `85ad0a29a` (pre-audit-fix). + +## Audit round 1 (claude-opus-5, adversarial, read-only) — NEAR-PASS + +| # | Finding | Disposition | +|---|---------|-------------| +| 1 | Qoder catalog branch in `src/codex/catalog/provider-fetch.ts` (4 hint calls, ~1598–1628) omits `captured.effectiveAlias`, which `45045623b` (#3601) threaded through every sibling branch. Git auto-merged because lines do not overlap. | FOLD — maintainer fix commit on L2 appends the argument to all four calls. | +| 2 | `tests/adapters/adapter-tool-conformance.test.ts` exempts `codebuddy`/`qoder` with a bare `continue`; a future tool bridge would keep passing silently. | RESIDUAL — v1 contract is `--tools ""`, documented in registry notes and docs-site. A guard test cannot be validated locally under the no-local-suite rule; deferred to a follow-up that can run it. | +| 3 | `src/adapters/coding-agent/protocol.ts:198` matches bare `authentication`, so vendor text like "authentication service degraded" becomes a 401 `invalid_api_key`, which drives reauth messaging and key-pool rotation. | FOLD — anchor to credential verdicts (`authentication (?:failed|error|required)`, `unauthorized`). Existing fixture "Not logged in; invalid token" still classifies 401. | +| 4 | `qoder`/`qoder-cn` seed `noVisionModels` with the full roster, advertising image input the adapter rejects. | REBUT — this is the repository convention (`registry.ts:912`, parity test :388, CodeBuddy CN roster §二十九): membership routes images through the vision sidecar and the fail-closed strip applies to every such provider. The adapter's 400 is the defense when an image reaches it without the sidecar path. | + +Non-blocking notes carried: CodeBuddy Global roster has no `noVisionModels` (static, vendor +manifest); `docs/qoder-cli-provider.md` lives outside docs-site (kept, wp3 adds the published +section); `--effort` vs `--reasoning-effort` rests on vendor manifests. + +Clean under audit: registry contract shape, seed parity fields, `qoder` free-directory +promotion + `preserveCustomDestination`, `authorityIdentity` backward compatibility, +connection-test path ordering, layout-guard JSON (delta is exactly the four new keys), +privacy (PAT redaction, allowlisted child env, SHA-256 fingerprint), CI path (no docs-site +build or provider enumeration on `pull_request`). diff --git a/devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md b/devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md new file mode 100644 index 0000000000..0093ab15f1 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/030_wp3_marks_docs.md @@ -0,0 +1,15 @@ +# 030 — wp3: L4 marks/docs/credits, L5–L6 secondary layers + +L4 `codex/prs-l4-marks-docs` (maintainer-authored): + +- `gui/public/provider-icons/qoder.svg` from `/tmp/ocx-marks/qoder.svg` (verbatim). +- `gui/src/provider-icons.ts`: aliases `qoder`/`qoder-cn` → `qoder.svg`; display names + Qoder, Qoder CN, CodeBuddy, CodeBuddy CN. No CodeBuddy asset (012). +- `gui/public/provider-icons/README.md`: Qoder provenance + CodeBuddy refusal note (012 text). +- `docs-site/src/content/docs/guides/providers.md`: "Official Qoder CLI (Global & CN)" + section after the CodeBuddy section; reference/configuration adapter list adds `qoder`. +- `CREDITS.md`: not needed — original commits keep the contributor as author. + +L5 `codex/prs-l5-hermes-yaml`: cherry-pick -x `a1fe9caeb` (#3990, rrmlima). +L6 `codex/prs-l6-gemini-tail`: cherry-pick -x `1837b8f99` (#3988; commit author is +`root`, so add `Co-authored-by: rrmlima` via the PR body/merge commit). diff --git a/devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md b/devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md new file mode 100644 index 0000000000..cf056aafcf --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/040_wp4_publish_merge.md @@ -0,0 +1,16 @@ +# 040 — wp4: publish, CI, merge, prove, close + +1. Push six branches `--no-verify` with `-c core.hooksPath=/dev/null`. +2. Open PRs bottom-up with explicit `--base` (L1→dev, L2→L1, …), template body + stack map. +3. Dispatch `ci.yml` `lane=all` on the L6 head; record run id and every job. +4. On green: merge L1 with `--admin --match-head-commit`, retarget L2 to `dev`, repeat. + Keep parent branches until no child targets them. +5. Fetch `dev`; assert each merge SHA is an ancestor; compare `dev^{tree}` to the certified + L6 tree. +6. Close #3340/#3349/#3350 superseded (credit Flowershangfromthebranches), #3990/#3988 + superseded (credit rrmlima), #3010 superseded by the landed Qoder CN PAT provider + (credit Liang-Psych). +7. Write 060 ledger; move unit to `_fin`. + +AUP decision: the maintainer authorized landing these headless-CLI PAT providers in this +session (2026-09-08); recorded here as the maintainer decision the prior reviews asked for. diff --git a/devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md b/devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md new file mode 100644 index 0000000000..8ada5b0bc6 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/050_delivery_record.md @@ -0,0 +1,58 @@ +# 050 — Delivery record + +Snapshot: 2026-09-08T14:10Z. `origin/dev` = `e2bf1672c` (was `29bb221c3` at unit start). + +## What landed + +| Layer | PR | Merge SHA | Head SHA | Source | Author credit | +|-------|----|-----------|----------|--------|---------------| +| L1 CodeBuddy Global/CN | #4026 | `b77b05aa5` | `769e4208f` | #3340 (4 commits, cherry-pick -x) + layout move | Flowershangfromthebranches (author field + trailer) | +| L2 Qoder Global | #4027 | `753ecb813` | `5adf130da` | #3349 (cherry-pick -x) + layout move + audit fix | Flowershangfromthebranches | +| L3 Qoder CN | #4028 | `07ac34b2d` | `615c5c62c` | #3350 (cherry-pick -x) | Flowershangfromthebranches; Liang-Psych trailer for #3010 direction | +| L4 marks/docs | #4029 | `9f0721299` | `6ba1e6750` | maintainer | — | +| L5 Hermes YAML | #4030 | `5bb8faf7b` | `295bcf82b` | #3990 (cherry-pick -x) + fr/zh-TW sync | rrmlima | +| L6 Gemini tail | #4031 | `e2bf1672c` | `16d49ceab` | #3988 (cherry-pick -x) + single-owner fix | rrmlima (trailer; carried commit author is `root`) | + +## Proof + +- CI: `ci.yml` `lane=all` run **34231255231** on `16d49ceab`: 26/26 jobs success. `windows 4/6` + failed once on `tests/codex-integration/token-guardian.test.ts` afterEach `EPERM rm` of its + temp dir (a file the stack does not touch); same-SHA rerun of that job passed. Earlier run + 34228268757 on `ba3912ce8` was cancelled when the head moved and is diagnostic only. +- Ancestry: all six merge SHAs and all six head SHAs are ancestors of fetched `origin/dev`. +- Tree: `origin/dev^{tree}` = `2201b9e54…` = `16d49ceab^{tree}`. Landed tree equals certified head. +- Hygiene/enforce-target: green on every PR before merge after two repairs (trailers moved to + the body end where `pr-carry-attribution.cjs` reads them; L4 got pinned icon tests for + `missing_regression_test` and a before/after screenshot for the GUI gate). + +## NOT RUN (by maintainer instruction) + +`bun install`, `bun run typecheck`, `bun run test`, `bun run test:changed`, `bun run build:gui`, +`bun run privacy:scan`, `bun run lint:gui` — none executed locally. Every Git mutation ran with +`-c core.hooksPath=/dev/null`; pushes used `--no-verify`. Hosted CI is the only execution proof. + +## Audit dispositions + +Round 1 (L1–L3): blocker 1 `captured.effectiveAlias` folded (`5adf130da`); blocker 3 auth regex +folded (same commit); blocker 2 tool-less conformance exemption → residual, follow-up; blocker 4 +`noVisionModels` → rebutted (repository convention). Round 2 (L4–L6): double `(continue)` nudge +folded (`16d49ceab`); fr/zh-TW Hermes contradiction folded (`295bcf82b`); seven locale copies of +the adapter list still stop at `azure-openai` (predates this unit; residual). + +## Closeouts + +#3340 (auto-closed by merge; credit comment added), #3349, #3350, #3990, #3988 closed as +superseded with credit; #3010 closed as superseded by the PAT design with credit to Liang-Psych. + +## Secondary PR dispositions (not closed) + +DEFER #3833 (layout seed trap, design call), #3952 (split required). REJECT for this stack +#3639, #3283, #3282, #2230 (C4 surfaces, conflicts, or maintainer-required security review). +See 013. + +## Residuals for a follow-up + +1. Guard test proving `codebuddy`/`qoder` still expose no tool catalog (audit round 1, blocker 2). +2. Locale adapter tables (ko/ja/zh-cn/zh-tw/fr/ru/tr reference/configuration/providers.md). +3. `docs/qoder-cli-provider.md` lives outside docs-site; consider folding into the guide. +4. Windows shard flake: `token-guardian.test.ts` temp-dir `EPERM` on cleanup. diff --git a/devlog/_fin/260908_provider_runtime_stack/060_ledger.md b/devlog/_fin/260908_provider_runtime_stack/060_ledger.md new file mode 100644 index 0000000000..cc5dbd4977 --- /dev/null +++ b/devlog/_fin/260908_provider_runtime_stack/060_ledger.md @@ -0,0 +1,17 @@ +# 060 — Ledger + +| When (UTC) | Event | Evidence | +|-----------|-------|----------| +| 2026-09-08T12:04 | Goal created; goalplan wp1–wp4 registered | `.codexclaw/goalplans/land-the-open-opencodex-provider-runtime-contrib` | +| 2026-09-08T12:06 | Worktree `/private/tmp/ocx-prs-stack-01a080e2` on `origin/dev` `29bb221c3`; L1–L3 carried by `cherry-pick -x` | heads L1 `769e4208f`, L2 `094cb93d0`, L3 `85ad0a29a` | +| 2026-09-08T12:30 | wp1 roadmap docs 000–040 written; audit NEAR-PASS (020) | this unit | +| 2026-09-08T12:35 | wp2 audit fixes on L2 (`5adf130da`): effectiveAlias ×4, auth regex anchor; L3 cascaded | 020 | +| 2026-09-08T12:40 | wp3: L4 `76c8a0b0b` (qoder.svg, aliases, names, README, docs-site), L5 `a49d1ad92`+`48666541b` (#3990 + fr/zh-TW sync), L6 `7bd84795b`+`ba3912ce8` (#3988 + single-owner nudge) | 030, audit round 2 | +| 2026-09-08T12:48 | Pushed six branches `--no-verify`; PRs #4026 (L1→dev), #4027, #4028, #4029, #4030, #4031 (L6) with explicit dependent bases | GitHub | +| 2026-09-08T12:49 | `ci.yml` `lane=all` dispatched on `ba3912ce8`: run 34228268757 (+ PR run 34228261835) | Actions | +| 2026-09-08T13:02 | Hygiene gate: `missing_coauthor_credit` on every PR (trailers were inside the Summary, gate reads end of body) → trailers appended at body end; `missing_regression_test` on L4 → pinned Qoder/CodeBuddy icon tests added, L4 amended `6ba1e6750`, L5/L6 cascaded, force-with-lease pushed | GitHub | +| 2026-09-08T13:24 | New top head `16d49ceab`; `lane=all` dispatched: run 34231255231 (first run 34228268757 on `ba3912ce8` kept only as diagnostic) | Actions | +| 2026-09-08T13:55 | Run 34231255231 (`16d49ceab`, lane=all): 25/26 jobs success; `windows 4/6` failed on `tests/codex-integration/token-guardian.test.ts` afterEach `EPERM rm` of its temp dir (remove-tree retry exhausted). The stack touches no oauth/guardian/remove-tree file. Rerunning that job at the same SHA. | Actions | +| 2026-09-08T14:00 | Run 34231255231 green 26/26 after same-SHA rerun of windows 4/6 | Actions | +| 2026-09-08T14:07 | Bottom-up admin merges: #4026 `b77b05aa5`, #4027 `753ecb813`, #4028 `07ac34b2d`, #4029 `9f0721299`, #4030 `5bb8faf7b`, #4031 `e2bf1672c`; `origin/dev`=`e2bf1672c`; tree == `16d49ceab^{tree}` | 050 | +| 2026-09-08T14:09 | Originals closed with credit: #3349 #3350 #3010 #3990 #3988 (#3340 auto-closed, credit comment) | GitHub | diff --git a/devlog/_fin/260908_provider_runtime_stack/assets/031_l4_provider_marks.png b/devlog/_fin/260908_provider_runtime_stack/assets/031_l4_provider_marks.png new file mode 100644 index 0000000000000000000000000000000000000000..18f4797503fd4c4885df4e8d34c05487e8de1324 GIT binary patch literal 30266 zcmeFZcRbeZ-#>n~u1cDOvWh|yB?;M4_TDqH_s-Trs3a>ZD|?eF$MHIz>vaSu$X(t|a+ribAncZu5K|%$ zwptMgo1}JZ#w&IDdj150%O*)N5f#_isXjLyvaa>>Kcd)!p-D2&{e?3fCIHF}G_{Hmncf8DG7nncuQd=7uif$qhDlAe`QhYq_YOvXamf>=^ z{5nU=@qc{%*bv#b?e}*Ho3<+c{)TW^`2WzCz9^hJLQX=-uA`x-D56Ln)5Olk#((WQ zjem7U+~VTQV3BD{V69pJa}L?`>ko2KA!w?``o8e$7@qP;)>+Kb-PGO zE8J$k%};b`JH%}wBn*o&ypPoPHn*~pQB;wYm96q#W0H-2qQG+V)-A~`i3%(-va+Au zMrbcyyx69vQ{k$3?0_P9XY%FXnZdeW-}_eT=zX5%=Tix|b2Wq-Jj&57k&ERy!^&z= z?YEmDL?Vv5`gEoH{Li_$$@Vn)DW|X1dxf5`WWGwG7xZ*po*PS(k5?i;=QOIo!NIX7 z?Zz9eV+X81zwp8zb4XXX&yNo`MjCS-@~^hPcCDnO#P$bUh{RLJk>>Ta6-o+0)8qa&?8N0@x=QDX50B1V?GOpe$jA^)Os6eNcT6@f z^VwJrWtP8x|9*s2O0o3O+oA?*Nx}3&f^I*Da9bnazB%yF(9_eOKVPzolAUYa-Xc;} zNlBD7A|_^Kc_MEwEnnDH#o}Of%E$)~gx8IVx~E^P*tocGGq4b@yWDIU$GS6`b#^Le#OIrP@%4g$k_(?fAIoXT@C!!mNf4WvM%Rhc_*=uHIW^8QC$HQi= z(2w+x!$@=7#`>=+T&+sivsdy`hNt!QKVzYUg@vW693&8W4g}R6K4U0mU|=vM7M=Rp zbGE52m|mGY{K13M#&5|nKo4z9P0zbbeyphxJ9+YChDxSQW3F!bw=Z8>uk7cN?Zwk} zb;VSkv7Ja}FH23m#1!g0-5;04!XA0S?Wd8c>4=Hv%OFaQ7c1Y(pU5}V*PD%ZWN=1h zA6g<1gtO+vGBD5s)&5=P4>Z^!;^K7e?au_)FSGW^8JDZRV@^ z9{;mfUS1y>GUAR|E4=x0c2+W|c5p^;@ynKn8mg)X>FD~eymu&F#mHdfn;RNVu(LNe zHsZ1^zxrqDMr34+MV&R32yTCH^y2uOaYhiM4=$eS(4jbfx59vJn+U?%nHd>NQzf6- zPMxx3#*)ZV&x?+UX*4SQ`SYju+H$9N*PAy?$B+A_j_qf>q*LzF)YVmzn)+>Fs<*$t zpTzg8@wSjl_wMTK*tzp)fV;c9bR@fVzL{YB^!M-UP3J$8((tr?`t+%%r|eao%e_#k zl!FHkrlzKjhxKzj=qk1p4gA36Lm-%$?^C_-u%WT>g2w{e^tOlTX=&;T3U*lFZ_but zN!>kk77s8xJDY@rBr`Mfw&+0Po>cQ_gGYQ9$Hu$TT;88Jal&VH#vi2&H$3`2Sy@S` zeqZ_bzH-d(H*emoTWdah_Uza6XXZSgjkRl(l#x%KJozhV(2j?nPM(E)d~8fpQxkJu zzWO9~x*Tz)(2&I&22_@o6W99PF0XHv%uY|II(Upa*;8~Joj30*;rqj zpPQ?%$oMP7FL~i~RnK8I_fOC5886@W{P9J^#>Pfe^!0Q5!AtiJiz{}Z?6K>XkyBAE zme7a3OH^VFx8lBV^5jHK02yg@e)r_TlWHA#JEO?vOWZbNs=NzO8k}(*7u&mcua}os zhKiI;yNQX(($dm6<0&?_`t*ReZ{N1HDM?F9U${_?=fd9E7*^BoCuM4l9eT`7*wGYuB#8B=5EPF5f)z3?@Go$Z}}0hI{|&yM{gYn7_xb?;*#n&kYX@>?b3;7_k^Cam?P{-uA_k z$=RQq2-iQvk##1FkB?&~xJ!Nhdu!rF%xV(f*L{7u`ug!n>DclzDPJVBjAIiUd~e;{Iwh*2=^3%1nv`k|z#d|N0 z;gU*qzH?NqiY^pjtzA}7c(BZykdtFABXc)2luWjrgF3P9v<$Y!Z||bo%dgpnNT`@H z9nkz*@hS=6W$^1)R#w(9DPwFxYin!zY6hh`dL9Koi!Hk{^)bw`sbiQ|tmGtg!KSvh z@?}M+nkPq1-e~~PwU(uldfU8J0Q$UsUm$kxABY$Fe+1b3qR?YvXqYt5j|D@^dg@dP z-}Be6U#silvdwm(=1p?`B5*833x!w9Qe&kkf zUB%eHfeF7~a1+7lL@LK?X6wF<;&J%Zk_QsA5m6Kaai}#5g zy}6k%`jt0Stw&vwnm4thTHeMxv(@nTt zS!rjyiNJS8Ze?%0Mf`mQ{7sMJqRNWXZSaJ+gIO2F6tr5l09~(TwICpRN zM;}4eW2;(A?PEWq4}Vkb+Jy^bf2s-6Fz%5=I^XTl6|<*!|K##a!|UC?18HxW@1I+A zceAB%uO}o->?iS+j$kwY`f9rJ*W-|o5Cs;UXI7fZ_kYdKYFD`0V_!Iz`7kAA7$u*J zFNN%4%r-&-(}4hPtB9*@S-m2pdw<3(my72Br2PV&3yIMn)Yuso16Ri z@#6{Q)CaG;mDA*8B_*SH>(C&(6-y#bp6yt1DacVp}A;?qMn_ssjfe zhKCPNPSViOfC!NtI3Tz(c~(fM3M>ef5LG)zw_Gi*^R@3T;Mti@b$w$KlRebjR<(f# zi8WGOG5OLxt*2&+xQks`B!sx&7cbU9+{&*_vxi97e0qMyEy*x1leNmUgv=Tu=G|8FSuhmo^WVG*a>AGn&y@1DtcPlQ=tvxDi@FJOAmVP zG^R8~CeEOUJ5La~#dYrmU;GD~qG#54v5+<;(sORZfTU*CHdi30T&D~iIx3_24F70BA&X+f~w70k4x^-*I z=FKdDWu8kvUwEwmP-<(a5=K425b?)BK|#3T(9m|^(eDgv4C$D zBlomxYD%KO^d<7dtk$T4A+fdB*Ra)>M9nsb!z;d(NH9tnE6PmzI> zu8+QFR9Ej(zjm}YNX@$FiPD(7&>FE=0SWsjv1n`e0*U|lVV9w@3@&cxKAQF0rq54nAND?NQYK(&U3#=E!+>WK=s z{r#26K_&nKjcje>!@`_^eTZnCDU_FwFFHCp^K45~QyjPTVYgF}jlh7*4b1T@;h>-O zi;If^WXvBLh)=G!#8$u5;kdZs%EDBZ@;#uLte}sT9@nPGMu1&_@6MVwJN+E+6cykW zR}6o+;qm11oh%hk+UUka?T07~yzwnqD2i!VK2b?5Sg4Rr@Y!;B5eU2R>C>SZR}97Y z9BTDLXbu#BVHaE`pD#tW2(DxUZ;^|yEseyV$~Z=FQsd*}^IDz*1}3RKP2$UN>eRi| zF)Sq1c#fOj9L&<+?Yw{YV-|{_`T2SMT2(83t>UJ) zjg6rVMkr`XX%Ai&CnN~7hVxyxkkx+q-r?}LxVX?z#>hs?G!IwT2b8$~0|7?eg~qqm z3ym8o+O$FfBSYUuOkzv1ea1VBTI(L+tV^r^SJ^70+K`?1+W^@U^IXB z=#Ycknnik$*$***$&mDvi(7g;`*1gmcMb6c-B%X;}|$Y-d4D5|F{e-3s|RL~fS=&UcjXVm6; zu0y@v9+NgfM3qh$*IC;!`s=} zSy3@$`7|XZrJn)RLr&KpR|1p#_RvZ_p6xsu+Cb$uFuOD)ADxQlEdF>LYv^HlcOz#; zZf>sr?)mcFkJIz=I4FX8hYE`=b9ziPH8g&>R($qek&T0}B6dl2$JU!Y$*f9BN+_%n zK7-*W)jP(pyDFI;-?sx(DrX}}fd%S?w#G%mXpJlXV_>A(AWBu%aM8pg$pw%$BOg7I z@H=(v`0?(Zo}Wvez`qU}&=Wm9S7#HO1w8bsyyKG6!4d&AKD6i@arN%at_?;Mszl6An$G2a!anCEJcBnQt70r440hD!Jrzci$^Vc zO)IND>3auhPNMQF4g!Kmde1>`8KRdm5gF$c(GsdTJ-OM&>a;KL2CjqGv6h%FeAf z&D&GAZQov`!A4CTqwlj8zRGvh(%Y)PA}ZA!ubfoRMd7sVeRhvVz76#kYQz(|o9z2` zp!gP9bh2isSXf%d#Klz_H%9bqfjl(6YsU^ANMYCoNl8h8kMIn!?5-Lba@+RHD3WWA z7cCfwCbo8WmnI}!fzE|1h8{QGxplng=~E0|;=OyjcYXwZSeWn9mp=CJ#+L05t*9HG zc%M6VAYi#~nOV?tG2c3(B~eyJCfchIGzjH#uuh|D&8MYh{49CluN)siv!5f2rooR{ zo~_R=NgY04WF*Z^$t@UhY-Lj0M_T}3*mdSBAY*8QBA7IIx09XS1E~}d5s~%vb>ddX z!t$}imR|FWniqd?UAgCygO$}JM4c>>C-}Gei`ly{GoxANGIt-+e9}Fbwwv!Qk6d^Y&c5${y~$ zW}6Z&LZrp5TYdGDleJ%4o`>p&AyLk;#RMbj#boLumQv-da<|e)1{-&O6q$CS7SL(= zcwJX7W3vC=tmA4?l~-n0*pbZp&?fN}njq2cxQWoCx=)Ux& z9+8eLn&!*=Sqe5nI%R7=HhP+GL{x07HqL$ZsVynoDEUE75WcLgshQD7l!He{%`)eQ zU$p+U&6(V+2(0-m7gvYjR`JS5;qS^&z;LCJk z6S#16kM6!s_gwudxrkW2YBn-CHDzfVfp4dzvN-Jf?>0#19g_#IG?CGBKMuj|W!60F zuK@fUU!!(C4B)DD`^yqR59iHF26yx+fUGJ}&x@I#{3)^(tUgCpJ7h1Bg*RtTQA8Y> zY58nJ-MKi1zqYEEC6pFEaG#=+{D zn3zsAfa3D)CL;@lu$NiMdF~vPKF`i#T&7E6etv65$J6e#WadBYJYn}O7N<+la95`N z7+MeEl2n4q6Q8z|`GR351WoMQPk!U~cPFjvx26;ic-~2d-jKbATx9>B??kP|6nZ`} zOVM6-&Q1lTj?NkEU+A>IeA@E84)=&s6)-{S6Uuk|{eL~Jn7N?6C>dRwyMbBfX%(Bjs2>f?v z@kbz0YoG{9QOaurGs}>Rc(xSX0^l%$#YswSzyvd;u4&koUqZRT2sij)9ks7FZM`mR-xC4 zw-~QhRTa8}m5uFPN5>re7^MuAzQZT<6@<>e~lR#Vr=_;&( z@hyf0tS3(zb4I0FN60W`WoH`|Xm|?J>yr^@`nZS+WWN`yKcxecY7Ec#R~r;{KM8g#Sta`8$Vt9OP)QjhtE zTb+cje0i86eVLE<1UX57m{OW1w0%#(jbNemAM^9pzi)8^ZF;x4UI?H>^QFn?=l*4EUB>hNIzC;S~3u{a`hZj;8ix%FG^V$Cc^#GaUm1Nrm{&4QHOT2MEwO{Q zpqT_}F9Ee4#op$bG~L+P_?Yh6S{3vCc-O{m^M*F#0}Zoj0hm82N;9q%*uBN+*;mKv z;$8XU&ihx54Grn&>N;|Mt9h%M1xetURiBg^UmMY?fOaFm&rif5(0=s2mxkd@U@aXs z<^)IqpWVLQAMa+;K`g%!>YXOxk&#fDR#um0<>LjXI`xeWd80aDz$3tb~&nUByWAWUr9ym=}ZBhhTa^&6PdFe@WLHUs!#pL_6 zLPyC-G}%57)ufi_QqvYX_>*UHa}NZFC6AR}x^!v({{4mpJjaebNl&kT^Twp%;c=py zw6XT9pc{qfX%_bc7Az3J^7692=Zr6)h>6KJ?7%2=uwKQ!9mM)yd4H*TsXlt&-tR)K z!?W1=4w7s$*P;rSQdhq=5%ECZP~PKt@Hwv22~>fNo%@4oVW+s*R?N&W$G;u=IXlu) z&}}7qdCm)>8HumqhiuJ}miQ`&sG;Yb_kiK^ zqqY$J5vxfEX!TdBpb9|4Id}ZHc-&dY=VsQQOgcL{YHDkn;)V2~s1ZT;@bt9L&mqa5 z%+;qM=b+A)6cx?R&kJ}hb4jYRhJ)l&owEq5tXxCFK}St3wRzxADg7t0GrqXk`M2JA zi_a9ZKCOCbM|6_@)6E+mJawm8*&{tTnZ8A(GZ-~ecnMUtG0XP}ERTS3szH$C@ONav&&b?kdcsBoGfZt zU0oFw6-D7i@Zg!tl$OKlzY{j$OoEChr9;~UcVXe+kf-k2Nk~YUo1ce7_Zb>VfS3b- zG72jVpHqExbuvVF(rP1PYL?{D52Fpsj#3m%;iJ+jMpPwIQ8bCU0xW)HR zrEs<|?96hpqe}WR+Rrp0a~T%6LfLd~o0^(pWMpiZh`Vs@l9*UFQ0{LV+8Ci1Hj2jH zUJq#5xDNeF_hO8qq2X6h$cCB!E=fvKn_j(oQLzI#kY7{1rsn1u_a?RyT9p_=MxnXY z*4Bc$G&GF8i#ofpIwAyC1FB^nO~+|e5AmFb=Dx%+K9CZEwBW-@Is>MZDi`;5a0Yx3OVbf5eP9yACMRcSh*q<;l==$)p)y(yW@2K!g1-#; z73v=L1xe;osLtRahF7n4TRjU7Zb3oh&@CI9n9x>HA*ZEn8n8oxM@+E;Ljdg>Cda_& z=;*+J{r6A2bivnPF<{)U&2Xfu_Oi8U9XfpYgCr%1uTlo=(@Tj8t3RsuLK#1z-wvf2 zC0O+0#lBCUP!PCnK1sAeK89P32RrPr1nPr~5Ed^>;9(xSE2^rUuWoHGvFaA}E7#W4 zH2;0&B3K?#QQgpm!lZ^FM2ab@h>3|o15T5TNmXGDrr~|~;K7%{K}WFhUAuxx9YI6#>S%Xg+6>J_n3dF`NA}|@ynO%OgMD<>HKE}=$YyUPG@d-WY!rLr6`TT zu2_LFqo`>A<>h);*&z=%k1iEUZjz*szmVWamn$nMIAi_*EN$Cn5rD|$oUkx*h;g_Z zx?te4RJkhG83u91Z{NQC7ljXNf~I*^c&80N1jS;7`k*BC%uM%*dGy8LKOriJ%%)tAp<_MlZp(||9hPw?}$)OY<4drPlABmzi zt|pY-%E}XgtSl^df`j+&+{x?sjr0)ho57i$BR4JDJC~rqgHPA0w%uIy#6Ix$trUCY ziebgp6qSq!pM~zeciE~Zg-VKxbJEiR2#rXWgZ7hi>}gZLiogJbhAP|Gu!}2lb91v% zOrTUj=te|iyl?MB@bmO|J&*XBgoK2i>LzMWyB&nq=5vK>SxOn7%CF@u?_nb+DgVOl zW&PPCDmog*IW&(4eM3N05St)OYiadhW_IK#t#Raf^GP1v*iDr5aw6|WnSVpp!Hjlp z!^hMz|GiuHvdlati+U<%ZG)AhT?-tZ1ZH8&T@0BA(W9K>R)$~ot1w- z+2GhffoJUqmcnrGT)lE9c9wTB=YyRt9ipbbEG7osxdO2QqgY7ck5yQm9UPS6zfMkO zduI}3ea_1Wj!8T@8QO67?%nTezSRS8=hCU=K>U)R=jP|zK?iT4oe`EO)9w;nM?~|}8Eq-f?sr2}D|K2_9 z1jHJ5$gdQCg?+`6o+(74t-T$P;2spo4lZ=^%>wv6L#jk!3$8Yb( zkoI$So)_9!lK1fNC_Lpae1sSi!F!uWKPxDJ@-OA;x(EyfWeD1iL>Y8M;^0s3y&-(s zv^iEaOHDFG3CjsVxl`KDi0=x+;C-9;Wl6cUY`?S5tb|O+nC*XeD*Ehtx_=)Lh7MA+Yp8+es zZ`-yF{tM&DH-+7kP=)0m^GDSU>b~&g<>q!l71^_A57=yTEH6MW(mThpQiwJvF67QcYhR;=eJM(%aLFJ?MagiR zyrY6Myloc+QeJRZAqM`yEClOi$V#aK48{E3i;S%MJZqFMl!g8~VoAU-x!NVUyWd(! zmH!yO#lrbk=kjI$r1VFR9@$oPM?H)-Vd)Zmf*{WHbw zJCn4$tel`cl&xJU(D)-BY}&NR^gy$>&zI}IzQf614S~nuQoegv?kO0bItJJI)T>v6 z0s>Xb786swhgib{Q#Hp^B^W}u$~m!BdCxYT-!HOBI8q59h`UcA?v_h$c0@-_b2B?5 z;})naPA7o!tjR=*fAK21xw(Oqhc_6(-h3)~tY*lLM`ZTfT6N2G-H#t@D+_v3Qgmw{ zv{BtvmByy--eoo(-b{CX>epxIr3%)lPcSeVhY^cFK+oW!HjvD5Bl7q%vW(-_5n>Dj zh{k1uD4sQ+Kf-$E%#7PvWmWN;EH_CRCA5{(L@ zjI^{7EZp`srOUxCQRjVbh%qFZN7oI8oFJ0V91$obOrf3kJ^x4pw6t;K;})K>5dY+} zS^~yF3SsiXojgeq)WAet3@t$^!<8R!9B`MzV>zsPfC}~g@L^8Ui|v49#rN;aVfB<5Q3m-RJn%J_brUD}*lCQAIo3Rnl5xa8mKVJlBlj8Roptu-vb6-~q<@)9SR_4#wR)q?LXN<4g34GlBcwflCA2k&8S zdZ?6<9nlEls>*tBg@cU(A&eFzo+0o<>W0~zMSBZ0*^E-Q-Jw(`MQNw6Xra^XOV$xU z2%yCfaT<&kEx@C*)TRTVgRoJYJaYzllmP69G#6a5VH<*~tT9r@x}OY@Kuy4oQC(dP zD5c33p_E}Y#Rmeb{>HEXj=qHBtYLBGU(soQkwsC`DwFu$eClO%S3gDtqsP}3i`>#E zAK$Cr|7RfSofZ6Bk&D}T6F(w;?LGooh4^KbbtDt^(Q#!UV$7KlGGnMmaGCU-PvHe! zvjH*9xxe#8PYw3@HskNjHu@B{@*g4_v*NqQan70V;NjW~wlX>-A3IqZx+F#G|?kDH3u@i(T71KL=UwpX9;{3Oi zdgnfsU`B`w`NTXV$^EHXB=Jw_#hh>c4u_EwuSxjql>o=zH}Rjh(@OZ4JN!24P!MH^Bn;-&-9wj%@~JV9mWA<=5{jEFV$fW5 zb+!j4{}EVI5joR3{5za>{r-W=#E=?6irSt$f(N;snIjwVg z`q)hvKxfaL^IDjUQejmsx%8H@BY62R={+jH5UCXGXZV=_T(7h=X1E8~woqbQMv64D z0g|I+Qq5zIhc-ZBg#;SkQr88#s#)y5kJvJS$R%?A1sd-L>^@p?n$3TukFmH>C&m^DREZIU_CsG0Ixe_yTt zY*Q?6ds|y!MMZ4m@I!J?2V}36mC05bIT{)y$HuyhIhPRl1dT21{a8R+jW~&Od&-+( z2kff=d+@&syjB)I+($3+10+eyF%Jr$nB-`n1s{vaw(&owcV) zgX=;Yhl&0J-{XM7Pt$anXBlq_>|3$c-8(=_%Ow;`Ytu~YQ zT)N82vzbCLc%0rnP6rz5QFeB8bf~DTB-s`80(OJVf;M>)QvAB3hi7y71=t-TngyMCG!JUbA7b z_256Q$9q`rK<$UlmZk0^WWQRY-7F^^!5%8{SV$Jzvr&gDmO|?%-WP&`85!#RH0$4p zEjq668QA@c96B?7a&#L9XQI_}p{Zu7W;MeKga!;i$f5IG0Xt{AjNe{*Z=ktU+kHAQ z$ibz>dml!2=ka52U@61`4j(?8IXgEy+pZ>pRrmZj68L( zZBMGT6X>3K;JUhK@8mQGIjkX` zOSUEEJjc@vFc!Ak}&4=?ctmjS9im@N^#vnKnfaW6mMXb8`YnjP^wn+H3-X zf?_aDgpVjNFN}9Ke*R4C&LGCK7N$R=Uj|)ABNG!I%X8)rb5&Tcp_9v^gT=#R1t!w- z>};91Y8dm7chM1r$pL+<LIFM^&E#ICUITem*wLZ<{wG18qo8{WQkaB%@q z!=}1(=gxSqg{b&=eF=$rkY*$iI^x99&kzf(SY6)>9f!OK4x-rwEiaRkR)I+f+Z3C< zPr_~W9Nb6Zi-1Fp@(mE<2dzO#>D%|x-S+cC&VldTxp_#e(fW#n(baz=Lwlmb0^%F? zbnHmRR7{ZPPMip689~op)T2i#s;US|2gO=K)&4%Jqpdl0O*8`pL zf239?l@*!6;(&IMrItffKi%E=%m)#j`seg)=eC0s6ly9eJbZi~GG4;3k{pEqe0|dv z3J$#rSf?fZ?v3^J60_)8ii?L*?Y-)1Z(pFm;^g4K2eAQOSB;@P66H|RWZN(Lkw%?1 zxGBcK`_F=QeJQwhKwu!Mj|ZA-P=Tx4k9*UF2{nua-Ka45rTqE<3VgJzw>wpx=iEwoRI|i zJAR8?ZQUTmf*j4FZU5+qt1>5alA-iu>kWymsg(dgBv$CEk$;?3gBPU zV`EFu#IrRDLtL^m1jvcf5^n3>9#D~R; zn}sR&9XbSekQ>A+MQN#BUMQpnZ;VW-Tnx8th6)mG$BrH)=1N|_HiRDokk$7bPX>|l z?%rPJF{npjQVFg#LFfww@)xu(G>pEyv6kn2cH!qjZpH^IaPealkM0#9^yQ+bXCX4PmhmFIiIoaHVGNAfvS!+#NzhG#>Q=% zH$^sj{rGYN)F3#Uk?{xw3b^n{wN5$h-5ZQKhUV7*u|jOW^GW1G^n~t>5anHkb`yY!8_J#JUejGd=Lk-moKb90A0Wp6E!=;E?9wp&6EGBWxkwMm;CpxO z>_B+KK&9i8Dp6)G?X9_(?PR@^IjxGZb6UJYv=p1GsmfUp8QY3ciIgKQ|y@?%m z9hUY%VhqsmvA;gBndPQ({p6B0i%wSL=mN8zV82C&C1UwH?7wPVcS>a_o!XczDv#34 zQuDU4wA5Bqd}UJ9Ks86n$f8H{BoVt8$PNN_AaQ}jJ`R)}I9p&=4Yr#LR}9wnQ_igna8y;ANFms#u0ZM)zkmk^sgg_sFW7BCQkGrcZkI%=$m6|Rl} zC3gg;K+EH+MsyCn+Dcye2+sHjp^^Jo!K>8^KVBaoCoZ`Y;cu~Vy*1*zdi83!6!Ioc zt`%RCUPF9+Oh?zK?#Ui5rM)f@%pW9x>W)WJ|J?fO)xkS=b^u-z)A@Ia(+e%O#N4oQ zY+M{Xpoag94qx=Pg8|0KnC#&*V8;VvW!$f557PC>Y$9S3dc*fNnjrwaG1qiQz7Vk| ztXS03QyX6htx+oK>PWBOr{Vp%)V7UgPpL5sC}d-a5n~X+Qs|j=V4RSYGxj>#+b6QX z?GbYOdHbFDAq14lK4*wHlvX@{{;|LRajH3rq<9cT=ZkC3vREDV#MbwC*l(dr1z0AK zc&k=_HbRH5zkd@}*XA2XV8eUCNkoN~{heL!|BrAnaz&UwNA`t9Mrv<}W96BcyvTlL z#ogP|!okJ$bm7qstRn#Yp`jtZ?HrngVl3qBT2Ir5>1hajWXK$to4cXI8j-8iu7}4h z{$!BTl`+y$h)$`{pLQXYpGoO(;hzaffS0X3@9sCtF{?$HV8st<>ZN zu>$?OH-E$};(&wCg8LnRRyItt>%Vy2*>q1)fSy$`Sz&ou=3~jm_1xUYI_xW-r3z2o zKZ3&*(0$|ygC{>fAD{xI2@^^Wk>|VWsJ)05>!C@Z`ZR*cfYGsNW*CVVvfU5+Q?zaR za}_Gh__uGVg5K?^vYT&w!9#>*indlE7NOo*&yIeo(0~bq~sS84_TR+;E4LrijAv$)!R&nkrH%kqZO+k zt}c=b%DTF1Ek5h*m>O1%N0CHsj>E=k5}j&oWtFQ_O6-tB2Tx(hUy>z-g~-hwSn6c> zw|QllA$gGUIkH}Yu*O0j-M25_b;b~xF$5lvfV~guqF3>}`2h)gBsC3RVdiPW`iQGA~+dc!pPog&bWFXy{QOKL=of9M2zSn*+yi<0m>*C@a4v zy9d8~fop@Hz~J=s=OR=2Lak-^?!;3N;G3f&|K($cJ2|D1e+3=FMC=EXTSn#+eiP3S z4|F2F82w$adwFC39=$N7*zS}z6cu`8KJ|lv~&q^lm=18Kb?ip*EplB z00hvFj5q`Y06*a)Jgz^!pd|uYpqQF8DETiCW;!Y=*ZFZ(&Rto10>lm+KJ1Q2J8|Ef z_y9S~9!;BWK=epSscmGVtq%>3{qS!fAU5bD#dH*e6T&t!CCNQmFplyB?=U34L)eQY zFfbrsX(1-=M25Mas8`~R8)9rr#}^_MlXb-y_Qy1Ra1%Lp02v7Q{ykN^@2|R8b>+5&m3$An3950eu%;Oy*DsUE%lTj+6 zXQRl1+nbuogo!Ehx_f#r4Mx#ZMF(mJU~*`bTV%^fJD0AGPQ`H^*NU_eb$#nfuL~E6 z`lfUrIlO%nb>i6!NQW~)TpUdRvhQ^~uQHO*$DMWjTtQJ0D1$IGTiP&KOCI+VdRAi7 z!Mkv<2R5FeKy<1bKV1|jER5E}SXAR|k9#Y)gK7=OMn|zp4O$XIlv-YLDxg=+%PsCG!l#lGIH`>rHM<$uCJ2o9w2M$=!L@@+QM?00It;O{Q6-+Vol60lp6T;OrZl=n+T)XT9wRF87hSu z**G}}eQ~f^9Z_KZ1X<>Tt?b5g#29ci2Z{jfR*qArj0-gI(Zv&_5c&@V)k4=e+SC-( zxp3I*@nIPwJtrB2zuFc;&UjlZ8AE^8afJSwFfqFI_y2=ftXfw7wppB*{v{fYm~}en zPJ~PbQA~dlCm#kC=bsYrzGTMli9vIGwfc#W6TO*)wQCpmkKX<5D@+tyBr=oOBk4`q zb(Dc+^Y8D})9=x8JUtt`m-w&9&KrNf9;uq1BCv%wEFyg{{eEW{lGsJgpL$>L-G9A+ zL!@-Y64h*1w00$ROtE~J*n%`VpW)(@OFfF&UE2w*;*Ts&c(!@}-|#!0!#|GIB8K0s z12d!O&rgf>{fO(y#S#_1>b^P=gR=sJHrDp%vJr%t-5;{Z z^1WRBTG)MQvv=cJ{byED2&r&e_kh1oe<~$IxP^+Ueq@%CO+(mR6;#8<<~uf1V7w}j z7pPK5E=*A%&yTE0B%7wv#!U#s$eWoTFNr+(zP8vRrWh<7g%%JB)n*SJ|HryIW(_vNYv7n=5ZvYReFS3LDDs(L^smd75Xq4+|a5ob4gsnI!mA~4C^ zy}!Z@G9}O}!l#c;8*JwFYcl!QqY|u;x%n?gC3J8^rkdlqtFSgm@S|DO=ZYSqIM?C_ zyfaRq>8t}L`UGZH+@)tZa2zGfrOo67c_8|%Pw70*cS$3QZvo^AE-J#20i@NFpQ}E@ z$HYlBU0uJ>SU5z5oCyX8u|23SIM1jK@>X%tAFD78!JWuRcxx(a4u|~CaB+b>8XbFF zR+}wwIxmFbu%{*PODL195NyOSGvyW};M5<-$I& zY~CXtGg{(Ap#U6)CIg%SF!6-gq*bBuKL`%bm;O6ZcXf5PW#gCq^G|@4AYDUn5ASv5 z5HE28&$Gy+X}r5=1QOYaK!YT5r{mj=|=n%l7 z|LxcWoGtawXC^o#L39cZ4hEb-LQqF1Rw{)d*b0K$n~_;Z2M2bY=PyTQF*fCvUF>aD zT+lke1?2SgtGsQT4`9!SKDi9Spg=wh3Z=k8WOJFjEIYZgep9j6@81{5Ekk>42>PES zkvm7e_g7wEW3%eaRNbs3dTybXRTXYuSFagMj2)i@)N&N!= z6VG~c%nD_RY=lmB={}95Vh5H!4*Y@D)n|T-qa5`ci;69qB50 zb#2LWJzKK~F<)0?qyv-we`vY?^^621azMzGtgH(N;|C@op%2hPbgP%qc0r6hF&>06 z$Z_(ku`QMbF{Vm;ft!=_;cD~}lES@&00)I^#+4sB2^6#fjcnAYvgglN@e%XV*gSILwd2H6l+2MT zzsZ7z+8!uMsW>M=g0i*oo1kP$8=892+^~D7@i3Q}0^GZQb1=dQ^Ak8?@L%K4dxcho z6+7P>sQBQXCx6&cp>7uk0rE6;%>A>|C5h9?qw#A1DQ=~R^%p;b=o z(j_fzZDRTi;{r+#dXFX&)MK1~5UrHKk9a8(|A3FazO_*L4w8twy7KVC^+sQQLw~>E zi4$XBiPIIcu%~^%$(iFlVY|W6fZ2hrbLFZU$POJXIdTmC)um9q;e;ap=sclD{mDgd z*iP_j-^i`{Vov%J!2^Po*&>|h&r|N$YNSISf+#5-mbrPu;0$10#~3At-Z2g~Ha2X& zup#VcIbalNLVd5Ns={oo0)&Ugea*cfOwlmo7f1`C{k2{|7O7mw)N zuh*bX5MCkc(zjXT@R$NH-xQ_p{}!f(1!;jK^`1XTYX0sqw3`J5HEyT({DM>$^qotl zYdB(&v>Hc4fUZNJJFj85_Gz4%HT*5uHp~U09Syk>`H1lz9FM?|)7eP3iol63w2b1+!-4cJ_%=~od11y451C^wg%O!H@k!6r#%nUTpEl6G91GWy1KfyeP!a0 z*W3TjVmAc97(web98K(6Xjf-C1onia_JAGHfE%nG5BqopC9m7c1#J*w3@2DvPIGZt z-7@FMD`d``6jwINKIzKvVcj7eaass@jF;}#H#OzNtwZpoqNXM$YxJp|o0H7T_Q3_ z7>*I$y?ZzG*9{zD@jMv0JuFi;I&Gz}fy+ac3S*b>8>!Q&Vah6iP&rWQ!ObitJ;F zL`kwuCuPYtWXTd~Rg}tBA)HJIon)6i5~0FD*+)@>RG4!@mgoJWWw!gipLwq5x^DkW zb6t}2`+b+s_x*lx=;2sO zmgifkn;}QdIM_tM{dohq7ZMKWMS~G>VoUDly0bWDhTSr%nj*M8#MuDGMTnZA-rmTX< zWP5YLW%XpKaOE}Rbb*B``^!k4Dj~~jrkGh*x2jWt9L7Z(Pu-@G6BVQ3;)RCou4$?C}^}|K3l+fMYGS`_hO(0 zX=>2P<0~NEZ{KB%NXS&jD*d|ZY95%Cs4~%RvX9~E%fO5{kktxp2CGia${)hE31cYh z8yMu?y}NAj0tkHrd2>t%Ox>q1hau=C7?eW9^HDbtmzLi9ZV7yA4D!KTCJs3WU zs*83gOjmWDE?jDUZ6>e#7`(qRSZ!wl196Csj*24C4-%0`5g{Ld7edflt**iNhJs}f zuQCPZ#8tgSos0Zy`?0)v;ZeK0ue%qz8#OlqnW!TiQ3XPB18gHiawXxU^teKW{(w_J z+*U7xM5E5q0E#dt%{1cxEF1_Ba6E*@$wr#%TtYegu|DQyWUM_XjE>54NUt-Q0xEvq zXtsgqzd=F*N&mkpyTA1H!HyRS(hQ4>Ge~+;JwDJV@ z3xAYsK;pokg{3LU?T88s(UW2%KGJVJamHn*-*@yRcoYg@RekV%QeyI7I*g(6*E!N zpwACrE_9R13S3I+r&0w20%ovvL9)g=cj-1yt!)-|U!pSvZ5`;MLw5;OTO3#rjA$S$ z!yyg`2*}*I4+b}kXPA=P%vdWBk`JXNRI|Lt{tx!6GpbX3N>8Ac@Ek(@R*5Hs=AkDF zNJrG!^%wm2gCTGtsUKECEP^h#Zf!e1R9;K&({%H4jw>(M*u9(n@KXP9x{LYGk0(aE z*T^LXas~;L$-g0AgDPMEDSQaLS0v3ew3(Y&-SHS9mWG9Ky1S2JkO6=e%3An5$8j$r zL;50on`|$jDHrY=y3}r@rPa#R;nfqK2zSlshYtbBsiR9wy9N~`&SUE=w6Fz*YlXF> zQz({}O6b_bE2aV1(@WomH3t2@AD~QMLJ$G7Xvg>)5=rW&QA)`a(*lhYvbv@gLmFGz z5~>dt^}WgScNZ$dja>3l6 z?pAU{v;>Z>y$CTmQ*q}4Ey3A8Ey>|fw|9>h^W<;Nm?dQ7UOd{qw`!NUJ=84f6#cC; zB_?Jl>~oTP_4j^8>pshe`Z*I#`Z4OpbNtWkvrtR&H=kqBetyB>dMZOfPMM9GqYan64WB`6^m6+#ouV0dxk7&U za7Ox+(}ryYGmdr!#yU>u&Q{w%WD;A{ewxj310S7Y!s6z*_S_sL!;?A-5>;Dimm0Dq zHBo)J5T5L>Vuxq{OU>rcvHFx#Kc2fJVK&aaI&sr%zMD#WBKA36{{`P!wxP`_PdwH3 zSVs|;XN8x;99@)HAELcZOizB$$8N zP=n4Iq_B`Jd8dl5H6x=&R8MmLlh5+w1EyQc%G45#pqsEPT7;cpBF3f7Lp3eQuTi>W z>;QIBbTH5UM0PrtP1)=98)N$%?TWuwX?@vV;dp@S$3@pDmh$b}%3OS2p%)d0duW|o z(a#2<1x-lvzxf7=0#$eYxZnVhNw=ioqJbmQ3?a=d#pHovo8+O2xL`4YnQV=jqwZs{@ZK`CVSO%3Pnp^Nl z;+2oWNHKE06%_A*5R$Xm2GXG=bEJZaAozlG6B7nkd-C4@uIT8kK!}cGmj6n0d?C6X z-8`R?r{&)PwjLJ2m&V zLd#l@tIEch75iQC9<57?Ir*TuAUfs=4gZ0C1hyVKeHGbBIKT4F( z9&Vr*8F4OO9uXI(a;RP~(TI1=8j7ju^T?Ui*$y#i=fYhgXxldxC1y=;B~HZagoI4M zZ#{Sr4e^;kpmCq?8yX_+tH3A1VZ{0kc zMB9J^KnQlgPOFO+j<~)mBCW*nH{ljWy8FEj9MuYkYak)~InSDro&6?TJt8V2^v3Z3 zg=DJ1L`eDT8yepMeskF+@xP~Zk|rQSVry}1FAXTgxLZl_%Q#ROZ2O}zX^aoiRcH%% z5ppszi&Q zQ`fh8U95VESM_^xY#*rA>68Ogw^!*GVZcD4+_uc-;KAJ==hfFr1Rzt7yb>nbCIy9Y z&{=r49&z&a_TD?avOd+ByMMlKYlrApTC88pDHb+3<=?Wg;hcN^+_~qtEI}6_04XV{ z^-^anH>yJ9baj>CJuZXc2cHOn>WPF~xO?Jms}l@-nG5*fn72>|jV1ieIHZp{;+TL! z7LB}kt)l8pkc)|D^zoNdOF20?p+}E_Jh*uTOC`PxM5G8X_tv35 z$fw3dZ{(d3*j~2S;nES$qx;NDh|U?yK7{4 z_?~Oee63v&TBIc;K=}0IQnhym>IS)K^tYgk*kvgTX~!e$%*jbVSe>$~4#2_TXBQO} zt?KNIosBwzjtsLPN?%)`@3Z#$M-GNQuI71EPp5|yS=^VeUYXb_MHDCMd% zdVxd(Spr5^4$<8(*#}eCWvXUyV8HEO2hy#lJZ!M$=P^}-_O^2EVJ3*nwyaR%a13Z@ zggzV`9E{ljmASib89cf9bCx)KOA|{=!mfm`0Uwe`rWTIdPlkte8#??hSi4JPXr71Qz>HPQ z;p4N64Qbv=9qqwp)j%sAPxk0L`zmDWplQ%(v_j9pE1{w4(Pe1*NL~8Nus2(ao_~RM zrKcX=CR#+%`h|;mW@wwHdx1Q_OTk}rdEdQse4j&dTB-Pmkfh{oW_CLoKM>Y0uc--U zwc;TkT6VSqdcxzx|+^>$cx7<7?gxi21S!0{V$w%h` zkGe01$sNlS6*csLm#)ujbqd=?_uwO25GpxU|2KUJ_kKGQQUB9s?}ksU@_v=d@g+n1 zY+5QIIXMrL2Q@N4zCbl#+%PPNt4NZ4trv^jczeDM3EfB5=+pl&UEbqbS2tjSKrFJ9 z^lW{mUwx79@-g&xG(o+4P}}8;3uNFCfRjNOdx*0o1vF0VeT6#wlBuK!U4o=`9;tD7 zT*bx8JLsrQ5a~oGIj+z^2Z)d%10+*SKnk1!V`DNbAovD7u9lXTfQO9q;+7d%6hkBY z7nAxivqF=7k?@Cx#u;=v$$sQ$TT9E8gj*A4#ge%93f)_9tC)k&E_rO6a_-|}?JdZJ zBoCVkJwCV>U}*hGVa`V=zW_%;SO<(+q;+QrIdI5esUS#?P}eOwC_|e2F7E~oxVcaR z!x6bm#Xg|=BK3GdACCW!m2x#8-|L-#k2=dCvMKaSHXfO>#ztA}EBN6ks&>rWWTe-j z%tx^gft!5qI_dof++h$X3k|{}4_*{d){|8Vm{zKQP9ujy2DT>7C1=nbo1cFzLCnqd6z1$U?cb(w zUjZfrT4?O``s6zIq#yjCDQ=uvot8J1>GI{gnXLWT>K#3To;Qx$48-@zoR}%?fmYp3o3OBfJI8og*mQZ% zDU5LQHf;8v@ZjU)lhsZLiqD?5!MPrDijB8{oz%91k8f~j2q}a2*lp43jEup9hY#T$ z5rrM@-GUnf*{D}WS~?xEZ6pj)6QW}k@T{+@aKfs8rwSh)w8IvF${JU8;S_+ha*}bJ z$K4-da?H@ncNlqVH8rA8L0oxE2Urglz!~~Go z#F-W2F*`qhmYxGC6UK6={jr{&9=vKS9F7yBv;Z?;jF1XGRogRP?Yo5w7VzVqI>gZp z4PBt@qN4-21GswDnk&qnhx5bH{JlJU5|{{WEiI7EpY7X9#cBkpEk{#`cZ)0a>eZF! zE2GKwjVP?7mo0AEP}THwz~-wm%*GyZi!z?O#@!&#T6F6y47Ty%rIhIL!|UEH87~^$ zZkuU#`?7m!*9M=qcZ{DXMat&X3eS(P&OWT#{%hbnCp|V$YS2a{b8K=9)%KOhNcbY? zYC3zN>Sue!e}G*Fdl4Mvm>?Mp|BxP~NwMSVn_Zew80%2SoMaUQ@%7$OV z!RM5cks(r6)^%$+I62+0jEA}Jz5~L)heYH6d#yVV+w^*yl)LjjSlF0_RN&`KL2G4cMQY!?S1_k*K=8Jy!tYjNb{j9%Gt_l z7=>46UvLCFDi09i}`19xxT-+hCoyh zUy9drfwgHre44nM=#X;T&=vx_tCrlPt-Px(*pHw~s5#P2dQTCz9c4Kbo>{+bax|}9 zTke=5{w==W(U^fxU<~-3JA+8!&uWsmAc*Zti115xvED@87_K-@?AzUl2J4F1^nQdx zI&5c@wVxOvVv>?%IXP!$|L2t9p$fqzu~5S6rweZ^CZdR><`+MS4gID$s~o>j)cm9z zzgS|yuWs+WWzDR-oc4{@C!slQCm%8@5!GSNzj9)fkOVF0R5FiLXCbqGp}SfP4>hK S8)%&*lCGA4<{gdwC;tcBR+_v3 literal 0 HcmV?d00001