From 53fe7df74147c7dbb424182ad275a8b63d335f48 Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 14:34:50 -0500 Subject: [PATCH 01/10] Checkpoint TFTMAC causal graphics authority and Gate 4 preflight --- .../tftmac-causal-graphics-v1/AUTHORITY.json | 242 +++ .../IMPLEMENTATION_CHECKLIST.md | 9 + .../IMPLEMENTATION_PLAN.md | 1864 +++++++++++++++++ .../tftmac-causal-graphics-v1/PREFLIGHT.json | 36 + .../tftmac-causal-graphics-v1/PREFLIGHT.md | 34 + .../tftmac-causal-graphics-v1/SCOPE_LOCK.txt | 21 + ...CS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json | 105 + ..._ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.sha256 | 1 + 8 files changed, 2312 insertions(+) create mode 100644 .clara/plans/tftmac-causal-graphics-v1/AUTHORITY.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md create mode 100644 .clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md create mode 100644 .clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.md create mode 100644 .clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt create mode 100644 .clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.sha256 diff --git a/.clara/plans/tftmac-causal-graphics-v1/AUTHORITY.json b/.clara/plans/tftmac-causal-graphics-v1/AUTHORITY.json new file mode 100644 index 0000000..89f305e --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/AUTHORITY.json @@ -0,0 +1,242 @@ +{ + "accepted_diagnostic_build": { + "content_match": true, + "expected_sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json", + "sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d", + "sidecar_match": true, + "sidecar_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json.sha256" + }, + "accepted_native_host": { + "content_match": true, + "expected_sha256": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json", + "sha256": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067", + "sidecar_match": true, + "sidecar_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json.sha256" + }, + "accepted_stopped_clone": { + "content_match": true, + "expected_sha256": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json", + "sha256": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648", + "sidecar_match": true, + "sidecar_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json.sha256" + }, + "app_integration_seams": { + "coordinator_file": { + "lines": [ + { + "line": 7, + "text": "private var runtimeController: TFTMACRuntimeController?" + }, + { + "line": 17, + "text": "let runtime = TFTMACRuntimeController(" + }, + { + "line": 46, + "text": "runtime.start()" + }, + { + "line": 104, + "text": "await runtimeController.stop()" + } + ], + "path": "tftmac/App/AppCoordinator.swift", + "sha256": "d0eb27df9a0e6aaa45ff60c63fd81bc229350a6f8feca833b776bbe4a954bda4" + }, + "runtime_file": { + "lines": [ + { + "line": 24, + "text": "let runtimeRoot = URL(fileURLWithPath: \"/Volumes/MAC MINI M4/TFTMAC/Runtime\", isDirectory: true)" + }, + { + "line": 30, + "text": "throw TFTMACRuntimeError(\"The proven Android runtime is not mounted at /Volumes/MAC MINI M4/TFTMAC/Runtime.\")" + }, + { + "line": 55, + "text": "let hostApplication = resourceURL.appendingPathComponent(\"TFTMAC Emulator Host.app\", isDirectory: true)" + }, + { + "line": 57, + "text": "throw TFTMACRuntimeError(\"TFTMAC Emulator Host.app is missing from the application bundle.\")" + }, + { + "line": 2400, + "text": "\"serial\": \"emulator-5582\"," + }, + { + "line": 2406, + "text": "[\"-P\", \"5038\", \"-s\", \"emulator-5582\", \"emu\", \"kill\"]," + }, + { + "line": 2436, + "text": "[\"-P\", \"5038\", \"-s\", \"emulator-5582\", \"emu\", \"kill\"]," + }, + { + "line": 2452, + "text": "payload: [\"pid\": ownedPID ?? 0, \"serial\": \"emulator-5582\", \"owned\": ownsRunningEmulator]" + }, + { + "line": 2503, + "text": "process.arguments = [\"-P\", \"5038\", \"-s\", \"emulator-5582\", \"logcat\", \"-v\", \"threadtime\", \"-T\", sessionStartSelector]" + }, + { + "line": 2598, + "text": "(\"launcher_method\", \"/usr/bin/open -n -W --env ... --args ...\", \"Mactician donor architecture\", \"DIRECT\")," + }, + { + "line": 2603, + "text": "(\"adb_serial\", \"emulator-5582\", \"known-good donor\", \"DIRECT\")," + }, + { + "line": 2643, + "text": "\"serial\": \"emulator-5582\"," + }, + { + "line": 2661, + "text": "\"--env\", \"TFT_ADB_SERVER_PORT=5038\"," + }, + { + "line": 2679, + "text": "\"@TFT_Ultra_Tablet\", \"-id\", \"TFTMAC\", \"-port\", \"5582\"," + }, + { + "line": 2698, + "text": "process.executableURL = URL(fileURLWithPath: \"/usr/bin/open\")" + }, + { + "line": 2706, + "text": "\"method\": \"/usr/bin/open\"," + }, + { + "line": 2795, + "text": "await status(\"Waiting for the proven ADB identity on emulator-5582\u2026\", false)" + }, + { + "line": 2802, + "text": "[\"-P\", \"5038\", \"-s\", \"emulator-5582\", \"get-state\"]," + }, + { + "line": 2820, + "text": "\"serial\": \"emulator-5582\"," + }, + { + "line": 2825, + "text": "\"serial\": \"emulator-5582\"," + }, + { + "line": 2831, + "text": "await status(\"Waiting for emulator-5582 to appear on ADB 5038\u2026\", false)" + }, + { + "line": 2840, + "text": "throw TFTMACRuntimeError(\"ADB emulator-5582 did not authorize in the logged-in Mac session (last state: \\(lastState)).\")" + }, + { + "line": 2842, + "text": "telemetry.recordEvent(\"ADB_DEVICE_AUTHORIZED\", payload: [\"port\": 5038, \"serial\": \"emulator-5582\"])" + }, + { + "line": 3707, + "text": "[\"-P\", \"5038\", \"-s\", \"emulator-5582\", \"shell\", \"perfetto\", \"--txt\", \"-c\", \"-\", \"-o\", remotePath]," + }, + { + "line": 4574, + "text": "[\"-P\", \"5038\", \"-s\", \"emulator-5582\"] + arguments," + }, + { + "line": 4588, + "text": "\"-P\", \"5038\", \"-s\", \"emulator-5582\", \"shell\", \"pidof\"," + } + ], + "path": "tftmac/Runtime/TFTMACRuntime.swift", + "sha256": "8932032d93af01b46e46b5fb5a04eff1ec457f2f0e8f92f364d5a1a703ab5a5f" + } + }, + "blocked_action": "Diagnostic first boot, loaded-runtime proof, TFT launch, and source instrumentation remain closed while the protected stock runtime is active or until all launch preconditions pass.", + "change_id": "e66bd32e-b6c5-43bd-ae7e-792a234335bf", + "control_runtime": { + "active": true, + "authority": "STOCK_BUILD8", + "mutation_attempted": false, + "processes": [ + "96695 1 /Applications/TFTMAC.app/Contents/MacOS/TFTMAC", + "96706 96695 /usr/bin/open -n -W --env TFT_EMULATOR=/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator --env TFT_ADB_SERVER_PORT=5038 --env ANDROID_ADB_SERVER_PORT=5038 --env ADB_MDNS_AUTO_CONNECT= --env ADB_SERVER_SOCKET= --env ANDROID_ADB_SERVER_ADDRESS= --env ANDROID_SDK_ROOT=/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK --env ANDROID_AVD_HOME=/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD --env ANDROID_EMULATOR_USE_SYSTEM_LIBS=0 --env ANGLE_FEATURE_OVERRIDES_ENABLED=exposeNonConformantExtensionsAndVersions:exposeES32ForTesting --env ANGLE_FEATURE_OVERRIDES_DISABLED=preferSubmitAtFBOBoundary --env MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0 --env MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE=64 --env MVK_CONFIG_FAST_MATH_ENABLED=1 --env TFT_HOST_LATENCY_QOS=user_interactive --env TFT_HOST_STDOUT=/Users/flash/Library/Application Support/TFTMAC/Captures/2026-09-01T19-05-12.436Z-462c1f5b-423f-441f-a316-9ec4d5333acd/emulator.stdout.log --env TFT_HOST_STDERR=/Users/flash/Library/Application Support/TFTMAC/Captures/2026-09-01T19-05-12.436Z-462c1f5b-423f-441f-a316-9ec4d5333acd/emulator.stderr.log /Applications/TFTMAC.app/Contents/Resources/TFTMAC Emulator Host.app -args TFT_Ultra_Tablet id FTMAC port 582 gpu ost audio oreaudio feature LESDynamicVersion,Vulkan,GuestAngle,-GLPipeChecksum,VulkanBatchedDescriptorSetUpdate,AsyncComposeSupport,VirtioGpuFenceContexts append-userspace-opt ndroidboot.opengles.version=196610 append-userspace-opt ndroidboot.tftmac.graphics_profile=tftmac append-userspace-opt ndroidboot.tftmac.session=2026-09-01T19-05-12.436Z-462c1f5b-423f-441f-a316-9ec4d5333acd skin 920x1080 vsync-rate", + "96707 1 /Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64 @TFT_Ultra_Tablet -id TFTMAC -port 5582 -gpu host -audio coreaudio -feature GLESDynamicVersion,Vulkan,GuestAngle,-GLPipeChecksum,VulkanBatchedDescriptorSetUpdate,AsyncComposeSupport,VirtioGpuFenceContexts -append-userspace-opt androidboot.opengles.version=196610 -append-userspace-opt androidboot.tftmac.graphics_profile=tftmac -append-userspace-opt androidboot.tftmac.session=2026-09-01T19-05-12.436Z-462c1f5b-423f-441f-a316-9ec4d5333acd -skin 1920x1080 -vsync-rate 60 -dns-server 1.1.1.1,8.8.8.8 -cores 6 -memory 5120 -no-hidpi-scaling -no-snapshot -no-metrics -no-boot-anim -crash-report-mode disabled -qt-hide-window -grpc 8554 -grpc-use-token -idle-grpc-timeout 300 -timezone America/Chicago" + ] + }, + "current_gate_state": "SOURCE_INTEGRATION_READY_DIAGNOSTIC_BOOT_BLOCKED_CONTROL_ACTIVE", + "diagnostic_mode": { + "avd": { + "adb_server_port": 5041, + "avd_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd", + "config_sha256": "090fe426402562e227a3a1a6bd6eab9f9572cd48fbe3d467c276d419860caf90", + "console_port": 5586, + "ini_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.ini", + "ini_sha256": "30d4ed7ebc20fb3415461fa48f6d91654955e04825de84176bd21a4adad9b98d", + "name": "TFTMAC_Diagnostic_API37_R9", + "root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD", + "serial": "emulator-5586" + }, + "avd_acceptance": "PENDING_FIRST_BOOT", + "build_id": "gate4-r9-20260901", + "comparability": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", + "controller_port": "UNRESOLVED_MUST_BE_ALLOCATED_AND_RECEIPTED_BEFORE_BOOT", + "emulator": { + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator", + "sha256": "fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa", + "uuids": [ + "4C4C4436-5555-3144-A1EE-05B0F446F580:arm64" + ] + }, + "gfxstream_backend": { + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib", + "sha256": "23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d", + "uuids": [ + "4C4C4449-5555-3144-A1FC-F6DFE0021481:arm64" + ] + }, + "loaded_binary_receipt": null, + "source_instrumentation": "CLOSED_UNTIL_DIAGNOSTIC_AVD_ACCEPTANCE_PASS" + }, + "diagnostic_runtime_processes": [], + "execution_scope_lock": { + "path": ".clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt", + "sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e" + }, + "governing_plan": { + "path": ".clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md", + "sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "version": "1.1" + }, + "head_sha": "c8b79ea009197c25bc7e64bebd5e8948eea918b1", + "installed_stock_app": { + "build": "8", + "bundle_id": "com.flashls1.tftmac", + "codesign_status": 0, + "codesign_stderr": "--prepared:/Applications/TFTMAC.app/Contents/Frameworks/libswiftCompatibilitySpan.dylib\n--validated:/Applications/TFTMAC.app/Contents/Frameworks/libswiftCompatibilitySpan.dylib\n/Applications/TFTMAC.app: valid on disk\n/Applications/TFTMAC.app: satisfies its Designated Requirement", + "path": "/Applications/TFTMAC.app", + "version": "2.3.0" + }, + "next_safe_action": "Implement the exact three-mode registry and fail-closed app-side mode/identity plumbing without launching or replacing any runtime.", + "noninterference": { + "clone_repeated": false, + "diagnostic_launch_attempted": false, + "runtime_build_repeated": false, + "stock_stop_attempted": false + }, + "observed_at": "2026-09-01T19:23:52.210992Z", + "project_id": "tftmac", + "schema": 1, + "state": "GATE4_APP_INTEGRATION_AUTHORITY_PASS", + "zenmc": { + "path": ".clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json", + "result": null, + "sha256": "4f0d706f7c5bf5d7f88a1fb4363ef6efeb9f57f678f78a39cf30fec3c5bf1c80", + "sidecar": ".clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.sha256" + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md b/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md new file mode 100644 index 0000000..51d997c --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md @@ -0,0 +1,9 @@ +# TFTMAC Causal Graphics Execution Checklist + +- [x] Restore and verify the governing implementation plan and ZenMC receipt. +- [x] Reconcile the accepted r9 build, stopped physical clone, and native diagnostic host receipts. +- [x] Map the current app-side native host and runtime configuration seam. +- [ ] **ACTIVE — Wave B:** implement exactly `control`, `advanced_diagnostics`, and `candidate` runtime modes with fail-closed identity and lease validation. +- [ ] Diagnostic first boot and loaded-runtime acceptance — closed while stock control is active. +- [ ] Wave C onward: fixed event ABI and causal instrumentation — closed until diagnostic AVD acceptance passes. +- [ ] Controlled experiment, candidate, rollback, documentation reconciliation, and final publication. diff --git a/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md b/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md new file mode 100644 index 0000000..0fd0c35 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md @@ -0,0 +1,1864 @@ +--- +title: TFTMAC Causal Graphics Optimization and Ultra-High Promotion — Implementation Plan +plan_version: 1.1 +date_local: 2026-08-31 +project: TFTMAC +request_class: PLAN +implementation_status: READY_FROM_CLEAN_CANONICAL_MASTER_AFTER_GATE_0A +canonical_authority_sha_at_amendment: c8b79ea009197c25bc7e64bebd5e8948eea918b1 +authority_inputs_sha256: 1d85f4f2f64f3b6089c79385b329dfe42bb479b8c65877c39bf01bdef13703ac +amendment_zenmc_model_sha256: e67e5473b309a210816b87dc55c0765567e4d996b48c9ca982eeb66863d7ad85 +scope_lock_sha256: dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e +zenmc_receipt_sha256: 4f0d706f7c5bf5d7f88a1fb4363ef6efeb9f57f678f78a39cf30fec3c5bf1c80 +--- + +# TFTMAC Causal Graphics Optimization and Ultra-High Promotion + +## 0. How Local Codex must use this file + +This is the implementation authority for building the causal graphics logger, deriving a narrowly supported runtime setting or source patch, and promoting the highest accepted TFT quality tier. + +Local Codex must read the entire file before changing source. It must execute the phases in order, preserve existing local work, and stop each wave at its acceptance gate. A later phase does not authorize skipping an earlier gate. + +This plan is intentionally robust to a local checkout that is newer than GitHub or newer than Clara's registered worktrees. Gate 0 establishes the actual local authority before any implementation edit. + +## 1. Current observed project state and evidence limitation + +Clara's most recent registered local observation, at approximately 2026-08-31 19:20 America/Chicago, showed: + +- Canonical project: `flashls1/TFTMAC` +- Canonical branch: `master` +- Canonical HEAD: `365e891ea2950e2cc68a9e4fec683c8538a831e6` +- Canonical checkout: clean and aligned with `origin/master` +- Most advanced managed convergence change: + - change: `43c40d13-47c8-4396-8ee5-62a17184e847` + - branch: `clara/finish-tftmac-clean-convergence-and-nati-43c40d13` + - committed HEAD: `f439b241c1fa0a215ac0270bb49380eff8f6d084` + - uncommitted protected work: + - deleted `Probes/EmbeddedControlProbe/main.swift` + - modified `TFTMAC.xcodeproj/project.pbxproj` + - modified `scripts/verify-tftmac.command` + - modified `tools/tftmac-direct-control.mjs` + - untracked `Probes/EmbeddedControlProbe/EmbeddedControlProbe.swift` + +Those local changes are native EmulatorController probe work, not the causal logger. + +Clara cannot truthfully assert the state of an unregistered Codex clone such as the path referenced by the attached design document. Therefore: + +> The current local checkout used by Codex may be newer. It becomes authority only after Gate 0 records its repository identity, HEAD, status, worktrees, and hashes without deleting or resetting anything. + +## 2. Source design incorporated by this plan + +The attached design requires replacement of the current symptom logger with an automatic source-instrumented causal logger. Each degradation episode must terminate in an honest `ROOT_CANDIDATE`, `ROOT_NAMED`, or `UNKNOWN`, with the proven playable runtime left untouched and a separately selectable diagnostic runtime used for source instrumentation. + +This plan preserves that design and adds the following mandatory corrections: + +1. Formal authority amendment before reviving any source-built diagnostic runtime. +2. A renderer-path receipt before excluding ANGLE. +3. An uninstrumented stock-to-diagnostic symptom-parity gate. +4. Hard lineage from transport work to actual presentation. +5. A fixed ring/clock/seal ABI. +6. Deterministic incident and statistical rules. +7. Separate logger acceptance, diagnostic representativeness, root discovery, patch acceptance, and quality promotion. +8. A production candidate mode distinct from both control and diagnostics. +9. A final quality ladder targeting `Ultra High / 60 FPS / Performance Mode OFF / 1920x1080`. + +## 3. Product outcome and hard win condition + +The program is complete only when all of the following are proven: + +1. The current playable stock runtime remains available as `control` and is never silently modified. +2. The causal logger can identify the earliest supported divergent owned boundary and fails closed when identity, timing, parity, or ownership is missing. +3. Controlled injected faults at every instrumented boundary are localized correctly. +4. A real TFT degradation produces either: + - a replicated `ROOT_NAMED` in owned code; or + - an exact honest unowned/invalid boundary such as `UNREAL_OR_PRE_ENCODER_UNKNOWN`. +5. A setting adjustment or open-source code patch is created only from a valid owned `ROOT_NAMED`. +6. The patch passes randomized matched A/B validation with instrumentation disabled. +7. A stock-compatible `candidate` runtime passes official Google Play/TFT/Riot lifecycle and rollback gates. +8. TFT passes the live 600-second acceptance window at: + - graphics: `Ultra High` + - frame cap: `60` + - Performance Mode: `OFF` + - render/display target: `1920x1080 @ 60 Hz` +9. Final performance acceptance: + - average presented FPS `>= 58.0` + - p95 presented interval `<= 20.0 ms` + - p99 presented interval `<= 33.334 ms` + - intervals above `33.334 ms` `<= 1.0%` + - intervals above `100 ms` `<= 3` per 600 seconds + - no renderer crash + - no Vulkan device loss + - no repeated validation/error storm + - no login, input, audio, visual-correctness, package-authority, or reconnect regression +10. The accepted candidate has a one-action rollback to the untouched control runtime. + +`Ultra High / 60 / OFF` is the quality goal because the product refresh target is 60 Hz. An uncapped mode is not a higher visual-quality tier and is outside this plan unless separately authorized after Ultra High/60 succeeds. + +## 4. Non-negotiable boundaries + +- Official package: `com.riotgames.league.teamfighttactics` +- Installer/update authority: `com.android.vending` +- No Riot binary or APK modification. +- No repacking, re-signing, process injection, or anti-cheat bypass. +- No credential, token, screenshot, or shader-content capture. +- No fabricated line-level attribution inside signed Riot/Unreal code. +- No broad optimization campaign before a root receipt. +- No quality reduction, dynamic resolution reduction, resolution lowering, or Performance Mode enablement to claim the quality target. +- No hidden dependence on a retired application, retired project, or abandoned source-build tree. +- Raw evidence is authoritative; SQLite and AI-readable reports are derived and rebuildable. +- AI explains an immutable deterministic finding. AI never decides `ROOT_NAMED`. + +# PART I — AUTHORITY, PRESERVATION, AND CONTROL + +## Phase 0 — Reconcile actual local truth and protect concurrent work + +### Objective + +Establish the exact local checkout Codex will edit, preserve all uncommitted work, and create a new implementation branch from the newest compatible local authority. + +### Required actions + +From the checkout Codex intends to use, record: + +```bash +pwd +git rev-parse --show-toplevel +git rev-parse HEAD +git branch --show-current +git status --porcelain=v2 -b +git remote -v +git worktree list --porcelain +git submodule status --recursive || true +``` + +Create: + +```text +.clara/plans/tftmac-causal-graphics-v1/ +├── LOCAL_AUTHORITY.json +├── PREFLIGHT.md +├── IMPLEMENTATION_PLAN.md +├── ZENMC_RECEIPT.json +├── SCOPE_LOCK.txt +└── protected-local-work/ +``` + +`LOCAL_AUTHORITY.json` must include: + +```json +{ + "repository_root": "...", + "repository_remote": "...", + "branch": "...", + "head_sha": "...", + "status_porcelain_v2_sha256": "...", + "worktree_inventory_sha256": "...", + "observed_at": "...", + "known_clara_master": "365e891ea2950e2cc68a9e4fec683c8538a831e6", + "known_clara_advanced_change": "43c40d13-47c8-4396-8ee5-62a17184e847", + "known_clara_advanced_head": "f439b241c1fa0a215ac0270bb49380eff8f6d084" +} +``` + +If the checkout is dirty: + +1. Do not run `git reset`, `git clean`, checkout-overwrite, or destructive rebase. +2. Save: + - `git diff --binary` + - `git diff --cached --binary` + - untracked-file manifest with SHA-256 +3. Create a checkpoint commit or a separate preserved worktree/branch. +4. Confirm the five currently known native-controller files remain preserved if they exist. +5. Create the new implementation branch from the newest compatible preserved HEAD: + +```text +codex/tftmac-causal-graphics-v1 +``` + +### Drift resolution + +- If local Codex files are newer than Clara/GitHub, retain them and record their hashes. +- If local files conflict with the attached logger design, classify each conflict: + - `NEWER_COMPATIBLE` + - `NEWER_REQUIRES_PLAN_AMENDMENT` + - `UNRELATED_PROTECTED_WORK` + - `STALE_SUPERSEDED` +- Only `NEWER_REQUIRES_PLAN_AMENDMENT` may alter later scope, and only through an append-only amendment plus a targeted ZenMC rerun. + +### Gate 0 acceptance + +PASS only when: + +- all local modifications are recoverable; +- the exact implementation checkout is identified; +- no existing worktree has been overwritten; +- the plan files and scope lock are persisted; +- the implementation branch base is recorded; +- `git diff --check` passes for the preserved state. + +Failure result: + +```text +BLOCKED_LOCAL_WORK_UNPRESERVED +``` + +## Phase 1 — Formal authority amendment and canonical documentation + +### Objective + +Make the diagnostic source-build exception explicit without undoing clean-ownership decisions. + +### Required documents + +Use the canonical project documentation locations discovered in Gate 0. If root `facts.md`, `benchmark.md`, or `dev.md` do not exist, create them or place their exact required content in the existing canonical `docs/`/`ssot/` authority and record the mapping. + +Required authority statements: + +1. `control` is the protected playable runtime. +2. Source-built AEMU/gfxstream/MoltenVK is authorized only as an isolated diagnostic instrument. +3. The diagnostic source root must be new and must not silently resurrect the abandoned `/Volumes/MAC MINI M4/TFTMAC/Build`. +4. Diagnostic performance is not directly promotable to stock. +5. `MATCH_ENTRY` and `MATCH_RESULT` are optional annotations only. +6. Graphics lifecycle begins from TFT process plus exact SurfaceView/layer appearance and ends when that generation disappears. +7. The native presenter remains hidden context-only evidence. +8. Riot/Unreal internals are opaque. +9. The final visual target is Ultra High/60/Performance Off at 1920x1080. +10. A production patch is restricted to owned open-source runtime components. + +Create: + +```text +ssot/TFTMAC_CAUSAL_GRAPHICS_AUTHORITY.md +ssot/TFTMAC_CAUSAL_GRAPHICS_SCHEMA.md +docs/causal-graphics-logger.md +docs/graphics-optimization-promotion.md +``` + +The authority file must explicitly supersede only the source-build prohibition for this isolated diagnostic purpose. It must not supersede the protected stock-runtime, package-authority, clean-ownership, or no-Riot-modification rules. + +### Existing 42-minute capture + +Do not promote the stated 42-minute metrics to durable authority unless Codex locates: + +- capture directory or archive; +- raw manifest SHA; +- exact TFT layer identity; +- normalizer version/hash; +- query text/hash; +- coverage calculation; +- output receipt. + +If those are not present, store the values as: + +```text +CLAIMED_PRIOR_OBSERVATION_NOT_YET_RECEIPTED +``` + +### Gate 1 acceptance + +PASS when the authority amendment is internally consistent, all referenced paths exist, and a repository search proves no document still claims both “source build forbidden” and “source build required” without the diagnostic-only exception. + +Failure result: + +```text +BLOCKED_AUTHORITY_AMENDMENT +``` + +## Phase 2 — Freeze the protected control and the promotion target + +### Runtime modes + +Define exactly three modes: + +```text +control +advanced_diagnostics +candidate +``` + +- `control`: current packaged playable runtime and control AVD; default until final cutover. +- `advanced_diagnostics`: isolated source-instrumented runtime and diagnostic AVD; never used for direct stock performance promotion. +- `candidate`: release, instrumentation-disabled, stock-compatible runtime containing only an accepted setting profile or patch. + +Add a single mode registry, for example: + +```text +ssot/runtime-modes.json +``` + +Each mode entry must specify: + +- executable and library roots; +- AVD identity; +- ADB/console lease; +- manifest; +- configuration SHA; +- allowed purpose; +- comparability class; +- rollback target. + +Only one mode may own the AVD/ADB lease at a time. Preserve the current packaged macOS launch chain and logged-in user context. + +### Control receipt + +Before diagnostic work, record: + +- runtime binary SHA/UUID; +- emulator version; +- package version/signature/installer; +- renderer and graphics transport observations; +- exact display/layer identity; +- High/60/Performance Off settings; +- audio/input/login state; +- baseline performance receipt if a valid current run exists. + +### Gate 2 acceptance + +PASS only when selecting `control` is deterministic, leaves the known playable AVD intact, and produces a complete control receipt. + +# PART II — PROVE THE REAL PIPELINE BEFORE INSTRUMENTING IT + +## Phase 3 — Renderer-path and exact-surface receipt + +### Objective + +Prove whether the exact TFT gameplay SurfaceView is driven by direct Vulkan, ANGLE, or a mixed path. + +### Evidence to collect + +For the exact TFT process and exact gameplay surface generation: + +- PID/process generation. +- `/proc//maps` library inventory. +- package/activity identity. +- Vulkan instance/device/queue creation evidence. +- loaded ANGLE/EGL/GLES libraries. +- emulator/gfxstream renderer logs. +- SurfaceFlinger layer list and generation. +- color-buffer and queue identities where available. +- relationship between API submissions and the exact gameplay layer. + +### Required decision + +```text +DIRECT_VULKAN_PROVEN +ANGLE_PATH_PROVEN +MIXED_PATH_PROVEN +UNKNOWN_RENDERER_PATH +``` + +ANGLE instrumentation may be omitted only for `DIRECT_VULKAN_PROVEN` and only when the receipt proves ANGLE does not contribute work to the exact gameplay layer. Otherwise, add an ANGLE branch to the instrumentation map. + +### Gate 3 acceptance + +A signed/hash-addressed `PIPELINE_RECEIPT.json` exists and all later instrumentation stages match its decision. + +Failure result: + +```text +UNKNOWN_PIPELINE_RECEIPT +``` + +# PART III — ISOLATED DIAGNOSTIC RUNTIME + +## Phase 4 — Create the diagnostic source authority and build root + +### New external root + +Use a new root such as: + +```text +/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/ +├── Sources/ +├── Build/ +├── Install/ +├── Symbols/ +├── Manifests/ +├── Traces/ +└── AVD/ +``` + +Do not reuse or recreate the retired general-purpose Build tree. + +### Initial pinned authority + +Unless Gate 0 discovers a newer approved local lock, begin from the existing frozen source family: + +```text +AEMU branch: emu-master-dev +QEMU: ae9d18d2b6261179fbd57fffec720a04f7bfb053 +AEMU: 3c1ced8a369417db591eb7cd083af5bb2c317975 +gfxstream: d047a57228332d995d36600792fa9ccc26cf8ae6 +ANGLE: 901e32aa9923b05c3a2af846f8a28fc79c93d0be +integrated MoltenVK prebuilt authority: fb26612eb84576adb974fe7f18a49d263072116f +MoltenVK reference: db66022459ffb663aa2b50f6b018bc2e124f5edf +manifest SHA: 28865cd8a162178ba462b296f5714b6b7b6916e0cafcddfc0c5e44aa03f8e8d3 +``` + +Gate 0 may supersede these only with a newer pinned project authority. + +### Build requirements + +- Optimized release code. +- Debug symbols and dSYMs retained. +- gfxstream tracing compiled in. +- No debug assertions or validation layers during measured runs unless the specific experiment requires them. +- Build manifest includes: + - remotes; + - full commits; + - dirty state; + - source blob hashes; + - build flags; + - compiler/Xcode versions; + - binary SHA/UUID; + - dSYM UUID/hash; + - instrumentation schema hash; + - site-manifest hash; + - runtime configuration hash. + +At launch, loaded binary identities must match the manifest or the run fails before TFT starts. + +### Diagnostic AVD + +Use a separate AVD identity. It may be created from a safely stopped clone only when the clone operation is recorded and the control AVD is untouched. + +It must independently pass: + +- Google Play installer authority; +- official TFT version/signature; +- Riot login; +- first gameplay frame; +- exact renderer path; +- exact layer; +- input; +- audio; +- reconnect/session behavior. + +### Gate 4 acceptance + +```text +DIAGNOSTIC_BUILD_IDENTITY_PASS +DIAGNOSTIC_AVD_ACCEPTANCE_PASS +``` + +Failures leave control untouched. + +# PART IV — EVENT ABI, WORK IDENTITY, AND PRESENT LINEAGE + +## Phase 5 — Define `PipelineEventV1` + +### Fixed record contract + +Use a fixed-size, little-endian binary record. A 128-byte layout is recommended. It must contain only fixed-width values: + +```text +magic +schema_version +record_size +event_kind +flags +loss_state +diagnostic_epoch_id +manifest_short_id +producer_instance_id +process_id +thread_id +device_id +queue_id +clock_domain_id +site_id +span_id +transport_work_id +present_lineage_id +generation +producer_sequence +parent_work_id +timestamp_ns +duration_or_value_ns +value0 +value1 +result_code +``` + +No strings, dynamic arrays, heap allocation, formatting, file I/O, SQLite, symbolization, or blocking synchronization are allowed in a hot hook. + +### Site manifest + +Generate a static immutable manifest mapping `site_id` to: + +- component; +- semantic boundary; +- event kind; +- full source commit; +- file blob SHA; +- file and function; +- line/range; +- site-range hash; +- loaded binary SHA/UUID; +- instrumentation schema. + +Line number is navigation metadata. Commit, blob, binary, schema, and site-range hashes are authority. + +### Span authority + +A slow operation is normally attributed to a span: + +```text +root_span_id +start_site_id +end_site_id +decisive_child_site_id nullable +``` + +Do not collapse a slow span to one exact line unless child evidence isolates that site. + +### Gate 5 acceptance + +- duplicate site IDs fail the build; +- record ABI self-test passes on every producer; +- binary and site manifests match; +- old readers reject unsupported schema instead of misparsing. + +## Phase 6 — Prove `transport_work_id` and `present_lineage_id` + +### `transport_work_id` + +First audit existing gfxstream negotiated sequence IDs. Reuse an existing protocol identity if it crosses: + +```text +guest encode +→ ASG write +→ host receive +→ decode +→ host queue submission +→ completion +``` + +Call it `transport_work_id`, never `frame_id`. + +If the existing protocol cannot preserve identity, add the smallest diagnostic-only sideband. The official TFT APK remains unmodified. + +### `present_lineage_id` + +Add a separate identity chain for presentation: + +```text +transport work +→ host Vulkan submission +→ Metal command buffer +→ color-buffer generation +→ QSRI/release fence +→ emulator source-frame sequence +→ Android buffer generation +→ SurfaceFrame/DisplayFrame token or proven fallback +→ exact TFT actual presentation +``` + +Include generation counters so handle reuse cannot alias old and new work. + +### Required identity fixtures + +Prove: + +- one-to-one; +- one-to-many; +- many-to-one; +- batching; +- out-of-order completion; +- queue-handle reuse; +- color-buffer reuse; +- surface recreation; +- producer restart; +- sequence wrap; +- dropped-event invalidation. + +Timestamps may corroborate identity but may never create it. + +### Gate 6 acceptance + +At least 99.9% of eligible diagnostic presentation samples must join from the first owned hook to the exact TFT presentation endpoint with no ambiguous generation. Any incident with identity loss is `UNKNOWN_PRESENT_LINEAGE_GAP`. + +# PART V — SOURCE INSTRUMENTATION + +## Phase 7 — Instrument the approved boundaries + +Instrument only boundaries supported by the renderer receipt. + +### Required direct-Vulkan stages + +| Order | Component/boundary | Required events | +|---:|---|---| +| 1 | Guest Vulkan encoder | `vkQueueSubmit` encode begin/end, submit count, queue/device, transport ID | +| 2 | Guest ASG writer | wait begin/end, bytes, write, flush, ring/backpressure | +| 3 | Host ASG receiver | first byte, complete packet, queue depth, receive wait | +| 4 | gfxstream decoder | decode begin/end, dispatch identity, command count | +| 5 | Host Vulkan queue | queue-lock wait/acquire/release, submit entry/return/result | +| 6 | MoltenVK | pipeline create begin/end, cache hit/miss/unknown, enqueue, Metal association | +| 7 | Metal | command-buffer commit, scheduled callback, GPU start/end when valid, completion/result | +| 8 | Android buffer/QSRI | color-buffer ready, QSRI, acquire/release fence identity and wait | +| 9 | Emulator output | source-frame sequence, new/repeated/stale source status | +| 10 | SurfaceFlinger endpoint | exact TFT present/latch endpoint and actual present classification | + +### Conditional ANGLE stages + +If Gate 3 returns ANGLE or mixed: + +- EGL/ANGLE submit entry/exit; +- ANGLE Vulkan translation work identity; +- ANGLE pipeline/shader translation and cache receipt; +- association to the exact gameplay surface. + +### Metal timing + +Distinguish: + +- CPU commit time; +- scheduled-handler time; +- valid `gpuStartTime`; +- valid `gpuEndTime`; +- completed-handler time. + +Do not report scheduled/completed callback deltas as GPU execution time. + +### MoltenVK pipeline data + +Record pipeline-cache use and creation time. Do not enable internal-representation/statistics capture during performance measurement unless a separate diagnostic experiment proves its observer cost acceptable. + +### Gate 7 acceptance + +Every instrumented site compiles in release mode, appears in the site manifest, has a controlled-delay fixture, and emits the expected identity. + +# PART VI — LOW-OVERHEAD COLLECTION, CLOCKS, AND SEALS + +## Phase 8 — Per-thread rings and drain architecture + +### Hot-path design + +Use one preallocated SPSC ring per registered emitting thread. Registration may allocate before measured work begins. Emission after registration is fixed-record only. + +If a thread appears after measurement begins: + +- allocate/register outside the graphics critical section if possible; +- otherwise mark that producer `UNINSTRUMENTED_THREAD` and invalidate attribution across its boundary. + +### Capacity + +For each producer: + +```text +capacity >= max( + 4 × measured peak records/second × 10 seconds, + records needed for 5-second prehistory + 60-second incident segment + 5-second posthistory +) +``` + +Cap memory explicitly and record the selected capacity in the manifest. + +### Overflow + +- Never block the producer. +- Increment a monotonic dropped-record counter. +- Emit a loss marker when space returns. +- Any affected incident becomes `UNKNOWN_STREAM_LOSS`. +- No later normalization may hide the loss. + +### Drain path + +```text +hot hooks +→ fixed binary rings +→ dedicated drain thread +→ append-only binary segment +→ segment hash/seal +→ optional off-path Perfetto mirror +→ post-seal normalizer +``` + +Perfetto is corroborative; fixed rings are causal authority. + +### Segment sealing + +Each segment contains: + +- epoch/producer/generation; +- first and last producer sequence; +- emitted count; +- persisted count; +- dropped count; +- duplicate count; +- unmatched begin/end count; +- previous segment hash; +- current segment SHA; +- flush result. + +### Gate 8 acceptance + +Stress above measured peak rate and prove: + +- no hot-path allocation; +- no hot-path locks; +- no file or database call; +- deterministic overflow behavior; +- valid hash chain; +- crash leaves the last fully sealed segment valid. + +## Phase 9 — Clock-domain calibration + +Maintain mappings among: + +- guest monotonic; +- host monotonic; +- Perfetto trace clock; +- Vulkan device timestamp domain when available; +- Metal/system mach time. + +Use repeated two-way brackets and calibrated timestamp APIs where supported. Each transform records: + +```text +source_clock +target_clock +offset +drift +maximum_deviation_ns +valid_from +valid_until +sample_count +receipt_hash +``` + +Recalibrate: + +- at epoch start; +- periodically; +- before and after each incident; +- after sleep/wake; +- after process restart; +- after any discontinuity. + +Rules: + +- `<= 2 ms`: precise cross-boundary attribution. +- `> 2 ms and <= 10 ms`: ordering only. +- `> 10 ms`: `UNKNOWN_CLOCK_UNCERTAINTY`. + +### Gate 9 acceptance + +Controlled synchronized markers cross each clock domain within the declared uncertainty, and stale transforms are rejected. + +# PART VII — PRESENTATION AUTHORITY AND INCIDENTS + +## Phase 10 — Exact TFT presentation endpoint + +Perfetto FrameTimeline tables may be queried, but SurfaceView coverage must be proven rather than assumed. + +For the exact TFT layer, prove: + +- layer name and generation; +- buffer/surface token continuity; +- presentation coverage; +- duplicate/drop semantics; +- agreement with BufferQueue/fence/source-frame identity. + +Use: + +```text +actual_frame_timeline_slice +expected_frame_timeline_slice +``` + +only when the exact TFT SurfaceView is represented correctly. + +If not, use the instrumented BufferQueue/fence/present chain as authority and retain FrameTimeline as corroboration. + +### Gate 10 acceptance + +`PRESENT_ENDPOINT_RECEIPT.json` records the exact authority and at least 99% coverage for eligible presented frames. Otherwise: + +```text +UNKNOWN_SURFACE_IDENTITY +``` + +## Phase 11 — Automatic lifecycle and deterministic incident detector + +### Lifecycle + +Start graphics logging when all are true: + +- official TFT process generation exists; +- exact gameplay SurfaceView/layer generation exists; +- renderer-path receipt matches; +- clock and producer health are valid. + +End the graphics epoch when the process or exact layer generation disappears. Match markers do not control logging. + +### Workload classes + +Derive deterministic workload classes from observable lifecycle, not free text: + +```text +STARTUP +PATCHING +LOGIN +LOBBY +TRANSITION +GAMEPLAY_LIGHT +GAMEPLAY_HEAVY +SURFACE_RECREATE +UNKNOWN +``` + +A classifier version/hash is stored with every incident. + +### One-second bad window + +A one-second window is bad when any is true for the exact TFT present stream: + +- presented FPS `< 58`; +- p95 interval `> 20 ms`; +- p99 interval `> 33.334 ms`; +- more than 1% intervals exceed `33.334 ms`; +- any interval exceeds `100 ms`; +- stale/repeated source persists for two or more display intervals; +- exact presentation identity becomes incomplete. + +### Incident rules + +- Open after two adjacent bad windows. +- Preserve five seconds prehistory. +- Preserve the full incident. +- Preserve five seconds after recovery. +- Merge incidents separated by `<= 2 seconds`. +- Split and chain sealed segments every 60 seconds. +- Surface recreation closes the current generation and opens a new eligible generation after stability. +- Startup/patch/login incidents are retained but not compared to gameplay baselines. + +### Gate 11 acceptance + +Synthetic timelines exercise open, merge, split, recovery, surface recreation, and exact signature reuse without losing raw evidence. + +# PART VIII — SQL KNOWLEDGE BASE AND DETERMINISTIC ANALYZER + +## Phase 12 — Append-only schema + +Add versioned, idempotent migrations for: + +### `pipeline_diagnostic_epochs` + +Key fields: + +```text +epoch_id +mode +manifest_sha256 +runtime_config_sha256 +avd_sha256 +package_receipt_sha256 +renderer_receipt_sha256 +present_endpoint_receipt_sha256 +clock_receipt_sha256 +parity_state +overhead_state +started_at +ended_at +state +``` + +### `pipeline_events` + +Key fields: + +```text +epoch_id +producer_instance_id +producer_sequence +site_id +span_id +transport_work_id +present_lineage_id +parent_work_id +generation +clock_domain_id +timestamp_ns +duration_or_value_ns +event_kind +flags +result_code +raw_segment_sha256 +``` + +### `pipeline_stream_seals` + +Store all sequence, count, loss, duplicate, unmatched, flush, and hash-chain fields. + +### `pipeline_stage_spans` + +Store: + +```text +epoch_id +incident_id +present_lineage_id +stage +start_site_id +end_site_id +start_ns +end_ns +duration_ns +clock_uncertainty_ns +identity_state +missing_boundary +``` + +### `pipeline_root_findings` + +Insert-only: + +```text +finding_id +incident_signature +outcome +unknown_class +component +stage +root_span_id +decisive_site_id +rule_sha256 +input_receipt_sha256 +healthy_baseline_ids +epoch_ids +confidence +patchable +failed_gate +created_at +``` + +### Outcome taxonomy + +Top-level outcome remains exactly: + +```text +ROOT_CANDIDATE +ROOT_NAMED +UNKNOWN +``` + +Bounded stage is: + +```text +outcome = UNKNOWN +unknown_class = BOUNDED_TO_STAGE +``` + +Other exact unknown classes include: + +```text +UNREAL_OR_PRE_ENCODER_UNKNOWN +PIPELINE_RECEIPT_MISSING +ANGLE_PATH_UNINSTRUMENTED +DIAGNOSTIC_NOT_REPRESENTATIVE +PRESENT_LINEAGE_GAP +STREAM_LOSS +CLOCK_UNCERTAINTY +SURFACE_IDENTITY +OBSERVER_EFFECT +HEALTHY_BASELINE_INSUFFICIENT +NO_CAUSAL_FIRST_DIVERGENCE +``` + +Keep match annotations in a separate table with no causal foreign key. + +Use indexes on epoch, incident, work IDs, lineage IDs, site, stage, and timestamp. Raw binary segments remain the source of truth. + +### Gate 12 acceptance + +- migration from a copy of the current performance-lab DB succeeds; +- `PRAGMA foreign_key_check` is empty; +- re-running migration is idempotent; +- normalized tables rebuild from sealed segments; +- findings cannot be updated or deleted by runtime code. + +## Phase 13 — Root-classification algorithm + +### Comparable healthy baseline + +A degraded incident may compare only against healthy work with the same: + +- diagnostic binary and manifest; +- instrumentation schema; +- runtime configuration; +- renderer path; +- cache state; +- workload class; +- exact layer generation rules. + +Minimum data: + +- incident: at least 30 joined lineage items; +- healthy baseline: at least 500 joined lineage items and at least five healthy minutes across two or more windows. + +### First-divergence rule + +Evaluate stages in pipeline order. A stage is the first supported divergence only when: + +1. degraded p95 exceeds matched healthy p99; +2. median stage latency increases by at least 1 ms; +3. a bootstrap confidence interval for the degraded-minus-healthy difference excludes zero; +4. immediately preceding stage remains within its matched healthy interval; +5. the same lineage IDs carry the delay downstream; +6. all applicable producer streams seal without loss; +7. the clock transform is valid for the required precision; +8. exact surface/present identity is complete; +9. diagnostic symptom parity is already PASS; +10. observer overhead is `<= 5%`. + +Use hierarchical pipeline order. Do not scan all sites and pick the most significant result. + +### Site decision + +- One complete valid incident: `ROOT_CANDIDATE`. +- Exact `ROOT_NAMED`: + - same component, span, and decisive site; + - three fresh process epochs; + - at least two cold epochs and one warm epoch; + - same incident signature; + - every gate passes in every epoch. +- Owned stage but no decisive child site: + - `UNKNOWN / BOUNDED_TO_STAGE`. +- Lateness already present at first owned hook: + - `UNKNOWN / UNREAL_OR_PRE_ENCODER_UNKNOWN`. + +### Logger acceptance is separate + +The logger is accepted when identity, fault fixtures, seals, clocks, fail-closed behavior, and overhead pass. It does not need to invent a real `ROOT_NAMED` to prove that it works. + +### Gate 13 acceptance + +Golden synthetic datasets produce every expected outcome, including every `UNKNOWN` class. + +# PART IX — VALIDATION AND DIAGNOSTIC REPRESENTATIVENESS + +## Phase 14 — Controlled faults and fail-closed fixtures + +Inject deterministic delays separately at: + +- guest ASG wait/write; +- host receive; +- gfxstream decode; +- queue lock; +- host Vulkan submit; +- MoltenVK pipeline creation; +- Metal completion; +- QSRI/fence; +- source-frame output. + +Each fixture must name the injected component and span/site. + +Fail-closed fixtures: + +- missing event; +- duplicate work ID; +- fan-out/fan-in error; +- generation collision; +- dropped records; +- unmatched spans; +- clock uncertainty; +- empty Perfetto category; +- manifest mismatch; +- loaded binary mismatch; +- wrong TFT layer; +- surface recreation without generation change. + +### Gate 14 acceptance + +All injected owned faults are localized correctly. Every invalid fixture returns the exact `UNKNOWN`/blocked result. + +## Phase 15 — Observer-overhead gate + +On the same diagnostic binary, compare instrumentation enabled versus disabled using randomized AB/BA order. + +Measure: + +- actual-present p95; +- 1% low; +- CPU; +- memory; +- stall count. + +More than 5% degradation in p95 frame interval or 1% low invalidates causal conclusions. Reduce instrumentation or move work farther off-path; do not loosen the threshold. + +Failure result: + +```text +UNKNOWN_OBSERVER_EFFECT +``` + +## Phase 16 — Stock-to-diagnostic symptom parity + +Before explaining stock Build 8 with diagnostic evidence, run an uninstrumented diagnostic epoch and compare the degradation phenotype, not raw performance promotion. + +Required parity: + +- same official TFT build/settings; +- same exact layer behavior; +- same stale-source versus slow-present class; +- same general incident signature; +- same affected pipeline generation/workload class; +- no diagnostic-only crash, queue behavior, or source-build defect that explains the incident. + +Possible result: + +```text +DIAGNOSTIC_REPRESENTATIVE +UNKNOWN_DIAGNOSTIC_NOT_REPRESENTATIVE +``` + +A failed parity gate blocks transfer of a diagnostic root to the stock symptom. + +# PART X — LIVE ROOT CAMPAIGN + +## Phase 17 — Three-epoch diagnostic campaign + +Run automatically at fixed diagnosis settings: + +```text +High +60 FPS +Performance Mode OFF +1920x1080 +``` + +Required epochs: + +1. cold epoch; +2. warm epoch; +3. second cold epoch. + +Each is five to ten minutes of eligible graphics lifetime or long enough to contain the repeated incident signature. + +Every epoch must: + +- use a fresh process/producer generation; +- seal all streams; +- satisfy exact layer, clock, parity, and overhead gates; +- produce a deterministic finding. + +### Gate 17 outcomes + +- `ROOT_NAMED`: proceed to patch generation. +- `ROOT_CANDIDATE`: collect another independent matching epoch; do not patch for production. +- `UNKNOWN`: preserve the exact boundary and failed gate; do not guess. +- `UNREAL_OR_PRE_ENCODER_UNKNOWN`: no source patch is authorized inside Riot/Unreal. + +# PART XI — TURN THE ROOT INTO A SETTING OR PATCH + +## Phase 18 — Generate one exact patch target + +From `ROOT_NAMED`, generate: + +```text +ssot/PATCH_TARGET.json +``` + +Fields: + +```text +finding_id +component +root_span_id +decisive_site_id +source_commit +source_blob_sha +allowed_files +allowed_functions +allowed_runtime_knobs +forbidden_files +hypothesis +predicted_metric_change +falsification_condition +rollback +``` + +### Allowed candidate classes + +1. `SETTING_ONLY` + - an existing, documented runtime knob directly controls the named bottleneck. +2. `OWNED_SOURCE_PATCH` + - a minimal change in pinned AEMU/gfxstream/MoltenVK or TFTMAC glue. +3. `NOT_PATCHABLE` + - root is opaque/unowned or no safe causal control exists. + +### Stage-specific candidate examples + +These are examples, not pre-authorization: + +- ASG wait/backpressure: + - ring/buffer sizing; + - flush threshold; + - bounded batching; + - wakeup policy. +- Decoder: + - packet batching; + - lock duration; + - dispatch scheduling. +- Host queue: + - critical-section reduction; + - queue serialization correction; + - submit batching only when ordering remains correct. +- MoltenVK pipeline creation: + - persistent pipeline cache; + - validated prewarm; + - cache-key/miss correction. +- Metal: + - bounded command-buffer concurrency; + - scheduling/commit policy. +- Buffer/QSRI/output: + - fence wait correction; + - stale-source handoff; + - source-frame publication policy. + +Do not begin with a knob sweep. The root receipt selects the one causal family. + +### Gate 18 acceptance + +The target is owned, narrow, reversible, and traceable to one finding. + +## Phase 19 — Implement and validate the diagnostic candidate + +### Implementation rules + +- Modify only the files in `PATCH_TARGET.json`. +- One causal variable per candidate. +- Keep instrumentation available for root-metric confirmation. +- No dependency upgrade. +- No adjacent cleanup. +- No quality-setting change during root-metric validation. + +### Root-metric confirmation + +With instrumentation enabled, prove: + +- named span/site p95 materially improves; +- preceding stage remains healthy; +- delay no longer propagates downstream; +- no new first divergence appears; +- fault fixtures still work. + +### True performance A/B + +Then build the same candidate with instrumentation disabled. + +Use randomized matched AB/BA runs against the unpatched diagnostic build. Require at least three paired repetitions, including cold and warm coverage. + +Reject when any is true: + +- average FPS decreases by more than 1 FPS; +- p99 worsens by more than 3%; +- jank worsens by more than 0.25 percentage points; +- severe stalls increase; +- input, audio, login, package, rendering, or stability regresses. + +### Gate 19 outcome + +```text +PATCH_ACCEPTED_DIAGNOSTIC +PATCH_REJECTED_DIAGNOSTIC_AB +``` + +# PART XII — HIGHEST-QUALITY PROMOTION + +## Phase 20 — Quality ladder + +After the patch is locked, instrumentation disabled, and the diagnostic candidate accepted: + +### Tier A — Reconfirm diagnosis baseline + +```text +High / 60 / Performance OFF / 1920x1080 +``` + +Must meet the full 600-second performance contract. + +### Tier B — Target + +```text +Ultra High / 60 / Performance OFF / 1920x1080 +``` + +Procedure: + +1. Enter a live rendered match. +2. Exclude first 120 seconds for warm-up. +3. Capture next 600 continuous seconds. +4. Use exact TFT actual presentation authority. +5. Preserve fixed CPU/RAM/resolution/runtime configuration. +6. Record user visual-correctness confirmation without screenshots. + +Pass only if all product thresholds in section 3 pass. + +Do not lower resolution, enable Performance Mode, or silently change another variable to make Ultra High pass. + +### Gate 20 outcome + +```text +ULTRA_HIGH_60_ACCEPTED +PATCH_ACCEPTED_ULTRA_HIGH_OPEN +``` + +The latter means the patch is valid but the highest-quality goal remains unresolved. + +# PART XIII — STOCK-COMPATIBLE CANDIDATE AND CUTOVER + +## Phase 21 — Build the production candidate mode + +Translate the accepted setting or source patch into a release, instrumentation-disabled runtime. + +Requirements: + +- exact candidate source commits and patch SHA; +- release optimization; +- no tracing code active; +- binary manifest and symbols archived; +- official package/Play/Riot behavior unchanged; +- `candidate` mode uses an isolated validation AVD first; +- control mode remains untouched. + +### Candidate-versus-control validation + +The candidate must pass: + +- package/signature/installer; +- Riot login and patching; +- input/audio/reconnect; +- first frame and exact layer; +- High/60 acceptance; +- Ultra High/60 acceptance; +- cold and warm launches; +- runtime restart; +- rollback. + +Failure result: + +```text +PATCH_REJECTED_STOCK_CANDIDATE +``` + +## Phase 22 — Rollback and default promotion + +Create an exact rollback receipt before switching defaults: + +```json +{ + "previous_default": "control", + "candidate_manifest_sha256": "...", + "control_manifest_sha256": "...", + "rollback_action": "...", + "rollback_verified": true +} +``` + +Default promotion is authorized only when: + +- candidate source delivered and validated; +- Ultra High/60 accepted; +- rollback verified; +- control still starts successfully; +- no open blocker affects the candidate. + +After cutover, preserve `control` as emergency rollback until a later explicit retirement plan. + +# PART XIV — USER-FACING OUTPUT AND DOCUMENTATION + +## Phase 23 — Overlay and reports + +Display only: + +- exact TFT actual-present FPS; +- 1% low; +- source-frame freshness; +- provisional first-divergent stage; +- trace completeness; +- confidence/state; +- active runtime mode; +- current graphics tier. + +Do not display the native Mac presenter as a root candidate. + +The live overlay must label any stage as provisional. Final status comes only from post-seal analysis. + +After TFT exits: + +1. stop producers; +2. seal raw evidence; +3. normalize; +4. derive immutable finding; +5. generate an AI-readable explanation. + +The explanation includes: + +- outcome; +- component/stage/span/site; +- source anchor; +- first late lineage items; +- evidence hashes; +- rejected downstream candidates; +- unknowns; +- patchable state; +- accepted/rejected patch; +- highest accepted quality tier. + +## Phase 24 — Final project records + +Update: + +- canonical facts authority; +- benchmark methodology and receipts; +- development/patch workflow; +- performance lab schema; +- engineering map; +- build instructions; +- runtime mode documentation; +- rollback instructions; +- known limitations. + +Remove no historical evidence merely because a candidate failed. + +# PART XV — COMMIT WAVES AND CODEX STOP POINTS + +Use separate reviewable commits or managed changes: + +1. **Wave A — Authority and local reconciliation** +2. **Wave B — Runtime modes and diagnostic build identity** +3. **Wave C — Event ABI, site manifest, and work/present lineage** +4. **Wave D — Source hooks, rings, clocks, and seals** +5. **Wave E — Presentation endpoint, incident detector, SQL, analyzer** +6. **Wave F — Fault fixtures, overhead, parity, and logger acceptance** +7. **Wave G — Live root evidence** +8. **Wave H — Exact settings/patch candidate** +9. **Wave I — Quality ladder** +10. **Wave J — Stock candidate, rollback, and final delivery** + +At each wave: + +- run only the nearest decisive validation; +- checkpoint the exact head and evidence; +- do not start the next wave if the gate is blocked; +- do not treat a workaround as completion; +- record unrelated discoveries as deferred defects. + +# PART XVI — REQUIRED TEST MATRIX + +| Test | Required result | +|---|---| +| Dirty local checkout | preserved; no destructive reset | +| Manifest or loaded-binary mismatch | blocked before game launch | +| ANGLE contributes to TFT surface | ANGLE branch instrumented | +| Diagnostic symptom differs from control | `UNKNOWN_DIAGNOSTIC_NOT_REPRESENTATIVE` | +| Work lineage missing | `UNKNOWN_PRESENT_LINEAGE_GAP` | +| Ring overflow | `UNKNOWN_STREAM_LOSS` | +| Clock uncertainty >10 ms | `UNKNOWN_CLOCK_UNCERTAINTY` | +| SurfaceView absent from FrameTimeline | fallback presentation authority used | +| Empty custom Perfetto trace | `TRACE_INSTRUMENTATION_UNAVAILABLE`; fixed-ring evidence retained | +| Controlled delay at every owned stage | exact injected stage/site named | +| Missing/duplicate/fan-in fault | `UNKNOWN`; never `ROOT_NAMED` | +| One valid incident | `ROOT_CANDIDATE` | +| Three matching epochs, two cold | `ROOT_NAMED` | +| Lateness exists before first owned hook | `UNREAL_OR_PRE_ENCODER_UNKNOWN` | +| Owned stage, no decisive child | `UNKNOWN / BOUNDED_TO_STAGE` | +| Instrumentation overhead >5% | causal result invalid | +| Diagnostic A/B regression | patch rejected | +| Stock candidate regression | patch rejected; control retained | +| Ultra High misses contract | patch may remain accepted; quality goal remains open | +| Rollback not verified | default cutover blocked | +| Ultra High and all gates pass | `ULTRA_HIGH_60_ACCEPTED` | + +# PART XVII — ZENMC ADVERSARIAL GATE + +## Model + +The plan was evaluated as a state machine with: + +- 10,000 randomized adversarial trajectories; +- 24 targeted single-gate fault mutations; +- one complete success trajectory; +- explicit invariants at root naming, patch admission, candidate promotion, control mutation, and rollback. + +The randomized weights were selected for branch coverage and are **not empirical probabilities**. + +## Result + +```text +ZENMC: PASS +model_sha256: 561820eb6d896728962bae35adef19e7bfc7170e77d9d1c7270ff67b9d2cff6d +unsafe production promotions: 0 +false ROOT_NAMED outcomes: 0 +patch attempts without owned ROOT_NAMED: 0 +early control-runtime mutations: 0 +targeted fail-closed cases with expected result: 24 / 24 +targeted success cases: 1 / 1 +``` + +Most frequently exercised fail-closed paths included diagnostic non-representativeness, observer effect, missing renderer receipt, insufficient healthy baseline, unpreserved local work, presentation-lineage gaps, and clock uncertainty. + +## ZenMC-required remediations now embedded + +- local-work preservation gate; +- formal authority amendment; +- conditional ANGLE path; +- stock-to-diagnostic symptom parity; +- presentation lineage separate from transport identity; +- robust healthy sample floor; +- logger acceptance independent of real root discovery; +- exact unknown taxonomy; +- patch ownership gate; +- Ultra High acceptance separated from patch acceptance; +- rollback required before default mutation. + +# PART XVIII — EXECUTION-SCOPE LOCK + +```text +EXECUTION-SCOPE LOCK — TFTMAC CAUSAL GRAPHICS OPTIMIZATION V1 + +Implement only: +1. Safe reconciliation and preservation of the current local TFTMAC checkout/worktrees. +2. Formal project-authority amendments needed to authorize an isolated diagnostic graphics runtime. +3. A protected control runtime, an isolated advanced_diagnostics runtime, and later a separately gated candidate runtime. +4. Deterministic renderer-path, exact-layer, build-identity, symptom-parity, work-lineage, clock, stream-integrity, and observer-overhead gates. +5. Source instrumentation in only the pinned AEMU/gfxstream/MoltenVK/Metal-facing open-source code needed to localize the first owned graphics divergence. +6. Raw-first fixed-record collection, sealed evidence, deterministic normalization, causal classification, controlled fault fixtures, and append-only SQL evidence. +7. A narrowly targeted settings adjustment or owned-source patch derived from a valid ROOT_NAMED receipt. +8. Controlled A/B validation and the quality-promotion ladder ending at Ultra High / 60 FPS / Performance Mode OFF / 1920x1080 when all acceptance gates pass. +9. A stock-compatible candidate runtime with one-action rollback, only after diagnostic and production-layer acceptance. + +Do not implement: +- Riot APK modification, repacking, re-signing, binary patching, process injection, credential capture, screenshot capture, shader extraction, or fabricated Riot/Unreal source attribution. +- Unrelated refactors, cleanup, renames, reformatting, dependency upgrades, broad architecture replacement, or speculative optimization. +- Any source-built runtime as a hidden replacement for the proven control runtime. +- Any optimization selected only from timestamps, queue handles, aggregate counters, subjective feel, or a single diagnostic epoch. +- Any default-runtime cutover without an exact accepted candidate SHA, a rollback receipt, and Ultra High live acceptance. + +A material diff is permitted only when it traces to this lock, a listed phase deliverable, or a proven blocking dependency added through an append-only amendment and a targeted ZenMC/ZenGate rerun. +``` + +Scope lock SHA-256: + +```text +dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e +``` + +# PART XIX — START HERE FOR LOCAL CODEX + +Execute only this sequence now: + +1. Run Phase 0 and write the local authority receipt. +2. Preserve/checkpoint every current local change. +3. Copy this plan to: + ```text + .clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md + ``` +4. Write the scope lock exactly and verify SHA-256 `dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e`. +5. Complete Phase 1 authority amendment. +6. Stop before source instrumentation until the renderer-path receipt, protected control receipt, and diagnostic-only authority all pass. +7. Continue wave-by-wave without expanding scope. + +The first product edit is **not** a speculative graphics tweak. It is the runtime-mode/authority foundation that makes later causal evidence and a safe production patch possible. + +# Primary technical references + +- gfxstream architecture and tracing: + `https://android.googlesource.com/platform/hardware/google/gfxstream/` +- Perfetto TrackEvent flows and custom clocks: + `https://perfetto.dev/docs/instrumentation/track-events` +- Perfetto FrameTimeline and SurfaceView limitation: + `https://perfetto.dev/docs/data-sources/frametimeline` +- Android SurfaceFlinger/BufferQueue: + `https://source.android.com/docs/core/graphics/surfaceflinger-windowmanager` +- Android synchronization fences: + `https://source.android.com/docs/core/graphics/sync` +- Vulkan calibrated timestamps: + `https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_calibrated_timestamps.html` +- Vulkan pipeline cache: + `https://registry.khronos.org/vulkan/specs/latest/man/html/VkPipelineCache.html` +- MoltenVK runtime/performance guidance: + `https://github.com/KhronosGroup/MoltenVK/blob/main/Docs/MoltenVK_Runtime_UserGuide.md` +- Metal command-buffer GPU timing: + `https://developer.apple.com/documentation/metal/mtlcommandbuffer/gpuendtime` + +# PART XX — APPEND-ONLY CANONICAL REPOSITORY AMENDMENT V1.1 + +**Amendment ID:** `TFTMAC_CAUSAL_GRAPHICS_CLEAN_REPOSITORY_V1_1` +**Effective observation:** 2026-08-31 19:55 America/Chicago (`2026-09-01T00:55:04.583Z`) +**Canonical repository:** `flashls1/TFTMAC` +**Canonical branch:** `master` +**Canonical HEAD at amendment:** `c8b79ea009197c25bc7e64bebd5e8948eea918b1` +**Authority-input manifest SHA-256:** `1d85f4f2f64f3b6089c79385b329dfe42bb479b8c65877c39bf01bdef13703ac` +**ZenMC delta model SHA-256:** `e67e5473b309a210816b87dc55c0765567e4d996b48c9ca982eeb66863d7ad85` + +## 25. Amendment precedence + +This section is append-only and has the highest precedence inside this plan for **repository state, current authority files, implementation base, diagnostic-source baseline, and immediate start sequence**. It supersedes only stale start-state assumptions. + +It does **not** weaken or supersede: + +- the original execution-scope lock; +- the protected stock `control` runtime; +- renderer-path, lineage, clock, stream-loss, parity, observer-overhead, root-naming, patch-admission, Ultra High, rollback, privacy, or Riot-package boundaries; +- the rule that only an owned, replicated `ROOT_NAMED` may authorize an optimization patch. + +The attached source design still governs the core objective: replace symptom-only logging with an automatic source-instrumented causal logger that returns an honest `ROOT_CANDIDATE`, `ROOT_NAMED`, or `UNKNOWN`, while leaving the proven playable runtime untouched. + +## 26. Verified clean canonical authority + +Clara's current local/GitHub reconciliation now proves: + +```text +repository: flashls1/TFTMAC +branch: master +local HEAD: c8b79ea009197c25bc7e64bebd5e8948eea918b1 +origin/master: c8b79ea009197c25bc7e64bebd5e8948eea918b1 +working tree: clean +ahead: 0 +behind: 0 +open GitHub pull requests: 0 +``` + +The canonical repository is therefore the implementation authority. The earlier observation at `365e891...` and the assumption that current native-controller work existed only in a dirty managed worktree are superseded. Current `master` already contains the native probe/controller consolidation, including: + +- `Probes/EmbeddedControlProbe/EmbeddedControlProbe.swift`; +- the `EmbeddedControlProbe` Xcode target and generated gRPC/protobuf sources; +- `start-native-controller-probe`; +- hidden Qt launch with `-qt-hide-window`; +- authenticated `-grpc-use-token` controller behavior; +- the native runtime, automatic Build 8 logger, graphics stack receipts, and current authority documentation. + +Old Clara worktrees and their historical branches remain preserved forensic state. **Do not merge, cherry-pick, rebase, or copy from them merely because Clara still lists them.** They may be consulted only if current canonical `master` demonstrably lacks a required artifact and a targeted append-only plan amendment authorizes recovery. + +## 27. Current documentation and machine-readable authority + +The root authority files now exist and are current. Do not create alternate copies or substitute new authority locations. Use and minimally amend: + +| Authority | Current SHA-256 | Role | +|---|---|---| +| `facts.md` | `78016e5e3c7c08e263e2d8aba435f8519ae199cadc18ea74d6c39634cd0fff18` | locked facts, verified current observations, explicit unknowns | +| `project.md` | `273307f655f0749a12a0a3e48f421f5e61bc6bd40f00b1afb7040c0b2fd15adb` | project history and continuity | +| `dev.md` | `a40e186e4d37a4e7d6024bd069a69509729eb9e6efda36a0fab12162ecf60f7e` | code ownership, active experiments, next engineering gates | +| `benchmark.md` | `15a33754add669bdfea2001053cbfb47df1120658be7f10022a50656fb4069c6` | formulas, validity, SQL, analysis and promotion contract | +| `TFTMAC_GPU_RUNTIME_SSOT.md` | `bad70917a4e3230646748c33a171aeba0f0b1f4ff9b93fdfaa7b04788b84c532` | current stock-runtime and diagnostic-runtime boundary | +| `ssot/STACK.lock.yaml` | `e2b6fca2e3d310f97ca833b0fccd0f5202f766b6f72aeeb795f061a8c1baf096` | machine-readable Build 8 and diagnostic eligibility lock | +| `ssot/AUTHORITY_INPUTS.sha256` | `1d85f4f2f64f3b6089c79385b329dfe42bb479b8c65877c39bf01bdef13703ac` | complete authority-input hash manifest | + +Phase 1 is therefore changed from “discover or create authority files” to **append the causal-logger contract to the existing authority set, update relational/machine-readable receipts, regenerate `ssot/AUTHORITY_INPUTS.sha256`, and prove all hashes and cross-references remain consistent**. + +Do not overwrite the current short `TFTMAC_FULL_IMPLEMENTATION_PLAN.md`; it is intentionally a historical-plan pointer. Store this implementation authority under `.clara/plans/tftmac-causal-graphics-v1/` and add only a concise current-authority reference from existing project documentation when appropriate. + +## 28. The Build 8 degradation capture is now receipted + +The original plan's “claimed prior observation not yet receipted” branch is superseded. Current machine-readable authority records: + +```text +capture ID: 2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200 +private SQLite bytes: 63,897,600 +database SHA-256: c1ef9c9ffe591a297cb86660e3ccfea7e9aeb593f22100e4e732b2fc77d4ee77 +graphics-run duration: 42m27s +exact-layer coverage: 99.629% +frame intervals: 144,364 +weighted FPS: 56.98 +1% low: 21.49 FPS +p95: 21.51 ms +p99: 33.434 ms +maximum interval: 2,233.611 ms +jank: 6,544 / 4.53% +severe stalls: 144 +missed-vsync equivalents: 7,644 +degradation incidents: 189 +root attribution: UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE +``` + +This capture is valid as: + +- proof that automatic PID/layer-lifetime logging works; +- proof that current High/60/OFF does not hold the target continuously; +- the initial symptom signature and incident corpus for diagnostic parity. + +It is **not** an internal root receipt and cannot authorize a patch by itself. The source-instrumented diagnostic program remains necessary. + +## 29. Current renderer and control facts + +The current stack receipt identifies: + +```text +UNREAL_DIRECT_VULKAN + -> GFXSTREAM_ASG + -> HOST_VULKAN + -> MOLTENVK + -> METAL +``` + +ANGLE is conditional and is not assumed to render TFT's main surface. Phase 3 is therefore no longer broad renderer rediscovery. It is a **per-build and per-diagnostic-epoch receipt refresh** that must confirm the exact TFT PID, SurfaceView generation, loaded libraries, queue/device identity, and effective route. If that refresh contradicts `UNREAL_DIRECT_VULKAN`, the conditional ANGLE branch activates exactly as specified earlier. + +The current protected Control remains: + +```text +TFTMAC 2.3.0 build 8 +profile base: tftmac_5gb_native_v1 +6 vCPU / 5120 MiB +1920x1080 / 60 Hz +TFT High / 60 FPS / Performance Mode OFF +stock Android Emulator 37.1.11 +ADB 5038 / console 5582 / emulator-5582 +packaged logged-in-session Emulator Host launch +``` + +Ultra High remains a rejected current setting and the target this plan is intended to make safely promotable; it is not a starting baseline. + +## 30. Revised diagnostic source authority + +The isolated diagnostic source baseline is now explicitly recorded by current TFTMAC authority: + +```text +repository: flashls1/tftmac-runtime +commit: c8aa26ebaa5b977965eb165ad8aac5c98408469f +classification: isolated_non_comparable_diagnostic_eligibility_only +normal-play authority: stock Build 8 +``` + +Phase 4 is amended as follows: + +1. Begin from the exact `flashls1/tftmac-runtime@c8aa26e...` tree. +2. Verify its remote, full commit, clean state, source lock, and relationship to the AEMU/gfxstream/MoltenVK commits before editing. +3. Create an instrumentation branch/worktree in the diagnostic repository; do not import a historical Clara worktree into current TFTMAC `master`. +4. Place source-level guest/host graphics hooks in the diagnostic repository. +5. Place TFTMAC mode orchestration, schema readers, normalizers, deterministic analyzer, UI/reporting, and project documentation in `flashls1/TFTMAC`. +6. Install all diagnostic output under the new isolated diagnostics root; do not recreate the retired normal-play Build tree. +7. Preserve `non_comparable_to_stock=true` until the separate representativeness, instrumentation-disabled A/B, and candidate gates pass. + +If the diagnostic repository has advanced beyond `c8aa26e...`, Codex may use the newer commit only when it is clean, published, contains the same current diagnostic eligibility contract, and records a superseding source lock. Record the selected exact SHA; never silently follow a moving branch. + +## 31. Revised Gate 0A — clean canonical fast path + +The original broad Phase 0 preservation procedure is now conditional rather than mandatory. From the canonical TFTMAC checkout, run: + +```bash +git fetch origin --prune +git switch master +git status --porcelain=v2 -b +git rev-parse HEAD +git rev-parse origin/master +git remote get-url origin +git worktree list --porcelain +shasum -a 256 -c ssot/AUTHORITY_INPUTS.sha256 +/bin/zsh scripts/verify-tftmac.command +``` + +Write `.clara/plans/tftmac-causal-graphics-v1/BASELINE_AUTHORITY.json` containing: + +```json +{ + "repository": "flashls1/TFTMAC", + "branch": "master", + "head_sha": "", + "origin_master_sha": "", + "expected_sha_at_amendment": "c8b79ea009197c25bc7e64bebd5e8948eea918b1", + "working_tree_clean": true, + "authority_inputs_sha256": "1d85f4f2f64f3b6089c79385b329dfe42bb479b8c65877c39bf01bdef13703ac", + "source_verifier": "PASS", + "old_managed_worktrees_imported": false, + "observed_at": "" +} +``` + +### Gate 0A rules + +- If `HEAD == origin/master`, the tree is clean, the authority-input check passes, and `scripts/verify-tftmac.command` passes, create `codex/tftmac-causal-graphics-v1` from that exact HEAD and continue. +- `c8b79ea009197c25bc7e64bebd5e8948eea918b1` is the observed authority at amendment creation, not a command to reset a later clean aligned master backward. If master legitimately advances, record the newer SHA and continue only after the same hash and verifier gates pass. +- If the tree is dirty, stop the fast path and execute the original Phase 0 preservation workflow. Never clean or reset it. +- If local and remote diverge, stop with `BLOCKED_CANONICAL_REPO_DRIFT`. Do not pull/rebase/force automatically. +- If an authority hash fails, stop with `BLOCKED_AUTHORITY_HASH_DRIFT`. +- If the source verifier fails, repair only that exact baseline failure before creating implementation changes. +- Do not copy from the old Clara worktrees to “help” the clean canonical tree. Such an attempt is `BLOCKED_NONCANONICAL_WORKTREE_IMPORT`. + +### Gate 0A acceptance + +```text +CANONICAL_REPOSITORY_CLEAN_ALIGNED +AUTHORITY_INPUTS_PASS +SOURCE_VERIFIER_PASS +IMPLEMENTATION_BRANCH_FROM_CANONICAL_HEAD +NONCANONICAL_WORKTREE_IMPORTS = 0 +``` + +## 32. Current signing-trust issue is separately scoped + +Current authority records that Build 8's historical release hashes match, while the current login keychain exposes no valid `TFTMAC Local Code Signing` identity and deep/strict verification reports `CSSMERR_TP_NOT_TRUSTED`. + +This means: + +- repository changes, source tests, unsigned Release builds, diagnostic-runtime construction, causal logging, root discovery, and instrumentation-disabled diagnostic A/B may proceed; +- do not rebuild or re-sign the protected playable Build 8 merely to clear this operational issue; +- final installed `candidate` validation, signed app replacement, and default cutover remain blocked until the separate signing-identity repair passes `scripts/verify-installed-runtime.command`; +- no code workaround may downgrade or bypass the signing gate. + +This is a delivery-layer blocker only when the plan reaches installed candidate promotion. It is not a reason to stop the causal-logger implementation. + +## 33. Revised immediate implementation sequence + +The original Part XIX start sequence is superseded by this sequence: + +1. Run Gate 0A against current canonical `master`. +2. Create `codex/tftmac-causal-graphics-v1` from the verified clean aligned HEAD. +3. Copy this complete v1.1 plan and the v2 ZenMC receipt into `.clara/plans/tftmac-causal-graphics-v1/`. +4. Preserve the existing execution-scope lock exactly; verify SHA-256 `dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e`. +5. Amend the existing `facts.md`, `project.md`, `dev.md`, `benchmark.md`, current SSOT, engineering map, and performance-lab authority only where the causal contract requires it; do not rewrite unrelated Build 8 history. +6. Add the causal authority/schema/design files named in Phase 1 and regenerate the authority-input manifest. +7. Implement the three-mode registry without changing the default `control`. +8. Create/freeze the diagnostic worktree from `flashls1/tftmac-runtime@c8aa26e...`. +9. Refresh the exact renderer/surface receipt, then prove diagnostic symptom parity before source attribution. +10. Continue with the original event ABI, rings, clocks, work/present lineage, hooks, SQL, analyzer, fault fixtures, root replication, narrow patch, A/B, Ultra High ladder, candidate, rollback, and delivery gates. + +No broad repository cleanup, old-worktree convergence, native-app reconstruction, or logger rediscovery is part of this start sequence. That work is already present in canonical `master`. + +## 34. ZenMC v1.1 delta gate + +A targeted state-machine rerun evaluated the change from “unknown/possibly dirty local authority” to “clean canonical GitHub-aligned authority with conditional fallback.” + +```text +ZENMC DELTA: PASS +randomized adversarial trajectories: 10,000 +model SHA-256: e67e5473b309a210816b87dc55c0765567e4d996b48c9ca982eeb66863d7ad85 +implementation from dirty/diverged repository: 0 +implementation with authority-hash failure: 0 +noncanonical worktree imports admitted: 0 +candidate cutovers without signing validation: 0 +targeted fail-closed cases: 6 / 6 +targeted success cases: 1 / 1 +``` + +Randomized outcome counts: + +```text +READY_FOR_IMPLEMENTATION 5,129 +LEGACY_PHASE0_PRESERVATION_REQUIRED 1,395 +READY_FOR_IMPLEMENTATION_AND_LATER_CUTOVER_GATES 729 +BLOCKED_BASELINE_SOURCE_VALIDATION 656 +BLOCKED_NONCANONICAL_WORKTREE_IMPORT 621 +SOURCE_WORK_READY_CUTOVER_BLOCKED_SIGNING_IDENTITY 601 +BLOCKED_CANONICAL_REPO_DRIFT 516 +BLOCKED_AUTHORITY_HASH_DRIFT 353 +``` + +These weights are adversarial branch-coverage weights, not forecasts. The amendment changes only how implementation safely starts; it does not lower any causal or production acceptance threshold. + +## 35. Effective status after this amendment + +```text +PLAN VERSION: 1.1 +REPOSITORY BASE: CLEAN CANONICAL MASTER +IMPLEMENTATION STATUS: READY AFTER GATE 0A SOURCE/HASH VERIFICATION +CONTROL STATUS: PROTECTED BUILD 8 +CURRENT INTERNAL ROOT: UNKNOWN +DIAGNOSTIC SOURCE ELIGIBILITY: flashls1/tftmac-runtime@c8aa26e... +ULTRA HIGH STATUS: TARGET, NOT CURRENTLY ACCEPTED +FINAL CUTOVER SIGNING STATUS: BLOCKED UNTIL SEPARATE IDENTITY REPAIR +EXECUTION-SCOPE LOCK: UNCHANGED +``` + diff --git a/.clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.json b/.clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.json new file mode 100644 index 0000000..4c86a4e --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.json @@ -0,0 +1,36 @@ +{ + "active_step": "WAVE_B_RUNTIME_MODES_AND_DIAGNOSTIC_BUILD_IDENTITY", + "authority_receipt": { + "path": ".clara/plans/tftmac-causal-graphics-v1/AUTHORITY.json", + "sha256": "290f5e445597b72cd7f65aa4fd07ffba8012df9a636989602a3ebd3d65cd1f51" + }, + "blocked_action": "Diagnostic first boot, loaded-runtime proof, TFT launch, and source instrumentation remain closed while the protected stock runtime is active or until all launch preconditions pass.", + "change_id": "e66bd32e-b6c5-43bd-ae7e-792a234335bf", + "control_runtime_active": true, + "diagnostic_runtime_active": false, + "head_sha": "c8b79ea009197c25bc7e64bebd5e8948eea918b1", + "inferred": [ + "The smallest safe product change is a typed runtime-mode registry plus fail-closed path/lease/identity resolution before any diagnostic boot." + ], + "next_safe_action": "Implement the exact three-mode registry and fail-closed app-side mode/identity plumbing without launching or replacing any runtime.", + "observed_at": "2026-09-01T19:23:52.210992Z", + "project_id": "tftmac", + "schema": 1, + "state": "SOURCE_INTEGRATION_READY_DIAGNOSTIC_BOOT_BLOCKED_CONTROL_ACTIVE", + "unknown": [ + "A collision-free diagnostic EmulatorController port has not yet been selected and receipted.", + "No loaded emulator/gfxstream identity receipt exists because the diagnostic AVD has never booted.", + "Diagnostic AVD package, login availability, gameplay frame, renderer, layer, input, audio, and reconnect acceptance remain untested.", + "No internal graphics root cause is named or inferred." + ], + "verified": [ + "Original implementation plan restored and SHA-256 verified.", + "ZenMC v2 receipt matches its SHA-256 sidecar and reports PASS.", + "Accepted r9 diagnostic build and artifacts match their sealed manifests.", + "Final R9 physical stopped-clone receipt is valid; first boot and launch remain false.", + "Native macOS diagnostic host build is accepted and preserves the /usr/bin/open logged-in-session architecture.", + "The current stock app source has one exact runtime configuration/launch seam, currently hard-coded to the control mode.", + "No diagnostic build, clone, boot, TFT launch, or control-runtime mutation was repeated." + ], + "worktree_status_at_capture": "## clara/integrate-the-accepted-r9-isolated-diagn-e66bd32e\n?? .clara/" +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.md b/.clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.md new file mode 100644 index 0000000..71d6010 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/PREFLIGHT.md @@ -0,0 +1,34 @@ +# Gate 4 App Integration Preflight + +**State:** `SOURCE_INTEGRATION_READY_DIAGNOSTIC_BOOT_BLOCKED_CONTROL_ACTIVE` +**Observed:** `2026-09-01T19:23:52.210992Z` +**Managed change:** `e66bd32e-b6c5-43bd-ae7e-792a234335bf` +**Head:** `c8b79ea009197c25bc7e64bebd5e8948eea918b1` + +## Verified + +- Original implementation plan SHA-256: `78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b`. +- Verified ZenMC receipt SHA-256: `4f0d706f7c5bf5d7f88a1fb4363ef6efeb9f57f678f78a39cf30fec3c5bf1c80`; result `PASS`. +- Accepted diagnostic build: `gate4-r9-20260901`, manifest `9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d`. +- Final stopped clone: `TFTMAC_Diagnostic_API37_R9`, ADB server `5041`, console `5586`, serial `emulator-5586`. +- Clone is physical, sealed before first boot, and the protected control before/after identity matched. +- Accepted native diagnostic host receipt: `a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067`; launch owner is the native macOS app process through `/usr/bin/open`. +- Stock Build 8 active at capture: `true`. +- Diagnostic runtime active at capture: `false`. +- No runtime rebuild, repeat clone, diagnostic boot, TFT launch, or stock mutation was performed. + +## Inferred + +The smallest safe next source change is the plan-authorized three-mode registry and fail-closed app-side mode/identity plumbing. This is not permission to boot while the protected control is active. + +## Unknown / Closed Gates + +- Diagnostic controller port is not yet receipted. +- Loaded emulator and gfxstream identity are unproven. +- Diagnostic package/login/frame/renderer/layer/input/audio/reconnect acceptance is pending. +- Internal Unreal, ANGLE, ASG, gfxstream, MoltenVK, and Metal root ownership remains `UNKNOWN`. +- Source instrumentation remains closed until `DIAGNOSTIC_AVD_ACCEPTANCE_PASS`. + +## Next Causal Action + +Implement the exact three-mode registry and fail-closed app-side mode/identity plumbing without launching or replacing any runtime. diff --git a/.clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt b/.clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt new file mode 100644 index 0000000..34c6ed8 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt @@ -0,0 +1,21 @@ +EXECUTION-SCOPE LOCK — TFTMAC CAUSAL GRAPHICS OPTIMIZATION V1 + +Implement only: +1. Safe reconciliation and preservation of the current local TFTMAC checkout/worktrees. +2. Formal project-authority amendments needed to authorize an isolated diagnostic graphics runtime. +3. A protected control runtime, an isolated advanced_diagnostics runtime, and later a separately gated candidate runtime. +4. Deterministic renderer-path, exact-layer, build-identity, symptom-parity, work-lineage, clock, stream-integrity, and observer-overhead gates. +5. Source instrumentation in only the pinned AEMU/gfxstream/MoltenVK/Metal-facing open-source code needed to localize the first owned graphics divergence. +6. Raw-first fixed-record collection, sealed evidence, deterministic normalization, causal classification, controlled fault fixtures, and append-only SQL evidence. +7. A narrowly targeted settings adjustment or owned-source patch derived from a valid ROOT_NAMED receipt. +8. Controlled A/B validation and the quality-promotion ladder ending at Ultra High / 60 FPS / Performance Mode OFF / 1920x1080 when all acceptance gates pass. +9. A stock-compatible candidate runtime with one-action rollback, only after diagnostic and production-layer acceptance. + +Do not implement: +- Riot APK modification, repacking, re-signing, binary patching, process injection, credential capture, screenshot capture, shader extraction, or fabricated Riot/Unreal source attribution. +- Unrelated refactors, cleanup, renames, reformatting, dependency upgrades, broad architecture replacement, or speculative optimization. +- Any source-built runtime as a hidden replacement for the proven control runtime. +- Any optimization selected only from timestamps, queue handles, aggregate counters, subjective feel, or a single diagnostic epoch. +- Any default-runtime cutover without an exact accepted candidate SHA, a rollback receipt, and Ultra High live acceptance. + +A material diff is permitted only when it traces to this lock, a listed phase deliverable, or a proven blocking dependency added through an append-only amendment and a targeted ZenMC/ZenGate rerun. diff --git a/.clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json b/.clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json new file mode 100644 index 0000000..32e6fa5 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json @@ -0,0 +1,105 @@ +{ + "amendments": [ + { + "authority_inputs_sha256": "1d85f4f2f64f3b6089c79385b329dfe42bb479b8c65877c39bf01bdef13703ac", + "canonical_branch": "master", + "canonical_git_state": { + "ahead": 0, + "aligned_with_origin": true, + "behind": 0, + "clean": true, + "open_pull_requests": 0 + }, + "canonical_head_at_amendment": "c8b79ea009197c25bc7e64bebd5e8948eea918b1", + "canonical_repository": "flashls1/TFTMAC", + "delta_zenmc": { + "invariant_violations": { + "candidate_cutover_without_signing_validation": 0, + "implementation_from_dirty_or_diverged_repo": 0, + "implementation_with_authority_hash_failure": 0, + "noncanonical_worktree_imported": 0 + }, + "model_sha256": "e67e5473b309a210816b87dc55c0765567e4d996b48c9ca982eeb66863d7ad85", + "name": "TFTMAC Causal Graphics Clean Repository Amendment ZenMC Delta", + "note": "Scenario weights are adversarial branch-coverage weights, not empirical probabilities or forecasts.", + "random_outcomes": { + "BLOCKED_AUTHORITY_HASH_DRIFT": 353, + "BLOCKED_BASELINE_SOURCE_VALIDATION": 656, + "BLOCKED_CANONICAL_REPO_DRIFT": 516, + "BLOCKED_NONCANONICAL_WORKTREE_IMPORT": 621, + "LEGACY_PHASE0_PRESERVATION_REQUIRED": 1395, + "READY_FOR_IMPLEMENTATION": 5129, + "READY_FOR_IMPLEMENTATION_AND_LATER_CUTOVER_GATES": 729, + "SOURCE_WORK_READY_CUTOVER_BLOCKED_SIGNING_IDENTITY": 601 + }, + "random_trajectories": 10000, + "result": "PASS", + "seed": 202608311955, + "targeted_cases": { + "authority_hash_drift": "BLOCKED_AUTHORITY_HASH_DRIFT", + "clean_aligned_success": "READY_FOR_IMPLEMENTATION", + "dirty_repo": "LEGACY_PHASE0_PRESERVATION_REQUIRED", + "diverged_repo": "BLOCKED_CANONICAL_REPO_DRIFT", + "missing_signing_identity_at_cutover": "SOURCE_WORK_READY_CUTOVER_BLOCKED_SIGNING_IDENTITY", + "old_worktree_import": "BLOCKED_NONCANONICAL_WORKTREE_IMPORT", + "source_verifier_failure": "BLOCKED_BASELINE_SOURCE_VALIDATION" + }, + "version": "1.1" + }, + "diagnostic_runtime": { + "classification": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", + "commit": "c8aa26ebaa5b977965eb165ad8aac5c98408469f", + "repository": "flashls1/tftmac-runtime" + }, + "id": "TFTMAC_CAUSAL_GRAPHICS_CLEAN_REPOSITORY_V1_1", + "observed_at_local": "2026-08-31 19:55 America/Chicago", + "observed_at_utc": "2026-09-01T00:55:04.583Z", + "stack_lock_sha256": "e2b6fca2e3d310f97ca833b0fccd0f5202f766b6f72aeeb795f061a8c1baf096", + "supersedes": [ + "The old canonical-head observation 365e891ea2950e2cc68a9e4fec683c8538a831e6.", + "The assumption that current native-controller work exists only in dirty Clara worktrees.", + "The instruction to create missing root facts.md, project.md, dev.md, or benchmark.md.", + "The classification of the 42m27s Build 8 capture as unreceipted.", + "The old Phase 0 broad-recovery path when the implementation checkout is clean and aligned." + ], + "type": "APPEND_ONLY_AUTHORITY_AMENDMENT" + } + ], + "invariants": [ + "No control-runtime mutation before accepted production promotion.", + "No ROOT_NAMED without three matching epochs, at least two cold epochs, owned stage, and decisive site.", + "No patch attempt without an owned ROOT_NAMED receipt.", + "No production promotion without diagnostic A/B pass, stock-candidate pass, Ultra High pass, and rollback receipt.", + "Any evidence loss, clock failure, parity failure, surface ambiguity, or observer effect fails closed." + ], + "name": "TFTMAC Causal Graphics Optimization ZenMC", + "note": "Scenario weights are adversarial branch-coverage weights, not empirical probabilities or forecasts.", + "plan_filename": "TFTMAC_CAUSAL_GRAPHICS_OPTIMIZATION_IMPLEMENTATION_PLAN.md", + "plan_version": "1.1", + "random_outcome_examples": { + "BLOCKED_LOCAL_WORK_UNPRESERVED": 799, + "ROOT_CANDIDATE": 139, + "ULTRA_HIGH_60_ACCEPTED": 5, + "UNKNOWN_BOUNDED_TO_STAGE": 44, + "UNKNOWN_CLOCK_UNCERTAINTY": 731, + "UNKNOWN_DIAGNOSTIC_NOT_REPRESENTATIVE": 1302, + "UNKNOWN_HEALTHY_BASELINE_INSUFFICIENT": 867, + "UNKNOWN_OBSERVER_EFFECT": 1091, + "UNKNOWN_PIPELINE_RECEIPT": 1053, + "UNKNOWN_PRESENT_LINEAGE_GAP": 748, + "UNKNOWN_UNREAL_OR_PRE_ENCODER": 53 + }, + "random_trajectories": 10000, + "results": { + "all_targeted_faults_reached_expected_fail_closed_outcome": true, + "early_control_runtime_mutations": 0, + "false_root_named": 0, + "patches_without_owned_root": 0, + "unsafe_production_promotions": 0 + }, + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "seed": 20260831, + "targeted_single_gate_mutations": 24, + "targeted_success_case": 1, + "version": 2 +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.sha256 b/.clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.sha256 new file mode 100644 index 0000000..afe1775 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.sha256 @@ -0,0 +1 @@ +4f0d706f7c5bf5d7f88a1fb4363ef6efeb9f57f678f78a39cf30fec3c5bf1c80 TFTMAC_CAUSAL_GRAPHICS_ZENMC_RECEIPT_V2_VERIFIED_4f0d706f.json From d96a1caf68b807bbae1a03246666da7eea4df620 Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 16:30:37 -0500 Subject: [PATCH 02/10] Add Wave B runtime mode registry authority --- ssot/runtime-modes.json | 115 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 ssot/runtime-modes.json diff --git a/ssot/runtime-modes.json b/ssot/runtime-modes.json new file mode 100644 index 0000000..77c7dee --- /dev/null +++ b/ssot/runtime-modes.json @@ -0,0 +1,115 @@ +{ + "active_lease_relative_path": "State/native-runtime.lease", + "default_mode": "control", + "modes": { + "advanced_diagnostics": { + "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb", + "adb_server_port": 5041, + "allowed_purpose": "ISOLATED_SOURCE_INSTRUMENTATION_AND_ELIGIBILITY", + "application_build": "8", + "application_bundle_id": "com.flashls1.tftmac", + "application_version": "2.3.0", + "authority_manifest": { + "kind": "external_sealed_manifest", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json", + "sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d" + }, + "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd/config.ini", + "avd_config_sha256": "090fe426402562e227a3a1a6bd6eab9f9572cd48fbe3d467c276d419860caf90", + "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd", + "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD", + "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.ini", + "avd_ini_sha256": "30d4ed7ebc20fb3415461fa48f6d91654955e04825de84176bd21a4adad9b98d", + "avd_name": "TFTMAC_Diagnostic_API37_R9", + "comparability_class": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", + "configuration_sha256": "e689fe5c46587b019a5480eabfe32453fa4986a9f6682063d53bb56d2e6aaea6", + "console_port": 5586, + "controller_port": null, + "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator", + "emulator_sha256": "fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa", + "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib", + "gfxstream_backend_sha256": "23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d", + "launch_state": "blocked_pending_controller_lease", + "library_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64", + "mode": "advanced_diagnostics", + "requires_control_stopped": true, + "rollback_target": "control", + "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901", + "serial": "emulator-5586" + }, + "candidate": { + "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/platform-tools/adb", + "adb_server_port": 5042, + "allowed_purpose": "INSTRUMENTATION_DISABLED_STOCK_COMPATIBLE_CANDIDATE", + "application_build": "8", + "application_bundle_id": "com.flashls1.tftmac", + "application_version": "2.3.0", + "authority_manifest": { + "kind": "future_candidate_manifest", + "path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/Manifests/candidate-runtime.json", + "sha256": null + }, + "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/AVD/TFTMAC_Candidate.avd/config.ini", + "avd_config_sha256": null, + "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Candidate/AVD/TFTMAC_Candidate.avd", + "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Candidate/AVD", + "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/AVD/TFTMAC_Candidate.ini", + "avd_ini_sha256": null, + "avd_name": "TFTMAC_Candidate", + "comparability_class": "CANDIDATE_REQUIRES_ACCEPTED_ROOT_PATCH_AND_AB_RECEIPT", + "configuration_sha256": "845af5fb1f012557d7cc297155fdf1b9a08068d4696b4a806faa003628f0308d", + "console_port": 5590, + "controller_port": null, + "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/emulator/emulator", + "emulator_sha256": null, + "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/emulator/lib64/libgfxstream_backend.dylib", + "gfxstream_backend_sha256": null, + "launch_state": "blocked_not_built", + "library_root": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/emulator/lib64", + "mode": "candidate", + "requires_control_stopped": true, + "rollback_target": "control", + "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Candidate", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK", + "serial": "emulator-5590" + }, + "control": { + "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb", + "adb_server_port": 5038, + "allowed_purpose": "PROTECTED_PLAYABLE_CONTROL", + "application_build": "8", + "application_bundle_id": "com.flashls1.tftmac", + "application_version": "2.3.0", + "authority_manifest": { + "kind": "bundled_resource", + "path": "runtime-authority.json", + "sha256": "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" + }, + "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.avd/config.ini", + "avd_config_sha256": null, + "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.avd", + "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", + "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.ini", + "avd_ini_sha256": null, + "avd_name": "TFT_Ultra_Tablet", + "comparability_class": "STOCK_BUILD8_CONTROL", + "configuration_sha256": "bc8408b26402bf53011003afd83944a5fc85f70c4fe1e48909dd2882f8a19633", + "console_port": 5582, + "controller_port": 8554, + "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator", + "emulator_sha256": null, + "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64/libgfxstream_backend.dylib", + "gfxstream_backend_sha256": null, + "launch_state": "enabled", + "library_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64", + "mode": "control", + "requires_control_stopped": false, + "rollback_target": "control", + "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", + "serial": "emulator-5582" + } + }, + "schema": 1 +} From 310404da3ca3edaa63b6ebdecb2acc8d52fb59ba Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 17:48:02 -0500 Subject: [PATCH 03/10] Preserve Wave B draft and checkpoint v3 continuation authority --- .../AppCoordinator.swift.template | 126 ++++ .../INVENTORY.json | 77 ++ .../RuntimeLease.swift.template | 142 ++++ .../RuntimeMode.swift.template | 541 ++++++++++++++ .../apply-waveb-source.mjs | 552 +++++++++++++++ .../preserve-unaccepted-waveb-partial.mjs | 176 +++++ .../runtime-modes.unaccepted.json | 204 ++++++ .../validate-waveb.mjs | 149 ++++ .../wave-b-v2/RuntimeLease.swift.template | 142 ++++ .../wave-b-v2/RuntimeMode.swift.template | 556 +++++++++++++++ .../wave-b-v2/apply-waveb-v2.mjs | 666 ++++++++++++++++++ .../wave-b-v2/gate-waveb-candidate.mjs | 153 ++++ .../wave-b-v3/CONTINUATION_AMENDMENT.md | 39 + .../wave-b-v3/PREFLIGHT.json | 41 ++ .../wave-b-v3/PREPARATION_RECEIPT.json | 19 + .../wave-b-v3/ZENGATE_RECEIPT.json | 37 + .../wave-b-v3/prepare-waveb-v3.mjs | 222 ++++++ 17 files changed, 3842 insertions(+) create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/AppCoordinator.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/INVENTORY.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeLease.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeMode.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/apply-waveb-source.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/preserve-unaccepted-waveb-partial.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/runtime-modes.unaccepted.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/validate-waveb.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/apply-waveb-v2.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/gate-waveb-candidate.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/CONTINUATION_AMENDMENT.md create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREFLIGHT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREPARATION_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/ZENGATE_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/prepare-waveb-v3.mjs diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/AppCoordinator.swift.template b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/AppCoordinator.swift.template new file mode 100644 index 0000000..216e673 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/AppCoordinator.swift.template @@ -0,0 +1,126 @@ +import AppKit + +@MainActor +final class AppCoordinator: NSObject, NSApplicationDelegate { + private let mailbox = LatestFrameMailbox() + private var mainWindowController: MainWindowController? + private var runtimeController: TFTMACRuntimeController? + private var settingsWindowController: RuntimeSettingsWindowController? + private var activeProfile: TFTMACRuntimeProfile = .playable + private var terminationInProgress = false + + func applicationDidFinishLaunching(_ notification: Notification) { + let controller = MainWindowController(mailbox: mailbox) + mainWindowController = controller + let activeProfile = TFTMACRuntimeProfile.load() + self.activeProfile = activeProfile + + let runtimeSelection: TFTMACRuntimeSelection + do { + let registry = try TFTMACRuntimeModeRegistry.loadBundled() + runtimeSelection = try registry.selection() + try runtimeSelection.validateForLaunch() + } catch { + controller.showWindow(nil) + controller.emulatorView.setStatus( + "Runtime mode validation failed: \(error.localizedDescription)", + isError: true + ) + NSApp.activate(ignoringOtherApps: true) + return + } + + let runtime = TFTMACRuntimeController( + profile: activeProfile, + runtimeSelection: runtimeSelection, + mailbox: mailbox, + status: { [weak controller] text, isError in + controller?.emulatorView.setStatus(text, isError: isError) + }, + gameFrame: { [weak controller] window in + controller?.emulatorView.setGameFrameWindow(window) + } + ) + runtimeController = runtime + controller.emulatorView.onTouchInput = { [weak runtime] input in + runtime?.sendTouch(input) + } + controller.emulatorView.onMouseInput = { [weak runtime] x, y, buttons in + runtime?.sendMouse(x: x, y: y, buttons: buttons) + } + controller.emulatorView.onKeyboardInput = { [weak runtime] text, key in + runtime?.sendKeyboard(text: text, key: key) + } + controller.emulatorView.onPresentationSample = { [weak runtime] sample in + runtime?.recordPresentation(sample) + } + controller.emulatorView.onHostPresentationWindow = { [weak runtime] sample in + runtime?.recordHostPresentation(sample) + } + controller.showWindow(nil) + controller.window?.makeFirstResponder(controller.emulatorView) + NSApp.activate(ignoringOtherApps: true) + runtime.start() + DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak controller] in + controller?.enterNativeFullscreen() + } + } + + @objc func showSettings(_ sender: Any?) { + let settings = settingsWindowController ?? RuntimeSettingsWindowController(profile: TFTMACRuntimeProfile.load()) + settings.onSave = { [weak self] previous, next in + self?.runtimeController?.recordSettingsChange(previous: previous, next: next) + } + settingsWindowController = settings + settings.refreshFromSavedProfile() + settings.showWindow(sender) + settings.window?.makeKeyAndOrderFront(sender) + NSApp.activate(ignoringOtherApps: true) + } + + @objc func markMatchEntry(_ sender: Any?) { recordMarker("MATCH_ENTRY") } + @objc func startCombatBenchmark(_ sender: Any?) { + runtimeController?.startCombatBenchmark(performanceModeConfirmed: false) + } + @objc func markVisibleStutter(_ sender: Any?) { runtimeController?.markVisibleStutter() } + @objc func endCombatBenchmark(_ sender: Any?) { + var correctnessPassed = true + if activeProfile.experimentPreset.isActiveCandidate { + let alert = NSAlert() + alert.messageText = "Did Combat Latency A preserve correctness?" + alert.informativeText = "Reject the run if boot, graphics, input, audio, login, or gameplay correctness regressed. TFTMAC will restore Control for the next launch." + alert.alertStyle = .informational + alert.addButton(withTitle: "All Correct — End") + alert.addButton(withTitle: "Reject: Correctness Problem") + correctnessPassed = alert.runModal() == .alertFirstButtonReturn + } + runtimeController?.endCombatBenchmark(correctnessPassed: correctnessPassed) + } + @objc func markMatchEnd(_ sender: Any?) { recordMarker("MATCH_END") } + + @objc func revealCaptureFolder(_ sender: Any?) { + let captures = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC/Captures", isDirectory: true) + try? FileManager.default.createDirectory(at: captures, withIntermediateDirectories: true) + NSWorkspace.shared.open(captures) + } + + private func recordMarker(_ marker: String) { + runtimeController?.recordMarker(marker) + } + + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + true + } + + func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { + if terminationInProgress { return .terminateLater } + guard let runtimeController else { return .terminateNow } + terminationInProgress = true + Task { @MainActor in + await runtimeController.stop() + sender.reply(toApplicationShouldTerminate: true) + } + return .terminateLater + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/INVENTORY.json b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/INVENTORY.json new file mode 100644 index 0000000..055c76c --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/INVENTORY.json @@ -0,0 +1,77 @@ +{ + "schema": 1, + "state": "UNACCEPTED_WAVE_B_DRAFT_PRESERVED", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-01T22:47:27.564Z", + "rejected_registry_sha256": "457ca5865f1bfcfaca16bd1eee1f32db15f90bd9c8764706ba64db56b7a9e518", + "accepted_registry_restored_sha256": "81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2", + "preserved": [ + { + "source": "ssot/runtime-modes.json", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/runtime-modes.unaccepted.json", + "sha256": "457ca5865f1bfcfaca16bd1eee1f32db15f90bd9c8764706ba64db56b7a9e518", + "bytes": 9665 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/AppCoordinator.swift.template", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/AppCoordinator.swift.template", + "sha256": "5e95ff55b865d217e058ce252e8052eaba79a47bfd860c43cc9740e126ee35f6", + "bytes": 5567 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/RuntimeLease.swift.template", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeLease.swift.template", + "sha256": "de774fd9bd59020093ec35736374f0dfc6013831132ba42c386c6188a4bbe72e", + "bytes": 5137 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/RuntimeMode.swift.template", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeMode.swift.template", + "sha256": "2e105ff01b778e98a4a6ef33e0c02972102b4b73aa0c8cd2250eafb2bac6b113", + "bytes": 23127 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/apply-waveb-source.mjs", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/apply-waveb-source.mjs", + "sha256": "1f07d2f828db3ada7a5e91502610a8c473a25ffffb546d9a99749484c34337de", + "bytes": 32420 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/preserve-unaccepted-waveb-partial.mjs", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/preserve-unaccepted-waveb-partial.mjs", + "sha256": "3147b1ccd63acb2d373d54ccbe137d494bd2063fddf809656479a8d9ec20fadc", + "bytes": 8360 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/validate-waveb.mjs", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/validate-waveb.mjs", + "sha256": "b78d9ad64882a7ad7e154e013dee3207dff2f83559f4570e6da5a7494c0d719c", + "bytes": 6605 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/wave-b-v2/RuntimeLease.swift.template", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template", + "sha256": "f3b4db12f4e8c085343d87813ab026ff6045ec679cb8afea48dd87bf8f04c0f9", + "bytes": 5159 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/wave-b-v2/RuntimeMode.swift.template", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template", + "sha256": "cb8e62545832e457e12046bed5eb8dcd72a17feb090ce3dad3e15b6cfad7f60f", + "bytes": 23785 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/wave-b-v2/apply-waveb-v2.mjs", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/apply-waveb-v2.mjs", + "sha256": "07bcf67d0b3d6b549334b2b5636fb92af801d4d2c6f09958fa94b7c0e8556865", + "bytes": 39261 + }, + { + "source": ".clara/plans/tftmac-causal-graphics-v1/wave-b-v2/gate-waveb-candidate.mjs", + "preserved_path": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/gate-waveb-candidate.mjs", + "sha256": "1d661898f48386ab91519ad1ca6c1653e335eb8c1dcc24a96547c8c07f0a3330", + "bytes": 8629 + } + ] +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeLease.swift.template b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeLease.swift.template new file mode 100644 index 0000000..b430767 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeLease.swift.template @@ -0,0 +1,142 @@ +import Darwin +import Foundation + +enum RuntimeLeaseError: LocalizedError, Sendable { + case alreadyOwned(processIdentifier: Int32) + case cannotCreate(String) + + var errorDescription: String? { + switch self { + case .alreadyOwned(let processIdentifier): + return "TFTMAC runtime is already owned by process \(processIdentifier). Close the other TFTMAC session first." + case .cannotCreate(let reason): + return "TFTMAC could not acquire its runtime lease: \(reason)" + } + } +} + +final class TFTMACRuntimeLease: @unchecked Sendable { + private struct Payload: Codable { + let schema: Int + let pid: Int32 + let token: String + let createdUTC: String + let identity: TFTMACRuntimeLeaseIdentity? + + enum CodingKeys: String, CodingKey { + case schema + case pid + case token + case createdUTC = "created_utc" + case identity + } + } + + let processIdentifier: Int32 + let token: String + let url: URL + let identity: TFTMACRuntimeLeaseIdentity? + private var released = false + + private init( + url: URL, + processIdentifier: Int32, + token: String, + identity: TFTMACRuntimeLeaseIdentity? + ) { + self.url = url + self.processIdentifier = processIdentifier + self.token = token + self.identity = identity + } + + static func acquire( + stateRoot: URL, + identity: TFTMACRuntimeLeaseIdentity? = nil, + processIdentifier: Int32 = ProcessInfo.processInfo.processIdentifier + ) throws -> Self { + try FileManager.default.createDirectory( + at: stateRoot, + withIntermediateDirectories: true, + attributes: [.posixPermissions: 0o700] + ) + let url = stateRoot.appendingPathComponent("native-runtime.lease") + let token = UUID().uuidString.lowercased() + for _ in 0..<2 { + let descriptor = Darwin.open(url.path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR) + if descriptor >= 0 { + let payload = Payload( + schema: 2, + pid: processIdentifier, + token: token, + createdUTC: ISO8601DateFormatter().string(from: Date()), + identity: identity + ) + do { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + let data = try encoder.encode(payload) + try writeAll(data, to: descriptor) + _ = Darwin.fsync(descriptor) + Darwin.close(descriptor) + return Self( + url: url, + processIdentifier: processIdentifier, + token: token, + identity: identity + ) + } catch { + Darwin.close(descriptor) + try? FileManager.default.removeItem(at: url) + throw RuntimeLeaseError.cannotCreate(error.localizedDescription) + } + } + guard errno == EEXIST else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } + if let owner = leaseOwner(at: url), processExists(owner) { + throw RuntimeLeaseError.alreadyOwned(processIdentifier: owner) + } + do { try FileManager.default.removeItem(at: url) } + catch { throw RuntimeLeaseError.cannotCreate("stale lease could not be removed") } + } + throw RuntimeLeaseError.cannotCreate("another launch won the lease race") + } + + func release() { + guard !released else { return } + released = true + guard let payload = payload(at: url), payload.token == token else { return } + try? FileManager.default.removeItem(at: url) + } + + deinit { release() } + + private static func payload(at url: URL) -> Payload? { + guard let data = try? Data(contentsOf: url) else { return nil } + return try? JSONDecoder().decode(Payload.self, from: data) + } + + private static func leaseOwner(at url: URL) -> Int32? { + payload(at: url)?.pid + } + + private static func processExists(_ processIdentifier: Int32) -> Bool { + if Darwin.kill(processIdentifier, 0) == 0 { return true } + return errno != ESRCH + } + + private static func writeAll(_ data: Data, to descriptor: Int32) throws { + try data.withUnsafeBytes { rawBuffer in + guard let baseAddress = rawBuffer.baseAddress else { return } + var written = 0 + while written < rawBuffer.count { + let result = Darwin.write(descriptor, baseAddress.advanced(by: written), rawBuffer.count - written) + guard result > 0 else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } + written += result + } + } + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeMode.swift.template b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeMode.swift.template new file mode 100644 index 0000000..4af4b25 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/RuntimeMode.swift.template @@ -0,0 +1,541 @@ +import CryptoKit +import Foundation + +enum TFTMACRuntimeMode: String, Codable, CaseIterable, Sendable { + case control + case advancedDiagnostics = "advanced_diagnostics" + case candidate +} + +enum TFTMACRuntimeModeLaunchState: String, Codable, Sendable { + case enabled + case blockedPendingControllerLease = "blocked_pending_controller_lease" + case blockedNotBuilt = "blocked_not_built" +} + +struct TFTMACRuntimeModeError: LocalizedError, Sendable { + let message: String + + var errorDescription: String? { message } +} + +struct TFTMACRuntimeModeManifest: Codable, Equatable, Sendable { + let kind: String + let path: String + let sha256: String? +} + +struct TFTMACRuntimeModeDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let launchState: TFTMACRuntimeModeLaunchState + let runtimeRoot: String + let sdkRoot: String + let libraryRoot: String + let emulatorPath: String + let emulatorSha256: String? + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String? + let adbPath: String + let avdHome: String + let avdName: String + let avdDirectory: String + let avdConfigPath: String + let avdConfigSha256: String? + let avdIniPath: String + let avdIniSha256: String? + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int? + let serial: String + let authorityManifest: TFTMACRuntimeModeManifest + let applicationBundleId: String + let applicationVersion: String + let applicationBuild: String + let allowedPurpose: String + let comparabilityClass: String + let rollbackTarget: TFTMACRuntimeMode + let requiresControlStopped: Bool + let configurationSha256: String + + var computedConfigurationSha256: String { + let fields = [ + "mode=\(mode.rawValue)", + "launch_state=\(launchState.rawValue)", + "runtime_root=\(runtimeRoot)", + "sdk_root=\(sdkRoot)", + "library_root=\(libraryRoot)", + "emulator_path=\(emulatorPath)", + "emulator_sha256=\(emulatorSha256 ?? \"\")", + "gfxstream_backend_path=\(gfxstreamBackendPath)", + "gfxstream_backend_sha256=\(gfxstreamBackendSha256 ?? \"\")", + "adb_path=\(adbPath)", + "avd_home=\(avdHome)", + "avd_name=\(avdName)", + "avd_directory=\(avdDirectory)", + "avd_config_path=\(avdConfigPath)", + "avd_config_sha256=\(avdConfigSha256 ?? \"\")", + "avd_ini_path=\(avdIniPath)", + "avd_ini_sha256=\(avdIniSha256 ?? \"\")", + "adb_server_port=\(adbServerPort)", + "console_port=\(consolePort)", + "controller_port=\(controllerPort.map(String.init) ?? \"\")", + "serial=\(serial)", + "authority_manifest_kind=\(authorityManifest.kind)", + "authority_manifest_path=\(authorityManifest.path)", + "authority_manifest_sha256=\(authorityManifest.sha256 ?? \"\")", + "application_bundle_id=\(applicationBundleId)", + "application_version=\(applicationVersion)", + "application_build=\(applicationBuild)", + "allowed_purpose=\(allowedPurpose)", + "comparability_class=\(comparabilityClass)", + "rollback_target=\(rollbackTarget.rawValue)", + "requires_control_stopped=\(requiresControlStopped ? \"true\" : \"false\")" + ] + return Self.sha256Hex(Data(fields.joined(separator: "\n").utf8)) + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} + +struct TFTMACRuntimeModeRegistryDocument: Codable, Equatable, Sendable { + let schema: Int + let defaultMode: TFTMACRuntimeMode + let activeLeaseRelativePath: String + let modes: [String: TFTMACRuntimeModeDefinition] +} + +struct TFTMACRuntimeLeaseIdentity: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let avdName: String + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + let configurationSha256: String + + enum CodingKeys: String, CodingKey { + case mode + case avdName = "avd_name" + case adbServerPort = "adb_server_port" + case consolePort = "console_port" + case controllerPort = "controller_port" + case serial + case configurationSha256 = "configuration_sha256" + } +} + +struct TFTMACRuntimeSelection: Equatable, Sendable { + let registrySha256: String + let activeLeaseRelativePath: String + let definition: TFTMACRuntimeModeDefinition + + var mode: TFTMACRuntimeMode { definition.mode } + + func leaseIdentity() throws -> TFTMACRuntimeLeaseIdentity { + guard let controllerPort = definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted EmulatorController port receipt." + ) + } + return TFTMACRuntimeLeaseIdentity( + mode: mode, + avdName: definition.avdName, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial, + configurationSha256: definition.configurationSha256 + ) + } + + func validateForLaunch( + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws { + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + _ = try leaseIdentity() + + guard bundle.bundleIdentifier == definition.applicationBundleId else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected the application bundle identity." + ) + } + let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String + let build = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String + guard version == definition.applicationVersion, build == definition.applicationBuild else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected application version/build \(version ?? \"unknown\")/\(build ?? \"unknown\")." + ) + } + + try requireDirectory(definition.runtimeRoot, label: "runtime root", fileManager: fileManager) + try requireDirectory(definition.sdkRoot, label: "SDK root", fileManager: fileManager) + try requireDirectory(definition.libraryRoot, label: "library root", fileManager: fileManager) + try requireDirectory(definition.avdHome, label: "AVD home", fileManager: fileManager) + try requireDirectory(definition.avdDirectory, label: "AVD directory", fileManager: fileManager) + try requireExecutable(definition.emulatorPath, label: "emulator", fileManager: fileManager) + try requireExecutable(definition.adbPath, label: "ADB", fileManager: fileManager) + try requireFile(definition.gfxstreamBackendPath, label: "gfxstream backend", fileManager: fileManager) + try requireFile(definition.avdConfigPath, label: "AVD config", fileManager: fileManager) + try requireFile(definition.avdIniPath, label: "AVD ini", fileManager: fileManager) + + let manifestURL: URL + switch definition.authorityManifest.kind { + case "bundled_resource": + guard let resourceURL = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + manifestURL = resourceURL.appendingPathComponent(definition.authorityManifest.path) + case "external_sealed_manifest": + manifestURL = URL(fileURLWithPath: definition.authorityManifest.path) + default: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has unsupported manifest authority \(definition.authorityManifest.kind)." + ) + } + guard let expectedManifestSha256 = definition.authorityManifest.sha256 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted manifest SHA-256." + ) + } + try validateSHA256(at: manifestURL, expected: expectedManifestSha256, label: "authority manifest") + try validateOptionalSHA256(path: definition.emulatorPath, expected: definition.emulatorSha256, label: "emulator") + try validateOptionalSHA256( + path: definition.gfxstreamBackendPath, + expected: definition.gfxstreamBackendSha256, + label: "gfxstream backend" + ) + try validateOptionalSHA256(path: definition.avdConfigPath, expected: definition.avdConfigSha256, label: "AVD config") + try validateOptionalSHA256(path: definition.avdIniPath, expected: definition.avdIniSha256, label: "AVD ini") + } + + private func requireDirectory(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireFile(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), !isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireExecutable(_ path: String, label: String, fileManager: FileManager) throws { + guard fileManager.isExecutableFile(atPath: path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no executable \(label) at \(path)." + ) + } + } + + private func validateOptionalSHA256(path: String, expected: String?, label: String) throws { + guard let expected else { return } + try validateSHA256(at: URL(fileURLWithPath: path), expected: expected, label: label) + } + + private func validateSHA256(at url: URL, expected: String, label: String) throws { + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not open its \(label) at \(url.path): \(error.localizedDescription)" + ) + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not hash its \(label): \(error.localizedDescription)" + ) + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected \(label) SHA-256 \(observed)." + ) + } + } +} + +struct TFTMACRuntimeModeRegistry: Sendable { + static let environmentKey = "TFTMAC_RUNTIME_MODE" + + let document: TFTMACRuntimeModeRegistryDocument + let registrySha256: String + + init(data: Data) throws { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeRegistryDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + try Self.validate(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read runtime-modes.json: \(error.localizedDescription)" + ) + } + } + + var defaultMode: TFTMACRuntimeMode { document.defaultMode } + + var registeredModes: Set { + Set(document.modes.values.map(\.mode)) + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is not registered.") + } + return definition + } + + func selection(environment: [String: String] = ProcessInfo.processInfo.environment) throws -> TFTMACRuntimeSelection { + let requested = environment[Self.environmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines) + let mode: TFTMACRuntimeMode + if let requested, !requested.isEmpty { + guard let parsed = TFTMACRuntimeMode(rawValue: requested) else { + throw TFTMACRuntimeModeError(message: "Unknown TFTMAC runtime mode \(requested).") + } + mode = parsed + } else { + mode = document.defaultMode + } + let definition = try definition(for: mode) + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + return TFTMACRuntimeSelection( + registrySha256: registrySha256, + activeLeaseRelativePath: document.activeLeaseRelativePath, + definition: definition + ) + } + + private static func validate(_ document: TFTMACRuntimeModeRegistryDocument) throws { + guard document.schema == 1 else { + throw TFTMACRuntimeModeError(message: "Unsupported runtime-mode registry schema \(document.schema).") + } + guard document.defaultMode == .control else { + throw TFTMACRuntimeModeError(message: "The default TFTMAC runtime mode must remain control.") + } + guard document.activeLeaseRelativePath == "State/native-runtime.lease" else { + throw TFTMACRuntimeModeError(message: "The runtime-mode registry changed the protected lease path.") + } + + let expectedKeys = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == expectedKeys else { + throw TFTMACRuntimeModeError( + message: "The runtime-mode registry must contain exactly control, advanced_diagnostics, and candidate." + ) + } + + var occupiedPorts: [Int: String] = [:] + for (key, definition) in document.modes { + guard key == definition.mode.rawValue else { + throw TFTMACRuntimeModeError( + message: "Runtime-mode registry key \(key) does not match \(definition.mode.rawValue)." + ) + } + try validate(definition) + for (kind, port) in [ + ("adb", Optional(definition.adbServerPort)), + ("console", Optional(definition.consolePort)), + ("controller", definition.controllerPort) + ] { + guard let port else { continue } + if let existing = occupiedPorts[port] { + throw TFTMACRuntimeModeError( + message: "Runtime lease port \(port) is shared by \(existing) and \(definition.mode.rawValue).\(kind)." + ) + } + occupiedPorts[port] = "\(definition.mode.rawValue).\(kind)" + } + } + + let control = try required(.control, from: document) + guard control.launchState == .enabled, + control.runtimeRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime", + control.sdkRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", + control.avdHome == "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", + control.avdName == "TFT_Ultra_Tablet", + control.adbServerPort == 5038, + control.consolePort == 5582, + control.controllerPort == 8554, + control.serial == "emulator-5582", + control.authorityManifest.kind == "bundled_resource", + control.authorityManifest.path == "runtime-authority.json", + control.authorityManifest.sha256 != nil, + control.emulatorSha256 != nil, + control.gfxstreamBackendSha256 != nil, + control.rollbackTarget == .control, + !control.requiresControlStopped else { + throw TFTMACRuntimeModeError( + message: "The control mode no longer matches the accepted stock Build 8 authority." + ) + } + + let diagnostics = try required(.advancedDiagnostics, from: document) + guard diagnostics.launchState == .blockedPendingControllerLease, + diagnostics.controllerPort == nil, + diagnostics.avdName == "TFTMAC_Diagnostic_API37_R9", + diagnostics.adbServerPort == 5041, + diagnostics.consolePort == 5586, + diagnostics.serial == "emulator-5586", + diagnostics.emulatorSha256 != nil, + diagnostics.gfxstreamBackendSha256 != nil, + diagnostics.avdConfigSha256 != nil, + diagnostics.avdIniSha256 != nil, + diagnostics.requiresControlStopped, + diagnostics.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Advanced diagnostics must remain isolated and blocked pending its controller-port receipt." + ) + } + + let candidate = try required(.candidate, from: document) + guard candidate.launchState == .blockedNotBuilt, + candidate.controllerPort == nil, + candidate.requiresControlStopped, + candidate.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Candidate mode must remain blocked until a separately accepted candidate exists." + ) + } + } + + private static func validate(_ definition: TFTMACRuntimeModeDefinition) throws { + let requiredStrings = [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdName, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath, + definition.serial, + definition.authorityManifest.kind, + definition.authorityManifest.path, + definition.applicationBundleId, + definition.applicationVersion, + definition.applicationBuild, + definition.allowedPurpose, + definition.comparabilityClass + ] + guard requiredStrings.allSatisfy({ !$0.isEmpty }) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) has an empty required field." + ) + } + for path in [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath + ] { + guard path.hasPrefix("/") else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains a non-absolute path." + ) + } + } + guard (1...65535).contains(definition.adbServerPort), + (1...65535).contains(definition.consolePort), + definition.controllerPort.map({ (1...65535).contains($0) }) ?? true else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid lease port." + ) + } + guard definition.serial == "emulator-\(definition.consolePort)" else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) serial does not match its console lease." + ) + } + if definition.launchState == .enabled, definition.controllerPort == nil { + throw TFTMACRuntimeModeError( + message: "Launch-ready mode \(definition.mode.rawValue) has no controller-port receipt." + ) + } + for digest in [ + Optional(definition.configurationSha256), + definition.emulatorSha256, + definition.gfxstreamBackendSha256, + definition.avdConfigSha256, + definition.avdIniSha256, + definition.authorityManifest.sha256 + ].compactMap({ $0 }) { + guard isSHA256(digest) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid SHA-256 value." + ) + } + } + guard definition.computedConfigurationSha256 == definition.configurationSha256.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) configuration SHA-256 does not match its fields." + ) + } + } + + private static func required( + _ mode: TFTMACRuntimeMode, + from document: TFTMACRuntimeModeRegistryDocument + ) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/apply-waveb-source.mjs b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/apply-waveb-source.mjs new file mode 100644 index 0000000..621a104 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/apply-waveb-source.mjs @@ -0,0 +1,552 @@ +import fs from "node:fs"; +import path from "node:path"; +import crypto from "node:crypto"; + +const root = process.cwd(); +const planRoot = ".clara/plans/tftmac-causal-graphics-v1"; +const operationId = "tftmac-waveb-source-apply-20260901-v1"; + +const expectedInputs = { + [`${planRoot}/SCOPE_LOCK.txt`]: "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + [`${planRoot}/RuntimeMode.swift.template`]: "2e105ff01b778e98a4a6ef33e0c02972102b4b73aa0c8cd2250eafb2bac6b113", + [`${planRoot}/RuntimeLease.swift.template`]: "de774fd9bd59020093ec35736374f0dfc6013831132ba42c386c6188a4bbe72e", + [`${planRoot}/AppCoordinator.swift.template`]: "5e95ff55b865d217e058ce252e8052eaba79a47bfd860c43cc9740e126ee35f6", + "ssot/runtime-modes.json": "7912c8d40027a7dbf99b9a91f495493a918ef38921fa5cc4077fddfd987fe579", + "ssot/runtime-authority.json": "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f", + "tftmac/App/AppCoordinator.swift": "d0eb27df9a0e6aaa45ff60c63fd81bc229350a6f8feca833b776bbe4a954bda4", + "tftmac/Runtime/RuntimeLease.swift": "55a44dbd5fc8b112cb48d17e879c00ae068161f2755af1876244e03bf75b498b", + "tftmac/Runtime/TFTMACRuntime.swift": "8932032d93af01b46e46b5fb5a04eff1ec457f2f0e8f92f364d5a1a703ab5a5f", + "TFTMAC.xcodeproj/project.pbxproj": "4961d37cc1802ca179b7f115ff4be3a4f1c222e706a01aff9f137fcb27c57dfd", + "Tests/TFTMACTests/TFTMACGate1Tests.swift": "3a3307d19d2a48c22ee5504c96b4ee9e428992d2b026bedec2946240abc803d6", + "scripts/verify-tftmac.command": "d587850fef7d5b25bf2a46cf6249824703130761b1ed388e1e93c485be763ccc" +}; + +const templatePaths = [ + `${planRoot}/RuntimeMode.swift.template`, + `${planRoot}/RuntimeLease.swift.template`, + `${planRoot}/AppCoordinator.swift.template` +]; + +function absolute(relativePath) { + return path.join(root, relativePath); +} + +function sha256Buffer(buffer) { + return crypto.createHash("sha256").update(buffer).digest("hex"); +} + +function sha256Text(text) { + return sha256Buffer(Buffer.from(text, "utf8")); +} + +function sha256FileSync(relativePath) { + return sha256Buffer(fs.readFileSync(absolute(relativePath))); +} + +async function sha256ExternalFile(filePath) { + return await new Promise((resolve, reject) => { + const hash = crypto.createHash("sha256"); + const stream = fs.createReadStream(filePath); + stream.on("data", (chunk) => hash.update(chunk)); + stream.on("error", reject); + stream.on("end", () => resolve(hash.digest("hex"))); + }); +} + +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +function readText(relativePath) { + return fs.readFileSync(absolute(relativePath), "utf8"); +} + +function replaceOnce(text, before, after, label) { + const first = text.indexOf(before); + assert(first >= 0, `${label}: required anchor was not found`); + assert(text.indexOf(before, first + before.length) < 0, `${label}: required anchor was not unique`); + return text.slice(0, first) + after + text.slice(first + before.length); +} + +function insertBefore(text, marker, insertion, label) { + const index = text.indexOf(marker); + assert(index >= 0, `${label}: insertion marker was not found`); + assert(text.indexOf(marker, index + marker.length) < 0, `${label}: insertion marker was not unique`); + return text.slice(0, index) + insertion + text.slice(index); +} + +function configurationHash(mode) { + const values = [ + ["mode", mode.mode], + ["launch_state", mode.launch_state], + ["runtime_root", mode.runtime_root], + ["sdk_root", mode.sdk_root], + ["library_root", mode.library_root], + ["emulator_path", mode.emulator_path], + ["emulator_sha256", mode.emulator_sha256 ?? ""], + ["gfxstream_backend_path", mode.gfxstream_backend_path], + ["gfxstream_backend_sha256", mode.gfxstream_backend_sha256 ?? ""], + ["adb_path", mode.adb_path], + ["avd_home", mode.avd_home], + ["avd_name", mode.avd_name], + ["avd_directory", mode.avd_directory], + ["avd_config_path", mode.avd_config_path], + ["avd_config_sha256", mode.avd_config_sha256 ?? ""], + ["avd_ini_path", mode.avd_ini_path], + ["avd_ini_sha256", mode.avd_ini_sha256 ?? ""], + ["adb_server_port", mode.adb_server_port], + ["console_port", mode.console_port], + ["controller_port", mode.controller_port ?? ""], + ["serial", mode.serial], + ["authority_manifest_kind", mode.authority_manifest.kind], + ["authority_manifest_path", mode.authority_manifest.path], + ["authority_manifest_sha256", mode.authority_manifest.sha256 ?? ""], + ["application_bundle_id", mode.application_bundle_id], + ["application_version", mode.application_version], + ["application_build", mode.application_build], + ["allowed_purpose", mode.allowed_purpose], + ["comparability_class", mode.comparability_class], + ["rollback_target", mode.rollback_target], + ["requires_control_stopped", String(mode.requires_control_stopped)] + ]; + return sha256Text(values.map(([key, value]) => `${key}=${value}`).join("\n")); +} + +function validateRegistry(registry) { + assert(registry.schema === 1, "runtime registry schema must be 1"); + assert(registry.default_mode === "control", "control must remain the default runtime mode"); + assert(registry.active_lease_relative_path === "State/native-runtime.lease", "runtime lease path drifted"); + const names = Object.keys(registry.modes).sort(); + assert(JSON.stringify(names) === JSON.stringify(["advanced_diagnostics", "candidate", "control"]), "runtime registry must define exactly three modes"); + const occupied = new Map(); + for (const [name, mode] of Object.entries(registry.modes)) { + assert(name === mode.mode, `runtime registry key mismatch for ${name}`); + assert(configurationHash(mode) === mode.configuration_sha256, `configuration SHA mismatch for ${name}`); + assert(mode.serial === `emulator-${mode.console_port}`, `serial/console mismatch for ${name}`); + for (const [kind, value] of [["adb", mode.adb_server_port], ["console", mode.console_port], ["controller", mode.controller_port]]) { + if (value === null) continue; + assert(Number.isInteger(value) && value > 0 && value <= 65535, `invalid ${kind} port for ${name}`); + assert(!occupied.has(value), `port ${value} is shared by ${occupied.get(value)} and ${name}.${kind}`); + occupied.set(value, `${name}.${kind}`); + } + } + const control = registry.modes.control; + assert(control.launch_state === "enabled", "control must remain enabled"); + assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, "control lease identity drifted"); + assert(control.serial === "emulator-5582", "control serial drifted"); + assert(control.rollback_target === "control" && control.requires_control_stopped === false, "control rollback contract drifted"); + const diagnostics = registry.modes.advanced_diagnostics; + assert(diagnostics.launch_state === "blocked_pending_controller_lease" && diagnostics.controller_port === null, "diagnostics must remain blocked pending a controller receipt"); + assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.serial === "emulator-5586", "diagnostic lease identity drifted"); + assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === "control", "diagnostic noninterference contract drifted"); + const candidate = registry.modes.candidate; + assert(candidate.launch_state === "blocked_not_built" && candidate.controller_port === null, "candidate must remain blocked until built and accepted"); + assert(candidate.requires_control_stopped === true && candidate.rollback_target === "control", "candidate rollback contract drifted"); +} + +for (const [relativePath, expected] of Object.entries(expectedInputs)) { + assert(fs.existsSync(absolute(relativePath)), `required input is missing: ${relativePath}`); + const observed = sha256FileSync(relativePath); + assert(observed === expected, `input drift for ${relativePath}: expected ${expected}, observed ${observed}`); +} +assert(!fs.existsSync(absolute("tftmac/Runtime/RuntimeMode.swift")), "RuntimeMode.swift already exists; refusing a non-idempotent replay"); + +const registry = JSON.parse(readText("ssot/runtime-modes.json")); +validateRegistry(registry); +const control = registry.modes.control; +control.emulator_sha256 = await sha256ExternalFile(control.emulator_path); +control.gfxstream_backend_sha256 = await sha256ExternalFile(control.gfxstream_backend_path); +control.configuration_sha256 = configurationHash(control); +validateRegistry(registry); +const registryOutput = `${JSON.stringify(registry, null, 2)}\n`; + +const runtimeModeOutput = readText(`${planRoot}/RuntimeMode.swift.template`); +const runtimeLeaseOutput = readText(`${planRoot}/RuntimeLease.swift.template`); +const appCoordinatorOutput = readText(`${planRoot}/AppCoordinator.swift.template`); + +let runtime = readText("tftmac/Runtime/TFTMACRuntime.swift"); +const actorStart = runtime.indexOf("actor TFTMACRuntimeService {"); +const controllerStart = runtime.lastIndexOf("final class TFTMACRuntimeController"); +assert(actorStart >= 0 && controllerStart > actorStart, "runtime service/controller boundaries were not found"); +const runtimePrefix = runtime.slice(0, actorStart); +let actor = runtime.slice(actorStart, controllerStart); +let controller = runtime.slice(controllerStart); + +actor = replaceOnce( + actor, + " private let profile: TFTMACRuntimeProfile\n", + " private let profile: TFTMACRuntimeProfile\n private let runtimeSelection: TFTMACRuntimeSelection\n", + "runtime service selection field" +); +actor = replaceOnce( + actor, + " init(\n profile: TFTMACRuntimeProfile,\n mailbox: LatestFrameMailbox,", + " init(\n profile: TFTMACRuntimeProfile,\n runtimeSelection: TFTMACRuntimeSelection,\n mailbox: LatestFrameMailbox,", + "runtime service initializer signature" +); +actor = replaceOnce( + actor, + " self.profile = profile\n self.mailbox = mailbox", + " self.profile = profile\n self.runtimeSelection = runtimeSelection\n self.mailbox = mailbox", + "runtime service initializer assignment" +); + +const oldLeaseBlock = String.raw` let paths = try TFTMACRuntimePaths.discover() + self.paths = paths + let stateRoot = paths.applicationSupport.appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot) + telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ + "lease": "State/native-runtime.lease", + "pid": ProcessInfo.processInfo.processIdentifier, + "exclusive": true + ])`; +const newLeaseBlock = String.raw` try runtimeSelection.validateForLaunch() + let leaseIdentity = try runtimeSelection.leaseIdentity() + guard profile.controllerPort == leaseIdentity.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime profile controller port \(profile.controllerPort) does not match the accepted \(runtimeSelection.mode.rawValue) lease port \(leaseIdentity.controllerPort)." + ) + } + let definition = runtimeSelection.definition + let paths = try TFTMACRuntimePaths.discover() + guard paths.sdkRoot.standardizedFileURL.path == URL(fileURLWithPath: definition.sdkRoot, isDirectory: true).standardizedFileURL.path, + paths.emulator.standardizedFileURL.path == URL(fileURLWithPath: definition.emulatorPath).standardizedFileURL.path, + paths.adb.standardizedFileURL.path == URL(fileURLWithPath: definition.adbPath).standardizedFileURL.path, + paths.avdHome.standardizedFileURL.path == URL(fileURLWithPath: definition.avdHome, isDirectory: true).standardizedFileURL.path, + paths.avdDirectory.standardizedFileURL.path == URL(fileURLWithPath: definition.avdDirectory, isDirectory: true).standardizedFileURL.path, + paths.avdConfig.standardizedFileURL.path == URL(fileURLWithPath: definition.avdConfigPath).standardizedFileURL.path else { + throw TFTMACRuntimeModeError( + message: "The discovered runtime paths do not match the accepted \(runtimeSelection.mode.rawValue) registry identity." + ) + } + self.paths = paths + guard runtimeSelection.activeLeaseRelativePath == "State/native-runtime.lease" else { + throw TFTMACRuntimeModeError(message: "The accepted runtime lease path changed unexpectedly.") + } + let stateRoot = paths.applicationSupport.appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: leaseIdentity) + telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ + "lease": runtimeSelection.activeLeaseRelativePath, + "pid": ProcessInfo.processInfo.processIdentifier, + "exclusive": true, + "mode": runtimeSelection.mode.rawValue, + "registry_sha256": runtimeSelection.registrySha256, + "configuration_sha256": leaseIdentity.configurationSha256, + "avd": leaseIdentity.avdName, + "adb_server_port": leaseIdentity.adbServerPort, + "console_port": leaseIdentity.consolePort, + "controller_port": leaseIdentity.controllerPort, + "serial": leaseIdentity.serial + ])`; +actor = replaceOnce(actor, oldLeaseBlock, newLeaseBlock, "runtime lease acquisition boundary"); + +controller = replaceOnce( + controller, + " init(\n profile: TFTMACRuntimeProfile,\n mailbox: LatestFrameMailbox,", + " init(\n profile: TFTMACRuntimeProfile,\n runtimeSelection: TFTMACRuntimeSelection,\n mailbox: LatestFrameMailbox,", + "runtime controller initializer signature" +); +controller = replaceOnce( + controller, + " self.service = TFTMACRuntimeService(\n profile: profile,\n mailbox: mailbox,", + " self.service = TFTMACRuntimeService(\n profile: profile,\n runtimeSelection: runtimeSelection,\n mailbox: mailbox,", + "runtime controller service construction" +); +runtime = runtimePrefix + actor + controller; + +let tests = readText("Tests/TFTMACTests/TFTMACGate1Tests.swift"); +assert(!tests.includes("testRuntimeModeRegistryDefinesExactlyThreeModesAndDefaultsControl"), "Wave B tests already exist; refusing replay"); +const testInsertion = String.raw` + + func testRuntimeModeRegistryDefinesExactlyThreeModesAndDefaultsControl() throws { + let registry = try TFTMACRuntimeModeRegistry(data: try runtimeModeRegistryData()) + XCTAssertEqual(registry.defaultMode, .control) + XCTAssertEqual(registry.registeredModes, Set(TFTMACRuntimeMode.allCases)) + let selection = try registry.selection(environment: [:]) + XCTAssertEqual(selection.mode, .control) + XCTAssertEqual(selection.definition.adbServerPort, 5038) + XCTAssertEqual(selection.definition.consolePort, 5582) + XCTAssertEqual(selection.definition.controllerPort, 8554) + XCTAssertEqual(selection.definition.serial, "emulator-5582") + XCTAssertEqual(selection.definition.rollbackTarget, .control) + } + + func testRuntimeModeRegistryRejectsUnknownAndBlockedModes() throws { + let registry = try TFTMACRuntimeModeRegistry(data: try runtimeModeRegistryData()) + XCTAssertThrowsError( + try registry.selection(environment: [TFTMACRuntimeModeRegistry.environmentKey: "unknown"]) + ) + XCTAssertThrowsError( + try registry.selection(environment: [TFTMACRuntimeModeRegistry.environmentKey: "advanced_diagnostics"]) + ) + XCTAssertThrowsError( + try registry.selection(environment: [TFTMACRuntimeModeRegistry.environmentKey: "candidate"]) + ) + XCTAssertEqual( + try registry.definition(for: .advancedDiagnostics).launchState, + .blockedPendingControllerLease + ) + XCTAssertNil(try registry.definition(for: .advancedDiagnostics).controllerPort) + XCTAssertEqual(try registry.definition(for: .candidate).launchState, .blockedNotBuilt) + XCTAssertNil(try registry.definition(for: .candidate).controllerPort) + } + + func testRuntimeModeRegistryRejectsConfigurationTampering() throws { + let data = try runtimeModeRegistryData() + var object = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any]) + var modes = try XCTUnwrap(object["modes"] as? [String: Any]) + var control = try XCTUnwrap(modes["control"] as? [String: Any]) + control["configuration_sha256"] = String(repeating: "0", count: 64) + modes["control"] = control + object["modes"] = modes + let tampered = try JSONSerialization.data(withJSONObject: object, options: [.sortedKeys]) + XCTAssertThrowsError(try TFTMACRuntimeModeRegistry(data: tampered)) + } + + func testRuntimeLeasePersistsAcceptedModeIdentity() throws { + let registry = try TFTMACRuntimeModeRegistry(data: try runtimeModeRegistryData()) + let identity = try registry.selection(environment: [:]).leaseIdentity() + let root = FileManager.default.temporaryDirectory + .appendingPathComponent("tftmac-mode-lease-\(UUID().uuidString)", isDirectory: true) + defer { try? FileManager.default.removeItem(at: root) } + + let lease = try TFTMACRuntimeLease.acquire( + stateRoot: root, + identity: identity, + processIdentifier: getpid() + ) + defer { lease.release() } + let payloadData = try Data(contentsOf: lease.url) + let payload = try XCTUnwrap(JSONSerialization.jsonObject(with: payloadData) as? [String: Any]) + XCTAssertEqual((payload["schema"] as? NSNumber)?.intValue, 2) + let savedIdentity = try XCTUnwrap(payload["identity"] as? [String: Any]) + XCTAssertEqual(savedIdentity["mode"] as? String, "control") + XCTAssertEqual(savedIdentity["avd_name"] as? String, "TFT_Ultra_Tablet") + XCTAssertEqual((savedIdentity["adb_server_port"] as? NSNumber)?.intValue, 5038) + XCTAssertEqual((savedIdentity["console_port"] as? NSNumber)?.intValue, 5582) + XCTAssertEqual((savedIdentity["controller_port"] as? NSNumber)?.intValue, 8554) + XCTAssertEqual(savedIdentity["serial"] as? String, "emulator-5582") + XCTAssertEqual(savedIdentity["configuration_sha256"] as? String, identity.configurationSha256) + XCTAssertThrowsError( + try TFTMACRuntimeLease.acquire( + stateRoot: root, + identity: identity, + processIdentifier: getpid() + ) + ) + } + + private func runtimeModeRegistryData() throws -> Data { + let testDirectory = URL(fileURLWithPath: #filePath).deletingLastPathComponent() + let repositoryRoot = testDirectory.deletingLastPathComponent().deletingLastPathComponent() + return try Data(contentsOf: repositoryRoot.appendingPathComponent("ssot/runtime-modes.json")) + } +`; +const testsEnd = tests.lastIndexOf("\n}"); +assert(testsEnd >= 0 && tests.slice(testsEnd).trim() === "}", "test class terminal brace was not found"); +tests = tests.slice(0, testsEnd) + testInsertion + tests.slice(testsEnd); + +let project = readText("TFTMAC.xcodeproj/project.pbxproj"); +const ids = { + appModeBuild: "100000000000000000000038", + testModeBuild: "100000000000000000000039", + modesResourceBuild: "10000000000000000000003A", + authorityResourceBuild: "10000000000000000000003B", + modeFile: "200000000000000000000023", + modesFile: "200000000000000000000024", + authorityFile: "200000000000000000000025" +}; +for (const id of Object.values(ids)) assert(!project.includes(id), `Xcode object ID collision: ${id}`); +const buildDefinitions = `\t\t${ids.appModeBuild} /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.modeFile} /* RuntimeMode.swift */; };\n\t\t${ids.testModeBuild} /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.modeFile} /* RuntimeMode.swift */; };\n\t\t${ids.modesResourceBuild} /* runtime-modes.json in Resources */ = {isa = PBXBuildFile; fileRef = ${ids.modesFile} /* runtime-modes.json */; };\n\t\t${ids.authorityResourceBuild} /* runtime-authority.json in Resources */ = {isa = PBXBuildFile; fileRef = ${ids.authorityFile} /* runtime-authority.json */; };\n`; +project = insertBefore(project, "/* End PBXBuildFile section */", buildDefinitions, "Xcode build-file section"); +const fileDefinitions = `\t\t${ids.modeFile} /* RuntimeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeMode.swift; sourceTree = ""; };\n\t\t${ids.modesFile} /* runtime-modes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ssot/runtime-modes.json"; sourceTree = SOURCE_ROOT; };\n\t\t${ids.authorityFile} /* runtime-authority.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ssot/runtime-authority.json"; sourceTree = SOURCE_ROOT; };\n`; +project = insertBefore(project, "/* End PBXFileReference section */", fileDefinitions, "Xcode file-reference section"); + +function appendToGroup(text, groupComment, groupPath, addition, label) { + const pattern = new RegExp(`(\\t\\t[0-9A-F]{24} /\\* ${groupComment} \\*/ = \\{isa = PBXGroup; children = \\()([^)]*)(\\); path = ${groupPath}; sourceTree = ""; \\};)`); + const match = text.match(pattern); + assert(match, `${label}: group was not found`); + assert(!match[2].includes(addition.split(" ")[0]), `${label}: object already present`); + return text.replace(pattern, `${match[1]}${match[2]}${addition}${match[3]}`); +} +project = appendToGroup(project, "Runtime", "Runtime", `${ids.modeFile} /* RuntimeMode.swift */, `, "Xcode Runtime group"); +project = appendToGroup( + project, + "TFTMAC", + "TFTMAC", + `${ids.modesFile} /* runtime-modes.json */, ${ids.authorityFile} /* runtime-authority.json */, `, + "Xcode TFTMAC group" +); + +function appendBuildToSourcePhase(text, phaseId, buildId, label) { + const pattern = new RegExp(`(\\t\\t${phaseId} /\\* Sources \\*/ = \\{isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = \\()([^)]*)(\\); runOnlyForDeploymentPostprocessing = 0; \\};)`); + const match = text.match(pattern); + assert(match, `${label}: source phase was not found`); + return text.replace(pattern, `${match[1]}${match[2]}${buildId}, ${match[3]}`); +} +project = appendBuildToSourcePhase(project, "700000000000000000000001", ids.appModeBuild, "TFTMAC app source phase"); +project = appendBuildToSourcePhase(project, "700000000000000000000003", ids.testModeBuild, "TFTMAC test source phase"); +project = replaceOnce( + project, + "\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };", + `\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (${ids.modesResourceBuild}, ${ids.authorityResourceBuild},); runOnlyForDeploymentPostprocessing = 0; };`, + "TFTMAC resource phase" +); + +let verifier = readText("scripts/verify-tftmac.command"); +verifier = replaceOnce( + verifier, + ' "$ROOT/ssot/runtime-authority.json" \\\n', + ' "$ROOT/ssot/runtime-authority.json" \\\n "$ROOT/ssot/runtime-modes.json" \\\n "$ROOT/tftmac/Runtime/RuntimeMode.swift" \\\n', + "verifier required Wave B files" +); +const authorityHashAnchor = '[[ "$(sha256_file "$ROOT/ssot/runtime-authority.json")" == "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" ]]\n'; +const registryVerifier = String.raw` +ROOT="$ROOT" node <<'NODE' +const fs = require('node:fs'); +const path = require('node:path'); +const crypto = require('node:crypto'); +const root = process.env.ROOT; +const modesPath = path.join(root, 'ssot/runtime-modes.json'); +const authorityPath = path.join(root, 'ssot/runtime-authority.json'); +const registry = JSON.parse(fs.readFileSync(modesPath, 'utf8')); +function fail(message) { throw new Error(message); } +function assert(value, message) { if (!value) fail(message); } +function sha(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], ['launch_state', mode.launch_state], ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], ['library_root', mode.library_root], ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 || ''], ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 || ''], ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], ['avd_name', mode.avd_name], ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], ['avd_config_sha256', mode.avd_config_sha256 || ''], + ['avd_ini_path', mode.avd_ini_path], ['avd_ini_sha256', mode.avd_ini_sha256 || ''], + ['adb_server_port', mode.adb_server_port], ['console_port', mode.console_port], + ['controller_port', mode.controller_port === null ? '' : mode.controller_port], ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 || ''], ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha(Buffer.from(fields.map(([key, value]) => key + '=' + value).join('\n'))); +} +assert(registry.schema === 1 && registry.default_mode === 'control', 'runtime registry schema/default failed'); +assert(registry.active_lease_relative_path === 'State/native-runtime.lease', 'runtime lease path failed'); +assert(JSON.stringify(Object.keys(registry.modes).sort()) === JSON.stringify(['advanced_diagnostics', 'candidate', 'control']), 'exact runtime modes failed'); +const used = new Map(); +for (const [name, mode] of Object.entries(registry.modes)) { + assert(name === mode.mode, 'mode key mismatch: ' + name); + assert(configurationHash(mode) === mode.configuration_sha256, 'configuration SHA mismatch: ' + name); + assert(mode.serial === 'emulator-' + mode.console_port, 'serial mismatch: ' + name); + for (const [kind, value] of [['adb', mode.adb_server_port], ['console', mode.console_port], ['controller', mode.controller_port]]) { + if (value === null) continue; + assert(!used.has(value), 'runtime port collision at ' + value); + used.set(value, name + '.' + kind); + } +} +const control = registry.modes.control; +assert(control.launch_state === 'enabled', 'control is not enabled'); +assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, 'control ports drifted'); +assert(control.serial === 'emulator-5582' && control.rollback_target === 'control' && control.requires_control_stopped === false, 'control identity drifted'); +assert(/^[0-9a-f]{64}$/.test(control.emulator_sha256) && /^[0-9a-f]{64}$/.test(control.gfxstream_backend_sha256), 'control binary identities are missing'); +assert(control.authority_manifest.sha256 === sha(fs.readFileSync(authorityPath)), 'control authority manifest hash failed'); +const diagnostics = registry.modes.advanced_diagnostics; +assert(diagnostics.launch_state === 'blocked_pending_controller_lease' && diagnostics.controller_port === null, 'diagnostics are not fail-closed'); +assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.serial === 'emulator-5586', 'diagnostic lease identity drifted'); +const candidate = registry.modes.candidate; +assert(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate is not fail-closed'); +NODE +rg -q 'TFTMACRuntimeModeRegistry\.loadBundled' "$ROOT/tftmac/App/AppCoordinator.swift" +rg -q 'runtimeSelection\.validateForLaunch\(\)' "$ROOT/tftmac/Runtime/TFTMACRuntime.swift" +rg -q 'TFTMACRuntimeLease\.acquire\(stateRoot: stateRoot, identity: leaseIdentity\)' "$ROOT/tftmac/Runtime/TFTMACRuntime.swift" +`; +verifier = replaceOnce( + verifier, + authorityHashAnchor, + authorityHashAnchor + registryVerifier, + "verifier runtime-mode authority block" +); +const appBinaryAnchor = 'test -x "$RELEASE_DERIVED/Build/Products/Release/TFTMAC.app/Contents/MacOS/TFTMAC"\n'; +const appResourceVerifier = String.raw`readonly APP_RESOURCES="$RELEASE_DERIVED/Build/Products/Release/TFTMAC.app/Contents/Resources" +test -f "$APP_RESOURCES/runtime-modes.json" +test -f "$APP_RESOURCES/runtime-authority.json" +cmp -s "$ROOT/ssot/runtime-modes.json" "$APP_RESOURCES/runtime-modes.json" +cmp -s "$ROOT/ssot/runtime-authority.json" "$APP_RESOURCES/runtime-authority.json" +`; +verifier = replaceOnce( + verifier, + appBinaryAnchor, + appBinaryAnchor + appResourceVerifier, + "verifier packaged runtime authority resources" +); +verifier = replaceOnce(verifier, "EXPECTED_TEST_COUNT=43", "EXPECTED_TEST_COUNT=47", "verifier test-count contract"); +verifier = replaceOnce( + verifier, + "Validated TFTMAC native source ownership, runtime authority, SQL migrations, capture integrity, release build, 43 deterministic unit tests, packaged app resources, and the repo-local source verifier.", + "Validated TFTMAC native source ownership, runtime-mode authority, fail-closed lease identity, SQL migrations, capture integrity, release build, 47 deterministic unit tests, packaged app resources, and the repo-local source verifier.", + "verifier completion message" +); + +const outputs = new Map([ + ["ssot/runtime-modes.json", registryOutput], + ["tftmac/Runtime/RuntimeMode.swift", runtimeModeOutput], + ["tftmac/Runtime/RuntimeLease.swift", runtimeLeaseOutput], + ["tftmac/App/AppCoordinator.swift", appCoordinatorOutput], + ["tftmac/Runtime/TFTMACRuntime.swift", runtime], + ["Tests/TFTMACTests/TFTMACGate1Tests.swift", tests], + ["TFTMAC.xcodeproj/project.pbxproj", project], + ["scripts/verify-tftmac.command", verifier] +]); + +const staged = []; +for (const [relativePath, content] of outputs) { + const target = absolute(relativePath); + const temporary = `${target}.waveb-${process.pid}.tmp`; + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(temporary, content, "utf8"); + const mode = fs.existsSync(target) ? fs.statSync(target).mode & 0o777 : 0o644; + fs.chmodSync(temporary, mode); + staged.push({ relativePath, target, temporary, mode, sha256: sha256Text(content) }); +} +for (const item of staged) fs.renameSync(item.temporary, item.target); + +const receipt = { + schema: 1, + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + operation_id: operationId, + scope_lock_sha256: expectedInputs[`${planRoot}/SCOPE_LOCK.txt`], + input_sha256: expectedInputs, + control_identity: { + emulator_path: control.emulator_path, + emulator_sha256: control.emulator_sha256, + gfxstream_backend_path: control.gfxstream_backend_path, + gfxstream_backend_sha256: control.gfxstream_backend_sha256, + configuration_sha256: control.configuration_sha256 + }, + output_sha256: Object.fromEntries(staged.map((item) => [item.relativePath, item.sha256])), + effects: { + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + package_launch_attempted: false, + source_only: true + }, + next_required_action: "Run the exact managed production validator; do not boot diagnostics unless Wave B acceptance passes and a separate controller-port receipt is approved.", + applied_at: new Date().toISOString() +}; +fs.writeFileSync( + absolute(`${planRoot}/WAVE_B_APPLY_RECEIPT.json`), + `${JSON.stringify(receipt, null, 2)}\n`, + { mode: 0o644 } +); +for (const relativePath of templatePaths) fs.unlinkSync(absolute(relativePath)); +console.log(JSON.stringify({ + state: "WAVE_B_SOURCE_APPLIED", + operation_id: operationId, + changed_paths: Array.from(outputs.keys()), + receipt: `${planRoot}/WAVE_B_APPLY_RECEIPT.json`, + emulator_launch_attempted: false +}, null, 2)); diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/preserve-unaccepted-waveb-partial.mjs b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/preserve-unaccepted-waveb-partial.mjs new file mode 100644 index 0000000..e99c5ac --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/preserve-unaccepted-waveb-partial.mjs @@ -0,0 +1,176 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = process.cwd(); +const planRoot = ".clara/plans/tftmac-causal-graphics-v1"; +const destinationRelative = `${planRoot}/protected-local-work/unaccepted-waveb-partial-20260901T215825Z`; +const destination = path.join(root, destinationRelative); +const selfRelative = `${planRoot}/preserve-unaccepted-waveb-partial.mjs`; +const expectedHead = "d96a1caf68b807bbae1a03246666da7eea4df620"; +const expectedScopeLock = "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e"; +const expectedAcceptedRegistry = "81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2"; +const rejected = { + "ssot/runtime-modes.json": "457ca5865f1bfcfaca16bd1eee1f32db15f90bd9c8764706ba64db56b7a9e518", + [`${planRoot}/RuntimeMode.swift.template`]: "f0d2ef201d570c0ca89ed238bbcbff3a5cd729eab51d7e13750af8f3f79172a5", + [`${planRoot}/RuntimeLease.swift.template`]: "de774fd9bd59020093ec35736374f0dfc6013831132ba42c386c6188a4bbe72e", + [`${planRoot}/AppCoordinator.swift.template`]: "67ee87bdd7f088a05d7a3a7efc6d0bc320ea2270f52757e3f37fc8093e83fc68", + [`${planRoot}/apply-waveb-source.mjs`]: "ae2142505ffde36ec847772ecee01856f8f41db9ccfa07e70939ca63ecfe3d9a", + [`${planRoot}/validate-waveb.mjs`]: "5c5b36e4f695db37d9c0263eddbd7d988d56531648831952f445a5d1fb4b4213" +}; + +function absolute(relativePath) { + return path.join(root, relativePath); +} + +function sha256(buffer) { + return crypto.createHash("sha256").update(buffer).digest("hex"); +} + +function fileHash(relativePath) { + return sha256(fs.readFileSync(absolute(relativePath))); +} + +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +function git(args, options = {}) { + const result = spawnSync("git", args, { + cwd: root, + encoding: options.encoding ?? "utf8", + maxBuffer: 16 * 1024 * 1024 + }); + if (result.error || result.status !== 0) { + throw new Error(`git ${args.join(" ")} failed: ${result.error?.message ?? result.stderr}`); + } + return result.stdout; +} + +function copyPreserved(relativePath, preservedName = relativePath) { + const source = absolute(relativePath); + const target = path.join(destination, preservedName); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.copyFileSync(source, target, fs.constants.COPYFILE_EXCL); + const sourceStat = fs.statSync(source); + fs.chmodSync(target, sourceStat.mode & 0o777); + const sourceHash = sha256(fs.readFileSync(source)); + const targetHash = sha256(fs.readFileSync(target)); + assert(sourceHash === targetHash, `preservation hash mismatch for ${relativePath}`); + return { + source_path: relativePath, + preserved_path: path.relative(root, target), + sha256: targetHash, + bytes: sourceStat.size, + mode: (sourceStat.mode & 0o777).toString(8), + modified_at: sourceStat.mtime.toISOString() + }; +} + +assert(git(["rev-parse", "HEAD"]).trim() === expectedHead, "managed-change HEAD drifted"); +assert(fileHash(`${planRoot}/SCOPE_LOCK.txt`) === expectedScopeLock, "active scope-lock SHA drifted"); +for (const [relativePath, expectedHash] of Object.entries(rejected)) { + assert(fs.existsSync(absolute(relativePath)), `rejected partial file is missing: ${relativePath}`); + const observed = fileHash(relativePath); + assert(observed === expectedHash, `rejected partial drift for ${relativePath}: expected ${expectedHash}, observed ${observed}`); +} +for (const forbidden of [ + `${planRoot}/WAVE_B_APPLY_RECEIPT.json`, + `${planRoot}/WAVE_B_VALIDATION_RECEIPT.json`, + `${planRoot}/WAVE_B_VALIDATION_FAILURE.json`, + "tftmac/Runtime/RuntimeMode.swift" +]) { + assert(!fs.existsSync(absolute(forbidden)), `unexpected acceptance/product artifact exists: ${forbidden}`); +} +assert(!fs.existsSync(destination), `forensic destination already exists: ${destinationRelative}`); + +const statusBefore = git(["status", "--porcelain=v1", "--untracked-files=all"]) + .split("\n") + .filter(Boolean); +const expectedStatus = new Set([ + " M ssot/runtime-modes.json", + ...Object.keys(rejected) + .filter((relativePath) => relativePath !== "ssot/runtime-modes.json") + .map((relativePath) => `?? ${relativePath}`), + `?? ${selfRelative}` +]); +assert(statusBefore.length === expectedStatus.size, `unexpected dirty-path count before preservation: ${statusBefore.join(" | ")}`); +for (const line of statusBefore) { + assert(expectedStatus.has(line), `unexpected dirty path before preservation: ${line}`); +} + +fs.mkdirSync(destination, { recursive: false, mode: 0o700 }); +const files = []; +for (const relativePath of Object.keys(rejected)) { + files.push(copyPreserved(relativePath)); +} +files.push(copyPreserved(selfRelative)); + +const acceptedRegistryBytes = git(["show", `HEAD:ssot/runtime-modes.json`], { encoding: "buffer" }); +assert(Buffer.isBuffer(acceptedRegistryBytes), "accepted registry was not returned as bytes"); +assert(sha256(acceptedRegistryBytes) === expectedAcceptedRegistry, "accepted registry blob SHA drifted"); +const acceptedRegistryPath = path.join(destination, "accepted-head-runtime-modes.json"); +fs.writeFileSync(acceptedRegistryPath, acceptedRegistryBytes, { flag: "wx", mode: 0o644 }); + +const beforeStatusPath = path.join(destination, "git-status-before.txt"); +fs.writeFileSync(beforeStatusPath, `${statusBefore.join("\n")}\n`, { flag: "wx", mode: 0o644 }); +const headPath = path.join(destination, "accepted-head.txt"); +fs.writeFileSync(headPath, `${expectedHead}\n`, { flag: "wx", mode: 0o644 }); + +const registryTemporary = `${absolute("ssot/runtime-modes.json")}.accepted-${process.pid}.tmp`; +fs.writeFileSync(registryTemporary, acceptedRegistryBytes, { flag: "wx", mode: 0o644 }); +fs.renameSync(registryTemporary, absolute("ssot/runtime-modes.json")); +assert(fileHash("ssot/runtime-modes.json") === expectedAcceptedRegistry, "accepted registry restoration failed"); + +for (const relativePath of Object.keys(rejected)) { + if (relativePath === "ssot/runtime-modes.json") continue; + fs.unlinkSync(absolute(relativePath)); +} + +const adjudication = { + schema: 1, + state: "UNACCEPTED_PARTIAL_PRESERVED", + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + accepted_head_sha: expectedHead, + active_scope_lock_sha256: expectedScopeLock, + accepted_registry_sha256: expectedAcceptedRegistry, + rejected_registry_sha256: rejected["ssot/runtime-modes.json"], + reason: [ + "The rejected registry enabled advanced_diagnostics and allocated controller port 8556 without the controller-port receipt required by PREFLIGHT.json and AUTHORITY.json.", + "No WAVE_B_APPLY_RECEIPT.json, WAVE_B_VALIDATION_RECEIPT.json, or newer Clara handoff/scratchpad authority existed.", + "No product source file, test, Xcode project file, verifier, emulator, installed app, control runtime, or diagnostic runtime was accepted as changed by this partial attempt." + ], + preserved_files: files, + accepted_registry_restored: true, + effects: { + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + installed_app_replacement_attempted: false, + product_source_mutation_attempted: false + }, + next_required_action: "Resume Wave B from the accepted fail-closed registry and implement source wiring under a new guarded operation identity.", + adjudicated_at: new Date().toISOString() +}; +const adjudicationPath = path.join(destination, "ADJUDICATION.json"); +fs.writeFileSync(adjudicationPath, `${JSON.stringify(adjudication, null, 2)}\n`, { flag: "wx", mode: 0o644 }); + +fs.unlinkSync(absolute(selfRelative)); +const statusAfter = git(["status", "--porcelain=v1", "--untracked-files=all"]) + .split("\n") + .filter(Boolean); +assert(statusAfter.length > 0, "forensic preservation directory was not retained"); +assert(!statusAfter.includes(" M ssot/runtime-modes.json"), "registry remains modified after restoration"); +assert(statusAfter.every((line) => line.startsWith(`?? ${destinationRelative}/`)), `unexpected post-adjudication state: ${statusAfter.join(" | ")}`); + +console.log(JSON.stringify({ + state: adjudication.state, + accepted_head_sha: expectedHead, + accepted_registry_sha256: expectedAcceptedRegistry, + forensic_directory: destinationRelative, + preserved_file_count: files.length, + status_after: statusAfter, + effects: adjudication.effects +}, null, 2)); diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/runtime-modes.unaccepted.json b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/runtime-modes.unaccepted.json new file mode 100644 index 0000000..28a0682 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/runtime-modes.unaccepted.json @@ -0,0 +1,204 @@ +{ + "active_lease_relative_path": "State/native-runtime.lease", + "contract": "TFTMAC_RUNTIME_MODES_V1", + "default_mode": "control", + "modes": { + "advanced_diagnostics": { + "adb_path": "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb", + "adb_server_port": 5041, + "adb_sha256": "1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b", + "adb_vendor_keys_policy": "USER_DEFAULT_KEY", + "allowed_purpose": "ISOLATED_SOURCE_INSTRUMENTATION_AND_ELIGIBILITY", + "application_build": "8", + "application_bundle_id": "com.flashls1.tftmac", + "application_version": "2.3.0", + "authority_manifest": { + "kind": "external_sealed_manifest", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json", + "required_state": "DIAGNOSTIC_BUILD_IDENTITY_PASS", + "sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d" + }, + "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd/config.ini", + "avd_config_sha256": "090fe426402562e227a3a1a6bd6eab9f9572cd48fbe3d467c276d419860caf90", + "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd", + "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD", + "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.ini", + "avd_ini_sha256": "30d4ed7ebc20fb3415461fa48f6d91654955e04825de84176bd21a4adad9b98d", + "avd_name": "TFTMAC_Diagnostic_API37_R9", + "blocked_reason": null, + "clone_receipt": { + "kind": "external_sealed_manifest", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json", + "required_state": "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS", + "sha256": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648" + }, + "comparability_class": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", + "configuration_sha256": "005c85a2a7ffe86e7626c871fd3dd23f42c5d3ce994162d17b032e69cfc4d4f3", + "console_port": 5586, + "controller_port": 8556, + "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator", + "emulator_sha256": "fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa", + "emulator_uuids": [ + "4C4C4436-5555-3144-A1EE-05B0F446F580:arm64" + ], + "expected_emulator_version_contains": "35.6.3", + "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib", + "gfxstream_backend_sha256": "23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d", + "gfxstream_backend_uuids": [ + "4C4C4449-5555-3144-A1FC-F6DFE0021481:arm64" + ], + "host_application_resource": "TFTMAC Emulator Host.app", + "launch_state": "enabled", + "library_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64", + "mode": "advanced_diagnostics", + "native_host_receipt": { + "kind": "external_sealed_manifest", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json", + "required_state": "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS", + "sha256": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067" + }, + "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64", + "qemu_sha256": "042c4932b17fd09ff056ecc2dd21084e08e1110b774c594bbcaf1e4d1ceac608", + "qemu_uuids": [ + "4C4C447F-5555-3144-A16C-0DB6C4482B7A:arm64" + ], + "requires_control_stopped": true, + "rollback_target": "control", + "runtime_profile": { + "asg_data_ring_size": 32768, + "asg_draw_flush_interval": 800, + "asg_write_buffer_size": 1048576, + "asg_write_step_size": 4096, + "audio_backend": "coreaudio", + "density_dpi": 280, + "gpu_mode": "host", + "graphics_transport": "pipe", + "height": 1080, + "ram_mib": 6144, + "refresh_hz": 60, + "vcpu": 6, + "width": 1920 + }, + "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK", + "serial": "emulator-5586" + }, + "candidate": { + "adb_path": null, + "adb_server_port": null, + "adb_sha256": null, + "adb_vendor_keys_policy": null, + "allowed_purpose": "INSTRUMENTATION_DISABLED_STOCK_COMPATIBLE_CANDIDATE", + "application_build": "8", + "application_bundle_id": "com.flashls1.tftmac", + "application_version": "2.3.0", + "authority_manifest": null, + "avd_config_path": null, + "avd_config_sha256": null, + "avd_directory": null, + "avd_home": null, + "avd_ini_path": null, + "avd_ini_sha256": null, + "avd_name": null, + "blocked_reason": "NO_ACCEPTED_STOCK_COMPATIBLE_CANDIDATE", + "clone_receipt": null, + "comparability_class": "CANDIDATE_REQUIRES_ACCEPTED_ROOT_PATCH_AND_AB_RECEIPT", + "configuration_sha256": null, + "console_port": null, + "controller_port": null, + "emulator_path": null, + "emulator_sha256": null, + "emulator_uuids": null, + "expected_emulator_version_contains": null, + "gfxstream_backend_path": null, + "gfxstream_backend_sha256": null, + "gfxstream_backend_uuids": null, + "host_application_resource": null, + "launch_state": "blocked_not_built", + "library_root": null, + "mode": "candidate", + "native_host_receipt": null, + "qemu_path": null, + "qemu_sha256": null, + "qemu_uuids": null, + "requires_control_stopped": true, + "rollback_target": "control", + "runtime_profile": null, + "runtime_root": null, + "sdk_root": null, + "serial": null + }, + "control": { + "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb", + "adb_server_port": 5038, + "adb_sha256": "1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b", + "adb_vendor_keys_policy": "ABSENT", + "allowed_purpose": "PROTECTED_PLAYABLE_CONTROL", + "application_build": "8", + "application_bundle_id": "com.flashls1.tftmac", + "application_version": "2.3.0", + "authority_manifest": { + "kind": "bundled_resource", + "path": "runtime-authority.json", + "required_state": "PASS", + "sha256": "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" + }, + "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.avd/config.ini", + "avd_config_sha256": "15ba85c4f359befc7c8177c1d505a8e030c577e7dd955648ad65885e03b718a4", + "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.avd", + "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", + "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.ini", + "avd_ini_sha256": "ccd235021423598e9ac97fe7c3339895402b2de3bd1005861847ee97ac2c21da", + "avd_name": "TFT_Ultra_Tablet", + "blocked_reason": null, + "clone_receipt": null, + "comparability_class": "STOCK_BUILD8_CONTROL", + "configuration_sha256": "17d6e136ea71e62ffd71a16ab3a61bee60b9405aa6409cc6bb82792ce46b5c6f", + "console_port": 5582, + "controller_port": 8554, + "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator", + "emulator_sha256": "b3b8fc0dcedcf6e15b54b41f3e5156319029aa00b88a59fd489f80abdd8fc133", + "emulator_uuids": [ + "4C4C449E-5555-3144-A182-644CCB895091:arm64" + ], + "expected_emulator_version_contains": "37.1.11", + "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64/libgfxstream_backend.dylib", + "gfxstream_backend_sha256": "3772fef215058831ea419c9281fd203d010003d5defdc195dd120bc7748e4093", + "gfxstream_backend_uuids": [ + "4C4C4406-5555-3144-A122-8AC522465662:arm64" + ], + "host_application_resource": "TFTMAC Emulator Host.app", + "launch_state": "enabled", + "library_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64", + "mode": "control", + "native_host_receipt": null, + "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64", + "qemu_sha256": "eaa97a970b81f81640db73ed79e19ee173323653a0a1203217e1199d078011f3", + "qemu_uuids": [ + "4C4C4467-5555-3144-A10A-A9E5A99446F1:arm64" + ], + "requires_control_stopped": false, + "rollback_target": "control", + "runtime_profile": { + "asg_data_ring_size": 32768, + "asg_draw_flush_interval": 800, + "asg_write_buffer_size": 1048576, + "asg_write_step_size": 16384, + "audio_backend": "coreaudio", + "density_dpi": 320, + "gpu_mode": "host", + "graphics_transport": "virtio-gpu-asg", + "height": 1080, + "ram_mib": 5120, + "refresh_hz": 60, + "vcpu": 6, + "width": 1920 + }, + "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", + "serial": "emulator-5582" + } + }, + "schema": 1, + "selection_environment_variable": "TFTMAC_RUNTIME_MODE" +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/validate-waveb.mjs b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/validate-waveb.mjs new file mode 100644 index 0000000..17871bb --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/validate-waveb.mjs @@ -0,0 +1,149 @@ +import fs from "node:fs"; +import path from "node:path"; +import crypto from "node:crypto"; +import { spawnSync } from "node:child_process"; + +const root = process.cwd(); +const planRoot = ".clara/plans/tftmac-causal-graphics-v1"; +const applyReceiptPath = path.join(root, planRoot, "WAVE_B_APPLY_RECEIPT.json"); +const passReceiptPath = path.join(root, planRoot, "WAVE_B_VALIDATION_RECEIPT.json"); +const failureReceiptPath = path.join(root, planRoot, "WAVE_B_VALIDATION_FAILURE.json"); +const outputDirectory = path.join(root, ".clara/tmp/waveb-validation"); +const operationId = "tftmac-waveb-production-validate-20260901-v1"; + +function sha256File(filePath) { + return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex"); +} + +function countTests() { + const testsRoot = path.join(root, "Tests/TFTMACTests"); + let count = 0; + for (const name of fs.readdirSync(testsRoot)) { + if (!name.endsWith(".swift")) continue; + const content = fs.readFileSync(path.join(testsRoot, name), "utf8"); + count += (content.match(/^ func test/gm) ?? []).length; + } + return count; +} + +function writeJSON(filePath, value) { + fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o644 }); +} + +function fail(message, details = {}) { + const receipt = { + schema: 1, + state: "WAVE_B_VALIDATION_FAILED", + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + operation_id: operationId, + message, + details, + emulator_launch_attempted: false, + failed_at: new Date().toISOString() + }; + writeJSON(failureReceiptPath, receipt); + console.error(JSON.stringify(receipt, null, 2)); + process.exit(1); +} + +try { + if (!fs.existsSync(applyReceiptPath)) fail("Wave B apply receipt is missing; validation remains closed."); + const applyReceipt = JSON.parse(fs.readFileSync(applyReceiptPath, "utf8")); + if (applyReceipt.schema !== 1 || applyReceipt.project_id !== "tftmac") { + fail("Wave B apply receipt identity is invalid."); + } + if (applyReceipt.change_id !== "215ec5a3-6554-4ca3-95db-1525433bb20f") { + fail("Wave B apply receipt is bound to another change."); + } + if (applyReceipt.scope_lock_sha256 !== "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e") { + fail("Wave B apply receipt does not match the active scope lock."); + } + if (applyReceipt.effects?.emulator_launch_attempted !== false || + applyReceipt.effects?.runtime_replacement_attempted !== false || + applyReceipt.effects?.control_stop_attempted !== false) { + fail("Wave B apply receipt reports a forbidden runtime effect."); + } + const mismatches = []; + for (const [relativePath, expected] of Object.entries(applyReceipt.output_sha256 ?? {})) { + const filePath = path.join(root, relativePath); + const observed = fs.existsSync(filePath) ? sha256File(filePath) : null; + if (observed !== expected) mismatches.push({ relativePath, expected, observed }); + } + if (mismatches.length > 0) fail("Wave B applied source drifted before validation.", { mismatches }); + + const requiredMarkers = [ + ["tftmac/App/AppCoordinator.swift", "TFTMACRuntimeModeRegistry.loadBundled"], + ["tftmac/Runtime/TFTMACRuntime.swift", "runtimeSelection.validateForLaunch()"], + ["tftmac/Runtime/TFTMACRuntime.swift", "TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: leaseIdentity)"], + ["tftmac/Runtime/RuntimeLease.swift", "let identity: TFTMACRuntimeLeaseIdentity?"], + ["Tests/TFTMACTests/TFTMACGate1Tests.swift", "testRuntimeModeRegistryDefinesExactlyThreeModesAndDefaultsControl"] + ]; + for (const [relativePath, marker] of requiredMarkers) { + const content = fs.readFileSync(path.join(root, relativePath), "utf8"); + if (!content.includes(marker)) fail(`Required Wave B marker is missing from ${relativePath}.`, { marker }); + } + const testCount = countTests(); + if (testCount !== 47) fail("Wave B deterministic test-count contract failed.", { expected: 47, observed: testCount }); + + fs.mkdirSync(outputDirectory, { recursive: true }); + const result = spawnSync("/bin/zsh", ["scripts/verify-tftmac.command"], { + cwd: root, + env: process.env, + encoding: "utf8", + maxBuffer: 128 * 1024 * 1024 + }); + fs.writeFileSync(path.join(outputDirectory, "stdout.log"), result.stdout ?? "", "utf8"); + fs.writeFileSync(path.join(outputDirectory, "stderr.log"), result.stderr ?? "", "utf8"); + if (result.stdout) process.stdout.write(result.stdout); + if (result.stderr) process.stderr.write(result.stderr); + if (result.error || result.status !== 0) { + fail("Wave B production verifier failed.", { + exit_code: result.status, + signal: result.signal, + spawn_error: result.error?.message ?? null, + stdout_tail: (result.stdout ?? "").slice(-6000), + stderr_tail: (result.stderr ?? "").slice(-6000) + }); + } + + const appRoot = path.join(root, ".build-native-release/Build/Products/Release/TFTMAC.app"); + const appBinary = path.join(appRoot, "Contents/MacOS/TFTMAC"); + const appModes = path.join(appRoot, "Contents/Resources/runtime-modes.json"); + const appAuthority = path.join(appRoot, "Contents/Resources/runtime-authority.json"); + for (const required of [appBinary, appModes, appAuthority]) { + if (!fs.existsSync(required)) fail("Validated package output is missing.", { required }); + } + const receipt = { + schema: 1, + state: "WAVE_B_VALIDATION_PASS", + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + operation_id: operationId, + scope_lock_sha256: applyReceipt.scope_lock_sha256, + apply_operation_id: applyReceipt.operation_id, + verifier_sha256: sha256File(path.join(root, "scripts/verify-tftmac.command")), + deterministic_test_count: testCount, + package: { + app_path: appRoot, + executable_sha256: sha256File(appBinary), + runtime_modes_sha256: sha256File(appModes), + runtime_authority_sha256: sha256File(appAuthority) + }, + source_output_sha256: applyReceipt.output_sha256, + effects: { + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + package_launch_attempted: false, + source_build_test_only: true + }, + next_required_action: "Review and checkpoint Wave B; diagnostic first boot remains separately gated.", + validated_at: new Date().toISOString() + }; + writeJSON(passReceiptPath, receipt); + if (fs.existsSync(failureReceiptPath)) fs.unlinkSync(failureReceiptPath); + console.log(JSON.stringify(receipt, null, 2)); +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template new file mode 100644 index 0000000..b650a3b --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template @@ -0,0 +1,142 @@ +import Darwin +import Foundation + +enum RuntimeLeaseError: LocalizedError, Sendable { + case alreadyOwned(processIdentifier: Int32) + case cannotCreate(String) + + var errorDescription: String? { + switch self { + case .alreadyOwned(let processIdentifier): + return "TFTMAC runtime is already owned by process \(processIdentifier). Close the other TFTMAC session first." + case .cannotCreate(let reason): + return "TFTMAC could not acquire its runtime lease: \(reason)" + } + } +} + +final class TFTMACRuntimeLease: @unchecked Sendable { + private struct Payload: Codable { + let schema: Int + let pid: Int32 + let token: String + let createdUTC: String + let identity: TFTMACRuntimeLeaseIdentity? + + enum CodingKeys: String, CodingKey { + case schema + case pid + case token + case createdUTC = "created_utc" + case identity + } + } + + let processIdentifier: Int32 + let token: String + let url: URL + let identity: TFTMACRuntimeLeaseIdentity? + private var released = false + + private init( + url: URL, + processIdentifier: Int32, + token: String, + identity: TFTMACRuntimeLeaseIdentity? + ) { + self.url = url + self.processIdentifier = processIdentifier + self.token = token + self.identity = identity + } + + static func acquire( + stateRoot: URL, + identity: TFTMACRuntimeLeaseIdentity? = nil, + processIdentifier: Int32 = ProcessInfo.processInfo.processIdentifier + ) throws -> Self { + try FileManager.default.createDirectory( + at: stateRoot, + withIntermediateDirectories: true, + attributes: [.posixPermissions: 0o700] + ) + let url = stateRoot.appendingPathComponent("native-runtime.lease") + let token = UUID().uuidString.lowercased() + for _ in 0..<2 { + let descriptor = Darwin.open(url.path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR) + if descriptor >= 0 { + let payload = Payload( + schema: identity == nil ? 1 : 2, + pid: processIdentifier, + token: token, + createdUTC: ISO8601DateFormatter().string(from: Date()), + identity: identity + ) + do { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + let data = try encoder.encode(payload) + try writeAll(data, to: descriptor) + _ = Darwin.fsync(descriptor) + Darwin.close(descriptor) + return Self( + url: url, + processIdentifier: processIdentifier, + token: token, + identity: identity + ) + } catch { + Darwin.close(descriptor) + try? FileManager.default.removeItem(at: url) + throw RuntimeLeaseError.cannotCreate(error.localizedDescription) + } + } + guard errno == EEXIST else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } + if let owner = leaseOwner(at: url), processExists(owner) { + throw RuntimeLeaseError.alreadyOwned(processIdentifier: owner) + } + do { try FileManager.default.removeItem(at: url) } + catch { throw RuntimeLeaseError.cannotCreate("stale lease could not be removed") } + } + throw RuntimeLeaseError.cannotCreate("another launch won the lease race") + } + + func release() { + guard !released else { return } + released = true + guard let payload = payload(at: url), payload.token == token else { return } + try? FileManager.default.removeItem(at: url) + } + + deinit { release() } + + private static func payload(at url: URL) -> Payload? { + guard let data = try? Data(contentsOf: url) else { return nil } + return try? JSONDecoder().decode(Payload.self, from: data) + } + + private static func leaseOwner(at url: URL) -> Int32? { + payload(at: url)?.pid + } + + private static func processExists(_ processIdentifier: Int32) -> Bool { + if Darwin.kill(processIdentifier, 0) == 0 { return true } + return errno != ESRCH + } + + private static func writeAll(_ data: Data, to descriptor: Int32) throws { + try data.withUnsafeBytes { rawBuffer in + guard let baseAddress = rawBuffer.baseAddress else { return } + var written = 0 + while written < rawBuffer.count { + let result = Darwin.write(descriptor, baseAddress.advanced(by: written), rawBuffer.count - written) + guard result > 0 else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } + written += result + } + } + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template new file mode 100644 index 0000000..9838f21 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template @@ -0,0 +1,556 @@ +import CryptoKit +import Foundation + +enum TFTMACRuntimeMode: String, Codable, CaseIterable, Sendable { + case control + case advancedDiagnostics = "advanced_diagnostics" + case candidate +} + +enum TFTMACRuntimeModeLaunchState: String, Codable, Sendable { + case enabled + case blockedPendingControllerLease = "blocked_pending_controller_lease" + case blockedNotBuilt = "blocked_not_built" +} + +struct TFTMACRuntimeModeError: LocalizedError, Sendable { + let message: String + + var errorDescription: String? { message } +} + +struct TFTMACRuntimeModeManifest: Codable, Equatable, Sendable { + let kind: String + let path: String + let sha256: String? +} + +struct TFTMACRuntimeModeDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let launchState: TFTMACRuntimeModeLaunchState + let runtimeRoot: String + let sdkRoot: String + let libraryRoot: String + let emulatorPath: String + let emulatorSha256: String? + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String? + let adbPath: String + let avdHome: String + let avdName: String + let avdDirectory: String + let avdConfigPath: String + let avdConfigSha256: String? + let avdIniPath: String + let avdIniSha256: String? + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int? + let serial: String + let authorityManifest: TFTMACRuntimeModeManifest + let applicationBundleId: String + let applicationVersion: String + let applicationBuild: String + let allowedPurpose: String + let comparabilityClass: String + let rollbackTarget: TFTMACRuntimeMode + let requiresControlStopped: Bool + let configurationSha256: String + + var computedConfigurationSha256: String { + let fields = [ + "mode=\(mode.rawValue)", + "launch_state=\(launchState.rawValue)", + "runtime_root=\(runtimeRoot)", + "sdk_root=\(sdkRoot)", + "library_root=\(libraryRoot)", + "emulator_path=\(emulatorPath)", + "emulator_sha256=\(emulatorSha256 ?? \"\")", + "gfxstream_backend_path=\(gfxstreamBackendPath)", + "gfxstream_backend_sha256=\(gfxstreamBackendSha256 ?? \"\")", + "adb_path=\(adbPath)", + "avd_home=\(avdHome)", + "avd_name=\(avdName)", + "avd_directory=\(avdDirectory)", + "avd_config_path=\(avdConfigPath)", + "avd_config_sha256=\(avdConfigSha256 ?? \"\")", + "avd_ini_path=\(avdIniPath)", + "avd_ini_sha256=\(avdIniSha256 ?? \"\")", + "adb_server_port=\(adbServerPort)", + "console_port=\(consolePort)", + "controller_port=\(controllerPort.map { String($0) } ?? \"\")", + "serial=\(serial)", + "authority_manifest_kind=\(authorityManifest.kind)", + "authority_manifest_path=\(authorityManifest.path)", + "authority_manifest_sha256=\(authorityManifest.sha256 ?? \"\")", + "application_bundle_id=\(applicationBundleId)", + "application_version=\(applicationVersion)", + "application_build=\(applicationBuild)", + "allowed_purpose=\(allowedPurpose)", + "comparability_class=\(comparabilityClass)", + "rollback_target=\(rollbackTarget.rawValue)", + "requires_control_stopped=\(requiresControlStopped ? \"true\" : \"false\")" + ] + return Self.sha256Hex(Data(fields.joined(separator: "\n").utf8)) + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} + +struct TFTMACRuntimeModeRegistryDocument: Codable, Equatable, Sendable { + let schema: Int + let defaultMode: TFTMACRuntimeMode + let activeLeaseRelativePath: String + let modes: [String: TFTMACRuntimeModeDefinition] +} + +struct TFTMACRuntimeLeaseIdentity: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let registrySha256: String + let configurationSha256: String + let avdName: String + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + + enum CodingKeys: String, CodingKey { + case mode + case registrySha256 = "registry_sha256" + case configurationSha256 = "configuration_sha256" + case avdName = "avd_name" + case adbServerPort = "adb_server_port" + case consolePort = "console_port" + case controllerPort = "controller_port" + case serial + } +} + +struct TFTMACRuntimeSelection: Equatable, Sendable { + let registrySha256: String + let activeLeaseRelativePath: String + let definition: TFTMACRuntimeModeDefinition + + var mode: TFTMACRuntimeMode { definition.mode } + + func leaseIdentity() throws -> TFTMACRuntimeLeaseIdentity { + guard let controllerPort = definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted EmulatorController port receipt." + ) + } + return TFTMACRuntimeLeaseIdentity( + mode: mode, + registrySha256: registrySha256, + configurationSha256: definition.configurationSha256, + avdName: definition.avdName, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial + ) + } + + func validateForLaunch( + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws { + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + _ = try leaseIdentity() + + guard bundle.bundleIdentifier == definition.applicationBundleId else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected the application bundle identity." + ) + } + let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String + let build = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String + guard version == definition.applicationVersion, build == definition.applicationBuild else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected application version/build \(version ?? \"unknown\")/\(build ?? \"unknown\")." + ) + } + + try requireDirectory(definition.runtimeRoot, label: "runtime root", fileManager: fileManager) + try requireDirectory(definition.sdkRoot, label: "SDK root", fileManager: fileManager) + try requireDirectory(definition.libraryRoot, label: "library root", fileManager: fileManager) + try requireDirectory(definition.avdHome, label: "AVD home", fileManager: fileManager) + try requireDirectory(definition.avdDirectory, label: "AVD directory", fileManager: fileManager) + try requireExecutable(definition.emulatorPath, label: "emulator", fileManager: fileManager) + try requireExecutable(definition.adbPath, label: "ADB", fileManager: fileManager) + try requireFile(definition.gfxstreamBackendPath, label: "gfxstream backend", fileManager: fileManager) + try requireFile(definition.avdConfigPath, label: "AVD config", fileManager: fileManager) + try requireFile(definition.avdIniPath, label: "AVD ini", fileManager: fileManager) + + let manifestURL: URL + switch definition.authorityManifest.kind { + case "bundled_resource": + guard let resourceURL = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + manifestURL = resourceURL.appendingPathComponent(definition.authorityManifest.path) + case "external_sealed_manifest": + manifestURL = URL(fileURLWithPath: definition.authorityManifest.path) + default: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has unsupported manifest authority \(definition.authorityManifest.kind)." + ) + } + guard let expectedManifestSha256 = definition.authorityManifest.sha256 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted manifest SHA-256." + ) + } + try validateSHA256(at: manifestURL, expected: expectedManifestSha256, label: "authority manifest") + try validateOptionalSHA256(path: definition.emulatorPath, expected: definition.emulatorSha256, label: "emulator") + try validateOptionalSHA256( + path: definition.gfxstreamBackendPath, + expected: definition.gfxstreamBackendSha256, + label: "gfxstream backend" + ) + try validateOptionalSHA256(path: definition.avdConfigPath, expected: definition.avdConfigSha256, label: "AVD config") + try validateOptionalSHA256(path: definition.avdIniPath, expected: definition.avdIniSha256, label: "AVD ini") + } + + private func requireDirectory(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireFile(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), !isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireExecutable(_ path: String, label: String, fileManager: FileManager) throws { + guard fileManager.isExecutableFile(atPath: path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no executable \(label) at \(path)." + ) + } + } + + private func validateOptionalSHA256(path: String, expected: String?, label: String) throws { + guard let expected else { return } + try validateSHA256(at: URL(fileURLWithPath: path), expected: expected, label: label) + } + + private func validateSHA256(at url: URL, expected: String, label: String) throws { + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not open its \(label) at \(url.path): \(error.localizedDescription)" + ) + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not hash its \(label): \(error.localizedDescription)" + ) + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected \(label) SHA-256 \(observed)." + ) + } + } +} + +struct TFTMACRuntimeModeRegistry: Sendable { + static let environmentKey = "TFTMAC_RUNTIME_MODE" + static let expectedRegistrySha256 = "__EXPECTED_RUNTIME_MODES_SHA256__" + + let document: TFTMACRuntimeModeRegistryDocument + let registrySha256: String + + init(data: Data) throws { + let observedRegistrySha256 = Self.sha256Hex(data) + guard observedRegistrySha256 == Self.expectedRegistrySha256 else { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry SHA-256 \(observedRegistrySha256) is not the accepted packaged identity." + ) + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeRegistryDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = observedRegistrySha256 + try Self.validate(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read runtime-modes.json: \(error.localizedDescription)" + ) + } + } + + var defaultMode: TFTMACRuntimeMode { document.defaultMode } + + var registeredModes: Set { + Set(document.modes.values.map(\.mode)) + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is not registered.") + } + return definition + } + + func selection(environment: [String: String] = ProcessInfo.processInfo.environment) throws -> TFTMACRuntimeSelection { + let requested = environment[Self.environmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines) + let mode: TFTMACRuntimeMode + if let requested, !requested.isEmpty { + guard let parsed = TFTMACRuntimeMode(rawValue: requested) else { + throw TFTMACRuntimeModeError(message: "Unknown TFTMAC runtime mode \(requested).") + } + mode = parsed + } else { + mode = document.defaultMode + } + let definition = try definition(for: mode) + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + return TFTMACRuntimeSelection( + registrySha256: registrySha256, + activeLeaseRelativePath: document.activeLeaseRelativePath, + definition: definition + ) + } + + private static func validate(_ document: TFTMACRuntimeModeRegistryDocument) throws { + guard document.schema == 1 else { + throw TFTMACRuntimeModeError(message: "Unsupported runtime-mode registry schema \(document.schema).") + } + guard document.defaultMode == .control else { + throw TFTMACRuntimeModeError(message: "The default TFTMAC runtime mode must remain control.") + } + guard document.activeLeaseRelativePath == "State/native-runtime.lease" else { + throw TFTMACRuntimeModeError(message: "The runtime-mode registry changed the protected lease path.") + } + + let expectedKeys = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == expectedKeys else { + throw TFTMACRuntimeModeError( + message: "The runtime-mode registry must contain exactly control, advanced_diagnostics, and candidate." + ) + } + + var occupiedPorts: [Int: String] = [:] + for (key, definition) in document.modes { + guard key == definition.mode.rawValue else { + throw TFTMACRuntimeModeError( + message: "Runtime-mode registry key \(key) does not match \(definition.mode.rawValue)." + ) + } + try validate(definition) + for (kind, port) in [ + ("adb", Optional(definition.adbServerPort)), + ("console", Optional(definition.consolePort)), + ("controller", definition.controllerPort) + ] { + guard let port else { continue } + if let existing = occupiedPorts[port] { + throw TFTMACRuntimeModeError( + message: "Runtime lease port \(port) is shared by \(existing) and \(definition.mode.rawValue).\(kind)." + ) + } + occupiedPorts[port] = "\(definition.mode.rawValue).\(kind)" + } + } + + let control = try required(.control, from: document) + guard control.launchState == .enabled, + control.runtimeRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime", + control.sdkRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", + control.avdHome == "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", + control.avdName == "TFT_Ultra_Tablet", + control.adbServerPort == 5038, + control.consolePort == 5582, + control.controllerPort == 8554, + control.serial == "emulator-5582", + control.authorityManifest.kind == "bundled_resource", + control.authorityManifest.path == "runtime-authority.json", + control.authorityManifest.sha256 != nil, + control.emulatorSha256 != nil, + control.gfxstreamBackendSha256 != nil, + control.rollbackTarget == .control, + !control.requiresControlStopped else { + throw TFTMACRuntimeModeError( + message: "The control mode no longer matches the accepted stock Build 8 authority." + ) + } + + let diagnostics = try required(.advancedDiagnostics, from: document) + guard diagnostics.launchState == .blockedPendingControllerLease, + diagnostics.controllerPort == nil, + diagnostics.avdName == "TFTMAC_Diagnostic_API37_R9", + diagnostics.adbServerPort == 5041, + diagnostics.consolePort == 5586, + diagnostics.serial == "emulator-5586", + diagnostics.emulatorSha256 != nil, + diagnostics.gfxstreamBackendSha256 != nil, + diagnostics.avdConfigSha256 != nil, + diagnostics.avdIniSha256 != nil, + diagnostics.requiresControlStopped, + diagnostics.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Advanced diagnostics must remain isolated and blocked pending its controller-port receipt." + ) + } + + let candidate = try required(.candidate, from: document) + guard candidate.launchState == .blockedNotBuilt, + candidate.controllerPort == nil, + candidate.requiresControlStopped, + candidate.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Candidate mode must remain blocked until a separately accepted candidate exists." + ) + } + } + + private static func validate(_ definition: TFTMACRuntimeModeDefinition) throws { + let requiredStrings = [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdName, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath, + definition.serial, + definition.authorityManifest.kind, + definition.authorityManifest.path, + definition.applicationBundleId, + definition.applicationVersion, + definition.applicationBuild, + definition.allowedPurpose, + definition.comparabilityClass + ] + guard requiredStrings.allSatisfy({ !$0.isEmpty }) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) has an empty required field." + ) + } + for path in [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath + ] { + guard path.hasPrefix("/") else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains a non-absolute path." + ) + } + } + guard (1...65535).contains(definition.adbServerPort), + (1...65535).contains(definition.consolePort), + definition.controllerPort.map({ (1...65535).contains($0) }) ?? true else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid lease port." + ) + } + guard definition.serial == "emulator-\(definition.consolePort)" else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) serial does not match its console lease." + ) + } + if definition.launchState == .enabled, definition.controllerPort == nil { + throw TFTMACRuntimeModeError( + message: "Launch-ready mode \(definition.mode.rawValue) has no controller-port receipt." + ) + } + let digests: [String?] = [ + definition.configurationSha256, + definition.emulatorSha256, + definition.gfxstreamBackendSha256, + definition.avdConfigSha256, + definition.avdIniSha256, + definition.authorityManifest.sha256 + ] + for digest in digests.compactMap({ $0 }) { + guard isSHA256(digest) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid SHA-256 value." + ) + } + } + guard definition.computedConfigurationSha256 == definition.configurationSha256.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) configuration SHA-256 does not match its fields." + ) + } + } + + private static func required( + _ mode: TFTMACRuntimeMode, + from document: TFTMACRuntimeModeRegistryDocument + ) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/apply-waveb-v2.mjs b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/apply-waveb-v2.mjs new file mode 100644 index 0000000..978e28f --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/apply-waveb-v2.mjs @@ -0,0 +1,666 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = process.cwd(); +const planRoot = ".clara/plans/tftmac-causal-graphics-v1"; +const waveRoot = `${planRoot}/wave-b-v2`; +const operationId = "tftmac-waveb-v2-source-apply-20260901-v1"; +const expectedHead = "f1ef3f7c067b88e4ce464fc4567fcb03a6accf91"; +const expectedScopeLock = "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e"; +const expectedRegistry = "81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2"; +const expectedInputs = { + "ssot/runtime-modes.json": expectedRegistry, + "ssot/runtime-authority.json": "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f", + "tftmac/App/AppCoordinator.swift": "ef3dcfa1272726471407836911043118343b375a77e65dbcc6a8ac75f9a1937", + "tftmac/Runtime/RuntimeLease.swift": "55a44dbd5fc8b112cb48d17e879c00ae068161f2755af1876244e03bf75b498b", + "tftmac/Runtime/TFTMACRuntime.swift": "8932032d93af01b46e46b5fb5a04eff1ec457f2f0e8f92f364d5a1a703ab5a5f", + "Tests/TFTMACTests/TFTMACGate1Tests.swift": "3a3307d19d2a48c22ee5504c96b4ee9e428992d2b026bedec2946240abc803d6", + "TFTMAC.xcodeproj/project.pbxproj": "4961d37cc1802ca179b7f115ff4be3a4f1c222e706a01aff9f137fcb27c57dfd", + "scripts/verify-tftmac.command": "d587850fef7d5b25bf2a46cf6249824703130761b1ed388e1e93c485be763ccc" +}; +const activePlanFiles = [ + `${waveRoot}/RuntimeMode.swift.template`, + `${waveRoot}/RuntimeLease.swift.template`, + `${waveRoot}/apply-waveb-v2.mjs` +]; + +function absolute(relativePath) { + return path.join(root, relativePath); +} + +function sha256(buffer) { + return crypto.createHash("sha256").update(buffer).digest("hex"); +} + +function fileHash(relativePath) { + return sha256(fs.readFileSync(absolute(relativePath))); +} + +function readText(relativePath) { + return fs.readFileSync(absolute(relativePath), "utf8"); +} + +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +function git(args) { + const result = spawnSync("git", args, { cwd: root, encoding: "utf8", maxBuffer: 16 * 1024 * 1024 }); + if (result.error || result.status !== 0) { + throw new Error(`git ${args.join(" ")} failed: ${result.error?.message ?? result.stderr}`); + } + return result.stdout; +} + +async function externalHash(filePath) { + return await new Promise((resolve, reject) => { + const hash = crypto.createHash("sha256"); + const stream = fs.createReadStream(filePath); + stream.on("data", (chunk) => hash.update(chunk)); + stream.on("error", reject); + stream.on("end", () => resolve(hash.digest("hex"))); + }); +} + +function replaceOnce(text, before, after, label) { + const first = text.indexOf(before); + assert(first >= 0, `${label}: required anchor was not found`); + assert(text.indexOf(before, first + before.length) < 0, `${label}: required anchor was not unique`); + return text.slice(0, first) + after + text.slice(first + before.length); +} + +function insertBefore(text, marker, insertion, label) { + const index = text.indexOf(marker); + assert(index >= 0, `${label}: insertion marker was not found`); + assert(text.indexOf(marker, index + marker.length) < 0, `${label}: insertion marker was not unique`); + return text.slice(0, index) + insertion + text.slice(index); +} + +function configurationHash(mode) { + const fields = [ + ["mode", mode.mode], + ["launch_state", mode.launch_state], + ["runtime_root", mode.runtime_root], + ["sdk_root", mode.sdk_root], + ["library_root", mode.library_root], + ["emulator_path", mode.emulator_path], + ["emulator_sha256", mode.emulator_sha256 ?? ""], + ["gfxstream_backend_path", mode.gfxstream_backend_path], + ["gfxstream_backend_sha256", mode.gfxstream_backend_sha256 ?? ""], + ["adb_path", mode.adb_path], + ["avd_home", mode.avd_home], + ["avd_name", mode.avd_name], + ["avd_directory", mode.avd_directory], + ["avd_config_path", mode.avd_config_path], + ["avd_config_sha256", mode.avd_config_sha256 ?? ""], + ["avd_ini_path", mode.avd_ini_path], + ["avd_ini_sha256", mode.avd_ini_sha256 ?? ""], + ["adb_server_port", mode.adb_server_port], + ["console_port", mode.console_port], + ["controller_port", mode.controller_port ?? ""], + ["serial", mode.serial], + ["authority_manifest_kind", mode.authority_manifest.kind], + ["authority_manifest_path", mode.authority_manifest.path], + ["authority_manifest_sha256", mode.authority_manifest.sha256 ?? ""], + ["application_bundle_id", mode.application_bundle_id], + ["application_version", mode.application_version], + ["application_build", mode.application_build], + ["allowed_purpose", mode.allowed_purpose], + ["comparability_class", mode.comparability_class], + ["rollback_target", mode.rollback_target], + ["requires_control_stopped", String(mode.requires_control_stopped)] + ]; + return sha256(Buffer.from(fields.map(([key, value]) => `${key}=${value}`).join("\n"), "utf8")); +} + +function assertSHA256(value, label) { + assert(typeof value === "string" && /^[0-9a-f]{64}$/.test(value), `${label} is not a lowercase SHA-256`); +} + +function validateRegistry(registry, requireControlBinaryHashes) { + assert(registry.schema === 1, "runtime registry schema must remain 1"); + assert(registry.default_mode === "control", "control must remain the default runtime mode"); + assert(registry.active_lease_relative_path === "State/native-runtime.lease", "shared lease path drifted"); + const names = Object.keys(registry.modes).sort(); + assert(JSON.stringify(names) === JSON.stringify(["advanced_diagnostics", "candidate", "control"]), "runtime registry must define exactly three modes"); + + const occupied = new Map(); + for (const [name, mode] of Object.entries(registry.modes)) { + assert(name === mode.mode, `runtime registry key mismatch for ${name}`); + assert(configurationHash(mode) === mode.configuration_sha256, `configuration SHA mismatch for ${name}`); + assert(mode.serial === `emulator-${mode.console_port}`, `serial/console mismatch for ${name}`); + for (const [kind, value] of [["adb", mode.adb_server_port], ["console", mode.console_port], ["controller", mode.controller_port]]) { + if (value === null) continue; + assert(Number.isInteger(value) && value > 0 && value <= 65535, `invalid ${kind} port for ${name}`); + assert(!occupied.has(value), `port ${value} is shared by ${occupied.get(value)} and ${name}.${kind}`); + occupied.set(value, `${name}.${kind}`); + } + } + + const control = registry.modes.control; + assert(control.launch_state === "enabled", "control must remain the only enabled mode"); + assert(control.runtime_root === "/Volumes/MAC MINI M4/TFTMAC/Runtime", "control root drifted"); + assert(control.sdk_root === "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", "control SDK root drifted"); + assert(control.avd_home === "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", "control AVD home drifted"); + assert(control.avd_name === "TFT_Ultra_Tablet", "control AVD name drifted"); + assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, "control lease ports drifted"); + assert(control.serial === "emulator-5582", "control serial drifted"); + assert(control.authority_manifest.kind === "bundled_resource" && control.authority_manifest.path === "runtime-authority.json", "control authority manifest drifted"); + assert(control.authority_manifest.sha256 === expectedInputs["ssot/runtime-authority.json"], "control authority manifest SHA drifted"); + assert(control.rollback_target === "control" && control.requires_control_stopped === false, "control rollback contract drifted"); + if (requireControlBinaryHashes) { + assertSHA256(control.emulator_sha256, "control emulator SHA-256"); + assertSHA256(control.gfxstream_backend_sha256, "control gfxstream SHA-256"); + } + + const diagnostics = registry.modes.advanced_diagnostics; + assert(diagnostics.launch_state === "blocked_pending_controller_lease", "advanced diagnostics must remain fail-closed"); + assert(diagnostics.controller_port === null, "advanced diagnostics cannot allocate a controller port before its receipt"); + assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586, "diagnostic lease ports drifted"); + assert(diagnostics.serial === "emulator-5586", "diagnostic serial drifted"); + assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === "control", "diagnostic noninterference contract drifted"); + assert(diagnostics.authority_manifest.kind === "external_sealed_manifest", "diagnostic manifest authority drifted"); + for (const [value, label] of [ + [diagnostics.authority_manifest.sha256, "diagnostic manifest SHA-256"], + [diagnostics.emulator_sha256, "diagnostic emulator SHA-256"], + [diagnostics.gfxstream_backend_sha256, "diagnostic gfxstream SHA-256"], + [diagnostics.avd_config_sha256, "diagnostic AVD config SHA-256"], + [diagnostics.avd_ini_sha256, "diagnostic AVD ini SHA-256"] + ]) assertSHA256(value, label); + + const candidate = registry.modes.candidate; + assert(candidate.launch_state === "blocked_not_built", "candidate must remain fail-closed"); + assert(candidate.controller_port === null, "candidate cannot allocate a controller port before acceptance"); + assert(candidate.requires_control_stopped === true && candidate.rollback_target === "control", "candidate rollback contract drifted"); +} + +assert(git(["rev-parse", "HEAD"]).trim() === expectedHead, "managed-change HEAD drifted before Wave B implementation"); +assert(fileHash(`${planRoot}/SCOPE_LOCK.txt`) === expectedScopeLock, "active scope-lock SHA drifted"); +for (const [relativePath, expectedHash] of Object.entries(expectedInputs)) { + assert(fs.existsSync(absolute(relativePath)), `required Wave B input is missing: ${relativePath}`); + const observed = fileHash(relativePath); + assert(observed === expectedHash, `Wave B input drift for ${relativePath}: expected ${expectedHash}, observed ${observed}`); +} +for (const relativePath of activePlanFiles) { + assert(fs.existsSync(absolute(relativePath)), `active Wave B plan input is missing: ${relativePath}`); +} +for (const forbidden of [ + "tftmac/Runtime/RuntimeMode.swift", + `${waveRoot}/WAVE_B_IMPLEMENTATION_RECEIPT.json`, + `${waveRoot}/WAVE_B_VALIDATION_RECEIPT.json`, + `${waveRoot}/WAVE_B_VALIDATION_FAILURE.json` +]) assert(!fs.existsSync(absolute(forbidden)), `unexpected preexisting Wave B artifact: ${forbidden}`); + +const statusBefore = git(["status", "--porcelain=v1", "--untracked-files=all"]) + .split("\n") + .filter(Boolean); +const expectedStatus = new Set(activePlanFiles.map((relativePath) => `?? ${relativePath}`)); +assert(statusBefore.length === expectedStatus.size, `unexpected dirty-path count before Wave B implementation: ${statusBefore.join(" | ")}`); +for (const line of statusBefore) assert(expectedStatus.has(line), `unexpected dirty path before Wave B implementation: ${line}`); + +const registry = JSON.parse(readText("ssot/runtime-modes.json")); +validateRegistry(registry, false); +const control = registry.modes.control; +const diagnostics = registry.modes.advanced_diagnostics; + +const controlEmulatorSha256 = await externalHash(control.emulator_path); +const controlGfxstreamSha256 = await externalHash(control.gfxstream_backend_path); +assert(await externalHash(control.authority_manifest.path === "runtime-authority.json" ? absolute("ssot/runtime-authority.json") : control.authority_manifest.path) === control.authority_manifest.sha256, "control authority manifest file does not match the accepted SHA-256"); +for (const [filePath, expectedHash, label] of [ + [diagnostics.authority_manifest.path, diagnostics.authority_manifest.sha256, "diagnostic manifest"], + [diagnostics.emulator_path, diagnostics.emulator_sha256, "diagnostic emulator"], + [diagnostics.gfxstream_backend_path, diagnostics.gfxstream_backend_sha256, "diagnostic gfxstream backend"], + [diagnostics.avd_config_path, diagnostics.avd_config_sha256, "diagnostic AVD config"], + [diagnostics.avd_ini_path, diagnostics.avd_ini_sha256, "diagnostic AVD ini"] +]) { + assert(fs.existsSync(filePath), `${label} is missing at ${filePath}`); + const observed = await externalHash(filePath); + assert(observed === expectedHash, `${label} SHA-256 mismatch: expected ${expectedHash}, observed ${observed}`); +} + +control.emulator_sha256 = controlEmulatorSha256; +control.gfxstream_backend_sha256 = controlGfxstreamSha256; +control.configuration_sha256 = configurationHash(control); +validateRegistry(registry, true); +const registryOutput = `${JSON.stringify(registry, null, 2)}\n`; +const finalRegistrySha256 = sha256(Buffer.from(registryOutput, "utf8")); + +let runtimeModeOutput = readText(`${waveRoot}/RuntimeMode.swift.template`); +runtimeModeOutput = replaceOnce( + runtimeModeOutput, + "__EXPECTED_RUNTIME_MODES_SHA256__", + finalRegistrySha256, + "RuntimeMode registry signature" +); +assert(!runtimeModeOutput.includes("__EXPECTED_RUNTIME_MODES_SHA256__"), "RuntimeMode registry signature placeholder remains"); +const runtimeLeaseOutput = readText(`${waveRoot}/RuntimeLease.swift.template`); + +let coordinator = readText("tftmac/App/AppCoordinator.swift"); +const coordinatorAnchor = ` let runtime = TFTMACRuntimeController( + profile: activeProfile, + mailbox: controller.frameMailbox,`; +const coordinatorReplacement = ` let runtimeSelection: TFTMACRuntimeSelection + do { + let registry = try TFTMACRuntimeModeRegistry.loadBundled() + runtimeSelection = try registry.selection() + try runtimeSelection.validateForLaunch() + } catch { + controller.showWindow(self) + NSApplication.shared.activate(ignoringOtherApps: true) + controller.setStatus( + "Runtime mode validation failed: \\(error.localizedDescription)", + isError: true + ) + return + } + + let runtime = TFTMACRuntimeController( + profile: activeProfile, + runtimeSelection: runtimeSelection, + mailbox: controller.frameMailbox,`; +coordinator = replaceOnce(coordinator, coordinatorAnchor, coordinatorReplacement, "AppCoordinator runtime selection boundary"); + +let runtime = readText("tftmac/Runtime/TFTMACRuntime.swift"); +const actorStart = runtime.indexOf("actor TFTMACRuntimeService {"); +const controllerStart = runtime.lastIndexOf("final class TFTMACRuntimeController"); +assert(actorStart >= 0 && controllerStart > actorStart, "runtime service/controller boundaries were not found"); +const runtimePrefix = runtime.slice(0, actorStart); +let actor = runtime.slice(actorStart, controllerStart); +let controller = runtime.slice(controllerStart); + +actor = replaceOnce( + actor, + " private let profile: TFTMACRuntimeProfile\n", + " private let profile: TFTMACRuntimeProfile\n private let runtimeSelection: TFTMACRuntimeSelection\n", + "runtime service selection field" +); +actor = replaceOnce( + actor, + " init(\n profile: TFTMACRuntimeProfile,\n mailbox: LatestFrameMailbox,", + " init(\n profile: TFTMACRuntimeProfile,\n runtimeSelection: TFTMACRuntimeSelection,\n mailbox: LatestFrameMailbox,", + "runtime service initializer signature" +); +actor = replaceOnce( + actor, + " self.profile = profile\n self.mailbox = mailbox", + " self.profile = profile\n self.runtimeSelection = runtimeSelection\n self.mailbox = mailbox", + "runtime service initializer assignment" +); + +const oldLeaseBlock = String.raw` let paths = try TFTMACRuntimePaths.discover() + self.paths = paths + let stateRoot = paths.applicationSupport.appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot) + telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ + "lease": "State/native-runtime.lease", + "pid": ProcessInfo.processInfo.processIdentifier, + "exclusive": true + ])`; +const newLeaseBlock = String.raw` try runtimeSelection.validateForLaunch() + guard runtimeSelection.mode == .control else { + throw TFTMACRuntimeModeError( + message: "Only the accepted control runtime is launch-ready in Wave B." + ) + } + let leaseIdentity = try runtimeSelection.leaseIdentity() + guard profile.controllerPort == leaseIdentity.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime profile controller port \(profile.controllerPort) does not match the accepted \(runtimeSelection.mode.rawValue) lease port \(leaseIdentity.controllerPort)." + ) + } + let definition = runtimeSelection.definition + let paths = try TFTMACRuntimePaths.discover() + guard paths.sdkRoot.standardizedFileURL.path == URL(fileURLWithPath: definition.sdkRoot, isDirectory: true).standardizedFileURL.path, + paths.emulator.standardizedFileURL.path == URL(fileURLWithPath: definition.emulatorPath).standardizedFileURL.path, + paths.adb.standardizedFileURL.path == URL(fileURLWithPath: definition.adbPath).standardizedFileURL.path, + paths.avdHome.standardizedFileURL.path == URL(fileURLWithPath: definition.avdHome, isDirectory: true).standardizedFileURL.path, + paths.avdDirectory.standardizedFileURL.path == URL(fileURLWithPath: definition.avdDirectory, isDirectory: true).standardizedFileURL.path, + paths.avdConfig.standardizedFileURL.path == URL(fileURLWithPath: definition.avdConfigPath).standardizedFileURL.path else { + throw TFTMACRuntimeModeError( + message: "The discovered runtime paths do not match the accepted \(runtimeSelection.mode.rawValue) registry identity." + ) + } + self.paths = paths + guard runtimeSelection.activeLeaseRelativePath == "State/native-runtime.lease" else { + throw TFTMACRuntimeModeError(message: "The accepted runtime lease path changed unexpectedly.") + } + let stateRoot = paths.applicationSupport.appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: leaseIdentity) + telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ + "lease": runtimeSelection.activeLeaseRelativePath, + "pid": ProcessInfo.processInfo.processIdentifier, + "exclusive": true, + "mode": runtimeSelection.mode.rawValue, + "registry_sha256": runtimeSelection.registrySha256, + "configuration_sha256": leaseIdentity.configurationSha256, + "avd": leaseIdentity.avdName, + "adb_server_port": leaseIdentity.adbServerPort, + "console_port": leaseIdentity.consolePort, + "controller_port": leaseIdentity.controllerPort, + "serial": leaseIdentity.serial + ])`; +actor = replaceOnce(actor, oldLeaseBlock, newLeaseBlock, "runtime lease acquisition boundary"); + +controller = replaceOnce( + controller, + " init(\n profile: TFTMACRuntimeProfile,\n mailbox: LatestFrameMailbox,", + " init(\n profile: TFTMACRuntimeProfile,\n runtimeSelection: TFTMACRuntimeSelection,\n mailbox: LatestFrameMailbox,", + "runtime controller initializer signature" +); +controller = replaceOnce( + controller, + " self.service = TFTMACRuntimeService(\n profile: profile,\n mailbox: mailbox,", + " self.service = TFTMACRuntimeService(\n profile: profile,\n runtimeSelection: runtimeSelection,\n mailbox: mailbox,", + "runtime controller service construction" +); +runtime = runtimePrefix + actor + controller; + +let tests = readText("Tests/TFTMACTests/TFTMACGate1Tests.swift"); +const baselineTestCount = (tests.match(/^ func test/gm) ?? []).length; +assert(baselineTestCount === 43, `expected 43 baseline tests, observed ${baselineTestCount}`); +assert(!tests.includes("testRuntimeModeRegistryDefinesExactlyThreeModesAndDefaultsControl"), "Wave B tests already exist"); +const testInsertion = String.raw` + + func testRuntimeModeRegistryDefinesExactlyThreeModesAndDefaultsControl() throws { + let registry = try TFTMACRuntimeModeRegistry(data: try runtimeModeRegistryData()) + XCTAssertEqual(registry.defaultMode, .control) + XCTAssertEqual(registry.registeredModes, Set(TFTMACRuntimeMode.allCases)) + let selection = try registry.selection(environment: [:]) + XCTAssertEqual(selection.mode, .control) + XCTAssertEqual(selection.definition.adbServerPort, 5038) + XCTAssertEqual(selection.definition.consolePort, 5582) + XCTAssertEqual(selection.definition.controllerPort, 8554) + XCTAssertEqual(selection.definition.serial, "emulator-5582") + XCTAssertEqual(selection.definition.rollbackTarget, .control) + XCTAssertFalse(selection.definition.requiresControlStopped) + } + + func testRuntimeModeRegistryRejectsUnknownAndBlockedModes() throws { + let registry = try TFTMACRuntimeModeRegistry(data: try runtimeModeRegistryData()) + XCTAssertThrowsError( + try registry.selection(environment: [TFTMACRuntimeModeRegistry.environmentKey: "unknown"]) + ) + XCTAssertThrowsError( + try registry.selection(environment: [TFTMACRuntimeModeRegistry.environmentKey: "advanced_diagnostics"]) + ) + XCTAssertThrowsError( + try registry.selection(environment: [TFTMACRuntimeModeRegistry.environmentKey: "candidate"]) + ) + let diagnostics = try registry.definition(for: .advancedDiagnostics) + XCTAssertEqual(diagnostics.launchState, .blockedPendingControllerLease) + XCTAssertNil(diagnostics.controllerPort) + XCTAssertTrue(diagnostics.requiresControlStopped) + let candidate = try registry.definition(for: .candidate) + XCTAssertEqual(candidate.launchState, .blockedNotBuilt) + XCTAssertNil(candidate.controllerPort) + XCTAssertTrue(candidate.requiresControlStopped) + } + + func testRuntimeModeRegistryRejectsAnyPackagedRegistryTampering() throws { + let data = try runtimeModeRegistryData() + var object = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any]) + var modes = try XCTUnwrap(object["modes"] as? [String: Any]) + var control = try XCTUnwrap(modes["control"] as? [String: Any]) + control["console_port"] = 5598 + modes["control"] = control + object["modes"] = modes + let tampered = try JSONSerialization.data(withJSONObject: object, options: [.sortedKeys]) + XCTAssertThrowsError(try TFTMACRuntimeModeRegistry(data: tampered)) + } + + func testRuntimeLeasePersistsAcceptedModeIdentity() throws { + let registry = try TFTMACRuntimeModeRegistry(data: try runtimeModeRegistryData()) + let identity = try registry.selection(environment: [:]).leaseIdentity() + let root = FileManager.default.temporaryDirectory + .appendingPathComponent("tftmac-mode-lease-\(UUID().uuidString)", isDirectory: true) + defer { try? FileManager.default.removeItem(at: root) } + + let lease = try TFTMACRuntimeLease.acquire( + stateRoot: root, + identity: identity, + processIdentifier: ProcessInfo.processInfo.processIdentifier + ) + defer { lease.release() } + let payloadData = try Data(contentsOf: lease.url) + let payload = try XCTUnwrap(JSONSerialization.jsonObject(with: payloadData) as? [String: Any]) + XCTAssertEqual((payload["schema"] as? NSNumber)?.intValue, 2) + let savedIdentity = try XCTUnwrap(payload["identity"] as? [String: Any]) + XCTAssertEqual(savedIdentity["mode"] as? String, "control") + XCTAssertEqual(savedIdentity["registry_sha256"] as? String, identity.registrySha256) + XCTAssertEqual(savedIdentity["configuration_sha256"] as? String, identity.configurationSha256) + XCTAssertEqual(savedIdentity["avd_name"] as? String, "TFT_Ultra_Tablet") + XCTAssertEqual((savedIdentity["adb_server_port"] as? NSNumber)?.intValue, 5038) + XCTAssertEqual((savedIdentity["console_port"] as? NSNumber)?.intValue, 5582) + XCTAssertEqual((savedIdentity["controller_port"] as? NSNumber)?.intValue, 8554) + XCTAssertEqual(savedIdentity["serial"] as? String, "emulator-5582") + XCTAssertThrowsError( + try TFTMACRuntimeLease.acquire( + stateRoot: root, + identity: identity, + processIdentifier: ProcessInfo.processInfo.processIdentifier + ) + ) + } + + private func runtimeModeRegistryData() throws -> Data { + let testDirectory = URL(fileURLWithPath: #filePath).deletingLastPathComponent() + let repositoryRoot = testDirectory.deletingLastPathComponent().deletingLastPathComponent() + return try Data(contentsOf: repositoryRoot.appendingPathComponent("ssot/runtime-modes.json")) + } +`; +const testsEnd = tests.lastIndexOf("\n}"); +assert(testsEnd >= 0 && tests.slice(testsEnd).trim() === "}", "test class terminal brace was not found"); +tests = tests.slice(0, testsEnd) + testInsertion + tests.slice(testsEnd); +assert((tests.match(/^ func test/gm) ?? []).length === 47, "Wave B test insertion did not produce exactly 47 tests"); + +let project = readText("TFTMAC.xcodeproj/project.pbxproj"); +const ids = { + appModeBuild: "100000000000000000000038", + testModeBuild: "100000000000000000000039", + modesResourceBuild: "10000000000000000000003A", + authorityResourceBuild: "10000000000000000000003B", + modeFile: "200000000000000000000023", + modesFile: "200000000000000000000024", + authorityFile: "200000000000000000000025" +}; +for (const id of Object.values(ids)) assert(!project.includes(id), `Xcode object ID collision: ${id}`); +const buildDefinitions = `\t\t${ids.appModeBuild} /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.modeFile} /* RuntimeMode.swift */; };\n\t\t${ids.testModeBuild} /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.modeFile} /* RuntimeMode.swift */; };\n\t\t${ids.modesResourceBuild} /* runtime-modes.json in Resources */ = {isa = PBXBuildFile; fileRef = ${ids.modesFile} /* runtime-modes.json */; };\n\t\t${ids.authorityResourceBuild} /* runtime-authority.json in Resources */ = {isa = PBXBuildFile; fileRef = ${ids.authorityFile} /* runtime-authority.json */; };\n`; +project = insertBefore(project, "/* End PBXBuildFile section */", buildDefinitions, "Xcode build-file section"); +const fileDefinitions = `\t\t${ids.modeFile} /* RuntimeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeMode.swift; sourceTree = ""; };\n\t\t${ids.modesFile} /* runtime-modes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ssot/runtime-modes.json"; sourceTree = SOURCE_ROOT; };\n\t\t${ids.authorityFile} /* runtime-authority.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ssot/runtime-authority.json"; sourceTree = SOURCE_ROOT; };\n`; +project = insertBefore(project, "/* End PBXFileReference section */", fileDefinitions, "Xcode file-reference section"); + +function appendToGroup(text, groupComment, groupPath, addition, label) { + const pattern = new RegExp(`(\\t\\t[0-9A-F]{24} /\\* ${groupComment} \\*/ = \\{isa = PBXGroup; children = \\()([^)]*)(\\); path = ${groupPath}; sourceTree = ""; \\};)`); + const match = text.match(pattern); + assert(match, `${label}: group was not found`); + assert(!match[2].includes(addition.split(" ")[0]), `${label}: object already present`); + return text.replace(pattern, `${match[1]}${match[2]}${addition}${match[3]}`); +} +project = appendToGroup(project, "Runtime", "Runtime", `${ids.modeFile} /* RuntimeMode.swift */, `, "Xcode Runtime group"); +project = appendToGroup( + project, + "tftmac", + "tftmac", + `${ids.modesFile} /* runtime-modes.json */, ${ids.authorityFile} /* runtime-authority.json */, `, + "Xcode tftmac group" +); + +function appendBuildToSourcePhase(text, phaseId, buildId, label) { + const pattern = new RegExp(`(\\t\\t${phaseId} /\\* Sources \\*/ = \\{isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = \\()([^)]*)(\\); runOnlyForDeploymentPostprocessing = 0; \\};)`); + const match = text.match(pattern); + assert(match, `${label}: source phase was not found`); + return text.replace(pattern, `${match[1]}${match[2]}${buildId}, ${match[3]}`); +} +project = appendBuildToSourcePhase(project, "700000000000000000000001", ids.appModeBuild, "TFTMAC app source phase"); +project = appendBuildToSourcePhase(project, "700000000000000000000003", ids.testModeBuild, "TFTMAC test source phase"); +project = replaceOnce( + project, + "\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };", + `\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (${ids.modesResourceBuild}, ${ids.authorityResourceBuild},); runOnlyForDeploymentPostprocessing = 0; };`, + "TFTMAC resource phase" +); + +let verifier = readText("scripts/verify-tftmac.command"); +verifier = replaceOnce( + verifier, + ' "$ROOT/ssot/runtime-authority.json" \\\n', + ' "$ROOT/ssot/runtime-authority.json" \\\n "$ROOT/ssot/runtime-modes.json" \\\n "$ROOT/tftmac/Runtime/RuntimeMode.swift" \\\n', + "verifier required Wave B files" +); +const authorityHashAnchor = '[[ "$(sha256_file "$ROOT/ssot/runtime-authority.json")" == "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" ]]\n'; +const registryVerifier = `ROOT="$ROOT" EXPECTED_RUNTIME_MODES_SHA256="${finalRegistrySha256}" node <<'NODE'\n` + String.raw`const fs = require('node:fs'); +const path = require('node:path'); +const crypto = require('node:crypto'); +const root = process.env.ROOT; +const expectedRegistrySha256 = process.env.EXPECTED_RUNTIME_MODES_SHA256; +const modesPath = path.join(root, 'ssot/runtime-modes.json'); +const authorityPath = path.join(root, 'ssot/runtime-authority.json'); +const registryBytes = fs.readFileSync(modesPath); +const registry = JSON.parse(registryBytes); +function fail(message) { throw new Error(message); } +function assert(value, message) { if (!value) fail(message); } +function sha(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], ['launch_state', mode.launch_state], ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], ['library_root', mode.library_root], ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 || ''], ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 || ''], ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], ['avd_name', mode.avd_name], ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], ['avd_config_sha256', mode.avd_config_sha256 || ''], + ['avd_ini_path', mode.avd_ini_path], ['avd_ini_sha256', mode.avd_ini_sha256 || ''], + ['adb_server_port', mode.adb_server_port], ['console_port', mode.console_port], + ['controller_port', mode.controller_port === null ? '' : mode.controller_port], ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 || ''], ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha(Buffer.from(fields.map(([key, value]) => key + '=' + value).join('\n'))); +} +assert(sha(registryBytes) === expectedRegistrySha256, 'runtime registry packaged identity failed'); +assert(registry.schema === 1 && registry.default_mode === 'control', 'runtime registry schema/default failed'); +assert(registry.active_lease_relative_path === 'State/native-runtime.lease', 'runtime lease path failed'); +assert(JSON.stringify(Object.keys(registry.modes).sort()) === JSON.stringify(['advanced_diagnostics', 'candidate', 'control']), 'exact runtime modes failed'); +const used = new Map(); +for (const [name, mode] of Object.entries(registry.modes)) { + assert(name === mode.mode, 'mode key mismatch: ' + name); + assert(configurationHash(mode) === mode.configuration_sha256, 'configuration SHA mismatch: ' + name); + assert(mode.serial === 'emulator-' + mode.console_port, 'serial mismatch: ' + name); + for (const [kind, value] of [['adb', mode.adb_server_port], ['console', mode.console_port], ['controller', mode.controller_port]]) { + if (value === null) continue; + assert(!used.has(value), 'runtime port collision at ' + value); + used.set(value, name + '.' + kind); + } +} +const control = registry.modes.control; +assert(control.launch_state === 'enabled', 'control is not enabled'); +assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, 'control ports drifted'); +assert(control.serial === 'emulator-5582' && control.rollback_target === 'control' && control.requires_control_stopped === false, 'control identity drifted'); +assert(/^[0-9a-f]{64}$/.test(control.emulator_sha256) && /^[0-9a-f]{64}$/.test(control.gfxstream_backend_sha256), 'control binary identities are missing'); +assert(control.authority_manifest.sha256 === sha(fs.readFileSync(authorityPath)), 'control authority manifest hash failed'); +const diagnostics = registry.modes.advanced_diagnostics; +assert(diagnostics.launch_state === 'blocked_pending_controller_lease' && diagnostics.controller_port === null, 'diagnostics are not fail-closed'); +assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.serial === 'emulator-5586', 'diagnostic lease identity drifted'); +const candidate = registry.modes.candidate; +assert(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate is not fail-closed'); +NODE +rg -q 'TFTMACRuntimeModeRegistry\.loadBundled' "$ROOT/tftmac/App/AppCoordinator.swift" +rg -q 'runtimeSelection\.validateForLaunch\(\)' "$ROOT/tftmac/Runtime/TFTMACRuntime.swift" +rg -q 'TFTMACRuntimeLease\.acquire\(stateRoot: stateRoot, identity: leaseIdentity\)' "$ROOT/tftmac/Runtime/TFTMACRuntime.swift" +`; +verifier = replaceOnce(verifier, authorityHashAnchor, authorityHashAnchor + registryVerifier, "verifier runtime-mode authority block"); +const appBinaryAnchors = [ + 'test -x "$APP_BINARY"\n', + 'test -x "$RELEASE_DERIVED/Build/Products/Release/TFTMAC.app/Contents/MacOS/TFTMAC"\n' +]; +const matchingAppBinaryAnchors = appBinaryAnchors.filter((anchor) => verifier.includes(anchor)); +assert(matchingAppBinaryAnchors.length === 1, "verifier packaged-binary anchor was not uniquely resolved"); +const appBinaryAnchor = matchingAppBinaryAnchors[0]; +const appResourceVerifier = String.raw`APP_RESOURCES="$(cd "$(dirname "$APP_BINARY")/../Resources" && pwd)" +test -f "$APP_RESOURCES/runtime-modes.json" +test -f "$APP_RESOURCES/runtime-authority.json" +cmp -s "$ROOT/ssot/runtime-modes.json" "$APP_RESOURCES/runtime-modes.json" +cmp -s "$ROOT/ssot/runtime-authority.json" "$APP_RESOURCES/runtime-authority.json" +`; +verifier = replaceOnce(verifier, appBinaryAnchor, appBinaryAnchor + appResourceVerifier, "verifier packaged runtime authority resources"); +verifier = replaceOnce(verifier, "EXPECTED_TEST_COUNT=43", "EXPECTED_TEST_COUNT=47", "verifier test-count contract"); +assert(verifier.includes("43 deterministic unit tests"), "verifier completion test-count text was not found"); +verifier = verifier.replace("43 deterministic unit tests", "47 deterministic unit tests"); +verifier = verifier.replace("runtime authority", "runtime-mode authority"); + +const outputs = new Map([ + ["ssot/runtime-modes.json", registryOutput], + ["tftmac/Runtime/RuntimeMode.swift", runtimeModeOutput], + ["tftmac/Runtime/RuntimeLease.swift", runtimeLeaseOutput], + ["tftmac/App/AppCoordinator.swift", coordinator], + ["tftmac/Runtime/TFTMACRuntime.swift", runtime], + ["Tests/TFTMACTests/TFTMACGate1Tests.swift", tests], + ["TFTMAC.xcodeproj/project.pbxproj", project], + ["scripts/verify-tftmac.command", verifier] +]); + +const staged = []; +for (const [relativePath, content] of outputs) { + const target = absolute(relativePath); + const temporary = `${target}.waveb-v2-${process.pid}.tmp`; + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(temporary, content, "utf8"); + const mode = fs.existsSync(target) ? fs.statSync(target).mode & 0o777 : 0o644; + fs.chmodSync(temporary, mode); + staged.push({ relativePath, target, temporary, sha256: sha256(Buffer.from(content, "utf8")) }); +} +for (const item of staged) fs.renameSync(item.temporary, item.target); + +const receipt = { + schema: 1, + state: "WAVE_B_IMPLEMENTATION_APPLIED", + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + operation_id: operationId, + base_head_sha: expectedHead, + scope_lock_sha256: expectedScopeLock, + input_sha256: expectedInputs, + plan_input_sha256: Object.fromEntries(activePlanFiles.map((relativePath) => [relativePath, fileHash(relativePath)])), + output_sha256: Object.fromEntries(staged.map((item) => [item.relativePath, item.sha256])), + runtime_modes_sha256: finalRegistrySha256, + control_identity: { + emulator_path: control.emulator_path, + emulator_sha256: controlEmulatorSha256, + gfxstream_backend_path: control.gfxstream_backend_path, + gfxstream_backend_sha256: controlGfxstreamSha256, + configuration_sha256: control.configuration_sha256 + }, + diagnostics: { + launch_state: diagnostics.launch_state, + controller_port: diagnostics.controller_port, + serial: diagnostics.serial, + first_boot_attempted: false + }, + effects: { + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + installed_app_replacement_attempted: false, + package_launch_attempted: false, + source_only: true + }, + next_required_action: "Checkpoint this implementation candidate, then run one exact production validation without launching Android.", + applied_at: new Date().toISOString() +}; +fs.writeFileSync( + absolute(`${waveRoot}/WAVE_B_IMPLEMENTATION_RECEIPT.json`), + `${JSON.stringify(receipt, null, 2)}\n`, + { flag: "wx", mode: 0o644 } +); + +console.log(JSON.stringify({ + state: receipt.state, + runtime_modes_sha256: finalRegistrySha256, + changed_paths: Array.from(outputs.keys()), + receipt: `${waveRoot}/WAVE_B_IMPLEMENTATION_RECEIPT.json`, + effects: receipt.effects +}, null, 2)); diff --git a/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/gate-waveb-candidate.mjs b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/gate-waveb-candidate.mjs new file mode 100644 index 0000000..9ee2b43 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/gate-waveb-candidate.mjs @@ -0,0 +1,153 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = process.cwd(); +const waveRoot = ".clara/plans/tftmac-causal-graphics-v1/wave-b-v2"; +const receiptRelative = `${waveRoot}/WAVE_B_IMPLEMENTATION_RECEIPT.json`; +const passRelative = `${waveRoot}/WAVE_B_CANDIDATE_GATE_PASS.json`; +const failureRelative = `${waveRoot}/WAVE_B_CANDIDATE_GATE_FAILURE.json`; +const expectedHead = "f1ef3f7c067b88e4ce464fc4567fcb03a6accf91"; +const expectedScopeLock = "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e"; + +function absolute(relativePath) { return path.join(root, relativePath); } +function sha256(buffer) { return crypto.createHash("sha256").update(buffer).digest("hex"); } +function fileHash(relativePath) { return sha256(fs.readFileSync(absolute(relativePath))); } +function git(args) { + const result = spawnSync("git", args, { cwd: root, encoding: "utf8", maxBuffer: 16 * 1024 * 1024 }); + if (result.error || result.status !== 0) throw new Error(`git ${args.join(" ")} failed: ${result.error?.message ?? result.stderr}`); + return result.stdout; +} +function writeJSON(relativePath, value) { + fs.writeFileSync(absolute(relativePath), `${JSON.stringify(value, null, 2)}\n`, { flag: "wx", mode: 0o644 }); +} +function fail(message, details = {}) { + const failure = { + schema: 1, + state: "WAVE_B_CANDIDATE_GATE_FAILED", + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + message, + details, + effects: { + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + installed_app_replacement_attempted: false, + package_launch_attempted: false + }, + failed_at: new Date().toISOString() + }; + if (!fs.existsSync(absolute(failureRelative))) writeJSON(failureRelative, failure); + console.error(JSON.stringify(failure, null, 2)); + process.exit(1); +} +function assert(condition, message, details) { if (!condition) fail(message, details); } + +assert(git(["rev-parse", "HEAD"]).trim() === expectedHead, "Wave B candidate base HEAD drifted."); +assert(fs.existsSync(absolute(receiptRelative)), "Wave B implementation receipt is missing."); +assert(!fs.existsSync(absolute(passRelative)), "Wave B candidate gate pass already exists; refusing replay."); +const receipt = JSON.parse(fs.readFileSync(absolute(receiptRelative), "utf8")); +assert(receipt.schema === 1 && receipt.state === "WAVE_B_IMPLEMENTATION_APPLIED", "Wave B implementation receipt state is invalid."); +assert(receipt.project_id === "tftmac" && receipt.change_id === "215ec5a3-6554-4ca3-95db-1525433bb20f", "Wave B implementation receipt identity is invalid."); +assert(receipt.base_head_sha === expectedHead, "Wave B implementation receipt base HEAD is invalid."); +assert(receipt.scope_lock_sha256 === expectedScopeLock, "Wave B implementation receipt scope lock is invalid."); +assert(receipt.operation_id === "tftmac-waveb-v2-source-apply-20260901-v1", "Wave B implementation operation identity is invalid."); +for (const [key, value] of Object.entries(receipt.effects ?? {})) { + if (key === "source_only") continue; + assert(value === false, `Wave B implementation receipt reports forbidden effect ${key}.`); +} +assert(receipt.effects?.source_only === true, "Wave B implementation receipt is not source-only."); + +const mismatches = []; +for (const [relativePath, expected] of Object.entries(receipt.output_sha256 ?? {})) { + const observed = fs.existsSync(absolute(relativePath)) ? fileHash(relativePath) : null; + if (observed !== expected) mismatches.push({ path: relativePath, expected, observed }); +} +assert(mismatches.length === 0, "Wave B implementation outputs do not match the receipt.", { mismatches }); +assert(fileHash("ssot/runtime-modes.json") === receipt.runtime_modes_sha256, "Runtime registry SHA does not match the implementation receipt."); + +const registry = JSON.parse(fs.readFileSync(absolute("ssot/runtime-modes.json"), "utf8")); +assert(registry.default_mode === "control", "Control is not the default mode."); +assert(JSON.stringify(Object.keys(registry.modes).sort()) === JSON.stringify(["advanced_diagnostics", "candidate", "control"]), "Runtime registry does not contain exactly three modes."); +assert(registry.modes.control.launch_state === "enabled", "Control is not enabled."); +assert(registry.modes.control.controller_port === 8554 && registry.modes.control.serial === "emulator-5582", "Control lease identity drifted."); +assert(registry.modes.advanced_diagnostics.launch_state === "blocked_pending_controller_lease", "Advanced diagnostics is not fail-closed."); +assert(registry.modes.advanced_diagnostics.controller_port === null, "Advanced diagnostics has an unaccepted controller port."); +assert(registry.modes.candidate.launch_state === "blocked_not_built", "Candidate is not fail-closed."); +assert(registry.modes.candidate.controller_port === null, "Candidate has an unaccepted controller port."); + +const markers = [ + ["tftmac/App/AppCoordinator.swift", "TFTMACRuntimeModeRegistry.loadBundled()"], + ["tftmac/App/AppCoordinator.swift", "runtimeSelection.validateForLaunch()"], + ["tftmac/Runtime/TFTMACRuntime.swift", "guard runtimeSelection.mode == .control"], + ["tftmac/Runtime/TFTMACRuntime.swift", "TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: leaseIdentity)"], + ["tftmac/Runtime/RuntimeLease.swift", "let identity: TFTMACRuntimeLeaseIdentity?"], + ["TFTMAC.xcodeproj/project.pbxproj", "RuntimeMode.swift in Sources"], + ["TFTMAC.xcodeproj/project.pbxproj", "runtime-modes.json in Resources"], + ["TFTMAC.xcodeproj/project.pbxproj", "runtime-authority.json in Resources"], + ["scripts/verify-tftmac.command", "EXPECTED_TEST_COUNT=47"], + ["scripts/verify-tftmac.command", "runtime-modes.json"], + ["Tests/TFTMACTests/TFTMACGate1Tests.swift", "testRuntimeModeRegistryDefinesExactlyThreeModesAndDefaultsControl"] +]; +for (const [relativePath, marker] of markers) { + assert(fs.readFileSync(absolute(relativePath), "utf8").includes(marker), `Required Wave B marker is missing from ${relativePath}.`, { marker }); +} +const tests = fs.readFileSync(absolute("Tests/TFTMACTests/TFTMACGate1Tests.swift"), "utf8"); +assert((tests.match(/^ func test/gm) ?? []).length === 47, "Wave B test-count contract is not 47."); + +const allowedPaths = new Set([ + "ssot/runtime-modes.json", + "tftmac/Runtime/RuntimeMode.swift", + "tftmac/Runtime/RuntimeLease.swift", + "tftmac/App/AppCoordinator.swift", + "tftmac/Runtime/TFTMACRuntime.swift", + "Tests/TFTMACTests/TFTMACGate1Tests.swift", + "TFTMAC.xcodeproj/project.pbxproj", + "scripts/verify-tftmac.command", + `${waveRoot}/RuntimeMode.swift.template`, + `${waveRoot}/RuntimeLease.swift.template`, + `${waveRoot}/apply-waveb-v2.mjs`, + `${waveRoot}/gate-waveb-candidate.mjs`, + receiptRelative +]); +const status = git(["status", "--porcelain=v1", "--untracked-files=all"]) + .split("\n") + .filter(Boolean) + .map((line) => ({ line, path: line.slice(3) })); +const unexpected = status.filter(({ path: relativePath }) => !allowedPaths.has(relativePath)); +assert(unexpected.length === 0, "Unexpected paths are dirty in the Wave B candidate.", { unexpected }); +for (const required of allowedPaths) { + assert(status.some(({ path: relativePath }) => relativePath === required), `Required Wave B candidate path is not dirty: ${required}`); +} + +const pass = { + schema: 1, + state: "WAVE_B_CANDIDATE_GATE_PASS", + project_id: "tftmac", + change_id: "215ec5a3-6554-4ca3-95db-1525433bb20f", + base_head_sha: expectedHead, + scope_lock_sha256: expectedScopeLock, + implementation_receipt_sha256: fileHash(receiptRelative), + runtime_modes_sha256: receipt.runtime_modes_sha256, + output_sha256: receipt.output_sha256, + deterministic_test_count: 47, + diagnostics_launch_state: registry.modes.advanced_diagnostics.launch_state, + diagnostics_controller_port: registry.modes.advanced_diagnostics.controller_port, + checkpoint_paths: [...allowedPaths, passRelative].sort(), + effects: { + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + installed_app_replacement_attempted: false, + package_launch_attempted: false, + build_attempted: false, + tests_attempted: false + }, + next_required_action: "Checkpoint the implementation candidate, then run one exact production validator on the committed head.", + passed_at: new Date().toISOString() +}; +writeJSON(passRelative, pass); +if (fs.existsSync(absolute(failureRelative))) fs.unlinkSync(absolute(failureRelative)); +console.log(JSON.stringify(pass, null, 2)); diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/CONTINUATION_AMENDMENT.md b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/CONTINUATION_AMENDMENT.md new file mode 100644 index 0000000..2f33cd0 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/CONTINUATION_AMENDMENT.md @@ -0,0 +1,39 @@ +# Wave B v3 — Runtime-Mode Integration Continuation Amendment + +Status: ACTIVE APPEND-ONLY AMENDMENT + +This amendment supplements, and does not replace, the original TFTMAC Causal Graphics Optimization plan v1.1. The original plan remains at `.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md` with SHA-256 `78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b`. The execution-scope lock remains unchanged at SHA-256 `dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e`. + +## Current accepted authority + +- Active managed change: `215ec5a3-6554-4ca3-95db-1525433bb20f`. +- Exact base/head before this amendment: `d96a1caf68b807bbae1a03246666da7eea4df620`. +- Accepted r9 diagnostic build manifest: `9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d`. +- Accepted stopped-clone receipt: `09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648`. +- Accepted native diagnostic host receipt: `a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067`. +- Stock Build 8 remains the protected and default control runtime. + +## New finding and adjudication + +An unaccepted local draft marked `advanced_diagnostics` launch-ready on controller port 8556 without a durable controller-port allocation receipt. That draft is rejected, preserved under `.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3`, and must not become launch authority. The accepted registry is restored before product-source work. + +Five stale Clara watchers were observing operation IDs that never existed. They are observation noise only: they authorize no replay and do not prove any emulator, TFT, clone, build, or validation effect. + +## Effective Wave B implementation scope + +1. Preserve the rejected draft and restore the accepted fail-closed registry. +2. Add a typed three-mode registry contract for exactly `control`, `advanced_diagnostics`, and `candidate`. +3. Keep `control` as the only launch-ready default and preserve its existing Build 8 runtime, AVD, ports, serial, package path, state behavior, and /usr/bin/open app-host chain. +4. Give each mode an explicit runtime root, AVD identity, ADB/console/controller identity, state namespace, and lease identity. A single global exclusivity lease remains the collision guard and records the exact selected mode identity. +5. Keep `advanced_diagnostics` blocked until a separately receipted controller port is written through a later append-only gate. Its sealed build, stopped-clone, and native-host receipts must be structurally and cryptographically validated before it can become launch-ready. +6. Keep `candidate` blocked until an accepted ROOT_NAMED-derived, stock-compatible candidate exists. +7. Remove control-only hard-coded ADB, AVD, serial, console, and controller identities from shared runtime operations; resolve those values from the selected definition. +8. Verify selected binary hashes before launch and verify loaded emulator/gfxstream image identity before TFT starts. +9. This source-only wave performs no emulator launch, TFT launch, AVD mutation, runtime replacement, application install, or control shutdown. +10. Run one decisive changed-head production verifier after implementation. Do not rerun the already-accepted unchanged 43-test baseline separately. + +## Wave B v3 acceptance + +PASS requires: exact three-mode decoding; default control behavior; diagnostics and candidate fail-closed behavior; registry and external-receipt tamper rejection; mode-aware lease persistence; mode-derived runtime commands; unsigned Release build; all native tests; unchanged visible Git state after validation; and a review proving no runtime process was launched. + +After PASS, the next causal stage is a separate controller-port allocation receipt and guarded diagnostic first-boot gate. No later graphics instrumentation, candidate promotion, or production cutover is authorized by this amendment. diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREFLIGHT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREFLIGHT.json new file mode 100644 index 0000000..35ecbe7 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREFLIGHT.json @@ -0,0 +1,41 @@ +{ + "schema": 1, + "state": "READY_FOR_WAVE_B_V3_SOURCE_ONLY", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-01T22:47:27.564Z", + "base_head_sha": "d96a1caf68b807bbae1a03246666da7eea4df620", + "original_plan": { + "path": ".clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md", + "sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b" + }, + "scope_lock": { + "path": ".clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt", + "sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "unchanged": true + }, + "amendment": { + "path": ".clara/plans/tftmac-causal-graphics-v1/wave-b-v3/CONTINUATION_AMENDMENT.md", + "sha256": "df9d3a537d94d4f32337c2658168714925c1f3206775964069ea135a27cbdc4a" + }, + "accepted_registry_sha256": "81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2", + "rejected_draft": { + "sha256": "457ca5865f1bfcfaca16bd1eee1f32db15f90bd9c8764706ba64db56b7a9e518", + "reason": "advanced_diagnostics enabled on controller port 8556 without durable allocation receipt", + "preserved_root": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3" + }, + "accepted_external_receipts": { + "diagnostic_build": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d", + "diagnostic_avd_clone": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648", + "diagnostic_native_host": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067" + }, + "verified": [ + "Original v1.1 plan and execution-scope lock are intact.", + "Current managed change is based on the accepted published Wave B registry head.", + "Rejected draft is preserved before restoration.", + "Stock Build 8 is not modified or stopped by this source wave.", + "No diagnostic first boot, TFT launch, runtime rebuild, clone replay, or installed-app replacement is authorized.", + "Changed-head production validation subsumes a separate unchanged-baseline rerun." + ], + "next_safe_action": "Apply the bounded mode-aware source integration, then run one changed-head production validation." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREPARATION_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREPARATION_RECEIPT.json new file mode 100644 index 0000000..0cb83ee --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/PREPARATION_RECEIPT.json @@ -0,0 +1,19 @@ +{ + "schema": 1, + "state": "WAVE_B_V3_PREPARATION_PASS", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "operation_id": "tftmac-waveb-v3-prepare-host-20260901-v1", + "observed_at": "2026-09-01T22:47:27.564Z", + "base_head_sha": "d96a1caf68b807bbae1a03246666da7eea4df620", + "original_plan_sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "amendment_sha256": "df9d3a537d94d4f32337c2658168714925c1f3206775964069ea135a27cbdc4a", + "preflight_sha256": "bec3a488d3386966cb3f98cdf1b5f35a083519d1dfb873260db4d63576b19247", + "zengate_sha256": "6d460880102823285456668f98dde26d54a11b0e3e20f8270d699947ae2b7003", + "accepted_registry_restored_sha256": "81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2", + "preserved_root": ".clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3", + "product_source_mutated": false, + "runtime_effect_attempted": false, + "next_safe_action": "Checkpoint this preparation, then apply Wave B v3 product source." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/ZENGATE_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/ZENGATE_RECEIPT.json new file mode 100644 index 0000000..9c225f6 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/ZENGATE_RECEIPT.json @@ -0,0 +1,37 @@ +{ + "schema": 1, + "result": "PASS", + "gate": "TARGETED_WAVE_B_V3_ZENGATE", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-01T22:47:27.564Z", + "original_plan_sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "amendment_sha256": "df9d3a537d94d4f32337c2658168714925c1f3206775964069ea135a27cbdc4a", + "preflight_sha256": "bec3a488d3386966cb3f98cdf1b5f35a083519d1dfb873260db4d63576b19247", + "score_preserved": true, + "production_requirement": "MANDATORY", + "risks": [ + { + "risk": "unreceipted diagnostic launch", + "mitigation": "diagnostics remains blocked pending a later controller-port receipt" + }, + { + "risk": "control-path regression", + "mitigation": "control remains default and exact control identity is asserted in registry and tests" + }, + { + "risk": "cross-mode collision", + "mitigation": "lease persists registry/configuration/AVD/port/serial identity and rejects concurrent ownership" + }, + { + "risk": "receipt or binary drift", + "mitigation": "SHA-256, state, identity, and pre-launch binary checks fail closed" + }, + { + "risk": "scope expansion", + "mitigation": "no runtime launch, installed-app replacement, broad refactor, dependency update, or later phase work in this wave" + } + ], + "execution_scope_lock": "Implement only this amendment and the minimum source/test/project-file changes required for its acceptance. No unsolicited refactor, cleanup, rename, generalization, optimization, dependency upgrade, reformatting, future-proofing, or unrelated behavior change." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/prepare-waveb-v3.mjs b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/prepare-waveb-v3.mjs new file mode 100644 index 0000000..c508beb --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/prepare-waveb-v3.mjs @@ -0,0 +1,222 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { execFileSync } from 'node:child_process'; + +const ROOT = process.cwd(); +const CHANGE_ID = '215ec5a3-6554-4ca3-95db-1525433bb20f'; +const EXPECTED_HEAD = 'd96a1caf68b807bbae1a03246666da7eea4df620'; +const PLAN = '.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_PLAN.md'; +const PLAN_SHA = '78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b'; +const LOCK = '.clara/plans/tftmac-causal-graphics-v1/SCOPE_LOCK.txt'; +const LOCK_SHA = 'dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e'; +const DIR = '.clara/plans/tftmac-causal-graphics-v1/wave-b-v3'; +const PROTECTED = '.clara/plans/tftmac-causal-graphics-v1/protected-local-work/unaccepted-waveb-draft-before-v3'; +const DIRTY_REGISTRY_SHA = '457ca5865f1bfcfaca16bd1eee1f32db15f90bd9c8764706ba64db56b7a9e518'; +const ACCEPTED_BUILD_SHA = '9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d'; +const ACCEPTED_CLONE_SHA = '09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648'; +const ACCEPTED_HOST_SHA = 'a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067'; + +function fail(message) { + console.error(`WAVE_B_V3_PREPARE_FAILED: ${message}`); + process.exit(1); +} +function sha256Bytes(bytes) { + return crypto.createHash('sha256').update(bytes).digest('hex'); +} +function sha256File(relativePath) { + return sha256Bytes(fs.readFileSync(path.join(ROOT, relativePath))); +} +function ensure(condition, message) { + if (!condition) fail(message); +} +function git(...args) { + return execFileSync('/usr/bin/git', args, { cwd: ROOT, encoding: 'utf8' }); +} +function writeJSON(relativePath, value) { + const target = path.join(ROOT, relativePath); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, `${JSON.stringify(value, null, 2)}\n`, { flag: 'wx', mode: 0o644 }); +} +function writeText(relativePath, value) { + const target = path.join(ROOT, relativePath); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, value, { flag: 'wx', mode: 0o644 }); +} +function copyPreserved(sourceRelative, destinationRelative) { + const source = path.join(ROOT, sourceRelative); + const destination = path.join(ROOT, destinationRelative); + ensure(fs.existsSync(source), `preservation source is missing: ${sourceRelative}`); + fs.mkdirSync(path.dirname(destination), { recursive: true }); + fs.copyFileSync(source, destination, fs.constants.COPYFILE_EXCL); + return { + source: sourceRelative, + preserved_path: destinationRelative, + sha256: sha256File(sourceRelative), + bytes: fs.statSync(source).size + }; +} + +ensure(git('rev-parse', 'HEAD').trim() === EXPECTED_HEAD, 'managed change HEAD drifted'); +ensure(sha256File(PLAN) === PLAN_SHA, 'original implementation plan drifted'); +ensure(sha256File(LOCK) === LOCK_SHA, 'execution scope lock drifted'); +ensure(!fs.existsSync(path.join(ROOT, PROTECTED)), 'protected draft destination already exists; reconcile instead of replaying'); +ensure(sha256File('ssot/runtime-modes.json') === DIRTY_REGISTRY_SHA, 'unaccepted runtime registry draft changed; review before mutation'); + +const dirtyRegistry = JSON.parse(fs.readFileSync(path.join(ROOT, 'ssot/runtime-modes.json'), 'utf8')); +ensure(dirtyRegistry?.modes?.advanced_diagnostics?.launch_state === 'enabled', 'expected rejected diagnostics-enabled draft was not found'); +ensure(dirtyRegistry?.modes?.advanced_diagnostics?.controller_port === 8556, 'expected unreceipted diagnostic controller port was not found'); +ensure(dirtyRegistry?.modes?.candidate?.launch_state === 'blocked_not_built', 'candidate draft is not fail-closed'); + +const staleFiles = [ + 'ssot/runtime-modes.json', + '.clara/plans/tftmac-causal-graphics-v1/AppCoordinator.swift.template', + '.clara/plans/tftmac-causal-graphics-v1/RuntimeLease.swift.template', + '.clara/plans/tftmac-causal-graphics-v1/RuntimeMode.swift.template', + '.clara/plans/tftmac-causal-graphics-v1/apply-waveb-source.mjs', + '.clara/plans/tftmac-causal-graphics-v1/preserve-unaccepted-waveb-partial.mjs', + '.clara/plans/tftmac-causal-graphics-v1/validate-waveb.mjs', + '.clara/plans/tftmac-causal-graphics-v1/wave-b-v2/RuntimeLease.swift.template', + '.clara/plans/tftmac-causal-graphics-v1/wave-b-v2/RuntimeMode.swift.template', + '.clara/plans/tftmac-causal-graphics-v1/wave-b-v2/apply-waveb-v2.mjs', + '.clara/plans/tftmac-causal-graphics-v1/wave-b-v2/gate-waveb-candidate.mjs' +]; +const preserved = staleFiles.map((sourceRelative) => { + const suffix = sourceRelative === 'ssot/runtime-modes.json' + ? 'runtime-modes.unaccepted.json' + : sourceRelative.replace('.clara/plans/tftmac-causal-graphics-v1/', ''); + return copyPreserved(sourceRelative, `${PROTECTED}/${suffix}`); +}); + +const acceptedRegistryBytes = Buffer.from(git('show', 'HEAD:ssot/runtime-modes.json')); +const acceptedRegistrySha = sha256Bytes(acceptedRegistryBytes); +fs.writeFileSync(path.join(ROOT, 'ssot/runtime-modes.json'), acceptedRegistryBytes, { mode: 0o644 }); + +for (const stale of staleFiles.slice(1)) { + fs.rmSync(path.join(ROOT, stale), { force: true }); +} +fs.rmSync(path.join(ROOT, '.clara/plans/tftmac-causal-graphics-v1/wave-b-v2'), { recursive: true, force: true }); + +const observedAt = new Date().toISOString(); +const amendment = `# Wave B v3 — Runtime-Mode Integration Continuation Amendment\n\n` + +`Status: ACTIVE APPEND-ONLY AMENDMENT\n\n` + +`This amendment supplements, and does not replace, the original TFTMAC Causal Graphics Optimization plan v1.1. The original plan remains at \`${PLAN}\` with SHA-256 \`${PLAN_SHA}\`. The execution-scope lock remains unchanged at SHA-256 \`${LOCK_SHA}\`.\n\n` + +`## Current accepted authority\n\n` + +`- Active managed change: \`${CHANGE_ID}\`.\n` + +`- Exact base/head before this amendment: \`${EXPECTED_HEAD}\`.\n` + +`- Accepted r9 diagnostic build manifest: \`${ACCEPTED_BUILD_SHA}\`.\n` + +`- Accepted stopped-clone receipt: \`${ACCEPTED_CLONE_SHA}\`.\n` + +`- Accepted native diagnostic host receipt: \`${ACCEPTED_HOST_SHA}\`.\n` + +`- Stock Build 8 remains the protected and default control runtime.\n\n` + +`## New finding and adjudication\n\n` + +`An unaccepted local draft marked \`advanced_diagnostics\` launch-ready on controller port 8556 without a durable controller-port allocation receipt. That draft is rejected, preserved under \`${PROTECTED}\`, and must not become launch authority. The accepted registry is restored before product-source work.\n\n` + +`Five stale Clara watchers were observing operation IDs that never existed. They are observation noise only: they authorize no replay and do not prove any emulator, TFT, clone, build, or validation effect.\n\n` + +`## Effective Wave B implementation scope\n\n` + +`1. Preserve the rejected draft and restore the accepted fail-closed registry.\n` + +`2. Add a typed three-mode registry contract for exactly \`control\`, \`advanced_diagnostics\`, and \`candidate\`.\n` + +`3. Keep \`control\` as the only launch-ready default and preserve its existing Build 8 runtime, AVD, ports, serial, package path, state behavior, and /usr/bin/open app-host chain.\n` + +`4. Give each mode an explicit runtime root, AVD identity, ADB/console/controller identity, state namespace, and lease identity. A single global exclusivity lease remains the collision guard and records the exact selected mode identity.\n` + +`5. Keep \`advanced_diagnostics\` blocked until a separately receipted controller port is written through a later append-only gate. Its sealed build, stopped-clone, and native-host receipts must be structurally and cryptographically validated before it can become launch-ready.\n` + +`6. Keep \`candidate\` blocked until an accepted ROOT_NAMED-derived, stock-compatible candidate exists.\n` + +`7. Remove control-only hard-coded ADB, AVD, serial, console, and controller identities from shared runtime operations; resolve those values from the selected definition.\n` + +`8. Verify selected binary hashes before launch and verify loaded emulator/gfxstream image identity before TFT starts.\n` + +`9. This source-only wave performs no emulator launch, TFT launch, AVD mutation, runtime replacement, application install, or control shutdown.\n` + +`10. Run one decisive changed-head production verifier after implementation. Do not rerun the already-accepted unchanged 43-test baseline separately.\n\n` + +`## Wave B v3 acceptance\n\n` + +`PASS requires: exact three-mode decoding; default control behavior; diagnostics and candidate fail-closed behavior; registry and external-receipt tamper rejection; mode-aware lease persistence; mode-derived runtime commands; unsigned Release build; all native tests; unchanged visible Git state after validation; and a review proving no runtime process was launched.\n\n` + +`After PASS, the next causal stage is a separate controller-port allocation receipt and guarded diagnostic first-boot gate. No later graphics instrumentation, candidate promotion, or production cutover is authorized by this amendment.\n`; +writeText(`${DIR}/CONTINUATION_AMENDMENT.md`, amendment); +const amendmentSha = sha256File(`${DIR}/CONTINUATION_AMENDMENT.md`); + +const preflight = { + schema: 1, + state: 'READY_FOR_WAVE_B_V3_SOURCE_ONLY', + project_id: 'tftmac', + change_id: CHANGE_ID, + observed_at: observedAt, + base_head_sha: EXPECTED_HEAD, + original_plan: { path: PLAN, sha256: PLAN_SHA }, + scope_lock: { path: LOCK, sha256: LOCK_SHA, unchanged: true }, + amendment: { path: `${DIR}/CONTINUATION_AMENDMENT.md`, sha256: amendmentSha }, + accepted_registry_sha256: acceptedRegistrySha, + rejected_draft: { + sha256: DIRTY_REGISTRY_SHA, + reason: 'advanced_diagnostics enabled on controller port 8556 without durable allocation receipt', + preserved_root: PROTECTED + }, + accepted_external_receipts: { + diagnostic_build: ACCEPTED_BUILD_SHA, + diagnostic_avd_clone: ACCEPTED_CLONE_SHA, + diagnostic_native_host: ACCEPTED_HOST_SHA + }, + verified: [ + 'Original v1.1 plan and execution-scope lock are intact.', + 'Current managed change is based on the accepted published Wave B registry head.', + 'Rejected draft is preserved before restoration.', + 'Stock Build 8 is not modified or stopped by this source wave.', + 'No diagnostic first boot, TFT launch, runtime rebuild, clone replay, or installed-app replacement is authorized.', + 'Changed-head production validation subsumes a separate unchanged-baseline rerun.' + ], + next_safe_action: 'Apply the bounded mode-aware source integration, then run one changed-head production validation.' +}; +writeJSON(`${DIR}/PREFLIGHT.json`, preflight); +const preflightSha = sha256File(`${DIR}/PREFLIGHT.json`); + +const zenGate = { + schema: 1, + result: 'PASS', + gate: 'TARGETED_WAVE_B_V3_ZENGATE', + project_id: 'tftmac', + change_id: CHANGE_ID, + observed_at: observedAt, + original_plan_sha256: PLAN_SHA, + scope_lock_sha256: LOCK_SHA, + amendment_sha256: amendmentSha, + preflight_sha256: preflightSha, + score_preserved: true, + production_requirement: 'MANDATORY', + risks: [ + { risk: 'unreceipted diagnostic launch', mitigation: 'diagnostics remains blocked pending a later controller-port receipt' }, + { risk: 'control-path regression', mitigation: 'control remains default and exact control identity is asserted in registry and tests' }, + { risk: 'cross-mode collision', mitigation: 'lease persists registry/configuration/AVD/port/serial identity and rejects concurrent ownership' }, + { risk: 'receipt or binary drift', mitigation: 'SHA-256, state, identity, and pre-launch binary checks fail closed' }, + { risk: 'scope expansion', mitigation: 'no runtime launch, installed-app replacement, broad refactor, dependency update, or later phase work in this wave' } + ], + execution_scope_lock: 'Implement only this amendment and the minimum source/test/project-file changes required for its acceptance. No unsolicited refactor, cleanup, rename, generalization, optimization, dependency upgrade, reformatting, future-proofing, or unrelated behavior change.' +}; +writeJSON(`${DIR}/ZENGATE_RECEIPT.json`, zenGate); + +const inventory = { + schema: 1, + state: 'UNACCEPTED_WAVE_B_DRAFT_PRESERVED', + project_id: 'tftmac', + change_id: CHANGE_ID, + observed_at: observedAt, + rejected_registry_sha256: DIRTY_REGISTRY_SHA, + accepted_registry_restored_sha256: acceptedRegistrySha, + preserved +}; +writeJSON(`${PROTECTED}/INVENTORY.json`, inventory); + +const receipt = { + schema: 1, + state: 'WAVE_B_V3_PREPARATION_PASS', + project_id: 'tftmac', + change_id: CHANGE_ID, + operation_id: process.env.CLARA_OPERATION_ID ?? null, + observed_at: observedAt, + base_head_sha: EXPECTED_HEAD, + original_plan_sha256: PLAN_SHA, + scope_lock_sha256: LOCK_SHA, + amendment_sha256: amendmentSha, + preflight_sha256: preflightSha, + zengate_sha256: sha256File(`${DIR}/ZENGATE_RECEIPT.json`), + accepted_registry_restored_sha256: acceptedRegistrySha, + preserved_root: PROTECTED, + product_source_mutated: false, + runtime_effect_attempted: false, + next_safe_action: 'Checkpoint this preparation, then apply Wave B v3 product source.' +}; +writeJSON(`${DIR}/PREPARATION_RECEIPT.json`, receipt); +console.log(JSON.stringify(receipt, null, 2)); From 3326792efc694e853312aa7347abcb1edd96575a Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 18:46:34 -0500 Subject: [PATCH 04/10] Checkpoint Wave B v3 restart continuation plan --- .../RuntimeModeAuthority.swift.template | 841 +++++++++++ .../wave-b-v3/apply-waveb-v3.mjs | 1294 +++++++++++++++++ .../wave-b-v3/validate-waveb-v3.mjs | 278 ++++ 3 files changed, 2413 insertions(+) create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/RuntimeModeAuthority.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/apply-waveb-v3.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v3/validate-waveb-v3.mjs diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/RuntimeModeAuthority.swift.template b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/RuntimeModeAuthority.swift.template new file mode 100644 index 0000000..1aaf84b --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/RuntimeModeAuthority.swift.template @@ -0,0 +1,841 @@ +import CryptoKit +import Darwin +import Foundation + +enum TFTMACRuntimeLaunchStrategy: String, Codable, Sendable { + case bundledForwarder = "bundled_forwarder" + case externalNativeHost = "external_native_host" + case blocked +} + +enum TFTMACRuntimeProfilePolicy: String, Codable, Sendable { + case validatedNativePreferences = "validated_native_preferences" + case fixedRegistryProfile = "fixed_registry_profile" + case blocked +} + +enum TFTMACRuntimeHostKind: String, Codable, Sendable { + case bundledResource = "bundled_resource" + case externalApplication = "external_application" +} + +struct TFTMACSealedReceiptReference: Codable, Equatable, Sendable { + let path: String + let sha256: String + let requiredState: String +} + +struct TFTMACRuntimeHostAuthority: Codable, Equatable, Sendable { + let kind: TFTMACRuntimeHostKind + let path: String + let bundleIdentifier: String + let executableRelativePath: String + let executableSha256: String? + let sourcePath: String? + let sourceSha256: String? + let infoPlistPath: String? + let infoPlistSha256: String? + let buildReceiptResource: String? +} + +struct TFTMACRuntimeLockedProfile: Codable, Equatable, Sendable { + let identifier: String + let width: Int + let height: Int + let densityDpi: Int + let refreshHz: Int + let vcpu: Int + let ramMib: Int + let gpuMode: String + let audioBackend: String + let graphicsTransport: String + let asgWriteBufferSize: Int + let asgWriteStepSize: Int + let asgDataRingSize: Int + let asgDrawFlushInterval: Int + let angleEnabledFeatures: String + let angleDisabledFeatures: String +} + +struct TFTMACDiagnosticReceiptAuthority: Codable, Equatable, Sendable { + let buildId: String + let runtimeConfigurationSha256: String + let build: TFTMACSealedReceiptReference + let clone: TFTMACSealedReceiptReference + let nativeHost: TFTMACSealedReceiptReference +} + +struct TFTMACRuntimeModeSupplementalDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let stateNamespace: String + let usesLegacyApplicationSupportRoot: Bool + let emulatorIdentifier: String + let launchStrategy: TFTMACRuntimeLaunchStrategy + let profilePolicy: TFTMACRuntimeProfilePolicy + let lockedProfile: TFTMACRuntimeLockedProfile? + let adbSha256: String? + let adbVendorKeysPolicy: String + let expectedEmulatorVersionContains: String? + let emulatorUuids: [String]? + let qemuPath: String? + let qemuSha256: String? + let qemuUuids: [String]? + let gfxstreamBackendUuids: [String]? + let hostApplication: TFTMACRuntimeHostAuthority? + let diagnosticReceipts: TFTMACDiagnosticReceiptAuthority? +} + +struct TFTMACRuntimeModeAuthorityDocument: Codable, Equatable, Sendable { + let schema: Int + let contract: String + let selectionEnvironmentVariable: String + let modes: [String: TFTMACRuntimeModeSupplementalDefinition] +} + +struct TFTMACLoadedRuntimeIdentity: Equatable, Sendable { + let processIdentifier: Int32 + let qemuPath: String + let qemuSha256: String + let qemuUuids: [String] + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String + let gfxstreamBackendUuids: [String] +} + +struct TFTMACResolvedRuntimeModeAuthority: Sendable { + let supplemental: TFTMACRuntimeModeSupplementalDefinition + let hostApplication: URL + let applicationSupport: URL + let globalApplicationSupport: URL +} + +struct TFTMACSelectedRuntimeConfiguration: Sendable { + let registry: TFTMACRuntimeModeRegistry + let selection: TFTMACRuntimeSelection + let authority: TFTMACRuntimeModeAuthority + let profile: TFTMACRuntimeProfile + let applicationSupport: URL + + static func load( + savedProfile: TFTMACRuntimeProfile, + bundle: Bundle = .main, + environment: [String: String] = ProcessInfo.processInfo.environment + ) throws -> Self { + let registry = try TFTMACRuntimeModeRegistry.loadBundled(bundle: bundle) + let authority = try TFTMACRuntimeModeAuthority.loadBundled(bundle: bundle) + try authority.validateConsistency(with: registry) + let selection = try registry.selection(environment: environment) + let profile = try authority.effectiveProfile(savedProfile: savedProfile, selection: selection) + return Self( + registry: registry, + selection: selection, + authority: authority, + profile: profile, + applicationSupport: authority.applicationSupportURL(for: selection.mode) + ) + } +} + +struct TFTMACRuntimeModeAuthority: Sendable { + static let expectedContract = "TFTMAC_RUNTIME_MODES_V1" + + let document: TFTMACRuntimeModeAuthorityDocument + let registrySha256: String + + init(data: Data) throws { + let observed = Self.sha256Hex(data) + guard observed == TFTMACRuntimeModeRegistry.expectedRegistrySha256 else { + throw TFTMACRuntimeModeError( + message: "TFTMAC supplemental runtime authority rejected registry SHA-256 \(observed)." + ) + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeAuthorityDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC supplemental runtime authority could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = observed + try Self.validateStatic(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read supplemental runtime authority: \(error.localizedDescription)" + ) + } + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeSupplementalDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Supplemental runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + func validateConsistency(with registry: TFTMACRuntimeModeRegistry) throws { + guard registry.registrySha256 == registrySha256 else { + throw TFTMACRuntimeModeError(message: "Base and supplemental runtime authority hashes differ.") + } + for mode in TFTMACRuntimeMode.allCases { + let base = try registry.definition(for: mode) + let supplemental = try definition(for: mode) + guard base.mode == supplemental.mode else { + throw TFTMACRuntimeModeError(message: "Runtime mode authority mismatch for \(mode.rawValue).") + } + } + } + + func effectiveProfile( + savedProfile: TFTMACRuntimeProfile, + selection: TFTMACRuntimeSelection + ) throws -> TFTMACRuntimeProfile { + let supplemental = try definition(for: selection.mode) + guard let controllerPort = selection.definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted controller port." + ) + } + switch supplemental.profilePolicy { + case .validatedNativePreferences: + guard selection.mode == .control, savedProfile.controllerPort == controllerPort else { + throw TFTMACRuntimeModeError( + message: "Saved control profile does not match the accepted controller lease." + ) + } + return savedProfile + case .fixedRegistryProfile: + guard let locked = supplemental.lockedProfile else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) is missing its fixed profile." + ) + } + return TFTMACRuntimeProfile( + identifier: locked.identifier, + width: locked.width, + height: locked.height, + densityDPI: locked.densityDpi, + refreshHz: locked.refreshHz, + vCPU: locked.vcpu, + ramMiB: locked.ramMib, + gpuMode: locked.gpuMode, + audioBackend: locked.audioBackend, + graphicsTransport: locked.graphicsTransport, + asgWriteBufferSize: locked.asgWriteBufferSize, + asgWriteStepSize: locked.asgWriteStepSize, + asgDataRingSize: locked.asgDataRingSize, + asgDrawFlushInterval: locked.asgDrawFlushInterval, + controllerPort: controllerPort, + angleEnabledFeatures: locked.angleEnabledFeatures, + angleDisabledFeatures: locked.angleDisabledFeatures, + experimentPreset: .control + ) + case .blocked: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted profile." + ) + } + } + + func applicationSupportURL(for mode: TFTMACRuntimeMode) -> URL { + let global = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + guard let supplemental = try? definition(for: mode), !supplemental.usesLegacyApplicationSupportRoot else { + return global + } + return global + .appendingPathComponent("Modes", isDirectory: true) + .appendingPathComponent(supplemental.stateNamespace, isDirectory: true) + } + + func resolveForLaunch( + selection: TFTMACRuntimeSelection, + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws -> TFTMACResolvedRuntimeModeAuthority { + try selection.validateForLaunch(bundle: bundle, fileManager: fileManager) + let supplemental = try definition(for: selection.mode) + try validateModeEvidence( + base: selection.definition, + supplemental: supplemental, + bundle: bundle, + fileManager: fileManager + ) + let hostApplication = try resolveHostApplication( + supplemental: supplemental, + bundle: bundle, + fileManager: fileManager + ) + let global = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + return TFTMACResolvedRuntimeModeAuthority( + supplemental: supplemental, + hostApplication: hostApplication, + applicationSupport: applicationSupportURL(for: selection.mode), + globalApplicationSupport: global + ) + } + + func validateLoadedRuntime( + processIdentifier: Int32, + selection: TFTMACRuntimeSelection + ) throws -> TFTMACLoadedRuntimeIdentity { + let supplemental = try definition(for: selection.mode) + guard let qemuPath = supplemental.qemuPath, + let qemuSha256 = supplemental.qemuSha256, + let qemuUuids = supplemental.qemuUuids, + let gfxstreamSha256 = selection.definition.gfxstreamBackendSha256, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids, + let controllerPort = selection.definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) lacks loaded-runtime identity authority." + ) + } + let observedExecutable = try Self.processExecutablePath(processIdentifier) + guard Self.standardized(observedExecutable) == Self.standardized(qemuPath) else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator process path \(observedExecutable) does not match \(qemuPath)." + ) + } + try Self.validateSHA256(path: qemuPath, expected: qemuSha256, label: "loaded qemu") + try Self.validateUUIDs(path: qemuPath, expected: qemuUuids, label: "loaded qemu") + + let command = try Self.runCommand( + executable: "/bin/ps", + arguments: ["-p", "\(processIdentifier)", "-ww", "-o", "command="], + timeout: 10 + ) + guard command.status == 0, + command.output.contains("@\(selection.definition.avdName)"), + command.output.contains("-port \(selection.definition.consolePort)"), + command.output.contains("-grpc \(controllerPort)") else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator command line does not match the selected AVD and port lease." + ) + } + + let vmmap = try Self.runCommand( + executable: "/usr/bin/vmmap", + arguments: ["-w", "\(processIdentifier)"], + timeout: 30 + ) + guard vmmap.status == 0, + vmmap.output.contains(selection.definition.gfxstreamBackendPath) else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator did not prove the accepted gfxstream image mapping." + ) + } + try Self.validateSHA256( + path: selection.definition.gfxstreamBackendPath, + expected: gfxstreamSha256, + label: "loaded gfxstream backend" + ) + try Self.validateUUIDs( + path: selection.definition.gfxstreamBackendPath, + expected: gfxstreamUuids, + label: "loaded gfxstream backend" + ) + return TFTMACLoadedRuntimeIdentity( + processIdentifier: processIdentifier, + qemuPath: qemuPath, + qemuSha256: qemuSha256, + qemuUuids: qemuUuids, + gfxstreamBackendPath: selection.definition.gfxstreamBackendPath, + gfxstreamBackendSha256: gfxstreamSha256, + gfxstreamBackendUuids: gfxstreamUuids + ) + } + + private static func validateStatic(_ document: TFTMACRuntimeModeAuthorityDocument) throws { + guard document.schema == 1, + document.contract == expectedContract, + document.selectionEnvironmentVariable == TFTMACRuntimeModeRegistry.environmentKey else { + throw TFTMACRuntimeModeError(message: "Supplemental runtime-mode contract identity failed.") + } + let exactModes = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == exactModes else { + throw TFTMACRuntimeModeError( + message: "Supplemental authority must define exactly control, advanced_diagnostics, and candidate." + ) + } + var namespaces = Set() + for (key, definition) in document.modes { + guard key == definition.mode.rawValue, + !definition.stateNamespace.isEmpty, + namespaces.insert(definition.stateNamespace).inserted, + !definition.emulatorIdentifier.isEmpty, + !definition.adbVendorKeysPolicy.isEmpty else { + throw TFTMACRuntimeModeError( + message: "Supplemental runtime identity is invalid for \(key)." + ) + } + } + + guard let control = document.modes[TFTMACRuntimeMode.control.rawValue], + control.usesLegacyApplicationSupportRoot, + control.stateNamespace == "control", + control.launchStrategy == .bundledForwarder, + control.profilePolicy == .validatedNativePreferences, + control.lockedProfile == nil, + control.adbSha256.map(Self.isSHA256) == true, + control.emulatorUuids?.isEmpty == false, + control.qemuPath?.hasPrefix("/") == true, + control.qemuSha256.map(Self.isSHA256) == true, + control.qemuUuids?.isEmpty == false, + control.gfxstreamBackendUuids?.isEmpty == false, + control.hostApplication?.kind == .bundledResource, + control.hostApplication?.executableSha256 == nil, + control.hostApplication?.sourcePath == "RuntimeHost/main.c", + control.hostApplication?.sourceSha256.map(Self.isSHA256) == true, + control.hostApplication?.infoPlistPath == "RuntimeHost/Info.plist", + control.hostApplication?.infoPlistSha256.map(Self.isSHA256) == true, + control.hostApplication?.buildReceiptResource == "control-host-build.json", + control.diagnosticReceipts == nil else { + throw TFTMACRuntimeModeError(message: "Supplemental control authority is incomplete.") + } + + guard let diagnostics = document.modes[TFTMACRuntimeMode.advancedDiagnostics.rawValue], + !diagnostics.usesLegacyApplicationSupportRoot, + diagnostics.stateNamespace == "advanced_diagnostics", + diagnostics.launchStrategy == .externalNativeHost, + diagnostics.profilePolicy == .fixedRegistryProfile, + diagnostics.lockedProfile != nil, + diagnostics.adbSha256.map(Self.isSHA256) == true, + diagnostics.emulatorUuids?.isEmpty == false, + diagnostics.qemuPath?.hasPrefix("/") == true, + diagnostics.qemuSha256.map(Self.isSHA256) == true, + diagnostics.qemuUuids?.isEmpty == false, + diagnostics.gfxstreamBackendUuids?.isEmpty == false, + diagnostics.hostApplication?.kind == .externalApplication, + diagnostics.hostApplication?.executableSha256.map(Self.isSHA256) == true, + diagnostics.hostApplication?.sourcePath == nil, + diagnostics.hostApplication?.sourceSha256 == nil, + diagnostics.hostApplication?.infoPlistSha256.map(Self.isSHA256) == true, + diagnostics.hostApplication?.buildReceiptResource == nil, + let receipts = diagnostics.diagnosticReceipts, + receipts.buildId == "gate4-r9-20260901", + Self.isSHA256(receipts.runtimeConfigurationSha256), + receipts.build.requiredState == "DIAGNOSTIC_BUILD_IDENTITY_PASS", + receipts.clone.requiredState == "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS", + receipts.nativeHost.requiredState == "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS" else { + throw TFTMACRuntimeModeError(message: "Supplemental diagnostic authority is incomplete.") + } + + guard let candidate = document.modes[TFTMACRuntimeMode.candidate.rawValue], + !candidate.usesLegacyApplicationSupportRoot, + candidate.stateNamespace == "candidate", + candidate.launchStrategy == .blocked, + candidate.profilePolicy == .blocked, + candidate.lockedProfile == nil, + candidate.hostApplication == nil, + candidate.diagnosticReceipts == nil else { + throw TFTMACRuntimeModeError(message: "Supplemental candidate authority must remain blocked.") + } + } + + private func validateModeEvidence( + base: TFTMACRuntimeModeDefinition, + supplemental: TFTMACRuntimeModeSupplementalDefinition, + bundle: Bundle, + fileManager: FileManager + ) throws { + guard let adbSha256 = supplemental.adbSha256, + let emulatorUuids = supplemental.emulatorUuids, + let versionFragment = supplemental.expectedEmulatorVersionContains, + let qemuPath = supplemental.qemuPath, + let qemuSha256 = supplemental.qemuSha256, + let qemuUuids = supplemental.qemuUuids, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(base.mode.rawValue) lacks accepted binary identity evidence." + ) + } + try Self.validateSHA256(path: base.adbPath, expected: adbSha256, label: "ADB") + try Self.validateSHA256(path: qemuPath, expected: qemuSha256, label: "qemu") + try Self.validateUUIDs(path: qemuPath, expected: qemuUuids, label: "qemu") + try Self.validateUUIDs(path: base.emulatorPath, expected: emulatorUuids, label: "emulator") + try Self.validateUUIDs( + path: base.gfxstreamBackendPath, + expected: gfxstreamUuids, + label: "gfxstream backend" + ) + let version = try Self.runCommand( + executable: base.emulatorPath, + arguments: ["-version"], + timeout: 30 + ) + guard version.status == 0, version.output.contains(versionFragment) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(base.mode.rawValue) rejected emulator version identity." + ) + } + if base.mode == .advancedDiagnostics { + try validateDiagnosticReceipts(base: base, supplemental: supplemental) + } + } + + private func resolveHostApplication( + supplemental: TFTMACRuntimeModeSupplementalDefinition, + bundle: Bundle, + fileManager: FileManager + ) throws -> URL { + guard let host = supplemental.hostApplication else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) has no accepted native host." + ) + } + let appURL: URL + switch host.kind { + case .bundledResource: + guard let resources = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + appURL = resources.appendingPathComponent(host.path, isDirectory: true) + case .externalApplication: + appURL = URL(fileURLWithPath: host.path, isDirectory: true) + } + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: appURL.path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) is missing its native host at \(appURL.path)." + ) + } + let infoURL = appURL.appendingPathComponent("Contents/Info.plist") + guard let info = NSDictionary(contentsOf: infoURL), + info["CFBundleIdentifier"] as? String == host.bundleIdentifier else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) rejected native-host bundle identity." + ) + } + if let expectedInfoPlistSha256 = host.infoPlistSha256 { + try Self.validateSHA256( + path: infoURL.path, + expected: expectedInfoPlistSha256, + label: "native-host Info.plist" + ) + } + let executable = appURL.appendingPathComponent(host.executableRelativePath) + guard fileManager.isExecutableFile(atPath: executable.path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) native-host executable is missing." + ) + } + if let expectedExecutableSha256 = host.executableSha256 { + try Self.validateSHA256( + path: executable.path, + expected: expectedExecutableSha256, + label: "native-host executable" + ) + } else if host.buildReceiptResource == nil { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) has no native-host build receipt authority." + ) + } + if host.buildReceiptResource != nil { + try Self.validateControlHostBuildReceipt(host: host, appURL: appURL, bundle: bundle) + } + let codesign = try Self.runCommand( + executable: "/usr/bin/codesign", + arguments: ["--verify", "--deep", "--strict", appURL.path], + timeout: 30 + ) + guard codesign.status == 0 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) native-host signature is invalid." + ) + } + return appURL + } + + + private static func validateControlHostBuildReceipt( + host: TFTMACRuntimeHostAuthority, + appURL: URL, + bundle: Bundle + ) throws { + guard let receiptName = host.buildReceiptResource, + let sourcePath = host.sourcePath, + let sourceSha256 = host.sourceSha256, + let infoPlistPath = host.infoPlistPath, + let infoPlistSha256 = host.infoPlistSha256, + let resources = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "Control native-host build receipt authority is incomplete.") + } + let receiptURL = resources.appendingPathComponent(receiptName) + guard let data = try? Data(contentsOf: receiptURL), + let receipt = try? JSONSerialization.jsonObject(with: data) as? [String: Any], + string(receipt, ["state"]) == "CONTROL_NATIVE_HOST_BUILD_PASS", + string(receipt, ["host_application_relative_path"]) == host.path, + string(receipt, ["bundle_identifier"]) == host.bundleIdentifier, + string(receipt, ["source_path"]) == sourcePath, + string(receipt, ["source_sha256"]) == sourceSha256, + string(receipt, ["info_plist_path"]) == infoPlistPath, + string(receipt, ["info_plist_sha256"]) == infoPlistSha256, + string(receipt, ["executable_relative_path"]) == host.executableRelativePath, + let executableSha256 = string(receipt, ["executable_sha256"]), + let executableUuids = strings(receipt, ["executable_uuids"]), + strings(receipt, ["compile_arguments"]) == ["-Os", "-arch", "arm64", "-mmacosx-version-min=15.0"] else { + throw TFTMACRuntimeModeError(message: "Control native-host signed build receipt is missing or invalid.") + } + let executable = appURL.appendingPathComponent(host.executableRelativePath) + try validateSHA256(path: executable.path, expected: executableSha256, label: "control native-host executable") + try validateUUIDs(path: executable.path, expected: executableUuids, label: "control native-host executable") + } + + private func validateDiagnosticReceipts( + base: TFTMACRuntimeModeDefinition, + supplemental: TFTMACRuntimeModeSupplementalDefinition + ) throws { + guard let authority = supplemental.diagnosticReceipts, + let host = supplemental.hostApplication, + let emulatorUuids = supplemental.emulatorUuids, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids else { + throw TFTMACRuntimeModeError(message: "Diagnostic receipt authority is missing.") + } + let build = try Self.readSealedReceipt(authority.build) + guard Self.string(build, ["state"]) == authority.build.requiredState, + Self.string(build, ["build_id"]) == authority.buildId, + Self.bool(build, ["non_comparable_to_stock"]) == true, + Self.bool(build, ["control_runtime_touched"]) == false, + Self.bool(build, ["control_noninterference", "matched"]) == true, + Self.string(build, ["release_and_tracing", "runtime_configuration_sha256"]) == authority.runtimeConfigurationSha256, + Self.string(build, ["emulator", "path"]) == base.emulatorPath, + Self.string(build, ["emulator", "sha256"]) == base.emulatorSha256, + Self.strings(build, ["emulator", "uuids"]) == emulatorUuids, + Self.string(build, ["gfxstream_backend", "path"]) == base.gfxstreamBackendPath, + Self.string(build, ["gfxstream_backend", "sha256"]) == base.gfxstreamBackendSha256, + Self.strings(build, ["gfxstream_backend", "uuids"]) == gfxstreamUuids else { + throw TFTMACRuntimeModeError(message: "Diagnostic build receipt structure drifted.") + } + + let clone = try Self.readSealedReceipt(authority.clone) + guard Self.string(clone, ["state"]) == authority.clone.requiredState, + Self.string(clone, ["build_id"]) == authority.buildId, + Self.string(clone, ["diagnostic_avd", "name"]) == base.avdName, + Self.string(clone, ["diagnostic_avd", "root"]) == base.avdHome, + Self.string(clone, ["diagnostic_avd", "avd_path"]) == base.avdDirectory, + Self.string(clone, ["diagnostic_avd", "ini_path"]) == base.avdIniPath, + Self.string(clone, ["diagnostic_avd", "config_sha256"]) == base.avdConfigSha256, + Self.string(clone, ["diagnostic_avd", "ini_sha256"]) == base.avdIniSha256, + Self.int(clone, ["diagnostic_avd", "adb_server_port"]) == base.adbServerPort, + Self.int(clone, ["diagnostic_avd", "console_port"]) == base.consolePort, + Self.string(clone, ["diagnostic_avd", "serial"]) == base.serial, + Self.string(clone, ["accepted_build", "sha256"]) == authority.build.sha256, + Self.bool(clone, ["control_noninterference_matched"]) == true, + Self.bool(clone, ["sealed_before_first_boot"]) == true, + Self.bool(clone, ["first_boot_attempted"]) == false, + Self.bool(clone, ["launch_attempted"]) == false, + Self.bool(clone, ["control_runtime_mutation_attempted"]) == false, + Self.bool(clone, ["control_avd_touched"]) == false else { + throw TFTMACRuntimeModeError(message: "Diagnostic stopped-clone receipt structure drifted.") + } + + let nativeHost = try Self.readSealedReceipt(authority.nativeHost) + guard let expectedHostExecutableSha256 = host.executableSha256 else { + throw TFTMACRuntimeModeError(message: "Diagnostic native-host executable SHA-256 authority is missing.") + } + let expectedHostPath = host.path + let expectedExecutable = URL(fileURLWithPath: expectedHostPath, isDirectory: true) + .appendingPathComponent(host.executableRelativePath).path + guard Self.string(nativeHost, ["state"]) == authority.nativeHost.requiredState, + Self.string(nativeHost, ["build_id"]) == authority.buildId, + Self.string(nativeHost, ["app", "path"]) == expectedHostPath, + Self.string(nativeHost, ["app", "bundle_identifier"]) == host.bundleIdentifier, + Self.string(nativeHost, ["app", "executable", "path"]) == expectedExecutable, + Self.string(nativeHost, ["app", "executable", "sha256"]) == expectedHostExecutableSha256, + Self.int(nativeHost, ["app", "codesign_verify_status"]) == 0, + Self.string(nativeHost, ["launch_contract", "method"])?.contains("/usr/bin/open") == true, + Self.string(nativeHost, ["launch_contract", "emulator_spawn_owner"]) == "NATIVE_MACOS_APP_PROCESS", + Self.bool(nativeHost, ["launch_contract", "service_context_emulator_spawn_forbidden"]) == true, + Self.bool(nativeHost, ["control_runtime_mutation_attempted"]) == false else { + throw TFTMACRuntimeModeError(message: "Diagnostic native-host receipt structure drifted.") + } + } + + private static func readSealedReceipt(_ reference: TFTMACSealedReceiptReference) throws -> [String: Any] { + guard isSHA256(reference.sha256) else { + throw TFTMACRuntimeModeError(message: "Receipt authority contains an invalid SHA-256.") + } + try validateSHA256(path: reference.path, expected: reference.sha256, label: "sealed receipt") + let sidecarPath = "\(reference.path).sha256" + guard let sidecar = try? String(contentsOfFile: sidecarPath, encoding: .utf8), + sidecar.split(whereSeparator: \.isWhitespace).first.map(String.init) == reference.sha256 else { + throw TFTMACRuntimeModeError(message: "Sealed receipt sidecar is missing or mismatched: \(sidecarPath)") + } + let data = try Data(contentsOf: URL(fileURLWithPath: reference.path)) + guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { + throw TFTMACRuntimeModeError(message: "Sealed receipt is not a JSON object: \(reference.path)") + } + return object + } + + private static func value(_ object: [String: Any], _ path: [String]) -> Any? { + var current: Any = object + for component in path { + guard let dictionary = current as? [String: Any], let next = dictionary[component] else { return nil } + current = next + } + return current + } + + private static func string(_ object: [String: Any], _ path: [String]) -> String? { + value(object, path) as? String + } + + private static func strings(_ object: [String: Any], _ path: [String]) -> [String]? { + value(object, path) as? [String] + } + + private static func bool(_ object: [String: Any], _ path: [String]) -> Bool? { + value(object, path) as? Bool + } + + private static func int(_ object: [String: Any], _ path: [String]) -> Int? { + (value(object, path) as? NSNumber)?.intValue + } + + private static func validateSHA256(path: String, expected: String, label: String) throws { + guard isSHA256(expected) else { + throw TFTMACRuntimeModeError(message: "\(label) authority is not a SHA-256 value.") + } + let url = URL(fileURLWithPath: path) + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError(message: "Could not open \(label) at \(path): \(error.localizedDescription)") + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError(message: "Could not hash \(label): \(error.localizedDescription)") + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected else { + throw TFTMACRuntimeModeError( + message: "\(label) SHA-256 mismatch: expected \(expected), observed \(observed)." + ) + } + } + + private static func validateUUIDs(path: String, expected: [String], label: String) throws { + guard !expected.isEmpty else { + throw TFTMACRuntimeModeError(message: "\(label) has no accepted Mach-O UUID authority.") + } + let result = try runCommand( + executable: "/usr/bin/dwarfdump", + arguments: ["--uuid", path], + timeout: 30 + ) + guard result.status == 0 else { + throw TFTMACRuntimeModeError(message: "Could not inspect \(label) Mach-O UUIDs.") + } + for identity in expected { + let parts = identity.split(separator: ":", maxSplits: 1).map(String.init) + guard parts.count == 2, + result.output.localizedCaseInsensitiveContains(parts[0]), + result.output.contains("(\(parts[1]))") else { + throw TFTMACRuntimeModeError(message: "\(label) Mach-O UUID identity drifted.") + } + } + } + + private struct CommandResult { + let status: Int32 + let output: String + } + + private static func runCommand( + executable: String, + arguments: [String], + timeout: TimeInterval + ) throws -> CommandResult { + let manager = FileManager.default + let root = manager.temporaryDirectory.appendingPathComponent( + "tftmac-runtime-authority-\(UUID().uuidString)", + isDirectory: true + ) + try manager.createDirectory(at: root, withIntermediateDirectories: true, attributes: [.posixPermissions: 0o700]) + defer { try? manager.removeItem(at: root) } + let stdoutURL = root.appendingPathComponent("stdout") + let stderrURL = root.appendingPathComponent("stderr") + manager.createFile(atPath: stdoutURL.path, contents: nil, attributes: [.posixPermissions: 0o600]) + manager.createFile(atPath: stderrURL.path, contents: nil, attributes: [.posixPermissions: 0o600]) + let stdout = try FileHandle(forWritingTo: stdoutURL) + let stderr = try FileHandle(forWritingTo: stderrURL) + defer { + try? stdout.close() + try? stderr.close() + } + let process = Process() + process.executableURL = URL(fileURLWithPath: executable) + process.arguments = arguments + process.standardOutput = stdout + process.standardError = stderr + do { + try process.run() + } catch { + throw TFTMACRuntimeModeError( + message: "Could not execute \(executable): \(error.localizedDescription)" + ) + } + let deadline = Date().addingTimeInterval(timeout) + while process.isRunning && Date() < deadline { + Thread.sleep(forTimeInterval: 0.02) + } + if process.isRunning { + process.terminate() + Thread.sleep(forTimeInterval: 0.2) + if process.isRunning { Darwin.kill(process.processIdentifier, SIGKILL) } + } + process.waitUntilExit() + try stdout.synchronize() + try stderr.synchronize() + let out = (try? String(contentsOf: stdoutURL, encoding: .utf8)) ?? "" + let err = (try? String(contentsOf: stderrURL, encoding: .utf8)) ?? "" + return CommandResult(status: process.terminationStatus, output: out + err) + } + + private static func processExecutablePath(_ processIdentifier: Int32) throws -> String { + var buffer = [CChar](repeating: 0, count: 4096) + let count = buffer.withUnsafeMutableBufferPointer { + proc_pidpath(processIdentifier, $0.baseAddress, UInt32($0.count)) + } + guard count > 0 else { + throw TFTMACRuntimeModeError( + message: "Could not resolve loaded emulator process path for PID \(processIdentifier)." + ) + } + return String(cString: buffer) + } + + private static func standardized(_ path: String) -> String { + URL(fileURLWithPath: path).standardizedFileURL.resolvingSymlinksInPath().path + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/apply-waveb-v3.mjs b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/apply-waveb-v3.mjs new file mode 100644 index 0000000..3ecfbd1 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/apply-waveb-v3.mjs @@ -0,0 +1,1294 @@ +#!/usr/bin/env node +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { execFileSync } from 'node:child_process'; + +const root = process.cwd(); +const changeId = '215ec5a3-6554-4ca3-95db-1525433bb20f'; +const expectedHead = '310404da3ca3edaa63b6ebdecb2acc8d52fb59ba'; +const planRoot = '.clara/plans/tftmac-causal-graphics-v1'; +const waveRoot = `${planRoot}/wave-b-v3`; +const expected = { + [`${planRoot}/IMPLEMENTATION_PLAN.md`]: '78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b', + [`${planRoot}/SCOPE_LOCK.txt`]: 'dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e', + [`${waveRoot}/CONTINUATION_AMENDMENT.md`]: 'df9d3a537d94d4f32337c2658168714925c1f3206775964069ea135a27cbdc4a', + [`${waveRoot}/PREFLIGHT.json`]: 'bec3a488d3386966cb3f98cdf1b5f35a083519d1dfb873260db4d63576b19247', + [`${waveRoot}/ZENGATE_RECEIPT.json`]: '6d460880102823285456668f98dde26d54a11b0e3e20f8270d699947ae2b7003', + [`${planRoot}/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template`]: 'cb8e62545832e457e12046bed5eb8dcd72a17feb090ce3dad3e15b6cfad7f60f', + [`${planRoot}/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template`]: 'f3b4db12f4e8c085343d87813ab026ff6045ec679cb8afea48dd87bf8f04c0f9', + [`${waveRoot}/RuntimeModeAuthority.swift.template`]: '3ab10d59a94ef4e60e920290a940a55a624a0209a7fe6e05abe65fdfaf040c59', + [`${waveRoot}/validate-waveb-v3.mjs`]: '23fe5b2e93622c73ba349f8327ab0dc80f94a4d10857bb7af53ea20e320e9a61', + 'ssot/runtime-modes.json': '81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2', + 'ssot/runtime-authority.json': '2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f', + 'tftmac/App/AppCoordinator.swift': 'd0eb27df9a0e6aaa45ff60c63fd81bc229350a6f8feca833b776bbe4a954bda4', + 'tftmac/Runtime/RuntimeLease.swift': '55a44dbd5fc8b112cb48d17e879c00ae068161f2755af1876244e03bf75b498b', + 'tftmac/Runtime/RuntimeProfile.swift': '93b5ac436f4f1f315b343151cacc304d76337ac39c996df7dee38ffa48909bae', + 'tftmac/Runtime/TFTMACRuntime.swift': '8932032d93af01b46e46b5fb5a04eff1ec457f2f0e8f92f364d5a1a703ab5a5f', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift': '3a3302778bda256a9e2977cf2de51827867f211b97f5bf9f74e41389ecd0b7fb', + 'TFTMAC.xcodeproj/project.pbxproj': '4961d37cc1802ca179b7f115ff4be3a4f1c222e706a01aff9f137fcb27c57dfd', + 'scripts/build-native-app.command': '9bedc13dab3f395a75e8b74fccbeaff92209ddd48b1a83e368768196fd96ae0f', + 'scripts/verify-tftmac.command': 'd58721d6c06cd321052b150184b970f46b5977afe50c2ef6470ed4999dd5a84d', + 'RuntimeHost/main.c': 'c749cd998a6f066e2f7a6ef818eecf05b90d1a8808f6c9966e0b5fc21affeeed', + 'RuntimeHost/Info.plist': 'cab05fb3b54fb76c9b1b85e9f6a66aebcc5b91bed98c757b603db89e2b7939ca' +}; +const identities = { + control: { + adb: '1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b', + emulator: 'b3b8fc0dcedcf6e15b54b41f3e5156319029aa00b88a59fd489f80abdd8fc133', + emulatorUUIDs: ['4C4C449E-5555-3144-A182-644CCB895091:arm64'], + qemu: 'eaa97a970b81f81640db73ed79e19ee173323653a0a1203217e1199d078011f3', + qemuUUIDs: ['4C4C4467-5555-3144-A10A-A9E5A99446F1:arm64'], + gfxstream: '3772fef215058831ea419c9281fd203d010003d5defdc195dd120bc7748e4093', + gfxstreamUUIDs: ['4C4C4406-5555-3144-A122-8AC522465662:arm64'] + }, + diagnostic: { + adb: '1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b', + emulator: 'fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa', + emulatorUUIDs: ['4C4C4436-5555-3144-A1EE-05B0F446F580:arm64'], + qemu: '042c4932b17fd09ff056ecc2dd21084e08e1110b774c594bbcaf1e4d1ceac608', + qemuUUIDs: ['4C4C447F-5555-3144-A16C-0DB6C4482B7A:arm64'], + gfxstream: '23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d', + gfxstreamUUIDs: ['4C4C4449-5555-3144-A1FC-F6DFE0021481:arm64'] + } +}; + +function fail(message) { console.error(`WAVE_B_V3_APPLY_FAILED: ${message}`); process.exit(1); } +function ensure(value, message) { if (!value) fail(message); } +function absolute(relativePath) { return path.join(root, relativePath); } +function sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function fileSha(relativePath) { return sha256(fs.readFileSync(absolute(relativePath))); } +function externalSha(filePath) { return sha256(fs.readFileSync(filePath)); } +function git(...args) { return execFileSync('/usr/bin/git', args, { cwd: root, encoding: 'utf8' }); } +function readText(relativePath) { return fs.readFileSync(absolute(relativePath), 'utf8'); } +function replaceOnce(text, before, after, label) { + const count = text.split(before).length - 1; + ensure(count === 1, `${label}: expected one anchor, found ${count}`); + return text.replace(before, after); +} +function replaceSection(text, startMarker, endMarker, replacement, label) { + const start = text.indexOf(startMarker); + const end = text.indexOf(endMarker, start + startMarker.length); + ensure(start >= 0 && end > start, `${label}: section anchors were not found`); + ensure(text.indexOf(startMarker, start + 1) < 0, `${label}: start anchor is not unique`); + return text.slice(0, start) + replacement + text.slice(end); +} +function writeAtomic(relativePath, content, mode = 0o644) { + const destination = absolute(relativePath); + fs.mkdirSync(path.dirname(destination), { recursive: true }); + const temporary = `${destination}.waveb-v3-${process.pid}`; + fs.writeFileSync(temporary, content, { mode }); + fs.renameSync(temporary, destination); + fs.chmodSync(destination, mode); +} +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], ['launch_state', mode.launch_state], ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], ['library_root', mode.library_root], ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 ?? ''], ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 ?? ''], ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], ['avd_name', mode.avd_name], ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], ['avd_config_sha256', mode.avd_config_sha256 ?? ''], + ['avd_ini_path', mode.avd_ini_path], ['avd_ini_sha256', mode.avd_ini_sha256 ?? ''], + ['adb_server_port', mode.adb_server_port], ['console_port', mode.console_port], + ['controller_port', mode.controller_port ?? ''], ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 ?? ''], ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha256(Buffer.from(fields.map(([key, value]) => `${key}=${value}`).join('\n'))); +} + +ensure(git('rev-parse', 'HEAD').trim() === expectedHead, 'managed change HEAD drifted'); +ensure(git('status', '--porcelain=v1', '--untracked-files=no').trim() === '', 'tracked worktree changed before guarded apply'); +for (const [relativePath, expectedSha] of Object.entries(expected)) { + ensure(fs.existsSync(absolute(relativePath)), `required input is missing: ${relativePath}`); + ensure(fileSha(relativePath) === expectedSha, `input SHA-256 drifted: ${relativePath}`); +} +for (const [filePath, expectedSha] of [ + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb', identities.control.adb], + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator', identities.control.emulator], + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64', identities.control.qemu], + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64/libgfxstream_backend.dylib', identities.control.gfxstream], + ['/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator', identities.diagnostic.emulator], + ['/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64', identities.diagnostic.qemu], + ['/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib', identities.diagnostic.gfxstream] +]) ensure(externalSha(filePath) === expectedSha, `external binary identity drifted: ${filePath}`); + +const registry = JSON.parse(readText('ssot/runtime-modes.json')); +registry.contract = 'TFTMAC_RUNTIME_MODES_V1'; +registry.selection_environment_variable = 'TFTMAC_RUNTIME_MODE'; +const control = registry.modes.control; +Object.assign(control, { + emulator_sha256: identities.control.emulator, + gfxstream_backend_sha256: identities.control.gfxstream, + state_namespace: 'control', + uses_legacy_application_support_root: true, + emulator_identifier: 'TFTMAC', + launch_strategy: 'bundled_forwarder', + profile_policy: 'validated_native_preferences', + locked_profile: null, + adb_sha256: identities.control.adb, + adb_vendor_keys_policy: 'ABSENT', + expected_emulator_version_contains: '37.1.11', + emulator_uuids: identities.control.emulatorUUIDs, + qemu_path: '/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64', + qemu_sha256: identities.control.qemu, + qemu_uuids: identities.control.qemuUUIDs, + gfxstream_backend_uuids: identities.control.gfxstreamUUIDs, + host_application: { + kind: 'bundled_resource', + path: 'TFTMAC Emulator Host.app', + bundle_identifier: 'com.flashls1.tftmac.emulator-host', + executable_relative_path: 'Contents/MacOS/TFTMACEmulatorHost', + executable_sha256: null, + source_path: 'RuntimeHost/main.c', + source_sha256: expected['RuntimeHost/main.c'], + info_plist_path: 'RuntimeHost/Info.plist', + info_plist_sha256: expected['RuntimeHost/Info.plist'], + build_receipt_resource: 'control-host-build.json' + }, + diagnostic_receipts: null +}); +control.configuration_sha256 = configurationHash(control); + +const diagnostic = registry.modes.advanced_diagnostics; +Object.assign(diagnostic, { + state_namespace: 'advanced_diagnostics', + uses_legacy_application_support_root: false, + emulator_identifier: 'TFTMAC-DIAGNOSTIC', + launch_strategy: 'external_native_host', + profile_policy: 'fixed_registry_profile', + locked_profile: { + identifier: 'tftmac_diagnostic_r9', width: 1920, height: 1080, density_dpi: 280, refresh_hz: 60, + vcpu: 6, ram_mib: 6144, gpu_mode: 'host', audio_backend: 'coreaudio', graphics_transport: 'pipe', + asg_write_buffer_size: 1048576, asg_write_step_size: 4096, asg_data_ring_size: 32768, + asg_draw_flush_interval: 800, + angle_enabled_features: 'exposeNonConformantExtensionsAndVersions:exposeES32ForTesting', + angle_disabled_features: 'preferSubmitAtFBOBoundary' + }, + adb_sha256: identities.diagnostic.adb, + adb_vendor_keys_policy: 'USER_DEFAULT_KEY', + expected_emulator_version_contains: '35.6.3', + emulator_uuids: identities.diagnostic.emulatorUUIDs, + qemu_path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64', + qemu_sha256: identities.diagnostic.qemu, + qemu_uuids: identities.diagnostic.qemuUUIDs, + gfxstream_backend_uuids: identities.diagnostic.gfxstreamUUIDs, + host_application: { + kind: 'external_application', + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/TFTMAC Diagnostic Host.app', + bundle_identifier: 'com.flashls1.tftmac.runtime.diagnostics', + executable_relative_path: 'Contents/MacOS/TFTMACApp', + executable_sha256: 'd335a23d710956f96a4c01f977d49437424c9fd52ccc20ed872e5786d206eef2', + source_path: null, + source_sha256: null, + info_plist_path: null, + info_plist_sha256: '4e15592461ce8a50f17ccd6285fd12fcd84dd407eba86919f90c8c0026b5ca61', + build_receipt_resource: null + }, + diagnostic_receipts: { + build_id: 'gate4-r9-20260901', + runtime_configuration_sha256: '005c85a2a7ffe86e7626c871fd3dd23f42c5d3ce994162d17b032e69cfc4d4f3', + build: { + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json', + sha256: '9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d', + required_state: 'DIAGNOSTIC_BUILD_IDENTITY_PASS' + }, + clone: { + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json', + sha256: '09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648', + required_state: 'DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS' + }, + native_host: { + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json', + sha256: 'a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067', + required_state: 'DIAGNOSTIC_NATIVE_HOST_BUILD_PASS' + } + } +}); +diagnostic.configuration_sha256 = configurationHash(diagnostic); + +const candidate = registry.modes.candidate; +Object.assign(candidate, { + state_namespace: 'candidate', + uses_legacy_application_support_root: false, + emulator_identifier: 'TFTMAC-CANDIDATE', + launch_strategy: 'blocked', + profile_policy: 'blocked', + locked_profile: null, + adb_sha256: null, + adb_vendor_keys_policy: 'UNRESOLVED', + expected_emulator_version_contains: null, + emulator_uuids: null, + qemu_path: '/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64', + qemu_sha256: null, + qemu_uuids: null, + gfxstream_backend_uuids: null, + host_application: null, + diagnostic_receipts: null +}); +candidate.configuration_sha256 = configurationHash(candidate); + +const portOwners = new Map(); +for (const [modeName, mode] of Object.entries(registry.modes)) { + ensure(mode.serial === `emulator-${mode.console_port}`, `${modeName} serial/console mismatch`); + for (const [kind, value] of [['adb', mode.adb_server_port], ['console', mode.console_port], ['controller', mode.controller_port]]) { + if (value === null) continue; + ensure(!portOwners.has(value), `port collision: ${value}`); + portOwners.set(value, `${modeName}.${kind}`); + } +} +ensure(diagnostic.launch_state === 'blocked_pending_controller_lease' && diagnostic.controller_port === null, 'diagnostics must remain blocked'); +ensure(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate must remain blocked'); +const registryText = `${JSON.stringify(registry, null, 2)}\n`; +const registrySha = sha256(Buffer.from(registryText)); + +const modeTemplate = readText(`${planRoot}/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeMode.swift.template`); +ensure(modeTemplate.includes('__EXPECTED_RUNTIME_MODES_SHA256__'), 'runtime mode template placeholder is missing'); +const runtimeModeSource = modeTemplate.replace('__EXPECTED_RUNTIME_MODES_SHA256__', registrySha); +const runtimeModeAuthoritySource = readText(`${waveRoot}/RuntimeModeAuthority.swift.template`); +const runtimeLeaseSource = readText(`${planRoot}/protected-local-work/unaccepted-waveb-draft-before-v3/wave-b-v2/RuntimeLease.swift.template`); + +const pathsBlock = `struct TFTMACRuntimePaths: Sendable { + let mode: TFTMACRuntimeMode + let registrySha256: String + let configurationSha256: String + let runtimeRoot: URL + let sdkRoot: URL + let libraryRoot: URL + let emulator: URL + let qemu: URL + let gfxstreamBackend: URL + let adb: URL + let avdHome: URL + let avdName: String + let avdDirectory: URL + let avdConfig: URL + let avdINI: URL + let hostApplication: URL + let applicationSupport: URL + let globalApplicationSupport: URL + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + let emulatorIdentifier: String + let launchStrategy: TFTMACRuntimeLaunchStrategy + let adbVendorKeysPolicy: String + + static func discover( + configuration: TFTMACSelectedRuntimeConfiguration, + bundle: Bundle = .main + ) throws -> Self { + let selection = configuration.selection + let definition = selection.definition + let resolved = try configuration.authority.resolveForLaunch( + selection: selection, + bundle: bundle + ) + guard let controllerPort = definition.controllerPort, + let qemuPath = resolved.supplemental.qemuPath else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \\(selection.mode.rawValue) has no accepted launch lease." + ) + } + return Self( + mode: selection.mode, + registrySha256: selection.registrySha256, + configurationSha256: definition.configurationSha256, + runtimeRoot: URL(fileURLWithPath: definition.runtimeRoot, isDirectory: true), + sdkRoot: URL(fileURLWithPath: definition.sdkRoot, isDirectory: true), + libraryRoot: URL(fileURLWithPath: definition.libraryRoot, isDirectory: true), + emulator: URL(fileURLWithPath: definition.emulatorPath), + qemu: URL(fileURLWithPath: qemuPath), + gfxstreamBackend: URL(fileURLWithPath: definition.gfxstreamBackendPath), + adb: URL(fileURLWithPath: definition.adbPath), + avdHome: URL(fileURLWithPath: definition.avdHome, isDirectory: true), + avdName: definition.avdName, + avdDirectory: URL(fileURLWithPath: definition.avdDirectory, isDirectory: true), + avdConfig: URL(fileURLWithPath: definition.avdConfigPath), + avdINI: URL(fileURLWithPath: definition.avdIniPath), + hostApplication: resolved.hostApplication, + applicationSupport: resolved.applicationSupport, + globalApplicationSupport: resolved.globalApplicationSupport, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial, + emulatorIdentifier: resolved.supplemental.emulatorIdentifier, + launchStrategy: resolved.supplemental.launchStrategy, + adbVendorKeysPolicy: resolved.supplemental.adbVendorKeysPolicy + ) + } +} + +`; + +let runtime = readText('tftmac/Runtime/TFTMACRuntime.swift'); +runtime = replaceSection(runtime, 'struct TFTMACRuntimePaths: Sendable {', 'struct EmulatorControllerDiscovery: Sendable {', pathsBlock, 'runtime paths'); +runtime = replaceOnce(runtime, ` private let profile: TFTMACRuntimeProfile + private let mailbox: LatestFrameMailbox +`, ` private let runtimeConfiguration: TFTMACSelectedRuntimeConfiguration + private let profile: TFTMACRuntimeProfile + private let mailbox: LatestFrameMailbox +`, 'runtime configuration field'); +runtime = replaceOnce(runtime, ` init( + profile: TFTMACRuntimeProfile, + mailbox: LatestFrameMailbox, + status: @escaping StatusHandler, + gameFrame: @escaping GameFrameHandler + ) { + self.profile = profile + self.mailbox = mailbox + self.status = status + self.gameFrame = gameFrame + } +`, ` init( + runtimeConfiguration: TFTMACSelectedRuntimeConfiguration, + mailbox: LatestFrameMailbox, + status: @escaping StatusHandler, + gameFrame: @escaping GameFrameHandler + ) { + self.runtimeConfiguration = runtimeConfiguration + self.profile = runtimeConfiguration.profile + self.mailbox = mailbox + self.status = status + self.gameFrame = gameFrame + } +`, 'runtime service initializer'); + +const runFunction = ` func run() async throws { + await status("Validating the selected TFTMAC runtime identity…", false) + do { + let paths = try TFTMACRuntimePaths.discover(configuration: runtimeConfiguration) + self.paths = paths + let telemetry = try TFTMACNativeTelemetry( + profile: profile, + applicationSupport: paths.applicationSupport + ) + self.telemetry = telemetry + labStore = try CombatBenchmarkLabStore(applicationSupport: paths.applicationSupport) + await status("Starting Android through the native Mac app host…", false) + + let leaseIdentity = try runtimeConfiguration.selection.leaseIdentity() + let globalStateRoot = paths.globalApplicationSupport + .appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire( + stateRoot: globalStateRoot, + identity: leaseIdentity + ) + telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ + "lease": runtimeConfiguration.registry.document.activeLeaseRelativePath, + "pid": ProcessInfo.processInfo.processIdentifier, + "exclusive": true, + "mode": paths.mode.rawValue, + "registry_sha256": paths.registrySha256, + "configuration_sha256": paths.configurationSha256, + "avd": paths.avdName, + "adb_server_port": paths.adbServerPort, + "console_port": paths.consolePort, + "controller_port": paths.controllerPort, + "serial": paths.serial + ]) + try assertRuntimeUnoccupied(paths: paths, telemetry: telemetry) + try recoverInterruptedAVDTransaction(paths: paths) + recordFrozenReceipts(telemetry: telemetry, paths: paths) + avdTransaction = try prepareAVD(paths: paths, telemetry: telemetry) + try startADBServer(paths: paths, telemetry: telemetry) + let launchStarted = Date() + try launchEmulatorHost(paths: paths, telemetry: telemetry) + let discovery = try await waitForDiscovery( + paths: paths, + captureDirectory: telemetry.captureDirectory, + after: launchStarted + ) + guard discovery.port == paths.controllerPort else { + throw TFTMACRuntimeError( + "The emulator published controller port \\(discovery.port), not the accepted port \\(paths.controllerPort)." + ) + } + self.discovery = discovery + telemetry.recordEvent("EMULATOR_CONTROLLER_DISCOVERED", payload: [ + "pid": discovery.processIdentifier, + "grpc_port": discovery.port, + "record": discovery.recordPath, + "token_persisted": false, + "mode": paths.mode.rawValue + ]) + let loadedIdentity = try runtimeConfiguration.authority.validateLoadedRuntime( + processIdentifier: discovery.processIdentifier, + selection: runtimeConfiguration.selection + ) + telemetry.recordEvent("LOADED_RUNTIME_IDENTITY_PASS", payload: [ + "pid": loadedIdentity.processIdentifier, + "mode": paths.mode.rawValue, + "qemu_path": loadedIdentity.qemuPath, + "qemu_sha256": loadedIdentity.qemuSha256, + "qemu_uuids": loadedIdentity.qemuUuids, + "gfxstream_backend_path": loadedIdentity.gfxstreamBackendPath, + "gfxstream_backend_sha256": loadedIdentity.gfxstreamBackendSha256, + "gfxstream_backend_uuids": loadedIdentity.gfxstreamBackendUuids + ]) + try recordHostSchedulingReceipt(telemetry: telemetry) + + let (inputStream, continuation) = AsyncStream.makeStream( + of: EmulatorInput.self, + bufferingPolicy: .bufferingNewest(256) + ) + inputContinuation = continuation + try await withThrowingTaskGroup(of: Void.self) { group in + group.addTask { [profile, mailbox] in + try await Self.runController( + discovery: discovery, + profile: profile, + mailbox: mailbox, + telemetry: telemetry, + inputStream: inputStream, + status: self.status + ) + } + group.addTask { + try await self.waitForBootAndLaunchGame(paths: paths, telemetry: telemetry) + } + group.addTask { + try await self.sampleRuntime( + paths: paths, + telemetry: telemetry, + emulatorPID: discovery.processIdentifier + ) + } + group.addTask { + try await self.sampleGameFrames(paths: paths, telemetry: telemetry) + } + _ = try await group.next() + group.cancelAll() + } + if !stopping { throw TFTMACRuntimeError("The native emulator session ended unexpectedly.") } + } catch { + if stopping || error is CancellationError { + telemetry?.recordEvent("RUNTIME_STOP_REQUESTED", payload: ["reason": "application_termination"]) + await cleanup(status: "STOPPED") + return + } + telemetry?.recordEvent("RUNTIME_FAILED", payload: [ + "error": error.localizedDescription, + "diagnostic": String(describing: error), + "type": String(reflecting: type(of: error)), + "mode": runtimeConfiguration.selection.mode.rawValue + ]) + if profile.experimentPreset.isActiveCandidate { + recordCorrectnessRejection(reason: error.localizedDescription) + TFTMACRuntimeProfile.playable.with(experimentPreset: .control).save() + telemetry?.recordEvent("EXPERIMENT_AUTO_ROLLBACK", payload: [ + "failed_preset": profile.experimentPreset.rawValue, + "restored_preset": RuntimeExperimentPreset.control.rawValue, + "classification": "REJECTED_CORRECTNESS", + "applies_after_restart": true + ]) + } + await cleanup(status: stopping ? "STOPPED" : "FAILED") + if !stopping { await status(error.localizedDescription, true) } + throw error + } + await cleanup(status: "STOPPED") + } + +`; +runtime = replaceSection(runtime, ' func run() async throws {', ' func sendMouse(_ input: MouseInput) {', runFunction, 'runtime run'); + +runtime = replaceOnce(runtime, +` Self.processMatchesLaunchedIdentity(ownedPID, sessionMarker: expectedSessionMarker) {`, +` Self.processMatchesLaunchedIdentity(ownedPID, paths: paths, sessionMarker: expectedSessionMarker) {`, +'stop ownership check'); +runtime = replaceOnce(runtime, ` "serial": "emulator-5582",`, ` "serial": paths.serial,`, 'stop serial'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "emu", "kill"],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "emu", "kill"],`, +'stop adb identity'); +runtime = replaceOnce(runtime, +` let ownedPID = discovery?.processIdentifier ?? expectedSessionMarker.flatMap(Self.findOwnedEmulatorPID)`, +` let ownedPID = discovery?.processIdentifier ?? expectedSessionMarker.flatMap { marker in + Self.findOwnedEmulatorPID(sessionMarker: marker, paths: paths) + }`, +'cleanup owner lookup'); +runtime = replaceOnce(runtime, +` ownedProcessExists && Self.processMatchesLaunchedIdentity($0, sessionMarker: expectedSessionMarker)`, +` ownedProcessExists && Self.processMatchesLaunchedIdentity( + $0, + paths: paths, + sessionMarker: expectedSessionMarker + )`, +'cleanup ownership verification'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "emu", "kill"],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "emu", "kill"],`, +'cleanup adb identity'); +runtime = replaceOnce(runtime, +` payload: ["pid": ownedPID ?? 0, "serial": "emulator-5582", "owned": ownsRunningEmulator]`, +` payload: ["pid": ownedPID ?? 0, "serial": paths.serial, "owned": ownsRunningEmulator]`, +'cleanup telemetry identity'); +runtime = replaceOnce(runtime, +` guard !Self.anyEmulatorUsingSharedAVD() else { + throw TFTMACRuntimeError("AVD restore was withheld because another TFT_Ultra_Tablet process is active.") + }`, +` guard !Self.anyEmulatorUsingSelectedAVD(paths: paths) else { + throw TFTMACRuntimeError( + "AVD restore was withheld because another \\(paths.avdName) process is active." + ) + }`, +'cleanup selected AVD'); + +runtime = replaceOnce(runtime, +` process.arguments = ["-P", "5038", "-s", "emulator-5582", "logcat", "-v", "threadtime", "-T", sessionStartSelector]`, +` process.arguments = [ + "-P", "\\(paths.adbServerPort)", "-s", paths.serial, + "logcat", "-v", "threadtime", "-T", sessionStartSelector + ]`, +'logcat identity'); + +const occupancyFunction = ` private func assertRuntimeUnoccupied( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + var definitions = [runtimeConfiguration.selection.definition] + if runtimeConfiguration.selection.definition.requiresControlStopped { + let control = try runtimeConfiguration.registry.definition(for: .control) + if control.mode != runtimeConfiguration.selection.mode { definitions.append(control) } + } + let processOutput = (try? Self.runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-axo", "pid=,command="], + timeout: 10 + ).output) ?? "" + let emulatorConflicts = processOutput.split(whereSeparator: \\.isNewline).filter { line in + guard line.contains("qemu-system-aarch64") else { return false } + return definitions.contains { definition in + line.contains("@\\(definition.avdName)") + || line.contains("-port \\(definition.consolePort)") + || definition.controllerPort.map { line.contains("-grpc \\($0)") } == true + } + } + let leasedPorts = Set(definitions.flatMap { definition -> [Int] in + [definition.consolePort] + definition.controllerPort.map { [$0] } ?? [] + }).sorted() + var listenerArguments = ["-nP"] + for port in leasedPorts { listenerArguments.append("-iTCP:\\(port)") } + listenerArguments.append("-sTCP:LISTEN") + let listenerOutput = (try? Self.runCommand( + URL(fileURLWithPath: "/usr/sbin/lsof"), + listenerArguments, + timeout: 10 + ).output) ?? "" + let listeners = listenerOutput.split(whereSeparator: \\.isNewline).dropFirst() + guard emulatorConflicts.isEmpty && listeners.isEmpty else { + let modes = definitions.map(\\.mode.rawValue).joined(separator: ", ") + throw TFTMACRuntimeError( + "The selected runtime lease conflicts with an active \\(modes) emulator or port listener." + ) + } + let checkedIdentities: [[String: Any]] = definitions.map { definition in + [ + "mode": definition.mode.rawValue, + "avd": definition.avdName, + "console_port": definition.consolePort, + "controller_port": definition.controllerPort ?? 0, + "serial": definition.serial + ] + } + telemetry.recordEvent("RUNTIME_OWNERSHIP_PREFLIGHT_PASSED", payload: [ + "selected_mode": paths.mode.rawValue, + "checked_identities": checkedIdentities, + "existing_emulator_count": 0, + "existing_listener_count": 0 + ]) + } + +`; +runtime = replaceSection(runtime, ' private func assertRuntimeUnoccupied(telemetry: TFTMACNativeTelemetry) throws {', ' private func recordFrozenReceipts', occupancyFunction, 'runtime occupancy'); + +const receiptsFunction = ` private func recordFrozenReceipts( + telemetry: TFTMACNativeTelemetry, + paths: TFTMACRuntimePaths + ) { + let experimentReceipt = profile.experimentConfigurationReceipt + let receipts: [(String, String, String, String)] = [ + ("engine", "Unreal Engine", "user_locked_fact", "LOCKED"), + ("runtime_mode", paths.mode.rawValue, "sealed runtime-mode registry", "DIRECT"), + ("runtime_mode_registry_sha256", paths.registrySha256, "bundled signed registry", "DIRECT"), + ("runtime_mode_configuration_sha256", paths.configurationSha256, "sealed runtime-mode registry", "DIRECT"), + ("runtime_profile_id", profile.identifier, "validated mode profile", "DIRECT"), + ("runtime_experiment_preset", profile.experimentPreset.rawValue, "named launch experiment", "DIRECT"), + ("runtime_configuration_sha256", experimentReceipt.sha256, "canonical effective configuration", "DIRECT"), + ("runtime_configuration_json", experimentReceipt.canonicalJSON, "canonical effective configuration", "DIRECT"), + ("launcher_method", paths.launchStrategy.rawValue, "runtime-mode authority", "DIRECT"), + ("native_host_application", paths.hostApplication.path, "signed host authority", "DIRECT"), + ("macos_game_mode_eligible", "true", "LSSupportsGameMode bundle contract", "DIRECT"), + ("host_qos_requested", profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default", "named launch experiment", "REQUESTED"), + ("adb_server_port", "\\(paths.adbServerPort)", "runtime-mode lease", "DIRECT"), + ("emulator_console_port", "\\(paths.consolePort)", "runtime-mode lease", "DIRECT"), + ("adb_serial", paths.serial, "runtime-mode lease", "DIRECT"), + ("controller_port", "\\(paths.controllerPort)", "runtime-mode lease", "DIRECT"), + ("adb_vendor_keys", paths.adbVendorKeysPolicy, "runtime-mode authority", "DIRECT"), + ("avd", paths.avdName, "runtime-mode authority", "DIRECT"), + ("runtime_root", paths.runtimeRoot.path, "runtime-mode authority", "DIRECT"), + ("mode_application_support", paths.applicationSupport.path, "runtime-mode state isolation", "DIRECT"), + ("resolution", "\\(profile.width)x\\(profile.height)", "validated mode profile", "DIRECT"), + ("density_dpi", "\\(profile.densityDPI)", "validated mode profile", "DIRECT"), + ("refresh_hz", "\\(profile.refreshHz)", "validated mode profile", "DIRECT"), + ("vcpu", "\\(profile.vCPU)", "validated mode profile", "DIRECT"), + ("ram_mib", "\\(profile.ramMiB)", "validated mode profile", "DIRECT"), + ("gpu_mode", profile.gpuMode, "validated mode profile", "DIRECT"), + ("audio_backend", profile.audioBackend, "validated mode profile", "DIRECT"), + ("graphics_transport_requested", profile.graphicsTransport, "validated mode profile", "REQUESTED"), + ("emulator_features_requested", profile.effectiveEmulatorFeatures.joined(separator: ","), "named launch experiment", "REQUESTED"), + ("asg_write_buffer_size", "\\(profile.asgWriteBufferSize)", "validated mode profile", "REQUESTED"), + ("asg_write_step_size", "\\(profile.asgWriteStepSize)", "validated mode profile", "REQUESTED"), + ("asg_data_ring_size", "\\(profile.asgDataRingSize)", "validated mode profile", "REQUESTED"), + ("asg_draw_flush_interval_us", "\\(profile.asgDrawFlushInterval)", "validated mode profile", "REQUESTED"), + ("angle_enabled_requested", profile.angleEnabledFeatures, "validated mode profile", "REQUESTED"), + ("angle_disabled_requested", profile.angleDisabledFeatures, "validated mode profile", "REQUESTED"), + ("frame_transport", "raw_grpc_rgba8888", "native admission path", "DIRECT"), + ("raw_logcat_policy", "LOCAL_SENSITIVE_SESSION_SCOPED_NOT_FOR_SHARING", "privacy contract", "LOCKED"), + ("sdk_root", paths.sdkRoot.path, "runtime-mode authority", "DIRECT") + ] + for receipt in receipts { + telemetry.recordReceipt(key: receipt.0, value: receipt.1, source: receipt.2, confidence: receipt.3) + } + } + +`; +runtime = replaceSection(runtime, ' private func recordFrozenReceipts', ' private func startADBServer', receiptsFunction, 'frozen receipts'); + +const adbServerFunction = ` private func startADBServer( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + let result = try Self.runCommand( + paths.adb, + ["-P", "\\(paths.adbServerPort)", "start-server"], + environment: Self.adbEnvironment(paths: paths), + timeout: 30 + ) + guard result.status == 0 else { + throw TFTMACRuntimeError( + "ADB server \\(paths.adbServerPort) could not start: \\(result.output.suffix(1200))" + ) + } + telemetry.recordEvent("ADB_SERVER_STARTED", payload: [ + "port": paths.adbServerPort, + "serial": paths.serial, + "adb_vendor_keys_policy": paths.adbVendorKeysPolicy, + "output": result.output.suffix(2000).description + ]) + } + +`; +runtime = replaceSection(runtime, ' private func startADBServer', ' private func launchEmulatorHost', adbServerFunction, 'ADB server'); + +const launchFunction = ` private func launchEmulatorHost( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + guard paths.launchStrategy == .bundledForwarder else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \\(paths.mode.rawValue) requires its separately receipted native-host acceptance operation." + ) + } + let stdout = telemetry.captureDirectory.appendingPathComponent("emulator.stdout.log") + let stderr = telemetry.captureDirectory.appendingPathComponent("emulator.stderr.log") + FileManager.default.createFile(atPath: stdout.path, contents: nil) + FileManager.default.createFile(atPath: stderr.path, contents: nil) + for root in Self.controllerDiscoveryRoots(paths: paths) { + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + } + expectedSessionMarker = "androidboot.tftmac.session=\\(telemetry.sessionIdentifier)" + var arguments = [ + "-n", "-W", + "--env", "TFT_EMULATOR=\\(paths.emulator.path)", + "--env", "TFT_ADB_SERVER_PORT=\\(paths.adbServerPort)", + "--env", "ANDROID_ADB_SERVER_PORT=\\(paths.adbServerPort)", + "--env", "ADB_MDNS_AUTO_CONNECT=", + "--env", "ADB_SERVER_SOCKET=", + "--env", "ANDROID_ADB_SERVER_ADDRESS=", + "--env", "ANDROID_SDK_ROOT=\\(paths.sdkRoot.path)", + "--env", "ANDROID_AVD_HOME=\\(paths.avdHome.path)", + "--env", "ANDROID_EMULATOR_USE_SYSTEM_LIBS=0", + "--env", "ANGLE_FEATURE_OVERRIDES_ENABLED=\\(profile.angleEnabledFeatures)", + "--env", "ANGLE_FEATURE_OVERRIDES_DISABLED=\\(profile.angleDisabledFeatures)", + "--env", "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0", + "--env", "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE=64", + "--env", "MVK_CONFIG_FAST_MATH_ENABLED=1", + "--env", "TFT_HOST_LATENCY_QOS=\\(profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default")", + "--env", "TFT_HOST_STDOUT=\\(stdout.path)", + "--env", "TFT_HOST_STDERR=\\(stderr.path)", + paths.hostApplication.path, + "--args", + "@\\(paths.avdName)", "-id", paths.emulatorIdentifier, "-port", "\\(paths.consolePort)", + "-gpu", profile.gpuMode, "-audio", profile.audioBackend, + "-feature", profile.effectiveEmulatorFeatures.joined(separator: ","), + "-append-userspace-opt", "androidboot.opengles.version=196610", + "-append-userspace-opt", "androidboot.tftmac.graphics_profile=tftmac", + "-append-userspace-opt", expectedSessionMarker!, + "-skin", "\\(profile.width)x\\(profile.height)", + "-vsync-rate", "\\(profile.refreshHz)", + "-dns-server", "1.1.1.1,8.8.8.8", + "-cores", "\\(profile.vCPU)", "-memory", "\\(profile.ramMiB)", + "-no-hidpi-scaling", "-no-snapshot", "-no-metrics", "-no-boot-anim", + "-crash-report-mode", "disabled", "-qt-hide-window", + "-grpc", "\\(paths.controllerPort)", "-grpc-use-token", + "-idle-grpc-timeout", "300" + ] + if let zone = TimeZone.current.identifier.addingPercentEncoding(withAllowedCharacters: .alphanumerics), !zone.isEmpty { + arguments += ["-timezone", TimeZone.current.identifier] + } + let process = Process() + process.executableURL = URL(fileURLWithPath: "/usr/bin/open") + process.arguments = arguments + var environment = ProcessInfo.processInfo.environment + environment.removeValue(forKey: "ADB_VENDOR_KEYS") + process.environment = environment + try process.run() + openProcess = process + telemetry.recordEvent("EMULATOR_HOST_LAUNCHED", payload: [ + "method": "/usr/bin/open", + "flags": ["-n", "-W", "--env", "--args"], + "mode": paths.mode.rawValue, + "host_application": paths.hostApplication.path, + "open_pid": process.processIdentifier, + "adb_vendor_keys_policy": paths.adbVendorKeysPolicy, + "game_mode_eligible": true, + "host_qos_requested": profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default", + "controller_discovery_roots": Self.controllerDiscoveryRoots(paths: paths).map(\\.path), + "emulator_arguments": Array(arguments.suffix(from: arguments.firstIndex(of: "--args") ?? arguments.startIndex).dropFirst()) + ]) + } + +`; +runtime = replaceSection(runtime, ' private func launchEmulatorHost', ' private func recordHostSchedulingReceipt', launchFunction, 'emulator host launch'); + +runtime = replaceOnce(runtime, +` guard let pid = Int32(pidText), Self.processMatchesLaunchedIdentity(pid, sessionMarker: expectedSessionMarker) else { continue }`, +` guard let pid = Int32(pidText), + Self.processMatchesLaunchedIdentity( + pid, + paths: paths, + sessionMarker: expectedSessionMarker + ) else { continue }`, +'discovery process identity'); +runtime = replaceOnce(runtime, ` await status("Waiting for the proven ADB identity on emulator-5582…", false)`, ` await status("Waiting for the proven ADB identity on \\(paths.serial)…", false)`, 'ADB wait status'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "get-state"],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "get-state"],`, +'ADB state identity'); +runtime = replaceOnce(runtime, ` "serial": "emulator-5582",`, ` "serial": paths.serial,`, 'ADB state serial'); +runtime = replaceOnce(runtime, ` "serial": "emulator-5582",`, ` "serial": paths.serial,`, 'ADB unauthorized serial'); +runtime = replaceOnce(runtime, ` await status("Waiting for emulator-5582 to appear on ADB 5038…", false)`, ` await status("Waiting for \\(paths.serial) to appear on ADB \\(paths.adbServerPort)…", false)`, 'ADB missing status'); +runtime = replaceOnce(runtime, ` throw TFTMACRuntimeError("ADB emulator-5582 did not authorize in the logged-in Mac session (last state: \\(lastState)).")`, ` throw TFTMACRuntimeError("ADB \\(paths.serial) did not authorize in the logged-in Mac session (last state: \\(lastState)).")`, 'ADB authorization error'); +runtime = replaceOnce(runtime, ` telemetry.recordEvent("ADB_DEVICE_AUTHORIZED", payload: ["port": 5038, "serial": "emulator-5582"])`, ` telemetry.recordEvent("ADB_DEVICE_AUTHORIZED", payload: ["port": paths.adbServerPort, "serial": paths.serial])`, 'ADB authorized event'); +runtime = replaceOnce(runtime, ` "resolution": "1920x1080",`, ` "resolution": "\\(profile.width)x\\(profile.height)",`, 'TFT resolution receipt'); +runtime = replaceOnce(runtime, ` "audio_backend": "coreaudio",`, ` "audio_backend": profile.audioBackend,`, 'TFT audio receipt'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "shell", "perfetto", "--txt", "-c", "-", "-o", remotePath],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "shell", "perfetto", "--txt", "-c", "-", "-o", remotePath],`, +'Perfetto ADB identity'); + +const adbEnvironmentFunction = ` nonisolated private static func adbEnvironment( + paths: TFTMACRuntimePaths + ) -> [String: String] { + var environment = ProcessInfo.processInfo.environment + environment.removeValue(forKey: "ADB_VENDOR_KEYS") + environment.removeValue(forKey: "ADB_SERVER_SOCKET") + environment.removeValue(forKey: "ANDROID_ADB_SERVER_ADDRESS") + environment["ANDROID_SDK_ROOT"] = paths.sdkRoot.path + environment["ANDROID_AVD_HOME"] = paths.avdHome.path + environment["ANDROID_ADB_SERVER_PORT"] = "\\(paths.adbServerPort)" + environment["ADB_MDNS_AUTO_CONNECT"] = "" + return environment + } + +`; +runtime = replaceSection(runtime, ' nonisolated private static func adbEnvironment', ' nonisolated private static func adb(paths:', adbEnvironmentFunction, 'ADB environment'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582"] + arguments,`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial] + arguments,`, +'ADB helper identity'); +runtime = replaceOnce(runtime, +` "-P", "5038", "-s", "emulator-5582", "shell", "pidof",`, +` "-P", "\\(paths.adbServerPort)", "-s", paths.serial, "shell", "pidof",`, +'TFT process identity'); + +const processHelpers = ` nonisolated private static func processMatchesLaunchedIdentity( + _ processIdentifier: Int32, + paths: TFTMACRuntimePaths, + sessionMarker: String? = nil + ) -> Bool { + guard processExists(processIdentifier), + let result = try? runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-p", "\\(processIdentifier)", "-ww", "-o", "command="], + timeout: 5 + ), result.status == 0 else { return false } + let baseIdentityMatches = result.output.contains(paths.qemu.lastPathComponent) + && result.output.contains("@\\(paths.avdName)") + && result.output.contains("-port \\(paths.consolePort)") + && result.output.contains("-grpc \\(paths.controllerPort)") + return baseIdentityMatches && (sessionMarker.map(result.output.contains) ?? true) + } + + nonisolated private static func findOwnedEmulatorPID( + sessionMarker: String, + paths: TFTMACRuntimePaths + ) -> Int32? { + guard let result = try? runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-axo", "pid=,command="], + timeout: 10 + ), result.status == 0 else { return nil } + for line in result.output.split(whereSeparator: \\.isNewline) { + guard line.contains(paths.qemu.lastPathComponent), + line.contains("@\\(paths.avdName)"), + line.contains("-port \\(paths.consolePort)"), + line.contains("-grpc \\(paths.controllerPort)"), + line.contains(sessionMarker), + let pid = line.split(whereSeparator: \\.isWhitespace).first.flatMap({ Int32($0) }) else { continue } + return pid + } + return nil + } + + nonisolated private static func anyEmulatorUsingSelectedAVD( + paths: TFTMACRuntimePaths + ) -> Bool { + guard let result = try? runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-axo", "command="], + timeout: 10 + ), result.status == 0 else { return true } + return result.output.split(whereSeparator: \\.isNewline).contains { line in + line.contains(paths.qemu.lastPathComponent) + && line.contains("@\\(paths.avdName)") + && line.contains("-port \\(paths.consolePort)") + } + } + +`; +runtime = replaceSection(runtime, ' nonisolated private static func processMatchesLaunchedIdentity(', ' nonisolated private static func processExists', processHelpers, 'process identity helpers'); + +const controllerHeader = `@MainActor +final class TFTMACRuntimeController { + private let service: TFTMACRuntimeService + private var runTask: Task? + private(set) var failed = false + + init( + runtimeConfiguration: TFTMACSelectedRuntimeConfiguration, + mailbox: LatestFrameMailbox, + status: @escaping TFTMACRuntimeService.StatusHandler, + gameFrame: @escaping TFTMACRuntimeService.GameFrameHandler + ) { + service = TFTMACRuntimeService( + runtimeConfiguration: runtimeConfiguration, + mailbox: mailbox, + status: status, + gameFrame: gameFrame + ) + } + +`; +runtime = replaceSection(runtime, '@MainActor\nfinal class TFTMACRuntimeController {', ' func start() {', controllerHeader, 'runtime controller initializer'); +for (const forbidden of ['["-P", "5038"', '"emulator-5582"', '"@TFT_Ultra_Tablet"', '"-iTCP:5582"', '"-iTCP:8554"']) { + ensure(!runtime.includes(forbidden), `runtime still hard-codes control identity: ${forbidden}`); +} + +let coordinator = readText('tftmac/App/AppCoordinator.swift'); +coordinator = replaceOnce(coordinator, +` private var activeProfile: TFTMACRuntimeProfile = .playable + private var terminationInProgress = false +`, +` private var activeProfile: TFTMACRuntimeProfile = .playable + private var activeApplicationSupport = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + private var terminationInProgress = false +`, +'coordinator state root'); +const launchCoordinator = ` func applicationDidFinishLaunching(_ notification: Notification) { + let controller = MainWindowController(mailbox: mailbox) + mainWindowController = controller + controller.showWindow(nil) + controller.window?.makeFirstResponder(controller.emulatorView) + NSApp.activate(ignoringOtherApps: true) + + do { + let savedProfile = TFTMACRuntimeProfile.load() + let runtimeConfiguration = try TFTMACSelectedRuntimeConfiguration.load( + savedProfile: savedProfile + ) + activeProfile = runtimeConfiguration.profile + activeApplicationSupport = runtimeConfiguration.applicationSupport + let runtime = TFTMACRuntimeController( + runtimeConfiguration: runtimeConfiguration, + mailbox: mailbox, + status: { [weak controller] text, isError in + controller?.emulatorView.setStatus(text, isError: isError) + }, + gameFrame: { [weak controller] window in + controller?.emulatorView.setGameFrameWindow(window) + } + ) + runtimeController = runtime + controller.emulatorView.onTouchInput = { [weak runtime] input in + runtime?.sendTouch(input) + } + controller.emulatorView.onMouseInput = { [weak runtime] x, y, buttons in + runtime?.sendMouse(x: x, y: y, buttons: buttons) + } + controller.emulatorView.onKeyboardInput = { [weak runtime] text, key in + runtime?.sendKeyboard(text: text, key: key) + } + controller.emulatorView.onPresentationSample = { [weak runtime] sample in + runtime?.recordPresentation(sample) + } + controller.emulatorView.onHostPresentationWindow = { [weak runtime] sample in + runtime?.recordHostPresentation(sample) + } + runtime.start() + } catch { + controller.emulatorView.setStatus(error.localizedDescription, isError: true) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak controller] in + controller?.enterNativeFullscreen() + } + } + +`; +coordinator = replaceSection(coordinator, ' func applicationDidFinishLaunching(_ notification: Notification) {', ' @objc func showSettings', launchCoordinator, 'AppCoordinator launch'); +coordinator = replaceOnce(coordinator, +` let captures = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC/Captures", isDirectory: true)`, +` let captures = activeApplicationSupport + .appendingPathComponent("Captures", isDirectory: true)`, +'mode-specific capture reveal'); + +let tests = readText('Tests/TFTMACTests/TFTMACGate1Tests.swift'); +const addedTests = ` + private func runtimeModeRegistryData() throws -> Data { + let repositoryRoot = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + return try Data(contentsOf: repositoryRoot.appendingPathComponent("ssot/runtime-modes.json")) + } + + func testRuntimeModeRegistryDefinesExactControlIdentity() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + XCTAssertEqual(Set(registry.document.modes.keys), Set(TFTMACRuntimeMode.allCases.map(\\.rawValue))) + XCTAssertEqual(registry.document.defaultMode, .control) + let selection = try registry.selection(environment: [:]) + XCTAssertEqual(selection.mode, .control) + XCTAssertEqual(selection.definition.avdName, "TFT_Ultra_Tablet") + XCTAssertEqual(selection.definition.adbServerPort, 5038) + XCTAssertEqual(selection.definition.consolePort, 5582) + XCTAssertEqual(selection.definition.controllerPort, 8554) + XCTAssertEqual(selection.definition.serial, "emulator-5582") + } + + func testRuntimeModeRegistryFailsClosedForUnacceptedModes() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + for requested in ["advanced_diagnostics", "candidate", "unknown"] { + XCTAssertThrowsError(try registry.selection(environment: [ + TFTMACRuntimeModeRegistry.environmentKey: requested + ]), requested) + } + } + + func testRuntimeModeRegistryRejectsTamperedBytes() throws { + var data = try runtimeModeRegistryData() + data.append(Data(" ".utf8)) + XCTAssertThrowsError(try TFTMACRuntimeModeRegistry(data: data)) + XCTAssertThrowsError(try TFTMACRuntimeModeAuthority(data: data)) + } + + func testSupplementalRuntimeAuthoritySeparatesStateAndLaunchStrategies() throws { + let data = try runtimeModeRegistryData() + let registry = try TFTMACRuntimeModeRegistry(data: data) + let authority = try TFTMACRuntimeModeAuthority(data: data) + XCTAssertNoThrow(try authority.validateConsistency(with: registry)) + let control = try authority.definition(for: .control) + let diagnostics = try authority.definition(for: .advancedDiagnostics) + let candidate = try authority.definition(for: .candidate) + XCTAssertEqual(control.launchStrategy, .bundledForwarder) + XCTAssertEqual(diagnostics.launchStrategy, .externalNativeHost) + XCTAssertEqual(candidate.launchStrategy, .blocked) + XCTAssertNotEqual(control.stateNamespace, diagnostics.stateNamespace) + XCTAssertNotEqual(diagnostics.stateNamespace, candidate.stateNamespace) + XCTAssertNotNil(diagnostics.diagnosticReceipts) + XCTAssertNil(candidate.hostApplication) + XCTAssertNotEqual( + authority.applicationSupportURL(for: .control), + authority.applicationSupportURL(for: .advancedDiagnostics) + ) + } + + func testControlModePreservesValidatedNativeProfile() throws { + let data = try runtimeModeRegistryData() + let registry = try TFTMACRuntimeModeRegistry(data: data) + let authority = try TFTMACRuntimeModeAuthority(data: data) + let selection = try registry.selection(environment: [:]) + let effective = try authority.effectiveProfile(savedProfile: .playable, selection: selection) + XCTAssertEqual(effective, .playable) + XCTAssertEqual(effective.controllerPort, selection.definition.controllerPort) + } + + func testRuntimeLeasePersistsExactModeIdentityAndRejectsSecondOwner() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + let selection = try registry.selection(environment: [:]) + let identity = try selection.leaseIdentity() + let stateRoot = FileManager.default.temporaryDirectory + .appendingPathComponent("tftmac-mode-lease-test-\\(UUID().uuidString)", isDirectory: true) + defer { try? FileManager.default.removeItem(at: stateRoot) } + let first = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: identity) + defer { first.release() } + let leaseURL = stateRoot.appendingPathComponent("native-runtime.lease") + let object = try XCTUnwrap( + try JSONSerialization.jsonObject(with: Data(contentsOf: leaseURL)) as? [String: Any] + ) + XCTAssertEqual((object["schema"] as? NSNumber)?.intValue, 2) + XCTAssertEqual(object["mode"] as? String, "control") + XCTAssertEqual(object["registry_sha256"] as? String, registry.registrySha256) + XCTAssertEqual(object["configuration_sha256"] as? String, selection.definition.configurationSha256) + XCTAssertEqual(object["avd_name"] as? String, "TFT_Ultra_Tablet") + XCTAssertEqual((object["adb_server_port"] as? NSNumber)?.intValue, 5038) + XCTAssertEqual((object["console_port"] as? NSNumber)?.intValue, 5582) + XCTAssertEqual((object["controller_port"] as? NSNumber)?.intValue, 8554) + XCTAssertEqual(object["serial"] as? String, "emulator-5582") + XCTAssertThrowsError(try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: identity)) + } +`; +ensure(tests.endsWith('}\n'), 'test class closing brace changed'); +tests = `${tests.slice(0, -2)}${addedTests}}\n`; + +let project = readText('TFTMAC.xcodeproj/project.pbxproj'); +project = replaceOnce(project, '/* End PBXBuildFile section */', `\t\t100000000000000000000038 /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000023 /* RuntimeMode.swift */; }; +\t\t100000000000000000000039 /* RuntimeMode.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000023 /* RuntimeMode.swift */; }; +\t\t10000000000000000000003A /* runtime-modes.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000024 /* runtime-modes.json */; }; +\t\t10000000000000000000003B /* RuntimeModeAuthority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; +\t\t10000000000000000000003C /* RuntimeModeAuthority.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; +\t\t10000000000000000000003D /* runtime-authority.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000026 /* runtime-authority.json */; }; +/* End PBXBuildFile section */`, 'PBX build files'); +project = replaceOnce(project, '/* End PBXFileReference section */', `\t\t200000000000000000000023 /* RuntimeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeMode.swift; sourceTree = ""; }; +\t\t200000000000000000000024 /* runtime-modes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-modes.json; sourceTree = SOURCE_ROOT; }; +\t\t200000000000000000000025 /* RuntimeModeAuthority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeModeAuthority.swift; sourceTree = ""; }; +\t\t200000000000000000000026 /* runtime-authority.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-authority.json; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */`, 'PBX file references'); +project = replaceOnce(project, +`\t\t\t\t400000000000000000000007 /* Tests */, +\t\t\t\t400000000000000000000009 /* Products */,`, +`\t\t\t\t400000000000000000000007 /* Tests */, +\t\t\t\t200000000000000000000024 /* runtime-modes.json */, +\t\t\t\t200000000000000000000026 /* runtime-authority.json */, +\t\t\t\t400000000000000000000009 /* Products */,`, +'PBX root resources'); +project = replaceOnce(project, +`\t\t40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000019 /* RuntimeLease.swift */,`, +`\t\t40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000023 /* RuntimeMode.swift */, 200000000000000000000025 /* RuntimeModeAuthority.swift */, 200000000000000000000019 /* RuntimeLease.swift */,`, +'PBX runtime group'); +project = replaceOnce(project, +`\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };`, +`\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (10000000000000000000003A /* runtime-modes.json in Resources */, 10000000000000000000003D /* runtime-authority.json in Resources */,); runOnlyForDeploymentPostprocessing = 0; };`, +'PBX resources phase'); +project = replaceOnce(project, +`100000000000000000000025, 100000000000000000000028,`, +`100000000000000000000025, 100000000000000000000038, 10000000000000000000003B, 100000000000000000000028,`, +'PBX app sources'); +project = replaceOnce(project, +`100000000000000000000026, 100000000000000000000029,`, +`100000000000000000000026, 100000000000000000000039, 10000000000000000000003C, 100000000000000000000029,`, +'PBX test sources'); + +let buildScript = readText('scripts/build-native-app.command'); +buildScript = replaceOnce(buildScript, +`/usr/bin/codesign --force --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${HOST_APP}" + +/usr/bin/codesign --force --deep --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${DIST}" +/usr/bin/codesign --verify --deep --strict --verbose=2 "\${DIST}"`, +`/usr/bin/codesign --force --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${HOST_APP}" + +# Seal the non-reproducible signed Mach-O identity into a receipt that is then +# protected by the outer application signature. Source and Info.plist hashes +# remain fixed in the runtime-mode registry; the signed receipt binds those +# inputs to the exact packaged host executable and UUID. +/usr/bin/python3 - "\${ROOT}" "\${DIST}" "\${HOST_APP}" <<'PY' +import datetime +import hashlib +import json +import pathlib +import plistlib +import re +import subprocess +import sys + +root = pathlib.Path(sys.argv[1]) +dist = pathlib.Path(sys.argv[2]) +host = pathlib.Path(sys.argv[3]) +source = root / "RuntimeHost/main.c" +info_source = root / "RuntimeHost/Info.plist" +info_packaged = host / "Contents/Info.plist" +executable = host / "Contents/MacOS/TFTMACEmulatorHost" + +def sha256(path): + h = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + +uuid_output = subprocess.check_output(["/usr/bin/dwarfdump", "--uuid", str(executable)], text=True) +uuids = [f"{match.group(1)}:{match.group(2)}" for match in re.finditer(r"UUID: ([0-9A-F-]+) \\(([^)]+)\\)", uuid_output)] +if not uuids: + raise SystemExit("Control native host has no Mach-O UUID receipt") +with info_packaged.open("rb") as handle: + bundle_identifier = plistlib.load(handle)["CFBundleIdentifier"] +compiler = subprocess.check_output(["/usr/bin/xcrun", "--find", "clang"], text=True).strip() +compiler_version = subprocess.check_output([compiler, "--version"], text=True).splitlines()[0] +receipt = { + "schema": 1, + "state": "CONTROL_NATIVE_HOST_BUILD_PASS", + "generated_at_utc": datetime.datetime.now(datetime.timezone.utc).isoformat(), + "host_application_relative_path": "TFTMAC Emulator Host.app", + "bundle_identifier": bundle_identifier, + "source_path": "RuntimeHost/main.c", + "source_sha256": sha256(source), + "info_plist_path": "RuntimeHost/Info.plist", + "info_plist_sha256": sha256(info_source), + "packaged_info_plist_sha256": sha256(info_packaged), + "executable_relative_path": "Contents/MacOS/TFTMACEmulatorHost", + "executable_sha256": sha256(executable), + "executable_uuids": uuids, + "compiler_path": compiler, + "compiler_version": compiler_version, + "compile_arguments": ["-Os", "-arch", "arm64", "-mmacosx-version-min=15.0"], + "signed_before_receipt": True, + "outer_app_seals_receipt": True +} +receipt_path = dist / "Contents/Resources/control-host-build.json" +receipt_path.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\\n") +PY + +# The nested host is already signed. Sign the outer app without deep-resigning +# it, so the exact executable hash in the newly written receipt stays true. +/usr/bin/codesign --force --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${DIST}" +/usr/bin/codesign --verify --deep --strict --verbose=2 "\${DIST}" +/usr/bin/python3 - "\${DIST}" "\${HOST_APP}" <<'PY' +import hashlib +import json +import pathlib +import sys + +dist = pathlib.Path(sys.argv[1]) +host = pathlib.Path(sys.argv[2]) +receipt = json.loads((dist / "Contents/Resources/control-host-build.json").read_text()) +executable = host / receipt["executable_relative_path"] +h = hashlib.sha256(executable.read_bytes()).hexdigest() +if h != receipt["executable_sha256"]: + raise SystemExit("Outer signing changed the receipted control-host executable") +PY`, +'control host signed receipt'); + +let verifier = readText('scripts/verify-tftmac.command'); +verifier = replaceOnce(verifier, +` ssot/runtime-authority.json \\ + ssot/retained-evidence-index.json \\`, +` ssot/runtime-authority.json \\ + ssot/runtime-modes.json \\ + tftmac/Runtime/RuntimeMode.swift \\ + tftmac/Runtime/RuntimeModeAuthority.swift \\ + ${waveRoot}/validate-waveb-v3.mjs \\ + ssot/retained-evidence-index.json \\`, +'verifier required files'); +verifier = replaceOnce(verifier, +`[[ "$TEST_FUNCTION_COUNT" == "43" ]] || fail "native test inventory drifted: expected 43, found $TEST_FUNCTION_COUNT"`, +`[[ "$TEST_FUNCTION_COUNT" == "49" ]] || fail "native test inventory drifted: expected 49, found $TEST_FUNCTION_COUNT"`, +'test count'); +verifier = replaceOnce(verifier, +`node --check tools/tftmac-direct-control.mjs >/dev/null`, +`node --check tools/tftmac-direct-control.mjs >/dev/null +node --check ${waveRoot}/validate-waveb-v3.mjs >/dev/null`, +'validator syntax'); +verifier = replaceOnce(verifier, +`[[ -x "\${RELEASE_DERIVED}/Build/Products/Release/TFTMAC.app/Contents/MacOS/TFTMAC" ]] \\ + || fail "unsigned Release build did not produce the TFTMAC executable" + +/bin/zsh scripts/test-native-app.command`, +`readonly RELEASE_APP="\${RELEASE_DERIVED}/Build/Products/Release/TFTMAC.app" +[[ -x "\${RELEASE_APP}/Contents/MacOS/TFTMAC" ]] \\ + || fail "unsigned Release build did not produce the TFTMAC executable" +cmp -s ssot/runtime-modes.json "\${RELEASE_APP}/Contents/Resources/runtime-modes.json" \\ + || fail "unsigned Release app did not package the exact runtime-mode registry" +cmp -s ssot/runtime-authority.json "\${RELEASE_APP}/Contents/Resources/runtime-authority.json" \\ + || fail "unsigned Release app did not package the exact control authority" +node ${waveRoot}/validate-waveb-v3.mjs >/dev/null + +/bin/zsh scripts/test-native-app.command`, +'verifier build resources'); +verifier = replaceOnce(verifier, +`print "TFTMAC source validation: OK (unsigned Release build; 43 native tests)"`, +`print "TFTMAC source validation: OK (unsigned Release build; 49 native tests; Wave B mode authority PASS)"`, +'verifier final output'); + +const receipt = { + schema: 1, + state: 'WAVE_B_V3_IMPLEMENTATION_APPLIED', + project_id: 'tftmac', + change_id: changeId, + operation_id: process.env.CLARA_OPERATION_ID ?? null, + applied_at: new Date().toISOString(), + base_head_sha: expectedHead, + original_plan_sha256: expected[`${planRoot}/IMPLEMENTATION_PLAN.md`], + scope_lock_sha256: expected[`${planRoot}/SCOPE_LOCK.txt`], + continuation_amendment_sha256: expected[`${waveRoot}/CONTINUATION_AMENDMENT.md`], + runtime_modes_sha256: registrySha, + expected_test_count: 49, + modified_paths: [ + 'ssot/runtime-modes.json', + 'tftmac/App/AppCoordinator.swift', + 'tftmac/Runtime/RuntimeMode.swift', + 'tftmac/Runtime/RuntimeModeAuthority.swift', + 'tftmac/Runtime/RuntimeLease.swift', + 'tftmac/Runtime/TFTMACRuntime.swift', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift', + 'TFTMAC.xcodeproj/project.pbxproj', + 'scripts/build-native-app.command', + 'scripts/verify-tftmac.command' + ], + effects: { + source_only: true, + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + installed_app_replacement_attempted: false, + package_launch_attempted: false + }, + next_safe_action: 'Run the single changed-head production source verifier and correct only a proven failure.' +}; + +const outputs = { + 'ssot/runtime-modes.json': registryText, + 'tftmac/App/AppCoordinator.swift': coordinator, + 'tftmac/Runtime/RuntimeMode.swift': runtimeModeSource, + 'tftmac/Runtime/RuntimeModeAuthority.swift': runtimeModeAuthoritySource, + 'tftmac/Runtime/RuntimeLease.swift': runtimeLeaseSource, + 'tftmac/Runtime/TFTMACRuntime.swift': runtime, + 'Tests/TFTMACTests/TFTMACGate1Tests.swift': tests, + 'TFTMAC.xcodeproj/project.pbxproj': project, + 'scripts/build-native-app.command': buildScript, + 'scripts/verify-tftmac.command': verifier, + [`${waveRoot}/IMPLEMENTATION_RECEIPT.json`]: `${JSON.stringify(receipt, null, 2)}\n` +}; +for (const [relativePath, content] of Object.entries(outputs)) { + writeAtomic(relativePath, content, relativePath.endsWith('.command') || relativePath.endsWith('.mjs') ? 0o755 : 0o644); +} +console.log(JSON.stringify(receipt, null, 2)); diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/validate-waveb-v3.mjs b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/validate-waveb-v3.mjs new file mode 100644 index 0000000..d680b14 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v3/validate-waveb-v3.mjs @@ -0,0 +1,278 @@ +#!/usr/bin/env node +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; + +const root = process.cwd(); +const planRoot = '.clara/plans/tftmac-causal-graphics-v1'; +const waveRoot = `${planRoot}/wave-b-v3`; +const expectedPlanSha = '78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b'; +const expectedScopeSha = 'dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e'; +const expectedBuildSha = '9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d'; +const expectedCloneSha = '09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648'; +const expectedHostSha = 'a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067'; + +function absolute(relativePath) { return path.join(root, relativePath); } +function fail(message) { throw new Error(`WAVE_B_V3_VALIDATION_FAILED: ${message}`); } +function assert(value, message) { if (!value) fail(message); } +function sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function read(relativePath) { return fs.readFileSync(absolute(relativePath)); } +function readText(relativePath) { return fs.readFileSync(absolute(relativePath), 'utf8'); } +function fileSha(relativePath) { return sha256(read(relativePath)); } +function externalSha(filePath) { return sha256(fs.readFileSync(filePath)); } +function run(executable, args, options = {}) { + const result = spawnSync(executable, args, { + cwd: root, + encoding: 'utf8', + maxBuffer: options.maxBuffer ?? 32 * 1024 * 1024, + timeout: options.timeout ?? 30_000 + }); + if (result.error) fail(`${executable} failed: ${result.error.message}`); + return { status: result.status, output: `${result.stdout ?? ''}${result.stderr ?? ''}` }; +} +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], + ['launch_state', mode.launch_state], + ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], + ['library_root', mode.library_root], + ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 ?? ''], + ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 ?? ''], + ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], + ['avd_name', mode.avd_name], + ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], + ['avd_config_sha256', mode.avd_config_sha256 ?? ''], + ['avd_ini_path', mode.avd_ini_path], + ['avd_ini_sha256', mode.avd_ini_sha256 ?? ''], + ['adb_server_port', mode.adb_server_port], + ['console_port', mode.console_port], + ['controller_port', mode.controller_port ?? ''], + ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], + ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 ?? ''], + ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], + ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], + ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], + ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha256(Buffer.from(fields.map(([key, value]) => `${key}=${value}`).join('\n'))); +} +function assertSha(value, label) { + assert(typeof value === 'string' && /^[0-9a-f]{64}$/.test(value), `${label} is not a lowercase SHA-256`); +} +function assertUUIDs(filePath, expected, label) { + assert(Array.isArray(expected) && expected.length > 0, `${label} UUID authority is empty`); + const result = run('/usr/bin/dwarfdump', ['--uuid', filePath]); + assert(result.status === 0, `${label} UUID inspection failed`); + for (const identity of expected) { + const [uuid, arch] = identity.split(':'); + assert(uuid && arch && result.output.toUpperCase().includes(uuid.toUpperCase()) && result.output.includes(`(${arch})`), `${label} UUID drifted`); + } +} +function readSealed(reference) { + assertSha(reference.sha256, `${reference.path} receipt SHA`); + assert(externalSha(reference.path) === reference.sha256, `sealed receipt hash drifted: ${reference.path}`); + const sidecar = fs.readFileSync(`${reference.path}.sha256`, 'utf8').trim().split(/\s+/)[0]; + assert(sidecar === reference.sha256, `sealed receipt sidecar drifted: ${reference.path}`); + return JSON.parse(fs.readFileSync(reference.path, 'utf8')); +} + +assert(fileSha(`${planRoot}/IMPLEMENTATION_PLAN.md`) === expectedPlanSha, 'original plan identity drifted'); +assert(fileSha(`${planRoot}/SCOPE_LOCK.txt`) === expectedScopeSha, 'scope-lock identity drifted'); +for (const required of [ + `${waveRoot}/CONTINUATION_AMENDMENT.md`, + `${waveRoot}/PREFLIGHT.json`, + `${waveRoot}/ZENGATE_RECEIPT.json`, + `${waveRoot}/PREPARATION_RECEIPT.json`, + `${waveRoot}/IMPLEMENTATION_RECEIPT.json`, + 'ssot/runtime-modes.json', + 'ssot/runtime-authority.json', + 'tftmac/Runtime/RuntimeMode.swift', + 'tftmac/Runtime/RuntimeModeAuthority.swift', + 'tftmac/Runtime/RuntimeLease.swift', + 'tftmac/Runtime/TFTMACRuntime.swift', + 'tftmac/App/AppCoordinator.swift', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift', + 'TFTMAC.xcodeproj/project.pbxproj', + 'scripts/verify-tftmac.command' +]) assert(fs.existsSync(absolute(required)), `required Wave B file is missing: ${required}`); + +const registryBytes = read('ssot/runtime-modes.json'); +const registrySha = sha256(registryBytes); +const runtimeModeSource = readText('tftmac/Runtime/RuntimeMode.swift'); +const pinned = runtimeModeSource.match(/static let expectedRegistrySha256 = "([0-9a-f]{64})"/); +assert(pinned?.[1] === registrySha, 'Swift registry identity does not match packaged JSON'); +const registry = JSON.parse(registryBytes); +assert(registry.schema === 1, 'runtime-mode schema must remain 1'); +assert(registry.contract === 'TFTMAC_RUNTIME_MODES_V1', 'runtime-mode contract drifted'); +assert(registry.default_mode === 'control', 'control is not the default mode'); +assert(registry.selection_environment_variable === 'TFTMAC_RUNTIME_MODE', 'selection environment variable drifted'); +assert(registry.active_lease_relative_path === 'State/native-runtime.lease', 'global exclusive lease path drifted'); +assert(JSON.stringify(Object.keys(registry.modes).sort()) === JSON.stringify(['advanced_diagnostics', 'candidate', 'control']), 'registry does not define exactly three modes'); + +const usedPorts = new Map(); +const usedNamespaces = new Set(); +for (const [name, mode] of Object.entries(registry.modes)) { + assert(name === mode.mode, `registry key mismatch for ${name}`); + assert(configurationHash(mode) === mode.configuration_sha256, `configuration SHA drifted for ${name}`); + assert(mode.serial === `emulator-${mode.console_port}`, `serial/console identity drifted for ${name}`); + assert(!usedNamespaces.has(mode.state_namespace), `state namespace collision at ${mode.state_namespace}`); + usedNamespaces.add(mode.state_namespace); + for (const [kind, value] of [['adb', mode.adb_server_port], ['console', mode.console_port], ['controller', mode.controller_port]]) { + if (value === null) continue; + assert(Number.isInteger(value) && value > 0 && value < 65536, `${name}.${kind} is invalid`); + assert(!usedPorts.has(value), `port ${value} collides between ${usedPorts.get(value)} and ${name}.${kind}`); + usedPorts.set(value, `${name}.${kind}`); + } +} + +const control = registry.modes.control; +assert(control.launch_state === 'enabled', 'control is not enabled'); +assert(control.state_namespace === 'control' && control.uses_legacy_application_support_root === true, 'control state compatibility drifted'); +assert(control.launch_strategy === 'bundled_forwarder' && control.profile_policy === 'validated_native_preferences', 'control launch/profile strategy drifted'); +assert(control.runtime_root === '/Volumes/MAC MINI M4/TFTMAC/Runtime', 'control root drifted'); +assert(control.avd_name === 'TFT_Ultra_Tablet', 'control AVD drifted'); +assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, 'control ports drifted'); +assert(control.serial === 'emulator-5582', 'control serial drifted'); +assert(control.rollback_target === 'control' && control.requires_control_stopped === false, 'control rollback contract drifted'); +for (const [filePath, expected, label] of [ + [control.adb_path, control.adb_sha256, 'control ADB'], + [control.emulator_path, control.emulator_sha256, 'control emulator'], + [control.qemu_path, control.qemu_sha256, 'control qemu'], + [control.gfxstream_backend_path, control.gfxstream_backend_sha256, 'control gfxstream'] +]) { + assertSha(expected, `${label} SHA`); + assert(externalSha(filePath) === expected, `${label} hash drifted`); +} +assertUUIDs(control.emulator_path, control.emulator_uuids, 'control emulator'); +assertUUIDs(control.qemu_path, control.qemu_uuids, 'control qemu'); +assertUUIDs(control.gfxstream_backend_path, control.gfxstream_backend_uuids, 'control gfxstream'); +const controlVersion = run(control.emulator_path, ['-version']); +assert(controlVersion.status === 0 && controlVersion.output.includes(control.expected_emulator_version_contains), 'control emulator version drifted'); +assert(control.authority_manifest.sha256 === fileSha('ssot/runtime-authority.json'), 'control authority manifest hash drifted'); +assert(control.host_application.executable_sha256 === null, 'control host cannot pin a non-reproducible pre-sign executable hash'); +assert(control.host_application.source_path === 'RuntimeHost/main.c', 'control host source path drifted'); +assert(control.host_application.source_sha256 === fileSha('RuntimeHost/main.c'), 'control host source identity drifted'); +assert(control.host_application.info_plist_path === 'RuntimeHost/Info.plist', 'control host Info.plist path drifted'); +assert(control.host_application.info_plist_sha256 === fileSha('RuntimeHost/Info.plist'), 'control host Info.plist identity drifted'); +assert(control.host_application.build_receipt_resource === 'control-host-build.json', 'control host signed build receipt contract drifted'); +const buildScript = readText('scripts/build-native-app.command'); +for (const required of ['CONTROL_NATIVE_HOST_BUILD_PASS', 'control-host-build.json', 'executable_uuids', 'source_sha256', 'info_plist_sha256']) { + assert(buildScript.includes(required), `build script is missing control-host receipt field: ${required}`); +} +assert(!buildScript.includes('codesign --force --deep --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${DIST}"'), 'outer app still deep-resigns the nested control host after its receipt'); + +const diagnostics = registry.modes.advanced_diagnostics; +assert(diagnostics.launch_state === 'blocked_pending_controller_lease' && diagnostics.controller_port === null, 'diagnostics are not fail-closed'); +assert(diagnostics.state_namespace === 'advanced_diagnostics' && diagnostics.uses_legacy_application_support_root === false, 'diagnostic state isolation drifted'); +assert(diagnostics.launch_strategy === 'external_native_host' && diagnostics.profile_policy === 'fixed_registry_profile', 'diagnostic launch/profile strategy drifted'); +assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.serial === 'emulator-5586', 'diagnostic port identity drifted'); +assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === 'control', 'diagnostic noninterference contract drifted'); +for (const [filePath, expected, label] of [ + [diagnostics.adb_path, diagnostics.adb_sha256, 'diagnostic ADB'], + [diagnostics.emulator_path, diagnostics.emulator_sha256, 'diagnostic emulator'], + [diagnostics.qemu_path, diagnostics.qemu_sha256, 'diagnostic qemu'], + [diagnostics.gfxstream_backend_path, diagnostics.gfxstream_backend_sha256, 'diagnostic gfxstream'], + [diagnostics.avd_config_path, diagnostics.avd_config_sha256, 'diagnostic AVD config'], + [diagnostics.avd_ini_path, diagnostics.avd_ini_sha256, 'diagnostic AVD ini'] +]) { + assertSha(expected, `${label} SHA`); + assert(externalSha(filePath) === expected, `${label} hash drifted`); +} +assertUUIDs(diagnostics.emulator_path, diagnostics.emulator_uuids, 'diagnostic emulator'); +assertUUIDs(diagnostics.qemu_path, diagnostics.qemu_uuids, 'diagnostic qemu'); +assertUUIDs(diagnostics.gfxstream_backend_path, diagnostics.gfxstream_backend_uuids, 'diagnostic gfxstream'); +const diagnosticVersion = run(diagnostics.emulator_path, ['-version']); +assert(diagnosticVersion.status === 0 && diagnosticVersion.output.includes(diagnostics.expected_emulator_version_contains), 'diagnostic emulator version drifted'); + +const receipts = diagnostics.diagnostic_receipts; +assert(receipts.build.sha256 === expectedBuildSha && receipts.clone.sha256 === expectedCloneSha && receipts.native_host.sha256 === expectedHostSha, 'diagnostic receipt identities drifted'); +const build = readSealed(receipts.build); +assert(build.state === 'DIAGNOSTIC_BUILD_IDENTITY_PASS' && build.build_id === receipts.build_id, 'diagnostic build state drifted'); +assert(build.non_comparable_to_stock === true && build.control_runtime_touched === false && build.control_noninterference?.matched === true, 'diagnostic build noninterference drifted'); +assert(build.release_and_tracing?.runtime_configuration_sha256 === receipts.runtime_configuration_sha256, 'diagnostic runtime configuration receipt drifted'); +assert(build.emulator?.path === diagnostics.emulator_path && build.emulator?.sha256 === diagnostics.emulator_sha256, 'diagnostic build emulator identity drifted'); +assert(JSON.stringify(build.emulator?.uuids) === JSON.stringify(diagnostics.emulator_uuids), 'diagnostic build emulator UUIDs drifted'); +assert(build.gfxstream_backend?.path === diagnostics.gfxstream_backend_path && build.gfxstream_backend?.sha256 === diagnostics.gfxstream_backend_sha256, 'diagnostic build gfxstream identity drifted'); +assert(JSON.stringify(build.gfxstream_backend?.uuids) === JSON.stringify(diagnostics.gfxstream_backend_uuids), 'diagnostic build gfxstream UUIDs drifted'); + +const clone = readSealed(receipts.clone); +assert(clone.state === 'DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS' && clone.build_id === receipts.build_id, 'diagnostic clone state drifted'); +assert(clone.diagnostic_avd?.name === diagnostics.avd_name && clone.diagnostic_avd?.avd_path === diagnostics.avd_directory, 'diagnostic clone AVD identity drifted'); +assert(clone.diagnostic_avd?.config_sha256 === diagnostics.avd_config_sha256 && clone.diagnostic_avd?.ini_sha256 === diagnostics.avd_ini_sha256, 'diagnostic clone configuration identity drifted'); +assert(clone.diagnostic_avd?.adb_server_port === diagnostics.adb_server_port && clone.diagnostic_avd?.console_port === diagnostics.console_port && clone.diagnostic_avd?.serial === diagnostics.serial, 'diagnostic clone port identity drifted'); +assert(clone.accepted_build?.sha256 === expectedBuildSha, 'diagnostic clone accepted-build link drifted'); +assert(clone.control_noninterference_matched === true && clone.sealed_before_first_boot === true, 'diagnostic clone seal drifted'); +assert(clone.first_boot_attempted === false && clone.launch_attempted === false && clone.control_runtime_mutation_attempted === false && clone.control_avd_touched === false, 'diagnostic clone no-first-boot boundary drifted'); + +const hostReceipt = readSealed(receipts.native_host); +assert(hostReceipt.state === 'DIAGNOSTIC_NATIVE_HOST_BUILD_PASS' && hostReceipt.build_id === receipts.build_id, 'diagnostic native-host state drifted'); +assert(hostReceipt.app?.path === diagnostics.host_application.path && hostReceipt.app?.bundle_identifier === diagnostics.host_application.bundle_identifier, 'diagnostic native-host app identity drifted'); +const diagnosticHostExecutable = path.join(diagnostics.host_application.path, diagnostics.host_application.executable_relative_path); +assertSha(diagnostics.host_application.executable_sha256, 'diagnostic native-host executable SHA'); +assert(hostReceipt.app?.executable?.path === diagnosticHostExecutable && hostReceipt.app?.executable?.sha256 === diagnostics.host_application.executable_sha256, 'diagnostic native-host executable receipt drifted'); +assert(externalSha(diagnosticHostExecutable) === diagnostics.host_application.executable_sha256, 'diagnostic native-host executable drifted'); +assert(hostReceipt.app?.codesign_verify_status === 0 && hostReceipt.control_runtime_mutation_attempted === false, 'diagnostic native-host signing/noninterference drifted'); +assert(hostReceipt.launch_contract?.method?.includes('/usr/bin/open') && hostReceipt.launch_contract?.emulator_spawn_owner === 'NATIVE_MACOS_APP_PROCESS' && hostReceipt.launch_contract?.service_context_emulator_spawn_forbidden === true, 'diagnostic native-host launch contract drifted'); + +const candidate = registry.modes.candidate; +assert(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate is not fail-closed'); +assert(candidate.state_namespace === 'candidate' && candidate.launch_strategy === 'blocked' && candidate.profile_policy === 'blocked', 'candidate isolation drifted'); +assert(candidate.requires_control_stopped === true && candidate.rollback_target === 'control', 'candidate rollback contract drifted'); + +const runtime = readText('tftmac/Runtime/TFTMACRuntime.swift'); +for (const forbidden of ['["-P", "5038"', '"emulator-5582"', '"@TFT_Ultra_Tablet"', '"-iTCP:5582"', '"-iTCP:8554"']) { + assert(!runtime.includes(forbidden), `shared runtime still hard-codes control identity: ${forbidden}`); +} +for (const required of [ + 'TFTMACSelectedRuntimeConfiguration', + 'runtimeConfiguration.authority.resolveForLaunch', + 'TFTMACRuntimeLease.acquire(', + 'identity: leaseIdentity', + 'validateLoadedRuntime(', + 'paths.adbServerPort', + 'paths.consolePort', + 'paths.controllerPort', + 'paths.serial', + 'paths.avdName' +]) assert(runtime.includes(required), `runtime is missing mode-aware source seam: ${required}`); + +const coordinator = readText('tftmac/App/AppCoordinator.swift'); +assert(coordinator.includes('TFTMACSelectedRuntimeConfiguration.load'), 'AppCoordinator does not load the accepted runtime configuration'); +assert(coordinator.includes('runtimeConfiguration: runtimeConfiguration'), 'AppCoordinator does not pass selected runtime authority'); +assert(coordinator.includes('activeApplicationSupport = runtimeConfiguration.applicationSupport'), 'AppCoordinator does not preserve mode-specific capture state'); + +const project = readText('TFTMAC.xcodeproj/project.pbxproj'); +for (const required of ['RuntimeMode.swift in Sources', 'RuntimeModeAuthority.swift in Sources', 'runtime-modes.json in Resources', 'runtime-authority.json in Resources']) { + assert(project.includes(required), `Xcode project is missing ${required}`); +} +const testCount = (readText('Tests/TFTMACTests/TFTMACGate1Tests.swift').match(/^ func test/gm) ?? []).length; +assert(testCount === 49, `expected 49 native tests after Wave B, found ${testCount}`); + +const receipt = JSON.parse(readText(`${waveRoot}/IMPLEMENTATION_RECEIPT.json`)); +assert(receipt.state === 'WAVE_B_V3_IMPLEMENTATION_APPLIED', 'implementation receipt state drifted'); +assert(receipt.runtime_modes_sha256 === registrySha, 'implementation receipt registry SHA drifted'); +assert(receipt.effects?.source_only === true, 'implementation receipt is not source-only'); +for (const effect of ['emulator_launch_attempted', 'runtime_replacement_attempted', 'control_stop_attempted', 'installed_app_replacement_attempted', 'package_launch_attempted']) { + assert(receipt.effects?.[effect] === false, `implementation receipt reports forbidden effect: ${effect}`); +} + +console.log(JSON.stringify({ + state: 'WAVE_B_V3_SOURCE_VALIDATION_PASS', + runtime_modes_sha256: registrySha, + test_count: testCount, + control: { avd: control.avd_name, adb: control.adb_server_port, console: control.console_port, controller: control.controller_port, serial: control.serial }, + advanced_diagnostics: { state: diagnostics.launch_state, first_boot_attempted: clone.first_boot_attempted, launch_attempted: clone.launch_attempted }, + candidate: { state: candidate.launch_state }, + runtime_effect_attempted: false +}, null, 2)); From a84aaa709b59bd61a5b5ca6ee0ef305375f314cd Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 21:08:39 -0500 Subject: [PATCH 05/10] Complete Wave B runtime mode integration --- .../IMPLEMENTATION_CHECKLIST.md | 4 +- .../wave-b-v4/CORRECTION_AMENDMENT.md | 48 + .../wave-b-v4/IMPLEMENTATION_RECEIPT.json | 35 + .../wave-b-v4/PREFLIGHT.json | 29 + .../wave-b-v4/PREPARATION_RECEIPT.json | 22 + .../wave-b-v4/RuntimeLease.swift.template | 177 +++ .../wave-b-v4/RuntimeMode.swift.template | 556 +++++++ .../RuntimeModeAuthority.swift.template | 841 +++++++++++ .../wave-b-v4/VALIDATION_RECEIPT.json | 33 + .../wave-b-v4/ZENGATE_RECEIPT.json | 33 + .../wave-b-v4/apply-waveb-v4.mjs | 1330 +++++++++++++++++ .../wave-b-v4/validate-waveb-v4.mjs | 283 ++++ TFTMAC.xcodeproj/project.pbxproj | 20 +- Tests/TFTMACTests/TFTMACGate1Tests.swift | 93 ++ facts.md | 35 +- scripts/build-native-app.command | 79 +- scripts/verify-tftmac.command | 17 +- ssot/runtime-modes.json | 133 +- tftmac/App/AppCoordinator.swift | 74 +- tftmac/Runtime/RuntimeLease.swift | 108 +- tftmac/Runtime/RuntimeMode.swift | 556 +++++++ tftmac/Runtime/RuntimeModeAuthority.swift | 841 +++++++++++ tftmac/Runtime/TFTMACRuntime.swift | 447 ++++-- 23 files changed, 5573 insertions(+), 221 deletions(-) create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/CORRECTION_AMENDMENT.md create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/IMPLEMENTATION_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREFLIGHT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREPARATION_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeLease.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeMode.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeModeAuthority.swift.template create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/VALIDATION_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/ZENGATE_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/apply-waveb-v4.mjs create mode 100644 .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs create mode 100644 tftmac/Runtime/RuntimeMode.swift create mode 100644 tftmac/Runtime/RuntimeModeAuthority.swift diff --git a/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md b/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md index 51d997c..74f507d 100644 --- a/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md +++ b/.clara/plans/tftmac-causal-graphics-v1/IMPLEMENTATION_CHECKLIST.md @@ -3,7 +3,7 @@ - [x] Restore and verify the governing implementation plan and ZenMC receipt. - [x] Reconcile the accepted r9 build, stopped physical clone, and native diagnostic host receipts. - [x] Map the current app-side native host and runtime configuration seam. -- [ ] **ACTIVE — Wave B:** implement exactly `control`, `advanced_diagnostics`, and `candidate` runtime modes with fail-closed identity and lease validation. -- [ ] Diagnostic first boot and loaded-runtime acceptance — closed while stock control is active. +- [x] **Wave B:** exactly `control`, `advanced_diagnostics`, and `candidate` runtime modes implemented with fail-closed identity and lease validation; unsigned Release build and all 49 native tests passed under Wave B v4. +- [ ] **ACTIVE — Diagnostic first boot:** allocate and receipt a collision-free EmulatorController port, then prove loaded diagnostic runtime identity and acceptance while stock control remains stopped. - [ ] Wave C onward: fixed event ABI and causal instrumentation — closed until diagnostic AVD acceptance passes. - [ ] Controlled experiment, candidate, rollback, documentation reconciliation, and final publication. diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/CORRECTION_AMENDMENT.md b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/CORRECTION_AMENDMENT.md new file mode 100644 index 0000000..7370980 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/CORRECTION_AMENDMENT.md @@ -0,0 +1,48 @@ +# Wave B v4 — Verified Continuation-Harness Correction + +Status: ACTIVE APPEND-ONLY CORRECTION + +This correction supplements the original TFTMAC Causal Graphics Optimization plan v1.1 and the Wave B v3 continuation amendment. It does not replace or weaken either authority. The original plan remains SHA-256 `78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b`; the execution-scope lock remains SHA-256 `dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e`. + +## Current authority + +- Managed change: `215ec5a3-6554-4ca3-95db-1525433bb20f`. +- Exact clean and remote-aligned head before this correction: `3326792efc694e853312aa7347abcb1edd96575a`. +- Wave B v3 remains preserved byte-for-byte as historical continuation authority. +- The protected rejected Wave B draft remains preserved and is not an implementation source. +- Stock Build 8 remains the default protected control runtime. + +## Proven continuation defects + +A disposable clone proved that the published Wave B v3 apply/validation package cannot complete from the recorded head without correction. The failures are deterministic and limited to continuation mechanics and generated source: + +1. The guarded apply expects a pre-checkpoint head. +2. Four source replacements use non-unique anchors, and one section replacement uses reversed boundaries. +3. The validator searches for a stale Swift expression and counts only one test file while asserting the repository-wide total. +4. The inherited runtime-mode template contains invalid Swift string-interpolation escaping. +5. Generated cleanup, port-list, and lease-release source contains three compile defects. +6. The lease payload nests mode identity while the Wave B contract and test require exact top-level identity fields. + +With those corrections applied only in a disposable clone, the unsigned Release build and all 49 native tests passed. No emulator, TFT package, installed app, AVD, runtime binary, or control process was changed or launched. + +## Authorized correction + +1. Preserve Wave B v3 and protected rejected work unchanged. +2. Place corrected, accepted RuntimeMode, RuntimeModeAuthority, and RuntimeLease templates under this Wave B v4 authority. +3. Correct only the proven apply anchors, generated Swift defects, validator ownership string, and repository-wide test inventory calculation. +4. Guard the apply against exact head `3326792efc694e853312aa7347abcb1edd96575a`, a clean tracked worktree, exact source hashes, and exact accepted external binary identities. +5. Keep `control` as the sole launch-ready default. Keep `advanced_diagnostics` blocked pending a separately receipted controller port. Keep `candidate` blocked. +6. Run the existing production source verifier once after application. PASS requires an unsigned Release build, all 49 native tests, exact packaged registries, Wave B source validation, and zero runtime effects. +7. Update current project facts/checklist only after the verifier proves the changed source. + +## Explicit exclusions + +- No emulator or TFT launch. +- No diagnostic first boot or controller-port allocation. +- No AVD mutation, runtime installation, application installation, or signing operation. +- No Wave C instrumentation, candidate patch, performance experiment, or final cutover. +- No modification of Riot credentials, the official TFT package, protected history, or accepted external artifacts. + +## Exit condition + +Wave B v4 is complete when the corrected guarded apply succeeds on the exact recorded head, the production verifier reports the unsigned Release build and all 49 native tests passing, the runtime/process audit proves zero launch effects, and the result is checkpointed locally. diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/IMPLEMENTATION_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/IMPLEMENTATION_RECEIPT.json new file mode 100644 index 0000000..e6f6ced --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/IMPLEMENTATION_RECEIPT.json @@ -0,0 +1,35 @@ +{ + "schema": 1, + "state": "WAVE_B_V4_IMPLEMENTATION_APPLIED", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "operation_id": null, + "applied_at": "2026-09-02T02:05:30.118Z", + "base_head_sha": "3326792efc694e853312aa7347abcb1edd96575a", + "original_plan_sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "correction_amendment_sha256": "18e85884498c52144f3e56217eb372b78289b6d938c5c92c0459a35882296b15", + "runtime_modes_sha256": "136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479", + "expected_test_count": 49, + "modified_paths": [ + "ssot/runtime-modes.json", + "tftmac/App/AppCoordinator.swift", + "tftmac/Runtime/RuntimeMode.swift", + "tftmac/Runtime/RuntimeModeAuthority.swift", + "tftmac/Runtime/RuntimeLease.swift", + "tftmac/Runtime/TFTMACRuntime.swift", + "Tests/TFTMACTests/TFTMACGate1Tests.swift", + "TFTMAC.xcodeproj/project.pbxproj", + "scripts/build-native-app.command", + "scripts/verify-tftmac.command" + ], + "effects": { + "source_only": true, + "emulator_launch_attempted": false, + "runtime_replacement_attempted": false, + "control_stop_attempted": false, + "installed_app_replacement_attempted": false, + "package_launch_attempted": false + }, + "next_safe_action": "Run the single changed-head production source verifier and correct only a proven failure." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREFLIGHT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREFLIGHT.json new file mode 100644 index 0000000..acec4a1 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREFLIGHT.json @@ -0,0 +1,29 @@ +{ + "schema": 1, + "state": "READY_FOR_WAVE_B_V4_CORRECTION", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-02T02:00:39Z", + "base_head_sha": "3326792efc694e853312aa7347abcb1edd96575a", + "original_plan_sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "wave_b_v3_preserved": true, + "protected_rejected_work_preserved": true, + "accepted_external_receipts": { + "diagnostic_build": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d", + "diagnostic_avd_clone": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648", + "diagnostic_native_host": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067" + }, + "disposable_proof": { + "unsigned_release_build": "PASS", + "native_tests": 49, + "native_test_failures": 0, + "runtime_effect_attempted": false + }, + "runtime_precondition": { + "tftmac_process_active": false, + "emulator_process_active": false, + "diagnostic_first_boot_authorized": false + }, + "next_safe_action": "Apply only the Wave B v4 source correction and run the production source verifier." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREPARATION_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREPARATION_RECEIPT.json new file mode 100644 index 0000000..10e49be --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/PREPARATION_RECEIPT.json @@ -0,0 +1,22 @@ +{ + "schema": 1, + "state": "WAVE_B_V4_PREPARATION_PASS", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-02T02:00:39Z", + "base_head_sha": "3326792efc694e853312aa7347abcb1edd96575a", + "original_plan_sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "correction_amendment_sha256": "18e85884498c52144f3e56217eb372b78289b6d938c5c92c0459a35882296b15", + "preflight_sha256": "6e8e415d921d0517d00a82101125340f109f9ca8bd3824b9ab9a130939054cfe", + "zengate_sha256": "35c9fbf5e295fd33a4ead854da72a3ac972620f4a4cd0205f5e6ebaa03b06c49", + "apply_runner_sha256": "36275b1c20aafa68bd34ddca8e8ebd466c31d8e27f3ade1d08a246be4aa89c72", + "disposable_proof": { + "unsigned_release_build": "PASS", + "native_tests": 49, + "native_test_failures": 0 + }, + "product_source_mutated": false, + "runtime_effect_attempted": false, + "next_safe_action": "Run the guarded Wave B v4 apply on the exact base head, then run the production source verifier once." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeLease.swift.template b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeLease.swift.template new file mode 100644 index 0000000..b21badc --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeLease.swift.template @@ -0,0 +1,177 @@ +import Darwin +import Foundation + +enum RuntimeLeaseError: LocalizedError, Sendable { + case alreadyOwned(processIdentifier: Int32) + case cannotCreate(String) + + var errorDescription: String? { + switch self { + case .alreadyOwned(let processIdentifier): + return "TFTMAC runtime is already owned by process \(processIdentifier). Close the other TFTMAC session first." + case .cannotCreate(let reason): + return "TFTMAC could not acquire its runtime lease: \(reason)" + } + } +} + +final class TFTMACRuntimeLease: @unchecked Sendable { + private struct Payload: Codable { + let schema: Int + let pid: Int32 + let token: String + let createdUTC: String + let mode: TFTMACRuntimeMode? + let registrySha256: String? + let configurationSha256: String? + let avdName: String? + let adbServerPort: Int? + let consolePort: Int? + let controllerPort: Int? + let serial: String? + + enum CodingKeys: String, CodingKey { + case schema + case pid + case token + case createdUTC = "created_utc" + case mode + case registrySha256 = "registry_sha256" + case configurationSha256 = "configuration_sha256" + case avdName = "avd_name" + case adbServerPort = "adb_server_port" + case consolePort = "console_port" + case controllerPort = "controller_port" + case serial + } + + init( + schema: Int, + pid: Int32, + token: String, + createdUTC: String, + identity: TFTMACRuntimeLeaseIdentity? + ) { + self.schema = schema + self.pid = pid + self.token = token + self.createdUTC = createdUTC + mode = identity?.mode + registrySha256 = identity?.registrySha256 + configurationSha256 = identity?.configurationSha256 + avdName = identity?.avdName + adbServerPort = identity?.adbServerPort + consolePort = identity?.consolePort + controllerPort = identity?.controllerPort + serial = identity?.serial + } + } + + let processIdentifier: Int32 + let token: String + let url: URL + let identity: TFTMACRuntimeLeaseIdentity? + private var released = false + + private init( + url: URL, + processIdentifier: Int32, + token: String, + identity: TFTMACRuntimeLeaseIdentity? + ) { + self.url = url + self.processIdentifier = processIdentifier + self.token = token + self.identity = identity + } + + static func acquire( + stateRoot: URL, + identity: TFTMACRuntimeLeaseIdentity? = nil, + processIdentifier: Int32 = ProcessInfo.processInfo.processIdentifier + ) throws -> Self { + try FileManager.default.createDirectory( + at: stateRoot, + withIntermediateDirectories: true, + attributes: [.posixPermissions: 0o700] + ) + let url = stateRoot.appendingPathComponent("native-runtime.lease") + let token = UUID().uuidString.lowercased() + for _ in 0..<2 { + let descriptor = Darwin.open(url.path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR) + if descriptor >= 0 { + let payload = Payload( + schema: identity == nil ? 1 : 2, + pid: processIdentifier, + token: token, + createdUTC: ISO8601DateFormatter().string(from: Date()), + identity: identity + ) + do { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + let data = try encoder.encode(payload) + try writeAll(data, to: descriptor) + _ = Darwin.fsync(descriptor) + Darwin.close(descriptor) + return Self( + url: url, + processIdentifier: processIdentifier, + token: token, + identity: identity + ) + } catch { + Darwin.close(descriptor) + try? FileManager.default.removeItem(at: url) + throw RuntimeLeaseError.cannotCreate(error.localizedDescription) + } + } + guard errno == EEXIST else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } + if let owner = leaseOwner(at: url), processExists(owner) { + throw RuntimeLeaseError.alreadyOwned(processIdentifier: owner) + } + do { try FileManager.default.removeItem(at: url) } + catch { throw RuntimeLeaseError.cannotCreate("stale lease could not be removed") } + } + throw RuntimeLeaseError.cannotCreate("another launch won the lease race") + } + + func release() { + guard !released else { return } + released = true + guard let payload = Self.payload(at: url), payload.token == token else { return } + try? FileManager.default.removeItem(at: url) + } + + deinit { release() } + + private static func payload(at url: URL) -> Payload? { + guard let data = try? Data(contentsOf: url) else { return nil } + return try? JSONDecoder().decode(Payload.self, from: data) + } + + private static func leaseOwner(at url: URL) -> Int32? { + payload(at: url)?.pid + } + + private static func processExists(_ processIdentifier: Int32) -> Bool { + if Darwin.kill(processIdentifier, 0) == 0 { return true } + return errno != ESRCH + } + + private static func writeAll(_ data: Data, to descriptor: Int32) throws { + try data.withUnsafeBytes { rawBuffer in + guard let baseAddress = rawBuffer.baseAddress else { return } + var written = 0 + while written < rawBuffer.count { + let result = Darwin.write(descriptor, baseAddress.advanced(by: written), rawBuffer.count - written) + guard result > 0 else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } + written += result + } + } + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeMode.swift.template b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeMode.swift.template new file mode 100644 index 0000000..b436402 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeMode.swift.template @@ -0,0 +1,556 @@ +import CryptoKit +import Foundation + +enum TFTMACRuntimeMode: String, Codable, CaseIterable, Sendable { + case control + case advancedDiagnostics = "advanced_diagnostics" + case candidate +} + +enum TFTMACRuntimeModeLaunchState: String, Codable, Sendable { + case enabled + case blockedPendingControllerLease = "blocked_pending_controller_lease" + case blockedNotBuilt = "blocked_not_built" +} + +struct TFTMACRuntimeModeError: LocalizedError, Sendable { + let message: String + + var errorDescription: String? { message } +} + +struct TFTMACRuntimeModeManifest: Codable, Equatable, Sendable { + let kind: String + let path: String + let sha256: String? +} + +struct TFTMACRuntimeModeDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let launchState: TFTMACRuntimeModeLaunchState + let runtimeRoot: String + let sdkRoot: String + let libraryRoot: String + let emulatorPath: String + let emulatorSha256: String? + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String? + let adbPath: String + let avdHome: String + let avdName: String + let avdDirectory: String + let avdConfigPath: String + let avdConfigSha256: String? + let avdIniPath: String + let avdIniSha256: String? + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int? + let serial: String + let authorityManifest: TFTMACRuntimeModeManifest + let applicationBundleId: String + let applicationVersion: String + let applicationBuild: String + let allowedPurpose: String + let comparabilityClass: String + let rollbackTarget: TFTMACRuntimeMode + let requiresControlStopped: Bool + let configurationSha256: String + + var computedConfigurationSha256: String { + let fields = [ + "mode=\(mode.rawValue)", + "launch_state=\(launchState.rawValue)", + "runtime_root=\(runtimeRoot)", + "sdk_root=\(sdkRoot)", + "library_root=\(libraryRoot)", + "emulator_path=\(emulatorPath)", + "emulator_sha256=\(emulatorSha256 ?? "")", + "gfxstream_backend_path=\(gfxstreamBackendPath)", + "gfxstream_backend_sha256=\(gfxstreamBackendSha256 ?? "")", + "adb_path=\(adbPath)", + "avd_home=\(avdHome)", + "avd_name=\(avdName)", + "avd_directory=\(avdDirectory)", + "avd_config_path=\(avdConfigPath)", + "avd_config_sha256=\(avdConfigSha256 ?? "")", + "avd_ini_path=\(avdIniPath)", + "avd_ini_sha256=\(avdIniSha256 ?? "")", + "adb_server_port=\(adbServerPort)", + "console_port=\(consolePort)", + "controller_port=\(controllerPort.map { String($0) } ?? "")", + "serial=\(serial)", + "authority_manifest_kind=\(authorityManifest.kind)", + "authority_manifest_path=\(authorityManifest.path)", + "authority_manifest_sha256=\(authorityManifest.sha256 ?? "")", + "application_bundle_id=\(applicationBundleId)", + "application_version=\(applicationVersion)", + "application_build=\(applicationBuild)", + "allowed_purpose=\(allowedPurpose)", + "comparability_class=\(comparabilityClass)", + "rollback_target=\(rollbackTarget.rawValue)", + "requires_control_stopped=\(requiresControlStopped ? "true" : "false")" + ] + return Self.sha256Hex(Data(fields.joined(separator: "\n").utf8)) + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} + +struct TFTMACRuntimeModeRegistryDocument: Codable, Equatable, Sendable { + let schema: Int + let defaultMode: TFTMACRuntimeMode + let activeLeaseRelativePath: String + let modes: [String: TFTMACRuntimeModeDefinition] +} + +struct TFTMACRuntimeLeaseIdentity: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let registrySha256: String + let configurationSha256: String + let avdName: String + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + + enum CodingKeys: String, CodingKey { + case mode + case registrySha256 = "registry_sha256" + case configurationSha256 = "configuration_sha256" + case avdName = "avd_name" + case adbServerPort = "adb_server_port" + case consolePort = "console_port" + case controllerPort = "controller_port" + case serial + } +} + +struct TFTMACRuntimeSelection: Equatable, Sendable { + let registrySha256: String + let activeLeaseRelativePath: String + let definition: TFTMACRuntimeModeDefinition + + var mode: TFTMACRuntimeMode { definition.mode } + + func leaseIdentity() throws -> TFTMACRuntimeLeaseIdentity { + guard let controllerPort = definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted EmulatorController port receipt." + ) + } + return TFTMACRuntimeLeaseIdentity( + mode: mode, + registrySha256: registrySha256, + configurationSha256: definition.configurationSha256, + avdName: definition.avdName, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial + ) + } + + func validateForLaunch( + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws { + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + _ = try leaseIdentity() + + guard bundle.bundleIdentifier == definition.applicationBundleId else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected the application bundle identity." + ) + } + let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String + let build = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String + guard version == definition.applicationVersion, build == definition.applicationBuild else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected application version/build \(version ?? "unknown")/\(build ?? "unknown")." + ) + } + + try requireDirectory(definition.runtimeRoot, label: "runtime root", fileManager: fileManager) + try requireDirectory(definition.sdkRoot, label: "SDK root", fileManager: fileManager) + try requireDirectory(definition.libraryRoot, label: "library root", fileManager: fileManager) + try requireDirectory(definition.avdHome, label: "AVD home", fileManager: fileManager) + try requireDirectory(definition.avdDirectory, label: "AVD directory", fileManager: fileManager) + try requireExecutable(definition.emulatorPath, label: "emulator", fileManager: fileManager) + try requireExecutable(definition.adbPath, label: "ADB", fileManager: fileManager) + try requireFile(definition.gfxstreamBackendPath, label: "gfxstream backend", fileManager: fileManager) + try requireFile(definition.avdConfigPath, label: "AVD config", fileManager: fileManager) + try requireFile(definition.avdIniPath, label: "AVD ini", fileManager: fileManager) + + let manifestURL: URL + switch definition.authorityManifest.kind { + case "bundled_resource": + guard let resourceURL = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + manifestURL = resourceURL.appendingPathComponent(definition.authorityManifest.path) + case "external_sealed_manifest": + manifestURL = URL(fileURLWithPath: definition.authorityManifest.path) + default: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has unsupported manifest authority \(definition.authorityManifest.kind)." + ) + } + guard let expectedManifestSha256 = definition.authorityManifest.sha256 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted manifest SHA-256." + ) + } + try validateSHA256(at: manifestURL, expected: expectedManifestSha256, label: "authority manifest") + try validateOptionalSHA256(path: definition.emulatorPath, expected: definition.emulatorSha256, label: "emulator") + try validateOptionalSHA256( + path: definition.gfxstreamBackendPath, + expected: definition.gfxstreamBackendSha256, + label: "gfxstream backend" + ) + try validateOptionalSHA256(path: definition.avdConfigPath, expected: definition.avdConfigSha256, label: "AVD config") + try validateOptionalSHA256(path: definition.avdIniPath, expected: definition.avdIniSha256, label: "AVD ini") + } + + private func requireDirectory(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireFile(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), !isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireExecutable(_ path: String, label: String, fileManager: FileManager) throws { + guard fileManager.isExecutableFile(atPath: path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no executable \(label) at \(path)." + ) + } + } + + private func validateOptionalSHA256(path: String, expected: String?, label: String) throws { + guard let expected else { return } + try validateSHA256(at: URL(fileURLWithPath: path), expected: expected, label: label) + } + + private func validateSHA256(at url: URL, expected: String, label: String) throws { + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not open its \(label) at \(url.path): \(error.localizedDescription)" + ) + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not hash its \(label): \(error.localizedDescription)" + ) + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected \(label) SHA-256 \(observed)." + ) + } + } +} + +struct TFTMACRuntimeModeRegistry: Sendable { + static let environmentKey = "TFTMAC_RUNTIME_MODE" + static let expectedRegistrySha256 = "__EXPECTED_RUNTIME_MODES_SHA256__" + + let document: TFTMACRuntimeModeRegistryDocument + let registrySha256: String + + init(data: Data) throws { + let observedRegistrySha256 = Self.sha256Hex(data) + guard observedRegistrySha256 == Self.expectedRegistrySha256 else { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry SHA-256 \(observedRegistrySha256) is not the accepted packaged identity." + ) + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeRegistryDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = observedRegistrySha256 + try Self.validate(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read runtime-modes.json: \(error.localizedDescription)" + ) + } + } + + var defaultMode: TFTMACRuntimeMode { document.defaultMode } + + var registeredModes: Set { + Set(document.modes.values.map(\.mode)) + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is not registered.") + } + return definition + } + + func selection(environment: [String: String] = ProcessInfo.processInfo.environment) throws -> TFTMACRuntimeSelection { + let requested = environment[Self.environmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines) + let mode: TFTMACRuntimeMode + if let requested, !requested.isEmpty { + guard let parsed = TFTMACRuntimeMode(rawValue: requested) else { + throw TFTMACRuntimeModeError(message: "Unknown TFTMAC runtime mode \(requested).") + } + mode = parsed + } else { + mode = document.defaultMode + } + let definition = try definition(for: mode) + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + return TFTMACRuntimeSelection( + registrySha256: registrySha256, + activeLeaseRelativePath: document.activeLeaseRelativePath, + definition: definition + ) + } + + private static func validate(_ document: TFTMACRuntimeModeRegistryDocument) throws { + guard document.schema == 1 else { + throw TFTMACRuntimeModeError(message: "Unsupported runtime-mode registry schema \(document.schema).") + } + guard document.defaultMode == .control else { + throw TFTMACRuntimeModeError(message: "The default TFTMAC runtime mode must remain control.") + } + guard document.activeLeaseRelativePath == "State/native-runtime.lease" else { + throw TFTMACRuntimeModeError(message: "The runtime-mode registry changed the protected lease path.") + } + + let expectedKeys = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == expectedKeys else { + throw TFTMACRuntimeModeError( + message: "The runtime-mode registry must contain exactly control, advanced_diagnostics, and candidate." + ) + } + + var occupiedPorts: [Int: String] = [:] + for (key, definition) in document.modes { + guard key == definition.mode.rawValue else { + throw TFTMACRuntimeModeError( + message: "Runtime-mode registry key \(key) does not match \(definition.mode.rawValue)." + ) + } + try validate(definition) + for (kind, port) in [ + ("adb", Optional(definition.adbServerPort)), + ("console", Optional(definition.consolePort)), + ("controller", definition.controllerPort) + ] { + guard let port else { continue } + if let existing = occupiedPorts[port] { + throw TFTMACRuntimeModeError( + message: "Runtime lease port \(port) is shared by \(existing) and \(definition.mode.rawValue).\(kind)." + ) + } + occupiedPorts[port] = "\(definition.mode.rawValue).\(kind)" + } + } + + let control = try required(.control, from: document) + guard control.launchState == .enabled, + control.runtimeRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime", + control.sdkRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", + control.avdHome == "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", + control.avdName == "TFT_Ultra_Tablet", + control.adbServerPort == 5038, + control.consolePort == 5582, + control.controllerPort == 8554, + control.serial == "emulator-5582", + control.authorityManifest.kind == "bundled_resource", + control.authorityManifest.path == "runtime-authority.json", + control.authorityManifest.sha256 != nil, + control.emulatorSha256 != nil, + control.gfxstreamBackendSha256 != nil, + control.rollbackTarget == .control, + !control.requiresControlStopped else { + throw TFTMACRuntimeModeError( + message: "The control mode no longer matches the accepted stock Build 8 authority." + ) + } + + let diagnostics = try required(.advancedDiagnostics, from: document) + guard diagnostics.launchState == .blockedPendingControllerLease, + diagnostics.controllerPort == nil, + diagnostics.avdName == "TFTMAC_Diagnostic_API37_R9", + diagnostics.adbServerPort == 5041, + diagnostics.consolePort == 5586, + diagnostics.serial == "emulator-5586", + diagnostics.emulatorSha256 != nil, + diagnostics.gfxstreamBackendSha256 != nil, + diagnostics.avdConfigSha256 != nil, + diagnostics.avdIniSha256 != nil, + diagnostics.requiresControlStopped, + diagnostics.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Advanced diagnostics must remain isolated and blocked pending its controller-port receipt." + ) + } + + let candidate = try required(.candidate, from: document) + guard candidate.launchState == .blockedNotBuilt, + candidate.controllerPort == nil, + candidate.requiresControlStopped, + candidate.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Candidate mode must remain blocked until a separately accepted candidate exists." + ) + } + } + + private static func validate(_ definition: TFTMACRuntimeModeDefinition) throws { + let requiredStrings = [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdName, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath, + definition.serial, + definition.authorityManifest.kind, + definition.authorityManifest.path, + definition.applicationBundleId, + definition.applicationVersion, + definition.applicationBuild, + definition.allowedPurpose, + definition.comparabilityClass + ] + guard requiredStrings.allSatisfy({ !$0.isEmpty }) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) has an empty required field." + ) + } + for path in [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath + ] { + guard path.hasPrefix("/") else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains a non-absolute path." + ) + } + } + guard (1...65535).contains(definition.adbServerPort), + (1...65535).contains(definition.consolePort), + definition.controllerPort.map({ (1...65535).contains($0) }) ?? true else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid lease port." + ) + } + guard definition.serial == "emulator-\(definition.consolePort)" else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) serial does not match its console lease." + ) + } + if definition.launchState == .enabled, definition.controllerPort == nil { + throw TFTMACRuntimeModeError( + message: "Launch-ready mode \(definition.mode.rawValue) has no controller-port receipt." + ) + } + let digests: [String?] = [ + definition.configurationSha256, + definition.emulatorSha256, + definition.gfxstreamBackendSha256, + definition.avdConfigSha256, + definition.avdIniSha256, + definition.authorityManifest.sha256 + ] + for digest in digests.compactMap({ $0 }) { + guard isSHA256(digest) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid SHA-256 value." + ) + } + } + guard definition.computedConfigurationSha256 == definition.configurationSha256.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) configuration SHA-256 does not match its fields." + ) + } + } + + private static func required( + _ mode: TFTMACRuntimeMode, + from document: TFTMACRuntimeModeRegistryDocument + ) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeModeAuthority.swift.template b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeModeAuthority.swift.template new file mode 100644 index 0000000..1aaf84b --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/RuntimeModeAuthority.swift.template @@ -0,0 +1,841 @@ +import CryptoKit +import Darwin +import Foundation + +enum TFTMACRuntimeLaunchStrategy: String, Codable, Sendable { + case bundledForwarder = "bundled_forwarder" + case externalNativeHost = "external_native_host" + case blocked +} + +enum TFTMACRuntimeProfilePolicy: String, Codable, Sendable { + case validatedNativePreferences = "validated_native_preferences" + case fixedRegistryProfile = "fixed_registry_profile" + case blocked +} + +enum TFTMACRuntimeHostKind: String, Codable, Sendable { + case bundledResource = "bundled_resource" + case externalApplication = "external_application" +} + +struct TFTMACSealedReceiptReference: Codable, Equatable, Sendable { + let path: String + let sha256: String + let requiredState: String +} + +struct TFTMACRuntimeHostAuthority: Codable, Equatable, Sendable { + let kind: TFTMACRuntimeHostKind + let path: String + let bundleIdentifier: String + let executableRelativePath: String + let executableSha256: String? + let sourcePath: String? + let sourceSha256: String? + let infoPlistPath: String? + let infoPlistSha256: String? + let buildReceiptResource: String? +} + +struct TFTMACRuntimeLockedProfile: Codable, Equatable, Sendable { + let identifier: String + let width: Int + let height: Int + let densityDpi: Int + let refreshHz: Int + let vcpu: Int + let ramMib: Int + let gpuMode: String + let audioBackend: String + let graphicsTransport: String + let asgWriteBufferSize: Int + let asgWriteStepSize: Int + let asgDataRingSize: Int + let asgDrawFlushInterval: Int + let angleEnabledFeatures: String + let angleDisabledFeatures: String +} + +struct TFTMACDiagnosticReceiptAuthority: Codable, Equatable, Sendable { + let buildId: String + let runtimeConfigurationSha256: String + let build: TFTMACSealedReceiptReference + let clone: TFTMACSealedReceiptReference + let nativeHost: TFTMACSealedReceiptReference +} + +struct TFTMACRuntimeModeSupplementalDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let stateNamespace: String + let usesLegacyApplicationSupportRoot: Bool + let emulatorIdentifier: String + let launchStrategy: TFTMACRuntimeLaunchStrategy + let profilePolicy: TFTMACRuntimeProfilePolicy + let lockedProfile: TFTMACRuntimeLockedProfile? + let adbSha256: String? + let adbVendorKeysPolicy: String + let expectedEmulatorVersionContains: String? + let emulatorUuids: [String]? + let qemuPath: String? + let qemuSha256: String? + let qemuUuids: [String]? + let gfxstreamBackendUuids: [String]? + let hostApplication: TFTMACRuntimeHostAuthority? + let diagnosticReceipts: TFTMACDiagnosticReceiptAuthority? +} + +struct TFTMACRuntimeModeAuthorityDocument: Codable, Equatable, Sendable { + let schema: Int + let contract: String + let selectionEnvironmentVariable: String + let modes: [String: TFTMACRuntimeModeSupplementalDefinition] +} + +struct TFTMACLoadedRuntimeIdentity: Equatable, Sendable { + let processIdentifier: Int32 + let qemuPath: String + let qemuSha256: String + let qemuUuids: [String] + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String + let gfxstreamBackendUuids: [String] +} + +struct TFTMACResolvedRuntimeModeAuthority: Sendable { + let supplemental: TFTMACRuntimeModeSupplementalDefinition + let hostApplication: URL + let applicationSupport: URL + let globalApplicationSupport: URL +} + +struct TFTMACSelectedRuntimeConfiguration: Sendable { + let registry: TFTMACRuntimeModeRegistry + let selection: TFTMACRuntimeSelection + let authority: TFTMACRuntimeModeAuthority + let profile: TFTMACRuntimeProfile + let applicationSupport: URL + + static func load( + savedProfile: TFTMACRuntimeProfile, + bundle: Bundle = .main, + environment: [String: String] = ProcessInfo.processInfo.environment + ) throws -> Self { + let registry = try TFTMACRuntimeModeRegistry.loadBundled(bundle: bundle) + let authority = try TFTMACRuntimeModeAuthority.loadBundled(bundle: bundle) + try authority.validateConsistency(with: registry) + let selection = try registry.selection(environment: environment) + let profile = try authority.effectiveProfile(savedProfile: savedProfile, selection: selection) + return Self( + registry: registry, + selection: selection, + authority: authority, + profile: profile, + applicationSupport: authority.applicationSupportURL(for: selection.mode) + ) + } +} + +struct TFTMACRuntimeModeAuthority: Sendable { + static let expectedContract = "TFTMAC_RUNTIME_MODES_V1" + + let document: TFTMACRuntimeModeAuthorityDocument + let registrySha256: String + + init(data: Data) throws { + let observed = Self.sha256Hex(data) + guard observed == TFTMACRuntimeModeRegistry.expectedRegistrySha256 else { + throw TFTMACRuntimeModeError( + message: "TFTMAC supplemental runtime authority rejected registry SHA-256 \(observed)." + ) + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeAuthorityDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC supplemental runtime authority could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = observed + try Self.validateStatic(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read supplemental runtime authority: \(error.localizedDescription)" + ) + } + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeSupplementalDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Supplemental runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + func validateConsistency(with registry: TFTMACRuntimeModeRegistry) throws { + guard registry.registrySha256 == registrySha256 else { + throw TFTMACRuntimeModeError(message: "Base and supplemental runtime authority hashes differ.") + } + for mode in TFTMACRuntimeMode.allCases { + let base = try registry.definition(for: mode) + let supplemental = try definition(for: mode) + guard base.mode == supplemental.mode else { + throw TFTMACRuntimeModeError(message: "Runtime mode authority mismatch for \(mode.rawValue).") + } + } + } + + func effectiveProfile( + savedProfile: TFTMACRuntimeProfile, + selection: TFTMACRuntimeSelection + ) throws -> TFTMACRuntimeProfile { + let supplemental = try definition(for: selection.mode) + guard let controllerPort = selection.definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted controller port." + ) + } + switch supplemental.profilePolicy { + case .validatedNativePreferences: + guard selection.mode == .control, savedProfile.controllerPort == controllerPort else { + throw TFTMACRuntimeModeError( + message: "Saved control profile does not match the accepted controller lease." + ) + } + return savedProfile + case .fixedRegistryProfile: + guard let locked = supplemental.lockedProfile else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) is missing its fixed profile." + ) + } + return TFTMACRuntimeProfile( + identifier: locked.identifier, + width: locked.width, + height: locked.height, + densityDPI: locked.densityDpi, + refreshHz: locked.refreshHz, + vCPU: locked.vcpu, + ramMiB: locked.ramMib, + gpuMode: locked.gpuMode, + audioBackend: locked.audioBackend, + graphicsTransport: locked.graphicsTransport, + asgWriteBufferSize: locked.asgWriteBufferSize, + asgWriteStepSize: locked.asgWriteStepSize, + asgDataRingSize: locked.asgDataRingSize, + asgDrawFlushInterval: locked.asgDrawFlushInterval, + controllerPort: controllerPort, + angleEnabledFeatures: locked.angleEnabledFeatures, + angleDisabledFeatures: locked.angleDisabledFeatures, + experimentPreset: .control + ) + case .blocked: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted profile." + ) + } + } + + func applicationSupportURL(for mode: TFTMACRuntimeMode) -> URL { + let global = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + guard let supplemental = try? definition(for: mode), !supplemental.usesLegacyApplicationSupportRoot else { + return global + } + return global + .appendingPathComponent("Modes", isDirectory: true) + .appendingPathComponent(supplemental.stateNamespace, isDirectory: true) + } + + func resolveForLaunch( + selection: TFTMACRuntimeSelection, + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws -> TFTMACResolvedRuntimeModeAuthority { + try selection.validateForLaunch(bundle: bundle, fileManager: fileManager) + let supplemental = try definition(for: selection.mode) + try validateModeEvidence( + base: selection.definition, + supplemental: supplemental, + bundle: bundle, + fileManager: fileManager + ) + let hostApplication = try resolveHostApplication( + supplemental: supplemental, + bundle: bundle, + fileManager: fileManager + ) + let global = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + return TFTMACResolvedRuntimeModeAuthority( + supplemental: supplemental, + hostApplication: hostApplication, + applicationSupport: applicationSupportURL(for: selection.mode), + globalApplicationSupport: global + ) + } + + func validateLoadedRuntime( + processIdentifier: Int32, + selection: TFTMACRuntimeSelection + ) throws -> TFTMACLoadedRuntimeIdentity { + let supplemental = try definition(for: selection.mode) + guard let qemuPath = supplemental.qemuPath, + let qemuSha256 = supplemental.qemuSha256, + let qemuUuids = supplemental.qemuUuids, + let gfxstreamSha256 = selection.definition.gfxstreamBackendSha256, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids, + let controllerPort = selection.definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) lacks loaded-runtime identity authority." + ) + } + let observedExecutable = try Self.processExecutablePath(processIdentifier) + guard Self.standardized(observedExecutable) == Self.standardized(qemuPath) else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator process path \(observedExecutable) does not match \(qemuPath)." + ) + } + try Self.validateSHA256(path: qemuPath, expected: qemuSha256, label: "loaded qemu") + try Self.validateUUIDs(path: qemuPath, expected: qemuUuids, label: "loaded qemu") + + let command = try Self.runCommand( + executable: "/bin/ps", + arguments: ["-p", "\(processIdentifier)", "-ww", "-o", "command="], + timeout: 10 + ) + guard command.status == 0, + command.output.contains("@\(selection.definition.avdName)"), + command.output.contains("-port \(selection.definition.consolePort)"), + command.output.contains("-grpc \(controllerPort)") else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator command line does not match the selected AVD and port lease." + ) + } + + let vmmap = try Self.runCommand( + executable: "/usr/bin/vmmap", + arguments: ["-w", "\(processIdentifier)"], + timeout: 30 + ) + guard vmmap.status == 0, + vmmap.output.contains(selection.definition.gfxstreamBackendPath) else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator did not prove the accepted gfxstream image mapping." + ) + } + try Self.validateSHA256( + path: selection.definition.gfxstreamBackendPath, + expected: gfxstreamSha256, + label: "loaded gfxstream backend" + ) + try Self.validateUUIDs( + path: selection.definition.gfxstreamBackendPath, + expected: gfxstreamUuids, + label: "loaded gfxstream backend" + ) + return TFTMACLoadedRuntimeIdentity( + processIdentifier: processIdentifier, + qemuPath: qemuPath, + qemuSha256: qemuSha256, + qemuUuids: qemuUuids, + gfxstreamBackendPath: selection.definition.gfxstreamBackendPath, + gfxstreamBackendSha256: gfxstreamSha256, + gfxstreamBackendUuids: gfxstreamUuids + ) + } + + private static func validateStatic(_ document: TFTMACRuntimeModeAuthorityDocument) throws { + guard document.schema == 1, + document.contract == expectedContract, + document.selectionEnvironmentVariable == TFTMACRuntimeModeRegistry.environmentKey else { + throw TFTMACRuntimeModeError(message: "Supplemental runtime-mode contract identity failed.") + } + let exactModes = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == exactModes else { + throw TFTMACRuntimeModeError( + message: "Supplemental authority must define exactly control, advanced_diagnostics, and candidate." + ) + } + var namespaces = Set() + for (key, definition) in document.modes { + guard key == definition.mode.rawValue, + !definition.stateNamespace.isEmpty, + namespaces.insert(definition.stateNamespace).inserted, + !definition.emulatorIdentifier.isEmpty, + !definition.adbVendorKeysPolicy.isEmpty else { + throw TFTMACRuntimeModeError( + message: "Supplemental runtime identity is invalid for \(key)." + ) + } + } + + guard let control = document.modes[TFTMACRuntimeMode.control.rawValue], + control.usesLegacyApplicationSupportRoot, + control.stateNamespace == "control", + control.launchStrategy == .bundledForwarder, + control.profilePolicy == .validatedNativePreferences, + control.lockedProfile == nil, + control.adbSha256.map(Self.isSHA256) == true, + control.emulatorUuids?.isEmpty == false, + control.qemuPath?.hasPrefix("/") == true, + control.qemuSha256.map(Self.isSHA256) == true, + control.qemuUuids?.isEmpty == false, + control.gfxstreamBackendUuids?.isEmpty == false, + control.hostApplication?.kind == .bundledResource, + control.hostApplication?.executableSha256 == nil, + control.hostApplication?.sourcePath == "RuntimeHost/main.c", + control.hostApplication?.sourceSha256.map(Self.isSHA256) == true, + control.hostApplication?.infoPlistPath == "RuntimeHost/Info.plist", + control.hostApplication?.infoPlistSha256.map(Self.isSHA256) == true, + control.hostApplication?.buildReceiptResource == "control-host-build.json", + control.diagnosticReceipts == nil else { + throw TFTMACRuntimeModeError(message: "Supplemental control authority is incomplete.") + } + + guard let diagnostics = document.modes[TFTMACRuntimeMode.advancedDiagnostics.rawValue], + !diagnostics.usesLegacyApplicationSupportRoot, + diagnostics.stateNamespace == "advanced_diagnostics", + diagnostics.launchStrategy == .externalNativeHost, + diagnostics.profilePolicy == .fixedRegistryProfile, + diagnostics.lockedProfile != nil, + diagnostics.adbSha256.map(Self.isSHA256) == true, + diagnostics.emulatorUuids?.isEmpty == false, + diagnostics.qemuPath?.hasPrefix("/") == true, + diagnostics.qemuSha256.map(Self.isSHA256) == true, + diagnostics.qemuUuids?.isEmpty == false, + diagnostics.gfxstreamBackendUuids?.isEmpty == false, + diagnostics.hostApplication?.kind == .externalApplication, + diagnostics.hostApplication?.executableSha256.map(Self.isSHA256) == true, + diagnostics.hostApplication?.sourcePath == nil, + diagnostics.hostApplication?.sourceSha256 == nil, + diagnostics.hostApplication?.infoPlistSha256.map(Self.isSHA256) == true, + diagnostics.hostApplication?.buildReceiptResource == nil, + let receipts = diagnostics.diagnosticReceipts, + receipts.buildId == "gate4-r9-20260901", + Self.isSHA256(receipts.runtimeConfigurationSha256), + receipts.build.requiredState == "DIAGNOSTIC_BUILD_IDENTITY_PASS", + receipts.clone.requiredState == "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS", + receipts.nativeHost.requiredState == "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS" else { + throw TFTMACRuntimeModeError(message: "Supplemental diagnostic authority is incomplete.") + } + + guard let candidate = document.modes[TFTMACRuntimeMode.candidate.rawValue], + !candidate.usesLegacyApplicationSupportRoot, + candidate.stateNamespace == "candidate", + candidate.launchStrategy == .blocked, + candidate.profilePolicy == .blocked, + candidate.lockedProfile == nil, + candidate.hostApplication == nil, + candidate.diagnosticReceipts == nil else { + throw TFTMACRuntimeModeError(message: "Supplemental candidate authority must remain blocked.") + } + } + + private func validateModeEvidence( + base: TFTMACRuntimeModeDefinition, + supplemental: TFTMACRuntimeModeSupplementalDefinition, + bundle: Bundle, + fileManager: FileManager + ) throws { + guard let adbSha256 = supplemental.adbSha256, + let emulatorUuids = supplemental.emulatorUuids, + let versionFragment = supplemental.expectedEmulatorVersionContains, + let qemuPath = supplemental.qemuPath, + let qemuSha256 = supplemental.qemuSha256, + let qemuUuids = supplemental.qemuUuids, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(base.mode.rawValue) lacks accepted binary identity evidence." + ) + } + try Self.validateSHA256(path: base.adbPath, expected: adbSha256, label: "ADB") + try Self.validateSHA256(path: qemuPath, expected: qemuSha256, label: "qemu") + try Self.validateUUIDs(path: qemuPath, expected: qemuUuids, label: "qemu") + try Self.validateUUIDs(path: base.emulatorPath, expected: emulatorUuids, label: "emulator") + try Self.validateUUIDs( + path: base.gfxstreamBackendPath, + expected: gfxstreamUuids, + label: "gfxstream backend" + ) + let version = try Self.runCommand( + executable: base.emulatorPath, + arguments: ["-version"], + timeout: 30 + ) + guard version.status == 0, version.output.contains(versionFragment) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(base.mode.rawValue) rejected emulator version identity." + ) + } + if base.mode == .advancedDiagnostics { + try validateDiagnosticReceipts(base: base, supplemental: supplemental) + } + } + + private func resolveHostApplication( + supplemental: TFTMACRuntimeModeSupplementalDefinition, + bundle: Bundle, + fileManager: FileManager + ) throws -> URL { + guard let host = supplemental.hostApplication else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) has no accepted native host." + ) + } + let appURL: URL + switch host.kind { + case .bundledResource: + guard let resources = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + appURL = resources.appendingPathComponent(host.path, isDirectory: true) + case .externalApplication: + appURL = URL(fileURLWithPath: host.path, isDirectory: true) + } + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: appURL.path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) is missing its native host at \(appURL.path)." + ) + } + let infoURL = appURL.appendingPathComponent("Contents/Info.plist") + guard let info = NSDictionary(contentsOf: infoURL), + info["CFBundleIdentifier"] as? String == host.bundleIdentifier else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) rejected native-host bundle identity." + ) + } + if let expectedInfoPlistSha256 = host.infoPlistSha256 { + try Self.validateSHA256( + path: infoURL.path, + expected: expectedInfoPlistSha256, + label: "native-host Info.plist" + ) + } + let executable = appURL.appendingPathComponent(host.executableRelativePath) + guard fileManager.isExecutableFile(atPath: executable.path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) native-host executable is missing." + ) + } + if let expectedExecutableSha256 = host.executableSha256 { + try Self.validateSHA256( + path: executable.path, + expected: expectedExecutableSha256, + label: "native-host executable" + ) + } else if host.buildReceiptResource == nil { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) has no native-host build receipt authority." + ) + } + if host.buildReceiptResource != nil { + try Self.validateControlHostBuildReceipt(host: host, appURL: appURL, bundle: bundle) + } + let codesign = try Self.runCommand( + executable: "/usr/bin/codesign", + arguments: ["--verify", "--deep", "--strict", appURL.path], + timeout: 30 + ) + guard codesign.status == 0 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) native-host signature is invalid." + ) + } + return appURL + } + + + private static func validateControlHostBuildReceipt( + host: TFTMACRuntimeHostAuthority, + appURL: URL, + bundle: Bundle + ) throws { + guard let receiptName = host.buildReceiptResource, + let sourcePath = host.sourcePath, + let sourceSha256 = host.sourceSha256, + let infoPlistPath = host.infoPlistPath, + let infoPlistSha256 = host.infoPlistSha256, + let resources = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "Control native-host build receipt authority is incomplete.") + } + let receiptURL = resources.appendingPathComponent(receiptName) + guard let data = try? Data(contentsOf: receiptURL), + let receipt = try? JSONSerialization.jsonObject(with: data) as? [String: Any], + string(receipt, ["state"]) == "CONTROL_NATIVE_HOST_BUILD_PASS", + string(receipt, ["host_application_relative_path"]) == host.path, + string(receipt, ["bundle_identifier"]) == host.bundleIdentifier, + string(receipt, ["source_path"]) == sourcePath, + string(receipt, ["source_sha256"]) == sourceSha256, + string(receipt, ["info_plist_path"]) == infoPlistPath, + string(receipt, ["info_plist_sha256"]) == infoPlistSha256, + string(receipt, ["executable_relative_path"]) == host.executableRelativePath, + let executableSha256 = string(receipt, ["executable_sha256"]), + let executableUuids = strings(receipt, ["executable_uuids"]), + strings(receipt, ["compile_arguments"]) == ["-Os", "-arch", "arm64", "-mmacosx-version-min=15.0"] else { + throw TFTMACRuntimeModeError(message: "Control native-host signed build receipt is missing or invalid.") + } + let executable = appURL.appendingPathComponent(host.executableRelativePath) + try validateSHA256(path: executable.path, expected: executableSha256, label: "control native-host executable") + try validateUUIDs(path: executable.path, expected: executableUuids, label: "control native-host executable") + } + + private func validateDiagnosticReceipts( + base: TFTMACRuntimeModeDefinition, + supplemental: TFTMACRuntimeModeSupplementalDefinition + ) throws { + guard let authority = supplemental.diagnosticReceipts, + let host = supplemental.hostApplication, + let emulatorUuids = supplemental.emulatorUuids, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids else { + throw TFTMACRuntimeModeError(message: "Diagnostic receipt authority is missing.") + } + let build = try Self.readSealedReceipt(authority.build) + guard Self.string(build, ["state"]) == authority.build.requiredState, + Self.string(build, ["build_id"]) == authority.buildId, + Self.bool(build, ["non_comparable_to_stock"]) == true, + Self.bool(build, ["control_runtime_touched"]) == false, + Self.bool(build, ["control_noninterference", "matched"]) == true, + Self.string(build, ["release_and_tracing", "runtime_configuration_sha256"]) == authority.runtimeConfigurationSha256, + Self.string(build, ["emulator", "path"]) == base.emulatorPath, + Self.string(build, ["emulator", "sha256"]) == base.emulatorSha256, + Self.strings(build, ["emulator", "uuids"]) == emulatorUuids, + Self.string(build, ["gfxstream_backend", "path"]) == base.gfxstreamBackendPath, + Self.string(build, ["gfxstream_backend", "sha256"]) == base.gfxstreamBackendSha256, + Self.strings(build, ["gfxstream_backend", "uuids"]) == gfxstreamUuids else { + throw TFTMACRuntimeModeError(message: "Diagnostic build receipt structure drifted.") + } + + let clone = try Self.readSealedReceipt(authority.clone) + guard Self.string(clone, ["state"]) == authority.clone.requiredState, + Self.string(clone, ["build_id"]) == authority.buildId, + Self.string(clone, ["diagnostic_avd", "name"]) == base.avdName, + Self.string(clone, ["diagnostic_avd", "root"]) == base.avdHome, + Self.string(clone, ["diagnostic_avd", "avd_path"]) == base.avdDirectory, + Self.string(clone, ["diagnostic_avd", "ini_path"]) == base.avdIniPath, + Self.string(clone, ["diagnostic_avd", "config_sha256"]) == base.avdConfigSha256, + Self.string(clone, ["diagnostic_avd", "ini_sha256"]) == base.avdIniSha256, + Self.int(clone, ["diagnostic_avd", "adb_server_port"]) == base.adbServerPort, + Self.int(clone, ["diagnostic_avd", "console_port"]) == base.consolePort, + Self.string(clone, ["diagnostic_avd", "serial"]) == base.serial, + Self.string(clone, ["accepted_build", "sha256"]) == authority.build.sha256, + Self.bool(clone, ["control_noninterference_matched"]) == true, + Self.bool(clone, ["sealed_before_first_boot"]) == true, + Self.bool(clone, ["first_boot_attempted"]) == false, + Self.bool(clone, ["launch_attempted"]) == false, + Self.bool(clone, ["control_runtime_mutation_attempted"]) == false, + Self.bool(clone, ["control_avd_touched"]) == false else { + throw TFTMACRuntimeModeError(message: "Diagnostic stopped-clone receipt structure drifted.") + } + + let nativeHost = try Self.readSealedReceipt(authority.nativeHost) + guard let expectedHostExecutableSha256 = host.executableSha256 else { + throw TFTMACRuntimeModeError(message: "Diagnostic native-host executable SHA-256 authority is missing.") + } + let expectedHostPath = host.path + let expectedExecutable = URL(fileURLWithPath: expectedHostPath, isDirectory: true) + .appendingPathComponent(host.executableRelativePath).path + guard Self.string(nativeHost, ["state"]) == authority.nativeHost.requiredState, + Self.string(nativeHost, ["build_id"]) == authority.buildId, + Self.string(nativeHost, ["app", "path"]) == expectedHostPath, + Self.string(nativeHost, ["app", "bundle_identifier"]) == host.bundleIdentifier, + Self.string(nativeHost, ["app", "executable", "path"]) == expectedExecutable, + Self.string(nativeHost, ["app", "executable", "sha256"]) == expectedHostExecutableSha256, + Self.int(nativeHost, ["app", "codesign_verify_status"]) == 0, + Self.string(nativeHost, ["launch_contract", "method"])?.contains("/usr/bin/open") == true, + Self.string(nativeHost, ["launch_contract", "emulator_spawn_owner"]) == "NATIVE_MACOS_APP_PROCESS", + Self.bool(nativeHost, ["launch_contract", "service_context_emulator_spawn_forbidden"]) == true, + Self.bool(nativeHost, ["control_runtime_mutation_attempted"]) == false else { + throw TFTMACRuntimeModeError(message: "Diagnostic native-host receipt structure drifted.") + } + } + + private static func readSealedReceipt(_ reference: TFTMACSealedReceiptReference) throws -> [String: Any] { + guard isSHA256(reference.sha256) else { + throw TFTMACRuntimeModeError(message: "Receipt authority contains an invalid SHA-256.") + } + try validateSHA256(path: reference.path, expected: reference.sha256, label: "sealed receipt") + let sidecarPath = "\(reference.path).sha256" + guard let sidecar = try? String(contentsOfFile: sidecarPath, encoding: .utf8), + sidecar.split(whereSeparator: \.isWhitespace).first.map(String.init) == reference.sha256 else { + throw TFTMACRuntimeModeError(message: "Sealed receipt sidecar is missing or mismatched: \(sidecarPath)") + } + let data = try Data(contentsOf: URL(fileURLWithPath: reference.path)) + guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { + throw TFTMACRuntimeModeError(message: "Sealed receipt is not a JSON object: \(reference.path)") + } + return object + } + + private static func value(_ object: [String: Any], _ path: [String]) -> Any? { + var current: Any = object + for component in path { + guard let dictionary = current as? [String: Any], let next = dictionary[component] else { return nil } + current = next + } + return current + } + + private static func string(_ object: [String: Any], _ path: [String]) -> String? { + value(object, path) as? String + } + + private static func strings(_ object: [String: Any], _ path: [String]) -> [String]? { + value(object, path) as? [String] + } + + private static func bool(_ object: [String: Any], _ path: [String]) -> Bool? { + value(object, path) as? Bool + } + + private static func int(_ object: [String: Any], _ path: [String]) -> Int? { + (value(object, path) as? NSNumber)?.intValue + } + + private static func validateSHA256(path: String, expected: String, label: String) throws { + guard isSHA256(expected) else { + throw TFTMACRuntimeModeError(message: "\(label) authority is not a SHA-256 value.") + } + let url = URL(fileURLWithPath: path) + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError(message: "Could not open \(label) at \(path): \(error.localizedDescription)") + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError(message: "Could not hash \(label): \(error.localizedDescription)") + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected else { + throw TFTMACRuntimeModeError( + message: "\(label) SHA-256 mismatch: expected \(expected), observed \(observed)." + ) + } + } + + private static func validateUUIDs(path: String, expected: [String], label: String) throws { + guard !expected.isEmpty else { + throw TFTMACRuntimeModeError(message: "\(label) has no accepted Mach-O UUID authority.") + } + let result = try runCommand( + executable: "/usr/bin/dwarfdump", + arguments: ["--uuid", path], + timeout: 30 + ) + guard result.status == 0 else { + throw TFTMACRuntimeModeError(message: "Could not inspect \(label) Mach-O UUIDs.") + } + for identity in expected { + let parts = identity.split(separator: ":", maxSplits: 1).map(String.init) + guard parts.count == 2, + result.output.localizedCaseInsensitiveContains(parts[0]), + result.output.contains("(\(parts[1]))") else { + throw TFTMACRuntimeModeError(message: "\(label) Mach-O UUID identity drifted.") + } + } + } + + private struct CommandResult { + let status: Int32 + let output: String + } + + private static func runCommand( + executable: String, + arguments: [String], + timeout: TimeInterval + ) throws -> CommandResult { + let manager = FileManager.default + let root = manager.temporaryDirectory.appendingPathComponent( + "tftmac-runtime-authority-\(UUID().uuidString)", + isDirectory: true + ) + try manager.createDirectory(at: root, withIntermediateDirectories: true, attributes: [.posixPermissions: 0o700]) + defer { try? manager.removeItem(at: root) } + let stdoutURL = root.appendingPathComponent("stdout") + let stderrURL = root.appendingPathComponent("stderr") + manager.createFile(atPath: stdoutURL.path, contents: nil, attributes: [.posixPermissions: 0o600]) + manager.createFile(atPath: stderrURL.path, contents: nil, attributes: [.posixPermissions: 0o600]) + let stdout = try FileHandle(forWritingTo: stdoutURL) + let stderr = try FileHandle(forWritingTo: stderrURL) + defer { + try? stdout.close() + try? stderr.close() + } + let process = Process() + process.executableURL = URL(fileURLWithPath: executable) + process.arguments = arguments + process.standardOutput = stdout + process.standardError = stderr + do { + try process.run() + } catch { + throw TFTMACRuntimeModeError( + message: "Could not execute \(executable): \(error.localizedDescription)" + ) + } + let deadline = Date().addingTimeInterval(timeout) + while process.isRunning && Date() < deadline { + Thread.sleep(forTimeInterval: 0.02) + } + if process.isRunning { + process.terminate() + Thread.sleep(forTimeInterval: 0.2) + if process.isRunning { Darwin.kill(process.processIdentifier, SIGKILL) } + } + process.waitUntilExit() + try stdout.synchronize() + try stderr.synchronize() + let out = (try? String(contentsOf: stdoutURL, encoding: .utf8)) ?? "" + let err = (try? String(contentsOf: stderrURL, encoding: .utf8)) ?? "" + return CommandResult(status: process.terminationStatus, output: out + err) + } + + private static func processExecutablePath(_ processIdentifier: Int32) throws -> String { + var buffer = [CChar](repeating: 0, count: 4096) + let count = buffer.withUnsafeMutableBufferPointer { + proc_pidpath(processIdentifier, $0.baseAddress, UInt32($0.count)) + } + guard count > 0 else { + throw TFTMACRuntimeModeError( + message: "Could not resolve loaded emulator process path for PID \(processIdentifier)." + ) + } + return String(cString: buffer) + } + + private static func standardized(_ path: String) -> String { + URL(fileURLWithPath: path).standardizedFileURL.resolvingSymlinksInPath().path + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/VALIDATION_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/VALIDATION_RECEIPT.json new file mode 100644 index 0000000..44c0acc --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/VALIDATION_RECEIPT.json @@ -0,0 +1,33 @@ +{ + "schema": 1, + "state": "WAVE_B_V4_SOURCE_VALIDATION_PASS", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "verified_at": "2026-09-02T02:07:03Z", + "base_head_sha": "3326792efc694e853312aa7347abcb1edd96575a", + "verifier": { + "path": "scripts/verify-tftmac.command", + "sha256": "e63c9a767e7d71dde4f75711f3e08a04e88cad9f6e0efb6638e7e3c8a67ad3d4", + "exit_code": 0, + "result": "TFTMAC source validation: OK (unsigned Release build; 49 native tests; Wave B mode authority PASS)" + }, + "implementation_receipt_sha256": "af9e9c1c5612f9fb085fbd653dced0d3f8b0cfdf281bd2d5417b5a5ca297aab5", + "runtime_modes_sha256": "136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479", + "unsigned_release_build": "PASS", + "native_tests": { + "executed": 49, + "failures": 0, + "unexpected_failures": 0 + }, + "runtime_effects": { + "emulator_process_active_after_validation": false, + "tftmac_process_active_after_validation": false, + "emulator_launch_attempted": false, + "runtime_replacement_attempted": false, + "control_stop_attempted": false, + "installed_app_replacement_attempted": false, + "package_launch_attempted": false + }, + "nonblocking_warning": "RuntimeModeAuthority.swift uses deprecated String(cString:); it does not fail the build or tests and is outside this correction scope.", + "next_safe_action": "Allocate and seal a collision-free diagnostic EmulatorController port, then run the separately guarded diagnostic first-boot gate." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/ZENGATE_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/ZENGATE_RECEIPT.json new file mode 100644 index 0000000..18212e7 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/ZENGATE_RECEIPT.json @@ -0,0 +1,33 @@ +{ + "schema": 1, + "result": "PASS", + "gate": "TARGETED_WAVE_B_V4_CORRECTION_ZENGATE", + "version": "2.3", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-02T02:00:39Z", + "applicability": "APPLICABLE", + "hard_gates": { + "win_condition": "PASS", + "source_of_truth": "PASS", + "material_ambiguity": "PASS", + "safety_reversibility": "PASS", + "validation_integrity": "PASS", + "project_constraints": "PASS" + }, + "weighted_quality": 95.0, + "risk_penalty": 1.0, + "final_score": 94.0, + "decision": "PROCEED", + "remediation_mode": "NONE", + "original_plan_sha256": "78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b", + "scope_lock_sha256": "dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e", + "correction_amendment_sha256": "18e85884498c52144f3e56217eb372b78289b6d938c5c92c0459a35882296b15", + "preflight_sha256": "6e8e415d921d0517d00a82101125340f109f9ca8bd3824b9ab9a130939054cfe", + "win_condition": "The exact recorded head accepts the bounded Wave B source integration, builds unsigned Release, passes all 49 native tests, and produces zero runtime effects.", + "residual_accepted_risks": [ + "The source-only verifier does not authorize diagnostic first boot.", + "Final signed installation remains a later operational gate and does not affect this source wave." + ], + "execution_scope_lock": "Implement only the proven Wave B continuation corrections and minimum generated source/test/project changes. Preserve v3 and protected work. Do not launch, install, sign, refactor, optimize, or begin Wave C." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/apply-waveb-v4.mjs b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/apply-waveb-v4.mjs new file mode 100644 index 0000000..a44db86 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/apply-waveb-v4.mjs @@ -0,0 +1,1330 @@ +#!/usr/bin/env node +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { execFileSync } from 'node:child_process'; + +const root = process.cwd(); +const changeId = '215ec5a3-6554-4ca3-95db-1525433bb20f'; +const expectedHead = '3326792efc694e853312aa7347abcb1edd96575a'; +const planRoot = '.clara/plans/tftmac-causal-graphics-v1'; +const waveRoot = `${planRoot}/wave-b-v4`; +const expected = { + [`${planRoot}/IMPLEMENTATION_PLAN.md`]: '78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b', + [`${planRoot}/SCOPE_LOCK.txt`]: 'dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e', + [`${waveRoot}/CORRECTION_AMENDMENT.md`]: '18e85884498c52144f3e56217eb372b78289b6d938c5c92c0459a35882296b15', + [`${waveRoot}/PREFLIGHT.json`]: '6e8e415d921d0517d00a82101125340f109f9ca8bd3824b9ab9a130939054cfe', + [`${waveRoot}/ZENGATE_RECEIPT.json`]: '35c9fbf5e295fd33a4ead854da72a3ac972620f4a4cd0205f5e6ebaa03b06c49', + [`${waveRoot}/RuntimeMode.swift.template`]: 'e57dafefcd8d1cbdc20dc5494b02b81736bf23d8c53006ecedc87c8b37259aa7', + [`${waveRoot}/RuntimeLease.swift.template`]: 'f2a8f06ede29f06c57f038fd94f48047cd796ccf138d05b1d2e0bdd0de160cdc', + [`${waveRoot}/RuntimeModeAuthority.swift.template`]: '3ab10d59a94ef4e60e920290a940a55a624a0209a7fe6e05abe65fdfaf040c59', + [`${waveRoot}/validate-waveb-v4.mjs`]: '594ed6fce8c4897c1db83d90a425973805e2590267ea10bb29dc24550194a724', + 'ssot/runtime-modes.json': '81086498d8a16f2096f8461922731d7cf5c027cf6163d874452c16ffa543fdb2', + 'ssot/runtime-authority.json': '2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f', + 'tftmac/App/AppCoordinator.swift': 'd0eb27df9a0e6aaa45ff60c63fd81bc229350a6f8feca833b776bbe4a954bda4', + 'tftmac/Runtime/RuntimeLease.swift': '55a44dbd5fc8b112cb48d17e879c00ae068161f2755af1876244e03bf75b498b', + 'tftmac/Runtime/RuntimeProfile.swift': '93b5ac436f4f1f315b343151cacc304d76337ac39c996df7dee38ffa48909bae', + 'tftmac/Runtime/TFTMACRuntime.swift': '8932032d93af01b46e46b5fb5a04eff1ec457f2f0e8f92f364d5a1a703ab5a5f', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift': '3a3302778bda256a9e2977cf2de51827867f211b97f5bf9f74e41389ecd0b7fb', + 'TFTMAC.xcodeproj/project.pbxproj': '4961d37cc1802ca179b7f115ff4be3a4f1c222e706a01aff9f137fcb27c57dfd', + 'scripts/build-native-app.command': '9bedc13dab3f395a75e8b74fccbeaff92209ddd48b1a83e368768196fd96ae0f', + 'scripts/verify-tftmac.command': 'd58721d6c06cd321052b150184b970f46b5977afe50c2ef6470ed4999dd5a84d', + 'RuntimeHost/main.c': 'c749cd998a6f066e2f7a6ef818eecf05b90d1a8808f6c9966e0b5fc21affeeed', + 'RuntimeHost/Info.plist': 'cab05fb3b54fb76c9b1b85e9f6a66aebcc5b91bed98c757b603db89e2b7939ca' +}; +const identities = { + control: { + adb: '1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b', + emulator: 'b3b8fc0dcedcf6e15b54b41f3e5156319029aa00b88a59fd489f80abdd8fc133', + emulatorUUIDs: ['4C4C449E-5555-3144-A182-644CCB895091:arm64'], + qemu: 'eaa97a970b81f81640db73ed79e19ee173323653a0a1203217e1199d078011f3', + qemuUUIDs: ['4C4C4467-5555-3144-A10A-A9E5A99446F1:arm64'], + gfxstream: '3772fef215058831ea419c9281fd203d010003d5defdc195dd120bc7748e4093', + gfxstreamUUIDs: ['4C4C4406-5555-3144-A122-8AC522465662:arm64'] + }, + diagnostic: { + adb: '1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b', + emulator: 'fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa', + emulatorUUIDs: ['4C4C4436-5555-3144-A1EE-05B0F446F580:arm64'], + qemu: '042c4932b17fd09ff056ecc2dd21084e08e1110b774c594bbcaf1e4d1ceac608', + qemuUUIDs: ['4C4C447F-5555-3144-A16C-0DB6C4482B7A:arm64'], + gfxstream: '23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d', + gfxstreamUUIDs: ['4C4C4449-5555-3144-A1FC-F6DFE0021481:arm64'] + } +}; + +function fail(message) { console.error(`WAVE_B_V4_APPLY_FAILED: ${message}`); process.exit(1); } +function ensure(value, message) { if (!value) fail(message); } +function absolute(relativePath) { return path.join(root, relativePath); } +function sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function fileSha(relativePath) { return sha256(fs.readFileSync(absolute(relativePath))); } +function externalSha(filePath) { return sha256(fs.readFileSync(filePath)); } +function git(...args) { return execFileSync('/usr/bin/git', args, { cwd: root, encoding: 'utf8' }); } +function readText(relativePath) { return fs.readFileSync(absolute(relativePath), 'utf8'); } +function replaceOnce(text, before, after, label) { + const count = text.split(before).length - 1; + ensure(count === 1, `${label}: expected one anchor, found ${count}`); + return text.replace(before, after); +} +function replaceSection(text, startMarker, endMarker, replacement, label) { + const start = text.indexOf(startMarker); + const end = text.indexOf(endMarker, start + startMarker.length); + ensure(start >= 0 && end > start, `${label}: section anchors were not found`); + ensure(text.indexOf(startMarker, start + 1) < 0, `${label}: start anchor is not unique`); + return text.slice(0, start) + replacement + text.slice(end); +} +function writeAtomic(relativePath, content, mode = 0o644) { + const destination = absolute(relativePath); + fs.mkdirSync(path.dirname(destination), { recursive: true }); + const temporary = `${destination}.waveb-v4-${process.pid}`; + fs.writeFileSync(temporary, content, { mode }); + fs.renameSync(temporary, destination); + fs.chmodSync(destination, mode); +} +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], ['launch_state', mode.launch_state], ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], ['library_root', mode.library_root], ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 ?? ''], ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 ?? ''], ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], ['avd_name', mode.avd_name], ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], ['avd_config_sha256', mode.avd_config_sha256 ?? ''], + ['avd_ini_path', mode.avd_ini_path], ['avd_ini_sha256', mode.avd_ini_sha256 ?? ''], + ['adb_server_port', mode.adb_server_port], ['console_port', mode.console_port], + ['controller_port', mode.controller_port ?? ''], ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 ?? ''], ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha256(Buffer.from(fields.map(([key, value]) => `${key}=${value}`).join('\n'))); +} + +ensure(git('rev-parse', 'HEAD').trim() === expectedHead, 'managed change HEAD drifted'); +ensure(git('status', '--porcelain=v1', '--untracked-files=no').trim() === '', 'tracked worktree changed before guarded apply'); +for (const [relativePath, expectedSha] of Object.entries(expected)) { + ensure(fs.existsSync(absolute(relativePath)), `required input is missing: ${relativePath}`); + ensure(fileSha(relativePath) === expectedSha, `input SHA-256 drifted: ${relativePath}`); +} +for (const [filePath, expectedSha] of [ + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb', identities.control.adb], + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator', identities.control.emulator], + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64', identities.control.qemu], + ['/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64/libgfxstream_backend.dylib', identities.control.gfxstream], + ['/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator', identities.diagnostic.emulator], + ['/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64', identities.diagnostic.qemu], + ['/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib', identities.diagnostic.gfxstream] +]) ensure(externalSha(filePath) === expectedSha, `external binary identity drifted: ${filePath}`); + +const registry = JSON.parse(readText('ssot/runtime-modes.json')); +registry.contract = 'TFTMAC_RUNTIME_MODES_V1'; +registry.selection_environment_variable = 'TFTMAC_RUNTIME_MODE'; +const control = registry.modes.control; +Object.assign(control, { + emulator_sha256: identities.control.emulator, + gfxstream_backend_sha256: identities.control.gfxstream, + state_namespace: 'control', + uses_legacy_application_support_root: true, + emulator_identifier: 'TFTMAC', + launch_strategy: 'bundled_forwarder', + profile_policy: 'validated_native_preferences', + locked_profile: null, + adb_sha256: identities.control.adb, + adb_vendor_keys_policy: 'ABSENT', + expected_emulator_version_contains: '37.1.11', + emulator_uuids: identities.control.emulatorUUIDs, + qemu_path: '/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64', + qemu_sha256: identities.control.qemu, + qemu_uuids: identities.control.qemuUUIDs, + gfxstream_backend_uuids: identities.control.gfxstreamUUIDs, + host_application: { + kind: 'bundled_resource', + path: 'TFTMAC Emulator Host.app', + bundle_identifier: 'com.flashls1.tftmac.emulator-host', + executable_relative_path: 'Contents/MacOS/TFTMACEmulatorHost', + executable_sha256: null, + source_path: 'RuntimeHost/main.c', + source_sha256: expected['RuntimeHost/main.c'], + info_plist_path: 'RuntimeHost/Info.plist', + info_plist_sha256: expected['RuntimeHost/Info.plist'], + build_receipt_resource: 'control-host-build.json' + }, + diagnostic_receipts: null +}); +control.configuration_sha256 = configurationHash(control); + +const diagnostic = registry.modes.advanced_diagnostics; +Object.assign(diagnostic, { + state_namespace: 'advanced_diagnostics', + uses_legacy_application_support_root: false, + emulator_identifier: 'TFTMAC-DIAGNOSTIC', + launch_strategy: 'external_native_host', + profile_policy: 'fixed_registry_profile', + locked_profile: { + identifier: 'tftmac_diagnostic_r9', width: 1920, height: 1080, density_dpi: 280, refresh_hz: 60, + vcpu: 6, ram_mib: 6144, gpu_mode: 'host', audio_backend: 'coreaudio', graphics_transport: 'pipe', + asg_write_buffer_size: 1048576, asg_write_step_size: 4096, asg_data_ring_size: 32768, + asg_draw_flush_interval: 800, + angle_enabled_features: 'exposeNonConformantExtensionsAndVersions:exposeES32ForTesting', + angle_disabled_features: 'preferSubmitAtFBOBoundary' + }, + adb_sha256: identities.diagnostic.adb, + adb_vendor_keys_policy: 'USER_DEFAULT_KEY', + expected_emulator_version_contains: '35.6.3', + emulator_uuids: identities.diagnostic.emulatorUUIDs, + qemu_path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64', + qemu_sha256: identities.diagnostic.qemu, + qemu_uuids: identities.diagnostic.qemuUUIDs, + gfxstream_backend_uuids: identities.diagnostic.gfxstreamUUIDs, + host_application: { + kind: 'external_application', + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/TFTMAC Diagnostic Host.app', + bundle_identifier: 'com.flashls1.tftmac.runtime.diagnostics', + executable_relative_path: 'Contents/MacOS/TFTMACApp', + executable_sha256: 'd335a23d710956f96a4c01f977d49437424c9fd52ccc20ed872e5786d206eef2', + source_path: null, + source_sha256: null, + info_plist_path: null, + info_plist_sha256: '4e15592461ce8a50f17ccd6285fd12fcd84dd407eba86919f90c8c0026b5ca61', + build_receipt_resource: null + }, + diagnostic_receipts: { + build_id: 'gate4-r9-20260901', + runtime_configuration_sha256: '005c85a2a7ffe86e7626c871fd3dd23f42c5d3ce994162d17b032e69cfc4d4f3', + build: { + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json', + sha256: '9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d', + required_state: 'DIAGNOSTIC_BUILD_IDENTITY_PASS' + }, + clone: { + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json', + sha256: '09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648', + required_state: 'DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS' + }, + native_host: { + path: '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json', + sha256: 'a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067', + required_state: 'DIAGNOSTIC_NATIVE_HOST_BUILD_PASS' + } + } +}); +diagnostic.configuration_sha256 = configurationHash(diagnostic); + +const candidate = registry.modes.candidate; +Object.assign(candidate, { + state_namespace: 'candidate', + uses_legacy_application_support_root: false, + emulator_identifier: 'TFTMAC-CANDIDATE', + launch_strategy: 'blocked', + profile_policy: 'blocked', + locked_profile: null, + adb_sha256: null, + adb_vendor_keys_policy: 'UNRESOLVED', + expected_emulator_version_contains: null, + emulator_uuids: null, + qemu_path: '/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64', + qemu_sha256: null, + qemu_uuids: null, + gfxstream_backend_uuids: null, + host_application: null, + diagnostic_receipts: null +}); +candidate.configuration_sha256 = configurationHash(candidate); + +const portOwners = new Map(); +for (const [modeName, mode] of Object.entries(registry.modes)) { + ensure(mode.serial === `emulator-${mode.console_port}`, `${modeName} serial/console mismatch`); + for (const [kind, value] of [['adb', mode.adb_server_port], ['console', mode.console_port], ['controller', mode.controller_port]]) { + if (value === null) continue; + ensure(!portOwners.has(value), `port collision: ${value}`); + portOwners.set(value, `${modeName}.${kind}`); + } +} +ensure(diagnostic.launch_state === 'blocked_pending_controller_lease' && diagnostic.controller_port === null, 'diagnostics must remain blocked'); +ensure(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate must remain blocked'); +const registryText = `${JSON.stringify(registry, null, 2)}\n`; +const registrySha = sha256(Buffer.from(registryText)); + +const modeTemplate = readText(`${waveRoot}/RuntimeMode.swift.template`); +ensure(modeTemplate.includes('__EXPECTED_RUNTIME_MODES_SHA256__'), 'runtime mode template placeholder is missing'); +const runtimeModeSource = modeTemplate.replace('__EXPECTED_RUNTIME_MODES_SHA256__', registrySha); +const runtimeModeAuthoritySource = readText(`${waveRoot}/RuntimeModeAuthority.swift.template`); +const runtimeLeaseSource = readText(`${waveRoot}/RuntimeLease.swift.template`); + +const pathsBlock = `struct TFTMACRuntimePaths: Sendable { + let mode: TFTMACRuntimeMode + let registrySha256: String + let configurationSha256: String + let runtimeRoot: URL + let sdkRoot: URL + let libraryRoot: URL + let emulator: URL + let qemu: URL + let gfxstreamBackend: URL + let adb: URL + let avdHome: URL + let avdName: String + let avdDirectory: URL + let avdConfig: URL + let avdINI: URL + let hostApplication: URL + let applicationSupport: URL + let globalApplicationSupport: URL + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + let emulatorIdentifier: String + let launchStrategy: TFTMACRuntimeLaunchStrategy + let adbVendorKeysPolicy: String + + static func discover( + configuration: TFTMACSelectedRuntimeConfiguration, + bundle: Bundle = .main + ) throws -> Self { + let selection = configuration.selection + let definition = selection.definition + let resolved = try configuration.authority.resolveForLaunch( + selection: selection, + bundle: bundle + ) + guard let controllerPort = definition.controllerPort, + let qemuPath = resolved.supplemental.qemuPath else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \\(selection.mode.rawValue) has no accepted launch lease." + ) + } + return Self( + mode: selection.mode, + registrySha256: selection.registrySha256, + configurationSha256: definition.configurationSha256, + runtimeRoot: URL(fileURLWithPath: definition.runtimeRoot, isDirectory: true), + sdkRoot: URL(fileURLWithPath: definition.sdkRoot, isDirectory: true), + libraryRoot: URL(fileURLWithPath: definition.libraryRoot, isDirectory: true), + emulator: URL(fileURLWithPath: definition.emulatorPath), + qemu: URL(fileURLWithPath: qemuPath), + gfxstreamBackend: URL(fileURLWithPath: definition.gfxstreamBackendPath), + adb: URL(fileURLWithPath: definition.adbPath), + avdHome: URL(fileURLWithPath: definition.avdHome, isDirectory: true), + avdName: definition.avdName, + avdDirectory: URL(fileURLWithPath: definition.avdDirectory, isDirectory: true), + avdConfig: URL(fileURLWithPath: definition.avdConfigPath), + avdINI: URL(fileURLWithPath: definition.avdIniPath), + hostApplication: resolved.hostApplication, + applicationSupport: resolved.applicationSupport, + globalApplicationSupport: resolved.globalApplicationSupport, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial, + emulatorIdentifier: resolved.supplemental.emulatorIdentifier, + launchStrategy: resolved.supplemental.launchStrategy, + adbVendorKeysPolicy: resolved.supplemental.adbVendorKeysPolicy + ) + } +} + +`; + +let runtime = readText('tftmac/Runtime/TFTMACRuntime.swift'); +runtime = replaceSection(runtime, 'struct TFTMACRuntimePaths: Sendable {', 'struct EmulatorControllerDiscovery: Sendable {', pathsBlock, 'runtime paths'); +runtime = replaceOnce(runtime, ` private let profile: TFTMACRuntimeProfile + private let mailbox: LatestFrameMailbox +`, ` private let runtimeConfiguration: TFTMACSelectedRuntimeConfiguration + private let profile: TFTMACRuntimeProfile + private let mailbox: LatestFrameMailbox +`, 'runtime configuration field'); +runtime = replaceOnce(runtime, ` init( + profile: TFTMACRuntimeProfile, + mailbox: LatestFrameMailbox, + status: @escaping StatusHandler, + gameFrame: @escaping GameFrameHandler + ) { + self.profile = profile + self.mailbox = mailbox + self.status = status + self.gameFrame = gameFrame + } +`, ` init( + runtimeConfiguration: TFTMACSelectedRuntimeConfiguration, + mailbox: LatestFrameMailbox, + status: @escaping StatusHandler, + gameFrame: @escaping GameFrameHandler + ) { + self.runtimeConfiguration = runtimeConfiguration + self.profile = runtimeConfiguration.profile + self.mailbox = mailbox + self.status = status + self.gameFrame = gameFrame + } +`, 'runtime service initializer'); + +const runFunction = ` func run() async throws { + await status("Validating the selected TFTMAC runtime identity…", false) + do { + let paths = try TFTMACRuntimePaths.discover(configuration: runtimeConfiguration) + self.paths = paths + let telemetry = try TFTMACNativeTelemetry( + profile: profile, + applicationSupport: paths.applicationSupport + ) + self.telemetry = telemetry + labStore = try CombatBenchmarkLabStore(applicationSupport: paths.applicationSupport) + await status("Starting Android through the native Mac app host…", false) + + let leaseIdentity = try runtimeConfiguration.selection.leaseIdentity() + let globalStateRoot = paths.globalApplicationSupport + .appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire( + stateRoot: globalStateRoot, + identity: leaseIdentity + ) + telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ + "lease": runtimeConfiguration.registry.document.activeLeaseRelativePath, + "pid": ProcessInfo.processInfo.processIdentifier, + "exclusive": true, + "mode": paths.mode.rawValue, + "registry_sha256": paths.registrySha256, + "configuration_sha256": paths.configurationSha256, + "avd": paths.avdName, + "adb_server_port": paths.adbServerPort, + "console_port": paths.consolePort, + "controller_port": paths.controllerPort, + "serial": paths.serial + ]) + try assertRuntimeUnoccupied(paths: paths, telemetry: telemetry) + try recoverInterruptedAVDTransaction(paths: paths) + recordFrozenReceipts(telemetry: telemetry, paths: paths) + avdTransaction = try prepareAVD(paths: paths, telemetry: telemetry) + try startADBServer(paths: paths, telemetry: telemetry) + let launchStarted = Date() + try launchEmulatorHost(paths: paths, telemetry: telemetry) + let discovery = try await waitForDiscovery( + paths: paths, + captureDirectory: telemetry.captureDirectory, + after: launchStarted + ) + guard discovery.port == paths.controllerPort else { + throw TFTMACRuntimeError( + "The emulator published controller port \\(discovery.port), not the accepted port \\(paths.controllerPort)." + ) + } + self.discovery = discovery + telemetry.recordEvent("EMULATOR_CONTROLLER_DISCOVERED", payload: [ + "pid": discovery.processIdentifier, + "grpc_port": discovery.port, + "record": discovery.recordPath, + "token_persisted": false, + "mode": paths.mode.rawValue + ]) + let loadedIdentity = try runtimeConfiguration.authority.validateLoadedRuntime( + processIdentifier: discovery.processIdentifier, + selection: runtimeConfiguration.selection + ) + telemetry.recordEvent("LOADED_RUNTIME_IDENTITY_PASS", payload: [ + "pid": loadedIdentity.processIdentifier, + "mode": paths.mode.rawValue, + "qemu_path": loadedIdentity.qemuPath, + "qemu_sha256": loadedIdentity.qemuSha256, + "qemu_uuids": loadedIdentity.qemuUuids, + "gfxstream_backend_path": loadedIdentity.gfxstreamBackendPath, + "gfxstream_backend_sha256": loadedIdentity.gfxstreamBackendSha256, + "gfxstream_backend_uuids": loadedIdentity.gfxstreamBackendUuids + ]) + try recordHostSchedulingReceipt(telemetry: telemetry) + + let (inputStream, continuation) = AsyncStream.makeStream( + of: EmulatorInput.self, + bufferingPolicy: .bufferingNewest(256) + ) + inputContinuation = continuation + try await withThrowingTaskGroup(of: Void.self) { group in + group.addTask { [profile, mailbox] in + try await Self.runController( + discovery: discovery, + profile: profile, + mailbox: mailbox, + telemetry: telemetry, + inputStream: inputStream, + status: self.status + ) + } + group.addTask { + try await self.waitForBootAndLaunchGame(paths: paths, telemetry: telemetry) + } + group.addTask { + try await self.sampleRuntime( + paths: paths, + telemetry: telemetry, + emulatorPID: discovery.processIdentifier + ) + } + group.addTask { + try await self.sampleGameFrames(paths: paths, telemetry: telemetry) + } + _ = try await group.next() + group.cancelAll() + } + if !stopping { throw TFTMACRuntimeError("The native emulator session ended unexpectedly.") } + } catch { + if stopping || error is CancellationError { + telemetry?.recordEvent("RUNTIME_STOP_REQUESTED", payload: ["reason": "application_termination"]) + await cleanup(status: "STOPPED") + return + } + telemetry?.recordEvent("RUNTIME_FAILED", payload: [ + "error": error.localizedDescription, + "diagnostic": String(describing: error), + "type": String(reflecting: type(of: error)), + "mode": runtimeConfiguration.selection.mode.rawValue + ]) + if profile.experimentPreset.isActiveCandidate { + recordCorrectnessRejection(reason: error.localizedDescription) + TFTMACRuntimeProfile.playable.with(experimentPreset: .control).save() + telemetry?.recordEvent("EXPERIMENT_AUTO_ROLLBACK", payload: [ + "failed_preset": profile.experimentPreset.rawValue, + "restored_preset": RuntimeExperimentPreset.control.rawValue, + "classification": "REJECTED_CORRECTNESS", + "applies_after_restart": true + ]) + } + await cleanup(status: stopping ? "STOPPED" : "FAILED") + if !stopping { await status(error.localizedDescription, true) } + throw error + } + await cleanup(status: "STOPPED") + } + +`; +runtime = replaceSection(runtime, ' func run() async throws {', ' func sendMouse(_ input: MouseInput) {', runFunction, 'runtime run'); + +runtime = replaceOnce(runtime, +` Self.processMatchesLaunchedIdentity(ownedPID, sessionMarker: expectedSessionMarker) {`, +` Self.processMatchesLaunchedIdentity(ownedPID, paths: paths, sessionMarker: expectedSessionMarker) {`, +'stop ownership check'); +runtime = replaceOnce(runtime, +` telemetry?.recordEvent("EMULATOR_STOP_SIGNAL_SENT", payload: [ + "pid": ownedPID, + "serial": "emulator-5582",`, +` telemetry?.recordEvent("EMULATOR_STOP_SIGNAL_SENT", payload: [ + "pid": ownedPID, + "serial": paths.serial,`, +'stop serial'); +runtime = replaceOnce(runtime, +` _ = try? Self.runCommand( + paths.adb, + ["-P", "5038", "-s", "emulator-5582", "emu", "kill"],`, +` _ = try? Self.runCommand( + paths.adb, + ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "emu", "kill"],`, +'stop adb identity'); +runtime = replaceOnce(runtime, +` let ownedPID = discovery?.processIdentifier ?? expectedSessionMarker.flatMap(Self.findOwnedEmulatorPID)`, +` let ownedPID = discovery?.processIdentifier ?? expectedSessionMarker.flatMap { marker in + Self.findOwnedEmulatorPID(sessionMarker: marker, paths: paths) + }`, +'cleanup owner lookup'); +runtime = replaceOnce(runtime, +` ownedProcessExists && Self.processMatchesLaunchedIdentity($0, sessionMarker: expectedSessionMarker)`, +` ownedProcessExists && Self.processMatchesLaunchedIdentity( + $0, + paths: paths, + sessionMarker: expectedSessionMarker + )`, +'cleanup ownership verification'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "emu", "kill"],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "emu", "kill"],`, +'cleanup adb identity'); +runtime = replaceOnce(runtime, +` payload: ["pid": ownedPID ?? 0, "serial": "emulator-5582", "owned": ownsRunningEmulator]`, +` payload: ["pid": ownedPID ?? 0, "serial": paths.serial, "owned": ownsRunningEmulator]`, +'cleanup telemetry identity'); +runtime = replaceOnce(runtime, +` guard !Self.anyEmulatorUsingSharedAVD() else { + throw TFTMACRuntimeError("AVD restore was withheld because another TFT_Ultra_Tablet process is active.") + }`, +` guard !Self.anyEmulatorUsingSelectedAVD(paths: paths) else { + throw TFTMACRuntimeError( + "AVD restore was withheld because another \\(paths.avdName) process is active." + ) + }`, +'cleanup selected AVD'); +runtime = replaceOnce(runtime, +` if let transaction = avdTransaction { + do { + guard emulatorExitConfirmed else {`, +` if let transaction = avdTransaction { + do { + guard let paths else { + throw TFTMACRuntimeError("AVD restore was withheld because the launched runtime identity is unavailable.") + } + guard emulatorExitConfirmed else {`, +'cleanup path identity'); + +runtime = replaceOnce(runtime, +` process.arguments = ["-P", "5038", "-s", "emulator-5582", "logcat", "-v", "threadtime", "-T", sessionStartSelector]`, +` process.arguments = [ + "-P", "\\(paths.adbServerPort)", "-s", paths.serial, + "logcat", "-v", "threadtime", "-T", sessionStartSelector + ]`, +'logcat identity'); + +const occupancyFunction = ` private func assertRuntimeUnoccupied( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + var definitions = [runtimeConfiguration.selection.definition] + if runtimeConfiguration.selection.definition.requiresControlStopped { + let control = try runtimeConfiguration.registry.definition(for: .control) + if control.mode != runtimeConfiguration.selection.mode { definitions.append(control) } + } + let processOutput = (try? Self.runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-axo", "pid=,command="], + timeout: 10 + ).output) ?? "" + let emulatorConflicts = processOutput.split(whereSeparator: \\.isNewline).filter { line in + guard line.contains("qemu-system-aarch64") else { return false } + return definitions.contains { definition in + line.contains("@\\(definition.avdName)") + || line.contains("-port \\(definition.consolePort)") + || definition.controllerPort.map { line.contains("-grpc \\($0)") } == true + } + } + let leasedPorts = Set(definitions.flatMap { definition -> [Int] in + [definition.consolePort] + (definition.controllerPort.map { [$0] } ?? []) + }).sorted() + var listenerArguments = ["-nP"] + for port in leasedPorts { listenerArguments.append("-iTCP:\\(port)") } + listenerArguments.append("-sTCP:LISTEN") + let listenerOutput = (try? Self.runCommand( + URL(fileURLWithPath: "/usr/sbin/lsof"), + listenerArguments, + timeout: 10 + ).output) ?? "" + let listeners = listenerOutput.split(whereSeparator: \\.isNewline).dropFirst() + guard emulatorConflicts.isEmpty && listeners.isEmpty else { + let modes = definitions.map(\\.mode.rawValue).joined(separator: ", ") + throw TFTMACRuntimeError( + "The selected runtime lease conflicts with an active \\(modes) emulator or port listener." + ) + } + let checkedIdentities: [[String: Any]] = definitions.map { definition in + [ + "mode": definition.mode.rawValue, + "avd": definition.avdName, + "console_port": definition.consolePort, + "controller_port": definition.controllerPort ?? 0, + "serial": definition.serial + ] + } + telemetry.recordEvent("RUNTIME_OWNERSHIP_PREFLIGHT_PASSED", payload: [ + "selected_mode": paths.mode.rawValue, + "checked_identities": checkedIdentities, + "existing_emulator_count": 0, + "existing_listener_count": 0 + ]) + } + +`; +runtime = replaceSection(runtime, ' private func assertRuntimeUnoccupied(telemetry: TFTMACNativeTelemetry) throws {', ' private func recordFrozenReceipts', occupancyFunction, 'runtime occupancy'); + +const receiptsFunction = ` private func recordFrozenReceipts( + telemetry: TFTMACNativeTelemetry, + paths: TFTMACRuntimePaths + ) { + let experimentReceipt = profile.experimentConfigurationReceipt + let receipts: [(String, String, String, String)] = [ + ("engine", "Unreal Engine", "user_locked_fact", "LOCKED"), + ("runtime_mode", paths.mode.rawValue, "sealed runtime-mode registry", "DIRECT"), + ("runtime_mode_registry_sha256", paths.registrySha256, "bundled signed registry", "DIRECT"), + ("runtime_mode_configuration_sha256", paths.configurationSha256, "sealed runtime-mode registry", "DIRECT"), + ("runtime_profile_id", profile.identifier, "validated mode profile", "DIRECT"), + ("runtime_experiment_preset", profile.experimentPreset.rawValue, "named launch experiment", "DIRECT"), + ("runtime_configuration_sha256", experimentReceipt.sha256, "canonical effective configuration", "DIRECT"), + ("runtime_configuration_json", experimentReceipt.canonicalJSON, "canonical effective configuration", "DIRECT"), + ("launcher_method", paths.launchStrategy.rawValue, "runtime-mode authority", "DIRECT"), + ("native_host_application", paths.hostApplication.path, "signed host authority", "DIRECT"), + ("macos_game_mode_eligible", "true", "LSSupportsGameMode bundle contract", "DIRECT"), + ("host_qos_requested", profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default", "named launch experiment", "REQUESTED"), + ("adb_server_port", "\\(paths.adbServerPort)", "runtime-mode lease", "DIRECT"), + ("emulator_console_port", "\\(paths.consolePort)", "runtime-mode lease", "DIRECT"), + ("adb_serial", paths.serial, "runtime-mode lease", "DIRECT"), + ("controller_port", "\\(paths.controllerPort)", "runtime-mode lease", "DIRECT"), + ("adb_vendor_keys", paths.adbVendorKeysPolicy, "runtime-mode authority", "DIRECT"), + ("avd", paths.avdName, "runtime-mode authority", "DIRECT"), + ("runtime_root", paths.runtimeRoot.path, "runtime-mode authority", "DIRECT"), + ("mode_application_support", paths.applicationSupport.path, "runtime-mode state isolation", "DIRECT"), + ("resolution", "\\(profile.width)x\\(profile.height)", "validated mode profile", "DIRECT"), + ("density_dpi", "\\(profile.densityDPI)", "validated mode profile", "DIRECT"), + ("refresh_hz", "\\(profile.refreshHz)", "validated mode profile", "DIRECT"), + ("vcpu", "\\(profile.vCPU)", "validated mode profile", "DIRECT"), + ("ram_mib", "\\(profile.ramMiB)", "validated mode profile", "DIRECT"), + ("gpu_mode", profile.gpuMode, "validated mode profile", "DIRECT"), + ("audio_backend", profile.audioBackend, "validated mode profile", "DIRECT"), + ("graphics_transport_requested", profile.graphicsTransport, "validated mode profile", "REQUESTED"), + ("emulator_features_requested", profile.effectiveEmulatorFeatures.joined(separator: ","), "named launch experiment", "REQUESTED"), + ("asg_write_buffer_size", "\\(profile.asgWriteBufferSize)", "validated mode profile", "REQUESTED"), + ("asg_write_step_size", "\\(profile.asgWriteStepSize)", "validated mode profile", "REQUESTED"), + ("asg_data_ring_size", "\\(profile.asgDataRingSize)", "validated mode profile", "REQUESTED"), + ("asg_draw_flush_interval_us", "\\(profile.asgDrawFlushInterval)", "validated mode profile", "REQUESTED"), + ("angle_enabled_requested", profile.angleEnabledFeatures, "validated mode profile", "REQUESTED"), + ("angle_disabled_requested", profile.angleDisabledFeatures, "validated mode profile", "REQUESTED"), + ("frame_transport", "raw_grpc_rgba8888", "native admission path", "DIRECT"), + ("raw_logcat_policy", "LOCAL_SENSITIVE_SESSION_SCOPED_NOT_FOR_SHARING", "privacy contract", "LOCKED"), + ("sdk_root", paths.sdkRoot.path, "runtime-mode authority", "DIRECT") + ] + for receipt in receipts { + telemetry.recordReceipt(key: receipt.0, value: receipt.1, source: receipt.2, confidence: receipt.3) + } + } + +`; +runtime = replaceSection(runtime, ' private func recordFrozenReceipts', ' private func startADBServer', receiptsFunction, 'frozen receipts'); + +const adbServerFunction = ` private func startADBServer( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + let result = try Self.runCommand( + paths.adb, + ["-P", "\\(paths.adbServerPort)", "start-server"], + environment: Self.adbEnvironment(paths: paths), + timeout: 30 + ) + guard result.status == 0 else { + throw TFTMACRuntimeError( + "ADB server \\(paths.adbServerPort) could not start: \\(result.output.suffix(1200))" + ) + } + telemetry.recordEvent("ADB_SERVER_STARTED", payload: [ + "port": paths.adbServerPort, + "serial": paths.serial, + "adb_vendor_keys_policy": paths.adbVendorKeysPolicy, + "output": result.output.suffix(2000).description + ]) + } + +`; +runtime = replaceSection(runtime, ' private func startADBServer', ' private func launchEmulatorHost', adbServerFunction, 'ADB server'); + +const launchFunction = ` private func launchEmulatorHost( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + guard paths.launchStrategy == .bundledForwarder else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \\(paths.mode.rawValue) requires its separately receipted native-host acceptance operation." + ) + } + let stdout = telemetry.captureDirectory.appendingPathComponent("emulator.stdout.log") + let stderr = telemetry.captureDirectory.appendingPathComponent("emulator.stderr.log") + FileManager.default.createFile(atPath: stdout.path, contents: nil) + FileManager.default.createFile(atPath: stderr.path, contents: nil) + for root in Self.controllerDiscoveryRoots(paths: paths) { + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + } + expectedSessionMarker = "androidboot.tftmac.session=\\(telemetry.sessionIdentifier)" + var arguments = [ + "-n", "-W", + "--env", "TFT_EMULATOR=\\(paths.emulator.path)", + "--env", "TFT_ADB_SERVER_PORT=\\(paths.adbServerPort)", + "--env", "ANDROID_ADB_SERVER_PORT=\\(paths.adbServerPort)", + "--env", "ADB_MDNS_AUTO_CONNECT=", + "--env", "ADB_SERVER_SOCKET=", + "--env", "ANDROID_ADB_SERVER_ADDRESS=", + "--env", "ANDROID_SDK_ROOT=\\(paths.sdkRoot.path)", + "--env", "ANDROID_AVD_HOME=\\(paths.avdHome.path)", + "--env", "ANDROID_EMULATOR_USE_SYSTEM_LIBS=0", + "--env", "ANGLE_FEATURE_OVERRIDES_ENABLED=\\(profile.angleEnabledFeatures)", + "--env", "ANGLE_FEATURE_OVERRIDES_DISABLED=\\(profile.angleDisabledFeatures)", + "--env", "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS=0", + "--env", "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE=64", + "--env", "MVK_CONFIG_FAST_MATH_ENABLED=1", + "--env", "TFT_HOST_LATENCY_QOS=\\(profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default")", + "--env", "TFT_HOST_STDOUT=\\(stdout.path)", + "--env", "TFT_HOST_STDERR=\\(stderr.path)", + paths.hostApplication.path, + "--args", + "@\\(paths.avdName)", "-id", paths.emulatorIdentifier, "-port", "\\(paths.consolePort)", + "-gpu", profile.gpuMode, "-audio", profile.audioBackend, + "-feature", profile.effectiveEmulatorFeatures.joined(separator: ","), + "-append-userspace-opt", "androidboot.opengles.version=196610", + "-append-userspace-opt", "androidboot.tftmac.graphics_profile=tftmac", + "-append-userspace-opt", expectedSessionMarker!, + "-skin", "\\(profile.width)x\\(profile.height)", + "-vsync-rate", "\\(profile.refreshHz)", + "-dns-server", "1.1.1.1,8.8.8.8", + "-cores", "\\(profile.vCPU)", "-memory", "\\(profile.ramMiB)", + "-no-hidpi-scaling", "-no-snapshot", "-no-metrics", "-no-boot-anim", + "-crash-report-mode", "disabled", "-qt-hide-window", + "-grpc", "\\(paths.controllerPort)", "-grpc-use-token", + "-idle-grpc-timeout", "300" + ] + if let zone = TimeZone.current.identifier.addingPercentEncoding(withAllowedCharacters: .alphanumerics), !zone.isEmpty { + arguments += ["-timezone", TimeZone.current.identifier] + } + let process = Process() + process.executableURL = URL(fileURLWithPath: "/usr/bin/open") + process.arguments = arguments + var environment = ProcessInfo.processInfo.environment + environment.removeValue(forKey: "ADB_VENDOR_KEYS") + process.environment = environment + try process.run() + openProcess = process + telemetry.recordEvent("EMULATOR_HOST_LAUNCHED", payload: [ + "method": "/usr/bin/open", + "flags": ["-n", "-W", "--env", "--args"], + "mode": paths.mode.rawValue, + "host_application": paths.hostApplication.path, + "open_pid": process.processIdentifier, + "adb_vendor_keys_policy": paths.adbVendorKeysPolicy, + "game_mode_eligible": true, + "host_qos_requested": profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default", + "controller_discovery_roots": Self.controllerDiscoveryRoots(paths: paths).map(\\.path), + "emulator_arguments": Array(arguments.suffix(from: arguments.firstIndex(of: "--args") ?? arguments.startIndex).dropFirst()) + ]) + } + +`; +runtime = replaceSection(runtime, ' private func launchEmulatorHost', ' private func recordHostSchedulingReceipt', launchFunction, 'emulator host launch'); + +runtime = replaceOnce(runtime, +` guard let pid = Int32(pidText), Self.processMatchesLaunchedIdentity(pid, sessionMarker: expectedSessionMarker) else { continue }`, +` guard let pid = Int32(pidText), + Self.processMatchesLaunchedIdentity( + pid, + paths: paths, + sessionMarker: expectedSessionMarker + ) else { continue }`, +'discovery process identity'); +runtime = replaceOnce(runtime, ` await status("Waiting for the proven ADB identity on emulator-5582…", false)`, ` await status("Waiting for the proven ADB identity on \\(paths.serial)…", false)`, 'ADB wait status'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "get-state"],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "get-state"],`, +'ADB state identity'); +runtime = replaceOnce(runtime, +` telemetry.recordEvent("ADB_STATE_CHANGED", payload: [ + "previous_state": previouslyLoggedState ?? "none", + "current_state": lastState, + "serial": "emulator-5582",`, +` telemetry.recordEvent("ADB_STATE_CHANGED", payload: [ + "previous_state": previouslyLoggedState ?? "none", + "current_state": lastState, + "serial": paths.serial,`, +'ADB state serial'); +runtime = replaceOnce(runtime, +` telemetry.recordEvent("ADB_UNAUTHORIZED_OBSERVED", payload: [ + "serial": "emulator-5582",`, +` telemetry.recordEvent("ADB_UNAUTHORIZED_OBSERVED", payload: [ + "serial": paths.serial,`, +'ADB unauthorized serial'); +runtime = replaceOnce(runtime, ` await status("Waiting for emulator-5582 to appear on ADB 5038…", false)`, ` await status("Waiting for \\(paths.serial) to appear on ADB \\(paths.adbServerPort)…", false)`, 'ADB missing status'); +runtime = replaceOnce(runtime, ` throw TFTMACRuntimeError("ADB emulator-5582 did not authorize in the logged-in Mac session (last state: \\(lastState)).")`, ` throw TFTMACRuntimeError("ADB \\(paths.serial) did not authorize in the logged-in Mac session (last state: \\(lastState)).")`, 'ADB authorization error'); +runtime = replaceOnce(runtime, ` telemetry.recordEvent("ADB_DEVICE_AUTHORIZED", payload: ["port": 5038, "serial": "emulator-5582"])`, ` telemetry.recordEvent("ADB_DEVICE_AUTHORIZED", payload: ["port": paths.adbServerPort, "serial": paths.serial])`, 'ADB authorized event'); +runtime = replaceOnce(runtime, ` "resolution": "1920x1080",`, ` "resolution": "\\(profile.width)x\\(profile.height)",`, 'TFT resolution receipt'); +runtime = replaceOnce(runtime, ` "audio_backend": "coreaudio",`, ` "audio_backend": profile.audioBackend,`, 'TFT audio receipt'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582", "shell", "perfetto", "--txt", "-c", "-", "-o", remotePath],`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial, "shell", "perfetto", "--txt", "-c", "-", "-o", remotePath],`, +'Perfetto ADB identity'); + +const adbEnvironmentFunction = ` nonisolated private static func adbEnvironment( + paths: TFTMACRuntimePaths + ) -> [String: String] { + var environment = ProcessInfo.processInfo.environment + environment.removeValue(forKey: "ADB_VENDOR_KEYS") + environment.removeValue(forKey: "ADB_SERVER_SOCKET") + environment.removeValue(forKey: "ANDROID_ADB_SERVER_ADDRESS") + environment["ANDROID_SDK_ROOT"] = paths.sdkRoot.path + environment["ANDROID_AVD_HOME"] = paths.avdHome.path + environment["ANDROID_ADB_SERVER_PORT"] = "\\(paths.adbServerPort)" + environment["ADB_MDNS_AUTO_CONNECT"] = "" + return environment + } + +`; +runtime = replaceSection(runtime, ' nonisolated private static func adbEnvironment', ' nonisolated private static func adb(paths:', adbEnvironmentFunction, 'ADB environment'); +runtime = replaceOnce(runtime, +` ["-P", "5038", "-s", "emulator-5582"] + arguments,`, +` ["-P", "\\(paths.adbServerPort)", "-s", paths.serial] + arguments,`, +'ADB helper identity'); +runtime = replaceOnce(runtime, +` "-P", "5038", "-s", "emulator-5582", "shell", "pidof",`, +` "-P", "\\(paths.adbServerPort)", "-s", paths.serial, "shell", "pidof",`, +'TFT process identity'); + +const processHelpers = ` nonisolated private static func processMatchesLaunchedIdentity( + _ processIdentifier: Int32, + paths: TFTMACRuntimePaths, + sessionMarker: String? = nil + ) -> Bool { + guard processExists(processIdentifier), + let result = try? runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-p", "\\(processIdentifier)", "-ww", "-o", "command="], + timeout: 5 + ), result.status == 0 else { return false } + let baseIdentityMatches = result.output.contains(paths.qemu.lastPathComponent) + && result.output.contains("@\\(paths.avdName)") + && result.output.contains("-port \\(paths.consolePort)") + && result.output.contains("-grpc \\(paths.controllerPort)") + return baseIdentityMatches && (sessionMarker.map(result.output.contains) ?? true) + } + + nonisolated private static func findOwnedEmulatorPID( + sessionMarker: String, + paths: TFTMACRuntimePaths + ) -> Int32? { + guard let result = try? runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-axo", "pid=,command="], + timeout: 10 + ), result.status == 0 else { return nil } + for line in result.output.split(whereSeparator: \\.isNewline) { + guard line.contains(paths.qemu.lastPathComponent), + line.contains("@\\(paths.avdName)"), + line.contains("-port \\(paths.consolePort)"), + line.contains("-grpc \\(paths.controllerPort)"), + line.contains(sessionMarker), + let pid = line.split(whereSeparator: \\.isWhitespace).first.flatMap({ Int32($0) }) else { continue } + return pid + } + return nil + } + + nonisolated private static func anyEmulatorUsingSelectedAVD( + paths: TFTMACRuntimePaths + ) -> Bool { + guard let result = try? runCommand( + URL(fileURLWithPath: "/bin/ps"), + ["-axo", "command="], + timeout: 10 + ), result.status == 0 else { return true } + return result.output.split(whereSeparator: \\.isNewline).contains { line in + line.contains(paths.qemu.lastPathComponent) + && line.contains("@\\(paths.avdName)") + && line.contains("-port \\(paths.consolePort)") + } + } + +`; +runtime = replaceSection(runtime, ' nonisolated private static func processMatchesLaunchedIdentity(', ' nonisolated private static func controllerDiscoveryRoots', processHelpers, 'process identity helpers'); + +const controllerHeader = `@MainActor +final class TFTMACRuntimeController { + private let service: TFTMACRuntimeService + private var runTask: Task? + private(set) var failed = false + + init( + runtimeConfiguration: TFTMACSelectedRuntimeConfiguration, + mailbox: LatestFrameMailbox, + status: @escaping TFTMACRuntimeService.StatusHandler, + gameFrame: @escaping TFTMACRuntimeService.GameFrameHandler + ) { + service = TFTMACRuntimeService( + runtimeConfiguration: runtimeConfiguration, + mailbox: mailbox, + status: status, + gameFrame: gameFrame + ) + } + +`; +runtime = replaceSection(runtime, '@MainActor\nfinal class TFTMACRuntimeController {', ' func start() {', controllerHeader, 'runtime controller initializer'); +for (const forbidden of ['["-P", "5038"', '"emulator-5582"', '"@TFT_Ultra_Tablet"', '"-iTCP:5582"', '"-iTCP:8554"']) { + ensure(!runtime.includes(forbidden), `runtime still hard-codes control identity: ${forbidden}`); +} + +let coordinator = readText('tftmac/App/AppCoordinator.swift'); +coordinator = replaceOnce(coordinator, +` private var activeProfile: TFTMACRuntimeProfile = .playable + private var terminationInProgress = false +`, +` private var activeProfile: TFTMACRuntimeProfile = .playable + private var activeApplicationSupport = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + private var terminationInProgress = false +`, +'coordinator state root'); +const launchCoordinator = ` func applicationDidFinishLaunching(_ notification: Notification) { + let controller = MainWindowController(mailbox: mailbox) + mainWindowController = controller + controller.showWindow(nil) + controller.window?.makeFirstResponder(controller.emulatorView) + NSApp.activate(ignoringOtherApps: true) + + do { + let savedProfile = TFTMACRuntimeProfile.load() + let runtimeConfiguration = try TFTMACSelectedRuntimeConfiguration.load( + savedProfile: savedProfile + ) + activeProfile = runtimeConfiguration.profile + activeApplicationSupport = runtimeConfiguration.applicationSupport + let runtime = TFTMACRuntimeController( + runtimeConfiguration: runtimeConfiguration, + mailbox: mailbox, + status: { [weak controller] text, isError in + controller?.emulatorView.setStatus(text, isError: isError) + }, + gameFrame: { [weak controller] window in + controller?.emulatorView.setGameFrameWindow(window) + } + ) + runtimeController = runtime + controller.emulatorView.onTouchInput = { [weak runtime] input in + runtime?.sendTouch(input) + } + controller.emulatorView.onMouseInput = { [weak runtime] x, y, buttons in + runtime?.sendMouse(x: x, y: y, buttons: buttons) + } + controller.emulatorView.onKeyboardInput = { [weak runtime] text, key in + runtime?.sendKeyboard(text: text, key: key) + } + controller.emulatorView.onPresentationSample = { [weak runtime] sample in + runtime?.recordPresentation(sample) + } + controller.emulatorView.onHostPresentationWindow = { [weak runtime] sample in + runtime?.recordHostPresentation(sample) + } + runtime.start() + } catch { + controller.emulatorView.setStatus(error.localizedDescription, isError: true) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak controller] in + controller?.enterNativeFullscreen() + } + } + +`; +coordinator = replaceSection(coordinator, ' func applicationDidFinishLaunching(_ notification: Notification) {', ' @objc func showSettings', launchCoordinator, 'AppCoordinator launch'); +coordinator = replaceOnce(coordinator, +` let captures = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC/Captures", isDirectory: true)`, +` let captures = activeApplicationSupport + .appendingPathComponent("Captures", isDirectory: true)`, +'mode-specific capture reveal'); + +let tests = readText('Tests/TFTMACTests/TFTMACGate1Tests.swift'); +const addedTests = ` + private func runtimeModeRegistryData() throws -> Data { + let repositoryRoot = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + return try Data(contentsOf: repositoryRoot.appendingPathComponent("ssot/runtime-modes.json")) + } + + func testRuntimeModeRegistryDefinesExactControlIdentity() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + XCTAssertEqual(Set(registry.document.modes.keys), Set(TFTMACRuntimeMode.allCases.map(\\.rawValue))) + XCTAssertEqual(registry.document.defaultMode, .control) + let selection = try registry.selection(environment: [:]) + XCTAssertEqual(selection.mode, .control) + XCTAssertEqual(selection.definition.avdName, "TFT_Ultra_Tablet") + XCTAssertEqual(selection.definition.adbServerPort, 5038) + XCTAssertEqual(selection.definition.consolePort, 5582) + XCTAssertEqual(selection.definition.controllerPort, 8554) + XCTAssertEqual(selection.definition.serial, "emulator-5582") + } + + func testRuntimeModeRegistryFailsClosedForUnacceptedModes() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + for requested in ["advanced_diagnostics", "candidate", "unknown"] { + XCTAssertThrowsError(try registry.selection(environment: [ + TFTMACRuntimeModeRegistry.environmentKey: requested + ]), requested) + } + } + + func testRuntimeModeRegistryRejectsTamperedBytes() throws { + var data = try runtimeModeRegistryData() + data.append(Data(" ".utf8)) + XCTAssertThrowsError(try TFTMACRuntimeModeRegistry(data: data)) + XCTAssertThrowsError(try TFTMACRuntimeModeAuthority(data: data)) + } + + func testSupplementalRuntimeAuthoritySeparatesStateAndLaunchStrategies() throws { + let data = try runtimeModeRegistryData() + let registry = try TFTMACRuntimeModeRegistry(data: data) + let authority = try TFTMACRuntimeModeAuthority(data: data) + XCTAssertNoThrow(try authority.validateConsistency(with: registry)) + let control = try authority.definition(for: .control) + let diagnostics = try authority.definition(for: .advancedDiagnostics) + let candidate = try authority.definition(for: .candidate) + XCTAssertEqual(control.launchStrategy, .bundledForwarder) + XCTAssertEqual(diagnostics.launchStrategy, .externalNativeHost) + XCTAssertEqual(candidate.launchStrategy, .blocked) + XCTAssertNotEqual(control.stateNamespace, diagnostics.stateNamespace) + XCTAssertNotEqual(diagnostics.stateNamespace, candidate.stateNamespace) + XCTAssertNotNil(diagnostics.diagnosticReceipts) + XCTAssertNil(candidate.hostApplication) + XCTAssertNotEqual( + authority.applicationSupportURL(for: .control), + authority.applicationSupportURL(for: .advancedDiagnostics) + ) + } + + func testControlModePreservesValidatedNativeProfile() throws { + let data = try runtimeModeRegistryData() + let registry = try TFTMACRuntimeModeRegistry(data: data) + let authority = try TFTMACRuntimeModeAuthority(data: data) + let selection = try registry.selection(environment: [:]) + let effective = try authority.effectiveProfile(savedProfile: .playable, selection: selection) + XCTAssertEqual(effective, .playable) + XCTAssertEqual(effective.controllerPort, selection.definition.controllerPort) + } + + func testRuntimeLeasePersistsExactModeIdentityAndRejectsSecondOwner() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + let selection = try registry.selection(environment: [:]) + let identity = try selection.leaseIdentity() + let stateRoot = FileManager.default.temporaryDirectory + .appendingPathComponent("tftmac-mode-lease-test-\\(UUID().uuidString)", isDirectory: true) + defer { try? FileManager.default.removeItem(at: stateRoot) } + let first = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: identity) + defer { first.release() } + let leaseURL = stateRoot.appendingPathComponent("native-runtime.lease") + let object = try XCTUnwrap( + try JSONSerialization.jsonObject(with: Data(contentsOf: leaseURL)) as? [String: Any] + ) + XCTAssertEqual((object["schema"] as? NSNumber)?.intValue, 2) + XCTAssertEqual(object["mode"] as? String, "control") + XCTAssertEqual(object["registry_sha256"] as? String, registry.registrySha256) + XCTAssertEqual(object["configuration_sha256"] as? String, selection.definition.configurationSha256) + XCTAssertEqual(object["avd_name"] as? String, "TFT_Ultra_Tablet") + XCTAssertEqual((object["adb_server_port"] as? NSNumber)?.intValue, 5038) + XCTAssertEqual((object["console_port"] as? NSNumber)?.intValue, 5582) + XCTAssertEqual((object["controller_port"] as? NSNumber)?.intValue, 8554) + XCTAssertEqual(object["serial"] as? String, "emulator-5582") + XCTAssertThrowsError(try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: identity)) + } +`; +ensure(tests.endsWith('}\n'), 'test class closing brace changed'); +tests = `${tests.slice(0, -2)}${addedTests}}\n`; + +let project = readText('TFTMAC.xcodeproj/project.pbxproj'); +project = replaceOnce(project, '/* End PBXBuildFile section */', `\t\t100000000000000000000038 /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000023 /* RuntimeMode.swift */; }; +\t\t100000000000000000000039 /* RuntimeMode.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000023 /* RuntimeMode.swift */; }; +\t\t10000000000000000000003A /* runtime-modes.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000024 /* runtime-modes.json */; }; +\t\t10000000000000000000003B /* RuntimeModeAuthority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; +\t\t10000000000000000000003C /* RuntimeModeAuthority.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; +\t\t10000000000000000000003D /* runtime-authority.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000026 /* runtime-authority.json */; }; +/* End PBXBuildFile section */`, 'PBX build files'); +project = replaceOnce(project, '/* End PBXFileReference section */', `\t\t200000000000000000000023 /* RuntimeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeMode.swift; sourceTree = ""; }; +\t\t200000000000000000000024 /* runtime-modes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-modes.json; sourceTree = SOURCE_ROOT; }; +\t\t200000000000000000000025 /* RuntimeModeAuthority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeModeAuthority.swift; sourceTree = ""; }; +\t\t200000000000000000000026 /* runtime-authority.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-authority.json; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */`, 'PBX file references'); +project = replaceOnce(project, +`\t\t\t\t400000000000000000000007 /* Tests */, +\t\t\t\t400000000000000000000009 /* Products */,`, +`\t\t\t\t400000000000000000000007 /* Tests */, +\t\t\t\t200000000000000000000024 /* runtime-modes.json */, +\t\t\t\t200000000000000000000026 /* runtime-authority.json */, +\t\t\t\t400000000000000000000009 /* Products */,`, +'PBX root resources'); +project = replaceOnce(project, +`\t\t40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000019 /* RuntimeLease.swift */,`, +`\t\t40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000023 /* RuntimeMode.swift */, 200000000000000000000025 /* RuntimeModeAuthority.swift */, 200000000000000000000019 /* RuntimeLease.swift */,`, +'PBX runtime group'); +project = replaceOnce(project, +`\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };`, +`\t\t800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (10000000000000000000003A /* runtime-modes.json in Resources */, 10000000000000000000003D /* runtime-authority.json in Resources */,); runOnlyForDeploymentPostprocessing = 0; };`, +'PBX resources phase'); +project = replaceOnce(project, +`100000000000000000000025, 100000000000000000000028,`, +`100000000000000000000025, 100000000000000000000038, 10000000000000000000003B, 100000000000000000000028,`, +'PBX app sources'); +project = replaceOnce(project, +`100000000000000000000026, 100000000000000000000029,`, +`100000000000000000000026, 100000000000000000000039, 10000000000000000000003C, 100000000000000000000029,`, +'PBX test sources'); + +let buildScript = readText('scripts/build-native-app.command'); +buildScript = replaceOnce(buildScript, +`/usr/bin/codesign --force --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${HOST_APP}" + +/usr/bin/codesign --force --deep --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${DIST}" +/usr/bin/codesign --verify --deep --strict --verbose=2 "\${DIST}"`, +`/usr/bin/codesign --force --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${HOST_APP}" + +# Seal the non-reproducible signed Mach-O identity into a receipt that is then +# protected by the outer application signature. Source and Info.plist hashes +# remain fixed in the runtime-mode registry; the signed receipt binds those +# inputs to the exact packaged host executable and UUID. +/usr/bin/python3 - "\${ROOT}" "\${DIST}" "\${HOST_APP}" <<'PY' +import datetime +import hashlib +import json +import pathlib +import plistlib +import re +import subprocess +import sys + +root = pathlib.Path(sys.argv[1]) +dist = pathlib.Path(sys.argv[2]) +host = pathlib.Path(sys.argv[3]) +source = root / "RuntimeHost/main.c" +info_source = root / "RuntimeHost/Info.plist" +info_packaged = host / "Contents/Info.plist" +executable = host / "Contents/MacOS/TFTMACEmulatorHost" + +def sha256(path): + h = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + +uuid_output = subprocess.check_output(["/usr/bin/dwarfdump", "--uuid", str(executable)], text=True) +uuids = [f"{match.group(1)}:{match.group(2)}" for match in re.finditer(r"UUID: ([0-9A-F-]+) \\(([^)]+)\\)", uuid_output)] +if not uuids: + raise SystemExit("Control native host has no Mach-O UUID receipt") +with info_packaged.open("rb") as handle: + bundle_identifier = plistlib.load(handle)["CFBundleIdentifier"] +compiler = subprocess.check_output(["/usr/bin/xcrun", "--find", "clang"], text=True).strip() +compiler_version = subprocess.check_output([compiler, "--version"], text=True).splitlines()[0] +receipt = { + "schema": 1, + "state": "CONTROL_NATIVE_HOST_BUILD_PASS", + "generated_at_utc": datetime.datetime.now(datetime.timezone.utc).isoformat(), + "host_application_relative_path": "TFTMAC Emulator Host.app", + "bundle_identifier": bundle_identifier, + "source_path": "RuntimeHost/main.c", + "source_sha256": sha256(source), + "info_plist_path": "RuntimeHost/Info.plist", + "info_plist_sha256": sha256(info_source), + "packaged_info_plist_sha256": sha256(info_packaged), + "executable_relative_path": "Contents/MacOS/TFTMACEmulatorHost", + "executable_sha256": sha256(executable), + "executable_uuids": uuids, + "compiler_path": compiler, + "compiler_version": compiler_version, + "compile_arguments": ["-Os", "-arch", "arm64", "-mmacosx-version-min=15.0"], + "signed_before_receipt": True, + "outer_app_seals_receipt": True +} +receipt_path = dist / "Contents/Resources/control-host-build.json" +receipt_path.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\\n") +PY + +# The nested host is already signed. Sign the outer app without deep-resigning +# it, so the exact executable hash in the newly written receipt stays true. +/usr/bin/codesign --force --sign "\${SIGNING_IDENTITY_HASH}" --timestamp=none "\${DIST}" +/usr/bin/codesign --verify --deep --strict --verbose=2 "\${DIST}" +/usr/bin/python3 - "\${DIST}" "\${HOST_APP}" <<'PY' +import hashlib +import json +import pathlib +import sys + +dist = pathlib.Path(sys.argv[1]) +host = pathlib.Path(sys.argv[2]) +receipt = json.loads((dist / "Contents/Resources/control-host-build.json").read_text()) +executable = host / receipt["executable_relative_path"] +h = hashlib.sha256(executable.read_bytes()).hexdigest() +if h != receipt["executable_sha256"]: + raise SystemExit("Outer signing changed the receipted control-host executable") +PY`, +'control host signed receipt'); + +let verifier = readText('scripts/verify-tftmac.command'); +verifier = replaceOnce(verifier, +` ssot/runtime-authority.json \\ + ssot/retained-evidence-index.json \\`, +` ssot/runtime-authority.json \\ + ssot/runtime-modes.json \\ + tftmac/Runtime/RuntimeMode.swift \\ + tftmac/Runtime/RuntimeModeAuthority.swift \\ + ${waveRoot}/validate-waveb-v4.mjs \\ + ssot/retained-evidence-index.json \\`, +'verifier required files'); +verifier = replaceOnce(verifier, +`[[ "$TEST_FUNCTION_COUNT" == "43" ]] || fail "native test inventory drifted: expected 43, found $TEST_FUNCTION_COUNT"`, +`[[ "$TEST_FUNCTION_COUNT" == "49" ]] || fail "native test inventory drifted: expected 49, found $TEST_FUNCTION_COUNT"`, +'test count'); +verifier = replaceOnce(verifier, +`node --check tools/tftmac-direct-control.mjs >/dev/null`, +`node --check tools/tftmac-direct-control.mjs >/dev/null +node --check ${waveRoot}/validate-waveb-v4.mjs >/dev/null`, +'validator syntax'); +verifier = replaceOnce(verifier, +`[[ -x "\${RELEASE_DERIVED}/Build/Products/Release/TFTMAC.app/Contents/MacOS/TFTMAC" ]] \\ + || fail "unsigned Release build did not produce the TFTMAC executable" + +/bin/zsh scripts/test-native-app.command`, +`readonly RELEASE_APP="\${RELEASE_DERIVED}/Build/Products/Release/TFTMAC.app" +[[ -x "\${RELEASE_APP}/Contents/MacOS/TFTMAC" ]] \\ + || fail "unsigned Release build did not produce the TFTMAC executable" +cmp -s ssot/runtime-modes.json "\${RELEASE_APP}/Contents/Resources/runtime-modes.json" \\ + || fail "unsigned Release app did not package the exact runtime-mode registry" +cmp -s ssot/runtime-authority.json "\${RELEASE_APP}/Contents/Resources/runtime-authority.json" \\ + || fail "unsigned Release app did not package the exact control authority" +node ${waveRoot}/validate-waveb-v4.mjs >/dev/null + +/bin/zsh scripts/test-native-app.command`, +'verifier build resources'); +verifier = replaceOnce(verifier, +`print "TFTMAC source validation: OK (unsigned Release build; 43 native tests)"`, +`print "TFTMAC source validation: OK (unsigned Release build; 49 native tests; Wave B mode authority PASS)"`, +'verifier final output'); + +const receipt = { + schema: 1, + state: 'WAVE_B_V4_IMPLEMENTATION_APPLIED', + project_id: 'tftmac', + change_id: changeId, + operation_id: process.env.CLARA_OPERATION_ID ?? null, + applied_at: new Date().toISOString(), + base_head_sha: expectedHead, + original_plan_sha256: expected[`${planRoot}/IMPLEMENTATION_PLAN.md`], + scope_lock_sha256: expected[`${planRoot}/SCOPE_LOCK.txt`], + correction_amendment_sha256: expected[`${waveRoot}/CORRECTION_AMENDMENT.md`], + runtime_modes_sha256: registrySha, + expected_test_count: 49, + modified_paths: [ + 'ssot/runtime-modes.json', + 'tftmac/App/AppCoordinator.swift', + 'tftmac/Runtime/RuntimeMode.swift', + 'tftmac/Runtime/RuntimeModeAuthority.swift', + 'tftmac/Runtime/RuntimeLease.swift', + 'tftmac/Runtime/TFTMACRuntime.swift', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift', + 'TFTMAC.xcodeproj/project.pbxproj', + 'scripts/build-native-app.command', + 'scripts/verify-tftmac.command' + ], + effects: { + source_only: true, + emulator_launch_attempted: false, + runtime_replacement_attempted: false, + control_stop_attempted: false, + installed_app_replacement_attempted: false, + package_launch_attempted: false + }, + next_safe_action: 'Run the single changed-head production source verifier and correct only a proven failure.' +}; + +const outputs = { + 'ssot/runtime-modes.json': registryText, + 'tftmac/App/AppCoordinator.swift': coordinator, + 'tftmac/Runtime/RuntimeMode.swift': runtimeModeSource, + 'tftmac/Runtime/RuntimeModeAuthority.swift': runtimeModeAuthoritySource, + 'tftmac/Runtime/RuntimeLease.swift': runtimeLeaseSource, + 'tftmac/Runtime/TFTMACRuntime.swift': runtime, + 'Tests/TFTMACTests/TFTMACGate1Tests.swift': tests, + 'TFTMAC.xcodeproj/project.pbxproj': project, + 'scripts/build-native-app.command': buildScript, + 'scripts/verify-tftmac.command': verifier, + [`${waveRoot}/IMPLEMENTATION_RECEIPT.json`]: `${JSON.stringify(receipt, null, 2)}\n` +}; +for (const [relativePath, content] of Object.entries(outputs)) { + writeAtomic(relativePath, content, relativePath.endsWith('.command') || relativePath.endsWith('.mjs') ? 0o755 : 0o644); +} +console.log(JSON.stringify(receipt, null, 2)); diff --git a/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs new file mode 100644 index 0000000..6da8435 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs @@ -0,0 +1,283 @@ +#!/usr/bin/env node +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; + +const root = process.cwd(); +const planRoot = '.clara/plans/tftmac-causal-graphics-v1'; +const waveRoot = `${planRoot}/wave-b-v4`; +const expectedPlanSha = '78785b29815dba26a8da1d2ed56e0e9c256d3e7d9cfb4c4857b3c954846e8d2b'; +const expectedScopeSha = 'dc77b6913d14409adc883dd27a67c42e982c40ab9149a68771b61dc99fae297e'; +const expectedBuildSha = '9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d'; +const expectedCloneSha = '09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648'; +const expectedHostSha = 'a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067'; + +function absolute(relativePath) { return path.join(root, relativePath); } +function fail(message) { throw new Error(`WAVE_B_V4_VALIDATION_FAILED: ${message}`); } +function assert(value, message) { if (!value) fail(message); } +function sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function read(relativePath) { return fs.readFileSync(absolute(relativePath)); } +function readText(relativePath) { return fs.readFileSync(absolute(relativePath), 'utf8'); } +function fileSha(relativePath) { return sha256(read(relativePath)); } +function externalSha(filePath) { return sha256(fs.readFileSync(filePath)); } +function run(executable, args, options = {}) { + const result = spawnSync(executable, args, { + cwd: root, + encoding: 'utf8', + maxBuffer: options.maxBuffer ?? 32 * 1024 * 1024, + timeout: options.timeout ?? 30_000 + }); + if (result.error) fail(`${executable} failed: ${result.error.message}`); + return { status: result.status, output: `${result.stdout ?? ''}${result.stderr ?? ''}` }; +} +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], + ['launch_state', mode.launch_state], + ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], + ['library_root', mode.library_root], + ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 ?? ''], + ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 ?? ''], + ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], + ['avd_name', mode.avd_name], + ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], + ['avd_config_sha256', mode.avd_config_sha256 ?? ''], + ['avd_ini_path', mode.avd_ini_path], + ['avd_ini_sha256', mode.avd_ini_sha256 ?? ''], + ['adb_server_port', mode.adb_server_port], + ['console_port', mode.console_port], + ['controller_port', mode.controller_port ?? ''], + ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], + ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 ?? ''], + ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], + ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], + ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], + ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha256(Buffer.from(fields.map(([key, value]) => `${key}=${value}`).join('\n'))); +} +function assertSha(value, label) { + assert(typeof value === 'string' && /^[0-9a-f]{64}$/.test(value), `${label} is not a lowercase SHA-256`); +} +function assertUUIDs(filePath, expected, label) { + assert(Array.isArray(expected) && expected.length > 0, `${label} UUID authority is empty`); + const result = run('/usr/bin/dwarfdump', ['--uuid', filePath]); + assert(result.status === 0, `${label} UUID inspection failed`); + for (const identity of expected) { + const [uuid, arch] = identity.split(':'); + assert(uuid && arch && result.output.toUpperCase().includes(uuid.toUpperCase()) && result.output.includes(`(${arch})`), `${label} UUID drifted`); + } +} +function readSealed(reference) { + assertSha(reference.sha256, `${reference.path} receipt SHA`); + assert(externalSha(reference.path) === reference.sha256, `sealed receipt hash drifted: ${reference.path}`); + const sidecar = fs.readFileSync(`${reference.path}.sha256`, 'utf8').trim().split(/\s+/)[0]; + assert(sidecar === reference.sha256, `sealed receipt sidecar drifted: ${reference.path}`); + return JSON.parse(fs.readFileSync(reference.path, 'utf8')); +} + +assert(fileSha(`${planRoot}/IMPLEMENTATION_PLAN.md`) === expectedPlanSha, 'original plan identity drifted'); +assert(fileSha(`${planRoot}/SCOPE_LOCK.txt`) === expectedScopeSha, 'scope-lock identity drifted'); +for (const required of [ + `${waveRoot}/CORRECTION_AMENDMENT.md`, + `${waveRoot}/PREFLIGHT.json`, + `${waveRoot}/ZENGATE_RECEIPT.json`, + `${waveRoot}/PREPARATION_RECEIPT.json`, + `${waveRoot}/IMPLEMENTATION_RECEIPT.json`, + 'ssot/runtime-modes.json', + 'ssot/runtime-authority.json', + 'tftmac/Runtime/RuntimeMode.swift', + 'tftmac/Runtime/RuntimeModeAuthority.swift', + 'tftmac/Runtime/RuntimeLease.swift', + 'tftmac/Runtime/TFTMACRuntime.swift', + 'tftmac/App/AppCoordinator.swift', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift', + 'TFTMAC.xcodeproj/project.pbxproj', + 'scripts/verify-tftmac.command' +]) assert(fs.existsSync(absolute(required)), `required Wave B file is missing: ${required}`); + +const registryBytes = read('ssot/runtime-modes.json'); +const registrySha = sha256(registryBytes); +const runtimeModeSource = readText('tftmac/Runtime/RuntimeMode.swift'); +const pinned = runtimeModeSource.match(/static let expectedRegistrySha256 = "([0-9a-f]{64})"/); +assert(pinned?.[1] === registrySha, 'Swift registry identity does not match packaged JSON'); +const registry = JSON.parse(registryBytes); +assert(registry.schema === 1, 'runtime-mode schema must remain 1'); +assert(registry.contract === 'TFTMAC_RUNTIME_MODES_V1', 'runtime-mode contract drifted'); +assert(registry.default_mode === 'control', 'control is not the default mode'); +assert(registry.selection_environment_variable === 'TFTMAC_RUNTIME_MODE', 'selection environment variable drifted'); +assert(registry.active_lease_relative_path === 'State/native-runtime.lease', 'global exclusive lease path drifted'); +assert(JSON.stringify(Object.keys(registry.modes).sort()) === JSON.stringify(['advanced_diagnostics', 'candidate', 'control']), 'registry does not define exactly three modes'); + +const usedPorts = new Map(); +const usedNamespaces = new Set(); +for (const [name, mode] of Object.entries(registry.modes)) { + assert(name === mode.mode, `registry key mismatch for ${name}`); + assert(configurationHash(mode) === mode.configuration_sha256, `configuration SHA drifted for ${name}`); + assert(mode.serial === `emulator-${mode.console_port}`, `serial/console identity drifted for ${name}`); + assert(!usedNamespaces.has(mode.state_namespace), `state namespace collision at ${mode.state_namespace}`); + usedNamespaces.add(mode.state_namespace); + for (const [kind, value] of [['adb', mode.adb_server_port], ['console', mode.console_port], ['controller', mode.controller_port]]) { + if (value === null) continue; + assert(Number.isInteger(value) && value > 0 && value < 65536, `${name}.${kind} is invalid`); + assert(!usedPorts.has(value), `port ${value} collides between ${usedPorts.get(value)} and ${name}.${kind}`); + usedPorts.set(value, `${name}.${kind}`); + } +} + +const control = registry.modes.control; +assert(control.launch_state === 'enabled', 'control is not enabled'); +assert(control.state_namespace === 'control' && control.uses_legacy_application_support_root === true, 'control state compatibility drifted'); +assert(control.launch_strategy === 'bundled_forwarder' && control.profile_policy === 'validated_native_preferences', 'control launch/profile strategy drifted'); +assert(control.runtime_root === '/Volumes/MAC MINI M4/TFTMAC/Runtime', 'control root drifted'); +assert(control.avd_name === 'TFT_Ultra_Tablet', 'control AVD drifted'); +assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, 'control ports drifted'); +assert(control.serial === 'emulator-5582', 'control serial drifted'); +assert(control.rollback_target === 'control' && control.requires_control_stopped === false, 'control rollback contract drifted'); +for (const [filePath, expected, label] of [ + [control.adb_path, control.adb_sha256, 'control ADB'], + [control.emulator_path, control.emulator_sha256, 'control emulator'], + [control.qemu_path, control.qemu_sha256, 'control qemu'], + [control.gfxstream_backend_path, control.gfxstream_backend_sha256, 'control gfxstream'] +]) { + assertSha(expected, `${label} SHA`); + assert(externalSha(filePath) === expected, `${label} hash drifted`); +} +assertUUIDs(control.emulator_path, control.emulator_uuids, 'control emulator'); +assertUUIDs(control.qemu_path, control.qemu_uuids, 'control qemu'); +assertUUIDs(control.gfxstream_backend_path, control.gfxstream_backend_uuids, 'control gfxstream'); +const controlVersion = run(control.emulator_path, ['-version']); +assert(controlVersion.status === 0 && controlVersion.output.includes(control.expected_emulator_version_contains), 'control emulator version drifted'); +assert(control.authority_manifest.sha256 === fileSha('ssot/runtime-authority.json'), 'control authority manifest hash drifted'); +assert(control.host_application.executable_sha256 === null, 'control host cannot pin a non-reproducible pre-sign executable hash'); +assert(control.host_application.source_path === 'RuntimeHost/main.c', 'control host source path drifted'); +assert(control.host_application.source_sha256 === fileSha('RuntimeHost/main.c'), 'control host source identity drifted'); +assert(control.host_application.info_plist_path === 'RuntimeHost/Info.plist', 'control host Info.plist path drifted'); +assert(control.host_application.info_plist_sha256 === fileSha('RuntimeHost/Info.plist'), 'control host Info.plist identity drifted'); +assert(control.host_application.build_receipt_resource === 'control-host-build.json', 'control host signed build receipt contract drifted'); +const buildScript = readText('scripts/build-native-app.command'); +for (const required of ['CONTROL_NATIVE_HOST_BUILD_PASS', 'control-host-build.json', 'executable_uuids', 'source_sha256', 'info_plist_sha256']) { + assert(buildScript.includes(required), `build script is missing control-host receipt field: ${required}`); +} +assert(!buildScript.includes('codesign --force --deep --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${DIST}"'), 'outer app still deep-resigns the nested control host after its receipt'); + +const diagnostics = registry.modes.advanced_diagnostics; +assert(diagnostics.launch_state === 'blocked_pending_controller_lease' && diagnostics.controller_port === null, 'diagnostics are not fail-closed'); +assert(diagnostics.state_namespace === 'advanced_diagnostics' && diagnostics.uses_legacy_application_support_root === false, 'diagnostic state isolation drifted'); +assert(diagnostics.launch_strategy === 'external_native_host' && diagnostics.profile_policy === 'fixed_registry_profile', 'diagnostic launch/profile strategy drifted'); +assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.serial === 'emulator-5586', 'diagnostic port identity drifted'); +assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === 'control', 'diagnostic noninterference contract drifted'); +for (const [filePath, expected, label] of [ + [diagnostics.adb_path, diagnostics.adb_sha256, 'diagnostic ADB'], + [diagnostics.emulator_path, diagnostics.emulator_sha256, 'diagnostic emulator'], + [diagnostics.qemu_path, diagnostics.qemu_sha256, 'diagnostic qemu'], + [diagnostics.gfxstream_backend_path, diagnostics.gfxstream_backend_sha256, 'diagnostic gfxstream'], + [diagnostics.avd_config_path, diagnostics.avd_config_sha256, 'diagnostic AVD config'], + [diagnostics.avd_ini_path, diagnostics.avd_ini_sha256, 'diagnostic AVD ini'] +]) { + assertSha(expected, `${label} SHA`); + assert(externalSha(filePath) === expected, `${label} hash drifted`); +} +assertUUIDs(diagnostics.emulator_path, diagnostics.emulator_uuids, 'diagnostic emulator'); +assertUUIDs(diagnostics.qemu_path, diagnostics.qemu_uuids, 'diagnostic qemu'); +assertUUIDs(diagnostics.gfxstream_backend_path, diagnostics.gfxstream_backend_uuids, 'diagnostic gfxstream'); +const diagnosticVersion = run(diagnostics.emulator_path, ['-version']); +assert(diagnosticVersion.status === 0 && diagnosticVersion.output.includes(diagnostics.expected_emulator_version_contains), 'diagnostic emulator version drifted'); + +const receipts = diagnostics.diagnostic_receipts; +assert(receipts.build.sha256 === expectedBuildSha && receipts.clone.sha256 === expectedCloneSha && receipts.native_host.sha256 === expectedHostSha, 'diagnostic receipt identities drifted'); +const build = readSealed(receipts.build); +assert(build.state === 'DIAGNOSTIC_BUILD_IDENTITY_PASS' && build.build_id === receipts.build_id, 'diagnostic build state drifted'); +assert(build.non_comparable_to_stock === true && build.control_runtime_touched === false && build.control_noninterference?.matched === true, 'diagnostic build noninterference drifted'); +assert(build.release_and_tracing?.runtime_configuration_sha256 === receipts.runtime_configuration_sha256, 'diagnostic runtime configuration receipt drifted'); +assert(build.emulator?.path === diagnostics.emulator_path && build.emulator?.sha256 === diagnostics.emulator_sha256, 'diagnostic build emulator identity drifted'); +assert(JSON.stringify(build.emulator?.uuids) === JSON.stringify(diagnostics.emulator_uuids), 'diagnostic build emulator UUIDs drifted'); +assert(build.gfxstream_backend?.path === diagnostics.gfxstream_backend_path && build.gfxstream_backend?.sha256 === diagnostics.gfxstream_backend_sha256, 'diagnostic build gfxstream identity drifted'); +assert(JSON.stringify(build.gfxstream_backend?.uuids) === JSON.stringify(diagnostics.gfxstream_backend_uuids), 'diagnostic build gfxstream UUIDs drifted'); + +const clone = readSealed(receipts.clone); +assert(clone.state === 'DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS' && clone.build_id === receipts.build_id, 'diagnostic clone state drifted'); +assert(clone.diagnostic_avd?.name === diagnostics.avd_name && clone.diagnostic_avd?.avd_path === diagnostics.avd_directory, 'diagnostic clone AVD identity drifted'); +assert(clone.diagnostic_avd?.config_sha256 === diagnostics.avd_config_sha256 && clone.diagnostic_avd?.ini_sha256 === diagnostics.avd_ini_sha256, 'diagnostic clone configuration identity drifted'); +assert(clone.diagnostic_avd?.adb_server_port === diagnostics.adb_server_port && clone.diagnostic_avd?.console_port === diagnostics.console_port && clone.diagnostic_avd?.serial === diagnostics.serial, 'diagnostic clone port identity drifted'); +assert(clone.accepted_build?.sha256 === expectedBuildSha, 'diagnostic clone accepted-build link drifted'); +assert(clone.control_noninterference_matched === true && clone.sealed_before_first_boot === true, 'diagnostic clone seal drifted'); +assert(clone.first_boot_attempted === false && clone.launch_attempted === false && clone.control_runtime_mutation_attempted === false && clone.control_avd_touched === false, 'diagnostic clone no-first-boot boundary drifted'); + +const hostReceipt = readSealed(receipts.native_host); +assert(hostReceipt.state === 'DIAGNOSTIC_NATIVE_HOST_BUILD_PASS' && hostReceipt.build_id === receipts.build_id, 'diagnostic native-host state drifted'); +assert(hostReceipt.app?.path === diagnostics.host_application.path && hostReceipt.app?.bundle_identifier === diagnostics.host_application.bundle_identifier, 'diagnostic native-host app identity drifted'); +const diagnosticHostExecutable = path.join(diagnostics.host_application.path, diagnostics.host_application.executable_relative_path); +assertSha(diagnostics.host_application.executable_sha256, 'diagnostic native-host executable SHA'); +assert(hostReceipt.app?.executable?.path === diagnosticHostExecutable && hostReceipt.app?.executable?.sha256 === diagnostics.host_application.executable_sha256, 'diagnostic native-host executable receipt drifted'); +assert(externalSha(diagnosticHostExecutable) === diagnostics.host_application.executable_sha256, 'diagnostic native-host executable drifted'); +assert(hostReceipt.app?.codesign_verify_status === 0 && hostReceipt.control_runtime_mutation_attempted === false, 'diagnostic native-host signing/noninterference drifted'); +assert(hostReceipt.launch_contract?.method?.includes('/usr/bin/open') && hostReceipt.launch_contract?.emulator_spawn_owner === 'NATIVE_MACOS_APP_PROCESS' && hostReceipt.launch_contract?.service_context_emulator_spawn_forbidden === true, 'diagnostic native-host launch contract drifted'); + +const candidate = registry.modes.candidate; +assert(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate is not fail-closed'); +assert(candidate.state_namespace === 'candidate' && candidate.launch_strategy === 'blocked' && candidate.profile_policy === 'blocked', 'candidate isolation drifted'); +assert(candidate.requires_control_stopped === true && candidate.rollback_target === 'control', 'candidate rollback contract drifted'); + +const runtime = readText('tftmac/Runtime/TFTMACRuntime.swift'); +for (const forbidden of ['["-P", "5038"', '"emulator-5582"', '"@TFT_Ultra_Tablet"', '"-iTCP:5582"', '"-iTCP:8554"']) { + assert(!runtime.includes(forbidden), `shared runtime still hard-codes control identity: ${forbidden}`); +} +for (const required of [ + 'TFTMACSelectedRuntimeConfiguration', + 'configuration.authority.resolveForLaunch', + 'TFTMACRuntimeLease.acquire(', + 'identity: leaseIdentity', + 'validateLoadedRuntime(', + 'paths.adbServerPort', + 'paths.consolePort', + 'paths.controllerPort', + 'paths.serial', + 'paths.avdName' +]) assert(runtime.includes(required), `runtime is missing mode-aware source seam: ${required}`); + +const coordinator = readText('tftmac/App/AppCoordinator.swift'); +assert(coordinator.includes('TFTMACSelectedRuntimeConfiguration.load'), 'AppCoordinator does not load the accepted runtime configuration'); +assert(coordinator.includes('runtimeConfiguration: runtimeConfiguration'), 'AppCoordinator does not pass selected runtime authority'); +assert(coordinator.includes('activeApplicationSupport = runtimeConfiguration.applicationSupport'), 'AppCoordinator does not preserve mode-specific capture state'); + +const project = readText('TFTMAC.xcodeproj/project.pbxproj'); +for (const required of ['RuntimeMode.swift in Sources', 'RuntimeModeAuthority.swift in Sources', 'runtime-modes.json in Resources', 'runtime-authority.json in Resources']) { + assert(project.includes(required), `Xcode project is missing ${required}`); +} +const testCount = fs.readdirSync(absolute('Tests/TFTMACTests')) + .filter((name) => name.endsWith('.swift')) + .reduce((total, name) => { + const source = readText(`Tests/TFTMACTests/${name}`); + return total + (source.match(/^ func test/gm) ?? []).length; + }, 0); +assert(testCount === 49, `expected 49 native tests after Wave B, found ${testCount}`); + +const receipt = JSON.parse(readText(`${waveRoot}/IMPLEMENTATION_RECEIPT.json`)); +assert(receipt.state === 'WAVE_B_V4_IMPLEMENTATION_APPLIED', 'implementation receipt state drifted'); +assert(receipt.runtime_modes_sha256 === registrySha, 'implementation receipt registry SHA drifted'); +assert(receipt.effects?.source_only === true, 'implementation receipt is not source-only'); +for (const effect of ['emulator_launch_attempted', 'runtime_replacement_attempted', 'control_stop_attempted', 'installed_app_replacement_attempted', 'package_launch_attempted']) { + assert(receipt.effects?.[effect] === false, `implementation receipt reports forbidden effect: ${effect}`); +} + +console.log(JSON.stringify({ + state: 'WAVE_B_V4_SOURCE_VALIDATION_PASS', + runtime_modes_sha256: registrySha, + test_count: testCount, + control: { avd: control.avd_name, adb: control.adb_server_port, console: control.console_port, controller: control.controller_port, serial: control.serial }, + advanced_diagnostics: { state: diagnostics.launch_state, first_boot_attempted: clone.first_boot_attempted, launch_attempted: clone.launch_attempted }, + candidate: { state: candidate.launch_state }, + runtime_effect_attempted: false +}, null, 2)); diff --git a/TFTMAC.xcodeproj/project.pbxproj b/TFTMAC.xcodeproj/project.pbxproj index 667a8b3..7b493ae 100644 --- a/TFTMAC.xcodeproj/project.pbxproj +++ b/TFTMAC.xcodeproj/project.pbxproj @@ -50,6 +50,12 @@ 100000000000000000000035 /* GraphicsStackReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000021 /* GraphicsStackReceipt.swift */; }; 100000000000000000000036 /* GraphicsStackReceipt.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000021 /* GraphicsStackReceipt.swift */; }; 100000000000000000000037 /* GraphicsStackReceiptTests.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000022 /* GraphicsStackReceiptTests.swift */; }; + 100000000000000000000038 /* RuntimeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000023 /* RuntimeMode.swift */; }; + 100000000000000000000039 /* RuntimeMode.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000023 /* RuntimeMode.swift */; }; + 10000000000000000000003A /* runtime-modes.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000024 /* runtime-modes.json */; }; + 10000000000000000000003B /* RuntimeModeAuthority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; + 10000000000000000000003C /* RuntimeModeAuthority.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; + 10000000000000000000003D /* runtime-authority.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000026 /* runtime-authority.json */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -81,6 +87,10 @@ 200000000000000000000020 /* CombatBenchmarkAnalysisTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombatBenchmarkAnalysisTests.swift; sourceTree = ""; }; 200000000000000000000021 /* GraphicsStackReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicsStackReceipt.swift; sourceTree = ""; }; 200000000000000000000022 /* GraphicsStackReceiptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicsStackReceiptTests.swift; sourceTree = ""; }; + 200000000000000000000023 /* RuntimeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeMode.swift; sourceTree = ""; }; + 200000000000000000000024 /* runtime-modes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-modes.json; sourceTree = SOURCE_ROOT; }; + 200000000000000000000025 /* RuntimeModeAuthority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeModeAuthority.swift; sourceTree = ""; }; + 200000000000000000000026 /* runtime-authority.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-authority.json; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -107,6 +117,8 @@ 40000000000000000000000A /* Generated */, 400000000000000000000005 /* Probes */, 400000000000000000000007 /* Tests */, + 200000000000000000000024 /* runtime-modes.json */, + 200000000000000000000026 /* runtime-authority.json */, 400000000000000000000009 /* Products */, ); sourceTree = ""; @@ -143,7 +155,7 @@ path = Presentation; sourceTree = ""; }; - 40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000019 /* RuntimeLease.swift */, 20000000000000000000001A /* TelemetrySignalClassifier.swift */, 20000000000000000000001B /* GameFrameTelemetry.swift */, 200000000000000000000021 /* GraphicsStackReceipt.swift */, 20000000000000000000001E /* CombatBenchmarkAnalysis.swift */, 20000000000000000000001F /* CombatBenchmarkStore.swift */, 20000000000000000000001D /* TouchInput.swift */, 200000000000000000000015 /* TFTMACRuntime.swift */, 200000000000000000000016 /* AVDTransactionGuard.swift */,); path = Runtime; sourceTree = ""; }; + 40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000023 /* RuntimeMode.swift */, 200000000000000000000025 /* RuntimeModeAuthority.swift */, 200000000000000000000019 /* RuntimeLease.swift */, 20000000000000000000001A /* TelemetrySignalClassifier.swift */, 20000000000000000000001B /* GameFrameTelemetry.swift */, 200000000000000000000021 /* GraphicsStackReceipt.swift */, 20000000000000000000001E /* CombatBenchmarkAnalysis.swift */, 20000000000000000000001F /* CombatBenchmarkStore.swift */, 20000000000000000000001D /* TouchInput.swift */, 200000000000000000000015 /* TFTMACRuntime.swift */, 200000000000000000000016 /* AVDTransactionGuard.swift */,); path = Runtime; sourceTree = ""; }; 40000000000000000000000A /* Generated */ = {isa = PBXGroup; children = (40000000000000000000000B /* EmulatorController */,); path = Generated; sourceTree = ""; }; 40000000000000000000000B /* EmulatorController */ = {isa = PBXGroup; children = (200000000000000000000009 /* emulator_controller.pb.swift */, 200000000000000000000010 /* emulator_controller.grpc.swift */,); path = EmulatorController; sourceTree = ""; }; 400000000000000000000005 /* Probes */ = {isa = PBXGroup; children = (400000000000000000000006 /* EmbeddedControlProbe */,); path = Probes; sourceTree = ""; }; @@ -210,13 +222,13 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; }; + 800000000000000000000001 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (10000000000000000000003A /* runtime-modes.json in Resources */, 10000000000000000000003D /* runtime-authority.json in Resources */,); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 700000000000000000000001 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000001, 100000000000000000000002, 100000000000000000000003, 100000000000000000000027, 100000000000000000000004, 100000000000000000000005, 100000000000000000000020, 100000000000000000000021, 100000000000000000000023, 100000000000000000000025, 100000000000000000000028, 10000000000000000000002A, 10000000000000000000002C, 100000000000000000000035, 10000000000000000000002F, 100000000000000000000031, 100000000000000000000033, 100000000000000000000015, 100000000000000000000016,); runOnlyForDeploymentPostprocessing = 0; }; + 700000000000000000000001 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000001, 100000000000000000000002, 100000000000000000000003, 100000000000000000000027, 100000000000000000000004, 100000000000000000000005, 100000000000000000000020, 100000000000000000000021, 100000000000000000000023, 100000000000000000000025, 100000000000000000000038, 10000000000000000000003B, 100000000000000000000028, 10000000000000000000002A, 10000000000000000000002C, 100000000000000000000035, 10000000000000000000002F, 100000000000000000000031, 100000000000000000000033, 100000000000000000000015, 100000000000000000000016,); runOnlyForDeploymentPostprocessing = 0; }; 700000000000000000000002 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000006, 100000000000000000000017, 100000000000000000000018,); runOnlyForDeploymentPostprocessing = 0; }; - 700000000000000000000003 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000007, 10000000000000000000001C, 100000000000000000000008, 100000000000000000000022, 100000000000000000000024, 100000000000000000000026, 100000000000000000000029, 10000000000000000000002B, 10000000000000000000002D, 10000000000000000000002E, 100000000000000000000036, 100000000000000000000030, 100000000000000000000032, 100000000000000000000034, 100000000000000000000037,); runOnlyForDeploymentPostprocessing = 0; }; + 700000000000000000000003 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000007, 10000000000000000000001C, 100000000000000000000008, 100000000000000000000022, 100000000000000000000024, 100000000000000000000026, 100000000000000000000039, 10000000000000000000003C, 100000000000000000000029, 10000000000000000000002B, 10000000000000000000002D, 10000000000000000000002E, 100000000000000000000036, 100000000000000000000030, 100000000000000000000032, 100000000000000000000034, 100000000000000000000037,); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ diff --git a/Tests/TFTMACTests/TFTMACGate1Tests.swift b/Tests/TFTMACTests/TFTMACGate1Tests.swift index 028e25f..59893a8 100644 --- a/Tests/TFTMACTests/TFTMACGate1Tests.swift +++ b/Tests/TFTMACTests/TFTMACGate1Tests.swift @@ -264,4 +264,97 @@ final class TFTMACGate1Tests: XCTestCase { PipelineLogSignals(vulkanErrorCount: 1, moltenVKWarningCount: 1, shaderErrorCount: 1) ) } + + private func runtimeModeRegistryData() throws -> Data { + let repositoryRoot = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + return try Data(contentsOf: repositoryRoot.appendingPathComponent("ssot/runtime-modes.json")) + } + + func testRuntimeModeRegistryDefinesExactControlIdentity() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + XCTAssertEqual(Set(registry.document.modes.keys), Set(TFTMACRuntimeMode.allCases.map(\.rawValue))) + XCTAssertEqual(registry.document.defaultMode, .control) + let selection = try registry.selection(environment: [:]) + XCTAssertEqual(selection.mode, .control) + XCTAssertEqual(selection.definition.avdName, "TFT_Ultra_Tablet") + XCTAssertEqual(selection.definition.adbServerPort, 5038) + XCTAssertEqual(selection.definition.consolePort, 5582) + XCTAssertEqual(selection.definition.controllerPort, 8554) + XCTAssertEqual(selection.definition.serial, "emulator-5582") + } + + func testRuntimeModeRegistryFailsClosedForUnacceptedModes() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + for requested in ["advanced_diagnostics", "candidate", "unknown"] { + XCTAssertThrowsError(try registry.selection(environment: [ + TFTMACRuntimeModeRegistry.environmentKey: requested + ]), requested) + } + } + + func testRuntimeModeRegistryRejectsTamperedBytes() throws { + var data = try runtimeModeRegistryData() + data.append(Data(" ".utf8)) + XCTAssertThrowsError(try TFTMACRuntimeModeRegistry(data: data)) + XCTAssertThrowsError(try TFTMACRuntimeModeAuthority(data: data)) + } + + func testSupplementalRuntimeAuthoritySeparatesStateAndLaunchStrategies() throws { + let data = try runtimeModeRegistryData() + let registry = try TFTMACRuntimeModeRegistry(data: data) + let authority = try TFTMACRuntimeModeAuthority(data: data) + XCTAssertNoThrow(try authority.validateConsistency(with: registry)) + let control = try authority.definition(for: .control) + let diagnostics = try authority.definition(for: .advancedDiagnostics) + let candidate = try authority.definition(for: .candidate) + XCTAssertEqual(control.launchStrategy, .bundledForwarder) + XCTAssertEqual(diagnostics.launchStrategy, .externalNativeHost) + XCTAssertEqual(candidate.launchStrategy, .blocked) + XCTAssertNotEqual(control.stateNamespace, diagnostics.stateNamespace) + XCTAssertNotEqual(diagnostics.stateNamespace, candidate.stateNamespace) + XCTAssertNotNil(diagnostics.diagnosticReceipts) + XCTAssertNil(candidate.hostApplication) + XCTAssertNotEqual( + authority.applicationSupportURL(for: .control), + authority.applicationSupportURL(for: .advancedDiagnostics) + ) + } + + func testControlModePreservesValidatedNativeProfile() throws { + let data = try runtimeModeRegistryData() + let registry = try TFTMACRuntimeModeRegistry(data: data) + let authority = try TFTMACRuntimeModeAuthority(data: data) + let selection = try registry.selection(environment: [:]) + let effective = try authority.effectiveProfile(savedProfile: .playable, selection: selection) + XCTAssertEqual(effective, .playable) + XCTAssertEqual(effective.controllerPort, selection.definition.controllerPort) + } + + func testRuntimeLeasePersistsExactModeIdentityAndRejectsSecondOwner() throws { + let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) + let selection = try registry.selection(environment: [:]) + let identity = try selection.leaseIdentity() + let stateRoot = FileManager.default.temporaryDirectory + .appendingPathComponent("tftmac-mode-lease-test-\(UUID().uuidString)", isDirectory: true) + defer { try? FileManager.default.removeItem(at: stateRoot) } + let first = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: identity) + defer { first.release() } + let leaseURL = stateRoot.appendingPathComponent("native-runtime.lease") + let object = try XCTUnwrap( + try JSONSerialization.jsonObject(with: Data(contentsOf: leaseURL)) as? [String: Any] + ) + XCTAssertEqual((object["schema"] as? NSNumber)?.intValue, 2) + XCTAssertEqual(object["mode"] as? String, "control") + XCTAssertEqual(object["registry_sha256"] as? String, registry.registrySha256) + XCTAssertEqual(object["configuration_sha256"] as? String, selection.definition.configurationSha256) + XCTAssertEqual(object["avd_name"] as? String, "TFT_Ultra_Tablet") + XCTAssertEqual((object["adb_server_port"] as? NSNumber)?.intValue, 5038) + XCTAssertEqual((object["console_port"] as? NSNumber)?.intValue, 5582) + XCTAssertEqual((object["controller_port"] as? NSNumber)?.intValue, 8554) + XCTAssertEqual(object["serial"] as? String, "emulator-5582") + XCTAssertThrowsError(try TFTMACRuntimeLease.acquire(stateRoot: stateRoot, identity: identity)) + } } diff --git a/facts.md b/facts.md index c12abc3..7139a50 100644 --- a/facts.md +++ b/facts.md @@ -1,7 +1,7 @@ # TFTMAC Facts -**Authority date:** 2026-08-31 America/Chicago -**Observed runtime evidence through:** 2026-08-31T23:13:30Z +**Authority date:** 2026-09-01 America/Chicago +**Observed runtime/source evidence through:** 2026-09-02T02:07:03Z **Purpose:** preserve facts and hard boundaries that future TFTMAC work must not casually reinterpret. This file separates durable product facts from mutable observations and historical @@ -79,8 +79,10 @@ must never be presented as measurements of this M4 Mac mini. login keychain now exposes zero valid code-signing identities and `codesign --verify --deep --strict` fails with `CSSMERR_TP_NOT_TRUSTED`. Current-host installed-runtime verification is therefore blocked until the - local identity is repaired in a separate operational task. This does not - rewrite the historical acceptance result. + local identity is repaired. This does not block unsigned source builds, + diagnostic-runtime work, or causal instrumentation; it must be repaired + before a final signed candidate installation/cutover. This does not rewrite + the historical acceptance result. ## 3. Launch and ADB architecture @@ -525,7 +527,28 @@ campaign, useful for candidate selection but not current M4 runtime performance: measured, but no matched valid Control/Combat Latency A pair exists. Never call it faster until a compatible comparison exists. -## 13. Explicit unknowns and open acceptance +## 13. Causal graphics implementation state + +- **VERIFIED CURRENT (2026-09-02T02:07:03Z):** Wave B source integration is + complete under the append-only Wave B v4 correction authority. The default + and only launch-ready mode is `control`; `advanced_diagnostics` remains + blocked pending a separately receipted EmulatorController port, and + `candidate` remains blocked. +- **VERIFIED CURRENT:** runtime-mode registry SHA-256 is + `136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479`. + Runtime identity, registry/configuration hashes, AVD identity, ADB/console/ + controller ports, and serial are persisted in the exclusive lease contract. +- **VERIFIED CURRENT:** `scripts/verify-tftmac.command` completed with exit code + 0, produced an unsigned Release build, and passed all 49 native tests with + zero failures. The post-verification process audit found no active TFTMAC, + emulator, or `qemu-system-aarch64` process; no runtime, AVD, installed app, or + official TFT package was changed or launched by Wave B. +- **LOCKED NEXT GATE:** diagnostic first boot may occur only after a + collision-free controller port is allocated and sealed. Wave C causal-event + instrumentation remains closed until diagnostic AVD/runtime acceptance + passes. + +## 14. Explicit unknowns and open acceptance 1. Combat Latency A's effect on continuous whole-run FPS, 1% low, p95/p99, frame-budget misses, and visible stutter versus Control. @@ -546,7 +569,7 @@ campaign, useful for candidate selection but not current M4 runtime performance: 10. Whether any owned candidate can hold the complete automatic run at the 60 FPS target without correctness, audio, login, memory, or cleanup regression. -## 14. Authority and update rule +## 15. Authority and update rule Use this precedence for current truth: diff --git a/scripts/build-native-app.command b/scripts/build-native-app.command index 0d4d316..8891c92 100755 --- a/scripts/build-native-app.command +++ b/scripts/build-native-app.command @@ -99,8 +99,85 @@ HOST_MACOS="${HOST_APP}/Contents/MacOS" /usr/bin/plutil -lint "${HOST_APP}/Contents/Info.plist" >/dev/null /usr/bin/codesign --force --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${HOST_APP}" -/usr/bin/codesign --force --deep --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${DIST}" +# Seal the non-reproducible signed Mach-O identity into a receipt that is then +# protected by the outer application signature. Source and Info.plist hashes +# remain fixed in the runtime-mode registry; the signed receipt binds those +# inputs to the exact packaged host executable and UUID. +/usr/bin/python3 - "${ROOT}" "${DIST}" "${HOST_APP}" <<'PY' +import datetime +import hashlib +import json +import pathlib +import plistlib +import re +import subprocess +import sys + +root = pathlib.Path(sys.argv[1]) +dist = pathlib.Path(sys.argv[2]) +host = pathlib.Path(sys.argv[3]) +source = root / "RuntimeHost/main.c" +info_source = root / "RuntimeHost/Info.plist" +info_packaged = host / "Contents/Info.plist" +executable = host / "Contents/MacOS/TFTMACEmulatorHost" + +def sha256(path): + h = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + +uuid_output = subprocess.check_output(["/usr/bin/dwarfdump", "--uuid", str(executable)], text=True) +uuids = [f"{match.group(1)}:{match.group(2)}" for match in re.finditer(r"UUID: ([0-9A-F-]+) \(([^)]+)\)", uuid_output)] +if not uuids: + raise SystemExit("Control native host has no Mach-O UUID receipt") +with info_packaged.open("rb") as handle: + bundle_identifier = plistlib.load(handle)["CFBundleIdentifier"] +compiler = subprocess.check_output(["/usr/bin/xcrun", "--find", "clang"], text=True).strip() +compiler_version = subprocess.check_output([compiler, "--version"], text=True).splitlines()[0] +receipt = { + "schema": 1, + "state": "CONTROL_NATIVE_HOST_BUILD_PASS", + "generated_at_utc": datetime.datetime.now(datetime.timezone.utc).isoformat(), + "host_application_relative_path": "TFTMAC Emulator Host.app", + "bundle_identifier": bundle_identifier, + "source_path": "RuntimeHost/main.c", + "source_sha256": sha256(source), + "info_plist_path": "RuntimeHost/Info.plist", + "info_plist_sha256": sha256(info_source), + "packaged_info_plist_sha256": sha256(info_packaged), + "executable_relative_path": "Contents/MacOS/TFTMACEmulatorHost", + "executable_sha256": sha256(executable), + "executable_uuids": uuids, + "compiler_path": compiler, + "compiler_version": compiler_version, + "compile_arguments": ["-Os", "-arch", "arm64", "-mmacosx-version-min=15.0"], + "signed_before_receipt": True, + "outer_app_seals_receipt": True +} +receipt_path = dist / "Contents/Resources/control-host-build.json" +receipt_path.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n") +PY + +# The nested host is already signed. Sign the outer app without deep-resigning +# it, so the exact executable hash in the newly written receipt stays true. +/usr/bin/codesign --force --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${DIST}" /usr/bin/codesign --verify --deep --strict --verbose=2 "${DIST}" +/usr/bin/python3 - "${DIST}" "${HOST_APP}" <<'PY' +import hashlib +import json +import pathlib +import sys + +dist = pathlib.Path(sys.argv[1]) +host = pathlib.Path(sys.argv[2]) +receipt = json.loads((dist / "Contents/Resources/control-host-build.json").read_text()) +executable = host / receipt["executable_relative_path"] +h = hashlib.sha256(executable.read_bytes()).hexdigest() +if h != receipt["executable_sha256"]: + raise SystemExit("Outer signing changed the receipted control-host executable") +PY /usr/bin/codesign -dvv "${DIST}" 2>&1 \ | /usr/bin/grep -F "Authority=${SIGNING_IDENTITY_NAME}" >/dev/null diff --git a/scripts/verify-tftmac.command b/scripts/verify-tftmac.command index d8abe33..898395d 100755 --- a/scripts/verify-tftmac.command +++ b/scripts/verify-tftmac.command @@ -47,6 +47,10 @@ for required in \ ssot/AUTHORITY_INPUTS.sha256 \ ssot/STACK.lock.yaml \ ssot/runtime-authority.json \ + ssot/runtime-modes.json \ + tftmac/Runtime/RuntimeMode.swift \ + tftmac/Runtime/RuntimeModeAuthority.swift \ + .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs \ ssot/retained-evidence-index.json \ ssot/TFTMAC_ENGINEERING_MAP.sql \ ssot/TFTMAC_PERFORMANCE_LAB.sql; do @@ -201,7 +205,7 @@ while read -r expected_hash authority_path; do done < ssot/AUTHORITY_INPUTS.sha256 readonly TEST_FUNCTION_COUNT="$(rg -n '^[[:space:]]*func test' Tests/TFTMACTests --glob '*.swift' | wc -l | tr -d '[:space:]')" -[[ "$TEST_FUNCTION_COUNT" == "43" ]] || fail "native test inventory drifted: expected 43, found $TEST_FUNCTION_COUNT" +[[ "$TEST_FUNCTION_COUNT" == "49" ]] || fail "native test inventory drifted: expected 49, found $TEST_FUNCTION_COUNT" [[ "$(plutil -extract LSSupportsGameMode raw "$INFO")" == "true" ]] \ || fail "native app is not eligible for macOS Game Mode" [[ "$(shasum -a 256 tftmac/Assets/TFTMAC-Official-Icon.png | awk '{print $1}')" == "d6ba9ceb76c4b1e44e87f059f775a0ed629f9bea29b0dd73245853d7dca3a016" ]] \ @@ -233,6 +237,7 @@ while IFS= read -r script; do done < <(find scripts -type f \( -name '*.command' -o -name '*.sh' \) | LC_ALL=C sort) node --check tools/tftmac-direct-control.mjs >/dev/null +node --check .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs >/dev/null [[ ! -f tools/tftmac-v2.mjs ]] || node --check tools/tftmac-v2.mjs >/dev/null node tools/tftmac-direct-control.mjs engineering-map-selftest >/dev/null node tools/tftmac-direct-control.mjs lab-selftest >/dev/null @@ -282,8 +287,14 @@ readonly RELEASE_DERIVED="${ROOT}/.build/native-ci-release" -derivedDataPath "$RELEASE_DERIVED" \ CODE_SIGNING_ALLOWED=NO \ build -[[ -x "${RELEASE_DERIVED}/Build/Products/Release/TFTMAC.app/Contents/MacOS/TFTMAC" ]] \ +readonly RELEASE_APP="${RELEASE_DERIVED}/Build/Products/Release/TFTMAC.app" +[[ -x "${RELEASE_APP}/Contents/MacOS/TFTMAC" ]] \ || fail "unsigned Release build did not produce the TFTMAC executable" +cmp -s ssot/runtime-modes.json "${RELEASE_APP}/Contents/Resources/runtime-modes.json" \ + || fail "unsigned Release app did not package the exact runtime-mode registry" +cmp -s ssot/runtime-authority.json "${RELEASE_APP}/Contents/Resources/runtime-authority.json" \ + || fail "unsigned Release app did not package the exact control authority" +node .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs >/dev/null /bin/zsh scripts/test-native-app.command @@ -293,4 +304,4 @@ cmp -s "$STATE_BEFORE" "$STATE_AFTER" || { fail "source verification changed tracked or visible generated state" } -print "TFTMAC source validation: OK (unsigned Release build; 43 native tests)" +print "TFTMAC source validation: OK (unsigned Release build; 49 native tests; Wave B mode authority PASS)" diff --git a/ssot/runtime-modes.json b/ssot/runtime-modes.json index 77c7dee..f29e550 100644 --- a/ssot/runtime-modes.json +++ b/ssot/runtime-modes.json @@ -36,7 +36,75 @@ "rollback_target": "control", "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1", "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901", - "serial": "emulator-5586" + "serial": "emulator-5586", + "state_namespace": "advanced_diagnostics", + "uses_legacy_application_support_root": false, + "emulator_identifier": "TFTMAC-DIAGNOSTIC", + "launch_strategy": "external_native_host", + "profile_policy": "fixed_registry_profile", + "locked_profile": { + "identifier": "tftmac_diagnostic_r9", + "width": 1920, + "height": 1080, + "density_dpi": 280, + "refresh_hz": 60, + "vcpu": 6, + "ram_mib": 6144, + "gpu_mode": "host", + "audio_backend": "coreaudio", + "graphics_transport": "pipe", + "asg_write_buffer_size": 1048576, + "asg_write_step_size": 4096, + "asg_data_ring_size": 32768, + "asg_draw_flush_interval": 800, + "angle_enabled_features": "exposeNonConformantExtensionsAndVersions:exposeES32ForTesting", + "angle_disabled_features": "preferSubmitAtFBOBoundary" + }, + "adb_sha256": "1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b", + "adb_vendor_keys_policy": "USER_DEFAULT_KEY", + "expected_emulator_version_contains": "35.6.3", + "emulator_uuids": [ + "4C4C4436-5555-3144-A1EE-05B0F446F580:arm64" + ], + "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64", + "qemu_sha256": "042c4932b17fd09ff056ecc2dd21084e08e1110b774c594bbcaf1e4d1ceac608", + "qemu_uuids": [ + "4C4C447F-5555-3144-A16C-0DB6C4482B7A:arm64" + ], + "gfxstream_backend_uuids": [ + "4C4C4449-5555-3144-A1FC-F6DFE0021481:arm64" + ], + "host_application": { + "kind": "external_application", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/TFTMAC Diagnostic Host.app", + "bundle_identifier": "com.flashls1.tftmac.runtime.diagnostics", + "executable_relative_path": "Contents/MacOS/TFTMACApp", + "executable_sha256": "d335a23d710956f96a4c01f977d49437424c9fd52ccc20ed872e5786d206eef2", + "source_path": null, + "source_sha256": null, + "info_plist_path": null, + "info_plist_sha256": "4e15592461ce8a50f17ccd6285fd12fcd84dd407eba86919f90c8c0026b5ca61", + "build_receipt_resource": null + }, + "diagnostic_receipts": { + "build_id": "gate4-r9-20260901", + "runtime_configuration_sha256": "005c85a2a7ffe86e7626c871fd3dd23f42c5d3ce994162d17b032e69cfc4d4f3", + "build": { + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json", + "sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d", + "required_state": "DIAGNOSTIC_BUILD_IDENTITY_PASS" + }, + "clone": { + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json", + "sha256": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648", + "required_state": "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS" + }, + "native_host": { + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json", + "sha256": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067", + "required_state": "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS" + } + } }, "candidate": { "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/platform-tools/adb", @@ -72,7 +140,23 @@ "rollback_target": "control", "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Candidate", "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK", - "serial": "emulator-5590" + "serial": "emulator-5590", + "state_namespace": "candidate", + "uses_legacy_application_support_root": false, + "emulator_identifier": "TFTMAC-CANDIDATE", + "launch_strategy": "blocked", + "profile_policy": "blocked", + "locked_profile": null, + "adb_sha256": null, + "adb_vendor_keys_policy": "UNRESOLVED", + "expected_emulator_version_contains": null, + "emulator_uuids": null, + "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Candidate/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64", + "qemu_sha256": null, + "qemu_uuids": null, + "gfxstream_backend_uuids": null, + "host_application": null, + "diagnostic_receipts": null }, "control": { "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb", @@ -94,13 +178,13 @@ "avd_ini_sha256": null, "avd_name": "TFT_Ultra_Tablet", "comparability_class": "STOCK_BUILD8_CONTROL", - "configuration_sha256": "bc8408b26402bf53011003afd83944a5fc85f70c4fe1e48909dd2882f8a19633", + "configuration_sha256": "b74eb944b70af29b73ab9cfa3a5bcb522e728a66f1c89ec2b767c36dc90dfc38", "console_port": 5582, "controller_port": 8554, "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator", - "emulator_sha256": null, + "emulator_sha256": "b3b8fc0dcedcf6e15b54b41f3e5156319029aa00b88a59fd489f80abdd8fc133", "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64/libgfxstream_backend.dylib", - "gfxstream_backend_sha256": null, + "gfxstream_backend_sha256": "3772fef215058831ea419c9281fd203d010003d5defdc195dd120bc7748e4093", "launch_state": "enabled", "library_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/lib64", "mode": "control", @@ -108,8 +192,43 @@ "rollback_target": "control", "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime", "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", - "serial": "emulator-5582" + "serial": "emulator-5582", + "state_namespace": "control", + "uses_legacy_application_support_root": true, + "emulator_identifier": "TFTMAC", + "launch_strategy": "bundled_forwarder", + "profile_policy": "validated_native_preferences", + "locked_profile": null, + "adb_sha256": "1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b", + "adb_vendor_keys_policy": "ABSENT", + "expected_emulator_version_contains": "37.1.11", + "emulator_uuids": [ + "4C4C449E-5555-3144-A182-644CCB895091:arm64" + ], + "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64", + "qemu_sha256": "eaa97a970b81f81640db73ed79e19ee173323653a0a1203217e1199d078011f3", + "qemu_uuids": [ + "4C4C4467-5555-3144-A10A-A9E5A99446F1:arm64" + ], + "gfxstream_backend_uuids": [ + "4C4C4406-5555-3144-A122-8AC522465662:arm64" + ], + "host_application": { + "kind": "bundled_resource", + "path": "TFTMAC Emulator Host.app", + "bundle_identifier": "com.flashls1.tftmac.emulator-host", + "executable_relative_path": "Contents/MacOS/TFTMACEmulatorHost", + "executable_sha256": null, + "source_path": "RuntimeHost/main.c", + "source_sha256": "c749cd998a6f066e2f7a6ef818eecf05b90d1a8808f6c9966e0b5fc21affeeed", + "info_plist_path": "RuntimeHost/Info.plist", + "info_plist_sha256": "cab05fb3b54fb76c9b1b85e9f6a66aebcc5b91bed98c757b603db89e2b7939ca", + "build_receipt_resource": "control-host-build.json" + }, + "diagnostic_receipts": null } }, - "schema": 1 + "schema": 1, + "contract": "TFTMAC_RUNTIME_MODES_V1", + "selection_environment_variable": "TFTMAC_RUNTIME_MODE" } diff --git a/tftmac/App/AppCoordinator.swift b/tftmac/App/AppCoordinator.swift index 8fe73c4..9852ade 100644 --- a/tftmac/App/AppCoordinator.swift +++ b/tftmac/App/AppCoordinator.swift @@ -7,43 +7,55 @@ final class AppCoordinator: NSObject, NSApplicationDelegate { private var runtimeController: TFTMACRuntimeController? private var settingsWindowController: RuntimeSettingsWindowController? private var activeProfile: TFTMACRuntimeProfile = .playable + private var activeApplicationSupport = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) private var terminationInProgress = false func applicationDidFinishLaunching(_ notification: Notification) { let controller = MainWindowController(mailbox: mailbox) mainWindowController = controller - let activeProfile = TFTMACRuntimeProfile.load() - self.activeProfile = activeProfile - let runtime = TFTMACRuntimeController( - profile: activeProfile, - mailbox: mailbox, - status: { [weak controller] text, isError in - controller?.emulatorView.setStatus(text, isError: isError) - }, - gameFrame: { [weak controller] window in - controller?.emulatorView.setGameFrameWindow(window) - } - ) - runtimeController = runtime - controller.emulatorView.onTouchInput = { [weak runtime] input in - runtime?.sendTouch(input) - } - controller.emulatorView.onMouseInput = { [weak runtime] x, y, buttons in - runtime?.sendMouse(x: x, y: y, buttons: buttons) - } - controller.emulatorView.onKeyboardInput = { [weak runtime] text, key in - runtime?.sendKeyboard(text: text, key: key) - } - controller.emulatorView.onPresentationSample = { [weak runtime] sample in - runtime?.recordPresentation(sample) - } - controller.emulatorView.onHostPresentationWindow = { [weak runtime] sample in - runtime?.recordHostPresentation(sample) - } controller.showWindow(nil) controller.window?.makeFirstResponder(controller.emulatorView) NSApp.activate(ignoringOtherApps: true) - runtime.start() + + do { + let savedProfile = TFTMACRuntimeProfile.load() + let runtimeConfiguration = try TFTMACSelectedRuntimeConfiguration.load( + savedProfile: savedProfile + ) + activeProfile = runtimeConfiguration.profile + activeApplicationSupport = runtimeConfiguration.applicationSupport + let runtime = TFTMACRuntimeController( + runtimeConfiguration: runtimeConfiguration, + mailbox: mailbox, + status: { [weak controller] text, isError in + controller?.emulatorView.setStatus(text, isError: isError) + }, + gameFrame: { [weak controller] window in + controller?.emulatorView.setGameFrameWindow(window) + } + ) + runtimeController = runtime + controller.emulatorView.onTouchInput = { [weak runtime] input in + runtime?.sendTouch(input) + } + controller.emulatorView.onMouseInput = { [weak runtime] x, y, buttons in + runtime?.sendMouse(x: x, y: y, buttons: buttons) + } + controller.emulatorView.onKeyboardInput = { [weak runtime] text, key in + runtime?.sendKeyboard(text: text, key: key) + } + controller.emulatorView.onPresentationSample = { [weak runtime] sample in + runtime?.recordPresentation(sample) + } + controller.emulatorView.onHostPresentationWindow = { [weak runtime] sample in + runtime?.recordHostPresentation(sample) + } + runtime.start() + } catch { + controller.emulatorView.setStatus(error.localizedDescription, isError: true) + } + DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak controller] in controller?.enterNativeFullscreen() } @@ -82,8 +94,8 @@ final class AppCoordinator: NSObject, NSApplicationDelegate { @objc func markMatchEnd(_ sender: Any?) { recordMarker("MATCH_END") } @objc func revealCaptureFolder(_ sender: Any?) { - let captures = FileManager.default.homeDirectoryForCurrentUser - .appendingPathComponent("Library/Application Support/TFTMAC/Captures", isDirectory: true) + let captures = activeApplicationSupport + .appendingPathComponent("Captures", isDirectory: true) try? FileManager.default.createDirectory(at: captures, withIntermediateDirectories: true) NSWorkspace.shared.open(captures) } diff --git a/tftmac/Runtime/RuntimeLease.swift b/tftmac/Runtime/RuntimeLease.swift index a64f86c..b21badc 100644 --- a/tftmac/Runtime/RuntimeLease.swift +++ b/tftmac/Runtime/RuntimeLease.swift @@ -16,18 +16,80 @@ enum RuntimeLeaseError: LocalizedError, Sendable { } final class TFTMACRuntimeLease: @unchecked Sendable { + private struct Payload: Codable { + let schema: Int + let pid: Int32 + let token: String + let createdUTC: String + let mode: TFTMACRuntimeMode? + let registrySha256: String? + let configurationSha256: String? + let avdName: String? + let adbServerPort: Int? + let consolePort: Int? + let controllerPort: Int? + let serial: String? + + enum CodingKeys: String, CodingKey { + case schema + case pid + case token + case createdUTC = "created_utc" + case mode + case registrySha256 = "registry_sha256" + case configurationSha256 = "configuration_sha256" + case avdName = "avd_name" + case adbServerPort = "adb_server_port" + case consolePort = "console_port" + case controllerPort = "controller_port" + case serial + } + + init( + schema: Int, + pid: Int32, + token: String, + createdUTC: String, + identity: TFTMACRuntimeLeaseIdentity? + ) { + self.schema = schema + self.pid = pid + self.token = token + self.createdUTC = createdUTC + mode = identity?.mode + registrySha256 = identity?.registrySha256 + configurationSha256 = identity?.configurationSha256 + avdName = identity?.avdName + adbServerPort = identity?.adbServerPort + consolePort = identity?.consolePort + controllerPort = identity?.controllerPort + serial = identity?.serial + } + } + let processIdentifier: Int32 let token: String let url: URL + let identity: TFTMACRuntimeLeaseIdentity? private var released = false - private init(url: URL, processIdentifier: Int32, token: String) { + private init( + url: URL, + processIdentifier: Int32, + token: String, + identity: TFTMACRuntimeLeaseIdentity? + ) { self.url = url self.processIdentifier = processIdentifier self.token = token + self.identity = identity } - static func acquire(stateRoot: URL, processIdentifier: Int32 = ProcessInfo.processInfo.processIdentifier) throws -> Self { + static func acquire( + stateRoot: URL, + identity: TFTMACRuntimeLeaseIdentity? = nil, + processIdentifier: Int32 = ProcessInfo.processInfo.processIdentifier + ) throws -> Self { try FileManager.default.createDirectory( at: stateRoot, withIntermediateDirectories: true, @@ -38,18 +100,26 @@ final class TFTMACRuntimeLease: @unchecked Sendable { for _ in 0..<2 { let descriptor = Darwin.open(url.path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR) if descriptor >= 0 { - let payload: [String: Any] = [ - "schema": 1, - "pid": processIdentifier, - "token": token, - "created_utc": ISO8601DateFormatter().string(from: Date()) - ] + let payload = Payload( + schema: identity == nil ? 1 : 2, + pid: processIdentifier, + token: token, + createdUTC: ISO8601DateFormatter().string(from: Date()), + identity: identity + ) do { - let data = try JSONSerialization.data(withJSONObject: payload, options: [.sortedKeys]) + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + let data = try encoder.encode(payload) try writeAll(data, to: descriptor) _ = Darwin.fsync(descriptor) Darwin.close(descriptor) - return Self(url: url, processIdentifier: processIdentifier, token: token) + return Self( + url: url, + processIdentifier: processIdentifier, + token: token, + identity: identity + ) } catch { Darwin.close(descriptor) try? FileManager.default.removeItem(at: url) @@ -71,19 +141,19 @@ final class TFTMACRuntimeLease: @unchecked Sendable { func release() { guard !released else { return } released = true - guard let data = try? Data(contentsOf: url), - let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any], - object["token"] as? String == token else { return } + guard let payload = Self.payload(at: url), payload.token == token else { return } try? FileManager.default.removeItem(at: url) } deinit { release() } + private static func payload(at url: URL) -> Payload? { + guard let data = try? Data(contentsOf: url) else { return nil } + return try? JSONDecoder().decode(Payload.self, from: data) + } + private static func leaseOwner(at url: URL) -> Int32? { - guard let data = try? Data(contentsOf: url), - let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any], - let number = object["pid"] as? NSNumber else { return nil } - return number.int32Value + payload(at: url)?.pid } private static func processExists(_ processIdentifier: Int32) -> Bool { @@ -97,7 +167,9 @@ final class TFTMACRuntimeLease: @unchecked Sendable { var written = 0 while written < rawBuffer.count { let result = Darwin.write(descriptor, baseAddress.advanced(by: written), rawBuffer.count - written) - guard result > 0 else { throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) } + guard result > 0 else { + throw RuntimeLeaseError.cannotCreate(String(cString: strerror(errno))) + } written += result } } diff --git a/tftmac/Runtime/RuntimeMode.swift b/tftmac/Runtime/RuntimeMode.swift new file mode 100644 index 0000000..81fd9e6 --- /dev/null +++ b/tftmac/Runtime/RuntimeMode.swift @@ -0,0 +1,556 @@ +import CryptoKit +import Foundation + +enum TFTMACRuntimeMode: String, Codable, CaseIterable, Sendable { + case control + case advancedDiagnostics = "advanced_diagnostics" + case candidate +} + +enum TFTMACRuntimeModeLaunchState: String, Codable, Sendable { + case enabled + case blockedPendingControllerLease = "blocked_pending_controller_lease" + case blockedNotBuilt = "blocked_not_built" +} + +struct TFTMACRuntimeModeError: LocalizedError, Sendable { + let message: String + + var errorDescription: String? { message } +} + +struct TFTMACRuntimeModeManifest: Codable, Equatable, Sendable { + let kind: String + let path: String + let sha256: String? +} + +struct TFTMACRuntimeModeDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let launchState: TFTMACRuntimeModeLaunchState + let runtimeRoot: String + let sdkRoot: String + let libraryRoot: String + let emulatorPath: String + let emulatorSha256: String? + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String? + let adbPath: String + let avdHome: String + let avdName: String + let avdDirectory: String + let avdConfigPath: String + let avdConfigSha256: String? + let avdIniPath: String + let avdIniSha256: String? + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int? + let serial: String + let authorityManifest: TFTMACRuntimeModeManifest + let applicationBundleId: String + let applicationVersion: String + let applicationBuild: String + let allowedPurpose: String + let comparabilityClass: String + let rollbackTarget: TFTMACRuntimeMode + let requiresControlStopped: Bool + let configurationSha256: String + + var computedConfigurationSha256: String { + let fields = [ + "mode=\(mode.rawValue)", + "launch_state=\(launchState.rawValue)", + "runtime_root=\(runtimeRoot)", + "sdk_root=\(sdkRoot)", + "library_root=\(libraryRoot)", + "emulator_path=\(emulatorPath)", + "emulator_sha256=\(emulatorSha256 ?? "")", + "gfxstream_backend_path=\(gfxstreamBackendPath)", + "gfxstream_backend_sha256=\(gfxstreamBackendSha256 ?? "")", + "adb_path=\(adbPath)", + "avd_home=\(avdHome)", + "avd_name=\(avdName)", + "avd_directory=\(avdDirectory)", + "avd_config_path=\(avdConfigPath)", + "avd_config_sha256=\(avdConfigSha256 ?? "")", + "avd_ini_path=\(avdIniPath)", + "avd_ini_sha256=\(avdIniSha256 ?? "")", + "adb_server_port=\(adbServerPort)", + "console_port=\(consolePort)", + "controller_port=\(controllerPort.map { String($0) } ?? "")", + "serial=\(serial)", + "authority_manifest_kind=\(authorityManifest.kind)", + "authority_manifest_path=\(authorityManifest.path)", + "authority_manifest_sha256=\(authorityManifest.sha256 ?? "")", + "application_bundle_id=\(applicationBundleId)", + "application_version=\(applicationVersion)", + "application_build=\(applicationBuild)", + "allowed_purpose=\(allowedPurpose)", + "comparability_class=\(comparabilityClass)", + "rollback_target=\(rollbackTarget.rawValue)", + "requires_control_stopped=\(requiresControlStopped ? "true" : "false")" + ] + return Self.sha256Hex(Data(fields.joined(separator: "\n").utf8)) + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} + +struct TFTMACRuntimeModeRegistryDocument: Codable, Equatable, Sendable { + let schema: Int + let defaultMode: TFTMACRuntimeMode + let activeLeaseRelativePath: String + let modes: [String: TFTMACRuntimeModeDefinition] +} + +struct TFTMACRuntimeLeaseIdentity: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let registrySha256: String + let configurationSha256: String + let avdName: String + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + + enum CodingKeys: String, CodingKey { + case mode + case registrySha256 = "registry_sha256" + case configurationSha256 = "configuration_sha256" + case avdName = "avd_name" + case adbServerPort = "adb_server_port" + case consolePort = "console_port" + case controllerPort = "controller_port" + case serial + } +} + +struct TFTMACRuntimeSelection: Equatable, Sendable { + let registrySha256: String + let activeLeaseRelativePath: String + let definition: TFTMACRuntimeModeDefinition + + var mode: TFTMACRuntimeMode { definition.mode } + + func leaseIdentity() throws -> TFTMACRuntimeLeaseIdentity { + guard let controllerPort = definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted EmulatorController port receipt." + ) + } + return TFTMACRuntimeLeaseIdentity( + mode: mode, + registrySha256: registrySha256, + configurationSha256: definition.configurationSha256, + avdName: definition.avdName, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial + ) + } + + func validateForLaunch( + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws { + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + _ = try leaseIdentity() + + guard bundle.bundleIdentifier == definition.applicationBundleId else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected the application bundle identity." + ) + } + let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String + let build = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String + guard version == definition.applicationVersion, build == definition.applicationBuild else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected application version/build \(version ?? "unknown")/\(build ?? "unknown")." + ) + } + + try requireDirectory(definition.runtimeRoot, label: "runtime root", fileManager: fileManager) + try requireDirectory(definition.sdkRoot, label: "SDK root", fileManager: fileManager) + try requireDirectory(definition.libraryRoot, label: "library root", fileManager: fileManager) + try requireDirectory(definition.avdHome, label: "AVD home", fileManager: fileManager) + try requireDirectory(definition.avdDirectory, label: "AVD directory", fileManager: fileManager) + try requireExecutable(definition.emulatorPath, label: "emulator", fileManager: fileManager) + try requireExecutable(definition.adbPath, label: "ADB", fileManager: fileManager) + try requireFile(definition.gfxstreamBackendPath, label: "gfxstream backend", fileManager: fileManager) + try requireFile(definition.avdConfigPath, label: "AVD config", fileManager: fileManager) + try requireFile(definition.avdIniPath, label: "AVD ini", fileManager: fileManager) + + let manifestURL: URL + switch definition.authorityManifest.kind { + case "bundled_resource": + guard let resourceURL = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + manifestURL = resourceURL.appendingPathComponent(definition.authorityManifest.path) + case "external_sealed_manifest": + manifestURL = URL(fileURLWithPath: definition.authorityManifest.path) + default: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has unsupported manifest authority \(definition.authorityManifest.kind)." + ) + } + guard let expectedManifestSha256 = definition.authorityManifest.sha256 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no accepted manifest SHA-256." + ) + } + try validateSHA256(at: manifestURL, expected: expectedManifestSha256, label: "authority manifest") + try validateOptionalSHA256(path: definition.emulatorPath, expected: definition.emulatorSha256, label: "emulator") + try validateOptionalSHA256( + path: definition.gfxstreamBackendPath, + expected: definition.gfxstreamBackendSha256, + label: "gfxstream backend" + ) + try validateOptionalSHA256(path: definition.avdConfigPath, expected: definition.avdConfigSha256, label: "AVD config") + try validateOptionalSHA256(path: definition.avdIniPath, expected: definition.avdIniSha256, label: "AVD ini") + } + + private func requireDirectory(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireFile(_ path: String, label: String, fileManager: FileManager) throws { + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: path, isDirectory: &isDirectory), !isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is missing its \(label) at \(path)." + ) + } + } + + private func requireExecutable(_ path: String, label: String, fileManager: FileManager) throws { + guard fileManager.isExecutableFile(atPath: path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) has no executable \(label) at \(path)." + ) + } + } + + private func validateOptionalSHA256(path: String, expected: String?, label: String) throws { + guard let expected else { return } + try validateSHA256(at: URL(fileURLWithPath: path), expected: expected, label: label) + } + + private func validateSHA256(at url: URL, expected: String, label: String) throws { + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not open its \(label) at \(url.path): \(error.localizedDescription)" + ) + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) could not hash its \(label): \(error.localizedDescription)" + ) + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) rejected \(label) SHA-256 \(observed)." + ) + } + } +} + +struct TFTMACRuntimeModeRegistry: Sendable { + static let environmentKey = "TFTMAC_RUNTIME_MODE" + static let expectedRegistrySha256 = "136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479" + + let document: TFTMACRuntimeModeRegistryDocument + let registrySha256: String + + init(data: Data) throws { + let observedRegistrySha256 = Self.sha256Hex(data) + guard observedRegistrySha256 == Self.expectedRegistrySha256 else { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry SHA-256 \(observedRegistrySha256) is not the accepted packaged identity." + ) + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeRegistryDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC runtime-mode registry could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = observedRegistrySha256 + try Self.validate(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read runtime-modes.json: \(error.localizedDescription)" + ) + } + } + + var defaultMode: TFTMACRuntimeMode { document.defaultMode } + + var registeredModes: Set { + Set(document.modes.values.map(\.mode)) + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is not registered.") + } + return definition + } + + func selection(environment: [String: String] = ProcessInfo.processInfo.environment) throws -> TFTMACRuntimeSelection { + let requested = environment[Self.environmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines) + let mode: TFTMACRuntimeMode + if let requested, !requested.isEmpty { + guard let parsed = TFTMACRuntimeMode(rawValue: requested) else { + throw TFTMACRuntimeModeError(message: "Unknown TFTMAC runtime mode \(requested).") + } + mode = parsed + } else { + mode = document.defaultMode + } + let definition = try definition(for: mode) + guard definition.launchState == .enabled else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(mode.rawValue) is \(definition.launchState.rawValue) and remains fail-closed." + ) + } + return TFTMACRuntimeSelection( + registrySha256: registrySha256, + activeLeaseRelativePath: document.activeLeaseRelativePath, + definition: definition + ) + } + + private static func validate(_ document: TFTMACRuntimeModeRegistryDocument) throws { + guard document.schema == 1 else { + throw TFTMACRuntimeModeError(message: "Unsupported runtime-mode registry schema \(document.schema).") + } + guard document.defaultMode == .control else { + throw TFTMACRuntimeModeError(message: "The default TFTMAC runtime mode must remain control.") + } + guard document.activeLeaseRelativePath == "State/native-runtime.lease" else { + throw TFTMACRuntimeModeError(message: "The runtime-mode registry changed the protected lease path.") + } + + let expectedKeys = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == expectedKeys else { + throw TFTMACRuntimeModeError( + message: "The runtime-mode registry must contain exactly control, advanced_diagnostics, and candidate." + ) + } + + var occupiedPorts: [Int: String] = [:] + for (key, definition) in document.modes { + guard key == definition.mode.rawValue else { + throw TFTMACRuntimeModeError( + message: "Runtime-mode registry key \(key) does not match \(definition.mode.rawValue)." + ) + } + try validate(definition) + for (kind, port) in [ + ("adb", Optional(definition.adbServerPort)), + ("console", Optional(definition.consolePort)), + ("controller", definition.controllerPort) + ] { + guard let port else { continue } + if let existing = occupiedPorts[port] { + throw TFTMACRuntimeModeError( + message: "Runtime lease port \(port) is shared by \(existing) and \(definition.mode.rawValue).\(kind)." + ) + } + occupiedPorts[port] = "\(definition.mode.rawValue).\(kind)" + } + } + + let control = try required(.control, from: document) + guard control.launchState == .enabled, + control.runtimeRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime", + control.sdkRoot == "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK", + control.avdHome == "/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD", + control.avdName == "TFT_Ultra_Tablet", + control.adbServerPort == 5038, + control.consolePort == 5582, + control.controllerPort == 8554, + control.serial == "emulator-5582", + control.authorityManifest.kind == "bundled_resource", + control.authorityManifest.path == "runtime-authority.json", + control.authorityManifest.sha256 != nil, + control.emulatorSha256 != nil, + control.gfxstreamBackendSha256 != nil, + control.rollbackTarget == .control, + !control.requiresControlStopped else { + throw TFTMACRuntimeModeError( + message: "The control mode no longer matches the accepted stock Build 8 authority." + ) + } + + let diagnostics = try required(.advancedDiagnostics, from: document) + guard diagnostics.launchState == .blockedPendingControllerLease, + diagnostics.controllerPort == nil, + diagnostics.avdName == "TFTMAC_Diagnostic_API37_R9", + diagnostics.adbServerPort == 5041, + diagnostics.consolePort == 5586, + diagnostics.serial == "emulator-5586", + diagnostics.emulatorSha256 != nil, + diagnostics.gfxstreamBackendSha256 != nil, + diagnostics.avdConfigSha256 != nil, + diagnostics.avdIniSha256 != nil, + diagnostics.requiresControlStopped, + diagnostics.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Advanced diagnostics must remain isolated and blocked pending its controller-port receipt." + ) + } + + let candidate = try required(.candidate, from: document) + guard candidate.launchState == .blockedNotBuilt, + candidate.controllerPort == nil, + candidate.requiresControlStopped, + candidate.rollbackTarget == .control else { + throw TFTMACRuntimeModeError( + message: "Candidate mode must remain blocked until a separately accepted candidate exists." + ) + } + } + + private static func validate(_ definition: TFTMACRuntimeModeDefinition) throws { + let requiredStrings = [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdName, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath, + definition.serial, + definition.authorityManifest.kind, + definition.authorityManifest.path, + definition.applicationBundleId, + definition.applicationVersion, + definition.applicationBuild, + definition.allowedPurpose, + definition.comparabilityClass + ] + guard requiredStrings.allSatisfy({ !$0.isEmpty }) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) has an empty required field." + ) + } + for path in [ + definition.runtimeRoot, + definition.sdkRoot, + definition.libraryRoot, + definition.emulatorPath, + definition.gfxstreamBackendPath, + definition.adbPath, + definition.avdHome, + definition.avdDirectory, + definition.avdConfigPath, + definition.avdIniPath + ] { + guard path.hasPrefix("/") else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains a non-absolute path." + ) + } + } + guard (1...65535).contains(definition.adbServerPort), + (1...65535).contains(definition.consolePort), + definition.controllerPort.map({ (1...65535).contains($0) }) ?? true else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid lease port." + ) + } + guard definition.serial == "emulator-\(definition.consolePort)" else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) serial does not match its console lease." + ) + } + if definition.launchState == .enabled, definition.controllerPort == nil { + throw TFTMACRuntimeModeError( + message: "Launch-ready mode \(definition.mode.rawValue) has no controller-port receipt." + ) + } + let digests: [String?] = [ + definition.configurationSha256, + definition.emulatorSha256, + definition.gfxstreamBackendSha256, + definition.avdConfigSha256, + definition.avdIniSha256, + definition.authorityManifest.sha256 + ] + for digest in digests.compactMap({ $0 }) { + guard isSHA256(digest) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) contains an invalid SHA-256 value." + ) + } + } + guard definition.computedConfigurationSha256 == definition.configurationSha256.lowercased() else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(definition.mode.rawValue) configuration SHA-256 does not match its fields." + ) + } + } + + private static func required( + _ mode: TFTMACRuntimeMode, + from document: TFTMACRuntimeModeRegistryDocument + ) throws -> TFTMACRuntimeModeDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} diff --git a/tftmac/Runtime/RuntimeModeAuthority.swift b/tftmac/Runtime/RuntimeModeAuthority.swift new file mode 100644 index 0000000..1aaf84b --- /dev/null +++ b/tftmac/Runtime/RuntimeModeAuthority.swift @@ -0,0 +1,841 @@ +import CryptoKit +import Darwin +import Foundation + +enum TFTMACRuntimeLaunchStrategy: String, Codable, Sendable { + case bundledForwarder = "bundled_forwarder" + case externalNativeHost = "external_native_host" + case blocked +} + +enum TFTMACRuntimeProfilePolicy: String, Codable, Sendable { + case validatedNativePreferences = "validated_native_preferences" + case fixedRegistryProfile = "fixed_registry_profile" + case blocked +} + +enum TFTMACRuntimeHostKind: String, Codable, Sendable { + case bundledResource = "bundled_resource" + case externalApplication = "external_application" +} + +struct TFTMACSealedReceiptReference: Codable, Equatable, Sendable { + let path: String + let sha256: String + let requiredState: String +} + +struct TFTMACRuntimeHostAuthority: Codable, Equatable, Sendable { + let kind: TFTMACRuntimeHostKind + let path: String + let bundleIdentifier: String + let executableRelativePath: String + let executableSha256: String? + let sourcePath: String? + let sourceSha256: String? + let infoPlistPath: String? + let infoPlistSha256: String? + let buildReceiptResource: String? +} + +struct TFTMACRuntimeLockedProfile: Codable, Equatable, Sendable { + let identifier: String + let width: Int + let height: Int + let densityDpi: Int + let refreshHz: Int + let vcpu: Int + let ramMib: Int + let gpuMode: String + let audioBackend: String + let graphicsTransport: String + let asgWriteBufferSize: Int + let asgWriteStepSize: Int + let asgDataRingSize: Int + let asgDrawFlushInterval: Int + let angleEnabledFeatures: String + let angleDisabledFeatures: String +} + +struct TFTMACDiagnosticReceiptAuthority: Codable, Equatable, Sendable { + let buildId: String + let runtimeConfigurationSha256: String + let build: TFTMACSealedReceiptReference + let clone: TFTMACSealedReceiptReference + let nativeHost: TFTMACSealedReceiptReference +} + +struct TFTMACRuntimeModeSupplementalDefinition: Codable, Equatable, Sendable { + let mode: TFTMACRuntimeMode + let stateNamespace: String + let usesLegacyApplicationSupportRoot: Bool + let emulatorIdentifier: String + let launchStrategy: TFTMACRuntimeLaunchStrategy + let profilePolicy: TFTMACRuntimeProfilePolicy + let lockedProfile: TFTMACRuntimeLockedProfile? + let adbSha256: String? + let adbVendorKeysPolicy: String + let expectedEmulatorVersionContains: String? + let emulatorUuids: [String]? + let qemuPath: String? + let qemuSha256: String? + let qemuUuids: [String]? + let gfxstreamBackendUuids: [String]? + let hostApplication: TFTMACRuntimeHostAuthority? + let diagnosticReceipts: TFTMACDiagnosticReceiptAuthority? +} + +struct TFTMACRuntimeModeAuthorityDocument: Codable, Equatable, Sendable { + let schema: Int + let contract: String + let selectionEnvironmentVariable: String + let modes: [String: TFTMACRuntimeModeSupplementalDefinition] +} + +struct TFTMACLoadedRuntimeIdentity: Equatable, Sendable { + let processIdentifier: Int32 + let qemuPath: String + let qemuSha256: String + let qemuUuids: [String] + let gfxstreamBackendPath: String + let gfxstreamBackendSha256: String + let gfxstreamBackendUuids: [String] +} + +struct TFTMACResolvedRuntimeModeAuthority: Sendable { + let supplemental: TFTMACRuntimeModeSupplementalDefinition + let hostApplication: URL + let applicationSupport: URL + let globalApplicationSupport: URL +} + +struct TFTMACSelectedRuntimeConfiguration: Sendable { + let registry: TFTMACRuntimeModeRegistry + let selection: TFTMACRuntimeSelection + let authority: TFTMACRuntimeModeAuthority + let profile: TFTMACRuntimeProfile + let applicationSupport: URL + + static func load( + savedProfile: TFTMACRuntimeProfile, + bundle: Bundle = .main, + environment: [String: String] = ProcessInfo.processInfo.environment + ) throws -> Self { + let registry = try TFTMACRuntimeModeRegistry.loadBundled(bundle: bundle) + let authority = try TFTMACRuntimeModeAuthority.loadBundled(bundle: bundle) + try authority.validateConsistency(with: registry) + let selection = try registry.selection(environment: environment) + let profile = try authority.effectiveProfile(savedProfile: savedProfile, selection: selection) + return Self( + registry: registry, + selection: selection, + authority: authority, + profile: profile, + applicationSupport: authority.applicationSupportURL(for: selection.mode) + ) + } +} + +struct TFTMACRuntimeModeAuthority: Sendable { + static let expectedContract = "TFTMAC_RUNTIME_MODES_V1" + + let document: TFTMACRuntimeModeAuthorityDocument + let registrySha256: String + + init(data: Data) throws { + let observed = Self.sha256Hex(data) + guard observed == TFTMACRuntimeModeRegistry.expectedRegistrySha256 else { + throw TFTMACRuntimeModeError( + message: "TFTMAC supplemental runtime authority rejected registry SHA-256 \(observed)." + ) + } + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + do { + document = try decoder.decode(TFTMACRuntimeModeAuthorityDocument.self, from: data) + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC supplemental runtime authority could not be decoded: \(error.localizedDescription)" + ) + } + registrySha256 = observed + try Self.validateStatic(document) + } + + static func loadBundled(bundle: Bundle = .main) throws -> Self { + guard let url = bundle.url(forResource: "runtime-modes", withExtension: "json") else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app is missing runtime-modes.json.") + } + do { + return try Self(data: Data(contentsOf: url)) + } catch let error as TFTMACRuntimeModeError { + throw error + } catch { + throw TFTMACRuntimeModeError( + message: "TFTMAC could not read supplemental runtime authority: \(error.localizedDescription)" + ) + } + } + + func definition(for mode: TFTMACRuntimeMode) throws -> TFTMACRuntimeModeSupplementalDefinition { + guard let definition = document.modes[mode.rawValue] else { + throw TFTMACRuntimeModeError(message: "Supplemental runtime mode \(mode.rawValue) is missing.") + } + return definition + } + + func validateConsistency(with registry: TFTMACRuntimeModeRegistry) throws { + guard registry.registrySha256 == registrySha256 else { + throw TFTMACRuntimeModeError(message: "Base and supplemental runtime authority hashes differ.") + } + for mode in TFTMACRuntimeMode.allCases { + let base = try registry.definition(for: mode) + let supplemental = try definition(for: mode) + guard base.mode == supplemental.mode else { + throw TFTMACRuntimeModeError(message: "Runtime mode authority mismatch for \(mode.rawValue).") + } + } + } + + func effectiveProfile( + savedProfile: TFTMACRuntimeProfile, + selection: TFTMACRuntimeSelection + ) throws -> TFTMACRuntimeProfile { + let supplemental = try definition(for: selection.mode) + guard let controllerPort = selection.definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted controller port." + ) + } + switch supplemental.profilePolicy { + case .validatedNativePreferences: + guard selection.mode == .control, savedProfile.controllerPort == controllerPort else { + throw TFTMACRuntimeModeError( + message: "Saved control profile does not match the accepted controller lease." + ) + } + return savedProfile + case .fixedRegistryProfile: + guard let locked = supplemental.lockedProfile else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) is missing its fixed profile." + ) + } + return TFTMACRuntimeProfile( + identifier: locked.identifier, + width: locked.width, + height: locked.height, + densityDPI: locked.densityDpi, + refreshHz: locked.refreshHz, + vCPU: locked.vcpu, + ramMiB: locked.ramMib, + gpuMode: locked.gpuMode, + audioBackend: locked.audioBackend, + graphicsTransport: locked.graphicsTransport, + asgWriteBufferSize: locked.asgWriteBufferSize, + asgWriteStepSize: locked.asgWriteStepSize, + asgDataRingSize: locked.asgDataRingSize, + asgDrawFlushInterval: locked.asgDrawFlushInterval, + controllerPort: controllerPort, + angleEnabledFeatures: locked.angleEnabledFeatures, + angleDisabledFeatures: locked.angleDisabledFeatures, + experimentPreset: .control + ) + case .blocked: + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted profile." + ) + } + } + + func applicationSupportURL(for mode: TFTMACRuntimeMode) -> URL { + let global = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + guard let supplemental = try? definition(for: mode), !supplemental.usesLegacyApplicationSupportRoot else { + return global + } + return global + .appendingPathComponent("Modes", isDirectory: true) + .appendingPathComponent(supplemental.stateNamespace, isDirectory: true) + } + + func resolveForLaunch( + selection: TFTMACRuntimeSelection, + bundle: Bundle = .main, + fileManager: FileManager = .default + ) throws -> TFTMACResolvedRuntimeModeAuthority { + try selection.validateForLaunch(bundle: bundle, fileManager: fileManager) + let supplemental = try definition(for: selection.mode) + try validateModeEvidence( + base: selection.definition, + supplemental: supplemental, + bundle: bundle, + fileManager: fileManager + ) + let hostApplication = try resolveHostApplication( + supplemental: supplemental, + bundle: bundle, + fileManager: fileManager + ) + let global = FileManager.default.homeDirectoryForCurrentUser + .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) + return TFTMACResolvedRuntimeModeAuthority( + supplemental: supplemental, + hostApplication: hostApplication, + applicationSupport: applicationSupportURL(for: selection.mode), + globalApplicationSupport: global + ) + } + + func validateLoadedRuntime( + processIdentifier: Int32, + selection: TFTMACRuntimeSelection + ) throws -> TFTMACLoadedRuntimeIdentity { + let supplemental = try definition(for: selection.mode) + guard let qemuPath = supplemental.qemuPath, + let qemuSha256 = supplemental.qemuSha256, + let qemuUuids = supplemental.qemuUuids, + let gfxstreamSha256 = selection.definition.gfxstreamBackendSha256, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids, + let controllerPort = selection.definition.controllerPort else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) lacks loaded-runtime identity authority." + ) + } + let observedExecutable = try Self.processExecutablePath(processIdentifier) + guard Self.standardized(observedExecutable) == Self.standardized(qemuPath) else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator process path \(observedExecutable) does not match \(qemuPath)." + ) + } + try Self.validateSHA256(path: qemuPath, expected: qemuSha256, label: "loaded qemu") + try Self.validateUUIDs(path: qemuPath, expected: qemuUuids, label: "loaded qemu") + + let command = try Self.runCommand( + executable: "/bin/ps", + arguments: ["-p", "\(processIdentifier)", "-ww", "-o", "command="], + timeout: 10 + ) + guard command.status == 0, + command.output.contains("@\(selection.definition.avdName)"), + command.output.contains("-port \(selection.definition.consolePort)"), + command.output.contains("-grpc \(controllerPort)") else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator command line does not match the selected AVD and port lease." + ) + } + + let vmmap = try Self.runCommand( + executable: "/usr/bin/vmmap", + arguments: ["-w", "\(processIdentifier)"], + timeout: 30 + ) + guard vmmap.status == 0, + vmmap.output.contains(selection.definition.gfxstreamBackendPath) else { + throw TFTMACRuntimeModeError( + message: "Loaded emulator did not prove the accepted gfxstream image mapping." + ) + } + try Self.validateSHA256( + path: selection.definition.gfxstreamBackendPath, + expected: gfxstreamSha256, + label: "loaded gfxstream backend" + ) + try Self.validateUUIDs( + path: selection.definition.gfxstreamBackendPath, + expected: gfxstreamUuids, + label: "loaded gfxstream backend" + ) + return TFTMACLoadedRuntimeIdentity( + processIdentifier: processIdentifier, + qemuPath: qemuPath, + qemuSha256: qemuSha256, + qemuUuids: qemuUuids, + gfxstreamBackendPath: selection.definition.gfxstreamBackendPath, + gfxstreamBackendSha256: gfxstreamSha256, + gfxstreamBackendUuids: gfxstreamUuids + ) + } + + private static func validateStatic(_ document: TFTMACRuntimeModeAuthorityDocument) throws { + guard document.schema == 1, + document.contract == expectedContract, + document.selectionEnvironmentVariable == TFTMACRuntimeModeRegistry.environmentKey else { + throw TFTMACRuntimeModeError(message: "Supplemental runtime-mode contract identity failed.") + } + let exactModes = Set(TFTMACRuntimeMode.allCases.map(\.rawValue)) + guard Set(document.modes.keys) == exactModes else { + throw TFTMACRuntimeModeError( + message: "Supplemental authority must define exactly control, advanced_diagnostics, and candidate." + ) + } + var namespaces = Set() + for (key, definition) in document.modes { + guard key == definition.mode.rawValue, + !definition.stateNamespace.isEmpty, + namespaces.insert(definition.stateNamespace).inserted, + !definition.emulatorIdentifier.isEmpty, + !definition.adbVendorKeysPolicy.isEmpty else { + throw TFTMACRuntimeModeError( + message: "Supplemental runtime identity is invalid for \(key)." + ) + } + } + + guard let control = document.modes[TFTMACRuntimeMode.control.rawValue], + control.usesLegacyApplicationSupportRoot, + control.stateNamespace == "control", + control.launchStrategy == .bundledForwarder, + control.profilePolicy == .validatedNativePreferences, + control.lockedProfile == nil, + control.adbSha256.map(Self.isSHA256) == true, + control.emulatorUuids?.isEmpty == false, + control.qemuPath?.hasPrefix("/") == true, + control.qemuSha256.map(Self.isSHA256) == true, + control.qemuUuids?.isEmpty == false, + control.gfxstreamBackendUuids?.isEmpty == false, + control.hostApplication?.kind == .bundledResource, + control.hostApplication?.executableSha256 == nil, + control.hostApplication?.sourcePath == "RuntimeHost/main.c", + control.hostApplication?.sourceSha256.map(Self.isSHA256) == true, + control.hostApplication?.infoPlistPath == "RuntimeHost/Info.plist", + control.hostApplication?.infoPlistSha256.map(Self.isSHA256) == true, + control.hostApplication?.buildReceiptResource == "control-host-build.json", + control.diagnosticReceipts == nil else { + throw TFTMACRuntimeModeError(message: "Supplemental control authority is incomplete.") + } + + guard let diagnostics = document.modes[TFTMACRuntimeMode.advancedDiagnostics.rawValue], + !diagnostics.usesLegacyApplicationSupportRoot, + diagnostics.stateNamespace == "advanced_diagnostics", + diagnostics.launchStrategy == .externalNativeHost, + diagnostics.profilePolicy == .fixedRegistryProfile, + diagnostics.lockedProfile != nil, + diagnostics.adbSha256.map(Self.isSHA256) == true, + diagnostics.emulatorUuids?.isEmpty == false, + diagnostics.qemuPath?.hasPrefix("/") == true, + diagnostics.qemuSha256.map(Self.isSHA256) == true, + diagnostics.qemuUuids?.isEmpty == false, + diagnostics.gfxstreamBackendUuids?.isEmpty == false, + diagnostics.hostApplication?.kind == .externalApplication, + diagnostics.hostApplication?.executableSha256.map(Self.isSHA256) == true, + diagnostics.hostApplication?.sourcePath == nil, + diagnostics.hostApplication?.sourceSha256 == nil, + diagnostics.hostApplication?.infoPlistSha256.map(Self.isSHA256) == true, + diagnostics.hostApplication?.buildReceiptResource == nil, + let receipts = diagnostics.diagnosticReceipts, + receipts.buildId == "gate4-r9-20260901", + Self.isSHA256(receipts.runtimeConfigurationSha256), + receipts.build.requiredState == "DIAGNOSTIC_BUILD_IDENTITY_PASS", + receipts.clone.requiredState == "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS", + receipts.nativeHost.requiredState == "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS" else { + throw TFTMACRuntimeModeError(message: "Supplemental diagnostic authority is incomplete.") + } + + guard let candidate = document.modes[TFTMACRuntimeMode.candidate.rawValue], + !candidate.usesLegacyApplicationSupportRoot, + candidate.stateNamespace == "candidate", + candidate.launchStrategy == .blocked, + candidate.profilePolicy == .blocked, + candidate.lockedProfile == nil, + candidate.hostApplication == nil, + candidate.diagnosticReceipts == nil else { + throw TFTMACRuntimeModeError(message: "Supplemental candidate authority must remain blocked.") + } + } + + private func validateModeEvidence( + base: TFTMACRuntimeModeDefinition, + supplemental: TFTMACRuntimeModeSupplementalDefinition, + bundle: Bundle, + fileManager: FileManager + ) throws { + guard let adbSha256 = supplemental.adbSha256, + let emulatorUuids = supplemental.emulatorUuids, + let versionFragment = supplemental.expectedEmulatorVersionContains, + let qemuPath = supplemental.qemuPath, + let qemuSha256 = supplemental.qemuSha256, + let qemuUuids = supplemental.qemuUuids, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(base.mode.rawValue) lacks accepted binary identity evidence." + ) + } + try Self.validateSHA256(path: base.adbPath, expected: adbSha256, label: "ADB") + try Self.validateSHA256(path: qemuPath, expected: qemuSha256, label: "qemu") + try Self.validateUUIDs(path: qemuPath, expected: qemuUuids, label: "qemu") + try Self.validateUUIDs(path: base.emulatorPath, expected: emulatorUuids, label: "emulator") + try Self.validateUUIDs( + path: base.gfxstreamBackendPath, + expected: gfxstreamUuids, + label: "gfxstream backend" + ) + let version = try Self.runCommand( + executable: base.emulatorPath, + arguments: ["-version"], + timeout: 30 + ) + guard version.status == 0, version.output.contains(versionFragment) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(base.mode.rawValue) rejected emulator version identity." + ) + } + if base.mode == .advancedDiagnostics { + try validateDiagnosticReceipts(base: base, supplemental: supplemental) + } + } + + private func resolveHostApplication( + supplemental: TFTMACRuntimeModeSupplementalDefinition, + bundle: Bundle, + fileManager: FileManager + ) throws -> URL { + guard let host = supplemental.hostApplication else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) has no accepted native host." + ) + } + let appURL: URL + switch host.kind { + case .bundledResource: + guard let resources = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "TFTMAC.app has no Resources directory.") + } + appURL = resources.appendingPathComponent(host.path, isDirectory: true) + case .externalApplication: + appURL = URL(fileURLWithPath: host.path, isDirectory: true) + } + var isDirectory: ObjCBool = false + guard fileManager.fileExists(atPath: appURL.path, isDirectory: &isDirectory), isDirectory.boolValue else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) is missing its native host at \(appURL.path)." + ) + } + let infoURL = appURL.appendingPathComponent("Contents/Info.plist") + guard let info = NSDictionary(contentsOf: infoURL), + info["CFBundleIdentifier"] as? String == host.bundleIdentifier else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) rejected native-host bundle identity." + ) + } + if let expectedInfoPlistSha256 = host.infoPlistSha256 { + try Self.validateSHA256( + path: infoURL.path, + expected: expectedInfoPlistSha256, + label: "native-host Info.plist" + ) + } + let executable = appURL.appendingPathComponent(host.executableRelativePath) + guard fileManager.isExecutableFile(atPath: executable.path) else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) native-host executable is missing." + ) + } + if let expectedExecutableSha256 = host.executableSha256 { + try Self.validateSHA256( + path: executable.path, + expected: expectedExecutableSha256, + label: "native-host executable" + ) + } else if host.buildReceiptResource == nil { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) has no native-host build receipt authority." + ) + } + if host.buildReceiptResource != nil { + try Self.validateControlHostBuildReceipt(host: host, appURL: appURL, bundle: bundle) + } + let codesign = try Self.runCommand( + executable: "/usr/bin/codesign", + arguments: ["--verify", "--deep", "--strict", appURL.path], + timeout: 30 + ) + guard codesign.status == 0 else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(supplemental.mode.rawValue) native-host signature is invalid." + ) + } + return appURL + } + + + private static func validateControlHostBuildReceipt( + host: TFTMACRuntimeHostAuthority, + appURL: URL, + bundle: Bundle + ) throws { + guard let receiptName = host.buildReceiptResource, + let sourcePath = host.sourcePath, + let sourceSha256 = host.sourceSha256, + let infoPlistPath = host.infoPlistPath, + let infoPlistSha256 = host.infoPlistSha256, + let resources = bundle.resourceURL else { + throw TFTMACRuntimeModeError(message: "Control native-host build receipt authority is incomplete.") + } + let receiptURL = resources.appendingPathComponent(receiptName) + guard let data = try? Data(contentsOf: receiptURL), + let receipt = try? JSONSerialization.jsonObject(with: data) as? [String: Any], + string(receipt, ["state"]) == "CONTROL_NATIVE_HOST_BUILD_PASS", + string(receipt, ["host_application_relative_path"]) == host.path, + string(receipt, ["bundle_identifier"]) == host.bundleIdentifier, + string(receipt, ["source_path"]) == sourcePath, + string(receipt, ["source_sha256"]) == sourceSha256, + string(receipt, ["info_plist_path"]) == infoPlistPath, + string(receipt, ["info_plist_sha256"]) == infoPlistSha256, + string(receipt, ["executable_relative_path"]) == host.executableRelativePath, + let executableSha256 = string(receipt, ["executable_sha256"]), + let executableUuids = strings(receipt, ["executable_uuids"]), + strings(receipt, ["compile_arguments"]) == ["-Os", "-arch", "arm64", "-mmacosx-version-min=15.0"] else { + throw TFTMACRuntimeModeError(message: "Control native-host signed build receipt is missing or invalid.") + } + let executable = appURL.appendingPathComponent(host.executableRelativePath) + try validateSHA256(path: executable.path, expected: executableSha256, label: "control native-host executable") + try validateUUIDs(path: executable.path, expected: executableUuids, label: "control native-host executable") + } + + private func validateDiagnosticReceipts( + base: TFTMACRuntimeModeDefinition, + supplemental: TFTMACRuntimeModeSupplementalDefinition + ) throws { + guard let authority = supplemental.diagnosticReceipts, + let host = supplemental.hostApplication, + let emulatorUuids = supplemental.emulatorUuids, + let gfxstreamUuids = supplemental.gfxstreamBackendUuids else { + throw TFTMACRuntimeModeError(message: "Diagnostic receipt authority is missing.") + } + let build = try Self.readSealedReceipt(authority.build) + guard Self.string(build, ["state"]) == authority.build.requiredState, + Self.string(build, ["build_id"]) == authority.buildId, + Self.bool(build, ["non_comparable_to_stock"]) == true, + Self.bool(build, ["control_runtime_touched"]) == false, + Self.bool(build, ["control_noninterference", "matched"]) == true, + Self.string(build, ["release_and_tracing", "runtime_configuration_sha256"]) == authority.runtimeConfigurationSha256, + Self.string(build, ["emulator", "path"]) == base.emulatorPath, + Self.string(build, ["emulator", "sha256"]) == base.emulatorSha256, + Self.strings(build, ["emulator", "uuids"]) == emulatorUuids, + Self.string(build, ["gfxstream_backend", "path"]) == base.gfxstreamBackendPath, + Self.string(build, ["gfxstream_backend", "sha256"]) == base.gfxstreamBackendSha256, + Self.strings(build, ["gfxstream_backend", "uuids"]) == gfxstreamUuids else { + throw TFTMACRuntimeModeError(message: "Diagnostic build receipt structure drifted.") + } + + let clone = try Self.readSealedReceipt(authority.clone) + guard Self.string(clone, ["state"]) == authority.clone.requiredState, + Self.string(clone, ["build_id"]) == authority.buildId, + Self.string(clone, ["diagnostic_avd", "name"]) == base.avdName, + Self.string(clone, ["diagnostic_avd", "root"]) == base.avdHome, + Self.string(clone, ["diagnostic_avd", "avd_path"]) == base.avdDirectory, + Self.string(clone, ["diagnostic_avd", "ini_path"]) == base.avdIniPath, + Self.string(clone, ["diagnostic_avd", "config_sha256"]) == base.avdConfigSha256, + Self.string(clone, ["diagnostic_avd", "ini_sha256"]) == base.avdIniSha256, + Self.int(clone, ["diagnostic_avd", "adb_server_port"]) == base.adbServerPort, + Self.int(clone, ["diagnostic_avd", "console_port"]) == base.consolePort, + Self.string(clone, ["diagnostic_avd", "serial"]) == base.serial, + Self.string(clone, ["accepted_build", "sha256"]) == authority.build.sha256, + Self.bool(clone, ["control_noninterference_matched"]) == true, + Self.bool(clone, ["sealed_before_first_boot"]) == true, + Self.bool(clone, ["first_boot_attempted"]) == false, + Self.bool(clone, ["launch_attempted"]) == false, + Self.bool(clone, ["control_runtime_mutation_attempted"]) == false, + Self.bool(clone, ["control_avd_touched"]) == false else { + throw TFTMACRuntimeModeError(message: "Diagnostic stopped-clone receipt structure drifted.") + } + + let nativeHost = try Self.readSealedReceipt(authority.nativeHost) + guard let expectedHostExecutableSha256 = host.executableSha256 else { + throw TFTMACRuntimeModeError(message: "Diagnostic native-host executable SHA-256 authority is missing.") + } + let expectedHostPath = host.path + let expectedExecutable = URL(fileURLWithPath: expectedHostPath, isDirectory: true) + .appendingPathComponent(host.executableRelativePath).path + guard Self.string(nativeHost, ["state"]) == authority.nativeHost.requiredState, + Self.string(nativeHost, ["build_id"]) == authority.buildId, + Self.string(nativeHost, ["app", "path"]) == expectedHostPath, + Self.string(nativeHost, ["app", "bundle_identifier"]) == host.bundleIdentifier, + Self.string(nativeHost, ["app", "executable", "path"]) == expectedExecutable, + Self.string(nativeHost, ["app", "executable", "sha256"]) == expectedHostExecutableSha256, + Self.int(nativeHost, ["app", "codesign_verify_status"]) == 0, + Self.string(nativeHost, ["launch_contract", "method"])?.contains("/usr/bin/open") == true, + Self.string(nativeHost, ["launch_contract", "emulator_spawn_owner"]) == "NATIVE_MACOS_APP_PROCESS", + Self.bool(nativeHost, ["launch_contract", "service_context_emulator_spawn_forbidden"]) == true, + Self.bool(nativeHost, ["control_runtime_mutation_attempted"]) == false else { + throw TFTMACRuntimeModeError(message: "Diagnostic native-host receipt structure drifted.") + } + } + + private static func readSealedReceipt(_ reference: TFTMACSealedReceiptReference) throws -> [String: Any] { + guard isSHA256(reference.sha256) else { + throw TFTMACRuntimeModeError(message: "Receipt authority contains an invalid SHA-256.") + } + try validateSHA256(path: reference.path, expected: reference.sha256, label: "sealed receipt") + let sidecarPath = "\(reference.path).sha256" + guard let sidecar = try? String(contentsOfFile: sidecarPath, encoding: .utf8), + sidecar.split(whereSeparator: \.isWhitespace).first.map(String.init) == reference.sha256 else { + throw TFTMACRuntimeModeError(message: "Sealed receipt sidecar is missing or mismatched: \(sidecarPath)") + } + let data = try Data(contentsOf: URL(fileURLWithPath: reference.path)) + guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { + throw TFTMACRuntimeModeError(message: "Sealed receipt is not a JSON object: \(reference.path)") + } + return object + } + + private static func value(_ object: [String: Any], _ path: [String]) -> Any? { + var current: Any = object + for component in path { + guard let dictionary = current as? [String: Any], let next = dictionary[component] else { return nil } + current = next + } + return current + } + + private static func string(_ object: [String: Any], _ path: [String]) -> String? { + value(object, path) as? String + } + + private static func strings(_ object: [String: Any], _ path: [String]) -> [String]? { + value(object, path) as? [String] + } + + private static func bool(_ object: [String: Any], _ path: [String]) -> Bool? { + value(object, path) as? Bool + } + + private static func int(_ object: [String: Any], _ path: [String]) -> Int? { + (value(object, path) as? NSNumber)?.intValue + } + + private static func validateSHA256(path: String, expected: String, label: String) throws { + guard isSHA256(expected) else { + throw TFTMACRuntimeModeError(message: "\(label) authority is not a SHA-256 value.") + } + let url = URL(fileURLWithPath: path) + let handle: FileHandle + do { + handle = try FileHandle(forReadingFrom: url) + } catch { + throw TFTMACRuntimeModeError(message: "Could not open \(label) at \(path): \(error.localizedDescription)") + } + defer { try? handle.close() } + var hasher = SHA256() + do { + while let chunk = try handle.read(upToCount: 1_048_576), !chunk.isEmpty { + hasher.update(data: chunk) + } + } catch { + throw TFTMACRuntimeModeError(message: "Could not hash \(label): \(error.localizedDescription)") + } + let observed = hasher.finalize().map { String(format: "%02x", $0) }.joined() + guard observed == expected else { + throw TFTMACRuntimeModeError( + message: "\(label) SHA-256 mismatch: expected \(expected), observed \(observed)." + ) + } + } + + private static func validateUUIDs(path: String, expected: [String], label: String) throws { + guard !expected.isEmpty else { + throw TFTMACRuntimeModeError(message: "\(label) has no accepted Mach-O UUID authority.") + } + let result = try runCommand( + executable: "/usr/bin/dwarfdump", + arguments: ["--uuid", path], + timeout: 30 + ) + guard result.status == 0 else { + throw TFTMACRuntimeModeError(message: "Could not inspect \(label) Mach-O UUIDs.") + } + for identity in expected { + let parts = identity.split(separator: ":", maxSplits: 1).map(String.init) + guard parts.count == 2, + result.output.localizedCaseInsensitiveContains(parts[0]), + result.output.contains("(\(parts[1]))") else { + throw TFTMACRuntimeModeError(message: "\(label) Mach-O UUID identity drifted.") + } + } + } + + private struct CommandResult { + let status: Int32 + let output: String + } + + private static func runCommand( + executable: String, + arguments: [String], + timeout: TimeInterval + ) throws -> CommandResult { + let manager = FileManager.default + let root = manager.temporaryDirectory.appendingPathComponent( + "tftmac-runtime-authority-\(UUID().uuidString)", + isDirectory: true + ) + try manager.createDirectory(at: root, withIntermediateDirectories: true, attributes: [.posixPermissions: 0o700]) + defer { try? manager.removeItem(at: root) } + let stdoutURL = root.appendingPathComponent("stdout") + let stderrURL = root.appendingPathComponent("stderr") + manager.createFile(atPath: stdoutURL.path, contents: nil, attributes: [.posixPermissions: 0o600]) + manager.createFile(atPath: stderrURL.path, contents: nil, attributes: [.posixPermissions: 0o600]) + let stdout = try FileHandle(forWritingTo: stdoutURL) + let stderr = try FileHandle(forWritingTo: stderrURL) + defer { + try? stdout.close() + try? stderr.close() + } + let process = Process() + process.executableURL = URL(fileURLWithPath: executable) + process.arguments = arguments + process.standardOutput = stdout + process.standardError = stderr + do { + try process.run() + } catch { + throw TFTMACRuntimeModeError( + message: "Could not execute \(executable): \(error.localizedDescription)" + ) + } + let deadline = Date().addingTimeInterval(timeout) + while process.isRunning && Date() < deadline { + Thread.sleep(forTimeInterval: 0.02) + } + if process.isRunning { + process.terminate() + Thread.sleep(forTimeInterval: 0.2) + if process.isRunning { Darwin.kill(process.processIdentifier, SIGKILL) } + } + process.waitUntilExit() + try stdout.synchronize() + try stderr.synchronize() + let out = (try? String(contentsOf: stdoutURL, encoding: .utf8)) ?? "" + let err = (try? String(contentsOf: stderrURL, encoding: .utf8)) ?? "" + return CommandResult(status: process.terminationStatus, output: out + err) + } + + private static func processExecutablePath(_ processIdentifier: Int32) throws -> String { + var buffer = [CChar](repeating: 0, count: 4096) + let count = buffer.withUnsafeMutableBufferPointer { + proc_pidpath(processIdentifier, $0.baseAddress, UInt32($0.count)) + } + guard count > 0 else { + throw TFTMACRuntimeModeError( + message: "Could not resolve loaded emulator process path for PID \(processIdentifier)." + ) + } + return String(cString: buffer) + } + + private static func standardized(_ path: String) -> String { + URL(fileURLWithPath: path).standardizedFileURL.resolvingSymlinksInPath().path + } + + private static func isSHA256(_ value: String) -> Bool { + guard value.count == 64 else { return false } + return value.unicodeScalars.allSatisfy { + (48...57).contains($0.value) || (97...102).contains($0.value) + } + } + + private static func sha256Hex(_ data: Data) -> String { + SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined() + } +} diff --git a/tftmac/Runtime/TFTMACRuntime.swift b/tftmac/Runtime/TFTMACRuntime.swift index 4ef9581..fd11f27 100644 --- a/tftmac/Runtime/TFTMACRuntime.swift +++ b/tftmac/Runtime/TFTMACRuntime.swift @@ -10,63 +10,74 @@ import SQLite3 import SwiftProtobuf struct TFTMACRuntimePaths: Sendable { + let mode: TFTMACRuntimeMode + let registrySha256: String + let configurationSha256: String + let runtimeRoot: URL let sdkRoot: URL + let libraryRoot: URL let emulator: URL + let qemu: URL + let gfxstreamBackend: URL let adb: URL let avdHome: URL + let avdName: String let avdDirectory: URL let avdConfig: URL + let avdINI: URL let hostApplication: URL let applicationSupport: URL - - static func discover() throws -> Self { - let manager = FileManager.default - let runtimeRoot = URL(fileURLWithPath: "/Volumes/MAC MINI M4/TFTMAC/Runtime", isDirectory: true) - let sdkCandidates = ["SDK", "sdk"].map { runtimeRoot.appendingPathComponent($0, isDirectory: true) } - guard let sdkRoot = sdkCandidates.first(where: { - manager.isExecutableFile(atPath: $0.appendingPathComponent("emulator/emulator").path) - && manager.isExecutableFile(atPath: $0.appendingPathComponent("platform-tools/adb").path) - }) else { - throw TFTMACRuntimeError("The proven Android runtime is not mounted at /Volumes/MAC MINI M4/TFTMAC/Runtime.") - } - - let avdCandidates = ["AVD", "avd"].map { runtimeRoot.appendingPathComponent($0, isDirectory: true) } - guard let avdHome = avdCandidates.first(where: { - manager.fileExists(atPath: $0.appendingPathComponent("TFT_Ultra_Tablet.ini").path) - }) else { - throw TFTMACRuntimeError("The TFT_Ultra_Tablet AVD is missing from the proven runtime.") - } - let avdINI = avdHome.appendingPathComponent("TFT_Ultra_Tablet.ini") - let iniText = try String(contentsOf: avdINI, encoding: .utf8) - guard let avdPath = iniText.split(whereSeparator: \.isNewline) - .first(where: { $0.hasPrefix("path=") })? - .dropFirst("path=".count), !avdPath.isEmpty else { - throw TFTMACRuntimeError("TFT_Ultra_Tablet.ini does not identify its AVD directory.") - } - let avdDirectory = URL(fileURLWithPath: String(avdPath), isDirectory: true) - let avdConfig = avdDirectory.appendingPathComponent("config.ini") - guard manager.fileExists(atPath: avdConfig.path) else { - throw TFTMACRuntimeError("The TFT_Ultra_Tablet config.ini is missing.") - } - - guard let resourceURL = Bundle.main.resourceURL else { - throw TFTMACRuntimeError("TFTMAC.app has no Resources directory.") - } - let hostApplication = resourceURL.appendingPathComponent("TFTMAC Emulator Host.app", isDirectory: true) - guard manager.fileExists(atPath: hostApplication.path) else { - throw TFTMACRuntimeError("TFTMAC Emulator Host.app is missing from the application bundle.") + let globalApplicationSupport: URL + let adbServerPort: Int + let consolePort: Int + let controllerPort: Int + let serial: String + let emulatorIdentifier: String + let launchStrategy: TFTMACRuntimeLaunchStrategy + let adbVendorKeysPolicy: String + + static func discover( + configuration: TFTMACSelectedRuntimeConfiguration, + bundle: Bundle = .main + ) throws -> Self { + let selection = configuration.selection + let definition = selection.definition + let resolved = try configuration.authority.resolveForLaunch( + selection: selection, + bundle: bundle + ) + guard let controllerPort = definition.controllerPort, + let qemuPath = resolved.supplemental.qemuPath else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(selection.mode.rawValue) has no accepted launch lease." + ) } - let applicationSupport = manager.homeDirectoryForCurrentUser - .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) return Self( - sdkRoot: sdkRoot, - emulator: sdkRoot.appendingPathComponent("emulator/emulator"), - adb: sdkRoot.appendingPathComponent("platform-tools/adb"), - avdHome: avdHome, - avdDirectory: avdDirectory, - avdConfig: avdConfig, - hostApplication: hostApplication, - applicationSupport: applicationSupport + mode: selection.mode, + registrySha256: selection.registrySha256, + configurationSha256: definition.configurationSha256, + runtimeRoot: URL(fileURLWithPath: definition.runtimeRoot, isDirectory: true), + sdkRoot: URL(fileURLWithPath: definition.sdkRoot, isDirectory: true), + libraryRoot: URL(fileURLWithPath: definition.libraryRoot, isDirectory: true), + emulator: URL(fileURLWithPath: definition.emulatorPath), + qemu: URL(fileURLWithPath: qemuPath), + gfxstreamBackend: URL(fileURLWithPath: definition.gfxstreamBackendPath), + adb: URL(fileURLWithPath: definition.adbPath), + avdHome: URL(fileURLWithPath: definition.avdHome, isDirectory: true), + avdName: definition.avdName, + avdDirectory: URL(fileURLWithPath: definition.avdDirectory, isDirectory: true), + avdConfig: URL(fileURLWithPath: definition.avdConfigPath), + avdINI: URL(fileURLWithPath: definition.avdIniPath), + hostApplication: resolved.hostApplication, + applicationSupport: resolved.applicationSupport, + globalApplicationSupport: resolved.globalApplicationSupport, + adbServerPort: definition.adbServerPort, + consolePort: definition.consolePort, + controllerPort: controllerPort, + serial: definition.serial, + emulatorIdentifier: resolved.supplemental.emulatorIdentifier, + launchStrategy: resolved.supplemental.launchStrategy, + adbVendorKeysPolicy: resolved.supplemental.adbVendorKeysPolicy ) } } @@ -2025,6 +2036,7 @@ actor TFTMACRuntimeService { typealias StatusHandler = @MainActor @Sendable (String, Bool) -> Void typealias GameFrameHandler = @MainActor @Sendable (GameFrameTelemetryWindow?) -> Void + private let runtimeConfiguration: TFTMACSelectedRuntimeConfiguration private let profile: TFTMACRuntimeProfile private let mailbox: LatestFrameMailbox private let status: StatusHandler @@ -2065,53 +2077,96 @@ actor TFTMACRuntimeService { private var stopping = false init( - profile: TFTMACRuntimeProfile, + runtimeConfiguration: TFTMACSelectedRuntimeConfiguration, mailbox: LatestFrameMailbox, status: @escaping StatusHandler, gameFrame: @escaping GameFrameHandler ) { - self.profile = profile + self.runtimeConfiguration = runtimeConfiguration + self.profile = runtimeConfiguration.profile self.mailbox = mailbox self.status = status self.gameFrame = gameFrame } func run() async throws { - let applicationSupport = FileManager.default.homeDirectoryForCurrentUser - .appendingPathComponent("Library/Application Support/TFTMAC", isDirectory: true) - let telemetry = try TFTMACNativeTelemetry(profile: profile, applicationSupport: applicationSupport) - self.telemetry = telemetry - labStore = try CombatBenchmarkLabStore(applicationSupport: applicationSupport) - await status("Starting Android through the native Mac app host…", false) - + await status("Validating the selected TFTMAC runtime identity…", false) do { - let paths = try TFTMACRuntimePaths.discover() + let paths = try TFTMACRuntimePaths.discover(configuration: runtimeConfiguration) self.paths = paths - let stateRoot = paths.applicationSupport.appendingPathComponent("State", isDirectory: true) - runtimeLease = try TFTMACRuntimeLease.acquire(stateRoot: stateRoot) + let telemetry = try TFTMACNativeTelemetry( + profile: profile, + applicationSupport: paths.applicationSupport + ) + self.telemetry = telemetry + labStore = try CombatBenchmarkLabStore(applicationSupport: paths.applicationSupport) + await status("Starting Android through the native Mac app host…", false) + + let leaseIdentity = try runtimeConfiguration.selection.leaseIdentity() + let globalStateRoot = paths.globalApplicationSupport + .appendingPathComponent("State", isDirectory: true) + runtimeLease = try TFTMACRuntimeLease.acquire( + stateRoot: globalStateRoot, + identity: leaseIdentity + ) telemetry.recordEvent("RUNTIME_LEASE_ACQUIRED", payload: [ - "lease": "State/native-runtime.lease", + "lease": runtimeConfiguration.registry.document.activeLeaseRelativePath, "pid": ProcessInfo.processInfo.processIdentifier, - "exclusive": true + "exclusive": true, + "mode": paths.mode.rawValue, + "registry_sha256": paths.registrySha256, + "configuration_sha256": paths.configurationSha256, + "avd": paths.avdName, + "adb_server_port": paths.adbServerPort, + "console_port": paths.consolePort, + "controller_port": paths.controllerPort, + "serial": paths.serial ]) - try assertRuntimeUnoccupied(telemetry: telemetry) + try assertRuntimeUnoccupied(paths: paths, telemetry: telemetry) try recoverInterruptedAVDTransaction(paths: paths) recordFrozenReceipts(telemetry: telemetry, paths: paths) avdTransaction = try prepareAVD(paths: paths, telemetry: telemetry) try startADBServer(paths: paths, telemetry: telemetry) let launchStarted = Date() try launchEmulatorHost(paths: paths, telemetry: telemetry) - let discovery = try await waitForDiscovery(paths: paths, captureDirectory: telemetry.captureDirectory, after: launchStarted) + let discovery = try await waitForDiscovery( + paths: paths, + captureDirectory: telemetry.captureDirectory, + after: launchStarted + ) + guard discovery.port == paths.controllerPort else { + throw TFTMACRuntimeError( + "The emulator published controller port \(discovery.port), not the accepted port \(paths.controllerPort)." + ) + } self.discovery = discovery telemetry.recordEvent("EMULATOR_CONTROLLER_DISCOVERED", payload: [ "pid": discovery.processIdentifier, "grpc_port": discovery.port, "record": discovery.recordPath, - "token_persisted": false + "token_persisted": false, + "mode": paths.mode.rawValue + ]) + let loadedIdentity = try runtimeConfiguration.authority.validateLoadedRuntime( + processIdentifier: discovery.processIdentifier, + selection: runtimeConfiguration.selection + ) + telemetry.recordEvent("LOADED_RUNTIME_IDENTITY_PASS", payload: [ + "pid": loadedIdentity.processIdentifier, + "mode": paths.mode.rawValue, + "qemu_path": loadedIdentity.qemuPath, + "qemu_sha256": loadedIdentity.qemuSha256, + "qemu_uuids": loadedIdentity.qemuUuids, + "gfxstream_backend_path": loadedIdentity.gfxstreamBackendPath, + "gfxstream_backend_sha256": loadedIdentity.gfxstreamBackendSha256, + "gfxstream_backend_uuids": loadedIdentity.gfxstreamBackendUuids ]) try recordHostSchedulingReceipt(telemetry: telemetry) - let (inputStream, continuation) = AsyncStream.makeStream(of: EmulatorInput.self, bufferingPolicy: .bufferingNewest(256)) + let (inputStream, continuation) = AsyncStream.makeStream( + of: EmulatorInput.self, + bufferingPolicy: .bufferingNewest(256) + ) inputContinuation = continuation try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { [profile, mailbox] in @@ -2128,7 +2183,11 @@ actor TFTMACRuntimeService { try await self.waitForBootAndLaunchGame(paths: paths, telemetry: telemetry) } group.addTask { - try await self.sampleRuntime(paths: paths, telemetry: telemetry, emulatorPID: discovery.processIdentifier) + try await self.sampleRuntime( + paths: paths, + telemetry: telemetry, + emulatorPID: discovery.processIdentifier + ) } group.addTask { try await self.sampleGameFrames(paths: paths, telemetry: telemetry) @@ -2139,19 +2198,20 @@ actor TFTMACRuntimeService { if !stopping { throw TFTMACRuntimeError("The native emulator session ended unexpectedly.") } } catch { if stopping || error is CancellationError { - telemetry.recordEvent("RUNTIME_STOP_REQUESTED", payload: ["reason": "application_termination"]) + telemetry?.recordEvent("RUNTIME_STOP_REQUESTED", payload: ["reason": "application_termination"]) await cleanup(status: "STOPPED") return } - telemetry.recordEvent("RUNTIME_FAILED", payload: [ + telemetry?.recordEvent("RUNTIME_FAILED", payload: [ "error": error.localizedDescription, "diagnostic": String(describing: error), - "type": String(reflecting: type(of: error)) + "type": String(reflecting: type(of: error)), + "mode": runtimeConfiguration.selection.mode.rawValue ]) if profile.experimentPreset.isActiveCandidate { recordCorrectnessRejection(reason: error.localizedDescription) TFTMACRuntimeProfile.playable.with(experimentPreset: .control).save() - telemetry.recordEvent("EXPERIMENT_AUTO_ROLLBACK", payload: [ + telemetry?.recordEvent("EXPERIMENT_AUTO_ROLLBACK", payload: [ "failed_preset": profile.experimentPreset.rawValue, "restored_preset": RuntimeExperimentPreset.control.rawValue, "classification": "REJECTED_CORRECTNESS", @@ -2394,16 +2454,16 @@ actor TFTMACRuntimeService { inputContinuation?.finish() if let paths, let ownedPID = discovery?.processIdentifier, - Self.processMatchesLaunchedIdentity(ownedPID, sessionMarker: expectedSessionMarker) { + Self.processMatchesLaunchedIdentity(ownedPID, paths: paths, sessionMarker: expectedSessionMarker) { telemetry?.recordEvent("EMULATOR_STOP_SIGNAL_SENT", payload: [ "pid": ownedPID, - "serial": "emulator-5582", + "serial": paths.serial, "method": "adb emu kill", "ownership_verified": true ]) _ = try? Self.runCommand( paths.adb, - ["-P", "5038", "-s", "emulator-5582", "emu", "kill"], + ["-P", "\(paths.adbServerPort)", "-s", paths.serial, "emu", "kill"], environment: Self.adbEnvironment(paths: paths), timeout: 15 ) @@ -2415,10 +2475,16 @@ actor TFTMACRuntimeService { inputContinuation = nil var emulatorExitConfirmed = true if let paths { - let ownedPID = discovery?.processIdentifier ?? expectedSessionMarker.flatMap(Self.findOwnedEmulatorPID) + let ownedPID = discovery?.processIdentifier ?? expectedSessionMarker.flatMap { marker in + Self.findOwnedEmulatorPID(sessionMarker: marker, paths: paths) + } let ownedProcessExists = ownedPID.map(Self.processExists) ?? false let ownsRunningEmulator = ownedPID.map { - ownedProcessExists && Self.processMatchesLaunchedIdentity($0, sessionMarker: expectedSessionMarker) + ownedProcessExists && Self.processMatchesLaunchedIdentity( + $0, + paths: paths, + sessionMarker: expectedSessionMarker + ) } ?? false if ownsRunningEmulator { recordDiagnosticSnapshot(paths: paths, telemetry: telemetry, label: "session_end") @@ -2433,7 +2499,7 @@ actor TFTMACRuntimeService { if let ownedPID, ownsRunningEmulator { _ = try? Self.runCommand( paths.adb, - ["-P", "5038", "-s", "emulator-5582", "emu", "kill"], + ["-P", "\(paths.adbServerPort)", "-s", paths.serial, "emu", "kill"], environment: Self.adbEnvironment(paths: paths), timeout: 15 ) @@ -2449,7 +2515,7 @@ actor TFTMACRuntimeService { } telemetry?.recordEvent( emulatorExitConfirmed ? "EMULATOR_EXIT_CONFIRMED" : "EMULATOR_EXIT_TIMEOUT", - payload: ["pid": ownedPID ?? 0, "serial": "emulator-5582", "owned": ownsRunningEmulator] + payload: ["pid": ownedPID ?? 0, "serial": paths.serial, "owned": ownsRunningEmulator] ) } if openProcess?.isRunning == true { openProcess?.terminate() } @@ -2457,11 +2523,16 @@ actor TFTMACRuntimeService { var avdRestoreConfirmed = avdTransaction == nil if let transaction = avdTransaction { do { + guard let paths else { + throw TFTMACRuntimeError("AVD restore was withheld because the launched runtime identity is unavailable.") + } guard emulatorExitConfirmed else { throw TFTMACRuntimeError("AVD restore was withheld because the emulator exit was not confirmed.") } - guard !Self.anyEmulatorUsingSharedAVD() else { - throw TFTMACRuntimeError("AVD restore was withheld because another TFT_Ultra_Tablet process is active.") + guard !Self.anyEmulatorUsingSelectedAVD(paths: paths) else { + throw TFTMACRuntimeError( + "AVD restore was withheld because another \(paths.avdName) process is active." + ) } try transaction.restore() avdRestoreConfirmed = true @@ -2500,7 +2571,10 @@ actor TFTMACRuntimeService { let errorHandle = try FileHandle(forWritingTo: errorURL) let process = Process() process.executableURL = paths.adb - process.arguments = ["-P", "5038", "-s", "emulator-5582", "logcat", "-v", "threadtime", "-T", sessionStartSelector] + process.arguments = [ + "-P", "\(paths.adbServerPort)", "-s", paths.serial, + "logcat", "-v", "threadtime", "-T", sessionStartSelector + ] process.environment = Self.adbEnvironment(paths: paths) process.standardOutput = outputHandle process.standardError = errorHandle @@ -2559,94 +2633,145 @@ actor TFTMACRuntimeService { return false } - private func assertRuntimeUnoccupied(telemetry: TFTMACNativeTelemetry) throws { + private func assertRuntimeUnoccupied( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + var definitions = [runtimeConfiguration.selection.definition] + if runtimeConfiguration.selection.definition.requiresControlStopped { + let control = try runtimeConfiguration.registry.definition(for: .control) + if control.mode != runtimeConfiguration.selection.mode { definitions.append(control) } + } let processOutput = (try? Self.runCommand( URL(fileURLWithPath: "/bin/ps"), ["-axo", "pid=,command="], timeout: 10 ).output) ?? "" let emulatorConflicts = processOutput.split(whereSeparator: \.isNewline).filter { line in - line.contains("qemu-system-aarch64") - && (line.contains("@TFT_Ultra_Tablet") || line.contains("-port 5582") || line.contains("-grpc 8554")) + guard line.contains("qemu-system-aarch64") else { return false } + return definitions.contains { definition in + line.contains("@\(definition.avdName)") + || line.contains("-port \(definition.consolePort)") + || definition.controllerPort.map { line.contains("-grpc \($0)") } == true + } } + let leasedPorts = Set(definitions.flatMap { definition -> [Int] in + [definition.consolePort] + (definition.controllerPort.map { [$0] } ?? []) + }).sorted() + var listenerArguments = ["-nP"] + for port in leasedPorts { listenerArguments.append("-iTCP:\(port)") } + listenerArguments.append("-sTCP:LISTEN") let listenerOutput = (try? Self.runCommand( URL(fileURLWithPath: "/usr/sbin/lsof"), - ["-nP", "-iTCP:5582", "-iTCP:8554", "-sTCP:LISTEN"], + listenerArguments, timeout: 10 ).output) ?? "" let listeners = listenerOutput.split(whereSeparator: \.isNewline).dropFirst() guard emulatorConflicts.isEmpty && listeners.isEmpty else { - throw TFTMACRuntimeError("The shared TFT_Ultra_Tablet runtime or ports 5582/8554 are already in use. Close the existing emulator before launching TFTMAC.") + let modes = definitions.map(\.mode.rawValue).joined(separator: ", ") + throw TFTMACRuntimeError( + "The selected runtime lease conflicts with an active \(modes) emulator or port listener." + ) + } + let checkedIdentities: [[String: Any]] = definitions.map { definition in + [ + "mode": definition.mode.rawValue, + "avd": definition.avdName, + "console_port": definition.consolePort, + "controller_port": definition.controllerPort ?? 0, + "serial": definition.serial + ] } telemetry.recordEvent("RUNTIME_OWNERSHIP_PREFLIGHT_PASSED", payload: [ - "avd": "TFT_Ultra_Tablet", - "console_port": 5582, - "controller_port": 8554, + "selected_mode": paths.mode.rawValue, + "checked_identities": checkedIdentities, "existing_emulator_count": 0, "existing_listener_count": 0 ]) } - private func recordFrozenReceipts(telemetry: TFTMACNativeTelemetry, paths: TFTMACRuntimePaths) { + private func recordFrozenReceipts( + telemetry: TFTMACNativeTelemetry, + paths: TFTMACRuntimePaths + ) { let experimentReceipt = profile.experimentConfigurationReceipt let receipts: [(String, String, String, String)] = [ ("engine", "Unreal Engine", "user_locked_fact", "LOCKED"), - ("runtime_profile_id", profile.identifier, "validated native preferences", "DIRECT"), + ("runtime_mode", paths.mode.rawValue, "sealed runtime-mode registry", "DIRECT"), + ("runtime_mode_registry_sha256", paths.registrySha256, "bundled signed registry", "DIRECT"), + ("runtime_mode_configuration_sha256", paths.configurationSha256, "sealed runtime-mode registry", "DIRECT"), + ("runtime_profile_id", profile.identifier, "validated mode profile", "DIRECT"), ("runtime_experiment_preset", profile.experimentPreset.rawValue, "named launch experiment", "DIRECT"), ("runtime_configuration_sha256", experimentReceipt.sha256, "canonical effective configuration", "DIRECT"), ("runtime_configuration_json", experimentReceipt.canonicalJSON, "canonical effective configuration", "DIRECT"), - ("launcher_method", "/usr/bin/open -n -W --env ... --args ...", "Mactician donor architecture", "DIRECT"), + ("launcher_method", paths.launchStrategy.rawValue, "runtime-mode authority", "DIRECT"), + ("native_host_application", paths.hostApplication.path, "signed host authority", "DIRECT"), ("macos_game_mode_eligible", "true", "LSSupportsGameMode bundle contract", "DIRECT"), ("host_qos_requested", profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default", "named launch experiment", "REQUESTED"), - ("adb_server_port", "5038", "known-good donor", "DIRECT"), - ("emulator_console_port", "5582", "known-good donor", "DIRECT"), - ("adb_serial", "emulator-5582", "known-good donor", "DIRECT"), - ("controller_port", "\(profile.controllerPort)", "native authenticated controller", "REQUESTED"), - ("adb_vendor_keys", "ABSENT", "launch environment contract", "DIRECT"), - ("avd", "TFT_Ultra_Tablet", "installed runtime", "DIRECT"), - ("resolution", "\(profile.width)x\(profile.height)", "5 GiB gameplay evidence", "DIRECT"), - ("density_dpi", "\(profile.densityDPI)", "5 GiB gameplay evidence", "DIRECT"), - ("refresh_hz", "\(profile.refreshHz)", "5 GiB gameplay evidence", "DIRECT"), - ("vcpu", "\(profile.vCPU)", "5 GiB gameplay evidence", "DIRECT"), - ("ram_mib", "\(profile.ramMiB)", "latest retained 5 GiB runs", "STRONG"), - ("gpu_mode", profile.gpuMode, "playable baseline", "DIRECT"), - ("audio_backend", profile.audioBackend, "audio health receipt", "DIRECT"), - ("graphics_transport_requested", profile.graphicsTransport, "playable baseline", "REQUESTED"), + ("adb_server_port", "\(paths.adbServerPort)", "runtime-mode lease", "DIRECT"), + ("emulator_console_port", "\(paths.consolePort)", "runtime-mode lease", "DIRECT"), + ("adb_serial", paths.serial, "runtime-mode lease", "DIRECT"), + ("controller_port", "\(paths.controllerPort)", "runtime-mode lease", "DIRECT"), + ("adb_vendor_keys", paths.adbVendorKeysPolicy, "runtime-mode authority", "DIRECT"), + ("avd", paths.avdName, "runtime-mode authority", "DIRECT"), + ("runtime_root", paths.runtimeRoot.path, "runtime-mode authority", "DIRECT"), + ("mode_application_support", paths.applicationSupport.path, "runtime-mode state isolation", "DIRECT"), + ("resolution", "\(profile.width)x\(profile.height)", "validated mode profile", "DIRECT"), + ("density_dpi", "\(profile.densityDPI)", "validated mode profile", "DIRECT"), + ("refresh_hz", "\(profile.refreshHz)", "validated mode profile", "DIRECT"), + ("vcpu", "\(profile.vCPU)", "validated mode profile", "DIRECT"), + ("ram_mib", "\(profile.ramMiB)", "validated mode profile", "DIRECT"), + ("gpu_mode", profile.gpuMode, "validated mode profile", "DIRECT"), + ("audio_backend", profile.audioBackend, "validated mode profile", "DIRECT"), + ("graphics_transport_requested", profile.graphicsTransport, "validated mode profile", "REQUESTED"), ("emulator_features_requested", profile.effectiveEmulatorFeatures.joined(separator: ","), "named launch experiment", "REQUESTED"), - ("asg_write_buffer_size", "\(profile.asgWriteBufferSize)", "playable baseline", "REQUESTED"), - ("asg_write_step_size", "\(profile.asgWriteStepSize)", "playable baseline", "REQUESTED"), - ("asg_data_ring_size", "\(profile.asgDataRingSize)", "playable baseline", "REQUESTED"), - ("asg_draw_flush_interval_us", "\(profile.asgDrawFlushInterval)", "playable baseline", "REQUESTED"), - ("angle_enabled_requested", profile.angleEnabledFeatures, "playable baseline", "REQUESTED"), - ("angle_disabled_requested", profile.angleDisabledFeatures, "playable baseline", "REQUESTED"), + ("asg_write_buffer_size", "\(profile.asgWriteBufferSize)", "validated mode profile", "REQUESTED"), + ("asg_write_step_size", "\(profile.asgWriteStepSize)", "validated mode profile", "REQUESTED"), + ("asg_data_ring_size", "\(profile.asgDataRingSize)", "validated mode profile", "REQUESTED"), + ("asg_draw_flush_interval_us", "\(profile.asgDrawFlushInterval)", "validated mode profile", "REQUESTED"), + ("angle_enabled_requested", profile.angleEnabledFeatures, "validated mode profile", "REQUESTED"), + ("angle_disabled_requested", profile.angleDisabledFeatures, "validated mode profile", "REQUESTED"), ("frame_transport", "raw_grpc_rgba8888", "native admission path", "DIRECT"), ("raw_logcat_policy", "LOCAL_SENSITIVE_SESSION_SCOPED_NOT_FOR_SHARING", "privacy contract", "LOCKED"), - ("sdk_root", paths.sdkRoot.path, "filesystem discovery", "DIRECT") + ("sdk_root", paths.sdkRoot.path, "runtime-mode authority", "DIRECT") ] for receipt in receipts { telemetry.recordReceipt(key: receipt.0, value: receipt.1, source: receipt.2, confidence: receipt.3) } } - private func startADBServer(paths: TFTMACRuntimePaths, telemetry: TFTMACNativeTelemetry) throws { + private func startADBServer( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { let result = try Self.runCommand( paths.adb, - ["-P", "5038", "start-server"], + ["-P", "\(paths.adbServerPort)", "start-server"], environment: Self.adbEnvironment(paths: paths), timeout: 30 ) guard result.status == 0 else { - throw TFTMACRuntimeError("ADB server 5038 could not start: \(result.output.suffix(1200))") + throw TFTMACRuntimeError( + "ADB server \(paths.adbServerPort) could not start: \(result.output.suffix(1200))" + ) } telemetry.recordEvent("ADB_SERVER_STARTED", payload: [ - "port": 5038, - "serial": "emulator-5582", - "adb_vendor_keys_present": false, + "port": paths.adbServerPort, + "serial": paths.serial, + "adb_vendor_keys_policy": paths.adbVendorKeysPolicy, "output": result.output.suffix(2000).description ]) } - private func launchEmulatorHost(paths: TFTMACRuntimePaths, telemetry: TFTMACNativeTelemetry) throws { + private func launchEmulatorHost( + paths: TFTMACRuntimePaths, + telemetry: TFTMACNativeTelemetry + ) throws { + guard paths.launchStrategy == .bundledForwarder else { + throw TFTMACRuntimeModeError( + message: "Runtime mode \(paths.mode.rawValue) requires its separately receipted native-host acceptance operation." + ) + } let stdout = telemetry.captureDirectory.appendingPathComponent("emulator.stdout.log") let stderr = telemetry.captureDirectory.appendingPathComponent("emulator.stderr.log") FileManager.default.createFile(atPath: stdout.path, contents: nil) @@ -2658,8 +2783,8 @@ actor TFTMACRuntimeService { var arguments = [ "-n", "-W", "--env", "TFT_EMULATOR=\(paths.emulator.path)", - "--env", "TFT_ADB_SERVER_PORT=5038", - "--env", "ANDROID_ADB_SERVER_PORT=5038", + "--env", "TFT_ADB_SERVER_PORT=\(paths.adbServerPort)", + "--env", "ANDROID_ADB_SERVER_PORT=\(paths.adbServerPort)", "--env", "ADB_MDNS_AUTO_CONNECT=", "--env", "ADB_SERVER_SOCKET=", "--env", "ANDROID_ADB_SERVER_ADDRESS=", @@ -2676,7 +2801,7 @@ actor TFTMACRuntimeService { "--env", "TFT_HOST_STDERR=\(stderr.path)", paths.hostApplication.path, "--args", - "@TFT_Ultra_Tablet", "-id", "TFTMAC", "-port", "5582", + "@\(paths.avdName)", "-id", paths.emulatorIdentifier, "-port", "\(paths.consolePort)", "-gpu", profile.gpuMode, "-audio", profile.audioBackend, "-feature", profile.effectiveEmulatorFeatures.joined(separator: ","), "-append-userspace-opt", "androidboot.opengles.version=196610", @@ -2688,7 +2813,7 @@ actor TFTMACRuntimeService { "-cores", "\(profile.vCPU)", "-memory", "\(profile.ramMiB)", "-no-hidpi-scaling", "-no-snapshot", "-no-metrics", "-no-boot-anim", "-crash-report-mode", "disabled", "-qt-hide-window", - "-grpc", "\(profile.controllerPort)", "-grpc-use-token", + "-grpc", "\(paths.controllerPort)", "-grpc-use-token", "-idle-grpc-timeout", "300" ] if let zone = TimeZone.current.identifier.addingPercentEncoding(withAllowedCharacters: .alphanumerics), !zone.isEmpty { @@ -2705,9 +2830,10 @@ actor TFTMACRuntimeService { telemetry.recordEvent("EMULATOR_HOST_LAUNCHED", payload: [ "method": "/usr/bin/open", "flags": ["-n", "-W", "--env", "--args"], + "mode": paths.mode.rawValue, "host_application": paths.hostApplication.path, "open_pid": process.processIdentifier, - "adb_vendor_keys_present": false, + "adb_vendor_keys_policy": paths.adbVendorKeysPolicy, "game_mode_eligible": true, "host_qos_requested": profile.experimentPreset.requestsHostLatencyQoS ? "user_interactive" : "default", "controller_discovery_roots": Self.controllerDiscoveryRoots(paths: paths).map(\.path), @@ -2783,7 +2909,12 @@ actor TFTMACRuntimeService { let token = values["grpc.token"], !token.isEmpty else { continue } let name = candidate.deletingPathExtension().lastPathComponent let pidText = name.dropFirst("pid_".count).prefix(while: \.isNumber) - guard let pid = Int32(pidText), Self.processMatchesLaunchedIdentity(pid, sessionMarker: expectedSessionMarker) else { continue } + guard let pid = Int32(pidText), + Self.processMatchesLaunchedIdentity( + pid, + paths: paths, + sessionMarker: expectedSessionMarker + ) else { continue } return EmulatorControllerDiscovery(processIdentifier: pid, port: port, token: token, recordPath: candidate.path) } try await Task.sleep(for: .milliseconds(200)) @@ -2792,14 +2923,14 @@ actor TFTMACRuntimeService { } private func waitForBootAndLaunchGame(paths: TFTMACRuntimePaths, telemetry: TFTMACNativeTelemetry) async throws { - await status("Waiting for the proven ADB identity on emulator-5582…", false) + await status("Waiting for the proven ADB identity on \(paths.serial)…", false) var lastState = "missing" var previouslyLoggedState: String? while !stopping { try Task.checkCancellation() let result = try? Self.runCommand( paths.adb, - ["-P", "5038", "-s", "emulator-5582", "get-state"], + ["-P", "\(paths.adbServerPort)", "-s", paths.serial, "get-state"], environment: Self.adbEnvironment(paths: paths), timeout: 10 ) @@ -2817,18 +2948,18 @@ actor TFTMACRuntimeService { telemetry.recordEvent("ADB_STATE_CHANGED", payload: [ "previous_state": previouslyLoggedState ?? "none", "current_state": lastState, - "serial": "emulator-5582", + "serial": paths.serial, "diagnostic": String(diagnostic.prefix(800)) ]) if lastState == "unauthorized" { telemetry.recordEvent("ADB_UNAUTHORIZED_OBSERVED", payload: [ - "serial": "emulator-5582", + "serial": paths.serial, "authorization_is_user_controlled": true ]) } else if lastState == "offline" { await status("Android is booting; ADB is temporarily offline…", false) } else if lastState == "missing" { - await status("Waiting for emulator-5582 to appear on ADB 5038…", false) + await status("Waiting for \(paths.serial) to appear on ADB \(paths.adbServerPort)…", false) } previouslyLoggedState = lastState } @@ -2837,9 +2968,9 @@ actor TFTMACRuntimeService { } try Task.checkCancellation() guard lastState == "device" else { - throw TFTMACRuntimeError("ADB emulator-5582 did not authorize in the logged-in Mac session (last state: \(lastState)).") + throw TFTMACRuntimeError("ADB \(paths.serial) did not authorize in the logged-in Mac session (last state: \(lastState)).") } - telemetry.recordEvent("ADB_DEVICE_AUTHORIZED", payload: ["port": 5038, "serial": "emulator-5582"]) + telemetry.recordEvent("ADB_DEVICE_AUTHORIZED", payload: ["port": paths.adbServerPort, "serial": paths.serial]) try startLogcatCapture(paths: paths, telemetry: telemetry) let bootDeadline = Date().addingTimeInterval(300) @@ -2936,9 +3067,9 @@ actor TFTMACRuntimeService { guard launched else { throw TFTMACRuntimeError("Android could not launch the official TFT activity.") } telemetry.recordEvent("TFT_READY_FOR_USER", payload: [ "engine": "Unreal Engine", - "resolution": "1920x1080", + "resolution": "\(profile.width)x\(profile.height)", "refresh_hz": profile.refreshHz, - "audio_backend": "coreaudio", + "audio_backend": profile.audioBackend, "profile_id": profile.identifier ]) telemetry.markRunning() @@ -3704,7 +3835,7 @@ actor TFTMACRuntimeService { """ let trace = try runCommand( paths.adb, - ["-P", "5038", "-s", "emulator-5582", "shell", "perfetto", "--txt", "-c", "-", "-o", remotePath], + ["-P", "\(paths.adbServerPort)", "-s", paths.serial, "shell", "perfetto", "--txt", "-c", "-", "-o", remotePath], environment: adbEnvironment(paths: paths), input: Data(config.utf8), timeout: TimeInterval(durationSeconds + 30) @@ -4556,14 +4687,16 @@ actor TFTMACRuntimeService { ) } - nonisolated private static func adbEnvironment(paths: TFTMACRuntimePaths) -> [String: String] { + nonisolated private static func adbEnvironment( + paths: TFTMACRuntimePaths + ) -> [String: String] { var environment = ProcessInfo.processInfo.environment environment.removeValue(forKey: "ADB_VENDOR_KEYS") environment.removeValue(forKey: "ADB_SERVER_SOCKET") environment.removeValue(forKey: "ANDROID_ADB_SERVER_ADDRESS") environment["ANDROID_SDK_ROOT"] = paths.sdkRoot.path environment["ANDROID_AVD_HOME"] = paths.avdHome.path - environment["ANDROID_ADB_SERVER_PORT"] = "5038" + environment["ANDROID_ADB_SERVER_PORT"] = "\(paths.adbServerPort)" environment["ADB_MDNS_AUTO_CONNECT"] = "" return environment } @@ -4571,7 +4704,7 @@ actor TFTMACRuntimeService { nonisolated private static func adb(paths: TFTMACRuntimePaths, _ arguments: [String], timeout: TimeInterval) throws -> ProcessResult { let result = try runCommand( paths.adb, - ["-P", "5038", "-s", "emulator-5582"] + arguments, + ["-P", "\(paths.adbServerPort)", "-s", paths.serial] + arguments, environment: adbEnvironment(paths: paths), timeout: timeout ) @@ -4585,7 +4718,7 @@ actor TFTMACRuntimeService { let result = try runCommand( paths.adb, [ - "-P", "5038", "-s", "emulator-5582", "shell", "pidof", + "-P", "\(paths.adbServerPort)", "-s", paths.serial, "shell", "pidof", "com.riotgames.league.teamfighttactics" ], environment: adbEnvironment(paths: paths), @@ -4649,6 +4782,7 @@ actor TFTMACRuntimeService { nonisolated private static func processMatchesLaunchedIdentity( _ processIdentifier: Int32, + paths: TFTMACRuntimePaths, sessionMarker: String? = nil ) -> Bool { guard processExists(processIdentifier), @@ -4657,21 +4791,27 @@ actor TFTMACRuntimeService { ["-p", "\(processIdentifier)", "-ww", "-o", "command="], timeout: 5 ), result.status == 0 else { return false } - let baseIdentityMatches = result.output.contains("qemu-system-aarch64") - && result.output.contains("@TFT_Ultra_Tablet") - && result.output.contains("-port 5582") + let baseIdentityMatches = result.output.contains(paths.qemu.lastPathComponent) + && result.output.contains("@\(paths.avdName)") + && result.output.contains("-port \(paths.consolePort)") + && result.output.contains("-grpc \(paths.controllerPort)") return baseIdentityMatches && (sessionMarker.map(result.output.contains) ?? true) } - nonisolated private static func findOwnedEmulatorPID(sessionMarker: String) -> Int32? { + nonisolated private static func findOwnedEmulatorPID( + sessionMarker: String, + paths: TFTMACRuntimePaths + ) -> Int32? { guard let result = try? runCommand( URL(fileURLWithPath: "/bin/ps"), ["-axo", "pid=,command="], timeout: 10 ), result.status == 0 else { return nil } for line in result.output.split(whereSeparator: \.isNewline) { - guard line.contains("qemu-system-aarch64"), - line.contains("@TFT_Ultra_Tablet"), + guard line.contains(paths.qemu.lastPathComponent), + line.contains("@\(paths.avdName)"), + line.contains("-port \(paths.consolePort)"), + line.contains("-grpc \(paths.controllerPort)"), line.contains(sessionMarker), let pid = line.split(whereSeparator: \.isWhitespace).first.flatMap({ Int32($0) }) else { continue } return pid @@ -4679,14 +4819,18 @@ actor TFTMACRuntimeService { return nil } - nonisolated private static func anyEmulatorUsingSharedAVD() -> Bool { + nonisolated private static func anyEmulatorUsingSelectedAVD( + paths: TFTMACRuntimePaths + ) -> Bool { guard let result = try? runCommand( URL(fileURLWithPath: "/bin/ps"), ["-axo", "command="], timeout: 10 ), result.status == 0 else { return true } return result.output.split(whereSeparator: \.isNewline).contains { line in - line.contains("qemu-system-aarch64") && line.contains("@TFT_Ultra_Tablet") + line.contains(paths.qemu.lastPathComponent) + && line.contains("@\(paths.avdName)") + && line.contains("-port \(paths.consolePort)") } } @@ -4847,12 +4991,17 @@ final class TFTMACRuntimeController { private(set) var failed = false init( - profile: TFTMACRuntimeProfile, + runtimeConfiguration: TFTMACSelectedRuntimeConfiguration, mailbox: LatestFrameMailbox, status: @escaping TFTMACRuntimeService.StatusHandler, gameFrame: @escaping TFTMACRuntimeService.GameFrameHandler ) { - service = TFTMACRuntimeService(profile: profile, mailbox: mailbox, status: status, gameFrame: gameFrame) + service = TFTMACRuntimeService( + runtimeConfiguration: runtimeConfiguration, + mailbox: mailbox, + status: status, + gameFrame: gameFrame + ) } func start() { From d3375748b7d1b6f8e3b828b9480f7c2b3933a10c Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 21:23:24 -0500 Subject: [PATCH 06/10] Prepare guarded R9 diagnostic first boot --- .../diagnostic-first-boot-v1/AMENDMENT.md | 26 ++++ .../PORT_ALLOCATION_RECEIPT.json | 25 +++ .../SOURCE_VALIDATION_RECEIPT.json | 30 ++++ .../ZENGATE_RECEIPT.json | 24 +++ .../validate-source.mjs | 107 +++++++++++++ RuntimeHost/DiagnosticInfo.plist | 32 ++++ Tests/TFTMACTests/TFTMACGate1Tests.swift | 14 +- facts.md | 25 ++- scripts/build-diagnostic-forwarder.command | 144 ++++++++++++++++++ scripts/verify-diagnostic-runtime.command | 77 ++++++++++ scripts/verify-tftmac.command | 6 +- ssot/AUTHORITY_INPUTS.sha256 | 2 +- ssot/STACK.lock.yaml | 2 +- ssot/runtime-modes.json | 20 +-- tftmac/Runtime/RuntimeMode.swift | 8 +- tftmac/Runtime/TFTMACRuntime.swift | 4 +- 16 files changed, 516 insertions(+), 30 deletions(-) create mode 100644 .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/AMENDMENT.md create mode 100644 .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/SOURCE_VALIDATION_RECEIPT.json create mode 100644 .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/ZENGATE_RECEIPT.json create mode 100755 .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs create mode 100644 RuntimeHost/DiagnosticInfo.plist create mode 100755 scripts/build-diagnostic-forwarder.command create mode 100755 scripts/verify-diagnostic-runtime.command diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/AMENDMENT.md b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/AMENDMENT.md new file mode 100644 index 0000000..7399935 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/AMENDMENT.md @@ -0,0 +1,26 @@ +# Diagnostic First Boot v1 — R9 Native Forwarder and Port Authority + +Status: ACTIVE APPEND-ONLY GATE + +This gate follows verified Wave B v4 commit `a84aaa7` and preserves the original implementation plan and scope lock. It exists because the previously receipted Swift diagnostic host is hardcoded to the older `TFTMAC_Diagnostic_API37` AVD, ADB port `5042`, and a no-controller/no-window first-load harness. It cannot launch the accepted R9 AVD or provide TFTMAC's native controller display and therefore must not govern R9 acceptance. + +## Authorized change + +1. Preserve the old diagnostic host and every accepted r9 build/clone receipt. +2. Allocate diagnostic ADB `5041`, console `5586`, and controller `8556` only after listener and exclusive-bind checks pass with stock control stopped. +3. Build a new external diagnostic forwarder from the proven `RuntimeHost/main.c` launch chain with a diagnostic-only plist and ad-hoc local signature. Write a new immutable build receipt and sidecar; do not overwrite the old host or receipt. +4. Update `advanced_diagnostics` to the new forwarder/receipt and enable it with controller port `8556`. Keep `control` the default and unchanged. Keep `candidate` blocked. +5. Permit the existing main TFTMAC runtime controller to use the receipted `external_native_host` forwarder. Do not introduce another emulator spawn path. +6. Update the pinned registry identity and tests. The source verifier must build unsigned Release and pass all 49 native tests before any boot. +7. First boot must fail before TFT launch unless the loaded QEMU path/hash/UUID, command-line AVD/ports, and mapped gfxstream path/hash/UUID match the accepted R9 authority. + +## Exclusions + +- No modification of the stock control runtime or control AVD. +- No reuse of the stale diagnostic host as R9 authority. +- No candidate runtime, Wave C instrumentation, Riot credential handling, or APK modification. +- No final application install, distribution signing, or default-mode change. + +## Exit condition + +The port and forwarder receipts are sealed, `advanced_diagnostics` is selectable only with the explicit environment variable, source verification passes, and guarded first boot proves the accepted R9 loaded identities. Manual PIN/Riot/gameplay acceptance remains a user-operated continuation after the identity gate. diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json new file mode 100644 index 0000000..e02e490 --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json @@ -0,0 +1,25 @@ +{ + "schema": 1, + "state": "DIAGNOSTIC_PORT_ALLOCATION_PASS", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-02T02:12:04Z", + "base_head_sha": "a84aaa7", + "mode": "advanced_diagnostics", + "loopback_only": true, + "ports": { + "adb_server": 5041, + "console": 5586, + "controller": 8556 + }, + "checks": { + "listeners_found": 0, + "exclusive_bind_5041": "PASS", + "exclusive_bind_5586": "PASS", + "exclusive_bind_8556": "PASS", + "qemu_system_aarch64_processes": 0, + "control_runtime_stopped": true + }, + "reservation_scope": "TFTMAC advanced_diagnostics runtime lease", + "invalidated_by": "Any listener or runtime using 5041, 5586, or 8556 before guarded launch requires a new receipt." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/SOURCE_VALIDATION_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/SOURCE_VALIDATION_RECEIPT.json new file mode 100644 index 0000000..11eeb4a --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/SOURCE_VALIDATION_RECEIPT.json @@ -0,0 +1,30 @@ +{ + "schema": 1, + "state": "DIAGNOSTIC_FIRST_BOOT_SOURCE_PASS", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "verified_at": "2026-09-02T02:20:37Z", + "base_head_sha": "a84aaa709b59bd61a5b5ca6ee0ef305375f314cd", + "runtime_modes_sha256": "6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d", + "source_validator_sha256": "3095f0466033364eba071ee7127dc2479467fdb870dc426bc9365ad9006ed732", + "source_verifier_sha256": "664fd4435ac47632d1995916957a990db09fb01f5e91deb98c3ce70ce752676b", + "diagnostic_forwarder_build_script_sha256": "634cc6468ee160711c183b912d7bb95a63419aa157401b5b65b5dd568411f204", + "diagnostic_forwarder_receipt": { + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-forwarder-r1-native-host-build.json", + "sha256": "3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f" + }, + "diagnostic_ports": { + "adb_server": 5041, + "console": 5586, + "controller": 8556 + }, + "unsigned_release_build": "PASS", + "native_tests": { + "executed": 49, + "failures": 0 + }, + "control_default": true, + "candidate_state": "blocked_not_built", + "runtime_launch_attempted": false, + "next_safe_action": "Run the local diagnostic-runtime preflight, then launch the guarded R9 first boot from the unsigned verified app." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/ZENGATE_RECEIPT.json b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/ZENGATE_RECEIPT.json new file mode 100644 index 0000000..5c9f6ae --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/ZENGATE_RECEIPT.json @@ -0,0 +1,24 @@ +{ + "schema": 1, + "result": "PASS", + "gate": "TARGETED_DIAGNOSTIC_FIRST_BOOT_V1_ZENGATE", + "version": "2.3", + "project_id": "tftmac", + "change_id": "215ec5a3-6554-4ca3-95db-1525433bb20f", + "observed_at": "2026-09-02T02:12:04Z", + "base_head_sha": "a84aaa7", + "hard_gates": { + "win_condition": "PASS", + "source_of_truth": "PASS", + "material_ambiguity": "PASS", + "safety_reversibility": "PASS", + "validation_integrity": "PASS", + "project_constraints": "PASS" + }, + "weighted_quality": 94.5, + "risk_penalty": 3.0, + "final_score": 91.5, + "decision": "PROCEED", + "remediation_mode": "NONE", + "execution_scope_lock": "Build one new R9 native forwarder, seal one port allocation, enable only advanced_diagnostics, verify source, then perform the guarded identity boot. Preserve control, candidate, stale host, accepted artifacts, and later-wave boundaries." +} diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs new file mode 100755 index 0000000..62394ae --- /dev/null +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs @@ -0,0 +1,107 @@ +#!/usr/bin/env node +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; + +const root = process.cwd(); +const registryPath = 'ssot/runtime-modes.json'; +const expectedRegistrySha = '6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d'; +const expectedPortReceiptSha = '3536b1d54a0643bc3fcbb9dbff01be2402ca9c45d2100e220c2f857e65a129cd'; +const expectedHostReceiptSha = '3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f'; + +function absolute(relativePath) { return path.join(root, relativePath); } +function read(relativePath) { return fs.readFileSync(absolute(relativePath)); } +function readText(relativePath) { return fs.readFileSync(absolute(relativePath), 'utf8'); } +function sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } +function fail(message) { throw new Error(`DIAGNOSTIC_FIRST_BOOT_SOURCE_FAILED: ${message}`); } +function assert(value, message) { if (!value) fail(message); } + +function configurationHash(mode) { + const fields = [ + ['mode', mode.mode], ['launch_state', mode.launch_state], ['runtime_root', mode.runtime_root], + ['sdk_root', mode.sdk_root], ['library_root', mode.library_root], ['emulator_path', mode.emulator_path], + ['emulator_sha256', mode.emulator_sha256 ?? ''], ['gfxstream_backend_path', mode.gfxstream_backend_path], + ['gfxstream_backend_sha256', mode.gfxstream_backend_sha256 ?? ''], ['adb_path', mode.adb_path], + ['avd_home', mode.avd_home], ['avd_name', mode.avd_name], ['avd_directory', mode.avd_directory], + ['avd_config_path', mode.avd_config_path], ['avd_config_sha256', mode.avd_config_sha256 ?? ''], + ['avd_ini_path', mode.avd_ini_path], ['avd_ini_sha256', mode.avd_ini_sha256 ?? ''], + ['adb_server_port', mode.adb_server_port], ['console_port', mode.console_port], + ['controller_port', mode.controller_port ?? ''], ['serial', mode.serial], + ['authority_manifest_kind', mode.authority_manifest.kind], ['authority_manifest_path', mode.authority_manifest.path], + ['authority_manifest_sha256', mode.authority_manifest.sha256 ?? ''], ['application_bundle_id', mode.application_bundle_id], + ['application_version', mode.application_version], ['application_build', mode.application_build], + ['allowed_purpose', mode.allowed_purpose], ['comparability_class', mode.comparability_class], + ['rollback_target', mode.rollback_target], ['requires_control_stopped', String(mode.requires_control_stopped)] + ]; + return sha256(Buffer.from(fields.map(([key, value]) => `${key}=${value}`).join('\n'))); +} + +for (const required of [ + '.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/AMENDMENT.md', + '.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/ZENGATE_RECEIPT.json', + '.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json', + 'RuntimeHost/DiagnosticInfo.plist', + 'scripts/build-diagnostic-forwarder.command', + registryPath, + 'tftmac/Runtime/RuntimeMode.swift', + 'tftmac/Runtime/RuntimeModeAuthority.swift', + 'tftmac/Runtime/TFTMACRuntime.swift', + 'Tests/TFTMACTests/TFTMACGate1Tests.swift' +]) assert(fs.existsSync(absolute(required)), `required source authority is missing: ${required}`); + +const registryBytes = read(registryPath); +assert(sha256(registryBytes) === expectedRegistrySha, 'runtime-mode registry identity drifted'); +const registry = JSON.parse(registryBytes); +assert(registry.schema === 1 && registry.contract === 'TFTMAC_RUNTIME_MODES_V1', 'runtime-mode contract drifted'); +assert(registry.default_mode === 'control', 'control must remain the default mode'); +assert(JSON.stringify(Object.keys(registry.modes).sort()) === JSON.stringify(['advanced_diagnostics', 'candidate', 'control']), 'runtime-mode inventory drifted'); + +for (const mode of Object.values(registry.modes)) { + assert(configurationHash(mode) === mode.configuration_sha256, `${mode.mode} configuration hash drifted`); +} + +const control = registry.modes.control; +assert(control.launch_state === 'enabled', 'control is not enabled'); +assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, 'control ports drifted'); +assert(control.avd_name === 'TFT_Ultra_Tablet' && control.serial === 'emulator-5582', 'control identity drifted'); + +const diagnostics = registry.modes.advanced_diagnostics; +assert(diagnostics.launch_state === 'enabled', 'advanced diagnostics is not enabled'); +assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === 'control', 'diagnostic isolation/rollback drifted'); +assert(diagnostics.avd_name === 'TFTMAC_Diagnostic_API37_R9' && diagnostics.serial === 'emulator-5586', 'diagnostic AVD identity drifted'); +assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.controller_port === 8556, 'diagnostic port allocation drifted'); +assert(diagnostics.launch_strategy === 'external_native_host', 'diagnostic launch strategy drifted'); +assert(diagnostics.host_application?.path === '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-forwarder-r1/TFTMAC Diagnostic Forwarder.app', 'diagnostic host path drifted'); +assert(diagnostics.host_application?.bundle_identifier === 'com.flashls1.tftmac.runtime.diagnostic-forwarder', 'diagnostic host bundle identity drifted'); +assert(diagnostics.host_application?.executable_relative_path === 'Contents/MacOS/TFTMACDiagnosticForwarder', 'diagnostic host executable path drifted'); +assert(diagnostics.host_application?.executable_sha256 === '128239b2cf3ddb04669c4fda97e895e1a4a800dcf2c2144066979427d92af5b6', 'diagnostic host executable identity drifted'); +assert(diagnostics.diagnostic_receipts?.native_host?.sha256 === expectedHostReceiptSha, 'diagnostic host receipt reference drifted'); + +const candidate = registry.modes.candidate; +assert(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate is not fail-closed'); + +const portReceipt = JSON.parse(readText('.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json')); +assert(sha256(read('.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json')) === expectedPortReceiptSha, 'port receipt identity drifted'); +assert(portReceipt.state === 'DIAGNOSTIC_PORT_ALLOCATION_PASS' && portReceipt.ports?.controller === 8556, 'port receipt contract drifted'); + +const runtimeModeSource = readText('tftmac/Runtime/RuntimeMode.swift'); +assert(runtimeModeSource.includes(`static let expectedRegistrySha256 = "${expectedRegistrySha}"`), 'Swift registry pin drifted'); +const runtimeSource = readText('tftmac/Runtime/TFTMACRuntime.swift'); +assert(runtimeSource.includes('paths.launchStrategy == .bundledForwarder || paths.launchStrategy == .externalNativeHost'), 'runtime does not accept the receipted external native host'); +const tests = readText('Tests/TFTMACTests/TFTMACGate1Tests.swift'); +assert(tests.includes('testRuntimeModeRegistrySelectsReceiptedDiagnosticsAndRejectsUnacceptedModes'), 'diagnostic selection contract test is missing'); + +const testCount = fs.readdirSync(absolute('Tests/TFTMACTests')) + .filter((name) => name.endsWith('.swift')) + .reduce((total, name) => total + (readText(`Tests/TFTMACTests/${name}`).match(/^ func test/gm) ?? []).length, 0); +assert(testCount === 49, `expected 49 native tests, found ${testCount}`); + +console.log(JSON.stringify({ + state: 'DIAGNOSTIC_FIRST_BOOT_SOURCE_PASS', + runtime_modes_sha256: expectedRegistrySha, + test_count: testCount, + control_default: true, + diagnostics: { avd: diagnostics.avd_name, adb: 5041, console: 5586, controller: 8556 }, + candidate: candidate.launch_state, + external_artifacts_read: false +}, null, 2)); diff --git a/RuntimeHost/DiagnosticInfo.plist b/RuntimeHost/DiagnosticInfo.plist new file mode 100644 index 0000000..5b40d5f --- /dev/null +++ b/RuntimeHost/DiagnosticInfo.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDisplayName + TFTMAC Diagnostic Forwarder + CFBundleExecutable + TFTMACDiagnosticForwarder + CFBundleIdentifier + com.flashls1.tftmac.runtime.diagnostic-forwarder + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + TFTMAC Diagnostic Forwarder + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleVersion + 1 + GCSupportsGameMode + + LSApplicationCategoryType + public.app-category.games + LSUIElement + + LSSupportsGameMode + + NSHighResolutionCapable + + + diff --git a/Tests/TFTMACTests/TFTMACGate1Tests.swift b/Tests/TFTMACTests/TFTMACGate1Tests.swift index 59893a8..e148917 100644 --- a/Tests/TFTMACTests/TFTMACGate1Tests.swift +++ b/Tests/TFTMACTests/TFTMACGate1Tests.swift @@ -286,9 +286,19 @@ final class TFTMACGate1Tests: XCTestCase { XCTAssertEqual(selection.definition.serial, "emulator-5582") } - func testRuntimeModeRegistryFailsClosedForUnacceptedModes() throws { + func testRuntimeModeRegistrySelectsReceiptedDiagnosticsAndRejectsUnacceptedModes() throws { let registry = try TFTMACRuntimeModeRegistry(data: runtimeModeRegistryData()) - for requested in ["advanced_diagnostics", "candidate", "unknown"] { + let diagnostics = try registry.selection(environment: [ + TFTMACRuntimeModeRegistry.environmentKey: "advanced_diagnostics" + ]) + XCTAssertEqual(diagnostics.mode, .advancedDiagnostics) + XCTAssertEqual(diagnostics.definition.avdName, "TFTMAC_Diagnostic_API37_R9") + XCTAssertEqual(diagnostics.definition.adbServerPort, 5041) + XCTAssertEqual(diagnostics.definition.consolePort, 5586) + XCTAssertEqual(diagnostics.definition.controllerPort, 8556) + XCTAssertEqual(diagnostics.definition.serial, "emulator-5586") + XCTAssertTrue(diagnostics.definition.requiresControlStopped) + for requested in ["candidate", "unknown"] { XCTAssertThrowsError(try registry.selection(environment: [ TFTMACRuntimeModeRegistry.environmentKey: requested ]), requested) diff --git a/facts.md b/facts.md index 7139a50..1291314 100644 --- a/facts.md +++ b/facts.md @@ -1,7 +1,7 @@ # TFTMAC Facts **Authority date:** 2026-09-01 America/Chicago -**Observed runtime/source evidence through:** 2026-09-02T02:07:03Z +**Observed runtime/source evidence through:** 2026-09-02T02:20:37Z **Purpose:** preserve facts and hard boundaries that future TFTMAC work must not casually reinterpret. This file separates durable product facts from mutable observations and historical @@ -531,9 +531,7 @@ campaign, useful for candidate selection but not current M4 runtime performance: - **VERIFIED CURRENT (2026-09-02T02:07:03Z):** Wave B source integration is complete under the append-only Wave B v4 correction authority. The default - and only launch-ready mode is `control`; `advanced_diagnostics` remains - blocked pending a separately receipted EmulatorController port, and - `candidate` remains blocked. + mode remains `control`, and `candidate` remains blocked. - **VERIFIED CURRENT:** runtime-mode registry SHA-256 is `136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479`. Runtime identity, registry/configuration hashes, AVD identity, ADB/console/ @@ -543,10 +541,21 @@ campaign, useful for candidate selection but not current M4 runtime performance: zero failures. The post-verification process audit found no active TFTMAC, emulator, or `qemu-system-aarch64` process; no runtime, AVD, installed app, or official TFT package was changed or launched by Wave B. -- **LOCKED NEXT GATE:** diagnostic first boot may occur only after a - collision-free controller port is allocated and sealed. Wave C causal-event - instrumentation remains closed until diagnostic AVD/runtime acceptance - passes. +- **VERIFIED CURRENT (2026-09-02T02:20:37Z):** diagnostic ADB `5041`, console + `5586`, and controller `8556` passed listener and exclusive-bind checks with + control stopped. A new R9 diagnostic forwarder was built from the proven + native `RuntimeHost/main.c` chain, ad-hoc signed, deep/strict verified, and + sealed under receipt SHA-256 + `3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f`. + The stale first-load host remains preserved but is not R9 launch authority. +- **VERIFIED CURRENT:** `advanced_diagnostics` is selectable only through the + explicit `TFTMAC_RUNTIME_MODE=advanced_diagnostics` environment request. Its + R9 registry SHA-256 is + `6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d`; + unsigned Release and all 49 native tests pass. Control remains the default. +- **LOCKED NEXT GATE:** guarded diagnostic first boot must prove loaded R9 QEMU + and gfxstream identities before TFT launch. Wave C causal-event + instrumentation remains closed until diagnostic AVD/runtime acceptance passes. ## 14. Explicit unknowns and open acceptance diff --git a/scripts/build-diagnostic-forwarder.command b/scripts/build-diagnostic-forwarder.command new file mode 100755 index 0000000..1b55df2 --- /dev/null +++ b/scripts/build-diagnostic-forwarder.command @@ -0,0 +1,144 @@ +#!/bin/zsh +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +readonly EXPECTED_HEAD="a84aaa7" +readonly EXPECTED_MAIN_C_SHA="c749cd998a6f066e2f7a6ef818eecf05b90d1a8808f6c9966e0b5fc21affeeed" +readonly EXPECTED_PLIST_SHA="91306c277a84a800617b2b5f20e5614795f183e2373f19309d9033530869e483" +readonly EXPECTED_PORT_RECEIPT_SHA="3536b1d54a0643bc3fcbb9dbff01be2402ca9c45d2100e220c2f857e65a129cd" +readonly DEVELOPER_DIR="/Applications/Xcode-26.6.0.app/Contents/Developer" +readonly OUTPUT_ROOT="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-forwarder-r1" +readonly APP_OUTPUT="$OUTPUT_ROOT/TFTMAC Diagnostic Forwarder.app" +readonly MANIFEST="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-forwarder-r1-native-host-build.json" + +fail() { print -u2 -- "DIAGNOSTIC_FORWARDER_BUILD_FAILED: $*"; exit 1; } +sha() { /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}'; } + +[[ "$(git rev-parse --short=7 HEAD)" == "$EXPECTED_HEAD" ]] || fail "repository head drifted" +[[ -z "$(git status --porcelain=v1 --untracked-files=no)" ]] || fail "tracked worktree must be clean" +[[ "$(sha RuntimeHost/main.c)" == "$EXPECTED_MAIN_C_SHA" ]] || fail "proven forwarder source drifted" +[[ "$(sha RuntimeHost/DiagnosticInfo.plist)" == "$EXPECTED_PLIST_SHA" ]] || fail "diagnostic plist drifted" +[[ "$(sha .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json)" == "$EXPECTED_PORT_RECEIPT_SHA" ]] || fail "port authority drifted" +[[ ! -e "$APP_OUTPUT" ]] || fail "immutable app output already exists" +[[ ! -e "$MANIFEST" && ! -e "$MANIFEST.sha256" ]] || fail "immutable build receipt already exists" + +readonly SDK_PATH="$(/usr/bin/env DEVELOPER_DIR="$DEVELOPER_DIR" /usr/bin/xcrun --sdk macosx --show-sdk-path)" +readonly CLANG="$DEVELOPER_DIR/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" +readonly TEMP_ROOT="$(/usr/bin/mktemp -d /tmp/tftmac-diagnostic-forwarder.XXXXXX)" +trap '/bin/rm -rf "$TEMP_ROOT"' EXIT +readonly TEMP_APP="$TEMP_ROOT/TFTMAC Diagnostic Forwarder.app" + +/bin/mkdir -p "$TEMP_APP/Contents/MacOS" +/bin/cp RuntimeHost/DiagnosticInfo.plist "$TEMP_APP/Contents/Info.plist" +"$CLANG" \ + -target arm64-apple-macos15.0 \ + -isysroot "$SDK_PATH" \ + -O2 -Wall -Wextra -Werror -Wno-unused-parameter \ + RuntimeHost/main.c \ + -o "$TEMP_APP/Contents/MacOS/TFTMACDiagnosticForwarder" +/usr/bin/plutil -lint "$TEMP_APP/Contents/Info.plist" >/dev/null +/usr/bin/codesign --force --sign - --timestamp=none "$TEMP_APP" +/usr/bin/codesign --verify --deep --strict --verbose=2 "$TEMP_APP" + +/bin/mkdir -p "$OUTPUT_ROOT" +/bin/mv "$TEMP_APP" "$APP_OUTPUT" + +/usr/bin/python3 - "$ROOT" "$APP_OUTPUT" "$MANIFEST" "$DEVELOPER_DIR" <<'PY' +import hashlib +import json +import os +import pathlib +import subprocess +import sys +from datetime import datetime, timezone + +root = pathlib.Path(sys.argv[1]) +app = pathlib.Path(sys.argv[2]) +manifest = pathlib.Path(sys.argv[3]) +developer_dir = pathlib.Path(sys.argv[4]) +executable = app / "Contents/MacOS/TFTMACDiagnosticForwarder" +plist = app / "Contents/Info.plist" + +def digest(path): + h = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + +uuid_output = subprocess.check_output(["/usr/bin/dwarfdump", "--uuid", str(executable)], text=True) +uuids = [] +for line in uuid_output.splitlines(): + parts = line.split() + if len(parts) >= 3 and parts[0] == "UUID:": + uuids.append(f"{parts[1]}:{parts[2].strip('()')}") + +receipt = { + "schema": 1, + "state": "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS", + "build_id": "gate4-r9-20260901", + "attempt_id": "gate4-r9-forwarder-r1", + "built_at": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"), + "source": { + "repository_root": str(root), + "head_sha": subprocess.check_output(["/usr/bin/git", "rev-parse", "HEAD"], cwd=root, text=True).strip(), + "forwarder_path": str(root / "RuntimeHost/main.c"), + "forwarder_sha256": digest(root / "RuntimeHost/main.c"), + "info_plist_path": str(root / "RuntimeHost/DiagnosticInfo.plist"), + "info_plist_sha256": digest(root / "RuntimeHost/DiagnosticInfo.plist"), + }, + "toolchain": { + "developer_dir": str(developer_dir), + "clang": str(developer_dir / "Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"), + }, + "app": { + "path": str(app), + "bundle_identifier": "com.flashls1.tftmac.runtime.diagnostic-forwarder", + "executable": { + "path": str(executable), + "sha256": digest(executable), + "size_bytes": executable.stat().st_size, + "uuids": uuids, + }, + "info_plist": { + "path": str(plist), + "sha256": digest(plist), + "size_bytes": plist.stat().st_size, + }, + "codesign_verify_status": 0, + "signing_identity": "AD_HOC", + }, + "launch_contract": { + "method": "/usr/bin/open -n -W --env ... --args ...", + "emulator_spawn_owner": "NATIVE_MACOS_APP_PROCESS", + "service_context_emulator_spawn_forbidden": True, + "forwards_tft_emulator_environment": True, + }, + "port_allocation_receipt": { + "path": str(root / ".clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json"), + "sha256": digest(root / ".clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json"), + }, + "control_runtime_mutation_attempted": False, + "runtime_launch_attempted": False, +} + +data = (json.dumps(receipt, indent=2, sort_keys=True) + "\n").encode() +manifest.parent.mkdir(parents=True, exist_ok=True) +fd = os.open(manifest, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) +with os.fdopen(fd, "wb") as handle: + handle.write(data) +manifest_sha = hashlib.sha256(data).hexdigest() +sidecar = pathlib.Path(str(manifest) + ".sha256") +fd = os.open(sidecar, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) +with os.fdopen(fd, "w") as handle: + handle.write(manifest_sha + "\n") +print(json.dumps({ + "state": receipt["state"], + "app": str(app), + "executable_sha256": receipt["app"]["executable"]["sha256"], + "manifest": str(manifest), + "manifest_sha256": manifest_sha, +}, indent=2)) +PY diff --git a/scripts/verify-diagnostic-runtime.command b/scripts/verify-diagnostic-runtime.command new file mode 100755 index 0000000..9252166 --- /dev/null +++ b/scripts/verify-diagnostic-runtime.command @@ -0,0 +1,77 @@ +#!/bin/zsh +set -euo pipefail + +readonly ROOT="${0:A:h:h}" +cd "$ROOT" + +fail() { print -u2 -- "TFTMAC diagnostic runtime preflight failed: $*"; exit 1; } +sha() { /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}'; } + +readonly REGISTRY="ssot/runtime-modes.json" +readonly MODE="advanced_diagnostics" +readonly RELEASE_APP="$ROOT/.build/native-ci-release/Build/Products/Release/TFTMAC.app" +readonly PORT_RECEIPT="$ROOT/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json" + +node .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs >/dev/null \ + || fail "source authority validation failed" +[[ -x "$RELEASE_APP/Contents/MacOS/TFTMAC" ]] || fail "verified unsigned Release app is missing" +cmp -s "$REGISTRY" "$RELEASE_APP/Contents/Resources/runtime-modes.json" \ + || fail "Release app does not package the exact diagnostic registry" + +readonly PORT_RECEIPT_SHA="$(sha "$PORT_RECEIPT")" +[[ "$PORT_RECEIPT_SHA" == "3536b1d54a0643bc3fcbb9dbff01be2402ca9c45d2100e220c2f857e65a129cd" ]] \ + || fail "diagnostic port receipt drifted" +jq -e '.state == "DIAGNOSTIC_PORT_ALLOCATION_PASS" and .ports.adb_server == 5041 and .ports.console == 5586 and .ports.controller == 8556' "$PORT_RECEIPT" >/dev/null \ + || fail "diagnostic port receipt is invalid" + +for key in build clone native_host; do + receipt="$(jq -r --arg key "$key" '.modes.advanced_diagnostics.diagnostic_receipts[$key].path' "$REGISTRY")" + expected="$(jq -r --arg key "$key" '.modes.advanced_diagnostics.diagnostic_receipts[$key].sha256' "$REGISTRY")" + required_state="$(jq -r --arg key "$key" '.modes.advanced_diagnostics.diagnostic_receipts[$key].required_state' "$REGISTRY")" + [[ -f "$receipt" && -f "$receipt.sha256" ]] || fail "sealed $key receipt is missing" + [[ "$(sha "$receipt")" == "$expected" ]] || fail "$key receipt bytes drifted" + [[ "$(awk '{print $1}' "$receipt.sha256")" == "$expected" ]] || fail "$key receipt sidecar drifted" + [[ "$(jq -r '.state' "$receipt")" == "$required_state" ]] || fail "$key receipt state drifted" +done + +for field in emulator gfxstream_backend adb avd_config avd_ini qemu; do + case "$field" in + emulator) path_key=emulator_path; sha_key=emulator_sha256 ;; + gfxstream_backend) path_key=gfxstream_backend_path; sha_key=gfxstream_backend_sha256 ;; + adb) path_key=adb_path; sha_key=adb_sha256 ;; + avd_config) path_key=avd_config_path; sha_key=avd_config_sha256 ;; + avd_ini) path_key=avd_ini_path; sha_key=avd_ini_sha256 ;; + qemu) path_key=qemu_path; sha_key=qemu_sha256 ;; + esac + artifact="$(jq -r --arg key "$path_key" '.modes.advanced_diagnostics[$key]' "$REGISTRY")" + expected="$(jq -r --arg key "$sha_key" '.modes.advanced_diagnostics[$key]' "$REGISTRY")" + [[ -f "$artifact" ]] || fail "$field artifact is missing: $artifact" + [[ "$(sha "$artifact")" == "$expected" ]] || fail "$field artifact identity drifted" +done + +readonly HOST_APP="$(jq -r '.modes.advanced_diagnostics.host_application.path' "$REGISTRY")" +readonly HOST_EXEC_REL="$(jq -r '.modes.advanced_diagnostics.host_application.executable_relative_path' "$REGISTRY")" +readonly HOST_EXEC_SHA="$(jq -r '.modes.advanced_diagnostics.host_application.executable_sha256' "$REGISTRY")" +[[ -d "$HOST_APP" && -x "$HOST_APP/$HOST_EXEC_REL" ]] || fail "diagnostic native forwarder is missing" +[[ "$(sha "$HOST_APP/$HOST_EXEC_REL")" == "$HOST_EXEC_SHA" ]] || fail "diagnostic native forwarder identity drifted" +/usr/bin/codesign --verify --deep --strict --verbose=2 "$HOST_APP" >/dev/null \ + || fail "diagnostic native forwarder signature is invalid" + +if /bin/ps -axo command= | /usr/bin/grep -F 'qemu-system-aarch64' | /usr/bin/grep -v grep >/dev/null; then + fail "an emulator is already running" +fi +for port in 5041 5586 8556; do + if /usr/sbin/lsof -nP -iTCP:"$port" -sTCP:LISTEN | /usr/bin/grep -q .; then + fail "diagnostic port $port is already listening" + fi +done + +readonly LEASE="$HOME/Library/Application Support/TFTMAC/State/native-runtime.lease" +if [[ -f "$LEASE" ]]; then + lease_pid="$(jq -r '.pid // 0' "$LEASE" 2>/dev/null || print 0)" + if [[ "$lease_pid" == <-> ]] && (( lease_pid > 0 )) && /bin/kill -0 "$lease_pid" 2>/dev/null; then + fail "runtime lease is owned by live PID $lease_pid" + fi +fi + +print "TFTMAC diagnostic runtime preflight: READY (R9 identities; ports 5041/5586/8556; control stopped)" diff --git a/scripts/verify-tftmac.command b/scripts/verify-tftmac.command index 898395d..19d24f0 100755 --- a/scripts/verify-tftmac.command +++ b/scripts/verify-tftmac.command @@ -51,6 +51,7 @@ for required in \ tftmac/Runtime/RuntimeMode.swift \ tftmac/Runtime/RuntimeModeAuthority.swift \ .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs \ + .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs \ ssot/retained-evidence-index.json \ ssot/TFTMAC_ENGINEERING_MAP.sql \ ssot/TFTMAC_PERFORMANCE_LAB.sql; do @@ -238,6 +239,7 @@ done < <(find scripts -type f \( -name '*.command' -o -name '*.sh' \) | LC_ALL=C node --check tools/tftmac-direct-control.mjs >/dev/null node --check .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs >/dev/null +node --check .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs >/dev/null [[ ! -f tools/tftmac-v2.mjs ]] || node --check tools/tftmac-v2.mjs >/dev/null node tools/tftmac-direct-control.mjs engineering-map-selftest >/dev/null node tools/tftmac-direct-control.mjs lab-selftest >/dev/null @@ -294,7 +296,7 @@ cmp -s ssot/runtime-modes.json "${RELEASE_APP}/Contents/Resources/runtime-modes. || fail "unsigned Release app did not package the exact runtime-mode registry" cmp -s ssot/runtime-authority.json "${RELEASE_APP}/Contents/Resources/runtime-authority.json" \ || fail "unsigned Release app did not package the exact control authority" -node .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs >/dev/null +node .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs >/dev/null /bin/zsh scripts/test-native-app.command @@ -304,4 +306,4 @@ cmp -s "$STATE_BEFORE" "$STATE_AFTER" || { fail "source verification changed tracked or visible generated state" } -print "TFTMAC source validation: OK (unsigned Release build; 49 native tests; Wave B mode authority PASS)" +print "TFTMAC source validation: OK (unsigned Release build; 49 native tests; diagnostic mode source authority PASS)" diff --git a/ssot/AUTHORITY_INPUTS.sha256 b/ssot/AUTHORITY_INPUTS.sha256 index 5cdc7b1..da773bd 100644 --- a/ssot/AUTHORITY_INPUTS.sha256 +++ b/ssot/AUTHORITY_INPUTS.sha256 @@ -1,7 +1,7 @@ # TFTMAC Build 8 documentation and machine-readable authority inputs # Regenerate only after reviewing the complete authority change set. -78016e5e3c7c08e263e2d8aba435f8519ae199cadc18ea74d6c39634cd0fff18 facts.md +d249f848a10b775676dd64fae68721f2c265b1d570d9557dda52c37fee0fc8ec facts.md 273307f655f0749a12a0a3e48f421f5e61bc6bd40f00b1afb7040c0b2fd15adb project.md a40e186e4d37a4e7d6024bd069a69509729eb9e6efda36a0fab12162ecf60f7e dev.md 15a33754add669bdfea2001053cbfb47df1120658be7f10022a50656fb4069c6 benchmark.md diff --git a/ssot/STACK.lock.yaml b/ssot/STACK.lock.yaml index a425daf..2bb415c 100644 --- a/ssot/STACK.lock.yaml +++ b/ssot/STACK.lock.yaml @@ -9,7 +9,7 @@ authority: documentation_authority: "facts.md + project.md + dev.md + benchmark.md" authority_inputs: "ssot/AUTHORITY_INPUTS.sha256" runtime_authority_sha256: "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" - authority_inputs_sha256: "1d85f4f2f64f3b6089c79385b329dfe42bb479b8c65877c39bf01bdef13703ac" + authority_inputs_sha256: "ae4178700439e1a42bebd1ba5cd856da0f7f8e468e306ad761f575e880b7c0b6" zengate_version: "2.3" zengate_score: 95.8 zengate_result: "PASS" diff --git a/ssot/runtime-modes.json b/ssot/runtime-modes.json index f29e550..9bd57a0 100644 --- a/ssot/runtime-modes.json +++ b/ssot/runtime-modes.json @@ -22,14 +22,14 @@ "avd_ini_sha256": "30d4ed7ebc20fb3415461fa48f6d91654955e04825de84176bd21a4adad9b98d", "avd_name": "TFTMAC_Diagnostic_API37_R9", "comparability_class": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", - "configuration_sha256": "e689fe5c46587b019a5480eabfe32453fa4986a9f6682063d53bb56d2e6aaea6", + "configuration_sha256": "08ced04cb1cd2e6ecf2880c66c5f6e45e3af64449d265d8c7e2d736aeda04009", "console_port": 5586, - "controller_port": null, + "controller_port": 8556, "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator", "emulator_sha256": "fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa", "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib", "gfxstream_backend_sha256": "23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d", - "launch_state": "blocked_pending_controller_lease", + "launch_state": "enabled", "library_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64", "mode": "advanced_diagnostics", "requires_control_stopped": true, @@ -76,14 +76,14 @@ ], "host_application": { "kind": "external_application", - "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/TFTMAC Diagnostic Host.app", - "bundle_identifier": "com.flashls1.tftmac.runtime.diagnostics", - "executable_relative_path": "Contents/MacOS/TFTMACApp", - "executable_sha256": "d335a23d710956f96a4c01f977d49437424c9fd52ccc20ed872e5786d206eef2", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-forwarder-r1/TFTMAC Diagnostic Forwarder.app", + "bundle_identifier": "com.flashls1.tftmac.runtime.diagnostic-forwarder", + "executable_relative_path": "Contents/MacOS/TFTMACDiagnosticForwarder", + "executable_sha256": "128239b2cf3ddb04669c4fda97e895e1a4a800dcf2c2144066979427d92af5b6", "source_path": null, "source_sha256": null, "info_plist_path": null, - "info_plist_sha256": "4e15592461ce8a50f17ccd6285fd12fcd84dd407eba86919f90c8c0026b5ca61", + "info_plist_sha256": "91306c277a84a800617b2b5f20e5614795f183e2373f19309d9033530869e483", "build_receipt_resource": null }, "diagnostic_receipts": { @@ -100,8 +100,8 @@ "required_state": "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS" }, "native_host": { - "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-host-r1-native-host-build.json", - "sha256": "a72d10106acb83444a38027ed3978b6ef3bc60e7ec0ae0ba9439f67eb57f6067", + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-forwarder-r1-native-host-build.json", + "sha256": "3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f", "required_state": "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS" } } diff --git a/tftmac/Runtime/RuntimeMode.swift b/tftmac/Runtime/RuntimeMode.swift index 81fd9e6..d1edaa0 100644 --- a/tftmac/Runtime/RuntimeMode.swift +++ b/tftmac/Runtime/RuntimeMode.swift @@ -280,7 +280,7 @@ struct TFTMACRuntimeSelection: Equatable, Sendable { struct TFTMACRuntimeModeRegistry: Sendable { static let environmentKey = "TFTMAC_RUNTIME_MODE" - static let expectedRegistrySha256 = "136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479" + static let expectedRegistrySha256 = "6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d" let document: TFTMACRuntimeModeRegistryDocument let registrySha256: String @@ -421,8 +421,8 @@ struct TFTMACRuntimeModeRegistry: Sendable { } let diagnostics = try required(.advancedDiagnostics, from: document) - guard diagnostics.launchState == .blockedPendingControllerLease, - diagnostics.controllerPort == nil, + guard diagnostics.launchState == .enabled, + diagnostics.controllerPort == 8556, diagnostics.avdName == "TFTMAC_Diagnostic_API37_R9", diagnostics.adbServerPort == 5041, diagnostics.consolePort == 5586, @@ -434,7 +434,7 @@ struct TFTMACRuntimeModeRegistry: Sendable { diagnostics.requiresControlStopped, diagnostics.rollbackTarget == .control else { throw TFTMACRuntimeModeError( - message: "Advanced diagnostics must remain isolated and blocked pending its controller-port receipt." + message: "Advanced diagnostics no longer matches its isolated receipted R9 authority." ) } diff --git a/tftmac/Runtime/TFTMACRuntime.swift b/tftmac/Runtime/TFTMACRuntime.swift index fd11f27..abd4d63 100644 --- a/tftmac/Runtime/TFTMACRuntime.swift +++ b/tftmac/Runtime/TFTMACRuntime.swift @@ -2767,9 +2767,9 @@ actor TFTMACRuntimeService { paths: TFTMACRuntimePaths, telemetry: TFTMACNativeTelemetry ) throws { - guard paths.launchStrategy == .bundledForwarder else { + guard paths.launchStrategy == .bundledForwarder || paths.launchStrategy == .externalNativeHost else { throw TFTMACRuntimeModeError( - message: "Runtime mode \(paths.mode.rawValue) requires its separately receipted native-host acceptance operation." + message: "Runtime mode \(paths.mode.rawValue) has no accepted native forwarder launch strategy." ) } let stdout = telemetry.captureDirectory.appendingPathComponent("emulator.stdout.log") From 521f2632e25fa8c1ebc3352eb47920ea6dcd8d6a Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 21:30:46 -0500 Subject: [PATCH 07/10] Fix diagnostic SDK root for R9 boot --- .../validate-source.mjs | 4 +++- Tests/TFTMACTests/TFTMACGate1Tests.swift | 2 ++ facts.md | 17 ++++++++++++++--- ssot/AUTHORITY_INPUTS.sha256 | 2 +- ssot/STACK.lock.yaml | 2 +- ssot/runtime-modes.json | 6 +++--- tftmac/Runtime/RuntimeMode.swift | 4 +++- 7 files changed, 27 insertions(+), 10 deletions(-) diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs index 62394ae..8a789c0 100755 --- a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs @@ -5,7 +5,7 @@ import path from 'node:path'; const root = process.cwd(); const registryPath = 'ssot/runtime-modes.json'; -const expectedRegistrySha = '6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d'; +const expectedRegistrySha = '798bad7512da1079167b120575c5c446a1ae7a5bec3030c19fc1da817dbf206b'; const expectedPortReceiptSha = '3536b1d54a0643bc3fcbb9dbff01be2402ca9c45d2100e220c2f857e65a129cd'; const expectedHostReceiptSha = '3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f'; @@ -67,6 +67,8 @@ assert(control.avd_name === 'TFT_Ultra_Tablet' && control.serial === 'emulator-5 const diagnostics = registry.modes.advanced_diagnostics; assert(diagnostics.launch_state === 'enabled', 'advanced diagnostics is not enabled'); +assert(diagnostics.sdk_root === '/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK', 'advanced diagnostic SDK root drifted'); +assert(diagnostics.adb_path === '/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb', 'advanced diagnostic ADB path drifted'); assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === 'control', 'diagnostic isolation/rollback drifted'); assert(diagnostics.avd_name === 'TFTMAC_Diagnostic_API37_R9' && diagnostics.serial === 'emulator-5586', 'diagnostic AVD identity drifted'); assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.controller_port === 8556, 'diagnostic port allocation drifted'); diff --git a/Tests/TFTMACTests/TFTMACGate1Tests.swift b/Tests/TFTMACTests/TFTMACGate1Tests.swift index e148917..e8fe75f 100644 --- a/Tests/TFTMACTests/TFTMACGate1Tests.swift +++ b/Tests/TFTMACTests/TFTMACGate1Tests.swift @@ -297,6 +297,8 @@ final class TFTMACGate1Tests: XCTestCase { XCTAssertEqual(diagnostics.definition.consolePort, 5586) XCTAssertEqual(diagnostics.definition.controllerPort, 8556) XCTAssertEqual(diagnostics.definition.serial, "emulator-5586") + XCTAssertEqual(diagnostics.definition.sdkRoot, "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK") + XCTAssertEqual(diagnostics.definition.adbPath, "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb") XCTAssertTrue(diagnostics.definition.requiresControlStopped) for requested in ["candidate", "unknown"] { XCTAssertThrowsError(try registry.selection(environment: [ diff --git a/facts.md b/facts.md index 1291314..7ee8dfe 100644 --- a/facts.md +++ b/facts.md @@ -1,7 +1,7 @@ # TFTMAC Facts **Authority date:** 2026-09-01 America/Chicago -**Observed runtime/source evidence through:** 2026-09-02T02:20:37Z +**Observed runtime/source evidence through:** 2026-09-02T02:29:46Z **Purpose:** preserve facts and hard boundaries that future TFTMAC work must not casually reinterpret. This file separates durable product facts from mutable observations and historical @@ -532,7 +532,7 @@ campaign, useful for candidate selection but not current M4 runtime performance: - **VERIFIED CURRENT (2026-09-02T02:07:03Z):** Wave B source integration is complete under the append-only Wave B v4 correction authority. The default mode remains `control`, and `candidate` remains blocked. -- **VERIFIED CURRENT:** runtime-mode registry SHA-256 is +- **VERIFIED HISTORICAL (Wave B source checkpoint):** runtime-mode registry SHA-256 was `136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479`. Runtime identity, registry/configuration hashes, AVD identity, ADB/console/ controller ports, and serial are persisted in the exclusive lease contract. @@ -551,8 +551,19 @@ campaign, useful for candidate selection but not current M4 runtime performance: - **VERIFIED CURRENT:** `advanced_diagnostics` is selectable only through the explicit `TFTMAC_RUNTIME_MODE=advanced_diagnostics` environment request. Its R9 registry SHA-256 is - `6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d`; + `798bad7512da1079167b120575c5c446a1ae7a5bec3030c19fc1da817dbf206b`; unsigned Release and all 49 native tests pass. Control remains the default. +- **VERIFIED CURRENT (first-boot attempt 1):** capture + `2026-09-02T02-23-48.444Z-9a2df80c-263a-4e10-beaa-8980d095c365` + failed before QEMU because the diagnostic registry incorrectly used the + emulator-only R9 install directory as `ANDROID_SDK_ROOT`. The forwarder and + isolated ADB server did launch, the emulator reported `Broken AVD system + path`, no QEMU process loaded, and the R9 AVD configuration was restored to + its accepted SHA-256 + `090fe426402562e227a3a1a6bd6eab9f9572cd48fbe3d467c276d419860caf90`. + The corrected registry restores the existing dedicated API 37 SDK and ADB at + `/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK`; source validation and all 49 + native tests pass after the correction. Loaded-R9 acceptance remains open. - **LOCKED NEXT GATE:** guarded diagnostic first boot must prove loaded R9 QEMU and gfxstream identities before TFT launch. Wave C causal-event instrumentation remains closed until diagnostic AVD/runtime acceptance passes. diff --git a/ssot/AUTHORITY_INPUTS.sha256 b/ssot/AUTHORITY_INPUTS.sha256 index da773bd..709eca1 100644 --- a/ssot/AUTHORITY_INPUTS.sha256 +++ b/ssot/AUTHORITY_INPUTS.sha256 @@ -1,7 +1,7 @@ # TFTMAC Build 8 documentation and machine-readable authority inputs # Regenerate only after reviewing the complete authority change set. -d249f848a10b775676dd64fae68721f2c265b1d570d9557dda52c37fee0fc8ec facts.md +3573bd6877ebddc9357644b32ed8d8565d06d42d3f3b1f87f67a4b7c58bd4b06 facts.md 273307f655f0749a12a0a3e48f421f5e61bc6bd40f00b1afb7040c0b2fd15adb project.md a40e186e4d37a4e7d6024bd069a69509729eb9e6efda36a0fab12162ecf60f7e dev.md 15a33754add669bdfea2001053cbfb47df1120658be7f10022a50656fb4069c6 benchmark.md diff --git a/ssot/STACK.lock.yaml b/ssot/STACK.lock.yaml index 2bb415c..5fe4d10 100644 --- a/ssot/STACK.lock.yaml +++ b/ssot/STACK.lock.yaml @@ -9,7 +9,7 @@ authority: documentation_authority: "facts.md + project.md + dev.md + benchmark.md" authority_inputs: "ssot/AUTHORITY_INPUTS.sha256" runtime_authority_sha256: "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" - authority_inputs_sha256: "ae4178700439e1a42bebd1ba5cd856da0f7f8e468e306ad761f575e880b7c0b6" + authority_inputs_sha256: "2bcb0c0c7c4858b1090ce22491bb344756085f2f6ebb17c0cb73840fb3df6a38" zengate_version: "2.3" zengate_score: 95.8 zengate_result: "PASS" diff --git a/ssot/runtime-modes.json b/ssot/runtime-modes.json index 9bd57a0..7ad6f05 100644 --- a/ssot/runtime-modes.json +++ b/ssot/runtime-modes.json @@ -3,7 +3,7 @@ "default_mode": "control", "modes": { "advanced_diagnostics": { - "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb", + "adb_path": "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb", "adb_server_port": 5041, "allowed_purpose": "ISOLATED_SOURCE_INSTRUMENTATION_AND_ELIGIBILITY", "application_build": "8", @@ -22,7 +22,7 @@ "avd_ini_sha256": "30d4ed7ebc20fb3415461fa48f6d91654955e04825de84176bd21a4adad9b98d", "avd_name": "TFTMAC_Diagnostic_API37_R9", "comparability_class": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", - "configuration_sha256": "08ced04cb1cd2e6ecf2880c66c5f6e45e3af64449d265d8c7e2d736aeda04009", + "configuration_sha256": "1c7b33f3b32a530fff0ba79aedeb82001f392295ebd538a516374fff5db7f903", "console_port": 5586, "controller_port": 8556, "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator", @@ -35,7 +35,7 @@ "requires_control_stopped": true, "rollback_target": "control", "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1", - "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK", "serial": "emulator-5586", "state_namespace": "advanced_diagnostics", "uses_legacy_application_support_root": false, diff --git a/tftmac/Runtime/RuntimeMode.swift b/tftmac/Runtime/RuntimeMode.swift index d1edaa0..d335ed9 100644 --- a/tftmac/Runtime/RuntimeMode.swift +++ b/tftmac/Runtime/RuntimeMode.swift @@ -280,7 +280,7 @@ struct TFTMACRuntimeSelection: Equatable, Sendable { struct TFTMACRuntimeModeRegistry: Sendable { static let environmentKey = "TFTMAC_RUNTIME_MODE" - static let expectedRegistrySha256 = "6fb1861abcf6d3fb711e8a730163fc0325b7cae3b1730076bbae9145bf8e9c3d" + static let expectedRegistrySha256 = "798bad7512da1079167b120575c5c446a1ae7a5bec3030c19fc1da817dbf206b" let document: TFTMACRuntimeModeRegistryDocument let registrySha256: String @@ -423,6 +423,8 @@ struct TFTMACRuntimeModeRegistry: Sendable { let diagnostics = try required(.advancedDiagnostics, from: document) guard diagnostics.launchState == .enabled, diagnostics.controllerPort == 8556, + diagnostics.sdkRoot == "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK", + diagnostics.adbPath == "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb", diagnostics.avdName == "TFTMAC_Diagnostic_API37_R9", diagnostics.adbServerPort == 5041, diagnostics.consolePort == 5586, From a325cda426f6581cc1dfdfdc8d2805b58ea7dcf3 Mon Sep 17 00:00:00 2001 From: flashls1 Date: Tue, 1 Sep 2026 21:33:38 -0500 Subject: [PATCH 08/10] Gate emulator flags by runtime version --- .../diagnostic-first-boot-v1/validate-source.mjs | 1 + tftmac/Runtime/TFTMACRuntime.swift | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs index 8a789c0..f989c4d 100755 --- a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs @@ -90,6 +90,7 @@ const runtimeModeSource = readText('tftmac/Runtime/RuntimeMode.swift'); assert(runtimeModeSource.includes(`static let expectedRegistrySha256 = "${expectedRegistrySha}"`), 'Swift registry pin drifted'); const runtimeSource = readText('tftmac/Runtime/TFTMACRuntime.swift'); assert(runtimeSource.includes('paths.launchStrategy == .bundledForwarder || paths.launchStrategy == .externalNativeHost'), 'runtime does not accept the receipted external native host'); +assert(runtimeSource.includes('if paths.mode == .control {\n arguments += ["-crash-report-mode", "disabled"]'), 'R9-incompatible crash-report flag is not isolated to control'); const tests = readText('Tests/TFTMACTests/TFTMACGate1Tests.swift'); assert(tests.includes('testRuntimeModeRegistrySelectsReceiptedDiagnosticsAndRejectsUnacceptedModes'), 'diagnostic selection contract test is missing'); diff --git a/tftmac/Runtime/TFTMACRuntime.swift b/tftmac/Runtime/TFTMACRuntime.swift index abd4d63..fbb2371 100644 --- a/tftmac/Runtime/TFTMACRuntime.swift +++ b/tftmac/Runtime/TFTMACRuntime.swift @@ -2812,10 +2812,13 @@ actor TFTMACRuntimeService { "-dns-server", "1.1.1.1,8.8.8.8", "-cores", "\(profile.vCPU)", "-memory", "\(profile.ramMiB)", "-no-hidpi-scaling", "-no-snapshot", "-no-metrics", "-no-boot-anim", - "-crash-report-mode", "disabled", "-qt-hide-window", + "-qt-hide-window", "-grpc", "\(paths.controllerPort)", "-grpc-use-token", "-idle-grpc-timeout", "300" ] + if paths.mode == .control { + arguments += ["-crash-report-mode", "disabled"] + } if let zone = TimeZone.current.identifier.addingPercentEncoding(withAllowedCharacters: .alphanumerics), !zone.isEmpty { arguments += ["-timezone", TimeZone.current.identifier] } From 9220cdf497b0ce516e45296758e96d53308b2f58 Mon Sep 17 00:00:00 2001 From: flashls1 Date: Wed, 2 Sep 2026 09:19:17 -0500 Subject: [PATCH 09/10] Recover DEV baseline and checkpoint causal graphics work --- .../validate-source.mjs | 25 +- CausalRuntime/PipelineEventV1.cpp | 210 ++++ CausalRuntime/PipelineEventV1.h | 95 ++ CausalRuntime/PipelineEventV1_test.cpp | 59 ++ ControlLauncher/Info.plist | 30 + ControlLauncher/main.swift | 162 +++ DevLauncher/main.c | 63 ++ Probes/TFTMACVulkanProbe/AndroidManifest.xml | 21 + Probes/TFTMACVulkanProbe/shaders/probe.frag | 13 + Probes/TFTMACVulkanProbe/shaders/probe.vert | 13 + Probes/TFTMACVulkanProbe/src/main.cpp | 959 ++++++++++++++++++ .../TFTMACVulkanProbe/workload-manifest.json | 18 + TFTMAC.xcodeproj/project.pbxproj | 9 +- Tests/TFTMACTests/TFTMACGate1Tests.swift | 137 ++- benchmark.md | 71 +- dev.md | 76 +- facts.md | 313 +++++- project.md | 108 +- .../analyze-vulkan-experiment-campaign.mjs | 242 +++++ scripts/build-causal-stock-runtime.command | 48 + scripts/build-control-launcher.command | 60 ++ scripts/build-dev-launcher.command | 128 +++ scripts/build-stock-shadow-runtime.command | 172 ++++ scripts/build-vulkan-probe.command | 131 +++ scripts/install-desktop-launchers.command | 61 ++ scripts/prepare-causal-source-runtime.command | 89 ++ .../run-vulkan-experiment-campaign.command | 133 +++ scripts/setup-android-unlock.command | 21 + scripts/sign-apk-v2.mjs | 132 +++ scripts/test-causal-runtime.command | 15 + scripts/verify-diagnostic-runtime.command | 2 +- scripts/verify-tftmac.command | 65 +- ssot/AUTHORITY_INPUTS.sha256 | 14 +- ssot/STACK.lock.yaml | 88 +- ssot/TFTMAC_ENGINEERING_MAP.sql | 22 +- ssot/TFTMAC_PERFORMANCE_LAB.sql | 14 +- ssot/runtime-authority.json | 35 +- ssot/runtime-modes.json | 87 +- tftmac/App/AppCoordinator.swift | 14 + tftmac/Assets/TFTMAC-DEV-Icon.png | Bin 0 -> 2743913 bytes tftmac/Runtime/GameFrameTelemetry.swift | 19 +- tftmac/Runtime/GuestUnlockSecret.swift | 148 +++ tftmac/Runtime/RuntimeMode.swift | 11 +- tftmac/Runtime/RuntimeModeAuthority.swift | 61 +- tftmac/Runtime/RuntimeProfile.swift | 117 ++- tftmac/Runtime/TFTMACRuntime.swift | 568 ++++++++++- .../Runtime/TelemetrySignalClassifier.swift | 229 +++++ 47 files changed, 4866 insertions(+), 242 deletions(-) create mode 100644 CausalRuntime/PipelineEventV1.cpp create mode 100644 CausalRuntime/PipelineEventV1.h create mode 100644 CausalRuntime/PipelineEventV1_test.cpp create mode 100644 ControlLauncher/Info.plist create mode 100644 ControlLauncher/main.swift create mode 100644 DevLauncher/main.c create mode 100644 Probes/TFTMACVulkanProbe/AndroidManifest.xml create mode 100644 Probes/TFTMACVulkanProbe/shaders/probe.frag create mode 100644 Probes/TFTMACVulkanProbe/shaders/probe.vert create mode 100644 Probes/TFTMACVulkanProbe/src/main.cpp create mode 100644 Probes/TFTMACVulkanProbe/workload-manifest.json create mode 100755 scripts/analyze-vulkan-experiment-campaign.mjs create mode 100755 scripts/build-causal-stock-runtime.command create mode 100755 scripts/build-control-launcher.command create mode 100755 scripts/build-dev-launcher.command create mode 100755 scripts/build-stock-shadow-runtime.command create mode 100755 scripts/build-vulkan-probe.command create mode 100755 scripts/install-desktop-launchers.command create mode 100755 scripts/prepare-causal-source-runtime.command create mode 100755 scripts/run-vulkan-experiment-campaign.command create mode 100644 scripts/setup-android-unlock.command create mode 100755 scripts/sign-apk-v2.mjs create mode 100755 scripts/test-causal-runtime.command create mode 100644 tftmac/Assets/TFTMAC-DEV-Icon.png create mode 100644 tftmac/Runtime/GuestUnlockSecret.swift diff --git a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs index f989c4d..e038b3b 100755 --- a/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs +++ b/.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs @@ -5,9 +5,9 @@ import path from 'node:path'; const root = process.cwd(); const registryPath = 'ssot/runtime-modes.json'; -const expectedRegistrySha = '798bad7512da1079167b120575c5c446a1ae7a5bec3030c19fc1da817dbf206b'; +const expectedRegistrySha = 'f92cfc78923814d8eb3d8f6f550a4763ba918fe5e1c20088e2863d89ce58eafe'; const expectedPortReceiptSha = '3536b1d54a0643bc3fcbb9dbff01be2402ca9c45d2100e220c2f857e65a129cd'; -const expectedHostReceiptSha = '3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f'; +const expectedStockShadowReceiptSha = '540f57f762d67b894916a96adc2c0836aec803a8af9cba988b8b5df94ddde285'; function absolute(relativePath) { return path.join(root, relativePath); } function read(relativePath) { return fs.readFileSync(absolute(relativePath)); } @@ -42,6 +42,7 @@ for (const required of [ '.clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/PORT_ALLOCATION_RECEIPT.json', 'RuntimeHost/DiagnosticInfo.plist', 'scripts/build-diagnostic-forwarder.command', + 'scripts/build-stock-shadow-runtime.command', registryPath, 'tftmac/Runtime/RuntimeMode.swift', 'tftmac/Runtime/RuntimeModeAuthority.swift', @@ -62,22 +63,30 @@ for (const mode of Object.values(registry.modes)) { const control = registry.modes.control; assert(control.launch_state === 'enabled', 'control is not enabled'); +assert(control.application_bundle_id === 'com.flashls1.tftmac', 'control app identity drifted'); assert(control.adb_server_port === 5038 && control.console_port === 5582 && control.controller_port === 8554, 'control ports drifted'); assert(control.avd_name === 'TFT_Ultra_Tablet' && control.serial === 'emulator-5582', 'control identity drifted'); const diagnostics = registry.modes.advanced_diagnostics; assert(diagnostics.launch_state === 'enabled', 'advanced diagnostics is not enabled'); -assert(diagnostics.sdk_root === '/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK', 'advanced diagnostic SDK root drifted'); -assert(diagnostics.adb_path === '/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb', 'advanced diagnostic ADB path drifted'); +assert(diagnostics.application_bundle_id === 'com.flashls1.tftmac.dev', 'advanced diagnostic app identity drifted'); +assert(diagnostics.adb_vendor_keys_policy === 'USER_DEFAULT_KEY', 'advanced diagnostic ADB-auth policy drifted'); +assert(diagnostics.runtime_variant === 'stock_shadow', 'advanced diagnostic runtime variant drifted'); +assert(diagnostics.sdk_root === '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK', 'advanced diagnostic SDK root drifted'); +assert(diagnostics.adb_path === '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/platform-tools/adb', 'advanced diagnostic ADB path drifted'); assert(diagnostics.requires_control_stopped === true && diagnostics.rollback_target === 'control', 'diagnostic isolation/rollback drifted'); -assert(diagnostics.avd_name === 'TFTMAC_Diagnostic_API37_R9' && diagnostics.serial === 'emulator-5586', 'diagnostic AVD identity drifted'); +assert(diagnostics.avd_name === 'TFTMAC_Diagnostic_StockShadow_R1' && diagnostics.serial === 'emulator-5586', 'diagnostic AVD identity drifted'); assert(diagnostics.adb_server_port === 5041 && diagnostics.console_port === 5586 && diagnostics.controller_port === 8556, 'diagnostic port allocation drifted'); assert(diagnostics.launch_strategy === 'external_native_host', 'diagnostic launch strategy drifted'); assert(diagnostics.host_application?.path === '/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-forwarder-r1/TFTMAC Diagnostic Forwarder.app', 'diagnostic host path drifted'); assert(diagnostics.host_application?.bundle_identifier === 'com.flashls1.tftmac.runtime.diagnostic-forwarder', 'diagnostic host bundle identity drifted'); assert(diagnostics.host_application?.executable_relative_path === 'Contents/MacOS/TFTMACDiagnosticForwarder', 'diagnostic host executable path drifted'); assert(diagnostics.host_application?.executable_sha256 === '128239b2cf3ddb04669c4fda97e895e1a4a800dcf2c2144066979427d92af5b6', 'diagnostic host executable identity drifted'); -assert(diagnostics.diagnostic_receipts?.native_host?.sha256 === expectedHostReceiptSha, 'diagnostic host receipt reference drifted'); +assert(diagnostics.diagnostic_receipts?.build_id === 'stock-shadow-r1-20260902', 'stock-shadow build identity drifted'); +for (const receipt of Object.values(diagnostics.diagnostic_receipts ?? {}).filter((value) => value && typeof value === 'object')) { + assert(receipt.sha256 === expectedStockShadowReceiptSha, 'stock-shadow receipt reference drifted'); + assert(receipt.required_state === 'STOCK_SHADOW_RUNTIME_IDENTITY_PASS', 'stock-shadow receipt state drifted'); +} const candidate = registry.modes.candidate; assert(candidate.launch_state === 'blocked_not_built' && candidate.controller_port === null, 'candidate is not fail-closed'); @@ -90,14 +99,14 @@ const runtimeModeSource = readText('tftmac/Runtime/RuntimeMode.swift'); assert(runtimeModeSource.includes(`static let expectedRegistrySha256 = "${expectedRegistrySha}"`), 'Swift registry pin drifted'); const runtimeSource = readText('tftmac/Runtime/TFTMACRuntime.swift'); assert(runtimeSource.includes('paths.launchStrategy == .bundledForwarder || paths.launchStrategy == .externalNativeHost'), 'runtime does not accept the receipted external native host'); -assert(runtimeSource.includes('if paths.mode == .control {\n arguments += ["-crash-report-mode", "disabled"]'), 'R9-incompatible crash-report flag is not isolated to control'); +assert(runtimeSource.includes('if paths.expectedEmulatorVersionContains == "37.1.11" {\n arguments += ["-crash-report-mode", "disabled"]'), '37.1.11 Control/shadow crash-report consent suppression drifted'); const tests = readText('Tests/TFTMACTests/TFTMACGate1Tests.swift'); assert(tests.includes('testRuntimeModeRegistrySelectsReceiptedDiagnosticsAndRejectsUnacceptedModes'), 'diagnostic selection contract test is missing'); const testCount = fs.readdirSync(absolute('Tests/TFTMACTests')) .filter((name) => name.endsWith('.swift')) .reduce((total, name) => total + (readText(`Tests/TFTMACTests/${name}`).match(/^ func test/gm) ?? []).length, 0); -assert(testCount === 49, `expected 49 native tests, found ${testCount}`); +assert(testCount === 54, `expected 54 native tests, found ${testCount}`); console.log(JSON.stringify({ state: 'DIAGNOSTIC_FIRST_BOOT_SOURCE_PASS', diff --git a/CausalRuntime/PipelineEventV1.cpp b/CausalRuntime/PipelineEventV1.cpp new file mode 100644 index 0000000..93eb55c --- /dev/null +++ b/CausalRuntime/PipelineEventV1.cpp @@ -0,0 +1,210 @@ +#include "PipelineEventV1.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace tftmac::causal { +namespace { + +constexpr size_t kCapacity = 256; +constexpr uint64_t kSegmentDurationNs = 60ULL * 1000ULL * 1000ULL * 1000ULL; + +uint64_t MonotonicNowNs() { + timespec value{}; + if (clock_gettime(CLOCK_MONOTONIC_RAW, &value) != 0) return 0; + return static_cast(value.tv_sec) * 1000000000ULL + + static_cast(value.tv_nsec); +} + +uint64_t CurrentThreadId() { + uint64_t thread_id = 0; + if (pthread_threadid_np(nullptr, &thread_id) != 0) return 0; + return thread_id; +} + +std::array Sha256(const void* bytes, size_t byte_count) { + std::array digest{}; + CC_SHA256(bytes, static_cast(byte_count), digest.data()); + return digest; +} + +bool WriteAll(int descriptor, const void* bytes, size_t byte_count) { + const auto* cursor = static_cast(bytes); + while (byte_count > 0) { + const ssize_t written = write(descriptor, cursor, byte_count); + if (written < 0 && errno == EINTR) continue; + if (written <= 0) return false; + cursor += written; + byte_count -= static_cast(written); + } + return true; +} + +struct ThreadRecorder { + PipelineEventV1 events[kCapacity]{}; + size_t count = 0; + uint64_t overwrite_count = 0; + uint64_t loss_count = 0; + uint64_t sequence = 0; + uint64_t segment_started_ns = 0; + uint64_t transport_work_id = 0; + uint64_t present_lineage_id = 0; + uint32_t lineage_generation = 0; + std::array previous_segment_sha256{}; + int descriptor = -1; + bool enabled = false; + + ThreadRecorder() { + const char* enabled_value = std::getenv("TFTMAC_PIPELINE_EVENT_V1"); + const char* directory = std::getenv("TFTMAC_PIPELINE_EVENTS_DIR"); + if (!enabled_value || std::strcmp(enabled_value, "1") != 0 || !directory || !*directory) return; + struct stat directory_stat {}; + if (stat(directory, &directory_stat) != 0 || !S_ISDIR(directory_stat.st_mode)) return; + char path[PATH_MAX]{}; + const int length = std::snprintf( + path, + sizeof(path), + "%s/pipeline-%d-%llu.bin", + directory, + getpid(), + static_cast(CurrentThreadId())); + if (length <= 0 || static_cast(length) >= sizeof(path)) return; + descriptor = open(path, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, S_IRUSR | S_IWUSR); + enabled = descriptor >= 0; + segment_started_ns = MonotonicNowNs(); + } + + ~ThreadRecorder() { + Flush(); + if (descriptor >= 0) close(descriptor); + } + + void Append(const PipelineEventV1& event) { + if (!enabled) return; + if (count == kCapacity) Flush(); + if (count == kCapacity) { + ++overwrite_count; + return; + } + events[count++] = event; + if (event.timestamp_ns - segment_started_ns >= kSegmentDurationNs) Flush(); + } + + void Flush() { + if (!enabled || count == 0) return; + const size_t payload_bytes = count * sizeof(PipelineEventV1); + PipelineSegmentHeaderV1 header{}; + header.magic = {'T', 'F', 'T', 'P', 'I', 'P', 'E', '1'}; + header.schema_version = 1; + header.header_bytes = sizeof(PipelineSegmentHeaderV1); + header.event_count = static_cast(count); + header.segment_sequence = sequence; + header.started_ns = segment_started_ns; + header.ended_ns = events[count - 1].timestamp_ns; + header.overwrite_count = overwrite_count; + header.loss_count = loss_count; + header.previous_segment_sha256 = previous_segment_sha256; + header.payload_sha256 = Sha256(events, payload_bytes); + + std::array chain_input{}; + std::memcpy(chain_input.data(), header.previous_segment_sha256.data(), 32); + std::memcpy(chain_input.data() + 32, header.payload_sha256.data(), 32); + std::memcpy(chain_input.data() + 64, &header.segment_sequence, 8); + std::memcpy(chain_input.data() + 72, &header.started_ns, 8); + std::memcpy(chain_input.data() + 80, &header.ended_ns, 8); + header.segment_sha256 = Sha256(chain_input.data(), chain_input.size()); + + if (!WriteAll(descriptor, &header, sizeof(header)) || + !WriteAll(descriptor, events, payload_bytes)) { + ++loss_count; + } else { + previous_segment_sha256 = header.segment_sha256; + ++sequence; + } + count = 0; + segment_started_ns = MonotonicNowNs(); + } +}; + +thread_local ThreadRecorder g_recorder; + +} // namespace + +bool ParseOwnedProbeTransportLabel(const char* label, uint64_t* transport_work_id) { + if (!label || !transport_work_id) return false; + constexpr char prefix[] = "TFTMAC/"; + if (std::strncmp(label, prefix, sizeof(prefix) - 1) != 0) return false; + const char* final_slash = std::strrchr(label, '/'); + if (!final_slash || final_slash == label || !final_slash[1]) return false; + uint64_t value = 0; + for (const char* cursor = final_slash + 1; *cursor; ++cursor) { + if (*cursor < '0' || *cursor > '9') return false; + const uint64_t digit = static_cast(*cursor - '0'); + if (value > (std::numeric_limits::max() - digit) / 10) return false; + value = value * 10 + digit; + } + *transport_work_id = value; + return true; +} + +void SetThreadTransportWorkId(uint64_t transport_work_id) { + g_recorder.transport_work_id = transport_work_id; +} + +void ClearThreadTransportWorkId() { + g_recorder.transport_work_id = 0; +} + +void SetThreadPresentLineage(uint64_t present_lineage_id, uint32_t generation) { + g_recorder.present_lineage_id = present_lineage_id; + g_recorder.lineage_generation = generation; +} + +void ClearThreadPresentLineage() { + g_recorder.present_lineage_id = 0; + g_recorder.lineage_generation = 0; +} + +void Record( + EventKind kind, + Boundary boundary, + uint32_t source_site_id, + uint64_t duration_ns, + uint32_t queue_depth, + uint16_t flags, + const uint8_t* payload_sha256) { + if (!g_recorder.enabled) return; + PipelineEventV1 event{}; + event.schema_version = 1; + event.event_kind = static_cast(kind); + event.boundary = static_cast(boundary); + event.flags = flags; + event.process_id = static_cast(getpid()); + event.thread_id = CurrentThreadId(); + event.timestamp_ns = MonotonicNowNs(); + event.transport_work_id = g_recorder.transport_work_id; + event.present_lineage_id = g_recorder.present_lineage_id; + event.lineage_generation = g_recorder.lineage_generation; + event.source_site_id = source_site_id; + event.queue_depth = queue_depth; + event.duration_ns = duration_ns; + if (payload_sha256) std::memcpy(event.payload_sha256.data(), payload_sha256, 32); + g_recorder.Append(event); +} + +void FlushCurrentThread() { g_recorder.Flush(); } +uint64_t CurrentThreadOverwriteCount() { return g_recorder.overwrite_count; } +uint64_t CurrentThreadLossCount() { return g_recorder.loss_count; } + +} // namespace tftmac::causal diff --git a/CausalRuntime/PipelineEventV1.h b/CausalRuntime/PipelineEventV1.h new file mode 100644 index 0000000..43015ee --- /dev/null +++ b/CausalRuntime/PipelineEventV1.h @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include + +namespace tftmac::causal { + +enum class EventKind : uint16_t { + kBegin = 1, + kEnd = 2, + kInstant = 3, + kLoss = 4, +}; + +enum class Boundary : uint16_t { + kGuestProbeSubmit = 1, + kAsgHostReceive = 2, + kGfxstreamDecode = 3, + kHostVulkanQueueLock = 4, + kHostVulkanSubmit = 5, + kMoltenVKPipelineLookup = 6, + kMoltenVKPipelineCreate = 7, + kMoltenVKEnqueue = 8, + kMetalCommit = 9, + kMetalScheduled = 10, + kMetalGpuStart = 11, + kMetalGpuComplete = 12, + kColorBufferPublish = 13, + kSourceFramePublish = 14, + kSurfaceFlingerPresent = 15, +}; + +#pragma pack(push, 1) +struct PipelineEventV1 { + uint16_t schema_version; + uint16_t event_kind; + uint16_t boundary; + uint16_t flags; + uint32_t process_id; + uint64_t thread_id; + uint64_t timestamp_ns; + uint64_t transport_work_id; + uint64_t present_lineage_id; + uint32_t lineage_generation; + uint32_t source_site_id; + uint32_t queue_depth; + uint64_t duration_ns; + std::array payload_sha256; +}; + +struct PipelineSegmentHeaderV1 { + std::array magic; + uint16_t schema_version; + uint16_t header_bytes; + uint32_t event_count; + uint64_t segment_sequence; + uint64_t started_ns; + uint64_t ended_ns; + uint64_t overwrite_count; + uint64_t loss_count; + std::array previous_segment_sha256; + std::array payload_sha256; + std::array segment_sha256; +}; +#pragma pack(pop) + +static_assert(sizeof(PipelineEventV1) == 96, "PipelineEventV1 ABI drift"); + +// Exact parser for labels emitted by the owned probe: +// TFTMAC/// +bool ParseOwnedProbeTransportLabel(const char* label, uint64_t* transport_work_id); + +void SetThreadTransportWorkId(uint64_t transport_work_id); +void ClearThreadTransportWorkId(); +void SetThreadPresentLineage(uint64_t present_lineage_id, uint32_t generation); +void ClearThreadPresentLineage(); + +// The append path is fixed-capacity and allocation-free. Recording is disabled +// unless TFTMAC_PIPELINE_EVENTS_DIR names an existing private directory and +// TFTMAC_PIPELINE_EVENT_V1=1 is present in the emulator-host environment. +void Record( + EventKind kind, + Boundary boundary, + uint32_t source_site_id, + uint64_t duration_ns = 0, + uint32_t queue_depth = 0, + uint16_t flags = 0, + const uint8_t* payload_sha256 = nullptr); + +void FlushCurrentThread(); +uint64_t CurrentThreadOverwriteCount(); +uint64_t CurrentThreadLossCount(); + +} // namespace tftmac::causal diff --git a/CausalRuntime/PipelineEventV1_test.cpp b/CausalRuntime/PipelineEventV1_test.cpp new file mode 100644 index 0000000..666ad16 --- /dev/null +++ b/CausalRuntime/PipelineEventV1_test.cpp @@ -0,0 +1,59 @@ +#include "PipelineEventV1.h" + +#include +#include +#include +#include +#include +#include +#include + +int main() { + using tftmac::causal::ParseOwnedProbeTransportLabel; + uint64_t value = 0; + assert(sizeof(tftmac::causal::PipelineEventV1) == 96); + assert(ParseOwnedProbeTransportLabel("TFTMAC/control/stable_descriptor_draw/184467", &value)); + assert(value == 184467); + assert(!ParseOwnedProbeTransportLabel("TFTMAC/control/stable_descriptor_draw/not-a-number", &value)); + assert(!ParseOwnedProbeTransportLabel("Riot/control/stable_descriptor_draw/1", &value)); + assert(!ParseOwnedProbeTransportLabel("TFTMAC/control/stable_descriptor_draw/18446744073709551616", &value)); + + const auto directory = std::filesystem::temp_directory_path() / + ("tftmac-pipeline-event-test-" + std::to_string(getpid())); + assert(std::filesystem::create_directory(directory)); + assert(setenv("TFTMAC_PIPELINE_EVENT_V1", "1", 1) == 0); + assert(setenv("TFTMAC_PIPELINE_EVENTS_DIR", directory.c_str(), 1) == 0); + tftmac::causal::SetThreadTransportWorkId(44); + for (uint32_t index = 0; index < 257; ++index) { + tftmac::causal::Record( + tftmac::causal::EventKind::kInstant, + tftmac::causal::Boundary::kGfxstreamDecode, + 1001, + index, + index % 3); + } + tftmac::causal::FlushCurrentThread(); + assert(tftmac::causal::CurrentThreadOverwriteCount() == 0); + assert(tftmac::causal::CurrentThreadLossCount() == 0); + + std::filesystem::path segment_path; + for (const auto& entry : std::filesystem::directory_iterator(directory)) { + if (entry.path().extension() == ".bin") segment_path = entry.path(); + } + assert(!segment_path.empty()); + std::ifstream stream(segment_path, std::ios::binary); + tftmac::causal::PipelineSegmentHeaderV1 first{}; + tftmac::causal::PipelineSegmentHeaderV1 second{}; + stream.read(reinterpret_cast(&first), sizeof(first)); + const std::array expected_magic{'T', 'F', 'T', 'P', 'I', 'P', 'E', '1'}; + assert(first.magic == expected_magic); + assert(first.event_count == 256); + stream.seekg(static_cast(256 * sizeof(tftmac::causal::PipelineEventV1)), std::ios::cur); + stream.read(reinterpret_cast(&second), sizeof(second)); + assert(second.event_count == 1); + assert(second.previous_segment_sha256 == first.segment_sha256); + stream.close(); + std::filesystem::remove(segment_path); + std::filesystem::remove(directory); + return 0; +} diff --git a/ControlLauncher/Info.plist b/ControlLauncher/Info.plist new file mode 100644 index 0000000..e0d293a --- /dev/null +++ b/ControlLauncher/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + TFTMAC + CFBundleExecutable + TFTMACControlLauncher + CFBundleIconFile + TFTMAC-Official.icns + CFBundleIdentifier + com.flashls1.tftmac.control-launcher + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + TFTMAC + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 15.0 + LSUIElement + + + diff --git a/ControlLauncher/main.swift b/ControlLauncher/main.swift new file mode 100644 index 0000000..0d1fd2c --- /dev/null +++ b/ControlLauncher/main.swift @@ -0,0 +1,162 @@ +import AppKit +import Foundation + +private enum ControlLauncherError: LocalizedError { + case missingControl + case missingADB + case launchFailed(String) + case adbUnavailable(String) + case unlockRejected + + var errorDescription: String? { + switch self { + case .missingControl: + return "The protected Control app is missing from /Applications/TFTMAC.app." + case .missingADB: + return "The protected Control ADB executable is missing." + case .launchFailed(let detail): + return "The protected Control app could not be launched: \(detail)" + case .adbUnavailable(let state): + return "Control did not reach authorized ADB device state on emulator-5582 (last state: \(state))." + case .unlockRejected: + return "Android did not accept the saved unlock PIN after two bounded attempts." + } + } +} + +private struct CommandResult { + let status: Int32 + let output: String +} + +@main +@MainActor +struct TFTMACControlLauncher { + private static let controlApp = URL(fileURLWithPath: "/Applications/TFTMAC.app", isDirectory: true) + private static let adb = URL(fileURLWithPath: "/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/platform-tools/adb") + private static let adbPort = "5038" + private static let serial = "emulator-5582" + + static func main() { + let app = NSApplication.shared + app.setActivationPolicy(.accessory) + do { + let secret = try TFTMACGuestUnlockSecretStore.loadOrPrompt(applicationName: "TFTMAC") + try launchProtectedControlIfNeeded() + try waitForAuthorizedDevice() + try unlockIfNeeded(secret: secret) + } catch { + showError(error.localizedDescription) + } + } + + private static func launchProtectedControlIfNeeded() throws { + guard FileManager.default.fileExists(atPath: controlApp.path) else { + throw ControlLauncherError.missingControl + } + if !NSRunningApplication.runningApplications(withBundleIdentifier: "com.flashls1.tftmac").isEmpty { + return + } + let result = try run( + executable: URL(fileURLWithPath: "/usr/bin/open"), + arguments: ["-n", controlApp.path], + timeout: 30 + ) + guard result.status == 0 else { + throw ControlLauncherError.launchFailed(result.output) + } + } + + private static func waitForAuthorizedDevice() throws { + guard FileManager.default.isExecutableFile(atPath: adb.path) else { + throw ControlLauncherError.missingADB + } + let deadline = Date().addingTimeInterval(300) + var state = "missing" + while Date() < deadline { + let result = try runADB(["get-state"], timeout: 10) + state = result.output.trimmingCharacters(in: .whitespacesAndNewlines) + if result.status == 0, state == "device" { return } + Thread.sleep(forTimeInterval: 1) + } + throw ControlLauncherError.adbUnavailable(state) + } + + private static func unlockIfNeeded(secret: TFTMACGuestUnlockSecret) throws { + for attempt in 0..<3 { + let user = try runADB(["shell", "dumpsys", "user"], timeout: 15) + if user.output.contains("RUNNING_UNLOCKED") { return } + if attempt == 2 { break } + try sendUnlockOverStandardInput(secret: secret) + Thread.sleep(forTimeInterval: 5) + } + throw ControlLauncherError.unlockRejected + } + + private static func sendUnlockOverStandardInput(secret: TFTMACGuestUnlockSecret) throws { + let process = Process() + process.executableURL = adb + process.arguments = ["-P", adbPort, "-s", serial, "shell"] + let input = Pipe() + let output = Pipe() + process.standardInput = input + process.standardOutput = output + process.standardError = output + try process.run() + + var command = Data("input keyevent KEYCODE_WAKEUP\ninput keyevent KEYCODE_ENTER\n".utf8) + let pin = try secret.transientPIN() + for scalar in pin.unicodeScalars { + command.append(Data("input keyevent KEYCODE_\(scalar)\n".utf8)) + } + command.append(Data("input keyevent KEYCODE_ENTER\nexit\n".utf8)) + try input.fileHandleForWriting.write(contentsOf: command) + command.resetBytes(in: 0.. CommandResult { + try run(executable: adb, arguments: ["-P", adbPort, "-s", serial] + arguments, timeout: timeout) + } + + private static func run( + executable: URL, + arguments: [String], + timeout: TimeInterval + ) throws -> CommandResult { + let process = Process() + process.executableURL = executable + process.arguments = arguments + let output = Pipe() + process.standardOutput = output + process.standardError = output + try process.run() + let deadline = Date().addingTimeInterval(timeout) + while process.isRunning, Date() < deadline { + Thread.sleep(forTimeInterval: 0.05) + } + if process.isRunning { + process.terminate() + process.waitUntilExit() + } + let data = output.fileHandleForReading.readDataToEndOfFile() + return CommandResult( + status: process.terminationStatus, + output: String(data: data, encoding: .utf8) ?? "" + ) + } + + private static func showError(_ message: String) { + NSApp.activate(ignoringOtherApps: true) + let alert = NSAlert() + alert.messageText = "TFTMAC Control Launcher" + alert.informativeText = message + alert.alertStyle = .critical + alert.runModal() + } +} diff --git a/DevLauncher/main.c b/DevLauncher/main.c new file mode 100644 index 0000000..fcc1e96 --- /dev/null +++ b/DevLauncher/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include + +static const char *const kRuntimeMode = "advanced_diagnostics"; +static const char *const kCoreExecutable = "TFTMACDEVCore"; + +int main(int argc, char *argv[]) { + char launcherPath[PATH_MAX]; + uint32_t launcherPathSize = (uint32_t)sizeof(launcherPath); + if (_NSGetExecutablePath(launcherPath, &launcherPathSize) != 0) { + fprintf(stderr, "TFTMAC DEV could not resolve its launcher path.\n"); + return 70; + } + + char resolvedPath[PATH_MAX]; + if (realpath(launcherPath, resolvedPath) == NULL) { + fprintf(stderr, "TFTMAC DEV could not canonicalize its launcher path: %s\n", strerror(errno)); + return 70; + } + + char *lastSlash = strrchr(resolvedPath, '/'); + if (lastSlash == NULL) { + fprintf(stderr, "TFTMAC DEV launcher path has no containing directory.\n"); + return 70; + } + *lastSlash = '\0'; + + char corePath[PATH_MAX]; + int written = snprintf(corePath, sizeof(corePath), "%s/%s", resolvedPath, kCoreExecutable); + if (written < 0 || (size_t)written >= sizeof(corePath)) { + fprintf(stderr, "TFTMAC DEV core path is too long.\n"); + return 70; + } + if (access(corePath, X_OK) != 0) { + fprintf(stderr, "TFTMAC DEV core is missing or not executable: %s\n", corePath); + return 70; + } + + if (setenv("TFTMAC_RUNTIME_MODE", kRuntimeMode, 1) != 0) { + fprintf(stderr, "TFTMAC DEV could not select its isolated runtime mode: %s\n", strerror(errno)); + return 70; + } + + char **coreArguments = calloc((size_t)argc + 1, sizeof(char *)); + if (coreArguments == NULL) { + fprintf(stderr, "TFTMAC DEV could not allocate its launch arguments.\n"); + return 70; + } + coreArguments[0] = corePath; + for (int index = 1; index < argc; index += 1) { + coreArguments[index] = argv[index]; + } + + execv(corePath, coreArguments); + fprintf(stderr, "TFTMAC DEV could not start its core: %s\n", strerror(errno)); + free(coreArguments); + return 70; +} diff --git a/Probes/TFTMACVulkanProbe/AndroidManifest.xml b/Probes/TFTMACVulkanProbe/AndroidManifest.xml new file mode 100644 index 0000000..9e7416e --- /dev/null +++ b/Probes/TFTMACVulkanProbe/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/Probes/TFTMACVulkanProbe/shaders/probe.frag b/Probes/TFTMACVulkanProbe/shaders/probe.frag new file mode 100644 index 0000000..809aab3 --- /dev/null +++ b/Probes/TFTMACVulkanProbe/shaders/probe.frag @@ -0,0 +1,13 @@ +#version 450 +layout(set = 0, binding = 0) uniform sampler2D sourceTexture; +layout(location = 0) in vec2 uv; +layout(location = 0) out vec4 color; +layout(push_constant) uniform Push { + vec4 tint; + float offset; +} pc; + +void main() { + vec2 wrapped = fract(uv * 8.0 + vec2(pc.offset * 2.0, 0.0)); + color = texture(sourceTexture, wrapped) * pc.tint; +} diff --git a/Probes/TFTMACVulkanProbe/shaders/probe.vert b/Probes/TFTMACVulkanProbe/shaders/probe.vert new file mode 100644 index 0000000..d4f5dcd --- /dev/null +++ b/Probes/TFTMACVulkanProbe/shaders/probe.vert @@ -0,0 +1,13 @@ +#version 450 +layout(location = 0) out vec2 uv; +layout(push_constant) uniform Push { + vec4 tint; + float offset; +} pc; + +void main() { + vec2 positions[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0)); + vec2 position = positions[gl_VertexIndex]; + uv = position * 0.5 + 0.5; + gl_Position = vec4(position.x + pc.offset, position.y, 0.0, 1.0); +} diff --git a/Probes/TFTMACVulkanProbe/src/main.cpp b/Probes/TFTMACVulkanProbe/src/main.cpp new file mode 100644 index 0000000..f6f9b96 --- /dev/null +++ b/Probes/TFTMACVulkanProbe/src/main.cpp @@ -0,0 +1,959 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +constexpr char kLogTag[] = "TFTMAC_VKPROBE"; +constexpr uint32_t kTextureWidth = 256; +constexpr uint32_t kTextureHeight = 256; + +#define PROBE_LOG(...) __android_log_print(ANDROID_LOG_INFO, kLogTag, __VA_ARGS__) +#define PROBE_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, kLogTag, __VA_ARGS__) + +struct Workload { + const char* id; + uint32_t drawsPerFrame; + bool textureUpload; + bool pipelineChurn; + bool queueWaitIdle; +}; + +constexpr std::array kWorkloads{{ + {"stable_descriptor_draw", 1, false, false, false}, + {"texture_upload_sampling", 1, true, false, false}, + {"pipeline_shader_churn", 1, false, true, false}, + {"fill_rate_overdraw", 64, false, false, false}, + {"queue_fence_present_pressure", 4, false, false, true}, +}}; + +struct PushConstants { + float tint[4]; + float offset; +}; + +struct VulkanProbe { + android_app* app = nullptr; + VkInstance instance = VK_NULL_HANDLE; + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice device = VK_NULL_HANDLE; + VkQueue queue = VK_NULL_HANDLE; + uint32_t queueFamily = 0; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkFormat swapchainFormat = VK_FORMAT_UNDEFINED; + VkExtent2D extent{}; + std::vector swapchainImages; + std::vector swapchainViews; + std::vector framebuffers; + VkRenderPass renderPass = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + VkPipeline pipeline = VK_NULL_HANDLE; + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + VkDescriptorSet descriptorSet = VK_NULL_HANDLE; + VkCommandPool commandPool = VK_NULL_HANDLE; + VkCommandBuffer commandBuffer = VK_NULL_HANDLE; + VkSemaphore imageAvailable = VK_NULL_HANDLE; + VkSemaphore renderFinished = VK_NULL_HANDLE; + VkFence frameFence = VK_NULL_HANDLE; + VkQueryPool timestampPool = VK_NULL_HANDLE; + VkImage textureImage = VK_NULL_HANDLE; + VkDeviceMemory textureMemory = VK_NULL_HANDLE; + VkImageView textureView = VK_NULL_HANDLE; + VkSampler sampler = VK_NULL_HANDLE; + VkBuffer stagingBuffer = VK_NULL_HANDLE; + VkDeviceMemory stagingMemory = VK_NULL_HANDLE; + void* stagingMap = nullptr; + VkPhysicalDeviceProperties physicalProperties{}; + PFN_vkCmdBeginDebugUtilsLabelEXT cmdBeginLabel = nullptr; + PFN_vkCmdEndDebugUtilsLabelEXT cmdEndLabel = nullptr; + bool hasTimestamps = false; + bool textureInitialized = false; + uint64_t textureGeneration = 0; + uint64_t errorCount = 0; +}; + +uint64_t fnv1a64(const void* bytes, size_t length, uint64_t hash = 1469598103934665603ULL) { + const auto* cursor = static_cast(bytes); + for (size_t index = 0; index < length; ++index) { + hash ^= cursor[index]; + hash *= 1099511628211ULL; + } + return hash; +} + +uint64_t frameIdentity( + const std::string& profile, + const char* workload, + uint64_t frame, + uint64_t textureGeneration +) { + uint64_t hash = fnv1a64(profile.data(), profile.size()); + hash = fnv1a64(workload, std::strlen(workload), hash); + hash = fnv1a64(&frame, sizeof(frame), hash); + return fnv1a64(&textureGeneration, sizeof(textureGeneration), hash); +} + +std::string property(const char* key, const char* fallback) { + std::array value{}; + const int length = __system_property_get(key, value.data()); + return length > 0 ? std::string(value.data(), static_cast(length)) : std::string(fallback); +} + +std::vector readAsset(AAssetManager* manager, const char* name) { + AAsset* asset = AAssetManager_open(manager, name, AASSET_MODE_BUFFER); + if (!asset) return {}; + const auto length = static_cast(AAsset_getLength(asset)); + std::vector bytes(length); + const int64_t read = AAsset_read(asset, bytes.data(), length); + AAsset_close(asset); + if (read != static_cast(length)) return {}; + return bytes; +} + +bool check(VulkanProbe& probe, VkResult result, const char* operation) { + if (result == VK_SUCCESS) return true; + ++probe.errorCount; + PROBE_ERROR("{\"event\":\"vulkan_error\",\"operation\":\"%s\",\"result\":%d}", operation, result); + return false; +} + +std::optional memoryType( + const VulkanProbe& probe, + uint32_t typeBits, + VkMemoryPropertyFlags required +) { + VkPhysicalDeviceMemoryProperties properties{}; + vkGetPhysicalDeviceMemoryProperties(probe.physicalDevice, &properties); + for (uint32_t index = 0; index < properties.memoryTypeCount; ++index) { + if ((typeBits & (1U << index)) != 0 && + (properties.memoryTypes[index].propertyFlags & required) == required) { + return index; + } + } + return std::nullopt; +} + +bool createBuffer( + VulkanProbe& probe, + VkDeviceSize size, + VkBufferUsageFlags usage, + VkMemoryPropertyFlags memoryFlags, + VkBuffer* buffer, + VkDeviceMemory* memory +) { + VkBufferCreateInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (!check(probe, vkCreateBuffer(probe.device, &bufferInfo, nullptr, buffer), "vkCreateBuffer")) return false; + VkMemoryRequirements requirements{}; + vkGetBufferMemoryRequirements(probe.device, *buffer, &requirements); + const auto type = memoryType(probe, requirements.memoryTypeBits, memoryFlags); + if (!type) return false; + VkMemoryAllocateInfo allocation{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + allocation.allocationSize = requirements.size; + allocation.memoryTypeIndex = *type; + if (!check(probe, vkAllocateMemory(probe.device, &allocation, nullptr, memory), "vkAllocateMemory(buffer)")) return false; + return check(probe, vkBindBufferMemory(probe.device, *buffer, *memory, 0), "vkBindBufferMemory"); +} + +VkCommandBuffer beginOneShot(VulkanProbe& probe) { + VkCommandBufferAllocateInfo allocation{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + allocation.commandPool = probe.commandPool; + allocation.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocation.commandBufferCount = 1; + VkCommandBuffer command = VK_NULL_HANDLE; + if (vkAllocateCommandBuffers(probe.device, &allocation, &command) != VK_SUCCESS) return VK_NULL_HANDLE; + VkCommandBufferBeginInfo begin{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + if (vkBeginCommandBuffer(command, &begin) != VK_SUCCESS) { + vkFreeCommandBuffers(probe.device, probe.commandPool, 1, &command); + return VK_NULL_HANDLE; + } + return command; +} + +bool endOneShot(VulkanProbe& probe, VkCommandBuffer command) { + if (command == VK_NULL_HANDLE || !check(probe, vkEndCommandBuffer(command), "vkEndCommandBuffer(one-shot)")) return false; + VkSubmitInfo submit{VK_STRUCTURE_TYPE_SUBMIT_INFO}; + submit.commandBufferCount = 1; + submit.pCommandBuffers = &command; + const bool submitted = check(probe, vkQueueSubmit(probe.queue, 1, &submit, VK_NULL_HANDLE), "vkQueueSubmit(one-shot)"); + const bool idle = submitted && check(probe, vkQueueWaitIdle(probe.queue), "vkQueueWaitIdle(one-shot)"); + vkFreeCommandBuffers(probe.device, probe.commandPool, 1, &command); + return submitted && idle; +} + +bool uploadTexture(VulkanProbe& probe, uint64_t generation) { + auto* pixels = static_cast(probe.stagingMap); + for (uint32_t y = 0; y < kTextureHeight; ++y) { + for (uint32_t x = 0; x < kTextureWidth; ++x) { + const uint32_t checker = ((x / 16U) ^ (y / 16U) ^ static_cast(generation)) & 1U; + const uint32_t red = checker ? 0xE8U : static_cast((x + generation) & 0xFFU); + const uint32_t green = checker ? static_cast((y + generation * 3U) & 0xFFU) : 0x44U; + const uint32_t blue = checker ? 0x65U : 0xD9U; + pixels[y * kTextureWidth + x] = 0xFF000000U | (blue << 16U) | (green << 8U) | red; + } + } + + VkCommandBuffer command = beginOneShot(probe); + if (command == VK_NULL_HANDLE) return false; + VkImageMemoryBarrier before{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + before.oldLayout = probe.textureInitialized ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; + before.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + before.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + before.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + before.image = probe.textureImage; + before.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + before.subresourceRange.levelCount = 1; + before.subresourceRange.layerCount = 1; + before.srcAccessMask = probe.textureInitialized ? VK_ACCESS_SHADER_READ_BIT : 0; + before.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + vkCmdPipelineBarrier( + command, + probe.textureInitialized ? VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &before + ); + VkBufferImageCopy copy{}; + copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy.imageSubresource.layerCount = 1; + copy.imageExtent = {kTextureWidth, kTextureHeight, 1}; + vkCmdCopyBufferToImage( + command, + probe.stagingBuffer, + probe.textureImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + © + ); + VkImageMemoryBarrier after{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + after.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + after.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + after.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + after.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + after.image = probe.textureImage; + after.subresourceRange = before.subresourceRange; + after.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + after.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + vkCmdPipelineBarrier( + command, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, nullptr, + 0, nullptr, + 1, &after + ); + if (!endOneShot(probe, command)) return false; + probe.textureInitialized = true; + probe.textureGeneration = generation; + return true; +} + +bool createTexture(VulkanProbe& probe) { + VkImageCreateInfo image{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + image.imageType = VK_IMAGE_TYPE_2D; + image.format = VK_FORMAT_R8G8B8A8_UNORM; + image.extent = {kTextureWidth, kTextureHeight, 1}; + image.mipLevels = 1; + image.arrayLayers = 1; + image.samples = VK_SAMPLE_COUNT_1_BIT; + image.tiling = VK_IMAGE_TILING_OPTIMAL; + image.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + image.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if (!check(probe, vkCreateImage(probe.device, &image, nullptr, &probe.textureImage), "vkCreateImage")) return false; + VkMemoryRequirements requirements{}; + vkGetImageMemoryRequirements(probe.device, probe.textureImage, &requirements); + const auto type = memoryType(probe, requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (!type) return false; + VkMemoryAllocateInfo allocation{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + allocation.allocationSize = requirements.size; + allocation.memoryTypeIndex = *type; + if (!check(probe, vkAllocateMemory(probe.device, &allocation, nullptr, &probe.textureMemory), "vkAllocateMemory(image)")) return false; + if (!check(probe, vkBindImageMemory(probe.device, probe.textureImage, probe.textureMemory, 0), "vkBindImageMemory")) return false; + + VkImageViewCreateInfo view{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + view.image = probe.textureImage; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = image.format; + view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view.subresourceRange.levelCount = 1; + view.subresourceRange.layerCount = 1; + if (!check(probe, vkCreateImageView(probe.device, &view, nullptr, &probe.textureView), "vkCreateImageView(texture)")) return false; + + VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + sampler.magFilter = VK_FILTER_LINEAR; + sampler.minFilter = VK_FILTER_LINEAR; + sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler.maxLod = 1.0F; + if (!check(probe, vkCreateSampler(probe.device, &sampler, nullptr, &probe.sampler), "vkCreateSampler")) return false; + + constexpr VkDeviceSize textureBytes = kTextureWidth * kTextureHeight * 4ULL; + if (!createBuffer( + probe, + textureBytes, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &probe.stagingBuffer, + &probe.stagingMemory)) return false; + if (!check(probe, vkMapMemory(probe.device, probe.stagingMemory, 0, textureBytes, 0, &probe.stagingMap), "vkMapMemory")) return false; + return uploadTexture(probe, 0); +} + +bool createPipeline(VulkanProbe& probe) { + const auto vertexBytes = readAsset(probe.app->activity->assetManager, "probe.vert.spv"); + const auto fragmentBytes = readAsset(probe.app->activity->assetManager, "probe.frag.spv"); + if (vertexBytes.empty() || fragmentBytes.empty()) { + PROBE_ERROR("{\"event\":\"asset_error\",\"detail\":\"SPIR-V assets unavailable\"}"); + return false; + } + VkShaderModuleCreateInfo module{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + module.codeSize = vertexBytes.size(); + module.pCode = reinterpret_cast(vertexBytes.data()); + VkShaderModule vertex = VK_NULL_HANDLE; + if (!check(probe, vkCreateShaderModule(probe.device, &module, nullptr, &vertex), "vkCreateShaderModule(vertex)")) return false; + module.codeSize = fragmentBytes.size(); + module.pCode = reinterpret_cast(fragmentBytes.data()); + VkShaderModule fragment = VK_NULL_HANDLE; + if (!check(probe, vkCreateShaderModule(probe.device, &module, nullptr, &fragment), "vkCreateShaderModule(fragment)")) { + vkDestroyShaderModule(probe.device, vertex, nullptr); + return false; + } + std::array stages{}; + stages[0] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[0].module = vertex; + stages[0].pName = "main"; + stages[1] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[1].module = fragment; + stages[1].pName = "main"; + VkPipelineVertexInputStateCreateInfo vertexInput{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; + VkPipelineInputAssemblyStateCreateInfo assembly{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; + assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + VkPipelineViewportStateCreateInfo viewportState{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; + raster.polygonMode = VK_POLYGON_MODE_FILL; + raster.cullMode = VK_CULL_MODE_NONE; + raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + raster.lineWidth = 1.0F; + VkPipelineMultisampleStateCreateInfo multisample{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; + multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + VkPipelineColorBlendAttachmentState attachment{}; + attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; + blend.attachmentCount = 1; + blend.pAttachments = &attachment; + std::array dynamicStates{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; + dynamic.dynamicStateCount = dynamicStates.size(); + dynamic.pDynamicStates = dynamicStates.data(); + VkGraphicsPipelineCreateInfo pipeline{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; + pipeline.stageCount = stages.size(); + pipeline.pStages = stages.data(); + pipeline.pVertexInputState = &vertexInput; + pipeline.pInputAssemblyState = &assembly; + pipeline.pViewportState = &viewportState; + pipeline.pRasterizationState = &raster; + pipeline.pMultisampleState = &multisample; + pipeline.pColorBlendState = &blend; + pipeline.pDynamicState = &dynamic; + pipeline.layout = probe.pipelineLayout; + pipeline.renderPass = probe.renderPass; + pipeline.subpass = 0; + const bool success = check( + probe, + vkCreateGraphicsPipelines(probe.device, VK_NULL_HANDLE, 1, &pipeline, nullptr, &probe.pipeline), + "vkCreateGraphicsPipelines" + ); + vkDestroyShaderModule(probe.device, fragment, nullptr); + vkDestroyShaderModule(probe.device, vertex, nullptr); + return success; +} + +bool createSwapchain(VulkanProbe& probe) { + VkSurfaceCapabilitiesKHR capabilities{}; + if (!check(probe, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(probe.physicalDevice, probe.surface, &capabilities), "vkGetPhysicalDeviceSurfaceCapabilitiesKHR")) return false; + uint32_t formatCount = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR(probe.physicalDevice, probe.surface, &formatCount, nullptr); + std::vector formats(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(probe.physicalDevice, probe.surface, &formatCount, formats.data()); + if (formats.empty()) return false; + VkSurfaceFormatKHR chosen = formats.front(); + for (const auto& format : formats) { + if (format.format == VK_FORMAT_R8G8B8A8_UNORM || format.format == VK_FORMAT_B8G8R8A8_UNORM) { + chosen = format; + break; + } + } + probe.swapchainFormat = chosen.format; + probe.extent = capabilities.currentExtent.width != std::numeric_limits::max() + ? capabilities.currentExtent + : VkExtent2D{ + std::clamp(ANativeWindow_getWidth(probe.app->window), capabilities.minImageExtent.width, capabilities.maxImageExtent.width), + std::clamp(ANativeWindow_getHeight(probe.app->window), capabilities.minImageExtent.height, capabilities.maxImageExtent.height)}; + uint32_t imageCount = std::max(3U, capabilities.minImageCount + 1U); + if (capabilities.maxImageCount > 0) imageCount = std::min(imageCount, capabilities.maxImageCount); + VkSwapchainCreateInfoKHR swapchain{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR}; + swapchain.surface = probe.surface; + swapchain.minImageCount = imageCount; + swapchain.imageFormat = chosen.format; + swapchain.imageColorSpace = chosen.colorSpace; + swapchain.imageExtent = probe.extent; + swapchain.imageArrayLayers = 1; + swapchain.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain.preTransform = capabilities.currentTransform; + swapchain.compositeAlpha = (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) + ? VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR + : VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + swapchain.presentMode = VK_PRESENT_MODE_FIFO_KHR; + swapchain.clipped = VK_TRUE; + if (!check(probe, vkCreateSwapchainKHR(probe.device, &swapchain, nullptr, &probe.swapchain), "vkCreateSwapchainKHR")) return false; + vkGetSwapchainImagesKHR(probe.device, probe.swapchain, &imageCount, nullptr); + probe.swapchainImages.resize(imageCount); + vkGetSwapchainImagesKHR(probe.device, probe.swapchain, &imageCount, probe.swapchainImages.data()); + probe.swapchainViews.resize(imageCount); + for (uint32_t index = 0; index < imageCount; ++index) { + VkImageViewCreateInfo view{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + view.image = probe.swapchainImages[index]; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = probe.swapchainFormat; + view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view.subresourceRange.levelCount = 1; + view.subresourceRange.layerCount = 1; + if (!check(probe, vkCreateImageView(probe.device, &view, nullptr, &probe.swapchainViews[index]), "vkCreateImageView(swapchain)")) return false; + } + return true; +} + +bool initialize(VulkanProbe& probe) { + std::vector instanceExtensions{ + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, + }; + uint32_t instanceExtensionCount = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, nullptr); + std::vector availableInstanceExtensions(instanceExtensionCount); + vkEnumerateInstanceExtensionProperties( + nullptr, + &instanceExtensionCount, + availableInstanceExtensions.data() + ); + const bool debugUtilsAvailable = std::any_of( + availableInstanceExtensions.begin(), + availableInstanceExtensions.end(), + [](const VkExtensionProperties& extension) { + return std::strcmp(extension.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0; + } + ); + if (debugUtilsAvailable) instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + VkApplicationInfo application{VK_STRUCTURE_TYPE_APPLICATION_INFO}; + application.pApplicationName = "TFTMAC Vulkan Probe"; + application.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + application.pEngineName = "TFTMAC Deterministic Probe"; + application.engineVersion = VK_MAKE_VERSION(1, 0, 0); + application.apiVersion = VK_API_VERSION_1_1; + VkInstanceCreateInfo instance{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; + instance.pApplicationInfo = &application; + instance.enabledExtensionCount = static_cast(instanceExtensions.size()); + instance.ppEnabledExtensionNames = instanceExtensions.data(); + if (!check(probe, vkCreateInstance(&instance, nullptr, &probe.instance), "vkCreateInstance")) return false; + VkAndroidSurfaceCreateInfoKHR surface{VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR}; + surface.window = probe.app->window; + if (!check(probe, vkCreateAndroidSurfaceKHR(probe.instance, &surface, nullptr, &probe.surface), "vkCreateAndroidSurfaceKHR")) return false; + + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(probe.instance, &deviceCount, nullptr); + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(probe.instance, &deviceCount, devices.data()); + for (VkPhysicalDevice candidate : devices) { + uint32_t familyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(candidate, &familyCount, nullptr); + std::vector families(familyCount); + vkGetPhysicalDeviceQueueFamilyProperties(candidate, &familyCount, families.data()); + for (uint32_t family = 0; family < familyCount; ++family) { + VkBool32 present = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR(candidate, family, probe.surface, &present); + if ((families[family].queueFlags & VK_QUEUE_GRAPHICS_BIT) && present) { + probe.physicalDevice = candidate; + probe.queueFamily = family; + probe.hasTimestamps = families[family].timestampValidBits > 0; + break; + } + } + if (probe.physicalDevice != VK_NULL_HANDLE) break; + } + if (probe.physicalDevice == VK_NULL_HANDLE) return false; + vkGetPhysicalDeviceProperties(probe.physicalDevice, &probe.physicalProperties); + const float queuePriority = 1.0F; + VkDeviceQueueCreateInfo queue{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; + queue.queueFamilyIndex = probe.queueFamily; + queue.queueCount = 1; + queue.pQueuePriorities = &queuePriority; + const char* deviceExtensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; + VkDeviceCreateInfo device{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; + device.queueCreateInfoCount = 1; + device.pQueueCreateInfos = &queue; + device.enabledExtensionCount = 1; + device.ppEnabledExtensionNames = deviceExtensions; + if (!check(probe, vkCreateDevice(probe.physicalDevice, &device, nullptr, &probe.device), "vkCreateDevice")) return false; + vkGetDeviceQueue(probe.device, probe.queueFamily, 0, &probe.queue); + probe.cmdBeginLabel = reinterpret_cast( + vkGetInstanceProcAddr(probe.instance, "vkCmdBeginDebugUtilsLabelEXT") + ); + probe.cmdEndLabel = reinterpret_cast( + vkGetInstanceProcAddr(probe.instance, "vkCmdEndDebugUtilsLabelEXT") + ); + + VkCommandPoolCreateInfo pool{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; + pool.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + pool.queueFamilyIndex = probe.queueFamily; + if (!check(probe, vkCreateCommandPool(probe.device, &pool, nullptr, &probe.commandPool), "vkCreateCommandPool")) return false; + if (!createSwapchain(probe)) return false; + + VkAttachmentDescription color{}; + color.format = probe.swapchainFormat; + color.samples = VK_SAMPLE_COUNT_1_BIT; + color.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + color.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + color.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + color.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + VkAttachmentReference colorReference{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorReference; + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + VkRenderPassCreateInfo renderPass{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; + renderPass.attachmentCount = 1; + renderPass.pAttachments = &color; + renderPass.subpassCount = 1; + renderPass.pSubpasses = &subpass; + renderPass.dependencyCount = 1; + renderPass.pDependencies = &dependency; + if (!check(probe, vkCreateRenderPass(probe.device, &renderPass, nullptr, &probe.renderPass), "vkCreateRenderPass")) return false; + + probe.framebuffers.resize(probe.swapchainViews.size()); + for (size_t index = 0; index < probe.swapchainViews.size(); ++index) { + VkFramebufferCreateInfo framebuffer{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + framebuffer.renderPass = probe.renderPass; + framebuffer.attachmentCount = 1; + framebuffer.pAttachments = &probe.swapchainViews[index]; + framebuffer.width = probe.extent.width; + framebuffer.height = probe.extent.height; + framebuffer.layers = 1; + if (!check(probe, vkCreateFramebuffer(probe.device, &framebuffer, nullptr, &probe.framebuffers[index]), "vkCreateFramebuffer")) return false; + } + + VkDescriptorSetLayoutBinding binding{}; + binding.binding = 0; + binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutCreateInfo setLayout{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + setLayout.bindingCount = 1; + setLayout.pBindings = &binding; + if (!check(probe, vkCreateDescriptorSetLayout(probe.device, &setLayout, nullptr, &probe.descriptorSetLayout), "vkCreateDescriptorSetLayout")) return false; + VkPushConstantRange push{}; + push.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + push.size = sizeof(PushConstants); + VkPipelineLayoutCreateInfo pipelineLayout{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pipelineLayout.setLayoutCount = 1; + pipelineLayout.pSetLayouts = &probe.descriptorSetLayout; + pipelineLayout.pushConstantRangeCount = 1; + pipelineLayout.pPushConstantRanges = &push; + if (!check(probe, vkCreatePipelineLayout(probe.device, &pipelineLayout, nullptr, &probe.pipelineLayout), "vkCreatePipelineLayout")) return false; + if (!createPipeline(probe) || !createTexture(probe)) return false; + + VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1}; + VkDescriptorPoolCreateInfo descriptorPool{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + descriptorPool.maxSets = 1; + descriptorPool.poolSizeCount = 1; + descriptorPool.pPoolSizes = &poolSize; + if (!check(probe, vkCreateDescriptorPool(probe.device, &descriptorPool, nullptr, &probe.descriptorPool), "vkCreateDescriptorPool")) return false; + VkDescriptorSetAllocateInfo descriptorAllocation{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + descriptorAllocation.descriptorPool = probe.descriptorPool; + descriptorAllocation.descriptorSetCount = 1; + descriptorAllocation.pSetLayouts = &probe.descriptorSetLayout; + if (!check(probe, vkAllocateDescriptorSets(probe.device, &descriptorAllocation, &probe.descriptorSet), "vkAllocateDescriptorSets")) return false; + VkDescriptorImageInfo imageInfo{}; + imageInfo.sampler = probe.sampler; + imageInfo.imageView = probe.textureView; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkWriteDescriptorSet descriptor{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + descriptor.dstSet = probe.descriptorSet; + descriptor.dstBinding = 0; + descriptor.descriptorCount = 1; + descriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor.pImageInfo = &imageInfo; + vkUpdateDescriptorSets(probe.device, 1, &descriptor, 0, nullptr); + + VkCommandBufferAllocateInfo command{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + command.commandPool = probe.commandPool; + command.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + command.commandBufferCount = 1; + if (!check(probe, vkAllocateCommandBuffers(probe.device, &command, &probe.commandBuffer), "vkAllocateCommandBuffers")) return false; + VkSemaphoreCreateInfo semaphore{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + if (!check(probe, vkCreateSemaphore(probe.device, &semaphore, nullptr, &probe.imageAvailable), "vkCreateSemaphore(image)")) return false; + if (!check(probe, vkCreateSemaphore(probe.device, &semaphore, nullptr, &probe.renderFinished), "vkCreateSemaphore(render)")) return false; + VkFenceCreateInfo fence{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + fence.flags = VK_FENCE_CREATE_SIGNALED_BIT; + if (!check(probe, vkCreateFence(probe.device, &fence, nullptr, &probe.frameFence), "vkCreateFence")) return false; + if (probe.hasTimestamps) { + VkQueryPoolCreateInfo query{VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO}; + query.queryType = VK_QUERY_TYPE_TIMESTAMP; + query.queryCount = 2; + if (!check(probe, vkCreateQueryPool(probe.device, &query, nullptr, &probe.timestampPool), "vkCreateQueryPool")) { + probe.hasTimestamps = false; + } + } + + PROBE_LOG( + "{\"event\":\"initialized\",\"device\":\"%s\",\"api_version\":%u,\"driver_version\":%u,\"width\":%u,\"height\":%u,\"timestamp_period_ns\":%.6f,\"debug_labels_available\":%s}", + probe.physicalProperties.deviceName, + probe.physicalProperties.apiVersion, + probe.physicalProperties.driverVersion, + probe.extent.width, + probe.extent.height, + probe.physicalProperties.limits.timestampPeriod, + (probe.cmdBeginLabel && probe.cmdEndLabel) ? "true" : "false" + ); + return true; +} + +void destroy(VulkanProbe& probe) { + if (probe.device != VK_NULL_HANDLE) vkDeviceWaitIdle(probe.device); + if (probe.stagingMap) vkUnmapMemory(probe.device, probe.stagingMemory); + if (probe.timestampPool) vkDestroyQueryPool(probe.device, probe.timestampPool, nullptr); + if (probe.frameFence) vkDestroyFence(probe.device, probe.frameFence, nullptr); + if (probe.renderFinished) vkDestroySemaphore(probe.device, probe.renderFinished, nullptr); + if (probe.imageAvailable) vkDestroySemaphore(probe.device, probe.imageAvailable, nullptr); + if (probe.descriptorPool) vkDestroyDescriptorPool(probe.device, probe.descriptorPool, nullptr); + if (probe.sampler) vkDestroySampler(probe.device, probe.sampler, nullptr); + if (probe.textureView) vkDestroyImageView(probe.device, probe.textureView, nullptr); + if (probe.textureImage) vkDestroyImage(probe.device, probe.textureImage, nullptr); + if (probe.textureMemory) vkFreeMemory(probe.device, probe.textureMemory, nullptr); + if (probe.stagingBuffer) vkDestroyBuffer(probe.device, probe.stagingBuffer, nullptr); + if (probe.stagingMemory) vkFreeMemory(probe.device, probe.stagingMemory, nullptr); + if (probe.pipeline) vkDestroyPipeline(probe.device, probe.pipeline, nullptr); + if (probe.pipelineLayout) vkDestroyPipelineLayout(probe.device, probe.pipelineLayout, nullptr); + if (probe.descriptorSetLayout) vkDestroyDescriptorSetLayout(probe.device, probe.descriptorSetLayout, nullptr); + for (VkFramebuffer framebuffer : probe.framebuffers) vkDestroyFramebuffer(probe.device, framebuffer, nullptr); + if (probe.renderPass) vkDestroyRenderPass(probe.device, probe.renderPass, nullptr); + for (VkImageView view : probe.swapchainViews) vkDestroyImageView(probe.device, view, nullptr); + if (probe.swapchain) vkDestroySwapchainKHR(probe.device, probe.swapchain, nullptr); + if (probe.commandPool) vkDestroyCommandPool(probe.device, probe.commandPool, nullptr); + if (probe.device) vkDestroyDevice(probe.device, nullptr); + if (probe.surface) vkDestroySurfaceKHR(probe.instance, probe.surface, nullptr); + if (probe.instance) vkDestroyInstance(probe.instance, nullptr); +} + +double percentile(std::vector values, double quantile) { + if (values.empty()) return 0.0; + std::sort(values.begin(), values.end()); + const size_t index = std::min(values.size() - 1, static_cast(std::floor((values.size() - 1) * quantile))); + return values[index]; +} + +bool renderFrame( + VulkanProbe& probe, + const Workload& workload, + const std::string& profile, + uint64_t frame, + double* cpuMS, + double* gpuMS, + double* queueWaitMS, + uint64_t* identity +) { + const auto cpuStart = std::chrono::steady_clock::now(); + if (!check(probe, vkWaitForFences(probe.device, 1, &probe.frameFence, VK_TRUE, 3'000'000'000ULL), "vkWaitForFences")) return false; + if (probe.hasTimestamps) { + std::array timestamps{}; + if (vkGetQueryPoolResults( + probe.device, + probe.timestampPool, + 0, + 2, + sizeof(timestamps), + timestamps.data(), + sizeof(uint64_t), + VK_QUERY_RESULT_64_BIT) == VK_SUCCESS && timestamps[1] >= timestamps[0]) { + *gpuMS = static_cast(timestamps[1] - timestamps[0]) * + static_cast(probe.physicalProperties.limits.timestampPeriod) / 1'000'000.0; + } + } + vkResetFences(probe.device, 1, &probe.frameFence); + if (workload.textureUpload && !uploadTexture(probe, probe.textureGeneration + 1)) return false; + if (workload.pipelineChurn) { + vkDestroyPipeline(probe.device, probe.pipeline, nullptr); + probe.pipeline = VK_NULL_HANDLE; + if (!createPipeline(probe)) return false; + } + + uint32_t imageIndex = 0; + const VkResult acquired = vkAcquireNextImageKHR( + probe.device, + probe.swapchain, + 2'000'000'000ULL, + probe.imageAvailable, + VK_NULL_HANDLE, + &imageIndex + ); + if (acquired != VK_SUCCESS && acquired != VK_SUBOPTIMAL_KHR) { + return check(probe, acquired, "vkAcquireNextImageKHR"); + } + vkResetCommandBuffer(probe.commandBuffer, 0); + VkCommandBufferBeginInfo begin{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + if (!check(probe, vkBeginCommandBuffer(probe.commandBuffer, &begin), "vkBeginCommandBuffer(frame)")) return false; + if (probe.hasTimestamps) { + vkCmdResetQueryPool(probe.commandBuffer, probe.timestampPool, 0, 2); + vkCmdWriteTimestamp(probe.commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, probe.timestampPool, 0); + } + + *identity = frameIdentity(profile, workload.id, frame, probe.textureGeneration); + std::string label = "TFTMAC/" + profile + "/" + workload.id + "/" + std::to_string(*identity); + if (probe.cmdBeginLabel && probe.cmdEndLabel) { + VkDebugUtilsLabelEXT debugLabel{VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT}; + debugLabel.pLabelName = label.c_str(); + debugLabel.color[0] = 0.91F; + debugLabel.color[1] = 0.31F; + debugLabel.color[2] = 0.44F; + debugLabel.color[3] = 1.0F; + probe.cmdBeginLabel(probe.commandBuffer, &debugLabel); + } + VkClearValue clear{{{0.015F, 0.02F, 0.06F, 1.0F}}}; + VkRenderPassBeginInfo pass{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + pass.renderPass = probe.renderPass; + pass.framebuffer = probe.framebuffers[imageIndex]; + pass.renderArea.extent = probe.extent; + pass.clearValueCount = 1; + pass.pClearValues = &clear; + vkCmdBeginRenderPass(probe.commandBuffer, &pass, VK_SUBPASS_CONTENTS_INLINE); + VkViewport viewport{0.0F, 0.0F, static_cast(probe.extent.width), static_cast(probe.extent.height), 0.0F, 1.0F}; + VkRect2D scissor{{0, 0}, probe.extent}; + vkCmdSetViewport(probe.commandBuffer, 0, 1, &viewport); + vkCmdSetScissor(probe.commandBuffer, 0, 1, &scissor); + vkCmdBindPipeline(probe.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, probe.pipeline); + vkCmdBindDescriptorSets(probe.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, probe.pipelineLayout, 0, 1, &probe.descriptorSet, 0, nullptr); + for (uint32_t draw = 0; draw < workload.drawsPerFrame; ++draw) { + const float phase = static_cast((frame + draw * 17ULL) % 360ULL) * 0.017453292519943295F; + PushConstants push{{ + 0.62F + 0.38F * std::sin(phase), + 0.62F + 0.38F * std::sin(phase + 2.094F), + 0.62F + 0.38F * std::sin(phase + 4.188F), + 1.0F}, + workload.drawsPerFrame > 1 ? (static_cast(draw % 9U) - 4.0F) * 0.008F : 0.0F}; + vkCmdPushConstants( + probe.commandBuffer, + probe.pipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + sizeof(push), + &push + ); + vkCmdDraw(probe.commandBuffer, 3, 1, 0, 0); + } + vkCmdEndRenderPass(probe.commandBuffer); + if (probe.cmdBeginLabel && probe.cmdEndLabel) probe.cmdEndLabel(probe.commandBuffer); + if (probe.hasTimestamps) { + vkCmdWriteTimestamp(probe.commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, probe.timestampPool, 1); + } + if (!check(probe, vkEndCommandBuffer(probe.commandBuffer), "vkEndCommandBuffer(frame)")) return false; + + const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submit{VK_STRUCTURE_TYPE_SUBMIT_INFO}; + submit.waitSemaphoreCount = 1; + submit.pWaitSemaphores = &probe.imageAvailable; + submit.pWaitDstStageMask = &waitStage; + submit.commandBufferCount = 1; + submit.pCommandBuffers = &probe.commandBuffer; + submit.signalSemaphoreCount = 1; + submit.pSignalSemaphores = &probe.renderFinished; + if (!check(probe, vkQueueSubmit(probe.queue, 1, &submit, probe.frameFence), "vkQueueSubmit(frame)")) return false; + VkPresentInfoKHR present{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + present.waitSemaphoreCount = 1; + present.pWaitSemaphores = &probe.renderFinished; + present.swapchainCount = 1; + present.pSwapchains = &probe.swapchain; + present.pImageIndices = &imageIndex; + const VkResult presented = vkQueuePresentKHR(probe.queue, &present); + if (presented != VK_SUCCESS && presented != VK_SUBOPTIMAL_KHR) { + return check(probe, presented, "vkQueuePresentKHR"); + } + if (workload.queueWaitIdle) { + const auto waitStart = std::chrono::steady_clock::now(); + if (!check(probe, vkQueueWaitIdle(probe.queue), "vkQueueWaitIdle(workload)")) return false; + *queueWaitMS = std::chrono::duration(std::chrono::steady_clock::now() - waitStart).count(); + } + *cpuMS = std::chrono::duration(std::chrono::steady_clock::now() - cpuStart).count(); + return true; +} + +void runProbe(android_app* app) { + while (!app->destroyRequested && app->window == nullptr) { + int events = 0; + android_poll_source* source = nullptr; + const int result = ALooper_pollOnce(100, nullptr, &events, reinterpret_cast(&source)); + if (result >= 0 && source) source->process(app, source); + } + if (app->destroyRequested || !app->window) return; + + VulkanProbe probe{}; + probe.app = app; + if (!initialize(probe)) { + PROBE_ERROR("{\"event\":\"complete\",\"state\":\"FAILED_INITIALIZATION\",\"errors\":%llu}", static_cast(probe.errorCount)); + destroy(probe); + ANativeActivity_finish(app->activity); + return; + } + + const std::string profile = property("debug.tftmac.probe.profile", "control"); + const bool smoke = property("debug.tftmac.probe.smoke", "0") == "1"; + const double warmupSeconds = smoke ? 2.0 : 30.0; + const double workloadSeconds = smoke ? 3.0 : 60.0; + PROBE_LOG( + "{\"event\":\"start\",\"contract\":\"TFTMAC_VULKAN_PROBE_WORKLOAD_V1\",\"profile\":\"%s\",\"mode\":\"%s\",\"warmup_seconds\":%.0f,\"workload_seconds\":%.0f}", + profile.c_str(), smoke ? "NON_COMPARABLE_SMOKE" : "SEALED_CAMPAIGN", warmupSeconds, workloadSeconds + ); + + using Clock = std::chrono::steady_clock; + size_t workloadIndex = 0; + bool warmingUp = true; + uint64_t globalFrame = 0; + uint64_t windowIndex = 0; + uint64_t windowChecksum = 1469598103934665603ULL; + auto phaseStart = Clock::now(); + auto windowStart = phaseStart; + std::vector cpuSamples; + std::vector gpuSamples; + std::vector queueWaitSamples; + + while (!app->destroyRequested && workloadIndex < kWorkloads.size()) { + int events = 0; + android_poll_source* source = nullptr; + while (ALooper_pollOnce(0, nullptr, &events, reinterpret_cast(&source)) >= 0) { + if (source) source->process(app, source); + if (app->destroyRequested) break; + } + if (app->destroyRequested || app->window == nullptr) break; + const Workload& workload = warmingUp ? kWorkloads[0] : kWorkloads[workloadIndex]; + double cpuMS = 0.0; + double gpuMS = 0.0; + double queueWaitMS = 0.0; + uint64_t identity = 0; + if (!renderFrame(probe, workload, profile, globalFrame, &cpuMS, &gpuMS, &queueWaitMS, &identity)) break; + ++globalFrame; + cpuSamples.push_back(cpuMS); + if (gpuMS > 0.0) gpuSamples.push_back(gpuMS); + if (queueWaitMS > 0.0) queueWaitSamples.push_back(queueWaitMS); + windowChecksum = fnv1a64(&identity, sizeof(identity), windowChecksum); + + const auto now = Clock::now(); + const double windowElapsed = std::chrono::duration(now - windowStart).count(); + if (windowElapsed >= 1.0) { + const double cpuSum = std::accumulate(cpuSamples.begin(), cpuSamples.end(), 0.0); + const double fps = cpuSamples.size() / windowElapsed; + const double onePercentLow = cpuSamples.empty() ? 0.0 : 1000.0 / std::max(0.001, percentile(cpuSamples, 0.99)); + PROBE_LOG( + "{\"event\":\"window\",\"profile\":\"%s\",\"phase\":\"%s\",\"workload\":\"%s\",\"window_index\":%llu,\"frames\":%zu,\"fps\":%.4f,\"one_percent_low_fps\":%.4f,\"cpu_mean_ms\":%.4f,\"cpu_p95_ms\":%.4f,\"cpu_p99_ms\":%.4f,\"cpu_max_ms\":%.4f,\"gpu_mean_ms\":%.4f,\"gpu_p99_ms\":%.4f,\"queue_wait_p99_ms\":%.4f,\"command_checksum\":\"%016llx\",\"error_count\":%llu}", + profile.c_str(), + warmingUp ? "warmup" : "measurement", + workload.id, + static_cast(windowIndex++), + cpuSamples.size(), + fps, + onePercentLow, + cpuSamples.empty() ? 0.0 : cpuSum / cpuSamples.size(), + percentile(cpuSamples, 0.95), + percentile(cpuSamples, 0.99), + cpuSamples.empty() ? 0.0 : *std::max_element(cpuSamples.begin(), cpuSamples.end()), + gpuSamples.empty() ? 0.0 : std::accumulate(gpuSamples.begin(), gpuSamples.end(), 0.0) / gpuSamples.size(), + percentile(gpuSamples, 0.99), + percentile(queueWaitSamples, 0.99), + static_cast(windowChecksum), + static_cast(probe.errorCount) + ); + cpuSamples.clear(); + gpuSamples.clear(); + queueWaitSamples.clear(); + windowChecksum = 1469598103934665603ULL; + windowStart = now; + } + + const double phaseElapsed = std::chrono::duration(now - phaseStart).count(); + const double phaseDuration = warmingUp ? warmupSeconds : workloadSeconds; + if (phaseElapsed >= phaseDuration) { + PROBE_LOG( + "{\"event\":\"phase_complete\",\"phase\":\"%s\",\"workload\":\"%s\",\"global_frames\":%llu}", + warmingUp ? "warmup" : "measurement", + workload.id, + static_cast(globalFrame) + ); + if (warmingUp) { + warmingUp = false; + } else { + ++workloadIndex; + } + phaseStart = now; + windowStart = now; + cpuSamples.clear(); + gpuSamples.clear(); + queueWaitSamples.clear(); + windowChecksum = 1469598103934665603ULL; + } + } + + const bool complete = workloadIndex == kWorkloads.size() && probe.errorCount == 0; + PROBE_LOG( + "{\"event\":\"complete\",\"state\":\"%s\",\"profile\":\"%s\",\"frames\":%llu,\"errors\":%llu}", + complete ? "PASS" : "FAILED_RUNTIME", + profile.c_str(), + static_cast(globalFrame), + static_cast(probe.errorCount) + ); + destroy(probe); + ANativeActivity_finish(app->activity); +} + +} // namespace + +void android_main(android_app* app) { + runProbe(app); +} diff --git a/Probes/TFTMACVulkanProbe/workload-manifest.json b/Probes/TFTMACVulkanProbe/workload-manifest.json new file mode 100644 index 0000000..e5f7255 --- /dev/null +++ b/Probes/TFTMACVulkanProbe/workload-manifest.json @@ -0,0 +1,18 @@ +{ + "schema": 1, + "contract": "TFTMAC_VULKAN_PROBE_WORKLOAD_V1", + "package": "com.flashls1.tftmac.vulkanprobe", + "warmup_seconds": 30, + "workload_seconds": 60, + "workloads": [ + {"id": "stable_descriptor_draw", "index": 1, "draws_per_frame": 1, "texture_upload_each_frame": false, "pipeline_rebuild_each_frame": false, "queue_wait_idle_each_frame": false}, + {"id": "texture_upload_sampling", "index": 2, "draws_per_frame": 1, "texture_upload_each_frame": true, "pipeline_rebuild_each_frame": false, "queue_wait_idle_each_frame": false}, + {"id": "pipeline_shader_churn", "index": 3, "draws_per_frame": 1, "texture_upload_each_frame": false, "pipeline_rebuild_each_frame": true, "queue_wait_idle_each_frame": false}, + {"id": "fill_rate_overdraw", "index": 4, "draws_per_frame": 64, "texture_upload_each_frame": false, "pipeline_rebuild_each_frame": false, "queue_wait_idle_each_frame": false}, + {"id": "queue_fence_present_pressure", "index": 5, "draws_per_frame": 4, "texture_upload_each_frame": false, "pipeline_rebuild_each_frame": false, "queue_wait_idle_each_frame": true} + ], + "network_access": false, + "riot_interaction": false, + "frame_identity": "FNV1A64(profile,workload,frame,texture_generation)", + "result_stream": "logcat:TFTMAC_VKPROBE" +} diff --git a/TFTMAC.xcodeproj/project.pbxproj b/TFTMAC.xcodeproj/project.pbxproj index 7b493ae..e3826b2 100644 --- a/TFTMAC.xcodeproj/project.pbxproj +++ b/TFTMAC.xcodeproj/project.pbxproj @@ -55,6 +55,8 @@ 10000000000000000000003A /* runtime-modes.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000024 /* runtime-modes.json */; }; 10000000000000000000003B /* RuntimeModeAuthority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; 10000000000000000000003C /* RuntimeModeAuthority.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000025 /* RuntimeModeAuthority.swift */; }; + 10000000000000000000003E /* GuestUnlockSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000027 /* GuestUnlockSecret.swift */; }; + 10000000000000000000003F /* GuestUnlockSecret.swift in Tests */ = {isa = PBXBuildFile; fileRef = 200000000000000000000027 /* GuestUnlockSecret.swift */; }; 10000000000000000000003D /* runtime-authority.json in Resources */ = {isa = PBXBuildFile; fileRef = 200000000000000000000026 /* runtime-authority.json */; }; /* End PBXBuildFile section */ @@ -91,6 +93,7 @@ 200000000000000000000024 /* runtime-modes.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-modes.json; sourceTree = SOURCE_ROOT; }; 200000000000000000000025 /* RuntimeModeAuthority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeModeAuthority.swift; sourceTree = ""; }; 200000000000000000000026 /* runtime-authority.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssot/runtime-authority.json; sourceTree = SOURCE_ROOT; }; + 200000000000000000000027 /* GuestUnlockSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestUnlockSecret.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -155,7 +158,7 @@ path = Presentation; sourceTree = ""; }; - 40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000023 /* RuntimeMode.swift */, 200000000000000000000025 /* RuntimeModeAuthority.swift */, 200000000000000000000019 /* RuntimeLease.swift */, 20000000000000000000001A /* TelemetrySignalClassifier.swift */, 20000000000000000000001B /* GameFrameTelemetry.swift */, 200000000000000000000021 /* GraphicsStackReceipt.swift */, 20000000000000000000001E /* CombatBenchmarkAnalysis.swift */, 20000000000000000000001F /* CombatBenchmarkStore.swift */, 20000000000000000000001D /* TouchInput.swift */, 200000000000000000000015 /* TFTMACRuntime.swift */, 200000000000000000000016 /* AVDTransactionGuard.swift */,); path = Runtime; sourceTree = ""; }; + 40000000000000000000000C /* Runtime */ = {isa = PBXGroup; children = (200000000000000000000017 /* RuntimeProfile.swift */, 200000000000000000000023 /* RuntimeMode.swift */, 200000000000000000000025 /* RuntimeModeAuthority.swift */, 200000000000000000000027 /* GuestUnlockSecret.swift */, 200000000000000000000019 /* RuntimeLease.swift */, 20000000000000000000001A /* TelemetrySignalClassifier.swift */, 20000000000000000000001B /* GameFrameTelemetry.swift */, 200000000000000000000021 /* GraphicsStackReceipt.swift */, 20000000000000000000001E /* CombatBenchmarkAnalysis.swift */, 20000000000000000000001F /* CombatBenchmarkStore.swift */, 20000000000000000000001D /* TouchInput.swift */, 200000000000000000000015 /* TFTMACRuntime.swift */, 200000000000000000000016 /* AVDTransactionGuard.swift */,); path = Runtime; sourceTree = ""; }; 40000000000000000000000A /* Generated */ = {isa = PBXGroup; children = (40000000000000000000000B /* EmulatorController */,); path = Generated; sourceTree = ""; }; 40000000000000000000000B /* EmulatorController */ = {isa = PBXGroup; children = (200000000000000000000009 /* emulator_controller.pb.swift */, 200000000000000000000010 /* emulator_controller.grpc.swift */,); path = EmulatorController; sourceTree = ""; }; 400000000000000000000005 /* Probes */ = {isa = PBXGroup; children = (400000000000000000000006 /* EmbeddedControlProbe */,); path = Probes; sourceTree = ""; }; @@ -226,9 +229,9 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 700000000000000000000001 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000001, 100000000000000000000002, 100000000000000000000003, 100000000000000000000027, 100000000000000000000004, 100000000000000000000005, 100000000000000000000020, 100000000000000000000021, 100000000000000000000023, 100000000000000000000025, 100000000000000000000038, 10000000000000000000003B, 100000000000000000000028, 10000000000000000000002A, 10000000000000000000002C, 100000000000000000000035, 10000000000000000000002F, 100000000000000000000031, 100000000000000000000033, 100000000000000000000015, 100000000000000000000016,); runOnlyForDeploymentPostprocessing = 0; }; + 700000000000000000000001 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000001, 100000000000000000000002, 100000000000000000000003, 100000000000000000000027, 100000000000000000000004, 100000000000000000000005, 100000000000000000000020, 100000000000000000000021, 100000000000000000000023, 100000000000000000000025, 100000000000000000000038, 10000000000000000000003B, 10000000000000000000003E, 100000000000000000000028, 10000000000000000000002A, 10000000000000000000002C, 100000000000000000000035, 10000000000000000000002F, 100000000000000000000031, 100000000000000000000033, 100000000000000000000015, 100000000000000000000016,); runOnlyForDeploymentPostprocessing = 0; }; 700000000000000000000002 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000006, 100000000000000000000017, 100000000000000000000018,); runOnlyForDeploymentPostprocessing = 0; }; - 700000000000000000000003 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000007, 10000000000000000000001C, 100000000000000000000008, 100000000000000000000022, 100000000000000000000024, 100000000000000000000026, 100000000000000000000039, 10000000000000000000003C, 100000000000000000000029, 10000000000000000000002B, 10000000000000000000002D, 10000000000000000000002E, 100000000000000000000036, 100000000000000000000030, 100000000000000000000032, 100000000000000000000034, 100000000000000000000037,); runOnlyForDeploymentPostprocessing = 0; }; + 700000000000000000000003 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (100000000000000000000007, 10000000000000000000001C, 100000000000000000000008, 100000000000000000000022, 100000000000000000000024, 100000000000000000000026, 100000000000000000000039, 10000000000000000000003C, 10000000000000000000003F, 100000000000000000000029, 10000000000000000000002B, 10000000000000000000002D, 10000000000000000000002E, 100000000000000000000036, 100000000000000000000030, 100000000000000000000032, 100000000000000000000034, 100000000000000000000037,); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ diff --git a/Tests/TFTMACTests/TFTMACGate1Tests.swift b/Tests/TFTMACTests/TFTMACGate1Tests.swift index e8fe75f..74003ac 100644 --- a/Tests/TFTMACTests/TFTMACGate1Tests.swift +++ b/Tests/TFTMACTests/TFTMACGate1Tests.swift @@ -1,4 +1,5 @@ import CoreGraphics +import CryptoKit import XCTest final class TFTMACGate1Tests: XCTestCase { @@ -124,22 +125,29 @@ final class TFTMACGate1Tests: XCTestCase { XCTAssertEqual(candidate.identifier, "tftmac_native_6144m_8c_30hz_flush400") } - func testRapidCombatExperimentHasExactlyTwoNamedPresets() { - XCTAssertEqual(RuntimeExperimentPreset.selectableCases.map(\.rawValue), ["control", "combat_latency_a"]) + func testRetiredInteractiveExperimentsAreNotUserSelectable() { + XCTAssertEqual(RuntimeExperimentPreset.selectableCases.map(\.rawValue), ["control"]) } - func testCombatLatencyAChangesOnlyTheHostSchedulingRequest() { + func testDevGraphicsCandidatesChangeExactlyOneEmulatorFeature() { let control = TFTMACRuntimeProfile.playable.with(experimentPreset: .control) - let candidate = TFTMACRuntimeProfile.playable.with(experimentPreset: .combatLatencyA) XCTAssertEqual(control.effectiveEmulatorFeatures, RuntimeExperimentPreset.baselineEmulatorFeatures) - XCTAssertEqual(candidate.effectiveEmulatorFeatures, RuntimeExperimentPreset.baselineEmulatorFeatures) - XCTAssertEqual(control.vCPU, candidate.vCPU) - XCTAssertEqual(control.ramMiB, candidate.ramMiB) - XCTAssertEqual(control.asgDrawFlushInterval, candidate.asgDrawFlushInterval) - XCTAssertFalse(control.experimentPreset.requestsHostLatencyQoS) - XCTAssertTrue(candidate.experimentPreset.requestsHostLatencyQoS) - XCTAssertEqual(control.comparisonConfigurationSHA256, candidate.comparisonConfigurationSHA256) - XCTAssertNotEqual(control.experimentConfigurationReceipt.sha256, candidate.experimentConfigurationReceipt.sha256) + let candidates: [(RuntimeExperimentPreset, String)] = [ + (.queueSubmitInline, "-VulkanQueueSubmitWithCommands"), + (.virtualQueueOff, "-VulkanVirtualQueue"), + (.fenceContextsOff, "-VirtioGpuFenceContexts") + ] + for (preset, expectedOverride) in candidates { + let candidate = TFTMACRuntimeProfile.playable.with(experimentPreset: preset) + XCTAssertEqual(candidate.experimentPreset.emulatorFeatureAdditions, [expectedOverride]) + XCTAssertTrue(candidate.effectiveEmulatorFeatures.contains(expectedOverride)) + XCTAssertEqual(control.vCPU, candidate.vCPU) + XCTAssertEqual(control.ramMiB, candidate.ramMiB) + XCTAssertEqual(control.asgDrawFlushInterval, candidate.asgDrawFlushInterval) + XCTAssertFalse(candidate.experimentPreset.requestsHostLatencyQoS) + XCTAssertEqual(control.comparisonConfigurationSHA256, candidate.comparisonConfigurationSHA256) + XCTAssertNotEqual(control.experimentConfigurationReceipt.sha256, candidate.experimentConfigurationReceipt.sha256) + } } func testRetiredPerformanceModePresetMigratesToControl() throws { @@ -148,6 +156,78 @@ final class TFTMACGate1Tests: XCTestCase { defer { suite.removePersistentDomain(forName: suiteName) } suite.set("home_run_a", forKey: "runtime.experimentPreset") XCTAssertEqual(RuntimeExperimentPreset.load(from: suite), .control) + suite.set("combat_latency_a", forKey: "runtime.experimentPreset") + XCTAssertEqual(RuntimeExperimentPreset.load(from: suite), .control) + } + + func testPipelineEventV1HasFixedNinetySixByteEncoding() { + let event = makePipelineEvent(workID: 7, boundary: .gfxstreamDecode, durationNS: 20_000_000) + XCTAssertEqual(event.encodedBinary().count, PipelineEventV1.binaryByteCount) + } + + func testFixedPipelineRingReportsOverwriteAndRetainsNewestEvents() { + var ring = FixedPipelineEventRing(capacity: 2) + ring.append(makePipelineEvent(workID: 1, boundary: .asgHostReceive, durationNS: 1)) + ring.append(makePipelineEvent(workID: 2, boundary: .gfxstreamDecode, durationNS: 2)) + ring.append(makePipelineEvent(workID: 3, boundary: .hostVulkanSubmit, durationNS: 3)) + XCTAssertEqual(ring.overwriteCount, 1) + XCTAssertEqual(ring.orderedEvents().compactMap(\.transportWorkID), [2, 3]) + } + + func testCausalAnalyzerNamesOnlyReplicatedFirstOwnedBoundary() { + let events = (1...4).flatMap { workID in + [ + makePipelineEvent(workID: UInt64(workID), boundary: .asgHostReceive, durationNS: 2_000_000), + makePipelineEvent(workID: UInt64(workID), boundary: .gfxstreamDecode, durationNS: 22_000_000), + makePipelineEvent(workID: UInt64(workID), boundary: .moltenVKEnqueue, durationNS: 28_000_000) + ] + } + let finding = PipelineCausalAnalyzer.analyze( + events: events, + eligibleFrameCount: 4, + unambiguousLineageCount: 4, + overwriteCount: 0, + observerOverheadPercent: 1.2, + officialTFT: false + ) + XCTAssertEqual(finding.state, .rootNamed) + XCTAssertEqual(finding.boundary, .gfxstreamDecode) + XCTAssertEqual(finding.owner, "GFXSTREAM") + } + + func testCausalAnalyzerDoesNotInventOfficialTFTGuestIdentity() { + let finding = PipelineCausalAnalyzer.analyze( + events: [], + eligibleFrameCount: 100, + unambiguousLineageCount: 100, + overwriteCount: 0, + observerOverheadPercent: 1, + officialTFT: true + ) + XCTAssertEqual(finding.state, .unrealOrPreHostUnknown) + XCTAssertNil(finding.boundary) + } + + private func makePipelineEvent( + workID: UInt64, + boundary: PipelineBoundary, + durationNS: UInt64 + ) -> PipelineEventV1 { + PipelineEventV1( + kind: .instant, + boundary: boundary, + flags: 0, + processID: 1, + threadID: 2, + timestampNS: workID * 100, + transportWorkID: workID, + presentLineageID: workID, + generation: 1, + sourceSiteID: 1, + queueDepth: 0, + durationNS: durationNS, + payloadHash: SHA256.hash(data: Data()) + ) } func testGuestPowerReceiptRequiresPoweredStayOnAndAwake() throws { @@ -265,6 +345,18 @@ final class TFTMACGate1Tests: XCTestCase { ) } + func testGuestUnlockSecretAcceptsOnlyBoundedNumericPINs() throws { + XCTAssertNotNil(TFTMACGuestUnlockSecret(pin: "1234")) + XCTAssertNotNil(TFTMACGuestUnlockSecret(pin: String(repeating: "7", count: 16))) + XCTAssertNil(TFTMACGuestUnlockSecret(pin: "123")) + XCTAssertNil(TFTMACGuestUnlockSecret(pin: String(repeating: "7", count: 17))) + XCTAssertNil(TFTMACGuestUnlockSecret(pin: "12a4")) + XCTAssertEqual( + try TFTMACGuestUnlockSecret(pin: "9876")?.transientPIN(), + "9876" + ) + } + private func runtimeModeRegistryData() throws -> Data { let repositoryRoot = URL(fileURLWithPath: #filePath) .deletingLastPathComponent() @@ -279,6 +371,7 @@ final class TFTMACGate1Tests: XCTestCase { XCTAssertEqual(registry.document.defaultMode, .control) let selection = try registry.selection(environment: [:]) XCTAssertEqual(selection.mode, .control) + XCTAssertEqual(selection.definition.applicationBundleId, "com.flashls1.tftmac") XCTAssertEqual(selection.definition.avdName, "TFT_Ultra_Tablet") XCTAssertEqual(selection.definition.adbServerPort, 5038) XCTAssertEqual(selection.definition.consolePort, 5582) @@ -292,14 +385,26 @@ final class TFTMACGate1Tests: XCTestCase { TFTMACRuntimeModeRegistry.environmentKey: "advanced_diagnostics" ]) XCTAssertEqual(diagnostics.mode, .advancedDiagnostics) - XCTAssertEqual(diagnostics.definition.avdName, "TFTMAC_Diagnostic_API37_R9") + XCTAssertEqual(diagnostics.definition.applicationBundleId, "com.flashls1.tftmac.dev") + XCTAssertEqual(diagnostics.definition.avdName, "TFTMAC_Diagnostic_StockShadow_R1") XCTAssertEqual(diagnostics.definition.adbServerPort, 5041) XCTAssertEqual(diagnostics.definition.consolePort, 5586) XCTAssertEqual(diagnostics.definition.controllerPort, 8556) XCTAssertEqual(diagnostics.definition.serial, "emulator-5586") - XCTAssertEqual(diagnostics.definition.sdkRoot, "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK") - XCTAssertEqual(diagnostics.definition.adbPath, "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb") + XCTAssertEqual( + diagnostics.definition.sdkRoot, + "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK" + ) + XCTAssertEqual( + diagnostics.definition.adbPath, + "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/platform-tools/adb" + ) XCTAssertTrue(diagnostics.definition.requiresControlStopped) + let authority = try TFTMACRuntimeModeAuthority(data: runtimeModeRegistryData()) + XCTAssertEqual( + try authority.definition(for: .advancedDiagnostics).adbVendorKeysPolicy, + "USER_DEFAULT_KEY" + ) for requested in ["candidate", "unknown"] { XCTAssertThrowsError(try registry.selection(environment: [ TFTMACRuntimeModeRegistry.environmentKey: requested @@ -324,6 +429,8 @@ final class TFTMACGate1Tests: XCTestCase { let candidate = try authority.definition(for: .candidate) XCTAssertEqual(control.launchStrategy, .bundledForwarder) XCTAssertEqual(diagnostics.launchStrategy, .externalNativeHost) + XCTAssertEqual(diagnostics.runtimeVariant, "stock_shadow") + XCTAssertEqual(diagnostics.expectedEmulatorVersionContains, "37.1.11") XCTAssertEqual(candidate.launchStrategy, .blocked) XCTAssertNotEqual(control.stateNamespace, diagnostics.stateNamespace) XCTAssertNotEqual(diagnostics.stateNamespace, candidate.stateNamespace) diff --git a/benchmark.md b/benchmark.md index f2dfacb..433f9ea 100644 --- a/benchmark.md +++ b/benchmark.md @@ -1,7 +1,7 @@ # TFTMAC Benchmark and Analysis Contract **Authority date:** 2026-08-31 America/Chicago -**Formula version:** `tftmac-benchmark-v2` +**Formula version:** `tftmac-benchmark-v3` **Current installed runtime:** TFTMAC 2.3.0 build 8 on the M4 Mac mini; automatic graphics lifecycle and complete stack receipts live-verified, including a 42m27s automatic graphics run **Purpose:** give a developer or AI agent one exact, reproducible process for turning TFTMAC session data into findings, comparisons, decisions, and explicit unknowns. @@ -167,6 +167,14 @@ different session. | `graphics_runs` | automatic TFT process/layer lifetime, configuration SHA, target FPS, and start/end reason | base graphics scope and lifecycle continuity | | `graphics_pipeline_incidents` | automatic exact-layer degradation, trace link, conservative first boundary, explicit unknowns | incident triage, never a battle classification | | `diagnostic_artifacts` | trace path/hash/processor/normalization | bounded causal evidence | +| `pipeline_diagnostic_epochs` | sealed diagnostic workload/profile epoch, lineage/loss/observer state | causal admission gate | +| `pipeline_events` | normalized `PipelineEventV1` boundary events | first-owned-boundary timing | +| `pipeline_event_segments` | 60-second binary segment hashes and previous-hash linkage | raw-event integrity | +| `pipeline_source_sites` | source commit/blob/path/function/line receipts | exact code ownership | +| `pipeline_lineage` | transport and present lineage generations | ambiguity/loss gate | +| `pipeline_findings` | only `ROOT_NAMED`, `ROOT_CANDIDATE`, `UNKNOWN`, or `UNREAL_OR_PRE_HOST_UNKNOWN` | deterministic conclusion | +| `pipeline_experiment_runs` | sealed probe run, effective features and correctness | one-run authority | +| `pipeline_experiment_comparisons` | paired Control/candidate deltas and decision | balanced campaign authority | | `combat_benchmarks` | finalized bounded-window identity/validity/metrics | controlled `BOUNDED_AB` result; table name is retained from the implementation | | `combat_incidents` | bad-window trigger, trace, boundary/unknowns | incident analysis | | `combat_comparisons` | Control/candidate deltas and code decision | controlled A/B output | @@ -810,7 +818,58 @@ source-level incident owner remains `UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE`. The native Mac presenter remained near 60 Hz and is retained only as hidden correctness context. -### 11.2 Build 7 Combat Latency A historical finding +### 11.2 2026-09-02 severe-slowdown diagnostic run + +Capture `2026-09-02T05-26-14.078Z-0fb7a877-23f7-4933-bc9f-5525ed8c6d3d` +preserves the user's reported severe-slowdown game. Its sealed SQLite database +is 18,583,552 bytes with SHA-256 +`2246edff4f433cd5a6d8d995a612274930d2ad979fa649f9249b690fe6f3ed8b`. + +The final 300-second tail has 213 exact TFT layer windows: mean effective FPS +15.884, minimum-window FPS 0.684, mean 1% low 10.081 FPS, 13,494 missed-vsync +equivalents, 4,329 jank intervals, and 2,001 severe intervals. Mean per-window +p95/p99 were 173.048/184.885 ms and the maximum interval was 1,979.745 ms. This +is valid direct evidence of a sustained, unacceptable useful-frame collapse. + +Two bounded Perfetto incident traces were captured and normalized. In trace 2, +Unreal's `RHIThread` was scheduled running for 13.38 seconds of an approximately +14.7-second trace (91.3%), while runnable-but-not-running time was only 1.6%. +That is a strong signal of serialized RHI/Vulkan work rather than lack of guest +CPU assignment: guest CPUs `0-5` were all online. It does not yet prove whether +the first correctable late boundary is Unreal submission, virtio-gpu/gfxstream, +host Vulkan, or MoltenVK. + +The image stream delivered approximately the same low useful-frame cadence with +no sequence loss, so the near-60-Hz Mac presenter was repeating late source +frames and remains outside root-cause ranking. Guest warnings about fence-passing +capability and virtgpu caps/context initialization are retained as suspects, +not findings of ownership. The run is a diagnostic/regression authority and is +not eligible for promotion. + +The complete severe run and the immediately restored Control run compare as +follows: + +| Metric | Severe `combat_latency_a` run | Restored Control run | Direction | +| --- | ---: | ---: | --- | +| Duration | 1,355.8 s | 353.5 s | context only | +| Exact frame intervals | 35,424 | 14,348 | context only | +| Weighted FPS | 26.446 | 47.384 | Control +79.2% | +| 1% low | 2.770 FPS | 7.870 FPS | Control +184.1% | +| p95 frame interval | 117.088 ms | 34.002 ms | Control 71.0% lower | +| p99 frame interval | 218.054 ms | 50.492 ms | Control 76.8% lower | +| Maximum interval | 3,633.456 ms | 2,554.692 ms | Control 29.7% lower | +| Jank interval rate | 34.714% | 19.090% | Control 45.0% lower | +| Severe-stall rate | 21.037% | 1.429% | Control 93.2% lower | +| Frame-budget miss rate | 67.754% | 61.347% | Control 9.5% lower | +| Missed-vsync equivalents | 44,922 | 3,820 | duration-sensitive | + +This is sufficient to reject `combat_latency_a` for normal play and retain +Control as the playable authority. It is not a formal causal A/B because the +durations and gameplay workloads were not matched. Therefore the result does +not claim that macOS QoS caused the regression; it proves only that the observed +candidate run produced no usable gain and must not displace Control. + +### 11.3 Build 7 Combat Latency A historical finding #### Identity and boundaries @@ -1023,10 +1082,10 @@ frames. 2. `observer_overhead_invalid` is stored but does not alter the code decision. 3. Cold-confirmation/promotion linkage is policy, not a normalized SQL field. 4. Clock RTT is too high in the current full run for cross-host cause. -5. No common work ID currently spans guest submit through owned emulator - transport/translation completion. The allocation-free source-built - correlation ring remains a planned, gated next - layer; stack-receipt/frame-window joins do not replace it. +5. The probe emits a known frame identity and the app/C++ fixed ABI is + implemented, but the loadable source-built hooks have not yet passed parity + or lineage acceptance. Until they do, no common work ID spans guest submit + through owned transport/translation completion in accepted live evidence. These gaps limit attribution and automation; they do not erase the direct player-facing frame distribution already captured. diff --git a/dev.md b/dev.md index 867c900..b63954d 100644 --- a/dev.md +++ b/dev.md @@ -1,8 +1,8 @@ # TFTMAC Developer Record -**Development baseline:** TFTMAC 2.3.0 build 8 installed and live-verified with automatic PID/layer logging and complete stack receipts; historical release hashes match, while current-host signing trust is blocked by the absent local identity +**Development baseline:** untouched TFTMAC 2.3.0 build 8 Control plus a playable isolated Emulator 37.1.11/API 36 stock-shadow DEV runtime; three consecutive DEV native-frame launches passed **Control:** High / 60 FPS / Riot Performance Mode OFF -**Active candidate:** `combat_latency_a` +**Active campaign:** deterministic owned Vulkan probe screening; `combat_latency_a`, Home Run A, and Performance Mode Beta are retired **Primary objective:** hold at least 60 useful FPS across the complete run while preserving the proven native app. This is the engineering working file. It contains code ownership, measurement @@ -110,9 +110,43 @@ QEMU child-thread inheritance=NOT_CLAIMED_WITHOUT_COMBAT_EVIDENCE The candidate configuration SHA-256 is `05039d1fd0987f46fc7da8de5f483d8c7ffaf8f39bd1eaecdd1aee11603bbb07`. -It has passed launch/readiness and was the active observed preset in the latest -Build 8 automatic run. That observation is not a performance promotion or a -controlled comparison. +It passed launch/readiness, but the 2026-09-02 severe run delivered 26.446 +weighted FPS, 2.770 FPS 1% low, 117.088 ms p95, and 21.037% severe intervals. +The immediately restored Control run delivered 47.384 weighted FPS, 7.870 FPS +1% low, 34.002 ms p95, and 1.429% severe intervals. The workloads were not +formally matched, so QoS alone is not assigned causality; the candidate is still +rejected because it produced no usable normal-play benefit. + +### Separate Control and DEV launch products + +```text +Desktop TFTMAC.app + -> /Applications/TFTMAC Control Launcher.app + -> unchanged /Applications/TFTMAC.app + -> com.flashls1.tftmac + -> control / TFT_Ultra_Tablet / 5038 + 5582 + 8554 + +Desktop TFTMAC DEV.app + -> /Applications/TFTMAC DEV.app + -> com.flashls1.tftmac.dev + -> advanced_diagnostics / TFTMAC_Diagnostic_StockShadow_R1 / 5041 + 5586 + 8556 +``` + +`DevLauncher/main.c` is the minimal mode-selecting wrapper. It exports +`TFTMAC_RUNTIME_MODE=advanced_diagnostics` and execs the separately packaged +`TFTMACDEVCore`. `scripts/build-dev-launcher.command` builds/signs the isolated +bundle and packages its generated DEV artwork. `scripts/install-desktop-launchers.command` +verifies the protected Control hashes before and after installing DEV, the +signed Control unlock wrapper, and the two Desktop symlinks. The PIN remains in +Keychain and is sent to Control only through an interactive ADB shell stdin +channel pinned to `5038/emulator-5582`, never in process arguments. The shared +global runtime lease is the collision guard. + +The DEV AVD accepts the logged-in user's normal ADB key and reaches `device` +without `ADB_VENDOR_KEYS` injection. R11/API 37 remains historical +failed-first-frame evidence. The current physical stock-shadow clone passed +three consecutive native-frame launches and is the only DEV baseline permitted +for screening. It remains an engineering launcher and cannot replace Control. ## 4. Graphics pipeline and observability @@ -454,15 +488,22 @@ queue depth at each owned handoff static source-site ID mapped to commit/blob/function/line in a sealed manifest ``` -**Status:** **PLANNED, GATED NEXT LAYER.** The current automatic graphics logger +**Status:** **PARTIALLY IMPLEMENTED, NOT YET LIVE-ACCEPTED.** The current automatic graphics logger adds `graphics_runs`, stack-receipt SHA, per-window joins, and conservative `TFT`/`PIPE` views; the presenter remains hidden correctness context. Those do not create a shared work ID. +Swift now provides the exact finding enum/analyzer, fixed 96-byte ABI, 256-event +ring model, segment seals, and eight SQL structures. The matching C++ ABI, +fixed per-thread ring, 60-second segment format, and strict +`TFTMAC///` parser compile and pass their standalone +test. The remaining decisive gate is integration and parity of the loadable +gfxstream/MoltenVK hooks in the isolated modern source runtime. + **Gate:** the 42-minute Build 8 automatic run established an unresolved internal -causal gap below the SurfaceFlinger authority. Implement only in isolated -source-built `tftmac-runtime` at -commit `c8aa26e`, never by replacing normal-play Build 8. Clock mapping, +causal gap below the SurfaceFlinger authority. Implement only in the isolated +modern `emu-main-dev` manifest pinned at +`2692acc620f6563b21995540656674faeb536cdc`, never by replacing normal-play Build 8. Clock mapping, source/binary manifest, and overwrite counts are mandatory. Do not log shaders, frame contents, or credentials. @@ -601,9 +642,9 @@ or weaken AVD rollback merely to report a smaller startup number. by ID, size, hash, and normalized metrics only; keep the raw database private. 2. Keep stock Build 8 as normal-play authority and keep the final Mac presenter out of displayed/ranked causal views. -3. Implement H2's work-ID/source-site instrumentation only in isolated - `tftmac-runtime@c8aa26e`, with parity, clock, loss, stream-seal, and observer- - overhead gates. +3. Complete the already-started H2 work-ID/source-site integration only in the + isolated modern `emu-main-dev` source runtime, with parity, clock, loss, + stream-seal, and observer-overhead gates. 4. Have the diagnostic run identify the first owned divergent boundary or name the exact missing/unowned boundary as `UNKNOWN`. 5. Use that evidence to choose exactly one owned performance change from H3, @@ -658,9 +699,10 @@ runtime: /Volumes/MAC MINI M4/TFTMAC/Runtime Verification claims must be scoped: - unit tests prove parsers, configuration, comparison logic, and local contracts; -- source verification proves the unsigned Release build and 43 native tests; -- installed-runtime verification proves current local hashes/runtime/signing and - is presently expected to fail on the missing local signing identity; +- source verification proves the unsigned Release build and the current 54-test + native suite; +- installed-runtime verification proves current local hashes/runtime/signing; + the 2026-09-02 post-repair check passed for both installed launchers; - launch receipts prove runtime readiness, not combat gain; - SQL combat comparison proves measured change, not internal cause when clock or observer gates fail; @@ -678,11 +720,13 @@ session can seal and restore its AVD transaction. ## 14. Current gaps to close +- complete the owned-probe campaign on the accepted stock-shadow DEV baseline; +- build and parity-check the pinned modern uninstrumented source runtime before + enabling causal hooks; - first-boundary frame correlation during the worst sustained under-60 period; - source-site receipts and complete work-ID joins across owned diagnostic stages; - recurrent Riot WebView/IME reliability; - audible-sound user acceptance; -- repair of the local signing identity for current-host trust verification; - public signing/notarization if distribution beyond this Mac becomes a goal; - source-level gfxstream/MoltenVK performance changes only after the diagnostic logger names the relevant owned boundary; diff --git a/facts.md b/facts.md index 7ee8dfe..644310f 100644 --- a/facts.md +++ b/facts.md @@ -1,7 +1,7 @@ # TFTMAC Facts -**Authority date:** 2026-09-01 America/Chicago -**Observed runtime/source evidence through:** 2026-09-02T02:29:46Z +**Authority date:** 2026-09-02 America/Chicago +**Observed runtime/source evidence through:** 2026-09-02T13:32:00Z **Purpose:** preserve facts and hard boundaries that future TFTMAC work must not casually reinterpret. This file separates durable product facts from mutable observations and historical @@ -62,9 +62,10 @@ must never be presented as measurements of this M4 Mac mini. directly proves authorized ADB, official TFT PID observation, exact `GameActivity` SurfaceView selection, automatic graphics-run admission, `COMPLETE` stack receipts, and frame-to-run/hash/window/receipt linkage. -- **VERIFIED CURRENT:** `/Users/flash/Desktop/TFTMAC.app` is a symlink to the - installed `/Applications/TFTMAC.app`, so the Desktop launcher opens the same - release rather than a second copy. +- **VERIFIED CURRENT:** `/Users/flash/Desktop/TFTMAC.app` points to the signed + `/Applications/TFTMAC Control Launcher.app`, which launches the unchanged + `/Applications/TFTMAC.app` and may unlock only `emulator-5582`. Direct launch + of `/Applications/TFTMAC.app` remains the rollback. - **VERIFIED CURRENT:** `LSSupportsGameMode=true` is present in the installed bundle. This establishes Game Mode eligibility, not proof that macOS activated it during a particular match. @@ -74,15 +75,14 @@ must never be presented as measurements of this M4 Mac mini. - **VERIFIED HISTORICAL RELEASE ACCEPTANCE:** Build 8 was signed with the local `TFTMAC Local Code Signing` identity and passed deep/strict verification when the release receipt was created. It is not notarized for public distribution. -- **VERIFIED CURRENT HOST AUDIT (2026-08-31T23:13:30Z):** the installed TFTMAC +- **VERIFIED TIMESTAMPED HOST AUDIT (2026-08-31T23:13:30Z):** the installed TFTMAC executable and emulator-host hashes still match that Build 8 receipt, but the login keychain now exposes zero valid code-signing identities and `codesign --verify --deep --strict` fails with `CSSMERR_TP_NOT_TRUSTED`. - Current-host installed-runtime verification is therefore blocked until the - local identity is repaired. This does not block unsigned source builds, - diagnostic-runtime work, or causal instrumentation; it must be repaired - before a final signed candidate installation/cutover. This does not rewrite - the historical acceptance result. + Current-host installed-runtime verification was therefore blocked until the + local identity was repaired. The later 2026-09-02 recheck records two valid + identities and deep/strict verification PASS for both installed apps. Neither + observation rewrites the historical release acceptance result. ## 3. Launch and ADB architecture @@ -99,8 +99,9 @@ must never be presented as measurements of this M4 Mac mini. - **LOCKED:** ADB server port `5038`; emulator console port `5582`; serial `emulator-5582`. - **LOCKED:** do not inject `ADB_VENDOR_KEYS`. The launcher uses the logged-in - user's established ADB identity and clears inherited `ADB_SERVER_SOCKET` and - `ANDROID_ADB_SERVER_ADDRESS` values. + user's established ADB identity. Build 8 passes empty `ADB_SERVER_SOCKET` and + `ANDROID_ADB_SERVER_ADDRESS` values through `/usr/bin/open`; its packaged + `RuntimeHost/main.c` does not yet remove those variables before `execv`. - **VERIFIED HISTORICAL ROOT CAUSE:** the incorrect direct path used `5040`, `5592`, and `emulator-5592`, leading to `unauthorized` and eventually `Timed out waiting for emulator ADB device.` The Android runtime, AVD, GPU, @@ -414,6 +415,106 @@ Decision rules: first internal graphics boundary remains `UNKNOWN`; present evidence localizes lateness upstream of or at the exact TFT SurfaceFlinger layer. +### 2026-09-02 live severe-slowdown capture + +- **VERIFIED CURRENT CAPTURE:** + `2026-09-02T05-26-14.078Z-0fb7a877-23f7-4933-bc9f-5525ed8c6d3d` is retained + as the user's severe-slowdown run. The sealed SQLite authority is 18,583,552 + bytes with SHA-256 + `2246edff4f433cd5a6d8d995a612274930d2ad979fa649f9249b690fe6f3ed8b`. +- **VERIFIED PERFORMANCE:** the final 300-second tail contains 213 exact-layer + windows. Mean effective FPS was 15.884, the worst window was 0.684 FPS, mean + 1% low was 10.081 FPS, and the windows accumulated 13,494 missed-vsync + equivalents. This is direct evidence of unacceptable sustained frame loss. +- **VERIFIED PIPELINE CONTEXT:** stream delivery averaged approximately 15 FPS + with no sequence loss while the final Mac presenter continued its established + near-60-Hz correctness cadence. The useful-frame deficit therefore existed + before the final presenter; the final presenter is not a selectable root-cause + candidate. +- **VERIFIED CPU ASSIGNMENT:** guest CPUs `0-5` were online and present and the + guest reported six processors. The slowdown was not caused by TFTMAC assigning + only two guest vCPUs. +- **VERIFIED TRACE SIGNAL:** in the second bounded Perfetto trace, Unreal's + `RHIThread` was scheduled running for 13.38 seconds of an approximately + 14.7-second trace (91.3%) and runnable-but-not-running for only 1.6%. + `SwappyThread3`, `GameThread`, and `RenderThread` were scheduled running for + approximately 40.2%, 24.6%, and 11.4% of the trace. This is the strongest + current signal of serialized pressure in the guest Unreal RHI/Vulkan path; + it does not by itself prove which owned gfxstream/MoltenVK boundary must be + changed. +- **VERIFIED GUEST WARNINGS:** the run logged + `VIRTGPU_PARAM_CREATE_FENCE_PASSING` unavailable 26 times, nine + `DRM_IOCTL_VIRTGPU_GET_CAPS` invalid-argument failures, and nine + `DRM_IOCTL_VIRTGPU_CONTEXT_INIT` file-exists fallbacks. These remain causal + suspects, not proven owners. +- **VERIFIED HOST CHURN:** `emulator.stdout.log` contains 307 internal emulator + helper ADB failures with `cannot start server on remote host`, while TFTMAC's + primary ADB server remained authorized on 5038. Empty inherited ADB endpoint + variables are a source-level defect to repair, but this background churn is + not yet proven to explain the frame collapse. +- **VERIFIED ARTIFACTS:** two bounded traces and their normalized JSON/CSV + receipts are retained under the capture's `perfetto/` directory. They are + private diagnostic evidence and must not enter Git. +- **USER ACCEPTANCE:** this run was reported as too slow for enjoyable play. It + is a retained regression/problem record, not a promotable configuration. + +### 2026-09-02 restored play authority + +- **VERIFIED CURRENT LAUNCH:** capture + `2026-09-02T05-54-33.919Z-e13fd9b8-1091-4516-bd6e-66f8b50a912d` passed the + exclusive-runtime preflight, launched through the packaged Mac host, authorized + ADB on 5038 / `emulator-5582`, and produced a 1920x1080 first native frame. +- **VERIFIED CURRENT SETTINGS:** preset `control`, six vCPU, 5120 MiB RAM, + 1920x1080 at 320 dpi and 60 Hz. This is the normal-play authority restored for + the user's game; do not restart or replace it during live play. +- **VERIFIED CONTROL RESULT:** graphics run + `3ebd80ab-5f0f-489e-97ae-d9e0d780831a` retained 14,348 exact TFT frame + intervals across 353.5 seconds: 47.384 weighted FPS, 7.870 FPS 1% low, + 16.868/34.002/50.492 ms p50/p95/p99, 19.090% jank, 1.429% severe stalls, + and 3,820 missed-vsync equivalents. +- **VERIFIED REJECTION:** the preceding severe run retained 35,424 intervals + across 1,355.8 seconds: 26.446 weighted FPS, 2.770 FPS 1% low, + 16.975/117.088/218.054 ms p50/p95/p99, 34.714% jank, 21.037% severe stalls, + and 44,922 missed-vsync equivalents. Control was decisively more usable, so + `combat_latency_a` is rejected for normal play. The workloads were not a + formal matched A/B pair, so the QoS request alone is not claimed as the cause. + +### 2026-09-02 Control and DEV launcher separation + +- **LOCKED CONTROL:** `/Applications/TFTMAC.app` remains the protected normal-play + app with bundle ID `com.flashls1.tftmac`. Its executable SHA-256 remains + `d3bf7c249a3e5f11b81f778b063e1a8cfe2e7fdeec0537ee6bd8447b1c2268d2`, + and its packaged emulator-host SHA-256 remains + `ea028ec1d74cc025638c2a0e5f8c783748803c1b0ba9012962c038251fb3eb63`. + The protected app remains directly launchable as rollback. The Desktop icon + points to the separate signed Control unlock wrapper and retains the official + Control artwork. +- **VERIFIED DEV INSTALL:** `/Applications/TFTMAC DEV.app` is a separately + signed native app with bundle ID `com.flashls1.tftmac.dev` and a distinct + generated DEV icon. `/Users/flash/Desktop/TFTMAC DEV.app` points to it. +- **LOCKED ISOLATION:** DEV selects `advanced_diagnostics`, uses state namespace + `advanced_diagnostics`, ADB/console/controller ports `5041/5586/8556`, serial + `emulator-5586`, and AVD `TFTMAC_Diagnostic_StockShadow_R1`. Control continues to + use its original application-support root, ports `5038/5582/8554`, serial + `emulator-5582`, and AVD `TFT_Ultra_Tablet`. The global runtime lease forbids + either launcher from starting while the other owns the runtime. +- **VERIFIED CURRENT SIGNING:** both installed app bundles pass strict deep + `codesign` verification with the local `TFTMAC Local Code Signing` identity. + The current keychain exposes that identity and the Apple Development identity; + `scripts/verify-installed-runtime.command` also passes for Control. +- **VERIFIED CURRENT:** the stock-shadow DEV runtime physically clones Emulator + 37.1.11 and the API 36 Control AVD into the diagnostic root. Its sealed receipt + state is `STOCK_SHADOW_RUNTIME_IDENTITY_PASS`; the Control AVD tree hash + remained unchanged before and after cloning. +- **VERIFIED CURRENT:** three consecutive stock-shadow DEV launches reached ADB + `device`, awake/unlocked Android, authenticated controller, exact native first + frame, official TFT package/layer, input/audio receipts, and clean shutdown: + `2026-09-02T12-16-42.125Z-c46f...`, + `2026-09-02T12-18-11.819Z-1300...`, and + `2026-09-02T12-19-13.294Z-3d6d...`. +- **BOUNDARY:** Control is the dependable playable launcher. DEV stock shadow is + launch/play compatible for isolated diagnostics but can never replace Control. + - **VERIFIED CURRENT:** Build 7 live capture `2026-08-31T02-54-28.329Z-14000b50-bf29-44c6-a963-9203d5313494` reached authenticated ADB, a 1920×1080 RGBA first frame, awake/stay-on guest @@ -512,48 +613,70 @@ campaign, useful for candidate selection but not current M4 runtime performance: animation, extreme effects/LOD, blind 50% scale, and blind PSO prewarm. - Riot Performance Mode Beta and the combined Home Run A host flags. -## 12. Current experiment: Combat Latency A +## 12. Retired experiment: Combat Latency A - **LOCKED TEST SHAPE:** Control remains High/60/OFF and the complete proven emulator stack. -- **CANDIDATE:** changes only the packaged emulator host's requested pre-exec - QoS to `user_interactive`; declares Game Mode eligibility. +- **RETIRED CANDIDATE:** changed only the packaged emulator host's requested + pre-exec QoS to `user_interactive`; it is not selectable for current tests. - **VERIFIED IMPLEMENTATION:** candidate/configuration hashing, stale-preset migration, host QoS receipt parsing, guest power gate, correctness rollback, and stable semantic TFT-layer comparison have native tests. - **VERIFIED LAUNCH:** Build 7 established the requested QoS at the host pre-exec boundary and reached TFT ready with logging active. -- **UNKNOWN:** comparative combat benefit. One full candidate match is now - measured, but no matched valid Control/Combat Latency A pair exists. Never - call it faster until a compatible comparison exists. +- **VERIFIED REJECTION:** the user rejected the gameplay and the measured run + was materially worse than the restored Control. It remains historical only. ## 13. Causal graphics implementation state -- **VERIFIED CURRENT (2026-09-02T02:07:03Z):** Wave B source integration is +- **VERIFIED CURRENT:** R11 is `FAILED_FIRST_NATIVE_FRAME` historical evidence, + not launch-ready authority. Emulator 35.6.3/API 37 cannot govern current DEV. +- **VERIFIED CURRENT:** exactly three runtime modes remain: `control`, + `advanced_diagnostics`, and fail-closed `candidate`. Current DEV uses the + `advanced_diagnostics` stock-shadow runtime described above. +- **VERIFIED SOURCE:** `DevExperimentProfile` seals the profile, one-factor + feature override, effective configuration SHA-256, workload-manifest SHA-256, + duration, warmup, and correctness requirements. The balanced campaign order + is Control / queue-submit-inline / Control / virtual-queue-off / Control / + fence-contexts-off / Control. +- **VERIFIED SOURCE:** the owned ARM64 Vulkan probe has five deterministic + one-minute workloads after a 30-second warmup and no network/Riot access. +- **VERIFIED SOURCE:** the app schema contains all eight causal SQL structures. + Swift and C++ define the same 96-byte `PipelineEventV1`; the C++ per-thread + ring has a fixed capacity of 256 and strict owned-probe label parsing. + Standalone ABI/parser verification passes. +- **BOUNDARY:** runtime/source hooks below the app and the seven-run campaign are + not yet accepted evidence. No internal component is named as root until the + label, lineage, loss, observer-overhead, and replication gates pass. + +The R9/R10/R11 entries below are retained as **historical failure evidence**. +They do not override the current stock-shadow DEV authority. + +- **VERIFIED HISTORICAL (2026-09-02T02:07:03Z):** Wave B source integration was complete under the append-only Wave B v4 correction authority. The default mode remains `control`, and `candidate` remains blocked. - **VERIFIED HISTORICAL (Wave B source checkpoint):** runtime-mode registry SHA-256 was `136d1f8f9ac587f9ab0e839e7521b21d9c5e7a1d451d5a0bac44b44a8fe56479`. Runtime identity, registry/configuration hashes, AVD identity, ADB/console/ controller ports, and serial are persisted in the exclusive lease contract. -- **VERIFIED CURRENT:** `scripts/verify-tftmac.command` completed with exit code +- **VERIFIED HISTORICAL:** `scripts/verify-tftmac.command` completed with exit code 0, produced an unsigned Release build, and passed all 49 native tests with zero failures. The post-verification process audit found no active TFTMAC, emulator, or `qemu-system-aarch64` process; no runtime, AVD, installed app, or official TFT package was changed or launched by Wave B. -- **VERIFIED CURRENT (2026-09-02T02:20:37Z):** diagnostic ADB `5041`, console +- **VERIFIED HISTORICAL (2026-09-02T02:20:37Z):** diagnostic ADB `5041`, console `5586`, and controller `8556` passed listener and exclusive-bind checks with control stopped. A new R9 diagnostic forwarder was built from the proven native `RuntimeHost/main.c` chain, ad-hoc signed, deep/strict verified, and sealed under receipt SHA-256 `3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f`. The stale first-load host remains preserved but is not R9 launch authority. -- **VERIFIED CURRENT:** `advanced_diagnostics` is selectable only through the +- **VERIFIED HISTORICAL:** the R9 `advanced_diagnostics` variant was selectable only through the explicit `TFTMAC_RUNTIME_MODE=advanced_diagnostics` environment request. Its R9 registry SHA-256 is `798bad7512da1079167b120575c5c446a1ae7a5bec3030c19fc1da817dbf206b`; unsigned Release and all 49 native tests pass. Control remains the default. -- **VERIFIED CURRENT (first-boot attempt 1):** capture +- **VERIFIED HISTORICAL (R9 first-boot attempt 1):** capture `2026-09-02T02-23-48.444Z-9a2df80c-263a-4e10-beaa-8980d095c365` failed before QEMU because the diagnostic registry incorrectly used the emulator-only R9 install directory as `ANDROID_SDK_ROOT`. The forwarder and @@ -563,15 +686,145 @@ campaign, useful for candidate selection but not current M4 runtime performance: `090fe426402562e227a3a1a6bd6eab9f9572cd48fbe3d467c276d419860caf90`. The corrected registry restores the existing dedicated API 37 SDK and ADB at `/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK`; source validation and all 49 - native tests pass after the correction. Loaded-R9 acceptance remains open. -- **LOCKED NEXT GATE:** guarded diagnostic first boot must prove loaded R9 QEMU - and gfxstream identities before TFT launch. Wave C causal-event - instrumentation remains closed until diagnostic AVD/runtime acceptance passes. + native tests passed after the correction. +- **VERIFIED HISTORICAL (R9 first-boot attempt 2):** capture + `2026-09-02T02-31-04.642Z-c7f52368-7fd7-411d-bbf9-d6dee45eb765` + failed before QEMU because Android Emulator 35.6.3 rejects the stock-control + `-crash-report-mode` argument. The argument is now gated to Control; it is not + sent to the diagnostic runtime. +- **VERIFIED HISTORICAL (R9 first-boot attempt 3):** capture + `2026-09-02T02-33-42.154Z-d39fac1f-393f-409f-b235-5200853db209` + loaded the R9 QEMU/gfxstream runtime but crashed in + `protozero::MessageArena::DeleteLastMessageInternal` through + `perfetto::TrackEvent::Initialize`, `gfxstream::host::InitializeTracing`, and + `FrameBuffer::initialize`. Exact symbols place the first R9 blocker in the + custom gfxstream Perfetto initialization path, not in Riot, the AVD, + MoltenVK, Metal, ADB authorization, CPU, RAM, or audio. +- **VERIFIED HISTORICAL (R10 first boot):** capture + `2026-09-02T03-00-38.256Z-b95cb5a2-59c6-4855-859e-846bc1deca8a` + proved the successor passed the R9 initialization crash, loaded API 37, + MoltenVK, selected the Apple M4 Vulkan device, enabled + `VK_EXT_robustness2`, and initialized the OpenGL ES Translator adapter. It + then crashed in `perfetto::protos::gen::TrackDescriptor::SerializeAsString` + from `gfxstream::SyncThread::doSyncThreadCmd`, + `SyncThread::initSyncEGLContext`, and `FrameBuffer::initialize`. This proves + default-disabling `InitializeTracing` was insufficient because unguarded + gfxstream trace-name macros still entered Perfetto. +- **VERIFIED HISTORICAL (R10 minidump adjudication):** the retained macOS 26.6.2 + arm64 minidump reports uptime `3 seconds`, `EXC_BAD_ACCESS / + KERN_INVALID_ADDRESS` at address `0x8`, and a crashed instruction in + `libandroid-emu-tracing.dylib + 0x749c`. Its stack carries + `track_event`, `gfxstream.default`, and + `libgfxstream_backend.dylib + 0x314278`; its gfxstream Mach-O UUID is + `4C4C4449-5555-3144-A1FC-F6DFE0021481`, and its annotation reports + `35.6.3-standalone-0`. This is the already-classified R10 Perfetto + track-registration null dereference, not an R11 crash and not evidence + against TFT, Riot login, the API 37 image, MoltenVK, Metal, CPU, RAM, audio, + or the stock 37.1.11 runtime. +- **VERIFIED HISTORICAL (R11 sealed successor):** R11 kept tracing compiled but + places the gfxstream event, instant, and name-track macros behind an explicit + runtime opt-in. Sealed build manifest SHA-256 is + `3fd3e18aab970728fcb94efded84952fbde0e84bce86d0ef3592184eaa1170fa`; + gfxstream SHA-256 is + `a770f67660c8d88f5a853b4705aefa0210ef37670a9a8df1b22b702b1f79584b`; + runtime-configuration SHA-256 is + `c910e13e1096da4d3ee162ed82d5658d32aee4b29d9c6af30d19447c03784560`. + The fresh stopped `TFTMAC_Diagnostic_API37_R11` clone receipt SHA-256 is + `e7418f81a37ad3d8169a9c1818e904f1678722e3879fcf7ee610c3257b80d419`. +- **VERIFIED HISTORICAL (R11 source/runtime gate):** registry SHA-256 is + `b2a8080248900c27efdaac7fe3825ccb919188d43072af7a870bfc49c3e0e96f`. + Diagnostic preflight is `READY` on isolated ports `5041/5586/8556`, and the + official unsigned Release verifier passed all 49 native tests with zero + failures. Control remains the default and candidate remains fail-closed. +- **VERIFIED HISTORICAL (R11 live attempt 1):** capture + `2026-09-02T03-18-30.572Z-f4a767a5-b385-4385-bcff-7873c9cffdf9` + reached controller discovery and `LOADED_RUNTIME_IDENTITY_PASS` for exact R11 + QEMU and gfxstream hashes. It did not crash. TFTMAC then performed an owned + shutdown because `runController` still hard-coded the Control emulator version + `37.1.11` and rejected the valid R11 status `35.6.3.0 + (35.6.3-standalone-0)`. The check is now mode-aware and consumes the sealed + `expected_emulator_version_contains` authority (`35.6.3` for R11); the + regression assertion is included in the existing 49-test suite. +- **VERIFIED HISTORICAL (R11 corrected live attempt):** capture + `2026-09-02T03-27-32.017Z-80c1dff8-30cf-4f3d-984f-2a3c37863de6` + passed controller authentication and exact R11 loaded-runtime identity. The + R9/R10 Perfetto crash did not recur. ADB changed from `offline` to + `unauthorized` using the logged-in user's default key and no + `ADB_VENDOR_KEYS`; no native first frame arrived before the bounded 120-second + gate. The emulator explicitly reported that the API 37 guest requires a host + supporting `QemuCameraSensorOrientation` and `VulkanVirtualQueue`. The owned + shutdown restored the diagnostic AVD configuration. +- **VERIFIED HISTORICAL (R11 wake-control retry):** capture + `2026-09-02T03-33-05.318Z-d463ced7-5843-4a11-8c95-c9757c7ee032` + repeated exact R11 identity/controller passes and sent `Power` immediately + after authentication. It again produced no first frame and ADB remained + unauthorized. This rejects a wake-command timing explanation; repeating the + same R11 runtime is not an eligible next experiment. +- **VERIFIED HISTORICAL (R11 ADB provisioning and isolated DEV launch):** the + existing logged-in-user ADB identity was approved once inside the isolated + DEV AVD; no `ADB_VENDOR_KEYS` injection or authorization bypass remains in + the runtime profile. Final DEV capture + `2026-09-02T07-46-40.998Z-8260f517-a8a4-4d5e-918f-723b81de32f4` + passed ownership preflight, exact R11 loaded-runtime identity, and ADB state + `device`. Automatic session/database logging started in the isolated DEV + application-support namespace. +- **VERIFIED HISTORICAL (R11 first-frame failure after ADB repair):** that same + capture never emitted `FIRST_NATIVE_FRAME` and recorded `RUNTIME_FAILED` at + `2026-09-02T07:48:46Z` with `Timed out waiting for Android to post its first + native frame.` The 120-second gate therefore proves the launcher and ADB + authorization are no longer the blocking boundary; the custom R11/API 37 + rendering path still fails before native frame delivery. DEV was shut down + cleanly after preserving this evidence. +- **VERIFIED HISTORICAL (hybrid compatibility probe):** substituting the R11 + gfxstream backend into an isolated APFS clone of the stock 37.1.11 host failed + to load because stock `libemugl_common.dylib` does not export the actively + required `g_emugl_dma_get_host_addr` symbol. Substituting the paired R11 + `libemugl_common.dylib` passed that loader boundary but the stock QEMU then + terminated with `SIGSEGV` during gfxstream renderer initialization (minidump + `21ab1231-eb10-42b6-a896-35f4e3c31511.dmp`). A null-symbol shim would corrupt + active DMA call sites. Further binary-library swapping is rejected. +- **VERIFIED SOURCE BOUNDARY:** Google's published 37.1.11 stable release notes + state that the release added Vulkan extensions required by API 37 system + images. The public QEMU history exposes 37.1.8 as the last 37.1 canary version + bump but does not expose a `37.1.11` bump commit or a 37.x release branch. + Therefore an exact source identity for build `15917651` is currently + `UNKNOWN`; no branch head or 37.1.8 revision may be represented as that exact + source. +- **OPEN LIVE GATE:** R11 proved crash removal and exact loaded identity, but it + did not pass native first-frame or API 37 AVD acceptance. The next eligible + runtime is one built from a coherent modern `emu-main-dev` manifest graph, + not another 35.6.3 retry or hybrid library swap. Manual device PIN, Riot + authentication, and gameplay remain user-operated and are not automated. + +### 2026-09-02 clean-stop continuation facts + +- **VERIFIED SOURCE:** the modern manifest is pinned to + `2692acc620f6563b21995540656674faeb536cdc` on `emu-main-dev`; preparation and + uninstrumented Release build scripts enforce four-job parallelism and refuse + to run while Control or DEV is active. +- **VERIFIED FAILURE AND FIX:** the first sync target was the case-insensitive + external APFS volume and failed because Android requires distinct `BUILD` and + `build/` paths. `scripts/prepare-causal-source-runtime.command` now creates a + 180-GiB sparse, case-sensitive APFS image and validates case sensitivity + before syncing. The failed checkout is historical partial state and is not + source authority. +- **PAUSED, NOT FAILED:** the corrected case-sensitive sync was deliberately + interrupted for this clean handoff. No source-lock receipt or uninstrumented + causal-stock build receipt exists yet. The preparation script is resumable. +- **OPEN LOCAL SETUP:** Keychain service + `com.flashls1.tftmac.android-unlock.v2`, account `android-user-0`, was not + populated before this stop. The PIN is never in source, arguments, logs, SQL, + or this repository. `scripts/setup-android-unlock.command` is the only setup + entry point. +- **NOT RUN:** the seven-run owned Vulkan-probe campaign has no accepted result + yet. No one-factor candidate is promoted and no source component has been + named as root. ## 14. Explicit unknowns and open acceptance -1. Combat Latency A's effect on continuous whole-run FPS, 1% low, p95/p99, - frame-budget misses, and visible stutter versus Control. +1. The causal magnitude of Combat Latency A's QoS request under a formally + workload-matched A/B. It is already rejected for normal play because its + observed severe run was decisively worse and provided no usable benefit. 2. Whether QEMU decoder/render/submission workers actually receive beneficial scheduling after exec. 3. The first divergent boundary in the run's worst sustained under-60 periods. diff --git a/project.md b/project.md index 79d4f6f..a930a24 100644 --- a/project.md +++ b/project.md @@ -1,9 +1,9 @@ # TFTMAC Project Record **Project:** native macOS TFT client experience using the official Android TFT package -**Current development line:** `codex/native-tftmac-2.0.0` -**Current installed release:** TFTMAC 2.3.0 build 8, installed, live-launched, and automatically logging; release hashes match, while the timestamped current-host signing audit is blocked by the missing local identity -**Project record through:** 2026-08-31 America/Chicago +**Current development line:** `clara/implement-wave-b-runtime-mode-selection--215ec5a3` +**Current installed release:** protected TFTMAC 2.3.0 build 8 Control, a separate signed Control unlock wrapper, and an isolated TFTMAC DEV stock-shadow diagnostic launcher; protected Control hashes match +**Project record through:** 2026-09-02 America/Chicago This is the continuity document for a new developer or a new chat. It records what TFTMAC is, why the architecture changed, what has been built, what the @@ -45,6 +45,25 @@ Runtime files live on the external volume at `/Volumes/MAC MINI M4/TFTMAC/Runtime`. Captures and the normalized laboratory stay under `~/Library/Application Support/TFTMAC`. +The installed products are intentionally separate: + +```text +/Applications/TFTMAC.app + -> protected playable Control + -> bundle com.flashls1.tftmac + -> TFT_Ultra_Tablet / ports 5038, 5582, 8554 + +/Applications/TFTMAC DEV.app + -> isolated engineering runtime + -> bundle com.flashls1.tftmac.dev + -> TFTMAC_Diagnostic_StockShadow_R1 / ports 5041, 5586, 8556 +``` + +The Desktop contains one launcher symlink for each installed product. The global +runtime lease prevents them from running concurrently. DEV has separate state, +captures, AVD, ports, bundle identity, launch profile, and generated icon; it +does not mutate or replace Control. + The shipping display path is raw authenticated 1920×1080 RGBA from the emulator controller into a bounded native Metal presentation ring. MMAP/zero-copy remains a later controlled experiment because readiness fencing, stride/color integrity, @@ -400,10 +419,19 @@ Direct evidence from that capture: - clock p95 RTT was 86.757 ms, so this match cannot assign the first upstream cause or serve as a formal matched candidate-vs-Control decision. -The Desktop launcher `/Users/flash/Desktop/TFTMAC.app` points to the installed -`/Applications/TFTMAC.app`. Runtime process state is intentionally not frozen -as a durable fact; documentation and Git publication do not restart the app or -its emulator. +The Desktop launcher `/Users/flash/Desktop/TFTMAC.app` points to the signed +`/Applications/TFTMAC Control Launcher.app`, which launches the unchanged +`/Applications/TFTMAC.app` and unlocks only `5038/emulator-5582`. Direct launch +of the protected app remains the rollback. Runtime process state is not frozen +as a durable fact. + +The Desktop launcher `/Users/flash/Desktop/TFTMAC DEV.app` points to +`/Applications/TFTMAC DEV.app`. Its wrapper selects the isolated +`advanced_diagnostics` profile. R11 is retained only as historical +`FAILED_FIRST_NATIVE_FRAME` evidence. The current stock-shadow variant clones +the proven Emulator 37.1.11/API 36 baseline and passed three consecutive +controller/ADB/unlock/native-frame/package/layer/input/audio launches. Control +remains the dependable game launcher and is never replaced by DEV. What the Build 7 run does **not** prove: a Combat Latency A FPS win. It is one historical candidate baseline, not a compatible A/B pair. @@ -412,28 +440,34 @@ The current Build 8 full-session authority is capture `2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200`: a 42m27s automatic graphics run with 144,364 exact intervals, 99.629% exact-layer coverage, 189 incidents, 56.98 weighted FPS, 21.49 FPS 1% low, 21.510 ms p95, -and 33.434 ms p99. It observed `combat_latency_a` with High/60/Performance Mode -OFF; that is an observed active preset, not a performance promotion. The run +and 33.434 ms p99. It historically observed `combat_latency_a` with +High/60/Performance Mode OFF; the current selected profile is `control`, and +the historical observation is not a performance promotion. The run proves degradation and continuous logging but leaves internal root attribution `UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE`. -The same 2026-08-31 host audit confirmed that the installed main and emulator- +The timestamped 2026-08-31 host audit confirmed that the installed main and emulator- host hashes match the historical Build 8 release receipt. It also found zero valid local signing identities and a current `CSSMERR_TP_NOT_TRUSTED` result. -Historical signing acceptance and current-host trust are separate facts. +Historical signing acceptance and timestamped host trust are separate facts. +A 2026-09-02 recheck after restoring the local identity found two valid signing +identities and deep/strict verification PASS for both Control and DEV. ## 10. Current repository state and authority map Current repository observation: ```text -branch: codex/native-tftmac-2.0.0 -HEAD: 2889cf00b54da28ff62e81fd14a6ae892f37d7cf (Build 8) +branch: clara/implement-wave-b-runtime-mode-selection--215ec5a3 +clean handoff HEAD: the branch tip containing this receipt +published upstream HEAD: must equal the clean handoff HEAD remote: github -> https://github.com/flashls1/TFTMAC.git ``` -The Build 8 line was committed cleanly. Branch/worktree state is mutable and -must be re-observed before it is used as a handoff fact. +The Build 8 line is the playable Control authority. The clean-handoff branch tip +containing this section owns the launcher/profile, stock-shadow, owned-probe, +campaign, and partial causal-logger changes. Re-observe the branch tip and live +process state before acting; no document can freeze mutable process state. Current authority roles: @@ -491,9 +525,10 @@ records must not override the current SSOT. receipt completeness, and conservative boundary views using `benchmark.md`. CPU/RAM/audio remain correctness context only. 5. The latest automatic run confirms an unresolved internal causal gap below - the SurfaceFlinger authority. Implement the planned source-level work-ID - instrumentation only in the isolated - `tftmac-runtime` diagnostic stack at `c8aa26e`; do not replace Build 8. + the SurfaceFlinger authority. Resume the pinned modern `emu-main-dev` + preparation, prove the uninstrumented API 36 stock-shadow parity build, then + integrate source-level work-ID hooks only in that isolated runtime. Do not + replace Build 8. 6. Use that evidence to choose an owned code target. Current TFT is direct Unreal Vulkan; ANGLE is second-line only if a run receipt proves it is active. 7. Preserve the recurrent Riot WebView ANR as a separate login reliability issue, @@ -506,3 +541,40 @@ The native app is launchable and playable. The remaining project objective is not another wrapper or another generic FPS counter; it is a measured improvement that holds at least 60 useful FPS across the complete run without destroying correctness or the official package boundary. + +## 13. Clean-stop continuation receipt — 2026-09-02T14:07:33Z + +The branch tip containing this receipt is the continuation authority. At the +stop boundary: + +- Control was running through `/Applications/TFTMAC Control Launcher.app` on + `5038/emulator-5582`, capture + `2026-09-02T14-05-44.327Z-48a72032-8f61-4639-8912-418001248ad5`. It was not + stopped, restarted, or modified. A resuming agent must re-observe live state + and must not disturb Control if it is still active. +- No DEV, diagnostic emulator, experiment runner, source-sync, or source-build + process remained active. Orphaned sync children were terminated explicitly. +- Stock-shadow DEV has three consecutive launch passes. The owned Vulkan probe, + sealed experiment profiles, campaign/analyzer, Control/DEV launch separation, + secure-Keychain code path, causal SQL schema, Swift/C++ 96-byte event ABI, + fixed rings, segment hashing, and deterministic finding states are in source. +- The one-time v2 Android-unlock Keychain item is not configured. When Control + has exited, run `scripts/setup-android-unlock.command` and enter the PIN only + in the local secure prompt. Never pass it to a shell, source file, log, or SQL. +- The seven-run campaign did not complete and has no winner. Do not infer a + candidate from setup attempts. +- The first Android source sync failed on the case-insensitive external volume. + The corrected script creates `/Volumes/TFTMAC Causal Source` from a sparse + case-sensitive APFS image. Its sync was intentionally paused for this handoff; + rerunning `scripts/prepare-causal-source-runtime.command` resumes it. +- After a `CAUSAL_SOURCE_LOCK_PASS` receipt, run + `scripts/build-causal-stock-runtime.command` and prove API 36 first-frame and + owned-probe parity before adding any source hooks. The actual modern + gfxstream/MoltenVK hook integration and custom optimization patch remain + incomplete. + +The shortest valid resume order is: re-observe Control; wait for it to exit; +complete Keychain setup; finish the seven-run stock-shadow probe campaign; +resume the pinned source sync; build/prove uninstrumented parity; add hooks; +then select at most one evidence-owned patch. Riot login and gameplay remain +manual. diff --git a/scripts/analyze-vulkan-experiment-campaign.mjs b/scripts/analyze-vulkan-experiment-campaign.mjs new file mode 100755 index 0000000..ffeb068 --- /dev/null +++ b/scripts/analyze-vulkan-experiment-campaign.mjs @@ -0,0 +1,242 @@ +#!/usr/bin/env node + +import { execFileSync } from "node:child_process"; +import { createHash, randomUUID } from "node:crypto"; +import { readdirSync, readFileSync, writeFileSync } from "node:fs"; +import { basename, join } from "node:path"; + +function fail(message) { + throw new Error(`TFTMAC Vulkan campaign analysis failed: ${message}`); +} + +const campaignDirectory = process.argv[2]; +if (!campaignDirectory) fail("campaign directory argument is required"); +const runsDirectory = join(campaignDirectory, "runs"); +const runReceipts = readdirSync(runsDirectory) + .filter((name) => name.endsWith(".json")) + .sort() + .map((name) => JSON.parse(readFileSync(join(runsDirectory, name), "utf8"))); +if (runReceipts.length !== 7) fail(`expected seven runs, found ${runReceipts.length}`); + +function sqlJSON(database, query) { + const output = execFileSync("/usr/bin/sqlite3", ["-json", database, query], { encoding: "utf8" }).trim(); + return output ? JSON.parse(output) : []; +} + +function weightedMean(rows, key) { + const eligible = rows.filter((row) => Number(row.frames) > 0 && Number.isFinite(Number(row[key]))); + const weight = eligible.reduce((sum, row) => sum + Number(row.frames), 0); + return weight > 0 + ? eligible.reduce((sum, row) => sum + Number(row[key]) * Number(row.frames), 0) / weight + : null; +} + +function summarizeRun(receipt) { + const eventRows = sqlJSON( + receipt.database, + "SELECT payload_json FROM events WHERE kind='OWNED_VULKAN_PROBE_WINDOW' ORDER BY monotonic_ns" + ); + const payloads = eventRows + .map((row) => JSON.parse(row.payload_json)) + .filter((payload) => payload.phase === "measurement"); + const grouped = Object.groupBy(payloads, (payload) => payload.workload); + const workloads = {}; + for (const [workload, rows] of Object.entries(grouped)) { + const cpuP99 = weightedMean(rows, "cpu_p99_ms"); + const gpuP99 = weightedMean(rows, "gpu_p99_ms"); + const queueP99 = weightedMean(rows, "queue_wait_p99_ms"); + workloads[workload] = { + windows: rows.length, + frames: rows.reduce((sum, row) => sum + Number(row.frames), 0), + fps: weightedMean(rows, "fps"), + one_percent_low_fps: weightedMean(rows, "one_percent_low_fps"), + cpu_p99_ms: cpuP99, + gpu_p99_ms: gpuP99, + queue_wait_p99_ms: queueP99, + relevant_pipeline_p99_ms: Math.max(cpuP99 ?? 0, gpuP99 ?? 0, queueP99 ?? 0), + error_count: Math.max(...rows.map((row) => Number(row.error_count ?? 0))), + }; + } + const runRow = sqlJSON( + receipt.database, + "SELECT experiment_profile_id,state,correctness_passed,event_loss_count,effective_feature_receipt_json FROM pipeline_experiment_runs LIMIT 1" + )[0]; + if (!runRow) fail(`missing pipeline_experiment_runs row in ${receipt.database}`); + return { ...receipt, ...runRow, workloads }; +} + +const runs = runReceipts.map(summarizeRun); +const expectedOrder = [ + "control", + "queue_submit_inline", + "control", + "virtual_queue_off", + "control", + "fence_contexts_off", + "control", +]; +if (runs.some((run, index) => run.experiment_profile_id !== expectedOrder[index])) { + fail("run order or sealed experiment identity drifted"); +} + +const focusWorkload = { + queue_submit_inline: "queue_fence_present_pressure", + virtual_queue_off: "queue_fence_present_pressure", + fence_contexts_off: "queue_fence_present_pressure", +}; + +function percentChange(candidate, control) { + return control === 0 ? null : ((candidate - control) / control) * 100; +} + +const comparisons = []; +for (const candidateIndex of [1, 3, 5]) { + const control = runs[candidateIndex - 1]; + const candidate = runs[candidateIndex]; + const focus = focusWorkload[candidate.experiment_profile_id]; + const workloadDeltas = {}; + let maximumRegression = 0; + let valid = true; + for (const workload of Object.keys(control.workloads)) { + const baseline = control.workloads[workload]; + const observed = candidate.workloads[workload]; + if (!observed || baseline.windows < 55 || observed.windows < 55) { + valid = false; + continue; + } + const lowDelta = percentChange(observed.one_percent_low_fps, baseline.one_percent_low_fps); + const pipelineP99Improvement = percentChange( + baseline.relevant_pipeline_p99_ms, + observed.relevant_pipeline_p99_ms + ); + workloadDeltas[workload] = { + one_percent_low_delta_percent: lowDelta, + relevant_pipeline_p99_improvement_percent: pipelineP99Improvement, + }; + if (workload !== focus) { + maximumRegression = Math.max(maximumRegression, -(lowDelta ?? 0), -(pipelineP99Improvement ?? 0)); + } + } + const focusDelta = workloadDeltas[focus]; + const correctness = Number(candidate.correctness_passed) === 1 + && candidate.state === "PASS" + && Number(candidate.event_loss_count) === 0 + && Object.values(candidate.workloads).every((workload) => workload.error_count === 0); + let decision = "REJECT"; + let reason = "THRESHOLDS_NOT_MET"; + if (!valid || !focusDelta) { + decision = "INVALID"; + reason = "MISSING_OR_INSUFFICIENT_WORKLOAD_WINDOWS"; + } else if (!correctness) { + reason = "CORRECTNESS_OR_EVENT_LOSS_FAILURE"; + } else if ( + focusDelta.one_percent_low_delta_percent >= 10 + && focusDelta.relevant_pipeline_p99_improvement_percent >= 10 + && maximumRegression <= 3 + ) { + decision = "ADVANCE_TO_REVERSE_CONFIRMATION"; + reason = "SCREEN_THRESHOLDS_PASSED"; + } else if (maximumRegression > 3) { + reason = "OTHER_WORKLOAD_REGRESSION_EXCEEDED_3_PERCENT"; + } + comparisons.push({ + comparison_id: randomUUID(), + control_run_id: control.session_id, + candidate_run_id: candidate.session_id, + candidate_profile_id: candidate.experiment_profile_id, + focus_workload: focus, + workload_deltas: workloadDeltas, + one_percent_low_delta_percent: focusDelta?.one_percent_low_delta_percent ?? null, + relevant_pipeline_p99_delta_percent: focusDelta?.relevant_pipeline_p99_improvement_percent ?? null, + maximum_other_workload_regression_percent: maximumRegression, + correctness_passed: correctness, + decision, + decision_reason: reason, + }); +} + +const advanced = comparisons.filter((comparison) => comparison.decision === "ADVANCE_TO_REVERSE_CONFIRMATION"); +const result = { + schema: 1, + contract: "TFTMAC_VULKAN_EXPERIMENT_CAMPAIGN_V1", + campaign_id: basename(campaignDirectory), + generated_utc: new Date().toISOString(), + metric_method: "frame-count-weighted mean of one-second probe windows", + runs, + comparisons, + finalist: advanced.length === 1 ? advanced[0].candidate_profile_id : null, + campaign_state: advanced.length === 1 + ? "SCREEN_PASS_REQUIRES_REVERSE_CONFIRMATION" + : advanced.length > 1 + ? "MULTIPLE_SCREEN_PASSES_REQUIRE_REVERSE_CONFIRMATION" + : "NO_CANDIDATE_ADVANCED", +}; +const canonical = `${JSON.stringify(result, null, 2)}\n`; +writeFileSync(join(campaignDirectory, "campaign-analysis.json"), canonical, { mode: 0o600 }); + +function quote(value) { + if (value === null || value === undefined) return "NULL"; + if (typeof value === "number") return Number.isFinite(value) ? String(value) : "NULL"; + return `'${String(value).replaceAll("'", "''")}'`; +} + +let sql = ` +PRAGMA journal_mode=WAL; +CREATE TABLE IF NOT EXISTS pipeline_experiment_runs( + run_id TEXT PRIMARY KEY, session_id TEXT NOT NULL, experiment_profile_id TEXT NOT NULL, + capture_path TEXT NOT NULL, database_sha256 TEXT NOT NULL, state TEXT NOT NULL, + correctness_passed INTEGER NOT NULL, workload_summary_json TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS pipeline_experiment_comparisons( + comparison_id TEXT PRIMARY KEY, control_run_id TEXT NOT NULL, candidate_run_id TEXT NOT NULL, + candidate_profile_id TEXT NOT NULL, created_utc TEXT NOT NULL, workload_deltas_json TEXT NOT NULL, + one_percent_low_delta_percent REAL, relevant_pipeline_p99_delta_percent REAL, + maximum_other_workload_regression_percent REAL, correctness_passed INTEGER NOT NULL, + decision TEXT NOT NULL, decision_reason TEXT NOT NULL +); +`; +for (const run of runs) { + sql += `INSERT INTO pipeline_experiment_runs VALUES(${[ + run.session_id, + run.session_id, + run.experiment_profile_id, + run.capture_path, + run.database_sha256, + run.state, + Number(run.correctness_passed), + JSON.stringify(run.workloads), + ].map(quote).join(",")});\n`; +} +for (const comparison of comparisons) { + sql += `INSERT INTO pipeline_experiment_comparisons VALUES(${[ + comparison.comparison_id, + comparison.control_run_id, + comparison.candidate_run_id, + comparison.candidate_profile_id, + result.generated_utc, + JSON.stringify(comparison.workload_deltas), + comparison.one_percent_low_delta_percent, + comparison.relevant_pipeline_p99_delta_percent, + comparison.maximum_other_workload_regression_percent, + comparison.correctness_passed ? 1 : 0, + comparison.decision, + comparison.decision_reason, + ].map(quote).join(",")});\n`; +} +const campaignDatabase = join(campaignDirectory, "TFTMAC_VULKAN_CAMPAIGN.sqlite"); +execFileSync("/usr/bin/sqlite3", [campaignDatabase], { input: sql }); +const databaseHash = createHash("sha256").update(readFileSync(campaignDatabase)).digest("hex"); +writeFileSync( + join(campaignDirectory, "campaign-receipt.json"), + `${JSON.stringify({ + schema: 1, + state: "TFTMAC_VULKAN_CAMPAIGN_ANALYSIS_PASS", + campaign_database: campaignDatabase, + campaign_database_sha256: databaseHash, + campaign_analysis_sha256: createHash("sha256").update(canonical).digest("hex"), + campaign_state: result.campaign_state, + finalist: result.finalist, + }, null, 2)}\n`, + { mode: 0o600 } +); +process.stdout.write(`${join(campaignDirectory, "campaign-receipt.json")}\n`); diff --git a/scripts/build-causal-stock-runtime.command b/scripts/build-causal-stock-runtime.command new file mode 100755 index 0000000..2d77c02 --- /dev/null +++ b/scripts/build-causal-stock-runtime.command @@ -0,0 +1,48 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly SOURCE_MOUNT="/Volumes/TFTMAC Causal Source" +readonly SOURCE_ROOT="${SOURCE_MOUNT}/emu-main-dev-2692acc6" +readonly RECEIPT_ROOT="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/causal-source-20260902" +readonly BUILD_ROOT="${SOURCE_MOUNT}/Build/causal-stock-20260902" +readonly INSTALL_ROOT="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/causal-stock-20260902" +readonly REBUILD="${SOURCE_ROOT}/external/qemu/android/rebuild.sh" + +fail() { print -u2 "TFTMAC causal stock build failed: $*"; exit 1; } + +[[ -x "${REBUILD}" ]] || fail "prepared modern emulator source is unavailable" +[[ -d "${SOURCE_MOUNT}" ]] || fail "case-sensitive source volume is not mounted" +[[ "$(/usr/bin/jq -r '.state' "${RECEIPT_ROOT}/source-receipt.json")" == "CAUSAL_SOURCE_LOCK_PASS" ]] \ + || fail "modern source receipt is not accepted" +if /bin/ps -axo command | /usr/bin/grep -E '/Applications/TFTMAC( DEV)?\.app/Contents/MacOS/' | /usr/bin/grep -v grep >/dev/null; then + fail "Control or DEV is running; source build is intentionally deferred" +fi + +export DEVELOPER_DIR="/Applications/Xcode-26.6.0.app/Contents/Developer" +export CMAKE_BUILD_PARALLEL_LEVEL=4 +/bin/mkdir -p "${BUILD_ROOT}" "${INSTALL_ROOT}" +"${REBUILD}" \ + --out="${BUILD_ROOT}/aemu-out" \ + --config release \ + --task-disable CTest \ + --task-disable ZipIntegrationTests \ + --task-disable PackageSamples \ + --verbose + +readonly DISTRIBUTION="${BUILD_ROOT}/aemu-out/distribution/emulator" +[[ -x "${DISTRIBUTION}/emulator" ]] || fail "emulator artifact is missing" +[[ -f "${DISTRIBUTION}/lib64/libgfxstream_backend.dylib" ]] || fail "gfxstream artifact is missing" +[[ -f "${DISTRIBUTION}/lib64/vulkan/libMoltenVK.dylib" || -f "${DISTRIBUTION}/lib64/libMoltenVK.dylib" ]] \ + || fail "MoltenVK artifact is missing" +/usr/bin/ditto "${DISTRIBUTION}" "${INSTALL_ROOT}/emulator" + +/usr/bin/jq -n \ + --arg state "CAUSAL_STOCK_BUILD_PASS_PENDING_FIRST_FRAME" \ + --arg source_receipt_sha256 "$(/usr/bin/shasum -a 256 "${RECEIPT_ROOT}/source-receipt.json" | /usr/bin/awk '{print $1}')" \ + --arg emulator_sha256 "$(/usr/bin/shasum -a 256 "${INSTALL_ROOT}/emulator/emulator" | /usr/bin/awk '{print $1}')" \ + --arg gfxstream_sha256 "$(/usr/bin/shasum -a 256 "${INSTALL_ROOT}/emulator/lib64/libgfxstream_backend.dylib" | /usr/bin/awk '{print $1}')" \ + '{schema:1,state:$state,source_receipt_sha256:$source_receipt_sha256,configuration:"Release",parallel_build_jobs:4,instrumentation:"OFF",artifacts:{emulator_sha256:$emulator_sha256,gfxstream_sha256:$gfxstream_sha256},control_touched:false}' \ + > "${RECEIPT_ROOT}/causal-stock-build.json" + +print "TFTMAC causal stock build: PASS_PENDING_FIRST_FRAME (${INSTALL_ROOT})" diff --git a/scripts/build-control-launcher.command b/scripts/build-control-launcher.command new file mode 100755 index 0000000..bf0fa81 --- /dev/null +++ b/scripts/build-control-launcher.command @@ -0,0 +1,60 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly ROOT="${0:A:h:h}" +readonly CONTROL_APP="/Applications/TFTMAC.app" +readonly CONTROL_EXECUTABLE_SHA256="d3bf7c249a3e5f11b81f778b063e1a8cfe2e7fdeec0537ee6bd8447b1c2268d2" +readonly CONTROL_HOST_SHA256="ea028ec1d74cc025638c2a0e5f8c783748803c1b0ba9012962c038251fb3eb63" +readonly ICON_SOURCE="${ROOT}/tftmac/Assets/TFTMAC-Official-Icon.png" +readonly DIST="${ROOT}/dist/TFTMAC Control Launcher.app" +readonly MACOS_DIR="${DIST}/Contents/MacOS" +readonly RESOURCES_DIR="${DIST}/Contents/Resources" +readonly ICON_WORK="$(/usr/bin/mktemp -d /private/tmp/tftmac-control-icon.XXXXXX)" +readonly SIGNING_IDENTITY_NAME="${TFTMAC_CODE_SIGN_IDENTITY_NAME:-TFTMAC Local Code Signing}" + +cleanup() { /bin/rm -rf "${ICON_WORK}"; } +trap cleanup EXIT +fail() { print -u2 "TFTMAC Control launcher build failed: $*"; exit 1; } + +[[ -x "${CONTROL_APP}/Contents/MacOS/TFTMAC" ]] || fail "protected Control app is missing" +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/MacOS/TFTMAC" | /usr/bin/awk '{print $1}')" == "${CONTROL_EXECUTABLE_SHA256}" ]] \ + || fail "protected Control executable identity changed" +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/Resources/TFTMAC Emulator Host.app/Contents/MacOS/TFTMACEmulatorHost" | /usr/bin/awk '{print $1}')" == "${CONTROL_HOST_SHA256}" ]] \ + || fail "protected Control emulator-host identity changed" + +/bin/rm -rf "${DIST}" +/bin/mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}" +/bin/cp "${ROOT}/ControlLauncher/Info.plist" "${DIST}/Contents/Info.plist" +/usr/bin/xcrun --sdk macosx swiftc \ + -O -whole-module-optimization -swift-version 5 -parse-as-library \ + -target arm64-apple-macos15.0 \ + -framework AppKit -framework LocalAuthentication -framework Security \ + "${ROOT}/ControlLauncher/main.swift" \ + "${ROOT}/tftmac/Runtime/GuestUnlockSecret.swift" \ + -o "${MACOS_DIR}/TFTMACControlLauncher" + +/usr/bin/sips -z 1024 1024 "${ICON_SOURCE}" --out "${ICON_WORK}/icon_1024x1024.png" >/dev/null +/bin/mkdir -p "${ICON_WORK}/TFTMAC-Official.iconset" +for specification in \ + '16 icon_16x16.png' '32 icon_16x16@2x.png' '32 icon_32x32.png' '64 icon_32x32@2x.png' \ + '128 icon_128x128.png' '256 icon_128x128@2x.png' '256 icon_256x256.png' \ + '512 icon_256x256@2x.png' '512 icon_512x512.png' '1024 icon_512x512@2x.png'; do + pixels="${specification%% *}" + filename="${specification#* }" + /usr/bin/sips -z "${pixels}" "${pixels}" "${ICON_WORK}/icon_1024x1024.png" \ + --out "${ICON_WORK}/TFTMAC-Official.iconset/${filename}" >/dev/null +done +/usr/bin/iconutil -c icns "${ICON_WORK}/TFTMAC-Official.iconset" -o "${RESOURCES_DIR}/TFTMAC-Official.icns" + +readonly SIGNING_IDENTITY_HASH="$(/bin/zsh "${ROOT}/scripts/ensure-local-signing-identity.command")" +[[ -n "${SIGNING_IDENTITY_HASH}" ]] || fail "stable local signing identity is unavailable" +/usr/bin/codesign --force --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${DIST}" +/usr/bin/codesign --verify --strict --verbose=2 "${DIST}" + +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/MacOS/TFTMAC" | /usr/bin/awk '{print $1}')" == "${CONTROL_EXECUTABLE_SHA256}" ]] \ + || fail "Control executable changed during wrapper build" +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/Resources/TFTMAC Emulator Host.app/Contents/MacOS/TFTMACEmulatorHost" | /usr/bin/awk '{print $1}')" == "${CONTROL_HOST_SHA256}" ]] \ + || fail "Control emulator host changed during wrapper build" + +print "TFTMAC Control launcher built without modifying Control: ${DIST}" diff --git a/scripts/build-dev-launcher.command b/scripts/build-dev-launcher.command new file mode 100755 index 0000000..8541598 --- /dev/null +++ b/scripts/build-dev-launcher.command @@ -0,0 +1,128 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly ROOT="${0:A:h:h}" +readonly ICON_SOURCE="${ROOT}/tftmac/Assets/TFTMAC-DEV-Icon.png" +readonly ICON_SOURCE_SHA256="660d312767f6367d5e60d21ff9f05c8e17c29c0e258a45f5cb5e40ac0cb4c945" +readonly REGISTRY_SHA256="f92cfc78923814d8eb3d8f6f550a4763ba918fe5e1c20088e2863d89ce58eafe" +readonly TRACE_PROCESSOR_SHA256="d29864d1ba3b36855527bb1b0ca3aa7f703cdce338b9680bb922c5c151b358fa" +readonly SIGNING_IDENTITY_NAME="${TFTMAC_CODE_SIGN_IDENTITY_NAME:-TFTMAC Local Code Signing}" +readonly DERIVED="${ROOT}/.build/native-dev" +readonly BUILT_APP="${DERIVED}/Build/Products/Release/TFTMAC.app" +readonly DIST="${ROOT}/dist/TFTMAC DEV.app" +readonly ICON_WORK="$(/usr/bin/mktemp -d /private/tmp/tftmac-dev-icon.XXXXXX)" + +cleanup() { + /bin/rm -rf "${ICON_WORK}" +} +trap cleanup EXIT + +fail() { + print -u2 "TFTMAC DEV build failed: $*" + exit 1 +} + +if [[ -z "${DEVELOPER_DIR:-}" ]]; then + if [[ -d /Applications/Xcode-26.6.0.app/Contents/Developer ]]; then + export DEVELOPER_DIR=/Applications/Xcode-26.6.0.app/Contents/Developer + else + export DEVELOPER_DIR="$(/usr/bin/xcode-select -p)" + fi +fi + +[[ -s "${ICON_SOURCE}" ]] || fail "DEV icon source is missing: ${ICON_SOURCE}" +[[ "$(/usr/bin/shasum -a 256 "${ICON_SOURCE}" | /usr/bin/awk '{print $1}')" == "${ICON_SOURCE_SHA256}" ]] \ + || fail "DEV icon source failed its SHA-256 receipt" +[[ "$(/usr/bin/shasum -a 256 "${ROOT}/ssot/runtime-modes.json" | /usr/bin/awk '{print $1}')" == "${REGISTRY_SHA256}" ]] \ + || fail "runtime-mode registry failed its DEV launcher receipt" + +"${ROOT}/scripts/build-vulkan-probe.command" >/dev/null +readonly PROBE_APK="${ROOT}/.build/vulkan-probe/TFTMACVulkanProbe.apk" +readonly PROBE_RECEIPT="${ROOT}/.build/vulkan-probe/build-receipt.json" +[[ -s "${PROBE_APK}" && -s "${PROBE_RECEIPT}" ]] \ + || fail "owned Vulkan probe build did not produce its sealed artifacts" + +readonly SIGNING_IDENTITY_HASH="$(/bin/zsh "${ROOT}/scripts/ensure-local-signing-identity.command")" +[[ -n "${SIGNING_IDENTITY_HASH}" ]] || fail "stable local signing identity is unavailable" + +/usr/bin/xcodebuild \ + -quiet \ + -project "${ROOT}/TFTMAC.xcodeproj" \ + -scheme TFTMAC \ + -configuration Release \ + -derivedDataPath "${DERIVED}" \ + CODE_SIGNING_ALLOWED=NO \ + build + +[[ -d "${BUILT_APP}" ]] || fail "Xcode did not produce ${BUILT_APP}" +/bin/mkdir -p "${ROOT}/dist" +/bin/rm -rf "${DIST}" +/usr/bin/ditto "${BUILT_APP}" "${DIST}" + +readonly MACOS_DIR="${DIST}/Contents/MacOS" +readonly RESOURCES_DIR="${DIST}/Contents/Resources" +readonly INFO="${DIST}/Contents/Info.plist" +/bin/mv "${MACOS_DIR}/TFTMAC" "${MACOS_DIR}/TFTMACDEVCore" +/usr/bin/xcrun --sdk macosx clang \ + -Os -arch arm64 -mmacosx-version-min=15.0 \ + "${ROOT}/DevLauncher/main.c" \ + -o "${MACOS_DIR}/TFTMACDEVLauncher" + +/usr/bin/plutil -replace CFBundleDisplayName -string "TFTMAC DEV" "${INFO}" +/usr/bin/plutil -replace CFBundleName -string "TFTMAC DEV" "${INFO}" +/usr/bin/plutil -replace CFBundleExecutable -string "TFTMACDEVLauncher" "${INFO}" +/usr/bin/plutil -replace CFBundleIdentifier -string "com.flashls1.tftmac.dev" "${INFO}" +/usr/bin/plutil -replace CFBundleIconFile -string "TFTMAC-DEV.icns" "${INFO}" +/usr/bin/plutil -replace NSRemovableVolumesUsageDescription -string \ + "TFTMAC DEV uses the isolated Android diagnostic runtime stored on MAC MINI M4." "${INFO}" +/usr/bin/plutil -insert TFTMACRuntimeMode -string "advanced_diagnostics" "${INFO}" +/usr/bin/plutil -lint "${INFO}" >/dev/null + +/usr/bin/sips -z 1024 1024 "${ICON_SOURCE}" --out "${ICON_WORK}/icon_1024x1024.png" >/dev/null +/bin/mkdir -p "${ICON_WORK}/TFTMAC-DEV.iconset" "${RESOURCES_DIR}" +for specification in \ + '16 icon_16x16.png' \ + '32 icon_16x16@2x.png' \ + '32 icon_32x32.png' \ + '64 icon_32x32@2x.png' \ + '128 icon_128x128.png' \ + '256 icon_128x128@2x.png' \ + '256 icon_256x256.png' \ + '512 icon_256x256@2x.png' \ + '512 icon_512x512.png' \ + '1024 icon_512x512@2x.png'; do + pixels="${specification%% *}" + filename="${specification#* }" + /usr/bin/sips -z "${pixels}" "${pixels}" "${ICON_WORK}/icon_1024x1024.png" \ + --out "${ICON_WORK}/TFTMAC-DEV.iconset/${filename}" >/dev/null +done +/usr/bin/iconutil -c icns "${ICON_WORK}/TFTMAC-DEV.iconset" -o "${RESOURCES_DIR}/TFTMAC-DEV.icns" +/bin/cp "${ICON_WORK}/icon_1024x1024.png" "${RESOURCES_DIR}/TFTMAC-DEV-1024.png" +/bin/cp "${PROBE_APK}" "${RESOURCES_DIR}/TFTMACVulkanProbe.apk" +/bin/cp "${PROBE_RECEIPT}" "${RESOURCES_DIR}/TFTMACVulkanProbe-build-receipt.json" +/bin/cp "${ROOT}/Probes/TFTMACVulkanProbe/workload-manifest.json" "${RESOURCES_DIR}/workload-manifest.json" + +trace_processor="/Applications/TFTMAC.app/Contents/Resources/trace_processor_shell" +if [[ ! -x "${trace_processor}" ]] || \ + [[ "$(/usr/bin/shasum -a 256 "${trace_processor}" | /usr/bin/awk '{print $1}')" != "${TRACE_PROCESSOR_SHA256}" ]]; then + trace_processor="$(/bin/zsh "${ROOT}/scripts/install-trace-processor.command")" +fi +[[ "$(/usr/bin/shasum -a 256 "${trace_processor}" | /usr/bin/awk '{print $1}')" == "${TRACE_PROCESSOR_SHA256}" ]] \ + || fail "Perfetto trace_processor failed its pinned SHA-256 receipt" +/bin/cp "${trace_processor}" "${RESOURCES_DIR}/trace_processor_shell" +/bin/chmod 755 "${RESOURCES_DIR}/trace_processor_shell" + +/usr/bin/codesign --force --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${MACOS_DIR}/TFTMACDEVCore" +/usr/bin/codesign --force --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${MACOS_DIR}/TFTMACDEVLauncher" +/usr/bin/codesign --force --sign "${SIGNING_IDENTITY_HASH}" --timestamp=none "${DIST}" +/usr/bin/codesign --verify --deep --strict --verbose=2 "${DIST}" + +[[ "$(/usr/bin/plutil -extract CFBundleIdentifier raw "${INFO}")" == "com.flashls1.tftmac.dev" ]] \ + || fail "DEV bundle identity drifted" +[[ "$(/usr/bin/plutil -extract CFBundleExecutable raw "${INFO}")" == "TFTMACDEVLauncher" ]] \ + || fail "DEV launcher executable drifted" +/usr/bin/strings "${MACOS_DIR}/TFTMACDEVLauncher" | /usr/bin/grep -Fx "advanced_diagnostics" >/dev/null \ + || fail "DEV launcher does not contain the enforced diagnostic runtime selection" + +print "TFTMAC DEV built without modifying Control: ${DIST}" diff --git a/scripts/build-stock-shadow-runtime.command b/scripts/build-stock-shadow-runtime.command new file mode 100755 index 0000000..c056cb6 --- /dev/null +++ b/scripts/build-stock-shadow-runtime.command @@ -0,0 +1,172 @@ +#!/bin/zsh +set -euo pipefail + +readonly BUILD_ID="stock-shadow-r1-20260902" +readonly CONTROL_ROOT="/Volumes/MAC MINI M4/TFTMAC/Runtime" +readonly CONTROL_SDK="${CONTROL_ROOT}/SDK" +readonly CONTROL_AVD_HOME="${CONTROL_ROOT}/AVD" +readonly CONTROL_AVD_NAME="TFT_Ultra_Tablet" +readonly DIAGNOSTIC_ROOT="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow" +readonly DIAGNOSTIC_SDK="${DIAGNOSTIC_ROOT}/SDK" +readonly DIAGNOSTIC_AVD_HOME="${DIAGNOSTIC_ROOT}/AVD" +readonly DIAGNOSTIC_AVD_NAME="TFTMAC_Diagnostic_StockShadow_R1" +readonly DIAGNOSTIC_AVD="${DIAGNOSTIC_AVD_HOME}/${DIAGNOSTIC_AVD_NAME}.avd" +readonly DIAGNOSTIC_INI="${DIAGNOSTIC_AVD_HOME}/${DIAGNOSTIC_AVD_NAME}.ini" +readonly MANIFEST_ROOT="${DIAGNOSTIC_ROOT}/Manifests/${BUILD_ID}" +readonly MANIFEST="${MANIFEST_ROOT}/stock-shadow-runtime.json" +readonly CONTROL_EXECUTABLE="/Applications/TFTMAC.app/Contents/MacOS/TFTMAC" +readonly CONTROL_HOST="/Applications/TFTMAC.app/Contents/Resources/TFTMAC Emulator Host.app/Contents/MacOS/TFTMACEmulatorHost" +readonly EXPECTED_CONTROL_EXECUTABLE_SHA256="d3bf7c249a3e5f11b81f778b063e1a8cfe2e7fdeec0537ee6bd8447b1c2268d2" +readonly EXPECTED_CONTROL_HOST_SHA256="ea028ec1d74cc025638c2a0e5f8c783748803c1b0ba9012962c038251fb3eb63" + +fail() { + print -u2 "Stock-shadow build failed: $*" + exit 1 +} + +sha256() { + /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}' +} + +tree_sha256() { + local root="$1" + /usr/bin/find "$root" -type f -print0 \ + | /usr/bin/sort -z \ + | /usr/bin/xargs -0 /usr/bin/shasum -a 256 \ + | /usr/bin/shasum -a 256 \ + | /usr/bin/awk '{print $1}' +} + +uuid_receipt() { + /usr/bin/dwarfdump --uuid "$1" | /usr/bin/awk '{print $2 ":" $3}' | /usr/bin/tr -d '()' +} + +[[ "$(sha256 "${CONTROL_EXECUTABLE}")" == "${EXPECTED_CONTROL_EXECUTABLE_SHA256}" ]] \ + || fail "protected Control executable identity changed" +[[ "$(sha256 "${CONTROL_HOST}")" == "${EXPECTED_CONTROL_HOST_SHA256}" ]] \ + || fail "protected Control host identity changed" + +for port in 5582 8554 5586 8556; do + if /usr/sbin/lsof -nP -iTCP:"${port}" -sTCP:LISTEN 2>/dev/null | /usr/bin/grep -q LISTEN; then + fail "runtime port ${port} is active; close TFTMAC before cloning" + fi +done + +[[ -d "${CONTROL_SDK}/emulator" ]] || fail "Control emulator is missing" +[[ -d "${CONTROL_SDK}/platform-tools" ]] || fail "Control platform-tools are missing" +[[ -d "${CONTROL_SDK}/system-images/android-36/google_apis_playstore/arm64-v8a" ]] \ + || fail "Control API 36 Play image is missing" +[[ -d "${CONTROL_AVD_HOME}/${CONTROL_AVD_NAME}.avd" ]] || fail "Control AVD is missing" +[[ -f "${CONTROL_AVD_HOME}/${CONTROL_AVD_NAME}.ini" ]] || fail "Control AVD ini is missing" + +if [[ -e "${DIAGNOSTIC_SDK}" || -e "${DIAGNOSTIC_AVD}" || -e "${DIAGNOSTIC_INI}" ]]; then + fail "stock-shadow target already exists; refusing to overwrite" +fi + +readonly CONTROL_AVD_TREE_BEFORE="$(tree_sha256 "${CONTROL_AVD_HOME}/${CONTROL_AVD_NAME}.avd")" +/bin/mkdir -p "${DIAGNOSTIC_SDK}/system-images/android-36/google_apis_playstore" \ + "${DIAGNOSTIC_AVD_HOME}" "${MANIFEST_ROOT}" +/usr/bin/ditto --clone --noqtn "${CONTROL_SDK}/emulator" "${DIAGNOSTIC_SDK}/emulator" +/usr/bin/ditto --clone --noqtn "${CONTROL_SDK}/platform-tools" "${DIAGNOSTIC_SDK}/platform-tools" +/usr/bin/ditto --clone --noqtn \ + "${CONTROL_SDK}/system-images/android-36/google_apis_playstore/arm64-v8a" \ + "${DIAGNOSTIC_SDK}/system-images/android-36/google_apis_playstore/arm64-v8a" +/usr/bin/ditto --clone --noqtn \ + "${CONTROL_AVD_HOME}/${CONTROL_AVD_NAME}.avd" "${DIAGNOSTIC_AVD}" +/bin/cp "${CONTROL_AVD_HOME}/${CONTROL_AVD_NAME}.ini" "${DIAGNOSTIC_INI}" + +for mutable in multiinstance.lock hardware-qemu.ini emu-launch-params.txt read-snapshot.txt bootcompleted.ini; do + /bin/rm -f "${DIAGNOSTIC_AVD}/${mutable}" +done + +/usr/bin/sed -i '' \ + -e "s|^path=.*|path=${DIAGNOSTIC_AVD}|" \ + -e "s|^target=.*|target=android-36|" \ + "${DIAGNOSTIC_INI}" +/usr/bin/sed -i '' \ + -e "s|^avd.id=.*|avd.id=${DIAGNOSTIC_AVD_NAME}|" \ + -e "s|^avd.name=.*|avd.name=${DIAGNOSTIC_AVD_NAME}|" \ + -e "s|^AvdId=.*|AvdId=${DIAGNOSTIC_AVD_NAME}|" \ + -e "s|^avd.ini.displayname=.*|avd.ini.displayname=TFTMAC DEV Stock Shadow|" \ + -e "s|^hw.ramSize=.*|hw.ramSize=5120|" \ + -e "s|^fastboot.forceColdBoot=.*|fastboot.forceColdBoot=yes|" \ + "${DIAGNOSTIC_AVD}/config.ini" + +readonly CONTROL_AVD_TREE_AFTER="$(tree_sha256 "${CONTROL_AVD_HOME}/${CONTROL_AVD_NAME}.avd")" +[[ "${CONTROL_AVD_TREE_BEFORE}" == "${CONTROL_AVD_TREE_AFTER}" ]] \ + || fail "Control AVD changed while creating the stock shadow" + +readonly EMULATOR="${DIAGNOSTIC_SDK}/emulator/emulator" +readonly QEMU="${DIAGNOSTIC_SDK}/emulator/qemu/darwin-aarch64/qemu-system-aarch64" +readonly GFXSTREAM="${DIAGNOSTIC_SDK}/emulator/lib64/libgfxstream_backend.dylib" +readonly ADB="${DIAGNOSTIC_SDK}/platform-tools/adb" +readonly CONFIG="${DIAGNOSTIC_AVD}/config.ini" + +/usr/bin/jq -n \ + --arg build_id "${BUILD_ID}" \ + --arg emulator_path "${EMULATOR}" \ + --arg emulator_sha256 "$(sha256 "${EMULATOR}")" \ + --arg emulator_uuid "$(uuid_receipt "${EMULATOR}")" \ + --arg qemu_path "${QEMU}" \ + --arg qemu_sha256 "$(sha256 "${QEMU}")" \ + --arg qemu_uuid "$(uuid_receipt "${QEMU}")" \ + --arg gfxstream_path "${GFXSTREAM}" \ + --arg gfxstream_sha256 "$(sha256 "${GFXSTREAM}")" \ + --arg gfxstream_uuid "$(uuid_receipt "${GFXSTREAM}")" \ + --arg adb_path "${ADB}" \ + --arg adb_sha256 "$(sha256 "${ADB}")" \ + --arg avd_name "${DIAGNOSTIC_AVD_NAME}" \ + --arg avd_path "${DIAGNOSTIC_AVD}" \ + --arg avd_ini_path "${DIAGNOSTIC_INI}" \ + --arg avd_config_sha256 "$(sha256 "${CONFIG}")" \ + --arg avd_ini_sha256 "$(sha256 "${DIAGNOSTIC_INI}")" \ + --arg avd_tree_sha256 "$(tree_sha256 "${DIAGNOSTIC_AVD}")" \ + --arg control_avd_tree_sha256 "${CONTROL_AVD_TREE_AFTER}" \ + --arg control_executable_sha256 "${EXPECTED_CONTROL_EXECUTABLE_SHA256}" \ + --arg control_host_sha256 "${EXPECTED_CONTROL_HOST_SHA256}" \ + '{ + schema: 1, + state: "STOCK_SHADOW_RUNTIME_IDENTITY_PASS", + build_id: $build_id, + runtime_variant: "stock_shadow", + comparison_class: "STOCK_BUILD8_CONTROL_SHADOW", + first_boot_attempted: false, + control_runtime_touched: false, + control_avd_touched: false, + control_noninterference: { + matched: true, + avd_tree_sha256: $control_avd_tree_sha256, + executable_sha256: $control_executable_sha256, + host_sha256: $control_host_sha256 + }, + runtime: { + emulator: {path: $emulator_path, sha256: $emulator_sha256, uuid: $emulator_uuid}, + qemu: {path: $qemu_path, sha256: $qemu_sha256, uuid: $qemu_uuid}, + gfxstream: {path: $gfxstream_path, sha256: $gfxstream_sha256, uuid: $gfxstream_uuid}, + adb: {path: $adb_path, sha256: $adb_sha256}, + expected_emulator_version_contains: "37.1.11" + }, + avd: { + name: $avd_name, + path: $avd_path, + ini_path: $avd_ini_path, + config_sha256: $avd_config_sha256, + ini_sha256: $avd_ini_sha256, + tree_sha256: $avd_tree_sha256, + target: "android-36", + installer_authority: "com.android.vending" + }, + lease: {adb_server_port: 5041, console_port: 5586, controller_port: 8556, serial: "emulator-5586"}, + locked_profile: { + width: 1920, height: 1080, density_dpi: 320, refresh_hz: 60, + vcpu: 6, ram_mib: 5120, gpu_mode: "host", audio_backend: "coreaudio", + graphics_transport: "virtio-gpu-asg", asg_write_buffer_size: 1048576, + asg_write_step_size: 16384, asg_data_ring_size: 32768, + asg_draw_flush_interval: 800 + } + }' > "${MANIFEST}" + +readonly MANIFEST_SHA256="$(sha256 "${MANIFEST}")" +print -r -- "${MANIFEST_SHA256} ${MANIFEST:t}" > "${MANIFEST}.sha256" +print "Stock shadow created: ${MANIFEST}" +print "Manifest SHA-256: ${MANIFEST_SHA256}" diff --git a/scripts/build-vulkan-probe.command b/scripts/build-vulkan-probe.command new file mode 100755 index 0000000..3d17619 --- /dev/null +++ b/scripts/build-vulkan-probe.command @@ -0,0 +1,131 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly ROOT="${0:A:h:h}" +readonly SOURCE="${ROOT}/Probes/TFTMACVulkanProbe" +readonly SDK="/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK" +readonly NDK="${SDK}/ndk/29.0.14206865" +readonly TOOLCHAIN="${NDK}/toolchains/llvm/prebuilt/darwin-x86_64" +readonly BUILD_TOOLS="${SDK}/build-tools/36.0.0" +readonly ANDROID_JAR="${SDK}/platforms/android-37.0/android.jar" +readonly BUILD="${ROOT}/.build/vulkan-probe" +readonly PACKAGE_ROOT="${BUILD}/package" +readonly OUTPUT="${BUILD}/TFTMACVulkanProbe.apk" +readonly SIGNING_ROOT="${BUILD}/v1-signing" + +fail() { print -u2 -- "TFTMAC Vulkan probe build failed: $*"; exit 1; } +for file in \ + "${SOURCE}/AndroidManifest.xml" \ + "${SOURCE}/workload-manifest.json" \ + "${SOURCE}/src/main.cpp" \ + "${SOURCE}/shaders/probe.vert" \ + "${SOURCE}/shaders/probe.frag" \ + "${ANDROID_JAR}" \ + "${NDK}/sources/android/native_app_glue/android_native_app_glue.c"; do + [[ -f "${file}" ]] || fail "required input is missing: ${file}" +done + +/bin/rm -rf "${BUILD}" +/bin/mkdir -p "${BUILD}/obj" "${PACKAGE_ROOT}/lib/arm64-v8a" "${PACKAGE_ROOT}/assets" + +"${NDK}/shader-tools/darwin-x86_64/glslc" -O "${SOURCE}/shaders/probe.vert" -o "${PACKAGE_ROOT}/assets/probe.vert.spv" +"${NDK}/shader-tools/darwin-x86_64/glslc" -O "${SOURCE}/shaders/probe.frag" -o "${PACKAGE_ROOT}/assets/probe.frag.spv" +/bin/cp "${SOURCE}/workload-manifest.json" "${PACKAGE_ROOT}/assets/workload-manifest.json" + +"${TOOLCHAIN}/bin/aarch64-linux-android28-clang" \ + -O2 -fPIC \ + -I"${NDK}/sources/android/native_app_glue" \ + -c "${NDK}/sources/android/native_app_glue/android_native_app_glue.c" \ + -o "${BUILD}/obj/android_native_app_glue.o" + +"${TOOLCHAIN}/bin/aarch64-linux-android28-clang++" \ + -std=c++20 -O2 -fPIC -fvisibility=hidden -DVK_USE_PLATFORM_ANDROID_KHR \ + -I"${NDK}/sources/android/native_app_glue" \ + -shared \ + "${SOURCE}/src/main.cpp" \ + "${BUILD}/obj/android_native_app_glue.o" \ + -static-libstdc++ -Wl,--gc-sections -Wl,-soname,libtftmac_vulkan_probe.so \ + -landroid -llog -lvulkan \ + -o "${PACKAGE_ROOT}/lib/arm64-v8a/libtftmac_vulkan_probe.so" +"${TOOLCHAIN}/bin/llvm-strip" "${PACKAGE_ROOT}/lib/arm64-v8a/libtftmac_vulkan_probe.so" + +"${BUILD_TOOLS}/aapt" package -f -M "${SOURCE}/AndroidManifest.xml" -I "${ANDROID_JAR}" -F "${BUILD}/unsigned.apk" +( + cd "${PACKAGE_ROOT}" + "${BUILD_TOOLS}/aapt" add "${BUILD}/unsigned.apk" \ + lib/arm64-v8a/libtftmac_vulkan_probe.so \ + assets/probe.vert.spv \ + assets/probe.frag.spv \ + assets/workload-manifest.json >/dev/null +) +"${BUILD_TOOLS}/zipalign" -f 4 "${BUILD}/unsigned.apk" "${BUILD}/aligned.apk" + +# The host intentionally does not require a Java runtime. Produce a standards- +# compliant JAR/APK v1 signature with the system OpenSSL implementation. This +# key signs only the local, owned probe and is regenerated for every build. +/bin/mkdir -p "${SIGNING_ROOT}/META-INF" +/usr/bin/openssl req -new -x509 -newkey rsa:2048 -nodes -sha256 -days 30 \ + -subj "/CN=TFTMAC Vulkan Probe/O=flashls1/C=US" \ + -keyout "${SIGNING_ROOT}/probe-key.pem" \ + -out "${SIGNING_ROOT}/probe-cert.pem" >/dev/null 2>&1 + +readonly MANIFEST_MF="${SIGNING_ROOT}/META-INF/MANIFEST.MF" +readonly CERT_SF="${SIGNING_ROOT}/META-INF/CERT.SF" +readonly CERT_RSA="${SIGNING_ROOT}/META-INF/CERT.RSA" +readonly MANIFEST_SECTION="${SIGNING_ROOT}/manifest-section.bin" +/usr/bin/printf 'Manifest-Version: 1.0\r\nCreated-By: TFTMAC Vulkan Probe\r\n\r\n' > "${MANIFEST_MF}" +while IFS= read -r entry; do + [[ -n "${entry}" && "${entry}" != META-INF/* && "${entry}" != */ ]] || continue + ENTRY_DIGEST="$(/usr/bin/unzip -p "${BUILD}/aligned.apk" "${entry}" | /usr/bin/openssl dgst -sha256 -binary | /usr/bin/base64)" + /usr/bin/printf 'Name: %s\r\nSHA-256-Digest: %s\r\n\r\n' "${entry}" "${ENTRY_DIGEST}" > "${MANIFEST_SECTION}" + /bin/cat "${MANIFEST_SECTION}" >> "${MANIFEST_MF}" +done < <(/usr/bin/unzip -Z1 "${BUILD}/aligned.apk") +readonly MANIFEST_DIGEST="$(/usr/bin/openssl dgst -sha256 -binary "${MANIFEST_MF}" | /usr/bin/base64)" +/usr/bin/printf 'Signature-Version: 1.0\r\nCreated-By: TFTMAC Vulkan Probe\r\nSHA-256-Digest-Manifest: %s\r\n\r\n' \ + "${MANIFEST_DIGEST}" > "${CERT_SF}" +while IFS= read -r entry; do + [[ -n "${entry}" && "${entry}" != META-INF/* && "${entry}" != */ ]] || continue + ENTRY_DIGEST="$(/usr/bin/unzip -p "${BUILD}/aligned.apk" "${entry}" | /usr/bin/openssl dgst -sha256 -binary | /usr/bin/base64)" + /usr/bin/printf 'Name: %s\r\nSHA-256-Digest: %s\r\n\r\n' "${entry}" "${ENTRY_DIGEST}" > "${MANIFEST_SECTION}" + SECTION_DIGEST="$(/usr/bin/openssl dgst -sha256 -binary "${MANIFEST_SECTION}" | /usr/bin/base64)" + /usr/bin/printf 'Name: %s\r\nSHA-256-Digest: %s\r\n\r\n' "${entry}" "${SECTION_DIGEST}" >> "${CERT_SF}" +done < <(/usr/bin/unzip -Z1 "${BUILD}/aligned.apk") +/usr/bin/openssl cms -sign -binary -md sha256 -nosmimecap \ + -in "${CERT_SF}" \ + -signer "${SIGNING_ROOT}/probe-cert.pem" \ + -inkey "${SIGNING_ROOT}/probe-key.pem" \ + -outform DER -out "${CERT_RSA}" +/bin/cp "${BUILD}/aligned.apk" "${OUTPUT}" +( + cd "${SIGNING_ROOT}" + /usr/bin/zip -q -0 "${OUTPUT}" META-INF/MANIFEST.MF META-INF/CERT.SF META-INF/CERT.RSA +) +/usr/bin/unzip -p "${OUTPUT}" META-INF/CERT.SF > "${BUILD}/verify-cert.sf" +/usr/bin/unzip -p "${OUTPUT}" META-INF/CERT.RSA > "${BUILD}/verify-cert.rsa" +/usr/bin/openssl cms -verify -binary -inform DER -noverify \ + -in "${BUILD}/verify-cert.rsa" \ + -content "${BUILD}/verify-cert.sf" \ + -out /dev/null >/dev/null 2>&1 +readonly NODE="$(command -v node)" +[[ -x "${NODE}" ]] || fail "Node.js is required for the local APK v2 signing block" +"${NODE}" "${ROOT}/scripts/sign-apk-v2.mjs" \ + --input "${OUTPUT}" \ + --key "${SIGNING_ROOT}/probe-key.pem" \ + --cert "${SIGNING_ROOT}/probe-cert.pem" \ + --output "${BUILD}/v2-signed.apk" +/bin/mv "${BUILD}/v2-signed.apk" "${OUTPUT}" + +readonly APK_SHA="$(/usr/bin/shasum -a 256 "${OUTPUT}" | /usr/bin/awk '{print $1}')" +readonly MANIFEST_SHA="$(/usr/bin/shasum -a 256 "${SOURCE}/workload-manifest.json" | /usr/bin/awk '{print $1}')" +readonly LIB_SHA="$(/usr/bin/shasum -a 256 "${PACKAGE_ROOT}/lib/arm64-v8a/libtftmac_vulkan_probe.so" | /usr/bin/awk '{print $1}')" + +/usr/bin/jq -n \ + --arg apk "${OUTPUT}" --arg apk_sha256 "${APK_SHA}" \ + --arg workload_manifest "${SOURCE}/workload-manifest.json" --arg workload_manifest_sha256 "${MANIFEST_SHA}" \ + --arg native_library_sha256 "${LIB_SHA}" \ + '{schema:1,state:"TFTMAC_VULKAN_PROBE_BUILD_PASS",package:"com.flashls1.tftmac.vulkanprobe",abi:"arm64-v8a",min_sdk:28,target_sdk:36,apk:$apk,apk_sha256:$apk_sha256,workload_manifest:$workload_manifest,workload_manifest_sha256:$workload_manifest_sha256,native_library_sha256:$native_library_sha256,signing:"APK_V1_AND_V2_SHA256_RSA_LOCAL_EPHEMERAL",network_access:false,riot_interaction:false}' \ + > "${BUILD}/build-receipt.json" + +print -- "${OUTPUT}" +print -- "TFTMAC Vulkan probe build receipt: ${BUILD}/build-receipt.json" diff --git a/scripts/install-desktop-launchers.command b/scripts/install-desktop-launchers.command new file mode 100755 index 0000000..721ce38 --- /dev/null +++ b/scripts/install-desktop-launchers.command @@ -0,0 +1,61 @@ +#!/bin/zsh +set -euo pipefail + +readonly ROOT="${0:A:h:h}" +readonly CONTROL_APP="/Applications/TFTMAC.app" +readonly CONTROL_LAUNCHER_SOURCE="${ROOT}/dist/TFTMAC Control Launcher.app" +readonly CONTROL_LAUNCHER_APP="/Applications/TFTMAC Control Launcher.app" +readonly DEV_SOURCE="${ROOT}/dist/TFTMAC DEV.app" +readonly DEV_APP="/Applications/TFTMAC DEV.app" +readonly CONTROL_DESKTOP="${HOME}/Desktop/TFTMAC.app" +readonly DEV_DESKTOP="${HOME}/Desktop/TFTMAC DEV.app" +readonly CONTROL_EXECUTABLE_SHA256="d3bf7c249a3e5f11b81f778b063e1a8cfe2e7fdeec0537ee6bd8447b1c2268d2" +readonly CONTROL_HOST_SHA256="ea028ec1d74cc025638c2a0e5f8c783748803c1b0ba9012962c038251fb3eb63" + +fail() { + print -u2 "TFTMAC launcher install failed: $*" + exit 1 +} + +[[ -d "${CONTROL_APP}" ]] || fail "protected Control app is missing" +[[ -d "${CONTROL_LAUNCHER_SOURCE}" ]] || fail "build the TFTMAC Control launcher first" +[[ -d "${DEV_SOURCE}" ]] || fail "build TFTMAC DEV first" +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/MacOS/TFTMAC" | /usr/bin/awk '{print $1}')" == "${CONTROL_EXECUTABLE_SHA256}" ]] \ + || fail "protected Control executable identity changed" +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/Resources/TFTMAC Emulator Host.app/Contents/MacOS/TFTMACEmulatorHost" | /usr/bin/awk '{print $1}')" == "${CONTROL_HOST_SHA256}" ]] \ + || fail "protected Control emulator-host identity changed" +/usr/bin/codesign --verify --deep --strict --verbose=2 "${DEV_SOURCE}" +/usr/bin/codesign --verify --strict --verbose=2 "${CONTROL_LAUNCHER_SOURCE}" +[[ "$(/usr/bin/plutil -extract CFBundleIdentifier raw "${DEV_SOURCE}/Contents/Info.plist")" == "com.flashls1.tftmac.dev" ]] \ + || fail "DEV source bundle identity is not isolated" + +/bin/rm -rf "${DEV_APP}" +/usr/bin/ditto "${DEV_SOURCE}" "${DEV_APP}" +/usr/bin/codesign --verify --deep --strict --verbose=2 "${DEV_APP}" +/bin/rm -rf "${CONTROL_LAUNCHER_APP}" +/usr/bin/ditto "${CONTROL_LAUNCHER_SOURCE}" "${CONTROL_LAUNCHER_APP}" +/usr/bin/codesign --verify --strict --verbose=2 "${CONTROL_LAUNCHER_APP}" + +if [[ -L "${CONTROL_DESKTOP}" ]]; then + /bin/rm "${CONTROL_DESKTOP}" +elif [[ -e "${CONTROL_DESKTOP}" ]]; then + fail "Desktop TFTMAC.app exists but is not the protected Control launcher" +fi +/bin/ln -s "${CONTROL_LAUNCHER_APP}" "${CONTROL_DESKTOP}" + +if [[ -L "${DEV_DESKTOP}" ]]; then + [[ "$(/usr/bin/readlink "${DEV_DESKTOP}")" == "${DEV_APP}" ]] \ + || fail "existing Desktop TFTMAC DEV launcher points somewhere unexpected" +elif [[ -e "${DEV_DESKTOP}" ]]; then + fail "Desktop TFTMAC DEV.app exists and was not replaced" +else + /bin/ln -s "${DEV_APP}" "${DEV_DESKTOP}" +fi + +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/MacOS/TFTMAC" | /usr/bin/awk '{print $1}')" == "${CONTROL_EXECUTABLE_SHA256}" ]] \ + || fail "Control executable changed during DEV installation" +[[ "$(/usr/bin/shasum -a 256 "${CONTROL_APP}/Contents/Resources/TFTMAC Emulator Host.app/Contents/MacOS/TFTMACEmulatorHost" | /usr/bin/awk '{print $1}')" == "${CONTROL_HOST_SHA256}" ]] \ + || fail "Control emulator host changed during DEV installation" + +print "Control launcher: ${CONTROL_DESKTOP} -> ${CONTROL_LAUNCHER_APP} -> ${CONTROL_APP}" +print "Developer launcher: ${DEV_DESKTOP} -> ${DEV_APP}" diff --git a/scripts/prepare-causal-source-runtime.command b/scripts/prepare-causal-source-runtime.command new file mode 100755 index 0000000..ae0bd33 --- /dev/null +++ b/scripts/prepare-causal-source-runtime.command @@ -0,0 +1,89 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly LEGACY_SOURCE="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Sources/aemu" +readonly SOURCE_IMAGE_ROOT="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/SourceVolumes" +readonly SOURCE_IMAGE="${SOURCE_IMAGE_ROOT}/TFTMAC-Causal-Source.sparsebundle" +readonly SOURCE_VOLUME_NAME="TFTMAC Causal Source" +readonly SOURCE_MOUNT="/Volumes/${SOURCE_VOLUME_NAME}" +readonly SOURCE_ROOT="${SOURCE_MOUNT}/emu-main-dev-2692acc6" +readonly RECEIPT_ROOT="/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/causal-source-20260902" +readonly REPO_LAUNCHER="${LEGACY_SOURCE}/.repo/repo/repo" +readonly MANIFEST_URL="https://android.googlesource.com/platform/manifest" +readonly MANIFEST_BRANCH="emu-main-dev" +readonly MANIFEST_COMMIT="2692acc620f6563b21995540656674faeb536cdc" + +fail() { print -u2 "TFTMAC causal source preparation failed: $*"; exit 1; } + +[[ -x "${REPO_LAUNCHER}" ]] || fail "Android repo launcher is unavailable" +[[ -d "${LEGACY_SOURCE}/.repo" ]] || fail "preserved reference checkout is unavailable" +if /bin/ps -axo command | /usr/bin/grep -E '/Applications/TFTMAC( DEV)?\.app/Contents/MacOS/' | /usr/bin/grep -v grep >/dev/null; then + fail "Control or DEV is running; source synchronization is intentionally deferred" +fi + +/bin/mkdir -p "${SOURCE_IMAGE_ROOT}" "${RECEIPT_ROOT}" +if [[ ! -e "${SOURCE_IMAGE}" ]]; then + /usr/bin/hdiutil create \ + -quiet \ + -type SPARSEBUNDLE \ + -size 180g \ + -fs "Case-sensitive APFS" \ + -volname "${SOURCE_VOLUME_NAME}" \ + "${SOURCE_IMAGE}" +fi +if [[ ! -d "${SOURCE_MOUNT}" ]]; then + /usr/bin/hdiutil attach -quiet -nobrowse -owners on "${SOURCE_IMAGE}" +fi +[[ -d "${SOURCE_MOUNT}" ]] || fail "case-sensitive source volume did not mount" +readonly CASE_PROBE_UPPER="${SOURCE_MOUNT}/.TFTMAC_CASE_PROBE" +readonly CASE_PROBE_LOWER="${SOURCE_MOUNT}/.tftmac_case_probe" +/usr/bin/touch "${CASE_PROBE_UPPER}" +if [[ -e "${CASE_PROBE_LOWER}" ]]; then + /bin/rm -f "${CASE_PROBE_UPPER}" + fail "source volume is not case-sensitive" +fi +/bin/rm -f "${CASE_PROBE_UPPER}" + +/bin/mkdir -p "${SOURCE_ROOT}" +if [[ ! -d "${SOURCE_ROOT}/.repo" ]]; then + ( + cd "${SOURCE_ROOT}" + "${REPO_LAUNCHER}" init \ + -u "${MANIFEST_URL}" \ + -b "${MANIFEST_BRANCH}" \ + --reference="${LEGACY_SOURCE}" \ + --no-clone-bundle \ + --no-tags + ) +fi + +/usr/bin/git -C "${SOURCE_ROOT}/.repo/manifests" fetch origin "${MANIFEST_COMMIT}" +/usr/bin/git -C "${SOURCE_ROOT}/.repo/manifests" checkout --detach "${MANIFEST_COMMIT}" +( + cd "${SOURCE_ROOT}" + "${REPO_LAUNCHER}" sync -c -j4 --no-clone-bundle --no-tags + "${REPO_LAUNCHER}" manifest -r -o "${RECEIPT_ROOT}/source-lock.xml" +) + +readonly MANIFEST_HEAD="$(/usr/bin/git -C "${SOURCE_ROOT}/.repo/manifests" rev-parse HEAD)" +[[ "${MANIFEST_HEAD}" == "${MANIFEST_COMMIT}" ]] || fail "manifest commit drifted" +for project in external/qemu hardware/google/gfxstream external/moltenvk; do + [[ -d "${SOURCE_ROOT}/${project}/.git" || -f "${SOURCE_ROOT}/${project}/.git" ]] \ + || fail "required project is missing: ${project}" +done + +/usr/bin/jq -n \ + --arg state "CAUSAL_SOURCE_LOCK_PASS" \ + --arg source_root "${SOURCE_ROOT}" \ + --arg source_image "${SOURCE_IMAGE}" \ + --arg source_mount "${SOURCE_MOUNT}" \ + --arg manifest_commit "${MANIFEST_COMMIT}" \ + --arg manifest_sha256 "$(/usr/bin/shasum -a 256 "${RECEIPT_ROOT}/source-lock.xml" | /usr/bin/awk '{print $1}')" \ + --arg qemu_commit "$(/usr/bin/git -C "${SOURCE_ROOT}/external/qemu" rev-parse HEAD)" \ + --arg gfxstream_commit "$(/usr/bin/git -C "${SOURCE_ROOT}/hardware/google/gfxstream" rev-parse HEAD)" \ + --arg moltenvk_commit "$(/usr/bin/git -C "${SOURCE_ROOT}/external/moltenvk" rev-parse HEAD)" \ + '{schema:1,state:$state,source_root:$source_root,source_storage:{image:$source_image,mount:$source_mount,filesystem:"case-sensitive APFS",sparse_maximum_bytes:193273528320},manifest_commit:$manifest_commit,revision_locked_manifest:{path:"source-lock.xml",sha256:$manifest_sha256},projects:{qemu:$qemu_commit,gfxstream:$gfxstream_commit,moltenvk:$moltenvk_commit},sync_jobs:4,control_touched:false,legacy_dirty_source_touched:false}' \ + > "${RECEIPT_ROOT}/source-receipt.json" + +print "TFTMAC causal source: READY (${SOURCE_ROOT})" diff --git a/scripts/run-vulkan-experiment-campaign.command b/scripts/run-vulkan-experiment-campaign.command new file mode 100755 index 0000000..e4dea4c --- /dev/null +++ b/scripts/run-vulkan-experiment-campaign.command @@ -0,0 +1,133 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly ROOT="${0:A:h:h}" +readonly DEV_APP="/Applications/TFTMAC DEV.app" +readonly CONTROL_APP="/Applications/TFTMAC.app" +readonly CAPTURE_ROOT="${HOME}/Library/Application Support/TFTMAC/Modes/advanced_diagnostics/Captures" +readonly EXPERIMENT_ROOT="${HOME}/Library/Application Support/TFTMAC/Modes/advanced_diagnostics/Experiments" +readonly RUNNER_LOCK="${HOME}/Library/Application Support/TFTMAC/Modes/advanced_diagnostics/State/vulkan-campaign-runner.lock" +readonly CONTROL_EXECUTABLE="${CONTROL_APP}/Contents/MacOS/TFTMAC" +readonly CONTROL_EMULATOR="/Volumes/MAC MINI M4/TFTMAC/Runtime/SDK/emulator/emulator" +readonly CONTROL_AVD="/Volumes/MAC MINI M4/TFTMAC/Runtime/AVD/TFT_Ultra_Tablet.avd" +readonly KEYCHAIN_SERVICE="com.flashls1.tftmac.android-unlock.v2" +readonly KEYCHAIN_ACCOUNT="android-user-0" +readonly RUN_TIMEOUT_SECONDS=900 + +fail() { print -u2 -- "TFTMAC Vulkan campaign failed: $*"; exit 1; } +[[ -d "${DEV_APP}" ]] || fail "${DEV_APP} is not installed" +[[ -x "${CONTROL_EXECUTABLE}" && -x "${CONTROL_EMULATOR}" ]] || fail "Control authority is unavailable" +[[ -f "${DEV_APP}/Contents/Resources/TFTMACVulkanProbe.apk" ]] || fail "installed DEV app has no owned Vulkan probe" +[[ -f "${DEV_APP}/Contents/Resources/workload-manifest.json" ]] || fail "installed DEV app has no workload manifest" +/usr/bin/security find-generic-password \ + -s "${KEYCHAIN_SERVICE}" \ + -a "${KEYCHAIN_ACCOUNT}" \ + "${HOME}/Library/Keychains/login.keychain-db" >/dev/null 2>&1 \ + || fail "secure unlock is not initialized; run scripts/setup-android-unlock.command once" + +if /usr/bin/pgrep -f '/Applications/TFTMAC.app/Contents/MacOS/TFTMAC|@TFTMAC[^ ]*.*-port 5582' >/dev/null; then + fail "Control is running; it will not be disturbed" +fi +if /usr/bin/pgrep -f '/Applications/TFTMAC DEV.app/Contents/MacOS|@TFTMAC_Diagnostic_StockShadow_R1' >/dev/null; then + fail "TFTMAC DEV or its diagnostic emulator is already running" +fi + +/bin/mkdir -p "${RUNNER_LOCK:h}" "${EXPERIMENT_ROOT}" +/bin/mkdir "${RUNNER_LOCK}" 2>/dev/null || fail "another DEV campaign owns the runner lease" +cleanup() { /bin/rmdir "${RUNNER_LOCK}" 2>/dev/null || true } +trap cleanup EXIT INT TERM + +tree_hash() { + local target="$1" + /usr/bin/find "${target}" -type f -print0 \ + | /usr/bin/sort -z \ + | /usr/bin/xargs -0 /usr/bin/shasum -a 256 \ + | /usr/bin/shasum -a 256 \ + | /usr/bin/awk '{print $1}' +} + +readonly CAMPAIGN_ID="$(/bin/date -u +%Y-%m-%dT%H-%M-%SZ)-$(/usr/bin/uuidgen | /usr/bin/tr '[:upper:]' '[:lower:]')" +readonly CAMPAIGN="${EXPERIMENT_ROOT}/${CAMPAIGN_ID}" +/bin/mkdir -m 700 "${CAMPAIGN}" "${CAMPAIGN}/runs" "${CAMPAIGN}/profiles" +readonly CONTROL_EXECUTABLE_BEFORE="$(/usr/bin/shasum -a 256 "${CONTROL_EXECUTABLE}" | /usr/bin/awk '{print $1}')" +readonly CONTROL_EMULATOR_BEFORE="$(/usr/bin/shasum -a 256 "${CONTROL_EMULATOR}" | /usr/bin/awk '{print $1}')" +readonly CONTROL_AVD_BEFORE="$(tree_hash "${CONTROL_AVD}")" +readonly WORKLOAD_MANIFEST_SHA="$(/usr/bin/shasum -a 256 "${DEV_APP}/Contents/Resources/workload-manifest.json" | /usr/bin/awk '{print $1}')" + +profiles=(control queue_submit_inline control virtual_queue_off control fence_contexts_off control) +for index in {1..7}; do + profile="${profiles[$index]}" + print -- "TFTMAC Vulkan campaign ${index}/7: ${profile}" + /usr/bin/open -n -W \ + --env "TFTMAC_DEV_WORKLOAD=owned_vulkan_probe" \ + --env "TFTMAC_DEV_EXPERIMENT_PROFILE=${profile}" \ + "${DEV_APP}" & + open_pid=$! + deadline=$(( EPOCHSECONDS + RUN_TIMEOUT_SECONDS )) + while /bin/kill -0 "${open_pid}" 2>/dev/null; do + if (( EPOCHSECONDS >= deadline )); then + dev_pid="$(/usr/bin/pgrep -f '^/Applications/TFTMAC DEV\.app/Contents/MacOS/TFTMACDEVCore$' || true)" + [[ -z "${dev_pid}" ]] || /bin/kill -TERM "${dev_pid}" + /bin/kill -TERM "${open_pid}" 2>/dev/null || true + wait "${open_pid}" 2>/dev/null || true + fail "run ${index} exceeded the ${RUN_TIMEOUT_SECONDS}-second bounded runtime" + fi + /bin/sleep 1 + done + wait "${open_pid}" + capture="$(/bin/ls -1dt "${CAPTURE_ROOT}"/* 2>/dev/null | /usr/bin/head -n 1)" + [[ -n "${capture}" && -f "${capture}/TFTMAC_NATIVE_RUNTIME.sqlite" ]] \ + || fail "run ${index} did not produce a capture database" + database="${capture}/TFTMAC_NATIVE_RUNTIME.sqlite" + session_id="$(/usr/bin/sqlite3 "${database}" "SELECT session_id FROM sessions LIMIT 1")" + observed_profile="$(/usr/bin/sqlite3 "${database}" "SELECT experiment_profile_id FROM pipeline_experiment_runs LIMIT 1")" + observed_state="$(/usr/bin/sqlite3 "${database}" "SELECT state FROM pipeline_experiment_runs LIMIT 1")" + [[ "${observed_profile}" == "${profile}" ]] || fail "run ${index} profile receipt drifted" + [[ "${observed_state}" == "PASS" ]] || fail "run ${index} did not pass" + configuration_sha="$(/usr/bin/sqlite3 "${database}" "SELECT configuration_sha256 FROM pipeline_experiment_runs LIMIT 1")" + database_sha="$(/usr/bin/shasum -a 256 "${database}" | /usr/bin/awk '{print $1}')" + window_count="$(/usr/bin/sqlite3 "${database}" "SELECT COUNT(*) FROM events WHERE kind='OWNED_VULKAN_PROBE_WINDOW'")" + [[ "${window_count}" -ge 295 ]] || fail "run ${index} has only ${window_count} probe windows" + /usr/bin/jq -n \ + --argjson sequence "${index}" \ + --arg profile "${profile}" \ + --arg session_id "${session_id}" \ + --arg capture_path "${capture}" \ + --arg database "${database}" \ + --arg database_sha256 "${database_sha}" \ + --arg configuration_sha256 "${configuration_sha}" \ + --arg workload_manifest_sha256 "${WORKLOAD_MANIFEST_SHA}" \ + --argjson window_count "${window_count}" \ + '{schema:1,sequence:$sequence,profile:$profile,session_id:$session_id,capture_path:$capture_path,database:$database,database_sha256:$database_sha256,configuration_sha256:$configuration_sha256,workload_manifest_sha256:$workload_manifest_sha256,probe_window_count:$window_count,state:"PASS",privacy:"LOCAL_SENSITIVE_NOT_FOR_GIT"}' \ + > "${CAMPAIGN}/runs/$(/usr/bin/printf '%02d' "${index}")-${profile}.json" + /usr/bin/jq -n \ + --arg id "${profile}" --arg base_runtime_variant stock_shadow \ + --arg effective_configuration_sha256 "${configuration_sha}" \ + --arg workload_manifest_sha256 "${WORKLOAD_MANIFEST_SHA}" \ + --argjson duration_seconds 330 --argjson warmup_seconds 30 \ + '{schema:1,contract:"DevExperimentProfile",id:$id,base_runtime_variant:$base_runtime_variant,effective_configuration_sha256:$effective_configuration_sha256,workload_manifest_sha256:$workload_manifest_sha256,duration_seconds:$duration_seconds,warmup_seconds:$warmup_seconds,correctness_requirements:["image","input","audio","crash","leak","cleanup","event_loss"]}' \ + > "${CAMPAIGN}/profiles/$(/usr/bin/printf '%02d' "${index}")-${profile}.json" +done + +readonly CONTROL_EXECUTABLE_AFTER="$(/usr/bin/shasum -a 256 "${CONTROL_EXECUTABLE}" | /usr/bin/awk '{print $1}')" +readonly CONTROL_EMULATOR_AFTER="$(/usr/bin/shasum -a 256 "${CONTROL_EMULATOR}" | /usr/bin/awk '{print $1}')" +readonly CONTROL_AVD_AFTER="$(tree_hash "${CONTROL_AVD}")" +[[ "${CONTROL_EXECUTABLE_AFTER}" == "${CONTROL_EXECUTABLE_BEFORE}" ]] || fail "Control executable changed" +[[ "${CONTROL_EMULATOR_AFTER}" == "${CONTROL_EMULATOR_BEFORE}" ]] || fail "Control emulator changed" +[[ "${CONTROL_AVD_AFTER}" == "${CONTROL_AVD_BEFORE}" ]] || fail "Control AVD changed" + +readonly NODE="$(command -v node)" +"${NODE}" "${ROOT}/scripts/analyze-vulkan-experiment-campaign.mjs" "${CAMPAIGN}" +/usr/bin/jq -n \ + --arg state TFTMAC_VULKAN_CAMPAIGN_PASS \ + --arg campaign_id "${CAMPAIGN_ID}" \ + --arg control_executable_before "${CONTROL_EXECUTABLE_BEFORE}" \ + --arg control_executable_after "${CONTROL_EXECUTABLE_AFTER}" \ + --arg control_emulator_before "${CONTROL_EMULATOR_BEFORE}" \ + --arg control_emulator_after "${CONTROL_EMULATOR_AFTER}" \ + --arg control_avd_before "${CONTROL_AVD_BEFORE}" \ + --arg control_avd_after "${CONTROL_AVD_AFTER}" \ + '{schema:1,state:$state,campaign_id:$campaign_id,control_unchanged:($control_executable_before==$control_executable_after and $control_emulator_before==$control_emulator_after and $control_avd_before==$control_avd_after),control_executable_sha256:$control_executable_after,control_emulator_sha256:$control_emulator_after,control_avd_tree_sha256:$control_avd_after}' \ + > "${CAMPAIGN}/control-integrity-receipt.json" +print -- "${CAMPAIGN}" diff --git a/scripts/setup-android-unlock.command b/scripts/setup-android-unlock.command new file mode 100644 index 0000000..8b3da1d --- /dev/null +++ b/scripts/setup-android-unlock.command @@ -0,0 +1,21 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly DEV_APP="/Applications/TFTMAC DEV.app" +readonly KEYCHAIN_SERVICE="com.flashls1.tftmac.android-unlock.v2" +readonly KEYCHAIN_ACCOUNT="android-user-0" + +fail() { print -u2 "TFTMAC unlock setup failed: $*"; exit 1; } +[[ -d "${DEV_APP}" ]] || fail "TFTMAC DEV is not installed" +if /usr/bin/pgrep -f '/Applications/TFTMAC( DEV)?\.app/Contents/MacOS/|@TFTMAC(_Diagnostic)?' >/dev/null; then + fail "Control or DEV is already running" +fi + +/usr/bin/open -n -W --env "TFTMAC_UNLOCK_SETUP_ONLY=1" "${DEV_APP}" +/usr/bin/security find-generic-password \ + -s "${KEYCHAIN_SERVICE}" \ + -a "${KEYCHAIN_ACCOUNT}" \ + "${HOME}/Library/Keychains/login.keychain-db" >/dev/null \ + || fail "the secure Keychain item was not created" +print "TFTMAC Android unlock setup: PASS" diff --git a/scripts/sign-apk-v2.mjs b/scripts/sign-apk-v2.mjs new file mode 100755 index 0000000..aaf653f --- /dev/null +++ b/scripts/sign-apk-v2.mjs @@ -0,0 +1,132 @@ +#!/usr/bin/env node + +import { readFileSync, writeFileSync } from "node:fs"; +import { createHash, createPrivateKey, sign, X509Certificate } from "node:crypto"; + +const APK_SIGNATURE_SCHEME_V2_ID = 0x7109871a; +const RSA_PKCS1_SHA256_ID = 0x0103; +const EOCD_SIGNATURE = 0x06054b50; +const APK_SIGNING_BLOCK_MAGIC = Buffer.from("APK Sig Block 42", "ascii"); +const CHUNK_SIZE = 1024 * 1024; + +function fail(message) { + throw new Error(`APK v2 signing failed: ${message}`); +} + +function u32(value) { + const result = Buffer.alloc(4); + result.writeUInt32LE(value >>> 0); + return result; +} + +function u64(value) { + const result = Buffer.alloc(8); + result.writeBigUInt64LE(BigInt(value)); + return result; +} + +function lengthPrefixed(bytes) { + return Buffer.concat([u32(bytes.length), bytes]); +} + +function findEocd(apk) { + const minimumOffset = Math.max(0, apk.length - 65_557); + for (let offset = apk.length - 22; offset >= minimumOffset; offset -= 1) { + if (apk.readUInt32LE(offset) !== EOCD_SIGNATURE) continue; + const commentLength = apk.readUInt16LE(offset + 20); + if (offset + 22 + commentLength === apk.length) return offset; + } + fail("ZIP end-of-central-directory record was not found"); +} + +function chunkedContentDigest(sections) { + const digests = []; + for (const section of sections) { + for (let offset = 0; offset < section.length; offset += CHUNK_SIZE) { + const chunk = section.subarray(offset, Math.min(section.length, offset + CHUNK_SIZE)); + digests.push(createHash("sha256") + .update(Buffer.from([0xa5])) + .update(u32(chunk.length)) + .update(chunk) + .digest()); + } + } + return createHash("sha256") + .update(Buffer.from([0x5a])) + .update(u32(digests.length)) + .update(Buffer.concat(digests)) + .digest(); +} + +function parseArguments(argv) { + const values = new Map(); + for (let index = 2; index < argv.length; index += 2) { + values.set(argv[index], argv[index + 1]); + } + for (const name of ["--input", "--key", "--cert", "--output"]) { + if (!values.get(name)) fail(`missing ${name}`); + } + return values; +} + +const args = parseArguments(process.argv); +const apk = readFileSync(args.get("--input")); +const eocdOffset = findEocd(apk); +const centralDirectoryOffset = apk.readUInt32LE(eocdOffset + 16); +const centralDirectorySize = apk.readUInt32LE(eocdOffset + 12); +if (centralDirectoryOffset + centralDirectorySize !== eocdOffset) { + fail("ZIP64 or a non-contiguous central directory is not supported"); +} + +const beforeCentralDirectory = apk.subarray(0, centralDirectoryOffset); +const centralDirectory = apk.subarray(centralDirectoryOffset, eocdOffset); +const digestEocd = Buffer.from(apk.subarray(eocdOffset)); +// Verification removes the signing block and rewrites this field to the +// signing-block start before calculating the protected content digest. +digestEocd.writeUInt32LE(centralDirectoryOffset, 16); +const contentDigest = chunkedContentDigest([ + beforeCentralDirectory, + centralDirectory, + digestEocd, +]); + +const certificate = new X509Certificate(readFileSync(args.get("--cert"))); +const certificateDer = certificate.raw; +const publicKeyDer = certificate.publicKey.export({ type: "spki", format: "der" }); +const digestRecord = Buffer.concat([u32(RSA_PKCS1_SHA256_ID), lengthPrefixed(contentDigest)]); +const signedData = Buffer.concat([ + lengthPrefixed(lengthPrefixed(digestRecord)), + lengthPrefixed(lengthPrefixed(certificateDer)), + lengthPrefixed(Buffer.alloc(0)), +]); +const privateKey = createPrivateKey(readFileSync(args.get("--key"))); +const signature = sign("sha256", signedData, privateKey); +const signatureRecord = Buffer.concat([u32(RSA_PKCS1_SHA256_ID), lengthPrefixed(signature)]); +const signer = Buffer.concat([ + lengthPrefixed(signedData), + lengthPrefixed(lengthPrefixed(signatureRecord)), + lengthPrefixed(publicKeyDer), +]); +const v2Value = lengthPrefixed(lengthPrefixed(signer)); +const pair = Buffer.concat([ + u64(4 + v2Value.length), + u32(APK_SIGNATURE_SCHEME_V2_ID), + v2Value, +]); +const blockSize = pair.length + 24; +const signingBlock = Buffer.concat([ + u64(blockSize), + pair, + u64(blockSize), + APK_SIGNING_BLOCK_MAGIC, +]); + +const outputEocd = Buffer.from(apk.subarray(eocdOffset)); +outputEocd.writeUInt32LE(centralDirectoryOffset + signingBlock.length, 16); +const output = Buffer.concat([ + beforeCentralDirectory, + signingBlock, + centralDirectory, + outputEocd, +]); +writeFileSync(args.get("--output"), output, { mode: 0o644 }); diff --git a/scripts/test-causal-runtime.command b/scripts/test-causal-runtime.command new file mode 100755 index 0000000..bd7e1f1 --- /dev/null +++ b/scripts/test-causal-runtime.command @@ -0,0 +1,15 @@ +#!/bin/zsh +set -euo pipefail +unsetopt BG_NICE + +readonly ROOT="${0:A:h:h}" +readonly OUTPUT="${ROOT}/.build/causal-runtime/PipelineEventV1_test" +/bin/mkdir -p "${OUTPUT:h}" +/usr/bin/xcrun --sdk macosx clang++ \ + -std=c++20 -O2 -Wall -Wextra -Werror \ + -I "${ROOT}/CausalRuntime" \ + "${ROOT}/CausalRuntime/PipelineEventV1.cpp" \ + "${ROOT}/CausalRuntime/PipelineEventV1_test.cpp" \ + -o "${OUTPUT}" +"${OUTPUT}" +print "TFTMAC causal runtime ABI: PASS (96-byte event; strict owned-probe label parser)" diff --git a/scripts/verify-diagnostic-runtime.command b/scripts/verify-diagnostic-runtime.command index 9252166..05760b3 100755 --- a/scripts/verify-diagnostic-runtime.command +++ b/scripts/verify-diagnostic-runtime.command @@ -74,4 +74,4 @@ if [[ -f "$LEASE" ]]; then fi fi -print "TFTMAC diagnostic runtime preflight: READY (R9 identities; ports 5041/5586/8556; control stopped)" +print "TFTMAC diagnostic runtime preflight: READY (stock-shadow identities; ports 5041/5586/8556; control stopped)" diff --git a/scripts/verify-tftmac.command b/scripts/verify-tftmac.command index 19d24f0..e22c38e 100755 --- a/scripts/verify-tftmac.command +++ b/scripts/verify-tftmac.command @@ -35,11 +35,35 @@ for required in \ "$PROTO" \ "$PROTO_SOURCE" \ tftmac/Assets/TFTMAC-Official-Icon.png \ + tftmac/Assets/TFTMAC-DEV-Icon.png \ + ControlLauncher/Info.plist \ + ControlLauncher/main.swift \ + CausalRuntime/PipelineEventV1.h \ + CausalRuntime/PipelineEventV1.cpp \ + CausalRuntime/PipelineEventV1_test.cpp \ + DevLauncher/main.c \ + Probes/TFTMACVulkanProbe/AndroidManifest.xml \ + Probes/TFTMACVulkanProbe/workload-manifest.json \ + Probes/TFTMACVulkanProbe/src/main.cpp \ + Probes/TFTMACVulkanProbe/shaders/probe.vert \ + Probes/TFTMACVulkanProbe/shaders/probe.frag \ Generated/EmulatorController/emulator_controller.pb.swift \ Generated/EmulatorController/emulator_controller.grpc.swift \ scripts/generate-emulator-proto.command \ scripts/build-tftmac-app.command \ scripts/build-native-app.command \ + scripts/build-dev-launcher.command \ + scripts/build-control-launcher.command \ + scripts/prepare-causal-source-runtime.command \ + scripts/build-causal-stock-runtime.command \ + scripts/build-stock-shadow-runtime.command \ + scripts/build-vulkan-probe.command \ + scripts/install-desktop-launchers.command \ + scripts/run-vulkan-experiment-campaign.command \ + scripts/setup-android-unlock.command \ + scripts/analyze-vulkan-experiment-campaign.mjs \ + scripts/sign-apk-v2.mjs \ + scripts/test-causal-runtime.command \ scripts/install-trace-processor.command \ scripts/ensure-local-signing-identity.command \ scripts/test-native-app.command \ @@ -98,7 +122,7 @@ jq -e ' .runtimeProfile.tftGraphicsQuality == "High" and .runtimeProfile.tftFrameRateCap == 60 and .runtimeProfile.tftPerformanceModeBeta == false and - .runtimeProfile.activeExperiment == "combat_latency_a" and + .runtimeProfile.activeExperiment == "control" and .finalInstalledRelease.version == "2.3.0" and .finalInstalledRelease.build == "8" and .finalInstalledRelease.receiptScope == "HISTORICAL_BUILD8_RELEASE_ACCEPTANCE" and @@ -145,10 +169,15 @@ jq -e ' .currentGameplayCapture.markersAndBattles == "OPTIONAL_ANNOTATIONS_NOT_VALIDITY_OR_CAUSAL_GATES" and .currentGameplayCapture.automaticLogging == "VERIFIED_PID_LAYER_LIFETIME" and .currentGameplayCapture.rootAttribution == "UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE" and - .currentGameplayCapture.nextLayer == "ADVANCED_SOURCE_CAUSAL_LOGGER_PLANNED" and + .currentGameplayCapture.capturedExperiment == "combat_latency_a" and + .currentGameplayCapture.nextLayer == "ADVANCED_SOURCE_CAUSAL_LOGGER_PARTIAL_NOT_LIVE_ACCEPTED" and .diagnosticRuntimeEligibility.repository == "flashls1/tftmac-runtime" and .diagnosticRuntimeEligibility.commit == "c8aa26ebaa5b977965eb165ad8aac5c98408469f" and - .diagnosticRuntimeEligibility.normalPlayAuthority == "STOCK_BUILD8" + .diagnosticRuntimeEligibility.normalPlayAuthority == "STOCK_BUILD8" and + .diagnosticRuntimeEligibility.currentDevVariant == "stock_shadow" and + .diagnosticRuntimeEligibility.currentDevAVD == "TFTMAC_Diagnostic_StockShadow_R1" and + .diagnosticRuntimeEligibility.consecutiveFirstFramePasses == 3 and + .diagnosticRuntimeEligibility.r11Status == "FAILED_FIRST_NATIVE_FRAME_HISTORICAL" ' ssot/runtime-authority.json >/dev/null || fail "current Build 8 capture or diagnostic-runtime authority drifted" jq -e ' @@ -187,7 +216,8 @@ for locked in \ 'cssm_error: "CSSMERR_TP_NOT_TRUSTED"' \ 'installed_runtime_verifier: "BLOCKED_SIGNING_IDENTITY"' \ 'id: "2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200"' \ - 'advanced_source_causal_logger: "planned"'; do + 'current_selected_experiment: "control"' \ + 'advanced_source_causal_logger: "partial_source_schema_and_cpp_abi_not_live_accepted"'; do rg -q -F -- "$locked" ssot/STACK.lock.yaml || fail "active stack lock drifted: $locked" done @@ -206,11 +236,31 @@ while read -r expected_hash authority_path; do done < ssot/AUTHORITY_INPUTS.sha256 readonly TEST_FUNCTION_COUNT="$(rg -n '^[[:space:]]*func test' Tests/TFTMACTests --glob '*.swift' | wc -l | tr -d '[:space:]')" -[[ "$TEST_FUNCTION_COUNT" == "49" ]] || fail "native test inventory drifted: expected 49, found $TEST_FUNCTION_COUNT" +[[ "$TEST_FUNCTION_COUNT" == "54" ]] || fail "native test inventory drifted: expected 54, found $TEST_FUNCTION_COUNT" [[ "$(plutil -extract LSSupportsGameMode raw "$INFO")" == "true" ]] \ || fail "native app is not eligible for macOS Game Mode" [[ "$(shasum -a 256 tftmac/Assets/TFTMAC-Official-Icon.png | awk '{print $1}')" == "d6ba9ceb76c4b1e44e87f059f775a0ed629f9bea29b0dd73245853d7dca3a016" ]] \ || fail "official TFTMAC icon source hash drifted" +[[ "$(shasum -a 256 tftmac/Assets/TFTMAC-DEV-Icon.png | awk '{print $1}')" == "660d312767f6367d5e60d21ff9f05c8e17c29c0e258a45f5cb5e40ac0cb4c945" ]] \ + || fail "TFTMAC DEV icon source hash drifted" +jq -e ' + .default_mode == "control" and + .modes.control.application_bundle_id == "com.flashls1.tftmac" and + .modes.advanced_diagnostics.application_bundle_id == "com.flashls1.tftmac.dev" and + .modes.advanced_diagnostics.requires_control_stopped == true and + .modes.advanced_diagnostics.state_namespace == "advanced_diagnostics" and + .modes.advanced_diagnostics.adb_server_port == 5041 and + .modes.advanced_diagnostics.console_port == 5586 and + .modes.advanced_diagnostics.controller_port == 8556 +' ssot/runtime-modes.json >/dev/null || fail "Control/DEV launcher isolation contract drifted" +/usr/bin/xcrun --sdk macosx clang -fsyntax-only DevLauncher/main.c +/usr/bin/plutil -lint ControlLauncher/Info.plist >/dev/null +rg -q -F 'private static let serial = "emulator-5582"' ControlLauncher/main.swift \ + || fail "Control unlock wrapper is not pinned to emulator-5582" +rg -q -F 'process.arguments = ["-P", adbPort, "-s", serial, "shell"]' ControlLauncher/main.swift \ + || fail "Control unlock wrapper does not keep the PIN out of process arguments" +rg -q -F 'setenv("TFTMAC_RUNTIME_MODE", kRuntimeMode, 1)' DevLauncher/main.c \ + || fail "DEV launcher does not enforce its runtime mode" readonly PROTO_SHA="$(shasum -a 256 "$PROTO" | awk '{print $1}')" readonly RECORDED_PROTO_SHA="$(jq -r '.vendoredProtoSHA256' "$PROTO_SOURCE")" @@ -238,11 +288,14 @@ while IFS= read -r script; do done < <(find scripts -type f \( -name '*.command' -o -name '*.sh' \) | LC_ALL=C sort) node --check tools/tftmac-direct-control.mjs >/dev/null +node --check scripts/analyze-vulkan-experiment-campaign.mjs >/dev/null +node --check scripts/sign-apk-v2.mjs >/dev/null node --check .clara/plans/tftmac-causal-graphics-v1/wave-b-v4/validate-waveb-v4.mjs >/dev/null node --check .clara/plans/tftmac-causal-graphics-v1/diagnostic-first-boot-v1/validate-source.mjs >/dev/null [[ ! -f tools/tftmac-v2.mjs ]] || node --check tools/tftmac-v2.mjs >/dev/null node tools/tftmac-direct-control.mjs engineering-map-selftest >/dev/null node tools/tftmac-direct-control.mjs lab-selftest >/dev/null +/bin/zsh scripts/test-causal-runtime.command >/dev/null if [[ -n "${TFTMAC_FORBIDDEN_TOKEN:-}" ]]; then if git ls-files | rg -i -F -- "$TFTMAC_FORBIDDEN_TOKEN"; then @@ -306,4 +359,4 @@ cmp -s "$STATE_BEFORE" "$STATE_AFTER" || { fail "source verification changed tracked or visible generated state" } -print "TFTMAC source validation: OK (unsigned Release build; 49 native tests; diagnostic mode source authority PASS)" +print "TFTMAC source validation: OK (unsigned Release build; 54 native tests; diagnostic mode source authority PASS)" diff --git a/ssot/AUTHORITY_INPUTS.sha256 b/ssot/AUTHORITY_INPUTS.sha256 index 709eca1..4cc2dc0 100644 --- a/ssot/AUTHORITY_INPUTS.sha256 +++ b/ssot/AUTHORITY_INPUTS.sha256 @@ -1,11 +1,11 @@ # TFTMAC Build 8 documentation and machine-readable authority inputs # Regenerate only after reviewing the complete authority change set. -3573bd6877ebddc9357644b32ed8d8565d06d42d3f3b1f87f67a4b7c58bd4b06 facts.md -273307f655f0749a12a0a3e48f421f5e61bc6bd40f00b1afb7040c0b2fd15adb project.md -a40e186e4d37a4e7d6024bd069a69509729eb9e6efda36a0fab12162ecf60f7e dev.md -15a33754add669bdfea2001053cbfb47df1120658be7f10022a50656fb4069c6 benchmark.md +7edaf15029fc4bcdb5563e17f7da4a3b4f2f7bc8988ac700316da5c3b0eee39d facts.md +b8b9bfc812d3dd1a737bb341beac26fdc08a53877db3dea09c13c7a3257b7121 project.md +231848da5018c62940ee34d918e1b5133295ac405f1a3b9d0da1b3d4c9d03c03 dev.md +d8156dc98fa6116de90e2335d77bd03dafe18148215990af788a3c14cbb8b708 benchmark.md bad70917a4e3230646748c33a171aeba0f0b1f4ff9b93fdfaa7b04788b84c532 TFTMAC_GPU_RUNTIME_SSOT.md -2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f ssot/runtime-authority.json -9f5d87a2ae5a34eb8f89691ec1756ad1c7152fc94706aa8de0a111363623dd24 ssot/TFTMAC_ENGINEERING_MAP.sql -e2b495770c13abe3f65779027656a699a9dec200278a9260e7de767516ffa0c1 ssot/TFTMAC_PERFORMANCE_LAB.sql +2646434592e1867cdaf1c5860cb86ce4fea250ab8aca01c7c122a3cf6caaec47 ssot/runtime-authority.json +a4bdab6304b32c135fe00234564ef408e6049135945f025005c8286f0439e39a ssot/TFTMAC_ENGINEERING_MAP.sql +38e7f818ffafe7d678a44044b9570b1a1e4be60f48b58e076ce39395eebe30bf ssot/TFTMAC_PERFORMANCE_LAB.sql diff --git a/ssot/STACK.lock.yaml b/ssot/STACK.lock.yaml index 5fe4d10..8b64b67 100644 --- a/ssot/STACK.lock.yaml +++ b/ssot/STACK.lock.yaml @@ -1,5 +1,5 @@ schema: 3 -frozen_at: "2026-08-31T23:13:30Z" +frozen_at: "2026-09-02T07:59:18Z" phase0_status: PASS authority: @@ -8,12 +8,12 @@ authority: ssot_version: "4.0-build8-reconciliation" documentation_authority: "facts.md + project.md + dev.md + benchmark.md" authority_inputs: "ssot/AUTHORITY_INPUTS.sha256" - runtime_authority_sha256: "2af6196e08b3f81032b8226fa3a9c25a3b0d99537f0872b7eb21a96aaf2b5d2f" - authority_inputs_sha256: "2bcb0c0c7c4858b1090ce22491bb344756085f2f6ebb17c0cb73840fb3df6a38" + runtime_authority_sha256: "2646434592e1867cdaf1c5860cb86ce4fea250ab8aca01c7c122a3cf6caaec47" + authority_inputs_sha256: "22305e38b4fd588e0f70ad03862cd394d2fcebeecbff50124e1962f48960f95a" zengate_version: "2.3" zengate_score: 95.8 zengate_result: "PASS" - source_build_inputs_status: "historical_reference_only_for_normal_play; isolated_diagnostic_eligibility_only" + source_build_inputs_status: "modern_isolated_case_sensitive_source_sync_paused; source_lock_and_live_parity_pending" production_guest: "official Android 16 Google Play ARM64" shipping_render_target: "1920x1080@60" @@ -56,7 +56,8 @@ release: qemu_worker_qos_inheritance: "NOT_CLAIMED_WITHOUT_COMBAT_EVIDENCE" game_mode_eligible: true guest_gameplay_power_gate: true - active_experiment: "combat_latency_a" + historical_latest_capture_experiment: "combat_latency_a" + current_selected_experiment: "control" tft_graphics: "High / 60 FPS / Performance Mode OFF" perfetto_trace_processor_version: "58.2" perfetto_trace_processor_sha256: "d29864d1ba3b36855527bb1b0ca3aa7f703cdce338b9680bb922c5c151b358fa" @@ -68,10 +69,37 @@ release: cssm_error: "CSSMERR_TP_NOT_TRUSTED" installed_runtime_verifier: "BLOCKED_SIGNING_IDENTITY" conclusion: "Historical signing acceptance remains distinct from this timestamped host trust audit." + latest_host_signing_recheck: + observed_at: "2026-09-02T07:59:18Z" + control_deep_strict_codesign: PASS + dev_deep_strict_codesign: PASS + signing_identity: "TFTMAC Local Code Signing" + protected_control_hashes_match: true + installed_runtime_verifier: PASS + +launcher_products: + control: + installed_path: "/Applications/TFTMAC.app" + desktop_path: "/Users/flash/Desktop/TFTMAC.app" + desktop_wrapper_path: "/Applications/TFTMAC Control Launcher.app" + direct_rollback_path: "/Applications/TFTMAC.app" + bundle_id: "com.flashls1.tftmac" + runtime_mode: "control" + status: "PROTECTED_PLAYABLE_AUTHORITY" + dev: + installed_path: "/Applications/TFTMAC DEV.app" + desktop_path: "/Users/flash/Desktop/TFTMAC DEV.app" + bundle_id: "com.flashls1.tftmac.dev" + runtime_mode: "advanced_diagnostics" + state_namespace: "advanced_diagnostics" + runtime_variant: "stock_shadow" + avd_name: "TFTMAC_Diagnostic_StockShadow_R1" + status: "THREE_CONSECUTIVE_FIRST_FRAME_PASSES_PROBE_CAMPAIGN_PENDING" + concurrency_policy: "GLOBAL_RUNTIME_LEASE_NO_CONCURRENT_CONTROL_AND_DEV" verification_contracts: repository_source: "scripts/verify-tftmac.command; no installed app, external runtime, signing identity, credentials, or private capture" - installed_runtime: "scripts/verify-installed-runtime.command; local-only and currently blocked on signing identity" + installed_runtime: "scripts/verify-installed-runtime.command; local-only; latest 2026-09-02 signing recheck PASS" github_ci: "repository_source only" android_command_line_tools: @@ -124,6 +152,43 @@ diagnostic_runtime: commit: "c8aa26ebaa5b977965eb165ad8aac5c98408469f" status: "isolated_non_comparable_diagnostic_eligibility_only" normal_play_authority: "stock_build8" + mode_registry_sha256: "b2a8080248900c27efdaac7fe3825ccb919188d43072af7a870bfc49c3e0e96f" + latest_capture: "2026-09-02T07-46-40.998Z-8260f517-a8a4-4d5e-918f-723b81de32f4" + adb_acceptance: "PASS_DEVICE_USER_DEFAULT_KEY" + automatic_capture_start: PASS + first_native_frame: "FAIL_TIMEOUT_120_SECONDS" + playable_status: "NOT_ACCEPTED" + +modern_causal_source: + manifest_branch: "emu-main-dev" + manifest_commit: "2692acc620f6563b21995540656674faeb536cdc" + source_volume: "/Volumes/TFTMAC Causal Source" + filesystem: "case-sensitive APFS sparse image" + sync_jobs: 4 + source_lock_receipt: "NOT_CREATED_SYNC_PAUSED" + uninstrumented_build: "NOT_RUN" + source_hooks: "NOT_IMPLEMENTED" + +owned_probe_campaign: + baseline: "stock_shadow" + sequence: "control,queue_submit_inline,control,virtual_queue_off,control,fence_contexts_off,control" + keychain_service: "com.flashls1.tftmac.android-unlock.v2" + keychain_item_status: "NOT_CONFIGURED_AT_HANDOFF" + state: "NOT_RUN_NO_WINNER" + +latest_playability_comparison: + candidate_capture: "2026-09-02T05-26-14.078Z-0fb7a877-23f7-4933-bc9f-5525ed8c6d3d" + control_capture: "2026-09-02T05-54-33.919Z-e13fd9b8-1091-4516-bd6e-66f8b50a912d" + candidate_weighted_fps: 26.446 + control_weighted_fps: 47.384 + candidate_fps_one_percent_low: 2.770 + control_fps_one_percent_low: 7.870 + candidate_p95_frame_interval_ms: 117.088 + control_p95_frame_interval_ms: 34.002 + candidate_severe_stall_percent: 21.037 + control_severe_stall_percent: 1.429 + decision: "REJECT_COMBAT_LATENCY_A_KEEP_CONTROL" + causal_scope: "WORKLOADS_NOT_FORMALLY_MATCHED_QOS_CAUSALITY_NOT_CLAIMED" current_gameplay_capture: id: "2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200" @@ -131,7 +196,7 @@ current_gameplay_capture: database_byte_count: 63897600 database_sha256: "c1ef9c9ffe591a297cb86660e3ccfea7e9aeb593f22100e4e732b2fc77d4ee77" graphics_run_duration: "42m27s" - active_experiment: "combat_latency_a" + captured_experiment: "combat_latency_a" tft_graphics: "High / 60 FPS / Performance Mode OFF" automatic_logging: "verified_pid_layer_lifetime" exact_layer_coverage_percent: 99.629 @@ -152,7 +217,14 @@ current_gameplay_capture: mac_presenter: "excluded_from_causal_candidates_context_only" markers_and_battles: "optional_annotations_not_validity_or_causal_gates" root_attribution: "UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE" - advanced_source_causal_logger: "planned" + advanced_source_causal_logger: "partial_source_schema_and_cpp_abi_not_live_accepted" + +development_verification: + native_test_inventory: 54 + causal_cpp_abi_test: PASS + causal_event_bytes: 96 + causal_ring_capacity: 256 + current_internal_root: UNKNOWN generality: status: "historical_reference_only_not_release_acceptance" diff --git a/ssot/TFTMAC_ENGINEERING_MAP.sql b/ssot/TFTMAC_ENGINEERING_MAP.sql index 49fcf45..1fc5dc7 100644 --- a/ssot/TFTMAC_ENGINEERING_MAP.sql +++ b/ssot/TFTMAC_ENGINEERING_MAP.sql @@ -1412,8 +1412,10 @@ INSERT OR REPLACE INTO evidence(id,observed_at,kind,source_path,source_sha256,st ('ev_current_host_audit_20260831','2026-08-31T23:13:30Z','host_trust_audit','ssot/runtime-authority.json',NULL,'The current-host audit found release identity hashes matching the historical Build 8 receipt with zero identity findings, while the host trust policy reported CSSMERR_TP_NOT_TRUSTED. This audit is timestamped separately and does not invalidate or rewrite historical signing acceptance.','DIRECT','Trust-policy result is not a release-identity mismatch.'); INSERT OR REPLACE INTO runtime_variants(id,entrypoint,classification,runtime_family,graphics_path,display_profile,resource_profile,exact_result,promotion_state,source_document_id,current_relevance,notes) VALUES -('rv_stock_build8_normal_play','TFTMAC.app','RECOMMENDED','Stock released Emulator37.1.11 / Android16 API36 Play through packaged macOS app host','Unreal direct Vulkan -> gfxstream/ASG -> host Vulkan -> MoltenVK -> Metal','1920x1080 / 320 DPI / 60Hz target / native full screen','6 vCPU / 5120 MiB / CoreAudio / host GPU','Build 8 automatic 42m27s graphics run complete with exact-layer coverage and stack receipts.','PROMOTED',NULL,'Current normal-play authority','Active observed combat_latency_a uses High/60/Performance Mode OFF and is not promoted as a performance result. Markers and battle classification are optional annotations.'), -('rv_tftmac_runtime_diagnostic','isolated source-built emulator','DIAGNOSTIC','tftmac-runtime @ c8aa26ebaa5b977965eb165ad8aac5c98408469f','Planned source-instrumented gfxstream/MoltenVK causal trace','Not applicable until isolated diagnostic acceptance','Not comparable to stock Build 8','Eligible only for the planned advanced causal logger.','NOT_PROMOTED',NULL,'Diagnostic eligibility only','Requires separate parity, correctness, clock, stream-seal, and observer-overhead gates. Never replace normal-play stock authority by implication.'); +('rv_stock_build8_normal_play','TFTMAC.app','RECOMMENDED','Stock released Emulator37.1.11 / Android16 API36 Play through packaged macOS app host','Unreal direct Vulkan -> gfxstream/ASG -> host Vulkan -> MoltenVK -> Metal','1920x1080 / 320 DPI / 60Hz target / native full screen','6 vCPU / 5120 MiB / CoreAudio / host GPU','Build 8 automatic 42m27s graphics run complete with exact-layer coverage and stack receipts.','PROMOTED',NULL,'Current normal-play authority','The selected profile is control: High/60/Performance Mode OFF. The historical combat_latency_a capture remains evidence only. Markers and battle classification are optional annotations.'), +('rv_stock_shadow_dev','TFTMAC DEV.app','DIAGNOSTIC','Physical Emulator37.1.11 / Android16 API36 Control shadow with isolated AVD and ports','Control-equivalent gfxstream/ASG -> host Vulkan -> MoltenVK -> Metal','1920x1080 / 320 DPI / 60Hz target','6 vCPU / 5120 MiB / CoreAudio / host GPU','Three consecutive clean stock-shadow launches passed ADB, controller, unlock, first native frame, TFT package/layer, input, audio, and cleanup gates.','NOT_PROMOTED',NULL,'Current DEV screening baseline','Isolated serial emulator-5586, ADB 5041, controller 8556. It cannot replace or mutate Control.'), +('rv_r11_api37_failed','historical R11 diagnostic launcher','HISTORICAL','Emulator35.6.3 / API37 diagnostic runtime','Failed before first native frame','Diagnostic only','Not comparable to Control','FAILED_FIRST_NATIVE_FRAME','RETAINED',NULL,'Historical negative evidence','R11 is not launch-ready authority and cannot support a TFT performance conclusion.'), +('rv_modern_causal_source','isolated pinned modern source runtime','DIAGNOSTIC','emu-main-dev manifest 2692acc620f6563b21995540656674faeb536cdc','Uninstrumented parity first; PipelineEventV1 causal hooks second','Not applicable until first-frame parity','Not comparable until parity passes','Preparation/build scripts and ABI exist; source sync, parity build, live hooks, and overhead gates are pending.','NOT_PROMOTED',NULL,'Causal implementation in progress','Never replace Control or name a component before complete lineage, loss, clock, and observer-overhead gates.'); INSERT OR REPLACE INTO unknowns(id,question,owning_layer,blocking,next_probe,status,resolution) VALUES ('unk_current_internal_root_attribution','Which owned component and source site first diverges before the exact TFT SurfaceFlinger actual-present degradation?','cross_stack_causal_logger',1,'Build the planned isolated source causal logger with explicit work IDs across owned boundaries; require complete joins, clock validity, sealed streams, and observer-overhead <=5% before naming a cause.','OPEN',NULL); @@ -1424,19 +1426,19 @@ INSERT OR REPLACE INTO decisions(id,decided_at,decision,rationale,state,evidence ('dec_markers_optional_annotations','2026-08-31T23:13:30Z','Treat match and battle markers as optional annotations.','Automatic TFT process/layer lifetime determines raw capture validity; marker absence cannot invalidate causal analysis.','ACTIVE','ev_build8_current_capture_20260831',NULL); INSERT OR REPLACE INTO map_meta(key,value) VALUES -('current_phase','Advanced causal graphics logging planned; Build 8 automatic full-run baseline verified.'), +('current_phase','DEV stock-shadow baseline recovered and owned-probe/source-causal implementation in progress; Build 8 automatic full-run baseline verified.'), ('current_release_gameplay_benchmark','VERIFIED_CAPTURE_ROOT_ATTRIBUTION_UNKNOWN; capture 2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200.'), -('current_runtime_authority','Stock Build 8 packaged macOS-host launcher is normal-play authority. tftmac-runtime@c8aa26e is isolated, diagnostic-only, and non-comparable.'), -('current_observed_configuration','combat_latency_a; High graphics / 60 FPS / Performance Mode OFF; observed active, not performance-promoted.'), +('current_runtime_authority','Stock Build 8 packaged macOS-host launcher is unchanged normal-play authority. The Emulator37.1.11/API36 stock-shadow is isolated DEV screening authority; R11 is failed historical evidence.'), +('current_observed_configuration','Current selected profile: control; High graphics / 60 FPS / Performance Mode OFF. Historical capture: combat_latency_a, observed but not promoted.'), ('current_pipeline_receipt','Unreal direct Vulkan -> gfxstream/ASG -> host Vulkan -> MoltenVK -> Metal; ANGLE conditional; final Mac presenter context-only.'), ('current_capture_validity','Automatic PID/layer lifetime logging is verified. Match, battle, combat, and result markers are optional annotations and are not validity or causal gates.'), ('current_root_attribution','UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE. Existing telemetry measures degradation but lacks shared owned-stage work IDs for causal naming.'), -('current_advanced_logger_status','PLANNED: isolated source-built runtime instrumentation; do not claim a root component or source line until all causal evidence gates pass.'), +('current_advanced_logger_status','PARTIAL_NOT_LIVE_ACCEPTED: ABI, fixed rings, hash-chained segments, SQL structures, analyzer states, stock-shadow runtime, owned probe, and campaign runner exist. Modern source hook, parity, lineage, clock, loss, and observer-overhead gates remain pending.'), ('current_host_audit','Timestamped current-host audit: matching release identity hashes, zero identity findings, CSSMERR_TP_NOT_TRUSTED under current host trust policy; historical release signing acceptance remains distinct.'); INSERT OR REPLACE INTO map_meta(key,value) VALUES ('current_presentation_candidate','RETIRED_AS_CURRENT_ACTION: final Mac presentation is context-only; earlier broad HWC/ASG directional candidates remain historical and cannot name a root cause.'), -('current_graphics_next_action','Plan the isolated source causal logger first. No graphics tuning intervention is current until it identifies an owned first divergent boundary or reports an explicit unowned/missing boundary.'); +('current_graphics_next_action','Execute the sealed seven-run stock-shadow probe campaign, then build the pinned modern source runtime uninstrumented for parity before enabling causal hooks. No component patch is authorized without replicated owned-boundary evidence.'); INSERT INTO update_log(observed_at,subject,change_summary,evidence_id) VALUES ('2026-08-31T23:13:30Z','Build 8 full-run baseline','Recorded the verified automatic 42m27s capture, private integrity metadata, direct Vulkan stack receipt, and explicit UNKNOWN root-attribution boundary.','ev_build8_current_capture_20260831'), @@ -1477,6 +1479,6 @@ INSERT OR REPLACE INTO map_meta(key,value) VALUES ('current_connector_state','The direct-Vulkan stack is receipt-verified. Per-frame ownership below the guest TFT surface remains unmeasured; no internal component is a proven live root cause.'), ('current_native_telemetry','Private local SQL and sealed sidecars are captured automatically across the TFT PID/layer lifetime. Match, combat, battle, stutter, quality, and result markers are optional annotations.'), ('current_native_metric_boundary','Exact TFT SurfaceFlinger actual-present timestamps are FPS authority. Final Mac presentation is hidden correctness context only and cannot be selected as the root cause.'), -('current_game_settings','Observed Build 8 capture: combat_latency_a; High graphics; 60 FPS; Performance Mode OFF. This is an observation, not a promoted tuning result.'), -('current_pipeline_next_probe','Build the isolated source causal logger with owned-stage work IDs, valid clock joins, sealed streams, and <=5% observer-overhead gate before any causal patch.'), -('current_optimization_priority','Use all automatic full-run graphics data. Name or patch a component only after the source causal logger proves the first divergent owned boundary; otherwise report UNKNOWN.'); +('current_game_settings','Current Control target: High graphics; 60 FPS; Performance Mode OFF. The historical combat_latency_a Build 8 capture is evidence, not an active or promoted configuration.'), +('current_pipeline_next_probe','Run the deterministic stock-shadow Vulkan-probe campaign, then establish uninstrumented modern-source parity and enable owned-stage work IDs with valid clock joins, sealed streams, and <=5% observer overhead.'), +('current_optimization_priority','Use the deterministic probe to screen supported settings, then use causal hooks to name the first divergent owned boundary. Patch only replicated evidence; otherwise report UNKNOWN or UNREAL_OR_PRE_HOST_UNKNOWN.'); diff --git a/ssot/TFTMAC_PERFORMANCE_LAB.sql b/ssot/TFTMAC_PERFORMANCE_LAB.sql index c90115b..c1a71bb 100644 --- a/ssot/TFTMAC_PERFORMANCE_LAB.sql +++ b/ssot/TFTMAC_PERFORMANCE_LAB.sql @@ -712,7 +712,7 @@ INSERT OR REPLACE INTO runtime_configs ( 'tftmac_stock_build8_high60_control','tftmac_5gb_native_v1','Stock Build 8 High/60 normal-play control','37.1.11','37.0.1','system-images;android-36;google_apis_playstore;arm64-v8a',7, 'TFT_Ultra_Tablet','emulator-5582',5038,5582,6,5120,1920,1080,320,60.0,'host',1, 'virtio-gpu-asg','Conditional: do not assume ANGLE is TFT main rendering path','Unreal direct Vulkan observed','gfxstream host Vulkan -> MoltenVK/Metal','authenticated raw gRPC -> AppKit Metal full screen','CONTROL','2026-08-31T22:30:26Z', - 'Normal-play authority. Active observed experiment combat_latency_a uses High/60/Performance Mode OFF and is not a promoted performance intervention.' + 'Normal-play authority. The selected profile is control: High/60/Performance Mode OFF. The historical capture observed combat_latency_a but did not promote it.' ); INSERT OR REPLACE INTO sessions( @@ -765,12 +765,12 @@ INSERT OR REPLACE INTO lab_meta(key,value) VALUES ('current_playable_baseline_session','2026-08-31T22-30-26.086Z-8df607d7-a34a-4e2a-b00d-739aa3143200'), ('current_release_gameplay_benchmark','VERIFIED_CAPTURE_ROOT_ATTRIBUTION_UNKNOWN'), ('current_runtime_mode','STOCK_BUILD8_NORMAL_PLAY_AUTHORITY'), -('current_active_experiment','combat_latency_a observed High/60/Performance Mode OFF; not promoted'), +('current_active_experiment','control selected; High/60/Performance Mode OFF'), ('current_renderer_path','Unreal direct Vulkan -> gfxstream/ASG -> host Vulkan -> MoltenVK -> Metal; ANGLE conditional only'), ('current_mac_presenter_policy','Final Mac presenter is excluded from causal candidates and retained only as context/correctness telemetry.'), ('current_marker_policy','MATCH_ENTRY, MATCH_END, combat, battle, and quality markers are optional annotations only; automatic process/layer lifetime defines capture validity.'), ('current_root_attribution','UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE'), -('advanced_source_causal_logger','PLANNED: isolated non-comparable tftmac-runtime diagnostic build; no causal code-site claim until complete work-ID joins, valid clocks, sealed streams, and overhead gate pass.'); +('advanced_source_causal_logger','PARTIAL_NOT_LIVE_ACCEPTED: PipelineEventV1 ABI, fixed rings, segment hashing, SQL schema, analyzer states, owned Vulkan probe, stock-shadow DEV runtime, and campaign runner exist. Modern source hooks, uninstrumented parity, live lineage, clock, loss, and observer-overhead gates remain pending.'); UPDATE experiments SET state='CANCELLED', @@ -780,19 +780,19 @@ WHERE id IN ('exp_asg_flush400_ab','exp_native_frame_trace','exp_tft_fps_cap_ab' INSERT OR REPLACE INTO lab_meta(key,value) VALUES ('current_presentation_candidate','RETIRED_AS_CURRENT_ACTION: final Mac presentation and broad SurfaceFlinger/HWC directional candidates are context only; causal changes wait for the planned source causal logger.'), -('current_graphics_next_action','Build and validate the isolated source causal logger. Do not run a tuning A/B until it identifies an owned first divergent boundary or explicitly reports that the first missing boundary is unowned.'); +('current_graphics_next_action','Complete the sealed seven-run stock-shadow Vulkan-probe campaign, then build and validate the pinned modern source runtime and causal hooks. Do not patch a component until replicated evidence identifies the first divergent owned boundary.'); -- Exact-key overrides for the Build 8 authority. Earlier values remain in the -- SQL history but cannot survive as the effective current policy. INSERT OR REPLACE INTO lab_meta(key,value) VALUES ('logger_guard_policy','Automatic logging follows the TFT process and exact layer from game start until process/app close. MATCH_ENTRY, MATCH_END, combat, battle, quality, and result markers are optional annotations only.'), ('multi_match_policy','Keep raw telemetry continuous across every game. Process/layer lifetime and timestamps define validity; marker pairing and battle classification are never required.'), -('current_measurement_gap','Exact TFT SurfaceFlinger actual-present timing is implemented and verified. Internal causal attribution below the guest TFT surface remains unimplemented because owned-stage work IDs are absent.'), +('current_measurement_gap','Exact TFT SurfaceFlinger actual-present timing is implemented and verified. PipelineEventV1, storage, SQL, analyzer states, and the owned probe are implemented, but live modern-source hook joins below the guest surface have not passed parity, lineage, loss, clock, or observer-overhead gates.'), ('current_tft_graphics_observed','High'), ('current_tft_fps_cap_observed','60'), ('current_tft_performance_mode_beta_observed','OFF'), ('current_native_frame_truth','Exact TFT SurfaceFlinger actual-present timestamps are FPS authority. Final Mac presentation is hidden correctness context only and is excluded from causal ranking.'), ('current_native_logger','Automatic private SQL capture covers the TFT PID/layer lifetime, exact intervals/windows, receipts, incidents, and bounded supporting telemetry. Markers are optional annotations.'), ('current_surfaceflinger_counter_policy','Exact TFT actual-present intervals and one-second windows are primary. Cumulative counters are supporting context only and do not require marked windows.'), -('current_optimization_priority','Analyze all automatic full-run graphics data. Do not tune or name a root component until the planned source causal logger proves the first divergent owned boundary or explicitly reports UNKNOWN.'), -('current_graphics_experiment','No tuning A/B is active. The next development phase is the PLANNED isolated source causal logger; combat_latency_a is an observed High/60/Performance Mode OFF preset, not a promoted result.'); +('current_optimization_priority','Run the bounded owned-probe screen first. Name or patch a component only after source causal hooks prove the first divergent owned boundary; otherwise report UNKNOWN or UNREAL_OR_PRE_HOST_UNKNOWN.'), +('current_graphics_experiment','Control is selected for normal play. The isolated stock-shadow DEV seven-run Vulkan-probe campaign is prepared and awaits its sealed execution; no synthetic candidate or historical combat_latency_a configuration is promoted.'); diff --git a/ssot/runtime-authority.json b/ssot/runtime-authority.json index f94c844..859acaa 100644 --- a/ssot/runtime-authority.json +++ b/ssot/runtime-authority.json @@ -31,7 +31,7 @@ "tftGraphicsQuality": "High", "tftFrameRateCap": 60, "tftPerformanceModeBeta": false, - "activeExperiment": "combat_latency_a" + "activeExperiment": "control" }, "androidWebView": { "package": "com.google.android.webview", @@ -154,13 +154,42 @@ "markersAndBattles": "OPTIONAL_ANNOTATIONS_NOT_VALIDITY_OR_CAUSAL_GATES", "automaticLogging": "VERIFIED_PID_LAYER_LIFETIME", "rootAttribution": "UNKNOWN_UPSTREAM_OF_OR_AT_GUEST_SURFACE", - "nextLayer": "ADVANCED_SOURCE_CAUSAL_LOGGER_PLANNED" + "capturedExperiment": "combat_latency_a", + "nextLayer": "ADVANCED_SOURCE_CAUSAL_LOGGER_PARTIAL_NOT_LIVE_ACCEPTED" }, "diagnosticRuntimeEligibility": { "repository": "flashls1/tftmac-runtime", "commit": "c8aa26ebaa5b977965eb165ad8aac5c98408469f", "status": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", - "normalPlayAuthority": "STOCK_BUILD8" + "normalPlayAuthority": "STOCK_BUILD8", + "currentDevVariant": "stock_shadow", + "currentDevAVD": "TFTMAC_Diagnostic_StockShadow_R1", + "currentDevRuntime": "EMULATOR_37_1_11_API_36_PHYSICAL_CLONE", + "consecutiveFirstFramePasses": 3, + "r11Status": "FAILED_FIRST_NATIVE_FRAME_HISTORICAL", + "causalLogger": "PARTIAL_SOURCE_AND_SCHEMA_NOT_LIVE_ACCEPTED", + "modernCausalSource": { + "manifestBranch": "emu-main-dev", + "manifestCommit": "2692acc620f6563b21995540656674faeb536cdc", + "storage": "CASE_SENSITIVE_APFS_SPARSE_IMAGE", + "sourceLockReceipt": "NOT_CREATED_SYNC_PAUSED", + "uninstrumentedBuild": "NOT_RUN", + "sourceHooks": "NOT_IMPLEMENTED" + }, + "ownedProbeCampaign": { + "sequence": [ + "control", + "queue_submit_inline", + "control", + "virtual_queue_off", + "control", + "fence_contexts_off", + "control" + ], + "keychainService": "com.flashls1.tftmac.android-unlock.v2", + "keychainItemStatus": "NOT_CONFIGURED_AT_HANDOFF", + "state": "NOT_RUN_NO_WINNER" + } }, "evidenceOperations": [ "native-events:CONTROLLER_AUTHENTICATED", diff --git a/ssot/runtime-modes.json b/ssot/runtime-modes.json index 7ad6f05..3ebea38 100644 --- a/ssot/runtime-modes.json +++ b/ssot/runtime-modes.json @@ -3,58 +3,59 @@ "default_mode": "control", "modes": { "advanced_diagnostics": { - "adb_path": "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK/platform-tools/adb", + "adb_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/platform-tools/adb", "adb_server_port": 5041, - "allowed_purpose": "ISOLATED_SOURCE_INSTRUMENTATION_AND_ELIGIBILITY", + "allowed_purpose": "ISOLATED_STOCK_SHADOW_SCREENING_AND_DIAGNOSTIC_BASELINE", "application_build": "8", - "application_bundle_id": "com.flashls1.tftmac", + "application_bundle_id": "com.flashls1.tftmac.dev", "application_version": "2.3.0", "authority_manifest": { "kind": "external_sealed_manifest", - "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json", - "sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d" + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/Manifests/stock-shadow-r1-20260902/stock-shadow-runtime.json", + "sha256": "540f57f762d67b894916a96adc2c0836aec803a8af9cba988b8b5df94ddde285" }, - "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd/config.ini", - "avd_config_sha256": "090fe426402562e227a3a1a6bd6eab9f9572cd48fbe3d467c276d419860caf90", - "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.avd", - "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD", - "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/AVD/TFTMAC_Diagnostic_API37_R9.ini", - "avd_ini_sha256": "30d4ed7ebc20fb3415461fa48f6d91654955e04825de84176bd21a4adad9b98d", - "avd_name": "TFTMAC_Diagnostic_API37_R9", - "comparability_class": "ISOLATED_NON_COMPARABLE_DIAGNOSTIC_ELIGIBILITY_ONLY", - "configuration_sha256": "1c7b33f3b32a530fff0ba79aedeb82001f392295ebd538a516374fff5db7f903", + "avd_config_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/AVD/TFTMAC_Diagnostic_StockShadow_R1.avd/config.ini", + "avd_config_sha256": "b8cccc257dcc114ae5e6d24149514b7149b7e60a580fb74f79ca343823c28125", + "avd_directory": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/AVD/TFTMAC_Diagnostic_StockShadow_R1.avd", + "avd_home": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/AVD", + "avd_ini_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/AVD/TFTMAC_Diagnostic_StockShadow_R1.ini", + "avd_ini_sha256": "85a50d6174c22d815ccb7c8ebeae13342922c2904f24e461fac47f953fb1a587", + "avd_name": "TFTMAC_Diagnostic_StockShadow_R1", + "comparability_class": "STOCK_BUILD8_CONTROL_SHADOW", + "configuration_sha256": "3321a0246409313194cbe120a90c7d16b32f34c2ff550632554c8912ed69b4a0", "console_port": 5586, "controller_port": 8556, - "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/emulator", - "emulator_sha256": "fb7782eb3abd7c5b4cb000e68f0c296fed1098f9581aacb01971a45f6b6836aa", - "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64/libgfxstream_backend.dylib", - "gfxstream_backend_sha256": "23d54a05a3b73704a7f7d0394f40e04f21bd7e546b1982911a681ae0fe375c9d", + "emulator_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/emulator/emulator", + "emulator_sha256": "b3b8fc0dcedcf6e15b54b41f3e5156319029aa00b88a59fd489f80abdd8fc133", + "gfxstream_backend_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/emulator/lib64/libgfxstream_backend.dylib", + "gfxstream_backend_sha256": "3772fef215058831ea419c9281fd203d010003d5defdc195dd120bc7748e4093", "launch_state": "enabled", - "library_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/lib64", + "library_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/emulator/lib64", "mode": "advanced_diagnostics", "requires_control_stopped": true, "rollback_target": "control", - "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1", - "sdk_root": "/Volumes/MAC MINI M4/TFTMAC-RUNTIME-DATA/SDK", + "runtime_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow", + "sdk_root": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK", "serial": "emulator-5586", "state_namespace": "advanced_diagnostics", "uses_legacy_application_support_root": false, + "runtime_variant": "stock_shadow", "emulator_identifier": "TFTMAC-DIAGNOSTIC", "launch_strategy": "external_native_host", "profile_policy": "fixed_registry_profile", "locked_profile": { - "identifier": "tftmac_diagnostic_r9", + "identifier": "tftmac_diagnostic_stock_shadow_r1", "width": 1920, "height": 1080, - "density_dpi": 280, + "density_dpi": 320, "refresh_hz": 60, "vcpu": 6, - "ram_mib": 6144, + "ram_mib": 5120, "gpu_mode": "host", "audio_backend": "coreaudio", - "graphics_transport": "pipe", + "graphics_transport": "virtio-gpu-asg", "asg_write_buffer_size": 1048576, - "asg_write_step_size": 4096, + "asg_write_step_size": 16384, "asg_data_ring_size": 32768, "asg_draw_flush_interval": 800, "angle_enabled_features": "exposeNonConformantExtensionsAndVersions:exposeES32ForTesting", @@ -62,17 +63,17 @@ }, "adb_sha256": "1811e253b21b12cbfda7201ebaf86c10e7ddcb5c606a7a81f7c82b4c429c2d3b", "adb_vendor_keys_policy": "USER_DEFAULT_KEY", - "expected_emulator_version_contains": "35.6.3", + "expected_emulator_version_contains": "37.1.11", "emulator_uuids": [ - "4C4C4436-5555-3144-A1EE-05B0F446F580:arm64" + "4C4C449E-5555-3144-A182-644CCB895091:arm64" ], - "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Install/gate4-r9-20260901/emulator/qemu/darwin-aarch64/qemu-system-aarch64", - "qemu_sha256": "042c4932b17fd09ff056ecc2dd21084e08e1110b774c594bbcaf1e4d1ceac608", + "qemu_path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/SDK/emulator/qemu/darwin-aarch64/qemu-system-aarch64", + "qemu_sha256": "eaa97a970b81f81640db73ed79e19ee173323653a0a1203217e1199d078011f3", "qemu_uuids": [ - "4C4C447F-5555-3144-A16C-0DB6C4482B7A:arm64" + "4C4C4467-5555-3144-A10A-A9E5A99446F1:arm64" ], "gfxstream_backend_uuids": [ - "4C4C4449-5555-3144-A1FC-F6DFE0021481:arm64" + "4C4C4406-5555-3144-A122-8AC522465662:arm64" ], "host_application": { "kind": "external_application", @@ -87,22 +88,22 @@ "build_receipt_resource": null }, "diagnostic_receipts": { - "build_id": "gate4-r9-20260901", - "runtime_configuration_sha256": "005c85a2a7ffe86e7626c871fd3dd23f42c5d3ce994162d17b032e69cfc4d4f3", + "build_id": "stock-shadow-r1-20260902", + "runtime_configuration_sha256": "540f57f762d67b894916a96adc2c0836aec803a8af9cba988b8b5df94ddde285", "build": { - "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-build.json", - "sha256": "9556ffe5c9d083d3ba90006628b8fc5a94a6989f56fa21d40bb9a30f2f99ef8d", - "required_state": "DIAGNOSTIC_BUILD_IDENTITY_PASS" + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/Manifests/stock-shadow-r1-20260902/stock-shadow-runtime.json", + "sha256": "540f57f762d67b894916a96adc2c0836aec803a8af9cba988b8b5df94ddde285", + "required_state": "STOCK_SHADOW_RUNTIME_IDENTITY_PASS" }, "clone": { - "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/diagnostic-avd-clone.json", - "sha256": "09e4b2d21290de582320cb0aee3148af25f5e2e59199e225e604afbb6cb19648", - "required_state": "DIAGNOSTIC_AVD_CLONE_RECEIPT_PASS" + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/Manifests/stock-shadow-r1-20260902/stock-shadow-runtime.json", + "sha256": "540f57f762d67b894916a96adc2c0836aec803a8af9cba988b8b5df94ddde285", + "required_state": "STOCK_SHADOW_RUNTIME_IDENTITY_PASS" }, "native_host": { - "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/Manifests/gate4-r9-20260901/gate4-r9-forwarder-r1-native-host-build.json", - "sha256": "3a0bfccbcc96466bbdb83a14a0530906ef7c37ec0e0e61b8f701b2e534e15c7f", - "required_state": "DIAGNOSTIC_NATIVE_HOST_BUILD_PASS" + "path": "/Volumes/MAC MINI M4/TFTMAC/Diagnostics/GraphicsRuntimeV1/StockShadow/Manifests/stock-shadow-r1-20260902/stock-shadow-runtime.json", + "sha256": "540f57f762d67b894916a96adc2c0836aec803a8af9cba988b8b5df94ddde285", + "required_state": "STOCK_SHADOW_RUNTIME_IDENTITY_PASS" } } }, diff --git a/tftmac/App/AppCoordinator.swift b/tftmac/App/AppCoordinator.swift index 9852ade..dd1a29e 100644 --- a/tftmac/App/AppCoordinator.swift +++ b/tftmac/App/AppCoordinator.swift @@ -25,14 +25,28 @@ final class AppCoordinator: NSObject, NSApplicationDelegate { ) activeProfile = runtimeConfiguration.profile activeApplicationSupport = runtimeConfiguration.applicationSupport + let unlockSecret = try TFTMACGuestUnlockSecretStore.loadOrPrompt( + applicationName: runtimeConfiguration.selection.mode == .advancedDiagnostics ? "TFTMAC DEV" : "TFTMAC" + ) + if ProcessInfo.processInfo.environment["TFTMAC_UNLOCK_SETUP_ONLY"] == "1" { + controller.emulatorView.setStatus("Automatic Android unlock is stored securely.", isError: false) + NSApp.terminate(nil) + return + } let runtime = TFTMACRuntimeController( runtimeConfiguration: runtimeConfiguration, + guestUnlockSecret: unlockSecret, mailbox: mailbox, status: { [weak controller] text, isError in controller?.emulatorView.setStatus(text, isError: isError) }, gameFrame: { [weak controller] window in controller?.emulatorView.setGameFrameWindow(window) + }, + completed: { + if runtimeConfiguration.workload == .ownedVulkanProbe { + NSApp.terminate(nil) + } } ) runtimeController = runtime diff --git a/tftmac/Assets/TFTMAC-DEV-Icon.png b/tftmac/Assets/TFTMAC-DEV-Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..20d2b54687e751b76acc20f6d937832d9e7ec42a GIT binary patch literal 2743913 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%0D+!fS;9Mw@G!+;d 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 IW;>sH7bWi(HQru zW}`iQxb3}G{V*zrdCM&xSZoZP2A!Us${V?i0YZDW89daJlH76jmcd~3^3A<7A9zo{ zDi1drvbOs8lTQH-oT*LMP*6?5sNv*^kxPT*q60IF7GR1tNRL~YTmhw6V2@A=)sd1} z-MHv$jzY@T5=b6*PWs?FnxHg8RW*!L=*5xI0NYH-CDp+Q>g`qsM~Uh~0*q8Vp@|Tb z8k9HTnz^*!KlQ#JJNk~5y_Mg&{>880;jwHI8PFe+wXDM&LG4hYSwKqIC}nXeT|>%y z?ETR(*U2^|T2pF)BWux5uG_F+Al*HRBDyXo4m!Mqs~3R`XaY-PJQE-GFc#nnO)r;TPX zMlwjX88hLSEI1$*cAcc8+EcYkN(hYBUHNPOx*mOlzxcRZ_#}oe5?27Jn0`!Jy{aZgMHGlU zs1yZg(Y^g2y6^vx96Ihl@frQ&e@ESCC>J8qs72)<9^$P=3uWXP#1mWT!0Wi8xBW!+ zcmL`bMfGn!h5z>7u=NTtsX7FOdbk`+kSLlJx0Yy7qWmbIe!qL)54PTX)?dC^KKKdT z{50trIEvz?Z60@7ve?mUF*y}&=7$&CclP)CE8+ZI?)7)$oBOi2qc0)JBJL9b<~mpc z*inPvASJ~YI8dNCG%hDM4OCL~A~z~J1yvx$?Uv7RG8twWoZ~5YKiIuM#qs9xd#jDF zOL-jxVv-O*Oq@diDzfG=&SpdZl7uRy5g}bKO-8a&O$1ZbspgRf4u12`RY&gK`SdDr zuDS~y6Un6A$#!(Td{v_@^8KibfJpPRtT$&vS+QzHFX zX>I>2lU>$?8QP~bsN;~8It-{Zg=61v*nOW9L;mQ_ta~FSc!Ey&kHwovFl%YYTdER#NWT%zWdhMdv9yr zc`Co}s{hql_pzQnR7%$nw3%|iN$^C7HpguH@L~f5@aZ&p_YJf!m3%*{)?0dKqbHv zY@7@eagfr~eG`0ul#!y|zV=;>pzeG0NR^@pxf}W=2(j)2B{D__vdBh`jejY$7bfS( zk&;s)cA}P{IZ`dyWt^3v64*SGcwIuG%1v%hWzz)sP_eq8zURvdr8h|csLchZnD3BG z=IEvWK~+Ui5g;0py-@{%HFFVZyobpurQ2eLIC9lAl?7nv(nK&oBYtMU1QRl-YhtQN zvrU~*P=!&2eyPJi!=Pi0w@zwJT5G(q;;mV3h0TLEe{A=e6%1qot`JHaCdd>Nh;uB` zKt*EMgb(70ho%g0L9;>^j%J4s@PXy&W#@|l4R)%vwem_g+*BT9u2k~shl7zMK{)_$ zGmA?H56>M~K5+2Rfw`rnLkkNtGqcm3Ja6WWCOJo<rzPh%yy0U)t z+Q$0Ya1^SKxvqn<{po5DdI zSap1T`)mLCu~!}~=8lhUK7rBs)S#8xmXqj9ocyU)ZE%QcB4)Oe2~<+1crz!+hOyQO zNO*<88L{mx)gi6ETFbteMYyrGDawi(kTzt7F*A#WB|dbfxcvklJy^`m zYWtSv;=#uBY`c{W8l84Aa}>>a?DcT1H@LEKeS32-@Plo?cdfs6wOYL?H@9@FC)*Wv z$Du!l2ZlfZ0<(i(8$bG6)N11G_hDfU({t!6E$e|zqZipy^8qK1} zaQNuqv!`x*+q>TUzHfcsU3cDo>n&%`U3lrqr=D3^TO)R@PNTQm8!wfabE`MkMfK#_ z<9i!>dmFv!*>8dv42LX>P6UUTxnvar(%iV@uoXdm`1@ zJ8yaZ+4JXLymZ&ScW!KMZLf6?9y%}>jH+>!yL@%6ONGAnO?PyfQ_p;Tt=Vd}I!&oC zGd~@Igt4@ziy+W$b?oTUV_$o`SA`Sz+`HH9z2nsE)#smo{_D?k-V$>!nsP%C#P1_& zurIx&XxNO-npXTiuWdmV!{x}@kP21LramgW80=e7ByEg+!Gj`At*G6T)>VQOj>U=_ z(qPY+?QnEIF~6$yW+(5p504>uyq3CO(?bUuDsYoUAZ^z9yJlWpg1f>07Blf@j^u25IPmW3q?r^QT4G@S#2RS;2gLxny5-$Tq5jmfw6}$Spdmj zsv1nL39hSwH+yknS0NRSufV0b|CfHSQdvs3fUs-F>P| z>`0wV$Ss`Fw4xof0z7040Ng+rDUG0I8nBdDhpN^lrHV9Dw?6B*N37aR#H1pcQR@!A z{U>nb^>Xu3dHxU3eU{MMZ_Lsnv5T;b$OEDh5N6!F|3&^+Kjf+9Kl(fP+($6DKzT+i z8o694vV$ThIH#;>GMxk{c^xSp`0K?l{bj$);a_|dU-=_!Uju>IsrMj-R;U80QyGwY zBf+Ua!Dt+(+rM95^FDgbt<@;>|L9}#!tX)X5l7R9B&r`&EOpPJYWlAcijgsCv(Uwz zy_$X3oF)rS#RsfWMMb~^?R?Jp@ z6UO_D*-}UW!z3g%HDIC+R1_m9jJ;;lhSF(QK!s>f5_%4RH2cQnDgkP?X9!WR|5Y^@ zdy51j)#~ct>5sYPd#KzN8G*f-aDos!36gr`qFvpWA@56$;~xb7gDU90^p7Z2v}}p8 zW?2ZsO8RQt!hN|%`UKj4eXqKRI*+8(x)5IiOzv@=K*iIEtd`_~PR*U2)9Gh+A0MEM zP|Cgw-1kXpjjYjPCw;0kie3eE!*4tSrDTI9&s-_$A4I@}5U~fZ!k~h)RF;J4`DP=AqxP!yVfng^yJF%1BVZtT39%dow;T1i6>S+`<3e(TcyjJ&NW6p zlp;i6#|n#;p+o{9$H9xnpxSUE@IqfD6$iHl`sA|ioi?1-HLAYmKCfQfCk zx@AroYerx%eyHPs5b>L|SZM-}*dI(eQwi+gf&?!Wj9eP`-DI!XUbpgN%2X+3Vlj)W zLvu=S&m>5&P=jI(oRjdcJspX~VRncbERHyj?V2nQ02$>CmpdXME<*q~XB8CzIb@Eq zTr;VHr_yT$5`lOP#xb>dr%dMH<2f6EXYN_zL{7xs2_Od50Eh&klwqo))~sNfmW)XZf+eew`K-vI#065R zJKkrTZ)C+gik%_0yvPNm5tU<*5HyQZJ;4qpvZTh#Wu5F;M^r#mDp74LwO@0peb+6G zSsnLB=x&9T9lx~`t_=D5$lvf`FV#@zXO5pdb?dFC&zxB}c5?R6;kl{l*@N@W745v) zbXj|*T@8X#@THJ*RAh~2-UhoSz*I2cM>^_uH@8+_x%Tq;7cN{l_rlkoJa^%R!Egg0 zS1h;M2ZV~sSK_@A#f=b)X{e1QS@0potEti1eP+$dGBHIL#TYuoV7XrEZu$J=!|qQL;*~<(ev2i-K*6r-Q6L18QvJ* z>}_2f+_==ezFlpOv^T<_kF63zj}jOGW1u2NW}QL`xB?6bV|1UKmEDS{{MdUSKs>PxBSqL{J;YbyywJ;qhI^# zHO?%w=OR( zUB7yriL;^zWoWfpc{?8u{9tcX6h&G2h56ZLGkf}}7pXJXIe1w1cJ7>C__G&YTwh;p z%^#N_WVgtccPt6U=#hX3_W+S)0DzoLgof3=xL6W}!ZpY#Dh`ix1js~%;nTBqWME{#V@4HR~kab)l%%&Ixgk_d-)h zOHhc9mqaN7NwxG;h>ck^#Uh2p8_v=>1`}n_7SpV9;r$+MKwd?mh8^&lSB80D_@tFe;<2K5C(>jDiF)slGKMR3Fn~dRmO@A zz3mtAeLq<4R`PrQ1rPsMs;*I^K!7Tz01R7+n z##!~4!7ZLSOPyP)-YX&?8&6<6ixlGH8InZJP$lRrcV5f$Ck8hj^5;H}>041ffv_8; zawbN{>QZ&*e$ALSYU5niycaYtz02_H@iE!Hn525OsWNOPV>ioim0wK|0HvGhMFUXA zafIu(gK-yf|&gCf+p<~JsbuU;MXWqji+PzQ8KA2K;u;$9{& zG$9oLIPf&4mvw0kTLTPY*7M&bt_ev^j~=yEv!6M2;ZN+TgKJR(Dg%_L&%eej^Kkxfj<7&S~(nl*SnA3cHhy%_szcl z%y(oJ zx>N{9EYaUY4ysW^)EutXxoS*_6Kypv0*13GK9s;rJ8~UbavH_PlWF5hpn@0zQL_Gq zLRnO;x8K2_Y!kC}%nlm*p;w_SVKY=E#9r~Zooqsng*BqW_55nG{6r+$MoY}={u8na zTdJ&DW*D&V_Odw@$|%AJ20WSggyR}liEB^^Oqu~Xqcx3#3w*ku<`ypYbZv}nL8%1M zz?2b;w4U4Bi9(16%9m%-nl==Jr`X+#6l*`s+Q}TC1+@j;{@|2Ea8JPn>OGc)bh!ravK z{GH41eElu&`;PBHuUcPu<^1KxzyA0m4?gt7mmlfvJPQ=9nG@XTc%Z715V)HVX04JI zfpbE-Oo0fPDJdb<1tkR_9;C>@I#lU{to~d@NGBdvtY8w!G7(UWeX(YRBD7(rVsleX zJ|TJ%O^GX|5^hZ(j^~lMcX8p_%UDI=gNg`4TTbUXSX#!}lkV=L?Gy9G{A`$8&JG-& zU+B0-Mj!$=R@GkxG~u7t(2=P;l_HoI@VFC;}Yc%;|i5W$sCj`B@rzNp+O1? zVr`%GSOa!(Td-pavh^gsR$}W4T1~w21U8-ob-_?y#iG8&bZNw8Dw@R&7{^gqeiI}A z2ue=eO)Rm-OoNgkj~*p9HPJo`!6}ZXG$=^pl=(>_lO`3X=rh3xLa`na*yUPv1@0gI z&;Q`e>Er+5U;W#E|Es@t;lj;EyLIHysb;$sf`A}#G6WGwG?dlo^5vED=YIRoKmWOJ zdG7=N=okLy2OfA=o;Sbr$b(zk+pSh-ZfWl5u_MEN|K&^9gk*MkrW*KRcf5Rjp)=Lq z+v-M>GP2RCI!h*GJ)fe%o?ou8UnZ0x?w*B)X4O2eX zt-J786$uRinf`(*$XK9W!%$T7X5+GUpC3FljoGIz%9eYk)DbAtC}f{Tv|F`M>zYix zv{dVy+1vvWU=5H+_Mc)3iaJDsM*e@DCe@6w07_F*iBe*0pA=HaUJE!yo2XU=A=OX; z9`K1T9n=n@qMSi;q9$Cfp$}9<6H^&&nnAQF)r_*hR!*oj8qKnrd>?eboW3SakNQEU zTjFA2Dz2MkE++l7=_As^+ZPJPoLTJ=*yCmg6skE9sd9!{qA5YstEa35*#j6_DHJGC z`*E%Hy$mY1-m)x~qiwm6wMQv2sRm+FPt?BEo&GL4aJ%fhq?i93J5K;R3TCz0U{ZGk zscjzu#crk&?kL^&x9NNSs$5;sPkjt8{64UaEGI&+jEpjZ*D!+GR2vt)o%ha(IMx1u z-u*Y|7e1`_b>x447@zwC46gwWl0l(m1yoT^NIX>GSPk%Gf^=y4-TJx@V0jr|`%-x6 zXNXdJlP=olLbwx-7Vr-g@<;TRHP!bvJ>y}gYD|! zU&i1mP!mw|-~_e;Sk$7$4{YsY5lA7 zTuO&eKmU(%=$JQN?OvbG7Tz#@|I6~yQ~hU^LewWp82L9IHXb`U&G;3mn9=M50OjP4 z6!T8?Qn@)m#rr}@(Bw{q7@o5N-f|NaB?y$6lt@J?04mP9C>5k?b7-JGXLjUvO8w(! zyI0mO{Lpswwg-+EXBO@{F?aCJ#Y4aI>_@-6w&jt#yx=C25(z_@h?%Sf+sJCpaV*3+ z=Y0UwhGj*bssy-Pr$oeJa!_@Y30O!Xq@8@c0r=MOAZ$IK6eG1r&PoLX zb_zxb5klka%;DEB%^ztG`s3lnYyGSJ>e9yGVqbRyvLk11eb4K^=XGzs@5~)%mX984 zOfLp5dVBrhc(k)qGWG;AHP>u58?!B{&{>*mskq!BXx8pPJsMi|s_|BDd}FP5b!+FP z)t%=rt#0j%D`I5L_T0?k!qnMAGbiVkmtTAO+u!lP5B}7~%K7tO{QO^h_EVpF`q?J{ zZOxo%G#7jb!G{>;k%I_a9Lx+y2qAG78CeD}h)9D#rB9dAO9Uuo{2V5&Gx!*_&`V!X9Wq48+l? z8gHa(3N-*E2#7R}xQJFnlZUpzaMGC;AzMvRzSUthH7S6U7|38W<2Z9j6W=M(fEAP^ za%fU%aNcC%*bi|Ky*3=(|2Rw>a~uKmL3r{_wFQ zS6;rdvA*uub!IxPW+RM4R^-(%RIZwy?Qo{9k(J}B8kbokJ9K0*FPeFlWzKb4o$mH< zc5(jDiNhcJ&EMJE>E8e5H(tJQb@k@@{DJusCr(n3^XJa@yTf*;-JWigqfm|gcvM09 z%}yiFs6Qx$WMOgk+U0B4HU_tS%Y6cWdSQ0==JjWuehSDy#xb+Imq-DsCa$1SgvnMo z?~6mE4s@b?+UTo1 z>>uChKN^@Qp9P@fF)#+%!0p;Q*xF2alpT;W0;zZlTRHJT6oFz^IXO2`G#YbIjLV(m zQIb+g3|=*12LOapQlWKA8&V&Nxf;VrB_NWht!~Cq#=^362GlE5sR3?70qso+pGM%M z$XftNB5kt<2GY~70ipB*l1g(*T=$2~W Yf8JDyAH&rzQr6{+ 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≻D*of>L1J+a0^O5RWFdl3Jky@uGzV9K>o8BqGkiO?;56 zGIWcCUNNXcgDym7a@hmZI9!W(FyaUtK$Mise65uh$0#}pOC6r#+a>fl23 zNHoI-bPKmfMa_b$QxYZtH&(N6D-mO(rp04 ztwIK&p9(u)!15<6MYR%muu*ZO04GE?_V5!cAcBVM11OOYJjoD_1r2oentiwG((37@ ze(t1UO}lPLrSv|jWhrF&(#Ci^Y)mysn25_#rnk+ciRrGb+mzeQ=EAv)>ixNMr{=bA z+k3_Swe^*JqfZv~sr2wwhXWxiSmsYR7{@PlrdE)3x zs${M8RrwoNNCJoF%0Dam-yTScjd=MKI3O>g-5AAbMUH}C)W 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

yq zCr)i{tZ!}ieU_8as6P>r`NjG1w4Z{RA;pv-r$l9{42DE%p~7US69c@N^(H!4={s7?0AZpft78l$b1< z5;>aDnmuuzxi*;-YWaM=?CbFrI&qyp)1O|MM)moZK0Cn{Y?-O7K|xa~s8dQtM#QQN zB26(QX5^;xG4y*d|I{`BF0ahvn zF%&bT6hPDjLYgC!aXKcxW#% zjYiexm7S%f`Bta9y?KR5&BS#Uoh$0`AjJuRjKpFf7KM>T!mQ8+4Idr=1Wopy99a-a zB$Rm>4hJ{i^o&3Fga7@)7e4Q!ANuIuy!(Cg-T7~P-D~zAIgpaZIu5o*YAI-7c8iNE zpZVmce(+zt`RTJy?_0g54z-zzxnZ>(WBjgfdDFLl=lA{hU;VFle&tgk!sq^#U-#X6 zmiPVjJO3wxidLRtFr-iipNTNnA%d6)p{kwF#7lr3-+OG~u=~|t`s>d;b??7_@jw0V zKlHY5yYscb`{_UZOnpz(k#MdYO_NBl24HAnyTmuBk&{{Y%OqBbbL2&L?e33!^pF1G zHE(&-?|$U7<+&$M-g)0IeE&fNp=ObV!Az+ZHFKa|F-OF8oocI0Rh7kMW>GaY4m$yRpHmVf=QwXf za3>Cp*(oI$k%?;(unhpjk{SAOx-#EAvba!9=;ZoVH4Z*wKr~r9&m?nojHc2O;S8EI znP#qGU8<-EXD~+z906emv6Q^?^M!9`5^D_+QQ0}_crJ(vL$A$V$STWPRI~_{>b6oT znV=O=j3a5v+q!VnR-Y}4&uJC6IN1;K&iI9~xv!+H4Ga|n zaP5#hrJfpLeOy|UYmXKSYL~a;bfP3?mW(JyI=^0*AA!@XqpK$ z3@824#y+p-d;W%_i_f_Ez=>P4xo$SOoF4k@<@+Cd>Y>Nap5E$j1#)P4v~r($Di}h^ z)MA~YFnRVdYFpYz77j!$Pj7D;iNOTk!H;9L;JR6|h5v`E|Bm-1tIGWGXRWn&Rei#V zH|Nf|>81lT83Y6Yi6WzdN)S}UtT;NOTb$7jL0NId{QPTQHNSB>eeJ;sp%{*+X4>40<7l%!n@p!x$xOGibD^VW zxo=jl#=~Ezw%zD2dfTku>E_-j{&GeiSVMJJDjzQGl%{pd$kE8SRv+PKg@~!cI!M$JO4H?;H0yT+DuxIWmvEv1oCYoxcoKV0jSZ(A;OMr-H1!g+YMtzHuKt)A!%9nTD zc?EV6=S)l{Fb5*03GB|{^p@q-FP=O5(Avq>>3St4x{!jolex?wU6(nyrPXSAwN#OQ z)*aJ0&}1CPDFL-bix32hlXB{XiD;tJGS$Rzgt3+s%)!@Go{ndqzwH?>-*^3Ij(_Ry z;p07;30kk(+MM-gx$8_K>M=$}i9k~wfeL`4)xu7Znv?bmJAk=5|S8YBrwb16B2+NE@|ANC~2chrPjJ;LRk7jEaAi$820GVPkO_rbvZGLHnWYC1B$WTkvwbludK-zR#fYh45J{7`DTMx8W z+``lDp@vA(+CB*luCvX*IuN#MBn{NKpat5pZ!MI@Ozgl0B%n4`z-hO`o^;J(Io$m6 zSI1wwcj-&lUht+DAAIiaS!bOK`?NP-%=pZa(aDeBN?}4F zxfkDAIk~npob1~+*WWpdnXV2Ze1193w*KBo3&m7k$6Ou!o zqd3GD-q^i&QyOefGoO(pP0iP)Eyf1i z>Z=ALA?GMlGr&>%;7%|iIH62UJ!fj#$i>Y8Oi0WUgAI`z-kU+lF>y3)RA8edBq>Rr z?=3nPDRqGoHed?ehG~UhpaeK-J=ci=gEo0nRb$%P9#fm@X*39fk#oc}jT_TAG*fY& zxl>rTBWV&wb*kW!Zbg^D&0Iem;7VL^ zjdf>fRN~~5_Rt+PK8J!#4J}T|KnbSAfF%nhEW!debG@c5h*2}SHF75#48m==y%`FL zAQ_>@La?c6t(MR%R+zRjvB1`B-|TUqw$)L}Ey%YSXxlgfZ=IzHEqt2VH#ATc5^MT| zwNk5LN+KZHvN{sd)@_R#kgp?Z;=v%w!0zeyYy+^(;3`C})mvE@&di#6dJ@(IA}1Ub zv}F-@fPt9V3pruYR&?dYc+Vnc5EdAd5eW;irLAe2o3b)$KARbs#YlkYb3eEHy8rc+ zTb94C{EeUZ-rX;};0n!VWZ|D4`s8na=Lg>Lmp^jZOD^49UssxrMkB42jb;~TLKQS= zJ*|E2Sg5X3(P4}z#n9;%HqUFD8&|vr z1mOOBuh%a?oR}0QnajIH9HlZWd}-*e;ftG55xTzWh4 zRMKy)i>FHJxwFgh%sr*cyCM-3VyJ~{ag>zJghfOgKuBzqxz2VC zbCU0L^9QEfA8%IMU(@~NU)=ZFgYu7u%MbkP`U@`3fB7Zzt7Z7f-&sEWW$(H|YirQc zt{8>EX&as<8xb}^6H6ltV{&S#B96Y>iG!0yl}78#_Fww#-*)Wi(XuY{Uca1{<)mC& z+bFvErI%g&@1MI_E#%$<=5tS^u#`L3?c@mQ=o3dQ#Y--`=y@-^>G>~w@s8~~yR)66 zj~@N-2S5C!FMjFnJMTWTcD5W(3DoWNwr|@xJ2T59{rP^XVv0H%j#HI(?8N-uU0s)x zrOomB$x|mzpF3T~IyIMka~W;TqqKFg0slc(rL86Amg$3u9FccfK_n@vDT(uzl$bTe zX2iABdiYJvG*N?ifZ9`6ZhHi24-smbRCDr=Jo1ns?%lK7x!n6stkc5cHn4Sj{n^>s z(*Vf%nccp(7)NWV9s>!I5s?v@2BP*Efh{*ro13*JSWkeGCT7Yr-rO8qedRO$@~{8) zSy*Fk}q|L1gDQGkz zvL@}qEX-=7@x+YDT<*9|ff)ie)GVe^4eZ$GC}6_Qv&!b?$VfdGTkB0niI_Nd&9aXZ z;9ZuK39>vGu61U2b^E(#=c}j{Y7pfvpY3&hA;WPsts&waTY?giA~LDPBL4{{$*{f!teurm!q|s8ME`3z$rNw9Z z`R8TXGguawGJ?RO#R^)(1SkN8TZ7$=wLA6nz3JRhU0=ntl8|KNG0m+8jmlD?y?&me z4X66>iF$Jsg&c%c)D@&k(=xci$C}S>2IaUoSLDv(G+0vS#R(#Z)xn?+^E}!jm3obJ9LQ+mD5faBSqz2TH zG<02mPj{DqkB^p0t%;<=nI~t8IqCJ-70{QQf7vz9nEmQkCSQ2ycog!IMZ{2tOBZ)M zcW&3ldN{hg8I%f3v*;WUzjH_N!t45;?7@5MXk;oUSJSB8Ff|27k)%$zuu>;Wr7LZm z$C(4P<5l^#_j$jQDS~q7Nz)@by`zjrm4}oOlLOC@vdIqSt}s}~rd6OBCW1kck(Ndk zQKzZbB$*Y=!JN~nS~BD$J!WDEtWueGmefjcpV5O2$)-_5v^mh_aF_J3(^E#qX3_{L z%xlnFM}sdet=@Wi>Dc=EScj8rf_y;5h&g)lg^wX=9OXqe@4Sq37zW#AcK^)W(sb?A zctvGOE<{yLaO|8QrKpItl2R(IiWC7&q(q6q5pgx0dsgSN@4w)ccP!uem8IJ=>M*FL zNi^pm1)Qg>K;cay*bo$w5QP{-(dsQ!1TELg!?+2PKJrWDf+xqvzrOjkCEd)aP_dxa zAZ)Y=J8g+5wWXePXIxJ;m0^0WUe(Yn0;P$|HZed&)0Jw}v|AxD0mcnlsquIwz|4eP zvPht`m0V?rAu*^GPoOQ>WNVSCNQS!gwjpjY0;!SZwwA2?Elbu$FK&&fTTdLa_5oxL zTW&^!Aw@XXeinLapoJv^8HqrXO%vE)Y}3@VGU|8&CNQW2LP~>`m4E-r#y1~%;-%ML z`u3MycTq>2b#nUZ&G$|YpW}Te4vx9`g4{r|cd<+We6iVFuB-B92;_;Q$m9d^Tx3F_Y z=DKNRNKwq^5JMed3g?M(i-uHf`3W1Rl_LmT4r0WHAnnu~h#E!68n2B`plXzX1d%`v zS)x?cA+3~~4ynVm%P$=0?+-dXI(T9wtR-bdYEA&uZV!x!wZ&buOw>lbZ0c-OjS#os zz-T&YT4#5gK;>qzYTnW;Cz#lb36e}1lq@Qlg99|6X6D+0ni@&8$=IqvoI2~yV^@V} zFhxDZs4)yvi!4Uc#P9|%c|uC2LY~0Mw3!SWQHxrkcLexmDsjcIAyQ93UmdnXe#C1V}IU<)- znMvT8n1~v>uUewkX56ryNkMJO2bQcMWHOOg^8|`0Eg3OK4XWt7`58Z(b1{m8Q9Ur1 zAkCV{lWGOwN0sM^Nly*1~D~D+NjNDu#{SFa+5x7gk0O| zvN1(V`D%t_0z4Riv&K9Bv>RDW6)Xg4kAW;?3?p$l6B{hW2*^rrtw{Mc9)u zjD;IUcVjMYj11I#x6Hy2Gh&8nQUVj3frQ97rNr#O&_oOlbtt;?wy^*2?)>T-Prl$) z*I%wT^FCYro@?Lqsl)&NTW|iY@A>t&z5JaoEILJ5RU1nym}0Uv4JplS?=#$Ba~MO6 zl}@;fb&M0^9xd#gosP=&l~I*fW+{(FRmPLYPOYq;o1dSb>CcS@Qwzq9S-6_kXU{G# zFRfQe>nb5h2(}T26Pp5Y%rhHq2!m>e<@q;crf#^}yBV{o1bhV?f zzA1GE6_s)2|L*b9LtzpF6iy#~=TlQ>Q4$3U^d65}ecY9~g&OM#3e{%WQi4(_G zhif6W_x!DibSrw$J~s?cORY~kZrbNUvqB^SymL9R0In?qYoZmxDK?&evNl9u4FIXB zL2fcdEeEir7c`Lo1wj$ZRJ$xYdE)ry%1W=>iFK+5Q8Mb!%`Trgy}GoQsS7|PFZzph zUDx9kphnZ*ra)6Um?EG}C2|9LFk)CF0@y=qW{89Hvbj09@w)5(=I{RQiYu@9$cO&# zKY!}xZf|B`zNjbm|2}`);r&OiyZ)-)T&F1Ve!tu8_y7FQ{`^;e@mH!k?%cJ%99E*9 z5myFh_RJsrpTGS-HTfU;v3HzXIRR*=H}i%!zb8%YpFjS=tdl$NWHb`b-g{GJvZM$p z_)G}UM7j4!DJJu9aosS+OI~!<@82S08GiDKfBpK&yZ+M^uYKinUi|E5UH`B5eCeZ) zfBa$GML`9Hv4E5jDMb)#!-NA!A}QFD)>U%Ii+pnW$?z-!CTya&gZChTQ z(WA$P4}RqoPX%ZAn|D5ZAC{(&i7@%x89B!}bv)&%ijh;d=+q%js>+c_!+kZ*+2@2a zgVU?^s*n?~gOn+Bsnh3zs`Ap=T`#(J@8eIFH$QMXz-NLgRnc@+CuaDL#RHdJ*1L3j zZ$o2mM^>*=dB*nb^*avo@jJrlK`3k^#h{5XY5r)SWhaVSn*tdG68i(Is1> zmEe z)xwMq)45$#NT1KRK%v4(4p?5!E56xp6tY%{(1Puv+ z$Z7-tEoTx|SR$|omzXYNHJLIvp{ZbTiaJ>$qG*v|Ow=T4iA)gZ_dkQ5Z z-s%EPh>9fOW~#LIxzsR5nssEWkVJ%LKL_G1(q41Gqvkxf1@UQWP_{~N&~7lde8Fu) zYa@51h8EL4{m8*m`+g~b6s~9qD`xj)Pt4kZ~g$%|5m%#$G z02?w-+yo5+^6a9QT~!>MS+1~p-^sYTA>G2fZ@?)ah7x)O#^Z84&4Gh^I^Dg!;V}Xj z!eBvYnyy_&Q#ff15{M&WfDI1fNJJnhu~~(D4ynd;0%GI>qZa1m$bblp zw9>SemHC0rj*Dh4#3rqzb%O|7`@^JW7;KK|3<9?SA4`^^ny?UANCBj+1-ucMh}BHk zA#I&xfCk!RWZd+ll6dlfHFR8tn3Awh(4ZxOgdCBn#S?aHwOpQ~*)gUC<}zeLG_chQ z;|fDo5{P5hgijsipcD~Wx-mcyW>G^jb;JZxGe=o-_(*0j2ssCr+IdwPpFlDb5+-j3 zA!!~j+@_kGrz}`#y#qu97IKUPH2uXU#6}Qfzyw*w+Y4EwxN6mtsXj>*gq@iu5J;#g zaBtR11R)n2K5Sz>ZQ)prdZF#?4`TAbGNo)TgobfrC}ODT#H`EQ$;e(xY~*;TdOoYriJsZ$;b~ z4yIHBHkHXh*T-qV$O26r$%d^NSJQll4|K;TAD$l3i+^(uzt^%07s6kU%AZ;HKh~#L z_-Fj(`Q2aaeDR+jvyRMJcTF?L&ciYJDJIcUFc3>J4(bTGne)sU zBGn|Z==U=lXCsA`W$! zPDcm#AN;Ss`rj`+@BH=6)xZAxzq$LayB>ey@y)^JXgoSllhZ}>9)wPEoy?=FMc{G{SF>GCGO_$Qsi)UYJTx%`D)_2g_ zz=#-8piW$tyUmTw7eD8wzxjuM*ni-_-~ZL$eECb?*tWQPZd+fxES*>*LX7pJM;;+1yWj=i{;Y3*=`)}A>ASx0i6j4fSRa8+9cPZ6T1nC@ zavi|z7(vO5%?ycHx}E&o?f>@R&9C^;UwH5Dz5S=B8|f1t`})gYas7M#d{jKsS_;2k?Num~{=H&_G{W`R#=LbK+D4Xh!?q?s2ZONi_Bn26`Qy=|BsU{d7S zwvJzq5o*ljoOhm?V&>UcQcaF|zT-1;foV#Sjm@~rZZYHCeR9F-iFUxVvm%KzpeNKJ zXo)zrkSs5(zb$qSX!izJJkQa^L>+>M0;z(PpbYR3CeENw==d9H_0F_$%r?(qu*_BE zDsb(IW+?)tTBUIs<0QsOFcuSUECl1&)X2H4QivgEBG24$W+7Q9tB}~Td0Cqb9ymG# zv@An^MlZXh|BP#PKjWHSzniVC)%SjL`O!zt96mBwo21d8e#N2lzvsIzzWiD9xBvUu ze>?T)S&URP)=6vIOrtI%cNxg4YHDClk~xA>GI7Xql8tI*9ETZsCTh;C9@3{GPngSk z&$;xX(&^22oCzHJ-0cVtOGQQ@U?s#aK5^^~{R=LAU61y{m$dl}96gt2nc^BIW6G@% zb~BEqNn;wVPu2kQ|>$2E2x3mP=ZS0S)p0d%E$@L03FyEk_metgOxxHO5lRw zOvkE~V$QUqyocnXoVKwElW*^aToS%M9sPf2*1o#3d~|a-ii1EC_%-yV&a3yxqzrLf zmg1~aWOdL`r^x2Ss+dM`vfaARy>O>1!#7Xgf7DJDOlmQN$lM%d%&1wfn?glcK&B=j zVvVQ*%FE^83;Nf6%q*i!8}uj|nN6R1@DM@32~jN(v0B<%sDifop;{e+ zXzR4MC4RK$zs5M%%(}G2I`|gd6>tr?#8LzcG;B5EY>AE9Do-%8FeMTgPzN|~F|@qS zSXrnLYM2@lrqP^G*PF%g(A`h``mw*g?|IYBae2>!;Cb46UjKsqp&FE@PV14ARu737 z$4{?6yt?<&Z8FoRnRz?8VUdgkOqfQnhX;sJ!!n{gk7rNH-u;KJ+L!gHTt&F|I0hwV z`W6Yo#tzZoKzRp)mBHC@32dM1cNY6YRWw%KSVN=53Mn*ot6;VOA}02hlmx_V+SWCg zH5trKVe^vStu%oy`rE*pX{8pB}zRAv%)OqMM** zo(fNSnM%jrkW7h5k{N*=Q8I;@fTNnH?fvXhw%N((TosQAj|~QEL_coIpkNlXB4P$d zBj$q4)RZ8pA^id=C6E~fGZ1;^!XReBtVxxVrbNufTBni5YML^JFlQNDh_+jHUeG;o zrd~Z(o{7bjSS{tC9#O~06O%C%j@ZLFxWY`p3{fphNX{2L0~cIsjtIcHlXm1@)C0@f zB}NO*M}S3Z#?I!|OJv54cw!pNw)o&mW{nwGnwPFw0)n-Ua$?^j6rmnkTqYYr73^T# zMqzc!o=t@R!0bgcwLa}gG~2pev@9w}Ge!agBsOAVrWDN-Dn!`o<7(tmZM7FP|LQ46 zA~#z(YN5W(PKLHb*|ruJXcjcgS*n|-t^|Zhi0d1VPn7B z@!Z|%jug+Gc*S|w&F9^Z{MF5;9zXt*|L4aJU3`H>oP6xb)ukzcro(FO%wR!gEyTg{ zDDP+NZM-_IM>@N$ljXtz^YeYleK?VdP9Cbber{BBix4V}DUEGoV^~)KDp_6(S69dD zlRVEMG_J?dM?j}K9NC~o6>OR#n*jpKi4Mk?!lx85y4yD1Hof-!2Rc9Q@r-`@KXv_^ z6Mw33@5nFy%RQZaom>9m$t5dy`We$f2+pJ!VmQ?)BPBBek>m|1>`7SBqj!w}%Aj#ll1A^Xnno6K5KABsOF=ZRaaP=dB@@hetL0t zPXGJC^5YMLS6`g{$PJwnW%{w-KX>>e!EY1Op{|^zyvF2=mZz8o6vwG9fr==a2E+<% z8fu}`Ti8B4^Ei+ID~j%Sy!z!wpE$CyIi8tW7;H?6PF7FKP}WyJ)6;g~=IRudp7;(iOjAml zIU(_;P>rUhDVQZ{b1urxag*+D6GL0L3xg$XEe}oJ322+E2vK9l6%p82S>L{GVfXHx zb2G&>Oqb6b3-QEcv|jj*cUcHy8?9Q3Xx%zuX$usfseQ(^Y;$TmrJF2C!%uUxxv}|@ zo1XjkANs$0_V50S|NW=m`1<|lU2sWWWaGhTGMaANF(d4cK6>KkwMHTh(nW5Bt6TWH7XZ-~BIt{QYl#>+k>epZ&>){$N^8fa=1_U-0&~zUz)# zZ~OAszBo5CA442&j*D)-ZO6{RU}Ix*v)=&;yG#JCswj@K+?CTnnRYodxEOhOvfQdNKpc?AroU@?+@2~&j&Hw(<=f3SNxBtVZHp8Jm|Ii&*{I{3w zyXBOedBw6?v@2VOI?>@5cZi!NCB!$iJNVsHFiHDA&sg@ z9eax=l#2*bl{ATo5(u8H?Ztr+i-Q5`1jIy^0CJv%8Bo;#m&X-GV4l~30L)af+@pt${93CrGYxsagdnO z{<-bv?Vq{j)}^J%V4GibMzJmzvm&rfQAeZYfThiF<-Q^*j(ytJk7#d^^Dd6vrRyVR zPm{9VtX5|n-EfF5xN*;}n~K@z`)t3+EMts#pANqfF)622 zrJQ(0dPVi*H1aO4?zv1Q=&Yb=1>Y1aH(MC!!C(Moo>n_$ll^iRrE1g(H z2IhpDbBnYta>_A@Jk`=?JFx6_KCM!}{^Nla?3Jo$`VjcTfOMtPyG zRwdVZAt)xMmCs5?@D+6Sz0|^pXgzxwpxfH0vQ~f-+-mPg21K75_s~|uP7A#EA zcubnw8)-hcA_b%XN?>mxz~wL_%F&;(Xy-oqc}xamuq;pK9>e)_i&tDA*IiMcUE6r* z!Rn!haO&8p+aA2;g@<;}b)V?XsAdLf_L`uEE+^*lY_A+fr>4~t zrvXr2G=5klvj%nJ3IrXV8;(mX&QW*gECkR9Z-@z@1`?3kqDW8+UTVqu0umwyvk^lX z>`gpDgmY4u%Ry&tcnjvp4MO?!I;Ds{jr|qgTVoF*o%#koLEHvX%j=7#(Jlngx(&?}~nsi7)%vn?SL@ha48yFh3rzaMO zA%T*$@l^my3~QY6%*-8jMNE}hVx|W6!z>1B3VKy^8ppyJne;~09|zVqC1cAGR7yNO`}T&*EI_|U51TFQWFYo zL=J1}qe&X6#oCwAmj1jYx;9s7WA1oLIVr|A-Stuf@L6|eiH8sO8 zt0rLrw@#Bb|4+=qmKwFVwUNV!nV7`@Gm5GVkTD6Tr0kL9+1lErCa_9OZkGUxQ zg>I+<8C))A=0);CVvIomi$HY0Q@7ihtW4P1w%v2%NjVvfQdx#nId#MmlT~$?R%O=n zGuyjyqneiGbUN9!b4Rz|v9@=LlZ(Ns7%Ko3rUc5VAoH71k4j3C&Vw8|=SIIYe#Rq* zc70$Lzm(J8Nc#IJ4y*il=fLkSyynX8?Z0~F@#W$EnVp_9(M_n!U1yXgQws#2%n|hx zx@Nfr$-4gfXZAhYv4QSA*xfi@o_S*0?TJSW9N6j@N}|XlU@;>WpLOP9IZJLkX7<*l zRB`&;AKvwQ@7p$;;ScYxKJ{>V%_Z{QtMfsnKl#V&k9}P8d1rB=gEPp7Ha@G>5@Ey` z8)}Uu5ZD$CqAl zs6?pG5`y+Z2`!hf+%gl5}$GbH*bAfQ3X+xLjW~fwhsFakw9Y% z(Mbk&-shpNNUil~w0mxAV%VxdE!Y+gussPhMuw-35zTPC6<%pB4glk-+_hteLp*!x z#OiQ)eeDb&EHX1Uljq$q-mp}{8X=dBn#$yMC?{|e9HI7lQ#5uUfrxV=!{P9G&w9?^ z|KmSyTbTXzU;6KN-1YGDU;L7N2lgy4FV|I;LU1DImd~&YZ~mU|8mz6o^9O(Mt6#o# z-~RJLz{c8ICY{yIr9-<8{>h*G>GjWf#()3i-~N-o{`07nYIx3b-tgA9z4J?7`s}T@ z-!j+V<_aQ&@hFrN>-Bnz+jg>Zby=nqbC+qfJon;+0Cvg1S?)YJ%e{g*@QwfJ+UI}t zhFb=A&2F2QEEYMB)5cw!=Z-vd^wW=h>1F5L^s-By`@L7c{DH?0|MNrt@-OQ*Z-x_| zXHg(+0X`cr9)nUc&bia?ZJv4fj+?*mUw`5?Z@Bp@X=1nBcKmlg_4qHm_QE`3e%~T* zoY2)Jo8NuOI}X0?@6P-8M>ZCU9i`(2V4+4vDJo~|!AP;$12KUjs}M+4gfsR=ly&kt zRaIT*MV10P7LCTt?3^cWMg$V}o+SkZ#CdT{TBigvvb=DX)Dek7OtQ>naOE@_o1e;| zo!Lw$TRRY&6i$o^&kH@$V5}^R%pukY8(LSEb##8t zwqNJAJ=gbMfb4veS<;-WL1!jVf_Y*CFCjjZ$|Gt0k^1z#)8Sc;r7vTK8Lu9LQcG6p zOQ~s8>9`JqVNjUs7z;7j6;6|t;|ffai83i8LYb(O!;7oOIv7u;aX1Nss-AXpx@>Rn zqC@*HxnSmkOFIgF;)#{df8*%mXV%WHO+#ru6g}zh?k?``_UiHG#oPA2>NV$YzbL== zch*01$74?nmq%t|Iml(q2{D;jswP@FqK+#Hmr-(#y?{I;q*6sGnWrpcF{DVjz;&hY z@VU><-@R)*N{=32+3pt#tIG5=(53~nG2}P z=z)dJG&wEK>&gs;voS~J<~{Ef9i}vh;)Um#dSsghBkF>3#I+RVGLQiQg z(Lv$;j%TQ4{djIu{r8va|8#2U%gd)98Lw}IjT#fUDSV#w=lVtTadSKv>o_7BAy`TZ z5ub@qL8F;EOB7?MOP$UjzpA@$rJnxf<}D?LJ#qy&p#)L}4hT)7X@Ug=B1=@)t{IlZ zDXpfJXVal~?0@}ZlaqI?-aW>oCt0$pRO(R9poox22_(i5)n>Imz-EFv@&Za0BSK@- zHA+BifR7!>v%8l+d+x#yE)8B&cDttwHMK!OHT3Ct)H#G~7%0~hn$ydHlNlL<1AmUili(Px*-J9l+2 zIzQic-p=cKAY5NZCzy3l9CbKegVAnc3GBOilGRLSYkich1 zYAHY(L~B${WEwO9(#!jM^1V5Cm+Et+Nz$MQ#EtpWo{IK0tMsPM6m3SAgv1ERREX4A z!4_yzO=_!JmjI|yCIp6H%PihZA_f(fWFe^vQDuWO7?n2JWxFrt z3ts77nbaQFqi1n?1E&*0#FWh$q9PIW=~aF*uq!co+-dkeQLdJ8-h7q-LM37N*I zk(r3HrO9x-QNFl$?XCXdCnoEf3H!eBEKAQIX31P4Ca^Pju#hKMvbv_3ZMgI*+qV;Q zMq}8chjHu?LW1*90I}U4H9WQk4BgcHCN*MR5G5`7hx1q=D%nK%^ zh{m$4H545&LZ~z=y529Qvg2f%_4f>?c|dsSPwx7y_iURL{Q5oBXC8@fyn=uDDz6DY z`)BJ9elTTo8D%3oeH_@ZxNMWttOL#}Er)6)Okq*W+BC43mX)AfJaDyE>#!+6MNxdm zD_<3=^0sf>d(nj#!8_Nd0_t@Ci>(jK2!LfDVSL!G&Ou=bK-K>aV{5TRb?hM zC1w`K46r#TOj2|@MYrROW?MYMg( z+n+`$HciDMK4rkSf3tNn7hefTpGy+gdb` zH%+Z!jFbpOoOu}xhR?t0`5*oGKRLnA{>0DSdFO){UvgF6E#|k+EuCHpvF^@v9=`vf z?o9Txzx2~a>2yvYf-EF`B`+xMJSKsu$cmC90f9N0B zi^lOwUh<~5zx`bw{m3V8yZxKnx9=#+dODhrvu-ahr`5Sr=eFxb`n zQSZj*?7sHrUh?CwJ^kvB-SbbMD*wgTx%t{uwT`aHVqJUZ2+%}A(7OJYKmUt&zxAcB zf6KRh8YJe&9Wd9SYP^>Ua1$7BX4LPi8~?8qFOBX*93OxUD9_kvDixtf)3ktJG!Nc>(WuCe1zHWmmFWB-gh_Q&ojVGuL_^X##o_8(*r=eO)(> zXe_A;n8Z$HzIGJ4G_FHgoAkL98!n9LFbo~CsemNgjJ z3~|y)J)V@)@o3CeZ=2_5UOs=t)rSrp>}KlDov9vp^yKI7I&%2T+S0hHD$A)Wl=pq! z;bL#T?flNReihE!vFCX&*;eeLfBxWO|KEL&t(k~37D>^By{R%Zsm;5Y%jb7=gwL(7 zPNpG2bIye{S*+@yEYhf63K)0b3(k|#B-OJ;FW2nhM>iB$kRFIbRWgg1%*aek)GIn_ zX=PnE&P``2_nuZpak5=On$o_GO9DAz+G%`Wa{S7+&jmM5o0mdTvxKy{qR+OV-zpe~Uo zovIDsdO{h+m0HD;MA^;QPI54#os3T7rf=dvu%q?p3rov4pE-NyV0|f7)BY6m72LWj zr!J1ulyoDwUZT2kWr%T5O&vQD#Dp?blNewip*q#UQnXSu+}OWlXEFEX`mRTCW;@N# zkWW?)ZRo)Q7cGFeLRlMN#zd7>mDQddMH=YpvuyW!U-G7d-94ZF?7yGInT$GBnkXW} zO)VJ^pwUuBc|f&+wb@jx*=mVN^B_=!MqP}SfF@RI>$d)^{Ic)f{gQh|4?Y+loS|N_ zl%NK6AOoUlkLTxQ+sa^dy<9TDOe2(mgb2_?CtY;sXkl!l0XCc4SVB}N8T=N_v{~y% zi@X&%6Hr0`D5oBQ%~C{D!!8k_!RR!TZPK_U&o)M(#yn#THZ>wAq-vot=@IbMWZP&( z02(iGgSlz-(son(bp5#d4_n-)q+L~rN7L(>3`l66WF%mPB?ys_#ROu4T8hvBR-^Gmc*M}ivo;!r;b3s?7`a)$eJ6HrKmVEwzxNeaU%#VcG46TWGk$Zh z_Vo|mf|U)P@0u54G4CMYWRkgh{oLY3hc3Kwr|)8A6{EWjV>0I1Sw-8=NJuasfwDrf ztbFp!>hhpC(BHmi4)a|dZn7~sQOb~N$kUZJ1cOL>RG_W-o&lEu0v0&WJ|lKY*^cL4 zb@0mFVLY5EW@gXZy*|60P$74!3?q1gGDQPtW(EYL8f*|UQ%iBvHXoms^KMSed+Ctn zL{1S(8`c;%Ro?_MHh{E+8nKz`)+)l9X`2YZ7~}h=4`3QrY+0J4{nmLWXmSv4fsCqT z(GoYz+*X`#V$ez0w=)EhAvJiZO*^|`r%vmU9k%QFc)<_2H`hA7S0A_qUpt8tW@JsR z3z?8avkdbG{ndxM*PI?5*-Ym=Iz~|~5a8e$9FPdYL?B8qhB#zQ!X^w)pq!;a{|I|W z4n_nauqV%i+JYx$@|D$!L?#9y^mEKx2$7d2)d|(1kO&n)!xp<(lO;=xqu#V`@z(pn1Ta{jhNj+# zgt)!a7&+&26 zcS<5oNE*|!riSay*5J4p3Ij}-+bOw;?-G-D;5^n*>&Yu#dG*{(k>_~u!PQ}ugU`R> zx95s?Z7dHL-XWh5+GcMTH|26;34=+n^u2&SN!t#1rCsY+F zBde1nrVhL_JGh6hyrQ=;7|jcI5gvM|#z_17`>0beilUCmz--7noxIqQ>VD=It-F6? z>O-dA`Ev(;=k2qZ=>NDse&PZ9?yKY{u6CyMlmD>x&5xJ)tTT+_@@euTt2T6W%5?^) z2WdLeScx}kd54h@i43N0X4{^VyyZJ@z2)oUQ90NwUDx|Um?gye ziYqUB_<{S6Jo&`J+-@dEf(Z5Am*tp=MO@~xX25Ll{LXu3PO4;_lR<0eP-ba-xlcKxwl0iDceSRDMxVO=sBM;RbTDo1-Ss%uLo;JY zk@vGKOCiEbhz(k!wN0_GskTedh9uV9{@QLEqqaT(h6Hjx>mUWwviZCKnI-^}aY<0M zvI>L6VpnqP$aj0)tjN93x6T*T+CixKK2nphZSVnG!zwdt%g1+aFc`kzc`x|*CqEU- z(U1S=Pd;$(6PG{Zx?-mD<{-#+aeO{&rJZhGZ+z3xAK=3oBp{s$h| zvAD;mW>GbBBqGu&@}!tdhAAczB5+w&-fL7&DRp|Cx>PSxd-@!h65t%b)n{>e0K#mp<N>{Q3d34 zmpkWrJQ(P*q*>1P&w1x1H&9CKg>wp}X>D0X{ahRtgSwdYD4PiMzsyWnqd-Y5))FY%;1^UVYL7F|Kp`l^F-H@;?OZ2A{} z{?OOgo~T5GT?PkJA!2fg65zU$9q8_V&PC^6eqL5p)rqC)sbi&adUE~Dxv=gyGf?3= zp0jCH^`z)#IT>%(6E7~ee6Ufb+IDy6^CAo20*qM6{=hskvv2X%bt^7>X$5T3{G9;;-S3+={5%q*Tr=Z*=)Rscz1@N3$FfPdU z5xQhk(`0f${DS8>(xo&#T8U(CZw_bmQb~?|&+{VN1jIm2FwhhhEskoPNwx>HTm0Uf z7YG@VC-{a*0-V*(iZomwpDB6V>E`Dq=R_E= zX{wa9wnRZ|OVN}_h>6K+jkN}!!i#6Gysm%2&Ff!3oz4pCWMvW(OOmX_B!PvT03}KW zd-7mQ6hVN-Ra>7||GGopwtKq$5AXfpzt-Pi&Ik$AAXGwxIr5E%HlbFiAx|6#CJ~JQ zz{DU?B()%IF-*LcFZquCOOFkf{(0>yQ^cMzTHjhT8DiEiF6P@etCh3Uvjs9{5@R*q z!uf^?k|RGWvubIOMg$}aOuSWNNdy)agGH;GY6so|sX921%&`}ukeW~-F=Pw%3L!BA zh@vGXX`RMIW~te#Gy_Po#(o^pZZ4Z=0#RFgvZb;DEdsSkvC>nIK@i}c@|`xWKeP53 z1=d!ZZ7N<7$mJlIC0LDWXbi+i=)e@IL=12SV#Jyp0l_BAdiY)%k8Co4Dw2T>DYbvfclVhEe&RhZ8cFwo&mFbZbsKKN6MRldh`nRflga)o zF7WexB^*047(Q?e5$c`QsZ~s?K&jAM<{P>PAbIdpb(c5UzPn%3(}qvON4mUPNZr7xL1onzJ} z1lRQ#ZIJW~{>q#a` z#u(Z9Kv!3=G)S9o;n!c~uXrdNUdCpLDVs2>T2NKCtb>Iv7T2rQfv)D%2QovfFy4Bl z`aU`Ul{QJu{Q{(B0>^MLA&8hWA`dYm2hR{D4wf7o%yN=wNiBG=S*$Gxx&?N4WW(}A zsMaTXnh<~t8a$J!sVT@cCAVAl10f)3GQbdtxdAc}leR}FC!7-~#j>F;5jiv33YrOs zO$h{HXJ`p$26B0h%x*7_d}BH$cAEEmo}2VkxzQ#~gj{Z*rmY>u*5t?c@5gnQ*`Wg4 z43AZ~?=h^Op)3Q;VgQ6h5y{#>nIMH$j4|30HyM(V>p;Y`f{vkPnh+9-9q26L%mY}z z4{;enXbiN>h*P8qEJ4te7PLYRj0hGR0GVsSY|T--VScuIoh@8&8%%BfZ8Mds!N_Hn zDm0Zj7N884hPn(;L;7tPr0u!9^(8V=I~$uR*b@^pHJddS=UgYc5MvD_P~$ZuYIX|E zE!0S;Swed!-i!^z?97xivSb7%Ng%S+U;;&>fteU7CL)0mv13Av!AzN@fqXw@8U~Xl zh)COaoytl;=g?5EAP1NhrjQg-}}~|eA9Qm`@8SB^|l9Yx%=#i>Fz`OX6K3+ z>eZz+*I}*GV-Gxe#dVj>ZksuK26b6a$0d1kOvi zBM-;dUL`+rjT=S$!e4BB`A;WVkJu06>Jg(sDpwJf;VTUjttW(Js8fuV3}#4yGo-3y z3v+ueSzmf0jL$L?5x?MtFFvq;_aFY=|C(KxpH@{EP3N|Cs%bS`8(e(xr62f>-!!QA zg{nf~ya!NKrE2mbW~QdX5!qX=|y>%~puEJjAee^9UnT zBO+lhnFn*KqjLfy67eFTuFHC$-!jW4O#sM*sc}<~Hs~g6kb7=4SmKd);(cD2nm960 zs>4=mKx^S?`C%HHi4vBY>yg@n0uy&YqB?F;NY?nlQ~_+PtjQH_er89#;PxLpI4mcl z!6?=#RLO~NHlw-~T(_pGZ7Z<=NV5<(1CbISELrXcgTZs2ebdK2{!d{tdG|Zt^Uy;_ zuDSLGmle}84mMV-(ra(HpsJ>qUv%;J|Iqi`bH^QTfBO#|IeB8+!p?CuEyp!L>ywk` z?YQW}ANjOO+Be^E@0}4T)b)42?)zT%rZ@lVr@wmtJ&*0#vu8RgM}we@EOXQ8 z6ogKZr>J#RB{lM>$|}oqjfq*s`*Kn-xX6o8n}KI%=V?2#&^fw({BJ+>Pw)HXpS|ta zeV@Po3p-{HO)#!TvD@uN4OLz3+Oz+nt1nsIn0)ZzPn0Xe8~0uP18@D_ul(6J?>YN# zh0Kz)4q=UnAe>1Zh&a#t^Z)1f{`loD|C@LH#DDtrANduU-?y@B+aG-J7+$yUO;?@o zE;^cS{<1&+LYwbA_m>a7^5(<0o>;$N$Dv865Gfaqnur}!R8v*UoTQWtD(nO~)Q2P? z3cEbxScWN?z#wqKg_sj&F=2R3oH@=5)|gUIFVx9|6N5POj)^TM201Uz9I<*4R%4}J zC-=!V)^)baySgGwRGQ?@%rwFnu4kUP5b_KyQLdyaRkK|>{~EXL8lHI$`Dd`q6K1SY zPGSkvU=PW`HSjpXW48LBoqZ5zkA_f%L+52#?xsN}jyDwRrlT0fWrX)qAcjx}b>gax zFsLW$Irlj;S7nTo)bIPEFOy*`ry=V*X4aS@>ecDS+Gtcx#=95jJ70b1+g`SJ`%Jd> zM0x*XXC8d~=))(^Jh8gEG#S-VGh_wloleo`Zk9YH^@uLIdE#01lS$YCzUsAjQKaxo|7Y|FZ4uyD-Giy*CG?UHODSq~WyY4=mUB7t#4KG>z_8+#v5&PG_k#i?T zfOLGui74_8ztHhQL5)qaSvI0X)3N3xI~TiagD|RD#Aia5RBQ7>(=e^#Fh{v7&o8-Y zZqIAx=3ndc^B6tCQN(Yi$wLt*AnR}?du7fD!X}^&0Mn_0jrXvbRhuE($8w&4EuD#O zyQc^pC_K>uNmpc^>r-`gHj+uc!x|UQt3+WRk|!q?*u>GSjG|aztd7Y#OR$ z27;<3Gh!qlX#@bZ8WpE-le_H3`SXvAj^8~!GDX=Ts%&#DRb5a-RbvWd5h+;`@{VMZ zCI({1h&s^0q7|?0yzuD8`k$ZvD>IAN%B3&c{=(Ds+5fxoFUvOWV@4^dwQ@l~U2w1OdsW&T#AQd?oXQ9c zXhI?w!y>}ihFNk7%iyLMQ{&M!1Gs6&Xk;Wn7~1|F07%Gr&IO1Xf(0hdkP%TvS%p$H zHJ_{PG{IBPCuI_tHDx&sC)uE_BGNWed~1n#YZ=0SOts=$-UEQ!^7kp8Qji)`o+W7A ze$9x0Yo55oWGTREi^}4Zaz-MpO?2zqY#zf#mTcpcRbx;Ni*RUDaAr_80SZCx2$X8Q z^OLu}Z)5ahKl;koUp!Yb)jJpX75jRScWBuc`g%t zlkIEHyW|a75&hC5sN-oqk`1@!4=Jpk|Yt^JFX#ArEo{ zM-YJ%5(5O%XtS;f`Is_8GzMcsZ1S`@_RPzL3AUcjPOu6pGs(=v;K|ewB9arARE?5a zw5^zUW2tY49Ilm2q1^l*P|^ehGbL7#5DCakn}xDi^RL@5u_%m0L}s1unP}xULkdh8 z=bpF=-=)r?n<_j;jxoAaTpd+6i5ndCbtA* zu)u(%5P>P078w|f(IA~HS*#GJ(9r%erH9@QaE-}f)aM}D&YT3K3OXT*ZJMeXBb(O{ z$jG62$(SQ1f*N}?7KU#fT(=U@PX`y;CTO*K(i8?aQg7Scs@f)IiHUO}QVPwwu)&XQ zxf>ecl35Dk%u>~=Qa}uK^ZI8JYQB9nW+4*CVk*r)%Uni~%wp>W=uB;hjcA<0bG@HS9 z*eH1~o12?uHJzRByNub9^D~7{h$)g8B_VY4&MdOo zIL-3jqIDNGCVtwL*SvqnZ@zV=Ap7kH<3B#EZ@gOGd%54J^gsXA>Rlh2cxH;zI5f!RupOqwbX=NTLyl^!D~JR(bEPEG_)mcs;9)e!C-LRwby^> z!yk#&^xg0L(FY%T@{$WK@AUf+Ov`d^ezpqJM;?6a`7gfd6|Z^KS3iIAJKyy~$ImQv zIy044sY)ruQMGx~)i3(!$3AxMS@s_jPtS_dgqN*!DiO!bz;qZm=9^0Q03{`XaX z`_?zS>+b(^GpGwKiJgIC9f|CU8@_$-MOUAC;>lA_9659BiQoUD5B>7{fAAkZbmQ>{ z@5WV^o>~ci^u^PA_Fee=E1$Raxx06Ky{NG%l6EkV zt3!ySrY1}Vb1t)5$CJ^7%Q`98gk2#W0;@^4=!ps$ix*Em1Z9Eu(s54BlIncFH#^r^ zJ2%n5S&=a;F_V(_;)z+sR6Wa#mkg9S&br*sDP!tnkb>Z-ni?etnuBM6H~V7AFJtZzb=swlCTL?ZEWjn-V!D01 zJoB=J8?L$V+8gEyk~?pC@~^)6;N6GMJvm$t)woH}W#Z;Lg*PXOye6iUd#{ygtrzdy z@$HviarnvA$B#~)^KA!v2kBFPas1}Pk9M;jj3pTpJIM_cRn;^XSNM*p4Z?U3##NO@ zgJbKTPtRQ0zPePcZ-k3F2dL{g>11O#Qxq91RL_R7gBX=WewO;%XXm^l-=obT$Ry9q zd0Q_BtE1pS=WXj8y0UlR<=Ylt={n~--o^;92U5I0>HSJ;oJArbN+1Ro1P3ia42U&3 z9c4mL6!7PX927IN4Q0<3VH-)K@uKi9N~KlD>oiJv*SQ_cb8I8?&QVU}Ne8MU1Cr*^ zb_Ck%vO@(ec=%>a<@VmO0=;d#@s)F@zj9{%$fz7psPc%p;5s1}%ZqVHQw>oP2$M9K z#Bt?DwUo({af%v~#!~A>HLR>AVu4pOFeQyqtIY8H#cQwTgLf?-xutq=oy**^geFEO zm03U~!~&UGsX#%J5Wxx~N?1;-m(kvzzvO#PkJop(2=rFg5T@B~rCez+SxgtXJ=O;T>o0`_SfRR;bSp?humC88kpf7-2`Pf5G0Kr+(`3mYYN0}^kRpk;n4Mr?p{9~DOrSMH zpaf1J0eRGlTtR{=qU)tAGLq#_-1)cr4_)}9&srf{d-#~%J1uW`R`K#1W^rZx$WnFR z(e%(0_T*#O(b;q1wtk-;UB&p$$5D-WX2zxoOlFEYg2_k`0*H_~Y^<-J8V(f;^W5Dz zGf+?!kPCq{F~~z29+(4ZODt?7kOc7{f)u6>U~(Rl60X1PSr=?OPmZmIN0!jbu;bud z=e#}BuMsPw`8e!QmklAKfi4m=Qq#VJmYl&#M5d;s%sPsz^@ zHzCHSDs@0ic{Dm<%L$VTwSkxoO%nir_b{# zszWcwOhhm>Y5D_A95O&0Wdvq(WaP=C(OQYkEFzK;EHH7@GJ$%uID-p&vOmal6qb>c z$q5|Hj6%?o$O$MVI2N_05GN@HRo(`Ez5L`{SfXwX;9Mu(}P zo0Bmhk{LSA^$D(yr6G`mK~0mUF{A^YvwV-uo=>`An`bml*doE3FwE2W7s_*Y+ulSS z!DCZ<=m^G};Eur)Cla$1(HPEIkQ6LvBdP+8jaWfU&|s;C1yCYvRkP+ftis0Qn4BU} zG7zU9jxlH6yrDFuzOJ>xS>>ky1VBBGYKy(N+p$8aEK5++aT zGRdGI<;)i%nKfnuMKT4TL0L##G-!z6rxi1ol8QK0YWJ~51O^-+L}+-&X3XRmq)K3B z;ik}4lcsub-7^pNx?Tj2+&^47W4kY094xI*R!$QQUiFr@Qo-N%yFdQkm%RJs-~GaS zKlk-}zk2_?WG^}YdH1d#eeAI#ANZ9&_}~Zs;RoOIJ+Jw`S6=smXWsg`|99V=_YF2D zGqlj__nb(Ip)SLCFwVN1b*UUxdEqkWH&)h1qtWcl3qp0ajB)VoP-F`C{rkGzSYH2ux4z};x88bY z<@l~`7lu%I$rN6c$K#1vBp}65T2d&CVhn208k6t0q;#m=INDQp+{Vq@gt@6rgKKl& z78Wxzjg!&D7r7=26D5LCSY27$x%09g{l#Cs=bK;r@@GHo9rb4yy(vfP5`AqB*eZc5o2zi3jyTl^kiE_T-__QVHmmxfj^d zcqfxds8UKcnU=%NiING?bUc}krwstPnSHHEDoIYxLu1pzy0zd=B1VMF%XmDx{Ibjc z?t_2d>-ryh`@8SC=h3UKytX&f8Lo}sTz9579ZrUm(X*fZvhRH3>%MUFzrN$`?>upC zx!dg}B&|}SIIYGneeP@i>Ej=M;I@Z;;9Wm>eEB#~+;r_Lf8|$y{^CP>KmF-j&Ym3Z z+`Vseb+~?dt=paTz8b6#0atW8>x=bjInL2r~b8ey6$*0vM zmu-u4i!h{7G^N7(kA3cgdk^gS>G%EAFZ|Ij?Ce~?j_Wc&$YnCFrlWE!6rl9F3%~QK zo!5Njo^QPVXI@?W=|w3WX6#a9(aX7P=GVRF7vA-s zU;WsS8t?|1CJP@jFl!n2B>{n2Yb@F&Nv&9127 zv`Q|gsH~KXGKNM=?7SvT(Y$k2s#B~X6k-5Wxaj+is)#a!y!TB%H#b1`q>^+dmz}$2 z#AGlootbl9h(wHtg~`E$j1|J1GrF*xIQQ%cJ;H1sMGjG-F+&apghYJS(HbBf*qt!h|l>Y@4I>*fA~G zPOiqa;3u%@G$kf;Ql}WFDq{US6J^Pr)H+(Ph|!(N=VyxC%XCt$Yz#Jr<4G77K3;O+ z+;eZZ@XBjC+qP%b5VY(p~2J{1TeKtwwT1=<{Wp07>F%RC#+SLf(f~O-nN@u zQFJ0uvMW9n$#?!PL`M`T1pBh4oam>3$y3XU4LbN@9iu1ePjCg3d)=*CyXpc z#L`An1Vc1ar9_~FIMh&Zp1~!=k&a#~SVz7jeV5vD{Q5@Omn$CGIJ8=Ed^z6qr{{6JB&(TgmqDBT7O&d*O zNVKYo6GbGTMh$}i!D3T!(Iid@FoX&zAaW0_NHV^CWPn=ofelHK965ric@Oq5MwTNgrWN(F&U$(D=-Q*xaN)LmW>B-4U_}a_d zCHv>D+T$L+aO11JD=z6>b>V`~aO&&Jqq`rcSi<$u5PDl3xLN5&z_{zMG&%Fc*_C11 zF)Q7J3+NSyCG`a4Q5llK6i$!~tSA`C!AQqra0YU48GHt15a3zsnl8C`+l}Wr#)-$) zj(_#kiC3S0<<;A_U$yVVY#$cD9we>#S-DvuxBkX0|7NRzH^|=x`OivDla_;Ymf#BR zXCXz=CqGXAHDuu+9QcTTx0?owPd~gUmA%2Lt5LqA*0Mw!Dh8-M1Y|wbh6fmz(xv!SW^#MCsTrzmXxeV z-7L$eIvJ(O9POHsnW;@m9S5sCTmUj{_qvxI%%1OpOM1fF17~pVEQ%f+P$vrklE4a0U=K77+XRhZ1_wlgD!7qN0$3a9 zCeWln$-)HnaikiSOqfVvOlqbjAsSNK-HL>*N=5>k5yS%k6m5&C5dfC0mW$?f#BD0R z6;YcZcB_4{S=GT{O2TcwYZE$UfD|df3Bfhaf%fd)+@84cvv3NPYSpIp&=8o2V9dfI zNCqQmST`yx!t6wxC2`^b$)xMOpQdVkW0l}tmUVmm!spDsoKy-GWJpiuiSq2*a=aZTUgv)Y!`9eey1*{lhMe!)Su~$ z27}3Xyluy#&ty88IG1;N`O5OS^|kf$E&g!g{Hc)t%uMgi z^1S(-#ea)m``VHDuAi~Fp*iJZ2Jzzadlz1xFRhkhMm6sJW|=29=kigt35ymh$Lw6j z+*O&2Zee2sv{&Ex<2!!-duB`0U%I{e($Vz2*U9%?;?7L#pZ&`-kAG;xC1zC}ubQsG zmUVg-ZU`3{0TM||O_i0VrifGG)JUv`AQ^Z1`S8gHMSRkFes1Bv{r6uQZ>~M?;KRH2 z9L&1TCQ*c^)5-2#ijjyHbqYu@nkqmSGX%5oe^ z%DTNyrd8z%O3A!0dc7H9^yYSp=c=q#O=B6Yiq&*H+87Mh2&Nj$0svvxWY^Iy zZyB^23=$Em)|SE+WL{w{8lm}i>KLYF8Dmw4GRB~ej1V;hty?LT%+w?+db8UT`Eoi+ z)fg6<%bbYFB7i*4N8{1?2M+%AU;Ne1ZS(Jb#}D0i-xF6{aTQ3bSSMAdmSr|rUwz>V zp7Vq6`GHS;^q=1I!|y(~zTWHhst}0S`)o2E+<4`4e)|J|{Lv5n+b{jbPpzyi_1vDf ze)kXk{Lj93IG+6Lzuh{nCYM}x{>EfjR^!?EIkh@ep(qN;T+m5f*BRvon@+2gEX#AS zv5+>F50YN5=oH2JU^7_iWW~bv9vqOH;s3|hd&lXPRb~FqT6^zv&YLP%-JC<`+zk!g z&@@3%5FI5bU;+da2+Eko(HRAGR8TPt=nox7M@NYwf~2OQ>D+YAH;1~F!<)}Jd+)V= zf1I}(Wp-+D8kAVR(k!>govFUf){r-u1 zbGxfCQLVRn`u9Khm%sDJzkcXtx19XuJ#lSMeP{idXXFE)JMq`we_8i=mn{9wM`q`K zk&kZs-v4s+bN{l~+uRs$%;XF<#xRwUjJ2ZCQ&g%Bk|ug#OA>`FnP?%(#yDps5=9s? zi8De{t>29?M$A~|##7UA(d0{M?8RAjwQ;lHI-#ZjL=g)W5F98`yFoZ6gNO5#N8{qL*jc0gz!u=b za*s45?CMnHQj}6glx2MSyq~Z%46F%48GQ(nsFDVWk)m+y4`n!DPKk|Lp)^a!#;o_{ zg~iSOU^7kW(60JbSM0p{#)-M9w0$8waL@5?9ed{3neK(ou(z4lBxBTCNm6rZ8Ty5X zQCKykCI(5_Wl3tqCS0qTM1yr`mGfyliz{C+esFf;>vwPd>&fG}p}MglmLQIZ!_fCA z5>66!PEA!eRZD7Rl)NkwlWZTGo~hN_dCxdgGl`ej9fZy>S#J+-J~(yY4GALkzKW@q zT>8Rsvs;%w5l`Rm(Zzb~8n>~*LSfbbAH|C0M>C0n(2s8+3+ zusq8M3IIcB0csKy*d(dSgB;*sr^wWqTZ9}`gRBRhU^XmXqyaua#t}Nubs|e7OjCp$ zh#FT#3K1VPjXI`wmo-N+nqxT81TbcV=xD>=wz~A?`3rY!bmk>?tVGvG=3%`vFgAcn z34IhE7(`#Fs8cZYLhhp{MC+ssc?r*|CXx~oWAixhnhS)W0bUHs%1b7=W$K!XYrAe+ zzWe_C>5>=~ut$rGEz}p112G{hpg@74Qq7jkBFMFK1CIXe{@3O3zklMd9}G`V+Q~#K zh#f#A6sl-NAw{ks*S?OxnBHqhU>ck?INJ=HL+u+>n8>K48O&Tdb9{60^9x@&FKZLn z!NfvwWOO41Af$>?l|al&TGcQ@W#k90B7RaAqat&ZcmweO_o zG*luoBB~UtI@#}(Rk!BVkwv+hU@Z{U7vK!_84!?fpzI;$ASI~AP@Ur;2CR@!`J7dS z7!(9CO4-+P016tk;?rmdM6A_(WC#Li7?kYJOpPuxGqAws#iwMAtWIEFBH+F;*5yfWRpcX6`I50Kubi2=WY@X59eU=B&NfDMBi5lPzs-o=>a-gPn8Z-2 zHtvuJ5E~)@fIxr0R4pogD53C_X^jC@lTc&KHbnAXY%5^YRYk@Gjw*^W#;6J)s#cA5 zAaE2(*cp(D1o1(=Qi$IUMpx6csV)@N%7MxXtybf*<>{tt|CKY8dP_mKu#BR9GKnQE^NP zqe4WE)j_PnGg(1Gq^NLAqjwLfj<`NhgJ>8Inv61yP(#e*AWooB%b-f8+A%W7iV}$^ z38~l6MSEE}!}e`FH%%+cvbcuO!1epx^PAd?Av!(Y$AcFzD3P|n1Ydv)fZ!vztiFM2 zp9E_l0Z{-CV1y1Hh0H2#yegs)s2>$RQxhtx1CT(AN_el3yea|$+3M|pQ75VjD(yuD z6&Kf-QF?ZC=V2W+xXM6R;wZsg&1sO1tXe6R4mTY)LnI^O3G!aAILsyO{rf1);)nPjlJJ}efu*Z1t1JMiV(Z}*Ij6d(G^hwpjz?q7cSdtd&B z?|JyEk3DiGC180)K>S=MMa>gP`_oIiQ~z(q%FqvklB zncRWp$2a}PEbTUFmghc!l+ha!M@bpWYMaxOZcs$hsIinf$VXC5Irz~1i$`BDf6bgWhURa@R8wfBvuub}76?o56w-t+16gVeBVc8wVWAJ~?fUFba#6KGrxryl5y znbdkOeqc33AVwx*NlZXvc_`a2Pv7~z*|&XHqZ{#oJHpo&<%h3!Z@9>w8OVS6@ZzzL zttTl^53#$Z<%;?xLu<~ql?E{viC$x&QV=8#HUR-eNC`m8l1N-_D)g3F)`?Rhz4=AA z+<4=SfAPnEROYI|^m}=unU%wGeR=aOZ+ZPQPd)q1d%w|WP7j8CW1O>)7`xrgLb}zK zuDVkHkH_nCae)yakBza_Hiw8|Kx|YwwW)KCEQzm*&DdDWqRJF}aIUs}$KILkyPZpG z^^DXu$C{1$cs}U-*&lrH-n+k9tJnAMy!hg)pI`JlkKKRQ>f(A@%d{4|?XF4KvbBk0 z!=a2tkvGOCk6vo$O}fR5>a;sci%Y}2pAUONF-9#5PbTF3LG`s&qoHJcd^>09=EhPS_EG7$ssybL zGR`G~!C=?iuD|@~$BrI7_)~9t=e>75cJ$&at+U0TXm1P}6OBeQnLlyn1uwepo$q<) zKmM=(^|SB#*>R|_2<9~aS$jg8>NrIw(fRAF(6 zA(&n_cbxSH<mfBJvF`zPP^wqJSYpgXM98b!=S z)vzHYA9QzZ-+sH}qu=_>nlJzAlYjYruX@$zKXdn^k3RJqzw>JnHzBDA$fTSk=~%rS z1mEen#>D-f{@agTb?xha?#F)bktce0e|_eqI~p_lzVyZUf4*Ywhu`@6<6nAj`se>J z{oC&{WA1%_a@|k;hp*OL6SYi)L~LR?gbG6Eln_FU6`?YKh~dF(owF*UfeabvEGbyk zS<|q#Sx>#{u$?CXE~U-2L0*I;VFo2c1WA}3$TAs6&ah>2K&^%vlY=G%R!}MZcCd9F z+es6baq|+JT}5seaSKREgT|;-5E+nFlad_*_vzqXzxdE_>10@4;T*{jNogt6Sq$Z+ z2&s?^d+@4*T!T=Ato2KqIt2}iP>70^5Go>egz+JkMXssKQe%xJaM;-BuB?^Qt>ns! zT9;lly>myBffp9qU-|Nrj~zdAY+-Ssx9M~1kxpQIUu}1dP?W>Igd#6fat%9CXei16 zAT?<%sW)A{!8JdO(Z?|wpOCrEv&o~MF6Z{}{ZFob_4K(l^)SZ8h!_JrkqotDG62P> z1dQ9JV-tfqaEvBJI%YBz@5^D`q`PKojix;}Uz}X%c@%snFR#0W3;pA#x~b)vF?aDr z)8&fq6hk-LxcF6LjZ4NRZ*Ig% zk$NDIGKe)43W3?p_9&?(LqMw?^bi|jZ;VOSpC*F z@^9rpjq0Snlt6?iQPc|xkHAO`OpvmN+^_>MkZxb)Msv}RZ+q3#os)mH@tKq1d`fi% zqWGZ7%tRDbJW8VsHC}T;1fkG8B?ppHqXCU^Js}QSSh$MN>$RMu)=F>l)7`J0jVoh3 zOQ_OqU{FNW%P6WbA^>o3AOK=O5iwSkC!=|TBBEl88A)8|U?pGPMl&h9Qc3^kfOMy?_W2o`BTfI<)mRS)JC zwRA)YR@G4>hK{Jk(5+Hdj1p+04+{iDfd&i$(n+*-L5AqB!Vffha7Bb2wKa|szt4G* z88FbYk5~|^hEP>9jT#LRRWM?lRF6LO#7?C|0m`f<84xQaQyDQ!vAn+A3k>YpH=b;7 z4c3P?5m{f>l_mewGlgIU&zrpdd2=;)fha`9B^R3%(p$&!nr!xov=VK|fP|odQnt0s zFZEX2Lxa|~UE`Q;%KEZ3Ow~WAwGe?2tgUtvqY_HXUo|X=-|q!rdjBjA?T#nT5c3EQfPi3u>cDNFGCJ#T8Nne{C7o2fQ6__GnFS$= zLNbVjY81dwlGx^$opHUi(1M71=*cL7Tm_;;MVYvI;SCv5wlJhdM3l5tUuj`gbgH@t z40H9TM1{#D>mNy#dNC@@jbLMZ^`*m_aRHG=b6MhKC$ z023m`t*(^HTwk3)E!43lmgN;!sf95LCU#UwvK8|zF+`$y7yVWA z38=wXBxB~r?bp3=Y-~FoSmeReN_VWIJw$UtE97q@rC4ClQRJ{GG(cjN2qli7s1c*c zbOek65u$AIdq)#@l?z2Og>*aoD)R2Ayh=fAM?MHBz^ak9z|vr%k-Y*V`#AF!Y-uY4 zJR;}Ps4cb{b*m=I%5PCwYPq@r5~>Q?3JNEqUe>C<<~wq*7`ci^;NMYO4nUxa=B>n* zVThOw2N5Qf2qJ5Zvt(6_vCgouR5NfF7N2_6%f9Q~zxJ|&2gfXPe;Cf4?ml$ancKhg z$QQqP&)DR?*~vYFm`fO4xH_^w2$UGC>{tQA62WE*8NJ2FQ;>p~8Dzj9W<#di?cI3& zk!`azC{{1{m?x7HwZw4Q-6#f~m%r#m<73nFr!J7%)kqx*oj1Sr z@Xd$5^69V7pSovI_Qq{%YG$JEi^m^4{wu%uUq1RLfAi8;-ugYSd)e#W`i7z`mX=o^ zy7!Ss?|AzWV06Epr zR==d>D*Q6Jfiw$+49yz2Y@twk2lVdnF(R|*GH~h>y-xW1xwfdkpD2v=St!U^CH&x@7CH}b&-C7%0 z?-s2L2r5F%RDlgiiCAM)5>N^@LIWgvR!wSkh6vwj2Cg3cx|Ih2P?o+o98^iC!WTlSM#`cr zLcwgeVlc7WUXslaLQWv9VonT#8dhgrUKXwT*q{9IA76dlgV41nSc1i&%F2N{7@#E+lIbJYBS@y<;KC?SH0s+@45f6 z2mbksf9*r_vfVFy-!HuDx))sctp|>sonK;;Hfl*$PvC-~q_^7dwtKCqMp=5LU=ll4 zn=H$+GuRXrn_6p`3BDLIOud%)GBT-Q+WG0_Ax>Xb&4>uIJKWNN>OY zi#J?y^RK@BSN_ZY_n!{euBloUjS(eDk?l$M0OpysQxmm%Zt~CG_NkqF$G-2)uleAg zeQjyu`I|3%%bV}{`+x49Io;ZEa5yvhM_)Yq z;`dxV_4YSD{mUP?{<>?@H{W{k_q2ZECyxI8-#vSzc2!?f!)!Px0~H>fNu!Sv0CLWO zSR>f6wG@L?nS5uh1|by-Of<4q&9%D)r!KW@p^>@nk|ZPYaDc0s)DVJNrqpnjFbgG& zI%^W)dlHI}jnnkSX6$m?yqc23WGBd^&7QcF`H7s@xAn zzuOs6`Wg!gNz)?e zv4#G#=SvdWki3n}WIdz2;G9v&0|@;v5hyhl+|87YbsL1-=N*$_d zSG#-d?ibBo{n*-xueBc-ps=WkmQj7i2?IgBA+l;J*-#Le;nW0p3)|Ph#k%KB+g^4C z=RUal&*yb@ipLD8m$FLzjgH(<00EImEjg>EP%rR;P#IhL(r*V64UViKhK59CRvR_c zmg4$`4lK0{*-AJiWmFhY1)xGfG%|5SAdn-cfP;%DbIqBEsVa12g;ruIAO!9E_PNkk z6$c}us!yV=8+*kxwy;9P;HcH)$pTeG+G^JE`)ViZ&tV^S|%X$=>a zk3F^4xng2+=cJjLL0l6BiH9Q;JzZQod+yL9o$}IF`nfyi&wk@s5XrthG=53Cwh>OA z4)gQ6z5y!0iLy5th#V4&rH$pq-Vk%M)2(E7vV2xi29SeGQFthUEuw%K#%ic)GmVmg zFt}2*fCw4-^qM1+m+p-~dpYFK&SQ1CXy-k}$(U+;UL9N%5n7Ru08*{MMG_GW3_}A# zbtPG{1X2X%G-_lRL!_!^%OD3OASz-|Z`gUw*NU|o8VO}ko1!_M%uaBW(t0ftxI|Ni zsc}7_ETzObXBeInB_XvnYFes~ySap2uEV}x3erp1s#w*?BnGBb3J8vBsxiQmTG3e5 zatfkEAsC1yL!to!Hi-&D#IRLV>KRCdiBv(FNVIjH+*aGOQLb=tN3VwY!1m7%4O16wfqt##ED8& z4S*nq>OvXGq~eu`$ly6r*T@fCfs`uC!03Ln#eSnv+IA#OSB=m-+SI71G8qRlhyfZa z9knt9SAWSUQc*wu*K$8HR=0D$Hy&P3_pZ#fM(@ zvX}h%U%zf{XYH{iZ4Y#+iCbSbcJs|U-u%`}@4x-(-};aL^yImFcOSS;q2A{zAj7Jo zRxqtj*324(Evt}%nW!>!Qst92hT*D>Du_j__xba0*gMwDK#?UEn_sxl z)&A=8dM#^=wZ@m@W-MbZt<|#hu?L^{A&J}f%ssVuY{$%w$=b})@bu94C+&3ICVA{T z9*-oYmWh&=0${eT)FK8=DX`|b4%JZ5n3n~aluYfO&z;Omd)){3*f+acXMFJCweBBu zYM61~SKIZHv2FjeI5s~ZrHOIgdr=m0^_ytU)J{Co=`F{(mdOV_6%TlgYMfEhvIsFL zpZ`4f!#5?HdHnE$`CaGvjn7ZM`%=E|LiwkEeBtCjZV;(9qxLpru&8lO{j%W!q%4Xa z$dhwqE!1e$pJ}YdP_?Uw_iQMsHS^xGguZ8&B<{7}_k-77ebt}*@rRm|v-=M3TV8K7 zSw9R*^GiSQgRfp)Tm97MK0e-@4S94nu?E)KBJbzEgX*&Xe|~H^n{>r3_4lt!&jY)|T0$bBe=d4DY*ZuUCs!4ILLv~_ye+HwEi z6Z#0IfHHVr1|~y{;jmAZG{mwjhxsrB*@{ucvg~fn!+?fru>~lR4Kb+qzxSc{-}>@f z-|-XgyyN!!FS_W8iRsDlnJMeCPIt34)>u4y;pm|~@B8&%_{x{Q{GMNUx6je4%?|P& zY2uvO9IhPR^Mdz(;6ulsc=Qur{+~Y3(S0v?_s_j|Zg%#rJ07VwCz)zlCNtZ|*O%MN z%WLgkuRrLuCdSzDxnuJ_#^(4KB(^u(Wf2;UIsyIOP*lhm0KU|GP$sEW3H?C~s!~Lg z(pc8ew#E=P7S?=O_WIq%_}J!!<&S;l&))y855Ml#H-GBupV+_i(thY@G$O)qlXeo3 zSABG*JM{Tu)N_YQu~kMF(V zrZW%D^X~cjm6x18JN)&}KJ&l6_eE>h9De$@f9vv#57_JX{qXNybl+FcwpRv?sYa=g zk}B?;MA0Y^GQ_H!Sj&b9Br!6$mN_AkSaGY>B_@eVF@^$RSSB#_jJc3j;$W0jog-t6 z1(702DKnHZ)tHPxhN8XF*0KGFnS4o7zn08ivSUP9W$c4SXbup;0Zo_ydK`nhEZu5B0JeCf0w(t0Qg zTb}I=HX)@(A94T$R!BeQDbm?=vY91i8T?QiJZ5t;2Eu8BZOf%~(kPzE)i}vqeQ7z`{LI^8yM_F?IkbSfB2U1Juj&>W)je8A*l}>m zrlD}Eq9KpmV4AE%6qQ1T;*(16bDh;e6CK4k&&A@t&gM7U%Xhagoa_xYsr0Q#wbEES zmK3oVP+5k;s&zFs&g8lDia|FPDd|SBxm2v@Qe-9_7ClR3l>qANARt7EmN}1oB@qpU z4kLsWrRGAyP!$x~&(W)+`GV$^i^G-Ax4(W~*XvvpEpinCmm&t7up5k#XQ@+47%KtLKbD44;e zO2SFqIj`z{9-vW_sj9AtM2H$H@LfRRH8-%8`pV#_ab&?&Ffr38*ccH3FgU=gMnDBI z0x2>E^+P+Cu7eGbN+7Ky(osRHs)31!H8aLUWhlHB&pipN(CpT9N?UeLjCyxQVOOF5 zb7N|^X56aWqSWCK<>p9~HB2Va5FtiGsWEU;XKTJql86cxV_j5>JRhN_Dp%3SSQ#t8 zG^iR=Jxt1tmTI-$8~N}wswz{KQ0Sd|{QSyy@7*z*)-K-Nz5kq+Ju*Tyi=oHi-D5Ah zVri^CzaDS@>?7q}k5eNF{dG)F%H)*YcaX*>Ksn4e z2O9&-HE8ni_RZ!v`95k16lyHsV3LucnutsaVv;JLJW45(F(gEyJepUP4Xa9wf+|Ky z3YA>@MLA44O|{-knsrQQV5kwqsIdwiDXI-316oB>M?lKTN{?8DGa1!nq99XU3YH8J zmmy~|LDf=XnX3`E@>^Cay&+Sl35FR+TPOwZ>}cu_05%#B_vy(W+8)YjCY%*QAw3YYf2>Stbi5 zV{D};8%x$Wh$C{&CPXGlTALfovyGV#fAmc=J8OUQVCRIS#gbe*9S)4w8kya;YvMI; ze!+D&9eVd$|KW3YJg{xwRR)RratoGIjjGl6Z>%N5HU<$E4V47VD$LBrSg0i;Ff*so zlY*Z2ydBM!9j?piCx&T~l5=I*?(`N~s9*nrtGao&v(c+%^~Ad9hZ>~jYNZy>u08(S z-}o>8`sBa9gWe?6aX)MdK9y;Cm_G9Oded}9~ef01CdTwgR zrB`2k^%YlMdHuDoeElm|SJwaQFa36Rvok$4e(><#3+I=eb*W2cW~R@bIJ2~{aNx+^ zCm(onZhCIV-1en2r@H;M9dkRznyta+LZzs)v5`XQgBo(|R48(+TtEc|rT8hCo201= zSn1obsbuV1UpZgCgRcLL-RWCxeb;39rS+mca0|7if9Wke6~~hCZdq>M<91$eJ4-$l zYB)OkP#~dNLU|}-7)BIYJ>b+N)(pK4Hsbe--g$8E(Qdons%PV4jpYl=6JxEHz2as6@fY4#`eOI?xqg3WTvBhQiFN1C zo_Y=r@!U>&Yk#q|nj3iywr0=o!1ZrAhnXNE5mgN;h>XR^d_^j13{^O6Rbr+XBN12D zT@k6;xiy9&hS4BfuqqKuJ{m6xKvgAODRyi~r3huI(G#c`u5YfKu`aW&meiWesmn6k zoNm-7($-w`{a$;c7<5z$f|4O@d4TmfwqIp|*cxA*b4lWe07wiHeFRCA(pqDTRrO#Z z89^pSGZ{sIEE{XM*B}1IFaOFLU;l$Y{kEU}+HLpj-+Q?9zTF!njaIGZ>Wys|&Yj=C zd&hhKvufDG=sF6+$hu%=iMmLAcm+pJfAO7LT&R;nBp^yA-QRX{mulx_M zej`!y^Z$0|k)sDLzIpPAA09>+di87E<5&8POl_0Nk}0P;vprF zg9(%nH$fffG5BX>^$}fuG!E7fnKdyoi5$FHN=ei$bub9IdNt%D%3NH^X~L_Wk}Ri* zCIlvKwvs_#2AvR;TVt-7m}-$pY^-V#2K_;oCEq!jU4HrAiw}&|YrNRsyz|jV9zA{P z_|ocTf53nN*SMZimYFO9Wl#%K=f>XJ&T*=p=$uT5t{yvlqBz$L!+JKM8pQ`TY^zro z#8nKMNVtgP4}O4QfnpGbOfEHKguE#`+DmHYz@DkQ&ph6f z4j942+~+kih7b^kS_BOY2N)#@2mz(1B1f=9K`LKsL5ic<{=M~?UQdp7&z_M}>)K_q z71!6Y6AfOWu&f$25ECd0yZ{ynDQChr;EH$deRW3euNFReGA_>Y^uGG`hE31(7dB-W z5EWvGs%(*E<6~6SAi$OZAE z)c;5e8?PP5Y?!q0IU?na@Beeh7Iy0as9XM9LUn3XU<8G!9+HN^Qq`na=7`Z{K_gVk zbADhN4M?N^_1yE7U{$2LeG*wnBtw8#Q7~&XstR^IdlB!tB+Nf0^N#}o&XP;Ogcy-p z*BV1%V%b9sFlMB>aD|+O0uT>tp^8|7a~Zbb8sHQljRA$HEYTurVhm&O*!+dn;;L~s zd+E02%xJr$L@^x3ZeDxUEjzE451jb=%8_yU} zq5Y1OIZ27l&hqiq&32fau(hdXI}*yEsUiw&RlZtPhC~p-7!?{FzS&l=WhINek6n9b zuiD#eVA<>N#ELGgQiy}oiz_RG-HrOh&S}if;LHXE1+%h+4=@R;x^^V0o<@6wxFudO zRg_!?TR2|VHp)49{)Rh^9!Vo@}JTHqBnX|RJ+A`)|y^=(!u1;a%sLETZ*{CpN zWUH%vRBr>W^ji_tk)N}geAvNQNwtPrdq7Sh&uq_(*8by_nRLmlfRYeJ9WszWDf#5}ni9iB0 z(_Mvj6@Fxkl}KcPs9T^RA|kaaYMG*vLxv(OmW!oyD4~cVMi6XNg;gSG6dEyah1e)j z_2zMwuvBm3zl`lUtxBciy9*@d~B?_5} zm&42sAY)lWh>!{v&4vj^ltIR^6;XC+r`u~L%_D~<*xb zn3=Scf`kp3Qp?I*)WSp_Vrh6lrhWIxm3Opn`LBm2e>~G0rm!CSpX;6ZWUo6kY3d3M zbGuUBgW|Zhh+|vNJybM6RC(f7iM$(`tg)t>Z#*}D{@=)@(G*Kt7GaE@#{b9EN<>@Ucj9XHQw2ncNA~#2Qb44D zQH>!A1X2A~xaR+%?#jq17Dsk`W+K)ROI)ja{0Q0`i|4*4AMD6uSx3O8Je7&5v=MSgA} z$V|q$UcdLYANi4=|G9Vn(tCgH^Pj){$dSuLVt+6koLk;p@9o>Sb8TrQRlNOY-g@`l z-~6Rt|D}8&&1`y5e(9UT zjs8Vf9F0+8kg|~W`bu*$JGgsqe=uBJUlf%?hYz|Wou8kd-`Etk<5SZjy0)}l%j~x8 zvus>@W3xBxrD^J8IT-lNg=#yS`@!t^WPLjEWx2Mz@xYT$F1Nd5)8oV5pw$|4l-&8? zZIkKbFTU*;-uI#RZMNI>q&_J7Dw=X80W4%-VkwqP%2`T@cma_zLm*KZVDd5;c&jdL zT4T$+vIQqtYm;Tzjp8m^EOr3mta><_k z-#z_PKf3>a{NwuM+>Vl*RM`n*s&etfF#uw%_9OM0H42TYOl;UXgBVRf&DffuSi~$f zEjDSXwbZbJnOy>FU_oq1at$4CQa`g(XK!#5*V*h!S!gdh2Fz}YdYA{&ohJ~Kb1rZ1&K8i1b_e#b_uRcl$8htE#WoGSMt65i* zri>B`M3a{`+xI^4@S_)=eX2XZHY~+E0y$1H zaw$wknS&Jx0HT(;@SghIbXtFU^LQ5Z2M^x7s_RdkKBJ}?q0VrV(=x`PkA{(%S}B^A zW3N1N=+=v-=D!si+u>%ihfWnwciZha+*NNp@3LJdSL*-%=!rrCD_L?1ZO8tw@AuWV z&1UuJqcfByw$5n-E}eANX_*INh0$(VZb-kAZ>r`8b~i4%a?hpTJwA1HGCt<8h_!$7 z%a0As32WCiZJ98sxE@?L<1cL#Pe^PlH-LnwfO?G(Gftc;40NcreGg@RWYS3DlrRLAjj(p<_Wf5}x9yu3 z?i*l`!gfM0FnLPUy?qlk#4;!({xqR^d~y`^?_o$SBGyC03udW1UH zNJF8~!a}4nDh|;X4GfN|rIc_`MNjf6Nq%tR#@Eii;7n)fzpsDp$#}L&V@<9%$vK6C zQN$7$pejPds(vWBBU=sq7S^jLPzG1^a|V{0=GV1mkIc>8d-Ac{<{$TLoI>Cg z5H+OLDNLe9VzMxmLc?Iupa6qQ&HF(UW1@IPB%)G6Le`lSup+TUNh6GBrO>ce*iocRa7%42P6z~C|0A)y; zdWv(aOB+QE&BGVZKC^EktS+)u@`KPE-+k-R=3Le#oPPR3SX$>gC<`b8G+=XC%b_{} zGwc*i?4Y@A*t6F(>N<>g=&7~key3aRpR%=?7HVTs^dv;Y0E(dJ;4us~RR9lUC`lo# z#FQk6B;Jf&d(rmGW@`w=itRtXfU?hxT9{vIudK`d`ozu&dvIqseT+3CaZD-_p^6v@ zKvYy`2R2NC7f8QhO?9y$_!Fgn^B`q4HaYI9Mx-7SFs$EF>C9#&Vih8 zrv9Lq>%aHt{ts+R_POnEXwLmYS=u$7^WG@q zN2kIn&I^z#i~*bHeEQ6!Oe8{xu%f}2W0Mmv+IDDvv41)F) zgFZM#ogf6`5bHo4uBBlUxj`&I5$s4j83v+64`LXH=%H1XE`gg?IFxHpz>dK+L4`=4 zs6_0kmXJtX39PKF6@REIJFU*S5L6Exj85av!BH9H0EU!c2Z~hrf!P3NWMCvBvSgfU z)GddM$|%b~%qk#500UKpqv+`GsseCK%qo=~*jhFkt0qaq#t|8)F;#uN0%Qy&)}%2i zb8U6~!lefe{>V>Wr=qi&apxB28)N6htRKs7`O&>n;^Y5v-|15)A9>{L|NPtE|NFmv z+lyZNkrR(BPEBo-=)qj2`BaGvGrLeN1S+?rHI>Y43`0%TcMP^sG__f;zjXD{o!fWT z04$&G_coACnVK~l-OYA;`L*Bk^20~>edEsi)hC%tnJAQA1r_>RA%<8~HuLqbEq?K# zjr%TcUVPKRo34BQRT~@KXHK0Nlmq0YW0xSSn_^l7*%D zhrjj6p1r#o%|_W(7;ZMF$R&?G^5m_re95+5vl~mj>9JX-4UfTQZ*8`@tDe@%Vp!)^ zKxxS+BSOK zS5K%?7E0f;wEKz-39xADHO$W!t54^%wak)e7y<*so)Dub+XPgmNzz^Q>!*6Jy{45U zc;IyZzrX*?iLaI|mnBqa%*(+lc#WtH>B1K9J!sBGNQa_@_#y@Zgk9C+QrV9L8mDIV z4!WzcTqQCyN&@D9hQY zW;rZs%_eM2l5}-#@jKgVzVkz$v-FN`wiO?Eno^M?a=I8n&=jsnhZ0u zvFyE9QI}>!oH&=HX$+7kY?vLQuMmGqL=vNQE=G`O>5CY>&kNO9tvjpZh|1QYT1gQ{ zBeZxZh)H5O>~>X|O_CGCWUetjwQV=m=Qy3n`|Cw-L#6i}vvL(vAFTTdwiu4p8IB26lEtv?_j|8;#drPZ|MVMw@cV!CkN^0uhYnr>rpjs*q!dk_ zedgJO@V;O8*=HYl=$GIBpNE4`Pbd0CpOvg}?P6)?^pPL_fuFzkf&2dEpZ?p%=6q@! zt+A=GiK){UPIL#WV47cE*|st}KGj-YS?_NQ4qvgS*UwL#IA5O_zxnEm4fAdP{`J+B zmDwFr!rIyFN6qW4M#9915<)0LYF(PTaxj3AQDQ)R0zSBZkJ+n!DGr83xmuP3U-a`~ z9O`&#$^Uj3sV`TSp{GrL&Xu*qCT%BeWV#G(YPF(pZrAWpVqZ6+u) zsV~*5x-@Oh1ThhVq?JkN^%tLRw08AZPxX#HogTbldFHaW{r=~^@Rlo%{MgdM?YHf| z=ttG)Ex)tt-p?Oj$wOLCN~?|;&WJ`;HMY`h6r{!(YbhZT5mC*YNe!VS4rryE61Zj( z%ZX5CU_psR!eoHZ*Dw^OxNRp*z8GUKOzPJdw~e??Vj-d^LDk*ez|=uPdO^cey7{glVeKl5PK5xQq?dgR1~oohCo_RT?hi=q+z;)d{`Di z)pm<)(oVOmZMoj2?=0(ldvkeVak@blADuY5r#?4j*LvNDPe1tJ{L@cuEUxu?K}BGU z$*e`fj#Yi|4NfOalLYI2t&4%e?cnW=n4IgJ=U9IK-sf4@|Hi3@va|+H`+1KIHC$5F zEu=O})J~bkbvqAUluh3Ih5pWoWcOir=VP5a&adV+4>k-pHp|CLMKmxXRI>?j4BkhL z5z;RU>pOKy#_MSJKbF|RDB6>|q-D~&~N88vW2{KT!6)Nz+opJ59mGfU;T|PbR zuV@&WfJU%s$ViRpm!;Lxf*URg9%Tq2)zW$&%0N*$dd-JAh!TZjpF1n7!jMM(L#E)J&^TqSGez(9%q(J9cdJehFsJj zhz?FrdgKW?!wd=}LNEliqOY;f`?0x~-QRuaPgXv2R@R$tLX{=@^+5;FQc8o7H8E(g zTiFT=H)=&3-9RltJW3^jAwwKA*ce_pyXU(vK6K}UcmL5dcRd?QLv_)z@}NaT14}S~ zfXI>|Xc$c|LLdvX^;3rs14y}&p$LNDrL0t6Q|YusP$4n^i7FErA`w!^xEp)T)h|D= zZTCl?{sfpbR*x|i1l|H8F?dvjq9YooY*AWAXa*YD6f1+Az{inLF?v#t^wsA^)Nemp zo&zsYB_MANwxdtABj9KC6dfgJXsgH7j;4;HttUP&{Z*N}lBTZV`VLzxh6~SXe;p`f zV^Ov8`3T57XAIVna$*35M70bF1Pg}75|$7MC6E~u43`q1iN)fDQ;#jIUN&`Tf2(on z&i1#S)ImXc7gt>}dtlNfSnQ+o@EHsWt~>Pt5>SMC;(%DHk5m-eZ);}(n>*snE*hI9 zTNlq1bU$$EHM>qJkC^jQ`QLX&*5UQ58 zKy_tS2Z!o9P;5Q5D)V@C{X|vK$beS?$dctzxRou84MiNeAL^$AypEw*f_3cD&3 z6iQX1nxK{vQlnxGoT0>M;!Hx~GOjz#SW`<$f|^BQ)LA46(uSrrairx`j2BHbu7At! z>7O0f!>pqAh}-`c+owJ{_T*nJKfB&eE$vDg^=P}A52+~N2U-wW3)j=0MO0{1F@UHL z!NEi=1-5Qx^P*pA4hF`nFjuImN}Xm=iV!AdHd5uvGz>Lw>R3N?^N56%JRw9W~s5K%*}ODBvi`h%6*%EL2r18d)`y zRmWdfmnrbvgosDU4aPA#H z{LPXFQ8j!j&BzcZn{S%gzxVKk#li8j@%3-~jeq#`2R{Dy zKl##Ed~kDhIM!;4mLwGpjiD8cxyqPTjZgv*F^gJ)F>Fbk2*a=;m*?H*UvZ?_N}y<@ zS(~=h7t!qCvS(VP{w)d@Nkj94-wupV`=%jz7Lq{NekbeB!g+ z#^f#|iL_TDFTgL8-E?jk@}Y*lvAM<^MXqL4q(mwbN+A$iM3Sr>D31Ldp9qP0K;Ke0Je|zy9;jJoD_QKl_R8GkXWafg!ha ze!1Cd2>jCW`TysYZC~-;(e(8EE{9V)SLAX z?0Ng*m4hDF(JtA>yry7KxYvuB=ou(NVXVtdQjtRrA@ zW&9HH`A}ns604@x;5|qs`WQp?^+#NK8eQm0u*R0YJbKY(zx#pT|J=WP?!$lnmxm5q zZk;QKo(zLyy;&RfhrZYQnfJVNxW4+UANY-Kx8KaB2E`BxW0G#UFxlLB>rFrM`0)q7 z{Pn*Z=0lg(tVwEFb7Ot2yB2-vo8x0oJ#-9x`=VD}(b9oQrq(X>PoFq<>6Hf$9NPQD zLr;C}wyzJ1V&8%NxgV@=Zk7XYYi@crYp=AI7gww$fz+F6QG`w>&+0a6>~#nIVSgf> zx_I|tx&Xhfm%i-c-`(>YkKTLo(Wjnz?Bo-t){f0@oGVPP)bN!Dzi{)>mp}jL^^c!= zij)l+mNI}GWh7z%@o;cHkD&~xo*W9p(5O{ro+O9L^zND zT2-$S1H_S)5+XotN=C&gTc%ouOyQJFLKb8|wS=ft?hDG8)-gNB6PHo_8r!&<-8S$z z!9pTJp_&5(%0LDjfz!yJmG(nna8kP`wdirD?*@TlYHUUWk&T{g3?(>t59!3f82VUv zRi@}geT*Rrq5{4Cu#qOr((e_VP&S^)kn4?Pyk*NxzqryZhr{vR&8si3zv7h#>n2%Q z9zJsF+0Q=o_~Ywm=lg4e5D7KQY123m`KY4sQYM;aR3o*ek12S9not(-Bxi%z?uGU5 zow<5jEB)u=_bin~BdO&wBm)I)4hM#;MWUrmsdoL&JujNtcJ^$ygr92EKXcE8yEj(* zWJH1i`XP3f+6jrJ%)yYrs#U0g&DfT)9D*Cp4F`pmDuFj+*jVW|0FFR$zqy=k)u-oZ za;CQL)@{3AoK0R;vrIT9o1g3UABf?&sTFQ4u(L!=HX$h?g=9kV)zJ5)Zg68R<4MG` zsy$VPnI=jBsCoqhM!CUipdFzNC4rr>+$2Qk5aft=GAv*e3SEwB1Wl%Kq63x>SWG}N zg4GdHEkYlRYhTz{{&HvObbGKa!vT3T1Ck`msw$+RFN;|Awam*w#;%1ri#D@t1O0Z{ zE!ji0klbtG;RDJd^a9D_-6tP?=-Mmh4&AZzpbu=-4P!UL2Y4bIlma}%uu=hE+080^ zpdqd!8>ev}``7N<|H{jr_v9T{5rEXe4uk(6_xzJ{$q=OqMZ{R`Jx3>$ty~PT zmmr8$m`=A$dh+d^tW=(5f$*pyHg54uzhnRTZ3Xo^6Eq_x(|5RvM!&F?E<3X8XjD{9 zgMa{*D_w+*p_uE1yL90`t=Hia&!pv$FmeeZs!||Zk#V)JzO({;yKo)7s`^H9;us*eys zEHU~vDhR3}Ut-w7VyP=DTAQSWZn>v{7RbHK>9aW^`pB zv9JzE!OTj;E=q2$J+$w-J==|*%xUAn3wrzl)hEaadfoiY#-PC1Bu!nmb7OXfyDP$} zl2Z_ZCn$m_8Bju|vIJN8P*u^W3T0xeq^g0*rY;qM7ga=Hgilg1jigSZDjlt=6ocko z3qc47R-Hp#br=*5nSls~qMnTv^#H0C5ko{oG9tQGtD4cTtCD4hif>zen+BxJBUd~_ zym~=Q$udY3j;y7Gl?^);BwPb1!k4imP(sF0qDqDwt4%0Xbw-km>lrnTBu;B}Ze*Nk ztmd2AI2tUmS;&EA?aG%-?|SuQ<9lklgR}$z!lDOg{8t*+zHIltzny&S^UG&?!pj@Mcor(z=0YIpi4Q1KN<>WwZ{ZYbDNV^nANsLFAm#)FBO)Z#!I6|zlmTLfR22*` zY(&uuc*&8QFW$HJOHbVX$nw*g3UkGlrK(P=D#TSGC}1tQ6k=c!H4c{9Qq-WWN&Dit z!A15?AMaV<^3HbuiFRows7^ZcSnpu9jbRtDKqyg^kQ`+Xz7K0)93+PUsxjCZh)Afq zR1H;laD%Peh=oRy9PFVAzoc=6!aB)twA()Y zm4}vo=ta}7d+TfOz4xif*?sdXXMXsNzx$7${p}C@(c6CdZT~$-mKaxg^O;FvRN8te zKwzR6t4`XeY77$@9RY+5iBTVJxM63#?m$3klPnR|;N`;diHo-HJ9>EEpMUUA@3`aZ zb9=YtWf%^6qG8Kmua#P#RJaMDnoEL|ZQt7{Itzmf52g=ZG;!%AQx{K8jW>L~U3Ql` zt~+#v@5Lh2xoO0c(G0amo_r*0B}XqiaM$943S~nxvooiTAA9PtC$78k+OPflH`JM( zdv+~6b!sRZ9ltV_&SjM3(oZRkh(W}XOHxA;%d$|2vlfgHR7DIiYh|FYsjwGckZ;xjeLEr5+sv^7Z=Wnl;8PG{f>#1i43tJHX_Q#s4~GMX_}^~1aXP;-UsikFi@blOQR72>g(@x{}N8!M|-z`&PYR6<^; z3By6I3Wj)JC{UKA<(^5BD)?Y*WmBb~a>W7^l|KT6PApFNa`t^-Y zXDpiie0we?1GY-AQ0)n!-S^r9Po@U<^}?N8s@&NtW2 zZ=Akw;jyQl{`xoXd0_F8e}D4duiO3nUE|x=hZ|IK!`2x{*lAQ^uu+p3VMGl)O086z zI#r2aOC->tAFi2<(^?jX{SbyWb!BhaC1qUa{NB4ZuiAdu_g;D5Z3o`|d;j!zA9zQR z4sh(WrblMql>N}Br@wG#dwO=VD^yAJDv^oEA$1HQHcFzFIL$ao2)Ve(wG<6QIz*zB zD2yTuB6UMn)7gD?{1RKgo{~%0ZUZ+-6F^jgq5v3_f*4oM761fqK4YFwW{ zYt~NhX-&;;<6@ZRo7w$mHovvL(nYk!5;RIoZGsRDC}m@r%TQX-c+y})MKP>%Hks6> zl6vU*L0R-L82Ulo>+@c)`||hBCYK^g^hpn?fd)o6q`2J%9K32#Bf4H8iNF; z2yx>kn}Mv6o>58-5{(|d491YDF*!mCFw`pmsxxXt0VrV@Y)QK$^FRqEXb!AbC3LEx zpuI$U4DGcvPN)M3iB+!Rk&nsxziljhX{~)S3|6D`ZGn0)Rx<}<5Ydj_n8+kU?X-PS z5a3K6%bp)h*v6q9GoAHzuNV+TBJt`A$s?6Q(Z|wLERp})-FLt8$PIJaTGZ82^O6R+ z6qYRm9?`%$vQkNr3XhUu2vnnbgVIt5J?%ZyxxmkS>vaD@2J2uHV#q*65CyR^)}<^E zWhRC|h*VSYZ_aLh`_!xMX+QMg&Oe`{&bXaW(HOm{W+--S2ofcFqsnYlRY(9*jUX}1 zsv4xa4aN%S0WM=)e_@MnnwmMjR{Y(w-&|FH3gX;&j8bg?6-p2WD@0JWM37{tTJLU@Llhwe@}Uk@E9)b%l!ByYW)Dm3>(cQkJ=hwU$r)Hvah^x> zd;?-9b6#$}!0+Eqgc!N-)USo>whfkka8qCb5JNIup(agg908?{QR~@oVTLQ}` zH_D|=CaX#U!It?JRsI$P5waGR0fu3S=S0I(C!Ty}Y31m+BVj*4S*ej>SLT`TvDLc?DLN9I$Tc`YiEk(JCCC%bz(}{Q@5QzySTX=X7||X zgEMD#@6?AEv|#{-0PHk)zz~~Cv8mF2DpJj?kT@zo6%adP92+O%X=Kz9BB?suRai#V z>ky5jMoI`V3hj^#ENWE;(Ij?WYOhHsJQE&UlLb&v^&nv-*&2G8sABnwQq>5nP*RhS zWnv$_AzNJ{1_laC%xZ!bB}xZZWj?twQIFOXno!MA!&2g7p~zX)z!*&k#=;6fk{C); z)Do>b&79U!8cQ^_;u4$GC__{uerL4TT{L(22dBngoAPc}M|2Fd6IusWKuhYcmgE(7 z=M@uEKTu!#%ig!Xw(ufkquNoYgczU6o2LfRG_VH6Rj^AzPG#LJMP3po|&~ z8)gSJ^J_FpkQe}Yy{D-~ey7R#I&TD`&`z^Yn^0c9{X zz(Ab@1w}rxUA9l;tV1z!SAkERMStDw*(VbT0+28!n`k(cLv-8l0mB@=1MOl^0tyCV z7iA9`N1GrORj)CEnb;r-sUtQLfpVxA5{qg;TtSGHOOME?V6>mAc6cTsW>my)LnGIp zib_?j2pw5k0Cp-4KGA3Z2U~&zkwavyYOlCrtpUs$y=t|l3DCGD%z(&&93rW)fFZIl z20~C#xQZi2w(=lVw>1Vxg0QhPQfNt)ELp>jMwPh+>Y}8Z-P8Z+7v3_tEh~m4TRYqw z)QtQ2w_Gv&^b@x~F@JoJJ+*f6kG$@RfBdH#AN=~06T2?CaPIt@-trfJ^NIJp;a#u$ z=MVo2r8}%4i2@;_krSRxC8;a1Rfq~3V^n!-q9uTf9ChNOmrhYa<;nQWqk~~??S#$y z`TXXI8xQQXS#x1=Lqk>!#G~lt?IIKy4XXmcAYpZ?M!W~2WkbfQr2?`zSlGzdo>+fq zI+@wg+%eOfY&7fj`gmTXxgQRF-;$47rZ#=@;U_!mYnNYj$z5N5peS-;g@RNv8ac#u z5Ze_4VpGwG!J<}@HwHCRJGCLjm)E1=(rFpnshaJVwP+Xeuc>KL4!v-^un>e{9{Y+x zhy%Ewh@li?GNxS0jfNY4=Hb;x9=j04*UUs>qwk&ZVL67gge5Y4NG!_|Cc+2tC396C z9v~!9LCVHJRQwQ%OP_!1#AN-!+y6JT4>HEkn}6sh-u@GB`K!P9=tB=bamkTO3m<$4 ztyZlp!(grRzTbZLXFm1WZ`}LMJv$Ef`+du{D9U=H?tQVbx%{2G-fz#Vl@Wj~8CTh7 zs{DRdYo=++Og6D13P*`cd>IusNos@caAInz(P+e)OwZ1;N%tSzopJ4ko3EVPvHh_} zPk!x-x8+5?y09sQG2|xaW|l52wbzDI+sCcd<@rIsGq9Pp?0k`Dwak}gKIpk5AR(MA$G@#oHijlM3Kule9{d03ssZm(dTZl4rw~*+7LUET4YZn8X+B7CvolFVl%o zYyhLtv@!o@=CHpa;;XkSzV1>IK5irz1DQoSS&AY_&oGC@~FO6O9$PYLb-c( z-*jWU$@!7fkDp#TpTd3S@!NL)`|QEFgV!Ir>e`F0z50bmFaDu}ubjN;EvH`l^rz1M z{l`Ch`-wYzOUJXR0x=~kQ4>lKReVXRmYk?~Uy!Nv1BegRFJkm$t#uSaJKu;dYgW&x z5F$x5NiVf&SUR@)$-6h+dDEpo_tT$z-`ijGkf%PGSMCn={&E~tw{O4^sQH=>zn<+* zLKA98q6V+p2LqJBq(DykgobCO_k?Vm(2Ygy3~4Crg-k-ZkLolgve5P$%3X=YK&<1m zVPinijY&#kv|og>)GT%0t3;47c`=kSz^JVo4O04G1nq^kN_o-t>6@N6e(A+&YPh#5 zr_U~Z;m&h+&d;A(Yv-X*^3G)STCFOl2gJviAW6xQGEn9k9MVMVP$m#5hE%TmFs}8w zy3NoYM|$<-u5)4K{?2)rS|K4dhEXqq5M15V>M@((*8b*nXa^Vb=46Y{^MzjTiQ%S@ z&B&D!nW|NgI@p9Q0VJkIsbymXOu-maH%ZgfG-w%$8vJaM9eMfAJ+IETeP7+}VJxD1 zn_sx6pFg8X$JR7UiBOU=unp3HauCVDW>gj)E!b%$1rL#!M8SR|x}DA(Avq}wQc;wE zQ(_<^RV5Ef2?QA^HHaegyjB_4m=%~r`uO5XfKMnBEeb7|m_Y%)ga^pN7BVm}8D&N$QgK>?#%d~wm7>c~FlqG(*n&JEB98jX5G+y}MNS2fSaqOoVP$m-o4KXU z21dOK5?4T2{Wi@+za3xQ`WVftTXwwv>yc|mO@muQarO6ZeUV6`j-63X7bb;ah>T1o zm9bfZvOuOGHZis~!u)fVjDg92hf%mhN6^}_sx z#XXbbgUU4Jwv@Hlwx~h z`=vA6Yv=*<9}E?x~6Guu!5TOKmRvQc7)~lB*uZ9#MD+rnArq7V zV#!4nf%0e+u|`wYB&C!n5%mD2s9CtJwTjKqteZNbwN$H{X2Y~N+BzjQV-t~jl^P;65E)WO zl0d*9!!}koFq0q%xJud@jIc%{s!>&Gu%#ke8g09RR?8qLh@qAY0YNna22!i>j)~gN zPQKcU3zS$zRH>ri23p;p0jNrZR%YNTc2S*lS;;~`#sQ>J!IdzTfjzMqfx9acBXi|$ zCo*IVv4t=j7A2`#bJP%bmon)90RR9=L_t&;W=l$JYu&+Mwl(pN_ud>s)F9-HfxYn5 z#>s{5YhG~p`Pc3K>;Li1Pkr^t|N6!&e)oev^8L5|cAjf(_vQ0Xp8lC%`1o&r=#961 z?eUeT+tcY-L{N=H1gX&NhB&HNafHCB0tn@b<~sy$vOtyt}uu3{TD^ zwp(lt^5ORVa}#@--~EF>u$JF-GpAqrs#osWw{3Z$SCfp0W~XN# zzUPq>PoI3@EjK;&_{mnYIXAa$ex=_Hn*-`>Z|quJKkMPGGLeZ0y>gR@70Toyh%3*w zP$bF8a>WBzQ-dn7q3flN!!(w-U}ab>eSc!CzUPKCI*IF=9indTS56O8Con}>v`h4b za!^nN(a0(QNr*87AVCr9jm#zz{e00|Ch8HbupKCJmB<>5ql&2m1cHD-BoYEM6B`L$ z)gQd-g{`sX!*~2sKHPN9h2XEd=H@^A(C^*#%{%_#A3k+x@6lQ#qv&~PEW5St`U`Kl z`M}`=ule5B%#3Z%8uj7I24J#!T5mQlTsZyzOtBJG%M^w}Ltw+IO3GQIQLEQO84Mf4 z9LivvOH)hanYp{sskg?~S2uc_`PAI>?5>&iTD~yfHoo`j*KZ%>v)hM27>%ktNL_CH^7@ijm7uAj~aa^%n@;fGkBKvldXpf;$*|im^8SI{2XDFV+QV12rdt;}E9aKx&lDG) zK6d(!WA`_{JbCyZ_g#7Ll3QMU;|*6{cIz8vZ}<-v-}}E``3HaVclWP6IOg`$Ovccr zNewYGG0;dG%!n~Ku5{}Wt&6#$sz|jDjj>k_N}FWHS}8n{$@{~4bCB9jaq7uacO1U% z`}WSh;TL}MQ@?oA|M=47Z+o3Pd%`@p(_G(pfn(<36YW8|~;E}WUoH+jE`tn+*Yz>=AoN(P)XRVTkAj3jR zt`-8S2_>y$%!@BVtaG!*%@j2WC9`cfmrK4Di-8ubXsEev_rcP}Z=O6E$yJ+o1=Ts3 zOlq~Hl~Q6$+wyg3qn_D|uNm)W;i2RGF6F}PU?U_b8yEr`HBDOsv<%9W)SOL>jnUU^ zjX4Ylz4_th(TRy$-?U@<%S?LEw)Q$^$bxqNt;`>e!v}>2G+`2F3_H|n98}m4v9f`U z1WUqdC)w^MvyEg^wJnq|Ea{l?#XyI#9w`zvN&5l?wOAP_07KQTn3T0tx}wY|bu?~}V3_+NC<-lvgJ>BL80MjsCwCpW zY24LM`&>ya)FUw2YBH(xhJaX8`@H(~%b|U;JRcBQQfG{pVNW_Gl@`WV=uJ}5N?%os zie$VJ1Z5DA3suKXRe}~sFGLbj#ml zX)DyI&;4IK2cywSV*#6Lv#v2hx8~ItH3s4o5ZyeDSYq4dX8%=jtfh{U>%J$ReLS9f zQo{f)A(OxuRGOh-#LBTJWK$(UKBN?+q=Nv%SX=I%S}BJ+S`#MSxqYAsAK9C3YZ%t< zCgqQwL0(|eVT1t-kP<2&g;aKE9-WnqA_O3S5|n=B{QBx`MOi>*t>Sv-|mp#pIT~GrPxA;LI}C?>R*)ZJKVV zF&Y3kIlbCBxjeXTYJ8HWF4@<i=$;w_uFqLT6jN}@_&s%FMe{o5|#!u|fp=<-TjdzRh78MU_l#Gu z2}~NbLQI3ITY(By*du@>0*=U7L;}G$j%BHq`SJs_YZ4Ch|5NpzVU}Ihng6@i-us+$ zW93fON!{vJD<=>_M@pFwtO45&|R; z5(tE{)KceE-IeRsjpv-b_geoC=ayi;=+RT%eJkCw_X_X(drv_=cS@f;DzQgH(2|F) zQM0W{liE{g)V0^a+9F0nm2vX(Fuu-jYYgrY{hB)R@4)c5+>k9)mM9$PwsyCBX zBh8Y;4UpgUr7z$91Gisx#r_jd+?$$=SQ?X4XP-Fp*^hnh=YI3wA2_`Cu?J7?nmKS` z`Anqz+@+IO?t1q2$=wT^ryA5EM1=(Ps&JGtX(_n@Teg*7)T<6O2vsPdkU@ip!l-72 zYRxz%jVNaiX0tDLy|vMxS58l~FP<2#tn^G0LL3POLHfpqQ5*<~QVcODLexBHZj*^x zEj6YX^cG`WqS%R4*tAgeL)jOOCb1k97NIOb!iJ@cFp&(P8q0w~wqJg=bM)A~9~%wU zk|YT+Oi#|g?|pw;=A%FS{Xd(U*w(1G%3)9=X<|1wHk;P{>@WP(fBlXBy1ce{WZ#XO z-A(IUk>?Zbc3$R%9}sP&5Pwg{3T*KYtC_AqRcumAlZ>D-_~<=lX_6%&N{p!0GiKvU zG0erNa1*xI9W0(*Bjf7L+T8ry-FJLrqc>PMyHFNojapd){f*)F`5lAdM!C4wm~w+b zZ*^tWd!N;_;3br$wG={(K04=u7vbovRn}OPS`Bw35ScXP(#Ogt8DbC>QdJGXYbeVy zA6Zwgx2JdPy>|bh8!w(evATGU5QxdSv_3IoY6Xay*>Ebc9N$a|0PXe!fnwoF!O${< zD3J&nqe$F3WU5k$opYlif9nst^_4Gt)o=aYZ#{kP#C3%dZ?T8ir7L$4}zaQ9dLswn)##I7uBB(A2BhMl3YY!j1@ z!usm^#Kh!8YjU(coY}rDtEW#qaAMEF?Xa=45}*CN8+Yt#efyrrk6g8HZtu2_zwZmJ z$;o=NF&g%-z2ORiKJw5LWhrT`*6Vbqr|U7=waw+-+vb1bhko*&uidjSIJ>vD|9tnN zRdP+9&$fq9@?Zef<;|7#jg1Gs`RGR;`s|*mJukof1+Tj9)|cIK>yaae|LPO}@~?M& zZ8RuT>t^jF3A2X?rzS&;5_7er(N}5D5=BIqNW72C%m!L2q6C3D!>kfxiGl~Nu`X!# z?)t|0J=-t;u@^u5=YFwK(Zew?VcpAt^gN6VejnR8-i2!pE@d;gfKsKJz zu!)dUXH`c6?@(GAB^ZisbVGDpco`O)I@{^z>$yi}LI}o~JTHqpHk-AiWs0F66h#Rk zLeL6{!G=@_o89hUFr3QFO?#(qyHZnFrR#ZoWkkui$Hy2%O|t(2V}`U$&2rIb=3QS$=1Ab9bG z7KILKn7$Y z#8L~4LrT3zU@*Z5g4bXT8`VMdOue`33x4Xr+m4Qo|K-|8RB+JR8pjdtY}na%T^#2K_H44)`X0xL`ap# zpfM6)NW26?iKvpQAqpA+t$GawIT!|mG}nCGhe8+>HIjIRipI*ZC}V$NRnLu!wyNHX z@S#d>R>~`t-!oU|ciUiWwW(D-MD+i7aCEDeRja7}l)gtVTzy2br6(RcJXOb4u2$5R z2xWl42~5CXK~FBmm4~!4#caPKx#}fu-;wgv19IuK#vE+eWmUAUQY40mQe{(yhgc;7 zTS_g$V7R=Vlwo=@N#>fE*jc;oGTU+tY@W!AQ|Fi>aVh{v5d$Pv8>B6|DOYb@t)Prt znQ5upFZxA1WN7;G?Pn(%Sn5!BUHcu)>Y6r~#E=z%PS5Op<&kTyZ5~!F{@sC%OXbp~ za{7v$JLVfh;LOoZ=g|dr3P&gl2q9~tv)+4bdGP8ZJDQlgV(#?ZHa&9^%p`zGlw>TU z5|CrCSI;02llnlU#1;~&u3IX&QZ=nmR4~`5x}{C$u}fNGwRTkqSHm09>LaAulg03z*43VTeRkR1H}}MwJ9e zh)Hb@wVEnQ!%EeTi=2f6s;`+UC8t%FP@2H0!XZgGt#dsFfZ4L(j1%C(YpDY)?H0&M^Y0R1}9qW`GLUf}`yzm82tCC@((MB%QnoG$Eq>@Q6u@XhDR<)J%-Y7E>5m&LdVkoFG5O~Kv zdd|E~6OID+E$V|$qTivGk?6I%0n_Djh16(gLX!s6BOf3yAqo@V2;_iNS;mQ`#()?G zsCFI-5tAnS=BJ-C<)E5egJ{d7O+cmZt@6V#78`Fl7L*K;CAQ=6rs@-b$koX> zDb^u5RH_-}Ggb^X#u@{GHIBrPaFw4yN`?)Dn3>6zMMx98>BpbteT0Z}R{C=08w(eX zUfgzQ|M?TEzxK92{nyX`)-S%}W$%6e=Xd{y*S+H{*FX8#YyR#%ciLT7x!LVs{rj&@ zTzSRBEzerH>;9y*onVEeGNnMFQhifQT&-3sW4;-;uZBxMy7IC;wT9bxsDI&1iL~Wv zL>ArNvS@L|wR__rKK{ig>e8HSwKj|87$dfon76vymoP;T<*!nd~4rwXCaWJaDrHMXk2MPL`5ZvD#VaeDkCT- zjvAF9s)@E8IaMlA5SpTz0`s@l=t{*IG_GQ9VfE?ZhV<*Eng<0YZ{RW3I|N0@%K=Q{ zk_jb*l6@?^U(~QhrZ5&{0<;I}0}?$6Na2l91%m=vtqe2KmkOQUxlclQ>an{*zMiB> z2+<<_>%aQztFFBK=ic$l{cd^1;r(P}xSqR|O^wPy_ZNQcS08)mk-vN2-|U(>7$E8u z#EnKhO=}C6&W+W-|4+j@h6B^scL)$Gn5}KJ+fWpvTqGJYQ6zJQiC~RHvevdIQ}vS7 zlDVBzWsjIFaXLLQ^~N{7=<8p3aCU0u;P)T=`d98d|K!T_&WX9*b4wR4gb+r9{-7U* z!!7~M)`ZJ=&@VI+F{RE7L-ZjUYpk)v^th4-X(hj3TiZ zmBV7x8Fm+3GO_dW8|L<2b?Wi^iea}51?PQcH|%aQsS-0gsPb65MSJG=4EuxrpqDrc zsvh!Zdi#o5KlU{x*5zgXyl21YN8j*{zx}7bzvnyOII#WjuozNm$WZXU(QGZ8J%8o? zeJ{WD1t0zLzdUg2ks410jRASZkW`q&%$+-Z^!SOdTIq$%BCl`w`b}JyFouMQPdiZ>1MOj8LY3a*Ia6%dF1XV+Ku`(&pCYd{L-2G&c%=p z);m^k_4P+qH#RmmdSxNK&COjq_PzZr?{Ln2?ZLZuZ`&>?kDfjjL!6#$LzO`Fsdk#w zo0Aw7!q zK|NC%L$FE4%t5q523EKPK#XM-iJ>4;<^%$lCQyyVpxNkm`xh2Jcklepm)vms4}bfw zzxJ-*`@8?~JHJ_m<@760xVK$>)4L{~dT?QFMJ6U(j9OE!sWuE*Q74GqNI_~=THB~` zy=h$MvKx(^hiMV&5R&Ls2Ot4CXbnbzRnp^{pGN1XcF)P?GKM*Mz}Ai3sg88@Vi=5~ zY1&w$2$KsHBBNZK*TK-20+-p0IL}L{2y-bxqUPeoh{k9X^^8OCD{I}+pf_Q0&F+ck zT(j$%>l;m*ow?BY%>DO2aO%|2wZ*|OC{m?b%S`TW?3(5FAn&f0t0O5UZF?$hb<3ej zR8l2ka*k3!v)C5{X+8k{6#24S=`TC0!r z@OrfRY#r`KAZCSIh`S`;r50`mzfWIqT`tthf13iB+%CfAMv5!P-##vUz5PZ%_6pF)`M@S%zkU`9g7z2cz ziGdK598z+p)|UIy6Q#^q7bvwf3WJdhJxZu}Ex=O5JWx;)HlV1P*c;n7Z{)ob<=NB4 zg#>0Ro>Y}oD9AYRPD&InvA0}byW-Bxub=g2g_y}i_0@AEQbsB*OtqL1h(HKRU_}(J z5@)njEouGDddoZJ-o_N(-}$$T+S_Jkta3Fs0*%S0M2PBht(LAqKqDPFwT6s92xQoZ zN|4BawXD#Q4q9RTr?1`pnim{??0v`o^yA0x>!yL*3}Z+{#=)2se~8A7UzNU7p;CiN zUIZ1@%q07!x0C9^+7bYURZ5>>4RCtJPg zIGSSY#KkzfWb68^h{4|tj#E`)9(TW0(MW(sRjrr~s2rIz-V&=QOa>D84m8(Jk3?Wd z1{aIX1#a)=UDxrp1G0ElHZF9^AI7uKwa zD!GmV*dR%e7yXA%_s-qA@9LzzdosIhK0kGW$^f#k7Ua|iwr&guHw-cm7WHHe;+BnA zv8Dc2VveE)%*I8j?A=@eODk#O)~{EHO{E?mOEFaeNf=)GtLR6{89GE~C0yK_9hz~w zCD*7B$ zzi_(e3vIdjT#^>Xs~`7RIZ>XN)tpXzd*mJ;?Y^H6zbt9J-pN&(zB)O4Xm;Db)gSpk z8+R@(UaL+OYWF=`o+nHU8^NG!E7JK=pf@Ed*YkScK=v}9%hNGc*O zh%9tW1A-cBT!^Bo#&A#&6OoC^fF*VnsJMzF4Wj|?+-+WXz09T z$;IAj7#(XSRmQnK)xlU<33RKtA8%Nzjjj>{;wu)I!~hmZNn<;P5Tu%XK%nFdCj=ux z21bP#%;ZR|!jN$yFk}EDDrF49u{G%cMDLw-D@QxWzHy#wyt3SzYBnEv`us2a%%6YZ zbHCi}Jp0f8;-kOwUw+~b-u1G_pEz^>*Du)FePMO+D}VpBYi@u3+Cxtb%UE-X!uZHl z%#0V)xP3Q7-~1qo!%?`1;wq zzI4}*{LoMB*t=ul>{6CFusMcY=+TFszG~mi%PY%5@${vq zZk)gM;MA2zHy(4GsIZbSjF&(J!zO4HNXAa28aM_oBLPKKPqC&V8Z!iiZi)w-ARV4l z`Zm>FGV$CLL~Ex)4|z>Y9`aI4K~aW*by8|I*bhp%f^y$y?vk`^4s6} z?MLqW*k?aEKY5VZ4o5|v$67s^Xf`jMJ->T)_Kn|n`tZjX~Kv)VQ+mJ4vKqO?S{klvZmSf zK6~zKpE&c`{YNjmZRRy^z3~mEM)TQR8_j;<3Av#(F9I-9BtVQYRvBdkcpsSAFiE9% zBOUwH1mFZ34Xe+6zP^&yZ2zIVzxBK44!-23xg#%o?>FB2oUgp{2j1|))dx;*JJYuZ zn&0;avmgAq6%2MxG`METdP1Qgm#h`$_UO#DrheEZSF_nh+#+No6@GpQC6FVk6Gx&; zkh9V|F1?e|J4gADh6VbHu4rj#vlBR%*%@n@sKqI$KZ-?3rp`rIH-`a^Spnyy)Vwdm zYOD>a5ph_Q6d0=3G9h-mo%K#HG3B1g=5ub@bHf$Q*@@cHdgm+mJ#_!+V~?z!U)t;o z5=TjD>P~BInwm1xleSrg;YPkXz%W8B*%0zxxfxL~86qbtjOa1UWu&SZ%}CU49JOqn zNrxeK>ihP{ay9u^Io>?itlf2dtN%Z)8Q%(6X;F=&-Np9H-ljAH{Mbr1QodUrIR)WhpU80CP~0pdus@iCCoC4MU$q67*w{ zDCbc(rPGrRGv|_fl+aKjFtJwF5s_c2db{310oyJs<{b$$Ir3o)i%zBrMEeCZifE#H}ETK)95!^!nNM zs}Ak`&}WYS%{R}S@U4WKL>eTJ62{Ma1%Wh1O;j~70U@dykU~64Bc?#8lifM7%~@Jp zTPYNFyy=vT2*gquCnbOt5KAyb29h#VHA2a7P*IIC-g<2f7y(h0Dngd66&1iDqH zTJ2-27Fr=y>O|GhjuA~n&=^#ijHu5g0Lnnn>hBPPuoX-`ZYRIzztHcI3XjFZKt&85 zD~YQV9ilP>n^Bv7}gtY}FHLHTA0+q$(Duvh5lRRahlM6h^Z6cw9VAQ`^wkM%gs& znA9RCo0__lwM)`nr!dqc12Nz#OD9By!I>+LpS-j&nAy`d%{m?0WB0T&i#$j7!KZaJ zGL0-kfD#nPqZSB6z=TSs#a63~3IbHgl4+*pdT*gq6u{(M)9jj)^XtS8wFDlB0nQS| zz?>YJukUPkfp0vtxZ0JsJa6|c-@l_XDAMRR*130P9py+iNc$ZS32g+mtlGTEwWtFa|o#>VzuPLL90@=RAl;fB*|-g0I%&%$4j{m~54RR4uR+ z3KAZto{m?@m3xo?rLm#VRgOYsRTB8VtS%Isa3T?PnrU!bDBlc=Lkt{vJS&2+WTTGL z3k2jSv1Ec)OFHM^6gK7h{^=wAe0{Z8vE(caQN=j4&uD-Fn<1-l9bybzLWzMDQpdHF z>orPaDBIBI&+oqB_Fc2DZ_qU?Gs<1^f2WWAQ|IX?`Wu^2Xse!1HEX4(k(Ke=IOsr- z14HK3kQ4*I@=!SU^ycN?Fju~Mf?sRG6*@UxfA00^{(qeQ+9xi4Q?{BLXlCDYj+enFoB3jnb(gvbH3ZOs?&@pr$#%Vdk_Wf*JytIM- zDuM?qtVIOKKypY4jgUYDQX|4J&02kjOD8ru=Pq@g7!;>e`@{ys8mYoVjmI3QH0Df< z3UbdbflBl_Oy#LoVuRon5fGw^a~DBM&S+dbw{eGx!U`D$pk!zq)ks_Xw(95*5LHJX zD&t>;>XL%M6+4QUK?VGVcmqTt8Sm*U8*b8Q)Mtl-wHPbH6@jc_!(uB&t18171(7ic zrEBZ`JMMVurw-mi;IQtO&UW2wtu@p7w@-ev-yd9Y)fEqa>s!D4>mUB>KmL(HXY<{E z@%}&fPe1+Mzk187Uh~%%7caTFx&E=!%V!TyUv$rGr;)=hHa)(4etvuCpomfb+8G<{OSPlG;<>xabFQVo$?nrj&v$jSU;s zaFMJ{veee|(J)P2n!3@b5cNh?WDI9Rj0BAu^t*!TE#n&zGaF+Q>xyD@$7jFzBX54| zZ7;j=qksReWh|XbYOc0@dgq=0`sLTW{?$MH)*o6~{_BL?^4i5GPCwZ5nbTU$U_uUsy9v#-| zJb(3ctzG}t*EcL|9?MZEJW7vY0(MA#OSVtUy!0YKeecA(9)b%n}3$|BF)ACZ;E6_w+ZH^6p7S!D$*|8AEv2Z~nKR|An9W^Z)aIzI5k3 z2M-)dn@Qd)B&to5&CbfM`5iy;(?9Vm?|A2#izoNYUFoINXoO;`-7?m#t}d`KTFsHG z@k`aUj;Ax#JJlswGtFwu6hf$O%p^%vB}rVV0gw>I8m-k*Ytzz8)~vatp`PpYCi%E+ z`^1Z0{+xa;qe2efxUC!%WiR*nFs-*wJn~epvsn(q+}`cRxb9}Z*|O`48&ZZ=s}9v( zr>hcc^^Do}dqZLn#5xv%L_m}+S<6wB0B3CkAQBOw#Foc~apI^#YMf2T@~FSCx^QCW zzAG-C`sT2^Y)y?IY*2)Gslh{A7>E)s%n@clZb2u(vme+Aing! z`m?`M4)VYK+rQn`-qmbOdd-cs-Un;z-OhR|GjIC-+aEvi*eAdCZwjj*K|xR^3#F(? zlG(|b-NE-qgHlw?R@1Itgh)iJvnF8z5|Oh%hcTF{BT3|W(*qOldHUFs|NM~;?b~y3 z|MV40t7}Rjs~e48)wHLl>a|SQhkodnMvEXQ#d4%UiXHQN4(z-9(%B0qPOUxMf8yxI z*$#K!dF_wiaND7o6H^^5W!$W%t&uN*SOo&cm_t)09>Z-Q05c=RXib%o4nU1#D2(CY zW8NRqaA|t}iq_u7i+^yxf6Y&Rv=7Y#lhLwJ6ZNFaxt)Kxu2si zl(Q5Lo4Jfe>@A7N@`a+F+D476BXLkeK2jcHa0Egq#VWi9fvts2D32Z>n;0_O?+rHB zHnkYePt;!ZqMgsWwXv<%Ja@YH^~WB3;KGwnY@A!!7<#aQNp03}O_CG^&)0Td*4jVp zkJdL=B66XSfD&*X`@`XIqyx)r$S^^PRD7u=G|rg08c%P;B8d1Hl-O}CwZ^K9ytK^3 z-p2f99QF!o@odAmD87ink;}LSHP+PTvWaa;ZLUnNpKok)={LWyw$KezwW$v0nv-S6 zOc|^(i6Cy2tHr1{=gh4~+J|4hW6$?BXO7gFAP?!<9eH?E+>+%k+eo$s+ali+$%uAP z7$U4lGRtNUX~GheCsAKVI3dMFF>{2=iI>#Pu{pqM6iY%%Tw|VNGGI?U#iSr5H3lB& zsz%X45hpzkf(}_eoMFajosd?MtHdCD2TPysp15oM;>mu0g-UM)2{-DRdDULFJK1w2 z{q{eO)&|~~W@MuVc`Q_;noxwi8%ACOGg~%31Rp{qN=#BB`dCn^OtB2P(co-4knRZm zK&1gIqDNlAaxGj54`ruje|_6T%-Ynbqgj9gN~s9Cgi7z~U~(<4!R2q6eRZeYylZ&> zkP0R%8ZEPm1Vn}NHSS^d+Uw!Y_;=|UY zt*X``77am#m_#LNAaEn8rJQujoW;{OaK`R z0%D|Uc|uH;GY#LB|5YeANI>2NJE$Uf7^9-9k;sw(p_I)F=qzg5f~_N+(dij%KSVo@ z(D`G!bQV%VN{B&XR0Q5@?$p+B`uzE)7oUCI&dFVq7q3CRWfEZVRNjB|m{qSyP0Qi9 zVUBUUWvz^bRl-n=V1WaSAuwVjlVGuP>Ud}A`8%g(n%Ug+KnR}5BxFflqAZ&CHEm5C z+0mM#g&gNUcYNhv9=P{+U;FcKI227hCWsStXh>jhD2kf z6rw7Hg;4QPKp+woQZ{5%5k=Kh>8)HLyoKVXEV9^yvYNIg+}uokdq1q5=^pLtx}tEf zfT;rK6~Z)5m{w&A0*KWpjDjaZ%s zU}dTJRW?)3R4p?>8D69eG{4{6wv&z!%|$$5@#uLhUqVv3-%5lMD8~|a1R{gcntbQJ za`7Bo8yg+KfHG)a>5*X!R1pgJ5#Y5Nq#-qCQZ?)3oyG3ctDQ#`8?aE>$}k#_%*C*Soeum1ZF=I{Q~5C7Ub zf8>K7c-t#};Lr0xX4=zdzj<`}>La#YFNLu-WEDb0);ceR*V3qUY$OW7gN7p!p%7K0MvvIgl&QWjD3?xk4JdiC=WXZ) z&m@B|C@?6|ALwd89)gcVpuj+sC{!AwK}Jy{K_td%_@NZ7)euI|z>cZHU{x~=Hc}R# za%RWw$?3V}#k0eWlcWWli^0bbf9dCc{nvlvKm6nSKltf?yJPRZgHY4o92#cl-1_P| zi+|U<-}SMNe)0pKeE+uAzF|JH#(-dmr`uDf&m9Y)BsS3R5z_+zj}-%=%+{F980&ph zt>)^s%zaun6K88Xmf?bl-S`+CoAM`fX zjDf-!ldw<~i$DY)V!}z1+M*bSA}|pPR1ssOik2z@CK4htXHFe^;dRfSn3*4Tm!Kj7 zo2C?^1W&}KnnMAt_T+kJqsYs8t+mzHlf(#x#OQsfLao6l^YTY-|IsTBUH?D-^ndgR za@pSbVLn7O#9FV{%3(R&*!bDE{$#he`S<_!{vvowX_OKKMgnL+k*2$L?z>)M=v-J( z38``FC8{z4F@>NpqFGN2VK^9Rf-FhdNbJeki|3zp(+#)X@SM-y|HX+Z+FTvveP65B z9=Z4IP0zc0qLo}YyE?mbqSq@foL*_qPSx6JEJoK{f8^BB<0pK3f#!#@Z%~WHlp7y%oR0m#mSz@M-Fj zEbR>kpE&g|Czqf4wd;TBM{j!V?>_jRXrwI@!@&sf5+hYbDPjx}JZ5Uf5Shn=877WJ z;bR9wXH8QRYVSQTdH4n0b#CpLxaPUnUv~BMzCF|F_IJPU*Z=H4{Pu_6_^Ml9@azMV z6DW)F@Q+M9`H8dL<9y@ur+2-A8n@YGCu4%PGy_mk4Fo9H!9qBL;;ArrD)i52zCh7q zSlWV3q3jcsj2!5UsNV}d0)`4D0gr+VRo8~mF=Z*)6ziQl2SsQoq8~_BvuR?CwL!&~ zF)?Q3i^Y}AvMgGbZaFmh!sqR};rb@8<6942c<;k^eskf8h4qa90!+=c+oon=Ev$H> zkq@^I-Z*j9TDP;D_f%pDQKJ?#l04U5)Lc=fWT7M)nK&R0Wwg`GT{m?_&+B@30VJgc zRqM!9S5^(lJnu?ltDA2oXeCR^cTN#g(sYp7`?mnWu{Gg7}gHtlD~#S&+%4R1y(9`1Hxw zz2Mp#uiN?Ydyge*RZR>rXi$pY=cN{<7DC81H^GRC5&}fkM^zIza#_fz^xfNUxoyfO zAAR6U-OwW8Udp2EGJT5DZL#(!(2NfeJK;zY3TAaN||3 zF!v0;vxsFK#}4=i15!ayP^`cd&;lcX6%xmt4?$I+9^rZR+Fxk@V43Tmbw2gw_=shb z8K)A>3Sr-I|s?Gvq+?%w^WOBX(|wvy09 z(>aI+4OQ!=QdLo^P)k-2MaRpkN*){$ENluJqPJw2u`%i>#IYqplt`6&O;w`TO6$uy zUIjB5702WVK}1EMsw!p-4u_~(BGG8ZAUO3>GFgQ(Sm3LwLm*YJF&-aRThX!0X*`IJ zI@Z97Rxajh)CL7qg{q1aTZWsh4exiWnyNmn`qu9;t=g@7c$~{NzIDc`XWnX1s}447 z-P&V&3IJ5eHzYtDXE}-}RRmhDqJ>q3d{@gJicRz{hLtBMYirh~*?B;;*F^{@N*Ga2 z$XYaNSiZD&`a)7(cm1_H)}|*KbqnCqLl^Q(D~VM_&{zN^d_gD`5fotr0+>p;6|3-@ ziUX@YN@_6}E?wNbIKcFrZSR{N)G|Z?7}i1o3eiVgwR`f~Z5d-}wHTeagr|;u<4-?h zYp;LvYxeIYeD#Tq;feDc1|X|R4Qk<1fKb#iT1!TQuoi^e!;@Lu7BtKojV>qzi37^>uT%@wI!IyC`-^- zN+fW@G=yxLW&tBq-#8P28BPSE1ZHbY92*K)5v^f`M37~cNt|5RTv8t~k!30FGKp4?_uKg8I1GbH{iPXX~Mtw+$SRf1# zM?g7#s}lhkCoOMvp?7qx_ie#4aW#jMEhZFi(X~a1tEw}K0t}lFr-T5t8Y7sLV#PcM zr_czkcCA)Xndc1*kIycQ-(O?5YNZQ=QOMZzj&VdywQ;TXf<#rOjxyV=!-Ti2tCc;F z2@K*G%0Yi!G!hvalkHS#j4Q87?P^!7Y&SYjZ=0Nb@$;@(e7dvk@>ajI9&EX?;_v$U z!%020bvNp7WJzo9?)`uHzdkY1Xujj^FaG<#`{KL*{KLQY%RlmwfBKm>{Mg@zvZX%=C+f`rs)Ym1>GIN^L_8&U@t#3SV z=V!if`wxHrlMg)pyUcR7|3u=pKpfEI@QN|AtJ+w>IZo*h$yLH zHin^56oLqj)$BZ=@bF3$*;{R9wgo1yVHk2ECXE3D&!d4Z7ubj#V)bgql2Q<1Yk)!| zk1<#E#gN>|MTzu*Y)*{-+0%5oN4c1wmvUKjZJ0y z&Yhjjwbjl=RHp8&aqn2zJ{~StSDZ_-j17lM9G5s!O)>|-81^BU#93oKNmS|g2Q#&_ z(QIlojfqyX(KvhJ^rZ`DPnzM{YfG`tdWf+otL@ zH@RzSZ80D9is5Kbj{`pl8mVMw#mQObtwTbQfFP(l+#T!>AGRz=L z8c8V#l*uhEEi%YCn>CsmqP2FEk8xB`yH20He1DDG@=Y^7e;I6yO)+OUOIDWxQX`MRDGg;?!wvrVExXoefEZp+jj4} ztkr1u2EC&6SuO3Yj=V(CvdClZ14$WFTx#oeE=I!>Pak(lTCdmHVY1yA(%|m(dp5t- z`{@I3f5ZI0`|!f&vtWuM2ZRkrAFZ{_>?IIWWekfV%wV`s=23jJIe+<~Yf6zzr_V?c zBgE&IinaCLxig(d-v7jBcFtdUFstuud->#hKYq_AK6A^B*L>eAZhO;Dy|6yRul84`$SPLnlLiCm|;$ZW33UT)agVY!EG)S z{T})SBCAc*M-)-Skr>K*q5*R?7l;a`pd5UJ;k3^6)H*gcG3&j!vep@ly6qHK&o^&- z{`7U%HD@w=`i%eRCmy={$;Tf%cfM2R3M6)F%G6nnQLZdptkwsfvUAU#IoycpsqP@t z+C;szP%iXj7&H&$6(Op3>s zgCif%t8I4^38kSFXKZFoj6MXKwC$Elri{C0wy}R(^4N*aw>MTzmXJjZ z7TD2f-TJ)k*S>OQ?8Ds9MY$-Arv$g5=D$PApuR3&Z(~<_EGnY4NyU*W>5nhVFV!Eq3p*_5HA&cMJsohVJ4^s$#-Jr1+AM#gb%HK=3aR$<?N61gW|>DDTtEPx1Kb;E{eq`gL1{qg-fZ$Eh1`=31d$@RsWopLa~ z!U`}|RP`vLh?OBzs#p;k+uE!9-hi1%NgdgWCv2=C5Gjb%F#`x8tadk|`qU6tuteClG-Ez;a+JVd+5L&ZSh@T6Ke>AB z+0#dMJoeegc))ofmS2`+z{kZgFylXzy{3X zm{=55a*IXc*ah)T(_Mmn^E3~>6rcFq#?iCg3q?MJvSX(akd0VcwRNuN(GO+RmQX3#B}cB(^)zxm zP%+Z31Q|uDCDzqsQ0S%Q;?&0nhwqzw-Ww-pev;%Gnc1JdB;!6e6MrlM1v9#0tZR0V+@fcE~aq z1LW`>_#tEjia_NERVYY}#L(@Xh{N;c=xLY&V`T)0NG0OCsYU=u)l|L)MEv`;wA|BJ; zw!TzlW5z31W559TsW}<4YD|n!Yrs~yXAKI-^q$JHTTiHI1EIRO*1F-Wb={^_G1{ox;f%PU{?(tAF0-}?IM^%5tLf2&VMN>@`oUJ<{`=4Qh$TQc5OP z@qOtLj3pO>XEN5B;LE6phy>4^mr?|jh4xZy)X_q8m9Ab%gJ`L_U{L5FM?Y}aOQ}$X zEdz**VJONVd6Zn?i8RJsQHlmB`oz|{1fUqUV!ni9Ibut@_8+ipFPwZhA6&3ZY_0cY z2>u;!|M!3R2mkFm-}?67{lh;dNh9Vu=nd1%WwlzrGgvrz?w9}LFI{!rHMiV&bJ_E) zscnVN8JrjSwuu?Ge0t%SqDmFpGTLBE9z5nP5n!xM2^3?D8m+Oxi)D7H^?4}7J7>HP zDoC=#Ffkj6D!H#uX1nHRpMK=%!}ou^-fFI`_1^!!_tsl_{WaIk%}%cO2K{n){`g8Z zF=MlO_fo!jp;vFztTlttpguEQ^an)|h#es1s8ou>?nqG#htXxN_QY&^YSwLRHd<3D z(dyFq5P~tzS|)a3R2pN{I)+grfEZ4!p~9CjqRM;#5|#CpbH^sP?{`@{6g>xuK{bj? zU4+J9fxyg5s~4GwDJi4RlDbP0t~H!7!x4@Auqb?`I=1ZI@`FG1_~Va$@k@8?-gbb2 zG7oH+EvGIyfA-9Cuew$9GXOdJ~= z|I?@bUMMhwx1bzq`h-#@$Us#{+1+(} zvhRE2RhWm@sD+{g5g`Q`a2HsR{E4vfXy_di-zAMMh#dya9c?hy`jG&Kq7- z+rKOAoW?!(ow)OfCm&cizq~StS|lc!NM>1$6-PcAW+N0tl(_^5$zHcRY?$MN^OLp4 zq4wUBqq9XZ9BE%D8bXjzA^NU-WB3KVr}}Q-8s& z`;WY0YW|hAnQb+*h~;~W^Z&3;3p5?G8Zr|tDe0pgJry2+tB-$+$AZeuEj-I&{m7 zhjnazzJKiVD`y@at(_J>v^ki$PN_JefLQ7#2RZ79{56|FQoj}dmi}F+itpk zYTJh|98K(YLng*CZJs0wi6PXTjiN;y#VQ?$AR781j&D)Imrs7n%b==81Z9CC!IFXz zDg;li-Y^qn6&t7hIjPXrh$V_@+#5wkI&d(D?PdMG|7>~Bx8kE+>KSlQ6$n+y1FBwv zLOp!0o`@L~wG>1m7Wh&Wq-|t-X!pfY_sMYQgYtBsP-6p84O*>{f{I8~glcD0iZ^74 zP{cq)AQ=mEAwk2|h~5s+X@}K!T(BEX;4!mT zsy!lAq9a5C1S*K4w3WI>UZUIL+yQ_}l&GqPHLcoPC>xLpK@tNa!LlKV3N=hb97PrC zwn{N#_CZidI8~xX!{jACL;9_3sL%A40;#@8jJYY5kng)@R8qtk1wJCER#;!zT9%Fn z!Pr{TVjRlw3{v=eKGV2mtRfaJlBz>u1O7=SzKOy?EQDbS*&(RJ*A}i05XIIlqJ=goEptc-s$$% zMmzS^>)R&nj(zdeIZ6gpPh677D8^cI`kI6L_D!C?b}yPU>^CK24Fs|vslc0CNlq0_ zNhA_85edaehN#-avL~gg?{I7@{44V~g`?UxnJVv1$HXogZ@!omhRpak2`$mhrRT$_ z&J(Ra%zzp7zbE31VgHYdJC6PvtgSy8pp0? zvN|^iX%tP$;S0A<-}3L~cicYV_PE$qI-~iW;fXITKK<0-!eG>aC|l=}GWtA5(J0Dw zZAHU9iG@nsTJ1|gWu#8Ph)FEK2$C1khiIIlp4KGjdG9Y?$WQ{Km3yUoBmWMuS)d=EdgI0IJ6Z8 zt(7Ux0ltq2Xd7i8#Q?~mebO8i7p@|2!NSzU5A(H$RF_~zAky)3p{kxp5w&`Xse;6) ziAZ55$WACosX*?5#I*Jkqa3X%Ij|xCY@i?sW7h#QltH#S+fbQgDybwpC1zq$l^Dm~ zHc=HBhmVfIu9hm1GDraeGnujJ4GO~q17)gE)nj)yGuw)1P{p${jioC@V78X2(>?n7 z7rp4^KX~v1@4n+3Pk;73fAoR>^1pv>a@sw0ba8(Bu8mPyDwwQcD*MBBb3(-Y??3<7 z9W$*T`_Y$uRrCml@a&d=TZ*$2Mxh0h<}b@=%&dd|e@)_C@Z z%2sVy9NW|wN5)u6Yqfg6HzZb@7^v|Dlqz6AWL6edfGAcfi_|upNtvxEgj8Y-B3arz z**)`5@B8Q9`|aPm@i|xDbN7R-scGY^2JGK=#p6#s^3U)4*t`DlH-72A{QR+#=fC;* zxulVh55dP1oyRVpy5Y#o^+#788N_}a^~#M?4MzzONI)0hRe#_VKkZLw3X788>- zXZig3lW+O4x4hz&ue|+LuR3||#O|rfyS>d?(g>=pMt!2$K6dP=4>^%}rcYMOA-np)a%*$#`2!|`RlH@;q&)?@yUg! zQ&+F*ErJ2rs3A+XHR{_odZ&h?MIuLBfkFgTl~h%bhAQG)2wq5r!(nF3WPL(POPlV- zTdp?=zwaOZ?cCxMGk)hokJScwzP&y-cW}m+VS0W794=j2b+9^$q`d#ieG{`+Ja+%l z3!To3zV9WgtLt}t{d0aaoSED)H8I!i_f}Wepm51@2!*p*voX*+e)*mYXCJ=fpU;xf&9(DB?`!N^tIknkZ4u&V)QzLHd<0NZx%luspMKwcFaPUXfBz4Ea_;+Dnu08_2)%^3BHg3DcRCa+Zr)Ydj%;hm+FI87_Ftr=BOZsmyjgM zRNYNQ?Vjm(`u&;7+ACgKzxw86evj)f;_-(re(Xa}-+%nV@k^V-7=>azYo~p);3?(yjBTanai)gYWK?tRn%cjz2 zA8xEH$~TX9mt^2$-^ zX!vTh0z{1?)t1sc>2{($3GFo0Bxw>dR10-n#QNtuXYSj)@L0ZaMh7c#1Pf{;Sz^W8 zRD38)DZK(a5-Rcs2(e-wLYR2mLeUlxnZ}FB3cag{TX_toau2Gguv9$*s_WK* zfrL3RWK@l@5dx4QjUE{WA&L&Q#I2PLF3FZRe`Yzi^M?%{Z*76 ztpfEq)LS4>F)(R8o<4Ws=%s_(r>7NZ;+}qR(Vtv^M$w?LfCL~y!?;te+GDA5bSoTG zfB*@T285`Ni4hl8S64^0*R>}TYSdyR3QAQjWp98hk2DT%vy9FFqhl-R_BAyiG0g;_ zl);dQ)j1UpXCNN^b_7CO3`k+N399wIVEEt63) zRf1C~p1`CwL2BSqqJ$lZO=G>rwTu%7Yr#?$hh6r(+YVm-ws!qlX*nlB#eSBKy?^Cf zk6k*|>vs@}M2W4$KrxRh5Y16K)TWYD8NGZYh(Q$<2fNTB#sa1nMg^D3!Ap_rU{Hn{ z*=Wm@vm~*R^jKaj+&en;boaKe?6~}AQoJD6U(VMZZ0>p0!AIWLy6^6Dr_paUsDvE` zVdY2~LJ;wmlR8a^mg8h8LbaWC70p)3S_`rPL3BK`F;wYZh^r&k7tG8YBrnj|$$R&? zeN)+x^YaVk`SUhCpgw}2BnUzTz-T@K85n~RgCdAflt6?flpY9R zqfx+3%H|Nfl*>T3nnb}@bTl0YPiQs0vpQZG5y%iMU_ch4&;%eY3r!O+BZBaZqN<`O zZFwg_V}%8cn=Yt;U9~Ec;J*vAtyHYlF)$8*Rt-YNRhH~(n+jpBl4DTiteR?EqFRkw zNR^n_kTdK^469`rV+;T=*(B|CH!{_C{rZo1ikHq@AT#|}ANuF-fAecz{v*%7^HcAc zoI98Y9t=io*@*Qq1V3s|Ob?3Td*1VT5||b$~^wAWtF@Oom)FS5z`41PV++{GQ$0U9K*52aX&$^~j|_gMNS2_b!R9 zs|!nOi^E~RH|S)}HC(O2yAu&9jW?qp5P~n58E{Ebi_r&Pii(m5L^YB|LmVKY9x#n; zuAVd;CxtJD-nt*`r~U;CM}zj17F<9w1>5e*@p*m&r`)D2hfxbf+g$2Q8fCbd!N$u)vZ z)TmSvD5ykI17_Az0wG!wQBP_EhK0J+)*V~Xs>%vthGiV2ZZdW0WJ8MHlVW{qf z7?p$wA|k5RFoeBCW}^~9P&O$MMPCN-?djQ>ZQDDm7y6qQRP!XU#@gX<5JULgcm4Kn z{?>0k`S_E6_MX3t>Ly%^faYXfODXc=q5GeF)0=@02$mkGR;la8$cFrIl=tAg0Fb?huD8)I21v96Y;NtQ()6|pGGOBa_U z6fhQQ+EbIHrasf0nVnu*Si195cl?Ln{H6c;U*D;*=;oN5s2zRe{1Z%bPoQ z%pN>^@ZyDy>#o1*^mV5{{jtxSJ$|WPYd3ez1-8mOvvXgmE^(=~lqBl&e!tgUT|B+E zda>8tVDcaVEP-3?W<7PxE|2U*27_W|V&>{Au0C?;%BzlCwb>bb{L`PfxO$chh$xDT z9l0i5I&*(wU)Px3zjFSV_>rx(LzL3{x@*FbFPv%^8`Ytz;zKAxPG!#wtaT|9Sxcj$ ze9?1XdhM0hzxSX1cCEX9aL<*aVic9EH4e$z`bLuQZ8tpY(Gw5e^TfT0$wXDe14dy) zb89E-_4#4BG8`>b-T~22mSU|1tS`&NrN)qo_`Ed67{{V9FN#r&j_Qd{rJBvRx1C)) z^||{#$yp($^W?+#FP&Ss`p^yCjoz&sWwb9CQXaAA*aC5Z0uox9D ze%Z^*F#OoZ-#Z$1j~sl~&Rx4kqtUQGac)bzoMr9G_8=mu z%M3ZTrrv4^sOXhZeO5~)QaOw+wbK(bE1S!oS^8+>E3L(q1%MHhh+{faxwSTTTQ)IOb6u=IRh;<5djF|1$?bHKHHJ))+@$41EomHyAAo}~R$WFRgkCr3 zK5oA;&7RHjb@pEkrVA~j$qY9tK@)`tVnrS7h?>N6L>bB_!+^u|4H<5s@@Vkqf|;{) zJ@XOL?Sux9LLC#x0JwnStD|#Y?VfsYuyi&bteOD~ArYr=q#`34veUfCN1<@e=2DcZ zk%AZqAgV?5Y^jX7lCn*{x^jB^bowK&xn=6%+J~Neq=(Frsp2{nVJI>xL#cURheR%D z!CDQQG)Kv5nWAHgT16%lP@PVu6SA=^hA0Ax1PKGVmeoEG5{V>ghzM1Fc!Vh8%eFuF z%4FY%7yj)eP6OnKqWVb0#6eXN1!F9b*Gj&DQllW6YH=W1QkbU3HRh_EC+)?*vfQM`Le2T7!6QRrJ$^&lpMFZyJy%-09v-0nAFFT6e2OIfXIswt7Bu?NQ?xr zhE;_kr4B{|SPYYjSj1-HYK(zK$AE|c#1tW-Fl-f25g-zopkm1~X;d{}8KX*|5LV-0 zJqj9c%&YnN_`;N}ex9}#qzsnomLKB($`YsmODLx8nJP+!8Oa2X^bL{hJt zmrx8)n}e+rE44DLE^VAxn0wxlxjLWfo7KA?*3DJZv{L381DM94xD3RA@koQmT+=9( zKymCSF1>Mkl30k5xjuCcw#mTQNk9y zlnF+?lzH&biFrOW(>%cZ6ot*Ml%vENVxtnZ3Q3F+%BW&dNui?EIHscf1b`T1VN*DR zDx*tDW2};T0Z~n0XHnaQ(M4!Uh5%@cV1A}`R1JV3<_fO`GDJdJXk3SmKy{^*lSzak zc9)Q)gi00Sh=8h*2B?xwRO!s)InmfdQEj0#cu<6Rg@Oz*YXDV#84-Zl7>$)Igor9l z3TXt5ovW&-(4>yZs%Vv90T3GtwZ^0t7GwZsV~uqxU^Ya&)?N6iSHAAr7tH!I_2>H*WUKuz3;2P z@gHCFwx9gI;PuDe{@*|N5C8SE|M2=>{GB_#^05aR2X3~FDW7{K0}}xuu8v5NW^o6aSpx+y`Tl7wym`%OD32oF9zLVCl8|_CBY;nbGD|6 z5JGC(i~W^& zrZxM>w;y`#>t6e_KmRlD{FPt*;Kx3^b8u-AY?%jK@IC8~~?Yp+` z-iFA-UjK`Ce&NjNg=atiwq6lF^ubTweACUBUvqG2X`|k1Jo|Y!FI>2I^3=t9?zm^8 zx7KXV9J%4}>eA9?XE~d4Y@8alsVzqNXmeEhI4H|vuqt7*zp*kJ^vg)u!=*HICSl+I??Tyx!x*WR+Z*o~cTUEND=c;TDgcKa9azW>9Y`rxP-x_SyGs>En2 z#?*Y-Sv>RP%iw zedQbO{pLMSJpJU(>G@GHu(n1pM37iO%UiF0_R`X+FFp80VpcLSdW^|`(NLCU^SSSh zMi+?e7}fv?G{(pTCMHs5(kf?`$&n$T@WW7I?%uG8%Oy#NJ@DlD7;93QcXpxy-uE*hB?IQ6w(4mNhDI z*{ZqjaP-e#`$)T4BQ&B)W>Xbwg?c_`tWj_-B($;_hCYr+N1g*fHO?76;XF!bP&}BKL)q zzOfz#s?m~->hoAKnI^aDNUXt7`gtssC_&cb_7u(3sSa=%WHW3kLY+xfC#bp2w%0dC zk8fT&lP?Y68`LmGkAj_|c1x_&Fq^nTJ2J`omx`4muV~G`bh34eo!F7`67pkV;j`=A zheB~0N$J{IecRrw*|O1UIS`~kMiMj@$_cZn_^J{SaRp7iB~4z!;Zf;-vq-y^>r8E< zK~$h5vK;!K8a3ZkvoAL~B-+c|BCP>NsiL@VAl_9h-qSsI z|7hh*Tv;qPl}lu%mX;y}1uJam4~Nc?h9W|Ojb6$UK@1nMRILX0ss?5B0nsD~5`9cQ zeez++23O9`U*2dwHtfPUUwQzEp;C(?jtb3{U`Yxs8HNd}F=|wbQ3D`RLIH1JhRRAQ46+!4+Z?R9CD{++|mMRm2w-w+QqR_CF0$jjPHQnL>zFARyD1 z!FC?}@{13?@y$1$d35nl?tb)9FLhH_m96Ab6^+$vDu|T@u|ib_t+omjG0tEJ3I@+K zW@@!`ac!y8I1Z(NFsWrTk*0>V@Q6_?!;+??8Pr;JWEooeXbsgZXGWWjN20kZ00ET> zqH1g`fSO7ki*YyVm{F}ZL5A3C5Fq2Moov4_xU1`XQq~iVW~y6 zNZs<8Uq>wxY~!<%CH9zq$J6-0tH0{MU(@SC0t7N8WUsKFV@x$B1|^i(I<=k zqmRS)z;z8JBmhdr!djIADv&rv*Qks;WC>tGFn}kv>LZx3ytaN~Wl-*!oUSKxt&)Hk zD6obhYOU$3wx?5+1HH2w@z_Pupw>V{qeLSVqn1UbhlVH_RyeQ$iAW$Kw%GWW&)v`A znxA`F?J}Nf0F6L$znUxePSdld&t5oi{;^Jfq`R(~%KPY@9U;#(W0)G%Q_V*(2EIfr zVHq(XkXnb}MI$joV~oNehN-sO#7r=%mRKd0qRh-u#IiBOsxad?KDKbxFN28*8dWR| z2?1o_qWTKH?I=+ti`1iB3YTWEV=mjdeRB8m==^%IRH97O5iG-^3bPq+-n<(|hn2RaY?RXpty!w?No%z~_E-F0g)K?r4&kPjf1c;Hln1UmP~cn0ASV_p(<=O`cM>-UUma+y53DDS(kc`UGV1@ z5`rP)y;Ke*DI<}CAxHrct?*r5uw21!(6Q=#N&Y^dY0xq%HSTQ)2NVpe0= z7#LPV)+Da6*&WQao4@wXS4a#eKXUTGmGi&-AAbE;|Hps+@;AQl8^7{?agN3XD6w7EVgCSADtX@!t%deRkob7!6{%>zIucK7s zYENoq^lLyd%6p~v3|e1V>ujuLwVE}ih)TpTED;I{rB9M52xSN^spZ424-p(mBPoj5 z_n}O0OI{GWgOoB#7azVko-(%Iu@-}lMCot&KFLJN`* z{F%+ib3fYM-d}T#i@h_3IHlSccAyl;BzX=}GK>eL_tD?AimNkiA0HkO*K+w0{Kv|O}Fnk*q)rphn>X>$MfN`HLyv- zgkG<^V{X@bKkyH)e)X$9{QiG@-v>To?bO`ltRcee{Q@lM{o@!NP@wdZWH`*ZdV%UfD=nHnoFZ-$o1 z`UWlK4}b5E-uu@dedlk#^X6w=b8%sD<>LCjtLFFW{K3NqzIyM)uYT<_cYax0X_hoH zwMkl!YbRDHAquf9@-ld%ka8qO)U?{$=4;ct>J!cG>bdoWz7IuXYTjn;?!ptk7EFF|b!q)8U;g5BW15MF zgHe)ER;z1>o1K+sU4N5OdB=CYnEN8LjUtql3lazlq_tg2IvSi+6=qxQ`I%kjvJlG< zgJa`;NrsHE4ABtFDA7p0k$AP54AAl(&E5p3^Oge%w}(&$yZqJoGZpn#-slGjZ zxBJ!1Imh_@vGxhPzxT}_^+{EoPvS$odWJkR$DM-QC8_rIPzeY!ilm^Ql*HLAD1 zcJEbJHKwL#=Vxaw*tNmfcz9QBWLJ%I)-R}U{$;=a(+g|$Ix*7DWu?hohRg-0ks9Oz z_yC1KR)ow8CXeZ83!WzM*nzUv5p1yjN5NK}JRG+i@;0AP(oH5#2X z6Na@9ApkE(3j|}-E1V}_*O;0XKE1SZw6ol#REUu%64EN_VzyGWD#34w*A8#y%JbBv z?^sj2G*)$j)39_$v2=UCIPRc>v5$vhlZLRdknm0HX}_03ZYS~Tx$I`U}4;eXcXvy z_X`2|M}GGH=F|^63(sWBGuX^c3M$o>GZz`!6bI6+~OGcJ7f$wzl4hg1(DNK@}Tco7baNTDx12TqCh;siv% zXW|G55xo=vJc}>UxLzEJ%0l6!59BpOfWYEef=1=U2Vnvd2<0?A7xv%LdUtIjJX`VtvLj>%d zX9cR<@;TtLO$rbYQGpJnRSFS=3&@pViCiwB9Yhca+T4Ea`q4MN>dMeB{`xzQ-`VLW zY81rf!UT$-R1!0bC{zf@BCA5SvR$O`Tn|{9ctz4Y^IR0Z2xW2tmO5lWWTZd{3WXF9 z_z1Y7Bto%@6f=rggDm3mJVG0jBqSslKr-izCI{ex59J(L$_T_&e6b)rmreqVfB`~= z`Ih?T%onq6Nuw=;69>^XKj9Rj4E*>6tKZvmZky-4uB%1kPb-AWg-lre`+>n#3zlBi za;7}Enh^-F^tTR(RltBm!UC&H0Vx?vt9>cJ09(7-|H^7G4-eKdAOH*^AcTMb0oVa3 z00z=P1_Xc$AeJnLxCZ33ONR3J&UCZa@#AB*%X>y&$#j%4ha~e$mLr~HWoPtmQ8bAjCLJEADtmjEF3JWtJky3~#rJ6pJUUUt@ z3N-?F0VNs$5z$~wM9#Z`3mH+72$MpiLHm+w4oZP$0RvG@4QZ%&mVW4*OY^mM-S*nW z6UnBto#TNs0vlsgesF{pO_T?Tp`ui5F-EpAR*^&E!)4WpYcAig>1T$Mn=G#bNCCeI zC;q$j#E)l=&-E6hD5As!pFua39-M8 zQ#&?{jNekd^xxLr|BaK+7Rx5F0ac%&@4ZGwgN64jq7{2^h=z~_2vKto5m6W`3PHqk zP#S>BEJC5+(mdF$mu!0TO>WCj-j)2x+3usyQm<#@h(VZ3w-_R7)TFeqmrywI1(b1h z;y5r!z|zGog%r6s0rn6Iq<}=oUIK_{vJHr8oG(kUfaC{{1QCZ~wem(#G#JK_0t_g= zY-gzqYek2U3mK|zBkqO%5h%(5q7%YFlq=GJ4_w9tGJ(?Nc?pAdw(MgyDuoCV7*HXV zEW6b#FH!@waQQieX`tFD5ojfbN0kM0nH)=`6lxNsQI+YinzUAiL?b9`;@H}=os%DY z^$Ry&o#c-fvk!L~;8-t*hv za-F5dj(tU@f}+5J>`+6A(qjRw$fqGmXw#PD!0r2Idu@pe(LI1JazW4rC>S%w0x&qv zUFeMs4O<&^^A@5iHT-}Wg40$+z&TH`Qi_O#g!9l(U5B84;pXQJ)ki{_%`Yv^w-<8> z2GCNqQjL|?WK0M?%lbt~oy(XDB-CV^{nlqb`RRZ7*MIzlH~rk-{P{n1mX}AyMqgy5)O_tfOvFljSjxZTygV_&;R`2{hvL1cK-1n{?Yfp z_rrA?w@$2I(^>AN9j-N!II&Os=#d+)yXO7B`5S-yKR^0sfANV%G8XAb>sWGq?$p`! zW9w`6`a=)@Fbh2*#Sm6;5(DWH5tZ5_1Vl6@O5&ta_nmgvhkyc`w{2OsabvHS z?tl8J*{SJnYq8f^Nwd7$X$3Hq>d=neyX(V^`I*`O_2ECS*gJFT5c`ah3TgC3@I|hZSV`iuRUiK9oEiia zk|LeE?B=U)Zp4jm{^z%fT*gK#K^!UY!3l?Mx4nJSwptY5|K#1>te@zbFH0q$GQ=;6 zCXh_lKPQqQXk1Nr76Cw|wH5Fp5|}+QA_JiSD227^(8SvHlEcE%^v=eG>nDeQ{Pdmu zUj8fF-??Yo-hX)H3rl{!ULQHr4|C_gy>0W}YrEHP+p>AXp7lw^JaO-#k+oy{_Fewu z(~o@mum7aqF5dWtcQi&uo_hS5HR~qgYCJ!E7C@BJsFaB)PjhA!LMXDrg)9WOX5FT^ zn#|A4AxIP{?}{|f^TPFeskSU2KKR0=aTJR{yT1scb?7h69j~#O&d)?Jbou19Ym?3O z;i1{~)c&LQuk_{=X-cdZLfRH%Ws_=*>LJ?^M_w~=J2umr_L>P zn!&p$xN2>3%m(Y7I(1~_C9m8ZiF)?Hu~;qaxnPseok&oKIBd7QXS~0-@WdBSkBn_> zE9@yM6a@_cpd<1goaZb^nt3MB*61L)^Cnh`FgOsAGWZvnj4?!^*KfC*oy5vT8|&9S zuW{j~TFuh&nfB-Y?a*V-Odp$XuJ}F@Cnkw8iYTh+L_AtBE)*enFFE_75f8d-aelN6CmAfvfzvdu9<3# zmR-@6UMfx?uB-YGjf~)M!bSn6P~@B;NJLr#WD+8*4BJZ6_0OlBAP}pnHdq9ghhFe` z3})YW_4;ckE__vE^kQvd3kKW?={@aQcLqK#NhfO9DA{T3km|1lVM*4ID3JnCP*+IT z5S5TZv_ytD7q&=iDZX4`51U^u!cnd&8;vTl5c&d&)mlXr0uN9@000NlD_xSPXc*ZtBxPCzz-d^yr*;1Bx%mVA*16Dan;zOCi86#-z*-CBdfh%UYD1!=C~}8I zE}g(4M4~8YpB8CDB~ev#E6$w1P~cT0XH;e0$vaq3KZwdoj_SjqR^e4UQ zU^Kj1xvt8ESG!gX90PO&36w4y_0>Lkz}qNWQ$!MG!~xZ+%<~z1U8VoGY)Xa8e*jB2 zER?X&fjAl1BM}VDO9fy7NWcI(0@9!&U;<(g#~d((lSik6rmc!vD=U(-wh?QBj3J~T z1q6XX-cR|-8IZte)KM9`1U{4$J}3eh56U8h?)inKrS!tFdVOPK76?0C)Ry~2Wykt> z!w5m>$xSxCDuT9JYQ0w@L_z~vwTc(AhuFQ7D_2Bko22!TE8p<(DQ^d5L9JNE)p z-?0DFcbv!UieJ6u@_oZw5?*E?1?z7dn|#6Z=bzcz`pzNu3~QrVDkKB~uSx{|rH6MD1ROv>5%%EsM|i>Ev1`XM!vfRI6}!4gx9WH64Y5>p}q z#udA5 zmy5zPkq^Luy&{WbP<#j=2!R8EA~Z+}5S4gjTz$6&c7cl|xp1$!Vj`)!?jwHT;ln(0 zCenzgAb3UOMc4}}qe-I_0)XO0JOD^wB2fyNOE?oF$^aAx0t5qD0RjL4#7ILRIkmO;!+Sx^!x3s6?x7Q`cvaG6yj;#1TGk^+hV7=o99TA_@cCE)-Ft0w>g z84w(pF$Dn1OkY41$v`E-2q;X52pA-IB0?kyL`pMrxsUQ+c-}iaxjuq)vkDQr6BFfn4 zzaPEpTVML-+urxi!%rT*=X;M04Ufe(IdkGvx7!>YnRx7;r$71O&;QO}y#H_i^)vN% zR=@O}FX>1{Ixbux2(4l!3%&7p)7r-7zVEJd7gA0&DvdU98M%ofp%gW(9`vP6R|s^e zKq<4c0fPvoMK|Scx%nU55g-B-xGa`1gdoCNM*+n79)KDi+RzwYqcyghQ{D7zp0z>5 z7)wfJX@`J5^4q`jp%4F7-b>&1=3hH?dTRUj3zE3zGN&V|RBKr`J^1KDuXyz<-ur>~ z{r>O#!KXj_*R^;!vN1ANO(W~{Hf-KHHac?m!*{M^ONxkB5ooLT=X2(oa;Rb}wGl++ z@}dNgwVKWSPdp(a!=od^jiEzNA6!{k$b)l50T6uJS2`LV9iJFq7u#B6XefBsZFgs< z7N^dfIeq%f4L85AQB#MXIYt-jD6&N>WF${Ka&&Cn$n#%%%Z`ipJ$CN{owV8O6-A2G zHEV_@*E$zb+~@}qP(DjVGV)m{($@T${_<%l+HquEUqTqxm2J_`=4^R}2;=(N5ZwI2 z%>2UqhHrl5KkodmdmsJ|*|P0-z+pgc9GKq`$O5#VeBjZE&M7yy9WWji)*yK3Lnk38~lbE!KvG|}sKjn#lcfXmCxHRB^YH*IJv+m=WJ|ZjP>4gU`8o|Lji6bPL zojTiW&quztt~PYCeK^C+sOZs?kNozFKXlVC-tf2I`SO{SqeW%qeE*rHm6_wG9^1HS z`{v25H(dSvm%jdmd4Ml{;a|RW`)5K%k|_Obic? zuN%^Uc`w%*RL$=F$oTxJ=7AraZH#P^L}fjQM#+=(R~Tag!7K}mAPgb%$YLWZ3h{-n z)uM=0(E;Y*f?H}X7e%^$t-9&?V^>{OpQyx(%kI9%jz4nZ?Ea~#X4?f2t4+l=Vr3N* zf>vU{DP+l=Q=k%xmi%%D+JGfwB^b~Zv8rI@siA5XOeaetp_gpljln&=csdoM2r5w7 zUR$F;FSq+9R3}XwFc<*GzTz1)mCzL9&M!q<5dwU9663ov0G42vt-Kg^1t; zJjfDACK!nfF>C?YLb4UHfl>vDfd~{3ACQ$Nd;P=x`FrM9PIfyBp$9rQiI0;U$Rl~> z4JywCgA)=j!Ha~vDB};?zN^VrwD!eCYlTt3*)&g=bbs1mYnOsJ!ekK}y&!2n#qsX5g+A7Of_z1peLE z{>s{oqrdTwe}1mLQlW}qfPp@=;5*YfQdy6!L4$D!+=~VOn@G| z0#S$qkt-mJpnw7eL>iT6aO_LdrWYr`8k7JULQO;{!d^Hql2QOHv6eM8wPT`Ex7=#> zTV3uKg#s{&03`3U^E9ngY@*@H)5kwRqb1Hl0Id4fFd!hH24U0&k=U0AZ3d#jPIaJEEML!3Eewb(Km%42BCvqa05)7A zkJuq80TS=Q2xtwV^fQw$80$mxk39D2zxmF#Yc4-}$3x({5-ZRIiogX(R{(NQ8nhj# z6U&&4A{7xJ1)u;3G=VUPlQJS*Ntj!1wo?Q3#$*CD1Kk2$2MFpHPpAp%gY?d|+>x^c z9;}f(lq*)`0>nx1ATmh*DG5(vK}=bXfnp#} zY#^#40&p{5ra(igQKwNYeGQ~AN_52+0!WcHR#!0B#^ENhH*Q;d@$)xK++3#%FifyI zrB?3rkAH9OndANQS=Lj9vz`?8Tpw8&^8#HK@=Usn1(Nq6XfPEu+-OwKwa-uYyRoX& zbsQjLv8#*vQUxH25QKZ&!y;H~Y@~<>51|tgED)nqQUkG|L>v`RM3~1Eqor=(M~^ob zK9^r|=h!8$86W$3MSEmybLF}#HgEs;(TDzZ<)N9@iV>sYOo9jJDdfQk1%=v(%h`Jg zP_A5Xz+MJr9b-Ti1&VwxZ{z4hzcF-fRz^@~kDdxAPS!|JMIuN<1_8Llml26@D4@uY zgHjkmQ4U{l&~vhg5J{Pg3Mhl1V-5sLRD^02RUEPz@Uy7OC_eyk2r!_f6GEBVj2h8^ z7^DcGC}VFVFbwGE4BVD{2DpIGg;G3T8s!N9LkWWeL=Y;|eIy8y0zzaKRKNm6Kn8_G zfT%Pnmb1egh@k|BE2C75;01mn&_L7xsE9&fAX21&kw|IO0EnP8XeHVztH}r(BBhj3 zI}ykxq~<^U)xW=H%f6ZUsrRgX z%Wu5u`A;04-LPxZikGQguW&5h0l3M@Ei*@+eEfl97w+41!}Bj18>@cpE06r{Z~o24 z|Ki<0_~tv_^V@gdfByr?mVK%|4n8m|E*IJ&h~$d?*oH(AJ$veSCYj;+;JQdX_OTCr z0M1<+Fh}b#ax1O&t_v?7jmKu?+yD*^Wv?DQXXI4{;%P(W{c3p+qX0y4Rp|r}oiAaJ zgb1;$O@y&}e;4eQaT7d1<-TFS6cZZ_D;M>le?T@L4aaH*{n|9@sl$j5fv<1IXfF zT8$Jq4A<(<+jr&u0|%cyd}{0F9nRBAa_>w7Ou+p6R*M&rBUMWRXaMUrkU5 ziYnUFz3&F!hE=q~z&Jnn80Q^oWff@wlHjl`tt51NE#J9s-s5KDecB!Aqj}61vD{g%6#p|!Q^U=E= zI(pan=3D?!)+Ci-<|4~G21Z_X!Oy+r*4JOQ;UbeYe(=4=?|J5-ljr8NuQlS~iHVV- zU|UyNp0Vpi!?A}xXiRK1!sxF5I<@P9kr!V-xp<~^^x5S#>qbc{lc4hjr(}oq4WHP0 z`gI59&#nyNI3jtEVo(HJ0l60>r4{5^5CBrFm0~XE&~a9WQ~EH#(}TdOeC=0T7fTU7(=ZRWl8R5Fm|37ZCb> z1y~Bms*uDIrJ z5P|}PHl$zAPu<>Hezqv)`qeH}`f8mWPHMC$MVdPy<^XB#$dWd?$g?681>~%_@VRGi zGzCaK3QM8cabEPeFGv~tEJw#|O{55%D*_Y<0>FY0*m)O7GlM*G`uNocc2pRulrI5h z=p8sf!-6Fu9)ukP1zI5huoI5}0)YTL6oSYoj5dReoZffMp7md!IMJH5s0|E;;6lrwgtD@gneaS_5;b#}W z{@wK66kMcYB9tHuOhAJbA2J9KqJvPHY6FNuU4|b37+<;(K^VM7-Iw;-kiKQZ_BUL# z>zUU4Q{9Crri!X*03LK}Du^I}A`}3>8tqax@g=rkWr}f zP(bMeg@Ii7ryEjPUAe+ffDzAmS$|S0ih!183S$?;^KXUXlstPU%s(TL11cm$Db>FS zD8e~vTV{s>DJWBx%9>pSf&(Jqa_1lekuhkHQs$#p2h{-rh*E=kfZZTFz~_PlX#mth z6ud`5FdDl{cmLJj&`?!UL8%1R;7jR{hNuQvfKFR9fvKReLWmLoSlEH!U~MY`ia={{ zPK1;Zo?Tp7>^Xq?WEE<$#qUz zJY2uK{)$^F`@T5#;CGiF@2#i`A=YvRjfLYJFh?{@dFj&9grrnp1^`m3G)V}C+~v+B z_KHi2onu8ebdR+2N1svM6`Mq%jEzPhM8%|tgoTTYrHA5ikftlZUVsHyLKwKqnag*r zh_L5!fyoY)Y3OJoaLU;E&rSF=guDLuXDOTjJQJ z-88A2d@<|$?!GH8yzv#6Nr2{D`+|$MzVm$}-}~yLZ+*)rKJ(YV@gM*6hEIOx;XnWD z`=GM6v1?b+CkO!uff)?}`?0ZlvBW2rru)#YdBfcEE)AxNp$`E4v{(2dNbnq%yGu8{ z@aiW|zVO7ip7kMUA_gdYAd)=qqJkB-ve=s4v-PrT_PuyyWOV=jN6w$0>UEX_^-*QO zp_k7+b@*YY zg|#RuIgEk|2#8sjL%Ai^WA!z|^+}!Rc4xNTo$9AekwBy(TPH2OZadM*2R`(HU;n@d zs$nM#CY1zioDpl_oB7yHZ_-;!MkR&y}Z;!luD%{q*YvPck;8;P*+lltsq>pQt-o;J)?)|G`aai(D$S+EPL}#UqvVxgwLEil=FAx< zj7n(}MMISZQ%S2$716GD!}iBP&82oQS8= zeab;th)|IV3<9EUEflRo58ipv&97cK{_xV-BND0z3Q)Kxm{d7z`Y8yxlrP_&Ejzp2 z&Y?p`q=@p|4K+q5N8Qr$Y$$@u^DFjV6^iuXBM-XZVimjK0gwm+djxH5BZRCdR#qF- za)?kuo}jGKnF}YZR7|8m24M#hymPq=eFRxMvfV_f2hGEyBlj-;kiTtz z|E2G{W#cu^p4;-;SKqcUH1+u}{nJAy@2U^irsmFk^pF2%>KDB)F4%I-jo05YeRe+0 z-L4CEEYG#tt&YoOc#Y|IvAxo()}r8jyV*C^AYhgjN>P?|t+u^hii9SjPPa#@9~ql> zT#*+>18I$cy)R;$03_`+1rE1e`U}@waMOV^hramWUmlx!27s-tTZ$Qc+Fu%iu~%RI ztH1b~H(tJG?`SrB{NTBV4(`9_@h9gKzh!dwupSB>4lc0ocNaU9Kxa8ibJy6qK3#Dr zGP$lk+bX{PFNZGKJAU~UTkiYrljl#(Z`d}XBJG*;UQa2%Idbw?AqU`OMMYu0VsS*@A)^tslz?tJwAgJ+JP z@AeBJR7AFFN!Sx>&E&G6A&!)l04@Z_1v1t3&}dRiU28G#u>_6aBzKS{SevjDIlGSU zAWG_T78o*(0P=YAJOV}<6OXrS-1YoT>kmvVAMek%u|P4tD1taIfkDS$B2)%6iME_n zp)pjcRI1u}UPxO_mnw|MOd?cdA?@WW0kR2*cVD{xqF0P=y16>Br53lrAAyyBFN(v# zPJwNS28zcFX%rBS5o;tyLdvQF7@&L9=gTm(*F+PL3v((aQB*-OKve*M&|;T)s!+T| z(^}vRbcCux(t*$s^nexs(a(96fYboT1vU{}Ml^|1N2!znP=o;RL|FJvd+MINbpW#^ zV2CroOs88mHAZS?W_}@Hkt&`ky4|3ILSKLjK~(4$y>@6T!88<>OwJ*f44^>5X6Pvp zqbP&mBm+P~4HCL8Ge`^$fjxWSGJupr@PziqOH1}Yz6ZWnNH>Sz0+fA%2ex2HsB~A9 z!7~8D5Xv6F4~%}0N>`o+qy<74EQ!33Fb6;c3XBp;kuWeJ0HB8e zh)djB@vR63V`)PVyakPw#5YNAidN)}P(7?co!rK6CEbqd7EmL!ivP zU_w>$1`*3U1qd)e7$7{#ZF0FB7&t7Q7to{?QD9&x1&LC|_83$IA|VihB_se6R)CR4 zWbF1`vr{Bh2;M8=N}|%`j>Y2I7i_=g^|x%keB0cE2j|XwXQks~qYDlZ0t<@*CqP6> zn*bQN+)xUD5R#W5A__=A3V^;ZmYU06!YcTPg!wr^uYeG$*u)^1hXR1hx>Q#4&Hw*4 ztAlR$Cq4Xg2nl&kMyz4_d$6(wiW_0`RdCzQxO7Y&{VGf!5GfEnq5)@oU46C+W9DGLs!~+3@F0d(Cpg<(7kPEU}(l$)Z zP?ShK%7p=DPymQHwqB241x3#k#l4eWk3Qjf&{Pv&E@6!UKgM- zme{e#vFCoOF1%!9^Qe;0&Q*TsJha--sEH`R0KniKumfN~77hS@Fx~+Kb^s2*fkG$DK2y2n^61jt$xh4bm7f^n zon!K{o#Ek|{Oym(Gl!wQEFu&qq)bUnMUMa;jUqoVY_p&yQb^3@{wn~o0s-KXhXaTr zq>wdH5CBjbH4Ng(wFRRp#9@;b6aKDscs?UC@9^us}rs1+XW@Od&7?1Qvya2FPL7&K>O7WpCXLTeLpO zeDIW6oHkk^Xe`?`B<6sq6d{Ko?4ZneVML%%io1mc7^rlpmoAC2GZYaaDdi`1vTFp$ z=Zh%aK_rI&4v61GN&zZiK_USV1~jo!2@9jBQjr1_AmpWb10;vA0>JQ`T|^X+0(PY_ zp=8GmkO8F1H7rV*e)k-Z2~h}90Y;>UtgQ(bMb09O6p(bO!x)?aK(KmJ3lM=pO{K#_ zp&snIgaAmP(aL}*K+@V86$Ma8cBR>T@fEvwzqIDh^4!5*oJ4ja-hW`)L!~lW|HNnC z`{1=dSX`M=7oix4r+xqu&^Q7L^jT|&fuZ}5D=|wFJJV9 zde7T_|B8LreCr!uyW@dx`o14uyN;D>Hs`$0m9orvt8=atk|3DKHi&E##R^N@KoAJd zxey8w5pY&%8=EiO{ts9E&9$$4*K6MVwx9p>-+pPS)tac)tBuO!$OxxCqRQ!KkN@ch z{^ISw`z!DI;M*>|WY>(&gUyZqckJBaO=V=+I=Eby}U} zPPXE~Yf*%xKs^_k3qk+^2+H3E@q|WE5P>qS6o5SYAcDXc08qsyuEy2K#(>alPo*n! zS>6=zS{X%EL`<_5fV}Yf8~@~!AHVK-&%5(`cYomv|Gc==o*dsYIy&qXr_D@x6wk+> zJ*c$$>%aT#YDbo4t;1)x z?A@I8U9Y`dsm0bR-|u^uE3k`;EmMi&`mm0z18X8390aXZkml_1m6`M1#VJFe2t5e| z?|pFW$rxY^MS&zJ0}&J=GnMafTHQ;KO~%eX^@AIK<_+ui-mrM)D7&0=RT*OMd{Jm? zkc_Z@uDxer1Ufr2KRwe-Dm64}Zgv`lCdbxlfpb%5H*elnPvXa(y{}dDA{}|=AZ0ci z1CovEfL!Elk$|Nnc-6`Tt2(;DARbvb7l}|2fJpGc70gT&*DE8HWO%B1ex=tO8XhO5 za?VYH)lu_g>)@B~zxTBl+&nCe6W^b|{8fAY@Yg>4yPqhYoPS`$*7fVRY&dy_n=4C~ zU3kT=y*r(TPDr_T(J4+YAz)VJH2)=5;Atlwu3s$#13WN|U`9tcU0Y#gCd ziqIGoK<`~(00lvqT`=09(s}9%pKhvdy!HCmjIJH~uOEH$;JLed#j-NhSXlw+XEQO3 z{_;(4eap|j>C)Yo)>rBW?l|%6ku!0nzHf4;xv2I;_n4~bNGEB?(mXd7(`LWh>X?dT z-9?v1){eQXlg;3ivGH?%wB>K# zbG+^@)U}$AA!Oh@qJ>Zh5?Z4`L8p_qI_*3!)(oqcTs?m6&5d=VwdvXZ1CJkl?3wdV zpPpY?>II-mWoRs_HliAOUhK{bV`2<=0YI&^7IN$|UsSNNd1Rvzy_793`h|=;0i8i4 z3`XpxXmcZ}o#{+xk`a0cs%mT1$fjwkKwE9J$7{#8-gf2s^NZ<^XJ;3K*VX_t$iN#H zLtIr6085ZMRyWqihfLK0Eats#miZ7gB}|;=?Eu{kM(@3HV)u*c8*i+QUr>vO2+qLb z_tNus<>8<8&ylb?!3< zX+URDXOfQTj`MD3PE3a+Y(pal3iaDYI-M4Es_H~^Q*NCZStBE@C0;VN|n!_b%dcRwqKV`UW) z$a5s5GGIo$1cN%#hM9Bk0Q65E223zyl*u3fXYzzI)5&cV4#l!IS4ddHnDp z;fNA|0R{wDU3iKJWUxwI-SA<#+8scMup|P*wEe;RSSWV6~l_$~?B0?gv zh$%ziQ4m7#x%VyvK_V(8g=IQG+05%s*8R>?-}NjCEJFY(i7u<(5<(E4xl{xK6tG%E z{#4c~uKI*=P$iU|?@#8%1Bnw10xCcwEJA-po;?NUz7Nwcl^vJS))(;dBJ^hjG5`-H zd|4S3X79xZ02H-aP_h#uvK0^(8JJ)P(*a;a0|RzcfRZ^}W+9ZmHBu5hAb@y~GH(`u z46qsuZf$}?68U})D2SpB6 zgCbxL$dI->GtEv0wKZ`(SuK1K07fp~THRO|kn~*Po<5630ntzyzylIM3J3*InVb}m z`KQ`%0um4ytbYYjYv?VxBj8iNGKm7E)g6Cbe$?4 zF@5MntQ8TW76~lkMKqz4f=~=aft@EP<1`$Hm^3oBv0JAhG^S8`r3oh=%1@naUvm5K=sog(LY zExCRVZ>*`9^?b*lIAim^P2z$<*lSH3LTN0P5KtUR5MiK_h6e-)q?rpSTg|~h0!#BU zfDi(B=733MQrY2NdRp8ZkOPp_>aJ96kO-B*Hs#(3NC_)Z8cDzh#1ddOQ1bzYvfnM` z$EA?CY?8~&iE>^rP!S7*5J(WE5I~q$3E`zhB>-Bb8^(?+UE$D0ObG&W#)1SC#KS-= z1R{i}2niSk2t~snfep(D001Z**Ah^ZQlODZSScNm=RBYPrC+=a63Gs^#j~9an@3Kj z{nN`QD>nYxzkKJ4tKaebt8e}8-QV=m>KDx*>4vdwOUrZb{_+Pu<^SweuX!1N_mLkw zeZ==gJa6Arz2xEzS-a=Fudl6lm)(DV_0h4h>TN%F)ySIY&;Rl}-@AR?$3FJDd%p5Z zzy4?U-u^F7*ew_8iHXqd2DVU0oW!k`?}lZ7uFq4{g#ypsf#isoXT8Gr9ptQBtJnP0 zXFs#pnQV{x=`ryJOc?FT3QO%{Tq? z*S_9b?CiZ@i_PL=N6s$HEN|SfF>m%i{|A3JbLzI&yzADTU;l^Ced6<<{hQA&<+J0X z45E5(Jb0Shx^M z{)86+Q4|?vtcoKW+gJ;P!uMMJ+1#yUt_$F_GI2DF1f6aRKsK-6_@R${-pYZbZ7ojZMc>fE`L$B!Cis+F2eqNrMLE_Rng2S6ECCowUAT2+xjC|VxV6$dckC1g z9ACF751rZb)BRot$OjiXOI|0FqRHn0k*yVSzJ2b1_ZB!~$wdMpu=ngekOX!D%)(R_ z5F7#rBr2mIgaayrffAp1Qv?d)!i$tfk<6mMPTAS`JxRggi&l zm|317u$$NH8m=~$XIG}Dr)zPg5e<(w(lsNK$Im}|dgZJpXZ;dP^4@1p~%#hTPwNGtM!_Vw96fW0+UvUV(0Vw zryssxc*hH_+;R6qvw#1oJ74vh>)-L}cmMuBoLp+pym05uoow;+@#EWfUF3q#+5vLg zSfjV?-qJ~zP1j7FS%_+pwYIg?V&TSEJ&r0`D+s8yvDW5U5k)q5VJ|i|!G}C^C1H(7 z5u?jPzu&KN^^(n(Uw`HGGxKv_zw__T%^dUTqh}?85xeSgpI%RI$_(>?}@oWl4f~ zscyP%&r5E)=%P#4u31;#zVX7J9>+v$s{oL9(_XW8(VN!1=1BU_e|~zB_Mowu7X(C& zN@;e!-Ru|8O``njeT~a5sqWd`;1r%Ze)3EI@xw<>&77O$SXCKTD$Dy9HMZQcW6QB~{qLMSbJq6)YAYCoy@)|=01%LwE$N|3ZPYX@ z+NC^ghrAmKMi$C**R23vw6%7{%h&9FWwPdqimek&!TgVUryeZ)0jc>cAC|3J{P6gwxQ!r+fC^rRn{7|0H3zUO*h8Na{!i3l6?0 zOeNwhInbQmHmVxq8hQ)s);9LJXzEaNF;9W4AQeUGq?<$Lz$XwhC<3V) zL+D-T33>qC=YB$QY%Plqka@@hd)TGB8Yv z2qOTI^6U`Bit8ym&7j%SnC^VfPDg#oKFdILrPM>A&rl;|;Vise+5Zf&dCo zgv%wc2R5K^u(m1!Fo9J_K>|U!789T{fK3(Xm219fV)9*AUozk8eD>twrzKQ%4LJA^ zN+n}SO+`Q!Kw$=9@Cc$nm2e=2!TJ z9()K{;KCJNm`fa#FbWB9d9!=*8kIr{;`^acpb%9V3%^QE5{6JBc{5H|yYLe8yShOA zse4wQ`-4@H@ah^CpVK>)*Na}A?PSntFwS$APiLp!8CskTTanDY{i8+j|5CStG1A9OZmF5&fegkBkU+ngJ^3g+wO{?$n*54O?X_2# z8~4O}qx_<}-%vN#Zh@26`R|_&cib1wJuN<^C?V8@D9nhUlp;h9pmETM5}`)L>`Mb8 zfg(X71koU5Ng-nC9oMKWSNQ_0R(1>UPV<57a5G#cdf!1VVj4G1olpDUd zc+2p(N(Bzg z5*)Z7f*?o)N+C#rg$8us9DpXBgKHLji&cfSQ~_GMf8I_1$I_W6`d7bhbo9MOw#e`n zd-Y|bTkohH`spMe2Cx8!3 znbt}~5r`%Ts5C$+AR)&;X+cXgx3DJwLM*JKEy z%PJnQ3_vcY*#Qv;Or}*W3kU&OMCFT2*lTUPw*U?YGCx{v4G@tKwL;B;NEQT1i-f^A z69hCWO{T=c5fYU5j+y#nQ+SojP{rJ#YU* z?`2|ST`P0_mgKIz)J-RbxB1S}2fq57ADlh=v#7V=TmHU754<0V2ifHe8 zCIu4WSobm)LKmRNOb9{P2j@yfRNx|Yo!sT1d?9l3{F%A#lxHB)3Q?oBhWee>o^99t z(MSIHvMVnB-=Fx{5AVBsXmrBFc5&%kmURS*(gz}-m5LO_aWpbIu^yPxe%FUAI0p~_ zLtqy|DA(eo2obywfjEwa_O~AU%g=oJkIf(6^x{hsuKfGgzT2JdSG?`76hx>aJ3Knv zTwMCMPkrs_hxWhcf4<}6pa1Ahx7_eopZxTlkKAsJ9g0UHg-)E4BKJ%E_EM)eopgsQ zcC2a}8`o?Tklg2amgYrTILE7(g_E#qK!`2H9(==0)Z!X~Qbr3PaL9eHlPza%#f7ft z6alS{lx~Q)Zodft>n7H{>%H%O+gsk8M9DvW@ymC7`}R(&H?elh=-5QBpEf&9Ql^qr z=H}1MoImrkufOdBANn76+QHrJ?V9P?g|nx7 z>(-6eD)n}|H8MJ?l|uH`U~Q<{T<$T2Zma9MzB*iQjEz-?tJmFd?GNv`_xh0>_&BYBs=XPos~Aig?86dRZI zeO3S$EI|{Pp^DK%y@ehEqX-8_gs9LnQ|S^79D+j>6lNEgJ(3z^5-LNeyk{GY9r^KH zm%i+^8~0szX!;oY+}0`qfS9664bTRcvCGT)V&EA=U@qpD&(+q~hDS!07nkQ}7e;C$ z7w@@ZYWc+B=>voWfT2vDKn512V^Z1`y%5qeml5E(L+v?SN2#e302cPu>bgo&UtXR= z&jO&7sm2XOHZM}=eWa3VwL*kG2U1EY6;wermC5qK_VJ77w{EYkpE}q6(OqXQxN6NU zTVHkO*?)cD?)y4LYh+|?JW|UF27t-*pO{x`k$wHw@;hyL;D)AzS}E6~s*^+siQZM{3+nP2ehw~bw#Z(W(` zax>K8inXz`MO0OedsA~KJ9*QX+UT~OFMHJuJ2tH!**qpLWS#CEfAeGKx@k9cY3_Q? z4&(4xednGHyDnZ=-LMt_p8t`}rw^XEvhfY3ove_yep*B&iP9`yN9BZGlh*GF)+ODrRmaC)9c258_DMa?nnxk#? z&09w%m%Hs_&FOAvMFu0b0)>cnTx_>HFRJf8)jvO1%;!{~a9s~2Iz~?l;)E&|WUSiQ z)>!k*Oy_~Q^C$9F6xm2nF<3DotWZVP?b+0i)2Tz<_PM;j7#zf`YPMQ27J>@xekKB1izuaxAXb+9>PWkF_2?)CuGe7a zy2|)7^QS`&n6OAUq(%jxfXsq<5sF-Th4dK-6p-iTVr5}^zT<;JB+Z2j1%r2ekdSf@ z0TqED`;Y@jU`BMHJ$s*l*a|-Xvc2Lu)2AO=1n(qR&=wUEcl~l2d`~(F#2R%O`oJZj z1K0x-DHiX50U#R)OO~PFV&zrqFI+RU{oALWI-hrlO2RORFrgwq1&T{3>%alY z0)v!323Dek(^tYp|D*QyUGa{uwEq5}oQzeZK?#PkreOdagmZvGrHKg1b11|KG7ict z0UUrkO8uWEl|c@!`TFt64_$lpY_s=~M<2brmnEt`sIEbkvpgE`ZGpu>i2{OwOOpni zT0x)^!o&awQrcC#6dXK28G9*%3Jj&Jp9l#7guOCk6&ez2lp%2FW2>A?b?ChOWqV%s z)|b>tp7_RH=MPLT&UAO~+jPP9OEzy`YaW|-We^T&ue2|U+`GUfn}8G{voK-+Mj@a9 zY7+;wAQ>?T#4t#~c&-dpK!gfJc(7T;=UUNnUHe?iia(h}uI9}QwyUI2v9QQ{`srD+8e0jJV!NpA{t zf~EpWiD%FjO%=Qs@xTJ$ffyu!cLT#F_}<)dr<;wASL4wd1P2=?>RZNR3_VfBfwQpK zhDIF%Kq#B5vg3VD^yJG_Ob`Je@x>sdr+ma53r2ua%rBdzZC0Ap}?6pI*o?J#vRoI9Q0_ha+Dy>!DB^rFkvz6NhIvUUG(-w4urd&lC}ymvI0~wgg}uYIt6#l&X@F2jAy~SiLC||C9A^#-L?j^3!GcXxEwFE;9Vb3Q3m}C!LPH9@ z^TY-$f&fG~n1nGVwvte-8@fUAqF_QoG=K#&hIw}v(v~L zIZ>cRb6jty{H}3msa<15-(XT33nyN*MtkeA&;VM$pDO*W+@S!{ytO zMMRMzGR(d-Wr=WU3oPSG*?Xmj)@*nlsoLDxCn0pjl&br(2`wcQ0$@-Xk#aqO0EAq! zo-zQBG@ue924M#xKrzq=QWZi+cnL6+@B&Z@qzpYS(cCP8NNUj2vH+IW3_&E2QfUAv z%&zYwAeY2rFXE9%zz=9_2*QGhrR0Z2X`2{|*!vK?Dht+CBP*d&N-NU9fJi`y0L;?v zExzSVuQEfB-S4LkwzqB>pHJP7Pai8dSJa0}dg$cI$SS3MfZS4CNH5L1bL_TMFY?^` zgL^)HWNGSszx1B>zVp^+jvc%3!Zixnxx6|&v~<4z*n`K@OrplnqmQ0{%P;-!-}v=k z{EI*Tg@69anzz6AlP|h%-^V`j_M5L<|Hj{c5_xgxqdItiqL1yyw4nGNZv#$G6@Gs(|(b40N~;a zE_>@Qzx8!L_v&gT`Sy3d{a^q2-I?jdv7yQBJ2nBRUcc=EN0HT9A3OYXtsZ~kFaGp- z*IxbSfA-1GeD*WVW@n-?$srJ02_Py|Y7q-h&z|Y^TLTsSbGy~&#=on9Z31L$WOO2; z^4uw7wKa(30^8Ui>1ws16)nxpojrAUd}7ni?R%P?`D(+|hS$`G>RY$%c=pgU=gyz4 zCiO;bD5)6|KRQ~8Yqj=r?loV0^&S#^;?T*nW9P5G@rHl@*MEBaq3_*y?|-jZx8c@X zU-vVwd3Cp+FU&0G{d{3|#koRP5Hz%AI-XrptyXIB%&E+?VgVL5Qoe9x$VAq=z^+gVB!u9c4-R}mnt)kInK)6(azLHLf*Q3Ad5+q0YxexpKlDWa zRSCZD`vy_0=8*RQc_1zxoIK@=h#INynzJkCH;rtsCAF2-^7!cbg0rKu2eObEGQPa} z0R9eJABT~r4^-wjH)H|G|QA#ain|^qB!<0 zxL!aYkPsVN6n<%CX~X!&Yp;4y=!OHQ_McpQdMRD7#*Gb6INxh`mjUcMU-=uq_Kvq) z)YyCI2ge@x{^8as8H&d?PSz`xsJ)!dpKlrk&6N%jj*V6?+r8!Z+4fVu#K*}c4X&b|x*@^@lyGo`=L#mf$9E2?`pK2qbN$&g z6fs2rUZW}krtCJGt=ErSvYfR}_h&Q60Ws0_NRr^dpf+TE2q8$LYEE`mPPUgkdZl3*7cjZ)YZPNt^7^~PA zV*ykTg7Xu#jFWY^= z3$D2I{)Lm@?za&w0tXICFylNGt{ddg&sh;^FCM52wF-lo6f!eAC zc|(2I|GMQ3-*{?&*L6GuBS3_Kxl~>IP>O8DOQ1n(!A`sovp^8=lI?<#H>j8IQrmCu z-t%4es7I_2aR}^XHPy51&PrWJ>1AavJ{MOiSDiQlrH}$JiwJ=tbdo9GytOv`kxQR< zvfclk$L_zcmsx5Uq;fe~dL+GgB?F6)h(?6%ikar3Xev^X*Ioxi`U=%jIDIAr2_ zj!=(|k626XAgIU%?iVgCeBqfzsa2k?Ryvd_S_I}n$W6IQ^%4ft0TC+O%kuOGNOYvg zrbQOO5ojzeyQOmk2N|kAS+NdIds3(vSfot1MfrbT%K)GO$}LJ+K^h<{5I_nnX8q|q zK#zfmdE0yNCC|rWPwU-~d1Xezj@WU=5ZOnW6_qAtQJ%q(H~0j1&bh zLkK`T2zx^yjbVPJ-%Vqv#=|k_iru|AUN>R@(rH&bbq;+2aYI4|;z0^1r(tA(w19`A z58?)GwhW-nFj!JCKmbFS#9?-R@#yr$&)?z!9=!cT_UMy(d^m6}fk6O_h%Z0@YIRJk zr^%w;;mRgg_Oc*AMLi`T@8rqOi>F z6iqsy&!t2zu}23W3KRkmqJgR=oB1^7LI4bvakoGUl@=8gcqJJ^03=WZiNPKz03BnE zRyFi8FjiVX#~_AGnThPVs8)tYDkIaa^M%WZfYA#H3JahI(Asny21BB2d7(PFTe-7& z{!n(s{X?7IP?Kv#T}hiZ)rN10_I$Db$Tt>_Hl2!WB}!6oeJY3o6J}DNjmGwEg-gd$ zk>nYc{pam+x1#ExgvFJ*JEcqzkD!t$CJlYy%=OBJy&5cA1AtbbiHOBJUk-N$ZyG{k zL9H81rkzd|ZiSR8^(j(@Qk9uULP(m(2(ScS!dXiM7g8BU!KEHspmfO^z=pCLQ8hv_ zE3OODAC&RsoRX;QiU&uG005y`a=!NWCm84opCbHf#qRw6SRPWHP+U0x3FZtrr|8nZH=RWf855M+T zUexXO+RNRz5k>WQ`E+-BrklGWsU#B<>z+Dz^fx~Isn@;nmiK(%RXcYM|N8HJ@$ReN z^|8)(Fq=|B720a@5TJbL4@W6uu2gOnx$5b=VDXq*q;7ba3g7J~P~6JzaS z5f{s!leR)PTz~6t{l@S2+MSR6)gL|a_(R?lh0prEZje3zMz*0%)z}IMXk{hD*49PP zm{^f#VWp6?_}notmS%-jdodyrDFF;17At+#`rCWHaAEbLO}M4HedJf({pzp$bLH+w zen6weP-UoB^jB6^)~%nI*tqw^v&X*hC;#~H4uRW+;RI4?)?6#GiPhH(d}CU}tS@&t!;?Z(Y7yZ*K<+jrjo zgL@a2m)C5VaCw-WTM8_D_U$!Mbok(t%tb$ol_F*A+9*nDdfVdLxC^A7p2(FZi@anF+tR{Gn{D6az90&p- zsAhY?dtx65tWwrSiFi?{lr`EIBJw$FZAmK#fK-xOLQ?mIZa%g0tm%bohPGUO;l%gv z=*w8-E(_go`HOd~-+gZGg3epk38|n(jzCP4mOvY3?LBKU@XCE#WWNo2~~}@ zMyY<@Z=dPSoL)Ne$OCuXdH<`w`-*pc>OJrI#O_bNYk!UOC6|uwx-gCsm~StB?VkPj zJ$v@>`ISzl3?@VMjpMqaH5Elab9oXcHCtnGVnI9!Qxewm-CY=Ss#KGDmY*EEd{hGO7`v)|u0jZc6j%gAlW1Kwv4~hs`juiIQ+nNtw!QfMFQ0$>^nd^L zw{;Y4TszV2dSx+i!4T|l%@|!cAw{Y4T^C#sM50xRFO>j!1}PWf1Eek^Q4lVvOEfTy zJ?BjY0;NC!aDV^3#&YMuQ2Z@x5LAcZ#LGYjkU%U(!FCyL{BDfsb zLsSPyK&in$Ees^WB7sS(u(;f9_ANkMQBa$xU9gEJRY#u76k}mded&9cb$Mt6Tn0iQ0+|B} zAPiX{7{EqiB1k+IIsf$>*4wV#V?B)3t4;@LT1=D5$f$9^HX zph6@PQ?rfXT4O1jUFk1-$U#&PF=SZ+0vd=Tta89SM(c~0_(XjN+Eb31er9Fpac;@Lm*C2qq*dQ%jtw1o;hp~kRW4L$faDP zlS@qlh{>F*Nv&e+6wu09ckb_&_uQ9V@%rKMH`uU4s<*0(_te+F%pU%`-s6w=|j;mWX4PUjP6RGhOvS*j_r zAm3GRklKn$7*J`VI?=GG9(z5ots<55BLFT(X{aq}$H!;N9Dikx%b^y3qg-G21U_mBP6k$;!FS#EhF3p$&x7Co*6rW`vlJk^7Z)(^^xh*C6nT0|#wFANu z86Glg*KcL&v+wAdojo%Lgc3ASr7==Lp|ssKRw=Ovs#-Tb53bn^Xo3TwNJIqy6<2hi zyxUPmPp;dve&eS0;+z81#$>&2zqOL}+w1~48%l;7f+n`Ha{VR;hrsWz>thL4v_?gWy@cEnl1m|DX;kYPDeD#t1PYm@ofSez zpnVZcFgqF>jKHCl<4eA!&|1_5I|4zWjPp8IuOGQ+7#oKd=5tVM?ApR+jsq2>g_N>@ zScKpMM`Vj2q|``Ubs_8fV8B?>qf}XADnr`j6ruOp>~4=ftj?D?45iZ`x8( zEtq>cee|)V^rSW^Rl(F_m5icB@L4D_fEdUi3L1^ZV9tRfNiJ3KbtE2SMbsE!6{Ia- zK#e0800PuN90M2vX$yE!_EUOO+Y?)1aVS$@Cq~thX4vmFchKCs7u3- zlY$Tcf-gC&h?XdbM-XN&C_(9epE|nOUfC4v6%ZW`D;^sN074{0K<$3NVNFc7A7qeH zQ%16ZAfjWB#3-QO07{VH#1ob_vNDZ^P#~~3iZrO43jskP zmcRl;h@?|VheGs<3fZjM2Jvk?g&r>7LmPp5WupZM`B_JqCkXEJcEJ+#X0XZ#gX-`_NGbu zl3OlpojiBvXTIHS;w6_)cyx2~D}pdQ6ca(G-EX_VVhYazFaQJ)KoUkS`%8qt42Xmj zI1oV?NVu3~prI}Mi!zH92hw3Ef)61uaLMySBm(8dp_GnR7{u}XA$sUH=(p*-@Pf<7=&|+Toq%aO0YgLrX~Nli;p`*w?AKuPm9Xwgxb{u3<61cM6<9t6LgF1j z4muKCLwX0y}kssgg^*;u+_Tq{@x>>Zwlr8-n1 zVFu?wTpukLsMQ0o0NX;<3@E@q#v}uP20;yM#S;XSA3k#A4`)CbXm%jhkaYlyvL6PQ z7x~`c1+Y+E5-1~41gZqxwmkiqKk@?Hw+pVg2Cuskc5i^qS_UgPd<~Qb{iBfe=vvfPf}LsKKKGRY=c;Da1I2NTJS!g(ae(LRIiOlsM1<5#`<) zGK5;?upUacY~OU{D<;R^Sk_k)ObDF7`nUa&udkdwl+1NF3xia73%Qphu~}`Pym!OK z&he@9$wfdRBr6^uicQVLI_Y&X>0&V&LZuL`fC3XyrKC#4WLZLtYq|!G0*Yc2M4(l! zL#81QL6uNJ6l0iKQbs#87@}x}p#f(A1eFo;=#&aP`{Is5U_((W?ai$$4^`F#=3LHg z1VLm0V8z1Dc?&|hW6dQ&$wXCj*~R8$=4YPooj+&yJyN;+1C{tr%D2nNWPIbkcs|L#30tAr@;!muEJzWk)h4a)SYOj@epL<}XG>CFp<|Sdy zH6W4!VMf-Vk-dl)@r*10iU?T?IspJAf&dga>E>wzNKh4=YLSv5eN6)>R0e?x{tAE* zj0s1AU@XttS-u2Vyr%#`NnvR7MRQP(um*wveU%D8genH{z)63!RfsxNfEWOxtS(_@|XYckACgDU;X`${>fc`@&EkOlMf#Fz#sqGyFd8u%Qp<(|GCFt~7O1e-Y~;PPIyw}^CbcY{iHak=2=~o<#Zr&O4p9WDqc53} zZ=Ct+=F+BL+4#o z>klydx2OnsFKJf9tpflI#lu%$bIrbMuDJCjFS+K%Yd3A$V!%A}^mBjz*MI-mWBZpE z>*Y#$%jTV75IW#`tFA!Bacs1jJ%6s_ai#ImKl{kfzUA4ag)^1f;Ne40Joe<% z?|8=>heifgI(F06O=FXT=g&?ZeE8XJ(l$XDl(ALMNyX(#2rM>jn%FQ?nxq1fCuyFE zF}hS68C$9%{+?}_kUdd({@JOXvtCoh#-EJE-Bz0SrOx-MD7^*)wO3Ej+%^TF{EhQKSQEcNdd1dCe_v`orJ*@QqjAc<#~ZZ{7P~{Rodn z6M8~rz0OKo2Ey9lcnL_@`Yd&&QUyY@ys%VH8-rWQ+g`qL$L;I5Ne?{r_;;T8{!{0l znpv8)fFT4Ev~d*12C$3>%4>qav+8oHzyuftXcTC+P9uOXY=ps@fh|jk{>0b*{qox{ zyYtPj{@s6l^vPqcvy!)=4q8R=XjLmkTC31zLO@D^5*?_RF|)bNAZsIs7!Z=tD$iY# z=Srb5Cd(`_Z7z>hj6U7G&~)t*l}cflh99!L8_i@G#1l*bY#S1T+f>g z+Y^sQX|0v_?7RfZly!-`j!Y>)G7Mo5#@a+cfu|GoW^<|0P3@X+;FVVnZoDp7dt)$u zO<1jwoP@Jq@60^jO{U3sQ!AO#F{2T^Wd|$-Y(U2l4jM&3Df*V!%;7Ls_UZC1+IPer z6YWqB19w)fFd1M8um%((2tXZxgoY4H1R7yQc-~1fhce*~1y?HEgfIj+2r|$Q`vF0I z5T+i;EnVX?VOeTnRg!G^I2Mv76XNuS1#{tz#6?0XP8X+2-Ctu`vQ$ z^2j+l0TZlb=|heA4FPU413l$WcNUsbcT@$5K{5NBg-Rwag(}Ijp3S{DAW)*T0>>mk1HHQewpyk!5v3a}Rt z1;F4DgisiOu>czEg#l>D3~w}Rodsewpa&b$p7--@$O*L}qGF(2)b}AWI1f$$6{sQ) zq)0+ir~)#@Al?cK3LpzGlF1Snk5C&!Fo<(rg=LvlUV4wd`s5NQp9sDRf zLM~mIOAjfl8Yo=V_-R~?7?%DxlM22B1*M-&Su_?j;p}~K_Ips?3d1{K_Z@V{FYx{U z2v7-M^S=DpVLA9EfHr6aC`g5ym1LFW1q9$i1H8&9LBW{o^8xT->6000M|HJ}0~pcMrI z&1n%MVF}Pd&eAvZaxv5CM>iLViOQg$cn8{GZHR0JdBQL5mlH3@qZ?q?UUlQmuy3af zggh|``)^ z48(Pzor4UP%KL5{Jijvh;?#=<1Vk8^!8P;6q~2&`ON<^x8&Cwsi6{(}1R+)fDKS$S zLXBaWN+!~VBIPi0L6GA{RlfNrYNeM3KvH^b>Dq7MvrozjBy1QU2&g0=B2HKW3LIz7 zI|U?wIphqe2{Uh>Iq}>`c{qS5g{A;&0`X$K1IRVGwzaW#5qjp#fOe3UpgL&EZI;8W zZ1%qF{PFHp4-Rg5M=aL?T?cEohhwh|w|+i&=F|DXg*=IZjbri9`anud9ZFuT2WPX2 z8wj<^peG0x9kT_m*lD9R66Sg0q$`q#Cz15gv5IQA~c0~gxMFx;)T{v zga`>xn7!789+;F;!~jAH6&6c5a(t=#sRRC0ZEtCQe#e$;O{h=LJ)_aE_@nJ-2Xy$Mm;d@*kA2|} z{?BiQ=_k8T>xBT+ux4&%cmw&n|8GsXDk)kTRpQ2j$KDxbjRGQSz6Cewhbd+aZ z#nF3y`WFs7{p6?b`o{}XXB;H$Znks#wc9paQ!5S6&dpBEomr_bW1_rBxaZpav*73(rAAaJ*ckX&% z`!!o{y#2=i_Wt+1_x_@v8ho@XZ1BIs;Jgw-@{F%2Wi6``5{`6;Ff9D;8Bc%iT z4-5~Kg0h=FdM@qtK(Tl*%8ZTj-2B4)y3Om-cA7S`C@u{TPb|zAYsjiXOwfa0X-uE6X}!0A03xeN z5W-58O7Uo?v)t<~A=2u6r;wJQh|ub3rvHsU`joVe36+yn0eSD4T@;pky-u%}g<$}W zM2N^3W3zeBt3Uvqu~@%aJkKILVu>g^}{;hkpBi{oF78+(>um{*OPr z^kiC9waYJGw>;abFE)C;tX}6ll;N@A(nt^pxx_6mE-cjNhqhO5e9dJ$Ube9_WAFX` z!(Vy$?kA5v)6HxIW>jyOq;=#YCuBKWhAaRqITJy7NDcP$2nez~YjQg_Q3$bPOUwY? zN(U!ig}zJhu$Y9&PTm3P>oaMh zF|6rmCGRx5sTXY&36p?E1Wlwwi`9`ThitraN{7`*g_`oTcOhL#AX}#^uXy#EeLpj> z>E?1k08MC}=fmGimmkdYi#CeQ*l-v}CNzXj95E`eJx(l}n8E=Slo1)kiU)Qv$1hRU zmuYUYJ>>a3a+%nnFkl713J6e45CAv;4?sc@VF=I?Zg^258(3~Z+@o-uWSArdG^hX| z0sojRK5Z{Nn$Dg~>!+YACI!%?01;48qQJUTOrHBZ17OWwxmMowV3jd|0Es|$zdFfN z5HG+4QludjHY?}Za&9ys(M9%&^Ii1MOkbGG&S%n%A?;8VAS#T73X#z#zH22100Tyf zHZmYZ;5aubST{7W(3|PxT|z+exnu=zlMfr`eV`1<}!os=tM2ZkR zvj-KCA%uXmXR(rscp=uLt>oVIULCD{&-$x6UjFLD3tw$60mdN^i$})(QiTOu>7AgH z!bVsaABqr45%92Tr7TjKB8XqU3>v`S92PtQj6&Q@M8ca5yL&P+;RQE>%j^14kB~JH2phx+zp*AnE&o z2?3q=#ca^AFgrl>?0ivFD9rsVrNY|L&)bwf5Mm9gK=?n#<{|g#)4~CZ3NY3&0A@ZH z0PNSU09;b){(m1HH2jzb8Ttd&K0g3Z5Gx)K05uo`AkdwH?s=%6lC9Sx0hmGj)t?K; z+u0v(k#GG2WDA5|#DXFKjeVN;k~64(sO{6RMM@L&9V*zDk}ClKQmbrgf9nEdAOZHk z7Qh#+u;49d0#K`dU=U#>0zi>MLZ6B402&NK(Gh?Gqo9>EW}Axw!Nh>MLZlXD2(2Sa z?!-I>0gwV;@FWhr1@Zk@V*=n+NieMPz(x5-Vfo`CsL25o&O(NAnV7uIfj~Til}klc z2vQL6Kv>{&5f7x$dl3{x6qmFykY_UUqMtd%2cN@jdvMEc!Wai8_2vzB^bU=aiq99NZMi^^}QNjr0N>BySkv!J?27+g)hqfH|T< zDhioAgBNlLOo}Zi6ab7JlXs~oPspK(qfjs9?%=s>;UC(&_xnAsFRgjAf~!T}0Gqak zBRA=-|74zd$gVW0yn^`!Os8CQxT7)?hXEo3c_aqzu@GT^sI)ey0VMZ%zr0ESHIf%4 z%z#w5Df%2{ALkXIGz2sPJpdxq(tq1%VGB?wX*G}nDa5x7$P9u=0Gwwl&UTm?H42gl z1FkB5v9Em)6k$eGfCeByh*8x5%K|JEfMft3lprf%0990>NkQtbE-?tgh=t&v2(?0T z9uO5$tW7B1d!HATx$Ff=_e1Xhi?NgBciis*B(>etcNs0A2joD9xlQI5&Xp?RwvGEj6CJ(qq#;7# zr|OT@&X#`v&A;=RAAa^DU-;t-jhR3B-yivS(4kHQQ`K@ z+s@6L`LmDx`-4wB``f?up>N#xS0DcMKRxixzxm7grOoTs0S0|nb>Yn@Odm)9lq5Z> zKw%+Z$y=@V?rr<-c*Rc~Ir7{OAOB9hHOt`FP3*dC=S#M4+A}w`c=q_|i!0|=+VhMV z1w^($oq;h?U?QJ%qBs~Cop3hKlcZm04#L7330KpD`Xm()_Eq{QfVo(sD!K3c<>|l9 zv;4nZ_TFcX9{H!=`L}oc>YG0DXTST||M=VwA9x~IYbrz4V056DrPy4lRLdd8Yu2o5 zCe7*N7tfuTdhnjdh9+t|uH1ap)q8Kh;T3Ow?OSq}FD=h6%r7imTw0i!TV7b|b$Usj zd&kHWf{x>OXwC5O=tymRU~uig=)}n6*M_aFcFA4PHe_@fU# z_2hG-`iWV|V7r`NqsLKrczVdBy`{BO7;Y9hsaI#!?h?n$6Vq zRvNR5(<{z)z00$t>ue6fgzUU^Ht!!4xWK8jVf~hg@rlhFH*MUsaqEul1GQm8q0RHm zX6a!;&i!G?lux486F<#b{g&W(rUIQ z6iJe;_F}8OT*Rab_uKi1OcW0F(nha4FXD+zaSDRfXwE)(?Z2O}-?jh<07gedI?IzH zRMWAuHZ4W9Qe18)Ezb@S5siq?Ei0`6+2%|T>RLz!+l@{y?+y;vx=Yy)Pd)RhTW|U6 z55McLJ{doDwm#rCIH{u+hI?&6r zv}URXf>KpCR#uWEFIU2lg6?uBOS3C??i;QQUzk04@ZA2z?mQ93LCF~IrgORVZ-4ze ze&_c;blo-AK6BThZ+`K+dO6;;X^(9y3WD-@L_@XYcrQs33!>VlLP5LNo|?N@TC1*q z*WR74*t9U){&^DHW_)a5L~{fh z+DWsk8>Dp@$4l+{nZ*-}vRtB)h9C%ZJ+F&#!+QO5Cr>sm)_3h)e|p)MN+sbW>p7zh zD#^VEFd7s9o4~};pm3J?T(DT?3=vveh>1)|Yj9|?U_*6eeLS?(Suq^$2sTtynB>+W zTlStAv9zW%GNEe=o#wpl=r9~Fl{;ByuG`2x#!(z;?X7c;g(xau6h3Yl5F z5Ks`RFjkU-tqW)DN*rIWDt8#^LHeY}DG87u2l0YsfDV8MHHd&99e@y^f+)f*_Dv5J z!0QOEP`FlM1-Oc=gg^)go`c1&XXl?zo2M|Fp@qb?Kv@w$>EU92wI-Oo4atr&`man;L*WzOL zE6MIAiuwcQqEK)(Mbfg(7(9C`4v_(YP+4)}dao~U{M8LN3e#Vn-2b)a zY>r`w#l`~yMHW$k6F>l19HCnEe-)BoUbTJpEi-~bqDR9q!@<AaqP$}tmKf>w{rd5u&IMYG@h+F(z)Sv<= zXz%{ZU6@e~PzZqFi=*?8MGz|kK)`)RU}4fkQvx!@`~fJ2XaMy9P=rRyT$|qey4U^b zo6!6H&nMC5xHK6~ef&V@llKxblmgB>;2Xd#$a=sTKn864s$g$dPx-~gER1R%fB_U> z2)YcU`%YIb;I@D-W-9>VQQWHR8344bPK^yIaSP(UmGDLtn zf)a^VLZNdz%Y)Zlv3C3G21j2qKzk4nw28SB~$zb-4U`jcY(ckQ&1h&@w>+y+_>Hd+HB9J@YhlTRJBy1`J*}vyxiQ znAl1#;5}FYW)Mc_#e&WpW<~lE7b0a*3M1r_p=wNJaX_pLluBwKRB^1rvI?sbm2xxa z&H6I!xGvc9#<=`e;fFg`S?;cw~#V3dz<*4H#U=AlJ^{2$4&(% zFedj&Ctb>=<)Q1O$B+S8=X1*$gC_)qB;YM)3{Jp{SOx?!h>9imkN`3g00;|jHF& zG%^AbAwVVQ5m~&4qD-i-;V6Q?H9??MnNW!^d)BI?g9wC~bMG?{hX4SiC@A(v1O=c& ziWCLpNrN(^2@qKkDovqMniPb(I=!%Tp7z%<<*t zy6M?2%r!f+%2?(U#XGS^h0f~Gl#PlCUapoVjpe&G^VK z{zwvB0z}3*-&Y8{qQFC;JmHX2F^?!|Be6o zo9nml`tXN;Wp?3|g6N7pFTHx-%g&yhx-dIi0`6svh1NVpoV&zvh6FB^N_EZn_$K0@ z+iaA|;mFAF?CiOP#c4Fc;+%IyxjA^zDhPC7y@P`FWhBys3ytZMaRv9Y~RKv3Au5@hbD59{Uo%oe{ zz22(lHWl>4Vby{2?)pxHI}6K8 zGxKwEbMvRqOs&i{(q58_^|{nWD}y70A%J0hBcFv|G*8_OKWi{MbJFqd9G{ z8n5n}Iw(hR6+tN-2ul=2Yc{Nl!Wft~Z`)+^{M^);)5ngq+U<24cjkGXrwJe{O=;Jf zCYW?L^Y)))(tb%ggOF^u zRX6nN>7dY-L*D~mAZ!Xu6@YWwBMLQY5q9k3ur^p3?`EA&(hf~PL?TE!Aku*f2@oZ! zmB-7b)Lv|%1Uf1OE*i)Ot{&a>-q*iz_l`9`IC$v(FF$u7J-v44NEgy>kOYHf`xSe} zHjddeE0xOS(%`A*r}IwgQrqpeJR}y}h3Oe+?NU}b(W zS?-Y-$^7EtLU}!1_R2k1y>93H{L+`c{k403_`r)NPY9S%JvK(`0<2{@kU$7#9M`NX zZC_j6V61Uj-f**v!Tbs@ufS5n&Rgtg3dX{XyUo7I>csK6lV`f;5vio3TwIshJy@B_ z4}bHoKKbI*n*aBo&kd$F@bhF&cnL0KF(A4JL%J z%E6ZMn!%tp*J;#~*3OZUTlWsH8<)lT{M;;`oauDE)S{pohZpKg7kdp4xN&%>9GTNA zb4zJEH04qdiSyRlD2ys$X&|l!5{gsK+uSC-G}kU0A5?pf`uLp4ym9lB5XZJRizC2oRhW}L=#hBpj6gc3uo+GlB0yTVC{8A zQb``Rcv6g2Y7lX-h*<&Y0vIAw&=!cEnVCyYMgVq`+O2Rs$^aEQQv!e&r1Q9+-|rXq zXA4KOWyTzoE(Jju+gaM|^@LCmJc09$jB+3dkl6$jGhvRLxn2%E=W-&WbiizLn-ZxKD${>mc{InLEORH60Oi(?T5S_Ftl zAp)XfRzLu3!B(Pb7^s=nG^1m2h@AKyk|0Qg0Tz+MVg*4FdK51pj4?D{H(7q=n#n^a zr~j?FlBf|8L1bp{p`XFy`bCB!Bt?6ONH#7wX-3YtRvmhMvk`&-D=cQ&hCnG)j(sY* z2TuSDEGPnANLYN4Q7{VQYjCYoJjb&wZZJ5ls1RrrquT-s6d6es}k z;2AuvGK2~V0F6XrdK?iK?Q8}qVo?@~1W;Jn1Vy1LUK)+0u^(3>z$g+ZG$@hA5|K~s z1b2S*7jC}g58mkPyh+;jso6*FJ+c4z^7*+mWd&rAOm3ZHNiFAyDP!CEgvEhmB96s_ zI1$f%B9KKG#Dg&Q@%WSg0RR9=L_t)uLSo>&IOHRG@ra0m3doRV;Y>38Q5taZCg6g1 zjVMIK)aR?o7OS0!mm;b9bAP#Xs$6{#(U*qIeQyu`2tvsvg))N_I8zFNH=qhZ9QYI^ zmrws$`h$DLwV*dcCSW~eu6dW#%I?YU$l_4|4`hHM=$ljliG+RsWLw0LqFM#h1yxXd zso&Ru!cfElqXE+WgT<=!2m!(8Pz0eCw005nqzsxEQL%Nx3^ox*7!rgU$or*6vzd;q ztBh@?-k@GS1Ihl2(CtYrhNKJJK}f)7AQ?bjaIL}&#nWb9O;06I8W6!1h*U1=egQz3 z!C?XOq0m<=1l#YSMF1cT;KT_KA`*aLQI@I{2#Jtj5vU7@7?ffZWZRTRU7Cw-=Da_3 z1C8yB2DSy`6Qm|^a7}q~i_Dy}vnPCWM)?c`6bUi~qzwjTCMFDZwHI|wk3tdCv3Xy7&7$zbpgi3=c5`9990d)Y8fe?s{3Ydkh0E=_k5W1@; z2CjYi$l5p8)S!YHXnbNt?UvFz2YO#i=f0M0d&gkuO?vO`BNN|_cipx0ovHcrIyG8p zKqoB7ETV`-BxT2dL<-olh(Zz~5MlO!L`r!sCL*~qfrqT;1<)fZB~CP?(Ca~vNZ5tS zaBT=F$lAQ}aC-iryX=W*&o2f1GI85^bUTf{0oOhuL!a|_5Oh|`Lhf--sW1}})?}hI z7Xpk_Ttq@Cj|P=O4PY#I?{gGURK(X56A>g*%wAYfD->a8J?DUeN=g5Hj!2{kM6CC| zIMnscU*L-hUluAv!$>5>ZH%ieHHFK73u#Kha2f#xq(L;G0$}kepdcBL0EoqV2124j z5&=-$y4(k={d^R}BCZ^XR7gTj9HR1$Nr^C{6n1<8q5fi{2n2PJZtaVnF#;e2QWPkq zfJqRw4#8vFFZ|T|Ukl=s<7v=Ur44v&dg;{i%mtY3WXoW(G;NV)P1s7C0M_6@(NK%V zXIXo(ZX4ak_|W=&J70P5#QjEb6jZ)@^1Gcp`Kh&UuU<3ospr0U;e8i==a+x$=YRek zfeJqRxqB>>qbRZpvaFjW&KMXhmv?R2JUw&%FaGi`Uj2$!-1v$&tpBa;58U^?Lx*w# zuY&-@OHnjkNGVV`XB{)31f^hZX)e#)4Y%F&jc?vFyKritwE1V>^YiT)eCmnkW)?1V z(`@Ia^MO0^W1mY3`GR$WwI$U-QnP?%ReGeAI$41z4I z5JPPsE2KV>Q4(RCQu3cm|8aW%iQn4$n{OPu<2#@G&Y@=xy!|b2-~D@+-~GV7Pd@VK z^4yGDKT;X4M#gAGJ)d$f# zJx5VEG#s~E?fJ9QNvE-S)4C7*{JURz`>nQ-e(IC|`sHtZ>A4r4R}hR=*90a=dKscK zK^O<2GL*ZtUazONy^DND+bECC^p`oEx zquFfs8tvu9`PpW(5g4^@PMtel8yKq8hD5|$o23?&sg76jE-y6acU`@8!=_FD`EQ?o>)T$xe#4r7`1r@a z^uGe`}AOcD&R0u|wsgz2 zfzfWevC^8OOGN39#silG*n*@1DbG40jwnzn@I_8UACz9op8PSpasOuU6zWw}jkDh#f?o7D3ytK5kaN(KT-*o%sH|$E2ZrjdRHgdN)YOHmc3<(j*WdZRB(n^VU26@K68X znyaq;{$1Zc@QvgCR4`InH@t43Hmgyyi{2 zSLT}k`1ybR>H~MbaN;BbjD?e9vZjoK&H^&6Q|mUBcC3lVLya??r32l^&ifaa^HX&< z*G^j*5H)&>zI*614 z?;N5M@q!-2BZAM?(JWF#R3 z6_eIr6Sf&^O{Ppb#JGY%2;33x*vB01RFzu{rjk5r<+Owqt!pR>Bo%201%yM00@45x zhBC{D$VPzr!WDFNte38?NZsWkv zUmX1Q=j%rkf)XiVUKNTKPpGI$DL?@d5(^U`09$YbS^;7I;MAAnA}9cC`IePDg&c_l zya)gmfS&tx5PkNG8Hx+O8n;UTh%B7v4wOO>Cjz0y!N{DoD?d2>z}+VvIb3ghG%BbD zfe>{qTVDWl6d>o>_aodvr2lAz7?g{I3@m7J=?@=^d!_$dL$O{XD1(6qmrGtqhzkxG z3nCd20UUdQOMGOJ;dJRke)K0^TKwhGm-K)AZwUPpvnqz8P|Pbl*+RSmO;8vghUk{}`Xdf=MkR{(lQzHek@51s*vnUC~GBq}Ua^nfD1NE?s(;8p~H z3u+6z2SR`Vn1BSF1Ga*Mg{VOgiZeVg_Kk?J%60qVUc^GCAVelWV(?b?&iDg!E?R5G z_xjOYux6*Jji@ynAs#ZrYt`~JF3du+4mQ)^Lc{<9B}yS0B85m2#HbCZFo(@jx_Zm_ z?$=CCzIK4F0~ruF4xMkhj@CD+K4g^t3hWXI%i5UXz1D~yQ@xkl_s zN1y~Mv%c%W5h61)FoFPz17{#mpgc2ziYas~F_vOg2Cp>gP#f^R=UX+0dxqj`_paUX znxX2o5r}lZpH6?>o;Wdm&1=R>FT?J$?x{odlT*Fxj}MN$t2+AMDlfY_+Vtsx`+jiY zv1~4nSRsZO5M#y(AShHtbBq9LGz{KzE`$O|g@2%kTxM{bX+$p>3uqk(UGwj`}hdx6GzQG3;(ggyFf(|<% zm3Rq3M?s)iOO|8KMhL(-2sC&vRzxuTE9HsED-{R7fI(q=gB=5NQ%B+E5TR2oY++ zKmjozqDCsOG#VR6DzACxcAN3}@62r)TR(TabLiZ;X3$8CUXNZ`Fyp%%35_Hyph9qX?6sn`Dc-QW3CD)nkO{OI{d>&wfxjotpvZEyJY z=?8!H4}R^~^Ur_a7k@F*<-hs6&!#C>25L5kq|>t+lDvxw*G*0~+Kb=0|JyH~ICa}? zcfR?JKe1!O_;>FAOgFz6hE+!L#hxgPfSGeSr(qCwllF3FVcW)S-}}}BPkjH;m*4cR zH{SV^7cN|U@QH8CFE3OFt05$Fix*0zNEwyqsR-&I@a)5|Y*Z;vy&|j)RI(&lX)IgM zCX92Nh!;dvtdN9Ij3-DDuyV{$2z~^kAckCWmkLM@HiSTtJi7eg#b?fcVCT=h;`ZB) zKK;U9|J9%0cE@Yp_L8^Xdh^ZuAAk1b$~11IPdMAhymJB;~ zmQAGDi?bdOf{1EE@#5@?R+Z7Uqgi4b3*GWSwK5pwUDsY}M*)nj8$I;+q1V0TbvyR% z{-;lV;@>~}soP%m(trKuPkr^X-+0?kzxCZe|5nb-Z@CzyIqMmcq}v#x_0{qia}q|* zNprMf-}3t3xM9z}&FjB@?Aht#tyb2KI){FEJXYnsH|&_5 zS}2j(uz4(9NtYH{aW)bUnUU()vF8u^CH|Q=|MXQ?TzTKq-~Qrb|FV+Jnm`d6h0yCR zg&6<$U;NN-{LTksQ~8fS|H9OhD{I0{qx&WnPqi*Cwo2s?yc{_^z3cLci9Mry)}OsF zotehw*RH+kJ=cmdcYWz|pa05T&pm$#Af5;}j?rW!6_;BhW?is$U3F)TYnh}6dOti3 z&rSDEFYv5`LhPmp3_%b;fJJ!*Afun<^E37HGxpS*Cf|3(+O207FIbz$I!I9oNONUz z_m!Hog4`e~g)HQ~*wkjiLIOcR)?uDo_8b_4K;jrcv{vX590p?c46oZbICiGFbS_!U zHF%M8z4nn)&B=4!i6CBEs%{*vQ7)$%D<@hj8Te2K3TUa-X>d>ub}0s7P^y_SVy((x(OF-b zAeXUHz`|N%5Uae$d6!j4r5cHV2_UK#N@efRn{BFkixw~GV;0X#9BUdP2|yAC0jvN7 zh?dzg4+3sN+zq&0!4TqTQ4fN^kUz`|_op+D_ZAN)&1LLDfM6V=)slsfsx)<0<($@W zY`8K!UYnXP!-7eki+Dz{;6<#>b0lzL8Ng!B?0lB8V97)S)k?e5Nb-~bL?{Of z;u*b>B5@M{e9OYupFXLV7dJu@g}D1QyWVl6cHrxe&v9ZvD?}D{Vo9-px8gyNK@_Q; z@inHDuG!~eP))RJ6#KDu-5G7PSD*V2&kvD9=?B0ck8lnI} zz!8uGPk`9hx)l&aSiDAaK3zVW&$ii0QQ0c1Fa&@>Qcg7(B`Oy$h}6$7wMA)3&NdL* z9d6%O*|VIs=6JRTZ7j@S%mo!GBCG8q0OI>d5?8^ia6p=hfg$fnIPcyCweB z%U-c^vEEFSyiUZ6mMFav8;2;zl{V>l5IfcFl?Apj{wnlcxhJJ-JKo+Ia; zI`sH`$B)kCi4LMj8$bop%ksoQ>cz1KtvrAe6clIK{m3X&Jbx%IT0h?CNBC`ZMVBA< zqYCz!j6OArNCFF4c@PAYl2V|5cxv6jeUSzRJqD30n2^Gbf4WJAOtT+3}AspG651XF{(g} z1|0y9h(jZ=w3IYDIgDu|oQpj%150yA0!HCL6|9$b2eOtVZNMA~#V#Q93r>CE=>~9E zSo$~vaRo5IBF)TOKtWQ#eQ`GC7D*KiRRAL3*>k~c6%Ykbfuh3ON?4@p2zv%VBn5n_ z`GZI+4G8QcpO*8>`Nbo8dJl~4GNT)HTr;DSsyd`X&O{3-4=$-%1 z(C7`}&M(#OJAUd6bd)iK$fztRLz=y3(2BItI(M04hmfQ4%q##XQuI9|faN02*C+!b zxnt+Wvez0l8fZE6+PB#TP>##xWrnlQ+t$CUpBOUL>kuly3jEbFIYGByr#5{7_dmif zwz{Ozgc?C-3`%Q4$Z{Y{1_DiziD$L}g`y;96!BV#u=n7+cmS_Z7fTY7F5Z-$g~d~U zhR4F0FGRjYEIY2wt*DSH6sw2s<5dt;C<0JS=uiPFEczx;p^B9%u_PdfN&zTlL`A^1 zn4AJ=RD`RAWvBtAh(u9{f|phwRDcQu1-y5e*0ItR00x%=`=YX<5LSqw(IKG{AYnu% zO~xY?C&g|T)F%ww;g(}zLdAxK~qOryI1#+ z8>5nLn!D`p{>NX5m7o0hV*pf4Oqo3?C{+R^I&uE!w#n^(`Jqqzzn}cjO!w4qu=Ysj z=xk^Hiov}%j9z!Dd+e{i@UiDk9{9l9Klt0f^$VZ<>{pMUIx{vo92t|j9yXE^cFU!Rb^guI zfAh`neAla9`?@C|dG0e`_;kIuw0`}jUe-y{M$Qt)V_`sPhlwZ%bmky1l^`euVdS!` z*XZ=pmNpns#GGqo1QFOdmt!I011_u|3Kb~!-ZQhaT#jRn*ksS_81o!5g&3>y+1{Ct z9{iIxZhFJdT=tU#3zd8CzU$%VzWI{UglHK zA_x|2+Dl6i#X8^|bf}F^=Pyhzo}a3g!;Rb5zvYd0-f+V;)pC6C-1&d}o4>#J;rpLI zegr@dmPRY4p!b46N+1;u$* zT5F9&Dod@++``OaxmpdPQfVOWHWSG)Pi>YY?5VZf%FAx&m0RXcH>NL6{pttb^TmJs zpbzuQ{TV;z`z$iED&h$X?b{_0cAu*OaKeb70g=UdZv#^i<-O0TXrEa1vf`>l zxL_>^6(V@=`)(jA1RKRZsh!J`v{|c+MnRlpi4?6DiX$v#S=!CAJ(Zi*4R1a%`=Zs| z>VWR`T$0#0uGY#!&UPL;x4-olEAKgS`|Iw!vHG^b@Sd?9usoB@pE!B`^ke78!;v*Z z6TQivTk^a>1A1_9{aD7?v7?8^%-Gw0{`HlK%0GYQllLC@jHs+yHcr4fn`PbY>vw+i zkN($N-})0rA3OJhuiV#N>TO?pnNEXXSe4gB%NJ8m$>2yiSxD#Snt3T(b_w#W337EE4cdQN8=UFzJAA2-EGG|ZE^Hd5= z03r$ulu1<4Qsx2r-o1WvJ4I9j@@G2-zBY|Nx$V8fX?3>MR-!c;0bucAtTbswWf5mx z=Dqh~nZ0Kw!H@zVRHQ+hz$lwLwuoAV6aWk5xO-s3jholJINN+-Y0-xe80~BZV&c%` zgtKXqvYPAV*7~;V31NvMVe8nJ!Z^w$3c{EIrNbx=A+yh)yU=cRM+3Uz%G!=wYg=!q zjDgCRVD6}0KH{45uCw6so|FbcDk&AH0FW|Q8d70EE@337j1U>f69hn;iq9pCF{qGI zKpLYex}M}Iqv2?+4lmQ_&>hNg3QVNc2uT2tAr=8T3Pd{|6WEKm9dVdo7%}SiWVpw9 z;gMwi>1^S!T{_`f!WjtZu%yFEC0xpq<)qDCn8X{-tZ!%DM>tlk3{@)iyzAKsfJbni zNg<L7*Lqxmj#H7Mer6IPv9KWbQ6vf>WP;yq zA5I_x3XAy)_+l*(Ma0Z3R*(fWA`%sLCtyJjBEm{=1P3Q%B+DicekA-Pfq==psDY%xt8B#=$Kp`PhD#;$G{QR2hbxwcu)YtxX>X~KaijIo^ zhfrkb6xLJVzV4~7eC&_C_-ds0M-tchst5Mn|BhMQ25YOQ)f@iH0sTzgeWSJCIkD;g zUnysl0uW}8fEoz_bN1YSGIA*)kC0ZG(th?k^m|-5=NthE6oU8Qz2pjF>MK!E`eqSW zg{hZ5=)ZpY<9PK)AG*(u6l6;g$|9E_tLyi>O8>I=kGU*>)PGS#`i(e5!VF3&t$F^i z%)cm4-3z5bxcpUo<9qb0e%jsjZ+y=uAX@@K@NF>>Dh;b`j^bS(uX+ImA_Cs^VKW!M zAp;b;T-*1o76I9~8Uo!9872?`wnF`O5AY) zvrsXTIxz&KV0azL7<3jnnSHprj`eto@sZav4Uxrgb|6vul1$ts$=_Z99{FOYV?YbcL*$l+y$q< z**^JX>+Eu;4mJy=1xd%XyWC45OChl$UTmk?91e!7ro5OhW|+mGd(s($c-aow}&2=nOm5#EI9T3>#ry8QBB?bmVJSJcx-o6|lwVVJP7xrk!V z6j4MVP7uHgvJ-NQ0Vsuz*$D_KkDN=t-kKE|4@KUd0$>yeRMhl%_BpIt#ek?!A{9~q zKp;&N0w^dd-Bh2T1$F?mDzhg*4HS~DYE$vt=r00PED07+#4{og6)FY=iUCP6b)7@txos(XCI%vaPFnIz5KmD z{Tqi~xZ&RWzTD|fDIF6Od$a2#9n{FenNOBxm;c9a{QicuS08%n>{q|~wWZ!%*;LcC zmF8_i&uH_k3ksYQtrcR3B1*+k7%8G&>Rq0C@nI>;&F1dtzioLKe zHvmLLR4hU&01Cpe9M@_fnDsK|+%ucNAdt1r1V$spNZyI_J`4i()>^NP7SGLkBZvZ< z`?Q-43=e<+p#cP&y%_Pvl;OIbYAZ#zU z4?ObhhHcvqKKyv#TOa$xU;e|#|NdY8`BSgE^OZf@{>&#o`}iY2Ja_&?v(W^QQn_5M zh0fYENuA39pi&#WZ0|MKUw_RFH{5jj<$KnyU#Bp*c=6)VgD*~<`~K|g#o4)en>%DF z55$9mgMx!unxP^VVk@OeOd67QXa3^sO1+h4sdYXG$|EDAyDr;XisL9Og<(7~IjmT9 zTdn2gh30be(1AnWz3+jfmjXa;dr2>CcY3wjfb(fT9#by$()3Rds|N`|VJwV1g3c$3 zg3wfQ=vkK{nL=&SXJ7g&8Y3t~&0GlT6o5#7luO0ys!3;grXJQ6thucni_s+(*UcK0imp_uhvts`-4~ZJ4I&wAE@n61eqA$f zuffwD>OTAB6R&yeb=%iZ96Nl0SM0>r@%DUo{`A7$-J9?DsVj~iKL62w``xF`{4fZy zWXhynyR{4~?|AJ`fB27nXY0t0@BGUnFFroaZ9NdK$vT;6s4uvv7FT@OTy9ldnCbel zxr~5XTc|fSMw`~_tu?o( zdwj;7?mzd3z@v<4LL2#WiTGD5+ChNsf!pP74Nd+Exc+w(<<37}Di z-RilS!8#EJZ30b1#NfqSAr?gjSU3a1BIaFO;s=4Q8d`tjmNgd|=?hEq9kzit4nUkz zNCA)*6>23S^i{r0M9 zL;YcU;L)UehKxfL)+r1R8y!ver7{vp()7d>4ePXRb|Su#!JtfN2%JDJoC|7!34jeqdz4H9j{ua56lU;8dHG?x@OZZT ztY13A%c;viSrt(vIcLIlcqq=pe6icM+BpKtlH1HPd-TnfZYNFG4h#;J%BNa0sI&s@ zz#*fM^^!ZtkSLK9b6dk$YwG#jkZ$KI$LBjJpnw_JpsAS1u|uCbwg6(de<035AIN$K z<~ujkhQ9as!AF+rEl`1UJupf@h$3FVE9~=9AZ)!=h@PzzuStRU+-E=@kXax=+PiKC z9Z<0P(;@ zWRW5uabUR|=*e=tZlDYbTAeg!VWgAw{OoeK9O*a=6cAeuNi-2NCvaKT1L>oL2>(+iwuXRSPTv2o-)&R6rW2AA|Ix2`DoV z^haEVwAq`?Vjf=<(}v=au@DnH$F$4;U& zKvyKGLn{Gd2(*+2Xk?S3b<&vPmGhFe3ZyE!FVzJgUNC%oUvWOQbY(T7$bqH}l2ARYs(m0E) zhFV!v<%wWqovDmhDz!>jE7usJH8Qu%o%(>aSC=Z+y>w#JtE%x!L)i)70KX2?-|3xr zqH+F0vIKb^aLRdC(q+HY;T~vqVnyREA%6#pWwsK3=;`Llv4oOrQSx#RCVExirOy zI3%&XNGzMe&;U7bCJqcOqP^HzIPqZf^y#r%-afYeZF<{>hDUC#?)%D`N1mQ}KAB!H zS&5920MHU@5*;c7;4Ev;c|m8hMN~wji@-S%aGVikJ-I5gF21Ul1_c&`ux zty6)n6Q#g_>UksqCe7e1I}faoNh>ej`5cfG5(qK^vm-p>Zq(Nz53qXK{v!SR0Q9uF?fKaIj!Jzkm zLga+|CB{SmL|AwWikNg1@oAnl`w`qgNQ8*u8Bvo`%);IYpdk||gPw?#2BT4dC=yai zYi-0U&8B4+KJd011~*45CtFYa;P^XU`;xqs%`GgsQYW?b#I})80kx8)-2*${b?uu! z{U3K-bJO(%s?RwCYNLxNKO`tu;u2Orb=Rkd2dn?_xBmc}KxDu9Dl&~- zm!4kE7dFB6>n3lSu3z}*zx~!vz4X0ry7S$eH?8~9H@;F|S&ZY7QA&V_$mJQJt5#xh zxHx_GyWd*ed-=6H_w0M$Pygmak9_s;@y7&}Qd-z|l7@g2;a0Ep8^88@uXy#F{^}$D zK3pA7@?4=I4Y^B&z0u;VcWenY5g`&H>43`RY7~}S%6V>s(3ImSb?qYH9#JDQ0BUV= z$AF+vvts~a7U!81X)>(Xd6%XZNtNPqF9(-<&z`}9cm*029BUr`v-V%SZS$Moxb6+t zZQOVK)a)~NKl#Ilzpu81d$#Yq^5!dU{LPmxrSm6GoIi2q+{L+z3-hyClB!4}DDfOd zDy~LE$~#{;TND^$f~XwFair0(Wd}ZoJkPUEuVsBgL?c7vJ9qEeclF*)6KhA;jsz;K zFV&xYX8$wK?|=5-!PCdjq+m-yd91qL1d(%?<<2>)G{uqDMmwLcv=%x^+pz-#1;ndI zhach9)nTn7g`fl^FoD*Q^%MjZ1tv+`#Wtr)fhMvUE7Aa%WtnqM2N9B>MsZ+s2}2!3 zVV-&u8E+jkw_9zaqo^E-XPY_#ASEWydFE~A!&qx=l8$RNJ4q)sCU%~UE>CV4(xh5T z%iYFOx0#MlZoKB^-D@h<>5CUP?AWsJrmO${V;}qXfBEFf%JR&G3jkn(zytw%+v~Og z0F~LfXV1QUS6zGk_19c|&AN3PCfBU#b$Ta{y?FOm@14Ckv$V93S?4pTRLUFHtub-X zYbGon2}qf8shruY)od;<)H|o!0vyD_=;*|?+qQ1rvUz-B-N4X@x7=>EE>2A?udK|@ zOr1FT{L0clF{PV3x2Z9PqlKN0ls6$i$&at&^9ZGf7w0-m2M<1`Whi7KGc_rVx ze$C#!I~u*@xy2V>eC|S3;>-3 za>z?q4A4R8AT(HrVe%|3Xgoy(EZ%{RR3MyX$yzSG>9S3?y>9&MVfyO9rFxb{foA61 zu~s@Dvd(+qKt+*JfziU~*@-|z;ZR&1FjdY`d*AG}Qm`9_;~Q@t*z@vup+-<5>^W~|SvgkmFwVBp<)jnF!tWLy$WYII*BjjHE^tQ5ZbvMbC~c<#iL3+#|Iu=K@YAgjGC zMO{0GN@qSV*d;HXkQ4z6dhvvSMBzI%V~j8kC=H56iF zEP#&?pa6Ja6x5^`*o&w>bY(0~|I+Ka4EkLoA}9rJUv0W^PCWDl5q1jLsASi!RuAB|)SBF!7KuB!bZAQ3=2Y zs4V!LoyUGY2_bL+T#DHtBJ=}(`%fPFojt3=g}zlo7eeOYU~=8?*3;836t4sKufMFq zy8nt&FL_u0?~hCWCc4k};%ZQW2$C)=zd*(F>=U+vC_sP)f--3%X;W;oh)C&g8%3y8 zu@r&^qfkJkCl?>)FCGC^fv^nR1+^7#dJ8mOl#`FZ(glD7gOD@GT)uQ&5tRD{{7bFy%O zloiN;d%#_AIV6enW;q?g!V66TiULhqfl;i%X$?U{ zv7sOUWa6T)7A8sPn~bXRufhn+JQ zdNb0?14+fE-0MiM?wTFxIAF&v=Y-J-WR6pSpyyg1l!Fe6bRi2d>TtV6l?Y8LSpbz- zLE;kz?}RlNLedzB2%!p95Mbn)P;d>DZ<(09<;KYkuNk170E=+qGb@k$@XV3vcH+yZ zSy9GC`44DN0u0W17Hc{6$f6u7f8J*^Q|Y;XZQp!g=$dzo48GJ{f92TL`v#8QJ8|#P zqbK|lh|(%d#d`;e5I~`54Vpo~qe3M>B!q}W0?gKX0p}nC5e0@p0IWit+f0x`jn;D- zQu#{L+fDUhSU%_5T^O~xaYD|XY;S%j+4YKe_%$(H3+mOdd3QW|>-e@Wmk&PFKGE*A zN+#5%#|D5%>5O~1C_qd_Id45W5KH6%oQNku1Y$-6(pq^C0OtYwbOmDJ<>-^5+*jO6 zze1vz*q|@~5>dchOnf|m04l^Hv_}aj6s>e6&;uG{5)DF7G+0YfHwC1%_#(Cd5Qse~ zA|fh6K3Da@N{WPg5Md|6s+c7Sv+E(D02DQ$MHefPF2n@h<(dLQ1V)WUfhJajffA*a zCeXyjs8Z5QhP8k9uU+r0Klj+|>5KJBEv_%LyLo33mRFLx3P1sMTCLEj5C7EfK78N) zPPQ)i(Lers^@G{(0Dw_Z!!Nbl zy>TAfRM}FlRlfVkJtvn={q!v#`0wv}|6TWg`T4WQ28U~b4jfzX07Pk$X*9zlBPLSM zJpJ&QbEkG}+kNAecdQ+meB|l-6Wi2e0NB|)@%5Xpe*FjD|A9aH$ft6P!{cij*|e8D zFjeL}OLAj~luFWcU|_gh;v~s!=F7EeB`VvFSK3qtDkwILReQx|c}hy0vmO}`JTvx( z5daPYj0Q@zUe;~p?Of$rDWfzn=gyN9Me1Il*dv9(5o4^Pj&JH|j~yyw|R?|=55@gJ_c?(!SE5o#TW;hM?yqZ7kx){d{6oZPW({a~fi>vhkZ zIC<~>C!Tx$;L%fu&z(D;ai%b;l?Q8KObj;5GS?%}Q4m!sk#|Yvl6J4%PCL2JSNA+* zDfX+r4CvBsC&i2bl^`iJgvL2t8yeYrQL){C%~JqaGr9iiYxiAq z&9yh)eDl_=Th@$^qaqQQySVh&gO5G;^s|lDLaWgU!b&9`*tB_2D`hju(i~8tSmmkj zc9TwLvDI#SaHP$)%XVzrzH8@>t!vkg*J=Z4D_dM#JbUKc69*5SIB{b7!u0&YY_HSn z_L9_f1uOt5Qd*mG6l<;6d*>XWMunjXo%eZ~6yA_aF9BY9d46;{VG%1xKpI&9Y??RY zV5k&UlDy{}Yi)>-#UY}IBh-XpUlt=I{jj&fuR&o*oT5ohp6v`A1%o?%g~w z=Dgl{`PS!;9&aoj`Nj9YWN2qdC-^0|uHSg$@ZWsoi+}!qKC)t4mv6pxVR@mQ%qD5$ zWxHPUkw5>#+wZ*P=vPla^q>2E8t$3c>=Wrm9bKVzC-sXmGCnBQ&CH))QFGV5ckdnV zzD>pEZ~p3IU%C4$2ah~I2xEIH*Gu#_v}SJmO~E!HN*r) zKo>r zuCxYbB}N%UVV?_&Xr;!ZZE_YSVPdhO=@7f;T+C8M+#>p?WA zTwGBYU?I;qBNRc$!iZv&0(QA1AgI73wyA(TM5m7{iLARLT6e~B0c<`zZ zJc`3pah$>eWD=r?Nx1%6s{PevZyE|KAAa%fFSkxBUDANU0$j8U;_4s{1egE-kfooi z*qB0NH0+k{c##x9r-u zxRO75YHm8Q4B~`^lp+9j#vy6SoLJyMt3trq$vIGzuw(+6pl1;z2Jv1ppLt;mo)HPP zV+JWibp86VLhC00PP`Q>tITSF{R>S;kt2lw0Z{IeBh$~ey34C(*HyWb@PCD-tCP(i z$&CLm5ZnKv?xXfgd&=tY2#VLPpWs(KCIf2Jp`Z~of&x+q!4ZIqV{7qgp$+dpAcaV= z_#Av4@&qJ@2 zwA#{{!%`WLAgDlPk`(aL3FyuO`XY)+uqY6)MM)-r0DC|#2wnsdSXEpj0E-X+_`Z0) zUx49@7APuUIUpe;djN%?GzPJXG*FtS!d{_LN+Tl*X{9tMViRB#LR`X9AVH|Y0K&l8 zu(4e2=tz~z!Xr8E+7NELW6i{yN^mXs4WPP^{w*K_?0~I9BA&?gbqRVQy97V0PnM#sKsvr!MA;gSx z(#CLLd^zIs)#2prJ2zeV^1ljoXO-#l^6+o~gP4{p6|a{YJX?|=97g9~RDAwwix zaC!)eB1OvPIgr*G1<87k2!!lGj531Ao)xfw^{fz!W@+nDJ5LtDt*K>u%AH9(JIDFq zF3z`+VqG%}-Td^y^vtnj?_*}`%PX~4#(cGu-yU9mMX>gJrHx-{9(bWSld?7@BuYv5 zSf!{)DPl@oPrTAfYx0h*Z~`bqAf6C43K2NJ%F+{Iu_&*4^9WE25E6qhdj=FD0`53Da{Inlu)38fFck=)CzSgUwQp2 zcCX!5vYq_ceBti;D;mG@mj8a^!gXK#=9kXcQ4rd?NUy2hdO(r#n9-mEV*d-Yz@ z%hF!A*R?&q@ycteS42B`=X(ZzX5H0m1_uYCD2hzz({yQN{=(Vw_uq5Ru~SEmo z+_{D3GJ_Zh%VDJ!jSv|2((NP)B`~TSmJJyq$XvUXHri>|vitF^P5N0K|7F|j?`Nct zlz=8Oaa^`mz^nCJwr$(F?a1@bY8@zTNTIb(DWgbPo1-EkWdbcCS&|m>AQNl0kR~=P z1>P}x2|^Qu00=I(UWqYU2Sx<)+=r2hqOjfQVGs-qm7*Z3FL!39r>)J##>aQ=+V#e_ zykXkRtNT%)V5vUVi1}d-q&+(~UP?cG+b+ zcI_A%987!3#q$@R{NZD>v$GUxqst}^h6V-(Yq6WOI*OO)8%a9{v?9K~((E*Qy>3TH zf^uc+?(N%lY~Qqb{lL(0Ij+_hTj!_FJb2&pXU?2If9~wX>FJ9XXM4?F4o;&{Mk6St z^guLJWRnOmkz!_MMx{fe3k8Q`pXOa=`(v5EmqIG~2zC{<7WzO-7${QA>^VzqyAlpW zrqtu4Kwl)vixrSS1)6j(?;FjI&-j_^fYZhHv-!Z-U~?V7e)nR`voTdH| zRNxX!%cewgZB&p(|0%LEh1n`pBqRk#1D_G8h=@42!P4yMwNVsSR>PTdCe}4UNm)Y7 zY{we)b)^c1v6)3wczMqa```cI&drPdSAJ#rYiGw~O-6>)TUaIzv0=q**4;gr<49Eu z5@Y5vCet*N?Qz*b+&}2t`OxfjAL<-=XTK9MIU}$A{$%rIt}e4~QIXq)9X2yl>lM}L zk^BdPhfAg>DtU+JcDwE_gD3*E1Lh9FgLBeG!?p%dnnk|PxCPQ>)h$8B;(;3rs%0ba z5sk9<8WfR$b_f@g=Guj zOzp>J?)lEc4=A^h7vcp;mxWMx@BJU658HladTlm?nW*ZDRsgmBE&bKtvM% zER8(vNH!m)nV-J#FU;qIAARi)e`9#6G2NV5V`xW~m>K{9QA9z8jkaP+KxH~S6;(>k za*3E6k~^t#8tkT%#M2;$hzLzlt568BnI3gOVW39CEXDWj-~A28c8_CxdV6%W31eb5 zHZ}Y$^HgC)37RY~Es==EC`Hbdq7td4ec7l8XomulaN~rQlSWALc_L7ndqt6eAnm&q zO7wH0q}?zu>4I>eaoqId2!M!1JrOZDQDzi6r37DVPT#&kv@NcF{ZH-m3u^IIkcuR~ z7D!Sg2TZM%6F$=_8zi))ZTo6%gH5eIlL4M0{}JS12pWkE!it{wO_({!Htqc%rQS}N zJ7)GCkd0Nn{4%fwE?^vSdz#yDBLGM#@Y<@k6W}i`mmTShr=;?!Qwnc+NB{;a5OlZ#0@<#zMKOzF9^#=MF(5QalbCFi zlthyaxFoHrLIo1RCY@0wLW~3jt4aW%)5;$N)yQPpLoEaXbC#PfDVkVD^+W_%A_h^6 z$zj^&Cd-jq?c~~LWF7AIsOZ^FCdmEjVyLdq=8n8~u;RieSJKsZ8>;O|ij^di53iEPWM&ATn9Ce3imy&rP1ay7}6xyT0LL`*(koj{M;4 zUp#or(cfGA-Q%x5kE>+Zsw0~Ly%?jlAOjU25E&XJk|=YVPDZU$rK*Tf^zZ-?%*03E z?PRwtO!l~{6h2j%H`ns5t*doD37rm6r)M@pxb#$YCn2YUCujP7deo@=c_yqQ)>2ix8L%8)nODEHff8n1mQ6qs+oN z&8%25j>*;I3TFNL{?T_pWO#Pt_>*TBJF^VEaB20bUtI}TVXCNRJU)BV?2*6zZGZV6 z{_B6zbu)9F9X;1K$cSB%>pN#PkTI0!9q}xNDk*0Ny`#6^^}ApA>Zu#9{N2Cy*FOFY z-}-aE{0qPQ_^%2zj=7A(A3gf~=*7==?*4}29rt!`xxaVYoBs0g>g21JPX6ho6JLDf zv)yjKWB-nQO9%JOA6)A1+A*_ZslTv`4`s~SjrB|=PW#$>^^>oyu5C(Lo_&WC7-W7MV&E_c@0risKP5q0U=z~#(jGMDvdDf)Q%+;W6>MRDx5 zTaF&S>8|^3nVIcZlda$S^T|EW^upTuDnNh%LMm3G^6hus`|gL{^}Y{&;I^A@ z-nV!6V9*gf?&8MQrou62 znKK0L^m_wim5gdDxv@4Wn34>K02L95LDa|4#L)Oyht{yIC8p}Mf4WwjwB=7aOX^if zO$Io?hd3!~?iRD%qEpwNl$cCFun^R5qI(E_${z zYBpbQPTp1Da>>6*Xj1+|h*DT5kqwi{jIqu-)}U2cab`L$TQ9fw?CsA8pISZ@xH+(I z@2Hv_+`V7UZvW{MFF*V@ZhhscQ$O*KfA+VZ{G(lioqy*Of4i(#AA9`|_r(MM{D1wC z@BT-h=vMB;|Mte@*>K(bp{y8eYz(!Fxt)WH<8>)@-;o`g8=Gre>vw$k<_~?>d#)^B z`N8k`Tfg;3zqv77+tod^&mEnw4`ickHtgEpIhJ|zMttFUdE}(Nq?iE4QVt+Fnj+O& z;MOfBK|ACW3O1^V(D!y;HrgjoxoHB5N==AhZq#?Fm|dE`a$;M9b2hgCyjquAW1G+r z5kzB9CgV(!E*Yg*nBvO1{L=rtc{{JWr)wz$A0int5Xm^3%ey-|{Xw2pO^iXS z=$mFlA@0xZb+^pj{0;ea@9XV7SYQKZzgAv;)Yq@MSaNTMXEWn=TVvG_tW~z^hrv4P z3`~fKpsb)!Mqfo+@Z5oHu-jTA4u~8Y9?| z4QOg9JvC7qN_A$^p^0arjI05TW!sQ(Y)hS3VMn~}CynaJPm<`75NpJZa=bWK#QA!B z_0)me7QbnK_t!3*oRjM_Qy7qFFhq6qAR&T?P%93MLF-7-5x0C@qDpE7m?&s4${_Vp zGnffX1map6vSh729X38R$A5YM{cEqSeX%N?&1@=^ryXTV{fvl26eRG}jzc601*Mp( z9m6Cd4mp9|IdkXDf8~K&#&^H+zn^|=<<-(ihdL~1<7!kRrS2dxZ&h2}EHe^xnOaGa zHUgnts)8yQ8D;Bn{k@v~``iBFOn3I59RHnPAH5m5n-Rqj01#3nVT$FvHic6mv`IHg z00nrcns&-|jX?{A;2KQ?t;a5uQu~)Ips3{blN6St*GZ5{BqX+K1OQE8yGleX5~D;Sh)UF$ zlwPS-2`w`#&A)`e1QtY9HDnp44NrtL>1mYEti*~z>y`^@ErGsXwsUQP`ZJsOwf)1k z+e&%{nYIdU<5E*AJM{=60J`jg5T5BBKHLB9XHXtExUe?edQ3S^>eTfrwAjS%2c;*sc%DbG@p8@8$+W9y6# z9ZZg_!)^glG>p}c5lWCkeM?;?q}Ce5)7@EAm83nG>G-76uPVd|@K1aNAuz)_TUhEK zl0<1@5O^XoWJHqU8P+hVA>o|!Oo~jq1SQCUGG`2tf`r+zuTfU2q=sQw zT>{P`d~zsNO|iXE+Vze^SjlDioGs>LysXU-B-HxHCxN;ud4d6)sw2+84nokFvSR=u zt6_Dk*>F9bj8TpUo>`h-v}B#h z$}qa?mir)f@7(^6eds;UJ#qY%<0lP=tka1NRaF(@B*{aV?07PYf_`UbC!5b_yGz~O zJ?$J?I?y$}3d7Tv-&mcLqiUOooV9F-2+W)?7h~+Wt}kp{;fWcAYDp$LW_Db+ctf}9 zuUD(XY6S_l%5sDtK8QAHa+V~5l49+}8gdoNN6J5awtV)M{Dxc14Y%v9@6GOfM|R^` zU4B(wJ2`ptEHur2bAHMzA`DR@7gl*2mIO{k-`6T7!Td4HY+=55=ZwVh6X zAc zV^?GcjvN^D=LWk5Cr_MOzr4M*Ilg-C>el-DaJW96jDwH8na&;Wzh&Q^qkE4Wn3*8l|=9c-w*3wuqo>UF+Mp!Plyw6zz!+1+j^x^{&YKaI9^l zEOl(pux*-Ad(u;CVhd*^s$kL{YZFI~JBCC=w#qA(^D#Dl^^N~l4VyY2>V#CICCh4y zyekpLm`+i|Mgl?%-f#x6a%78fHHlm|D9^56DE82yg9n~@>B|*1zW1Me;`ujU{P7?8 z(O1sCwrA$Zw?6QR<@2xqmp}d4TZ_AX@@M|-`@iR&$;;*0&#m^y{arWjlISOho1;lp zg#h30<(2PkZeGb2!biUUBRAc3{V)H@FaPJC|BuhT^lYD&ZW_FEHZBe7g>E&oKf8Xu zzw2^y;Tie->+)2Ib-*z?iM9B)BF`jbMl>+-HQLmYdOPYqc%Wp z;Jid7t+bib{=&lI%H?w%EizLW^-xmvA&N+JmVF%|=;cLjY~6_WL`2TGS62MvC zMbRsSC3pkQvqGYfq1@0yw^taqF>KbVN#!^DkeinVcfEK1=5O!pKhP-xwywkzzge$5 zs#|A*@n&wu^%qT6AV7^(jarv*4$gvm#t^9}6U8V^8OdsYm+9@{?k=NV>-C^PvmKTU zNiAf7vB1ME5%-CEq^m0DysoJlqdlRUh;KDGOtgz=0qB517(t)ZjVI#rySsNE(SFffE&_in+W-9d7i#ei zHX({0%{YciyqA!OP!uFL-8Y9DpZUV8-~Mgal^t7P@~t=T`pUT%M|N!0rPe_x3L-O9 z0yDEg6`O!Y$fq8LT3wxrUwrA+otWI&?gDKfWflcQ{1Hr}QEpSkmUmb&vl^73!~>gZ(TZqD3- z!AVX@5Y=ldUgAVY)nu3?iXPAH$q$ag#-?Axlp5N4vZ6(p(K1?1%Y>fNQ3N1}K~j6E zkQ#8ns#Vkgw5`0t z7}N5h6&hoLC`F;F3{DQX34D+wHUkU9kdZ_PZ@F5Q+jJih#3>dhEpHg9L6oU<4gZ(g z)j$8I3Q%&vWhHL=C`}Qdu|-a&GL+WB*jP;(DG4pdr(FtlYEYc;WC4t7oZ>IjSXUyb zQ3Qg8v7{dLCP6if^@R&mZqgm!?7s7##xu{$BfqO>Ues8FJVHa{T9q8N1o%|=(o~Dw zw$rN9Z%F&@+7XdxOqu8a0d;^g*u1*(Uw#qBps8S>V-FH&gIKo&;}~1l?=*-62vL1a zaSZ8b^vDL(S)i=YY8$=+SyF-qXhw{a z#wus>;-khc45@pih zMTm_NVQJ%#B_c+tOWVzF-#wZynoBjkv0>j>)zx8LMv2iHTQ(+!QEjruWImHhI-9F< z-2Njpl8m=v`lLRHnmc0q-z zOZzzx3C`r1kcAQqiT7+X4Q(8ns!tByD#FzI)k8JKy^1K4WzM0kD|-y>ofv~=&M`5A z5eQ6rB&OWnRRoT%a3zUbou(eWNF`eM0 z98b=C{|CQs-;TXM@}K_Ik%jB3Q6Ry5zn^hFmc}?sks2>Wk*Sbx)LKhM^Ss#J76mk#fjo6m2)LNrMO!jWHl%|E?6JFv6AXMJ$4H1D%ngMEvRVOP-U!FdH%2`h2k2~*q$2%Un{miS&apD1hRD#@7}Snbo%Pn{#{3I zn7Q%HGuFLb)j0f3-SahbCR{Aw+8| zbFXeF8IQF?Urpdu0N8>J6%&k~te<%XFCV~@$Lzry_~5LYxgp=T)AcXw@|C!{g{`qn zO4&R&Uh83YANJ&M4FW(0`3_o|&-xeZ)0btXFh$pOGn+YfN=%VKk{AS{%4~~HVcA+X z#2P|bP3lP)dtZgv2ohv(C@DkQAo2g(2brQ63}zRLZojU*uQmFRm$}wa@dMjR`&&YeXO_B+L<6o{LB|skYX)cOTf> zotwL5@BRnh_s*Gqe|u}~>92j|(&ZCp-h6$yy$K+(1Q&j)&fH-+g!A zbI%?3+;(XHftlHv(dPE%%GJ%y&F$^c+Levjh2HGKU}?{eY82-d`rV@Q=4)sCWC9A? z!xEQPV_n~L*Uj(y@WVTocI2I&vpDZL&ifDXmC6CNj*{$Ew@u96fNy<<&FGD;J#U z5NV@T6H7zp#Q52te{?!p}Exf}1EzwtxG z;dl0T?zGs(nXlBVkHqRUOl4xp-K^7{!=S?&wVHsP8YnBWE+}fKQ52-2^~i%Dma+jl zJ52W==L_sNrCATglAE(cgjzWRBGkd=L>-1zJs0CfL|1VK>mktf%zK!Y2;D?`gPhQf zN8;+E&BoKRea5Voy2YrwQJhZ7av<)8nZc0aE1RRM^~iJ!W6?w}h^(R3rsg0NMWjO* zO1;?(J;5;~dXEq!Ff$NJt)bwwaHuk5D~?{>u6B234i&pr>kUH=h&8;|I`sfC*=R$8 zdL>ErkYyY-p>k{l$jCxtr6UV&psbo_t`1ETy(7o$hH>z_uV1<8>Hh8SUkn$|9=&1k z|2lo(S57Wh=o-pvB&vc$^`e2mF(PPLYe}SvHji=2t5OjG$R<*@Mj`}_$#YbqsET85 zLet^ylf(6&JO1c*?!Dt9#qQs&*CJ;&NrsSC{^Y`ttW9Z}iK>b3nFzi;Q_Q$N)K$S7 z@Nbll4gW`TY_RtaSDy1=R*Dc&wPcd46xtG$r|CP4_LZjc)0PcFiK(GrCdxHmleKqB z=Re*3H*Q(j^}|p9*IypKW_Y&4Ml?bt#Wlp%B@U^j1R?niCO9-n0*w|oE#BM2(Nk9* z8SBu%yp8OdgrVtwl)65&a9kqXrUi}(5cr^BM*D1xqS;f-_Fezg)%Ej}N^Q4bCyE#a zl%gb5A(q&SDybpz61{?<3a}#7(ORk`K_7|!iJ&@_;3iNE!Ya}((4xXb3XKp3MX0ov zCnovxC*6&xipGd*2fQ_Ln#zN9x(ldI2{QkeUF%!2lCOJQ)3VYuXjR)bRbq=1CfCq} zeW&1nW>dlzG=M>zjswymroe{l7yYRELS&fHdUsA;xfg%^3MYpdX zs(zRohV}Kh5_MFg0tt|!ggB$z!Zs=dn~{wwLA}HjjF%hafHSaBH7GgCl~HNgZRlO@ z&<744zU_|Pd+wa!4(juG;ZHUnee?7at8cDh(`0$xaXwT;rqQa2b%T(h!_W+-LpgC; zOh6|2tH;QGqT8Y&sANuG;$bXIJ02xc0s$4!`T07w6u~ci*~r zjAPmo68pV_S!&o{++sJjSN-Y@D|gBnEZry1mP_nY`Jo|FYchQg-BHMgPMNx9ZII z^4$-0_J4ZkYrma+_34$<-Wb~vsE`Pv(aItR<(^0!J@5#bh1Jxo;{!rUvi~23wPyKhpK?Ou@>QEj$EdDY3}X{b15_ zwnv*c?^}G=cN~mf;wY?~D`)2y4&JbkU0ANBmk-VD``h33{r}=$|CCpk zcY2${)kz4wL3iN#Ls`i<7f}@yogz+Dg^EEz5br}Zno!5Oj#fIE-!Z#2Sy&!jMTh%y zOY`Bt#^?;829(IC`peC^v5pS*uGhwV_T(2%Zohu_uG{ZCa9dWKIk$1C_I1`}kZ5d2 zwoyEhvVlM(Dq*m(QvSk!|IC;E^s7Jg*S_23vAWFq6uYORtS}WK)Y+9w7ry%1^KYJfd23@8 zfH9P3u5NrC8Uo+@;DZm||Bm;)@BO#ke%sL_hYgXj9K~1Fcsw4ReEp3)&vx(LJv%#N zovB9U{O-Zp<>BhZ)#2vm=9N`tx%sy14;;E~@7_ImR`dq>%JSN)ubg=H>6e~+_Q{uC ze);U#3&U~?$gS)27Iqq&XY35ab#f)6%7&aZFhN3HSEKQG9AX`#Z<<=9NvSjX zw!=LwH{P1OUi;$D=~2J#S!k2$+eZ{>jO`Gtiin1?9_6OvY*t9G`CM zqqedq1;H3w){~8`RZ>oZ93@3E+yWEPmMnK<$H2`*kxr*OJGZp4wOab22tdJ7MwFB5 z!idJGKKQ1}W;$-6vwQDgbb0jJ$!8XKXFv5H|7EwE{ooIL_o>S#ZrXMKZ3o}Av9kK* z*M9%|-~D|*`qTe>$Add2;|X_p?x9(;?bNFl&@m|InYoS~$JMi=Ex&TlcijHax8C{M3(s<;g!Cn1x$Aw-4fcSvDPXj?CQHm%$6oS6`~XdKGT~FmOp9l@JsFAWmE2 z^hhSQ46DjD%30gVg4$A8!DI+LrM;0M6GauFiy4D#BwNt99anC-?!6|s%j=Ef%rL=6 zkXXYpG>VYJ&1RiJQ8bmGG(JjPD!O;LL{ zX3p3ic$2hJJ8wGsjF~60sE0vD;yP@*hAn9&NWpMQJOC=h&4>b6RKAz#M%G=BIdBgq z9n39ip3t?&!t!IX^ed(o9sJoP_21Q_E zAqp{)BCUb~v8)`!u-<(B$_tzjNM|Os_Zk91VR9&lRjKh3m7*0grgK@EUwZ1?-_G^m zbs2TzH@#!;6PMpOJ{}Q~h-bq=eT<=Fa|K3zBwT|+5^oZaT3N$p8iJ`z1X7>WlPn6U zMU62aG2|RrnYP*f{^t367xsMDo?D(d^T;U?HbjVoq^3*zjZ)i%Xi930ks^d)I#ev0 z`JU-+H)WKXlvc6viyNPv*)Rc(VUygdln~wu&{nphE$%RNFhUwUr3tb}=(+sx!qKLxE^J?2aQ&s(`Sp5qX1L|D zjtCkbiBr&*1gHTSHmM4cglT|9BLRjuiV%~Jv55krI6Z^0^;cp7fe}QYG;Lp7lC46L z`R5c$HI|Hl5x{E{710E)zI}H{r0W*kZhb+g^r)}jwbN<4Mw$9Elj!zK+Zx9)qiy{( zrKC@fTe{xU$0AZ7)IidCI!H{t#B^XVJ#T<&1lhOV5-T*h5VfRP0;hH!!o&nSM;b9c z9Uu8Q*m-p4;A<$M*hhzNf*M&FRBz7V}1nQX_wJ=mmqt^rk2*IJGzy|2%gP`jt6pOi zDMfVm{>2YnH@>cjTU9okxT`~2nMj$OQMC+X2bZy}Lu3&UDpzke405)}E{-vI+z(IF zktcNiJ;uF<^iJ%!KHKrZr9HpW`P~0peeu#TiQ)G?NZbDre&j}_3V#=V{_8aH)Va+`O?Yd)5rGQ zyl2P3eM|e!t)8o!aWbWhArK+N5Y;Qi5TmFcm_1K?`Ny{%2KKZduybx^ zXH`!`BzL*ZtgoBcM8n8(b|6RDMzvWsqwD&I8&{p$zN&_ZI7%QQBJv>wB4=%f`&G@2 zOwgLdUt@eHqDWK%DQC!ub%@cHjLtWgir{*t*K_m> zFjsJQM}L2|)lscEGf{#D1;IE7V$;+TgO5IHh!T^8rrkY=+Z4FBbko;%#IzhwN8Q&p z9GfvaX6Lfpu#+g`YUG@=d1qngQjrzgTifH|)`ZH*cmmSJxw-k-*;ijXKA4#)I$bhs zjVsG4NOZXaI7Ss!;~W`=!dPa~=)HvKGMBkL_&6DkCskSW`a5?YI(+O{GpY9<+IQ*P zn=d^5_?xf4eE!tQh{iBmYeI-IYK;Ew2OfOSyB~V+{s-@U;GV;W4jba__3dg>83VSg z3S-^U&ZSc)^UD{n?A^U<-~OfT&GB$`eDRH|VCv5FdcEHL?|PuqEbJoEhV7hXT{#>J~wfvm{pdULyWFCGSE)^uEMj3t{wo(&PRL}|*hEXQ@Z*_37D z%NXkznyCKk8qt=N+g2EFI|+ZzIQ;AS+W&LuF@4q)ae!)w(HoPI7=?H#$JKDYzpKc) ze%;heY>6h@rR~n`JhEecZZ0p(x#M3xaCqV0{I?(9*x3G?-}jv_ zzw+eG2kt+*bm!&sS6{pG_}~BbzxyLU`474`b|$0JWtllfv`F&0)~^TK(d+7V{jzwk3xRxj@D9b1fhr9m0}L3jPpnPbcK%H#ECPxz+= z&D2Oq04P|&I;B~+l|3TCr4VMFLaCy{WTvUMsg+Hou_0n^Nx??i6&o{HqKH~bi&$ax z-rH_oIbW}il}xU}K6sm1MnDLQz3j-s&U&chIs}gxWZ;Si4(#Zg?1f8L*GG|%GmLe) z16eXnsJ13sgyy=P`2+7?y6q$V>+YE?dcbL1dbGaq6~FP4Dc7jTX|7{uXSq`#)@m&J zeUuZ8l@@d4a`=WwNSatTv6x5ii0K|M)=|FBs9@%Z=c#EVt_s!add3#4fn*{nqeI4$ zI7ixp-k^L8bcks$YadGDKmdi~y7HxF>npx~n#QN>reI`UJx`^mDZrBh*4t3hL|hyk%HH#Du$FPsy1GIqm?FmT}Gp2 zPzHgBy~InC)t=>n?Qi=vPc~{GN>L(W7^2Z@u!cz`#E^VD>nNZoEL+|KQ7P718#SU* z`w>BsH7t+_dkar(uKnuc=YM$d7_Du5?d3~=&Cmp`h|~)pve22?Gry|}&Fd>Cy#_-B z(kRK2C5h!y8i9(UbrU5eN~Cl|X?-`E*mUx&Mq}7)!F*}$%s;#SoquWd$WL#-;n7W| zUqr+$R>`S2eya%tENnsfLbl-4PMUfWt41pUG6IuPV=Zh9noLPFne-|waq5q{1)+iW)#E zEQ%DWX`f0hLTVj|6KD_-PL1DS5J3nI2st_oYIG7%ry42=^GQit%{irhDeZO!x?T5=WgFgB_x_%r_{<79r$yg|~y>mE~ z=k2*}HK;_YAc2Od7MB5m1b_&lN*WD9AOLua06f)WYYVQzLjp)arVUL^ufsI;A*1A? z1er*cY1#{f`?NIf)hc`xt=h5HB^Z~d=jK2d=*F+E`gMj))K~U`|~eX}1&6EzO~o2OUKZLI&+ldpeExM%lG{pRHh+oSP!efTfk zcjv9&^1pr0p1A`kLcP@(W7bB?cEAVc_B}s(!EolRAt6@Ei=3i?qOO|$Y+(w`GlQs; zX5!0IHGpf?W;|JqQVqHbi*whHCd*~Bl5~AWc^I}mPVP2)cDfzwvhvF1m(FZm+_!jm z=fc8PMQa-yDR_%mlV&N2L!-*xxm|U$8F~2=AA4Una~CdM>2wC9ak#xM(zwi#vNbFs z1jBGfxtGs&T<_(lURxht_O@JJyV@z{yE8N6@fva5o?Kj6KPRfz*-oC5VIr}XqlAnI zQCCOHvv%e^$38e}wx7B3lyzjBYnm!qBPKHyh58sQn@(rO`n>YPsKF2=eoYEeYISgw zxUs?@!w|%Y#!0AG0}PBchKZuYq4-Y@KfPOacBtr8eH*eK@_Nm`X5ZMxCK@k6qDqJX zP;T9DqF!U5On0bj0z6esn3Bl!@&+L}eocX=)Xx$b<8teA>v9QDB~dk`Oax{kF7i$Y zzHX`zVjK>A)2yy67rEQF_rOQL`C~7={L*M#c3dtoLN&{rv(`5;M$NLU=oC%uMWS_1 zePm;@+%;u08jXVwGqdwI-G0}B>u)HB_3HA)s~1ile_?B5<#JVSQ9DjY6oKHjyYGMR zd*A)R_r3RyyYIgK@S&~k`qIUVPdxT?lzMS~Y5&2!y}`gR)m2SO*4Z0wysj$Ct5?^C z!-+B69b}oCn_rw?+`U+itFvd$f9Xq)z3}2oFTZsB%`J|u<*Wbnum6L;^W%TR?5EN8DC^`* zM8w(?+Nov>v5s|JZf31lTG2yEe!C7uF? zD5{7?1_RklzF3E`psG=Kklp#JMM#2$0>)C2Q!+eIRX-tBWzwwB?hN$~+Tsw$Myks}E98A6jn)?g zfbFpD5r9}JMb)5MibmC0@P5|oL5B%DNEe_vaqIXG`T5D!ugLhN$Rq6Q=WfB4 z6KpdoE5jIuQEJr)35b@>b+g@!==rO|tA5*OwIT#WC8`99Mr{N_4BB^{>*se&s`}0K zHMJxZiQz>=Yo!oSNA;v|CSyoq?HWUo0yGZ2e|hb6-(>~6AOWPz(nt-BN>M2iph%4d zjIjgPt$ec`Mzx55Eue@Q*$5v{sYE7ar3}uo3DPiGva^qGZR~q=r7K%sICC;$Y1U*z zMx(X?gYC}wox6ALy0W>PJQeLU`HqQHg^iV{tv6L#7Lw}=lPV-eXpl$-*0PCFlqtEh zK0RJN5mvwX$gxkpdir=1#Y}Hgv_*ZAI{{FTC@f`t?sd^4zW2F~OAtQnm@&Qc%inA+RAOFhN>+XzMYGx-Ei=SOL7=Ka)0h)gWh&sKw#i+2 zddps08x_*_GXw=3%&4Bcc;R>%COPHfP;WP05I`oV05C0$BDIu=sLUwtZ`D42)?#vTcu4fv6hLT+;JjfP0m8 z4EWY>(JQC*#P2CF$ii1j5iSGSDIZy<3pIgMV*mpQm2P*)Hc6PsXavfk5=cCvPmWU> z1F<1yjS=dh;hF<=JL^}4MnI6*>WPO#P-#fEG>n8YG8P)i_HD7>+HS0u{p51=leBm6 zbg+VUjuaDIt{O-g%A}k^s6~YkB}8IoX?gEV8bT9Qm{}nVRgD25bu6)gtb;rtr2Bzy zl4349aLjc7q&jofZC0E9UNoyXt_oT;@osaovL<1xUaYL;LUq)djF38T{&ie*Kq1jCXYUQ z{_&NIm#~%NXHHyw_{Du6{MOww5A(Zj-*M#ggQq{g z_Q?5_vs?{2&Kft73D~rxGQ$!@*^5C93U)Axw7n@iciO=ymY0V#ERCoIlM0k_b^?Oh z+~ysVJIV~%PB$;W6hjnhnlP)_xyLQM%i23wXQv+1UY(MIAvT7sA?C=Ivx18#RaC<; zZF$$u9oq_0r5)S=QQj&v+iX-oBt}l;gEW~+G!tz^swlN9I)&RQ+0L?DX`~oe>@yPw zgC;B>4vbpP7+LU>k(Qe=R7B7yk`xid$?K2FvF#E`qay+kg9w;7+07YZW=`Q{X-#u3 zH)KgzQ!W)jL~~;eoKa^fbDSGkh;i1E%36K-`@iF!{!TmDtaYSseD?gg^H&z;7A|hQ z@dv;0#rOV&hyK}b{^R=(eB@vL+rR&B{+EB-sBtvoo60#N)zxx6dObXUM9$W^n`x@1 z+v#S`jkd;%J9dmm6-Dm%I^{;Su%lN`!usl(byQD6l;|8oWH?&&zV3II=KA|=)vc=a zAY%dyY=hCIcxEKCizc zq)fzYLpQ2&OhkEZ1wxFno&d0HEyI$P1|0le+Wm<;zNHwLUwZmix0_L?(+%pG+7l=# zEEf`EsADX0?)7F|la=+*hYHa41_yxFcLAiyj4f@(OeSqs4MG(XuNV_FWBl)7^b-c!1^qoj943Swi7u}qn9xnYwMYSXir zIqO-#Xw;RfE2@#8GxIYNf)Bx1v%RstvU>R+{;xlB(=9js?9cvex6==yvDT6yfDOYs zW5@;{*}%CxdZEm$uWjlu5Sv|l_8&NKbl;)t%W8b_^c&|-y?o`undnPn$XeT$BdYg4 z@UDkH^r3g&ckeBC-MN3?f%TQ;*Izqv{P|Z_mp3~zc{8ea?^&F?zCW1hN{B+R&MDv< zKQ}*j3fF-89>nvi`Oju*A*UNG=+*+vg^DeI;#5(6!c)-XdoKm|FFu$=6#?`*WaG zdK-mIr}f5^>-P2Vs=nQ#zYNJLlEYefPoM^QB=e< zxe!$*R#HV^7*Lv4FcTAufGeqUmL7MvwzrCIKIjd$wl^hG=871NZ(>p88l-HR{$R!# zT)A-iiLZV3*um>Q{yiW6+@qiV*Z<<5ZEmbA&K@?DojUhYZ`ApTANm)6<;VVFm>Z0E`wYeR(4t;3KS@`6vCQujs~UL>T0DX@}W$EZ-Vp z?bR^p@I=BeG{JCGX(WWu+%%KlxwCs}Wq4w;+Sm&0L##a_G5HX|o-~L=4QB7$fqk<} zFOE*sD51d4Y!pumI$xVq(W23blklk%+;Vh<5^K%tR)ZNGK?RN2MAKn2962 zwDi%0-H0Nl^1sr?BDDd*Yvb66MvF{Tq9m6K$;eD(=J(HR-qxw#b@cE;FWa8DCohd( zt6|K%SKY2AZnSxMd%4ouOzUgMtgVSivOS%KdL%>U)PtxN%rl+-Ry8iAap(mJb!;L< zBDxsEuU~%iFYmeWHn(`ZS@!C(1mv`iK50hUE)P!a49^a1ua17*Z^LfYbANYu>)OOrsLY8WCKL_uUYC4^E`Wl^hK z1yK^OEjB&{I@9bLt&xRlOoTotv;|JlE-#$1Rb{1EYlsOFpElcsDWrOB&jyIhHF^|b zDl&a*6QQY~w>=)yeV*QG8{0mS0J2P}?B&)WH=&e7U`lbaDQmQaj1zPz0&wd9s49qW z$8`basi{e_-trxVz=?@r&0E&ka?L2_csBaIa`5<6h5{gp4V#@N?rFsgqYfD0o&DbZ=_&y##EfLCnRWm&3PtopA@OxoLePvm`|@lD2Mt({QpebkN#Uyk5L3GUgSH1m zm@L|(n?8a>jTX)@g$Ql=+mXnK1|cCv2;Q?-8wEidU<}?O{hAoB=7UcED(2s9`rlx> zpNuEJw0?RRLYfgoQ4^Ro2lqI)N{!Z)4m~E~ZLRgDM^iO9J4?oLF;njluN`uGJNswd zyw_%HysaEnMOg)G;5f)Gn1_!XdgvnumLBTkAaEL2emA`E#PU;buDsE#l+^THZ{JLB zuE<|lzS@K`k_TzfARs0I6dDP}!AA9!YGyi6Bg{#>7E}VLK_pPe3`Am3&j3^O5`ZWO z7TwHb0EN&bW&~gcdC`R7Q`@7nkF36N_UgBM=(?Lf+TZinijUmA@7N#AKKj-5Cq^qi zulretm`5=fHf&66ViP74Vn0~Smkv%UzxwC~-W*I`yJ*f_&6$nvZ+ z$nrs6pm9!IMlO#mlg9bx`aStg@9OOR#!mK-(Y>l`gtMyGgU(ZRHiX1KPu{-P1TjQx zm`Rw#Sk6VG7tc(REVxKwJH|@v4MDqjPU)Q5l2nLDVL-_!ScpVXg}BwkO_%S^1_z}# z8>({0-r_^w+@ITN|L{+mlh3RXjD!+#1NB<0w*j%1B&MsKBodJYNR@r4M8Y*X2NAJh zff_c3Y`YdFgbP-p8rGKA$ChC&tmBM=VYZpgGRlk^0$Y>SqjARa?LT;jj{#PzjdJxk$aSeX&!_Wo{-j#iUwp z{74a)TtwK^^#-GE?DSpkwLY_Ua;~0V?Cl-o3sJ<^b&M(1jG*q;1NX&IzC1qn;afj` z-Hrpl^h=+D7R5|zNRxS(a2 zQ{B{}=oY;q?~W(ibu(@uVodo?NH&YfFiBfwQ#&LVP9}2{EqKY!Tg^sNDk+2vxjqm2 zu2-8fh^LytaLy65d@Eb^&pcYpHEl2LzK&}h&|4fPHrBEu=uJKEm*^rt_g+897Iva!b5;G-yKg*DDJRU~2K$XC_! z<+WnA==3`K4<6pRW6xlIers+0wHKc_f9{plE0+w#tjI{%M;~H1cJoc&{NZo@!292S z=l%EY-@E7hnM)^5y!Pqe`}D;N=S1bmbvMlPX7=viQErY%$=6Mc5`%!1iHIRWolf`Y zv197X(e~){>9dbN`uHP{e)*~ApFMNxa-)H5-@4w+!of~&X=Y(5bF*2eYck91VqJ!M z8-BAa*SEKpC*zH(-frrNh`-h*w!*J#^8ifi1AS{s@b;#&Wp_h4>5t6%4Vk{8> z8Z{BO+t`6Al78*A@O6|i)hN=i$(UUfKWf$sGgG)88K!6$QPTOPn5MdDX(g@Chfb?5 zv?E~^g=JrX{osXoe%ua zU-`w~|I~kzrkc9TffB847YwI@;9$fJI%W?wYcXS@u&5O^6C!ZUC>585Kz;Fsl&S!6t z4hU#NFRxX1Dfgni6WW@vHT8HKDxt(=p*9Uo1j=L-LTZ@EYm=kzOi{{+n6~4_!~5RX zcg3rxhI97Fj!v)dNUNAxS5M-F3)QJmS6+pz%N$3ZRI)J{)lsd@eXKQ%b~<;%b@tZx zFW&IJ?hQu=7~}M_lQUl~hc64ZxiI6L15s^;RE|QsJoro+)^?(yzRJopT8`D0f1*U$BQ!@x} zVEM87>=X6nC!3YyveAH1bY?nS&{*m$i!`UIq#cSKjDmWjFbH1D5Et_7oj1%b5I+6N z#=1_F#F794iIG%Ih+2nGgV5!Huj7g33m3*KYD6eRsA^CaL1?5RQe#9!+dvn#1o-54 z1AxI`H33iy74i{HpxSGlw1yGUP)h|YV+d6fBoHYlzuzRLgl4dYi=d5xb!4OZsFabh zWF!VQ`DV;D*H1ifptDQ2E{_*7-F##Hl6E}1tJ@dX%GFUbjOv{wAC;6Xry(9!Dl`qO zm-heZ534G=&fU8I=;`H)r#4p_4L}TSAUizsmp4|r6=uB|zz^XhdFe@_NeH2BgEAEJ zZmy7S<;yKyFSQI1V+g{j)gmHQ@!F`mWOg8}e0!?NBS4d8iE=mwHQG#PZ-PXzCuYq` zt!~q$f3fqg-nn$cf4K0QzchKO;>;P2>KUZU#0ghR8sa33LTn>84Uu6aIkd)FFkY!ABSGWf+G*`{F-`P-3){7wjIzpCLF-mQ3S+^k^K6AWDTPD{)OsVK zWolnTGE%lk!aFoQSxH$DM3PomfRKEJ005$`KT3LW!`yOelmJ*Z7KUNK)WqO5T=NTf z+x$|eASuaoZrL(*(hrFU!eB{RGjFX^(|UEfeeg@!qsKZVd}aCA7;xi=2~2B^9u0 z2r3a8=`Fm}Cs-d)Fu(1PL=|l#a506s(*?)rNsbsmPz^+?ek=M>U9UwmW62qIlt>RT z7#JoiN+JRdI#u+hJvW5|CPY0-AY+ro4HK(~z+~hsQpjv zuT2#xLUVMso8k6kbJoo7=j4#NSTxMF?1qso#}tz&cnBVY01z%L5JFx0+7LO)>Hy1G&*fV({M6a4v%fL=#+MJg|2q!M zegoZjdwqHdSauJ zio$l9sG!i)sx@&^Tr(v%7t=Zbx6$58Ovy}GlAD4v87UjG&SWg?*g1AatzpYB)*1y? z%eD7EbnNimow5n_w&zLMd2Ht->c+n5nT(kY zfIRC&AH1&(L)4e`7S$u?dU-ZyO;Od`UdPPNsu^Qa#xhgKlt-#pMx%{#byx53%X zU#@S47=dPA|E^iL@Adk$X!j%UfBzdNmtQ{p`ux)Tq`4x}Sj&c)Kp{qJP4LQAx<%ht z95UX$XQ8Ynmo6^HjC`oaot(C-3!p3%To-^(cyu(MJufTB#j5a=Z7p z?W(5LFtst3-MpLCK(%>l zdLp*gWX9%MmW#9*0&Ez7%UrVMXJ%)!X3{83mQ#`EP2)vTjwV^|Y@US>gTUtf$G-YF zB;-Xm?H4I>p2!dzCI*FZIq{oyZ&2L-o(K2t-8Y$(A^58o&z(H+u)-obH09I z4IC_G<=79m$7HnI?G;6qSkK$*8!tTf{L3#q`}C79ymsP^myf?*`o{J;#oYe6?t*be zmi2nGi{0*gr$0k*D$RK7>SVk+8eW-sRGN5P=aywT3fAnba z)z)L8&0$UqHA~s-yqL!vZl5=)tba|<>bFRBsHZ`we?$yVhd-0DMJeZlQ>aDUK-F@J_Kl%gz{M)|!;q9_C7Orb3GDVP*)=@1eCk=>M zq}_br#>1%XkN=II{6Bu}7kZd|_uzgTdZCg1dg$29?W20_Gyb=p505DtZX*pMA!$F} z4r>b$w?TNVeMp)#87NOla;-Ro+9p<2Q@UfS(L|vJtN`gX;!#&?Yufd_**^3ZjOf%9e?FFS5>{ANiZC5AmP9nNl0$!q2fHXtB5D{W z(`6#WNeE-%2@GJm)^wRHL&YpHSmUzS2ABiwBf5!k1M@DDd6IU50@_6Vc)a*nefE+1 z+zbB7P{sgfHtXlk*`bSKbh9d5#zNgnWyIK4X;_u1453!3NegFZT=(4i#v9F6WB|d( zpsZ}*H8e7b@B!W^1M&R$(quGhs4)ys3=)_Ck`ODQpd>*>5kVqAP&H(TIRZh%!7|ZU zYDa?^lU>#AMyr5IC`81h(3PpUKSG))q{Pe-AvIxvf)nnTB8rYvQH02pvLYoam>8g- z?(AfAWxc#^SAWKa2X9$Ay;1(w@^<8&l1|EPV$BFq!~jr@q6?jlG45(Pj;-`EsVD&= zCS~R*Iu2n}PMpn{I3fh`Eh?jMWH+UGX|nnkiUS|jrQeHdwRW@Ahbf?>Bn-}w4|uLa z-AX2Fx=~@wOhyyo9|Yy8YY`EeSS4}@x44^5mlRc{2r@8p*+4X|Hg!zR6cG`anAMJC zd>{7y_>mvHY2om{JM}+)ZS%_w8%rD{s33(rC&6lR7;2X;)oE)Q2yDq&HljXNI8)$T zQm-S3qAgNYV_TsHB&`QeyPpZ7g_$)AbKO}V%i2!_YB=FSF*zOyj8oelE1L3*&^oiF z^<2=lkrB!0i=>@6Q`1s9kvi!J2qhOga5C4@q`^tRJ?wO9=Eyl>%eINJiH+9~r`>k? zgG@{+Ox6$w38Kk0mZ7N=rfZuEQ=&s(^PV7`GPd68asSLDbh>dU)W)hJ)ao2KH_DQd zgA;qUP244@5*tl%Uu=mPU{WX=5EB_~m)DpY>M3Ofty!>6OJ}qO!rC6wL|lnrP8iV? zD4se(5hrCfpg;jz0Dx40)r(JKc$E%4MEl;M``&@eui(@ZIy^@@fks7aNxW%U*0+u< zn2Am6FU3q6fuM-0ng-g}I%iHFUu3!i;@bQGZ`qqGW6}{kv1;GPeXP5smE@C2H8_rm)Hck`NUlBt+uHSMUu* zSWrg7xN>@2osm5+G<*NzOz)c=Zo}a3_HVtjzw6U8XFfT6;q}#X(U+D86jUrx#u*_h zjA1*DLxEUg(P&|FwjzFlkw!-oJ88PPDM&0SOjH--SZDseBlEXEuw(zj^Ed=t#+A>M zpZomz$If0}2_+eH9W}AaEVjzgdLx9WCKe_e%R~?itRTeJ?#vNoQ9XkVkeuALWzYf; z!<3Vo=(r5!M7JWUh?=M{%mk4T8VE;c5h8ijCV-r=O>Dq05JS!u?)doXxv!1hxU}_+ zuN=PPFAQeB*S_!m#lyc{Jo(3$|8!;bLas^3IWed@=-jY({#{36X?kbZd3$U}V=9}1 z9gEi>#yFQ{F|eV6Oh%l=+BB8RB%@dz&~Wdu!JXeRyYwwNjsg|%lx%%Ap87&qer4fXR>RoLzT*Qoe8-2ohkBt3^v>J6zj4#j+Ukl`QI?dd2WE|qiOGcM zl?_Q$5V1jwp@qMc!A4<8nb{eziZUz_Gqa>{WiW&dTgwi@M26HDb~)!3j>R%tL&liA z9+t|Jzy5dbS5gzvTx{m@jx*WXc;whq9_Nd>tCv^4_QG>}&n{el@P^5Vu3T9@6)ttr ztx@&SA=DRNxwJGtuPV&SmV%eebYOIG&(5ec-Wy&{&Wnj-(=t3^`Do#H|b4!$DZ;bvlfoh*9N+y?0Eu z%Jr@F>pF+7-*e#8pZ(luytU`n9joV8V^ii`Cn6xC5S?*Ng3cFC3o z{d_oD8E!9=@y-|^iU<>!IZ8-cAdyILh6|$dH;?~XuHo|bg^taXSR|;3vyQZBg1{Jw zF@;B~D5v6xVv%>4OqO+_vGKK!L9~t%lK)n_(Y`ebB?iZ7EN5o2j_Zx35@9vg zIMamCo#}R$2It?rz=k@#Zis5Fi$3|sV_Nv&8X;%8AGG6_w3HK3x|o>_8*6Ot@($D} zkmy+iShk|kS)-BK={<;vU9S_PdLMk<0I=4Is5Ft7RmfOV^!ht@?R@FQXQZXiaOO;w z<>TRaqZ)U6ojv>a!t;agdtlH0oiBXtsW)DEer4s#_T~xzHUJPsfq45p_kH5y-}c^z z-hJmi_pGh1zWVaZZ@l)#>e@>tq)EV?PmN&0nyfQZ!Y%Q-B{m!17 z_b=>RoSo^rJOlLHne!)3y!PU=FFg13i!Z+P^44%vPN+LSx3KpnSGclLo6ihp=X$-F zUbklpS8k8Cmrsqx8|7$aJiIa)t~FuOZu`t^rt|icCP*o}O{at2R#t?maphYlclx+S z*uoUnOW0N0ZKiSX+n$-4BWjr$shE^Mt6{|y51GC)R3!yMGDo4PO&!KWY}f>e1hQ;J zJ<`C-I??EZ2M91ooG*Ht4F{2Ej2a8>7|JE8kKz%!-i}-~7SnzHnpbzWs6})?w0AH@O@4cdk1w&wQ@_)r)wI$g*aF zK-a`m8b`8wJ3Qe6PfY5Go0~ zbnby~xb08=;7lCPwI_9SQ90Vh*?hKuv9K;?19e^X0lpG;F)Gm{sG1;I(S(<3f;7|2526u~$wW{BKc&6bkeF|zM3h9f zZ@Emha+t)eCI(;>vnX<8s%F?s%DCN-H(*X@U1b`0EfHeckyC0E+WS3qCaP}@sFE2) z5V6bvMYKUH=~RU2YoY_;rPD8`RI0Z9nKrJfZ85;qZZyWBu$Aj5^4NM+UpRqF&*9KJ(A|qY_kdVOm!KuIQEi|RlspOAFh6C2rYV(C z1-ud@L9FSo5Uw$DNks{o{A~c{l=pIN7DQ7YDJVoprHxdDLP<1&O-q0$R;^S3bx;tS zAXSi1WHY(#HuaE*R7s%Rh673R{ZnN_tQ2GNI#f7zDFP&YE=x>=AQD)>2vIyqBv=C! z#&ho~>((=q%O|THpU)0_^PvBY1wMeKyE}^yboP9*`}&tQU%a?-0UO)4%!#bJ2CNdD zvLb?bf{{QoI8|8KoE#wIFsXv{97Pe1aWDA3ojdNkZ}*{h&$`1Fg3+hy<6qf$9AUliVp$I;!{O%LpR>{YcJ8_^gIkj9e+Hk^Fr*k&5z)VwD$k+hU!3pfH> z&Pf<4Xk3Za5R6M+*$Tss$&fHp#$X76nP3?nm1wZo`n}rymsB5LqGhFzWYD@!~gx}eYgCbzxcOoj!SE6ubn+V9Bz-t)nb2O zf|=XbcN4MEiI8Dq$kh`+(;dt&%vEJQ9@fiemzVbTOhL`44&JljAfc0YLqG`XtP2q# z27rhRk%qPh;F}M=dttD6`pUCG%CtWzG-yoSyT^EaG9Fer5eb^b{JN|eoY}rOk?Ny2 z-?w&k^NABr?A$jKbvT}^8^=jylw}q!^FHQ9mfYfYEX->YH?MBQp#7a4Dw<0h%T+VB zUDhZPh0|WD!c0&!!CT4>?mQN~4{Oy*SpK;ee_^ND<+8kzz-)}M5>rBqdhZ$22n(8~MT|nBj-1szN@Yz>>>3e*?YbTr zM2)%YHBDe9XEWcFik76)P6X+#N`2ZRT`NWyu*O(6nK90~46sbxnj0(Fz@##OXuLf! z)^_{75PT5L^Ss+Bs?tx!rLirg1xmhd@{Y^1tSrmn*7o7+k9N8pjp%f{RapH zpm*J=~rKVQKDxiW)e|}*t>WCH-6JcKJxH4-gV!-3kwS; zUOn-9zy13!yzumRIO%1x`;Y9InVof6KH8X!x5^mni>Fsd!>Zfs47!8c-gW2V;*P^d z_7m{to9CW;`kCjRdiJTOpF4N%!t#}^e9*IbZ+7=hJBwKu^0jAYXH0Kqepjz>Qg1F_ zJ+-=eVSDpRIo_(Ok)kD96LX@1q-p6?qeJcZ_3fR|HF9a2O!@U)Ws9S>=i=J=Xv4?e zdYS3dr>O(!gi?w!1c8W=oJ-%<08ihOPI+9aDjE%2WAYelFJmLlaz8nL7-k<4AxxHG z46Kk&m03J3kXjsGC@Ec|XoOC0Y_-- z6pG|cGBv51o)?{p#W0nBQ=0&ZMA6c=ihk?lB#N9S$vRmm3zWdrnw^FmvoqOJQ#HA9 zXZ@*foO^KB;_M^OKV8II5KZmH8Y{$Ek;SBR%G}UT)+QSn!j1F&``^8E+q=3q-#N1| z4;kUq7lv0Jk+s)=5-e`E?>adVi9}V6)@YF-%cvR!sU$Br%as|H*;w_Wku~pQu!~$* z%C#8BYMrr`bR=Yu%_R~pNvYTpL}CjaD|Rb?gTbAIL!{jVFAxK`is6&~;-l52FZz{N zb!CDfQ`57WQ-F?r@F9?jv&I5d6-C$)?O(Fp0;}6`8$rNT)x;PgYmiX+D%kAGIGh}9 z*9c4;r2$8;b?NKKUMRGgZy=8uERPGG2OJ3l%h#i%jBas zD%Nll^RKLp-m~g&JvLWuuFq$5*vdv66L*~@l4wbtvrW(_u*N`W?8~T06r1`;Ni=mY z0i=pZL=y>+khYeD+0pdqSaut+e6?JCc-MiyQXhMH?S+--4XlM0$Y*(wp%7pwTSFZ+ zXiPhQj|#k{I;6y+l$MMzEfcTxI!GT{6^a1aY_@_%nVQNHz-q@bdDz_YllT7cZM%;A z_%lEIU$6c_Nyx~B*ccdwN%vzS%BHbG0wS4_EO-=TU=*u5ZGW7a9mzyqNZ1MO0WwZUdeC^rrr@tTHd>&zw z*^({TI0*`3MPN3f0hE$|+GP|FA~RL3wByyc5Z(4YS~6BOs03mVrXEW~Z5(*Jy+~_I zNtjL#-{v}%fcTWBszPkq?b9%!!OGWkc46%8f)HnbsQ+AvfYO8j*J ziMHV&^cD-Z9Z-<8t#%^cr&G<-aYVZH+xvq=1nmwls_mvTWt6AZ!L)FMxfYu%b=1Zb0vG}_I|z%YFf3VasSq5}5D4%oJDCASr8+Sz zHs2hV=l*1P_PLD%e>6Dy@ukj(9DN-7?(FY)uzUEAW=?!<^|_7n7qL;h*ijP+LF26H z7o3|&9v-Tsw!=kEnHLzcIb}Y27yV5|@$TDp-}1ht*`pnFc>GfR`d8Oqes$xO<Of7c6HlWEAAvE-M#dn8#;Ac|b1E2}fLMzsR1TRyz@iix;DXQxX9R*# z?oj4|9ECzG86quXGWlu0{i{!vZ=M-F z{M_Dq|I%XdQG3_TJ9hng@5WDWd~tc=f!QNV*?zZnHR$6d-I#`$`60ITYNCb9^fQKpN?m~*qnZ)I(5}gEXN-DC6pBb2nZqp z5)q^P|JnNQXv?niJ`ntU-`@M2bHlqY)vH%I00k6sBmpph5flSRN|Z!VEw^N=ZL7yE zx4Wmu?zX3U#%tC%s7I1TOI9+iU`e!SiIhZ&B1JHhAVCm;Kp~@0xn5Ph9Bw-2?7hEl z{@CX}aMl{EMFOi(c(3k#_w4Zdp1t;`Us<32;C!zgmey#i%20H~6siT- zHCmJCWAI4*#Kg=*pxq-_m6$D)V^}5!oe0M6J9jSt-W%DER;*EVl?%MHuhXRGlb%WUb# zOes_YqS3k5c(Kahc0qH5zuiorA{?E{|7E7&-R(J&yQ0-M=Ahxcx7?+nM~RJ#M_ zs9KGyx~!Ry&+cK zdVI89iDG+et0?latOu(*-dB6(_uTo0JMX#Yp1pe)^W0v%yz+(5fBC!L{O#`*`m{Gv1KAZ*zWf?&Rtx+xV?FCYjZh-@$Mbp_=nOg zB9j|+f(6hdl8^~a!#pLesi66l3EE8)3>pod07_}RsS2GMoSlh)q|j>Cs+3X=C7s~y zjRXsTrAgQ+O&*)(kG=co5UEB18_rc#q^@IWxyZ7dMPiJWDJiC65GXn0g80}ZTT+@; z(@3eBqOmn<0I1YhB;ZLRep{n6IGxy1vA7N0-+#D&!t zGHVUz-jBWa?|kz|e(U4^UQXj1fB4+>2M!;;eot7EYEx;ap1-#hB|s5ljOxj_qTPMr z^UwX-|MBlnKf8Q$?~Sd|)K=K&pmp2+JGXW4=Uc!1c=?DS%F&sCp<{Y+f@ma)d7MK}Y#0ZWV0%SpU(7-+T7y?aQmC zmCv%}Sc!GHAvl;IVW;Y^57#V4cOII4&yUUD`1yjG*}ht%w7JPz zZ9~vv3Q~(kWCg(Jv`weYA}T@h7Ko7*+U^-Ymf)dQ+f$g@%eF<)i(xV?ljQ~xS}GeN z!y1)F(19w8IlwqZxB+z1;uxeOl+1)<$kTE8$!h64;p$UimTZVRU+|GbZYSu~jX2^UA&zSgD3OF1GT_AinQ6=G8-rj%B?=8}RU|}s zQ85;P`l<@39h+U@eR8@6sRZ6M@;INle9zQeS=GaGU@Z)55J~MUX-`ND-B9aobqC!1 zdOfuiueP}x5tSH9hRMeiiDH1*Xcs50i9_A_yXKEy+gw{MH^iu6W*|ynvP4kvOaj#q zYPP(r`RC89TJbY+JWce$WAiH)R#(&!8!)WE5HTAe7&2AVf%jyXQ=p4BOH~5Ja%Y^i z!>Vkg0GjkTf**=~A<|O#OIsUvxQi$3o|{a2IgW{J$M$Bm*S2mLM%%GpY6XH-1Aq{l zo0VSIwx;|ffYROt1#u&DMYG(hKn)o{$69LQhDeEE#PzkjP51x5Zutde1}h=y&B?Uy{>L z>*yK~)HpU)VSzx*K=OO?MBEEvP7-2mZox1yTBNlNUi!j!-^fu#l`Z@+8Pywes z(xg9f`uY=AHa2KMgY!1jt3si|WMM67)ZrN&GI6e)s}|4HTFTCfjKFR173=6m0^SOZW|n znNrrWKyiAj|LRw_UU_Eo@bTjtze_AkfRzPIw^^H*NFwzCmsy67Eo z^OvgS9j(Tp0tMwzN#E1B)PW%e!dM~@QnzxNaU8iWcNEx^Z3PDkX&>_%Nx+Wb(($ZH zQGtwFT_{M#ItUsfDoj3(g5cwr4STITN(&dYWLCg>4VLrZYqD%@Rv1@1{>tjLGk-pO z*K>n+JiPC~L;3!{*Z#om`Jt~2pEw&{?()SeLg##U({zw!q7=LpCgX^ONQ|{?9MzU1 zO-J0@?!4pPxto8i+j@77>w)tqf3H6G$mr##<+W=%FiI_FGOlBpAwq!&)LMrS;G_CF z)`Do*cp)%Z>x7&MzLwy%R*Ik|aHk=bBoZ~r@(NAeGe{bBr2bRW98`^VgjFMPU~=So z`OI~&t$KTT>(ch`{mG@x(7xqH^OaNMSHC)@we3JPYO9i)yoWf{dLR-=ysEOz6)Eu> z(vZMb)eu?Bd7|H%6;4GJhFFA%tR+j4oylx!UWGMaOOC}Dau8#fbf?4G^XojCI1^DkE=TxJ+#VZfYdfhd7g zDJ2DJBqEgv)hNMIwz7R;V|&RmS+d|L66N(sRch2S1R|NqPt5lYzq)$KhW4@E@jX+E zUp@ET>F!*pv9-09JFb0gjRh!1Qq@+T*Oe!>5R3;St6gH6>gB70<*QrgLAA@+*R`lx z!xAC@Ya9uwQpMc!WW? z&)s>?y^p=}-JS79ce_*hvM;`!w>X>7Y^n{|)@)cwu*?ldXRI|&m7H_NI4Gis#yZRL z^c!LbA~ACr8z&(KA8x<>j_&OIAOFE0Om%w3Ab1&%DurZ4URQycvceKL)`6^1pjG5H zWE)r4%8~Ey3>Nnuy7T^fTJ26=WM^M^>9I#&xNznyG+0N@Iq!Xpaqq&ucf9i*ANs(D z?tS3C%$OHmc;U;BeEs}|O9-@g|NNnYhl--LwYjssIW&f%r&!0WjV)3=eDv@gcinl% zowxR;ruOpNy9>#2bu}2;YyqLJOQfQjJruE1p=Ei zf~HHdfxwV3-t>}eE2ti`Paj1@q54h z%898XbJMf^WiOUHcanOoSG}|&w_-gmyL)>;_Vs`NmEZfd|Gacz=lZETY?-fxm3`*G zt^4kJMW6nwwf}tHzf^Fc(156L0=FCN-i#Kz5Lly_Z{*a}xXWmgRl*axym5pj;i77s zJdVs{RVk`iGP@u_)CjnR{7?*$IIhdaVcq-Yx8MHzzx#5m_qypE7KO<&!#<9$?yPK$ z*IKT+@0OV#`S8*E-m-7+e(s;HpZ~MXtB;c`TR#?)p(tAIt_>rpOX*H?W*a)7u4CSz znOW1yXnQjnf@`sDQ>zEp7UkealpFN+nPQ&BiwxBmwo{}Y>XqA!3h`Q$2)mc~HqsLY zN1z9o_LFABDJS^_Y&`B)zEf{J8JEw;zs+P9KBlhY;t%0E$wes=UZ0GjF)0ftkx8r~v`{*5;K|o^}g6V2Bh^m2#%G&Ai5OsF^6h zJ$hv)8})zc$q#e>J%E57{Wi`x^y_$vbnwaf~zqMJKNeXQA>hh$V4QO z8O0crBo(BIkX8VstRyN)<73#WYLrB!QYx*OY@s+trLp$Ym-Y~HRKIWdehVYVAv>|{%t zNPN@ngtR0!m0itc@IC9VoVNpmq*4h)1ae4&4})Z^zJeM^O~p+- ze=L>*Ew`wwu7*AO+NXv-HL`kVk__Hxgh<|7-4t1{fBNyYgV2tgLL3-CG(& zy2+rR-Tx#NQ4#={RQv|@>1VA{iv;4L<7NwPhdA=;(> z@buLuE?j*rZiBPAZ0d&j=}xP)erZ)9wbbB9qAED{s}sNsF^@S;H_k|kzFOosuZi5wtij!F!Z&QopF9N1kBn}48*HZ0+f62Q#N zhzc^q2Ab>vL|h>2!dNznD66mSeDcrM<_@$suJ!9z`Xpn?Y6K-MICtBL*0Rw+tkxK7*@=)*LqTfV{^-Zv zkxl7f%9(69+}!A&tK*Kb z1et)4KB&T4LqsYh%DHhs*y(S@7^e1gXY!edYFrIOKuur`M-etAH@S~>5XlTP2uj8= z#6}+p)a^_auH|D$=c9-ak+DWKiiD~bI9PVhww-O0Qe^?wI^;k`raRZ=f>w&zW2obGgVk9v9ZiXM3Rk0RgJY^ z5R75A&Os@JATe6Qs;VLk&a)hhVZU#T$((`erSq4r&pYj+Eh;1_;T#+Vd=`1g6%*2r@#2@lRtRv#nW5st7l$0wYs)+<@`nKkQFY}v8<}xn)~m6 z;Dhgb_$_aH+s!xMy0*6d#AA=IJa46I$vMi91TmC*?J^p7!Lb` zylCBi_Z|1#bN8Kh-(H9Cjjw$DJKy@&cfR-d3(vi{y0&F)-kVw2bMX51RIk zj4e^$uRXK$)M97xKx^N?SG5lXIwIcYdvCt^_Pm>a_4&U#zj4ZC)>u>dD){>S_y6dx z|LTA6XX)#|{p76&Z`sqGTf4L~ePr5en9j3e&MiN`;*MbYSg*Sne`Zfcg@CNO9Jp|{z81#gRwRl-wNF(Il+CxNO0Q=(H$ByWQwp^P zky^>C1*_H}8p3S5mz!)f9t9gU1dlps4H84DgpkHU)veLyF!a~PtHQq4fDjD~H3qY& zs+Ncd5eTZ6!(cJL?k%0$zdw9>jVfgqDHv;Sli+64fEoeYNAZ&Onq)`Y1<-cII4a2^!j_1F z#K|_dD-uyk`8&G%WhPAD>t|Z}x}=H>-8s8|TJ~i&ABK&MdUdFq9wk97!V7rzjJ*6c z{LMY_zK7_+2kF5N&^tdsE3fj`AJcDqK0fnktowjB#SFWGC@CQu=LjeRJAe=ZKp@-v z8PXqB1R9X^LP^VkrE#oU=u{9=po^ediYE{&MR>1uUv_FOwZVZjO()DIY8ArR zl3`*+ATkBFri%HDi@FXfF?b2$0mB4AFqDOYzSmzn{b+sn(!v{F>b>#DvzZU@8`f#x z_u@?(_IsD;+D@#4fyo2KD3ycbnp#!7!DYAa@7;3$+_860XYXN5fxoNEe;J!`GR6>CD5`*sAtF{|*jX47!(?NGWn+zX>X?mT zV<;14%a+s(MjJ;DbRPPJVm%$e%*@6RqOc!? zBBvhP)#24wtFs%_-?oD?j6QthkG|)w_x#eI{n{1=-R^AWxE}kW(?YFM)6{fFgIqd$ zB~Z;KR<#Ex3K>TV3En44l`TYjNs^`C{>@ z)6ciEe6h9Xz6Wl3@#W_nNqb7JY%F^nG1NFSff$uxVutjG)|D};#zD1HXv?``JT8%iR$c_DYVV_{v#BEv%*HS)ln^CG z5LvcKbR~j3Yjs;wF-SG8h1433QANdAXP83_DiXzuiZxcnw2N+Ms=d=+-PpO3Ak~H5 z{-cMFAG~x}x>-;O2q#WlckGD+{b!KiR z#3(@(WHYNm(Mz5?K&z3@GdDHUt47teE7#cSop;~)k)Qm@1N--WZ?t~?+_TR;vlV3A zD%vyC?ZId`8usVs7vA-*cm3Fpe(1jY@1LHUdHLm6KlRB^J^Rcv>l+)L?$oj4*Y$eS zws70)n+jj#c{LiZY^;q(gWlBCL+^Xf$y-j|c=O4#r_X)jw?6SVfBS{+efN7S>l<0o z>9l7L9lI^>&JwqZqPMv3;N0SY+4(sY84cH8ec^@GD`%H3zIgTWIUoXHW0*L}^;IQm zOv0;)-U?0VL!-{(=2vI}RT(B&Hbx|!52^TM^65?v7@nlGeG*YG~{BkM5#&?&o*Z%B#uYbdgh9joAUKo zm57|BEWmq_%;cmf;|L(jP7xE{K?F|zKk=UHj2w|!4cE$@@pL}lqE2R}*1~2lcR%~K zzcXytpLp!!=Qp3raz|hv>fr02c=N}8^*&q&U9kRrq`k5d7_M_*ojz?2GSlPMEHMbB>9>g0T+;i{!v)9ke_P6WT9^Ja| zY{WoYmPy>)J{P?qPot5~I~qek1p|)h$Fep*KDk^c3(-Ru&A(VL#!|8D8r)S=DlFuToLQ&z1KihR9{C=2-fj(peHVFe0cAyaJlzL@xkMB zmtWZ#`JOd4DJKn64K1uyky@m%Jl}2wv7?>sBn}qHD1_jBat#RttSP3!@FeV)NF)Nv z#OpFFJK5XsebB!4?Em$(Z*J6N5z{Lo(uu4;GLTxW3^SC2Mg=TcO%N49MVUA>mqG&W zQv{KMG;OviR)*BpQojL5{Hp!E@VyqdGMHVmI^|+9ufPmiR53kidpoMRK>EuCYUPSf-)A_71Lj>w8?Kmc?ApElk`1Kd2$uZKIB<|HQu z$H|#Ki5)hn$vKg^$)uXDfW$X5O{AdI5VxukL=o~s5@mL5y#%je=u3gLxM(wROa?ZZ z$U6urExCah6Y{94CJ}I{^A^n&@Vca@@wQ^3sM(c#G^bf|8oOEAKTn4`rZ0KxUU(L= zVJPFQ%{Gs|R#m7~%D@I%gGo~gsC61VAYh@iohFr6!b4&p;>1uB8%=eo&5dOUQE8$p zHfGYIkRJGy9grb!p&F%QqG7tp023co>QE)tYC~2w0jmUTp2y4y9DD%v0Bf)4)+?wt zpn=lpr*Yz|p8QZJpk=ChN|;Gvk<)lO0Y7QtY<-=>PhXY-yJR-+Qc-DqZ(BUuCbF-VpbD2&Z)UUOm5a zc|0(#AmQBDp5x>5?VI1#+y65iEW$q;Pkrjj_n%&SVYt4HvbNE%gcvPs9m{iTtAWB; zDh34vkQea;WpJ3_y`su60D^h}9FZjkGJwW1vS`imbWmSH4cS_BxDppmW4u`#F@?!J z22~gZR8hUaJL0IKs!9Stq{+l1!$uHQ2;{O>w>1TD>1&a|a8M?Ywd|vKgm%W{!Zlw# zvO2o_cuRWj&aqA(!=d}_-dS^F3*Y{_`N7I|$VDjgkyzqlz`gS`_dYm#^gUDAn={M< zFJSF!)yrS2o_%5TT3L?rNNpR1qJ#*EFbp!pq*^IL%9)G^5j9kq$ygGj6jFe&7as_0 zGn2F~8dC;98UcwcK_mIb@ty?1>11p|I8xF^l44LZDyk4vDQFlswCN}d-(WJru92Z{^<*uZ9Np#(9^ zhSd;A1w>?xGh|pDDH}GdaWky`?1%1Y?>DgwZm6^r*PkxWo$23l)5*`Te&@B-)B9)k z?u@0^YRAp02-)85Ow8*iH=bSgOB>kfV{IR1{?R*r?%j92>oZS%d7C#2+m#R<+vt6F z&+K5e9uLCeu^wu3WiT99+d(~`&e^i|qDk)Mi4wdLRYfFDj%ESK+Crm<)S%>CNW4|@ zt0&iol8UIj<>rUaow;0%%HxMl9GO1SE!_InmHESY75eL|Yo;K>G#=NMjdLcbB$>B` zi50q2Q+a5&Ot-{l;DNEq#7qx{J~F~G*L@!F&uJ0^m)E=E~j-<M{sNj~&1Nt@rhMGiOe}`1}9y|8wEOxy-qCI~V2Qa4;?h$BrNS z(8E9aV;}jk>u)$wjmuL{KljY3Q&*O*_$m}x>*P%*$Ahx0N;5V+)0^&fH&#|QwziC= z#RL03@)HkVf8xfeUiYc*Klulr_`R=w?Q74SdNqP)_beVhdbHi0iP70Co7%JY(2)~| zjvUX6Z0W*lubg^x`O0hS>laq9T##5cry02fdPTa@V2FuQ{A`LZRW!omW^qk~DH}u0_hickP!TmL9tM=8cumel zx}!DXhsMA3uuSHcU0qc(;?VBK96i~>y0(`XwHl1K9k=r=^R-vu!nP_UABD+^gsE(f zjU9})n>dW!??nogAfCuGjAb{b(Xg!c*~3scgWIpWYh2Wyc=Y3ER-f#)r%0&`WAE!9 zf7?fY`{TcP@f#ao_^rooI(BlpJ-u;leeOWdSK4159y;E;a_-XE&DS3MAMc%7nEkU~ z`pjSd&ga)J^bd7!oTmA~Xi!9V_knx1wErKs{?AjRZyRnI%4({JoDw(f^@$v7p33wS zE0_qVMEwujy)*@gBR}z61$0c&Ry+pKBzb4rQfft)=QnS&U-{3B?ejX`*~1NQu$4EoSo3 zgM=9(-fK`$0)T@yA$bH6mMd{2I_18I~Bkb(CSNLV5QC<-DwvpSNmp4)uGVs_wqrxfl!(7ol{&MB|N78;>& zWI!>+tZEcvXeQ6rN0lg|D3PGKWmpL!F?r>sv9$w$VG||lWN`xHtlt^L>b`?F9=-UT zt7YHV%n@Sh&mlCnO|Vdt@Du?~x{?N7V?zj#*f4e)B^i7ZHmd}a+9n7v(Un@=j>G>v z``Hub@Gp%&`3*c*P}eXE0-9b9ril$TXauQAvQTB9@$OpUR1-x?hAhF6l1Cj707*p& zf~XDDhXh|Y>PQg5?8z4Ai@jUpjdj1Qjf6OvBz2dRPV4tXE~iNi%tVPkZIHy~jn$wb zNuG6*qLZ{Vrhx++ktz{2Qw;4Yah1T1on;46k65XX2+95KRVoQ#m-$HIDBH zV3cz(BMxZeyZXpe`t1Yqg*W*J-a!w&#eMYWdnaZOjW1vQ>u;?5#b^D+i`cpxtAWi6 zlVwp2Y^K4hwJ9=G$!fG<19(W4V8Qg7C>hb4H<@6ZDu}HT(1^1Wl`XsX)#MdUP*^gs zEr5XfbyZ|z@-{l5m6DW+Y>^y(s5kW7-=e*U&S4aLkhRdBM;MWenm0TdK_(&G+I-`b zih!nKmn?`Ok-$ol=-HIhrztg48=h9th@6Q?n_ebv)K00+T1gY+lavz>hBomdY*bOk zA%Prctf5WQhqCL2=wBT#d3X!WDK{WhvSa~@62aWqUsN>!5gJK=T53TI6o(k}!yr^K zv#ykJq+m3oj4$}BSC-eG|C=lKKY!@%x9vavv9^6k551#v=mVV--Kls}6lh>B6ppJ};GeK2JS&DC=J(S_8?Y<`=ri?JsDk2&} z&=@r`3=@I|g(e~zAfp^921pAnf*GQW2#$El&Xgi7HWDsA*nvpTkF1Jmz|j6`|jx7^uC$SL%G}xT)@sBRnL94 z|MUy})8n|6MeQh4!de*QDj%3RbA|&EG*gKUsR5Bj0t8iNLy8EA6oZCHH4CTy$q>rK z&8rG?22e~g5E7_z5_rmluKzKi`5&FUK<#Yb*fY(HJ?w^0-FFyD)ZcpbAzy0Tb`P5g7Vydb~L3ZlW&&;=D9ka|y zpcq(UtyK5>gI1@2h8UwU6k>?#i9}R_1|k)Sli514%#H+J>q+Q^q-a4juvtogB!%ql zo$R>9=eM89&>C&|6AxauzOjDg;yJQmV`bUb<08vqQ}bfdQIQo{Zi-=lkV&WQT6*)M;y)_z-yHlMgadT}0s^j7K+Le`SOILlYy_7j;+TefI8bb_XqY_ob zhgwygGYZ5IU7i`oDyjlw$Xbq3h_v195Yg#ZU+s3=?N+xpJ$vN3L;DXLKJ)6Oet+C< zcWjGA5rVMgR?)G}47Rq`*EibT&W$(TeA~UZ8elZo{N8sSdF91t0CYN2D z96oWw-u(wG{N*#xpFRD9%NL(ty>da+rw5shNf)5R-7uw8$wt@}2?32MU^3zWU^YaC zQVU~>;@1#@SMeeNP$HvI08h*lP@IV^5m_RE74bi8qDqn{CMITPo|t$@6X3=OQP9LQ z>f|15GO5#wm2O4`6tMw$8&ag%h#OUKVipNdiN4J8o^w;a-l@XYsOrph7oi;L+HsqM z6^zEA>{92%?8$-YzdT;IV3}OOn$TfYg%c4b07cq(V5$3r{{*-I|Ua);-y?TFmv&RrS;j15Bv{z z%`VRW`+xLXfBAcV+le#Rcki@;tGZk?3-{i3@2jJi|Kr79zEr(rDHDm2BS4CXl;zm8 z=&`CNa?K#5M3heevhe!G+VB#IDV^}x&8$=lT%(Bsr>=qq#0R*E)I!R+6pZ%J^&K;H ztz3#U-o)h(zVRQQd203ArJaYbf9nVCyY-GE3pdPl4de2~(KA2Tx$-iGTRJtSpBBocuKBa;%y6_Grb#ZZ;D;6Y&DK_ zw5cvjs*PBQgi09djB(7Rh$r=kz7{ZS?nG+uQIK2A^TopUmvHW!-=^SW^r)uu*0G|u zuRXitLp2(X5O+eqk5NFa5+Z`8VoOdXLPDgKmgMre_RPlc>Q=Ss*k!5O5TX#TwZ4uT zqbUMG@KUNqP)fexpvq7t6^caQ6iD1`ZNX+6Bmu` ziZ$4U*sXbEP5rz|Ncr;cw2Yer#$_i$*<%hmQ3wo*r(; zJhLV}uPtMQkSfLqGsu(h&sv48!vhm!i3JJqFWR`5uC=ga6f`tW< zs&kZsAQ~Jvz(T>00v$(%hp%*$){6uPio&6FZ1(oW&f@b|9``;PWdMRO(ZwLS*%K7r zNIex3CXdr5#o&l^)TWg$Qd2=pqM}W-p2mjPMUqLQ5tfQ762flDFc|>{l_1{3$I0{p zP*fR*s=4(i``E-P@aupzC9qie|hi8jf4cH26 zD{{U55H~tfByOE zz3=NSy%xUv!nJQaQa}B5#(->#R6zwf7k#NjPy-lPg7^dngQ&S*jX@L;t3;3m*%VO- z38}MGV>w6N}81Wk8R!afMZXk0u(FrX9~JP}2ya+B5~4e_;Wk<}!4 zu#;ruB%PAU4b7@5qPZ=UwZ=#h1<`BV(e1UcdcYlNWwR?`xs;KpD!hS9>~m6E#~2OR zLMRG+ip5fq5J`wag>o!asN#ZMU^ZKIzaYsOmI+k7rsu9*SbpWd9(vEK*WdEdJ?)Pf z{h;i9b3T9f;>xGnoSTI=wRsL8^gpdHe{J~Wnbp^Hqb^)mY~K&cI2HsV3&c`KB?cf4 ziW%;R)PRUaZjM)Pi2=hZ4CAFHqKvW#5g`FA=M39YYmkqmYNM5r35qFg&FstQ1TF6G zwpaTII%5wnDXq(Dgl}T&h(VH?449hKZ;64)Id-HRgYSp!MB9syvtUaQBch~ah$L#H zKsmSf7H*GS8De8cPQNAx`r+37{^qyl^KaxIIXZpam$H{0-*E-*dROPr$GUn4&`0?5 z@bahokAG+VxsBnf6=@qa0wWqU1T`jO)d(d}Rf#huvo0VVfPgfIju#K|!30rZPSHw1 zQTnK)Mi2-voIr}yX248F(?Zpp4UK9;pu`!INfK6(WEu}T`9u<_QWbp-smTyvq})X8 z7zSbmtpH1*)>vt%hy)_U#H<=bG)Po0VvQqMMnPmW!m>4FNJv%5I%9H74EZX_9nJt7 zHc$g)Yn@T6LNLi~C91kHUjOM2-?(r?UREKL;_B?mqwCwN;g);%fBe*^#@g?+X2;`U zMc{D<+ZM>qR_D*evjePVqCa)(&wTKfA9;T8>Yx6_Z=Tt>)GijMTJvwd=dEYYzjXS_ z=}u>=HQ%!ZwcA|{81_dZ-WZ}JiWIS#sp>k42PqIqMJXoG8rr~Wmb;1=CB-esMDw3c zEn=1gl!s^@e#d{eab?WG9X@>QrW3ck>7g6eFRhHXtEwJsZ?CA1`{S`Qt}sr3x{3t0 z$XHBaTZkEZ*UnuT%UXtBgH=%WgkL<*V!2FD^az^Cbf>u3bt0G6h&6m_4fAC^4iMTbFUr0{>EGG zy1jlTEHAIlFHBeCvdB9wvpbvH8|xc;7x%pTq4ylW;ky3z&gSaUOD{e3+AA*r$nvbN z{BYQBcc$L;u7^JK{tvzVp||#0o#$V8?r%T$#dGJ*5t*6k*&|06^HytfwLc!0?M~q= zZ>_8?U%arhv3&iF$KUq0AG`gHw>i#F{ovG}{J|f8^=n^y>GWwuJ~cgeu9w7;*(#!_}bGK&%RJq+W?r^+AKZ1Ng|iVk4X_a8p16(nkISv zla(^f0;#yM>EoR!+vSJmyxoytQih@mG9p53m~FDhC)t>alCg$O5|*b;nRa3GG@dpB zBN7odtU~E@q7=lyX>UxlpeTfPWpp|bf=ni%2^g;+l~{$k%Ce41%ZI_RUN7oiH}3_l zyf3Rz6>tSR)wnvmG|(L;0yCPH;4~@=2o{bgdaW5&5e%r3ZRYk4jsNEKXD)9&(``+K zAW>@{>i6FJ-rxFnzxDjzzVhe4^7&g&zF}&*b@lSq1Bdr=%{yED+4*8)bmj8S`3L{m zy}kW2|MFx1=BuB3a=x>FUgv!!?D_cgb$8!-*VE-wzkBhQFI6uaxRA1Zl#$plNi2#^ zFnmR`f*Nhs)|^OH$C^^v8%1yGz?0pv5=e-@O(J1KCP_+}4D*B`Z?*t6#3~H%q1N?Y zMwRx*x;?8i?|#<<9i95szyGs$9Jy)AnbkG_!uLm4UX`_LKEQN}*519w6&fm^XH*a4 zU`(VGRBdLMAzq3$&CQtES*}MSIeJq(f5NtBD2}CC^>JIR7&pxXNQCVIhMcj~0-|aq zN~&|vBV=wcw2x>%X`48?RnKDkiF)<%xcaDWyg(aeEN6{Bki|?X2Ty6~V-e6P2!>iy zW*oGxB{J1f#+7G-uE{cMV_jDgE0JW8FoxnNnBZ=loxTBiHo_KRb5pF^+_+4OBc16( z?e2DeyjG5=u;VaTtyU^C5Dls@79of-S!?RxRW-9**3tX1sSzQ}TFY=8Ju~Mf2dktg zO+aF_Y(lK-7$QogTGSgD5DRG(HN>0*eMAvHA{aI=m6w*UF7Hs;qAX~gJ^)QcJD5l# zf@naZP)J3*LagCB_)>Jix>nKI81{?Y-8R3s4q`+RhmRg`Cv41y zVRa>3+Lo0XeVWwgDYSVp05r{uFo}qUD#U{gxoId62e|ZDy!4&HV~;%dUmu{GZ_%4? zKlu0FfAl9F>^}GKE1&$-i@*PgYIP7p4J^B2$~mV*K8lhcdZMTRI2GYAi~}(_f&{3a zG^VnqtY9UOfE|c1DVAtjoYH3>lOIam2LJ@6#ygk5jjF zDskf5QUUR1s2FNNTz+@5)}=-F2~4lyXCl5vYz zDGL;GMo2-CO-~i2n-9>MJRmj7N~_Fgg)Ow!fsVa~78RLsj^J(eieDN%US3@~eBb#4 ziy!RZHt_po|D9840}GI^$jUGI=T6nHl%uUY_NX<~(O4@(Qj6A*hyX~WdZ;6ZJfpnS ziitCJUdAa+irEB+QF4@tMgp@o)yf2GU@Hv>}ZRz?DylF&@az*;szlGOnq1od?Y8E2Vw z-iP!#ftaFbw+k046@s^XO)>JO|GZy+Y4eUBWc&Xw?VJ92>)!20HLcnYx*03djL>ZjYZbgG4NE9Y&{1VCvCNiKz z$ry$)Y^fP^dED>kt@6iy;r6PI)zG(WK73(x>YGc477t(9TsgJ&V!PX_>oLV>i1xPU z>t%lt8>jKg0M|}r2Y>3$_wSiG_@7_-^Dmxy1n}MN!ORrC_Q&=e|8GA0Q@{Vmzx(YM zzWavu^xnloc{>|y)mu9|qjBi8TUA|4@(-t;TSkmA*~CNw(rHfV08gP8wV>MFS9h_- zRJ{$T5A|&822$D{T%Mb9Z+ydTANuHf_aE(T_OBkh<=DO>NBUdqPd@j}XU{(qeF%sW zB?Rv%8*Nvu3`*K|84HK8-zm51Fv<(5>Z-0QYfXZj4U9ynkh3m{G&ORp;ad6B^i1vR zVYOp2Hkk`bRV`8A9EBh;1Zyk+A7d3FgPpa`It8KxQetq7wLr;f8kfD7gc3&)B1%=C z#7ry@BPz~hi&F>vxQ`(^`BW$CZEdbt$#RpcqSY$)?%g{ajQiW8>DE*^te_gJxW2Io zC^3s*|G^Un4;*~#yWh(4f*4>EL$KDeB`C5~h8|+{UL+dBDfGQ)6?u{SI)vaMVvU`h zn`L9RH+N2-ez|Dn2M-hX)` zPXov^SJl3*>b-jpy#L|%edNb}{O#{}yF_{F@$Y~8o8Nft^lP2Y^zrMiGwhM zD)#2Pp{lQ4x;7Z@s8$cY^T9jsx%&X8Kv=)72ku#3y7rYXedTYz__yEq>URcyJ8$jT zxBr%+J5`p_A8Kc&d+^vz2M%06-7%y7m6Z$6EM0v0(uJ2-uboW;fpu9zO;yq40b=4b zLF#HwQ(SuXlQ@W}X~!^1GzouD)gard>Av6o_1}8_v6p}2SN`*j2k(iwyEb0w(sbpk zR$h0C_R{4`{oeAs{>|I6z3qSYlmE|ee)$L2_ipc^GaQW(^p@#+9(cpOf3y78zwyGq z-PDzRt?M`adJLPBy~eVn;SPQO$@GP z^3&uL^nwXv4FaoSaEb9O_Rh5yHpeTVxTUKPFFbtX`wr>jMX|nk;fcZ0YqGN?Wo04U z?smHwSypR=0-Q+8S*ZYrx>Q$KO9+)P(ZYf|aM)^4sbp@i>FwoWit6p)cSOAw8Jpa2 zkI5)p6Pqegq*U!H-)#68VIT88U^bCRgfZ$A1DVR<{g6jW*@o*(NF!K+|%O-g!|(f@##x&G(fb+I1Vb3Wy?vQ}4M-go>(#v23G?X!1M7iNsiT z=`;o<&F}<1OYudR#Q$J&cQk+7&3>Cekj*9YL;JU4GAyOc;T-KA_RPD*F6IUGQarN} zE|0MdXrscxuKQInd6l+7G$k?23}ub1398{1oPw3A%cHM<5?}8iUwHK!Kf3+)x8D7c zcRcV*|4bM6k6*lcLFpzSP7-C&=KUgo1u6H-fe0o^7CeXv zwbrW`uVCtW?0b*~i@Nm;`JG0iqOsvbL6fT`k+%R?NTHa-U0PA|+~bCxacx=1#pm!;6;k7CK}g8ihb$FO`qha}8v% z(HemaTe#HVQ)%!NJVLEu$L|!a!mu67h?NL+jM`$Cac+!Tqx!p-uWbF1zvc0Tqwk#F z^FAl5mk%C5mE!b-f z5Gh+&Lq=4h#*AFj8&+BsAdj-7N>mQ%;(oKQ(3#s$OuM@nJ#-$(=Gw)%;b^%Yw5(pw z#}2jTU-hTYR~J@v%`iJMOe#vEYRNgyBof0o&JEj?92Z0~HWH(k;4&p45@sTWSl4b( z&lqE3g)C3a%7!%hy4noegJ;`ewTSOW`z~Xy(9Y*&>GSp3=Qf|cymcDBY6HyC)U^hM zc=5GF!yqB3Gsc3Hm8>hskeBEIWdZ{h#0*#_7STviG%{8%~PZ?Srkas5Ew=vBaHz@!HOU%9#%jB4M|Hx zj@iU0j40w`sEM7Sma(mNHl@A}ew0%1Nb0D5atIp3ga{%-u#IQeI8sAoESbdUF|avW zd+>q9>+bKABX5QvrE`CAb>-UdjK?;4EjoR<=NpykJ!3n~#6%=EKK-`Jeylzxkbi^Nq(JRVl7New4L} zF~%URmMhCjHCk&&RY`_Yg9^|PQxO6QX~r~Eka8s>MMEE@WmQQPDdg5jjGb&gll-q9 z`9vLu)9t-qdvWvPryhsM+WOks>ehYx-ge80H{A2U-7ma&>g(Tn$_7u4tR@>ux z$eB1LNOYN{0AKmWr;su+H0CyEvW6+dprVD#s}NA3Z7CER!fP zHmOLe6hZ`Po@Zlk3}se}l&3Z~yZ7*QNBb{twpyLwWn7QC3#~nS_v{P?Wi_6injQ2< zS>~*BTU(pW*-AXWXYc&tf`}3uYdM45QwI`nV_BX!z#g&yM z0I9U5s{OI+j=%Sz_y72h|HRwh_29LoYhV7GFFp12GnX$ebvnh3H{B8|m8j!Uzi1Wh zc0Sx0tX#XoKyP~X;fEf+>6Vj+j~;vex#xfL-~GmCKlc|;KYI!=z21RCi^px=9`2Mo zgSzN;jvqgE2s)|ZzmQ~q>FljPQQ1Z2=-iTyXO&28_PWEy#+-%I$T)1qUv5t4GFhFAP z6gr8@Z}|G=`V$pMn!-6Py`&OVRjH|rCsl?X1%={~Budc{4k;^GpQbi=d5H}!hq-^&hD8fYF%4fzUiigjhzeE^vVbR zAMZxj{^Otcr{Dk93&&?~r-3bF)u!U+xtmTNx%E#k{rPXd`hR*13Z5=e&vg#2?vz2t zq!VV9coKfm$m#$}r*NuwLep^AVKUIMYIq%;Y!ZWs8X2B#3XQ<331%=l84{b14Pe-k zumFehn}|?`%0q16U-$?AZQd`w^vBCrUZ$~kS<4ucbzJ5gxt0bmmN_G04n@H(QGfz@vzmnSzugM1eAsq(BP%TyMc29QL1mbsWHUtNOSL(5b@<-d9u~5@uAlwN`R&W~I4e3y zqmeliLKG24+Ricy9jcUd8G<(qiXcw(WK0{50oCeNb;`B6o$hcv97SJgoz{Cp(NbK& zU~%gDpD%Cx5A{>a(ZkyGzG@PLGPq$QW6G|FY6@gZ2I%z9fJ`c6(!)Ru!;)9R84B(ZCqkw(Ye|s|w{X zj%qCxV!#n9i6sL^giFJ7VHhF;6N{2FdB?Ov@THakAw9ed!)gsI0X1UdD@+vVgo2x_ z&qSnA)4rE-xp-0_G&vO}XF@}zVUp~FL?xsJmUDK{1_uc#MVK1oP!cJ)yRZ{}Xyc^U zGiE1P;_IjNF3vd7v`p5tqz#^Ef;EX|V}Z_o9NTa9v)YQQWq)DAUmIdu$)^{q5YmZd zmYQWgeIE-}`XCLD_l zrn_n1zsjfof)0FDUwmnFF4SbG%`Jrre4FzqbqQfmlK7WeSy(|#{Z)<%uU=I%f7bP*pM|_gn5jgsVlFBT156*SYD!Q z$FtdcT6dmkAAWB5>e>22A3JSRSW3ob3$UZip@6a|8{#0!u#JeDVhlczv1}RSqp|sv zYfo`ua==uC9hjBjzTx1G1AP7M^E2mp|pd^XjB6Fnk?~c^U@!?2cWfQ90B_mVQU(N&NDRViY+CI&vJWC& zC`B$aO?rBhnFfw1J(II^?WwHOT8P>*RcRfZ5vZkaO}im@i~&;X)jYp^EM08z1&F)=9{SSAZ$X2a}M z*jOgAVbqU2c=%&)ml$O`bn<-boBhYW@bck>8!s-euaq0zZfk9L-oc1gmSQVr%V)NZ z()gkqWZ+{+(xw=_A`l5ABn_~_I#UoxQ4>Uw@(c|~n3R}F0Sz!W(d zuvBGL)xkPerc~P_=}rxzD$`TbtyZ@`=$GXv$#pcqz?SuRrajjydYi*_U)RPOWg}4y zv2`hAi=+XBjR;gYcU@H;l|umY^ZSoqcl5&Lm-Z~oN!yg6T9}&c&U9ARHmbUAcU#q{ z%xvCjb^3!r8rF?9LE`q-wzbw6lY~-Po~uY|QVexXY*f`{xwY0<2ZA*Yk?OKi4c0jY zt03LSs@j{LX3Ac9{)OPnd){!zyB~Vbt#{wPxw`)S?|$t|U;N8Um(Ck&vMj6X+IxTe z*opVQ?>!&=>5o15<~N^y<;*Al@K2t6>Z#4uey1~a?>_#8FMi?jwJVvO-nZ|@JnO~a>N>!=`TYyMx#@N% z&z&rv{r+>;&R<(PI~)(wGHGp2Oe!&^2wzQrEA0*slc8icDwdN@0mLfJT4=0GYM>Y^ zky*xmgO+;fqwE#VLw8Ic}01#u#IGB3#?`Ts8M8Xkw{SnMl+m z$ZkLiH=!Yn)KeiyB4R{L0AWnv^a<}vyC6Oqs+C233}v48)JPo$JJqF(vg>Exx-wdM zVep)#BI7)235j48#D)VF?85&F4O&@ZhOKnmrrA!mceOrS>8c^C5Ff+d>HWX^tDo4u zHu&HFmw$b5|1F*FOut;syPZ-?U#)d}3$L7cb?BCV^4C6!Dfi$1jC!W7y<}NA? zB8<4}J14JSxbc(M{^XCZ{gyM-qrGJu55|2)dr$YoO8-T9Jp?#5#3>n71tP&EVK81F zG7>}Ff)X%HeT>vdx*3gI%p_id)TF62^&6+3P+DS>bqzp`a+VG*w2lnNLkG7lSKhYx z&bPh)w(ouUKG?JX0RR9=L_t)1<-#jf(VE>mmlJC}29p{BD$ST|REaXZsMpjGVz^xUf#%M#fgeO$!1bJIGi8hnT8Z|fsL%}KZl;q=M~My* znN$}G>|pq8SbscT`=+d%l9g2*GSPI-T_=iK)r)9=C-oVPJwg;R6oOzZGr7q!Y*p%o z1`%T)(}z5U#3#tOE(L6j6+vAFm(yaebU8{m7mOQEF0a*|l8W$}@rA8E*JcDb*kZt%sqn91KxekBPu!48oC&?tTJM1rPHB{uzvD(MFwR9JPE zTZir3qMezVo>{N9S9LU`Ky0k?w9R{2s|7{7J(4i4y^6H5e8=n8FAQ#6nA&HfA63WN z*+yL=X1R5o83Qq_LWqK4@TJ5xU-g3zMxk)V1QjTmL|uxEW!xsaICr3~>arg9{h*ep zq>gNqsH%o&M+V)N{qfn`HkY=4H(V?w=7xy`fF(xC3Wh>BY7`BVm1>f)Mut@+b*Cps zC6vh#nGwbZbpL;6KXTaY|IPAKpN?M)6dh-ibS7dni8oBd%5j$sq!gG$fJxpyueHKB zDk8KNKh}{)ou1Q(0H}cp2 zFrkTJrHQ}?P%xV)0Z5bQ1P9a~+DHLRz7!_hZ1cq_$zDB_7O;4)yMI0&*rDxL<<)ET zg&o~dc%q~XZD{G&UxH4a2PlA)tDe+`>9bA~kTYEzMpcngGnHZ61W;I$Z+`alH~$iy z133AHPi_C)2R{7Hd;abJ`o8l&b@n^o``cgtqt&ZRapNM&oucTGE0SGSLVz&|3q}m7 z{}#q1%^lc+fvAuG0LCCHu~o8(o=nBcpb6?iDZoIQhye&doVArmtI;kgK2Z!OOX_6f zS3+}-X|g~nkI0|J%2hQjLZwm>cZ{1iSspQ#dPBol5h(RyCf%@7Q|hhC>?~(W@R3B( z7>;z(olHy+Nl_U{;ZlZ)<@H`)OsZ~DI}Q=0kXt55C8PAsM1vvc$W}TCk`W=G?x15; zRjo6binTDQPnjCkQS@4tI*y2}qNqnQT&u4g?%j~vd@F3Rnh2>SLPmj!O(rnb6 zNHzPG{I$=nUm6WdrnYVE)b^aNtPHQtWvv@J``^-gcI`o#ddxOIwu%!J@ z*KC;1+Ldc@h1Iv6Y021EWgOSBti?yt+Iumc;bWBPsp)Pv+Z+wo>+PIcWVvlSM8+6n z3@4#q#x{qmjbpVC5~O4X1wOc-gR3jxXLsUp0R$_sOcn~>=kb)>FgcU3?jK>kl#?8b@ zS!g(kkYR{fErCeMlF7(1EGb*Ij-84!Im33Nzjgd*_st(YSe21QHQ<^5@bcRB;4ODA z{MT=Oe_^_Hu^iT6T)6h29^@|M!qeT}{e1g6mjC+vmzL{u#!eg4GDHwKm$%zf6rDz% z>&*n?Kk>(Zq^11JU;GzG51jbi=e}aPZ5vst7<_1VYz-dyigOk3BLzk3%oPzo2>}*@ z$z3Og3JA^k2o^~5vjLb<*43Ntc+b7Jzvb$s%lF;>CYuXvb#?2?>ekBAm8;8FmoBbe zUf*6?-(Gs^wMPIr>R98}F6S|Vh$!k*KGm9j*H7R3(RbYO=I_1y6rAS;044Huh^&S=MzNW-&eo;)7@gy8rw5_+waxLc zfAdW@|JX-<;!W?mckSx(m%sSAzxmv!mo8t*vb@!5kH@2kc>A6AyyqS7`rwB?_||v6 z`SO`7pZ?TmzW$9zuU%c;cX08<$rHovF^mqk`&qjvI{DhQ<(>Y{{N9-d-}R0M-twkn z$Br*uUi$M-e&(;g@YzSd_ML$*yS+WfkKa$?JZV(do|@h}JJ)Jw#AQ8Rzx2w|=H}AI z`f|F9nbUGYk^(O$V}mr$Wn)C#twC*+P_RT~tb>rM8j~595fLZ+nX3l9x zXv_rBS_mqlEDTa&(U1a(ph_yFK_Eo7oy}F~Z-@R-ezmF~Xxu5vE&piF=iK)AH`Xh*)GE>)g zPIS!7pIrOX&u@RKZCeF(0*$R^DmoZ%Ellm7ZyjA7pGC5wHMZSG0+--yMzT(%anJ)P z1D2QyAgYeBTV@N;gdovmOClh-VH6X4GpRO(kW5ffukmR6Mr)`ZdIE|-|IzMJplUTRDrhYVQi>wRv@MC(vc@>XQHW(!SYsl2FV;{{@uF;*1W+|> zyG1tNvUwlV9XfWKxw@r~zbr3qjxU$vTB@OxUVNu*43S1Ztab*v6QpW3iQu8)Y+ht7 zHXNl6@Rg1geq5Ci(Q7ays_J9KhGA4SdMO2lUBLi2DrtzdGKfSWQPngk`O{{G{?ZPGO)YbqF>9=Y zH8#Yk);i}<3o{$A1_9fPmHomCYxi7cYvs-(vz6Vturq39b0Qjj;Ebb6zl!}j^n;8v z)GCGzNwkKdho-(zMbt3Y>K&WiSH-YCSnJm#FxiwjoYp}i1$Ickx%Jvdj@|Op-FqL| zy7poW%8no+WQ~EOxL!jVMI8TrcVSSdi0DicYH+@qNe@AGkV4NJ|5hmakiqOc{Rji~54#q_2fysZhySKhhuuAjc+Z@Qc}TI zBN5(RwULT&c+T!$pxJ$K{}FrWtXz0LKEJBV5o3^<;B>MZ)|>teyXu==|EvWR8j)E0dZSE`n+weg`B(tU8LZPqs_lquidQ zFwm`6;^+djrpEQ#2%9G2cb*`{LfTw8L*Fpojrw zFcEtl$LN`?1ruyQZIOXupvu7tVn1&AShp=_Xj@{Pm{}B1#8mSIh=)&m?2fLlkEf>d zxqcXoFwBrU(}W#5{l$?O-1bvb<{`un@!T7Ga}Rb8{8i`a zudY6|y}oWd8%%NAMO*54pkoC@gC#rEv4PD@CL(RhK(UU&z&Ooj?QEsPp$396q?MFV zUF4bjXKp>A$11p|`&ZZMu~IhWrq68;uYF@YJC!eA7_aMSKoG40RXuH07`|3tx>{d3 z+}d~V%qr=8EV zYExXT_m1k@_nMnOYz{xz#hVQra7wrS%wPUi*gRXFd~bWt0mn{8C~NjnyqB_y)zFXC zM3LxIoS=B;Osk-=-&z~2?|7ec_y zD~fC+o3)lLvNH#|S2l|8=yy+FI}>TtDGsJ+L9lT)EAoz`JkL9ZGA_)4nZ?0Y^&fx# zGc(2P+pc@dqv6@YNKJ-=A1Q)}kK&0`B&Z6Z@c~*Y3}-<{6LUp6 zG(|PRv7{P%#lHJ)d)LKRuB}{MJ8*dKf!V$D2dCeA$HNDY?^#=4TU%Rx?WJ>P&YnN} z>X|dAPoG~p*Vj$In+XcAp@Cof)XV?*!tlcFhwfP3x^lXDwa7X*9=~;VYTwrC#>(co zi`ULb5GE&xOx8yBF<96m3x{pw_5O-;CbwO~w#ddoeTa3MYh#F%RtJDVo7)?eAE|1V z=OG3srk!^sgf@4V`^zgkt0(4fxwv|%tjZ$q5F3C)Xs9#8210BZ991!u&1EhdV+dez zY7a8GdUb6uEQ>66hGu5FlwtYWieqQU5b6Gd3)b-3+8O|fu_)T4*xKG|a?}&+6opxh zF=R3Z+00nuBuI!+)Q2c!okY!?V~_?VmfRKA+UIFKJdZ!-F4e-YpW~Y`pTovKK<;s0A)!}e$1`)We1 z(ZeR`k~)u%RbftVY)NDv30pW zIQvh2;}@q6&V1}6f9J7hpSq>OrJy( zy}+*45sMCFsy}$6jQW+ z!OpaJ?SkK23f8#XL2H?xr*;b(q}&$c(4Nb(X=e%|2MsDik$wP^wgtBWw=$iybkw9z z0|8h;|LJ(`+kW}ma_tm$1}a_4b2j8u0RstDl(9%9Dn==gC8MmB_g)Z~)R1TdsRr+c zG-XY2I;ebEixP=KBU!MILI%w6A%Hk@nSpIZwnN@G?QXs$+pP7=FIG=nt_H@tc8p~N zM}_a#WjC{V+w7FXk?*tB&<&LaE#^Q;h zBPY}dP125+;HsHU*R=9iHr6+NFvKp)0D=gy*{sK&ZB0d04au-I#xhAAOv`w0UtAwv zH`l)F-UF@Ky!)zt<%!k4_nw?{)`!5XAR(qY2C~QumoXTk7?lZ>66_U)Elw;Pmsq{F zcD{}w1pyet4JJk=YBWSSw;rjMKfC(;+q0XG@!a#W8Z;PH1xFQ2%)~@6h8B|+k|l1S^)wZGNd#)#mT_*ve|al>5q3t zai|hgCa^SNd(9%OjhH1-tg^egPW~>~WptZ?Qd7JYCUT&()+El82n;i+<^f=i<~RQ6 zjUOzRFP~a{^;^}~FUisnLqM2pbCUfqvx?VGuSV@W`4@H~VNKE-nz(tJAAg$vcE4iU zg%AT&lrmTV9aCNyKKkmpN99+Z{POV|Z=AaI9sldU{K+4~n||cK{h7b~(=UJTJCChD z`$D+746NtY#=OTWAc+Z6O_{!yHN}7@C9tIYq=^_fr9~yWR1}w)T9+532GH&R17$% z2!f-`k=c{)vuww;G=Fr{yyk>*88#W^NZ1b8fTM=ZYORg#6n9r-HK+eCTmKzx*>T=PY=Z@(eca81&>+vU_ zzjz`pR!$nQmfFrV23nR<7*IyJDzUhnY$X*_)+C-V6C?zYfebw=3*%K9)Yy^D-E0o- zae_Jqq4~RRoVd}U z_4wNH4e5zyEwplN16qJm?nAv6T4Q?>^UKcjH}$UU=@z{M^Jh&wjJyAw?-pU1XyhI^Ix9q0H zAW)UsRu#z*7)R>}0M4?e4^eww0 z->`H4?EV{ep}6(lTZ+L}SUtVIdhzO&E0?aUTt2sQ{^HW5^A|2$Tt45At3Xu5$1i>L z@k?Jd=tTHzkZpv;{X1{H`}&98_LjGQ`-v|+{_LYM#JRcIrs<%PmDQz8b5ogNF+`-< z>DgZ4wK7xf>3-1-qItuG;6s36W0)f}24BU}*hGSfMzLha?O3N_n0!QB?$XmMv$LxAVyWlo(`a&Q0uCTv|DG@`9UaG};Zj$(?rF zSPsEYO;1K2LK$Y~W<+r9>N1gu64)4HY~`y2O}zIYa?TMzMvZk<6|8Yk6_MZrG4kB8 z8YMQ)#3~x*M(+HuT3cP3+cEprA9?7|_16u%{V#m}FTVNpFNsQ)<$0EsWnpdh_IJGd zCw}~c?|$TwLq`s+Tv>ef>F2IozPxm0Wq$Yk!D9y>|N3)*eT-fMF=O%awaO3oAKY`# zy$`d|k0?^B=p^mo7W=*nid)1KHhe{5`GE=C73jYea3c4}*2S#5E z_*Z}QH{Sce2mayz`cJm{&I z_~Oy#UHw7T!o&{Vv9GmzP<21I`K{Hsvdio$rGj{iOo)X7kuW2QZVlHb+qTr3WQk%rd8snM#2pALhNI3c8lhRmh-5*^k9|W$7?}YTFNFc`8$0U7 zS5;Bzz()F8zx1te&-~0vp@R4MB%dLWJ7Xj0P`Sm6b+tt3lA9ss_P}1Te8- z7BWCgGCc#sA=)5wo%SqeGm{oMJ@IP!-wXLc@7+RC%8L_d5ltPC_ zmakZa%1dPp3q^1Wou#^;LM1^mA%G-ms5M6`y^bvEBUws)0R*EZH72L%ip8;sNDw3{wMcU?9)DH}%eJpw}vkgvlJnVe~|A%%tz ztYP9Pimpaq4oReGj3Y2$$RH?_8wfS$+q>R*5VCsn&Z&hf>(8AV+N>E(tST`~?JO%o zWi3e^=OSPtRm%)ONQudjTi9G)>#cf$tj-)#0z_jxDt;H}M-p=;*;fkOpumbD)k8Czy=0ls2LiQ-D*- z*C92kI;zr1BzJhzmZyIJ3x*F#-W{~ zd9%G?BH;M&wU_nPz7`5F866Er-x#lL?~5bFGinKnjv#CL%5=c3DP5@*D+w$rpbWC8 z<9RjJBS1Z1KtWuGdCJ(T_u}`CzxX|T`I~?D@~d~h<=#g=@W9{s?T`N0=7*no^o19m zc>cxjeYbq!74%lDZBv$6qft`za7`?OB4D8eYm^z@*YPmSqx)!N07h+tse=GHW8*YN zl?u@lv$9D<6A^7kWYQG@Z%J4@bHPVf*B=r+WHNH|ig&=h>6Okb%P*8Qu1fwE`ZGaHSFe#D% zFeYnCr9(rkkWE>0WaoHxEbAZ+2eGO&BtJhC46<;n(U5U)B}xyUAqRYgVxhXS#~v;b zhtg{xV^}4rsM?B9)}{##nXpF=OoCdn=(>-cma`W(Z+yD7|K72=ceQW_+~0C{-Lq@& z7uqj;Y4Yi_S1w^Ab0%Zgq9GU;rj%M_CK)jCeC{6(|KEDTl{tayRc? z_x{x4$sVLd69!shXgTleU<{PC7&}0YL1F+QDP&loN>x;he1>QHQha&w@rzq4$HuQe z+B|Y*cqK$WGPZZm#Ey$=moJw~hM0(r8m9)Z#$}e-An&v%o0Qq%V6Wxdk2UZ4+2-Vr z=du&L1^KIZ;g5%}es^$kO9q|1-;zDkY$ga6fxSlqk;MDlHanf^ zDq=X?2-=G%kW{}$lXf?W48b-H#?&ygt!Gdw3MS)7Ar-YTenay{Yt4!NYXuDn1*3$j z_`ohVj+Io6WrL_uRFi-(MrCW+G$=9viDKD6RYV<}p*mo|!dW;+&akuOGIB=Qkg>*b zq<&m`%Ukx&&y}xz@BCfw--}9K``m>mUO4lfV?Q!B+n75r^|jX@zf2dJY&LWwXfSMw zF!;UC{^_5+{FhDM!IVKmR0EK8#@YtKiXyXiFsRyD-pU-Qv(`4GIcBpv?zrj5J$wJv z@BG;l3*QhfGUi$ASe7Lp3UyE<|DM#giqY&Z1>S@(h&9VvpTH@hRidEPOnc{>Z+*+T z*Us1slT%YrotVzw_2Um-cVy?V9KL@1%#&Yv@yewY5ssTOJ=UCPPu{rqz6XxIyEEP% zR9jb9&%b!$x#vzidFtGmtHXsMx)D79m6Vs4Ph4I;b?NG>w=CVWy1wM8P(z}gpyT5c zW3DsP*(0SLZe7ffS7m5sdAl`MhF(Ut8ih#!sP&x+<(RPxD$FENLWmQs$%Zz2vB!?v zG`2R_xUhC+*W}z}W1?I3n~jF15KE>Qg^g>qnrv+~9F8?6#>OW4{Z&BQn3!o#_Xm9+ zWO{6}($eMm#PmcOjPBYyYcd)RhQ>5DyZx(+3(O`ak!cb-604BSGB#}4SZ71<0Gx9n zsKj6`XPG5qqNoDKursdFZVdawjnz$O=}m9C`|da0v$4GR{YSt4#ADw>?TOW@D#trh zkG%H-ANt7;z2oig*t>gf;qt;OFTK3Bv`R!%lT$n9=lZ>Vzv%ARGr731Y8z(h+CtuR z_dRs);UkA{zx%f3Yiob@hyV3cpZnAg9)HGzW~O!?+_&GjcBDLNJ~25vHaTuwEc#nl z&c3#~c5Y*Jv63N10$^3qG^5|%l;2S3u)guR#8T9I5b6wSVlp;w7;-U)b6IPF-r0QpaM1t3KEmnrwwJYCQ;;~BGIEBkkj@7Es-@bRA6xJ_ zi5%;#J~6t|HsK!&)s|f?XaQQu_8*W&GF{e>gLAgmB0D_ z`lah`Ir^aw|HNZ2Jabdy{;G%#o!Dpg@0#4TrPrSBf9ryrJ&+xn>+E0JxYCu%uq9B0 zrYL2{CTi>!gXzYB<-wVVa@3nZqd!UzLBZ4loIn{F)d>VnG(vM`C&G&Uwtla^I_cF` z7+_>}HMKa9prQd`kGw1AO=FCBMEh}!i@5%j#C+NSD{0fXSK`Lkhp*3LYA0G}bkng(-5pV*5oSUZ z2^vQJKHbK3QKcrU0aotI@V@NMe{$2W-!gXW|9$p9o(yLkx#Z^~O$;`tAzhNJ5+D+} z&bLdZyjrG`&|Z2uQm+hvh*-lkjY>)1ZUxa(U^PkCX;4o<1VIoYs=Ajj<*_ECvPM87 zhO4-oAvZ7#1SC^#nnI0qwh0QS)BBCK`1i(rP+43trzY$Wb zNg~GTsH*J=;u~-{@omYsxc&JgrP&q-3ym%gw!bPxe*twj1Vzv|4(uAc(V;4Ps~hFz z|N7cvmvz}g3>j67wump|T6?TMV2^x|v8Y-wkoPwYdiHsTtc8~}S z(5N+zO)k@z5{L4!Ie`-uo#yujrv9y97#QyvJ-^>GKqJU zB!ALcq{u1?oBopG_;dt@Yf4#(p;8ye36yO;v671XvMzl$tUd?Bq!ox^cbIGs!kU(s zRW>7hvLq01j~`eiB9+&Pr0GSHOQw-YJv$a5atx*#-vUTsFP;D>*M)c*1JsZMG-@R< zP-7WT^tFGbxH1{0gPH<)sXj&p*JOH=no4F%w-{_w)D|f#3v{T1z~Nx$$ZH$NON}ie zK_m?ov>yS|2DB270C*ip)s?<$WT$;~=J}1iFEws`V)EeqlRJK_skdV8hVggZKYra8 zXI}i;<(F2kt-yDhc>^X>HeBHWw=(t z11?9y01;KGL@=T(WXLEiL}F4w5VS%?V24aKDv?n;M(rW#+2NIqqS)Qsvp3r}@VbBe zx(Bb{|I(S}(xqOdMbqV^glIF9=dMK|vz2oZvnX$zv3I?{b^Xtb-Ut#kc&Cl|_954B3!CRk-&Yfo zHADa+1LZmt-GWk)6Pz*B)J5?yf(z^`fT% z(U7Q!G3GYw`~Ls><=-h#W!VH&n2Z2WGR9=qdar?m)d#PZ8m{S@(#$lM!XlV`d**L{ z_mO*l@76zF|9uCWgWk*UEwuNi`rlm0Q-Zu|Omn5tfRimdjXuPJka8SZAq*z2{~kj4 z(8C|C7P{BYUY*@Fm08Uw-xZGj=RnUfp`}@#FpeYVJN%-gM;Hjfby)%Oel@cm49|<0iW7%ZejP2WZ%MFKbSX?-N>e7j#=&u$_Yr_?FnzIcdGMk_w zNQlbJY>gp8s3L)53>n;x<~(`hy(i0R#5w!=!t2ZH3jso`#0XK1bxg*G7!cVQXPghi zPTn4GO{}h60x)66=O(6{qlw9hPP?-->{-JzGn0AN7!1myU-e@bge=c5EnFQGE6zC| z1!P1thLBG1?eQ^Y6NY8<;(fH1*&2$0jb$b_Rur-F%}%q`Z1y(0{XwtUXw1y)xaXmJ zCR)wspL^_EU;he#Ja0&hRav&1WAAy-2Y%rbpLp=W`zI$li&w9mJAGkub2G~u`w#8S z^8Ct~E3Rz^8@*z!9BXB(Eac4nkG%bsTaI0Ki$MoJ# zK5g=R*w=QJPtEV{bS9-L23uE`md>oMUg-9gkP`68Aqh8iqyc_IPo6xAqYNaiN!Vl} zr4*wrL}Z!S7zeh-Sg3Z!$6em=e$d;vRu0zzGA2_bCe=dUxFLa*yTmai#-_eO)g%f7 zAgN?dBaulpkaa(Vl4=#oexBvcW@j+y2Vd>mbNyYnJuo#j`TZvzUAVT;YL1OhOfYk| z+aC=3Ap{^A)6B9=>ryu)(cQ>gMG&pQ85uStHE&WIVMYfa1#x}N@WurjQ5f~dJ`RbD zGfj5d%sB8@5S$EkFwPaNKO?(-NxEuL-;%2SNaxKx4m%#d~k~ ziNF67zy6>9{Er@c<_E`)-rDbOWz*xvm>49priz30t%Z;M;zy3&dc#M5<-IOc}O`NnvIPhB}zU zuDS7}1K*b@n_+neX8*<~e(Kz#Tbs*nN5dehDqM~@L* zY?9iOq#?2p=P+Yr8rC#Oqw0E$9vBC1WV)I30O7j2(HECc9G9ix$Dq;|?5H|3!5_lgarF{D6eT>YMS*wUu90nPt$_o%;h}M$JatQ(I zht)t~JNd*g_Iw;#!%9h*3PBW&$x$XM#LCQGt4sX_K$3k(Bzg@k*9=v>SS%cF?Apuo zXTnv$avG7aib&MBQmk7_4V)oKO$i!B5*2I+N_Aa`s`yItoSH79B3Rpg?b6c1@x?>; z-=uMU{;j)jI??^X^P47{F_s}(mQ@)lD6An9On{IQQHqA+nChfSnl>kJQXoQ2S{RvG zgoq4*9RY|DTqs_lwQ-u*p^Zz}iXv%f1)>l`GJj(G?3{!lnriBW2oY+cDb-(x{l7H- z@kZ78mrwuRpRa$RprJJ^BLyjxMWt4mWDYRF;~`6Cd4 zru@u4N~36^UBO2U3=o)G@vwa7R@G_78J3mBRF1*LA8Et zX_H7RAtRMsP@T#SL&Q-`iG6k%sS_3wAgO%QRyOZf-tox zm<;L2AXI-ZM)uY8$ z7^n1^`m1bW|I)Z36`_tiqdyFB1sWg%6(B%jEuz){GGK#9BG9S=vAVV;MX`M5v!6cm z+0TFb&krAa@cwtb=aIL+<=%&W;k^%i=v}}6TmR|&H@`Bh7UPu#^wxP!2bv)5=7{ivBCINk1WGXqv_PGdt=o?$UFW*`gKbSM z5GlwcpFX^hhq6Vcbx#+K9;GtGkQKzBnv*5SPzMsoaT~~j#t31Ulp4q21~(eg5RgM= zz$Jze>W~X)Q7-Ro?z<(s^~J^KD-0RdkX6+H+KRCO8iopm$_565aw~RS|90({@l+x&fn#K$JufMWQlDEwQjVL%ARZiCmv-SP|4yPOUw& zH#S`7()x+M@2MNP5jYh}5R)Tv1gHk65?dmpU=o{YbAl!(?R2gUUkyU^b8gq2okQ1+ zPxZTlwrx?cq((vnt6^p#@?_M+7@~MKDR@beGG2p#K`?9_p_^1TM228UjU~gWLz%51 zP};EshTH3oRV0zRSEdW~dA zln>nV;RlaB@Qp8gduw@kRbT@}-4m7QXrQXZOzRyZ_dk@4n^8kt5f=<&pahyUozQuyOVD>X}#0zI^h+Yp=cb z+G}TD?xWWqE&^~_gP2zPTh}(uU0yqV-OiKO@4jhzV(zBNn^x8rmsXZ4@>S^e%A!I^ zhS^YNToh5#l-6i7BZ4x7-Px`VO>BiN!?vh~qOp}VhsEG(Z_(w>**r$cG6xtDIBP{@ zI2fv$G8QduiuYA008EcfUAJr3CPfwFY$MO|hGf%I(;!(}UE8?26(`0fraGNYYkhr{ z5WyJ`n5{A@UkOBsBnT0ri1%Jq*fr8i|k1I=y&e{V94$SVH9rnuQ z-6bUUw+}`vnMb7*iXIh-Usel zT3GFF^n~NY^mwn^1F37W9oqN(_=<5;^f z<^w{cM&6#9+mU5i&|>-8iKT_J8yiQ0oC~r#u!yt0{}6MlE&*Q zHBm_sN;K;9qm&aH;~-T1nTg#84;|XvSnt`!(Hm~M`>reK~3pASek7!Y1LedLi z`#>|ouS6i#5Mt5DCmg5@{eD>98jepjXF{w7mA9NLV$?vyN-54xpgh)^ZshHyjYXl# zvL!NA=smdq?f>|f{>fi|`?G)c?a$tEe%O939Z>rm85AN>lyr3r@U;F%)E;-60g??PWx^=SAylKwNLS-v%60;$f ztT{x;IUAP6cyo5XdE?^nq#*)1sS~)FK#EAUyVcc>M5LS@o0|5R8iwa$Tn2jE^lXB! zsRonl2|-Po1PKoLp3W^G@}Y{MS_v!v?4keV;OyKN{_N6}opIJmdbui%QJo_oHd@%T z%goPlf3@syNh7zN32wENodhQ1*ffa8Af<*)A*0wye1LI;aFlrl1VR_Z%d+;OtbI>c zp7GZ%X`ig`7&^kj7(%0kCmjT-d~CEVJ5;1Y@q_52HR`nTl@}4#piu>eG$<$vP#X(V zA0iAhQx)UTdt$@@1&n1&>;yDa788mvR@pmuPdsvedwm%GLD#twy8Ws|KYnltM&|ArK|6r594-D8Y-0G0qZ|aWITs zGGy395ii09N*ZEd1ko6v%vRt!+4N?y93>EI>LL*d7zNQVF;qlryCyS5kvdWoK_uqf zI`6N3W_fiI?FqEKQ~)tdieMCysFBzKN`zP+?}Z6bq5_VMB_PI_5)l*o7o_Qk*>nr{ z+%rqpy?rkZk-52j`}=mDzI=6Yv+~glgD)!|;FZ`glLU!D#WUMf{FVy&3=E}GQzb)2 zATb3sCBKc-VpI}h<&3ih8D62aDeBB>`?791CQ5N`3QctDs2Opaqhn6046Kye-<}L{ zKp-Lu7ZLi}&(Zps=?~r7yz!GupMBatmy@xufTnKXlxqiwAX(3AF0rN zIc-yYwY!7r+zozE~x&aWwrpJ(; z+6Z~_=mB6P@7+dZ+mhjJ>Xj@;D&bmoo9MaGbU|ynGSnF@NM$($jc@ED5|uM0f)|j0 zDlpr;-Dr(zEQY7fK6mPs=RWkQR3cQ#*u?CosR(MP zyHQ2WwNgEO9t~4c7FH5DCCN=XQZU#h$t47kmCzf4r@TTeRbB8?18!Y8P>!O|_46kfn+%vXsk|#H0-5`iYCd;Y;G|;T@UiuPL ziqaP{-0<4u(il_Ns%OJW=$?9N`Oeqo?|XIEq4)2=+hBj*-u1x#L!aL9+835yesSSi zHB=yT&5VL74PrIWVFp8>4vj(i`77rdO&ZU}CbIFVqF+c+pvqLJ9*qQ6$|*Cjh#Dh7 zAp!ydJO~+#2YYxZks3$M3L&aExHg(zbiM3OvRmk_Z=UqKn$7vfd|TTUsv-m;E_`e$ z-)JZAyK(-uw@%J{$l)!(63YK4T=-hJ{E}WRah1cBe6ToNPi4Zvd#^eOAyhy>5Q!R< zVXX}*hYgW51o6&UXL2DwEPJJt#3shfa%QZt#xhY#TiaG%gu3<|#FPf25|te>8!se6 zP-_^fCd2^JW^-)1v5UxD-gtR+aGCR*4JRj@f>k1j*=B~DQAA^@h=73_D3Q7jPt2LQ zj&_Pr4x}2y!8Ka{?#h{y{ce{B6{F#%Rr(qVg0a-fk!RFWBb&nwaB^p}b(u<(7>oh5 z@Womrry8v_=?Q|_vbAI>rok&Q5vA@iBE!bO^#|Sk`}6nw{Gru_trM@lIPRuD{fFQA z&ENjW+dlTDa?M|UY3t(J!t3QZ{n6v`n}34cKWjd5F`hfG zFBr{g?xJ4kL9m8wjH6_M`cHkjR+4c{{GAW~+M&7KW6egt@Z3O@aP$4wH^&>7Pc7Jv zefh=L2R<}sTK#UZd}*Z`mOe&tS<^JyO*6T3ws~l3$IOn6V)*P6C;HbmF1&j6{N`op zgk5`P4_|-izS|$l8qKTMF1>o;xu;)w@`YDlKK{xptNkl!4bJmSxjb>@sh2N5IoI5~ zci#c0&F0kjp_xM<=~mrqt5+|tUo0_fSlh^(1QR7Sr!y%GWwXs)>|JlrGuB#|z)(_a zt;^cPBoI={$Q6a(8V<57Z)DC{OB!SF!Ta9kdQ}wwCdMb5JaOXu>%-C;^ru?nOw;j8k*tEYM~*+xl0utwA~8OvFakj@OM z%xGD5K^7JLk$Z6j=?SCO05VJ=gc9Y!?9Q?F>}G$Jg)hbPceU>O@K3${^)GK>tvVki}D&`qS*GaWE=h&U$z z@g$a>DVM+Rm!F~4^LA~he%#PrBbLP}F+!mNc$I$8K@48B45EQ0C^?XD3?c|or3xYz z0+c>xmJC(Csx&eiHio1WRn8n6B^6Ya7>>?b6Vy~>Rc+}fO4&2bQ`a?{+ziot`D?x7 z3mY%5bt!8zwYo#?4M>1uSXEV(6RYypaIjSjqg91S485Yr8__rpiYj`O`Jf@hXbgjb zQc7J4#)1GZMT}+CQaBiPU_ulSr3xiWq^gC)-BX8*YoA>_v7@zfyfwGkUsM5^7$p!1 z5k-kaX|7!>Eh&*FDhe`$7^{-XX*1u_<`&k+!G~MBmt<|N=+%R72$PbbfIuS7x)42q ztzlIkHL{X0GoUIls)4%PY1C56u~tT^Vwx|X*tqxWrw;s$!|IC3>)Mk|IltJIY;5R# z&}egmGH8rBV#~2qy!Jx|mr-h}goCYE&U*1~HL?BZ{J46biA#oCKu=B6jK`WQbu@IgG;}p8e6EJNn^0 z*}U}qg^i2rSTk@DRjS+3`hA&jdL5^vBalc0KnkrqqC-xpQCU$F;;5wxX+%!-urpYg z!=2lO=xq0tAzNeL-jhpL^Ht)$Rw-K&9weguHf2NBi01Sf^nehg7mv9$h6xZ~|fU*vtr4dYf z15B&Jj=p{*Wd>@WCq}V>^-G-kMeB^BgzAV$B?19#AtQV&Q7J|*Dx~C0y8|Na_s@Ov z8|S|HEoiFC-cme?Rh6#*%+A_^pe2tm?wB~F?v)I{j$g4Vp3jy!Cd zAS;dL2_U6pLx%JbdO#M!S|8e&yt&;zRF><*QdFu$o2mq2NePK>klXbkW@Oz0fe=Lu zY<)Knk*5AVFc^d=FkBCZ(#w=&@uDIiFlBHF`xv8?Ax&ci!D}$EQ`tm7TnQ^{F<6j= zt>6tfL*we;QhzYWsWr`cE6<8B==&m20NJ6IMf9-{WmG{+gbZFZYSf@1xgu9U-`To) z`tw`&yx6_%>A8LH>flaH{z~)yHyt?g<*AcjT{?bh@tQBB$r?=>GMDfQhuhm zcCNccxHjX)8fc^_rU)2V1Lxr#IRhqDtA>RTL4jD<5(jWbd7))$#S~QqGhBok%8gov zWipj|rfh)XV!zxwJ~d`Lv5afJYoouNCvH2s^a?FJ(8Qi?=pO|vz|Oq+viMeIlNBF2zq zVghH@8Rohcdi%hp5)f5k$PjUq5Y=;pm?}ycV<2K8D^P+MvTU+J+*;hcF!XD#(GZrD zi9PDxM(wZ%lA&9n(5OnPhQJKxRTjhYTD4Mg-#ahbKfBdyY>YeS%s3j^goKvm3J{G% zL9Ic{&9&Rp8|AgK8k&YtumZ%&3=%J4OJJRKOhjr78HOb_>6m4SNMXR7{xCaODWGQX ziQl+;a)!?yUw-!Sr)Hb`pZem7&o&AFQsgS5i*Sw__;Sf*FFfPc28@M?}xq&6+)JQKqAJlNQ^;TW(}EMuiP=S>+ZX5xOn;eoF zml1RF@WfCln5|W%RN={niHM1fwanDr>XyY|c7Dg5_uZR;7Z)x(`-8{UH=g*uz3&!lOxs2V!%-Dl(zxU}MJolMTe&s#ydz)=q z5l^7&Z#+z(#igase*JTw``qWh`|a-z{BUA?=Fr|d3|V2r)EJ-K(V3WJimR)aS5_{p ztX!`AFb(gS?8vE9KdbGd)%Ikn9;YU;gt4PHXeyzBG0t#CYK>{wJhyoR!bB_@TdfXT z40`M9%a?=i5*e^l5R?p?6fLV!jmwxhh5pG%p`^8gEo!oKrX7R`b=YEJS1l=pY9P^% zk4@Zh>wWh>@L+dy{mjX&8;;(x@8E%rwY9B{%|q86=}b&)b+muG5~g#|(5ji`q^t^Nr^>7S z&HbID9osq8d(2YixG6@!tl9wBuuZEr*9QYKoPh{ph>b*8Gv(L?xvJRO2CSlDiIQHC zh@tQ(CTM==*pXq;B~UkPa+Kfvu}@@uoPT~Wkxg5}tmG6Gp*>Ell3AMFWoD-lhcOn? znR3mJGY-a}t_>arQD92xpusWVR_1wPFox(q5wCowy810yd_HUpq-f+aW-*PBp$g(v z5!5kUMlQp!&_StPuaaR{ghILH*g2O~P>#b&grO|nOHd(35FdgB2>=;ojSPY{22oVW z8e^0S-sR?$U-^#y>0_HuFRv9YWX*>09DFFF8B~=gIMseN zXyi?oW&PfI5i80hN(>Z*sxn5_%$VGe^->4|842oD1qe!kNMcImWb%knE5jrj5MixR ziQd?ps*VgXi;A%E zDpBQ)pzx%aL~Up!VgrrJjH#lt}A zFC6(aYTUOCQIqs{6dmwJJTOLO-N{Itviw+~Q6s^QV|IcLwduMJ&t8)k&&e}GSp$fX zfn<~<^~O40Z;*=ZPyZ0FTBFl9M9V+)y`!2LjMB13AL;10o21gC38->y#7rM2zBoet z2=EG2A*{xTvIMA9FvjGq%(N*KVRadxwNL)v|7H25T_5<-T|e@$IkemS>fh_U{bs+l zUViK8_^ChBtH*%>!J;unrbTQusw$DS5P$+@Ruc-{4pug#Du{xS2pp8aPDG4Qp`@x* zO~+75ZFMSXh%uUW)Pd27_)NoSN(p2Dm?5$~07wEyVkKEEde1BkFWPK^p_V(5&}{Bx zHRW)@%c^R@Y1mBlF#)7tGnyBr->$U=7$9(};j8B>qZy4M0uVG>j4IethZ~%sjMONY zSt%oAfE8xR*fF`Lb$jfbDa~M54AB$B)V66+21tn()XZc%_s-6H8C+gl=%U{bgGzlV z9uY~iU!jP^LB+=qNxiQOWo%q9bPD~e7tg)^M;muPId}Adso4jb?m?dYt?}8nj2-y& z)Jxx9eBs))74pt-2V+~>Hw4StWHW2WV$?14d%jS_oSGI{sTIQl+(5HMu0l)&dyW|j zr^X03Y&MX}A#b1=C`1H7AmS#nOjQ*IuE`x%r!bCfW-}7%SD{qa(jP#6@4j94ynV;6 zM<#GDFbBMhbDta@|I+I5Q@!QPws-H~rs);sy6+D#EV)u2*}z&8RV#^700lHgp-3vA zC=!BH$%CD_mbHz(U+?>_*NRvHww4f-V2JDX3BhP$6;&dn7J=8ao>Hu0>17b9P!a+q z>yCBCBlL^q&DaB%oI7PDikkBBQ~*iBK#{(xS50>Gl>I4e8W7)&D}%6JqV%>@s?;cv z5KBoR8m6G6#!#jtiYh{4)$`~#?8L#jWBqde-12K>7z!&JX5o?fT~qlNMX<4sGn+g< zAZLtI!@?;n$C-wUrdj1{-IaH|chAEgpDWAQZZ~f_xc`M$uHAX;N1px8i~DDH-2U$C zzW?19&iKnNM-jWMLY4ptAp&fTVMD%32~uQ;LQrDO8jZZ!C<}=J*0@eK25s7*8*?qY z%S0dBbF>wg@=BV8dwlJQSJz&hZ|s<~)9a!5a{P-2c=JJi_jhHuipvZ)8Zc3Ant<7c z0YnC>3Qoot2DY^KpT7MczWVJi-8y~yq0XVn+3C*Cso8zAv%BZ^-ZZyke&%iWJbYm4 z;Dt+9PQHGAIIOOmzqr299}dgTSZCMt%;Z$ARoP$LGGg5Lc(2+zef6Xt^V54Kn@!Vf z~8o_G25XZ?lAL>GV2#T%Os3S zt1=YE8EcFv7$(hWMbK_dUbpAS`uZlB%hu-6lSG}F-!VQuJ~+DtAhVek<=V=+08CUB zWuEcmWT#(-&e+)g{kwWATm8ZlaqyuY+7LAwO){n`eU@2fqr}eH=p~8}w3%m68uSMt zdY8NLiT2@p?i?F$`?CAkiyVln>UVHuZ?|kiBU;f%R zo_qSm0GgSZKfGgiRRjTPgALgZR%*H&F*6${3L;@LiIFu~?o7_c0WNQLjLVHNRat5bV`H86czf~M`IT#Dpu#4v2jX?o ztV!FFF%HBcb>c1rYz&|(A{uL@*{I^L4$(;DCs<<{Ly_6$p1p_fzUNKHZoDOmFUsQ3 z(IeB-(}S&^W!`_?0bhn*cS~dJwAxANGZ^&O)>gOHH=0@Fj@$3-jE(uST3uaUTv=RO zUmg?#07+;!x-!YCYhp~R9V?8++IdxXuahN+XrLPE*MtObBeQgUiDN7(KWJqWjnEv% z{+3_ql#^qP@!U5`jSOLiKtv)SL<$79(X#Wg%BlIc-}Mh>XJ&r+cmKxp*i7DN7P85d zRiSijqE>4w%lF=K+xy=CzTf`c-}=_mU)!4>>-#>qwNDT1q@Az&A3QDJ2su ztvJlI$I=nz2?BsiSbny+@Xg}Vqq=YkLuJ#>%pT_*m8@0NvXVe57FD5^sNLX}fGwOu zC}dcP0KP>XdwpS z$h184Q1gyoXf|)8cpA@trugDZy_dRu9aqPu^i^hn7&eRHuo_Tq4Fnn;TV^V$3h*4g zM~EDiW92J0lI2+pjj|djL+f)?q+}0-L=W_gan8 zu96a1GHYTC>D^_3Ad#R%N~A$zNyv;*kRk?!C#W&OM^SQ?U>awy_Fntzi-&J<AY@|X-+RgnZ_L?qF$Nn~4R`>>K!QcYp%q4qtGG~cq@%|9Pc z{_(~Ca@sFlhkd`X=fm%uc+0aZFP+wl8H{Y_qNP;2nsXx>@vKxQq^p5?6anHSrMUWoVFQPp&?Brg(+mB0@yi_JnQIq?)L0O`;W&G*VGbwCx-8L*Oq_{ z%EpmT8k5)X-Xxkgz;caIxt<@86%7$0ijW=;G(tzp+*&&=HCIpD(3|UNM*TV`LKHx% zVo%(BP0fS3hQ#$NEktZ>jBz0hmo4X_3ezHLx7*isn)`d**M`MHj6FfcCaZVk`d*-< zsjxwKSkICG`P(;Vfife@E6MXOluYS9>JfJL~28bkmsRYrGC*@q5 zj`JetS9Rm^%e_OdO&)!G`q;A*dmicVTWIfnGqYb9-}`41uRgPJrrhcwj=MI4*Q>G* zHn8JpI^`kC0A$DofxrUFkQrzOGB6HoV4O3sXc&{jlp34V@CX47OH!!^C9kWE1OuC+ z1A{(ri$2p)>L{k#6o z|MJWK=;!{~-hJ((@3{FN{D*(_um8?(KlFiP-~RKbuj-YYvdC4?s01=fj3^O;JaY`I zq6E&YHCe`-S?&J2?N+Gbb*bxwsaV`qdiTV8)Gi{n|np zILbTuTo&>t;#Y3r2kzpxUc`$h{;pP?)EX47%_2ckHOZTlk zu;=35RcsXiqqTEx*WN=rj~>~#Z(`TY<4112^`_#UVmVy7xP0!+g$o;(HvD>DR{IO* z2ZPz(f!#YN=Z$Sf?|eR%Wjhdtr9@2coZd0FcXr40;=chly2?{d6C78zL&YpwAy#2BqL)>;WdtTPki8*9s-|H@xi z-nZLhAR{prmF%3}GcnQFEH?pa*hZE)Ac~4;Bop(TCnh`BE?iz(T)uSn>R@eide>aL z)2h5rV9&5?HOHAv5?vFsvsR)gkU0y*us>Uf^# zS(aB-(QLHe{m4)J+$VnN;fLPb+gks@<4>GAeI`_K@7}$$(=%DiZLM!zJ$r3@s^!b- z^0{k=kM6tczB~5p+tuw3zWeR(fARBQ`rc!Yo;!Wf<<0p$M`osXl|?9vGRxY{_81wf zad748iKWHU-Tpf2U9lz*x4FtU_SO3Tb-oBv$sZ-B7&BXDBQX*?l}O}_%bKmR=wUd^ zTkX8niC(JVAXLNY9W&#T(+gKmtt_5_22NC)0zzOSw)Hl~1ZIgbIcSNQIE_{Xsw$Bf zDL*`&MMNSJg_PVNxNGFpubJtKva?_0@VML+? zlRRRok`!L`2zOL*Q$zil5Wq-nM1V3;>3h~>&1NU`eW`<$;%dV+I;~FV7f~z|D=KT9 z#27`0)UXkR806y*|Khvueb?Xr!@pO>a?jMktztcQ4kTG4W3tN&3)dgq^9#T5bN}X# z|IHV^|GAy{;lfvj+>FldqrIo~>8Iq2aa6-NIwz_iCfdBO-Nm50&Hhpb=c|)@^TT`1 zfiCrz%7wMCHkHliJmF&$F=tn=ylMU&)7bUg=9gCFbd$#oGpxoqG~709iIr3UiP2kj znaP4EV3Iv1E{qbmv6SC_ZR$Fu!}Ov2&wXVVf=XPu-9o{f(dd=;lk+ z);XDKwlm8BnI@SWLdcn>cAN1DNMDVk=1#{^bzLM1GR0A%o5`_XNg@TMB6@X2iGa|(@guqSYGflc}H^22Kv%NoW zVX^$z;h8@Q-+5(lmW!ChC_X@fMnl$c7-+!;43wd8hQ}MtK(Rsvt3iX;pazj7l27S} z){He=7>2c|9!6Ay0?-IZa-s%NW-yV&8o2rxnl3jC(V#IJHU=nSKR~Q;MXao`(^GSe z*jn4VDq1l)P(oHnCN3gQn#RPh5(C5$kqKVQp6Omcb!c(%!sT#LV_6Tq2_zaNSSD5B zBv?rcE~HMM1qcF?A_|Bz23Uil2%+g%G*+U`JnvTFnHTyy=i75XdBfN(J0H4h`Rf1n z)Qe}UJmgse4QHB}>Gu8A?$(+wDl$wqw^T)dP{pWBDs_v@whgk*?*(cPk*Y$O$S^r+ zT+lT~xQF&1r-fH!*_+s8gSvl}e1uZe)W0gGP`?K=zhHmjAol!G|I?4-=|IAusF6~W zio}}0!>GPvM7A;!fkerIQyHZYsftjP^gc>~ajDyxG^&j0_u_szWX{_#5&2G{;{ zWlQ<(Ffu@%&A+^+Zx@}2Sq?22n?JfukFGyiMP^pVp z>w^Z^z#13>&S2O5>gA0yfHE3_kO($`G8Egj+jX<%2%saeouh!x(E>Z7BL9FCGKd-s8wRKR z|Fjb;YGrc5GBKq^CBLik=#?W?35X6*(n`=qBcsd^tBOFGje$kd6cZ4|b5)ojA}v)b zUF}ZuBvDHJNi6~~0u0{NWm4*S+AKF6GDFtdtdd|P_Yx9ouEK&)X|%AZdK8dSOO4bp zEkjg=65Qx!IHA1@uM97o>)rC?)Uo$XO};s6e8}B)*PcUvId}G}>!;6byk2g0A!=+C zGR)(yBS8(>BKn}g!ZgWv)ef49KpMxm;WRUe%*c>C+oZgwvCX!k5TT`31Z#+*M1{$y z(J^g_L@>^}hG}SwGVrs?hsWH(xrsa9F*oy(3ArD91%p4WUjFpTV_#i=DQ<|hj$K7% z5dtL7O(T+2p(=f;9GEnQn4~lyATk1=95i~Brfa$^Hz8XqR)Um6zfsCCXkjb?mK6k( zwnzetNK|pCjb8Qa0{{@CM2NK}lRU&BNDVWx@g(D~xf*IdT+@VUxK=ZgP%!1MNJz;sDcVvTg z&lzBG&j;@Lm0$VAFa7>E+G9U$=B#-zhO{VoF6Lf@(~dBc;eNQQ8#%2tidX z8iC5o`I&=_J-5rzz_MKS2TNPeE?s@`2hTQ<&0=Qf^}CMVe&pEE1NYx?d*}UQeymvR zUR}6yFUp|X+psyt#`BU)xkcGjHYf+@&v$$4oAYx!4&89bd%v;1 zb?WTPCtrEV4YC_>F^pI;A)Et?x>1d{0U7$d-vc6+Tth^L#95*lv1>$bb!^rqL3zrMV*aPq{Zv!_q`Shy@N%d(N> zKmNg=__>e&!hQEW*z0Y6;d7sR{k7LbFf}!E-HrQZcFbOUWnp&DL}x6!c5ZcMPiNPz z`5m)6_Z{AK_T+_6{@1_!!dJfhaPn(>F!~V+B zxuxYZ{lNx+RII8gS_s=>v$U_LQE1vy2{6nq&8HY9?b6JK$x2jf96(XI(e7l8R;-Za zE^D-0*05wMKP-#E#Kic-#MHHg^NUwr2O_amqhe-EZ|vW*SFpP*2HoCzQ4M{N7$foaK%AIaRJ2ZF zG7>|KzP9I#*j9{o$ND%^A9c1}uW1e)hSioaS+gywSn&wTLbKljBi z{P9=*@9BK6uT&}9tB0?n!>9DAC*{i#fx!YH@aSl{%~~h{L-el6)fwK^lIB8r&e7No zci>&~@9EF3KlaM=l(oj}R1o6@$CqBbY5LZ8jPHBC_`>VeV+PFJiqek?!)<1#Dh&8o zvRXsAVe+DeT@)47%+8aJ6_KO%1eJv&mLSzodOOXHdna#S9j*(zLA6RT{`Qam`u;}q z)yFp`;F^w=V4S)ZMX$`5n!xx3$Rc>MjR zhl?-E6^UU-lMm*ZF+-7|Y7q4VPgHpctZL1$sEsMI>#Q%A=ofK-@Gh>-witSTaE#2p1ed@{8OY0wCA!jkZjD3LKD z!5D^uS(!{s`o6U4jLe2$13}Q@N_pNE8eJp>8CD5V#28XUB@v|{Fez>qBp@awf=CQN zP7IY0V>A|Qh(rWII6@4u6keJP4A?HPVX&r;epq7rL#yow%GOTY1g#^)(fE$+;AGgj zmuCmM_Uh(iS9QU|6A{!ZL~B|dBbcg8G?J(#F(8egCz4tAjdAa2tocI}>-MusB{wzW z{lnQ*y3Ngwc8B`=6LjBxCIr%y!OK!Vo!Ye-DB;@}K~@Mv4s1Z8As_}Kp{&j5sFGYf z>3{cs4?A{oryYkw^Wz_v{qMIQd{5_t?-T&s}{)=Ca$6v+zH7N^jPuR>wQ6>@= zNP?i8#Qyb!ku8iRP3Os!oM=G=5hAA)RU^oPnA0>vBDQm<*^I)cOubB`KJ;`8$q!w= zq{M}aYRdi{379HX-|atF7MI4F`&-)Uw{2CRJ|I+~F+Xe^_KIyTm(2(CsIjq0smP!@z<+Qe`DpTjm0e^dDhC=M2={} z^n&ZYYB)A9npffkfs=D8-I>WQW-U@OnvuF(4}cot+_{#j_*f}|YOL1@5s(F?(pQKK zK@J>LE21kWY`gL&O2Y1SE@MpsQcKlxno~i z`pji45IFVVLDP$3plOw(6rQfCLPAhhTrAFisp#F%y!mkBx}Dklgq_N?4U$5OL0Miq zb@kk-OJ9fE)7f>?gE!oC-*tO$-f_!aH}ktF5Ed7%ET339{@vFmbVsjSte)RcgUN}R zMk_al2b+U3L{T5MHbmJNcjV}irpf)VsH&~ce)99*_{?{9?V7*)-dk_F;ns(5efzKc z^zha5FFpC(W6wVS-0|bb7psM|el2WXTG+hQu(`3#*Os0Q+<)`byB@jey|?q7FI;-& zrSs3Phb3d!<+&j%$5 zEM9u)_~X~ETqai0pd!sipbSz2r~zQukZ}^d#;P`ulK}`CHHB-?i1w(jIPr)dh%zjy%}#T=;hVz% zqd;80FkGvannin}H5Q`}K$f=$)n-)B9Koin2G`FX`}L3f=I5XM>?a@lZ%5~D9fY2$ z5?kYl1e@!dtoozx|GDR0e)V7e`R|NpyWySZuv-ouq8k_V%+vDafC0gbOlaFj!O`KV zj_ahZu1n;7=14AnL6>}m>+SA;_~8HW!tF2q`#=5DzTMo>I8>Bz7{e2*Pu@Lo?|UZy z_Ksrz6I-A1vf-!=_KH&Al#G%ZFd$XvH?k>1nJNr{iGvT#Y;HW89+c;{;(0|>cn=*j z)5m7tRw;Qxh<XG<7m%Nvjr^#B`m25bXsu? zbd+&~v6~sdI{b@% zDnwG_sPJVhWh0oWD%;V>c8)hEycYV9nBrqMW{3B=wGBLeqI%_J|N8%BIz%tLURGlqPOfsi{^h+5;( zc>PrWz*86P-D7%jYln@KPP3?=l2zK~!oJ0()hm`f2u;$sjEV9UnDR7b*f8D+{q zR#hmhVM8{Ei1+|784vfkoO{R|xtn)?H=Z7#ilWX?hye_xKro_+S{=jTkDK?8qxIjy z7oWqcmNHd|@Tqq+s)!;9-?Yv!t&x}l3^v3GO%qf|lgU2)6GnA1q!10eu;<;K_kC#Z zd#-ElIorMX2bVwfjpET2TvG~)SRn-R6^a;twzHS0o^g^uF!K9r zO+loMC8m&JC}*ZM)!NgsJ2=wNZxnuch(2lwO-v9ifqn)g%`)*rD&Hhfp%Kge|1$$j z0^9A-_Vo32Xz&R1)yYvJ8i2->IkeZ^G2NWl*t-0Ze{2Pp0z8OFjY1QVr)d);!^A35 zgX!&@+Y#CvWjxf(H;rgK{16uXA=C;2+4^(otLv*tDw-%-)lg@*fQU&&>UTk6yVD{< z3<>GMsK$EdR!uE93IhhfBav|0Ygi!&F~ufPV^URg^+H@OiL&bV|E2%_7wO&a#=GB~ z-FsK|4}V@i{$c(06Y`};<-6b3#mf{cK+qoJyaRG7Q4}g3)l0Y^|<+*;L zSV>Y;6xU{E9bJ;Tdb@tMP^wwwH1t)BZl}?JBn>K*iR{SttSR-6iNK}TrIp^AL$l+i zEoV?;(QHt2+;oCg8*#&vr}Q?i?;KL9*O7EG08}(WVacYZ5K(n7meb*h6lB>kCEI{N zW1WM=M66nC5&&p{l3<%~j%=CQgh;%W8Jwc5pcZT?SCCMZ+1!*c>DT~LNseCf8W|=+ zl~ptjwHH;r#1>8D)Ko&DMGzm+3a;^NZ}pXDmJhw$zTDQMrN|e)o@tMiQap7`pqAo-|@BscV|wzxu0Q*w^&c#)ETYVEH{qN> zy%vGPAoPb4w}xBZWtEh}*so+5)RSuNEZCA~14acDfEr~K(pww$231QyQ9J{z))Hyb zjtZqYnJNSlVLW6*u&BmRX1SG_+piG%$^@2tWL_}4ipa_W&Nl~~e0bm#dM2$jBFa-7z zw=S-oIC1IN+{E7bu>+TSE9?w7#uy3CvLPV?F&Rt7Fsl$TWj4={XPPwo@Jdw%LelOO#`_lvK`(-CUOCY_}rizH90 z7X+;j0uYdp@;X+2F#PUw!>8wY=PtW@o_FuGv$Hh0ud(aq<_%*!DXbe+cjaqKkA7{* z!OR?(*!!kEJMW&IJvedeb$8x)!<}#Oi)YTAJpSD26EB|Zt}I`ioA}I{)Im`yYDX=7)dehPNM`yWzy@@mDXuwlY{| zl#RS$jZsztg($$Fe0^i{^!eAAZBrV%$LEDYZ>wjWtGxG>&z)mX zF&H-6dERlwR&d5bWiaRgP$4pg$@B*U@8ej<5_nit*4X*oyT?17YB20~H$U^K|91TN z3x-)qVw9RsL3 zayLk)HFn$G_aD9a`d40j?O*?Y{>@+hGaDhYv+bl7l1Jtpb7rr|Nmx+T98Awp4HYHKWaHJkzu2n? zo0upEF|%!7Ro0sMU3*<-7A~D!S~>#)$U#!5gwb?>1yfQxu8}7Xo;Br{zc_Yhm2~tU!6xzlZm)kn3 z!iWadr0F0?G-N5pXsrck*dO-#{a(Mjw6u8T^0lfQm>m7#khdckwsSFvNfEVvJOpJj zFqvr7q_j+@%i5wp+JEayJ`$5bnc%~q3XMkI3ei{ET^%fr=SRjG69JX$nC|l0upC&+ z-d7W?slWMCzkXr$;=lZ>f4*ntfJX_5L@ugiY=*<(a4>ksLyxR(t^Aum|KD3~I*(%k z!x^1FfI}O4&9$g?5CBnhx-DBfBE-zoSY8Sfae{%Obe&f9#9X#ES z*Q)7uP7Uiiqyl2)jGA-AEYgnZ*u~GIne7HHoN1WVzH&4o)g;;d?ar#-y0o<|_q zdPo&Dc=5)nQuMxzz6|1>ZRTdo`@WjUK*D1f>EVbds;HHUmsdu1`TQjU8GU`={ zsVOH!fx!b*`2#Joe-b|X9A0Iz#OkHmjyXyk zQ;?`60zrMWt|>*!#*vF8ED4>mg{ibsh#7_703<3N)eYILKXc$?JKK|=yYP)qFMi`y zyj)T@!mEj*aeHgQpGzh+5HM!LI)Kp@bTYYBQmck#pbo1cA~`}o_!pFHCK)xV}eMMmPn z1*|WdW)9b2ux42bl+gMTF;u`7Oe2vqV2#E=s0Gh}s-&tLPI3v5zF|uyBI5`oQYEXj z)^(~h^2d^h8Zunp-`fPY3Y3k55>bfSUH4l68_EFFrd@BEd8pYk&s=-q((r0T5u^}! zM@A7xLIxSFf$2r#I=Tr+MIoxNY^_?528j{E#zaD$SIHnpR;_`tRL43Q*q~J@fk+fV zC?s1`i2(x!BoKjTu!SL2Am+@Rr$F+$*gfY=6s42_AtD0eF&seqQgmpn!($d%Uy4eD z*VxYT4HuvEOD{cf^{r?7cRji5z(>aPA&lMW?s#x||JU0GzS}>!&|Q$Sm02Y#OcTg@ zvFORr!7>zz32HfVj*(1ZCO0j1LpYOIaxz4mbEbeHo12zUM#54Q(^?*yZQc3s#BCp$ zrw>9i(0N?@y{%{eWc|?-%a>8wJe%ZJKv~2hkXOrHzquuw%B~`BH1^B>pz3-pQVe5M zP=MoHg-`({R18Qw2E(!|L5)o%sF<3VpB$eU7Msgk%ieoq49GxOM3j};Y%{4N2?qp0 zQq&cZNUUNR$fprX-SNbv8p==w4P=a^Ohk|rl&NmTXoy}AiBf8pjZj9*n2rM8Zw2Xs zMmLyB%~GV)xcbAi!WbHTsHy~kF#wAwQ81Y+tHswAe_-spXF9V>{Z{-NY`W}+Yi;^sJZUDKuieB}?{ zG5*fm%$fB*i&w;g=sXWusX+4!xeAN$t#zWUfxk3M(qxnURpG~SsZ!J`+y_~^y2-niqI zn-1MFF*SAsH%<*_yXEGf*X?)voN>F=CK#|GYeXQ?H*9MxpIqF$y1Kb&tQ(W&-s#r8f{#BRR_K$MKJdG30pTIXU2WjUCg+jZT+!y3cp z*3zX5uRs6d0stZtC5(@azxTcG|JcVr_V8QYy0*IV=}&$7>8GBB=%K?$$J*mwe1Fhy zQ-grZ7cY~<1J@n6<+j`Ixa*FyXD|HjzxcoY>!1F~i^rcQw06(jFwvPZF00B)Begmm zo71r0E6d{Y^3wX+l`8fCFdL*im2IQXXu!EGz^XUt6dMeiZhHcW3bU>EaOOm05NzIP zwa3O|q-JZ(80#Ueu@13mjWspGIWxC&cXwmu!r7NL)-Mwqz=8;zN;`R^_DPv0qr*oG zl#+U-j#m;9B4V~_={C$zNR;FwRZ%9R(O$lEd3Aa1P4_==+ikadA1YtD%*7aogQ1F8 z%g&ibvuUj%W{?t@7^6_kaw{qz${N=DASxQj2Ol+BYa6ZBB8dGg~iMLK|h8F z1CwQxtX3&nLy4K?|4Y|@hg+6h^}+COt*Y94pKx>M9H*xzXU!;#ghmk|36Kav0t~#y z#$doW@q&3xG}zw<#x@uX0wWLtl=DaU<0pmU3-JAO&iX3gdY-uaO=o7Vr*@BaK$b1Jt*x4)d(JS(gL2K_;&zjEWX zx8|+ZpMCBR$#6@id@M(JatrM(ssBv;Y9EUXlaSR~nTFK@D?J#iFaZP5MZJ(|W2e2Q z87CUz{_e!5AOGDa|L`aO;J<$8KmPW&{^;4Wr?xh>w4^D<9$r4ACEc;{om0*2kFNaP zON)<0oNq~%o0eKzR>6RrYf44Ec%i9l8pTv@GKn#UYPmmcY!hN4#Bgl#2*fWgozkkD z9h|sxe9!;$!GCUNSGup2qj|$L9OY~>ih;<%7K*+|Bl2#+RZRPs_b{fYKD;l+xfjCp zSHigm<@7X__ew!9p>*t=(MTZcnv~*_F=u<>eJ$1qozQL>l>^szjAoVB9r!wnlc0W;-|0 zhMfpa{n}I2*Iw)&S?p+TD9d^_s8;Z5xyr#A^XO<+mcAUsrpedl*`Bdx4ni~%ses+x z9GhskSGs5BtNEB$1R>TaF(QBvGy(xOhFFF;0F4{Un{K=>QFM?BX3=_HTT9iz0Et9J z5cO%xj}nxPQC6_>a1(|aYn2c+KvUdjlg?oy9U%2`YvNHXMX)`2ro zB18;xCI$q{#UNIXRwv)s+I^?p`Di#lO+F|ro1hv*o$B3m^N-p0d-Z=2KK&dHT9YXd z$=7Z)L@JWFc%sSkMpH`$KtzZ*su0w|MhJtOJZ>plmc;>9hV2`vMj};>1BCM{i;tdt z{;!t){xnWmj!F^`g#xJ>qNrdHGm$49u3f4~jwO;HGG>$T&>Cb&^SCSI1obA9dOjvH zhD_8r-#J^;TAIXraA_SO1p@>n55d;#+Hc%AMK29E&lZWuFdu9J^@%z88`0m&9wR`Z9f12I6 z11`oVUkqRRQhe!IEG-Zb3I|uP$yDn6CJ4wFRjOM}N^ZTZWa^xCtbSHPomnJct_itd zkOil{!4I>4h8J^vI*0u}kxCr0a|vuzQxTJrS0h7-e28I1W){M^7B;obNRBDX4QB1d znZ7PCRjLtCOGslORkCn~p&BD#$(lr0CSy2Dj0F!LNyrd<+Cmi$T(BdnDxjFI4T1`) zpvr(#J3ya6f`LE{Sq4=a1Y`&~+Ym(&tpPg*NkphnI?^0gK}ykU72z|^1tDM{@B@g5 zAEz-#nPpR=v@BKV2huX5FJF4?=-)2C{n(a$-?OIqT~_bGOg)dyF;<8$oYxYvh{~&~SOd`*P>J+KA;_j0ja}QW>2~K=dc9C}R88GR5{Stf zRw1xS)$p(gR)GZZ$`MpM?bdf3vuO0uD?(5&oQ8#@#B2;PNvxs@G$i9JtJ2XqqeQ{D>MBvCdZ>@qamINw$;jG zFd-7>g^L+=c-`cNh8aEf(rYu9X0F<|_r+reE-rPZ#>X3Wu+&*zS}xUqpi!bp6E1)N zLk6OPxV_j7ln*R_ZIaiGW$U(J=Xrm+)Q%;ms$@(e`qXK-_2T&*u$zS&E=93ND?M2` zFXw^hzg6Bhi8WU*?Y_F$y}z;d+SdNv>-XFmuTrwJe*Vm*bBF)%;1Rsm+}7Uo&hZU5 zt$oAJ*WL5OcQ1TMUt2nM`uK@s&z(5>>hTlj&zzk*=NfL!nzdwXyJ%9#*tx2Totc$g z+s60r*|T%=mh-QjJ$C5mt4|y@C2!rk`P#Sdzv-SE-}`UgdgSb>ZyxyCW6wPD#0yU! zpFIYIrX6w4o|t?7@XS*dtu1SJPK>Wx*Ivt$8@pv^era}PWf`Dmqgga^%eL1YWUk#T zTC*$X0)&)DYl|JaYe;q`A??ks-l??3g# zfv3Q{b<5Vt$w?Sln3-=hi=yGC&rcT(yL<2M8*jMw>g%sQe|qLm{^)=G^~e6|@uwd* zC^k>-pBmrjilV>LGipaCMxC)M%Zr`4nT6%)PG>Qq0#MV=6C1o{;_4OsYTcgD zh;7XYtY1=7(2QkOR%Msvt=4$a7*Qc(sWmd%TkaTBxXfA3R1v&izivafvvlO}6aD@y zb3xWgEudy1l9;47s}A_elxD=q1}N6!_u7PlB-vx8?D-f~g$=7p@O`FY?bP@+`>(tC zhMT6Qrh0>348gLg3tgrx&)V%~vt1a=)xZx*A1e=rF(%71k;rvXE`XZMh^T{eStcr{`*9RnTFi@plSA#bZB6R423e6 zi<279M%w37d@DjM`_)p@P2|4Wm(KLy-1=(k+KGuvi)X9QGu#NVd(WNkdhb2&`JF%c z&t)t(j&JP@W}UU(S1xlPUg<1t-L!klmc3to_!Hf-Gns9Q;&W<^(gx4*rTFa?%=1u> zqlk6etc)bh6-8o|V72tD)3;~kGzHp1JDSL@F*lvjQ$P2Yzw}!_@@v2Io?rcM&wT8m zr(Y~gv4+<;6ql+?_n&_7_U*U*;F^DT?dTgGzWC{L)hWhyWv&OdZ$+5+A zmwMeZO-wYhrscx2=>^Bl(RRLWZs9P?^m#q3aZpvdJ#YQa2ma;evDVzvGcIps)|fHY zlC=au$%>A`>?2%9*l%?gks$(M8sT7^JrJkwms2l>v&$&gHL%xIR{JEuXkS7VAckDd zgF*C)pc-P#@{AZ&sbY;Nd5_4_^<~$WQ6Nza8zv6E5*x^fu`1A>4$fD)FwIUz7=fw;B4uKw5Nk@mr2Z;hPU-H5b%C4i1r`9L0yu$TR*g}GNWq%AXn-Km zIwz9+&x90S0x>fwvxzYdqL5*7rt~qhCUZu}loeIM2gE39ZS&-Oxp1o7Fc)-YI?hk8 zr9t23QCJG=O6ix<${lCfLbvK>Oam+r%IT$9QMF9IZUKdc$PP2Bs;HE)q)%POm!82vrWAD)pk(Us(X=U( zXe1&_6p~Y9-Mm3n0s@c{Zj|5(JIZQFI;2UXj?~*TNXVb7&Yqk<`)WLTflfyBjIm0B zC>lW^%Z4FJ5mDE*Cbs44U1?KWl#*m>`=dJEMp9R}N{mH%YHiNM!y}X#Q&^iJR%PfY z$|1{lm0yh7#R->T*R<`VxWggi7DEX`y>C(7wO#S+u?kEBAXA^30I1bs!tCDNcuN-6 zUkZmW`lpxh8c-1#Rg;E?SNbZ|IBiXcNe6v(svGMAQAGEU;?+O*#aWU6@BUp`s|~FPu@x6W3>6|_}1&_mUaA=z5I^5;%B~r zZy(Sz$8qVDF3*w8s4)VzDVM#bUh?qlrU3+-;c24U`I8dvMUY5|PtF7w6(uOK5fP{o zn_9&*#F-g@ieP9xo>qs|fyXdNJxx%OF0m(_XXXx^m>cU62EZ7NZy&uys64sw*os_= z7zAAgt4+rQBpMiwDXIEZA(kxF&apz!jF=fwB9S8^IE4kb;EaJl5s{*+Ab^%AbDQ0~ z;r5H&b1%$4lMhQVKwM3q77z>*M>QZgASMoXSs_#kg7FAoA;4n*7$RYCnMx2IvC!PG z7wLwTUg&|yM%QxfW7=7K;^?ghS8jP`!ZwnyJol;jZ=Ii+HQZ=4y~d^3E2Ud%)rrf&NU1@jiWmfxg#{ZnhKXX(z98f_Q;7^R zmL!S}Yo&n?5!%ce1!<4E{m@tVpw;xk#gX%;ErG-s%8W6ptZJ-vMvVrrHKet=3|FY5 z6%sWi%&<>`P$Xz7L>UMP3~JgwODglAN`@sy5g`VcRiOcvoHd!JGWZqH00v2$4N|J7 zC<2qx4P)K40?ZjWi(Dc4;c~$c1~aiCW)U(*ee6#!ooSAYt!ZrNh0|rNJp)mQO11U1 z7~(vN0ZZaXF&U5@^t(HEwfBE`qT30qgaFP+D=dGmyYTQ}4QhxZoG}P+uA!avZrTG#YoN-tj^jjvkhl*wHzZOur(<6aa%<_X*WLE*N56gejAch_*G^Pn&|T??L_?$y5n*D{$i|pDB#Ri-GOf|}Sc8gz zFOSB9t--~qY~!TcupFoRvYd8bP|al_Xw5jPmz80OT|3^SVQ2k)A`-+IT%3s)AMQTt zy7{Krjn}uXxo*vM*G=7U&G`OXHeA!d?H%7gd+FkZzq)kXpJd{ZJ0>>Vy=MK+bvNvI zr@amrJIgPedj7c=UwQe(_S*KSi}C!WxoXL8n%ca6Vtv)? z%}!5$@el8P;*&32bL+l+Z`$+Ww|w}Yyz`&Dcqd$83M-gaeR|M!3Y#Ipw+THDuOGtu0bn^6&Ulr<;Yk*cNc z!ljj&xw&&azf{+NWT01`(Dcw%*NS1a!Gz%^2@spQ%Syd%no-pkgdw(h-fE9bj7_ZZ zUb;*DVx&n)GR~A24e{DpT-v#J@6!DAp_d=@VcD35f>o0w&1yXat%+MYRQ-s=1njJm zvJ?u9%$C?7O;KZA0W+zuda9ThUAJe?wKrUM!|px1Vu+n?7pg_GNMg4<%dN9TBWtyr zA;hvQV+@(I!X|16Aq>hg&zy5sqI%I(+Earys;{E4hC-|c)nG6vy(i*E(b~Rs$A%5- zPn|h=`rKKG!X~xRsC#^4BnBnJ1VOBO*1GoL)E{0^x}=RY9o%6(1Q}Fa%S9t^`9TQU zIlXwSt7|&t60?cY-M#UufAM2K`|U@*`Rpst-?00(nWYOcfDqXjjk45T+^}ZTO*g#Z z!Dqj6arWex+fs%q$H=H%mz(@}`Q)NrNUVx~1gk2DVd^n<@|s8p!DX@=5#&-l9>{N` ztxb&YqgyWUg`fSzzxnyQe(~R5`!m_GhRvc=xdK|Yi_@3_uKck z?s%qu|HCK0w$MM#wiwTMsIAoWN7ub|$L+hy@Tle1m!5jJ) zk39M4y~hsU=i^J)jNbeoe)Jb_xOUsp*DjctJ7-B%yHP5kg0L2RE9|X|{fy0t{-b(C zmY?@?-=x`xIlVZzuo$|P z+9aW7ht7Pr4^Td`?_z5msv*=iYu5KENkL&&W&WJ5H}EC?WwO>z=nhHit#n)zB(ROupf zsYD{I3Z~52+*u2PXfQS?sTWN~XfcYld8;)wD3|)aV_6NE#Oyb0hPwtOma(cbu?*|U z)N2Wes4y`TQyna+%nUVAgVe}snw}vcADJ;kWQ~y!f z7-GYas4zrPhAd$ypiGD&L`0}H?NAccob$ef2mHykMe7i z%*W#c&*NBTG9n5!uvzzlQR-mJ)gfa#j8c05)l^v35L5dMTS*wmN?$uV#AdY)1WRnp zlC$W`veZgA`Bg>(vc`(QfIP}^ZEr6&?Aowp@9dUlnRQTFGEhH6AW<786NdR@HMuqM zK!-gW5iG$H<%CROj4fEJnEIn3tTNBxbl#a$|^neeOPm1xCV|)A->J z@|&)~o=x;iKd$fo9vps^UVKrXIiN2*t1HvwGHQ$w*_foW%qn#pPF;0a2N6<5&HDnB zU{Z4)L6(eDA!yJz)cugD`Oh`xT;B(p5Hc_^SXgW8&>?lHz8fhif0@995`LEEBSo*g z9L+-5I99B6X0oA;HTlL;&t5EF8laa&L!7W-P83*05KTJn=%oUzMcrLVj4IZ#+MHkj z2BLsPC3>xtA}It?p$rwXeS;+BjdbEbOpmgSzmqV4c6MY zZCB&kdnVR@a0K@N40;7~U+NwF%-o|-FP?y+J%Xyg6gxqy%J;>Dh^kay`az&z48<5D zG-`;ULMBlLqCO%-B_p|U#xhr4DhUw^hSxBVpoWU9B|tw0QBUMo`g5lR*L_ITR!ceF{HSlL!@}y>6H*b+D$n zVPP;n2rFvUFl!77QDqf&oQrZ)m)1a)7>z2JZR6tH{Hcc)H{Lzs7laH!Nsh;budTFb zoYhW_Pab~$(4+tD(9i$Y2cwO@{a=2)o6oe1(U5n#)nd0((hP4J-LP(K?WOL#fejUn zPqcGeRQ=c-Z6cb`k;YVG*PiY3$L6O-CY7t1{^|MGW?C(4+qBYITIqL8+U?W&%7{|8 z=jnjtCJ!3Bp;vL)K`%$UkIw1p$Qrk~WycVuAD5#H>h|CtjXAN3oqva_q^3NA39zsP zuE8b3X`DXQJ^AJCSF=-N`>_9x4L9Aq@!I|4*Y4fEXaAP|JDY2+oBYVTe&V0J_orVt@yypB`^vW-eDJxW z&jQ|(%bXd6`6H)i3|`*4Y1jHS+qR5sSifO?uV1b#F0CvtcKu-8`psL{ZhiHLi8{z# zmK#@f7sH@(mIZ3qj*X5F%D#s9#y7n#^sBQc&KP5Q-EL=P#kwqbbvE0zclUKST{Clj zZef1<@uwf1ojcFQAZm=^jyvx9(I5Ws_kQ5}%X09Uzx(t<4?SvZwq?uK(XlZySYBKl zn;4Bk=T4swGT6Rr+grcut=HXf%}X!8^q+p`KmFau|Ka7sFEa8SQ`b!v8;iyWOP1Lt zF)4>`n7gp>+NDb;%h*M_>FR0Y(TC zwrCbAYMr&#^arJ{yef*K(P-wGb7iO&<`+X5nGIV*B*tYiN(>?jVFiqYU>V$OxGc+k z73X!fGk59IMbXg6nq#f8`K1L`GR%>pthSv^z;3d<^TPOzqxhy9j@t`zR~Y>y|0>0*YEWU z*SzVvH@tM@xuYkaY3J)>tgN;Q9xF_KAs(L7lLl6~({e7rP6yjW9}LV$aZ+;T;*@YVA#| zw^E&0GlS}opE(d_ACj4uFg@=&4XZn{j@2$}r_$h6E!feZ)DR>Zf}!YDM8WD+2I)c! z!H~%;6Ck8z^n>7oiXodf93ne1fkY8SB?c81SPdc~AV);h4PmCca$*@98)LU^oVseN zZ3;KQV6N&(q=AHvuewo7A+}lG$b`X4LYy%q244k}!LazM41+*mGU$}Og%!79G}|+g zt?3NbjL62ji|k@1U#-ezyQZ+OO!p2gEJRyHjf$AwUPwR{L4g>AEfFWnBJt>1$#OH6 zn{k!CXa$8KYi$n7R5ZpI)kl$Jb)rb)=F}j@N~==(f=b!Ogv{1T8j6X!N$C|eiD1|i zBm!V^v8CEo2r5xhBBPTcNa<0gAnmlr2~@zUFvLcoWE}BGW}sU7Qe!YgxwF=*#%iL~ zY~_tX75f^X(#jnIGHZo{*X*^koh{9B{rfgIZ{M};*nH`1;c2t6ee zm7-?G3}O_{)F?!`)|7&4W8}o-pt_8vy3uX~&KkqA?AJ6Zug{B_(eVYEP=m54vnjr3#G^aFju1Im}h)MU?5V zC(Kil>QsqHV59h`2y9d(sEQ%ZrHG1dTv~^<-#_;5^>OW|Pk#N8-ZK$G%83YrB-gA9 zfYb}r?94>a!4PvyByc9nrcgx)B?%&{h_5NWsycL6TCFo^*f6Gv)0K^2JyE~>UWe!@&P80UwSR{&LZ|= zy{V_LjoR$JhJ{H}QmYaVM;c0;oS7)Kw?m*c)}W}QA!aJ%0b&gT60#OY~qH8M;<%+N4!AoUsyoDh&PX#{bG zR?Bga!Ackecv1*OM^+J|iZQJlx88!jp1O3hpaz5nT15m8b!svymg4LP7X^>OxOr3$ zoI8KyFPCn5dhF`=wkO}y!1rSP+w%2a&lm0+Oh43{J2Oxi&hng!v5X?=vM7Nt0IO+J zZVfzTD(GnxuVadJo3fp69NF}JV|Wj18*~EQZ->`DyL8}z*_V2q*vxa}%hKze8TQNs>uRBfFKR+qZzdS_M+3MdS504KYX1hY_@npqMJ z!ACz>1bNDu#%5#*YCt5>jq2o{@jbmbINEtxm|$$;rzAK4nk3l(r_i@yXH0+!)I(~- zwHA1T>tY^6Ad~#eOeyFr4rbQ2$0pkAXBN-a?XxC77_~L&nb@#u4C*s>k%Cw68ur{p z|KEP&u|N3AcSoltV;x}S-eo@@+9Oo<1A^JPbK65-cxu4mU;X9}jkdC1`%nLVrgv_v z*@|2RQ=MHr=0kV;njIDE?80KR$eqm$7sQ@nHB!?x#~ULQ!^W*^J1Z;Se&+sQJB8zD zs>S(bkT5G4L8N9!s2E~VQK&Tz!lKcuU+B*VlpR@8h=C)7Ie#|ic41peTE>our(u^v zX%!fb@UGk?>aDaca)$|Nb*2^wR3Kx+OdJtk)fZmA_%dJQ_1JW^*?Y_88~1M7yLu&M%)mf9UK}j~{&mVa<-UJKnT&@79gCZQh$*Q_OVcPtRXGeQvsYsnb90 zXUo@?=I7jKk!3EHGFTpz%+^{6Z`!iqx?8UwVDQ*OPtAR?yJpkcYj54N|BbtU?O*)% zKl_pCZ#?pqZ#;6};|HF+xN@d`(;QBoKYa51;kA=nwr$?CVdJJ9Tei&2E}fe@f8)Mu zSYuyT0OpLrR4!FkjWt~PvS?(ZQ)AuUVEV%B_~_)`>vxTfwY~S-BfO{*8AYIdtUre)D%f_P2k1_{d?4#>Vlz8^*R5G)g6n@VL!0 zLF|+ZGo3T1XAkzma=oqAXt)kD>uL}$6^pfQXmwjALu`5Is5qPu*Xee|Otl6)cUfU= z(P*@@ypX&WA|bJ2qbgEBU5yDOphi6EWDTvI8h|aEuDW*rt-E*b&NAEUbz_h`&x$;^%*NR) z&z-X%Wy8!Ae25}8vyDcBVGNVC>?86#&oeT~vfD5-BtkQIA43pk^`r=CL4&o$$o9>f zw{AFn=G-fX4qZBb76NDNpzImrOy-P%#0XMrYy@Hy5ls>sN~=wcb*vh2tlm`VTnraC zA|ixX4ML}tjW=Se7v@9V5jQ#U?x<#m;Rhc)^2GxOA3R^3DDmWhFFgC|H}1IM%^%pjcmKq;Ej~6k z?<&SentGwSbg{f)TkF?;{U`rodUJK`>|-B)>GgN)9sjPioiAQ+j_u8p=1ymB&vBFC z45$=`_r$hLVsnQ;0H%5-e%d zpwTcYubF|8mKxNkh0V#i%vFQ3^8JXwRxCj@Mu{3@Oydb+5I9#O+N-LAgY#!zTUvj1 zgw(J2PNgDs*rFw7FoT2ll`*zuokk2wQ57;_Fz7@HY>A9Q)ff_WEB&$<*G;)`D{a{hVz7lR3LWW( zK2)7+lW9Z>rSJI4D+Og0UnvE!Dv3hbnh<*nowI@gtOx}HMAgEAR1$L8YHr@xuP)43}^%^3tOg)ZEj>^ z(YR&%c470}$y22m3nRph!UZp6Mc7>E$@vAp;ijwfuDj{l>D|-ag^#`*du`*`hu|FP zAeN!flVt`0HZX&Is#?%Oki z1%c9BkcdG7st_WHsh6b43=7NRR01j8*|_7UcKpZ=-TDtFzx3(B7w2%E00SfBYpW?- z(ZA`i9vIr^K$VBwZ-A97K&nBhR0$$6h4kuBC||F8a(NjXnhmAaD@iW+3f?b<+Z-!_ zNQU?`*FFJY0-^$NIo58^Z`#v-b60U_@v95vOCE~=2$_-$0qT_h3L09t>#+B`yzZek z9>j2_SUdJ2we9tL8#dopi~|30oBbWdlwE~SS6k9y>z#->5hDlf@> zpTK#!^){Z<@RBst!C}wcmvjaXl%bTGy%y0%J&!W=-t$p%ObqIBKFM4~~q~7;6NwQg-{^Gipn^MA>I% zfFmS`hlJeN!nShL%$)NB@g*WzRg-qVbbT2ZhGljV%UDYdI919FCOEd4Ktj}rM$z81 zX;UkN&g{Y^?+1nmkyW@UlQ)mvv9+=8iKWK_Jh9PqF^7c4C^S+6WRk#J6EQg5iBZA; z98x$O)yrd|&6s3>OqxV=K45uyaCUjn76?)o_1&!J3@^_wHyYfqZH66GezaALkB)?Xtg7Dghn~H- zbl$e?pz5)zA&#n+jil5{%gK>jYb!etAQ~e=W^AQ{LFg)_kTFRdt${2_sGMn9D!lfS z`(NF!4qXtg7-3$qV*mgmBCYawYAJErLSq`FIW${tRKN@9ek(lktesT~{F?%TFUui-8h&d#0f zzvQRSPR}o{*f!^R?zj;Ge1I9t%2=IQyky#qt9NW>i{~Fa{P5?W-ge`Lo8EEN```M# zKk(f@^4yVU4?OnmN1izF%rnm}gc$%}%*>yinLj&TOzqoy!z90DBANcT({@Au{TkpH~YhU`}SEgrXwrtt9cGub}`uVxp_Gq(_ z=NHe-lx278_DyfO=bdl4=glXNpZx#+_V0h}<9~DT)fby~WOHk0!;MaiZ6KdF^O4bY zV?LC#%jai$XQ$_1>*#`_9-$^=?23-)@~B$V$F38l>YblCN&1PwV2CCv4G0iXCL%J% zWR2FS%W?>{$0k&)FJoRfCSrDmtYH&F06+%)L05X+=?jOtojGF~ilq4@|jDA;If@Q9N2x5NlYEdd3SiUNge@7;6FnyJZi=T1w|v9a;?NISC*0JCYf z3hP{`qC&IG8X~q-xZFBJ%vBj#ZB>P;?=x#%=3K_mM!# zT7?RtJGXD$yk+C@N zZ4B$tdX4~G*~HeyA&^0}>`am6#UMH&4N_jc`T7ss^8;VH_e%?NgPU)?b#8G^yvs8h z$y#&$Zsp6H_up!4_N^yBQ@9aBPNF($Slj5txoLj_X4oGL!Lni9M#Fk2O{0a_LW9;N zsd8;dfFV`~21?8yjn77{uIC$f^1czf;c0o~m%sL}-)Z0Tf$w?$zi9r@Gv$#7pMLpb zZ+@+vT4y&d#+AQ&=qq<@y8iBWT=n`}e(m@*AA0okw;q4x*)t2To$kHzz`ehLdq<|4 zJKJL$U89{hN5&`DL&HecY-O20ZMz3Me{%5N3wNFS-hca6nKCwO6mOltRRjR1Q6BD3 zKOZh0kh9OlbMq3$+xhk^HmDc0Vu`8)LQk~}s+M4=s#FpQOUZkQsgxs>QM`&ol^_I& zm#7*Md<<2LO4M)}NA32Py$(X?6T#%Hu~LMnAp}v@+*#CUnLvV9!Q{ zR1v{3h6)q~0g~DV5%o}kQ6`Boqzv__ft6G=Mo$D|NDx5EurawQktB~5V>n5?84wk~ z5F>gO2~2q7!q#WeA4IuqB8GRiy_964hAQ$ja6lvt!NLt2b|b z>B8xLjF8MRdO=B*V>F}#6%uo4vC?x(R2FDl(|qsJ`fnfY9IDFT%Mu|sgIOc;h^=7;g&0>sH;JN#j4`PWg)m6l%Gd2&zinGqRkP?RI`QNg zd8E6dYOLX)9<@XYz-rcpBd`}l6|Pr!y`o63U1o>n4Mbz4D!>axCYwe9T92NS(iNo+ z%4%SQlMI$AvudGHG<;Y7)?d2%7aOhozrFnDe?RzSX*zkdk%AzIN=n8~Jwqa1QQZq@ z-Ty+92~!&JDLGObqlkJ%3B=*&qt)SE@`|QZI9$11(U5^MT(M|%`dWWm>jzfblyuwx zG&0)Qv|FZhd~3daL5{z&{P40I13bfmC}mI&Vcnq=g%~OflFQuEdN)mnH!#+Y$ zn`R7k>If=AG~2KmN<`)i2udHW{wYoYdtx${U2AdNR+}C|IHb%4r-8CGJi8 z$LB8`T8lj+c5RE-wRmD6bDc03(GO{vOX@~dA~Iyt^})6KnK2*;5FnM*Q30e#*bb;d zm3W^8GEbxwE2#ovMou6pMKC#YGczR7f|D&T3nYp}MO2A3zcJZo6A^{z4;+5v^z18v z20fC5@_J3Mp;^(gg^`Z-SnXyz)}hWy=qqKhk-sF}Gmlg^z0$k(;mM63Y4AOWKP;1X zH^)8~mOek|9g=dcvd$QG&JYGbpPS04#A`Xx)X5vNt?zHS?{RXCQc&}-&i_O8>NmPi zA6-1nRktX_QNJun2`nD5A1WbHl88zuf+%W)kOGD^#0Z$oWg=C-Tp^B3Hhs%ruGqW14d>~FLX-eTIOr#oo3~YV3?6Pl6jZAG_x5=o^&i7}RqCj97 z1d{Yp!)%9!E@>zT!xm8@$S{K_s3)juF*335`deP_W9Qjt?wdJ(kfO5MSef0;-EUfZ z%aO%{XO~W!wiO!zAR1UD0;&KAC?t2K#6D6L)a(NVDve5Pm=iWjL$+i+8;cSQlah$^ zgYC`@E<(BnhDezVvtcp}Ltx7W5(Ne%0bvl!$S@=-(Y9Mff5ZRyqh~()!<%^=<;!K~ zLN&g@X<&(75&B&}H8r+&+s42B%Lh)KzVx$y{NBHs`rrTJ-~G#jXP+J&8D%lb{(R@O zkgl6p<9lMVqSId*gwF1<{m2GTYGheaArilVbDntX$G|#voAW&}s7Y+GWrR|I1%2zIy%L*WCQp>wn=#e&Odn^799tfBd1x z?mO`GC?!D^9Cl23#^ytBsY4^fBGiA-ZEv+@EH93}dVF?f`kwE(r#+IVp2`{up;9%80C4qH*SzZ;@A{D+`^XK~UiZ+0 z5C7R8|F7f6j&Ino@#Y(EtwNliTWF5v&30p9esOtuX==^nyWalJ_kQ2I2i^Xk{?VWO z*`NOT^RGNNnosRnd!6+Kt8<#QY&*}!8hO6Zy?A==)e8$J`&b5)+0-f6|9Gl!<%5!S zc3K3%t`kva${Vg|<$0b%R6;b4jWHS(3YR-;IR=Rm^JZq)RQ<|0lR}B1 zaJh{^ypMn;s-i-jGm(&%6^)`q62ynl?Jh1YEv_uCWUetb!rks*rQ4IsHJpkn8zzN8 z2IUybWYnBgcEkH_Wy|hwKJjTUp>5Y!agb3_WNk&5>75MhnXEvNw7^3iHq|}N z5XDK=mI7p;29%uJQBM`>-c<=;P{8sLd7`I_H`1M(-Oe}1cfT56{$}{fw?F^2|7-Uz zeBg~g_~w1Leg42hPrrQp5@t8@mT_C0Jb&WEU!A{Y&E6Z{y7?#e{q*;&txj~Ff92w# zC?rusQW*LO3&%{}YYlO!8rH0ti3DOH zgk*?ade4^GKr||1zpR+UntUwN*snU3E=NQ*mSFo;Ss3T6iDgxg*|sLzC{&JRjdhj) z%+uUs-4%2iwpEy{_RuoM7!DF@a8QMf6~ri!iG@^>39^Awkk~6F8!?kxNA@=?pISK< z!eV64CXx|}QBaW)fv@e#YA$6><5wsX>TpigAkwfCdC}BHACe~iY7FX$8blCvuGMqd7&af{_hqs=g4SPjZ zg*CLUX|5f0dkY(V|LDsr_pa!456hIm)!G_84Gxn5%IZ(mA#|MHSxqobKUhJQGh;YF zV=ZD^MVPNBmHuBlF#R9@p#Z_Ies)DtW@?JOtvmCYolq-e>S@JLoi^;b>mBq8+RWt{ zHF3I01Tb13HKoLfqu~gdIU$ljt|HKgl<&$GDv%_Q5U{J6bV}+yk-`+n3(_(8jz0Vu zIq*%|wV$rKNpHBxeD|B}P5X12EZ+Be?}!gPA0GK;c={n;nc?OLvX&wvavHo)fW#r9 z8=<5zrtS~KFbpU{sEA z#t)=9F|affpPmhk5!#qh%b;jr>(1tNBdy}t{1bEWY)utWn^IhrnaPA87NBG&=OF{F zk}MxF380;F4^pCZFp3bgvSbySFm6#;7y}j+RkmylhIS$j#)N?WY`+?4ztoBV$F7o! zV3;f`mde?S=Po)zM%2@a*{C8y92^)b)~N$go2ZYn=NAVmmRb%)gc%g}`Q_fl&*H{s z$G5&GoA?mp4KP1zC*Rs0xzG2$6szZboaut|2wT!9m3XGWATK@!CZnPnL^4}gTA~T`hZjg%g+ns55;T%Enq%j-o_lV4)-;s*#Oa3M-2zpL=FTq}y4%Kq!?+ zV^p6{Wurpfqn*P&T{iXQYGG0dsW44uhuD?4Or+3Q8>OdNN)%$@bcIT0*r`fHNc;~d zC+@ToR3mX2Y0wW{NC~ortT8MhiV;;0fS5Q&L161OB0{PVt&L<{X2^_=9z3`3x!*tX zL;rc7+t*%moSueTU7%kVNR5N77dB1s~{#$6G6)sfRB}rl_H1+C|Q>oc7v*mlthK-rI#|6n4C&b z#CrWt6p~?aJ!I@$S!iGJ;MGMr9a)>%rlmYaNSf%g5==u!)HDeixpz^HefIpZ&z}E# z#?{k3a$UAybL#%{$#EGxHa`~-3k1B%L^5Bstyh`C3nJYBJsfmfP(TSH{ zI6OPMu(91L@~mQK$n?AY&PsRv)W&wvyf}UC@S#IDzwVaZ`}Vx_(o^H(lgrDCsy&Zf%+cP;c_KqxXgvkzBvc^+kpZGg7+yq|9hfLt1J(wI zUR6}%71vlzQ%ZWBWGrm6Y;0s~a&l^N?Zn7vGcWQ+t8m6ZC3ww@B_M_%$@58sg+$a^ z!%U&7qC}S)fMO6fNvQ>E*;t$9Squ`qClU$KFjK}==_QKItt+g{Yz*;SHGSgvNm1{m z?Du<7qRkvgRFp_Hs;Ck(8AHfG0UA`5QdO!~R2RBRWw`QD-*8a|Dj|idf7f;I8gEYi z>0kf(hV`4+C^Segd68LCUxsbtJ8#;1+fzp$o?bjX>bAsKIb@k@8pDhIa}_!UnW(0S ziea5gsdiKVunZDJtx1LfWSLEEeT-y_T3d<(aVT$Pf}GWZbAIM(+`5zZZIV5Xi_>`N zPmceW1IHi!*&q4o@7ngdZFbKK^M}u$UYVAat#-qRX-&^Be&LgITkYnnU$^G2U3a{7 z`yDfL@yOz_Q;TO$oH$=edG$?uHeTPd${W^?jf{+}-8a5|Z(cNT{?Ovmx%tI|3uC*+ z=04qh=8rDU9c@il`BJ-S))hJm?{o=KL0-UsI2FZ!)T??%RH;g^WkXtp7(y)>QK%0= z6-pW;gsAIBn`5ow+``JBUzJq_j%hOuUJ7S9V+KW%%9qf{j5P0477>jSVZds@L|QxB z8zK<`tR+>iu?$J3;zLjpMewl-qLgVjaG`J(4L03!5PWHzsVatR*t`+MG}ufTGt$(2 z+!kW>R9yPA{@~kw&*Z4_#o56^NtM#@JLn@ zDyXIMqQVKc;FN<0#Hd07Lrc=XZ~6K8-h5NXMbD`*Kuo13Gp88?rR|wiC1kAcxc2s` z*7zr%elVK+@XY*$`Q=Kyun|Jv2XatIKZuLbSz8h<_~O;ar>8#s&Fr3iTDaEEHB2)Z zsS|NZ4QCcY)F_U~DG}R7Zc86azz6j#0s%Ox8r1%WHQdHTKonsz0Em!B+BMSLwz*Aq zusqi}eSTrb=+wyCRz6)SM<(`Bn2pr_M!>Kc6bLj%N!iW}5Gf_QOHxElGiXZ3bZD2C zk~Ku3$!^d9Iwb9z$*nF*CyQgu(S32MLo0ESthf^&sL@_|W zZVu}eYH0N|+-`<_9S!kDhC0hFrk1J*RZ%L{0T7bsXkDHRm-At}Jp_ttxo0APCjRG@ zJ#p$_c@=;K4b`=(s?2C+W?RebAIr86;{5dB$!<6<=o4AS&^fuL&kjYMTDSTsinE4O z>yJjO3p1~>PgF?3;9-t^`UICT;Vb)BtbQ(B`Cr2ZT~o--l|>aO%@J#XR>IlRd#-Wj z8lFykdLmPIJ#}8FUh$hS6#pc=IHY-SI-LXpTNS`CR7eH33FEZtK|GROOub2Qjkrn$ z7_b8a5|tEQfRvIjO4*o5UynRRN1nv}lkqb*Nf>0WdvAHoF2CFHT~}rAe>?r%r^4qy zrsq#nudj$yv@{zbV(@6|_yG#;rCh?JEp@rEpbpwYqs7G$kvhHMJ7HHP7U z0K-Zo6+%}!$zxen9cPBvt5--w)#OYNg+vh*BBTVZ5DbhXs3C1e@rU2C2@y>j7?v%OEbwI8q}?<;6O+5Oqrow53Q6}}PT`bx?2`u^mNru|)6 z^B$*fpg5uCoXP>2{Y3xx!^=mOWjQxM5q!5Bx}^?!p^6$Z=0Wh4R@P8}fW$I+se+PW zCPP7^S5Kr7rHEIdLGXo+Pqj9>L1V#RBBIPWW|lz2hI2v_#xlVYjOCmhMfJ&US|Mpe zQ6lS%s2GaM)l7droD-_BbK|BB<1H7s(Y7!^gI(qT3K{?~S!-?3$izXQ#Mas<8e^pl zB_iW{of9k5r=TlvBb<%G6snOkbEtiRS%j#nWZGOzYFI)yKq`=h zRAdrvpv1}cj0x6pv*|`F>G#4ic(@{^U4<0NAg~cdjM2NiFa`*fNQfGkEVB^^NJX?? z38Qi*8Wks+8I-DAum| z$3K4QM1TF%_`!p(9(wIy(Xv_7@<7F_7)>MsRb{pW#3%$K8kr5%9DjB$gCayZ;rOH!M~Q$7W9+ z{@>3&hi6CDjckAW_8m9uy6%?i+&hY;xcJ($N0z?c@1CDqx;Rf+-e`@uyfBe{6}!DM zvm@7Eb9=AsoS!}Yxj(t@D}VH@TkgE>)_33d-Zy{nN5AJMUU>P%FMaC^4?Oa~vj<=3 zU}bc4H0PpQEi=q_-Ts!UC?9zIF)g&$?rqO-@YSbmPq->h#6wESJ&I zk?4JAX-OfkyX&s^eBZlTt()jkYqE#VQ6h)>&gsjG?Lo zhBN0(W<m;3J8++;OBRQ9>Z- z_~h7)w_H0m(LQ_jbWymesfkyQ9Vx5IIWw#s6sj?JO*JKqhz=DsJj5JGheD_;#|-$6 z@q+;dvQcKPYUhc3O=>x9{j zJULOcg!@lEdg|b#bDKA{wrptMwEL>N_w9R){F&*6Ypz;z{f8JEfQV2kuNQB;AEixO z$2TpEpL^=OMubT|!YePA{mFIPc_b?{9aLb}XrZjgNi_Nah}bj?N0AUCNLizXL5Qj( zN%j;~R6>lz6hjO#wu*dWtmu{1LVsnTl^9X+L>f7QqerHyoSWcPSc$cYo(W(GBp@=l zif~jIlc^BA8f%D{gbag2v_h?BI|k{*K_?8nRFNtmz{o(fBWhjKWY7?dRf(aB6%hy3 zzE^|BXkKK2xTUQzgXgvPMA?7L@3?DpD;1}oT%PVM4onFLfkchOq_y#mff~a$h(=Ln z0|O`|3Xx@-v(g|gTv(JQfpZFh-?+>N>!Mj`E z^ZH!}W)C0ew%w>2iXk*IlSk=`G}w?awlG~(5+ufffE2LCsEQ~{QYS%q$ipURGBGQd z*SdVN-9mKDy=&g^gEwA%Vrk37L_g-wpF2PARmmhPgv6|<6?(&|R*WGf%BTn@yS!S{ zlxS^2N>UqFrek3us?^&>jVVva5ID(7VGNw{W*_bPNdEnuk-k-HHM{7i|7`ltp2d^I zzO79UFRNk(;-QoywLGiHrzX&p08Ysx%8o}H`8rYbtJx4cKt=VsZBS>}uC8u1KUM2* z)$FYV1p<`30IvX8X*g@EUru$P7!g{Q))m?AR<>EaEDWCNgd+j7gkWFU_&*8kp5YBOL}=1`;JYj{?B?NuCwLpGjzpM?G?|jVN$)~ z@8Kc7%z3N-R!L^Lly1ekabB&+(hKY3Ic#Nzg8>>oKPp=%ny98A&TC`9T9i^xiBVtH z3=vod0wlq(0s@SIs`v_q*%cVsL`3Af@z~=OWAD;g>MWS=exL5xO4m-g-~4IXzu*7E zC#kSlx)5J_9?KWFXlT|XTOdG_kToipVI9b56d1q)kr1IZ0$e-!)(#nBydOvk_yE_J z2N5Ym(?}zUs}m>0fK=0GNQqvWjyyAXXe&lcY?X{L(8|m73yWVn)@g^ZVt_V{k7Ar* zd+2#By?DrgjRR~ILx>Rq^_rnrr)x_yI;%4TtRMi!z^!00(`3Icq(r0)%j8r^)fg_A zTo6%MG8rr&Fl2HnAhFb}LY3x2fChx9KGtQuhBxQFpNligOVdG9*Oy)@(KzjV$P<~oj3 zz_j3LS^Q$W@YVA8Yu))=rQINrsJ`@rPSqPwsSJssKjf+9eDGDaJ9qi}w% zzg)=xh@w8kN)*c6t7O}T8?G9??z!VH%=9lglapj3)>^hLLJKAX6RB8h3kby!!K@Oa zigOf#2GzV#AaEFzPK+p)efQ9XbG=}u8spmw+nh4Ufk|Dvab)V%$z`dk&{G5BY|udD z3}*~5IiW$~rm0Y*$To7jEtIKdKn}8+EAik||KRBonhhw6$_htDRRxQkoIn*EvX^vRWn4jnp=g{qOXKm91W zZ_EDE7f<}kkNnqP_`MH(?9cw}s^8!HM}PSTGrfzMYedzt_Slkke)oU=+OPimU;n+| z{Ezp2<-X5-?!lu=rzhLvn#FEs1sq!=jit^Yh$jM*2{95UmqLnRNFfohu~3MFAYL>k znLRV7Kq>K(_I@J6fM`w467@s|Lu+-QR${ESsfmF^LpsiCS$+8n)-=0!CUbBa4I}xF zBB&T*%UMtaRnjyM3Zk&oBx8vXP#ul09DVJTkH7XeQ`mLanp@wv{q|cXuid$R_pN(w z?DxW<>0?L!_T^{)_UTqJw(E!X?0Vy_>uUO#jar4Bs&9`msbvvgHUOIl@D-W-G>bf`Yz4l#K{o9ZH>QDdR&wc5@=l=dP zpSu6~Z!6{iy#2;^z4smO{mN&)c5dPP&a1DALHhkcr?*^ot0pyw7;028F*0@f_}MRf z>hmA^@gF?;%fI@}(@*{LfBrM?dgt5DoIU-AzyBvsJo0#+<=0<-eS38L+^Gw;phnTq z7(2b?YEbRHYWLf}`|TSyZGYt9Z~poJ`m_7K{dEJoX>{9oa}ugmCyumRQ(MXAJgHf#*QF3Yk! zH#Re5%RyN*oyjs&W<{$p=#&cbJ~}ducF|ev70o;hd{uRh9eHAT?l{pfYEG$sdkhgt zbXe5xjtWhtpmDezt4b7v)tIdR<0I|2%#MkBgWl2O2iI>}w{GqFPNx)ss`@B4Llli= zC8EqGFC3u3dxDCRaSUs++_7Vbgb-1CsHk z5CJPV_p+Ru#ok@Kf1Ea6Bcpvg_hR_UYmYtq_H`e6-`n2z;alE1v!naWxkG1On>{sH z7|U9kTb1(Y`IT61K6A2KvnemsWIgxNy{CKC*v|L2Mt7TmRJP02Kx}1v=8fa#p3(k7 zXWhHj{P3P@KK@(BAN|Ie7PgK~j+6vuh#|@$UVIfLxyllWC^1}SWe}oBjH1RwiJ}@q zj0#R*qezI-o^ai=dhPtBWnaQ58Htq_iDVQe^s50|k`R?*a_bQ&8xoCG^ap7>_}#qRW?T?s~%qKFrYM6iava1eEd4O~z!1SVr3 zsw9#dlan!|eo#%T@7TuHR%;~dGzLMf(d4lQO&K;CVn7OUA@~p=i3YF3bh-pyiAwLn z{BcKZwzNd#by;+fd6dLNyUMsA!41Rhus7-=3l*WLc=V0>g!H*DSc z11CfZh&3w+daAJB|C=e_VRfrOSLDJ!s7}F-r%A!InqF`dK zrNC;)KuJ(*_Y4dOQ6+h$rgn_dJTN)ff|-<*oVv9KNX*z$Hkm8 zOSVFp;ujbMMQ!_x%cE;TTHdL~O;byz1h6WF=%e(bt^lPXQu2)k1BoTQ>hYVPuVh|s zY9w*!T}0pM5SKV#L&P!h$dY?}W_hx3y9&D%V*251zdT;)G^o$XC5%(;gBrplt!02i zzA@EvL=4->gkPri4QV!0UvYKID0N*_bGe5=>;G%&sL(6ElYZ9fU|9j!Apwf&<4Z&N zMOvCM^uS!r$i~osSR#>uBqu8x_N4&KmEOfvPlnP%fEtL>8qHQxfz9ArDhl5Lkj?~1 ziA?=7(;$j0m{PBZ7*Oj86i`?~j56>r3}eXV>{=|UVI_X?zlSFt;Op+vTW+gv*^P;{ z^iO`t+__D=v$*#G{qmRP;44^OA={^-fZ;SXP%_|bI9X4ANf`(TRs9=5DeH)ciP-zT zK*$gglG-Ravei=nBFOOhi5ZPp-y{km!>Z*K6d)mGjVzulRX&>XqnXv&@Hv+D31uq zcaLE~hQLIwrc%H%T)H$eG7U7HapR5gz<$|x7OT0gEQv;iFfoWK9VAtTLTDIXXP8JM zN!;KjuU)hI*xbnyKBqPjy!yg42N*bIPre%mV{XJqMwU8=r@t1)o{%*kbR*wq%w6nm zVv$^;*o`@qbQbiGmS2~}`~1ll!v(~ul`AwxEwx;Vy^eMRhae&>k;;LZrfn2(ecwyT zXQJBX_EfR4krgv?MyZTEC_^9cs+BUB@&Q(=h}&=8y=&v-eFt7R(>d>KZcNe6TviYq zoH4A1C=-F8GRFB36W>5Zz)Cjbtj!$Dem{mm+ch_|M#t<}KlDz{S2>M@GJ^n4H*Rm; zuxp#s_Jx&mbA#zl=rS^5Nh3I6_)xJimZd_F*pKJ{UV~NBG;V~LBvxu8H~It-6Vt-0 zka}@Q3RxLQ{}MEU8E^z4>ooQuB^aR0XvW+y+O#njuTg|R2~s6+;-wIPD26giE-mMR zfe&59KqwMtLJ|=G4TvCEW12mJH5Hz`=viWe{S}dfB9eS-?#5S{^$R2=D^ z`u2f|v8jLmZ~pbn>_XZ1|NGBB{?J1YiI<(*cZ`fql!MC0`Jz!o4V}(>)$4EFwdL-6 z-m-h=o`Z*9`mJC8jjw*?%MsW$wR^;k$BKO?v`5=h8%AAWyVcV4rSs<&PIY33K$e|~ zs>(1Op03y(fy;FRh7JX(BjSXr(W>kPAT|V65R+lU%xu`PF~(+DUN9T$T=c@6WqH$B zlNSw*oaF^G4+dopEYB?wqiD3J7pG6X_MC)eB2yO{RJ)xG>yBg)CS*+gPv&6}L6Fq* zgdyB|WwycPsqyd|6jjD1HVk?zhmJhIv^e*!cYa{qhK*I}Lr~W=A%qwM8+KVnj1U8Z zMTiZuJhRRjXNe$DAmUORN*rR0F*36RC01u`@Ii+*l38JuAR)pUBE(4QkjHFLmaMdA z@2;{OJpJ_3i`_Zvj4?T19wI0wOD7TN>ZePAehdXDCf}K11No2P<&^j8O!3C6-_~l3 zJov!3w{F}PWAs%tqY+A-<(`)QEw6tg7v_Kc<^RZS%b^i87FpAoM$a!UmlqQ2M4|O~ zI;mKdhXPfT%r>E-8U>nyb5)6xTO^1mQ&b`XsNpP17?O%t@%@;}KSK^G7v<=@%Lvft=Vtx@F+h!{m}!Tc=F8~-}SCL-t^w~ZE`gZT{`;gp)<#pX9pM?#fWLCD{1~U zDKZ)v%gV*<__sTq1-bDfV^eQv&;-hUq$Ulz5-PYgMYhiM`-Aaov!D8}d&mFhYxjQq zya_v9D-)s^ggi7V3~N*osRqiHtmCQ*#t^J=gn^G$j8Kg#AOuk&5=A;RE8Rh-*Nq0& zk|MxF6%oWVYYj1m7+hwFm`nmwQZ*&2qKtI2TH>ijvz5E0LAg9ojtr%iYmD1A2iqT1 zP}9g7)`(PPrGp4hmWBEQ@gY=|4nmAfhO9=7hA2W*v}sI#Nvkn&+t{o%?XFp#)>jTx zpM7Hb)&8=#8rergHlzyCQ1cNvVM|H|oSbi>v6L5i+nAz^oq&$mo|k?{vbJs-YiukB zOFqo9NpXONiJ}BUuC^W32t*{7C5YGxMI`hJN+#jEB~xa&5k-Ki-YEz~Dk@ACL)mAV zouN+DL{w#Ce2|XqzIDr8k1alVy#HF}Oxm+VgaAjTXYuYyNi=OC*7mr>z`{#J);l1k`jU&&j zeC4I?A&uT-s=-TbGAzULS!<~1GSZehn_-Ntab!q|Nfa7Ypq#M-BT8VhqFzZEhLTrI zojgbc)260jK8{n5bRT+h<%Q!ozJxhT)S^~|cnws0X%Y<;vqQNoC7MhPwjzlx7zyQu zWtgb_UNr!sQU#Laj*|jMnC!4!3u)Uz?edsPjf6>SjcC>sj$vg1B>&sGjS&?XgQhiW zn#FFHtqIj)w>(nHMWAG2g-yS7XlF&MZRN1X#_Ca3RjnOxbl5#&7>=0MVGOa))m^Fn zvJS5q{y1C#iw>Xl|Bo~TJKWz^dB3TVOv4Tgv(ty|Wjb8LeSe6ZG7xGJ7ukfygNABY z8a{8>odZx6BCAl171XmEMc&et8H7GKhbE>X0kLl1R!0XCVHgsVu_Wp^%VZ1_Lq#Vq3@5f+UgFQRJXz|!1`vr1qGHK1*uagOQA@H=E_#g(wm~a}F{o66g=uq9Aw-T* zq!QDxS!iI;iF1Ef`NuK&uQT(0tA(m6BItrte=pVNWa$OHAXqj|Edf;|->dvWSXt0s zsTDbeiVtNaeI}lC6RoTz5(m;%D#n}REz_E4ubJ&%TI?^D(vPT=l38xLRwHqBaqd*N zf8E>PF|}^uj*oxi*|Yt*0yNUdvVvgY2$mdk7SwApAAuMH5iP5rw%wlEDrU4hJ+0tI zqrGX})@wFxbrqjDJ3rU$Uy7!?Fov$vi`1EoZp7_gyJ=k*Jv%pk^xWCS<+nuo(Nd%fDTyuTW2$XZMi2tQu$nY)F)C@U8o{-u28M}&Sl02=YRMEttepH>1ZoM5 zW;WH}F$7exiV25LBg>>oNYOZIEH|Ai5JTxZk$NF^kSOs~^?j@`uw+2Sa;^l45)nzI z^i}2nwI#-Unb`H}MBM_#(0UmCr~-udop-*U^w+i!2*_U3i1>A}L` z`IE2wmxD)fWX)}pTi?HN@2#8f_|a=uK8TkO9(?t&BWIqyI5#tITHGFK=bVw(KvfL= zR=YJZx+`pmOP!_9{m#Aj|Ji}NfANkVd(Th4|E3>lG~LO=$3FePzqn!D`er^-mP?_E zMkz6{Z03kKR)L$j_vO@@@v<|x_w!%xbyxa>@{tD)l!M-uU0cS-C;RI{37cO4>&0qhGPkj7u`!d)uxqY-4mni+ks@yo*s!&%k(gcH zXu2$qK~)U1$s62gv32iX$nSc?o!ho=d-}PjUp;!L*Il+YcP^7*+gI;~fJlTSx|^h9 zP>+0T&@%qxiiQA1kT~L|3U16yUzlpGn;$F?Vc_FnP_-LoVR3f%h8<%QqaXe3e_!ZL zk7b*@lnvKveh{Vf_)H1RoC>nlz9)uf{JWI+&B#F=(P zR~3ewLKKl<6&_fPSTvS0ubo%IQxuC~_Y8`qC74muZ~?~&-vh4#9)xNMywh*Z%> zV%02D(a>Mi#^%;f{O5gZHlO{}N2j41B{D433y8=O5JMGJ)Ui>KDkzKQkhC~8`M2*A{)qu!^ z5ZM_(EZD)WEQWBCWRq^;a6J08aO4$wX}NbweJ}{7il{;i)+Tt|M-9Y8kPru)HqWR8 z19i@h7WrsI8NK&XSrdc?%l@3|_}a7C zPmkz^^;_SvgsktM8z7bqERA~ zNet?YTyAnhCd3d_qIwW3h=h=c5+EWHQA2FVCL><~L5-vArSipZ>gnh8sTJxNxE3`6 zLPSullUA8hyP3`sLq!m2I8uxtB4gOqa5%EUO*q>wtB#M$grF3Fs2b{xDy=U>wUcYz zM2aFgZb2`PQ+cSCpy5KKDVmKGn#}aznAVTAcNI1(``sYjLGNr?o)dJKNYk$nNgGIw z$f35VPF?>ha5|jJ>nhw?uYjo&t@oq)Zvq*js3LX$m;iv3DVVl59S)AKY;IS3x-07? zfM8cQx?xW!!v(k&ccreAlI;63LNI&*r7m}9qo=j&@?|IC`a00zu}BjF29z|w7!`;g zFc#C!O;}a%CUGz7`9uQ8W3_6?1WKW)4oo#S%5ah?rP;GYh$y*?T5F&R-^0acAwf^S zqQ_n~KlI)>+LnABe*V3v-it?$;|urdWB2N%SGnJV@njra3uIwbi4i>j7@N34NnMjP zL9T|*dZ8ns~3LSJ`Jace-x@C>qG`i;K%Gpag+d|GnQ`i_` zI=X0JNmCb|ej7(bOF|$6GHep&Oa>JOGht49!CFlB&-Y|S;4KUQ)j%La@KUDrl#~pz z%s3UwC^O{BG9I5kGeBvGgL(@hNF}ACW~9(XKQnn5N(gM0uLSRqXUv&LJQCs;g1N_1 zgG^*t(i0lLDd8ZZAQ}?V3Vsj=eX2S!^u!Air%VVTY8g>RwQS6W_Bsi2zAPh2mN!ND zbm!D`|9m%gy(%#|c2Stg88RR?$QA~tzWLbUHRIRaaa+6Mn?8BqrHivw(a24cU_qpo zn5?19grG#q&Qx9lwRmEU8{b)M*&ezJeqpgNQvI7$k-1NEC9ek&TVIDeD(&D>a# zO+l%WZi$tsU2x!9%pgDzgs8@GBOtN{!xSl!R7_cjl_IiX(GaRKZ#l2-SN`;irBn%nP@>x!b-Q=(fBwnCfBYZ*{KLQS!N2*_ zzx>O;|HMcC;?KTt;FEXL|x{cSa-@Eo)@50Nc4?p>92Ofv6dE=(N z-@EhX*YCXRZP%PQbn%J%pLylc*Dju!$(hEcMkXfOR9fFJm&>JgtG#jkhILbGr#qMa z;Ws{)kG8M5bzi5~IezTK*yy^^=EPEG(Pf#VytC40M>aRsz!_52MmsA9p|jW@8ylaP z7=7%4Csw-MsWnsUH(%ZF_qzSAijdc;8k{~kGqqvzeINXuYp=O(Zg%z${^0lj;p3m2 zTbbKDv1OvUHdKCTZn;&oCda4ptWoOV+}ycy3#SL@gUGOjCUXs34s)sx`tYz54P%@V zpvp8HCMU#56C(%!h}lp*x-rgXHgjoVWHwn|WLZvZmBrfJSH96~x!m=817gl{8-wIU zUJV9Han1Uv<>mQfN1jyaf|7v(hztNxO+J0~c)li4)x0u-BE>o<72NPsP<{QNW>uuY z%5d*b?GS;C$!Di8Y`$e5V(ESVwNrI2d5 zT5Iofe&NQ7U7@?Gb5^Tcu@zeZNkjnx1GX_Rj1!*m!;$gW9>4Lk$2M4CV;c)>69+RS zfh0f@LOFD+yVW_z%K7H|3+L>;)_Q;J^Sf2z`Q6s1yHs`S-rxP5bM^|~#F`B3u?hr& zp*N_xTh=fOSG_32Zk}_tYz&EYfV&8nzEecpEd&WcRGkQBO=>*|iLeu_X(dSAugBZt z?d|dIeaqkaz7Je~-Hnev@$lKRr?Z+!U?~BLOe}ztChM|o0#Sh)e8z?LnZgQJPK~8Y zndGgnKliow-u~X3uD|iCk3Eo>s(y6$we^kN3yZJ0^Y+hw{nL-W{Po>~Ynqh%)!f3| zo=LN{K0X(?im`8&nlvG%u6ZG1s>;_lSGc;Ta+R2+J5mWiR&yo+*gb(-ByhEqkrm3q+116IEuj@CqjoB?SeQG9ipe}@92ZBBV20yia7aFHFFd!DLBijf6M5(7Zy#(~`2&4+a@CK7e&I&M#=`+sTs zfybl(jX-k0S*Y_uJ-{$Do1R-H3&N(RWQGy}>mcv^Od#TcP{pcWhe67zu?_VRlPM{< zCCOXq%n;Rl|4^Q6jq*7XF;{>|*wx&!x)OQWlm)4oYqN&B@q!e^CxYBfEs4ZRf@fkV zsBt$UF?V+nsab++1BWA1X)xVIV4f-9qOShQsW0@z>JZi2?r9<`K4#O@Lao>z1@4H$ z+5{rC=@Nf$d>!scx>>2a0pd$+7`Yzm2;na<(d!P;)jpKcieF3qffu|{8p5? zzDTXPFM*v*tTrJhBN+r4Yc^*Rc4xQ|1%(rrKGMWoiECyyZc<9#w#;mmRean=7xMOA zSv)wmw?8_zVOxQXJ3eqZ0H~PR8q6HRLS9Vaq3%U+kUhZ=I26M=A$FqHvbzHzVrXdL zSxPF0nRGipB7_yY^f~A%hscvZR%!0ZbrM#OR z6kUjFWuY)z^mczhvkTEp?FE%BW(L-HOBDLf*|kOCOc&+R?C+C-NZc~qzyYeD(u*k6 zzyS`j>?O3romk*T#BSDUmBWByAH-<4{juZqEdnS&odn;_iHTTT+07sU1lTN}le-%l0I`snt`&kpGcv=aELW^Zh8PJ*AV=$y zwf54P^RJq<3FGqcFtK^gZjmbU>|_8XS65~MOEB}+tdFp3eoxaj+urmrXnYEU2rVJg z=Gti6__QJ>3du9WH}WVOmiG>pUq1-f5l#>-0szL~73qIKdbdM9)1G;0a|Ca=ZJ<-t zWX>c#sdLUbXM($DbIVAhc05XHQ@6KmBl%=|YhBHzI!QEjvEX73H>!BhujZL))K1*p zf<1NSfnWKZ=G)$S^R2h+dCP6L{nBotHHn1a%mKONIV&wRm9HEw@rw-Z+1{ z*;uLjEGceHHn-QeZLE~27Y3C?Wb>kSN!Z$4J-u-%y~w>Y_2TkUe_`LDJ=e3vwaJ;3 zHyhIylVn?pv07${68i9-D+q~@h?7}suFS+vmVpqNtqidaD@70nBPS*>Bc~#toZ*K= zWa>GoAxI!8m9yaN-97B?8O+08Z@+MFI@(Bi3vuemFoUqE!Mc!gcPO$uB>)6fCx$So zCZjl0foh}LpPSq8=5K%aw|{Zz2k!m0YtH`mnb*Jm`o(>7ANdczzqz^+20e}rGM2Et zy*=Dj-}n7*aT0#KrLx*<2`;p}kECLh%nPWu|mX=2qs4jv=wb zlDK01R}?9ik5Hebja@!aeFlq_d9|worDG%FQXD<2n*@oKM02XSszWb$6|7zyED?M5 zw9#BzZ7($5h=e-y&2^lnAg|!9r$RS0Az)Ufla0di(ot zyYJo`-uV8j-pO0><vona{aA8bjuI@__wcrXMX7G55Mrhi|c1s zFI+eysUFtzgN446uWqjQ7KZx{9PTeIpTBhe=?9;6#=-rELmj87VU1?FUZ@2DE)qgH zD^p52CkbI|eI!D=ch4UXLFl8>k3c083RP19UhU7KGXy!}1zcOF(iU_AzV-z+Zv2ZA5h&f0IAw~vgHzA32-Rt$q#S%h{v5Kj6K{eiaNIB0VkP*wOeP;p1l30+b7$X+STbp-}vgyx7~jD>TB08t-El}IYcIe7((5P znk-b}4$D^6p{{FYX24W)o1D<=_n28#3%=@bse-m@&c!iD*xPB#puwQZ$#T|MMaypL zL^K!-IK^k4e*WTx^Vb|cbl0t~%}LLkJ40kn?(U^_z@1~oY^vJzBSl~8MLwgQH6xt6 zMNt`NortqfPL5u9@%%OKzUJL~7Wch;=FI%=;dnZpj@sAU{hDdo{^U14Hs9NwOsm)% z_IFL1$?E95v&Ybnp&!D6kJs9?CCmmRlG&cx+*{jWwh_;)pmq)iDWW;!=3wYz2WfDql<^H-o0;6y*TVe1HxW3VZr9z4*TBQxi=3CfDOPMZL8bk%?qm= zr!Rct&;Im@XJ7g8fADXvJ-Gj2YmFV`nw=O~JM=9EW}#-BrYW~>*)*$ppzLaHmW^42 zi=U8Z*Vgli^D80pBsC`LNUb&5TM7;m%f^wQrkWiA%FMzdIk~z8A$SlB=Hf!_5mTG1 z>fj|EDr9XgPDUe)8=fR<#nq9;joeyovu7^c9T+(U=ZZpB&uFUjhsMxMOt z&p*ET$a89g;oNdq&q=dYRYY479nh*88FL^iW&%V2G70r78M+f3YLiJ`Z*2?G5NXO8 zl8CjPp69SMM_2X2{;7?VuCWA=s~X^D%FIN_Nr@|ob=KVG25ewB%-m<}#_S+9Z_U^x zNY9+r+G2-96hXnv%@m%PL8NA-{kP)6K!S;@P}mjcw$plRD$EW8nE?}>w7CRBP|XYn zviF3+P_>NYP<6^qV|B}EY)zAMzeHd~ZYDNz+LGRh7q+hc(yRVmyY0xnYu|n3*vn5x z%tu3CC^<~6$IKF~v25I9O34feBu&m02ZaJzz?}8QdM>#hOC#sn%qLBg;Sg`~h+Jx5 zO6~FW3wO`mvWphZ;dE)o%{{QFsl$bKX12~XmOw(HmeH-d+BP@k@DCgm4if?z06LL2WySnB1NnBh)DOj2qQfdvBX zfvSpnAq>I&$#k6ULeh1DIoP3a+kqlyqF3*hh9HA>lh}*_49xJ&E-9?rB9)CNj2#QT z>R_mr(bnYo!lkc{M^9(lB<_Y)ce4&LEhA*XYWa#uu%KD3ED~o?N*V)V68MCis4EfB-iLY2qcJn%j!VGRMzr6$d((JVoQP_Fi-DjdR z&6}-tY32asv?JQ>K6SPjDBs{pwlWKc0pOOW06UBUNbT;>=}as>tItH;PFe&Mx;&~G zt-wKK8O(6sSuhv4$z9_%Y$OM5Wcz~*_JIzbms;M4D-cif8`uckY0_I>{= zo_&>r(RABBf4@EaCEq+l+)!0gwa7y#0D8xp1{Vh33^TDAubDw*=S_gP7vK&v%Q&0q zIGCtJCeRK5&O`=qml;Jx5mBBF03Co!Zk~*$EwEzewnp0n-*Zjd??NIO1Rl^}gGXOp zdE%U|)?5?3MH^9Fzw7W_*I)PFA8ns%UmRd=p8AbXH?a;RwF7}Md(um6c8cGq$=*> zW1E=f`HHW(V|e&Gt9Xe0708;|^MXr7pCHB;*m5yv1k z)JOwS522t>jdj6Ts=bsLf&8n7^ zX*_k((4%2L3?&E?b4M=)vNK#*o6xLnuWjk-T$(KO4jj1Z=wMQxTX|(PS#NEcDLXTv z&r}O4hZ&M16KA6ge#?#f5H=Gh9nOostG8a01C)F?*kvbz;A~J`m=fFXcJ)@`r;nrlG zU);UEb>YW<>bHLVXMXVY-+ko8UwZbs_Z;}U|LiaQ;)j3Z*!h+I;r^hm5F}07s?NI) z`E}RdvUYZS;@I(x-(I`-JKy+g|M?gH{{Qw5Kk@L#f!ve9u)k}Xw|?al|Ng62ees9x z`>R#_z^5Mm)JnUuFc>7`az+b_t93&uikoeI{>T65xzoqb z4ww7$gXQI=J%hRarAzDE?PR#PuxI~X7aott#c8k>l+v5cm2u7KlV%i=@*_p_SC+? zRj=LuI#0B*x)H0mG+gKp`Xs(Ox_D~+X_Lc}1;&JwC#zluGUpyuufA!_!zU#sP2TSFzLuB050n(5ra zV0&}(#pfT^yh#)RB{00~HM_OAyAjN0SU$l^X1IHvh0)LGVKe9t08;>0P61RAB5`n# zS;?#d%$%~iOEo-q{M8$8xb?`jH*IXKZcjI#e)7@7*IYMP7`BtKGpSl{5JWg9t$THh zf#9*05CRc$&Nj`=sCrcut5{Wz(lfhd>o9~ENGP?bowiJ<>re<9RUJ7>ZZrB7G1M$0 zFZAYby#9t0Cr*C!V;`L#_M{3Tg^ge69A1i`sgo14sAdOdn}zp~nlbUK;ba_xLKiy|jKRVN_Q`hfk-| z;h9mV~G1VL$Zw%u68`cmAziw{;3YMMW4wfZ=Qeo)Y&Iq{ziIm4L97j zbm^ooB1SEWT_SflLERWZLD{@pF)j0@x6s8C=N8q~R;R5yd&V|iM`zL?8 zdERu?n`iLqR!W@IQkz;PCw6sXW}@gMPJxh3m5qjBp(l$#Xl%R58|ov)wsY%HKp}9z zNV%F$?LyRres52rt*v(CJ~c9TxSNCk2f>IWhCT&O)2X@^3Ve4u5!4J^cz8K!6QmNV z7<~m9G7~dLb2o3y8oHd+Wezn}A~+=@7%0T*mR-x6+x+C_X`^0epomiNixieyQwA|n z>nci>8M9O8QsG-UZCgvwC~;8LkzLhdBw}uqS4Xn`*;kg{c+?Lp_TF*b)qi&E#TT1e z=K2vi!$6*$Kv|>#w~mTgjorN$q7z)TqNv&)2-RQx)(=>oe)zMWIMZf;vTG_JA-O>T zWTfNM<2Uw>UK0<#tgno1vnpZ@hZIRpxA7skX3Hdn&krGSCnKYd`{3rTo&gey1j=s9 z)!}=t`G6k}msT#ikEnR&kak00ciM8M1e5@E@5WIS4lqLbQpnwdOdygXyE350!a`Vb z3I-ThEhk%<=2c+a`8gM>1)^EzPnnoHL!9n>`6kP`GFKH(-ws}wwH5|v!XVW9t8jBw z?=o6#npZbQk15uvGr^|IARKio+Zn>?J6xnL+XaLjkD_jCXjJYVVv#~V_Hq|d$4#0! zgSmsa7&{lJv?K}p&e?Z)sjpofgcAu7nV~2^XKj)L2v?r={!OY_1{e?&7QU%>J-|*2 zVCVu`yEC_F=x2^u){V5Y`FQ8slm?9`l0*lPCj_`9%To}+GEh)NU?)0ahIqgM5m-Uw zy0dfr(^Ns68+tQJYS6EBS=j0cS=@>M|oUCWwHDsz3ubZgi?; zR}K=gz}#T{!RH=X80=T?d%DUJkdd+`g~a)|xRk1Z;jr!R$J}7Fe&XWe&rD7|)6e4y zbyfk_RqV%DiE&`WN+`qJU4hogI7o~VI3{^?LVDk{06tGX>aLid#^3q?Is9Q}1X9~9Um8?TQL|Dz-l|beh#rrj@)hMaK)^?%#Lh_n@_VRiLobrHxOcpJP8yzNTb`U<8v#1 zF`*%3Ap$IUUTwGQJls`ZwGbD#rkibU3JE46I>eB>c^H|2k}+G+Ao8Mv&e55VY=7h< zU;2%EzI6L{-2DEx-~P6{_TBlmBX2u){`j-6yzu3J@)d<#|Nf&l{m{|(eftOQed{~E z{AXWz`u=Cv&t4*Hv|V7L5HM}0O`f`uFjrNrjR7_s^h9Gj$<^*KH$Rw;CmZV7*me;@YzIW`}z4xnM{=$Fy5C8H0N4~r$%eU>mv!-f$ zV_b2Z@6Y$<1{7#xw0?Ty#70M{>HzSLRdtypy7OiiAtKMfQZc7leJ6JiOM%desFg(+ z1PbLdm;+Hk84)FzB1jeLsy`Tdrqmc1{a$6++JxbJr75|i>Q~dPCbt@Eio~1imyREM zM)M|fbT2^&OkIu}@3aeLw>={nWkBI}S|(4Jo_+R(d+xend1=q&{Hdp&dGgI~d(WOddzy8WxCvx?j5%Kcl z1*W*wtlj_2m%sZ>KY07mo4@#t2bUHX?!NIgkG%Nc3+JC)sP<-S`qiRoUfa6h)CR82 zRV3uB&2+LjzqHifyE;BC(wP;*x#Mkv{R-v`_AF8|TyN3eFFCajsgdq+;@US=y&PsGHatUVLQq%Kcl^ zJ2n?kRj3)gAqIVD#8k1#*dk1Zm@>9{AV+Q7@8cb}9{At|-}CYr=PDGChy~i3u{k4I zZYC+2HlACUI+0MeY;I}_auPGsoWTOPwc1ipB13dywcI94%o&u;S~n17wbH;6K*S+y z>Yh5GltPr@d{|nd!Bum7+n##W^xW3k#J8YIK2>f&8Lo~5&kikNBqE)hl~~NFypIg2 zLhV^nhS0EIE$s>Y%K6!i(TmOc-28AZdNWDWHcLNeZzq#c=1C4ygH|CpkWF(czLc?t z-g4XQTB;*BGQ}^Sc8x{8xc57+tn(pSM`BP<`~sfw5W+5`ONp1 zZz@J@Jo)7L70uOTQ^I@|Of{?5EN*rSy{oyMT-5rWg0eeREWAS;>9&ne7GkDGw8zhrI${xN!s71#Vy}1V4!)LZKz2|It3p}_*iNG z%TQ~A019QLRY(~HbW{%m+B=l}Q5SlVr@X%1ZnVBR%^QX>kz%GZEXPXcMmB>GubfQ_ z6j8W2vq~|e+0x~exH|#E5O-I-YpUMSNDJf9@uq#!(naT%A;qo<9V|LicJ3UT-Q@Jm zFeZSG{A}(x zSNv{41FT~WcPA;}>N7rXH>8!Jqr**0_lKFfW)|>3LbLX5MuelwH5Y)XrLh-bDiJt< z7}j>L{+oEkB|SpH0c6ky01DPWi|H%R5KlaDoYo|U$Z@Depw8TH~RxI3v2Oh-f=lt|@e&!`?o+FGY*5Jym@DU;r z97=`nLy;r`=#0!bz#ZZ+vf_B&1w(foF1qcebYJ-|93h20_0WXj^u>wL)ZZB@X*vDLt z2JV!R1NuV9lmiEYI+?k7n-0#^ci%C0>xY)*eF3Y!{Y&l2$91xTs;2q#U`4t>r_ZK* zYIFG|Iq+Te^7juGf3o+wclECR`0%+eZ#;K$w87gHl}X_yRLTMZF~Ksj0m9KJt95Uz z5E#*%z$DyrrIBv6wv{Xsgo(|QAk^p?xXBYHi4Imk0S^nkrNPw;!=sDiidMGAXHH(& z_{te!)iWrsM6;e1JRO|(b0?JwpG9xaOC2QeC2#8@0 z2}JA)=DHW=`#v-%`-rI)t}MHoOX&CN10=)A^kSPXk(i5^J4)=f353k87{XhL&ndx? zR_+1=!8s@M5X#Dh9h!|qYPX!+=l34Ibm7$>`H5fszkm71?)uwr`qKaYnd?4q;LUDKl|=GzUR$1zWw1>9z45twpYcXZ4e;G*x9G7yANr;hSw$i(zsv?2c z#%tSoEz`Ki^*n|d1y}d1?F8eoZRoVw)jPB_w|m-*H>c}{Vo|67DU5*{vDmd6h@8|F zM70g0EIZ}L@x&v~-@o|$-gnR4_w9GQ?;Y3P`|a1>H#s$a^3@j~|MYW@e)^$(M-JZp z*KT{~y>GwoUGIGH^fNDh<@uLCe`N>Zo*;oPv;>i6$ zePOh=y*;iD#r`1HbDUC|Y&X01E{-=xr(QXYz^{4z9dCQrTaH|P?N`6_`G5G4pZx4s z|E$K~rsdm*p+6l@Tc6I={odSwnKs*vbF1gp#;X|(h}e1O-NXO*gF1D0+3OZ*T({vZ z*NF)XMtLBMv1BoPhdVKa5LKO-OP?J$_J>0W6@wd1AQ2XjsOfNi$i&&X?hDL`O>-g- zDeJLUo@tv^>g;3zNU61$-3qgX^o}=_f$|keza11?{_CiS=MeWuJ+P*kjx$gJ6~O3A z-Cwj`M3dbWtOx;hbeoXk(wSGzT{XXF&sCRJFRpD~JbmiK;e&_!gTA>^_bpfgyF-FV z5N#DqRgC?9Z#dT{C(FfqnX_g$mmnZ=5HVR+&nhBSkI6lVEG!J+NGTH#>qyy5i+?jr zv9`7`9Mtc5?|W{$?T*Kudicqwzp=J{Q7zRxj8YZbHX;sztO%`2=t`NFP*gTWHA+DH z=P$cE;KFizE^`tzxCUGcy+q`!ir{)M3nuaxufj=;mK{%G)mg4ag2ya zIXjFZF^g$&+|=yGPVSjPHqQmca?eB_gtV{*#o^xO#6dKhQHWAIldBUuft@&ndcIy7 zU?2!f`{YF1-hb-sv8@X!rWif94LHNqG=nk+g)7`q44VlOieDNbkP@{9$_yX$SSsu9 z4vW|Ao*PZuXC_1K zIyEHOpeO?~F_8(0n-~&g(%7ZY)aHR`NVMgiK;AV)$_F{xP*1ri9Z zW{KE^2*~Bk==GM&r=!V=Y3tN5sl(m16F`|4*0H-XIm4W(b-A><`P$*t?_9Y0k2YSO zN{_iXa(8E+m)K5s>v$(dEDY2VtkAK@*uh|dWc9#Apqv$fqzbL!>>95B(uv_+`>_z_ z?poUY`PDO*Qedvx;Z_GqL@8N>L;?!{QO7i8DRJmzJ*r08|L9|%e&EatCnrr#a|SRIlVfLH1%QdvOVD@f#*Cs|g=M#S+H>o!`xfM? zJLn(mRiiTvrcPJ{L8zP}ToDMSZXgnd zgW>AA1hRH3{m$h~0e6$qSXnVfFQWj8qbb47OjrUJHoKW?q&k4qv%v#7O1w@I8R6OunM4pFZ~|b66N)d5)Jx-hTbuqZ*qZ_^vmiq*Hllj?LhV{@W{R7NjsDc86GJ*3wtzYb&3!tQKE{<9!bpI z$Q7A|Q_fAB_Q~Kihvx2i@1DIM?BNLVSM#Oc9-nxiX{{R8vEgiE7xR>PGth|b#Kp<6 zU*5Xzv85w_X|DgRvhUu(zRwM=`t7a$SM=%a)m0uDxq2c7JELWuh2}RNcuX zL_%&e2ogC0xox+SjSUD=qtg+XdrJs)jIkWr8E8>)H9xnM7nkdWDz)1_Ue6a_&6ke# zd9zp7?v%?Z=j<+~V#G1_1${Shl2R=S^_w{mMKvfaTT--5)^@8MV}nCXs$37}`+IhW z-I8ohmV4vD#VMI#qR2Y+U{2~lp%S=r;Rm`JQ2>iuCW2e`(xRgXC<{2{q+aNEW>k59 zPuP#zUD zH=a6i?8Lsg<=4IQ?gKYpm0HbHonNfQ__+!F>90O;^tMxf?Qi_p>uXn7nFqWTCf9M8;`*+>YES638<^6-Reh*J3H5Gt51C3+FjmMqEs2{$TqL z|KNc?y!(NBzT^7$z3Hmg-+thx+lDuvNoT%s;jvHs<4=7KU%K^2uYc_i-g)z1{Lrg+ zoc#LN9(duIlWQkV4(q}E+|pofkXr>);4mFeL*MIIO|uX{B0O$kD~?c2#@YaoaXcUt+J*Zd6x<%_w zy`;{5AG)Jl-MP=aI_kmU8xQR|czAx-t~8pQIDYEf$yM|!#5uGr zkP&;R*vFSFog-R#`GqHLzW(O<0ijXMNiYTUk~;!9X@qw+g)cmqtJ=93TF=l=8hg%lwie2Wu}>8W^;#BY-BdooGY21 z=B*;5;1bAO$cG@|8Zf;~=qOP}3V;!u1W@($ZC&4126{tUs;6_&`wR8Le6`rK9)~bL zw=ift1o51!9$i>H-Ac1+W65b_veK(?vE9DsHTV7HpZ}gOfAaLt|I|x2-Eceg2I>IA zh%zB%&5op&3E4eUm;Y#1pb2soa?3fhgisf(HIrnuM5LywP_Q$RYRO3u)duV-w*(e; zgSn}2B@$gZXP&DEi^Jh)vb{3Cct%xea&CKNJ7$VvFczqpp;gLE>XhMH6pRE2iwJ9S z^^!ixIa|!w-(OgW^OG$<&>R+v2M1s4QUh;@}!o*h>=}As~WPQ@By_+m)t1I?mFx>OVj28NAI-p5E0Ir z+|6BySshw59Ogs>VK0doq~1{^#a-1VDQy>ltyywX;_TjbwhLCw6b&e1NT@C zrp+0PxUKQoOO6yI$%lO)pI+&!)*aV2dbs)5L65zEf0Y4NA8S?JDNwLA@J{ zX(piM&OqO(0|`aFvl7^OZ!yDE%V0Fgi9i*1#n(IA4zryhu1j8!%PW4LUANf}yVGR> z2s?Hlmy0}R_P#T$@6Ww{N2K}daqU}h=|w+vKj}I=Q^~h2ilA9_{d3qX?R?Q4w6=4Y zU@ylsW@Bo(TguQ60|gHA4tN@s?*$aXun;q-2<6Pl+>A(O;8NixTTvsU{7(Sp&LK$% znn8e?X9IzRAamX$=!N|G{|BE*7%t-*;^qJC#H%~!5JQf zqJjgW!?PcLoAyKz z0jAVqi)<2|dcD()zWng&O{b@KJ~)5iM+fvhxarOFhkxV7L%(zG%P*aL1uIFKKp3E( z96+eKg0rEsdIU@hIRFU6!a*oxObv~3CKr&E_qn(j^{c85HD_^mOAez-f@eQ-`V?(9 z+uIkmHrIH2ZK;pIb8yODcGg7Y@|eXKh?yaQtJIKnJ9I~Y!4&4fQ_fzBy|<3G8Lul` zorrqb#;r^i!*Z{lU&P^14d=0EHJ#bYtF3J&8W*k^$ecQ?-n(TPcQ7-}9z^5WO3R4F zO&I`@d1mkdEDd}CDYrHqqahB`>lw+oxtQ}MaB^mMBW96k8IXeUa>tkTjMu@F^m$nfQ>Zaj1G#lP@lzw#UZ;jetl&wbZt|LGrn?w@_;&L6(} z+uruR<98mnz1Vy8RZJA?7^>h(7hl>~Jvj<-;h`@)``kk>e&>(B@8duBJOA6i`)B|4 z)4wsoSfmORVilh~^T1N?^xj=ZP3L0hw|O#}ZqzX{b2jZJ$QeJgoLx-C?@_v=yc;%W z$Jpg*c6Q>;+}>%2jN+FMPP+1to%Pk14_69KUP)fY1VNXPxCZ{P@_*k z3FHiH?npW%mWp~XGxRdr^WzsL`M^?d|Dc|WQZ?-)Ygch4Pf z`hk0X@cTcs(rn%T;Mbn}+6xyiobweL&du*yT4tlcLa&ZB1*!*uf;4RkAq?mGa23JY z%4##29z1yHt?z!zJ#V=CrI%j%seka3zxnIG(V#s#e`I&u2je`+(ZXPEp{ix8SwFLS zW_`Lb_9=HVuNe(^wgi~XEwdulow`EQCDnIjr)+gQ!v?0}zr=xvMTn_edJ@la&xryD zb7El@u6u*3>cctZmRTeQk)YJXx`z5>GzR552Foc%+1y;!oJQkjW9@7y>eSsowDT&_ z>1TFEpiE?)F6N4l*wo|F=l}R&OEoRd1BzhScm-R}Ag_REw0&uNd;jA6!pi!kW3RrFbUHsjx3#|6Wf+hL zVK_`}FzhWYFNP3uo0_(D_Yk=5Rm=p4gu>`Bsf373idmowiNdQY5~!K94#X;C%OM0! zO2Ykq?dsz^0j%Gz+;HO66VE*V%$|MAciw&vd;QXhXH^vxgat$}kT4NcjYNn-*Ikfx zggQ5x)y^x{^=0r^W?r9MdgRzc-*?|%7`2Z)e)1vVg%GNRxuIv>*j{ZsE!2CKs^QrS zXQ&bh(G5%_f>ArJs@==;*Ie3sMY_knSUdBq2?3Sv3|*tP^QbdPd3nqg94rE>)LN0g z@SqH-RTwnw2&8}!g|bhdc}ZkI&5}{60HufPmMre-n2!A1NFyO`P8NA0{V*pKV^dj1 zzaF;DNV(Zc>&kRiDx(d?Bg%)+jm3g4I4GhPi_I_jr6 zT*+;k#z{O&W7H}VD7z>33`0s~IbofOo`nRaO_SFoE)RxRQ|h8 z%Ic7#niew_*p4&I3iXJUdEF}wrh;Q8f4CcW*AixT$Z)xKlm}Rx8{b%IpEVe0%1|OwHz#me@RP&HU_?Y-mI!6hP{^=my=F3jfn*@4)Oo-4Rxdly)ZMod%{ROhMSv*;a-bFom`+|v|4z~xha+iGa`<`-5CyHn*A_214N~!7KKlV zbcM`i+}d_ zu)Xf4n5=-tT!TVz7T;m_%rF)+u#?P8`DdWNmxXQ#(V%dSwj>}=$4SYIesQZ&c_mD~|^XUN1GgXNMF#kq^C;n&kjvC9@{*!#>&qmKZx4vqKbv@vai@k^B za+{~AO^h1mtge9@iC@3C_5AN_zxCzi8^3#D;XA_MAMm?hckqV)vi#+*ocPlAv2)l4 zJA(pA;2J8-VdRv&5pqzWnS~fANKBsF)GD&DySb?nlwbrA8blrh4_R$8Njf&nOVYgE ztX({Rx;e9=dCk#^I0+HNNtii+)m+s?tcxL0An?w)KjKP!;R$apNvtOwEV_iR7%=^4>i+U06B(U4QM@e(@jw!1w;# zcRc(rzxLUG^_d&)yXE$8yF0#qVG^3@b}JPIyZU)OAAkDN_DWhhxEKOG_SjQD{SzPg zfggY0&;B3(?#`R<{@LIB_s^_6>p}X|@5laDdv5*ArKSFXx#8Xc7J|e{vz~JkgQ!`_ z`}Uc*f(v=tl{>3Y+nGAAz)`vTT=Xxg!Rb`WzF zLa)_Hb`3%Rxgl~O(`@c=MJ^ypkLQ>u(d19^ANblBp0}9yXCf6 zML2TO7(*fP^yh~2i}M6*ZEk7Ss;&lu9y3W`fQpffsfq|Q=WOl>5{aOut`L!|>W&yC zIa!;Tsj$dm6bWM4+}+HoSl#`)yQ^XU4?gz$X|jFj(7}a;rPZ}H)g&==J(W3u-4fu; zWQwu?D-1faLp{?=7Mz@L*2_!_pysZ67LpeJTW0h`5{9%Ay(& zsWnek4bFybp_*ggnr(s!vpdW!aJ0@2fQgJ*h)gxPTd|{>u{4;7;ejc_J)v>(#>RlN za<(?6fumJSdra`DAy4wcuETE#wClpj&%F4|3zNi)3-*tG_I9* z$Q<2;h31C~G0TO`i(}vBfd*A$O`Zs3=IRoFDl(L`)oc^BF`PsKtmpzLYhVgQOe(?p zw=5lb&viG$_`w&>)(E?ohA(VwJ+roz25gkG8Yw6BUN4&JbkZ)zg+W}Xd2y1qT#^Jb z&DpX*g-AG3fN`6(aY_WsW@YK6swL!ziG9}bIXO|=+PLz%*T1o^y16wWOeB)4suNKG zEt0~Sg*cigM+U=HA;K>1TCgj1myUJgs*|#Ub}RN{VxD}qCLw0Ho0>V#?>(}2-wlsH z^vCNtKRDUCd$K+Vi+xmU#v)wC21ao$aprQaa#kDks+$iUdg0=kiEwjNQ8GHH#SE5?1d z9KHF5n}6qvUw`nzTCY${6NtGRrpxBuN(79Mn+9v&ePr=3z3J$5O8@4M9(xJiC&|7u6Ls@y zS^duzj#nU^->jzEfiT0L>zw|4Cw1j-UM>TfC&%s8GvFR5&vGC^9^D*>JlKu24c!JD z&a;v{8y+7#VpiD_~VE0m0NJ_8*#^7 zbjxkny&Jc`x7u?kL~fsdJRkqMtv^dTp}HV>;sO|v6Rf-pc5ozjCsm!X)r)#HlvR7= z!LVL3P19yVA%rM!&pCksb}4HrSXuTG2?Gha(PltBz(VBM7ceABgam{Nv2g-i5E_id zMLD~h!!ugI15@&egK8RV%KGOneDT4L50>i1w_bbK(cA9u{ejo{@Sdw~zjVV|+-`il z*{om6YpsuKCL&6f7~G?w2{oG3b2h1EAYRqz_b7THQy>H);pk9hYtCzVYEbN8dj`d<$Lk@A^OV2RC2;8_R$6%&Xt9Q&otSMDeQPeuLJ@r=9s*N!OH` zBQd9(vS%j5Tp<2?3iO5AX0L`+T9+`-H}qUasp zmKckcKsUich=m};WaeWZjcI(xp#XwF zeZTqFS2wM{m|k5uk$l{=YZ=qdI~)#jVtAf9dL)sh;vI&2G13PWvP|(EE*gEcmZ{>Z zjv=UNle2pn2^?f*EhrMPn>X!b*Y2xVL-m9I{J;OqiTD5YfAIGC!Q7XB`O~YM|`CZjv= zx@~@8__06yz2{zjs;-9&a`qBfQ{v^jxPM_ z7eC_6(FZX~qoYe}XGYC>pb#P3?doK*>*&Fw&%W}E8KP7m_Y5IPO#|g4`)+;V%!6Hr zAwm%3&ae|O7*luKplj(!WwZ}gb8(13?lAG-H%{^Tv!9Qw%L z)h|Bvr6(Ub`Of!TpL6<0Kl8>>{?b=I_x#?yw;@)!F*Ef51-L5QS*OTuuCAu3Gv(}p z4|LMBZJH)c2<|W|R+H?2n=2bJBbmaCnY<%YJ5Z8A$kgjl4P$?tHX9q~kV9~g<=nU% zb5S&AgJ)-VhzOhv#sxOwDlm7VaAs%~y}ohj$eRz}2+$*EE}Yz++_ALllKbP6)s2`C zm^c~d?W`^X4W^a|@bN?$waiu3Kz&`2l#@$xGnN>HvbXB3M8Khj5bM&uF(>ubi>$ib zsRWJ$)s!xd#%GuI+%>m&!z7)~sev0Y05;21Jm9>z^@&KYuzX#_K~8}LJNQ1L*n2*6dwdTb* zOq~^+KniuZkxPl{WiH?+!IJ8Pyb9hYPL^A;80(WK*N;AbuDb0uzwY3*-+AohV_#^; zb*SbfL&z(Tv8#X#J)xsl@7sN7c`CZ$4U)H{M&?>n-GxzFNYn)hBZG^GJCv;N)djoo zjkU)Yw7-PqHLRHX4DTa%>(Egr?QV;5+!nDmt+V|hE_;3Hx>-NpZ)X;M;?)&hw7p7<` zst97_JM7~ETssQVTkc@aQ1;noofVcd++hk-U_m>@WF6X|VCWpt zUxFL9pYq3^!82F+u4@p8_uU-d^w!>MZjg7syLsuE{Ix&UXYTjWMNBt|Clnc6xtD00 zvN5w_3su69n5ZOf0DzNl)vuPB`mL>l;8rf07LqSf0GFI=XGYEz%2jdCmQ7s1YShu8 zg&0x>5hk(XV+JBJ^W@NCOJ&}A=cg%+Pe?annAezInVedEZf(yr-gNyvHdTah*TOCF zPz6rUo_^(_3s0W)N$FI|tz#-i)+OSC$wg3;SMy;JOw&BgZpC%8$th+&gk5i3y!He4 z+<41-7kz*Wzd3pGE9dV&f8qi)RhaKv5Kd;=PIak@#-=`Tb_gtaCf`oRFclkFn~02k zyY{cO=bria>Yeu=xc9xguKVu3{3zah@4f^7Zej6H2ak@=Y$GwpfZCjTGza)d$1$?1 zz(_cPOtY56aC45du+ZOM(L&bBRm3YZB=?*>Pqm2i)ws>DfT|aB>Z>+oqikwSZE%_G zp_p9U7!32QuEZi93Pq}P04gvLQ6QH{5kieliAjXrk;+_lT~pB;C-T|Fu6padPvg{>is|2j)NZ%b)oCKl%8()3+~w_f^|u z%pvC%N{uyR8{K!qdyLx8yzuFi+qt@DhMjN8fs(p| zI1njJT~!$|z!jO`i~wMy7f-HDk1W4t*TPkS;>PwRGYAEV0U6mEW+6~EC59MVDLw9> zNXRxj9|%04-I?i6Mo?^=Av8xOty`>*|$?`hxpwXKK0_WMsf`1=nY zx$e5x|JB!i@crL0e*5HsuYBdvFFtwh*eioOuOFv$=G2Lr=}m8Z?Q8CS?c8wj^fQf5>Tn0Tl8E8Su7CMlXkW;SP*SoL~QdRcAvzJ009o0F+X z$T@KdAZ<0oNDR#>rxXLNudS@EUUF+0V(5m`%j=8o#b0@w7(8RP*YMfrl~%wJKs{n% zS0ffePM5ythkxSR?|bd2Y1L^s>}N#`A;!9Gr{+Gtv>18ZY&>gW12hFQz@`5pqG>al zOs9jv5RPN7yy9kcRjuVsVx*LNgJG}N8*h)M&2(-sm>Uix1~p@H4qU~m; znY+g-m_xIbncs35NvMSOFdXJtl}m?0UiE^FJ!|d{`)!k-dg2)-zvr&kH*IrqYA5Mzp`&>|70@Kj1a2a$vr;0dmb)(PS5_a#lrn>4KZ<<@UY6KeJaQOQ7?7#1k zzxBsI_YZ#NpZ)gTulqambHcU#lYe#Z-}#@v^4O!V?7!-U1Tr%Y;^tQ3DQEd!%mAb) z;E5UPrmCK^C3Pins1w}WNtoT;Oi^6>-OQL>70fZRxKW#P9my5K0g5&^93aHd?C#`l zW?2p7F^DIfG%XPasv`G^vgWC)#aP~D3KF3~+iEH9xoP3BC;!Ijb1$uK?;7@(7kbaE zt-Uzj)B&kCWR1JJCo&y3Byfh0$K!f1gdlLtMy)2|ESxoI(B0+*1WnknyczvF)XyrSu#Ulw`|A^2h`nET|}5-8HP9nD>hdJj3I@) zn<{0NT8K?`wyZHgc-Ha~v6-<1z=GIh?bOTbD^=BJ!3g$^X1lM*6q(%2I8)Nq&?M$zYu>9w8#B`=0zoC!Q!kzQ>Qk>gd*OV`qLju>az+%+Y9h?c zmbJt{GK<=dI}wr@;1g`G*xFrlw^B-9YQ8$flsT}|PBLaeS$!5t2e?oGl^Fokxd-nM zaee2MfEUFRQTM(V#sn7&sBVyQQ_nT^gllu^(?XBunQ1$3jnkF^CpMmUY%)cmz9Y?e zTixsF3P0`q4wZ-ZioU^SpswR`J}MQy0suxJ)K$1X^xoV`Xs0jv^hLC1fVO~hvu$11 z#1x>m+l|cLpHhPgXQNPXubfD`A(qHt*}>LTSaz6u*g11&o5Bt-ovB_`^_qqFH{N~Y zOD8w}-k&^q$DyV7zxL?Gi9WMBS{d6p%|)OGD!M%1;huGCN0KXi2X``jy8T@E|HV`P z+{YDbY|JLuGG5vY%k8SYyHUN*X)%vBJuXvkpEoN&JEIqOwFH2BCaKv;bqr)eX=rzr z<^;kFm7Trta&2|my|W#7UOE$jgNR+&XXe0#piu)4x4x0`lchsr@YYY0Ld2qCbTducR_wJ8CS z0=q=6h=_{Q5C{we2uMgOihb%eG-b~LoM!K}cJ?0SI4EvUL}Ub2n+$@G`P4SCjl5yU z)>j{Cj_uxDieeYraRv{0ZtSjT0IJbfXlsqbBUOwb;A}pS#rbNN-mDA0!uUz`#Gp|0CPicq&^F$6$LM$F?0!tG0IaUZEz<`##6>pIY zc}%HsYmva_%onQZr!Kzy_Snv09L^jhINGq&BeRGEK}G11CuU}j z?u~l_Tyv68mxqyAn2NtH)pc*!AE2o?2tqfqN|X>QLQ4oND((THgZ$iP8$<=%DVw*> z8EhjxGg;fZ)H^%uUu7QW>wQb%>UqXiyLNVTVY6M+F!s~D|$%|HLZclCep6TkJ* z&;GqXe(UDD4}Ra#NtosfmN&?GJa?csLG|=AuU=eP=RRF`)6vuCF8tk}`?>GD=^a1$ zlRx~HtKax9|LCVb_S`2_nwkboaQ4mS)cEYif!(()4EL(0N!oVI@}{YKdjN1(HheZs z%-DxSa3KWyCSSY%0Ye3|5>$S583_U$E+q54U32|KV z9urTLyyKfuGG($@^f@pl0Kq#gNKqCv0QayY>=Rn~UH`4$-T1?!8@GI@_buOb$NS!T z?LF_h`re1mJ^%S*-}tS6^!tw-y#CEU_WJkS_nuph-tlX{`771@V6-(kdi0u~{5wB! z*X?(I;j3Tz`G5O!UwZ6o0oBpD>-S-Q@QNDlSH0nK&CxG4E627^oSYs z+IbWGay2PsS7u_9@;Th;Rf~R_xvXi3gGeY4YiUyoXltfih-BsRmo+krAc|B30dv3C z>-Pt#-H;H8nVD1D8Z1O1B25{BsvlBr&tEv{HU+|E0$5SzbTM)}w^Mnkxwy^m+$*$G za{+*X9;hZ5vl1)iHLCZ1$9KP*1Lroeh=>4I;@)Bq0@k*-Q`!U)NWgvMgwAQA6mlPp zMhgpbB68-`$;o&!81z{vXRC)*f6!CaW-^^ym>UfHrbcElN>xV&g&-jcoU&#P%qX-m z^`Z)nq-LfTD=}kJNad=UTXnY(MAbyN*ROSCRUJgwVDk%e@pOFbkw@#kEG;cuTsd1j z*44`J;==4)r2oB?pt&JnrVO+l?~U%}V47{ScYxMHWnzP?w^#Hb?t~cXO6ra2#fuxK z@4DrU=U2{W)j_pj6(UC!1g<&9yKjESXCL`Jg_66(;5v&(f)ooDrCcDISPzIeHRICq zl5lA^nT3c=duLXUzv0fm!J{Ahg-?F``lD~y+B(zdr1Ty{Wyc3VoH{hfyod^8hw?JF zItFr8U)`VIyK(7>7%Ow3FqeIln~fNycj%q`<{!ttIZbVIVAwx0XY1|PA33#muKLj5 zeA}@Hzwc9D{qisU+uMKYUwtq)&2TyX%MZW#Z~jjYz4G$$J^QYvN|JgI&guwGnF~Bf z!YY(=SF~-dMOzxk6kXE|YtsDs_x7 zHFI@lHmGSPVu-t`Vyc>*hgH>s_S}@%oQTaxoLR`LUOl|3+G8Vs?&8Y1Nz)6sc5h#M z`qJv=s%b6mHnny_46b-PH{}eC!V)|aShS9Vrm2*iDI>R$5J1^elE$IglCu(N&RTeW zX4%QgI8>SfoAq-N-E3{N^=z6PLKb)hYP(*v!x0T^+zH1V+=bYaME7K>h5SCFU?{Bb%n*0(mtnl^NGn#P6&qff|6JJjf^u%b9ec98ETWFP#66pL+g}*T=$@IS6d%=Cp3P3^(k2!OoU_rcLcWW{$y^3*_a)pRU;W z{<%(Uht}-wm?g&oN;+{fJAI7jucqEE*T!`O&NExQonFmQEg>uX;?6YtO|QXc@Hjd& z8?Hp*vM|?YnhrQTJA{1aGM7HzJJV&e%M?9Rcmon#PLu&mJ21AmExThfLNi4g!;7k< z+uxg(YsHWrg+7xaPxRSO+KDIRp?mnq?YQPB-*GE_?^|5mo_G?U{9}Lca~Q7?Win$H z0nD{rE$@~c4ss?UBQj{3nvJFFz`PjG6LS@6_AXz57@D;ri5|&0daS5|J9n6T_hUIY zP>2X(91#Q36cdLtA$!iA02fdoQMh^zs4K3_wN+;}$}#jJ=DGWaOIS zkmq5Zyf-B3^V~$6i8i1Rxo1Y^#8d_D52}T&v~3pMY~JQxQ}2J*bvM4@EmzOqz&6D* zpI!UHqc1-=dS*pN5_>%oVl}aLnm1br>2eI~%_K4fQiKu=;fXYhPms5o?Ify%i8d14 zECYgwle+$2U%GJX&tCPdUpaK^ckkYF3w_sHZ@6c4^u)^6<1bu#DXp*ZsETzZwL6EJ ziG4g7Pt!P1kG+LcKriSpO}(-4WIAytVaaCfPFjMb34j~eC347#;i0OcX{$z77S&X2 zo{O(b=ZOUh{klKs)sq%(F4UQh2}E23;$ZE_RjQU1*#TjwL)DxzNV~^^8KkP4TWvee z7lZ6x=wGvE*U{S-4up1k?EI-`S6?}uPL6dAy(yqX0%6Y$sN0b{!>x5Pc$vzA!yxSz zuRZIl%*kZrJTYV^b+uyYWM%{=W;Ziyvy;1`3ND!@XG0*_}!oVe}Bgh9sV1C^qar;)&KJ| zcb$6E^?&KM!+ZCf;d8H^UK{1f*-Pg(o9Xs+(w8_%+l$L{w^V~Ky!ybCKk?MR_y_;5 zU;p7>{prvCoB#Ux|8~+(_oT;8U{TvVzVgsw?@*!jmDiS$0|oA|5fHI?o}EiGPO6vQ zF}T5tVf{Csp|cb1$}{uwZ+H7v0y#B0IlpmyV|%#R-#;8KF7R+~wSUg$bu)kG9Upx0 z?5p=*_}gbZgZJsbdoYkErBrl>I%4P%-3hF!~pSU}WvcUrC8gov3nqK+v^r!#x!@vB4 z{qOkR*MG-ruD|nd&Hcd3o2MQ;``D-c<)@xLc<`?8yXP-{+mALkju+<^?z;J&XCHm^ zC;sN&{QXaT6yQVsL%V3t678t-_9+Pu_ER%fiD?&Wuz*4YqM?g%RNy1RccV>9g(zVag% z7IPqPK+5E9jm+&?nD4U`8XLPKR4ha=4ImfHIWTbt{<_U#KI3@y<8C z>(gKQ%neuH2EdI%sI+d}D`fr^28gVjhnJQv)D~LUr8;2U^5Ruq7Pkv=6 zg#$#U%EA)knYA-N^I!hm|MH>l-}kxd+{G7`<`0}(eIbLnFr>(d#4Vc%6B9$tvt|)t z2{{p{7ppqATcN+}hI@bXsn7qH>GmVB+SQ*wde3)%|5tziBYFMlCa2z2^>}NYYrk}A zbA5er`RL-@^5Rp^Y}|KK^>_cTzw)ntV(VxB^&i}I`@s+VB~P@oDG$|;)3)B$G^ zcTZVks99n=<>k0=c)08Q_NB3^2Y^Y7-BWO>c}pEiE>-V2nrnfl6!gD zR$3p53ub&OueC9OGKr~W)oIZco0>?8YB27!kp|}uks@-WoG*zD=fd79UcK3#^pIHC zq3%TohrlK2A(sh(A;bc6q5x#GBwWAGWFjM~@C(a~FDZ^=psr-u>+4QX=lVY9g;A$gv!GVHnTybTj4&%(AA`5stIE z1Tj+x3sW}RA>xvgm7Gs9Aq1j}w*JD#tM~1C{k7G#&rV-eH*pQjMKa1H>|U&W%Yl$B zGe|wp9C|Tpzd;2L0I69I@u2MAvh|C;R??@;l{&Mv5(=yU&&A~!>h)&rVmd#;G{K2j zz|5@H1;BbSf$9b^@1WmqdYyrM-6^$G96H*Fca-lP#j?9IV^=R6s%Tj}GSf6YKS{4T zHb4Lg&y07k_;xdPPd7`>fY$PVyI!W`n3l;9ontLJgtK7LfHM;nA6vIr_Go2>>C#em zPB?NWB`jCro`XwYd*Q;XMtggMQOdvb#My7V>%i@|UKKw5GJ&03iqnJ|bLVDUypU+; zP4HqSIuqE=+N+(A8|;9>vw5{UYH6ps{tw^->-sK~Byq94NmMzFY;v4r5fmxTd71(V zNZsOs6quhoeD7rAgiem_M0u8t23>gpFE@hJS%nimVQfF44E^WVrk|-K)ZE z!@$zTRG5Nj7TJ0k4F@^Q5F(&xHpr))Q%96WpLMG3|)4{NSZ-0NJR() zC+d9V1DJ>n$%{mUL`Vb@JX9PR5>W}jASsJ)A_mo7tEQ2S17bxLIhz}1i*|IM#pEUs z24&Mgkx7yk?|7gGcIx+IV31H&4=xIAJsa2&7kFW*UR<4SjIA*!QH)>*&q;q!4OU2k~9(%nB0?@qhk z_}N{b`^v>HoH@Rlw~T2}&q)x2OOOgNB^A#?b%maIb#dcTYwje00~1%m|_^S zT=LD`NEm=>0ux1cn`Rql8zs)iM%8lc-&`Gd-M+m?`Uf9dd*-Rl=Qk!7T*in7Pn{&N zOMr8?1UI;#I53$xCzUPKML^Sl)sjO&5&(f}X{q3yPo`=^L0Gtq)Ug`Yy@k}Qx9t|l zz*a=p?p_F<37MH4q)yDlOlInx^}M<>6`v{q#0*Q*mVzHTeEs7WPJH*@`i=ki55MzU zfAafY{@pKqh_#pl8-dneW?XR!b? ztA_5u=}Z^C8Q{6{gRc1Z<+HOp+pcg7EE1EcZcVo*lWpINBj0(`yY9N>b*D~U>at$U2)e?7I=vM!m#1?<*ip zx)MVjyjsXH%tXWznYplnJK2ow)R}TkcfKMKIE1R|4MK>qs@o|rn8WIP$?l%mMiWNT}* zb({-yCQw$bIMj7y=9ILkr3w>_K!JnwSj|mML_|2H zf;PFiF|hG=A!j45vSy|(_|Vjv z@m2v?n7QZ(n7E5VFc^7=OOG6X;{W)_xw?)Q)?OL*t`hE>rBc}oFTjg|C(0_`h{;Tg z1t@_A^9OC3HrLOeKl%KT_xz2QKKIjU>qQzpfBS3SymZy>Km7mvrF7{rI(^LRrF?Ot zx@~WJX??mHcJ1lwIDg{LPW_z^UH{kr(U1JfzxdUE_>;f2XV1dxKX7xJ=3C#m@H0Pu z=imQ(Po6rJcJDnHLY*xE6sthNiql9Jgbagg)1QxxwY*!1z{q~$`YIc zi#WUf_htZBlW+})Fl1act~P{`)Yp;Z-; zx;M1(B$(bafA9^9NA6#F@%imDF?zWagMgHtDBXkrI_{;xtqetjEEso z;81mEpYf}is}N+M#sF6Wbv4h#0^y4(edX2XR@zBXf|Q(FAty&Bt(X)x%{E{6f^ZeY zlVvjm0Wh+hI4&;rmSSui)GVF<>d7N79>eXo(zS;U-L|y$Kn{`6QXjT!u{Y$Z*BhQ2 zwd>YQ+@M|&hd_;*!D5giT33A^B-Lfz7YnTyvl zb?VB3D1wNxtCkg4kx-%oPrW`XrW1%t;vUxJw5#!~H@jdr18z{LlXr1_rcbpoXZ9cy;X0FUTWk-}?AcJ9wYEGd? z>)xF6T~r4OhsOY$7o6=E45*JOp}o2`-r14enue6`DXY<&ODuxCO9H7k4ud6UB-pz|}`b^;2)gy?64b{~JB` znSS*ydd@R_?i!ppg3~K@_Z@!h6R_iiv0BMqloGCN9cNjSY9&2LkwXwb<{G)g@48dL z0fiTaZaJCv!?9o0!WFr zwWI)(NJ#B4rDT$_HUzZI#7pR^s~9!C_Jflze*XT!rakE^cJANxG~WN6{>p21U-H4; zXTN;%-j%fmrU?|K&wX(p(+r5mHWBLexJM)aOQ@11HLF6%t_~96a*+xo1B+EXXe?(n zV}e`YTGiDd9Gu0SSt3&fhf>}gZ)%cYvw?dhuea>~nYmEc86Y5XPy~TwZ*vzkZzXZQ zJ2;5VvzY?sWJFu3efa3|%G%nAN2|v_Y3JovE-XGvuJ3zw`|3Tb?Pyy;BIp=IT+8n7_GZ`<T_$ z?>lt+#c#j&Z;wsxU68#y>w^JN;UNUT)y*weT$@=g;Y%HZDs-onix90gk3M)VU%l%Y zJLe8;jMg=`J+4LSOq1lpaTxgc5uj=DW+Gt` zW+4_S2dP;Z^K-VYz?2Er0d)CSoG} z$!NH8?s!V;Oj7t?=aE(4&QHQL8_8(fUUXWnC3KhGUPM;vKt@*L++75d>&N|u_`RG|X4 zHnz56tOv6*!eluUbBqCQy^t=EL-#*)j33Qmx$_uJ7G-Xy@#~BWE7E z@8LVY=@no9yT9`Xqv3{xxV5=KQG)TKM<3la^TcOd@s%IC|DDW++y?0L zv}H51yQEx+}yA9~dv{MlQ7==v95-H!4TpF8{d z|9j0({mhpRAI%33Ucy8Q0V#->*~!(^)FiMuNQIc8YB_<}oedO15aA|I423CNvfL_; zmQ(9W6e3ffWd<}e8|I&|IH0jNn`S+5ByUR8LpeE-v$B8yRj>qN&#e;RrkYfQU7=a# z9Uqa@Bk&CH3M$V@Zf6oPBoCc%~= z#EqE)nL-Han#<_M0Fwo(>(p42G0U~kL`{hS#@PIU;i^w%Ib7(PImf_m4mV;I(@C4T zo^?cFnA^CW2r;pn=RxG1v!QJ(*QM2yM-P4Y%Y4-p*tK`p6L$AM_lVG-*T>RKZ(*i( zkE?2DN28M)Lx2ZNRyHt}8k9krNZ2%+8<+%QFahN(gd}+^4b} zQqLpj0E%z|0;Gm1k-(eHhu#fjVgNFQsu^V;FxA3=0N4~OF0*1JiLh)oZ8FYpD>_SP z5KU#PMVQV+5hNY|>ikRc4vvLk$_WDniUU}7Z-7oQdY;~685BSc*Xh2N%PP4;=X*=! zjU-pdpqkH|nf6eU~2YH@2#!MO{n1r(IAc8xE zB1eE{ZMj1i+^y3#3PpjCOQc#5164v5Aq4bdh*UA8d%gnM)7!gysdr-I)P2Ka$6O3; z@)3~d8P->`&;1nWbkuVc)ek?XGWTU&HGAn+HCz^6q=@`wZ@DIWa1*sp%+r1ehvA3lX=8 zD-C#1SM@|ELdpcHsaWC>xxz#Q3=(pnu?a~|xpgO}pl-0laB_(xn=*X+L${y)oALAS z-FNT_GxOKs+21$!q%X|f_R-Z_?mu(?Xw6ySQgd%HP_!D@jObU?iy?-Lk>YF2Q6 zPR-W(`k4@fCAwy&Sk-gPmF7lMF0Liy#T=bfjhQ4!_c?Sg7p@E^<_ax=m~3jTwF~om zdh>hV@R3h{`rb!==jUJYHP?Q}N8a+!AN|b_UH^?we%aGr*zd(RfAJ%mHtsLf8EHID zno-9%oUA6DecbHj_cuqr_h(=CoiBL#PrTq~Z{Bg!AKv;W9~*u;Ggn@0dlb-7IvY96 z)k~OQVp|RkTv?ee&VN*h0Hzuc?MjaN_B`8ZFuFs7x@mU%O#RP*Y^fcA>pJ#l!u~5~ zuAZ$HG;1}8Dp+1U*PH3T{F$%3Z09Ba`1wD%XXA72WU{ZitXIuu%h@uSDY>}?3I;c{ z1PQ3rL9k9|>l`t&+Mc-Q>}Q{}=S7F+EurR7_o8!AqL8t-AjVC z6P!z^2D!Os%MLKHIVrMH3->;DIosX%(oY=w;`PU#^qrTz`o)*N`0K9tI-ilF>yMuO z?8&#U{X2&+&pT!p78mAv4NX>U{oa%JofsWYNWwzy#rUYo3S*NUB~aLlFxV ztrIcjRyAvg(;bB4-8`}tk813nE2^vB!;)7$HUF9H}6Db{3yJPy72 zm;KO>f9tEh?Q>tc_l^Jf-kSWWH(fs$>+;$xg zaYtEsl_$}(NjLx)4u?dDF1==ZBChN_ANpNyLjWMO`;t}8+zTt|nC6za7TNlA$$ zvmoLQ>yl5Lm;`~~IUpjkGF6`1JQ=4nX&F@aE6oaI4uT1#HqFfTcI;UC{O4{ze&X=u zS6vpX8}57Pp7Cf>9+Ih$t(*v^Nui*?)H!C^^b@x&4l2~i$L`#xeZ^z;@IKM?@nm7g z;_mgy`e*L`_{}#x{ae22>;LY}|9tS!<3c|Wk++nzJ+plJs)J9u?a^C?dCfgm!l(!1 zrm17!kcx3J5fP)yi7#(Bik^<#9W2aIvvb8Wyi@Zq=dD_HSkCG$5<3+Xq~P?0#Yhl9 zm>Ev)==F9e<~PUOi%V{}|82i-W9sE&ulye)jdR`#<0M<&zKm z1Mj;?uDwB5x2*Es((Gh?a}Bin(5`!ym*4!}W3PPa4ZFhNEpK?+4}JUZ{Qlp+=7twv zJz38;edWUM{?Sc8{$rne_i;u3K^cwp>bBqrw!Dh}j+Wo=ax-T||Q&E+@xLZ(*>sI5;{S-o1Y8#AMlGX40f%5n?uX7jj1e zh!{!LGzF=cgE~yxNFgFzR`0wd>^QM;;>37GdVx5>im2YFS~Hj$5gEZPqcHJ0h!yTm z%;p*56!Xc=`|fTeT9~K#HRNOs@wDrrDN%%o3|$tZWny8I4!Ll1gOjj`flZaU5^>9o zc`gsq*=D0KldU5|fms4cB)D3eoI~hGtDD@qLIfG+EHp)U3XmZr1PGCt?(Ow&xctzO zbH|RZtf$^CcU_p_y}jO2zfWzuv*u54r#(4bWx7q>k>AGm_z?p-)sW(8gBY!;^wE1QFftP=r-Q@T9T#-J7Ynao{< z#m$_AiAL>a@(D4)gOZU0nwbMLXG>GWREyt7Imx|b{%uzQqT-jPP`FN~%Wm&Y9SwmT zv!U7x*+HQP*LHl$^C|TeqD%;w+CXA^Ho^47BTO60ZgMDFQ^M4YsY@#92IvcV6?zPK zdVZzeSs)NO7r2|*0b*xofRbyQbB%QMLVe@@9oOudm*FS_^F2{lC#a_99b9mko617>3QcSL~z9vLvPW1 zkhjKe8B`2f3bN_bRc9)uQ{alYa+xEBr7ciHp2*ERgRBb_N>jZJI-vN1YOYBw!_#!= zKL4Igcc&Mye5WgSGX>cc%nBtVX4+9;n^|6rB(VA@EW=tSzzrpRjf&(I=%CudE(S4m zeqbEoW(IQRdMBJcpYumg_`|p0wnMn~UR?8B8tkg)E{=0INSsH(XqCKW=IP&^vQL8RGp9m9_K znXNq7m6nWb&p*qI>_(J6p=WLu4!pcfGu zZ(8_B8>ToT3&h%_R5h~SXP>on@MSN)X4lIr7&brGKKzm8kKcRjfRHS^ zb9Pg>QqJwL;vREQRfVgmrQGL!FiVAkW^jkPXIR!ET@8v+V`KByJXfL0IW=t#L?Yg% zAyJ5^PVnSC8=t%TBL}bl{Ke0C+V0C=IGFoteC4y2E`8tJd*6HP?vu+~mSZo>cpnHx zk(ps3QbnvyY9RzAbM93&l!9=HIVd)}>;g6N=*|Qo2pJ2*sa0b^T}fZ4GA*N(cny5PIj_QW7}HI zlZ*J!?!iT@v!_N2%l>FHS(yP}&U5PdK0SBFH@a+QWdtT+WOqx>!NEmQLUBpb1^anfkiZBV<}1Q zss@rk1ciZ_sc9NWIC#}HcP^iJ!4Ll9Z~fRyzwve7`skm3@-u(`*{hy<)mK09SxN0J zUwG&8*1EEDbkoEv?NHqtn{W45`%bPMdBcbP_}w3U$4|ZL`~K>tKlqJ%e)~=5{&fRm zni3}nX|;KDM)uS)@9@S9=1w-HZ%oSqF(|kx0Yv1G=~1=~;hf*~;jv%;X=){az>_>_ zm9O1*`M#Mwq)3fwG&SW=t(;q5UEX-YQnsp&|@W(lr|CgkX0f!Mx;J6`k19Z!Db&EIp`cYoDWUvlM>ulkmq z-}cD69=T`Z!GpUm@i{v&Jo?b)qbJA5#y%1faVZO)3+cY)M;DUQd6$8bgK!@5MrX6s z9pPQa5`u(Kfjbsh8MSGu1)*XgQ%T1(CT8lg_=trmICHG~Ay(s2V_EB&UYg|jo%55e zVKZ)GFKU}PkmsD*)+|*uuWziTc37N>rz`3UHmx1LTHbw|s&u9|hhI?Q&X=?)xeP)a zNNN#DldZ>p<$wQ$pZejQGjijN`+sx!-2eHdH+;=kJmrQb-!wZrc;xV@KYZige*TkR zjF&!zVn45(1u?1_Z`X>h6b2%3%H_G`Hq})PU_2U@`O33}z#`=4ZQGh#RaJwTK^23k zxmt)!LaxN!Ru07Ea8qRwbWMEMeF%%eG&?g%9h!-!)TW%wa}eTK=aff7XJa#C1_$0) z->j?f!WTX7eINRd4}R#~i-VnWiwmjENi!3>ySWl5NTps{&}>d!7SZ-K?K+Ush}#8M z*Dv`0W4^Mb^{thKnH?AHy!fHh_q_W9|Ne{r=e2j;dFLJXJ$&HMl`E?&0QLLf^vP2P z`+L9o2`_ug7ydess!tZ?_q69uK`F-AXzOZ3;>C7_&Likt#(D>blC4DBpucp;<`0g}K1A-MkKF!yKXB#uz5b%_ z{yq7pxsU$K?_7J;r9b)l-+SHvdimz3|02qF$Gumklbb#l5?5!AuE)jR?%lg?zvuMs zxs~VLwC`8`@PGaK&;9QAe#>wE=|BARlfU}P@ww&+PwM~98=m}{@4fZJ@&kJgT-vA< z#;ZgogR8-*5M(SRW;TEzBmtTX)a%U*G>^uOs*;&hAger6h(XnWLF~;lRYqaxIJ;@r z&sP`E&OfrbwZ)1M3#-+@C5BVgATC5|t}t>~k+#A#0DC}$zf&dEpqh`ecy>dU*st7G zg(W_l^|-Ixb^7=@J12GHW~PNzYwjijc1~?;Uf^*l&RzxSA!T;2bANAdr?=tm)zvi` zv3U0425h+)_OcVqy?h8tU?I60Q6Peuxp&e)cL&-LR*y{%@5SB)T5N5+;_IO(t@3i-uHEu2Ym4k)r_wPKgYyR|^ z)pM&GYa5fLfx)c;LT_>T;jO`&K3~0jO#621y>yWt9Pgf43T|ubqvLC%lS56+y(%=V zyO6lHYCYma9+=Io&<_bFu3`UKu16 zaCPR6c046{bk=~>ZM+L9s9Pd-0()};MdC$~i$cB6Ik%IONT;Ezz?f-DIPVZqnvzIB z-4x1&GCEz`l}EMLtFUbu?FjIP|PTZbWa$)xM92+EwP z(;r(Ng`vq^!NI8_=@a){C%^8tfyFR2dmuO0}h%=WwouBfOe&5%Q9p3!Hzog^u<+Q?Va5d7x?lv#_ zD>lkZdG2o?&lP&!MUfDjOcLO`(2fXIco=T$|V;k86Kqs^E3;JW_4 zo3FXz<`-Pndy-h?t8W{A>OF_wy?*ymUQ4m9D1cB?NR}EiB_raAH#IpCw~#0`pc5au zCka53*3A=Ou#6T7#2K1RTWeb$Cu$6>h?uCmvLktJJsS+j8RLMEDBhcoo><;`;6r<# z{qX*$fA!9NUsqlJt>K#&Fa6Z}=N>t}adtdBGj2frAU$WXB84LF#n`AZaUJVks8kVR zpa2L+N-j*704-g)HRi|?CBWZS` z7%GF3x9r_{=UkLiMcrCB2~$6xLag8hw6>n&VhnRD1m1sACrij!A$B&SeQe%WpzawFYP=q zu805o4gY$}XKwg~*F5|3i!b}=o8EWoj^odK*_G8bFMiWKA3Bm(`*WeL*^q)zP^Hkc zaXI$WF5hwY_`aY0$KQJOjj#BHYkvO92M_-K$-g;_GblMfM8SEe%R}9m3w!5iN5*8N zo771-%E{W<@8m9^%LwMvo$B-e?qI-e?fdi`o6|IRCxH&4kr-F*2| zCHQ#KP(^0w)%_-o@4oZ?i!a{)KfmIC@4fB7J0JPy`+@o1u1b2UDNtnvz&5~1 z;X=ha&b;_4f!wL0{<-Fn+m5~WDVKiL&c)s2n52oD^obmB_VW-uM3WF z>e5)dym)f3h+AncoSEDt#9Crsq%u`EBe1IWXKI+|wslj@EKzb!rWr`F!fT-;Amq9eDdN~e(jt8_zkzb z`yU5$JEb0Mo;wA^-sLY=naPt8f+0HqZ~$}JCKGjg7XVpvpLzf^H9W?>=_o(Lry%u4;G9S~f>UM6nvUS1C27 z=>p+X2UhsBcz2pGf6T?6b~DrEc2TtE;o4|r_tL?o(V;Ki|C!I+@ws38_1AvOtG-9m zXwSl~G-)NX<+QcFb=|c$9_oMMc>5^l7?}6&Jap>pDT#f+S=cpCLw~9G%rOZ$J9Q1Q z!#M`Hr_?OY@4e}|n?L=f|Co_*(}Aaa?C_`EwP3UEV2&Zg5Ncz%F(|}-pJFhR_2px; z^9xH){_4E3Iyrr>ZG8E`KmFy|m%rxH=Y8Yw*nMyOwI6@&ul&jP{q!4t>nHwu`of!f zH@&htaLwfSX52AX?Or&2c%#R=_FcFC)`!Q?gkD`GOA-RptZ>f*i^x{S{hBX}c5r5KadT_zrew;kw`Oc4?AdurGh+#! zTT2-Z7a|0v*pGwR*~Rq{j-1`N?7-fg2j*7K4ZnQ+_#^q`nyfevlP7nF5W_X)0wFrU zfjuWPm%z;G)*1u?B5_6EXZO|%>!$aN&NV?}U^O~#OkDs{VuGoa%p2}tt5T7tFo!b% zMv~2&6pVicFGxxB0kTNznH&ih+Z3{CYNNN2E;-n?G*Qas{xDXk+c`-xAy#PDXPFBLvFB;J6_JCvJA8>5(y2PBz#?R13;>$U2-XcL z+p|D-XsZ(d?PkR8J+Df)T8>$UIJS)h2}EjI9&MY71xG;v2^DxYRC}40^5m@PF}D@Q zq|8vheQuRbqU>s?liKtj(+4io(X{Dsr|t2zW2Rn6Qte7R!(FB=O1A|hOg#&nh(Scm zjb=;jEcEjE-t+hE{FbNhKd@`|p5^xU-uKXFk8Pf6ZT`&U+h_Ve^_(kDtZY5|`h8El zdhd7t_WRE=7Y`2Vejs&mfnCWf%@I+FBO<1<7P{~dCxi=jkkgOk^cI<}vbVp%r+pan zp6g}t3LBo*$qASfMR!mcn7? ztw$Z}I^N7$yo?jWg<(a^O$;xh1cAE2!6FC*2^>wq90Er`x|@*+#lVjBoUX5oSBE}o z&@|(*bK|6Nid1+#4zq}O$?O$q;?R;Hx=G>9S$1SV3UgWdJ9_AQvj3I+7=D^Y# zO_KMWZ;)LteB6~!eg5O-Zm4xePk(6R)E76u^uVK^86H2uTOd~RT4IJza_bJIoV}a~ zFyh9{;j_Zo2#!EBY==TK%>=sa7-6!hV@u-_b?rLTt&wdenp7b&s7?CUDeG60GR>KOp?`{C5Sk(y1Lo6Eszsn86~Ma8K?oTDNRo5 z#+l*DLVd}lJFc?cfzg?*tuyOm*>%OfE3TWd!N%-+*Y7=}Yb+Brb9W~vCfDRSc#xu8 zgoC6c*mZ)zZk1#i%q+$ECc8FH%wjpandO|MH<;bb>b`4y6N3>E) zCLxvwH6w{a<)}3>z|}+|L0Cdob#3Nm27^nkdGl>wzT5>Z~MqU zf8>UnpZLEof7#oPedzwp(_3OyWP%BKJ8s&PhQm#Dy=Z3ttPI}##kU_>Jo2(@Uw$y` z{==0we{T4t39>nJhbcG1d}byr)iMhTt!^pC1q5_Ara;E-O5ifLqac0TwFB(k>38AW zvVAI^|4oMnu9p_}om)M8YU9-NX8#-9COVolO{l82%>e3|+Q}Y0dHCR=z2EVI@4Do3 zhyL-dzdqVL+}L@huyQZcE6q<&U(ejz&W(iDFCG+&PbYF$ZY!2)8t<&mwzSFqyYkNOXzC3## zxr5l5dw0D5o&WsFmp=K1YgZW``1IY)+DeRQn{z(YUKOpkKbu>cpq+r+b0T+ea4XYP zabE}ob%$#4gMb=DgqbBUfYjuwl3u?GA$V4-UmN@%jd7U`m&dP)hpir z;diZXY}8;PV}ip~)!{KzforO(oRj6&EKTw0DX=|_p4z^a-Try|BYM750D%-~b@SZJ zV8_m#dmlM+@=gE#kKg=F-}u8n`n|vQ%Wrt{HP2}#EfUS|n6XW<Dw`)S(oi=h3NDq^(wH}3iHcx!#f)h~$qURcTV){Y!& z@BZ|?chxeuw6}BRS6=(mzyH^N^TJoZ?t}mEvH$!~k%-aq@(*Z$!5|JG~1^$&jMZ~xczFTQ+hxxMZ=i$C{sPx(Ku`Q+wu zSUPZdPC^VO7A6<&awoLL^ zo=rk1CtEqem{~P-_huF#xD!dw5!HYWGAUp^v5;wYvgsf~%O)QVimo=RuY%%+GVf4if0Z3^>sL?4=Z z>|>kta~|Y7e>%FsxET4uOv{N`7Aoe>-a((qUE9eV(z7p_{pw41K5gG_$~d((`IAq7 z`6CZ)95b(_s$$s4?H_&Ok?+0f;$Qu?r^LDHZ~yL=e>=Pxn4L<>6?@lCbhz$?5a~8I zsi5G#owp0n1&+bnAkBG`!wbF*(|NW0l5OJ@1_vqb^ESuDOUzZ*A8~5Pn&L+?HC6KM z>(XhCk;t>_7A$}wC~$Exp&~RbeuhdQqDUfeg=tx=`gC~3`HtYiCu-B30#GismwA;s z*uB``6T$Oztq>d_Q-@D`vd6sQ^VQ3?v7vsh~<_gENOd`rxM>{ejFf zi@6ITiqf*X`o;2_`rHo~OfZfJEX9N&aOT~ppRu_2riLE zkeEOacQ^;QlZ~j(rb*N2oK41CBk}nSL4S5>Ztta6JbwSaIU60x_dK+^(j-00sjv^_B^a0ImXy zfV@Oa0W56lL`CDu<)nqM1SysSL?EU%We4xO{BaMQJO1Jye$!w6&`V$bi{E(vpMUg| z@A~ky2QU4>tG?ksj(+9?C%%|w5xA~m-K1=-nbB-rd)90?xOmB3!(*Sm<&R(XglGKp z;D_FS?nCd`_~;|)xB)`NkSuTJ)3q)3>qRhWaz_g&gXzNKpup@Goc`OOpKk*?xZpUP z{%X6)aIzD}?^d)s=#qp~z;aGJ5Ys*W5xqOE@Y^S|M7doTU#&;8}+ zmOpzkjdu+$uFwZT-9TK6yIO)fEJ8pwb>!1BRY&f(7=C&EQxh9qyZ;%x7WS-eotZQ_ z1~at1D!?&JTTUu0LehAnp3Bivd>aeSAWX1rn^spSL$ve2bfqRhW_5>3`sbCu`{(!m z9Z(0Vx{jfosNK!9U4cra-Chuv=@djH9VfeM!pahvwvksBV(I!73fseAX(3{WA%wPR zQDQdCY#ZY)v;+c?FjaAOP}hA2<>Xb}Pr034=(~C|ZhHM1-LBnoGDjlP&CT`A;aT;D zNT!DNGzD7Aogm$fPzYetn)R3);W4el`3?TIGRpH7EIUV%nfCZSzxJa)v*$_A;r{H& zPrkcZJ66SB6@zK3xz*tbsxQK94Kk#r^K{?z-1A3&{^!5)`qzHs z-M2jQ;6pcE_DpMZ2D2J-ZYR&W;+fCg_thUi{jQv=;nwQ@-TRN6IvlGRCM(X4rR89W z#KcM>y;ubf=4Lr%SPSt`N!zqN=!=dRn?hVaO#+4p|<_zQ2|{pWxFGe7j5 zumAa1|G}@k`G>E2(Pg7^?X$k_z%Omw{JNj}!p7NpX~#jYDkFtCoI_+M$*lzn#BPGJ z5|R)M?qcL%3Pu*|Pz1oX<|MaGvuUkzOI-XK z+%$;@gN!H=IcfGx@F4wauv7XATN5+$Yc8Lc1^MVhhwofFuDymyHMdzOV0DLPb%HRt zTX_$d`@P;EYnxKzo<$k4+v-@^@WN9yb`$#V* zmIF>|p5fVHEY6|XOlMc*%r$dY?zP9ATDwnuji@+VlW;ItnRts1763WHB6-iD;66wU zr?2F+>} zMRJRb#o2|;H2(DJ`pG-K+!t)A2B~HwW;ar=3|xhv=3^hY?W{wb?fd+k+ah-CoBP^l zocsKJwi%XsgHXjawiQJ+=0S*Ru%r{f2q6k*g&8x6TXri`jS&^LY|)LB=DQ$oOjbcw z{8Y=$J~=S3nTfB0O21vQ2*}07T{{u7xhr>hmH@FighB`v6Pc%MWw}tUdx<~a-jH6% z*#J>TpqQ5XZU;%l3=YH;0fhr@HXSVsN33fOI;jx@J&C&{?q%v*-m<*rzHB-sv`pQc zimqKR_tiGmI~_!)%%rIu*R;HJ+~KLShC4`zq`1PBjb69>ojxZo$v`$;f0Rcl=O-b# zX-)xp<6`eSuRHKRUV3>m#s|N!_Qp>>^o8|}EpSizGeMk?)q;fV{XhKtkL+4jhK!MC3uSi52iP%&9?fFK~)={xQ0 zF>oN6H>ylG!AxO*={gO9ixp!ZJtzDb|iC95Z)-oS3Bo2k68-PiM*L zs-s&YT=+cg{Gd5KF+j``tmp)o+;sXZrgg2nXT@E>(5aoggH^kqQ6A09b|io!3_$TD zLqQxmMrF4IHWYI`FXrP$KWcY;Bf1;pCbeJLrHsL7o;)+8XVse-gko-Ao~`Rw9X zTzT;`zy30O9sHD?eB;^&-}T_TH}7AgAyojRAESC}s^)o1+ZkHeS1+AvPE2fUFd|9T zf+esd8@D>ioCiFp!RjgH>>-jDM7)?{YxZ`m!-*SQhd;NqHooX9Hs<%fln(yr%*&rNbH!V>zI5B>(KF3B zp`p+sl1NI<6=x_LOGohoXAh3xQn4sPliNVWdK|YoZXxX z%IYZIbbyi1!_82FyvkT;3Xto>kq|R^9&c`0 zGjQr-_9ELqoA%dZZbl)f^~fu?3Jww@67BM_$Wr#=_7qB^PY?nN%-yV`ys4YDoz4?P z+&K+`A!ORDZ%o!nm{_LX?o{l`jMcRz4lz{X!Pv`6)Zh}xVOfi_3M2$LXLSf^OC0D%rt$(-n$@P~#^*NXH54_{pCyq6nakhp6 z1kE0*kXp3v)&Blce{gDL|85cMd=DspVT&eS=5{0r18)n(??F zW-F<)lj;NzH_Mc#LzWkI$&?Yw1%lr`XMK8-PEX_W6AN`rp)s>CWJz|+4`wvER08sp zl`B@$)Fh9sdLDaw_rv#`TR!!a8=m-+yI=dx&%OJ7$KJUyTwdTkRqT=GRuQ=F2}~_{ zLqtLXsJn8{LpQHOXlh7mxQty(Tt z_g{sR=S0OH62ek)j|*d2SfaPI*`B4m zv$!``OCl2LUV8Y}Blmx*fae^8Y0j=@*-TwCnq}|rbv2|!0iKMwa*m!FfWQ@Eg{;tt zd$E_q%uK(kDq`vasR9++QK+lHoZ2=KM1+F~O8KD>Wcq%U>uEV>A|heUDok8Osq3s+ zv$8{iv`ua&t%$^0nkJ2h8`nwcAN zXmf7bF$~N?9lym>ZmD2e5>$=6YsIE+iavdpQAXm&!q?>aE96Fk;42QcGXLqiw zoqWqX|KSxcf5p%K#!tNJ#oxU-8SM;9lZ|%A{L?CK6I=COL5>LR1YFfz+J(__{3H-A%JolCY{UAeGwX6vqXJG6i9 z>itW19Nik+cIN3%@<02_pZVeM{H0(1reFWrH~sh%U-r1sN`Aq&UNYXmZ~eyoLk|mw z4zw<+Y8gVYHLqgGDQi|Da?NH&OiWC|mXXzknYqLeiMo?!lBlLk9HT&CWaqp+Vg22; z>=_IuVaMqfYvY`}DH=bbSmrngIk6F!y@`Yw=W60QPFSpF7iQw^XV2Vm_IQJ)7u{4- zn*g)2*e!A5%;avG&7FcqM=^IbYmM9~xEl+z&{kf(XY>A3lf!LjSj;SwxIw9dRSFj3 zR^+ct0L*NgmOgoUe(K>VKeI0aWY8-3^cV8VOenTtX{G! z8OYG0K7rd5lp}$!`Pt)o3ncX&8k*Jvi-PBdBO?P&&B$ELgBa?$knf$7WN?xrr(vQjsxcduugJ3~{24#T^S z!8xGjO0IqgpH8!#`A1n}@V0AlM@uWOf{7)9 z%`~HYl)CIU19M3)peYpqMTcG5BPIs9s)Hb6CMDn``%t~Xcuh~9)y<0#W~qOv?Y+XT zc^s`jiypqmANp*2?zS*F7F>y`93sRVgos=XB7vO?xt}l%EM%bO2&qu@s9$+g!<{Ig z&4{366qt%tTU}Fi+oQMMzk1(1?O_0J#2knNsE}cu5g8REa_EN$Lo)PupgLM`Inf_Xo$g#Hji5$xfmGcI@S>x^}=AG zUKr5)%wWgns99fLG3Fo@EHj!O^(GlBJp9nz$4?$^Uwr5M6|b!8=ix~=%s&1Dv-iDc z^MN}zj-S;)lXNQcS zjq3&`5&hk5T)cgF`pw5Mr_Ft*&mPlCWe;Qq?FRA|xl3hmBSa#CtEKE}E=&Yh@01eU z#RgL6j6*E3#7&f{yL#IygZm<}gGS&+9hH&*mOvt^Zmzj) zCHHf$ecQ*r{JH#rnZ5|6R++=XV7_Tpy9#jjz1oo1PG_d&lN`zdU@< zkkJuGCygo~!hxyRlYy!yZ@NY7bYAVC=joCNaL{>)Ye9JE{L*l`K_n1FNZc75tJs^H znQd(B?oz>6ofYia%*g8by2bdj_kH%GcYW~j*Is%3HBVev*!|)A-*;^7DC=Uyv!IxC z!tjb_08($2oJmR=FLjy?2eUbZ>DcJ*@uQnp?YVh&ut=P@Mrz4}gqdm{9-4Mc<`vI+ z#Z4MnDKpci!l4c-KCyt3l|t=sQz#+0XM;I;wx+YjB(}{4q+4+#1Fo9c+t7>Ls{pd3u8pbMv?>FNyh`oRITU&Vg+Lxbp(A<4K2<$JLK?Aj zMpio(m#R8?msn7!#2l-TQ<}hgy}GU|5e^{$aJa-!@>)uv)0Es@B)FNHg(&@g4@Awl zRn1lg4g<(zFQhh4M&l->oHG-L$SUrJrcEGF;QkCva&z|V@+FsF^1}Fnx4iW&$4{P| zo1G;_6{?JEZa{hNC8*j|^OUmAD4UGZytn|{^r-)Qv1xjxr>lG?qBb`xYo`wEzGC;n zp_8ZYfBkR&+CTl>-@f{rU-|a8yzhlKehs(d$yzf!H@>^Q=jxlj{?$+UzQ6k1Z;K8$ zN2>=9T=M9V2WAGdz;?I@h}_N15(p_b$PV)2aY88Z0GYVo8*DxO`7h|r%KJX^XD`Fo z{PI(O>HpmJ3q!PlddzKLsI{gjmfg%y_dFR{kXY9&ArQq7oAD5nlU(n>SV{9}b!ErZ zFSzs05B&Y_|HW^=@h@NV1K)Aa=idTIee~wg?JatovXIZrykk*;;dXeS06|iDYiI(oh>OzAY!so$pIrlyu8|dqeu%1S4tI=`MmQ5C*d$ry){At}&e{F_{`%_X+O7A@ zy!weZ7o%HR3iPl$~jje$(786Ibr*=OjFAkcSqo0 z?yBnCErz>J+wuv0bO$Z<&=W+11s0|vVX$p&z&6qH{3?)8+V_+jLvdX${E@D`Q&*;l zj_N(-6HiUv34y1x(Rq)BY1#5(0fO!HoN^o$D3O4^@GQ|R#~IKdHzT#Pnoqc`5^^_y zbP0+jB*JaGe)+VG=;q~egmIaLr$;TO<;bUjIs{^endY)p**^734~I^P<4gb*cQH11 z)k2o>-I2fL#w)+)8CUF`0 z-pS5fl0039pg3JZLa5&b2ayGV#E@pt1>$DWs0> zxo$77Nv4TLT|sa+ca#3^dTvj%c2p;4rhio4FzKk_<;8mWY#5Q0kg?7MZhMVUV0~*k zB7C{1Hbr;M%iBPpqUixLb^a$x2I2@;f|!{ZIg5I5?gj3-!_x-V?t(<$derWxRDC@k z*jruyB-wX~-Mhyh{&3zpQh6p4f^=GFz(^HFL}n0S%2t@@0H{X{CYRcKb2Qhu!c#=w zIghO&D0!$k3iXa}oStAfOY`I+OkND8oeK2}6;Kp}2-DG<)!Lx#!4RKv(T?Xn`{2&6 zTg0WXBYy6$H$L~iN8hz}&+*V$O-_@x-D=yRct}1O&@2~=67XtTJF%hPE*giai-{CSm~-0;nPbO}r(_8M#;=!*lYXA`v`$&YI`y*}V&UYw6Y1+;BKK zv30u1t_*k#WTswMwPjbsoKzc>Z{Ij~=HEA-efN%=zkYtl%R}$G@T3>aUGX3F18*PR zcXxhhGmnhMW*nF@lS+xC7L(fRKD)LKu*9AvGIJ$>6ym0?YSlo3S3zUdlg0UZwyM3A z;VL@ywg9mpGLccw)a+buHj|`VBGD|vl@Q91Xh1SGLZJ@;frT_pz{MKV07cOu==5`) z4B0Fcv-g@XYuI{l`Qf9>Cj^#L%Dt-Iam~!ajBcLUJoZrDI1+*qd+>^4)h2UM5P3F~ zFym}4L?Y<&K?1Xo!4wXIIte?93t=a!?!t$?OCK(qDN}PY5o@(E_sD(s(vz_&>M9}# z5w(^*C-0ne80G}x04phIA^>umA=r88C3l}a_WbYvi`Re0OaJ@Ne&^}Gyyep${P1;$ zuKB^szV7WuKlZtEj}Ey-2%3x$2GVb~8t!S!D3Q-+sO}o`sA0s=IZBu$Bu9P z@TpIJdi}E-x@l#egu3TsnLSq30%feVrwQGOTbM%K=?Vq~ax%0RQbD?NYI{96?V`*6 ztZ;I23RRq|>)yu7I*44*wuvGTOed!99;`nb)hFfRa z)up(uTJD8Nix%9y5@e_|AaqfMg{=z2jtDjRJkE-$6Xmb}~0 zK9-jH|2?lx?+}z`W4nMBW-oG+n8}^p%}qOYl37<##~ajJM}HBnaHYUdF3GN-;L-zC z;J_T2qp1;S*RCB7OKoD|0$`R*AQq|n{TM`o5RE(uqv=ANiF`C(+ZwJd z&Fx&@Sp4K?-v4)h`Ihhh@$dTByKXso`shW2i&s`QcJJB=^ZRap_(%Tx55N1Ke?2{U zWO?<-WtTs7ZfmVY0E7 zCll^3O_n#}?COqdzVe-K{kyAgy!KE2=1t%Jimy8S<$ofn;uHUy+U)4)$+@RpyuRFi z@l)ga#rvw>Oqi2TfA(y;QGfGIzxPW&@Uy@E${+iG{^)0){4HP6uGkB{Yfo>$zxqpG zI(?$qeaR)+*-fap)p~$yF^z&#RrM_AtX5*iH5*G{50%F%^13yRCW;b5ur`MnB~WUb zmDG$NgTM)SoHrE{Sn^^|@9uCn0}DBc1h)#Q7cn;*XLfLJDa;0!)8n<3$(BcV%}q0A z6l-5_h&eY!^XaN6alm9`Ni9`^I`&DW_0|(OvshJQFbIQ8jk9<5b)8GOPpK57W`M8+ z_f{=+O)?T(9ogKNP{tcK2v>lcsf(#^jWZ3ZgZq{)&s$sP+QY(BfD|>q`^&TGG`NU{ayBPR-r;GC&PWNxv6Ia!V|GwhV`Od2bKT#2=<;WH zj%SXYqKUZ)3@8b^P)DLjm?g(Z_Nam3)SBF*>l6Kl}W=vOfyw1>{(4G zHb2jY76!9*mCQ8JncI)-x#iRGYpw=*{pY@*dhEU2@Fdt=Up<3VI%~2v@V#;dF zL<(|ZAt;zVWi{f$i&ZmWDM=(kl&wIZr0yWF*s`8nrGpDT+e2)81Y$ESaYou@iIEVS z!Ca|?yLJmucVt7FLQOUu_X@}tx&>_4aCi2(0H!BA+>|JY#KIqBVuN+e%7PD5F`p~! zS~dvtY?K3`S~O^C*G-SQZ8}Ck3qU9s6_1`N@K`wJ1<1lrrB6d+VmC{mY-B+BJN^RTzeM~2Rbo?Xg9JtP()&Wz{ za(YoZp5iujil(IEZC^fj04*jboGN%G(r&(;ZqN;cFiRlMo9Czb4hZZp=k5s+!?!DX zsm<9PK=zy=42oX7S&85iAUj%uQb+2>HWQCK9=cEA;_{0uv8w0yr+gHGqNPqwe#O2m0h&oRH3S@XO0QRH4Os#0&zzm2@rMSB8n9N7)Y2w zbg-vPs(T2J-#Pc}r(JyAOZVVLpuy%}r+eSC`u@Xr-N!4b3M@JM$hgTgO4g1s8ibi) z#w^Xv(yRiTHopDb?Imc43Fg_o>RB}Vzv7KgS-R+-+C3kf+;bwI%xIaSRZw;%7%GziWK5xTC3rSe996UC zHq>>upK~DjB}$6Q3wq8 z@4p3XiBX>MbZh%FS7XRMcL?SuEjo1y@!QM?c)CGsQE$q7} z4d#F9Z{P8W&piCAuX)LHue$tw@A~6ix9@t{_0PGMFa7xN-aEIB$6mkU%Aj#J4sEis zwQfBm8xe(ry*(Rg>y7um=?Sw}f92)R+&{DL%?z=W_Um33m9L!DHnAKea-W|h$A&qg?Hn^#`M9wT^W^jiW z{d8d~1+LUb_pN@SZHJfax>iIs*4L3a_G;AZ3RUA6=X-%k8XbeOm*lXiA(9XmYA$n7 z&FadKtZL9wx`bd|8d%v}7C{j)vBS-a%$d7AEzoh@r`46a3)@l8LCnO`&8(4FP)G;c z8ZaU?D|1(=dBWn3AQD1o+m?ugSyh?D%&WQ*jxb~4Dn_ulA=aFloK-~v;5oOZSz<8D zZJLZm>t<<+tWI%t0*YNM%q^b>OS`Fa+gb4cWnQJn{$?lA=^oXwt>7&KObG+`?P<%l z3m<#}-9YYv$eochdq(l^i+zL|MeZvxgqSq-xVL-v?vzv3TnUSCRfiBHNa)qI1Obt% z3W*5E7&tJTNQx-X0Elq8)L9ik+a}G~O+}bcnX54|iK(%0aB=exqLU@0P>HFhY=Flq z6t5i&dW(y54?no_z&)QiaM9kEyy(SOTzbVFU%LIo>EpRgA&R&;&QGDtrC+ycle7I1 zD}zM0DEG%+^#8OwD#f3O)!Ox~b4&9(_w6|N$mzTP^dH{%H81*_@Be@P`(M8PAD;G< zr_Qy5ellJ`v>m4{fmS71Dl&i|DU)1^xwbwFTUf*cm4H=zp29fu-O24uUcfz zj+|3Vfkc#?a=T%|9CoRiY0}gX5sk5d&$qs8 z<;(A=z1M%{%dNM&Szf1^Iq6k*-MMW02m5c{HBK|{xaHB+8};Yj`WtWf!Jq#1@B87O zpZw{y|MTgi4Sm+DcD)u)`qkIpdGe8m=l2}y^#|i7k&B@rqFBY85rPP_iMXX?nJL7` z5^Axqvo|x_tInjY@j+5 zy@fb;s9wBrVd1)k`HeLA$mug@N9#!v!ARAq%&UX~qOzEpWfLI~n<)J#y?_sZBFn zi3E2LnR;iiS6Gg4S6Gy24i#BV)+qIz2C6Os=GL_mZcN3|Cz}(Q73L}&S>BqLUZv8G z{p`CxdEhxO!TiN^#nWb=dgbU{UvkrmtKAFLTANnJrp!gW+geGkk^}_eRy8n{hNfiq zm7|Y|016#>lL&5vfY8!-gw4z7@{z9|_6OB9aCCPwWOK zHg9A*rRl6=lVF4Z1e_;pb#x?0nhIk&%_&cLStUod3nYgX+e+>r_y62yOzY3|DNP6O zQXPpLC6~m>fRqie2;4B}zw!zDuHQTJz_I3V%Rl|kpZ(+`M^=Fl>OQz=Rt?V19fjAu z~-4b=?+C zXUcBuBLxzXcFXq8N=qFeRFGa#(_y>Pc26i0vsqgvJ@-5{pP}u|#1sX#vSa}iJb*JO zmbc82JN&j=ZnMF?WO+|jWZnA<%A=Lx$$Rp6W%@dcOOtgkWje$Xh3zf4ySb;*emJ-g zy#aHw?ml;ONY^5mcP272sKx`XBJKA`0z|bHHB@3Je2U1ibK)TVFU!!NHZcV4oRqM>$VB!Ijal6%yTC~XS&8*P97}Jy9{j(+nktW@C#|X&P6(9`Sh6gnm_hVRP-|dnPY9y5mXr%`Cix{d(VZ zAU^N$Veh-z&)+_LbiG|et`ZduYL#gK*{~qJ(4@9a$yv#rsY0=Fj?m<}MI1zqaWrgC zT00p{kV4r}#sE}61>r(diNfUGvJ0ayMY~XMFl9~5GW~QH0Zr}}ROS$Y6VxC;-i}r& zMsW&r=SWq6CLgXMjsS)R_sSb=oqqV}V1DuPo&BpXURu~Qd~nH6-b-7jZM<3cS-Bz( zs6tN3Y*Ne#V1(jBZ?JBsTsDg8Q@w|qbEx24c*EOEPlq`WD3FV)6TvJq$h^2Cnrqf# zV#r-j>K*`?W#XWgwN;6%2F(x&M39o%oKij8-*feo-gD&S7k>23zxOj=_YJ@B`VaiY zU)=GTJD;@w+N);we{}2KFRmXxI^J5Ap_8xWa5-2~hNL1$S1mv8&w&{_@zgjwTuHtn3GK=$=qTkskNp_sm*n-3c}6Ag2>KYOZ|Efd-bii z-a45~uDkAF8~$KQD{ein)VyCy_7$H4X3Tl^crtp ze=i1e<92g>YjtsM$L#v<`yaadFaGAwe(q;}^3!j-M0F^jm;BtTRZn3xb*nZ!@b@tBb#L+;vhLqb5I~f!{bI~2(czWQx1ZD zTyV}whrRxuW0Qw}^__q8dtd)EpZ%9FJvuzLzqe~LSzT^g5mCOD~D&HHjiBsW6!kmoHn+Pc&ceXY}bv=`H+~x`3g{bN3?y1054kL24N#Xu1*1NA-eB8mXcX3$n z-!XGKj*pDaoR}P85u*&ah^P^RAa2>yvXElg*y&t$a3HLjh*l9n6urGBdR{e^^voilxzp-rSm66!K~w^5|@k|C!%6@Soq6kMic|}8S}lclX)g*O?G&aPC7OTnLwRiU^#%S z;O!Tj=-b=dB0<5n6B7Y!*5xI70WVEUy(8K#5S_siZ_m=+@uRxX3wVGDyAkE&fbJ4H zwAj1S`9+uPzv=3|_n%q&x1-CqoZHOEEY(1QyQ*d)5~rg0)q?7kYRAmkMZ0YoBB3SzHzR*P5excKzO zxf8>)fqE5c0*O}@MK}fKz|5f55;7=I)zA)?`6}LY?cS$;)q%Me_i+$QLl<4n~>BLZFzfWrXqpon}}- z-GtfQoVr*vVmP^Y2o%TOWMpE8=hm7^!u;&cZ2F12KDwG$VyNmWvfEgjiYdg}-62lw z*%C>}z!>9xC1Z@$vsAHdM#%;w^znN)PCu+qxxIhzrB(H0qHm<@uBrF^8-MA;lTSU8 z=QA@C0&3zu>K>D^5@{xFvxgYV4ut?RXLgAd6wPSVG|jo?=CFG|4i>|XI?lwJ&<84r zkT6Z$C&?VzCU;Pf=$_pvNFnN#36&fL=QJy)Vs=pIK0HByVt=DWV%_OCifbq`(HNe5 zJklUk^~tkm_031N?rpYCTw3khU6F@fhvt@c$dQNAk-I!^0;%c+*We^zfYg&yU`P-G zj4UN|+Ew;0Xh*xV-5e~;K?rVYWUdKiYt8{6iCk*1krka})>dr-1`tGKO8Ce*LpXrU zJrl9!)X^5)x<#xIz)2O_?7Z~g=Gx>{Kl|1n{F-O~&!77Cxqo@!OCS5hfy0Ym`^0Bl zUq9}B%Xi!{Ir2z82Wi2%WWHMRz$`+Ir`=(3)5afo^p;BphpxNm$qR#Bcdp)kdUzru z5fM`WTAOc96)a@_d23bKM62{hKy`3sX~vTW&)mBwAJd^ivKel zu7yZRg>g+85T((Bt6z*VvwLZOyF6^uWPWxjkdSekTPW9YKxD&4l8-n_2dE0En;S|9 zig&I&k(ouDiIcWj6Tzp|w``GNQ}}V(Y;BJh0)oP}=~$iTY?)0-n1Zl)XOs=*(5<11 zsv(r$?AToZip@g^frw1CM8`8rR+AX2*mr|@CTGj0Ddm(ytVUZ~%!N5jfTzjWktUO7 zb91d}Hl`UW<*Q3vBSLZJ+hz)%ucqh!J-r5x{o4LBbW^VXr#}J;NqGBoJpU)t2F1Ek zmbZWeR7i=c$aQU-Bd}2HISavw196ZLv*wF0I<&a7aCUW_8FjyoQDO|eUazX62vt>G zxZhP(NeEL#jF)YNqYHB`C6B?vqN*@gRdWx4Y0#UD#zacYnv@C*9jLCOdSE74JD9CQ z8{CMQ>VDOxl-ksrsc(AfjSGv5|MvEO`=_`4(?tgk?cB9vrr+P(+H_(RqttHCZA8u_ z4l++}oi{l!jRPr8{@XpqV?UPDW~20sPQ_b~0{Ht4^`o`z|!ry)3UElojuRfPf|JvJr z?*Tg|lnPzZOo;;vle_0ln>dk3WV41`Vt?T6gbZB8w7FHy?^rzexNmy-x4!*9{{7Y8 z_mhA7d#`OD_&{Cvdsp6+SC%s-h&=J$r#^J<$i5vnUbA!V`YV3t4?cF$*$>>X^!#Hh z?>X}RyRQA7o4pF-&HRjS*!?Sd!!Q2)tq(l(<)wpH_WO%%L+-H-Vo}@N6xp3{Ad$cv zCXL6IoKIvq8P8dUXt>nw)YcX<;`dA`$@%YGsS-nkH%M z^ycYPdhz3X7tPmkI8yD?Vl_Y8&aG=BA;8r%7o`}0Af~QnYDj9W6PyE)k%NV&yV{P3 z#OzeU=*)-|546xOu8CG@{&+I}t)TPqtM`NYBv zFQ&K{Z+d?3+PAiMuY_j6%02NxpM97O7Naz|J1qlKHi{(ky_rl{84jD2om>KUwvt7x zN89v&FudYw)s|23*}ZabN4sashE8zzV)^J(8l<|GGs+6(leTw%W$d#lI$A6wHEC0Y zexN#|VN&Z9@txSDaDACMt71TL-^60P!l&An;Nh791gI+v>@Qt{R3wOK^~I z=W+xuNNKS{?ucWZxC#!kWl;@kz|I1?8n z@O)Kr7^r1oy70v9zGr(yOXufROy~9Kzd#@5#eMo%Q@j(PDa+;p7y%s_ zseFK^8k=pX764qK!|7JF8~RJFaL?A+-@A8f(W&7Rb()i|I%8^o>R!wzx|9qF_vjk!>V`? zb}}JwfU{{Lf+M>bb%NOGrRX*b<#W}ktqZIW;0`tCtl1n{Em;DI2*Xv~*@%S9)l5q$ zYb8W5^%YUBD7p{FlN0VT*Waz$tHQ#<&iQ^88jlCAzMd3r+O3^!;_A*$ktA?PFfHsm zgaEI+x3$%t+gOhnz`5pL@SuQrh}^44%s|fL@dWEYvcB0fXZJqwMF$SOY~F8%FZNBk%}i|!{YvVT^UCCG<9Q|wq>7WA)LL@~ ziy3JyxC~{_QnWHHOWlJ_vKu4A$wc~Lu)*=mleF@YeASn#YhF0m^WUOfg{AMWp8uq3 z&)-UKBorJ*qNqUw=27;FVxQ5PwW=hXEvp-`u&|Jjc^)SQ`mqP2AUzflbV61L++7@5 zZQNw%+^D-Vi%=5VHlZb$ISB`ZoO8*RF;fzP7wcdFbElCdKYvU~)opOviE|mz% zppZp{VYxVucFA#IcP{ijGq{t3gxLUSmwFC$0-L6y`H;FV5;SGgpyP$@*95k1<(4*A9(alAG`CD_g>z+?0@Wd z!3VZ(fAiX>j^(w)d4X!pja%&1fdpziOie%5v%SI5@v-ImRvv%w%4h6*&LhhYJT$y- zEv>0%B6e>(TexmEcLFh2FoQRawzL)7?eT@j>wg(ooINCL9o>8+rA&%utBrL`WF*q) zSQ`x@nWY^k03mSGU@(|HcKXO&kKCGcB3;OePs^p(gmGTp%FDB1VbGhO2{V!~&ReR* zfZZJV0;OcxH-|A+?pwJfR?nK5omp94x4aan-xCs=w5b(|k^8-%;-sETEL)qsA#nMi z3$dCNA3IfxK`N;T%p}>9YDRZbPM6#u6rYKbV@}xKpcax9F1Yy}Boc%Ih*79_?jUi% zt)$m@!CKusnU)ccMO4ikF%*kW#k8mqC`cV+-L%=%LSPBZgq*FlNzQGkLNlJs%=RXe zVcQHPU~{;c^VnT4eDAhv4E8RRc#SYD( z4i@z0!qSew-VV=ra(Dnmx0WQLB?7fMU4G>iRaK3*Mp0s~R|&JQ#3~3gv$!M15bG!$ ziisov(jm%O&0N*gvZ|R{s3OI3Dd1`n#Ioj878{;ZN^ORr3L+uo*4w59 z8H1Q)(lqO2)rgyz_<}+XTYOI_M2#j$no$IS0zwFpi~v7u6J!I=2@p2I#x|ITZLoP{5cq*XfXP81 z1VShap&Uk&^Gwh5bh_Pr;|Y7ORaL(~);_me0{_nEqtK^s-?P(MtE#?fSLIyxZUM~Z zU$njkxg4?f`5TuF1Lhz{KWDH>yRor(VRiMu^5DoLPe1;XKmT(-`-}hO#^+vt_oqMo znmb>!eR3^&2pS&#^n=g))?2>h(ARw6%pXyjoIm^Yk%Pyce)fT3y$YtBbFnyfD^yZ8 zhZ%`T5Xsp=h_Pk~u3!>PGqb4(3G+`s^z%0#x$dhDzwFNIkFS2y^QZS+{Ei3yW9>C~ zVr4J~VHURzpl-GUs;WA6`9^N%0??C-z-*x~ppd+z7n^0vdb9A16N zl{*O=7u&nOVb6c0JAdHKA9(cfdyn0ClhBHS+!+KRNm<=lf&`%$*gFp)MB=XN)+dR% zibhc+=bT9`^(KYdX$SCid;@ygB(V*^GI0T7q8Rn`59U!=i_#}-_Pd3v?CkaoT>%zWN zqaN7en8sNr#OB6MMqEPYm|*5=p1}?mHxmg3GY7GV5V-gW_n@wqQAG(W_Uv0*I}eKF zJ=I>u?BZ<96%)gdyPN?9GRWK+WF#IWI83vbNE>no0+qW=Ueb}>Z63B}o%;nFi)oUq zL~dXrksPpt61tkR&4vxY&YfFNLv>fTC;=dY`}~^)=A^k|QBwm+@!id+gh!Dp@MNMw zv=o|w$o|7CHkoo=!-f|>a{tmlei%pY!tlDKFMYwe`~Pyb*>=oh0RUpUWHzsEr-Gi`FVG>E!`%O+ZHZ9);+9I;X*E@C9%0>Qr{bSZ-m2Kg6L{4t=vI`+#xX6bV;z6b1%(pu| z*X9cuJ46|-LS!Jg3m5#cc*Nv6>Zg|u+UH=~yp5UzuI_Ha!Q9;3x#WwH_ie`|pW3p> z%?HHfZcJ9>S#G2bGabQSuy63j7a#eSZ@MiF^aJmD@-6qQz2|(JV3A`*a3EV(!q@=> z7J!mD+=M6t?rc3wT_iwG;PNPrI~`OsAMy4rUcdYI=lBJC*)DmeEaTQU=?=Oqm-W)N zIPZ9=Z?@>~Zm&*|0_+r8`Mmfjn{+U;$_(VJTJ@VSL4#rl>eGj$AEc{>T|U%&4+5{ zecCD!3ptyqdmrZlA;&mOTVz3x)m?-Y}qvx17hw^(a6+5o}C%YeJD=g z0H*+E7J+zf+v!uaA8MQK#CA*ne-gxH~D-)v~44yTa&{41`wj&6$7 zdg}mF2o!_In(KlqN?@u1fCB=eAXQWa2!VvcAT$fZh0fXwv-62k9b!^TUF*zX3d{tg z+?6R-D7p_<1F`7TXA~qSC*vTM1thkqSQ7`E=ASq{d*b)=o%ao{dqcf&m)Mu#Ir|p$ z)2@ergayzl!W0x(+p_EjnOd4zmLO_Ym_iI8Cv}Y?F~q>tuv%z51`rowaDXrsrdKM$ zbtdwHy~D}Pvr{tUQlAqb!dku=EaX~faWEtIK6}}T!n|kfqnossf0|JgSOMY<$Vd}Z za1MkSFGTOo?L2vwj@^30Eq7MUBAvQ#Iz6j;F^0e_ak!YYOX{Q#VVlP6)*AMH|Le?5g_Jh2{iY z7BlUi9gwO+5?8YS_~Fyrn_u;VZ+qjHKKJ|IeAkf|-Fn|2zEd9bmmRz1>Tu|{C-3_3 ziSg(%*pWWko}MRWViv-chv?z`^b&4(5aJiPJn$?1uiO^J*sVt2uE zA_^kGT@5Y%PP4kpckvQKcKHkteOR1Qrb-7@Q*&%t7n)&ar4F7+IX86$cviAjrDATv zsb`;>=Iz~H#e1yLu30#K+$WhIoa7*s22y#0>{zLbSLNOE=ag*a!_V` z1R2};&zyPh(c$sHqgE%Y!+mgLrx>DICXbag0#4c)Sskls;;ij%A1K8(gFud)jR29r z%xt2R%v5`xu=P8Bc_1#^W-eJql&Xyj@1l@^g+++aJF+r!iP0!q50|twDv5YR1+M9n z2{fw+d0Cmw4IW|)A($%QEIkn>6U>YR1fNZIn!28h$J5C+iMQP(=c!q~Y(RYZuITe^ z1^w8!=OtgFG!q4<+*6b2(!aa>Y59A5*7*)rzFYJ0^QAjT^U=OLKyl!)f>anZR1JLN zX>YecgJR795@ce5hzsoI=icnVY}yW*I#v=yVpRo}SVa*IA;v0(D7&SfyA|W5AVFdf zA_7v@oHGDbBZ7ngWR9ZQRh5MzqNy27gaENF=d5bli>i}l1K=@=l``FpRDf>n+=Ye3 z;n#ir*X}#8|8M^G{gdf2%Z!?xh@3(Cd9~5yQ0u(0 z#e8Oxy<6Wpx3aW%|DGdTv-Yn(^sYzm{THwQ-Y8X_o3x%lg{J^q%~K z-}&Z`{6BwT)~#=!zGm-{VYAmg2d>I6R;^EFVFoh55+pEFtf_FKLI}>}o{2>*XUoHd zm2Q&1=Y2nV7q0(PQK^P+wU0Nx7dZQEbAnppNUWaoR|#eq#VHPnzMs^XB|n+ z7uy}}I$zjxYkU5~|MENk?GOIP?|t-hA34AF=|s7@^_xb|z1bIr2d-FcnV0IC&7N8B z4qdnS^>6+MtGa&2&8r^t?(h5Mm;C(q)Gs*b8@hF2_To3}`|05qf8W1-|2+>pc=Xt< z^~#E=!5zYZ#f)MkVPSSz;K1UhsHmOh8njSX3%S|KI}U(Rv6#(EbC*!FAdo@e9HqA9 z%2pR-wWuDFfu$Oanr*{hKDF`q=F?AfTa!wSJIWnAJ1e<@y|Zan?Q{Z|1a`~CD3eJz zGLn}uvTNyML#w9T%7Ra{dt|&;54^7B=SLZL_W+`&N1DQ#rGc-@}oh5G7`pPp>!DIzVkq!$ZAXMoKNg3KyT62zQc zbJ6k>2m-icSH8&P>M#wi0c_Nde;lHkVh}SGxCE_jJh}K7QC+*{0PjOhh>24_Q7lC) zgv0?bt2wy^?n6cxs6b0q70G9<)*)1NRl_HnlR?9w=D~1rdiH$!#D}V{z8x4gcRoKX zzq`B8d2Gr+FS69ZTXp8%{`H&YZ><-S4cIXk6jXNvCD>UJZ;z?E8>XFd~g2{hX6 zlnO{yDiQ(^e9+MHLO3v>gNABmYvc5^`FcPWP$nu9SSgSO5j)S5bD^Fb?!BIpeb<+y z2MTvZ4rNtyko9Z)%WLXAT@XDSJTc-ih%=q5W4Jy*25LvxeZtXxZT~pXs!9L(fPf@w|gpaSRNWOVQo+v5|hf=1Ni8@txTwtJcS zcX}Yg3c-7~)W9xz*p|Cr38$3^4KOjak;IBM~2PbmA!{G zUu^2CpR}0+q;8xoauiTPVjv(mNL>}qUIjEYH!vbp1D3#nAhp*}T7VwgyK1+%-e__a zBYD10*WW*R__LdzJh65GHmi_0PjoizCOa5sn87FA%#b*QpmnwhL$Y;&Dx#1z8zrG? z>JuP{cxMWyipmxhikQ~P%sso;90y_G8EzzCRDggZ5lQwkAP7rX;c8iF*6DOBuP0=6 zH%$dwR7DVB32s1$gQ`xs%bLm6jYKF0&z5F+N(h74m};kOl9VLR$ke16)~CAeFF$tS zc_)Xry=1iiH5J_oT1R=8_F<(pf^Ml1ox6F+-VH1fnT}K{OwA^c>xy zI%6=9Q(0_#A^?%61Yrc~)v!cJWu9dehajUy$CFc!pC0X5T8(y7x4vBasdne0L+65Ik$09Wt}GRaAk?xonGkaoTvH|&RV43rx{YMr?r@C&gDr&vuekZE5AQp2 z=HjU%o7X>c{_zuAk8QLUC+%iaFEAA~LaXV&!u>sc9UY``FGn&pBrbCiy(y}HJ=BR5e_(bK?bn9qj3AQ29+_}+VLVqMpOyDA4J6dEuQfkR+s3F2m5QZsXRRb{4}plW8GbM8{I z-W3{PcxS{U%t}<&sJ5?gfBKhx_ANjA->-k(b!(5Edg<+7{O~;|1`C6c4+yD3d zZ$X}2xN!3N<2T)N|EHG1h&Zch5wM!N6BmP`l$AJ?!A;IN=Z-){*C(+OkI81sd#+dx z`#*U4W0$-rV~Q)I zgVzpL532FutCoen?8%S(>3cr%@EgA6`~TO^zj=1{{=F~Ed!PTDEe@MoQ=6qh#M)-o z2WOj4&7ODNVBz9qH0@sUBmeL{k39P6fBBXd{_dOV!^_>)Z0q9ej@Rw`#padY_b>kT zN+b7n#^Eqa&;M!_#$(7gv&8p-^$VQo=Huokp z&+1IZOj4|XnVATstP`n5<+biimX@RDtVLy@>MTNl8WDMr z^2`HLxE$`i(w*G13Uk^og82$%jTLYqytoqC_W3{Q5A^> z&E(`>(iMbzuOD|;%>=1L+`P-yR1#bp;;597XQrM*3zAOHo*U~Tb0-5tn#Ij`eel4S zd^z^qLRZ`n53f$nZFH8lb7roz>jHwnSY23LRaFb=#t2T7HJ5mLGmNTcu^DYlChP6g zd$-dv`4s}l^9(y%s2Rc(lP6)a`JUo-$v&5Q;k~IR07St{!Qb1;md%2#@1HDtf;&S< zdc$)sL@_THyrhJ{j3T7L!jKj#jEEYdX5tse>0;~a;Bg?0Bqa(i6RRr|Gf}~b;RXDJ zIeSsVfz-96itc_&PvR`CIF*Tp&nMLi^fjK(TU^XtYMHFCYSqPw)ZF2LLXi5};ox81 zaqZXLx#x+UjX(Q^PyhC3&Oe-UQ`L=eR#o#dAufKvrKw@!?B)enfg4+X zYJnO6b5G#D9V=bv9K9&4Y-ULRe$R%n{;%fCb(o8A`oh)cH+9|yd%vj9A?b2hCFG|B z7GJgn*nDHyZTRP7X22oDRq5^kqj?-l&%bpo9cc-M1+W`9J3oN(i)^nTlkxzncBH{W9Ry=MS;Y2jO(7;dcegCEVBxd0s&P33^ze zFF}YIo>RAD)CdK42ha0w3Iqdpn30vist|*ugi|ZrylDRnC1e!@cLo>b8i9p{NXUuE zg-mEhyqPm?tebCb%F2~{ssp2@UO6zp0vxFJgypbkX{^Cm5Gh6%14jrTN|xOOQd1Qu zsB=IJ90t;a6h^7u%k_1ugBN|xHTjFwqdQyvO+5KqTOWJm*{5XMM(JR!=fr8-c6QRN z^%R37<>WJvH*o;coLSv#T8J^gX=XDgvIs1 z8Cgj_k0KnovpmhSC_>d>l3av&sk-NU`}iMC?)>D!t^atbc?0_a*nU6sy7;^;ADpCT zCbM<(CdBQGilu7e)Z3X;7PO|CO~6qiISGXTB6pDx)F}YbQA46s2th(;oC}9rM7Ro6 zcQ(t~87B``vUA*2)tH5dODej1f;utdvJ7h?DGzWzrs>H7Oy0M(Fa;6VKp>m?bmp?- zvp{t~-T3&~&7JXhX)jOn{v*e)Jbuf$NABKOdkoWwQrFKFS%`%^gczL2Gz*fsmcrWA zsDJ^MK?W+u-a>#wLFBH?b*vVMYPG2&!&@R)HVUFHM6nQ&OpQc{K(2kZX904JN?H}% z%NF43Ah0kDL_q>+r{4LYtF9kUw!Y)P{rMN)e&c`sS9jfU`^_Ky)4$sD2ws2ND~~T+ z`74`$^5E7}+k`>YxHypn2~J2E#KyuRl3btIJb7xPK73%$?fdRJw|(ZB>C-#iRzk~C zzN}eQ(VMPcdR>~vVs}X>W76G4NDV%y_RsR{(+_;+^*4RRp#ulnwQjxLF?e9E>uR+Q zo#n~aIH%OBjXod{fhm2uX^&#(>d9pz1JSvclEK2ueJ?)`?&FANrUSELBUv^V2{lNTQH&t1BY|fwPbhGz189S+Y4$;cjyX zHPK2n+?wr71Ju=$GfNeMXEk$g5xj1~pq9GM4SSt3!JH#^NyOrn%gYVR)0-zw=TjZc zLJ%PanX88Bu7Hu7=IokDsMHghyCN@OuV4hR;tb&iVeTs1;+eVYW=F5k;z(WIdV1s0 zeT!Et4UPs{$TlsWp2aJw*xiDh$edtW@RR7A0fprrn+AcstUu-;_)@H|s7I%^*EY4Y zg4we4%bo;h)vQzGMPVViN|uerPo(Ys$)^IY@>~P}Bk(1L#cqe@Oum2E>}%qM&529M zjLlX-aHg}HT{Jnm5^5PvA9`9p@y_t7W4^S1@y_F$4}9FZ#9Ue1R>Wdf2?dd4rAaQN z3nO=Pcj;eRG;8O$O8Kt(E8KAOCD>S1yg@G9*&R$X0VX+3Y9_jA*9GW%GmEs?2G z;_5*aOCcVY4;GfWSdn_58$v`10Bn8eTMyUuG_9W1+V7V0`_lVAF=)3N?3*Sykuxcr za&crwxMt6x1B-iSQ@wH|(@K8i&p-FU$DVx%978jTq^1f31uj@>kvf)vX`kK#Q0XI? zL5f{JEH7HHIpFI;R8@6V$2pyrN{_Y6a|Y%ELkdA^xU1&=xx0L@KJVPZ?!Gq%0LsAl z3&GXCqs5%x+XH!oK1OdIwsYC8dWm~o9x4iM?tN4S;nGL!HlgMH;O>{cDG=i528WfP zIh5oA2XPG5qIpX=zrFeRy_+8f1}sBDa2`@@khfho$rC)!`Fs750hnX)K7WgL8}~U% zggNe7KmebgOV9f+KiT&PrD8FYnyc8%rk$Cwgc4EI$Ns|AREUIvnHiZAmzi0qIn^>z z0D_r?V*253?iEX*;7aCPcr26!nkz|SW6yH&f=_8<50+<>BXFp@?5VCja%8+VK1~-- z>vm^dMOEhs&cz@!AXHqbo0$!GC=|%hWH}aw&pEK~rfc>byLEARS7kefMbH$J&vf@c zeC8Z?nW!~QoOX0J%c-N>xiTUPvC_7*b3Dqo6%VtE(#8$Ea z2|<~HM_4eY7MgVCU0us4yOlIQ7}}X8q>0bQm;h;0H@eAIM-vl+laRyI=OS*ql4krz#FG$ z-CjV~UsqrCQ2prp=z)7TPR!hlr4kV#)F7UjW&;HwV^Rqsl?Y`@GjEJVoy%7+x-dns zczHP8Ow}MER$NQHS?%#gqFaGG_J2%=SF)pBSw*p85=u(OyR8=ICN!LDg?$kn69b7rOXLR)B z_ERUvk99gh&&e)DlkZ|WxU|0X+?>Dr>X!)jO@C@D-_Q{jV!gVu5~$ux+uO5kW~qju zMx{gSOeXC#am~{-o3=ZE5+VUi)R`Wruf6%o+dAzuQ(X^cZHjfg>hMhmR*pXL^aBsB z-F>k=n?3zK2Ql9nb`e)1b{{{v^{F~mN0zRh<=L#A)m{(cAhm7RbycieZH0-P+`AYA z+L}{fr~!fCq`MD5Z_l6vW?^z8Vs=&}RmJCRvE?^n?ygkWzJ+{L+>YT+A&7`1Rlr50 z?^K1$9Hy$Hu(aBytRl=rSye>b-Fh{zm$=XvW3jX?Ja=NGWU9GpXf_+S?Uo|}W|#T* zeBmYQ2ggp18;{>`>vM1Zi@*Gf-M>RYb}0bjo_l@Hd=~w8f1`gvKl=Cmz-50;1mt#` z>k-!r?7=*kG@cw)Kc4n#p>*NsGKRHpP09Vn8?XG()A!wa=bdp-uRpaBLX0ugP3*1u zSWGnmYF0(AVvryqvL!b+Vpg?ceF$?2>`BY<yHq1%7>Yn1}!E}hP+FCM-1w_owEzW0-V@u6p`>Z*m6fvUS}RSTOz zjYLY(T?s=tcZr%f1s8&YGom} zJI|as)!L>+&+0^V5HWN0>_)XaS|$qdox+P(6(0$_uaB2c_Xc*vtD`jmZ>6wDgn+My^u_qh0To25|OcR8O?AB z0xcuC5-)B5GYf0pd~)q0-cDM?VALUz5M46173wiTgR8qb*BmSBTGPZ#ZmG~(pe3CI zM9$`xyNkX#MyJeL1W?q|m_4UV3Q`Mvy6q-@?ztR>G!UO8WTL_f>#3&hZcf>aK_&e& zn+Ad~Ytm5R@KSwfI5>A+va?2NM*N1}1ovW3Bog+1qN#suvWfhC4X?k1@e6)-h0$Xwk(E=~Y-NJL?& zITE#*PRA{Z%`b$4!pu5H@kuP56PG-#OHGmYY8`VWVs<#Rw6Mj&-aPN_jHO0Hk8_Gp zHR8ns;pnJZx|lDVvy~J#%9jcm_?Y-)Yo^$=$bo%~BAAjGIXa3}g zodkpsY6LT%x%ZX}MF;LBjIuOz0+ejC5=|$4#(TeJYCk&c$$V^ zLfi57x~B6d2RIKu=K4$);FhcRT|vW-pKH&y8|*wlQ?bl^>TVSeh@s>a25ezL<6g*( z%X?q=ykj@Nc0b(+tozpcw(VmWy?hw<$>@vuu8k|I`_4Uh@#1DXnbp=oHCW0Pxc5V^ zI1mOcTGiBQ3-^Gi?kN{0h8AGDjH#GNNkLY8Nnq|`rWVocsaK{t-OQ8L)68@LsFNq4 z#biCTnuUlVW8d!3PSH6`0wY69?gmSc+L_y|4hk_cNX-nI+7!c}sq50%mzZ2*HnXxU zs5u%op>f+vjDuliDW|SmB)#S8!3$rqvizb7=a4?2>vwx|9WT9s5Euvy z%T7*Wm?eu-j@8cT^N&7z4-pZ~5WI+EORZs=3V)<{*O)VNWz_XHq7sjuBw5J-O{XY5`}>>#pdFb=H|i< zmYj`y~LOiS*ce~hbOx9-0gZrAcQF9&cxYrwvz43 zMM?|9Emz*Yf91g1`uP~^P}M{Rpqptei?`hHq9aGHe(L_M4KpFW_R4F%>=j?O zwtjk+68a!na$-XC5_ve^F+acU{KA)i;q&r^AB%p#+6!6WDNipVO&yhoMR!IJ5LN2zr z(aqUYc1J%=XD?Q$h2SB9kl{iCaWe!7#m~70+;Y}Jl7%~0l@RA(T}obrTJ9i{$Q5Gh zvWGAnQ9GmQbh>x{@*Cdp^~bNj{;&S(Z4W*6z?DajFOL>CcD9IQmodOB?$%qYoAq(_ zJw#B-uQGF=-^w}2diijEUVHU_G}n#snf;4L_bl$+oa}ty;~)I+yFc^tfBv$!eb?L9 zH@2p2JN2v;ti#ivIQb2)|C;~tmp?kyi>J>&efaRTqv768rxlB4RT#O&s##bVx%+ss zLtH{IxukdZXF*1wY>7QHV`uyP$rBGByY{xH9{yOHw%0B`bzt?XuHEi@#-JhtAVT@> zYwkFRGqEt-^Y#hbc$VuCtfDX!ny?M?sf$madi?2qSIENRKY!zo{q!&Yn{UHU|MoBZ z`|Zd6aT!+-@M~{{@=mg z(GCCd%Th!6sjcyoTg~lzf9026`k%i4Gr#fIk9fRlb$JCDgSOajAA zfaO6m>skr|C7)W*Fpzq2P}ity8ELj|Hno(Pm;(ueA;VZNEH8|P!_(9Av%Enu5xZuO zQh}5#5jhDQW|kevtTiMd5+*ANkj@fN6sRH$N72TZxlj;}o0GPk<|`KVFD@@Vl-rBl z_A@&h(d)y*eOC^z9B)sjX&R+?sLj`HmZaGUAx1#6PTfjAr!%pex>Lb*;n3a$*t9ek z)oi;xd18YW>l^E8X=-QOTA*Me@ZO`?=c&sm#)T3W%mHsnf~)mZKXO8^VjF8Z(d`(K z7LBx_G|zA?T^@+QPBCm{y02Y3$_Ixs*u<8@cBOd56sVwz$_R5e-E1mABT_Rj4@ONB zV-=?T!)Gly2sBhoP7w(*VAn;+;``DC+~i`hV5N!&`~#t-g>86 z33qBjh%AmAMaVg8w-Tx$R~yd-Kq?b5bc=HA_r zhy-&3Uhij&MKoV<%(6Jx9KLk0k+YK$goq4U-1Py>+mpzMM1evG9)k?GeR5&v%%*Q7 z%t*AF8zKfqU?NcH9mJhWlpAv??wQNLZtig5MRwmGO!-I@`-MJ;=o0RL-fgI~8GYAB zr4*oY^P%Q29T4``gWHx?Uvb41`DxOY3{~~mPDv0)6WrP2N47i5}Et6nI|GC zwyV^8;vdTnR4eBfHX zdf$O*>u1}|i+OY6lXB+fDjphIsPkatazizG@y&;C`-)@LD{5Q`z2DBfbNyrQdVIP~ zw|?O0@z?Gf-Bw-o#^odTE*^RB=tK9Od?0PK$X4v!g-tCbC$5AOsdt(U7Nzp6$y4Q# zK;{-XCRZ3Ui9^k^7u#rtxwh)jf-~KE)s5F3-FN>}k3Dhbf+l3A)WHCNK!3j{ju~cK z*_B4s!j5h2iYhRq^?IH)Y&X~s~KztsDv8YIcFzJISW@z%H*oqOJY$V zpF>00EJ{?@q}?Fv;YRPgX?Vx$R;w2UT*UYt-Mt^&x$iU|I9R{PVD!@G z4UW8R=bn2fk6y^EMQuzZm9up2$w~wm4CIEaq!3{!04Fxn+~qVJ z@ZxA_vz;`~2^qnh09Q8y!%D0Pq=XVX%67`cE(bLA8AIO?N+a_LV>KXK((-mwe}se%t0Be&)gVf8zGRmH*}1Z+++5 zC;#}uhn{NBFJf^hjd>;^wM-O49jx<|br>6%uI-$J`)Fl(7)LXm_Qvb|w|=(>#x9X$ zUMGKEPjYEAh!kjfSglOAr%fD~S>Bm?MJvlol4))8;`VqufKkRP=CfIwHDPXHmyrVv zuiAfIh>bex*Z@>WaOUo0U8gIH2VZ>TXiJmxkDV!pWtSK1^CQA;=L%wQOWO~xf2_;n zLxXFB`__0XR&`U4rtR1P&gR0ANHqmi$+8HH%4m^ec3rlwQ?Ix{#}*j3H@iA*jgz!GAJ$-2UI=^caJdpvb$|Zgb6tH@pWJ~ z#XJD;(xy6peL?T^g|ADN3q)X_rz3ekW_8Omm_f{C5iE!mx{MHbxW^|oEv-5WW;;IF zLAQPL@#j2v--C+_E4M!PxjUQNmVIF~j3EfPYNAMhA&3lyP17`UQ4CBCB?VVFFy&-s zR@4S+Fw&Inex%r;`ckjX9 zcW-98b7AYuq19_v7MIVgJ^NF?_|t#<`@ePct|Om#&nK_F@`ei=>x1P%6XnrQKk~BY ze(|?`@pu2?`+vBbZJj*(+p?nFon$W++)XaR6?)oL|ma zq>0T!MhNvn?pQT*Waf^C&ch{37cjFpp1tW?{=@(H#UJ?AfBoNn;}?Hq`c9O)Y^rPi#h0Y*+57(4 zuRQ15zxt~0x#K5(>G}NTkNwVHJ+>6D9}Y$Zt1F6IK@jGgoD3mI?le^OfND_z1D!;K zy~E`NREtfe<~x(zY3{NDXqtL9G3|6PY6isF^V1s}XEx7tGBqd^97Q#$soD%ME|#;o zgLUSe!r1aeg^BzB`-S&)=GknnmpZ9BVd|H_`h@(G-s=-SL%2?&7)w6x^Q zxy`6Z8HyOZGS5k8B3v9u9BeufAviQ!Z>p^%u_lRbMw&pGD4P}ui9x!Kcj}du1J&X7 z{QA!9DXIuPB^dquq;$9(T-6v-4LxVe%H%{{F{7p;f;D!MEJRFBRvhFD<#ks{OU&-# zCd6i}+fHMqMwZsPjVhFG+{{QwdWesy=#Hq!_YB4i)@1b5xvlfTrzQqYhHRD`7K3V@ zPLi*HtKe9rlY08nx-oSw%p?c-D zx2-lS?|kSJJJV^1oXTazJlUg^;#4T9dFET=e1UmCq4pvIcBsvfHc;8`9KAOxmDbU7 zU)`7AS?-zxP~m`HvZ}eWsWJ9;CQqkx(eS4p%E4fhc4W zxDXQ+iA0a%kee2-4iu(YUnelc-TIX8dAQ5Gjxg`}o26T``6#qs1hczayFmP$<;5@E zx9|Erdt#P#q(6N4{!d+4KZj0G1!5F;GAct6I7qF(M5UoCye1|pS={Dx+bZt|jR3q? z^!U8%DHtTwbbB&clKS(SRqFdG%xx^@Q-0zeq}^3l&8v|)^JO0Ac=>Kw4!vLB3zVt^ z6v+hUTwl@*bC8qo0=q!(%+!x+0Ol}qkf#ZDafbri_Wvm-5FAb%z>OnAeg0!!l%j44 zmzdDfp92iV*wM@L2X}=RRKG)BLsme*!6D!Qh+$Kpbyv{tiS(#)UpJOYqwl6m@7iBj z^sFXlVg~_%BmnN3iZs`uJ=Spv(e7yl)RWZVuufY5fG`#BW1=1$pF;smSpc}^@`Q~C%4w_+j??>HU?3} z0#+8&!nIhsZU5?>UwUBa8>=O$U$aNvfA()4ef;b!OEq}%p+|3Azj*6s4qx^1 z#o?XRoyQMf@qv}U`rwHVpMG}D#zBPH#X=S8HY+GFLJ8RxrpO*pj7YfRk+Yg*W>z<) z{<)_DVw4@ub!O?@_Qe+;Id)sTVSVd??QJ5HSO*Xajv71;J?srDTXylRZjh(l7$T91 zSln2(#A`!X%t?sVGBXhcW->D&l!>o7Tyq_Vky)5Ri0&e&g7ZN0!9cfM74Lk(-osy3 z;}G&Q`NCgzAN=6O`!+N+3s0=ux!>)+=!xcT08lZSD(>QN1nTtw4p)OnKie{zuZ<<^a<_uZ$OW5qSM_8Fkp!-WSa}7vva%SM z%@QgiVpjtjESV<PFMfO z?|k4--~Z?@{kxaF{6)t<_j~UcKXm?UZhq-YM>qfG+4sC}^X>~dEjI%u#1LI6tGQdO zLe`eDFNY;2Jo4TwnjlVt6V4Ub-N@S0{}ST|MZtuhkeF$xpU+Roih zo_+S|vrhtGu+L>4pMO-`FFc^4uMvcfb{^XPj#MO(gzB*m`WeIF*!4BakrfvJlGJ36fl^da^5||lz*10BiOWjWK2>g57nmMlq zW>#^$>8hJ9*bYMRl<)7{-0qUx z4VEDUkwTtB3?z))A`JM7n^84-;vTGBpoJlFcmGpQe9c#U^|7M|AAIQ1!C+7~RfwUf zqeNliP=%(hhYJl0r!J|QgP5V3L8aOvVGu*J^?W&l69mGM-Mx4@Yt}OUb$4Qxz&R;| zn0muDX0~iBY^rdIl~4uz+Q%RM z$cO&=(=Ym`&wuc59+_Z!d3D4U*%wb#FF-{ITNpSkhQ;@@mM@!qB3%IJAtJIhPsXU~O0D;8x_XEFI8uKw;P&Sb_n z{EJs?uU-7p|N3iRyINiI`j`0L>0kWdPyXZM|0R6G)j$3VFJAePPyNB~J+ZTV)#Bb& z&VZ*N9zf<6hyWKO5)RB2s*3BW+AvfjYxXuP5#F}#IHzRPW~+yh)NHDwrdb@+6y0Qe zdU`HT+mzNlCKf_2I?t4Kral#Bz#R%wP@c=@d!#{x3zEe_+>up<8SHLwvl?7iGPM~A zA6=;q?}?++!{jZ6bWUeH)k9%*@8W))YQ5mYeqmF$BP=_yTC6;0B&?+{b$dvYvdqAN>;4l!=%KREW)% z+yhY%Qdnmg3q7>Cu^?PA4T1>4%uw>Fz)?^~j#a2)gLazkepFs{8Y|cGu>)}kOmd!d zB9T%Wuq+K@R?8IyrkR53YTV7H=9ICtu(;R^q%dfmBS-C9N>^8Ak)8sZ1Bqj{*`2av z>Zy+o1pqH5jtmA0D~k#ySLh8)!J&>^_-Xw!Ltv0;W{M(gy{9F)1)*BP0#OAJJey73 zW`+qNQ&}8|2oREng&}|`YiRcyv`Elc6?5NpkTsa^vOsi%&pv$vOE56#|o7eQg6YHoePV& zJeRviS+*R9S&#P3QR*@S02ct2Ah-FwbW6 zDA1_@0RR9=L_t(KA1~S*KJ2Y7!lnIi{zPA5VwOzaZNuCFevAVeT3L3;$F(oTZ`_j0z( zZ~>EB3umx64~UmR*>wuRpVhtp*s9}MO zzOVNA9$C`=n7qFifvSpYRZZ4TEho)@pl7RFLB&uW93nLrxS)J3Epm*7a+w|Gu}t60 z0f|!8sKms8irFF1(jmgh%@dd`+Rk*gHJ%(>*}urcp)YMx=c)@DufXt*!I78VamAsp zUc{^6o0$B1`}ALLeB{BW9+<9;2c9c56;B=OYtKG#YVD3kj@)|lfg@kKc<^gADj&Pv2hBQ(pCoI6HMu%w-EbT=jmLklvLk5W87Q znBI5#ktcuqR0J{Ci?T-?+M0Jji`-%cO`ROrw{JUcZ0%f_xm7_R)~3##VCb~<4hrgx z_7y32%oQ;+DCH~?g$1fzGBa)Bz!N*gSPvKhov_-$$afwa-gW)r)h`<0Ik1Us|5K%h1$_5dPX2ZGqDKa|zpOs^>L9oK!ncMyZ&|tKJ?*DIHu>z??x|Ut z6(2OCDu#hbB$3R9;wsR8V>A^}vt`dD6hh4E3PQ-!JQ?q_EoKNp$gcg~B|t8D28N0Wwf&?MpOofHIgNM99Um2!vh*n-!#RDrzH=8Yw#kh$x4)~_1X!`DzSo63AtxbR)>H)LRBx^blcGOM6$E5;U;d@5cjz)VQJo(^yyHz!fZeNh03fC6jO_o3`U_+zK%?$5@|# z_RQwaMPNQ5{d{Pzkc-I6RL-e){s$ov`LnZ!W;(lZ`PNahxV1Aev4zE^#jMLoDk-y9 z;h3x?hMS9!+kB4L4^QSZlEOGDXeSB5RjJ4i3-cnxP>3_d8;QYgkRYx`Bn4H_t|O5` zQ7OqQUhssnbQ`IugCQa$U{lNGE|_`ocG7GTL^Z2gRYz58)0E(8HgRw9cN_YCn=B9~ z%q=gOP!xcvozXlG;G468Z@hZoQ4vWJ!$OXAQ}TsJS<*ZZxQKJSZa%b;G`S|YT{gWU(-8xa-jDdQ+=^S905W~OQikeh3^u5EM9 znyoiy)_GCneaK|EH{dHl?|!O_FlKKA5#muAAjpza2dqFgJ*qA(1}x``!=gJow_6)mb z@lWqvkHhd)Kk)Ti=zi}%z2zIpzy240{5QY#yFc(Z0sJn9`R~Q zy4_t|3d@18N3b_GmMq7e*4^?fF4AJPFq-Xk4{E7G2o#gFAlfmT>9(RX>zJ~s$GWNF zD0NfI+bqG6EoG<9y>;t=WZuCu3zKu2O}DmBF7DCc-j^=S&h4y!m{`H(`!7W-(}$l+ zM9xYq)zEWtoe^_S(v$%^xuSH;4uTbfN$YiO-dD#UqJB|g5SwEo#L3;QRg`d3bqt*&aWD;4^qf*>9ghy5P%s37PNyx^zV4$WNh(}E|M3}ix9obT+={=wRWk) z-mm3OB^S%Psh_LRL}EecT)7nC=EMa;EPa$|ADM3G9hdsOZ;qoDmT<4A^sIf~h!A9f zX@L;Q-E3w)ai2O`h7vjV*eMAIa@TAjurNc-EE6*TVWK(XjD^cCQg$g2innzUua?a~ z&F2HqIfezFPg?tlvzPI{5D2E`h9S$rdf|o3D{s8@h8qqnyzhw|cbglhw>ygsSF5)h>VVe6N zu^o5^9)W6-6_C2l+!J{MDWD>w;qtYnIkgw(JLw$7M$d2WE4p&Bo?+BGlJ_QHgg$Lz zek00G=_FDUMfX(t;9Q(?=7QDIa)5{!<|c(O*Tc005U~_cq71!=gh_(4Ah1cGSWzHH zfCQE@SA!tHYaoiWOgZE9=H@uh8XD}krDfzB2Fouwe$Dl-JQiNhz90EB`SfpZeDo8~ z-ZNesS7}_6Ms%LDPmvKsW+Lx7_sqwiJ@c~1uX@1?4jz2j;ES){ck_pq-|>M*{`U0g zXLL)+m_rq+Y#Kxeo)Nkppt#)+6I~ES?8G<<87NGHiy){at6q5Bzca z;s*xL`O<3TrGgjG-fNoI+|u0qH{HiRxApM3$;K?Bu7ZRCg}@SOGN!uC{bQ;qxI}rj zqOeh5Xztn$ZI-snW9Q7mjHrg53pZ!|I~R<_0Wgb|&53$-3#b?;GhAS4J~eAd24Hqe z#N?LHhlQ5*N=XeOPK8&TNE(n3i3^GoBb7LIGq3~fWMxW5C76lS)riZC!rfg05u!N( zMkGO+7>CKTC095TaTUqo%z&F}|8ZavC(Lp?wHTq!y^Nii#8uUuq&UmPz$_Bo9Reao z`PP_Aj0LZAcU3KBw8UhpfN;R@*kRkZ@}uv0;H`iA@PGgI7r*S*e|q9=fBDgmfAUMN ze9p0jm7h5MXZN=ks=+dYB(f(}Q-Utm%S?2(J<)krNfSbyH1#V6UHb2N1w3EPF6%>f z7fpu&fjB&J`cr02Vy#EjVA@Q)15ghlV6)lG#TORqW??UdG-)U2+A`oPA`=7X=%K4t zR`!l3lZ9qLN#hEs-~4X@d9Sfvvy}^`?fn?w7A&()yF<4 z%ti!aSg}6{_2PbaonG8_=;vMS`7`l(03Y?86fTXF%Xqi!cb9d#KA(9@M5w?FZ;2dj zO9AMnzPO(RcHvocTRf1OCg(R#U3u{O7r*3X7dAE=-ZXWrV$)P2ED{DyQ`c4b<-+1{ zBbC6V`9zuK3)?(*T3yw8+grGsn`TwB-Y=t^T(MCrTI2$DNzdepwdBr;DO6n2ajeVQ zWnre8%!8_B?IznhtBZ@Te$6ZY`aSP{?|VN4ksvi-#DUz*Q3^ojV1-I&#k8+j*OY5k zB+CStLxEyGJ;!6QTWwr=6|(_D+Um}C-Qm@Ry&GFQAAaDYAN#=lFZ!+*oWJKRaku}# zqQu~xU06TA^}x<|eCI#;|K9gYV?Fuo=?AahetujSJaXdx<;A^&(SmSPH4vE^gP39S z0wV|q31FyM)>LR!1gPh#3Td`>@~O{Wb?vPW-Ftdt@>sJO_V2y&%=rh)h3vZwcJ4Dy z0oM>DX-6ckQve(*W`-rOd)E;Yg(^?h28%0;%{AZi4d3_+fA~jl{OnT5qUQWO^$ z+z^8-EjF4hWs9}M5YS(c6$aVxH%A`_q#2tg%K+eOSNQa<~b2D$3Z<ET>`6O=7hbwolt>pIZZc!n4#pi^yC$uNim zLzuV`2e<~7E@!|aOO!@f+T2a@tblnA6M}mp(P7-zb~{OT`pC>O&L`6HD9mHV$~d`j zGnjZ@vHQG(Eh~Zv)$Z=ZLRFB)oGiEIGti7YF=c>=VzHcIBH=#u!^J(9K4~Um3?OaVX*R}Mp)_m4hSi5~+qJS$J#484aFFAblu0t!lJ-z$f z#!r6cGatHmafT4N5{Sdqt!0xH^=ml5z0(#ERb-oXEZWmxR@d#Waj0ixUIi_Il+MSIv4_V#@LiyT* zs61-G{NY01MY?BL?ro5rV9tHnFsIhj?*DT)@6t>unWg#mSTu&l^Jz*^qm}T0z*2&@ zh(Hj7wrQ3T7-jt`#aW?L6$n=tAhi4Sa|1&Hht5>Vl6A?u&e{%Bm*mjGm*-HG zJOC27tD}!~=`k4tAP_?D^F~mI2wciY3YHw8s^-B8dC+d^-V(R&$t@Qt13Z9=PlJIJ z%FYThS3w+*tIsCxU2k^{Ct>6wFNqxL7#ea*=*++zooZobu1w2t2ZBnZ0R+V`t7sQp z3qPU{?~(|EW#bSG#udR61jJI*xy5OJK0hk!IaCp2Wp0`@#9*cpf;-IANVA)Q*b8?N z4&lHGN0(?=FWq$g*;D7f`RCsI)wdsg(?9&$>yAHr&)>ZJSX%sV`@i*PHsAK~jT01x zqk$;Ub*bh!8Z4a|pWM`Q25sUp%yUkc^9px|gO_ld&+7~?{ip*(w!ZlYOI*cGX02M* zoG7}Px`2t9L^b7khp}qSae)xg4cb`PDGRitH)8|WTzf`)TpCY+~L7|MQp#TZve0s9G*xtP7 zh4o-?aeck1n-IcuI*m;bqO4BE8Q)=UBGMCZ`Vk-rF<6wew^<_Ta|}ULyikhGra2L* z85c?oF^c=Jl#vaaWfn1aW_E|Ff_xXdGc%TcMRxO)(|oS#?q2p`ffIYq3FMYjr>RRV zi+6cuo&mpf!{)C`yDOZDZ@K2CJ74fZ2j`jY>`eCVS^bKydflf!`EmX&b^@{Vt2@{! zn1?V}0>$}67=8cQ@1B2ebG-XD6NC_Y*U{pD+7E!{HK1_?{)BKllhC*lUKv2us1X;z2z7OutH$~*{h2;`pC)Gep%>dX{^ zq?Q=GJ=t1bUi{kEf7KO7u6ob=-np@n+`X=Ap`fmX8BSa%Ai|-Tb(tyvrCwykRCGPP zT&kZ+(C1(4%ddVZJv*ChPcI%^ymIg2>ZuE7|G)qJ8^88z|KqwZy7B1`K6A}A*PcJQ zJ*Wq(gXIU_{i&DS`HFx2>VNZNfAyxxWb3g<@BNZjy!Nl(@yDa(Mb%l`WiyR2q-mxg zB0_|ma_1_7rmjFVolQ+Mi2zVlcXv@Dzi|HX5TvS?yVf*$f>U!V7N|KZ5XsPC^+M3R`+Q~%Q4Rqt2FN`m4bf>elu2w*O(|*YZoPtnN zRpJmzUDfj>`!%ElUmBpMijuoy#MBJxk$|*wHQsEuGP)FSKHFz5o;^BR-8WdgYH|PR z^%EM~B5aPo0KDu${4D3bZ!+>|+aGvqpRFSbXiv7T)vFg_AACDh4i6 znl@{4OR3f5Ag(Bes%o=>8O)@H&W%liWa|Y5!VGdFD>!Az7V6M-m@SYryfV>?o$W9a zQ4z=*1KG@=Wl-psSr2+&KzR>Vl{8Ir=6az%q?*Rv7KxZ9^_h7xPXYs3;7D*YB`Sn& z780m2Qy?}|X0Ak1RyP%nMC4lh)?AAppcR8(&wbLY(>%)!jzDbC-B^-2;8}LFva|+s zGt&j)1F?DWfh%8m)in+B{adI0;^D{d?Y01l+%ya;Uev{-%$+FA*TCXej55+O7;|Z9 zZO#)$>0^5zW1o|+%2&%XiXANNvXTj*;BB-JuD(s_PKzq$8qO9WB+LGx=;E1 zN8kXtd${a}3P_w#RNB3FZa*W1XQF~%z#UZWkNa=Z^`~t7Wa-Z5KU`*+?s3e| zZr8x6z#tJ0w{8y5_Wu+PN3rUf!>^Yit+d;?UOGJ6-EZ7`C31gLiQ(4!0{0r()~$nA z@CDEiJRpv4Q&&&j2GB9_r5K*xAPYSdFlQ8%+R6cv*z1%$_u4S(&$ytZ?j?V6swRR^ zSm#~XuEq9+kk8b|%EJ z7LAyU#}a1@3L!kI7vA#GkAKmlSAE4-T(S4n!xwz_o|`_j=g#7~;NT(FgQbQSYHMuES7!01!RWO&9eCN7 zF3}eOHRI{`*Z*B1r&+)D(tLL9PfQA($X?5SHXQ zX-i^c=9XPEM<5%(B(YSM6a&0$+Xg2RvI51KyE_MhGn^$v3YC>0EHe;Cn3JoL7A->_xB@aiA^ zpP&ByKfM1#?RZQQ1Ic2u((3Gjp2-9I6v8pp{C%ea|$FTscVhZ;lrw48ZL^&vPvb(t6|Un)qQncv7xTx;VTcU z9$ebl*&Z&)O)t3m_;arqHN%Jg>%AAZE|7qkz2w04z=QR2{W-knZd{Zt^EI3RCxb(X zw({wRE`02&mFI*(oV44+dL)5+$_a>s$}EM5dkqkCAp+#ArkO~%NAPq$3ZxQ8$i1T@ zaUn@^i7zM6JTAflkr$9o%_T%)xO(x?-lbF(YFE($IKy*RI7{!pUx-Pnx#t~`o3`er zn#|q*|Ahecb6f`9a`laOJ^#fahHjEArNvSGy07~3Yj3>f{KYd>tdl7-n?)}^VGzw- zq-ClWy`A;H=@N|VmpdT#@cVqg+{cwun76kC?=hxJ?{LG_$V27i&=zj&YN@0B*Ym++ ze*OYC=503+Y);m%zw(B!{|B!>bNY1Zy45{ zXVsikHK(km<-uSUVk+&bQ;Cv*dHKqkBao{yQ3w^AsyY#ih!*=MHdh4UPIWeG%O2KL zf!JG+X(DrBY6i7LnT=)b^u>BOe(r5I9y+-9qaXd`-S>ZNV{nQd*7RY zTv*CDtEZ~D5rsay;gW+TcI8Z8@G>|NXY1C-Yx@U>RtGB=w>RJSnGf9k;isPS4L7dc zf68RG@6fVjidFUa6DKabfBReB_ziD)_gi-CsZ(bjx$Su`yY==vAGrVSs;WaEk;*LB zRaMB{yo>*2O_D{}R3!v14R&94K*Zg2?abrD(Mn1Uv^#VD{$q!4-@kl(ZSxtShC?vR zz?@1))H4v_1Y=~NBO>=C;vkqM21(O&Gfect!hstGw)Mu>|HHTb#h;!z`^<;m`PT9M z?^qrk#goQ5^%N@%GMOwRvXK|Mwq1F*!f}#vgg(yN3KL|MFMg_?9=l>Hqnq zAN!AAH~jIXFa3pog{r#ph5LT?f4}&@{Lp7V^@-Da_FNU4CQn=Bp1fV`S(d87LRAl? zKC-;9e?idY!C;_H7m{t*^h~hV`CkA?vimELnC_4@woy829fyy7Fv&)5?`sF6?`9dhoP9 zZO9hVmYoTXrD_kziOo}H3k%KCs2R51POB4lk}FfA6gULaJe^#yJO=e>ClSFDF0nP| zW7EExw)wh|IjHCSbob=d*gvFZ-M1?dhNv1bxoMG88j(9HiNYmXhN$Oc5;F-)%31|U z@J_vQ>WFrx`Qmm?W34HW#p#I)3ma#!TGO4c+;`V|w$Gl(444Tc3Tmf13K3dW?^i_* zDNLAc&Nd^q%BjE+d`mOR2XhE_I5zmXT{ejJ&i50>wa~@0EPF zM%b-;%5z6VQi%lVrABiPHyu;(00@AP6jR<{HidVD z-3fS^NtF=SOQ1ZcK&<70Ib2lYo|7jbX_#5dg)HAXt`SBEamF3x1*1I&>*Fuod+-hW?3E62 z+>NupvHkJ4pZVC<+08KZ+GpN|NS?DM%Vrj`!X(PHo29HK~=b%ACq?+Ijhpn_V(`>|qV7cIT z0H_L8$_WsHz{#CmnOp+Za7l)NM1YcYIVWe-%nr-Y$T1*@v1(!|2@CzEAc5S2Wdx}K zH_s^HNhcnVe;yE@jvv5D@`WA*;c%nL5BhVkOWncLt%N)&rP{z_4N#U=D?) zVig0aK@pn!or!waU>Fy^EJ^L^(AFjwRUkon{c7g2q&8-N3yyB1ofs~I$BEj%WPwOUPSF!Ir&EM}q^rItHl&(M@-np;SA%MJs(75id@ zp7s(VVP1z4u>?1DD6yDYSwDzFh&7=iiMb;sQ_~Oy?(hsJRqYMgoqF&skXtEd$^eXE zWDXHRh7ymiz7|va<@Y@L8}C2yeP4C^^N)wK7cTzb7yZzS|M1;E^S8fvVsd^-4%Aq9 zVsii3wg_Cy5JuC!55eUt>ZSjkt4}WHi|kTZ=irZujg|)cH#f#cwtQe|e7@@)y?OG95n*l}oS3C+XIWFu9msmwSkKPF7rcBvbH47#H7~mBCBh+h2}boWe%WhY z_53?;zj$u#@Uf#SODktL&NBiifGbFFEl22axTk9`^kY`P^k`iEVV4gzh@{wxq4(q< zK+3#%cPdIQTrENdAb}Zj5@FBDEz0s04#IeoIRR}q-Bz_X{owcS-M9aq&plYzO;gvy z;jpf%x~iH%4fousllLURxfi#aW!Ic@A>)S-T+nMVi?GEUmkx>Mg+v*IUv6|+RwM^X zWPCqF4>3se)TXwZm7$UZsT#Mjshb2gCkZlKTr}9ZGi%%1n=g6UozJ=H=6AgF?N6V6 zobrG}X;vLnlc4l6G;d~!9X8gj?VYWCqa%BVd!JrA z^DDpk)?fUe|M}?i4xRbb+D+HpwsCTcC@`vrK6CdgUi&5g{EPqjkAL9%X5+29Kl9-) z`O>d?=z)hcS!{;W$(UoP1~GSO*3F0!LU2!}-cF|y#Nlp6fh{=;33JYw$jsD`6r;iD z(0Jo1B0qWhv$tONCElg;(^D+V?$Df3@}4lVzOAAZSq z{a+t__DLG-8NoZBNoW??YfTxjrG=rnH5@%-JheeZTh^W1%qM5l3%W6(X&bcj)JgKF zmQ@o5gVC^Fob627Y3E>yy>ULchMO0;U;+D$$c+dr0)=HG4%7=oBT!|tlsBidErS(( zn>$<;Y+HQ(q3y>d$*5VrdT{l|_WG9Ygxb5jb+I!aSi=KnPstmpj;!(@ZV z$+H>E98An1Sq7Yh-AzjpwFC!DojDN0UCo#%&$^9`jb~Pl-Mr`UU1v_5Li;T0Qg7Q_ zB1T|FiLlNSo3iCZvIrsMnWl-mQLK8DLyaIsMc#iYP^|cE9w3t4++88=p?hll=-|Yx z0*R@sI5~sN6i&=yuIj1~;t+|nZ4DMAR!pwuLPkig2%$@PtA#|*A#P6EY+Z0i6+naS zb33aKJT6zaXs%eg^EmzW6Esak6?b_+VY#VWPpNC82$-z%)G0BOBdfU(5d}h4OKeWA zZe|{WU_Q@u&kk}zYvZYIHNFThc`)WE1+_EvUbyB(j#T1gv&G7PzU=d{+rfp>`IZf)pF8wFP4j+N=knU}FAHQGQ&Ot; zfd{Z@8P4}b*&L$mQQo=0*)Iv5eco-BnAW-G6Z27iT&`A*r>!S!c9#01D8qqyauHp2 z8f8MzckF!$(9fj+XYTud1c$+l3KO5mVdM##+z1qb%4w0MCK56QW%stvBMI{s|Uj2=N~=r)hqrwu|v*JVEm`);a@xd zu7@5u8Bz+|aY9Vfu9GPb22~}}&bm%Bgp^Xp?Kn+4)j=J=ywi1+$3Ye95FSVy4}anV zFMsUD*T3qD>?A-<{5!L_!tC;YtwH@K_0hx~#3kswgp3 zf!fa1l?lvJkp`v)h=eGpoWwzO6YCYBMT}M@lE7Iwu!lgEq7bmlEg&LxVgeB=qELtk z>N#)}s_Vh93XKv+t}L5Qjnnjw;ht~4<=Wd`-_Z4LYuNgr-FMIIlh2GVLO+X6LUiE5*ApM#E_pFFQp^!c;EG^ax zdos%u1e>}UMfThR0I?HP6ZcDW6)?DJ@$gq%d*gEt?tS3=&R;z8*r{{@lyYvfx6T=+ z<$i&va2lD&a#2B)NpMdCA?mH;dh$uX0!I!FdBqeFd$Emy-IXJ!l*)!LC6v$~8Cq`rF^~ zxwVszOwVlDI)Mc|te1i0i~X{Vzs@TG&J z@nklc%tFm=b5E;dooxV4pFUd ztQjCYG+JQ?K?uVbgWB1Y&P$o)_RBqd4jNyY_|10YHg9LSP!VAqnKvTLpAC6|MM`2S<; zzvC^-uJTay8)MA5*4lfYR5@4YQg=)0Zb{wBnIuFI2oTBF2*kAw+;<)BlkIoyYivIZ zesZ`Z+p-N86O2I!0Rl;Y0*b91TOF!XbyrTOPTXOwIma09kGb}#0&{--YgL!_*=O%{ z_8N1H@ug7gC!ng%Q0?s)L5MLBh)J_*8F$NZT0wzH$jY(>bfeFk^ZtMha={+Lmd<>W4bn7zl>{*EFBE{4i1h^ zbkniUVj1JHuEKZM(unY`(eC{#hcCA0+IA)qnJjBI4rmc5)I4t{zwjU=p&@-EwkNL?CA3 zNMX5(1kKs9Ym|`TfxI=H8f_`ah%{ed5+;S=v^k`yfc; zJY-&|q5|Wh-V!!=>ZN}KBDMknfdHcbn?Pj09&*fO&FYMubWk=&&KP$dBUOyx)G>O$ z9|8$Qquh@neUat))F9q-#3HC>uiSh(z34u3WR$Bw^W($&*}rT*9nLIpV}O~(!RA5~ zoSDGxg`cMG63Nw7bI^9B!jY9-GsrWWv$Zx^|Kz<}0rj~$RvZ_=!~lvc1VqLQbzO&M zp{-vyI^Z(UiOjJT{yl;AL z1a+_LuX+sEi)L;uh87u6t%Fel5-A#f=3EW1IH7XDO351QA!wH9Q(2mmx?awwD)1`(CoL`@0w7 zH#fKyvZd$M#m2FSfH;3ymGyRJ-H~LkJ}7)_Ec)v6*&3I-M#hS6s~yT%y$U zh1GoKeVZ?Oa&YUb>cPu|ZpYxw@$Lu0OLA%>HxnGivk14`$~ zEF?z3wYdD1DGxxQ(U$owS`3K0Aj_~Zps)-wl&C zANtha`S?5jUw{9Hzxl@>`@Mg4VfrlK1gUw@@Z!eog55Z;_EmL<*f}rg*Gp92CEuvx z09+(YrsLD6&rZiP0n@TCt_){gGE*T^H8tcmt6A#0TACmg=4(qLuDA*uNx6wt6uI{7 zTGk1XP1nb}k1W+KF0Eb#V7XpcdH$>&k2fzy*~c7I*LRMD`AJb$1wH>|F7YX~ycism zH{nyPU2Z!jU#j<+=e~xUnK`o)^=9x^kn+NXBJ=DbA##-|xqI=S3v~teoH`IRYpf$N zBkxdkoTwON&aY!(eCEWVC(XJ$3lk86Xg1Bc^n@jgQFG$RaF`i!aWhqR&6?bEkG9=_ zeD0iN*PRU98;LJ^{)-ky3)(3X4TghPy!Mr^c{&%-o>hsN3-iY#CXMRz#RsO__F!!oxNq>?US}$TwYpVzjpGokKX;`&wK0rKlYzK z`_IYc^I!PLx4-d+tIrRn<4HY;UDv5+E=?j++qPv2C^j%A$ao;OG{0G1Cs&D&_zxfZ|@gM%#+b%u!*+cQbtA6tB$4(sHI6s-$ z^x{*i8yBD0eERBFXX_t*>WTGp7iJeO0*=Y$|Nff+Xaq<0H;ae&E?s)xgC}k|ch3us zf72TdzWlpS-2Ad*-MRMP|J^Tt@)OT6AC!79nt<7q%av&bLVwX13451Y!O_q~Ila*>||Kfr1bbNOGY@26ZsK*eZ zKpfpbkRVWOx?IRMR-D_2gjhXmA8A>< zl1WYbt#41F_Exurhmi-8LuW0~Jkkawnxkh{7#v`7(Q@k-muV7ra;W(f$PQzg<8-cb zYup|iG`JKuEhmSEA~{e9p(=KQ=0Y5Vg`D6KYNjxAn;ct``;YExvwZE!v;r!TRx{?X zXZa~iWI)-qdf82D5-5R}hC+ubjHJ2@`IFIGfJ>4j2%>er0GL zwQ9vGVn^xd?rSQ`p?7Vg-p84UIlwxzgpQOe@Q`E(u3TsE8TvF5qd6#2vgX`6;!uoaxG3D` z(&Qq>Yo}M|?J0v;SZc%>+ElWMq3TX>Q*tW2h9Yxi;Xt53?Cz?{97Ti*aSb4bA*m-r zB32?WoS;-WYPf@=?z<%}{=nhzqeH*Ved7KVo4kAa=)10b;mnmaVUu8_#JW;fQFSY8 z@(IMIDVyum+YEyk+`2qNFlgcPk~0}2r8c2cMxw51T3S7n?AUArlQEGTO|pkgS?5CC{KB5(pJ@%~TVGfJV3m z2_Z1Y(1jI*2dT(>h(#u|@J=)7)lGW|@fRUNizm zvRp?fXQ;VL%8tfoMB7FjMn^%c)ppYre3vl0}ml9rFy}~96CUNKvCZMV!rL`x` zT4WUEMHF2tK~%H5nQD2QyXTaccXU9#UxmAyDKk80X6ZLRB@?>;1FoNd{jY3pXWUDM z$lL??xwky$=+PrNB`89O54_^VFMat-C*zHFHXbc6NtB$@H+{ove&HAYBb-9j02S1% zZ;;%wS4)Sx@fGM8L~sTdv&sI0-$T4Kx9gwVUG&=x%i!L@5X2NmVYnB~vU7wPg}@G& zdTeCz7#8;VbQ3ft-HMaTo8xOg{{27vy4Sz{sVAP&oR8jgc;A8Du?ppUEK+1I0jj;_ zm4(115UB4C%PL~N5g?)v1d!s#WbSHS#@IQzpkI^|5ed1OspXu@7DLrs69Cno2j0#S z9HHXHFp8m?PP^1~5<Z}`Sf$Dv8I`28>ANlL>`i&U(jb9F+wf6G#+`?dKWwfw5-T3(D zKDzn%-#+#&x19dsCsLh8E0wwJ-Lq%=+GaQ@Z~dVk{MFCBQ@CB<*5)VI zzwn*AzU`%lU-Oys4>Ii%G3JUmfB{z&Ct(qGW45db9+(<;up|+5TbtEzST(!rT?c0! z;(-H#;XnU-zxJ6`*mH{5k_&r;l1ApjLrb-KP04-Vh@_imqD`}*e|KVyqW zWU!Q(lR(5xU^VBUx!kX+?&{*ia4trJWUAxsEoL?Yu~5iB;o|@$XFN7$?3&8f#ycjC z!=+t=YGKw*y4i;5O!Jh3kvN$%n5|g;G02IFZJaUF4AU*%O1`HuU*e_x_2DjWC0!%K zQnUNW(#^6Rc7?@eAg4B;J~zHd6-TKwfw>Z4qM&4814N98I~Q{^rsSNBl6xX%m=jBn zFI5$6x_<7n<7=Cm))*seBM?HxkS(!P{&D z;XzYrR`u*$Wkzy0x9yz8EYxApz~R}r9*)LW#`eh9`N#|Gz%6_3zxB#jKj%sFMHih?cju(DC|@q7vEWmYSR z_XUC?5~7;jvZo&OE0)RL15r$Y5C8*dsR=wEWlEz@#R{0f;J^?-+$*9e>}~=QqDn~I zkfxP(D>a6-ELZW3uR3;U_rm}4fybV?*2U4T$R3^Cq26-38H4^S-ic2>$?XB zHjC7MIXb^`~1`sG~N2TOqU3Eu8g zw*YP3Dw3Kw0zx3q$_ldsb4~+l1TKY*FBV?Bu<{Eh@T!0adK&33 z(#7B2c=&VI&QaG@jccCd>9&o*LAiumk^|G+vGCsIm7x#MY@J6|Dmek-<~dsiz^H^U zo^Gw@brKe-LKTDM3Gm+ShaUgE3*Ys{dtUurNB4Y7egD7M`@#?I{lFie`M}qox{$Xf z@IYLd=A>>FiD#V|;D{lxDk(yc8deF{f(9&}r)q025EoXm1D|0L!>@SM6rakFd&b8>*;Y;Mdz zc7;&0L^335UAMfQp>0t`6mh;(-nIRW;D8VeeK1wdAcZU1smDMPJR3;BHL4Y^N8WC` zuEC~`TO`#$%dr~Jyp*DM=peg{C2z6KEP+PKo#VG-0k?Bk#R89?M%fcaq$eN5waso=k zV-a?l5i{48)c`Pi(bTCKKmvD`D6ZscB*G-FOaPG(f~{}-#P`0WJ-hj#-}}?p)tRmY z8A>HjbdN+|SgCH}3T->duCwXo&L;DM={pt!ena0|O5}XGIInsAjDnrgH^6uGe zy1g~tyK7fF(RSKZ6*o=OZg(Xo!~s*wGarqHi`6pv;|;T}&6XlqSlroW9!3%*#7LTi zAZu%D>D=+5;FmWX7)5~CzkH(JxbVg*POWWUot=$b z1*wu2aF9$DA%NV}O51I23^F1%QdO7&VsIulc+SatM+p#Ib0(Mh_)(U3g$L-G677T= zmG!A(H$;hbJc;W6iIFfmRq0k>fx{dwICaxw2$17ZJ~H>b$To z9JoDY_swRi4=$B7ud<@Lw`j`@MV* zt-7M5LBI-N*(0u|s;bJR-?09bI_AAcQ4gE-uEM>;bN|R4!IGJiI5Fp}?WEJ>Rb4GE zjV5E6j%S(^3!B+=tK*7Z^ZHlVpXcBF@4xdcZ}{f#dgBlO(fi&#o^8i!q2wBpu)CWY z6NM0&c-kg4>zkq-{p$SndA}{_I~3pH4_t4C`u{QLTE04&jYorB3)RxevrqrlyWank zKmGlCj_${l!KXzV?-mf5R)^B2-VN zIWKw%gtquL-0?zL~+%r%*6UV9BaxN_}*Kr*<8v#tB2qQtQM32N;-R}n`wnfa zuea0H!HIkA^pn5$?oWT`5B<>R{`3z|o&4AnpZIl$iV#c12w~6|HzkdGSPk|cx%HlV zUU2^{_rCHKcOBce>+s%v%}t9o3SiD^o(-+HlU6sc;p*z%yY~OoKfb5_`Nux``vh-O96Vp$u_XBL*`CoR^vas3r=Hse>c2+N=c< z!3ib$lgPDfq1;h+hdsp0A%wZcIUF!>tM|hjMBQTuW-g9Sb$vFi zh820S_(HM-Ag4SC*lb%!7z&n*;3UivhTZnK{oKjHt5;DSTYB+xN5B7t_Hs*zHC53w zs}2LFWX{qR?+s$JZ06cqBAL!HYR?LXv-uA7W`1@lkX_XhTxu-Md?R7XUV=IMfC2#K z9Jpqx%*81I3GVLMUC~bw1_bmD0^%?RxvPOn_)mZk0fqpM!o}%9fGP;V%`6H)^hX zcU?I3g^N$FuU;htD%^3NSGH2YdcSAP4=>-D(5~0z9W1m!$8&rYCCb#zokeP*iVMZ1 z1Q)ovC-mM+n9opJlHmzEeC9G_xxunpBo5^V_RZv6(b?m)J&WrG{p$7YVHqHIM%f!t z)*Jr#SIzTw7*q2-`{e2M5B~zXNsnG$mw1AD1?>%oKmi$UoF$2R7Su9(H0ghmd@ zz5yy7+630Qjfn!nz)_J5i5k->ymKhI&T*3RJMTMHpHJ^)k}hiwpf_@By-R>XiAtCx z&qrJ(urrw(L5j0o%@GbEk^UYrbBn_4rk0dKrevhq65t@O;Po=F1TgXo7-sZv;xA({t;d;sT*_$JArm00f(PB8y_koWw(&kUHTZYic}c2a7_qMVMOCV5+^xLFWK@nSoT1HJrYUaicB0) z*n~mqj6hToge8=4`B+sJK!_F93pU)7n|tfgo9;Ps-}f!!d6=E{wLfn^@Tqg}KX>*S zYP%uv0GemSK^c;GC|D6KGRGy1!GdRS!Wg1p_Yl; z#mkyL)*XG658o5&*NMHxvClaOZo=R&$Hz#`h*^TL85r4f@?4T!tfYAm!^(~;aJ?M% z9#*%!ehNB+C@jGY_0UsCKA{04B~P>Kw_3SXV?YpOFY&D)rWgQrbp(MoR5zf2yye|C z$U!A4naQJjW^P^GrGZ5XLNstq;0QBtAgP%n0Fp=+N#a#azw*Ur-}C6;%=k)J7#Ym9 zrC2km<*uI)OAL*O=S<8TYUaoR1UEMp2C*9jijgZflw>4lW)8h193m1#Si3gQI;Er( zi~%=v&txb;~iEsY4L+}1)zqoJzo~8DxZ(n9b z41+-&iq#UBU@32HZk}^YZO1pSZ_?-6y6dI2Pwl!+H^IDiV_y15DWnb?s8clvAqHmY z+B_T#nkG(jEz>C(;9wCmi#*u1u)oZKAk1{qrYVC%2(bzhnHg0h1ed_gpxT_~lodc- z)$Me3s$L;P%Gp=l+uq;sI&I1Uw(B-O=vTAa$9yw0q<1?iq}^@ZxH3JvuQ?W?WOH(M zSHDgVHfF$~ZcKzAFeid)HZl@M@u>7dNi~8O9!p7GCj&E!NdK9DYwF4kQOx^GuwEHb zOBq&ESmDMI6P!uSdttX_Ch13TCUS|fQT42O{tF`(u0l=jSrve}4PtZ8UH2?6FQr+R zIzMv!@T*_az)i<~@CU!^U;OO9acd<;h;%7)5OO8BcGGI< zK$>iMcNLzQ*-1d+=1kNF4*;M(17Lola~ZfmjJlFApn8d$Wl%-L!d9*liEy)v_nxq3 z5!1~W+c3MFH=b!K{+XZuzi+kD}$AC#K?jG}l*h2%=h&jZCwd8rU zQckI=tEO(ccBY!=*$icQG0!C_OLp8ap!yAW^No!Wd1u{rx3PQaz@E{rC$DY)(TCsn zd;9h2*(PkrDSA99>tzZi^Rob%}Xp+2m~;Bkf1qHiHt5?mNQeu zutLO8OS8!}zzvzi2_+E4KnN5XwPhbvv02sehE5R+zs($~LD%vc<@%uTB6dfvhSkzk z)>B9q*VZ>zHy+q`;_;`hoW8mmcUx=*i84qka)2~zDJ>`wU!JX4)>34Sj6@!&_diFk zI4JGA7<>w$=EyzOpxZcoQKypshpd=5l88H@3hQm&8+;@SSGt+G1tC{UZh=XdU9Cv%8j-zq zMeeG(b6pZzT3VRSrjwkrSvf|Cdb^FR|?>V?!HxE62?K7v>-NyH9j&I$wv}>V?l))sTxe!R4NPsZ+K5>H0*9P-dLeB=$8-9v`7+euI z9IBjb&;FMT!rpTiKh))CfNJOQ4ns;n1z7+p$dIUkCietSC9AHC6qt7w)RQtxwxRbE zERn+$*KY`OD>b8_Oz1TRWdwr5Tb(h)ok{{#xs=&eNSU?scC6!y>Y8gJbU9~Oh`<6o z0t#P)e`GrQt;@4ZbzWZ>Nbqhu2r8qAL)DG403Fl{Q~_mjSG{oMd^cNRC%CKU?46b~ z1leGnrpaugmJ?c`kj-apD_m7ffYddi>K>e)dE`^;uYLBW?|Sv|W8XHs^CuVIe)G%z z_`Oek;;Hk`w%4qZ=!1bXhdN1`cCEn!M>l~5=HSZCBq1`QW}hKmmi^!S@`Ecc3wZ(K52S}axcvtwpZZL9 zWvc=W$=JOZO3u_H6R~xu1^{e2>r6W$x17PH!*f$Bx^-t{II@#_VAo{CRH?NH&Pg9{^hVe|tqcI;wafNDX;PN;?)Ytzbg=0;pI08LqjH6_NxV+F1BT-rRnxkX~t!azIq zY?fzk3GN_uRgi(WcMx~DXLyX&qHFS;G&@s>p`wn(0*NGbCQuA!qz;iHtaG=-ZZ$^< zgPHp{wb?UAvFv7UWaI*Ohnp%3sUpN+u9}Skxq*ef_UXmbKky?rO`ckR{L2r0$G5-s z58wHDGBout#E{z*V#ScIo3*~7n9gTXzh1BL*M80apTDYdou4IudAF`tX;gQe7{DTv zaW`BVm3>9kG_*C-?9ANFI#$`Ubg-6Tt7Br?((UoaHSv-?fToGXrUHPg!K`ajnZ8&S zDjZ1OWHa-bBhM>VIUUM=j~(O)L~ND`8APf&s0Yg{OY3Xvv#t$+iFgjUxkESgYUrw^ zu(u2(?w(RhTsvHIq8Nx^YG4X6A|q>(!p>7=axEqqL=H03a+8&DH@S)QNhWUEHx}@s zM=tw3X4b5IlAk&ga!*o)gNt96_p(wq>VKB1F;lE+O5{E*n&&8SI2_e=J>A}REyhuN zeBY5ZWo>?o^_5?R30(?MHs}tv~jU48r8|JirF`Attf{$yaj`KIH8L2asKWmUdR zZD&0}Mb%{HW@aW*jHAmii+&sK0C@}?qfmM2mfgt=MTE%&R|iuRQ4mUCtb0m@t-}fs zxv7~K0)c5#Q)7k%+S(XjySzDEXzF22L^)-+v5>VGZ;og6suSw zmPbol*>g$-T35{!LS5G>r*<|bCXwi7Y8kZSAMORd>l+yVOSkP`xj$*%h-IYJ_R7)r zw%yh4C0hIXvtRwQ_dNKGY*@mOTn(OGy!$-3xmUstqc_ zbmN*c!f@cMd3$R%UGvGao6lZFdjZG<1V(r5?0EGn05WT$8C2$ z|GpR9ch4Os?z#Dv{fq33%O|%V{qVKRk8E$BzIyDo(e1C_w{XWwYA5N`mHPI*L2|x4 zVOrr>4{yIM^RwwgUrEnD@nb)8->r9@`NjYI?76F5edM4bs&aN91i0!fmuwRWf!w;b zHS4*1uJimgEz-jx!Xj6rQrtUK^++7E={8X&@oY}P$SkXgXO0YzcU~#ov3PLb@{uoI zd-B@W84pAZwUX+aX0)|NktxoSR@G<_7exaBn`z@CPn>!Af!luQ)wf*x*yQW8hhuPe z$xs%!n+Q8u&MnvgRZm$vV`bz{XGWb`Dx&Lb>Yj-hZZHMA=@c~c#pUMEzRCKDy!i|f zh{aW1K^zc-P|r56n9YbXC^*5BN`Si&ISMFE7 zVGt+TCTe5&IN7oUN}_1CPH*jg_%S~GLhL)Z{DNcE7cYk{lcpw6Wj^UtLSVNj?8(i{ z2xdk?s$OihvMMu;>ZZ-I*-gFJ{FOnxcVA;OOE$~W)ff^Yj9rRbf&?mnA2G2(Ra^J$ z)&ZHMXG`vsK~rT3J>X`5Sz+@Ci4c_zKa!9;DTqjf%laKqXh+&E#r)je_4mB|mRG*) z*pWz>qwWd1vI5^l0ZeHBO%3a(3;o9j7 z7uL>ss}SPoy<%)WQ9#PL)T5ha=qL`vmhqbo_nE&z6Z@Aoh!l2~ z{&O{M4;B*@Dgy1aQ#Uqagy^ya7@4BD)s~ZPK0O14#9}?HdtIZ$^X`u3jM?jlLVsAg zySDSV1)4i(l~pafscQ!XiZ4h1AR?*=?pDZMhBKhmw8A`&m$IA)+IV>{2A-~b*_`8U<>o#&2_Vaeg#E29cC1elAP%L}v~)9TTB zpIdR78-uB=tTBJp%%)cOcg&JqgOhL|ayLszW)|IqLWeGMR?;&0PN!XdR>Mu~0k%wd z)nE_~(}UBs4{lEVY992bUd9QN+ngYDG?DPs}i}e zGqj^Fm$+dz0+=ajYaOaMnCYamyjaC;bnn0N%opE%;k!@X@%nGxxA&Wx@44@`m;T<7 zKl;R@pIyCl0pn&cj6s!Ad7EKf%5Y(hBEc2CA*Oo}273t9>=rD7f(XUPo~UzYp-@6b zotQbg$Es>X8s<8L%Cd3hy0gOwuiAg;+g^C=#4Cq>2i6}>PkeCprw^b0)W+p&(sqj` z4MHVtD#Q?%7*k3VSfV&GyM%~H_}tT+xdjl1nr zKDkIx7Xb^Rz!LI|njw6_CmX06s&}EALR(l11Ek?FbRsX#svgSls)yt6OaqI11owrkVqX z)(K7|fxy<|V+=16T(bcho4xHP@y@Rmu5ez`?Ah?pY0RRK`tgA_sO& zVx4GCrTKG_SQv>M<|$~5+;t>GA(rBc5T~2l#2asY%iSOOZ-4NLmp&l7nk^d-<3c4B z-0K(wk=Z0dlbSn&ZYZofW%7p2CJ4QFfcj#3T^BL$hrKMmw6gl}p~D=+$?HMfZf9Le zbyII_jiZFYs7V{08VJse1G^57>QOrxGfTF%waH*1G=nBaG=s{6Pp8K0v6c`6$^00Q z0nsA57I3B|#VW9I!{IkCkd8X;88*A7?P|)`KwYHpcYf?||E<6MW54qozwyiOeCO(9 zJH|+K9XVFdYuzPN8-_)22^XPYQl7j#l1m~zID`l|*n^9@svDJU=UnZfY9TN)qeOgJ z&Q2oz#TH>ADmk3}{NzUDh51#UhK1F#ngIqYcudcnB8I7PNjoajxx^q*Ety&jO;rut zb223+bFU@de)H|4#i4etrq93kuG??FWjx!K$T7xPS0(950u!1m7cU>X?arV0$shaI z|Mur|-W%#AC-y$9*oh^Z#)Vzgp}V^aj}py@YFXNAB0d>=nh|oZEHxu?5_U6kb0&mF zhD%l~?m?jnq{4va1QJ==6ZhRlONSIW@C>udzWUT`#aA} zRRwdA;>AhkUbun`^4=@Uivy5wZ`@sSJIMN@oB*|wvH$|vJRO=0B_OAlU(RzAn5n?? z1{Yx>bX`haQq5XCU6@!%Gfa($>bk~~Y})qf>U!LWi^~hmFt(G_&Su1@oAC7Gr#|@? zpSPG6;;gt zJfr$w`R{U9z{j>R9&hbk*}ZSH>*?*y-~EH%|Bko5`p_$mwx1gBJ$!I5n;~HL^5VwD z?dsg&w|&pw_`{$3O=-gR`25++r(XA}Z+_25e)Gu6QMe77;jG(Wwis(FOml+6LWtxf z0q8AQO5@-hqIp@+QKr0W-(9EAT{-!+$A9vF{RjW$SAXf``0EGH-1^EFz4qa!o__N5 zsi|$q!t!uwuhC+)v@qGaG}}7k-5My*wr8-;bZVX)nTXJP3TW!(0I{iui^Bse%lq%R z^{)G#|G)z;yZ_GHPuzO*C<>C=)}{9RS2jQPiL2u+-dIhVeUW#M2FIRx>e|ev_w3oz z>}%9k?ddDw=n@&Vr>}+syW*aOu>1Lw?os>5SGVr-*Z#<{0|yuW)jPiW&@)>L$8V9k z${ck5S=1tY=a6!uva(l~5Cvpb(%U#N1!mJ+CM)ivOyhwAw^sqDo_VpMa3}(xx zxImol25MxqGT6tlNoFYOU-aOox^hK1OgFl9N7#iJ5G!6_+l&J~KfC%D7ta5`Uv}*8 zyyiK-{4qM!J{bqfl5$a~0;cNh8C}*XXhtD1nPp>g%`+;I(r{3L!L_W^fK0*6u65g| zr+Ub%W1u1P6z%gpYR1*vuLMo{`=*(=fT71!=V@q}X!r3#AkFRt{ zftVzaOJSGZFol-r-vUU^q01iU6iBMd@7b#PM7Om4(1!X#2zb^{3qFbZhNPEZG& z1GkSq{fY+;99p4go_gln|M8oC|2N;;b}57b6Pv0?%*pBsNvBp;ayw;f&Qkfy-EY6v z?ALaG-Pc?ZA)V>XOE(=pcre>EwMk+~8)%efd zcx`f7h!xnJZ3&~Uh1ja53QM6|O`bCd=BnIVr&~5yQlBshQ=>*!{Ohkrk@kfT2qL3c zw+PeOWOn}x?|^@;ss_AhPsE_2~$}r3bUEdL0vGD zm$Xp8tx(1VOy*wFUWw+5!$PDro39SN5RXHs926zMDJ6511T|k6EFL;^Fc2AI@4-FK zectmsO<+__!zAt$Y9S)cCb8N-*d z6xF`lDGa*HPa@5#dZAuiPStiEZ;)q8U4M!dKTLPm#1e>Wx8Nk6JS@}<;ZQlqy`sTN zbLe*2b$B{yeS1T;PutpKv$e;+;kB>-xnKNwCSPA)+kbF>RaIV$8+K;V`86q@MKd!s zVlHDd0M)`6r_!#O7G$&>zA)>Z|GgM9lwli1Fyl<*Kp9FkYmeO&h9_h0W@2V;g)S1kH`cd?qZ-7n=u$VGPATKU*^7Vjq2GV;y|4J5H~)YzfBe&bJRBYr zAyoyKg>vfLoF&9+&~;PHTeW$|Q~u$eOLgOjO8?VM>^ql-T5m75=lABL`-ZzOjjw$A zYoGY~N1wR$)d!#a(8C#d`Ot9d%B+&c$L+`*?v+C6@)zH1+C zZRG8V3?gM6K5*yuhR;5I#?$c5H}3xT2VeZp|J9d1`P9kg;1Sxrl+{|zPLLQZ=OPO5 z0$hQ}2_)_aQ4n1743^;R<{^|NM5y8@#6~HRRFGQ9-Ln_LL%u=(*Po_XP}ecyi1@Y}E4@#|k}*X)7> z%4X`RM?+v{oqE~{cy_qDmfXFPKu+8fMIc1(t_D-WrmjCVzIH1OmuYmsrcaX)SPC2h zCy>Go3@_6z6H)CDiZy)dxl^41&au*N#>`Bi>r$v2lFD=L38w;As1gSzKs6WQ#7y&% zdU-3Sao!RkE;y?Ma;WwSoz2{BZ>Ov(L`3@R)}%Rq#Vn7rDd0>{bU9ZcY`5K1LYJ|< zsVhshWo}#9e&|ed`4krKqvMB{4lb-+=!QZw_oyDsnURtuGZK(##SGVpmV6BtAcoN9 zv@w}vH!sGxrf@gcBD8aNbtSUS)&&(gI~Z;xl^~d!B4uyQbNSUUM-Wj9c9)Nog~idl$-h^-yi_{6^YrAPO@_|AQ|9$Bm+IM82w`rJD|^7zx6 zwmevnKoz-63oskNY*rv~B5>Dr%XRg_qc<Wn zLP~59W)gPKlsqjjFTU|xUiUx#;CHT!r$Y`zL@Y(`sz@R7EKlLaBO&3==~L6oPkiWu zKm62--u&jHOD~PDzWvbi-naMNAAI&t&polaHPMO&gC;f=$fs@Fd4}~kCbO`T2**ei z2@DbrB;p)HY!Pc7CZrf(Y!o4(0siV};3K?s#_2p%JG z#Z?t6%P!zij4RDxS;K;c!Nm9G?&v~y;`wsm`xpG%*p`jf;SbXK`|Z&O+s~YxKBG2X z2-6A^%QNc|vWq*+$q>lYRFgS4h%lSw+)jxzR}~PGvdX4whibM z?G|K6%`T5h9>C-}fipq`$5Od^enbUm2MHiTo&icCpvo?%Qq?vy3p`T?HvS31TqCLi?0Z1&$2Kxf3Fa zfk`NPQw>LhMRMWX3oThVTXHE34rh)Gjv)w%XX8K&5(o>IIufNK27@JVf#IB`XPOgH zWap5(*0#?7{kOgT%%c|%A6;5HzWm`Yf1ztJTBzVAA*fjh0=7xF>7IMWVBhEdC7AWb z3e*p!{qpk0{`h(;Oyoj?yKcSz(&a0w`!3#b%kf#;N{rLlteM8eJ)>6B)|xg=t(Ll3 z&Rut4|G~xKUf`+nEF0r>h!01NNgD?;*i|PCW}DNtV~(=0JgVvnKnR1J0#F564iwBs z*(1=-oA{mAW^KCIu3sc*RWX2iR1Fsg0J8I2|L)(r`Oe#Z;(z}Kk3IfmQ`JS2Qe>^! z)7Uo~(jb**Hz)Jn;=7+Ap}j=X)!nih^)~B8_Gs=d+&|n+2@ok!qrSubqWK)b+*`R9 z-s;W~mcIN zOf&KZw$IpwuePg?zU;-X_nf(65!AO4a4VyJ z&-N+#3RJR0L`>C8=b3%|Wu*B+!A#AqYzO8cGQhlFhxPo!;xE)Ilgp>g748y(BO|+u zutQUJV0qVK)l{2n+taPK9>!Qp+X}fHzWKoGS6(+-UikQD-@Cqf?M-id%azrOk3Rm@ z(ZXJ46q%A5rQ8J(4kBJzPTsR$`hKf?1p0Tgb5~N|>HKvKlM~pW*Ywh)+a3*<_K$X- zxqAA){OWK1;;;S7;T_H9#&S^2cBHvl}PZzH+JJ%0gP(xN5ouv;<~y2$`FM)EvnGu4FJ6 zE-nss9a*{M&Rd>)_w6ru!F?||wEy72TL*}K@$&dX?|bOcuRQzYW2f60xLY`Wz3l;bNA$myUl5RXqc0? z8?!j5oo(>ko7-y3BF&!acE4os?|$Xwzx~1@F@mX= zBt<7C2Ta|?naMhJazUuWppm6X-bS=*xcr_cPYtURH?53bu=m8LXIoROQ4mHp>px&t zBGy4ng7RVWc@CuzU6$nkPs>f&|JqT?ovtC)VT*1kHg8;ZGYkv-E_Af zJUG00d3bWQYi$^1kbEoWnz(InxYJxreOZKi2}Mt<+!-3m zl7A^I5e6x5v_6I90y>#xhjH(~Lk?pIbH#A81c;Lp%G+fj5sqM}maJcy4{WePLoGj% zh+PMyFFwBK`(Jj`T}KzXq>o%2fBoqz+mrO{waNK0Rdp?a3)dqGGqW>+i37AqmI(>w zpj!_d+dCY7?fk`OwysR!42j%0%zBM$5!v1Vu$BX;bQ3l=n!nEM>;cRh^pe-7upUt@ z5jTJX<}NJkLQH1K(xzK-%;47ZPy2UF^U1GFh2?KRW&YZMaSOLB1{Q(#d^EaFK@}pV zUP;<(eCWE9@Ep{<&RIj4BfE10Bosld!OLfrdsEySx+{R;(Rdm8O0f_stx69KLwEX~ zGRc6nCmR>2*mvg1odLCfO?^w}#XhkZAM>#uVkroPWpi0SdEsl1tlj(JBX_*@z~Idh2gtwIcfWe^<^Of@$=|>F^(U{iv#y~4 ziUQ*3Yk8Z%kpxOY(X&k_GlQm-go8*(Sv7kIl(Q`lMu!jX4kf*sqm!#z2o=~OLyJ$re@aT%D|sH*zy=%}iv#m4MBXk|wYrXMiaN za`JYJHo=#8xYzSG#+&G_K?6xcJaEkpLx@BKBTyh%(T&3#P?%pY8inL1m6MT^D>)0t ziYR(g*Oo&hZzPV?609tMJyz0A{o_xcGRxhG)l0wsuRr;!?|AXKN1p!dek}^ zK^2?9h_kuO+Q8jxGTA>mcxdJLqtAY>XdljBe0J82hl6H&HZ#@G@Z$cVyNA>oDLCc+H5-ehR=3x#zU2r1#_#{(`+xsE?-_AZ zFYU@XOZXD@`NmZEGg z_;YU=T3WN7j;rn^vD}NIw;-qeF=n|-DJ3&w5oWQuyv4obE;$_JU_j^I!D^;i%WBrl z`oIbyI5asxZUjYD$CR{SiEwgN7J+e2IlIOni^~hsaobH>gSo4A)=}QQZ{^$H_{Pz2 z`OiQ0M<4yf2k$!Z+>=i}-nO$Ct76g2q|TgkCbB~1b2aaUQYD#ihl*y!n4{Ns{ZBV? ze~b5Sg3AGaAl=lIy08KEQRHZgxV!Hhle|t#5hF zH!Q#F#5kYLnm_f>`@Zw_Z~m6&y!qUP$G2$BRa5Ga$bb++YCEtOtlo_s6uF9V5MmG! zca|8;Q9+_rpZMteFJC?xrGa62&+=nWJ=5xxWjLN(-Lx?Pql_L@Hg{NdfEucH)e8p} z4<28+`JUTf^1v-GdEQ+wT3T8%%ID6mo&55-kDoeuVReHCyEdbI>EVZC*5e2EA3A(E zZ*xa+&%tKbaPiuu$@z0vFJ7z;9@`7(V-K&+PV8P>iqAYfzWKI==f3{%<4>=C@Yhzq z@u&7K-Lh-Ex<0-%sh1jxf$N9_-V=9^mZ*d)ZG!gG+kg25xBka-|L)hHzB+*{EPBg1 zITh}{8i<*Kxx$EJAZJY`A+Wnr4&rVKqfj*=1j{+4v06(^FjI9%5O>XL>P*Z`ZrW+y z#&i&Bb8%StY#59K7sF@?R_o!YvBhz2ok*+cqiavS>q~=gI&{;WdlpV# zJb1FZMnf^+)$ON-lLLH<6_B7SOg{HC8byhKL zY|d5&HBs2Qmb$M!UA=M(EBou44}vZP9f;eIeYuwHNfweoWM&Qv5Q7&KZ1*21IxperQz0OhMbI~ zOWI_Gx^IpOWOQhpI zQHO}VTA-zUzI7QJeZu1o>P(RNk}09L%#|{5_ufo}yA0krJW7qA`R=pd3eZk;+B^q> z`c)aArc)pTB*YFjbC9#Jn>k4zZ?luvTGm$*+|=zx09F7h@@exlzX(3R<~oaK;o7SPQvhMH+iy~JOhJB!*O@;0b_S(o7uMEO6X8DL&a+h04WinpY)xX0keK# zU1Y!@z+i!xh}D(Bb5;|~P052`qSMwjL!HF~JH%WNDBB=~K^yerkDWRBk5*s!?juLv zw!8V(fP=7qqPKtlp5wo`@U=fV|H#>EIdNS}W*LOKBL&nk5DD4S#HQmsWe&`svR@;D z=)l9;wawrDAMcw?+J!hQU?>bs3^q8asZ^OrvbAl}FbLV4kecD>LtAIR_9ts^di1t$ zef^;WuNyq@_ZOaX_Y3~u1LywunNt@h+s%RwFj$HqP>!gCByt@Q1G5Bn0uq#RfY%|a zTO$n%d87$-fyp%^Vc6=CX7ueRZvO5!99?_`rOsFXr2Eh(uYU0K#Zz5Q1Nfqv&bl^b zZH>%8V9nO0l$$Wb5aa1224NP>*>*Lh)iHc-0_xKHEaGfH0zA zK-z{*-L}CA%*;$8#s7;#bW?Xg4Mr3hMJ-f}7~LIAQs{f-4i$h2CE66OGp0rcqgH2@ zrzFfIFz;e+t5M`;inKl3)@be?LWE@naVX*=B5~79MC3{&Ax04AtYAJZftq&UQYnTeUfY*gA37a^&X;l{+8u0H$r zpSUNgw%cpBz4UcI{r7(6@_2Q*IaIczs-1{%;OS(0zR0^ibnM zaPIP{t;v;x`)(Z@x|9`&gKD@uoV7z5(xIF7A3k�EcF{e0SJLX|hT&SzgiH0Ml~x z;eYxn+tVObO5Hnt{@>5q@sIuZ+os**XMgtJec(_3ysm320YyxOc}va?D3XC4q@+@^ zP>FQsqgA9Egit)dV0~x}W9~wTB0W`TxrW6%RZwQgx%Y#ksE>$P$g~`Y#X}k(CO6Bb zfddg0ZyWNtM6e7tBE>Ym=+H#iatQ&M^MK4ltPUMMEFp{r^=;3&y|XM9VkHjBj!^h| zRGcTcWFItxrk%Bu@%DfI&;Q}%$)~>l@K-}T(F}HDaZ&f)#Dl%!!r;kv8}~N5U-0U| zO?Rw*?en^RUZ?9-9n6#~fg8D_PqocldfQ0I?4hoPyW^hQ!tUc?&%UIdL0z|*&wZgi z`N5bkfAhD0_iz0AuP!eytX{b|SQv&7%kWuFRquNj6e1Z*@wGBgZ@yY=JcvovRgs4^G~VkakID)AH&*ddyY1nlfi z6ez@c)~0sWRdsZCP09c-C<~1@v3h=OxH5R%>tD4ns{iam?|^nO$x~q2KCcn7})t+YY+|@I`^C$27 z@xS|~bHA(Go9m-JOF7xrR$JB8#_HPPU5EeXD}UgZKKwJWSyJ(fZh(yYIO7mgnDp{Qeg_=bnZAyDZq{C$ByH()Bm>}Ho|Y2DIh0x2=#&7<#m+o5_8|M{<3-L9l{*u@;5_(2s|r1EG{gLZ929ss!G?InZP0hf;!JZ zoG5{#MbddMl8J4osP zRnyKXJE#}C^`{+!wsq~)?3rL!AMeMa0$vm_NCYC}OfjfAAjHxe-v}eHCx;M8v@S_i zbBJIypIREbwhf|y?E~(pSb$O6(0Dt; zqzPf*zR-kef2r(tiFylZ57bfemD>o=mmf!-|W_wMs9MA}J zLQBjJnw#SQJ&_n7H}BLG zb00r_ZH*-^4nRDGFV@&M8qB)fsY+6;N1;6H>A4>79dmShnDvJ0T{;a!Jtp;2OYzLLD2TsAjEBP~4fp zF1sM?X&pW(e#yN>6UlsjEaP1{S1@<*VIqddsruT+RE(KwVuBh`EpZrRXy)!Sx8i`c z(-nDdb94jIWd|0Xqpba}oNwr*%)PiA6yxMPfAtX)%2@hp54@Bi+bZ~u3DKl7;z zkFReka;)px%$O<}I55c*k<6&wl-$TUQstg=CWdT{C#&1f1|C&GvUR;zr|JA-gRF^} zK#|CE&I)H?uPG2;;q8C>_!r*y)SjPs)j8YdUSnr>Zle+ z3+%2U;F=q2AyIN?dE(ec&dz{<14RiSlLW54No~S(dVu_aL;Jq-rMErz^+O!T~ zpKZVA;b*@*-X2%%OKhZ?XFBJ%B{fG1#9f=G=$7~FUtC;@8*6Ru+#O2Dw6MG|tecJT zmgTZuqYx|d0Ih_ZVZG3BHRP~TM>gn;Fvj9`cMG>Ky*nKJ)&+cP$j3Zv!ajx7Pv}=Z zuU|N$msz?Ir$9!RmGsLOGYLlmK>E3Wpam_IZKSC z2C2hyVX82U%sqq{I683%6&wm<0!xUI)z!7_Iu&AJ%AJPTM*$UbDLVy{oGrvy&X*$7 z2*Msnp%~zUjo1UpV=kdyZ_KzxwVE{0XdK1h*3Gh8TibH`T4b?AX#T z7kl2zoJ&&X*6SxnU*~ql!kulUt2;q1ubx{7Ag9UJIHk?Rv92y$Id|dG`J;z#CqcHHXE}x#M{%$;nst+UIJ)VUI{@Tv z5_j)Tb*tUBxx3axBlj&L1LOu4O#cSm3yn96$j0W@zy7yB|DN~0mnwPk76 zybC!dNQ^XSbIP6=L5QkYF@>C!nX;*7Ga%V*%&RLAfl7#+y2TiXSR@qFJJ>upR4pejw9F<9mX>!{ z&0u-YuED~nO*s%^C1eIQBPNAN@x<-bo=hxMZCqK~d-%}%-uv!v{Fd)};>pKG`$AmE zRxRa)qZT9+J8w*JFj&rg43VbJ~LPrUtSe(tAPXl?asL7%AKg!UxfooUU? zi3xgr5nwj|=z0mcF#-#F7&fM+=H{+h`;N`ZL26~h@4t7h6b)5q&`ifOO*$V0$y801 z8M$)@F+-DsNSM^YU?b1j`d-1^)Z58SYKentvN1ELCIx6|&#uX2a(VmGefK>-S^K9S z{y^?>j04v!OlGd?L?q1StT{1=i5-P*-4CtUan9_i;{OxEN;ljJbM}}aZ|dc(?e(e} z?H}#Ca`oza|M{(pSW$_w^f`^1$)&7#jVZDk6yc41@hQ-^-&`@Zj;ANeIRP0%kq z`SEu=|7ZW@JO264zT+Kg$`xfwv+c24PF<^kx-Pq>cD6mUc6)m(X`6MXmef-r-3bDb z$D;8ECAF(pFRjjIhJ=KGYFFI5uUXj>b{$zcdVF;3xwk&|jw8=|&P{hUdwAxv3tzwT z;g3D~^!e58&FNF;PCuPbhsKWWx#h?$d+X(e?J>2`t6Qt5PM>+nw?3z8?)~T=f9=%i zYr7YQdxs+)r7xd)`swp$-td|Sp7+87Pd>4J`eb|P#NI>4m(QPC9qp^(bow!Q-ph9% zJ-ol2ZBNd05jNQxZ#=Vp?xBm9pSX1Kv1hKFzHss4>SQ{d<*_4yl`X&J4R3qV4}RzV zh4jef@o3i)oOG%HGb$oMtl7=jw4Ijl7*h^aBW9{o4iy_r)sWqknFW%w0zx8|lY>w) zGPA=?SkP+pY9a2fY1p}vN{H;DW@Iok1EdNuSj?@Wfz&kVwzk_%vzCgz1Wh|^o?qKK zMvJ$ttXxR9u8vo=YQ03+yZ8Ehr^2mqV|N1A5(e(htk7h+aF&G%k60qHdS11Q59W)H zzzA{VwrzPr5+DKf0NE_JJnx{X3ZB%{3{@a210LW?m^$23atoQwbL-wYwBI|U1P~ap zldEfSr=U(}r?xL$om|_$xDv1NL{->{3X{56xjK^ouIhnUlZGIRA&lF}3}9g=WVLb5 ztFxK8Hb@~^P#aV{nJEP#ueYDRx^(_L9k>&BKWFjSCoi44#$m}-q0}%1Q!xlrAY?TI z2{Td#d+|Onw?T-;VLNx~%FN{CaCT>stXj5>*`{lL#Q;Wdb7v#sKHnIuWq1X{%b;s4 zFf%m`LPSDbq|^qVqpQUr5C!5cLM&3(!tQnAamwc|Z&zt{YJHqS9EeB|SB$sQ@&ZmA zTbzu$uRXK9k!Znmnp0RB?%uUvY0?TANX?De*@U7w8O-5i6gdXB?4ETlz3lhMew~;~ zW~MZ++aSZvio7J1(-$ej!bhKu7cecV<+0t@|Gv!I08AkE%yv(3XJ)pl(@K?Mi9d)N9`U!8R(o8 z+#|O)G>`>`onN$mbs;xUv8l(H$l=-H)O%CW4g;Hb=e^8k>Ef(g3vqW97pi7Yw8fM* zHBI3ehFWUpJTuFl(2u{MA~5LtG*N?~I3H?HVk0Kc4pJb198h?_D<;ZhdlmYTXbY132hefYl5?S0Kp9UuG+;e(W4XUq35zTtNkPyE`YPki~A)3dP> z!mu_4u?#S97A011)iQZ7a^q;ZBe4OG8bWcB6&4UQtFxP%hy)Z}nMp7SWQ=TJ4j@=C z54tdvN7}3Z^phX^rpHhG=r`YT{2QD5e`?|G`=0x!e{}VuPh34endN|C6`7)tpb8-{ z!^)%)MTS&0F?thJ#F7B+vvx7rbC;IB>z?B;`Nlo;LZmBp_1*e`PhI-6vlq@%9uJXY zY6c;a=ZUqm4pQJ4=VFOTNSJ=|r*5?k2at5Agy+#-3^#Cq6N zLy1j@tXySOQ(K&*d-vx1Uo~pJyJ{aWj!IAS$B7nhAk5!{oY$)LF)Ppz7QnrfHb6T85VkrfoYN}8L<}T-1 zo7mv0Y8mjrLhk07f`E*`fdG;0h%o>pRVcO4U5F@15H3S{g%H#fORsEqSbDC_~MQlj+*}`n5Z5J#l3JE$6O0 z6-Cx{cjEG`gwP}LjcieTy^76uXvTe4NlDF+f47rL;>m$w5Qy)wH z?{z9=%jl|F200ON!lNgjpn`%ESqWEw6@6BQ6Vb|OFR5G|UuMWcwOC6Hm(nf~AVSE_ zBIY`;?^M#KN!WXWCYXo`QMmYsmThu*8E|*4}%$ zcku2zY2`T2kU^Kbcq@19P!r`xltX&6!tvEqc}Y9-gVCoysFfx+`wxE@<3Kno3{ zHw|XtObX2?y(>TZZQq_B$SX{BgJwi9}W{ zpaqA(l%SxLlc@teSkZIjd>#UUeB<3bzZCslTF%*iU?n1_sg5sAFW$cVyd@9&n}d&> ze)#DxTt56wN1yuG!+F|8iNlfS&TG`?9(wk4Rs zCuZlTr#H`DZP)6Bidqg_3(1Pbhd=g34gA7apLqRf_?1sQb^eLVGMXK^=fLPn^YqiF z{`ga$f8D+J-FE!Y)yp$%kE^D-?UtHDe%=dq@7p`rwZb%+UQ63w`rWUcJ$35Qhfkh* z?EEFWI>UxxRzo63CQ7jb=@9jKf1>{AZ;oy{(YDz_MNAY}1HqUKBEo>@jNDlWCC|BO z>N+-_yF?*t29yM@PRz{YKnPp{CcQ8e5Q#Didq>Dx#o?}aa9?w5mS(P-AvOrvDH`W& z$z6L&LLXU}XTH6qtK)9nykic+Y&x0RW(r*gUu4|1u;+{(dn!MY%~=R8j%?Y55lBk> zFj37>D8O=plAtEtzqY8@~7LotI{cN$xlhv6G{~b)>wqaO#CJWKJMH)C?-%MmuL>CW?Vuv&;LF z-7XG*!?mo0YHnzP0B(rWtv$bRjUQw`eedeSw=|DmYdb6X>~3BQ51F#6GH0e)HfD+< zPT)d;BCa{Iu)23i3jo2)E3Sx$C}qm-9SgNKR$d>_+Q7CHT|aiGfjTCFXzg8tkbaz=bmbL&eXzFoA=BUkchlrsus6*U!*OD(ftFbgVQ+l$8$f|F37Bmw+u?L z=y!<=BwGQ8iqQz(z)OKxE(R>Lz6T0x>Rlq`-cUA^eZ#-ZtM4*6_Md|75vcf?7XDQS zbkPt>krq?wvR#1$0#(b929}_mTZR=bs6rJ~ND>)*;?zTrh0&4gFFet1eV2UVOfXs~ zmwKZz02J&n0N1`nFH=}^usFQ1nZ1Afy7<79qLX`(6jk7g%-y<_uXLH1hb*BE%_trX z%9NA(eBN51#+;d>v#WLH*~ytgkfp#ecXP80WO9+>;^@)GP*))_sH+J@VoH|SJLWh^ zQ;$yY)TX(#gD~tYPf{9$(LhFt<5xDXJ^SC?{P^$OcK?61UVl(%75a02$H!0H`s-`Y z{OW6e^6JfN6PqDaVUS2O%nTftW@)Bws-~n2O4h0gM=RsHzEf~Bwcd};WUl5ceSzd= zOkhja<~e~qU?s*h$A8#({@H(b?Js}#9e?gG9XkAD;iukn?0vs?^iyBF{P-K2(^*GB zB3D6bv>u|{9B4sGwbhkZN=boEbKP~v-T&PECw}~g&eV^xM~uI0Pkd(Y4_?}MR`;eu zOpsH^ohHl!n6jpldts_kxF9S8lUd%`-Q4s2tQqdYv68qpTph%EXMdVIcMDa;jKCI! z>!un;iqYbrs;b1*z8`fvJJNSPET=v(v>y^XreO;GI$ioL`^FRc{i$zC)&aayXPvis zGVfZ}nYWW}nn(?4o~9jU2wl>-BO5g5me@gHQtMhEqlj@hKmu4?*_A^Ry)$tHH&m3whV2#~pSK9Rk}-=x zlNtLwb!zH>wzq zNEfeO=(_n}*l70DYDfaI0tZU-?!J5Oy7iV@pMCDCQ&$bvr~9rp5zlZ2#UjDxerEfp zWI5&4D;Xi~DBv9HRY3jFx7^r;CFS|No!xf$z7emCr+Z7`5Id*b32`dn4xlKtdNxy4 z1(zwXmjkuT(HA~Lks$1@S&LDL#fhLLtDDiAT0y2J%nDWQn=vy2NTO&~0zgvwSOSRq zaXaFo=@hQZT091x$ST5UAeMBG*~`<6!l=XH*Q@~JKNsmFMZ|9E~(~dfJjJPW~LBAP8p66B8be9 z(YhKfhE1ieDQu&K-r>&*#@?JQd4G>LIDrz{Yj)|j{I+2=yyfsM&tHA%SAXO8{`+72 zTXcGG{q>t`E62hh&L*>}8C-es>g~_m{dfP)fBqYP!XK9 zN0#?D$Jef2ed5(8pSyJF{MAeQdD5EIVdU_^O0~Qe>oDvlzLPeO9vpt+K`BGXysEf)V0? zLIdMa38H2-6(R{V7=-5d>WQ^*WVYAs&D(@v%!T8|6bZzX*0~*v(9bpx1{)zxh7+cQ!WH1hXX>S?n(pVbbT|kSx@nR@ z455!g+}h38;{F2sG^93*A50l-boGAViT zK6$jK9hGIno9LpqG=0=tKB+QKQ&k@-tygFTKl7~ZM?G65ovS}HXOjDVnkF; zSe9y+BAKUdQg^d^k5`|3&mH&t%m`Om453h*S@v4yEXJ_OR5u_T_!^i<37*|qNA(B#%dQcAs%`mvsT^#P?81%jx z@3@^#ex&xFpmaOp%r}cUFP{Jqfyv>P5>?EVuvgr%&Y2OV8s@46&6%rgU1|xxEy;%p5a5OxdR2xEKKgiR*0pA=t_Z!0<%a(6u{(xuD`MIj)#x_$cK+#eDawG z-}jEEzWK~^SD#z1mW83&M9Ky@Bx~n32FmsRmN_GM0e4u4V;0L*2N5E3FiY{zxuw?PfS4$T(6;k?@44gl+wOe!xfiSDuyW%5)Lw0OCPXeWFdM*= zh%y(XQDI8{DQl~ld7ozarf;I0jlDgH`uAdYzPY=%dF$F;W8O*H0x*i%au6vQ$n&PSfGZ%*DV(uKu7@UbAWNHPZ;k}fm zZ1jnU0!w{P57TR-}Tpa0x{@%R71ul)M2Z@&0h*?28%e+ajKq`vL` zaR2>5_xAS3Z@hkuQmO_a#28mst)qPp=<+-)$0H5JW@7I1*34Pw-NonTFMnn7{1+oO z@4Wr?|M4IHk3aj@e@0cewl>Rpvs_0Yh#b&;iJaWZ6w3*qg6%EYZ@mT_ML`Yf4X%A^ z5TL5Lhs99N>Tps!sEEoeAbU2rsiK%h(bJwNh!}Z9&e;uF^L(BN6ha^(b7vs~F*q=C zs}f{bg&;A=e6m09x{jGtTT^Ed5w5Fv?3FHy!BUq?U%FWdN2Tc6)SUt zS&=%Ytil|tz)HEBo2mOk1y(-1{fOk?!t_6NjUHU03wcC2BPY7I+il%>=-!mm2&>6(+fLp4wma@!J#^TYWxO$Y z)o}RwlUMRad-BNo z`#y2ov8DQvyH}6iVYz8ve&)v4|HGx{UVQG2mtMVk_4O(C=bQ#I8dht!(utZvaIV1- z5KxQ=fto6YK=AI;{!8B7`rv(^_{vt?uwgw~a?9m-6_GAyH7zD2_h>1N3S zrM#bXP7xxEWNIow;Pc(t=H`4j+a5ISQnMD1t=y7kUDs|YRH`5*u-tVHLWn~`%-vYK znUfMT&}YW7RGt%{puplp;_8<7t=l&_hSd{TKH~FB@Xp!^x^dY}9c=&6w^ia0R1H!B z36YhkWp@P;70(6^z$pfoI>w50*|~1Lig7N;tjRD9mBwW^<-Et7$gG#t_w*G+u7tR$ z>MnJvKGovl5wL)nU`thm>C{z$iFz#<#n>9>?17_kHGlESVD~C79m73$ubf?OE|2G$ z&8Z4ZBI+JkM0_u+FjwHtjNJoKL8#9yt11aeV9(ARs!%1f&brQ0*$kT-L9$Jv99fDh zJ60#mz27miFD6i2a6SF~tEVF@bZEkhT+Gsj6S(luoru6hZ0HZ!qBE6BszKl>BM^w) zyn+o~gSQVHTm9(!Pp{r{Vs^v7{k7MB@z=ip%GJrnoH8}clF`SNavyx+0$6Ed>CH-l zNepK0=)DcJD1eOIN@^^e+`$qFu3lWm1?yghl|t}H)i74XHtjkFD-;KyqEdS;@Insb zpj45~+4U`PskAsJdqWN#lrch;m+Fm#oGV(EdU-mTZlnuJSJn3niNL+;r~gan;GCsD zTObv}u$2)*C|+dugUZY4Es)-R9NX^}4}86f**0GOCQq(e-*5LjZ0|Dz%KO@f$9k_a z>v>MFg!KpI{XeTue;;kc`n$0AlDC)pmW;RrETLbq7Q=K=@?`Is+kkc6?tmGghGr1J z>}CkdsFq+ENR|)|otV2l|BdIiUj8O91~FV=JR(sL| zM0jZ!Ms*C+`L5brC}lV!FhMPs9>O#wVv$N+37R=4)ofZxrR=TdIlLhc9wxbKxNE6v zd^tAqTpmCFxhEg_%F)OE>g|Vqp^-bOJLU18jeg`WJ@mjoyZZUBUAi<$+*M055;QYQ z$i7?;lc#aFXPE+9n|lA3JB%o4rWlIl!9Wxkj-1t)LyVznyz_Q8C*mMgY+_DOD1_O) z8pg-R+ZTTSiJv-m_n-gilPfdvN{3fBqDGly%?7zt(-_Guxj&f8!GQY{2ax&#B8fB@|nvx3h_>g0fmawpVqL zs2M>5b8y5ELU9lfNHkDlb+zn)DtC)o4Z>j5G$GWLg*x+E^0UwnoQ-dPcZ{E)?h!-n ze1qCA__^OsfAnPgVrOZE6I(}J7Mr!%lkt!e*`%G0yP1WYeBPy*dTZP&CS9IW6@>>O zR+i=|&CAij)sTpCH-j6Ix)ZVq5Y30iYl9#bTf|8mPUd^=v8jft*|MTYEfyCdivVhx z3C2vG;ZDMpdvQy!yR!r)xEAn116L?HDhZS|5jmGxjf+_(DLizzaurrbagAGblBBJH zBuHu##7P1fy6o%2l@Go1;Y&BJKY#gBXa-aT?X>Ty!OW~#OTrN&m@!zG*|L#Hu{0u5 z&Z^$az|_pFB*l`dW>#ijuZEr5?mVT6737c@1diYgBPNN$fh1?*KteX&xbS!XyN9Ys zds|!gKJ@lq`EUNGc{^KPK2&%U!jf}ZY6iQr8_DK<15oyR@V8I^7L&q$151nZ;Xsmf zu)17~;1=r}0Z(;ua(K^A|ImK~u^XE=R#y*$DCHa)XjaM;he5N#DUQO59U5#5-gxb` zx4-`f?z-)P3s+ubq6-%<-rU~3{phjDUaQ&DRGFoav?hDg<9D3A|A7ZT{h3eC$Cr-W zc4Fzs>B;spuoPuzJTTqsof%&22yd~IyyZc|&HGK2^|zR}5RlEm;Dq^&*~O!S6HE2V z*8U9uC>?N_05c~|rE7JlyPKL*(XrPKnX{H8ST|g~yiwQj(I5HYPyg2MKK;~l>+6R^ zWICURNvP_opr8y?H*iG=T*TmNIS5M#rk*T^7zkvU_BMBx4zK(#zxdC7;wOIOpZpL1 z^gG}G?)Xn$!i!%F_q>;Gdw;m)EDxHT=Xo}zsu|B_ai)e~@Y(iEVwG6}X*bgf``9?Q z_xzV9FMK_8uOB;dzr!?hW{NR}Ae=a* zlyjcV=ZkS15kZrI5UP;coab2r50)AS+t??2Q)ZCRcy9_u98eXi?|l1vfAXEjAA9W4 zzw$Fb|NFoH2j|W|=j=_h1owifE_IsSsUm_>cXChtL1=E0ftwP!WSv4j*2=e*T7j-Tuzs z`niAq#b3^{xg3|tO(cX^10Dqe8pUc5>eZF?)xnXYqod0{7&gNiONW<^pIkq2$H_CH z3K(IwpZ2$BZ(QE^-EThr+O?~fwytl?w`bIu`0~I2Y-fAYZFY3$ z-A9)Wzw6}c>iT^v(N_j}xk~$6yWjclH=q2aC!fCh(hFM`c5uBxIx5R6arL+yTB4r0-qb*)S{yQ#Jvg0tE6$+eH(_80dDcYWvLchB&F7T;xwyx zocwSVLPSp0{`s40uU??z_hIei>f26)Z#^%`hND3?*JQyZfT9qk?5btaR)^qO+pG>4 ztVn|vG*xO%lcntGz)~5QJ53YaALsq7&K`+!0XCaCz`Yi=Y#pIQVkIkK;ong=KDcMQ zmsx5r1zy}5vnn$OrgDFAM*yKfUcXK`CuL$&r0MvsWATUIaqQkhCvLm#aIBV|{G;=~ z{gsQKdue+QgF(Fl>08jOh6Nh$fbR=;Vqri{4Yv4qZQ)`h67F@mz2m54DLE)O*x@BH z3q&R3jX?|^RKuErX*<_6*N#fJRrIqsxNEQ%5we4F%XwljK)p{ubNB(nh!#IrK3SDH z0n8kW|2ZIBxb*7lo11gIMBaJ7Ts??^?{~j_DoVK#I7))+;@-57`YyJt{o6u|CBfpG z4*t5*OP3&aCy?)-?|$!p0ZquUh&f)!DJ-2v z+5lHDWcrMF&epG)s|U@l<*3G+>GEW-y75C$|jNvpR)lTA0ci{s1R{r~;KKg8xG zq}MqfHfQ_$w-0vTK{ui%(n$DG3JgPYFTVN1LOz4OLBsd#Ur{wA# z33K6iabJ$BSzR|$bIz@s8+m7mW5EC-uqbmy)t-i5d+FL!|785vzIEH%|4LK;6#wKq zj=cR>SHJX!J1=de*?vyrkw~@S}Ge{;>upF#m==_dB!S_|C;==Uo~` z9r8@Oj@k@W6w(@TA2khwk`!uaY2GNrz!b7l3@j`~K3B&$ij6pHCUU8mVu*vLSqX!s zx`t9U)%Bd;b%HKDG2zkNOJ1*8#K<0P6*$8D?3U}#pg z+>vSUjNExLQMIhz8YNVkk)Te924i7YC8>ui#~?D^y`H-{vGnnhnHp5@J9GB2hws^+ z<|;%PT{A1{Pfn9tH(|qo!s2}($~K}#A@Ig z@DPG!t3pK)lifWlA=>@1M*WF@phW32Gx~FrP;@vsYo<4~8*g^4{olf*riVr+Klx*S z?TPPwHC@yX|DWG2Av#g4xd6vFFf&oZ4uEaAJUD*x#A~m=3e^uj{D~)?`s(id+WD)m zzJB@q+57Gz1j}ZMZtk(75M!Fp;QsKtA6Yvz+PVJpk+YZ8-QZEE4kMxCvotl`>-S>* zXCLe0Aum)nNL9a`&(qPUmBgi}ZPD-Xn0!TB{gBKq&rF z0(%q@k^(FYkpXgpNH8lCm41~1F9T#TH;`M2;vuF!=8jR8{5@K@=#RYsvlkr{1H{Bs z1|>u+q(<&u)v~_6I-5-Hy8G-0KK#Mg&YgedY@T*4-9s8-j`1k&=|Cj&MsasA@ zCgW?@uSng3%0uV?dzE z{=||tOSN`tSyvCOyytyC@V)PS{}=z+|M%Ye@A}|JK6K*5sVAR#d_37B=2%7d&fP>< z%~P906lV@0kV7rQl@F2*inPl0U<-fnkuL?>LjBf%)){2bt$cNVzI(Vid{ho^T)z3+ zzyGP9_#5vz`oW|7U)s6#%-Q{oSvyUK4~@FL*^9q-{{H{??C<>jUm5G}ttXFH&XRd_ zXlU6@oH*2V%|Nbvw$ruy-FRyn2bR)2hIv;FmmWC2e)jk+58rpo`cOvoe0pvF;u~*#?YXDE|H2DT??1VL z*A>$xu8+pUr+Mv=EFZ1bRR{OIrB;1@fpmV>L7JbGjA6GNjQ!_-5p>KO98D-);k0T!=6>pt;k8dse z)l$m#ly7&q2MSFP%RWopQdO;tmIS_;_h11e8C5uS_h4yheEoI3z70-*sTud|C3c5_ zvlgEQW=^62MJ6JqHg_|1hjrPCQzDU1)mvtZQG}S5Cj0yT^m#lowc*tR#q%2O^?&zrE>%KtV~2 z6#ep(@@WeH<0zh)y2y7 zps@lkmW9-BH%ovjgAv@7;LH-K&^tJ5o6&W7sy#yofKw0MEDxavojA&ncY=1qZ3dPD z8115XDW+D25l|6T46&lca}y?Zn(NNR&1WZS0i1ia3Llgay}TK3E>O!W+}BZyZC+nc z`GOeymWrhR^96*d1kz9utCTq`fhmk|%e#E@dEejYVN`veDT}J+;4fS37X08PCZAly z&220l16n$K61!)7|3&B?oZ&UX5g^02fYdjQ?g#B+nT9U**BKy?z!bzJ0_$w|BD#I# zF#$flz~h&Qm&5AWFk0@$Z{+doKq~B+-tWs+bdYd3xcG4TRuct;h()$X|Jqq;SE;AA z^-3wiA~Q=-5?-y>sFh9qf@Z9(?QTrRi-m@w95-IP@XX?HHJk2CFVE*YfkMSYVJ=VE zO#x(6BXZYBSt%t-g&$0in&T{|%o;dm)>e~{M5-uPl{Isk3#z5K9AXoso+bHr7cPD8 zAKv(>KfdSAUs$gmVPAIqEWPuir|;O1 zK-rO*M^lUw8vxPB&Tuo%Ijh;E8m?7?mDt4jbmqo6c_rc|H8&JuH+K(Qhsa(1bZ7tM zk6!)QQ|o{JCypNbOLE6QjJG^+xw%W`ocitLzDd*0zRP1iK?F^Y&nr6vtKAzl!X^;pfEj^5Lh>;OYNhk_Y zZE-|(%rZ?*S}(w6v@^2gaugFD!_Y5GV0CttHae5Jhv zvnAH(on>t^h3wH2VbaaB83!b7J0ztv@1{!0k=50Mn37pG&z)up5uDw#gF_fNMRRv< z`tcbN9GY`oHD`~XkSNc*{Komst^J&=HaEBIQpG64It-VVLZ{Q|Y~Q`}1%6e#jwx25 z5n;1r-AuC+3zL|-_EglOOrfkN)oe_Sx6>-Z(rs!p3f37R?^3rfui*ykAZ@BI*Cz%ToN{2I9R^$nhrO zZ?WRSn~R*j<9qW^_G9ZO|L~80^ZfRcfBU`vczxx>*3Q`Gph{Agsu-A{NkdbDI$WA? z_}I})SFc{ZaPj?*eB=+l{PxG6yY@zR>8bBO{=WBrtctPS??MyIdWepiq)B?;dmee{ z!FPT6E8pL^@YQZV5X>~eR#pzb4RhJwevZ(hNWR~EoPV}&HFquz%Hp^u^cz$-03}C4 zdt-L()aYyz1})7Tlyc%gZar>M-OUw+o>5fCz#{vMxKC|&WDr5kKnToWR#P|Uvga*D z5wTI37=nob5_WZWbCPm&QwWTriCc_znJH(DQ9z_wnK@?-!ou8kxlNsDnD4bKOT&*o z`oYz;)hC~PZm=}G|LymiS=Y7zayAf|gKBm&DfyWI9A+MZ2vG@y41rCAh$s8gc9w=q z!=L}_Klk%L_tRhe!k2&Nw?6&VuYB>s)yHSAe{tWI5Dr%>s}={`tZ+4~hc&q2P|v56 z?&d|k{#0FcXHTE`>7V^?|Fi$}Z{Bw6t!+EIas3*YtEwU(u$Y>`izeCK8GZfrCLxK) z9h!A9S1gfu{-z}AV8!U3RWY@9Q?(bDkaAN|P5 z6Q_RfGyncip7`3k-}T{lJ@UwlFFd!galPw|2%rKFlk$G`D|8Vr=0QK8Z$Y!%VpUkhmv2kU5+F)pY&3-rT{BDfSdy zZ|`CdaqW#`eAEy9Km4pNbGRgq>&UB}LK ztYRR7n`Sa*CpWf?5SmfFUdK^t6XHAs_tecNQ}e_T(F6qRmDuX0$yyczaqbWT5nPi- zj)B><%gDKa1G&&>tW+CySs;c_|BuZess9krSL7iRu7ro&3a=tK~-lWBR01@+1k8vIo$D1TD?^- zKbM0?xSItDIU6w-0^+n>UPS6{;97!eRw8!Vo~K4Ase#Z$QO(oNW`XzTX?0nG@pwYB zr!S87H!-*ccigtJKG@#wkQ#}hn;@U^ zK-MfI$vX3$Ax050Go!%fP7oG$HA8YNq&f>xsK2Qg^~H?V`*Wc%;jxgel$(ee7)0Eq zZZ?xVtJ>K-&37NW^XT9Ci|@Gg%iv;-c0%?GqQ-q$~4(rr)H zqKQ37G+k6VL}hkcOmmCvdii&2>^-mF{T-b6Fr7V3zUiDHLKdBYcz5-{U(*Kq%)j>C zXTSj@AnVPsMMzBxY?3n^K!!v(yqjXa3tPx>K`fQa(3Ns%xL(8Tx>JBDP*HQMG|Sdr zwe|)fyHY>0lB#!V3BT1pdyq+6J}>>cxaimqL_>(&&;CnqUhpvoqHjV;qwM)Lspy&e z;()1F*D<>*LCtk+Ge)R53SvZ6hoN{7h`T3G^V|WHJ&DbXQjkb)2~H%LV6N=RsTIf^ zLA*}fWobFbF3%&?6*sYJDyd%V(m(&>@BhHJj{VSII&=K5jOw=sJA&aqt$*Uj?s(vz zZU51Cu3nh66(S^9DT6^y!DfhpL*9{T^;Af)XhD|xoJd$}1daV=mDMhvhq zlSCmAwgk8kGqs)WZ~V;9eQA9@dvTZm110q~*;q{R>QCkhk4{Q8q1oTz``{qOy#49WK#r7vbzQf6ib z#HA8)2ia(O`OF<>Hm+X3`{9QkeeX{``@$15+x_lyPh7q7`suT0XFEB~RVrv^sYR&T z-x;5|^|trF{}W&R>Nm!l-wN`sIxeww6i28|*P)tCH}m`=QHlThvtHJ>ewD_BdMW@M z2Q~hi9q!!r#@*iG!O_8B-lfiygUs3BgcKY zyo*u?4)6ca`;Hzz`uz8w-`d!D=#dAHojBs|Ii=YQs#>g?0p=bf#cY{_Aorz%uy;wx zG_a6s*L7Vt55mhUD<6OCv5!CY*!IFtu464reW_z(TfEp_1o^UD7ErB^vUv6 zIE9Ngb&>thziU$PzXVmYvJ{5{B<1QYO&c6=b#Q6&goMRRbEip@sS!~KkywjGihLz#QU3pyQ63>%yU1K@3Bf{ts+1P z;9j(@{j#}Sz9qByJwkF%laS3qEJ{mL}Jt$_{1qq{C z6t+K^w(}0!jH;n^;ZQX?GCX{0_1NKN{p=m54lk{Z4$I#D?DffwZ$9CG|iWK1FEZtTt! zXn{qmAcQPlee$mV#!h|s^P7A7v5G;EQ;5u-&9Vp)ady#;B1zNKQ6iMdq%-$`$OWV) zmO9T~RTZhLbE8I~=f1QwIF1!%!u2${GT-~LdybFrj-98wXVQ78N!^T`D}hFM zA`UEK))BGSLe8!;*O@1U2qJ?V3fLaD&tvIcP=indGlDuhKolZ~!2-ZFQB}bS-2`bL zg z9TN4LOn5H@DMsA#qH)=fm331AfR(8q1Q6i^U?R+ zmvZ|nzxLfvKeh4l47pkkF(^U32wsdiB&T^!r6~uo6BOA>!-?L)T8tLN)MIED;D}xc zMWrBuV_}p6n;A@r5h>PG#}K=mv$b3oRO}Qt+1QbWtO{ z#Yok^x1nfWoDTk=?=9UOEC2)MB@nFtVJE=zzMcCbW;a2hz@Qf!^u9BG^CDj)<&^0p z3N>8!apAXUy3hV@yZIfz{5ZO?!(beikIVfZr#tSp&1Zf0IfA(v%*%BM^gO4xB-7-@ z>cZiMLNYAm0*AYKp29@;FU)3FkoWr9NQTv^_Y7}&sM~yUdj4~mZF6;m;vvg(Pus*D zEG@cXd-Fhi5WjPyz^59iS<- zHm*^%8fso@y$V{_JZuKdSnJQvE2xR)A#Y5FxbURaI4auI`|il`WBtDmmAs|LuFPe&GDkkA3vynV+dfKf|;P zz?+ZMzRvkM-26)Z(s!gv<^Bv$LA z(R%JYXRYgo5JQNJMmvsiSfd)L-@3GXTRrj=ZcJSehCynj(Y_u>e(*Tn^WNsrqg8sp z=R+2DIDf-m{gi$2d(-E-wB=pw+{nz-Th|uCL{#`mM53B;5b&t%EG$7FoB}CJ z;=nSoPT|7AwP({IyJrm?jJ5B26mSU?a_-zsLLeenb7yACDZg^zwPC%)5}5-WWK>p$ zk;Ik2ED$1BHK!mHDv4^ys-a?KpAj61yyol@1nw|Ym9PF_ukUT60t4I9Upk`lh40+;q>s-aJWQ@ZkAD-Cr3c2i8RCz+%&7jDjq#? za_i>K<<~C$)KC8G*S`CiuRrxi-#!226Hk5j*e$nq(fEc(9X@?8Ev?xY>ZADt)Eo=(RGPn04sFAqxm*01uVRlnFa(x&^sPH&%xt#R zZmo|_GHNCZ!BTEn0(pTh5}egc$%#o=2v9dwPbsCY%hoOA*FmK#_I;zmourT4z~2k*S&&Kp;6 z4wjaMF&Z`Rd*6E=y#F0fJ@x&^pLp`n+Vb1p@wQVZk2ABG&1dr%1GrK(RgHCop-sw} zBnUH`c@Sx0CeN&{?69swW~WfHoo}fFa4We z{na-n`NWYE@BPT5f8#&;`9~l9(6AZKrjyN^Hw&y!I20xdi?~_u7w8d;aKN-*X~Mxw zppq!l>z-VD6?p%F_MYUhNM|JgWnpUz-e}(8cCX_=6ntyES5=s&?#9(kte|q< z-`*LFV#PAqYpF&>yx(@AAqgx*RUN0@%#fL=8t`N`Pnl`N!)h=ecMU4>rh>MeCH2TE zhGr(CSk<<4$J$-@-+ku;cb{2Xu6dcSU)eo>?c#S{_}WXCUVi%8%jfaR9M=NpN}9uR zDDdH$B_w8na6O=vfiz3iXlrM8x4U%1_9nic&?Y3stT0PT6VcnS%K1jj5H`!E?)DdN z`>)Qv?H4|~*n)t~~}u1g&HkSjBT6A-GJ*aVp<5P+^#cZm{$5GQJ9Mz9d1YXfScJiu{V4C`sAnX^bbF{_QdtOp1pptOKna`SxE$@>I`>gb&xw# zvqI9K-Sc+a*@>x-P7MLw6ni%?x(i27Vs_s5H)tRQltUqqlP7`%1V-_!+8o*e#T&t1 z`V#NTbFEiv%dZQ_T25=wd<8|;8?MEulA?T zv_>EzP38h2N-4)cK`3iZ%tB%yf~Tw@l1m)V^DNSCmk>!fZe7}2KlcXT{Z3mszI5mD z>YE#wcMOiglC24G-f6{QKX)bZrOi1NRjNZ(iMhWJi&#U1+zQp)%!H)qU(7*(Y6p-o zySbB#P#MOt1n(t~y;lT4fi~m7>F#C#L8Px*T-^XL_nH(bV^h=0l-qpQq1E@@ce+|0 zef_B`|KU$wd0}_nRU{qg}>G0fZV}A+92>f&(TuE!_lWK-mT_MxgFa97CPj{ATG;RIA>1 zBlV>LfwcXaU*>)*!k*lE^p8eSB{ht_Lcw+B`KSZ}h zJ$D+t`k$CsdVMd5$a||b4hApW53Gs%{c6#Y_iuyrix}x?PsGuY;f5aAsBr1ItfUV1 zBFrNxcUEDBb{PM+tA26r7hHYdJ1n_S)<&%{E_n8eR~>Z$9SJDLZhVNH@dnv7>Vu_D*5?Pe); z5OOmkgQ!#Ld^)IxAqFDPof}!FT1A?%gJ?|kmnVBK{D<`6=hi;@^ULc$SNUP!n(zH~ zdf}`7jm!HNg56viv=vSBjH|3E8>v*(mBl8*+|6@2c36nu`_sK_Sy)7dEGD5Auj{&Y z4M41eo;_FYE|aSZQav-tNDZPsBizFfxnmZxN+ltfo}YceeUzNd7GxwJU4QX8^J6A$Zp9sgPf5qDP==ebeURX1v=N96BvP*SlCHajU`B| z;9}YVx%f4uqHqXFi^nP-I(h7W{U^V)Io&+He7lI4 z8aahZhD*y=ZoZsL6i|O%6H)L!RBW-Zav`vJE-{a9IahH|3ojbfgVwHZVu_&U?|krM z*REYW_xLmKyYr!DFzPH-qlyQv$Wn2r7~;-G(ubBbb#>bvw_ZGd8GCi z_IAGc)$e`dJ@5TcUDuP{sSHFK&dEb9fK9fhAAH{ryzhe_Irr+nR^1pJzIW#2#vB4n z$%jA%>Pn#lfTSY#@-cq%i~jU8=m&WR3??iZ^*puRWGPBaxn*#W;A{pXXXfHu6$XrQ zrkpj8XZxLxYr%R&#|Lt_Mq~$(Dq8h%YugF?2{VJ{VAPN_F-8$c3}xe5x+i5tab5)! z#j#n=xojUw1Yb#BDJy$Vsb%IMY}si9=s@9LS%gssH-MJ9D36|CS4J5gFiA3(P%mCobZ0ZLCm(uy7 z*8>uP)T~%lg_)T`08#%VrSCPfLcDf(R@1EgiuTR%xtp1)wln7uQ{Zmgc5SC-U@|u| z;vfM4g4J=J+Wql_$F#CGicQ5tc~*b#J5PT9nP=YrzW06jy^ntJ8=rF^7oaGMmuTHG zH7i|{m@OU!v6vp@%o6&`*%mchKUh8}V9JcCcMt*&pXvU7+C9|VK5yqIkDfkv_0=!_ z!4n_(i|;)Bo9j1jTv@KyZu!AexW)hE|NTs)c;wJ}J4-t^+x24vwc3NIc9Z$;?#_JP zF_Tw@K+A)M*Vbk>pG_tiIXN|fnqh%p)5=P{JDF^E^R<=L!)wdC`}>pmY}(DGD#DGt zHQP&;1I5|2LyJo4q3>G1j!3=}QU=&SR=QIx-LBX4F!S=p=ef;(#%WuDJWp(55RlCe_aU>E* zf|tgG$vGkns9qwAJgjB$dH6ATtb6lzXnFr71rg@(DX20S|%xXT^~Rfz7X+Mn&%i*N8p$5>s8 zcb{%X&kV+xA#`f%!@*Qyx8F@uu7uUpm^)Jx?=lo5xp+c^-4KL~KyJd~<=8LH3Ok#d zWrZ+^okhg@bkh>N%hux+da<#URb}t)FRl}JD{;nRhC_3xQ{f@0I|D++IP2MR89}r~ufe6ul_FIC$35jP!a@I?w}`qml`5GA6jl(OVwq zmTvpS7hd`B+uwckwhx`V@HsFL8q`B{bEFC42vGPgP?8jALC@7P$B$eMN6Y(p%(<|w zsDBkfi+-|HN7na;Z~o4rk;B1C7NP&$#VrZ_pShcXtzTUh{d+OG7yv_D#+iq3Ibrik z!K*q@oSaMyhC9QwSWMqi$MmspCv#6^Y$t(e%aT~V0Wv$h~fAL58e5b z`!9W7^L`kvbX!kZd#S%&^a+kVsjy5S2&G-H#nbLwj=Neu*71^O4n;lxD? zU?q~-&B1JLP=MSl5fPOQwu6Y1C!xTB%-x_2oBL#zXJg%u6j;OnL0D-9%fr$2t*f)# zg%G@i>XF6}lIIv>*LB&{g*uzGnks2DXQA3^G03Q18CENs9e(B9YhU>9Y?{>r7z`F`3Rtd8DxWcAkd)h*2zZrptK`;{ zh+gG+&Ro@Xv()B&HqorcUbYP&3(V>n*0w$!R4Y)@l*|ker94$fRl7LXaWmOxU*DMh ztLr~~?>+U0tN9mZU;NbM+Y{bsbhaX6Py064N|iKmXRzGnY?*|}D5uQ45D=8ARjr-R zm?VUX%rvS?W7R%MYy&8>aJnInMZq(djC^=Wc)C!^8SRA>ZyHl1yp( zH9Y>Q*=N4B|JoRNSb3c*Mn`Gdwv#+}HWDZ_r)-718z`xn64;GWvNomGsRO6d4N7bf z$g-KK6NrT9fidkIYD$Ei>8i*PbE5)>J5tYdByxw8XG zAg)j~og8Tn4Mw;z-MXohBw5XvvI7hKh%k|=YU;`vYB>`Hk&3ADOrTgvrRHjCEM#$o zM#p4r$7Zg^%*4b*W=>!U5zw5~nb>QQ!E$p*=UF=sagcIyAV?&GIJp{gbY>D{Rksuv zL=-rf!ofiben}hvR3wl|N-j~@*{zZ&$mT#3V*o=@H5Hq2MidFexyx0ISFi1!ITC*K z&mF&f;ljQ5-#yvd{q5iWt?0ub0s|RDm_q<`XL7@#RLm4`;o3}zdVx)U!t}diE&ba< zaI!cd56-}TA?u5kD-p#kxWYTFno}^8deEX2zeM|N3dq*F9-|DTW zD2%tc?U12HU82d%H}~n$wgjm{aKmUcl$F3jmhH@$Ti*V_ebfEv z)6YJ0?%d1IKll9l`r+YVFdPo*rm34oSV9benFE`7h_SSn1~4OcYG(6!n^QNP&gS!W zygRvZ^X40Gym95ql`9)p+LR6-S%2?`AN%kBpFjT2cRnzPA*FV6b0a4UF@_KXR0=E> zHZ?9#mZI+|uwN?R-kvR4ev^rE%0xuvH7Oob)8Y+dX4QV}X{zXDO1X%Mtluc~oo4Z} zmbbo$j+5u&{vu-ae)XENc3nBxp;;YXey}+0h{$q(gLB7hI#<H^c;wKbQ@5VHZ|B}$|IJ^0?zt!LzUyr#j^BFo=4R7KHU&sR zNU0-c5pwI*;^lFag$?zn4PPu)4}45-xq1&S*0)qo4s!BY-oLSX`OM&q7_Ue@m<&Jt z?>_%SKlg)YK77ZO-@AD9?MGJLwsh`~U%PSj%G>XHXu2~|Sg2y#*~S~&0W|XF#>K58 zw=D1NkFRg+E+1any*aipKXz();MGj0D&6MJ-pbO_u!*y2r-?#?-3=7SJdtK~CGr;ZNSZ#}WTg0%#DrRgk>w{6EUFXt8`62+3521g(# zOBv|5R1P)G-l0#cCItrykFGxU*FN+Qzk74#wd;GSNy=$HZH-bEB}ZU4HgE{cmOKXy z4suiVD3Q4YAEKM*ig~mgx_L@d8x5MnhewUX-JLMs-gPw&;DTF=LZ)s8qrePj%Uxl= zm5MQt{O|j2OtI9NhpYNc6hQh^)xGz2pC``%$3O#b;$>UyH8^BgLva9pI@h@c88lo zq+EW)mmq7$7vi)4NeyYZ%4pwKO00I+9h#9JdoW~*OKE&9kJNfD>GJhm2 zug^i*O-!>TDdj5|1U1Xbfyv#}Or-2oQ%&8y>nq51aWcxHl1X@b1=P^8Ee**+~TF{AkG1}}^ zX5w5^+&2%Pu0LP7Uyzpt-kUNsS_GxjpYB=@nrZ}kb4gk-6}}jmGb|S-Egi^@7biMA zL&wm0`MdgmoeJNgB?ys#HbCT#YLql zF90q8%+hd-rmdzK;3W^RkGLxF03jR#%w$2PAVgXb3xq738+7iTAU7?g)p9KkKJ~L5+i*#f$Ha=)BB>b;meepd{ zU;F8wx$p4bjC`8%Lw@=f2S4+p_lv8$AgKLq-5-Z4^2&U9!pBraGh9@WRVAPD3OlPxk^5Qoy$uU}t z4S^(3DXT3BMa#yJP}j^23wyuqfH48gLNJ4tVVoH=)MCM9W+N6R_Eu}H?_N3e1NYv3 zerx0NFFwDKwx~)@;%-g_qbJ3B1Y(ep!!43jAvA=jjsOW9i9CA(sKMaW=)^KFT^esu z2r;^OCilpZLo9PI5hap9^=h>?q^b?9otdcwX5kWX!6BHcJF=6L3Q1YuF;N+E7mX-D zWm;Xu2$7s1LCj1-5CJne8AF&jQV`+DQvQ-aF60QpqSvlo{fGbcU8^IxnWo3?y7!m= z*{{C7dvSemB8HILRK;j+t1E}E?_TVDQch%YB1m!1E^v2FBm{C-FX9$@v&zN6aoeA~ z2XuHpkh>Hy%8}KRH*RkDJl=QDz11?$r&Eq-CvydwDpIKGLB$MJlfVQ>ASV-!x7~Z& zr3;tddHSIT?|lCg&wl-Ce(g)&{@erizda0PKAShGAtFs^s$j13-S)9heDGr*{K&ui zoqyYopBo%{7&>hCr^#BNA{+x5(Y{j&yrws3xboF|7Wo#V^#kB&O z21iG@|0GrK2&Qs#T)le5U%E)oU(L_l*gvyKn1h5iGM??~Y9mK5J zQ0Db0Jxp&3%Go8xd*627PyX~@ICJamU6)eZ#^owTW}*H))BD1D$G9B;DWSgk|9PNW{#+t0eajP`9&XP{r2l{ekBc+Q#4O;vNwP%Gh&A%v8Y zoAnt&LNQ3rX2JWVs+yZq6wOAUs*XgYS=&kLWGuuYs%oahM27NQQkRGz#B~#hhSSOH z^$VBpy8HHr-~G_b7hd_JFaO^D_jjAY(r_>^GJ$CB(~=xqVz}ROJ-)f;r8hw!MKo7l znYUcJZ(gr|YWz+>Mz_&j>S$ht7@ZFfR$e*x%H*Z?*hkjsqOU)^wt4Bs)1QCh>}_{M z_S9K3sG1{UInUd)equOHOLJ=vt*osLmIl&vNb&G$XS#K5y1X2Z4A-*itnN&8Hn9*w zYV-cqSU}`9-raj?Yo9f&*Q4WMWo1yW)rW3Bddn^K$y?S=92%_+MuXj(JD1uk&)WHffVKodZS{4WkgG}esxeHZI-9%Guwd-^?olR$XYM26P zacL8XLs_)}PG&HIsUr{tXF%B5JTvoBwOkRq+lg@a1g-waJ)ij4T|e{G>(h;mmrm66 zC{7Y)Q|O#*JnyCxYG>ZT%ozy8ERh38mZ}<7)rcbnVR0Y~B*4UtV}(&zs;jl-A+qkc zhq@vr(-^1-%}pl9yL9+kKwa%=EH-u#`{)>fx>$d?)n)QuP*b!{ESv1o$XDf?{KL7rz| zqe_s?)WJk`B+ZTvvmFe8J5J)row#ZGQ>(YF-ncqmCP{Uew>q89 z#$9KCnS*Ii#ag(GuI8@9EP!WaDkokhVmCDu&nKJ=KtYcyu+$vAb#%+_&fZ?0a32U- zOq+ z^*vs972OqZbTWX`&biCqx}LV4YnFcc&{-d>pV>V(Fx{!@lSkGc*xlV2PcFH2{RY+9 z7pb@axhhdXIBMCkqo*SsH0o0FVlcao`7S(zMuQU%hUUol!l!e$d-}-3w=SJ}{?g}f zw$}&ow8Wve*5v*M znaw<#l4xv#vXQB)dqqP*bc;>XNJU>7Z$0xbzy4F-z5D$?f3o^SpoaZN>1`i8bo+0t zeCs#2zxT?+2^5qrr(Y*Sg)^ZoWCOnRkO&PqO9&k1SjRnl-x@Tal@u;6PJ1 zZDleVEO%+v>AdD)&RIB=*r3*ugcz74)DDoMYkg0-TlP71({ARXuDR3B#0p9+Yvv%U zYinv~)2y4O5}wTznG5uTg(K%sS9Q)bOG!dt6|@))tF^l7Ci==&=lk=!mg)Yx24_Cp z$a~3-Kx)qyvHb=6<3F5!@s+*Z3SNgfd8_R#cV->KlI1D74l~u(pyn{k5Hg3RUN)z> z&D5!9BlVJm#LVPfH_dshp22Y9Y|dm(Y=|M&OsuJOG9pf07h+8=KnQW*eVT-udXS3P zQ%=3c#NE_1by4a{0%v$42`rI;7%gsJ+da?McS(Z}A{ukfngFlZjQS|lz(G}A%|S87 zzyr?$qR3ov;>t6`MMP1BYUcDDlPG83a`&lw3rD zkY#tM#JIaVUy}AO{FPgh<-^C0qSOEVSAH|*;mXvDd8-*#DGt_D@y9y?xYVv)x|eqw9xHP4+u=RLfOP zrl!;VxxqM8Tm`Aw%}I!eJi#b0uP%)SgPrTwe*8y2`6thO;kj2I|H4;4`| z_swft^{8H|NAotvA;+d3Z_SUKUH$35_*cL5m9O5s@x6L!|`tV zGV})6HO&_zP+DxC_)qD93Gmvz>Gk9gcvl8(YokLanv>(*{iYfP3YImK8o6r9ND1xs z^t#aApF6wqS3a=vz>!JQ&e=17aBRtCHEq7ZP0^YlCpRL^NE6rWqDfNoKNiok2VXiZKwVZQFJ}uLt$0X%63c=L7e@O>^Gc z-P_;aACJe=>2z;*Z#tjOrZZDD2a~gKHE5dQAcQa&G>6yMmzS2;4y}bKA;hL>>ZXBd z&fR!>vov)gVK8W{MBNdW?PcNa79DR%uUUNF$jXnIdEZ)=lFo{ft$e3Q;eQYZ2|;2N zrqii)$|4KZm1pgLM6-g)t)$=rCGWzlU*|eBDG4z%5gD_q=By=JxybEGfDniz2vnWf zy-$fG0s`euO`U}RHiuIsQ|KY#+14kY?I^7+=@|(}C^78s%1;A{q%o>KC z%=Y%CKBPf4h=I?)cy;~IXmx40x3|B$yDv?ZCf#0ccPIN8qycfx+ICrnI#Lpjf#vQ) zCs&TG93LG%5)YqQJ$ASrhNaj}+sSzE^7U)qd+kr2zwz43yO-X`SFicCJ!}?)GS+KPY?-B6AfXO=ey(WSOsplmS$U*L~!bJmTFUrJd zBrcrQe)JuG`9J>gpSkVuif{SxV@KDHAFo%IH(uO1RyRMg9Br8=q^Smr^N6OY+u!T9 zZqB#H?e(qs?#=n$-fVBuZf;DkZSQT)kS0ybO{@o@uB47&q7ay=sscN0ZA?>}=53FJ zC5BpOAajO95kNI(byVvC%nEGLH*7aE~=1Lf3772sXE`O5CoUo@|rtCaR62otG6Sllg}GI54xcQbXEaLA^S zeP;O9^DiG+S|*ADH}&jjs-T)@UEZEzcdreZL4(~Jdv@-!{J2ySHuz)Y+_Ru%A2>a1z%i5z8OUi2x%&cv7Zb~pC+9GPP@2N?=m8dPM; z=HzOg-Gzz?$ecvI*X9zi+4az1xR{l@02Po_)1 zhxrYM!3}PJfEk_v=?&-y1CH_y&CTmZD3r;B7A+w-HO30W4Bp2v}r__Ck@O zon5SbixG68#UWxR?_U2bSp{sh)~&CddEdwXi;cbUYv;dx^TOw5`!5TV z|5-#b^*-E1;kan;3E%}MkbweqYLQx04MJ3jpa{5W9q5p71d>t$%o$)opXXLq(1k=& zxMKa)zj#IthT9~~jJYcPNvUzUI3EDdQ+F*|7ebH1B6hg-N-F}O`p8&*O_I9#TaIJ4sNOt4cRyYmdMCWq;jTYu5P79YvB%x0wr!W*P*5uJDv%LFsQF) z`ZrIX``&-M`R6}y`|UrvT76vn2 zW*%RkZf2M?VeZq;I}&ri$!Re&CuVk0vkvX;XKr8Gm8-As7&J;n=FFj70@a1Qz{l#fGp=YjCIohY_5bDLj!^k70I@#5kxo+hQmP|b#oP16B||; zRl_E8ld{ipP2D@*Hn{hFqxzBPcLTv~6Z>DsH$Ff4!i)1O*>o5+dS{wh6Q!)JQ|d@t zN(pUiQ*a0Oq=`a-vk{3n!(qxfTj!)sUgGuKEv43Ta#xVBFkFd(lR#?b8WK?Mj;5|k zV6YGZb0s0TyC&5xi;xJjfud(qcrGFf>Ir!)QnJj5otqe!QBNn`{8@FR>q=4u`iQ+V9Qn<$$En7{f z5k;Y@?k+*tNn4FEI=OXLQ{8Yqh{I$~%E>J-gxDO+5?I*S92|nV1>xd9>Fu<|HpK`r zY<%T4r&Z}V*w)uYh$)Eb+&wTdJ|C?X`=acPcSC&r< zPn@7Fna?JJwL`;`$G6Tebz9#ACNKpVda!?KR+;+Xu0DQ1LhT&PjHDq%Xka$g>4_t! z?>%<+6OTWYHC0suE^!F%jCq>w&u-qm&VTd$xBt)snI|{LH>T21v*yhmhlgiw>uy|v zr%*B1kc3dVDJdHZa)u{Rg*IVt50*1r>jv*Q!S6XMKljo2%9ZLH&*ZParcdtdZOxIC zIgVmoWvvV(5>!o?sgN73#O-nMCyDTEKD&JB%Fd15$Hwrv3qK}6)((W56%o+z>|Vz#UxIKU$A{q;_On}rxPtEuIb6}q>(&HHRQ z$0`s}2!W($Qx`}w5i^qm#8f)fQfW}X{qz#QQ4(c($OjzcTz(S0Bz7@IDZMR=a22Yq z>q_83sog}_%(P$*OG{jUIKCiC77-LcQdVvxA|lWtBrYmDqLi|#5nKzuSzXPTh=|NR zb;;pwNL@~;V+N75ZP#@vC(S7nGjm{K4uOz7I~B-frrhNaaQfEcJJ0U^>wooY?|#oi zpLq0#_Qt#C&cCoUT6J>MTv*dx*G8%OtFU+SIvnJ|T@R937gnytEqHMgKZs;qD2K7= zSNpBNB#$>|H}5!gSGSXEBx#qv_l>7N`XB#bb#It`Wxv}`hu4p`d-LpO@ab$e-)Rvj zc^>am*Ud2L##=k4Q@WwUQBwh&)0snSt1AuXTcjZ~TOBS%ua*xDhdf$c9TAxiFq=>I zw|6gGz4V3Go_X!&<;#=nug|Yv#Puy)12U0Esw!#fSRcYV+zA>2a!TE7&cqUerJOXA zP^d#TZEe0g?UHv2Wpbu+MlDEPi}4y3wN&=fgEd0SB1d9%ydE5p=4idL&h>yJ$t)du z=eyomyKO&2ZLFI4^r=e&TRM6BYF&@_FYPU#SdME|-Nab&a9xfZYC;?!t(I+{5QIT< zv^RC@dUxr{H}+ZPL<}^pl?MtegGQt#n3I!8B#G--n8C*LAltHR4c63Z4Lwg) zUBjKu*?X<^{;|(3Df#^Tk6Ybc-M4Suv-cXF=lgI}X_K}#R-zDV=R|A-&K*n^>#LXm z0RR9=L_t)62(I%uL{Nymg{d%qw@#bDa5V}crSSOX)?jnHuKIyF5F@J>O{|2?Q9kFJON1EeoLQg0B(sSx z9;|P^Bw?AREFmP#LKH~Uoh;vc=<1|+{KBc3xp%wM0%oAx zA%7Vlao)@uc@spjM~gEWn`dGY=5ig+*=sMLYeDR8nlcLrMO7s$aY-@Dc>_-3!G#s- z!+V?;z3%Xbox_1ehNilR&_~GuTJ6qwiyV~PiVSVOESz_F zzS9WK@2hUXIUgN%Uot<6-2(tXh%1h@6&WK4olUbekaLod+q|?gc!nid^CF?lPQTi{ zX!i_f0?&oZ=$r!`YrYFNDM=ePUU zzWvqwqWo*nH^FVp=#a1+T&vx&QxldJ_dGKxkv6_WgiPT1w=@c;4 z&H_ikJmg(LFlQ2|ZijYkJFL~v^5?MYY7X%88wY)x<0)kk&z}Ts|cxQs5`TCEGr_Cb~bCLqs8H_ zOL5%JEJV0b(`c^>FgAq{VyV&sU=R=9q)-JQW}i8;I!RGJgqlD?akMp>&a#=*^&lq$ z5QH2i>{YDDt3W+5>DRsJ$|j5TVAW;UOjm7m<1XBJ*W%v$hJHJH4?f29qxRXqZ2soq ztrKH!Lr4Qw*6cZ1ZcSTH#yYcU+qTZuQrqej)B;L@vlG;$szo>%vZbVrQYx}=5;oN` zm@dR7+4!PSsf%F&rb9849aUUs4xlB5omUINgaB<|i}MY`Fi?bLIaD{bc56Y9J% z5Z{S(LFeQ^H$`JdYVxdh-MTnxHd^fR?24ADCLxOb*jo%>OO}y6RHAB5h<#2oO_sx; zst1GTjz9Y~U;EV$eg4yb^}#=Q&xil~?w8&5mM?hI`7>*S&Ee|8YEIfrQh!mV8_mk$ z`rE(rTR!#R{f|BVXuWdH;_6|tLwP-?YH@h@cCUvQAGqSpW1#KsBJYNwLKMp7Qv5D3 zxQjzz*&PTyt}5~wbh0#DT3uP4VV13R%c-4OP$eBVn@zs*1vjjI-F$?kbx#cHwMqA!2IQ7zr_xtA|L=WZ6vMAdUzQ3zV}rhUSWHu4^T9%?fUO zyL`HWM&?#r2*ux(a|VH!$y~LB3&PE^stB8V(b}j(wcBE7 zGIwXDoXm2T5Lk$a+os7msXClOkP^59McX8ah#%@v)L@vA?HjA7HG}{jD* z3A2moYy}xu-S;%W;Hl3YPfr^i#^6Clm*`*vlbE)S%thpW4G4GtYScI3v}kKB0uAs^-SGwbav?O7RIbIt1heS?+d zuzFK(|H}ujiTgMb8Z?)D`?77WrL`-~<*{weaOUFd(Pyqa_4L-pmQJ?}6zWh(KX42o z1c1$w1R_XkShyDl0of>943!z9A%VatI91GT=UXLVQF3(!5QP-(s!kpl>YB5WP~gbK zifo#h#aqw0-AI#j&1|@Y`>tL2+@%|zdwOjvJ3?EOLeS*!qEshg&*r8G@SKXj9zbck zD2;sk0uEeq79xiVTqGj4g1 zxiMDLRMx89;tj>+?*NdE$%)jb>r^kfLyfX46AP27b|xh^byY)PxO$s%9i&aECqaoC za3FG35EcS^GG!o!X`8Qj%S@}is-1+%)0eBwE55pyt~uOas;;a}r{+f7W2xEDrbyD7 znn6>_W+F@l5NFO5)Mv@eK@7^B=9S&&&{U_gN>xt{X1ioh_B7M+i<9k(=+p`;2@lOnN_W%VwL6BL-(EfCz1HK(GMF$IW; zlUZxo2yoK5QFRA~)cq+hYS_%nU_#h&U~&1DmBWkFdv4?W@vZYY1X@^_PbI|^m9J8Bn z%-K>obzho>=12oZUYAG)QzcKGZ@di*ngJ6-=g*hvH+Vs=a3 z)$%2fLWqk0Sm)c`oe^~zFagEy8icL!?MKkTxT3{o6gH9&P&+%UDaUo^kad2+%ggqn zV2F-~0f%$h%n%4&#}0rDpqxjfDM&4$r+Ee{G6n(}N)7?j96n57V9wMk^Lv2QGjs9H zy1|Gb9Ewu3*X#HCyC$P`Rc8+FX5?UXG#o;*mbe0Iq8T9=u{nf{SPhol1d%x?rfyS- zi@m|FrdoJ#ZR?T0J$~C~&cFSuZaDn4gLpg3H}F08t=#@6OP~Dn&Bq?UvNdXQmcg(( z*k8SZNzHM~wn$~>ZDvtu$}N~m{))MWP-(KWC(qaQ(7cGF*^QWlz${@9`(dV4WF7)N zP{o01FbEULv%h-Z=4UV1q!JraL%BuDNXAI6jkcLn=G>+> z(JWKSo-Abb1gHpm(W0YOHFa_+x0IDS2~_aBUdFD(=FTJ)2|GpZ4IsfBTrtcwD>zCp za&rXYz)~?qQ)3dULK)2}$WkU^iGj=mlPkQ$fNbvA4mJYpXLOv4TJ*A`f+}qDf7$uIr%UPB8?9XH5W!2sy(f z#;U5LxWp>dq1R|b5|}&?JB(NuRliy&OvyCMQpuniw5m*z0Wt)VzElSm7W;Kvn~k<} z!z>cmnG}@GTv!B9R37?0sfkSUAO;~}j_zi#mRUrOuT5V2x`kJ~tX{uz{=lAnXOBPg zzK?x;cW+-W)S-%19mgYG-Mcz&x7H>X05Af|(2|0C8KW|D@Is?^WfWIora3I3+sZ<` zbbT+DuDl>enXg)1`mvhki`n-K236JLr~!3QQ%`wesj7xiB0#39${M1O5E#`UWX&Mk zf9<~Ko_!`w+i&}p?>cev$tRw9@HhYDH*R^!O$QGjy0Up`xH?!|9kQUrkZxa^-1GX| zzw_Jw@elv2AJ{niq5ke`cVB;>?%f-Earv74SmMo%duPuFjGu&WIu$g<98xehdbk;c zA(fLr21LXG5*#_9#Z~(c96Yes;1)d7)TB|dQL|am_SfBg?AzY3dvW`*(er1P`W$*# z7yy5YRTBw_)p9B5vAG zw_Z(Od5=7KN39= zZ@uaIdtZO|Ywo>!WpS05nayFdnO0RGFa%XEcG!xNK1^g~uc+2_#pWzbbB`32D4o(^ z7L++)1x{HcK+I*MT7*I&6o-kEaJfN!?nNQ$c*rk+f8C4E%d*q_GM%@{q}?*M({`2` zqMSv{3@+tw@wd$z+)hK=b+DayPRP{VO@g=?3?ghW5m7bO3_wJ3L9|6F;$DXZVRz)L zfEPX%Kp_eXx!2>7tE!MxRls6zHp6V%=GJoV#<3D9xR@G8UR>=@MznTeebeaVz zjy67W|Az)=tGep3WRQEXoV5h`md8wpiZFlyCo1p1&)<-;H=ZZhztFM1(6yGvZ7!3a z-}Ic3*X&|Ov$wZ8NzEv@^yt#Lwa5SNk#i@{96Wf{uHDQ1{k^*1V~E3I3xcxHZPd#>@Y3!yhju9qHfr(1ctHXEN!?IoXFaht%VL=aYHg*i(_gGJTL z&pZQ>h+(}pYjo7w<^ z9EGW>VG>A5h=RJ!3?xxt+0-ORBv(r&%z$tT;>DE}SjrTtu!fnPSxwu?cw^Q~)SUT5CNKqodSIS zeq4JL<277(+Vh0m$s@>_Q63_IfWTanz$lPSO;rY09k}(aRXsfM&ur^y!M2LYMK`1+jAlyksMdaxV zryI=<3M@|Ztjjb(S2E>p~l-=e&w>_i}QSJhY)^Dyr$31!b^aL;Z=J7;WH5|lHa zn5n$1P90NDaVCoH7{vP8Jy-Xu>Qm1=ai$qp{RO8kWfcx|dK#h#I6+Z($xs7`V$seq zsRQh)kcwoXs(1GWi@iaZY;BFw<+d4PbA!m78-y_}B(nvGfCV~lO3Q|FZnWI-RlMl9 z1W;!A&YiNivq#O6JTI=L(dA_2{V!HZUWM+(%94a=Oh#A239 z&4~zN7tVa}LJ299%H08lm-uFfb1e(|hlj~=gxhPG6~KO?amGZD3lU~oQo>cp=QDzRl?x{D8Yz$lD1XdH91>rshG8s z&X^;kJk^w)B1%*?WzB>fDLZSnmNitNW(#WURC%4I1Kr#nd-CO$` zs@1Qq`4|@eg}nJ~t2h5f@BM#q`T4VIAi$OfgIWZMi~^&XS_Cx?GIIxu1afG0qR_Tr z;n?f7TTMGlJ?V>t)Ob%~;6R0sB7ndJL`2zp{WypV?O2(EkR;7cl2Z;47^%8MiJ@kd zx~ffGHOH!-lZsYVwa|-wF^W?jBsl=N2Klu|dpF)kE(QuEsFtj|7XpMKBw-+pd< zCdIbjn^JO8^)@57mRsbc$=GJvWKBx5jA_#B;!3S~a+qf4z(ksJ%QB#9(RAXL&2u^Q zO`QZ?R98u)V1Pu8IQFFKE2x-A2@V!QHYY-mP_xu#V#Guoq|S|lj0l=kLQMdxb3kev z5JCuSL9>HAu(-N8C3840_ZB9z@m5Mz7^HT#Jx*`F`I_Ae2R`}8h2tCBqmtV$n6}Bq zh=JUu8~`g6R8s;AyHHE9id-zbRN`KYJPV7d6G9d107hov(64KNJh5<1$d;X`Vy@~~ z!Pv5?d4Z2xYavuD=H`~&g9Hw{dcCW5*I|=&V*~>^xs$oqp=whWAQBI%UX?Twsw#pA z3d#-xDu!X&SklSYf7cPfh!aux&ENRbaoes8cUeN!k8G54-n;wA=bwAH&6AQ-RYp@p zte&aUMwWGJp5M;hN#fl=vGDx_u4P8||F=LaH6oLYnoAWOxaXeNE$`kn9?giDK*e&E z8l7yOrtM(U7eRxOA&dA8mDvw!xjk3Ia*ul@EfZ9Mm(mD}HV%`09r*zJAC zxf5p_-!E6aPA~7m)^Vis;07GZT}54du7iZ6b}yj|0UX@CVaMUtZiM~wHQ5Uwa9f(v3sGu=6Y|*MpNkp8@GUyzzo)<5dun@ z+|4;67^UO{lK^&?3UDZ(3PdQdwdPuk!>xGy3_o(lA32+kUtT}g+H6KZ zKZYS<9YO?G93wf*JOp7!Zu8@hJ$d}`;~)IM$6xo_*MH%cy=is#F3Y(~l_TRAnp$K9%C2`7S5i#bP#g)U9WlW`Qy)?etK!R%7mOuVnBdp1)wP_a*Q#h zHfs(Nh)A_)96E{STp6(=g59~e{Y5p{yaoq#H8BwZn`vWfd+XZawdXEgTJ8_O`fXqJ z7a#cB@BZa)MfZ{H)#xwrkSt0JY7`-@&RV1~CW`Dx<@-qp4iyRj6-ggcMZ^;N5wZ~L z1&@(}keleF86|6DU?ESMA_q@SU5U3vNw%Q8=DyNJd*1FI*W=D zATU)zA&LkEID-Rm1+JVH`-=w=cB|3mmFF&9dfZ&y+)^US;2Cu0J|O}@3qzO#Gb>q3 zLL7T;t$AV^P%jcFF0ER%nkFf4ZWF0^lh#fx9oTpDwmW7PHZD&;bE>`23)ft=`uJ0u zx6Swe17JM*=HW! z_|QY=j-R?XoYL;?{>^ZBcAY`+SHf<0T$f_kv>IOFk zIhkr=i4?>PmMsKg!pW^mfAaKnT2lBQp%n z&LNkNTGkx0qZVOCX`1e85s5to?0=rG)o z0hhtwd_7#Y_n@4uc6o7w*PW}SYk?6JsoH$wN3rC;bU>dM4&L&8n?pf}+fe@W!Kmu<^+6ffdXY05Yc%Kvgz)1{XMinWZWwbr{_83$eWA zmMFt+j_hQvfO^qr5fRLhA?RKVe4g3k%w+1d3~oB~%35Uf^xAATqN0579B!R}*Fhk5 zpc8YuQ<=;Zh@6{S;|{P8xNuI1B!q#Gq&!xez>Ua!ZuFgJa~BhN;iMI{7z=ljMP|=B z(mWN4L860l2@7U2s2PNVaW(@v0<(GJ6bXbf=yw$f*>mIo?$raaU>CMePjnhMa=mai z(|ex1^yp7--TU6FU-v^R)xAV7^}|2Yf5+X2Kl|UeKJuCEcGju|3A)@HQWaSzIT6QD zRWWH+fG8NjyZTC~su!1bkL`+%Gl-Z(0>w~Ov8sbZW?T_!$bcl0FcyY&vOG<3k`q`M z5v)v{vk^;GMPebRUaXe-12|76t+BH?QLLrEApN@4rG!JUI}hT{mk(E8AN=KlCGdI7 zKJ3qYxcR^%lgF>vBn~~2$7DKfQ}W=6b*fF$Mj0lWFikc~7-w&cK}_b!DR~#^%i`AN zaPYdDhPzi!KK9w!q~V&n_J+%n#3&SY7lQ?X0ijTXqA;w&SpbAW zEA^|oUscTF!W0BhH%N#@ z#~7s&E-`7Yur}o=byfFTwPGoEml$gnfpfOZ2I)m24#Fs^OM(l6gsi?bPJ!4Ay-<;` zS}x;5Cj=uh?+Gu)2xWGKDhn}F3<7tH&LU5rn7rcE!~0&>+n8QnUEXWf{MjG<)$Zy* z6)RW3e0wxnS{Wv9&TpMDI8$&3BM8^-&IRmb$^?fJWPXayH!vN+g@~k_hfM6Q4(!0~ zc1~gf0RqZS!>@bow|~i--&Uzv%OcT*s~(4%Sj-Kh&FKPqy~T8~hV^VCRR_Yq z{rCU+^x3n2_1<@%`PBbDdhL;g)q|%Wdj7)mYpx5vvcL;N-#qB+Phou8byNc9i2yE0 z!dj{YQ!xctCywcY zBLtYCZJ=AO$*Zcp;|Se(Jx`6+x5C*Ac>1zFd4Bfz+U(@SCr!xSmuewYeW`*bc#zPm zVvOFTC!TofndeTNIQ`VUci(&GJumC`7lKFu+m`Agr7R-du-B~kCJWk>x+yXfb4N?+ z+$!Z>Fo23U8AKfBP^<3NDIcRbIM6$%3lo)5m!r#M=qdz8=}0?u8(uKq*u0mWH=Zaj zq|?(8m`F_>#Vj+=CiUWZbrerZp=%N`Q_4A~%&nHDw`p2tFf*K(2|+X~Gc-Ga27`W9 zn@p!|+onnGJgUwiIJ4wrAg_BB0INf4bvm9*rws{72vskpjNGVZW2UfB<<@eOLKXI1 zwR<+5e*9yfyzP$L?tA^4&iv7tSu^U_3lc6(*yXw|cugGh7AIk%p&Cr3h87nW0pnYdFhQZVyCp)dV9)Ud!rPRQAaBXc!NPF0xZ z*?8^woQ@M`_o-VV5Qk8}V9-QN%u=F*nAubQgVXvOuYcJW?Y(JoeCw%66Bha|O^HD^chBCjHo3DJ zQUFEvw)pD}EaWYwo8D%KAofe0*_G~2Tt*fk4vR~>j-lUgHyoC<9i?WodG-N_pf{l4 zuF1`)1G_3f#LPm)j_PheQT8za3gT|Eu!=p`X*<%*5kg{m;V+i*1P~cKnZYfTJP6_< z$OK58%VySqChIUtV3H7}Qc4UCgI z#Sckr-OAO4nZT^s90;)vGEk!Itutj;2q+Gn$l1*p4usMexC@u8O{jwzfr%Vy(YV=0v+3Tt6F7hXvM%Pc3g|I%)xnRblU>7ikZe4+GzQGu zybfR2eNsiJ0=iNDyjw&`fq)Zr5U}}i)(vKD-UIKfTP?ge|J|Vg!!rS$6L{|NfE&z+ zrMtpp1&hZJP5~!Csmv$36=HdzJL01*@Taq|5{lQfbhq@PiE+7T3vV05C0I2`tlibE z0Vzt-X%T;ufE$7ofRGcQN?bWqt?52IaOMCfQ!je%B4Q{DimqNP6+R0iQmHi*#G%uF zcPUCXcdEW9yMh=@GaVm4|41NA+6lmBod#T@iF#bF7J5As@md_tp?@4;&!0)|bcbYO_ZC=+E_c) zwngIsSv70UG--UJ(QS(4&X&Ofqg*n}V4T$*eU;wU_EtOH02E&K+#T8ifT@GI5Q5AE zu`(;@uwXfdP%{e^F?a-%kc&uQiO_OBgcu2y-JQuSsYD4bVoXBi9p)Iy#DrN)J0eRz z$YLD=D785V_Xkx@_RyL2_%ZpiS029kXuWrJ|D`rPdTR6Y=dXaWyQ^B@0KgQ?A&Ml= zY93Gpmz;A-CbcA}u)xR+bzxv+ZM`KpWt*7y`vK1G?vPMbFsDKx6$(;uAj`x;A+Rbz zNm$I(TMsdAPui3`M2ZsOC@Tq7l0eD`!qJ@@i^Qf`lQX!kC4kk9jS^!k&A#Eg_SC_* zH?LGnd*1m!fA7@AbH^5MA}6?8w(0id>iq|wyKtgO8#E`~5rs}k;ZVy=Y~86!a5iM> z#-kmIkidY<%^QWQS=1%-zP9tlic==)z2i+k@{$8D`M_U(;B~LLdwJj9&8;aD$0&tN z4l+$Pn>Ny;UW_pY4luxyaUfGRRta?YnnNdM&pr0pC;#z3c?Ti?+n@SZzwplgd}#lH z@B04le*W20XP!HI=;;1tWW8ZO4#M{N$)T(F|JR@UPvh?xfAIeQmD=Xg-Cw-92JiL4 zk-cuMU2qJeEbpbQbG~)X+YRUx)^ZKvns@;kDLVIp8JyHZyvZ)7Uc)N_{+cewp|-fy*JXdx7;UgW1nPEXo2$Lf*ihC!yq?Wtse2s^Ju2B zK)T&pc973g!@L0OQ~~!;va1cTqFx<)!;oFvY_>hyxR_=$R0|ZM=Y&{6Gq%Q#v8iDg z?T(}L+M7T@w#Iz&GM+e(N6$xB*uS4dp zB{x;AWVc$@vK%O+H0mmBVuoewnph$tYTGuaJh$l*ilNm?EsQp`yJIMui%u)J-C?p1~uU*mB`on&ZU~CduljW&OC0xhpbT(z=(Ej1&k71t4)`7E^{Ny$mGK~ghQSjkZWW%n5ummW&$qybEb zL`v|Sv(2S*B*H;bhEWadCf>z+cX>$E z^xW|iH{Em3OYXkq@X4w}0sm9=q|Ly}$npAN%FM z`Q+W#?s@&uL%q+@-Y0im_3EqYs~6&-m}fkFdP|?Nuu|vcz;)R7(&}sPKK519V`m<3 zKJ&5l_kZB*XC7S}ty6!oUkz&@kivmjRiNBXl^{Y~GZAyvOvIho$6bnsksJ!m262g0 z-0VR}U3E6&iY0~#HP25jo=X?M==y`r?DpSzYWplQ5Bf@~IYS7{p3UJ9A`*(FaRo(! zW>YW)%qBShJoWeD@)@)V97waPLxcfnc7P-d7WRd(v^`x{ZB&Ahcwn#~R>)Jg1Wm96 z){?JLp8RfjrCQo%qENnX%?guDKRrTQ-66nO9ifG1eU5|s?Z2Im)#W;m(cs2X_Omt zRdMXOw`Q41T6iYU&<4;f&biv1 zpVIYw-KG=sRi$edQ=}Kf9pZ2*oKFa-{3p9-bU`wC$HHnQ$9R6=hIzkA-Ke0OU%$}l z(oQ!^^L7+Od#?36UWfH(u@>NI=P)n$GIabV+i6A1-Adi|wfjM*Ng$m|Y|6dBaCG}d zs{{3&Q_5qX|KmaIV8DrsTHU(+Z9!agd*qVN6kq};q5u!X39i)f{|alt0I&q%3eIL_ z>?G8&*GkHK?l{K9K576tSh_b@C(my@R+249ip1ZGE3fOt%Pgh4_nbHs&%g_l&d%%T z^KZWcE1gK^rv}8<7L6SRHk!snTuBUcfg_@)xgfx#OE`>^z5{FPsH;ErDz{`Fs}G*Wvh@dl!ap6}#D09M93#hy3Fon|<{3>`c-teHyt2jQ4OA zdmvb{CWSm}rZaCfn7KoU*m7=LpD8y4A_@>va(9Ikce_JEsOn2+o=?p-r6jQgLjz1s z#N7vgz=47QL@vZZV(dD!s)|)bMy_BEp{!M%h^45ks$`@aa`!frG6OHk(nVbfypag#G_kVXFqo0P=E2ds}`?0IymSHpTD%; z=Ij9sf(gLt9#|Lx4qS0h>xv~XS9MRM6+oi4O$vd_vM8&YTOff{3`w5dNn$0=&J=`@ zT_kb{o-7FE#z_JJFmg9CiV{K)D8Ny{RS2>5=*VErh~;kf}g&0QcZ;`cV`NLV>vL* z6P0l(I>#W$d8Y#1k^2?^D~WmH`QRBZoWFBR5M?0#qc{J^p1Anm-uYkOeAAnEukOv{ zVL%+j9XY3ZAoW7U6=IK7H7Du~q685FqIB9#mz*;ZuD$Kpvrjz#;3uB^&hPssVgENj z`J?~t=YF)R>+k!Ke|qlZh0B*OEiNr;wuO~JsKe;o`1)I~`ITS##qa#i@BQ#+{%E$f z&ey!Ty5W_!*wd{IBBF60(}52cWO#`4wl^cojfhA+NJ*?Q3PeF8WooWq^h`6kOhjM# zMPGjXORsn9BdQ*y7EOz6zP{($p@cipa~MHjSff}yHoC)X7U zBH64nRf1pG*Uby1PMr(zT+PMZo#9^2UvI+``>ih10;Nwl2RMZ#gZcHY? zpeX?!Loid*>_*IDOm2!7`K*8){dQ3!b^~sDp#ywj!D0Y`4e5M3yRf)&;D-I*`v*UC zT#jEIk0nn7^wc~`m0MM_Dnv7Dni+xW&;yWC2E3MRUt@Lb)Xmf z#GEZBq>SWZO>Q!BM$WlyZ021FQC=M>Qi+c)E;uQ+Jy&wBxH3ac^{`r4s0XA(kZc)% znkt}7#D&ivI3t6>q)81LVpR2bcv<+OI}Uuw_Z?jOoWA>ip8V7I z9zTC!b8%(0?)8mG&0whdy{xU7MhS$3Op&3`HkV9O1G$r#DI_~PTsujmF+4+@$X(D| zifbFQ4?ch4HT(B`#Vhu2jb8cAbN6p&Mcro0-LuC`T-52s5N9ZQJqu0_AwsgP^EmS~ z@{B?S5qLZI#&_J;dU4Ov?yEL0J-5C69HN%}8vukr!VW>20hxk%N}aWx9I9^q0{pm$ z0G&W$zx$aydtnzqM;sy_e2JgF-2fJmY2amxn?A(XHpV&YI}qvi~jKFK17 z+R+B4VQ9bbD%KddmfV7F=}2BcLftkM z3}**5NEvxv{FKhWYx&JGb(uFsI91-fE;1k61U=b~5X8tzVA%y0@+2M?|0 z(xY}}CXzx*@?y_bI1$v!flRV0VM*H!*AXL#))7Jo32r6Hpp*_E^UU0VB8i+}s^w&6 zca(R~-H3y`x)%C>*J*=F)+|U2R#I)s0+Y=cFL;H!@k)7^I;2yn61=b9HG{v#-V}5VP=KI(76#bD}}0jub3!XrcTW5Ou@VH2$Cgp5f-)9 z9j#Fy7B0{&kcc6xWu_R|Q}$4aRdGC7Q=2NR)wU-+P1>NcD$F2@aVc5+EhZ!P3g&wp1HB9chx9rm5BJ5|EQN z*(Tew#UAQv*ame~ZF5h0xz#8VoFPB}M-W`6=2A@E6s2-CZBvYWRjoL}%@r}$VllP> zV@~E(8+$G4Sw6(g%l6tEUb%SijXk-Cup6`mzn>reKzjcZ%`=m{2}~Dg)Y|rVjFbZp z27$&tnR+u#?aZ6ZO{2LG2|#WDOGOrP$`Xv2EteaMRE>&Ij{%>GH!g0-MgP|UuBCjJ z%CLr=M5>xdT#J|x1cH%B6<3T*+e>JVHrJHd>c zgM`3LtuYt|&Nl27lCWmVAm%FMoX+RjnJd%Bw%7Na98^_og*r@w6&1f!Wolv^dm$R? zsaV5h%-57&zd1YOszEigI<7| zB@$&e5HTrxgM}V1_r%Ob-B=f%yoq)-$<{X4k)mhSP_Z*o zvi=~3$Q&TCFjOf7E*u16ka3_u0%E@ImSayo`t&D1`1n8lfp6{)2S4@`KlFqD;h%3$ zMnC!={>92<`TU6sjd?qr4ww7Ae!YEmbki%Y|DE6cU*Gk;|N3wK{@v7!Loedk?X3zx?8F{*v2oy7=&)EZAB-oFR;Pkm6#bCH9bQaW`Lc5Bi7g{6i9JYk+DG@4c}( z_b`ix{kv$pvB?-v5m@6egbJ>d8;?C%Jh*geqyIaEmao zXSSyor$=OPsrm7$+_+J)wU_73PNC>g6D^)~Sy+NOKx)>>@Ca1a!PH&tPCN1_5IR$O83Vi^(duLprIm%x zq&dZFb}=2Nr*7n1TTEnXL{<@bOAIhmJ8KylDL9am8mx~1VpTOl#r;ytxOoVXMY3s2 zStMrn_s{P-hK3?H{81?1l?Z0{PagZ@jE~M%Li_~`Ah!M8^7=0zV)$3?t1qh ze&&(C`oM`tkH7V+UK@nBE^oi$uA82GV(_!S^~n$1f8?9K<|SYLFK^p>+n)RX__>AI zbl=L-g}RYR${#+x@=<@qorjO!xjXKu+9!PQvM@N-+k9X=`lFNmMH;?juV3F^xt;&X zuV3>O_aFT2|N7XUfBf{;Xkl?_sjhn&lD#b<=WWh0kVI}$c9vd^oZGCaSiOY>?#Z%h zCMIH5OD?8u+bS>by&6=lrz?+bUjD0R&-~DlV_);?gD3y~miJB`R7^Rhthr2|T{8*6 zU|A80;DHdNlSL@eWa|AI*IkeEOZd#1>zE~2auX+V%SN&9y)d1f^!741fEmdk6>7i? z+QM46xf#HY3^OMXb4i^93wfukwPX~Sz^=)sYr1`f2dlQQFHfGS$U$UgPR?#1%4RGg zgq*DsF>?lD2q`N92Px7;>xa0jjy;h{)2N#_I#>!#&P>(ilWPYadpcfstyjIcyCO84 za}_Iu(90e?*TN%HFY)W3NQ@B2xoxu*N|BlgGYrM?ZjQh)gsAR@OmHTHO*d!HJD`|= z)GRxkSs+E$ULxzvJ;R#pta)OLAZ$gt&2dNVYgS@!2!NY*>K4sB}uR^M>&AMCF7f8^W;FSHM_B!H<~7BhiC?CwmFA>4UFsoP0{KmjZ$n@OI#WC71U zT)Fl78@}Y+$@?#y`6wXQ4R5?>;igkt&wO(7_?XS0AnSq!r~nilT$)26Vd^YF-Fw0v ziMQ~k%WQ>+#5zh994I-#4#12gh=fuGl)|+DHi-gvHdiw*vD*ROHM(&3LMkZi@{(Z6 z4$tm}LRyy?<1P*mo+WQhH3$I9u1vxlv?R;J%}FExPMz4ngnO#pr#z{KSTP4RH8K#K z%*c!sT`qz#k+V2!cB5Fw#Z~XuX=6q~lQ*EcrKY%M-6t(ERZ((X$->jq$uIoYW3T$# z)vx-NV|%_j$}-E_>9sH4`;y;Y{=45l_nGtC=KY10e%+5z)5H@~XsiX3R8FMU>U3*5 z91IthT5Kg#ckzC&iaGaVC{9~q7e-_bgqj$2WfaJ=f}JcNz?=ybs26&5?DtWpsZqjk zrYk95H`IG?9^Cwvh3d_W{p18ZinH(Y_ufB!;8Jsikq0tyogz(rmbf)eV-Oise|^l9QVoq{z6?g&Y!)$As*xD9$KmP!*(a?5-``I0WKgAW#sg zoW#rlmntv|K!tToE>MmVV-#1*WNsD&0W3`7#6V7MW9)<|L6ph77XYbTRW-9nEPnie zpmCNg5mmA3#W=Q>g+Z=KotT3J@z!v1dsM{$P#t1|Il(x9nVp3QB!Po_UJCY#!^2%H z8&8cn4n~|3X=5{UH&TK}3dBqlA_sD?aLHwNBMCtyF7y`!G@Z=KP^kp1wQXJ)(k<8T zLiQ6+Oa)1-9fYB;|aVp91Cn@HwI0 z=bN*+v7*3rcBX?wa4vDLb`PID5q|HF&P*Hm=U+d(@tVR-X-$pU zdyCXIP=!Q@fod3F=3J3G+Q!u(fdUg8*?p>>HnpBwFSh%7xcV^hEn>_WGTQ22xDbw? z(nl`(XP(PXuTP)f)&^wYS-bV%=Rf`6=Rftk@BHI$`sRQ5MPKyx<;5WZNm~&Xkq|8&b=RDWi=ddah)vZDY-VlBn$^rwn}ehRRWegXP|d|h1~><* zxXxMgWajR%3aTa|%*bsfAOwz;1TUp8W=)%>?Wj#51`-Mq_aEBZ8`c-kuWfIS+MIg5 zUK!FmS-sG!>%pUsJa*0XM_=>m*T3iefBe)l4;}mpZKY_e*6QY{A1t$&pvt6b%(y}AKzEsHvEPE@fW7s!)5lA z+fgRZi|?l|y!Dme`R#AXjh%bf_?mB7+4Ut0?O&{%_^nUx{phntUUegGUeP=ID|gmE z_}h1U*?X@0_5c3)4?cFD>s?E`maEuzIGG8ON-`#9PEOggQg(8KIvEqggSr`Vc}QH! zeWz|S&C}uP%F-U&YDOQtc)3;d>AY2%GLK6jp!V7nY zbgl-Xl2SokMU5h0Eh{8qM&8Euh2Ea4W`kAbP|o}^4lBpkj=PnavTBqd#3HPwOq5fS zSPiSN-0P91R(xiv#uYQiU`YWUWzC;`y1MT*zH7OE)k?jPD@99ydKILuDrs{hIKyD% z7*rJnvWc3ix(6^bgSmx~WspUVgcw*n&suBEGBZ1}*_5d#h{75VA}m>X?UpoEd=sBhE36qfQ;^DoOkEt40i)5C<4~45X&z?9Fwc)y05?E8;1&tn`<`3A-~&(n^`p-}wcQ~xBHYT5*?EVvjI!GHc|w49DqI4LI|ic@hr-dOvRo@u z1TOEqbyJG&<5)s{0>H#&E}$sAwZk#rsvAK9U@$B1aCcHrhs`E}dxBe=HeepZz@cth zQc@g+*5K~M65+7yB%%rtW@5EWB(9mc7OCeR3@LX^ftnF{_T+ggQe_8w2pmCBH*s;Q zxxahTrY5!IT1UyqZOT;$Fm1B;gXGy-QjTKKaw@U-*|-ebIMZHF$&2 zLE81h_1C`n=$*ej{`-$yJaJ)r-=6-$aADnTn`aXXlQvZqi?x$knr%%6Rli>^OtEDO z5e`h0bWl}YT(*(8aq<9K?hVFm8qIRe!G&|qrP8ZI98`53qZmhnjI`fO4~pG&Q~k=j zmWFSMxPdePCw=>)_L0ADKX7__(Y5XK4BlAVXgirT$(qJ;(~d=3sp`pW+<4|bS@O2Y z8Z>J%HDV!#S#oA#QB6gZT@1=h;tsdg4A9I>5He#|mR?2ug}{<$W1US)7t0dB!4wo& zf&j!u!l9~aaUqbflwT2dV$>BI#9NCb{a&O5Yb`KKz8bq%9 z=vASeP$;oc2FfNb++ZQV2$n4{FZ5_BBAOF3MS_rJXJ9%@8{4z3?JEnzOW*x3Zw!I9 zM_Y@Fdp`X4AO7?sPaIjefsAs_y;x1gla>98Ta%3|)3fdh5)cQf;FL`rrA+B`Ic`OG zQX~xYBCU$gk4~o!lkRiZ9K1}7LFNX?rHzZ1*VokS0B*eRb@v4dTN~T;N|n_J6nilQ zs(Yath`Z+Gp<;5((FMlBAZSt&CUT~ZpB#d`{MENU`S4T!`<)+t{TIIa&)@Z~fBl31 z_J95PuRi+t!$12Ue&(Jpe$C>>aQ) ziC^VQpAFZ)X>jcwX?QSEpn71b@o@`lX{jPI@`l?6TPO9*1NrjjTra)mwm1BnfA_EM zzU$@BK6Uy%AOCx!^gXZr`fs@FuI&f^E{>k-@0~eqQ*X+H6b9r_M8~dOeE79q9rjCq z4OfG(h{Lq)#RD(3wB2l-te5-LTSPOqQDP=Uv@P5`_TqET_(wmoe)F}}z4!Kp!`b+J zOMwOp1P9l1VgPmb0|~r!0Ipz1VB{BJv%pj&P1!JMJUbMSt!z%lCILrwwMVbwxAZ7C zbmmfc;K}fb&K_tg5@={Bt{?^@lsvIZd*HY=bSQZoh-lY?1; z!eGTiPu+vrJ)rY6cc1StcebnZ0&8A4b&tFvo%AP8wZ{kTupSR8=>@5T2r!WffSD#u z8BLQLwVb^*m_oVJXnN{CaYgXtb50wIa&)H#>%7o~y+2f4buD2qIn8nwu2u&7k0k5~%Lm$VPGbxEZjexMHCWt#ATA74!Qy=`Z zYH4-#`de?m@19qG&%gWZ|N5Cz@BOi#x&KdI_Lgt|(s#V^`+xkaKl#b$AN$;sPe1%{ znvK1Ryu7klMXvSX_y6S+pZTjBZ+iunw@yC&pq*VOZK{4RgoSpRKmGhiHpZ9!#oNB_ z!4E(F`BRHu`m?v~`_k3Rj~_n$2cH`z8lK;ahnM4hd-E%+V_&=YGymYVpZM)dKldx2 zd+zeq-hGE8^vpx7qjB5hZl0VQ%_*zr(!giU)+KO?nQDP+I@rx^I^H$!`0D}5VT+fgC~2zrmY4MB6c+p7mN-?Sau~7 zhPT_;Iu-0?92ZjAN|_QwSjd2}~A*ePvwSh2*3q~|bj;zd*+FV66 zGuuDx6IboUF#i0x!Dy5A9N^opU*7ZJ=JQjkDvIpM#K74E6qu5_sxmW-Yl-8O-Mxxp z=1E<^Qq^oO9J1Q1ohF|-lmRt^laN$l$b^)0vJnA>q^7R!o{KBp&5}1ER3U_{jjD=- zj!i{#b7E<7tR%gVIaxtCS<*uL?H-N7t3^4YJ53Lf!Llai#o?~2GS$Yc+V|KN#G0?d8vYc6p&U zbofFK=N@1Cng4!axCak@goZUrkS_(~3=yyab2>j9?5+lDVJ)U3j7LBV1UG&0Wi*!t zdFLc8vsLdp8iFfyiI-kKyhpcZXZ1q)T5>nf-A;6VvRWZ&7eHV+lZ$F&eh7O3mlOvk zygQ*^=wYd|X3`5N5uo@zhKKmIUu7ToHB8Ij+I4sHtt^0COgjZrRGPbTmBK?q<3Ik} z-^-a^vFGhKRj>POa~VDXDAKZ^&X~Zpu=EMWWJChW^ZKu(Fp+u@PAQ>qZk=7WH=cRy zk&o%^c$#dAPhu%BI8I1>}QnPJD_ zTQ;!70C6bG6C<7*P{AEpTLEW|Aq-ifYHK;UXX`q4CK5ss4iIsiUw)lUch1b$;uR=w zKFHiBP0q=5Acfz+ANd z>O>OCu*5vX;R=>k#}}Vg%EDw3CEllj8X-h-8U?rDDS*f7b?Eh0!o`Mu{WGUO_UOjf zzv-G+{>=+Y^bXkBU?ryuRQjv2ytc8tQCdi$&=L_E2c867j~lHW)Kg;6-njP zB&;{Bu?*^}k=DrFy$U=B!jcGUt4th2fWtW?IFS)EnFNwbA~Tumu&Vc7MfJXL^?_Ya zo|`&SlqzXkb1b$`5fiXLLJY*w;UO?FnS~H4ZF9=z*{nRK*AVa?n z0jP+~tQVPPE`1CFX$ummK#Kv3k&saZDr=sNQF~=F3;pRE-Zr@P-b4HDI2u-wbp~N~ z{L)YVRxd3MsyaBU8_YxGy?ge4@`?ASJS7&mGeRx36@^ei(4(6YmUS!OB|goHvA;x& zIEb7eoot1=z08Zov>iL4)$ww@duy_F(^a=#z3)&Mpq2_ku@5c#Kzx?D|zWmMK z{x#qE13&uxS6_EkZ*4HTvb}v}JN9C;J#Dt)*Z!j~z3Z-*{rrFXjo*9MpR9lCztR&g zrK|5A9DOMkugXU9C{|v5XEc5uEVnbUYpHybUH*Ksa;D< zF~D`T_uAZCwq_iMtKO@1JShWB4(^W4jeOzx@he`@yYbezbzx&|(>b8O#4-rTnn&*H z98p;P<}if>r~>36f|y9%y<|iaIV?LOITu(wn(TE=&gASIQPqw%TPEH1@WZ3FCKp2k)Qafe{=QW1JfzPv_Bk32$Yk+iHa_s%X9QX z!%RCe-Oer6>5I7B-19!Q+{oQWXl~x|dC|~O4ZFS-AZBRiXoWCy72Q3hq^hb~+?yc; z)e^^wIevlwgec_-RMjSBGb@p;JA`BJUV&#-VP+;cD{R#_S7phQ%Z?Q0Rgd6#fQC0u={^y%92ZqkI#sWIP) zzo6s>99k--F*e57gc9kC8{CqD`=a{l#sB+1e|r8s)b6x#Qy6!9_OctGvfv_)?ykjc zg|Ni^ArE@o>&HRuRVAUKU*n1adVGA&}X~T;U`T zrqYfPJF~#a3>>2rmOCVb5bKzdh9H)6+q4o_Lw|4R?OQl_U6WU|8uYJOja6iei-)h8 zsUVZ)sZQ3I6U{E>E2o-`eD>M*o_yaskAB6s-TbXT_|zZB_{l$i_+3Br(BIs+a?@*W zx%-}LZdiKaBM)AD@P6`%TXuxHs_Wp*rS*s3_xOQh*B?2yc`n#vvH+|>NzUA7lIJWum;}&ULb9(QWp>bfUvY1%;C*<2A=jG(Se&cx~v24zIwWC{S7lUM*v z+eEAi1QH?y7K0~GW+V_IP1?4e)YZs|1m>koR}e&)Bw80Z7wn(a_T1a z#3*@*%%I?IaPE{fOkRAjuI!Z%3-Z)vFRFW9xS@y$V4G9)2{2cp8VJl#oy~Wm06ffh z!L-xt`i>5HZZ1YyM!FS{9Uz!pw)=k{ThA0ARo7Aj-LAER8!2FfNEF?y_-Ne?=xzJC zhw}XfJ~+Mk>fwZ2Myu^*JI}q@?Urh-TeXxJ!xyVCLR}$j#=x zeFm;*dJ19x?&a(IDL&V(f8gXJuq#?T?H1IVUA*U&yIy~4^4#OIPmma*z}OYeL=aOg z!OESAiX2wn1}c0ert*A~7Y(hm&3~1tEL)5zG7C&iXJ&1YPZwptoCjShlT5_E6L9pR z=>XA-<`?7+1+{9%T#<0rB+?7jf|*&Kz*BD95JV(0Gl`_sYT1~XvqZIQ?HEw=*3Cdd z92w#uH4_#?F29r6vt?ol6jBZxmKsgt(MEuWx=!xm3Q{$5usRt4foW_TFjJDI@v1i% z^m_H<8}0x57mvRFvn${9E!Q6U=9+gyzMfwC_SGAHbLoLU*!twT9E9tYs*-9WhpEr{ zQD)PWw;EaM)xCaBQ#2a-R7)W5v=s&yP;@fGtTk(lvQqL8g`9?=9#(Owu8<&8!=yP} zwQqXa@Y=U6$lYwKu;lh>Kk?U-zy9Rtfh&2tA5+a*YoeTIIk{!W)bb=vQ<`y5&A!=; zJO)FXk}yROa|oK?Qgi@~ni5%eI${3JVlvH6LOYIbhN(KCQ{Z^k=?D;x1D1-bV5Vlw zQiTu+0SHVYHAe|#A|h1?II^0Xi-ZEPGy|D4xC+75VH5)~ktd51IJ>L$ zIK)6SF>#MVHK^|h2~hM5k*JQ`Gp_-OaP`p@-Oi&uN1HdkZFv2C2kWa}7#um6&7=+{fzo3pSe5YL*l%_KxZIUAzUXIgnD@PO?O{(d_(*^LzL2`!B!v|NPVM{73KllfV7b_q^}% zXWyBhcJt!_TseQ5EuTNX@k_t@ z3$NOB>__hXN}N2wYtO7KX~q^;Gv^kpBx-I_v(?d8Uy1rCF27fNo5BK&5QJjzrpfIr zRzvRX(dmZe?8Rb&t^jk#V3BTpMMb1r7pHmV^#b}UG4vPHq_sx9F!SfVohn=*0vLo* z5bZ_MLJm_WAPBNLJ0u{tn6!}S{S^*FHU$aI&gZq$dikQ~Kuva1-@1bR9u5#auYNh_ zO2V+exV*AB9ghjBDYs2q_j_(uOdqNWkcg`q72apmUR8|>Cj}wI5Ms_*&2rYJX_=XvG;6t_)G`rV$(`DiOx4{x zw5G$*StK>*g1xkC#uQ@6Ij5A&%v6~13waVjV-|RxutoF>;Jy{lXO?IehhzM<0762=Cpu@BI1G{Sb0H zEBAF-m3W6;?pCG-a?_n&6!SN3KBKoCR&ZAr%{xoST+G&eu3qRncNQtMqoCVqNuAjF z|L$6MPKx=}zw^82r^oz7IMg#x%#-Nc2_SY32tyfE-rF}=IaKY9SzHl&b?dDOCQZ|_ zZqG(Do2h3P*T#vs3Nhza&8gUq!DbjWvx>uNe^+bSBTbskSx#WGtXAy$?yA|HIaVNc zB90U!xQjb8L=&3@sds7KwXpxD+|v59oAth`9xkTQc7J)vX3fTv4~^H?($?jC<&00) zDfX&9sydm@3^`We`FH;0<=emH_22hzo_^mgC*Jid+&sVW&|@F_?Ej?tfb@d5qt1Dw zmK#?x5s9EHCmyU9hAYEC><{v|QBBNk5IKjF4<7%-ci!}62M+pw`QN`XSzr6!ANz`f zUvS+Mzx<)4_~el{zeEQZKlnV>CktPCwIAXBwe$o3^OZOL!s37YFOO_YeD~gitwqgA z#mzmnnMoo`Ib5P}R-~LMknEVr%W9tBW;wS^EU_}WNMzQk`T;tRzZQKn>&&!Q4j_@B~ySE+P29V>Xt1R8GFea<4(Gu zIk(BFwL+IdLE@1|Gj;5E*Ijdic`w!d9OgsA`4#RRYJdU@1KQDMa~bHNs{`0ez6=FN zbcs9`?r60_OIVh7dE}OipFu3>>CXY<`7hDVpty7Ez3?X)JQD>kjWR{@zzBP2c@K^l@-yQnvrj}4J58JMT`zsZ z!ZY;VD<>1p7}3xWyEqZVJyY3bl9{=8*r)PIVVDEVl*StmKC^LVp+2&IWpCQL@|(~6 z8RN>xw|lW7a`U{0k9^O4-?l!w@)IA}dL}39d$SOayVFuF@+?QTg(gH zN!XxfS>i(7->q%Rvvt$9)mc^5?g>y9Ap{PA2=MGkRwxkNz`ppU%Pzm0v^l}aiOB#X zP`~F@e{1c6c@A|gy=pocvngB=h+NEOU}27I$}Gv`9g?+EfkMP}Jx9gVwrXT*x%a5+js@_6f_pd08J#i2+X0v{*ysteE{fg@( z9HpaMG9tJy%tEc@lrkID68eD$6)pGbNHk!gSzc&oFTa}Zc;ia_wrE!qh;Y)^-=lx^ zH|rlfHCZQa`_TrHB{^xE+nH(tWwS{;YklUDoJ^6yzO4$NY zlnbB;=!vP5jLt1a-IG>^V`An1-CL205TVpLNMmFQZX!YIx*(n?#t>N8rIt{K*snts zxWxLp89BsRh^Vy~Lg=%b5sZUcvKX0QsYzxOg=-F?1Tg}j7Fe8}GxcI5A~hFgiNWC< z$hBKXxS|S?%racnB2!?gC}^g@BBYB|b@2+F-e|WuP((D2Tq&!vwb_Ij#15-NRdWR3 z0jiypk)`y&URObwo#0MYIXNpSS3(p7MX#bD+yfz@Cp_rUfMKomDh4pDh!c34N87X3 z^Wm5HE5BxN)f-m44^7C8!9f)jt6mJ@cYf{92D-f5+Xb>96j)lu(IeM<`k9X=n*ai5 zpwaW*uuI?=gS)qFHc-Vbfh7c(nOlj+V(z?qzf8;=x@u}0h_x2DH#g<~?$|#tU zN@S}t4G;0^tGt=n_H&`CiTaimQ9#N7&{(rgF-i_VCN_zjQ?dGk1xyA`<16Omy%k})w27voV75dKrl5;S_a+B9XK^aakaKh<(0UbR6*M^wx$rsvOAmw z8ER^9mq3i5NpqXMb8lJ^Wf61Ensc!bg#Mrxd$F0t$!MykB3$t$UXEmar{UXE7ON20oyHR}v?yDot#NT}yUYU zGJooWAN?oKp1%3^m7}K)u00v5LEx%Oo0v-|5H@pQ_GG3?qLsv~&HQkdn`#t?!)h>y zRhPQJVNF(^df^$pefy2aRzGvue&drL8vNM&?Kj?jZPXr_Z?AmxalYlq@AbY4LEW>NN0&d7E0#o*}-K?@xu1QtVB-$M!E6L zEj$lj0G?3|DX?d_D8-SdhWfG#b9Hclb>;c?>m*Cb69s{|~&^ zTsV;XyxV%7jYKLzWD>IyQd2*h%`(Rx^WMJKWtejS`0f z4id9EjD(W#=CskqR}}M^+QltV^Liz|;^y(%gVSAW)R`$nj^N5YWfTFfaIp*a`i{b{ zw3^l2*wqw7LTpPmuKy>4q3W%=be>q;31-F;+_cQS%d5I?=OU8c4GBmQJ@-n|>xxeY z!Qjj+;Ots>Z1-N&N+5!miw`#H@hR`JcKcDfl-oStR0nbJ=33so;@u&IiiA-Ti;8r# z>>R|9*b|sU6q$)(aB^~x2W=8g-V|=SO`kkx^F6r({KmWO!@slh(MJx>ZTR_1RIOrf zLBkcFP0b8Yj7H!HiX`sHpnzad?av<4z8j^V&q5dv?Qp0la9z;=lse)Sq6$c!=Z+56 zK?v^V39gO|SA}2li;mqr>;uvlvwB~(z|3k!&Vq_C0GnC|8oIMt7_xyQ_hR>9=;DhG;v$e=-lgTh_tf91UJ@k8U5|yEzU}Vs zxo338$6tK<#jPhg99E=)yoVR}7P~i9uN-33`jo&56Xz1yOe`=~%Yrz_+a3Q?)B^IC0b8e(ewb#N$8l`1}hoh5|#0 z2Qd^*%*E9@fQY5^;}J0xR0%}`VCu%sC4*qO$`)is`y4iU*=K_OwJeXhF2T6v#klOk z!4fN)2Qmb}#S z6d=uAO@#xBIe`hJ0IM0qSdfxAvjlJU_kw~3VUcGU3wL8CX0n`PsFQV;=M@i_gJ^YrV&3H8U>t*lP$}qV9=!VLA2|H3Z#sR~_eQ!KehaPtSp2|OoVxobc0cj?=KMSk zW3?Nq8ElbSENrwM0%}@VR1c+nu{@s@0#N~mT-_4bWf0=AVYM1KI?^l;w7X~B-}Kt? zvG-K@t!`t(q2Z74z%MU;`GL(R7TQD#>trE!)|zY5oRJgguxYcIaR+W)o75=_)Vi+g zs=9V?n+_f7teKKgHtkn?GbcnZ4+h*_sZjCduoMQ7tM?yf)3Rz(s0t*Z+7VY?rbl8R z5Ml@+#t=vXafm|B0;vasibE|D0-1LEd(*w$SxR2H444DSFjSL4H3~6QF*QaKC7M~b z>?F}yBXKm2U=G3DvS(s0AEwAr-OUx{lj?v&f~XeQjB}etp&o*})Oy9D!U%N`OF1a+ zf93cUXQ~SyS2CUqWa4aO)5W4Su7uNaNF@b29gK!qvjC%OO5kW32gwT3ue73vLdiRbmk=K0d(W7s#5C8{?{&9(|O|R^3 zoILjY6EA)6*FSM~^`^?=BDJHzc-|b2$18DAJ$3CtcLRa}LmEY@QcmVzW_He=Y00&M zKwvX9n0Z=qu0$m6@jOyW} zI<;~7%ipze^6cs1$5wW>5AMG2)$e=Xm%sC^Z#aJPnB}~;x!ug0rfcqg?cIOydmsA! zpZ`xk@PY4q+sV7HeEOla$tp>woDmaolG;tOiFwTkhPB%;xf`=5DD6_U0%xk=n#`0) zJx^`1MK))cH#5&25ty9=rR?Ue89*LPf;xpkjH{Eh@a|wgFFGW^C^?|ePKgi$Qo_=s z2x1^PfDoYyFWOB7bbHP10LKDc&GUffLEhk3rRP|KkVo}A^; z>Z$Mj-tYaM@BN-Lr#G7ULQOSi5e_l11kFlPq9#jsVA(&pJQ#HS_H{2PL%}n=*kiok zHha}ffspLF;&gfaI?R_!Klfe?T)wGV84k>hn2USUVcLNTb4OHKRRGs)Wg1k~(pezP z6v@hr&B2_R!KA7V?-pq>ZR=qb2UVKUV$rbhWNrP-%{Q(*^Z3@*RSBm@ zlkxuEUaTTBn<|A+K9v&43%X-vE{A1XUbTvX;?hzij3vo>UG9Wp6kYC}*Hzj7msR%V zkNa}UqL&xbCGXmU6y!^~{EL3!%U|@!gS#zxS5z3Dl^bsy+&^!%@79z387o)V(vu4I6As^`ku8Dx9nZMI^UZe zzi}8v4|I=w+YVayL4Zk>b6x-#u1(y_?!+H-anNChw$?o3MV9f+X{ zVhHukM-pHPgA6Ojob0$;E5E9ZnI}b7z0xEfIWi zV?qQ1V>qmj7}}=YQ*To@2Qs1T(bmtSpnxyBECIX>A>g`PrX11SCk!#%6dU*8%l{%i z{4cS2jjo$?)=&} zz3ES8Z+iUkM_^L)nw7;hA4cFHFB(|KZj=cQMycEajM$fDKkSSmt0+rgF(#F5|2jn5 z|Lx4M?0heoY)hVI>05DgaG56@R>GOd30!K;9d1q_DYDYesT^=q&5gl)cvH1@TL__> zy$FZMgekzyQs<;hpuk1CK*B_9O2q86e4BeNP~mI^!-@gJBN`%)Ly%h0EZRMgvq+B< z2peZu3z9@41ZS{t=WPTzb7PB+C|0IKCiUkR-SfY2{_P(hf9rQ1J^sxBYlL^x-LE}z z^MCCAK@C%1q;<`qNltN0-EY^07lAEBj ztZYi^Xn^bqjLeNgC80L$axy0?5<63`S2u*?VtxoB z3ItlFcydYZ1_j|Ny1~^XhEP{b!9fzkXfO;!?1&+X2!n;I$bq2K*=%R?pj%AO-azku z&(T-C^2mvei0oI-rzanoKK5x=25fLVk3y~Xn=OM^wP}c$?YTV5zLc}XsxI2W#m~?+kZ*=ZWE)Dwk!bnL0`!A^>$X3i3f!{q#Tiuitv~p6~yAf8pNA+yDL#e5J#7H}_nOg{x6LSgGAqBE>qynhVq$>vA-j z6y_@wl+amNgh42kCn$ZCWpVA(X)zkqb&O5hZEqc1xx76YuYBeE-}An&dDjciUA}VZ zDn-9``O0GtKJ~=Y7n*j_=9D{CxD4a!>dL7bPTqIltN!WxzxniulanJOC!6j~uUxnm zg@eGLXK%lG>&lg%|Cc}ct~*})=id7M%?F+yudK$2fVQbp8LA8%AxmX6V2Jsk;v@Hw zta`+e)(0QIx+T*+rT@ZC-$+`r05jb1|%!&;W`ttb?^N@@PmKjz3+P4Vm3eA-w!dyDvC&7{Y@O|0H$I#DGx*s!T0$k zJ)1{FMNjKr^qi_|o$i_I3}C zoIY~BD&YpB+x zT7Sity!-J_e)QTCzm~QitXEgNbU?l%jBY;XVHL+KR8?-)w7DLLur9XGYd42=?5X5X zR4oSQZ=Q$RJKx`FN5 z;j!V$N=1j(9d`51n}(;;mv&FS?p?3F<;3L|pL0rUXK%_oa|{Tty#W;`_xnC@=FdMj z`(J+avHiM|7*#W?5+FhjF$u=*n%H9PfhlBF5(OwH4Y8`?5L6MlIy)%>`=ClysBVaZ zD1#?gt8T7LnlmvR0XheJziqzEVG`6pc1apa60 zJGFA-+VI>#!=Pf-1Smte{2=z?Oi*`#DVdrY$b~su4$SVJ`@NA$EDMMLb$2HpjZa1$ z?@ssBTSA%1mwBfs+>!J;Q8ScgKM+$OVly?**Tog(#70>NK*VfhfHKGohR8A^B{y2^ zUuX`m>inAN6zt9bmlo*6LOnReWbUOyx-`0iOYaLgmuBTaOsp+5+R8Divp)YsedCv$ z{K3D1w;aFxs}DA_%b2$9Klx|adBm{!o*FGr=AliBM?$C#FoHaE*9r9@KhL_rZbJ} zA-4NO;eNZMKttgbrr;XHCpmTS3^e`AiXLXUe&~iTI;VSH^yLHjI@@hK_34Y}fWW2V)zNBu+wk^x*ROwU_T0zQV^c;JGRowoP~6Imj=sC1$H)P= zYeAltBSSAaD$g$Z+iFQjFNxT`aoc*d~=uc+kwYAek5+yKL ze>Lj@K}6iu$RHFnTOek(q)8oIB671g-MsX1kx@p@lvM=PWGne^zqI?{Kizr%2akQ# z_nxTVO}_5cUzN9i+4|l8pY+Eco;`E9TN~B08oZw;$7>$4?wXL3EJf3`4=NgEN}Z34 zDahKmS^=uL*?fBE4f!o^T0izpL%arvP8ZSsj(_~W?*G?E_g-{6T=j+%Dih(Hxq~H5 z*%}S#x{ON9vbn0w%@<~!gpgI4jo91VIwO0l-j<}S<@*jZl2}O?7|c?M%n~@O@$nm9 zA%gSIJdv}7z-GDpQqKT;zl$q@h=ULZ(;^J6g4ARZYN@Iq;K+eVnx@^}+*=&(9bIqV z@%AI{eb3!*e*NU^F|Mvd_dusdE?%$)KQaI4hp#^L;JK?;M>m{0K3T03ize|l5vZ;u zB$o~q7!|W~R!anrb#Q7lGjVc|BY=8%i;&&KxiZ91X)ZlF(`$HU=R(#+I9`3y`^LXJ8U%O3oy)5~vdp0|&*p4s38WClaB$Vp6XeEQka4 znaLurjlxPKofPTsKK*qY;dY{$oS>;EOPGii*mP=*Ps!fJgY`Q$ zo_^@1|MDxpamVT%lDJK2RF4j)duyw!ZuturKV@!A0gjr7fkd;a=W@)d_x?9EWiS(! zSfAy&C(HtH;nRAosi#-S9fj>BI5VZ(-hc1grK^7O*Z%(Y6o32Mzh-!3ytBQ-AvjyT zR!NZ5cA+MSsAcZ}MpcWNRx!l7X1PAt5C`sY;p^+EzkHN0Az_FRz{9$#>nbPh+V1j& ztHQi-baMRonh4ST_kP7!y*DRIIjboQF@}0n4@NNv=cHZJE)M6@^9KM#sIFrrGM~*S z8>{2t;3xn7zrss9Klqpa-u_DmXlS&4%%$NfC=!WMrH(|wWB`QZqnok%CQoy3Hd$&= zSlF;sZvxB@xc@9h7bflTwibBQJgHTcwFQ_KBluITm04U0-Yq`uRfR?WzQs`5# zAa^M1T-U-BA{Y*7utFldx1jSc+OyB=))b2n_7{A4j+YMdR@WT~c*`k%&)wD8W8wE7 z_CLAYzUN(E@z?+E58QO)nS=dlsH+e|h=G_z#LaTfs+pyt-r?hBMj~!T%YC)1pJih~ z5lZ#)@?MC;M5fjoRts*uROk@kY9N@K+p-S2TrA}>DoZB89hx!`xtY1Al#1oj&EUwU zWL8pDRMj0Uf@~rzTs2LrW~FLAtC@Ns7u>y+Co@y-%q)9}l4ZDiUL-I`s9m(~5Mfi- zYy=EOgIIanw#|HDxvfS~ljUS(R%fP^v~4`rlsZcE>zm z^ETyyRHI6uJQ|MJ8H|HwHf`q(+HAV84(3kA!fKwi6A7-KT|q)T9e&Wh)x14P|kfIJ%R%FW|L^vVQAjh?8EFoO#uI1FB zayU#=mMjuOjFvrj$`Gk&FEt-~c5g)SP%}$xW`ThUKkC^{36AO!CmVSvt108vd)?_p9_^x4j#KOYs&T#A^9$W;N5 zh#Q+4g}^M9OPsaD;l`0Ow+X%J`D+j5>2~S+z!kOa;3;nn%ki&yBzjMZbKv+G0IX*CTU+%z?D$P`4FkaLDx zWF$3nDhBmrAR)lH=m&f0DGD^$Gp6M{wa&DOJYufZdeN`j<^a3jtLf(yv#7A?i<&AH6%V4zj z2mkqL=mN23sob;YnKxaT6p>~?cRh^u`XO1;e}_CgGrVzkK0EK5m@gZq<#5hz5W%y{Pog*1AwFh%}el5&sfvajM3|^41G=# z0mYMvk~vIlX1kZ|q093xFe*a5!ly>DCJSSno{UcJrAy{Q7%?b$dzNqc_Ost|&)S*i zcg}xu`}2=BkGr&q+Igl_J}XSl0w+d*Ifxw0pcu&w*|dj#K_wI>Vfq{%{*}-Dw-?&y zp4xx3mWm06EW{anl8*n`SAX5s_QD?fg+HbT=Qd548+Ry6KQH4N*>N51rt3jfBt+M{ z+X}`-#gniEwnZZPt)=`#Uj|Cibr!n3#>H3QME(3FOxK4{FYz};EbYVw9BQ)wIk7q{ zbz6oo9N#<`pY3#~U2K}phzu+MdszrTrVcLDF0Ql0AooyVd@|Q-NOPGCc@XrVb5ekd zi(Qzrw&a002xnyBK+Xh$vBANSLh#fi%|ew}OtZWg)WgBBy0ozW@W9?@o@u}B%Z|SC z&kk@W;dVOt4+bCj%E7Zgz4+_{&BcYg$hbwlB06R{v@j41009qaGU28n2@s3(4r>dq zvz|Vl?s#*3_A55xTZK-*caT47pa0GM-~3ebojMs; z#DfZyErKS4K#IjYXX2sI%yH=GgfdD9r899|g{q1e5qCb|FbJXPLJ|-}Aes2&D4bjw zymUz~T+<-6isYQ8t--A}R3bz0SVFZ{bHH?w4zi{~tumq%REGqpg@;7U?oLjq0u3S< z7zdiv6eBvYIM;>^M%VbkP79j9>PzI-_peUgSz#3@*6+?scbO+(4|v|v!|m3k-J{=e zQY!eECCJbG*e{LK>Z$ePmf2k;Ba+{7^X(t~-0wAcN+b*x)PhJQxxq_LOfCZ4!k$%J z1&M8L6h;71?6odl0=I4HOe0#hS5v7ZVRp{|Hdc@Q;b%X%xwHRe_k8Cax8E_}o3miD zKFBNxMr`$bHLO=briCM}OeE z|Ht)sgC{ha>X$GQ()me;)NYyaxs z{hOyw9Gf>?HK;-rC5StOnTR00uv0aQ#Bzle{MxTea?qnf=>Ha_TD{1CZFw0JGov)w zEEQ^{=&XpBRIleO^mlY2bZt437GFS_PC6KBym%Rz98cK0R?q$iT>zFt&vq)9P zteU!9wpA`N-Q^#i!7NNQJ3=#WQrm?}BuJ=G^77A{M=I0AdxZY9z$dgTr>w zg%~8VscBXKu@X@1TJ2hOhq)3EB7-V7gcxFs`+EnU{*wpZ{pIicz&Cv0fBWD5+2hZ= zxH35!BbAin0uU6HG64<)xvH9xh+OZk=%si|_OxKR*B8`&sKHVcg{AuMzsIfq_x4u5 zPO^fC%7?W0;rk)1Fg1MvBAGH+5RTE&8;57^8r^&Q%3W-6v)g@cdTu*y9j3XGNv!5g zo4Ju%$O9E`YG8%2_-JMQlb615>d2|Dz2yVH{rm@Kc|lBdU~?VRgOs#EJInLAEoOPq z!9WE?bRrN7$cZdSEUSK$;b7%B^IA1pH>*O3Fb!3b(Rw{u%L%(zt~B%g!Jwv%)wKV_ z!ynzg{oXgd?!Di3>GD(8UV64ohfEYlA=}JbON+UwQ4nU;c0rsausb|!DSKDVaFQTy zq-IRcLd+s0stTqM0uhnN$RVfBaw>~S#Z{S?0|zr!LoG50Lov^}m1ryDFk&4sZW$k) zrRkwI8)5X>XCCvNo!Q~ln`3p`3&&S)7=^O~-Q4tNobEl_ZFSYn)!V-L%6A&U5QzwL(912^0kXeXjIjq8*IMxJMx0qghZdjkxR*1(=(}D*I6T=vA zR}l^@a1A6y;A~(w7iMz^b2f{CGt++8NeBj=5Q9NLh*E`NY8UpxWqD)r;p*V#jg{eZ zXne9ZI9rdcuAjL&e`I?;&5+{1gh%pRR!(N_`7w$jYE~dTP|YJRDXlZP%Eq7Z$NUGys=CgRzXGVrJ9U5M;vfs1A;M z2s+>NbV%Iw2@@{XD=WFD0DYP7&Lvu@k02;5$PR!)zpnAXz0xrAG$Yh>Vp4y@{r3Df zr62#P{h$7EAW*wc!;urfBM4(yp=q(M5XD-Bqo;7~5*Bm1`&HFn`DQ-<6n-|4CkPjz z4mg0ERLPAvXzJY6@&cfH-}-g`_{Vr8{Tp2XybKj_ue!)^K&mYPo&31qUfk|&rm?g zh@^C~Qz^={O~Z8{S5Rj&*;y>A%b&2*NK;2*_vzc%}?pPD|n zY5P?@TdndylQnHJHO(o-L7h_9rUt=Ob51a^u1hXLV%Zl?ZB{d45lT+O)uZFJjlG?V z^XZJGf6>jI3bsdNnmj3}NSn$##w@ab`6ArIc*23*AVEw!Cnsiba0GXvARH?glSrtC z%)!m8nqx$2rqioC)Xi?bW%A8mf8%@Kb@bj_Wz4SdtXQaX39DviK{h(r_bV6jg{KZL zJa-`AH@;!xFaOZ#KmC_a|KiWQ_{+ce*g#I)a{4CmKr>^)xQ=56CmYsb65^~$^UTCS zYAj4!LuPaH7-JwANeop~$~AGfNMaaOv1?oi;~37Y4AR^mJKvN?7>!kdAeOomD0G_9 zVKk^lk&aEI9rE*=-9eLwqd2MW)T{CXt4WI--g2#(m$K z+*RZB+V_XE?^~>0f8f18Jd2H7-Ob%tsy}+*BTNnqUv=yK>-D;Go*Wrx%FS$n>?=nn zqt)8k%yXzD)`5jAySh3l7-Af2F*ATT5X%3s6qJ=i*_@<+%vL;*rJqxCX~Y2qsp?>E zrcUn8Fm+8@lGw9ZzxNVxV1l`!P*)s@nRB)-b!Tor^YAA>```ZcFMrEdebcM%dCS%( zAFc-*q-=wUkJOuv>jh%A0IER2DJbe8t-KC$+|y@>0z4oCmPlvb>>(erHpq=O4Z1|G zu39*}UbU0K1T}XBGh2phsX%ukvQ+dag#KtHnD>e#LzmzN0wx0tj?!c$rbI8C*C(IW zbDMs7j%#f=Kf~3zUtJ^z?i?LH-jQZRrM%$$FA2q3y6Oo$bE)j7xh$5n_ z4z{diLpJxEl$c6BQwUsFv096ZMRPcvi~4X-g<)_&)vB83^M$JwM?gxNQ)ZG7!+3Q( z-J5k?jxm^;Il4AG)L|SDT$;m{0?a(ma}meQXHBT-rdw{jaPi`={rYcw@Av(=um8qx z{0~3(FPpZGRYjnjGY59na$DwHDCNSbm{~6A`Z;GW`XK6YsPfK~Pf-sBevwq-i`-KG z|NOWCd zH>>KHEfWZur}Npk8o|-F$s#JL_PX}NpZ(Z3-uJ$*IR1{`z51~O98$0YZ!YR~r)~CZ z&_4b|BEW{C!}2btl2zemDVxY-P@f8e<10r_I}e*hR`c2Z&R{sGYN>_Ne1CB;OI;(f zQBOwj#cccBGmp%V-+bF-e8g|QZMJ=7cI`4m;g;JOhbqLV-P}C)9gLPul>pORatYkr za$8=xY%U@MZgs|7v4<{o*|Z8Zpb?>tgHD@lmf0ArZcGwLlDaUZtkLL3tgSYZ^J1Vb z+MXO&hg@$TE-I0Orv2!JCr$=FdF=G3Km3_HuI%0Rjc=RJ+V=O)4S3-9oxxGR)wI->V3)N~$Sv_ObTBDQ42Y_3hSU`DJ0k!bRqIxvsd zM+2*{ShyM!vxnSTN|`g8*RCxB_m)CIFY9Gc2;O$s+r|~M%)U7V1-Ox-m-D#6LB)V- zB|4~sW(vV`h67|UzHXCtO~tehcaq?JEZL;Vj*C2V`6hN zCjtToGB@|YY}pvZL5dQ@nbe$!Vvwxbl2s(rrcJ7z#BV7m4A)|`xlxXYQCB1wWS%u1UhN|cBi9DzlRvMOFi1^a|whO172 zOwj&*_9A~Z;*usuR76rvj93qkFa^qp7%0%{!U-iRqTJ^WW~ziLA_#`;>RZ2S_{Lio|LRA(M;{-C z5E|&_Wwci*t~w?@7`raeB@6GBicLuz)rw+EjBY zi7WuISl4-W&p(}`){l;j6?O9^^4O(n%8shk)U zAnpVVMq%UX_WtzQt>eemS83H;GOWqz2%mc2jbDCDCeL1b_|d~J?B*?wK;NKBT%>gF zL4=)LNhlBkzyx-r4kidf41yM$Gf_pd(8Ye3ojewA@Z&e1zH9&Sod+NPoVf)F=3oOE z+;c&$KxSn9ty6Rb4yGmNT%JA_FUnz{G*>y)dI3@)MEak{9GQZVn&-azju~FK+af9K zlb^~nvCI}^0=t#GV?T*kz?YuS7*1JaMnHs7o+YCe& z%*iuMN!62!BOrV0)VQ=}M#RpltR9$06C6fk11)pn++0xZR}wg^uqq|2K5NGSMFL0* zwG#wZ7MDyR5LK=uQQ~mm5Z5TNjiq3*IQC6n_nNoAVSRlBb#xg` zMrU3UQUnx)G~-~$ubxjApG#LSbXPAdE}xrU+uZ+^|NO{}rv~5k=U(|2fB5G2f7|Jw z`G?Pb`cEFa<@oKVM(eTTI%7mM96$n^)*-<(vp_hq5|R!>#X^=Xn|7(2&zcy-U8*Y9 z405K<#c^U3k4^aM)wF0)PwFrv&UtN>hvVUNnwuE{2OhxP4)${86%i)HGN=ZD$4u2I zmfj^9NX^9AEA~MZibP^SR1sDJ+1zc{u;?6V{kYxs?%}cb4&@caOb*XWKR*!?@RHk~ zBz=>%tjgrt2{fv}ARb zAr5YE_d;d3_X-;#F1rwe5vb@q$xR00<~bV$E;S^@@yin2U}`KB0)wfWcgM~gKfJp2 zTR-u?zw(CLzvi9aIeY0sHJp$(P99Efpx$$zQ=U_$6b;e1as=@B1g+e^tRk&N#*mEJ zCc1s-%yZ+pMcW{C$nIve>;gj(iv(yYB2wh+ZU}*Lh7vTR$n!0spFV#4xM>=WMnM9TNFTz>{hcY~Ml9Sn!I(;rezx>J5~+t%ncb}X zD{-G^Yw9dq+LBc*MkzBH5j3m0mraYA`&xy9S2{o_4%ptmU?uX;Q8q9kHdfOm>kc)8 z!raW1nalB3wrdEvS+i(E422&qYT#mgW1)hR7$c>;m@h&lRjkL8(V|(*W=#yCs={o# zXuD2?i{QXanTd!~Qcnq>YFKq$GD9`2Nj0e*?#>Ka4Jz$xy1c|><}MR)2$E9{72W&l zSN`_z{Mt|c)IWR6Ti$c_##dZ8e{L+WIvLI0;)1qrCsjCoG73va#5HFh9(8nwF`u3%rZdXs^ z^oHaY^!!!dB!;5p&^N#f1!7U{muGbik(q;LmoN;2aXma92OHzHlR1aMcw*!v9tVTA zneJS<$YRy79;~eeIwn=6tQC*d54F2^{^4gS2*g}7;F=QHSs1P`lE6SPO`19oOAxmV zcVD(axEY{KK_oDdS!QO3f|yAOsmZPRFnLtZD{;cahuu8E1IH4ZOMtB9jzcc+ZTo({>0j`Q{t7qc$Lm>*vYuQ z8c!V=;@l!2)La>{x)BMJGw9fGyfUm`Jh-->8w(5xJuFFF?gb)s&m2Pmrvw;IL=U?VO~KcpoMem1*B&nCBPuWHSF*z9()|bb>H4b7$XK^g*lQTlyhH- z5Da9bxo99r7*Gg#YQdl&WbD~JXB5+PVRU=5HIsyLXgWK5q3Pmcf6y$>nV5LV?#fQRe}y)V`aM>I9N`^qH3Trl#{y=Q_$!>}6H6~JEISWLk**L(&Fa;Y!)j&!>Pz#(LuM9^=E*q#{cReka<{`gH@8e#+0+ia z+wEbhqD(E0S2H3IhoVKsb=aymFBJnl5CahrBAgM$eT)+~)B4c&X!WhP-uPXwKlkx_ zyGI|%m!|2T{<{78f2H9Nqcy}efNnbl+X}g%4rNtxN60 zJO0VX(JoLAiklu~J#MqXFgO`bzk2mmZ#ptr-+b)B*-H=p?$7_iGr#sndA{Y=Kr=}O zJ3PZ2eYzL*3|@aq_JZ63h!8>qSK?Ag9g08{iVRZAMBG^$f;HW4lg>BY*7fbQUy-n! zm#7GXmxN)T*05Bbmivz=fUajcJFdUREY5(Y-s}$gBC?hoC18uF6nHy`N=9Gr2VEZe z6*IzK^L`*|2Oh22n8B%$)&; z1lNUmW*LJb4=T7?*A>;jySo|-drn4?)+flF&v%F$olV_lgjC`~99$e_?yg3V%EBb0 zMr5_lO)X2Sb4wXucM;0O+NOmQscMuuXU#5E9JmByZWCR6Z1%|~+IN3s^2V>8jJ}fS zOK{Vxs#6~gFMUuqAGLX-(Uu!YMrF!OYo~SNbu@n4kl!9KfzOaW?4SFU!;e34YuRBq*xZ}$Jnsx5 zb+{|TjRKRGz)1pw$cm|pq$=rF<`!ZAv8F_U)dGPj){J0I4v|=Mtlc7rV~BwRwcUK@ zvhVHQe&fp5f9IXw{LMGsb<-da9O%?rN0Yqi+=c20a@uM9+U2}`Nw+Vj%@@;jyK4{I zZtkI~&zwD;+9Ox4ZvD^?e(b})dG`DN&KrL8=kERJFKqt%fAP}RLB8ko4b+;oPNB%p z)zt?>A%&(~3-f@>y5*H9B$+Bx%4+Um7}+>vl1L%@v4J4l?le^_WHc}w-H>~3lZ}(~ z=o5JUTqoIC;ObT2#bGxZ#PtE!ouk!(@JNVY9GT1qL^0AJfE86h9B?o~>pInDk&K$7 zx8wE?jE=mcqLXair|6YAln7Ar7tBAI+eflql6IT+c4Y4`e`@#A-QTjh_Llmk7q6YY z{rIz=f8h^4_`vIq-p7g3%*UhgBF$FD6B$$wUVYG=grYkEvF5R=F^6o~49q3_o&f|@ zrn)!V?tDSSjFLB4>$Lp( zWx%gk#h7BnaFi$%ic*L?A`f){+|5(lt{qzq?mznv|9O3J_I-ctf9`f>m?Fv`Q=-X8 zj;wpybDNW7NOD#lvR6*5Sh*GBd)>0j5gOg$EIvC=dFIU&siTzia7MYKY}S^{3-<#5 z1X$`XN=tAD%;A)C=>msaNx17ZL0O#vQ}={wfMX}acr7UC^7Gx(=b8%_{o0hax^Qt$ z&+hBfv)nq42Yl<@;RA0DZ@y1O?fJ*^C!b#IZDAqd$!U0U5!Y_H^Q*q)n{T@DX3D9a zOt=&wGm8iloB1+ruw0s;VkBeIl6C36TvN*fRb=E)?RnI)qZUFHTmWFtDFLL}v^1p^ z-hi2zm&zZ&T+IO#sCEe2u7V&hOXl7C2Au0NQL(m4k@WvR|H0RJR4>)t zg$!VFh=&{bwznRA$2)HR(pQ|gYk#)=!1)Is-hBMr?BWb_6ZJ~R)u7ACVP=+cNo3@@ z9;7zGY#hfan`bNUyQ>XDSn<_chBv(PhBu8(w)gkW3{Jn$Tsn%4ZR~H`)xZ@Il{eQ3 zR#cQsT~0w5L@610&GFdU(X*4)WAk~pyR|c)()e_^>DD`5^@jTffv;V@^30PDP4~9j zMLSp>IBPebO*dcCcF*%7vN1KTrfqUSD1hL_$eO#XSz<*n*Hm6$>&sTmG?!R37IqKI zzzC91i$u7asWAzOcmOPWM~+2WY=k43{J`eyUKYl{LXL&Es(fnY$lk&9(xvTFvU+qa zIP&gvevHC_L)9v&H@Elf%x(9-^|g=x(I+4N{Rdz7&ex9u=TGSH%xQYXx;L6y*UUn} zq_zypY6b?@W3?Jao#q*7$AGXY;KUNmU`iAORCr@kCUUE*=<{xC+DsQ+r)E)^#gY=c zqYCv%1}iyDQ?o~s+|*qW9j?d@&y?mq-NxEc+<21OJM5A3&KV-!V=aP|X)u60+Sb`g z2+0r$Cf>Cq?8V}5*)5UhqL_h}$Q)Q!Vu4V}0cA4JhwbzwozFTuBxEY%EeXS%U|v2* zNUFpXL|~@b`lvv6VRHAZ9)-!!sjiGFQC-Y)j*`@e!BTkgS$V{vV0 zn$)n@=#KH+Di^Y>PN+g?HD@&uValbW*Pue&w_j$%k~%By94}T2BJ-@)iCKh@v6oJtPgknrGE6WKXyQ_mU z63{7HM+Y|`uv7$txp{KTntY9QC)>VZO7Jf#cGH^yRDmGI@(7<57@1hMV=N20hxyB~BXGMakq0>V-h1SPDrf78&e#bY$!s zhfQ-uch}Om@fkQl)m1An4{+u!t8e_w{l9tXcei~JEZ#A^=j`Z~Cl8-^v3-%?OdNS2 z9^J^CgoC@NX95QnhY3N+%ry`P@I~7Cw^x7lm#_Zr47P=Zp>fj4v6zD@gtrXe@Yint zuIcRH|NZ>G{{#Q5yAx+-Arp5gbyX&%_qGR8iHbhn;lw21l9~-Hdm5QRByO&xr8}$W zm;r$cvs($t08wdbEdyvD2TD{N+f3A_Yn4wEg9L$J_R~2C*}6Rn1Bw$41BnCI&e~M4 zIbw$h@x-fDuOq3@A`v&R7El7asY8nJ-qaie9&XU!m^Pj1oTXLM)F{P3&M}PGkv*9a zNJIhwt~rKa%7&b{vO%p?%=KV)=$Ait_^BrrU-!9{yZ%fa-bD2`^POMHH~$)*`;|qM z2Fao1orZdG{I0?H{n6hWd(YcmLR3s)SN>lgW8;xI1FlHnO!}f_b$KT-jm<|_ulbU?>n`=;sCoLbtQp> zhU`_OVW6wi{Lmx&FTHfwQPf4)y^!}eHP3_`-dSEWa3zDbICK2?4abf=`oyKb^j*LE zm;UnoU;F28x$D)d|K&$6Klk9d`)<8;IH6|Y?oTImyKj_N+)SO@5SYa1;3%X}f(@h8kp?x_C2pYBmuT$3RD?|%G0pOh0TVVqK`V+;_Lc*{+s~NS2A5i3>rgmXdeEr8Li%RO-??;kKmO++f97xBR-q3kpG! zHgCG=1Mhm{I|o%g>kgG@xL#*hgRy`DLI`lutP(f`5$-Qyz(Oebz=e)8XD0@EU-}Ao zfpNJE%ti(lS%QV-SSpV&^?gjHMnII{QUZEP*HN)Rmby7twZ1qIXqs-gvNEiz|M+A7 zXy?<9{ZD`C$0&?3+l+(SawnsT)+bn*(9~gb#B9Mm7*#~#sDPEb5YKp?(%@zpowUUT z>z<}by@lTOs_M=6@UfM2u$@2k`+EKY_GVPo z%&~g%AU-m~#%*_h^*4XR9e3S1sAx19h7g!J1PRi|VKFT=$-Ye2<328&h?fr1l0)xH zXv59>Y=~u8BTP+%9iDTxz6<<1z1O$@(e*OXvKRveO<)iSmnJadS<_w0#AI6NR&saER`3rda;B`>92^V>!>S5NwQF;~?y3u8IIPY5a5~@LJ{XP% zgVCV!cz7^h%$iUM$Es~Qa+b(NbpUr_0#i;(!cMxky_dS@yK9h#YXGAvMS^C z;rM~8UpO~^@#*&b%$t2|-;CSdd;H5D-GBJm?inXk!a<^DQ+No0*qMSmayF@soV@Wh zN6*}L^}^=0tFvk}xb40>CTpixj+{LA#3LX2#eWwAuO3_P^5J53b+)(D&PBVq2?J&^%Vya$seAB>i5=AC&Rwe* z-AuC%WHgd-PHm^%O{1Hxbep@~L5xxgJejGopi+JE+zU^ut=Z%_9nZ6NbGkkA`8^v) zwf3jBuI+cTT0}TRhB4*&0()~(baS0Aw9tnH60nO~_FBS`@k$-)OY^P0 zG`EUKggo?N&?3YPVj`gs+#Hq>n1im@oc0pD9ZW(KS(AlfH1^zRsD||rEpl!S+z3I) z1thSpUv#>bg#4yc$m-X2v3d;cHV6~~I)f68SL4wQ?-uFWvQB}{Aj-8q6?r`Ckc1SxMJzn3qCXa4Mgjo5&IkY(tvjT2Rg_lQicZYC^ z3&OCf7usb@z1|84A__09+e*uM8^)$Jg^KE~B!ZV@FBTBFmXV#oCgiEzCJ!}-b+7L| ze)B@Q!%O>nZF`*;HDpl9hY8EmS&EMmJv6;EXp|0+auPASdudc7mZH;=g8C6VG1g9D z{g_`lhbqT2RaoG^A+WRydg2 zV~=9{MY{PcpE|BbkK??>8&9skWzbzd1`>3g2_ufMei9oe=+sSd@14y!o(>Ey>qD78~M^D;ss$|US0sWf4Znd#utG1=czxsU6Suu<|1A$}Keg-o(Q9%H zY&fAcIPdF0=L-Y?4lgGTfpTBY$|y$G;yX6)g+f#YjUJCFb1)cEM8EE(_NELbWd&s~ z)DKgsi|_G{@-$I|L_lDMLZKKz1ZH4`x7M^CSEyPcsi_vYyP0JWM>=xWPu+&SJwKRv z2$U01a?S1nmg1IHFApDF1{vA(kh(c@DTeMY|W+mEh(d%(?9{WaWk@9N&OgrU1Q-|Q#9a#+7N+I@}+ z*!KCa+b4fz@%hJfs|vGqI*>fG#hls}s-(%WPn}0+(A$>k1|*l6Uz(pdz2 zQL2O}4ps#?psLcr-u{K>-ge)yANdzw_l|d*2$6Q4Ir#W5KK;_O7n^yjE;1Qwj64j- zkFVcy&kZ-fX5;Pm9{b3Z>3{fzkGya$pS|G~N7s*}sdn=PQnxZ0RIx_R6g{~k)6HjY z+@J6MC*tRG%8cQ=%c9%hzrrdNC zVi1_9^(MMXoS?~&w2D!fd}eDguGW6A=QUGh9xJS^F%p^vTU&a#Wn+mFIJG(mY=%J~ zG2@Poj9AT)tQL--+G#N0vCxn(VsiHOK<5YT;Hcj74fWA)7{_}E)%8#mb6qa04!q#_ zW9vSiXV2*3fDY!8hhe&pHejd8pP9e(fxmrf<5t<--8p&m$hGs^pZx95z4FLix}Uqb zt*?&`XY-Y{@o0VcnMXfiZbKfZc}+DVntNnP)-iGRR1PWH#8CxQnF$aAS+l`Qj2ao8Il}Y~S;oy3P*O9c-`;B*>{0T9;HK6n@B! zEccxtOi&{; z?f2k@V|KWc&OPBDyW-OYHJJ!vfm){Lcm46XY~1;(FaN6d-F43^$D`4BIIOB5!Z8N) z(K@iA@9piV&g83rtS!MchvrGMEim)39Y8FlN~QB!uN z<$77x(ZYmS?(>0*5xJ_!-Gc@-?Yd;D=&M*fFQrc*EW-}qDJ!|Fngn+DG;6B58c#;M zI|m2T*C}A;p)+qT|bylyL#XpfrQ+cvk_Rc&lmH0P_3@75Xrom59^U? zZkoA-V3y&f60aD6od{O+gap@RF|rr-l}r;+KX^H`&#UZbF1t>#f~fyQ`~ZbOdcWT; ztkk=rpk6YtdVN{}6b2Z-IlTQlZvOVSoqp3i&p!G51E1Oa+|%8;22B-tSdTh%aUiKx zO%^CLU6L5dKx%ayB+UefNY2`IG?1`XuOAy6U7_(H(qb{cvbg&B_Uhi=?k=uoG}?bk z!jts*X7k{u{?4Y*37oRDM;NeI@MeTNU1A#hUXIM=()3;$=TuVnTgeu zpzaPgr#|A{je&P@;Cuk@|hZc84UY=FP0l?ICjONC=UL%$ceR z9DHGb`Fw$$1r9PsYdCV+FYY1=SP+S-AnQkYbv^A}fDGVpU66>k4F*i)P@@t*uDOJF z_7Xo2Zj2x$mCwC+KeOfJ3^tWeNgQaGa+)$RO8FKs_wl)iB4nPk4n*9|+|^Ws)V=rv zT|K$GP}`)9mEjPkx!a#*Vgu=fWicgvahsb%OxEhNN0~N*QzdNkE`W2VOhiU)R%KU5 zmveENn_3ha4eG_LOmIQo;5iuxhsquZaJd~7*|v$?Ob}vU-Rv8;;K&)wrhfT3kRS}uEP;sY7 z6y4Q5g9^WD=qaIc1}{azAh?I6d$nW+mF~jcfn6kGeSgD}r0q}TFr@Lia|K-gk3H4U z%V|iif9Px*G+#MDumV`h-^SSx&Jv9FVhGcZv8bd4O?7WA~ zUwi6TpLzQ69b9_czu>I3R5{})ojP&T%6HuHRj(f1`q=E5kL`Z`W0yX$mv?F(4rnEL zPLwL5RDv(rjmnFa-Q7W8bz}xeGP?rog&q|OOl_hE=1>2@=7V2)?6n7y0AUJ&IBC8y z-1=v3`BP^GCw}{--~aIR5B7B{P#_EN=u9dtaR$n>-nXurOQ|Jb67OF?Ub@SiD6j+u z7j=Ho*_R4<1n$H3*mWB?Dn zUPU!Ptg&`fcTnq?+IyxbEFU&@L||h+2k| za3Dt*jJupYb6we@oy{fcYNdzt(R1yEpS<>-&#u1q`zCk`(fhFWwuz15u<#b)H!#LT z9rXA8;a@%Y!%ynvHgw}St*oijVP4GAyhZlto-OC(#fp!l$OHpeDk<4j%uuzg85Ked zsD#r*D5fn!~H-zL49Q1UC2FHQ;QnBmprN0~W_9 zRU~I;Ch6ZJk|^WR!MW#;^6pRk$a}u~JMIiay7JMBpZn#{TzGCr;xI-QN33JI)J_lg z_S^ZxhttNIV>hk6`CYI3vTu0x``+`XKls6OKldL$``{-(d-}w!r%v6Vxk{-^vvx8b z#X4%2)wJt$W3qna*40mZ{^IlB{gJ=&x8C#>KYH@ay@L<_lMCU*i8IHBv$-?VaDavS zJUd0H$T{ij#Yt8O%IJiUcU`DzAjF_Y9x0QwUT=S4^9yTrU7W? zc-Hf$b9&qsFL-;%yE|dJa2iM^+9z*2e0I9C@#^j!fBuYlt_LJczx0#8RV@Z5POVRy zh2%(zSjjCn-TKg#hc@&13S)K&2$5=at3$1>T%1cFfdI}}I?Q{b#tPi3mJ2O&JtM~o zJ4v)8T?@BUM2c{vaX9){zvG9en+I3s7he0C``p`Z))L!zeK;6ZUDvg30&}Q?1kset z5QkAj+IgD|XT>|h=rt5%MWcy-Y1EFOJm{=^f_OBekh@yrGn4)U`Hdb!i}h_8M{{EFAc z`){{=sOO%`fB1+WG)NiQS%qNevbochX?S)~AHVb7FL~G7Z@cO2%CKHr9S;UIb6}S1 zMYvXm9yMmcQU_iZBwF5ZT2dH3lw|L^Uq5HJ&a$;c?; zdzhm>j?-_#8{c>A%innXP2H&b*(ZMEbBCXKvAaAB^*TU2=rMXfj?q&4bfBn>!ai_*;v`oZYX!DBGLc&1`DzVlYIEHd+m^ zq-h>2CaH6qhfqqO(~h>SOwQEYYD0&hYN+$vI|!;B@hRJn`#Dy5JzU}mdtVy zbM&(q%ksXprIb$#0KpuEqN(reA-h*pKXu{BZ+hJu-p23wgBL!mD?T+dK;ZBUXT=vMw)@2I$J9a*@tc zdww^zhnU1OXPb#Yvm2Ej^Fp)%`g5cz5Z6diFxCc z0r|=24u0b~{f$2YQi)xHws`3=Jh_X#%f2{(8&b|2T{o(#tQVht;m3rnHd%WEuMCuWNk8pc%CV=K2s36NN>?Y;1Zz{QnY zqzi^_fm}qK9e?V!SEX0H@b9i| zo!j2U&fTL|f7uORadG>F&+dLs3GCU3TFV``841W{mK+8R>}IYxGY278%UUFY%z^P@ zKL5|3`9FT{+4XC>HN!MG%sjc>AUC}Gw%5JkRX5%8Cnv6ccJB|<$11B%;Mh?)e%Y^H z(TmgvK$Z+GD%cJ)6W9#B?1ZGaoQS=cdza-!In;LV98Js2M)ozxouu>SwkEm04amA=N6Gc8CphP5Sc3jGtdEi z1P`cU?pmkPGvRP0%AJDAtH>$Ol>-tHc?gnH*2e2PR5TclV%K&~l0-L~Hm?rILR#SJ zNB19lu6g^r)^7UK5wBQ2#%tsY_!s=ruXMlnhX;>sTU!kl6SP&DdDG<7T9?JTlycJS zMirTQ%2|;OT~3)KM5#;@u^6eMBk8)-c^5-)M}ntbJcd$NRrqdlFMZkUaHzwn9-mk} zd8XaFR$_jg9WYA`ARMEEO#y~fHOas-a}_v<=H!43hZ1T3nMc3um8(DgBj5C@`!^0A z-hTN1`1FN`uB>kyzw^}X%C1$H&1U;q7kcu@`cX^{rsH`|+gJB~`)5D=J3s$>cin&c z*ZjqIf9vo3=?5OT`fq;flMj9Nfg4WWact#SV=3jN(-cGog9t~OcLT2OzU`K4TU$T* z4<7j5?fc&FU8mMh#XtD5z0DoF_0-DjP-~$GLPrv)s*tlMcOi;QgDSWgIR=Ah#<_zK z1{JN>gk)lVbXCN4vB<*^*GAmzTbk04$yS9l`B-Jn3?oai?5Tatu0_^&kHJ zAA9D}#~%2jr+(vX?snr<*20F+V+kz*CfJ$K3B$S#3c z0#k2ra5b0fI?=-Q^=jlYTQiGDA7jqNm*G&=a)Fk$%IrENrA7V-AZwo=p=uzcCaK%; zGbeuk*M9Y zGD??h_fs@`j=No79C*`Nraaj1DPBd)*E9~ z)%FY1hd*}p+_}7ci2WQk=W<~$pPM$F&M}jLt zf+lYp=NNW7d44|}x$Bj$c+=}o96z~wWNkbdg%ArQ!y@jz7LH28p~F-`VCH4*HdL*| zC=&V$Q?s&2X|+KQxO)f!FZF+(O2r~5SqdRIf_Z{b@h}(rC84y@dR9%T)E_z#mEYRb zN(YklUVBf;O4qJL@sb3j?(SXJc5Nrj9N4lESfW_A5Q7MHO~;W;y;-!S(h+MO^ZBo<0up?ALX5`pn5Eo_ylzPd#(XZ8sj-Si5p{&%6e?sfvUm z8|teiiu#vW3#w5V?U&~q5Rs}f%hIY!{Sb3~YwiEx%Z0XB;QFDcA9b$N>b(>S>{P;@ z@4#K}s^9&N)9<)>a7!Dy-`)JfPd)dkm-KuXP(2KTDp;3=LuwKmSJj|x+F?Buk*>*1 zE*9L87Z!-eymG@}Z6h9CuZIWSwR3xqywINC@=Zl)ws#;97)G zutfc2F9jMfS9VZ&PK}xR&`@{lY+(iw8u93Yp8L#;pL)&4TW?r7`^@x-6%QY(4E?aXoxAuwqsWEi3EO>r`HXD6c|1EOGR zfq9x{k8fW4nmg}!uE@t{2nK}HkHt<7f$hSa$lMe;5o3KD$L z;BboQ7yuXceg6=u@D2ua*;9tLZVLpEk;y~`D{-_^jaHi7m%M8|=R*IwimMYx)2cpx z-#z!e|A=1DY+$hc1@+$(bddTPK}F8wW_&EZDx2RDmn8)QiCa%1WK4%V6hTk z?9i-1MAfShm>5Q_`oSW{fH9GTpb5#T$)bs7=MTrb`#5?F-Fi|c$XhAYbuAuRoeZj3 zlgJ^UHfJ~miCNX$ge9rx#Uh(p5!?{WG+B;uR8_-y+E+_uLsvKvuMAhL;?3Enl_kSV zo20pua6s?#cMicdCvs<@5~xs4^XofR0ffv*$or~GUh;ed4*maI)W={~z?A~r3qC_` zhI)jqqnlq<|Dzw#XCLYQU%%u(@jJdapcftnDV}`LDS}ra6NK6qb7+f2gHU5KMszg$ zIDde=hnz4viaYQ27e9yTvwr57zVl{U|8~E%Zbu|um%-D6>UO3 z#I*&i>6gC}*r9Hu3xBDAXNSX$ zNI>Oe2)MrP_TTw>(S5-VLb0HNiu`(cYCF6Kv2i_eX{j7T&#)1ZyTIXH3kV>EawT^13;yp2jNS;f<3gJrr0|e%;ws3 zU3Rz1L(OuodG=2pdj8nT>dI^R@Pa;fHEIvJ1#x^Z1o{+IghIGRo#9p zpPSPmxPux1hBG;lN(A?nGQ|_YMg#&24Ed^Gx@<22UJCXAuPIz%Ye|qNEetzqh0u#BAQ*XWE;yvZ!zlL)u64vr=FuRjq@02eg zSiQ!nylYCb^azImIFiFjK@5sZ{s*w7qL>&`)xoj<^!5H%cXtvd9Qfwbw0ab? z18w%m79>UJXv>SdJlY8qVF?nbTKC9KZrYF~VuqB5Ot(8Ui64ofQ(A)YNNh zaU8j|`LwkdjA$M@_Q3U!TYTYCdg(uH-SwwZ;8gAgKX zmzhC9l2PYI?rRkt-;nu%4h5@||C6de54$Y8>ca8QT5Iof?(|MIS65Y6kLh$eLnob) zkU?dz1Ld5KlZtm*w0h-RCT@e*1h+fv-e(~5u=(S2aePx&!E}?fm9S2+Bpm2DhGlm zuPd$sjVhwfdFI_tN}M-t_I+Pj4c;>3+Zh2a{v~N8Knw|lspEv^2h;3P+dNBLM?~7r zxZI&lE<=W57ceFXc%j?6`;BYk?4pd7&r|47Ow{4P<8Oqz)~Ffum5Y z0E|3*|6lyU&wS=jKJ?Jf|XR>T=PPH)D+l<@+9Z~KJ0GZr_ z$Gs#6;EwJ(=1*gBlGAlUqfO%}GuWLqyLTn^%F6**Gt5xT6TPU}kg}VCBM(=?U~RxF zgSNrRCwHEGt~qtquD5)BQJvoO=Qq=tF0BAxag)63b@9!wv>N%vllItWecnKXIFi84 zA?oHN<`pB1!sS^!u_Ke?cisN#SMS}}zjx2xm6es@U{J*fKw>Bc_udNw?@K_-%+f;` zZeOMcE*TqEDh=V~4fduPcupl&gs8tJmQ{(UZ5m+_VHdcYmO+=GW`$KZGlx65=HjC+ zgDa_KDlBkGv4(-sbxG9fx(ZcT%-UwY=-O6QRjHP`)UKvB39+e`!-N&&f~8AsPN|H$ zy^EMV)?#X4rfex`+a?wcf$Kp;3pUR=x2joH8%vsmg9B!s-85^Lx{BjqSQBA3UrcAS zAi~1)-Gu}SRRmG-Pt}8(gr0r&x%*ys-y7cWhWGu-d!KlEYdD+$wU@q#rICsNlng|3 zcbF-_EHJa>b)v#`mp^rslWPF-628B2KKe2we>uw*(u8_J8WSU%p>&408#FlIgO`2% z4Wis#D5cN(^6% z>uZBO2S@vc7!dLc+b2J<`NSDJ*k(XCuhVs9BQle zpeCw9<}etHCZlHBY+k;cOh+q|!FXKPQq@dK^|0p1Tg}zf?uNjl$wZ`*P^rR_b-KvD z-L#9`&S5PP2;#j4yH6lDC?lfi#{l%%4rG?&Xpe-AZg$0VM&+I@N!2XN=(1kBXYR}~ zh5>qfE+=GyhzNl?%0r$!eeIF4u5S4L0ZxNG5V>-&(W?%;YBlWp^$+~|IO$(<0Y zDz;{TCv+X0Lu6%lj)D+llN&=9L|{;NIEOeKgcYLDQ0JboBF{GSPhYt1EGwg7OSWf_ z-+kZSsDt1B^qJ3ZiPb}`)X|wu%`SgpAbI7hOtOKk+(JW|lz|8s zPG&han~h)Hq}v>a_sgD$a~>qtM3V|rqj6RAnWRo;3Zg(nY#pgN+MJmrlnmVBTw}|y z;ou-7%oYxBi7bQ&=bdhIw`*o;O3UB@Vp260W(hDi>GwMd0fy|E!}9d&0JtBL%CsWE zi!GR$pk6+?zVf4xP+($|7uKgHz>xN^dN<9TReZNTD) zkeWcA^D>*pU>({y?`-<)vhVKF9j~TCci00T=i6Qte&FxvZ~e5MJA*x|n1Hsf=_hyF zhpy(2ej0-zSkYdG^rRP3hipquxcBxuDX8~&k{gl7DzNvJ&0Y}i5~je?&jl=4Qflsn zf-9dC1JofSY7moz9?I%Z7)AcmtGa-o?m(ZI16KkO#brgg10HVZk-kjj;yt@m7}=$z z&nT!YH z+@bc->j$qmy64c*g9o3!{`@ao_`QqitaApSPE5f)CGCP&PDojqxs<}Yn<)ewgiF44 zA2;iz9M3P|(o@Z|_s;K#ku$Y$1kf#${aOJk0^6^m5wQH49K$d=5lNckBMQ0R>_fUAO)sD#2P0s{`!KE$jKA6^bv&Oo4Q zKvH?fstyh;3EO8}6Onqipa|EFIP|-a!(rf_=A}X9gH>8xXYBQ>r);)ehC8!N6x5Pi zra(F6Sh1_OZH{r0-E!*Mq~l65a+>C@>xR{+RfQQ<+;D8Gx>4GBqJ8@0rMI8jbI;dJ zF5KV!!7uH+aB;9Zs+%zuy67xrvUysx+A3+=HcIZI3QM^&n2VZcwG6;r)w+U|nk#X# zu2D{4P0bFol`HC2n#zO-t{KJ-F7@x8jY8>tHk)19I{gJQa@AgiR=RV=Ejt2Hj84In zC^BL&g_+5CK$>=+f9~&o&prR@AHQ+1Gk^R?KYIGXvwPML48|k%l-rC54%Tipi+M9# zk1^6>rd`r(oo0=rf#qD);rROP2lgI){_`h)=-vP3yZ_d^zxi*z>E2fz{^=k8^urH6 z{?eD+vv>d6Y&P=+S*N2(HK-&na+JL1@OrLBpZnjJMgxA$-#qq~f6br&=krr1{LWiP zac%(?BW4}iY@wDE$katm226ym^}tjQN$0wE7}iHVzwR|-D1LZ@s)}}Zkmd%%FnEZh zoe2>|#ERHGFbyUgiMWGr<#x9X<8UoEiW84{DysC{sBB!Yu*vy6a>b3U7)~Ub!{kKWL^($NJ`_{Wz`n8|?UmI~P zYrEYfzfM{0*nxwSeJg+T&>tjA0TV&x#wca?asWiQQ zvJaf?h0JEX700wM|8#RxGq>re(Se>^T7u{_xIoW##>+e%4zDD3FAnbs5MUx zQyu{G1kaulER(5gh7**bg0K&~7rH?60=6He`FU?=Hrs`EWU$QM!V}1$n=hQ!OV@C%l{35Hx$FAW^>)W`E8}}#$$#!%zWXS2 znx215FI+*JVF95MH_vcW2P4*uBA^r6Zt2t}szZ0)^6J-(hHHB__U+lbJ{S%|U6rhn zUY_d?McKakW^@*JGh+ENqT9`g*$Ji3rdN!X{Z6fXD>YM976Hn*PG!S3bF++$o;D*g zGbH6AT~l>)x1uPvoJ+Plu@EzLT?V5}A^B zT_UFt#LRLw5hh_ZW0BM)gTtvr&N8z*a+}>vD#{B_DR;>T1VOXt%skf79H~j#DaTR( zYeXO+UFfwdvz5tsvbw?{&Uvwz&f!)K;$qsSPGcR2xSeIGcw=Mz)C;FR^80`Eo^Sc4 zcYf_V|L6OEWip)Gz^?#_HNjMLp&b7dict2(+R)x4O^iXs43X8R&2h|a>q-rvZ^0GtiJKD>p%JI#6X z1dy9@pZU|JX6|87biWK}aSt+^Dv=ONVMD0Ig%PPHz}?kc0cI8e>h7KeGR5{6w;s4@ zbo>6np{wmh1q6ea@*Vr;`#*EyVPBEe!#6#D?dfUW(kq*9KXCNk<3~@Nxp;kN>-pzS zyngtyJCEJGm^QxCO;24&m#&PD93M!SUrU!Sc22R1m8%8jWU6LLo|VkmnN;1~W30_o zpbRz33>FYLvPVWuM2=+2Eb&6>{^-={W3;YbZErQJN9wPB``Xbv)~_eK|HBt@3LXXs zW9Sr=h}CloHYD{RWQv{3IP)C#-$ZvG^7aZ&KUTU4krY)0O)y5AK?cn*xA|3@64?69 z$ckQ-iN&*WkljlcKlE!)oPG9l(AFrqDqIVK;8vD0hc2|)vOFmcR`+C%Y#vyK9BK!X zX|GTqcCJE9s%GZahXSUoU7#9l#L0Bww%u997*yPJN~B|w-Sb=e{H1tr!umR|4b67C zrX%731?qAnuE<7Qp$gV@r9(JdFX41Y!REA}YaG~ePEE7eA_>fuS$5|PB2fMEq5?qN$YU!lljWf=Ms+3*?h0oV=LU&e5n_~NW$le-!syiF z2HpKN^zLuPXks7wAfEUH&R@#^^*@0@xkGY*Jct8OhN*`P7jy+AGrM#a^UgW>bQ4E! zU;8KjRMMqu_kSGG{Px;!x(N{MUxQ}*?GM`j{(bDf8M95q0Lowo6kUcJO2ma`zzT2I z&j{juCScKSs8P11->6tEdId-SW`Q2yHebecYS9k^IazKN^Q>(~a@;>eFulbvbYg-TBIV@>7`M%jcg0Uf%dN z%Nzpto_i{dQOr&T1A%Q2z)snaZgfHwc+MQlS4LjQgFdCG6ssZ35G zc>AP2@}Wy-+S3*@0 zCwF!4ZC5CfU<8nn5Ug>XQMEV3^*mkm`IbXrP8^)!ZZ3jgP%>nqL^9y2*2FTF%sy=w zDK)J$ERua{u~wDbrn$4#t4)g29Ij1q{r&ULe==X+(sQ%0v%z!83$$8y$R_fA{P6fBb>J{bT>nPyDxcef0e={K|iSv>P8hy8m#q(=jj{a2=QjF-9H| zPmZqn-sZ4QU=?(aQx-;ent|7d#Vgx_&|G)~-*)n<*Oi=KpAM+g)u7>Lw^ld*>( z-?SbE(Su-Rg~tO3qn%sVIgt;eNF{XP>Jtg{@KO!OuKc-=8I~3mwAs^4ejjeX5Q*pCaf6^Pz`C3yjFjD ze(m@x^J~8Oka^>rMfkV>^B=x=?&3?=j%S?@xK>qnJ9fwMPn@{_Z1;rFARq+9K+)YC zX0RAULhN$mFe&ZIgh)YMtt14XWbO9yK_)6`Azw1;-w+r2@`MWqklNYhJcH7Y{J_6F ze&m?8?fRY#8JePFqN)lA!Q6;2oD2wdU_4dJDP`69e6ccK`NBgFefW?5I1#CDb#x^j ze7Wt+ea;950x859322>!$q23lB{z40!oBjimoc<_&Sy{4;xcJx?ZR7S7t7fiEk`EP zB2NQ@a&pgbz!a`9heV(3<;ng^GoN|BJ$Yh&_98YLy4HmkuFx}^`s7Z^j#sYJ*WMey z;%?tRuxr=skuUo7El*m4ec=jMj}_dJ0RclP3c`@LyYTp?w1;j#{+h2GjE4sf9yoYt z|LWSxa5xkR5+nN0X*muRKAQ;3074>HbMEILU;ab@%&gz)(BCjinFcwKQpd~&@-N#^ z9mqM~*zJpvbh&FYsF0Xi)-5xKuq87y5HU;kt^hg!LKGsJO&9H=8;)xbjaPt-EoMAfmZglE~D(^w=>62}B{QrmjnEvg{65RR#;QMafAu zYjF#yxd??ia6{LxZO*3i(PTUr)*;BES){J31|>Dt!OlWCXNlp+&Bs3Rr+@s5zx;D= zfBU;$|N5_Z;K4r|)B_389Hd4hOMau=z$LPq`vaG-Fq>L=0&YB?N2fV$w?s(H)U|H8)7%ngH+5Tb%T&~ICDoRe3y}aMByGNa&r81J>%aQ{ z_o0vc)aHvP2o(_lC9u;2S87x8(O|HrYp$8M1^QSjnVD}?3>R&SW-oG;o=g`k@d5&= zXC_(rY$sn8$V7&%rUUWN>-N5U^ZM3cCBEz3Z~f4-e|qZdbAv#T>WuH+9rxXJ^WkZ` zk(>FGUwr=fO$QF$eM|_um###xY^-1$ch7g%x4Np1ArJ>Lm!`=bv~%MiLLqB1F5D0? zLUD+e=5&$36o|w;X)@!)V2+##XH&OlkL(S@%bW8P)6LI4dbOLcUUa7Qp;c^MbP6;a zdDnS1kf2OE4hjraPrH0{Aa9;%y3L+gLEH8oz+x0612Z%MP5~wJudFRZ1eaxyAwh(z zy4^YR@JHY0d6y(O6vD7l%V->88Ec87ds1yk#FB}W0fk67#z8bQLl7f|xn+l|Wj6?$ zIWalIV8&=Q6KoiRGUnN4>Z6o{TVSVQY!{wRT@7tRB>+;!6X^b2(P#xGiRk*N> zV^mN|G}E@ge?kypB`}*fJHg4FMVQ*O?U?{&7ITGjhBAeS7}?Y_v$(@FlQ1)@CZ}@q zmCDJIdPjiSjq!-NY^fv+6sw&;gse#51;PLq$CtF-zuzis2n%KFaA#l^L&X$w#W8$lpnb?e)|<PjLM$SJ!PQCSIU66;BjqH(fbzvNs* zX0S4mYEjRW+s-YOQ&ivf8@TB8AyTM7xTDl)P#_UE^XxR<2=DlI!`1xDFM7TX&aRoN z8j1Q#lC|7FMf?bM2*?*czu@P$b6ugC5)w2!1+bV|nMHESB9u}`n%HS&?^@1bcXJvm z-P+ww+L3z{vFv84GZ~{Im+i&Q+~ZgV9B{qC3ui1yXe(=^U3i0tR+}cZEn0)++-6VC zYMwP`7Z}Vur`#eq$Xt_~In+E0o0;_mv+U{_4$h4MjsPYK6`Zxr)!P1J_x!o5XCG}} ze2ln=;R?)^9VJ$*Jh%*wh{3_GMM(@-A{Gv{yI3|F3{fBQ#C$2yK zUp_gzuruDb?quatN@i;Z*Y3FKP(7}<=3D2lZ=Sh!u{Cp%Q5f9*id$Yad})*P{MpS@ zC(bOo-7u)yglZIDcGs&Oec8d+STqfA!}cId|&RUAMoKD5agI zG9RziRbWmu7=`irdR`fxduXx$(9XVht-kvIrN{ok?zt0w`|T5%Ta45R?Ivp+F%pP8 zJIDhl5T#^$CpfrYDjxVp`qL=({5lP zh|gw5p!3_iXPf8$#lLuYsBq!b)%`aeoL-r~?4(4P#}D6h{4*ba_^n^{l`H#4mo8l8Xyd&j8it+g(`K5+>qA#vG>vK|!Eihz z;*>J6sdH6}Fncxxa(5CkH3m}@S2HIexVo1P6e1>ebuWiR=NEo4o4X}2Id)sr zN`pY9V64qDfGf0h#{gJ!z}t)1d=B&Lp68TWa_Ax<8>u0=C1`@FyHVFUK$ekOSAztM zR(S1DSSFia5s(JPoLG#U-4N7by6n- za#u>GUC5P))FqNDX-2H1$@0j>ur)b;^Q*q19*_6$*>mKkgL^jC$D?rwp~O*AKT^7? zi7?bbM6$FyT2VopJNGkWxnE3+rUv~7-fy91&O$-B_w9J0X`xxwP`YQzC{-X!O__*t z_8_6EA`s!!rPMWD5yo|GM<5b%1CT|C7;V!MSb{KfT~{gP>sPmlC|07T-8_XlFrjNx zR+YdYY8OcY6H!i9Hkq7N+a!S{1ZU(nSu%%_P)=rQRaFfJl@Pi5Y`!S9z|Ep_H+Ptu zC373p&}YNqY> zl}qYvZl=v*Q4N9!=akLO0L>lXrHPUHiQfAX1R^sKtUz7n+02<>uE1cvz5Rg?{N#&Q z?gxaHnN?m+r6?~o<>ZbUNaaji&^mWjRrJiZf7$U;mg-ixyTXcbOw9sGruIU2W<+ZO zTljpat6SF=b(i1##y6k6cI^|7ezrj?9=1(Ced%P{nScEqcOTfhcIBL2y*iz&PAciGGPzyN!?VtDC}@ID{mEA+9`6* znl&34ab%8N>x%)`YvYNebanR3HT!%2^Ya@kRX04GH}>Z=#e5qXUa>=91SjGMc4G3* zJQ*^aMI*2}!elRYuOJe{(01;bNZm5bNy_-YY`I*nMWu%V=wpOP8p3KcZ^j zzx#gwNR8+8r3DEIZTePwWggl#!;T7RFA69{HY0l&GoDYqG2Ms}3CP4{K*0K9;k zC3~o-YvJxh!UWY0uo1`AQ5~94?4MskaC>M05yO|)uYBd|J@;SvKTqQE(%o0KQG>aa z*Ty$kR^a~<2GjBv3|b2H3Q5`%s%)2D)Q3Kf-K)z4CSR)KZm{NnySWPW)~S+UP-#F&YTvPy^;tZq(DpyG%nh`CD-qO!X&7tYod zx#o)9JMYY^ebvfd+4FptFXpq#O62C+p=&Uk(blC)=Rfg>pV{{LligE+IS{M6pgOvG z{mw)Np?|e$X*aZkfl#hh{2WaC`zH(NtW;P-z0JM`e zv{NWPVj{8N{@m>8_r7=~S#nk;OR&v$zH@E&;CS+?jobHM-#Bkq0_fP_@bTeICw5L= z)axFiQ_=1MefK*#ITc)^s5MafzRELWC{>ANaVJJ!4r`_O48$-e;V-+wg)kO}5V32b zijWIs!Z3pr?RYpJrdS)I5dp*mDu(k?0048mOJ zChD9!ZIgEt%`D}VoYlD;?UG9>jg4+bt`v+d!weQg#*8+5M*_f98)rg@zZ(V#5 z$8VpsSra*f#7P4gdDFQ9bs%OBhJ6#>*ubT!4cUh^>Vavil>h*V3%dl0rLq8Mw!NEW z8l;17j;mikiuW=Ni30k=mBACBpbFRlPB<=5z$kBaS5Gw;Ui7&KAI31OX34rlyBTU! zkHgA=z-zocO_nemOE+g%!18mmQ*V3c`YXR~PuDgGERlcbKYsYy?#?Y6N85Hbpg~<# zLk#Y_?<+q1HqLuU-eg3R`*=HvRMzS(f*nTNN#RcjVchD zMdz?kg%AXQT4o|)As{7nw`v$l2MORTff#Tr&b9(z-585XM7D#Ln=yJ0`2YINmr^JI zH*;0B(z0a+f`qU$-M!`b@t^p2KY8)u*$@2MFZ`Q7{q)Db=db>!@BGN?{?5N??_S5b z?Ti%Fn1mFB3Nms;cbI{cU~r4XV?ePuiS8nF;ax+XJvUGzD^?ohyKV_z`k_%*7omRJ9_g?`}gl%Utg`N7-A3+ zDlh<-3A2R#FfS)n0JLP_m)@3MjI?yUqPIEq-R4E4gaS?%>uI)Z>ZQF;m!48Ct%=Mq zXpwFg17xg3q;mIYIcHUKz${lWsyY~{(<1LQ^#ZR$5F)3J&1||es|HnwqDf0YHklU& zgP3y80CF}7T-7YGUd)=;C2_YdrMB&=80xwjjB0~7ZEIZ)k}Z-*vyw=t$&iPGdQ^|Lx3BH)ZpFA#4~MGB z)t74B{v^W7?xx~~E#e~8EG$CQ>(7>)z|tmFE{^pwGwL&fi_EM~^+)MzwvpEN$;-d} z<=^$5w|(or+xA_2?D~5@_&b02-2Zve&aH&Op1u1r)L}JM6hTTkZEK6^JXY0cZJl{wit*}7702^-`|!;NXS>%g?pz|I1$Jh$nI$z#q2j6z z(#ngMKWpAHVnK2H&$I6UG~tov z)_i-svajpBYp*kGdDL9W3znE0KvMcwdWi@T3Ty-?NM995LQIsC=@4sU+L(8C*PXX% zpx^z>$4*W!j;kSia-uEmp0Syc?v7zIW*JgeE|VO1?^{;SAEEtbr5;T8P;rupTj5N32i-Spfr?=L{lcDu3ZWhXbXdCm@< znGS>lqXgGm(Gv^7w0A&|!zno3x_9lan~psE^odyjkw9+0VvP)<7^NPCI-@pW)Xl{m z+quR!-5ihYAFNf2nbx&bijZ|B1|^y;x`nD~W|7r;B-Z5)$xN67ESal26O*9Sf>2*C zu2#bDsd)TJh-;}5I)xGXM1p?UDFS=u!kI1wcSfb&u~>rp!HY_^1aW~WgghV=U z$IiB0z0BYK_4M6uOz-4=$es2mw$<&PB{wM7i$P z=Op!ek`+J-U;6Jx?lBo?k>;~@+M#1qWzbx%lzpDByOsjH{xM&Mu!96nk;5SHWIPI8 zOh{!uga;-8v6}>}eeG@E`u*Sh?jQbzOHW+?JfU*`vRS$up9uKUMEYe}zc&_%Vqoei z&*IYaWoYp1BF;J5MUQ`>zjOtGU#slj%1h^7 zoThDe2>J{t0heDeQ2}U$io1Mi>jyyQ@Z9e!#2|AeC$JIAo;?TeJ$$!b!qexUZ*?A7 zge1FXrn%cQ_QEsm3&q7;bM#*Oi}P2vcXk#BUV7;AiTNiU{P^m8_6_&E{d-pUxhF3? zm(L7n7!-th4CCqJ_okC!OPvj{$?YA1gA39Wf&o~u#9$FPfU&Ha4QB*SoYk32kryn z!1V;)c?Z{oC=_Z(&}`&HByLI!ONoTx>YY*~%k0Ev898xH1v*Wg60?WUq-<;?o^#IX zM8*WwCU{naLF6_!-a1HFA~{oH5K%2TYfetl0PEUD3E8u!WZr?TJdjzlLE+g{S!2a@ zvNpHb#gIKzlYRT|oX*ZJX4jpS2$nl9{m{g&4tFB9b~-(Gf&?VBm*NujlD6(dmX!jV z6@#%mi#eR62o5Qt><193R#xXPo`3xv@^^ml-u>(KWB=h}Tc@tC9otVvO_zL#BX=IR zmFjyp@(b$jsG`)B49LM$b=l9iXV0H}=2NFX^dCRC|Bbi2{d?c@EnoHS zuef?<>yd|^KY#Udhvx9)fF7*==P!Qv!kJ6|#`|Lx{-*No5!C;W4 zov26l$yyzmsu7P@hmv&r>0Iqkt8cGg`eUmn{@L`}mHO!I)qFFf1{oHeE0e)FkSa)h zrNaIdwoWP8xMm?BTV!yJ5I7iyHM7Dp=DT^ZP?^x7w}i>tM)6)k)z5csP68NgZd@^j zgp1Gz&8}Ho6KlDf>MYash3P1aR(X4tw|0^aDz8Gja7tzdC^%3U$b4?|-CW0TdgmGq zE`7(peH#fjuWcW=>EQL}w|@7R{@1O;qdM1|?dZy$cGli<>&vvl$6x%Axkn-bS2Pfk z#ufxJSM{XG28$Bl-dbC8%_L@pV%2hLGS_m3HFxbZnLvPUc{w;X%v zeJ{D^Cw}3_@7j0YefQma`SP{VS`|m^WTCD%FKo?r7S$kt%*?9+i?BOVmt!P}m7A6# zQWkM_MGlp)1XJywcPr+JUg?WID#}Yxc~51S6>VuLhc1Z@BYSj{_4;E=b!$mpZ@Wc=P>z~2fU+us7P&@bGs6vxG zg0Mn9vP|9>SI$P3B=CUznopnNbOqY@d}_@+Xl7_?RXfiKp21FC12wq99o3MAYrMPQ z&pw==e$p0-YDm{JJ$1>S+V=Au))?P#2YtXjAfcR8Q{V5pSage~33DM3q(J8Ay0SH( zop;0z_q2DNwejYN!U$Omq;je+1*4!Y8wietV~u`*W4jenOV+l zpo+mpWrX)KHkg_8SdWSbxoOriZD~)RpdUy3)D8yphStAaTpfuYcyuLmj&HYV~-1bL(>!Z53T&Gk7*ZkcvG+&9857 zXLC=s5!YWj-v5d{cSMy_i_;(3{L{zn*{M$z3RFZD;KYH5oQOCO+%%i2BNtey_tF;! z6^v*&nCt^W(=1Fagi&3uhI+8r?SOj!p^csG>zdQf=EchwPv>q+gr_?SG6~F1#H^My zwFH7WTv2Yc8x`>|hY(kUQgBe*gb7e5aSuIoVN5V`2qK8xwLmTak&`1iEO2zsj``9T zXFXcr#v}lj+Dm{PBvM&FgpipQIWiSu10YDYjv*r+t9LVWFCE@__r~#^&8_E7ow{`S z!sXe82&pI}YqwLg9>`n-M^;0&EZh*UD@02&bQ87-MIDm@aRoiM^V0dX1>$; zN=0hP$+M|D5p(Ly0E+BZRs%P)q{;$e&RL6q*>ZL&Q#i*eng#1}2-39kb6eYk+C7>r zW-^QxgLQMCPcdtX(APTy2MXeCkAHerl0Xbk+xF!1hcO|0PxwB!<9uT=EM@m@(c|!3b z6FE|{0FJ~UH8o+;Y{G$A&76q>#dgscj3FtTR-w_HGOa|eiM$)kE?u*;7wLAT{p-W^ zYI@NZO{VO_DoU3EOBC5jZEG&>QMi(@Qqw~7LSba;8b!2(rQc}ObO(_Tsha`9lyc@! z5vU-%?p9_l5SeE0cZWtCR$+J680Wg&48B^_3pvw5eM1hu^s{dbkzvV736?o-s@QqQ{;gAZehtQmZ z_F!^(wWaikOY(#(uIU0j>@Rg$QV$xd{PD zk5+`DS8$m2E}b5ngfA|oKm09(8fhC`{#3z^JoB_bH72gW3<+QY1*%5I1Gqo})zOr$hdsEqeeMS_=%Q6GfyzR8i)EH2J2wYhb(dbCzg_HEBk8)*T_ zJR8{iu^$C4VhH#C>k?wd1k1n@DPTCjft<{=)%gxlfDkzln5y7_yN1Eg=P+&l_FsGX zy|37R;#VKM^2qs>{d+>>MQW=3!^3yo`oPJ@|LxEIr!SuR0;r-m4pK9PibF)jh}j{* z#>0)AMvK%=)8bE_`^``O)NkCr=S@HK?jL;X*Szt}>C;a<{_GBRS8hGBv9|KS#~%3y z-?{lOfBvt1+uykBPk-<9GY_6V6c2A47_(szcy*NnaaGZ1gyBHaJWo%gl`*fsYk2#@ z&i&-(Y-``@nuLW~Mu}h!6)98KApjeDY0n|(wpTzsW*K_Bpt_PUq(LOkPZ*oPS>(rk>mhAt+B7=ZUx!IOuX0*3k8*LVQ$wzU z3NIGwPI-nGPjo4HJA)%-Cki}k78jZq{=(mR$&r^0r`LB^Rz@+(&;I>ixjs)XJ$~fu z<~`WTL(9^**Z0K zDwZ{c8ghaussRQow6jYOKjcrJ$ny@vA@3@E@uWR+&8}x0j`Xc}g?GFhw;ssb*SpU@ z=%pnmIdw)|XGzgnDaIu=nD?rv(lp#P9wMaTZ4J+C4X=!DK62NqCutT#hScHYqlSKu>Eyh&RoF#-ZiRZGCky zZ+5n)0IE8=xsz3O?2%=LB}fcl)oif}oo3Hk1YyliGhUsDWHS#{Y!+QRZ#`L63mjdW zm}xMK08*RVuI)5?a;^l-sm+#`Zd0Sygk&iHVuWawZmG)|?IMP?YQ$n3kw^dJ>CMyQI6AoR zpu{+g)gZ)^mrjsXCL|R%ZQEHA4kRR<&1Z8n+#ZkKyYKG92lk%Zx_tkohd$SQ{v6J# zH;zCUh>V#l3Sy=VGD}RPxrM2D1~Q=3m*e$13wI|T#A=Nwrqo(C4%K*dqg|M8&qGz$ zvCe7k+O+NV*)!*JY9s`Qfrv%Op(&dtz(v^2%o2!*gIgvFy?6jZ2y)@yYkXco-qD2tnLjH3^48ns909HL;S* z?{J{v=vMa7*#}b0inp8 zOr5Jr!hj`aIG8f!wwpbB`Mj`A+XaQ}DZ?^Cg>DRY42Ia*MTjI0SE?c$OYYPm0eOyR zpTOR|^wOJf?4Un4gzrKGN??XWn8FBT6a&mlsW7CB`PpG5@V7TEvI7ZVP$Y?Pf@#0D zv3hR2+wSI3>NxTmU$loKPIytaLD zbKA^CJcAPXTy@@HEd~d3jNQWQ+|`&9R#!)d#`Vc2C@PVPxek$&2DLg$r)J=3mn6`# z{S}cSM=?i-lpPA^KCofwKqo5csS=n7u)ecVq28BRYp?irrDY+ol+Z#h9cV-n+>182 zJT$%(VSt1Q?5+?v9BD}ReKUXMyX_C&=MQ|)pZGYeqwW&C@s2n~AXrLpfjB-B{Jvk#zx`V{_dHRDSmsCbtZ;`o zQU`Z1K}$xJ6;m|&U8on{7d;7zr?ado(0(3d9*zbxt!X@qv;& znd;;0-#|jS=h4}RJx&QvD->8Y7Xr4Sr=M{MG`LnAu-0|H=WR?>0 z^)zoizv}ke7u)%>Pd|LYE(}p6Ptp1A(Va)CgHP`~^L#ps;L-!Q;@}>J5(c`ncK!p? zPc~>8ZUQK?oZP;A>f+f~9K7RY$8P_~<|%G)=xx%EU@Ygp+R1W9PFvy^8HkYg?aZ zOd>X~EvAjrq~6}uS!4Amw%L-|?rwo(Fl()AvebianyGRjoZdcn&%ML1`TMtZjm>su z`)@w@z^{My{eSeo?_GWUbf=3nSRb!n-<;m}`nw;${N$%Df5buNnNU|eFw5%M-4!WF z=(H`mo@6PbBe0@{gTRq1hM1?;+me3iu;pTHR_tCR=E}V=xJ3NJ;4lwTy>Rhl)1-g> z13xRH@l%h!@UmCj-ORdb!e+jCX`7kqQEh77q8p5>oHS(}jw1*;rw|21MP!n?9D_Kc zT_h2!>%gU&mB`FGEdfJFIg^%?EftAYDLpZDhmuH%uJ1*vOm5I@L?qOcRzxn5tuTUwilLe?7S}Sml*fL#@2t zwG~&&jZ;v`$>-;N_c838#C*p)f@QRwwQAV~FokC1gf6*MJRb4x6kq(jKK`UlJ5(c{ z5yv)-QEeDID}4pvrHSI38LIZ*`N^;bgM1v3FxWpUxd~Qb$2uGnywnedNfGe^R~_9n{xMt&>*{tan!St^B*qipf^7geOUp)Kh`=9#VC+)fHGer^R4Md{w zunKiHH%(?aYa(*8Qe)`wOf2q zm(E<(?RM>^gB*vMrCJ|so@~#bZ!JU?={i*>mS9aPvS(G#nvx}eqEwm^Gn>OYtGH72 z+!}=-9O1R*01~b(r{omSX@1Mp2HPdxdqQ-tnY&xXcwXLqyQ*HZw&;B?yB$v z1J>8Vn-5oaQG0%`GL=kv1c3*bfs4?Ki&WYzkr_fDBZLapx;jz@(6>ODfrP>k9^7&- zJXTol;0oPtEiim-O^9N8fyg0FT!DfqVToxYXOMFg*W``5L}YWy zm~GO_-dg?eKeUIQ?Y7O=fFtYBg@5|j3dQy`L`Bx&xREX8` zs2Z4?e%BV=98YT0|s!fkRV$4X5&`66~0suQ-TcpjzBLm=K}P~(u{gz zW?gz*m%sY5sg@B0R8}kQlWg4pq26IYW~GHTL=I)~UpjWAl(ljX%b0sMDnVy1#kdPF zg;?zC*2{6M5MO|haQ`+akT7xftZrO3NmzC@D8UymRS@Z1G zZYN4?HSeX3Z{PpU6$}6M;s;Lqm4KjZ{SngwxR-O3su}`$K?Z`rp{e6o5e=OjD5>Ry zYUI|T?LZ0#n85@$h`5!oQ9~?N?*(z^h4Jr$f-`dKRZWN#CvFS@1XNW(<@4*_ZUecX zbPg(m9NfVQN+r1;9KbxN>UP)664$}W!0PTLB*aOxi);pK;YPwuHs)%8LCJQo zQo|I;I9PVh?5bT(h;A^|Ry~810b>)=w%xt5eR}`M_l@==H`ivD(sbJ74yIC7TEW$s z2i_q@|I{yk{MU_nb^Q>Cg+!zhL^G|3tI^O&%5Y&# z&N;0Ns+{UsgHU-!Y`gr&PrvV}fA#r){1^Y_TfgcJpZxvL&UUvC@7);4Jx`r{{zw1z zFZ`4L{C%%^=k1e~>g>}yQq9)(ji9IpK3sJ+l1N|-sz4(UfC_uQZe%C@%4c@>AD`3< zH-f@icM%Y5utqEU+1=uRE2gyYz>u08Xs+kP8eYu@zF|anGYNs0k`pf?ujGxvgohOb zc+Twsoj+mC7H?hl-9#3|2Rx{7ebdfwQWrU7r#ghdP4>-g&B)0q#F$lErBFw%#XCqv zyR)roa_u{R^xja@wTs&uhYsYO{8Rt*7mvnU4(~sF@#5uud-ru|aqy-?GOmC96F)!q zt%w2KE7Xz1VcD{gMh;dcJV2344xAw~NDvcpvJ@m#Jai@Xq^|wqiqZ(zZ(?-A_q7E2 z3Mv_-nl@YC{Z)TsZEf|v@BNjx-1D|Q`}deQ5jC>~N8Yn%-Lfy5SqNh4BnXwHq^edA zf(W_0stG7m0YKL#4qR1|ld<(uCJ-@^sg`1Orjmw8enS#tW=rsym`$}{)jep+OB)E6 zhHMfhR04#miY$N|3xv39i7EX(l zs|Y!i+cjzzk=>-n1EXr!;YGknES-#5s+yLkK@NI(J>f|4e4f)Y7-&Tw}Y(%c{I;gCQ^1al_D zTDDR+wG(ISx9_>-?l>B+Ooj&!?LByK|Gs_elgY5EDkf%ODq)h#=n0_I98mFm7Qm}d z`T;;i)a^vX!a3y|?i zH!rD3T}mRHv*whUsTvIy)5UZ)gCGv#_SSr7XEvFP#^Z4eRns-I>D-+Zrs_<@fkO-A}rfP?^+Wb-doR zZ3t32drX~(LI|X!=**M~rRrKf`Eqh75HH+`8AWqMAc(`MRG5(zIUx+$6PvsQcYOD2 zzwIx4({~+v$?@waxBuI3{N6{t_|bE-Yx~zXZoTD}Nj<43#DS-jJ4E zRWg__X6>|bvFt z{AP~zYH2hL%-NkJ6983WhZ}Qg3J~c7NF;a#1&de^5L)vL=DK#*)Xp3;cT$D{c!3vb$I6&-W2CXPG zC5fn)RF!$hiNyPyY7mz_v4^sXyO9w3QL`WRnV5|k<8?Z62aeo|TaG&-9)AX(`vgAu ze(av5NEF0MzY7Hf#)jkmKmcH*SB zm++~N`=cjt>fvvb7pvnT6dR8j4T3;tar4q|EmvlOUVF@w;aC4TP zj3mM!R;j8B$yY}8BE{|NsW`ZUxeBo+V#@$bIM!92R9*8RjTgZ|vPv~|%pDU`T80mGs> zCrBS3h*E4`qPTT#c|km&IEE%q3FO{&@CCF5qn9F>l?Ey>ds0jWs3Nj?GX**%LyRCs zQV=6B%)xHzkN^<67BmMZvc|O~%kD%{f!x)Kyw(ehzye|IQq%3EVe{%&+;`#HmDA@> zf|P=L+c`VPG$}}l-BeAJ>GyG*}rAS5`VV>y%hE$82q^rK+*BaEFdZq3y%ZmB$wt_@*vg=* zs({8lP+S!dC=!nua5s2kyq_oETwi}=Hox2sS1Q}hI`C=)T_l)~R;swhHixUz0+HMr zYde#hP`^gTuaA5O({O1w(1MmY)T~P!iK`04n1UY1>|?t5ur)Kzff|x(gDzi8EWT%7 zXs+3{xzE*CCvh~PwzJL6G@WG4I-e?MMZVZL-o*E1A>-Bb1ZoYzmdUiMY30xQzmZH_Dhbw`nC7G>A(Hf z&(Y=aO^6AYyVfMC62M$6dKhf27n5`>6SqbDLjDG0TGaJ7;gDI&tmn!J2J z&CV=AhAV4FZolh3n^$Am_><2*aMLgT%wPV&AD>^%?Q^H;4kn|~ zzI}TR9z3w`;Kq0|5@87ikR>9Rc~4WDODO7VE3GQbtf~N5xI`m`7>KB_s6{iZTJ+@5 zq#^`R&bb#DyXTacNlTw0_wa*w2FjQ5nV%xMisRUN_wA;ogsxE=Uc+f1mf+n|Zr|`Op zrW&gds+hA*w`UwfUB_(NEV|;|3sKs6*EKl~Dq)UQF!#1;yDkxdg`0VvPdCS_!z#vB zq**j2$PA3WVn?9rIc2~=?C|aDn?e)PjhPn{8VNaX74|yNk_hyL;*p&1l{>Lm3}myX_?hkB?j~EzW)7 z{GWX>eR0#SWHbQ441*vJWhgA2wry_IGeH0m32JJpL@coqu882NHA`hgEb$}~hOt^9 z5<=zKiK-ClZr(_U+Rak4XwxF+Or8mu%yUX4B}JLs4W7zXvto%XNX$~^S44L1fsCCp z!GK)MR#q}dA*u`R4XcTI9Xl_{4sqAMjnR{P`RnEMk%0=xFeQ}eQE?|L0qlN5Y$)Y9 zh{L^uYLDeb*K9f>XwbAYwXRJ~_8dq$v5-D0l8)cS&6a zv8m;pl^j9>&dJm*R)I2U(!g9-qfxyQtE$zslbV_9To>kT&QoAUrrt6SR!hdLgS^W` zN-*EO0IP7@9@=-aZw)XW($1FeTqafko~=K#=LT1<=I2cBEX0_=fEdsyIDibU-peNm zBGAs!!r{4vYvJmN#S2?R%rUr%8!v;e$kYI)Sb0uH(PaP^7$Fl7+}NB|Rfyd^IRqtu zKJGSc;soPRbEKG31JmPs_Z%FLPG3F0Id6o9?A~M_2tz1kpDof@urjJrtK^}(H1%eN z^*v$VI+J>%gQ_|>mN*{g(cs!*la|v})~qmQ0*EPeno%k@%rlA%QPf@G1QL?0>HxF2 zu_+U=K)4h*ld}Z4^}+0YY!kWJlGQJJ2AJ5LpblndxDi|&>{8*taoqcrIC{HZei2W7 z4ksSRwbP(PaH$7Qk<38RJ4Ij;fmz9R1`FK0$-c6V^}V<}!#!`rd%g?*<5z8Nc=81r z1zgzHzxQAKQy(Uo;?gOYW=;f8N(6#JfnLN*%QH!@y6sO2 zOz7h)sO)d<889>LnvSvo3Pdv}2zU@e9VD762g)fkML^tCb8E=N(S7LJ&C|{m;_cmQ zbp#{#r8B-X7Pt}xHzSHpJwkWGGgDq+nG*|C(`T6${Q!uHY1C013k8{wCD67c3&7~E z;%WnHsU)bl5k+_|#{I&w3rjX7kh+5)JqleC{Q62f<{r;;Ga@td!m5HPL!~d14ophS zW-xH}qD|qt#D%M>CLwZnbt51MxpVnP!KAL}*#c%}H6@g^M>tH2*$d7Pb#)}BXdosM z7c+KOfoIC#1a@=vVCuf(?bLQFj)M?LNl+gd9~d24+q1Ust1rCai_gFKq@5n4TA>xD zu#4H0rY?zHV1{DiCN>b10CLtH-re> zZT0b$uy(pTb2eYms$lXZo6Hf4rp9~InsuN-7#|c!N($rw|aua{y%uQd9vTf}sz510w{ALWDRPbXVth9U1-kZ#v4`&AA88RfAz1^G!#O zzlvh?eF}Govp23d+!GydFliWY9S78 zPL|1#I;toRhL)O?G=>=D;5_a8^vC|yxy?&|`<;JTayW77;$#$Gd&{dIJNe|l|B?6o zNc~q{`}Mb112&_;Y%OHKJSHC8I9l`})n-0=SxoP)cK+M+z%3i20b4}s-~-|cqxC>@ zV4Lk?(z$7Ed^^Y2gzB||!$bl&dG4hd$k`IW%#lSZ7@-B7LGuypJes%8YTL07$wp{0 z*j*+x9-v5IwFlaZ?r2Dmc2e(UYsJO1wNAT*2V zzN7m$AG!RSzx=@?gCnsHfZcWX(eszi9XNbo)Zb6HM!B@l&)$lO3A%!Y2jlka}d z_y7JUe*cLVpZxx}{;fUxH>_wDJB@=_kLqUL?QHHa(O^)AnsZ7bQV**Td8sBPB2vw2 zUXqziGglFSX~E9>E{@{1(pGb#GQ=`5Noi=|f^NE-s`nj;#1c4XHPbR`GZ6q~^eKzN z=$REN!>y`^x|*!7AHL~$x7}D$Vf)BO|M1}9m%i)U|JL-^?ziVJ^3D6h)<)OH%;v^4 z%i3(oh`n8C)1V`?PVTCnQ%U{cY8+mCK|gbU-kD>(N|zV->}mhP6|6;i`_XXsUW_=k zGo0x>MsOf;FUD~KLX06sX1X!5F0tpbkrgEgOpTdu9PkSeZ0F%ViaO_S0N{oE@vtIB?NPCW^)M~2eOzg7PAF`VjV(c z7IaOvE*GLegi|ur%t8_ZfM(HlO;R<$ISQqmyA-Qf)s?DlZSGbv#yW&b+9si-Bb8op z2f-vz+hk{&tc|Z+x#Z-N)lrC&a?|Ce$jVach?%J8zfIN20tcp$@g?mlF-WysNOxic zCI*>Esr@8JWan&+dbj4IH|%@!x4-K<-u3n0c;MjPGf$lRv48jTAO8HucWi!i-@)4s z+*HRvP?FTP>gJQd$TLz(RTYO-*uA!ub#`og(`|?DIC9{o%_~=*x$^jDuYdL_d!n(q z!ihOhwS3S(pjqDa5+H&QWE5hZb9TQWzIC{1Zrs&0i-;9F9R~@c5GS#!)rb(r!wQ7? zbjLKQDGM_>N04=vl$q5Mki2OBL8{tk43wIR5_nx`jim~nC=f*g97;&&8PpQJNiIbs>hheq0mQSC}Gp>fCV5F*Ut_sg;VBsi=7BGiW z#l(~o#EN4|hzA}44k!v4JS&LE4Z4kd&aaIyx{K~O zgsU}9zld((s?c_M8w(=)^M3FU?XPj*Algk(LI@y+7!=5c5KwwPyB0QgUzF&a ze$f&^28c;wi7p^vEs?8z_L6|bB>)lC8mbA5Pz6|oMlXi49{RHc3mmc_Il);q)h$Zq z0)@I&J9_BQ`s&)}o_?~+E<%C1zwMT86%Y}NRD*7}^`;@2ghPA72)?5Osn+(bUR$(h zu5Dg!W=bA}ouEe9`@4x5;_Q|Iv}(@1zA>9IQGxSFN?AG?Ld7e4C{#YZ?DNct#rptR zAu}gtW+~~UB}JgbVuJ}Jl-U^&@wh>IkHK5NbOz4Y*yG(CANxI=d>Hd9oLgpwL?<^F zcPF7f_m4o8Ai+(jBDhh8hk<aV;H*SG2QM^SyX|K$7i7k>ra6c;XG_d11! zB{>&|34^WY8HtGuoJiF@qo<3@BS~)AEfaB{G*m`9GZI-w&v_s0j502{5DcaSf(>e} z!w{S7h@dzcuGOQBrfJ}FQ&sKU)ja218X#0SIE-OIJgci`m2NbU3fwKLIKRxaZiI?C zx_9)Yq+X(>>j6C}@tdlZN-&X)-VPse5rnTHgUcZl;RPEfCelWLbqNGHX#Pcrj~oB{4X|`d&;$ z??UNmdWXXm){p0~p7eDq3vh;#8ps0nJ9t6itzO2E>b{#J6n2VSTb0n8+EhqsuvZ@`(o*Jb&25T<0Yl1PPf+`3k3|)5K=S%^f4dvKa79%EP z2ODAlfMjk!5UR#*wUa>1+Bw3IssVECT|3Qb4b7ZMd0u5jpWDfJ3z~YtwW0IVen3zLfFXN~{2IB*x$-ce+ z_Io)ym3h*X6~|?t8xZFZ`W<@dM+-!_AYI{@{Zjy40N76OOrN z%0}!Q#Le1S;|u~zsp{|$>J8QW{)gUoee3d%y!(fTlkrmzpW0Kcz2^2;K6v86|MZW3 z?O&|@^*i5uX!mLgk>a{A1LP#sFA-R}1hRWYqpu#!|E$@1dUO9v_oU9@Bohw%84P?{Au5P3Oi?gHgjGTTBGf$b-Sd5 zG_|$;90u6g)T^7x$#}@~S=Y^J-gZ)nCWCoS8bd`UP@i{sSn;)M*DrNv{>Bg7GdLjI z=dX<>17iN=pZegU#oA=`xo6KDKeYeIp}prW+MRda_T-f(PUWYFqQe-WqOqxUKF{bX z483^ZkR24MVqzvq+5w1EIZRChM{*=@Gdfo(=oi51nGu|PxsgMP0?Ko#!U9aSd&?WY z@v+Z+{(&bx^}3^Pxb4^-o0n(D?pV+BJe|(h4v#hIl^3rxO|$pNIvnl18;+`KSe4{P z0su1e+$LfVRY?h^Y806$r%a3>!Ohha+&7H%xTHh4l#VUK#JxXd5>w6!M+iYZt7-|k zE!M1}i;-f-EgL_x8%&qzr_*3KSlhez;F06)BEjQ1#E<;W?;SaI*USIHJGbBWNt|y6 zqnp~RPjqNG6OS}+Z&ej^*4VB>3Gmz^w*aFWQ6HiM z<_)aGoI6};odZcA%Mf*mNEspaC47NVCPQ0h^_%u1xT^zruBzBIUG|diNI9!5`v!Be)U_NWung*2Rm&YEA*hk&@~``B(TZ?tHEHI+?IOkK zBAiv5McXtS>tJT3qb`y(%D_O8t$6rvDgv1n75II<=uMmB49=9AUY>c-0M_H5BK zS#t@$NL>aDfygN*E!FR)s%j)OoldV@yS#7zUXDC#rh|H%ax$2g$D{WOm%~`!wMxtM zM|XEOroN(#IS_H*d`4hmCQhWSHV3i#O|SggZ-38Uc>PzsX);+k^|>=Y_6tArkq17x z7*(R3rqq~uOhO_KZ<{oU^?cS$cdo6=>RWDo{bAp`+cwYdp82hZe*LlZ z_@-UzyaBODWMs3>ADIDF;k*lQ2oBC&nuxiiwH-86sh!KZIJaoiV!RD=3{ZyKLH zml_v_fkaHrnpPT-1O>r_6f7z!r$;%XE&?Oy*>0Gq|rseEXpq81gMGC zl9+izg&bwe6zdEbcFtxyh|j|JtvrmjqJ?El$JpM>!>TpW3L+znC%C)?w?WtU?8Y1L z>=STIg-7a4VIT#SV4r0svmTg03H9785tF5C!S*U3fSps3+=)O;aNbl*2^_!+h7q_2 zWwe0nn@*t4NK_%&?9WK1Z8A0@mGyqFaM-D5(NQaMdOV*$_;8=O5l#j+@(fXJqVyRE z&S3L84u@XB?amC7DbUB^0|*d_ZL+<+`PupG?6jFC;?g;lI;9+5jTwzaaKtI23Gy7K znek0x0Gy~ZHUcHJB>p9bZvU27f6;?yAAa}4ADY=-puF&<%vnONBid zzDF>NbGrT({`Rla(IWon1E^~}w~ePS;n`0jZNZliqmauJp&6cPfcFrADnf}EVG*i; z5W!M1rhQEnOsuMs2X7NH1?6nKBLej5pqmYMs+2Nk0l;Fvzf=yw`O@6lpufV1^Z8a? zO@JyJ%9z+dX5!eZnOG`9sTP~2Ca9Ukwx!?&shdE%vxPf_4cSSNRZ`??l&evW{jpT9 zj;wiQo-*SZop4M5+rIwNsc^8)P{ST>*j+I?vlSUq_khTm@2twPT@Ci+k&;b^q{l1@`&&Yg6U0&AAO4D_et;HECHFg}}AZ7+N5IY~tnUZ7n?2{@x@?bSFy85?ttx04o zFhHI^{s>GiCy>D`NNR%ots`+DBB)7D+0M0j`RK-f@g3js3cD1y{g@;1Ph!=~6SFYc(5(bwq&px;J3`^ofN3eJY-(;ZA z*wg1^*PJ7lYr!pNY7LpxWg++~Rqwxi=UuM26!#i4mqJ5nQ25K3+upg$&74p=O@&`Q zwEP0+`sZdR=j}Q2Ei_}9gq%X7);p%Pse=nB0wHEqv-{pV2NELJ0dk=*fiD0eW|Ii# zx^dnFC;Mr775(jVj7$H^@=ZFa^sw%!@B0t=j>cX&G3qc!6u+|+o;6^L)%0->*@Zu`^%QD+R znsqg3Fw3V51KO~6)EilB%q(N*5Ij3JI5Q&86dVk`UsPK=hmV$D`4tEsWNT!RmUU*9&E7#e}y${QeKV^7h-lky~%M;gP3KuB!&6+ijAo z9X zD^mlva0Sg9s~RHb2R%2QwXH~5dInFXwHSsAJ+@%AmOXMMNj=+a&%WptgIE32BdHN} z)?ZjSbKj}Id*8=44jv_?t8wEBUzCNBIc5&tkV#|CmpR3drBs(%356?q z!IR5kV!lG6BdB+&59e|VUGBJ121ydSs!8oHSlKZAVAlqy|v9f-Y^+{hv#hFJtu}U#i^)pG=SM+To#l!Ma~7qAI3yI0ktJAx85K#;h4K zoQPrMxsHaePlJ#P4yjAi6M0}n88jRSI7?LuPvDPU`)M{S& z(mSH*e0*i|awuGXv`|%b(ylipvv3HU`N-WB%G6BRarQ2X2(iz%GbU!2ji`={ok?p| zY~vBEf77eK@>}2eju*Y@RUZESk39PBKY!m{pSow>#A8P`jt)kJgVZ&vv1f9q=1rTd z>`^cHwA=1%UG7W&8*X^x>u-JK_SU8M-1YaLiuXMwPexO~i(@lqNTM-Ii_uyI3R+wo z9XPypy>o7NzFCd8n)zNE=c=u$0?E4NaSn5JeN+IsFzEM}nfjR%!p;->vg|i?9ZDt- zUj#4+DK#}Z)17ueRE+?c3Q(r8cBj3J2@ce(Ms)@Qolrn-T-|8Ho8td^zv+UpOD=0SYxY=sv)4*B; zPRTs^h_-}3!AFmWBb#aG(dyJ0yR=PhFALaQwi+tJaU&=KP7% z=Zb}5t>1t0^r_ux!>*uS#IQiGcj;t(W>4IpvojzX-~gc_5JB76 zm8LoeVnVd;KH$NMHiE#=tljOmCvyk^rZKjeh70cYMcE+)vkdVD0cu2!44UIWaKZOq zbi;||J}o^o+O^cw7gHLGHGt(99kDZ$45S7!1egh|mO!nkI- zMg=>ANnYdSUP845E!mqk$9(wLFMa9jZoKK#rQQGXnY%x>}Dj?Em$f-!k&y zzuox{Ps|$U3xx`@->Lfqy!WOSHFW_VD7)OOWNdK6C3zxhrJY;DMEPfdh!vDf9axa8 z`_%I1Wnw9lKNXn*rUct*H}C%7r=Ht-szT+=B@^u1T!@%Z5FzD;Lk0(^HDifW-600p zf3AM=Pd58E_79z|FOhg6Uf16D4&L&8H@y9#?f$~Ezy0p!Zla(jPKbnzpqy zY7Z`uldkTCJK7f!LDblhbJ?*=L>3jvz!7Z%1tP$dJey<;cmAn%PyhvbL(HaV5(Wzh zLy0Y7B=(3(K9iO*bj|>U^H3lu$f@_jeQ^tqpFJN>J!^wOaqxs2j@0|^%@`n95|c!n z0Y3YES!@)%Y19;r3Q_o?$rxNj-36_KU9+)w6*CKR1>rb1z>6^o16hNNDCJ%3WXk#Y105o4rWa7#10%Z zDLGFZbZh&ozvacRdg0Rfk36k=vDb6QZ@cEMCm#BrfBoA#sXDN5tZkwuSzKBQp_uGU zwzto06bHWb>%aBr`k~+av0r`F7r)|L-u5kj{qawn*{Ocy8-MuvW9tum?!LS3`Q+pE zBQwlQSiiTDXCA*c}%Lo3j=OLLl zut9h~*`>*8HCbGH>7~=Vuef=2 z_0aO(mDylzSPuPkdp6&xLU5zyQK~gHacO;|V$C>mpipv(xnK$G+0>kK-a95rDTxYz z5S)mb8fOk9jD1J_W!?wTlW`V3_IH^~2A`#`yNby~7LQE!LGfhazNnDwIrtq?B)1&QnT2 zE{jylFm>;{1PD7aF)|B*eBjGddUUtcwcC~to+t}Xgh8(y_6KWgYa2&47FQNRQ7{oP zsfY`qyJzQ{t14$^3E}GV*VIIn9pxw#5qElQ20Q@dIG1&2GP5Mjjh`y&oXZ*4JSRxf zT)v%`zuvpprj*1vXQpi%j_dyDJB@4_olXAEn_O0q7V~1 zQ&D0{DSt$&DYcchMeOx@YDS=5uh&r9w#g!@NejYYp)YM}XDKg7h)G1-X=KMPaGWQ0 z?1GDJZ0FHA2d3Gi$@=becUJaGGpJ}NoF=Je^}L#S4mmbd&r`m^##Ypnh}yOl(b;rf zU70Pej@aqEne6Utst6NzsbDkJ>}c30P43&ai9B`1!w5c@p|kvvc57^t8ne1hH{;kp z{j#@x!#ltE1#fz3K)CPkANb#Y@SeNxy-$-JIe6%R>kk*p(s@=yqBxJKX=q4AD9ost zv~7LmfUbVw@z=lMrq|lE{*Cv&`>)%-z0_U?LN=jCt3}%!^)zbL5~IH|JhHTSpg$P3 zF>UT$+8JLlv}y^6s?o^MabRIk>KwCBgX5ws7kh(6q7d5z6wJQp^_nI%^_-xy>AY!X z#40hG%rn^m1me;ZhGe;_jXVe{kyODfO$CD?=Dwes z|DWIN6Gn}m|7S8IgI>Lf?oY8T%m|_L#gSK&ykf}hn#2JVntH;%n8lf<+)l-?5AQCVo?aTaLXVb@yF(+ZSL9?t z${>dKMn=R)37fmP3_GGY(8J;?F7G1vuH|E}h|xi`yQn8<+fKbmV&u8#TOvYoo-G;J z7-lJgn0y}3JS296B3~E=CO!B*dVM5?CsYouK=kM)RRdJanZ(kSYM4cN{KENu>1Qf! zwxO~)?}@z$h@2#8*@7X#l3Ej!vExA1G!A+`&BZS6P>NVx?j2f+>AX4%!Bb;puV~v; zH&PO{%&lq?&Gz-&t7)c=oT`cDSF1A=%xNOO)96xfw_Sw|^2*_cjDG;bK4w>oPkJRVKG@E-MHo zCX}VFyt+5zZsnP47Dy~zS1i8f+Uu4rmdlG@dic8gCR-O&L8P!?_M*dUufFZZe|+lE zC!c&ersUX?)KD)_kHS;WaTh88NZA}%O!G^Y$dw#=R5GzC2OwFuVeg3cW=fjVWxOv4 zqhmCyp<6#Bh;ukuo&1G6f4Q|;joOhjQi8$AbMUStbqXb?FqeNee5OMqmo~-A>GI!< z?;cDGGbD;;=~kTh^5rk?A3uJgT7L0`8~(VyM*t^$m=9iC9GS$uXVQf+CgiO9E6u3X zeZ(Xov#D&dB{hLiv_`6mN@u%qe4tm9!&M3c<2@=CEG!X4roz$|OkoA70&J;9FgP*+ zIH2gEZon`Y72ceIf#8S=sAW(SWjmP*#vY;|AOs?3&cTQVL$J5m4iw}|%MC|n0GZ3Y zb=Rdm4InbnWHF8UiP|)qqaLTTn}$GT4@BsdU(WAYrv#(aSlbfA zg3s{7uI4Gb@4bTwQ6$%c_9+7kKt#+wxPD(0s?PTY&0eIX#kah9qpWD>ksVI)z;#FW zs_I>T@%xXRJGruWG^wy@C_~_)na=jMx8HonSN`PB{KyU0Ui)jm{9C{9hrj+k)!TpS zhkxt~U-ddFzKHwDxc{?0$R>mNUU@3FxR&iS&m!v|L+#zQw8 zoW<(>551Q_xoLNSR{L(DmPuwTc`lPm;8HY+Y2aWcju=3+mcXvV<)QO$b|qdcmdmO6 z>YXePciLU+s55kB(g0@>v^=+U;bn&xuRn3j5=>oD_NwV5wuy|FH$4t^D_MAKA2*i#gX-ZL{L{x-gAAHg>mXGo6rrGB#)-~)vRh=>Xlhl+qTWO z$y{J#X3W$DaRKgPCtaRB-$TfgB?G|+2f#|dur}OiHrjce=E>cN#~(lYd%yVW-}!I< z`RYIUrqjRnn68}*!_drQwHp@>)*8`H%>-g>OwT^2k3MC^h!VnkAC3=g+BM7J_fFM4GzsBlnc2l*W4#AAFXAz4tx@_KxR`sFK-m zVVFdAuI#k))(6jly=OI~C`4%5Rz=%3rB+;E=a?Nl`;<~sH+5Z;k%)!TyV4n1Jx^6T zafM@-bJVIL#2`UaHHzd5PXRmUcg5PGD48&;W^^^yOH8C>SvgcSb(~!%>Nqe%p(f(; zZcahWj@c8`(#-aPgx3vk|Bi3?=C}OQuQ~ihH+Tt;e&~_k{DVKe^HZN{RF~J+dZD*G z9BL&RwW``)2>oGiVK`{UP2@PM=GA1f$ct~d0pCe0Z+ST4kBFjeX356_Quox`6f^vdPIXt`;k zY79lc?2oeQ4y4q!geY;QaSk@k?uC5kBL|3DqVDV_m=Q@wpHiWm|3c^7+xKAPU%H=R zN0(5wee2!TK-Kea{Q1AG&a3qNeG~v0U42nMKeZA%X_xYkdIxyT`Yad_Vk0)Q7G!V` zW-`a>mdllK+H0iU@JDNlkEDCf;w(d>%^a|Ui|6^`Q_rpzsIGtcVLdmS?QU-z8m%r4 z_o_)%^6FB#ygYED5K13b2QX}&YpTSHqf$()0mxh#SQNsk&3W^p2xT%{X~*Z<$xam? z-brS)IqnZv4h*n4otxI6rjrV6Uk}V*NbiWf#RLGJi3FM~7n7*L_fR-253o*lsfXc` z=>)AJMJju+gxF#-!$i;n4md0<;))0PEMOuG&|gGRpqT+iXvjN@L|{`TDqIMjyl6C5 zXf*EbF&w;^n7Zssp`vfX2o63V6fnRPy#dAA>TYdHnjORvf@c@nTA19a>DX7Irj|J% zMy4=ua4s-gmT{dcoYNGIxKT~!!GSzdOLG27XlK?R_K&X=<%J>nDLB!#Ek6QNZF6)N`D; z!`}8KSYF2YOZem^&>Y)m?7#miswws^QK1GQGg7gnAnPzL&`kS>N!}w7IA?~Teckoy$V%DTd-deNzVz081CVnd0AQx39@fwQ$}GRMSxo>ioSIN)IJ8Wz z6cu6$1U8LG%l-c5ZuLL!|HP%~{6$A^ym7d4X?!J`I`EFAM^B!7!N&RumjSV7dbI5I zIS?qCRYJQdO;c`g^GPyDFt1tFvCE-8CQky7;2;UnImh6XKvU*(J58s$|Rra@qb&Z~#n6$>6lnszL3XBQpq{p~*k& z-P?b*KU^p$UIL1!sV~JHquamr$XA)vAH49{4@^ICE}apdl#Gp?28Ad)z(E}h@E{kv zoj(DIt9Ja*nR`y}o}1}h=a=CUM4>(OR*@1gw|4HhU-lOy#U||{PAs)33jk)01|wK) zO$&A)pq;}2^ei=yNYapVa0E?2_B4panu0(q!xb&gFxi7ADo19uwsQ*Jj1d*yBjrLJ zqQE&jYM9s6Hu(ZUEX|0RlpsAq0dK?(Z2|*Pjk+XP_v$p!q~r)0TP&vRo2HR^ju5!? zs*SaCOHmDGv7=1Ebx(`z87aKArbI0S(h!O4Y@h%5lcp@YbGAUP2N95=03!Cew*~<@ zf@4c$QQ(s6Erk9eEQyFKdQ1h(v3E!y3TgMs8(($k<+mQ%d-!~HVO$Q~`tgIm_LuMZ zyHDOZ?2Xt#+FC)qVlbVJ)9&;~-}(JN^6!7>vClsJE#LNCcRlclZQ1$Ar$6zIbKmlc zm%eiFw;%oMd;j8N5C7HozvI%i_15#xyl z(nHIh7O20$S9a563g35`3)+ZAvgFA3*p!lDXFJ04aIpxUQ>(M8b%6%G&`#Sk=XbUy z|iaCG0cb)Nlf~pm*2+VQxBg#aD4URsSESTY_vAY zlTg#Ne&Bs@^Sv6RyPwS9xhhG^olMYiXv1`5&GPcd+f1z@{IKl7w0PX z!TYNn@4a7GTsUxaV|jI@SC-7|z3Z~_M7gHTIdX;9M%vhh5S-(b z(tg9OFq5ivkPjvUi3l;9DH{<{N{NV(Csk8W9=V;FrkFs;Z^q0@+BTY|RVe&yHiLqg z)Fd?^%EeKl3g;cE#WtxKAnaXR)v7vJ7&h~&siO}Jq9l@KVU;{1Cjcqt<|3%ZyrpW} zPS8t9%#fO2FkD+(-Q~UAt+DeylpcVHIY+5YDTySl>qch6 zOrZ>U$KZmiXSEB?46|u;feA(o4z8`E!hGRj)qyZ`FJhaNYFTW-C5K5rVETZAQq(#J}rQc5YX8w>|w`2=$GI61#i6d;EmJs zlizv&d+u!RI^SMk1Y?PqiFF-U3QQ+?CVQc481PWxGU5ErXLp z(dYY4KkrvQbVI*f4q-H#RbW3DE&`?Zg`{e}x7SKtcwbE?Mzx`}l-N0dRa#;;%}uJD zAx}ikOjMgrzwH{9^1Bjy{(V0G{;hK-?_Y;I<1X3r#~^+FNBe($==i*|GPB;Ovm)C5 zT{DXuAnV4|9HY$-B$I52v+n2-CITZ$tEpI9I)3fK;b*Tz2%z+YK6M_?DWs1@g*GC8Tnv|(I%w?O=bcXa*Q}dwP(B2v^k(*Nk@;^le_Q<25S?z03~dXalXOr zB?6<@LnI3hg+~%p6X+Q*g9;iPKt0jalJjKHRt(XFlEJPllO{2B-XtZnY*L~9^{clC zga8MM4V*V+ga9pUmO#1bQ}(fQY>A`kuph`E6-8z<$*T}1f;teJvH(3F0dETB>@SY1NO-y;0m&ta_OinekfqfB5 zArb{q>By-iNiC>#)Tl<%wlNtK9rV4D`YKa}G7L=Yj0~m`=ERa}qGF9!Pf*d<>8`bN zR28Vje2O%M)fr9(M}RXCu#tnQK!r*VQ^W`oV^WDA4`Z;W+h0%X2W)$++YJr{ER1Zr zM{$ox?3q*W9$Y{rJDot92TRH{U>HovR8z*auu0O?uydA#^3SN|oT?FXx0wRP)LO1w z(Qb8Qs{7yQ?CjTI;imFMuQ~BrAL65@??1KkG%y!YvaJ(q#lkb(Kwu2w45~JOuU2ey zCJLyTNmPrREgHfgH}HePrS6082Fa`I1|{-?{z0~?s?Wfzv#CFyTDy8kz-K5E?H@Gz z<_}OeLu*%cr|I+GibJ1^k+Mf;Fr!XqAQ*(e0&(OVoXfF?E;b3z&Iy&h-lh5c-s$Ao z*<_=dUNc;}f4Z{=b}Ihp1UFCVRDAkuwx*^D%|5E4wR6;k%OfH2qH zz`5KKf!t%Eq(UjX;w*oav!YC0pHc4gQIHrBDRX!>ZT)QZ7r*=TKi=#QU!ooM3~L#@ z!lPs1z|ul_-O`bx=NJF`+4o%5-NJh(JtQwI6r4DiXDH`g1`z=a&5A=ktDc)T=RvSS z2nMu%b-i3WQlFm0>JqsSXt;ni4sMD;6*m*MkXmp=GPof?a2^D*7O91?-?#yby?E+j z+dO5Kz?uWXR0NYm5|J7zJd_b@NCODDVA*o$y{Um2MFDn@8X1cMCQ^7dO|Y3+3)Dbs zAo8AEw4`WZjlySLnfJ39VnBzm$v-S63E4|j9o+A#gzw}qsPPHTgv%qnVw9QYHSjM znS(H!AtmL4MXXh0=4P*6UhLm=!|=?x-lYqZt@#zf{N~$-U-{;vFL-Nt{(bhp|M%T@ zU-`Rt{q_&~1)6PdFRm`Y(;xniKR^52l@o_=MzW$VhQqa*wXE@)t| z9`%=Kow;b!EFwC1$Bu+y4iHb?kxNEI5U4Z0s)`k^R1-xq2!ZzTp13N-QMcsF6oLH) zJz_wK9YKkN$w_K%zwX5^e(~+6o;g4C3(W596X%N_FKsOK2d=3akoEednKgAg9QB-Y zQCm|jC?FFc48#Nj6M5(M(^iK4$YrN}81lrSmeGJY3Ema)<&RlST?PwThgjJkT#cdm zFA-5@bUlroqX^lwl2OB;9MxnOTsbIK4lT9uaEcKTI_o{~)Wg5_v%m43KlR-={P2JL z+%Nr5uX*;sa@p)P=8<}CJmZI-NSjj{9UVM$UO)bLz1Vkm9PST&Q&$32=jke`fE~H+ z%WTfEMg?EJF_Y%ci73~Tnt`B1)a$V?{F!O-*k(a1*B&`~ya)po4Z#(Kch2<(gVl`# zt7|I@OQX;$L-54pTn7B+@pu`@GO^})qf6xxmA#9{{1)W#H*K;(&;i=LlN z>dDT$KP;A(7C=1S8_y)!dc2|tV{K0VS==u#M_qLj?XD&QZr7B}cnH&dBQBqQ7PuyKQX@5t%e=o~JUD+F~ z^#@CJ9gF^=FM8}lJ8$N*rm6Ruree>cN=}$G#R$Mm(Mj~$DXSfGg!c8)thm~~P4EBl z_dYL;(*AGu|Gn*NApiGV+r3d{|K?>g0lpJ^$?YRm^8aVQU&_r>$o&)mOkmN7V2(Lt zE&vgOOrXRNBS0LPnkY+3v+?)}$7TqB)}9;VvXL=LA|s)sdT6haIJWs% zr!`l#YsC|oh!V`AH5Yf!RcTcb!7wIBryPS^7AlPhA}%;C``R>;Cde5ZpLtizy}X zHJ)4xG%9n1fn%TNAr)ii&9h`4vZq{qXugl(29+h%Q){Ovdhi8O02g2;&lcIaGPuB| z9GTfCgQ*yc2dm}wUM9**|s_x;9ww z?Ziff-;Q-r@?5l0)FMqxnF$==a(R_wpHf;{+_>r5+s>YU=Jb_|Nd*i-O^BvR&@zj2 z5|gy#QTh;tBNMA50<5c^R5tUpbj)vDOA9BYzbd=uFntis9;yZeh@!J(cIf^6pA8alGkGc<=k{*Z&y3KA!pv+AUauO9)Iknr{NvO|AK7 zBG0SD-CUThiv%Mkl{Pg-=z2n){{glA__%?IuV#YOC?lHCStJa=$Su6=&`S;!>z_D% z=gD-^#0*BPj^e^dmPU&s_=bqgbtlw551jTFQTr#r=k2q|iKLz@UU~g>2SzCGda5QP z@YN+3fecI>mWFGl<12ezs;U!xJ7)*mz7Fd5ztH=V?*2R8KQ8mqg2921!EOMMqfcpH zV=#zXc8)2m^B5|Wv$vR?BQujES~vx)7Fp`|H@rVhao~#;ADBc;OE@*F8>z>$7a!bs z(UB7`K7LG0-~Zr!d-K_szvPv#K78XxdXL?SnAABjHZWP*CxVEoBPU3eTA&a$e^8Xv zJTnZUYGeVvUyKM`wbP_Eb4M0-a0G~%nHUKeQIhV19AL(|RnR1AOsY{;VGNg4GnB;) zra4^A9&AcrC=>=IGByist6LB1&ZEt&qUg(}D=CQmFp`44Zo=A~c!hL`NFz4#B$ ze&B*#@oBgstHqpWsYd#5rk8tYC&jm=G6Tjb+O) zBOgqXiDo&^k{F}&ABaGS$Sm!d)a1R1=xh#6uxJ1=8(iLkM*2`IrL$=uqO zR2?JDtzjCB%#{#^8=w}bFZ+wB87G-^IlycJElP5Q5otY(jYtT@Z0v(44rOXvIMmzK zfy1Mhy?B|_`5<@r~dA{onf3qYn%Rizd)0&T+5kZSI~qzH;z;zWbkk;veq% z;UE36^Yw1Ox0qa8lHZM&?|=A_w|wF8gUjn@_r@!0>s!0kZ{7WeKl9c9=D^~{&wta; z{m?J{z_ubw#j;QG=vk`PtVYKvxlhP*nJN5A#IzB$=Ejic`cfOG~^V2rAnMblOFA(~$@7}qEtyjqE&1VsKX`)AoR9OlIHjl> z`cOeL7U~%>8EZAKCX+UVVogvtlSzB|wihqG@t>YJ{)Xbx-T1|S@tODD`@qTB)BpM_ zzT~#A+8AHlY^_~dJNV?Mp8CDtc<+Jr6R|cVSzcSJsv2sm2Uh<0{l8hG3MgS1@xdM~ zv?*3v0p=)}g1}MRf`geR6-O*4YUaqPX+m`5nYh)av0AauQHNy*keTI{seB~n)ng6> zW~ZnbjNsrD$&A1LE57;S`78H*_JOZ@%a=28TgTyWiPv|U z2eQf)5`aoq0GMKAW={-fsw%BUB=21)!+3W(TpBDajwX9EiB=Sz8BNpX<#ucm0QN*c zYz1T?IA&C{Mhorr3+H$~YodrFWZVZpngm24c$Xu}u#^O#l*G)W&AbvyFu%pyU zSH_#=Ft(lT@$S~7H!RDdkXFpJty4z&dFNCiQ3j)4D0pXkZ$7VhPUK)_v4Jlf7!p$w z$p%q!a7?pF#m*HyM~tQsZQHUJcDB=%i$>vh*l|p;a0F9TX3oPHXYV}`dqRGF z?tfp@RE<)tQxmy)aKrb0%RArx&Tl^YisLSXv!8tKkAClcpS|}{AS|yQZevW8T8(Yn zcn&&eR;;Wq%1jwHn~Zlh_tyJs-}q%;`O=$S_|yYW{>I`ymYbQ4qt%KC zGqVIVKygjD`I-YaN^9G*&8KHiMzrLdE4(S#v8qZ^b_96SR+7TZF(eNNzY}Pes;iHAYyH z%$m|j>`0l(;7QF=(@LrZGe$xOwzFKnN5le0?3kr$E}zp~7%8N(nIRIfanq8pc_jm4 z#l6S&PQH5K`fHBfJUuz@RY z#9FaLlt`fo4s&Y8G8=0pNLDyA)i#0+P>XW;;+ZRaPPKvKuE9aA8{zZ4O_HT(g@Y@= zJ>p=^-13(w!?S~;p5Xj5=DhW9=EJ?gl_*L~&e<#(h+K(OOPsV4#RUT-CdZT&$__!IoV_%l5jL(5U;J`xUQ8dk z+nN>(6pQHX+1wjKf7C0~vqqArh$%HB^&2t}Mr6{~r&)j}%QZdSIvL&uI_X~8?^LD0uIrkph{ zhJuZ<|DTNw$)oTbL|X`+z4X*0xPK?@0TkHhn~bVzTlwS-IrYbu4G{b12D&T~@_4Bx zthsUwY6(PYGK3x;3_~Y~(*EW<{}Px$YO;uqmjog*2*ClQSqcMSpEt7Zdo=dvRYOM_ zx0us9Al@%WKyW{w1GRV4JU1yNfEQID`j|^lUZhJmkI<)##$F4v8jDOXM zW1qfq83ty@gg()=t1Cw~)@qT<^JWurZhP;qFPwjTvb6*H!E!wiF(_(ts9byVb#J(| zb@`snN2|`505btQ5Q)JtgGem`tR1=&393X3iyLK8ZeBS#tLOMUIJ=N3l0q{h5->AI zM$S>ARx`-_OnuN+iVjBv7%?is2o*IG85Qf*jrTZ=F_LiDkFgiK=2?(D0`S$x^Qam zfyWn)Z2Ja$meJ!+G!Za-ozWCrS)DUkrmCFc$p0?0cffCH#NuSBe&ZTI9e zq9T9;ASNxWg%hxYnVC09q`6Ft0S8Z@EE{rnEm+ACR83pJ!FeDTmleoo zR0u?{q~smoz`0b3G$2C6Aer#w_dU<^DfPTJYG-od*wHV0^-Df=-#rgM^CbGgNZ`D= z0+cViYAITF^s`rMj0+D_nDb=S-m7mr@WLBcwm<$zvw8XWt8YHNdGT*Q{h^uG>*adV z#Eye^MM0@#-1D zoSKYfafM?f1TGdsY!nS36jN$VNzD_9q~J7S^3?g=nATqMhT%87=Ef7R2v6Np|NIYq z{BQ1j_|l{X=#GQee(!&I9a)-9C+pW8R@MLfZ-32FSrh|l6AL@$CRQ)F<;C|r@yTbV z4|?>)bVMryUIQpf0g1^sQoZ!LH^1P9TYmX}{?Y~?+c>l|oyXzQaB*!E3T|ubFZG5C z{kpDGE2CaXjJAp7$$M`Q_72dtj-rxX!MNxhgYsP*`$(Gl|@9x!THknm-;J*S7I%y21y%y z{PE|W`-T7CFa79${Lxqa?62PSv){h>BsGQq+{0~H?C&*v_XD%d3MUS_wLYV1n(XJy z<_5}cH6nCX=g#G{`hK?7lN!X#`Ao0}v%!oU75(B$;~qKdrp5Y!YhEx~S1T`~6-BfpdFZ=b6qrUiUCiv$l=SxuPfl>jn(xK!ha3EF#Xk6eUlO zD&YM%P41Am`k>AtxvBc#B_;#dgV{CGs#q0cQHK6-FrCcHqUiO@wvMW%ro@z@Wa6f( zrI^KZGqc#LFI?Ft6Pt{y-k@Aq8njKSrj_ODhAiW%rkDg*30nk5h{(xMfMh>Bt13j~ zgC}yN65A+I9m6{=ilVOLmCL)5Bn0jc`expjLB*b7c{(c+*#@>@@Bwy6n)lcXUykycdLIRcrf zb3SLevNPW@zFX8eGBsG7>l7+CF5dW#w}0z5ecLx)_o|zVez@@2^Y8gTfAQJ-9%1<9 zg^i-$Ll0@%#!9YS-1S1kQMtan+RW+zn(a)z;icEU@D1PenuXrtgAY9VFMsJLKRvt0 z#ifBOqt}U^t1z}M_?^obde`-DdExO_%x2T4cAmIcpCfaj2;TQ3Z*}tn$7FvoB1uIg zbySV+GS>B8dbb#g1z(QZRzuMDW&8?LB4eTK+q&D8HKXf8!lFRbvxTr%m%}S{^B7lF4huLYzgcJ zg*3Bv=R({*EtAX8DTIOP7!?3d!I+5P(aTj*o}2*;C4*YCC0EWjSHj@7URmfojW*Vn z4{uz${7eBi=np6`d3DzfQM$8F&M(Z9TSqEY7*#C|iv%Y`b!rsmCx zqFI8=z&ijbb0Xj!2v7kOo)HBE^3DKb&xO~{oX(yl=!4l@Xv~|`tSM9_RI#lBP zL2Pa!COAdE5A6~WSa5W7$%YFs1xf@DI24N*tzl^e<87N%q=}$#o?L0@K`OCYnmO1J zF}N_H&X3)-5-JV)Mm?N3I{2o8*A(kd9vW1Cbq_Ff8^>*zwc0|P*gL2;^O_}j4}qFQ z2WpHWX+W3TbpM+e(FhdVG@`M@zq1u5rIfKTX?~q zDNtxLO3)Qt3^goJanROpZblpF*~jGJzsKGdEv_OIXoCp=m+eV8JquW75|RVhfMj5U zM;Ksm2uH3%Eb+?M**Crh&u(J03L<>wPTYSt=G$=639|r5O%s7~1Qrkzp^WCvm(1*K zA~3n`!3+ag9^HuGNrhF-Omm7ekEYz6jYe$b$vHD6Ut0tuP;a4JBC=U4Q`w!QEdo3R zA`lrN*NdWc(gf+ox_l?k%`7>iO`--OXf_@jn7vx0&cw?Mh&G=3!FgEPA2#!_LSP52 zwy!+J3<5Kenh-dD00v?(We}^0?;IMmKMy>AsBvd+CW5tQsdIF|0OHt$=|$3}`%+n# z+Lz4KCCb0goDY#MxbKKtNzCEt@%D3PFTLqYzwEWIoes+K10OtHsW=W$EV|y|!J;dA z_dfmXUp@28(WUkE#icP76Ykx!x%0Zst(hv5Pu3jp%ir<(uhC2MpZnmuK2x0(-?7U~ zGqgw99Ly1!LZgzh85zt}rEX?KIX9O+Z#Xy6WUOFIrYhP)ShQY(&8(Gu)j}=r&YdX~ z#>^m+Tr->vX^NK|d&w7_c-22X`;T{Cyobn}Cf*n9ExZ3=s?rF^8F^9~?^yNGdh=sX zdJ_Cb)2eD1;dLyr)#5v&Drj5e1*fxNUl82G5 zRG8TkM9k`>5Z5|b{ROXDJ3OMto;oE~ZCrEkcR&2M_dfb?>3b@oNt_R+Xq#A}UR^!# z>{F*7di)8ZGNu$$qY%d)z}DV&nxyq|xwL@R5U{p%;@K-t|DTWk{?C5nzn<(hzxLC= zGo8uXe)da$_xFC~M}P3AKlrH+uP>h{;Nom7gV`Ogd-aXe>)-c*-}?1CfBE07{rhXL zKlsR}PaZpb@cj1a-}^6raqX=~HeR-}{p56dR)$Ig4$WmDGmDsy6NJj(+EZzAceU`1 zLsP|`@rEJ9`0j;C>Vb-jGcH{N*1*Dfv`cMtse_{YBUy&rkx>3UX#w7$e6 z_2VD>(JxxPzC8WeX9h=x#Npll?Y*D<%o8^szJ0zoW1@v(w7tE#zO*5b7FjLFQ2e>IDwo^&A&uBo^~MSj-r#hGYq(9!@khHg7S{^!9uJt3Xu0V&-`@ z^K@;0JT)_cG7%Bf3g?#^fa_Mg1?yW1HqoxP$_dV`{#wxYVQ zG+^RtQZW;Go==-3&2Vwh*0Jn+CaUWwDT2%ePt2(nV-$s#B&N!qa(E!Aq$oZ(E`zD5 zn=8&26V$jCQl%}ngvy`nk)09DH;^%21BV z)x)cCE^Q?(@v-6YlTV)hk3atNKmH3p@Y4R(Al-dOD@X@hNs%p~ty48?1c7Pi3J-q^4=xx`|C1EDm*UZAz29>3mkX;6zks;=Jz<`@`ko zbUZ17A1#f>JCn9iA6QJyM3TfdvO`h&>14b)nXIm_7kz)>(w3yAC_~iQWVW}&D+W~& z$GNYmBZd&U5DF#-Ad18&lwpk4HZl=uZeG6r+u#0dPjFKXw1sX}oN$ui1HEr&%S7pzVk|Dv& zl0c%dk~bvn;!zP`0tiX~LzRdDM_?kAY6@*2AQwyoAs`qjSybbeykPgTojD^LD^vh= z1p>GPIkeWb>%d{aSnPrOuof<0-ohCi&`j;Z7TR4*E|}H?F=I)Ns32Eb+n6OXF)d(5 zo{eA%iwY3CAg#k_fZaA-jIaJecj$X>_=ih#z4tu&o^1o8Wtz;IrV?pQTJ8ia1C*IW zXnQv6Gl^MOX3b21h>4?UboTOOXFR#IHx1@$gG3BV3&Gb-jFHn^uroy)t?apeF>S`R zAE5736phM6jvU}rlOu9I1n)_>iMfC>bK6+~F?CD{&}^6_77=g|i_r)i%u*6oUyuuM zeO_2*E>qLm*{7Sk)V80d-II_=u>?C!xda*=$AP;3rH%z8(w*u_pe1g4F<$;g3>R?f zSxmO=FYdwP58}dOaDwRtkii8w4*(i1wO|2V<)7unkr*VWb12Ua%mk?JKWzas73(Tn zG(|Eqjo6QI5*(S4THZ#eq#l(q(XPssJI0ID%-ZKs)34bXdmR;oAjMyHg4ZhH0uC2SfH* zW*0$FQ-aIAD)}7q`>HC@zQnu#Py4NY`y08A#6$#mo$oYNMbdOUqnwzxtF5k_nQ{ir zkM{hGH<+4u=F^(~)2BZ6_VM@)x8HvMrE{OTd^Uoayo#)Z^6+qJcd!2J#Y<1t^G)5m z&I*AqeX$MPvvv7=Y>C`}%c`v}U%c?f8(;OxL$^Ng+^LF;iHX2T4*KOA+`-*AdscQU zhA@eW5fPg+Gi&x{=f@SLG|x)_g}SawHhWGOYG&;VhBv&W|MJs&7d{@Jyrk1^A>eb{ zPrk?G&-bd88b$(k>ZFocl*WUy!-7oNkrGq@a=D8zuT4}{nb=2ljS-O&yfcUxeY$<( zmmYi1S8cy~hB(nCm?PC=eCVHTeD#T?TP7|0hLt->>rS7G!Dgc6YYh_{K@SBg14y--))M;xQ zcn9Z*0jCBawqV=mhh>ezhyi1QYQyWdz3li4UhvqRAF8Hf_Kuj5Wd-k1^g(2815=n% zwhgnTBu3gz*Up(4g@9g3BqBluZB8a1`t<$7{&3V^9b+skAVZFDb7sLYyfZLFsVKx$ z+s5^MJ(lvo=w-LB(dOpP$&*V*4^(FV@X5P(<8)==fN4v)xGJxboRR+Ln%x@6eCWHYh7$|@zV@QOzB2Z@1OvyswZb^ZB-M&hk}_y z;ZkgwDXXh_c>>Pp0D~fUU-k;;Sj}8MtO=^7B3bI`^~=0h%=kVAWg~Hi`N{aR&Wo$a zx*T*rRc0BNV*4A`y!^~tOZHs!i#SZnhnJH=*~V-)+nmkxVH$?<`7(kO5511&$(6>&D9@w6ADoc`&7k zb7-3gSWL;p;2bl}=S^&*bB;^Ss(xE1k>pF)%%emJrFWiHwQUkC`H~0Ro9s@TM!0HH zBX!k8OA50jYDS)$Hr7qEurws_&h}(5>i7Hos;=55WvPSIENOx{GGDm8@oaC*2R06> z$eB}T);CsN@Ct2X+f7+S8FrPwSq2kTC5Wh*5KJXTou*XZw0zw=zU7;~;hWxe{Y!7_ zje7M{(+~aW$3J!F{hOPUL(9h&4=skCpH>x@44@uQh_E;ul+N3{y?p81kc+Q+%@@7( zO>dk}_Wt^B-~T5ceeXlFM=1GnFc6B{a%nDm3AI=P$f58E{c>?w^kYn?XD92)qh$Ss z!7yrS>bmfrn47lp>;QUlD{a)1=hErZ zmmYiU)C2dQKlRKO&TnCdX;!#8x#BUs^be;#aqV@7mk+EYiU+Sba_Gp>=bk+sdWBo) z`SpeV>TvTybNXWRON$89RE>HTCK0Glt)&K0U}g+*jzVse1u;nB9GGEwv7RfI#5|w^ zv;6fUiNuLqFg2oRv4T{@$_(k2@oZ$q3Swvk=9pf_*-L7Si|1j6UJsO;ISKt9Ex?9^ zgMF+mV|y1&@C0cwpTH~X3aKKr@P=fTT6j+mP!H$HB_e07!8!OqzCde$gJUX7N`(!F zJSa%j3yv)~cg;}m9LuRO1kI&L0uzw=^4xgR zo1*02u;)Ty);7s#Ubid#;QOW46Wy6n+oCt{3%y#eOjA3lB#M$_@4RmWXxa+QzC1h}2GUzax>D zDzO>z)Jh$&B6rt0BFl+oht=a)J7I3gz3t2K+Slmc-DRgA!gw2>_Lyv;*@jcfTO)u} zOa-hNaZ6;dWGZk4LCmxpj5{-w?oT;LaG4YMs~Z)F6%#P^e{hIPD)91h5fB=9wfxzHevCm}nQ8VJ2pBWXxneDhFY( z7pEEwykOigp~EjWB;Hh%ox zJAdPm`&x+?n;CInu$eBF{k4TfW6Vi?2%+D1WfA8_psCs2XHQpcBjg~U;43QQI?bq;isq%%!1AKaQH(~e65 z1F0l~0KCy#`_kpxL;J#8=-Pkeryp$3>|$oZjS*vLej%Rz3+P&^8}8Mpsz_Y-&RJ?h9^!318SN?>;+tQ_`B z>lhWW==-AYhc&0|xC=@dAY}m9;1m+Ge{WJ`;u)zl?;Mkmd{@I$$ynz(d6$TS!pPPZv*0b5( zm>sh#Id~<~l!yWk7Q%2bi6z}ZJ%e{UhVD&C| z>PxKPtV0~-*Sj%Xb~O_SBu38IquHIm{Enp?uU(lwbbs33KJ?O;eD2w&KKJB9M9hXL zts^fIE$PLbXV!V)WncKx6E_|!dsfqIC<7y5b_8dPwWZZQhavo-#ia|)4hRXc@CADK z#4``LIo)#b#FwnR{;&S@1NT4o$S?fzkNof7{LlK%^!p$9lg0ArfkW%7tE2H``}$+o zKehgXzkTxk$5yX<+iSjlb8~xGu3Wcq^PTU%=M}&9k~jU-Yl^3ui;v7~8cN1=+_Gs| z_-c|`_Q7#I*810hSvpS*5~)E=Fl*_`IL<`Px%oUg zCGxD$$xf@}N6X>RhF9@d&Zo(C3zaM5D;Fmhj$Yq;`@g*Hj(@h&FT=-v|J-~2;A8ha zb$MaFd~|SAZ+S7MS_|2o&ldac`~JflIM9W&mv4Ic4GR3?PyS{RM(Yc!)pS~h;F6n- zXV>0%eCnFJPJMvMi>bqCoMMF6X z(+U2>@Y)Tfq|j^zem(|fwod|}t})I8a9fkz-~N+dxwQA}QND4ZSh{j{%UW4KvD((D zwWhbyuO`)OI`@6=g0H7-UDdsX0>&wtYH}s3sCNvdYTCF043ZcDVn@F4rbsGA>YVr9 z6G&8?a|Vd!pB+t-3@FM%L^8WlMTl5c_PxHjD~g?CW>V?wGa?3pn3^LoF*W8~&Zef_ zSB#h}nVG?pAB4ebeysVtdbTeCn~g zpY+;$*|C@F4Q{j9+1lMvvR=`f&uUeS7KfAZyq&f4?ePNl-*m_8-ujj=nQcvf{r7+8 zPd@d>r{`ypihh3-T{USpTb-MUP*hDl8V<`v$H5gvn`Ez@G;uDb3Y38dqlM{oOz_Jq zYfW3v=3{bDQuYNqitW7BS~PYr?7S_?fl>>D(ZRvsK#E$`6%m6|Q%@8PnJ|-zrFINB z6$M1$U|GS#ei`up;|Hew0<3&$1@?U(hTiqd-U9cAzE}heT;WAUlTIgd=Z(o*O7+gg znR5%P8>~9RK4xnZvWa_7q1_F_RpSr`dRlViCg(ojO{+Wj!{p5q6d-$=(uADoIOMkL=m%lr`B4ICchpH!vYLakpX*3$3p3ap>ILybQ7xzLdRu=4Ck~p0@aAqq%gWW3ma^FQIQc}w-w(-wt3^=bO_2kq2nkXk|s z7#zB#63CL+)rAr(L`)M90fsp<&C@;h!4wriyM^C2>q>uyxIOJl3!eUDfU-POst>~SYE%5_2p6VqA} z5jl7<3BX~uOzgIF7tnk}8%T)vU^^OPXG+|kShINwVdOTBEx$O?M3C~=Lreg6?D9mZ zNPqz5y9pK4eKenEGKOgfoZ3$`5D^0cTMY|`dFf(vrnXK+-Ur-$-s+C1yU2IKEdbWM zGl0VJuITQ3mtl@w?hZ2JhW%xxg<)TdULzA`S{@8&8=6{2<)ztPV@57GjRd|to&VXV z@A~xRClippRngjGe*N`#yl&xbuYBV?KJfH|m*@BH5lFMlo9$zrT9?mg}clQi}& zu=5>8)RCGh@+(ZQDleoA5EHAhh^P@eZ*aL$2>~--oz#Yil+Bp6)$_Xf=a)ZvVsGQ= z`ALv1Q2&;}t*zI4$B*o#md(He4vWcZ$SxpYg0?B`PNg!6<`tAwl92;>P(e;}@(#ri z3mXsyJXY7yPBA@W3S=~u8C-w~+8Tl225(q-!U$o6(1REpK@`jgeO^6iZEfRCNCVgLO!A5c01u1F z+2^L`Pct$55-yMlxomFNB(1b9q$MUQ7|EDPB@!#V>x>GH;mEQH*%&aeS)&+W6Hhg<>bqWQ+i|*l9bNOyZ~oe*h~u5TYY!jZ zJhcNdW)^KJP%7P1v&}Q7&wc$H-|{tY{PJJ@>vw(YH$L%;|KX?p%dh;0S#1B}Lw|Ys z@~J!j{?5}UPfqr#qlb=P+KL z_`tg!`IC2l^pSIWqiW;G@Vcet1?R0C^v_(Xn>ofh|Gsa3^^4xTc;<;S2X8#+d%ZjV z_+xjz@17Uk@Dj5aocHRSqyEz9#+zU8zuy1f=du-e)l<3b4zRHR06X@%8B4S^q=J}$ zN~b0D_H!@hf+sO0uzCW56-q6c@im1;IHJNlBEw?-Ck00jg#M?|haJ+oTc`QQpNEf!OB^P+qW-s&R*_ z&$A@uB_SHiph>cN*Doqg?B zyy2_TrT4!7{xe%LS_^fuC`hopP0mI$=eWDZcjjQgz)ZO{x08Dny@KGv**!fu;kLK2 za?O#!;-U{d=R6Y?MaVOG(JMUr;KS;Hm4k;4EUzr~dSy|BB6!E-z0XeI{4P|~h?!ZU zI?qg$cgbLTk}K~kfFwu#O;fKp8CsVGBJw~`V& ziV{uDlh4?#YF_6&tr|jEgrbPES+8GK+Qit7_fo&t8!q$+ytgy<#Ox?l$)d$Js#?)2 z%q%rxBxPBKz-`-#S!zLyFe6tuK5V<77N3i^7*K)-lH9JgFwYR8^xa zEDZL>duL9c@g*0f-`Uwt(m3{jsV1V%rfx>6W{A$^z_Bwlb-OokOaJT}zW)cm|GRE_ z#VzH+kQ`t5_~}pm!M%3b-L!J+!pcG@TuZcw<=Dthy9d~4IGRkS)qFa?G%ne{^>uG} z>zlu%9?yT{4}SaiKmLd3Cg=ND9*kB}Y^Q0fN)s~$R1o{TbnV7*(bQHq~@I$q&7vD3hkxHf@|suKos@N&f5rGV_Ds!Tw;)`9h=)!ME)^ z$xLkyOCT~hpoI~Tp_r7vr<8+2*4??8;fkG+JC)T-g|Jr`R+SH_16y4(gft(C4COErlW!p`7p5 zdwY}8TbzyS*$(#$A<8Ui;(~)YK$`LR+~;PSC;Q9SFCV>bY3<16(@#s<=?#3EoqF`{ zKR?Yo9Cb8urN4qife&RR({Kp?mF64_J4$v;?=k@2T`qhsf{_PzXZ= z&Vf8yL5B1=Hbrh)@A7;_-?;IdG7<9L#wr@ks1I0>H6EU?#~Ujh1(>95kUwcKuAIeP(&()l1i2H z&Eed8;+yu~Yt1?PkM*9C`Wxe`QKLqsbMCq4yzkm;&gXf44~W>wh1r&@Y9eBTixlO} zL*(Av%}Vo=W;jVxj|WD(c_*hid(Xne5ut_$KwW^u4k^zfn2{`>g~Uuwrs^b!8%|8! zKB{57<22uXr2Wia=zBgylk3~)W4}h4-6~ct*W?XpF?&J!{0OQlm$(s+I&~DN7i))L$-FCX|GpA)IXE;dx zfSgN>>{5Dk0&JP|!|I?K4VxOYAPy|1CKRbap}@jy<_tedvD;>ziS+g?oL3P-dSd;z5&tqTGWp7@zL@&*}OkgT68-atJ+zd=2d||%-s}Fr< zrK-l%$|Iy27i$YaIb_OkbY9MB*7-!2S%;1(4f)d9fmJ4a;clw9c@c2#B zqj&giUGR0R3}vNa*~zmWeWGMmI>g+qpg`PIiJ61Ax+kEpy-Fj#xuNu}gyp zBJhJvZM#4Puz(^$;G?TPSZU9l_3bSHs01!(72}#Bdk0se!2lGU1msWyfmqzlGZ9B{ zO`{4@dBQTV3P3XysD`q7%=)=bt^pa!%a2upf>Id%J}+cALRi02cdfDjRc>LKq< z@?zmKj6T&i_pu2Moovs2z}b>Jrn~9WpP5Xjm$SCFynN;R{^rYG^0h;s@H_smPrUoL z|MZE?-BEvHy*a(Iy4G|}p+jt4*@ssZ%ayE8K6kjm zf(J4JEeV(Gk{sj;B&NuaFA96W{YWSP!f?Ksm}#?ZaFbC6X&w- zrR8IhnOF!}+oUYTwp{RtVrG=x1*Nx>h~&To?CJ{Vf^u4dxd{MDeGXBncq!-oGJE62 zKLS%VD=r2nVM|Jp>T&41IPU7M9rr1>+^?NFRt@g|-1)~J`L*Z1>HhKee(P60^w5)^ ze(Vxh!bsqniM=o#$jN+Zp)Yv}I$#|lFbkJ04#4I63 zCN}jDAt6c#LBe=-b?wl`+WKl;*Fqd)Am-wiVPQ3kA(ToO%j!%bqDc$lm6niN20V4W z#IQv06LPN{#j^EXU)ObrGMUWXy>6<-yi3_aggbK1<&LP?oZQs9c^8|Qx~!I2M9qni za~2lOT42AbnsZ7irJPB`I_tWAygG{Y`o;5?Vhl|aL*&IGp-(XeC+ZfdlHl)FL;6T^*xd_e6P90X&`D`J9+j(m+3A~u~ebTy)#VOOb8DzxBz4cvN4lB zEPmrRf9qF2^h@XWE{*xnvGp6;c{g3`bh^lv49TE?+%&xF%U<%@&Gy10XCE~%33Yv6 zT7uMG^yX?iZ{1Z~cK3FgYA{+E^*MK`b<(z*8d6DUAMCJ8OeqdWN9(~#x7hETBoHX& zewNY%zWo1}y4e?XR6lU@IW2oE%DGh5C=|m`LKEsk#G`63NWEsShbxC-wVJyfcy8zO zZr0X=Mx>fC8yKP}=6Aku<)hDj{GESt%S|_LgpIx33s)X}^z0V`b~8g(n(zA6%W~p&KYfdBo=2w;LEB+#=2wB^PBlD4I3p*B zqgOZ(1YLrcFd8rIE2Z4S+4^E0A?wtgWqhbPb+gGR?_Je)0nL=uCp++S`k7jHPSQ)q z;Vlgf996`h3RIATo2V^H<7CPfq$+C?GiPEdU>PD)i^P$I9eqkoh)k5Tb|5%Ub3VT{ z+1s6pXrlM6uViv$-pb&#B#+z5o66(5LOm&(WFZ$a-+1Sg=}vDvJBtmAqK@jmmK63Ri-G+|3|H zM9?K_X!(npmo>5%7bvsARC8ge2+=?WouRYB7_V=(+gEJ| zaC0Lpc}C`baWXv-WSOP;;%Hfx&|EpqCReXqKj-Kftmv01Vee__H&}{P;Y&W!zjW#> zuj#VbF4Uz1z0`rYk5v1vFWW&&OpDwVB)t5De&E}rAA{GX*lQ|hJdHv2(F2BCyOgf3X^b7P01PB1%x9w+UPo1C}-Fs56$Hz|I@Y;>T zxA66i+5C)6cFOlV3^xY#kwv$yi$qnB!Pw)_QxDDFO(6n_2o+IuSA+Tc5kS`SgY701nJOoH?3J?!4_QzUEuM{_K;_{oTL!!=HKjq0c}2 z$Tz?FEr0Dh{@TYr|EVjpGjF)34qjeSdt@4KE+BuGhoH`&}wY zltBCQ-F@uQ(fGpoi@wu-<9%Ot=Z&YXOgDe$zx>`myzTG*?A!iLH=qCFdw+9%bXu5p zXLB$O27}L>{n&?}`rx$~fJ@SZ<^(_j6vo49 zsA!(tof`>c#$IKw8o#i&$tk`1D^|Yxt#=>3ebisD-}u*m{s-^<$dj9!!?eCC$3}yV z=przqtR836HYMu0A2j)g|Ccwe-6)q{=ug~y65yZv$zSU`IeF-irsT%rf@sH2o~p*f zcf9*o4XL6HIQN<|_27z8N>I$*gvFM?cdkNIQ}u#!^B^YUU5T^sAqK?1dvIj%}NG_Q&A3KTcN2-t zux7^Y-kt;rL2}M3D`Qu0+eJ=UL_&}vezFu!II22QLA;7@y#G{_;26bNbu9ZsQA2o_+Gtv~$M5mr0G%=!~-6 z_5FafAtEsfOU1ry0E$&4A|W2Fj1L{%SUG2mkwfc`RVQ1m6jJ&uT&KW%JC2l zwikIcs^9o^uX@$%U$K2|`(M`_p95hP_$ zu!<eCpiiKYHnxKXLBWcOAa(=YwkS#rvLmcX?L;v z;C^?uJ3OY{&AlftUOD8jg0hc2ki&K*8%kJIIC7Q{)cC9;W8B9Rm3$* zowycuIuS7>kkCPSMO8&)gL73?6%mq2@vOR=lNuLA%X^D9w>|+wVH#$-=W18A75#iIf>cFguvdnaN24vxsn?or%o3#9y@Nd?A`= z%`F&Gj~JB)TlR;rz%oopoVfJY8Huf$q?g||~)U3u3uK4E67f9J)wXjsg089*4MwKO1VaX&~)=3r!m%9-=;LNnX zHdtR9RwMzXR~dn*fiP%>?4FN@l{;2Xo}XPkmo{4h#7T`H?itK*)D^$vrjsXj&+hE+ z3bUI6L?leC)}OiZ*zUEf`{|k>lzF`DR+g8N zJh3jPoRG`u$RvO>1u8}Mgo7JQ`Ml+Vh=Zs3vVL8N0Cs}`QkqrGA*{^A>>yQ3Id5ir za&LPWhi9%&7UFwt8u1uZ?=5B*=i3vTISO6L``kmZ$K5+V{@#!M`5)dCj!SIB)GezC z3*e=auxvo#5FlfD<1z^W4zuN}M}*y!JeMzc?&iLjBHf}ltoFlsUi4Lb#qqm6w@+St zV&=-hRkP<@9z2#E#;+ON{ieZvADBJ({{FLx;9>_BIu;f;Gc)2yAa`Eoz+#CCIiz&C z9;}p6lHcY4g#(Wq(SjDA-+3tRJ(=AQwD-l<{<##W?I&L9VE{r?H^-WKqs{wZcUSFO zS94;xfg?phHgx;GcOD6_fJKdV3XQ-3nm`Vc<)zF7#t0GSaHFU`-*N4|n>*ETqY&K) z6alz07TJdttsk-JyxiZBKtVib=(5BdAS9zI`d*75r~~=~Z$cD!u*D2%4z9pPRP>)r zfx*!;lM960jHOomB zarvP{;)(y(FaFlY9{u>*>gm1xi*Ng#|NCG5=>PtP*MG(D{^@fMKl|`M`l+8h)C|7x z#KT+L?QOTbs*d&Ac>Kb4u28{@$jSZkl?!?5cZ`mWLR??SQC>TJ+iidTi9h}MfApXK z*?;{fKl;yq?6Xfi@`ZDc92(y^o9}Z7!$GsPxcI(@-}RaszWkOuZ+_%+U%2hm%@02P zh2Q;8fBuvI^?$hefz^lqYeOnvfw(|L3x%~L! zJ1>3tdcRPbQHV6#@kM8COTz&lUW>e)H@7o8D)#;Tc6~UihH=&}E^S>+vUuRl$G+~z zP943yx%~0z|MwsK+DAY6g$rA)*mxX|4hDm$6=`->2T7#;$^Im@wG7YW`EUE$m%i@1 z4{cwb57z1`%6oqCFaGjR9=`jQmoH|mW^V?ybykn+yI=Z>UwO}e-p`jBIyMZ)HRZWY zk!--L6*umlEGzV&Sxtr673Qh)g~O8?|+M;D&kd*o~G`O5ij&LNGDjry*e?{^RyjO)6p=F@rZ6IZgB zrqQ863}G>87mK!TB0!qdU_@esoKkE8)Up`|?1=TnX`g+{= zsp~E0zVF=Q>Z#M=(4niFXMgomXYV~3Uvul-ciuL6_QIuSFHLq@(uOIZ5GTyRPJlB( zn3@0yGD&n{i#Pi^kB=QXeR?=v_3T7m)uBA;g~<%WEG%%6D1*UZI2^95jz^#d}jgV5JNv#5^!McyXk%kRmDt>f<%TTcP?t56+u4r zNgZ_)G;2_iZux*3cHgK-t>Dn?UeO)2TD-Os7L z|IYh<@UMRVw|&<)pS=Ba99Fi~J@f~k|LmVVnXb<^>Wv$3I8NN`Z_ldr%3VVvw$N^` z?Wo_|os8B8U-!LVb=Pa}zIJ~5=l;{%e&^%={lea*G1iV8IiGxa`ua^!%) zeQWpMwf>TJYusSu^QLSc(ItP&VlUieXnW@({3rJ9yF@rOYdw;cc}t_Wi%MAhET=03K}${ zaqio8y5F~%Xc4NI+l8ljteWZeWirBO)jSQygBXUXH{lQ}ZmPPSPfV>}EJ7tY6CllC zWZo{OyN-!@^1L=)KO6?w+q&AdT@XpRcQbOo^!%P#hD3t|GLYqLBGKHnZ4rX7csB5| zk*L&m7ABmgE}KgrCMTvCqPnJb&K!bBqzL2OPr7TneH@F_#9_E`IL{aDW50WCFud&t zf9!g|_22*P?RWgA4?gslcYXJFtRBB{_wcFa)c8YBUU>3c_u5yi|HZo=S)DJw{Z040 z`s2)vO9aNUHQanzx5NbNK|lyFhN@G8Krrz^Evq+F zNsbRIg3M3;1Q;U ziwHHC5q*)aUyPR^U4}AWv~Br;Y`A3gfl7C^x_e&{yGNCZ>&jVkcFmbEJ}eten726# zc+&397xUHTc6Cn!gmnr5 zh)x-SO&*(GxRf?qHudF_d%5y918A+O?>>HHg9N2sfec`j5^%C@z0_$Zu+^Yj?%F@Z}%St+0PO3$0Ez5HTkqNa%j!4KLc6Z@GOZi+2W{J!0(B0ue zY`)}7GC{F~1Q2)`F9sEIRDo&`5zN&z21&rvY43&0GjSE7&dp4ia`xHG6R|TF6P$tF z;9Hn{X!|ivd*5>8fq(GrKltRQu7BdQ?^jeIP*#wEi6hrpEo*YHks4Ad2^MB9%4b>Z zvzTUc6QanJ9j5(W-Wy{eloolh)9)M`Z>$Yhb32#1%9?WD8L6}9oQ4?RQQi2!#yw~4 z`d@U9BqZSg&rTp>200NE2Z;{qJS&{JfXN&IrE#&D*qkkV6HBi5(_tRtQH?m3Dh#G&U% zhmZ41@6pRossfCOj02N|oaDA+D@Tts^9MH@qc9vk^}=)e)5TzI0L=tv zApoP%>a&kN^T{tf2p~%2F#71{K6&o)Gp~Bdy}$dX!)x=+4}A7oBp$>t91L5U)J@n} zUy}=@rc5BWO2TxuH}>WLu|Q70HLtpTkt3v-~Ky4{?=)~69cXmP@f>=hc=iGhj~lg%vPHq#{K^6+HA8~u~&cX_;r8(&eN|Qw$I?-{P1u7`3L{9 z-6Qgqm3W8(WzFnr-ZSb!Gi0^B`A&>79EPslz4fsC&7XQ5*N6=bSDOouU47fX`PEyF z+!d*!h8Byqia|NweEV(BoPXj|SKk+KXeFFjjmKHA-)^@)-`A}X#%vMHMI&VTUx9L4&e$!1z)75#07$92bB@oN$H?N%&2$gSKRU1 zho5?I)tVD)N3UGlJa%$}30>DM_Git;psr)P-|lSg#8FVFL<%9!r;Bdhk}#ay+{igF z%q<%ShI>vH>)@tl5N1EYWRs1rgqmd4FcK}4l+})wB#W-qiK>{(C4w(|MDG!XL z^%<^N$&I-<6w8hhs$X>0*iyoyCI3K(0>>saYjt)tHwr$R=-iWnYZ;xo;jaDZ$%n6> zfAo`=?>%0>^7Jit-_l;%+Ii;U{`Nwhm*Bc6)I^GbQ1O0Cm$q;{MQe@>Po8YnkCYoN z30TC<%1>BAh_Wp03^5GH!_j!SerR<(8rD@MAxMy7;$~tdf{>;Zo7&x2#OxqQEC1#SUG_P__St1it>b10^<*b^t8iZz0&897x zEKOh_VwjaIv4Kjk)`?uA5Fuv*4DMWUkT~66FfZyRhAPaai`jJHhPsMP6E&cp_okk6 zUi!emAT6UZF{d`0>wG#-y%I2A%td50UWrvuQ;tlD7qhOas}SS^p4ytguGvv7z2xbIyx^+}lof~pBk)sXr2V)xqiwdriH?b_*de>&e6 zshWCF#b(e9t5_2#yC%*1(^=p5YHd#Gwo^BM_ji2DcYp79zvP~mHfuFHJo)}7KJ@z^ z-@l@#51(2+eY}a0S#~z}FQ3~ww6=ESrm>~8e|dj8Y2}36cHilje$_4eJM&-s#b5p9 zKl-oFZ$G`tYex>9$|-G6HfR0JJZJ9!9$@Xx)jM8t=;iBJdHmv2=kl4?4!+{)$un2l z^K~--D>=Imi+EmUx<$myRE@|(6_E)7)lA5_OUV`o!K?Du1DhMy^rW7bd4#DTM1#_qe;u;pzlj?kX+J{lw)G04C%?XxLS1!9u zo>LcNowd&vDb^uI5d#T(L8CI9SqP+>bJm0Ab`};XzBkL}3<8&ag&^!^ecOXPMhdmC zan6gJW?Th>1c}w)Nc!wMo}b#CfBhei4mD@r`AhTXKl<1&KR3MLw&ZK8Z+g>fzVg+d z{=lQ}{?n(w|2tl`F{l6bfeY_`-?Lxy`kUVPbtjH|^U?7G>%8ajeE#OIx_$Q}S1&*H z#Dr=(e55%%&KwOPRv;)+lDf1hcWRl0NGSw1gJmTlk>I_;`);;yRZAUMSU7+b+O~UL zn#^@5s~e|pyJgXBzwpR2-Q;qP!E=^SJ1bOOorJvDHbkfzkO%5IpYHMM5TlV>iy#;` zVI9>9WafIj$-~C`1!{%@J%IxR$d1ei1`p_g5U7se2#u~}Y0>V!(6!svPGJTfpdzTN zCUPSY3c=ewTsnhmgvkP_#iB(Bgt)SH_(*en3hZ7p@|nP@5GjG2gK!fo0jXLk)^u|t z>dm7&Gn~ZSAfoEYFlxAp+<=?FWER(k$y(oU$r)=avJw$&)~0FK?JgE=7UxE!T%x@S zZe`R`1%a8_EPyjP#LaTfp3RK|#m2m*;V9OX&GuZmrfNNmda}&5d4iOY#Yuz(z6^zu zI-x#E75n@;Mz`XoH(@UR-l(P2fU}hLG+)+Wsp(gjXsY>3!c z%DMzoEv3Mc&ODfC%gE{Oj%?1M@>F`;Z8@1ziE1W*it)3EtO6>^Qqf%vUQi`VlT|?k z_(5C15=yCxP_8OeQtmR@R=(F8L0UmKseBfQu<;7t%kZM zhlu9|#JFN#B=mu9f92Z$^g7yq<<|eF$C*!+9%G0g2h;;_fEw7*D}uls>>xw#97J4` z69+Nqu~*;nFMsUi|KYzs_S`&!g(^mZLlA57>}t^9E>sVZ2;ReiY^Z8jLHGnX5GwQ; z&CoSLjRN58Zjgwo0h4D%HRQp{QYlg{6eu@93B(kGn{up3Iqyx=WLB(H27(g>0mxGZ z^D?|Ip5aGEb@--@t@qCt(*=!!XQL3D2oPfC5TOflLee`CD`&d;bEP>|T?9gy@(}`1i+k59OUh4$l-s}3v>AODmkq6)Y%fI_q zzx%Jh>)r4DlaKvgRo##^_lq3ku&&z=J^G&49DCg>?z!`$pLp=(krU^hxb|DW{N8{6 z#=n2d14lmct|w0)J3X1tGy8CTIJq`ulWJV`+Qm_Q@w1y}?!R)|51n}M?Posu*i&zO z>C2_{)MB(o*~sTUyKcLLqc=qmPoM0rU)|p0{lhoQ8@~O>J^$nS>Pu_8j9>gGAAR@l z{Ke(X-HmX3IH&oEME z|M+bqUOzNi?-mOZ8jeOOFIHB^>xU2h$G87`LtYC<8y;%sA=HQJlU<%qZLil>sjaOB zLJ7o`IW1e4ybmM<%9eGN-}j2YcKzCQUeq_=a(uQm-MzLmIy5Gu-AlWZ$wcaqleM#UbYz_S z)Xo+}T#staW~LmOh0KZ%iu*o?Qt;+_&}&Z;#nnw6v8;5786`kPM7^e1y6oM_kxiE- z7-43%Y~^@>7TOR4fLgHzm$Ays7yxq#$S><|tcZ>NIX}9QO70TGzwJ8JvdEciHf|-@{X;oDaYUh13sCBsz zpuSULs3EH{G02U5x;G!JG_eYcc_&29uw=wUrAAfFN;MyoW$G7+g(RSF&EXI*aZ@*K z?&f=QFoxr%TlBO2MY~wYOqyZC%sJ(D(UqTz7s!UXCu1?NNtA%fyh4IKGzt@%u`l}k)ZE8Vj?0_xVgE4-OO@lOy=yd z3DiTgOA|+b2_d{fBS;mK!|LANo{1?s(G&?o#CF{EmY=8*~Gg9u!iY23SDBRsM0fb=X z+Eq?5XD2dsFoIMd4pmgkeM%+JE`eZTs-`({2oi;3|Kx8y{R@|0`j)?O%U6B<*$=%p zU4AC%mV}jue*Vu^{eS+}zxA!}`B#7ZAAa;*-}7UC<-7jYD=vL{>v#X~;>X{6;Vo~z z>E5q7hE)%Dhwu95FM0E`w>@Plc^?grVcwsY+Z#Xer8+BQYIo6Gfb0{ z93cV>u81OfMK{NMjyQx77MTX>a|A_IqdOekhsZNX1+P$GH|7V-8V4Ao6_5amevi0E zYQ5d|+)^wi#~Oh59f+asno$RkVqw_73S^`nBru^=aab8h7*SJ=PUq?NV$zeiD>Ix( z;H*YL*e&;2Eg&+doMCQ6H4DhHX%CRA5qBMCYNH`nux^%oz&;~*-u1o{B_#rY$%(`OHx&win$ymHr%nq? z3Jc_cBm-O8X6PJU4_kOz3Y}IwwGeKq5Dm7-9XzGJ-`v}trUW8$@>0R&#T9KmQiQTm zh6mINbr_ai_xxg67ZHVnQx6AdB|6YQ>BXgbF%uIBa|9_YbBtkhwBOq_Z5aZByP7+} z%ZC?Xkck6}EMu51L|HA6NU64iF@eBBT%PAlMQ#NVt9vA7=41u5%SNPSr4KNQ;%}gX z)c}@|pzPUT66Dc#^GAN`Z3HE*Dkd+B7-AuDqvL$+<<;#M?fk>(@s3o8oSDcO!k|)? zYi3IewPiRP0E%#AbvuCFAY$S##0;uTe zLSVPam7WaNEtOSbuwbb@0!;)*2?L;+Ee z8^C(UE#nQs=JS`v!@>2*?EL1HvJoudMiL=V*4(D#fJhVxrU}6LD;HmO>wTw=pV&FO zSH;@Z*<-6ZOLG?97_P2V&2GQHJKvkOyA_XP9LK{WuB7jKb4W924v+TwZASHySKRm8 zzxpSX>mU0E|M1U0{AbgCa}bZan{yluk6ho`diTS>ealz=#K}{~7u#2EICb>HANtfs z-uuRTzw*{kzW?dXy{m_g95&A;9S!@c8a1P)ZTqac2mj6C&4EJ7iG(tGcFEZTVxS21Dpnio>%)3wXSVbF=5u%5y80bI{@ScM+8DC%ul>{C zeEKubz4WG6MUT19&Q?_%q`vL8yZ-ni@4nJMKENr4#2}iwlmSqb;o*ANYuo0w*TupY z6$L?bxOy^Vp@ODG;9y>sqfX^PvOLXE474bfHZX!G?-{|-15~!+YUWT!GUSqS^-?}T zL|(!Csq3Fy3rE)vt$p$f4}RzCzH?>R>|Nh&s=>BS0re546%Tt$&D7uVch622I zGIzBlnQ58sSZ+GG%--bYW$JPiq#Xg~=72l7nZrrS#iI8h8aPrc4+k>^n+VM(){D7& z-{-+7R)fRM%3!j8=(+j+ljrtEVSj{0O%;pIr@Gtfejhp-$CX3FwPVeAgIFXA;KCHE zP5>p6CtYWMxHw#hfrXCCiD{HGOD=Wj%pss5cW?^9|KX(qo;w2ay3WZ8DOXZ%; zohpW_DQ5fg@yZZX<-SkmMXk!3B?y5`OAty$s&>)VgG!?GZ7)%B$}tLoQ=dW=-H}pe zCW)f%i&-}q)C8!x2&)^Hw30cTP|)x)}p&0^B_T@RwBsdcES zPt*N*-}QA>*!3_+YWu3HLLCUSn0C2W7IbX~r@^?+YKz%I0)sG}&NN%<5(pe9<;=oO zUGMKts=AF;OxpH|Sjb>*<>|(z2643#J_QNXTyvHnYb&cxdgjczXPuoo6Hy{Eo!bCwer`-44#ZVc6DF}ra;-a65(i>m(+8_F%@BhYc`-Y<@k4lWW)yF^l z#KRwYf~IuO-7jBRU+r7lxw7B)T1xloIu2sk-Q6Az>Wx>d9e>@4kiv(5`@x_4t)KtP zr$16D-+A&5Q(T)|y|TClxO#^Bp>XVFH@|F+*XLb&;p#>Cvd$0Xj z2W_fGsTUD47KyO3168;YOEYXj2&vCGCsk!e*LCg*Uz|1xSmG+kE0)GxQ@3T>Eftt0 zW66jFPELBTKm!n}YE%u^S%$G5p=9!=o0gPd&1e{gwQASx&P5=>rHYOWH&=5{Av&CM zzhLPIP7bbz^`J`aqHPzBG^&RoO3rhj74qD7eeT+JO2}@R3-Zv_G!c`Tk}lPul3mJ{ zhyou2^yLyJatgZY~`E?B;F?Mb;juBt#BGByMn5HDhp@ zSm3UjiK!0beDUK?{?_^NiMz-3TI&1Axxy6n;v@g%7hZDbsqg%UU;nlr`T5`Yr~m%U zTi)^`f9H*V=bx>=@BcpgU;eKrU-kP>z40|iZ@cUG;N>fWH;#_oH@No)*Z=xc{U84K z&0qP*#VgzO>P^SJs+G%5%A^Wp31%FKKrU=xq!N{5W-(`W5_TfX*1ItYld<$2dEi+0 zJ@&Te$eF4@U}pveg0Ywfc5@0sRpYu`gR%%TA$3HR45QEHx$A8=GlkKL&yGhN+Q5E~ zr1B) z$eeO7Ogh_d6Dk>2VO`^d(2_e71&Jx8sBp{7U=b%S)hXuYBnAUBoU-ORkW}z&j%Yv# zAvoBKW8;eibBtH&jUmM?Fe3BDV9-(MI?e=gj%B{``QUvGnQ+doUFa&0sJ* zq%=;mp60OLfhG<><~i4t(_;4Q#V5123@{(qWlKDUm>iL$jH>ERM5Q5hd1xObLy5o$ zL{M`uxfg5~nW0ZvQHo*}@TuoLFM3dk=7Pw12}fY2x(cJFsoTBV0F+b^=VkzfAR5$5pN#;efAovD4t#0Jjk^I-#_t#N{pEL9@Q9EAi7*E;sA5@l zNLj?g4NH3Pl6zP7?F1=3CveMd0M#Ty6aW&5isZ|k8Z%>AkxB%VY!wHF857u%REz#= zzN{QFXh3DKez~HwY#=fMdd&o7u0D3{`2dTdVJA0bBFj0sk7@V{ddXYw`kse(AA8~4 zxlNxHOg>puLyw+GI0UdR*+>+YmocXveE?3#kprx`(%oW!V?(%%h^_{DyGiN5q82`aMf0L`j10WAz(oJ}lHhh@|iB)FPKvbJ@TV>ccedfJ)vAaTm3gdh|e>k>jl z!#+GYe%%{3?mK$rFCJ5h%SUoD1b~ApBWDT%uH4L>s1i>ZLLi|qaIT~2mmoPGZ4mF>3clwx!R zq96n)s3JEqBN;Vjk!rf_hMM*l^UdoUH=Mq>xqWTtI+)bd+yk?#a^TCCubw=1=++~* zefFu(t94B?nzh^4ukTbL9zT5Yk+V;lx)6~;$@bd)MYk9>tK^!~gs6abDN*|z~k@x>bt-0`K?RG*AAb(bncgb=^g*~SN@xOzvh-d`R&iF z9a>HEuA8@maf}<-+uqsTnYC>vLpt}w&SQUh_T_Iq_24@nfAsvb8>9Pbq3Km09igfM z9pSwTdhUfqeXqa#C&x$Md^k4p&>x=rZ~x`@KljMlc3)P*kwfuxT}xhQmy>e{#1->A z&9nP}BV5#6By4PKz+~^*{yy!!;j3PM?Dk>T_JdLL;M+g@&j0wXn-0B17EDYrR7%z_ z<~Q7S;>zU0pFaO?!8#-4oMtv@!nn_Kf)KfP6k~I!SyM~1JZtl8Zo9z8G>yXYhcG5R*MxKzkpicNHP&qhI9E$5tb z4wcZLR&%(qaA~5kC99!u5I{m^P6mU9z*b~oCRJmG8H>Z+bDz8b-q|&|7Z(Oo37x>r&D2zgVpD0>)VVW-I^;gXIK(hqZHh631lXgL`l<;z!xA^6L8xWW zuXgEV*Uzraw^O&@&Zmi#LX0cpmBC6g9EVUznZrx9c?@oZzyc|c{urZ35T;PqA|et; zE2H(pYlG1+gbGAOCe6K4Qz%Oun*gJ>ZBteUVvOy)4I*%B+pZbZs(s(*{k_S`+89-p z`qXzlF|knU6AODTiDvX|8$z5-7NHVn>ia}QU6(nKnJ;Fo2!}dO_hsRz|$XW!H$ za@V$Q0qm(?MuX`^)_evPR(g=ss+9^og*)0s=Vly9j2DwdH*c#ZiiCRDq^{rJomGR1 zh%{SHxnJ}v8>3j&p_18N*L7Xpgg)o_)m8!n)Gk^QCT4=CoJ}Cp$DzV^)Ck-_03 zrwocf=mrt7tO~E{rivpFvgVXi>U&jn^zPl4D5b^uRxTKoglLx1e70;XFOO9!lPfJt zFPuom%NKvBRXIEQ?DNGAG!vPKR836~NA{#dQ3Nc|lyU;dh%|Te@|`!hnIpTag=!Ei z?QdTrAU2%U7u`&!odhCQODRV|)8(^OOt%S4n5KZsb&i+7Ptt;92mpVL{GD8xGL zo!@Pz!{$g8oB7tB*44^*qq}|1{D&A;(ezw)6!dgrrGJo?wZ=Plp* zeYbDkz47#W&V24;+q)m$IkeH-{M9#Cuh|&iU9EgseCz!;f5TrM{iRM1z|u7s@Ce(LTNB(P}TpLy!(-Rl=ff{}{^ z&*ThghHi;+f~bR$6@X`e$fJ8Q-rz)+4aQuUlrkhy&ZJ1l{Qr~*>&-5kU$YF(aQ zS01i69;u7Ln(PTtax%{zn3Lsf9xHaJs)3jS6()kI_t_&X2&tpX7KNQ{)_G80XXB>o zviQ|G^*yRkuZ@Ibnr9vjR+?&>Fd=P0g-Pz&ingcA;m}moiHri(1B4Z;S6mv^XY~)n?dp_=;`(w<{kt7tv7>j8J z^$3bm?ZW~~c(MN2wJdSWnMBH51}elv1{CT}jO8_&m(dSmQ+JSqDM#Tk$JNlRuMZ9# z?WgmtCl-{3+z^XWChPm$!h0d8cPwCqx=MLeEEAVjNhoJcxz8*++Ln+ug_9H}+7cE= zk;LK29Y6pgGl3PR=u4lC7fp;AfYTR&#sm&riwxB;ozIf?AOq-yZa(ein?%G_`5()e zS&C%<2Ds0?yJd7l0m~};^7uQ*YI?yhl~&9WJ{>BIHs82mVduD_c z&~`EO_151txcBb*jwh#2J)h5VAg~$$6O;>|lNvE%6)H8&X$mPO76z$#?#%$LLIYzb zMaa%vUQ4qKC8f2n^ zNGp6fMy$vP9uX?{1n(dY1h9Yv!r%akP(`Rvk01@Ghd8v97gtaNDSYNvz5vrACjt%% z;2Mai#z=GIjH+5@{b?DChAEH{BO-gwZeeqee&K1qdS(|5f!$jJ98Cpnyct(F-9CQB z9lW}>`|Mu6aBiufmu8)c+*#^X9&noOBDYl4#F>JEf_o+r3Hp{%G14h%G#&A|b6MFse5 zL{Sik6mUTdeIIpGY(SxiDovP?1>FN`^@JaefFuJ{TDy8 z{e)%W82R`_bhu=S{ zZb;e@(dzivmHG33_QD_BxN-B*BWvx|&67uuKJ>}Q|MZVP@rJj&;nbNb1TfBtX1_S^3HtG9jpS6;Zke_1_hm>~+Zu2b_S%RP3> zKOV^mdgPDJ{l+i;@uxrce7^`4A07=?262?;1`#2uBp6_-S$lG-Wx&qFEVWGL`;VP@ zblxWz#PrP5XNl2mx9|Bk@A~u~efFj6cRCs@a<$qpA#(~mK63c*fBU^(H|H^JWbYa5 z?pafiiU2G9QJUvTqf{&L&?u}7^SIOLzHSN3V1?#QgzSZgP@aLs?k7&}?m{B4^~@(_nSjr+z+} zH)~C-VmqDXE>|%E%d87}mWs@cNmP?414t=zpb!HuPwnDQ@{|&YLX?~`F@>s}JWD)Y zPMM`t+rWto?&hgY1$wO6n2U$UN|v$|YYR)PA_`4MmCG|^DFqhAmMRVgbX}iQGC)Eo z-;ta%Dv_!o=0a5k(_(_I?}eqR8qz-JT-SB1z0R>24Z3`I(X|Q_mKaO3p8y=9l)_kv zLV<~xrIc1th%v@M;Hs)ZBo3iz2IKK~JRCH`nw&xirF5KytEyBMp`CZb(O@(l^le_u z7Z`$xOB#iUx~_+LT?bX&-QFLs4r7#@%uFFtax2BhE0qv&w(Rchybm$Bd#q!>D5F1e zm)kZE(KN$)F<&%QH5d-&i^aGaiHK%pX0=RUsia%IcI?-}O72J5^oBI>b>k^DgBCUPT>)fD>aC-fw`|o`1k?q`^!uA1csjo@uGUplRawe=pG6o%*<3DyE zb99hda?@q$aEWpiCsr{q@GuUCRWmjxDeugjR8x>zV6hgcR8<3za4_>ahQhm6Q(;zC z1+uCk2R3HX-eMpn4=iTHoRE|2BxlzYQU*iJG7*{fu=10F11uqg;O4n&-7}!%%YH?a z6Q``{3U}3eUXoO}gs8pH=s+ydymSYY+?o}+$!KYVKlpQbw`3Og%mwwXsZ1sg77_9i z>n*1%<&*-)!FZ)l$*dcUHn=A3ySAOKY#iP_`^0bjvwwcu%f9ZW+mFsBd)Lpt@bCV& zpa19wU-efWc-_hSPY-vyajepr-6wwjsiU`!Pkz&le&0%UuiW*`EC2EpcYn>hcK-dZ zpLuv|Z|&p}52PdxcV-Tzrf^6IETo#%l|{-r!iYJg5Y1O2>NOm$WUZ=) zu6fZtw}Ol3us;ROu{YJ})!a|LyXJXLLT+$#R1JmTIl~N|VY+Mom;{L>s93PxqZwBJM836T$Wu*>K^j45#L{yr*LGH`}WClSPP`v`K zGAO5(7!0+%fO!ZZm{g7Q#2Iy8tz~yhjMRhFRj_{Z+5_J$t1q4HozrJNiL1}y>eFa1 zQS3%OO}ro`DZdi2a3OwD=|w3Q6wB`BE-Y%< zL8XYj$Y2I=F}%Wr!C)pDj_P_43vCd{Sqnm`P!Y>D2}I09!j)&qmNoZ=>_jX=mWODL z$l!UOpoj;>cUD}ykbs6cD7u9HAiv7Xd(?8hwH!smm&~gN{u3;<-Q_7%R(ct6c z4)+pO)@A&aloY7$I`*2cxaZ5?{m5^>?}gvbrUmk3zQm%q8<>klJ8*P$bpsobZDad| zbn&cRy2@7w#MU@vCU#8jJMxO3{g!|Fkw-uLzkclBpROFrC9E7B9lE`pThSK@ytLuPvyVT! zcXi^L9SK1R>JpF%F~H1?sbXk}&KGd2Q&TPV)hNY)AQGx(Al1Oz4ncuX%7+|`z{~f6 z0^U;$a3GVFIDildK#UNJ43DBiUGu^9vWqgqp$mD_3XTLK?V3 zq}rZc`T940?ce#EZ~gqIzwoYiy?44d|2u#4?|$2Ne)q5c#@m1Q1MgV0T{~Hv+BmW? zT$^=mEmirJPuppW+2-{NU-rNQKl#spteejN;gA2+dq4C+V`)as=Px|+sm;glJN_~{ z)6Zu6+1p_iu5N98;n~jvYk&HOA9~B1zVV;_^gsLN?|iVMtwB7zm`&qwu)cci+};a+ zdG;^9>7H*F@|EGR-|T<;ci#P`Z+h*k-gxI9{@RD?J8B}Ng>`*4V05%jz0Ic6l_SH8 z&tLt_ho5}a-?;UYzwzwT&!2z!>09cG^g68^mg+{o_Z>dq4l_Gt;Rw z;}gw5Dy}R8i2_&JsTze4GUcI||TD;idzUadF!es(=y>Af{{27}?s=#T&W_n&j7q2Xj*Ru1r-)fHt^N}T&lLL4ZiWbRzD*u4=s2&x6}Yo!bz#6SYe zs@V%qDEDbO@Rsnc5|Ddj3u#oi&qXfRVJ1~UZ_DwPKA64{C16k^E@ zG6x|*B!nu)7|Bu9alAGjt&Ai@IK?_RJS8RK(P|So6H~9&W(uUqkSSIn_iCz41%QXH%PeH-i+Lx^sp~a_tV+by zpq|ebRUJ8mUejW)jj@Wg%=f#lPtBkvCNR2rPW?16Cm022=P4_KFXjn^*a)2aHW7Qd z^Q11vCNg-sKZ})ARoL5`s-tS6nHr2hi$&**stV)5cs}jOarnsk-fZ_%pMLP{xu;b* z)=kw6K+G(;@3T{sMubI#Nm!Vf%vH0QdI-^t_7~T3?!NX_U;E=f`qnpo(;HTftbwdc zeeU|{?zCIvlQ*7_Q`KV6_OHw*lQufW8%0` z`TEh9-+$t+x1as}$MUn|YE3Dtrez$~t!iJa?EioMkY)YWf!*Uv zJjp=!;?#U_Mll7CjA3*Mp)&HUxg_i0;#&O4Y?{roBLStyLYG&?z zRymME+_WnhuO)J3sVw`Fc6NYWaff>*3T6fpVuBkplXJnwsXLRnJ98C6?Z!m|%9-6$ zYA3XIEXc}yGS%euAT)#FnTJ2KeeTlw=!Pci`ucHHM?dw6hoAl2+1I}89=$aCs(Wtv zp>MsvJ3YGov5T{}J#zfjr&j;UX?jgPx*>esKREJ|2ZsOk7ta6cr!LjU*N2DeS*vbD zg>Kwu!VF~ll1Aa)8QBpBo_=WHG#1D1LxkOYuH*#MY%&JHpqcepSWeoM_@ zw$2chT=V`u53&m(A{+^~t>E6^myY1UJ9(Z~X&AY7Sts<2jdko?#{`&eyLFb$a|bq% zBLsAgSW^rjl+Yhi@65!8oB)MoSOS^n1yF*Qy=#J!1I()CUBZcD$KLX?*ZKii-kGEAF=*o9 zRf00pEccz0M-Ief%EVBGc?>bRCUbYn#!3}pW2ls(Im0s?X6iX{skvOt1G#XVC)E)0 zk=uudZ^Qgzd+9H2_jwwxR=0lzk2ku@pY5Od7%o4Av<1{g9#2pM2}(}Y z?EsMOa6^gRSS}4#mW`N50@NHJeoS z2kI2u>l9W(NJ*FjF%*;lLIg?`$cu|kW~Sxli#&Vr9)NP7r1> zav=42P?cP(5&$xTn{!z%nya`F6N4F)d`UMD3J$1Rgnh;7mwojuw>8(K$o5JwS*3UkhR(sy0X*-SuzC`w@Ama@8cYUQgenJTkFvf_dXDY|;F zdV&7)mp*rB{dCsIh|6nX`OO@NzGldL@FFAT*5~iI@`q3CJU-LOHcuG@3T_5$ z^qcAI$Dg>Xx#I_peBZma-+$K5Dca(mAr67U0E3RwHQ(-iBBdV%3TD>~VqwYFnWs=V zx24t(?l1-gr8QYK;T@Z2D%#+3{v;-%u#EjKzfOW@b9Z)@;tm3{fTg(gVMWNHCE1i2 zZa`0JaPrhEaTp!z_RkU$Af63@z*4@A5OP&?QcywlUTc$?ap;L807J2!5x$!KvpOau*B=Bf&sRY0z7ipOWVGkUA$ZvPBd&REraw1b*PRFH$04^ojrVE^V6@`dG*nwhjuUR9Xr19>Cb%b zLx1-1uXyvlAARqqxA(5BA3Ca%xh6{%YExuHt_IPz_@f{D)LUQs1NXh<*2jM5`Io)) z=G7aRH)!Lv#9Tf9*v>Eg%pX5@Wv8KLqq?bCwNPQ93nrw_)H~r2LhxK}C`#mlC=eyD zW7VhBr#>UcP!)_yMeCF4k)QsFpZVRl|Chi0*Z!x!_^o%!-u?I9aPy~Mcz&_9;{&?? z%kMk8dFD@^{ou*?l3~4SxofIHn-@-*&B-ZQYU0q%nXS(qzy<&^*EVpdv|g1HM@Ki! zb!T&SzV*F17OtwWK#>uo)UPuaZhG0}F@zDyJq)lHfpY{Vuu}k3J=0Qj#lh~-mmC4t z6F1y)Z?hpdd2`gvc;=RUz@^-4F-hD2KxeH-KOYf-@6`z|5|eaxTp` zA+S5j>}qAuEnZ?_&6abn>R7aHgAzl6ltykckigxX8db|yC{1iLQw3KN6)d8b$tnj} zlaf0dGnTLoDkC}(v-9$IAQD3?dKZTnV-;fzA~GBe$15v?(IA8ns~{rF3PIt;e6iQ< zH%-0PtVRi`%hPGw483k*?s>6j$KxO(g~rD$g>f1pyIY?$Mkx1&bb*@EIiqnt!}KuCNAb}6@z6{H4c&~=U9chsroKS;21(@z2;o((>dh@sE#34l{cLGG?~mfFxX>NC1eDS zYJHz`m%+qBW+-cD3*IeyQzxdjOCiRU)p1gt?#;jmQJ6SZJQ}Z5Re0)|rylzJgNt^* zii0jK7Hz7VQEX~vCV1cWIrSmNrWps3Vn{R7l>3x3$XS>)^!;?cxPD~iwjY1%TYumO zzUTDaH^RN0bY;`Ufub^GmmafcQtE> zv6kRHdFo$1c-cM2UjB~rfAVBLvr=zB+%>Zle;nL3#LC^6B-XV=o-bO>$-I|{+;s=@ zY7tgSM}s&(6brf!mf!?LCn2slHrx!Q8I#l@M6y=$9JWY#-tKMZ+#OuU>QfuHow)Jz zjVDeW-Z*;b@S&VM#;R@GSW{isL8^9h?QPFI<&+j3 zW|R5;e%jr}exKX2Z;7F*cv#SJY92$QS_bv>;`HnPKV$HhN~6oa77>i`B4wS(p$Dg; z((>G}rTc@(OS#=axDHE-E0zg0EZ6kQB*zl#4zp|;iK|f6#qUC1X|Lv5H^ZtLnf9vc z&Q&v5%r?=_&sI&y6c(We4^Re zTX|~Dx@>nuyN7RlWA)E&zw@qNUir7b{`9`pqoaow9f*Y~I19O@K1m1?g7#YeePB0D zT|4Dci3dTbh{<475oy%akyND#8swTXI53L^g3>bRMB+{qg&gQxBBLg1CLF4dzhv!) z*8GlS=hirXdG%0-er|ewF~73o{Q}o_(e>nvSb3iTLlr3qG=qr-0UnSXtk4YCQfTiv zkr>oq8I+01^NfU{Epi9)Wd>Wwk%)aZn^a1#JbBk+m(EXJ9U7z>#YU{})%)DLdlU(Q zwa-Kjk)|1{d*vL>RwDsmkT6wMg_P8Q$Q%Odh~Wsw*2e2qY>l1G3a`tUSwL(Sgux*~ zJ+Ng5RU8{7A_ti>TNFapUb9gacDJ62AQE?E`D*k1yNTrz}}U_6WgWj9o29)}y8+_gavusJ6+5x_QM0Cqx=0qDTVNeCsXxpc2B zDI*686)kP32h%FUX&JXn7SJvGX1&al#>5OVEE!2mrE-gcqY%4O){00~;pkmE%|ZmT zVW>w{Rq_zMY60YCcT;sT=AcU!aw!!oX)H;wC)$V4Jp6*9S5ml?)6)-*x8mj^mt@(< z9j?&Q?g!SZ`NH-2RR+5_KyKc9zd|Qoe&m(5t(RwKzxmWxpE`WQ+s^;`Gu<-{4;<*T z8Z;m<3{Y}oG9$Cpm(E)U%o(H(O`egdRK=T_nUm^T7(H<7t4G7tPoDkUxy2RDWpP*v z+_*3Ztn`5rL5m@z1XsPB;iU#Jo0=IY5YdZ2ADDvx&5lgOHoY{z(9+-#c;Mzl4XPou z$D*aWA~MhB2%vzrM|3z`6-?j=COAR8+$#Zw11hZGA>23>&HkmNIDWJG*&j8~b}ePeBj_y+eVePolg^O&7DPk3atx)4gnL z4(1A>@~nU%Xo*BoUAqJ7h)nL@B?{!cMCU*RN!`Fr)U3lM+;-E6XE(3ScY4$nUnLKlO&vH-0%9W_99fGz+dDT|z*|O#s7<-c&)?{O?nQ!gJ zy55;AE?&Kyk%$H`OxxX4D<_YQk4oS)U%1(Dbm-dF{8!%o>!1DHXTR&)zdOCLfBww5 zQ>R~d%c+~5zIY~O3(N!(;mR9GBeJ)+FiPKZlc%M`OvL5-TmBy&%XQZZ~xK%`ENb=@yFl!@n5|8$g3j9z1`g^ z)|=hghcABin_vDN4aY;Hjk8zJzx_9V{~N#gjSqa)-S7O3KWT<5meq;1x3t?gqrqZ- z(zQY{oPS~Skw>0-)eqfv<&%?F{Oti=4SW)3KeG6vKmYU-m(LvtoM6^}rjyW^nuApZPz2wx-d5)^eA{t3cEU^#G?pSijnK z-a0Zvk|rTm&(35eeZuUeMcn}4=-TNgpMLVp{xkRT1KfqhUKc`K zOxif8#~b6^b?sgYC0A&&I>vU^tEXyE^@}VO$68XaP9~Af9Gd%HNf4qG_MN)Hh?q#o z4Cs{uyE&6kq^@f($k^&xTvECuX!p*2IyV#tyYO2&{Pw+?-oK(E;s;aV{;F+QCl;B~)RyH*Zs~Zq}u4)>lm!jt4~bqD@`bXVnlhi|9OqL4>Z$ z63HE!%-oqsRkP-lR77&t()2?_VHg;aI<1D)aAi1|&OZ9dk39F>=evFmV1{W7loi?}KbUt2>cYpOAH{5&cwa=XY*Z<%r-}h&K zT-*3%r|zFlCr@8~?t0$oylbg-^W(!)FTL~SM>mddZ|yvD_PMRyoi=sKKBz0p7Bo!q z&db6bUwz_D@4NKD&-R~NkH|QL5Sv!ba#Z-|uIayT!hH1`zAx54`5pFMG+$?z{gLM-QEh z^+=60w=X<*c6)cZwPbzW(@CYyuu>1qkXz3Qj;NtG9z0^&lRx z{73x1hgjg?N><91%hjx0XbRfxU{gj!g5~9t%T4Y@4k$Ah*9TZi6p*M~wTqz(1j|W@ zlY0^wN~}OJr}=dI8m%3x>i>tV{|vY6%F283cZ@OTT5IopV&y93*rFx1ItMx@x`A%G z!5FZ?VACdI_uDlO_GY{H-oN{eZ~5yV_|A8H{0|>l zK6LPom)!itk3H~nKmXw$`?j|odgqB}e*00W;)&aCPN!#j0rZ+db3K3OkDXY#hX3Br zKeThHUq5l(yie+kP?ZrAWU3wpks##gXXDh5Rh@E#r63?f&dL&)f;%xsO&K7Lm8qK( zGdlt?EzEbNLZVpe%zfUuWKTmHtvHFh)#L|>&bYUMlE9PM){bAgjDCW7k07*mm~3Es zyNDTm>v>Maxkv&KG*L_wF0t2adHx=Ed~n% z)m24sgNlnUJRug`PlV-BsJFWLmh}dhx*;%0=@b`=sw$AfM_zQ@JKlWrr+@G9?Z+8` z78uLY1f-5k-m^sqn`r^i?&H}U5cfb2Vo zd$Lx=91dQy_Hus7p|i(N>AA1I=G8YYUGt^0_dPy-eudX=#gQdnejGXboMBD|m;?vh zO+|#z~ymB0-mi#DAM)PzXL5yof+7>qDapa2%IfXl1Nh?xSg=#V7D0U!{k!00>O z-0%!^Ee&b{V>E&_K5xAUo*^J-5VUU$BhTCw$sbAsYin*2!jZ10t^B$BQXSCF?oFYsaF>9^4!6zVF@dYgb0wyE`}Cbo1H{lVe{10RR9=L_t)O z5BI5;DzaeIG#59|-gMgy$BrM}yuAJDH@xb7f9XBH@N573v5!A8SaKjcr!ca53DkB{ zOJ}oI_YO8khlAnmx8Jg1^qc?fci;InU;lsq)Q>&;9p}z>&tG%+_||qW!j%2-%U^uy zwXeMP+7r9aZy#PeaQ}S|eCm@Ay!@SC_2CbGW@Go#`s$&spH)poE_-`BF$8l9%gn7j zdHU&>e*10H6VreB|NP#KN3MV7u0j-}<_nZ$Gx%_8z)^z0Lf`Y5s26c7v`s;W?>JkM?n7Afyu9me_+b+11U-xvhM;WLJrZ!A>D? zMa36HWNs+>>*AyoMj;rQA>qrnu|?LUfIv|%FFkkpnaOOAR?Ik44z3PJlv-!LySbaD zIaE~)vCn-!?_E?_ENf^Y0iMiENlN=}V^}0y3ieh=h*GZ-d@!gddEU;t!Keni zYjJUv9-qa1-OWX)RMGTp7h`1(>yt#`Kz)~3O3VtTbjJdmsW;LgPpBjlR2!|!;zhtSfFZV#zDNdlrjj_AewvE_3j>HtYWpi zvJxtJ=G3!~KJ-X$9Wn3jZjSf1z>s>Cz@WIccDNce-MpL6CiB@eNLXH8tLp)rb55!6 zQ|b%UM`94?dAHN0-4|W=@*n@PANot*{GJ1c*0k%=Z0^Jma@JT$kYYxKnWvOVs2NaR z=5AfA^TRhEx#LZD_M7ux`Un61SAORgclTyD9J<|DPF_8EuDhUWNpf%VWj^@IJ706d z(c>HAohM&-`ohK~7V~Iz%i+tqz}j_~g}d=jW42v(k{Qyz~_>yWzz3pT6$_S{l9oZ`}6e$2LFvsYiO_Q8m1B zd2?%g{^FUlAemm~A9(XC@A~3>kB+V#eBIZ- z{zJd_#b5rDFa3>IzUZ0x=DE+D`=;w`^vY|y-t~jC_U_^Eb@exX$1z!X$xr;V2Y1e% zUB3Rhz6(y|l468u%E^e?9jaYMpIs#g3Au5(CQ22Fgv_OiIVaD#BqXICNNk*;T{ber zu)whvf1DAJNem%SRol`4nyx%M{>?WJ_kw?6Y7ai#>KXAaq3@7-kC7r@MSX=zy<OBc+tT5kqsln)asbBtzhZn)vK-*9-i{>T?Uz4iE~ z$7ddDx1ZLHN7#2*I(UW%NpN$d1PNTicZHGf4qd=y7QT1pB09S(VX>K6*hPto|FndJ zX%R01)Ic?O09p#oiLiQ;u-fE#x0&0XS?@3=4J_sk0 zboU#*ij};)-OS92B^dkLJdg>w6PYCkfg>R(b-!``H$HRuL+g3%HrC+q%D$P*NaTE({Kyjj%LSPWg z7J+CcaPUm<084qY6>omS%A0PVKlbr-=`=W?S#vf>k8TcT3hWMKLl8)W0mRUZ(r;hD zE-6D+uzC%0K)VYz%sZGOhDBGUqVRR01gZGo5m`Qzwl_Vu=o2+H6fj0L@J^|TsH4wk z2!q9I(hM8`M{+cRSi6HNSwNK{IT$E`$LKl3KuzOW5P9*JVL>FosTRPYR!UYW2zob1 zQx8+`?F=49#MwiHW`I#KG{fDE5d+u(c7*MxFG2#bK*&=j3dn}Ys3H=9;Hprgz(^T= zzqHiUgl;|?g>d1@*44comcV5KfWP()uetul>;B0<_~(y5`pm&&CxoD`gJFI6(1|Bb zof>@VL+^k4dzb3Lcs{-M(6N)Jp9xI^F#=MY&HFt~p5|70b^C3%9$7n*t=BAo3q{Q~ zo=;-q)xqYu3(sHKxpMQZH|=asPMuHvz&!wB! zkKKEATZK4~TJHOvXWe0~t{97h2(DS+o%Q5Z@X9l?=j_fz|5Y4mMx) zKR^4~y&oF?`=9!I!z0ZHf9tp3iFf?=ul?aCpZUUCJV7QQ1#(V4Nv_#CAr=k})XeHx zErYqUPTk0ZTdFw{v6?#BP)3eC)!h!Q!!k5=S83d=glnZ9!UryWo2OITBM?(9E(HZ# zI&u~#4&Y8|JrK>+7K*`Qlr6?tCMpFp^ZE43#!jy~o{p#E+0t+@-EPBj^d5V=JCmIW zMG7qathHcZQ8kcD6cHAdu5F3DscJH)YED*~zd{wQ>AhWTwo-EM5wKOieR00le78E(BbZXbZ@M1WuZaq9GR;k)@OZlRK$- z@rhV@C+yF|Fh~f)rGcsCKFJkScU_NdKqo(hY zn@KGxVX`-Gma2d--koN%x(ez!^*Qy40?hMl+J&A&CG&A-P>}VlE(AazXY0FEp33=n zUJnLDKA+Aed((E-4TcRdyIX2KrvxU;a2PSvEcYe>?hYYKu6+-}U}+GgYU*m<&7V8{ z+{tI3I(Omu*|hW>NUVp=(ke5jE;)E+;z|G?Aq;3$jH>yvxJ>$xi&g-^z?g1uloMC{m3tT{?|X&e{?|W#GI{HQvthM z(iEG~p(Dp<)5&Z;S4x)qq;2-T#B^Y(;I;9UXaIo%bETR|jAOG>Uz4h&@%PUVm^7PZEPyfLKAI+BcHaBMD@%G02;B|*mnl?=k;lqax z>7}jd?&fokJyMOTi|4l*=9_N3B8^x7*?%1~Wt4jNq`| zkg_ME2;+X9`ZkJ0fO6N9D3fLF+b)w}&)!L4*~QfT&L)r72k#ty!~0G&k$&{2?%z0f z{=khlPshn&U@lG&>x|fw8W2J=l2D6;)X%g{4xs`U<6yakg94DVkw{a;)pZF~H<|R) zJ+ z)H=6ZiMV^x6a>lBxVI{nfVx*A?$#%Zu?oRdZRS|6>XhxuB(doK8v4z> z;ni(QJpc|IiH96r;v}@8VlAZ0hOgIH=;R`rzw zw_bDOi|d{9GCrNQo=-xWc35`7S)vkuZ;BlpW>Y^`3LL!MkaO(+Fa;#MR z^oty3A*3w2szE?jr-s5h@joDB17(lDQOnYUf$W* z8Bd_lyP0YlOH+LopK}=1G$fm}N z9X{70;sT=H$dLeI33E$WXp07dK+F}!4b{CThZ66fhHSK0(lLmO=dEZWg#l0~S#a9Q zdy_m1xb)EG3lYtXCQkVLrHAa%@Yv3oL>|08&PQ*I#|L5cgr2%8n`7EJJ3F`QlSOED z0hnYkIn%zffFPW;d+_{&C$Bs`ORae#kY`)v(VLII^v)wUK7RGo=Py0BVZE^v3(>+p zSj5%xv^W`^vYCz}0YW`MGk|7K1`z6ixrmCiSLM0GEM<@t#7jy|u z2<+}KM{V7N0FJgOn&(}KBY#Lz591~etA;^z2D+oh&zm_wg?AS|t{ zVwJ*Zm|+2SYH0N_k8o6>$g9D=7kq7zHol`g#Zp{I^<*P zCx%r$AzE4=RIz^1Ew>$6Il48w3=BtAPe?3&pq|z3y(}^+k5@yY&tu0`RQZf z@M~WEs)z6W(x?8sq>y)`nDtTW*8kF>bSczd;IBhulU-VR(|T>xp?ubmhWDTtCu%+ zPCk70)@!d>X$G-A{LBkywj?>iG7pmL6BkaNy7Kf+9w*2W4V817I|8lp+WO$&<@r@C zNJUWBAmXOeygTt(_Fj?d&>XC9`QSs3Ui^u_|I^?0fq(QrU-@f4``iEcxx z(-_7ikt;Zv8|}8eLKWF0=TypCMMO258628CR0L)-bN8Hk5hgBhB&Zt; za-UU`5ebWyPXeN>N=D37{ElQ0;RO@LRBaJ9GjrO%DHd3av%?IG@|G}nVpdgkV}fcX z5EWYczG<*G)q|`|jV2ngyGV_ulidAF|S(O4a zvjkC93KHwOs%vHnG1P-*Fd8;ZQ&klKy(bbb3D{CM>uMYbwgA1r3;%z?b|Auh*0M;| zgq$>IjZu8R+m0CkR1H+1l`g_63Q$fOYR+oxBm!bieP;DCmzGHvGpRy(hx8vSDhajPevvIOQ z2NKG?av;r?``j!wv-vbxp3SE1Y+em2so7>(6)aFq1a^l6(QJL!i?BqgD1_l)*oy79kjS&vnt z-jjPt-P z9gOB}@A$f}efPT#t{j(U@JGM<$IqU8W_x=)OR1gPfdlKKVRhYYCzcPV%NMqXOZD>7 zfZcP~S)OiQzPx?8dB=O+`K{mhO|N*_OWNI>(4Bhbx!?cgPd)a~!zZ78=E*1d&pxs{ zYj*)-4&qux9u5KwrfE9g-I=yN?N8xBAV-Qsl-+?K3@yURK8KEeaOO}h z*;pu>p#2~{Xi@W6oD(1{MBVZZrIKJr0ppeQ+CrB#BUL8}#7wqe zeFH|!nmcBrQ2Mt5k)9{>6&8(%Z}mILql`eQ$DulTW_zW2(r&mFks`dMdr zQAu20AHo#a8-lY$0x?Ibn>;tBAXP2k-1npeGGaGawjO;45rjZ7usGBqTpA)s$U}{~ z@ugKCM9g|HW4r60Z_mB5Q6}V!-7SctpFyXD)~9pi1Y~rkiDj?~7PtU4F{D~qS-l?J zp3UdIv*sB?oB|bTKy~4UWPz!Z6^$L_i#-EM`h$`h1tMczj1TNkEk=VPJ!WHY#DZ4` z7AAHBSV-6;OiHh>dsYce6|2fpJD;>GJ5$OXVhDq(3TzyE7G`&1av^mgu31V-M1+H? z>ZG0QDrKh3tT2^;)RUSZEYV;IY0kc#Cp)M9{LjM9^I`Y&nr(HY9rsSU2&9>VoGB2K znwvW<$cg}gos5b%wuFGliKrxm7-R(nTpF7kfM+e~8p|0JC>}(0U0lAERPyu;=>AV zkXp?Rv8Wnb{ciJ08YOoc_w%B7(EL0oJd<}eS; z-$}wxZ=KofH^@t3uIx(OOLq?&%)N}OM$WvSa40e85_l*$sDghFBtv*~&X53gitc;Q zroHpJdK0hR$k*Q$hC|(IyoZyMkSB)-$kFwvD==VI=qoTsA`n3{QYY7+kWtk8or0hu z?=pHtsGu1{RM(yeRRxOO_O_?aQ;{(%^z4x-);WF2eL`Kq-FxN1pgFW`>|NUPdGAVK8Z;5DYnQ1S z?6vbQt5i{#2Qt_}e&D`GKJdMK$31s^=HvJ6?v91atD20hj#a1zAO8GjUwX$&zWM#% z{PE9xV%qI|%~!wY+rR6ZufOJ+(bDkxo3DTF{xcu_<4<05^D(9FP49U1pMCc3kAC)K zh2^!;QZ?|F=Z~Fx_~Fy{XHDR+wReSGvd*5o{P1gD_Z@>X&-}07`ps)^xv5XP5M{7w zZ=iV>gf7jhFvz(EPSeDj@ z^GVlFd@xuZk7u9!qtE=%&wShazv0cl{lO1q%~z(|YP_-2Z_m%X@`me{YP{m6+dhBx ziH&wEAda}+)yZYuG1!2X<~ENM1UP^LH-wwE^Ei3md2%KrO`3!fEO%(<-U>wrlIMyB zEA_2kICb{B{?pHW;Fa&c>(y`iu_Mc;PMyF1;=O14i>u+<?p5;6MZ zN!_#OibcT5iz^@M89??-=u7lekpl&Fb)uSUb4}Jd5&+6b-ZH@u%vcIp0Tj4)ugo(+ ze1G-oa7I`pL45zxic&yLKn29}SI-Q6DM;9~z4I3?EnjmKRcOaEwLa(EjFvp3>$)%q zxmOBKi>guTW_{bvNN8y^vgFwnfR{2iLvFKFY?@P_C~`BXHK`FKO3qr0KQTmycU>Q= z0D`K!nFvXc5(FuUvy#OHhy`Y*YRp6ghJ#^lo{SjeWJX%{hx;a5CAdR`%SQtd!Q9j& zNYQDD+0;V}S=B(*u#(6COnp9YbDt@&lY1s)1(-CMxVeQWC1P9E6^IN_1IHL*h*f0f zst$GCgcw2yv5syQs#r0@OtV&lI;Wh?0bgoA{jmgiHg2Nf~3 zvknfa*qx@6c{7L-WIAcpy&2VAmuJ%yGCMq_Y}sQSSTJw3?{Z9;gsro#>m{XG%~+E6%@310)n7_<~`5P5<`9$YuVRea%Xhw;L*b;_b#8_J#)3+a|9Q4ov+dHZ+OdlZoKxo$6k2i(UVW?&c>mN!=+); zl+4Go?uHY`?l^jDcWL&_)}!w{`nsR`fq(s>hd%iCpZpnm1)831;E5o3fM&$-m@m;Oav2aQwQMi`nBKlw|?aP?|pZk zc3*t(q2K#IfAZYf%aFV@7&(XK!|V0T`X2Mm$@v8zHq4;#tM}ab>Kku9dh*GWzxF?V<>aG}U%33tc(T>bQs1}BgLR_7Zfm0zse&p87SC!q zwP~W>C!RAiISkoJlR2CS(LK?^##=II{1qXi94IWz>>vm;!~uer6^*Hah@!KTnUO1? z`}(St+vt}?)kPj{fnQo={q~8TrT&Jc1TR45T5S5{P9$LQf-B)r_;F6`CV;DT=u?o$ zENUs|A`2PZ`!rYShxO{!{^?)1|KGml=D+mnSHJ4QbK~~P-rX;|qg$8ulW{l7C$F3u zeDdSpa`f2n<{P>*I~V@P!w36Y4}9Bo@BD^i|G9eQPyWn9XD?h_zV7(WUM?CtF*G}Y zf`qI&bv-i!W?6|C5+&B`&Y4q}Rjrg_Ks8PF@_b${TMz*eETec-Bq9bZk6eMiLjX-% z?|Ofsowemt$9y~mWzY=$p5-}mi@pb1h*4(OsVloMT*g7lCC{Ah7p2lWXA6r^F#f0URkA5m%tL z(>hdK0yK{0SRWV+Rwa0=&fL$kZBIEX>ROtbNi>-nx?bG~>TFmW4vpj0WI0>PaHxAy z>s?@QbvH-ugYkd|>mrfM!yBJ?Z_n5$|nJdkkJogCusW`W7~O$w|^pbSJ15hpiti^K{t zQxG{pKxXb_LW}leGh3?gy1PyszV_hSpP$@8-z%Sz5eEbltO>_d`u}{agvu|cD zFkxW?E9o*)fE^4DB|rfu19{-gNSY{6DJe47Y^gI92sm$J`x(B}E56V^(Peqf>K!*7 zzV?RsEnk{HJF~qS&0Y1aFI~EABW-_a{Pe}V?L=VaATT3PsDirgTiD>)_R{#n&)xUT z*7x}_%-WPzGn8Ya+7g@2YVqekm{mll-If6w6LQ$O&D#Qj7pc!xkfjPwr$e5hc zy|cFS3|4L+1dmIUXP``h+#Jkcf+eVe7G$`hzLF5Y-tA4EJMAf>G){$x$cuT87{-VV zu}~GQ%X#xE08|wm2oVqp?0u#|gCyQ%s+nTtU4muA27L=57|=u-3_Uxgj2Nh?Tm>Ac zsSs#6ok0oW(%mPplodqGo}TARYuE@O1p`hmKPF+VYpIZ-XSL$hBo(#TyaA# zbsd)Cf#3Vh-}}H{|BmR(8j` z|K$Jvx$pbGzPB2M?bCbb&z^by@#h};(i2ZU{_N?CXSR2?Z++2=ZaHz|N4y@y!Lfr! zFON4qdhe%CZa6P*2ojkeerdz)B^!+DpyXB3qdh2H&_>+3D*3HWv z0sx-deCp)o$F4hi>-mjyBGo58^Ti9#jov?@fKbwz?8Ta;NNQ*4EU>6?r*7 ze*c+MPw#&F-+J{Q{ow~M>2oLewkp)yx|e1+dwJ=a>y{6WRu5GNrn631M9s%9fb2tt5n-TxqQC*+(pD-$6|xe*gljDbMH zGFovGrd^qhr*2wF#Vo`r5PU{(je#k!+JfFhplrs%u?o$grhpKnu!3V%g&@qtBupGC z&M6U*s)~rJQpJ?jL1s?yQmEtZ#86d-6(oaZtLorIxbBt6i$k~|5X_898pWVlV;u=R z*_)15hCnx;cFnNqx>iEyQwG7YU|tflsivIER(mvRM5^)5csiNKD4~k;S;rwjyqoj{ z4^5C>cDDA0T~iHfsW^3JImar@b3dERNvNvhcxTf0sOne{Unwcva@Ice05oZ+16qQJ zW)CF#P9`xjBZipz>2xxF)jhBH@gM!6uYKRw z)Etp=O1Amb)$Qjux%0Jy2iDiup*%a^)y(lo&9V?KOx?OfqpFg4=2ss6um9vS9}!=+K(L;&cm5*a5= zd%Bx;o;ZL1O-o1r(bxa%{ip8z?hpQ8M^y93I0IHyHDKkonLd)ZMV(mzO}pi$q)VU(@%ft z>gMyiyW3_72#heOM(d+B5pkfZ>XdSy+MKl~>bseFo4qIG;&v>AeF77SEgG!}R>!c! z0ll`WSt<#k0R&8HMqUzn#ze%Gxl3SIfLKgTm4$)?%}%VETFr^r32K_099H~Y`;phh z1BNfJ|MsJCY?hQ%I2NK0(^pc1#11BRSF<8h<(y-+G#s6nPp{^77hrgAo|zZjJb*I@ zmNQMNIGFWUKJ@G_U2M<1;>df?K7a0y{%rP&8*U!fqmIZqe(wCq8$WU18&(dlzUKPw z&&SXG{Ab$Bcb@oL_q^%rulbpj|L)H{w!1MLtsR-RnPW0nH{&2?PNrZpH`C; z#IkVS6hS2r2+#t_A!j3mxW4Y5+l_6mYBWtj5@J3_MCcloCk|Rbb)V&WM?cKaR^z!ODt5xRin0A_+~TX4yOnM~cW`#cI_Yj)Nn0II+}J zDF;nNVi0g78F_8IG>|~(Eon}wgcwO;6<0?qbI|2HQ6?p1QxXV~GP06M&2`0y$Q4mT zp3% z3ur0=$vUL*)W>E;s>9ySynRIH8rC~|L3WoslLz=+B-uBHUQ5JOc}u~kPR zW~>Z(5CNDGXHKR7Nkn;$7aiIQoKzXo_eDaY0t@$A!ok6)-VH#%NDY*bHfidw5;JoE zfzL`?x>7ohDCReDeD7!R@r$LkV$!!Clo2-*V{nigW+0g_57*wus2r2LCz0w5svKU9)3EYEY{wIuO^HCmKv}`m zi~@3Ua&TyK%J5QNlyW|@dfn-br~c7T{y)F`Yrpue_r2vm{ImZShr=q?^KRx!3P>gE zhYmgbz5J^I*FANr$D ze(|#p_neL_A033|=@(9Y@}bkuZk$pimeTd-prFYC8qdd*fHI6)wALt>83domPQ8lzd2 z7%<$}$iIgNKeqeOYeu(z&22A#%eTJa@zYO#NV(6N6zpyWEuX^xk(bR-fP48nl#3IS6#r=N${Ylurho+IMdAVwlzMh8(Takm zGe=-q{0=WmRB;!fFzu$QS)6vTGoktJbnoJYtA~#ss3lByr}a{-)(4%Ly)S9Q6x&Jq^_cnkZ@JS z(oaLdi#{A;0K9KgJ%~imY(&)eIYgmF^aTapm$JHBfF#dQ%4+qX(roidON6o`$l1z( zm%2oO9q#7stQ`yov57mIdrPYWjx?LiLkR7xGq~*=#?0KZni&h_q%h1U^QsOjt4p)V ze7rYlmIe}Jyfc%E+jc%3&)1GD#af7H^UBWBfl*b5zO}APY{Y`xW4^96H!E&Cc%5m+rs!p-1oE*}bX; zHzyHBsGB7U^=Nr%FdXJC?d@!}ZGYh4k>S$H?)FA%TVk#UD^;`166VwG*<{Dn>*10F zww!WG4kwPndAz%^JY4>p-}AlS{{tVm<0W@!*Z1SD+fJ7ry*$4#8AVw?x;k84nO(_J zp;@baZa!D4qo#~(2CG*_>D1mY|KvaU{XhQAqjvbtTVDLdt*5_m`RO@3SCv`H-Ta#2 ziNE%~zk2Jjn?L%cFFbPk(cZejU?`Q4NZWRSP?7BI%~);ChG#E4Q+fX{-t@DV_~N(y z*0*oG6nQ7`DPYa_n$m@ayl6sBsR^UX<{8`lQbRAq!LfGw6qcgSI%5` z^yGz=we@fL_HTae%U*TuwFe&j{Jo$2*q`42@PnH>=l6Clm?r?jb(BUz6{Lw$n~|wz zHK5Bmsk^z6n|kNSK);YElyy-UkO5;1qbyf(EmkWo!Kp_oY#2zaVB};HU|Cb&g4qzD z2vyBenG@h#Qvgyw&qjbSGgmc*?4}|FGP7*CcTaBFOx-e-$E{dZ7Wk1x4;L1~Z3_@s z2uuiz%z|ftiNqJDl*80gt0cqKV=bg>cbN?2S-ZgOa8qL@I8thbeHf8)d;bf+zqNgC zsK?GfRIStCuIq02&_fT%a&s&me(Kcu8^3hw+SlE3@TIpV`1#*@)Mov)Km4k29Y@Q*3YuA+E%%Os-rtA)q;9aNM^_T==)eI+iAm)XV8iYcyWB^&; zBap1Dhl;&3@13mo?dd|OP*ALq%ua3QQ`gfiKyN-zG%zIdq$Gp{xDk^fNHYp(`gUf0 zPi~eAw>d%JQp1q%5+0NSd|GHEEmnwsm@mY+8Bt+)8vOsCy#L z83UF9^VCsni$tuTMO`AfyB0AIAfbhvybqi;x9r?ADmN`Dpi&@&a%_?y90)6SNnFl* zXFYA_`SX@`q0_+o#oipUDG1C#h}jr!fl8Fe0V}yvGE-<^rv=xx*tgwH19K$GUF!%D zq-LdkEjmOX%}j9SVTo`vQLJo@Ex7C8p;KZ99D*K1_wxl6D*;3u%RT17eqL6 zVuV0s=sLHFtlvzL(#0phphiIANx_VY0E0S0;h{6sQGtT{WDC_AuDPDq588z@m~21@ zU}8cLa`CJ*s38%tfe}UaJ^>7gWjlu6Xjn^A>$r0!3IZng9tAbbHT4<2GnrHY=0pLb zie+FL%{cGOlJ21$BiPzuqZ{ZA@@_N6(M* z$#eac%{{bzSgJ!M(y+u(IHpcy1{w{~c0fWU3ry6ofo7B82;lzM9h;rgSufB4To@khV^CvSfHJ3jW2KRJzJjprVD^6&oaPds_T0+%nQqMYUUkns$F4atZ@Wvo zmqUYtqvflcS3mXGCtI5}gSw(P@8=AHuu}>Dvy*SP+sTiPhNGvSec~No|F(C(^J_o+ zu|HT^UEdq;mPJ@re}41nb61`@apc-FSI_Uw#~=RaC;!Ixy#H-q_wrx*55LuGXYL#< zJI1?ng-*LRR5Ds`9=P}6hwuODzw*6r`@4VVUyWrW@DdBn+iq9s($1v_C*g_(<~?-J zXDgw)Gu(8sy*!7$qP}Ad>rd>RzG7P$32cU(-D|3aLLe?mk(&~HKsC6mUZ}H9I2`1I ziahhdY?nT=d+DLwkKep>@J*|C{LmY}Z!=!`^iyB_+_?uI%@29!tKrBoJ`%ZVc$fkp z7U0GN(wT^b z&0Hi9NTE`TW{~i3RCDCXF3)FkVq!54A?4nQ3KzlQD5j&pRb9n85|IRsF@z}0QiWK> z7$Y+?3A-6wBuGj1mM&R0<4P=9&Zw%Gx)kf+hHR>?1X4973Q>5X2o+Qcn(Mf>1l}`?hVPj7Fo; z(x~m*R;``oVCpytGs|absia;RnxNynNxzh0`0GmokXMP~c1)V+Cne z*AF$#&{CdF_vX`asOlT8y*Y5bapnAcvd0|j!SY~fHK#P*-qbX$su-#vM@ij8bIZ&j ziskWmy7#J=zy9z2*xz~A*S%xqz_O0}jpsME&W$IhXFR3@Ys-TnQx5a3mg>454k-6& ztM}nhmc;rLmWDy`)PMQ-&;PT3ar%X4-+b#=)9T=lpZ)Zs)3c~5Q*GyChP>l7Z~fMH zedC1}Hh$wHe|T|wLnN#$56rD?lbP0aJ&a*G9$TAUcHK*k*x=&Ti+|^>|8V*E@;CnG z2QGDctIfJ16LZDlYNbvVj1VG=XUkpJnkIrdnQ8YIp+R2>c@_YX8!<@OCrwJJi6e-m)VijWW=yUy za>S|zq3=79pxMX~syYPe+L>F2oH#adFiQPgGh#h-v%=jbL11MuQ#I>NduZ0&EqZil z(F;Z-i>vTLA%S~#cSj-;fQc$1S-6Q^9TtL^&E|U-V_X61SgnM>Ik$bkn^i@qz*80* zJU8>M3Q-j2_Z}S4fmOQZ%-*rL-+0UGkKMi3ZryY1&7(_$t7py~zIHj>e(d-+zhwF8 zgWC_DzWVDAAO603-uKsTzjSK;&;RK0mAhZsNifePqAN_yAuB9+@IdZKGt4x#=0t83 zDv?0snvFO(F+f~Lz)f=6*^TT+@497jVQcTHGo(G0u9Q+?oE)uUJNT9CHwo1d5kQ6z zxe$kvD1>E_s$M$M#C6*`pXa-azFd@{Cp+6X< z)7jN?mtRPlIRKH_0aR5zAS2=_fh36aYF30Su7ua?X4cM=GuVYGs|Ar5LUf^I#0V0W zN23aHoYExE2iXrbVY!w_lEJn$_byQo5LwQi9VT^C4XidA#aQ=bbNB4A84NX&QJ8i! zW2U%F@nC3Hb2s*Ghx^Mh?Yi|$2FeIn_%DiHUFuxPg(MKGDx(DQ zjHw`-X(6-{S0n~0X;+4mdt^jHC8z?`To^2r%_^cnlpvI{d*Ditnc6;!dLT~lE@daH zBUYMC0FUQ0Hz0Gx z>qa?SD%LM|lwx9l+%1`>n=OSWmtuXD^x` z&$YFrfF$in!;PbBU)|hvVSMpacX@+mXLYk9HHNA(2?tX4WE~lK>26fBLVa^S_h zyX)-+IKl{(5ZrTu2t30HX3hd4SB5LCF(l&n^?vXOc6Tt@MK&-YMo)kUICv5oE~8n- zy!D(B3x&8~?1*AOHE<3X38|wt(MF$73zJ2}f z8?Sxwje~2Ch6C$WQ*#|C25N%rZ(o)Gq~v|_R(;a>l`D4cygqVr_Q}WQfBw`)D~=`( z)`gd%QJ@wMP{RnpJEfZ40}Mpsl%a`+l~Zsts%ki_%V38yh7szX91>8~foYLYQgkUR zKonB1Fz<4|w!B_nx%wNw`g?DA!<*jv);Ipw|L|*44XbKEJ#S5}p1*YFwi|B!xu5$- zH{Ws7Z~n%Y-umV@ziaR{_kQt_&p!GE)0TMk!Bh7?d+w<_Zo2cD6USEvgUgq$1eRC5 z^kuX8-h+?bKhNW4G^`}%5-%wuL~=KqOs9L3$#n;hJ$?UE_kI5J?|sKR{_G?Fr)xW= zkaCV-W*+CAlUE+S;n?kKqt)GZ@8qM;f9j(T-1COpSAS{g;`xh*4<8-x?s=w^bv&MD z(`Gf+v6^kRANr#Ye%}v%`;o!HXWM6P;k&Q)TSU}Q)q5Yg8tW`*2vkj}zob`>VEJ9w zzT(K*OD{e@u6gj(`20zGp+!%Gh)KxzvX>zefJA`{xeVA_n9mAKZeJF@tRzJh>k?7TqQ^q zJ-YDHKwLFj-&@yvGNj}kEi%nU3qCg&z?O0SKBM*dlPbtF47tGwz;`AZugp%k#@!vhY3i761PmM#Qn(tYfT=Bx$UPE171L^&lhBPLxe z?j&^?L?Wz7LlwzFg_7c6q1+n_#VX`%mP{%EdFr*eSVSl#n{LmhllgFI z5Gbhi5@c^@QV*+8%Vck2s@13(E)RCMcITV(v^&+Pgp9T={SMuSMKy>Fe_IdI+j zq3edT%ahdh&8vnzsjVM<@RL9E zRe$ZyJMaGX|MlY!k58@F2Yc_;EJzR%bEi;;SUh&#&gWe}%a-?1l^OeNp)b#@w77v3 zn1(a41fF*jQ@j28JAdr&{p8zT|J6@E{`@ce!mmF1)XDMg930jUADB5qQr4?p$kkDh$tslA=O5NWuyl2Yjx z;1EGfQ36!6=eFH5GcJ2&kszG1C+*8r9m7&xEiszFqm(HG8B`3{zDvSQN;2M=Wu0U3f@SAW!>DgN*JNGmuvj&t6e^f9D?EB(3%jZ%;);CM z&HJieB9XS!rPXVPbZB?$`D{6|6a!p=)Ma%ijTDGTF`e_(&p-G1(R}`vTkp){&1P4Y zUx>^iP&dIWhh%2)M%L#C);9$>QbQ*`prIoZd(Ve}#xsAyL?X*NZ;6!zV zlJ%M0F*Tc-gutUF6C)FGAQ4XtNa@uAa-Qz>5m9Q7LrrtALltVU1XdPnbDmFUF^t@M zAhW5Nb}RV~#r2BO&NU~Nu8B+vHR`DU75@w``Q=af@{3<*IE<`N`jojC@ssz&C_ zg&*S!7`~aA78(y6rp`jb!J*l*L*ZVUhuphGFG?o!iOoWe!Qu>&zrmT zm)YmcUM4S76$<7KS0>M<#ZzEpXA@01v9ueB!NYE%q^XwD8$<`+!7JQ3E2Uv2zfsWw~%K8iIA{+ zSOAt-Kmvd$2v-DH`<@ry^6fwI?rK!M^}{Fs^KXClsU39>6j;m&Zi*^U$DvazJB{S- zAa&<`P$j+$NiU97ctMzvNFau@;me+A1GBjqYlpcfP40tu;K=bC)w^?-p6=6_q*%h3 zK_rW2!i7J&fRh&%9|18tLqHX|!gY}+Ejuq~>$$yXSGH*K`22k6to4*B6Qfgu#XIHZ zqgbx2xkTd)OnS*gTw5HVYLj-cj7U~+N(>V466(Y8poB0AgCG@|ISFNEk03Ei2#UhY zA`}C%t5aYS@kAsH5zh%s(1nAXh+zbGsskL}c5>~te(gQ!?EOTHL4&Lm+@~{WLe0oP zRv4iQkVr7{36lG{lde5n5i0-?hg3vFfn6Qus4E#RWd*cDAPSXdlzk`m<#j8sxPA1>uNvKWtU9n7)|VnNFbC#n zuex?Vo%wb$GpZUQLkOVkxwq{NW0AXVuU_?Lyz_N~@7U;1J-`0Zhx!lRyZhwko~zNy za=kV}6wm5?GV3f7B#^mhC3SCrVWiA(1{)Ee$w8e&=HwvyRlxo;@Ri@A%g5{DHsy*IxRv7hgEH`S!p3 z{=dAmM17vN<3IW6$N%|1|5q0_PBqQ)_H66Er@nAu^ThE($1h#Ee8Y9u{KQZF@Leyz z^W>Ay{K9|yZ@>Bn|8umwL@H)!|Gi1X5`^2_kA|bb^w47ue9xP|@6|7T%>$3#AFE-? z$=KQ1ke}Z=d3pQn^~aB28DE*~wtx1)PrUxkf9I~3-uB=lj~&0}gsS#^a(4<=D##@G zXl?M+sb?nh{Py?1`qzKsBi9XYAMcG<`9Q^FW}VLtS8D?qUTrTadL!G?*`piJeg7@* zy7SoaU;EetkK6M-b>>Q(pa6M=N)VH$$_9~Yp^)8$IceLWH7I#3oT0g!p@*hrIvQ-b zp_;1Lo1WPjU&iDU+xMTi>@N-1y!X2I{`FUX>$&diXP)}fC(eHHBp$7KY2eGNwk8q`)@<3ln2H!|P=LUp ztPUZSkP;g#TZkc4%;Q-*>p?yUb;^NFnK|WLg^B}*APx(GLlhA%*wVVLVjVTJWAgy7dnZXsS`+| zwBydq221sLXEGhnVimLI@{uYrA{8NpVho+7oHN0R-5oi(=0r>sr0dh<(lo{@R-qX+ zL$m34#zGv?r7rEMS#E|^-}U3YX$a&F3UJ4GGGQW#5&|=mF&V7DbW)$B=8A$U)UsM$ zU0z{jV?A@`g~y(J@`dxyPNut{YPfn}G^|IYxC z+Bm44{mP{ashy|XEv>CPqV{Pv-A(P>fWc^qK&hXY?ujH2llARve)}DF{mf7Q)YrZH zYgbm6(fJFHo_^+Y&(AN<)+Ks)(#C<*P3o)M>P+wSq{gW`sm0n z&OiKbfBCn5<$w94ealN;(*^pYQ(wIA$}=OA zrUd6Gbu$=9U>Mv~$=clJG;7jyQZ%csxu^YqeJ-u?E! z_U*5F{Y&;X`_F#*v%m3Mzxv#nr_P?ekUGSHtQ7_P*q+ z2!SZnXo&X{Uhd36SO8X2)v2qPl9>`@P_GP^POz+0qdMnak*3p)Zob>6iIYP@GaN~X z5-N_v+|T;yjzlJsDh_xwB<3`4VX6j}sFwP6milw5sj8!}WL3+VgH%HtToBfrKp8F!O_40V^;L7SXH=MZg(C(GfoAm)F zwp@we(WPdv{>1tDM(??j!P0Or z7|y$Vac_Ka+-|getLmU$74RV3s%3a5(uc?p@j&}=bD~fRMQK6YH$k8h4}~v8GT9%V z2qkXmUl|qw@&#y^7LG7tA_RA15mUG^OG8q7fstDZ`_t*-XJ6>6iwU+!=LM4Wu zG7kdk-Zl*;6wHj7)m?}pNeS>X?e8nx!5ozaAI)NUwz$Q*Zgn)$EVMA zs6%DQ6_fV4hm?EvJSB$*roOc05!_A79dJ=iut>TV7dn9m1!3jId*=Idcy{e2WwNBb zD__~ZSk*Og1hFraZE`}G{<=E z6O>u*}Q;aRzOa^vcbUUJx>>hQ~k*PoePe4@KZE-9!pJS8@% zZ8)3dFI_s>Nq^CHr^rs^N`Xg*mTwH)Y>ZELy5qhz2_d2Jyau9 z6%l(jw?K7-1oS;9dv@!b>LEIHg-ak|ij^k@Vm%s+RtNpudQ~1oVWL*0ZctTu-1e6? zk*C8EzwWlfuetsDSH66B+YRB+S~##0ssJR+FXDkuw$DE^-@MwnN1G$f(|C8HV6)H+ z8|%_&sa{_h96B&KcpOb_UwF9ZMvq)u-T3l&^J}VCzI626?^}A|^wCc}F#nTh`-jhV z7}C;O&BMAUNvf`1daqDdAoET!tfh)RoqKAXn1sOW$y|u5hzj#wrs!a5Al!E2O#|jr&z(Mc^qQ}J?K{5v`@Z38zV_8CYoo`{Y=7#>@lz+acg{cA zT|Kv2&))jBm;T}}{>s1jXaDe1U;Ox>UecV-T|P6OjOWw#;L#wCVFtY-?QiC9G9 zR(tiSOOL+(j(02%MthU?^Y=b-_W6z1z3ZNje&Vy+JG)?-&)b|lE=eADnm7z(Fc@rH z+PL?#54`8w-tepc`%iXt3mjUXRi+tfiB?WD2L*I#?k&0@1`~8o%q~84=Hj81!9)4E zU79guj#kYZsu-+pfK_M)JPK4h!K`g9&21LhBSfJy@5rlwdI?L0u*!$3FlrTTPQYM2 ztSZf?dF%P@@iVym!O07^oE^PxaMQP5_r7oVs<(agvHL!A;ek^)bqUY+m@nzU0all= z%3enw1q@?shBQLR!;muiHqFes>>W7u){%ou-2jA&EB8X&CxWTj!Wx9k6o3U5-`tAb zr9jilL}y5#MI!=`FKnH?oX-HTXerJ2CfnEeb=r6BWEx|&vT~rRt9hGpvKYx>{k*U1 znwWE^=6NnQo6Wc;VM(n9p`26S_n{7IjxG_vf!xeH1{nlotes|605MjY)Zip!y^FAU zcGW`hCni_xx=aF*kk!>ym~{VUNb14>7}=OhQ#YBJJE>dwfB=b`_c`ajcOqdiE1~@b zuHUkv05(mHG}OV(E2`?O2IOq6TE`%!rY2FSIFOh_h#`=fK{!^SiWP&2Sy)Qhgt@0a zS9JuS*^G^uRCC)=RY#p?0I{z6HigLAD+{?%?u-Muc{k52&Vr@orSaZmGMNPy5lUSu zR%aF|!fdGHbZ=TWDj`hw=A+f&Y-e5%Ywc6t_9SfCXX7?BVK8dic{iVQF|q@iT$2{s zM%hTryLK|wIGwGmFOOE1b~biFCP8AwIa}9tA@Y3E%_kaaGBpr`y-!JJCV@Bz30Z4a zAR`rPvec()SdHpoYSWd=mrp%=>dfV{+k2PiT>>Q3E6reKY3&dYbKjPePm{vEu19rU zT{`#7&eba^chzv@j@-3fyJ-}U9=o|24R$s!wxytzsIEqg*r&N!PjCs;j>iCh;Jd%? zNB{N@-+9*^#L{lhp8Vu9&)&??!?|A7C|KRt0{dav^yR-Lm zKlQJ^aPPy14<2jcpi7;3o7Hmm7zD1-W4ANb&8_c#{d<=~^N&9AUj{mO@A3Ei!TC@B z$;Ky-434_9CmYmFtZI?qaAs>Y&AQpNoxroZGKue#wNc==z`h1hIH3q4BHX5~Z_|kb z*ZrLz{Ri)S$J_3^_mQ9ZxqtKgg$paAW;9qEEDf@na;};fP?1Pg*Ws@!=bHh^)J^Nq&!!La1v!6YC{+aEa&1NtPR1cRLmdNbQpe9CE%_+6*q))S~ zGcRi7;s+N|sLMwCfdO-aS#PQ9rvzb&R4&QpA~NZA=V?3~95P-eRH#C1>TH7mL(rU4 zH{W&jI2gpi@~}P<;!@XcPxiL!Du>2my3`8oJ3PScyJw+N4*xU)4vrFV*T~GR*kDPztyc~PiHFqC9 zbmGVzhjz|(&ph_rwUhb5qem}X*gN?0gLEvmkB;fh^^4zp&3Ap%){p(t3rlysv;~yWY~$x9OB@+yXhFgg-$zj1izh1Awd7Da<6UWoslMU5h)-ABDku%Lx>1D8-tX!GtH$! zxdf?DuKxw3$ctY&fnb^!!zC35IshhFZB}m|tlzAj98*%8Z9bYNXRO}}NHK`270$zc zr*Ux=k{25>A-f5cP^Fc~2C#rZFv>o|&6G%(p{7D2Tm&@;T$pMyGINEiGNBGEgc{Gdn)lp(=MTJp@2QRXKm47n!G?7f-kZ-Z?#(vZeow9Uf+VtH0VtBbfyQ&Y zywlBLk)ykr=RhI56NF*K-YFD{uPG%@ZjK_cn!yOv=bSs^g*6uYiPUn0YRMBZ0Fnjk z+apQfFmf~;s@%1YeD**6>8&q1dgQ%tc<~$WyyFv3TzzJ<%{V@)?>>GY z7@pbQdvbTKATDiB?q3<(7j9U$(i=;pmdn1W2%`H#syI+;UmV0NOq6|YDdH8_%A7c6s*TGq!yxPZ3BEhgL1+(DVG+es4~> z4d#(S1a%J~jE*dY1JgX~CNn4z3)nn6aRk*&4G_Sg^ujMR&qYVKp^&OLzzQ_mZn$;u zwQs1;Jo2&^u6zt$0ZJwgp(c2rK#pOB7$^e|O=+pcbeg0aC*=aqwa-julC; z3=hI}&^#vwLg0EpL9AjP)h5)r&-Z4YVi;AmL^n_4NxQRCRs9?8sK54A$6kN;=-T6h z18ako0rgjHcEL|S(Cv=t!gF@!?Cgaz)4k2aH8(4mY>a2KIkUxK+}mpVHV;-~sA;l0 zUmcBJ^Xi+w`m2{I$YY<~o$gKVe%0zNcZ6dv;yZ4Rcf2va?$yorjP;49^uK>@^7~)d zq$)HAmvSwbD@eI!RHR*o2}f~JC-bZjN5xdOVO4Nh6edkug@mf93U#))Hq_zf#IA;B zxODc?=5PMOAAHj{z2_Uh^&4OJp7*}~&3C`#CD$K5wt8Ww`;AY$@QFvqr=DwfH|IX1 zbVa8ZAOGOTKk`?;>0ST$XaDuT{kK2&`+xd7O|xWb)4W5KT)cYm*M9XkuUy@H{=&sy z{O|wypZ$k_x;fwdm0$g(mDTl>i|2%blpUw^DJ>0_+FAR_FMQ&sfA*)}{g!us_%k1A z;xJnQu(E3V!q&5Q&R%x>=&?)NTNlr7f8rCL{mb9+_G^wFIe+f#O*h`Kx9i#|dIOuP zTAM{gOdfjhk+;9|t8Y7a!{zNWH`gz+K4s7nty~k19bG=S+m0iJng*@S8>(uqpV``a z;?iu6S%ZO6&rSj<@45=j5G#k8L!quWC)+b?d+WidX<**BJ{9ngRu42s2WSQ|>dhI$ zlnI{INjNG9Ry8;vajC;zPLt1Fz3@@of8E*PPu}%6|NdY5fv3-IeB?{_Keu)2%;fpY z{khXPvxN%;ALR9#Rz|*3`LK~DQe=^)S`r$Wr%at#Ye-3_ksJ0X9J8uZ*_0*`A#k!D zB)kY5s6tE1Ma`8|C;)EAhH|0QvJ$*9KG*8r9G%7d@KX;>x5jtf@e(tQbzD0*s#iuP z*8l&w`tNwnuB*NuUuExe&QounJ6(0uZON8wxyTKSI~Ze1Vp`~!VABaE)DT)i$TtOI z0uH1BG1vr*aWArES(0T-Rvpb~`pms^`@K&)=j^@LTE9QeGs5}JYyO#e-I>>O%d^j3 z>+|`%KTL#8r~GsunCeuGOQpo#BVd;2O<*EMk(f-45Fwe6InRV-qA^C!DRa3<3S|U< zqLYJa5}oF2ld`8qFI8=_u_iGZD6?zOK@AdF%sg|G>O^dcw?U@3MKCiF!6tgDR+m9d zRT56mW5OitoQbNLih{wEn?S&ZZ~cb2Sk^9Fa-qX91(hU zS;kD1XBk*Sl~Q(%|Egg)m?<(7fTa{w)x^wEU=s!F75IM-J{Aj;j=E@AFv42ENFI zl1$9nGyQs8uAV=Y!dQ%E7Y;5SJXB4pwF~F7cK^t++Z^{UoqcLD*a8&**X_@e%d1I= zDtVTxR>R@w>T7QNADgQm-g)2e{F}f3==-l)IPl6>z2@1q)ek-PkyDe)W2;5N0u?{< z-QV@kf95Cl@7wVVzNXvn4M*eAI21*eLaZxwZSJ?bTbnz(D=RX8zUv+D_?B;c%iP?|y`R1JkN)%TKJ?^+moBX-WUW@# zZuiJ#g>Mx_8=>iLszNmxmBYFoi!~|GuMO5tZ%qKGnh>T9g9r`Sv{3;dU4fhsP;A~5 zussQ47xUej{oL~9WTIiOu7;@|*OQ@h?Yz6#n?IblXToF*z%FZ3yffIFlK%af>SijI)HCt^)T zY`)Nxf=Lt!8Y{ILrp}56%7b8{C`kfxPMjm4K|o{%2FJuGRRl1Pgg^ofArDYYux93f zcv3Hg3#D=PO)q_o&*sj3{^`{X=Tp||w49&UQuMwpx~fN4=U@MZ!*Bff&i}o***ZEK zCL^M$f4OOtMRkCN4Ym&%!~oP{v^wQT>RA+=XY!mhVh$EWFkvI<0b!mYfv8|c1_Xk{ z4iF)UqQ_apmbX0wWnf3nRFFtP1-v&EWCT)`GD`4SJNJdwqN!|hnuO4}Ivug0O2a@w zLncsV?;!yYfkZ+w)xy&2ufO31GV}St6B}u8rW%Z$Q>2Cr!idJQTURY`tyV5UK#|!w z@}`htL*paIM9hTb95aYRN~#G67!aJF>0_&J*oFQ3x#Q8aaITg6-K3Kc5*O{6`PqzN zXRREsA=l2L8Hxr^NXB(iA|N6&OO2fe@rw1-5L6HlSp^J?kpM|R5u17!Kww8GmOu>w zfU&tys|X-5I~Cw;cKOCP%p85y?$-IubDvIoXCaMEMj*j65ukyw127aZGxLpqcbbHq zw%8C*BN$HqjDUs&Bq$2TU$g86Qzj%tMj%9wz^b0H;A!clBX$N3FqM-~SNk$~-l5|5 zn-3hl=Ro)CZs!+VW7}&TjYU?B5w}K@K}>@n!Jz4O2`LdFF)Jt_J0diSV8goB#@J<+ zQKpEjfPex7kPw)Fxsg~gHSaz`P)$IL05hHT!hA2AFz7UCX-I$$u_=f}5CbHl+(5ohkYtL@3KD&O?<sH;I=wns z`&j*ubNLu*a%{>G5R?0c{V%v<|22QH@%g{oePkG+gYBD&MPI^2*)yM%4H(o?WAILK zvN5aHp8S$YSFkHl1vreq!^%rN!~M zA_NJ+Vg%=!w=FP$bASXypkl%LFTMSx-}!qfWo0tfa#)o^E6cr!?JAlQ+1~ajtS1A|6yrE>ZlZ8;7f=4}nFk+U zy79nOJ?iDHV*3K-f@uWw6 zSHJPQvhRM^TM?<~`U`vMzdpEi@9FaRnQHr@atWPwPBa{@UHi@Nr zVwSTyfmDUc1oq7>eeNTldFpN7`pzHu;g5dyqsav(76nG{oNbKOPG3H8%XKeopUb!Q zMxXi2egEX!-}s8xyzsyO+20*HaF9un!e~2Djy|Jmlpy0G&o7?7Fj}v_@mpT`AO7Tj z-^4dguolbr`NhSeU+#ry*1}c>u0+ZpL$&+&9urB57OWJ|9DFoEz!vm+JiFXlMuVL& zoJc)}Ne147udD{33|ejKd1$w+hXTWBfKEVmV--O?6=1H^;2jci0vx1jD8ml)UcCPs zUVqCi`#V>E7^@(vp9phP6*D3a=ECTPga#6-;OJR+$j@0tvoIq%TGXBmL1Od%E$g&ZQWiiIeMV9Amx zGD;Lt%Q6oL$W%{)&m1zf zoJK3l%6V6ftD;-PAVCu#gh`}~h|Ls-yCVZDTG`I16p)NFLrZl^BE%dk0aTagTGf+L zU6|z#)FbrO_O0}pnH1*VqTb=EqtMBbtsE= zaq;5n17CXZ*|SfJQLDXg>EMw(?}n-Zs{pC40y|>Q%v=sjAjpb5lw~>D3FVN`A31hg zf9dFCxHlYbx_0-#q3iSZ%<8$PN4u9z#5tc8ZDbchO$40z(P$&3$veK|yMFTLe)_IE zUw{C^!Pezdt0(V2v-8Y&sefRm-HT%gp{mAJs-eHo?RK;A_BeKR@p%h#_Z(*SpZ}eY z{?2=UYwgncufOY6`E2nQkA3>dt@Bl^E384~rB~nZo?rf@w|vJpUwZiQ-~89Vy1ur3 z;Lz1KTr;~p7(D*yDR461@9gYMVx_IN&s{Ou9h7I!|I2Utv3u^k=b!((pE^EVf9s*I zd+W>I_(z}k<4UW2?fo^>4oDOxv6|H50JW;9C1`rX8bi}_3lKnsgg}m*P6=zq=-K(Y zo&dnR{@G9drO;YYT% zH?BH*^tXQVmtX(dmxWUQ;?Ljz_n-RUxr0GWEv_N7TuY4 zt1mI8Br%l8=zOLUQ>;k>5}7h*Z3IHXrd$=#Sex@FB~kL3^SMS#l8{?KxpRmGnA9nh zDGkl)X{3!1QB4!52$YHwge<0zVBBggh!KJVlv?Y8dJZ6(Gy%7yL6KbUqRE+R_0t!> zy!h1oJxj;t_s>4Qc@bsi5ZL;&Ys=5O8dnGDV=MISS1sN&_s!pU`0xJRiY_k#dXt)n zlu*S?fygx^Sp!Cg8iNe$g^X^y@oLv?KYC_uZF|Q^6d-T499XJCtV+OUCrGMb$W&xz zU{zE^GSnb23Sb4)Y6-v?2r-r>gzQL@rp7bqkP%Wa6HS#_?g&3xvo3q8g2TQ52n&T(VkHT;03$fA9O$9dziQ-uA*+)c@z{FMVO>S#)Hqs>%#R zB!nq(ZVVzw1d0M?g0-n9%$!RJO3;?`RTcX==8mPRE1||^9M*?^GJ!rrI}?psn_88` zCgZ`y(aKhed9RbaPU=mP63HBDStsPiCyouPKc$2Qgr*V!kqDDSgr+i5LrR5mj;_`w z5<`fnI(>&swI>oVYs^xb6g3CeCQ4|UWedc9=kg;P=N=3@PchUDViC|cGOU>}Gzrs) zQ#U9yv4SbW2^$>G75Qr#iZ!){aoA|Ega#rB9e5^FWkk>HRXw98%n36_OoFkBlZn@K zY$?0*MRPaZxpd&prS@V0qitC^Wmg?c+j|fc41!2Z5=A{y;lPpvu?)!&)C7>!K+T+4 zj2h}hfTHSv&>BA{ikg`*yJ#v6fE-jzrhIQ}?6&}*XizAj+7vo9#ScyaxF$xf1(azD zfC(TVut`eQuEttZi4d7UE&e|vt4-@&o3AD|fzf|F@~&i75!_;D|Nh?oQ|m>gYyedR{noxbkqQ4e6AMPZccjh(%I z3NwTqLP+(|PVYb~AD8j`u-wqF2Ppz7x+^bC!5RSN6+9mz5KhnI=~|+B*$I)G&K-NM zA9e}=HZU}E0FA3!8&7pZQ=9rCz|115D2QP~LO_|$#)MZU;l|aj01loj_-imufMAM@ z#!~5^(lJPe&Xda^>haO(KfOS2TfFsohmT&3*R+Qx_Tpf%v-FzzJL>J-;m(t44m1cR z^K2r3KwhhAwJNufB74rbZD@6>%mA(E`MLdBFE<;oU8;8^g((bM3>d&MPzDN!WDS2M z?mhdd`_7-Zxw^DsnPW$m2qYRZGzlut5ECRrG8109^@i_y{X$sier63|xC53TRgf_> zFf8Y&$SfHsK)aw$$AV#jP$0P65@6Os$D9`s%xa6{5>o9);};)lef!rfzy39y8|k)lYtK<(X4utJj*H>ldxoUO5@o6|hNG4@VmcvbD1pV_MobpOFWb7$It6 zud%E{tQ2Y@Tp#GUOQ*h^pL)^tx7>L6pzgrs%c=KFKG)CYPhtCuaQGHJbQdjOg>QUy z>$Y3>{m)N!{`Cho$}Q_&HCxxERi$Ia7A8>*29B}tkPHBT0X#w!5VPC^V-*s#@^-&7 z9!E7Hu&nT8yt{Lm0goNN^-XVn<11eI;v?4`x#s$VvB_E_`OPre4m?U7 z=Q|yV>*sdQJ(jjkv+m9JT*sH>m`oQ6{ zE9buFd%ydS-}}e^`MvLb`!|2nGtWHk^Uh3f{`=(u7s9{9|a5*C*h9z5~v2mbDZ z?|IM9zWmOY-v5;ce9=`9M9wI$)8zcl$?M~d%lj7A2b)hl{mf&JKlQ?|zxB`l?1QVD zs|ETxR$>sxX2v3r5%#+6;pW~~AO7kazU4)K^2dKM)~zg%t@ZF>OPq04lIImo1KCH45XQj0RF0XbanF5Ea@q+s?Y6jsS;YvR?1( zTFFrC!-cHnQxXLhfPx{ztft}lcot-QJ@5OrTVMO~8xCAOKl9|1@{z}P&ux?f>Iio0 z;==Cas?mXKX0E#P;4Aguch(Ps?80`EIzmZ8M(QE+;6XBP zZNrIU~jEPiKK?%tWBuPq5g}}7Fl873JpJ_rw=RFZBLP01hE@=q>f{2i1 zc~kf0ykjOrPlPEZ0yMLfQkMCm)rv8Rh?yXJyHc`e4PrhDFt`SFC^{LHoqj8C=aX@X zh*^s@Sc5ib*uTtFRCK=Zp5n%IWR3OQD+d=N1Qh>#G+} zl*0|jjGX(TVCN;(3<4N-b}sFoKk&=H`n%upj&EOBTriWBiz}NKE{B0E?AtfX;Ho_C z$zWrwT6gAK?Vd9Ule$8uOSc|4bkDJ^6D$Am-~Rref9Nk3iiMZn^Qxz}S08xh;jLjw zo|8@bmi^R^{^*aq`<)B3`@Zo0k3I3ZFI~5E-RoZeHc)%~D~}B}#!|ulLkqQ3n_;ih zYR}Kio;!VdZ~ffA{=T1m$z8Af=fC+2pIHCu9laZV;HBUBl{1fh;;9FZ9k^j=L#?n* zu?&-_WvxN1Y2u}ZL`&4P9om)7RYOFF+{}T9$SyOJx}My5?d|XTv-d5}AN-|z$0~X-!58xpB0WgvYCY8WT&nsNlVb6mTYPuqp2zR|Nj?$jWS`=09X@f zz=rEdSCrVV5iq8F&t{Z~0G855N*hpl8vAN*2BDp|XMJ~h`Pfx1gRRw5yKAR2@7ZNw zpb0oDeBSByXRC7Tv!!Y@8t!g5lFa)MV=ba0l7gWzW&q}0W}Yn8F;;-UmXN%mbKa|_ zIs`;xZZ2CUDS#?dhR9-~2~^Gb%w=89*@2kUG8v>eG#Dca@-*j$8qEYj6{QTDId@w{ zQKt&Uw_FcFHIBdxz?hg3LtUH0qHs@#vmbo=(^q%8hxRXi;qp^Ee!Lv>a}PW-bIpO) zftmV&Ro>sCx9-35rE_mMy7__2!`Xv{q=-zUfM_WwAaL#wNrHf=S3Wws{E{2@-FEZr zmoE-uibP~8W}-160HlbTn#2SVhB_io&5PLb4gj$E* zBo+cuOXyfp>dCmfG{4-x{>hc`U_5Dllr1GNMn*zx27O3E#LO9Tp7}x~m>IaZtK$!y zeeAfu^sU$4er&)?X=OlFRTE+dicL2PAvE(d zGde&9aD<*wk|2Ns%LrSZJwsuXr<%&0WnbTR$K3PpIC%Jl3v<`By-yH=9$zh=IHyPU z_wGuB>qK#Qyf!co@#m5ZF|QA;DLQZ9X2pv2j-!*50>h(2S8i5-1oM6Pucf zv_PMC=e2Y1eCwSzE$w~gtG?5oOyW3-`E0ukkDgtFe(qY`76GOD^~dgb^G!EDapLs3 zjnU%r;b(_C??3tFlVRNGx(+F`RsxG4&}=V=n@{7))QXK89j16;0KY&$zp&;yhR{rv zP0q}K7LUG|fVM6^YH5P(tVvy);T6C-7#Sd_00R(%CewsO*5CjcP1Tx^NV7S)LaPF8 zE~Wqkj0OZ(2+m++=43Z*-#2>vWIT6x)E{dYVhyOqe0bm0i&-2GCRNUtaq>u9-Hau% zYhDb4nFR#`^jT|x(c)xVC&4)1=jXri=?yzfEt&ygE|5N0Pk*8pIm{J9S@x)t0RUnW(t~s9J(CH z8+u@X%wg67-!=>A97>{Ai-6EvHHvX(L?ImR(RCfT>*~%+jxF7JcXr@#k>vmYFfrLS zF6q$H+$&yH9KAYR-YYMxmd_r)aQ5=0d=9H>9Bo&v^jU~dBe~JJ%k55oadt6lxi}7z zB-vm%-W!egkTlC@7xypkpPBdbe0j1*^(0L!9~b*#Z(~fYj5b#2F?;j^7_`#|H;l5pC0&Y+P<$aiWX}C2RVbWAwdoZZYo?Gn8U`5KdzIsT|PgvcX7=` zJ^RsUD~I+gZhOr?`R=#9;*BpkbY!{HZ-<@mp}%|j1LxA2eFwLtGa96N7}}t-EzEaz z;>DBY`G;}yY%YPjAQ)RYS!ecxAN-&z@Y~-0Pq#NWAAR~u-Bv$J+8*q++r9buxtohy zo;myU_x{j#{noGl-Y>rAU;gw@|3p!Ae)tD|gogU1k32k|&#~ijToZ%OT7Ub|kA3r- z-}dd__VzD)<%JWc2O?Gv zUVM7pwh>$gfPg*dFYsK;y!UM|zaIDYbZ-&@LC)xtfd?NT<=F1KxfbWq>R}vAU@Vrp zkhig4_-qh{2q{PMY=Xm;aMnZh^~<-u{na-eJ2&i^XpZLh~D*Dd0mCw z+V)Z&3{Gu~9mIn1;Oz1uUv>S=-EWu=5yr!`w+F)uqqU9k=IY?mrSigAxv&E}BNz;% zR)`4BK$#lm92kg!Dh2})t3d;31%LouNA0FcPfXONWyc6iNNP18m_<_yfDfJf)F^H3 z;?7>2bft{~aTL=?x$k30O$7o1m{O=>(P?E_HY&$yP@)6wcuiVKtjd}ZQ;=8(Vq$V( z5{%5{E>)6ZNHGwR1d-{Xs3HOmQAuKSg%c5}Q|6ub9xSut#c~%iO?N!C1m20CYFiy&fnjQ-UNv5Ql6q5SfqghG{1Sup_BxY4r(Ba;w zKhw>Nd@?DK*=1Z!B9I|NHLiW(icTg$CzDcCGVeV4GM1qZgoGIySgf?cBZM-sCj*Ef zGLsr`#wnyQ63&P{r4R=@!}d(uWjr2MS)KudMAb^s0TNbaBnRXO3F}D=JA+osv*+=k zOgik%bjVRPs+dTlqKB;TqtRq{usb`~yY1L*RY>ndi5#-y?#zM! z5#?$!*&SA8>GRy@Z8Ofhlx2BUhRI;mpY8k1Z*Qzh3Pc%uj@m4Aw_` zml4o&=8H@fRMj-G#u)a-J$JL?@p!y?er2$^mpi|BV77Zhw_KM~ zpTE4jKIqLAj$Kt%NEHxvdinJ)Iks?g{zHHK*Z6+m4mzcGfR#+90#BzTl2yn=3nO zTa)XrJE}uC@${2eZT){g`D@3H-uz>~^V5HO>AoYd{MKXNu$OlK?A{MTFW;>8_TpY0 z>L7K}(5%Iou-QyEW-0`_f@Pf6HBYg?V2(T>RbdPOzx)%w{Zs$q`=5Q}!uP-Dr=C4` zxi_=8eBiLBET)8oB^6R1WBJUJPnDs1%{RRIT|fDK*WYl>6OWzz*`NBE2fp(8lc$aY z08-EUu4k9GS}x0xz0~!j8rAhErCK$b8IU%k#gz($X}0TY=FfjrS*MiEsSRy<*#kg8 zp5jlZANRHL>~lQM=9dzpTBTBjatMH-^5i;UbkgVjy4;K79c@w(nEPV3)jJGWlx2lT zDIxipeTNsT(V#B35z#ppr6l%-mQpf}L|n9crEn5jzivArP`BCKYMO+lYv! zDG8vEbImq^$stk-2|%b-_+k#b$0Av(Hg&X?$_;=WfW*!r6ds+CDvTAuv_rsVP~?R} zs=`=M6qHODID*wFfd_T^<;gQ2IrYGIUiZptjvRh=?bQB|k9Jqieev<)%Is1UB!?i-`191-dtq3+imp_EcO+iNSfz5)@}k$C$%L} z(aC)pjw3+a8QIPrLV_Yk?^87~h)DvebULnuRBIh1vGX~jDOPIC7(|I!)KmeC2_Xsq zF%y|yaS)g`1GysQ&bfpcNX<~G03wkyFarnF#95Ll0=8VX(3!i5d}};>Hl#5@C8^Yu z5WsO8*fnuV)zl;s(G(JrqM8a$EBhL+x~efw5yj1zVA#mpjr4^Gss;p*@pKUJo*XHu zHa*Xtpg{AgMdqNc=eqF5Z@TsNyO+BMJDqlft!+7bVR(KM_abb^dUNCtWT39`7O5!- zWd_O|MOm?+sYl6x1Vqh<$kYrpV`}>b6s!&a5TYh9ZoZC92&VT+3lM9d$us{H_49o~kSjsSFa!mpnC=ILO z6KkiR9P*>1ONJHT6ifvK&6lWoH~}@pDFqY2sf=h*H2gGXR(H$HWIyWio( zYg#+i-r6M*o~QaXp$0 zwstmSX}~ z0K`@UKQQnFz*7!00XhfH0~W&)Du!&PPqg7oRN_rHz39h(=!f6@mX{v5ZYd6R?ZQr+ zK!2`v)Weqo2wbOMqx6J^@7jxj}S5rK%<`Ei(B+_|uP=&G67-uBA* z`yPDwyVt+_<*&K>%MU&(M^jU~m$xzkXUZ7K1NXbL+v~&K%jKKi{_;nD|G&?*=Q`S< z3aH3-hP#ILyc-U`@UG>P&ul+_>GUklu=x(P3o2T!m@PVGRl35jlzY26sG)X{71U{E z#jpwtF5_;`&7e_PR}&d0O9i$V*;!stYmi1jvCWuhcs8tfu-7l%@%?YV?byEMbI0Rn z?p=NM((2ZRi`w$sDcVV-PO(Bu?N%oPuL$eIGMX{KrQxuJlY{N{EW0`G9Oy4zJ?md~ zC>3)dST#t)wZUk8w6{@h4rFIk?+(Ivw;b%&gF!u=3|09gvAL(jX!Y3tQN+ ziE3=x)U}?}Nb0>KW)KKOC`0-Ay)S(V$@?(i)mVGIGRhs&*x80!tJF@Qu&MLSP1jwY4! zzTIoZkjBHRT6JmV+ZMXIM{VzZA*nJP&yRx|5=g&pr6$z0)Y@xZCNax-Q2h67}ciXBYQXbx;E`Ek~n}LVtcX_wAj{waI8WzqBk# zM!OpVK_n5O&kKnfB{{n#z1GyXN+z*WY~Ig_DmTz>Sx zwJ+S->$GimJlsom$Bj1?il4jh=-qo)^_G%&cqfh_& zMw*OW+8k^em{^)V=K+`*2qg&sIC6j}W?;a`#HbAhl8lHQx+Jj<<*oal|A&9@zMHSU z>QDatUw-g!J`^xt-ghL+TjZgxD~{CecG`J%`uLOOWbfrKyZZ-!{QGXa`MO8G^wr<_ zSO4nX2R?W1!fAja&*u@HLDuVaGj;}PG};TXim^0HW{vxo5vXag(_Bqx-9d&TXbh6 zxpFiTjm!iFpvqZ+;DA9>XcCE@Nj1f~1_UI>E+-f7>f&@BGl1}rQr-kI#wIvHF2<-JNDSl& z^P)T7_A?r)(cZemS|A`G8iFZ#AZM4#T@X<%GY5=Fj1=vFrr-GHZ(JMfyz3L6X}9}V zcl)_98kZ0Sz%y$ULuUX;NQNmUZcNAu>>Jp-XGN?7m_e(++yR(cY!FC=A@$ zliEZJpAk8i7o2B6s%WWcEoSG;ykW*9XsYNC6Hx|Gi8fx0#&PN#lXKIKDYOK!;Yu>{ zwEqC1ITZmwrdu&?$~J)0+ z-MQod0Za@LO&v^WMgMr_J$HyT$xgfS7dBnuA%f;{l0gw+6wOGOkjylhf*4{`xPyi! zskQh7auB9b_bYgO$$~4p^7#K1zVV3VqM)$3s3$Bc=1SduWjTyl)0Dv@Yq6p@J z7@H(&nCNJWT77hFD+e;3w69+5Egjw+j?mCT0$^l#mgt+`g+{j z*7N5_dz!XK!>Uy$v%-*zwI zGo6DsT=&9juf3LojLT|uedC$4&kpuBCiPAgBVi6iyp|Q%+rR%%f$hcq{9k0nA<}M{nWx{AlZ*>ks_UUtPL%DP-5p5&%eL2-+euHB0ClY8qP-LjafU4a>5& zPP@%Oqv6iox4it9fB#or^SbBno*IAZe?IW&W2Y`(9OXs(&X-*K^>2K^fB2P`{g3~C z|6hInQ?$IVKi}OtcXDvzVYjz3>(tE@Tx3cJb<&_fNinrMomj>X{oUVv&-Z=LH@)fG z-uGwkO%T0v8=Gr0?b*Wz4-|op$kCH$pZ(ZpKhZ8)A?bsUey*P_e8UTlR;k(>jVXim z?TtMd0_go;`utrlxclyxy!^9Y_&6X)OomzJ^D+)E@13v4;{*Ga&##<4e)7~q4?KF; zJ-76V-rnYJr_-$}(SUi|TV$)zc|X(6CR>w7?|b5|m)@{sbE7z#jSD%tl!9}#e`)6S z=N%YN>d!yy%DD_0tC~rFl(Y(tw;V|*2(jCH$Njb2-g*^KO>6JF_>m@%DK{7U&DK6Bd@d z)KXPdU1Mov-1TnJ7l(b9i`I5Nen39_;OYnD__m$&xC0mxPK0+NZb!YG(x%!7K%lYg zV`jjJ`gDZt**2j>@8lkFH|vE$_qA;YEY{RC`@)Ic|WUCjULD>l!=^+ zA;l`SdhHaI*g!4T$>k&oG&QzlRG>y#bs1{VC=rMxVN%Hu(I}MB7o0-UBw67QAVxJb zkz}fZh5(KWAXF7q148dSAV^g3WTvr7Ok@d6ahl;l0JSC}(mYVWngdmuC7_6DN-#~r z7&59V0V0D%HEJkU0szjjHf663d$HNKGKrXTKt!6z=^9TfW zRkLFxh(Sz^nas2fF~vv)6G1%*h~^3=kD(0pB>Gl{grSa-R8`|dfh@*ou@U!xnNyUQ zL=BixBBrPTW3t5TJ6Ts%ue$b{#pT6EzVg-g|IPn>_RMhwZue$ey>4A85w_adWN!jU z?V=@7s!>Ty{e^}8+)_CjJMUwRJDb~*(%j-gr`y`y*xK7#>CP;5I`g|*D=Ah)z%EmR zRD&TEt%A^LiXs&=gAr&Nj<#>T;g;Y0jbDG=H@>;mYVB@po;!E39EY}V&+ngQq{*m4 zFtg;HTe!Yg)mxi8Ln`8-7wo_J&YSX9`yc-Lqrd;}fA`t5&piLu7tD3%pFaD{iS^SV zB_*_2z3mmR`{m#G)fe1-_leIw@TY(EAuR3K(OYJ8ad>8nhIM=2d}n?J6>q%e>T-3o z^6+8!A?p-{4G84ejjI7Dyz{L;{j)#uV^4hP{LlREubf+7 zZ_O;vwAz-_cvuQh?z7(P+~o^r_by+)`{j4O^IiY!rkjsF_@ys@_dor$2fp-$)r}RO zFLb(BnE@w5C0QfD{sd0w5Rys3F30a_rX(!vF@B%q+zS#2{i?N*YDl z3KI|Jecl<>dtox1TRzp2q&Ol2=Uj^7 z+2{RsuiaYc<}Kv4waKO3QIu44T9hQ2q(r9Ty*Ee_6Of7u1oN%7s)Dj(r^sLy$0G&B zFwq$G`~c1_*qUGxgoH^n1wcjTI2ni;Dv=`qm1KrY9!)@Hcd`>RR%9?|NX#BB^BDri zx{iREZ_Uok9m+Y|-8h$|1POpfgdmmz6yAYoo{^fR0EpT&mU>eT=}6XUwM)>+`fxmh z#d6V^D-c6HNzs~Mo=7lgJ7?U(9+7 zz5XGH)nt68tS+Q#2PB|xluiWWsXM_8fEwxy03ecyfk+$jd79bK-3chcv_u5K7-@Rx zZ>CoSQ#B-_D-gFSFVzx?CuSrDBb_$qfhdvWh`ro7qS`o)rP>>})~dnBpDa&lmgUIg z3*TxLaS~O`l0u9s7DY^r(GWmY(1@o}sS#i@V*o>lYHG%aQK1TwAgQHb5zQK$WP_bk z05Vj#@_A2B8Bs(+Cx(W)Ti2UWOIHB(v3o6aufhZSZDRvA*6iFffDx)4hy&CT$y5}k z^zSJkwqafwH25WK*iJUp9;e3~KDV>G5(=H3OO@e{BO@J$1Vmq(elWCX3hdCDvRDJN z1VBJc7|m*vEGs_zl?&z1{n=~YaL3}IgCG0I`CgE-FDs5t8Ynhhgp2v0a!q# zJj6UuT!Lu6nu znbz?%?xCq)rwP95G%I`Ml$R@IjS4DFF&J1qvN+PcRm)GUtM7jt(pWfTN;?c@7brE1<|- zt5vRSmy?aJyQcF)ufFEa=eG~+&pTZN16{G*CuH@wTsRTWpDA}IvGzD-+UxUPEHCV= z497b=+j}kQ6qW0=a;qR43=M*BF`|s)#@gV*-ee1N%Zj#lnxu|WRdrlgI(qHVn^RqW z>8qdG*}E_<$90NP5~4H(<-RCHFbxf@b$Q&%xYN$&G<4d2ZvWieO-B}QJ$&S*8b4^H@>0u@#~NL#Q)s-%LDeX0OYpsDbi5FFjfL)h@Nu?ZHK0&j@eWrhn*A$J`TzF*bB~{?N0oQjBcg(wLo|+<5{M|IR*ti+c1$*`6S~Z! z6$p&hRX#A&a|9{GcFtN!651JAs9>#9LUlQ|7<0C)s~K0WRkh}I>FCViql<8u;V8lq zz!2am_{#kkzWB_OUs+jua(lcT$#7qWvk5mN49avl;AyoDvl>7Mi_Epj908h<<6J?Q zvWM3`|MHF3v~6Y_CW`<_7OFZ_Y+jQ@U}WUxoIx`L6iDnm7)T6+oM*l{UYgQoFo+=% zg3Cz7VjT?|Oc91M7^!c&sFG4*VN;nN8UTP;mw^B|qh#tGg(L=&w+l3|q=2B>1Wu;t zJ0eaZDG6r801}(N)`oka2FS!_CP^A6Fc1Qesi}!I$9MBUqUX-yY0LtrG>j&V+RzK8 zsVmi{Uk94!001V@W&wa;F(or_4g)|Ep(tu5QK#iP8Ma!*UO5C!?5UiTMV>d+H88zQ zm@1ei17yebI0$R2TQIww&7Iw?-FB~IV094Z$iPyPhTb7&u}Ur@Ag#us;G7tI!Q*j- z5y&9`R&||BilPwF5Tav_DY7R(3snS0B8pMilY#;?+hcxwq(Cu~+-P-D!_Z&kt91eZv z7Z#T-g^i2nM|%6FYR|K(E(j*9d#U&ildWn4V+h2sZj=AQr3t9#ci)Ekw}=H1s^d+5UDJC0mC+nasxLdU3eZLX6 zHvids-g)ok)5jLCJ2-Rj@?h(y z03b8w?1IMeWN^5B^gsUUe|g^i8~?}e{ogM?_DHKYd+^Xv>hb2*E||4v+TB)fu(kEX z1NSd2&Hl!3|KjW4`l^#ppM2Ll-}TYYeRTEmTBpA}JAbo*OTl_`-8?So<{&1ab@izrfs ziHRK%q!gPpm};FQs2PAF^3;C}%`I1_!T?OK`^_yJ4G|Fu0FuhCiXs$5r7EX-qZ(gC z&Rx;z^=DKju?%3rd@pbHdNVV_tQhWGswTUJn&m~7wGat3##AK@DU8XZ&kACWF@PD8 z5GXhTQaQDdw} z`?=%yespj0t>dp*hvAA9U78>bDU+|=@y=GZ+A2Tt|VnS zarA6r1Q}2h5JWOl5+aoZX2b|0#Ex?hL@^4OX$)e*rjWJy-~!zYh3|l_`FQ55bu(EKSkimMGv|H`A_)Y>56G#9+Osqx-o}k+) zaurRfG^vw72HeVl5K?NAuiRo{B?5Ltq9l;a!~_5{V(+*XMML&Z#L&Py1~W21Mnhv@ zHC1b@6CkxTj};(t$T@j50A^K5LBX}M?gG)0Ywz=UuJy)v@Ju;Aqc$Li#7+UhfQS?t zCk>z@Luwv{lHFseaz9XT~2KtOI#Xli0;H1#~D2JFU!qG~FP)AlTC z9Jhd|$`%dOJGa!zX1!-LBSWUqBn>zB<`1-WQaHacgbO?FkcZhBKpcZkLU3%yy4_K=+-c3NmZKBppfV*OP}FFp#1dkY zA#E_iU^LydOm~5bfMh6T9b#!9cm*c_Ms_9QicC1=r0Fy^42|g=)Qk+#c#5|&Kvf_l zAQ4$=&wlF-uekr*lNZi@rDP^RV|)j%eq2?R8buw8g>RTZaR@T9;5$dC*? z0x^IG@IVffAQAW+h(T)`@0vR5%~@HN+gkuaNFWOBHdF%4nnGjx>&_8+v}jg%@V+5{ zbIz2t70AqUD=V@>tFl^Mf8jj8^INWY&8s?B9n1g#wqfn_Y2%a**L5(o)zx}?Y$Jkd zo;J6K*rGBYUS2(Wd2nJd+GursmM^My#9LA1ltfI0!eD1N%779tbeGhrRB?B*={XTu zuhk++mo7cJwsUSW-UK$E7r^FnMgn31NCp!{!;3KIPtlB z?uLbHUvlkDFMsLmt*?VyZqNVpCzt>D{iA>T#Zfp~aEq}{L<}vqCT~t?9>5uN+{IDa z8Q0g&&z@O1b9mo@dtUR>jf-oWPwzhe`8RZyvP);TB(<*kCkO6-u=_WE^U-@B{MGOM z;ctG|yWg?6Sp19k{F}YK$+gF>0SK`cbfUi z{dKQBe)j2$D`%a{E^l7Cys|RW?N3J4q%IpMSxf=U(6AcEA|Mg&?2T#(fRWk75S~2o z$ZPKTIu#3HMCc5KeLMF>877yu&L2K}&BFZB#_GxYzxu$|<-OOu{_aP<@Tdc3b?iJP zWaVC~V+viKnVY3*GYl@4cf9DG)anozR z=}kuub{5Y(0e|^{i;ta`VZ|BG7VI)4(w#$k3wRS~_v> ziI2YW=$kGLR+s91z1jZy_68xj786s9;ynv$C?jN;>g32#3u7HZ8N726g)`6yV3y?^ z8)?y@)oKXD*c7?Nl&Z3HIb-xuqk-0C?Q%v0DU*C8ro34bQ86`>l*oAil&HucB8_1vhJe79auPeU z3(jRGMrbM4v7U5#Z3HU!*2ja*x*7uT{Jx`QIoMvmV34(Y9ZMofR1#v+m{Kh&!i)$s z8co`q|I43$&pY4!?xjQftI_D`$DcWSW|bYaTixB=3FTZxj|#1JmgU}OZoFHLN8@6l z^^&`8@Lc@&KlmU2@jw5Ei|5bXa@B47myVn``|R-xPpc%C^IkQ)ao>&a{+@Te{O%Y1 z&0qfgm+reiORd}Qc)`BKnX@O(BYKzhB`?M!>Rv82a}M+BLRh}x>TbV#|Nr_}w^w}2 zU;cL78vN{!{otoBKYLaGs@dM+UL0K9SWgC=aYz-IP75i}nu3~UwT(??5)sj2N-@<; z&Ba$7vu9t*Sdx6_E57H~fBIMBn*83c|EH5@R}bHGboS`%UbPoO=ycjbly%z|o;f*O z+xYJ9{gxm6iFd?d{Dq(RxetBnAI_XVpJ#LXmTy6B*Ojze-PU549gX%jhl9(L$*Rf( zzE)hlGI>s^qChY;a?uq-7c}lfB!z}#t^nZL?fF)#*Y5NIJfe#tW)kZ%gvi8AW2Ksg zD1d~R87MmjgA|1ci8B>R8VOM~UFnrj1iqs5!W2N&NCH=uSTMaDqFEI}g;aQ-r8uzU zMOv}kU}7`b8L#BUT&KG~7Tv7Xn}LHn+mLh|%1~o$26*R@RbpM&GW59_P$LR~p){sI zV*~^c)M$_-R1$%R0YE1TJ|FF!9iMq*_5PRad-1F0UU*yg(ERf9zFY6SQ7UlD6TlcI2*aJ(~$8Z9Je zS?1X@S%q3Fc~k{YUI0>v06@UREPzSHg8CLUxnCj+bwE{eXwjf3px@zxphKs5o6wsX zArX0t1eP3;DQO+q&@(4VQ3O%YYf33)+P=K z07ywhQ~?oznt~ZqBjyZY5~C>+BPgo6Q4neMi}`)jI+}N8;&`_lT%PRiK)tGQji`bq z;s*`CjGL~IMhk_8m`@o(00CA6GjG1jGss@S0G&-et=7D$tpN`<#2>I}`v@vF=$UC^ z9tc39FhHB#;eOGhtSm#Tl`qV+HOSs*By50Ci-o9QPF>D9Do~8UXIu^vqKmcSC_<^ zJDnO!rn|Z;Yx$;L3>s<_H1Z<>*wEBF50VK8<8(A@Hp-28UK%GiIYvYXRnKS?? z&}2<9Ok-Uz)uhx^(sKj%QY3DswBx&Le|6%EF6f-^Bm_fD5}R*X^V4iV2!u#LU;<5A z5ReoUP>Bct4aF1z5T{XC1ZF@sF(l&*p&5m-0#Bv!gOf{VFMPHf?@G~H>@V)iU~Rmy z6}Bf~!kJ`%dX`&-}gE&u7i{63LXTA#gm`uR89 zRuoy#%Z8XCzNEs=vn|^kb_^MeO=$$u7(+SG%cW5 zaPu8*jjVRS=pC|yNRAKzw{?3Zo;w1)AHU`6zwzr2&V~7>o*8}Y*>g{yt9Pm_!1XH?Z;ZyE*e?nPLZ&&}zchokYt2k$d>o~k-#E;E3b zqD>%c_YF0KfC@yMVq)*=sv=}!sH&hM?N+fcKMQ21&Ypeh=_k)$Iz1du6uH%%ajw0z ze;F<7^gH9>XtFo1NEQzsbl@hVNx$7)-gmex%TULq{mc8091dmN+gl%A-mJz$_6!sz zyX&!@5M@5kTb+gRV6=AOBm&JZ9^}kMJKG_YU^S5$G)6v`IUY~OM-LqR&ENP}-~Nv8 z$XfZ{*4F9cXHFi!0O)3q^kSU`qe<5D5NiVN%(hf)v^$)XwQIMozvbHVColinum8*k z{`!CST<3+iz9?1pg-5@zJK4#6UP262^|}|l={w*4y(!lJ=?~wxy|aG!;L;0Ua#yd_ zIeqcs_U>q|H+RePm*Y^y5B<-}|v2`|I{3KQp^G9PEsC%@GroF^FlyxDr(`@C~F|6oHrs5mQQ0f|xj$5u%uS^h`Le2Ys0N z{a^df-}<_5dg%W=@_+u~FSd8ahxhMy;3w5EO0J1{%HoMkhf^180-ScSSuNes<2F__Q1HCuL5HOY#M z(5IM0BO<6M5&}Ath)6_aB23N`MoHELUr`&Nr{Xu8E}$$$Ik#eMX@SNkUalG?fw!0E$jeQ%ZHodEvYl5hjn|Vu)(y zm)Z@YdATZ#}Ni6mn*;ICdj^+5K-?MpX>P|bAv zi+1qb+L^6uE_23%$1W{Dv2o^f9l~KkIRCP<(@R8I)th&>pF9kWz*UU=g7c` zDIp>wNK#-`$TN1%RTUT{Kq7Q#s7aeT5g*}u@Dw6eKZs_l&Gn5r0p%N!yafg%BCn0w3(&@3SkilQ1M0Vf8vK(YiNXgOHH zP7EjsG;+BDBMEBrGNT$10$WVXi`tl>^KlkLNqVOvzX5hR1_JN}ZZdlp8aAxaB*4ds}Y_FYTH3O(MsM$Qu6jlta zn%YpTK_ksLm`S>;xJy$VRlS)`(^HMSNzf#qn@f}`qB8{~G&B%tu1O$fst1bMJ7#Vk zj7N{`Jv(9aT!^ZYpySO{e|Yto1@0NONa_dzApcLiM8O(6ZnGb4wDQKH(^M8trCVrJ z1wcRq5H%vCsR^giVbuiLBGs3wwM%IeDSGF!de3XFjttw*A*oA~@%-$*+~LkdQmCOI z(1tYyhKz(j1n7Z$o3M>5DB6f zfw6f2Mq@`lw@Fp4UdmO!{f^mx_WHvwd1=4h!O7F<rOA<`Ms?l|EC>B{?{Mh8Qxg9UJex? zfMrwjH(_#Z8*Rt!%0TMb?(FTadyzN%bpSkxlZ+i1< zZ@l%`>Ju9`9KEWp%K2hpacorIZI&8k6{HnQGaeVsnW)rCLjsR>+ zwm0JCWxyZ0>80QD=4cB^DC>z&#!7QmqWLpJO|DZq%I3YB~nobAc!JHh<%?y zil^Dm&;m-z0BI-P5B zF1UKMeBghc`|Kx9e)_^Q$IC5&JjY%q%Zapwq&t(e>%i^V`Dd%AI@$bvmp=ajy?t(G?unYC-A9ZMAU1c0#) zNfH8@LgT?P1wn0`Jt-wsBj=HT9LG8llZr~xW>`f;Qi{hE|DM;__m*-4e`bA&NXs?mWX`ww4t^`}2{?=Sw!FFpC# zqc>c2?NWFDrAsRpw=P=3tjM>^jXA&gGw=G97vA>b0H8o$zmI+7laD_2<=$*(-|`}1 zHmQfzsC@Fv=V#`7SMBeO$FZ&D(vgL1p`W%zJE{Gm`N?Q<`V*hI=B+o+J^$(tyz6KF z?7>egx0Z``XQ$fR9gG1TqE@L6DG?Lm6t76wtfj3HSOHN)Qi@51n3-8b7+tbS9qPNU zd&z(O{r4T_1AqBz?|Q7v$Kx;WU{w4S{sixLK>MS1OsFM0!Uwz9c_Yhg6NQ2 z&KD|XTBB*6w~4qe2T5dc@j$n~JU6=^jA~7LyQ5(_NU1iAngkFWJC{3&q6$7|W|yLQ za;A!iOi95@QuGK7b2d2xWfe0sRaJG)BbcNpmcZ1&nz}(S6HN|tL`V_=ps9+zqKh;^ zS`mq$s2YUYMXQ%*Z8L6nXNq<=hNu){9b-kU-a@zAl?2RKPIia8n=&2|CU$|46+@Y6(i?dL8g_C&(vo&Wc!KHBiF9&zj5{U+fF|JsxO_9 zLoVKaX#cC<{Hkww>#Nq@{heQZ@aa!~>mJX^2+YQgX>y>XU3?G8OSVy%y|(Z z1WP8-n4GeSD8RJo#UTNc117~*)?sVb2ttfvrb*ee1T{4zwj_3WWY5l{Hv~q_m=U$I zgqgDr7fDAos-h$U{_9BFCVrX3+G$Ktl)6RPXLwKApD~^ZsHz*c0%c2~krL z1muh@sB;7&s*LPZjfq8*Bp?PNiqY~;YkqDnpVT{XFiwyaxGmwyowX7qX&gmS165Qs zVva$^QQD3HZ8E8qIYkLt+i(oAG>7C6R6-PK`4Cf`f~ivDTNFj~Ch9r&V9^xBAv;5@ zW4t1|kr{|88Y3`cp`=WyL#>(FLkDN~ZH~*;7$zvA&68oYYSlJd?XwKIFi{1sYJfyU zppAV7iKjB4H6#Yevx6@NsLIJ@8`prS1e>&65sTEVoYRHE4w^$Jt1RIlV62q2je;#6gA z7S{?*z_OX_(IMr8PPI0R&&^Z-06<0F&U4>D!=|JRfJSt0Ub;gh1T__4Ze&e^D3Z)P z69JT>4wSRZ%z|1}HD=+g2DeuyCy6`?_;aJ`;q}3#pwEu0-Qj2@g#-W~&iRnS=4j`T z9+u+=HEc-+I$)(j>`aA3hN_6Z1qyDh6QWDLJmt_1HU+U zba#Q+GzzL}L+it4(AS2AjGzXFzywqLbyK>>AgE@T8(0NU2h&gsV1|lFj*1p2SZ#`v z9u-t9?o@jblBrU`&FqT~!34~Vc8TDuPUDI!0+<0tbYX>cgL~e3yj?F~T*nz1g74Nf|-fT$q za5xkZ=b4?xy4=}4wY_!z_^B`Viv3p~y8h_lTb8do((2H;bKCFzug|{r+|jrF!pytA zqoA_?>kp1bH+tt8LeiX64Qp^d(XE1>gH>|;Rn9|2OfLkD;s+oNz(f6`dvrvI(RvvXW#LI-}cRKdi&pg^aHu`N$SjJh!{iM z8g9)m9_jaIb|*Vuefp~x&aU3`x)=YSFMsIPL&s!jSzUCrH|sisDt5b_7PVU3-dG}&V!1^$MO@8fCuYYoL1tC|Umg~&5 z=1S1@(Qwb|qUZ#jtW8$8b>}E_-gx5+zV+J<9nSZC_OrWx|J5hXZ=!=Nht7;ETAs&s zV9)}{z}gut%ytLEuv?~NsoyFv34|n?z&HmyRJ6Nfj2OhXl4}zeZJ$bvJLcPzdoTgl zu-bW4EY=Gz;>B-hwO{JnM>7Dt^zn^{{`%~FUp)QL%BAyhr-smRorSC)F-_pYpgJ?r zQ^7VBh5(6ywE+r(Ay|Rk{jF>3C^41}e11HBTM^O{RfzVSB{Eeb2U+GMsPhgGVjY_`u_ISaDt7D~Cv5_# zPQ}C$GgXsncXOxH=^|JxBM^vc6O?hz)m4af=*`XSZtY4^LJT1RgUfg_s_If*9<$6R z??$7N5q<84!wF0P8Do`P;gC6oFdmNkb3I^)DOD3x(-@MH_S&7>+0Nzb1~Ma+G@9oOshKWZI$hr{~uZZ9d2t@)%oHh%=v~Dc0T!> zI;kR+p{ObfDT0z)0cmK_7IVUIZMnw&*-B#o^>%Bk*tF8NqL={%1PUoaK^0Wab?W4} zb6W8YbB;0YAMZNYw}0z->UqvzyY}8|ulde7$M^gBB;KKj_>_sPx3MLmzUGFjX6NVs z;JttN8^8BHtmPFq-Bp+2#QEbJ{cX>#bXC9D`ljpe{+S>8+3BgNzxt<-Jo@kxY1-+| zPe+ZH&Ts6Qooi>gX-G2+R-HS!L_6&06+6m}wXLUz2i|xCTK&}f|7#t#4}I6$PyFSF z{>NYZDYWL(R(qwtUB-&MQwc>?5fL#`GmtZI-Z^%vrmD^{0EQ4mq9J(in-H7>E~Kv_ zKl0k2{N;E5!p5=wZ~vFyAD$l_o;w=AmbaIkzCVR)gVSeKc4SEs%r=#mI~R1i%0spb=+?*tD<7 zJ7OOK0p&!PCDRtGqS%UYG`HiXs}9}FNmkaC#IU`wUP;lIkA0Rq-x7(=ySfMpnzd0> zV+EHZf=N?IH&l~E)M5ywNH9~lJl1F^uz8XJLWreG z5Ub&Tdm(_CYAg(5VI^Tom`aRwx!vrnR3bVrTf@h9P#yZ7qt<&C-=fDWp` zc9!R9*9|vU60p2GtI?{WR;xj)hNFTA>|6ur0YpFoB?I=IJV6TM<+>Q!;>qRbzSw)> z=7rl|bm6M~51c*y7oUCV_9HuAe#4R5-u&v9zy9vkOYc1S%;~Rx`H_G5;#VF!^Yj|5 zXPnI>(`lNXk87V>d!W;L*}9d1+)ZXQ3oKBVrAheBNa=Vxc%@xndVPTw@$`}(Nr z&a|OcCdXuH<_w{(Y7;Opb6!QgL$fGB0F0aiBnFHjI!=&~Oie0na-)pwlBS)A2t*8= zm>AT65s?r%WhAW33_Vdd@gPYRxL*kp_&hO}XlT}H01+f+L@`qkGa*I-F@Di)){bwjq)Y~y zdk4WBk|&BGFpx`#VkHtqKt-e07D@Tm@Rm9(_dC<0A_zi{~%HAxhiQqvwp z1ZD;#YZ(0MfV)Z7^?8T0GE}3w7?;IbS(^m*$m|lpL=hdaV@4o0Bm+PoaE>{3E*glT zcRp1Sht7c`BxFNk0EeND5ebx_F;A<-*uecK`CCG82JAUay+<-I#O9K~0LTczkdUC! z#hW*`({@}9-Q6&*0BTDr9B=5x>CuIDex+-LtzKD>MbHr_BQOX8CpbX}p-pbRCs=Zv zjPsPpHK`5vzZF&|M?RQTRsoR#oBh?KN@1YXkc6UzvQUfGtf$S{ZZcV%^jf2tMLPWG^Kn#=Q0htOIfjM*prchT10I4@MKmkWmk1cIu zV(WwTl#*6^Zf1ICUy3S}06KY_G(cpt62xQT?Xm#}Vrk&{vgiBfXn@~m3kuFqa{3BT<{SG?u!**jl6b$HIh2*yu}R+zPL=TUd1 zrt6RNzW(TQi~Z$Vi_Sdl+dpktr&kPmqf7nKa#asSEy*&8QEE+js+BLa)7cPv>&we! z*isvHr)K)2m0`8%+KFchIyR_+jkh;@!||XsJDns@g-wG3P}!NrK+Sru28cSbL|UlE zRgx$OVnim5Dlw2x^3;XeDqR_GuWk)bJ$>T-srH`32VQV+-!)^vzxepGo4q6NeBaJ@ zeP8=h5kGJ|hNGC~7$P7dCP1R-kkZ!K#j?J0VfTSuAOGWzeDU$Kx4z`%H@xB{vpc7S z`1!MIU-`^~r=I&N70cyHFI#+W|GtBJckf4wfAvovIr#o7e*M?~^Y;42Uw-%>fEL*C zaBD~oJJT&RWCzu#rUbor&hf(B?4u7p_UTW4_I>aFl^=NL_x{>{{Y_?C-dO67`qv)5 z?%btwYNBS0Jk{!~_Er{`R<1sDR6+=`H~GjT661ppe?2k({Xg)1pZWA>f|f~=nh6>M zz*>L#P^i1z>GoFZ(xv4G?*GbLzWv+o`=iI^w6km1j;)L1a#KUlZYTE%tzFu#YZ~_C z_*17}c=wS%{nGto7^cFWa4il~@>F&_q#bVeWXqvTA@5nWfV+3_LND}2APl*Ow9t^m zYH_m%$n0RFSgc@hb!+F#Zoc8}J7yPbc5N~K)z{A7`|My1c$TIUgc;82C{-OiQcgS$ z)jYdBoy-%j2aBo>ITgyCr9P>~)=u1X%T1e0A~v4%%sW!jfiXauq6cun3{_!7t#bFB zwBz+zepi|v^$_6fXV$;+XQ%GH|Kt-(t1Garpfl7xFx6G4H>(S4)v>Xi54vek02qNY z@CFf@wH}R>ub#bST-c!MXVgMdQ%N{Yl5D+R8O3FVa9LAT(Yg0dr2X+VH##*UlqFA%6UK@^3_{VD_zG>s~C3`7JC6N*Sx0gZ@6 zOeBhsgb?bQ$(-{sHbQw6Q9_C_GLxECr6g%$qK%jhF4H$mwJsyHFvv zlX^^sy-_O8doIQ$0#QQ6utdaST-7eLI&J2pthS2LFv-&C+37S*ocHI>oO|xrb7#+; z7!@TaK5caj*e9(JB?L*6Y~R6s-FANLv8T5-*7oe*yCa`2$K&<&wf5}%%)&z6N-mx` zxqj(%v>-9WSP?q|Y)#LIAc%HmW)P{rxf1HFX4Gb?6N4Kxf;dNLL`Fo+JRA;=?7#9q z|LU*2`R#9RcRRza-pOO92EEZtcbbW_w(s?dstDwuE<@re?_}d%*(Cq3f@{{>;VGCzemCpih#1wK?Txf8eb@{Jr1(z2}$C{`Mcd|NQde z&fPm5B&&-Xc}lbMc~Jy1+H>V>xm}z+c4^0sox<|yXC9x*>MP&$QV7E@{J_tbqcgAg zi~qLq_#?mlOTYS58QgTfRP^eyL}ZgF8q5e91%iqgpaa*?{=t|Sltcy1m>en~H3tM3 zR2yxW`Sl^r=F=X?=HdCD-u+~U(qC#~xL;17J)YrpRe zpa1fgfBAQQ`I!?>fxF+1O& z*pfVr(R?dY2@(U5nhG#HMKC= zi#H(%Kt~?QrLJWbs#uw62$ewHSOlBVt3i|y1jYous@97UV{=bPiO(|xpI}ferPx{@ zZTi-9XW`KN(JQOL_R@1tZLh5Cy!!f?Jx5ngJ=t4b>C7&47j|l_%W_l~V=4Mb4TcKI zfeKheB}C>}3m}3^p&a;DZRK$A)lZktKi0qHwwYV*98K-`yT^xLdiKd%_D|omXZj^C zICS^7A9>Xq@BaRkfB*bb=O4cJiHE-W_2-VCSd_&vY;EDdZR*aoe8{5_j4#UC8M!o< zPj5bRX8hSx2jBUEZ@#*9-`6+OnT`NK6`9d7sVS2Swbr%z#EC_#gq1A_nvyZIcL1Ic z0b@`^V(^F(qYzERU`fgj$*O>mySdySfVgH7lnfyfgJTj2R!ZGAnuTm3pRVfh=AhJ0 z0_KSlh=z@k8j(;5DOzJLB`{;>G*%iUao(cUB91dguSGB;bfhL0CGlh`QO!&Vn}BH} z7S(a6FZ3cBB0EM3RU|NE44}g13`k?f$beF*PrOHsK|P{#G%BjBiAWU{gxb_0fyBCw zb%ov}c9?yhgY)C4J;fj~s9Dpg14Wg(E~={V%mk_`Y(!?20 zvut^|EwW`eCalqffEs%o`4m*ZjENc@o0$=iVKW#PA}~=S2Rg2opY*ePF3^*Wqqz0SCV0EO1O3pydduNv^IZR{-K@15S zaWoJ&1TR%2cI+_*by<>_AQ6xwa!sRGqZvRHt)dyxH$te|V9^oi8>Mt3H2|aL#3UwY zOvGX)AQ~%xB!OvkZKD=MfYAz!1{Mbp`bahEvh+GxZ(mZ6u-XQ6Jg<9~fM(GYGV zxkLukbm>HtuoAdCQeaB2+9a%OyKHzV>moTQaj9)7|cZri@LcBj_yk48CFNyi!cVL8_=Dp0x>l4 zNd#AVmxuLW>>N6$LPk8<*&$<+m;xXxV)SYz zK?X5eQZJ}e0$&ZW#tG{hlA00Z5iX}J8s+aj@RwJ<(8TKbB;;~r**Ih!yd*O>an^E zckItzI?dBNZ+!Hb*%KGe);coOx~hib)xmhBwgIIom4&kKE^Fm82~W4P_NceC9R_t> z0E^ElCflL3#J38qMzI=?h7l{U090YS9#)rPFDOPJmu0PHiabG#Vl%T5WFi$uG#qRS z8X~4is%R=8T6(55Nz-;al%Xz%<8phjeQ~WgeyV-=s@=EG9GU;y&p%1;z3!dAx%WT* zKhS1cQJ>an2m8@Z+bpPM&Sgq^-l>`to1>>F?ch=pfB^PhNuOE{zj+ zAvxN|wKKzwMNV*B500OHdgqRPJ9h4^boAdo@ZWE~`9A9XOBJg?9)H|qd)rTFWmd+lMjl73(MzUamOnTA2@vO z(m7L{o!OD5*{QRqicyuN*L~M_yyf|`FF0}jTp8>2mDP(&=RWm?PyN-OfA~AT=bdkO z?HfLN&)?-)yDY}c96^U=Z#deX>P)rU?XAs?uRL=9cYpVH-};gltR7$9b8um}F?7^Q zJ8sY$&=9xF(xy4aaP0YGull~1b*$>?QfAJS6eSo9q--Tg2is*)G)T8DrhC$zQ{DEN z^-G4BV4AwT2nB{=VPQM=a-bK_9=!YZTW`L3KAz2wJvjd4;-zAZi*Yi;J96-y#Fy1@ z*0DIZQPs66BX_;u(N3j=3)|&pC}*=)2IfQDHAiK0Kd0=#jf^@hH~A` zTq+*ju1^%UY)}v|L86l&M*s{AK!~-}x6Qn?g>&0sF@;u2PPI0cG)cF@${;R%gAOVt z2rv%YCpR7ikaO|r`%ivlVS3NSc+ayd&%C7l5|_HV43m_Lf)Pk9Ze}26%oI&G*S6bJxkNFrH1i-acq7KZ%mz`Scyb03RT$V2lUn1fFvAABT~&byeUh1( zL?ohG%W=7V^Zq-3^WDEQ-Jkxe|N60|GmE>jJ)C93ax}8^z`lir9Si3!Et<0yX z11p9@ftb(DAn0hjuTkq*uuFaJy0bG@0bqo2zZh%}`vXyowIxXc#%bbq?A|@qnRDQs zM-}jiHy|bl0?ZSPSv?+?aa>lTP*t%mVl1k%2w_-D89`z!GnbP~h_gJ&R5W#}R@boz zu{4NHHWGo=)Ibo?tTqS^6V+H2weu|*1wz-Jnu!u(6}OhEV!YLz-!r@a8lZgGFDRWm zbkjGluby1Lc)S=cx4K=|ngW+<-io1!y*^lQSwe(jVC0xnP%vU{b&b1H56MN>fw*~k z#4A-@f?l;salM z`g31-^vS1=KfZP0j~@B^G_6`m2VHWp7#vBu2a>q)z=;Fjdc%ufn;(93t1QaII|gzF zP^n`S0T5zzqRQaJgp8-#(+R_<7}a(3p2<^)AkoNa;#ib`8{ibCS(@f8QZ2$zT{3$h zn>`Gh1{;Yrgdb)AM5(G_l%lHVNUm*nXFGFGu3ua%Yf8wuOiYoiK?5{=S28p}Kw(E3 z(SV3J@h+C4W}c~4b2oH1t4&MDr34fvGxMfANDff|4L}V|(P}V$hW@CGV3nyD z5V8aEgoAQi#)1G0qT`0;3kjoIs6%fw-c~k2l_0A|T6d8lOMC?_CI|I6#tK0lvq}&X zB4cEg2t)(~WC{@){|6x$6FNYF@ma$WN{vhi0h=Qd8j~qtgTO3`+T4q8sAXETRZO*CMglcIr%ws~IvJn~}gL8;M>jp842GfwuXFJ>Z^x|N! zCCW0^t#hCwlaa$(;*ipmpl(rEfV#s5>;apaW}{HK+=89#)0=rS0bI7tAR#75&QuM^ zT|TcO{C`fh1`t6TLr?<-``=_OU>a3H8X#9g32tV&2-q}U0Z_~sA(){G6Gt;J^MKmy zu&9Ztim53;b5*ZqF$yCpScs~K=-7j6dbG|^z{g4d698ZkhL5j3y;d$O1ZqaXh8f19 zK0XS^$1p^yE;n`S5^6~nraQaq(2;7TgiV2-Xv7#hh<1VE$&)wG0~ z8t}6U5H*lYFeGy0Alov$zI)vrvj@)(mQHP-A5^1=!2m$mxx@?vBBDWL0|U0kHIGWv z)TYf$wBgb>rPfK86{vA~BPtNW#OB)!gBb`xn{pf@Cz$4_L8}tUVd8^XU2Hq=(X|j$ zh_#_XRG+l3xcL=}&pxp6_ydr)8#)(ywirMP%ss>kL*_a&1PrDYS*vK^sGW1(jWv@~ z^i(gez}m*EZ`$_*Z@B8NJEsop^B^)f9#)>ijgzvq7KSw-rGxc?TLGYIPqp^!-u1@U zE^L)YPoG?V>=GM~XP;Err+@Ey*#Z7$x>co8D1X zNKuXj1Ark@tZU~9DVPXnocMMW5e;hO9UG_u5KYPh5(6Dw{&3Urq+%P@d3AkxefQ2?QKCz{PC*z45Y0Nt{Ej&m zrz$(|c+uAS#>f8tQ{ViWSO3Jje(cA7;;A~6XD*((=Fruzc=6qTdg0G9-#WVQaBn96e14~|E5o^pR|E8FXqz?kZ+ zn?}^r7tg*?zvarg-50h_Pt!tB>R`8oP$_cc+~rd|J&<8A&8Xc;^HCW0q)ah0GzAiZ zOL4gk{PJCgzUB7ASM8ZyJumltdi~-eZExh;;OEk$-EzAkt=Bb%>OiO6N@-L`0#>SG zfSs+hli=x%!9ZM_lPNL?<=%F_z?f8;F{H#WHfBt`OC3UO7GNqPK&-}aRqMJZH;u@)de2Rc@tdkhMINs?Bhx@n=+ zW!;%>6H%|%3qca%C>kXwf=_)_){{yqVhlke_%u_Af&z6FRfQ8Ghp|>wtBYU&79t=LlZk~OqJjw9YyEsG8x6-%Qt#Q+2HRDd zyCnB9hS9JTl_W_Ft=}(_ltm?s#AhxBQPZ-lk?`=5!*yMrJbC=tXP({M-q_yW22RzO z^A-pdLzvrh_{g=_jQd-|-oQKGU*ArWR;N2(){4#-W!QM`OlxL(?}7c}{$TOc1?QkU zJ2ky9tJ3Lj_I#S;oem+7i*Z>OF7?D*^)^E}Bw_$oRcr1Mh`|I*iP$CVIT;N5VEQXR z_lrOJQ$M+T-yRTs=xYyu?W+%!<8WaAf$g=zX1LqUq?Wmz-Ql=2!V2rvr4=N({bet{ z{slLD_CufkwfDXE+@-UxI(#>Xzwg-nTjOENw|jB59jAZk+kf@nyz$#Ub^n(?@{!+N zUSFQd+Pn5Hn8ILt#16aNPCcsDmPN1SqO2~RT%X@R*Pfa=`RJvEsp?JN`7#Q_U;ht3 zr>p0F=I{S7ncMlR-~P@IJaZ0RD};3al>t+*$_iIp`17Vikj^YSf0ss-{TJC3%90%Tvz@djhi%>*08NT=c4{kWhxAj1t6@ zn900%X_mI5uZnt5N(m+~DVQ0UA(EMi1tNzgCY7>i4E@b9vm