From f7583018da9c8e7089149fd3696048b95c05ee98 Mon Sep 17 00:00:00 2001 From: Farhad Ramezanghorbani Date: Fri, 5 Jun 2026 15:36:54 -0700 Subject: [PATCH] skill's token efficiency benchmark Signed-off-by: Farhad Ramezanghorbani --- skills/hyenand-retrofit/evals/README.md | 77 ++++- .../evals/bench_results.jsonl | 15 + .../hyenand-retrofit/evals/bench_tokens.png | Bin 0 -> 95883 bytes skills/hyenand-retrofit/evals/bench_tokens.py | 321 ++++++++++++++++++ skills/hyenand-retrofit/evals/plot_tokens.py | 156 +++++++++ 5 files changed, 559 insertions(+), 10 deletions(-) create mode 100644 skills/hyenand-retrofit/evals/bench_results.jsonl create mode 100644 skills/hyenand-retrofit/evals/bench_tokens.png create mode 100644 skills/hyenand-retrofit/evals/bench_tokens.py create mode 100644 skills/hyenand-retrofit/evals/plot_tokens.py diff --git a/skills/hyenand-retrofit/evals/README.md b/skills/hyenand-retrofit/evals/README.md index 65022ac1..fede3207 100644 --- a/skills/hyenand-retrofit/evals/README.md +++ b/skills/hyenand-retrofit/evals/README.md @@ -1,16 +1,17 @@ # Skill evals — future CI integration -This directory holds eval cases for the `hyenand-retrofit` skill. As of writing -they function as a **spec** for the skill's intended behavior, not a runnable -test suite — there is no harness in this repo that executes them. This README -is the design for wiring that up later. +This directory holds eval cases for the `hyenand-retrofit` skill. The **correctness** side (the grep assertions in `evals.json`) is still a **spec** — there is no harness that checks pass/fail yet, and the bulk of this README is the design for wiring that up later. The **token-efficiency** side, however, is built and measured: `bench_tokens.py` runs every eval through a real agent and records how much work each retrofit took in tokens, turns, and wall-clock. See [Token-efficiency benchmark](#token-efficiency-benchmark) for the latest numbers. ## What's here -| File | Purpose | -| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `evals.json` | Five eval cases (native pure swap, native hybrid, foreign 2D ViT, foreign 3D feature-map U-Net, foreign 1D causal LM). Each case has a prompt, the input files the agent should see, an `expected_output` description, and a list of grep-based assertions against the file the agent writes. | -| `inputs/*.py` | Standalone test fixtures the agent retrofits. Each runs end-to-end (`python ` produces a forward-pass shape) so the harness can sanity-check the inputs themselves before evaluating the agent's output. | +| File | Purpose | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `evals.json` | Five eval cases (native pure swap, native hybrid, foreign 2D ViT, foreign 3D feature-map U-Net, foreign 1D causal LM). Each case has a prompt, the input files the agent should see, an `expected_output` description, and a list of grep-based assertions against the file the agent writes. | +| `inputs/*.py` | Standalone test fixtures the agent retrofits. Each runs end-to-end (`python ` produces a forward-pass shape) so the harness can sanity-check the inputs themselves before evaluating the agent's output. | +| `bench_tokens.py` | Token/turn/latency benchmark. Runs each eval through a fresh `claude -p` agent (skill text injected inline, `acceptEdits` so it actually writes the retrofit), parses the JSON usage envelope, and appends one row per run to `bench_results.jsonl`. Restores the working tree after each run. | +| `plot_tokens.py` | Renders `bench_tokens.png` (stacked token breakdown + agent turns per eval) from `bench_results.jsonl`. | +| `bench_results.jsonl` | Raw per-run measurements — one JSON line per run (tokens, turns, duration, model). | +| `bench_tokens.png` | The rendered token-efficiency figure embedded below. | The evals together cover the four-axis grid from `SKILL.md`: @@ -20,8 +21,64 @@ The evals together cover the four-axis grid from `SKILL.md`: | `foreign-3d-feature-map` | 3 | False | feature_map | 0 | | `foreign-1d-causal-lm` | 1 | True | tokens | 0 | -`native-pure-swap` and `native-hybrid` cover the native path where the host -already uses nvSubquadratic builders. +`native-pure-swap` and `native-hybrid` cover the native path where the host already uses nvSubquadratic builders. + +### What each eval retrofits + +| eval | host model | what gets swapped | path & key challenge | +| ------------------------ | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `native-pure-swap` | nvSubquadratic ViT-5 attention config | `build_attention_net` → `build_hyena_net` (pure HyenaND) | native — edit a config, no adapter needed | +| `native-hybrid` | nvSubquadratic ViT-5 attention config | → `build_hybrid_net` with an `HHHA` layer pattern (3 Hyena + 1 attention, ×3) | native — edit a config | +| `foreign-timm-vit` | standalone tiny ViT using `nn.MultiheadAttention`, 64×64 images, 65 tokens | the block's `.attn` → HyenaND (`data_dim=2`) | foreign — adapter reshapes `[B,65,C]`→`[B,8,8,C]`, peels the CLS token, returns `(out, None)` | +| `foreign-3d-feature-map` | standalone 3D U-Net with a `SpatialAttention3D` bottleneck (`F.scaled_dot_product_attention`) | the bottleneck → HyenaND (`data_dim=3`) | foreign — channel-first `[B,C,D,H,W]` ↔ channel-last, no CLS to peel | +| `foreign-1d-causal-lm` | standalone causal char-LM using causal `nn.MultiheadAttention`, sequence length 256 | the block's `.attn` → causal HyenaND (`data_dim=1`) | foreign — `is_causal`, RoPE, `exp_decay` mask, `omega_0=100`, adapter swallows `attn_mask` | + +## Token-efficiency benchmark + +`bench_tokens.py` measures what it takes to invoke this skill: for each eval it spawns a fresh `claude -p` agent with `SKILL.md` injected inline, lets it carry out the retrofit (`--permission-mode acceptEdits`, so it really writes the sibling file), parses the JSON usage envelope Claude returns, and appends a row to `bench_results.jsonl`. `plot_tokens.py` renders the figure below. The working tree is restored after every run, so the benchmark leaves no diff behind. + +**`claude-opus-4-8`, 3 runs/eval, 15 runs** (each cell is the per-run mean): + +| eval | turns | output tok | billed tok | wall (s) | +| ------------------------ | ----: | ---------: | ---------: | -------: | +| `native-pure-swap` | 5.7 | 2,144 | 164k | 31 | +| `native-hybrid` | 9.0 | 2,810 | 287k | 53 | +| `foreign-timm-vit` | 5.0 | 6,751 | 168k | 74 | +| `foreign-3d-feature-map` | 5.3 | 5,792 | 183k | 66 | +| `foreign-1d-causal-lm` | 13.7 | 11,705 | 535k | 355 | + +![Token efficiency per retrofit eval](bench_tokens.png) + +### Reading the table + +**Turns** is the number of model↔tool round-trips the agent took to finish one retrofit — each turn is one model response, usually a `Read`/`Write`/edit cycle. It's the cleanest single proxy for how much work a retrofit was: every extra turn re-reads the cached context, which is what drives **billed tok** up. **Output tok** is what the agent actually generated (the retrofit code plus its reasoning); it's only ~2–3 % of billed tokens, because each cold `claude -p` process re-reads the large system-prompt cache on every turn. Dollar figures are deliberately omitted — see the caveats. + +### Why the evals differ — and why `foreign-1d-causal-lm` is the heaviest + +Turn counts aren't uniform because the evals demand different amounts of work: + +- **Native swaps** (`native-pure-swap`, `native-hybrid`) only edit a config — read one or two files, write a short builder shim. Fewest turns, least output. +- **Foreign retrofits** must read the host model, design and write an adapter module, then reconcile it with the library's API — roughly 3× the output of a native swap. +- **`foreign-1d-causal-lm` is the outlier** (13.7 turns, ~12k output tokens — the most of any eval, ~1.7× the next-highest and ~2.7× the native swaps). It has the most constraints to satisfy at once: `is_causal=True` on `CKConvND` (and *not* `fft_padding='causal'`, which the library rejects), RoPE, an `exp_decay` mask, `omega_0=100`, plus an adapter that swallows `attn_mask`/`need_weights`. The agent frequently trips the `fft_padding='causal'` footgun, hits the validation error, and retries — so it iterates the most and generates the most code. + +A separate 3× rerun of this eval confirmed the instability rather than smoothing it out: **5, 10, and 25 turns** — one run finished cleanly in 5, another ballooned to 25 turns and ~1.56M billed tokens. The skill *can* land this retrofit quickly; it just doesn't reliably steer the agent there. That makes the causal path the highest-value target for tightening `SKILL.md` (e.g. calling out the `fft_padding='causal'` rejection up front). + +### Reproduce + +```bash +python skills/hyenand-retrofit/evals/bench_tokens.py --runs 3 # default model: claude-opus-4-8 +python skills/hyenand-retrofit/evals/plot_tokens.py +``` + +Pin a different model to track drift across releases with `--model claude-sonnet-4-6`. Use `--eval-id 5` to focus one case, or `--dry-run` to preview prompts without calling the API. Re-running appends to `bench_results.jsonl`; delete it first for a clean dataset. + +### Caveats (so the numbers aren't over-read) + +- **No dollar figures.** The CLI's `total_cost_usd` proved non-monotonic with token usage on multi-turn runs (a 629k-token run reported a higher cost than a 1.56M-token one) — cache-write churn across turns isn't captured cleanly — so we report turns and tokens, which are internally consistent. +- **Overhead dominates the billed total.** Each `claude -p` is a cold process that re-reads the full system-prompt cache every turn, so billed tokens are mostly fixed overhead, *not* skill-specific work. Compare **turns** and **output tok** across runs/models/skill revisions, not the billed total. +- **Skill injected inline.** `SKILL.md` (~16 KB) is prepended to each prompt to simulate the skill being loaded, because it lives under `skills/` and isn't auto-discovered by the CLI. +- **`acceptEdits` mode.** File writes auto-accept (the deliverable); Bash is auto-denied, so the agent writes the `__main__` smoke-test block but never runs it. Runtime verification is out of scope — this measures code-generation work only. +- **Cost, not correctness.** This harness does not check the grep assertions in `evals.json` (still a spec — below). ## Why CI for these diff --git a/skills/hyenand-retrofit/evals/bench_results.jsonl b/skills/hyenand-retrofit/evals/bench_results.jsonl new file mode 100644 index 00000000..c298cb5f --- /dev/null +++ b/skills/hyenand-retrofit/evals/bench_results.jsonl @@ -0,0 +1,15 @@ +{"eval_id": 1, "eval_name": "native-pure-swap", "run": 1, "model": "claude-opus-4-8", "wall_sec": 29.1, "ts": 1780694126, "input_tokens": 1652, "output_tokens": 2096, "cache_creation_tokens": 21206, "cache_read_tokens": 114296, "billed_input_tokens": 137154, "billed_total_tokens": 139250, "cost_usd": 0.256294, "duration_ms": 28392, "num_turns": 5, "permission_denials": 0, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 1, "eval_name": "native-pure-swap", "run": 2, "model": "claude-opus-4-8", "wall_sec": 32.9, "ts": 1780694159, "input_tokens": 1654, "output_tokens": 2127, "cache_creation_tokens": 21323, "cache_read_tokens": 151091, "billed_input_tokens": 174068, "billed_total_tokens": 176195, "cost_usd": 0.276183, "duration_ms": 32061, "num_turns": 6, "permission_denials": 1, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 1, "eval_name": "native-pure-swap", "run": 3, "model": "claude-opus-4-8", "wall_sec": 31.4, "ts": 1780694190, "input_tokens": 1654, "output_tokens": 2209, "cache_creation_tokens": 1922, "cache_read_tokens": 170598, "billed_input_tokens": 174174, "billed_total_tokens": 176383, "cost_usd": 0.166725, "duration_ms": 30632, "num_turns": 6, "permission_denials": 1, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 2, "eval_name": "native-hybrid", "run": 1, "model": "claude-opus-4-8", "wall_sec": 46.4, "ts": 1780694237, "input_tokens": 1658, "output_tokens": 2725, "cache_creation_tokens": 21286, "cache_read_tokens": 220566, "billed_input_tokens": 243510, "billed_total_tokens": 246235, "cost_usd": 0.338142, "duration_ms": 45646, "num_turns": 8, "permission_denials": 4, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 2, "eval_name": "native-hybrid", "run": 2, "model": "claude-opus-4-8", "wall_sec": 72.0, "ts": 1780694309, "input_tokens": 1784, "output_tokens": 3052, "cache_creation_tokens": 4197, "cache_read_tokens": 316055, "billed_input_tokens": 322036, "billed_total_tokens": 325088, "cost_usd": 0.32163, "duration_ms": 71277, "num_turns": 10, "permission_denials": 12, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 2, "eval_name": "native-hybrid", "run": 3, "model": "claude-opus-4-8", "wall_sec": 39.5, "ts": 1780694348, "input_tokens": 138, "output_tokens": 2654, "cache_creation_tokens": 11716, "cache_read_tokens": 276258, "billed_input_tokens": 288112, "billed_total_tokens": 290766, "cost_usd": 0.284368, "duration_ms": 38700, "num_turns": 9, "permission_denials": 3, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 3, "eval_name": "foreign-timm-vit", "run": 1, "model": "claude-opus-4-8", "wall_sec": 73.3, "ts": 1780694422, "input_tokens": 1654, "output_tokens": 6732, "cache_creation_tokens": 55399, "cache_read_tokens": 107587, "billed_input_tokens": 164640, "billed_total_tokens": 171372, "cost_usd": 0.582579, "duration_ms": 72511, "num_turns": 5, "permission_denials": 2, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 3, "eval_name": "foreign-timm-vit", "run": 2, "model": "claude-opus-4-8", "wall_sec": 82.7, "ts": 1780694504, "input_tokens": 1656, "output_tokens": 7262, "cache_creation_tokens": 6552, "cache_read_tokens": 184163, "billed_input_tokens": 192371, "billed_total_tokens": 199633, "cost_usd": 0.328834, "duration_ms": 81891, "num_turns": 6, "permission_denials": 3, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 3, "eval_name": "foreign-timm-vit", "run": 3, "model": "claude-opus-4-8", "wall_sec": 65.5, "ts": 1780694570, "input_tokens": 8, "output_tokens": 6260, "cache_creation_tokens": 5355, "cache_read_tokens": 122555, "billed_input_tokens": 127918, "billed_total_tokens": 134178, "cost_usd": 0.257258, "duration_ms": 64819, "num_turns": 4, "permission_denials": 1, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 4, "eval_name": "foreign-3d-feature-map", "run": 1, "model": "claude-opus-4-8", "wall_sec": 76.4, "ts": 1780694646, "input_tokens": 1656, "output_tokens": 6567, "cache_creation_tokens": 22798, "cache_read_tokens": 184442, "billed_input_tokens": 208896, "billed_total_tokens": 215463, "cost_usd": 0.413177, "duration_ms": 75734, "num_turns": 6, "permission_denials": 2, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 4, "eval_name": "foreign-3d-feature-map", "run": 2, "model": "claude-opus-4-8", "wall_sec": 59.0, "ts": 1780694706, "input_tokens": 1654, "output_tokens": 5431, "cache_creation_tokens": 4590, "cache_read_tokens": 154656, "billed_input_tokens": 160900, "billed_total_tokens": 166331, "cost_usd": 0.256059, "duration_ms": 58326, "num_turns": 5, "permission_denials": 2, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 4, "eval_name": "foreign-3d-feature-map", "run": 3, "model": "claude-opus-4-8", "wall_sec": 61.5, "ts": 1780694767, "input_tokens": 10, "output_tokens": 5378, "cache_creation_tokens": 4864, "cache_read_tokens": 156728, "billed_input_tokens": 161602, "billed_total_tokens": 166980, "cost_usd": 0.249263, "duration_ms": 60723, "num_turns": 5, "permission_denials": 2, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 5, "eval_name": "foreign-1d-causal-lm", "run": 1, "model": "claude-opus-4-8", "wall_sec": 294.8, "ts": 1780695062, "input_tokens": 1914, "output_tokens": 11772, "cache_creation_tokens": 39646, "cache_read_tokens": 477955, "billed_input_tokens": 519515, "billed_total_tokens": 531287, "cost_usd": 1.244425, "duration_ms": 294059, "num_turns": 15, "permission_denials": 26, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 5, "eval_name": "foreign-1d-causal-lm", "run": 2, "model": "claude-opus-4-8", "wall_sec": 558.3, "ts": 1780695620, "input_tokens": 1918, "output_tokens": 12852, "cache_creation_tokens": 29890, "cache_read_tokens": 584403, "billed_input_tokens": 616211, "billed_total_tokens": 629063, "cost_usd": 5.170056, "duration_ms": 557564, "num_turns": 15, "permission_denials": 29, "primary_model": "claude-opus-4-8", "is_error": false} +{"eval_id": 5, "eval_name": "foreign-1d-causal-lm", "run": 3, "model": "claude-opus-4-8", "wall_sec": 211.9, "ts": 1780695832, "input_tokens": 1788, "output_tokens": 10492, "cache_creation_tokens": 20896, "cache_read_tokens": 410433, "billed_input_tokens": 433117, "billed_total_tokens": 443609, "cost_usd": 0.838811, "duration_ms": 211110, "num_turns": 11, "permission_denials": 10, "primary_model": "claude-opus-4-8", "is_error": false} diff --git a/skills/hyenand-retrofit/evals/bench_tokens.png b/skills/hyenand-retrofit/evals/bench_tokens.png new file mode 100644 index 0000000000000000000000000000000000000000..67cd98ed479033f9f7a3b45adc6f0c3e7fe0c933 GIT binary patch literal 95883 zcmeFZcR1JY|2O=iXlbBQNu(qz*^y8*C@O`>NJjP^*-Ar0DWhzaQQ12(+GLNAgvwr# zy#hd4c?oW?7)*HHwC! z6crAhy&OK!;_R-{y(l}}7~yhh?E`^Zj7(wc6pkJ8(-L~PjxWtDFf{43%r(_av*7I8 zAD(A_*`xK^OpWL8V8P_d^tK||x!92lVfK5*U#o_S9Wp!>qmI`66JrrUcqo3edxbm zU&6s4`mdKWJ~+6^|_U)-zS!(y@SF!B5fZsj!;_UL( zt1B8uR=o_*(Xq1=Rto07b$bIJ=Z+oEQWFf;v9q&xPJK>!w@@J5AvO1M!-TkN@_U$x9G0ZwojjF@9x&%7xYWh{caAMh?e+uKJ=gTo#?xFT-(?MIZ?!oiQXH`Ju+%RhenIQr}h)uzh$ z6*9L<5}tSMx5h*G-nsL>r{nUkwS_%&U>iK)rIG7Jm2s z{hyA{%vkcL=h7}>AyTum_k33>@`*bcbwKUxdirg_^Z z2Ah|!S@Y?|nfM<)J-*e|r_P-__hb0y`*Zo1g*<0^x%u@9w+d)wmN=Bv$R*NQc$3ig0YpA)%5fFuuCQW+aDir6Q^IjWvo&RtgHHyh~nLa70yAb+|vJ=-s<_ zw2O12_f;s7QjG$_9J5eu_!e}FJj`cULRZCF+_~Wh5s9JDW(#@amZ}J`7^<$c~?%5H)tJkm7S$%(X|UCFpqW!5>3 zb%<7dk?wKT0{@E0HmQ!jQkkjq+G)G6Fw^hfzxRrW_#`CoJ$?Grrl)#)L_W(NZEvO6 ztM~7(6&4oWYxzwykWXWcS=N?4d-n8v%i=>I#)`CIwf_v}v^_n1XX9?o^qu_t{1?p4 z@8Ee(M9Hw3nwrvO^Z%F*cxm5NPEM!3zCH~L3yZ?hqwU{w?KQ2Qg&S_GGal`#F!`Fg z9bXpNATzuE;~f^VX-{!HPbJi+=HwhbcW#q<;<+bkk;dg4EBpeHYs@{`bw&&3%G+X! z9Q!xAj`z`F+a8C8UVP(CqvVof)$$IDe>%^>)F{`nzu_Z}L6(etd{Z*AB<0Pv-)VPQ z`CM-xOR-7qm-dgnE}P4Gn=&pvmbBmXQX}Oap5{=J`umm^HuBnQE12!n=&6C`oV9q$ z>&O-x1+-#fiY(jLOixX5?Af!1LMX>)73jI&o|u~+o%-Rk7Uyk=y}kW<9@V9OTg2Yw zIrfj_e_xy*@+#f8B&68#n4;p_M9qwK>(?)Jb8~xMZ#FeMYw+dy>C1CdX)2N-#VWZ@ zgIn?(dTBK@H1My10_Qho7*~|qw~T154N{^*5~ixED$1Kr*`K(-?Z6iA3Gs&SqMuDI zVv+l!^@==qpNV6@In}qezQ1wZ`%je3x%o#%-uoQD{l2Y@edETB!+-v~McNH&dw_W76c^u! zoP}L|u9d~>IX~XW|H!-~*M781d2FERjOLA~DE3_^9!F2+@Mq*l$_th~*m1Nv%Uol< zpzc;g-r?Kp56a0=NBp*2f9*WfwXbMJcu&?4vV=IR~5vzFrv~wn>^nVqH_E_;0@xu=|507Mpf3IH3V)yclajxmwE>ZRK>Xz~4y}7+hOgbE+E*TnL z82pw+iXN}p%NP;MKfgXc*GSohXx6u~y2r$&6z#RR@XBR0PQCT5&oVxmcZnxLMOUC9 zC~zHDt=*%W?~8iCv2*9r$jHdO5)wB90s`I+21{sm*-HuuG0NXubNGd7>;)^Uk5g~V`J?1rze zuE-$;1#3ErR_+EWcU)YYYLTZ060aZf_HxSB-acTz^Y7i$`0S5OO`3P_-tE8{b1k#@ zn)-zD*Ylh{%;)jz!>y;PFFur%9HU*bgiBahm6n!vsrTcMkk81fnIloMUb>WTPEJmy zb(=0?FBUnQY1_6vXeVgpN*@UdDk>^!jSha#Jwy2>BqUtBcJ0_}r@({HO zKVxI$3z>d@mG(F+Y!zkNR#=ekVck|JAS5JI`~36{8l;0grNYbBZcF@f(tfLP>rMQF zl51Dqrw<=GUd`9m)p3c6o~3*X3JOFmzny*h>>2qpy1$R#ziaaq85ijByCIq`nws)7 zG&GDfTNm}V9Bt0FEYq0jzldY3`a+e9h9ihqt@c|hpGNZ85&ZIToMAfeshJriEa*^&~A?IRt3zK_7bTQSw%26qEoQ zDKi0sv7Q=QIiw!W}(o3n%b{nrVhMo_|@b5qim0r?F(cI`UyEz@)d^`W#> z$(+^fo~cLkWi)r3oavU$;xy=Gwo5r`7I_w&JAWRlHZt-Mk$9{uSRmGYdW2RED;?cY zksO|{Eg_m;P!Qx{ju!as+qX=cH}h~E4?f#4-tjp=YIJ^nvhCNv06+BsF^R^Ei<9%v zOZ6n)BS(&CHGagducDfA?c-ZL{=8krzMKjXHd5N?#y6=FA;m?-T>N<3HU84V0aW>Q z=H}+6t@*iR#dB{s4Ylg1M9BzLR#vLMJj-L+oSlTys!aK&rKO>dR*Tn`uZ+Oj?rv_Y zs8B{Vj5+=6$VFr0T}Uct<025|=7n?N@-v<(qK&`ub&I;Hq6BfEO8;!!uz^cCOnif$ zo?gUAdfpn=k+8@XN&l8~1%^fCDsxtDi4psP!N!!RO`A6>qJi5fC8dRE9wz51FZpSdxPW57s8@>^H5AxrGv-PL-g^7|pLlOkyt_dQK(fZQxPe zS!Hy~*L|ipo>mTtt^?;o$@R#Q8+PS6rgfj9(?<{4m%F&SmZAr+JD_Lv%|}ybnW(OX zLBZq5W*Ki^{aN?odu+6F^lP?04~l&Fkn`uypR{s`Nl7FwwQ{TkxRe6dQNMov+DZJ@Cjd=lrw z(Y#CJ=k<^6=NA$>JvTQOXzqSzqd*Lzk!kBz{)veR)wmOz3miAexWA(O(O!1Bu&!gQ z>Awj)_%!EQT!31p$!STu4&R3hQ-2IzoPKtL@_+SeUy_Sx#KcM2`Lpr)B9|(Cm13Ek zot+hxmDOq+lg`I~=Qv>V!@EJ+ydja1nVC5)Bcm?wPi$^(bnjN(JO{-PCzL53-F$rD zwQEb0M)v3x@}JMKs_(tl`pQ-wf%!6Lhec1idb0M5?9hpW?pTRGy6P{m5Ff zMI%Lb1FF4{m{`5$BlJyt5^UKPO;5!H;=>q2D`R(k4Sf9gdB9P75iy*uhXDaWW6azt zyCsCM97$p)RV3!^@>V?5XwI=_p_taKi_TbsC6sDDtQYT!lXua=f*+|zsyMNvnZ<E7K3%K+`n1oW7_2as-C^OpD*dd!-&cxz@`gxKvk-X;{WLB8)n-RkCnY+Lp2&(~M6 z1X}JlDqXL5@?>Ku(u3{vP|>0tKX*~%>MSh*d|8d!GpedFMrFaJezE1-4!Fi>uLVqr zaZFmrnCsB{a1Lj@bg>&Jj*3C8lWOin0AIAU6fn!u;@)@Bcc^eyg(_Lb?jG&z+SRti z%gZa*b3RXa5G@5clSl=>hK2-vmaT30#{T}sYG#UQ%a)gFaZkGMb?vgiLCUHO007}R zDDBZWhEq$o!Q|U(=afyXtam~}Lijb)6)w#z%+Gd?be5GaX5{6XmRRRKxw1>%t8TSv zd&kbA#`BagI^QHy1Rv867n`ZR`UEBN8$i!A9BvZ>H6h(&y>)ij0qv9&-x72aACNVa zf_P(>8jP@-xT2xEcKtffY!-?w6C>kxoO`A-XU_C~&&`nbockJ`o-tZ;l$~cSyJ6vj zNJ;7;t7O))!z1h_rN`Od_D-+zgb-7X_aRd0{7@> ztznZ2jPEq7G*V{O9F5jAo?b258Oyejojqk~t?(r4VTFeeA3EII><6^AidwODZB@%{ zX2u$GzyCN|@_R2;ZjCSvRe5_yqMV!o0QFy8U2%0h)ec+q2Hel4=;}~C9;N3MV$g}w z$^keh#~2kh<>8S z^CEol}81JhuQ;Ud_@!(yvX3a&k zaidG;8}+<&q9x{L#(Hr5q2Nl~T%`QWy$WHY(qkxmhHZr&Qg!LIPY(X(## zYSGOzVOGajxw)qcTIuQO`vh`q+dt9DeY(e%5VLuUNqT1HdN;RO?UXYrq6e$Xn}v$5 z?0V2Gk%+*4VgIbPs_Nv%J=*8isWtxm_3LRCKZ4%JbJ5;x?d=ZP>cB@b-rHyM6>c&8 z>gb3Wck=@9J)Kbh>&K61`wAA9Z5FlpG~tpx3DcIn-?9=arLit7lrVs=cB3+LHG0Ni z^_hMq6RlS^PfmpIJH0SJspm4*^WZyjX+w%$%F?EY@bIw(8AC4nXhpr$Q#%*0#N}tc z-*qxFd~nECUDSHlCC3UNd5KlU1of8XFD}eVnHrS_(oov3os{`n>gt$L%U+Re@k)@| z$<1x>_9`8Sh9f{sfn#WQF92+V<|?(zzXp6pOHKT4Nf4>{@@4%{!K7|-|1yg6DuCjT zj4By3;H<1KNXaHPD-R# zZcWu+LUACg4vh_DU$O$4rPI~bmFo4H`?HLS20x(XV`lC!@RbqW!#=kO{$$+(v+DF! zhtS;-I0c5Q9Uu1D&OM1GHa`B@(fiv#VaZ>(z=00N54a+~<6EJm=xh=4+g{;X%Qa45 z1mBF>Dxt}AjEg$pwh`^a*CH=jP%XoN=zVvK(rnw0P;y9RWA_a7O-*l^)xX>>Ah6nN zaXzPVEH!m+!KjgQK{a>L`0it&c@F&z0(vB>A3SPXp&TJrte^sPPnMz6d1r>CeHZ23 z@R)V_N$$1|(Oq|5yx>9i;ZO?-YsHW0uRO-a##(g)gM+7Ijxol>#r>*`*sqkgy}Od# zYmSETAUKSly}d6)PJ&z-YnV0K`kGrM{LL+9?sc0sJx-YG?d|=V?;_$o$DZT;v#8fa zzsK6uvw5H9=b>@+wkd>x4TBk!+6Dt~`-ZMXScCg1{L(EuMB-C8&IA*Vk- z{fwUQZ|;*V&aYg@d4IPR-N$dqDOBg$UqUC6|0Xyd2V%AFa;vsNzltykg84yGOpVo@ zT+J((Fmd5vNme&a zfslQRPyRE|B*Jw7i+lXhp6g1nwQiQ~69bz;Vq9U|afBoqITUPwlptI2Rll~32oqA3 zV7==rH(W36W;scT@z)^3w6ZO3dCX22<%S~~ zdzGuo(g~y6(P0P}__n1*$J%9vzCkz3EJ)p3#o%kIJ{W{LrBSeJ=aY?3jev^iiAa88 z?bdZfy{vxe{o5>p$J zom^Z$!C%-oIW>f~CTIxa#ri$fPo~-y7vggmD$)+1fdN$HYM$xYUpTH)<~@*dN$}Y= zx?c3#)WXm%zb7MZEhWF5Ik~tF^R@U(P4?C;I}@++(Yehdo?&JI{OT{%jOW_9c2`=~ zyAA)iqTZ76tFP}R^Kv>0*n_HOovS%fE}k5F2&m${C3>u zG=x=*KNuUt-bq>(^U_MVm8m zI`)c*2@FdaXMLCWjB`oI{0qo;U(=0NIsN{Ai*D7%3n)a-^@?P~t-e2JKFa{%0J+|F zVb0|)+y0H{`T1kMEh&2>SPUL?Rbu|t<)WP$&~wr*|GDTsS|Nd>8r%BjO4nB)r)xz; zUfG?!uTQI<>bCLhKkW~Q@aX(>fmMf5^A^=^G(@}-UO5&`SJ5^KmbC@VflOWIKkD}} zykSypPIuEU#NMjD$8;l;VUa;#eP|P+wp)gO_@GcQNc|XprCzi6KRqf zhEUMymxdPjiCt%@WOh8-#=FR&??HMDu^z;89!2Pq?HTx*)*ibwR1}qF-G&XIk-pl6cSrNIJs(3f9&U5 z%k!n72&AQy@2y)krL)j=GOb#+kkCU9Q2pB3I*?zJ2|UYQVc~Z;%S4Un>bJ~)_pnhS zOQh`Ne%W{f-jpIg=3OV=0D*XCnKxeSZ%CSg#3AH1VL{0Fi2cqDZuiW$rKV$mWP01%51AU|e zv3aoh;LN$Xxj``Pkd)lqn4;G>yL1dd%b^ycp%1#h4)Z2(>F+~CF70(1IM*qnl5(}{ zvqMF|b3vu!$IrAH?oP}J5w>@9JUsckC5Y7-u_N!`APTH`)n&Bn3E-sGH29|n{{G(J z&Glqh`whMR0C7^O$NT_GLw)5vHh33 zO<$R=H~iAn^S!8b)5gF#?X?V@5buzFp8!s+W3>2|xdNo$dq9GkLJv1lvoFWM8@7mb zuSd~u(yc0oWuv><+yh(o$8OduXMBmR9J& zvU>M-7x9EdwWu5eamOJhwgLa)_m>OkN?Ik~Kl>EQ@a}{0XfQRbw?Ux6@m>;p{Lv?b z2g0CDVnk6xzQe)YWMUDiYD}i)<>vG8Xk%Sv53Z2*VsZhMei>cU7744nAbw1h8@D#& ztMgaqtQqNZe6fr&(teE0*`2UeK85wh-poorR*55@A9AG`S8O4=!We0t*-%QNow|0n~)N znc2(AF(f)2?uzQRu}Afv(1?mBSU%ItDUXV=v$MO3qV>DAAYn2fX(n4k9Wa2@NJ?|D zvT(Pk=z7klllQyou0g#xU7NmTRsUf~AXMbC2V->Wp)T6|ctb;JdYPqin0{J<{^#tK z-~`FmlabOdL<9s8Sek?O6_-|z7brub@E{5o&YLE^XgaXuy==>7&I1S7h;9tbdl!0f zrdhobchA!m$9iVN&nqddM6>rG-l#|=Sl~Q8<>LByheZ1RNNBx*?Ndglp#g&6XA=G5 z%vLk!sqsR!GqwS0yY6b@nph462zm1@+G!!L1$U&QXXs^JNAICXQR~>)lB6GmYT^?> z=G{Tj>PS!l|AhKdj05XnmCg@Aq>R=6MqgtJJ9Pm`W}oZW^M{e);denO{pziYr^}P} zLz{=-qc`|;_iet*r~^GM3*$grkzRM)<6TqsAd`H8L9ppS5GFeNRL`^fnN~j{WIVJs zcesKKrw>}>l<$9yvVnYZkoy97i>DUM5VS2Gy*4ObLsT<8ulaG-S>ehS(cMTe=s@8gXdQO4gu{%%&R*%5MDw$aZ*~Phx%CRNO)^zMs@qbd( zD4#wg8PS+Z=e*_Y?E=T&qkr@;zeKrS+_2<`1~Mm2-XZwnwqB77*!ZS6McH#u#d z36nn`p^IH|+0)&4yh-}UqKpOvU-hIniqMaUeE__-@$1SN6kNGj)q=4UQSCg36|!@~ zK9&14fioY=ct`w{t_cyc!y&(0_${jj%D6nJ8>=73H+WF;Or1!&~}Dt8fO2>DbGE*`LWM~@zd>d+wFWGVX~@&0@4a2wv(#YpX8ufgt&K^kv6to*t(2CX^&#+34;pwB|+mP1h63c zfy0_fv!IzipvnAVmX)Yiq^nruwO9yzxQa^4%nXc<=D2n5UNAt3Vy<1MLaZuT4s}fs zEtM16cW&Kcq|(u;Yg?}+gm>1?*RICSk%>C5)te-+wS>zB75R{0+C&Yf&P{eLaFJ}J z?6CI*{ekt`*_P)`8xljH0`>(ys(1YA-{!#h0F5=@X#Mlk@B+t$=aI8g0YATS~>jrLve9`d5*`d6BJBFO7+PhI#}`i@w_Msw-^An zyF=|37d&V4s%+zk(zWosONC`b1oi{o%lX<62O7=1vc~n0{Pp{p&FIsyPd{8Vn z-P&}c^?QjpHky8xTM1J(Fg`eo0A9 z=vYYuH(^S_cU1M{7ArF{zL|uGnbs;$zPY)%qWC`mq~xfe>C4F9 zXxO-Ik9y)`${)*lDc5QSJ`MTlb|_*Lq5Ape(Yh-wc)?sn`63X(_A4R`348Mk6jyi| z%5~WpHaoNX=I#?smuTexvw#~FK&9|N@kew#)!w0(zh+DAn*O$;B5K{GOP7eg?9fwv zFjUm^srIBnkrB8F3+wRr4>~n!-+W zB1~KvH0H}Qjp(s&MMXt1Z7OvS5SG9fd=MsKUHazAl34JdM7cq#Axa*;r_{k+jPI8y zpNx_Tf*!4irtjmIFQU!uVi_nrWrX`*v3m7}lP6CKNk}|`HAe}ixel-s{zR$jtg8JzbmHYSaN2lX@zYUwN1a$GStnBy+W#x}=-yYl| zYU1Ci{BfYc127CegpXj@%@@9WIjfm^;mVg3J-yrOc{mYXMN%*GYtlT+}r{_TwljtOI0cjtVr~@e;DF?e3{Nu+3 z{QSCv(rBNuDei-e0_X;fU#a^=cboO$?7Sj7ar-(TI>JFBU!T8xH3GXT`Kup+972B zU1&;)l>{~v)wGL;d+QS(!BQzyHZA(rKk;hv7PwNNN$mSGImrUO5}p7isQB;z=><1l zO{^u(4&ET8+ZzRV!5EaV~j{<`R`S>j+E>eTj z@pYvI^ma~?XV=UyzExCI1cp=*^)41{z1{RkCx431jm-DpblLwNB@`iOXuA+Z;0<{} zGz420&8rh3u2d4{6UrZ)SeJeU4!vU>lgqL~c6kK_NkW~Wew@a0ZIy9-QX0Qwi`%{(D=G`Ew@7=q% zTPIHxs$q)A#O}^S?1!trBKptO>hmKs?q8OHoMaDTYmZqiy)e7rPENEe1LU8b(2`lBE<_HA1u7!d;fA zojVfC@8jEg0_{4>Hd)WRkOG8D45Lw^Pee$KC#@8wc>@G^|POrrGR+FXQ8VwwwzKv({%(%>OPm z-L-aU~S!_xN{4m|vkg^heFoIoh2&5UyRIg%gD4w8|5qR(SAk2tjo?G^)C7L+idH$HQ<}7tE*}GL_i9`019`E zV5;yfT~X9eqBEe8((3*R-#cvDdyUHsv1?aXkn=I3(yW!8TL+)J$(QGhXxe{vbOa7cgXB1< zt-TfSa$be*2^PC&Jln9#8lA+fd|a9xk4QLsa6vlW{6ezX)vQxb6!qw2QMB9P3={f zf>|{c#*~uIrO{G*?YmBp{=!@fmWLWNR$G^xBqKZ557s%`IXf4lc4D;UzF^T@x((mq zv3n@LtD%Ssp-w?wQ8(AZ`kl%!R{q-5v_W;y*LSQvev|~x%4$?gih|v(I;5+kW2vmH z?BCg;o-F&{-z5o2tFEqoF7*Npbpf3k=o`L{P{xAu>HR11PH(}?0F|WVX(=c)k(s4d zMHmbe0P=qh3@|`}gv~Y@l^-0KNo1+ZNXLp+uSE~+CdiDHRgnkI#6fFiMGqFNvDW;2aMqD8wh0w?9V7SO$LcMnS;=z!Ju-Tkpb;xGBF7Ca}kQ^=Z*FE&*E) zI~$DDgio&h95x+RMTlisxIxR)p)*7=mizqZ;lry~l#e9S9IzE)g(J`hlt?<472((5fS~8g0-fAYyozkD_<~ z^QV}dFN)@KDI9K$nD78#+&!BJT7}GWsGd2KHKOv5{TaBZPKkway?_=u3sA`FGyy%u z5c@VG9g18P81%v4V+i5R%y|E4@FZWqetpx>un~*!2_NiT(PE znV7q~`|xM(sGgRiTM#&hV4?ip(xQ*CCHUwS4j(3cfs~8LeY#-G+@R`4L$SqNi5wv7 z=-EcdUZDEc<5XM)L51V>qNA*&hBd#1_Y6LhBa9pZ#fB^az|U1s|HjiH>E-QT`2YJ@$&7(k*J(|dB`AI?C<0o+^7fZ6 zk<-mLY|VE$1BA1Sia{IvFfuav#D0e!|5tf=D=ETzU@C#YXhiz*zuxjnVc?6U-h^#| z32i3_hupVpOFn|kDcJfrVGJx87e`*rr`DmlH-$1xPzX*I7cZ|;f)yO6^{)rPB5=ZZ zqzXr@X-i%f;ZKpn1voh;huR)N=~+S9IyeM^20wQB@~gi#cOH%8@b3j~8VTQFgXbA1 zXfM;eQ3aC84v;;xaxktv%UA>6vFWk zKHsdYtflnyyyLCemSGL<64tGO;6PVWgj+xe?;fS`$IP6|#6ZZy#gw82)mo8Rbnk)f zAB&5Rntuau{s77kgimHIbjyFN?Sw_yx9=Q=8DoK*;aE;g>>#G`W^TUFL3LQ&S1>TF zC%*5Rr`I9+YJnYH>J94QFfvx6$k2yd%!fhvfsV!ZQUW^y!2A!R3U`f3XXDmOP*?*H z{I|7|f(gkA_AL{|uF-Mz|J<+439R;i@0~84Lt=;pp-U@=NlYHFYNb(d6!lq5BJ$03 z)?%EZ1A)fLDQsA>?k}sxv~lAuNPWyOl+$n^SEoA<>Bi>cHA*K=+2Z{-Wkju(lZXRzaDN z63t2puj_cyPH3PFGEs@@2D6|duG}_0siN| z*i$aVM* zI&Q;eU58KCmCtB{$qddAIXK|DjIcXebs$D~s1FSd>M&tG5gYs{R|gp`=u;c!zcNQ; zTt*a7K9_pCkJoEx(L6`w97B?%^DYmQIB71UyhANk)zp!~j7|*J{O_y*=xEW^R?6~1 zqpN?wy`%)NOXp3}i@8iicHPo2u#JwT_wL?3Yo#meK6Ogb3kSS*Iq{V@NP}XDnj3G_ zlQN2sv_F!2y5LgPwj|RTT4fk4n30tsiUgxx^#wK-d3kZ!*kUw`Yo3^|m#DWX4h1S9mRO0G&uw{f;rsbiRDb7&Al0-=|io1gDQ-%*;0`35CeP>^-D?mJ~( z2+Emx|2w;|J{ zn9Ro3t*;Ug>;6cH9!e45{CD#3D4G`z(DG@v z+%4(db=Zj^w`;4E!!ha@D*R5I$M_Q!V%_kj)+y=1Z^v}44lQW_nJ`qc89e-V%DrHL zj2C2Didy=hE5CzW2M(%NT4C47+}rgy(h*_rLz3i!jlQ;K+q#tymANmU73LY&vro_Tr_gy5(E&YWl9(k*z0&J_Vq$8FRTbo18E;rB zG`1k`bR{TpMl!c|(U1!dEg46T$*TIITrZhV3MJ5ZUiC` zaeykdrRw`&p8X8>B209ckD8wD4PT3eDcFoL*{3Q~}OXJ9#CVzTA7ApL#eWuXf* z{encZ!mgHJkkhfWTJ&OuYkD_mYg%cqX9{iUsCfw@RnV`3;#1Htq-zhA3roC0PhuX? zi|8TNesIlp=zO?zG6u`b%RA5tNsY1{aK+G9N=i!QYA5)s3v{%#KOo6i-#i;d1{}P* zt?i8_F1CCA#~=q9jSRBzS^UCHRQVq7MZ}726pT4DK(uT8U zC~#DDpMq)RQ?zw2D1Y*XA#p3N7F_;rB9#hHX}#tI=&~S{Ggd}xTIaCrQgtAd6B4VC zW`Z1)DKi{7*D^AgMEN5j@R^3(&-gC0Jw#1s+|d`##2pyLK>2it{JP%7bBFw>LUh-Q zgAelQLPf1r3U>4JpRi6ntgsV1w?bS{EAyE7w*=U=Tq|CjOM6QBLuioaI{@Egcz8G@ zw%!7I!;j!gQNA;2vpD~W(-p9H?xZ^EPRiCRS)=`-{9$eCD`$oVNOcf{eMm5hE5s5w z3PW!;jE%=CEDXI(Vqw2so4I+sfH4DwnZ}_=d^m4eD9&xxHm1^Y|M9GUyzN^X`MCcH zKzr9Z{`kDU{`;_h-ogkXl(^odA)=yJGRm!4I=QN2hV=Ou-w(;=V}bx($jiip!su?K zZeqJ9$yrRNj$Iduc%^ixOlVixnp{R`PgDo$u2%2gxY~DwnX%x^!c_ZON)8pewHGyp zZg_5g`3%IzZLk$zo*Cl-MfuEqnPdj&K#D^9G9G+7R%rv~PSZAI(;qJQfNluU1LilVcZ}Z0F-U#mfFsTwtuZk~&*udVCSzEF@A}u8)%P~XP z)WF9bQhc?RtN_#xnw}zE9Or0&1S-8yH=p;0uDxjg_^(Z-WL3~P;a-Bc$t^a2ejO%$ zz9sYwa=^^QRF29C<2rU|$tBdy=W0;GpKAPok!=cg1*#|8O?1)A_U`r{i!kGE(0-0l2HSktnmi!c=1aIb3#^~LCL;g7&xDlo1bV64GV^eC1j!i`|esy zUy06uYt_ZJKJ!Q2*9#X)pvv38nNFq#unoe`btON)Y@IGx9DZpsL+(H+eRUxOYUSI; zMixMckED{1CC)G(y|?u(hG5Ah0GVVfCHzpZB2QboKa$ z8`6zU&`6=ZEb}-)hHxLHlTQIch(Q``gb8%WR_V|y3Q&I{4Lo3RTD5lV+9VQ$y%pvL z20j3x+YzY6b|M)$IX6*1T1`WvVNcd@h;wms>yJ2^;dv(R#M?lgGwC|$nR0@>qW0O+ zVl1Ocd<#2f!6ZCjvyO$o7IOM0;{B_9RBuZoEh}CbC7a@C zVM2R^7*Rpmr+F=UVuWfFin9+$k(Xy*T*cEKQm{cmAUGCJQ)1WL*E|WOk%|_XGP5$w z+WKQ!TnY+O`cPGr?AjkLZ+PM>t-9u45|(Dwsyot+Lh*TK_j1UujU{C>l_4U_@PJ3)SVX`5iXcCaoGr>9BN5bP z>}JT7u;3e)%9ch0JjP`_Qi-Sf^ibU1uO+?Tg*~r5B_r(&+fG_?)c)48uyXU++>CyUN^@P6RS7b zCN-SJH}VT5uG-~&UVLe|L9{wi53?%B#~A`U?0xoga?)bh;}9q@Axy3!BIvWTvx)N+ z^Mdz)u#BcZ=n(SD(C`|xbYglZ-b}QyZZt z5sGmglALh{j-a;x!I1=1SOcoh1jF$S`NW2eSkuRy7GTA;!>t6GPbq{<)?{2dc|}_C zI50uVy)MgG+-}h4F)L?p4-RJ=0>~)1PA?|KGQl(lUDtLgDXC^xoRrSI?~Q6eOxbnz zb!#fhW*};9Bu5ti1vPVo(2Pa%6G%;8y`c>MLKDz9YvgD8V|D4kle_42yXJIb+NGob=89r5ReJO z^%{Clzyl7Cjh)TbLm!;x(5pJZ?b~_^wX9}8iu4kwm}KTIenS(LY{)v~Cy{z3pJ29woS_ zgzvio_UA1|S+Kl~E0{XRUI<_?7AhbU3c)+@i{wrmfYUc06lO1-$k+yBZFxGsN1f=X z=|qvt%)QlriS$zhQ2!M%QFB0;f*D`^X7t7kXaEw=#OtZ_E#YB{(`DN>^NEDm*x1&S z&(?2LF2Jbnj8eZECX;{>h{swZS-YnBXKAnNpO+oop&0%3fgjG`=ez3|E)XE|Lzta; zh9r->fG{#J{h<>fG43fI7*&p<;5r(9z)gL6tO@az;gN9>>@cLlr?vFpVvC8fA7Brx zN`FUVri6$+%%WiFK$aBFPn<7U+ghNACXpg&*)?9T(0y7>ec7AQs*M;8I5$mOjPp+T zOfuC3ZTutpayuP$-I<3e{e|_J?I`}bF0$N3lkB=1D#Xp&3J+k8EjZrA;Nr!-pb80L zhxYFyins0jjN_N2^BUdC$p}q4&a3xjW|jlQeBrq>zv8JxbJ*yn<&39ks@>hDKUyz0 z=RcQ9QR|qPo;v3##lC~f?hf&6;-QzXSW(k^*L2HRXjpoR54-2oLGD3-GK{9mf^-{` z$$h+`VkSvDSGbsaOcd33*^lX*i1C73WB7%xbA(D3w{E=)RhMj?@7=p!ro*-2dj@%9 zGc#ry@#hKk12&ZUX^U+XniInRqK~-Qy5pgk=xQIzE^kO7y+UP}BWb%99z-UTlTpzGZzp(a9mW0OZje6s`IPVO2 zA<|scWm;+AaWIF_@pCU2L3Hp+hq4YqCBBNBRE+wJnpz^Y@h)0D1Oo2T)6jG~L38+W<9PwCK-ry*_F={spQDR_z9MdDC}P-Cs+g(nm=P zM)~Tp|2^TI=&Y}%r3s;!qjaV5D52P|@6 zFT49N4NOzy+MkQK6vVZNc>%4aKJoxv&PB;h`<)USq9f3mO~JqV0Ad5;@6!IbnmZu4 z{=1`g1S`ml)=X_-sK0*|FexeAP)^R)9$pHTwpyv|9_D&HX9pz^y(~~}4xyvU%1*&q z7LGQ<^ls)=CHUEjVYwL#?jIcVgLXwG8gaEs?Mf4Z{-#wNF}xXQYk@xh8D?)dfUEoc zn7}X)eT7^m1*~xjBQD_6I?QxdmEx^3Cu-1m3?re@P&iTa_+_JSNHjE5O-+sKvKVEI zOMqCi#lt_+?q6*0>$?pKubqt1)xQjC&8YP~$Fa3ut(Z zTvQ;a{mL7k)}7mm%5(M=_?W=3cc3)N#jS6yVWZ^w{rthdfyDm#dZ_R{^szt(#JesI8tOEZCl&C}1uIKvE^Y*kB z%<{3BccG1WEak|HFY`>q5{Hk9EUFLCaOpi>Sn3gW9)ql#B<*$r7_Zy5?H+PZZ-)yY z4;ds#@;u{tpDp^rZ`lrY&lzT%4l?ITY98TLhHTvcnTbPfXf8Cm7M({LR07;;(=)ik zbcPwX8hz=rhplfJ22nn1oVxF;yX26<*hVeTeH3OK)gm}{#i+(Ajr7#)h;ZRn4&8}H26y`e3-BTL1%laDL?Zt1?VA==0=G-xTxffFbMyYj z@j49+kM5U8?CjDB6HocVGDcW;Q0fR_LNXGF&hI1b5SuEkd^8bKt%twM`O@T6{;04 z5{N3qL|Yr1b(ApfQAl!0H)p=oxGPCD_BOQ+F5up;Y0rrDn#{T15!fmGzp!OL>*#GQ zcwPI*0(8k=@)!;^nCr+!Q-&BX)at~ALp{n>RWq$cUV5fEhzT{ATFLz>N_tQ_cQ#rc zm!EyeNmpcTf1b!{XfHNUxMLs&QT6v;B>4Hr@Xq)F&$(9((vocZb4|Oq*ez~<-M%AX z!PRO;wkh}WpQnGXr6CL`=`P5*Lv>vDSFaE=`%=As2vSv$%+9}BR;xQ$r!zDBAh-Tg zZGg^2E-xUrgV09_Dx97AhnaICwmGDUI>7Tvjdt#WW%MB~OM>0qAAfTkH-8b14j_T(Zji@zLQ<|Rjf#xigQ=1%7&cBr zh>tz?fU`E!^h{HMn{)8n8v|F@fkX*Fqq~ZFp^*{^7DXY1+>^Lj`f}=eKJ^m_o)7S! z5>MlOcG*g&{jy-Ni5v$Fni*OQkOzr=81@4?Iy(4s4nqZ@^Tq(KB5~Je5;{%N6GJ^u zoEKm~UAbb#0|+8zz(vH>iZ_qJHDJO(Z7x&8`oW{@`)uSO6vE1Vl$b{m>+lKeK(wc0 zm{jq^iL)bxx8(vp!Ob57C_r4UNa487VJA%ZfiPcx#)CMHu!DCd!3&3=QZe_aZA7!Z z8NM!|wQoU?Bh)dnq5JULWtx?jj=_*>h$@YHSa@OaQ@V6kuQ0J=JTxFAZgjaEdjAJT zg-Bt*P1n#B6S)YcSR!6=f$Az7HzxO1_Kbf4{lUNF;0*G_N-9LsK2CiGc!mob0jK4@ zefy5#Iy}NA6YnMs2kd%{=Ud_Fi-C!lC?dE&WF5TjJZdik$)!SMt}e+t*!Sm^IHYjm zq(`;)O-r*)ZjR)vn%#?P%M8B<*QP%gXTc?_VIg8*p(L6nrX6bIPqKq>_6(LN(K`~& zgMT-!iWE3~`t;vVLcozv`j_i9!O=5q4p3ZdrCnQBY_en%aFW82Be!qfya_0H3(i$? zYOpPaXqm{&(itbGVil|AT$h5y3s}CL-3upGa3v2f2?F#Pd>-t85-&6};_hyhR7DjF z@60EfRyzCmc!g-PUeO-#j2mz#Af#p%j1O(byh>pe3n#BTFC*hR=y&H0(C_|Z$5{>= zlJ3{~?dVdUI-l~PU!4lYod0|_1FFPz9kx;*a)BU7J#r)F{u=^#@g2fy{>M*e6M&xM zCwq9T--G5z!)wWCIFRx6vjF&{JScjW8DG*yO*8DJrFB%#mNg4tRq1yMFWg0HHYf5OwCEt?^0M{hvC^lx?#je_u`aEP6)d2%YLm@-hGUQ(*u9bnmeX z-zO7Xle-PKF?th6El9o8w6ue8E(>Ai7-{$DXAE%4kbB3-v^<zHFcpQ)?sdcWVV*XvxK&*yobW@ryYt3{(%NiEQ#CHP6P zX**rV9}#o(#i2_EI^C;E4eEFm)X`Yy*YT;j$MyiaK7>IZGk!do*UIhNTUhqA`dgd( z>)eINePgK(;XJlv=*T5*^5TI?;SWQnz5yqRTpkXzl9*1tE<3<@M{= z3I$n(v`ZkX5xDI@Q7~F&@YHSaN_(gYS9lX??IlK#(*@!Uv(#KMIeqzH>jb+k)MWgD z*HB0!-m~}bcakd~^8P`+`VAV?QIH6%qDN;KF^`lw0@u}1@K8tNx#dpbJJ0MfXxln# z*Ekk)!IC8oJ{#_PbXm#vcnI_f@!XJ1vgrvE)mByg%Vo2^$L0w9Ts>gG?n6ElwL+x* zD=Y@4JuhPkSrZkazp#@`PBm1pWVNDRb4Zu^WLzHF>w}GZWt)d;Rni7We59q#xLBR@jn}Pah8+IPjQC z?EUouD@VESt7jVIy)7W1Ek^45rcIkpwz1hOYKmdIsJE=A;2`d|7)3jSU%ULa;DJK% zfLKCW&&_VsHc!tdmYHd@xr@Gl1LNwF6Zyi>Nb^O-^0aQK7eeYV{n z7<6rf>o^@b(W+Nis{6j7!AsD_DU66(9+Z}Dq75Ap%?wsY>YNeR$!?_kQFBG|{bo7W z!<{ZH${cHF`USDg^Z3wp>l)GRILuG~M512k>z<@iA*I{>Bw@*`qrfiLRb<}M4V*n| z7Rh7z+CgbM$SvKjHkL2<;owCF)GpA? zGaY|+tf;K4ufP;NABRb*r?{KG;uqFfQMqF7_#F`+ewt=iF}K2@s__ZT#q*-P@PM9H zCfyTE_M2A}rF62d$SIFfo&ZF1$`-Uss|;-cmK2KXzEJqYZI0fp8Q_dzB;ue z@lN5Z4v35C8NFz{c#snNxpQrAS#?%jiAV3$>?Hy9>eZ`b!Oo6&EP4D(q} zm!}3d?reJ8;G2yVfzXRB-|ME#yWNr`Q(B&5^8M(6ogk=|)Rd4@tRZpS3o$9A37|wo z5y5l^Q17*TpHrHe+Rs040kocp2*SkH!^1#$71BGY#pC2kSy}9#K{ZRLi8F?RB5Y_t zT(Q3@IuU;M5&XWb`x{$_>Y)VYdgP-`dGyc)`^Z`|lfkUQFl|((uM;V2UhFziZ)An~ z`>$mSN(T^n)?+1&1Wu}8+er&)QB!W()RZt?3~Rh0FrolzA~E&y>W6-2UZX817d)(s z-$UQFnu|FN%1As_S0N1=xT>{WBjVE*Fp22AwcdaU{b(Ab`!}Bo+&PgxuC!aQjQzxE z2g`555`iuY2eA;0K6Sn{!tCM^=>=#9PD(JU0l-RE=^c*^v8}^-PO@ncJ@{%*?}YJN z_JNk^yuv0u+VaIMggX@}glK`W@gwj{g2d6Zt1|`e+>B)fstf6K6=e~*wWaP(8eenT z`_cy~-gO=AcgV>0k`jv3!p0ti8W5|C%N$H)m~Sc%b|fK>a0m}!8>6gZ+lVuh_9Db+ zs9&uscr2~CuCw52uSpbOK%@cYd5E6}&z`NTQ?H?8URUkK5zokdwh%qf08Eqi#cZ8J zGzy&UVQ$`%B)twPvEj0}&8B;nHy|BdO>vc`{TmWw=<|7}_%K>%ujcudrqbi@=5*;f zCE>{ToebB*((R$!thju|4Eq0zb{j$8S|XXp1h2)nle&uoppM({&f<0kZapN_LBgpJ z4tpacsI+OOJaOs!*S|{hQY1nx#U+WT7pp~0q?EJMm0BD>V%CQ*Uv348Qe4{>EcXM? z&vUpy=u30(Ni*(*NYr+JdDl^!y}@juAU4t@xM*iOt`PO85lH0qL-wOV6CM&(93=$5 zoX|^k#L`;!Y_a{!ff36^{*HyafWH-%jKd_5M-;j=>yz{^nZdk;e}!VN0eko1iwtIy z#;L*O@=r%R%zAvmOvp=Vn>7ADfQuBR%9$mP_#Sds1OmME#>cX^uzVC>sX?->280C= zT8oo9Ln~eh#CA`iN8qrD6MvLubX>R}ZqcsYdeRgvC-gWgj~vmL zg0?F63s;cA)+Kh6R&a`tZBF^fDOh3S41%e@g%oi)J-c&Z;-I%OaKz4c+OF#Plq3%H z#SJJXLK~n>ctmXK@#g9-{U6}cFG>RzQqH=uXHOh2lRsMD#AMi!=)z+CAYBTMx4`l~ z+nIpnAut+yAhYuI>r)i3y82Cuw|#Relmw)Uh01N6Iv#jo?=6;w)WAc6gO?$b0 zo2MV(uO!x%0ye4*hm9K5ko_9twiPAycZ%EobrfKn`PJzsPMpvge-pOwH7)1JGv_w& zrQTt?ukUKA$xmfv^}d|woEx>bs)q2y9;}zTxx?e{lY;MK*^VxI*GIYveT|?b&UAIv zp_89NL5y*RP!5qxxZVo-+b#d_Bw*f6Ke^E{zqgu|xnX^eA1*nq90!cC7JcvibqC~E z)T&fj*AH6nDvUQ12I|nx;csHjPDt1pFz`Ep5tc|9nP}%}Vak9L0&W_U3&Il z%bnvb(qL$FNB!?fpU(mf$vgr=1y3$tW_i4rt4a^d>M$YWeh2K_8ryhja5E7VPH+ie zijZ#7FT*lwVjZZsyn6_tGxmK@f5@8>Ke^eB$AC0Su@!d}hQVv-x7`LYhcwCe?P=BX zvLV6vDR8IjF;-fNYlR_j>8&xLSe3(v@iNj!zXdI~uN>jvd*0lpdSoNH^7@KTR6|N9 zCddIZ_O$TO)c5xuA7Z$HOM3eLFKHpN5c)bknS@ZGASQeB=~O$Fkr?bUwyk=@pyGH! z_bsT1?dh~bAB*95B-s{1aRZVdw*LVaCMo%ZAs?iP(peOfbqQkkZx;UyVlV74X~smd zn7iaX!m;6x7ERkm+rk-CzDrn*eb|oo6y}|ky#TGTJ+i99puc)i~rO|eZ=m6%qonv2-(h(*KHGNC+>J+ zNU7?v`2L)Ab}F%(iH|YO*c&3fzje}U+19@!{`=VW;>!5nWTT|{qr9t(7z%9Br7jk< zzj|ZE;kHSfktutgM2{HJBzc5KSsCf8C>+w3=}R`FR|f2@P)wg*cqXcY+1`hTq~6MX zI~H=9Xjd?da|hoIm&q+csUaqp(yo*Ua?HA4zI*}MYXtsw!caS))(7fh_J#c7w3r-A zA3ad3ctFaRzMWOuxW)Frds;>*I9(DRkGrw?Ska3YpJHOso%7PJ^KH75D?;2Rgs3PbMOp){(PZ||a!%Jr&FJ@SJk&8AWK|rp-?ip*Diq#${&=GuWQ9c6 zo9Hm!T6POZPJ~!udfJf;YQ^iT?lR2~0#@}hJ1`H{e!>SYzLJd=V9{PSExUHX=KuS- zR+(J^12?ztAHmqEOr}PORORdIn1lH(wLSWy3;ixm|DfZLQnBL6WzR`#)~-E6)fF+1 zZHWl*0OuZBqG|i~vUBFT(@tX^m<09KJirWN9bh}8_EzNIX~*7|7(qxFueHs8kP8y=U?`a95x5C!818D0+o)RbGETR)A`5T!#fRqUlPa%M$ zexGO88Q3SeLXH?_L~7Qms?LKRpc4t2e~%-w3FVzsXp#K^U7rK{S11Sz*Fj-}pqfGI zz^xJl)>FJjiV#LZA|Han4CGwqJ?+0sNGtLlN?DkqHB#CUVs2)8(53Y+#)Xh+Q?188 zPqHG~4h?>XO_JDJ=D|=XMUb}^Q*G)znBb7Y&A-`Jr!jfRz{GYWOGpN)K||tEeWnpxFC^nn;Fbb%x879-jMnyTTg_Cmknu4w&D8F;|-@?hr6>DS`|C zIswE8ov8!_=#s+q2Tz}hSwC}W%%Dz&@cv?@i89v08Dp#ZEqI_B>qB;PfyhAoteii9 z+6D@4AdL84CWR?xeEIZ2gk@Vh4Q>J#B<%u3`UU18n2^F-bb=nxg=%cFi@^HyCRihl z5_#xn@j(+o3pEO1&C72)g#N*zy(hBIrVIcwAPl_b*!|FN`xubfLyUO`8WWvH_ag;| zNL6~409jgnxhL41JHsXvjT$wQL0UMGi(qmx&Ptpu5MEt{1QVo4xj_kBQM&>2+DQ!C zRx%xts$fkY3g>O;uH&ygeQP&UCh*biW2+bt2}H>msPWxzA!SP)6jItoj;wWgc{ZZX zY$AXsHPYLRd&#DnV|IwtU83HVY!VpMdbvVAm_TtIzV8ou49LJ5<_qCM9z1^@^kl#g zaiM%KPh6CK3U98(9=v&{u2V~CZ&|cu{dyw;HHCtH3@u2S1q$o`%|`K*D%(7ad{Z31 z@IM1f4y!1BrJfR!MkKsM(h3DBNqz5mmlfW`IL@C7X@*R#mgRG4W=v$sSRmUEH*i=I z3xl_LTs8#Z5@4%-V50fHQO%zeO1D5-pNMWSes&scox+<)vz`JWm^U0Z#M_yxSHGv_ zri@fcynn2U2VF-2Ji5=%jzdbfwQ*X#Pt5<<`i^jEbTWIytIgDxgb@})xi&mm^JSS} zy-)~}+nSh|gk;i8D6cx50a|!iMUNHIET6L0n}J7wh8i9?y$D(@GhOd;_4C+-%7zzJ z@ff>p6*Zb1*E&%Cq6Fi7UMmf5dwah8zppQkK}-a6*+SMdJl@)#kTMFU_G%@?t&dr^ zc0-pNio<&FVb>68gjV4=B#E&b-JaZVcei32V{~@Yh?_;ZR^=(4@#TqE0`ondVk%>_ zq=HexJK~kntVQo$%KbNE`h?kiHze6DMDbdcznu+1K%X=%WKOdPSn)76kx4a?#@=}r z->wpuu|%%3Ie>r!4dg;={QT5tZ{y8T{{x%Kpp4&eY!=yhxkVcHc3X8p%;=M4@^XqI`nna7Za8CrizZp60Ayt zXi$}-Cr&&jR3cckt~;VydND$v$Sfs^is1`M_FGAdR+{NGbzBdZrEK$;!uyfo)B!0(63j70HLw8q?k={!wh8@m~WkQhf%v7lU)6O7tp$b_nP zs4WFN5QKwBSu%SXrb=ypuV+k8I?H4}so4gvst+@IHZpX1lNK3&*`S9wgB?CZI3dQ1 z#|oa9Tyfiw2v}y-k)jUg{Viy9%Wf)7tclwJE;kJPB}BpI1DZ(L8*?2k3{> z801U_iuoQ1{^pp;y6){&?tVG*#uP4oFxs^BYOys4;XFrTQ^MNo`};f_Zyo5cFy0GBRZG9r^aNb5?rz*Cne zwaZ(aa`D^uykL_^T?6pLAy`Gx#F0hjWpWvH*ip!tX5#3HY?#n98kbw??~Vcqs_Zdo z@ox-m6Fd_)H``_%sAw1R2D(woUM5YO7(Qlu-DwkQACAZ1uYqpmS^yl;?=QfE2-zt+ zcHFpT3L4h@UixNfwZIiz!{lVg?bg-OBpHRtLsW!Iv0tM5Qsp_~!lYg$GLCR#4;bE< z2@^&W?vyj%>U4hoVefq3+IzKI(o8pdN_X-{^u=qYHJ9}XxFF0`!{)=k_U57Z;16gg z>h={1F|J@EW)<2TCb$E!X*i}v3i$$(C}^U+MIHOitdH=CCKmNMq6l@I)2fmwr42sL zlhF#zizV$NotU0!pjuAg?2Pb(T1GBgTdvAaub3V3F~&ILS>O;akFECKrS<}+07U{{ecj!|*xhN1>7&Uk(aE>+1k(3#l0tV$D{!gW%mxw|0PwFK zq!<-OTOujrpHWei0g`x%rQS}LRYE^$?JVe}_p`EYS(8mzrjbjR{>E^PZTR`l6v7j^ z$z(*oCumbgNA>|zd5@@505ydXPp_ZL{nUW8#$UIg-f1H)OJ{|F3{#c%qCn{npFL}Y z`eF6jwU4mVCSSNorq=#}YZXYi7A;rx(R8nEhO&k?IQPDc9L0T^CX_6~ZUi^orTP`BMX#jC$!HB#@|UJk2(rL8;K*tUDZyaBx2iXeigiB#>|ROT^n^- zDU>EB>#NT|GqjDyqbkOX*%DDlhCs$JY^BxIY14k~B9j`ywsQiG{g<1pBI;WMRxXV` z#07R5;<+Bq;(1ZWzB3f!GJhK4*^VL>p@2cZ7p3hc=Qzc@5#d)+j*HqFc2un>Mwpp8 z3Z!eBe;D#!fu)y97353|zu15{SKyOTXjK&oHmdYmfehVi9ZSQCwQ}c_Oi=4GO!TWd z&UrCw!1%iS_FFqPmlzvjm#=*}9-;KSe0V&9`E#gF8^W8=)LAN?CR0!`_TKmMWYLPg zCm~L&0(=8GQJ_6koC2G_9&OQ`GdwKbTI+)f<)$Htsv+x4+~ZE2*&Fkp%}jh;T>KqI zkkIyQUS7(BNvqis#Wk@|2lubtN{bTM2qocxOgC%=5t_7co%*D0i{NC0MUMc4js=C* zZle3&d+vh(<_=7J8ZZ6g)V9TG(2?YdwD)h#fEY;_s!g7csl8tLcV#!4soeJvI;>_= zw57ru^kQnjAG0byS-O{J+{?|)^~~Q|`_c06;;i!%p0)VALQpG;rhIE&6{Ixfsn=6T zml4H+vI4!?)wqfUEKs}-YAHrlerYmSRl|`~Y6g?H=19n$YulQ9qdMy&N@)!^ta115 z-3PB;ZNvRPM0K5%Wkp@G9M_1N(QD`mcq4aNy1KZ~`j^twfN<LiiU+L8cD963 zQ7i&AlJDUE`ym?-G=f(;S z)@pE$**1SN+=31DeSETv!mODTZ!788wPpKjy_@Qx-Zx^o{`Gj*|2OluL$B^zVrLzi z^KT(@*o*Ql{~zeZasw6c8Reb#_S2z*v9I$7O}eF4%UyO+{O5O`)32T3-DL6(gY&{d zYoDjGeJh9U5!pN4FASL>xR7d%saZ7Bm?$|b;XXNy=P@sZJuX*)-T!9?HYE!^GJP$)5h^v$?F{=?^)fr4@@Z7`5pE(W3SmOUjT>kseh`^4)tO5(^lCqM4W>jI9FvCD z!98Z`gbL|LG%kfNOKCAgG#2vsj^0!&-$pEEU-sY=#Vbg-UyIF0sk)~oF7`&!fh@+ z0h@#_Lg8w1YVmT!P4(oWyJQwfMoN=e!CYumgw9QV>~VI3+?v4CPfx^=SZmdE z66M_GWdQ^~l|iBqk@iL~IBI`cRbV6=(4LW?MCD8bAZKh<3r=S3=Y=g91-XI(V#B6tK#47S||TtXjG=0sj6Gp9axq)n!lu!6IgQf5i&Q2&YV$a`*V+ zu^(F7{aJSJL|e{dBZZ8!A$NIYd50V~5G7SCgdc^SR)EO6h;}Z7$!iBZpZ*xL^fSV)MqbTM9;;r+5;B;qn_&T1nB`s ziOg*vJ!TR;m(8WClVd@$CVnd=Cz2$H-dZiu^8QYCBRPqTo1yQ4kPC_jsBMKyl``NK z!-!^uQkJ9zCgln~i3kUP*cA=jy;|EZ1s$K=k3kwT8aEmc^IRBa_wIO=hwh1CV_+6`BVhZXe+ap5J4JFn#n z1&Rt-a$wqrVzblBjW_=-03aDPhW?^{q30^#NFg`{ZKl=eMzV<~F`LCYK<}ygb#fkPgt2lMnq|xud1t5eDe#)DU6_5A3{O zsADQB1tQB%bzdaXHXe3frp(%t4F+5$JA@2d&;beONYG98G*ZyJej|O$_X1A0BblcA z&?eM$XHK84L!S9Nt)Iw}g|BA~9A=O9}FW`vWwkKhpicqizY!pq-5&#fLZ8h z-5$d|O6HNUMHJG@p15qi5U@}VnKFL)7m>*UAbp)6PD8A-%U-3e6I>FP3o&rPyH35n zPC4qp&vjKIG1&REJBN5|VhL(Ff`n5nPv04*6e6aN-4ZZK8jLwz{Dna_G6f0uO4;k1 zDa?Y$5;UK6a_HPY{@8mY_{hxjO$eSIAW$NQx=57o>(tY)=gs+NVHu=0t-)*0-BIK> zXD?mqu|n(h+CwS5Z~fug&N1xB1%NIglPGX+Ksd*MhY%@1!-YIExIW9lp%E%6uofwC zb~v7%J`{z2GX>ppn~4$n_4lPnJ`)r9{K zSS|CA5ubrU56!;Z#*@K9I~mDmKAwY}a=&#wZ{SAFnzw}cB8LRq6UvL&xrc3X55=kM z@|r_S3Kv=h)YM!IZ8U5B`g+%Y>anrw-R)D%7C8jAGVQJJ^wP>{`~v4cFS{0fDl)n3 z>NjOk!j+$nof`b3rDcTc@)hqNdk(Ji{i6k~JH5NJW!JN*H%q;yC9GP|FyYZV^fY2-t`w&u9)=;4^ zYSNfK283fzUcE{n5DqLLJ)W)GVKJoKz~6qmboT7yz{m6xP;YPV;P5VUUS2bW!n@{a ziP~#;%WIyY0Yg_TZw_UMP03~-sSmcvt_*wC{MnU2`+}GRaBf#Ow@*I=riXk+uIj5Yu2sPf&y95}$ z4Q+zh{8|1F>M9hcT%{Ksdf0B&UnY9EhFN0ls|X+>T@k`4mRcF6-J6C~KYB2;mjQSE z8RJlyaI)Hj^vDu*m!H0i9caV^ESbJqV0icQ(M!t%v@$}6rmtMJD(flXdM>@5)QvH> z)<{DsJWMx_Rzd!+xKR0#gDtpHAYG8X%FnkgIAp&Lms9lk@jk?9d2u%VPnWYD zZ%9cVoqM3CGAVMv>P>{XZgr(SPKr#ggzU#+!GeQ`t@0Sy(SSZAlVd2T^+^pKA)`jc9W zCpwp_p_;4a?xs@OcFWL=4mz{OtUOsXZ#yl$=GYEyz@xof{b-Z+l><9ExG5djH_!rEGUCHx9&Jhl ze8;xN;B_OMZ-}`BgwwtA(M-u;q*%OAEDqo~t?41P_Vb^m#LWe%?n$@5Y{eE^b0n>x zyG%AJ`bM9yOT*3J@?{E(uEa4I71QZ!es4C zX-iQJ;j|Tgaol`j>i(NFryPzGj^N4F;E!t#SB^DdNm6Lg%*h(MBsP7;M;Jg~J!flH zt51gETvYhHrk12Nq%y7CjdPCJ%DPSec%l4wn~!Gm_Lilf$T9fz8+-={1i{@Z~$0%ht(KaTAD?}pWyY`1)4gk9ZZX8HXZO!>kVJ=wO=eKuk369~^ zoex*-rpQP-mtk*Y_!cI3+`*AkQ}GgxM7VS2qi>poHqw%GIt`hK%z4JVs+ZKnyu)T( zXTT6leOH8ozB&2fRIfl3<3ul2cPD;XweN|foNcXSa{{<)K+4h z)PDLY4ssG9mVi;?D2pT_gk^k?ASnWTBho6 zN$=*s$u(WmjUPU62PkUwqM4uNRCI$a%a(bR8>KpIasTwbyzPV^wR@G%uA8tInyLPj zC+C;Ff4vv!R$In^oPA-dOTO})+0y|2`>?%11uMX4=}VDOSXelZ*@)G&4z?zD(NF1( zI(5`OGq38(ew(V^y$gV^^zUUebM76CG-o-2UAIe3jre^Zx=cr+*NEQvb^{y?`_ba| z!^e-YAd}Rxtj4Ov!DK|ELX6lcjsslA9LOto&#-#uCOU(bV@rcbDxj94v7e3@Ugeip9^+ZST-YwZ{tn|=pK)BS6~V@0 zERus=$C5&PWePxvA2BUOiIzBkTnhf!857|5uNl5&v)zF1)uV-~tiKcolDp4oWAE%7 zE6un79Fi)YU2`e8fA!8CkxiQ6Pze#blOyw_N`Vm3Ebmf}#?B&AR6;UKnXMD(V~3&3 zJy#ksR#OvcCXcIh%`f__f6IcCUMDt>vJab1_P1j1;~mv^33`~==-bU&_cPq5ZQ`sA z$o1q21{S>k%tRkhiM%_mK`zl)b}}?=S6ox@zs0w5qVk$VhCKe{nhWgF%Q7Z$D33@vJWgu6_eQfQ?<}&m|an zgw$=&Bnn_k*5`JWzqlTV{GgYOaOaFS%iP{|U3706NY6Qcbww<(X_(rV6-SO8KQ1S8 zgWW4*kGHoQp{*Tr@Lo~6{T-%h7uz&ujXhs}i6wv=aK~VRhxv<5n59V3hW732qvp*M zlb6pKyN|;y*uYPoJ&VNEXc`($MZ12JOjed%{4R$kVsM8yWKR#?zdwxEGf_$fJo()S zdueO;^y!?9e&OKj8Ch9b$?*m07w=P-EERq(E;VP|TWi~W+V8sDpL11;L!L9g{Bk|u zRJB&E?DM&z?yFAkfe(1LHQ28GmJ60OUr@7}(2T)s-n=--0X43fOse?al0qvnGfd zPx`Bg_KS+o9V1puk4)X>nVeIg86HJMmP~{+#XIR z3ap;2hbxBxCUwI`YgY)6HqU>U8HpgHF^}J>rYg?j8QCiBm|*^duVk#Tlrs zDYa+Lti2iBKM6s8*_{bP9-!BlV*Y4K*7+mnT}B7=o-$xI4kr5+AdJKTpo97;gep^D zEG^}#^G1_j_z{lM^0-ye!?Lo^R}AgCJ#%2Xi_f}sqr<##FcEhj-M)2e=jW#3Z5yr{ z)^OFYr(e}qC^E{&>`u0K%3q#!mQm&teWTI!y#crVP3ZuVQ0JkL4ab0OW;Ga%Q+$&olOhDfxy%g)kW z@^Y#g)8!Gh>Zcr`Ybbz=$~+u}Ahd#z%|$nDF@>_C*?rsTQWBVSi|g+}9)juUmqNfN z{i1Rx{-~nmki|y=VL2NgK70tgy4mygZVMR;Cf$DVx8>`Wgg3>TNrZ}Y;@BdrWhk;;@*`w8mEm|{y1r;NxTpPK;*h`VK#}4 z8>5gQFvd4rb-HyasU~|lmMNW0zW*Ll`G}0M4_#huOaQ(eBdB>86h&MWuxT_NB8Iq5 zLLbJ@9l#yL5{5-gW>}G&JZY#vuQ1RRHN?Wy6I^1tHhX-|wpX)V$7>SN-XMIX55C?s z8pM*pvlsdL<;+@l(EoGy*G!DBiNXEOd0cSkjx)hNsmyxBd@<6n+1=d<+<{wK zw$e}rydkg83K={F@34dYD-Qb9sZ;fD8dSV_W5FA_gdWW)!ejRlg!-e*2z?MVR(r=H zlMU&k@_3FU&}U=1g*&mQ+w08op|;$$=+Yl=cZ>Cs*V2+5UA;MV{851(HD|9||ydj{>}f>n#qc{cQ4F;bB0B*7%5z1ufyC{Z1i zP%$X5NJZj;yYNnL-L=CdPFAEo#YFFst~+Q9a!F`s>2}DfZr*Se?X>qW+<6jVqZLA^ zcuHCMv*d4o7QyD;Pa0NiDQTd=wlpB!YcI7Z%pnN7>} z1ewUAn8%G)4GkJJ&?LISaE$-4t(w|?a!Y4wyg>AKN*Y4Na5SL_(yN_tUDM~<$sH&3 zX<{n>`#Q+LwP-zM&7aLL%1k#r%1uze4>@nV5FTfS3_c<4Ix&6fj{#+>=qDBh2t?Yy z!}ZzKcsLZanl`p+9x0L!ExGUhZ2z-H^0CkNUdO5MJ<$QZbq2?SYifI4!NOS`oH5MU zTm}sgA&z)VW&>`OU4K!s(~VIQ&I=MkZdCjqAG7q=@{tkG=4h z$-+QT4~6ycy?A<39*e*K{#)B?^XVDaS(DyAS#L0E66Q<3Z1q&G&8MP=ZtZiI$xMw4 zaM|h^j=J3(^*d~_?yc+fvFylkl%h?qt@uze8#i%2u8jO$84jd+{@l6nrBqKSN`m*j zhz~x~w7+51E5uYOg$#1P5K+9e_Ow6HQ)}IN)?YP%Xmcr*l1)TB8bcQYWjMHlBk?e3 z&<%v;aob}+*`&8(G*W_U2H#IF-bqNL*|~G)?31-Y(f(N*<*I$J<=-pNOg;EG(NBH0 zPnolyd@FO(BmecSejtxYA4!mu^ogJVDY{wvFRvck5tQWu+>_s!vI*mH86h$5=n^JN zBM4bWoJU4>cKMpErK~I7#3BDLfRx20IU~^-${x_j!P1Sn*=O+gha?2t-f7ntui%Qq zZ$D0M+cu!}&)aJEZ+HtW>$vOWu1?moHZqAY683o_IP%!M;WyZ-mZZJ2Gn6Coj24vM z*u9@jUg8dpTEKg|FZ+1YVOeXzI!5~1g_dpDGU4+_gD3OL-W?)j(KHA#-MCfK6vaUa z74bCM8DEIEh9nK$FZqY${jdZn#Gv)H(Drboztpa>QHS#UDK1X@(ttt4D^CLGmH@%| zZ`(E@rpOh{G!OX-F*@wTt|qN}`1E`Ou&Ed`ZC8RV2 z7SP1FH~4e;sZ2%kX}zah=ed1PhP(KGyfM55frU4EV*^& zkG##uc1PHnZhSHj5yfM}su}qlvh2`JF;W225+2fnGJ&i&^4rJCoJ>~7KQhuG47dMk z5?#=0x6PP-T)db}$onph8m())QG4>iJpwd=J3U8wW}0Csm)7~7`~ANbBfyhvcmF*3 zQFtT%lv6Y*aqFT53nl^sTIi_BFUAB2NL+^2H%}y(kV2MMzvJgdwilvRfBCvY)9=3X zA@U@JAa1RsiCo~zp`V{Te;xxkP>k+0`L9g*q#U2t)3PgFASmHbFBZLe;Up)MkiH37=8?2Xoj62KE!Q3v(UhYQVu zvDJ{&J6~kuKyiW9NKvD>C9T`JMKcz0v?WT=`eoE>1|k32A1QC}cH0Lw zX^Y4c8yibSh&>rbT)LO3HM0epz8W$(_WJef^*g)f%j)DlC^4N(3qUuqRQ( zPCB1zK0l|_SJ)@~MSiA@%HWUfW$PG3>s4v4#b6C9I&^Ut{=2_dU0NE)AQ}aB7(kMXgU2<1xsX(SS=MeoXWRaxRtiXV*`9yplnU;Qo`t{Y@F{1h;JXI)8 zC<2N6rEAwFz+q3~6~r6!vzt&#rXK^C74d&hVn}>f z#XJ`9eX70!b_WM*82`^ahU^B_D>@@gD@ay@Xsv_|?Z11JQu>+*d`&n9tLL=x3o9i% z!VD`pu0cm*TCrO55EfIw__N{C>$zXB=$GhGhtO$`)GCa|kJz5{JQh74%gY9Mej{?5 zO&p928A~!uw#6OzFUi~CgKt~TQifxgqo66}Z_w=Q@azBW>Wt=3m?+~HiC z=w6u7_tUfC7857>h)+e?lflSr8YMNJ`6$85S4x__%I6D~rA|lx(MTdTTrhxp2O@3V zap++H0@?wz{COF16b#z-w6xDnpHcT*9*{XuGeCQKK33*R!PZ}f_9@92u$-NI&9D=X zM*G_P_uEq}#=MF9JY>M~wki)W<`oBDfY@n##grPGdD zc}Uyf?TQViCeYwyX@ipv14P9_^a3TBkwApHQzNdh3z^?TE2vji!7F5>fi(PkyI+s-}m5fi3y11!t}DLPr?P0^%}p~9 z%(d=V`0^VJ8IEcK`9#<3As|&2l825N*znHH>iKV-Pjk_sixd$LrRhSLs1SI)`^Tr+_-u)c%1g`e>-sOZzu9eHR3R37gCfesDRC0CpbBZZ70I$jhj#CNmKG;f{|90-I>H!DZ}{^Cm!o_1ZyQP zE(K(@=YgtTo%JN*Yu(y+PZ@wKIZ`S-K^W`q1cjB+sSq%lO*7$oC+4jiS5#E!l>YMn z1kIc?aKir<%6u~0RYFkjrJmMuA3hy8#<0~Z!pi7!FOEyXMgRxd?*8M>hC{^4v&6ke zaUwLCX$r1iz=V;N^Irg#r_heDIg|1@Q&x_SQ54$iBF9=xA<^kucq2a&4_OAul<6ia z?wZ*q5DZsle*W}{vw#)WGhqOT51BWy!hSSX-H$%aLBqhsb^a`g5`h3{xVkZiemmzT zy!*&VlrK~IQ-DdH>6>@Jd|uynlBmPb^gG|w6oL>Ru;DGkFq{D?wROi67U(g-G;8<3 zH^-Q9by$QIxS*Qh_JEWhJ&?am@A0s)Jncx)Yx#lq3TFM~z>>DQ_eU6VRY}X#5>;PoZ4-B0h6ccHj}>SA z>C>lPdd=mJ9%vGkIX-%ik!p5-0C9 zR!T_2xcaf<|Lqrt9QT%>k})Z2SEqVH=QMrCNPk$qCl9HC7Hs5yx(haw4C+W-WXs{;+P$9c(ZicHOuIu`yZg7 z!-ba^Rsi*h1h1{zwd-LVM7vdbG^8+*4X#MXW}sZ;(v*oR$iZ7Ti~w9dQ8FtuS{8)Z zng(C~6BkssUq%~bN>R%099WQ znT&VJpyu+IN_N`*`d%d7z9i1@>=w0Wr;QJRpF{~zkk42BFvLe4)mRKE9g2k!Cbj!w z%xd@-VzoJCx)QD#>rBaNt$k9a9bEhQ86nhh*C!io?qDM{j0yROU_K;7*DbMQm3Az? z3w&$wTPww>*fVBt^T+?1mGt%_y^e3S{#lzfC!5RxsW5#vnkLksy0uu2w`E@-Wuc&A z==2IQH7CUoZK}F4Y)Rv4(d*3&nGH7761?&!X)))9zl9aiCSc&!8oL8gFpf*0#|9)?tsDrw zp9}pB3;cdsJ#V*eCi5oDgAARYl9V(yyWE@uOIIIJl5#9WyahZ1)>konN*DPy#g|3=c(=l<|9HG8!Dndg5y=vv~@~X6;7?$i$%mTSu*3#>4*75(5Ar#DjG1uN%cty z2U*qVdAAcqy99FPWcyII5OXoi(U;_QbV>c=NiQ)>;j4KHpYO1vB@O&)tj1`Ng#J(B zGGh+dO(rDG+Za4xeh?u2&xAOl*;9sdDLv3DlJlE&{sdfo{Q>;6vCyAgV4%7UU-+pFQa#nWzHgUq8pf8Y?+75kL$ja5sIO-&IxRVO3GM zYL2bla3yCrGgd&Lgqb4a66qs4k^^|Ldq)@kj_1#0eG)Iqb02$t5>rg6fir&VDHm?% zh4=YPh(|~lgO*OHKuIH&BC7jLzZMvmJi@GTW%6$CB4lYh2@E741gh*ww@37ELDH}Q zCb{^sc6u)7EH1d4yjk}gCR&mhq9sxM9ds=LtFT7l#`xsEbnVYns#e$N_-mG-c*lex zX5`Xpg34mEmFiRv^T@{%jpkAxF*8fWPlW$E!2c&t@bY1n?twnW}FW)%UI;1~G^rtO+lLrN^v%{RPm6u=PR>903rtfn&- zz2MlQNQ!?Bz@o+w%vxWmMP%)>hg;x~ssKzyDQK|p(Q0AU>6BF}4~THJ5)LPpywHD~ z>e_Oo^;s!YKfr;nIx;|Wq1{mhO2aV`GK!4LFRA_v)9&MUPlVqW;nnRscP^7YA~!Re zJo#4BZROc+t8N5K|U z^EFjG8)p!%h)3e86rG>ImeBpijtwzrWVg=2rHC%0FD27p@gBNA#E^dK!9%=kkuoiP zTFx`R2}7@8j3g}&gh({xYIH(Y>cXVUIq(B zof`m*h*DuX;B!({%lb3)IKi}& zs8>hq_0U>!u=AGRmVY`bDfz4wTm$rUyycbePQ`|^e%16`mewCI7(Kwh=Q2hNt@0lm zGw_Ydi&PNYaQny^h`7U{7^_SE6aK@u52f*t72^h!pOL>}odeDLbyXw;5y6-6xHfLw zm;;C{LKqcIMNyR|$WYe|d!lidM6V@wO46H6=S+W4aZA! zj_i}154@0aXx(}xw}3qNlbx1O>LQdtw)Z5(x9pJ@+;i zS42wSbh{Bd+-_j|UV~4w4J76J8cH`7oNb+rzOqQ5QB`A)ByVRY0T62NnO1ZmSPDTT~?K*r#G80j{ z(B*2fju!@DV6ll2EH;#ww_4~01fB6zfjDAAh3n9W zR7Js`R*;rel$Rg+ONF54)Y)XWuY?#&$h2C5MjnSEd{~=l*|34X(%|r>(n9sK5LeWM zNO{@cXbCvYXY4XDlli(r+N+RcV4W25W+=dRv5uAP}Xe=R#K?$x@6S`7A7u2CPZV38| zV!L>|G+T-PIk>I1JTy2ae`~HJTmv4JDiSiIC3r9u{xr&1=Uzmu1VeKlNSNq#(Zy=P zqhPYK3N+=S$2{g183dM#FFt@NMF4H<@ho^rGCD5-j@iUkjJHP!KdUy4?|hGbq?=G! z#-qm0EKn`fnC|m>4SY|))&oJhq(TTYl;IF|bdC0qS`V~f$y88$3mq8bwu*f>t4wvU z!n?8ork(V(0kjHGztO;v`E%;V2)L+`jmP)ueEYKtl<`qNI>2U-D!nfeh=5=tAF zOtdT%GW^4U(QZJP@smtxR?{>eA<{Co-t9?io3%-^)aJvy-7bWM_C=)=&r`G$tcc$O zxrAXoF3Gf(Rn#U9ldwfYbxxqe*rTM=`Knye$Y3Ui5gT2F?ca6SnU=%5h)x9^zFkm| z$rL7dqhsIx)SebC`6^t($bi^t2QG%9&$;=i1&5+Kyr#UNI>mC6oz*5+c2Hpiip#K- zTdlSVE9<=!m4Q5OIW(As*)A>#hz(4X)J;+jG@8t}?```Upbl|9=!K;62aSITt#{!_ zKf8fpj(ChpDvlII_Bm0r-jg>j*jx+1c)#uwI-v)Y8WW;pf2WS8BFPV&Kteqz5`4lG zC^R2(-f5OT&g})4919gGKxv}GwLY?e8Z^-O&~Cb}gWN*NCSbR^_39BQSD(4Kdi84Y z2m+-w=&!=A?Eq4MF2gb1U~X1D?NW~tUCw*Hh$;YF5&-DkS=(07?L>5r`1fq;RQ2$I zBKeSF6QWY?{m;Oe40M%hCuj0DsdkbwK}si$*fuxta9J0&Y}jB%!Ez;GT@1%Z7)Ks^ zj2v}@I>R~6N<;&mLHieTusq+9ImQUb0?oTYB#cSnijSmxA$ z1Iw;Wx)qSo-Y9eOiNE6MI3nzeCK?OCBPB9Wp$;D`kr5!G1CwMHSVW#M*-wYQGrVuN zKLbz}aC*klr;|vrOv}lO`=&H%)F?8iD+VZGA7Ez*p`A4VO>VexD=Fdv8@d6#Gp--4 zWo|<5RI;|ka(%ogBN|0?TljQC@ULI-&#f3qiNDO5gFikxVX6 zyqJI*Q$zxL(umMypg2AA_TX=)Dkbcb2Dq?b);L0tPZZ)}{TO#7aVjT6DIm3=Ey5kL ze>8*(BgYCv@wtyC+&$2>)oP~rf!H`K)a=Z?SYn)PfFO9J3uBd#UsAn9cFp*1$E_rNq3+8W2F4coMM?kRpFaA4a2YE%kJ={? z5y3(%#y7P_cC$|xFjC=G>AbQF6VtNy`l4&0(+NS1%iSMuGAh?L`cGLa>Se*~Gx1}s(=s^9o(62T|Z z#W6}z*f96>W1zcK1qvc3qw^j;3L^uK=BQ*W^T9lu;sQh=PE0zZ%u*hJ$``VSiy_R7 z-@XD_X} z3){+`KJA8VX~h4sn56q;JrVgCPdHq$X~PEhm+g!^9zA&A^Wfbh0TS-8%x2VgqUDam zLa<|}NQDH#%st4YN^zDx>a(wfOhdA1txUJa5A?hDGJD@To88%ty7#tH)F^^Km`ah0 zBZcJ<_|f7aJ)NAl|Bx@Qx?4QF9rxLw9mORfW!M)nmm&-YMI-l#qK&eMXL1RX4%d}9 z3b9(7AgMnTjV_j0Cw|_>n$Cx$f)HQ~ZF`M-2vKS&mMj<32D@kW88PK?uaAeLhc34o zHuLP1g5+uvo?Hg2CFR`(5W6Ay z6y#5>irS|kK|v9RO-v8rLN!(sHFt_M9~L^Q{gW_CoGJ%%XB z-}k-sqVoCWce1$|!D+|o4uBem6tgB6Fr6=TIjAj}I1)UgDjUE4gmZ>RwwUL6;>eMA z{ogDN+#SmJ>$CIrpT7aJJnmSXzDw{j$Yv&y!}~)%(=&80fkR+*Bs{BFF=g&auVtoz zIwP?nbMGBbk@6-fD-$oY?q{%ddxsFo7!#Y^iMGf@2?FgXNz-<{zVz2m!!Jd1N=iyQLqGIf(&TA=)(!- zq#7K7&%t6Fn$c~Kh~H0ctVs|-BN_c+Gz$KxZp`!WtDNQB3;h+=U-xvQ(Eq}ni%tY( z*2(O@!R^1EQA_ zoC5v%1->(05SH%>*@ew{efQbv_iC0hQC5^pAY0u(E+l~okHB4Pp_Y=uKbZDt*jwS@ z#QV^+J&v~XlLw8I`_}AiH6i8GySEc-@;DkIaZqUHxnCrMQvD;*3DNgB;x^Hnj&m4wa^6*i`2}oj z-d7L>xb7xEaG1ck>z8?ql(8NHgNu*m*hai1_}2LCPppbEq;(2pS=C)nnNuiqKZZb* z!NN&rg$@mE>L75A9g2-gFl#xE5~D>A<_d||{4nsJ?)H;`J$T)nDL)TgJ{94zEdxNq z9j|)tANV})j#bgbZFw6GU%bD8rQbi_v!B26OJe_Bwz>&LkKF4hzMPm;Uez=H z(A(0y8#mWaXdG?sXt3;UT&*T=B3g+0pKxyI*Gp{V6_xn^LQNIj-EpF!);9$u?hx-1VsQ#=|m!s4wcQO zhd>4`Nk@b!*PCBp$;qZqU8FAEqlFSD;2&_l;P!1N)@Cl44$CEdJ|KeS2-2hkj;!x8 zPwgH3Ap~jq_wilm)Kh~|DYO21r6dZ{oFb2~08n@wC)O5BlZbaln`fwW@r$?O=5w|T zXqcfM4I`lKmbM?sh9eOaU_pq~iy)yz(QRBv+msbceTf7Ho6I}mGIkN-FsX}RxL*|8 zMQX(bqT#lM{YTMowg0wIG>a>*8J80!nQEQ?`{u|YcYFue(bxD%PyOWWE!n5XZ|rX} zpyBOqE#LGU(#F_OTVd2>sa5FX8!esF?asR_3N|O-r?%lZXnrKuKgK+4WVcnPeO?T= zkZjvAyNk@6MNmp;f|ep(vRFx0h?x4HZv&PDw~k3=N+B*$^M~=Ugu2MOkaFb6 zO>!l@S(kp4>TlR+#3DI}4s$WY_1)?2Wrd(YMA+O>cYS?*(b^&ANj%hVMgOPxSKf+y zFq5PPZI|eX$wP*m)(f!f=AejB(bzpGTDBSAT?*J;ETADId^ir$V>%qgD^!O-IOsg zeXS1kTTE~S6l+6hV@6J4S_X?Fbt{Oi6Oe6OMo5>@58ON)ic6#2k$-8idixKZ(YThe ztbac!`!}15X&bkVYczbilZ2j!k>b`hRM?fz(|Lov&Pu?bS2*tIn!o0HSQT0zNw65`T6CQx zSlt+fkU6w<(UT|pQTr8Bz;=@)#_oA|K+$uC1Ao=OU(U?N%x_^lVCBPeI8-5w}eDZsWREc%gAMKr;9nZo4+^*qhEUmy0 zzjBxFYp}On*%>!J6MKpHBqE;9Yf*dm?Ac?Pv0tiZd>`2Qi+mmf;){%Sh_;{|PTnIY z>5A4=z^2>F?g7QXMmOL|VbLGxJdhn<3yy2BwSKq0S>^rtNJHg6TR<)D&V{uJW<)6Vr)eSB+z5ucD)8_ z@CHTr6tempqW@UY@uG&61pdC)yJ;3R*ngGgKSKlCCqW^|MhXC_7!tv+NzZ5jt&Yvo zwW^TMnqdPrCP51a%!1TR4}xoieY1x3KDyRhs%cfxhk9(Mf(Fjrd9SiJ<85E1zS#;D z|EsZJ1x`%|0S`+FDL)<`^W-smLYAaJ#fF-Pf}aV0PFFl%C^S)-10g3BxhZlsG(6cL zE|^DqN-J9Ec-ENKsqvzp#$`mD#0rQbi!s}`7B+=1_jxLc7Ql0<|G*-kXAJ&|Cy$Zx zArb8C8H`zH>l{(jkwx?I7ui{xHW57ci7LF++psRv2{^Qbi<*2$Ja0I9C`w)Pd!bcj#H0H^urdxt zB%-$T2uiUK9Mxw$_b(Xd4FaYm&N!dOGrv+snMZ-%XmauIa3_eEO|6#al!dgDpkV-- z6V(N--;$!D`V`@t@riCaRBy>LGZ$b??#RQh}y??HC6X z6GDJ~etq_b4g+1oC65&4BF`PSU=CnHLoGFy9~h2eLJJ!A91__TD)R2x{)v;<%Wh)5->tNrlcgSR%Szzw74nY#xj0dh(~m*}cQ z<%z7jrbTM0l$I!QPuk^}PQ5{vX@4kxgVshz80O z$xvpB2B9*P5E0637Zs^(Oy&m3tP&|o=Eyu%NVBPAhz3I_A#@(EviI5Fd!2Lcway>E zwSH?I>%PBh?_EB_`?{{z@O(X=&kGDl(8kEFIy$D~f|*K*59Xxh%n25nF*MAXiPbZ-$#~0~-~U{YstH%5 zib6tZAhU+fGZ-_Z!^G0*ztAgpCD~Q&oMZ|+k(x3!TJiJiEYb8x`_GrqGNTlWXI9Td zbmrevoZA=`@T+#aSWd>1VupwFmoWuemYE1%2Jf7~a6wDtivry>J$XJpz6dJe_Ps)* zSEOx%Pi^0?I;L(kiAk;6Zl(ixgw`O6{y!k{lZUK|wB-lw?w8N1cTMF?1 z7C=O?uTD{>*`gBT^UHu3t`B39am;S+ig%opJq&i)A4%p_DlXFvET24R{!=G#hGhSA z`9y=`$){phVCpZmi_nw#g}B94gy%G&_sG0})+!SEo1|9stL^OVAJgs<1ghKI z$EO+h$?KWU;%#IO16e^J5t|dk zz;Oyir2}ZWzuObel#ms9d>#3VRST&o7A87AEdrcjmi$)MXzR@fww^1&4zbS}Ln}27 zcDYE8sx)`a=(89A*c(;tD4(F!Yt}e(kE%c$Kn18hkD)9d0TdRu#Krj@Z`t&Rc>0K3 ziD87+BVn$7Z^8Qu;6!UI83)J}6Q`JUmOY+_+=Bbo)i$=B zTU*%*Q5q15Km)Z@y}q9JHEzH*pb@S7*`-2luzgd zw>8o~ML-V52!*I}%s-c{n%af|0A?|~yt}2Xt4TWTo9M8*N-6a03e=n{oqV(7E&gTmhLGoQNU34*IkMq(rN42V@G^ zEcuJpQ-pJo+XnKMK(EJU3y{jtHgLuz5G=6xzrTgtlgW{fE&Rzi{%|5F$YN*=IRTaV32xF=n3~sE7~WWg!jZreNzkM_|A}|_tEj0(A=*yXs`Mj-^vXE~Do_0%$mEmuWC#q^g|N4J_cnW9Fz~-flmbV8@71_6At)SV*UXFhEDaqeI4}M6t4?Y?Dn48*8mXI#+CbqcZ$GEhFVqj4oG-`r|GfB06?YE z8w%zpQ=PvP`$+)KD3QbL-L0LAizlqdt4VfdG)RG35;5Ogzs3od&vc(ks)`r%_;J5~ zTJex72n$;2Ho8#Ct@$A@9Tve0#SHC&@N(EwovC-k@#%v5ahMi}o%iEYa9>5;;m!#( z+@;G-R~7Q$9$j))IM`e}c&ojzuwT6HQ>NvXQ^t60CJLxo{nLcGg{@jz_A|r@zveVg^91PdM5{U z4%RB99ZzY^v(rp$W{dMdy(RZd_4an_W^OIw4;E7#+C)^z_Eu@zwj1rT+34{nZ&X&i zfB#VEh0s;aFbT*UdvW>Kv7Rc0Hh~Ya?xv*`f4Um=(k{i&r_}p>%_&*cVOwiW)hGWH zhW?CCPRcKRx#|k1msdW93CIYRmYITnvmI>G7(C7FjjGxd(-!PZAp}yrcQP=@aP`^? zD|`qPmQ(I+=~uGpe|P1zvhW`{4`d?Ny{)qq)U;6hKWs&Lqdj-F|a-`&Cb-?;1~kM`v*_8ib}oa5EZ)>3>&|eZdx`pCDs&)aic1;^rIp=noRXgvJ>9-?M zy5d%ih}JRGOPUr+ohayr>Hp*#j=NO7(CmboAcCvBV!~6TzlA`v^rQlmNau;Qb2KM8 zl8q+jpul3*+FMQ*{Gz_n2zP}VDU)u}l)n}ry~u&q+(aV008N{w+2|EZn%HaCRt#P& zJ`s@h6JrP`13!I%f-hcg0*~@IgW3NQ?^k-~@$1|Fi^xW@7s|n_QhW%EZ4EcNi3!Rj>l$b&1KyjtXIij^SOR_vFrr zVh$xnECMIUBc{ide-)5NxLVrgf$r~GGVv9duzK79Xmv2Xjw0`%F+Rkj!hJ!122gyC zCK0C-@P*A$tX22&Mgl8yKhb^CO?H$y8zFG~*s*~^!l2EN)s#i~rAKO)L!IjWYP@sS zee4*4TrwUxhwIY2P^Wp#-(4MhojZpff@;x8OY6F|?r(~z9cYdyk@eg*Lb#?KIsm$u z$drbxDs)cPU(*aYxW<|edCjJMaQh&-aDjeg*e0_)b}1=xl=Q^XR{x`p7oHT-v{O>_ zeMzAyG{6l~q|T)M@hp|Bh0P@}m1ZYumKY$Cr?3*zub8nhpHBx+Jq2Bex4HATO^7~n z5U_{|;2+kEaUtwdf@w)Mt9BT*AsGj_IgVrm1d=){{waeP3nr|^Md+Jrb2b5h3Kj0yq?%lf&`NRJt ziAqi)q=tZBB0CTut@s-^eu?b7qQLEhK>-Z##5G|O)A|!F(He-zPWRf$YqQqxJ7wcO zE%^P@?msHxUwXX^3zCj`>q?;;o6*{3Qdd3)Q@$OHU?vL83G7~ z4T%P}0vuSX3PD8*K&U6cTob^NLUS~8E~yMHUoeFcD!38%4#N`FB}mPC5IaOhn6$P+ zY&p^Y|7^27cka&x&mIt1GLaPqb(=g9dbQy3LIlRB%7l)~8qn49IO7gUN-vXx--ql= zsKc&z{R|C7TqHdo&LM6;zk7)HB8_EA>(@*a(x7Y5($f5okECiB zz?anCjX@RTZToKr6z-eB(+Ef1wAU>=229`KQ7-O;0#OR3s!F->4X&$jb8M~*_oqF~ zIUt^4 zQosQ-Tbgt*!`OVI1X}WQF{6>~d-miomzA%~pBO*Z@Wh_I&j)xt|Gr_bG2C5@NvjNS zsXHh_cTmrS)LG^Iv8@APyZ=7px7as6%le|{_06Fm-si+Ya#Fmb{=j`pGNNfq;s ze>(>_zStsV)|iq-uC4-kH@R+ZuD^xx8-eB3!9M|lVq(b5W$$tXN%u!6OUI0F&dQ^n z+J*mH8XTK=dh>p`2Qwu#DUxuDR<9*{VLJ>lxeF2pdHKqUrGJGfZd0eOadXY5YYfp@4fi~@LvQ+A(a-XnW}0eNabu=1Q`*Acg%L7 zy&U;=UF~+ty78g9J*0Mk9VKbDkmKSnAhd`Jzr8t;LUfH#+4G(-BMmODVpAuY34zee z8sc7)>$lEKPVgM(?~06vuD3(0;=H_el!rERzdvBFB84|~eZ#y$&=VXC^mdPcis#Vj z^{jJDs(hG;R9nNe`b1n?8Kdq|}f2a6u7%jIU$4Z{UC-71S?xSE$ES zGvzvdsri8%B|&oD!#ES>0^`>zjn2*G#*m>5O@ej1VF-sYd*Xh8axS6*OBg8DcO*@w6=Vx%r`9O?oq5)b#ipBU?@ zrPzBbbl*Mjfe7mPIiTk-TsGi;r9I&5^qVY$@H(-P*GN6#9xxp~kBlruGEN(PJL4U6 zNO5->wQwY*p52`jjxS!knEw35f}HrE8E-ah{^8)b?;w;=Nc23B~!xf;Qr&C*3qsw!G^6e_hlE|J% zK6P{g5)`~vsPt97MT}Zxp43dgrXqX-ads@JRm=I8gsN}}<*rycW7Sqb#)+G`GgbkU z9~I}oKKD?*NuSoBMeoN0V|e0694=kdwyCvssDO&(l?;*z%)`6UIl!1g!QiI6BP0$( zllqoO#qOhH$~Z8ruJ|6#^deUMpE*!>Zw@4IaVJUB=z&7Z09(VTdSAOOhf=zX?6M^| z@v9x&R>3D`@1yk5?UU!`80&OnlQwb0cJ%ktOVa|%Ek;)k#3p7U0TdkTOsS{?d1~?A zl@}>@H478fbKoQFEO=i+O@9*feox;;L;dB_2@xx%wuaMm*KZ`9+I;}EvHJ)ArLsKS zSv_Xlb{w8NV=WSOZ(kr03!XXn9^0(L*-;3v^p2pcg;rrhsU;)zhOPUKA)b4@>cQ}$ zdrmjIxEY~m&i!GixRBdq{+)d*;YK+>>ZaENK@6g|SKfPPA@qSAG6o=0sO7a<#PN5+ zAuBNH%B^)vr0~@qBcr=%yyhMfz^M+lmeP@fwAn;!(VUC|U74x3Gc91;2&&{+D{alp zUOnSxPosWct9%=r9X7W%l)oXx8jEg2gp(0D10zesJogd*2rPAC`tvi|i42rPcuk2d zwe=-nAOBBWdpnuR0Xk?n6RwoU2>F zTd6PzMiRB-5$6_|d9gF;UG71kGSW7qs!0c6$z;o>hiuc^Md51tSkwz(<-B#5Ax|l_ zBpfE)y7l_p3vSRcm!!)0qlwqkQmh%c!*{5JU@<@Y*{F;Z4T$vKgo zjvJhi4&Ybs>^W<*a7{VaAxBs8s@c@sV#Zv%Zrxp?sAt(1PUPh^GG0E z)FVR&DiJZ$=I~~b$*NjzsO-Q_`fWb(h!MsW(Lc&98ZyR#lIBeFD;#-gl&9`R5n%2a zw|J*U(~@thlu)t)z)nZ#H^KcLEWy$O%wm+R8|CcLU0RB~Q_mThEvffAR8`S1P-l)| zkIOYRRP4!j?{-an0iqa*^OUK-6mu?@aGtbNg0dkAAF~!VlxVY@xwt`GD76a3kB$CU zVD0^9Kk7d(Uyy)N3O!)({!0u#BZk@l&5NQ?0tFx6hDI9app)&*MJ6Ec22xaf&TRQCCIqzWna&OZSqF568N2K*zwdg7nqwlNe@qI-$OFA}y zGh(Li^`P<$Pf@A@*&je|XLWj(?9}B-8%Em)K^CLfz5d~dpD{fWMSGPp4$(^IS@jg| zd$8Nrj&Jg_u<8DNZu+kD9n!Oyjm}NS1MabZIIF+Q@wr}~8VdITAazpZifD}wEdw^o zH3y_rWm}7a2DZEZn-48ef{?N(y=-CN)F5)vFp|o87fdiH;InmTwXiReBIJf_Fp78VO_=Yf7 z0<_-dCfHx9{CQq%B1QN}ND`KfC`SCsK7KSe*vE?75h}@c>!fCd5vB{akl(huVgu^3 zauwu%R9%=<*l?<4Ku_n)e(N{~A4B)Mu5TV#2`wJMhs5b};Lg}YA!DS@DY{QF~ib{LHxhbBG9k%%haZHh8o6%RhF`QC#A?IPyEe_9!Z4A#ufUr?nM*$ zZ)ayu5O-Q2Jjs=UtXDp>`ptA6(f~cTm83y4Ouhc2Qg(l5_K5J8fgy9R#V<{z%9HPI zS1ER$XrNUvi`p9BK|ENx!r4_Lr?k~_;|L|Wu$M{x+*j9;EZj_I z%wWP-8XcB^{ASi7{W*RxyAPEELY>AGmbm<;#Q7saM*7T#H z&e4)jOTD!*kXxN~!&1Kt75ZvM<HXU!E`NJz|o6Bu?&8`Tm7@ZqzysrO9gNT9>5AAN>7xr zW@J|$h_rQ}P_KC9tmFiT{bbJhSZd94y==baVncPLo zK5OM!BpFOpM5kk3s6rXwMsyhmI>PM3L+Ivw=1~Uk=$FO%hlCPHLut9A`w+1^Wn+gj zzMu%77x943RRn}p)%|R0_fCXNQounF=FYUR1hs=uUb=^f13N-bDf>l)vgbiLh&y9t zdvbR+0>W{j#`WYAVZogiJMEeQwA0SBHV0l#(gI_#9p=|!r-Uv#RB_U z@1vDGZ+h8DN?(YG<}xzXio}m?W{WG)Fzx_V+ZQIS|a^h%sv8Z%AI0{v%=#OH)qmW6*Qd{ z{V;jJS=V=-4O&S5pFdHVF_n*j6DYroPFPEqti3!*HjSkKSYm=n*p$yG37`Em>)_lP z3caNN4d6Ouj_#D%E>F%LcOEUpLy@?lfUw;8n;L=t0h>Mi*Mn%L#{$U1ZWf}*Gnt!v z;h}2Hf(jQCx-53Qsz@1FFi=M1qV=7)2{hr3j1H@aUwk-s&sm1iqXko)2Ou zLYF0!HWB<{WV+y7-MWg{c<70qcl+SX?!Iz7VaVXE4C4_h*;_ za>F3ANsWVtYV1vJ^4NC3JQAT1&JF@QQQu7bctBw~jQbI1$NxZ;v|~O)6c^5|*mG0k zhmz3E{UJ;rqQ{*h`dD<=BR{}D7Zdn0oS(IgQpmr*=*FGNm)}q$NzInrpG!15U*lRr zfd~1LP2Ng4CJv1(2QJHh^Je$o7A~U9hPI=tf5qkbnd73;gjpUmgK?X!&;gj)cA6Z2 z5*a~2-VQ&d_uGK%cDV*54=Fo-umi5(trkpGaDk=u(4HG|G&2a)xIrR88D-z3i@{7aU{<>FUPXO4e^Y$6?++^8USFM#V;TkL!d zoGd!8`A;vxYg|lWZb`ax_Z!GJxF||z(B71dIO2g>d1y|NK|zWt18*y4rP^jlQq5gA z{;C4S;#q(jG08UQHf2=Mh2&`NL0WRBD8BOs>yATe{ z1b%&3wo^WMJ3}3V_Bj>hy~VW0|NQy$Lh+{g%Q?9z6ArOBeoCE8nIW~OQk`oJQqn=W z1r!qZDcToE=}zm{)x2yjQ}^c0JDAlw-6!n3eo8)VTH{%Z*qJ%mM2mY_=kg;--aS4oHTS#+5_y? zXGB=4nOPHT5RG;=6LA!VFYT#W(p@^3(ep0wHxzw>Xm+^BbswSoj$g5?hvGt~xo_q< zy_njWL`ja!(>@+ruP`@x?sT`xpIDi5lA7k|FQAH_h&!-AJ_M#6Wj7W~7uv2D-ttw- zxH-uUI&N+2MI#`W7l}F@>l%TG8R|(nC--rr|G5g*kC5*m(m2CUV|(o8vB*7`4EG8| z3Qg(bzne=ihKv6g$z3p=LdIbEU+Y3Bmp*~*`CrT}Tn^rWhxnptvaJ%gfZc22f z?w{$vz_8CIgzK1T+^iLac_1C0lylB%(V%Qc$aC90zpw(P>%c*(Jeo@Ku1GBhD?;kX zUu8HEHXY#m=r4<~)kB-^@A%mE=;ZU`8S+ga%*yqo)P>Fz@Q-4r4fC7VBZzuV>dJ_r zf{q$Yz3ii+O3AMHLhO|r<|u8e?AD$N9N>`qy@G5}vsyCn!Hx*YW_E*)39ix@=>^f**9nB&F4gw`J!kG5-$hgi@ z$Pg4yP24Omp4NPP6}@k8t8LuE36y)=^)bs$!Pc{E7Iaf=#$(5OR{dtXs^9EC%;r6g zEj1KVc5wG5xf)#0FG2<~a=<}xV1Nr;M98%@tcs1!_11K-ZTQ&MuDQJ}^Xl+HY=JDn zNRV#{1yh0?(_-R?He+1~Y$D=#lj>dIr4JyOjuhd8)S`AxZfz*J>8@Kdk`CSlPC3vvs_DEf3EXJV-?*2JLg7|yW;|ppw;LS3v@F{4 zzQdANQD@?N9sT*lH0D*xsEPjLy_d*eom2Vd`oFHwQ8Z756d>#y*1#g`1GWhkALB@?cl++bQ>)5 z_AYsQyMC+5LmvG&e{9lUAt!8}T)X4(YPZLz=2Qlo*qQ417AfoEVlw1$0idS4heu)8 z^E8r5+-}yTYu6hn%XuIS(#w_9mx`Zi~7ZSKGnl0Qjf*RNl%Pt)p56j$MDQDHe~Xh6Eq z&>$BzJ?B=uU4>3O`sh)I_%`sZK&BHHPDadhJ;R_PEndqscVtk2&5YMecLmulh-+K? zhpI+QmYQ%8UN|GkM{Fsu#;2IC9U3syF!cKXsm|SsEJ$>bV}C z9gwqbF#q_Ts<6J#n}JGIA34c*c^Lku|MQR1)xY1T`YY-G-f!ps{Hd?+?RIZwSO4VK z|E`Mte=qRgJ_FNZ?`MAl7d}WAU`daqu+vgQJ&hoIMMotidn>Vyo$8ZmT_o;{mV(SIl}Z?S23z_hPSjm^ke zH=aD11Z(^tS1C4W+xBPHt&#uQ5T(ane%lIPgjs8mzzK7;r@fA*|B<4++@ zg@92%x!_>~R;?jDWM?&1RbA@J?I1r%3>LZ(i~^{yHgM-gwC!w|)V?%;UtjtQ6WnbaCN2SMbaZhM)K(cHg0k|5PoDyiOeIZl@Y0q^QSvC5Q&>mO zV91k32du1INOU=S{(Q2pvSzqEc<>fw<*&djGswOY8bYvW^7Sn(&K^w^aH1dh$lSo3 zF^-9`77ZEoQ%C9T0O5S$xcT~K;9>xPBu>KmOWxS7+8pw)qfsz9sceBkp;5@sWS)~2 zG=FK#mOSwF?c1-P1s}?Z3h*Od-ELp$yRP%>-_B^F+@p8z?JR`_SpIj~Ax|e0V{Ffk zoEe?-9=(lKuy7cWz;*x)8Q(9&*qAb_GcajZ=Zc8`T-a{;ENnLLI&%rS=)x?SbSQ3v zzMB}o1TbgiA+sR$E3FH&p;kJ6oR?1`HCh~W&R zNP-c+#@wwyMj2KQ^ z)q&DGY2jps6UM`bU;OyVPFMS<^Xa$!2KjEhbKW~Qx}RO=>Kt(^e%RWn3GIhDEzKb{ z{OgT8dd8*raQm*WuU3Z+5%$4bx9*?t$}*{F#l6GP$G&fHa(mpnPoI>G7q?BpcyB;> zT=0-3m;oN-=U2N+}U=~PFJ$k&G>**A6;^$B_w)A_nYy1mYV+9CE0B( zERyHu466EWR-?8pFxrW6Z#NCqLp#&ErXLJj77!QzQO{ypi&m|69*dsuAys|QI2Dtw zpCWE;!=uEiD~*mfKK*WA)dtl$)II54 zP4@}d*f9J9xg2@s9Y;P?#}9`Ydt+lTh3lAhl2d}F*(q-mH`ICknDxmbCaqn)+SJz8 zHa;%KXfv&z1+?3z|K-r0TArSYhq@|t>Si*T8RCJAd~^_Ta9*4t!Abg^oQq=P9PREK zn$*eL{rxp)Gg{1LT_!#D@6R!P5NO8WP+=jnVDGyzvplL#NR(5Zh_~W ze+4w-_twW!3XfAq3#{+!OJQSSZSDW1qGE%uDPHskQF*&OWPELQV&+{YnH}`$vXzxX z26mPNVRHnGkR;|cy5K_rbmQwob?EYjkpu$dn#u)g!ed3E zuL@7)JJ?ARHMP#d7o+zwm6+Y;7Nhd(kZpK-O{m7riJ2idS|J)Sn*31ik{91^x)Nwq zjgOx^slr4q1b^q9y;HXS=lKs_>@^~tPx5tmehyd9F^`NHm&GIE>W&{1ooF_7;F1+R z9$R@37C;(Ea(1VR4*waOj=kJv_#ah-&Y#EsKdTya(q*EfKkaHQ=p=t}@wNrYHXQ1* zJ|s{wQ1ZKL)g{)*e@dSuS1~DK{Orp`J0k(i@zvL5&JfH(n2{c|nPi`Dw5{rF>HlT6 zL|sw6ocRL)YW-ng`I776VXO@d0I*8ps5!C5`drF4xBt+psG6koPu-R$U&5Ay!N3gOk^ODt|0c}ZEjk>d-B-K+*)pXYX?a5LsKv^ccgGqUnk-py#%_IChvMV!wzmK1 zlAt^-C()%kQzg7P){olzcE(#(r=qN?Mey}a+rh9p= zGmN{A6Q>i`+NMG0vICH6soJ9!?FfC!oE=76s$WY#M`|azqVxjLP8wbuc6g5EdO{zS z7}2{8#Xf(WnlJgMcW9ubq@uhHu1_IwNPHP)ufNLkq?$X<`278{OlE3dwy3P&9Gs|V zTvc!BH2r^dyT*T8xBtK9N8|q=4WRD2beB_509vCwlVBQHemqQf9X-enCG~-m#AAw5B$)YZGD5g^=!u&h9ltAQU3DW}YQ1q*)j9e& zkk&-uc}_5F$VLajbP4Xw-8}G{nL%?B2drEOU7>f|_EpE!>SoK7#_~`3jh2V$*0qP- zsMty*E$aII>7`3lRJWN@#J#>;eMo=Se4#3zGW7djZ7dCK;p?y)l|4qKb_F8)uvgO!yf zNoKvco%qqSf7rRNS`vOmc6`23dy8N7yYZBxeKaUTyZ(d5bUg7wb%{a#R46~m-F2Fp zwW)o$^QR-1kuEyvJEw&!Wiu=(dE3ap>Px6sfN~O<7I(SXv$S{r4wc)$D$c0@xvVT( zt8|09JxSNCZP z)q-}s+0v!uAT3F2Y?t0{9NlMz4)4vka_Vrir(vVYn~DGWZ+z1Z%T%4pYury3ue_5J zkM71Hc7eyxp)0>LDggl4GuKG}*FK*9Yab7aWn&e?7uNC9pux?wzliX`B5R5HS0 z1&5wf`qv6N<{XH=>fT{i-qXJStg2&9`(d%UFO}*mW|R-9IxF%y`D69&TKgH*pT7Ek zXEgph=T-m0wjmEv|NV30I@A76_SL_jy87=5<3C;?VHljcvEErOryja%RsUqcT6sK9 zRli?HD7ascl>?M_(U?0U-CLX(mSbbe+_;&tau5CI^LEIVjjQ`Y)zd~ILxGd~i2chO z`Gkju&nTZZrW==vY4%x=8_0-!R{4Q3e+aF^9DG8Xe#+Q*??A6k&}aP#GV6VBqgS25 z@L9v(v#W+DK_|JQS%R{{pLQ%~-4J6t-{VRN4LK1GEmOwKoYsYn*gxPrY5QZZqvJdK zg@Q>eTB2S*UxN$U>+h|G=|n=+7@N8m;Fd^9h?j#smfix`r9=11iDQsWIISW2J3k zInVdIR(FW8N3H3qp3QFdoS}2GXP|1!oY|8 z@cHw0V*Nsc2?Jlhd)E!tn~mBaBc3&kQVnUfMBp|)+P1yGv9w*jz9ln96b^TRBsEkT zZC)k~k50MsLjWL#2DbM08zLi}d$;YHKf^E7l>0{I`LDpW{zFO0R%+m3a;#v}(J8b$ z)jGeCLJOko54)($BaK#V+_dQihQ~6WLWXHce0yvRJX>6sETkvsxuvZGbfpnN5NZx#XvHuz+Lt=IXo&#!yO!+goIR={uJ#1v7 zdwzYg;apOB)*7M5Vly1hDbdGjFQnhnW3BPXmKz@+8U=GD*=@L%aW7(Z)uan2{mp>q zpyA&t5Tr7)Q2_Vhb_7PfD7XVsYfT!|IQI{Zgc0KJnJeyVr?lW;+i!F#u&zu_WgxPYNBXIa6-$(rNBQk+ zRKqkl>idm~Ajk?>jt^#wz+^R%cCvTx-qzu!%Bqw)Cy_p{_*U4_&7ej8Jb=Kh;o(~K zl$6GfI0P}roFU%~Nah#@w1wKdQ4j@u^t40p6%|AUU--;gKLjN+7_0@5u|P44v7S3MlCkzdI3JEq zPTJ72G(KLKR?1jt0~qUWB;p3G8ZNu_>Fmj}5mqV!7;FZA}H%I}(ht=lQi(3($v$s9ijZAN51#ORI~ZVLu2 zC!WX0=mi!E6s{z6N`@{2)J@IIlufJzYyOA|HdzjWRQOstc= ztViV+`uu~W;5ZC?1Y;{jFo=w-3ktVDUc%3`$nq!yHvyd2Z``P|Eo1FA&L^n71(b+< zNViINKGx9G)Lf5g5L{h3pn|o-DbZjOmIjsH<6CLuZiFYs)*bI=x}0K|&`l#!)7->Z zN==^i_S?5ju{R*@4G&fqnE}kWPQruWcppwiLg1ha&zxHe4kusy^1Oj8bSsDkoS-o>3bUJ;-B(xw-k;u$6EaJ3+e)hD(yCs=~aivyRg?9vC}Th)6b+%~oz5rvoW z6flVEn0M|*Y5FY-Cmd>GiGIo+QwDJytMWICxc>Ka%f?Q9Zt9nwZke+6K+6;&YL{U# ztjKz@@Zu2IwXVsiWOPN%p=JR1@|;8=dMFv#bMLh-0=jJs_3Wtq8SeT;Mn-ZLuus_( zjr9^S)V(etK1an{Dg&YY&SO(Xs;&%NepJdMB-(*eMDou&r>W*F{rUV9I|O~yF)o3uI-VLS z?=7$@aGW-+z3|x68Nz9xl-yQA1b+$H@`d>iGp`hyA#?}@lRBoc7bymIKe;>?nU=hro z;O(iWyqIIv$DX7008f>{F3aSCpM{GTo0o^6FO{1+xp#GKZg25s1Rt#n<2=NxlW}P) z>XzcE{f901JLYx0*|S#osNCU!n%W&Z9%I#WexaA2K2;xFv}qAJr+cqnYmOf6iiTwjS18J}L(t~CWlPGp zfbfxr=5*hp+Oy91@#E$Bl7qN=vL1Q^f?{n1xR>ETW~P7z*YFFSikwBE*n|a493Xf@ zHt(H%gVYrZImj@cmG}j8i?#`#z2w>}ZV9XbntY22w}j!s(&bq*eED!?Mgji*zqRXS z3tR9HQp-AsD$jr*iac|?^~_C82lF0Qc(&1K*CJvKM=zOa6c%N{DO?q*1LpYreBS|{ zBlPPRxFz!;Hc=Ko!xPBo#EG7`p!sm>3W9iv&ae{J3_d3K}Iysf8o9p*m_PGnhLthG{mRyK-8F=#p0+TKSZ9H4R@~CZM)g3H+IeJdn4UmNVz*SW` zbm(xHt6Gda9f6m*EzX4NwiE@~=TM7;a?zdKJLIXktR$}neC{oXqU3BYT)OlYSW50! z!?az?GIcId{z+?nc>K{;?4qeNXRf6zdB!L7%$I-wFTM^Ek?RQEYbfa0hl1aXVRZlI z=_Pg2*iFt`+S@aTyi|Kf1Ox>1yztZN-3PcRBlit#1K)6mfpZgT+=lpEL{CX*1!UjX zV3(J*)pNUJS2g$f@|_qEK-W~dmHeO_z+Kx|=!d_bO_ z-hgfzNv$_J>6{>fZtTAIKr~IDG=QFM-pmf2Tke>0`X2c^FE7uBhjc^}C#PNO7(?tQ zf$*rCEAm(wmT-bYaUCDZl`s~^^YI?OB}+Mm&FvOGVeD8Ho_8Y%pJhW2_vFegU9~|f~ZoToT z{fH&Ln>T0KN2nbgV)&GRbsx~3Hh4NQfZwPM#IYIASxs&2+B9976a(F{LseX+YfZ%` zgzd)yI&zP_K`Yru~8kLQ}zJG9PP79w5&(e73E;{88PtQ|hK-!&FQ64RyaNwQ0 zcM0NuiH&j)_YC#`fBQfoSW`iZyOu2bLd+DBQRIXXmdB{n7E5jQmi(|eO~P8(6uG@U z5)!=#kZU0OYJ%!5_{tb>D&&CRB^|nSQNlC5A>c|4d0YdMda82;(kTPEg zACTR}cdtp~#_cGdnksK&?Tf+N=)T zkvObE&$)jH-H3FtNs}fSiAvlAb`X523H%XuZg#(jlTF)N->Z>#uxUDNZ+Tk0+njS; zVe9LQs@#~VaX5P$o#W9_zHgwT2%JIwVfws-cQq&T=F{y~^*v^L1~;o5l z?F}?k(jjqK=L}?88XDFp++;E>1u!B@J^J0I46BvR_H;RiGxtX@xvKj9<<}X(!-o&| zY`W{>T#Z>tUfhP-OzGrw?(20Z-mGMvT1DSRunkf zpcPZ$v4diw)Z>ds0nAXq&2+ca3O#enc5SXo^|sRK++%xHU^wGHdB7xNBe*$#oj>1? z;JKQ(c)+{zXHn-z7}A>%j;v5_fSTs2ZblBB-?MMu zmW)GJu31xC_IZN_4U}3L=v@0z$>?g~k|o0ls=0|@tzX?g=w;gPIZ4c8AvP)w$0@XR ziG`pM`?qHY<-|^_DIbD3RKv7Q!|{yYS=_dRzhy6Q3wUjP?{l2;j`(feaVJ?D5~9ig zU^Ve;Xjp1H-kn8TONPTYpmbn480k>TaApDiFxV(4R)6glnveofOd-Wzw zR&|&7z}*1h>N2XkpV9ddtSYHvkulH3l}ZABDY)g zQH^=$DW*q698j|vNgmd(%tnn`QRsU|5)If@$%hYD=zBh(vVyH3|Ai2zL1e1g&MiC_ zl?B>)F%=yamYPTLP?(le@Y#k39oWULi5NkC^U&}tC-2g`j2TYueN0CQiU=Y^mwuGO ztprk9810KB8u7Rb{#?V;8`ZFQY`&mpEqvu4fKP(<#>oVfMmfGyvNRA+%5;`3EEeMDlcz>gvoz(A3r{&V%( zwO1cKYDLn>jyeQcT~0E5qSaJcGtYXz>Xhw$Hql|mbQ7@W>B*X`X zMHq?7Wnpi4KWERKt8ssHvuRFFQiM|43a9VEN#~}FBkx0Q?|u5uvq-fP4AfOOWqf1k zb=>3A%qN$;rDq(0RkYVP;8q=~;pbyg$1&U=uu zHNal+mXq6*efTg0AZ8I$K}Cw%1K<)9Vsre9=hxq!O9$n<&!S34%lP6NE2`Y2iT|-D zw3AXGl3q;OL=MEaf@cIGt1xZ&?#GWGR)@zNP*QJv!PjlA&Oewc6Bei5H}wM_vQ{%0 z)Hub146+_|vHiBuYw5he)>%)3io}+t9NqD1R_z54>o7oFD>^k+sJwnYN+_&aG?=!N$ng&&)6IJ8h_H7uK*!^nV z&fnbJLErR|a^Lt}Ih@Y>uxxjPgve7U`rU8iltW%$O4`d^F2~5*fFy_Gf07#xPdcYR z@LPeVo1L|F6VCa18kXnOtQKc1Hx0j5$E{n$GPiPO4P@QJVXUSz&SR_Hka$ zumg++gX@%CaLAt`mozN%X|1YSk9Rsb?{RYi@J)962g=cB8}u%YsrgwtJcV+et2YSSIxr& zO=*lc?$bG6T(;g9`r3M~#*hwS+^Sd(>wa1c`VZi6uICsP@5Lva%J0UWIdcnWsx0f% z%((1N%2((a!C-(Rz~fWZRCkVdbku-1-GGnkR!jf#vhni|WV-acpx%G^ zm&QDT!n8a6JxhOQE$Vgq3 zh~44J{2! z8W}w&$kkLpif_ce{6efLOWNGB$8Q1^-~_p_Fijg(Ut^wv;i%nx|6+U+na{=&vMZ0N zj{JAo8?RrlD<~)kZd)^duHLQ(2Ac7^Lf@?&dt#;~_mdBq*RHtLOY*)C*t2KA$X)kd z%2A^KzK>08Li|Ddn9eCTt?wBS$E7T3G?)9yHgjZtGu@Msm6%wM#8g)S_plMWW;J8v zZyu9tM&Ri_n+w=Dd54ZI`~Ibe;8(z!uoHe$G*(fmWny(7%xdZ46@de&O4k9%)-*j@ zS6*S&s+wrcV}k$u203z7R8(h>=nd$Thghiy(8htgMR($Gu2GI#0Xwniw$+qbi`NAo z^uJ%PVZ$~2ZTgCXx$Ar~-Y-W55qsi9`m(J}xy7j48o8esdnh$UqI&zlD9*RFTI` zrhPsZ@kv_h&-k78Ug~X1mYSC>MvUPq-KG%k7P`5~ZGy+?3Zn1@ynNHdJ}_1t%0w`KW{HbABn z$;0?NW6mvhO8D9Ux3K!a%K%9ZM>XZjSjkla^t!jbFnU+-hLB=Bb)8R6?8-p8hKW@y zb38XSR1VWMjT*T>TIS7MHD?~I*;OkxfWYh#m zo64gg|LURLql5isAZR5%0=Bp8Ia7()zkl<~3rpX(W%z-ijKkq%+WbG5H*IWf*yQr3 zZ_3S^*I_+TydOVnkHtRe~6stLQWZ3}d~G1li@}*;3!W<$F(Ftsn1W{ciuVP3ns6dJcckVAQHrOU5qD zQy;`RH6ST$CUw?SP^xXf^W(~c2QB$JSHZqAwoMXbP2gTo^qTGiug>AHQB%a_cFv;# zg~2qGikG74+fujq!1aQik+MQjRJlCbc`~fuIwjTLc*9=JZctF=y?eKrXcM`~Imhi9 z=bc{iDwE8Nwa^6JZjXWgfsTwlJ_8j;2Jm}k!5B}(*db^vOk2zu;R1R%#^(i z$qU?B;M%m<`m=k$x-QN(g95Snvuxpi`XZRw@8D>HyJXzV0%;h7Etdcfmp{$PCbyJ8 z5YVIo%(>XN< z4o+r#P+;I{d=Y90`~V!8IZyCgY_67QSXcbx zZt;qr@6Nv`vdc`0*2)nvvrEYjd=ai>WT>!FG9RPgSK>w1vPSB_E(#ymSeNhKZAd!z zEbLK`R8-L6OT?3WfI^Ik8gl! zUE&_&f-x~u21HLj-yBYjF`J_#XX(=epdo~>N%3>`jgNBbR4;Vo^=f*XP+5fjBPZ*? zleKLuJths;T*&1z8{tSKIB{@?@WC=#zl^t1W`N!l2ElQz4OK)YJf;eaJ$dpv8!v4h zopjC@F7Pe^k=)PJqXdIOi$Q}8CpF4fjcsk)xss{uF0le@u z;gDvmAL-_%Yh=_4n$ll*7v!#@KhOeEY9)CFYI6JqmYfmVxQ^ytcAJ;c#(4&=l1$3H z>sv~Odi?u0v>GO8*kZ8{6j^)nI(0S@D;G)v7Cfr>2|6zd#SFv7im6~LGMe)oUCfv= zzMk89olgL0eV}9MH)TDV(u%rqbS`X`qcdZMR-Hy|l>p-j#`18(R)u=~O7dj}}PQF%3D{E@J2kC8aR zkH~_oav8LR3U9)nn~JxeKX)!N=GDLz-&^7n>jNsxW^T--ecLU~%&u_unc#2CZdLns zhQcs=gLgU{wjKRF^yOYG*>8+ruknpz!HlW(L&;D@HTRP`BwH};C2Da=Ky9ClwG(JP zoe zyU=xhRkan+T|uB3Sc(jBMF{U+KJ9H zX8H)5wtXP5F~X_EOm5woGkv5h275oiSJoMOxG_V?8VUfz`egCL5xW(8%l9wy^b7?} zEHYk0EU3QI~cMZ2<_w&XPE zTZcXDxi~5h&V$S!9}l3_r8?;W->_EQx-Xa^{@$R$HE>%V?izB%qSdpz1z7FzMJmaq#mP-@KsbTxI zFKH`Y$A7*HYA(330DXg9VlN@LglZZ_9EpvMy>DT$Eo+0bm9NemczW4?a~svFxw|@- zrm}7a&ntvf0!xC3i-GP2qn(|=I;E>wxNwY~J6m`dab_W;Tt$lBd}iCLgMyk}to*r5 z5!vE48SwJs$NjD)>gtxCTUOqUo+Px+bHC8T&YFVrVC@pAJ3^Q$_&w~{wd)%Goks^T zOoj2XcVZm{t~Ohk7GJ)1?+>YTHf(4B4lU(%9-VFC+MWlqkAr&M+0(DZ;G3J|Y78NC z2&4>TCCL2d@8GUo5wPD!S(=bimlh7Vm>g+y=9A;pW9MJVlx*IPKEQqSbt}h5<*(X1 zNek<~1WH8nfUHwX`zi!sdSj??d(*`y>02CgyDj3@`T2!*EwkE z5ZY8-eG9UCwh;94{U{}M94_{kr$nD=)5a=kPNUTGzb0$u5X|6x>j#blE}e2~bHt=q z<1}^B(sF9C**V_iob;pi%(3~56e>#XP7N6cdau;RNJRlq=|is;3OFfS2^f9`&d&9Sd-8m|HuWRW!(koFlNFeA#e5jElE^4D7NH9mdt_`q zW@2?p`VUw=KI#S^cNMsz-I@H8Bm&bY&7$W1^Hcsu zb!Q&cbN>GQcgR>HYsr!#AyU>TqK}ZRjD3ixL5xyDNtR5q6e+UAXhX7(^+QOOlwnF) zh73_!2q_fudt4vp_xt|t`+M&DocrA8+~;=A{6W*_^M1dUYk6MJ>v>T>t_O@9xN&0x z-YXC@k`&v$gWZ=2&TrsM306#`4%E>7LS<2BLQ0V1pO@69ifu%48cNOxLAfr`-LMJy z@tYQQI_b8roQUXb3|@Mti1yXL&GR~6#4G#p}xX5aa+`Y|u=XG9D?e?zrt@}cqO z8#iqbPwOZQ-dIW1^NExu)LfSlQGIl|ZF<&Ax z-KmS@1AOzwnD%5KrZ>b0;67$QovLSBloBW$9V{-nYb}UmL|LBfvrj*L8ztBDaMUxx z@{f#o;%Lxg9X`Kn#0epl-hc4G1^Fn+OWEG)Bp6`QK9=t(vItj8XccSM)@D|bmZ6Vp zLX4?iPxmJCADvkVB*l$4khPJGPjX6CD+9XR)sMNE@|`syXvJPq;hmrr5f-#ES;BCD zcV)zElTZrfg(0ba7HiIwyda;j0~N;MuLzi#N`;qL!O>$6!N9~bo^6qTUIFEOzwhdf zAI@>AgkeZJDqt7URWey`cBSXDYxRAa>_6-hJJ*qAGJv)1-um;2@`C_8VuuYJj$E#} z=vH{f^Sd}kY}sW5=d#=w`7FgdLB#I8Ny5Dn>w>#YLjh3F);+)-YL~DMm9lrbpRhSF zUncpFk7$Jyng&bO3YqU*L*cIcAkK_>LR&l(1R;593IUR2B;E^RFrpY}j={Ls9)uFT zF*@j19qihVqbuA-l;y-9S^-41KNu zKSK^n@OzdyyN5s!ggny{KOfPZ^s@Ht2hKirlc4Xwe$nQ56R!z4{-(TqFrWmn_;|&Z zq(y2AU=>fQ(I*w}1O#Q)LTO7JFkE;^+T3;XPc(6r#LsPoF=G_=Nsh zH3@Co+%3qg)noo6J)Cu6Yr|9S*>xDfn@mIywryK5V&8k%Qon~%fOMHZKa|2$QO_rB zm<|_!uoRgJDKS5oQxFyITmacSonsR_@S`S$NUUJy_N3y%n3e9Lt8|radn8Cpmg2x{L1!JSUOaM;pbpz z7lt(4WihiRIMLp!){Pqn${JE4!^pyjT83ssT|Bqs2a|ifDu`mYT-Zpz^p1;Bh3hBK zGkXAPJ?NK)2$}0c>%T;CN{Q>W7aJ4E>CyUg`L5;UtlcavFN1Dn`@IEA;I>oeZ*}RN z(~5(=&yFTw7uPqT{~m$DL6<1~PKO~tz<3~}kVsEJBoYNJB?>MX9~MXmB~c4kwdXjM z#1z0kVn4Xh*TAkMg)V#fpfSwW`_R#XKHZz$W5l%Z;c-ce&?kw3|BiPXMEI*dE~9u@ zxr3u-Bz~GlV#K%q%70HmV~#xfJH1Hz$Y4#mNH#=B>{KDPM&G1&v>@+(Mw!kRqG0#f zW~qH%cT%JZEhP|G7F3Dn;Nyds0_SXXXnbO5O@C;S0v>Rrp0W;wEe4WjI|lwPqyPq2 z>Gkn6gw?&X={|=CPq+^SSqY7~gMzz#tgOuC+ADkVm)XD+0Kvh6Gu9v!c~LPeB;?gL z^-W8JzxuHtc4O8FE%naFMD7%~^Kb3i`Lqg$?;D%Ga^bs{=V#MI;_2-jh|v=`Q=C3$ zxTs(oWIo{*5~BUE>93C^_m3Hq@9sDp*8dx~hNm>7dSqMFITx_+8fb&1waMKrkL)5R zSig#@Y0hjheK;no;WI~r8*YOQr|wE2iy6yOkt80kP3Z{gdK35*us60nUL?VRSQrQ+ z`^UuBk)ep8vp1qDv!ij`ys)S!_^s=q@TJfq;o)2(r(Di8)rud7RL1|&uOu%|8_b+= z_Q}Z)6(-(S8anv_IV65(S)NXw7<9bOGyRw{*(16^n{#MV0AadMIWqSpnN132LYROn zvOezuq85X#Oh;U3_QO+Mgd|&3w2o{i>F(TzP|H5j%9GurTEr)+3=s2lC}LjWkW1AF z{C_$MAaa_xG1r z-_h~UeglSB-dw+umaD~5q*e_X@{AJzfL9Zf6ND#d3(hOVO_1S0(%Nc65B(%*VvOk$ zs>Lg^!UFd0-7B6wYx-B}NK#!FLKd{nXIN~ds^7BudH(7({-_oY6t<9IN8>qx<$O?# z*f(P}WKNyIPH!lnwxz@J_0#95t!C@4BBIzszv>LWwJ>woQRh4xnle@LcFfK2*nDpnWEcjgQ&v` zV!cZqSqYR_=y!yZ>I7@>=8m3qIci(@E-7$v66?VKKQZ^74vR6)V91e}bG4ZPU!BwS zk$4YlbD0C4vpGCG15t05nAd+o@=&D4{$8e_xXk7p?pMNj8X~iI-siQrLoxw0Ku#&H zb%;cj#l@d8@15)T0*;|ANhOqFsl!p_qoVBsQ4U;t)Q3Ixk*#w{0<<>mxV%?*Yakj* zTxdJ;nU)(iY;c4-=1&SHz$mPMRRsQIEKDS+sg&hA?s=4VRd+Wbf}X{U8Yq#Jm;9m* zi!$HZM*iBerEI^?12|(YbLXxnUaY3j76MMZlC*IT?~YXn?>lXf{q+>zo?eGfj~rS4 z@&Q)$!Z>9UIi{Rt7iv~g&#&G+#taVfV+qax9|}ea zOhi|z={q{1!#UxSwgbfJ=hq#uu%ID|dv%mrwQH}$Vu;Pb6D7LA*?p3qA4D+)s@v72 zv;Ytz2($HZ@mZl!gBx`M@!dV9gh5jQT`yl^lmn0@lEg%^uu9Z`##oqeDwJ$$QJ z7Q;@R>JZXVgm&+S|Ef+>hPSXE**iM1?zeW3K~QYVLR~mav+o^lCA27vBXqy%6y#ws zq;S`MFD>gBE}Sf~lPkm9yg`F-Cj0&7%^O>c!drfT$14A{%wnP%tQ5w~mhbGNDrp@o)6>U6h=u}3+|9BjkJHf zPE3EbH1|qvp}W|+r%AiT6c_`FlrJO9rxDq-X7{u=g zl>2ElGbC)q0j!CPYz`v4xA)VMbU8ps!{!ICvqs0Q8f8xvTc}ujoasPFo{`yuDC2gdl8p9GSa71*@Pq;s_^k>!y|`XL2CO^w(;g@_U+@Vm;*cDn{F zZ%xCE1(ZT3a;rX8R?#@q!m9TmlvzEx6Eh@ZM`b`O45(YDwc%qNI(x1 z%YndZK10Dk`_1_hjIa)qVJ^-3ZCMcJ(XEe5r@XFQSPf?hLTsb<4wvY19yz)!_oOrw zd?WzKE{-huO0)8tvNBnvh5!|GWldq=((B)8i|T{Wo%+-$(BdOjs_nF-%YOQ{`3{rA zYG|8g&3;w`(in`e5^(fdY&R#ar_U7(xD#a@v&koF*%oQ%QCkMkUIWj4#||M0;?93e zS1!S-5D<%0E*fMSfNUiMKuPYHqcY%#wTbhI(yq8uNl0<0Bj>~Zhl(w> zn-&BG&XHt;99{Qau~8klS%O~Cuxzoca-paveOVen7$Z~d$0m-iPk?g`C{)^>%7166 z0UIaM(1JtSrO1#(3^C2%l7AO@8TRaQ3zkZDMo(%8t7)?UxJlTG(1O0yfw{EOLPPXD zko+L)#*U7&Shr*nR%HE~o|vE0g5>Bb+a(54HW^^Vul#3Fi6Yelb+H{S5KIKsp@&#% zgNml1fCofRF&QYQto8GoyKM}h4Np8ZPk%+3)%$7I{X^fUKX9IB$2ppbmZ^sMw&>Ml z6vyhrVoD(u5w;nrW@3Z=cqLs%Rn`0meq!(MfBx}%sGph|h+JU&E+sixxTJ-xLr#zM z7>Kk82DT@AEWHDug{IxvW53?_GhFvXPHiH;OpOk&Fmdwa%k);^R>!{k#eT?;SRun@ z#IA9kNn-VH5hVXBA^$Ui^iCU^1z3|9Gw!37_3ilO-y5lr(@@43_HhjK41Y`xPL)AfsY((A$GaUYlcUX*U$> zN7-*Ugt|l@QN~IMdPfSODb|ow(B&~<{I33Po4HLAKNJO8PqkZ$j+z8Lk7p+Wq)2a2 zVT)%_n>tH5T&;(f!$%ix$ymmaWYe7e$<5s&8t?K7+VEE&x>5XM`*QoMLExaSlPiGs z;0w$4I>>(3V%I-8Av8!)Wj`ScpWYo7U&fIQ=mluyr?7oLz z?L)~AAhrf560Xhu%Z0B@Jdi#?in)#h@c2`+5+^iZQk<4jJ}^W0n`HC=!LeL(tPNeN z+Ojc(p>c@@=Djiz*z?V~F*q~yjKjk}TS2&yu~;9DdZJb$%rq{8VtsMcBelg{Pc(>S%~rj>}eU&!}Zggc-7Szz)IDGU1a zJL0fLW@xhkIFA|p+<)lMi2ATpMqOHB;(^eLMgOOGhjhLHbqHV*n`sY8i?hjPvw(8 z`M#Z%W<^_o)~~$NiY(=zq+H(K)%Se0kH3m38d!UdDiuePmKfmN+$T>Aalc!D zYEjiCiXNsXXhe%{qJPm8101j$^A6-Y(u>Bm?3?xeL=Nvb?( z>Ts&1agsi&C&!K--^|?@?&Woyy2^0rjNw!v%3?;3LD5OO4__(~h@l+!96x7dl!>*l z=-G1%VR+)htOcH)n=t$`FVGb$I0jzALZ4qtn+B^dP)H}X>MzA5 zPQ2Y1oHhI5bj0S`wQKX9HB4$x6~e$`_l>1gB7UZKWR8SyD~})9*!e|<`^iGTC=x?Y zGN7ah3ue)INL4f8A{rUe{|e7!Af;<1?)|)f#bL&u{sN@92mBMtR8~WAU*b=oI=*Y9??&V32h4mGp0jV?G+g6%iso5)g1mIdDsZ==5{6xvX@=N z%p{Y0&m`G}hdidUg?8L~&!A~inUxH#n_NJoh>f7!c4KL~2)aa;AdZc7j*gjGAD= z0mnEM=wWcXFTod1*gRDovFn{_-+NVHsSwsUXquKfPtT+HZwD-AdxVOm`lvfBDM;A_ z&8)VvfMIR}$e$dgFA&X^lK4-u`a_;O-df!wwtEPD#OwI*N?=z-qQ+$?fEI*^6PkO>i*2W;7{$ z`~@v1w1%_{$wovmHG%3Y?JQ4P?e5}KMQG#IkI)8@7wLq8F%_}ib@bQqx8gEpcSC7L z`T?ZJ;;oX7a|-306St-%0Ro}?_wB_Ifp?U?+|qlXT?L>f!vkD>lm z`dleR6~(Es-mgEmTx+_xum8txP=}5oL8BxX&%-o^tH#F6N=7)OU2Nsy=y~?C(0(T&N3xQea579==47g3ghuXt*RT zeWKC@p_CRbj1eh#bii`*AqknYd>aUx1*gB?+a#`)HofzHs5`i@3q__`!dxTM;c6(m zH&%Q8u)gXw>`kMz8#LPJXarvHgDAYrksek;CGse0W66|2vVGv~tmcaK@_1ZNDR}UE z2i7NuAw)oy)fAorO@lwrESOpDje*hY@85?xV)b!zRGk%f;19)8Ed1j*coF%U2Rvja6E+43yH%dRRQ-j*IlP`X) zs%uz&t|T+Q?sr^}Ja>Qn7t}4Iu~OTtyiLe=CbQ$;cn+rA>Amy2ck9*=EFQ(;KZM?ju)MS02V}ONtT*`10%CPRL0Fg+dej8r7hVLr>GZH0OZ~4#fpARGR4UvRTEU9>Wlp5yWxp{L00N1v} zsNi}(gOu~{5tJgN6EJ%&;>u%)R^OJEHUgIw59r$rsjKODhvI;g+vknntHzZ?#@hvkhV|4PSA5ucFwiEIvuZa7t-^^A5@|0aSc%r_h$ zB4$(0FL9FQY0gqOu=ItL<=Sax_+FHgOyOEa60~(3cOZh|z<8oES7^mvGzDyD1UQ{$ zYoX(d8D$QoDQ7d15Of_pE^0y(MG=eGz{rSZ>Mnd?1Q*+xL3twl_fNpWXN&X@Ipq3U zFYXwo&CyG5=rrmoQ7_$e+e6;gb85Xg$7ZUP2;;DRs=HB0L$SYK5^@XHjDn#&u4af z1)Vs1<>cgF)PMVM2dmQ|gT`GQxv&(q8a8dJ9b#XdDfKZ?j;h@=#1Gy)|NszwV6r2l`2=mYnG~raN?kxe+t51!5gas zKCLEn7G~>{3Y8}rs4(`QZbJ<^i{*VcIuE8U@`k{-tN%` zQA`(UCaf^f%JRGAV9Uh!LN2Fo2M%60q^}W5vdXytv6H?7Y8Ki`VR1)A7<;_*3Xn5W zuL|2>(=~WSm1>f(zNG;1IV9norD&yya<(Wusm4ru)eg%T=2RP^SY_yGYePd@7<*<$MkXdEA_V~8*bt2ikz*4@I4pg8 zyn8dYk9)O|tz8#9lzPck#J!S+6pCLb5$q%)=3)2FH7Fc2#qs_6&```nP%80-#MvSw zpk+v{PXx8}d(V#&jdT<`T&3fmDY5~lAS^a&-n@f|wdsaww7X<}1UneaEka~Pg;z8K zN7xL$kWTg}IfUFbUEKsGu{SYyo+2s$MhWGX{rfw^nrq7kHig+RhiP$0Af%FK!~v+d z@2G8*M!Ot0>G~3r#oQ#1Rme-CH(MPZRU;gp=pD$l#~5V={mI43W7i}YKY707+T0m4 zHg~x`Tvf3?OxHZeYFF23XT!pr)Ys-BX^)Q1SP^h5e=Kw(QTddcP9DS@-$}|)3~3w= zU($ivIy%k5vJ7SD@o|tWUCpo^r6E0#^0auzX^54)(Yd|V(vD)5Bo3kgh?!^tWq>4# zOx*+|RMY|-uuK}YJFJDs^?eIbiB4oHi5CY6L4?tRRie~4hUkw@jK&mHWT*u(n*&r) z{|`Bfy$b$pD+*V-VHm;T1Z$F4*_coj5%DU>VY<4L5V{uaH|)Xtu3zT_7u3i6$3%sq z#!Adq5As^@lEur{5-Y7klKoNA(g~{Fy;t+{HC8;1Tk}$@14ZbC#>KKRRK`MN#sFOt zX3CYzmj}tya`KLYkfCK864I33JF7)6x2fyrB*jw(5M>KeTzK70j-5W;9Qh+EETLRo zJJs%ugW6!G38tpvlHYe79cej`g}(Cmu`>aeInnYKk;ouEcOxYe<%UU2(-i#+G>AIG zDcwwDasze`;tJ%dTjX#_eQMGA`AwdHd$MvAK64p;habshRuBQT%=nd{H8`$j1t;3? zm4PmSOPdN1AUASjZtA& zmcMzjQrUzLPba@$G?`9B_jZ`RYoT03_4RR}qp%%VMkbXr4s96hhv6u7 z1_w{M7%-K=rA9ETMPTnhx{bB4axs8Gw#k$vaYs?qoeQ-Z2 z%8(i%p0-B1i+X(Nkl%?T-(26oU^qDlwfkw%E8@ti<&>{ow{A1>O)BgsS9o-}1WP3M zq9 z<-Y!wphBm(K_J-P!omr5NIVZKyDAc|VK4q(2Jxp|+qMID&5EZpM)vc;g=ObSZ920=kq{!%sBpNElQ6QlQAekk z)iOg&l=i5giYeUARN@HcYk^9(BL*7p9XjFAD)=aXSgp0CnL79|(6ooH+j{vP#Lc3#%Qb$~m0EpSVvs z`ot4aXKWhuLzfRoc?zA(ru6bhf|toI1D)MK4K5Gs5=p1H{(ykLl|ciBRt1nt`fYqAzRJ#U)-XmGgFLqv%W zj=BW)tsEVj5sdUO6<;P2?Gx=I(Yk~-xrx0LD~cT$!htd&rHO<_l28%*$4$o6{CmGB za-nXN?7iUqiAr&Buy}Hqv*j)B;#L{g0lU^%)KN)@ArAkx`0GZy2jJKC;8*P+f<(e9 z5)EZ4Jn7&Kd3?LXRUnLwfBf-Iy#cqwR>&JwRR7Nx(u{?x*nvVUjI=cNzddT{&CH$6 zXcUX!K;PhF;#r{?q(*q|tsK?$bbe6e9E|*DHwF=j$siMqAa)YC6LR!8u@qLztIqS0 z4pf#zuv|Qe$N@w9DT?1B{ntBFdte5rk~~PgwGVUALG;-vkER0NcaM7Bt9|>yO$NKP z!j&1NT^HP)wszCyxzoBMoIjj&SLXH9ZqOi-l@&0j1jDlRN=x`I(1gE~s&`7^hf73{3(!VTqOw;jdV1!{G)K^xb3^KSMX#F9pghH*ePU(c!P%Ej3{a^(Nc<`2X42gik; zYBa3AdbhQ&QFC)=CUy{Fi5h52q?dB`h6V-(3c(*+ZA{!74lSjY;`5Wr{72}474Ub& zgcjblIHDQy_g@bnlls0r0CRpYzwHT4q-f=UO8|Uxpmg(`ghrA{quT~4EKxX|XOW&l zikZeckqpOOPk6U;mI`@JptiwImLm*oBXl+M4{YTOSvBMg)t5_QE|W!K{QtdbD)njm#KB4mO*Z3z4HHpO(pHhHwFHm!1@vv-r_V$g8AIZt z@mut7rF)yk$}gxgrggnp8x*Es2^0 zm5*QeB(&S+@oi4gV~}rl``eI|QXBNvNkJokSkm!Fag@?PtZe0Th%p3U=SuvMZ>$;U zV&oSpel4$t|7eEGmD+GTncfl)(3H-!zfP1JMMRm}iI0pD<6=OX{V%~ zgT1O_f}7@+EG)|3_JT%`h3$`g_B_{cn%(MEq~f zHJ>N@`R&iQv5^1#O{Mz3C9f~%9Tf*f88 K>hPfHtNsI#<{obV literal 0 HcmV?d00001 diff --git a/skills/hyenand-retrofit/evals/bench_tokens.py b/skills/hyenand-retrofit/evals/bench_tokens.py new file mode 100644 index 00000000..218b34ce --- /dev/null +++ b/skills/hyenand-retrofit/evals/bench_tokens.py @@ -0,0 +1,321 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Benchmark LLM token usage for the hyenand-retrofit skill. + +For each eval case in evals.json, this spawns a fresh, non-interactive Claude +agent (`claude -p`) with the skill text injected inline, lets it actually carry +out the retrofit (read inputs, write the sibling output file), and records the +token / cost / latency figures Claude reports in its JSON result envelope. + +Because every `claude -p` invocation is a cold process, it pays the full +system-prompt cache-creation cost once (no warm cache between runs). That fixed +overhead is part of what "invoking the skill" costs, so we report it explicitly +(cache_creation_tokens) alongside the task-driven input/output tokens. + +Usage: + python bench_tokens.py [--runs N] [--eval-id ID] [--model MODEL] [--dry-run] + + --runs N Repetitions per eval case (default: 3) + --eval-id ID Run only the eval with this integer id (default: all) + --model MODEL Model to pin for reproducibility (default: claude-opus-4-8) + --dry-run Print the prompts and the exact CLI invocation; call nothing + +Each run appends one JSON line to bench_results.jsonl with these fields: + eval_id, eval_name, run, model, input_tokens, output_tokens, + cache_creation_tokens, cache_read_tokens, billed_input_tokens, + billed_total_tokens, cost_usd, duration_ms, num_turns, + permission_denials, ts +""" + +import argparse +import json +import pathlib +import subprocess +import sys +import time + + +REPO_ROOT = pathlib.Path(__file__).resolve().parents[3] +EVALS_FILE = pathlib.Path(__file__).parent / "evals.json" +RESULTS_FILE = pathlib.Path(__file__).parent / "bench_results.jsonl" +SKILL_FILE = pathlib.Path(__file__).resolve().parents[1] / "SKILL.md" + +DEFAULT_MODEL = "claude-opus-4-8" + +# Directories an eval is allowed to write into. Cleanup is scoped to these so we +# never touch the bench script, its results, or unrelated working-tree changes. +WRITE_DIRS = [ + "examples/vit5_imagenet/", + "skills/hyenand-retrofit/evals/inputs/", +] + + +def load_evals(): + """Load eval cases from evals.json.""" + return json.loads(EVALS_FILE.read_text())["evals"] + + +def build_prompt(eval_case: dict) -> str: + """Inject the full skill text + file hints + the eval prompt. + + Injecting SKILL.md inline reproduces the "skill is loaded" condition and + folds the skill's fixed context cost into the measured input tokens. + """ + skill_text = SKILL_FILE.read_text() if SKILL_FILE.exists() else "" + preamble = f"\n{skill_text}\n\n\n" if skill_text else "" + file_hints = "" + if eval_case.get("files"): + file_hints = ( + "Relevant files to read first (paths relative to repo root):\n" + + "\n".join(f" - {f}" for f in eval_case["files"]) + + "\n\n" + ) + return preamble + file_hints + eval_case["prompt"] + + +def porcelain() -> dict[str, str]: + """Map of path -> status code from `git status --porcelain`, scoped to WRITE_DIRS.""" + out = subprocess.run(["git", "status", "--porcelain"], cwd=REPO_ROOT, capture_output=True, text=True).stdout + status = {} + for line in out.splitlines(): + if not line.strip(): + continue + code, path = line[:2], line[3:].strip() + # Rename entries look like "old -> new"; keep the new path. + if " -> " in path: + path = path.split(" -> ", 1)[1] + if any(path.startswith(d) for d in WRITE_DIRS): + status[path] = code + return status + + +def restore_tree(baseline: dict[str, str]): + """Undo whatever the agent did inside WRITE_DIRS, leaving everything else alone. + + - Files newly untracked (not in baseline) are deleted. + - Tracked files the agent modified are restored with `git checkout --`. + """ + after = porcelain() + for path, code in after.items(): + if path in baseline and baseline[path] == code: + continue # unchanged from before this run + full = REPO_ROOT / path + if code.startswith("??"): + if full.exists(): + full.unlink() + else: + # Modified / added tracked file -> restore committed version. + subprocess.run(["git", "checkout", "--", path], cwd=REPO_ROOT, capture_output=True, text=True) + + +def parse_result(stdout: str) -> dict: + """Parse the `--output-format json` envelope (a single JSON object).""" + obj = None + try: + obj = json.loads(stdout) + except json.JSONDecodeError: + # Fallback: scan for the last line that parses and has type==result. + for line in stdout.splitlines(): + line = line.strip() + if not line: + continue + try: + cand = json.loads(line) + except json.JSONDecodeError: + continue + if cand.get("type") == "result": + obj = cand + if obj is None: + return {} + + usage = obj.get("usage", {}) + model_usage = obj.get("modelUsage", {}) or {} + # Primary model = the one that produced the most output tokens. + primary_model = "" + if model_usage: + primary_model = max(model_usage, key=lambda m: model_usage[m].get("outputTokens", 0)) + + inp = usage.get("input_tokens", 0) + out = usage.get("output_tokens", 0) + cc = usage.get("cache_creation_input_tokens", 0) + cr = usage.get("cache_read_input_tokens", 0) + return { + "input_tokens": inp, + "output_tokens": out, + "cache_creation_tokens": cc, + "cache_read_tokens": cr, + "billed_input_tokens": inp + cc + cr, + "billed_total_tokens": inp + cc + cr + out, + "cost_usd": round(obj.get("total_cost_usd", 0.0), 6), + "duration_ms": obj.get("duration_ms", 0), + "num_turns": obj.get("num_turns", 0), + "permission_denials": len(obj.get("permission_denials", []) or []), + "primary_model": primary_model, + "is_error": obj.get("is_error", False), + } + + +def run_one(eval_case: dict, run_index: int, model: str, dry_run: bool) -> dict: + """Run one eval case via `claude -p` and return a result record.""" + prompt = build_prompt(eval_case) + cmd = ["claude", "-p", "--output-format", "json", "--permission-mode", "acceptEdits", "--model", model] + + if dry_run: + print(f"\n--- DRY RUN eval {eval_case['id']} ({eval_case['name']}) run {run_index} ---") + print("CMD:", " ".join(cmd), " (prompt via stdin)") + print("PROMPT (first 400 chars of task portion):") + print(" ", eval_case["prompt"][:400], "...") + return {} + + baseline = porcelain() + t0 = time.monotonic() + try: + proc = subprocess.run(cmd, cwd=REPO_ROOT, input=prompt, capture_output=True, text=True, timeout=900) + except subprocess.TimeoutExpired: + restore_tree(baseline) + return { + "eval_id": eval_case["id"], + "eval_name": eval_case["name"], + "run": run_index, + "model": model, + "error": "timeout", + "ts": int(time.time()), + } + wall_sec = round(time.monotonic() - t0, 1) + + if proc.returncode != 0: + restore_tree(baseline) + return { + "eval_id": eval_case["id"], + "eval_name": eval_case["name"], + "run": run_index, + "model": model, + "error": f"exit {proc.returncode}: {proc.stderr[:160]}", + "ts": int(time.time()), + } + + parsed = parse_result(proc.stdout) + restore_tree(baseline) + + record = { + "eval_id": eval_case["id"], + "eval_name": eval_case["name"], + "run": run_index, + "model": model, + "wall_sec": wall_sec, + "ts": int(time.time()), + **parsed, + } + return record + + +def fmt_int(x): + """Format a number with thousands separators, or return str(x).""" + return f"{x:,}" if isinstance(x, (int, float)) else str(x) + + +def print_table(records: list[dict]): + """Print per-run rows and per-eval averages for successful benchmark records.""" + rows = [r for r in records if "error" not in r] + errs = [r for r in records if "error" in r] + if rows: + hdr = ( + f"{'eval':<24}{'run':>4} {'in':>6} {'cache_cr':>8} {'cache_rd':>8} " + f"{'out':>6} {'billed':>8} {'cost$':>7} {'turns':>5} {'sec':>6}" + ) + print("\n" + hdr) + print("-" * len(hdr)) + for r in rows: + print( + f"{r['eval_name']:<24}{r['run']:>4} " + f"{r['input_tokens']:>6,} {r['cache_creation_tokens']:>8,} " + f"{r['cache_read_tokens']:>8,} {r['output_tokens']:>6,} " + f"{r['billed_total_tokens']:>8,} {r['cost_usd']:>7.3f} " + f"{r['num_turns']:>5} {r.get('wall_sec', 0):>6.1f}" + ) + + # Per-eval averages + by = {} + for r in rows: + by.setdefault(r["eval_name"], []).append(r) + print( + f"\n{'AVG per eval':<24}{'n':>4} {'in':>6} {'cache_cr':>8} {'cache_rd':>8} " + f"{'out':>6} {'billed':>8} {'cost$':>7} {'turns':>5} {'sec':>6}" + ) + print("-" * len(hdr)) + for name, rs in by.items(): + n = len(rs) + + def avg(k): + return sum(r[k] for r in rs) / n + + print( + f"{name:<24}{n:>4} {round(avg('input_tokens')):>6,} " + f"{round(avg('cache_creation_tokens')):>8,} {round(avg('cache_read_tokens')):>8,} " + f"{round(avg('output_tokens')):>6,} {round(avg('billed_total_tokens')):>8,} " + f"{avg('cost_usd'):>7.3f} {round(avg('num_turns')):>5} {avg('wall_sec'):>6.1f}" + ) + total_cost = sum(r["cost_usd"] for r in rows) + print(f"\nTotal cost across {len(rows)} runs: ${total_cost:.3f} (model: {rows[0]['model']})") + for e in errs: + print(f"[ERROR] {e['eval_name']} run {e['run']}: {e['error']}") + + +def main(): + """CLI entry point for the token benchmark.""" + p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument("--runs", type=int, default=3, metavar="N") + p.add_argument("--eval-id", type=int, default=None, metavar="ID") + p.add_argument("--model", default=DEFAULT_MODEL) + p.add_argument("--dry-run", action="store_true") + args = p.parse_args() + + evals = load_evals() + if args.eval_id is not None: + evals = [e for e in evals if e["id"] == args.eval_id] + if not evals: + sys.exit(f"No eval with id={args.eval_id}") + + collected = [] + for ec in evals: + print(f"\n=== eval {ec['id']}: {ec['name']} ({args.runs} run(s), model={args.model}) ===") + for i in range(1, args.runs + 1): + print(f" run {i}/{args.runs} ...", end=" ", flush=True) + rec = run_one(ec, i, args.model, args.dry_run) + if args.dry_run: + continue + collected.append(rec) + with open(RESULTS_FILE, "a") as f: + f.write(json.dumps(rec) + "\n") + if "error" in rec: + print(f"ERROR: {rec['error']}") + else: + print( + f"in={rec['input_tokens']:,} cache_cr={rec['cache_creation_tokens']:,} " + f"out={rec['output_tokens']:,} billed={rec['billed_total_tokens']:,} " + f"${rec['cost_usd']:.3f} turns={rec['num_turns']} {rec['wall_sec']:.0f}s" + ) + + if not args.dry_run: + print_table(collected) + print( + f"\nAppended {len([r for r in collected if 'error' not in r])} rows " + f"to {RESULTS_FILE.relative_to(REPO_ROOT)}" + ) + + +if __name__ == "__main__": + main() diff --git a/skills/hyenand-retrofit/evals/plot_tokens.py b/skills/hyenand-retrofit/evals/plot_tokens.py new file mode 100644 index 00000000..16228bd8 --- /dev/null +++ b/skills/hyenand-retrofit/evals/plot_tokens.py @@ -0,0 +1,156 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Plot LLM token usage / cost for the hyenand-retrofit skill. + +Reads bench_results.jsonl (produced by bench_tokens.py) and renders a two-panel +figure to bench_tokens.png: + + Panel A — stacked mean token breakdown per eval (cache_read, cache_creation, + input, output). The stack height is the billed total; the labels + make clear how much is fixed skill/system overhead (cache) vs. + task-driven generation (output). + Panel B — mean agent turns per eval with std-dev error bars across runs. + Turns track how much back-and-forth the retrofit took and are the + cleanest proxy for work (the CLI's dollar figure is noisy for + multi-turn runs, so it is deliberately not plotted). + +Usage: + python plot_tokens.py [--results bench_results.jsonl] [--out bench_tokens.png] +""" + +import argparse +import json +import pathlib +from collections import defaultdict + +import matplotlib + + +matplotlib.use("Agg") +import matplotlib.pyplot as plt + + +HERE = pathlib.Path(__file__).parent +COMPONENTS = [ + ("cache_read_tokens", "cache read", "#bdd7e7"), + ("cache_creation_tokens", "cache creation", "#6baed6"), + ("input_tokens", "input", "#2171b5"), + ("output_tokens", "output (generated)", "#e6550d"), +] + + +def mean(xs): + """Arithmetic mean; returns 0.0 for an empty sequence.""" + return sum(xs) / len(xs) if xs else 0.0 + + +def std(xs): + """Sample standard deviation; returns 0.0 for fewer than two values.""" + if len(xs) < 2: + return 0.0 + m = mean(xs) + return (sum((x - m) ** 2 for x in xs) / (len(xs) - 1)) ** 0.5 + + +def load(results_path: pathlib.Path): + """Load successful benchmark rows from a JSONL results file.""" + rows = [] + for line in results_path.read_text().splitlines(): + line = line.strip() + if not line: + continue + r = json.loads(line) + if "error" not in r: + rows.append(r) + if not rows: + raise SystemExit(f"No successful runs found in {results_path}") + return rows + + +def aggregate(rows): + """Group rows by (eval_id, eval_name), preserving eval_id order.""" + by = defaultdict(list) + # Preserve eval_id ordering for a stable x-axis. + for r in rows: + by[(r["eval_id"], r["eval_name"])].append(r) + keys = sorted(by, key=lambda k: k[0]) + return keys, by + + +def main(): + """CLI entry point for plotting benchmark token usage.""" + ap = argparse.ArgumentParser() + ap.add_argument("--results", default=str(HERE / "bench_results.jsonl")) + ap.add_argument("--out", default=str(HERE / "bench_tokens.png")) + args = ap.parse_args() + + rows = load(pathlib.Path(args.results)) + keys, by = aggregate(rows) + names = [k[1] for k in keys] + model = rows[0].get("model", "?") + n_runs = max(len(by[k]) for k in keys) + + fig, (axA, axB) = plt.subplots(1, 2, figsize=(13, 5.5)) + + # ---- Panel A: stacked token breakdown ---- + x = range(len(keys)) + bottoms = [0.0] * len(keys) + for field, label, color in COMPONENTS: + vals = [mean([r[field] for r in by[k]]) for k in keys] + axA.bar(x, vals, bottom=bottoms, label=label, color=color, width=0.62) + bottoms = [b + v for b, v in zip(bottoms, vals)] + # Annotate billed total on top of each stack. + for xi, total in zip(x, bottoms): + axA.text(xi, total, f"{total / 1000:.0f}k", ha="center", va="bottom", fontsize=9, fontweight="bold") + axA.set_xticks(list(x)) + axA.set_xticklabels(names, rotation=20, ha="right", fontsize=9) + axA.set_ylabel("tokens (mean of runs)") + axA.set_title("Token breakdown per retrofit eval") + axA.set_ylim(top=max(bottoms) * 1.15) # headroom so top labels clear the legend + axA.legend(fontsize=8, loc="best") # auto-place away from the tallest bar + axA.grid(axis="y", alpha=0.3) + + # ---- Panel B: agent turns per eval with error bars ---- + turns = [mean([r["num_turns"] for r in by[k]]) for k in keys] + turns_err = [std([r["num_turns"] for r in by[k]]) for k in keys] + bars = axB.bar(x, turns, yerr=turns_err, capsize=4, color="#31a354", width=0.62) + for bar, t in zip(bars, turns): + axB.text( + bar.get_x() + bar.get_width() / 2, + bar.get_height(), + f"{t:.1f}", + ha="center", + va="bottom", + fontsize=9, + fontweight="bold", + ) + axB.set_xticks(list(x)) + axB.set_xticklabels(names, rotation=20, ha="right", fontsize=9) + axB.set_ylabel("agent turns (mean ± std)") + axB.set_title("Agent turns per retrofit eval") + axB.grid(axis="y", alpha=0.3) + + fig.suptitle( + f"hyenand-retrofit skill — token efficiency (model: {model}, {n_runs} runs/eval, {len(rows)} runs)", + fontsize=12, + ) + fig.tight_layout(rect=[0, 0, 1, 0.96]) + fig.savefig(args.out, dpi=130) + print(f"wrote {args.out}") + + +if __name__ == "__main__": + main()