# port-3: Gaussian plain-table Solidity port The delivered port beats t03 on the assigned real-engine sample: paired mean **+0.832385799 edge**, SE **0.159826532**, n=64. Gate F passes. Deployed size **18,466 bytes**; real-engine afterSwap peak **206,161 gas**, **0 OutOfGas**. These are local measurements, with source and harness below; they are not independent certification or a guarantee on other seeds. ## Setup All work and checkouts were inside the workspace's exempt `test/scratch/`. No account login was used. Setup was run once, from the pinned challenge checkout. The installed toolchain is the one specified in the assignment; the Markdown does not bundle the Python environment or native wheel. | Step | Local result | |---|---| | Clone amm-challenge; checkout `6b6921f8d463314aa7c96234e1be25a25245f704` | Passed | | Save and run supplied `scratch/setup.sh` once | Passed, exit 0 | | uv availability/install | Passed | | Download pinned amm_sim_rs wheel | Passed | | Wheel SHA-256 | `aedb68280aca34c110968f00148387c95885207913fb2cf19a1ab4c5cfd6887a`, matched | | Python 3.12 venv and requested packages | Passed; Python 3.12.3, amm-sim-rs 0.1.0.post1 | | Editable challenge install | Passed | | solcx install 0.8.24 | Passed | | StarterStrategy validate | `Strategy 'StarterStrategy' validated successfully!` | | Final Strategy validate | `Strategy 'TaylorGaussianPlainCoarse' validated successfully!` | The exact setup script executed: ```sh set -eu;R=$PWD/scratch;mkdir -p $R/tmp $R/bin $R/solcx echo "export TMPDIR=$R/tmp XDG_CACHE_HOME=$R/xc UV_CACHE_DIR=$R/uvc UV_PYTHON_INSTALL_DIR=$R/uvpy SOLCX_BINARY_PATH=$R/solcx VIRTUAL_ENV=$PWD/.venv PATH=$PWD/.venv/bin:$R/bin:\$PATH" >$R/env.sh;. $R/env.sh command -v uv >/dev/null||{ curl -LsSf https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-unknown-linux-gnu.tar.gz|tar --no-same-owner -xz -C $R/tmp;cp $R/tmp/uv-*/uv $R/bin/;} W=amm_sim_rs-0.1.0.post1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl;curl -LsSf https://github.com/gtmcknight/amm-sim/releases/download/sim-6b6921f8/$W -o $R/$W echo "aedb68280aca34c110968f00148387c95885207913fb2cf19a1ab4c5cfd6887a $R/$W"|sha256sum -c - uv venv --python 3.12 .venv;uv pip install $R/$W numpy numba cma py-solc-x==2.1.0 pyrevm==0.3.7;uv pip install --no-deps -e . python -c "import solcx;solcx.install_solc('0.8.24')" amm-match validate contracts/src/StarterStrategy.sol ``` Subsequent toolchain commands used `. scratch/env.sh &&`. Compilation used the unchanged [challenge compiler](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/evm/compiler.py): solc 0.8.24, optimizer enabled, 200 runs, viaIR, Paris. Individual checks were segmented under eight minutes; long harness commands used `timeout 470`. No engine seed outside 9510128..9510191 was consumed. Each was run once for the final port and once for t03; earlier contract revisions used replica callbacks only. ## Design Credits: Taylor (gtmcknight), [pinned solved-game README](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/README.md), [real.py](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/real.py), [table interpolation](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/evalpol.py). This ports Gaussian + plain with `soft=1`, not qm or lattice. The contract header credits Taylor. Persistent state occupies slots 0..7: log-price mean, variance, bid fee, ask fee, last own spot, estimated rival spot, timestamp, and own-retail count. All signed arithmetic uses 1e18 scale. New-step likelihood classification, truncated-normal moments, mixture thresholds 0.005/0.995, 0.5 phase classification, rival clipping, and the silent-step cap of 12 follow real.py. Amounts and oracle arguments do not enter the filter. Phase 1 means the first inferred retail fill; later fills use phase 2. The plain policy does not need a synced flag or an sd table dimension. `ln`: power-of-two reduction, atanh odd series through degree 29. `exp`: nearest-ln(2) reduction and [6/6] Pade rational approximation, with exponent reconstruction. `pdf`: exp(-x*x/2)/sqrt(2*pi), cut off beyond |x|=10. `cdf`: Hart rational normal tail (equivalently a rational erf construction); shares the already computed pdf in truncation, saturating beyond |x|=8. Square root uses bit normalization and seven Newton iterations. Truncated moments preserve the mass-below-1e-12 edge snap and quarter variance. Negative computed variance is clamped to zero. All fee outputs clamp to [0,10%]. The exponential rational has coefficients (665280, 332640, 75600, 10080, 840, 42, 1). Range reduction bounds its residual to about +/-0.3466. Coefficients are explicit in the source. Fixed-point truncation, CDF saturation, and float-to-WAD callback conversion introduce errors; the direct replay below measures their combined effect rather than claiming formal worst-case error bounds. Arithmetic is unchecked for the bounded simulation domain; invalid zero reserves are outside that domain. Initialization uses the two precomputed fees from the compressed table at (w,R,phase)=(0,0,0), 0.002821013442392051 each. This prevents solc from duplicating the table between init and swap paths. It initializes log-price from reserveY/reserveX. All dynamic table reads use the single internal `lookup` function over the constant bytes blob. No external table contracts or runtime downloads are needed by the strategy or fee reference. ## Table Input: [pol_mid.json](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/pol_mid.json). The original six tables contain 71,262 offsets. The selected coarse table retains every fourth own row: 81 rows, -800..800 bps at 20 bps spacing. Phase 0 retains every second rival column: -30,-20,-10,0,10,20,30 bps. Phases 1 and 2 retain every fourth rival column: -800,-300,-125,-60,-40,-20,0,20,40,60,125,300,800 bps. Order: A0, B0, A1, B1, A2, B2; row-major. Values are signed big-endian int16, in eighth-bps units, rounded using Python round. 5,346 values occupy 10,692 payload bytes. Payload is grouped into 32-byte blocks, each prefixed by 0x7f, with final zero padding: 11,055 encoded bytes. The prefix is safe for bytecode opcode scanning and is skipped by lookup. The last padding is never read. Maximum sampled-knot quantization error against the original JSON was 0.062000000000001165 bps. Bilinear interpolation and domain clipping match the reference at the new knots; interpolation error between retained knots is additional. Payload SHA-256: `17dba90f09943115242f7674fdf325673620399699318b8e532981901dd5184a`. Gate P was run **before changing the policy or tables**, using unmodified Taylor files and plain `python3 -I gates.py`. It reproduced all published digits ([gates source](https://raw.githubusercontent.com/gtmcknight/amm-sim/4812a6382311624e1506aca131ca35c378f930d9/research/solved/gates.py)): ```text seed perfect-info gaussian+plain gaussian+qm lattice+qm 10000 448.261189 443.455598 443.522608 443.663520 10001 576.779199 571.463409 571.623551 571.977293 10002 531.886497 525.168028 525.865859 526.411631 ``` Gate Q uses paired replica seeds, with both policies on their own trajectories. The full reference is RealPolicy(T, {'soft':1}). The compressed reference decodes the literal shipped in Strategy.sol. One coarse candidate was selected on 60000..61023; the holdout did not change the choice. The original adapted-reference measurements were also rerun through the delivered standalone decoder. Selection: seeds 60000..61023, n=1024; mean edge full 529.061693433, compressed 528.317594868; compressed-minus-full **-0.744098565**, SE **0.017530693**. Worst five (seed, difference): (60188, -3.115666539), (60809, -2.707236995), (60773, -2.696867820), (60304, -2.528082003), (60831, -2.503687832). Report holdout: seeds 10000..12047, n=2048; mean edge full 532.385686971, compressed 531.643333344; compressed-minus-full **-0.742353627**, SE **0.012367923**. Worst five (seed, difference): (11610, -2.810731163), (11851, -2.703957499), (10248, -2.674588068), (11005, -2.647019940), (11570, -2.539576106). This quantifies a loss of about 0.74 edge from coarsening; the port does not claim to preserve the full-table score. Replica results are not real-engine score levels. ## Gate F Passed: **50 runs x 2,000 callbacks = 100,000 callbacks**, 200,000 fee comparisons. Replica seeds 70000..70049. For each run the Python compressed reference drives the replica; the first 2,000 own-pool callbacks and expected fees are recorded in order in memory. A fresh pyrevm deployment is initialized, then those exact callbacks are replayed without reference-state injection. Side, amounts, time, and post-trade reserves are ABI encoded, with amounts/reserves converted to WAD using int(float*1e18). Each swap call is capped at 245,000 gas; an exception aborts the test. Oracle fields accepted by the replica callback signature are ignored by the reference. Mean absolute fee difference: **9.38885741024225e-12 bps**. Maximum absolute fee difference: **1.39892784856155e-08 bps**. Both bid and ask count equally. Initialization is excluded from these swap statistics; its max error was 4.33680868994202e-15 bps. Target: <=0.01 bps. All 100,000 calls returned successfully. Pyrevm replay peak gas: 156,888; mean 61333.94154. Real-engine instrumentation is reported separately below. Per-run traces are SHA-256 hashed over JSON of recorded argument/fee tuples. SHA-256 of concatenated ordered per-run hex hashes: `67445e46c8b149e6a0fd565ba219c3309b4e020fd03eb40f0bcc4e1b5ecae7a3`. Traces were transient scratch data; the recording procedure is in check.py below. ## Size Deployed runtime: **18,466 / 24,576 bytes**. Creation bytecode: 18,494 bytes. Strategy.sol SHA-256: `62930b8e68277c69fc1acfba18de781e684d7fc6daac8dc562b8210dc3932ac1`. Runtime SHA-256: `35edacf4f75cf0a9d9e5dda1cdc9421b6cdc3c1aad39c55afc457a08df556ce5`. Validator and compilation passed with the unchanged challenge restrictions and base contracts ([base](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/AMMStrategyBase.sol), [interface](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/IAMMStrategy.sol)). ## Gas Aggregated directly from `amm_sim_rs.gas_stats()` after each 8-seed engine chunk, resetting between chunks. Max takes the maximum across chunks; mean is sum_ok_gas/ok, weighted by calls. These are the Submission entries, including transaction gas. Every listed call was successful; all `oog`, `revert`, `other_halt`, `tx_error`, and `bad_return` counters were zero for both roles in all chunks. | Strategy | Callback | Calls | Peak gas | Mean gas | |---|---|---:|---:|---:| | port | afterInitialize | 64 | 141957 | 141957.00000 | | port | afterSwap | 686442 | 206161 | 95489.07264 | | port | getName | 64 | 21524 | 21524.00000 | | t03 | afterInitialize | 64 | 243234 | 243234.00000 | | t03 | afterSwap | 696326 | 232627 | 135532.54421 | | t03 | getName | 64 | 21742 | 21742.00000 | Port afterSwap peak 206,161 is below 245,000. This is an observed peak on the 64 assigned seeds, not a proof for all possible inputs. No engine seed was spent on earlier contract revisions. ## Paired vs t03 t03 was obtained from `code_zb64` of the [specified artifact](https://api.imd.fun/artifacts/2333ecf28d4356bd232b85c1e55842e94e1ada05e1cd067830b5625dfdbc5336), base64-decoded then zlib-decompressed. Source SHA-256: `cb6d945511e1e10af78baa64c2a6cb25806f0998403ce6440654bfc3c70092d9`, matches the requested prefix. Its deployed size was 14,654 bytes. Each strategy ran **alone against the 30 bps [VanillaStrategy](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/contracts/src/VanillaStrategy.sol)**, via `amm_sim_rs.run_batch(X, VanillaStrategy, configs, 8)`. There was no port-versus-t03 pool match. The reported difference is submission edge(port)-submission edge(t03) on matching seeds. Configuration construction follows [MatchRunner._build_configs](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/match.py) and [baseline config](https://raw.githubusercontent.com/benedictbrady/amm-challenge/6b6921f8d463314aa7c96234e1be25a25245f704/amm_competition/competition/config.py): 10,000 steps, initial price 100, reserves 100/10,000, mu 0, dt 1, log-size sd 1.2, buy probability 0.5. For assigned seed i, default_rng(i) draws size uniform[19,21], arrival rate uniform[0.6,1.0], sigma uniform[0.000882,0.001008], in that order. This equals building the MatchRunner prefix through index i and selecting its config i, without allocating millions of preceding configs. The exact mapping is explicit in engine.py. Seeds: **9510128..9510191**, 64 distinct paired seeds. Mean edge port 528.667795972; t03 527.835410173. n=64, mean_diff=0.832385798685, se=0.159826531714; sample SE = sample standard deviation of differences / sqrt(64). Port wins 46/64 pairs. Worst five pairs: | Seed | Port edge | t03 edge | Difference | |---:|---:|---:|---:| | 9510147 | 395.038382996 | 396.588421848 | -1.550038852 | | 9510189 | 380.184034946 | 381.583783981 | -1.399749035 | | 9510154 | 482.980045854 | 484.274449024 | -1.294403170 | | 9510157 | 360.571133149 | 361.590303613 | -1.019170464 | | 9510177 | 369.677167537 | 370.540984093 | -0.863816555 | Complete paired rows (seed, port edge, t03 edge), rounded for display: ```csv seed,port,t03 9510128,691.188770674133,688.206347476664 9510129,630.690449878013,629.739077875682 9510130,501.646025806007,499.506082567670 9510131,442.184804676246,440.551380112974 9510132,690.432423066113,687.730650733287 9510133,634.833169008847,632.764001037027 9510134,580.059507770657,579.699379344766 9510135,618.862170101760,617.154509663654 9510136,481.078143244926,480.129122019301 9510137,665.353556015297,662.973860411209 9510138,466.537414241802,466.330522781633 9510139,564.829090795177,564.274524336781 9510140,385.834701843668,386.076802317683 9510141,495.248061849136,494.022965207603 9510142,481.401181663675,480.975224145989 9510143,448.869976861977,449.002375026000 9510144,677.987415282952,674.578050064075 9510145,658.649118430017,655.982861511046 9510146,586.148510379009,585.251502467223 9510147,395.038382996473,396.588421848159 9510148,445.847463144901,445.503681753430 9510149,493.405894347824,493.561398299462 9510150,606.240529351739,604.727046036676 9510151,666.168123945875,665.111537312175 9510152,489.619307816478,489.328563918756 9510153,600.352409064442,599.852099464096 9510154,482.980045854191,484.274449024081 9510155,492.182020559194,490.846821890731 9510156,475.369272513198,473.334389092784 9510157,360.571133149210,361.590303613355 9510158,627.293780291333,625.301717111154 9510159,501.979643874212,499.944112540087 9510160,433.848058702816,434.266313609838 9510161,442.322500846434,441.603586723504 9510162,609.560081327336,609.039649452513 9510163,561.028542690680,561.412967267031 9510164,564.759676582230,564.542533150546 9510165,579.641858882029,577.994403286396 9510166,733.015088250984,731.149458210429 9510167,540.844902330648,539.750151600530 9510168,473.178568899113,473.805005262798 9510169,426.179803274751,425.820670871952 9510170,505.683572534184,505.730113180053 9510171,394.446610867412,394.473773223427 9510172,430.686530374320,431.122988198696 9510173,645.616566518864,643.868063411922 9510174,545.589487895343,545.067805139621 9510175,428.041490876415,427.494333068982 9510176,552.689524302864,551.165861412745 9510177,369.677167537430,370.540984092696 9510178,536.651055045730,536.781084789264 9510179,442.094311481166,441.888367283960 9510180,712.202950355495,707.104239364733 9510181,550.002955404368,549.160468528649 9510182,582.896391512016,582.727696169257 9510183,612.982466354843,612.239494218062 9510184,632.590957426367,629.882091717109 9510185,433.191926462542,433.995564716034 9510186,489.892443882833,490.617502956973 9510187,413.760509032523,412.862125729658 9510188,647.418030704841,644.430810762730 9510189,380.184034945918,381.583783981383 9510190,407.731146454426,406.795401658140 9510191,417.447231933500,417.635177028217 ``` ## Code The following blocks are the verbatim delivered sources. Extract Strategy.sol to `contracts/src/Strategy.sol` in the pinned challenge checkout, and Python blocks to the named scratch paths. Keep the unchanged challenge base contracts and engine installation from Setup. The fee reference uses only the standard library and the embedded Strategy.sol blob. Replay and replica scoring additionally require Taylor's pinned `replica2.py` (linked above); copy it adjacent to check.py or make its solved directory importable. Scoring also reads pinned real.py, evalpol.py and full pol_mid.json. These external measurement inputs and native toolchain are not bundled in this report; they are not runtime dependencies of the contract. Commands used, with later source-equivalent replay/comparison harnesses shown below: ```sh . scratch/env.sh && python scratch/table_check.py ../taylor/research/solved/pol_mid.json . scratch/env.sh && timeout 470 python scratch/check.py 50 . scratch/env.sh && timeout 470 python scratch/replica_compare.py ../taylor/research/solved 60000 61024 . scratch/env.sh && timeout 470 python scratch/replica_compare.py ../taylor/research/solved 10000 12048 . scratch/env.sh && timeout 470 amm-match validate contracts/src/Strategy.sol ``` Engine checks called engine.py once for each kind (`port`, `t03`) and each 8-seed range [9510128+8k,9510136+8k), k=0..7, then aggregate.py. Never rerun consumed engine seeds to tune the strategy. ### contracts/src/Strategy.sol ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {AMMStrategyBase} from "./AMMStrategyBase.sol"; import {TradeInfo} from "./IAMMStrategy.sol"; // Gaussian solved policy by Taylor (gtmcknight), amm-sim 4812a638. // Port: signed WAD arithmetic; coarse plain tables, signed int16 eighth-bps. // TABLE uses 32 payload bytes per 33-byte block, prefixed with PUSH32 (0x7f). // Taylor source: https://github.com/gtmcknight/amm-sim/tree/4812a6382311624e1506aca131ca35c378f930d9/research/solved contract Strategy is AMMStrategyBase { int256 constant U=1e18; int256 constant LN2=693147180559945309; bytes constant TABLE=hex"7fff3eff46ff4dff53ff58ff5dff61ff3eff47ff4eff53ff59ff5dff62ff3fff477fff4eff54ff59ff5eff62ff3fff48ff4eff55ff5aff5fff63ff40ff48ff4fff557fff5bff5fff64ff40ff48ff4fff56ff5bff60ff65ff41ff49ff50ff56ff5cff617fff66ff41ff4aff51ff57ff5dff62ff66ff42ff4bff51ff58ff5eff63ff67ff437fff4bff52ff59ff5fff64ff68ff44ff4cff53ff59ff5fff65ff6aff44ff4dff547fff5aff60ff66ff6bff45ff4dff54ff5bff62ff67ff6cff46ff4eff55ff5dff637fff69ff6eff47ff4fff57ff5eff64ff6aff6fff48ff50ff58ff5fff66ff6cff717fff49ff51ff59ff61ff68ff6eff72ff4aff53ff5aff62ff69ff6fff74ff4cff547fff5cff64ff6bff71ff77ff4dff56ff5eff66ff6dff74ff79ff4fff57ff60ff687fff70ff76ff7cff50ff59ff62ff6aff72ff79ff7fff52ff5bff64ff6dff75ff7d7fff83ff54ff5eff67ff70ff78ff81ff88ff57ff61ff6bff74ff7dff85ff8dff5a7fff64ff6eff78ff82ff8bff93ff5eff68ff73ff7dff88ff92ff99ff61ff6cff787fff83ff8fff99ffa2ff65ff71ff7eff8aff97ff9effa4ff6aff77ff85ff93ffa07fffa500adff70ff7eff8dff9cffab008e00c0ff77ff86ff97ffaaffb700a700d47fff80ff91ffa6ffbb007c00bd00e7ff8aff9dffb8ffe7009c00d200fbff94ffad7fffd4006e00b600e8010effa5ffc40019008d00cc00fd0122ffbbffea005700a67f00e0010e0134ffee0022007700b900f0011f0145005f0061009300c90100012f7f0157009a009000a800d7010c0139016100ec00dd00bd00e201170144016d01147f010500f100f601220154017f01400140014001400140016b019701e001e001e07f01e001e001e001e00280028002800280028002800280032003200320032003207f0320032003c003c003c003c003c003c003c004600460046004600460046004607f050005000500050005000500050005a005a005a005a005a005a005a0064006407f0640064006400640064006e006e006e006e006e006e006e007800780078007807f078007800780082008200820082008200820082008c008c008c008c008c008c07f08c009600960096009600960096009600a000a000a000a000a000a000a000aa07f0aa00aa00aa00aa00aa00aa00b400b400b400b400b400b400b400be00be00be07f0be00be00be00be00c800c800c800c800c800c800c800d200d200d200d200d207f0d200d200dc00dc00dc00dc00dc00dc00dc00e600e600e600e600e600e600e607f0f000f000f000f000f000f000f000fa00fa00fa00fa00fa00fa00fa0104010407f1040104010401040104010e010e010e010e010e010e010e011801180118011807f118011801180122012201220122012201220122012c012c012c012c012c012c07f12c01360136013601360136013601360140014001400140014001400140014a07f14a014a014a014a014a014a0154015401540154015401540154015e015e015e07f15e015e015e015e01680168016801680168016801680172017201720172017207f1720172017c017c017c017c017c017c017c018601860186018601860186018607f19001900190019001900190019001900190019001900190019001900186018607f1860186018601860186017c017c017c017c017c017c017c017201720172017207f172017201720168016801680168016801680168015e015e015e015e015e015e07f15e0154015401540154015401540154014a014a014a014a014a014a014a014007f140014001400140014001400136013601360136013601360136012c012c012c07f12c012c012c012c01220122012201220122012201220118011801180118011807f1180118010e010e010e010e010e010e010e010401040104010401040104010407f0fa00fa00fa00fa00fa00fa00fa00f000f000f000f000f000f000f000e600e607f0e600e600e600e600e600dc00dc00dc00dc00dc00dc00dc00d200d200d200d207f0d200d200d200c800c800c800c800c800c800c800be00be00be00be00be00be07f0be00b400b400b400b400b400b400b400aa00aa00aa00aa00aa00aa00aa00a007f0a000a000a000a000a000a00096009600960096009600960096008c008c008c07f08c008c008c008c00820082008200820082008200820078007800780078007807f0780078006e006e006e006e006e006e006e006400640064006400640064006407f05a005a005a005a005a005a005a00500050005000500050005000500046004607f0460046004600460046003c003c003c003c003c003c003c003200320032003207f032003200320028002800280028002800280028001e001e001e001e001e001e07f01e00197016b01400140014001400140017f0154012200f600f101050114016d7f0144011700e200bd00dd00ec01610139010c00d700a80090009a0157012f01007f00c900930061005f0145011f00f000b900770022ffee0134010e00e000a600577fffeaffbb012200fd00cc008d0019ffc4ffa5010e00e800b6006effd4ffadff947f00fb00d2009cffe7ffb8ff9dff8a00e700bd007cffbbffa6ff91ff8000d400a77fffb7ffaaff97ff86ff7700c0008effabff9cff8dff7eff7000adffa5ffa0ff937fff85ff77ff6affa4ff9eff97ff8aff7eff71ff65ffa2ff99ff8fff83ff78ff6c7fff61ff99ff92ff88ff7dff73ff68ff5eff93ff8bff82ff78ff6eff64ff5aff8d7fff85ff7dff74ff6bff61ff57ff88ff81ff78ff70ff67ff5eff54ff83ff7dff757fff6dff64ff5bff52ff7fff79ff72ff6aff62ff59ff50ff7cff76ff70ff68ff607fff57ff4fff79ff74ff6dff66ff5eff56ff4dff77ff71ff6bff64ff5cff54ff4c7fff74ff6fff69ff62ff5aff53ff4aff72ff6eff68ff61ff59ff51ff49ff71ff6c7fff66ff5fff58ff50ff48ff6fff6aff64ff5eff57ff4fff47ff6eff69ff63ff5d7fff55ff4eff46ff6cff67ff62ff5bff54ff4dff45ff6bff66ff60ff5aff54ff4d7fff44ff6aff65ff5fff59ff53ff4cff44ff68ff64ff5fff59ff52ff4bff43ff677fff63ff5eff58ff51ff4bff42ff66ff62ff5dff57ff51ff4aff41ff66ff61ff5c7fff56ff50ff49ff41ff65ff60ff5bff56ff4fff48ff40ff64ff5fff5bff55ff4f7fff48ff40ff63ff5fff5aff55ff4eff48ff3fff62ff5eff59ff54ff4eff47ff3f7fff62ff5dff59ff53ff4eff47ff3eff61ff5dff58ff53ff4dff46ff3eff05ff077fff0bff17ff22ff2bff31ff36ff3aff3dff43ff4aff4dff06ff07ff0cff17ff227fff2bff32ff36ff3bff3dff44ff4bff4eff06ff08ff0cff18ff23ff2cff32ff377fff3bff3eff44ff4bff4fff07ff08ff0dff18ff23ff2cff33ff38ff3cff3fff457fff4cff4fff07ff08ff0dff18ff23ff2cff33ff38ff3dff40ff46ff4dff50ff087fff09ff0eff19ff24ff2dff34ff39ff3eff40ff47ff4eff51ff09ff0aff0eff1a7fff25ff2eff35ff3aff3eff41ff48ff4fff52ff09ff0bff0fff1aff25ff2eff367fff3bff3fff42ff49ff50ff53ff0aff0bff0fff1bff26ff2fff36ff3cff40ff437fff4aff51ff54ff0bff0cff10ff1cff27ff30ff37ff3dff41ff44ff4bff52ff557fff0cff0dff11ff1dff27ff30ff38ff3eff42ff45ff4cff53ff57ff0cff0eff127fff1dff28ff31ff39ff3fff43ff46ff4dff54ff58ff0dff0eff13ff1eff28ff327fff3aff40ff45ff48ff4fff56ff59ff0eff10ff14ff1fff2aff33ff3bff42ff467fff4aff50ff57ff5bff10ff11ff15ff20ff2bff34ff3dff43ff48ff4bff52ff597fff5dff10ff12ff16ff21ff2bff36ff3eff44ff49ff4cff53ff5aff5eff12ff137fff18ff23ff2dff37ff40ff46ff4aff4eff55ff5cff60ff13ff14ff19ff24ff2e7fff38ff41ff48ff4cff50ff57ff5eff62ff15ff16ff1aff25ff2fff3aff43ff497fff4eff52ff59ff60ff64ff17ff18ff1cff27ff31ff3cff45ff4cff50ff54ff5c7fff63ff67ff19ff1aff1eff29ff33ff3eff47ff4eff53ff57ff5eff66ff6aff1b7fff1cff20ff2aff34ff3fff49ff50ff55ff59ff61ff69ff6dff1dff1eff23ff2c7fff37ff42ff4cff53ff58ff5cff65ff6cff70ff20ff21ff25ff2fff39ff45ff4f7fff56ff5cff60ff68ff70ff74ff23ff24ff28ff31ff3cff48ff52ff5aff5fff647fff6cff74ff79ff26ff27ff2bff34ff3eff4bff56ff5eff63ff68ff71ff7900e17fff29ff2aff2eff37ff42ff4fff5aff63ff67ff6bff7400e300ebff2dff2eff327fff3bff46ff53ff60ff67ff69ff6eff7900ef00f7ff31ff33ff37ff3fff4aff577fff65ff69ff68ff6b00e700fc0104ff36ff37ff3bff44ff4eff5dff6cff6bff6a7fff6e00f5010a0110ff3aff3cff40ff48ff53ff63ff72ff6eff70ff74010501187f011fff41ff42ff47ff4fff59ff6bff78ff72ff7500f601150128012fff48ff497fff4dff56ff60ff74ff7fff7900f2010901270139013fff4eff50ff56ff5eff697fff7fff87ff830106011c0139014b0152ff54ff55ff5eff67ff71ff8bff9100e27f01190130014d015e0165ff5cff5dff66ff75ff7fff9aff9f00f7012e014301617f0173017aff68ff69ff72ff8bff92ffb3009f010a01410157017501890190ff807fff81ff8fffc2ffd2fff700b5011c0153016a018a01a001a8ff8aff8bff9affe57f0010005400c7012d0166017e01a201bd01c7ff90ff91ffa3000d0035007c00d57f013a0172018c01c101f00202000000000000004c00c000d100e00146018401bc7f02a204b004b000a000a000b70105011500fc00f4015801b101f1039a04b004b07f0140014001400140014001400140016a01ca021903c404b004b001e001e001e07f01e001e001e001e001e001e0023f03ca04b004b00280028002800280028002807f028002800280028003da04b004b00320032003200320032003200320032003207f032003e104b004b003c003c003c003c003c003c003c003c003c003c003ec04b07f04b00460046004600460046004600460046004600460046004b004b0050005007f0500050005000500050005000500050005000500050005a005a005a005a005a07f05a005a005a005a005a005a005a005a0064006400640064006400640064006407f0640064006400640064006e006e006e006e006e006e006e006e006e006e006e07f06e006e0078007800780078007800780078007800780078007800780078008207f08200820082008200820082008200820082008200820082008c008c008c008c07f08c008c008c008c008c008c008c008c008c009600960096009600960096009607f0960096009600960096009600a000a000a000a000a000a000a000a000a000a007f0a000a000a000aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa07f0b400b400b400b400b400b400b400b400b400b400b400b400b400be00be00be07f0be00be00be00be00be00be00be00be00be00be00c800c800c800c800c800c807f0c800c800c800c800c800c800c800d200d200d200d200d200d200d200d200d207f0d200d200d200d200dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc07f0dc00e600e600e600e600e600e600e600e600e600e600e600e600e600f000f007f0f000f000f000f000f000f000f000f000f000f000f000fa00fa00fa00fa00fa07f0fa00fa00fa00fa00fa00fa00fa00fa0104010401040104010401040104010407f1040104010401040104010e010e010e010e010e010e010e010e010e010e010e07f10e010e0118011801180118011801180118011801180118011801180118012207f12201220122012201220122012201220122012201220122012c012c012c012c07f12c012c012c012c012c012c012c012c012c013601360136013601360136013607f13601360136013601360136014001400140014001400140014001400140014007f14001400140014a014a014a014a014a014a014a014a014a014a014a014a014a07f154015401540154015401540154015401540154015401540154015e015e015e07f15e015e015e015e015e015e015e015e015e015e01680168016801680168016807f16801680168016801680168016801720172017201720172017201720172017207f172017201720172017c017c017c017c017c017c017c017c017c017c017c017c07f17c01860186018601860186018601860186018601860186018601860190019007f19001900190019001900190019001900190019001900190019001900190019007f19001900190019001900190019001900186018601860186018601860186018607f1860186018601860186017c017c017c017c017c017c017c017c017c017c017c07f17c017c0172017201720172017201720172017201720172017201720172016807f16801680168016801680168016801680168016801680168015e015e015e015e07f15e015e015e015e015e015e015e015e015e015401540154015401540154015407f15401540154015401540154014a014a014a014a014a014a014a014a014a014a07f14a014a014a014001400140014001400140014001400140014001400140014007f136013601360136013601360136013601360136013601360136012c012c012c07f12c012c012c012c012c012c012c012c012c012c01220122012201220122012207f12201220122012201220122012201180118011801180118011801180118011807f118011801180118010e010e010e010e010e010e010e010e010e010e010e010e07f10e010401040104010401040104010401040104010401040104010400fa00fa07f0fa00fa00fa00fa00fa00fa00fa00fa00fa00fa00fa00f000f000f000f000f007f0f000f000f000f000f000f000f000f000e600e600e600e600e600e600e600e607f0e600e600e600e600e600dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc07f0dc00dc00d200d200d200d200d200d200d200d200d200d200d200d200d200c807f0c800c800c800c800c800c800c800c800c800c800c800c800be00be00be00be07f0be00be00be00be00be00be00be00be00be00b400b400b400b400b400b400b407f0b400b400b400b400b400b400aa00aa00aa00aa00aa00aa00aa00aa00aa00aa07f0aa00aa00aa00a000a000a000a000a000a000a000a000a000a000a000a000a007f096009600960096009600960096009600960096009600960096008c008c008c07f08c008c008c008c008c008c008c008c008c008c00820082008200820082008207f08200820082008200820082008200780078007800780078007800780078007807f078007800780078006e006e006e006e006e006e006e006e006e006e006e006e07f06e0064006400640064006400640064006400640064006400640064005a005a07f05a005a005a005a005a005a005a005a005a005a005a0050005000500050005007f0500050005000500050005000500050004b004b00460046004600460046004607f0460046004600460046004b004b003ec03c003c003c003c003c003c003c003c07f03c003c004b004b003e1032003200320032003200320032003200320032004b07f04b003da028002800280028002800280028002800280028004b004b003ca023f7f01e001e001e001e001e001e001e001e001e004b004b003c4021901ca016a01407f01400140014001400140014004b004b0039a01f101b1015800f400fc011501057f00b700a000a004b004b002a201bc0184014600e000d100c0004c0000000000007f020201f001c1018c0172013a00d5007c0035000dffa3ff91ff9001c701bd01a27f017e0166012d00c700540010ffe5ff9aff8bff8a01a801a0018a016a0153011c7f00b5fff7ffd2ffc2ff8fff81ff8001900189017501570141010a009fffb3ff927fff8bff72ff69ff68017a017301610143012e00f7ff9fff9aff7fff75ff66ff5d7fff5c0165015e014d0130011900e2ff91ff8bff71ff67ff5eff55ff540152014b7f0139011c0106ff83ff87ff7fff69ff5eff56ff50ff4e013f01390127010900f27fff79ff7fff74ff60ff56ff4dff49ff48012f0128011500f6ff75ff72ff78ff6b7fff59ff4fff47ff42ff41011f01180105ff74ff70ff6eff72ff63ff53ff48ff407fff3cff3a0110010a00f5ff6eff6aff6bff6cff5dff4eff44ff3bff37ff3601047f00fc00e7ff6bff68ff69ff65ff57ff4aff3fff37ff33ff3100f700efff79ff6e7fff69ff67ff60ff53ff46ff3bff32ff2eff2d00eb00e3ff74ff6bff67ff63ff5a7fff4fff42ff37ff2eff2aff2900e1ff79ff71ff68ff63ff5eff56ff4bff3eff347fff2bff27ff26ff79ff74ff6cff64ff5fff5aff52ff48ff3cff31ff28ff24ff237fff74ff70ff68ff60ff5cff56ff4fff45ff39ff2fff25ff21ff20ff70ff6cff657fff5cff58ff53ff4cff42ff37ff2cff23ff1eff1dff6dff69ff61ff59ff55ff507fff49ff3fff34ff2aff20ff1cff1bff6aff66ff5eff57ff53ff4eff47ff3eff337fff29ff1eff1aff19ff67ff63ff5cff54ff50ff4cff45ff3cff31ff27ff1cff187fff17ff64ff60ff59ff52ff4eff49ff43ff3aff2fff25ff1aff16ff15ff62ff5e7fff57ff50ff4cff48ff41ff38ff2eff24ff19ff14ff13ff60ff5cff55ff4eff4a7fff46ff40ff37ff2dff23ff18ff13ff12ff5eff5aff53ff4cff49ff44ff3eff367fff2bff21ff16ff12ff10ff5dff59ff52ff4bff48ff43ff3dff34ff2bff20ff157fff11ff10ff5bff57ff50ff4aff46ff42ff3bff33ff2aff1fff14ff10ff0eff597fff56ff4fff48ff45ff40ff3aff32ff28ff1eff13ff0eff0dff58ff54ff4dff467fff43ff3fff39ff31ff28ff1dff12ff0eff0cff57ff53ff4cff45ff42ff3eff387fff30ff27ff1dff11ff0dff0cff55ff52ff4bff44ff41ff3dff37ff30ff27ff1c7fff10ff0cff0bff54ff51ff4aff43ff40ff3cff36ff2fff26ff1bff0fff0bff0a7fff53ff50ff49ff42ff3fff3bff36ff2eff25ff1aff0fff0bff09ff52ff4fff487fff41ff3eff3aff35ff2eff25ff1aff0eff0aff09ff51ff4eff47ff40ff3eff397fff34ff2dff24ff19ff0eff09ff08ff50ff4dff46ff40ff3dff38ff33ff2cff237fff18ff0dff08ff07ff4fff4cff45ff3fff3cff38ff33ff2cff23ff18ff0dff087fff07ff4fff4bff44ff3eff3bff37ff32ff2cff23ff18ff0cff08ff06ff4eff4b7fff44ff3dff3bff36ff32ff2bff22ff17ff0cff07ff06ff4dff4aff43ff3dff3a7fff36ff31ff2bff22ff17ff0bff07ff05ff05ff06ff09ff11ff18ff1eff22ff257fff28ff29ff2dff31ff33ff06ff07ff0aff11ff18ff1eff23ff26ff28ff2aff2e7fff32ff34ff06ff07ff0aff12ff19ff1fff23ff26ff29ff2aff2eff32ff35ff077fff08ff0bff12ff19ff1fff24ff27ff29ff2bff2fff33ff35ff07ff08ff0bff127fff1aff20ff24ff28ff2aff2cff30ff34ff36ff08ff09ff0cff13ff1aff21ff257fff28ff2bff2dff31ff35ff37ff09ff0aff0dff14ff1bff21ff26ff29ff2cff2e7fff32ff36ff38ff09ff0aff0dff15ff1cff22ff27ff2aff2dff2eff32ff37ff397fff0aff0aff0dff15ff1cff23ff27ff2bff2eff2fff33ff38ff3aff0bff0bff0e7fff16ff1dff23ff28ff2cff2fff30ff35ff39ff3bff0cff0cff0fff17ff1eff247fff29ff2dff30ff32ff36ff3aff3cff0cff0dff10ff18ff1fff25ff2aff2eff317fff32ff37ff3bff3dff0dff0eff11ff18ff1fff26ff2bff2fff32ff34ff38ff3c7fff3fff0eff0fff12ff19ff21ff27ff2cff30ff34ff35ff3aff3eff40ff0fff107fff13ff1bff22ff28ff2dff32ff35ff37ff3bff40ff42ff10ff11ff14ff1bff237fff29ff2fff33ff36ff38ff3cff41ff43ff12ff13ff16ff1dff24ff2aff30ff357fff38ff3aff3eff42ff44ff13ff14ff17ff1eff25ff2cff32ff36ff39ff3bff407fff44ff46ff14ff15ff18ff1fff26ff2eff34ff38ff3bff3dff42ff46ff48ff177fff18ff1bff22ff28ff2fff36ff3aff3eff40ff44ff48ff4bff19ff19ff1cff247fff2aff31ff38ff3dff40ff42ff47ff4bff4dff1bff1bff1eff25ff2cff33ff3a7fff3fff42ff44ff49ff4dff50ff1dff1eff21ff27ff2eff36ff3dff42ff45ff487fff4cff51ff53ff20ff20ff23ff2aff30ff38ff40ff45ff49ff4bff50ff54ff567fff23ff24ff26ff2cff33ff3bff43ff49ff4cff4eff53ff57ff5aff25ff26ff297fff2fff36ff3fff47ff4cff4fff52ff57ff5cff5eff29ff29ff2cff32ff3aff437fff4bff50ff52ff55ff5aff5eff61ff2dff2eff31ff36ff3eff47ff50ff53ff507fff52ff58ff5dff61ff31ff32ff35ff3aff42ff4bff56ff56ff53ff55ff59ff5e7fff60ff36ff36ff39ff3fff46ff50ff5bff58ff54ff56ff5bff5fff62ff3aff3b7fff3eff43ff4bff57ff61ff5cff5dff5fff63ff67ff69ff41ff42ff45ff4bff527fff5fff67ff61ff62ff64ff680108010dff48ff48ff4bff51ff58ff67ff6cff687fff6bff6d010d0119011eff4eff4fff53ff59ff61ff71ff72ff71ff75ff7701207f012d0131ff54ff55ff5cff62ff69ff7cff7eff7e011101200134013f0144ff5c7fff5cff64ff6fff77ff8aff8d00f501260135014801540158ff68ff69ff70ff867fff8bff9c009b010801390148015c0168016cff80ff81ff8dffbdffcbffda00b27f011a014c015b0170017d0182ff8aff8bff99ffe00003004a00c60129015f016c7f01850194019aff90ff90ffa600070028007000d50139016b0180019801b901c07f000000000000003700ab00cc00e00145018301be021504b004b000a000a000eb7f00f2010c00f900f4015801ad01e2036e04b004b00140014001400157014001557f0140016b01c8020b03b604b004b001e001e001e001e001e001e001e001e001e07f023703be04b004b0028002800280028002800280028002800280028003d704b07f04b0032003200320032003200320032003200320032003de04b004b003c003c07f03c003c003c003c003c003c003c003c003ea04b004b0046004600460046004607f04600460046004600460046004b004b0050005000500050005000500050005007f0500050005000500050005a005a005a005a005a005a005a005a005a005a005a07f05a005a0064006400640064006400640064006400640064006400640064006e07f06e006e006e006e006e006e006e006e006e006e006e006e007800780078007807f07800780078007800780078007800780078008200820082008200820082008207f08200820082008200820082008c008c008c008c008c008c008c008c008c008c07f08c008c008c009600960096009600960096009600960096009600960096009607f0a000a000a000a000a000a000a000a000a000a000a000a000a000aa00aa00aa07f0aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00b400b400b400b400b400b407f0b400b400b400b400b400b400b400be00be00be00be00be00be00be00be00be07f0be00be00be00be00c800c800c800c800c800c800c800c800c800c800c800c807f0c800d200d200d200d200d200d200d200d200d200d200d200d200d200dc00dc07f0dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00e600e600e600e600e607f0e600e600e600e600e600e600e600e600f000f000f000f000f000f000f000f007f0f000f000f000f000f000fa00fa00fa00fa00fa00fa00fa00fa00fa00fa00fa07f0fa00fa0104010401040104010401040104010401040104010401040104010e07f10e010e010e010e010e010e010e010e010e010e010e010e011801180118011807f11801180118011801180118011801180118012201220122012201220122012207f12201220122012201220122012c012c012c012c012c012c012c012c012c012c07f12c012c012c013601360136013601360136013601360136013601360136013607f140014001400140014001400140014001400140014001400140014a014a014a07f14a014a014a014a014a014a014a014a014a014a01540154015401540154015407f154015401540154015401540154015e015e015e015e015e015e015e015e015e07f15e015e015e015e01680168016801680168016801680168016801680168016807f1680172017201720172017201720172017201720172017201720172017c017c07f17c017c017c017c017c017c017c017c017c017c017c0186018601860186018607f18601860186018601860186018601860190019001900190019001900190019007f19001900190019001900190019001900190019001900190019001900190019007f19001900186018601860186018601860186018601860186018601860186017c07f17c017c017c017c017c017c017c017c017c017c017c017c017201720172017207f17201720172017201720172017201720172016801680168016801680168016807f16801680168016801680168015e015e015e015e015e015e015e015e015e015e07f15e015e015e015401540154015401540154015401540154015401540154015407f14a014a014a014a014a014a014a014a014a014a014a014a014a01400140014007f14001400140014001400140014001400140014001360136013601360136013607f136013601360136013601360136012c012c012c012c012c012c012c012c012c07f12c012c012c012c01220122012201220122012201220122012201220122012207f1220118011801180118011801180118011801180118011801180118010e010e07f10e010e010e010e010e010e010e010e010e010e010e0104010401040104010407f104010401040104010401040104010400fa00fa00fa00fa00fa00fa00fa00fa07f0fa00fa00fa00fa00fa00f000f000f000f000f000f000f000f000f000f000f007f0f000f000e600e600e600e600e600e600e600e600e600e600e600e600e600dc07f0dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00dc00d200d200d200d207f0d200d200d200d200d200d200d200d200d200c800c800c800c800c800c800c807f0c800c800c800c800c800c800be00be00be00be00be00be00be00be00be00be07f0be00be00be00b400b400b400b400b400b400b400b400b400b400b400b400b407f0aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00aa00a000a000a007f0a000a000a000a000a000a000a000a000a000a000960096009600960096009607f096009600960096009600960096008c008c008c008c008c008c008c008c008c07f08c008c008c008c00820082008200820082008200820082008200820082008207f0820078007800780078007800780078007800780078007800780078006e006e07f06e006e006e006e006e006e006e006e006e006e006e0064006400640064006407f0640064006400640064006400640064005a005a005a005a005a005a005a005a07f05a005a005a005a005a0050005000500050005000500050005000500050005007f0500050004b004b00460046004600460046004600460046004600460046004b07f04b003ea03c003c003c003c003c003c003c003c003c003c004b004b003de03207f03200320032003200320032003200320032004b004b003d702800280028002807f02800280028002800280028004b004b003be023701e001e001e001e001e001e07f01e001e001e004b004b003b6020b01c8016b01400155014001570140014001407f04b004b0036e01e201ad015800f400f9010c00f200eb00a000a004b004b002157f01be0183014500e000cc00ab003700000000000001c001b901980180016b01397f00d5007000280007ffa6ff90ff90019a01940185016c015f012900c6004a00037fffe0ff99ff8bff8a0182017d0170015b014c011a00b2ffdaffcbffbdff8dff817fff80016c0168015c014801390108009bff9cff8bff86ff70ff69ff68015801547f01480135012600f5ff8dff8aff77ff6fff64ff5cff5c0144013f0134012001117fff7eff7eff7cff69ff62ff5cff55ff540131012d0120ff77ff75ff71ff72ff717fff61ff59ff53ff4fff4e011e0119010dff6dff6bff68ff6cff67ff58ff51ff4b7fff48ff48010d0108ff68ff64ff62ff61ff67ff5fff52ff4bff45ff42ff41ff697fff67ff63ff5fff5dff5cff61ff57ff4bff43ff3eff3bff3aff62ff5fff5bff567fff54ff58ff5bff50ff46ff3fff39ff36ff36ff60ff5eff59ff55ff53ff56ff567fff4bff42ff3aff35ff32ff31ff61ff5dff58ff52ff50ff53ff50ff47ff3eff367fff31ff2eff2dff61ff5eff5aff55ff52ff50ff4bff43ff3aff32ff2cff29ff297fff5eff5cff57ff52ff4fff4cff47ff3fff36ff2fff29ff26ff25ff5aff57ff537fff4eff4cff49ff43ff3bff33ff2cff26ff24ff23ff56ff54ff50ff4bff49ff457fff40ff38ff30ff2aff23ff20ff20ff53ff51ff4cff48ff45ff42ff3dff36ff2e7fff27ff21ff1eff1dff50ff4dff49ff44ff42ff3fff3aff33ff2cff25ff1eff1b7fff1bff4dff4bff47ff42ff40ff3dff38ff31ff2aff24ff1cff19ff19ff4bff487fff44ff40ff3eff3aff36ff2fff28ff22ff1bff18ff17ff48ff46ff42ff3dff3b7fff38ff34ff2eff26ff1fff18ff15ff14ff46ff44ff40ff3bff39ff36ff32ff2c7fff25ff1eff17ff14ff13ff44ff42ff3eff3aff38ff35ff30ff2aff24ff1dff167fff13ff12ff43ff41ff3cff38ff36ff33ff2fff29ff23ff1bff14ff11ff10ff427fff40ff3bff37ff35ff32ff2dff28ff22ff1bff13ff10ff0fff40ff3eff3aff357fff34ff30ff2cff27ff21ff19ff12ff0fff0eff3fff3cff38ff34ff32ff2fff2b7fff26ff1fff18ff11ff0eff0dff3dff3bff37ff32ff31ff2eff2aff25ff1fff187fff10ff0dff0cff3cff3aff36ff32ff30ff2dff29ff24ff1eff17ff0fff0cff0c7fff3bff39ff35ff30ff2fff2cff28ff23ff1dff16ff0eff0bff0bff3aff38ff337fff2fff2eff2bff27ff23ff1cff15ff0dff0aff0aff39ff37ff32ff2eff2dff2a7fff27ff22ff1cff15ff0dff0aff09ff38ff36ff32ff2eff2cff29ff26ff21ff1b7fff14ff0dff0aff09ff37ff35ff31ff2dff2bff28ff25ff21ff1aff13ff0cff097fff08ff36ff34ff30ff2cff2aff28ff24ff20ff1aff12ff0bff08ff07ff35ff337fff2fff2bff29ff27ff24ff1fff19ff12ff0bff08ff07ff35ff32ff2eff2aff297fff26ff23ff1fff19ff12ff0aff07ff06ff34ff32ff2eff2aff28ff26ff23ff1e7fff18ff11ff0aff07ff06ff33ff31ff2dff29ff28ff25ff22ff1eff18ff11ff097fff06ff0500000000000000000000000000000000000000000000000000000000"; struct Belief { int256 m; int256 v; int256 fb; int256 fa; int256 sp; int256 r; uint256 t; uint256 cnt; } function getName() external pure override returns(string memory) { unchecked {return "TaylorGaussianPlainCoarse";} } function mul(int256 a,int256 b) internal pure returns(int256){ unchecked {return a*b/U;} } function divi(int256 a,int256 b) internal pure returns(int256){ unchecked {return a*U/b;} } function ab(int256 x) internal pure returns(int256){ unchecked {return x<0?-x:x;} } function clip(int256 x,int256 a,int256 b) internal pure returns(int256){ unchecked {return xb?b:x);} } function ln(int256 x) internal pure returns(int256 z){ unchecked { require(x>0); int256 k; while(x< U){x*=2;k--;} while(x>=2*U){x/=2;k++;} int256 y=divi(x-U,x+U); int256 y2=mul(y,y); int256 q=y; z=y; for(int256 n=3;n<=29;n+=2){q=mul(q,y2);z+=q/n;} return 2*z+k*LN2; } } function exp(int256 x) internal pure returns(int256){ unchecked { if(x< -42*U)return 0; require(x<60*U); int256 k=(x>=0?x+LN2/2:x-LN2/2)/LN2; int256 r=x-k*LN2; int256 r2=mul(r,r); int256 even=665280*U+mul(r2,75600*U+mul(r2,840*U+r2)); int256 odd=mul(r,332640*U+mul(r2,10080*U+mul(r2,42*U))); int256 s=divi(even+odd,even-odd); return k>=0?s*int256(uint256(1)<>128>0){z>>=128;r<<=64;} if(z>>64>0){z>>=64;r<<=32;} if(z>>32>0){z>>=32;r<<=16;} if(z>>16>0){z>>=16;r<<=8;} if(z>>8>0){z>>=8;r<<=4;} if(z>>4>0){z>>=4;r<<=2;} if(z>>2>0){r<<=1;} for(uint256 i=0;i<7;i++)r=(r+n/r)/2; return int256(r10*U)return 0;return divi(exp(-mul(x,x)/2),2506628274631000200);} } // Hart rational normal tail approximation; erf(x)=2*Phi(x*sqrt(2))-1. function cdf(int256 x,int256 density) internal pure returns(int256){ unchecked { int256 y=ab(x);if(y>8*U)return x>0?U:int256(0); int256 n=35262496599891000; n=mul(n,y)+700383064443688000;n=mul(n,y)+6373962203531650000; n=mul(n,y)+33912866078383000000;n=mul(n,y)+112079291497871000000; n=mul(n,y)+221213596169931000000;n=mul(n,y)+220206867912376000000; int256 d=88388347648318400; d=mul(d,y)+1755667163182640000;d=mul(d,y)+16064177579207000000; d=mul(d,y)+86780732202946100000;d=mul(d,y)+296564248779674000000; d=mul(d,y)+637333633378831000000;d=mul(d,y)+793826512519948000000; d=mul(d,y)+440413735824752000000; int256 tail=mul(mul(density,2506628274631000200),divi(n,d));return x>0?U-tail:tail; } } function trunc(int256 m,int256 v,int256 lo,int256 hi) internal pure returns(int256 Z,int256 mt,int256 vt){ unchecked { if(v<=0)return (lo<=m&&m<=hi?U:int256(0),m,0); int256 sd=root(v);int256 a=divi(lo-m,sd);int256 b=divi(hi-m,sd); int256 pa=pdf(a);int256 pb=pdf(b); Z=cdf(b,pb)-cdf(a,pa); if(Z<1e6)return(Z,m79)q.i=79; q.f=p-int256(q.i)*U; if(ph==0){r=clip(r,-30*U,30*U);p=(r+30*U)/10;q.j=uint256(p/U);if(q.j>5)q.j=5;q.g=p-int256(q.j)*U;q.n=7;} else{r=clip(r,-800*U,800*U);while(q.j<11&&r>=knot(q.j+1))q.j++;q.g=divi(r-knot(q.j),knot(q.j+1)-knot(q.j));q.n=13;q.base=1134+(ph-1)*2106;} int256 a=blend(q,q.base);int256 b=blend(q,q.base+81*q.n); fb=b> -w?U-exp(-(b+w)/10000):int256(0);fa=a>w?U-exp(-(a-w)/10000):int256(0); fb=clip(fb,0,U/10);fa=clip(fa,0,U/10); } } function save(Belief memory b) internal { unchecked { slots[0]=uint256(b.m);slots[1]=uint256(b.v);slots[2]=uint256(b.fb);slots[3]=uint256(b.fa); slots[4]=uint256(b.sp);slots[5]=uint256(b.r);slots[6]=b.t;slots[7]=b.cnt; } } function afterInitialize(uint256 x,uint256 y) external override returns(uint256,uint256){ unchecked { Belief memory b; b.sp=int256(y*1e18/x);b.r=b.sp;b.m=ln(b.sp); b.fb=2821013442392051;b.fa=2821013442392051;save(b);return(uint256(b.fb),uint256(b.fa)); } } struct Work {int256 lo;int256 hi;int256 m;int256 v;int256 lp;int256 la;int256 Z;int256 mt;int256 vt;int256 d;int256 pi;} function update(Belief memory b,int256 s,bool buy,uint256 dt) internal pure returns(bool arb){ unchecked { Work memory q; q.lo=ln(mul(b.sp,U-b.fb));q.hi=ln(divi(b.sp,U-b.fa));q.m=b.m;q.v=b.v; uint256 n=dt-1;if(n>12)n=12; for(uint256 i=0;i0?divi(q.la,q.la+lr):int256(0);arb=q.pi>U/2; if(q.pi>5e15&&q.pi<995e15){ b.m=mul(q.pi,q.lp)+mul(U-q.pi,q.mt); b.v=mul(q.pi,mul(q.lp-b.m,q.lp-b.m))+mul(U-q.pi,q.vt+mul(q.mt-b.m,q.mt-b.m)); }else if(arb){b.m=q.lp;b.v=0;}else{b.m=q.mt;b.v=q.vt;} int256 pe=exp(b.m);b.r=clip(b.r,mul(pe,997e15),divi(pe,997e15));b.cnt=0; } } function afterSwap(TradeInfo calldata t) external override returns(uint256,uint256){ unchecked { Belief memory b=Belief(int256(slots[0]),int256(slots[1]),int256(slots[2]),int256(slots[3]),int256(slots[4]),int256(slots[5]),slots[6],slots[7]); int256 s=int256(t.reserveY*1e18/t.reserveX);bool arb; if(t.timestamp>b.t)arb=update(b,s,t.isBuy,t.timestamp-b.t); uint256 ph; if(!arb){ int256 c=t.isBuy?divi(mul(s,U-b.fb),997e15):divi(mul(s,997e15),U-b.fa); if(t.isBuy?cb.r)b.r=c; b.cnt++;ph=b.cnt==1?1:2; } int256 w=(ln(s)-b.m)*10000;int256 r=(ln(b.r)-b.m)*10000; (b.fb,b.fa)=fees(w,r,ph);b.sp=s;b.t=t.timestamp;save(b); return(uint256(b.fb),uint256(b.fa)); } } } ``` ### scratch/standalone.py ```python """Taylor/gtmcknight Gaussian plain policy, pinned 4812a638; compressed reference. Standard library only. Reads exactly the TABLE literal from Strategy.sol. """ import math,re,struct from pathlib import Path U=10**18 SIG2=.000945**2 LD_M,LD_S=math.log(11.12e-4),1.176 K0=[-30,-20,-10,0,10,20,30] K1=[-800,-300,-125,-60,-40,-20,0,20,40,60,125,300,800] def phi(x):return math.exp(-.5*x*x)/math.sqrt(2*math.pi) def Phi(x):return .5*(1+math.erf(x/math.sqrt(2))) def trunc(m,v,lo,hi): if v<=0:return float(lo<=m<=hi),m,0. sd=math.sqrt(v);a=(lo-m)/sd;b=(hi-m)/sd;z=Phi(b)-Phi(a) if z<1e-12:return z,lo if m'+'h'*(len(data)//2),data) self.m=math.log(100);self.v=0.;self.tlast=0;self.cnt=0;self.s2h=100.;self.fb=self.fa=.003;self.sp=100. def _fees(self,w,r,ph): p=max(0,min(80,(w+800)/20));i=min(79,int(p));f=p-i K=K0 if ph==0 else K1;r=max(K[0],min(K[-1],r));j=0 while j=K[j+1]:j+=1 g=(r-K[j])/(K[j+1]-K[j]);n=len(K);base=0 if ph==0 else 1134+(ph-1)*2106 def get(side): off=base+side*81*n def v(a,b):return self.values[off+a*n+b]/8 return (v(i,j)*(1-f)+v(i+1,j)*f)*(1-g)+(v(i,j+1)*(1-f)+v(i+1,j+1)*f)*g a,b=get(0),get(1) return (min(.1,1-math.exp(-(b+w)*1e-4)) if b>-w else 0.,min(.1,1-math.exp(-(a-w)*1e-4)) if a>w else 0.) def init(self,*args): self.fb,self.fa=self._fees(0,0,0);return self.fb,self.fa def on_trade(self,is_buy,ax,ay,t,x,y,arb=False,p=100.,s2=100.,j=0): s=y/x;dt=t-self.tlast;is_arb=False if dt>=1: self.cnt=0;lo=math.log(self.sp*(1-self.fb));hi=math.log(self.sp/(1-self.fa));m,v=self.m,self.v for _ in range(min(dt-1,12)): v+=SIG2;_,m,v=trunc(m,v,lo,hi) v+=SIG2 lp=math.log(s*(1-self.fb)) if is_buy else math.log(s/(1-self.fa));sd=math.sqrt(v) la=phi((lp-m)/sd)/sd;Z,mt,vt=trunc(m,v,lo,hi);d=max(abs(math.log(s/self.sp)),1e-9) lr=Z*.26*phi((math.log(d)-LD_M)/LD_S)/(d*LD_S) pi=la/(la+lr) if la+lr>0 else 0.;is_arb=pi>.5 if .0052 else 'contracts/src/Strategy.sol') n=int(sys.argv[1]) if len(sys.argv)>1 else 1 out=[] for seed in range(70000,70000+n): row=gate(seed,c);out.append(row);print(row,flush=True) (HERE/'gateF.json').write_text(json.dumps(out)) ``` ### scratch/table_check.py ```python """Verify the shipped blob against pinned pol_mid.json; no third-party modules.""" import json,re,struct,hashlib,sys from pathlib import Path T=json.loads(Path(sys.argv[1]).read_text()) vals=[];err=[] for ph in range(3): for side in 'AB': for i in range(0,321,4): for j in range(0,13,2) if ph==0 else range(0,49,4): v=T[f'{side}{ph}'][i][j];q=round(v*8);vals.append(q);err.append(abs(q/8-v)) raw=struct.pack('>'+'h'*len(vals),*vals) enc=b''.join(b'\x7f'+raw[i:i+32].ljust(32,b'\0') for i in range(0,len(raw),32)) s=Path('contracts/src/Strategy.sol').read_text() shipped=bytes.fromhex(re.search(r'bytes constant TABLE=hex"([0-9a-f]+)"',s)[1]) assert shipped==enc print({'values':len(vals),'raw_bytes':len(raw),'encoded_bytes':len(enc),'sha256':hashlib.sha256(raw).hexdigest(),'max_rounding_error_bps':max(err)}) ``` ### scratch/replica_compare.py ```python """Paired replica score; argv: pinned solved directory, seed start, seed end. Run selection 60000..61023, then report 10000..12047. May split seed ranges. """ import sys,json,math from pathlib import Path from multiprocessing import Pool sys.path.insert(0,sys.argv[1]) from real import RealPolicy from evalpol import load import replica2 as R from standalone import Coarse T=load(str(Path(sys.argv[1])/'pol_mid.json')) def ev(seed): full=R.run(seed,RealPolicy(T,{'soft':1}))['edge'] coarse=R.run(seed,Coarse())['edge'] return [seed,full,coarse,coarse-full] if __name__=='__main__': start,end=map(int,sys.argv[2:4]) with Pool(8) as p: rows=p.map(ev,range(start,end)) d=[r[3] for r in rows];n=len(d);m=sum(d)/n out={'n':n,'mean_diff':m,'se':math.sqrt(sum((x-m)**2 for x in d)/(n-1)/n),'worst5':sorted(rows,key=lambda x:x[3])[:5],'rows':rows} Path(f'scratch/compare_{start}_{end}.json').write_text(json.dumps(out)) print({k:v for k,v in out.items() if k!='rows'}) ``` ### scratch/engine.py ```python import sys,json,math,time,hashlib from pathlib import Path import amm_sim_rs from amm_competition.competition.match import MatchRunner from amm_competition.competition.config import BASELINE_VARIANCE,build_base_config from amm_competition.evm.compiler import SolidityCompiler from check import compiled,HERE def vanilla(): s=Path('contracts/src/VanillaStrategy.sol').read_text() c=SolidityCompiler().compile(s,contract_name='VanillaStrategy') assert c.success,c.errors return c.bytecode def configs(start,end): # _build_configs seeds parameter variability with np.default_rng(i). # Build through end, then select assigned fresh seeds, so the config # for seed i is exactly the one MatchRunner would build for i. # Equivalent direct transcription avoids allocating 9.5M configs. import numpy as np base=build_base_config(seed=None);v=BASELINE_VARIANCE;out=[] for seed in range(start,end): rng=np.random.default_rng(seed) size=rng.uniform(v.retail_mean_size_min,v.retail_mean_size_max) rate=rng.uniform(v.retail_arrival_rate_min,v.retail_arrival_rate_max) sig=rng.uniform(v.gbm_sigma_min,v.gbm_sigma_max) out.append(amm_sim_rs.SimulationConfig(n_steps=base.n_steps,initial_price=base.initial_price,initial_x=base.initial_x,initial_y=base.initial_y,gbm_mu=base.gbm_mu,gbm_sigma=sig,gbm_dt=base.gbm_dt,retail_arrival_rate=rate,retail_mean_size=size,retail_size_sigma=base.retail_size_sigma,retail_buy_prob=base.retail_buy_prob,seed=seed)) return out if __name__=='__main__': kind=sys.argv[1];start,end=map(int,sys.argv[2:4]) assert 9510128<=start