From 92298ca5a20930c0a124cd9ad6d8028491794694 Mon Sep 17 00:00:00 2001 From: valzargaming <7202504+valzargaming@users.noreply.github.com> Date: Tue, 20 Oct 2026 06:08:40 -0400 Subject: [PATCH 1/3] Publish source-pinned Civ13 architecture and UML atlas --- .github/workflows/jekyll-build.yml | 2 + architecture.md | 57 + architecture/audit.md | 113 ++ architecture/coverage.md | 69 + architecture/diagrams.md | 145 ++ architecture/persistence.md | 110 ++ architecture/runtime.md | 138 ++ architecture/validation.md | 60 + .../Civ13-architecture-UML-atlas.pdf | Bin 0 -> 1409611 bytes .../Civ13-architecture-audit-evidence.zip | Bin 0 -> 11177060 bytes public/architecture/2026-10-20/DIAGRAMS.md | 26 + public/architecture/2026-10-20/README.md | 96 + .../architecture/2026-10-20/SHA256SUMS.json | 117 ++ .../architecture/2026-10-20/SOURCE-GROUPS.md | 52 + public/architecture/2026-10-20/VALIDATION.md | 43 + .../diagrams/01-system-components.mmd | 20 + .../diagrams/01-system-components.png | Bin 0 -> 37623 bytes .../diagrams/01-system-components.puml | 41 + .../diagrams/01-system-components.svg | 1 + .../2026-10-20/diagrams/02-domain-types.mmd | 25 + .../2026-10-20/diagrams/02-domain-types.png | Bin 0 -> 41170 bytes .../2026-10-20/diagrams/02-domain-types.puml | 54 + .../2026-10-20/diagrams/02-domain-types.svg | 1 + .../2026-10-20/diagrams/03-input-dispatch.mmd | 28 + .../2026-10-20/diagrams/03-input-dispatch.png | Bin 0 -> 35048 bytes .../diagrams/03-input-dispatch.puml | 35 + .../2026-10-20/diagrams/03-input-dispatch.svg | 1 + .../diagrams/04-lighting-lifecycle.mmd | 21 + .../diagrams/04-lighting-lifecycle.png | Bin 0 -> 41442 bytes .../diagrams/04-lighting-lifecycle.puml | 26 + .../diagrams/04-lighting-lifecycle.svg | 1 + .../diagrams/05-lighting-call-candidates.dot | 24 + .../diagrams/05-lighting-call-candidates.svg | 177 ++ .../diagrams/06-nanoui-boundary.png | Bin 0 -> 24775 bytes .../diagrams/06-nanoui-boundary.puml | 30 + .../diagrams/06-nanoui-boundary.svg | 1 + .../persistence-services/help-sequence.mmd | 31 + .../persistence-services/help-sequence.png | Bin 0 -> 39001 bytes .../persistence-services/help-sequence.puml | 34 + .../persistence-services/help-sequence.svg | 1 + .../persistence-components.mmd | 19 + .../persistence-components.png | Bin 0 -> 38805 bytes .../persistence-components.puml | 40 + .../persistence-components.svg | 1 + .../2026-10-20/persistence-services/report.md | 93 + .../persistence-services/restart-state.mmd | 23 + .../persistence-services/restart-state.png | Bin 0 -> 46043 bytes .../persistence-services/restart-state.puml | 28 + .../persistence-services/restart-state.svg | 1 + .../save-load-sequence.mmd | 42 + .../save-load-sequence.png | Bin 0 -> 47684 bytes .../save-load-sequence.puml | 46 + .../save-load-sequence.svg | 1 + .../services-components.mmd | 20 + .../services-components.png | Bin 0 -> 47288 bytes .../services-components.puml | 55 + .../services-components.svg | 1 + .../runtime/01_runtime_components.mmd | 27 + .../runtime/01_runtime_components.png | Bin 0 -> 49041 bytes .../runtime/01_runtime_components.puml | 50 + .../runtime/01_runtime_components.svg | 1 + .../2026-10-20/runtime/02_round_lifecycle.mmd | 27 + .../2026-10-20/runtime/02_round_lifecycle.png | Bin 0 -> 50821 bytes .../runtime/02_round_lifecycle.puml | 36 + .../2026-10-20/runtime/02_round_lifecycle.svg | 1 + .../runtime/03_movement_sequence.mmd | 32 + .../runtime/03_movement_sequence.png | Bin 0 -> 52024 bytes .../runtime/03_movement_sequence.puml | 46 + .../runtime/03_movement_sequence.svg | 1 + .../2026-10-20/runtime/04_combat_dispatch.mmd | 26 + .../2026-10-20/runtime/04_combat_dispatch.png | Bin 0 -> 52664 bytes .../runtime/04_combat_dispatch.puml | 57 + .../2026-10-20/runtime/04_combat_dispatch.svg | 1 + .../runtime/05_crafting_sequence.mmd | 36 + .../runtime/05_crafting_sequence.png | Bin 0 -> 54318 bytes .../runtime/05_crafting_sequence.puml | 49 + .../runtime/05_crafting_sequence.svg | 1 + .../2026-10-20/runtime/06_research_model.mmd | 52 + .../2026-10-20/runtime/06_research_model.png | Bin 0 -> 49064 bytes .../2026-10-20/runtime/06_research_model.puml | 66 + .../2026-10-20/runtime/06_research_model.svg | 1 + .../2026-10-20/runtime/07_animal_ai.mmd | 24 + .../2026-10-20/runtime/07_animal_ai.png | Bin 0 -> 55611 bytes .../2026-10-20/runtime/07_animal_ai.puml | 35 + .../2026-10-20/runtime/07_animal_ai.svg | 1 + .../runtime/08_research_prerequisites.dot | 198 +++ .../runtime/08_research_prerequisites.mmd | 288 +++ .../runtime/08_research_prerequisites.svg | 1538 +++++++++++++++++ .../2026-10-20/runtime/09_process_state.mmd | 21 + .../2026-10-20/runtime/09_process_state.png | Bin 0 -> 45041 bytes .../2026-10-20/runtime/09_process_state.puml | 32 + .../2026-10-20/runtime/09_process_state.svg | 1 + .../architecture/2026-10-20/runtime/report.md | 121 ++ public/img/architecture-overview.png | Bin 0 -> 37623 bytes tools/check_architecture_atlas.py | 75 + 95 files changed, 4794 insertions(+) create mode 100644 architecture.md create mode 100644 architecture/audit.md create mode 100644 architecture/coverage.md create mode 100644 architecture/diagrams.md create mode 100644 architecture/persistence.md create mode 100644 architecture/runtime.md create mode 100644 architecture/validation.md create mode 100644 public/architecture/2026-10-20/Civ13-architecture-UML-atlas.pdf create mode 100644 public/architecture/2026-10-20/Civ13-architecture-audit-evidence.zip create mode 100644 public/architecture/2026-10-20/DIAGRAMS.md create mode 100644 public/architecture/2026-10-20/README.md create mode 100644 public/architecture/2026-10-20/SHA256SUMS.json create mode 100644 public/architecture/2026-10-20/SOURCE-GROUPS.md create mode 100644 public/architecture/2026-10-20/VALIDATION.md create mode 100644 public/architecture/2026-10-20/diagrams/01-system-components.mmd create mode 100644 public/architecture/2026-10-20/diagrams/01-system-components.png create mode 100644 public/architecture/2026-10-20/diagrams/01-system-components.puml create mode 100644 public/architecture/2026-10-20/diagrams/01-system-components.svg create mode 100644 public/architecture/2026-10-20/diagrams/02-domain-types.mmd create mode 100644 public/architecture/2026-10-20/diagrams/02-domain-types.png create mode 100644 public/architecture/2026-10-20/diagrams/02-domain-types.puml create mode 100644 public/architecture/2026-10-20/diagrams/02-domain-types.svg create mode 100644 public/architecture/2026-10-20/diagrams/03-input-dispatch.mmd create mode 100644 public/architecture/2026-10-20/diagrams/03-input-dispatch.png create mode 100644 public/architecture/2026-10-20/diagrams/03-input-dispatch.puml create mode 100644 public/architecture/2026-10-20/diagrams/03-input-dispatch.svg create mode 100644 public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.mmd create mode 100644 public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.png create mode 100644 public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.puml create mode 100644 public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.svg create mode 100644 public/architecture/2026-10-20/diagrams/05-lighting-call-candidates.dot create mode 100644 public/architecture/2026-10-20/diagrams/05-lighting-call-candidates.svg create mode 100644 public/architecture/2026-10-20/diagrams/06-nanoui-boundary.png create mode 100644 public/architecture/2026-10-20/diagrams/06-nanoui-boundary.puml create mode 100644 public/architecture/2026-10-20/diagrams/06-nanoui-boundary.svg create mode 100644 public/architecture/2026-10-20/persistence-services/help-sequence.mmd create mode 100644 public/architecture/2026-10-20/persistence-services/help-sequence.png create mode 100644 public/architecture/2026-10-20/persistence-services/help-sequence.puml create mode 100644 public/architecture/2026-10-20/persistence-services/help-sequence.svg create mode 100644 public/architecture/2026-10-20/persistence-services/persistence-components.mmd create mode 100644 public/architecture/2026-10-20/persistence-services/persistence-components.png create mode 100644 public/architecture/2026-10-20/persistence-services/persistence-components.puml create mode 100644 public/architecture/2026-10-20/persistence-services/persistence-components.svg create mode 100644 public/architecture/2026-10-20/persistence-services/report.md create mode 100644 public/architecture/2026-10-20/persistence-services/restart-state.mmd create mode 100644 public/architecture/2026-10-20/persistence-services/restart-state.png create mode 100644 public/architecture/2026-10-20/persistence-services/restart-state.puml create mode 100644 public/architecture/2026-10-20/persistence-services/restart-state.svg create mode 100644 public/architecture/2026-10-20/persistence-services/save-load-sequence.mmd create mode 100644 public/architecture/2026-10-20/persistence-services/save-load-sequence.png create mode 100644 public/architecture/2026-10-20/persistence-services/save-load-sequence.puml create mode 100644 public/architecture/2026-10-20/persistence-services/save-load-sequence.svg create mode 100644 public/architecture/2026-10-20/persistence-services/services-components.mmd create mode 100644 public/architecture/2026-10-20/persistence-services/services-components.png create mode 100644 public/architecture/2026-10-20/persistence-services/services-components.puml create mode 100644 public/architecture/2026-10-20/persistence-services/services-components.svg create mode 100644 public/architecture/2026-10-20/runtime/01_runtime_components.mmd create mode 100644 public/architecture/2026-10-20/runtime/01_runtime_components.png create mode 100644 public/architecture/2026-10-20/runtime/01_runtime_components.puml create mode 100644 public/architecture/2026-10-20/runtime/01_runtime_components.svg create mode 100644 public/architecture/2026-10-20/runtime/02_round_lifecycle.mmd create mode 100644 public/architecture/2026-10-20/runtime/02_round_lifecycle.png create mode 100644 public/architecture/2026-10-20/runtime/02_round_lifecycle.puml create mode 100644 public/architecture/2026-10-20/runtime/02_round_lifecycle.svg create mode 100644 public/architecture/2026-10-20/runtime/03_movement_sequence.mmd create mode 100644 public/architecture/2026-10-20/runtime/03_movement_sequence.png create mode 100644 public/architecture/2026-10-20/runtime/03_movement_sequence.puml create mode 100644 public/architecture/2026-10-20/runtime/03_movement_sequence.svg create mode 100644 public/architecture/2026-10-20/runtime/04_combat_dispatch.mmd create mode 100644 public/architecture/2026-10-20/runtime/04_combat_dispatch.png create mode 100644 public/architecture/2026-10-20/runtime/04_combat_dispatch.puml create mode 100644 public/architecture/2026-10-20/runtime/04_combat_dispatch.svg create mode 100644 public/architecture/2026-10-20/runtime/05_crafting_sequence.mmd create mode 100644 public/architecture/2026-10-20/runtime/05_crafting_sequence.png create mode 100644 public/architecture/2026-10-20/runtime/05_crafting_sequence.puml create mode 100644 public/architecture/2026-10-20/runtime/05_crafting_sequence.svg create mode 100644 public/architecture/2026-10-20/runtime/06_research_model.mmd create mode 100644 public/architecture/2026-10-20/runtime/06_research_model.png create mode 100644 public/architecture/2026-10-20/runtime/06_research_model.puml create mode 100644 public/architecture/2026-10-20/runtime/06_research_model.svg create mode 100644 public/architecture/2026-10-20/runtime/07_animal_ai.mmd create mode 100644 public/architecture/2026-10-20/runtime/07_animal_ai.png create mode 100644 public/architecture/2026-10-20/runtime/07_animal_ai.puml create mode 100644 public/architecture/2026-10-20/runtime/07_animal_ai.svg create mode 100644 public/architecture/2026-10-20/runtime/08_research_prerequisites.dot create mode 100644 public/architecture/2026-10-20/runtime/08_research_prerequisites.mmd create mode 100644 public/architecture/2026-10-20/runtime/08_research_prerequisites.svg create mode 100644 public/architecture/2026-10-20/runtime/09_process_state.mmd create mode 100644 public/architecture/2026-10-20/runtime/09_process_state.png create mode 100644 public/architecture/2026-10-20/runtime/09_process_state.puml create mode 100644 public/architecture/2026-10-20/runtime/09_process_state.svg create mode 100644 public/architecture/2026-10-20/runtime/report.md create mode 100644 public/img/architecture-overview.png create mode 100644 tools/check_architecture_atlas.py diff --git a/.github/workflows/jekyll-build.yml b/.github/workflows/jekyll-build.yml index 95e0d58..5284dc7 100644 --- a/.github/workflows/jekyll-build.yml +++ b/.github/workflows/jekyll-build.yml @@ -38,6 +38,8 @@ jobs: node tools/check_roadmap.cjs _site - name: Validate generated previews and fallback metadata run: python3 tools/check_site_previews.py _site + - name: Validate architecture atlas and preserved downloads + run: python3 tools/check_architecture_atlas.py _site - name: Exercise serialization, invalid payloads, and alternate origins run: python3 tools/test_previews.py - name: Upload validated site diff --git a/architecture.md b/architecture.md new file mode 100644 index 0000000..bc07666 --- /dev/null +++ b/architecture.md @@ -0,0 +1,57 @@ +--- +layout: page +title: "UML Atlas" +permalink: /architecture/ +description: "Explore Civ13 architecture with 18 UML diagrams, source-linked reports and downloadable evidence." +image: + path: /public/img/architecture-overview.png + width: 1922 + height: 573 + alt: Civ13 architecture component overview +--- + +
Source snapshot · 20 October 2026
+ +Explore the game's architecture through readable UML views, source-linked reports and a reproducible inventory. This atlas describes [Civ13/Civ13 at 5bf351248de6](https://github.com/Civ13/Civ13/tree/5bf351248de6050876fe5b53f91209a970cc5668), not the state of a deployed server or unmerged changes. + + + +[Read the audit]({{ '/architecture/audit/' | relative_url }}) · [Browse the diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Validation and limits]({{ '/architecture/validation/' | relative_url }}) + +
+
+Open the overview image for a full-size, zoomable SVG.
+
+## Downloads
+
+- [UML atlas PDF · 19 pages · 1.4 MB]({{ '/public/architecture/2026-10-20/Civ13-architecture-UML-atlas.pdf' | relative_url }})
+- [Complete evidence bundle · ZIP · 11.2 MB]({{ '/public/architecture/2026-10-20/Civ13-architecture-audit-evidence.zip' | relative_url }})
+
+The bundle contains editable PlantUML/Mermaid sources, rendered diagrams, reports, machine-readable inventories and reproduction tools. Large call-site tables are downloadable rather than rendered into this page.
+
+## Explore by subject
+
+- [Runtime and gameplay]({{ '/architecture/runtime/' | relative_url }}): startup, scheduler ownership, rounds, movement, combat, crafting, research and AI.
+- [Persistence and services]({{ '/architecture/persistence/' | relative_url }}): save/load ownership, restart recovery, Help, file spools and external boundaries.
+- [Diagram gallery]({{ '/architecture/diagrams/' | relative_url }}): 18 UML views plus two explicitly labeled dependency/call-candidate graphs.
+- [Source-group coverage]({{ '/architecture/coverage/' | relative_url }}): 46 source groups and their inventory counts.
+
+## What was inventoried?
+
+- **1,462** tracked DM files.
+- **1,257** files in the root environment's textual include closure, totaling **383,278** lines.
+- **93** registered research nodes and **99** prerequisite edges.
+- **215** source links checked for existing files and valid line ranges.
+
+These are file and lexical inventory counts, not compiler-certified symbol totals or runtime coverage percentages. Included, activated and deployed are different claims.
+
+## Main review targets
+
+1. Different restart paths use different recovery contracts.
+2. Scheduler comments and included controller infrastructure do not always establish actual ownership or activation.
+3. Custom persistence couples domain state, transient-field exclusions and derived-state reconstruction.
+4. Click, Topic, UI, callbacks and service spools have distinct entry-point and authority boundaries.
+
+These are architectural review concerns, not asserted runtime defects or a security certification. See the [full audit]({{ '/architecture/audit/' | relative_url }}) for evidence and recommended next steps.
diff --git a/architecture/audit.md b/architecture/audit.md
new file mode 100644
index 0000000..3ce9b63
--- /dev/null
+++ b/architecture/audit.md
@@ -0,0 +1,113 @@
+---
+layout: default
+title: "Architecture audit"
+permalink: /architecture/audit/
+description: "Source-pinned Civ13 architecture, UML diagrams, evidence boundaries and downloadable audit artifacts."
+image:
+ path: /public/img/architecture-overview.png
+ width: 1922
+ height: 573
+ alt: Civ13 architecture component overview
+---
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
+
+# Civ13 architecture audit and UML atlas
+
+Audit date: 2026-10-20. Source: [Civ13/Civ13 master at 5bf351248de6050876fe5b53f91209a970cc5668](https://github.com/Civ13/Civ13/tree/5bf351248de6050876fe5b53f91209a970cc5668). This is an immutable source snapshot, not a report of the deployed server or unmerged pull requests.
+
+## Executive result
+
+Civ13 is a BYOND/DM game with a large subtype/content tree, global registries and singleton controllers, a legacy process scheduler, independent yielded/deferred activities, map-specific round policy, and custom durable persistence. Its architecture cannot be understood as one linear main loop. Native BYOND events, virtual proc overrides, hook enumeration, queued callbacks, browser Topic messages, file spools and world reloads all add entry points.
+
+The atlas covers the entire tracked DM file inventory and the literal include closure of civ13.dme. It provides focused UML views of the important lifecycle and subsystem interactions, plus searchable source-linked declarations, inheritance candidates, call sites, control sites and unresolved/dynamic sites. It does **not** claim that all possible executable runtime paths have been enumerated. Loops, recursion, dynamic dispatch, mutable types/data, timing and external input make that set unbounded; a lexical scan cannot prove path feasibility or reachability.
+
+### Findings that matter
+
+1. **Scheduler ownership needs an executable source of truth.** Legacy /process scheduling coexists with included MC/timer infrastructure and independent movement/spawn loops. Comments suggesting subsystem ownership do not establish active routing. Keep lifecycle diagrams tied to actual startup and registration, not only file names. See [runtime audit]({{ '/architecture/runtime/' | relative_url }}).
+2. **Restart contracts differ.** Owned transactional restart recovery and scheduled maintenance save/reboot do not have the same completion/intent contract. This is a design consistency review target, not a demonstrated data-loss defect. See [persistence audit]({{ '/architecture/persistence/' | relative_url }}).
+3. **Persistence crosses nearly every domain.** A custom variable serializer, explicit runtime-field exclusions, durable graph schemas and identity restoration must evolve together. A new transient pointer/clock or cross-level relationship can invalidate save assumptions. Treat schema/ownership review as a feature gate, not an optional follow-up.
+4. **Entry-point and authority boundaries are distributed.** Click, native client/world callbacks, NanoUI, direct Topic handlers, admin verbs, Discord spools and Help worker exchanges have different gates. The presence of one UI or client gate does not prove that every alternate entry route is protected. No security vulnerability is asserted by this architecture audit.
+5. **Derived state has distinct reconstruction phases.** Lighting corners/overlays, processing registries, runtime reservations and restored-round daylight are not interchangeable with ordinary saved gameplay state. Startup and restoration should have separately testable invariants.
+6. **Names and comments can overstate behavior.** The preferencesSQLite directory uses delimiter-file storage on the audited path. Research comments describe optional prototype shortcuts while executable research completion requires the prototype gate. Distinguish documentation debt from proven functional bugs.
+7. **Included, activated and deployed are different claims.** Experimental gameplay bridge and immutable_capture sources are outside the main include closure. Human sub-tile movement is included but defaults disabled. Bot-service deployment is separately blocked by repository guidance. This audit changes none of those states.
+
+## Coverage and evidence strength
+
+| Scope | Result |
+|---|---:|
+| Tracked DM files inventoried | 1,462 |
+| Tracked DM source lines | 415,124 |
+| DM files in textual include closure | 1,257 |
+| Source lines in that closure | 383,278 |
+| Included proc declaration candidates | 14,081 |
+| Included type declaration/reopening candidates | 13,131 |
+| Tracked support files inventoried (selected source/map/UI/workflow extensions) | 660 |
+| Python AST function/class declarations | 2,036 |
+| Python parse errors | 0 |
+
+These are inventory counts, not compiler-certified symbol totals or a percentage of runtime behavior tested. Included types can be reopened; proc declarations can be conditionally compiled or macro-generated. Explicit parent_type overrides are recorded separately from path-default ancestry. All tracked DM files are scanned, including excluded tests and experimental sources; use in_include_union to filter production candidates.
+
+The include closure is a **conditional union**: literal includes are followed without evaluating preprocessor conditions. No claim is made that every union member executes, or even that every union member is compiled in every configuration. The default map include is maps/nomads/nomads.dmm; other map content and runtime configuration can change reachability. Source path and SHA-256 are recorded per file.
+
+### Evidence levels
+
+- **File accounting:** complete for Git-tracked .dm files at the pin; repeatable hashing and literal include reachability.
+- **Lexical inventory:** conservative source navigation aids, not a DM compiler AST. Proc/type recognition uses path and indentation heuristics. Macro expansion, braces/multiline edge cases and quoted interpolation can escape symbol recognition.
+- **Call candidates:** call-sites.csv records spellings and receivers; call-target-name-index.json lists same-name declaration candidates. Joining them is not proof of an edge. Native builtins, macros, inherited dispatch and dynamic receivers remain unresolved.
+- **Control sites:** conditions, loops, yields and returns are indexed. lexical-order-edges.csv contains consecutive source-statement navigation edges only. It is deliberately **not** labeled an executable CFG.
+- **Manual diagrams:** selected source-traced architecture abstractions with direct supporting links in reports. They omit incidental branches for readability; their notes identify the abstraction boundary.
+- **Runtime evidence:** none newly generated. No DreamDaemon, game client, live save/load, deployed service, external model or network bridge was exercised. No source edits, commits, PRs, feature activation or deployment occurred.
+
+## Read the atlas
+
+Start with the rendered overview and core type diagram in diagrams/. Then follow runtime/report.md for scheduler, startup, movement/combat, crafting/research and AI; persistence-services/report.md for save/load/restart and external services. Source diagrams are editable PlantUML (.puml) and Mermaid (.mmd). Graphviz (.dot) is used only for explicitly labeled lexical call-candidate views.
+
+[Diagram index]({{ '/architecture/diagrams/' | relative_url }}) lists the rendered outputs and source files. SVG is zoomable; PNG is convenient for previews. The PDF atlas collects the rendered diagrams with captions.
+
+### Additional source-traced boundaries
+
+- [atom.Click and mob.ClickOn](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/_onclick/click.dm#L7): native entry forwards through usr, then target/click-clock/modifier gates and type-specific behavior. Numerous subtype overrides and early exits prevent a single universal attack path. The input sequence is a conceptual dispatch skeleton, not a statement-order proof.
+- [client.Topic](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/client/client_procs.dm#L23): current usr/mob guard precedes routing. Direct handlers still own their own authorization and validation.
+- [NanoUI Topic](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/nano/_nanoui.dm#L494): updates status, requires interactive status and matching user, calls src_object.Topic and then updates associated UIs. [Topic-state policies](https://github.com/Civ13/Civ13/tree/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/nano/interaction) encode different physical/admin/inventory/remote contexts.
+- [Lighting construction](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/lighting/lighting_system.dm#L99): first constructs shared corners with deferred activity, then ordinary and compatibility overlays, activates fresh/existing corners, and releases readiness flags. Exceptions clear readiness and rethrow. Restored rounds use [apply_restored_lighting](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/lighting/lighting_system.dm#L138), not an assumption that fresh-round setup ran.
+- [Dynamic hooks](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/hooks.dm#L50): text2path + typesof + call builds runtime dispatch from a hook name. A name-only call graph cannot recover all these edges without language/type information.
+
+## Machine-readable inventory
+
+- files.csv: all tracked DM files, include-union membership, line/byte counts, SHA-256, source permalink.
+- includes.csv: literal include edges, location and existence checks.
+- declarations.csv: proc and type declaration candidates, reopenings and exact source anchors.
+- inheritance.csv: path-default ancestry candidates plus explicit parent_type overrides. Resolve overrides before using as a final type tree.
+- call-sites.csv and call-target-name-index.json: call spellings, receiver text, source-proc association and possible same-name declarations.
+- control-sites.csv: indexed control/yield statements.
+- statements.csv and lexical-order-edges.csv: source-order navigation within recognized procs, not executable flow.
+- dynamic-unresolved.csv: construction, reflection, hooks/callbacks, spawn/sleep, macro and opaque interpolation markers. A marker can be duplicated for different reasons; totals are sites/markers, not unique defects.
+- preprocessor.csv: directives requiring a real preprocessing pass for exact compilation configuration.
+- subsystem-coverage.csv: 46 source groups and their inventory counts.
+- support-files.csv: selected non-DM source/UI/map/workflow inventory; Python AST declarations and imports are separate tables. This is not an AST/control-flow audit of every JavaScript, shell, PowerShell or map file.
+- coverage.json: machine-readable pin, totals and limitations; check-results.txt: executed accounting/anchor checks.
+
+## Recommended next engineering steps
+
+1. Adopt the inventory as a baseline, then obtain a compiler-backed, configuration-specific DM symbol/type graph. Add explicit engine entry-point roots, parent_type resolution, macro expansion and virtual dispatch sets; do not relabel lexical edges as precise calls.
+2. Make an entry-point matrix for native callbacks, verbs, Topic handlers, timers, hooks and file spools, with authority/lifetime requirements and tests per route.
+3. Document one scheduler ownership model and verify each active worker's startup, cancellation, budget and teardown paths. Remove misleading subsystem comments only after behavior is confirmed.
+4. Review restart/save contracts together, then add cross-path tests of completed-generation selection and failure holds before consolidating code.
+5. Require explicit persistence decisions for new fields and schema changes, including restored references, transient clocks, resource ownership and derived registries.
+6. For each high-risk sequence, add bounded integration/mutation tests plus real-client checks where rendering, movement timing or dispatch depends on a connected client. Existing fixture success is not blanket server acceptance.
+
+No broad refactor is recommended solely on this static audit. First improve contracts and evidence at the boundaries above, then use narrowly scoped changes with regression coverage.
+
+## Reproduce
+
+Use a clean checkout of the exact pin. Run tools/build_inventory.py with the checkout and inventory output directory, then tools/summarize_inventory.py and tools/check_inventory.py. The scripts use Python standard library and do not execute repository code.
+
+Example: python tools/build_inventory.py SOURCE_ROOT OUTPUT_ROOT/inventory
+
+To explore a proc name: python tools/query_graph.py inventory create_lighting output.dot 45, then dot -Tsvg output.dot -o output.svg. The graph explicitly labels candidate edges and reports truncation. The default node cap is 80; changing it does not improve semantic precision.
+
+Diagram render versions and verification results are recorded in VALIDATION.md. Read source reports for the evidence behind each manually drawn interaction. All repository source remains unmodified.
+
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
diff --git a/architecture/coverage.md b/architecture/coverage.md
new file mode 100644
index 0000000..5b509ac
--- /dev/null
+++ b/architecture/coverage.md
@@ -0,0 +1,69 @@
+---
+layout: default
+title: "Source coverage"
+permalink: /architecture/coverage/
+description: "Source-pinned Civ13 architecture, UML diagrams, evidence boundaries and downloadable audit artifacts."
+image:
+ path: /public/img/architecture-overview.png
+ width: 1922
+ height: 573
+ alt: Civ13 architecture component overview
+---
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
+
+# Source-group coverage
+
+Counts are lexical include-union inventory, not proven runtime coverage.
+
+| Source group | Files | Lines | Proc candidates | Type declarations | Call sites |
+|---|---:|---:|---:|---:|---:|
+| code/__defines | 41 | 1966 | 15 | 0 | 43 |
+| code/_globalvars | 1 | 25 | 0 | 0 | 18 |
+| code/_helpers | 30 | 5970 | 350 | 9 | 1255 |
+| code/_onclick | 15 | 3702 | 244 | 94 | 714 |
+| code/controllers | 6 | 1675 | 51 | 5 | 187 |
+| code/datums | 26 | 3168 | 151 | 39 | 687 |
+| code/game/area | 2 | 1757 | 11 | 363 | 131 |
+| code/game/atoms.dm | 1 | 606 | 39 | 1 | 233 |
+| code/game/atoms_movable.dm | 1 | 318 | 20 | 2 | 81 |
+| code/game/base_turf.dm | 1 | 14 | 2 | 0 | 2 |
+| code/game/core.dm | 1 | 41 | 1 | 0 | 11 |
+| code/game/dna | 2 | 459 | 33 | 1 | 127 |
+| code/game/gameticker.dm | 1 | 346 | 8 | 1 | 68 |
+| code/game/jobs | 2 | 1015 | 24 | 2 | 237 |
+| code/game/lobby_music_player.dm | 1 | 53 | 4 | 1 | 14 |
+| code/game/mob | 172 | 44254 | 1703 | 630 | 12891 |
+| code/game/objects | 373 | 94620 | 4123 | 3407 | 25427 |
+| code/game/sound.dm | 1 | 657 | 4 | 0 | 223 |
+| code/game/turfs | 21 | 6818 | 204 | 561 | 1712 |
+| code/js | 1 | 37 | 0 | 0 | 0 |
+| code/modules/1713 | 238 | 135131 | 3744 | 5578 | 49598 |
+| code/modules/admin | 54 | 10568 | 299 | 30 | 2998 |
+| code/modules/chat | 1 | 128 | 7 | 2 | 31 |
+| code/modules/client | 18 | 2687 | 136 | 37 | 658 |
+| code/modules/collectibles | 3 | 1770 | 38 | 111 | 266 |
+| code/modules/dmm_suite | 2 | 304 | 9 | 2 | 81 |
+| code/modules/error_handler | 4 | 353 | 14 | 4 | 67 |
+| code/modules/flufftext | 2 | 106 | 6 | 0 | 40 |
+| code/modules/lighting | 9 | 1130 | 63 | 6 | 184 |
+| code/modules/magic | 15 | 7686 | 260 | 278 | 1878 |
+| code/modules/materials | 2 | 2353 | 79 | 170 | 180 |
+| code/modules/multiz | 7 | 1087 | 67 | 42 | 279 |
+| code/modules/nano | 23 | 1611 | 116 | 14 | 427 |
+| code/modules/organs | 15 | 3642 | 190 | 69 | 855 |
+| code/modules/persistence | 14 | 2896 | 173 | 26 | 1408 |
+| code/modules/projectiles | 18 | 6968 | 220 | 321 | 1572 |
+| code/modules/reagents | 40 | 17735 | 872 | 1111 | 4125 |
+| code/modules/research_tree | 7 | 3104 | 63 | 6 | 682 |
+| code/modules/statpanel | 1 | 180 | 6 | 1 | 69 |
+| code/modules/submarine | 12 | 6282 | 220 | 94 | 1135 |
+| code/modules/surgery | 12 | 1787 | 128 | 39 | 649 |
+| code/modules/webhooks | 1 | 49 | 11 | 0 | 21 |
+| code/modules/xgm | 2 | 387 | 25 | 3 | 55 |
+| code/processes | 43 | 4557 | 305 | 51 | 1019 |
+| code/root | 14 | 3103 | 43 | 8 | 534 |
+| interface | 1 | 173 | 0 | 12 | 3 |
+
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
diff --git a/architecture/diagrams.md b/architecture/diagrams.md
new file mode 100644
index 0000000..caece14
--- /dev/null
+++ b/architecture/diagrams.md
@@ -0,0 +1,145 @@
+---
+layout: default
+title: "Architecture diagrams"
+permalink: /architecture/diagrams/
+description: "Source-pinned Civ13 architecture, UML diagrams, evidence boundaries and downloadable audit artifacts."
+image:
+ path: /public/img/architecture-overview.png
+ width: 1922
+ height: 573
+ alt: Civ13 architecture component overview
+---
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
+
+# Architecture diagrams
+
+Source pin: [`5bf351248de6050876fe5b53f91209a970cc5668`](https://github.com/Civ13/Civ13/tree/5bf351248de6050876fe5b53f91209a970cc5668). These are static abstractions, not exhaustive runtime execution paths. Select an image or SVG link to zoom; editable sources are alongside each view.
+
+## System overview and boundaries
+
+### System components
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/diagrams/01-system-components.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/diagrams/01-system-components.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/diagrams/01-system-components.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/diagrams/01-system-components.mmd' | relative_url }})
+
+### Core domain types
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/diagrams/02-domain-types.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/diagrams/02-domain-types.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/diagrams/02-domain-types.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/diagrams/02-domain-types.mmd' | relative_url }})
+
+### Player input dispatch
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/diagrams/03-input-dispatch.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/diagrams/03-input-dispatch.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/diagrams/03-input-dispatch.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/diagrams/03-input-dispatch.mmd' | relative_url }})
+
+### Lighting lifecycle
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/diagrams/04-lighting-lifecycle.mmd' | relative_url }})
+
+### Lighting call-name candidates (not proven calls)
+
+This larger graph is provided as a separate zoomable SVG to keep this page lightweight.
+
+[SVG]({{ '/public/architecture/2026-10-20/diagrams/05-lighting-call-candidates.svg' | relative_url }}) · [DOT]({{ '/public/architecture/2026-10-20/diagrams/05-lighting-call-candidates.dot' | relative_url }})
+
+### NanoUI interaction boundary
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/diagrams/06-nanoui-boundary.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/diagrams/06-nanoui-boundary.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/diagrams/06-nanoui-boundary.puml' | relative_url }})
+
+## Runtime and gameplay
+
+### Runtime ownership
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/01_runtime_components.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/01_runtime_components.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/01_runtime_components.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/01_runtime_components.mmd' | relative_url }})
+
+### Round lifecycle
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/02_round_lifecycle.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/02_round_lifecycle.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/02_round_lifecycle.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/02_round_lifecycle.mmd' | relative_url }})
+
+### Movement and collision ownership
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/03_movement_sequence.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/03_movement_sequence.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/03_movement_sequence.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/03_movement_sequence.mmd' | relative_url }})
+
+### Combat dispatch
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/04_combat_dispatch.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/04_combat_dispatch.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/04_combat_dispatch.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/04_combat_dispatch.mmd' | relative_url }})
+
+### Crafting transaction
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/05_crafting_sequence.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/05_crafting_sequence.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/05_crafting_sequence.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/05_crafting_sequence.mmd' | relative_url }})
+
+### Research model
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/06_research_model.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/06_research_model.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/06_research_model.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/06_research_model.mmd' | relative_url }})
+
+### Animal AI states
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/07_animal_ai.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/07_animal_ai.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/07_animal_ai.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/07_animal_ai.mmd' | relative_url }})
+
+### Research prerequisites (dependency graph)
+
+This larger graph is provided as a separate zoomable SVG to keep this page lightweight.
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/08_research_prerequisites.svg' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/08_research_prerequisites.mmd' | relative_url }}) · [DOT]({{ '/public/architecture/2026-10-20/runtime/08_research_prerequisites.dot' | relative_url }})
+
+### Process lifecycle
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/runtime/09_process_state.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/runtime/09_process_state.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/runtime/09_process_state.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/runtime/09_process_state.mmd' | relative_url }})
+
+## Persistence and services
+
+### Help service sequence
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/persistence-services/help-sequence.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/persistence-services/help-sequence.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/persistence-services/help-sequence.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/persistence-services/help-sequence.mmd' | relative_url }})
+
+### Persistence components
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/persistence-services/persistence-components.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/persistence-services/persistence-components.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/persistence-services/persistence-components.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/persistence-services/persistence-components.mmd' | relative_url }})
+
+### Restart recovery
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/persistence-services/restart-state.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/persistence-services/restart-state.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/persistence-services/restart-state.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/persistence-services/restart-state.mmd' | relative_url }})
+
+### Save and load sequence
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/persistence-services/save-load-sequence.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/persistence-services/save-load-sequence.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/persistence-services/save-load-sequence.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/persistence-services/save-load-sequence.mmd' | relative_url }})
+
+### External services
+
+
+
+[SVG]({{ '/public/architecture/2026-10-20/persistence-services/services-components.svg' | relative_url }}) · [PNG]({{ '/public/architecture/2026-10-20/persistence-services/services-components.png' | relative_url }}) · [PUML]({{ '/public/architecture/2026-10-20/persistence-services/services-components.puml' | relative_url }}) · [MMD]({{ '/public/architecture/2026-10-20/persistence-services/services-components.mmd' | relative_url }})
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
diff --git a/architecture/persistence.md b/architecture/persistence.md
new file mode 100644
index 0000000..4a9e91b
--- /dev/null
+++ b/architecture/persistence.md
@@ -0,0 +1,110 @@
+---
+layout: default
+title: "Persistence and services"
+permalink: /architecture/persistence/
+description: "Source-pinned Civ13 architecture, UML diagrams, evidence boundaries and downloadable audit artifacts."
+image:
+ path: /public/img/architecture-overview.png
+ width: 1922
+ height: 573
+ alt: Civ13 architecture component overview
+---
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
+
+# Persistence and service architecture audit
+
+Scope: static read-only audit of Civ13 master commit `5bf351248de6050876fe5b53f91209a970cc5668`. No compilation, native runtime, paid model request, service action, or deployment was performed. Diagrams describe selected architecture-level paths and explicit branch families, not an exhaustive dynamic execution proof. Files present in the repository do not establish deployment. Mermaid component-like flowcharts are not formal UML component syntax.
+
+## Production boundary and ownership
+
+The main DME includes persistence functions, restart transaction, lifecycle control, durable graph/contract/timer/environment/world code, player reclaim, loader, and saver. It also includes the Help service, Python control process, preferences, and webhook code. `immutable_capture.dm` is absent from the main DME and appears in isolated test includes; the private gameplay bridge explicitly states it is not included. Do not conflate optional/test source with live production paths.
+
+Sources: [civ13.dme:1111-1124](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/civ13.dme#L1111-L1124); [civ13.dme:1215-1245](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/civ13.dme#L1215-L1245); [code/modules/gameplay_bridge/bridge.dm:1-4](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/gameplay_bridge/bridge.dm#L1-L4).
+
+`map_storage` is the serialization coordinator. `ticker.savemap` and `ticker.loadmap` wrap the backend with admission, exception handling and cleanup. `begin_persistence_operation` creates a unique `persistence_world_operation`; an active identity, not merely a boolean busy flag, owns release. It rejects existing operations, failed-load/dimension holds, active z reservations and conflicting restart intent. Backend and content entry are each one-shot. Direct Save_World/Load_World calls acquire an operation too, but the ticker load wrapper additionally supplies the preflight/clear/metadata/reclaim lifecycle; direct backend calls must not be modeled as equivalent to full ticker restoration.
+
+Sources: [code/modules/persistence/functions.dm:290-365](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/functions.dm#L290-L365); [code/modules/persistence/functions.dm:400-464](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/functions.dm#L400-L464).
+
+## Save graph and completed generations
+
+1. Admit the operation, prepare durable account ownership, capture supported durable world and round state, generate a round-v1/v2 identity.
+2. If a completed generation exists, invalidate the old backup marker, copy the old generation files, and copy its completion marker last. Only then invalidate the active marker. This preserves a prior completed generation before replacement.
+3. Write map metadata; for each z-level create a native savefile containing version, dimensions and generation. Traverse turfs and recursively selected objects/mobs; serialize changed fields, contents, and typed list/value envelopes. Explicit list identity preserves aliases/cycles.
+4. Finalize the separate durable graph (when opted in), write round.json, then publish save_complete.txt last. A partial save without that marker is not an accepted recovery point.
+
+The serializer excludes clients, map metadata objects, ignored types, should_save=false objects, spatial/session identity fields and `persistence_runtime_var` fields. This custom serializer visits tmp fields: tmp alone does not guarantee exclusion. `before_save_context` can participate through owned export frames and declared save transfers. A cross-z movable reference in a per-level object graph is rejected, not silently flattened. The separate durable metadata graph binds existing per-level entries without constructing a second leader/body.
+
+Sources: [code/modules/persistence/saving.dm:9-181](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/saving.dm#L9-L181); [code/modules/persistence/functions.dm:14-76](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/functions.dm#L14-L76); [code/modules/persistence/durable_graph.dm:1-109](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/durable_graph.dm#L1-L109).
+
+Durable metadata is opt-in by exact map profile, not universal world persistence. Schemas cover map/faction/research/economic state, environment, selected area/weather fields, timers, and bounded faction icon pixels. Timers and clock fields encode remainders/origins instead of copying a previous process clock. Capture rejects active seasonal/weather/lighting transitions. Extending map subtypes or adding state requires reviewing the schema and timer inventory, not merely adding a field.
+
+Sources: [code/modules/persistence/durable_contract.dm:1-86](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/durable_contract.dm#L1-L86); [code/modules/persistence/durable_world.dm:1-45](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/durable_world.dm#L1-L45); [code/modules/persistence/durable_timers.dm:1-70](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/durable_timers.dm#L1-L70).
+
+## Load, rebuild, and reconnect
+
+`ticker.loadmap` owns admission across dimension preparation, full save validation, mutation, restoration, and player callbacks. Validation checks marker, matching map metadata, round identity, dimensions, full grids, valid types, entry references, duplicate player ownership, and durable graph/schema. Dimension growth has its own reservation/recovery gate; rejection can retain a hold to prevent overwrite.
+
+After preflight, the wrapper snapshots the header, verifies an expected restart generation, requires durable world idle, marks mutation started, resets player restoration, suspends durable callbacks, and clears the map. The backend allocates every turf before loading references, indexes same-level turfs, loads recursive entries, invokes after_load, registers restored players, then rebuilds opacity and lighting. Metadata, durable world, and round phase/lighting are restored afterward. A post-mutation failure latches recovery; this is fail-closed restoration, not rollback of a partially mutated world.
+
+Sources: [code/modules/persistence/functions.dm:420-464](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/functions.dm#L420-L464); [code/modules/persistence/functions.dm:684-754](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/functions.dm#L684-L754); [code/modules/persistence/loading.dm:183-354](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/loading.dm#L183-L354).
+
+Durable player ownership is a normalized non-guest authenticated ckey, distinct from transient client/key fields. Preparation rejects ambiguous ownership; reconnect only claims one living, located, unoccupied restored human, checks playing/server bans, consumes the reservation, transfers the authenticated client's key through normal Login, and deletes the lobby. Restart recovery waits until its intent is consumed before reclaiming waiting clients. No Help conversation is restored with the body.
+
+Sources: [code/modules/persistence/player_reclaim.dm:1-116](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/player_reclaim.dm#L1-L116); [code/modules/persistence/restart_transaction.dm:156-185](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/restart_transaction.dm#L156-L185).
+
+## Restart state machine and deployment lifecycle
+
+The validated restart transaction supports native BYOND durable metadata profiles (reported in source as Gaia/Europe) and explicitly rejects OpenDream. It saves and validates a completed generation, writes a one-shot restart_intent.json binding generation/metadata/round hashes, rereads it, revalidates ownership, then requests native restart or graceful world deletion. Startup detects the intent before normal setup, holds fresh-round/player paths, prepares dimensions, validates the same generation, imports once, consumes only the matching intent and then releases player restoration. Malformed/mismatched intent, failed dimension admission, incomplete import, or failed intent deletion retains a recovery hold. An import that already began and failed is not retried into the same mutated world.
+
+There are two distinct persistence boot routes. PERSISTENCE configuration autoloads a matching completed ordinary save; an explicit restart intent applies independently of that gamemode. Scheduled maintenance is a separate save -> completion-marker check -> ordinary Reboot path, rather than `persistence_restart.execute`. This divergence is a review target, not a demonstrated defect: its recovery contract depends on ordinary PERSISTENCE autoload, whereas the transaction binds a specific generation.
+
+Sources: [code/modules/persistence/restart_transaction.dm:77-185](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/restart_transaction.dm#L77-L185); [code/setup.dm:136-172](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/setup.dm#L136-L172); [code/world.dm:356-398](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L356-L398).
+
+The compiled local lifecycle Topic endpoint requires IPv4 loopback, configured token/revision, exact allowed keys/actions and boot-session/operation binding. It exposes status, bounded diagnostics and save_shutdown, not arbitrary eval or shell. Operations have replay protection and a bounded operation count. The Python Nomads supervisor is explicitly restricted to port 1714 and NOMADS_EUROPE: fetch exact commit, detached build, generate catalog, switch that isolated checkout's map include, require clean compilation, hash binaries, ensure owned process/session identity, defer update with clients or busy save, request bound save/shutdown, snapshot validated files, launch a fresh run directory, and wait for matched restoration/readiness. Unexpected exit, mismatch or timeout preserves evidence rather than automatically starting a fresh round. These are source contracts, not proof that this supervisor is installed or running.
+
+Sources: [code/modules/persistence/nomads_lifecycle.dm:70-108](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/persistence/nomads_lifecycle.dm#L70-L108); [scripts/nomads-lifecycle/supervisor.py:222-422](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/nomads-lifecycle/supervisor.py#L222-L422).
+
+## External service and file boundaries
+
+- Help: authenticated client verb -> service availability/rate-limit/queue admission -> bounded JSON request and ready marker -> separate Python bridge -> approved player corpus/recipe/wiki retrieval -> configured Ollama HTTP endpoint -> atomic bounded response -> DM id and client-generation checks -> escaped/bounded renderer. Account identity is salted before spooling; conversation history is client-session-only with generation and action tokens. There are eight queue slots; configured worker count is one or two. Bridge startup clears old spool requests instead of replaying them. HTTP uses a separate deadline-bounded child, disables environment proxies and redirects, and optional credentials come from an environment variable. The model has no tools/actions. File deletion is not encryption or guaranteed crash-time erasure.
+- Discord: world messaging loop polls SQL/discord2ooc, discord2admin, discord2dm, discord2ban and discord2unban files, splits delimiter fields, dispatches chat/moderation and deletes consumed files. The local file writer and OS permissions are therefore a privileged integration boundary. This checkout does not contain the deployed bot implementation or establish who can write those files.
+- Preferences: despite the preferencesSQLite folder and SQL path names, inspected code reads/writes delimiter-encoded SQL/charprefs.txt. Existing-account update deletes/rebuilds that file; there is no database transaction shown on this path. Do not label it SQLite storage based on the folder name.
+- Webhooks: optional configured address/key gates outgoing asynchronously spawned world.Export calls with URL-encoded JSON. Login webhook fields can include ckey/IP/CID. Endpoint configuration, logging and access should be treated as privacy/security boundaries; no deployed endpoint was inspected.
+- World Topic: rate-limited public status/ping dispatch uses registered world_topic subtypes, with lifecycle handled separately through the restricted endpoint. This is different from object Topic/UI dispatch.
+- Script control: native `/process/python/execute` rate-limits invocation and delegates to shell Python scripts (sudo on Unix); OpenDream instead permits only fixed mapswap/restart spool actions. The process fire method is a no-op, so its registration does not imply autonomous command execution.
+
+Sources: [code/game/mob/player_help.dm:24-218](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/player_help.dm#L24-L218); [code/game/mob/player_help.dm:291-405](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/player_help.dm#L291-L405); [scripts/player_help_bridge.py:303-359](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/player_help_bridge.py#L303-L359); [scripts/player_help_bridge.py:462-641](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/player_help_bridge.py#L462-L641); [code/world.dm:183-232](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L183-L232); [code/world.dm:400-471](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L400-L471); [code/modules/client/preferencesSQLite/preferences_saving&loading&del.dm:1-124](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/client/preferencesSQLite/preferences_saving%26loading%26del.dm#L1-L124); [code/modules/webhooks/webhooks.dm:31-49](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/webhooks/webhooks.dm#L31-L49); [code/processes/python.dm:1-58](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/python.dm#L1-L58).
+
+## Launch, CI, and optional tooling
+
+Legacy launch.py and updateserver.py pull/reset a configured checkout, generate the crafting catalog, invoke DreamMaker, copy binaries/config and (launch only) start trusted DreamDaemon. These are not the transaction supervisor. Several shell steps use os.system without checked return values, unlike the checked catalog generation. Review this legacy deployment path before relying on failure containment; no failed deployment was reproduced.
+
+The main CI workflow uses reusable change selection, an offline evidence-checker job and a build job with conditional compilation/native fixture lanes. BYOND is pinned to 516.1681. Documentation-only changes can skip game compilation; extensive/new-test selectors govern many native fixtures and negative controls. A source-defined CI step is not a passing run, and fixture success is not connected-client or deployed-server acceptance. Other repository workflows cover tooling, documentation and review automation; this report does not certify their external secrets or execution history.
+
+Bot service control is default-off and its README explicitly says not to install/enable the draft unit yet: independent game supervision and bot-restart/game-survival acceptance are prerequisites. The helper's fixed service actions, nonblocking lock and cooldown are narrower than the legacy shell pathway. The gameplay bridge and immutable capture are separate non-production/test mechanisms at this commit, not live Help or live save replacements.
+
+Sources: [scripts/travis_pre_byond.sh:1-32](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/travis_pre_byond.sh#L1-L32); [scripts/launch.py:1-53](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/launch.py#L1-L53); [scripts/updateserver.py:1-46](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/updateserver.py#L1-L46); [.github/workflows/test.yml:58-172](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/.github/workflows/test.yml#L58-L172); [scripts/bot-service/README.md:1-92](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/scripts/bot-service/README.md#L1-L92); [code/modules/gameplay_bridge/bridge.dm:1-4](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/gameplay_bridge/bridge.dm#L1-L4); [tests/world_save/immutable_capture.dme:1-14](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/tests/world_save/immutable_capture.dme#L1-L14).
+
+## Architectural risks and next verification targets
+
+1. **Yielding snapshot semantics:** completed generation integrity is stronger than atomic gameplay snapshot semantics. Tick checks and hooks yield. Audit every state-changing subsystem's save gate and verify invariants under interleaving; do not claim transactional world freeze.
+2. **Schema/exclusion maintenance:** changed-vars traversal and explicit tmp exclusions create a continuing obligation for new fields, callbacks, timers, caches and cross-z references. Pair schema changes with disk roundtrip and legacy migration controls.
+3. **Recovery availability:** fail-closed holds protect data from overwrite but require an operator recovery runbook. Preserve the original compiled map and matched complete files; distinguish preflight rejection from post-mutation failure.
+4. **Two restart contracts:** consolidate or explicitly document scheduled-maintenance ordinary autoload versus generation-bound transactional restart. Test both, including interrupted writes and intent consumption failures.
+5. **File IPC privilege and durability:** Discord moderation, preference rewrites, Help and supervisor files have different formats and trust assumptions. Review ownership/permissions, concurrent writers, restart cleanup, partial writes and retention separately; one spool's safeguards do not automatically cover another.
+6. **Legacy deployment versus owned supervisor:** legacy shell launch has different error/ownership semantics and elevated commands. Confirm which path the host actually uses before making operational guarantees.
+7. **Evidence separation:** tests, disabled sources, authored CI lanes, historical documentation and actual deployed behavior are distinct evidence classes. This audit establishes static contracts only.
+
+## Diagram index
+
+- `persistence-components.mmd`: compiled persistence relationships and durable/runtime boundaries.
+- `save-load-sequence.mmd`: save and full ticker-load order with preflight/failure branches.
+- `restart-state.mmd`: one-shot restart and fail-closed recovery lifecycle.
+- `help-sequence.mmd`: client-session/model/file trust boundaries.
+- `services-components.mmd`: external boundaries with explicitly optional/disabled paths.
+
+PlantUML counterparts (`.puml`) are provided for each diagram. They express actual component, sequence or state diagram syntax; rendering is handled by the enclosing audit. Mermaid files remain available.
+
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
diff --git a/architecture/runtime.md b/architecture/runtime.md
new file mode 100644
index 0000000..c98e2bc
--- /dev/null
+++ b/architecture/runtime.md
@@ -0,0 +1,138 @@
+---
+layout: default
+title: "Runtime and gameplay"
+permalink: /architecture/runtime/
+description: "Source-pinned Civ13 architecture, UML diagrams, evidence boundaries and downloadable audit artifacts."
+image:
+ path: /public/img/architecture-overview.png
+ width: 1922
+ height: 573
+ alt: Civ13 architecture component overview
+---
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
+
+# Runtime and gameplay architecture audit
+
+Commit: `5bf351248de6050876fe5b53f91209a970cc5668` (Civ13/Civ13 master snapshot supplied for this audit). Read-only static analysis. No server, compiler, live client, deployment, publication, or paid service was used. All source links pin this commit. AGENTS.md was read; its operational guidance is not treated as proof of runtime behavior.
+
+## Scope and interpretation
+
+This report covers startup, process scheduling, round phases, human movement/input, item combat/projectiles, crafting, faction research, simple-animal AI, and delayed-action ownership. Mermaid files describe component, class, sequence, and state abstractions. They are not a claim to enumerate every concrete execution trace. Random choices, arbitrary player inputs, map-specific overrides, spawned callbacks, configuration recipes and unlimited repeated rounds make that set unbounded. The accompanying inventory covers the full tracked DM tree.
+
+Evidence labels used below:
+- **Proven source edge**: a call or state assignment is present at the cited location.
+- **Dynamic edge**: receiver type, hook, callback, map, recipe or registered object determines the implementation at runtime.
+- **Unresolved activation**: code is compiled, but an ordinary startup path to running it was not established by this review.
+- **Review concern**: architectural risk or stale documentation, not a verified gameplay defect.
+
+## 1. Startup and scheduling ownership
+
+Pre-map `/datum/global_init/New()` creates game ID, reference registries, configuration and chemistry definitions, then deletes itself. Native map construction occurs before `/world/New()`. World startup records compiled dimensions and detects persistence recovery before yielding, runs configuration post-load and startup hooks, builds materials and the shared research registry, creates `/processScheduler`, and schedules setup. The process scheduler is set up before `setup_everything()` initializes occupations, movable atoms, areas, access-list files, recipe files and dictionary data. These are interleaved cooperative operations, not an atomic initialization transaction. [code/world.dm:27-44](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L27-L44) [code/world.dm:81-123](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L81-L123) [code/setup.dm:1-28](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/setup.dm#L1-L28) [code/setup.dm:83-120](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/setup.dm#L83-L120)
+
+`/process/ticker/setup()` instantiates the gameticker and schedules pregame plus server watchdog, status-file, messaging and persistence loops. `/world/start_serverswap_loop` starts or restarts the legacy scheduler and separately creates/starts the movement machine. These background loops exist in addition to process objects. The persistence loop schedules saving and maintenance reboot; the messaging loop polls file-based external input. [code/processes/ticker.dm:6-28](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/ticker.dm#L6-L28) [code/world.dm:348-399](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L348-L399) [code/world.dm:400-502](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L400-L502)
+
+The scheduler discovers all compiled `/process` subtypes, constructs each, calls setup, and tracks name, priority and queue membership. In this revision `is_subsystem_member` defaults FALSE; no production assignment overriding it was found. The `SSUtility`, `SSCombat`, etc. headings in `process_list` are comments, not actual parent subsystems. `deferSetupFor(/process/ticker)` records a list but the shown `setup()` enumeration does not consult that list. Therefore the startup diagram does not claim ticker setup is deferred until all other processes finish. [code/processes/__processScheduler.dm:74-98](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/__processScheduler.dm#L74-L98) [code/processes/_process.dm:40-49](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/_process.dm#L40-L49) [code/processes/__processes.dm:1-49](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/__processes.dm#L1-L49)
+
+### Scheduler execution contract
+
+1. `start()` installs a new run token, sets interval from `world.tick_lag`, orders processes by priority and spawns the main loop. A replacement start retires the prior sleeping scheduler invocation through token inequality.
+2. Each cycle checks running processes, queues enabled idle processes whose game-state and interval gates pass, then relays eligible queued work within a tick-usage envelope.
+3. `relayProcess()` has `waitfor = FALSE`; it initializes a missing work snapshot and calls the process wrapper. `started()` marks running, records timestamps and invokes `onStart`; `process()` invokes `fire` unless paused; `finished()` returns idle and keeps only unfinished nonempty budget snapshots.
+4. Ordinary priorities copy registered lists and remove visited entries. VERY_HIGH aliases the live list and skips both removal and the ordinary per-process tick check. These macros affect movement/projectile/throwing semantics and must be represented explicitly in performance reasoning.
+5. Hung states escalate by elapsed time, then the scheduler constructs a replacement of the old runtime type, copies selected configuration/state, replaces owner maps/list entries and kills the old instance. Disabled/paused/state-gated are distinct from queue/running status.
+
+[code/processes/__processScheduler.dm:100-209](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/__processScheduler.dm#L100-L209) [code/processes/__processScheduler.dm:243-306](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/__processScheduler.dm#L243-L306) [code/processes/__processScheduler.dm:399-407](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/__processScheduler.dm#L399-L407) [code/processes/_process.dm:134-159](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/_process.dm#L134-L159) [code/processes/_process.dm:182-273](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/_process.dm#L182-L273) [code/processes/_process.dm:314-348](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/_process.dm#L314-L348) [code/processes/___defines.dm:28-33](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/___defines.dm#L28-L33)
+
+The source catalogue contains 37 directly included setup declarations under `code/processes/`; it intentionally does not claim this is the entire compiled `/process` subtype universe. See `process_catalog.md/json`. Major dispatches are mob -> `Life` (1 second), object -> `process_interval` (2 seconds), map -> `tick` (2 seconds), ticker -> `process` (2 seconds), research benches -> `analysis_tick` (10 seconds), and projectile -> `process` (configured 0.03 second). These are ideal schedule expressions, not measured frequency or guaranteed wall-clock latency. [code/processes/mob.dm:3-53](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/mob.dm#L3-L53) [code/processes/obj.dm:1-27](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/obj.dm#L1-L27) [code/processes/map.dm:3-12](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/map.dm#L3-L12) [code/processes/ticker.dm:6-45](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/ticker.dm#L6-L45) [code/processes/research_tree.dm:9-29](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/research_tree.dm#L9-L29) [code/processes/projectile.dm:3-40](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/projectile.dm#L3-L40)
+
+### Other timing mechanisms
+
+- `/process/scheduler` owns `/datum/scheduled_task` entries and dynamically calls procedure/argument lists with pre/post events; source-bound tasks register destruction callbacks. This is a task scheduler inside the legacy process scheduler, not the same object. [code/processes/scheduler.dm:7-34](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/scheduler.dm#L7-L34) [code/processes/scheduler.dm:52-132](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/scheduler.dm#L52-L132)
+- StonedMC, failsafe, base subsystem and timer sources are compiled, and `Master` is globally instantiated. Its constructor enumerates subsystem types, but does not itself invoke the full Initialize/StartProcessing path. `Master.Initialize()` does initialize and start processing when called. This review found internal recovery paths but did not establish ordinary startup activation of that method. The timer/controller branch is shown dashed, not claimed absent or running. A dynamic/admin entry could still activate it. [civ13.dme:114-119](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/civ13.dme#L114-L119) [code/controllers/mc/master.dm:12-96](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/controllers/mc/master.dm#L12-L96) [code/controllers/mc/master.dm:135-225](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/controllers/mc/master.dm#L135-L225)
+- Native `spawn`, `sleep`, `walk`, `walk_to`, event hooks and async procs remain distributed throughout gameplay. A single process graph cannot represent their complete timing behavior.
+
+## 2. Round lifecycle
+
+The live gameticker state variable begins PREGAME. `pregame()` waits on persistence startup hold and exits if the round was restored. It counts down a 90-second lobby under `round_progressing`, with map voting able to wait independently; zero advances to SETTING_UP. `setup()` retries or returns to PREGAME when persistence/save/admission gates do not permit a fresh round. Success sets PLAYING, resets occupations, creates ready characters, collects minds, equips roles, starts time-of-day logic and invokes roundstart hooks. Restored rounds bypass fresh character/equipment/map setup. [code/game/gameticker.dm:6-35](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/gameticker.dm#L6-L35) [code/game/gameticker.dm:45-157](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/gameticker.dm#L45-L157)
+
+Map tick checks faction boundaries, elimination conditions, map-specific win conditions and events; the base win-condition implementation sets `ticker.finished`. Ticker does not run every native tick: the process interval is two seconds. For normal rounds its process transitions PLAYING -> FINISHED and spawns delayed roundend/reboot handling; admin `delay_end`, epoch-swap state and persistence rechecks can alter that path. A persistence-active round clears finished and stays PLAYING. World reboot separately checks save/restart ownership and startup holds before native restart or OpenDream supervisor behavior. [code/game/objects/map_metadata/_map_metadata.dm:477-522](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/map_metadata/_map_metadata.dm#L477-L522) [code/game/objects/map_metadata/_map_metadata.dm:684-735](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/map_metadata/_map_metadata.dm#L684-L735) [code/game/gameticker.dm:193-245](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/gameticker.dm#L193-L245) [code/world.dm:235-277](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L235-L277)
+
+`02_round_lifecycle.mmd` is the gameticker abstraction, not a lifecycle diagram for every map metadata subtype. Map-specific state variables and hooks are dynamic extensions. In particular, a map's `game_over`, victory timer and `ticker.finished` are not universally synonymous.
+
+## 3. Input, movement and collision
+
+Input has native cardinal/diagonal handlers and held-direction start/stop verbs. The delayed mob-construction callback adds a non-lobby client to `movementMachine_clients`; the movement loop selects cardinal or combined diagonal intent, checks movement ownership/delay, then asynchronously calls `client.Move`. It removes the client while movement is busy and re-adds after the current delay. The loop requests a 0.01-second interval but this is not evidence BYOND delivers 100 Hz simulation. [code/game/mob/mob.dm:30-44](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/mob.dm#L30-L44) [code/game/mob/mob_movement.dm:97-145](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/mob_movement.dm#L97-L145) [code/game/mob/mob_movement.dm:977-1195](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/mob_movement.dm#L977-L1195) [code/movementMachine.dm:24-98](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/movementMachine.dm#L24-L98) [code/movementMachine.dm:102-126](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/movementMachine.dm#L102-L126)
+
+`client.Move` is a large policy junction: canmove/moving/delay checks, map boundaries, prone/lying actions, equipment, stamina, pulling, riding/vehicles and movement timing. It eventually uses polymorphic mob movement. Living Move coordinates buckle/drone/restraint/pull behavior, movable Move owns the native offset seam, and BYOND collision invokes Bump. Human Bump tries the shared mining operation before inherited living Bump's deferred pushing. [code/game/mob/mob_movement.dm:193-283](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/mob_movement.dm#L193-L283) [code/game/mob/mob_movement.dm:284-340](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/mob_movement.dm#L284-L340) [code/game/mob/mob_movement.dm:650-700](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/mob_movement.dm#L650-L700) [code/game/mob/living/living.dm:502-560](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/living.dm#L502-L560) [code/game/mob/living/carbon/carbon.dm:392-405](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/carbon/carbon.dm#L392-L405) [code/game/mob/living/living.dm:45-80](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/living.dm#L45-L80)
+
+The human physical sub-tile adapter is compiled but `human_subtile_enabled` defaults FALSE. It has restricted shape/direction/state eligibility and runtime ownership/capsule machinery. The movement diagram treats its enabled path as opt-in, not normal production behavior. Its presence does not establish real-client timing acceptance. [civ13.dme:230](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/civ13.dme#L230) [code/game/mob/living/carbon/human/subtile_movement.dm:1-74](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/carbon/human/subtile_movement.dm#L1-L74) [code/game/mob/living/carbon/human/subtile_movement.dm:230-246](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/carbon/human/subtile_movement.dm#L230-L246)
+
+### Shared delayed-action boundary
+
+`do_after` locks ordinary repeated actions, captures actor location, active hand and target location, shows progress, then sleeps and revalidates incapacity/movement/hand/target. It clears the lock and progress at completion. Optional mining context claims and validates actor+turf ownership; gameplay bridge context is conditional on `CIV13_GAMEPLAY_BRIDGE` and must not be flattened into the default signature. [code/_helpers/mobs.dm:190-280](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/_helpers/mobs.dm#L190-L280)
+
+Click and bump mining reserve actor/turf before a spawned worker, record exact tool, origin and physical step offsets, and revalidate before committing. `try_bump_mining -> start_pickaxe_mining -> pickaxe_mining_action.perform -> do_after(mining_context=...)` is a distinct ownership-sensitive path, not just an inherited generic attack call. [code/game/turfs/floor_attackby.dm:677-817](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/turfs/floor_attackby.dm#L677-L817)
+
+## 4. Combat and polymorphic item interaction
+
+`atom.Click -> usr.ClickOn` is the common mouse entry. ClickOn first checks target and next-click deadline, then routes modifiers, special equipment/vehicle branches, active-hand/self interactions, adjacent versus ranged interaction, or unarmed action. Do not interpret every click as an attack. [code/_onclick/click.dm:7-74](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/_onclick/click.dm#L7-L74) [code/_onclick/click.dm:198-287](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/_onclick/click.dm#L198-L287)
+
+Item dispatch order is explicit: resolve turf attack first when appropriate; then target `attackby`; then item `attack_obj` for objects. A truthy resolved result suppresses ordinary afterattack paths. Living target `attackby` can route surgery; otherwise item `attack` applies eligibility, stamina, logging, cooldown and animation, asks the target to resolve the hit, and invokes `apply_hit_effect -> hit_with_weapon` for a resolved hit. Target/item subclass overrides determine actual armor, hit-zone and special-effect branches. [code/_onclick/item_attack.dm:22-74](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/_onclick/item_attack.dm#L22-L74) [code/_onclick/item_attack.dm:92-121](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/_onclick/item_attack.dm#L92-L121)
+
+Gun `afterattack` routes aiming/PreFire or Fire; Fire uses weapon-specific ammunition acquisition and calls projectile processing/launch. Projectiles register and travel through their own process queue; `process`, `handleTurf`, `attack_mob`, `do_bullet_act` and target `bullet_act` decide collision, miss, penetration and damage. `process/projectile.reset_current_list` limits the current list to 500 and deletes the excess; this is explicit overload behavior, not proof of a measured problem. [code/modules/projectiles/gun.dm:138-193](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/gun.dm#L138-L193) [code/modules/projectiles/gun.dm:276-375](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/gun.dm#L276-L375) [code/modules/projectiles/gun.dm:460-524](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/gun.dm#L460-L524) [code/modules/projectiles/projectile.dm:175-239](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/projectile.dm#L175-L239) [code/modules/projectiles/projectile.dm:308-443](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/projectile.dm#L308-L443) [code/modules/projectiles/projectile.dm:472-728](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/projectile.dm#L472-L728) [code/modules/projectiles/projectile.dm:732-821](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/projectiles/projectile.dm#L732-L821) [code/processes/projectile.dm:34-40](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/projectile.dm#L34-L40)
+
+`04_combat_dispatch.mmd` shows the default melee and gun paths. Alternative overrides (explosions, thrown weapons, spells, surgery, vehicles, special weapon actions) remain extensions, not omissions claimed unreachable.
+
+## 5. Crafting and research
+
+Recipes have both code-defined variants and config-driven records. Setup reads `config/crafting/material_recipes*` lines containing 13 comma-separated fields into global/faction lists. `material.get_recipes_civs` chooses race/faction and map/civilization research values. Generation resolves result path strings with `text2path`, gates by research-node completion when mapped, otherwise legacy three-axis research thresholds, and applies era/material/feature checks before creating stack-recipe datums. This is a data-to-type construction boundary. [code/setup.dm:83-107](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/setup.dm#L83-L107) [code/game/objects/items/stacks/civ_recipes.dm:19-144](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/civ_recipes.dm#L19-L144)
+
+The stack menu Topic path validates actor state and held source, resolves recipe/sublist/multiplier, and uses `H.can_build_recipe` to serialize the operation. `produce_recipe` is a large content-specific transaction: feature gates, subtype-specific prompts and temporary constructions, derived time, `do_after`, post-wait special revalidation, debit with `use(required,H)`, dynamic `new recipe.result_type` and post-construction configuration. Craft cancellation and payment semantics are branch-specific. In particular, wood-handle crafting keeps the exact handle/source through the wait, revalidates both, and removes the actual equipment slot only after successful main stack debit. Do not generalize that transaction guarantee to every recipe branch without a separate branch audit. [code/game/objects/items/stacks/stack.dm:298-335](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/stack.dm#L298-L335) [code/game/objects/items/stacks/stack.dm:1805-1830](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/stack.dm#L1805-L1830) [code/game/objects/items/stacks/stack.dm:1898-1944](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/stack.dm#L1898-L1944) [code/game/objects/items/stacks/stack.dm:2355-2437](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/stack.dm#L2355-L2437)
+
+The new research architecture separates shared immutable-ish node definitions (`research_nodes`, recipe requirement index) from mutable map-owned faction progress. Benches register themselves globally, own faction/tier/assignment/queue, and operate under leader/director/researcher permissions. The process iterates benches and calls analysis_tick; the bench advances its queue, checks mode, tier, prerequisites, already-done state and an online authorized researcher, then credits progress and refreshes viewers. [code/modules/research_tree/research_node.dm:13-74](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_node.dm#L13-L74) [code/modules/research_tree/research_node.dm:159-234](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_node.dm#L159-L234) [code/modules/research_tree/research_bench.dm:23-94](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_bench.dm#L23-L94) [code/modules/research_tree/research_bench.dm:105-207](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_bench.dm#L105-L207) [code/modules/research_tree/research_faction.dm:43-71](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_faction.dm#L43-L71) [code/modules/research_tree/research_faction.dm:200-232](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_faction.dm#L200-L232)
+
+`add_research_ticks` moves an entry into IN_PROGRESS and completes ANALYSIS when cost is reached; PROTOTYPE needs both accumulated study and a submitted prototype. Books can complete through the explicit book route; notes and reverse engineering add progress; coin inputs upgrade benches. `complete_node` marks faction DONE and prototype era capstones can increase the world's ordinal age. Global era progression does not imply every faction researched every node: `is_node_done` has explicit baseline-era semantics. [code/modules/research_tree/research_faction.dm:114-190](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_faction.dm#L114-L190) [code/modules/research_tree/research_faction.dm:214-232](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_faction.dm#L214-L232) [code/modules/research_tree/research_bench.dm:585-740](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_bench.dm#L585-L740)
+
+The generated `08_research_prerequisites.mmd` covers 93 direct node constructor registrations in the selected registry file, with 99 declared prerequisite edges. `research_nodes.json` preserves costs, tiers, modes and line numbers; `research_graph_checks.json` checks unresolved prerequisite IDs and duplicate IDs. It is a declared dependency graph, not proof that every research route is dynamically reachable in every map. Recipe-to-node mapping and baseline grants are separate from prerequisite edges.
+
+Research storage comments describe faction progress as round-scoped and bench variables as saver-owned. This report does not infer current serialization solely from those comments; persistence schema/import coverage belongs to the persistence audit.
+
+## 6. Life and AI
+
+`process/mob` dispatches `Life()` over `living_mob_list` and catches per-object exceptions. Human Life combines physiology, body/visual state, nutrition, stamina, environmental/health logic and content-specific rules; survival idle multiplier separately uses input inactivity plus action/movement clocks. Simple animal Life handles status, starvation, following and then `handle_ai`. [code/processes/mob.dm:12-53](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/mob.dm#L12-L53) [code/game/mob/living/carbon/human/human_life.dm:40-180](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/carbon/human/human_life.dm#L40-L180) [code/game/mob/living/simple_animal/simple_animal.dm:124-175](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/simple_animal/simple_animal.dm#L124-L175)
+
+Simple AI returns for unconscious/dead, client-owned, anchored or empty-server cases, and for various movement restrictions. Idle hunger can preempt general behavior. Behavior strings select scared/wander/hunt/defends/hostile; attack/alert runs more urgently while idle is throttled. Tactical handling adds IDLE/ALERT/ATTACK/TIRED stance logic, perception, faction eligibility, target loss, pursuit, surroundings destruction and attack. Hostile mode can transition directly from IDLE to ATTACK, so ALERT is not a mandatory intermediate state. [code/game/mob/living/simple_animal/simple_ai.dm:3-121](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/simple_animal/simple_ai.dm#L3-L121) [code/game/mob/living/simple_animal/hostile/tactical_ai.dm:131-265](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/simple_animal/hostile/tactical_ai.dm#L131-L265) [code/game/mob/living/simple_animal/hostile/tactical_ai.dm:266-438](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/simple_animal/hostile/tactical_ai.dm#L266-L438)
+
+Cover and friendly-fire helpers apply to human NPCs; arbitrary animal subtypes can override target and attack procedures. Dogs additionally have a dedicated fast follow process. Pathfinding/native walking can continue between Life dispatches, so AI is not a single closed four-state automaton. `07_animal_ai.mmd` explicitly labels the simplified combat stance graph and behavior dispatch. [code/game/mob/living/simple_animal/hostile/tactical_ai.dm:4-127](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/mob/living/simple_animal/hostile/tactical_ai.dm#L4-L127) [code/processes/dog.dm:3-46](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/dog.dm#L3-L46)
+
+## 7. Review concerns and concrete follow-on verification
+
+These are evidence-supported review targets, not asserted bugs:
+
+1. **Mixed scheduler ownership and stale comments.** Included MC/timer infrastructure, legacy process comments naming non-existent grouping owners, deferred-setup record without observed use, spawned loops and native walking create competing mental models. Verify actual startup with a fixture trace of process creation, ticker creation, loop starts and readiness. Do not assume declared controller files are active. Sources: startup/scheduler sections above.
+2. **Budget fairness depends on list shape and macros.** Ordinary loops retain work snapshots, VERY_HIGH uses live lists, and research fire iterates a fresh bench copy with a tick check rather than the same current-list resume protocol. Inspect large-list progress and mutation behavior with native tests before claiming fairness/starvation. [code/processes/___defines.dm:28-33](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/___defines.dm#L28-L33) [code/processes/research_tree.dm:16-28](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/research_tree.dm#L16-L28) [code/processes/_process.dm:147-159](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/_process.dm#L147-L159)
+3. **Movement recovery ownership deserves a targeted test.** Legacy scheduler start has a run token; movementMachine.start simply spawns another process loop, and watchdog recovery calls start on a stale last_run. The architecture exposes different restart contracts. Whether duplicate live movement loops occur requires a controlled stale/watchdog timing test, not source-only assertion. [code/processes/__processScheduler.dm:100-131](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/__processScheduler.dm#L100-L131) [code/movementMachine.dm:24-31](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/movementMachine.dm#L24-L31) [code/world.dm:466-500](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/world.dm#L466-L500)
+4. **Crafting is a content-heavy transaction hub.** `produce_recipe` spans hundreds of branches and yields at input/do_after; consumption, object creation and cancellation need per-family conservation tests. Recent handle/drill/electronics guards are explicit examples, not blanket coverage. [code/game/objects/items/stacks/stack.dm:298-335](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/stack.dm#L298-L335) [code/game/objects/items/stacks/stack.dm:1805-1944](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/stack.dm#L1805-L1944)
+5. **Research comment drift.** Bench analysis comments describe prototype submission as a shortcut rather than mandatory; executable `add_research_ticks` caps study until the prototype is submitted. UI/examine text should be checked against executable completion gates. [code/modules/research_tree/research_bench.dm:66-73](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_bench.dm#L66-L73) [code/modules/research_tree/research_faction.dm:181-189](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/modules/research_tree/research_faction.dm#L181-L189)
+6. **Cross-cutting mutable globals.** Map, ticker, job master, process-list singleton, registries and actor variables are shared across input, periodic updates and deferred work. Save/import, round transitions and object deletion must preserve reciprocal ownership and avoid treating process-local deadlines as durable state. This report establishes the boundary, not persistence correctness.
+7. **Dynamic dispatch limits static coverage.** Hooks use text-to-path and call; scheduled tasks use dynamic procedure/arguments; crafting resolves data strings to constructors; every `Life`, `attackby`, `Move`, map `tick` and object `process_interval` may resolve a subtype implementation. A sound complete may-call graph needs DM type/inheritance resolution and config/map variants, plus explicit unresolved edges. [code/hooks.dm:50-64](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/hooks.dm#L50-L64) [code/processes/scheduler.dm:108-132](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/processes/scheduler.dm#L108-L132) [code/game/objects/items/stacks/civ_recipes.dm:114-144](https://github.com/Civ13/Civ13/blob/5bf351248de6050876fe5b53f91209a970cc5668/code/game/objects/items/stacks/civ_recipes.dm#L114-L144)
+
+## Deliverables and checks
+
+- `01_runtime_components.mmd`: startup and runtime owners, including unresolved MC activation.
+- `02_round_lifecycle.mmd`: round-state and persistence branches.
+- `03_movement_sequence.mmd`: held/native input, movement, collision/mining ownership.
+- `04_combat_dispatch.mmd`: default item, melee and projectile dispatch.
+- `05_crafting_sequence.mmd`: menu-to-dynamic-construction transaction skeleton.
+- `06_research_model.mmd`: research data/ownership class model and gates.
+- `07_animal_ai.mmd`: simplified behavior and stance transitions.
+- `08_research_prerequisites.mmd`, `.dot` and `.svg`: generated declared node prerequisite graph.
+- `09_process_state.mmd`: legacy scheduler work/status transitions.
+- `process_catalog.md/json`, `research_nodes.json`, `research_graph_checks.json`: machine-readable evidence and source links.
+- `build_runtime_artifacts.py`: reproducible lexical extraction. Does not execute game code. Run `python build_runtime_artifacts.py --source /path/to/pinned-checkout --output /path/to/artifacts`. The report itself is curated, not regenerated by this script.
+
+Mermaid is editable diagram source. Eight equivalent focused PlantUML sources are included for rendering during packaging. No runtime or performance validation is claimed. The source checkout remained unmodified.
+
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
diff --git a/architecture/validation.md b/architecture/validation.md
new file mode 100644
index 0000000..644a104
--- /dev/null
+++ b/architecture/validation.md
@@ -0,0 +1,60 @@
+---
+layout: default
+title: "Validation and reproduction"
+permalink: /architecture/validation/
+description: "Source-pinned Civ13 architecture, UML diagrams, evidence boundaries and downloadable audit artifacts."
+image:
+ path: /public/img/architecture-overview.png
+ width: 1922
+ height: 573
+ alt: Civ13 architecture component overview
+---
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
+
+# Validation and reproducibility
+
+Source pin: 5bf351248de6050876fe5b53f91209a970cc5668. Audit date: 2026-10-20.
+
+## Executed successfully
+
+- Fresh master checkout pinned to the revision above; final git status is clean.
+- Python lexical inventory over all 1,462 tracked DM files; include closure and SHA-256 accounting generated without executing repository code.
+- Inventory checks: unique file paths, every discovered literal include exists, four declaration anchors, three call anchors and two excluded-feature anchors. See inventory/check-results.txt.
+- Python AST parsing of tracked Python support files: zero parse failures, 2,036 function/class declarations inventoried. This does not validate imports or behavior.
+- Runtime audit extraction: 93 research registrations, 99 prerequisite edges; no duplicate or unresolved prerequisite IDs. Process catalogue intentionally covers 37 directly included setup declarations, not every possible process instance.
+- 215 commit-pinned report source links checked for existing files and valid line ranges; zero errors.
+- PlantUML 1.2025.10 with local OpenJDK rendered 18 UML diagrams to SVG and PNG. Graphviz rendered two separately labeled graph views. All 20 SVG files parsed as XML with no renderer syntax-error output.
+- Reviewed all 18 PNG render layouts in a contact sheet and representative component, sequence and state diagrams at full size. No missing render or visibly clipped diagram was observed.
+- ReportLab generated the 19-page PDF atlas; pdfinfo confirms 19 pages, no embedded JavaScript. Each diagram retains a diagram-sized page to avoid shrinking labels onto fixed paper dimensions.
+
+## Not claimed
+
+No BYOND compiler, DreamChecker, DreamDaemon, live server, connected client, save round trip, gameplay assertion, performance benchmark, deployed bridge or external model was run. No exact compiler CFG, complete virtual dispatch solution, runtime path coverage, security certification or exhaustive behavioral verification is claimed.
+
+The initial local Mermaid/Chromium rendering route could not start in the available sandbox. It was not used to claim successful rendering. Equivalent PlantUML sources were rendered locally instead; Mermaid sources remain editable alternatives. Font-cache warnings did not prevent successful PlantUML/Graphviz output.
+
+## Render commands
+
+Use an official PlantUML 1.2025.10 jar, Java and Graphviz:
+
+ java -Djava.awt.headless=true -jar plantuml.jar -tsvg 'OUTPUT_ROOT/**/*.puml'
+ java -Djava.awt.headless=true -jar plantuml.jar -tpng 'OUTPUT_ROOT/**/*.puml'
+ dot -Tsvg INPUT.dot -o OUTPUT.svg
+ python tools/build_atlas.py OUTPUT_ROOT
+
+Inventory and report link checks:
+
+ python tools/build_inventory.py SOURCE_ROOT OUTPUT_ROOT/inventory
+ python tools/summarize_inventory.py SOURCE_ROOT OUTPUT_ROOT
+ python tools/check_inventory.py OUTPUT_ROOT/inventory
+ python tools/validate_artifacts.py SOURCE_ROOT OUTPUT_ROOT
+
+Runtime-specific extractor:
+
+ python runtime/build_runtime_artifacts.py --source SOURCE_ROOT --output OUTPUT_ROOT/runtime
+
+The scripts operate on source/artifacts only. Dependencies for PDF packaging are Pillow and ReportLab; core inventory uses Python standard library. No paid services or cloud rendering endpoints are needed.
+
+
+[Atlas home]({{ '/architecture/' | relative_url }}) · [Diagrams]({{ '/architecture/diagrams/' | relative_url }}) · [Audit]({{ '/architecture/audit/' | relative_url }}) · [Runtime]({{ '/architecture/runtime/' | relative_url }}) · [Persistence & services]({{ '/architecture/persistence/' | relative_url }})
diff --git a/public/architecture/2026-10-20/Civ13-architecture-UML-atlas.pdf b/public/architecture/2026-10-20/Civ13-architecture-UML-atlas.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..df9e58182f1fbe691d7786f9d91941b43a214116
GIT binary patch
literal 1409611
zcma&O+19Gu(k6Jmui^u-S5OcT=@bz}u>%AZQIXybLCul1Z=vd}&g)u>_3b}1cU5KO
z_}?|g>#Iy>8xb?&i6>ThElTY!jQykhfBql;`~UTq7QEB^tGd^}V z{;C0Vc=I0f9PhZV7_ntdSY@6CQ{(S2ldzbkn2kHX)OQhHE$7eK{@K4g8T9@JC*>aN z_Qw%acp)5jJ{*8r#Z>^zstg5??qcI~>~U#mGxp@yU6{EHXo6{$R0?RFV} z@6>=i>4^F{?iz FqT`!>DG&KHj^W !Rr>ms_YRQ%(!MEQ0^kEUK(z{c zS `}&*LCS4mTmAruki7 xUP U%z`HXY0ZaH^;5AHP*g(q$arYH OvV}e+5d8* z0&doO??P|#i$aZeHAX)Ryu2D8fO70Xt7l{7*7f_Oo)j_f6PMN=`|NlxVe(pSJTSvj ze1=ccbqOjj%^&FZuc^&;@1kZc7K$~bVyHkKseEr9Ud^$0)NA|GuZW!bX}-AxHqpH9 zcdA(=i8=Xqk`VD3-&%9#ZLR0^XTL$ KW*6ppIvrZ!U6Qoohb_gPJge_>V<6 zhK%lroR&APb)Vtx2e|D#^Y?@n%C|Ny5dFbxlW>=PGfrBsN1-#NUlGAv$L9}y-sbHx zL3HK7jP<%(zK;iRNjhN#MC>YCEesmnPu`dwC~wyy)a*G}_lgD!QeuBnjtGbk2gY)^ z%Ii@ku1f1~_H8f&6JE_0a}n+=H`A@+6qztgTf6&Ty8nzW%K|9XSs8gy*YVZxq$VB~ zQ2m%phZul*Eor|npRv!cq_#i2Vn&0Sr}cNI4zXQA?GEXhLR;;XGkl(vv2BJTDBLro z4h>v0U)MWbI2*07@=nZ89Wss?Wiq;#=d(-R&Y;XRSDo8u;93uBlU1jcc2x(0PWo*2 zO%7j-hN?it50|<=uMR)*RD~3Mp}KJ3zr#Lm4+qD5EWoPD6%b|`6?T;H#c~Z9(wp!2 zQ~O*U21yRp-84BM!@+&c@Xg+Id=t#c;f@RAy8D_PZy8fW>xbVHe8kYufGX`;pRKN| zY3><9qd2m1T$!23rL1E4O$6`8v|Iz5>EmLK+;LoaH4Zc+9QSXaUCw+*CONg7FaJNW z8kSx8gM%O%-ZKf5KNq-cW3cQAP obemZGBqnGkD5=+T1C }p=#iS@zuvB=aRs{Her+RGjpFRpF^T4@YZtp#%Jp?Ec{}p{DU8sl zaqHOAq~=Mw0O53sF<~yh?x%IA#rx6|@>R5L?B64LJv-FNne^=0wf4HvpCG$C3n+y; z_cd7saJCZm>+17cHf~Z=d`vSyvVOIFX`ZT6T 5#8hh+I_pN@cy8Hd~i zPYjaI7kP(C+uk#|?V1^HKC@$iBv{5?V9HQ6TUFD0?;}L|S}Ik`9k)gJ*yo Z3MBsYZ z<(Wr86Ec|hGHz@?HkO$7rns?JmFl MEm?EvL>>t1tc^N@hxjtwI6!!v`y=v+^`)%^F3XJ2&cM43@TNYW1m<+1* zk!*g|d@MWQ;*)_Ll@4knBPrWiac&a)vgGso;15@oNAQdKPo{(G%g1^@S2jgxaH!2e zLwa3!mBo&cJ;*o_j8?jLxYk%Cest$U-?b&y9zNd0s9o$K8FKMp=T&yQz3Q}|LXGH5$EzE_lOUHcHO zI(4@@5S40ZcBQQ U4{Bc^p=kK}}RD_hlZ}63t zrNxc-AA$s}D0k9H2XmLiV5e|HtLA$!YGB&_A--_3cb*@VxmW48zK;!FB=XAZf}BzJ z)?XpU7aa!9&Avd+AsO+PTy?tcw5DEOW>3LeKqci}mzkNi8ny042!H=P_#?!ow+-)V z+3|h(blg{`RDf7DUp=W*ynLzv%O(!kN#G_o4jT+-RFFwc> PS)4_I7$&gLz|v4*}@Li2Z_(t*a>r-okl;Cc@BFo z0q4CTd{YQHS%1#$lMjpc4}=+7Wm%gTH(%+p=T(^q&5CEpr({q~fpoZ2&MAJiqpS8Q z0w3hL#q2H8>{Konn#L}DW<&RSE1aBdMC@t+VdJ Mm2GpnR_kXHc>&~?wK{a z`m6?9 zY%OI9EzLjn!<(Xd-V0~_4oYpA;XRxfgHwXe8W{Qp*5@~L)0dO!J7mc?Wz*!T2Fplp1SwETZjlT=|nbzdBK}1 zC_gPC#8>_P>qAfW YzuI6NYoE4tVd?}}A zaTE%M{QJP`h5u}GUJMb53aqMNgin5nBsoK8ZT+~ZK>qUDuvBM11R+rM*0S=;9Akc3 zBbDLEA9M^3IbrMZ!5^3jUp1$MOjQ;{_&xUedyn>)mZG8SZF$ozr`?g;=bOSyEV6Jy z<&;+?f8VL0{vxyw2R*RMIDJ*$+L?<0jecsMabsM-$T$!tHZno%e5c%wYw=F0b}? zLXAte)&2&Dd|*ZH%jxJsX+vka-s~CEm~KI!^ue-9tkkLH{GHFA-hx+ZbC+KL9k>7Q zpyGk2=;2&uXk~DQtrL Wg145H>WH?>eLqPiz>HUwN8y zVpy}it5Fe$?dz*Q@8&y5;KPbtBy=miIhmM26`TZmZ!>r(6x!dF;BbZ(Gb5pU@DYTS zPC9CKAiu$#2lU!t9%g?F|ID}?-99qNkO`UEHz ZcrqZvz;?~xiq_YUG95$&N)gNVa8Io zQ=mPqhj2ze-gD|0>6}GmuQ9X)JpKG6TlR`LxQ`ZGmexss3V(yc>RGjJrTa -_Cn(!&Pl~`j$U?MZOMm<|vg@?u z&E(!C`m?XZmEIpfY&qWw1QC6sH~m+lDgjEb2s#Ur=-Dq p>WVJ7Vc>p zLuJjMe;brs?F(A+<2P+GVf*ls_4U+!+GLTCeWPFna T=h7*89Ip;g9I`XWX^tw@cQ0KqQk~s0fP>eBp%N z{YI{z>-!?@wn$sg0n q4k|l z2bHP4?a)$B*^W=GYy<6o6d`>-4}F9<=HQb?w$Y~YkcFOCvN1B`W^+RRc4rlp8MSt9 zTuk?K3p+l3lDe~3jaQsgs^@&`^4^qoQzPD@HGMsAcZVTVA|DG_b_-Gg*Y8AV*0+@L z&0~(}_D5ZoZ=a3YQ(^myhPqrTAi@G$Vcs6d{2B(xo@ODDJtUwBMf|61%+M++UW=e$ zwU}m`YUQc6GO|{iF}mp8qDoVp+=|rMA0!_-&l~-eWq9()5q+C(Z;|Rcqp0_=!5HE3 zx1itc#dsCw0{Cu&Z(6JIQu&+Z(RIr1DhEG&ccm5gwiR}8_nP>){6IJx*#kmSs*ca3 ztX?JVR`2Xv9uk>r*v%hjVaE%NUA+jk`A0)ALJU*EZ2t+^zcaV`q-lHwl7jTZ>!#|{ z TrMzx0{XvdhnGm(`z=vBexqyBu-Crd+0CfA8or?T}I~h)|`p(>0>qf zv39%^{{7^PsqW^poSN5b9jUVYs`z2AFxYr9e@9u%v`g~AA&5#!?Ummg^#1LkN_Vt` zwk5XD=^oVYXq&1j#aV*-xLr`&A%@a&wqMRSi$U77i`?2xC}(sfPe)Q++-sv>w0yG9 zX;@H|uR9bgZ}j6PL6mL2^DW)CCYV@q_e$F%vWD67oc334M9c@P@bzxv_BMumx5!oc zQ*_e;v-lhiVxfovj?dYqwxvrw-;z>uQE%YOkz=`gsr i_5ZQ&e-qgt`g*X#CY0zIR5TFom5wqZS;wHp6T zbST|o;~`svL8B*7^xpna(le1guw4YEV~ N{-dDo8#8nIcHN`#jy%B z8aotRI^qO>b;^H{?H#w}za!gCQZK)yS?Ue36)k6V3_hO^3^nZ!exzhnMub(mZT=j^ z#cyxBjk~gn3~pJn$HoTa_ZvyOb>|c3D*At$7K$i?O*H==SEG69as#1gG+#2SE_n!C zswC&58Tvo7CEV0I>^yXR-_i@-Yt;sXJux7hvubv0JPI6##x%J?nq!0D@OiPwEw%MED;^vg1Jr8^ zH(EHP^kgQCMrGMVR@t{eV4?v(e X190S+%8lNy1$z8 za@mL91D2yU1sX3tfxrn^L!KmT5cr_d*|nY+^0|4ovK=yn_ZYr?D~A^cuc3A_1-UWv z*Vqe=&!G0a1gp*XBo$;F3vad>s|ofZTp2cEFJURc=ryTZxrA)c%|k6cgCeOE^*4jQ z21H_$p9%h?R+;) 6l|L6EGwdrBoT^lsz~>gd)j>gl znr>#-TY2!{sbIr%k6vzmM>F#*YH_=OebqK$n@(FOL(!Gi!S|{OHCi`WU9D4YRSpWf zaV`z}9x&{o*^f&xR~pr$sJndpq2GZ8IIlB3rgY2BrDQ^s@z3Hirh$*diRIrGi@6u` zK!u862c9cU=}7@Y^|S7+b(^f6oapq*ZmoM23bbsUty{Gz{dX?V2L 2S*2oEU!Oi|8;vlve{)fdCbKr4 ztbxHk(IOiO`-iJpuJUR#xEt!;jpt&-t$Rfk$L_?=+D3n!x2Xqu@9}9;SJIF%5oo*F zIV`mI@TnIx<9wXG&MQ$p4WGeQD$w>rQC5)D&dCqVv8bL!;}qcyP=Ehn)X5!b`YqzQ zK3|Zf&&~>oH|2MX^nzJ0z=y yJ?&y4y<&zmzuZ0Z|!Dzq!j zren!UG&|J%{2~y>``$JL`*7cNdl7RT !7{SAuRiGr6~ zB2nCLJcTaSsadT(en8aevIoiUivZW0c?y@%A~fF>esR44;2Vo7d|PC)D%be)+lzkf z*?9vvqtOu3+AX>~E)hLf?-14QEEJqu39@%T3x1)EZcUI>3h2N6nk&3FKBW4OTkbAl zv ~=sD)q`TyuD815B2E<4Yd2Xx86*lt7YP+JcDn6Fx%DgsBP8B zg3gVfm^F#-1`^?>1^SuGMZ2YUrL5z(GF{v;pkf-rNv$l~xzfS+jiYtjl$yAF2m0S= zC85mE2h*2T)jR}~a++75QtkWDGVqf*#nm`z0~ILl)k~k u_|u!1KKNjpgwgRYNu|$b+G8KWbwUrd9Lit zxps#4hx4s{G>SxBF;J26oc1O%gGxp>(i iz9!C_dBJwd7SxIn00#LkM;lblF~c2 z)Db7j?wWQEZo#+$z$q42<+OX@!!}3`FUvnC8p8OY3mS+;5HVe;V?`SIS5L)uksV5T z>Qb;7r-od`mVZc#C39>d6Z0COSi${lU5i;&!#YJR6M(11;$$WV+Pc1sqLiju6hi?p z4UDpiGL`sOQG9jztUdIp3fSj#b{_n@3 caCUycoBMfi9UAHtCu)bw ziRO61;J3fVfH#RrB46Eh;RzGR*#Ah|h(m<6fIL>6*+xk>TcfBE>b=is43Ky~j7JMv zIOn(~aog~*caZe=1p3cX^}gip!#>yWBH8{F%PoHR=ML@_)d8p#<%TXzo%J(W0yMl7 zmpZdM8K)vr`Lld+B7pg;AcZ`^O1plF8uR^k@)R>8FG^do!lD$K)nnLKf5JmNc&Z#R z;)RZQeY@Ot|FDyrZ21QfVFO%}&B8XHK@m_Vzdt?KUH-9`MqIU21KOZuK5Ak7Q_gyG zaDAp~{;!j%Ce*~Qke^VPAf+A`fr|JH_-(Rn1s*54VC7bvac5&B6&V
Xi4+Kr{vF!pS9IU=1=toSoSLz~xDDB}!PxUcZUCL{8T9-MgYq>g-hu zz?Zq3>`9)VDtd9T72MT`CPTVogaxlr2B7d#QG#=WoUEo;X&|4izcuRbgE}IM7hV+L z)CMP{sB4)ft9JOXyRTFI#=B*}vU)SjJBD5EEls*Q!Hh~PJJ$O^hlU+}rnJ_l{nhT= zXFoH1`h$uA^wat6S}Hl*9i5F@llt&BEIRFw0&+Pl-^VpwL}&$Q7nij8_T(6cIT7sx zdy!kvkL0Vxq8VYgNMv`bSbe3|;U>oyU+h0MTd_;WtFI1A@fvtx0a4`Y<|r6*+Cb~{ z;M~52`v)`DPS4r17bJK?1&zl~;x2N!m~Y{BuTWj6&mC*7Sz9mOvm4hY>pN(vA}u}J ziouvINSBS~8{)=%cODkz?8wFl&gSJ`znV>%`{j=
qf<3T9X^)si zpE-7z?VNq@$kjB?qQ1*na4OxX(&%Mh_tD+jgpei=YwV&BsUlQTAnGojm*pztBpg%R zS aUJjVe>5CicJmc5U&Jpl+{AwDdi;%fB_K6b(%Gb^F?!&9~Y=08_(@9NQ zRoA f=;I_A#lKR^-ji#F1Ax^8vEJu2^HxcLyu7)RL&d z*?{NF?mkKa IwLS3w(I<>~X6ML|>) zZ~ITahT0;F!_9%#5J gj#-g?-tOo6a(&+PxpF3^=;P>D zM0#Eem}4xdeZ H9AaqD~)ytx#V zJ&_>ov_WX0a~pN2qL}13zb;qwd~XemGxijp+?GCVv1@6 1hvgz8(dj&U8ci3vTKNqf@uH~9wzt$bSU)zfyj8|W6 zq>Vyo(s(|LwC`kNJ?mZaHmehF9dH_Z$k|rTQzWglhe%JZoene*;v2{M;JSFu_Pd2x z^%k{^m>zB%itht;u>Re6hHt>d6y{L@L%ds|8ucaq3vA=bt#TU+#Qee=N^n|!XYZ@d zH~c|x<>!LJGBs!8^zi2AT%?q0Gmtu8m%A>9->&0I9o$}q`iKs-X+J}==b_yOT>rsU zpF?Oo8VAyShmic_jGhPS+hwD?ee^e1U_IH=et+FRFSnw4e${FIH3R}n9N~amsI$kn z#@lh+p9zZwTl#dow{&HfuQUGG)|9l!cTa16y+ly$HkWs?Z97AIV4-vyFu|rl#Rl3z z?14N$kd`p9$Imh-9lPNfsq a>ry-c8G+x^^l}*XNFF#Lq2zQYA;*swg_5yznD%2TGoaXx%L0c+yY~= -l|9#!hfA7!x?gO|7>Ebu6^<8&cY3D6nD5X+ZnUmG= zftO3EbLFN@?mkF#>9xWa)$WWzS~}X;^v8?Zv;!l}Uu8M`9DQPhRy}7tPNO{?LT_S8 z5=0dx&H^qn;47!jDQljmSv6rh*OPVd(6KprRwx>bIOe0rv(TGv?`x}x-nb#03<9V( z-Ql;ewwR@nfRXyP;obn_pjcD~WE+4Y e?sUL_6R zF)Mc`p)`luN;PrBV;o?18fxRU0HkQs;6anE=sPCds81DG_gP(fmkru`_!Uce?)<1O za;++7%?z_sEw1=(-n;Kvd}2H|QOpjq;nU{80soaZl;3i`{EutG`;Krkh6ETHp0&!; z@Gc9!I@lHpw`Ml#;-#+0!px(clgROPURSq3whyk2X+?61F0ARm(rS#F)|0C;n?Jx* z0XC4{! RwrVqNFm2Y5^!A*EZn@bXR z1*d|FjbfBmJ9vPVn(*|aH%W8OF9_E?K9a>lE=21tW(}QqroyH)8QQBswq63?<)g7n z@i&Bl+NrabdR=x`edY@q^N*HWYvt$_*^k$tZPBZ@EBXv|w_WIuoJwipzWR+(Bkm51 zj 8za7JxAlroQC`AjW17=3qrEr)s<;1fz@)HY}vv52(^}IapmJG^z2N> z1n86wihd~4^L6K?*Z0ROVd$I6^$wb|CHMSn)OF*NU<;Kjj23r$<|5#$vl;H5Fc6SJ z@10EVzEt(qT6fM+=h AS_D%O5$Gb@S_bGAV%81%%7Hh{N&(czo-759knTGMNhF1 z%}@GHXXK(%v$4Gc1cf>?zpcmxBuj>@LHM $3; zs5qsy=I!U(t_l^089}VxhBBbj$+=hH(1tZ(F6&XG-5-N_k@Gs!crv1cx)V~)ve38> zS9AVXup6j ?e~t7G2+3qG^UGd(yE?|s$+ z7HKqn%6`ImEH)>7PFyx(Kf6tPgIR!c4{ ^Z1-h$i2xI&Ydno!^OQ5Eb@j`(?G< zW@cycG%u5jHUc0n^6Ql3b5;VArP7oVZ*qCC5gk@_qK98?RKq+ew@nC1i8epwD$+>G zM2M*sX2{xkZUrxsQ&r2V9d(N-Qz@K2+~H?`<->iyS7&f-8k~pA+mDptYG)h$8O9%{ zPF@ImB)_daY8TF>Uoi0@R^!U|1V%gdJvb>IJ$SDAd1_acc0*X*==Yj^L8>D?8H0to zDtlx%5JAl#mb#Xlr1O-j`|SvAli9~nkJ3c8_UZS%E(a5_%cp8usNAxY{Y~q8Fg<{Y z>Vzqi I)hZ&-IxXWqdaW5~(4o2SrSA^T&c3@V4Osz^aAee74CGea;|2J`PtC!r zGziaL*qK=9MW^w$=J=PAcdph8jQM&3i$yIzj;RgJJwOv|XU-JXYaLX2{K(}Js|*LH zT$s<>l63`pSOdabw>|V(GM3Aqm3hO*jI`-?PYIiiH`D$HtapOeWCf98c eV5A2 djNU9v;ha9w0bGpjxD&n zevi)^pdhpd_kwY3&k-JO0o;P5x@K)rb>VmDl?rGWIqTCStXiP60p3`zwQWr+w=wVa zw^GxPlxyCa(v}_SCs_1m%gZZW&m-}@`gLz$1oy^H>+RUAA;%?rdNa%#n67R+Inn94 z3s!Gea)PZQUd4ttU`jIfckp#60>Rtn_IfTPtFKap#k=`yEl=>!)Ndc_1`PHT)yTCN zm!gn!c=PkYf@e;?x=bxblRc8Oj!Y>AySbld _J)4LmLP-5nq mkUvOg`|>8vMRL07*c1Jv#cPsB DzfO%;;37O z<8>RX#D*G?v0g7J@2|CY%TUG}mjgt&DmnShbU(XNgZ{FsP&f}HIl7HH2={Ei67%=7 z?2p_q5%Bkm3r|hDWppm~G$r<;E0ACY;$CaEv*Me{j ?*F=% ztkEjtx7FfMoWBd%dB80{UFfQXs(%18`(<%H1 ?q^jn+_|p<4uohQwlVx8 zz2-16qj^=*HY=(tqhU%`9>6rRZ=c&JinhD6kz49KrxyhbS^Q{AjOhySeLOT3Wo$dV zXBRGxuKNAROu3V;=is{=ZQX~r?9e_aYj)qzfRhZP6rc_ !Zw)+iK)=2;-XEptvmeU|TTRi^uu(wdaRs8R?GJt*#(0Q=LU 8s;?b4;&a;$`FQ;^|8oI_t a9@o)g@~LqGTjxKS>NC23Eu_Qh zC!WkDlG{H!h6=qdc7Dp+D@%Rm#Zx@5H`>n+{kpX=R#s3Cmuu~rt$CH!fyF+nB6&uC zV6XO)phn^#?j8V#!sggo@Z{C22681UGRyQ?#$@+X0RxbB*DT;j-M=gMdZ;-gUA`Gq zFCow!dn1aXf6_MB;oT0{ihdChNpcQ6n288lUADP +_j^!0}ZbIj&*!=3vaWYz~pu^2>5_|8NL*SpOVUHU8aDf9>Qbqec2s?0`yT+c~ev zOzT~aw77TQQal8k0WLNVz&{JUxtCx4JVslyoWH9szX#wmA ndep6MByS43k(lqVXb^r;rRElY5ZbRgiYYg#)qyR+JIo|q#Gp6qb z)C9_M3CuXYB@F-ee-S-s!}0b(tuZKEVynq5b%3%+oF}ES{p2LAc;ti(2N1xYU34mH z&3!G}*K28TAM>TLPoX7FdUm$Em?~3D1xk{_>b`~QA4tYt+YU_3VCX*My)s)mq`-_& z#FZ_%8~(z1<-NOct8BHM-akawVavogfQoFhQF~)GvUoIr$*o%|a-iWXjpRawNZ-{^ z*^H;=(JI@5y zetQ#hxw}-l*C{285RctE%Qd$+^mKBf2075oNOuHT#K1;H)hBqlIV=Ji-E=Qy?N-+% z?|pP#`U1C2 F8TV>0^@`x&xSSl8#u|1 @xJrMw+W|g>v>_+;64?9@yNFyx#O_g-+k@{@Ya^F_dHh~D z@^x4j!jSZ?z>@#lD2%jwerc=bO|y8=ZZ+wn+4Q!}N%^RZgK;)BNPz;39yv=MS$T(q zH3E2iWv#J%j83JXygQpv*DQzEC;CMHUggbJMKs?IBy50G=lhHfUjY4pF);cDVxdb0 zcq{!@G1fkgTy41P2{2J>WUkjuAxX9Qp?Q-42gE#P=Y^}b8b_>tVSCHFt4zu}xQP}^ z+I~usF&m6mFMxm=GIQrn*D7DrH`cdW_qt0Dl@*^(=>=}wMzxR@SsuH9ExliV@nQXZ z?vaQ2PaE|Ztt D?oyu?tRHYSg#sSFu(5C!Olbtl#)i=uI6-amE c!!G0B0*mdq-s zB%j&kp`kV3t`-p)&MSPzd8eUvFmHZGcobI8sjAjr%?cQ2AJ^A%m(IpWgk^uLcoJ+G zPpdFf72wF*eN1GMlC}zFp~fV0o#ymb$Gyy$Tu0*bT+rLgq+=FX*wh@dsFkhCsSgWV zwpcqzY=(`dlaKRQ65BO@MBJ-bC@lBG_(b>3Ld|j((7fbbj;%RyTg)om99D9RYJyWg zh6Bq9OX+@XzK=tUIcsTaleWe E7zVEoxi1MzYI1r2 zlNgLo--GvDr+{7Ydq|mXV$?hDMU^HeK()Lc@z2O@JZ*w;naC2Ps@PDrA~_s^u4CY} z6lJ=xemJmJ&ZD(_U f*`? |VS+#U)BLeX zTIn&pNZe@s-(9d!iRmNe{eYGFg>Q4-onm(*jtbGLPZ#mS3)nMxEUTB1-z9zwk2)p1 zUzUB3g1j|fU~d8n2jsOpzTj_U=qxr71fGQpnXMmM+sC~9YNVix26pT{^;}E-LCS~F z2_g&et9koco^VT|K7R(Z*hkQnaGnI}%6~6{=qf15>D_i~6bD}xhF{ORK$u|f8sNDB z5V(j6-DEm>jWTE5j2`EV4^X @Sqb-bmq+;g{kaEn| unCtS$tm7#ugOZsz6X!UMUseI%F1KOFoZq4Pv$IlMar$dhIOtc}5$9>$9&x zyv4!R>zj9FdG{Hu_pLn`-GNsUW^~ubH%AtC%`#CFMho;fYFs4isHUI$?OpxBu3Acb z;a0o}HFE0r{m{GBqUmC{Qv3$#gcTVA564hzO8eER7E_1hd#f{*!MgUstB0z!J3f{6 z4%P6M1sSUXJYl_^*6tiG9q1zaU>MsXtFKt^J>Kr(be9&L^lA>j{^s qaU*qZX5 zHh%EsH{2`_wgJtFnZ#L}?w))hBU&)>Zvq C+MVvaWPFHcUetyhESdy4A1Vq85PU814a~jzjdt%v}}^^K|jHI}R+zPKX@6@|n#s zW*jJy%_;eXA$<*sgF2kqfXhdyqFSWOn^>WGgF=Z`6Af&1*vF3__DXMSZG>mD!{#Ge zTj=t7q$%hNqm8@Q%+JlcA8%%xB-x}VGyGbHi)Mq31Fw>u6i?fe0~_t^GSnODTV7nx z$;C7teUm#f3ALmrKh_!3y5+Md3X42}U{cfO%Q+ zgbO3V@Py04=hJG0GS>~HL;d;InX>O>E^oNjPa)+ryxWX~h|YPXui+5cb*?_C85Mch zu7QPlP}lgqFM;_760UQAwN+HTyazH=_0ZV{ZzyhLwR_aT&(LDpsRMJ|7o3Y3CSPx? zjktg=Da-HPh%pLJB_udwDZ{v9=sTWHkV694u|MaYMrETi8-fAW J7`_5%Of1l}g$iB1kUBe5tQ8CtY z8@!}r7wi!Y>a{E +P?)|A* 7~559A-bA xvv8*a(&1TyCK$nnXOHId$wg^ZMFf->P+_ed-kZ z!) Sj05nA7nL`RNw3|?Mq+4P4^J*0fiL}+T)NJu5+ggRZh@x_*QAZZ_X2LH za9-?JKoVC&fIMebFMnwWZtV1P@!mQ@jZnW|%b+A2`(AMwo_Eb+=22OzydU?9b~YHH zHh);RHUFt`{$;lO44|VoqVD;!*ttCV`^fpeaTOg$Y6W;uA&!nw^ zzAqgx_39o5S9n)kbvLTsTCLgw;)VUTRx*ZZ$&UHc{GvOnyaUm;+(~(J=L5oYE&3Ij z8!Dx3<#dHs&mJgXo{NZ=rwx24PvU-ZEZRx+0-Q=b)I*c MZYrnqfb8+0d$QsSl
-VMHv7 g{L2@zJ1xEyoVT@w+M*kpiP`zupch+8;?Ap9lL=AyBk)jm5pQJ$Q*m&Wj zaf6HT2Jm@0FKRuIn_YVUbau5rE!|$bOqi!6G|m?Pz?vpt@l*kgfUa=#2lg8ZQ{a|R zvCrtuOJ%=%Z%8yC_v#J?$pl`B&Z_<;1{(3RDent+@i5stE4e!>L-4xX1eaj*LtSGa zm*K;fLzexEydy%yu6zsaRwLF1s#^)ALp7al!QVxOss&6Xpi)?TIgR*r&PTALy{YZb z`%g3)0a5vF0FYSjZrcB@Ubm+q93Z%3ES(jvUy^O9!GO*+o1oj5N#3S~ysR{xirzkG zW3W0p58BDfua(TU#Gk p}3TagWpq8*VXyF7}k%(V*3KM=lJlR)q@l8 zaIk&6k&frpO$}O4o{gXgeZ0lVYc~&$Vm10A^haNHYYlC`8;xd-u3cFKavwP6wb9^< z+z)_w&~8K#vVxpL5~cS;?R(tI;!OgR9}?XNsEU^yiSs95*bKCQk0vY>sx|Oy@7V{K z6i+)>Z-rG%oh;ho_Ns4=*VAOqG2Li9u>o!nSZZd2h&B5yD&DMuxzK#f)n}=Cnk|kn zv>{L4TA3H~-AK%eyP~Z4?LOe(-e)DIL=7ea<##!1(0=ZV#vA=KHc>t(?hs>rCwrIQ zr*nVWw{UE((JSM`Sn*+<_%R~fI>#Szk2eR-;4oH)=1Y2pROMcFI)_vhx#Eex QHP4Ts#b}G?&+l$m>TSyhF46_ zD4nUW1qRs&cC2ky$;7AcjMh*mr`;T>T`K9P%Poq{Epjq$(EVV)1#V#xlOcgSPB|>y z{m1 Ya3(}lY)FD>8)fatdEOZ5_tS?*9qI@{r+h)HkA z{jmBLZ`SLM0c~<5_glD9?-Hx(ZF)8@7k;oiEHxAdI>*|Kx1mF&u@(G=c!yq`+yQ<; zGr5j|;_qAK(_4!cZnLEDKcAZTe$2PxYDFa~biDRT1W}jfdt&>88n@nDvWG`D?G%1r zykB)vfZ74i9g%EzhklDb*)@r80xDYh?X U2mh^LDJ_y iIz@E;dkn^#nhigx zFp9g24pYCys`f}-V6QouLlsy(ARh #Vl(>b1in(`9y_3##v!-+GSWrz^E!V}Mp>TN|@!U8}P_!J)?^7(NEhdH}`-yY1GV z@l+zK!n1X*gK;P<9J+Mgef#ZI?*D#Qj&e3F6~885yLLcFje497)2-I*V#O$!1pWlE zD$`}V>k&g*eP!2_1_PqYnWX@1QD?p{SS^qmf}f^wJcqEZnmgcgSrRgZjHSaf?- JG2Rv$oV z=hXEr!x5|hdn0z>H%y}8Q<$jV-z?~x+N#;A`SlL)Qqs3ZW06?0Vj-fSQYMb&E|pO3 zJhxbPk_nac#M%JQ2Jz}_l{CcOZ*A6A;rw|(Ftk60(c&{5gDuZ;eMJjZ^SZKn#M70; zY8@RAeRnpR2wLqfRJ*|SvF>jM-KMh$Nk(%9%Sw10?k6ogJWg7mnC~iI?Akett@}v# z>~57E<%Z9;7u0ue16yVs^@xhz-}*Lyx|7Uhy0C2HxZEf6&qDE(^|u$1!+8sz;x&Y% z-QZT)lb~EC{piORYTt&x@FG^)T+1Yn6w1E!6)@gaJW8yl1^8w<`eCjjqw2oXihJ z*L=U_^XyFHGW2E^(Wm<0TIoqWKV{e{Z5X1its+Y2w=33}-Yb4^M$((HYhU^m8mOsv z`TL0T0GuoyE1o%t&I@5bxOLkZ!mnpBezf)k&}-R}u9yh8kG 2|< z3eO77_V(WFo+RL&R+H%ff6Xctfb&ArDljs3Hz_w0c7EIwn$KyB@Fl1bH hxGi#&BcANS!i(r=}|~)e(fmoa{^}7z;Y+`_Euq*GygT zyaI*t*V+&-=D@R)w-g|?#%gT|i+2PhLY2}Hq??4`Q3XN02g=}8<15l>4ac#`p>CFe zoV}EnTh#)#YXj&&6-2q*@L(X~@0`361s?Uj;O#se6`vH<#{Ze!Zh%R6sUTY_1#=59 z)cVyMx8-sG@3z21$iNqAyBe*&eA@1V;w ^9qK@-A3L;)Q z;A1J&R2M3A`>PUox83GxbV~XUq;R5JK+>uJ+STZ7;{VbrN+yU!Xs7ipmw^D8P5!HI zKPe=vr2k6$O `h70>K!Lad4M%D_uMtYd5 zDrTFWbg5EN(^0qA{nMQy&5Oh^ay zBJdoq$uKPdU<*j)D*V5O0}VT$7iieQ&*Fv3yw_cw*Uk%=>XHIGmRnS3Up!q(_FMgq z=g&M~#>sfT$+E+>c`z5x|0 8Ak zCpn@Y@2VtV{pY}4HG uwAF-{hD|KSqb-VTE^cyp*-|-<9Kdz136CO z kLO (7k zsZp=@4bZRMfg!b$IVGzqcrmaKgC)CGz>14UuMeETeK4_^j4^;t;Q@Gjh|lze^&Q!? zMwY-9)9(W8351N)hy+O>p>vYpc{|-{!|o;kLO@;YuiUotot!X*nfLEMXHBmT-w@JB zxUQb1LCUfT-hI)rz*se2k4)0rZ?-nr4s>H5m!!?Z93NeD}Vc-(Sl?xR(8TBhcqL zNE%p`918vf<(H7e!{l9?t`EQna%*?>7_JS~+q{n|7&jS#7zDtp1lOl-g` 14#Fq<0{dy`+hd_Cr)xK#BJ*6IN1{c@%h@6#&xim~5AWz^s4 ztXaE-e#}y7oH%kN0JZmbNDS(gCev%9EDL|ufGDrRkJf?%W(-?CY)H0Q%d )vuy z7|+_8$Q +?cSxIJ`P3?A#xxA}O_n9V)hgq zl+LccNUy#6^^{rKs&~7cR%juKkjfc&4FgRwK1nwg-w2?Q!tQlhsBHPvr670HGhD4% zjR(-h{cib(mp$@ Oh*bQOg~nv8!*h>HKu9ix(GI8^8W=UI3orN=IG*O{0sQ@qT^aaN~g_=hJs9 z(2M<>-leI*xbNQAXYD(zrvQIf0j^}A$D^3}0{BskX}=bCiy?4-r=eASl-wyG$`Hum z+f^6Qrcd@9r-Qdtfa!e4%M9!%uuoFCuV?4V )+Y_<;lOau;5%%bhN;O#`<*rK3cQy;snI=b{{TZ9tAjUaY6Gg$~v=HnU6Zh%qKyG znJN|000ES~ukMi%;Cl(BW~*@u26yTqWb?r5u-o8?ZNfm2mM7DC4)-by07%!uv->DR zxze`gZ#Mt$O^gRkQvDgPNlrwiF4A`?(bXR@KGG1Z@&+Qb?>h=H;l`Jcq__LET4rBy zqI1PMJ{z6K_6R=a`ufvKM#~AOc8>}?Ggc~7-G;5GZ)s0srCCeB2$#%<)CQ3p8IW%5 zyKgx+^*vq_jA%o?W)EO`zrVLF9K?BbY#sT$z=C`)aE*tV`gzohHfLm?PGYd2hBRx4 zl$P@8tgq6q!X7W7JWaE2dTpj4&at}#x-Mly-}?6_gK-+=BZQj9&a; q<148K{YcZARNR{G1}ZtuffKFSl|ZJp_-1a$7tM}qcMv(5Gp zWlWGUm3gl*k6_o@Rie$>v~>I?Sm;vjeXKsQ3&Y$Hb67m?TA5Ot&}9NKoEhIERu@a+ z^sh!wqHTV N?W&PY=t0>%wJ4R$(;k?-N&R+{6 Eh!2I#SO&xePJdGAysc{RK D5WV}lZNGJx)s8{4Y#M#dL& ~N@s25H_7N+=U5v{9AyR{&vPv%E^0ZOk@f6lNM7(0e) zFi^^$@gXX=V7cDE6u42)7<#}w3)I*bvCux$rqye+X6x6jsMiiTphR2(%k+PJUhnKP z*FewXu>Blccl}9tH53Kal)CaMp^#JjsS*#AysL+E-g z`)-~*b)9!>Fx!r+9#DSmLGa^D;g%I_A+_&k3Dn+YZF|V?aMe5S*@K*)fU__4y)N*y zqj%J9Sx6vd%&-M^N~Pf~Vio167kS}rdwLUHN|^2*%}@PcPQCyC_bFWrI5Dj&vfQj% zY<+3;uVHj~KM8Hu$dlsjhI`?jq?5744D0M*cDmeO0f@=yG7Q rSv6{~?&^nV?d-9*|I!|>b@`rvUb5K)fn0}zS8WxabA|727{U40 z&&>i?ner2FzyL;Rqb z?0cHS`{3DLT*R%P-mSQ-eX*{lck z!FTlE1rFQF6!b3JOVg4XkX_=B7wD6lVt*-ow^U(z<=W^p|`H3?FZ2Q zb$FA 01^fhX9hmcRA>MC4(dR~VoU}ltUMQI z^%d=3fPyn^T9H<(mjqS=K4Z8gyz}i%gq$6OM)x_m4mJbVk^i1G=d_wASpN2j3Nf={ z8$E4)S-il?xgoUHi|fez06aY&j`_S9%t7`|=)<3@Hk)6z{JoX~zuKT^fubPq6aElQ5RZOkJ$shm*r+Jq;$fY@F}%k%lglvK_B8Q(OP*pE MlX1 t^IlkGb?xlhcwA}~h&2@2Zpyu)v@Bx~Ype9C?k%feB zWY`gmC)E;t|0Mx08-B0Qo9(<~6`89?v5hga(XzskqDjNQV#})yv+8q4WP*OgboQ@> zFueMWM0}-%sC}xp%*m++^mcB2!ZP_n(%PQaK9gFd+rOM9L*xw{tv`}eLJa2-y~} =EM ES#O^f5hCI%XW9ANR9a%Ek-k>7rwY=eDpSUK$IV z+5(Wbz?M{A78Cwv7ri}$*@eACUGtInodZEyJ-CiKClR1nA3Fk=*x6EDU?LT(-O=XY z@(bzilO4e+I8pApv%`<)7GjEkejir*ZYw>I-s7?Stai3_`q;B>gjSPPVbpwQaDmg% z_ssN#hj~%SQzh 6%Fb&6i8g%^zXg+wZ<~!?6n1azGSauu+z*^g%dTZ;yoO!hhI?>1PxxAyHWpG z<84M@I-yxDZSdZt9%Hks)}{1a@Gjmy_+IW(W@;1u`nD)OTEOvzX$$p`Y=67;A_r@Q z3ZL{xqe8Rb)qA|Tyv~Mr-reHBX$|7Gmiywss0 -h^` zan1XzzfX(hF{kHuy`nhF2~8B1gPsQ;YDI7utLCE+BHcu*C`H@`5*HA!F5IzU?r40G zV4N+TJm$+}J}b>OakYLP5;<0bIgD>vF?}C*phFuvJGaH!rcHgaif781w2rkkSY>X2 z4b6TCrS<@7y7^^ee)O$sevIOv+~4+O5HULH>X)yLq`7DWRfGT`0OO%CU6@t8Hx5Ty z>E+%p<$mn%>GU&IyVG?-8*%Fv$U80nb+6s1xXaZ!Sp*sCix@?~yW>%=s@VDYi?^bY z&j{gGmBY5MR98 {EMx=$U2lLHqhF6%K$n25cjGZ4uSS(Cz%PL4GRw zmJ-UC?5o&neE$`pN49;;u!xHe1m(ctNEylDaCVJsz?lWs)$WTOi|v(}Za{L)CbSMf zL9qot&i2O}p|N?6*6q72iyu;gM&s?1Ruua)-bDV1Y&MQF_C+;0`21qB2Deg-AAW#5 zuc43T2RcPxYS5~g8**74eE#{Vyb%yx6{PT)RVG*toGxMK0O%RJWG?=7AKUgK07ffa zdZ&jln0^GszK3Z)ez2+Iv5 3@7|+K)X~=gb+!;n`;_%jw@MdzO`_;Gc>%9)0YcMYsMXdbb z=-+5-e~FT^^Ds9(H=GAmozg*#OU0>j0Ra)U?r+s?ln|{DJjZKPzuNqo0xR$Pd^8>z zrzm`n2zbkygRpp(#3{Py2k7`_b>p|%hML>F4Sg?b&lAl`A08EqA&z*3x@}n<|JWW^ zofF^tuq2S`uWBr+?^C1uB6_~t=40gtfU>3C^GBcsW+b>uyE^M1q2jgPhAq#JPup$1 z!rh)j3o#$}3?!h>c=ig|533J|7SSK*)n3*tTClcetv#5Y$6ttS-y3{c{d)6NL9M*I z^IcM+VP<>QdUl$HXC^H;Z|c16-&XWh6?bxVbMI_Qbpm9W?fmtoF$XZr4phr($08FQ zTp;x TUNE|ScJqO{Dco$3Y<(yWq2MY&c%8e <1fW&gOu$`ewPPPTLw3TgomAf`F zouYemU18uZ*g|8~lk>AFdN7*+#q`a n=Rzd+}u#}LmUkf^1b?uwl#Ws?fQ!%2tOOw{ziIVD7F p zV~zLS5BVZnmo&`_49$ll2n56~TAh0ycDvkkaKxii59IzGL@!c~FwTBnXW|Pg998*L zQF&Bns7ED2`QHKQP11NV?2B9hyemf6*Bn*)50nB~DDLdH$oY50zD28cd_D% X=ZI-}E>!N~ZycFG7Cr_r%*NqtAQxrv49C=eez_ zwyoP|K`~$!6;M<}f?^JcAVGp)M1uPMw~e{azNgZ_To18EXwh=)LvttJP@diMl%s zSr2ck6_vFC1K7~)1x#X6t+TIFV8optXE$SYI=bI+O`m(C(|LDdq%(MG_H(xY&A$+G z)I*(XTWC<5Q7Qz-c@thyLd>!j9Me`Lux6#Z@ci20^jRp?+87Kt9Qx4g9tFDZEY}Et zNB2$G0aTCW^E9`74(QS8z0QvPS8%tMa`6*Qnhkx;Plep2cKLd+V$M13!t)Z9!$PNh ztqw~tjXn|-rJpnAy?(GyTYzvn^xtB8*%E^DZt%OKf=ujODT)azlpjeW;!3~5ple`} zGhkn2l{7r8083AM4Ycj+)P`2-s3!l!i(ecUKSwuO)dKpmyr#PG1syDVuZ(`QVrk=> zNsj31?4=fA@zct(96jnkJ@P?6eWGxyP77`RXx4W6)nhJnAZ&_ZeW{Nu#wAy16~y zS`tLs`38YI*-?J_AX?PMarZdh8N#-K-1Rg4*K6F-glc6j^}!E+lH(p{`thl|Al|*R zC}WG08V&Kr=}H`-QT+tQM<#jYvGWbn>rC>Ef($#@B0ytnoD!I(&KtWzg#skjsq~!b z)jK|3Zl)PaGiB9Z#>?^h6ugL@@-2<(mxv(gl8yh0c))9%ZYIlPl;GKDC*OW|wI@qn z@_|ZyERGkgW-U#m-GZs+U4Dgy$iXG (Uy*L>CK-ulp8Hx|Pd+&j*;-}?4+>BAHVtd!{)uk&kP+jn2T zEm@%N;7ZcrJiSE(`mQhj0ERoIyV;{S(|M&wn;>75htddEN0)k0$)>Y{B_>VrlT2II zTTKssOGSzC3GsSovL$JqGU%%8LTagv89&=BX`}jTLRR3#o$Gb6{;3c0eZW-wVyY)^ zj>kHDoZS2=Lmi3}mVl7&VA#L;ZmmCugjYqRy%>vsaliW0w@XfeWA1hJ9?Rz!p3wn4 z>-b6jhn21QOpjt*-2?zx$W=Cr-lUhSV=E<_c{~O8HXg*S)- ~n+8Z9Lg|)YpvUiR+Y{^ZF7|t(iJ*rZ_oMmp8I}T#wwa4n*r?&{+ zFmuf4I4Pb66!9PjWKq)Ur$bf;%KZ;gNEMz9<1ts9^vo>R>W5nASV@>?aJpW>VpYb9 z2 }{olp?6U)eddsVfW!yp6-{^6y7%l75f;^$TogbeSHrBM`p) e(r#mVI) zZb5r6y38VC@B`yQq2wOH9dAB_6`mI03uda!98QkcjSyzhgGlOe*%sRz z3R@Kn % z==0gs?-|S$cbBDRclySA^<=Q^XtGzBtgkMT>)vl~b7e1I82%pSTu_a{5dXdLZEm?d z@16YoS 7MZ~vxPbCQ6%XS&dLJFCY694Hh?p&Yr4y(|E;*(1>6;&05?j{e5pE|e z0+O-EVV@D=%yE&^pC&iMUAuLLOj>hZ-X~@J^HD7WGE6%=Su{Qf*GD$$o}FGl_Zyt= zEa1ToGu!p9e2qK&=qEp?tXwvRLEL!>mLn=oO$;pyk<8_#Bf$iC{^~z!-&%h2TxCJ% z9=+F2-L4hznQgDq{MtSNY#AT4?8n15gKH{GB602&;%;*btbM!IfPLfSexQ#=mIzJ8 zF-~0hv(lbX!8I-{7iv8*)2RXy+U@9>&&JXzbM2kK41KL05>++~vim$V@I_qz-5RTR zgRU$KOwsFB2{_^mkuneV_TSBW-z24zb3n>48sON+^eB?-;2F4qsg&Jd=y&%)FF9TA zva8;nzi*YkIa1sbR$AC?0sfHFeY+^xQxB$Zz%R;8PKR3}`f=_oLepxgFXgaLGgrmA z5py_`QBQfy? Oi+IX!oK`y_Iaik84y zoNGR_S_U`23P?uIpcY%#ww79T&%5%^Z$m 6 zbQf0Lss!xUd+t#H-_$CTkMeLB#IZBApOVcLvpwYyBTtNTz|woUlc>!uUNMhJgMzI^ zDR4-%XdJs`aC)@bxeFED8`^f6YBLC{URdxZzKJH}e6Ma(KBr;G^@dK_-nEXKoLDYf zgL=Ck==%M)2Hxo@{xlaWiq6Zo*$F<^nVAcI`H*={%;5(%Z4=&0v|z+fa<_@C4z+w# zi0SMIG79%--XFX&S90suxj5gn5CrrjKZ5vGk~xc>8=DH22TV}sIDJ6%=k>ZaJL(X! z;oGcyzhJe_ZmrCm`=gNyX>afVKuVNj?lp(L6g(0yl}`0_mM@g6O803o1ps^|czHVQ zJ*wgef&6-J%52z7hK7cAX>dP?=MJ<*=P^mK8QXJOaH7%aLJ;LBe)0mO~qC&()?s?%LOtHtv0@c z#i{^BybtS0m*b?9ROX|gmt7TT#Z(IGYNrTs-Qs4yBqdIZ@$>dzv@;PN{DOWPsEIcz zr}r!vd_0mQF6w~D1$H3+24yJTP2%bNvuV*vDAsd@hXUPVtbNuek7KwzF1Kt+n-ZJW zJj`_Ian7l13~u;~{pbN-*f2B-VyNwww+p5q^DlRtY}mmE0Z_oGQ|oBU8c$xPMNhNP z5+}Sa>bYf2g7Xg&4Jg5o>-BXnZVxA=Hqd_0rJ$%BTj#}NeLH{7FQdN?3VS&)Rb=`r z$1xcW&3EHYe>L7M#BfY~1^*!yuWXpTJ)s`4lo~9v17;pjqcWGyQ)0%0r+Ym`c0SSj zlepBEK6jomMN1`D%qi`UaBzb9#N8g;-zk+gXpVZVX*OPukTYiFwEA?~-eWhg%mV_c z&;?Y5v_|mmK*r0bwYF{W-&~Rv@B3Oj;=1IyO@8kAEMcFX44--M#_n%L!H|^$Cz|-dJ7Lca+Wedp- @2x zx;Q1mu-tB8u eOd{ofE@!DEFhU_wDU_fk&X1es0OJ;UZqK5FP=*HB0f4E##2dhP;UxQqN zqZm<&ZE8J>$+Qp28Q+# |_3bT*yOYg=x4U1yRxuaDYPr@N?X{bG2hMVBA$78618 zGjipjO5UKAL*4ZiDR=gaif8JG^u6LQyvQCcSViBV_;d4uc4GC+e$$xhc*DW4aNgZn znfn=`F?;q+58Vw+X>qbSdesl}-T^T)D8UZJ2HWXece$x)|M%gxFJAIVJy*TCjF6Vt zon3!Gb+J^TYGn3$Ay{0+i=W56aR4aRG3!kp>(8^t+0vGWVM}STQB_0X)}LOn1u@$V z(NZtNHZ?F#US%^n1=&w_jo9N!_}eYuk=%Lq-Vg86gya_-oV5IHZ4bS#Z~K-P8r^#i z966oFmYcBHD8IcFO@)}et5Vb@`SeCj>$bHkNoS?hKGFJdhO`Db`KG`8Or_lFP@5jh zL2*9a59s`bKjjAheXk19tKMgt{7ir6l(i_vuU%nZteo@jN;}S-4oqBAZY<=e+CHo1 zGTGygS__wZ=NCGN1$>P*v#9l#`wYIw3!o!@j6vy-r}|`PY;RIcxVm7D@_{u2ZgCpZoBRDrAB%?Rt$^y zVAsK3yyCQjydJ|bgeOJ7o0grGHMsJd+M{0z@ynvxhi38a_ V%Ap9goG3jp=66a`C*J#M}GJqhED+SEXJKRlo7#va&yLO_cwzJaBS{# zrEGobox3SsdKY?wr+;C*e&Chi%KyYAc3mvBIy>rY7c^!XXpVcLSXNZSv29!O3%Wt? zz>yib7hm3oCh50VhtQ1Q_>$Yh)UOAN-RGR$FK=uzjG)(}K^K1k|MY#Z7a`G+LG3 z-m!Z43SS(Bt@C+JJUx2~mPPw%e5zh?kuU-}gP)gp7Fp__)Nx7vyfADxJ0nDk#4? zeT!JJcBVZHIXOh1Un7}u-0XDDn_IfBz-DYR?f#{ipL^sx5@R0y>_Mx5= pleYAW#db=dW*%l95)J!})ms z^n>=_=aD@6Pbr8m)~Ba*!}1`DFx|qComMY#4} 2%_IA)EP{+;TO-pme!u_MElz5l{hrhagHuqc<~` z)7_@2ugr_1I4fWvEP{Q~fZ$2S^owd_cC|dm#UsC6*-7VC(SwyfBEIvPRFHGk!pm3= z9w7@L_^7n*4=1+<-{dA1b@0k9INHhnl692ksOq~=PT6!%8#3jM&qIeL>Yqs|q&p-& z@9Yt(MCMy-=)2Kz(}<06I6uE9pFu3YW{uNK2M)P}^@_WFlpeF#2qwki`o1)K0Dtn% zLk1d6yq095=#_#?48IosX6v~5D*4pkflDancTEOC7o%H~kt3>k?x$U(j{7N`dgN9) zufH8_KJ~tMu2pY>b-*624R-wu;kKCc*QZ=U<{Gz&u3TQxoS#9S3Bj1`<9~isk8p+` zEb|jGLZ33r$^+_Kr@u|j@`Dd-ruC_DUEo|lx|?lnz>3llyUKkK*nE3IX FiDAetv!)P5TpUxY|L*j$B=z zz1HWpfIcY~Uo#hZHKlTcl=@kN^m?yVECV`Qxr{!Z&Pwe)ryN=!ZiG=WeFI4Uy#u(2 z2Ebh|ukHhQt`odq&Y*!j;NXVsRf?U$)C3;?$O04D;ApP=%zfWREPi25?M!LR-V|s~ z@^yEA2etj-xLdw+tLfo2AGyx{Dg?k_H7g}%qjV~zjDTtj NaL}Uhu=#FGDIHE zevXznOP71S`%)uLsIS8=bh*0v3W4xqt`bJ{49(%qz@O1z)VVixpU_A6@P`ifv(+VI z !AV_Cq zt~20_T?Qk+X{DV!@g2SUXkOhM;Cxu3yc0J1<` *h>pc-R<~8c~!+9{#X{h1J!{HzkjKo!n1cUtTjP++IP# z)HR{gW@YOA>0-W73wRf6a>vSM)^=`aAJ3h;zxQt7cbijknSG4g3e1Ze@Aj+O9IS~= z)) `|jFNwK9j-(LuQGw8pg%5*8ViuM`TTBVlv;)DbnVvZY4}Cevs}R8K z&wA|@9K>c;p_{3{Aacje!+^i2*Zkcx33{;dnd_jloTz^Eo8K#qV{H#?vEu z1Pv|Gn_=B>HnmYTMtdcv6|=)_qhKE~>|3b3inZx*EE@Q-S @za3LQbN7f(YF}|^HogbG9soH{t9zfai>+iO= zcp$LNw4U6=U)9A`*lzz$D`JW5^FqR#4%ANOr>Q!6Wd40*tX6mjYW6UqXKb$R+yy3Q z0- caH4 z?4K%=3fCPQFUm1LRbF43U2FfiKGa1QtnI&j5&d8g#JJI~%(Q qsk2;)P!Dd>3ZA;p?2BSSCF<}YTUMyL1ay1Mba`uTcPq-I;IsLO$JR5@nf zV* *dy}kLN=;poSjr=QSYCCwwyL zf8Mi^148HUs;K9cS?rr@`fy70A%4nRmCmiZj7rb`RN-K+Mq0*-Pldi`C^E9y9pZH3 z*X%)rk0t!Rsh8{Xasos5&DX=Ov0U97%ldtQk)_+j*`X~Zz8wQ2ckPUtapV4gTF0ZR z%pvQN*{_Lsb;z!Vr6UIT=BRmJ&u{+aX|zx7hIQKW0^^r}L_4^Bewo>0yhWe2H<)B^ zbV!swJT_D#zd1(c*CZUWmsYfo7F@Zsqfv@?ABP$W!EUK(tn7;|Y<^K~&R1z91qB(T zI|F0?8=S}Mx(Z3&W$+kmc*BBo*U0G1v!Ih8+S+aFj!)esqHPOAi$53q?j`&zq6?Yr zd$PT}WJkA(cYm}9A%AWBP(iC48tUs~nfOu{SkB50rpx!f0>?Ipvd6q!u1H?3WAcJM zH(;M%4KQ?|kJ2nt8C@bcFJ@JDxq0UM!M8LuTyC?Qg7d)EH9gZno}}j8UF__^N!)>G zk-2wGkMohS9k3<~!eeCIjKHAYDESF9m};;@ t za~M6_r}y;#yRf6(Yv#`0kR1TNXgjA49@A!e{NW64=F8t Y&FAJoIGqG>P47io99gI=KWP1P3n) 9e{(EMJHHs2>tiom zCyach$QYKf>tl@@c+lIsD~IMSTb7wDbA>{7vsj`l`g!*t7K`j9mk2qPs^nIy<_`bb zr^YV2%{_n)va6Q46_4q(8s{fJ;UP*LHF%e#`&QGR*@AmtYI&i*D}QFST3Ja%&4Lu{ zH9gOfk$JCX@ar}3hs7dAlrza8?Or?CqU+xG={=W^?aR;o?e@Qnyjos2;LSvZ#_c=U z>uPZA!8y$FS=H9muNaJ0h4GO6DeOvlQ%0{|6OX 0^oDUK~1&!3U`0`_d{=s~-!up9LD 5SoUu{m zJpHSN%QjQ$ZA+VF9u;qtGXwdW-z#*8T8p&6A8Oq9Z(jZpTao$(?xr9~2l3Q^Jum%D zeEUT jd 8ZWP?uC1A+Eu+|U&j3_(j0#B5u+o^JsCk{CL0PD1UIc8Lce z$l!lh0CaatWXo>x91uVcdQV$s=mNl!#7(suZ2XBn#>R$H_U1 VFHn4}@*U$L_QoFA3vtK#ODH;=InhDSiv_qHBCg&w-7B%MVQl9uCFLxYf0xb U!$BG2mWDmshc)DL=XIb-jj zj3!{rjR61mPay`6z$s={Y}R18#i)W>CiY#zoz*H#@4%xs-Je?SAoXp#Og#@05OBg> z;rMF;OlZQ+2Ia=Ek-MYyQQ rFzVTl>Pi NivK_cNGBc#JNWGwDIs?w=Bl zh_f&znv)~@6BhDZ5}%XX`;xF7$RuebKVD*jl&KDjZ#J-c T&isb zwhOJ{BG@LL*X-nfJ9^y&!dCN9oND)TvujHTA-}q8zgz9BbtXNa69y);NdwjSa&96X zRJPkI!2wq2|5mxYNw2eP-Kzp}uA&tNVT9cI!F+RM5m_d_pZw+%Ejy!YIh7}G=e>?* zHoOy*@!v1QWq&HgJm>2e?`&Z=qPC}taX{v1z4e+m&%=tN9_ir(14vw9wT~W 7(x5(|PWyHJJ zmH8P}s}V zdYB5d*i^@Sg;1%GH9NUqy01fEo_mG!5X3K(3P?Ww-%b5q2m>y8U0ks-fNFd8+;qv# zW|ht31BAS8CXuv!Pn!BRZlldtFEf(O9yk?J)xmsP0_K{Y23eP!*CuCM#fjnj qvqL8NL!Y)C$sMIV|qo6}mK2a0-Cx?8j^ix=EOPqVM!iDsXL4 z#>bwNGDn~@y%uXzNAbR7;V0br^}FZ;)Rajie~09GRR%>mXSCkwS)N?@b#njY#^(~p zP57-$H;)DP@~V(N`5V8~dXp%+dyDI! a#%JQq z_wue-uMLNbyi!?zO2y+`Lw|u(HNvc!M!M!tf3;VxF^Wry)P2V7;sW_P^=J@I0y#6i zCB*(~^>eg8Ht|xzzU^Cc2j#4xz~Re)X9VP?r64jdM8(Q>l=J{OBhAwNcjvweNIdY) zFpk<4pVH+?ya)3o`;9el=GFPf{N%|uG1-AZX)-faeC9&jelWQezf*lSfuMsQd^{fg zbuJrv`&g&AUp-to4rk&GNj-BSUF6MypUDE`qO2v9+s?vp)T(x*8&~X2@>ht>;JI;X z%h9E js^ zmXS0NY kvYBh4Nkk!yTeSN ziiMj?Whc*JhqyAUgAU+_RcYU->ChG|mXXm3B0V39p|P6YzeLG)0&x47 UoD zSIrzPyQ_rK^LV}y`2(u8w A*T~&|u}G&+AuTTI1Ygalr@VX bp!y?XPFdWdB6a#jigV5e?jgNySO>{XN_39)AD1xrE4tIrF64_;j#k zW9i!E>TwuQXING!r?xF%U)rxLQ=z-CQ*E6M))!a>rv4KUd&dL3KE}|Yf3=jOfWYqU zkXJ;Vo1z50ce10Yjm+C0uL3*f7Q3$PyisFFf-#{qlWVG8&E+L|t##x_W|!EZ-+p+% zXjyxW&_NcCtm5lyJ^s#2b~zfzuYz2ho@#6GH#AkZ#<3lp?ms}LdMArh%lMr80}(g5 z7kkVMGPT8l?i70-Oo9JYt(kTo_3i^?b`5|xWZ}YX!Y}b^<$_&aU+LpC@Ol0_SJvA5 zh0E{2bx*BrW@c%=U#<@t$P&`6s;D76vx(NXrB;jCZsroc1|KHmXHj{=^_H76(QF0K zitC3Zq{W&!k&NjyAj!Ne0%B_pmgB*7yG26RXP8eHONnLcmc-w%n_GZnt!9pX%1- z)&cMBJdDlEo#ei~q?ZZC73iEh{?& T((rof&n5-+25nWmg{>~zuw)BwTN#u8@runZ8yMQwBXV))VaNy`+%{? zQw;NMRo%(;BXf%*)w;#q wTrf zK>&-nw%zI2dYncQyP? ux;3-o+GU3zw=WoF zgE*u1dZ|)3uvafOwWq2LT_xx}qR(Vk+-(L&rG6{d_nR`;j0$w6Fe!J7&KZ=mBFE@Y zt)w*p^fa%ASDihbo8?)>Km?9o;m!M@)9?iwtDK|&1+%csD4Eur7MhzDSjLJjdA*#x zLT||R-Ce5l#e=9%X9A(}l#^SS?IIx9-%^pK6t+tG$S?zjMUc F)CJIaCC3RU*+ zOHy=<_^F;R6qd2% ;OGI VZVtIZ8Fi=z3!}SN<`;h6cx?@>9g_!oL$$hrDXIu;;=JWivHLX$j?a1iV z?zN!3-+zOcH>OPze|X1TSs!5~Is;dJJZl^`)l+qmc+od63axx^NA2;_?~sY*V38~O zQ55k-*cyB14Lx=6@uOhj)NOp|!N@PIXOq9x$hIZt?KQ0Db_yKZO)DhPKJS9DHrrli z#LR}Gjv9jHgKB1Quh(O+>>5O0LI!>8Nn<;)M1OHU_2_){7sx4h5Rq;II8G}7#d`&u zoi~r}44$+*DRf=@q+C2`V%x{Ybg bpVz9p*ZwmYh2tk zB=+t}zhMLpwEs@a20`(vowXQoNAwHaY&2|)uNA0Yrw}GYe;YgE3u5pDO7y;6g8ZjA zf@y2wMB+#w_YEa_{&E#>&O)e2VMg}tMQ8uuZz7<~=qxAA--H@#L_mz!`v=_UvqLaz ze0E0h5+=d2-VOJeY`E=aFE;WIC*h)({QIfMF~+@4+w{PkABKUS_d=q{cAUzi&BfgJ zk65}n&o|10voBtBI(KeB4?=TVhA}(a{8Au T+8RWRT1e36$@5^>vkle=rF7X$WTIfy?v+c_guGK=x7!$ewAs`H$_NZ*a z*q4!(1ovE|?A-dtJJy_C41%#*?kh5n52@k%wr=hmvUh(Arw2trS7LBFyerLV3Aj!d zR($2qFxZ@it!J*!OIYn^0L^j2TG(}8e0GM4F;LBM8 GduO?tTNh|GZG|`|tN-?(_V*QwBYd!C%HT@A`ZT-C%P2nPhqO z8?FrV^BS(~?fG!mwbiQLJ`6XiBh8SGQGzImxY)S;*CUOw_EW8%4;`a?TR|}$_)UD! z-C=w`hwT6JaYGIdzyd%0Xa*t09!kkF50G8m8^Zm^f2dY@9UG16C(#z5lA7FqdgORt z$I6YJnwB-5hmZ>G@1V{GObiT;w!@#+?-~e>XRy_W!a!aVExEp0UyWkSFh|3*>DOkC zpV*`xSGOvdkopjzXg StMWqV;sJ^rX6u4nk@q_C3#o^Fxm5Ai&PE|O*%4dB1XR>E(P@T2X znEci6wHP<*+m+&-olFL+y-ySN_?Uhgkg$Ax{4}hL@aDJM!W2vVoF{JEy^dYL!F6_K zr#i-;o^|TK{pYg&c2{`@*df>1dw_}3CJs7 J~_Z zKh{a<{F^;(J{&B*2M7GB^`t90ohX(6d?@+Ckc?OUuSPVs 2xXm)kT2l*` iiS-NmA^8cJVoj9fH3ikI1)Si+NN|T-L ?%Zz!)FwY4y9ro+>%oanQNjjCDGxU{pK62PwcGK=h z11@K rP<3R31q0`{&w3U3o~430TBWV45^MUiX>w*L|L<14b}`lXSYdx RHCZCAIui5yoxpdL_tzEf+}!0 z1>`9+5zEf72SMKcXLiovi+aoHbjRM!3 7ek9-q!Xq zwvOqqcsp%om-+}M?wbB?y~x>&o%`Oex_JBIDUpEx4fy#=bHJ^Ohf*d4ZZ&vpj5g-i zS}v}$K-(Sm&WBx>KFL>BjQS^&tWqtgI7pdOl{f1-*?lmJLJ$rfqtkb&I^El|j9vP5 zZc=~&7}BbObp<`@^f%P4^IfPM4AFS`>U~hyfokvo3SRUB-4AcHTYf-b!E#Nm+J59e zvdP1%{4^~fE=;xcdzaCn4D`TOfivPP^o^YJz5I n$i${GC37MMtZSVZQu#<*CLAJ9Fv-6mT40+>)7-vLKBZjbhrwh0Sx0!cfy%$rIR z0C?Tg3q?(j4-ts(g*7QNkGo9^(a-nOmvrUdnbLmCdYjC6%FznSd%4-}m5KZ@p41Yc z4tDF4-(~Zvyh^ Co)`iSe&+JkLA>LsF!8IU+YNN{@gvDw3M;Ae7Poq#3{|dEz#>?&)fh{ |9 z#d6MR4_-H?dO%7mSb48T*Lj_Keb}f6<&Aj=tc#@tiYsb+7aNxcy*z+ALs7HcXExs8 zaNIzFl_bN=h|#*5S3cZiaMiktq#WIj!1)03=fu1M_fe@~6UpzrX*;*~G9qH`u`qGm z$v$W3wnG@?%v#sM0n !cG}H>EK%%!zF;1>Vm*)arKBd>8d#fmz`$CIJ&sb-- zi=bcx7{frg+)o<0t1>%xo9}vQ+n=JI3y-rMDBG8-b_;24fA=iRk0PRl&a!`xo6G+^ zZX%B1$(%l{JME&Ut62__Ya@D@1^tHf|6G?wR_%1{GzH!THo#kzVmy+1ut}eyXNANn zB|ik$okMhJ;yJrH_0TWA`x|>>cm6%c>yUSWcC?UNl18Nzk&XWPx1}?g4NQRA4~|7& zN4N22+holZK-A5fk7EtlmphXWlYc8a%0peEMX0rXcJLI>7irP62;4 NVX Z5b-jpQ(h+`oUP_-+tElM1g24_hfnL8Z z9$bbSz%*=7>-H-Z2!8CwNN|G(3;i ubLmiF}+e{QKazY^;jTa8}*>mh >*WbB?r9Bw-m)$5m@e&xL+#QGXqL z4$^-WE*QB+zH)^FE#E^LofR7^P$+%Y_m8uTDm*Ssva6ON`339?@87d( YL9?sRo zCtyT=jAcLgd**O|cM~@&!S+8K%L8; $+Roz1aBcB*gtWYVnw;pa!AXsAr OuBhTqrm;MpTY#kU}EoA_`#m9n16WQE%KzHf~X_z+zbZn$S&!S|qDU?ZxA+cME z3@DSO>Cw3-m~-G@ZTeInJ3uYy*vd8nn1-mYv<>J3e%`LXri>5q^x5w3w|oNiN-aX1 zadca8lE{;-$uB3jy>F 5g#%q*~E{F>AL6&b7)(wF!<^HY5q1WS}=(Dum zCT53N03JiJj<3%`2z&jlqOO%f-gIX?>T~=qT$#J}2&tVWVA}Xd$TQRr!-KScj)A|1 zX!(`mul+rVz5EYmO5r*Bbs6!AqcdJWs^x6XP~hOVmsLS=Ddjo?U&@+p+=p#3|<~2dxz5u`=Lzov8X(+ zJ$1dvtS@mZ0s+Xg6fobgP(OneF(WDuyL)&(pP_8PmbR3cI#X@mmLf72N{~RJ0}`wp z`jiA?F!AlibsVfw2ukS>n`9R01*0lcT}ai+RtkjG-Fp1^-t-g$K7IB{h{xr4K=+4Y zdb_f)Nk= #4-w^07@i`LL?-eK@D?LsWk?;@47kV|@Bym#$CWE u{djK0jXxkV zAD*qEwULlAiOvf~^;2Gn;nesy#L7 VU$0WL zK!%DS&TbgsQ?Osbk-}rgf^WDoy(5Kil?es`t~(zT-N0YVygJV(09%yV@@w2$pEE>= zjIE`NY&o>XfG1+Q4s8V&6qcit-!*t%+m3K#io@3rtC2S&ku+d?EoSgpDsCTW7vgyK zW8@2a>N5ZCjTI@8K70xhY)zvq_gWU4d5z=_9i(QF*L`6Ck9dk{-|n}Zl7U}v3k_*F zIx~<&o(}j!1xBVwW)an1sRMmyWsD3mjd5Y&PF`7}Z37F)IbV3S^Fyam?*p9A?`5@g zoI9$vx2InTuIJx7;CL;)z*)6b@%7*U=05obY_v)bALh#~#StHSi < `Eu6vccDKT6Mw zy|3LS&iGsdLu+sL?JL?*R^N*@#ZIkcoS zt#*i#RlYYDy44xo<1L}5%W#A(+t!O8)K>hpI=&B;Hd2^QeXG){`<4mO?6nw&fQ4uS zcZ1(Brrs0s$M>pGJ{y#LdpX^qcN^?nrr(V}